import React, { useState, useEffect } from 'react'; import Joyride, { STATUS } from 'react-joyride'; import { useLocation } from 'react-router-dom'; const GlobalTutorial = ({ userId, userRole }) => { const [runTour, setRunTour] = useState(false); const [dontShowAgain, setDontShowAgain] = useState(false); const [availableSteps, setAvailableSteps] = useState([]); const location = useLocation(); const isEmployee = userRole === "Collaborateur" || userRole === "Apprenti"; const canViewAllFilters = ['president', 'rh', 'admin', 'directeur de campus', 'directrice de campus'].includes(userRole?.toLowerCase()); // 🎯 NOUVELLE FONCTION : Vérifier si un élément existe dans le DOM const elementExists = (selector) => { return document.querySelector(selector) !== null; }; // 🎯 NOUVELLE FONCTION : Filtrer les étapes selon les éléments disponibles const filterAvailableSteps = (steps) => { return steps.filter(step => { // Les étapes centrées (body) sont toujours affichées if (step.target === 'body') return true; // Pour les autres, vérifier si l'élément existe const element = document.querySelector(step.target); if (!element) { console.log(`⚠️ Élément non trouvé, étape ignorée: ${step.target}`); return false; } // Vérifier si l'élément est visible const isVisible = element.offsetParent !== null; if (!isVisible) { console.log(`⚠️ Élément caché, étape ignorée: ${step.target}`); return false; } return true; }); }; // 🎯 Déclencher le tutoriel avec vérification useEffect(() => { if (userId) { let tutorialKey = ''; if (location.pathname === '/dashboard') { tutorialKey = 'dashboard'; } else if (location.pathname === '/manager') { tutorialKey = 'manager'; } else if (location.pathname === '/calendar') { tutorialKey = 'calendar'; } if (tutorialKey) { const hasSeenTutorial = localStorage.getItem(`${tutorialKey}-tutorial-completed-${userId}`); if (!hasSeenTutorial) { // ⭐ NOUVEAU : Attendre que le DOM soit chargé setTimeout(() => { const allSteps = getTourSteps(); const available = filterAvailableSteps(allSteps); console.log(`📊 Étapes totales: ${allSteps.length}, disponibles: ${available.length}`); if (available.length > 2) { // Au moins 3 étapes (intro + 1 élément + conclusion) setAvailableSteps(available); setRunTour(true); } else { console.log('⚠️ Pas assez d\'éléments pour le tutoriel, annulation'); } }, 2000); } } } }, [userId, location.pathname]); // 🎯 Obtenir les étapes selon la page actuelle const getTourSteps = () => { // ==================== DASHBOARD ==================== if (location.pathname === '/dashboard') { return [ { target: 'body', content: (

👋 Bienvenue sur votre application GTA !

Découvrez toutes les fonctionnalités en quelques étapes. Ce tutoriel ne s'affichera qu'une seule fois.

), placement: 'center', disableBeacon: true, }, { target: '[data-tour="dashboard"]', content: '🏠 Accédez à votre tableau de bord pour voir vos soldes de congés.', placement: 'right', }, { target: '[data-tour="demandes"]', content: '📋 Consultez et gérez toutes vos demandes de congés ici.', placement: 'right', }, { target: '[data-tour="calendrier"]', content: '📅 Visualisez vos congés et ceux de votre équipe dans le calendrier.', placement: 'right', }, { target: '[data-tour="mon-equipe"]', content: '👥 Consultez votre équipe et leurs absences.', placement: 'right', }, { target: '[data-tour="nouvelle-demande"]', content: '➕ Cliquez ici pour créer une nouvelle demande de congé, RTT ou récupération.', placement: 'left', }, { target: '[data-tour="notifications"]', content: '🔔 Consultez ici vos notifications (validations, refus, modifications de vos demandes).', placement: 'bottom', }, { target: '[data-tour="refresh"]', content: '🔄 Rafraîchissez manuellement vos données. Mais pas d\'inquiétude : elles se mettent à jour automatiquement en temps réel !', placement: 'bottom', }, { target: '[data-tour="demandes-recentes"]', content: '📄 Consultez rapidement vos 5 dernières demandes et leur statut. Cliquez sur "Voir toutes les demandes" pour accéder à la page complète.', placement: 'top', }, { target: '[data-tour="conges-service"]', content: '👥 Visualisez les congés de votre service pour le mois en cours. Pratique pour planifier vos absences !', placement: 'top', }, { target: 'body', content: (

📊 Vos compteurs de congés

Découvrez maintenant vos différents soldes de congés disponibles.

), placement: 'center', }, { target: '[data-tour="cp-n-1"]', content: '📅 Vos congés payés de l\'année précédente. ⚠️ Attention : ils doivent être soldés avant le 31 mai de l\'année suivante !', placement: 'top', }, { target: '[data-tour="cp-n"]', content: '📈 Vos congés payés de l\'année en cours, en cours d\'acquisition. Ils se cumulent au fil des mois travaillés.', placement: 'top', }, { target: '[data-tour="rtt"]', content: '⏰ Vos RTT disponibles pour l\'année en cours. Ils sont acquis progressivement et à consommer avant le 31/12.', placement: 'top', }, { target: '[data-tour="recup"]', content: '🔄 Vos jours de récupération accumulés suite au JPO/SF.', placement: 'top', }, { target: 'body', content: (

🎉 Vous êtes prêt !

Vous pouvez maintenant utiliser l'application en toute autonomie.

💡 Besoin d'aide ? Cliquez sur le bouton "Aide" 🆘 en bas à droite pour relancer ce tutoriel à tout moment.

), placement: 'center', }, ]; } // ==================== MANAGER ==================== if (location.pathname === '/manager') { const baseSteps = [ { target: 'body', content: (

👥 Bienvenue dans la gestion d'équipe !

Découvrez comment gérer {isEmployee ? 'votre équipe' : 'les demandes de congés de votre équipe'}.

), placement: 'center', disableBeacon: true, } ]; if (!isEmployee) { // Pour les managers/validateurs return [ ...baseSteps, { target: '[data-tour="demandes-attente"]', content: '⏳ Consultez ici toutes les demandes en attente de validation. Vous pouvez les approuver ou les refuser directement.', placement: 'right', }, { target: '[data-tour="approuver-btn"]', content: '✅ Cliquez sur "Approuver" pour valider une demande. Vous pourrez ajouter un commentaire optionnel.', placement: 'top', }, { target: '[data-tour="refuser-btn"]', content: '❌ Cliquez sur "Refuser" pour rejeter une demande. Un commentaire expliquant le motif sera obligatoire.', placement: 'top', }, { target: '[data-tour="mon-equipe"]', content: '👥 Consultez la liste complète de votre équipe. Cliquez sur un membre pour voir le détail de ses demandes.', placement: 'left', }, { target: '[data-tour="historique-demandes"]', content: '📋 L\'historique complet de toutes les demandes de votre équipe avec leur statut (validée, refusée, en attente).', placement: 'top', }, { target: '[data-tour="document-joint"]', content: '📎 Si un document est joint à une demande (certificat médical par exemple), vous pouvez le consulter ici.', placement: 'left', }, { target: 'body', content: (

🎉 Vous êtes prêt à gérer votre équipe !

Vous savez maintenant valider les demandes et suivre les absences de vos collaborateurs.

💡 Astuce : Les données se mettent à jour automatiquement en temps réel. Vous recevrez des notifications pour chaque nouvelle demande.

), placement: 'center', } ]; } else { // Pour les collaborateurs/apprentis return [ ...baseSteps, { target: '[data-tour="mon-equipe"]', content: '👥 Consultez ici la liste de votre équipe. Vous pouvez voir les membres de votre service.', placement: 'left', }, { target: '[data-tour="membre-equipe"]', content: '👤 Cliquez sur un membre pour voir le détail de ses informations et absences.', placement: 'left', }, { target: 'body', content: (

✅ C'est tout pour cette section !

Vous pouvez maintenant consulter votre équipe facilement.

💡 Besoin d'aide ? N'hésitez pas à contacter votre manager pour toute question.

), placement: 'center', } ]; } } // ==================== CALENDAR ==================== if (location.pathname === '/calendar') { const baseSteps = [ { target: 'body', content: (

📅 Bienvenue dans le calendrier !

Découvrez comment visualiser et gérer les congés {canViewAllFilters ? 'de toute l\'entreprise' : 'de votre équipe'}.

), placement: 'center', disableBeacon: true, }, { target: '[data-tour="pto-counter"]', content: '📊 Votre solde PTO (Paid Time Off) total : somme de vos CP N-1, CP N et RTT disponibles.', placement: 'bottom', }, { target: '[data-tour="navigation-mois"]', content: '◀️▶️ Naviguez entre les mois pour consulter les congés passés et à venir.', placement: 'bottom', } ]; // Étapes pour les filtres selon le rôle if (canViewAllFilters) { baseSteps.push( { target: '[data-tour="filtres-btn"]', content: '🔍 Accédez aux filtres pour affiner votre vue : société, campus, service, collaborateurs...', placement: 'left', }, { target: '[data-tour="filtre-societe"]', content: '🏢 Filtrez par société pour voir uniquement les congés d\'une entité spécifique.', placement: 'bottom', }, { target: '[data-tour="filtre-campus"]', content: '🏫 Filtrez par campus pour visualiser les absences par site géographique.', placement: 'bottom', }, { target: '[data-tour="filtre-service"]', content: '👔 Filtrez par service pour voir les congés d\'un département spécifique.', placement: 'bottom', } ); } // Étapes communes pour tous baseSteps.push( { target: '[data-tour="selection-collaborateurs"]', content: '👥 Sélectionnez les collaborateurs que vous souhaitez afficher dans le calendrier. Pratique pour se concentrer sur certaines personnes !', placement: 'top', }, { target: '[data-tour="refresh-btn"]', content: '🔄 Rafraîchissez manuellement les données. Mais rassurez-vous : elles se mettent à jour automatiquement en temps réel via SSE !', placement: 'left', }, { target: 'body', content: (

📅 Sélectionner des dates

Vous pouvez sélectionner des dates directement dans le calendrier pour créer une demande de congé rapidement.

), placement: 'center', }, { target: '[data-tour="calendar-grid"]', content: '🖱️ Cliquez sur une date de début, puis sur une date de fin pour sélectionner une période. Un menu contextuel apparaîtra pour choisir le type de congé.', placement: 'top', }, { target: '[data-tour="legende"]', content: '🎨 La légende vous aide à identifier les différents types de congés : validés (vert), en attente (orange), formation (bleu), etc.', placement: 'top', }, { target: 'body', content: (

🎉 Vous maîtrisez le calendrier !

Vous savez maintenant visualiser les congés, filtrer par équipe et créer rapidement des demandes.

💡 Astuce : Survolez une case de congé pour voir tous les détails (employé, type, période, statut). Sur mobile, appuyez sur la case !

), placement: 'center', } ); return baseSteps; } return []; }; // 🎯 Obtenir la clé localStorage selon la page const getTutorialKey = () => { if (location.pathname === '/dashboard') return 'dashboard'; if (location.pathname === '/manager') return 'manager'; if (location.pathname === '/calendar') return 'calendar'; return ''; }; // 🎯 Gérer la fin du tutoriel const handleJoyrideCallback = (data) => { const { status } = data; const finishedStatuses = [STATUS.FINISHED, STATUS.SKIPPED]; if (finishedStatuses.includes(status)) { setRunTour(false); setDontShowAgain(false); } }; // Si on n'a pas d'étapes disponibles, ne rien afficher if (availableSteps.length === 0) return null; return ( { const [showConfirmModal, setShowConfirmModal] = React.useState(false); const tutorialKey = getTutorialKey(); const handleFinish = () => { if (dontShowAgain) { localStorage.setItem(`${tutorialKey}-tutorial-completed-${userId}`, 'true'); } setRunTour(false); setDontShowAgain(false); }; const handleSkip = () => { if (dontShowAgain) { setShowConfirmModal(true); } else { setRunTour(false); setDontShowAgain(false); } }; const confirmSkip = () => { localStorage.setItem(`${tutorialKey}-tutorial-completed-${userId}`, 'true'); setShowConfirmModal(false); setRunTour(false); setDontShowAgain(false); }; const cancelSkip = () => { setShowConfirmModal(false); setDontShowAgain(false); }; return ( <> {/* Modal de confirmation */} {showConfirmModal && (
{ if (e.target === e.currentTarget) { cancelSkip(); } }}>
⚠️

Ne plus afficher le tutoriel ?

Êtes-vous sûr de vouloir désactiver définitivement ce tutoriel ? {tutorialKey === 'dashboard' && ' Vous pourrez le réactiver plus tard en cliquant sur le bouton "Aide".'}

)} {/* Tooltip principal */}
{step.content}
{/* Case à cocher "Ne plus afficher" */}
setDontShowAgain(e.target.checked)} style={{ width: '18px', height: '18px', cursor: 'pointer', accentColor: '#0891b2' }} />
Étape {index + 1} sur {size}
{index > 0 && ( )} {!isLastStep && ( )} {isLastStep && ( )}
); }} /> ); }; export default GlobalTutorial;