rajkhanke commited on
Commit
3728745
·
verified ·
1 Parent(s): 115d907

Update templates/doctor_dashboard.html

Browse files
Files changed (1) hide show
  1. templates/doctor_dashboard.html +458 -173
templates/doctor_dashboard.html CHANGED
@@ -54,14 +54,28 @@
54
  background-color: #2e59d9; /* Darker blue */
55
  border-color: #2653d4;
56
  }
57
- .btn-success {
58
  background-color: var(--secondary-color);
59
  border-color: var(--secondary-color);
 
 
 
 
 
60
  }
61
  .btn-danger {
62
  background-color: var(--danger-color);
63
  border-color: var(--danger-color);
64
  }
 
 
 
 
 
 
 
 
 
65
  .role-toggle {
66
  display: flex;
67
  align-items: center;
@@ -112,7 +126,6 @@
112
  box-shadow: 0 0.3rem 0.8rem 0 rgba(58, 59, 69, 0.1);
113
  background-color: #fcfcfc; /* Slightly lighter hover background */
114
  }
115
-
116
  .patient-item.active {
117
  border: 1px solid var(--primary-color); /* Highlight active item */
118
  border-left: 4px solid var(--primary-color);
@@ -133,7 +146,6 @@
133
  .patient-item.unknown { /* Style for unknown status in list */
134
  border-left-color: var(--dark-color);
135
  }
136
-
137
  .patient-status {
138
  padding: 0.3rem 0.8rem; /* Slightly larger padding */
139
  border-radius: 50rem;
@@ -164,7 +176,7 @@
164
  margin-top: 1.5rem;
165
  }
166
  .care-plan-content {
167
- background-color: var(--light-bg);
168
  border-radius: 0 0 0.35rem 0.35rem; /* Rounded corners at bottom */
169
  border: 1px solid var(--border-color);
170
  border-top: none; /* No border top because of tabs */
@@ -177,6 +189,18 @@
177
  font-size: 1rem;
178
  color: #333;
179
  }
 
 
 
 
 
 
 
 
 
 
 
 
180
  .patient-details-section {
181
  display: none; /* Hidden by default */
182
  }
@@ -213,6 +237,10 @@
213
  #patient-feedback {
214
  background-color: #e9ecef; /* Light grey */
215
  border-color: #dee2e6; /* Light grey border */
 
 
 
 
216
  }
217
  /* Delete button styling */
218
  .delete-patient-btn {
@@ -240,6 +268,36 @@
240
  .patient-item > div:first-child {
241
  margin-right: 2rem; /* Add margin to the content to make space for the button */
242
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
243
  </style>
244
  </head>
245
  <body>
@@ -260,12 +318,19 @@
260
  </li>
261
  <li class="nav-item">
262
  <div class="role-toggle">
263
- <a href="/" class="role-toggle-btn" data-role="patient">
264
- <i class="fas fa-user"></i> Patient
265
- </a>
266
- <a href="/doctor_dashboard" class="role-toggle-btn active ms-2" data-role="doctor">
267
- <i class="fas fa-user-md"></i> Doctor
268
- </a>
 
 
 
 
 
 
 
269
  </div>
270
  </li>
271
  </ul>
@@ -328,28 +393,56 @@
328
  <p id="patient-feedback" class="p-3 bg-light rounded border"></p>
329
  </div>
330
 
331
- <div class="mb-3">
332
  <strong>Last Updated:</strong> <span id="patient-timestamp"></span>
333
- </div>
 
 
 
 
 
 
 
 
 
 
 
 
 
334
 
335
- <!-- Download button now relies on patient ID -->
336
- <button class="btn btn-primary" id="download-pdf">
337
- <i class="fas fa-file-download me-2"></i>Download Care Plan PDF
338
- </button>
339
 
340
  <div class="care-plan-tabs mt-4">
341
  <ul class="nav nav-tabs" id="carePlanTabs" role="tablist">
342
  <li class="nav-item" role="presentation">
343
- <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>
344
  </li>
345
  <li class="nav-item" role="presentation">
346
  <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>
347
  </li>
348
  </ul>
349
  <div class="tab-content" id="carePlanTabsContent">
350
- <div class="tab-pane fade show active" id="updated-plan" role="tabpanel" aria-labelledby="updated-plan-tab">
351
- <div class="care-plan-content" id="updated-plan-content"></div>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
352
  </div>
 
 
353
  <div class="tab-pane fade" id="original-plan" role="tabpanel" aria-labelledby="original-plan-tab">
354
  <div class="care-plan-content" id="original-plan-content"></div>
355
  </div>
@@ -371,12 +464,25 @@
371
  <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.0/jquery.min.js"></script>
372
  <script>
373
  $(document).ready(function() {
374
- // Set active role button on load
375
- $('.role-toggle-btn[data-role="doctor"]').addClass('active');
376
- $('.role-toggle-btn[data-role="patient"]').removeClass('active');
377
 
378
  // Placeholder for storing selected patient ID
379
  let currentlySelectedPatientId = null;
 
 
 
 
 
 
 
 
 
 
 
 
 
380
 
381
  // Load all patients
382
  function loadPatients() {
@@ -385,7 +491,6 @@
385
  $('#no-patients-found').hide();
386
  $('#patient-list-error').hide(); // Hide previous error
387
  $('#patient-list').empty(); // Clear current list
388
-
389
  $.ajax({
390
  url: '/get_patients',
391
  type: 'GET',
@@ -395,7 +500,6 @@
395
  console.log("Patients loaded:", response.patients.length);
396
  // Update patient count
397
  $('#patient-count').text(response.patients.length);
398
-
399
  // Sort patients by status priority (Emergency first) then timestamp (newest first)
400
  const statusPriority = { 'emergency': 0, 'deteriorating': 1, 'improving': 2, 'stable': 3, 'unknown': 4 };
401
  const sortedPatients = response.patients.sort((a, b) => {
@@ -408,7 +512,6 @@
408
  const dateB = new Date(b.timestamp || '1900-01-01T00:00:00Z'); // Handle missing timestamp
409
  return dateB - dateA; // Newest first
410
  });
411
-
412
  // Populate emergency alerts
413
  const emergencyPatients = sortedPatients.filter(p => p.status === 'emergency');
414
  if (emergencyPatients.length > 0) {
@@ -422,7 +525,6 @@
422
  } else {
423
  $('#emergency-alerts').empty();
424
  }
425
-
426
  // Populate patient list
427
  sortedPatients.forEach(patient => {
428
  const statusText = {
@@ -454,66 +556,74 @@
454
  <small class="text-muted">Age: ${patient.age || 'N/A'} | Gender: ${patient.gender || 'N/A'}</small><br>
455
  <small class="text-muted">Last Updated: ${patient.timestamp ? new Date(patient.timestamp).toLocaleString() : 'N/A'}</small>
456
  </div>
457
- <span class="patient-status ${statusBadgeClass[patient.status] || 'status-unknown'}">${statusText[patient.status] || 'UNKNOWN'}</span>
 
 
 
458
  </div>
459
- <button class="delete-patient-btn" data-id="${patient.id}">
460
  <i class="fas fa-trash-alt"></i>
461
  </button>
462
  </li>
463
  `;
464
  $('#patient-list').append(patientHtml);
465
  });
 
 
 
466
 
467
  // Add click event to patient items (excluding delete button clicks)
468
  $('#patient-list').on('click', '.patient-item', function(event) {
469
  // Check if the click target is the delete button or its icon
470
  if ($(event.target).closest('.delete-patient-btn').length === 0) {
471
  const patientId = $(this).data('id');
 
 
 
 
 
 
472
  // Update URL without full page reload
473
  history.pushState({ patient_id: patientId }, '', `/doctor_dashboard?patient_id=${patientId}`);
474
  loadPatientDetails(patientId);
475
  }
476
  });
477
-
 
 
 
 
478
 
479
  // After loading the list, check if a patient ID is in the URL or if a patient was previously selected
480
  const urlParams = new URLSearchParams(window.location.search);
481
  const patientIdFromUrl = urlParams.get('patient_id');
482
 
483
- if (patientIdFromUrl) {
484
- console.log("Checking for patient from URL:", patientIdFromUrl);
 
 
 
485
  // Check if this ID exists in the loaded list before trying to load details
486
- if ($(`.patient-item[data-id="${patientIdFromUrl}"]`).length > 0) {
487
- loadPatientDetails(patientIdFromUrl);
488
  } else {
489
- console.warn(`Patient ID "${patientIdFromUrl}" from URL not found in loaded list.`);
490
- // Clear URL param if patient not found
491
  history.replaceState({}, '', '/doctor_dashboard');
492
  $('#no-patient-selected').show();
493
  $('#patient-details-section').hide();
494
  currentlySelectedPatientId = null; // Reset selected ID
 
 
495
  }
496
- } else if (currentlySelectedPatientId) {
497
- // If no ID in URL, but we had one selected before refresh/reload, try to load it
498
- console.log("Checking for previously selected patient:", currentlySelectedPatientId);
499
- if ($(`.patient-item[data-id="${currentlySelectedPatientId}"]`).length > 0) {
500
- loadPatientDetails(currentlySelectedPatientId);
501
- } else {
502
- console.warn(`Previously selected patient ID "${currentlySelectedPatientId}" not found in loaded list.`);
503
- history.replaceState({}, '', '/doctor_dashboard');
504
- $('#no-patient-selected').show();
505
- $('#patient-details-section').hide();
506
- currentlySelectedPatientId = null; // Reset selected ID
507
- }
508
-
509
- }
510
- else {
511
  $('#no-patient-selected').show();
512
  $('#patient-details-section').hide();
513
- currentlySelectedPatientId = null; // Ensure it's null
 
 
514
  }
515
-
516
-
517
  } else {
518
  console.log("No patients found.");
519
  $('#patient-count').text('0');
@@ -523,6 +633,8 @@
523
  $('#no-patient-selected').show();
524
  $('#patient-details-section').hide();
525
  currentlySelectedPatientId = null; // Reset selected ID
 
 
526
  }
527
  },
528
  error: function(xhr, status, error) {
@@ -535,15 +647,21 @@
535
  $('#no-patient-selected').show();
536
  $('#patient-details-section').hide();
537
  currentlySelectedPatientId = null; // Reset selected ID
 
 
538
  }
539
  });
540
  }
541
-
542
  // Load patient details
543
  function loadPatientDetails(patientId) {
544
  console.log("Attempting to load details for patient ID:", patientId);
545
  currentlySelectedPatientId = patientId; // Store the ID
546
 
 
 
 
 
 
547
  // Highlight selected patient
548
  $('.patient-item').removeClass('active');
549
  $(`.patient-item[data-id="${patientId}"]`).addClass('active');
@@ -552,9 +670,16 @@
552
  $('#no-patient-selected').hide();
553
  $('#patient-details-section').show();
554
 
 
 
 
 
 
 
 
 
555
  // Optional: Show a loader in the details pane while fetching
556
  // $('#patient-details-section .card-body').html('<div class="loader"></div>');
557
-
558
  $.ajax({
559
  url: `/get_patient/${patientId}`,
560
  type: 'GET',
@@ -563,14 +688,12 @@
563
  if (response.success) {
564
  const patient = response.patient;
565
  console.log("Successfully loaded patient details:", patient.name);
566
-
567
  // Update patient details
568
  $('#patient-name-header').html(`<i class="fas fa-user me-2"></i>${patient.name || 'Unnamed Patient'}`);
569
  $('#patient-age').text(patient.age || 'N/A');
570
  $('#patient-gender').text(patient.gender || 'N/A');
571
  $('#patient-feedback').text(patient.feedback || 'No feedback recorded.');
572
  $('#patient-timestamp').text(patient.timestamp ? new Date(patient.timestamp).toLocaleString() : 'N/A');
573
-
574
  // Set status badge
575
  const statusText = {
576
  'emergency': 'EMERGENCY',
@@ -579,34 +702,37 @@
579
  'stable': 'STABLE',
580
  'unknown': 'UNKNOWN'
581
  };
582
- const statusBadgeClass = {
 
 
 
 
 
 
 
583
  'emergency': 'status-emergency',
584
  'deteriorating': 'status-deteriorating',
585
  'improving': 'status-improving',
586
  'stable': 'status-stable',
587
- 'unknown': 'status-unknown'
588
  };
589
  $('#patient-status')
590
- .text(statusText[patient.status] || 'UNKNOWN')
591
- .attr('class', 'patient-status ' + (statusBadgeClass[patient.status] || 'status-unknown'));
592
-
593
- // Update care plans content
594
- $('#updated-plan-content').text(patient.updated_plan || 'No updated care plan available.');
595
  $('#original-plan-content').text(patient.original_plan || 'No original care plan available (or could not be extracted from PDF).');
596
-
597
  // Reset tab to updated plan and show content
598
- $('#carePlanTabs button').removeClass('active').attr('aria-selected', 'false');
599
  $('#updated-plan-tab').addClass('active').attr('aria-selected', 'true');
600
  $('#carePlanTabsContent .tab-pane').removeClass('show active');
601
- $('#updated-plan').addClass('show active');
602
-
603
-
604
- // Set up PDF download button with patient ID
605
  $('#download-pdf').off('click').on('click', function() {
606
  console.log("Download button clicked for patient ID:", patient.id);
607
  window.location.href = `/download_pdf/${patient.id}`;
608
  });
609
-
610
  } else {
611
  console.error('Error loading patient details:', response.error);
612
  alert('Error: ' + response.error);
@@ -615,6 +741,8 @@
615
  $(`.patient-item[data-id="${patientId}"]`).removeClass('active'); // Remove highlight
616
  currentlySelectedPatientId = null; // Reset selected ID
617
  history.replaceState({}, '', '/doctor_dashboard'); // Clear URL param
 
 
618
  }
619
  },
620
  error: function(xhr, status, error) {
@@ -625,99 +753,234 @@
625
  $(`.patient-item[data-id="${patientId}"]`).removeClass('active'); // Remove highlight
626
  currentlySelectedPatientId = null; // Reset selected ID
627
  history.replaceState({}, '', '/doctor_dashboard'); // Clear URL param
 
 
628
  }
629
  });
630
  }
631
 
632
- // Handle patient deletion using event delegation
633
- $('#patient-list').on('click', '.delete-patient-btn', function(event) {
634
- event.preventDefault(); // Prevent default button click behavior
635
- event.stopPropagation(); // Prevent the parent list item click handler from firing
636
-
637
- const patientIdToDelete = $(this).data('id');
638
- const $patientItem = $(this).closest('.patient-item');
639
- const patientName = $patientItem.find('h6').text() || 'Unnamed Patient';
640
-
641
- if (confirm(`Are you sure you want to delete the record for ${patientName}? This action cannot be undone.`)) {
642
- console.log(`Deleting patient ID: ${patientIdToDelete}`);
643
- // Optionally show a spinner or disable the delete button
644
- const $deleteBtnIcon = $(this).find('i');
645
- $deleteBtnIcon.removeClass().addClass('fas fa-spinner fa-spin');
646
- $(this).prop('disabled', true);
647
-
648
-
649
- $.ajax({
650
- url: `/delete_patient/${patientIdToDelete}`,
651
- type: 'DELETE',
652
- success: function(response) {
653
- console.log("Delete successful:", response.message);
654
- // Remove the patient item from the list
655
- $patientItem.remove();
656
- // Update patient count
657
- $('#patient-count').text($('#patient-list li').length);
658
- // Check if the deleted patient was currently selected
659
- if (currentlySelectedPatientId === patientIdToDelete) {
660
- console.log("Deleted currently selected patient. Clearing details pane.");
661
- $('#patient-details-section').hide();
662
- $('#no-patient-selected').show();
663
- currentlySelectedPatientId = null; // Reset selected ID
664
- history.replaceState({}, '', '/doctor_dashboard'); // Clear URL param
665
- }
666
- // Check if the list is now empty
667
- if ($('#patient-list li').length === 0) {
668
- $('#no-patients-found').show();
669
- }
670
 
671
- // Reload the full patient list could also be an option here
672
- // instead of just removing the element, to ensure sorting/alerts are updated
673
- // loadPatients();
674
-
675
- },
676
- error: function(xhr, status, error) {
677
- console.error("Delete failed:", error, xhr.responseText);
678
- // Re-enable button and restore icon on error
679
- $deleteBtnIcon.removeClass().addClass('fas fa-trash-alt');
680
- $(this).prop('disabled', false);
681
-
682
- let errorMessage = 'An error occurred during deletion.';
683
- if (xhr.responseJSON && xhr.responseJSON.error) {
684
- errorMessage = xhr.responseJSON.error;
685
- } else if (xhr.responseText) {
686
- errorMessage += ": " + xhr.responseText;
687
- } else {
688
- errorMessage += ": " + error;
 
 
 
 
 
 
 
 
 
 
 
 
689
  }
690
- alert(`Error deleting patient: ${errorMessage}`);
691
- }
692
- });
693
- } else {
694
- console.log("Delete cancelled.");
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
695
  }
696
- });
 
 
 
 
 
 
697
 
 
698
 
699
- // Patient search functionality
700
- $('#patient-search').on('input', function() {
701
- const searchTerm = $(this).val().toLowerCase();
702
- let foundPatients = false;
703
- $('.patient-item').each(function() {
704
- const patientName = $(this).find('h6').text().toLowerCase();
705
- const patientDetails = $(this).find('small').text().toLowerCase(); // Includes age/gender/timestamp
706
- if (patientName.includes(searchTerm) || patientDetails.includes(searchTerm)) {
707
- $(this).show();
708
- foundPatients = true;
709
- } else {
710
- $(this).hide();
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
711
  }
712
  });
713
- if (foundPatients) {
714
- $('#no-patients-found').hide();
715
- } else {
716
- $('#no-patients-found').show();
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
717
  }
 
 
 
 
 
718
  });
719
 
720
 
 
 
721
  // Initial patient data load when page is ready
722
  loadPatients();
723
 
@@ -728,29 +991,33 @@
728
  url: '/get_emergency_notifications',
729
  type: 'GET',
730
  success: function(response) {
731
- if (response.success && response.notifications.length > 0) {
732
- console.log(`Found ${response.notifications.length} emergency notifications.`);
733
- const alertCount = response.notifications.length;
734
- // Check if the current alert count is different or if the content has changed (basic check)
735
- const currentAlertHtml = $('#emergency-alerts').html().trim();
736
- const newAlertHtml = `
737
  <div class="alert alert-danger mb-3">
738
  <i class="fas fa-exclamation-triangle me-2"></i>
739
  <strong>${alertCount} Emergency patient${alertCount > 1 ? 's' : ''} requiring immediate attention!</strong>
740
  </div>
741
  `;
742
- if (currentAlertHtml !== newAlertHtml.trim()) {
743
- // Update emergency alerts section
744
- $('#emergency-alerts').html(newAlertHtml);
745
- // Reload the patient list to update sorting and potentially highlight new emergencies
746
- console.log("Reloading patient list due to new emergency alerts...");
747
- loadPatients(); // This will re-render the list and handle selection from URL/previously selected ID
 
 
 
 
 
748
  }
749
-
750
  } else {
751
- // If no emergencies, clear the alert area
752
- console.log("No emergency notifications.");
753
- $('#emergency-alerts').empty();
754
  }
755
  },
756
  error: function(xhr, status, error) {
@@ -760,22 +1027,26 @@
760
  }
761
  });
762
  }
763
-
764
  // Check for emergency notifications periodically (e.g., every 30 seconds)
765
  setInterval(checkEmergencyNotifications, 30000); // 30 seconds
766
 
 
767
  // Handle browser back/forward button for URL patient ID
768
  window.onpopstate = function(event) {
769
  const urlParams = new URLSearchParams(window.location.search);
770
  const patientIdFromUrl = urlParams.get('patient_id');
771
-
772
  // Compare with the ID of the patient currently *displayed* in the details pane
773
  // This needs to be tracked separately as loadPatients might be async
774
- const currentlyDisplayedPatientId = $('#patient-details-section').is(':visible') ? currentlySelectedPatientId : null;
775
-
776
 
777
- if (patientIdFromUrl && patientIdFromUrl !== currentlyDisplayedPatientId) {
778
  console.log(`URL changed to patient ID: ${patientIdFromUrl}. Attempting to load details.`);
 
 
 
 
 
 
 
779
  // Check if this ID exists in the currently rendered list before calling API
780
  if ($(`.patient-item[data-id="${patientIdFromUrl}"]`).length > 0) {
781
  loadPatientDetails(patientIdFromUrl);
@@ -786,15 +1057,27 @@
786
  $('#no-patient-selected').show();
787
  currentlySelectedPatientId = null; // Reset
788
  history.replaceState({}, '', '/doctor_dashboard'); // Clear URL param if not found
 
 
789
  }
790
- } else if (!patientIdFromUrl && currentlyDisplayedPatientId) {
791
  // If URL has no ID but a patient is currently displayed, hide details
792
- console.log("URL changed, no patient ID. Hiding details.");
 
 
 
 
 
 
 
 
793
  $('.patient-item').removeClass('active'); // Remove highlight
794
  $('#patient-details-section').hide();
795
  $('#no-patient-selected').show();
796
  currentlySelectedPatientId = null; // Reset
797
- } else if (patientIdFromUrl && patientIdFromUrl === currentlyDisplayedPatientId) {
 
 
798
  // If URL has the same ID as currently displayed, do nothing (user navigated back to the same state)
799
  console.log("URL changed but same patient ID. No action needed.");
800
  } else {
@@ -804,6 +1087,8 @@
804
  $('#patient-details-section').hide();
805
  $('#no-patient-selected').show();
806
  currentlySelectedPatientId = null; // Reset
 
 
807
  }
808
  };
809
  });
 
54
  background-color: #2e59d9; /* Darker blue */
55
  border-color: #2653d4;
56
  }
57
+ .btn-success {
58
  background-color: var(--secondary-color);
59
  border-color: var(--secondary-color);
60
+ color: white; /* Ensure text is white */
61
+ }
62
+ .btn-success:hover {
63
+ background-color: #17a673; /* Darker green */
64
+ border-color: #159d6b;
65
  }
66
  .btn-danger {
67
  background-color: var(--danger-color);
68
  border-color: var(--danger-color);
69
  }
70
+ .btn-warning {
71
+ background-color: var(--warning-color);
72
+ border-color: var(--warning-color);
73
+ color: #212529; /* Dark text for yellow */
74
+ }
75
+ .btn-warning:hover {
76
+ background-color: #f0ad4e; /* Darker yellow */
77
+ border-color: #ec971f;
78
+ }
79
  .role-toggle {
80
  display: flex;
81
  align-items: center;
 
126
  box-shadow: 0 0.3rem 0.8rem 0 rgba(58, 59, 69, 0.1);
127
  background-color: #fcfcfc; /* Slightly lighter hover background */
128
  }
 
129
  .patient-item.active {
130
  border: 1px solid var(--primary-color); /* Highlight active item */
131
  border-left: 4px solid var(--primary-color);
 
146
  .patient-item.unknown { /* Style for unknown status in list */
147
  border-left-color: var(--dark-color);
148
  }
 
149
  .patient-status {
150
  padding: 0.3rem 0.8rem; /* Slightly larger padding */
151
  border-radius: 50rem;
 
176
  margin-top: 1.5rem;
177
  }
178
  .care-plan-content {
179
+ background-color: white; /* Changed background */
180
  border-radius: 0 0 0.35rem 0.35rem; /* Rounded corners at bottom */
181
  border: 1px solid var(--border-color);
182
  border-top: none; /* No border top because of tabs */
 
189
  font-size: 1rem;
190
  color: #333;
191
  }
192
+ #updated-plan-content-edit {
193
+ width: 100%;
194
+ height: 400px; /* Match display height */
195
+ padding: 1.5rem;
196
+ border: 1px solid var(--border-color);
197
+ border-top: none;
198
+ border-radius: 0 0 0.35rem 0.35rem;
199
+ font-size: 1rem;
200
+ color: #333;
201
+ resize: vertical; /* Allow vertical resize */
202
+ display: none; /* Hidden by default */
203
+ }
204
  .patient-details-section {
205
  display: none; /* Hidden by default */
206
  }
 
237
  #patient-feedback {
238
  background-color: #e9ecef; /* Light grey */
239
  border-color: #dee2e6; /* Light grey border */
240
+ padding: 1rem; /* Added padding */
241
+ border-radius: 0.25rem; /* Rounded corners */
242
+ white-space: pre-line; /* Preserve line breaks */
243
+ word-wrap: break-word; /* Prevent overflow */
244
  }
245
  /* Delete button styling */
246
  .delete-patient-btn {
 
268
  .patient-item > div:first-child {
269
  margin-right: 2rem; /* Add margin to the content to make space for the button */
270
  }
271
+ .btn-spinner {
272
+ display: inline-block;
273
+ width: 1rem;
274
+ height: 1rem;
275
+ vertical-align: middle;
276
+ border-radius: 50%;
277
+ border: 0.15em solid currentColor;
278
+ border-right-color: transparent;
279
+ animation: .75s linear infinite spinner-border;
280
+ }
281
+ @keyframes spinner-border {
282
+ to { transform: rotate(360deg); }
283
+ }
284
+ .d-flex.align-items-center > .btn-spinner {
285
+ margin-left: 0.5rem;
286
+ }
287
+ .status-dot {
288
+ display: inline-block;
289
+ width: 10px;
290
+ height: 10px;
291
+ border-radius: 50%;
292
+ margin-right: 5px;
293
+ vertical-align: middle;
294
+ }
295
+ .status-dot.emergency { background-color: var(--danger-color); }
296
+ .status-dot.deteriorating { background-color: var(--warning-color); }
297
+ .status-dot.improving { background-color: var(--secondary-color); }
298
+ .status-dot.stable { background-color: var(--info-color); }
299
+ .status-dot.unknown { background-color: var(--dark-color); }
300
+
301
  </style>
302
  </head>
303
  <body>
 
318
  </li>
319
  <li class="nav-item">
320
  <div class="role-toggle">
321
+ <!-- Using forms for role switching -->
322
+ <form id="switch-to-patient-form" action="/switch_role" method="post" class="d-inline-block me-2">
323
+ <input type="hidden" name="role" value="patient">
324
+ <button type="submit" class="role-toggle-btn">
325
+ <i class="fas fa-user"></i> Patient
326
+ </button>
327
+ </form>
328
+ <form id="switch-to-doctor-form" action="/switch_role" method="post" class="d-inline-block">
329
+ <input type="hidden" name="role" value="doctor">
330
+ <button type="submit" class="role-toggle-btn active">
331
+ <i class="fas fa-user-md"></i> Doctor
332
+ </button>
333
+ </form>
334
  </div>
335
  </li>
336
  </ul>
 
393
  <p id="patient-feedback" class="p-3 bg-light rounded border"></p>
394
  </div>
395
 
396
+ <div class="mb-3">
397
  <strong>Last Updated:</strong> <span id="patient-timestamp"></span>
398
+ </div>
399
+
400
+ <!-- Action Buttons -->
401
+ <div class="d-flex gap-2 mb-4">
402
+ <button class="btn btn-primary d-flex align-items-center" id="download-pdf">
403
+ <i class="fas fa-file-download me-2"></i>Download Care Plan PDF
404
+ </button>
405
+ <!-- WhatsApp button - initially hidden until patient selected -->
406
+ <button class="btn btn-success d-flex align-items-center" id="send-whatsapp-btn" style="display: none;">
407
+ <i class="fab fa-whatsapp me-2"></i>Send via WhatsApp
408
+ </button>
409
+ <!-- Loader/Feedback for WhatsApp send -->
410
+ <div id="whatsapp-feedback" class="ms-3 align-self-center"></div>
411
+ </div>
412
 
 
 
 
 
413
 
414
  <div class="care-plan-tabs mt-4">
415
  <ul class="nav nav-tabs" id="carePlanTabs" role="tablist">
416
  <li class="nav-item" role="presentation">
417
+ <button class="nav-link active" id="updated-plan-tab" data-bs-toggle="tab" data-bs-target="#updated-plan-container" type="button" role="tab" aria-controls="updated-plan-container" aria-selected="true">Updated Care Plan</button>
418
  </li>
419
  <li class="nav-item" role="presentation">
420
  <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>
421
  </li>
422
  </ul>
423
  <div class="tab-content" id="carePlanTabsContent">
424
+ <!-- Updated Plan Container -->
425
+ <div class="tab-pane fade show active" id="updated-plan-container" role="tabpanel" aria-labelledby="updated-plan-tab">
426
+ <div class="d-flex justify-content-end align-items-center mt-3 me-3" id="edit-save-buttons">
427
+ <button class="btn btn-sm btn-warning me-2" id="edit-plan-btn">
428
+ <i class="fas fa-edit me-1"></i> Edit
429
+ </button>
430
+ <button class="btn btn-sm btn-success me-2" id="save-plan-btn" style="display: none;">
431
+ <i class="fas fa-save me-1"></i> Save
432
+ </button>
433
+ <button class="btn btn-sm btn-secondary" id="cancel-plan-btn" style="display: none;">
434
+ <i class="fas fa-times me-1"></i> Cancel
435
+ </button>
436
+ <div id="save-feedback" class="ms-2 small"></div>
437
+ </div>
438
+
439
+ <!-- Display area -->
440
+ <div class="care-plan-content" id="updated-plan-content-display"></div>
441
+ <!-- Edit area (textarea) -->
442
+ <textarea class="form-control" id="updated-plan-content-edit" style="display: none;"></textarea>
443
  </div>
444
+
445
+ <!-- Original Plan Tab -->
446
  <div class="tab-pane fade" id="original-plan" role="tabpanel" aria-labelledby="original-plan-tab">
447
  <div class="care-plan-content" id="original-plan-content"></div>
448
  </div>
 
464
  <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.0/jquery.min.js"></script>
465
  <script>
466
  $(document).ready(function() {
467
+ // Set active role button on load (handled by forms now)
468
+ // $('.role-toggle-btn[data-role="doctor"]').addClass('active');
469
+ // $('.role-toggle-btn[data-role="patient"]').removeClass('active');
470
 
471
  // Placeholder for storing selected patient ID
472
  let currentlySelectedPatientId = null;
473
+ let isEditingPlan = false; // State variable for edit mode
474
+
475
+ // Elements for Updated Plan editing
476
+ const $updatedPlanDisplay = $('#updated-plan-content-display');
477
+ const $updatedPlanEdit = $('#updated-plan-content-edit');
478
+ const $editBtn = $('#edit-plan-btn');
479
+ const $saveBtn = $('#save-plan-btn');
480
+ const $cancelBtn = $('#cancel-plan-btn');
481
+ const $saveFeedback = $('#save-feedback');
482
+ const $whatsappBtn = $('#send-whatsapp-btn');
483
+ const $whatsappFeedback = $('#whatsapp-feedback');
484
+ const $carePlanTabs = $('#carePlanTabs button'); // All tab buttons
485
+
486
 
487
  // Load all patients
488
  function loadPatients() {
 
491
  $('#no-patients-found').hide();
492
  $('#patient-list-error').hide(); // Hide previous error
493
  $('#patient-list').empty(); // Clear current list
 
494
  $.ajax({
495
  url: '/get_patients',
496
  type: 'GET',
 
500
  console.log("Patients loaded:", response.patients.length);
501
  // Update patient count
502
  $('#patient-count').text(response.patients.length);
 
503
  // Sort patients by status priority (Emergency first) then timestamp (newest first)
504
  const statusPriority = { 'emergency': 0, 'deteriorating': 1, 'improving': 2, 'stable': 3, 'unknown': 4 };
505
  const sortedPatients = response.patients.sort((a, b) => {
 
512
  const dateB = new Date(b.timestamp || '1900-01-01T00:00:00Z'); // Handle missing timestamp
513
  return dateB - dateA; // Newest first
514
  });
 
515
  // Populate emergency alerts
516
  const emergencyPatients = sortedPatients.filter(p => p.status === 'emergency');
517
  if (emergencyPatients.length > 0) {
 
525
  } else {
526
  $('#emergency-alerts').empty();
527
  }
 
528
  // Populate patient list
529
  sortedPatients.forEach(patient => {
530
  const statusText = {
 
556
  <small class="text-muted">Age: ${patient.age || 'N/A'} | Gender: ${patient.gender || 'N/A'}</small><br>
557
  <small class="text-muted">Last Updated: ${patient.timestamp ? new Date(patient.timestamp).toLocaleString() : 'N/A'}</small>
558
  </div>
559
+ <span class="patient-status ${statusBadgeClass[patient.status] || 'status-unknown'}">
560
+ <span class="status-dot ${statusClass[patient.status] || 'unknown'}"></span>
561
+ ${statusText[patient.status] || 'UNKNOWN'}
562
+ </span>
563
  </div>
564
+ <button class="delete-patient-btn" data-id="${patient.id}" title="Delete Patient Record">
565
  <i class="fas fa-trash-alt"></i>
566
  </button>
567
  </li>
568
  `;
569
  $('#patient-list').append(patientHtml);
570
  });
571
+ // Remove previous event handlers before adding new ones
572
+ $('#patient-list').off('click', '.patient-item');
573
+ $('#patient-list').off('click', '.delete-patient-btn');
574
 
575
  // Add click event to patient items (excluding delete button clicks)
576
  $('#patient-list').on('click', '.patient-item', function(event) {
577
  // Check if the click target is the delete button or its icon
578
  if ($(event.target).closest('.delete-patient-btn').length === 0) {
579
  const patientId = $(this).data('id');
580
+ // Check if currently editing before switching
581
+ if (isEditingPlan && currentlySelectedPatientId !== patientId) {
582
+ if (!confirm("You have unsaved changes. Discard changes and switch patients?")) {
583
+ return; // Do not switch if user cancels
584
+ }
585
+ }
586
  // Update URL without full page reload
587
  history.pushState({ patient_id: patientId }, '', `/doctor_dashboard?patient_id=${patientId}`);
588
  loadPatientDetails(patientId);
589
  }
590
  });
591
+ // Add click event for deletion (delegated)
592
+ $('#patient-list').on('click', '.delete-patient-btn', function(event) {
593
+ // This handler is separate and will only fire for the delete button
594
+ handleDeletePatient($(this).data('id'));
595
+ });
596
 
597
  // After loading the list, check if a patient ID is in the URL or if a patient was previously selected
598
  const urlParams = new URLSearchParams(window.location.search);
599
  const patientIdFromUrl = urlParams.get('patient_id');
600
 
601
+ // Determine which patient ID to try loading initially
602
+ let idToLoad = patientIdFromUrl || currentlySelectedPatientId;
603
+
604
+ if (idToLoad) {
605
+ console.log("Checking for patient from URL or previously selected:", idToLoad);
606
  // Check if this ID exists in the loaded list before trying to load details
607
+ if ($(`.patient-item[data-id="${idToLoad}"]`).length > 0) {
608
+ loadPatientDetails(idToLoad);
609
  } else {
610
+ console.warn(`Patient ID "${idToLoad}" from URL/previous not found in loaded list.`);
611
+ // Clear URL param and reset if patient not found
612
  history.replaceState({}, '', '/doctor_dashboard');
613
  $('#no-patient-selected').show();
614
  $('#patient-details-section').hide();
615
  currentlySelectedPatientId = null; // Reset selected ID
616
+ resetCarePlanEditState(); // Reset edit state
617
+ $whatsappBtn.hide(); // Hide WhatsApp button
618
  }
619
+ } else {
620
+ console.log("No patient ID in URL or previously selected. Showing placeholder.");
 
 
 
 
 
 
 
 
 
 
 
 
 
621
  $('#no-patient-selected').show();
622
  $('#patient-details-section').hide();
623
+ currentlySelectedPatientId = null; // Reset selected ID
624
+ resetCarePlanEditState(); // Reset edit state
625
+ $whatsappBtn.hide(); // Hide WhatsApp button
626
  }
 
 
627
  } else {
628
  console.log("No patients found.");
629
  $('#patient-count').text('0');
 
633
  $('#no-patient-selected').show();
634
  $('#patient-details-section').hide();
635
  currentlySelectedPatientId = null; // Reset selected ID
636
+ resetCarePlanEditState(); // Reset edit state
637
+ $whatsappBtn.hide(); // Hide WhatsApp button
638
  }
639
  },
640
  error: function(xhr, status, error) {
 
647
  $('#no-patient-selected').show();
648
  $('#patient-details-section').hide();
649
  currentlySelectedPatientId = null; // Reset selected ID
650
+ resetCarePlanEditState(); // Reset edit state
651
+ $whatsappBtn.hide(); // Hide WhatsApp button
652
  }
653
  });
654
  }
 
655
  // Load patient details
656
  function loadPatientDetails(patientId) {
657
  console.log("Attempting to load details for patient ID:", patientId);
658
  currentlySelectedPatientId = patientId; // Store the ID
659
 
660
+ // Reset any previous editing state and feedback messages
661
+ resetCarePlanEditState();
662
+ $saveFeedback.empty();
663
+ $whatsappFeedback.empty();
664
+
665
  // Highlight selected patient
666
  $('.patient-item').removeClass('active');
667
  $(`.patient-item[data-id="${patientId}"]`).addClass('active');
 
670
  $('#no-patient-selected').hide();
671
  $('#patient-details-section').show();
672
 
673
+ // Show WhatsApp button for the selected patient
674
+ $whatsappBtn.show();
675
+ // Set up WhatsApp button click handler for the selected patient
676
+ $whatsappBtn.off('click').on('click', function() {
677
+ handleSendWhatsApp(currentlySelectedPatientId);
678
+ });
679
+
680
+
681
  // Optional: Show a loader in the details pane while fetching
682
  // $('#patient-details-section .card-body').html('<div class="loader"></div>');
 
683
  $.ajax({
684
  url: `/get_patient/${patientId}`,
685
  type: 'GET',
 
688
  if (response.success) {
689
  const patient = response.patient;
690
  console.log("Successfully loaded patient details:", patient.name);
 
691
  // Update patient details
692
  $('#patient-name-header').html(`<i class="fas fa-user me-2"></i>${patient.name || 'Unnamed Patient'}`);
693
  $('#patient-age').text(patient.age || 'N/A');
694
  $('#patient-gender').text(patient.gender || 'N/A');
695
  $('#patient-feedback').text(patient.feedback || 'No feedback recorded.');
696
  $('#patient-timestamp').text(patient.timestamp ? new Date(patient.timestamp).toLocaleString() : 'N/A');
 
697
  // Set status badge
698
  const statusText = {
699
  'emergency': 'EMERGENCY',
 
702
  'stable': 'STABLE',
703
  'unknown': 'UNKNOWN'
704
  };
705
+ const statusClass = {
706
+ 'emergency': 'emergency',
707
+ 'deteriorating': 'deteriorating',
708
+ 'improving': 'improving',
709
+ 'stable': 'stable',
710
+ 'unknown': 'unknown'
711
+ };
712
+ const statusBadgeClass = {
713
  'emergency': 'status-emergency',
714
  'deteriorating': 'status-deteriorating',
715
  'improving': 'status-improving',
716
  'stable': 'status-stable',
717
+ 'unknown': 'status-unknown'
718
  };
719
  $('#patient-status')
720
+ .html(`<span class="status-dot ${statusClass[patient.status] || 'unknown'}"></span>${statusText[patient.status] || 'UNKNOWN'}`) // Include dot in HTML
721
+ .attr('class', 'patient-status ' + (statusBadgeClass[patient.status] || 'status-unknown')); // Set class for background
722
+ // Update care plans content - populate both display div and edit textarea
723
+ $updatedPlanDisplay.text(patient.updated_plan || 'No updated care plan available.');
724
+ $updatedPlanEdit.val(patient.updated_plan || 'No updated care plan available.'); // Use .val() for textarea
725
  $('#original-plan-content').text(patient.original_plan || 'No original care plan available (or could not be extracted from PDF).');
 
726
  // Reset tab to updated plan and show content
727
+ $carePlanTabs.removeClass('active').attr('aria-selected', 'false');
728
  $('#updated-plan-tab').addClass('active').attr('aria-selected', 'true');
729
  $('#carePlanTabsContent .tab-pane').removeClass('show active');
730
+ $('#updated-plan-container').addClass('show active');
731
+ // Set up PDF download button click handler for the selected patient
 
 
732
  $('#download-pdf').off('click').on('click', function() {
733
  console.log("Download button clicked for patient ID:", patient.id);
734
  window.location.href = `/download_pdf/${patient.id}`;
735
  });
 
736
  } else {
737
  console.error('Error loading patient details:', response.error);
738
  alert('Error: ' + response.error);
 
741
  $(`.patient-item[data-id="${patientId}"]`).removeClass('active'); // Remove highlight
742
  currentlySelectedPatientId = null; // Reset selected ID
743
  history.replaceState({}, '', '/doctor_dashboard'); // Clear URL param
744
+ resetCarePlanEditState(); // Reset edit state
745
+ $whatsappBtn.hide(); // Hide WhatsApp button
746
  }
747
  },
748
  error: function(xhr, status, error) {
 
753
  $(`.patient-item[data-id="${patientId}"]`).removeClass('active'); // Remove highlight
754
  currentlySelectedPatientId = null; // Reset selected ID
755
  history.replaceState({}, '', '/doctor_dashboard'); // Clear URL param
756
+ resetCarePlanEditState(); // Reset edit state
757
+ $whatsappBtn.hide(); // Hide WhatsApp button
758
  }
759
  });
760
  }
761
 
762
+ // Reset the care plan editing state
763
+ function resetCarePlanEditState() {
764
+ isEditingPlan = false;
765
+ $updatedPlanDisplay.show();
766
+ $updatedPlanEdit.hide();
767
+ $editBtn.show();
768
+ $saveBtn.hide();
769
+ $cancelBtn.hide();
770
+ $saveFeedback.empty();
771
+ $carePlanTabs.prop('disabled', false); // Enable tabs
772
+ }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
773
 
774
+ // Handle Delete Patient Action
775
+ function handleDeletePatient(patientIdToDelete) {
776
+ const $patientItem = $(`.patient-item[data-id="${patientIdToDelete}"]`);
777
+ const patientName = $patientItem.find('h6').text() || 'Unnamed Patient';
778
+ if (confirm(`Are you sure you want to delete the record for ${patientName}? This action cannot be undone.`)) {
779
+ console.log(`Deleting patient ID: ${patientIdToDelete}`);
780
+ // Optionally show a spinner or disable the delete button
781
+ const $deleteBtnIcon = $patientItem.find('.delete-patient-btn i');
782
+ const originalIconClass = $deleteBtnIcon.attr('class');
783
+ $deleteBtnIcon.removeClass().addClass('fas fa-spinner fa-spin');
784
+ $patientItem.find('.delete-patient-btn').prop('disabled', true);
785
+
786
+ $.ajax({
787
+ url: `/delete_patient/${patientIdToDelete}`,
788
+ type: 'DELETE',
789
+ success: function(response) {
790
+ console.log("Delete successful:", response.message);
791
+ // Remove the patient item from the list
792
+ $patientItem.remove();
793
+ // Update patient count
794
+ $('#patient-count').text($('#patient-list li:visible').length); // Count visible items
795
+ // Check if the deleted patient was currently selected
796
+ if (currentlySelectedPatientId === patientIdToDelete) {
797
+ console.log("Deleted currently selected patient. Clearing details pane.");
798
+ $('#patient-details-section').hide();
799
+ $('#no-patient-selected').show();
800
+ currentlySelectedPatientId = null; // Reset selected ID
801
+ history.replaceState({}, '', '/doctor_dashboard'); // Clear URL param
802
+ resetCarePlanEditState(); // Reset edit state
803
+ $whatsappBtn.hide(); // Hide WhatsApp button
804
  }
805
+ // Check if the list is now empty (considering only visible items after search)
806
+ if ($('#patient-list li:visible').length === 0) {
807
+ $('#no-patients-found').show();
808
+ }
809
+ // Reload the full patient list could also be an option here
810
+ // instead of just removing the element, to ensure sorting/alerts are updated
811
+ // loadPatients();
812
+ },
813
+ error: function(xhr, status, error) {
814
+ console.error("Delete failed:", error, xhr.responseText);
815
+ // Re-enable button and restore icon on error
816
+ $deleteBtnIcon.removeClass().addClass(originalIconClass);
817
+ $patientItem.find('.delete-patient-btn').prop('disabled', false);
818
+ let errorMessage = 'An error occurred during deletion.';
819
+ if (xhr.responseJSON && xhr.responseJSON.error) {
820
+ errorMessage = xhr.responseJSON.error;
821
+ } else if (xhr.responseText) {
822
+ errorMessage += ": " + xhr.responseText.substring(0, 100) + "..."; // Avoid long error messages
823
+ } else {
824
+ errorMessage += ": " + error;
825
+ }
826
+ alert(`Error deleting patient: ${errorMessage}`);
827
+ }
828
+ });
829
+ } else {
830
+ console.log("Delete cancelled.");
831
+ }
832
+ }
833
+
834
+
835
+ // Handle Save Care Plan Action
836
+ function handleSaveCarePlan() {
837
+ if (!currentlySelectedPatientId) {
838
+ console.error("No patient selected for saving.");
839
+ $saveFeedback.html('<span class="text-danger">Error: No patient selected.</span>');
840
+ return;
841
  }
842
+ const updatedPlanText = $updatedPlanEdit.val();
843
+
844
+ // Show spinner and disable buttons
845
+ $saveBtn.prop('disabled', true).html('<span class="btn-spinner"></span> Saving...');
846
+ $cancelBtn.prop('disabled', true);
847
+ $editBtn.prop('disabled', true); // Should already be hidden but good practice
848
+ $saveFeedback.empty(); // Clear previous feedback
849
 
850
+ console.log(`Saving plan for patient ID: ${currentlySelectedPatientId}`);
851
 
852
+ $.ajax({
853
+ url: `/update_care_plan/${currentlySelectedPatientId}`,
854
+ type: 'PUT',
855
+ contentType: 'application/json', // Specify content type
856
+ data: JSON.stringify({ updated_plan: updatedPlanText }), // Send as JSON
857
+ success: function(response) {
858
+ console.log("Save successful:", response.message);
859
+ $saveFeedback.html('<span class="text-success"><i class="fas fa-check-circle"></i> Saved!</span>');
860
+
861
+ // Update the display div with the saved text
862
+ $updatedPlanDisplay.text(updatedPlanText);
863
+
864
+ // Revert back to display mode
865
+ resetCarePlanEditState();
866
+ // Re-enable buttons and restore text after a short delay for feedback visibility
867
+ setTimeout(function() {
868
+ $saveBtn.prop('disabled', false).html('<i class="fas fa-save me-1"></i> Save');
869
+ $cancelBtn.prop('disabled', false);
870
+ $editBtn.prop('disabled', false); // Should be visible now
871
+ $saveFeedback.empty(); // Clear success message
872
+ }, 2000);
873
+
874
+
875
+ },
876
+ error: function(xhr, status, error) {
877
+ console.error("Save failed:", error, xhr.responseText);
878
+ let errorMessage = 'An error occurred while saving.';
879
+ if (xhr.responseJSON && xhr.responseJSON.error) {
880
+ errorMessage = xhr.responseJSON.error;
881
+ } else if (xhr.responseText) {
882
+ errorMessage += ": " + xhr.responseText.substring(0, 100) + "..."; // Avoid long error messages
883
+ } else {
884
+ errorMessage += ": " + error;
885
+ }
886
+ $saveFeedback.html(`<span class="text-danger"><i class="fas fa-exclamation-circle"></i> ${errorMessage}</span>`);
887
+ // Re-enable buttons
888
+ $saveBtn.prop('disabled', false).html('<i class="fas fa-save me-1"></i> Save');
889
+ $cancelBtn.prop('disabled', false);
890
+ $editBtn.prop('disabled', false); // Should already be hidden
891
  }
892
  });
893
+ }
894
+
895
+
896
+ // Handle Send WhatsApp Action
897
+ function handleSendWhatsApp(patientIdToSend) {
898
+ if (!patientIdToSend) {
899
+ console.error("No patient selected for sending WhatsApp.");
900
+ $whatsappFeedback.html('<span class="text-danger">Error: No patient selected.</span>');
901
+ return;
902
+ }
903
+
904
+ // Prevent sending if currently editing
905
+ if (isEditingPlan) {
906
+ $whatsappFeedback.html('<span class="text-danger">Finish editing before sending.</span>');
907
+ return;
908
+ }
909
+
910
+ // Show spinner and disable button
911
+ $whatsappBtn.prop('disabled', true).html('<span class="btn-spinner"></span> Sending...');
912
+ $whatsappFeedback.empty(); // Clear previous feedback
913
+
914
+ console.log(`Sending WhatsApp for patient ID: ${patientIdToSend}`);
915
+
916
+ $.ajax({
917
+ url: `/send_whatsapp_doctor/${patientIdToSend}`,
918
+ type: 'POST',
919
+ success: function(response) {
920
+ console.log("WhatsApp send successful:", response.message);
921
+ $whatsappFeedback.html('<span class="text-success"><i class="fab fa-whatsapp"></i> Sent!</span>');
922
+ // Re-enable button and restore text after a short delay for feedback visibility
923
+ setTimeout(function() {
924
+ $whatsappBtn.prop('disabled', false).html('<i class="fab fa-whatsapp me-2"></i>Send via WhatsApp');
925
+ $whatsappFeedback.empty();
926
+ }, 3000); // Show success for 3 seconds
927
+ },
928
+ error: function(xhr, status, error) {
929
+ console.error("WhatsApp send failed:", error, xhr.responseText);
930
+ let errorMessage = 'An error occurred while sending WhatsApp.';
931
+ if (xhr.responseJSON && xhr.responseJSON.error) {
932
+ errorMessage = xhr.responseJSON.error;
933
+ } else if (xhr.responseText) {
934
+ errorMessage += ": " + xhr.responseText.substring(0, 100) + "..."; // Avoid long error messages
935
+ } else {
936
+ errorMessage += ": " + error;
937
+ }
938
+ $whatsappFeedback.html(`<span class="text-danger"><i class="fas fa-exclamation-circle"></i> ${errorMessage}</span>`);
939
+ // Re-enable button immediately
940
+ $whatsappBtn.prop('disabled', false).html('<i class="fab fa-whatsapp me-2"></i>Send via WhatsApp');
941
+ }
942
+ });
943
+ }
944
+
945
+
946
+ // --- Event Listeners for Edit/Save/Cancel ---
947
+
948
+ $editBtn.on('click', function() {
949
+ if (!currentlySelectedPatientId) return; // Do nothing if no patient is selected
950
+
951
+ isEditingPlan = true;
952
+ $updatedPlanDisplay.hide(); // Hide display div
953
+ $updatedPlanEdit.show(); // Show textarea
954
+ $editBtn.hide(); // Hide edit button
955
+ $saveBtn.show(); // Show save button
956
+ $cancelBtn.show(); // Show cancel button
957
+ $saveFeedback.empty(); // Clear any previous feedback
958
+ $whatsappFeedback.empty(); // Clear whatsapp feedback as well
959
+
960
+ // Prevent switching tabs while editing
961
+ $carePlanTabs.prop('disabled', true);
962
+ $('#updated-plan-tab').prop('disabled', false); // Keep current tab enabled
963
+ });
964
+
965
+ $cancelBtn.on('click', function() {
966
+ if (isEditingPlan && confirm("Discard changes?")) {
967
+ // Revert textarea content to the text in the display div (original state before edit)
968
+ $updatedPlanEdit.val($updatedPlanDisplay.text());
969
+ resetCarePlanEditState(); // Revert UI state
970
+ } else if (!isEditingPlan) {
971
+ // If somehow cancel is clicked but not in edit mode, just reset
972
+ resetCarePlanEditState();
973
  }
974
+ // If confirm is false, do nothing (stay in edit mode)
975
+ });
976
+
977
+ $saveBtn.on('click', function() {
978
+ handleSaveCarePlan(); // Trigger the save function
979
  });
980
 
981
 
982
+ // --- Initial Load and Periodic Checks ---
983
+
984
  // Initial patient data load when page is ready
985
  loadPatients();
986
 
 
991
  url: '/get_emergency_notifications',
992
  type: 'GET',
993
  success: function(response) {
994
+ if (response.success) {
995
+ const emergencyPatients = response.notifications; // Assuming endpoint returns list of emergency patients now
996
+ if (emergencyPatients.length > 0) {
997
+ console.log(`Found ${emergencyPatients.length} emergency notifications.`);
998
+ const alertCount = emergencyPatients.length;
999
+ const newAlertHtml = `
1000
  <div class="alert alert-danger mb-3">
1001
  <i class="fas fa-exclamation-triangle me-2"></i>
1002
  <strong>${alertCount} Emergency patient${alertCount > 1 ? 's' : ''} requiring immediate attention!</strong>
1003
  </div>
1004
  `;
1005
+ // Only update if the alert content has changed
1006
+ if ($('#emergency-alerts').html().trim() !== newAlertHtml.trim()) {
1007
+ $('#emergency-alerts').html(newAlertHtml);
1008
+ // Reload the patient list to update sorting and potentially highlight new emergencies
1009
+ console.log("Reloading patient list due to new emergency alerts...");
1010
+ loadPatients(); // This will re-render the list and handle selection from URL/previously selected ID
1011
+ }
1012
+ } else {
1013
+ // If no emergencies, clear the alert area
1014
+ console.log("No emergency notifications.");
1015
+ $('#emergency-alerts').empty();
1016
  }
 
1017
  } else {
1018
+ console.error("Error checking emergency notifications:", response.error);
1019
+ // Optionally display a small error message in the alert area
1020
+ // $('#emergency-alerts').html('<div class="text-danger small">Error checking alerts.</div>');
1021
  }
1022
  },
1023
  error: function(xhr, status, error) {
 
1027
  }
1028
  });
1029
  }
 
1030
  // Check for emergency notifications periodically (e.g., every 30 seconds)
1031
  setInterval(checkEmergencyNotifications, 30000); // 30 seconds
1032
 
1033
+
1034
  // Handle browser back/forward button for URL patient ID
1035
  window.onpopstate = function(event) {
1036
  const urlParams = new URLSearchParams(window.location.search);
1037
  const patientIdFromUrl = urlParams.get('patient_id');
 
1038
  // Compare with the ID of the patient currently *displayed* in the details pane
1039
  // This needs to be tracked separately as loadPatients might be async
 
 
1040
 
1041
+ if (patientIdFromUrl && patientIdFromUrl !== currentlySelectedPatientId) {
1042
  console.log(`URL changed to patient ID: ${patientIdFromUrl}. Attempting to load details.`);
1043
+ // Check if currently editing before switching
1044
+ if (isEditingPlan) {
1045
+ if (!confirm("You have unsaved changes. Discard changes and switch patients?")) {
1046
+ history.pushState({ patient_id: currentlySelectedPatientId }, '', `/doctor_dashboard?patient_id=${currentlySelectedPatientId}`); // Put the old URL back
1047
+ return; // Do not switch if user cancels
1048
+ }
1049
+ }
1050
  // Check if this ID exists in the currently rendered list before calling API
1051
  if ($(`.patient-item[data-id="${patientIdFromUrl}"]`).length > 0) {
1052
  loadPatientDetails(patientIdFromUrl);
 
1057
  $('#no-patient-selected').show();
1058
  currentlySelectedPatientId = null; // Reset
1059
  history.replaceState({}, '', '/doctor_dashboard'); // Clear URL param if not found
1060
+ resetCarePlanEditState(); // Reset edit state
1061
+ $whatsappBtn.hide(); // Hide WhatsApp button
1062
  }
1063
+ } else if (!patientIdFromUrl && currentlySelectedPatientId) {
1064
  // If URL has no ID but a patient is currently displayed, hide details
1065
+ console.log("URL changed, no patient ID. Hiding details.");
1066
+ // Check if currently editing before hiding
1067
+ if (isEditingPlan) {
1068
+ if (!confirm("You have unsaved changes. Discard changes and go back?")) {
1069
+ // Stay on the current page with the patient selected
1070
+ history.pushState({ patient_id: currentlySelectedPatientId }, '', `/doctor_dashboard?patient_id=${currentlySelectedPatientId}`);
1071
+ return; // Do not hide if user cancels
1072
+ }
1073
+ }
1074
  $('.patient-item').removeClass('active'); // Remove highlight
1075
  $('#patient-details-section').hide();
1076
  $('#no-patient-selected').show();
1077
  currentlySelectedPatientId = null; // Reset
1078
+ resetCarePlanEditState(); // Reset edit state
1079
+ $whatsappBtn.hide(); // Hide WhatsApp button
1080
+ } else if (patientIdFromUrl && patientIdFromUrl === currentlySelectedPatientId) {
1081
  // If URL has the same ID as currently displayed, do nothing (user navigated back to the same state)
1082
  console.log("URL changed but same patient ID. No action needed.");
1083
  } else {
 
1087
  $('#patient-details-section').hide();
1088
  $('#no-patient-selected').show();
1089
  currentlySelectedPatientId = null; // Reset
1090
+ resetCarePlanEditState(); // Reset edit state
1091
+ $whatsappBtn.hide(); // Hide WhatsApp button
1092
  }
1093
  };
1094
  });