Docfile commited on
Commit
0e2aa9c
·
verified ·
1 Parent(s): 77e12b5

Create gestion.html

Browse files
Files changed (1) hide show
  1. templates/gestion.html +622 -0
templates/gestion.html ADDED
@@ -0,0 +1,622 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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>Gestion des Dissertations - Mariam AI</title>
7
+ <script src="https://cdnjs.cloudflare.com/ajax/libs/tailwindcss/2.2.19/tailwind.min.js"></script>
8
+ <style>
9
+ @import url('https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&display=swap');
10
+
11
+ body {
12
+ font-family: 'Inter', sans-serif;
13
+ background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
14
+ min-height: 100vh;
15
+ }
16
+
17
+ .glass {
18
+ background: rgba(255, 255, 255, 0.1);
19
+ backdrop-filter: blur(10px);
20
+ border: 1px solid rgba(255, 255, 255, 0.2);
21
+ }
22
+
23
+ .card-hover {
24
+ transition: all 0.3s ease;
25
+ }
26
+
27
+ .card-hover:hover {
28
+ transform: translateY(-2px);
29
+ box-shadow: 0 10px 25px rgba(0, 0, 0, 0.2);
30
+ }
31
+
32
+ .table-row:hover {
33
+ background: rgba(255, 255, 255, 0.1);
34
+ }
35
+
36
+ .loading-spinner {
37
+ border: 3px solid rgba(255, 255, 255, 0.3);
38
+ border-radius: 50%;
39
+ border-top: 3px solid white;
40
+ width: 20px;
41
+ height: 20px;
42
+ animation: spin 1s linear infinite;
43
+ }
44
+
45
+ @keyframes spin {
46
+ 0% { transform: rotate(0deg); }
47
+ 100% { transform: rotate(360deg); }
48
+ }
49
+
50
+ .fade-in {
51
+ animation: fadeIn 0.5s ease-in-out;
52
+ }
53
+
54
+ @keyframes fadeIn {
55
+ from { opacity: 0; transform: translateY(20px); }
56
+ to { opacity: 1; transform: translateY(0); }
57
+ }
58
+ </style>
59
+ </head>
60
+ <body class="min-h-screen">
61
+ <div class="container mx-auto px-4 py-8">
62
+ <!-- Header -->
63
+ <div class="text-center mb-8">
64
+ <h1 class="text-4xl font-bold text-white mb-4">🎓 Gestion des Dissertations</h1>
65
+ <p class="text-white/80 text-lg">Tableau de bord administrateur - Mariam AI</p>
66
+ </div>
67
+
68
+ <!-- Stats Cards -->
69
+ <div class="grid grid-cols-1 md:grid-cols-4 gap-6 mb-8">
70
+ <div class="glass rounded-xl p-6 text-center card-hover">
71
+ <div class="text-3xl font-bold text-white" id="totalDissertations">-</div>
72
+ <div class="text-white/80">Total Dissertations</div>
73
+ </div>
74
+ <div class="glass rounded-xl p-6 text-center card-hover">
75
+ <div class="text-3xl font-bold text-white" id="todayCount">-</div>
76
+ <div class="text-white/80">Aujourd'hui</div>
77
+ </div>
78
+ <div class="glass rounded-xl p-6 text-center card-hover">
79
+ <div class="text-3xl font-bold text-white" id="type1Count">-</div>
80
+ <div class="text-white/80">Type 1</div>
81
+ </div>
82
+ <div class="glass rounded-xl p-6 text-center card-hover">
83
+ <div class="text-3xl font-bold text-white" id="type2Count">-</div>
84
+ <div class="text-white/80">Type 2</div>
85
+ </div>
86
+ </div>
87
+
88
+ <!-- Search and Filters -->
89
+ <div class="glass rounded-xl p-6 mb-6">
90
+ <div class="flex flex-col md:flex-row gap-4 mb-4">
91
+ <div class="flex-1">
92
+ <input type="text"
93
+ id="searchInput"
94
+ placeholder="Rechercher par question ou cours..."
95
+ class="w-full px-4 py-2 rounded-lg bg-white/20 border border-white/30 text-white placeholder-white/60 focus:outline-none focus:border-white/60">
96
+ </div>
97
+ <div>
98
+ <select id="typeFilter" class="px-4 py-2 rounded-lg bg-white/20 border border-white/30 text-white focus:outline-none">
99
+ <option value="">Tous les types</option>
100
+ <option value="type1">Type 1</option>
101
+ <option value="type2">Type 2</option>
102
+ </select>
103
+ </div>
104
+ <div>
105
+ <button id="searchBtn" class="px-6 py-2 bg-blue-600 hover:bg-blue-700 text-white rounded-lg transition-colors">
106
+ 🔍 Rechercher
107
+ </button>
108
+ </div>
109
+ </div>
110
+ </div>
111
+
112
+ <!-- Dissertations Table -->
113
+ <div class="glass rounded-xl overflow-hidden">
114
+ <div class="p-6 border-b border-white/20">
115
+ <h2 class="text-xl font-semibold text-white">📚 Liste des Dissertations</h2>
116
+ </div>
117
+
118
+ <div id="loadingIndicator" class="p-8 text-center">
119
+ <div class="loading-spinner mx-auto mb-4"></div>
120
+ <p class="text-white/80">Chargement des données...</p>
121
+ </div>
122
+
123
+ <div id="dissertationsContainer" class="hidden">
124
+ <div class="overflow-x-auto">
125
+ <table class="w-full">
126
+ <thead class="bg-white/10">
127
+ <tr class="text-white/90 text-left">
128
+ <th class="p-4 font-medium">Date</th>
129
+ <th class="p-4 font-medium">Question</th>
130
+ <th class="p-4 font-medium">Type</th>
131
+ <th class="p-4 font-medium">Cours</th>
132
+ <th class="p-4 font-medium">IP Utilisateur</th>
133
+ <th class="p-4 font-medium">Actions</th>
134
+ </tr>
135
+ </thead>
136
+ <tbody id="dissertationsTable" class="text-white/80">
137
+ <!-- Les lignes seront ajoutées dynamiquement -->
138
+ </tbody>
139
+ </table>
140
+ </div>
141
+
142
+ <!-- Pagination -->
143
+ <div id="paginationContainer" class="p-4 border-t border-white/20 flex justify-between items-center">
144
+ <div class="text-white/80">
145
+ <span id="paginationInfo">Affichage de 0 à 0 sur 0 résultats</span>
146
+ </div>
147
+ <div class="flex gap-2">
148
+ <button id="prevBtn" class="px-4 py-2 bg-white/20 hover:bg-white/30 text-white rounded-lg transition-colors disabled:opacity-50">
149
+ ← Précédent
150
+ </button>
151
+ <span id="pageNumbers" class="flex gap-1"></span>
152
+ <button id="nextBtn" class="px-4 py-2 bg-white/20 hover:bg-white/30 text-white rounded-lg transition-colors disabled:opacity-50">
153
+ Suivant →
154
+ </button>
155
+ </div>
156
+ </div>
157
+ </div>
158
+ </div>
159
+ </div>
160
+
161
+ <!-- Modal de détail -->
162
+ <div id="detailModal" class="hidden fixed inset-0 bg-black/50 flex items-center justify-center p-4 z-50">
163
+ <div class="glass rounded-xl max-w-4xl max-h-full overflow-y-auto">
164
+ <div class="p-6 border-b border-white/20 flex justify-between items-center">
165
+ <h3 class="text-xl font-semibold text-white">📄 Détail de la Dissertation</h3>
166
+ <button id="closeModal" class="text-white/60 hover:text-white text-2xl">×</button>
167
+ </div>
168
+ <div id="modalContent" class="p-6 text-white">
169
+ <!-- Contenu du modal ajouté dynamiquement -->
170
+ </div>
171
+ </div>
172
+ </div>
173
+
174
+ <!-- Modal de confirmation de suppression -->
175
+ <div id="deleteModal" class="hidden fixed inset-0 bg-black/50 flex items-center justify-center p-4 z-50">
176
+ <div class="glass rounded-xl p-6 max-w-md">
177
+ <h3 class="text-lg font-semibold text-white mb-4">⚠️ Confirmer la suppression</h3>
178
+ <p class="text-white/80 mb-6">Êtes-vous sûr de vouloir supprimer cette dissertation ? Cette action est irréversible.</p>
179
+ <div class="flex gap-4 justify-end">
180
+ <button id="cancelDelete" class="px-4 py-2 bg-gray-500 hover:bg-gray-600 text-white rounded-lg transition-colors">
181
+ Annuler
182
+ </button>
183
+ <button id="confirmDelete" class="px-4 py-2 bg-red-600 hover:bg-red-700 text-white rounded-lg transition-colors">
184
+ Supprimer
185
+ </button>
186
+ </div>
187
+ </div>
188
+ </div>
189
+
190
+ <script>
191
+ let currentPage = 1;
192
+ let currentSearch = '';
193
+ let currentType = '';
194
+ let deleteId = null;
195
+
196
+ // Initialisation
197
+ document.addEventListener('DOMContentLoaded', function() {
198
+ loadDissertations();
199
+ setupEventListeners();
200
+ });
201
+
202
+ function setupEventListeners() {
203
+ // Recherche
204
+ document.getElementById('searchBtn').addEventListener('click', performSearch);
205
+ document.getElementById('searchInput').addEventListener('keypress', function(e) {
206
+ if (e.key === 'Enter') performSearch();
207
+ });
208
+
209
+ // Modal handlers
210
+ document.getElementById('closeModal').addEventListener('click', closeModal);
211
+ document.getElementById('cancelDelete').addEventListener('click', closeDeleteModal);
212
+ document.getElementById('confirmDelete').addEventListener('click', confirmDelete);
213
+
214
+ // Click outside modal to close
215
+ document.getElementById('detailModal').addEventListener('click', function(e) {
216
+ if (e.target === this) closeModal();
217
+ });
218
+ document.getElementById('deleteModal').addEventListener('click', function(e) {
219
+ if (e.target === this) closeDeleteModal();
220
+ });
221
+ }
222
+
223
+ function performSearch() {
224
+ currentSearch = document.getElementById('searchInput').value.trim();
225
+ currentType = document.getElementById('typeFilter').value;
226
+ currentPage = 1;
227
+ loadDissertations();
228
+ }
229
+
230
+ async function loadDissertations() {
231
+ try {
232
+ showLoading();
233
+
234
+ const params = new URLSearchParams({
235
+ page: currentPage,
236
+ per_page: 10,
237
+ search: currentSearch,
238
+ type: currentType
239
+ });
240
+
241
+ const response = await fetch(`/api/dissertations?${params}`);
242
+ const data = await response.json();
243
+
244
+ if (response.ok) {
245
+ displayDissertations(data);
246
+ updateStats(data);
247
+ } else {
248
+ throw new Error(data.error || 'Erreur lors du chargement');
249
+ }
250
+ } catch (error) {
251
+ console.error('Erreur:', error);
252
+ showError('Erreur lors du chargement des données');
253
+ } finally {
254
+ hideLoading();
255
+ }
256
+ }
257
+
258
+ function showLoading() {
259
+ document.getElementById('loadingIndicator').classList.remove('hidden');
260
+ document.getElementById('dissertationsContainer').classList.add('hidden');
261
+ }
262
+
263
+ function hideLoading() {
264
+ document.getElementById('loadingIndicator').classList.add('hidden');
265
+ document.getElementById('dissertationsContainer').classList.remove('hidden');
266
+ }
267
+
268
+ function displayDissertations(data) {
269
+ const tbody = document.getElementById('dissertationsTable');
270
+ tbody.innerHTML = '';
271
+
272
+ data.dissertations.forEach(dissertation => {
273
+ const row = createDissertationRow(dissertation);
274
+ tbody.appendChild(row);
275
+ });
276
+
277
+ updatePagination(data);
278
+ }
279
+
280
+ function createDissertationRow(dissertation) {
281
+ const row = document.createElement('tr');
282
+ row.className = 'table-row border-b border-white/10';
283
+
284
+ const date = new Date(dissertation.created_at).toLocaleDateString('fr-FR', {
285
+ year: 'numeric',
286
+ month: 'short',
287
+ day: 'numeric',
288
+ hour: '2-digit',
289
+ minute: '2-digit'
290
+ });
291
+
292
+ row.innerHTML = `
293
+ <td class="p-4">${date}</td>
294
+ <td class="p-4">
295
+ <div class="max-w-xs truncate" title="${dissertation.question}">
296
+ ${dissertation.question}
297
+ </div>
298
+ </td>
299
+ <td class="p-4">
300
+ <span class="px-2 py-1 rounded text-xs ${dissertation.dissertation_type === 'type1' ? 'bg-blue-500/20 text-blue-300' : 'bg-green-500/20 text-green-300'}">
301
+ ${dissertation.dissertation_type.toUpperCase()}
302
+ </span>
303
+ </td>
304
+ <td class="p-4">
305
+ <div class="max-w-xs truncate" title="${dissertation.course_title || 'Aucun'}">
306
+ ${dissertation.course_title || '-'}
307
+ </div>
308
+ </td>
309
+ <td class="p-4">${dissertation.user_ip}</td>
310
+ <td class="p-4">
311
+ <div class="flex gap-2">
312
+ <button onclick="viewDissertation(${dissertation.id})"
313
+ class="px-3 py-1 bg-blue-600 hover:bg-blue-700 text-white rounded text-sm transition-colors">
314
+ 👁️ Voir
315
+ </button>
316
+ <button onclick="deleteDissertation(${dissertation.id})"
317
+ class="px-3 py-1 bg-red-600 hover:bg-red-700 text-white rounded text-sm transition-colors">
318
+ 🗑️ Suppr.
319
+ </button>
320
+ </div>
321
+ </td>
322
+ `;
323
+
324
+ return row;
325
+ }
326
+
327
+ function updatePagination(data) {
328
+ const { page, total_pages, total, per_page } = data;
329
+ const start = (page - 1) * per_page + 1;
330
+ const end = Math.min(page * per_page, total);
331
+
332
+ document.getElementById('paginationInfo').textContent =
333
+ `Affichage de ${start} à ${end} sur ${total} résultats`;
334
+
335
+ // Boutons précédent/suivant
336
+ const prevBtn = document.getElementById('prevBtn');
337
+ const nextBtn = document.getElementById('nextBtn');
338
+
339
+ prevBtn.disabled = page <= 1;
340
+ nextBtn.disabled = page >= total_pages;
341
+
342
+ prevBtn.onclick = () => { if (page > 1) { currentPage = page - 1; loadDissertations(); } };
343
+ nextBtn.onclick = () => { if (page < total_pages) { currentPage = page + 1; loadDissertations(); } };
344
+
345
+ // Numéros de page
346
+ const pageNumbers = document.getElementById('pageNumbers');
347
+ pageNumbers.innerHTML = '';
348
+
349
+ const maxVisible = 5;
350
+ let startPage = Math.max(1, page - Math.floor(maxVisible / 2));
351
+ let endPage = Math.min(total_pages, startPage + maxVisible - 1);
352
+
353
+ if (endPage - startPage + 1 < maxVisible) {
354
+ startPage = Math.max(1, endPage - maxVisible + 1);
355
+ }
356
+
357
+ for (let i = startPage; i <= endPage; i++) {
358
+ const pageBtn = document.createElement('button');
359
+ pageBtn.className = `px-3 py-2 rounded-lg transition-colors ${
360
+ i === page
361
+ ? 'bg-white/30 text-white'
362
+ : 'bg-white/10 hover:bg-white/20 text-white/80'
363
+ }`;
364
+ pageBtn.textContent = i;
365
+ pageBtn.onclick = () => { currentPage = i; loadDissertations(); };
366
+ pageNumbers.appendChild(pageBtn);
367
+ }
368
+ }
369
+
370
+ function updateStats(data) {
371
+ // Simuler des stats basiques (vous pouvez créer une API dédiée pour des stats plus précises)
372
+ document.getElementById('totalDissertations').textContent = data.total;
373
+
374
+ // Compter les types dans la page actuelle (approximation)
375
+ const type1Count = data.dissertations.filter(d => d.dissertation_type === 'type1').length;
376
+ const type2Count = data.dissertations.filter(d => d.dissertation_type === 'type2').length;
377
+
378
+ document.getElementById('type1Count').textContent = type1Count;
379
+ document.getElementById('type2Count').textContent = type2Count;
380
+
381
+ // Compter aujourd'hui (approximation basée sur la page actuelle)
382
+ const today = new Date().toDateString();
383
+ const todayCount = data.dissertations.filter(d =>
384
+ new Date(d.created_at).toDateString() === today
385
+ ).length;
386
+
387
+ document.getElementById('todayCount').textContent = todayCount;
388
+ }
389
+
390
+ async function viewDissertation(id) {
391
+ try {
392
+ const response = await fetch(`/api/dissertations/${id}`);
393
+ const data = await response.json();
394
+
395
+ if (response.ok) {
396
+ showDissertationModal(data);
397
+ } else {
398
+ throw new Error(data.error || 'Erreur lors du chargement');
399
+ }
400
+ } catch (error) {
401
+ console.error('Erreur:', error);
402
+ showError('Erreur lors du chargement du détail');
403
+ }
404
+ }
405
+
406
+ function showDissertationModal(dissertation) {
407
+ const content = dissertation.generated_content;
408
+ const modalContent = document.getElementById('modalContent');
409
+
410
+ modalContent.innerHTML = `
411
+ <div class="space-y-6">
412
+ <!-- Info générales -->
413
+ <div class="grid grid-cols-1 md:grid-cols-2 gap-4 p-4 bg-white/10 rounded-lg">
414
+ <div>
415
+ <strong class="text-white/90">Question:</strong>
416
+ <p class="text-white/80 mt-1">${dissertation.question}</p>
417
+ </div>
418
+ <div>
419
+ <strong class="text-white/90">Type:</strong>
420
+ <span class="ml-2 px-2 py-1 rounded text-xs ${
421
+ dissertation.dissertation_type === 'type1'
422
+ ? 'bg-blue-500/20 text-blue-300'
423
+ : 'bg-green-500/20 text-green-300'
424
+ }">
425
+ ${dissertation.dissertation_type.toUpperCase()}
426
+ </span>
427
+ </div>
428
+ <div>
429
+ <strong class="text-white/90">Cours:</strong>
430
+ <p class="text-white/80 mt-1">${dissertation.course_title || 'Aucun cours spécifique'}</p>
431
+ </div>
432
+ <div>
433
+ <strong class="text-white/90">Date:</strong>
434
+ <p class="text-white/80 mt-1">${new Date(dissertation.created_at).toLocaleString('fr-FR')}</p>
435
+ </div>
436
+ <div>
437
+ <strong class="text-white/90">IP Utilisateur:</strong>
438
+ <p class="text-white/80 mt-1">${dissertation.user_ip}</p>
439
+ </div>
440
+ <div>
441
+ <strong class="text-white/90">User Agent:</strong>
442
+ <p class="text-white/80 mt-1 text-xs truncate" title="${dissertation.user_agent}">${dissertation.user_agent}</p>
443
+ </div>
444
+ </div>
445
+
446
+ <!-- Contenu de la dissertation -->
447
+ <div class="bg-white/5 rounded-lg p-4">
448
+ <h4 class="text-lg font-semibold text-white mb-4">📝 Contenu de la Dissertation</h4>
449
+
450
+ <!-- Introduction -->
451
+ <div class="mb-6">
452
+ <h5 class="font-medium text-white/90 mb-2">Introduction</h5>
453
+ <div class="bg-white/10 rounded p-3 text-white/80 text-sm leading-relaxed">
454
+ ${content.introduction}
455
+ </div>
456
+ </div>
457
+
458
+ <!-- Parties -->
459
+ <div class="space-y-6">
460
+ ${content.parties.map((partie, index) => `
461
+ <div class="mb-6">
462
+ <h5 class="font-medium text-white/90 mb-2">Partie ${index + 1}</h5>
463
+
464
+ <!-- Chapeau -->
465
+ <div class="bg-blue-500/20 rounded p-3 mb-3">
466
+ <p class="text-blue-200 text-sm font-medium mb-1">Chapeau:</p>
467
+ <p class="text-white/80 text-sm">${partie.chapeau}</p>
468
+ </div>
469
+
470
+ <!-- Arguments -->
471
+ <div class="space-y-2">
472
+ ${partie.arguments.map((arg, argIndex) => `
473
+ <div class="bg-white/10 rounded p-3">
474
+ <p class="text-green-300 text-xs mb-1">Argument ${argIndex + 1}:</p>
475
+ <p class="text-white/80 text-sm leading-relaxed">${arg.paragraphe_argumentatif}</p>
476
+ </div>
477
+ `).join('')}
478
+ </div>
479
+
480
+ <!-- Transition -->
481
+ ${partie.transition ? `
482
+ <div class="bg-purple-500/20 rounded p-3 mt-3">
483
+ <p class="text-purple-200 text-sm font-medium mb-1">Transition:</p>
484
+ <p class="text-white/80 text-sm">${partie.transition}</p>
485
+ </div>
486
+ ` : ''}
487
+ </div>
488
+ `).join('')}
489
+ </div>
490
+
491
+ <!-- Conclusion -->
492
+ <div class="mt-6">
493
+ <h5 class="font-medium text-white/90 mb-2">Conclusion</h5>
494
+ <div class="bg-white/10 rounded p-3 text-white/80 text-sm leading-relaxed">
495
+ ${content.conclusion}
496
+ </div>
497
+ </div>
498
+ </div>
499
+
500
+ <!-- Actions -->
501
+ <div class="flex gap-4 pt-4">
502
+ <button onclick="generatePDF(${dissertation.id})"
503
+ class="px-4 py-2 bg-green-600 hover:bg-green-700 text-white rounded-lg transition-colors">
504
+ 📄 Générer PDF
505
+ </button>
506
+ <button onclick="copyToClipboard(${JSON.stringify(content).replace(/"/g, '&quot;')})"
507
+ class="px-4 py-2 bg-blue-600 hover:bg-blue-700 text-white rounded-lg transition-colors">
508
+ 📋 Copier le texte
509
+ </button>
510
+ </div>
511
+ </div>
512
+ `;
513
+
514
+ document.getElementById('detailModal').classList.remove('hidden');
515
+ document.body.style.overflow = 'hidden';
516
+ }
517
+
518
+ function closeModal() {
519
+ document.getElementById('detailModal').classList.add('hidden');
520
+ document.body.style.overflow = 'auto';
521
+ }
522
+
523
+ function deleteDissertation(id) {
524
+ deleteId = id;
525
+ document.getElementById('deleteModal').classList.remove('hidden');
526
+ }
527
+
528
+ function closeDeleteModal() {
529
+ document.getElementById('deleteModal').classList.add('hidden');
530
+ deleteId = null;
531
+ }
532
+
533
+ async function confirmDelete() {
534
+ if (!deleteId) return;
535
+
536
+ try {
537
+ const response = await fetch(`/api/dissertations/${deleteId}`, {
538
+ method: 'DELETE'
539
+ });
540
+
541
+ const data = await response.json();
542
+
543
+ if (response.ok) {
544
+ showSuccess('Dissertation supprimée avec succès');
545
+ closeDeleteModal();
546
+ loadDissertations(); // Recharger la liste
547
+ } else {
548
+ throw new Error(data.error || 'Erreur lors de la suppression');
549
+ }
550
+ } catch (error) {
551
+ console.error('Erreur:', error);
552
+ showError('Erreur lors de la suppression');
553
+ }
554
+ }
555
+
556
+ function generatePDF(dissertationId) {
557
+ // Placeholder pour la génération PDF
558
+ showInfo('Fonctionnalité PDF en développement');
559
+ }
560
+
561
+ function copyToClipboard(content) {
562
+ const textContent = formatDissertationText(content);
563
+ navigator.clipboard.writeText(textContent).then(() => {
564
+ showSuccess('Texte copié dans le presse-papiers');
565
+ }).catch(() => {
566
+ showError('Erreur lors de la copie');
567
+ });
568
+ }
569
+
570
+ function formatDissertationText(content) {
571
+ let text = `DISSERTATION DE PHILOSOPHIE\n`;
572
+ text += `Sujet: ${content.sujet}\n`;
573
+ text += `Professeur: ${content.prof}\n\n`;
574
+
575
+ text += `INTRODUCTION\n`;
576
+ text += `${content.introduction}\n\n`;
577
+
578
+ content.parties.forEach((partie, index) => {
579
+ text += `PARTIE ${index + 1}\n`;
580
+ text += `${partie.chapeau}\n\n`;
581
+
582
+ partie.arguments.forEach((arg, argIndex) => {
583
+ text += `${arg.paragraphe_argumentatif}\n\n`;
584
+ });
585
+
586
+ if (partie.transition) {
587
+ text += `${partie.transition}\n\n`;
588
+ }
589
+ });
590
+
591
+ text += `CONCLUSION\n`;
592
+ text += `${content.conclusion}\n`;
593
+
594
+ return text;
595
+ }
596
+
597
+ function showSuccess(message) {
598
+ showNotification(message, 'bg-green-500');
599
+ }
600
+
601
+ function showError(message) {
602
+ showNotification(message, 'bg-red-500');
603
+ }
604
+
605
+ function showInfo(message) {
606
+ showNotification(message, 'bg-blue-500');
607
+ }
608
+
609
+ function showNotification(message, bgColor) {
610
+ const notification = document.createElement('div');
611
+ notification.className = `fixed top-4 right-4 ${bgColor} text-white px-6 py-3 rounded-lg shadow-lg z-50 fade-in`;
612
+ notification.textContent = message;
613
+
614
+ document.body.appendChild(notification);
615
+
616
+ setTimeout(() => {
617
+ notification.remove();
618
+ }, 3000);
619
+ }
620
+ </script>
621
+ </body>
622
+ </html>