716 lines
32 KiB
HTML
716 lines
32 KiB
HTML
{% extends "base.html" %}
|
|
{% load static %}
|
|
|
|
{% block title %}{% if object %}Edit Admission{% else %}New Admission{% endif %} - {{ 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">
|
|
{% if object %}
|
|
<i class="fas fa-edit me-2"></i>Edit Admission
|
|
{% else %}
|
|
<i class="fas fa-user-plus me-2"></i>New Patient Admission
|
|
{% endif %}
|
|
</h1>
|
|
<nav aria-label="breadcrumb">
|
|
<ol class="breadcrumb mb-0">
|
|
<li class="breadcrumb-item"><a href="{% url 'inpatients:dashboard' %}">Inpatients</a></li>
|
|
<li class="breadcrumb-item"><a href="{% url 'inpatients:admission_list' %}">Admissions</a></li>
|
|
{% if object %}
|
|
<li class="breadcrumb-item"><a href="{% url 'inpatients:admission_detail' object.pk %}">{{ object.patient.get_full_name }}</a></li>
|
|
<li class="breadcrumb-item active">Edit</li>
|
|
{% else %}
|
|
<li class="breadcrumb-item active">New</li>
|
|
{% endif %}
|
|
</ol>
|
|
</nav>
|
|
</div>
|
|
<div class="btn-group">
|
|
<a href="{% if object %}{% url 'inpatients:admission_detail' object.pk %}{% else %}{% url 'inpatients:admission_list' %}{% endif %}" class="btn btn-outline-secondary">
|
|
<i class="fas fa-arrow-left me-2"></i>Back
|
|
</a>
|
|
</div>
|
|
</div>
|
|
|
|
<form method="post" novalidate>
|
|
{% csrf_token %}
|
|
|
|
<div class="row">
|
|
<!-- Main Form -->
|
|
<div class="col-lg-8">
|
|
<!-- Patient Information -->
|
|
<div class="card mb-4">
|
|
<div class="card-header">
|
|
<h5 class="mb-0">
|
|
<i class="fas fa-user me-2"></i>Patient Information
|
|
</h5>
|
|
</div>
|
|
<div class="card-body">
|
|
<div class="row">
|
|
<div class="col-md-6">
|
|
<div class="mb-3">
|
|
<label for="{{ form.patient.id_for_label }}" class="form-label">
|
|
Patient <span class="text-danger">*</span>
|
|
</label>
|
|
{{ form.patient }}
|
|
{% if form.patient.errors %}
|
|
<div class="invalid-feedback d-block">
|
|
{{ form.patient.errors.0 }}
|
|
</div>
|
|
{% endif %}
|
|
<div class="form-text">Search and select patient for admission</div>
|
|
</div>
|
|
</div>
|
|
<div class="col-md-6">
|
|
<div class="mb-3">
|
|
<label for="{{ form.admission_type.id_for_label }}" class="form-label">
|
|
Admission Type <span class="text-danger">*</span>
|
|
</label>
|
|
{{ form.admission_type }}
|
|
{% if form.admission_type.errors %}
|
|
<div class="invalid-feedback d-block">
|
|
{{ form.admission_type.errors.0 }}
|
|
</div>
|
|
{% endif %}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="row">
|
|
<div class="col-md-6">
|
|
<div class="mb-3">
|
|
<label for="{{ form.admission_date.id_for_label }}" class="form-label">
|
|
Admission Date <span class="text-danger">*</span>
|
|
</label>
|
|
{{ form.admission_date }}
|
|
{% if form.admission_date.errors %}
|
|
<div class="invalid-feedback d-block">
|
|
{{ form.admission_date.errors.0 }}
|
|
</div>
|
|
{% endif %}
|
|
</div>
|
|
</div>
|
|
<div class="col-md-6">
|
|
<div class="mb-3">
|
|
<label for="{{ form.admission_time.id_for_label }}" class="form-label">
|
|
Admission Time <span class="text-danger">*</span>
|
|
</label>
|
|
{{ form.admission_time }}
|
|
{% if form.admission_time.errors %}
|
|
<div class="invalid-feedback d-block">
|
|
{{ form.admission_time.errors.0 }}
|
|
</div>
|
|
{% endif %}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Medical Information -->
|
|
<div class="card mb-4">
|
|
<div class="card-header">
|
|
<h5 class="mb-0">
|
|
<i class="fas fa-stethoscope me-2"></i>Medical Information
|
|
</h5>
|
|
</div>
|
|
<div class="card-body">
|
|
<div class="row">
|
|
<div class="col-md-6">
|
|
<div class="mb-3">
|
|
<label for="{{ form.attending_physician.id_for_label }}" class="form-label">
|
|
Attending Physician <span class="text-danger">*</span>
|
|
</label>
|
|
{{ form.attending_physician }}
|
|
{% if form.attending_physician.errors %}
|
|
<div class="invalid-feedback d-block">
|
|
{{ form.attending_physician.errors.0 }}
|
|
</div>
|
|
{% endif %}
|
|
</div>
|
|
</div>
|
|
<div class="col-md-6">
|
|
<div class="mb-3">
|
|
<label for="{{ form.referring_physician.id_for_label }}" class="form-label">
|
|
Referring Physician
|
|
</label>
|
|
{{ form.referring_physician }}
|
|
{% if form.referring_physician.errors %}
|
|
<div class="invalid-feedback d-block">
|
|
{{ form.referring_physician.errors.0 }}
|
|
</div>
|
|
{% endif %}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="mb-3">
|
|
<label for="{{ form.primary_diagnosis.id_for_label }}" class="form-label">
|
|
Primary Diagnosis <span class="text-danger">*</span>
|
|
</label>
|
|
{{ form.primary_diagnosis }}
|
|
{% if form.primary_diagnosis.errors %}
|
|
<div class="invalid-feedback d-block">
|
|
{{ form.primary_diagnosis.errors.0 }}
|
|
</div>
|
|
{% endif %}
|
|
<div class="form-text">Primary reason for admission</div>
|
|
</div>
|
|
|
|
<div class="mb-3">
|
|
<label for="{{ form.secondary_diagnoses.id_for_label }}" class="form-label">
|
|
Secondary Diagnoses
|
|
</label>
|
|
{{ form.secondary_diagnoses }}
|
|
{% if form.secondary_diagnoses.errors %}
|
|
<div class="invalid-feedback d-block">
|
|
{{ form.secondary_diagnoses.errors.0 }}
|
|
</div>
|
|
{% endif %}
|
|
<div class="form-text">Additional diagnoses or comorbidities</div>
|
|
</div>
|
|
|
|
<div class="row">
|
|
<div class="col-md-6">
|
|
<div class="mb-3">
|
|
<label for="{{ form.chief_complaint.id_for_label }}" class="form-label">
|
|
Chief Complaint
|
|
</label>
|
|
{{ form.chief_complaint }}
|
|
{% if form.chief_complaint.errors %}
|
|
<div class="invalid-feedback d-block">
|
|
{{ form.chief_complaint.errors.0 }}
|
|
</div>
|
|
{% endif %}
|
|
</div>
|
|
</div>
|
|
<div class="col-md-6">
|
|
<div class="mb-3">
|
|
<label for="{{ form.severity.id_for_label }}" class="form-label">
|
|
Severity Level
|
|
</label>
|
|
{{ form.severity }}
|
|
{% if form.severity.errors %}
|
|
<div class="invalid-feedback d-block">
|
|
{{ form.severity.errors.0 }}
|
|
</div>
|
|
{% endif %}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Bed Assignment -->
|
|
<div class="card mb-4">
|
|
<div class="card-header">
|
|
<h5 class="mb-0">
|
|
<i class="fas fa-bed me-2"></i>Bed Assignment
|
|
</h5>
|
|
</div>
|
|
<div class="card-body">
|
|
<div class="row">
|
|
<div class="col-md-6">
|
|
<div class="mb-3">
|
|
<label for="{{ form.ward.id_for_label }}" class="form-label">
|
|
Ward <span class="text-danger">*</span>
|
|
</label>
|
|
{{ form.ward }}
|
|
{% if form.ward.errors %}
|
|
<div class="invalid-feedback d-block">
|
|
{{ form.ward.errors.0 }}
|
|
</div>
|
|
{% endif %}
|
|
</div>
|
|
</div>
|
|
<div class="col-md-6">
|
|
<div class="mb-3">
|
|
<label for="{{ form.bed.id_for_label }}" class="form-label">
|
|
Bed <span class="text-danger">*</span>
|
|
</label>
|
|
{{ form.bed }}
|
|
{% if form.bed.errors %}
|
|
<div class="invalid-feedback d-block">
|
|
{{ form.bed.errors.0 }}
|
|
</div>
|
|
{% endif %}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="row">
|
|
<div class="col-md-6">
|
|
<div class="mb-3">
|
|
<label for="{{ form.room_type.id_for_label }}" class="form-label">
|
|
Room Type
|
|
</label>
|
|
{{ form.room_type }}
|
|
{% if form.room_type.errors %}
|
|
<div class="invalid-feedback d-block">
|
|
{{ form.room_type.errors.0 }}
|
|
</div>
|
|
{% endif %}
|
|
</div>
|
|
</div>
|
|
<div class="col-md-6">
|
|
<div class="mb-3">
|
|
<label for="{{ form.isolation_required.id_for_label }}" class="form-label">
|
|
Special Requirements
|
|
</label>
|
|
<div class="form-check">
|
|
<input class="form-check-input" type="checkbox" id="isolation_required" name="isolation_required"
|
|
{% if form.isolation_required.value %}checked{% endif %}>
|
|
<label class="form-check-label" for="isolation_required">
|
|
Isolation Required
|
|
</label>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div id="bed-availability" class="mt-3">
|
|
<!-- Bed availability will be loaded here -->
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Additional Information -->
|
|
<div class="card mb-4">
|
|
<div class="card-header">
|
|
<h5 class="mb-0">
|
|
<i class="fas fa-info-circle me-2"></i>Additional Information
|
|
</h5>
|
|
</div>
|
|
<div class="card-body">
|
|
<div class="row">
|
|
<div class="col-md-6">
|
|
<div class="mb-3">
|
|
<label for="{{ form.anticipated_discharge_date.id_for_label }}" class="form-label">
|
|
Anticipated Discharge Date
|
|
</label>
|
|
{{ form.anticipated_discharge_date }}
|
|
{% if form.anticipated_discharge_date.errors %}
|
|
<div class="invalid-feedback d-block">
|
|
{{ form.anticipated_discharge_date.errors.0 }}
|
|
</div>
|
|
{% endif %}
|
|
</div>
|
|
</div>
|
|
<div class="col-md-6">
|
|
<div class="mb-3">
|
|
<label for="{{ form.insurance_authorization.id_for_label }}" class="form-label">
|
|
Insurance Authorization
|
|
</label>
|
|
{{ form.insurance_authorization }}
|
|
{% if form.insurance_authorization.errors %}
|
|
<div class="invalid-feedback d-block">
|
|
{{ form.insurance_authorization.errors.0 }}
|
|
</div>
|
|
{% endif %}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="mb-3">
|
|
<label for="{{ form.admission_notes.id_for_label }}" class="form-label">
|
|
Admission Notes
|
|
</label>
|
|
{{ form.admission_notes }}
|
|
{% if form.admission_notes.errors %}
|
|
<div class="invalid-feedback d-block">
|
|
{{ form.admission_notes.errors.0 }}
|
|
</div>
|
|
{% endif %}
|
|
<div class="form-text">Additional notes about the admission</div>
|
|
</div>
|
|
|
|
<div class="mb-3">
|
|
<label for="{{ form.special_instructions.id_for_label }}" class="form-label">
|
|
Special Instructions
|
|
</label>
|
|
{{ form.special_instructions }}
|
|
{% if form.special_instructions.errors %}
|
|
<div class="invalid-feedback d-block">
|
|
{{ form.special_instructions.errors.0 }}
|
|
</div>
|
|
{% endif %}
|
|
<div class="form-text">Special care instructions or precautions</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Sidebar -->
|
|
<div class="col-lg-4">
|
|
<!-- Form Actions -->
|
|
<div class="card mb-4">
|
|
<div class="card-header">
|
|
<h5 class="mb-0">
|
|
<i class="fas fa-cog me-2"></i>Actions
|
|
</h5>
|
|
</div>
|
|
<div class="card-body">
|
|
<div class="d-grid gap-2">
|
|
<button type="submit" class="btn btn-primary">
|
|
<i class="fas fa-save me-2"></i>
|
|
{% if object %}Update Admission{% else %}Admit Patient{% endif %}
|
|
</button>
|
|
<a href="{% if object %}{% url 'inpatients:admission_detail' object.pk %}{% else %}{% url 'inpatients:admission_list' %}{% endif %}" class="btn btn-outline-secondary">
|
|
<i class="fas fa-times me-2"></i>Cancel
|
|
</a>
|
|
<button type="button" class="btn btn-outline-info" onclick="clearForm()">
|
|
<i class="fas fa-eraser me-2"></i>Clear Form
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Patient Quick Info -->
|
|
<div class="card mb-4" id="patient-info" style="display: none;">
|
|
<div class="card-header">
|
|
<h5 class="mb-0">
|
|
<i class="fas fa-user me-2"></i>Patient Information
|
|
</h5>
|
|
</div>
|
|
<div class="card-body" id="patient-details">
|
|
<!-- Patient details will be loaded here -->
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Bed Availability -->
|
|
<div class="card mb-4">
|
|
<div class="card-header">
|
|
<h5 class="mb-0">
|
|
<i class="fas fa-bed me-2"></i>Bed Availability
|
|
</h5>
|
|
</div>
|
|
<div class="card-body">
|
|
<div id="ward-bed-summary">
|
|
<div class="text-center py-3">
|
|
<i class="fas fa-hospital fa-2x text-muted mb-2"></i>
|
|
<p class="text-muted mb-0">Select a ward to view bed availability</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Admission Guidelines -->
|
|
<div class="card">
|
|
<div class="card-header">
|
|
<h5 class="mb-0">
|
|
<i class="fas fa-question-circle me-2"></i>Admission Guidelines
|
|
</h5>
|
|
</div>
|
|
<div class="card-body">
|
|
<div class="accordion" id="admissionGuide">
|
|
<div class="accordion-item">
|
|
<h2 class="accordion-header">
|
|
<button class="accordion-button collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#admissionTypes">
|
|
Admission Types
|
|
</button>
|
|
</h2>
|
|
<div id="admissionTypes" class="accordion-collapse collapse" data-bs-parent="#admissionGuide">
|
|
<div class="accordion-body">
|
|
<ul class="list-unstyled mb-0">
|
|
<li><strong>Emergency:</strong> Urgent medical care required</li>
|
|
<li><strong>Elective:</strong> Planned admission for treatment</li>
|
|
<li><strong>Transfer:</strong> From another facility</li>
|
|
<li><strong>Observation:</strong> Short-term monitoring</li>
|
|
</ul>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="accordion-item">
|
|
<h2 class="accordion-header">
|
|
<button class="accordion-button collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#bedAssignment">
|
|
Bed Assignment
|
|
</button>
|
|
</h2>
|
|
<div id="bedAssignment" class="accordion-collapse collapse" data-bs-parent="#admissionGuide">
|
|
<div class="accordion-body">
|
|
<ul class="list-unstyled mb-0">
|
|
<li><strong>Ward Selection:</strong> Based on medical specialty</li>
|
|
<li><strong>Room Type:</strong> Private, semi-private, or shared</li>
|
|
<li><strong>Isolation:</strong> Required for infectious diseases</li>
|
|
<li><strong>Special Needs:</strong> Consider patient requirements</li>
|
|
</ul>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</form>
|
|
</div>
|
|
|
|
<script>
|
|
// Admission form functionality
|
|
document.addEventListener('DOMContentLoaded', function() {
|
|
// Add Bootstrap classes to form elements
|
|
const form = document.querySelector('form');
|
|
const inputs = form.querySelectorAll('input, select, textarea');
|
|
|
|
inputs.forEach(input => {
|
|
if (!input.classList.contains('form-control') && !input.classList.contains('form-select') && !input.classList.contains('form-check-input')) {
|
|
if (input.tagName === 'SELECT') {
|
|
input.classList.add('form-select');
|
|
} else if (input.type !== 'checkbox') {
|
|
input.classList.add('form-control');
|
|
}
|
|
}
|
|
});
|
|
|
|
// Patient selection handler
|
|
const patientSelect = document.getElementById('id_patient');
|
|
if (patientSelect) {
|
|
patientSelect.addEventListener('change', loadPatientInfo);
|
|
}
|
|
|
|
// Ward selection handler
|
|
const wardSelect = document.getElementById('id_ward');
|
|
if (wardSelect) {
|
|
wardSelect.addEventListener('change', loadBedAvailability);
|
|
}
|
|
|
|
// Set current date/time as default
|
|
const admissionDate = document.getElementById('id_admission_date');
|
|
const admissionTime = document.getElementById('id_admission_time');
|
|
|
|
if (admissionDate && !admissionDate.value) {
|
|
const now = new Date();
|
|
admissionDate.value = now.toISOString().split('T')[0];
|
|
}
|
|
|
|
if (admissionTime && !admissionTime.value) {
|
|
const now = new Date();
|
|
admissionTime.value = now.toTimeString().slice(0, 5);
|
|
}
|
|
});
|
|
|
|
function loadPatientInfo() {
|
|
const patientId = document.getElementById('id_patient').value;
|
|
if (!patientId) {
|
|
document.getElementById('patient-info').style.display = 'none';
|
|
return;
|
|
}
|
|
|
|
fetch(`/patients/${patientId}/info/`)
|
|
.then(response => response.json())
|
|
.then(data => {
|
|
const patientDetails = document.getElementById('patient-details');
|
|
patientDetails.innerHTML = `
|
|
<div class="d-flex align-items-center mb-3">
|
|
<div class="avatar-sm bg-primary bg-gradient rounded-circle d-flex align-items-center justify-content-center me-3">
|
|
<span class="text-white small fw-bold">
|
|
${data.first_name.charAt(0)}${data.last_name.charAt(0)}
|
|
</span>
|
|
</div>
|
|
<div>
|
|
<h6 class="mb-0">${data.first_name} ${data.last_name}</h6>
|
|
<small class="text-muted">${data.patient_id}</small>
|
|
</div>
|
|
</div>
|
|
<dl class="row mb-0">
|
|
<dt class="col-sm-4">Age:</dt>
|
|
<dd class="col-sm-8">${data.age} years</dd>
|
|
|
|
<dt class="col-sm-4">Gender:</dt>
|
|
<dd class="col-sm-8">${data.gender}</dd>
|
|
|
|
<dt class="col-sm-4">Phone:</dt>
|
|
<dd class="col-sm-8">${data.phone || 'Not provided'}</dd>
|
|
|
|
<dt class="col-sm-4">Insurance:</dt>
|
|
<dd class="col-sm-8">${data.insurance || 'Not provided'}</dd>
|
|
</dl>
|
|
`;
|
|
document.getElementById('patient-info').style.display = 'block';
|
|
})
|
|
.catch(error => {
|
|
console.error('Error loading patient info:', error);
|
|
});
|
|
}
|
|
|
|
function loadBedAvailability() {
|
|
const wardId = document.getElementById('id_ward').value;
|
|
if (!wardId) {
|
|
document.getElementById('ward-bed-summary').innerHTML = `
|
|
<div class="text-center py-3">
|
|
<i class="fas fa-hospital fa-2x text-muted mb-2"></i>
|
|
<p class="text-muted mb-0">Select a ward to view bed availability</p>
|
|
</div>
|
|
`;
|
|
return;
|
|
}
|
|
|
|
fetch(`/inpatients/wards/${wardId}/beds/`)
|
|
.then(response => response.json())
|
|
.then(data => {
|
|
const summary = document.getElementById('ward-bed-summary');
|
|
summary.innerHTML = `
|
|
<div class="row text-center">
|
|
<div class="col-6 mb-2">
|
|
<div class="card bg-success bg-gradient text-white">
|
|
<div class="card-body py-2">
|
|
<h6 class="mb-0">${data.available}</h6>
|
|
<small>Available</small>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="col-6 mb-2">
|
|
<div class="card bg-primary bg-gradient text-white">
|
|
<div class="card-body py-2">
|
|
<h6 class="mb-0">${data.occupied}</h6>
|
|
<small>Occupied</small>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="mt-2">
|
|
<small class="text-muted">
|
|
${data.total} total beds in ${data.ward_name}
|
|
</small>
|
|
</div>
|
|
`;
|
|
|
|
// Update bed dropdown
|
|
updateBedOptions(data.beds);
|
|
})
|
|
.catch(error => {
|
|
console.error('Error loading bed availability:', error);
|
|
});
|
|
}
|
|
|
|
function updateBedOptions(beds) {
|
|
const bedSelect = document.getElementById('id_bed');
|
|
bedSelect.innerHTML = '<option value="">Select a bed</option>';
|
|
|
|
beds.forEach(bed => {
|
|
if (bed.status === 'AVAILABLE') {
|
|
const option = document.createElement('option');
|
|
option.value = bed.id;
|
|
option.textContent = `${bed.bed_number} (${bed.room_type})`;
|
|
bedSelect.appendChild(option);
|
|
}
|
|
});
|
|
}
|
|
|
|
function clearForm() {
|
|
if (confirm('Are you sure you want to clear all form data?')) {
|
|
const form = document.querySelector('form');
|
|
const inputs = form.querySelectorAll('input, select, textarea');
|
|
|
|
inputs.forEach(input => {
|
|
if (input.type !== 'hidden' && input.name !== 'csrfmiddlewaretoken') {
|
|
if (input.type === 'checkbox') {
|
|
input.checked = false;
|
|
} else {
|
|
input.value = '';
|
|
}
|
|
}
|
|
});
|
|
|
|
// Reset patient info
|
|
document.getElementById('patient-info').style.display = 'none';
|
|
|
|
// Reset bed availability
|
|
document.getElementById('ward-bed-summary').innerHTML = `
|
|
<div class="text-center py-3">
|
|
<i class="fas fa-hospital fa-2x text-muted mb-2"></i>
|
|
<p class="text-muted mb-0">Select a ward to view bed availability</p>
|
|
</div>
|
|
`;
|
|
}
|
|
}
|
|
|
|
// Form submission with loading state
|
|
document.querySelector('form').addEventListener('submit', function() {
|
|
const submitBtn = document.querySelector('button[type="submit"]');
|
|
const originalText = submitBtn.innerHTML;
|
|
|
|
submitBtn.innerHTML = '<i class="fas fa-spinner fa-spin me-2"></i>Processing...';
|
|
submitBtn.disabled = true;
|
|
|
|
// Re-enable if form validation fails
|
|
setTimeout(() => {
|
|
if (document.querySelector('.is-invalid')) {
|
|
submitBtn.innerHTML = originalText;
|
|
submitBtn.disabled = false;
|
|
}
|
|
}, 100);
|
|
});
|
|
|
|
// Real-time validation
|
|
document.querySelectorAll('input[required], select[required]').forEach(input => {
|
|
input.addEventListener('blur', function() {
|
|
if (this.value.trim() === '') {
|
|
this.classList.add('is-invalid');
|
|
} else {
|
|
this.classList.remove('is-invalid');
|
|
}
|
|
});
|
|
|
|
input.addEventListener('input', function() {
|
|
if (this.classList.contains('is-invalid') && this.value.trim() !== '') {
|
|
this.classList.remove('is-invalid');
|
|
}
|
|
});
|
|
});
|
|
</script>
|
|
|
|
<style>
|
|
.is-invalid {
|
|
border-color: #dc3545;
|
|
}
|
|
|
|
.invalid-feedback {
|
|
display: block;
|
|
width: 100%;
|
|
margin-top: 0.25rem;
|
|
font-size: 0.875em;
|
|
color: #dc3545;
|
|
}
|
|
|
|
.text-danger {
|
|
color: #dc3545 !important;
|
|
}
|
|
|
|
.avatar-sm {
|
|
width: 32px;
|
|
height: 32px;
|
|
font-size: 0.75rem;
|
|
}
|
|
|
|
.bg-gradient {
|
|
background-image: linear-gradient(180deg, rgba(255, 255, 255, 0.15), rgba(255, 255, 255, 0));
|
|
}
|
|
|
|
.accordion-button:not(.collapsed) {
|
|
background-color: #e7f1ff;
|
|
color: #0d6efd;
|
|
}
|
|
|
|
.form-check-label {
|
|
cursor: pointer;
|
|
}
|
|
|
|
@media (max-width: 768px) {
|
|
.row.mb-3 .col-md-6 {
|
|
margin-bottom: 1rem;
|
|
}
|
|
|
|
.d-flex.justify-content-between {
|
|
flex-direction: column;
|
|
gap: 0.5rem;
|
|
}
|
|
}
|
|
</style>
|
|
{% endblock %}
|
|
|