// ============================================================================ // DASHBOARD VIEW // ============================================================================ const DashboardView = () => { const { customer } = useAuth(); const [screens, setScreens] = useState([]); const [loading, setLoading] = useState(true); const [stats, setStats] = useState({ total_screens: 0, active_screens: 0, total_ads: 0, total_news: 0 }); useEffect(() => { loadScreens(); }, []); const loadScreens = async () => { setLoading(true); try { const result = await api.getScreens(customer.id); if (result.screens) { setScreens(result.screens); // Calculer les stats setStats({ total_screens: result.screens.length, active_screens: result.screens.filter(s => s.is_active == 1).length, total_ads: result.screens.reduce((sum, s) => sum + (parseInt(s.ads_count) || 0), 0), total_news: result.screens.reduce((sum, s) => sum + (parseInt(s.news_count) || 0), 0) }); } } catch (error) { console.error('Erreur chargement écrans:', error); } setLoading(false); }; if (loading) return ; return (

Dashboard

{/* Stats Cards */}

Écrans totaux

{stats.total_screens}

Écrans actifs

{stats.active_screens}

Publicités

{stats.total_ads}

Alertes actives

{stats.total_news}

{/* Liste des écrans */} {screens.length === 0 ? ( ) : (
{screens.map(screen => (

{screen.label}

{screen.location_city} • {screen.address}

{screen.is_active == 1 ? 'Actif' : 'Inactif'}
{screen.ads_count || 0} pub(s)
{screen.news_count || 0} alerte(s)
))}
)}
); }; // ============================================================================ // SCREENS VIEW // ============================================================================ const ScreensView = () => { const { customer } = useAuth(); const toast = useToast(); const [screens, setScreens] = useState([]); const [configurations, setConfigurations] = useState([]); const [loading, setLoading] = useState(true); const [isModalOpen, setIsModalOpen] = useState(false); const [isDetailModalOpen, setIsDetailModalOpen] = useState(false); const [isPreviewModalOpen, setIsPreviewModalOpen] = useState(false); const [editingScreen, setEditingScreen] = useState(null); const [viewingScreen, setViewingScreen] = useState(null); const [previewUrl, setPreviewUrl] = useState(''); // Fermer la modal de preview avec la touche Échap useEffect(() => { const handleEscape = (e) => { if (e.key === 'Escape' && isPreviewModalOpen) { setIsPreviewModalOpen(false); } }; window.addEventListener('keydown', handleEscape); return () => window.removeEventListener('keydown', handleEscape); }, [isPreviewModalOpen]); // Form state const [formLabel, setFormLabel] = useState(''); const [formCity, setFormCity] = useState('Genève'); const [formAddress, setFormAddress] = useState(''); const [formLatitude, setFormLatitude] = useState(null); const [formLongitude, setFormLongitude] = useState(null); const [formBusStop, setFormBusStop] = useState(''); const [formBusCode, setFormBusCode] = useState(''); const [formActive, setFormActive] = useState(true); const [formConfigurationId, setFormConfigurationId] = useState(null); const [formConciergeId, setFormConciergeId] = useState(null); // Liste des concierges const [concierges, setConcierges] = useState([]); useEffect(() => { loadScreens(); loadConfigurations(); loadConcierges(); }, []); const loadScreens = async () => { setLoading(true); try { const result = await api.getScreens(customer.id); if (result.screens) { setScreens(result.screens); } } catch (error) { toast.error('Erreur lors du chargement'); } setLoading(false); }; const loadConfigurations = async () => { try { const result = await api.getConfigurations(customer.id); if (result.configurations) { setConfigurations(result.configurations); } } catch (error) { console.error('Erreur lors du chargement des configurations'); } }; const loadConcierges = async () => { try { const result = await api.getConcierges(customer.id); if (result.concierges) { setConcierges(result.concierges); } } catch (error) { console.error('Erreur lors du chargement des concierges'); } }; const openModal = (screen = null) => { if (screen) { setEditingScreen(screen); setFormLabel(screen.label); setFormCity(screen.location_city); setFormAddress(screen.address); setFormLatitude(screen.latitude || null); setFormLongitude(screen.longitude || null); setFormBusStop(screen.bus_stop_name || ''); setFormBusCode(screen.bus_stop_code || ''); setFormActive(screen.is_active == 1); setFormConfigurationId(screen.configuration_id ? parseInt(screen.configuration_id) : null); setFormConciergeId(screen.concierge_id ? parseInt(screen.concierge_id) : null); } else { setEditingScreen(null); setFormLabel(''); setFormCity('Genève'); setFormAddress(''); setFormLatitude(null); setFormLongitude(null); setFormBusStop(''); setFormBusCode(''); setFormActive(true); setFormConfigurationId(configurations.length > 0 ? configurations[0].id : null); setFormConciergeId(null); } setIsModalOpen(true); }; const handleSubmit = async (e) => { e.preventDefault(); const data = { customer_id: customer.id, label: formLabel, location_city: formCity, address: formAddress, latitude: formLatitude, longitude: formLongitude, bus_stop_name: formBusStop, bus_stop_code: formBusCode, is_active: formActive ? 1 : 0, configuration_id: formConfigurationId, concierge_id: formConciergeId }; try { if (editingScreen) { data.screen_id = editingScreen.id; const result = await api.updateScreen(data); if (result.success) { toast.success('Écran modifié avec succès'); } } else { const result = await api.createScreen(data); if (result.success) { toast.success('Écran créé avec succès'); toast.info(`Code écran : ${result.screen_code}`); } } loadScreens(); setIsModalOpen(false); } catch (error) { toast.error('Erreur lors de l\'enregistrement'); } }; const openDetailModal = (screen) => { setViewingScreen(screen); setIsDetailModalOpen(true); }; const closeDetailModal = () => { setIsDetailModalOpen(false); setViewingScreen(null); }; const handleDelete = async (screenId) => { if (!confirm('Êtes-vous sûr de vouloir supprimer cet écran ?')) return; try { const result = await api.deleteScreen(screenId); if (result.success) { toast.success('Écran supprimé'); loadScreens(); } } catch (error) { toast.error('Erreur lors de la suppression'); } }; const handlePreview = (screen) => { // Détecter si on est en local ou en production const isLocal = window.location.hostname === 'localhost' || window.location.hostname === '127.0.0.1' || window.location.hostname.includes('local'); // Construire l'URL de base (HTTPS partout car le serveur local utilise SSL) const baseUrl = isLocal ? 'https://local.smarthall.screen:8890' : 'https://screen.smarthall.ch'; // Utiliser md5_id ou screen_code en fallback const identifier = screen.md5_id || screen.screen_code; // Construire l'URL complète const url = `${baseUrl}/?md5=${identifier}`; // Ouvrir dans une modal avec iframe setPreviewUrl(url); setIsPreviewModalOpen(true); toast.info(`Chargement de la prévisualisation...`); }; if (loading) return ; return (

Mes Écrans

{screens.length === 0 ? ( openModal()} icon="fa-plus" > Créer un écran } /> ) : (
{/* En-tête du tableau */}
Écran
Localisation
Configuration
Statistiques
Statut
Actions
{/* Lignes du tableau */} {screens.map(screen => (
{/* Nom de l'écran */}

{screen.label}

{screen.screen_code} {screen.md5_id && ( <> {screen.md5_id.substring(0, 8)}... )}
{/* Localisation */}
{screen.location_city}
{screen.address}
{/* Configuration */}
{screen.configuration_name ? (
{screen.configuration_name}
) : ( Aucune )}
{/* Statistiques */}
{screen.ads_count || 0} {screen.news_count || 0}
{/* Statut */}
{screen.is_active == 1 ? 'Actif' : 'Inactif'}
{/* Actions */}
))}
)} {/* Modal Créer/Modifier */} setIsModalOpen(false)} title={editingScreen ? 'Modifier l\'écran' : 'Nouvel écran'} >
{/* Composant de recherche de ville pour la météo */} {/* Composant de recherche d'adresse avec Maps API */} { console.log('🎯 [ScreensView] Adresse sélectionnée:', data); setFormAddress(data.address); setFormLatitude(data.latitude); setFormLongitude(data.longitude); console.log('🎯 [ScreensView] Coordonnées GPS:', { latitude: data.latitude, longitude: data.longitude }); }} /> {/* Composant de recherche TPG avec auto-complétion */} { console.log('🎯 [ScreensView] onStopSelected appelé avec:', stop); console.log('🎯 [ScreensView] Avant - formBusStop:', formBusStop); console.log('🎯 [ScreensView] Avant - formBusCode:', formBusCode); setFormBusStop(stop.nom); setFormBusCode(stop.code); console.log('🎯 [ScreensView] Après - formBusStop:', stop.nom); console.log('🎯 [ScreensView] Après - formBusCode:', stop.code); }} /> {/* Sélecteur de configuration */}
{configurations.length > 0 ? ( <>

La configuration définit le contenu affiché sur cet écran

) : (
Aucune configuration disponible. Créez-en une dans le menu "Configurations".
)}

Les informations du concierge seront affichées sur l'écran

{/* Modal de détail simplifiée */} {viewingScreen && (
{/* Nom de l'écran */}
{viewingScreen.label}
{/* Météo */}
{viewingScreen.location_city || 'Non définie'}
{/* Adresse complète */}
{viewingScreen.address || 'Non définie'}
{(viewingScreen.latitude && viewingScreen.longitude) && (
Coordonnées GPS: {viewingScreen.latitude}, {viewingScreen.longitude}
)}
{/* Arrêt de bus */}
{viewingScreen.bus_stop_name || 'Non défini'}
{viewingScreen.bus_stop_code && (
Code: {viewingScreen.bus_stop_code}
)}
{/* Configuration */}
{viewingScreen.configuration_id ? ( configurations.find(c => c.id == viewingScreen.configuration_id)?.name || 'Configuration inconnue' ) : ( Aucune configuration (manuel) )}
{/* Concierge */}
{viewingScreen.concierge_id ? ( concierges.find(c => c.id == viewingScreen.concierge_id)?.name || 'Concierge inconnu' ) : ( Aucun concierge )}
{viewingScreen.concierge_id && concierges.find(c => c.id == viewingScreen.concierge_id)?.phone && (
Tél: {concierges.find(c => c.id == viewingScreen.concierge_id)?.phone}
)}
{/* Statut */}
{viewingScreen.is_active == 1 ? 'Actif' : 'Inactif'}
{/* Informations techniques */}
ID: {viewingScreen.id}
Code: {viewingScreen.screen_code}
API Key: {viewingScreen.api_key}
)}
{/* Modal de Prévisualisation Écran - Plein écran avec Screenshot */} {isPreviewModalOpen && ( setIsPreviewModalOpen(false)} /> )}
); }; // Suite dans views.jsx pour les autres vues...