rajkhanke commited on
Commit
330f2be
·
verified ·
1 Parent(s): f97947a

Update templates/doctor_dashboard.html

Browse files
Files changed (1) hide show
  1. templates/doctor_dashboard.html +313 -181
templates/doctor_dashboard.html CHANGED
@@ -6,171 +6,204 @@
6
  <title>Doctor Dashboard - Patient Care Management</title>
7
  <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0-alpha1/dist/css/bootstrap.min.css" rel="stylesheet">
8
  <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.1.1/css/all.min.css">
 
9
  <style>
10
  :root {
11
- --primary-color: #4e73df;
12
- --secondary-color: #1cc88a;
13
- --danger-color: #e74a3b;
14
- --warning-color: #f6c23e;
15
- --info-color: #36b9cc;
16
- --dark-color: #5a5c69;
 
 
17
  }
18
-
19
  body {
20
  font-family: 'Nunito', sans-serif;
21
- background-color: #f8f9fc;
 
22
  }
23
-
24
  .navbar {
25
  background-color: white;
26
  box-shadow: 0 0.15rem 1.75rem 0 rgba(58, 59, 69, 0.15);
27
  }
28
-
29
  .navbar-brand {
30
  font-weight: 800;
31
- color: var(--primary-color);
32
  }
33
-
34
  .card {
35
  border: none;
36
  box-shadow: 0 0.15rem 1.75rem 0 rgba(58, 59, 69, 0.15);
37
  border-radius: 0.35rem;
38
  margin-bottom: 1.5rem;
 
39
  }
40
-
41
  .card-header {
42
- background-color: #f8f9fc;
43
- border-bottom: 1px solid #e3e6f0;
44
  font-weight: 700;
45
  color: var(--dark-color);
 
46
  }
47
-
48
  .btn-primary {
49
  background-color: var(--primary-color);
50
  border-color: var(--primary-color);
 
51
  }
52
-
 
 
 
 
53
  .btn-success {
54
  background-color: var(--secondary-color);
55
  border-color: var(--secondary-color);
56
  }
57
-
58
  .btn-danger {
59
  background-color: var(--danger-color);
60
  border-color: var(--danger-color);
61
  }
62
-
63
  .role-toggle {
64
  display: flex;
65
  align-items: center;
66
  }
67
-
68
  .role-toggle-btn {
69
  display: flex;
70
  align-items: center;
71
  gap: 8px;
72
- background-color: #f8f9fc;
73
- border: 1px solid #e3e6f0;
74
  border-radius: 30px;
75
  padding: 0.5rem 1rem;
76
  font-weight: 600;
 
77
  transition: all 0.3s ease;
 
78
  }
79
-
80
  .role-toggle-btn:hover {
81
- background-color: #edf2ff;
82
  }
83
-
84
  .role-toggle-btn.active {
85
  background-color: var(--primary-color);
86
  color: white;
 
87
  }
88
-
89
  .main-content {
90
- padding: 2rem;
91
  }
92
-
93
  .patient-list {
94
  list-style: none;
95
  padding: 0;
 
 
96
  }
97
-
98
  .patient-item {
99
  background-color: white;
100
  border-radius: 0.35rem;
101
- border-left: 4px solid var(--info-color);
102
- margin-bottom: 1rem;
103
  padding: 1rem;
104
  box-shadow: 0 0.15rem 0.5rem 0 rgba(58, 59, 69, 0.05);
105
  cursor: pointer;
106
  transition: all 0.2s ease;
107
  }
108
-
109
  .patient-item:hover {
110
  transform: translateY(-3px);
111
  box-shadow: 0 0.3rem 0.8rem 0 rgba(58, 59, 69, 0.1);
 
112
  }
113
 
 
 
 
 
 
 
 
114
  .patient-item.emergency {
115
  border-left-color: var(--danger-color);
116
  }
117
-
118
  .patient-item.deteriorating {
119
  border-left-color: var(--warning-color);
120
  }
121
-
122
  .patient-item.improving {
123
  border-left-color: var(--secondary-color);
124
  }
125
-
126
  .patient-item.stable {
127
  border-left-color: var(--info-color);
128
  }
129
-
130
  .patient-status {
131
- padding: 0.25rem 0.75rem;
132
  border-radius: 50rem;
133
  color: white;
134
- font-size: 0.8rem;
135
  font-weight: 700;
 
 
136
  }
137
-
138
  .status-emergency {
139
  background-color: var(--danger-color);
140
  }
141
-
142
  .status-deteriorating {
143
  background-color: var(--warning-color);
144
- color: #212529;
145
  }
146
-
147
  .status-improving {
148
  background-color: var(--secondary-color);
149
  }
150
-
151
  .status-stable {
152
  background-color: var(--info-color);
153
  }
154
-
 
 
 
 
 
155
  .care-plan-tabs {
156
  margin-top: 1.5rem;
157
  }
158
-
159
  .care-plan-content {
160
- background-color: #f8f9fc;
161
- border-radius: 0.35rem;
162
- border: 1px solid #e3e6f0;
 
163
  padding: 1.5rem;
164
- margin-top: 1rem;
165
- white-space: pre-line;
166
- height: 400px;
167
- overflow-y: auto;
 
168
  }
169
-
170
- .patient-details {
171
- display: none;
172
  }
173
-
174
  .loader {
175
  border: 5px solid #f3f3f3;
176
  border-top: 5px solid var(--primary-color);
@@ -181,11 +214,28 @@
181
  margin: 2rem auto;
182
  display: none;
183
  }
184
-
185
  @keyframes spin {
186
  0% { transform: rotate(0deg); }
187
  100% { transform: rotate(360deg); }
188
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
189
  </style>
190
  </head>
191
  <body>
@@ -202,16 +252,16 @@
202
  <div class="collapse navbar-collapse" id="navbarNav">
203
  <ul class="navbar-nav ms-auto">
204
  <li class="nav-item">
205
- <a class="nav-link" href="/">Home</a>
206
  </li>
207
  <li class="nav-item">
208
  <div class="role-toggle">
209
- <button class="role-toggle-btn" data-role="patient">
210
  <i class="fas fa-user"></i> Patient
211
- </button>
212
- <button class="role-toggle-btn active ms-2" data-role="doctor">
213
  <i class="fas fa-user-md"></i> Doctor
214
- </button>
215
  </div>
216
  </li>
217
  </ul>
@@ -221,7 +271,7 @@
221
 
222
  <div class="container-fluid main-content">
223
  <div class="row">
224
- <!-- Patient List -->
225
  <div class="col-md-4">
226
  <div class="card">
227
  <div class="card-header d-flex justify-content-between align-items-center">
@@ -232,27 +282,28 @@
232
  <div id="emergency-alerts">
233
  <!-- Emergency alerts will be populated here -->
234
  </div>
235
-
236
  <div class="mb-3">
237
  <input type="text" class="form-control" id="patient-search" placeholder="Search patients...">
238
  </div>
239
-
240
  <div id="patient-list-container">
241
  <div class="loader" id="patient-list-loader"></div>
242
  <ul class="patient-list" id="patient-list">
243
  <!-- Patient list will be populated here -->
244
  </ul>
 
245
  </div>
246
  </div>
247
  </div>
248
  </div>
249
-
250
- <!-- Patient Details -->
251
  <div class="col-md-8">
252
- <div class="patient-details" id="patient-details">
253
  <div class="card">
254
  <div class="card-header">
255
- <h5 class="mb-0" id="patient-name"><i class="fas fa-user me-2"></i>Patient Details</h5>
256
  </div>
257
  <div class="card-body">
258
  <div class="row mb-3">
@@ -266,34 +317,34 @@
266
  <strong>Status:</strong> <span id="patient-status" class="patient-status"></span>
267
  </div>
268
  </div>
269
-
270
  <div class="mb-3">
271
  <strong>Feedback/Symptoms:</strong>
272
- <p id="patient-feedback" class="p-2 bg-light rounded"></p>
273
  </div>
274
-
275
  <div class="mb-3">
276
  <strong>Last Updated:</strong> <span id="patient-timestamp"></span>
277
  </div>
278
-
279
  <button class="btn btn-primary" id="download-pdf">
280
- <i class="fas fa-file-download me-2"></i>Download PDF
281
  </button>
282
-
283
  <div class="care-plan-tabs mt-4">
284
  <ul class="nav nav-tabs" id="carePlanTabs" role="tablist">
285
  <li class="nav-item" role="presentation">
286
- <button class="nav-link active" id="updated-plan-tab" data-bs-toggle="tab" data-bs-target="#updated-plan" type="button" role="tab">Updated Care Plan</button>
287
  </li>
288
  <li class="nav-item" role="presentation">
289
- <button class="nav-link" id="original-plan-tab" data-bs-toggle="tab" data-bs-target="#original-plan" type="button" role="tab">Original Care Plan</button>
290
  </li>
291
  </ul>
292
  <div class="tab-content" id="carePlanTabsContent">
293
- <div class="tab-pane fade show active" id="updated-plan" role="tabpanel">
294
  <div class="care-plan-content" id="updated-plan-content"></div>
295
  </div>
296
- <div class="tab-pane fade" id="original-plan" role="tabpanel">
297
  <div class="care-plan-content" id="original-plan-content"></div>
298
  </div>
299
  </div>
@@ -301,10 +352,10 @@
301
  </div>
302
  </div>
303
  </div>
304
-
305
  <div id="no-patient-selected" class="text-center p-5">
306
- <i class="fas fa-user-md fa-4x text-muted mb-3"></i>
307
- <h4 class="text-muted">Select a patient to view details</h4>
308
  </div>
309
  </div>
310
  </div>
@@ -314,60 +365,50 @@
314
  <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.0/jquery.min.js"></script>
315
  <script>
316
  $(document).ready(function() {
317
- // Role toggle buttons
318
- $('.role-toggle-btn').click(function() {
319
- $('.role-toggle-btn').removeClass('active');
320
- $(this).addClass('active');
321
-
322
- const role = $(this).data('role');
323
-
324
- if (role === 'patient') {
325
- // Post to switch role endpoint and redirect
326
- $.post('/switch_role', { role: 'patient' }, function() {
327
- window.location.href = '/';
328
- });
329
- } else if (role === 'doctor') {
330
- // Stay on doctor dashboard and refresh
331
- $.post('/switch_role', { role: 'doctor' });
332
- }
333
- });
334
-
335
  // Show patient list loader
336
  $('#patient-list-loader').show();
337
-
 
338
  // Load all patients
339
  function loadPatients() {
 
340
  $.ajax({
341
  url: '/get_patients',
342
  type: 'GET',
343
  success: function(response) {
344
  $('#patient-list-loader').hide();
345
-
346
  if (response.success && response.patients.length > 0) {
 
347
  // Update patient count
348
  $('#patient-count').text(response.patients.length);
349
-
350
  // Clear patient list
351
  $('#patient-list').empty();
352
-
353
- // Sort patients by timestamp (newest first) and priority (emergency first)
 
354
  const sortedPatients = response.patients.sort((a, b) => {
355
- // Sort by status first (emergency > deteriorating > improving > stable)
356
- const statusPriority = {
357
- 'emergency': 0,
358
- 'deteriorating': 1,
359
- 'improving': 2,
360
- 'stable': 3
361
- };
362
-
363
- if (statusPriority[a.status] !== statusPriority[b.status]) {
364
- return statusPriority[a.status] - statusPriority[b.status];
365
  }
366
-
367
- // Then sort by timestamp (newest first)
368
- return new Date(b.timestamp) - new Date(a.timestamp);
 
369
  });
370
-
 
371
  // Populate emergency alerts
372
  const emergencyPatients = sortedPatients.filter(p => p.status === 'emergency');
373
  if (emergencyPatients.length > 0) {
@@ -381,150 +422,210 @@
381
  } else {
382
  $('#emergency-alerts').empty();
383
  }
384
-
385
  // Populate patient list
386
  sortedPatients.forEach(patient => {
387
  const statusText = {
388
  'emergency': 'EMERGENCY',
389
  'deteriorating': 'HIGH RISK',
390
  'improving': 'IMPROVING',
391
- 'stable': 'STABLE'
 
392
  };
393
-
394
  const statusClass = {
 
 
 
 
 
 
 
 
395
  'emergency': 'status-emergency',
396
  'deteriorating': 'status-deteriorating',
397
  'improving': 'status-improving',
398
- 'stable': 'status-stable'
 
399
  };
400
-
401
  const patientHtml = `
402
- <li class="patient-item ${patient.status}" data-id="${patient.id}">
403
  <div class="d-flex justify-content-between align-items-center">
404
  <div>
405
- <h6 class="mb-1">${patient.name}</h6>
406
- <small class="text-muted">Age: ${patient.age} | Gender: ${patient.gender}</small>
407
  </div>
408
- <span class="patient-status ${statusClass[patient.status]}">${statusText[patient.status]}</span>
409
  </div>
410
  </li>
411
  `;
412
  $('#patient-list').append(patientHtml);
413
  });
414
-
415
  // Add click event to patient items
416
- $('.patient-item').click(function() {
417
  const patientId = $(this).data('id');
 
 
418
  loadPatientDetails(patientId);
419
  });
420
-
421
- // Check if a patient is selected from URL
422
  const urlParams = new URLSearchParams(window.location.search);
423
  const selectedPatientId = urlParams.get('patient_id');
424
  if (selectedPatientId) {
 
425
  loadPatientDetails(selectedPatientId);
 
 
 
426
  }
 
 
427
  } else {
428
- $('#patient-list').html('<li class="text-center p-3">No patients found</li>');
 
 
 
 
 
 
429
  }
430
  },
431
- error: function() {
 
432
  $('#patient-list-loader').hide();
433
- $('#patient-list').html('<li class="text-center p-3 text-danger">Error loading patients</li>');
 
 
 
434
  }
435
  });
436
  }
437
-
438
  // Load patient details
439
  function loadPatientDetails(patientId) {
 
440
  // Highlight selected patient
441
  $('.patient-item').removeClass('active');
442
  $(`.patient-item[data-id="${patientId}"]`).addClass('active');
443
-
444
- // Show patient details loader
445
- $('#patient-details').hide();
446
  $('#no-patient-selected').hide();
447
-
 
 
 
 
 
448
  $.ajax({
449
  url: `/get_patient/${patientId}`,
450
  type: 'GET',
451
  success: function(response) {
 
452
  if (response.success) {
453
  const patient = response.patient;
454
-
 
455
  // Update patient details
456
- $('#patient-name').html(`<i class="fas fa-user me-2"></i>${patient.name}`);
457
- $('#patient-age').text(patient.age);
458
- $('#patient-gender').text(patient.gender);
459
- $('#patient-feedback').text(patient.feedback);
460
- $('#patient-timestamp').text(patient.timestamp);
461
-
462
  // Set status badge
463
  const statusText = {
464
  'emergency': 'EMERGENCY',
465
  'deteriorating': 'HIGH RISK',
466
  'improving': 'IMPROVING',
467
- 'stable': 'STABLE'
 
468
  };
469
-
470
- const statusClass = {
471
  'emergency': 'status-emergency',
472
  'deteriorating': 'status-deteriorating',
473
  'improving': 'status-improving',
474
- 'stable': 'status-stable'
 
475
  };
476
-
477
  $('#patient-status')
478
  .text(statusText[patient.status] || 'UNKNOWN')
479
- .attr('class', 'patient-status ' + (statusClass[patient.status] || ''));
480
-
481
- // Update care plans
482
- $('#updated-plan-content').text(patient.updated_plan);
483
- $('#original-plan-content').text(patient.original_plan || 'No original plan available');
484
-
 
 
 
 
 
 
485
  // Set up PDF download button
486
  $('#download-pdf').off('click').on('click', function() {
487
- window.location.href = `/download_pdf/${patientId}`;
 
488
  });
489
-
490
- // Show patient details
491
- $('#patient-details').fadeIn();
492
  } else {
 
493
  alert('Error: ' + response.error);
494
- $('#no-patient-selected').fadeIn();
 
495
  }
496
  },
497
- error: function() {
 
498
  alert('Error loading patient details');
499
- $('#no-patient-selected').fadeIn();
 
500
  }
501
  });
502
  }
503
-
504
  // Patient search functionality
505
  $('#patient-search').on('input', function() {
506
  const searchTerm = $(this).val().toLowerCase();
507
-
 
508
  $('.patient-item').each(function() {
509
  const patientName = $(this).find('h6').text().toLowerCase();
510
- const patientDetails = $(this).find('small').text().toLowerCase();
511
-
512
  if (patientName.includes(searchTerm) || patientDetails.includes(searchTerm)) {
513
  $(this).show();
 
514
  } else {
515
  $(this).hide();
516
  }
517
  });
 
 
 
 
 
 
518
  });
519
-
520
- // Check for emergency notifications periodically
 
 
 
 
521
  function checkEmergencyNotifications() {
 
522
  $.ajax({
523
  url: '/get_emergency_notifications',
524
  type: 'GET',
525
  success: function(response) {
526
  if (response.success && response.notifications.length > 0) {
527
- // Update emergency alerts
 
528
  const alertCount = response.notifications.length;
529
  let alertHtml = `
530
  <div class="alert alert-danger mb-3">
@@ -533,19 +634,50 @@
533
  </div>
534
  `;
535
  $('#emergency-alerts').html(alertHtml);
536
-
537
- // If there are new emergency alerts, reload patient list
538
- loadPatients();
 
 
 
 
 
 
 
 
 
 
 
 
 
 
539
  }
 
 
 
540
  }
541
  });
542
  }
543
-
544
- // Initial patient data load
545
- loadPatients();
546
-
547
- // Set interval to check emergency notifications every 30 seconds
548
- setInterval(checkEmergencyNotifications, 30000);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
549
  });
550
  </script>
551
  </body>
 
6
  <title>Doctor Dashboard - Patient Care Management</title>
7
  <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0-alpha1/dist/css/bootstrap.min.css" rel="stylesheet">
8
  <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.1.1/css/all.min.css">
9
+ <link href="https://fonts.googleapis.com/css2?family=Nunito:wght@400;600;700;800&display=swap" rel="stylesheet">
10
  <style>
11
  :root {
12
+ --primary-color: #4e73df; /* Blue */
13
+ --secondary-color: #1cc88a; /* Green */
14
+ --danger-color: #e74a3b; /* Red */
15
+ --warning-color: #f6c23e; /* Yellow */
16
+ --info-color: #36b9cc; /* Cyan */
17
+ --dark-color: #5a5c69; /* Dark Grey */
18
+ --light-bg: #f8f9fc; /* Light Grey Background */
19
+ --border-color: #e3e6f0; /* Light Border */
20
  }
21
+
22
  body {
23
  font-family: 'Nunito', sans-serif;
24
+ background-color: var(--light-bg);
25
+ color: var(--dark-color);
26
  }
27
+
28
  .navbar {
29
  background-color: white;
30
  box-shadow: 0 0.15rem 1.75rem 0 rgba(58, 59, 69, 0.15);
31
  }
32
+
33
  .navbar-brand {
34
  font-weight: 800;
35
+ color: var(--primary-color) !important; /* Override default link color */
36
  }
37
+
38
  .card {
39
  border: none;
40
  box-shadow: 0 0.15rem 1.75rem 0 rgba(58, 59, 69, 0.15);
41
  border-radius: 0.35rem;
42
  margin-bottom: 1.5rem;
43
+ background-color: white;
44
  }
45
+
46
  .card-header {
47
+ background-color: var(--light-bg);
48
+ border-bottom: 1px solid var(--border-color);
49
  font-weight: 700;
50
  color: var(--dark-color);
51
+ padding: 1rem 1.25rem;
52
  }
53
+
54
  .btn-primary {
55
  background-color: var(--primary-color);
56
  border-color: var(--primary-color);
57
+ transition: background-color 0.15s ease-in-out, border-color 0.15s ease-in-out;
58
  }
59
+ .btn-primary:hover {
60
+ background-color: #2e59d9; /* Darker blue */
61
+ border-color: #2653d4;
62
+ }
63
+
64
  .btn-success {
65
  background-color: var(--secondary-color);
66
  border-color: var(--secondary-color);
67
  }
68
+
69
  .btn-danger {
70
  background-color: var(--danger-color);
71
  border-color: var(--danger-color);
72
  }
73
+
74
  .role-toggle {
75
  display: flex;
76
  align-items: center;
77
  }
78
+
79
  .role-toggle-btn {
80
  display: flex;
81
  align-items: center;
82
  gap: 8px;
83
+ background-color: var(--light-bg);
84
+ border: 1px solid var(--border-color);
85
  border-radius: 30px;
86
  padding: 0.5rem 1rem;
87
  font-weight: 600;
88
+ color: var(--dark-color);
89
  transition: all 0.3s ease;
90
+ text-decoration: none; /* Remove underline */
91
  }
92
+
93
  .role-toggle-btn:hover {
94
+ background-color: #edf2ff; /* Lighter blue */
95
  }
96
+
97
  .role-toggle-btn.active {
98
  background-color: var(--primary-color);
99
  color: white;
100
+ border-color: var(--primary-color);
101
  }
102
+
103
  .main-content {
104
+ padding: 1.5rem; /* Reduced padding */
105
  }
106
+
107
  .patient-list {
108
  list-style: none;
109
  padding: 0;
110
+ max-height: calc(100vh - 250px); /* Adjust height to fit viewport */
111
+ overflow-y: auto; /* Add scroll for long lists */
112
  }
113
+
114
  .patient-item {
115
  background-color: white;
116
  border-radius: 0.35rem;
117
+ border-left: 4px solid var(--info-color); /* Default border */
118
+ margin-bottom: 0.75rem; /* Less margin */
119
  padding: 1rem;
120
  box-shadow: 0 0.15rem 0.5rem 0 rgba(58, 59, 69, 0.05);
121
  cursor: pointer;
122
  transition: all 0.2s ease;
123
  }
124
+
125
  .patient-item:hover {
126
  transform: translateY(-3px);
127
  box-shadow: 0 0.3rem 0.8rem 0 rgba(58, 59, 69, 0.1);
128
+ background-color: #fcfcfc; /* Slightly lighter hover background */
129
  }
130
 
131
+ .patient-item.active {
132
+ border: 1px solid var(--primary-color); /* Highlight active item */
133
+ border-left: 4px solid var(--primary-color);
134
+ background-color: #eef2fc; /* Subtle background for active */
135
+ }
136
+
137
+
138
  .patient-item.emergency {
139
  border-left-color: var(--danger-color);
140
  }
141
+
142
  .patient-item.deteriorating {
143
  border-left-color: var(--warning-color);
144
  }
145
+
146
  .patient-item.improving {
147
  border-left-color: var(--secondary-color);
148
  }
149
+
150
  .patient-item.stable {
151
  border-left-color: var(--info-color);
152
  }
153
+
154
  .patient-status {
155
+ padding: 0.3rem 0.8rem; /* Slightly larger padding */
156
  border-radius: 50rem;
157
  color: white;
158
+ font-size: 0.85rem; /* Slightly larger font */
159
  font-weight: 700;
160
+ min-width: 80px; /* Ensure minimum width */
161
+ text-align: center;
162
  }
163
+
164
  .status-emergency {
165
  background-color: var(--danger-color);
166
  }
167
+
168
  .status-deteriorating {
169
  background-color: var(--warning-color);
170
+ color: #212529; /* Dark text for yellow background */
171
  }
172
+
173
  .status-improving {
174
  background-color: var(--secondary-color);
175
  }
176
+
177
  .status-stable {
178
  background-color: var(--info-color);
179
  }
180
+ .status-unknown {
181
+ background-color: var(--dark-color);
182
+ color: white;
183
+ }
184
+
185
+
186
  .care-plan-tabs {
187
  margin-top: 1.5rem;
188
  }
189
+
190
  .care-plan-content {
191
+ background-color: var(--light-bg);
192
+ border-radius: 0 0 0.35rem 0.35rem; /* Rounded corners at bottom */
193
+ border: 1px solid var(--border-color);
194
+ border-top: none; /* No border top because of tabs */
195
  padding: 1.5rem;
196
+ height: 400px; /* Fixed height */
197
+ overflow-y: auto; /* Scroll */
198
+ white-space: pre-line; /* Preserve line breaks */
199
+ font-size: 1rem;
200
+ color: #333;
201
  }
202
+
203
+ .patient-details-section {
204
+ display: none; /* Hidden by default */
205
  }
206
+
207
  .loader {
208
  border: 5px solid #f3f3f3;
209
  border-top: 5px solid var(--primary-color);
 
214
  margin: 2rem auto;
215
  display: none;
216
  }
217
+
218
  @keyframes spin {
219
  0% { transform: rotate(0deg); }
220
  100% { transform: rotate(360deg); }
221
  }
222
+
223
+ #no-patient-selected {
224
+ min-height: 300px;
225
+ display: flex;
226
+ flex-direction: column;
227
+ justify-content: center;
228
+ align-items: center;
229
+ }
230
+
231
+ .alert-danger {
232
+ color: #721c24;
233
+ background-color: #f8d7da;
234
+ border-color: #f5c6cb;
235
+ }
236
+ .alert-danger strong {
237
+ color: var(--danger-color);
238
+ }
239
  </style>
240
  </head>
241
  <body>
 
252
  <div class="collapse navbar-collapse" id="navbarNav">
253
  <ul class="navbar-nav ms-auto">
254
  <li class="nav-item">
255
+ <a class="nav-link" href="/" role="button">Home</a>
256
  </li>
257
  <li class="nav-item">
258
  <div class="role-toggle">
259
+ <a href="/" class="role-toggle-btn" data-role="patient">
260
  <i class="fas fa-user"></i> Patient
261
+ </a>
262
+ <a href="/doctor_dashboard" class="role-toggle-btn active ms-2" data-role="doctor">
263
  <i class="fas fa-user-md"></i> Doctor
264
+ </a>
265
  </div>
266
  </li>
267
  </ul>
 
271
 
272
  <div class="container-fluid main-content">
273
  <div class="row">
274
+ <!-- Patient List Sidebar -->
275
  <div class="col-md-4">
276
  <div class="card">
277
  <div class="card-header d-flex justify-content-between align-items-center">
 
282
  <div id="emergency-alerts">
283
  <!-- Emergency alerts will be populated here -->
284
  </div>
285
+
286
  <div class="mb-3">
287
  <input type="text" class="form-control" id="patient-search" placeholder="Search patients...">
288
  </div>
289
+
290
  <div id="patient-list-container">
291
  <div class="loader" id="patient-list-loader"></div>
292
  <ul class="patient-list" id="patient-list">
293
  <!-- Patient list will be populated here -->
294
  </ul>
295
+ <div id="no-patients-found" class="text-center p-3 text-muted" style="display: none;">No patients found.</div>
296
  </div>
297
  </div>
298
  </div>
299
  </div>
300
+
301
+ <!-- Patient Details Main Area -->
302
  <div class="col-md-8">
303
+ <div class="patient-details-section" id="patient-details-section">
304
  <div class="card">
305
  <div class="card-header">
306
+ <h5 class="mb-0" id="patient-name-header"><i class="fas fa-user me-2"></i>Patient Details</h5>
307
  </div>
308
  <div class="card-body">
309
  <div class="row mb-3">
 
317
  <strong>Status:</strong> <span id="patient-status" class="patient-status"></span>
318
  </div>
319
  </div>
320
+
321
  <div class="mb-3">
322
  <strong>Feedback/Symptoms:</strong>
323
+ <p id="patient-feedback" class="p-3 bg-light rounded border"></p>
324
  </div>
325
+
326
  <div class="mb-3">
327
  <strong>Last Updated:</strong> <span id="patient-timestamp"></span>
328
  </div>
329
+
330
  <button class="btn btn-primary" id="download-pdf">
331
+ <i class="fas fa-file-download me-2"></i>Download Care Plan PDF
332
  </button>
333
+
334
  <div class="care-plan-tabs mt-4">
335
  <ul class="nav nav-tabs" id="carePlanTabs" role="tablist">
336
  <li class="nav-item" role="presentation">
337
+ <button class="nav-link active" id="updated-plan-tab" data-bs-toggle="tab" data-bs-target="#updated-plan" type="button" role="tab" aria-controls="updated-plan" aria-selected="true">Updated Care Plan</button>
338
  </li>
339
  <li class="nav-item" role="presentation">
340
+ <button class="nav-link" id="original-plan-tab" data-bs-toggle="tab" data-bs-target="#original-plan" type="button" role="tab" aria-controls="original-plan" aria-selected="false">Original Care Plan</button>
341
  </li>
342
  </ul>
343
  <div class="tab-content" id="carePlanTabsContent">
344
+ <div class="tab-pane fade show active" id="updated-plan" role="tabpanel" aria-labelledby="updated-plan-tab">
345
  <div class="care-plan-content" id="updated-plan-content"></div>
346
  </div>
347
+ <div class="tab-pane fade" id="original-plan" role="tabpanel" aria-labelledby="original-plan-tab">
348
  <div class="care-plan-content" id="original-plan-content"></div>
349
  </div>
350
  </div>
 
352
  </div>
353
  </div>
354
  </div>
355
+
356
  <div id="no-patient-selected" class="text-center p-5">
357
+ <i class="fas fa-notes-medical fa-5x text-muted mb-3"></i>
358
+ <h4 class="text-muted">Select a patient from the list to view details</h4>
359
  </div>
360
  </div>
361
  </div>
 
365
  <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.0/jquery.min.js"></script>
366
  <script>
367
  $(document).ready(function() {
368
+ // Set active role button on load
369
+ $('.role-toggle-btn[data-role="doctor"]').addClass('active');
370
+ $('.role-toggle-btn[data-role="patient"]').removeClass('active');
371
+
372
+
373
+ // Role toggle buttons - now just links
374
+ // They handle the redirection via href
375
+
376
+
 
 
 
 
 
 
 
 
 
377
  // Show patient list loader
378
  $('#patient-list-loader').show();
379
+ $('#no-patients-found').hide();
380
+
381
  // Load all patients
382
  function loadPatients() {
383
+ console.log("Loading patients...");
384
  $.ajax({
385
  url: '/get_patients',
386
  type: 'GET',
387
  success: function(response) {
388
  $('#patient-list-loader').hide();
389
+
390
  if (response.success && response.patients.length > 0) {
391
+ console.log("Patients loaded:", response.patients.length);
392
  // Update patient count
393
  $('#patient-count').text(response.patients.length);
394
+
395
  // Clear patient list
396
  $('#patient-list').empty();
397
+
398
+ // Sort patients by status priority (Emergency first) then timestamp (newest first)
399
+ const statusPriority = { 'emergency': 0, 'deteriorating': 1, 'improving': 2, 'stable': 3, 'unknown': 4 };
400
  const sortedPatients = response.patients.sort((a, b) => {
401
+ const priorityDiff = statusPriority[a.status] - statusPriority[b.status];
402
+ if (priorityDiff !== 0) {
403
+ return priorityDiff;
 
 
 
 
 
 
 
404
  }
405
+ // Fallback to timestamp if status is the same
406
+ const dateA = new Date(a.timestamp || '1900-01-01T00:00:00Z'); // Handle missing timestamp
407
+ const dateB = new Date(b.timestamp || '1900-01-01T00:00:00Z'); // Handle missing timestamp
408
+ return dateB - dateA; // Newest first
409
  });
410
+
411
+
412
  // Populate emergency alerts
413
  const emergencyPatients = sortedPatients.filter(p => p.status === 'emergency');
414
  if (emergencyPatients.length > 0) {
 
422
  } else {
423
  $('#emergency-alerts').empty();
424
  }
425
+
426
  // Populate patient list
427
  sortedPatients.forEach(patient => {
428
  const statusText = {
429
  'emergency': 'EMERGENCY',
430
  'deteriorating': 'HIGH RISK',
431
  'improving': 'IMPROVING',
432
+ 'stable': 'STABLE',
433
+ 'unknown': 'UNKNOWN'
434
  };
435
+
436
  const statusClass = {
437
+ 'emergency': 'emergency', // Use for border-left-color
438
+ 'deteriorating': 'deteriorating',
439
+ 'improving': 'improving',
440
+ 'stable': 'stable',
441
+ 'unknown': 'stable' // Default to stable color if unknown
442
+ };
443
+
444
+ const statusBadgeClass = {
445
  'emergency': 'status-emergency',
446
  'deteriorating': 'status-deteriorating',
447
  'improving': 'status-improving',
448
+ 'stable': 'status-stable',
449
+ 'unknown': 'status-unknown'
450
  };
451
+
452
  const patientHtml = `
453
+ <li class="patient-item ${statusClass[patient.status]}" data-id="${patient.id}">
454
  <div class="d-flex justify-content-between align-items-center">
455
  <div>
456
+ <h6 class="mb-1">${patient.name || 'Unnamed'}</h6>
457
+ <small class="text-muted">Age: ${patient.age || 'N/A'} | Gender: ${patient.gender || 'N/A'}</small>
458
  </div>
459
+ <span class="patient-status ${statusBadgeClass[patient.status]}">${statusText[patient.status]}</span>
460
  </div>
461
  </li>
462
  `;
463
  $('#patient-list').append(patientHtml);
464
  });
465
+
466
  // Add click event to patient items
467
+ $('.patient-item').off('click').on('click', function() { // Use .off().on() to avoid duplicate handlers
468
  const patientId = $(this).data('id');
469
+ // Update URL without full page reload
470
+ history.pushState({}, '', `/doctor_dashboard?patient_id=${patientId}`);
471
  loadPatientDetails(patientId);
472
  });
473
+
474
+ // Check if a patient ID is in the URL on page load
475
  const urlParams = new URLSearchParams(window.location.search);
476
  const selectedPatientId = urlParams.get('patient_id');
477
  if (selectedPatientId) {
478
+ console.log("Loading patient details from URL:", selectedPatientId);
479
  loadPatientDetails(selectedPatientId);
480
+ } else {
481
+ $('#no-patient-selected').show();
482
+ $('#patient-details-section').hide();
483
  }
484
+
485
+
486
  } else {
487
+ console.log("No patients found.");
488
+ $('#patient-count').text('0');
489
+ $('#patient-list').empty();
490
+ $('#emergency-alerts').empty();
491
+ $('#no-patients-found').show();
492
+ $('#no-patient-selected').show();
493
+ $('#patient-details-section').hide();
494
  }
495
  },
496
+ error: function(xhr, status, error) {
497
+ console.error("Error loading patients:", error);
498
  $('#patient-list-loader').hide();
499
+ $('#patient-list').html('<li class="text-center p-3 text-danger">Error loading patients.</li>');
500
+ $('#no-patients-found').hide(); // Hide no patients message if there was an error
501
+ $('#no-patient-selected').show();
502
+ $('#patient-details-section').hide();
503
  }
504
  });
505
  }
506
+
507
  // Load patient details
508
  function loadPatientDetails(patientId) {
509
+ console.log("Attempting to load details for patient ID:", patientId);
510
  // Highlight selected patient
511
  $('.patient-item').removeClass('active');
512
  $(`.patient-item[data-id="${patientId}"]`).addClass('active');
513
+
514
+ // Show patient details section, hide placeholder
 
515
  $('#no-patient-selected').hide();
516
+ $('#patient-details-section').show();
517
+
518
+
519
+ // You could add a loader here if the API call was slow
520
+ // $('#patient-details-section').addClass('loading');
521
+
522
  $.ajax({
523
  url: `/get_patient/${patientId}`,
524
  type: 'GET',
525
  success: function(response) {
526
+ // $('#patient-details-section').removeClass('loading');
527
  if (response.success) {
528
  const patient = response.patient;
529
+ console.log("Successfully loaded patient details:", patient.name);
530
+
531
  // Update patient details
532
+ $('#patient-name-header').html(`<i class="fas fa-user me-2"></i>${patient.name || 'Unnamed Patient'}`);
533
+ $('#patient-age').text(patient.age || 'N/A');
534
+ $('#patient-gender').text(patient.gender || 'N/A');
535
+ $('#patient-feedback').text(patient.feedback || 'No feedback recorded.');
536
+ $('#patient-timestamp').text(patient.timestamp || 'N/A');
537
+
538
  // Set status badge
539
  const statusText = {
540
  'emergency': 'EMERGENCY',
541
  'deteriorating': 'HIGH RISK',
542
  'improving': 'IMPROVING',
543
+ 'stable': 'STABLE',
544
+ 'unknown': 'UNKNOWN'
545
  };
546
+
547
+ const statusBadgeClass = {
548
  'emergency': 'status-emergency',
549
  'deteriorating': 'status-deteriorating',
550
  'improving': 'status-improving',
551
+ 'stable': 'status-stable',
552
+ 'unknown': 'status-unknown'
553
  };
554
+
555
  $('#patient-status')
556
  .text(statusText[patient.status] || 'UNKNOWN')
557
+ .attr('class', 'patient-status ' + (statusBadgeClass[patient.status] || 'status-unknown'));
558
+
559
+
560
+ // Update care plans content
561
+ $('#updated-plan-content').text(patient.updated_plan || 'No updated care plan available.');
562
+ $('#original-plan-content').text(patient.original_plan || 'No original care plan available.');
563
+
564
+ // Reset tab to updated plan and show content
565
+ $('#carePlanTabs button').removeClass('active');
566
+ $('#updated-plan-tab').addClass('active').tab('show');
567
+
568
+
569
  // Set up PDF download button
570
  $('#download-pdf').off('click').on('click', function() {
571
+ console.log("Download button clicked for patient ID:", patient.id);
572
+ window.location.href = `/download_pdf/${patient.id}`;
573
  });
574
+
 
 
575
  } else {
576
+ console.error('Error loading patient details:', response.error);
577
  alert('Error: ' + response.error);
578
+ $('#no-patient-selected').show(); // Show placeholder if patient not found
579
+ $('#patient-details-section').hide();
580
  }
581
  },
582
+ error: function(xhr, status, error) {
583
+ console.error("API Error loading patient details:", error);
584
  alert('Error loading patient details');
585
+ $('#no-patient-selected').show(); // Show placeholder on API error
586
+ $('#patient-details-section').hide();
587
  }
588
  });
589
  }
590
+
591
  // Patient search functionality
592
  $('#patient-search').on('input', function() {
593
  const searchTerm = $(this).val().toLowerCase();
594
+ let foundPatients = false;
595
+
596
  $('.patient-item').each(function() {
597
  const patientName = $(this).find('h6').text().toLowerCase();
598
+ const patientDetails = $(this).find('small').text().toLowerCase(); // Includes age/gender
599
+
600
  if (patientName.includes(searchTerm) || patientDetails.includes(searchTerm)) {
601
  $(this).show();
602
+ foundPatients = true;
603
  } else {
604
  $(this).hide();
605
  }
606
  });
607
+
608
+ if (foundPatients) {
609
+ $('#no-patients-found').hide();
610
+ } else {
611
+ $('#no-patients-found').show();
612
+ }
613
  });
614
+
615
+
616
+ // Initial patient data load when page is ready
617
+ loadPatients();
618
+
619
+ // Periodically check for emergency notifications (and refresh list if found)
620
  function checkEmergencyNotifications() {
621
+ console.log("Checking for emergency notifications...");
622
  $.ajax({
623
  url: '/get_emergency_notifications',
624
  type: 'GET',
625
  success: function(response) {
626
  if (response.success && response.notifications.length > 0) {
627
+ console.log(`Found ${response.notifications.length} emergency notifications.`);
628
+ // Update emergency alerts section
629
  const alertCount = response.notifications.length;
630
  let alertHtml = `
631
  <div class="alert alert-danger mb-3">
 
634
  </div>
635
  `;
636
  $('#emergency-alerts').html(alertHtml);
637
+
638
+ // Reload the patient list to bring emergency patients to the top
639
+ // Ensure currently selected patient remains selected if they are still in the list
640
+ const currentSelectedId = $('#patient-details-section').is(':visible') ? $('.patient-item.active').data('id') : null;
641
+ loadPatients(); // This will re-render the list and handle selection from URL
642
+
643
+ // If you want to *only* reload if there's a *new* emergency notification,
644
+ // you'd need to track seen notifications or compare list contents.
645
+ // For simplicity, we reload the list whenever *any* emergency exists.
646
+
647
+ } else {
648
+ // If no emergencies, clear the alert area
649
+ console.log("No emergency notifications.");
650
+ $('#emergency-alerts').empty();
651
+ // Optionally, reload the patient list if you want to revert sorting,
652
+ // but sorting already keeps non-emergency patients sorted by timestamp.
653
+ // So no need to reload the full list if only alerts disappear.
654
  }
655
+ },
656
+ error: function(xhr, status, error) {
657
+ console.error("Error checking emergency notifications:", error);
658
  }
659
  });
660
  }
661
+
662
+ // Check for emergency notifications every 30 seconds
663
+ setInterval(checkEmergencyNotifications, 30000); // 30 seconds
664
+
665
+ // Handle browser back/forward button for URL patient ID
666
+ window.onpopstate = function(event) {
667
+ const urlParams = new URLSearchParams(window.location.search);
668
+ const patientIdFromUrl = urlParams.get('patient_id');
669
+ if (patientIdFromUrl) {
670
+ loadPatientDetails(patientIdFromUrl);
671
+ } else {
672
+ // If no patient ID in URL (e.g., went back to dashboard root)
673
+ $('.patient-item').removeClass('active');
674
+ $('#patient-details-section').hide();
675
+ $('#no-patient-selected').show();
676
+ // Optionally refresh list if needed, but not strictly necessary here
677
+ }
678
+ };
679
+
680
+
681
  });
682
  </script>
683
  </body>