rajkhanke's picture
Update templates/index.html
115d907 verified
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Patient Care Management System</title>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0-alpha1/dist/css/bootstrap.min.css" rel="stylesheet">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.1.1/css/all.min.css">
<link href="https://fonts.googleapis.com/css2?family=Nunito:wght@400;600;700;800&display=swap" rel="stylesheet">
<style>
:root {
--primary-color: #4e73df; /* Blue */
--secondary-color: #1cc88a; /* Green */
--danger-color: #e74a3b; /* Red */
--warning-color: #f6c23e; /* Yellow */
--info-color: #36b9cc; /* Cyan */
--dark-color: #5a5c69; /* Dark Grey */
--light-bg: #f8f9fc; /* Light Grey Background */
--border-color: #e3e6f0; /* Light Border */
}
body {
font-family: 'Nunito', sans-serif;
background-color: var(--light-bg);
color: var(--dark-color);
}
.navbar {
background-color: white;
box-shadow: 0 0.15rem 1.75rem 0 rgba(58, 59, 69, 0.15);
}
.navbar-brand {
font-weight: 800;
color: var(--primary-color) !important; /* Override default link color */
}
.card {
border: none;
box-shadow: 0 0.15rem 1.75rem 0 rgba(58, 59, 69, 0.15);
border-radius: 0.35rem;
/* transition: transform 0.3s ease; Removed for form card */
background-color: white;
}
.card:hover {
/* transform: translateY(-5px); Remove slight hover lift for form card */
}
.card-header {
background-color: var(--light-bg);
border-bottom: 1px solid var(--border-color);
font-weight: 700;
color: var(--dark-color);
padding: 1rem 1.25rem;
}
.btn-primary {
background-color: var(--primary-color);
border-color: var(--primary-color);
transition: background-color 0.15s ease-in-out, border-color 0.15s ease-in-out;
}
.btn-primary:hover {
background-color: #2e59d9; /* Darker blue */
border-color: #2653d4;
}
.btn-success {
background-color: var(--secondary-color);
border-color: var(--secondary-color);
}
.btn-danger {
background-color: var(--danger-color);
border-color: var(--danger-color);
}
.form-control:focus {
border-color: var(--primary-color);
box-shadow: 0 0 0 0.25rem rgba(78, 115, 223, 0.25);
}
.form-select:focus {
border-color: var(--primary-color);
box-shadow: 0 0 0 0.25rem rgba(78, 115, 223, 0.25);
}
.role-toggle {
display: flex;
align-items: center;
}
.role-toggle-btn {
display: flex;
align-items: center;
gap: 8px;
background-color: var(--light-bg);
border: 1px solid var(--border-color);
border-radius: 30px;
padding: 0.5rem 1rem;
font-weight: 600;
color: var(--dark-color);
transition: all 0.3s ease;
text-decoration: none; /* Remove underline */
}
.role-toggle-btn:hover {
background-color: #edf2ff; /* Lighter blue */
}
.role-toggle-btn.active {
background-color: var(--primary-color);
color: white;
border-color: var(--primary-color);
}
.main-content {
padding: 1.5rem; /* Reduced padding */
}
.status-badge {
padding: 0.5rem 1rem;
border-radius: 50rem;
color: white;
font-weight: 700;
display: inline-block; /* Added to make it work better with margins */
margin-right: 1rem;
}
.status-emergency {
background-color: var(--danger-color);
}
.status-deteriorating {
background-color: var(--warning-color);
color: #212529; /* Dark text for yellow */
}
.status-improving {
background-color: var(--secondary-color);
}
.status-stable {
background-color: var(--info-color);
}
.status-unknown {
background-color: var(--dark-color);
color: white;
}
.patient-form-container {
max-width: 800px;
margin: 0 auto;
}
.upload-box {
border: 2px dashed var(--border-color);
border-radius: 5px;
padding: 1.5rem; /* Slightly less padding */
text-align: center;
margin-bottom: 1rem;
background-color: #fcfcfc;
transition: border-color 0.2s ease-in-out;
cursor: pointer; /* Indicate it's clickable */
}
.upload-box:hover {
border-color: var(--primary-color);
}
.upload-box input[type="file"] {
display: none; /* Hide the actual file input */
}
.upload-box label {
cursor: pointer; /* Ensure label is clickable */
}
#feedback {
min-height: 150px;
}
.care-plan-output {
background-color: var(--light-bg);
border-radius: 0.35rem;
border: 1px solid var(--border-color);
padding: 1.5rem;
margin-top: 1.5rem; /* Less margin */
white-space: pre-line;
word-wrap: break-word; /* Prevent overflow */
overflow-x: auto; /* Add horizontal scroll if needed */
font-size: 1rem;
color: #333;
}
.loader {
border: 5px solid #f3f3f3;
border-top: 5px solid var(--primary-color);
border-radius: 50%;
width: 50px;
height: 50px;
animation: spin 2s linear infinite;
margin: 2rem auto;
display: none;
}
@keyframes spin {
0% { transform: rotate(0deg); }
100% { transform: rotate(360deg); }
}
#pdf-viewer {
margin-top: 1.5rem; /* Less margin */
border: 1px solid var(--border-color);
border-radius: 0.35rem;
background-color: white;
overflow: hidden; /* Hide scrollbars from parent */
}
#pdf-viewer object {
display: block; /* Remove extra space below object */
}
.success-alert {
display: none;
margin-top: 1.5rem; /* Less margin */
}
.section-title {
color: var(--dark-color); /* Used dark color for title */
font-weight: 700;
margin-bottom: 1.5rem;
position: relative;
padding-bottom: 0.5rem;
font-size: 1.5rem; /* Larger font size */
}
.section-title::after {
content: '';
position: absolute;
left: 0;
bottom: 0;
height: 3px;
width: 60px; /* Wider underline */
background-color: var(--primary-color);
border-radius: 1.5px;
}
.results-container {
margin-top: 2rem;
border-top: 1px dashed var(--border-color); /* Separator line */
padding-top: 2rem;
display: none; /* Hidden by default */
}
.alert-success {
color: #0f5132;
background-color: #d1e7dd;
border-color: #badbcc;
}
.alert-success strong {
color: var(--secondary-color);
}
.alert-danger {
color: #721c24;
background-color: #f8d7da;
border-color: #f5c6cb;
}
.alert-danger strong {
color: var(--danger-color);
}
/* Style for PDF preview container if PDF not shown */
#pdf-viewer.placeholder {
display: flex;
justify-content: center;
align-items: center;
min-height: 200px; /* Give it some height */
color: #6c757d; /* Muted text */
font-style: italic;
}
</style>
</head>
<body>
<!-- Navigation Bar -->
<nav class="navbar navbar-expand-lg navbar-light bg-white px-4 mb-4">
<div class="container-fluid">
<a class="navbar-brand" href="/">
<i class="fas fa-heartbeat me-2"></i>
Patient Care Management
</a>
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarNav">
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse" id="navbarNav">
<ul class="navbar-nav ms-auto">
<li class="nav-item">
<a class="nav-link" href="/" role="button">Home</a>
</li>
<li class="nav-item">
<div class="role-toggle">
<a href="/" class="role-toggle-btn active" data-role="patient">
<i class="fas fa-user"></i> Patient
</a>
<a href="/doctor_dashboard" class="role-toggle-btn ms-2" data-role="doctor">
<i class="fas fa-user-md"></i> Doctor
</a>
</div>
</li>
</ul>
</div>
</div>
</nav>
<div class="container main-content">
<!-- Patient Form -->
<div id="feedback-form" class="patient-form-container">
<div class="card">
<div class="card-header">
<h5 class="mb-0"><i class="fas fa-notes-medical me-2"></i>Submit Patient Feedback</h5>
</div>
<div class="card-body">
<form id="patientForm">
<div class="row mb-3">
<div class="col-md-4">
<label for="name" class="form-label">Patient Name</label>
<input type="text" class="form-control" id="name" name="name" required>
</div>
<div class="col-md-4">
<label for="age" class="form-label">Age</label>
<input type="number" class="form-control" id="age" name="age">
</div>
<div class="col-md-4">
<label for="gender" class="form-label">Gender</label>
<select class="form-select" id="gender" name="gender">
<option value="">Select Gender (Optional)</option>
<option value="Male">Male</option>
<option value="Female">Female</option>
<option value="Other">Other</option>
</select>
</div>
</div>
<div class="mb-3">
<label class="form-label"><i class="fas fa-file-pdf me-1"></i>Current Care Plan (Optional PDF)</label>
<div class="upload-box">
<i class="fas fa-upload fa-2x mb-3" style="color: var(--info-color);"></i>
<h5>Drag & Drop or Click to Upload PDF</h5>
<p class="text-muted mb-0">Accepted format: PDF</p>
<input type="file" id="care_plan_pdf" name="care_plan_pdf" accept=".pdf">
<label for="care_plan_pdf" class="btn btn-outline-primary mt-2"><i class="fas fa-folder-open me-2"></i>Browse Files</label>
<div id="file-name" class="mt-2 text-muted small">No file selected</div>
</div>
</div>
<div class="mb-3">
<label for="feedback" class="form-label"><i class="fas fa-comment-medical me-1"></i>Current Symptoms & Feedback <span class="text-danger">*</span></label>
<textarea class="form-control" id="feedback" name="feedback" rows="5" placeholder="Please describe your current symptoms, any changes in your condition, and feedback about your current care plan..." required></textarea>
</div>
<button type="submit" class="btn btn-primary w-100 py-2" id="submit-btn">
<i class="fas fa-sync-alt me-2"></i>Generate Updated Care Plan
</button>
</form>
<div class="loader" id="loader"></div>
<div id="api-error-alert" class="alert alert-danger mt-3" style="display: none;">
<i class="fas fa-exclamation-circle me-2"></i> <strong>Error:</strong> <span id="api-error-message"></span>
</div>
<div class="alert alert-success success-alert" id="whatsapp-alert">
<i class="fab fa-whatsapp me-2"></i> <strong>Success!</strong> Your updated care plan has been sent to your WhatsApp number (if configured).
</div>
<div class="alert alert-warning success-alert" id="whatsapp-fail-alert" style="display: none;">
<i class="fab fa-whatsapp me-2"></i> <strong>Note:</strong> Could not send WhatsApp message (Twilio not configured or error).
</div>
<!-- Results Section -->
<div id="results" class="results-container" style="display: none;">
<h4 class="section-title">Generated Care Plan Result</h4>
<div class="d-flex justify-content-between align-items-center mb-3">
<div>Status: <span id="status-badge" class="status-badge"></span></div>
<button id="download-pdf" class="btn btn-primary" disabled>
<i class="fas fa-file-download me-2"></i>Download PDF
</button>
</div>
<h5>Generated Plan Text:</h5>
<div class="care-plan-output" id="care-plan-output"></div>
</div>
</div>
</div>
</div>
</div>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0-alpha1/dist/js/bootstrap.bundle.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.0/jquery.min.js"></script>
<script>
$(document).ready(function() {
// Set active role button on load
$('.role-toggle-btn[data-role="patient"]').addClass('active');
$('.role-toggle-btn[data-role="doctor"]').removeClass('active');
// Handle file upload display
$('#care_plan_pdf').change(function() {
if (this.files && this.files.length > 0) {
$('#file-name').text(this.files[0].name);
} else {
$('#file-name').text('No file selected');
}
});
// Handle drag and drop for upload box
const uploadBox = $('.upload-box');
uploadBox.on('dragover', function(e) {
e.preventDefault();
e.stopPropagation();
$(this).addClass('border-primary');
});
uploadBox.on('dragleave', function(e) {
e.preventDefault();
e.stopPropagation();
$(this).removeClass('border-primary');
});
uploadBox.on('drop', function(e) {
e.preventDefault();
e.stopPropagation();
$(this).removeClass('border-primary');
const files = e.originalEvent.dataTransfer.files;
if (files.length > 0 && files[0].type === 'application/pdf') {
$('#care_plan_pdf')[0].files = files;
$('#file-name').text(files[0].name);
} else {
alert("Only PDF files are allowed.");
$('#file-name').text('No file selected');
}
});
// Prevent default drag/drop on body to avoid opening file
$('body').on('dragover', function(e) { e.preventDefault(); e.stopPropagation(); });
$('body').on('drop', function(e) { e.preventDefault(); e.stopPropagation(); });
// Form submission
$('#patientForm').submit(function(e) {
e.preventDefault();
// Clear previous results, alerts, hide API error
$('#loader').show();
$('#submit-btn').prop('disabled', true).find('i').removeClass().addClass('fas fa-spinner fa-spin me-2'); // Disable button & show spinner
$('#results').hide();
$('#whatsapp-alert').hide();
$('#whatsapp-fail-alert').hide();
$('#api-error-alert').hide();
$('#pdf-viewer').html('<p class="text-muted text-center p-4">Generating PDF preview...</p>').removeClass('placeholder'); // Clear previous PDF preview and add placeholder
$('#download-pdf').prop('disabled', true); // Disable download button
// Create FormData object for file upload
const formData = new FormData(this);
// Send AJAX request
$.ajax({
url: '/submit_feedback',
type: 'POST',
data: formData,
contentType: false, // Required for FormData
processData: false, // Required for FormData
success: function(response) {
$('#loader').hide();
$('#submit-btn').prop('disabled', false).find('i').removeClass().addClass('fas fa-sync-alt me-2'); // Re-enable button & restore icon
if (response.success) {
console.log("Submission successful:", response);
// Store patient ID for download button
const patientId = response.patient_id;
// Display results section
$('#results').fadeIn();
$('#care-plan-output').text(response.updated_plan);
// Set status badge
const statusText = {
'emergency': 'EMERGENCY',
'deteriorating': 'HIGH RISK',
'improving': 'IMPROVING',
'stable': 'STABLE',
'unknown': 'UNKNOWN'
};
const statusBadgeClass = {
'emergency': 'status-emergency',
'deteriorating': 'status-deteriorating',
'improving': 'status-improving',
'stable': 'status-stable',
'unknown': 'status-unknown'
};
$('#status-badge')
.text(statusText[response.status] || 'UNKNOWN')
.attr('class', 'status-badge ' + (statusBadgeClass[response.status] || 'status-unknown'));
// Set up PDF download button with patient ID
$('#download-pdf').prop('disabled', false); // Enable download button
$('#download-pdf').off('click').on('click', function() { // Use .off().on() to prevent multiple handlers
console.log("Download PDF button clicked, ID:", patientId);
// Direct link for download
window.location.href = '/download_pdf/' + patientId;
});
// Display PDF preview if available (using base64 data from response)
if (response.pdf_data) {
const pdfData = `data:application/pdf;base64,${response.pdf_data}`;
// Use <object> for embedding PDF
$('#pdf-viewer').html(`<object data="${pdfData}" type="application/pdf" width="100%" height="500px">
<p>Your browser does not support PDFs. You can download the PDF instead.</p>
</object>`).removeClass('placeholder');
console.log("PDF preview embedded.");
} else {
$('#pdf-viewer').html('<p class="text-muted text-center p-4">PDF preview not available.</p>').addClass('placeholder');
console.log("PDF data missing or error during PDF generation on server.");
}
// Show WhatsApp notification
if (response.whatsapp_sent === true) {
$('#whatsapp-alert').fadeIn();
} else if (response.whatsapp_sent === false) {
$('#whatsapp-fail-alert').fadeIn();
}
// Clear the form after successful submission
$('#patientForm')[0].reset();
$('#file-name').text('No file selected'); // Clear file name display
} else {
console.error("Submission failed:", response.error);
$('#api-error-message').text(response.error || 'An unknown error occurred.');
$('#api-error-alert').fadeIn();
// If AI generation failed but fallback plan provided
if(response.fallback_plan){
$('#results').fadeIn();
$('#care-plan-output').text(response.fallback_plan);
// Set status badge (using status from fallback response)
const statusText = {
'emergency': 'EMERGENCY',
'deteriorating': 'HIGH RISK',
'improving': 'IMPROVING',
'stable': 'STABLE',
'unknown': 'UNKNOWN'
};
const statusBadgeClass = {
'emergency': 'status-emergency',
'deteriorating': 'status-deteriorating',
'improving': 'status-improving',
'stable': 'status-stable',
'unknown': 'status-unknown'
};
$('#status-badge')
.text(statusText[response.status] || 'UNKNOWN')
.attr('class', 'status-badge ' + (statusBadgeClass[response.status] || 'status-unknown'));
// No PDF data in error response, show placeholder
$('#pdf-viewer').html('<p class="text-muted text-center p-4">PDF preview not available due to generation error.</p>').addClass('placeholder');
$('#download-pdf').prop('disabled', true); // Keep download disabled
}
}
},
error: function(xhr, status, error) {
$('#loader').hide();
$('#submit-btn').prop('disabled', false).find('i').removeClass().addClass('fas fa-sync-alt me-2'); // Re-enable button & restore icon
$('#download-pdf').prop('disabled', true); // Disable download button
let errorMessage = 'An error occurred. Please try again.';
if (xhr.responseJSON && xhr.responseJSON.error) {
errorMessage = xhr.responseJSON.error;
} else if (xhr.responseText) {
errorMessage += ": " + xhr.responseText; // Show raw error if not specific JSON
} else {
errorMessage += ": " + error;
}
console.error("AJAX error:", status, error, xhr.responseText);
$('#api-error-message').text(errorMessage);
$('#api-error-alert').fadeIn();
$('#pdf-viewer').html('<p class="text-muted text-center p-4">PDF preview not available due to error.</p>').addClass('placeholder');
}
});
});
});
</script>
</body>
</html>