2025-08-12 13:33:25 +03:00

584 lines
26 KiB
HTML

{% extends "base.html" %}
{% load static %}
{% block title %}Patient Profiles{% endblock %}
{% block content %}
<div class="d-flex align-items-center mb-3">
<div>
<ol class="breadcrumb">
<li class="breadcrumb-item"><a href="{% url 'patients:patient_list' %}">Patients</a></li>
<li class="breadcrumb-item active">Profiles</li>
</ol>
<h1 class="page-header mb-0">Patient Profiles</h1>
</div>
<div class="ms-auto">
<div class="btn-group">
<a href="{% url 'patients:patient_registration' %}" class="btn btn-primary">
<i class="fas fa-plus me-2"></i>Register 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="exportPatients()">
<i class="fas fa-download me-2"></i>Export Patients
</a></li>
<li><a class="dropdown-item" href="#" onclick="importPatients()">
<i class="fas fa-upload me-2"></i>Import Patients
</a></li>
<li><hr class="dropdown-divider"></li>
<li><a class="dropdown-item" href="#" onclick="bulkUpdate()">
<i class="fas fa-edit me-2"></i>Bulk Update
</a></li>
<li><a class="dropdown-item" href="#" onclick="generateReport()">
<i class="fas fa-chart-bar me-2"></i>Generate Report
</a></li>
</ul>
</div>
</div>
</div>
<!-- Statistics Cards -->
<div class="row mb-4">
<div class="col-xl-3 col-md-6">
<div class="card bg-primary text-white">
<div class="card-body">
<div class="d-flex align-items-center">
<div class="flex-grow-1">
<div class="fs-4 fw-bold">{{ total_patients|default:0 }}</div>
<div>Total Patients</div>
</div>
<div class="flex-shrink-0">
<i class="fas fa-users fa-2x opacity-75"></i>
</div>
</div>
</div>
</div>
</div>
<div class="col-xl-3 col-md-6">
<div class="card bg-success text-white">
<div class="card-body">
<div class="d-flex align-items-center">
<div class="flex-grow-1">
<div class="fs-4 fw-bold">{{ active_patients|default:0 }}</div>
<div>Active Patients</div>
</div>
<div class="flex-shrink-0">
<i class="fas fa-user-check fa-2x opacity-75"></i>
</div>
</div>
</div>
</div>
</div>
<div class="col-xl-3 col-md-6">
<div class="card bg-info text-white">
<div class="card-body">
<div class="d-flex align-items-center">
<div class="flex-grow-1">
<div class="fs-4 fw-bold">{{ new_today|default:0 }}</div>
<div>Registered Today</div>
</div>
<div class="flex-shrink-0">
<i class="fas fa-user-plus fa-2x opacity-75"></i>
</div>
</div>
</div>
</div>
</div>
<div class="col-xl-3 col-md-6">
<div class="card bg-warning text-white">
<div class="card-body">
<div class="d-flex align-items-center">
<div class="flex-grow-1">
<div class="fs-4 fw-bold">{{ incomplete_profiles|default:0 }}</div>
<div>Incomplete Profiles</div>
</div>
<div class="flex-shrink-0">
<i class="fas fa-exclamation-triangle fa-2x opacity-75"></i>
</div>
</div>
</div>
</div>
</div>
</div>
<!-- Filters and Search -->
<div class="card mb-4">
<div class="card-body">
<form method="get" class="row g-3">
<div class="col-md-3">
<label for="search" class="form-label">Search</label>
<input type="text"
class="form-control"
id="search"
name="search"
value="{{ request.GET.search }}"
placeholder="Search patients...">
</div>
<div class="col-md-2">
<label for="gender" class="form-label">Gender</label>
<select class="form-select" id="gender" name="gender">
<option value="">All Genders</option>
<option value="male" {% if request.GET.gender == 'male' %}selected{% endif %}>Male</option>
<option value="female" {% if request.GET.gender == 'female' %}selected{% endif %}>Female</option>
<option value="other" {% if request.GET.gender == 'other' %}selected{% endif %}>Other</option>
</select>
</div>
<div class="col-md-2">
<label for="age_range" class="form-label">Age Range</label>
<select class="form-select" id="age_range" name="age_range">
<option value="">All Ages</option>
<option value="0-18" {% if request.GET.age_range == '0-18' %}selected{% endif %}>0-18</option>
<option value="19-35" {% if request.GET.age_range == '19-35' %}selected{% endif %}>19-35</option>
<option value="36-50" {% if request.GET.age_range == '36-50' %}selected{% endif %}>36-50</option>
<option value="51-65" {% if request.GET.age_range == '51-65' %}selected{% endif %}>51-65</option>
<option value="65+" {% if request.GET.age_range == '65+' %}selected{% endif %}>65+</option>
</select>
</div>
<div class="col-md-2">
<label for="status" class="form-label">Status</label>
<select class="form-select" id="status" name="status">
<option value="">All Status</option>
<option value="active" {% if request.GET.status == 'active' %}selected{% endif %}>Active</option>
<option value="inactive" {% if request.GET.status == 'inactive' %}selected{% endif %}>Inactive</option>
</select>
</div>
<div class="col-md-2">
<label for="registration_date" class="form-label">Registration</label>
<select class="form-select" id="registration_date" name="registration_date">
<option value="">All Dates</option>
<option value="today" {% if request.GET.registration_date == 'today' %}selected{% endif %}>Today</option>
<option value="week" {% if request.GET.registration_date == 'week' %}selected{% endif %}>This Week</option>
<option value="month" {% if request.GET.registration_date == 'month' %}selected{% endif %}>This Month</option>
<option value="year" {% if request.GET.registration_date == 'year' %}selected{% endif %}>This Year</option>
</select>
</div>
<div class="col-md-1">
<label class="form-label">&nbsp;</label>
<div class="d-grid">
<button type="submit" class="btn btn-primary">
<i class="fas fa-search"></i>
</button>
</div>
</div>
</form>
</div>
</div>
<!-- Patients Table -->
<div class="card">
<div class="card-header">
<div class="d-flex align-items-center">
<h4 class="card-title mb-0">
<i class="fas fa-list me-2"></i>
Patient Profiles
{% if object_list %}
<span class="badge bg-secondary ms-2">{{ object_list|length }}</span>
{% endif %}
</h4>
<div class="ms-auto">
<div class="btn-group btn-group-sm">
<button type="button" class="btn btn-outline-secondary" onclick="selectAll()">
<i class="fas fa-check-square me-1"></i>Select All
</button>
<button type="button" class="btn btn-outline-secondary" onclick="clearSelection()">
<i class="fas fa-square me-1"></i>Clear
</button>
<button type="button" class="btn btn-outline-primary" onclick="refreshTable()">
<i class="fas fa-sync me-1"></i>Refresh
</button>
</div>
</div>
</div>
</div>
<div class="card-body p-0">
{% if object_list %}
<div class="table-responsive">
<table class="table table-hover mb-0">
<thead class="table-light">
<tr>
<th width="40">
<input type="checkbox" id="selectAllCheckbox" onchange="toggleAll(this)">
</th>
<th>Patient</th>
<th>MRN</th>
<th>Age/Gender</th>
<th>Contact</th>
<th>Primary Care</th>
<th>Registration</th>
<th>Status</th>
<th width="120">Actions</th>
</tr>
</thead>
<tbody>
{% for patient in object_list %}
<tr>
<td>
<input type="checkbox" class="patient-checkbox" value="{{ patient.pk }}">
</td>
<td>
<div class="d-flex align-items-center">
<div class="flex-grow-1">
<div class="fw-bold">
<a href="{% url 'patients:patient_detail' patient.pk %}" class="text-decoration-none">
{{ patient.get_full_name }}
</a>
</div>
{% if patient.date_of_birth %}
<div class="small text-muted">DOB: {{ patient.date_of_birth|date:"M d, Y" }}</div>
{% endif %}
</div>
</div>
</td>
<td>
<span class="badge bg-primary">{{ patient.medical_record_number }}</span>
{% if patient.ssn %}
<div class="small text-muted">SSN: ***-**-{{ patient.ssn|slice:"-4:" }}</div>
{% endif %}
</td>
<td>
<div class="fw-bold">{{ patient.age }} years</div>
<div class="small text-muted">
<i class="fas fa-{% if patient.gender == 'male' %}mars text-primary{% elif patient.gender == 'female' %}venus text-danger{% else %}genderless text-secondary{% endif %} me-1"></i>
{{ patient.get_gender_display }}
</div>
</td>
<td>
{% if patient.phone_number %}
<div class="fw-bold">{{ patient.phone_number }}</div>
{% endif %}
{% if patient.email %}
<div class="small text-muted">{{ patient.email|truncatechars:25 }}</div>
{% endif %}
{% if not patient.phone_number and not patient.email %}
<span class="text-muted">No contact info</span>
{% endif %}
</td>
<td>
{% if patient.primary_care_physician %}
<div class="fw-bold">{{ patient.primary_care_physician.get_full_name }}</div>
<div class="small text-muted">{{ patient.primary_care_physician.department|default:"General" }}</div>
{% else %}
<span class="text-muted">Not assigned</span>
{% endif %}
</td>
<td>
<div class="fw-bold">{{ patient.created_at|date:"M d, Y" }}</div>
<div class="small text-muted">{{ patient.created_at|date:"g:i A" }}</div>
</td>
<td>
<span class="badge bg-{% if patient.is_active %}success{% else %}secondary{% endif %}">
{% if patient.is_active %}Active{% else %}Inactive{% endif %}
</span>
{% if patient.blood_type %}
<div class="small text-danger mt-1">
<i class="fas fa-tint me-1"></i>{{ patient.blood_type }}
</div>
{% endif %}
</td>
<td>
<div class="btn-group btn-group-sm">
<a href="{% url 'patients:patient_detail' patient.pk %}"
class="btn btn-outline-primary"
title="View Profile">
<i class="fas fa-eye"></i>
</a>
<a href="{% url 'patients:patient_form' patient.pk %}"
class="btn btn-outline-secondary"
title="Edit">
<i class="fas fa-edit"></i>
</a>
<button type="button"
class="btn btn-outline-info"
onclick="quickActions({{ patient.pk }})"
title="Quick Actions">
<i class="fas fa-bolt"></i>
</button>
<a href="{% url 'patients:patient_confirm_delete' patient.pk %}"
class="btn btn-outline-danger"
title="Delete">
<i class="fas fa-trash"></i>
</a>
</div>
</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
<!-- Pagination -->
{% if is_paginated %}
<div class="card-footer">
<div class="d-flex justify-content-between align-items-center">
<div>
Showing {{ page_obj.start_index }} to {{ page_obj.end_index }} of {{ paginator.count }} patients
</div>
<nav>
<ul class="pagination pagination-sm mb-0">
{% if page_obj.has_previous %}
<li class="page-item">
<a class="page-link" href="?page=1{% if request.GET.search %}&search={{ request.GET.search }}{% endif %}{% if request.GET.gender %}&gender={{ request.GET.gender }}{% endif %}">First</a>
</li>
<li class="page-item">
<a class="page-link" href="?page={{ page_obj.previous_page_number }}{% if request.GET.search %}&search={{ request.GET.search }}{% endif %}{% if request.GET.gender %}&gender={{ request.GET.gender }}{% endif %}">Previous</a>
</li>
{% endif %}
<li class="page-item active">
<span class="page-link">{{ page_obj.number }}</span>
</li>
{% if page_obj.has_next %}
<li class="page-item">
<a class="page-link" href="?page={{ page_obj.next_page_number }}{% if request.GET.search %}&search={{ request.GET.search }}{% endif %}{% if request.GET.gender %}&gender={{ request.GET.gender }}{% endif %}">Next</a>
</li>
<li class="page-item">
<a class="page-link" href="?page={{ paginator.num_pages }}{% if request.GET.search %}&search={{ request.GET.search }}{% endif %}{% if request.GET.gender %}&gender={{ request.GET.gender }}{% endif %}">Last</a>
</li>
{% endif %}
</ul>
</nav>
</div>
</div>
{% endif %}
<!-- Bulk Actions -->
<div class="card-footer bg-light" id="bulkActions" style="display: none;">
<div class="d-flex align-items-center">
<div class="me-3">
<span id="selectedCount">0</span> patient(s) selected
</div>
<div class="btn-group btn-group-sm">
<button type="button" class="btn btn-success" onclick="bulkActivate()">
<i class="fas fa-check me-1"></i>Activate
</button>
<button type="button" class="btn btn-warning" onclick="bulkDeactivate()">
<i class="fas fa-pause me-1"></i>Deactivate
</button>
<button type="button" class="btn btn-info" onclick="bulkAssignPhysician()">
<i class="fas fa-user-md me-1"></i>Assign Physician
</button>
<button type="button" class="btn btn-outline-primary" onclick="bulkExport()">
<i class="fas fa-download me-1"></i>Export
</button>
<button type="button" class="btn btn-outline-secondary" onclick="bulkPrint()">
<i class="fas fa-print me-1"></i>Print
</button>
<button type="button" class="btn btn-danger" onclick="bulkDelete()">
<i class="fas fa-trash me-1"></i>Delete
</button>
</div>
</div>
</div>
{% else %}
<div class="text-center py-5">
<i class="fas fa-users fa-3x text-muted mb-3"></i>
<h5>No Patients Found</h5>
<p class="text-muted">No patients match your current filters.</p>
<a href="{% url 'patients:patient_registration' %}" class="btn btn-primary">
<i class="fas fa-plus me-2"></i>Register First Patient
</a>
</div>
{% endif %}
</div>
</div>
<!-- Quick Actions Modal -->
<div class="modal fade" id="quickActionsModal" tabindex="-1">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title">Quick Actions</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
</div>
<div class="modal-body">
<div class="d-grid gap-2">
<button type="button" class="btn btn-primary" onclick="scheduleAppointment()">
<i class="fas fa-calendar-plus me-2"></i>Schedule Appointment
</button>
<button type="button" class="btn btn-success" onclick="newEncounter()">
<i class="fas fa-stethoscope me-2"></i>New Encounter
</button>
<button type="button" class="btn btn-info" onclick="orderLabTest()">
<i class="fas fa-flask me-2"></i>Order Lab Test
</button>
<button type="button" class="btn btn-warning" onclick="newPrescription()">
<i class="fas fa-pills me-2"></i>New Prescription
</button>
<button type="button" class="btn btn-outline-secondary" onclick="addNote()">
<i class="fas fa-sticky-note me-2"></i>Add Note
</button>
</div>
</div>
</div>
</div>
</div>
<script>
let currentPatientId = null;
document.addEventListener('DOMContentLoaded', function() {
updateBulkActions();
});
function toggleAll(checkbox) {
const checkboxes = document.querySelectorAll('.patient-checkbox');
checkboxes.forEach(cb => cb.checked = checkbox.checked);
updateBulkActions();
}
function selectAll() {
const checkboxes = document.querySelectorAll('.patient-checkbox');
checkboxes.forEach(cb => cb.checked = true);
document.getElementById('selectAllCheckbox').checked = true;
updateBulkActions();
}
function clearSelection() {
const checkboxes = document.querySelectorAll('.patient-checkbox');
checkboxes.forEach(cb => cb.checked = false);
document.getElementById('selectAllCheckbox').checked = false;
updateBulkActions();
}
function updateBulkActions() {
const checkboxes = document.querySelectorAll('.patient-checkbox:checked');
const count = checkboxes.length;
const bulkActions = document.getElementById('bulkActions');
const selectedCount = document.getElementById('selectedCount');
if (count > 0) {
bulkActions.style.display = 'block';
selectedCount.textContent = count;
} else {
bulkActions.style.display = 'none';
}
}
// Add event listeners to checkboxes
document.addEventListener('change', function(e) {
if (e.target.classList.contains('patient-checkbox')) {
updateBulkActions();
}
});
function getSelectedPatients() {
const checkboxes = document.querySelectorAll('.patient-checkbox:checked');
return Array.from(checkboxes).map(cb => cb.value);
}
function quickActions(patientId) {
currentPatientId = patientId;
const modal = new bootstrap.Modal(document.getElementById('quickActionsModal'));
modal.show();
}
function scheduleAppointment() {
if (currentPatientId) {
window.location.href = `{% url 'appointments:appointment_form' %}?patient=${currentPatientId}`;
}
}
function newEncounter() {
if (currentPatientId) {
window.location.href = `{% url 'emr:encounter_form' %}?patient=${currentPatientId}`;
}
}
function orderLabTest() {
if (currentPatientId) {
window.location.href = `{% url 'laboratory:lab_order_form' %}?patient=${currentPatientId}`;
}
}
function newPrescription() {
if (currentPatientId) {
window.location.href = `{% url 'pharmacy:prescription_form' %}?patient=${currentPatientId}`;
}
}
function addNote() {
if (currentPatientId) {
window.location.href = `{% url 'patients:patient_note_form' %}?patient=${currentPatientId}`;
}
}
function bulkActivate() {
const selected = getSelectedPatients();
if (selected.length === 0) return;
if (confirm(`Activate ${selected.length} selected patient(s)?`)) {
console.log('Activating patients:', selected);
location.reload();
}
}
function bulkDeactivate() {
const selected = getSelectedPatients();
if (selected.length === 0) return;
if (confirm(`Deactivate ${selected.length} selected patient(s)?`)) {
console.log('Deactivating patients:', selected);
location.reload();
}
}
function bulkAssignPhysician() {
const selected = getSelectedPatients();
if (selected.length === 0) return;
// In a real implementation, this would open a physician selection modal
alert('Bulk physician assignment functionality would be implemented here.');
}
function bulkExport() {
const selected = getSelectedPatients();
if (selected.length === 0) return;
console.log('Exporting patients:', selected);
alert('Export functionality would be implemented here.');
}
function bulkPrint() {
const selected = getSelectedPatients();
if (selected.length === 0) return;
console.log('Printing patients:', selected);
alert('Print functionality would be implemented here.');
}
function bulkDelete() {
const selected = getSelectedPatients();
if (selected.length === 0) return;
if (confirm(`Are you sure you want to delete ${selected.length} selected patient(s)? This action cannot be undone.`)) {
console.log('Deleting patients:', selected);
location.reload();
}
}
function refreshTable() {
location.reload();
}
function exportPatients() {
alert('Export all patients functionality would be implemented here.');
}
function importPatients() {
alert('Import patients functionality would be implemented here.');
}
function bulkUpdate() {
alert('Bulk update functionality would be implemented here.');
}
function generateReport() {
alert('Generate report functionality would be implemented here.');
}
</script>
{% endblock %}