diff --git a/.vs/RGC/CopilotIndices/17.14.1577.30250/CodeChunks.db b/.vs/RGC/CopilotIndices/17.14.1577.30250/CodeChunks.db index 3e14a5a..a2a3716 100644 Binary files a/.vs/RGC/CopilotIndices/17.14.1577.30250/CodeChunks.db and b/.vs/RGC/CopilotIndices/17.14.1577.30250/CodeChunks.db differ diff --git a/.vs/RGC/CopilotIndices/17.14.1577.30250/CodeChunks.db-shm b/.vs/RGC/CopilotIndices/17.14.1577.30250/CodeChunks.db-shm index 9b7ec2a..332515f 100644 Binary files a/.vs/RGC/CopilotIndices/17.14.1577.30250/CodeChunks.db-shm and b/.vs/RGC/CopilotIndices/17.14.1577.30250/CodeChunks.db-shm differ diff --git a/.vs/RGC/CopilotIndices/17.14.1577.30250/CodeChunks.db-wal b/.vs/RGC/CopilotIndices/17.14.1577.30250/CodeChunks.db-wal index cdda5d5..b716260 100644 Binary files a/.vs/RGC/CopilotIndices/17.14.1577.30250/CodeChunks.db-wal and b/.vs/RGC/CopilotIndices/17.14.1577.30250/CodeChunks.db-wal differ diff --git a/.vs/RGC/CopilotIndices/17.14.1577.30250/SemanticSymbols.db b/.vs/RGC/CopilotIndices/17.14.1577.30250/SemanticSymbols.db index 92cf262..4ae7c2d 100644 Binary files a/.vs/RGC/CopilotIndices/17.14.1577.30250/SemanticSymbols.db and b/.vs/RGC/CopilotIndices/17.14.1577.30250/SemanticSymbols.db differ diff --git a/.vs/RGC/CopilotIndices/17.14.1577.30250/SemanticSymbols.db-shm b/.vs/RGC/CopilotIndices/17.14.1577.30250/SemanticSymbols.db-shm index 3f49034..a30721d 100644 Binary files a/.vs/RGC/CopilotIndices/17.14.1577.30250/SemanticSymbols.db-shm and b/.vs/RGC/CopilotIndices/17.14.1577.30250/SemanticSymbols.db-shm differ diff --git a/.vs/RGC/CopilotIndices/17.14.1577.30250/SemanticSymbols.db-wal b/.vs/RGC/CopilotIndices/17.14.1577.30250/SemanticSymbols.db-wal index d9e4866..2dae5ee 100644 Binary files a/.vs/RGC/CopilotIndices/17.14.1577.30250/SemanticSymbols.db-wal and b/.vs/RGC/CopilotIndices/17.14.1577.30250/SemanticSymbols.db-wal differ diff --git a/.vs/RGC/v17/.wsuo b/.vs/RGC/v17/.wsuo index cdb06f4..717c5bd 100644 Binary files a/.vs/RGC/v17/.wsuo and b/.vs/RGC/v17/.wsuo differ diff --git a/.vs/RGC/v17/DocumentLayout.backup.json b/.vs/RGC/v17/DocumentLayout.backup.json index 14f170b..7fd02b7 100644 --- a/.vs/RGC/v17/DocumentLayout.backup.json +++ b/.vs/RGC/v17/DocumentLayout.backup.json @@ -50,6 +50,10 @@ { "$type": "Bookmark", "Name": "ST:131:0:{1fc202d4-d401-403c-9834-5b218574bb67}" + }, + { + "$type": "Bookmark", + "Name": "ST:0:0:{1c4feeaa-4718-4aa9-859d-94ce25d182ba}" } ] } diff --git a/.vs/RGC/v17/DocumentLayout.json b/.vs/RGC/v17/DocumentLayout.json index 7fd02b7..22bed45 100644 --- a/.vs/RGC/v17/DocumentLayout.json +++ b/.vs/RGC/v17/DocumentLayout.json @@ -1,7 +1,12 @@ { "Version": 1, "WorkspaceRootPath": "C:\\Users\\oimer\\source\\repos\\RGC\\", - "Documents": [], + "Documents": [ + { + "AbsoluteMoniker": "D:0:0:{A2FE74E1-B743-11D0-AE1A-00A0C90FFFC3}|\u003CMiscFiles\u003E|C:\\Users\\oimer\\source\\repos\\RGC\\SuiviREForamteur\\suivireforamteur\\src\\HistoriquePage.tsx||{0F2454B1-A556-402D-A7D0-1FDE7F99DEE0}", + "RelativeMoniker": "D:0:0:{A2FE74E1-B743-11D0-AE1A-00A0C90FFFC3}|\u003CMiscFiles\u003E|solutionrelative:SuiviREForamteur\\suivireforamteur\\src\\HistoriquePage.tsx||{0F2454B1-A556-402D-A7D0-1FDE7F99DEE0}" + } + ], "DocumentGroupContainers": [ { "Orientation": 0, @@ -9,7 +14,7 @@ "DocumentGroups": [ { "DockedWidth": 200, - "SelectedChildIndex": -1, + "SelectedChildIndex": 11, "Children": [ { "$type": "Bookmark", @@ -54,6 +59,19 @@ { "$type": "Bookmark", "Name": "ST:0:0:{1c4feeaa-4718-4aa9-859d-94ce25d182ba}" + }, + { + "$type": "Document", + "DocumentIndex": 0, + "Title": "HistoriquePage.tsx", + "DocumentMoniker": "C:\\Users\\oimer\\source\\repos\\RGC\\SuiviREForamteur\\suivireforamteur\\src\\HistoriquePage.tsx", + "RelativeDocumentMoniker": "SuiviREForamteur\\suivireforamteur\\src\\HistoriquePage.tsx", + "ToolTip": "C:\\Users\\oimer\\source\\repos\\RGC\\SuiviREForamteur\\suivireforamteur\\src\\HistoriquePage.tsx", + "RelativeToolTip": "SuiviREForamteur\\suivireforamteur\\src\\HistoriquePage.tsx", + "ViewState": "AgIAAEIFAAAAAAAAAAAEwFAFAAALAAAAAAAAAA==", + "Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.003213|", + "WhenOpened": "2026-02-13T08:45:05.704Z", + "EditorCaption": "" } ] } diff --git a/.vs/VSWorkspaceState.json b/.vs/VSWorkspaceState.json index bfe6639..a768aa5 100644 --- a/.vs/VSWorkspaceState.json +++ b/.vs/VSWorkspaceState.json @@ -2,7 +2,10 @@ "ExpandedNodes": [ "", "\\SuiviREForamteur", - "\\SuiviREForamteur\\suivireforamteur" + "\\SuiviREForamteur\\suivireforamteur", + "\\SuiviREForamteur\\suivireforamteur\\public", + "\\SuiviREForamteur\\suivireforamteur\\src" ], + "SelectedNode": "\\SuiviREForamteur\\suivireforamteur\\src\\HistoriquePage.tsx", "PreviewInSolutionExplorer": false } \ No newline at end of file diff --git a/.vs/slnx.sqlite b/.vs/slnx.sqlite index 4779d64..a7a99bb 100644 Binary files a/.vs/slnx.sqlite and b/.vs/slnx.sqlite differ diff --git a/SuiviREForamteur/suivireforamteur/src/HistoriquePage.tsx b/SuiviREForamteur/suivireforamteur/src/HistoriquePage.tsx index 6902210..62dcec2 100644 --- a/SuiviREForamteur/suivireforamteur/src/HistoriquePage.tsx +++ b/SuiviREForamteur/suivireforamteur/src/HistoriquePage.tsx @@ -941,6 +941,188 @@ body { min-width: 800px; } } +/* ✨ Bouton Tutoriel */ +.tutorial-button { + background: linear-gradient(135deg, #8b5cf6 0%, #7c3aed 100%); + color: white; + border: none; + padding: 0.5rem 1rem; + border-radius: 12px; + cursor: pointer; + font-weight: 600; + display: flex; + align-items: center; + gap: 0.4rem; + transition: all 0.3s ease; + font-size: 0.85rem; + white-space: nowrap; + box-shadow: 0 2px 4px rgba(139, 92, 246, 0.3); +} + +.tutorial-button:hover { + background: linear-gradient(135deg, #7c3aed 0%, #6d28d9 100%); + transform: translateY(-2px); + box-shadow: 0 6px 12px rgba(139, 92, 246, 0.4); +} + +/* ✨ Modal Tutoriel */ +.tutorial-modal-overlay { + position: fixed; + top: 0; + left: 0; + right: 0; + bottom: 0; + background: rgba(0, 0, 0, 0.7); + backdrop-filter: blur(8px); + display: flex; + align-items: center; + justify-content: center; + z-index: 2000; + padding: 1rem; + animation: fadeIn 0.3s ease-out; +} + +@keyframes fadeIn { + from { opacity: 0; } + to { opacity: 1; } +} + +.tutorial-modal { + background: white; + border-radius: 24px; + box-shadow: 0 25px 50px -12px rgba(0, 0, 0, 0.3); + max-width: 700px; + width: 100%; + overflow: hidden; + animation: slideIn 0.4s ease-out; +} + +@keyframes slideIn { + from { + opacity: 0; + transform: translateY(30px) scale(0.95); + } + to { + opacity: 1; + transform: translateY(0) scale(1); + } +} + +.tutorial-modal-header { + background: linear-gradient(135deg, #8b5cf6 0%, #7c3aed 100%); + color: white; + padding: 2rem; + text-align: center; +} + +.tutorial-modal-header h2 { + font-size: 1.8rem; + margin-bottom: 0.5rem; + font-weight: 700; +} + +.tutorial-modal-header p { + font-size: 1rem; + opacity: 0.95; +} + +.tutorial-modal-content { + padding: 2rem; + max-height: 60vh; + overflow-y: auto; +} + +.tutorial-step-list { + list-style: none; + margin: 1rem 0; +} + +.tutorial-step-list li { + padding: 1rem; + margin-bottom: 0.75rem; + background: #f8fafc; + border-radius: 12px; + border-left: 4px solid #8b5cf6; + display: flex; + align-items: start; + gap: 0.75rem; + transition: all 0.3s ease; +} + +.tutorial-step-list li:hover { + background: #ede9fe; + transform: translateX(5px); +} + +.tutorial-step-icon { + font-size: 1.5rem; + flex-shrink: 0; +} + +.tutorial-step-content { + flex: 1; +} + +.tutorial-step-title { + font-weight: 600; + color: #1e293b; + margin-bottom: 0.25rem; + font-size: 1rem; +} + +.tutorial-step-desc { + color: #64748b; + font-size: 0.9rem; + line-height: 1.5; +} + +.tutorial-highlight-box { + background: linear-gradient(135deg, #dcfce7 0%, #bbf7d0 100%); + padding: 1rem; + border-radius: 12px; + border-left: 4px solid #22c55e; + margin: 1rem 0; +} + +.tutorial-highlight-box strong { + color: #166534; + display: block; + margin-bottom: 0.5rem; + font-size: 1rem; +} + +.tutorial-highlight-box p { + color: #14532d; + line-height: 1.6; + font-size: 0.9rem; +} + +.tutorial-modal-footer { + padding: 1.5rem 2rem; + background: #f8fafc; + text-align: center; +} + +.tutorial-close-button { + background: linear-gradient(135deg, #22c55e 0%, #16a34a 100%); + color: white; + border: none; + padding: 0.75rem 2rem; + border-radius: 12px; + font-weight: 700; + cursor: pointer; + font-size: 1rem; + display: inline-flex; + align-items: center; + gap: 0.5rem; + transition: all 0.3s ease; + box-shadow: 0 4px 6px -1px rgba(34, 197, 94, 0.3); +} + +.tutorial-close-button:hover { + transform: translateY(-3px); + box-shadow: 0 10px 20px -5px rgba(34, 197, 94, 0.4); +} `; // ═══════════════════════════════════════════════════════ @@ -1106,6 +1288,7 @@ const HistoriquePage: React.FC = ({ const [editCommentaireFormateur, setEditCommentaireFormateur] = useState(''); const [editDateEvalTuteur, setEditDateEvalTuteur] = useState(''); const [editCommentaireRRE, setEditCommentaireRRE] = useState(''); + const [showTutorial, setShowTutorial] = useState(false); // ✅ Vérifier si l'utilisateur peut modifier (pas lecteur) const effectiveRole = impersonatedUser?.role || user.role; @@ -1316,18 +1499,21 @@ const HistoriquePage: React.FC = ({ }, [records, filter, campusFilter, promoFilter, studentFilter]); const dynamicStatusCounts = useMemo(() => { - // OUI = les deux sont OUI - const oui = preFilteredRecords.filter(r => - r.autoEvaluation === 'OUI' && r.evaluationTuteur === 'OUI' - ).length; + let oui = 0; + let partiel = 0; + let non = 0; - // PARTIEL = les deux sont PARTIEL - const partiel = preFilteredRecords.filter(r => - r.autoEvaluation === 'PARTIEL' && r.evaluationTuteur === 'PARTIEL' - ).length; + preFilteredRecords.forEach(r => { + // Compter auto-évaluation + if (r.autoEvaluation === 'OUI') oui++; + else if (r.autoEvaluation === 'PARTIEL') partiel++; + else non++; // NON ou vide - // NON = tout le reste (combinaisons mixtes, NON, vide, etc.) - const non = preFilteredRecords.length - oui - partiel; + // Compter évaluation tuteur + if (r.evaluationTuteur === 'OUI') oui++; + else if (r.evaluationTuteur === 'PARTIEL') partiel++; + else non++; // NON ou vide + }); return { tous: preFilteredRecords.length, @@ -1342,19 +1528,16 @@ const HistoriquePage: React.FC = ({ if (statusFilter === 'tous') return true; if (statusFilter === 'OUI') { - return r.autoEvaluation === 'OUI' && r.evaluationTuteur === 'OUI'; + return r.autoEvaluation === 'OUI' || r.evaluationTuteur === 'OUI'; } if (statusFilter === 'PARTIEL') { - // PARTIEL = les deux sont PARTIEL - return r.autoEvaluation === 'PARTIEL' && r.evaluationTuteur === 'PARTIEL'; + return r.autoEvaluation === 'PARTIEL' || r.evaluationTuteur === 'PARTIEL'; } if (statusFilter === 'NON') { - // NON = tout ce qui n'est ni OUI/OUI ni PARTIEL/PARTIEL - const isOui = r.autoEvaluation === 'OUI' && r.evaluationTuteur === 'OUI'; - const isPartiel = r.autoEvaluation === 'PARTIEL' && r.evaluationTuteur === 'PARTIEL'; - return !isOui && !isPartiel; + return r.autoEvaluation === 'NON' || !r.autoEvaluation || + r.evaluationTuteur === 'NON' || !r.evaluationTuteur; } return true; @@ -1800,6 +1983,10 @@ const HistoriquePage: React.FC = ({
{displayName} + {/* ✨ Bouton Tutoriel */} + @@ -2525,6 +2712,96 @@ const HistoriquePage: React.FC = ({
, document.body )} + {/* ✨ Modal Tutoriel */} + {showTutorial && createPortal( +
setShowTutorial(false)}> +
e.stopPropagation()}> +
+

📜 Tutoriel - Page Historique

+

Guide rapide d'utilisation

+
+ +
+

+ 🎯 Comment utiliser cette page ? +

+ +
    +
  • + 🔍 +
    +
    Rechercher et filtrer
    +
    + Utilisez la barre de recherche et les filtres (Campus, Promotion, Étudiant, Statut) + pour trouver rapidement les apprenants. +
    +
    +
  • + +
  • + 👁️ +
    +
    Voir l'historique complet
    +
    + Cliquez sur l'icône 👁️ pour ouvrir la fenêtre de détail avec l'historique + complet des modifications et le formulaire de saisie. +
    +
    +
  • + +
  • + ✏️ +
    +
    Ajouter une nouvelle action
    +
    + Dans la fenêtre de détail, remplissez le formulaire selon votre rôle + (Auto-éval, Éval tuteur, Date, Commentaires) puis cliquez sur "Ajouter l'action". +
    +
    +
  • + +
  • + 📄 +
    +
    Exporter en PDF
    +
    + Cliquez sur l'icône 📄 pour générer et télécharger un PDF complet + avec toutes les données et l'historique de l'apprenant. +
    +
    +
  • + +
  • + 📊 +
    +
    Trier les données
    +
    + Cliquez sur n'importe quel en-tête de colonne (Nom, Date, Statut...) + pour trier les résultats par ordre croissant ou décroissant. +
    +
    +
  • +
+ +
+ 💡 Bon à savoir +

+ Toutes les modifications sont enregistrées. + L'historique est permanent et assure une traçabilité complète de chaque dossier. +

+
+
+ +
+ +
+
+
, + document.body + )} ); };