import { apiGet } from '../api.js';
import { canOpenKioskSettings, openDeviceSettings, openNetworkSettings, openWifiSettings } from '../kiosk-settings.js';
import { syncNotifications } from '../notifications.js';
export async function renderDashboard(root, { experience } = {}) {
const currentExperience = experience || {
moduleKey: 'mixed',
moduleLabel: 'FTTH',
moduleMetricLabel: 'Missions FTTH',
moduleInProgressLabel: 'FTTH en cours',
moduleActionLabel: 'Ouvrir FTTH',
moduleOpenActionLabel: 'Voir fiches',
navItems: [],
};
root.innerHTML = `
tableau de bord
Vue d'ensemble terrain
Retrouvez vos volumes de tickets, vos priorités et les accès rapides juste après la connexion.
Raccourcis
Accès direct aux écrans opérationnels
${renderShortcutActions(currentExperience)}
${renderKioskSettingsPanel()}
Alertes prioritaires
Éléments qui demandent une attention rapide
Dernières assignations
Aperçu des tickets disponibles sans quitter le dashboard
`;
const alertBox = root.querySelector('#dashboardAlert');
const heroStats = root.querySelector('#dashboardHeroStats');
const metricsBox = root.querySelector('#dashboardMetrics');
const priorityBox = root.querySelector('#dashboardPriorityList');
const recentBox = root.querySelector('#dashboardRecentList');
const kioskButtons = Array.from(root.querySelectorAll('[data-kiosk-settings]'));
for (const button of kioskButtons) {
button.addEventListener('click', async () => {
const action = String(button.dataset.kioskSettings || '');
const handlers = {
wifi: openWifiSettings,
network: openNetworkSettings,
device: openDeviceSettings,
};
const handler = handlers[action];
if (!handler) {
return;
}
try {
await handler();
} catch (error) {
alertBox.innerHTML = '
Impossible d’ouvrir les paramètres de la tablette depuis ce terminal.
';
}
});
}
async function load() {
alertBox.innerHTML = '';
heroStats.innerHTML = 'ChargementSynchronisation…
';
metricsBox.innerHTML = 'Chargement du tableau de bord…
';
priorityBox.innerHTML = 'Analyse des priorités…
';
recentBox.innerHTML = 'Chargement des assignations…
';
const shouldLoadIncidents = currentExperience.moduleKey === 'backbones' || currentExperience.moduleKey === 'mixed';
const shouldLoadTickets = currentExperience.moduleKey !== 'backbones';
const [incidentsResult, ftthResult] = await Promise.allSettled([
shouldLoadIncidents ? apiGet('/api/mobile/incidents/assigned') : Promise.resolve({ ok: true, incidents: [] }),
shouldLoadTickets ? apiGet('/api/mobile/ftth/assigned') : Promise.resolve({ ok: true, tickets: [] }),
]);
const incidents = incidentsResult.status === 'fulfilled' ? (incidentsResult.value?.incidents || []) : [];
const tickets = ftthResult.status === 'fulfilled' ? (ftthResult.value?.tickets || []) : [];
const urgentCount = incidents.filter((item) => String(item.priority || '').toLowerCase() === 'urgent').length;
const inProgressFtth = tickets.filter((item) => {
const status = String(item.status || '').toLowerCase();
return status && status !== 'traité' && status !== 'validé' && status !== 'clôturé';
}).length;
syncNotifications({ incidents, tickets });
heroStats.innerHTML = renderHeroStats(currentExperience, incidents.length, tickets.length, urgentCount, inProgressFtth);
metricsBox.innerHTML = renderMetricCards(currentExperience, incidents.length, tickets.length, urgentCount, inProgressFtth);
const priorityItems = buildPriorityItems(currentExperience, incidents.length, tickets.length, urgentCount, inProgressFtth);
priorityBox.innerHTML = priorityItems.map((text) => `
${escapeHtml(text)}
`).join('');
const recentIncidents = incidents.slice(0, 2).map((item) => ({
title: item.ticket_id || `INC-${item.id}`,
subtitle: item.title || 'Incident terrain',
meta: item.status_label || item.priority || 'À traiter',
href: `#/treatment?id=${Number(item.id || 0)}`,
icon: 'fa-triangle-exclamation',
}));
const recentTickets = tickets.slice(0, 2).map((item) => ({
title: item.client_name || item.ref_code || `FTTH-${item.id}`,
subtitle: item.nature_intervention || item.client_address || `Mission ${currentExperience.moduleLabel}`,
meta: item.priority || item.status || 'À ouvrir',
href: `#/ftth-report?id=${Number(item.id || 0)}`,
icon: 'fa-network-wired',
}));
const recentItems = currentExperience.moduleKey === 'backbones'
? recentIncidents
: currentExperience.moduleKey === 'mixed'
? [...recentIncidents, ...recentTickets]
: recentTickets;
recentBox.innerHTML = recentItems.length
? recentItems.map((item) => `
${escapeHtml(item.title)}
${escapeHtml(item.subtitle)}
${escapeHtml(item.meta)}
`).join('')
: 'Aucune assignation récente à afficher.
';
if ((shouldLoadIncidents && incidentsResult.status === 'rejected') || (shouldLoadTickets && ftthResult.status === 'rejected')) {
alertBox.innerHTML = 'Certaines données n’ont pas pu être synchronisées. Le dashboard affiche les éléments disponibles.
';
}
}
root.querySelector('#btnRefreshDashboard').addEventListener('click', load);
await load();
}
function renderMetricCard(label, value, icon, badgeClass, href, actionLabel) {
return `
${escapeHtml(label)}
${value}
${escapeHtml(actionLabel)}
`;
}
function renderShortcutActions(experience) {
const actions = experience.navItems.filter((item) => item.path !== '/dashboard');
return actions.map((item, index) => {
const classes = index === 0 ? 'btn btn-primary mobile-cta' : 'btn btn-outline-primary mobile-cta';
return `${escapeHtml(item.label)}`;
}).join('');
}
function renderKioskSettingsPanel() {
if (!canOpenKioskSettings()) {
return '';
}
return `
`;
}
function renderHeroStats(experience, incidentsCount, ticketsCount, urgentCount, inProgressCount) {
if (experience.moduleKey === 'backbones') {
return `
Incidents
${incidentsCount}
Urgents
${urgentCount}
`;
}
return `
${escapeHtml(experience.moduleMetricLabel)}
${ticketsCount}
En cours
${inProgressCount}
`;
}
function renderMetricCards(experience, incidentsCount, ticketsCount, urgentCount, inProgressCount) {
if (experience.moduleKey === 'backbones') {
return `
${renderMetricCard('Incidents assignés', incidentsCount, 'fa-triangle-exclamation', 'text-bg-warning', '#/assigned', 'Ouvrir incidents')}
${renderMetricCard('Incidents urgents', urgentCount, 'fa-bolt', 'text-bg-danger', '#/assigned', 'Traiter urgences')}
`;
}
return `
${renderMetricCard(experience.moduleMetricLabel, ticketsCount, 'fa-network-wired', 'text-bg-info', '#/ftth', experience.moduleActionLabel)}
${renderMetricCard(experience.moduleInProgressLabel, inProgressCount, 'fa-file-waveform', 'text-bg-primary', '#/ftth', experience.moduleOpenActionLabel)}
`;
}
function buildPriorityItems(experience, incidentsCount, ticketsCount, urgentCount, inProgressCount) {
if (experience.moduleKey === 'backbones') {
return [
urgentCount ? `${urgentCount} incident(s) urgent(s) nécessitent une prise en charge.` : '',
!incidentsCount ? 'Aucun incident en attente pour le moment.' : '',
].filter(Boolean);
}
return [
inProgressCount ? `${inProgressCount} mission(s) ${experience.moduleLabel.toLowerCase()} restent à compléter.` : '',
!ticketsCount ? `Aucune mission ${experience.moduleLabel.toLowerCase()} en attente pour le moment.` : '',
].filter(Boolean);
}
function escapeHtml(value) {
return String(value ?? '')
.replaceAll('&', '&')
.replaceAll('<', '<')
.replaceAll('>', '>')
.replaceAll('"', '"')
.replaceAll("'", ''');
}