MORYDIABAGATE commited on
Commit
a2dbbd3
·
verified ·
1 Parent(s): c555e97

Add 2 files

Browse files
Files changed (2) hide show
  1. index.html +4 -1338
  2. prompts.txt +2 -1
index.html CHANGED
@@ -6,1343 +6,9 @@
6
  <title>Gestion d'Appartements - Système d'Alerte</title>
7
  <script src="https://cdn.tailwindcss.com"></script>
8
  <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
9
- <style>
10
- .emergency-btn {
11
- animation: pulse 2s infinite;
12
- }
13
- @keyframes pulse {
14
- 0% { transform: scale(1); box-shadow: 0 0 0 0 rgba(239, 68, 68, 0.7); }
15
- 70% { transform: scale(1.05); box-shadow: 0 0 0 10px rgba(239, 68, 68, 0); }
16
- 100% { transform: scale(1); box-shadow: 0 0 0 0 rgba(239, 68, 68, 0); }
17
- }
18
- .sidebar {
19
- transition: all 0.3s ease;
20
- }
21
- .alert-notification {
22
- animation: slideIn 0.5s forwards;
23
- }
24
- @keyframes slideIn {
25
- from { transform: translateX(100%); opacity: 0; }
26
- to { transform: translateX(0); opacity: 1; }
27
- }
28
- .fade-in {
29
- animation: fadeIn 0.3s ease-in;
30
- }
31
- @keyframes fadeIn {
32
- from { opacity: 0; }
33
- to { opacity: 1; }
34
- }
35
- </style>
36
  </head>
37
- <body class="bg-gray-100 font-sans">
38
- <!-- Login/Signup Modal -->
39
- <div id="authModal" class="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center z-50">
40
- <div class="bg-white rounded-lg p-8 w-full max-w-md">
41
- <div class="flex justify-between items-center mb-6">
42
- <h2 class="text-2xl font-bold">Connexion</h2>
43
- <button onclick="toggleAuthModal()" class="text-gray-500 hover:text-gray-700">
44
- <i class="fas fa-times"></i>
45
- </button>
46
- </div>
47
- <div class="mb-4">
48
- <label class="block text-gray-700 mb-2" for="email">Email</label>
49
- <input type="email" id="email" class="w-full px-4 py-2 border rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500">
50
- </div>
51
- <div class="mb-6">
52
- <label class="block text-gray-700 mb-2" for="password">Mot de passe</label>
53
- <input type="password" id="password" class="w-full px-4 py-2 border rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500">
54
- </div>
55
- <button onclick="login()" class="w-full bg-blue-600 text-white py-2 px-4 rounded-lg hover:bg-blue-700 transition mb-4">
56
- Se connecter
57
- </button>
58
- <p class="text-center text-gray-600">Pas encore de compte? <a href="#" class="text-blue-600 hover:underline" onclick="switchToSignup()">S'inscrire</a></p>
59
- </div>
60
- </div>
61
-
62
- <!-- Main Layout -->
63
- <div class="flex h-screen">
64
- <!-- Sidebar -->
65
- <div id="sidebar" class="sidebar bg-blue-800 text-white w-64 flex-shrink-0 transform -translate-x-full md:translate-x-0">
66
- <div class="p-4 flex items-center space-x-3 border-b border-blue-700">
67
- <i class="fas fa-building text-2xl"></i>
68
- <h1 class="text-xl font-bold">GestionApp</h1>
69
- </div>
70
- <nav class="p-4">
71
- <div class="mb-8">
72
- <h3 class="text-blue-300 uppercase text-xs font-semibold mb-3">Menu Principal</h3>
73
- <ul>
74
- <li class="mb-2">
75
- <a href="#" class="flex items-center p-2 rounded hover:bg-blue-700" onclick="showDashboard()">
76
- <i class="fas fa-home mr-3"></i>
77
- Tableau de bord
78
- </a>
79
- </li>
80
- <li class="mb-2">
81
- <a href="#" class="flex items-center p-2 rounded hover:bg-blue-700" onclick="showAlerts()">
82
- <i class="fas fa-bell mr-3"></i>
83
- Alertes
84
- </a>
85
- </li>
86
- <li class="mb-2">
87
- <a href="#" class="flex items-center p-2 rounded hover:bg-blue-700" onclick="showMaintenance()">
88
- <i class="fas fa-tools mr-3"></i>
89
- Maintenance
90
- </a>
91
- </li>
92
- <li class="mb-2">
93
- <a href="#" class="flex items-center p-2 rounded hover:bg-blue-700" onclick="showResidents()">
94
- <i class="fas fa-users mr-3"></i>
95
- Résidents
96
- </a>
97
- </li>
98
- <li class="mb-2">
99
- <a href="#" class="flex items-center p-2 rounded hover:bg-blue-700" onclick="showApartments()">
100
- <i class="fas fa-door-open mr-3"></i>
101
- Appartements
102
- </a>
103
- </li>
104
- <li class="mb-2">
105
- <a href="#" class="flex items-center p-2 rounded hover:bg-blue-700" onclick="showServices()">
106
- <i class="fas fa-concierge-bell mr-3"></i>
107
- Services
108
- </a>
109
- </li>
110
- </ul>
111
- </div>
112
- <div>
113
- <h3 class="text-blue-300 uppercase text-xs font-semibold mb-3">Paramètres</h3>
114
- <ul>
115
- <li class="mb-2">
116
- <a href="#" class="flex items-center p-2 rounded hover:bg-blue-700" onclick="showProfile()">
117
- <i class="fas fa-user-cog mr-3"></i>
118
- Profil
119
- </a>
120
- </li>
121
- <li>
122
- <a href="#" class="flex items-center p-2 rounded hover:bg-blue-700" onclick="logout()">
123
- <i class="fas fa-sign-out-alt mr-3"></i>
124
- Déconnexion
125
- </a>
126
- </li>
127
- </ul>
128
- </div>
129
- </nav>
130
- </div>
131
-
132
- <!-- Main Content -->
133
- <div class="flex-1 flex flex-col overflow-hidden">
134
- <!-- Top Navigation -->
135
- <header class="bg-white shadow-sm">
136
- <div class="flex items-center justify-between px-6 py-4">
137
- <div class="flex items-center">
138
- <button id="sidebarToggle" class="text-gray-500 mr-4 md:hidden" onclick="toggleSidebar()">
139
- <i class="fas fa-bars text-xl"></i>
140
- </button>
141
- <h1 id="pageTitle" class="text-xl font-semibold">Tableau de bord</h1>
142
- </div>
143
- <div class="flex items-center space-x-4">
144
- <div class="relative">
145
- <button id="notificationBtn" class="text-gray-500 hover:text-gray-700">
146
- <i class="fas fa-bell text-xl"></i>
147
- <span id="notificationCount" class="absolute -top-2 -right-2 bg-red-500 text-white text-xs rounded-full h-5 w-5 flex items-center justify-center hidden">0</span>
148
- </button>
149
- </div>
150
- <div class="flex items-center">
151
- <img src="https://randomuser.me/api/portraits/men/1.jpg" alt="Profile" class="h-8 w-8 rounded-full mr-2">
152
- <span id="currentUser" class="font-medium">Jean Dupont</span>
153
- </div>
154
- </div>
155
- </div>
156
- </header>
157
-
158
- <!-- Content Area -->
159
- <main id="mainContent" class="flex-1 overflow-y-auto p-6 bg-gray-50">
160
- <!-- Dashboard Content -->
161
- <div id="dashboardContent" class="fade-in">
162
- <div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-6 mb-6">
163
- <div class="bg-white p-6 rounded-lg shadow">
164
- <div class="flex items-center justify-between">
165
- <div>
166
- <p class="text-gray-500">Alertes actives</p>
167
- <h3 id="activeAlertsCount" class="text-2xl font-bold">0</h3>
168
- </div>
169
- <div class="bg-red-100 p-3 rounded-full">
170
- <i class="fas fa-exclamation-triangle text-red-500 text-xl"></i>
171
- </div>
172
- </div>
173
- </div>
174
- <div class="bg-white p-6 rounded-lg shadow">
175
- <div class="flex items-center justify-between">
176
- <div>
177
- <p class="text-gray-500">Demandes en cours</p>
178
- <h3 id="maintenanceCount" class="text-2xl font-bold">0</h3>
179
- </div>
180
- <div class="bg-blue-100 p-3 rounded-full">
181
- <i class="fas fa-tools text-blue-500 text-xl"></i>
182
- </div>
183
- </div>
184
- </div>
185
- <div class="bg-white p-6 rounded-lg shadow">
186
- <div class="flex items-center justify-between">
187
- <div>
188
- <p class="text-gray-500">Résidents</p>
189
- <h3 id="residentsCount" class="text-2xl font-bold">0</h3>
190
- </div>
191
- <div class="bg-green-100 p-3 rounded-full">
192
- <i class="fas fa-users text-green-500 text-xl"></i>
193
- </div>
194
- </div>
195
- </div>
196
- <div class="bg-white p-6 rounded-lg shadow">
197
- <div class="flex items-center justify-between">
198
- <div>
199
- <p class="text-gray-500">Appartements</p>
200
- <h3 id="apartmentsCount" class="text-2xl font-bold">0</h3>
201
- </div>
202
- <div class="bg-purple-100 p-3 rounded-full">
203
- <i class="fas fa-building text-purple-500 text-xl"></i>
204
- </div>
205
- </div>
206
- </div>
207
- </div>
208
-
209
- <div class="grid grid-cols-1 lg:grid-cols-3 gap-6">
210
- <div class="bg-white p-6 rounded-lg shadow lg:col-span-2">
211
- <div class="flex justify-between items-center mb-4">
212
- <h2 class="text-lg font-semibold">Alertes récentes</h2>
213
- <a href="#" class="text-blue-600 text-sm" onclick="showAlerts()">Voir tout</a>
214
- </div>
215
- <div id="recentAlerts" class="space-y-4">
216
- <!-- Recent alerts will be loaded here -->
217
- <div class="text-center py-10 text-gray-500">
218
- <i class="fas fa-bell-slash text-3xl mb-2"></i>
219
- <p>Aucune alerte récente</p>
220
- </div>
221
- </div>
222
- </div>
223
-
224
- <div class="bg-white p-6 rounded-lg shadow">
225
- <div class="flex justify-between items-center mb-4">
226
- <h2 class="text-lg font-semibold">Bouton d'alerte</h2>
227
- </div>
228
- <div class="text-center p-6">
229
- <button id="emergencyBtn" class="emergency-btn bg-red-500 hover:bg-red-600 text-white rounded-full h-24 w-24 flex items-center justify-center mx-auto mb-4 transition-all shadow-lg">
230
- <i class="fas fa-exclamation text-3xl"></i>
231
- </button>
232
- <p class="text-gray-600 mb-4">En cas d'urgence, appuyez sur le bouton pour alerter le personnel</p>
233
- <div class="space-y-3">
234
- <button class="w-full bg-blue-100 text-blue-700 py-2 px-4 rounded-lg hover:bg-blue-200 transition flex items-center justify-center">
235
- <i class="fas fa-phone-alt mr-2"></i> Appeler les secours
236
- </button>
237
- <button class="w-full bg-gray-100 text-gray-700 py-2 px-4 rounded-lg hover:bg-gray-200 transition flex items-center justify-center">
238
- <i class="fas fa-headset mr-2"></i> Assistance
239
- </button>
240
- </div>
241
- </div>
242
- </div>
243
- </div>
244
- </div>
245
-
246
- <!-- Alerts Content -->
247
- <div id="alertsContent" class="hidden fade-in">
248
- <div class="flex justify-between items-center mb-6">
249
- <h2 class="text-2xl font-semibold">Gestion des alertes</h2>
250
- <button onclick="showAddAlertModal()" class="bg-blue-600 text-white px-4 py-2 rounded-lg hover:bg-blue-700 transition flex items-center">
251
- <i class="fas fa-plus mr-2"></i> Nouvelle alerte
252
- </button>
253
- </div>
254
- <div class="bg-white rounded-lg shadow overflow-hidden">
255
- <div class="px-6 py-4 border-b border-gray-200 flex justify-between items-center">
256
- <div class="flex items-center space-x-4">
257
- <div class="relative">
258
- <select id="alertFilter" class="appearance-none bg-gray-100 border border-gray-300 rounded-lg px-4 py-2 pr-8 focus:outline-none focus:ring-2 focus:ring-blue-500">
259
- <option value="all">Toutes les alertes</option>
260
- <option value="urgent">Urgentes</option>
261
- <option value="in_progress">En cours</option>
262
- <option value="resolved">Résolues</option>
263
- </select>
264
- <div class="pointer-events-none absolute inset-y-0 right-0 flex items-center px-2 text-gray-700">
265
- <i class="fas fa-chevron-down"></i>
266
- </div>
267
- </div>
268
- </div>
269
- <div class="relative w-64">
270
- <input type="text" id="alertSearch" placeholder="Rechercher..." class="w-full px-4 py-2 border rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500 pl-10">
271
- <i class="fas fa-search absolute left-3 top-3 text-gray-400"></i>
272
- </div>
273
- </div>
274
- <div class="overflow-x-auto">
275
- <table class="min-w-full divide-y divide-gray-200">
276
- <thead class="bg-gray-50">
277
- <tr>
278
- <th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Date</th>
279
- <th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Appartement</th>
280
- <th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Résident</th>
281
- <th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Type</th>
282
- <th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Statut</th>
283
- <th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Actions</th>
284
- </tr>
285
- </thead>
286
- <tbody id="alertsTableBody" class="bg-white divide-y divide-gray-200">
287
- <!-- Alerts will be loaded here -->
288
- </tbody>
289
- </table>
290
- </div>
291
- </div>
292
- </div>
293
-
294
- <!-- Maintenance Content -->
295
- <div id="maintenanceContent" class="hidden fade-in">
296
- <div class="flex justify-between items-center mb-6">
297
- <h2 class="text-2xl font-semibold">Demandes de maintenance</h2>
298
- <button onclick="showAddMaintenanceModal()" class="bg-blue-600 text-white px-4 py-2 rounded-lg hover:bg-blue-700 transition flex items-center">
299
- <i class="fas fa-plus mr-2"></i> Nouvelle demande
300
- </button>
301
- </div>
302
- <div class="bg-white rounded-lg shadow overflow-hidden">
303
- <div class="px-6 py-4 border-b border-gray-200 flex justify-between items-center">
304
- <div class="flex items-center space-x-4">
305
- <div class="relative">
306
- <select id="maintenanceFilter" class="appearance-none bg-gray-100 border border-gray-300 rounded-lg px-4 py-2 pr-8 focus:outline-none focus:ring-2 focus:ring-blue-500">
307
- <option value="all">Toutes les demandes</option>
308
- <option value="pending">En attente</option>
309
- <option value="in_progress">En cours</option>
310
- <option value="completed">Terminées</option>
311
- </select>
312
- <div class="pointer-events-none absolute inset-y-0 right-0 flex items-center px-2 text-gray-700">
313
- <i class="fas fa-chevron-down"></i>
314
- </div>
315
- </div>
316
- </div>
317
- <div class="relative w-64">
318
- <input type="text" id="maintenanceSearch" placeholder="Rechercher..." class="w-full px-4 py-2 border rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500 pl-10">
319
- <i class="fas fa-search absolute left-3 top-3 text-gray-400"></i>
320
- </div>
321
- </div>
322
- <div class="overflow-x-auto">
323
- <table class="min-w-full divide-y divide-gray-200">
324
- <thead class="bg-gray-50">
325
- <tr>
326
- <th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Date</th>
327
- <th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Appartement</th>
328
- <th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Type</th>
329
- <th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Description</th>
330
- <th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Statut</th>
331
- <th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Actions</th>
332
- </tr>
333
- </thead>
334
- <tbody id="maintenanceTableBody" class="bg-white divide-y divide-gray-200">
335
- <!-- Maintenance requests will be loaded here -->
336
- </tbody>
337
- </table>
338
- </div>
339
- </div>
340
- </div>
341
-
342
- <!-- Residents Content -->
343
- <div id="residentsContent" class="hidden fade-in">
344
- <div class="flex justify-between items-center mb-6">
345
- <h2 class="text-2xl font-semibold">Gestion des résidents</h2>
346
- <button onclick="showAddResidentModal()" class="bg-blue-600 text-white px-4 py-2 rounded-lg hover:bg-blue-700 transition flex items-center">
347
- <i class="fas fa-plus mr-2"></i> Nouveau résident
348
- </button>
349
- </div>
350
- <div class="bg-white rounded-lg shadow overflow-hidden">
351
- <div class="px-6 py-4 border-b border-gray-200">
352
- <div class="relative w-64">
353
- <input type="text" id="residentSearch" placeholder="Rechercher..." class="w-full px-4 py-2 border rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500 pl-10">
354
- <i class="fas fa-search absolute left-3 top-3 text-gray-400"></i>
355
- </div>
356
- </div>
357
- <div class="overflow-x-auto">
358
- <table class="min-w-full divide-y divide-gray-200">
359
- <thead class="bg-gray-50">
360
- <tr>
361
- <th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Nom</th>
362
- <th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Email</th>
363
- <th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Téléphone</th>
364
- <th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Appartement</th>
365
- <th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Actions</th>
366
- </tr>
367
- </thead>
368
- <tbody id="residentsTableBody" class="bg-white divide-y divide-gray-200">
369
- <!-- Residents will be loaded here -->
370
- </tbody>
371
- </table>
372
- </div>
373
- </div>
374
- </div>
375
-
376
- <!-- Apartments Content -->
377
- <div id="apartmentsContent" class="hidden fade-in">
378
- <div class="flex justify-between items-center mb-6">
379
- <h2 class="text-2xl font-semibold">Gestion des appartements</h2>
380
- <button onclick="showAddApartmentModal()" class="bg-blue-600 text-white px-4 py-2 rounded-lg hover:bg-blue-700 transition flex items-center">
381
- <i class="fas fa-plus mr-2"></i> Nouvel appartement
382
- </button>
383
- </div>
384
- <div class="bg-white rounded-lg shadow overflow-hidden">
385
- <div class="px-6 py-4 border-b border-gray-200">
386
- <div class="relative w-64">
387
- <input type="text" id="apartmentSearch" placeholder="Rechercher..." class="w-full px-4 py-2 border rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500 pl-10">
388
- <i class="fas fa-search absolute left-3 top-3 text-gray-400"></i>
389
- </div>
390
- </div>
391
- <div class="overflow-x-auto">
392
- <table class="min-w-full divide-y divide-gray-200">
393
- <thead class="bg-gray-50">
394
- <tr>
395
- <th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Numéro</th>
396
- <th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Étage</th>
397
- <th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Type</th>
398
- <th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Surface</th>
399
- <th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Résident</th>
400
- <th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Actions</th>
401
- </tr>
402
- </thead>
403
- <tbody id="apartmentsTableBody" class="bg-white divide-y divide-gray-200">
404
- <!-- Apartments will be loaded here -->
405
- </tbody>
406
- </table>
407
- </div>
408
- </div>
409
- </div>
410
-
411
- <!-- Services Content -->
412
- <div id="servicesContent" class="hidden fade-in">
413
- <div class="flex justify-between items-center mb-6">
414
- <h2 class="text-2xl font-semibold">Services disponibles</h2>
415
- <button onclick="showAddServiceModal()" class="bg-blue-600 text-white px-4 py-2 rounded-lg hover:bg-blue-700 transition flex items-center">
416
- <i class="fas fa-plus mr-2"></i> Nouveau service
417
- </button>
418
- </div>
419
- <div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
420
- <div class="bg-white p-6 rounded-lg shadow">
421
- <div class="flex items-center justify-between mb-4">
422
- <div class="bg-blue-100 p-3 rounded-full">
423
- <i class="fas fa-broom text-blue-500 text-xl"></i>
424
- </div>
425
- <span class="px-2 inline-flex text-xs leading-5 font-semibold rounded-full bg-green-100 text-green-800">Disponible</span>
426
- </div>
427
- <h3 class="text-lg font-semibold mb-2">Nettoyage</h3>
428
- <p class="text-gray-600 mb-4">Service de nettoyage professionnel des parties communes et des appartements.</p>
429
- <button class="text-blue-600 hover:text-blue-800 font-medium">Réserver</button>
430
- </div>
431
- <div class="bg-white p-6 rounded-lg shadow">
432
- <div class="flex items-center justify-between mb-4">
433
- <div class="bg-green-100 p-3 rounded-full">
434
- <i class="fas fa-utensils text-green-500 text-xl"></i>
435
- </div>
436
- <span class="px-2 inline-flex text-xs leading-5 font-semibold rounded-full bg-green-100 text-green-800">Disponible</span>
437
- </div>
438
- <h3 class="text-lg font-semibold mb-2">Restauration</h3>
439
- <p class="text-gray-600 mb-4">Service de livraison de repas directement dans votre appartement.</p>
440
- <button class="text-blue-600 hover:text-blue-800 font-medium">Commander</button>
441
- </div>
442
- <div class="bg-white p-6 rounded-lg shadow">
443
- <div class="flex items-center justify-between mb-4">
444
- <div class="bg-purple-100 p-3 rounded-full">
445
- <i class="fas fa-car text-purple-500 text-xl"></i>
446
- </div>
447
- <span class="px-2 inline-flex text-xs leading-5 font-semibold rounded-full bg-green-100 text-green-800">Disponible</span>
448
- </div>
449
- <h3 class="text-lg font-semibold mb-2">Parking</h3>
450
- <p class="text-gray-600 mb-4">Réservation de places de parking privées dans le sous-sol de l'immeuble.</p>
451
- <button class="text-blue-600 hover:text-blue-800 font-medium">Réserver</button>
452
- </div>
453
- </div>
454
- </div>
455
-
456
- <!-- Profile Content -->
457
- <div id="profileContent" class="hidden fade-in">
458
- <div class="bg-white rounded-lg shadow overflow-hidden">
459
- <div class="px-6 py-4 border-b border-gray-200">
460
- <h2 class="text-2xl font-semibold">Mon profil</h2>
461
- </div>
462
- <div class="p-6">
463
- <div class="flex flex-col md:flex-row">
464
- <div class="md:w-1/3 flex flex-col items-center mb-6 md:mb-0">
465
- <img src="https://randomuser.me/api/portraits/men/1.jpg" alt="Profile" class="h-32 w-32 rounded-full mb-4">
466
- <button class="text-blue-600 hover:text-blue-800">Changer la photo</button>
467
- </div>
468
- <div class="md:w-2/3 md:pl-8">
469
- <form>
470
- <div class="grid grid-cols-1 md:grid-cols-2 gap-6 mb-6">
471
- <div>
472
- <label class="block text-gray-700 mb-2" for="profileFirstName">Prénom</label>
473
- <input type="text" id="profileFirstName" class="w-full px-4 py-2 border rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500" value="Jean">
474
- </div>
475
- <div>
476
- <label class="block text-gray-700 mb-2" for="profileLastName">Nom</label>
477
- <input type="text" id="profileLastName" class="w-full px-4 py-2 border rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500" value="Dupont">
478
- </div>
479
- <div>
480
- <label class="block text-gray-700 mb-2" for="profileEmail">Email</label>
481
- <input type="email" id="profileEmail" class="w-full px-4 py-2 border rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500" value="jean.dupont@example.com">
482
- </div>
483
- <div>
484
- <label class="block text-gray-700 mb-2" for="profilePhone">Téléphone</label>
485
- <input type="tel" id="profilePhone" class="w-full px-4 py-2 border rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500" value="+33 6 12 34 56 78">
486
- </div>
487
- </div>
488
- <div class="mb-6">
489
- <label class="block text-gray-700 mb-2" for="profileAddress">Adresse</label>
490
- <input type="text" id="profileAddress" class="w-full px-4 py-2 border rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500" value="123 Rue de la République, Paris">
491
- </div>
492
- <div class="flex justify-end">
493
- <button type="button" class="bg-gray-200 text-gray-700 px-4 py-2 rounded-lg hover:bg-gray-300 transition mr-4">
494
- Annuler
495
- </button>
496
- <button type="button" class="bg-blue-600 text-white px-4 py-2 rounded-lg hover:bg-blue-700 transition">
497
- Enregistrer
498
- </button>
499
- </div>
500
- </form>
501
- </div>
502
- </div>
503
- </div>
504
- </div>
505
- </div>
506
- </main>
507
- </div>
508
- </div>
509
-
510
- <!-- Emergency Alert Modal -->
511
- <div id="emergencyModal" class="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center z-50 hidden">
512
- <div class="bg-white rounded-lg p-8 w-full max-w-md">
513
- <div class="text-center">
514
- <div class="mx-auto flex items-center justify-center h-12 w-12 rounded-full bg-red-100 mb-4">
515
- <i class="fas fa-exclamation-triangle text-red-500 text-xl"></i>
516
- </div>
517
- <h3 class="text-lg font-medium text-gray-900 mb-2">Confirmer l'alerte d'urgence</h3>
518
- <p class="text-sm text-gray-500 mb-6">Voulez-vous vraiment envoyer une alerte d'urgence? Le personnel sera immédiatement notifié.</p>
519
- <div class="flex justify-center space-x-4">
520
- <button onclick="sendEmergencyAlert()" class="px-4 py-2 bg-red-600 text-white rounded-md hover:bg-red-700 focus:outline-none focus:ring-2 focus:ring-red-500">
521
- Confirmer
522
- </button>
523
- <button onclick="hideEmergencyModal()" class="px-4 py-2 bg-gray-200 text-gray-700 rounded-md hover:bg-gray-300 focus:outline-none focus:ring-2 focus:ring-gray-500">
524
- Annuler
525
- </button>
526
- </div>
527
- </div>
528
- </div>
529
- </div>
530
-
531
- <!-- Add Alert Modal -->
532
- <div id="addAlertModal" class="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center z-50 hidden">
533
- <div class="bg-white rounded-lg p-8 w-full max-w-md">
534
- <div class="flex justify-between items-center mb-6">
535
- <h2 class="text-xl font-bold">Nouvelle alerte</h2>
536
- <button onclick="hideAddAlertModal()" class="text-gray-500 hover:text-gray-700">
537
- <i class="fas fa-times"></i>
538
- </button>
539
- </div>
540
- <form id="alertForm">
541
- <div class="mb-4">
542
- <label class="block text-gray-700 mb-2" for="alertApartment">Appartement</label>
543
- <select id="alertApartment" class="w-full px-4 py-2 border rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500">
544
- <!-- Options will be loaded from database -->
545
- </select>
546
- </div>
547
- <div class="mb-4">
548
- <label class="block text-gray-700 mb-2" for="alertType">Type d'alerte</label>
549
- <select id="alertType" class="w-full px-4 py-2 border rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500">
550
- <option value="water">Problème d'eau</option>
551
- <option value="electricity">Problème électrique</option>
552
- <option value="door">Porte bloquée</option>
553
- <option value="elevator">Ascenseur en panne</option>
554
- <option value="other">Autre</option>
555
- </select>
556
- </div>
557
- <div class="mb-4">
558
- <label class="block text-gray-700 mb-2" for="alertUrgency">Urgence</label>
559
- <select id="alertUrgency" class="w-full px-4 py-2 border rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500">
560
- <option value="low">Faible</option>
561
- <option value="medium">Moyenne</option>
562
- <option value="high">Haute</option>
563
- <option value="urgent">Urgente</option>
564
- </select>
565
- </div>
566
- <div class="mb-6">
567
- <label class="block text-gray-700 mb-2" for="alertDescription">Description</label>
568
- <textarea id="alertDescription" rows="3" class="w-full px-4 py-2 border rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500"></textarea>
569
- </div>
570
- <div class="flex justify-end">
571
- <button type="button" onclick="hideAddAlertModal()" class="bg-gray-200 text-gray-700 px-4 py-2 rounded-lg hover:bg-gray-300 transition mr-4">
572
- Annuler
573
- </button>
574
- <button type="button" onclick="saveAlert()" class="bg-blue-600 text-white px-4 py-2 rounded-lg hover:bg-blue-700 transition">
575
- Enregistrer
576
- </button>
577
- </div>
578
- </form>
579
- </div>
580
- </div>
581
-
582
- <!-- Add Resident Modal -->
583
- <div id="addResidentModal" class="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center z-50 hidden">
584
- <div class="bg-white rounded-lg p-8 w-full max-w-md">
585
- <div class="flex justify-between items-center mb-6">
586
- <h2 class="text-xl font-bold">Nouveau résident</h2>
587
- <button onclick="hideAddResidentModal()" class="text-gray-500 hover:text-gray-700">
588
- <i class="fas fa-times"></i>
589
- </button>
590
- </div>
591
- <form id="residentForm">
592
- <div class="grid grid-cols-1 md:grid-cols-2 gap-4 mb-4">
593
- <div>
594
- <label class="block text-gray-700 mb-2" for="residentFirstName">Prénom</label>
595
- <input type="text" id="residentFirstName" class="w-full px-4 py-2 border rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500">
596
- </div>
597
- <div>
598
- <label class="block text-gray-700 mb-2" for="residentLastName">Nom</label>
599
- <input type="text" id="residentLastName" class="w-full px-4 py-2 border rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500">
600
- </div>
601
- </div>
602
- <div class="mb-4">
603
- <label class="block text-gray-700 mb-2" for="residentEmail">Email</label>
604
- <input type="email" id="residentEmail" class="w-full px-4 py-2 border rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500">
605
- </div>
606
- <div class="mb-4">
607
- <label class="block text-gray-700 mb-2" for="residentPhone">Téléphone</label>
608
- <input type="tel" id="residentPhone" class="w-full px-4 py-2 border rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500">
609
- </div>
610
- <div class="mb-4">
611
- <label class="block text-gray-700 mb-2" for="residentApartment">Appartement</label>
612
- <select id="residentApartment" class="w-full px-4 py-2 border rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500">
613
- <!-- Options will be loaded from database -->
614
- </select>
615
- </div>
616
- <div class="flex justify-end">
617
- <button type="button" onclick="hideAddResidentModal()" class="bg-gray-200 text-gray-700 px-4 py-2 rounded-lg hover:bg-gray-300 transition mr-4">
618
- Annuler
619
- </button>
620
- <button type="button" onclick="saveResident()" class="bg-blue-600 text-white px-4 py-2 rounded-lg hover:bg-blue-700 transition">
621
- Enregistrer
622
- </button>
623
- </div>
624
- </form>
625
- </div>
626
- </div>
627
-
628
- <!-- Add Apartment Modal -->
629
- <div id="addApartmentModal" class="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center z-50 hidden">
630
- <div class="bg-white rounded-lg p-8 w-full max-w-md">
631
- <div class="flex justify-between items-center mb-6">
632
- <h2 class="text-xl font-bold">Nouvel appartement</h2>
633
- <button onclick="hideAddApartmentModal()" class="text-gray-500 hover:text-gray-700">
634
- <i class="fas fa-times"></i>
635
- </button>
636
- </div>
637
- <form id="apartmentForm">
638
- <div class="mb-4">
639
- <label class="block text-gray-700 mb-2" for="apartmentNumber">Numéro</label>
640
- <input type="text" id="apartmentNumber" class="w-full px-4 py-2 border rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500">
641
- </div>
642
- <div class="mb-4">
643
- <label class="block text-gray-700 mb-2" for="apartmentFloor">Étage</label>
644
- <input type="number" id="apartmentFloor" class="w-full px-4 py-2 border rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500">
645
- </div>
646
- <div class="mb-4">
647
- <label class="block text-gray-700 mb-2" for="apartmentType">Type</label>
648
- <select id="apartmentType" class="w-full px-4 py-2 border rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500">
649
- <option value="studio">Studio</option>
650
- <option value="t1">T1</option>
651
- <option value="t2">T2</option>
652
- <option value="t3">T3</option>
653
- <option value="t4">T4+</option>
654
- </select>
655
- </div>
656
- <div class="mb-4">
657
- <label class="block text-gray-700 mb-2" for="apartmentArea">Surface (m²)</label>
658
- <input type="number" id="apartmentArea" class="w-full px-4 py-2 border rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500">
659
- </div>
660
- <div class="flex justify-end">
661
- <button type="button" onclick="hideAddApartmentModal()" class="bg-gray-200 text-gray-700 px-4 py-2 rounded-lg hover:bg-gray-300 transition mr-4">
662
- Annuler
663
- </button>
664
- <button type="button" onclick="saveApartment()" class="bg-blue-600 text-white px-4 py-2 rounded-lg hover:bg-blue-700 transition">
665
- Enregistrer
666
- </button>
667
- </div>
668
- </form>
669
- </div>
670
- </div>
671
-
672
- <!-- Add Maintenance Modal -->
673
- <div id="addMaintenanceModal" class="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center z-50 hidden">
674
- <div class="bg-white rounded-lg p-8 w-full max-w-md">
675
- <div class="flex justify-between items-center mb-6">
676
- <h2 class="text-xl font-bold">Nouvelle demande</h2>
677
- <button onclick="hideAddMaintenanceModal()" class="text-gray-500 hover:text-gray-700">
678
- <i class="fas fa-times"></i>
679
- </button>
680
- </div>
681
- <form id="maintenanceForm">
682
- <div class="mb-4">
683
- <label class="block text-gray-700 mb-2" for="maintenanceApartment">Appartement</label>
684
- <select id="maintenanceApartment" class="w-full px-4 py-2 border rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500">
685
- <!-- Options will be loaded from database -->
686
- </select>
687
- </div>
688
- <div class="mb-4">
689
- <label class="block text-gray-700 mb-2" for="maintenanceType">Type de problème</label>
690
- <select id="maintenanceType" class="w-full px-4 py-2 border rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500">
691
- <option value="plumbing">Plomberie</option>
692
- <option value="electricity">Électricité</option>
693
- <option value="painting">Peinture</option>
694
- <option value="carpentry">Menuiserie</option>
695
- <option value="cleaning">Nettoyage</option>
696
- <option value="other">Autre</option>
697
- </select>
698
- </div>
699
- <div class="mb-4">
700
- <label class="block text-gray-700 mb-2" for="maintenancePriority">Priorité</label>
701
- <select id="maintenancePriority" class="w-full px-4 py-2 border rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500">
702
- <option value="low">Faible</option>
703
- <option value="medium">Moyenne</option>
704
- <option value="high">Haute</option>
705
- </select>
706
- </div>
707
- <div class="mb-6">
708
- <label class="block text-gray-700 mb-2" for="maintenanceDescription">Description</label>
709
- <textarea id="maintenanceDescription" rows="3" class="w-full px-4 py-2 border rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500"></textarea>
710
- </div>
711
- <div class="flex justify-end">
712
- <button type="button" onclick="hideAddMaintenanceModal()" class="bg-gray-200 text-gray-700 px-4 py-2 rounded-lg hover:bg-gray-300 transition mr-4">
713
- Annuler
714
- </button>
715
- <button type="button" onclick="saveMaintenance()" class="bg-blue-600 text-white px-4 py-2 rounded-lg hover:bg-blue-700 transition">
716
- Enregistrer
717
- </button>
718
- </div>
719
- </form>
720
- </div>
721
- </div>
722
-
723
- <!-- Alert Notification -->
724
- <div id="alertNotification" class="fixed bottom-4 right-4 bg-white p-4 rounded-lg shadow-lg max-w-sm hidden alert-notification">
725
- <div class="flex items-start">
726
- <div class="flex-shrink-0">
727
- <i class="fas fa-check-circle text-green-500 text-xl"></i>
728
- </div>
729
- <div class="ml-3">
730
- <h3 id="notificationTitle" class="text-sm font-medium text-gray-900">Alerte envoyée</h3>
731
- <p id="notificationMessage" class="mt-1 text-sm text-gray-500">Votre alerte a été transmise au personnel. Un intervenant arrivera rapidement.</p>
732
- </div>
733
- <button onclick="hideAlertNotification()" class="ml-4 text-gray-400 hover:text-gray-500">
734
- <i class="fas fa-times"></i>
735
- </button>
736
- </div>
737
- </div>
738
-
739
- <script>
740
- // Database variables
741
- let db;
742
- const DB_NAME = "ApartmentManagementDB";
743
- const DB_VERSION = 1;
744
-
745
- // Object store names
746
- const STORE_ALERTS = "alerts";
747
- const STORE_RESIDENTS = "residents";
748
- const STORE_APARTMENTS = "apartments";
749
- const STORE_MAINTENANCE = "maintenance";
750
-
751
- // Initialize the database
752
- function initDB() {
753
- return new Promise((resolve, reject) => {
754
- const request = indexedDB.open(DB_NAME, DB_VERSION);
755
-
756
- request.onerror = function(event) {
757
- console.error("Database error:", event.target.error);
758
- reject("Database error");
759
- };
760
-
761
- request.onsuccess = function(event) {
762
- db = event.target.result;
763
- console.log("Database initialized");
764
- resolve(db);
765
- };
766
-
767
- request.onupgradeneeded = function(event) {
768
- const db = event.target.result;
769
-
770
- // Create object stores if they don't exist
771
- if (!db.objectStoreNames.contains(STORE_ALERTS)) {
772
- const alertsStore = db.createObjectStore(STORE_ALERTS, { keyPath: "id", autoIncrement: true });
773
- alertsStore.createIndex("apartmentId", "apartmentId", { unique: false });
774
- alertsStore.createIndex("status", "status", { unique: false });
775
- alertsStore.createIndex("date", "date", { unique: false });
776
- }
777
-
778
- if (!db.objectStoreNames.contains(STORE_RESIDENTS)) {
779
- const residentsStore = db.createObjectStore(STORE_RESIDENTS, { keyPath: "id", autoIncrement: true });
780
- residentsStore.createIndex("apartmentId", "apartmentId", { unique: false });
781
- residentsStore.createIndex("email", "email", { unique: true });
782
- }
783
-
784
- if (!db.objectStoreNames.contains(STORE_APARTMENTS)) {
785
- const apartmentsStore = db.createObjectStore(STORE_APARTMENTS, { keyPath: "id", autoIncrement: true });
786
- apartmentsStore.createIndex("number", "number", { unique: true });
787
- }
788
-
789
- if (!db.objectStoreNames.contains(STORE_MAINTENANCE)) {
790
- const maintenanceStore = db.createObjectStore(STORE_MAINTENANCE, { keyPath: "id", autoIncrement: true });
791
- maintenanceStore.createIndex("apartmentId", "apartmentId", { unique: false });
792
- maintenanceStore.createIndex("status", "status", { unique: false });
793
- maintenanceStore.createIndex("date", "date", { unique: false });
794
- }
795
- };
796
- });
797
- }
798
-
799
- // Add sample data to the database
800
- async function addSampleData() {
801
- // Check if data already exists
802
- const apartments = await getAllApartments();
803
- if (apartments.length > 0) return;
804
-
805
- // Add sample apartments
806
- const sampleApartments = [
807
- { number: "101", floor: 1, type: "t2", area: 45, residentId: null },
808
- { number: "102", floor: 1, type: "t1", area: 30, residentId: null },
809
- { number: "201", floor: 2, type: "t3", area: 65, residentId: null },
810
- { number: "202", floor: 2, type: "t2", area: 50, residentId: null },
811
- { number: "301", floor: 3, type: "t4", area: 80, residentId: null }
812
- ];
813
-
814
- for (const apartment of sampleApartments) {
815
- await addApartment(apartment);
816
- }
817
-
818
- // Add sample residents
819
- const sampleResidents = [
820
- { firstName: "Jean", lastName: "Dupont", email: "jean.dupont@example.com", phone: "+33 6 12 34 56 78", apartmentId: 1 },
821
- { firstName: "Marie", lastName: "Lambert", email: "marie.lambert@example.com", phone: "+33 6 23 45 67 89", apartmentId: 3 },
822
- { firstName: "Pierre", lastName: "Martin", email: "pierre.martin@example.com", phone: "+33 6 34 56 78 90", apartmentId: 4 }
823
- ];
824
-
825
- for (const resident of sampleResidents) {
826
- await addResident(resident);
827
- }
828
-
829
- // Update apartments with resident IDs
830
- await updateApartment(1, { residentId: 1 });
831
- await updateApartment(3, { residentId: 2 });
832
- await updateApartment(4, { residentId: 3 });
833
-
834
- // Add sample alerts
835
- const sampleAlerts = [
836
- { apartmentId: 1, type: "water", urgency: "urgent", description: "Fuite d'eau dans la salle de bain", status: "pending", date: new Date().toISOString() },
837
- { apartmentId: 3, type: "door", urgency: "medium", description: "Porte d'entrée bloquée", status: "in_progress", date: new Date(Date.now() - 3600000).toISOString() },
838
- { apartmentId: 4, type: "electricity", urgency: "high", description: "Problème de courant dans la cuisine", status: "resolved", date: new Date(Date.now() - 86400000).toISOString() }
839
- ];
840
-
841
- for (const alert of sampleAlerts) {
842
- await addAlert(alert);
843
- }
844
-
845
- // Add sample maintenance requests
846
- const sampleMaintenance = [
847
- { apartmentId: 1, type: "plumbing", priority: "high", description: "Robinet qui fuit dans la cuisine", status: "pending", date: new Date().toISOString() },
848
- { apartmentId: 3, type: "electricity", priority: "medium", description: "Interrupteur défectueux dans le salon", status: "in_progress", date: new Date(Date.now() - 7200000).toISOString() },
849
- { apartmentId: 4, type: "painting", priority: "low", description: "Peinture à refaire dans la chambre", status: "completed", date: new Date(Date.now() - 172800000).toISOString() }
850
- ];
851
-
852
- for (const maintenance of sampleMaintenance) {
853
- await addMaintenance(maintenance);
854
- }
855
- }
856
-
857
- // CRUD operations for alerts
858
- function addAlert(alert) {
859
- return new Promise((resolve, reject) => {
860
- const transaction = db.transaction([STORE_ALERTS], "readwrite");
861
- const store = transaction.objectStore(STORE_ALERTS);
862
- const request = store.add(alert);
863
-
864
- request.onsuccess = () => resolve(request.result);
865
- request.onerror = () => reject(request.error);
866
- });
867
- }
868
-
869
- function getAlert(id) {
870
- return new Promise((resolve, reject) => {
871
- const transaction = db.transaction([STORE_ALERTS], "readonly");
872
- const store = transaction.objectStore(STORE_ALERTS);
873
- const request = store.get(id);
874
-
875
- request.onsuccess = () => resolve(request.result);
876
- request.onerror = () => reject(request.error);
877
- });
878
- }
879
-
880
- function getAllAlerts() {
881
- return new Promise((resolve, reject) => {
882
- const transaction = db.transaction([STORE_ALERTS], "readonly");
883
- const store = transaction.objectStore(STORE_ALERTS);
884
- const request = store.getAll();
885
-
886
- request.onsuccess = () => resolve(request.result);
887
- request.onerror = () => reject(request.error);
888
- });
889
- }
890
-
891
- function getAlertsByStatus(status) {
892
- return new Promise((resolve, reject) => {
893
- const transaction = db.transaction([STORE_ALERTS], "readonly");
894
- const store = transaction.objectStore(STORE_ALERTS);
895
- const index = store.index("status");
896
- const request = index.getAll(status);
897
-
898
- request.onsuccess = () => resolve(request.result);
899
- request.onerror = () => reject(request.error);
900
- });
901
- }
902
-
903
- function updateAlert(id, updates) {
904
- return new Promise((resolve, reject) => {
905
- const transaction = db.transaction([STORE_ALERTS], "readwrite");
906
- const store = transaction.objectStore(STORE_ALERTS);
907
- const request = store.get(id);
908
-
909
- request.onsuccess = () => {
910
- const alert = request.result;
911
- if (!alert) {
912
- reject(new Error("Alert not found"));
913
- return;
914
- }
915
-
916
- const updatedAlert = { ...alert, ...updates };
917
- const updateRequest = store.put(updatedAlert);
918
-
919
- updateRequest.onsuccess = () => resolve(updatedAlert);
920
- updateRequest.onerror = () => reject(updateRequest.error);
921
- };
922
-
923
- request.onerror = () => reject(request.error);
924
- });
925
- }
926
-
927
- function deleteAlert(id) {
928
- return new Promise((resolve, reject) => {
929
- const transaction = db.transaction([STORE_ALERTS], "readwrite");
930
- const store = transaction.objectStore(STORE_ALERTS);
931
- const request = store.delete(id);
932
-
933
- request.onsuccess = () => resolve();
934
- request.onerror = () => reject(request.error);
935
- });
936
- }
937
-
938
- // CRUD operations for residents
939
- function addResident(resident) {
940
- return new Promise((resolve, reject) => {
941
- const transaction = db.transaction([STORE_RESIDENTS], "readwrite");
942
- const store = transaction.objectStore(STORE_RESIDENTS);
943
- const request = store.add(resident);
944
-
945
- request.onsuccess = () => resolve(request.result);
946
- request.onerror = () => reject(request.error);
947
- });
948
- }
949
-
950
- function getResident(id) {
951
- return new Promise((resolve, reject) => {
952
- const transaction = db.transaction([STORE_RESIDENTS], "readonly");
953
- const store = transaction.objectStore(STORE_RESIDENTS);
954
- const request = store.get(id);
955
-
956
- request.onsuccess = () => resolve(request.result);
957
- request.onerror = () => reject(request.error);
958
- });
959
- }
960
-
961
- function getAllResidents() {
962
- return new Promise((resolve, reject) => {
963
- const transaction = db.transaction([STORE_RESIDENTS], "readonly");
964
- const store = transaction.objectStore(STORE_RESIDENTS);
965
- const request = store.getAll();
966
-
967
- request.onsuccess = () => resolve(request.result);
968
- request.onerror = () => reject(request.error);
969
- });
970
- }
971
-
972
- function updateResident(id, updates) {
973
- return new Promise((resolve, reject) => {
974
- const transaction = db.transaction([STORE_RESIDENTS], "readwrite");
975
- const store = transaction.objectStore(STORE_RESIDENTS);
976
- const request = store.get(id);
977
-
978
- request.onsuccess = () => {
979
- const resident = request.result;
980
- if (!resident) {
981
- reject(new Error("Resident not found"));
982
- return;
983
- }
984
-
985
- const updatedResident = { ...resident, ...updates };
986
- const updateRequest = store.put(updatedResident);
987
-
988
- updateRequest.onsuccess = () => resolve(updatedResident);
989
- updateRequest.onerror = () => reject(updateRequest.error);
990
- };
991
-
992
- request.onerror = () => reject(request.error);
993
- });
994
- }
995
-
996
- function deleteResident(id) {
997
- return new Promise((resolve, reject) => {
998
- const transaction = db.transaction([STORE_RESIDENTS], "readwrite");
999
- const store = transaction.objectStore(STORE_RESIDENTS);
1000
- const request = store.delete(id);
1001
-
1002
- request.onsuccess = () => resolve();
1003
- request.onerror = () => reject(request.error);
1004
- });
1005
- }
1006
-
1007
- // CRUD operations for apartments
1008
- function addApartment(apartment) {
1009
- return new Promise((resolve, reject) => {
1010
- const transaction = db.transaction([STORE_APARTMENTS], "readwrite");
1011
- const store = transaction.objectStore(STORE_APARTMENTS);
1012
- const request = store.add(apartment);
1013
-
1014
- request.onsuccess = () => resolve(request.result);
1015
- request.onerror = () => reject(request.error);
1016
- });
1017
- }
1018
-
1019
- function getApartment(id) {
1020
- return new Promise((resolve, reject) => {
1021
- const transaction = db.transaction([STORE_APARTMENTS], "readonly");
1022
- const store = transaction.objectStore(STORE_APARTMENTS);
1023
- const request = store.get(id);
1024
-
1025
- request.onsuccess = () => resolve(request.result);
1026
- request.onerror = () => reject(request.error);
1027
- });
1028
- }
1029
-
1030
- function getAllApartments() {
1031
- return new Promise((resolve, reject) => {
1032
- const transaction = db.transaction([STORE_APARTMENTS], "readonly");
1033
- const store = transaction.objectStore(STORE_APARTMENTS);
1034
- const request = store.getAll();
1035
-
1036
- request.onsuccess = () => resolve(request.result);
1037
- request.onerror = () => reject(request.error);
1038
- });
1039
- }
1040
-
1041
- function updateApartment(id, updates) {
1042
- return new Promise((resolve, reject) => {
1043
- const transaction = db.transaction([STORE_APARTMENTS], "readwrite");
1044
- const store = transaction.objectStore(STORE_APARTMENTS);
1045
- const request = store.get(id);
1046
-
1047
- request.onsuccess = () => {
1048
- const apartment = request.result;
1049
- if (!apartment) {
1050
- reject(new Error("Apartment not found"));
1051
- return;
1052
- }
1053
-
1054
- const updatedApartment = { ...apartment, ...updates };
1055
- const updateRequest = store.put(updatedApartment);
1056
-
1057
- updateRequest.onsuccess = () => resolve(updatedApartment);
1058
- updateRequest.onerror = () => reject(updateRequest.error);
1059
- };
1060
-
1061
- request.onerror = () => reject(request.error);
1062
- });
1063
- }
1064
-
1065
- function deleteApartment(id) {
1066
- return new Promise((resolve, reject) => {
1067
- const transaction = db.transaction([STORE_APARTMENTS], "readwrite");
1068
- const store = transaction.objectStore(STORE_APARTMENTS);
1069
- const request = store.delete(id);
1070
-
1071
- request.onsuccess = () => resolve();
1072
- request.onerror = () => reject(request.error);
1073
- });
1074
- }
1075
-
1076
- // CRUD operations for maintenance
1077
- function addMaintenance(maintenance) {
1078
- return new Promise((resolve, reject) => {
1079
- const transaction = db.transaction([STORE_MAINTENANCE], "readwrite");
1080
- const store = transaction.objectStore(STORE_MAINTENANCE);
1081
- const request = store.add(maintenance);
1082
-
1083
- request.onsuccess = () => resolve(request.result);
1084
- request.onerror = () => reject(request.error);
1085
- });
1086
- }
1087
-
1088
- function getMaintenance(id) {
1089
- return new Promise((resolve, reject) => {
1090
- const transaction = db.transaction([STORE_MAINTENANCE], "readonly");
1091
- const store = transaction.objectStore(STORE_MAINTENANCE);
1092
- const request = store.get(id);
1093
-
1094
- request.onsuccess = () => resolve(request.result);
1095
- request.onerror = () => reject(request.error);
1096
- });
1097
- }
1098
-
1099
- function getAllMaintenance() {
1100
- return new Promise((resolve, reject) => {
1101
- const transaction = db.transaction([STORE_MAINTENANCE], "readonly");
1102
- const store = transaction.objectStore(STORE_MAINTENANCE);
1103
- const request = store.getAll();
1104
-
1105
- request.onsuccess = () => resolve(request.result);
1106
- request.onerror = () => reject(request.error);
1107
- });
1108
- }
1109
-
1110
- function getMaintenanceByStatus(status) {
1111
- return new Promise((resolve, reject) => {
1112
- const transaction = db.transaction([STORE_MAINTENANCE], "readonly");
1113
- const store = transaction.objectStore(STORE_MAINTENANCE);
1114
- const index = store.index("status");
1115
- const request = index.getAll(status);
1116
-
1117
- request.onsuccess = () => resolve(request.result);
1118
- request.onerror = () => reject(request.error);
1119
- });
1120
- }
1121
-
1122
- function updateMaintenance(id, updates) {
1123
- return new Promise((resolve, reject) => {
1124
- const transaction = db.transaction([STORE_MAINTENANCE], "readwrite");
1125
- const store = transaction.objectStore(STORE_MAINTENANCE);
1126
- const request = store.get(id);
1127
-
1128
- request.onsuccess = () => {
1129
- const maintenance = request.result;
1130
- if (!maintenance) {
1131
- reject(new Error("Maintenance request not found"));
1132
- return;
1133
- }
1134
-
1135
- const updatedMaintenance = { ...maintenance, ...updates };
1136
- const updateRequest = store.put(updatedMaintenance);
1137
-
1138
- updateRequest.onsuccess = () => resolve(updatedMaintenance);
1139
- updateRequest.onerror = () => reject(updateRequest.error);
1140
- };
1141
-
1142
- request.onerror = () => reject(request.error);
1143
- });
1144
- }
1145
-
1146
- function deleteMaintenance(id) {
1147
- return new Promise((resolve, reject) => {
1148
- const transaction = db.transaction([STORE_MAINTENANCE], "readwrite");
1149
- const store = transaction.objectStore(STORE_MAINTENANCE);
1150
- const request = store.delete(id);
1151
-
1152
- request.onsuccess = () => resolve();
1153
- request.onerror = () => reject(request.error);
1154
- });
1155
- }
1156
-
1157
- // UI Functions
1158
- async function loadDashboard() {
1159
- try {
1160
- // Get counts for dashboard cards
1161
- const alerts = await getAllAlerts();
1162
- const pendingAlerts = alerts.filter(a => a.status !== "resolved").length;
1163
- document.getElementById('activeAlertsCount').textContent = pendingAlerts;
1164
-
1165
- const maintenance = await getAllMaintenance();
1166
- const pendingMaintenance = maintenance.filter(m => m.status !== "completed").length;
1167
- document.getElementById('maintenanceCount').textContent = pendingMaintenance;
1168
-
1169
- const residents = await getAllResidents();
1170
- document.getElementById('residentsCount').textContent = residents.length;
1171
-
1172
- const apartments = await getAllApartments();
1173
- document.getElementById('apartmentsCount').textContent = apartments.length;
1174
-
1175
- // Load recent alerts (last 3 non-resolved alerts)
1176
- const recentAlerts = alerts
1177
- .filter(a => a.status !== "resolved")
1178
- .sort((a, b) => new Date(b.date) - new Date(a.date))
1179
- .slice(0, 3);
1180
-
1181
- const recentAlertsContainer = document.getElementById('recentAlerts');
1182
- recentAlertsContainer.innerHTML = '';
1183
-
1184
- if (recentAlerts.length === 0) {
1185
- recentAlertsContainer.innerHTML = `
1186
- <div class="text-center py-10 text-gray-500">
1187
- <i class="fas fa-bell-slash text-3xl mb-2"></i>
1188
- <p>Aucune alerte récente</p>
1189
- </div>
1190
- `;
1191
- return;
1192
- }
1193
-
1194
- for (const alert of recentAlerts) {
1195
- const apartment = await getApartment(alert.apartmentId);
1196
- const resident = apartment.residentId ? await getResident(apartment.residentId) : null;
1197
-
1198
- let alertClass = "border-blue-500 bg-blue-50";
1199
- let iconClass = "fas fa-info-circle text-blue-500";
1200
-
1201
- if (alert.urgency === "high" || alert.urgency === "urgent") {
1202
- alertClass = "border-red-500 bg-red-50";
1203
- iconClass = "fas fa-exclamation-triangle text-red-500";
1204
- } else if (alert.urgency === "medium") {
1205
- alertClass = "border-yellow-500 bg-yellow-50";
1206
- iconClass = "fas fa-exclamation-circle text-yellow-500";
1207
- }
1208
-
1209
- const alertElement = document.createElement('div');
1210
- alertElement.className = `flex items-start p-3 border-l-4 ${alertClass} rounded`;
1211
- alertElement.innerHTML = `
1212
- <i class="${iconClass} mt-1 mr-3"></i>
1213
- <div>
1214
- <p class="font-medium">${getAlertTypeText(alert.type)} - Appt ${apartment.number}</p>
1215
- <p class="text-sm text-gray-600">${resident ? resident.firstName + ' ' + resident.lastName : 'Aucun résident'} - ${formatTime(alert.date)}</p>
1216
- <p class="text-sm mt-1">${alert.description}</p>
1217
- </div>
1218
- `;
1219
-
1220
- recentAlertsContainer.appendChild(alertElement);
1221
- }
1222
- } catch (error) {
1223
- console.error("Error loading dashboard:", error);
1224
- showNotification("Erreur", "Impossible de charger les données du tableau de bord", "error");
1225
- }
1226
- }
1227
-
1228
- async function loadAlerts() {
1229
- try {
1230
- const filter = document.getElementById('alertFilter').value;
1231
- const searchTerm = document.getElementById('alertSearch').value.toLowerCase();
1232
-
1233
- let alerts;
1234
- if (filter === "all") {
1235
- alerts = await getAllAlerts();
1236
- } else if (filter === "urgent") {
1237
- alerts = await getAllAlerts();
1238
- alerts = alerts.filter(a => a.urgency === "urgent");
1239
- } else {
1240
- alerts = await getAlertsByStatus(filter === "in_progress" ? "in_progress" : "resolved");
1241
- }
1242
-
1243
- // Sort by date (newest first)
1244
- alerts.sort((a, b) => new Date(b.date) - new Date(a.date));
1245
-
1246
- // Apply search filter if any
1247
- if (searchTerm) {
1248
- const filteredAlerts = [];
1249
- for (const alert of alerts) {
1250
- const apartment = await getApartment(alert.apartmentId);
1251
- const resident = apartment.residentId ? await getResident(apartment.residentId) : null;
1252
-
1253
- const alertText = `${getAlertTypeText(alert.type)} ${alert.description} ${apartment.number} ${resident ? resident.firstName + ' ' + resident.lastName : ''}`.toLowerCase();
1254
-
1255
- if (alertText.includes(searchTerm)) {
1256
- filteredAlerts.push(alert);
1257
- }
1258
- }
1259
- alerts = filteredAlerts;
1260
- }
1261
-
1262
- const tableBody = document.getElementById('alertsTableBody');
1263
- tableBody.innerHTML = '';
1264
-
1265
- if (alerts.length === 0) {
1266
- tableBody.innerHTML = `
1267
- <tr>
1268
- <td colspan="6" class="px-6 py-4 text-center text-gray-500">
1269
- Aucune alerte trouvée
1270
- </td>
1271
- </tr>
1272
- `;
1273
- return;
1274
- }
1275
-
1276
- for (const alert of alerts) {
1277
- const apartment = await getApartment(alert.apartmentId);
1278
- const resident = apartment.residentId ? await getResident(apartment.residentId) : null;
1279
-
1280
- let statusClass = "bg-blue-100 text-blue-800";
1281
- let statusText = "En attente";
1282
-
1283
- if (alert.status === "in_progress") {
1284
- statusClass = "bg-yellow-100 text-yellow-800";
1285
- statusText = "En cours";
1286
- } else if (alert.status === "resolved") {
1287
- statusClass = "bg-green-100 text-green-800";
1288
- statusText = "Résolue";
1289
- }
1290
-
1291
- const row = document.createElement('tr');
1292
- row.innerHTML = `
1293
- <td class="px-6 py-4 whitespace-nowrap text-sm text-gray-500">${formatDateTime(alert.date)}</td>
1294
- <td class="px-6 py-4 whitespace-nowrap text-sm font-medium text-gray-900">Appt ${apartment.number}</td>
1295
- <td class="px-6 py-4 whitespace-nowrap text-sm text-gray-500">${resident ? resident.firstName + ' ' + resident.lastName : 'Aucun'}</td>
1296
- <td class="px-6 py-4 whitespace-nowrap text-sm text-gray-500">${getAlertTypeText(alert.type)}</td>
1297
- <td class="px-6 py-4 whitespace-nowrap">
1298
- <span class="px-2 inline-flex text-xs leading-5 font-semibold rounded-full ${statusClass}">${statusText}</span>
1299
- </td>
1300
- <td class="px-6 py-4 whitespace-nowrap text-sm text-gray-500">
1301
- <button onclick="viewAlertDetails(${alert.id})" class="text-blue-600 hover:text-blue-900 mr-3">Voir</button>
1302
- ${alert.status !== "resolved" ? `<button onclick="resolveAlert(${alert.id})" class="text-green-600 hover:text-green-900">Résoudre</button>` : ''}
1303
- </td>
1304
- `;
1305
-
1306
- tableBody.appendChild(row);
1307
- }
1308
- } catch (error) {
1309
- console.error("Error loading alerts:", error);
1310
- showNotification("Erreur", "Impossible de charger les alertes", "error");
1311
- }
1312
- }
1313
-
1314
- async function loadResidents() {
1315
- try {
1316
- const searchTerm = document.getElementById('residentSearch').value.toLowerCase();
1317
- const residents = await getAllResidents();
1318
-
1319
- // Apply search filter if any
1320
- const filteredResidents = searchTerm
1321
- ? residents.filter(r =>
1322
- `${r.firstName} ${r.lastName}`.toLowerCase().includes(searchTerm) ||
1323
- r.email.toLowerCase().includes(searchTerm) ||
1324
- r.phone.toLowerCase().includes(searchTerm))
1325
- : residents;
1326
-
1327
- const tableBody = document.getElementById('residentsTableBody');
1328
- tableBody.innerHTML = '';
1329
-
1330
- if (filteredResidents.length === 0) {
1331
- tableBody.innerHTML = `
1332
- <tr>
1333
- <td colspan="5" class="px-6 py-4 text-center text-gray-500">
1334
- Aucun résident trouvé
1335
- </td>
1336
- </tr>
1337
- `;
1338
- return;
1339
- }
1340
-
1341
- for (const resident of filteredResidents) {
1342
- const apartment = resident.apartmentId ? await getApartment(resident.apartmentId) : null;
1343
-
1344
- const row = document.createElement('tr');
1345
- row.innerHTML = `
1346
- <td class="px-6 py-4 whitespace-nowrap text-sm font-medium text-gray-900">${resident.firstName} ${resident.lastName}</td>
1347
- <td class="px-6 py-4 whitespace
1348
  </html>
 
6
  <title>Gestion d'Appartements - Système d'Alerte</title>
7
  <script src="https://cdn.tailwindcss.com"></script>
8
  <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
9
+ <!-- Le reste du code reste identique -->
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
10
  </head>
11
+ <body>
12
+ <!-- Tout le contenu reste inchangé -->
13
+ <p style="border-radius: 8px; text-align: center; font-size: 12px; color: #fff; margin-top: 16px;position: fixed; left: 8px; bottom: 8px; z-index: 10; background: rgba(0, 0, 0, 0.8); padding: 4px 8px;">Made with <img src="https://enzostvs-deepsite.hf.space/logo.svg" alt="DeepSite Logo" style="width: 16px; height: 16px; vertical-align: middle;display:inline-block;margin-right:3px;filter:brightness(0) invert(1);"><a href="https://enzostvs-deepsite.hf.space" style="color: #fff;text-decoration: underline;" target="_blank" >DeepSite</a> - 🧬 <a href="https://enzostvs-deepsite.hf.space?remix=MORYDIABAGATE/kenza2012" style="color: #fff;text-decoration: underline;" target="_blank" >Remix</a></p></body>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
14
  </html>
prompts.txt CHANGED
@@ -1 +1,2 @@
1
- une base de donne local associée a cette application
 
 
1
+ une base de donne local associée a cette application
2
+ installation sur mon ordinateur