552 lines
29 KiB
HTML
552 lines
29 KiB
HTML
{% extends "base.html" %}
|
|
{% load static %}
|
|
|
|
{% block title %}Telemedicine Session Details - {{ block.super }}{% endblock %}
|
|
|
|
{% block content %}
|
|
<div class="container-fluid">
|
|
<div class="row">
|
|
<div class="col-12">
|
|
<!-- Session Header -->
|
|
<div class="card mb-4">
|
|
<div class="card-header d-flex justify-content-between align-items-center">
|
|
<h4 class="card-title mb-0">
|
|
<i class="fas fa-video me-2"></i>Telemedicine Session Details
|
|
</h4>
|
|
<div class="btn-group">
|
|
<a href="{% url 'appointments:telemedicine' %}" class="btn btn-outline-secondary">
|
|
<i class="fas fa-arrow-left me-1"></i>Back to Sessions
|
|
</a>
|
|
{% if session.status == 'SCHEDULED' or session.status == 'WAITING' %}
|
|
<button class="btn btn-success"
|
|
hx-post="{% url 'appointments:start_telemedicine_session' session.id %}"
|
|
hx-confirm="Start this telemedicine session?"
|
|
hx-swap="none">
|
|
<i class="fas fa-play me-1"></i>Start Session
|
|
</button>
|
|
{% endif %}
|
|
{% if session.meeting_url %}
|
|
<a href="{{ session.meeting_url }}"
|
|
target="_blank"
|
|
class="btn btn-primary">
|
|
<i class="fas fa-video me-1"></i>Join Meeting
|
|
</a>
|
|
{% endif %}
|
|
</div>
|
|
</div>
|
|
|
|
<div class="card-body">
|
|
<div class="row">
|
|
<div class="col-md-6">
|
|
<h5 class="text-primary mb-3">
|
|
<i class="fas fa-info-circle me-2"></i>Session Information
|
|
</h5>
|
|
<table class="table table-borderless">
|
|
<tr>
|
|
<td class="fw-bold">Session ID:</td>
|
|
<td>{{ session.id }}</td>
|
|
</tr>
|
|
<tr>
|
|
<td class="fw-bold">Status:</td>
|
|
<td>
|
|
{% if session.status == 'SCHEDULED' %}
|
|
<span class="badge bg-warning">Scheduled</span>
|
|
{% elif session.status == 'WAITING' %}
|
|
<span class="badge bg-info">Waiting</span>
|
|
{% elif session.status == 'IN_PROGRESS' %}
|
|
<span class="badge bg-success">In Progress</span>
|
|
{% elif session.status == 'COMPLETED' %}
|
|
<span class="badge bg-success">Completed</span>
|
|
{% elif session.status == 'CANCELLED' %}
|
|
<span class="badge bg-danger">Cancelled</span>
|
|
{% endif %}
|
|
</td>
|
|
</tr>
|
|
<tr>
|
|
<td class="fw-bold">Platform:</td>
|
|
<td>
|
|
<span class="badge bg-info">{{ session.get_platform_display }}</span>
|
|
</td>
|
|
</tr>
|
|
<tr>
|
|
<td class="fw-bold">Scheduled Start:</td>
|
|
<td>{{ session.scheduled_start|date:"M d, Y H:i" }}</td>
|
|
</tr>
|
|
<tr>
|
|
<td class="fw-bold">Scheduled End:</td>
|
|
<td>{{ session.scheduled_end|date:"M d, Y H:i" }}</td>
|
|
</tr>
|
|
{% if session.actual_start %}
|
|
<tr>
|
|
<td class="fw-bold">Actual Start:</td>
|
|
<td>{{ session.actual_start|date:"M d, Y H:i" }}</td>
|
|
</tr>
|
|
{% endif %}
|
|
{% if session.actual_end %}
|
|
<tr>
|
|
<td class="fw-bold">Actual End:</td>
|
|
<td>{{ session.actual_end|date:"M d, Y H:i" }}</td>
|
|
</tr>
|
|
{% endif %}
|
|
<tr>
|
|
<td class="fw-bold">Duration:</td>
|
|
<td>{{ session.duration_minutes }} minutes</td>
|
|
</tr>
|
|
</table>
|
|
</div>
|
|
|
|
<div class="col-md-6">
|
|
<h5 class="text-primary mb-3">
|
|
<i class="fas fa-cog me-2"></i>Technical Details
|
|
</h5>
|
|
<table class="table table-borderless">
|
|
{% if session.meeting_id %}
|
|
<tr>
|
|
<td class="fw-bold">Meeting ID:</td>
|
|
<td>{{ session.meeting_id }}</td>
|
|
</tr>
|
|
{% endif %}
|
|
{% if session.meeting_password %}
|
|
<tr>
|
|
<td class="fw-bold">Meeting Password:</td>
|
|
<td>
|
|
<span class="text-muted">••••••••</span>
|
|
<button class="btn btn-sm btn-outline-secondary ms-2"
|
|
onclick="togglePassword(this)">
|
|
<i class="fas fa-eye"></i>
|
|
</button>
|
|
<span class="d-none">{{ session.meeting_password }}</span>
|
|
</td>
|
|
</tr>
|
|
{% endif %}
|
|
{% if session.recording_enabled %}
|
|
<tr>
|
|
<td class="fw-bold">Recording:</td>
|
|
<td>
|
|
<span class="badge bg-success">
|
|
<i class="fas fa-record-vinyl me-1"></i>Enabled
|
|
</span>
|
|
</td>
|
|
</tr>
|
|
{% endif %}
|
|
{% if session.waiting_room_enabled %}
|
|
<tr>
|
|
<td class="fw-bold">Waiting Room:</td>
|
|
<td>
|
|
<span class="badge bg-info">
|
|
<i class="fas fa-clock me-1"></i>Enabled
|
|
</span>
|
|
</td>
|
|
</tr>
|
|
{% endif %}
|
|
<tr>
|
|
<td class="fw-bold">Created:</td>
|
|
<td>{{ session.created_at|date:"M d, Y H:i" }}</td>
|
|
</tr>
|
|
<tr>
|
|
<td class="fw-bold">Last Updated:</td>
|
|
<td>{{ session.updated_at|date:"M d, Y H:i" }}</td>
|
|
</tr>
|
|
</table>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Patient and Provider Information -->
|
|
<div class="row mb-4">
|
|
<div class="col-md-6">
|
|
<div class="card h-100">
|
|
<div class="card-header">
|
|
<h5 class="card-title mb-0">
|
|
<i class="fas fa-user-injured me-2"></i>Patient Information
|
|
</h5>
|
|
</div>
|
|
<div class="card-body">
|
|
{% if session.appointment.patient %}
|
|
<div class="d-flex align-items-center mb-3">
|
|
<div class="avatar-circle bg-primary text-white me-3">
|
|
{{ session.appointment.patient.first_name.0 }}{{ session.appointment.patient.last_name.0 }}
|
|
</div>
|
|
<div>
|
|
<h6 class="mb-0">{{ session.appointment.patient.get_full_name }}</h6>
|
|
<small class="text-muted">MRN: {{ session.appointment.patient.mrn }}</small>
|
|
</div>
|
|
</div>
|
|
<table class="table table-borderless table-sm">
|
|
<tr>
|
|
<td class="fw-bold">Date of Birth:</td>
|
|
<td>{{ session.appointment.patient.date_of_birth|date:"M d, Y" }}</td>
|
|
</tr>
|
|
<tr>
|
|
<td class="fw-bold">Gender:</td>
|
|
<td>{{ session.appointment.patient.get_gender_display }}</td>
|
|
</tr>
|
|
<tr>
|
|
<td class="fw-bold">Phone:</td>
|
|
<td>{{ session.appointment.patient.phone_number|default:"Not provided" }}</td>
|
|
</tr>
|
|
<tr>
|
|
<td class="fw-bold">Email:</td>
|
|
<td>{{ session.appointment.patient.email|default:"Not provided" }}</td>
|
|
</tr>
|
|
</table>
|
|
<div class="mt-3">
|
|
<a href="{% url 'patients:patient_detail' session.appointment.patient.id %}"
|
|
class="btn btn-outline-primary btn-sm">
|
|
<i class="fas fa-eye me-1"></i>View Patient Profile
|
|
</a>
|
|
</div>
|
|
{% else %}
|
|
<p class="text-muted">No patient information available</p>
|
|
{% endif %}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="col-md-6">
|
|
<div class="card h-100">
|
|
<div class="card-header">
|
|
<h5 class="card-title mb-0">
|
|
<i class="fas fa-user-md me-2"></i>Healthcare Provider
|
|
</h5>
|
|
</div>
|
|
<div class="card-body">
|
|
{% if session.appointment.provider %}
|
|
<div class="d-flex align-items-center mb-3">
|
|
<div class="avatar-circle bg-success text-white me-3">
|
|
{{ session.appointment.provider.first_name.0 }}{{ session.appointment.provider.last_name.0 }}
|
|
</div>
|
|
<div>
|
|
<h6 class="mb-0">{{ session.appointment.provider.get_full_name }}</h6>
|
|
<small class="text-muted">{{ session.appointment.provider.get_role_display }}</small>
|
|
</div>
|
|
</div>
|
|
<table class="table table-borderless table-sm">
|
|
<tr>
|
|
<td class="fw-bold">Department:</td>
|
|
<td>{{ session.appointment.provider.department|default:"Not assigned" }}</td>
|
|
</tr>
|
|
<tr>
|
|
<td class="fw-bold">Specialization:</td>
|
|
<td>{{ session.appointment.provider.specialization|default:"General" }}</td>
|
|
</tr>
|
|
<tr>
|
|
<td class="fw-bold">License Number:</td>
|
|
<td>{{ session.appointment.provider.license_number|default:"Not provided" }}</td>
|
|
</tr>
|
|
<tr>
|
|
<td class="fw-bold">Phone:</td>
|
|
<td>{{ session.appointment.provider.phone_number|default:"Not provided" }}</td>
|
|
</tr>
|
|
</table>
|
|
<div class="mt-3">
|
|
<a href="{% url 'hr:employee_detail' session.appointment.provider.id %}"
|
|
class="btn btn-outline-success btn-sm">
|
|
<i class="fas fa-eye me-1"></i>View Provider Profile
|
|
</a>
|
|
</div>
|
|
{% else %}
|
|
<p class="text-muted">No provider information available</p>
|
|
{% endif %}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Appointment Details -->
|
|
<div class="card mb-4">
|
|
<div class="card-header">
|
|
<h5 class="card-title mb-0">
|
|
<i class="fas fa-calendar-check me-2"></i>Related Appointment
|
|
</h5>
|
|
</div>
|
|
<div class="card-body">
|
|
{% if session.appointment %}
|
|
<div class="row">
|
|
<div class="col-md-6">
|
|
<table class="table table-borderless">
|
|
<tr>
|
|
<td class="fw-bold">Appointment ID:</td>
|
|
<td>{{ session.appointment.id }}</td>
|
|
</tr>
|
|
<tr>
|
|
<td class="fw-bold">Type:</td>
|
|
<td>{{ session.appointment.get_appointment_type_display }}</td>
|
|
</tr>
|
|
<tr>
|
|
<td class="fw-bold">Status:</td>
|
|
<td>
|
|
<span class="badge bg-info">{{ session.appointment.get_status_display }}</span>
|
|
</td>
|
|
</tr>
|
|
<tr>
|
|
<td class="fw-bold">Reason:</td>
|
|
<td>{{ session.appointment.reason|default:"Not specified" }}</td>
|
|
</tr>
|
|
</table>
|
|
</div>
|
|
<div class="col-md-6">
|
|
<table class="table table-borderless">
|
|
<tr>
|
|
<td class="fw-bold">Scheduled Date:</td>
|
|
<td>{{ session.appointment.appointment_date|date:"M d, Y" }}</td>
|
|
</tr>
|
|
<tr>
|
|
<td class="fw-bold">Scheduled Time:</td>
|
|
<td>{{ session.appointment.appointment_time|time:"H:i" }}</td>
|
|
</tr>
|
|
<tr>
|
|
<td class="fw-bold">Duration:</td>
|
|
<td>{{ session.appointment.duration_minutes }} minutes</td>
|
|
</tr>
|
|
<tr>
|
|
<td class="fw-bold">Priority:</td>
|
|
<td>
|
|
{% if session.appointment.priority == 'HIGH' %}
|
|
<span class="badge bg-danger">High</span>
|
|
{% elif session.appointment.priority == 'MEDIUM' %}
|
|
<span class="badge bg-warning">Medium</span>
|
|
{% else %}
|
|
<span class="badge bg-success">Normal</span>
|
|
{% endif %}
|
|
</td>
|
|
</tr>
|
|
</table>
|
|
</div>
|
|
</div>
|
|
<div class="mt-3">
|
|
<a href="{% url 'appointments:appointment_detail' session.appointment.id %}"
|
|
class="btn btn-outline-primary">
|
|
<i class="fas fa-eye me-1"></i>View Full Appointment Details
|
|
</a>
|
|
</div>
|
|
{% else %}
|
|
<p class="text-muted">No appointment information available</p>
|
|
{% endif %}
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Session Notes and Documentation -->
|
|
{% if session.notes or session.status == 'COMPLETED' %}
|
|
<div class="card mb-4">
|
|
<div class="card-header">
|
|
<h5 class="card-title mb-0">
|
|
<i class="fas fa-sticky-note me-2"></i>Session Notes & Documentation
|
|
</h5>
|
|
</div>
|
|
<div class="card-body">
|
|
{% if session.notes %}
|
|
<div class="mb-3">
|
|
<h6>Session Notes:</h6>
|
|
<div class="bg-light p-3 rounded">
|
|
{{ session.notes|linebreaks }}
|
|
</div>
|
|
</div>
|
|
{% endif %}
|
|
|
|
{% if session.status == 'COMPLETED' %}
|
|
<div class="row">
|
|
<div class="col-md-6">
|
|
<h6>Session Summary:</h6>
|
|
<ul class="list-unstyled">
|
|
<li><i class="fas fa-clock text-primary me-2"></i>Duration: {{ session.actual_duration_minutes }} minutes</li>
|
|
<li><i class="fas fa-users text-success me-2"></i>Participants: Patient and Provider</li>
|
|
{% if session.recording_enabled %}
|
|
<li><i class="fas fa-record-vinyl text-danger me-2"></i>Session was recorded</li>
|
|
{% endif %}
|
|
</ul>
|
|
</div>
|
|
<div class="col-md-6">
|
|
<h6>Follow-up Actions:</h6>
|
|
<div class="d-grid gap-2">
|
|
<button class="btn btn-outline-primary btn-sm">
|
|
<i class="fas fa-file-medical me-1"></i>Generate Session Report
|
|
</button>
|
|
<button class="btn btn-outline-success btn-sm">
|
|
<i class="fas fa-calendar-plus me-1"></i>Schedule Follow-up
|
|
</button>
|
|
<button class="btn btn-outline-info btn-sm">
|
|
<i class="fas fa-prescription me-1"></i>Create Prescription
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
{% endif %}
|
|
</div>
|
|
</div>
|
|
{% endif %}
|
|
|
|
<!-- Action Buttons -->
|
|
<div class="card">
|
|
<div class="card-body">
|
|
<div class="d-flex justify-content-between">
|
|
<div>
|
|
<a href="{% url 'appointments:telemedicine' %}" class="btn btn-secondary">
|
|
<i class="fas fa-arrow-left me-1"></i>Back to Sessions
|
|
</a>
|
|
</div>
|
|
<div class="btn-group">
|
|
{% if session.status not in 'COMPLETED,CANCELLED' %}
|
|
<button class="btn btn-outline-warning"
|
|
data-bs-toggle="modal"
|
|
data-bs-target="#editSessionModal">
|
|
<i class="fas fa-edit me-1"></i>Edit Session
|
|
</button>
|
|
<button class="btn btn-outline-danger"
|
|
hx-post="{% url 'appointments:cancel_telemedicine_session' session.id %}"
|
|
hx-confirm="Are you sure you want to cancel this telemedicine session?"
|
|
hx-swap="none">
|
|
<i class="fas fa-times me-1"></i>Cancel Session
|
|
</button>
|
|
{% endif %}
|
|
<button class="btn btn-outline-info" onclick="window.print()">
|
|
<i class="fas fa-print me-1"></i>Print Details
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Edit Session Modal -->
|
|
<div class="modal fade" id="editSessionModal" tabindex="-1">
|
|
<div class="modal-dialog modal-lg">
|
|
<div class="modal-content">
|
|
<div class="modal-header">
|
|
<h5 class="modal-title">
|
|
<i class="fas fa-edit me-2"></i>Edit Telemedicine Session
|
|
</h5>
|
|
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
|
|
</div>
|
|
<div class="modal-body">
|
|
<form method="post" action="{% url 'appointments:telemedicine_session_update' session.id %}">
|
|
{% csrf_token %}
|
|
<div class="row">
|
|
<div class="col-md-6">
|
|
<div class="mb-3">
|
|
<label class="form-label">Scheduled Start Time</label>
|
|
<input type="datetime-local"
|
|
name="scheduled_start"
|
|
class="form-control"
|
|
value="{{ session.scheduled_start|date:'Y-m-d\TH:i' }}">
|
|
</div>
|
|
</div>
|
|
<div class="col-md-6">
|
|
<div class="mb-3">
|
|
<label class="form-label">Duration (minutes)</label>
|
|
<input type="number"
|
|
name="duration_minutes"
|
|
class="form-control"
|
|
value="{{ session.duration_minutes }}"
|
|
min="15" max="120" step="15">
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="row">
|
|
<div class="col-md-6">
|
|
<div class="mb-3">
|
|
<label class="form-label">Platform</label>
|
|
<select name="platform" class="form-select">
|
|
<option value="ZOOM" {% if session.platform == 'ZOOM' %}selected{% endif %}>Zoom</option>
|
|
<option value="TEAMS" {% if session.platform == 'TEAMS' %}selected{% endif %}>Microsoft Teams</option>
|
|
<option value="WEBEX" {% if session.platform == 'WEBEX' %}selected{% endif %}>WebEx</option>
|
|
<option value="CUSTOM" {% if session.platform == 'CUSTOM' %}selected{% endif %}>Custom Platform</option>
|
|
</select>
|
|
</div>
|
|
</div>
|
|
<div class="col-md-6">
|
|
<div class="mb-3">
|
|
<label class="form-label">Status</label>
|
|
<select name="status" class="form-select">
|
|
<option value="SCHEDULED" {% if session.status == 'SCHEDULED' %}selected{% endif %}>Scheduled</option>
|
|
<option value="WAITING" {% if session.status == 'WAITING' %}selected{% endif %}>Waiting</option>
|
|
<option value="IN_PROGRESS" {% if session.status == 'IN_PROGRESS' %}selected{% endif %}>In Progress</option>
|
|
<option value="COMPLETED" {% if session.status == 'COMPLETED' %}selected{% endif %}>Completed</option>
|
|
<option value="CANCELLED" {% if session.status == 'CANCELLED' %}selected{% endif %}>Cancelled</option>
|
|
</select>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="mb-3">
|
|
<label class="form-label">Session Notes</label>
|
|
<textarea name="notes" class="form-control" rows="4">{{ session.notes }}</textarea>
|
|
</div>
|
|
<div class="row">
|
|
<div class="col-md-6">
|
|
<div class="form-check">
|
|
<input type="checkbox"
|
|
name="recording_enabled"
|
|
class="form-check-input"
|
|
{% if session.recording_enabled %}checked{% endif %}>
|
|
<label class="form-check-label">Enable Recording</label>
|
|
</div>
|
|
</div>
|
|
<div class="col-md-6">
|
|
<div class="form-check">
|
|
<input type="checkbox"
|
|
name="waiting_room_enabled"
|
|
class="form-check-input"
|
|
{% if session.waiting_room_enabled %}checked{% endif %}>
|
|
<label class="form-check-label">Enable Waiting Room</label>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</form>
|
|
</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">
|
|
<i class="fas fa-save me-1"></i>Save Changes
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<style>
|
|
.avatar-circle {
|
|
width: 50px;
|
|
height: 50px;
|
|
border-radius: 50%;
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
font-weight: bold;
|
|
font-size: 1.2rem;
|
|
}
|
|
|
|
@media print {
|
|
.btn, .btn-group, .modal {
|
|
display: none !important;
|
|
}
|
|
.card {
|
|
border: 1px solid #dee2e6 !important;
|
|
box-shadow: none !important;
|
|
}
|
|
}
|
|
</style>
|
|
|
|
<script>
|
|
function togglePassword(button) {
|
|
const passwordSpan = button.nextElementSibling;
|
|
const icon = button.querySelector('i');
|
|
|
|
if (passwordSpan.classList.contains('d-none')) {
|
|
passwordSpan.classList.remove('d-none');
|
|
button.previousElementSibling.classList.add('d-none');
|
|
icon.classList.remove('fa-eye');
|
|
icon.classList.add('fa-eye-slash');
|
|
} else {
|
|
passwordSpan.classList.add('d-none');
|
|
button.previousElementSibling.classList.remove('d-none');
|
|
icon.classList.remove('fa-eye-slash');
|
|
icon.classList.add('fa-eye');
|
|
}
|
|
}
|
|
</script>
|
|
{% endblock %}
|
|
|