hospital-management/templates/patients/patient_detail.html
Marwan Alwali 610e165e17 update
2025-09-04 19:19:52 +03:00

517 lines
23 KiB
HTML

{% extends "base.html" %}
{% load static %}
{% block title %}{{ patient.get_full_name }} - Patient Details - {{ block.super }}{% endblock %}
{% block content %}
<div class="container-fluid">
<!-- Page Header -->
<div class="d-flex justify-content-between align-items-center mb-4">
<div>
<h1 class="h3 mb-1">{{ patient.get_full_name }}</h1>
<nav aria-label="breadcrumb">
<ol class="breadcrumb mb-0">
<li class="breadcrumb-item"><a href="{% url 'core:dashboard' %}">Dashboard</a></li>
<li class="breadcrumb-item"><a href="{% url 'patients:patient_list' %}">Patients</a></li>
<li class="breadcrumb-item active">{{ patient.get_full_name }}</li>
</ol>
</nav>
<div class="mt-2">
<span class="badge bg-primary me-2">MRN: {{ patient.mrn }}</span>
<span class="badge bg-info me-2">{{ patient.get_gender_display }}</span>
<span class="badge bg-secondary me-2">Age: {{ patient.age }}</span>
{% if patient.is_vip %}
<span class="badge bg-warning text-dark me-2">VIP</span>
{% endif %}
{% if patient.status == 'ACTIVE' %}
<span class="badge bg-success">Active</span>
{% elif patient.status == 'INACTIVE' %}
<span class="badge bg-secondary">Inactive</span>
{% elif patient.status == 'DECEASED' %}
<span class="badge bg-dark">Deceased</span>
{% endif %}
</div>
</div>
<div class="btn-group">
<a href="{% url 'patients:patient_update' patient.pk %}" class="btn btn-primary">
<i class="fas fa-edit me-2"></i>Edit Patient
</a>
<button type="button" class="btn btn-outline-secondary dropdown-toggle dropdown-toggle-split" data-bs-toggle="dropdown">
<span class="visually-hidden">Toggle Dropdown</span>
</button>
<ul class="dropdown-menu">
<li><a class="dropdown-item" href="#" onclick="printPatient()">
<i class="fas fa-print me-2"></i>Print Summary
</a></li>
<li><a class="dropdown-item" href="?export=pdf">
<i class="fas fa-file-pdf me-2"></i>Export PDF
</a></li>
<li><a class="dropdown-item" href="{% url 'appointments:appointment_create' %}?patient={{ patient.pk }}">
<i class="fas fa-calendar-plus me-2"></i>Schedule Appointment
</a></li>
<li><hr class="dropdown-divider"></li>
{# <li><a class="dropdown-item" href="{% url 'patients:patient_deactivate' patient.pk %}">#}
{# <i class="fas fa-user-slash me-2"></i>Deactivate Patient#}
{# </a></li>#}
{# <li><a class="dropdown-item text-danger" href="{% url 'patients:patient_delete' patient.pk %}">#}
{# <i class="fas fa-trash me-2"></i>Delete Patient#}
{# </a></li>#}
</ul>
</div>
</div>
<div class="row">
<!-- Left Column - Patient Information -->
<div class="col-lg-4">
<!-- Patient Photo & Basic Info -->
<div class="card mb-4">
<div class="card-body text-center">
{% if patient.photo %}
<img src="{{ patient.photo.url }}" alt="Patient Photo" class="img-fluid rounded-circle mb-3" style="width: 150px; height: 150px; object-fit: cover;">
{% else %}
<div class="bg-light rounded-circle d-inline-flex align-items-center justify-content-center mb-3" style="width: 150px; height: 150px;">
<i class="fas fa-user fa-4x text-muted"></i>
</div>
{% endif %}
<h5 class="mb-1">{{ patient.get_full_name }}</h5>
<p class="text-muted mb-3">{{ patient.get_gender_display }} • {{ patient.age }} years old</p>
<div class="row text-center">
<div class="col-4">
<div class="border-end">
<h6 class="mb-0">{{ patient.appointments.count }}</h6>
<small class="text-muted">Appointments</small>
</div>
</div>
<div class="col-4">
<div class="border-end">
<h6 class="mb-0">{{ patient.admissions.count }}</h6>
<small class="text-muted">Admissions</small>
</div>
</div>
<div class="col-4">
<h6 class="mb-0">{{ patient.bills.count }}</h6>
<small class="text-muted">Bills</small>
</div>
</div>
</div>
</div>
<!-- Personal Information -->
<div class="card mb-4">
<div class="card-header">
<h5 class="mb-0">
<i class="fas fa-user me-2"></i>Personal Information
</h5>
</div>
<div class="card-body">
<div class="row mb-3">
<div class="col-sm-5"><strong>Date of Birth:</strong></div>
<div class="col-sm-7">{{ patient.date_of_birth|date:"F d, Y" }}</div>
</div>
<div class="row mb-3">
<div class="col-sm-5"><strong>Gender:</strong></div>
<div class="col-sm-7">{{ patient.get_gender_display }}</div>
</div>
<div class="row mb-3">
<div class="col-sm-5"><strong>Phone:</strong></div>
<div class="col-sm-7">
{% if patient.phone_number %}
<a href="tel:{{ patient.phone_number }}">{{ patient.phone_number }}</a>
{% else %}
<span class="text-muted">Not provided</span>
{% endif %}
</div>
</div>
<div class="row mb-3">
<div class="col-sm-5"><strong>Email:</strong></div>
<div class="col-sm-7">
{% if patient.email %}
<a href="mailto:{{ patient.email }}">{{ patient.email }}</a>
{% else %}
<span class="text-muted">Not provided</span>
{% endif %}
</div>
</div>
<div class="row mb-3">
<div class="col-sm-5"><strong>Address:</strong></div>
<div class="col-sm-7">
{% if patient.address %}
{{ patient.address }}
{% else %}
<span class="text-muted">Not provided</span>
{% endif %}
</div>
</div>
<div class="row mb-3">
<div class="col-sm-5"><strong>SSN:</strong></div>
<div class="col-sm-7">
{% if patient.ssn %}
***-**-{{ patient.ssn|slice:"-4:" }}
{% else %}
<span class="text-muted">Not provided</span>
{% endif %}
</div>
</div>
<div class="row">
<div class="col-sm-5"><strong>Registered:</strong></div>
<div class="col-sm-7">{{ patient.registration_date|date:"F d, Y" }}</div>
</div>
</div>
</div>
<!-- Emergency Contacts -->
<div class="card mb-4">
<div class="card-header d-flex justify-content-between align-items-center">
<h5 class="mb-0">
<i class="fas fa-phone me-2"></i>Emergency Contacts
</h5>
<a href="{% url 'patients:emergency_contact_create' patient.pk %}" class="btn btn-sm btn-outline-primary">
<i class="fas fa-plus me-1"></i>Add
</a>
</div>
<div class="card-body" id="emergency-contacts"
hx-get="{% url 'patients:emergency_contacts_list' patient.id %}"
hx-trigger="load">
<div class="text-center">
<div class="spinner-border spinner-border-sm text-primary" role="status">
<span class="visually-hidden">Loading...</span>
</div>
</div>
</div>
</div>
<!-- Insurance Information -->
<div class="card mb-4">
<div class="card-header d-flex justify-content-between align-items-center">
<h5 class="mb-0">
<i class="fas fa-shield-alt me-2"></i>Insurance Information
</h5>
<a href="{% url 'patients:insurance_create' patient.pk %}" class="btn btn-sm btn-outline-primary">
<i class="fas fa-plus me-1"></i>Add
</a>
</div>
<div class="card-body" id="insurance-info"
hx-get="{% url 'patients:insurance_info_list' patient.id %}"
hx-trigger="load">
<div class="text-center">
<div class="spinner-border spinner-border-sm text-primary" role="status">
<span class="visually-hidden">Loading...</span>
</div>
</div>
</div>
</div>
</div>
<!-- Right Column - Medical Information & Activities -->
<div class="col-lg-8">
<!-- Quick Actions -->
<div class="card mb-4">
<div class="card-header">
<h5 class="mb-0">
<i class="fas fa-bolt me-2"></i>Quick Actions
</h5>
</div>
<div class="card-body">
<div class="row g-3">
<div class="col-md-3">
<a href="{% url 'appointments:appointment_create' %}?patient={{ patient.pk }}" class="btn btn-outline-primary w-100">
<i class="fas fa-calendar-plus d-block mb-2"></i>
Schedule Appointment
</a>
</div>
<div class="col-md-3">
<a href="{% url 'emr:encounter_create' %}?patient={{ patient.pk }}" class="btn btn-outline-success w-100">
<i class="fas fa-notes-medical d-block mb-2"></i>
New Encounter
</a>
</div>
<div class="col-md-3">
<a href="{% url 'laboratory:lab_order_create' %}?patient={{ patient.pk }}" class="btn btn-outline-info w-100">
<i class="fas fa-vial d-block mb-2"></i>
Lab Order
</a>
</div>
<div class="col-md-3">
<a href="{% url 'billing:bill_create' %}?patient={{ patient.pk }}" class="btn btn-outline-warning w-100">
<i class="fas fa-file-invoice-dollar d-block mb-2"></i>
Create Bill
</a>
</div>
</div>
</div>
</div>
<!-- Tabs for Different Sections -->
<div class="card">
<div class="card-header">
<ul class="nav nav-tabs card-header-tabs" id="patientTabs" role="tablist">
<li class="nav-item" role="presentation">
<button class="nav-link active" id="appointments-tab" data-bs-toggle="tab" data-bs-target="#appointments" type="button" role="tab">
<i class="fas fa-calendar me-2"></i>Appointments
</button>
</li>
<li class="nav-item" role="presentation">
<button class="nav-link" id="medical-history-tab" data-bs-toggle="tab" data-bs-target="#medical-history" type="button" role="tab">
<i class="fas fa-notes-medical me-2"></i>Medical History
</button>
</li>
<li class="nav-item" role="presentation">
<button class="nav-link" id="lab-results-tab" data-bs-toggle="tab" data-bs-target="#lab-results" type="button" role="tab">
<i class="fas fa-vial me-2"></i>Lab Results
</button>
</li>
<li class="nav-item" role="presentation">
<button class="nav-link" id="billing-tab" data-bs-toggle="tab" data-bs-target="#billing" type="button" role="tab">
<i class="fas fa-file-invoice me-2"></i>Billing
</button>
</li>
<li class="nav-item" role="presentation">
<button class="nav-link" id="notes-tab" data-bs-toggle="tab" data-bs-target="#notes" type="button" role="tab">
<i class="fas fa-sticky-note me-2"></i>Notes
</button>
</li>
</ul>
</div>
<div class="card-body">
<div class="tab-content" id="patientTabsContent">
<!-- Appointments Tab -->
<div class="tab-pane fade show active" id="appointments" role="tabpanel">
<div hx-get="{% url 'patients:patient_appointments' patient.id %}"
hx-trigger="load">
<div class="text-center">
<div class="spinner-border text-primary" role="status">
<span class="visually-hidden">Loading appointments...</span>
</div>
</div>
</div>
</div>
<!-- Medical History Tab -->
{# <div class="tab-pane fade" id="medical-history" role="tabpanel">#}
{# <div hx-get="{% url 'patients:patient_medical_history' patient.id %}"#}
{# hx-trigger="intersection once">#}
{# <div class="text-center">#}
{# <div class="spinner-border text-primary" role="status">#}
{# <span class="visually-hidden">Loading medical history...</span>#}
{# </div>#}
{# </div>#}
{# </div>#}
{# </div>#}
<!-- Lab Results Tab -->
{# <div class="tab-pane fade" id="lab-results" role="tabpanel">#}
{# <div hx-get="{% url 'patients:patient_lab_results' patient.id %}"#}
{# hx-trigger="intersection once">#}
{# <div class="text-center">#}
{# <div class="spinner-border text-primary" role="status">#}
{# <span class="visually-hidden">Loading lab results...</span>#}
{# </div>#}
{# </div>#}
{# </div>#}
{# </div>#}
<!-- Billing Tab -->
{# <div class="tab-pane fade" id="billing" role="tabpanel">#}
{# <div hx-get="{% url 'patients:patient_billing' patient.id %}"#}
{# hx-trigger="intersection once">#}
{# <div class="text-center">#}
{# <div class="spinner-border text-primary" role="status">#}
{# <span class="visually-hidden">Loading billing information...</span>#}
{# </div>#}
{# </div>#}
{# </div>#}
{# </div>#}
<!-- Notes Tab -->
<div class="tab-pane fade" id="notes" role="tabpanel">
<div class="d-flex justify-content-between align-items-center mb-3">
<h6 class="mb-0">Patient Notes</h6>
<button type="button" class="btn btn-sm btn-primary" data-bs-toggle="modal" data-bs-target="#addNoteModal">
<i class="fas fa-plus me-1"></i>Add Note
</button>
</div>
<div hx-get="{% url 'patients:patient_notes_list' patient.id %}"
hx-trigger="intersection once">
<div class="text-center">
<div class="spinner-border text-primary" role="status">
<span class="visually-hidden">Loading notes...</span>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<!-- Add Note Modal -->
<div class="modal fade" id="addNoteModal" tabindex="-1">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title">Add Patient Note</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
</div>
<form hx-post="{% url 'patients:patient_note_create' patient.id %}"
hx-target="#notes .tab-pane"
hx-swap="innerHTML">
<div class="modal-body">
{% csrf_token %}
<div class="mb-3">
<label for="noteType" class="form-label">Note Type</label>
<select class="form-select" id="noteType" name="note_type" required>
<option value="">Select type...</option>
<option value="GENERAL">General</option>
<option value="MEDICAL">Medical</option>
<option value="ADMINISTRATIVE">Administrative</option>
<option value="BILLING">Billing</option>
<option value="INSURANCE">Insurance</option>
</select>
</div>
<div class="mb-3">
<label for="noteContent" class="form-label">Note Content</label>
<textarea class="form-control" id="noteContent" name="content" rows="4" required></textarea>
</div>
<div class="form-check">
<input class="form-check-input" type="checkbox" id="isConfidential" name="is_confidential">
<label class="form-check-label" for="isConfidential">
Confidential Note
</label>
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Cancel</button>
<button type="submit" class="btn btn-primary">Add Note</button>
</div>
</form>
</div>
</div>
</div>
<script>
// Print patient summary
function printPatient() {
window.print();
}
// Auto-refresh emergency contacts and insurance info
setInterval(function() {
htmx.trigger('#emergency-contacts', 'refresh');
htmx.trigger('#insurance-info', 'refresh');
}, 300000); // Refresh every 5 minutes
// Tab switching with HTMX loading
document.addEventListener('DOMContentLoaded', function() {
const tabTriggers = document.querySelectorAll('#patientTabs button[data-bs-toggle="tab"]');
tabTriggers.forEach(function(tab) {
tab.addEventListener('shown.bs.tab', function(event) {
const targetPane = document.querySelector(event.target.getAttribute('data-bs-target'));
const htmxElement = targetPane.querySelector('[hx-get]');
if (htmxElement && !htmxElement.hasAttribute('data-loaded')) {
htmx.trigger(htmxElement, 'load');
htmxElement.setAttribute('data-loaded', 'true');
}
});
});
});
// Handle note modal submission
document.getElementById('addNoteModal').addEventListener('hidden.bs.modal', function() {
this.querySelector('form').reset();
});
</script>
<style>
.card {
box-shadow: 0 0.125rem 0.25rem rgba(0, 0, 0, 0.075);
border: 1px solid rgba(0, 0, 0, 0.125);
}
.card-header {
background-color: rgba(13, 110, 253, 0.1);
border-bottom: 1px solid rgba(0, 0, 0, 0.125);
}
.btn {
border-radius: 0.375rem;
transition: all 0.15s ease-in-out;
}
.btn:hover:not(:disabled) {
transform: translateY(-1px);
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
}
.nav-tabs .nav-link {
border-radius: 0.375rem 0.375rem 0 0;
}
.nav-tabs .nav-link.active {
background-color: #fff;
border-color: #dee2e6 #dee2e6 #fff;
}
.badge {
font-size: 0.75rem;
}
.border-end {
border-right: 1px solid #dee2e6 !important;
}
.htmx-indicator {
opacity: 0;
transition: opacity 0.3s ease-in-out;
}
.htmx-request .htmx-indicator {
opacity: 1;
}
/* Print styles */
@media print {
.btn, .dropdown, .nav-tabs, #addNoteModal {
display: none !important;
}
.card {
border: 1px solid #000 !important;
box-shadow: none !important;
}
.tab-content .tab-pane {
display: block !important;
opacity: 1 !important;
}
}
@media (max-width: 768px) {
.btn-group {
display: flex;
flex-direction: column;
gap: 0.5rem;
}
.d-flex.justify-content-between {
flex-direction: column;
gap: 1rem;
}
.nav-tabs {
flex-wrap: wrap;
}
.nav-tabs .nav-link {
font-size: 0.875rem;
padding: 0.5rem 0.75rem;
}
}
</style>
{% endblock %}