ReflAgent / templates /index-old4.html
OUAREDAEK's picture
Upload templates/index-old4.html with huggingface_hub
970c7aa verified
Raw
History Blame Contribute Delete
84.5 kB
<!DOCTYPE html>
<html lang="fr">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Dashboard Réflexif – ReflAgent</title>
<style>
/* ================= STYLES DE BASE ================= */
body {
font-family: 'Segoe UI', Arial, sans-serif;
background: linear-gradient(135deg, #f5f7fa 0%, #c3cfe2 100%);
margin: 0;
padding: 20px;
color: #333;
}
h2, h3, h4 {
color: #1976D2;
margin-top: 0;
}
h2 {
background: linear-gradient(90deg, #1976D2, #2196F3);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
padding: 10px 0;
border-bottom: 2px solid #e3f2fd;
margin-bottom: 25px;
}
h3 {
background: #e3f2fd;
padding: 12px 15px;
border-radius: 8px;
margin: 25px 0 15px;
display: flex;
align-items: center;
gap: 10px;
}
h3::before {
content: '';
display: inline-block;
width: 6px;
height: 24px;
background: #1976D2;
border-radius: 3px;
}
#reflection {
background: white;
padding: 30px;
border-radius: 20px;
max-width: 1400px;
margin: auto;
box-shadow: 0 10px 40px rgba(0,0,0,0.08);
border: 1px solid #e0e0e0;
}
/* ================= SYSTEME D'ONGLETS ================= */
.tabs-container {
margin-bottom: 30px;
}
.tabs {
display: flex;
background: #f8f9fa;
border-radius: 12px;
padding: 5px;
margin-bottom: 20px;
border: 1px solid #e0e0e0;
}
.tab-btn {
flex: 1;
padding: 15px 20px;
border: none;
background: transparent;
color: #666;
font-weight: 600;
font-size: 16px;
cursor: pointer;
border-radius: 8px;
transition: all 0.3s ease;
display: flex;
align-items: center;
justify-content: center;
gap: 10px;
}
.tab-btn:hover {
background: rgba(25, 118, 210, 0.1);
color: #1976D2;
}
.tab-btn.active {
background: #1976D2;
color: white;
box-shadow: 0 3px 8px rgba(25, 118, 210, 0.2);
}
.tab-content {
display: none;
animation: fadeIn 0.5s ease;
}
.tab-content.active {
display: block;
}
/* ================= NAVIGATION ================= */
.nav {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 30px;
background: linear-gradient(90deg, #e3f2fd, #f3e5f5);
padding: 15px 25px;
border-radius: 12px;
border: 1px solid #bbdefb;
}
#scenarioTitle {
font-size: 1.4em;
color: #333;
text-align: center;
flex-grow: 1;
margin: 0 20px;
}
button {
background: linear-gradient(135deg, #1976D2, #2196F3);
color: white;
border: none;
padding: 12px 25px;
border-radius: 10px;
cursor: pointer;
font-weight: 600;
font-size: 15px;
transition: all 0.3s ease;
box-shadow: 0 3px 8px rgba(25, 118, 210, 0.2);
display: flex;
align-items: center;
gap: 8px;
}
button:hover:not(:disabled) {
transform: translateY(-2px);
box-shadow: 0 5px 15px rgba(25, 118, 210, 0.3);
}
button:active:not(:disabled) {
transform: translateY(0);
}
button:disabled {
opacity: 0.5;
cursor: not-allowed;
background: #b0bec5;
}
/* ================= BOUTON LECTURE CROISÉE ================= */
#crossReadersBtn {
background: linear-gradient(135deg, #43A047, #4CAF50) !important;
color: white;
border: none;
padding: 12px 25px;
border-radius: 10px;
cursor: pointer;
font-weight: 600;
font-size: 15px;
transition: all 0.3s ease;
box-shadow: 0 3px 8px rgba(67, 160, 71, 0.2);
display: flex;
align-items: center;
justify-content: center;
gap: 8px;
width: 100%;
}
#crossReadersBtn:hover:not(:disabled) {
transform: translateY(-2px);
box-shadow: 0 5px 15px rgba(67, 160, 71, 0.3);
background: linear-gradient(135deg, #388E3C, #43A047) !important;
}
#crossReadersBtn:active:not(:disabled) {
transform: translateY(0);
}
#crossReadersBtn:disabled {
opacity: 0.5;
cursor: not-allowed;
background: #b0bec5 !important;
}
/* ================= ONGLET 1: ÉVALUATEUR GDPR ================= */
#tab-evaluator .evaluator-info {
background: linear-gradient(135deg, #fff3e0, #ffe0b2);
padding: 25px;
border-radius: 15px;
border-left: 6px solid #ff9800;
margin: 20px 0;
}
#tab-evaluator .evaluator-info h4 {
color: #ff9800;
margin-top: 0;
margin-bottom: 20px;
display: flex;
align-items: center;
gap: 10px;
font-size: 20px;
}
.evaluator-field {
margin-bottom: 20px;
background: white;
padding: 20px;
border-radius: 10px;
border: 1px solid #FFE0B2;
}
.evaluator-field label {
display: block;
margin-bottom: 12px;
color: #333;
font-weight: 600;
font-size: 15px;
}
.evaluator-field input[type="text"],
.evaluator-field select {
width: 100%;
padding: 14px 18px;
border: 2px solid #e0e0e0;
border-radius: 8px;
font-size: 15px;
transition: all 0.3s;
box-sizing: border-box;
background: white;
}
.evaluator-field input[type="text"]:focus,
.evaluator-field select:focus {
outline: none;
border-color: #1976D2;
box-shadow: 0 0 0 3px rgba(25, 118, 210, 0.1);
}
.evaluator-field input:disabled,
.evaluator-field select:disabled {
background: #f5f5f5;
color: #999;
cursor: not-allowed;
}
.evaluator-field small {
display: block;
margin-top: 8px;
color: #666;
font-size: 13px;
font-style: italic;
}
/* Style pour les boutons radio GDPR */
.gdpr-options {
display: flex;
gap: 30px;
margin-top: 10px;
flex-wrap: wrap;
}
.gdpr-option {
display: flex;
align-items: center;
gap: 10px;
cursor: pointer;
padding: 12px 20px;
border-radius: 8px;
background: white;
border: 2px solid #e0e0e0;
transition: all 0.3s;
flex: 1;
min-width: 250px;
}
.gdpr-option:hover {
border-color: #1976D2;
background: #f0f7ff;
}
.gdpr-option input[type="radio"] {
width: 20px;
height: 20px;
cursor: pointer;
}
.gdpr-option span {
font-size: 15px;
font-weight: 500;
color: #333;
}
#anonymousMessage {
background: #E3F2FD;
padding: 18px;
border-radius: 10px;
margin-top: 20px;
border-left: 4px solid #1976D2;
animation: fadeIn 0.5s ease;
}
#anonymousMessage p {
margin: 0;
color: #1976D2;
font-size: 14px;
line-height: 1.5;
}
/* ================= ONGLET 2: DASHBOARD ÉTUDIANT COMPACT ================= */
#tab-dashboard .manifest-item {
background: linear-gradient(135deg, #f9fbe7, #f0f4c3);
padding: 15px;
border-radius: 12px;
border-left: 6px solid #cddc39;
margin: 15px 0;
box-shadow: 0 3px 10px rgba(0,0,0,0.05);
font-size: 14px;
}
.manifest-item b {
color: #689f38;
}
/* ================= COMPÉTENCES COMPACTES ================= */
#competence-bars {
background: white;
padding: 15px;
border-radius: 12px;
border: 1px solid #e0e0e0;
margin: 15px 0;
}
.compact-competences-grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
gap: 12px;
margin: 10px 0;
}
.compact-competence-item {
padding: 10px;
background: #f8f9fa;
border-radius: 8px;
border-left: 4px solid #1976D2;
transition: transform 0.2s;
}
.compact-competence-item:hover {
transform: translateY(-2px);
background: #e3f2fd;
}
.compact-competence-label {
font-size: 12px;
font-weight: 600;
color: #333;
margin-bottom: 8px;
display: flex;
justify-content: space-between;
}
.compact-competence-bar {
height: 10px;
background: #e0e0e0;
border-radius: 5px;
overflow: hidden;
margin: 5px 0;
}
.compact-competence-fill {
height: 100%;
border-radius: 5px;
color: white;
font-size: 9px;
text-align: right;
padding-right: 5px;
line-height: 10px;
font-weight: bold;
transition: width 0.5s ease;
}
/* ================= LÉGENDE RADAR COMPACTE ================= */
.compact-radar-legend {
display: flex;
justify-content: center;
gap: 15px;
margin: 15px 0;
flex-wrap: wrap;
padding: 10px;
background: white;
border-radius: 8px;
border: 1px solid #e0e0e0;
}
.compact-legend-item {
display: flex;
align-items: center;
gap: 8px;
padding: 6px 10px;
background: #f8f9fa;
border-radius: 6px;
font-size: 12px;
}
.compact-legend-color {
width: 16px;
height: 16px;
border-radius: 4px;
border: 2px solid white;
}
.compact-legend-low { background: linear-gradient(135deg, #e53935, #f44336); }
.compact-legend-medium { background: linear-gradient(135deg, #fb8c00, #ff9800); }
.compact-legend-high { background: linear-gradient(135deg, #43a047, #4caf50); }
/* ================= RADAR COMPACT ================= */
#radar-container {
background: white;
padding: 15px;
border-radius: 12px;
border: 1px solid #e0e0e0;
margin: 15px 0;
}
#radar {
max-width: 100%;
height: auto;
}
/* ================= MESSAGE BOT RADAR COMPACT ================= */
.compact-radar-bot-message {
background: linear-gradient(135deg, #E3F2FD, #BBDEFB);
padding: 15px;
border-radius: 10px;
border-left: 4px solid #1976D2;
margin: 15px 0;
}
.compact-radar-bot-header {
display: flex;
align-items: center;
gap: 10px;
margin-bottom: 10px;
}
.compact-radar-bot-icon {
font-size: 20px;
background: #1976D2;
color: white;
width: 40px;
height: 40px;
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
}
.compact-radar-bot-title {
font-size: 16px;
font-weight: 600;
color: #1976D2;
margin: 0;
}
.compact-radar-bot-content {
font-size: 14px;
line-height: 1.5;
color: #333;
margin: 0;
}
.compact-radar-bot-insights {
background: white;
padding: 10px;
border-radius: 8px;
margin-top: 10px;
border: 1px solid #E3F2FD;
}
.compact-radar-insight-item {
display: flex;
align-items: center;
gap: 8px;
margin-bottom: 6px;
padding: 6px 10px;
border-radius: 6px;
background: #F5F5F5;
font-size: 12px;
}
/* ================= GRILLE DES MÉTRIQUES RADAR COMPACTE ================= */
.compact-radar-metrics-grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(180px, 1fr));
gap: 12px;
margin: 15px 0;
}
.compact-metric-card {
background: white;
border-radius: 10px;
padding: 15px;
box-shadow: 0 3px 8px rgba(0,0,0,0.08);
border-left: 4px solid #1976D2;
transition: transform 0.3s;
text-align: center;
}
.compact-metric-card:hover {
transform: translateY(-3px);
box-shadow: 0 5px 15px rgba(0,0,0,0.12);
}
.compact-metric-icon {
font-size: 24px;
margin-bottom: 8px;
}
.compact-metric-name {
font-weight: 600;
color: #333;
margin-bottom: 5px;
font-size: 14px;
}
.compact-metric-value {
font-size: 20px;
font-weight: bold;
color: #1976D2;
margin: 5px 0;
}
.compact-metric-value.high { color: #43A047; }
.compact-metric-value.medium { color: #FB8C00; }
.compact-metric-value.low { color: #E53935; }
.compact-metric-description {
font-size: 11px;
color: #666;
margin-top: 5px;
line-height: 1.3;
}
/* ================= HEATMAP COMPACT ================= */
.compact-heatmap-and-indicators {
background: white;
padding: 15px;
border-radius: 12px;
border: 1px solid #e0e0e0;
margin: 15px 0;
}
.compact-heatmap-analysis {
margin-bottom: 15px;
}
.compact-analysis-controls {
display: flex;
align-items: center;
gap: 10px;
margin-bottom: 15px;
padding: 10px;
background: #f8f9fa;
border-radius: 8px;
}
.compact-analysis-controls label {
font-weight: 600;
color: #1976D2;
font-size: 14px;
}
.compact-analysis-controls select {
padding: 8px 12px;
border-radius: 6px;
border: 2px solid #1976D2;
background: white;
color: #333;
font-weight: 500;
cursor: pointer;
flex-grow: 1;
font-size: 14px;
}
#heatmap {
max-width: 100%;
height: auto;
border-radius: 8px;
}
/* ================= LÉGENDE HEATMAP COMPACTE ================= */
.compact-enriched-legend {
background: white;
padding: 15px;
border-radius: 10px;
border: 1px solid #e0e0e0;
margin: 15px 0;
}
.compact-legend-section h5 {
color: #1976D2;
margin-bottom: 10px;
font-size: 14px;
display: flex;
align-items: center;
gap: 6px;
}
.compact-legend-grid {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 8px;
}
.compact-legend-item-small {
display: flex;
align-items: center;
gap: 6px;
font-size: 11px;
}
.compact-legend-color-small {
width: 16px;
height: 16px;
border-radius: 4px;
border: 2px solid white;
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
}
/* ================= INDICATEURS DE PERSÉVÉRANCE COMPACTS ================= */
.compact-persistence-analysis {
background: linear-gradient(135deg, #e3f2fd, #f3e5f5);
padding: 15px;
border-radius: 10px;
border-left: 4px solid #1976D2;
margin: 15px 0;
}
.compact-persistence-indicators {
display: flex;
flex-direction: column;
gap: 8px;
margin-bottom: 10px;
}
.compact-indicator {
display: flex;
align-items: center;
gap: 8px;
padding: 8px 10px;
background: white;
border-radius: 6px;
font-size: 12px;
border-left: 3px solid #1976D2;
}
.compact-indicator-dot {
width: 10px;
height: 10px;
border-radius: 50%;
}
.compact-persistence-text {
font-size: 12px;
line-height: 1.4;
}
.compact-persistence-text > div {
margin-bottom: 6px;
padding: 8px;
background: white;
border-radius: 6px;
border-left: 3px solid #1976D2;
}
/* ================= ONGLET 3: MESSAGE RÉFLEXIF ET ÉVALUATION ================= */
#tab-evaluation #reflagent {
background: linear-gradient(135deg, #e8f5e9, #c8e6c9);
padding: 25px;
border-radius: 15px;
border-left: 8px solid #43a047;
margin: 25px 0;
font-size: 16px;
line-height: 1.6;
position: relative;
overflow: hidden;
min-height: 100px;
display: flex;
align-items: center;
}
#tab-evaluation #reflagent::before {
content: '🤖';
position: absolute;
top: 15px;
right: 15px;
font-size: 40px;
opacity: 0.2;
}
/* ================= MÉTRIQUES DE CONFIANCE ================= */
#tab-evaluation hr {
border: none;
height: 2px;
background: linear-gradient(90deg, #1976D2, transparent);
margin: 40px 0;
}
.trust-item {
margin-bottom: 20px;
padding: 15px;
background: #f8f9fa;
border-radius: 12px;
transition: transform 0.3s;
}
.trust-item:hover {
transform: translateX(5px);
background: #f1f3f4;
}
.trust-item b {
display: block;
margin-bottom: 10px;
color: #1976D2;
font-size: 15px;
}
.stars {
display: flex;
gap: 8px;
margin: 10px 0;
}
.stars span {
font-size: 32px;
cursor: pointer;
color: #e0e0e0;
transition: all 0.2s;
text-shadow: none;
}
.stars span.active {
color: #ffd54f;
text-shadow: 0 2px 4px rgba(255, 213, 79, 0.3);
}
.stars span:hover {
transform: scale(1.2);
}
.stars span.inactive {
color: #e0e0e0;
text-shadow: none;
}
.stars span.inactive:hover {
color: #ffd54f;
}
/* ================= CHAMP COMMENTAIRE ================= */
textarea {
width: 100%;
min-height: 120px;
border-radius: 12px;
padding: 15px;
border: 2px solid #e0e0e0;
font-family: inherit;
font-size: 14px;
resize: vertical;
transition: all 0.3s;
margin-bottom: 20px;
}
textarea:focus {
outline: none;
border-color: #1976D2;
box-shadow: 0 0 0 3px rgba(25, 118, 210, 0.1);
}
/* ================= BARRE DE CONFIANCE ================= */
#trustBar {
height: 100%;
border-radius: 10px;
color: white;
font-size: 14px;
text-align: center;
line-height: 24px;
font-weight: bold;
transition: width 0.5s ease, background 0.5s ease;
position: relative;
overflow: hidden;
width: 0%;
background: #e0e0e0;
}
#trustBar::after {
content: '';
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: linear-gradient(90deg,
transparent,
rgba(255,255,255,0.4),
transparent
);
animation: shimmer 2s infinite;
}
@keyframes shimmer {
0% { transform: translateX(-100%); }
100% { transform: translateX(100%); }
}
/* ================= MESSAGES ================= */
#saveTrustMsg {
padding: 10px 15px;
border-radius: 8px;
margin: 10px 0;
font-weight: 500;
text-align: center;
transition: all 0.3s;
min-height: 50px;
display: flex;
align-items: center;
justify-content: center;
}
/* ================= STATISTIQUES ================= */
.stats-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
gap: 15px;
margin: 20px 0;
}
.stat-item {
background: linear-gradient(135deg, #e3f2fd, #f3e5f5);
padding: 15px;
border-radius: 10px;
text-align: center;
transition: transform 0.3s;
}
.stat-item:hover {
transform: translateY(-3px);
box-shadow: 0 5px 15px rgba(0,0,0,0.1);
}
.stat-value {
font-size: 28px;
font-weight: bold;
color: #1976D2;
margin: 10px 0;
}
.stat-label {
font-size: 13px;
color: #666;
font-weight: 500;
}
/* ================= ANIMATIONS ================= */
@keyframes fadeIn {
from { opacity: 0; transform: translateY(20px); }
to { opacity: 1; transform: translateY(0); }
}
@keyframes slideIn {
from { transform: translateX(100%); opacity: 0; }
to { transform: translateX(0); opacity: 1; }
}
@keyframes slideOut {
from { transform: translateX(0); opacity: 1; }
to { transform: translateX(100%); opacity: 0; }
}
@keyframes pulse {
0% { transform: scale(1); }
50% { transform: scale(1.05); }
100% { transform: scale(1); }
}
/* ================= RESPONSIVE ================= */
@media (max-width: 1200px) {
#reflection {
padding: 20px;
}
.tabs {
flex-direction: column;
}
.tab-btn {
width: 100%;
}
}
@media (max-width: 768px) {
body {
padding: 10px;
}
.nav {
flex-direction: column;
gap: 15px;
text-align: center;
}
#scenarioTitle {
margin: 10px 0;
font-size: 1.2em;
}
button {
width: 100%;
justify-content: center;
}
.gdpr-options {
flex-direction: column;
gap: 10px;
}
.gdpr-option {
min-width: 100%;
}
.compact-competences-grid {
grid-template-columns: repeat(auto-fill, minmax(150px, 1fr));
}
.compact-radar-metrics-grid {
grid-template-columns: repeat(auto-fill, minmax(150px, 1fr));
}
.compact-radar-legend {
flex-direction: column;
align-items: center;
gap: 8px;
}
.compact-legend-grid {
grid-template-columns: repeat(2, 1fr);
}
.compact-analysis-controls {
flex-direction: column;
align-items: stretch;
}
.compact-persistence-indicators {
flex-direction: column;
}
}
/* ================= PROGRESS BAR CONTAINER ================= */
.progress-container {
width: 100%;
background: #f5f5f5;
border-radius: 12px;
height: 24px;
margin: 8px 0 20px;
overflow: hidden;
box-shadow: inset 0 2px 5px rgba(0,0,0,0.1);
}
/* ================= TOOLTIPS ================= */
.tooltip {
position: absolute;
background: rgba(25, 118, 210, 0.95);
color: white;
padding: 12px 18px;
border-radius: 10px;
font-size: 14px;
pointer-events: none;
opacity: 0;
transition: opacity 0.3s;
z-index: 1000;
max-width: 300px;
box-shadow: 0 6px 20px rgba(0,0,0,0.2);
border: 2px solid white;
backdrop-filter: blur(5px);
}
.tooltip::after {
content: '';
position: absolute;
top: 100%;
left: 50%;
margin-left: -10px;
border-width: 10px;
border-style: solid;
border-color: rgba(25, 118, 210, 0.95) transparent transparent transparent;
}
/* ================= SCROLLBAR ================= */
::-webkit-scrollbar {
width: 10px;
}
::-webkit-scrollbar-track {
background: #f1f1f1;
border-radius: 5px;
}
::-webkit-scrollbar-thumb {
background: linear-gradient(135deg, #1976D2, #2196F3);
border-radius: 5px;
}
::-webkit-scrollbar-thumb:hover {
background: linear-gradient(135deg, #1565c0, #1976D2);
}
/* ================= LOADING ================= */
.loading {
display: inline-block;
width: 20px;
height: 20px;
border: 3px solid #f3f3f3;
border-top: 3px solid #1976D2;
border-radius: 50%;
animation: spin 1s linear infinite;
}
@keyframes spin {
0% { transform: rotate(0deg); }
100% { transform: rotate(360deg); }
}
/* ================= NOTIFICATIONS ================= */
.notification {
position: fixed;
top: 20px;
right: 20px;
background: white;
padding: 18px;
border-radius: 12px;
box-shadow: 0 8px 25px rgba(0,0,0,0.15);
border-left: 6px solid #1976D2;
z-index: 10000;
max-width: 320px;
animation: slideIn 0.4s ease-out;
display: flex;
align-items: flex-start;
gap: 12px;
}
.notification-icon {
font-size: 28px;
flex-shrink: 0;
}
.notification-content {
flex-grow: 1;
}
.notification-title {
font-weight: bold;
color: #1976D2;
margin-bottom: 5px;
font-size: 15px;
}
.notification-message {
color: #555;
font-size: 13px;
line-height: 1.4;
}
.notification-close {
background: none;
border: none;
color: #999;
cursor: pointer;
padding: 0;
font-size: 20px;
line-height: 1;
}
</style>
</head>
<body>
<div id="reflection">
<!-- NAVIGATION SCÉNARIOS -->
<div class="nav">
<button id="prevScenario">⬅️ Scénario précédent</button>
<h3 id="scenarioTitle">Chargement...</h3>
<button id="nextScenario">Scénario suivant ➡️</button>
</div>
<!-- SYSTEME D'ONGLETS -->
<div class="tabs-container">
<div class="tabs">
<button class="tab-btn active" data-tab="tab-evaluator">
<span>👤</span> Évaluateur (RGPD)
</button>
<button class="tab-btn" data-tab="tab-dashboard">
<span>📊</span> Dashboard Étudiant
</button>
<button class="tab-btn" data-tab="tab-evaluation">
<span>🤖</span> Message Réflexif & Évaluation
</button>
</div>
<!-- ONGLET 1: INFORMATIONS ÉVALUATEUR GDPR -->
<div id="tab-evaluator" class="tab-content active">
<h3>👤 Informations de l'évaluateur (RGPD)</h3>
<div class="evaluator-info">
<!-- Consentement RGPD -->
<div class="evaluator-field">
<label for="gdprConsent">
<strong><span style="color: #1976D2; margin-right: 5px;">🔒</span> Consentement RGPD <span style="color: #e53935;">*</span></strong>
</label>
<div class="gdpr-options">
<label class="gdpr-option">
<input type="radio" name="gdprConsent" value="accept" id="gdprAccept" required>
<span>J'accepte de partager mes informations pour l'évaluation</span>
</label>
<label class="gdpr-option">
<input type="radio" name="gdprConsent" value="decline" id="gdprDecline">
<span>Je préfère rester anonyme</span>
</label>
</div>
<small>Veuillez accepter le consentement RGPD pour pouvoir remplir les champs d'identification</small>
</div>
<!-- Champs conditionnels (masqués par défaut) -->
<div id="evaluatorFields" style="display: none;">
<!-- Nom et prénom -->
<div class="evaluator-field">
<label for="evaluatorName">
<strong><span style="color: #1976D2; margin-right: 5px;">📝</span> Nom et prénom <span style="color: #e53935;">*</span></strong>
</label>
<input type="text"
id="evaluatorName"
placeholder="Ex: Dupont Jean ou Marie Curie"
maxlength="100"
disabled>
<small>Veuillez saisir votre nom et prénom</small>
</div>
<!-- Rôle -->
<div class="evaluator-field">
<label for="evaluatorRole"><strong><span style="color: #1976D2; margin-right: 5px;">👔</span> Rôle principal <span style="color: #e53935;">*</span></strong></label>
<select id="evaluatorRole" disabled>
<option value="">Sélectionnez votre rôle...</option>
<option value="enseignant">Enseignant / Formateur</option>
<option value="chercheur">Chercheur / Scientifique</option>
<option value="expert_pedago">Expert pédagogique</option>
<option value="etudiant_avance">Étudiant avancé / Doctorant</option>
<option value="conseiller">Conseiller pédagogique</option>
<option value="responsable">Responsable de formation</option>
<option value="autre">Autre professionnel de l'éducation</option>
</select>
<small>Sélectionnez votre rôle principal dans le domaine éducatif</small>
</div>
<!-- Niveau d'expertise en réflexivité -->
<div class="evaluator-field">
<label for="expertiseLevel"><strong><span style="color: #1976D2; margin-right: 5px;">🎓</span> Niveau d'expertise en réflexivité <span style="color: #e53935;">*</span></strong></label>
<select id="expertiseLevel" disabled>
<option value="">Sélectionnez votre niveau...</option>
<option value="debutant">Débutant - Je découvre la réflexivité</option>
<option value="intermediaire">Intermédiaire - J'utilise régulièrement des outils réflexifs</option>
<option value="avance">Avancé - Je conçois des dispositifs réflexifs</option>
<option value="expert">Expert - Je forme à la réflexivité pédagogique</option>
<option value="chercheur_reflex">Chercheur en réflexivité</option>
</select>
<small>Indiquez votre niveau de maîtrise des concepts et outils de réflexivité</small>
</div>
<!-- Niveau de maîtrise des messages réflexifs -->
<div class="evaluator-field">
<label for="messageMastery"><strong><span style="color: #1976D2; margin-right: 5px;">💬</span> Niveau de maîtrise des messages réflexifs <span style="color: #e53935;">*</span></strong></label>
<select id="messageMastery" disabled>
<option value="">Sélectionnez votre niveau...</option>
<option value="novice">Novice - Je commence à analyser des messages réflexifs</option>
<option value="intermediaire_msg">Intermédiaire - J'évalue régulièrement des feedbacks réflexifs</option>
<option value="avance_msg">Avancé - Je rédige des messages réflexifs pour autrui</option>
<option value="expert_msg">Expert - Je forme à la conception de messages réflexifs</option>
</select>
<small>Indiquez votre expérience avec l'analyse et la création de messages réflexifs</small>
</div>
</div>
<!-- Message pour utilisateurs anonymes -->
<div id="anonymousMessage" style="display: none;">
<p>
<strong><span style="margin-right: 5px;">🕵️</span> Évaluation anonyme :</strong> Vos évaluations seront enregistrées sans information personnelle.
Seules vos réponses aux métriques de confiance seront conservées.
</p>
</div>
<!-- Boutons d'action -->
<div style="display: flex; gap: 10px; margin-top: 20px;">
<button onclick="fillSampleEvaluator()" type="button" style="background: #666; flex: 1;" id="fillExampleBtn">
<span style="margin-right: 5px;">📋</span> Remplir exemple
</button>
<button onclick="clearEvaluatorFields()" type="button" style="background: #9e9e9e; flex: 1;" id="clearFieldsBtn">
<span style="margin-right: 5px;">🗑️</span> Effacer
</button>
</div>
</div>
</div>
<!-- ONGLET 2: DASHBOARD ÉTUDIANT COMPACT -->
<div id="tab-dashboard" class="tab-content">
<h3>📝 Manifeste étudiant</h3>
<div id="manifest-list">
<div class="manifest-item">
<em>Chargement des données...</em>
</div>
</div>
<h3>📊 Progression par compétence</h3>
<div id="competence-bars">
<div id="compact-competences">
<em>Chargement des compétences...</em>
</div>
</div>
<!-- LÉGENDE RADAR COMPACTE -->
<div class="compact-radar-legend">
<div class="compact-legend-item">
<div class="compact-legend-color compact-legend-low"></div>
<span>Faible (0-50%)</span>
</div>
<div class="compact-legend-item">
<div class="compact-legend-color compact-legend-medium"></div>
<span>Moyen (50-70%)</span>
</div>
<div class="compact-legend-item">
<div class="compact-legend-color compact-legend-high"></div>
<span>Élevé (70-100%)</span>
</div>
</div>
<h3>🕸️ Radar – Learning Analytics</h3>
<!-- Grille des métriques radar compacte -->
<div class="compact-radar-metrics-grid" id="compact-radar-metrics-grid">
<!-- Les métriques seront ajoutées dynamiquement -->
</div>
<!-- Container Radar et Bot Message -->
<div id="radar-container">
<div style="display: flex; gap: 20px; flex-wrap: wrap;">
<!-- Message Bot Radar Compact -->
<div class="compact-radar-bot-message" style="flex: 1; min-width: 300px;">
<div class="compact-radar-bot-header">
<div class="compact-radar-bot-icon">🎯</div>
<h4 class="compact-radar-bot-title">Analyse de Profil</h4>
</div>
<p class="compact-radar-bot-content" id="compact-radar-bot-content">Analyse en cours...</p>
<div class="compact-radar-bot-insights">
<div id="compact-radar-bot-insights">
<!-- Les insights seront ajoutés dynamiquement -->
</div>
</div>
</div>
<!-- Canvas Radar Compact -->
<div style="flex: 1; min-width: 300px; text-align: center;">
<canvas id="radar" width="500" height="500" style="max-width: 100%; height: auto;"></canvas>
</div>
</div>
</div>
<!-- HEATMAP COMPACTE -->
<div class="compact-heatmap-and-indicators">
<h3>🔥 Heatmap d'activité - Analyse de Persévérance</h3>
<div class="compact-heatmap-analysis">
<div class="compact-analysis-controls">
<label for="persistenceMode">Mode d'analyse :</label>
<select id="persistenceMode" onchange="changePersistenceAnalysis()">
<option value="regularity">📊 Régularité du travail</option>
<option value="effortPattern">🔄 Schéma d'effort</option>
<option value="deadline">⏰ Gestion des échéances</option>
<option value="combined">🎯 Vue combinée</option>
</select>
</div>
<!-- Canvas pour le heatmap -->
<canvas id="heatmap" width="800" height="250" style="max-width: 100%; height: auto;"></canvas>
</div>
<!-- Légende des niveaux d'activité compacte -->
<div class="compact-enriched-legend">
<div class="compact-legend-section">
<h5>📈 Niveaux d'activité</h5>
<div class="compact-legend-grid">
<div class="compact-legend-item-small">
<div class="compact-legend-color-small" style="background:#EBEDF0;"></div>
<span>Aucune activité</span>
</div>
<div class="compact-legend-item-small">
<div class="compact-legend-color-small" style="background:#C6E48B;"></div>
<span>Faible activité</span>
</div>
<div class="compact-legend-item-small">
<div class="compact-legend-color-small" style="background:#7BC96F;"></div>
<span>Activité modérée</span>
</div>
<div class="compact-legend-item-small">
<div class="compact-legend-color-small" style="background:#239A3B;"></div>
<span>Activité élevée</span>
</div>
<div class="compact-legend-item-small">
<div class="compact-legend-color-small" style="background:#196127;"></div>
<span>Activité intense</span>
</div>
</div>
</div>
</div>
<!-- Analyse de persévérance compacte -->
<div class="compact-persistence-analysis" id="compact-persistenceAnalysis">
<h5>🎯 Indicateurs de Persévérance</h5>
<div class="compact-persistence-indicators">
<div class="compact-indicator">
<span class="compact-indicator-dot" style="background:#FF6B6B;"></span>
<span>Régularité calculée : <strong id="compact-regularityScore">-</strong></span>
</div>
<div class="compact-indicator">
<span class="compact-indicator-dot" style="background:#4ECDC4;"></span>
<span>Schéma d'effort : <strong id="compact-effortPattern">-</strong></span>
</div>
<div class="compact-indicator">
<span class="compact-indicator-dot" style="background:#FFD166;"></span>
<span>Gestion échéances : <strong id="compact-deadlineScore">-</strong></span>
</div>
</div>
<div class="compact-persistence-text" style="margin-top: 10px;">
<div style="margin-bottom: 10px;">
<strong>Schéma d'effort :</strong>
<div style="margin-top: 5px; padding: 8px; background: #F5F5F5; border-radius: 6px; font-size: 13px;">
<span id="compact-patternText">Analyse en cours...</span>
</div>
</div>
<div>
<strong>Persévérance et gestion des efforts :</strong>
<div style="margin-top: 5px; padding: 10px; background: #F8F9FA; border-radius: 6px; border-left: 3px solid #1976D2;">
<span id="compact-regularityText">Analyse en cours...</span>
</div>
</div>
</div>
</div>
</div>
</div>
<!-- ONGLET 3: MESSAGE RÉFLEXIF ET ÉVALUATION -->
<div id="tab-evaluation" class="tab-content">
<h3>🤖 ReflAgent – Analyse & accompagnement</h3>
<div id="reflagent">
<em>Le message d'analyse apparaîtra ici après chargement...</em>
</div>
<hr>
<h3>🧑‍⚖️ Volet Expert – Métriques de Confiance</h3>
<p style="color: #666; margin-bottom: 20px; font-style: italic;">
Évaluez votre confiance dans l'analyse de ReflAgent pour ce scénario :
</p>
<!-- MÉTRIQUES TRADUITES EN FRANÇAIS -->
<div class="trust-item">
<b>Authenticité Réflexive (AR)</b>
<div class="stars" data-metric="AR">
<!-- Les étoiles seront ajoutées par JavaScript -->
</div>
<small style="color: #666; display: block; margin-top: 5px;">
L'analyse reflète-t-elle fidèlement la situation réelle de l'étudiant ?
</small>
</div>
<div class="trust-item">
<b>Alignement Empathique (AE)</b>
<div class="stars" data-metric="AE">
<!-- Les étoiles seront ajoutées par JavaScript -->
</div>
<small style="color: #666; display: block; margin-top: 5px;">
L'agent comprend-il les émotions, motivations et difficultés de l'étudiant ?
</small>
</div>
<div class="trust-item">
<b>Encouragement Sensible au Risque (ESR)</b>
<div class="stars" data-metric="ESR">
<!-- Les étoiles seront ajoutées par JavaScript -->
</div>
<small style="color: #666; display: block; margin-top: 5px;">
Les encouragements tiennent-ils compte des risques et difficultés identifiés ?
</small>
</div>
<div class="trust-item">
<b>Support aux Défis Mentaux (SDM)</b>
<div class="stars" data-metric="SDM">
<!-- Les étoiles seront ajoutées par JavaScript -->
</div>
<small style="color: #666; display: block; margin-top: 5px;">
L'agent aide-t-il l'étudiant à développer sa pensée critique et ses compétences cognitives ?
</small>
</div>
<div class="trust-item">
<b>Support Métacognitif (SM)</b>
<div class="stars" data-metric="SM">
<!-- Les étoiles seront ajoutées par JavaScript -->
</div>
<small style="color: #666; display: block; margin-top: 5px;">
L'agent aide-t-il l'étudiant à réfléchir sur ses propres stratégies d'apprentissage ?
</small>
</div>
<h4>💬 Commentaire expert</h4>
<textarea id="trustComment" placeholder="Ajoutez vos observations, suggestions ou critiques concernant l'analyse de ReflAgent..."></textarea>
<div style="display: flex; justify-content: space-between; align-items: center; margin: 25px 0;">
<div style="flex-grow: 1; margin-right: 20px;">
<h4 style="margin-bottom: 10px;">🔒 Indice global de confiance</h4>
<div class="progress-container">
<div class="fill" id="trustBar">0%</div>
</div>
<div style="display: flex; justify-content: space-between; margin-top: 5px; font-size: 12px; color: #666;">
<span>Faible confiance</span>
<span>Confidence moyenne</span>
<span>Forte confiance</span>
</div>
</div>
<div style="display: flex; flex-direction: column; gap: 10px; align-items: flex-end;">
<button id="saveTrustBtn" style="height: fit-content; width: 100%;">💾 Sauvegarder l'évaluation</button>
<button id="crossReadersBtn" style="height: fit-content; width: 100%; background: linear-gradient(135deg, #43A047, #4CAF50);">
📊 Lecture croisée
</button>
</div>
</div>
<div id="saveTrustMsg"></div>
<!-- Statistiques rapides -->
<div class="stats-grid">
<div class="stat-item">
<div class="stat-label">Scénario actuel</div>
<div class="stat-value" id="currentScenarioNum">-</div>
</div>
<div class="stat-item">
<div class="stat-label">Confiance moyenne</div>
<div class="stat-value" id="avgTrustScore">0%</div>
</div>
<div class="stat-item">
<div class="stat-label">Niveau de risque</div>
<div class="stat-value" id="riskLevel">-</div>
</div>
<div class="stat-item">
<div class="stat-label">Activité moyenne</div>
<div class="stat-value" id="avgActivity">-</div>
</div>
</div>
</div>
</div>
</div>
<!-- Script principal -->
<script>
// ================= VARIABLES =================
let scenarios = [];
let currentScenarioIndex = 0;
let radarMetrics = [];
// Métriques de radar par défaut (sans abréviations)
const DEFAULT_RADAR_METRICS = [
{ label: "Démarrage des activités", value: 85 },
{ label: "Connaissances validées", value: 72 },
{ label: "Niveau moyen de compétence", value: 68 },
{ label: "Taux d'erreur (inversé)", value: 35 },
{ label: "Achèvement des activités", value: 74 },
{ label: "Interactions avec les ressources", value: 80 },
{ label: "Domaines de compétence", value: 78 }
];
// Noms des métriques traduits en français
const trustMetrics = {
"AR": 0, // Authenticité Réflexive
"AE": 0, // Alignement Empathique
"ESR": 0, // Encouragement Sensible au Risque
"SDM": 0, // Support aux Défis Mentaux
"SM": 0 // Support Métacognitif
};
const trustWeights = {
"AR": 0.30,
"AE": 0.20,
"ESR": 0.20,
"SDM": 0.10,
"SM": 0.20
};
// MAPPING PERSÉVÉRANCE PAR PROFIL
const perseveranceProfiles = {
"Étudiant engagé": {
level: "Très élevée",
interpretation: "Efforts constants et durables, persévère même face aux difficultés",
color: "#43A047"
},
"Étudiant actif mais inefficace": {
level: "Moyenne",
interpretation: "Efforts importants mais mal régulés, persévérance peu productive",
color: "#FB8C00"
},
"Étudiant orienté vers le succès": {
level: "Élevée",
interpretation: "Persévérance principalement guidée par l'atteinte des objectifs",
color: "#4CAF50"
},
"Étudiant motivé": {
level: "Élevée",
interpretation: "Engagement soutenu et continuité stable de l'effort",
color: "#4CAF50"
},
"Étudiant surmotivé": {
level: "Très élevée",
interpretation: "Effort intense, parfois excessif, avec risque de surcharge",
color: "#43A047"
},
"Étudiant stratégique": {
level: "Élevée",
interpretation: "Effort bien dosé, persévérance optimisée selon le rendement attendu",
color: "#4CAF50"
},
"Étudiant en amélioration": {
level: "Moyenne à élevée",
interpretation: "Efforts croissants, persévérance en cours de structuration",
color: "#FF9800"
},
"Étudiant en difficulté": {
level: "Faible",
interpretation: "Découragement fréquent et difficulté à maintenir l'effort",
color: "#E53935"
},
"Étudiant évitant l'échec": {
level: "Moyenne",
interpretation: "Persévérance motivée par la peur de l'échec plutôt que par l'apprentissage",
color: "#FB8C00"
},
"Étudiant à risque": {
level: "Très faible",
interpretation: "Abandon rapide et très faible tolérance à l'effort",
color: "#C62828"
},
"Étudiant en progression": {
level: "Élevée",
interpretation: "Efforts réguliers et de mieux en mieux maîtrisés",
color: "#4CAF50"
},
"Étudiant acceptant l'échec": {
level: "Élevée",
interpretation: "Bonne résilience, persévère malgré les erreurs et les échecs",
color: "#4CAF50"
},
"Étudiant inactif": {
level: "Très faible",
interpretation: "Manque d'engagement, difficulté à initier et maintenir l'effort",
color: "#C62828"
},
"Étudiant non engagé": {
level: "Faible",
interpretation: "Manque de motivation, efforts sporadiques et peu soutenus",
color: "#E53935"
},
"Étudiant persévérant": {
level: "Élevée",
interpretation: "Constance dans l'effort malgré les doutes et difficultés",
color: "#4CAF50"
},
"Étudiant actif": {
level: "Moyenne",
interpretation: "Efforts soutenus mais parfois désorganisés ou mal canalisés",
color: "#FB8C00"
}
};
// ================= INIT =================
document.addEventListener("DOMContentLoaded", () => {
console.log("✅ DOM chargé, initialisation...");
loadScenarios();
initTrustStars();
initTrustSave();
initTabs();
initGDPR();
// Initialiser la barre de confiance à 0%
updateTrustBar();
});
// ================= SYSTEME D'ONGLETS =================
function initTabs() {
const tabBtns = document.querySelectorAll('.tab-btn');
const tabContents = document.querySelectorAll('.tab-content');
tabBtns.forEach(btn => {
btn.addEventListener('click', () => {
const tabId = btn.getAttribute('data-tab');
// Retirer la classe active de tous les boutons et contenus
tabBtns.forEach(b => b.classList.remove('active'));
tabContents.forEach(c => c.classList.remove('active'));
// Ajouter la classe active au bouton et au contenu correspondant
btn.classList.add('active');
document.getElementById(tabId).classList.add('active');
});
});
}
// ================= GDPR =================
function initGDPR() {
const gdprAccept = document.getElementById('gdprAccept');
const gdprDecline = document.getElementById('gdprDecline');
const evaluatorFields = document.getElementById('evaluatorFields');
const anonymousMessage = document.getElementById('anonymousMessage');
// Activer/désactiver les champs selon le choix GDPR
function updateGDPRFields() {
if (gdprAccept.checked) {
// Afficher les champs et les activer
evaluatorFields.style.display = 'block';
anonymousMessage.style.display = 'none';
// Activer les champs
document.getElementById('evaluatorName').disabled = false;
document.getElementById('evaluatorRole').disabled = false;
document.getElementById('expertiseLevel').disabled = false;
document.getElementById('messageMastery').disabled = false;
} else if (gdprDecline.checked) {
// Cacher les champs et afficher le message anonyme
evaluatorFields.style.display = 'none';
anonymousMessage.style.display = 'block';
// Désactiver et vider les champs
document.getElementById('evaluatorName').disabled = true;
document.getElementById('evaluatorName').value = '';
document.getElementById('evaluatorRole').disabled = true;
document.getElementById('evaluatorRole').value = '';
document.getElementById('expertiseLevel').disabled = true;
document.getElementById('expertiseLevel').value = '';
document.getElementById('messageMastery').disabled = true;
document.getElementById('messageMastery').value = '';
}
}
// Écouter les changements
gdprAccept.addEventListener('change', updateGDPRFields);
gdprDecline.addEventListener('change', updateGDPRFields);
// Initialiser
updateGDPRFields();
}
// ================= CHARGEMENT JSON =================
function loadScenarios() {
console.log("Chargement des scénarios...");
fetch("/static/scenarios.json")
.then(r => {
if (!r.ok) throw new Error("Erreur de chargement du fichier JSON");
return r.json();
})
.then(data => {
console.log("Scénarios chargés:", data.scenarios.length);
scenarios = data.scenarios;
loadScenario(0);
})
.catch(error => {
console.error("Erreur:", error);
document.getElementById("manifest-list").innerHTML =
`<div class="manifest-item" style="background:#FFEBEE;color:#C62828;">
Erreur de chargement des scénarios. Vérifiez que le fichier scenarios.json existe.
</div>`;
});
}
// ================= CHARGER SCÉNARIO =================
function loadScenario(index) {
console.log("Chargement scénario", index);
if (index < 0 || index >= scenarios.length) return;
currentScenarioIndex = index;
const s = scenarios[index];
// Mettre à jour le titre
const titleElement = document.getElementById("scenarioTitle");
titleElement.textContent = `Scénario ${s.id}${s.title}`;
// Mettre à jour le manifeste
document.getElementById("manifest-list").innerHTML = `
<div class="manifest-item">
<b>Type de Manifest :</b> ${s.manifest.type}<br>
<b>Manifeste (écrit par l'étudiant) :</b> ${s.manifest.manifeste}<br>
<b>Description du Profil :</b> ${s.manifest.description}
</div>`;
// Mettre à jour les compétences compactes
updateCompactCompetences(s.competences);
// Mettre à jour le radar avec les nouvelles métriques
if (s.radar && s.radar.length > 0) {
radarMetrics = s.radar;
} else {
// Utiliser les métriques par défaut avec variation pour chaque scénario
radarMetrics = DEFAULT_RADAR_METRICS.map(metric => {
// Variation de ±15% selon l'index du scénario pour rendre les données plus réalistes
const variation = (index % 7) * 5 - 15; // -15 à +15
const newValue = Math.max(10, Math.min(95, metric.value + variation));
return {
label: metric.label,
value: newValue
};
});
}
// Mettre à jour la grille des métriques radar compacte
updateCompactRadarMetricsGrid();
// Mettre à jour le graphique radar
drawRadar();
// Mettre à jour le message bot radar compact
updateCompactRadarBotMessage(s);
// Mettre à jour la heatmap enrichie compacte
drawCompactEnrichedHeatmap(s);
// Mettre à jour la persévérance spécifique au profil
updatePerseveranceProfile(s.title);
// Mettre à jour le message ReflAgent
document.getElementById("reflagent").textContent = s.reflAgent;
// Mettre à jour les boutons de navigation
updateNavButtons();
// Mettre à jour les statistiques
updateStats();
}
// ================= FONCTIONS POUR LA VERSION COMPACTE =================
// Mettre à jour les compétences compactes
function updateCompactCompetences(competences) {
const container = document.getElementById("compact-competences");
if (!container) return;
container.innerHTML = '';
competences.forEach(comp => {
// Déterminer la couleur selon la valeur
let color;
if (comp.value < 50) color = '#E53935';
else if (comp.value < 70) color = '#FB8C00';
else color = '#43A047';
// Créer l'élément de compétence
const compItem = document.createElement('div');
compItem.className = 'compact-competence-item';
compItem.innerHTML = `
<div class="compact-competence-label">
<span>${comp.label}</span>
<span>${comp.value}%</span>
</div>
<div class="compact-competence-bar">
<div class="compact-competence-fill" style="width: ${comp.value}%; background: ${color};">
${comp.value >= 10 ? comp.value + '%' : ''}
</div>
</div>
`;
container.appendChild(compItem);
});
}
// Mettre à jour la grille des métriques radar compacte
function updateCompactRadarMetricsGrid() {
const grid = document.getElementById("compact-radar-metrics-grid");
if (!grid) return;
grid.innerHTML = '';
radarMetrics.forEach(metric => {
// Déterminer la classe de couleur selon la valeur
let colorClass = "";
if (metric.value >= 70) colorClass = "high";
else if (metric.value >= 40) colorClass = "medium";
else colorClass = "low";
// Déterminer l'icône selon le type de métrique
let icon = "📊";
if (metric.label.includes("Démarrage")) icon = "🚀";
else if (metric.label.includes("Connaissances")) icon = "🎓";
else if (metric.label.includes("Niveau moyen")) icon = "📈";
else if (metric.label.includes("Taux d'erreur")) icon = "🎯";
else if (metric.label.includes("Achèvement")) icon = "🏁";
else if (metric.label.includes("Interactions")) icon = "📚";
else if (metric.label.includes("Domaines")) icon = "🔧";
// Déterminer la description
let description = "";
if (metric.label.includes("Démarrage")) description = "Rapidité d'initiation";
else if (metric.label.includes("Connaissances")) description = "Acquis démontrés";
else if (metric.label.includes("Niveau moyen")) description = "Moyenne des compétences";
else if (metric.label.includes("Taux d'erreur")) description = "Précision et attention";
else if (metric.label.includes("Achèvement")) description = "Terminaison des tâches";
else if (metric.label.includes("Interactions")) description = "Utilisation supports";
else if (metric.label.includes("Domaines")) description = "Étendue couverte";
const metricCard = document.createElement("div");
metricCard.className = "compact-metric-card";
metricCard.innerHTML = `
<div class="compact-metric-icon">${icon}</div>
<div class="compact-metric-name">${metric.label}</div>
<div class="compact-metric-value ${colorClass}">${metric.value}%</div>
<div class="compact-metric-description">${description}</div>
`;
grid.appendChild(metricCard);
});
}
// Mettre à jour le message bot radar compact
function updateCompactRadarBotMessage(scenario) {
const radarBotContent = document.getElementById("compact-radar-bot-content");
const radarBotInsights = document.getElementById("compact-radar-bot-insights");
if (!radarBotContent || !radarBotInsights) return;
// Messages pour chaque profil basé sur le titre du scénario
const profileMessages = {
"Étudiant engagé": {
title: "Étudiant Engagé et Motivé",
message: "🎯 Ton engagement est impressionnant ! Tu démontres une forte volonté d'apprendre.",
insights: [
{ icon: "🔥", text: "Motivation élevée" },
{ icon: "🎯", text: "Objectifs bien définis" },
{ icon: "📚", text: "Implication active" }
]
},
"Étudiant actif mais inefficace": {
title: "Actif mais Peu Efficace",
message: "📊 Tu es très actif mais ton taux d'erreur est élevé. Concentre-toi sur une compétence à la fois.",
insights: [
{ icon: "⚡", text: "Activité élevée" },
{ icon: "⚠️", text: "Erreurs fréquentes" },
{ icon: "🎯", text: "Focus nécessaire" }
]
},
"Étudiant orienté vers le succès": {
title: "Orientation Réussite",
message: "🏆 Tu vises l'excellence avec détermination. Ta rigueur est exemplaire.",
insights: [
{ icon: "⭐", text: "Excellence visée" },
{ icon: "🎯", text: "Objectifs ambitieux" },
{ icon: "📈", text: "Performance supérieure" }
]
},
"Étudiant motivé": {
title: "Nouvellement Motivé",
message: "🚀 Ta motivation est un excellent point de départ ! Progresse étape par étape.",
insights: [
{ icon: "🌟", text: "Motivation récente" },
{ icon: "🧱", text: "Construction des bases" },
{ icon: "📖", text: "Curiosité ouverte" }
]
},
"Étudiant surmotivé": {
title: "Surmotivé - Attention",
message: "💥 Ton niveau d'investissement est exceptionnel, attention au risque de surmenage.",
insights: [
{ icon: "⚡", text: "Investissement maximal" },
{ icon: "⚠️", text: "Risque de burnout" },
{ icon: "⚖️", text: "Équilibre nécessaire" }
]
},
"Étudiant stratégique": {
title: "Stratégique et Efficient",
message: "♟️ Tu abordes l'apprentissage avec intelligence et planification.",
insights: [
{ icon: "🧠", text: "Approche réfléchie" },
{ icon: "🎯", text: "Optimisation efforts" },
{ icon: "📊", text: "Analyse des retours" }
]
}
};
// Récupérer le message pour le profil ou utiliser un message par défaut
const profileMessage = profileMessages[scenario.title] || {
title: "Profil d'Apprentissage",
message: "Analyse de votre profil d'apprentissage en cours...",
insights: [
{ icon: "📊", text: "Évaluation indicateurs" },
{ icon: "🎯", text: "Forces et améliorations" },
{ icon: "🚀", text: "Recommandations" }
]
};
// Mettre à jour l'interface
radarBotContent.innerHTML = `<strong>${profileMessage.title}</strong><br>${profileMessage.message}`;
// Mettre à jour les insights
radarBotInsights.innerHTML = '';
profileMessage.insights.forEach(insight => {
const insightElement = document.createElement('div');
insightElement.className = 'compact-radar-insight-item';
insightElement.innerHTML = `
<div class="radar-insight-icon">${insight.icon}</div>
<div class="radar-insight-text">${insight.text}</div>
`;
radarBotInsights.appendChild(insightElement);
});
}
// Dessiner la heatmap enrichie compacte
function drawCompactEnrichedHeatmap(scenario) {
const canvas = document.getElementById("heatmap");
if (!canvas) return;
const ctx = canvas.getContext("2d");
const cellSize = 15;
const padding = 1;
const days = ["L", "M", "M", "J", "V", "S", "D"];
const weeks = 4;
const totalDays = weeks * 7;
ctx.clearRect(0, 0, canvas.width, canvas.height);
// Titre enrichi
const scenarioTitles = {
1: {
title: "Engagé mais désorganisé",
emoji: "😅",
pattern: "Effort concentré avant échéances"
},
2: {
title: "Actif mais peu efficace",
emoji: "😰",
pattern: "Démarrage lent, accélération tardive"
},
3: {
title: "Autonome et stratégique",
emoji: "😊",
pattern: "Travail régulier et équilibré"
}
};
const scenarioInfo = scenarioTitles[scenario.id] || {
title: "Votre activité",
emoji: "📊",
pattern: "Schéma à analyser"
};
ctx.font = "bold 14px Arial";
ctx.fillStyle = "#1976D2";
ctx.textAlign = "center";
ctx.fillText(`${scenarioInfo.emoji} ${scenarioInfo.title}`, canvas.width / 2, 20);
ctx.font = "12px Arial";
ctx.fillStyle = "#666";
ctx.fillText(`${scenarioInfo.pattern}`, canvas.width / 2, 40);
// Générer les données d'activité selon le scénario
const activityData = generateCompactPersistenceData(scenario.id, totalDays);
// Dessiner la heatmap
const colors = ["#EBEDF0", "#C6E48B", "#7BC96F", "#239A3B", "#196127"];
for (let day = 0; day < totalDays; day++) {
const week = Math.floor(day / 7);
const weekday = day % 7;
const x = 30 + week * (cellSize * 7 + padding * 7) + weekday * (cellSize + padding);
const y = 60 + weekday * (cellSize + padding);
const intensity = activityData[day];
// Dessiner la cellule
ctx.fillStyle = colors[intensity];
ctx.fillRect(x, y, cellSize, cellSize);
// Bordure avec indication des échéances (vendredi = jour important)
if (weekday === 4) { // Vendredi
ctx.strokeStyle = "#FF6B6B";
ctx.lineWidth = 1.5;
} else {
ctx.strokeStyle = intensity > 0 ? "#239A3B" : "#eee";
ctx.lineWidth = 0.5;
}
ctx.strokeRect(x, y, cellSize, cellSize);
}
// Analyser et afficher les métriques de persévérance compactes
analyzeCompactPersistenceMetrics(activityData, scenario.id);
}
// Mettre à jour la persévérance spécifique au profil
function updatePerseveranceProfile(scenarioTitle) {
const profile = perseveranceProfiles[scenarioTitle];
if (!profile) {
console.warn(`Aucun profil de persévérance trouvé pour: ${scenarioTitle}`);
return;
}
// Mettre à jour l'interface
const regularityText = document.getElementById("compact-regularityText");
if (regularityText) {
regularityText.innerHTML = `
<div style="display: flex; align-items: center; gap: 8px; margin-bottom: 5px;">
<div style="width: 12px; height: 12px; border-radius: 50%; background: ${profile.color};"></div>
<strong style="color: ${profile.color};">${profile.level}</strong>
</div>
<div style="font-size: 12px; color: #555; line-height: 1.4;">
${profile.interpretation}
</div>
`;
}
// Mettre à jour le score de régularité dans les indicateurs
const regularityScore = document.getElementById("compact-regularityScore");
if (regularityScore) {
// Convertir le niveau textuel en pourcentage approximatif
let scorePercent;
if (profile.level.includes("Très élevée")) scorePercent = "90%";
else if (profile.level.includes("Élevée")) scorePercent = "75%";
else if (profile.level.includes("Moyenne")) scorePercent = "55%";
else if (profile.level.includes("Faible")) scorePercent = "35%";
else if (profile.level.includes("Très faible")) scorePercent = "20%";
else scorePercent = "50%";
regularityScore.textContent = scorePercent;
regularityScore.style.color = profile.color;
}
}
// Générer des données de persévérance compactes
function generateCompactPersistenceData(scenarioId, totalDays) {
const data = new Array(totalDays).fill(0);
switch(scenarioId) {
case 1: // Scénario désorganisé - Effort concentré avant échéances
for (let i = 0; i < totalDays; i++) {
const weekday = i % 7;
if (weekday === 3 || weekday === 4) { // Jeudi et vendredi
data[i] = Math.floor(Math.random() * 2) + 3; // 3-4
} else if (weekday === 5 || weekday === 6) { // Weekend
data[i] = Math.floor(Math.random() * 2); // 0-1
} else {
data[i] = Math.floor(Math.random() * 2) + 1; // 1-2
}
}
break;
case 2: // Scénario peu efficace - Démarrage lent, accélération tardive
for (let i = 0; i < totalDays; i++) {
const progress = i / totalDays;
if (progress < 0.3) {
data[i] = Math.floor(Math.random() * 2); // 0-1
} else if (progress > 0.7) {
data[i] = Math.floor(Math.random() * 2) + 3; // 3-4
} else {
data[i] = Math.floor(Math.random() * 2) + 1; // 1-2
}
}
break;
case 3: // Scénario stratégique - Travail régulier
for (let i = 0; i < totalDays; i++) {
const weekday = i % 7;
if (weekday === 5 || weekday === 6) { // Weekend léger
data[i] = Math.floor(Math.random() * 2); // 0-1
} else {
data[i] = Math.floor(Math.random() * 2) + 2; // 2-3
}
}
break;
default:
for (let i = 0; i < totalDays; i++) {
data[i] = Math.floor(Math.random() * 5); // 0-4 aléatoire
}
}
return data;
}
// Analyser les métriques de persévérance compactes
function analyzeCompactPersistenceMetrics(activityData, scenarioId) {
const totalDays = activityData.length;
// 1. Calculer la régularité (écart-type)
const avgActivity = activityData.reduce((a, b) => a + b, 0) / totalDays;
const variance = activityData.reduce((a, b) => a + Math.pow(b - avgActivity, 2), 0) / totalDays;
const stdDev = Math.sqrt(variance);
const regularity = Math.max(0, 100 - stdDev * 25);
// 2. Identifier le schéma d'effort
let pattern = "Régulier";
let patternDescription = "Effort équilibré toute la semaine";
// Analyser la distribution
const weeklyPatterns = [];
for (let w = 0; w < 4; w++) {
const weekData = activityData.slice(w * 7, Math.min((w + 1) * 7, totalDays));
if (weekData.length < 5) continue;
const weekAvg = weekData.reduce((a, b) => a + b, 0) / weekData.length;
if (weekData[4] > weekAvg * 1.5 && weekData[3] > weekAvg * 1.3) {
pattern = "Effort concentré";
patternDescription = "Pic d'activité jeudi/vendredi";
} else if (weekData[0] < weekAvg * 0.7 && weekData[4] > weekAvg * 1.2) {
pattern = "Accélération progressive";
patternDescription = "Démarrage lent, fin forte";
}
}
// 3. Calculer la gestion des échéances
const deadlineDays = activityData.filter((_, index) => index % 7 === 3 || index % 7 === 4);
const nonDeadlineDays = activityData.filter((_, index) => index % 7 !== 3 && index % 7 !== 4);
let deadlineScore = 50;
if (deadlineDays.length > 0 && nonDeadlineDays.length > 0) {
const deadlineAvg = deadlineDays.reduce((a, b) => a + b, 0) / deadlineDays.length;
const nonDeadlineAvg = nonDeadlineDays.reduce((a, b) => a + b, 0) / nonDeadlineDays.length;
deadlineScore = Math.min(100, Math.max(0, (deadlineAvg / 4) * 100));
}
// Mettre à jour l'interface compacte
document.getElementById("compact-regularityScore").textContent = Math.round(regularity) + "%";
document.getElementById("compact-effortPattern").textContent = pattern;
document.getElementById("compact-deadlineScore").textContent = Math.round(deadlineScore) + "%";
// Mettre à jour l'analyse textuelle compacte
document.getElementById("compact-patternText").textContent = patternDescription;
}
// ================= RADAR =================
function drawRadar() {
const canvas = document.getElementById("radar");
if (!canvas) {
console.error("Canvas radar non trouvé!");
return;
}
const ctx = canvas.getContext("2d");
const cx = canvas.width / 2;
const cy = canvas.height / 2;
const radius = 200;
const n = radarMetrics.length;
ctx.clearRect(0, 0, canvas.width, canvas.height);
// Dessiner le radar
for (let i = 1; i <= 5; i++) {
ctx.beginPath();
ctx.arc(cx, cy, (radius / 5) * i, 0, 2 * Math.PI);
ctx.strokeStyle = "#e0e0e0";
ctx.stroke();
}
// Dessiner les axes
radarMetrics.forEach((m, i) => {
const angle = (2 * Math.PI * i) / n - Math.PI / 2;
ctx.beginPath();
ctx.moveTo(cx, cy);
ctx.lineTo(cx + radius * Math.cos(angle), cy + radius * Math.sin(angle));
ctx.strokeStyle = "#b0bec5";
ctx.stroke();
// Labels
const tx = cx + (radius + 25) * Math.cos(angle);
const ty = cy + (radius + 25) * Math.sin(angle);
ctx.font = "10px Arial";
ctx.fillStyle = "#000";
ctx.textAlign = angle > Math.PI / 2 || angle < -Math.PI / 2 ? "right" : "left";
ctx.textBaseline = "middle";
ctx.fillText(`${m.label.split(' ')[0]}`, tx, ty);
});
// Dessiner le polygone
ctx.beginPath();
radarMetrics.forEach((m, i) => {
const angle = (2 * Math.PI * i) / n - Math.PI / 2;
const r = radius * (m.value / 100);
const x = cx + r * Math.cos(angle);
const y = cy + r * Math.sin(angle);
i === 0 ? ctx.moveTo(x, y) : ctx.lineTo(x, y);
});
ctx.closePath();
ctx.fillStyle = "rgba(25,118,210,0.25)";
ctx.fill();
ctx.strokeStyle = "#1976D2";
ctx.lineWidth = 2;
ctx.stroke();
// Dessiner les points
radarMetrics.forEach((m, i) => {
const angle = (2 * Math.PI * i) / n - Math.PI / 2;
const r = radius * (m.value / 100);
const x = cx + r * Math.cos(angle);
const y = cy + r * Math.sin(angle);
ctx.beginPath();
ctx.arc(x, y, 4, 0, 2 * Math.PI);
ctx.fillStyle = "#1976D2";
ctx.fill();
});
}
// ================= NAVIGATION =================
document.getElementById("prevScenario").onclick = () =>
loadScenario(currentScenarioIndex - 1);
document.getElementById("nextScenario").onclick = () =>
loadScenario(currentScenarioIndex + 1);
function updateNavButtons() {
document.getElementById("prevScenario").disabled =
currentScenarioIndex === 0;
document.getElementById("nextScenario").disabled =
currentScenarioIndex === scenarios.length - 1;
}
// ================= BOUTON LECTURE CROISÉE =================
document.getElementById('crossReadersBtn').onclick = () => {
console.log('Navigation vers la page de lecture croisée...');
// Animation de transition
const reflectionDiv = document.getElementById('reflection');
if (reflectionDiv) {
reflectionDiv.style.opacity = '0.7';
reflectionDiv.style.transition = 'opacity 0.3s ease';
}
// Redirection
setTimeout(() => {
window.location.href = 'cross_reading/cross_readers.html';
}, 300);
};
// ================= MÉTRIQUES DE CONFIANCE =================
function initTrustStars(){
console.log("Initialisation des étoiles...");
// Réinitialiser toutes les métriques
for (const key in trustMetrics) {
trustMetrics[key] = 0;
}
let starsCreated = 0;
document.querySelectorAll(".stars").forEach(div => {
const metric = div.dataset.metric;
console.log(`Création des étoiles pour: ${metric}`);
// Vérifier que la métrique existe
if (!trustMetrics.hasOwnProperty(metric)) {
console.error(`Métrique inconnue: ${metric}`);
return;
}
// Vider le conteneur
div.innerHTML = '';
// Créer 5 étoiles
for (let i = 1; i <= 5; i++) {
const star = document.createElement("span");
star.textContent = "★";
star.classList.add("inactive");
star.style.cursor = "pointer";
star.title = `${i} étoile${i > 1 ? 's' : ''}`;
// Stocker la valeur dans un attribut data
star.dataset.value = i;
star.onclick = function() {
const value = parseInt(this.dataset.value);
console.log(`Clic sur ${metric}: ${value} étoiles`);
// Mettre à jour la valeur de la métrique
trustMetrics[metric] = value;
// Mettre à jour l'affichage des étoiles dans ce groupe
const allStarsInGroup = this.parentElement.children;
for (let j = 0; j < allStarsInGroup.length; j++) {
const starElem = allStarsInGroup[j];
const starValue = parseInt(starElem.dataset.value);
if (starValue <= value) {
starElem.classList.remove("inactive");
starElem.classList.add("active");
} else {
starElem.classList.add("inactive");
starElem.classList.remove("active");
}
}
// Mettre à jour la barre de progression
updateTrustBar();
};
div.appendChild(star);
starsCreated++;
}
});
console.log(`${starsCreated} étoiles créées pour ${Object.keys(trustMetrics).length} métriques`);
console.log("Métriques initialisées:", trustMetrics);
}
function updateTrustBar(){
console.log("=== MISE À JOUR BARRE DE CONFIANCE ===");
let scoreTotal = 0;
let scoreMaxPossible = 0;
let details = [];
// Calcul détaillé
for (const metric in trustMetrics) {
const valeur = trustMetrics[metric];
const poids = trustWeights[metric];
const contribution = valeur * poids;
const maxContribution = 5 * poids;
scoreTotal += contribution;
scoreMaxPossible += maxContribution;
details.push({
trique: metric,
valeur: valeur,
poids: poids,
contribution: contribution.toFixed(2),
max: maxContribution.toFixed(2)
});
}
console.log("Détails du calcul:");
details.forEach(d => {
console.log(`${d.métrique}: ${d.valeur}/5 × ${d.poids} = ${d.contribution} / ${d.max}`);
});
console.log(`Total: ${scoreTotal.toFixed(2)} / ${scoreMaxPossible.toFixed(2)}`);
// Calcul du pourcentage
let pourcentage = 0;
if (scoreMaxPossible > 0) {
pourcentage = Math.round((scoreTotal / scoreMaxPossible) * 100);
}
console.log(`Pourcentage calculé: ${pourcentage}%`);
// Mettre à jour la barre de progression
const barre = document.getElementById("trustBar");
if (barre) {
barre.style.width = pourcentage + "%";
barre.textContent = pourcentage + "%";
// Changer la couleur selon le niveau
if (pourcentage < 40) {
barre.style.background = "#E53935"; // Rouge - Faible
barre.title = `Faible confiance (${pourcentage}%)`;
} else if (pourcentage < 70) {
barre.style.background = "#FB8C00"; // Orange - Moyen
barre.title = `Confiance moyenne (${pourcentage}%)`;
} else {
barre.style.background = "#43A047"; // Vert - Fort
barre.title = `Forte confiance (${pourcentage}%)`;
}
console.log(`Barre mise à jour: ${pourcentage}% (width: ${pourcentage}%)`);
} else {
console.error("Élément #trustBar non trouvé!");
}
// Mettre à jour la statistique de confiance moyenne
const avgTrustElem = document.getElementById("avgTrustScore");
if (avgTrustElem) {
avgTrustElem.textContent = pourcentage + "%";
console.log(`Statistique moyenne mise à jour: ${pourcentage}%`);
}
// Afficher un résumé dans la console
console.log("=== RÉSUMÉ FINAL ===");
console.log(`Indice global de confiance: ${pourcentage}%`);
console.log("Valeurs des métriques:", JSON.stringify(trustMetrics, null, 2));
console.log("====================");
return pourcentage;
}
function initTrustSave(){
const saveBtn = document.getElementById("saveTrustBtn");
if (!saveBtn) {
console.error("Bouton de sauvegarde non trouvé!");
return;
}
saveBtn.onclick = () => {
console.log("=== DÉBUT SAUVEGARDE ===");
// Récupérer les informations GDPR
const gdprAccept = document.getElementById('gdprAccept').checked;
const gdprDecline = document.getElementById('gdprDecline').checked;
// Récupérer les informations conditionnelles
let evaluatorName = "";
let evaluatorRole = "";
let expertiseLevel = "";
let messageMastery = "";
if (gdprAccept) {
evaluatorName = document.getElementById("evaluatorName").value.trim();
evaluatorRole = document.getElementById("evaluatorRole").value;
expertiseLevel = document.getElementById("expertiseLevel").value;
messageMastery = document.getElementById("messageMastery").value;
}
const comment = document.getElementById("trustComment").value;
const msgDiv = document.getElementById("saveTrustMsg");
// Validation : consentement GDPR obligatoire
if (!gdprAccept && !gdprDecline) {
const message = "❌ Veuillez sélectionner une option de consentement RGPD.";
console.error(message);
if (msgDiv) {
msgDiv.textContent = message;
msgDiv.style.background = "#FFEBEE";
msgDiv.style.color = "#C62828";
}
return;
}
// Validation : si GDPR accepté, vérifier les champs obligatoires
if (gdprAccept) {
if (!evaluatorName) {
const message = "❌ Veuillez saisir votre nom et prénom.";
console.error(message);
if (msgDiv) {
msgDiv.textContent = message;
msgDiv.style.background = "#FFEBEE";
msgDiv.style.color = "#C62828";
}
const nameField = document.getElementById("evaluatorName");
nameField.style.borderColor = "#E53935";
nameField.style.boxShadow = "0 0 0 3px rgba(229, 57, 53, 0.1)";
nameField.focus();
setTimeout(() => {
nameField.style.borderColor = "#e0e0e0";
nameField.style.boxShadow = "none";
}, 3000);
return;
}
if (!evaluatorRole) {
const message = "❌ Veuillez sélectionner votre rôle.";
console.error(message);
if (msgDiv) {
msgDiv.textContent = message;
msgDiv.style.background = "#FFEBEE";
msgDiv.style.color = "#C62828";
}
return;
}
if (!expertiseLevel) {
const message = "❌ Veuillez sélectionner votre niveau d'expertise en réflexivité.";
console.error(message);
if (msgDiv) {
msgDiv.textContent = message;
msgDiv.style.background = "#FFEBEE";
msgDiv.style.color = "#C62828";
}
return;
}
if (!messageMastery) {
const message = "❌ Veuillez sélectionner votre niveau de maîtrise des messages réflexifs.";
console.error(message);
if (msgDiv) {
msgDiv.textContent = message;
msgDiv.style.background = "#FFEBEE";
msgDiv.style.color = "#C62828";
}
return;
}
}
// Vérifier si au moins une évaluation
let hasEvaluation = false;
for (const metric in trustMetrics) {
if (trustMetrics[metric] > 0) {
hasEvaluation = true;
break;
}
}
if (!hasEvaluation) {
const message = "⚠️ Veuillez évaluer au moins une métrique avant de sauvegarder.";
console.warn(message);
if (msgDiv) {
msgDiv.textContent = message;
msgDiv.style.background = "#FFF3E0";
msgDiv.style.color = "#EF6C00";
}
return;
}
// Calculer l'indice de confiance
const trustScore = updateTrustBar(); // Cette fonction retourne le pourcentage
console.log(`Indice calculé pour sauvegarde: ${trustScore}%`);
// Préparer les données
const data = {
scenario_id: scenarios[currentScenarioIndex].id,
scenario_title: scenarios[currentScenarioIndex].title,
trust_metrics: {...trustMetrics},
trust_score: trustScore,
gdpr_consent: gdprAccept ? "accept" : "decline",
evaluator_name: gdprAccept ? evaluatorName : null,
evaluator_role: gdprAccept ? evaluatorRole : null,
expertise_level: gdprAccept ? expertiseLevel : null,
message_mastery: gdprAccept ? messageMastery : null,
comment: comment || null,
timestamp: new Date().toISOString(),
trust_weights: {...trustWeights}
};
console.log("Données à envoyer:", JSON.stringify(data, null, 2));
// Envoyer au serveur
fetch("/save_trust", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify(data)
})
.then(res => {
if (!res.ok) throw new Error(`Erreur HTTP ${res.status}: ${res.statusText}`);
return res.json();
})
.then(responseData => {
console.log("✅ Réponse du serveur:", responseData);
if (msgDiv) {
const nameDisplay = gdprAccept ? evaluatorName : "Évaluateur anonyme";
msgDiv.innerHTML = `
<div style="display: flex; align-items: center; gap: 10px;">
<div style="font-size: 24px;">✅</div>
<div>
<strong>Évaluation sauvegardée avec succès !</strong><br>
<small>Merci ${nameDisplay} pour votre contribution.</small><br>
<small><em>Indice global: ${trustScore}%</em></small>
</div>
</div>
`;
msgDiv.style.background = "#E8F5E9";
msgDiv.style.color = "#2E7D32";
msgDiv.style.padding = "15px";
}
// Réinitialiser après succès (optionnel)
setTimeout(() => {
resetTrustEvaluation();
}, 3000);
})
.catch(error => {
console.error("❌ Erreur de sauvegarde:", error);
if (msgDiv) {
msgDiv.textContent = `❌ Erreur: ${error.message}`;
msgDiv.style.background = "#FFEBEE";
msgDiv.style.color = "#C62828";
}
});
};
console.log("✅ Bouton de sauvegarde initialisé");
}
// Fonction pour réinitialiser l'évaluation
function resetTrustEvaluation() {
console.log("Réinitialisation de l'évaluation...");
// Réinitialiser les métriques
for (const key in trustMetrics) {
trustMetrics[key] = 0;
}
// Réinitialiser les étoiles
document.querySelectorAll(".stars").forEach(div => {
Array.from(div.children).forEach(star => {
star.classList.add("inactive");
star.classList.remove("active");
});
});
// Réinitialiser la barre
updateTrustBar();
// Vider le commentaire
document.getElementById("trustComment").value = "";
console.log("Évaluation réinitialisée");
}
// ================= FONCTIONS UTILITAIRES =================
// Mettre à jour les statistiques
function updateStats() {
if (!scenarios || scenarios.length === 0) return;
const currentScenario = scenarios[currentScenarioIndex];
document.getElementById("currentScenarioNum").textContent = currentScenario.id;
// Niveau de risque
const risk = currentScenario.risk || 50;
let riskLevel = "Moyen";
let riskColor = "#FB8C00";
if (risk < 40) {
riskLevel = "Faible";
riskColor = "#43A047";
} else if (risk > 70) {
riskLevel = "Élevé";
riskColor = "#E53935";
}
document.getElementById("riskLevel").textContent = riskLevel;
document.getElementById("riskLevel").style.color = riskColor;
// Activité moyenne à partir des données radar
if (currentScenario.radar && currentScenario.radar.length > 0) {
const avgRadar = currentScenario.radar.reduce((sum, item) => sum + item.value, 0) / currentScenario.radar.length;
document.getElementById("avgActivity").textContent = Math.round(avgRadar) + "%";
}
}
// Fonction pour remplir un exemple d'évaluateur
function fillSampleEvaluator() {
// Sélectionner l'option GDPR "accept"
document.getElementById('gdprAccept').checked = true;
document.getElementById('gdprDecline').checked = false;
// Mettre à jour les champs
initGDPR();
// Remplir les champs
document.getElementById("evaluatorName").value = "Martin Sophie";
document.getElementById("evaluatorRole").value = "enseignant";
document.getElementById("expertiseLevel").value = "avance";
document.getElementById("messageMastery").value = "intermediaire_msg";
showNotification("Exemple", "Champs d'évaluateur remplis avec un exemple", "info");
}
// Fonction pour effacer les champs évaluateur
function clearEvaluatorFields() {
// Sélectionner l'option GDPR "decline" par défaut
document.getElementById('gdprDecline').checked = true;
document.getElementById('gdprAccept').checked = false;
// Mettre à jour les champs
initGDPR();
showNotification("Champs effacés", "Les informations d'évaluateur ont été effacées", "info");
}
// Fonction pour afficher une notification
function showNotification(title, message, type = "info") {
console.log(`[${type}] ${title}: ${message}`);
const msgDiv = document.getElementById("saveTrustMsg");
if (msgDiv) {
msgDiv.textContent = `${title}: ${message}`;
msgDiv.style.background = type === "success" ? "#E8F5E9" :
type === "error" ? "#FFEBEE" : "#E3F2FD";
msgDiv.style.color = type === "success" ? "#2E7D32" :
type === "error" ? "#C62828" : "#1565C0";
}
}
// Changer le mode d'analyse de persévérance
function changePersistenceAnalysis() {
const mode = document.getElementById("persistenceMode").value;
const currentScenario = scenarios[currentScenarioIndex];
// Redessiner la heatmap avec le mode sélectionné
drawCompactEnrichedHeatmap(currentScenario);
// Ajouter une annotation selon le mode
const canvas = document.getElementById("heatmap");
const ctx = canvas.getContext("2d");
ctx.font = "12px Arial";
ctx.fillStyle = "#1976D2";
ctx.textAlign = "center";
switch(mode) {
case "regularity":
ctx.fillText("📊 Analyse de la régularité", canvas.width / 2, canvas.height - 10);
break;
case "effortPattern":
ctx.fillText("🔄 Schéma d'effort", canvas.width / 2, canvas.height - 10);
break;
case "deadline":
ctx.fillText("⏰ Gestion des échéances", canvas.width / 2, canvas.height - 10);
break;
case "combined":
ctx.fillText("🎯 Vue combinée", canvas.width / 2, canvas.height - 10);
break;
}
}
// Exposer les fonctions globales
window.changePersistenceAnalysis = changePersistenceAnalysis;
window.updateStats = updateStats;
window.showNotification = showNotification;
window.fillSampleEvaluator = fillSampleEvaluator;
window.clearEvaluatorFields = clearEvaluatorFields;
</script>
</body>
</html>