OUAREDAEK commited on
Commit
cbc515a
·
verified ·
1 Parent(s): 625dd0c

Upload templates/index.html with huggingface_hub

Browse files
Files changed (1) hide show
  1. templates/index.html +676 -242
templates/index.html CHANGED
@@ -13,6 +13,7 @@ body {
13
  margin: 0;
14
  padding: 20px;
15
  color: #333;
 
16
  }
17
 
18
  h2, h3, h4 {
@@ -70,6 +71,7 @@ h3::before {
70
  padding: 5px;
71
  margin-bottom: 20px;
72
  border: 1px solid #e0e0e0;
 
73
  }
74
 
75
  .tab-btn {
@@ -87,6 +89,7 @@ h3::before {
87
  align-items: center;
88
  justify-content: center;
89
  gap: 10px;
 
90
  }
91
 
92
  .tab-btn:hover {
@@ -119,6 +122,7 @@ h3::before {
119
  padding: 15px 25px;
120
  border-radius: 12px;
121
  border: 1px solid #bbdefb;
 
122
  }
123
 
124
  #scenarioTitle {
@@ -127,6 +131,7 @@ h3::before {
127
  text-align: center;
128
  flex-grow: 1;
129
  margin: 0 20px;
 
130
  }
131
 
132
  button {
@@ -143,6 +148,7 @@ button {
143
  display: flex;
144
  align-items: center;
145
  gap: 8px;
 
146
  }
147
 
148
  button:hover:not(:disabled) {
@@ -160,41 +166,6 @@ button:disabled {
160
  background: #b0bec5;
161
  }
162
 
163
- /* ================= BOUTON LECTURE CROISÉE ================= */
164
- #crossReadersBtn {
165
- background: linear-gradient(135deg, #43A047, #4CAF50) !important;
166
- color: white;
167
- border: none;
168
- padding: 12px 25px;
169
- border-radius: 10px;
170
- cursor: pointer;
171
- font-weight: 600;
172
- font-size: 15px;
173
- transition: all 0.3s ease;
174
- box-shadow: 0 3px 8px rgba(67, 160, 71, 0.2);
175
- display: flex;
176
- align-items: center;
177
- justify-content: center;
178
- gap: 8px;
179
- width: 100%;
180
- }
181
-
182
- #crossReadersBtn:hover:not(:disabled) {
183
- transform: translateY(-2px);
184
- box-shadow: 0 5px 15px rgba(67, 160, 71, 0.3);
185
- background: linear-gradient(135deg, #388E3C, #43A047) !important;
186
- }
187
-
188
- #crossReadersBtn:active:not(:disabled) {
189
- transform: translateY(0);
190
- }
191
-
192
- #crossReadersBtn:disabled {
193
- opacity: 0.5;
194
- cursor: not-allowed;
195
- background: #b0bec5 !important;
196
- }
197
-
198
  /* ================= ONGLET 1: ÉVALUATEUR GDPR ================= */
199
  #tab-evaluator .evaluator-info {
200
  background: linear-gradient(135deg, #fff3e0, #ffe0b2);
@@ -792,6 +763,16 @@ textarea:focus {
792
  }
793
 
794
  /* ================= BARRE DE CONFIANCE ================= */
 
 
 
 
 
 
 
 
 
 
795
  #trustBar {
796
  height: 100%;
797
  border-radius: 10px;
@@ -805,6 +786,11 @@ textarea:focus {
805
  overflow: hidden;
806
  width: 0%;
807
  background: #e0e0e0;
 
 
 
 
 
808
  }
809
 
810
  #trustBar::after {
@@ -822,9 +808,39 @@ textarea:focus {
822
  animation: shimmer 2s infinite;
823
  }
824
 
825
- @keyframes shimmer {
826
- 0% { transform: translateX(-100%); }
827
- 100% { transform: translateX(100%); }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
828
  }
829
 
830
  /* ================= MESSAGES ================= */
@@ -875,6 +891,151 @@ textarea:focus {
875
  font-weight: 500;
876
  }
877
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
878
  /* ================= ANIMATIONS ================= */
879
  @keyframes fadeIn {
880
  from { opacity: 0; transform: translateY(20px); }
@@ -897,88 +1058,14 @@ textarea:focus {
897
  100% { transform: scale(1); }
898
  }
899
 
900
- /* ================= RESPONSIVE ================= */
901
- @media (max-width: 1200px) {
902
- #reflection {
903
- padding: 20px;
904
- }
905
-
906
- .tabs {
907
- flex-direction: column;
908
- }
909
-
910
- .tab-btn {
911
- width: 100%;
912
- }
913
- }
914
-
915
- @media (max-width: 768px) {
916
- body {
917
- padding: 10px;
918
- }
919
-
920
- .nav {
921
- flex-direction: column;
922
- gap: 15px;
923
- text-align: center;
924
- }
925
-
926
- #scenarioTitle {
927
- margin: 10px 0;
928
- font-size: 1.2em;
929
- }
930
-
931
- button {
932
- width: 100%;
933
- justify-content: center;
934
- }
935
-
936
- .gdpr-options {
937
- flex-direction: column;
938
- gap: 10px;
939
- }
940
-
941
- .gdpr-option {
942
- min-width: 100%;
943
- }
944
-
945
- .compact-competences-grid {
946
- grid-template-columns: repeat(auto-fill, minmax(150px, 1fr));
947
- }
948
-
949
- .compact-radar-metrics-grid {
950
- grid-template-columns: repeat(auto-fill, minmax(150px, 1fr));
951
- }
952
-
953
- .compact-radar-legend {
954
- flex-direction: column;
955
- align-items: center;
956
- gap: 8px;
957
- }
958
-
959
- .compact-legend-grid {
960
- grid-template-columns: repeat(2, 1fr);
961
- }
962
-
963
- .compact-analysis-controls {
964
- flex-direction: column;
965
- align-items: stretch;
966
- }
967
-
968
- .compact-persistence-indicators {
969
- flex-direction: column;
970
- }
971
  }
972
 
973
- /* ================= PROGRESS BAR CONTAINER ================= */
974
- .progress-container {
975
- width: 100%;
976
- background: #f5f5f5;
977
- border-radius: 12px;
978
- height: 24px;
979
- margin: 8px 0 20px;
980
- overflow: hidden;
981
- box-shadow: inset 0 2px 5px rgba(0,0,0,0.1);
982
  }
983
 
984
  /* ================= TOOLTIPS ================= */
@@ -1040,11 +1127,6 @@ textarea:focus {
1040
  animation: spin 1s linear infinite;
1041
  }
1042
 
1043
- @keyframes spin {
1044
- 0% { transform: rotate(0deg); }
1045
- 100% { transform: rotate(360deg); }
1046
- }
1047
-
1048
  /* ================= NOTIFICATIONS ================= */
1049
  .notification {
1050
  position: fixed;
@@ -1094,6 +1176,112 @@ textarea:focus {
1094
  font-size: 20px;
1095
  line-height: 1;
1096
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1097
  </style>
1098
  </head>
1099
 
@@ -1120,6 +1308,9 @@ textarea:focus {
1120
  <button class="tab-btn" data-tab="tab-evaluation">
1121
  <span>🤖</span> Message Réflexif & Évaluation
1122
  </button>
 
 
 
1123
  </div>
1124
 
1125
  <!-- ONGLET 1: INFORMATIONS ÉVALUATEUR GDPR -->
@@ -1213,7 +1404,7 @@ textarea:focus {
1213
  </div>
1214
 
1215
  <!-- Boutons d'action -->
1216
- <div style="display: flex; gap: 10px; margin-top: 20px;">
1217
  <button onclick="fillSampleEvaluator()" type="button" style="background: #666; flex: 1;" id="fillExampleBtn">
1218
  <span style="margin-right: 5px;">📋</span> Remplir exemple
1219
  </button>
@@ -1439,11 +1630,11 @@ textarea:focus {
1439
  <h4>💬 Commentaire expert</h4>
1440
  <textarea id="trustComment" placeholder="Ajoutez vos observations, suggestions ou critiques concernant l'analyse de ReflAgent..."></textarea>
1441
 
1442
- <div style="display: flex; justify-content: space-between; align-items: center; margin: 25px 0;">
1443
- <div style="flex-grow: 1; margin-right: 20px;">
1444
  <h4 style="margin-bottom: 10px;">🔒 Indice global de confiance</h4>
1445
  <div class="progress-container">
1446
- <div class="fill" id="trustBar">0%</div>
1447
  </div>
1448
  <div style="display: flex; justify-content: space-between; margin-top: 5px; font-size: 12px; color: #666;">
1449
  <span>Faible confiance</span>
@@ -1451,9 +1642,9 @@ textarea:focus {
1451
  <span>Forte confiance</span>
1452
  </div>
1453
  </div>
1454
- <div style="display: flex; flex-direction: column; gap: 10px; align-items: flex-end;">
1455
  <button id="saveTrustBtn" style="height: fit-content; width: 100%;">💾 Sauvegarder l'évaluation</button>
1456
- <button id="crossReadersBtn" style="height: fit-content; width: 100%; background: linear-gradient(135deg, #43A047, #4CAF50);">
1457
  📊 Lecture croisée
1458
  </button>
1459
  </div>
@@ -1481,6 +1672,87 @@ textarea:focus {
1481
  </div>
1482
  </div>
1483
  </div>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1484
  </div>
1485
  </div>
1486
 
@@ -1614,6 +1886,11 @@ document.addEventListener("DOMContentLoaded", () => {
1614
 
1615
  // Initialiser la barre de confiance à 0%
1616
  updateTrustBar();
 
 
 
 
 
1617
  });
1618
 
1619
  // ================= SYSTEME D'ONGLETS =================
@@ -1683,46 +1960,108 @@ function initGDPR() {
1683
  // ================= CHARGEMENT JSON =================
1684
  function loadScenarios() {
1685
  console.log("Chargement des scénarios...");
1686
- fetch("/static/scenarios.json")
1687
- .then(r => {
1688
- if (!r.ok) throw new Error("Erreur de chargement du fichier JSON");
1689
- return r.json();
1690
- })
1691
- .then(data => {
1692
- console.log("Scénarios chargés:", data.scenarios.length);
1693
- scenarios = data.scenarios;
1694
- loadScenario(0);
1695
- })
1696
- .catch(error => {
1697
- console.error("Erreur:", error);
1698
- document.getElementById("manifest-list").innerHTML =
1699
- `<div class="manifest-item" style="background:#FFEBEE;color:#C62828;">
1700
- Erreur de chargement des scénarios. Vérifiez que le fichier scenarios.json existe.
1701
- </div>`;
1702
- });
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1703
  }
1704
 
1705
  // ================= CHARGER SCÉNARIO =================
1706
  function loadScenario(index) {
1707
  console.log("Chargement scénario", index);
1708
- if (index < 0 || index >= scenarios.length) return;
 
 
 
 
 
 
 
 
 
1709
  currentScenarioIndex = index;
1710
  const s = scenarios[index];
1711
 
1712
  // Mettre à jour le titre
1713
  const titleElement = document.getElementById("scenarioTitle");
1714
- titleElement.textContent = `Scénario ${s.id} – ${s.title}`;
 
 
1715
 
1716
  // Mettre à jour le manifeste
1717
- document.getElementById("manifest-list").innerHTML = `
1718
- <div class="manifest-item">
1719
- <b>Type de Manifest :</b> ${s.manifest.type}<br>
1720
- <b>Manifeste (écrit par l'étudiant) :</b> ${s.manifest.manifeste}<br>
1721
- <b>Description du Profil :</b> ${s.manifest.description}
1722
- </div>`;
 
 
 
1723
 
1724
  // Mettre à jour les compétences compactes
1725
- updateCompactCompetences(s.competences);
 
 
1726
 
1727
  // Mettre à jour le radar avec les nouvelles métriques
1728
  if (s.radar && s.radar.length > 0) {
@@ -1756,13 +2095,19 @@ function loadScenario(index) {
1756
  updatePerseveranceProfile(s.title);
1757
 
1758
  // Mettre à jour le message ReflAgent
1759
- document.getElementById("reflagent").textContent = s.reflAgent;
 
 
 
1760
 
1761
  // Mettre à jour les boutons de navigation
1762
  updateNavButtons();
1763
 
1764
  // Mettre à jour les statistiques
1765
- updateStats();
 
 
 
1766
  }
1767
 
1768
  // ================= FONCTIONS POUR LA VERSION COMPACTE =================
@@ -1774,6 +2119,11 @@ function updateCompactCompetences(competences) {
1774
 
1775
  container.innerHTML = '';
1776
 
 
 
 
 
 
1777
  competences.forEach(comp => {
1778
  // Déterminer la couleur selon la valeur
1779
  let color;
@@ -1807,6 +2157,11 @@ function updateCompactRadarMetricsGrid() {
1807
 
1808
  grid.innerHTML = '';
1809
 
 
 
 
 
 
1810
  radarMetrics.forEach(metric => {
1811
  // Déterminer la classe de couleur selon la valeur
1812
  let colorClass = "";
@@ -1951,6 +2306,7 @@ function drawCompactEnrichedHeatmap(scenario) {
1951
  const weeks = 4;
1952
  const totalDays = weeks * 7;
1953
 
 
1954
  ctx.clearRect(0, 0, canvas.width, canvas.height);
1955
 
1956
  // Titre enrichi
@@ -2027,6 +2383,16 @@ function updatePerseveranceProfile(scenarioTitle) {
2027
 
2028
  if (!profile) {
2029
  console.warn(`Aucun profil de persévérance trouvé pour: ${scenarioTitle}`);
 
 
 
 
 
 
 
 
 
 
2030
  return;
2031
  }
2032
 
@@ -2155,12 +2521,15 @@ function analyzeCompactPersistenceMetrics(activityData, scenarioId) {
2155
  }
2156
 
2157
  // Mettre à jour l'interface compacte
2158
- document.getElementById("compact-regularityScore").textContent = Math.round(regularity) + "%";
2159
- document.getElementById("compact-effortPattern").textContent = pattern;
2160
- document.getElementById("compact-deadlineScore").textContent = Math.round(deadlineScore) + "%";
 
2161
 
2162
- // Mettre à jour l'analyse textuelle compacte
2163
- document.getElementById("compact-patternText").textContent = patternDescription;
 
 
2164
  }
2165
 
2166
  // ================= RADAR =================
@@ -2174,7 +2543,7 @@ function drawRadar() {
2174
  const ctx = canvas.getContext("2d");
2175
  const cx = canvas.width / 2;
2176
  const cy = canvas.height / 2;
2177
- const radius = 200;
2178
  const n = radarMetrics.length;
2179
 
2180
  ctx.clearRect(0, 0, canvas.width, canvas.height);
@@ -2205,7 +2574,13 @@ function drawRadar() {
2205
  ctx.fillStyle = "#000";
2206
  ctx.textAlign = angle > Math.PI / 2 || angle < -Math.PI / 2 ? "right" : "left";
2207
  ctx.textBaseline = "middle";
2208
- ctx.fillText(`${m.label.split(' ')[0]}`, tx, ty);
 
 
 
 
 
 
2209
  });
2210
 
2211
  // Dessiner le polygone
@@ -2240,21 +2615,19 @@ function drawRadar() {
2240
  }
2241
 
2242
  // ================= NAVIGATION =================
2243
- document.getElementById("prevScenario").onclick = () =>
2244
- loadScenario(currentScenarioIndex - 1);
2245
-
2246
- document.getElementById("nextScenario").onclick = () =>
2247
- loadScenario(currentScenarioIndex + 1);
2248
-
2249
  function updateNavButtons() {
2250
- document.getElementById("prevScenario").disabled =
2251
- currentScenarioIndex === 0;
2252
- document.getElementById("nextScenario").disabled =
2253
- currentScenarioIndex === scenarios.length - 1;
 
 
 
 
2254
  }
2255
 
2256
  // ================= BOUTON LECTURE CROISÉE =================
2257
- document.getElementById('crossReadersBtn').onclick = () => {
2258
  console.log('Navigation vers la page de lecture croisée...');
2259
 
2260
  // Animation de transition
@@ -2266,9 +2639,47 @@ document.getElementById('crossReadersBtn').onclick = () => {
2266
 
2267
  // Redirection
2268
  setTimeout(() => {
2269
- window.location.href = 'cross_reading/cross_readers.html';
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2270
  }, 300);
2271
- };
2272
 
2273
  // ================= MÉTRIQUES DE CONFIANCE =================
2274
  function initTrustStars(){
@@ -2304,9 +2715,11 @@ function initTrustStars(){
2304
 
2305
  // Stocker la valeur dans un attribut data
2306
  star.dataset.value = i;
 
2307
 
2308
  star.onclick = function() {
2309
  const value = parseInt(this.dataset.value);
 
2310
  console.log(`Clic sur ${metric}: ${value} étoiles`);
2311
 
2312
  // Mettre à jour la valeur de la métrique
@@ -2569,54 +2982,48 @@ function initTrustSave(){
2569
 
2570
  console.log("Données à envoyer:", JSON.stringify(data, null, 2));
2571
 
2572
- // Envoyer au serveur
2573
- fetch("/save_trust", {
2574
- method: "POST",
2575
- headers: { "Content-Type": "application/json" },
2576
- body: JSON.stringify(data)
2577
- })
2578
- .then(res => {
2579
- if (!res.ok) throw new Error(`Erreur HTTP ${res.status}: ${res.statusText}`);
2580
- return res.json();
2581
- })
2582
- .then(responseData => {
2583
- console.log("✅ Réponse du serveur:", responseData);
2584
-
2585
- if (msgDiv) {
2586
- const nameDisplay = gdprAccept ? evaluatorName : "Évaluateur anonyme";
2587
- msgDiv.innerHTML = `
2588
- <div style="display: flex; align-items: center; gap: 10px;">
2589
- <div style="font-size: 24px;">✅</div>
2590
- <div>
2591
- <strong>Évaluation sauvegardée avec succès !</strong><br>
2592
- <small>Merci ${nameDisplay} pour votre contribution.</small><br>
2593
- <small><em>Indice global: ${trustScore}%</em></small>
2594
- </div>
2595
- </div>
2596
- `;
2597
- msgDiv.style.background = "#E8F5E9";
2598
- msgDiv.style.color = "#2E7D32";
2599
- msgDiv.style.padding = "15px";
2600
- }
2601
-
2602
- // Réinitialiser après succès (optionnel)
2603
- setTimeout(() => {
2604
- resetTrustEvaluation();
2605
- }, 3000);
2606
- })
2607
- .catch(error => {
2608
- console.error("❌ Erreur de sauvegarde:", error);
2609
- if (msgDiv) {
2610
- msgDiv.textContent = `❌ Erreur: ${error.message}`;
2611
- msgDiv.style.background = "#FFEBEE";
2612
- msgDiv.style.color = "#C62828";
2613
- }
2614
- });
2615
  };
2616
 
2617
  console.log("✅ Bouton de sauvegarde initialisé");
2618
  }
2619
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2620
  // Fonction pour réinitialiser l'évaluation
2621
  function resetTrustEvaluation() {
2622
  console.log("Réinitialisation de l'évaluation...");
@@ -2638,7 +3045,10 @@ function resetTrustEvaluation() {
2638
  updateTrustBar();
2639
 
2640
  // Vider le commentaire
2641
- document.getElementById("trustComment").value = "";
 
 
 
2642
 
2643
  console.log("Évaluation réinitialisée");
2644
  }
@@ -2646,33 +3056,39 @@ function resetTrustEvaluation() {
2646
  // ================= FONCTIONS UTILITAIRES =================
2647
 
2648
  // Mettre à jour les statistiques
2649
- function updateStats() {
2650
- if (!scenarios || scenarios.length === 0) return;
2651
 
2652
- const currentScenario = scenarios[currentScenarioIndex];
 
 
2653
 
2654
- document.getElementById("currentScenarioNum").textContent = currentScenario.id;
 
 
2655
 
2656
  // Niveau de risque
2657
- const risk = currentScenario.risk || 50;
2658
- let riskLevel = "Moyen";
2659
- let riskColor = "#FB8C00";
2660
-
2661
- if (risk < 40) {
2662
- riskLevel = "Faible";
2663
- riskColor = "#43A047";
2664
- } else if (risk > 70) {
2665
- riskLevel = "Élevé";
2666
- riskColor = "#E53935";
 
 
 
 
 
2667
  }
2668
 
2669
- document.getElementById("riskLevel").textContent = riskLevel;
2670
- document.getElementById("riskLevel").style.color = riskColor;
2671
-
2672
  // Activité moyenne à partir des données radar
2673
- if (currentScenario.radar && currentScenario.radar.length > 0) {
2674
- const avgRadar = currentScenario.radar.reduce((sum, item) => sum + item.value, 0) / currentScenario.radar.length;
2675
- document.getElementById("avgActivity").textContent = Math.round(avgRadar) + "%";
2676
  }
2677
  }
2678
 
@@ -2717,21 +3133,38 @@ function showNotification(title, message, type = "info") {
2717
  type === "error" ? "#FFEBEE" : "#E3F2FD";
2718
  msgDiv.style.color = type === "success" ? "#2E7D32" :
2719
  type === "error" ? "#C62828" : "#1565C0";
 
 
 
 
 
 
 
2720
  }
2721
  }
2722
 
2723
  // Changer le mode d'analyse de persévérance
2724
  function changePersistenceAnalysis() {
2725
- const mode = document.getElementById("persistenceMode").value;
 
 
 
2726
  const currentScenario = scenarios[currentScenarioIndex];
2727
 
 
 
2728
  // Redessiner la heatmap avec le mode sélectionné
2729
  drawCompactEnrichedHeatmap(currentScenario);
2730
 
2731
  // Ajouter une annotation selon le mode
2732
  const canvas = document.getElementById("heatmap");
 
 
2733
  const ctx = canvas.getContext("2d");
2734
 
 
 
 
2735
  ctx.font = "12px Arial";
2736
  ctx.fillStyle = "#1976D2";
2737
  ctx.textAlign = "center";
@@ -2758,6 +3191,7 @@ window.updateStats = updateStats;
2758
  window.showNotification = showNotification;
2759
  window.fillSampleEvaluator = fillSampleEvaluator;
2760
  window.clearEvaluatorFields = clearEvaluatorFields;
 
2761
  </script>
2762
 
2763
  </body>
 
13
  margin: 0;
14
  padding: 20px;
15
  color: #333;
16
+ min-height: 100vh;
17
  }
18
 
19
  h2, h3, h4 {
 
71
  padding: 5px;
72
  margin-bottom: 20px;
73
  border: 1px solid #e0e0e0;
74
+ flex-wrap: wrap;
75
  }
76
 
77
  .tab-btn {
 
89
  align-items: center;
90
  justify-content: center;
91
  gap: 10px;
92
+ min-width: 200px;
93
  }
94
 
95
  .tab-btn:hover {
 
122
  padding: 15px 25px;
123
  border-radius: 12px;
124
  border: 1px solid #bbdefb;
125
+ flex-wrap: wrap;
126
  }
127
 
128
  #scenarioTitle {
 
131
  text-align: center;
132
  flex-grow: 1;
133
  margin: 0 20px;
134
+ word-break: break-word;
135
  }
136
 
137
  button {
 
148
  display: flex;
149
  align-items: center;
150
  gap: 8px;
151
+ white-space: nowrap;
152
  }
153
 
154
  button:hover:not(:disabled) {
 
166
  background: #b0bec5;
167
  }
168
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
169
  /* ================= ONGLET 1: ÉVALUATEUR GDPR ================= */
170
  #tab-evaluator .evaluator-info {
171
  background: linear-gradient(135deg, #fff3e0, #ffe0b2);
 
763
  }
764
 
765
  /* ================= BARRE DE CONFIANCE ================= */
766
+ .progress-container {
767
+ width: 100%;
768
+ background: #f5f5f5;
769
+ border-radius: 12px;
770
+ height: 24px;
771
+ margin: 8px 0 20px;
772
+ overflow: hidden;
773
+ box-shadow: inset 0 2px 5px rgba(0,0,0,0.1);
774
+ }
775
+
776
  #trustBar {
777
  height: 100%;
778
  border-radius: 10px;
 
786
  overflow: hidden;
787
  width: 0%;
788
  background: #e0e0e0;
789
+ display: flex;
790
+ align-items: center;
791
+ justify-content: center;
792
+ padding: 0 10px;
793
+ box-sizing: border-box;
794
  }
795
 
796
  #trustBar::after {
 
808
  animation: shimmer 2s infinite;
809
  }
810
 
811
+ /* ================= BOUTON LECTURE CROISÉE ================= */
812
+ #crossReadersBtn {
813
+ background: linear-gradient(135deg, #43A047, #4CAF50) !important;
814
+ color: white;
815
+ border: none;
816
+ padding: 12px 25px;
817
+ border-radius: 10px;
818
+ cursor: pointer;
819
+ font-weight: 600;
820
+ font-size: 15px;
821
+ transition: all 0.3s ease;
822
+ box-shadow: 0 3px 8px rgba(67, 160, 71, 0.2);
823
+ display: flex;
824
+ align-items: center;
825
+ justify-content: center;
826
+ gap: 8px;
827
+ width: 100%;
828
+ }
829
+
830
+ #crossReadersBtn:hover:not(:disabled) {
831
+ transform: translateY(-2px);
832
+ box-shadow: 0 5px 15px rgba(67, 160, 71, 0.3);
833
+ background: linear-gradient(135deg, #388E3C, #43A047) !important;
834
+ }
835
+
836
+ #crossReadersBtn:active:not(:disabled) {
837
+ transform: translateY(0);
838
+ }
839
+
840
+ #crossReadersBtn:disabled {
841
+ opacity: 0.5;
842
+ cursor: not-allowed;
843
+ background: #b0bec5 !important;
844
  }
845
 
846
  /* ================= MESSAGES ================= */
 
891
  font-weight: 500;
892
  }
893
 
894
+ /* ================= ONGLET 4: EXEMPLE D'ANALYSE ================= */
895
+ #tab-example {
896
+ padding: 20px;
897
+ }
898
+
899
+ .example-container {
900
+ background: linear-gradient(135deg, #f3e5f5, #e1bee7);
901
+ padding: 25px;
902
+ border-radius: 15px;
903
+ border-left: 6px solid #7b1fa2;
904
+ margin-bottom: 30px;
905
+ }
906
+
907
+ .example-container h4 {
908
+ color: #7b1fa2;
909
+ margin-top: 0;
910
+ display: flex;
911
+ align-items: center;
912
+ gap: 10px;
913
+ }
914
+
915
+ .example-analysis-box {
916
+ background: white;
917
+ padding: 20px;
918
+ border-radius: 10px;
919
+ border-left: 4px solid #7b1fa2;
920
+ margin: 15px 0;
921
+ box-shadow: 0 3px 10px rgba(0,0,0,0.05);
922
+ }
923
+
924
+ .example-message {
925
+ background: linear-gradient(135deg, #e8f5e9, #c8e6c9);
926
+ padding: 20px;
927
+ border-radius: 10px;
928
+ border-left: 6px solid #43a047;
929
+ margin: 20px 0;
930
+ line-height: 1.6;
931
+ font-size: 15px;
932
+ }
933
+
934
+ .example-message::before {
935
+ content: '🤖';
936
+ float: left;
937
+ margin-right: 10px;
938
+ font-size: 24px;
939
+ }
940
+
941
+ .example-competences {
942
+ background: #f9fbe7;
943
+ padding: 15px;
944
+ border-radius: 10px;
945
+ margin: 15px 0;
946
+ }
947
+
948
+ .example-competences ul {
949
+ margin: 10px 0;
950
+ padding-left: 20px;
951
+ }
952
+
953
+ .example-competences li {
954
+ margin-bottom: 8px;
955
+ line-height: 1.4;
956
+ }
957
+
958
+ .example-metrics-table {
959
+ width: 100%;
960
+ border-collapse: collapse;
961
+ margin: 20px 0;
962
+ background: white;
963
+ border-radius: 10px;
964
+ overflow: hidden;
965
+ box-shadow: 0 3px 10px rgba(0,0,0,0.05);
966
+ }
967
+
968
+ .example-metrics-table th {
969
+ background: linear-gradient(135deg, #7b1fa2, #9c27b0);
970
+ color: white;
971
+ padding: 15px;
972
+ text-align: left;
973
+ font-weight: 600;
974
+ }
975
+
976
+ .example-metrics-table td {
977
+ padding: 15px;
978
+ border-bottom: 1px solid #eee;
979
+ }
980
+
981
+ .example-metrics-table tr:last-child td {
982
+ border-bottom: none;
983
+ }
984
+
985
+ .example-metrics-table tr:hover {
986
+ background: #f5f5f5;
987
+ }
988
+
989
+ .metric-stars {
990
+ color: #ffd54f;
991
+ font-size: 18px;
992
+ }
993
+
994
+ .metric-observation {
995
+ font-size: 13px;
996
+ line-height: 1.4;
997
+ }
998
+
999
+ .metric-observation .success {
1000
+ color: #43a047;
1001
+ font-weight: 600;
1002
+ }
1003
+
1004
+ .metric-observation .warning {
1005
+ color: #fb8c00;
1006
+ font-weight: 600;
1007
+ }
1008
+
1009
+ .metric-observation .error {
1010
+ color: #e53935;
1011
+ font-weight: 600;
1012
+ }
1013
+
1014
+ .example-summary {
1015
+ background: #e3f2fd;
1016
+ padding: 20px;
1017
+ border-radius: 10px;
1018
+ margin: 20px 0;
1019
+ }
1020
+
1021
+ .example-summary ul {
1022
+ margin: 10px 0;
1023
+ padding-left: 20px;
1024
+ }
1025
+
1026
+ .example-summary li {
1027
+ margin-bottom: 8px;
1028
+ line-height: 1.4;
1029
+ padding-left: 5px;
1030
+ }
1031
+
1032
+ .example-separator {
1033
+ height: 1px;
1034
+ background: linear-gradient(90deg, #7b1fa2, transparent);
1035
+ margin: 25px 0;
1036
+ border: none;
1037
+ }
1038
+
1039
  /* ================= ANIMATIONS ================= */
1040
  @keyframes fadeIn {
1041
  from { opacity: 0; transform: translateY(20px); }
 
1058
  100% { transform: scale(1); }
1059
  }
1060
 
1061
+ @keyframes spin {
1062
+ 0% { transform: rotate(0deg); }
1063
+ 100% { transform: rotate(360deg); }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1064
  }
1065
 
1066
+ @keyframes shimmer {
1067
+ 0% { transform: translateX(-100%); }
1068
+ 100% { transform: translateX(100%); }
 
 
 
 
 
 
1069
  }
1070
 
1071
  /* ================= TOOLTIPS ================= */
 
1127
  animation: spin 1s linear infinite;
1128
  }
1129
 
 
 
 
 
 
1130
  /* ================= NOTIFICATIONS ================= */
1131
  .notification {
1132
  position: fixed;
 
1176
  font-size: 20px;
1177
  line-height: 1;
1178
  }
1179
+
1180
+ /* ================= RESPONSIVE ================= */
1181
+ @media (max-width: 1200px) {
1182
+ #reflection {
1183
+ padding: 20px;
1184
+ }
1185
+
1186
+ .tabs {
1187
+ flex-direction: column;
1188
+ }
1189
+
1190
+ .tab-btn {
1191
+ width: 100%;
1192
+ }
1193
+ }
1194
+
1195
+ @media (max-width: 768px) {
1196
+ body {
1197
+ padding: 10px;
1198
+ }
1199
+
1200
+ .nav {
1201
+ flex-direction: column;
1202
+ gap: 15px;
1203
+ text-align: center;
1204
+ }
1205
+
1206
+ #scenarioTitle {
1207
+ margin: 10px 0;
1208
+ font-size: 1.2em;
1209
+ }
1210
+
1211
+ button {
1212
+ width: 100%;
1213
+ justify-content: center;
1214
+ }
1215
+
1216
+ .gdpr-options {
1217
+ flex-direction: column;
1218
+ gap: 10px;
1219
+ }
1220
+
1221
+ .gdpr-option {
1222
+ min-width: 100%;
1223
+ }
1224
+
1225
+ .compact-competences-grid {
1226
+ grid-template-columns: repeat(auto-fill, minmax(150px, 1fr));
1227
+ }
1228
+
1229
+ .compact-radar-metrics-grid {
1230
+ grid-template-columns: repeat(auto-fill, minmax(150px, 1fr));
1231
+ }
1232
+
1233
+ .compact-radar-legend {
1234
+ flex-direction: column;
1235
+ align-items: center;
1236
+ gap: 8px;
1237
+ }
1238
+
1239
+ .compact-legend-grid {
1240
+ grid-template-columns: repeat(2, 1fr);
1241
+ }
1242
+
1243
+ .compact-analysis-controls {
1244
+ flex-direction: column;
1245
+ align-items: stretch;
1246
+ }
1247
+
1248
+ .compact-persistence-indicators {
1249
+ flex-direction: column;
1250
+ }
1251
+
1252
+ .stats-grid {
1253
+ grid-template-columns: repeat(2, 1fr);
1254
+ }
1255
+
1256
+ .tab-btn {
1257
+ min-width: 100%;
1258
+ }
1259
+
1260
+ .example-metrics-table {
1261
+ display: block;
1262
+ overflow-x: auto;
1263
+ }
1264
+ }
1265
+
1266
+ @media (max-width: 480px) {
1267
+ .stats-grid {
1268
+ grid-template-columns: 1fr;
1269
+ }
1270
+
1271
+ .compact-radar-metrics-grid {
1272
+ grid-template-columns: 1fr;
1273
+ }
1274
+
1275
+ .compact-competences-grid {
1276
+ grid-template-columns: 1fr;
1277
+ }
1278
+
1279
+ .example-metrics-table th,
1280
+ .example-metrics-table td {
1281
+ padding: 10px 8px;
1282
+ font-size: 13px;
1283
+ }
1284
+ }
1285
  </style>
1286
  </head>
1287
 
 
1308
  <button class="tab-btn" data-tab="tab-evaluation">
1309
  <span>🤖</span> Message Réflexif & Évaluation
1310
  </button>
1311
+ <button class="tab-btn" data-tab="tab-example">
1312
+ <span>📋</span> Exemple d'Analyse
1313
+ </button>
1314
  </div>
1315
 
1316
  <!-- ONGLET 1: INFORMATIONS ÉVALUATEUR GDPR -->
 
1404
  </div>
1405
 
1406
  <!-- Boutons d'action -->
1407
+ <div style="display: flex; gap: 10px; margin-top: 20px; flex-wrap: wrap;">
1408
  <button onclick="fillSampleEvaluator()" type="button" style="background: #666; flex: 1;" id="fillExampleBtn">
1409
  <span style="margin-right: 5px;">📋</span> Remplir exemple
1410
  </button>
 
1630
  <h4>💬 Commentaire expert</h4>
1631
  <textarea id="trustComment" placeholder="Ajoutez vos observations, suggestions ou critiques concernant l'analyse de ReflAgent..."></textarea>
1632
 
1633
+ <div style="display: flex; justify-content: space-between; align-items: center; margin: 25px 0; flex-wrap: wrap; gap: 20px;">
1634
+ <div style="flex-grow: 1; min-width: 300px;">
1635
  <h4 style="margin-bottom: 10px;">🔒 Indice global de confiance</h4>
1636
  <div class="progress-container">
1637
+ <div id="trustBar">0%</div>
1638
  </div>
1639
  <div style="display: flex; justify-content: space-between; margin-top: 5px; font-size: 12px; color: #666;">
1640
  <span>Faible confiance</span>
 
1642
  <span>Forte confiance</span>
1643
  </div>
1644
  </div>
1645
+ <div style="display: flex; flex-direction: column; gap: 10px; align-items: flex-end; min-width: 200px;">
1646
  <button id="saveTrustBtn" style="height: fit-content; width: 100%;">💾 Sauvegarder l'évaluation</button>
1647
+ <button id="crossReadersBtn" style="height: fit-content; width: 100%;">
1648
  📊 Lecture croisée
1649
  </button>
1650
  </div>
 
1672
  </div>
1673
  </div>
1674
  </div>
1675
+
1676
+ <!-- ONGLET 4: EXEMPLE D'ANALYSE -->
1677
+ <div id="tab-example" class="tab-content">
1678
+ <h3>📋 Exemple d'Analyse – Étudiant en difficulté / évitement de l’échec : peur de l’échec supérieure à la motivation de réussite.</h3>
1679
+
1680
+ <div class="example-analysis-box">
1681
+ <h4>Message auto-réflexif</h4>
1682
+ Ton niveau d'engagement est actuellement très faible : seulement 35 % des activités ont été démarrées et 30 % achevées. 😔 Tes compétences restent fragiles (40 %), ce qui indique un risque élevé de décrochage.
1683
+ Tu sembles parfois éviter les situations qui pourraient mener à l'échec, mais il est important de te rappeler que l'échec fait partie de l'apprentissage et peut devenir une véritable source de progression. 🛡️
1684
+ Commence par fixer des objectifs minuscules et accessibles, et entreprends de petites actions régulières dès le début de la semaine. Cela te permettra de reconstruire progressivement un rythme stable et de retrouver confiance et motivation.
1685
+ Tu dois travailler les compétences mises en avant : la compétence Favoriser la progression du domaine Paragraphe et la compétence Valoriser les petites victoires du domaine Texte.
1686
+ </div>
1687
+
1688
+
1689
+
1690
+ <div class="example-separator"></div>
1691
+
1692
+ <div class="example-analysis-box">
1693
+ <h4> Évaluation métrique avec observations</h4>
1694
+ <table class="example-metrics-table">
1695
+ <thead>
1696
+ <tr>
1697
+ <th width="25%">Métrique</th>
1698
+ <th width="15%">Niveau ★</th>
1699
+ <th width="60%">Observations (avec passage du message)</th>
1700
+ </tr>
1701
+ </thead>
1702
+ <tbody>
1703
+ <tr>
1704
+ <td><strong>Authenticité Réflexive (AR)</strong></td>
1705
+ <td><span class="metric-stars">★★★★☆</span></td>
1706
+ <td class="metric-observation">
1707
+ <span class="success">L'analyse reflète fidèlement la situation :</span> « Ton niveau d'engagement est actuellement très faible … Tes compétences restent fragiles » ✅
1708
+ </td>
1709
+ </tr>
1710
+ <tr>
1711
+ <td><strong>Alignement Empathique (AE)</strong></td>
1712
+ <td><span class="metric-stars">★★★☆☆</span></td>
1713
+ <td class="metric-observation">
1714
+ <span class="warning">L'agent montre une compréhension partielle des émotions :</span> « Tu sembles parfois éviter les situations qui pourraient mener à l'échec » ⚠️ Peut être renforcé avec plus de soutien émotionnel direct
1715
+ </td>
1716
+ </tr>
1717
+ <tr>
1718
+ <td><strong>Encouragement Sensible au Risque (ESR)</strong></td>
1719
+ <td><span class="metric-stars">★☆☆☆☆</span></td>
1720
+ <td class="metric-observation">
1721
+ <span class="error">L'agent indique le risque mais le soutien reste limité :</span> « …ce qui indique un risque élevé de décrochage » ❌ Faible guidance concrète pour sécuriser la progression
1722
+ </td>
1723
+ </tr>
1724
+ <tr>
1725
+ <td><strong>Support aux Défis Mentaux (SDM)</strong></td>
1726
+ <td><span class="metric-stars">★☆☆☆☆</span></td>
1727
+ <td class="metric-observation">
1728
+ <span class="error">Suggestions très limitées pour développer la réflexion ou les compétences :</span> « Commence par fixer des objectifs minuscules et accessibles » ❌ Pas de stratégie cognitive détaillée
1729
+ </td>
1730
+ </tr>
1731
+ <tr>
1732
+ <td><strong>Support Métacognitif (SM)</strong></td>
1733
+ <td><span class="metric-stars">★★☆☆☆</span></td>
1734
+ <td class="metric-observation">
1735
+ <span class="warning">Encouragement minimal à réfléchir sur sa méthode :</span> « entreprends de petites actions régulières » ⚠️ Peu d'indication sur planification ou révision de stratégie
1736
+ </td>
1737
+ </tr>
1738
+ </tbody>
1739
+ </table>
1740
+ </div>
1741
+
1742
+ <div class="example-separator"></div>
1743
+
1744
+ <div class="example-analysis-box">
1745
+ <h4> Résumé compact pour experts</h4>
1746
+ <ul>
1747
+ <li><strong>Profil global :</strong> Étudiant à risque, faible engagement et compétences fragiles.</li>
1748
+ <li><strong>Points forts :</strong> Volonté minimale de progresser (essayer malgré l'échec), possibilité de reconstruire motivation par petites actions.</li>
1749
+ <li><strong>Points à améliorer :</strong> Engagement, organisation, stratégies cognitives et métacognitives.</li>
1750
+ <li><strong>Objectif pédagogique :</strong> Réintroduire l'étudiant dans un rythme régulier avec des objectifs accessibles, renforcer la confiance et la motivation, fournir un soutien plus concret.</li>
1751
+ </ul>
1752
+ </div>
1753
+
1754
+
1755
+ </div>
1756
  </div>
1757
  </div>
1758
 
 
1886
 
1887
  // Initialiser la barre de confiance à 0%
1888
  updateTrustBar();
1889
+
1890
+ // Ajouter les écouteurs d'événements pour la navigation
1891
+ document.getElementById("prevScenario").onclick = () => loadScenario(currentScenarioIndex - 1);
1892
+ document.getElementById("nextScenario").onclick = () => loadScenario(currentScenarioIndex + 1);
1893
+ document.getElementById("crossReadersBtn").onclick = navigateToCrossReading;
1894
  });
1895
 
1896
  // ================= SYSTEME D'ONGLETS =================
 
1960
  // ================= CHARGEMENT JSON =================
1961
  function loadScenarios() {
1962
  console.log("Chargement des scénarios...");
1963
+ // Tentative de chargement depuis différents chemins
1964
+ const possiblePaths = [
1965
+ "/static/scenarios.json",
1966
+ "scenarios.json",
1967
+ "./scenarios.json",
1968
+ "../scenarios.json"
1969
+ ];
1970
+
1971
+ let loadAttempts = 0;
1972
+
1973
+ function tryLoad(pathIndex) {
1974
+ if (pathIndex >= possiblePaths.length) {
1975
+ console.error(" Impossible de charger les scénarios depuis aucun chemin");
1976
+ showError("Impossible de charger les scénarios. Vérifiez que le fichier scenarios.json existe.");
1977
+ return;
1978
+ }
1979
+
1980
+ const path = possiblePaths[pathIndex];
1981
+ console.log(`Tentative de chargement depuis: ${path}`);
1982
+
1983
+ fetch(path)
1984
+ .then(r => {
1985
+ if (!r.ok) throw new Error(`Erreur HTTP ${r.status}`);
1986
+ return r.json();
1987
+ })
1988
+ .then(data => {
1989
+ console.log("✅ Scénarios chargés:", data.scenarios?.length || 0);
1990
+ scenarios = data.scenarios || [];
1991
+
1992
+ if (scenarios.length === 0) {
1993
+ console.warn("Aucun scénario trouvé dans le fichier");
1994
+ showError("Aucun scénario trouvé dans le fichier JSON");
1995
+ return;
1996
+ }
1997
+
1998
+ loadScenario(0);
1999
+ })
2000
+ .catch(error => {
2001
+ console.warn(`Échec pour ${path}:`, error.message);
2002
+ loadAttempts++;
2003
+ tryLoad(pathIndex + 1);
2004
+ });
2005
+ }
2006
+
2007
+ tryLoad(0);
2008
+ }
2009
+
2010
+ function showError(message) {
2011
+ const manifestList = document.getElementById("manifest-list");
2012
+ if (manifestList) {
2013
+ manifestList.innerHTML =
2014
+ `<div class="manifest-item" style="background:#FFEBEE;color:#C62828;">
2015
+ ${message}<br>
2016
+ <small>Veuillez vérifier que le fichier scenarios.json est présent.</small>
2017
+ </div>`;
2018
+ }
2019
+
2020
+ // Afficher un message dans la console et éventuellement une alerte
2021
+ console.error(message);
2022
+
2023
+ // Désactiver la navigation
2024
+ document.getElementById("prevScenario").disabled = true;
2025
+ document.getElementById("nextScenario").disabled = true;
2026
  }
2027
 
2028
  // ================= CHARGER SCÉNARIO =================
2029
  function loadScenario(index) {
2030
  console.log("Chargement scénario", index);
2031
+ if (!scenarios || scenarios.length === 0) {
2032
+ console.error("Aucun scénario disponible");
2033
+ return;
2034
+ }
2035
+
2036
+ if (index < 0 || index >= scenarios.length) {
2037
+ console.warn(`Index ${index} hors limites (0-${scenarios.length-1})`);
2038
+ return;
2039
+ }
2040
+
2041
  currentScenarioIndex = index;
2042
  const s = scenarios[index];
2043
 
2044
  // Mettre à jour le titre
2045
  const titleElement = document.getElementById("scenarioTitle");
2046
+ if (titleElement) {
2047
+ titleElement.textContent = `Scénario ${s.id} – ${s.title}`;
2048
+ }
2049
 
2050
  // Mettre à jour le manifeste
2051
+ const manifestList = document.getElementById("manifest-list");
2052
+ if (manifestList) {
2053
+ manifestList.innerHTML = `
2054
+ <div class="manifest-item">
2055
+ <b>Type de Manifest :</b> ${s.manifest?.type || "Non spécifié"}<br>
2056
+ <b>Manifeste (écrit par l'étudiant) :</b> ${s.manifest?.manifeste || "Non disponible"}<br>
2057
+ <b>Description du Profil :</b> ${s.manifest?.description || "Non disponible"}
2058
+ </div>`;
2059
+ }
2060
 
2061
  // Mettre à jour les compétences compactes
2062
+ if (s.competences) {
2063
+ updateCompactCompetences(s.competences);
2064
+ }
2065
 
2066
  // Mettre à jour le radar avec les nouvelles métriques
2067
  if (s.radar && s.radar.length > 0) {
 
2095
  updatePerseveranceProfile(s.title);
2096
 
2097
  // Mettre à jour le message ReflAgent
2098
+ const reflagentElement = document.getElementById("reflagent");
2099
+ if (reflagentElement) {
2100
+ reflagentElement.textContent = s.reflAgent || "Message d'analyse non disponible pour ce scénario.";
2101
+ }
2102
 
2103
  // Mettre à jour les boutons de navigation
2104
  updateNavButtons();
2105
 
2106
  // Mettre à jour les statistiques
2107
+ updateStats(s);
2108
+
2109
+ // Réinitialiser l'évaluation de confiance
2110
+ resetTrustEvaluation();
2111
  }
2112
 
2113
  // ================= FONCTIONS POUR LA VERSION COMPACTE =================
 
2119
 
2120
  container.innerHTML = '';
2121
 
2122
+ if (!competences || competences.length === 0) {
2123
+ container.innerHTML = '<em>Aucune donnée de compétence disponible</em>';
2124
+ return;
2125
+ }
2126
+
2127
  competences.forEach(comp => {
2128
  // Déterminer la couleur selon la valeur
2129
  let color;
 
2157
 
2158
  grid.innerHTML = '';
2159
 
2160
+ if (!radarMetrics || radarMetrics.length === 0) {
2161
+ grid.innerHTML = '<em>Aucune métrique radar disponible</em>';
2162
+ return;
2163
+ }
2164
+
2165
  radarMetrics.forEach(metric => {
2166
  // Déterminer la classe de couleur selon la valeur
2167
  let colorClass = "";
 
2306
  const weeks = 4;
2307
  const totalDays = weeks * 7;
2308
 
2309
+ // Effacer le canvas
2310
  ctx.clearRect(0, 0, canvas.width, canvas.height);
2311
 
2312
  // Titre enrichi
 
2383
 
2384
  if (!profile) {
2385
  console.warn(`Aucun profil de persévérance trouvé pour: ${scenarioTitle}`);
2386
+
2387
+ // Valeurs par défaut
2388
+ const regularityText = document.getElementById("compact-regularityText");
2389
+ if (regularityText) {
2390
+ regularityText.innerHTML = `
2391
+ <div style="font-size: 12px; color: #555; line-height: 1.4;">
2392
+ Analyse de persévérance non disponible pour ce profil.
2393
+ </div>
2394
+ `;
2395
+ }
2396
  return;
2397
  }
2398
 
 
2521
  }
2522
 
2523
  // Mettre à jour l'interface compacte
2524
+ const regularityScoreElem = document.getElementById("compact-regularityScore");
2525
+ const effortPatternElem = document.getElementById("compact-effortPattern");
2526
+ const deadlineScoreElem = document.getElementById("compact-deadlineScore");
2527
+ const patternTextElem = document.getElementById("compact-patternText");
2528
 
2529
+ if (regularityScoreElem) regularityScoreElem.textContent = Math.round(regularity) + "%";
2530
+ if (effortPatternElem) effortPatternElem.textContent = pattern;
2531
+ if (deadlineScoreElem) deadlineScoreElem.textContent = Math.round(deadlineScore) + "%";
2532
+ if (patternTextElem) patternTextElem.textContent = patternDescription;
2533
  }
2534
 
2535
  // ================= RADAR =================
 
2543
  const ctx = canvas.getContext("2d");
2544
  const cx = canvas.width / 2;
2545
  const cy = canvas.height / 2;
2546
+ const radius = Math.min(cx, cy) - 40; // Ajuster selon la taille
2547
  const n = radarMetrics.length;
2548
 
2549
  ctx.clearRect(0, 0, canvas.width, canvas.height);
 
2574
  ctx.fillStyle = "#000";
2575
  ctx.textAlign = angle > Math.PI / 2 || angle < -Math.PI / 2 ? "right" : "left";
2576
  ctx.textBaseline = "middle";
2577
+
2578
+ // Raccourcir les labels longs
2579
+ let label = m.label;
2580
+ if (label.length > 15) {
2581
+ label = label.substring(0, 12) + "...";
2582
+ }
2583
+ ctx.fillText(label, tx, ty);
2584
  });
2585
 
2586
  // Dessiner le polygone
 
2615
  }
2616
 
2617
  // ================= NAVIGATION =================
 
 
 
 
 
 
2618
  function updateNavButtons() {
2619
+ if (!scenarios || scenarios.length === 0) {
2620
+ document.getElementById("prevScenario").disabled = true;
2621
+ document.getElementById("nextScenario").disabled = true;
2622
+ return;
2623
+ }
2624
+
2625
+ document.getElementById("prevScenario").disabled = currentScenarioIndex === 0;
2626
+ document.getElementById("nextScenario").disabled = currentScenarioIndex === scenarios.length - 1;
2627
  }
2628
 
2629
  // ================= BOUTON LECTURE CROISÉE =================
2630
+ function navigateToCrossReading() {
2631
  console.log('Navigation vers la page de lecture croisée...');
2632
 
2633
  // Animation de transition
 
2639
 
2640
  // Redirection
2641
  setTimeout(() => {
2642
+ // Essayer différents chemins pour la page de lecture croisée
2643
+ const possiblePaths = [
2644
+ 'cross_reading/cross_readers.html',
2645
+ './cross_reading/cross_readers.html',
2646
+ '../cross_reading/cross_readers.html',
2647
+ 'cross_readers.html',
2648
+ './cross_readers.html'
2649
+ ];
2650
+
2651
+ // Vérifier si le fichier existe avant la redirection
2652
+ function tryRedirect(index) {
2653
+ if (index >= possiblePaths.length) {
2654
+ console.error('Page de lecture croisée introuvable');
2655
+ showNotification('Erreur', 'Page de lecture croisée introuvable', 'error');
2656
+
2657
+ // Restaurer l'opacité
2658
+ if (reflectionDiv) {
2659
+ reflectionDiv.style.opacity = '1';
2660
+ }
2661
+ return;
2662
+ }
2663
+
2664
+ const path = possiblePaths[index];
2665
+
2666
+ // Vérifier si le fichier existe (approximation)
2667
+ fetch(path, { method: 'HEAD' })
2668
+ .then(response => {
2669
+ if (response.ok) {
2670
+ window.location.href = path;
2671
+ } else {
2672
+ tryRedirect(index + 1);
2673
+ }
2674
+ })
2675
+ .catch(() => {
2676
+ tryRedirect(index + 1);
2677
+ });
2678
+ }
2679
+
2680
+ tryRedirect(0);
2681
  }, 300);
2682
+ }
2683
 
2684
  // ================= MÉTRIQUES DE CONFIANCE =================
2685
  function initTrustStars(){
 
2715
 
2716
  // Stocker la valeur dans un attribut data
2717
  star.dataset.value = i;
2718
+ star.dataset.metric = metric;
2719
 
2720
  star.onclick = function() {
2721
  const value = parseInt(this.dataset.value);
2722
+ const metric = this.dataset.metric;
2723
  console.log(`Clic sur ${metric}: ${value} étoiles`);
2724
 
2725
  // Mettre à jour la valeur de la métrique
 
2982
 
2983
  console.log("Données à envoyer:", JSON.stringify(data, null, 2));
2984
 
2985
+ // Envoyer au serveur (simulation)
2986
+ simulateServerSave(data, msgDiv, trustScore, evaluatorName, gdprAccept);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2987
  };
2988
 
2989
  console.log("✅ Bouton de sauvegarde initialisé");
2990
  }
2991
 
2992
+ // Simulation de sauvegarde serveur
2993
+ function simulateServerSave(data, msgDiv, trustScore, evaluatorName, gdprAccept) {
2994
+ // Simuler un délai réseau
2995
+ setTimeout(() => {
2996
+ console.log("✅ Simulation de sauvegarde réussie:", data);
2997
+
2998
+ if (msgDiv) {
2999
+ const nameDisplay = gdprAccept ? evaluatorName : "Évaluateur anonyme";
3000
+ msgDiv.innerHTML = `
3001
+ <div style="display: flex; align-items: center; gap: 10px;">
3002
+ <div style="font-size: 24px;">✅</div>
3003
+ <div>
3004
+ <strong>Évaluation sauvegardée avec succès !</strong><br>
3005
+ <small>Merci ${nameDisplay} pour votre contribution.</small><br>
3006
+ <small><em>Indice global: ${trustScore}%</em></small>
3007
+ </div>
3008
+ </div>
3009
+ `;
3010
+ msgDiv.style.background = "#E8F5E9";
3011
+ msgDiv.style.color = "#2E7D32";
3012
+ msgDiv.style.padding = "15px";
3013
+ }
3014
+
3015
+ // Réinitialiser après succès (optionnel)
3016
+ setTimeout(() => {
3017
+ if (msgDiv) {
3018
+ msgDiv.innerHTML = "";
3019
+ msgDiv.style.background = "";
3020
+ msgDiv.style.color = "";
3021
+ msgDiv.style.padding = "";
3022
+ }
3023
+ }, 5000);
3024
+ }, 1000);
3025
+ }
3026
+
3027
  // Fonction pour réinitialiser l'évaluation
3028
  function resetTrustEvaluation() {
3029
  console.log("Réinitialisation de l'évaluation...");
 
3045
  updateTrustBar();
3046
 
3047
  // Vider le commentaire
3048
+ const commentField = document.getElementById("trustComment");
3049
+ if (commentField) {
3050
+ commentField.value = "";
3051
+ }
3052
 
3053
  console.log("Évaluation réinitialisée");
3054
  }
 
3056
  // ================= FONCTIONS UTILITAIRES =================
3057
 
3058
  // Mettre à jour les statistiques
3059
+ function updateStats(scenario) {
3060
+ if (!scenario) return;
3061
 
3062
+ const currentScenarioNum = document.getElementById("currentScenarioNum");
3063
+ const riskLevelElem = document.getElementById("riskLevel");
3064
+ const avgActivityElem = document.getElementById("avgActivity");
3065
 
3066
+ if (currentScenarioNum) {
3067
+ currentScenarioNum.textContent = scenario.id || "-";
3068
+ }
3069
 
3070
  // Niveau de risque
3071
+ if (riskLevelElem) {
3072
+ const risk = scenario.risk || 50;
3073
+ let riskLevel = "Moyen";
3074
+ let riskColor = "#FB8C00";
3075
+
3076
+ if (risk < 40) {
3077
+ riskLevel = "Faible";
3078
+ riskColor = "#43A047";
3079
+ } else if (risk > 70) {
3080
+ riskLevel = "Élevé";
3081
+ riskColor = "#E53935";
3082
+ }
3083
+
3084
+ riskLevelElem.textContent = riskLevel;
3085
+ riskLevelElem.style.color = riskColor;
3086
  }
3087
 
 
 
 
3088
  // Activité moyenne à partir des données radar
3089
+ if (avgActivityElem && scenario.radar && scenario.radar.length > 0) {
3090
+ const avgRadar = scenario.radar.reduce((sum, item) => sum + item.value, 0) / scenario.radar.length;
3091
+ avgActivityElem.textContent = Math.round(avgRadar) + "%";
3092
  }
3093
  }
3094
 
 
3133
  type === "error" ? "#FFEBEE" : "#E3F2FD";
3134
  msgDiv.style.color = type === "success" ? "#2E7D32" :
3135
  type === "error" ? "#C62828" : "#1565C0";
3136
+
3137
+ // Effacer après 5 secondes
3138
+ setTimeout(() => {
3139
+ msgDiv.textContent = "";
3140
+ msgDiv.style.background = "";
3141
+ msgDiv.style.color = "";
3142
+ }, 5000);
3143
  }
3144
  }
3145
 
3146
  // Changer le mode d'analyse de persévérance
3147
  function changePersistenceAnalysis() {
3148
+ const modeSelect = document.getElementById("persistenceMode");
3149
+ if (!modeSelect) return;
3150
+
3151
+ const mode = modeSelect.value;
3152
  const currentScenario = scenarios[currentScenarioIndex];
3153
 
3154
+ if (!currentScenario) return;
3155
+
3156
  // Redessiner la heatmap avec le mode sélectionné
3157
  drawCompactEnrichedHeatmap(currentScenario);
3158
 
3159
  // Ajouter une annotation selon le mode
3160
  const canvas = document.getElementById("heatmap");
3161
+ if (!canvas) return;
3162
+
3163
  const ctx = canvas.getContext("2d");
3164
 
3165
+ // Effacer l'annotation précédente
3166
+ ctx.clearRect(0, canvas.height - 30, canvas.width, 30);
3167
+
3168
  ctx.font = "12px Arial";
3169
  ctx.fillStyle = "#1976D2";
3170
  ctx.textAlign = "center";
 
3191
  window.showNotification = showNotification;
3192
  window.fillSampleEvaluator = fillSampleEvaluator;
3193
  window.clearEvaluatorFields = clearEvaluatorFields;
3194
+ window.loadScenario = loadScenario;
3195
  </script>
3196
 
3197
  </body>