thors1 commited on
Commit
3edd5cd
·
verified ·
1 Parent(s): 4e20bb3

Initial DeepSite commit

Browse files
Files changed (3) hide show
  1. README.md +9 -6
  2. index.html +386 -19
  3. script.js +448 -0
README.md CHANGED
@@ -1,10 +1,13 @@
1
  ---
2
- title: Deepsite Project Dc4ig
3
- emoji: 🏃
4
- colorFrom: yellow
5
- colorTo: yellow
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: DeepSite Project
3
+ colorFrom: green
4
+ colorTo: purple
 
5
  sdk: static
6
+ emoji: 📱
7
+ tags:
8
+ - deepsite-v4
9
  ---
10
 
11
+ # DeepSite Project
12
+
13
+ This project has been created with [DeepSite](https://deepsite.hf.co) AI Vibe Coding.
index.html CHANGED
@@ -1,19 +1,386 @@
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="en">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>MedAdmin Pro - Patient Management</title>
7
+ <script src="https://cdn.tailwindcss.com"></script>
8
+ <script src="https://unpkg.com/lucide@latest"></script>
9
+ <link href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&display=swap" rel="stylesheet">
10
+ <style>
11
+ body {
12
+ font-family: 'Inter', sans-serif;
13
+ }
14
+ .sidebar-link {
15
+ transition: all 0.2s;
16
+ }
17
+ .sidebar-link:hover {
18
+ background-color: rgba(255, 255, 255, 0.05);
19
+ }
20
+ .sidebar-link.active {
21
+ background-color: rgba(59, 130, 246, 0.15);
22
+ color: #60a5fa;
23
+ border-right: 3px solid #60a5fa;
24
+ }
25
+ .table-row:hover {
26
+ background-color: #f8fafc;
27
+ }
28
+ .sort-icon {
29
+ transition: transform 0.2s;
30
+ }
31
+ .sort-asc {
32
+ transform: rotate(0deg);
33
+ }
34
+ .sort-desc {
35
+ transform: rotate(180deg);
36
+ }
37
+ /* Custom scrollbar for table */
38
+ .custom-scrollbar::-webkit-scrollbar {
39
+ height: 8px;
40
+ width: 8px;
41
+ }
42
+ .custom-scrollbar::-webkit-scrollbar-track {
43
+ background: #f1f5f9;
44
+ }
45
+ .custom-scrollbar::-webkit-scrollbar-thumb {
46
+ background: #cbd5e1;
47
+ border-radius: 4px;
48
+ }
49
+ .custom-scrollbar::-webkit-scrollbar-thumb:hover {
50
+ background: #94a3b8;
51
+ }
52
+ </style>
53
+ </head>
54
+ <body class="bg-gray-50 text-gray-800">
55
+
56
+ <!-- Mobile Overlay -->
57
+ <div id="mobile-overlay" class="fixed inset-0 bg-black bg-opacity-50 z-40 hidden lg:hidden" onclick="toggleSidebar()"></div>
58
+
59
+ <div class="flex h-screen overflow-hidden">
60
+
61
+ <!-- Sidebar -->
62
+ <aside id="sidebar" class="fixed lg:static inset-y-0 left-0 z-50 w-64 bg-slate-900 text-white transform -translate-x-full lg:translate-x-0 transition-transform duration-300 ease-in-out flex flex-col">
63
+ <!-- Logo -->
64
+ <div class="h-16 flex items-center px-6 border-b border-slate-800">
65
+ <i data-lucide="activity" class="w-8 h-8 text-blue-400 mr-3"></i>
66
+ <span class="text-xl font-bold tracking-tight">MedAdmin</span>
67
+ </div>
68
+
69
+ <!-- Navigation -->
70
+ <nav class="flex-1 overflow-y-auto py-4">
71
+ <div class="px-4 mb-2 text-xs font-semibold text-slate-400 uppercase tracking-wider">Main</div>
72
+ <ul class="space-y-1">
73
+ <li>
74
+ <a href="#" class="sidebar-link flex items-center px-6 py-3 text-sm font-medium text-slate-300">
75
+ <i data-lucide="layout-dashboard" class="w-5 h-5 mr-3"></i>
76
+ Dashboard
77
+ </a>
78
+ </li>
79
+ <li>
80
+ <a href="#" class="sidebar-link active flex items-center px-6 py-3 text-sm font-medium">
81
+ <i data-lucide="users" class="w-5 h-5 mr-3"></i>
82
+ Patients
83
+ </a>
84
+ </li>
85
+ <li>
86
+ <a href="#" class="sidebar-link flex items-center px-6 py-3 text-sm font-medium text-slate-300">
87
+ <i data-lucide="calendar" class="w-5 h-5 mr-3"></i>
88
+ Appointments
89
+ </a>
90
+ </li>
91
+ <li>
92
+ <a href="#" class="sidebar-link flex items-center px-6 py-3 text-sm font-medium text-slate-300">
93
+ <i data-lucide="file-text" class="w-5 h-5 mr-3"></i>
94
+ Medical Records
95
+ </a>
96
+ </li>
97
+ </ul>
98
+
99
+ <div class="px-4 mt-8 mb-2 text-xs font-semibold text-slate-400 uppercase tracking-wider">Management</div>
100
+ <ul class="space-y-1">
101
+ <li>
102
+ <a href="#" class="sidebar-link flex items-center px-6 py-3 text-sm font-medium text-slate-300">
103
+ <i data-lucide="user-plus" class="w-5 h-5 mr-3"></i>
104
+ Doctors
105
+ </a>
106
+ </li>
107
+ <li>
108
+ <a href="#" class="sidebar-link flex items-center px-6 py-3 text-sm font-medium text-slate-300">
109
+ <i data-lucide="pill" class="w-5 h-5 mr-3"></i>
110
+ Pharmacy
111
+ </a>
112
+ </li>
113
+ <li>
114
+ <a href="#" class="sidebar-link flex items-center px-6 py-3 text-sm font-medium text-slate-300">
115
+ <i data-lucide="credit-card" class="w-5 h-5 mr-3"></i>
116
+ Billing
117
+ </a>
118
+ </li>
119
+ </ul>
120
+ </nav>
121
+
122
+ <!-- User Profile -->
123
+ <div class="border-t border-slate-800 p-4">
124
+ <div class="flex items-center">
125
+ <img src="http://static.photos/people/200x200/42" alt="Admin" class="w-10 h-10 rounded-full border-2 border-slate-700">
126
+ <div class="ml-3">
127
+ <p class="text-sm font-medium text-white">Dr. Sarah Chen</p>
128
+ <p class="text-xs text-slate-400">Administrator</p>
129
+ </div>
130
+ </div>
131
+ </div>
132
+ </aside>
133
+
134
+ <!-- Main Content -->
135
+ <div class="flex-1 flex flex-col overflow-hidden">
136
+
137
+ <!-- Header -->
138
+ <header class="h-16 bg-white border-b border-gray-200 flex items-center justify-between px-4 lg:px-8">
139
+ <div class="flex items-center">
140
+ <button onclick="toggleSidebar()" class="lg:hidden p-2 rounded-md text-gray-600 hover:bg-gray-100 mr-4">
141
+ <i data-lucide="menu" class="w-6 h-6"></i>
142
+ </button>
143
+ <h1 class="text-2xl font-bold text-gray-800">Patients</h1>
144
+ </div>
145
+
146
+ <div class="flex items-center space-x-4">
147
+ <button class="p-2 rounded-full text-gray-500 hover:bg-gray-100 relative">
148
+ <i data-lucide="bell" class="w-5 h-5"></i>
149
+ <span class="absolute top-1 right-1 w-2 h-2 bg-red-500 rounded-full"></span>
150
+ </button>
151
+ <button onclick="openAddModal()" class="hidden sm:flex items-center px-4 py-2 bg-blue-600 text-white rounded-lg hover:bg-blue-700 transition-colors shadow-sm">
152
+ <i data-lucide="plus" class="w-4 h-4 mr-2"></i>
153
+ Add Patient
154
+ </button>
155
+ </div>
156
+ </header>
157
+
158
+ <!-- Content -->
159
+ <main class="flex-1 overflow-x-hidden overflow-y-auto bg-gray-50 p-4 lg:p-8">
160
+
161
+ <!-- Stats Cards -->
162
+ <div class="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-4 gap-4 mb-6">
163
+ <div class="bg-white rounded-xl shadow-sm p-6 border border-gray-100">
164
+ <div class="flex items-center justify-between">
165
+ <div>
166
+ <p class="text-sm font-medium text-gray-600">Total Patients</p>
167
+ <p class="text-2xl font-bold text-gray-900 mt-1">1,284</p>
168
+ </div>
169
+ <div class="p-3 bg-blue-50 rounded-lg">
170
+ <i data-lucide="users" class="w-6 h-6 text-blue-600"></i>
171
+ </div>
172
+ </div>
173
+ <div class="mt-4 flex items-center text-sm">
174
+ <span class="text-green-600 flex items-center font-medium">
175
+ <i data-lucide="trending-up" class="w-4 h-4 mr-1"></i>
176
+ +12%
177
+ </span>
178
+ <span class="text-gray-500 ml-2">from last month</span>
179
+ </div>
180
+ </div>
181
+
182
+ <div class="bg-white rounded-xl shadow-sm p-6 border border-gray-100">
183
+ <div class="flex items-center justify-between">
184
+ <div>
185
+ <p class="text-sm font-medium text-gray-600">Approved</p>
186
+ <p class="text-2xl font-bold text-gray-900 mt-1">1,156</p>
187
+ </div>
188
+ <div class="p-3 bg-emerald-50 rounded-lg">
189
+ <i data-lucide="check-circle" class="w-6 h-6 text-emerald-600"></i>
190
+ </div>
191
+ </div>
192
+ <div class="mt-4 flex items-center text-sm">
193
+ <span class="text-emerald-600 font-medium">90.1%</span>
194
+ <span class="text-gray-500 ml-2">approval rate</span>
195
+ </div>
196
+ </div>
197
+
198
+ <div class="bg-white rounded-xl shadow-sm p-6 border border-gray-100">
199
+ <div class="flex items-center justify-between">
200
+ <div>
201
+ <p class="text-sm font-medium text-gray-600">Expired</p>
202
+ <p class="text-2xl font-bold text-gray-900 mt-1">128</p>
203
+ </div>
204
+ <div class="p-3 bg-rose-50 rounded-lg">
205
+ <i data-lucide="alert-circle" class="w-6 h-6 text-rose-600"></i>
206
+ </div>
207
+ </div>
208
+ <div class="mt-4 flex items-center text-sm">
209
+ <span class="text-rose-600 flex items-center font-medium">
210
+ <i data-lucide="trending-up" class="w-4 h-4 mr-1"></i>
211
+ +5%
212
+ </span>
213
+ <span class="text-gray-500 ml-2">from last month</span>
214
+ </div>
215
+ </div>
216
+
217
+ <div class="bg-white rounded-xl shadow-sm p-6 border border-gray-100">
218
+ <div class="flex items-center justify-between">
219
+ <div>
220
+ <p class="text-sm font-medium text-gray-600">Pending</p>
221
+ <p class="text-2xl font-bold text-gray-900 mt-1">42</p>
222
+ </div>
223
+ <div class="p-3 bg-amber-50 rounded-lg">
224
+ <i data-lucide="clock" class="w-6 h-6 text-amber-600"></i>
225
+ </div>
226
+ </div>
227
+ <div class="mt-4 flex items-center text-sm">
228
+ <span class="text-gray-500">Requires attention</span>
229
+ </div>
230
+ </div>
231
+ </div>
232
+
233
+ <!-- Filters & Search -->
234
+ <div class="bg-white rounded-xl shadow-sm border border-gray-200 mb-6">
235
+ <div class="p-4 border-b border-gray-200 flex flex-col sm:flex-row sm:items-center justify-between gap-4">
236
+ <div class="relative flex-1 max-w-md">
237
+ <i data-lucide="search" class="absolute left-3 top-1/2 transform -translate-y-1/2 text-gray-400 w-5 h-5"></i>
238
+ <input type="text" id="searchInput" placeholder="Search patients by name, email, or phone..."
239
+ class="w-full pl-10 pr-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500 outline-none transition-all"
240
+ onkeyup="filterTable()">
241
+ </div>
242
+ <div class="flex items-center space-x-3">
243
+ <select id="statusFilter" onchange="filterTable()" class="px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 outline-none bg-white text-sm">
244
+ <option value="all">All Status</option>
245
+ <option value="approved">Approved</option>
246
+ <option value="expired">Expired</option>
247
+ </select>
248
+ <button onclick="exportData()" class="p-2 text-gray-600 hover:bg-gray-100 rounded-lg border border-gray-300 transition-colors" title="Export">
249
+ <i data-lucide="download" class="w-5 h-5"></i>
250
+ </button>
251
+ </div>
252
+ </div>
253
+
254
+ <!-- Table Container -->
255
+ <div class="overflow-x-auto custom-scrollbar">
256
+ <table class="w-full text-left border-collapse">
257
+ <thead>
258
+ <tr class="bg-gray-50 border-b border-gray-200">
259
+ <th class="px-6 py-4 text-xs font-semibold text-gray-500 uppercase tracking-wider cursor-pointer hover:bg-gray-100 transition-colors select-none" onclick="sortTable('name')">
260
+ <div class="flex items-center space-x-1">
261
+ <span>Patient</span>
262
+ <i data-lucide="chevrons-up-down" class="w-4 h-4 sort-icon" id="sort-name"></i>
263
+ </div>
264
+ </th>
265
+ <th class="px-6 py-4 text-xs font-semibold text-gray-500 uppercase tracking-wider">
266
+ Tags
267
+ </th>
268
+ <th class="px-6 py-4 text-xs font-semibold text-gray-500 uppercase tracking-wider cursor-pointer hover:bg-gray-100 transition-colors select-none" onclick="sortTable('created')">
269
+ <div class="flex items-center space-x-1">
270
+ <span>Created</span>
271
+ <i data-lucide="chevrons-up-down" class="w-4 h-4 sort-icon" id="sort-created"></i>
272
+ </div>
273
+ </th>
274
+ <th class="px-6 py-4 text-xs font-semibold text-gray-500 uppercase tracking-wider cursor-pointer hover:bg-gray-100 transition-colors select-none" onclick="sortTable('approved')">
275
+ <div class="flex items-center space-x-1">
276
+ <span>Approved</span>
277
+ <i data-lucide="chevrons-up-down" class="w-4 h-4 sort-icon" id="sort-approved"></i>
278
+ </div>
279
+ </th>
280
+ <th class="px-6 py-4 text-xs font-semibold text-gray-500 uppercase tracking-wider cursor-pointer hover:bg-gray-100 transition-colors select-none" onclick="sortTable('expires')">
281
+ <div class="flex items-center space-x-1">
282
+ <span>Expires</span>
283
+ <i data-lucide="chevrons-up-down" class="w-4 h-4 sort-icon" id="sort-expires"></i>
284
+ </div>
285
+ </th>
286
+ <th class="px-6 py-4 text-xs font-semibold text-gray-500 uppercase tracking-wider">
287
+ Notes
288
+ </th>
289
+ <th class="px-6 py-4 text-xs font-semibold text-gray-500 uppercase tracking-wider">
290
+ Contact
291
+ </th>
292
+ <th class="px-6 py-4 text-xs font-semibold text-gray-500 uppercase tracking-wider cursor-pointer hover:bg-gray-100 transition-colors select-none" onclick="sortTable('status')">
293
+ <div class="flex items-center space-x-1">
294
+ <span>Status</span>
295
+ <i data-lucide="chevrons-up-down" class="w-4 h-4 sort-icon" id="sort-status"></i>
296
+ </div>
297
+ </th>
298
+ <th class="px-6 py-4 text-xs font-semibold text-gray-500 uppercase tracking-wider text-right">
299
+ Actions
300
+ </th>
301
+ </tr>
302
+ </thead>
303
+ <tbody id="tableBody" class="divide-y divide-gray-200 bg-white">
304
+ <!-- Data will be populated by JavaScript -->
305
+ </tbody>
306
+ </table>
307
+ </div>
308
+
309
+ <!-- Pagination -->
310
+ <div class="px-6 py-4 border-t border-gray-200 flex items-center justify-between">
311
+ <div class="text-sm text-gray-500">
312
+ Showing <span class="font-medium text-gray-900" id="showingStart">1</span> to <span class="font-medium text-gray-900" id="showingEnd">10</span> of <span class="font-medium text-gray-900" id="totalItems">50</span> results
313
+ </div>
314
+ <div class="flex items-center space-x-2">
315
+ <button onclick="changePage(-1)" class="px-3 py-1 border border-gray-300 rounded-md text-sm hover:bg-gray-50 disabled:opacity-50 disabled:cursor-not-allowed" id="prevBtn">
316
+ <i data-lucide="chevron-left" class="w-4 h-4"></i>
317
+ </button>
318
+ <div class="flex space-x-1" id="paginationNumbers">
319
+ <!-- Generated by JS -->
320
+ </div>
321
+ <button onclick="changePage(1)" class="px-3 py-1 border border-gray-300 rounded-md text-sm hover:bg-gray-50 disabled:opacity-50 disabled:cursor-not-allowed" id="nextBtn">
322
+ <i data-lucide="chevron-right" class="w-4 h-4"></i>
323
+ </button>
324
+ </div>
325
+ </div>
326
+ </div>
327
+ </main>
328
+ </div>
329
+ </div>
330
+
331
+ <!-- Add Patient Modal -->
332
+ <div id="addModal" class="fixed inset-0 z-50 hidden">
333
+ <div class="absolute inset-0 bg-black bg-opacity-50" onclick="closeAddModal()"></div>
334
+ <div class="absolute inset-0 flex items-center justify-center p-4">
335
+ <div class="bg-white rounded-xl shadow-2xl max-w-2xl w-full max-h-[90vh] overflow-y-auto transform transition-all scale-100">
336
+ <div class="p-6 border-b border-gray-200 flex justify-between items-center sticky top-0 bg-white">
337
+ <h2 class="text-xl font-bold text-gray-800">Add New Patient</h2>
338
+ <button onclick="closeAddModal()" class="text-gray-400 hover:text-gray-600">
339
+ <i data-lucide="x" class="w-6 h-6"></i>
340
+ </button>
341
+ </div>
342
+ <div class="p-6 space-y-4">
343
+ <div class="grid grid-cols-1 md:grid-cols-2 gap-4">
344
+ <div>
345
+ <label class="block text-sm font-medium text-gray-700 mb-1">Full Name</label>
346
+ <input type="text" class="w-full px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 outline-none" placeholder="John Doe">
347
+ </div>
348
+ <div>
349
+ <label class="block text-sm font-medium text-gray-700 mb-1">Email</label>
350
+ <input type="email" class="w-full px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 outline-none" placeholder="john@example.com">
351
+ </div>
352
+ <div>
353
+ <label class="block text-sm font-medium text-gray-700 mb-1">Phone</label>
354
+ <input type="tel" class="w-full px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 outline-none" placeholder="+1 (555) 000-0000">
355
+ </div>
356
+ <div>
357
+ <label class="block text-sm font-medium text-gray-700 mb-1">Date of Birth</label>
358
+ <input type="date" class="w-full px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 outline-none">
359
+ </div>
360
+ </div>
361
+ <div>
362
+ <label class="block text-sm font-medium text-gray-700 mb-1">Medical Notes</label>
363
+ <textarea rows="3" class="w-full px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 outline-none" placeholder="Enter medical history or notes..."></textarea>
364
+ </div>
365
+ </div>
366
+ <div class="p-6 border-t border-gray-200 bg-gray-50 flex justify-end space-x-3 sticky bottom-0">
367
+ <button onclick="closeAddModal()" class="px-4 py-2 text-gray-700 hover:bg-gray-200 rounded-lg transition-colors">Cancel</button>
368
+ <button onclick="savePatient()" class="px-4 py-2 bg-blue-600 text-white rounded-lg hover:bg-blue-700 transition-colors">Save Patient</button>
369
+ </div>
370
+ </div>
371
+ </div>
372
+ </div>
373
+
374
+ <!-- Toast Notification -->
375
+ <div id="toast" class="fixed bottom-4 right-4 bg-gray-800 text-white px-6 py-3 rounded-lg shadow-lg transform translate-y-20 opacity-0 transition-all duration-300 z-50 flex items-center">
376
+ <i data-lucide="check-circle" class="w-5 h-5 mr-2 text-green-400"></i>
377
+ <span id="toastMessage">Operation successful</span>
378
+ </div>
379
+
380
+ <script src="script.js"></script>
381
+ <script>
382
+ lucide.createIcons();
383
+ </script>
384
+ <script src="https://deepsite.hf.co/deepsite-badge.js"></script>
385
+ </body>
386
+ </html>
script.js ADDED
@@ -0,0 +1,448 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ // Sample patient data
2
+ let patients = [
3
+ {
4
+ id: 1,
5
+ name: "Emma Thompson",
6
+ avatar: "http://static.photos/people/200x200/1",
7
+ tags: ["Critical", "VIP"],
8
+ created: "2024-01-15",
9
+ approved: "2024-01-16",
10
+ expires: "2025-01-16",
11
+ notes: "Severe allergy to penicillin. Requires constant monitoring.",
12
+ phone: "+1 (555) 123-4567",
13
+ email: "emma.t@email.com",
14
+ status: "approved"
15
+ },
16
+ {
17
+ id: 2,
18
+ name: "James Wilson",
19
+ avatar: "http://static.photos/people/200x200/2",
20
+ tags: ["New Patient"],
21
+ created: "2024-03-20",
22
+ approved: "2024-03-21",
23
+ expires: "2024-09-21",
24
+ notes: "Post-surgery recovery. Physical therapy scheduled.",
25
+ phone: "+1 (555) 234-5678",
26
+ email: "j.wilson@email.com",
27
+ status: "expired"
28
+ },
29
+ {
30
+ id: 3,
31
+ name: "Sarah Chen",
32
+ avatar: "http://static.photos/people/200x200/3",
33
+ tags: ["Follow-up"],
34
+ created: "2024-02-10",
35
+ approved: "2024-02-11",
36
+ expires: "2025-02-11",
37
+ notes: "Routine diabetes check. Blood sugar levels stable.",
38
+ phone: "+1 (555) 345-6789",
39
+ email: "sarah.chen@email.com",
40
+ status: "approved"
41
+ },
42
+ {
43
+ id: 4,
44
+ name: "Michael Brown",
45
+ avatar: "http://static.photos/people/200x200/4",
46
+ tags: ["Urgent"],
47
+ created: "2024-04-05",
48
+ approved: "2024-04-05",
49
+ expires: "2024-10-05",
50
+ notes: "Cardiac monitoring required. High blood pressure history.",
51
+ phone: "+1 (555) 456-7890",
52
+ email: "mbrown@email.com",
53
+ status: "expired"
54
+ },
55
+ {
56
+ id: 5,
57
+ name: "Lisa Anderson",
58
+ avatar: "http://static.photos/people/200x200/5",
59
+ tags: ["Regular"],
60
+ created: "2024-01-28",
61
+ approved: "2024-01-29",
62
+ expires: "2025-01-29",
63
+ notes: "Annual physical completed. All vitals normal.",
64
+ phone: "+1 (555) 567-8901",
65
+ email: "lisa.a@email.com",
66
+ status: "approved"
67
+ },
68
+ {
69
+ id: 6,
70
+ name: "David Martinez",
71
+ avatar: "http://static.photos/people/200x200/6",
72
+ tags: ["New Patient", "Insurance Pending"],
73
+ created: "2024-05-12",
74
+ approved: "2024-05-13",
75
+ expires: "2025-05-13",
76
+ notes: "Initial consultation completed. Awaiting test results.",
77
+ phone: "+1 (555) 678-9012",
78
+ email: "d.martinez@email.com",
79
+ status: "approved"
80
+ },
81
+ {
82
+ id: 7,
83
+ name: "Jennifer Taylor",
84
+ avatar: "http://static.photos/people/200x200/7",
85
+ tags: ["Critical"],
86
+ created: "2023-11-15",
87
+ approved: "2023-11-16",
88
+ expires: "2024-05-16",
89
+ notes: "Oncology patient. Chemotherapy cycle 4 of 6.",
90
+ phone: "+1 (555) 789-0123",
91
+ email: "jtaylor@email.com",
92
+ status: "expired"
93
+ },
94
+ {
95
+ id: 8,
96
+ name: "Robert Johnson",
97
+ avatar: "http://static.photos/people/200x200/8",
98
+ tags: ["Senior"],
99
+ created: "2024-03-01",
100
+ approved: "2024-03-02",
101
+ expires: "2025-03-02",
102
+ notes: "Arthritis management. Mobility assistance required.",
103
+ phone: "+1 (555) 890-1234",
104
+ email: "r.johnson@email.com",
105
+ status: "approved"
106
+ },
107
+ {
108
+ id: 9,
109
+ name: "Amanda White",
110
+ avatar: "http://static.photos/people/200x200/9",
111
+ tags: ["Pediatric"],
112
+ created: "2024-04-20",
113
+ approved: "2024-04-21",
114
+ expires: "2025-04-21",
115
+ notes: "Vaccination schedule up to date. Growth chart normal.",
116
+ phone: "+1 (555) 901-2345",
117
+ email: "amanda.w@email.com",
118
+ status: "approved"
119
+ },
120
+ {
121
+ id: 10,
122
+ name: "Christopher Lee",
123
+ avatar: "http://static.photos/people/200x200/10",
124
+ tags: ["Follow-up", "Physical Therapy"],
125
+ created: "2024-02-28",
126
+ approved: "2024-02-29",
127
+ expires: "2024-08-29",
128
+ notes: "Knee replacement recovery. PT exercises 3x weekly.",
129
+ phone: "+1 (555) 012-3456",
130
+ email: "chris.lee@email.com",
131
+ status: "expired"
132
+ },
133
+ {
134
+ id: 11,
135
+ name: "Maria Garcia",
136
+ avatar: "http://static.photos/people/200x200/11",
137
+ tags: ["Prenatal"],
138
+ created: "2024-01-10",
139
+ approved: "2024-01-11",
140
+ expires: "2024-10-11",
141
+ notes: "Second trimester. Ultrasound scheduled next week.",
142
+ phone: "+1 (555) 111-2222",
143
+ email: "maria.g@email.com",
144
+ status: "approved"
145
+ },
146
+ {
147
+ id: 12,
148
+ name: "Kevin Davis",
149
+ avatar: "http://static.photos/people/200x200/12",
150
+ tags: ["Emergency"],
151
+ created: "2024-05-15",
152
+ approved: "2024-05-15",
153
+ expires: "2024-11-15",
154
+ notes: "Fractured wrist. Cast applied, follow-up in 2 weeks.",
155
+ phone: "+1 (555) 222-3333",
156
+ email: "kevin.d@email.com",
157
+ status: "expired"
158
+ }
159
+ ];
160
+
161
+ // State management
162
+ let currentPage = 1;
163
+ let itemsPerPage = 10;
164
+ let sortColumn = null;
165
+ let sortDirection = 'asc';
166
+ let filteredData = [...patients];
167
+
168
+ // Initialize
169
+ document.addEventListener('DOMContentLoaded', () => {
170
+ renderTable();
171
+ lucide.createIcons();
172
+ });
173
+
174
+ // Sidebar toggle for mobile
175
+ function toggleSidebar() {
176
+ const sidebar = document.getElementById('sidebar');
177
+ const overlay = document.getElementById('mobile-overlay');
178
+ const isClosed = sidebar.classList.contains('-translate-x-full');
179
+
180
+ if (isClosed) {
181
+ sidebar.classList.remove('-translate-x-full');
182
+ overlay.classList.remove('hidden');
183
+ } else {
184
+ sidebar.classList.add('-translate-x-full');
185
+ overlay.classList.add('hidden');
186
+ }
187
+ }
188
+
189
+ // Sorting functionality
190
+ function sortTable(column) {
191
+ // Reset all sort icons
192
+ document.querySelectorAll('.sort-icon').forEach(icon => {
193
+ icon.setAttribute('data-lucide', 'chevrons-up-down');
194
+ icon.classList.remove('sort-asc', 'sort-desc');
195
+ });
196
+
197
+ // Toggle direction if same column
198
+ if (sortColumn === column) {
199
+ sortDirection = sortDirection === 'asc' ? 'desc' : 'asc';
200
+ } else {
201
+ sortColumn = column;
202
+ sortDirection = 'asc';
203
+ }
204
+
205
+ // Update icon for current column
206
+ const currentIcon = document.getElementById(`sort-${column}`);
207
+ if (currentIcon) {
208
+ currentIcon.setAttribute('data-lucide', sortDirection === 'asc' ? 'chevron-up' : 'chevron-down');
209
+ currentIcon.classList.add(sortDirection === 'asc' ? 'sort-asc' : 'sort-desc');
210
+ }
211
+
212
+ // Sort data
213
+ filteredData.sort((a, b) => {
214
+ let valA = a[column];
215
+ let valB = b[column];
216
+
217
+ if (column === 'name') {
218
+ valA = a.name.toLowerCase();
219
+ valB = b.name.toLowerCase();
220
+ }
221
+
222
+ if (valA < valB) return sortDirection === 'asc' ? -1 : 1;
223
+ if (valA > valB) return sortDirection === 'asc' ? 1 : -1;
224
+ return 0;
225
+ });
226
+
227
+ lucide.createIcons();
228
+ renderTable();
229
+ }
230
+
231
+ // Filter functionality
232
+ function filterTable() {
233
+ const searchTerm = document.getElementById('searchInput').value.toLowerCase();
234
+ const statusFilter = document.getElementById('statusFilter').value;
235
+
236
+ filteredData = patients.filter(patient => {
237
+ const matchesSearch = patient.name.toLowerCase().includes(searchTerm) ||
238
+ patient.email.toLowerCase().includes(searchTerm) ||
239
+ patient.phone.includes(searchTerm);
240
+
241
+ const matchesStatus = statusFilter === 'all' || patient.status === statusFilter;
242
+
243
+ return matchesSearch && matchesStatus;
244
+ });
245
+
246
+ currentPage = 1;
247
+ renderTable();
248
+ }
249
+
250
+ // Render table
251
+ function renderTable() {
252
+ const tbody = document.getElementById('tableBody');
253
+ const start = (currentPage - 1) * itemsPerPage;
254
+ const end = start + itemsPerPage;
255
+ const paginatedData = filteredData.slice(start, end);
256
+
257
+ tbody.innerHTML = paginatedData.map(patient => {
258
+ const statusColors = {
259
+ approved: 'bg-emerald-100 text-emerald-800 border-emerald-200',
260
+ expired: 'bg-rose-100 text-rose-800 border-rose-200'
261
+ };
262
+
263
+ const statusIcons = {
264
+ approved: 'check-circle',
265
+ expired: 'x-circle'
266
+ };
267
+
268
+ const tagColors = {
269
+ 'Critical': 'bg-red-100 text-red-700',
270
+ 'VIP': 'bg-purple-100 text-purple-700',
271
+ 'New Patient': 'bg-blue-100 text-blue-700',
272
+ 'Follow-up': 'bg-amber-100 text-amber-700',
273
+ 'Urgent': 'bg-orange-100 text-orange-700',
274
+ 'Regular': 'bg-gray-100 text-gray-700',
275
+ 'Insurance Pending': 'bg-yellow-100 text-yellow-700',
276
+ 'Senior': 'bg-indigo-100 text-indigo-700',
277
+ 'Pediatric': 'bg-pink-100 text-pink-700',
278
+ 'Prenatal': 'bg-teal-100 text-teal-700',
279
+ 'Emergency': 'bg-red-100 text-red-700',
280
+ 'Physical Therapy': 'bg-cyan-100 text-cyan-700'
281
+ };
282
+
283
+ return `
284
+ <tr class="table-row transition-colors border-b border-gray-100 last:border-0">
285
+ <td class="px-6 py-4 whitespace-nowrap">
286
+ <div class="flex items-center">
287
+ <img class="h-10 w-10 rounded-full object-cover border-2 border-gray-200" src="${patient.avatar}" alt="">
288
+ <div class="ml-4">
289
+ <div class="text-sm font-semibold text-gray-900">${patient.name}</div>
290
+ <div class="text-xs text-gray-500">ID: #${String(patient.id).padStart(4, '0')}</div>
291
+ </div>
292
+ </div>
293
+ </td>
294
+ <td class="px-6 py-4">
295
+ <div class="flex flex-wrap gap-1">
296
+ ${patient.tags.map(tag => `
297
+ <span class="inline-flex items-center px-2 py-0.5 rounded text-xs font-medium ${tagColors[tag] || 'bg-gray-100 text-gray-700'}">
298
+ ${tag}
299
+ </span>
300
+ `).join('')}
301
+ </div>
302
+ </td>
303
+ <td class="px-6 py-4 whitespace-nowrap text-sm text-gray-600">
304
+ ${formatDate(patient.created)}
305
+ </td>
306
+ <td class="px-6 py-4 whitespace-nowrap text-sm text-gray-600">
307
+ ${formatDate(patient.approved)}
308
+ </td>
309
+ <td class="px-6 py-4 whitespace-nowrap text-sm text-gray-600">
310
+ ${formatDate(patient.expires)}
311
+ </td>
312
+ <td class="px-6 py-4">
313
+ <div class="text-sm text-gray-600 max-w-xs truncate" title="${patient.notes}">
314
+ ${patient.notes}
315
+ </div>
316
+ </td>
317
+ <td class="px-6 py-4 whitespace-nowrap">
318
+ <div class="text-sm text-gray-900">${patient.phone}</div>
319
+ <div class="text-sm text-gray-500">${patient.email}</div>
320
+ </td>
321
+ <td class="px-6 py-4 whitespace-nowrap">
322
+ <span class="inline-flex items-center px-3 py-1 rounded-full text-xs font-medium border ${statusColors[patient.status]} capitalize">
323
+ <i data-lucide="${statusIcons[patient.status]}" class="w-3 h-3 mr-1"></i>
324
+ ${patient.status}
325
+ </span>
326
+ </td>
327
+ <td class="px-6 py-4 whitespace-nowrap text-right text-sm font-medium">
328
+ <div class="flex items-center justify-end space-x-2">
329
+ <button onclick="viewPatient(${patient.id})" class="text-blue-600 hover:text-blue-900 p-1 hover:bg-blue-50 rounded transition-colors" title="View">
330
+ <i data-lucide="eye" class="w-4 h-4"></i>
331
+ </button>
332
+ <button onclick="editPatient(${patient.id})" class="text-gray-600 hover:text-gray-900 p-1 hover:bg-gray-100 rounded transition-colors" title="Edit">
333
+ <i data-lucide="edit-2" class="w-4 h-4"></i>
334
+ </button>
335
+ <button onclick="deletePatient(${patient.id})" class="text-red-600 hover:text-red-900 p-1 hover:bg-red-50 rounded transition-colors" title="Delete">
336
+ <i data-lucide="trash-2" class="w-4 h-4"></i>
337
+ </button>
338
+ </div>
339
+ </td>
340
+ </tr>
341
+ `;
342
+ }).join('');
343
+
344
+ // Update pagination info
345
+ document.getElementById('showingStart').textContent = filteredData.length > 0 ? start + 1 : 0;
346
+ document.getElementById('showingEnd').textContent = Math.min(end, filteredData.length);
347
+ document.getElementById('totalItems').textContent = filteredData.length;
348
+
349
+ // Update pagination buttons
350
+ document.getElementById('prevBtn').disabled = currentPage === 1;
351
+ document.getElementById('nextBtn').disabled = end >= filteredData.length;
352
+
353
+ renderPaginationNumbers();
354
+ lucide.createIcons();
355
+ }
356
+
357
+ function renderPaginationNumbers() {
358
+ const totalPages = Math.ceil(filteredData.length / itemsPerPage);
359
+ const container = document.getElementById('paginationNumbers');
360
+ let html = '';
361
+
362
+ for (let i = 1; i <= totalPages; i++) {
363
+ if (i === 1 || i === totalPages || (i >= currentPage - 1 && i <= currentPage + 1)) {
364
+ html += `
365
+ <button onclick="goToPage(${i})" class="w-8 h-8 rounded-md text-sm font-medium transition-colors ${currentPage === i ? 'bg-blue-600 text-white' : 'text-gray-700 hover:bg-gray-100 border border-gray-300'}">
366
+ ${i}
367
+ </button>
368
+ `;
369
+ } else if (i === currentPage - 2 || i === currentPage + 2) {
370
+ html += `<span class="px-2 text-gray-400">...</span>`;
371
+ }
372
+ }
373
+
374
+ container.innerHTML = html;
375
+ }
376
+
377
+ function changePage(direction) {
378
+ const totalPages = Math.ceil(filteredData.length / itemsPerPage);
379
+ const newPage = currentPage + direction;
380
+
381
+ if (newPage >= 1 && newPage <= totalPages) {
382
+ currentPage = newPage;
383
+ renderTable();
384
+ }
385
+ }
386
+
387
+ function goToPage(page) {
388
+ currentPage = page;
389
+ renderTable();
390
+ }
391
+
392
+ function formatDate(dateString) {
393
+ const options = { year: 'numeric', month: 'short', day: 'numeric' };
394
+ return new Date(dateString).toLocaleDateString('en-US', options);
395
+ }
396
+
397
+ // Action handlers
398
+ function viewPatient(id) {
399
+ showToast('Viewing patient details...');
400
+ }
401
+
402
+ function editPatient(id) {
403
+ showToast('Opening edit mode...');
404
+ }
405
+
406
+ function deletePatient(id) {
407
+ if (confirm('Are you sure you want to delete this patient record?')) {
408
+ patients = patients.filter(p => p.id !== id);
409
+ filterTable();
410
+ showToast('Patient deleted successfully');
411
+ }
412
+ }
413
+
414
+ function openAddModal() {
415
+ document.getElementById('addModal').classList.remove('hidden');
416
+ }
417
+
418
+ function closeAddModal() {
419
+ document.getElementById('addModal').classList.add('hidden');
420
+ }
421
+
422
+ function savePatient() {
423
+ closeAddModal();
424
+ showToast('New patient added successfully');
425
+ }
426
+
427
+ function exportData() {
428
+ showToast('Exporting patient data to CSV...');
429
+ }
430
+
431
+ function showToast(message) {
432
+ const toast = document.getElementById('toast');
433
+ const toastMessage = document.getElementById('toastMessage');
434
+
435
+ toastMessage.textContent = message;
436
+ toast.classList.remove('translate-y-20', 'opacity-0');
437
+
438
+ setTimeout(() => {
439
+ toast.classList.add('translate-y-20', 'opacity-0');
440
+ }, 3000);
441
+ }
442
+
443
+ // Close modal on escape key
444
+ document.addEventListener('keydown', (e) => {
445
+ if (e.key === 'Escape') {
446
+ closeAddModal();
447
+ }
448
+ });