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.
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: (
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".'}