progitanas1 commited on
Commit
dfe8a7c
·
verified ·
1 Parent(s): 9e9b346

crees les autres HTML et le serveur - Initial Deployment

Browse files
Files changed (7) hide show
  1. README.md +7 -5
  2. dashboard.html +396 -0
  3. index.html +544 -18
  4. login.html +90 -0
  5. prompts.txt +12 -0
  6. register.html +103 -0
  7. server.js +101 -0
README.md CHANGED
@@ -1,10 +1,12 @@
1
  ---
2
- title: Sang
3
- emoji: 🐠
4
- colorFrom: purple
5
- colorTo: pink
6
  sdk: static
7
  pinned: false
 
 
8
  ---
9
 
10
- Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
 
1
  ---
2
+ title: sang
3
+ emoji: 🐳
4
+ colorFrom: red
5
+ colorTo: green
6
  sdk: static
7
  pinned: false
8
+ tags:
9
+ - deepsite
10
  ---
11
 
12
+ Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
dashboard.html ADDED
@@ -0,0 +1,396 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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>Tableau de bord - LaboConnect</title>
7
+ <link rel="icon" type="image/x-icon" href="data:image/svg+xml,<svg xmlns=%22http://www.w3.org/2000/svg%22 viewBox=%220 0 100 100%22><text y=%22.9em%22 font-size=%2290%22>💉</text></svg>">
8
+ <script src="https://cdn.tailwindcss.com"></script>
9
+ <link href="https://fonts.googleapis.com/css2?family=Poppins:wght@300;400;500;600;700&display=swap" rel="stylesheet">
10
+ <script src="https://unpkg.com/feather-icons"></script>
11
+ <script src="https://cdn.jsdelivr.net/npm/[email protected]/lib/anime.min.js"></script>
12
+ <style>
13
+ body {
14
+ font-family: 'Poppins', sans-serif;
15
+ background: linear-gradient(135deg, #f0f9ff 0%, #e6f7ff 100%);
16
+ }
17
+ .card-hover {
18
+ transition: all 0.3s ease;
19
+ }
20
+ .card-hover:hover {
21
+ transform: translateY(-5px);
22
+ box-shadow: 0 20px 25px -5px rgba(0, 0, 0, 0.1), 0 10px 10px -5px rgba(0, 0, 0, 0.04);
23
+ }
24
+ .btn-primary {
25
+ background: linear-gradient(90deg, #4f46e5 0%, #7c3aed 100%);
26
+ transition: all 0.3s ease;
27
+ }
28
+ .btn-primary:hover {
29
+ background: linear-gradient(90deg, #4338ca 0%, #6d28d9 100%);
30
+ transform: scale(1.05);
31
+ }
32
+ .active-tab {
33
+ border-bottom: 3px solid #4f46e5;
34
+ color: #4f46e5;
35
+ font-weight: 600;
36
+ }
37
+ .appointment-card {
38
+ animation: fadeIn 0.5s ease-in-out;
39
+ }
40
+ @keyframes fadeIn {
41
+ from { opacity: 0; transform: translateY(20px); }
42
+ to { opacity: 1; transform: translateY(0); }
43
+ }
44
+ .pulse {
45
+ animation: pulse 2s infinite;
46
+ }
47
+ @keyframes pulse {
48
+ 0% { box-shadow: 0 0 0 0 rgba(79, 70, 229, 0.4); }
49
+ 70% { box-shadow: 0 0 0 10px rgba(79, 70, 229, 0); }
50
+ 100% { box-shadow: 0 0 0 0 rgba(79, 70, 229, 0); }
51
+ }
52
+ </style>
53
+ </head>
54
+ <body class="min-h-screen">
55
+ <!-- Header -->
56
+ <header class="bg-white shadow-sm">
57
+ <div class="container mx-auto px-4 py-4 flex justify-between items-center">
58
+ <div class="flex items-center space-x-2">
59
+ <div class="w-10 h-10 rounded-full bg-indigo-100 flex items-center justify-center">
60
+ <i data-feather="droplet" class="text-indigo-600"></i>
61
+ </div>
62
+ <h1 class="text-2xl font-bold text-gray-800">LaboConnect</h1>
63
+ </div>
64
+ <div id="userSection" class="flex items-center space-x-4">
65
+ <span id="userName" class="text-gray-700 font-medium"></span>
66
+ <button id="logoutBtn" class="text-gray-500 hover:text-gray-700">
67
+ <i data-feather="log-out"></i>
68
+ </button>
69
+ </div>
70
+ </div>
71
+ </header>
72
+
73
+ <!-- Main Content -->
74
+ <main class="container mx-auto px-4 py-8">
75
+ <!-- Welcome Banner -->
76
+ <div class="bg-gradient-to-r from-indigo-500 to-purple-600 rounded-2xl p-6 text-white mb-8">
77
+ <h2 class="text-2xl font-bold mb-2">Bienvenue sur votre tableau de bord</h2>
78
+ <p class="opacity-90">Gérez vos rendez-vous de prise de sang</p>
79
+ </div>
80
+
81
+ <!-- Navigation Tabs -->
82
+ <div class="flex border-b mb-6">
83
+ <button id="tabNewAppointment" class="pb-3 px-6 active-tab">Nouveau rendez-vous</button>
84
+ <button id="tabMyAppointments" class="pb-3 px-6 text-gray-500">Mes rendez-vous</button>
85
+ </div>
86
+
87
+ <!-- New Appointment Form -->
88
+ <div id="newAppointmentSection">
89
+ <div class="grid grid-cols-1 md:grid-cols-2 gap-6">
90
+ <div class="bg-white rounded-xl shadow-lg p-6 card-hover">
91
+ <h3 class="text-xl font-semibold mb-4 text-gray-800">Prendre un rendez-vous</h3>
92
+ <form id="appointmentForm" class="space-y-4">
93
+ <div>
94
+ <label class="block text-gray-700 mb-2">Laboratoire</label>
95
+ <select id="laboratorySelect" class="w-full px-4 py-2 border rounded-lg focus:outline-none focus:ring-2 focus:ring-indigo-300" required>
96
+ <option value="">Sélectionnez un laboratoire</option>
97
+ <option value="Labo Central Paris">Labo Central Paris</option>
98
+ <option value="BioTest Marseille">BioTest Marseille</option>
99
+ <option value="MediLab Lyon">MediLab Lyon</option>
100
+ <option value="AnalyseLab Bordeaux">AnalyseLab Bordeaux</option>
101
+ <option value="SangTest Lille">SangTest Lille</option>
102
+ </select>
103
+ </div>
104
+ <div>
105
+ <label class="block text-gray-700 mb-2">Date du rendez-vous</label>
106
+ <input type="date" id="appointmentDate" class="w-full px-4 py-2 border rounded-lg focus:outline-none focus:ring-2 focus:ring-indigo-300" required>
107
+ </div>
108
+ <div>
109
+ <label class="block text-gray-700 mb-2">Heure du rendez-vous</label>
110
+ <select id="appointmentTime" class="w-full px-4 py-2 border rounded-lg focus:outline-none focus:ring-2 focus:ring-indigo-300" required>
111
+ <option value="">Sélectionnez une heure</option>
112
+ <option value="08:00">08:00</option>
113
+ <option value="09:00">09:00</option>
114
+ <option value="10:00">10:00</option>
115
+ <option value="11:00">11:00</option>
116
+ <option value="14:00">14:00</option>
117
+ <option value="15:00">15:00</option>
118
+ <option value="16:00">16:00</option>
119
+ <option value="17:00">17:00</option>
120
+ </select>
121
+ </div>
122
+ <div>
123
+ <label class="block text-gray-700 mb-2">Type d'analyse</label>
124
+ <select id="analysisType" class="w-full px-4 py-2 border rounded-lg focus:outline-none focus:ring-2 focus:ring-indigo-300" required>
125
+ <option value="">Sélectionnez un type</option>
126
+ <option value="Hémogramme">Hémogramme</option>
127
+ <option value="Cholestérol">Cholestérol</option>
128
+ <option value="Glycémie">Glycémie</option>
129
+ <option value="Bilan thyroïdien">Bilan thyroïdien</option>
130
+ <option value="Vitamine D">Vitamine D</option>
131
+ <option value="Ferritine">Ferritine</option>
132
+ </select>
133
+ </div>
134
+ <button type="submit" class="w-full btn-primary text-white py-3 rounded-lg mt-4 pulse">
135
+ Prendre rendez-vous
136
+ </button>
137
+ </form>
138
+ </div>
139
+
140
+ <!-- Laboratory Info -->
141
+ <div class="bg-white rounded-xl shadow-lg p-6 card-hover">
142
+ <h3 class="text-xl font-semibold mb-4 text-gray-800">Nos laboratoires partenaires</h3>
143
+ <div class="space-y-4">
144
+ <div class="flex items-start space-x-3">
145
+ <div class="bg-indigo-100 p-2 rounded-lg">
146
+ <i data-feather="map-pin" class="text-indigo-600"></i>
147
+ </div>
148
+ <div>
149
+ <h4 class="font-medium text-gray-800">Labo Central Paris</h4>
150
+ <p class="text-sm text-gray-600">123 Rue de la Santé, 75013 Paris</p>
151
+ </div>
152
+ </div>
153
+ <div class="flex items-start space-x-3">
154
+ <div class="bg-indigo-100 p-2 rounded-lg">
155
+ <i data-feather="map-pin" class="text-indigo-600"></i>
156
+ </div>
157
+ <div>
158
+ <h4 class="font-medium text-gray-800">BioTest Marseille</h4>
159
+ <p class="text-sm text-gray-600">45 Avenue des Laboratoires, 13008 Marseille</p>
160
+ </div>
161
+ </div>
162
+ <div class="flex items-start space-x-3">
163
+ <div class="bg-indigo-100 p-2 rounded-lg">
164
+ <i data-feather="map-pin" class="text-indigo-600"></i>
165
+ </div>
166
+ <div>
167
+ <h4 class="font-medium text-gray-800">MediLab Lyon</h4>
168
+ <p class="text-sm text-gray-600">78 Boulevard des Sciences, 69003 Lyon</p>
169
+ </div>
170
+ </div>
171
+ </div>
172
+
173
+ <div class="mt-6 pt-4 border-t">
174
+ <h4 class="font-semibold text-gray-800 mb-2">Pourquoi choisir nos laboratoires ?</h4>
175
+ <ul class="text-sm text-gray-600 space-y-1">
176
+ <li class="flex items-center">
177
+ <i data-feather="check-circle" class="text-green-500 mr-2 w-4 h-4"></i>
178
+ Résultats sous 24h
179
+ </li>
180
+ <li class="flex items-center">
181
+ <i data-feather="check-circle" class="text-green-500 mr-2 w-4 h-4"></i>
182
+ Personnel qualifié
183
+ </li>
184
+ <li class="flex items-center">
185
+ <i data-feather="check-circle" class="text-green-500 mr-2 w-4 h-4"></i>
186
+ Équipements modernes
187
+ </li>
188
+ </ul>
189
+ </div>
190
+ </div>
191
+ </div>
192
+ </div>
193
+
194
+ <!-- My Appointments Section -->
195
+ <div id="myAppointmentsSection" class="hidden">
196
+ <div class="bg-white rounded-xl shadow-lg p-6">
197
+ <h3 class="text-xl font-semibold mb-4 text-gray-800">Mes rendez-vous</h3>
198
+ <div id="appointmentsList" class="space-y-4">
199
+ <!-- Appointments will be dynamically added here -->
200
+ <div class="text-center py-12 hidden" id="noAppointmentsMessage">
201
+ <i data-feather="calendar" class="w-16 h-16 text-gray-300 mx-auto mb-4"></i>
202
+ <p class="text-gray-500">Vous n'avez pas encore de rendez-vous</p>
203
+ <button id="bookFirstAppointment" class="mt-4 text-indigo-600 font-medium">Prendre votre premier rendez-vous</button>
204
+ </div>
205
+ </div>
206
+ </div>
207
+ </div>
208
+ </main>
209
+
210
+ <!-- Notification -->
211
+ <div id="notification" class="fixed top-4 right-4 bg-white shadow-lg rounded-lg p-4 border-l-4 border-green-500 hidden z-50">
212
+ <div class="flex items-start">
213
+ <i data-feather="check-circle" class="text-green-500 mr-2 mt-1"></i>
214
+ <div>
215
+ <h4 class="font-medium text-gray-800">Succès</h4>
216
+ <p class="text-sm text-gray-600" id="notificationMessage"></p>
217
+ </div>
218
+ </div>
219
+ </div>
220
+
221
+ <script>
222
+ // Initialize Feather Icons
223
+ feather.replace();
224
+
225
+ // DOM Elements
226
+ const logoutBtn = document.getElementById('logoutBtn');
227
+ const appointmentForm = document.getElementById('appointmentForm');
228
+ const tabNewAppointment = document.getElementById('tabNewAppointment');
229
+ const tabMyAppointments = document.getElementById('tabMyAppointments');
230
+ const newAppointmentSection = document.getElementById('newAppointmentSection');
231
+ const myAppointmentsSection = document.getElementById('myAppointmentsSection');
232
+ const appointmentsList = document.getElementById('appointmentsList');
233
+ const noAppointmentsMessage = document.getElementById('noAppointmentsMessage');
234
+ const bookFirstAppointment = document.getElementById('bookFirstAppointment');
235
+ const notification = document.getElementById('notification');
236
+ const notificationMessage = document.getElementById('notificationMessage');
237
+ const userName = document.getElementById('userName');
238
+
239
+ // State
240
+ let currentUser = JSON.parse(localStorage.getItem('currentUser'));
241
+ let appointments = JSON.parse(localStorage.getItem('appointments')) || [];
242
+
243
+ // Check if user is logged in
244
+ if (!currentUser) {
245
+ window.location.href = 'login.html';
246
+ }
247
+
248
+ // Set user name
249
+ userName.textContent = currentUser.name;
250
+
251
+ // Show notification
252
+ function showNotification(message) {
253
+ notificationMessage.textContent = message;
254
+ notification.classList.remove('hidden');
255
+
256
+ setTimeout(() => {
257
+ notification.classList.add('hidden');
258
+ }, 3000);
259
+ }
260
+
261
+ // Switch tabs
262
+ tabNewAppointment.addEventListener('click', () => {
263
+ newAppointmentSection.classList.remove('hidden');
264
+ myAppointmentsSection.classList.add('hidden');
265
+ tabNewAppointment.classList.add('active-tab', 'text-gray-800');
266
+ tabNewAppointment.classList.remove('text-gray-500');
267
+ tabMyAppointments.classList.remove('active-tab', 'text-gray-800');
268
+ tabMyAppointments.classList.add('text-gray-500');
269
+ });
270
+
271
+ tabMyAppointments.addEventListener('click', () => {
272
+ newAppointmentSection.classList.add('hidden');
273
+ myAppointmentsSection.classList.remove('hidden');
274
+ tabMyAppointments.classList.add('active-tab', 'text-gray-800');
275
+ tabMyAppointments.classList.remove('text-gray-500');
276
+ tabNewAppointment.classList.remove('active-tab', 'text-gray-800');
277
+ tabNewAppointment.classList.add('text-gray-500');
278
+ renderAppointments();
279
+ });
280
+
281
+ // Book first appointment button
282
+ bookFirstAppointment.addEventListener('click', () => {
283
+ tabNewAppointment.click();
284
+ });
285
+
286
+ // Logout
287
+ logoutBtn.addEventListener('click', () => {
288
+ localStorage.removeItem('currentUser');
289
+ window.location.href = 'login.html';
290
+ });
291
+
292
+ // Appointment form submission
293
+ appointmentForm.addEventListener('submit', (e) => {
294
+ e.preventDefault();
295
+ if (!currentUser) return;
296
+
297
+ const laboratory = document.getElementById('laboratorySelect').value;
298
+ const date = document.getElementById('appointmentDate').value;
299
+ const time = document.getElementById('appointmentTime').value;
300
+ const analysis = document.getElementById('analysisType').value;
301
+
302
+ const appointment = {
303
+ id: Date.now(),
304
+ userId: currentUser.email,
305
+ laboratory,
306
+ date,
307
+ time,
308
+ analysis,
309
+ status: 'confirmé'
310
+ };
311
+
312
+ appointments.push(appointment);
313
+ localStorage.setItem('appointments', JSON.stringify(appointments));
314
+
315
+ showNotification('Rendez-vous pris avec succès !');
316
+ appointmentForm.reset();
317
+ renderAppointments();
318
+ });
319
+
320
+ // Render appointments
321
+ function renderAppointments() {
322
+ if (!currentUser) return;
323
+
324
+ const userAppointments = appointments.filter(a => a.userId === currentUser.email);
325
+
326
+ if (userAppointments.length === 0) {
327
+ noAppointmentsMessage.classList.remove('hidden');
328
+ appointmentsList.innerHTML = '';
329
+ appointmentsList.appendChild(noAppointmentsMessage);
330
+ return;
331
+ }
332
+
333
+ noAppointmentsMessage.classList.add('hidden');
334
+ appointmentsList.innerHTML = '';
335
+
336
+ userAppointments.forEach(appointment => {
337
+ const appointmentEl = document.createElement('div');
338
+ appointmentEl.className = 'border rounded-lg p-4 flex flex-col sm:flex-row justify-between items-start sm:items-center gap-4 appointment-card';
339
+
340
+ const dateObj = new Date(appointment.date);
341
+ const formattedDate = dateObj.toLocaleDateString('fr-FR', {
342
+ weekday: 'long',
343
+ day: 'numeric',
344
+ month: 'long'
345
+ });
346
+
347
+ appointmentEl.innerHTML = `
348
+ <div class="flex items-start space-x-3">
349
+ <div class="bg-indigo-100 p-2 rounded-lg">
350
+ <i data-feather="calendar" class="text-indigo-600"></i>
351
+ </div>
352
+ <div>
353
+ <h4 class="font-medium text-gray-800">${appointment.analysis}</h4>
354
+ <p class="text-sm text-gray-600">${formattedDate} à ${appointment.time}</p>
355
+ <p class="text-sm text-gray-600">${appointment.laboratory}</p>
356
+ </div>
357
+ </div>
358
+ <div class="flex items-center space-x-2">
359
+ <span class="px-3 py-1 bg-green-100 text-green-800 rounded-full text-sm font-medium">Confirmé</span>
360
+ <button onclick="cancelAppointment(${appointment.id})" class="text-red-500 hover:text-red-700">
361
+ <i data-feather="x-circle"></i>
362
+ </button>
363
+ </div>
364
+ `;
365
+
366
+ appointmentsList.appendChild(appointmentEl);
367
+ });
368
+
369
+ feather.replace();
370
+ }
371
+
372
+ // Cancel appointment
373
+ window.cancelAppointment = function(id) {
374
+ if (confirm('Êtes-vous sûr de vouloir annuler ce rendez-vous ?')) {
375
+ appointments = appointments.filter(a => a.id !== id);
376
+ localStorage.setItem('appointments', JSON.stringify(appointments));
377
+ renderAppointments();
378
+ showNotification('Rendez-vous annulé');
379
+ }
380
+ };
381
+
382
+ // Set minimum date for appointment
383
+ function setMinDate() {
384
+ const today = new Date();
385
+ const formattedDate = today.toISOString().split('T')[0];
386
+ document.getElementById('appointmentDate').min = formattedDate;
387
+ }
388
+
389
+ // Initialize
390
+ document.addEventListener('DOMContentLoaded', () => {
391
+ setMinDate();
392
+ renderAppointments();
393
+ });
394
+ </script>
395
+ </body>
396
+ </html>
index.html CHANGED
@@ -1,19 +1,545 @@
1
- <!doctype html>
2
- <html>
3
- <head>
4
- <meta charset="utf-8" />
5
- <meta name="viewport" content="width=device-width" />
6
- <title>My static Space</title>
7
- <link rel="stylesheet" href="style.css" />
8
- </head>
9
- <body>
10
- <div class="card">
11
- <h1>Welcome to your static Space!</h1>
12
- <p>You can modify this app directly by editing <i>index.html</i> in the Files and versions tab.</p>
13
- <p>
14
- Also don't forget to check the
15
- <a href="https://huggingface.co/docs/hub/spaces" target="_blank">Spaces documentation</a>.
16
- </p>
17
- </div>
18
- </body>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
19
  </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>LaboConnect - Prise de sang en ligne</title>
7
+ <link rel="icon" type="image/x-icon" href="data:image/svg+xml,<svg xmlns=%22http://www.w3.org/2000/svg%22 viewBox=%220 0 100 100%22><text y=%22.9em%22 font-size=%2290%22>💉</text></svg>">
8
+ <script src="https://cdn.tailwindcss.com"></script>
9
+ <link href="https://fonts.googleapis.com/css2?family=Poppins:wght@300;400;500;600;700&display=swap" rel="stylesheet">
10
+ <script src="https://unpkg.com/feather-icons"></script>
11
+ <script src="https://cdn.jsdelivr.net/npm/[email protected]/lib/anime.min.js"></script>
12
+ <style>
13
+ body {
14
+ font-family: 'Poppins', sans-serif;
15
+ background: linear-gradient(135deg, #f0f9ff 0%, #e6f7ff 100%);
16
+ }
17
+ .card-hover {
18
+ transition: all 0.3s ease;
19
+ }
20
+ .card-hover:hover {
21
+ transform: translateY(-5px);
22
+ box-shadow: 0 20px 25px -5px rgba(0, 0, 0, 0.1), 0 10px 10px -5px rgba(0, 0, 0, 0.04);
23
+ }
24
+ .btn-primary {
25
+ background: linear-gradient(90deg, #4f46e5 0%, #7c3aed 100%);
26
+ transition: all 0.3s ease;
27
+ }
28
+ .btn-primary:hover {
29
+ background: linear-gradient(90deg, #4338ca 0%, #6d28d9 100%);
30
+ transform: scale(1.05);
31
+ }
32
+ .active-tab {
33
+ border-bottom: 3px solid #4f46e5;
34
+ color: #4f46e5;
35
+ font-weight: 600;
36
+ }
37
+ .appointment-card {
38
+ animation: fadeIn 0.5s ease-in-out;
39
+ }
40
+ @keyframes fadeIn {
41
+ from { opacity: 0; transform: translateY(20px); }
42
+ to { opacity: 1; transform: translateY(0); }
43
+ }
44
+ .pulse {
45
+ animation: pulse 2s infinite;
46
+ }
47
+ @keyframes pulse {
48
+ 0% { box-shadow: 0 0 0 0 rgba(79, 70, 229, 0.4); }
49
+ 70% { box-shadow: 0 0 0 10px rgba(79, 70, 229, 0); }
50
+ 100% { box-shadow: 0 0 0 0 rgba(79, 70, 229, 0); }
51
+ }
52
+ </style>
53
+ </head>
54
+ <body class="min-h-screen">
55
+ <!-- Header -->
56
+ <header class="bg-white shadow-sm">
57
+ <div class="container mx-auto px-4 py-4 flex justify-between items-center">
58
+ <div class="flex items-center space-x-2">
59
+ <div class="w-10 h-10 rounded-full bg-indigo-100 flex items-center justify-center">
60
+ <i data-feather="droplet" class="text-indigo-600"></i>
61
+ </div>
62
+ <h1 class="text-2xl font-bold text-gray-800">LaboConnect</h1>
63
+ </div>
64
+ <div id="authSection" class="flex items-center space-x-4">
65
+ <button id="loginBtn" class="text-indigo-600 font-medium hover:text-indigo-800">Connexion</button>
66
+ <button id="registerBtn" class="bg-indigo-600 text-white px-4 py-2 rounded-lg hover:bg-indigo-700 transition">Inscription</button>
67
+ </div>
68
+ <div id="userSection" class="hidden items-center space-x-4">
69
+ <span id="userName" class="text-gray-700 font-medium"></span>
70
+ <button id="logoutBtn" class="text-gray-500 hover:text-gray-700">
71
+ <i data-feather="log-out"></i>
72
+ </button>
73
+ </div>
74
+ </div>
75
+ </header>
76
+
77
+ <!-- Main Content -->
78
+ <main class="container mx-auto px-4 py-8">
79
+ <!-- Auth Forms -->
80
+ <div id="authForms" class="max-w-md mx-auto hidden">
81
+ <div class="bg-white rounded-xl shadow-lg p-6 card-hover">
82
+ <div class="flex border-b mb-4">
83
+ <button id="showLogin" class="pb-2 px-4 active-tab">Connexion</button>
84
+ <button id="showRegister" class="pb-2 px-4 text-gray-500">Inscription</button>
85
+ </div>
86
+
87
+ <!-- Login Form -->
88
+ <form id="loginForm" class="space-y-4">
89
+ <div>
90
+ <label class="block text-gray-700 mb-2">Email</label>
91
+ <input type="email" id="loginEmail" class="w-full px-4 py-2 border rounded-lg focus:outline-none focus:ring-2 focus:ring-indigo-300" required>
92
+ </div>
93
+ <div>
94
+ <label class="block text-gray-700 mb-2">Mot de passe</label>
95
+ <input type="password" id="loginPassword" class="w-full px-4 py-2 border rounded-lg focus:outline-none focus:ring-2 focus:ring-indigo-300" required>
96
+ </div>
97
+ <button type="submit" class="w-full btn-primary text-white py-2 rounded-lg">Se connecter</button>
98
+ </form>
99
+
100
+ <!-- Register Form -->
101
+ <form id="registerForm" class="space-y-4 hidden">
102
+ <div>
103
+ <label class="block text-gray-700 mb-2">Nom complet</label>
104
+ <input type="text" id="registerName" class="w-full px-4 py-2 border rounded-lg focus:outline-none focus:ring-2 focus:ring-indigo-300" required>
105
+ </div>
106
+ <div>
107
+ <label class="block text-gray-700 mb-2">Email</label>
108
+ <input type="email" id="registerEmail" class="w-full px-4 py-2 border rounded-lg focus:outline-none focus:ring-2 focus:ring-indigo-300" required>
109
+ </div>
110
+ <div>
111
+ <label class="block text-gray-700 mb-2">Mot de passe</label>
112
+ <input type="password" id="registerPassword" class="w-full px-4 py-2 border rounded-lg focus:outline-none focus:ring-2 focus:ring-indigo-300" required>
113
+ </div>
114
+ <button type="submit" class="w-full btn-primary text-white py-2 rounded-lg">S'inscrire</button>
115
+ </form>
116
+ </div>
117
+ </div>
118
+
119
+ <!-- Dashboard -->
120
+ <div id="dashboard" class="hidden">
121
+ <!-- Welcome Banner -->
122
+ <div class="bg-gradient-to-r from-indigo-500 to-purple-600 rounded-2xl p-6 text-white mb-8">
123
+ <h2 class="text-2xl font-bold mb-2">Bienvenue sur LaboConnect</h2>
124
+ <p class="opacity-90">Planifiez vos prises de sang en quelques clics</p>
125
+ </div>
126
+
127
+ <!-- Navigation Tabs -->
128
+ <div class="flex border-b mb-6">
129
+ <button id="tabNewAppointment" class="pb-3 px-6 active-tab">Nouveau rendez-vous</button>
130
+ <button id="tabMyAppointments" class="pb-3 px-6 text-gray-500">Mes rendez-vous</button>
131
+ </div>
132
+
133
+ <!-- New Appointment Form -->
134
+ <div id="newAppointmentSection">
135
+ <div class="grid grid-cols-1 md:grid-cols-2 gap-6">
136
+ <div class="bg-white rounded-xl shadow-lg p-6 card-hover">
137
+ <h3 class="text-xl font-semibold mb-4 text-gray-800">Prendre un rendez-vous</h3>
138
+ <form id="appointmentForm" class="space-y-4">
139
+ <div>
140
+ <label class="block text-gray-700 mb-2">Laboratoire</label>
141
+ <select id="laboratorySelect" class="w-full px-4 py-2 border rounded-lg focus:outline-none focus:ring-2 focus:ring-indigo-300" required>
142
+ <option value="">Sélectionnez un laboratoire</option>
143
+ <option value="Labo Central Paris">Labo Central Paris</option>
144
+ <option value="BioTest Marseille">BioTest Marseille</option>
145
+ <option value="MediLab Lyon">MediLab Lyon</option>
146
+ <option value="AnalyseLab Bordeaux">AnalyseLab Bordeaux</option>
147
+ <option value="SangTest Lille">SangTest Lille</option>
148
+ </select>
149
+ </div>
150
+ <div>
151
+ <label class="block text-gray-700 mb-2">Date du rendez-vous</label>
152
+ <input type="date" id="appointmentDate" class="w-full px-4 py-2 border rounded-lg focus:outline-none focus:ring-2 focus:ring-indigo-300" required>
153
+ </div>
154
+ <div>
155
+ <label class="block text-gray-700 mb-2">Heure du rendez-vous</label>
156
+ <select id="appointmentTime" class="w-full px-4 py-2 border rounded-lg focus:outline-none focus:ring-2 focus:ring-indigo-300" required>
157
+ <option value="">Sélectionnez une heure</option>
158
+ <option value="08:00">08:00</option>
159
+ <option value="09:00">09:00</option>
160
+ <option value="10:00">10:00</option>
161
+ <option value="11:00">11:00</option>
162
+ <option value="14:00">14:00</option>
163
+ <option value="15:00">15:00</option>
164
+ <option value="16:00">16:00</option>
165
+ <option value="17:00">17:00</option>
166
+ </select>
167
+ </div>
168
+ <div>
169
+ <label class="block text-gray-700 mb-2">Type d'analyse</label>
170
+ <select id="analysisType" class="w-full px-4 py-2 border rounded-lg focus:outline-none focus:ring-2 focus:ring-indigo-300" required>
171
+ <option value="">Sélectionnez un type</option>
172
+ <option value="Hémogramme">Hémogramme</option>
173
+ <option value="Cholestérol">Cholestérol</option>
174
+ <option value="Glycémie">Glycémie</option>
175
+ <option value="Bilan thyroïdien">Bilan thyroïdien</option>
176
+ <option value="Vitamine D">Vitamine D</option>
177
+ <option value="Ferritine">Ferritine</option>
178
+ </select>
179
+ </div>
180
+ <button type="submit" class="w-full btn-primary text-white py-3 rounded-lg mt-4 pulse">
181
+ Prendre rendez-vous
182
+ </button>
183
+ </form>
184
+ </div>
185
+
186
+ <!-- Laboratory Info -->
187
+ <div class="bg-white rounded-xl shadow-lg p-6 card-hover">
188
+ <h3 class="text-xl font-semibold mb-4 text-gray-800">Nos laboratoires partenaires</h3>
189
+ <div class="space-y-4">
190
+ <div class="flex items-start space-x-3">
191
+ <div class="bg-indigo-100 p-2 rounded-lg">
192
+ <i data-feather="map-pin" class="text-indigo-600"></i>
193
+ </div>
194
+ <div>
195
+ <h4 class="font-medium text-gray-800">Labo Central Paris</h4>
196
+ <p class="text-sm text-gray-600">123 Rue de la Santé, 75013 Paris</p>
197
+ </div>
198
+ </div>
199
+ <div class="flex items-start space-x-3">
200
+ <div class="bg-indigo-100 p-2 rounded-lg">
201
+ <i data-feather="map-pin" class="text-indigo-600"></i>
202
+ </div>
203
+ <div>
204
+ <h4 class="font-medium text-gray-800">BioTest Marseille</h4>
205
+ <p class="text-sm text-gray-600">45 Avenue des Laboratoires, 13008 Marseille</p>
206
+ </div>
207
+ </div>
208
+ <div class="flex items-start space-x-3">
209
+ <div class="bg-indigo-100 p-2 rounded-lg">
210
+ <i data-feather="map-pin" class="text-indigo-600"></i>
211
+ </div>
212
+ <div>
213
+ <h4 class="font-medium text-gray-800">MediLab Lyon</h4>
214
+ <p class="text-sm text-gray-600">78 Boulevard des Sciences, 69003 Lyon</p>
215
+ </div>
216
+ </div>
217
+ </div>
218
+
219
+ <div class="mt-6 pt-4 border-t">
220
+ <h4 class="font-semibold text-gray-800 mb-2">Pourquoi choisir nos laboratoires ?</h4>
221
+ <ul class="text-sm text-gray-600 space-y-1">
222
+ <li class="flex items-center">
223
+ <i data-feather="check-circle" class="text-green-500 mr-2 w-4 h-4"></i>
224
+ Résultats sous 24h
225
+ </li>
226
+ <li class="flex items-center">
227
+ <i data-feather="check-circle" class="text-green-500 mr-2 w-4 h-4"></i>
228
+ Personnel qualifié
229
+ </li>
230
+ <li class="flex items-center">
231
+ <i data-feather="check-circle" class="text-green-500 mr-2 w-4 h-4"></i>
232
+ Équipements modernes
233
+ </li>
234
+ </ul>
235
+ </div>
236
+ </div>
237
+ </div>
238
+ </div>
239
+
240
+ <!-- My Appointments Section -->
241
+ <div id="myAppointmentsSection" class="hidden">
242
+ <div class="bg-white rounded-xl shadow-lg p-6">
243
+ <h3 class="text-xl font-semibold mb-4 text-gray-800">Mes rendez-vous</h3>
244
+ <div id="appointmentsList" class="space-y-4">
245
+ <!-- Appointments will be dynamically added here -->
246
+ <div class="text-center py-12 hidden" id="noAppointmentsMessage">
247
+ <i data-feather="calendar" class="w-16 h-16 text-gray-300 mx-auto mb-4"></i>
248
+ <p class="text-gray-500">Vous n'avez pas encore de rendez-vous</p>
249
+ <button id="bookFirstAppointment" class="mt-4 text-indigo-600 font-medium">Prendre votre premier rendez-vous</button>
250
+ </div>
251
+ </div>
252
+ </div>
253
+ </div>
254
+ </div>
255
+ </main>
256
+
257
+ <!-- Notification -->
258
+ <div id="notification" class="fixed top-4 right-4 bg-white shadow-lg rounded-lg p-4 border-l-4 border-green-500 hidden z-50">
259
+ <div class="flex items-start">
260
+ <i data-feather="check-circle" class="text-green-500 mr-2 mt-1"></i>
261
+ <div>
262
+ <h4 class="font-medium text-gray-800">Succès</h4>
263
+ <p class="text-sm text-gray-600" id="notificationMessage"></p>
264
+ </div>
265
+ </div>
266
+ </div>
267
+
268
+ <script>
269
+ // Initialize Feather Icons
270
+ feather.replace();
271
+
272
+ // DOM Elements
273
+ const authForms = document.getElementById('authForms');
274
+ const dashboard = document.getElementById('dashboard');
275
+ const loginBtn = document.getElementById('loginBtn');
276
+ const registerBtn = document.getElementById('registerBtn');
277
+ const logoutBtn = document.getElementById('logoutBtn');
278
+ const showLogin = document.getElementById('showLogin');
279
+ const showRegister = document.getElementById('showRegister');
280
+ const loginForm = document.getElementById('loginForm');
281
+ const registerForm = document.getElementById('registerForm');
282
+ const appointmentForm = document.getElementById('appointmentForm');
283
+ const tabNewAppointment = document.getElementById('tabNewAppointment');
284
+ const tabMyAppointments = document.getElementById('tabMyAppointments');
285
+ const newAppointmentSection = document.getElementById('newAppointmentSection');
286
+ const myAppointmentsSection = document.getElementById('myAppointmentsSection');
287
+ const appointmentsList = document.getElementById('appointmentsList');
288
+ const noAppointmentsMessage = document.getElementById('noAppointmentsMessage');
289
+ const bookFirstAppointment = document.getElementById('bookFirstAppointment');
290
+ const notification = document.getElementById('notification');
291
+ const notificationMessage = document.getElementById('notificationMessage');
292
+ const authSection = document.getElementById('authSection');
293
+ const userSection = document.getElementById('userSection');
294
+ const userName = document.getElementById('userName');
295
+
296
+ // State
297
+ let currentUser = null;
298
+ let appointments = JSON.parse(localStorage.getItem('appointments')) || [];
299
+
300
+ // Show notification
301
+ function showNotification(message) {
302
+ notificationMessage.textContent = message;
303
+ notification.classList.remove('hidden');
304
+
305
+ setTimeout(() => {
306
+ notification.classList.add('hidden');
307
+ }, 3000);
308
+ }
309
+
310
+ // Switch between login and register forms
311
+ showLogin.addEventListener('click', () => {
312
+ loginForm.classList.remove('hidden');
313
+ registerForm.classList.add('hidden');
314
+ showLogin.classList.add('active-tab', 'text-gray-800');
315
+ showLogin.classList.remove('text-gray-500');
316
+ showRegister.classList.remove('active-tab', 'text-gray-800');
317
+ showRegister.classList.add('text-gray-500');
318
+ });
319
+
320
+ showRegister.addEventListener('click', () => {
321
+ registerForm.classList.remove('hidden');
322
+ loginForm.classList.add('hidden');
323
+ showRegister.classList.add('active-tab', 'text-gray-800');
324
+ showRegister.classList.remove('text-gray-500');
325
+ showLogin.classList.remove('active-tab', 'text-gray-800');
326
+ showLogin.classList.add('text-gray-500');
327
+ });
328
+
329
+ // Switch tabs
330
+ tabNewAppointment.addEventListener('click', () => {
331
+ newAppointmentSection.classList.remove('hidden');
332
+ myAppointmentsSection.classList.add('hidden');
333
+ tabNewAppointment.classList.add('active-tab', 'text-gray-800');
334
+ tabNewAppointment.classList.remove('text-gray-500');
335
+ tabMyAppointments.classList.remove('active-tab', 'text-gray-800');
336
+ tabMyAppointments.classList.add('text-gray-500');
337
+ });
338
+
339
+ tabMyAppointments.addEventListener('click', () => {
340
+ newAppointmentSection.classList.add('hidden');
341
+ myAppointmentsSection.classList.remove('hidden');
342
+ tabMyAppointments.classList.add('active-tab', 'text-gray-800');
343
+ tabMyAppointments.classList.remove('text-gray-500');
344
+ tabNewAppointment.classList.remove('active-tab', 'text-gray-800');
345
+ tabNewAppointment.classList.add('text-gray-500');
346
+ renderAppointments();
347
+ });
348
+
349
+ // Book first appointment button
350
+ bookFirstAppointment.addEventListener('click', () => {
351
+ tabNewAppointment.click();
352
+ });
353
+
354
+ // User authentication
355
+ loginBtn.addEventListener('click', () => {
356
+ authForms.classList.remove('hidden');
357
+ showLogin.click();
358
+ });
359
+
360
+ registerBtn.addEventListener('click', () => {
361
+ authForms.classList.remove('hidden');
362
+ showRegister.click();
363
+ });
364
+
365
+ logoutBtn.addEventListener('click', () => {
366
+ currentUser = null;
367
+ localStorage.removeItem('currentUser');
368
+ authSection.classList.remove('hidden');
369
+ userSection.classList.add('hidden');
370
+ dashboard.classList.add('hidden');
371
+ authForms.classList.remove('hidden');
372
+ showNotification('Vous avez été déconnecté');
373
+ });
374
+
375
+ // Login form submission
376
+ loginForm.addEventListener('submit', (e) => {
377
+ e.preventDefault();
378
+ const email = document.getElementById('loginEmail').value;
379
+ const password = document.getElementById('loginPassword').value;
380
+
381
+ // Mock authentication
382
+ const users = JSON.parse(localStorage.getItem('users')) || [];
383
+ const user = users.find(u => u.email === email && u.password === password);
384
+
385
+ if (user) {
386
+ currentUser = user;
387
+ localStorage.setItem('currentUser', JSON.stringify(user));
388
+ showDashboard();
389
+ showNotification('Connexion réussie !');
390
+ } else {
391
+ showNotification('Identifiants incorrects');
392
+ }
393
+ });
394
+
395
+ // Register form submission
396
+ registerForm.addEventListener('submit', (e) => {
397
+ e.preventDefault();
398
+ const name = document.getElementById('registerName').value;
399
+ const email = document.getElementById('registerEmail').value;
400
+ const password = document.getElementById('registerPassword').value;
401
+
402
+ // Check if user already exists
403
+ const users = JSON.parse(localStorage.getItem('users')) || [];
404
+ if (users.some(u => u.email === email)) {
405
+ showNotification('Cet email est déjà utilisé');
406
+ return;
407
+ }
408
+
409
+ // Create new user
410
+ const newUser = { name, email, password };
411
+ users.push(newUser);
412
+ localStorage.setItem('users', JSON.stringify(users));
413
+
414
+ currentUser = newUser;
415
+ localStorage.setItem('currentUser', JSON.stringify(newUser));
416
+ showDashboard();
417
+ showNotification('Inscription réussie ! Bienvenue sur LaboConnect');
418
+ });
419
+
420
+ // Appointment form submission
421
+ appointmentForm.addEventListener('submit', (e) => {
422
+ e.preventDefault();
423
+ if (!currentUser) return;
424
+
425
+ const laboratory = document.getElementById('laboratorySelect').value;
426
+ const date = document.getElementById('appointmentDate').value;
427
+ const time = document.getElementById('appointmentTime').value;
428
+ const analysis = document.getElementById('analysisType').value;
429
+
430
+ const appointment = {
431
+ id: Date.now(),
432
+ userId: currentUser.email,
433
+ laboratory,
434
+ date,
435
+ time,
436
+ analysis,
437
+ status: 'confirmé'
438
+ };
439
+
440
+ appointments.push(appointment);
441
+ localStorage.setItem('appointments', JSON.stringify(appointments));
442
+
443
+ showNotification('Rendez-vous pris avec succès !');
444
+ appointmentForm.reset();
445
+ renderAppointments();
446
+ });
447
+
448
+ // Render appointments
449
+ function renderAppointments() {
450
+ if (!currentUser) return;
451
+
452
+ const userAppointments = appointments.filter(a => a.userId === currentUser.email);
453
+
454
+ if (userAppointments.length === 0) {
455
+ noAppointmentsMessage.classList.remove('hidden');
456
+ appointmentsList.innerHTML = '';
457
+ appointmentsList.appendChild(noAppointmentsMessage);
458
+ return;
459
+ }
460
+
461
+ noAppointmentsMessage.classList.add('hidden');
462
+ appointmentsList.innerHTML = '';
463
+
464
+ userAppointments.forEach(appointment => {
465
+ const appointmentEl = document.createElement('div');
466
+ appointmentEl.className = 'border rounded-lg p-4 flex flex-col sm:flex-row justify-between items-start sm:items-center gap-4 appointment-card';
467
+
468
+ const dateObj = new Date(appointment.date);
469
+ const formattedDate = dateObj.toLocaleDateString('fr-FR', {
470
+ weekday: 'long',
471
+ day: 'numeric',
472
+ month: 'long'
473
+ });
474
+
475
+ appointmentEl.innerHTML = `
476
+ <div class="flex items-start space-x-3">
477
+ <div class="bg-indigo-100 p-2 rounded-lg">
478
+ <i data-feather="calendar" class="text-indigo-600"></i>
479
+ </div>
480
+ <div>
481
+ <h4 class="font-medium text-gray-800">${appointment.analysis}</h4>
482
+ <p class="text-sm text-gray-600">${formattedDate} à ${appointment.time}</p>
483
+ <p class="text-sm text-gray-600">${appointment.laboratory}</p>
484
+ </div>
485
+ </div>
486
+ <div class="flex items-center space-x-2">
487
+ <span class="px-3 py-1 bg-green-100 text-green-800 rounded-full text-sm font-medium">Confirmé</span>
488
+ <button onclick="cancelAppointment(${appointment.id})" class="text-red-500 hover:text-red-700">
489
+ <i data-feather="x-circle"></i>
490
+ </button>
491
+ </div>
492
+ `;
493
+
494
+ appointmentsList.appendChild(appointmentEl);
495
+ });
496
+
497
+ feather.replace();
498
+ }
499
+
500
+ // Cancel appointment
501
+ window.cancelAppointment = function(id) {
502
+ if (confirm('Êtes-vous sûr de vouloir annuler ce rendez-vous ?')) {
503
+ appointments = appointments.filter(a => a.id !== id);
504
+ localStorage.setItem('appointments', JSON.stringify(appointments));
505
+ renderAppointments();
506
+ showNotification('Rendez-vous annulé');
507
+ }
508
+ };
509
+
510
+ // Show dashboard
511
+ function showDashboard() {
512
+ authForms.classList.add('hidden');
513
+ dashboard.classList.remove('hidden');
514
+ authSection.classList.add('hidden');
515
+ userSection.classList.remove('hidden');
516
+ userName.textContent = currentUser.name;
517
+ renderAppointments();
518
+ }
519
+
520
+ // Check if user is already logged in
521
+ function checkAuthStatus() {
522
+ const storedUser = localStorage.getItem('currentUser');
523
+ if (storedUser) {
524
+ currentUser = JSON.parse(storedUser);
525
+ showDashboard();
526
+ } else {
527
+ authForms.classList.remove('hidden');
528
+ }
529
+ }
530
+
531
+ // Set minimum date for appointment
532
+ function setMinDate() {
533
+ const today = new Date();
534
+ const formattedDate = today.toISOString().split('T')[0];
535
+ document.getElementById('appointmentDate').min = formattedDate;
536
+ }
537
+
538
+ // Initialize
539
+ document.addEventListener('DOMContentLoaded', () => {
540
+ checkAuthStatus();
541
+ setMinDate();
542
+ });
543
+ </script>
544
+ </body>
545
  </html>
login.html ADDED
@@ -0,0 +1,90 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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>Connexion - LaboConnect</title>
7
+ <link rel="icon" type="image/x-icon" href="data:image/svg+xml,<svg xmlns=%22http://www.w3.org/2000/svg%22 viewBox=%220 0 100 100%22><text y=%22.9em%22 font-size=%2290%22>💉</text></svg>">
8
+ <script src="https://cdn.tailwindcss.com"></script>
9
+ <link href="https://fonts.googleapis.com/css2?family=Poppins:wght@300;400;500;600;700&display=swap" rel="stylesheet">
10
+ <script src="https://unpkg.com/feather-icons"></script>
11
+ <style>
12
+ body {
13
+ font-family: 'Poppins', sans-serif;
14
+ background: linear-gradient(135deg, #f0f9ff 0%, #e6f7ff 100%);
15
+ }
16
+ .btn-primary {
17
+ background: linear-gradient(90deg, #4f46e5 0%, #7c3aed 100%);
18
+ transition: all 0.3s ease;
19
+ }
20
+ .btn-primary:hover {
21
+ background: linear-gradient(90deg, #4338ca 0%, #6d28d9 100%);
22
+ transform: scale(1.05);
23
+ }
24
+ </style>
25
+ </head>
26
+ <body class="min-h-screen flex items-center justify-center p-4">
27
+ <div class="w-full max-w-md">
28
+ <div class="bg-white rounded-2xl shadow-xl p-8">
29
+ <div class="text-center mb-8">
30
+ <div class="mx-auto w-16 h-16 rounded-full bg-indigo-100 flex items-center justify-center mb-4">
31
+ <i data-feather="log-in" class="text-indigo-600 w-8 h-8"></i>
32
+ </div>
33
+ <h1 class="text-2xl font-bold text-gray-800">Connexion</h1>
34
+ <p class="text-gray-600 mt-2">Accédez à votre compte LaboConnect</p>
35
+ </div>
36
+
37
+ <form id="loginForm" class="space-y-6">
38
+ <div>
39
+ <label class="block text-gray-700 mb-2">Email</label>
40
+ <input type="email" id="loginEmail" class="w-full px-4 py-3 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-indigo-300 focus:border-transparent" required>
41
+ </div>
42
+
43
+ <div>
44
+ <label class="block text-gray-700 mb-2">Mot de passe</label>
45
+ <input type="password" id="loginPassword" class="w-full px-4 py-3 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-indigo-300 focus:border-transparent" required>
46
+ </div>
47
+
48
+ <div class="flex items-center justify-between">
49
+ <div class="flex items-center">
50
+ <input id="rememberMe" type="checkbox" class="h-4 w-4 text-indigo-600 focus:ring-indigo-500 border-gray-300 rounded">
51
+ <label for="rememberMe" class="ml-2 block text-sm text-gray-700">Se souvenir de moi</label>
52
+ </div>
53
+ <a href="#" class="text-sm text-indigo-600 hover:text-indigo-800">Mot de passe oublié?</a>
54
+ </div>
55
+
56
+ <button type="submit" class="w-full btn-primary text-white py-3 rounded-lg font-medium">Se connecter</button>
57
+ </form>
58
+
59
+ <div class="mt-6 text-center">
60
+ <p class="text-gray-600">
61
+ Vous n'avez pas de compte ?
62
+ <a href="register.html" class="text-indigo-600 font-medium hover:text-indigo-800">S'inscrire</a>
63
+ </p>
64
+ </div>
65
+ </div>
66
+ </div>
67
+
68
+ <script>
69
+ feather.replace();
70
+
71
+ document.getElementById('loginForm').addEventListener('submit', function(e) {
72
+ e.preventDefault();
73
+
74
+ const email = document.getElementById('loginEmail').value;
75
+ const password = document.getElementById('loginPassword').value;
76
+
77
+ // Mock authentication - In a real app, this would check with a server
78
+ const users = JSON.parse(localStorage.getItem('users')) || [];
79
+ const user = users.find(u => u.email === email && u.password === password);
80
+
81
+ if (user) {
82
+ localStorage.setItem('currentUser', JSON.stringify(user));
83
+ window.location.href = 'dashboard.html';
84
+ } else {
85
+ alert('Identifiants incorrects');
86
+ }
87
+ });
88
+ </script>
89
+ </body>
90
+ </html>
prompts.txt ADDED
@@ -0,0 +1,12 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ plateforme web de prise de sang en HTML + CSS + JS dans un seul fichier, avec fonctionnalités basiques :
2
+
3
+ Inscription / identification patient
4
+
5
+ Prise de rendez-vous pour prise de sang
6
+
7
+ Sélection de laboratoire
8
+
9
+ Visualisation des rendez-vous existants
10
+
11
+ Stockage local (mock, facilement adaptable à un backend Flask ou Node.js)
12
+ crees les autres HTML et le serveur
register.html ADDED
@@ -0,0 +1,103 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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>Inscription - LaboConnect</title>
7
+ <link rel="icon" type="image/x-icon" href="data:image/svg+xml,<svg xmlns=%22http://www.w3.org/2000/svg%22 viewBox=%220 0 100 100%22><text y=%22.9em%22 font-size=%2290%22>💉</text></svg>">
8
+ <script src="https://cdn.tailwindcss.com"></script>
9
+ <link href="https://fonts.googleapis.com/css2?family=Poppins:wght@300;400;500;600;700&display=swap" rel="stylesheet">
10
+ <script src="https://unpkg.com/feather-icons"></script>
11
+ <style>
12
+ body {
13
+ font-family: 'Poppins', sans-serif;
14
+ background: linear-gradient(135deg, #f0f9ff 0%, #e6f7ff 100%);
15
+ }
16
+ .btn-primary {
17
+ background: linear-gradient(90deg, #4f46e5 0%, #7c3aed 100%);
18
+ transition: all 0.3s ease;
19
+ }
20
+ .btn-primary:hover {
21
+ background: linear-gradient(90deg, #4338ca 0%, #6d28d9 100%);
22
+ transform: scale(1.05);
23
+ }
24
+ </style>
25
+ </head>
26
+ <body class="min-h-screen flex items-center justify-center p-4">
27
+ <div class="w-full max-w-md">
28
+ <div class="bg-white rounded-2xl shadow-xl p-8">
29
+ <div class="text-center mb-8">
30
+ <div class="mx-auto w-16 h-16 rounded-full bg-indigo-100 flex items-center justify-center mb-4">
31
+ <i data-feather="user-plus" class="text-indigo-600 w-8 h-8"></i>
32
+ </div>
33
+ <h1 class="text-2xl font-bold text-gray-800">Créer un compte</h1>
34
+ <p class="text-gray-600 mt-2">Rejoignez LaboConnect pour prendre vos rendez-vous de prise de sang</p>
35
+ </div>
36
+
37
+ <form id="registerForm" class="space-y-6">
38
+ <div>
39
+ <label class="block text-gray-700 mb-2">Nom complet</label>
40
+ <input type="text" id="registerName" class="w-full px-4 py-3 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-indigo-300 focus:border-transparent" required>
41
+ </div>
42
+
43
+ <div>
44
+ <label class="block text-gray-700 mb-2">Email</label>
45
+ <input type="email" id="registerEmail" class="w-full px-4 py-3 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-indigo-300 focus:border-transparent" required>
46
+ </div>
47
+
48
+ <div>
49
+ <label class="block text-gray-700 mb-2">Mot de passe</label>
50
+ <input type="password" id="registerPassword" class="w-full px-4 py-3 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-indigo-300 focus:border-transparent" required minlength="6">
51
+ </div>
52
+
53
+ <div>
54
+ <label class="block text-gray-700 mb-2">Confirmer le mot de passe</label>
55
+ <input type="password" id="confirmPassword" class="w-full px-4 py-3 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-indigo-300 focus:border-transparent" required minlength="6">
56
+ </div>
57
+
58
+ <button type="submit" class="w-full btn-primary text-white py-3 rounded-lg font-medium">S'inscrire</button>
59
+ </form>
60
+
61
+ <div class="mt-6 text-center">
62
+ <p class="text-gray-600">
63
+ Vous avez déjà un compte ?
64
+ <a href="login.html" class="text-indigo-600 font-medium hover:text-indigo-800">Se connecter</a>
65
+ </p>
66
+ </div>
67
+ </div>
68
+ </div>
69
+
70
+ <script>
71
+ feather.replace();
72
+
73
+ document.getElementById('registerForm').addEventListener('submit', function(e) {
74
+ e.preventDefault();
75
+
76
+ const name = document.getElementById('registerName').value;
77
+ const email = document.getElementById('registerEmail').value;
78
+ const password = document.getElementById('registerPassword').value;
79
+ const confirmPassword = document.getElementById('confirmPassword').value;
80
+
81
+ if (password !== confirmPassword) {
82
+ alert('Les mots de passe ne correspondent pas');
83
+ return;
84
+ }
85
+
86
+ // Mock registration - In a real app, this would send to a server
87
+ const users = JSON.parse(localStorage.getItem('users')) || [];
88
+ if (users.some(u => u.email === email)) {
89
+ alert('Cet email est déjà utilisé');
90
+ return;
91
+ }
92
+
93
+ const newUser = { name, email, password };
94
+ users.push(newUser);
95
+ localStorage.setItem('users', JSON.stringify(users));
96
+ localStorage.setItem('currentUser', JSON.stringify(newUser));
97
+
98
+ alert('Inscription réussie !');
99
+ window.location.href = 'dashboard.html';
100
+ });
101
+ </script>
102
+ </body>
103
+ </html>
server.js ADDED
@@ -0,0 +1,101 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ```javascript
2
+ const express = require('express');
3
+ const path = require('path');
4
+ const app = express();
5
+ const PORT = 3000;
6
+
7
+ // Middleware
8
+ app.use(express.static(path.join(__dirname)));
9
+ app.use(express.json());
10
+ app.use(express.urlencoded({ extended: true }));
11
+
12
+ // Stockage en mémoire (à remplacer par une base de données)
13
+ let users = [];
14
+ let appointments = [];
15
+
16
+ // Routes
17
+ app.get('/', (req, res) => {
18
+ res.sendFile(path.join(__dirname, 'index.html'));
19
+ });
20
+
21
+ app.get('/register', (req, res) => {
22
+ res.sendFile(path.join(__dirname, 'register.html'));
23
+ });
24
+
25
+ app.get('/login', (req, res) => {
26
+ res.sendFile(path.join(__dirname, 'login.html'));
27
+ });
28
+
29
+ app.get('/dashboard', (req, res) => {
30
+ res.sendFile(path.join(__dirname, 'dashboard.html'));
31
+ });
32
+
33
+ // API endpoints
34
+ app.post('/api/register', (req, res) => {
35
+ const { name, email, password } = req.body;
36
+
37
+ // Vérifier si l'utilisateur existe déjà
38
+ const existingUser = users.find(u => u.email === email);
39
+ if (existingUser) {
40
+ return res.status(400).json({ error: 'Cet email est déjà utilisé' });
41
+ }
42
+
43
+ // Créer un nouvel utilisateur
44
+ const newUser = { name, email, password };
45
+ users.push(newUser);
46
+
47
+ res.status(201).json({ message: 'Inscription réussie', user: newUser });
48
+ });
49
+
50
+ app.post('/api/login', (req, res) => {
51
+ const { email, password } = req.body;
52
+
53
+ // Vérifier les identifiants
54
+ const user = users.find(u => u.email === email && u.password === password);
55
+ if (!user) {
56
+ return res.status(401).json({ error: 'Identifiants incorrects' });
57
+ }
58
+
59
+ res.json({ message: 'Connexion réussie', user });
60
+ });
61
+
62
+ app.post('/api/appointments', (req, res) => {
63
+ const { userId, laboratory, date, time, analysis } = req.body;
64
+
65
+ // Créer un nouveau rendez-vous
66
+ const newAppointment = {
67
+ id: Date.now(),
68
+ userId,
69
+ laboratory,
70
+ date,
71
+ time,
72
+ analysis,
73
+ status: 'confirmé'
74
+ };
75
+
76
+ appointments.push(newAppointment);
77
+
78
+ res.status(201).json({ message: 'Rendez-vous pris avec succès', appointment: newAppointment });
79
+ });
80
+
81
+ app.get('/api/appointments/:userId', (req, res) => {
82
+ const { userId } = req.params;
83
+ const userAppointments = appointments.filter(a => a.userId === userId);
84
+
85
+ res.json(userAppointments);
86
+ });
87
+
88
+ app.delete('/api/appointments/:id', (req, res) => {
89
+ const { id } = req.params;
90
+ const appointmentId = parseInt(id);
91
+
92
+ appointments = appointments.filter(a => a.id !== appointmentId);
93
+
94
+ res.json({ message: 'Rendez-vous annulé' });
95
+ });
96
+
97
+ // Démarrer le serveur
98
+ app.listen(PORT, () => {
99
+ console.log(`Serveur démarré sur http://localhost:${PORT}`);
100
+ });
101
+ ```