OUAREDAEK commited on
Commit
cdf0628
·
verified ·
1 Parent(s): 2789653

Upload folder using huggingface_hub

Browse files
Files changed (2) hide show
  1. index-old1.html +1342 -152
  2. index.html +961 -3
index-old1.html CHANGED
@@ -1,159 +1,1349 @@
1
  <!DOCTYPE html>
2
  <html lang="fr">
3
  <head>
4
- <meta charset="UTF-8">
5
- <title>Cognitive-Driven Language Learning</title>
6
-
7
- <style>
8
- body { font-family: Arial; margin: 0; background: #f4f6f8; }
9
- header { background: #1e293b; color: white; padding: 15px; text-align: center; }
10
- nav { display: flex; background: #334155; }
11
- nav button {
12
- flex: 1; padding: 12px; border: none; color: white;
13
- background: #334155; cursor: pointer;
14
- }
15
- nav button:hover { background: #475569; }
16
- section { display: none; padding: 20px; }
17
- section.active { display: block; background: white; margin: 10px; border-radius: 8px; }
18
-
19
- input, select, textarea {
20
- width: 100%; padding: 8px; margin: 5px 0;
21
- }
22
-
23
- .card {
24
- background: #f8fafc; padding: 10px; margin: 8px 0; border-left: 4px solid #3b82f6;
25
- }
26
- </style>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
27
  </head>
28
-
29
  <body>
30
-
31
- <header>
32
- <h2>🧠 Cognitive-Driven AI for Language Learning</h2>
33
- <p>Optimizing Long-Term Memory Retention through Spaced Repetition (SM-2), Self-Regulated Learning, Metacognition, and Gentle Reminders via Multi-Armed Bandits</p>
34
- </header>
35
-
36
- <nav>
37
- <button onclick="showTab('objectif')">🎯 Objectif</button>
38
- <button onclick="showTab('planner')">📅 Planner</button>
39
- <button onclick="showTab('journal')">📔 Journal SRL</button>
40
- <button onclick="showTab('notifications')">🔔 Notifications</button>
41
- </nav>
42
-
43
- <!-- OBJECTIF -->
44
- <section id="objectif" class="active">
45
- <h3>🎯 Définir mon objectif</h3>
46
-
47
- <label>Compétence cible</label>
48
- <select id="competence">
49
- {% for c in competences %}
50
- <option>{{ c }}</option>
51
- {% endfor %}
52
- </select>
53
-
54
- <label>Date de début</label>
55
- <input type="date" id="start">
56
-
57
- <label>Date de fin</label>
58
- <input type="date" id="end">
59
-
60
- <label>Durée par session (minutes)</label>
61
- <select id="duration">
62
- <option>10</option><option>20</option><option>30</option>
63
- </select>
64
-
65
- <button onclick="generatePlanner()">Générer le planner</button>
66
- </section>
67
-
68
- <!-- PLANNER -->
69
- <section id="planner">
70
- <h3>📅 Planner personnalisé</h3>
71
- <div id="plannerContent"></div>
72
- </section>
73
-
74
- <!-- JOURNAL -->
75
- <section id="journal">
76
- <h3>📔 Journal de bord – Self-Regulated Learning</h3>
77
-
78
- <label>To-Do</label>
79
- <textarea id="todo"></textarea>
80
-
81
- <label>Doing</label>
82
- <textarea id="doing"></textarea>
83
-
84
- <label>Done</label>
85
- <textarea id="done"></textarea>
86
-
87
- <label>Qu’est-ce qui a facilité l’apprentissage ?</label>
88
- <textarea id="q1"></textarea>
89
-
90
- <label>Qu’est-ce qui a été difficile ?</label>
91
- <textarea id="q2"></textarea>
92
-
93
- <label>Stratégie à tester la prochaine fois</label>
94
- <textarea id="q3"></textarea>
95
-
96
- <button onclick="saveJournal()">Sauvegarder</button>
97
- </section>
98
-
99
- <!-- NOTIFICATIONS -->
100
- <section id="notifications">
101
- <h3>🔔 Gentle Reminders intelligents</h3>
102
- <button onclick="getReminder()">Afficher un rappel</button>
103
- <div id="notifBox" class="card"></div>
104
- </section>
105
-
106
- <script>
107
- function showTab(id){
108
- document.querySelectorAll("section").forEach(s => s.classList.remove("active"));
109
- document.getElementById(id).classList.add("active");
110
- }
111
-
112
- function generatePlanner(){
113
- fetch("/planner", {
114
- method:"POST",
115
- headers:{'Content-Type':'application/json'},
116
- body:JSON.stringify({
117
- competence: document.getElementById("competence").value,
118
- start_date: document.getElementById("start").value,
119
- end_date: document.getElementById("end").value,
120
- session_duration: document.getElementById("duration").value
121
- })
122
- }).then(r=>r.json()).then(data=>{
123
- let html="";
124
- data.forEach(p=>{
125
- html+=`<div class="card">
126
- 📆 ${p.date}<br>
127
- 📘 ${p.competence}<br>
128
- ⏱ ${p.duration} min<br>
129
- 🔁 Répétition ${p.repetition}
130
- </div>`;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
131
  });
132
- document.getElementById("plannerContent").innerHTML = html;
133
- showTab("planner");
134
- });
135
- }
136
-
137
- function saveJournal(){
138
- fetch("/journal",{
139
- method:"POST",
140
- headers:{'Content-Type':'application/json'},
141
- body:JSON.stringify({
142
- todo:todo.value,
143
- doing:doing.value,
144
- done:done.value,
145
- reflection:[q1.value,q2.value,q3.value]
146
- })
147
- });
148
- alert("Journal sauvegardé ✔");
149
- }
150
-
151
- function getReminder(){
152
- fetch("/notifications").then(r=>r.json()).then(data=>{
153
- document.getElementById("notifBox").innerText=data.message;
154
- });
155
- }
156
- </script>
157
-
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
158
  </body>
159
- </html>
 
1
  <!DOCTYPE html>
2
  <html lang="fr">
3
  <head>
4
+ <meta charset="UTF-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>Cognitive-Driven AI for Language Learning | Professionnel</title>
7
+
8
+ <!-- Chart.js pour les visualisations -->
9
+ <script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
10
+ <!-- Font Awesome pour les icônes -->
11
+ <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
12
+
13
+ <style>
14
+ :root {
15
+ --primary-color: #3b82f6;
16
+ --secondary-color: #10b981;
17
+ --accent-color: #8b5cf6;
18
+ --warning-color: #f59e0b;
19
+ --danger-color: #ef4444;
20
+ --dark-color: #1e293b;
21
+ --light-color: #f8fafc;
22
+ --gray-color: #64748b;
23
+ }
24
+
25
+ * {
26
+ margin: 0;
27
+ padding: 0;
28
+ box-sizing: border-box;
29
+ }
30
+
31
+ body {
32
+ font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
33
+ background: linear-gradient(135deg, #f1f5f9 0%, #e2e8f0 100%);
34
+ color: var(--dark-color);
35
+ line-height: 1.6;
36
+ min-height: 100vh;
37
+ }
38
+
39
+ .container {
40
+ max-width: 1400px;
41
+ margin: 0 auto;
42
+ padding: 20px;
43
+ }
44
+
45
+ /* Header */
46
+ .header {
47
+ background: linear-gradient(135deg, var(--dark-color) 0%, #0f172a 100%);
48
+ color: white;
49
+ padding: 2rem;
50
+ border-radius: 15px;
51
+ margin-bottom: 2rem;
52
+ box-shadow: 0 10px 25px rgba(0, 0, 0, 0.1);
53
+ position: relative;
54
+ overflow: hidden;
55
+ }
56
+
57
+ .header::before {
58
+ content: '';
59
+ position: absolute;
60
+ top: 0;
61
+ left: 0;
62
+ right: 0;
63
+ height: 4px;
64
+ background: linear-gradient(90deg, var(--primary-color), var(--secondary-color), var(--accent-color));
65
+ }
66
+
67
+ .header h1 {
68
+ font-size: 2.5rem;
69
+ margin-bottom: 0.5rem;
70
+ display: flex;
71
+ align-items: center;
72
+ gap: 15px;
73
+ }
74
+
75
+ .header p {
76
+ font-size: 1.1rem;
77
+ opacity: 0.9;
78
+ max-width: 800px;
79
+ }
80
+
81
+ .badge {
82
+ background: var(--primary-color);
83
+ color: white;
84
+ padding: 5px 15px;
85
+ border-radius: 20px;
86
+ font-size: 0.9rem;
87
+ display: inline-block;
88
+ margin-top: 10px;
89
+ }
90
+
91
+ /* Navigation */
92
+ .nav-tabs {
93
+ display: flex;
94
+ background: white;
95
+ border-radius: 12px;
96
+ overflow: hidden;
97
+ box-shadow: 0 5px 15px rgba(0, 0, 0, 0.05);
98
+ margin-bottom: 2rem;
99
+ flex-wrap: wrap;
100
+ }
101
+
102
+ .nav-tab {
103
+ flex: 1;
104
+ min-width: 200px;
105
+ padding: 1.2rem;
106
+ border: none;
107
+ background: transparent;
108
+ color: var(--gray-color);
109
+ font-size: 1rem;
110
+ font-weight: 600;
111
+ cursor: pointer;
112
+ display: flex;
113
+ align-items: center;
114
+ justify-content: center;
115
+ gap: 10px;
116
+ transition: all 0.3s ease;
117
+ }
118
+
119
+ .nav-tab:hover {
120
+ background: #f8fafc;
121
+ color: var(--primary-color);
122
+ }
123
+
124
+ .nav-tab.active {
125
+ background: var(--primary-color);
126
+ color: white;
127
+ box-shadow: 0 5px 15px rgba(59, 130, 246, 0.3);
128
+ }
129
+
130
+ /* Sections */
131
+ .tab-content {
132
+ display: none;
133
+ animation: fadeIn 0.5s ease;
134
+ }
135
+
136
+ .tab-content.active {
137
+ display: block;
138
+ }
139
+
140
+ @keyframes fadeIn {
141
+ from { opacity: 0; transform: translateY(10px); }
142
+ to { opacity: 1; transform: translateY(0); }
143
+ }
144
+
145
+ .card {
146
+ background: white;
147
+ border-radius: 15px;
148
+ padding: 2rem;
149
+ margin-bottom: 2rem;
150
+ box-shadow: 0 5px 20px rgba(0, 0, 0, 0.05);
151
+ border-left: 5px solid var(--primary-color);
152
+ }
153
+
154
+ .card-header {
155
+ display: flex;
156
+ justify-content: space-between;
157
+ align-items: center;
158
+ margin-bottom: 1.5rem;
159
+ padding-bottom: 1rem;
160
+ border-bottom: 2px solid #f1f5f9;
161
+ }
162
+
163
+ .card-header h3 {
164
+ font-size: 1.5rem;
165
+ color: var(--dark-color);
166
+ display: flex;
167
+ align-items: center;
168
+ gap: 10px;
169
+ }
170
+
171
+ /* Form Elements */
172
+ .form-group {
173
+ margin-bottom: 1.5rem;
174
+ }
175
+
176
+ .form-label {
177
+ display: block;
178
+ margin-bottom: 0.5rem;
179
+ font-weight: 600;
180
+ color: var(--dark-color);
181
+ display: flex;
182
+ align-items: center;
183
+ gap: 8px;
184
+ }
185
+
186
+ .form-control {
187
+ width: 100%;
188
+ padding: 12px 15px;
189
+ border: 2px solid #e2e8f0;
190
+ border-radius: 10px;
191
+ font-size: 1rem;
192
+ transition: all 0.3s;
193
+ background: #f8fafc;
194
+ }
195
+
196
+ .form-control:focus {
197
+ outline: none;
198
+ border-color: var(--primary-color);
199
+ background: white;
200
+ box-shadow: 0 0 0 3px rgba(59, 130, 246, 0.1);
201
+ }
202
+
203
+ .form-row {
204
+ display: flex;
205
+ gap: 20px;
206
+ margin-bottom: 1.5rem;
207
+ }
208
+
209
+ .form-col {
210
+ flex: 1;
211
+ }
212
+
213
+ /* Buttons */
214
+ .btn {
215
+ padding: 12px 25px;
216
+ border: none;
217
+ border-radius: 10px;
218
+ font-size: 1rem;
219
+ font-weight: 600;
220
+ cursor: pointer;
221
+ transition: all 0.3s;
222
+ display: inline-flex;
223
+ align-items: center;
224
+ justify-content: center;
225
+ gap: 10px;
226
+ }
227
+
228
+ .btn-primary {
229
+ background: linear-gradient(135deg, var(--primary-color) 0%, #2563eb 100%);
230
+ color: white;
231
+ }
232
+
233
+ .btn-primary:hover {
234
+ transform: translateY(-2px);
235
+ box-shadow: 0 10px 20px rgba(59, 130, 246, 0.3);
236
+ }
237
+
238
+ .btn-secondary {
239
+ background: var(--secondary-color);
240
+ color: white;
241
+ }
242
+
243
+ .btn-large {
244
+ padding: 15px 30px;
245
+ font-size: 1.1rem;
246
+ }
247
+
248
+ /* Visualizations */
249
+ .visualization-container {
250
+ background: white;
251
+ border-radius: 15px;
252
+ padding: 2rem;
253
+ margin-top: 2rem;
254
+ box-shadow: 0 5px 20px rgba(0, 0, 0, 0.05);
255
+ }
256
+
257
+ .chart-container {
258
+ position: relative;
259
+ height: 400px;
260
+ width: 100%;
261
+ }
262
+
263
+ /* Planner Cards */
264
+ .planning-grid {
265
+ display: grid;
266
+ grid-template-columns: repeat(auto-fill, minmax(350px, 1fr));
267
+ gap: 20px;
268
+ margin-top: 2rem;
269
+ }
270
+
271
+ .session-card {
272
+ background: white;
273
+ border-radius: 12px;
274
+ padding: 1.5rem;
275
+ box-shadow: 0 5px 15px rgba(0, 0, 0, 0.05);
276
+ border-top: 4px solid var(--primary-color);
277
+ transition: transform 0.3s;
278
+ }
279
+
280
+ .session-card:hover {
281
+ transform: translateY(-5px);
282
+ box-shadow: 0 10px 25px rgba(0, 0, 0, 0.1);
283
+ }
284
+
285
+ .session-header {
286
+ display: flex;
287
+ justify-content: space-between;
288
+ align-items: flex-start;
289
+ margin-bottom: 1rem;
290
+ }
291
+
292
+ .session-date {
293
+ font-size: 1.2rem;
294
+ font-weight: bold;
295
+ color: var(--dark-color);
296
+ }
297
+
298
+ .session-repetition {
299
+ background: var(--primary-color);
300
+ color: white;
301
+ padding: 5px 15px;
302
+ border-radius: 20px;
303
+ font-size: 0.9rem;
304
+ }
305
+
306
+ .session-details {
307
+ margin-top: 1rem;
308
+ display: flex;
309
+ flex-direction: column;
310
+ gap: 8px;
311
+ }
312
+
313
+ .detail-item {
314
+ display: flex;
315
+ justify-content: space-between;
316
+ padding: 5px 0;
317
+ border-bottom: 1px dashed #e2e8f0;
318
+ }
319
+
320
+ /* Notifications */
321
+ .notification-card {
322
+ background: linear-gradient(135deg, #fef3c7 0%, #fde68a 100%);
323
+ border-left: 5px solid var(--warning-color);
324
+ padding: 1.5rem;
325
+ border-radius: 12px;
326
+ margin-bottom: 1rem;
327
+ animation: slideIn 0.5s ease;
328
+ }
329
+
330
+ @keyframes slideIn {
331
+ from { transform: translateX(-20px); opacity: 0; }
332
+ to { transform: translateX(0); opacity: 1; }
333
+ }
334
+
335
+ /* Stats Cards */
336
+ .stats-grid {
337
+ display: grid;
338
+ grid-template-columns: repeat(auto-fill, minmax(250px, 1fr));
339
+ gap: 20px;
340
+ margin-top: 2rem;
341
+ }
342
+
343
+ .stat-card {
344
+ background: white;
345
+ border-radius: 12px;
346
+ padding: 1.5rem;
347
+ text-align: center;
348
+ box-shadow: 0 5px 15px rgba(0, 0, 0, 0.05);
349
+ }
350
+
351
+ .stat-value {
352
+ font-size: 2.5rem;
353
+ font-weight: bold;
354
+ color: var(--primary-color);
355
+ margin: 10px 0;
356
+ }
357
+
358
+ .stat-label {
359
+ color: var(--gray-color);
360
+ font-size: 0.9rem;
361
+ }
362
+
363
+ /* Quality Indicators */
364
+ .quality-indicator {
365
+ display: flex;
366
+ gap: 10px;
367
+ margin: 15px 0;
368
+ }
369
+
370
+ .quality-dot {
371
+ width: 25px;
372
+ height: 25px;
373
+ border-radius: 50%;
374
+ cursor: pointer;
375
+ transition: all 0.3s;
376
+ display: flex;
377
+ align-items: center;
378
+ justify-content: center;
379
+ color: white;
380
+ font-weight: bold;
381
+ font-size: 0.8rem;
382
+ }
383
+
384
+ .quality-dot:hover {
385
+ transform: scale(1.2);
386
+ }
387
+
388
+ .quality-0 { background: linear-gradient(135deg, #ef4444, #dc2626); }
389
+ .quality-1 { background: linear-gradient(135deg, #f59e0b, #d97706); }
390
+ .quality-2 { background: linear-gradient(135deg, #10b981, #059669); }
391
+ .quality-3 { background: linear-gradient(135deg, #3b82f6, #1d4ed8); }
392
+
393
+ .quality-dot.active {
394
+ box-shadow: 0 0 0 3px white, 0 0 0 6px currentColor;
395
+ }
396
+
397
+ /* Responsive */
398
+ @media (max-width: 768px) {
399
+ .form-row {
400
+ flex-direction: column;
401
+ gap: 0;
402
+ }
403
+
404
+ .nav-tabs {
405
+ flex-direction: column;
406
+ }
407
+
408
+ .planning-grid {
409
+ grid-template-columns: 1fr;
410
+ }
411
+
412
+ .header h1 {
413
+ font-size: 2rem;
414
+ }
415
+ }
416
+ </style>
417
  </head>
 
418
  <body>
419
+ <div class="container">
420
+ <!-- Header -->
421
+ <header class="header">
422
+ <h1><i class="fas fa-brain"></i> Cognitive-Driven AI for Language Learning</h1>
423
+ <p>Optimizing Long-Term Memory Retention through Spaced Repetition (SM-2), Self-Regulated Learning, Metacognition, and Gentle Reminders via Multi-Armed Bandits</p>
424
+ <div class="badge">Version Professionnelle 2.0 | SM-2 Niveau Avancé</div>
425
+ </header>
426
+
427
+ <!-- Navigation -->
428
+ <nav class="nav-tabs">
429
+ <button class="nav-tab active" onclick="showTab('objectif')">
430
+ <i class="fas fa-bullseye"></i> Objectif
431
+ </button>
432
+ <button class="nav-tab" onclick="showTab('planner')">
433
+ <i class="fas fa-calendar-alt"></i> Planner SM-2
434
+ </button>
435
+ <button class="nav-tab" onclick="showTab('journal')">
436
+ <i class="fas fa-book"></i> Journal SRL
437
+ </button>
438
+ <button class="nav-tab" onclick="showTab('notifications')">
439
+ <i class="fas fa-bell"></i> Notifications IA
440
+ </button>
441
+ <button class="nav-tab" onclick="showTab('stats')">
442
+ <i class="fas fa-chart-line"></i> Statistiques
443
+ </button>
444
+ <button class="nav-tab" onclick="showTab('learn')">
445
+ <i class="fas fa-graduation-cap"></i> Apprendre SM-2
446
+ </button>
447
+ </nav>
448
+
449
+ <!-- Objectif Section -->
450
+ <section id="objectif" class="tab-content active">
451
+ <div class="card">
452
+ <div class="card-header">
453
+ <h3><i class="fas fa-bullseye"></i> Définir mon Objectif d'Apprentissage</h3>
454
+ </div>
455
+
456
+ <div class="form-row">
457
+ <div class="form-col">
458
+ <label class="form-label"><i class="fas fa-language"></i> Compétence Cible</label>
459
+ <select id="competence" class="form-control" onchange="previewSM2Curve()">
460
+ <option value="">Sélectionnez une compétence...</option>
461
+ </select>
462
+ </div>
463
+ <div class="form-col">
464
+ <label class="form-label"><i class="fas fa-brain"></i> Niveau Actuel</label>
465
+ <select id="level" class="form-control">
466
+ <option value="0">Débutant</option>
467
+ <option value="1" selected>Intermédiaire</option>
468
+ <option value="2">Avancé</option>
469
+ <option value="3">Expert</option>
470
+ </select>
471
+ </div>
472
+ </div>
473
+
474
+ <div class="form-row">
475
+ <div class="form-col">
476
+ <label class="form-label"><i class="fas fa-calendar-start"></i> Date de Début</label>
477
+ <input type="date" id="start" class="form-control" value="2026-01-29">
478
+ </div>
479
+ <div class="form-col">
480
+ <label class="form-label"><i class="fas fa-calendar-end"></i> Date de Fin</label>
481
+ <input type="date" id="end" class="form-control" value="2026-12-31">
482
+ </div>
483
+ </div>
484
+
485
+ <div class="form-group">
486
+ <label class="form-label"><i class="fas fa-clock"></i> Durée par Session (minutes)</label>
487
+ <select id="duration" class="form-control">
488
+ <option value="10">10 minutes (Micro-learning)</option>
489
+ <option value="20" selected>20 minutes (Optimal)</option>
490
+ <option value="30">30 minutes (Approfondissement)</option>
491
+ <option value="45">45 minutes (Session intensive)</option>
492
+ </select>
493
+ </div>
494
+
495
+ <div class="form-group">
496
+ <label class="form-label"><i class="fas fa-chart-line"></i> Qualité Estimée de Rétention</label>
497
+ <div class="quality-indicator">
498
+ <div class="quality-dot quality-0" data-quality="0" onclick="selectQuality(0)">0</div>
499
+ <div class="quality-dot quality-1" data-quality="1" onclick="selectQuality(1)">1</div>
500
+ <div class="quality-dot quality-2 active" data-quality="2" onclick="selectQuality(2)">2</div>
501
+ <div class="quality-dot quality-3" data-quality="3" onclick="selectQuality(3)">3</div>
502
+ </div>
503
+ <small id="quality-description">Bon - Consolidation progressive</small>
504
+ </div>
505
+
506
+ <button class="btn btn-primary btn-large" onclick="generatePlanner()">
507
+ <i class="fas fa-cogs"></i> Générer le Planner SM-2
508
+ </button>
509
+
510
+ <div id="preview" style="display: none; margin-top: 2rem;">
511
+ <h4><i class="fas fa-eye"></i> Aperçu de la Courbe SM-2</h4>
512
+ <div class="chart-container">
513
+ <canvas id="intervalChart"></canvas>
514
+ </div>
515
+ </div>
516
+ </div>
517
+ </section>
518
+
519
+ <!-- Planner Section -->
520
+ <section id="planner" class="tab-content">
521
+ <div class="card">
522
+ <div class="card-header">
523
+ <h3><i class="fas fa-calendar-alt"></i> Planner SM-2 Personnalisé</h3>
524
+ <button class="btn btn-secondary" onclick="exportPlanner()">
525
+ <i class="fas fa-download"></i> Exporter
526
+ </button>
527
+ </div>
528
+
529
+ <div id="plannerStats" class="stats-grid"></div>
530
+
531
+ <div id="plannerContent" class="planning-grid"></div>
532
+
533
+ <div class="visualization-container">
534
+ <h4><i class="fas fa-chart-line"></i> Visualisation des Intervalles SM-2</h4>
535
+ <div class="chart-container">
536
+ <canvas id="sm2Visualization"></canvas>
537
+ </div>
538
+ </div>
539
+ </div>
540
+ </section>
541
+
542
+ <!-- Journal Section -->
543
+ <section id="journal" class="tab-content">
544
+ <div class="card">
545
+ <div class="card-header">
546
+ <h3><i class="fas fa-book"></i> Journal d'Apprentissage Autorégulé</h3>
547
+ <button class="btn btn-secondary" onclick="loadJournalEntries()">
548
+ <i class="fas fa-history"></i> Historique
549
+ </button>
550
+ </div>
551
+
552
+ <div class="form-row">
553
+ <div class="form-col">
554
+ <label class="form-label"><i class="fas fa-tasks"></i> Planifié (To-Do)</label>
555
+ <textarea id="todo" class="form-control" rows="3" placeholder="Ce que vous prévoyez d'apprendre..."></textarea>
556
+ </div>
557
+ <div class="form-col">
558
+ <label class="form-label"><i class="fas fa-spinner"></i> En Cours (Doing)</label>
559
+ <textarea id="doing" class="form-control" rows="3" placeholder="Ce que vous faites actuellement..."></textarea>
560
+ </div>
561
+ </div>
562
+
563
+ <div class="form-group">
564
+ <label class="form-label"><i class="fas fa-check-circle"></i> Accompli (Done)</label>
565
+ <textarea id="done" class="form-control" rows="3" placeholder="Ce que vous avez accompli..."></textarea>
566
+ </div>
567
+
568
+ <div class="form-group">
569
+ <label class="form-label"><i class="fas fa-star"></i> Auto-évaluation (1-5)</label>
570
+ <div class="quality-indicator">
571
+ <div class="quality-dot quality-0" onclick="setEvaluation(1)">1</div>
572
+ <div class="quality-dot quality-1" onclick="setEvaluation(2)">2</div>
573
+ <div class="quality-dot quality-2 active" onclick="setEvaluation(3)">3</div>
574
+ <div class="quality-dot quality-3" onclick="setEvaluation(4)">4</div>
575
+ <div class="quality-dot" onclick="setEvaluation(5)" style="background:linear-gradient(135deg, #8b5cf6, #7c3aed)">5</div>
576
+ </div>
577
+ <input type="hidden" id="auto_eval" value="3">
578
+ </div>
579
+
580
+ <div class="form-group">
581
+ <label class="form-label"><i class="fas fa-lightbulb"></i> Stratégie Métacognitive</label>
582
+ <textarea id="metacognition" class="form-control" rows="3" placeholder="Quelle stratégie avez-vous utilisée ? Que changeriez-vous ?"></textarea>
583
+ </div>
584
+
585
+ <button class="btn btn-primary btn-large" onclick="saveJournal()">
586
+ <i class="fas fa-save"></i> Sauvegarder l'Entrée
587
+ </button>
588
+
589
+ <div id="journalHistory" style="display: none; margin-top: 2rem;">
590
+ <h4><i class="fas fa-history"></i> Dernières Entrées</h4>
591
+ <div id="journalEntries"></div>
592
+ </div>
593
+ </div>
594
+ </section>
595
+
596
+ <!-- Notifications Section -->
597
+ <section id="notifications" class="tab-content">
598
+ <div class="card">
599
+ <div class="card-header">
600
+ <h3><i class="fas fa-bell"></i> Notifications Intelligentes par Bandits Multi-Bras</h3>
601
+ <button class="btn btn-secondary" onclick="getIntelligentReminder()">
602
+ <i class="fas fa-sync"></i> Nouveau Rappel
603
+ </button>
604
+ </div>
605
+
606
+ <div id="notificationContainer">
607
+ <div class="notification-card">
608
+ <p><i class="fas fa-info-circle"></i> Cliquez sur "Nouveau Rappel" pour recevoir une notification personnalisée basée sur vos habitudes d'apprentissage.</p>
609
+ </div>
610
+ </div>
611
+
612
+ <div class="visualization-container">
613
+ <h4><i class="fas fa-chart-bar"></i> Efficacité des Types de Notifications</h4>
614
+ <div class="chart-container">
615
+ <canvas id="notificationChart"></canvas>
616
+ </div>
617
+ </div>
618
+ </div>
619
+ </section>
620
+
621
+ <!-- Statistics Section -->
622
+ <section id="stats" class="tab-content">
623
+ <div class="card">
624
+ <div class="card-header">
625
+ <h3><i class="fas fa-chart-line"></i> Tableau de Bord d'Apprentissage</h3>
626
+ <button class="btn btn-secondary" onclick="refreshStats()">
627
+ <i class="fas fa-redo"></i> Actualiser
628
+ </button>
629
+ </div>
630
+
631
+ <div id="statsContainer" class="stats-grid"></div>
632
+
633
+ <div class="visualization-container">
634
+ <h4><i class="fas fa-chart-area"></i> Progression de la Rétention</h4>
635
+ <div class="chart-container">
636
+ <canvas id="retentionChart"></canvas>
637
+ </div>
638
+ </div>
639
+ </div>
640
+ </section>
641
+
642
+ <!-- Learn SM-2 Section -->
643
+ <section id="learn" class="tab-content">
644
+ <div class="card">
645
+ <div class="card-header">
646
+ <h3><i class="fas fa-graduation-cap"></i> Apprendre l'Algorithme SM-2</h3>
647
+ </div>
648
+
649
+ <div id="sm2Explanation"></div>
650
+
651
+ <div class="visualization-container">
652
+ <h4><i class="fas fa-chart-network"></i> Comparaison des Niveaux de Qualité SM-2</h4>
653
+ <div class="chart-container">
654
+ <canvas id="comparisonChart"></canvas>
655
+ </div>
656
+ </div>
657
+ </div>
658
+ </section>
659
+ </div>
660
+
661
+ <script>
662
+ // Variables globales
663
+ let currentChart = null;
664
+ let currentQuality = 2; // Niveau 2 par défaut
665
+ let previewChart = null;
666
+
667
+ // Initialisation
668
+ document.addEventListener('DOMContentLoaded', function() {
669
+ loadCompetences();
670
+ refreshStats();
671
+ loadSM2Explanation();
672
+ updateComparisonChart();
673
  });
674
+
675
+ // Navigation
676
+ function showTab(tabId) {
677
+ // Masquer toutes les sections
678
+ document.querySelectorAll('.tab-content').forEach(section => {
679
+ section.classList.remove('active');
680
+ });
681
+
682
+ // Désactiver tous les onglets
683
+ document.querySelectorAll('.nav-tab').forEach(tab => {
684
+ tab.classList.remove('active');
685
+ });
686
+
687
+ // Activer la section sélectionnée
688
+ document.getElementById(tabId).classList.add('active');
689
+
690
+ // Activer l'onglet correspondant
691
+ const tabNames = {
692
+ 'objectif': 'Objectif',
693
+ 'planner': 'Planner',
694
+ 'journal': 'Journal',
695
+ 'notifications': 'Notifications',
696
+ 'stats': 'Statistiques',
697
+ 'learn': 'Apprendre'
698
+ };
699
+
700
+ document.querySelectorAll('.nav-tab').forEach(tab => {
701
+ if (tab.textContent.includes(tabNames[tabId])) {
702
+ tab.classList.add('active');
703
+ }
704
+ });
705
+
706
+ // Actions spécifiques par onglet
707
+ if (tabId === 'stats') {
708
+ refreshStats();
709
+ } else if (tabId === 'learn') {
710
+ updateComparisonChart();
711
+ }
712
+ }
713
+
714
+ // Charger les compétences
715
+ async function loadCompetences() {
716
+ try {
717
+ const response = await fetch('/api/competences');
718
+ const competences = await response.json();
719
+
720
+ const select = document.getElementById('competence');
721
+ select.innerHTML = '<option value="">Sélectionnez une compétence...</option>';
722
+
723
+ competences.forEach(comp => {
724
+ const option = document.createElement('option');
725
+ option.value = comp.label;
726
+ option.textContent = `${comp.id} - ${comp.label} (${comp.category})`;
727
+ select.appendChild(option);
728
+ });
729
+ } catch (error) {
730
+ console.error('Erreur chargement compétences:', error);
731
+ }
732
+ }
733
+
734
+ // Sélection de la qualité
735
+ function selectQuality(level) {
736
+ currentQuality = level;
737
+
738
+ // Mettre à jour les indicateurs visuels
739
+ document.querySelectorAll('.quality-dot').forEach(dot => {
740
+ dot.classList.remove('active');
741
+ });
742
+
743
+ document.querySelector(`.quality-dot[data-quality="${level}"]`).classList.add('active');
744
+
745
+ // Mettre à jour la description
746
+ const descriptions = [
747
+ "Difficulté - Révision fréquente nécessaire",
748
+ "Moyen - Intervalles standard recommandés",
749
+ "Bon - Consolidation progressive",
750
+ "Excellent - Rétention à long terme optimale"
751
+ ];
752
+
753
+ document.getElementById('quality-description').textContent = descriptions[level];
754
+
755
+ // Mettre à jour l'aperçu
756
+ previewSM2Curve();
757
+ }
758
+
759
+ // Prévisualiser la courbe SM-2
760
+ async function previewSM2Curve() {
761
+ const competence = document.getElementById('competence').value;
762
+ if (!competence) {
763
+ document.getElementById('preview').style.display = 'none';
764
+ return;
765
+ }
766
+
767
+ try {
768
+ const response = await fetch(`/api/planner/visualize?competence=${encodeURIComponent(competence)}&quality=${currentQuality}`);
769
+ const data = await response.json();
770
+
771
+ if (data.success) {
772
+ document.getElementById('preview').style.display = 'block';
773
+
774
+ const ctx = document.getElementById('intervalChart').getContext('2d');
775
+
776
+ if (previewChart) {
777
+ previewChart.destroy();
778
+ }
779
+
780
+ const labels = data.intervals.map((_, i) => `Répétition ${i + 1}`);
781
+
782
+ previewChart = new Chart(ctx, {
783
+ type: 'bar',
784
+ data: {
785
+ labels: labels,
786
+ datasets: [{
787
+ label: 'Intervalle (jours)',
788
+ data: data.intervals,
789
+ backgroundColor: '#3b82f6',
790
+ borderColor: '#2563eb',
791
+ borderWidth: 2
792
+ }]
793
+ },
794
+ options: {
795
+ responsive: true,
796
+ maintainAspectRatio: false,
797
+ plugins: {
798
+ title: {
799
+ display: true,
800
+ text: `Courbe SM-2 - Niveau ${currentQuality}`
801
+ }
802
+ },
803
+ scales: {
804
+ y: {
805
+ beginAtZero: true,
806
+ title: {
807
+ display: true,
808
+ text: 'Jours'
809
+ }
810
+ }
811
+ }
812
+ }
813
+ });
814
+ }
815
+ } catch (error) {
816
+ console.error('Erreur génération preview:', error);
817
+ }
818
+ }
819
+
820
+ // Générer le planner
821
+ async function generatePlanner() {
822
+ const competence = document.getElementById('competence').value;
823
+ const startDate = document.getElementById('start').value;
824
+ const duration = document.getElementById('duration').value;
825
+
826
+ if (!competence || !startDate) {
827
+ alert('Veuillez sélectionner une compétence et une date de début');
828
+ return;
829
+ }
830
+
831
+ try {
832
+ const response = await fetch('/api/planner/generate', {
833
+ method: 'POST',
834
+ headers: { 'Content-Type': 'application/json' },
835
+ body: JSON.stringify({
836
+ competence: competence,
837
+ start_date: startDate,
838
+ session_duration: duration,
839
+ repetitions: 6,
840
+ quality_level: currentQuality
841
+ })
842
+ });
843
+
844
+ const data = await response.json();
845
+
846
+ if (data.success) {
847
+ displayPlanner(data.plan, data.intervals);
848
+ showTab('planner');
849
+ } else {
850
+ alert('Erreur: ' + data.error);
851
+ }
852
+ } catch (error) {
853
+ console.error('Erreur génération planner:', error);
854
+ alert('Erreur lors de la génération du planner');
855
+ }
856
+ }
857
+
858
+ // Afficher le planner
859
+ function displayPlanner(plan, intervals) {
860
+ const container = document.getElementById('plannerContent');
861
+ const statsContainer = document.getElementById('plannerStats');
862
+
863
+ // Calculer le total des jours
864
+ const totalDays = intervals.reduce((a, b) => a + b, 0);
865
+
866
+ // Statistiques
867
+ statsContainer.innerHTML = `
868
+ <div class="stat-card">
869
+ <div class="stat-value">${plan.length}</div>
870
+ <div class="stat-label">Sessions Planifiées</div>
871
+ </div>
872
+ <div class="stat-card">
873
+ <div class="stat-value">${totalDays}</div>
874
+ <div class="stat-label">Jours Totaux</div>
875
+ </div>
876
+ <div class="stat-card">
877
+ <div class="stat-value">${currentQuality + 1}/4</div>
878
+ <div class="stat-label">Niveau de Qualité</div>
879
+ </div>
880
+ <div class="stat-card">
881
+ <div class="stat-value">${document.getElementById('duration').value}min</div>
882
+ <div class="stat-label">Durée/Session</div>
883
+ </div>
884
+ `;
885
+
886
+ // Sessions
887
+ container.innerHTML = '';
888
+ plan.forEach(session => {
889
+ const card = document.createElement('div');
890
+ card.className = 'session-card';
891
+ card.innerHTML = `
892
+ <div class="session-header">
893
+ <div class="session-date">
894
+ <i class="fas fa-calendar-day"></i> ${session.date}
895
+ <div style="font-size: 0.9rem; color: #64748b;">${session.jour}</div>
896
+ </div>
897
+ <div class="session-repetition">
898
+ R${session.repetition}
899
+ </div>
900
+ </div>
901
+ <h4 style="margin: 10px 0; color: #1e293b;">${session.competence}</h4>
902
+ <div class="session-details">
903
+ <div class="detail-item">
904
+ <span><i class="fas fa-clock"></i> Durée</span>
905
+ <span>${session.duree}</span>
906
+ </div>
907
+ <div class="detail-item">
908
+ <span><i class="fas fa-sync-alt"></i> Intervalle</span>
909
+ <span>${session.intervalle}</span>
910
+ </div>
911
+ <div class="detail-item">
912
+ <span><i class="fas fa-bullseye"></i> Type</span>
913
+ <span>${session.type}</span>
914
+ </div>
915
+ <div class="detail-item">
916
+ <span><i class="fas fa-lightbulb"></i> Stratégie</span>
917
+ <span>${session.strategie}</span>
918
+ </div>
919
+ </div>
920
+ <div style="margin-top: 15px; padding: 10px; background: #f1f5f9; border-radius: 8px; font-size: 0.9rem;">
921
+ <i class="fas fa-bell"></i> ${session.reminder || ''}
922
+ </div>
923
+ `;
924
+ container.appendChild(card);
925
+ });
926
+
927
+ // Visualisation
928
+ createSM2Visualization(intervals, plan[0]?.competence || 'Compétence');
929
+ }
930
+
931
+ // Créer la visualisation SM-2
932
+ function createSM2Visualization(intervals, competence) {
933
+ const ctx = document.getElementById('sm2Visualization').getContext('2d');
934
+
935
+ if (currentChart) {
936
+ currentChart.destroy();
937
+ }
938
+
939
+ const labels = intervals.map((_, i) => `Répétition ${i + 1}`);
940
+
941
+ currentChart = new Chart(ctx, {
942
+ type: 'line',
943
+ data: {
944
+ labels: labels,
945
+ datasets: [{
946
+ label: 'Intervalle (jours)',
947
+ data: intervals,
948
+ borderColor: '#3b82f6',
949
+ backgroundColor: 'rgba(59, 130, 246, 0.1)',
950
+ borderWidth: 3,
951
+ fill: true,
952
+ tension: 0.4
953
+ }]
954
+ },
955
+ options: {
956
+ responsive: true,
957
+ maintainAspectRatio: false,
958
+ plugins: {
959
+ title: {
960
+ display: true,
961
+ text: `Courbe de Répétition Espacée - ${competence}`,
962
+ font: { size: 16 }
963
+ },
964
+ tooltip: {
965
+ callbacks: {
966
+ label: function(context) {
967
+ return `Intervalle: ${context.raw} jours`;
968
+ }
969
+ }
970
+ }
971
+ },
972
+ scales: {
973
+ y: {
974
+ beginAtZero: true,
975
+ title: {
976
+ display: true,
977
+ text: 'Jours'
978
+ }
979
+ },
980
+ x: {
981
+ title: {
982
+ display: true,
983
+ text: 'Numéro de Répétition'
984
+ }
985
+ }
986
+ }
987
+ }
988
+ });
989
+ }
990
+
991
+ // Journal
992
+ function setEvaluation(score) {
993
+ document.getElementById('auto_eval').value = score;
994
+
995
+ // Mettre à jour les indicateurs
996
+ document.querySelectorAll('.quality-indicator .quality-dot').forEach((dot, index) => {
997
+ dot.classList.toggle('active', index === score - 1);
998
+ });
999
+ }
1000
+
1001
+ async function saveJournal() {
1002
+ const entry = {
1003
+ todo: document.getElementById('todo').value,
1004
+ doing: document.getElementById('doing').value,
1005
+ done: document.getElementById('done').value,
1006
+ metacognition: document.getElementById('metacognition').value,
1007
+ auto_eval: document.getElementById('auto_eval').value,
1008
+ competence: document.getElementById('competence').value,
1009
+ timestamp: new Date().toISOString()
1010
+ };
1011
+
1012
+ try {
1013
+ const response = await fetch('/api/journal', {
1014
+ method: 'POST',
1015
+ headers: { 'Content-Type': 'application/json' },
1016
+ body: JSON.stringify(entry)
1017
+ });
1018
+
1019
+ const result = await response.json();
1020
+
1021
+ if (result.success) {
1022
+ alert('✅ Journal sauvegardé avec succès !');
1023
+ clearJournalForm();
1024
+ } else {
1025
+ alert('Erreur: ' + result.error);
1026
+ }
1027
+ } catch (error) {
1028
+ console.error('Erreur sauvegarde journal:', error);
1029
+ alert('Erreur lors de la sauvegarde');
1030
+ }
1031
+ }
1032
+
1033
+ function clearJournalForm() {
1034
+ document.getElementById('todo').value = '';
1035
+ document.getElementById('doing').value = '';
1036
+ document.getElementById('done').value = '';
1037
+ document.getElementById('metacognition').value = '';
1038
+ setEvaluation(3);
1039
+ }
1040
+
1041
+ async function loadJournalEntries() {
1042
+ try {
1043
+ const response = await fetch('/api/journal/entries?limit=5');
1044
+ const entries = await response.json();
1045
+
1046
+ const container = document.getElementById('journalEntries');
1047
+ container.innerHTML = '';
1048
+
1049
+ entries.forEach(entry => {
1050
+ const div = document.createElement('div');
1051
+ div.className = 'session-card';
1052
+ div.innerHTML = `
1053
+ <div class="session-header">
1054
+ <div class="session-date">
1055
+ ${new Date(entry.timestamp).toLocaleDateString('fr-FR')}
1056
+ </div>
1057
+ <div style="background: #10b981; color: white; padding: 5px 15px; border-radius: 20px;">
1058
+ ${entry.auto_eval || '?'}/5
1059
+ </div>
1060
+ </div>
1061
+ ${entry.competence ? `<div style="color: #3b82f6; margin: 5px 0;"><i class="fas fa-language"></i> ${entry.competence}</div>` : ''}
1062
+ ${entry.done ? `<div style="margin-top: 10px;"><strong>Accompli:</strong> ${entry.done.substring(0, 100)}...</div>` : ''}
1063
+ `;
1064
+ container.appendChild(div);
1065
+ });
1066
+
1067
+ document.getElementById('journalHistory').style.display = 'block';
1068
+ } catch (error) {
1069
+ console.error('Erreur chargement journal:', error);
1070
+ }
1071
+ }
1072
+
1073
+ // Notifications
1074
+ async function getIntelligentReminder() {
1075
+ try {
1076
+ const response = await fetch('/api/notifications/intelligent');
1077
+ const data = await response.json();
1078
+
1079
+ const container = document.getElementById('notificationContainer');
1080
+ const card = document.createElement('div');
1081
+ card.className = 'notification-card';
1082
+
1083
+ const icons = {
1084
+ 'motivation': '🌱',
1085
+ 'rappel_court': '⏰',
1086
+ 'encouragement': '💪',
1087
+ 'metacognition': '🤔'
1088
+ };
1089
+
1090
+ card.innerHTML = `
1091
+ <div style="display: flex; align-items: center; gap: 15px; margin-bottom: 10px;">
1092
+ <div style="font-size: 2rem;">${icons[data.type] || '🔔'}</div>
1093
+ <div>
1094
+ <div style="font-weight: bold; color: #1e293b;">${data.type ? data.type.charAt(0).toUpperCase() + data.type.slice(1).replace('_', ' ') : 'Notification'}</div>
1095
+ <div style="font-size: 0.9rem; color: #64748b;">
1096
+ Efficacité: ${(data.effectiveness_score * 100).toFixed(1)}%
1097
+ </div>
1098
+ </div>
1099
+ </div>
1100
+ <p style="font-size: 1.1rem; line-height: 1.5;">${data.message}</p>
1101
+ <div style="margin-top: 10px; font-size: 0.8rem; color: #64748b; text-align: right;">
1102
+ ${new Date(data.timestamp).toLocaleTimeString('fr-FR')}
1103
+ </div>
1104
+ `;
1105
+
1106
+ container.insertBefore(card, container.firstChild);
1107
+
1108
+ } catch (error) {
1109
+ console.error('Erreur notification:', error);
1110
+ }
1111
+ }
1112
+
1113
+ // Statistiques
1114
+ async function refreshStats() {
1115
+ try {
1116
+ const response = await fetch('/api/learner/stats');
1117
+ const stats = await response.json();
1118
+
1119
+ const container = document.getElementById('statsContainer');
1120
+ container.innerHTML = `
1121
+ <div class="stat-card">
1122
+ <div class="stat-value">${stats.total_sessions}</div>
1123
+ <div class="stat-label">Sessions Complétées</div>
1124
+ </div>
1125
+ <div class="stat-card">
1126
+ <div class="stat-value">${stats.success_rate.toFixed(2)}/5</div>
1127
+ <div class="stat-label">Score Moyen</div>
1128
+ </div>
1129
+ <div class="stat-card">
1130
+ <div class="stat-value">${stats.journal_entries}</div>
1131
+ <div class="stat-label">Entrées Journal</div>
1132
+ </div>
1133
+ <div class="stat-card">
1134
+ <div class="stat-value">${stats.planned_sessions}</div>
1135
+ <div class="stat-label">Sessions Planifiées</div>
1136
+ </div>
1137
+ <div class="stat-card">
1138
+ <div class="stat-value" style="color: ${stats.engagement_level === 'high' ? '#10b981' : stats.engagement_level === 'medium' ? '#f59e0b' : '#ef4444'}">
1139
+ ${stats.engagement_level}
1140
+ </div>
1141
+ <div class="stat-label">Niveau d'Engagement</div>
1142
+ </div>
1143
+ <div class="stat-card">
1144
+ <div class="stat-value" style="color: ${stats.risk_level === 'low' ? '#10b981' : stats.risk_level === 'medium' ? '#f59e0b' : '#ef4444'}">
1145
+ ${stats.risk_level}
1146
+ </div>
1147
+ <div class="stat-label">Niveau de Risque</div>
1148
+ </div>
1149
+ `;
1150
+
1151
+ // Mettre à jour le graphique de rétention
1152
+ updateRetentionChart(stats);
1153
+
1154
+ } catch (error) {
1155
+ console.error('Erreur statistiques:', error);
1156
+ }
1157
+ }
1158
+
1159
+ function updateRetentionChart(stats) {
1160
+ const ctx = document.getElementById('retentionChart').getContext('2d');
1161
+
1162
+ if (window.retentionChart) {
1163
+ window.retentionChart.destroy();
1164
+ }
1165
+
1166
+ // Données simulées pour la démonstration
1167
+ const labels = ['Sem 1', 'Sem 2', 'Sem 3', 'Sem 4', 'Sem 5', 'Sem 6'];
1168
+ const retentionData = [0.3, 0.5, 0.65, 0.75, 0.8, 0.85];
1169
+ const engagementData = [0.7, 0.8, 0.75, 0.85, 0.9, 0.88];
1170
+
1171
+ window.retentionChart = new Chart(ctx, {
1172
+ type: 'line',
1173
+ data: {
1174
+ labels: labels,
1175
+ datasets: [
1176
+ {
1177
+ label: 'Taux de Rétention',
1178
+ data: retentionData,
1179
+ borderColor: '#3b82f6',
1180
+ backgroundColor: 'rgba(59, 130, 246, 0.1)',
1181
+ borderWidth: 3,
1182
+ fill: true,
1183
+ tension: 0.4
1184
+ },
1185
+ {
1186
+ label: 'Niveau d\'Engagement',
1187
+ data: engagementData,
1188
+ borderColor: '#10b981',
1189
+ backgroundColor: 'rgba(16, 185, 129, 0.1)',
1190
+ borderWidth: 3,
1191
+ fill: true,
1192
+ tension: 0.4
1193
+ }
1194
+ ]
1195
+ },
1196
+ options: {
1197
+ responsive: true,
1198
+ maintainAspectRatio: false,
1199
+ scales: {
1200
+ y: {
1201
+ beginAtZero: true,
1202
+ max: 1,
1203
+ ticks: {
1204
+ callback: function(value) {
1205
+ return (value * 100) + '%';
1206
+ }
1207
+ }
1208
+ }
1209
+ },
1210
+ plugins: {
1211
+ tooltip: {
1212
+ callbacks: {
1213
+ label: function(context) {
1214
+ return context.dataset.label + ': ' + (context.raw * 100).toFixed(1) + '%';
1215
+ }
1216
+ }
1217
+ }
1218
+ }
1219
+ }
1220
+ });
1221
+ }
1222
+
1223
+ // Apprendre SM-2
1224
+ async function loadSM2Explanation() {
1225
+ try {
1226
+ const response = await fetch('/api/sm2/explain');
1227
+ const explanation = await response.json();
1228
+
1229
+ const container = document.getElementById('sm2Explanation');
1230
+ container.innerHTML = `
1231
+ <div class="card" style="margin-bottom: 20px;">
1232
+ <h3 style="color: #3b82f6; margin-bottom: 15px;">${explanation.title}</h3>
1233
+ <p style="margin-bottom: 20px; line-height: 1.6;">${explanation.description}</p>
1234
+
1235
+ <h4 style="margin-bottom: 15px; color: #1e293b;"><i class="fas fa-layer-group"></i> Niveaux de Qualité</h4>
1236
+ <div style="display: grid; grid-template-columns: repeat(auto-fit, minmax(250px, 1fr)); gap: 15px; margin-bottom: 20px;">
1237
+ ${Object.entries(explanation.quality_levels).map(([level, desc]) => `
1238
+ <div style="padding: 15px; background: #f8fafc; border-radius: 10px; border-left: 4px solid ${getQualityColor(level)};">
1239
+ <div style="font-weight: bold; color: ${getQualityColor(level)};">Niveau ${level}</div>
1240
+ <div style="font-size: 0.9rem; color: #64748b;">${desc}</div>
1241
+ </div>
1242
+ `).join('')}
1243
+ </div>
1244
+
1245
+ <h4 style="margin-bottom: 15px; color: #1e293b;"><i class="fas fa-lightbulb"></i> Principes Fondamentaux</h4>
1246
+ <ul style="margin-bottom: 20px; padding-left: 20px;">
1247
+ ${explanation.principles.map(principle => `
1248
+ <li style="margin-bottom: 10px; line-height: 1.5;">${principle}</li>
1249
+ `).join('')}
1250
+ </ul>
1251
+
1252
+ <h4 style="margin-bottom: 15px; color: #1e293b;"><i class="fas fa-check-circle"></i> Recommandations</h4>
1253
+ <ul style="padding-left: 20px;">
1254
+ ${explanation.recommendations.map(recommendation => `
1255
+ <li style="margin-bottom: 10px; line-height: 1.5;">${recommendation}</li>
1256
+ `).join('')}
1257
+ </ul>
1258
+ </div>
1259
+ `;
1260
+ } catch (error) {
1261
+ console.error('Erreur chargement explication SM-2:', error);
1262
+ }
1263
+ }
1264
+
1265
+ function getQualityColor(level) {
1266
+ const colors = ['#ef4444', '#f59e0b', '#10b981', '#3b82f6'];
1267
+ return colors[parseInt(level)] || colors[0];
1268
+ }
1269
+
1270
+ function updateComparisonChart() {
1271
+ const ctx = document.getElementById('comparisonChart').getContext('2d');
1272
+
1273
+ if (window.comparisonChart) {
1274
+ window.comparisonChart.destroy();
1275
+ }
1276
+
1277
+ // Données des différents niveaux de qualité
1278
+ const intervals = {
1279
+ 'Difficulté (N0)': [1, 2, 4, 8, 16, 32],
1280
+ 'Moyen (N1)': [1, 3, 7, 14, 30, 60],
1281
+ 'Bon (N2)': [2, 7, 16, 35, 70, 140],
1282
+ 'Excellent (N3)': [3, 10, 25, 60, 120, 240]
1283
+ };
1284
+
1285
+ const labels = ['R1', 'R2', 'R3', 'R4', 'R5', 'R6'];
1286
+ const colors = ['#ef4444', '#f59e0b', '#10b981', '#3b82f6'];
1287
+
1288
+ const datasets = Object.entries(intervals).map(([label, data], index) => ({
1289
+ label: label,
1290
+ data: data,
1291
+ borderColor: colors[index],
1292
+ backgroundColor: colors[index] + '20',
1293
+ borderWidth: 2,
1294
+ tension: 0.4,
1295
+ fill: false
1296
+ }));
1297
+
1298
+ window.comparisonChart = new Chart(ctx, {
1299
+ type: 'line',
1300
+ data: {
1301
+ labels: labels,
1302
+ datasets: datasets
1303
+ },
1304
+ options: {
1305
+ responsive: true,
1306
+ maintainAspectRatio: false,
1307
+ scales: {
1308
+ y: {
1309
+ beginAtZero: true,
1310
+ title: {
1311
+ display: true,
1312
+ text: 'Intervalle (jours)'
1313
+ }
1314
+ }
1315
+ },
1316
+ plugins: {
1317
+ title: {
1318
+ display: true,
1319
+ text: 'Comparaison des Courbes SM-2 par Niveau de Qualité',
1320
+ font: { size: 16 }
1321
+ },
1322
+ tooltip: {
1323
+ callbacks: {
1324
+ label: function(context) {
1325
+ return `${context.dataset.label}: ${context.raw} jours`;
1326
+ }
1327
+ }
1328
+ }
1329
+ }
1330
+ }
1331
+ });
1332
+ }
1333
+
1334
+ // Export
1335
+ function exportPlanner() {
1336
+ const plannerData = document.getElementById('plannerContent').innerText;
1337
+ const blob = new Blob([plannerData], { type: 'text/plain' });
1338
+ const url = URL.createObjectURL(blob);
1339
+ const a = document.createElement('a');
1340
+ a.href = url;
1341
+ a.download = 'planner-sm2.txt';
1342
+ document.body.appendChild(a);
1343
+ a.click();
1344
+ document.body.removeChild(a);
1345
+ URL.revokeObjectURL(url);
1346
+ }
1347
+ </script>
1348
  </body>
1349
+ </html>
index.html CHANGED
@@ -245,6 +245,269 @@
245
  font-size: 1.1rem;
246
  }
247
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
248
  /* Visualizations */
249
  .visualization-container {
250
  background: white;
@@ -394,6 +657,30 @@
394
  box-shadow: 0 0 0 3px white, 0 0 0 6px currentColor;
395
  }
396
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
397
  /* Responsive */
398
  @media (max-width: 768px) {
399
  .form-row {
@@ -412,6 +699,28 @@
412
  .header h1 {
413
  font-size: 2rem;
414
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
415
  }
416
  </style>
417
  </head>
@@ -432,6 +741,9 @@
432
  <button class="nav-tab" onclick="showTab('planner')">
433
  <i class="fas fa-calendar-alt"></i> Planner SM-2
434
  </button>
 
 
 
435
  <button class="nav-tab" onclick="showTab('journal')">
436
  <i class="fas fa-book"></i> Journal SRL
437
  </button>
@@ -492,6 +804,58 @@
492
  </select>
493
  </div>
494
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
495
  <div class="form-group">
496
  <label class="form-label"><i class="fas fa-chart-line"></i> Qualité Estimée de Rétention</label>
497
  <div class="quality-indicator">
@@ -504,7 +868,7 @@
504
  </div>
505
 
506
  <button class="btn btn-primary btn-large" onclick="generatePlanner()">
507
- <i class="fas fa-cogs"></i> Générer le Planner SM-2
508
  </button>
509
 
510
  <div id="preview" style="display: none; margin-top: 2rem;">
@@ -539,6 +903,131 @@
539
  </div>
540
  </section>
541
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
542
  <!-- Journal Section -->
543
  <section id="journal" class="tab-content">
544
  <div class="card">
@@ -636,6 +1125,33 @@
636
  <canvas id="retentionChart"></canvas>
637
  </div>
638
  </div>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
639
  </div>
640
  </section>
641
 
@@ -663,6 +1179,21 @@
663
  let currentChart = null;
664
  let currentQuality = 2; // Niveau 2 par défaut
665
  let previewChart = null;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
666
 
667
  // Initialisation
668
  document.addEventListener('DOMContentLoaded', function() {
@@ -670,6 +1201,9 @@
670
  refreshStats();
671
  loadSM2Explanation();
672
  updateComparisonChart();
 
 
 
673
  });
674
 
675
  // Navigation
@@ -691,6 +1225,7 @@
691
  const tabNames = {
692
  'objectif': 'Objectif',
693
  'planner': 'Planner',
 
694
  'journal': 'Journal',
695
  'notifications': 'Notifications',
696
  'stats': 'Statistiques',
@@ -708,7 +1243,78 @@
708
  refreshStats();
709
  } else if (tabId === 'learn') {
710
  updateComparisonChart();
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
711
  }
 
 
 
 
 
 
 
 
712
  }
713
 
714
  // Charger les compétences
@@ -817,11 +1423,14 @@
817
  }
818
  }
819
 
820
- // Générer le planner
821
  async function generatePlanner() {
822
  const competence = document.getElementById('competence').value;
823
  const startDate = document.getElementById('start').value;
824
  const duration = document.getElementById('duration').value;
 
 
 
825
 
826
  if (!competence || !startDate) {
827
  alert('Veuillez sélectionner une compétence et une date de début');
@@ -837,7 +1446,10 @@
837
  start_date: startDate,
838
  session_duration: duration,
839
  repetitions: 6,
840
- quality_level: currentQuality
 
 
 
841
  })
842
  });
843
 
@@ -916,6 +1528,18 @@
916
  <span><i class="fas fa-lightbulb"></i> Stratégie</span>
917
  <span>${session.strategie}</span>
918
  </div>
 
 
 
 
 
 
 
 
 
 
 
 
919
  </div>
920
  <div style="margin-top: 15px; padding: 10px; background: #f1f5f9; border-radius: 8px; font-size: 0.9rem;">
921
  <i class="fas fa-bell"></i> ${session.reminder || ''}
@@ -988,6 +1612,340 @@
988
  });
989
  }
990
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
991
  // Journal
992
  function setEvaluation(score) {
993
  document.getElementById('auto_eval').value = score;
 
245
  font-size: 1.1rem;
246
  }
247
 
248
+ /* Flashcard Application */
249
+ .flashcard-section {
250
+ margin-top: 2rem;
251
+ border-top: 2px solid #f1f5f9;
252
+ padding-top: 2rem;
253
+ }
254
+
255
+ .flashcard-container {
256
+ max-width: 800px;
257
+ margin: 0 auto;
258
+ }
259
+
260
+ .flashcard {
261
+ background: linear-gradient(135deg, #f8fafc 0%, #e2e8f0 100%);
262
+ border-radius: 15px;
263
+ padding: 3rem 2rem;
264
+ margin: 2rem 0;
265
+ min-height: 300px;
266
+ display: flex;
267
+ flex-direction: column;
268
+ justify-content: center;
269
+ align-items: center;
270
+ position: relative;
271
+ cursor: pointer;
272
+ transition: all 0.3s;
273
+ box-shadow: 0 10px 25px rgba(0, 0, 0, 0.1);
274
+ border: 2px solid #e2e8f0;
275
+ }
276
+
277
+ .flashcard:hover {
278
+ transform: translateY(-5px);
279
+ box-shadow: 0 15px 30px rgba(0, 0, 0, 0.15);
280
+ }
281
+
282
+ .flashcard.flipped {
283
+ background: linear-gradient(135deg, #dbeafe 0%, #bfdbfe 100%);
284
+ }
285
+
286
+ .flashcard-front, .flashcard-back {
287
+ text-align: center;
288
+ width: 100%;
289
+ }
290
+
291
+ .flashcard-category {
292
+ position: absolute;
293
+ top: 15px;
294
+ left: 15px;
295
+ background: var(--primary-color);
296
+ color: white;
297
+ padding: 5px 15px;
298
+ border-radius: 20px;
299
+ font-size: 0.8rem;
300
+ }
301
+
302
+ .flashcard-content {
303
+ font-size: 1.5rem;
304
+ font-weight: 600;
305
+ color: var(--dark-color);
306
+ margin: 1.5rem 0;
307
+ line-height: 1.6;
308
+ }
309
+
310
+ .flashcard-example {
311
+ font-size: 1rem;
312
+ color: var(--gray-color);
313
+ font-style: italic;
314
+ margin-top: 1rem;
315
+ border-left: 3px solid var(--secondary-color);
316
+ padding-left: 15px;
317
+ }
318
+
319
+ .flashcard-stats {
320
+ position: absolute;
321
+ top: 15px;
322
+ right: 15px;
323
+ display: flex;
324
+ gap: 10px;
325
+ align-items: center;
326
+ }
327
+
328
+ .flashcard-score {
329
+ background: #10b981;
330
+ color: white;
331
+ padding: 5px 10px;
332
+ border-radius: 15px;
333
+ font-size: 0.8rem;
334
+ font-weight: bold;
335
+ }
336
+
337
+ .flashcard-difficulty {
338
+ background: #f59e0b;
339
+ color: white;
340
+ padding: 5px 10px;
341
+ border-radius: 15px;
342
+ font-size: 0.8rem;
343
+ }
344
+
345
+ .flashcard-controls {
346
+ display: flex;
347
+ justify-content: center;
348
+ gap: 15px;
349
+ margin-top: 2rem;
350
+ }
351
+
352
+ .flashcard-btn {
353
+ padding: 10px 25px;
354
+ border: none;
355
+ border-radius: 10px;
356
+ font-size: 1rem;
357
+ font-weight: 600;
358
+ cursor: pointer;
359
+ transition: all 0.3s;
360
+ display: flex;
361
+ align-items: center;
362
+ gap: 8px;
363
+ }
364
+
365
+ .flashcard-btn.easy {
366
+ background: #10b981;
367
+ color: white;
368
+ }
369
+
370
+ .flashcard-btn.medium {
371
+ background: #f59e0b;
372
+ color: white;
373
+ }
374
+
375
+ .flashcard-btn.hard {
376
+ background: #ef4444;
377
+ color: white;
378
+ }
379
+
380
+ .flashcard-btn:hover {
381
+ transform: translateY(-2px);
382
+ box-shadow: 0 5px 15px rgba(0, 0, 0, 0.1);
383
+ }
384
+
385
+ .flashcard-progress {
386
+ margin-top: 2rem;
387
+ text-align: center;
388
+ }
389
+
390
+ .progress-bar {
391
+ height: 8px;
392
+ background: #e2e8f0;
393
+ border-radius: 4px;
394
+ margin: 10px 0;
395
+ overflow: hidden;
396
+ }
397
+
398
+ .progress-fill {
399
+ height: 100%;
400
+ background: linear-gradient(90deg, #3b82f6, #8b5cf6);
401
+ border-radius: 4px;
402
+ transition: width 0.3s ease;
403
+ }
404
+
405
+ .flashcard-stats-summary {
406
+ display: grid;
407
+ grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
408
+ gap: 15px;
409
+ margin-top: 2rem;
410
+ }
411
+
412
+ .flashcard-stat-item {
413
+ background: white;
414
+ padding: 1.5rem;
415
+ border-radius: 10px;
416
+ text-align: center;
417
+ box-shadow: 0 3px 10px rgba(0, 0, 0, 0.05);
418
+ }
419
+
420
+ /* Productivity Options */
421
+ .productivity-options {
422
+ display: flex;
423
+ gap: 15px;
424
+ margin-top: 10px;
425
+ }
426
+
427
+ .productivity-option {
428
+ flex: 1;
429
+ padding: 15px;
430
+ border: 2px solid #e2e8f0;
431
+ border-radius: 10px;
432
+ text-align: center;
433
+ cursor: pointer;
434
+ transition: all 0.3s;
435
+ }
436
+
437
+ .productivity-option:hover {
438
+ border-color: var(--primary-color);
439
+ background: rgba(59, 130, 246, 0.05);
440
+ }
441
+
442
+ .productivity-option.selected {
443
+ border-color: var(--primary-color);
444
+ background: rgba(59, 130, 246, 0.1);
445
+ box-shadow: 0 5px 15px rgba(59, 130, 246, 0.1);
446
+ }
447
+
448
+ .productivity-icon {
449
+ font-size: 1.5rem;
450
+ margin-bottom: 8px;
451
+ display: block;
452
+ }
453
+
454
+ /* Energy Pattern */
455
+ .energy-patterns {
456
+ display: flex;
457
+ gap: 15px;
458
+ margin-top: 10px;
459
+ }
460
+
461
+ .energy-pattern {
462
+ flex: 1;
463
+ padding: 15px;
464
+ border: 2px solid #e2e8f0;
465
+ border-radius: 10px;
466
+ text-align: center;
467
+ cursor: pointer;
468
+ transition: all 0.3s;
469
+ }
470
+
471
+ .energy-pattern:hover {
472
+ border-color: var(--secondary-color);
473
+ background: rgba(16, 185, 129, 0.05);
474
+ }
475
+
476
+ .energy-pattern.selected {
477
+ border-color: var(--secondary-color);
478
+ background: rgba(16, 185, 129, 0.1);
479
+ box-shadow: 0 5px 15px rgba(16, 185, 129, 0.1);
480
+ }
481
+
482
+ /* Time Slots */
483
+ .time-slots {
484
+ display: flex;
485
+ flex-wrap: wrap;
486
+ gap: 10px;
487
+ margin-top: 10px;
488
+ }
489
+
490
+ .time-slot {
491
+ padding: 10px 20px;
492
+ border: 2px solid #e2e8f0;
493
+ border-radius: 8px;
494
+ cursor: pointer;
495
+ transition: all 0.3s;
496
+ text-align: center;
497
+ min-width: 80px;
498
+ }
499
+
500
+ .time-slot:hover {
501
+ border-color: var(--accent-color);
502
+ background: rgba(139, 92, 246, 0.05);
503
+ }
504
+
505
+ .time-slot.selected {
506
+ border-color: var(--accent-color);
507
+ background: rgba(139, 92, 246, 0.1);
508
+ box-shadow: 0 3px 10px rgba(139, 92, 246, 0.1);
509
+ }
510
+
511
  /* Visualizations */
512
  .visualization-container {
513
  background: white;
 
657
  box-shadow: 0 0 0 3px white, 0 0 0 6px currentColor;
658
  }
659
 
660
+ /* Flashcard Progress in Stats */
661
+ .flashcard-stats-card {
662
+ grid-column: span 2;
663
+ background: linear-gradient(135deg, #f8fafc 0%, #e2e8f0 100%);
664
+ }
665
+
666
+ .flashcard-stats-header {
667
+ display: flex;
668
+ justify-content: space-between;
669
+ align-items: center;
670
+ margin-bottom: 1rem;
671
+ }
672
+
673
+ .streak-counter {
674
+ background: linear-gradient(135deg, #f59e0b, #d97706);
675
+ color: white;
676
+ padding: 5px 15px;
677
+ border-radius: 20px;
678
+ font-weight: bold;
679
+ display: flex;
680
+ align-items: center;
681
+ gap: 5px;
682
+ }
683
+
684
  /* Responsive */
685
  @media (max-width: 768px) {
686
  .form-row {
 
699
  .header h1 {
700
  font-size: 2rem;
701
  }
702
+
703
+ .productivity-options,
704
+ .energy-patterns {
705
+ flex-direction: column;
706
+ }
707
+
708
+ .time-slots {
709
+ justify-content: center;
710
+ }
711
+
712
+ .flashcard-controls {
713
+ flex-direction: column;
714
+ }
715
+
716
+ .flashcard-btn {
717
+ width: 100%;
718
+ justify-content: center;
719
+ }
720
+
721
+ .flashcard-stats-summary {
722
+ grid-template-columns: 1fr;
723
+ }
724
  }
725
  </style>
726
  </head>
 
741
  <button class="nav-tab" onclick="showTab('planner')">
742
  <i class="fas fa-calendar-alt"></i> Planner SM-2
743
  </button>
744
+ <button class="nav-tab" onclick="showTab('flashcards')">
745
+ <i class="fas fa-layer-group"></i> Flashcards
746
+ </button>
747
  <button class="nav-tab" onclick="showTab('journal')">
748
  <i class="fas fa-book"></i> Journal SRL
749
  </button>
 
804
  </select>
805
  </div>
806
 
807
+ <!-- Habitudes Productivité -->
808
+ <div class="form-group">
809
+ <label class="form-label"><i class="fas fa-chart-line"></i> Méthode Productivité</label>
810
+ <div class="productivity-options">
811
+ <div class="productivity-option selected" onclick="selectProductivityMethod('pomodoro')">
812
+ <span class="productivity-icon">🍅</span>
813
+ <div>Pomodoro</div>
814
+ <small>25 min travail / 5 min pause</small>
815
+ </div>
816
+ <div class="productivity-option" onclick="selectProductivityMethod('deepwork')">
817
+ <span class="productivity-icon">⏳</span>
818
+ <div>Deep Work</div>
819
+ <small>90 min focus intense</small>
820
+ </div>
821
+ </div>
822
+ <input type="hidden" id="productivity_method" value="pomodoro">
823
+ </div>
824
+
825
+ <!-- Type d'Énergie -->
826
+ <div class="form-group">
827
+ <label class="form-label"><i class="fas fa-sun"></i> Type d'Énergie</label>
828
+ <div class="energy-patterns">
829
+ <div class="energy-pattern selected" onclick="selectEnergyPattern('morning')">
830
+ <div>🌅 Matinale</div>
831
+ <small>Meilleure concentration le matin</small>
832
+ </div>
833
+ <div class="energy-pattern" onclick="selectEnergyPattern('evening')">
834
+ <div>🌙 Vespérale</div>
835
+ <small>Plus productif en soirée</small>
836
+ </div>
837
+ <div class="energy-pattern" onclick="selectEnergyPattern('flexible')">
838
+ <div>🔄 Flexible</div>
839
+ <small>Adaptable selon le jour</small>
840
+ </div>
841
+ </div>
842
+ <input type="hidden" id="energy_pattern" value="morning">
843
+ </div>
844
+
845
+ <!-- Créneaux Disponibles -->
846
+ <div class="form-group">
847
+ <label class="form-label"><i class="fas fa-calendar-check"></i> Créneaux Disponibles</label>
848
+ <div class="time-slots">
849
+ <div class="time-slot selected" onclick="toggleTimeSlot('morning')">08:00-10:00</div>
850
+ <div class="time-slot" onclick="toggleTimeSlot('late_morning')">10:00-12:00</div>
851
+ <div class="time-slot" onclick="toggleTimeSlot('afternoon')">14:00-16:00</div>
852
+ <div class="time-slot" onclick="toggleTimeSlot('late_afternoon')">16:00-18:00</div>
853
+ <div class="time-slot" onclick="toggleTimeSlot('evening')">19:00-21:00</div>
854
+ </div>
855
+ <input type="hidden" id="selected_time_slots" value="morning">
856
+ </div>
857
+
858
+ <!-- Qualité Estimée -->
859
  <div class="form-group">
860
  <label class="form-label"><i class="fas fa-chart-line"></i> Qualité Estimée de Rétention</label>
861
  <div class="quality-indicator">
 
868
  </div>
869
 
870
  <button class="btn btn-primary btn-large" onclick="generatePlanner()">
871
+ <i class="fas fa-cogs"></i> Générer le Planner SM-2 Personnalisé
872
  </button>
873
 
874
  <div id="preview" style="display: none; margin-top: 2rem;">
 
903
  </div>
904
  </section>
905
 
906
+ <!-- Flashcards Section -->
907
+ <section id="flashcards" class="tab-content">
908
+ <div class="card">
909
+ <div class="card-header">
910
+ <h3><i class="fas fa-layer-group"></i> Application Flashcards avec Répétition Espacée</h3>
911
+ <div>
912
+ <span class="streak-counter">
913
+ <i class="fas fa-fire"></i> Série: <span id="streakCount">0</span> jours
914
+ </span>
915
+ </div>
916
+ </div>
917
+
918
+ <div class="flashcard-container">
919
+ <div class="flashcard" id="flashcard" onclick="flipCard()">
920
+ <div class="flashcard-category" id="flashcardCategory">Conjugaison</div>
921
+ <div class="flashcard-stats">
922
+ <span class="flashcard-score" id="flashcardScore">Score: 85%</span>
923
+ <span class="flashcard-difficulty" id="flashcardDifficulty">Moyen</span>
924
+ </div>
925
+
926
+ <div class="flashcard-front" id="flashcardFront">
927
+ <div class="flashcard-content" id="flashcardQuestion">
928
+ Chargement des flashcards...
929
+ </div>
930
+ <div class="flashcard-example" id="flashcardHint">
931
+ Cliquez pour voir la réponse
932
+ </div>
933
+ </div>
934
+
935
+ <div class="flashcard-back" id="flashcardBack" style="display: none;">
936
+ <div class="flashcard-content" id="flashcardAnswer">
937
+ Réponse ici
938
+ </div>
939
+ <div class="flashcard-example" id="flashcardExplanation">
940
+ Explication détaillée
941
+ </div>
942
+ </div>
943
+ </div>
944
+
945
+ <div class="flashcard-controls">
946
+ <button class="flashcard-btn hard" onclick="rateCard(0)">
947
+ <i class="fas fa-times"></i> Difficile
948
+ </button>
949
+ <button class="flashcard-btn medium" onclick="rateCard(1)">
950
+ <i class="fas fa-minus"></i> Moyen
951
+ </button>
952
+ <button class="flashcard-btn easy" onclick="rateCard(2)">
953
+ <i class="fas fa-check"></i> Facile
954
+ </button>
955
+ <button class="flashcard-btn" onclick="showAnswer()" style="background: #3b82f6; color: white;">
956
+ <i class="fas fa-eye"></i> Voir Réponse
957
+ </button>
958
+ </div>
959
+
960
+ <div class="flashcard-progress">
961
+ <div>Progression: <span id="currentCard">1</span>/<span id="totalCards">10</span></div>
962
+ <div class="progress-bar">
963
+ <div class="progress-fill" id="progressFill" style="width: 10%"></div>
964
+ </div>
965
+ <div id="nextReview">Prochaine révision: Aujourd'hui</div>
966
+ </div>
967
+
968
+ <div class="flashcard-stats-summary">
969
+ <div class="flashcard-stat-item">
970
+ <div style="font-size: 2rem; color: #3b82f6; font-weight: bold;" id="totalReviewed">0</div>
971
+ <div>Cartes Révisées</div>
972
+ </div>
973
+ <div class="flashcard-stat-item">
974
+ <div style="font-size: 2rem; color: #10b981; font-weight: bold;" id="masteryRate">0%</div>
975
+ <div>Taux de Maîtrise</div>
976
+ </div>
977
+ <div class="flashcard-stat-item">
978
+ <div style="font-size: 2rem; color: #8b5cf6; font-weight: bold;" id="avgScore">0%</div>
979
+ <div>Score Moyen</div>
980
+ </div>
981
+ <div class="flashcard-stat-item">
982
+ <div style="font-size: 2rem; color: #f59e0b; font-weight: bold;" id="cardsDue">0</div>
983
+ <div>Cartes à Réviser</div>
984
+ </div>
985
+ </div>
986
+ </div>
987
+
988
+ <div class="flashcard-section">
989
+ <h4><i class="fas fa-plus-circle"></i> Ajouter une Nouvelle Flashcard</h4>
990
+ <div class="form-row">
991
+ <div class="form-col">
992
+ <label class="form-label"><i class="fas fa-question"></i> Question</label>
993
+ <textarea id="newQuestion" class="form-control" rows="2" placeholder="Entrez la question..."></textarea>
994
+ </div>
995
+ <div class="form-col">
996
+ <label class="form-label"><i class="fas fa-lightbulb"></i> Réponse</label>
997
+ <textarea id="newAnswer" class="form-control" rows="2" placeholder="Entrez la réponse..."></textarea>
998
+ </div>
999
+ </div>
1000
+ <div class="form-row">
1001
+ <div class="form-col">
1002
+ <label class="form-label"><i class="fas fa-tag"></i> Catégorie</label>
1003
+ <select id="newCategory" class="form-control">
1004
+ <option value="conjugaison">Conjugaison</option>
1005
+ <option value="grammaire">Grammaire</option>
1006
+ <option value="vocabulaire">Vocabulaire</option>
1007
+ <option value="expressions">Expressions</option>
1008
+ <option value="autres">Autres</option>
1009
+ </select>
1010
+ </div>
1011
+ <div class="form-col">
1012
+ <label class="form-label"><i class="fas fa-star"></i> Difficulté</label>
1013
+ <select id="newDifficulty" class="form-control">
1014
+ <option value="facile">Facile</option>
1015
+ <option value="moyen" selected>Moyen</option>
1016
+ <option value="difficile">Difficile</option>
1017
+ </select>
1018
+ </div>
1019
+ </div>
1020
+ <div class="form-group">
1021
+ <label class="form-label"><i class="fas fa-info-circle"></i> Exemple/Explication</label>
1022
+ <textarea id="newExplanation" class="form-control" rows="2" placeholder="Ajoutez un exemple ou une explication..."></textarea>
1023
+ </div>
1024
+ <button class="btn btn-primary" onclick="addNewFlashcard()">
1025
+ <i class="fas fa-plus"></i> Ajouter la Flashcard
1026
+ </button>
1027
+ </div>
1028
+ </div>
1029
+ </section>
1030
+
1031
  <!-- Journal Section -->
1032
  <section id="journal" class="tab-content">
1033
  <div class="card">
 
1125
  <canvas id="retentionChart"></canvas>
1126
  </div>
1127
  </div>
1128
+
1129
+ <!-- Flashcard Statistics -->
1130
+ <div class="flashcard-section">
1131
+ <h4><i class="fas fa-layer-group"></i> Statistiques des Flashcards</h4>
1132
+ <div class="flashcard-stats-summary">
1133
+ <div class="flashcard-stat-item">
1134
+ <div style="font-size: 2rem; color: #3b82f6; font-weight: bold;" id="statsTotalCards">0</div>
1135
+ <div>Total Flashcards</div>
1136
+ </div>
1137
+ <div class="flashcard-stat-item">
1138
+ <div style="font-size: 2rem; color: #10b981; font-weight: bold;" id="statsMastered">0</div>
1139
+ <div>Maîtrisées</div>
1140
+ </div>
1141
+ <div class="flashcard-stat-item">
1142
+ <div style="font-size: 2rem; color: #f59e0b; font-weight: bold;" id="statsLearning">0</div>
1143
+ <div>En Apprentissage</div>
1144
+ </div>
1145
+ <div class="flashcard-stat-item">
1146
+ <div style="font-size: 2rem; color: #ef4444; font-weight: bold;" id="statsDue">0</div>
1147
+ <div>À Réviser</div>
1148
+ </div>
1149
+ </div>
1150
+
1151
+ <div class="chart-container" style="height: 300px; margin-top: 2rem;">
1152
+ <canvas id="flashcardProgressChart"></canvas>
1153
+ </div>
1154
+ </div>
1155
  </div>
1156
  </section>
1157
 
 
1179
  let currentChart = null;
1180
  let currentQuality = 2; // Niveau 2 par défaut
1181
  let previewChart = null;
1182
+ let selectedTimeSlots = ['morning'];
1183
+
1184
+ // Variables pour les flashcards
1185
+ let flashcards = [];
1186
+ let currentFlashcardIndex = 0;
1187
+ let flashcardStats = {
1188
+ totalReviewed: 0,
1189
+ masteryRate: 0,
1190
+ avgScore: 0,
1191
+ streak: 0,
1192
+ totalCards: 0,
1193
+ mastered: 0,
1194
+ learning: 0,
1195
+ due: 0
1196
+ };
1197
 
1198
  // Initialisation
1199
  document.addEventListener('DOMContentLoaded', function() {
 
1201
  refreshStats();
1202
  loadSM2Explanation();
1203
  updateComparisonChart();
1204
+ initializeHabitsProductivity();
1205
+ loadFlashcards();
1206
+ updateFlashcardStats();
1207
  });
1208
 
1209
  // Navigation
 
1225
  const tabNames = {
1226
  'objectif': 'Objectif',
1227
  'planner': 'Planner',
1228
+ 'flashcards': 'Flashcards',
1229
  'journal': 'Journal',
1230
  'notifications': 'Notifications',
1231
  'stats': 'Statistiques',
 
1243
  refreshStats();
1244
  } else if (tabId === 'learn') {
1245
  updateComparisonChart();
1246
+ } else if (tabId === 'flashcards') {
1247
+ loadFlashcards();
1248
+ }
1249
+ }
1250
+
1251
+ // Initialiser les habitudes productivité
1252
+ function initializeHabitsProductivity() {
1253
+ // Productivité par défaut: Pomodoro
1254
+ document.getElementById('productivity_method').value = 'pomodoro';
1255
+
1256
+ // Type d'énergie par défaut: Morning
1257
+ document.getElementById('energy_pattern').value = 'morning';
1258
+
1259
+ // Créneaux par défaut: morning seulement
1260
+ document.getElementById('selected_time_slots').value = 'morning';
1261
+ }
1262
+
1263
+ // Sélectionner méthode productivité
1264
+ function selectProductivityMethod(method) {
1265
+ document.getElementById('productivity_method').value = method;
1266
+
1267
+ // Mettre à jour l'interface
1268
+ document.querySelectorAll('.productivity-option').forEach(option => {
1269
+ option.classList.remove('selected');
1270
+ });
1271
+
1272
+ document.querySelectorAll('.productivity-option').forEach(option => {
1273
+ if (option.textContent.includes(method === 'pomodoro' ? 'Pomodoro' : 'Deep Work')) {
1274
+ option.classList.add('selected');
1275
+ }
1276
+ });
1277
+ }
1278
+
1279
+ // Sélectionner type d'énergie
1280
+ function selectEnergyPattern(pattern) {
1281
+ document.getElementById('energy_pattern').value = pattern;
1282
+
1283
+ // Mettre à jour l'interface
1284
+ document.querySelectorAll('.energy-pattern').forEach(el => {
1285
+ el.classList.remove('selected');
1286
+ });
1287
+
1288
+ document.querySelectorAll('.energy-pattern').forEach(el => {
1289
+ if (el.textContent.includes(
1290
+ pattern === 'morning' ? 'Matinale' :
1291
+ pattern === 'evening' ? 'Vespérale' : 'Flexible'
1292
+ )) {
1293
+ el.classList.add('selected');
1294
+ }
1295
+ });
1296
+ }
1297
+
1298
+ // Basculer créneau horaire
1299
+ function toggleTimeSlot(slot) {
1300
+ const index = selectedTimeSlots.indexOf(slot);
1301
+ const element = document.querySelector(`.time-slot:nth-child(${getTimeSlotIndex(slot) + 1})`);
1302
+
1303
+ if (index === -1) {
1304
+ selectedTimeSlots.push(slot);
1305
+ element.classList.add('selected');
1306
+ } else {
1307
+ selectedTimeSlots.splice(index, 1);
1308
+ element.classList.remove('selected');
1309
  }
1310
+
1311
+ document.getElementById('selected_time_slots').value = selectedTimeSlots.join(',');
1312
+ }
1313
+
1314
+ // Obtenir l'index du créneau horaire
1315
+ function getTimeSlotIndex(slot) {
1316
+ const slots = ['morning', 'late_morning', 'afternoon', 'late_afternoon', 'evening'];
1317
+ return slots.indexOf(slot);
1318
  }
1319
 
1320
  // Charger les compétences
 
1423
  }
1424
  }
1425
 
1426
+ // Générer le planner personnalisé
1427
  async function generatePlanner() {
1428
  const competence = document.getElementById('competence').value;
1429
  const startDate = document.getElementById('start').value;
1430
  const duration = document.getElementById('duration').value;
1431
+ const productivityMethod = document.getElementById('productivity_method').value;
1432
+ const energyPattern = document.getElementById('energy_pattern').value;
1433
+ const timeSlots = document.getElementById('selected_time_slots').value;
1434
 
1435
  if (!competence || !startDate) {
1436
  alert('Veuillez sélectionner une compétence et une date de début');
 
1446
  start_date: startDate,
1447
  session_duration: duration,
1448
  repetitions: 6,
1449
+ quality_level: currentQuality,
1450
+ productivity_method: productivityMethod,
1451
+ energy_pattern: energyPattern,
1452
+ time_slots: timeSlots
1453
  })
1454
  });
1455
 
 
1528
  <span><i class="fas fa-lightbulb"></i> Stratégie</span>
1529
  <span>${session.strategie}</span>
1530
  </div>
1531
+ ${session.productivity_method ? `
1532
+ <div class="detail-item">
1533
+ <span><i class="fas fa-chart-line"></i> Productivité</span>
1534
+ <span>${session.productivity_method === 'pomodoro' ? '🍅 Pomodoro' : '⏳ Deep Work'}</span>
1535
+ </div>
1536
+ ` : ''}
1537
+ ${session.optimal_time ? `
1538
+ <div class="detail-item">
1539
+ <span><i class="fas fa-sun"></i> Heure Optimale</span>
1540
+ <span>${session.optimal_time}</span>
1541
+ </div>
1542
+ ` : ''}
1543
  </div>
1544
  <div style="margin-top: 15px; padding: 10px; background: #f1f5f9; border-radius: 8px; font-size: 0.9rem;">
1545
  <i class="fas fa-bell"></i> ${session.reminder || ''}
 
1612
  });
1613
  }
1614
 
1615
+ // ============================================
1616
+ // FLASHCARD APPLICATION
1617
+ // ============================================
1618
+
1619
+ // Charger les flashcards
1620
+ async function loadFlashcards() {
1621
+ try {
1622
+ const response = await fetch('/api/flashcards');
1623
+ flashcards = await response.json();
1624
+
1625
+ if (flashcards.length > 0) {
1626
+ currentFlashcardIndex = 0;
1627
+ displayFlashcard(currentFlashcardIndex);
1628
+ updateFlashcardStats();
1629
+ } else {
1630
+ // Données par défaut
1631
+ flashcards = [
1632
+ {
1633
+ id: 1,
1634
+ question: "Je (être) content de te voir.",
1635
+ answer: "suis",
1636
+ explanation: "'Être' au présent: je suis, tu es, il est, nous sommes, vous êtes, ils sont",
1637
+ category: "conjugaison",
1638
+ difficulty: "moyen",
1639
+ score: 85,
1640
+ nextReview: new Date(),
1641
+ interval: 1,
1642
+ repetitions: 3
1643
+ },
1644
+ {
1645
+ id: 2,
1646
+ question: "Nous (aller) au marché demain.",
1647
+ answer: "allons",
1648
+ explanation: "'Aller' au présent: je vais, tu vas, il va, nous allons, vous allez, ils vont",
1649
+ category: "conjugaison",
1650
+ difficulty: "facile",
1651
+ score: 92,
1652
+ nextReview: new Date(),
1653
+ interval: 3,
1654
+ repetitions: 5
1655
+ },
1656
+ {
1657
+ id: 3,
1658
+ question: "Elle (faire) ses devoirs chaque soir.",
1659
+ answer: "fait",
1660
+ explanation: "'Faire' au présent: je fais, tu fais, il fait, nous faisons, vous faites, ils font",
1661
+ category: "conjugaison",
1662
+ difficulty: "moyen",
1663
+ score: 78,
1664
+ nextReview: new Date(Date.now() + 86400000),
1665
+ interval: 2,
1666
+ repetitions: 2
1667
+ }
1668
+ ];
1669
+ displayFlashcard(currentFlashcardIndex);
1670
+ updateFlashcardStats();
1671
+ }
1672
+ } catch (error) {
1673
+ console.error('Erreur chargement flashcards:', error);
1674
+ // Utiliser des données par défaut
1675
+ flashcards = [
1676
+ {
1677
+ id: 1,
1678
+ question: "Je (être) content de te voir.",
1679
+ answer: "suis",
1680
+ explanation: "'Être' au présent: je suis, tu es, il est, nous sommes, vous êtes, ils sont",
1681
+ category: "conjugaison",
1682
+ difficulty: "moyen",
1683
+ score: 85,
1684
+ nextReview: new Date(),
1685
+ interval: 1,
1686
+ repetitions: 3
1687
+ }
1688
+ ];
1689
+ displayFlashcard(currentFlashcardIndex);
1690
+ updateFlashcardStats();
1691
+ }
1692
+ }
1693
+
1694
+ // Afficher une flashcard
1695
+ function displayFlashcard(index) {
1696
+ if (flashcards.length === 0) return;
1697
+
1698
+ const card = flashcards[index];
1699
+ document.getElementById('flashcardQuestion').textContent = card.question;
1700
+ document.getElementById('flashcardAnswer').textContent = card.answer;
1701
+ document.getElementById('flashcardExplanation').textContent = card.explanation;
1702
+ document.getElementById('flashcardCategory').textContent = card.category.charAt(0).toUpperCase() + card.category.slice(1);
1703
+ document.getElementById('flashcardScore').textContent = `Score: ${card.score}%`;
1704
+ document.getElementById('flashcardDifficulty').textContent = card.difficulty.charAt(0).toUpperCase() + card.difficulty.slice(1);
1705
+
1706
+ // Mettre à jour la progression
1707
+ document.getElementById('currentCard').textContent = index + 1;
1708
+ document.getElementById('totalCards').textContent = flashcards.length;
1709
+ document.getElementById('progressFill').style.width = `${((index + 1) / flashcards.length) * 100}%`;
1710
+
1711
+ // Mettre à jour la date de révision
1712
+ const nextReview = new Date(card.nextReview);
1713
+ const today = new Date();
1714
+ const diffTime = nextReview - today;
1715
+ const diffDays = Math.ceil(diffTime / (1000 * 60 * 60 * 24));
1716
+
1717
+ if (diffDays <= 0) {
1718
+ document.getElementById('nextReview').textContent = "Prochaine révision: Aujourd'hui";
1719
+ } else if (diffDays === 1) {
1720
+ document.getElementById('nextReview').textContent = "Prochaine révision: Demain";
1721
+ } else {
1722
+ document.getElementById('nextReview').textContent = `Prochaine révision: Dans ${diffDays} jours`;
1723
+ }
1724
+
1725
+ // Réinitialiser l'affichage
1726
+ document.getElementById('flashcardFront').style.display = 'block';
1727
+ document.getElementById('flashcardBack').style.display = 'none';
1728
+ document.getElementById('flashcard').classList.remove('flipped');
1729
+ }
1730
+
1731
+ // Retourner la carte
1732
+ function flipCard() {
1733
+ const front = document.getElementById('flashcardFront');
1734
+ const back = document.getElementById('flashcardBack');
1735
+ const card = document.getElementById('flashcard');
1736
+
1737
+ if (front.style.display !== 'none') {
1738
+ front.style.display = 'none';
1739
+ back.style.display = 'block';
1740
+ card.classList.add('flipped');
1741
+ } else {
1742
+ front.style.display = 'block';
1743
+ back.style.display = 'none';
1744
+ card.classList.remove('flipped');
1745
+ }
1746
+ }
1747
+
1748
+ // Voir la réponse
1749
+ function showAnswer() {
1750
+ document.getElementById('flashcardFront').style.display = 'none';
1751
+ document.getElementById('flashcardBack').style.display = 'block';
1752
+ document.getElementById('flashcard').classList.add('flipped');
1753
+ }
1754
+
1755
+ // Évaluer la carte
1756
+ function rateCard(rating) {
1757
+ if (flashcards.length === 0) return;
1758
+
1759
+ const card = flashcards[currentFlashcardIndex];
1760
+
1761
+ // Mettre à jour le score basé sur l'évaluation (0=difficile, 1=moyen, 2=facile)
1762
+ let scoreChange = 0;
1763
+ switch(rating) {
1764
+ case 0: // Difficile
1765
+ scoreChange = -10;
1766
+ card.interval = Math.max(1, card.interval - 1);
1767
+ break;
1768
+ case 1: // Moyen
1769
+ scoreChange = 5;
1770
+ break;
1771
+ case 2: // Facile
1772
+ scoreChange = 15;
1773
+ card.interval = Math.min(30, card.interval + 2);
1774
+ break;
1775
+ }
1776
+
1777
+ // Mettre à jour le score (limité entre 0 et 100)
1778
+ card.score = Math.max(0, Math.min(100, card.score + scoreChange));
1779
+
1780
+ // Mettre à jour les répétitions et la date de révision
1781
+ card.repetitions++;
1782
+ card.nextReview = new Date(Date.now() + card.interval * 24 * 60 * 60 * 1000);
1783
+
1784
+ // Mettre à jour les statistiques
1785
+ flashcardStats.totalReviewed++;
1786
+
1787
+ // Calculer le taux de maîtrise (cartes avec score > 80)
1788
+ const mastered = flashcards.filter(c => c.score >= 80).length;
1789
+ flashcardStats.masteryRate = Math.round((mastered / flashcards.length) * 100);
1790
+
1791
+ // Calculer le score moyen
1792
+ const totalScore = flashcards.reduce((sum, c) => sum + c.score, 0);
1793
+ flashcardStats.avgScore = Math.round(totalScore / flashcards.length);
1794
+
1795
+ // Mettre à jour la série si l'évaluation est positive
1796
+ if (rating >= 1) {
1797
+ flashcardStats.streak++;
1798
+ } else {
1799
+ flashcardStats.streak = 0;
1800
+ }
1801
+
1802
+ // Mettre à jour l'affichage
1803
+ updateFlashcardStatsDisplay();
1804
+
1805
+ // Passer à la carte suivante
1806
+ nextCard();
1807
+ }
1808
+
1809
+ // Carte suivante
1810
+ function nextCard() {
1811
+ if (flashcards.length === 0) return;
1812
+
1813
+ currentFlashcardIndex = (currentFlashcardIndex + 1) % flashcards.length;
1814
+ displayFlashcard(currentFlashcardIndex);
1815
+ }
1816
+
1817
+ // Mettre à jour les statistiques des flashcards
1818
+ function updateFlashcardStats() {
1819
+ if (flashcards.length === 0) {
1820
+ flashcardStats = {
1821
+ totalReviewed: 0,
1822
+ masteryRate: 0,
1823
+ avgScore: 0,
1824
+ streak: 0,
1825
+ totalCards: 0,
1826
+ mastered: 0,
1827
+ learning: 0,
1828
+ due: 0
1829
+ };
1830
+ } else {
1831
+ const today = new Date();
1832
+ const mastered = flashcards.filter(c => c.score >= 80).length;
1833
+ const due = flashcards.filter(c => new Date(c.nextReview) <= today).length;
1834
+ const totalScore = flashcards.reduce((sum, c) => sum + c.score, 0);
1835
+
1836
+ flashcardStats = {
1837
+ totalReviewed: flashcards.reduce((sum, c) => sum + c.repetitions, 0),
1838
+ masteryRate: Math.round((mastered / flashcards.length) * 100),
1839
+ avgScore: Math.round(totalScore / flashcards.length),
1840
+ streak: flashcardStats.streak, // Garder la série
1841
+ totalCards: flashcards.length,
1842
+ mastered: mastered,
1843
+ learning: flashcards.length - mastered,
1844
+ due: due
1845
+ };
1846
+ }
1847
+
1848
+ updateFlashcardStatsDisplay();
1849
+ updateFlashcardProgressChart();
1850
+ }
1851
+
1852
+ // Mettre à jour l'affichage des statistiques
1853
+ function updateFlashcardStatsDisplay() {
1854
+ document.getElementById('totalReviewed').textContent = flashcardStats.totalReviewed;
1855
+ document.getElementById('masteryRate').textContent = flashcardStats.masteryRate + '%';
1856
+ document.getElementById('avgScore').textContent = flashcardStats.avgScore + '%';
1857
+ document.getElementById('cardsDue').textContent = flashcardStats.due;
1858
+ document.getElementById('streakCount').textContent = flashcardStats.streak;
1859
+
1860
+ // Mettre à jour les statistiques dans l'onglet Stats
1861
+ document.getElementById('statsTotalCards').textContent = flashcardStats.totalCards;
1862
+ document.getElementById('statsMastered').textContent = flashcardStats.mastered;
1863
+ document.getElementById('statsLearning').textContent = flashcardStats.learning;
1864
+ document.getElementById('statsDue').textContent = flashcardStats.due;
1865
+ }
1866
+
1867
+ // Ajouter une nouvelle flashcard
1868
+ function addNewFlashcard() {
1869
+ const question = document.getElementById('newQuestion').value;
1870
+ const answer = document.getElementById('newAnswer').value;
1871
+ const category = document.getElementById('newCategory').value;
1872
+ const difficulty = document.getElementById('newDifficulty').value;
1873
+ const explanation = document.getElementById('newExplanation').value;
1874
+
1875
+ if (!question || !answer) {
1876
+ alert('Veuillez entrer une question et une réponse');
1877
+ return;
1878
+ }
1879
+
1880
+ const newCard = {
1881
+ id: flashcards.length + 1,
1882
+ question: question,
1883
+ answer: answer,
1884
+ explanation: explanation || 'Pas d\'explication supplémentaire',
1885
+ category: category,
1886
+ difficulty: difficulty,
1887
+ score: 50, // Score initial
1888
+ nextReview: new Date(),
1889
+ interval: 1,
1890
+ repetitions: 0
1891
+ };
1892
+
1893
+ flashcards.push(newCard);
1894
+
1895
+ // Réinitialiser le formulaire
1896
+ document.getElementById('newQuestion').value = '';
1897
+ document.getElementById('newAnswer').value = '';
1898
+ document.getElementById('newExplanation').value = '';
1899
+
1900
+ // Mettre à jour l'affichage
1901
+ updateFlashcardStats();
1902
+
1903
+ // Afficher la nouvelle carte
1904
+ currentFlashcardIndex = flashcards.length - 1;
1905
+ displayFlashcard(currentFlashcardIndex);
1906
+
1907
+ alert('Flashcard ajoutée avec succès !');
1908
+ }
1909
+
1910
+ // Créer le graphique de progression des flashcards
1911
+ function updateFlashcardProgressChart() {
1912
+ const ctx = document.getElementById('flashcardProgressChart').getContext('2d');
1913
+
1914
+ if (window.flashcardProgressChart) {
1915
+ window.flashcardProgressChart.destroy();
1916
+ }
1917
+
1918
+ const data = {
1919
+ labels: ['Maîtrisées', 'En Apprentissage', 'À Réviser'],
1920
+ datasets: [{
1921
+ data: [flashcardStats.mastered, flashcardStats.learning, flashcardStats.due],
1922
+ backgroundColor: ['#10b981', '#f59e0b', '#ef4444'],
1923
+ borderWidth: 2,
1924
+ borderColor: 'white'
1925
+ }]
1926
+ };
1927
+
1928
+ window.flashcardProgressChart = new Chart(ctx, {
1929
+ type: 'doughnut',
1930
+ data: data,
1931
+ options: {
1932
+ responsive: true,
1933
+ maintainAspectRatio: false,
1934
+ plugins: {
1935
+ legend: {
1936
+ position: 'bottom'
1937
+ },
1938
+ title: {
1939
+ display: true,
1940
+ text: 'Distribution des Flashcards',
1941
+ font: { size: 16 }
1942
+ }
1943
+ },
1944
+ cutout: '60%'
1945
+ }
1946
+ });
1947
+ }
1948
+
1949
  // Journal
1950
  function setEvaluation(score) {
1951
  document.getElementById('auto_eval').value = score;