import { clearSession, getStoredClient, getToken } from './auth.js';
import {
fetchIncidentDetail,
fetchIncidents,
fetchNotifications,
fetchProfile,
fetchUnreadCount,
markNotificationsRead,
} from './api.js';
import { renderLogin } from './views/login.js';
import { renderForgotPassword } from './views/forgot-password.js';
import { renderOnboarding } from './views/onboarding.js';
import { renderDashboard } from './views/dashboard.js';
import { renderDeclareIncident } from './views/declare-incident.js';
import { renderHistory } from './views/history.js';
import { renderIncidentDetail } from './views/incident-detail.js';
let shellRoot = null;
function parseHash() {
const raw = (location.hash || '#/login').slice(1);
const [pathPart, queryPart] = raw.split('?');
return {
path: pathPart || '/login',
params: new URLSearchParams(queryPart || ''),
};
}
function getBackConfig(path) {
if (path === '/incident') {
return { fallbackHash: '#/history', label: 'Retour' };
}
if (path === '/declare' || path === '/history') {
return { fallbackHash: '#/dashboard', label: 'Retour' };
}
return null;
}
function layoutShell(path, unreadCount) {
const backConfig = getBackConfig(path);
const root = document.getElementById('app');
root.innerHTML = `
${backConfig ? `
` : ''}
e-Intervention
Espace client FTTH public
Espace client actif
`;
shellRoot = root;
root.querySelector('#btnBack')?.addEventListener('click', () => {
if (window.history.length > 1) {
window.history.back();
return;
}
if (backConfig?.fallbackHash) {
location.hash = backConfig.fallbackHash;
}
});
root.querySelector('#btnLogout').addEventListener('click', () => {
clearSession();
location.hash = '#/login';
});
root.querySelector('#btnNotifications').addEventListener('click', () => {
const panel = root.querySelector('#notificationPanel');
panel.hidden = !panel.hidden;
});
return root;
}
function renderNotifications(panel, notifications) {
panel.innerHTML = `
Notifications
Messages de prise en charge et de suivi.
${notifications.length ? notifications.map((item) => `
${escapeHtml(item.title)}
${escapeHtml(item.body || '')}
${escapeHtml(formatDateTime(item.created_at))}
`).join('') : '
Aucune notification pour le moment.
'}
`;
panel.querySelector('#btnReadAll')?.addEventListener('click', async () => {
await markNotificationsRead();
await renderRoute();
});
}
async function renderRoute() {
const { path, params } = parseHash();
const token = getToken();
if (!token && path !== '/login' && path !== '/register' && path !== '/forgot-password') {
location.hash = '#/login';
return;
}
if (token && (path === '/login' || path === '/register' || path === '/forgot-password')) {
location.hash = '#/dashboard';
return;
}
if (path === '/login') {
const root = document.getElementById('app');
root.innerHTML = '';
await renderLogin(root, () => {
location.hash = '#/dashboard';
});
return;
}
if (path === '/register') {
const root = document.getElementById('app');
root.innerHTML = '';
await renderOnboarding(root, () => {
location.hash = '#/dashboard';
});
return;
}
if (path === '/forgot-password') {
const root = document.getElementById('app');
root.innerHTML = '';
await renderForgotPassword(root, () => {
location.hash = '#/login';
});
return;
}
const [profileResponse, incidentsResponse, notificationsResponse, unreadResponse] = await Promise.all([
fetchProfile(),
fetchIncidents(),
fetchNotifications(),
fetchUnreadCount(),
]);
const client = profileResponse?.client || getStoredClient();
const incidents = incidentsResponse?.items || [];
const notifications = notificationsResponse?.notifications || [];
const unreadCount = Number(unreadResponse?.unread || 0);
const root = layoutShell(path, unreadCount);
root.querySelector('#clientChip').textContent = `${client?.full_name || 'Client'} • ${client?.subscription_number || 'abonnement'}`;
renderNotifications(root.querySelector('#notificationPanel'), notifications);
const view = root.querySelector('#view');
if (path === '/dashboard') {
await renderDashboard(view, { client, incidents, unreadCount });
return;
}
if (path === '/declare') {
await renderDeclareIncident(view, {
client,
onSuccess: async () => {
location.hash = '#/history';
},
});
return;
}
if (path === '/history') {
await renderHistory(view, { incidents });
return;
}
if (path === '/incident') {
const incidentId = Number(params.get('id') || 0);
await renderIncidentDetail(view, { incidentId, incidents, fetchIncidentDetail });
return;
}
location.hash = '#/dashboard';
}
export function startApp() {
window.addEventListener('hashchange', renderRoute);
showBootSplash().then(renderRoute);
}
async function showBootSplash() {
const root = document.getElementById('app');
root.innerHTML = `
e-Intervention
Déclaration client et suivi intelligent des interventions
`;
await new Promise((resolve) => window.setTimeout(resolve, 1400));
}
function formatDateTime(value) {
if (!value) {
return '—';
}
const date = new Date(String(value).replace(' ', 'T'));
if (Number.isNaN(date.getTime())) {
return value;
}
return date.toLocaleString('fr-FR', { dateStyle: 'medium', timeStyle: 'short' });
}
function escapeHtml(value) {
return String(value ?? '')
.replaceAll('&', '&')
.replaceAll('<', '<')
.replaceAll('>', '>')
.replaceAll('"', '"')
.replaceAll("'", ''');
}