hospital-management/templates/extras/appointment_request_list.html
Marwan Alwali a710d1c4d8 update
2025-09-11 19:01:55 +03:00

410 lines
23 KiB
HTML

{% extends "base.html" %}
{% load static %}
{% block title %}Appointment Requests - Appointments{% endblock %}
{% block content %}
<div class="container-fluid">
<!-- Breadcrumb -->
<div class="row">
<div class="col-12">
<div class="page-title-box d-sm-flex align-items-center justify-content-between">
<h4 class="mb-sm-0">Appointment Requests</h4>
<div class="page-title-right">
<ol class="breadcrumb m-0">
<li class="breadcrumb-item"><a href="{% url 'core:dashboard' %}">Dashboard</a></li>
<li class="breadcrumb-item"><a href="{% url 'appointments:dashboard' %}">Appointments</a></li>
<li class="breadcrumb-item active">Requests</li>
</ol>
</div>
</div>
</div>
</div>
<!-- Action Bar -->
<div class="row mb-3">
<div class="col-12">
<div class="card">
<div class="card-body py-2">
<div class="d-flex justify-content-between align-items-center">
<div class="d-flex gap-2">
<a href="{% url 'appointments:appointment_request_create' %}" class="btn btn-primary">
<i class="fas fa-plus me-1"></i>
New Request
</a>
<button type="button" class="btn btn-outline-secondary" data-bs-toggle="collapse" data-bs-target="#filterCollapse">
<i class="fas fa-filter me-1"></i>
Filters
</button>
<button type="button" class="btn btn-outline-success" onclick="exportData()">
<i class="fas fa-download me-1"></i>
Export
</button>
</div>
<div class="d-flex gap-2">
<div class="input-group" style="width: 300px;">
<input type="text" class="form-control" placeholder="Search requests..."
id="searchInput" value="{{ request.GET.search }}">
<button class="btn btn-outline-secondary" type="button" onclick="performSearch()">
<i class="fas fa-search"></i>
</button>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<!-- Filters -->
<div class="collapse {% if request.GET %}show{% endif %}" id="filterCollapse">
<div class="row mb-3">
<div class="col-12">
<div class="card">
<div class="card-body">
<form method="get" id="filterForm">
<div class="row g-3">
<div class="col-md-3">
{{ search_form.appointment_type }}
</div>
<div class="col-md-3">
{{ search_form.status }}
</div>
<div class="col-md-3">
{{ search_form.priority }}
</div>
<div class="col-md-3">
{{ search_form.provider }}
</div>
<div class="col-md-3">
{{ search_form.date_from }}
</div>
<div class="col-md-3">
{{ search_form.date_to }}
</div>
<div class="col-md-3">
{{ search_form.department }}
</div>
<div class="col-md-3">
<div class="form-check mt-2">
{{ search_form.is_telemedicine }}
<label class="form-check-label" for="{{ search_form.is_telemedicine.id_for_label }}">
Telemedicine Only
</label>
</div>
</div>
<div class="col-12">
<div class="d-flex gap-2">
<button type="submit" class="btn btn-primary">
<i class="fas fa-filter me-1"></i>
Apply Filters
</button>
<a href="{% url 'appointments:appointment_request_list' %}" class="btn btn-secondary">
<i class="fas fa-times me-1"></i>
Clear
</a>
</div>
</div>
</div>
</form>
</div>
</div>
</div>
</div>
</div>
<!-- Appointment Requests List -->
<div class="row">
<div class="col-12">
<div class="card">
<div class="card-header">
<div class="d-flex justify-content-between align-items-center">
<h5 class="card-title mb-0">
<i class="fas fa-calendar-alt me-2"></i>
Appointment Requests
<span class="badge bg-primary ms-2">{{ object_list.count }}</span>
</h5>
<div class="d-flex gap-2">
<div class="btn-group" role="group">
<input type="radio" class="btn-check" name="viewMode" id="listView" checked>
<label class="btn btn-outline-secondary btn-sm" for="listView">
<i class="fas fa-list"></i>
</label>
<input type="radio" class="btn-check" name="viewMode" id="cardView">
<label class="btn btn-outline-secondary btn-sm" for="cardView">
<i class="fas fa-th"></i>
</label>
</div>
</div>
</div>
</div>
<div class="card-body p-0">
{% if object_list %}
<!-- Table View -->
<div id="tableView" class="table-responsive">
<table class="table table-hover mb-0">
<thead class="table-light">
<tr>
<th>
<div class="form-check">
<input class="form-check-input" type="checkbox" id="selectAll">
</div>
</th>
<th>Patient</th>
<th>Provider</th>
<th>Date & Time</th>
<th>Type</th>
<th>Status</th>
<th>Priority</th>
<th>Actions</th>
</tr>
</thead>
<tbody>
{% for appointment in object_list %}
<tr>
<td>
<div class="form-check">
<input class="form-check-input row-select" type="checkbox" value="{{ appointment.pk }}">
</div>
</td>
<td>
<div class="d-flex align-items-center">
<div class="avatar-sm me-2">
<div class="avatar-title bg-light text-primary rounded-circle">
{{ appointment.patient.first_name.0 }}{{ appointment.patient.last_name.0 }}
</div>
</div>
<div>
<h6 class="mb-0">{{ appointment.patient.get_full_name }}</h6>
<small class="text-muted">{{ appointment.patient.patient_id }}</small>
</div>
</div>
</td>
<td>
<div>
<h6 class="mb-0">{{ appointment.provider.get_full_name }}</h6>
<small class="text-muted">{{ appointment.department|default:"General" }}</small>
</div>
</td>
<td>
<div>
<h6 class="mb-0">{{ appointment.scheduled_datetime|date:"M d, Y" }}</h6>
<small class="text-muted">{{ appointment.scheduled_datetime|time:"g:i A" }}</small>
</div>
</td>
<td>
<span class="badge bg-info">{{ appointment.get_appointment_type_display }}</span>
{% if appointment.is_telemedicine %}
<br><small class="text-info"><i class="fas fa-video me-1"></i>Virtual</small>
{% endif %}
</td>
<td>
<span class="badge bg-{% if appointment.status == 'scheduled' %}primary{% elif appointment.status == 'completed' %}success{% elif appointment.status == 'cancelled' %}danger{% else %}warning{% endif %}">
{{ appointment.get_status_display }}
</span>
</td>
<td>
<span class="badge bg-{% if appointment.priority == 'high' %}danger{% elif appointment.priority == 'medium' %}warning{% else %}success{% endif %}">
{{ appointment.get_priority_display }}
</span>
</td>
<td>
<div class="dropdown">
<button class="btn btn-sm btn-outline-secondary dropdown-toggle" type="button" data-bs-toggle="dropdown">
<i class="fas fa-ellipsis-v"></i>
</button>
<ul class="dropdown-menu">
<li><a class="dropdown-item" href="{% url 'appointments:appointment_request_detail' appointment.pk %}">
<i class="fas fa-eye me-2"></i>View Details
</a></li>
<li><a class="dropdown-item" href="{% url 'appointments:appointment_request_update' appointment.pk %}">
<i class="fas fa-edit me-2"></i>Edit
</a></li>
{% if appointment.status == 'scheduled' %}
<li><hr class="dropdown-divider"></li>
<li><a class="dropdown-item text-success" href="#">
<i class="fas fa-check me-2"></i>Check In
</a></li>
<li><a class="dropdown-item text-warning" href="#">
<i class="fas fa-clock me-2"></i>Reschedule
</a></li>
{% endif %}
<li><hr class="dropdown-divider"></li>
<li><a class="dropdown-item text-danger" href="{% url 'appointments:appointment_request_delete' appointment.pk %}">
<i class="fas fa-trash me-2"></i>Delete
</a></li>
</ul>
</div>
</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
<!-- Card View (Hidden by default) -->
<div id="cardView" class="row g-3 p-3" style="display: none;">
{% for appointment in object_list %}
<div class="col-md-6 col-lg-4">
<div class="card h-100">
<div class="card-body">
<div class="d-flex justify-content-between align-items-start mb-2">
<div class="form-check">
<input class="form-check-input row-select" type="checkbox" value="{{ appointment.pk }}">
</div>
<span class="badge bg-{% if appointment.status == 'scheduled' %}primary{% elif appointment.status == 'completed' %}success{% elif appointment.status == 'cancelled' %}danger{% else %}warning{% endif %}">
{{ appointment.get_status_display }}
</span>
</div>
<h6 class="card-title">{{ appointment.patient.get_full_name }}</h6>
<p class="card-text">
<small class="text-muted">{{ appointment.patient.patient_id }}</small><br>
<strong>Provider:</strong> {{ appointment.provider.get_full_name }}<br>
<strong>Date:</strong> {{ appointment.scheduled_datetime|date:"M d, Y" }}<br>
<strong>Time:</strong> {{ appointment.scheduled_datetime|time:"g:i A" }}<br>
<strong>Type:</strong> {{ appointment.get_appointment_type_display }}
{% if appointment.is_telemedicine %}
<i class="fas fa-video text-info ms-1"></i>
{% endif %}
</p>
<div class="d-flex justify-content-between align-items-center">
<span class="badge bg-{% if appointment.priority == 'high' %}danger{% elif appointment.priority == 'medium' %}warning{% else %}success{% endif %}">
{{ appointment.get_priority_display }}
</span>
<div class="btn-group btn-group-sm">
<a href="{% url 'appointments:appointment_request_detail' appointment.pk %}" class="btn btn-outline-primary">
<i class="fas fa-eye"></i>
</a>
<a href="{% url 'appointments:appointment_request_update' appointment.pk %}" class="btn btn-outline-secondary">
<i class="fas fa-edit"></i>
</a>
</div>
</div>
</div>
</div>
</div>
{% endfor %}
</div>
{% else %}
<div class="text-center py-5">
<i class="fas fa-calendar-times fa-3x text-muted mb-3"></i>
<h5 class="text-muted">No Appointment Requests Found</h5>
<p class="text-muted">No appointment requests match your current filters.</p>
<a href="{% url 'appointments:appointment_request_create' %}" class="btn btn-primary">
<i class="fas fa-plus me-1"></i>
Create First Request
</a>
</div>
{% endif %}
</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 {{ page_obj.paginator.count }} entries
</div>
<nav>
<ul class="pagination mb-0">
{% if page_obj.has_previous %}
<li class="page-item">
<a class="page-link" href="?page=1{% if request.GET.urlencode %}&{{ request.GET.urlencode }}{% endif %}">First</a>
</li>
<li class="page-item">
<a class="page-link" href="?page={{ page_obj.previous_page_number }}{% if request.GET.urlencode %}&{{ request.GET.urlencode }}{% 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.urlencode %}&{{ request.GET.urlencode }}{% endif %}">Next</a>
</li>
<li class="page-item">
<a class="page-link" href="?page={{ page_obj.paginator.num_pages }}{% if request.GET.urlencode %}&{{ request.GET.urlencode }}{% endif %}">Last</a>
</li>
{% endif %}
</ul>
</nav>
</div>
</div>
{% endif %}
</div>
</div>
</div>
</div>
{% endblock %}
{% block js %}
<script>
document.addEventListener('DOMContentLoaded', function() {
// View mode toggle
const listViewBtn = document.getElementById('listView');
const cardViewBtn = document.getElementById('cardView');
const tableView = document.getElementById('tableView');
const cardView = document.getElementById('cardView');
listViewBtn.addEventListener('change', function() {
if (this.checked) {
tableView.style.display = 'block';
cardView.style.display = 'none';
}
});
cardViewBtn.addEventListener('change', function() {
if (this.checked) {
tableView.style.display = 'none';
cardView.style.display = 'block';
}
});
// Select all functionality
const selectAllCheckbox = document.getElementById('selectAll');
const rowCheckboxes = document.querySelectorAll('.row-select');
selectAllCheckbox.addEventListener('change', function() {
rowCheckboxes.forEach(checkbox => {
checkbox.checked = this.checked;
});
});
// Search functionality
const searchInput = document.getElementById('searchInput');
searchInput.addEventListener('keypress', function(e) {
if (e.key === 'Enter') {
performSearch();
}
});
});
function performSearch() {
const searchTerm = document.getElementById('searchInput').value;
const url = new URL(window.location);
if (searchTerm) {
url.searchParams.set('search', searchTerm);
} else {
url.searchParams.delete('search');
}
url.searchParams.delete('page'); // Reset to first page
window.location.href = url.toString();
}
function exportData() {
const selectedIds = Array.from(document.querySelectorAll('.row-select:checked')).map(cb => cb.value);
const params = new URLSearchParams(window.location.search);
if (selectedIds.length > 0) {
params.set('selected_ids', selectedIds.join(','));
}
params.set('export', 'csv');
window.location.href = '?' + params.toString();
}
</script>
{% endblock %}