280 lines
12 KiB
HTML
280 lines
12 KiB
HTML
{% extends base_layout %}
|
|
{% extends base_layout %}
|
|
{% load i18n %}
|
|
{% load static %}
|
|
|
|
{% block title %}{{ _("New Complaint")}} - PX360{% endblock %}
|
|
|
|
{% block extra_css %}
|
|
<style>
|
|
.form-section {
|
|
background: #fff;
|
|
border: 1px solid #dee2e6;
|
|
border-radius: 8px;
|
|
padding: 25px;
|
|
margin-bottom: 20px;
|
|
}
|
|
.form-section-title {
|
|
font-size: 1.1rem;
|
|
font-weight: 600;
|
|
color: #495057;
|
|
margin-bottom: 20px;
|
|
padding-bottom: 10px;
|
|
border-bottom: 2px solid #667eea;
|
|
}
|
|
.required-field::after {
|
|
content: " *";
|
|
color: #dc3545;
|
|
}
|
|
</style>
|
|
{% endblock %}
|
|
|
|
{% block content %}
|
|
<div class="container-fluid">
|
|
<!-- Page Header -->
|
|
<div class="mb-4">
|
|
{% if source_user %}
|
|
<a href="{% url 'px_sources:source_user_complaint_list' %}" class="btn btn-outline-secondary btn-sm mb-3">
|
|
<i class="bi bi-arrow-left me-1"></i> {{ _("Back to My Complaints")}}
|
|
</a>
|
|
{% else %}
|
|
<a href="{% url 'complaints:complaint_list' %}" class="btn btn-outline-secondary btn-sm mb-3">
|
|
<i class="bi bi-arrow-left me-1"></i> {{ _("Back to Complaints")}}
|
|
</a>
|
|
{% endif %}
|
|
<h2 class="mb-1">
|
|
<i class="bi bi-plus-circle text-primary me-2"></i>
|
|
{{ _("Create New Complaint")}}
|
|
</h2>
|
|
<p class="text-muted mb-0">{{ _("File a new patient complaint with SLA tracking")}}</p>
|
|
</div>
|
|
|
|
<form method="post" action="{% url 'complaints:complaint_create' %}" id="complaintForm" novalidate>
|
|
{% csrf_token %}
|
|
|
|
<div class="row">
|
|
<div class="col-lg-8">
|
|
<!-- Patient Information -->
|
|
<div class="form-section">
|
|
<h5 class="form-section-title">
|
|
<i class="bi bi-person-fill me-2"></i>{{ _("Patient Information")}}
|
|
</h5>
|
|
|
|
<div class="row">
|
|
<div class="col-md-6 mb-3">
|
|
<label for="{{ form.patient.id_for_label }}" class="form-label required-field">
|
|
{{ form.patient.label }}
|
|
</label>
|
|
{{ form.patient }}
|
|
{% if form.patient.errors %}
|
|
<div class="invalid-feedback d-block">
|
|
{% for error in form.patient.errors %}
|
|
<small class="text-danger">{{ error }}</small>
|
|
{% endfor %}
|
|
</div>
|
|
{% endif %}
|
|
</div>
|
|
|
|
<div class="col-md-6 mb-3">
|
|
<label for="{{ form.encounter_id.id_for_label }}" class="form-label">
|
|
{{ form.encounter_id.label }}
|
|
</label>
|
|
{{ form.encounter_id }}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Organization Information -->
|
|
<div class="form-section">
|
|
<h5 class="form-section-title">
|
|
<i class="bi bi-hospital me-2"></i>{{ _("Organization") }}
|
|
</h5>
|
|
|
|
<div class="row">
|
|
<div class="col-md-6 mb-3">
|
|
<label for="{{ form.hospital.id_for_label }}" class="form-label required-field">
|
|
{{ form.hospital.label }}
|
|
</label>
|
|
{{ form.hospital }}
|
|
{% if form.hospital.errors %}
|
|
<div class="invalid-feedback d-block">
|
|
{% for error in form.hospital.errors %}
|
|
<small class="text-danger">{{ error }}</small>
|
|
{% endfor %}
|
|
</div>
|
|
{% endif %}
|
|
</div>
|
|
|
|
<div class="col-md-6 mb-3">
|
|
<label for="{{ form.department.id_for_label }}" class="form-label">
|
|
{{ form.department.label }}
|
|
</label>
|
|
{{ form.department }}
|
|
{% if form.department.errors %}
|
|
<div class="invalid-feedback d-block">
|
|
{% for error in form.department.errors %}
|
|
<small class="text-danger">{{ error }}</small>
|
|
{% endfor %}
|
|
</div>
|
|
{% endif %}
|
|
</div>
|
|
</div>
|
|
|
|
<div class="row">
|
|
<div class="col-md-6 mb-3">
|
|
<label for="{{ form.staff.id_for_label }}" class="form-label">
|
|
{{ form.staff.label }}
|
|
</label>
|
|
{{ form.staff }}
|
|
{% if form.staff.errors %}
|
|
<div class="invalid-feedback d-block">
|
|
{% for error in form.staff.errors %}
|
|
<small class="text-danger">{{ error }}</small>
|
|
{% endfor %}
|
|
</div>
|
|
{% endif %}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Complaint Details -->
|
|
<div class="form-section">
|
|
<h5 class="form-section-title">
|
|
<i class="bi bi-file-text me-2"></i>{{ _("Complaint Details")}}
|
|
</h5>
|
|
|
|
<div class="mb-3">
|
|
<label for="{{ form.description.id_for_label }}" class="form-label required-field">
|
|
{{ form.description.label }}
|
|
</label>
|
|
{{ form.description }}
|
|
{% if form.description.errors %}
|
|
<div class="invalid-feedback d-block">
|
|
{% for error in form.description.errors %}
|
|
<small class="text-danger">{{ error }}</small>
|
|
{% endfor %}
|
|
</div>
|
|
{% endif %}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Sidebar -->
|
|
<div class="col-lg-4">
|
|
<!-- AI Information -->
|
|
<div class="alert alert-info">
|
|
<h6 class="alert-heading">
|
|
<i class="bi bi-info-circle me-2"></i>{{ _("AI Classification")}}
|
|
</h6>
|
|
<p class="mb-0 small">
|
|
{{ _("AI will automatically analyze and classify your complaint:")}}
|
|
</p>
|
|
<ul class="mb-0 mt-2 small">
|
|
<li><strong>{{ _("Title") }}:</strong> {{ _("AI-generated title")}}</li>
|
|
<li><strong>{{ _("Category") }}:</strong> {{ _("AI-determined category")}}</li>
|
|
<li><strong>{{ _("Severity") }}:</strong> {{ _("AI-calculated severity")}}</li>
|
|
<li><strong>{{ _("Priority") }}:</strong> {{ _("AI-calculated priority")}}</li>
|
|
</ul>
|
|
</div>
|
|
|
|
<!-- SLA Information -->
|
|
<div class="alert alert-info">
|
|
<h6 class="alert-heading">
|
|
<i class="bi bi-clock me-2"></i>{{ _("SLA Information")}}
|
|
</h6>
|
|
<p class="mb-0 small">
|
|
{{ _("SLA deadline will be automatically calculated based on severity")}}:
|
|
</p>
|
|
<ul class="mb-0 mt-2 small">
|
|
<li><strong>{{ _("Critical") }}:</strong> {{ _("4 hours")}}</li>
|
|
<li><strong>{{ _("High") }}:</strong> {{ _("24 hours")}}</li>
|
|
<li><strong>{{ _("Medium") }}:</strong> {{ _("72 hours")}}</li>
|
|
<li><strong>{{ _("Low") }}:</strong> {{ _("168 hours (7 days)")}}</li>
|
|
</ul>
|
|
</div>
|
|
|
|
<!-- Action Buttons -->
|
|
<div class="d-grid gap-2">
|
|
<button type="submit" class="btn btn-primary btn-lg">
|
|
<i class="bi bi-check-circle me-2"></i>{{ _("Create Complaint")}}
|
|
</button>
|
|
{% if source_user %}
|
|
<a href="{% url 'px_sources:source_user_complaint_list' %}" class="btn btn-outline-secondary">
|
|
<i class="bi bi-x-circle me-2"></i>{{ _("Cancel") }}
|
|
</a>
|
|
{% else %}
|
|
<a href="{% url 'complaints:complaint_list' %}" class="btn btn-outline-secondary">
|
|
<i class="bi bi-x-circle me-2"></i>{{ _("Cancel") }}
|
|
</a>
|
|
{% endif %}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</form>
|
|
</div>
|
|
{% endblock %}
|
|
|
|
{% block extra_js %}
|
|
<script>
|
|
document.addEventListener('DOMContentLoaded', function() {
|
|
const hospitalSelect = document.getElementById('hospitalSelect');
|
|
const departmentSelect = document.getElementById('departmentSelect');
|
|
const staffSelect = document.getElementById('staffSelect');
|
|
|
|
// Hospital change handler - reload form with selected hospital
|
|
if (hospitalSelect) {
|
|
hospitalSelect.addEventListener('change', function() {
|
|
const hospitalId = this.value;
|
|
const form = document.getElementById('complaintForm');
|
|
const actionUrl = form.action;
|
|
|
|
// Create URL with hospital_id parameter
|
|
const url = new URL(actionUrl, window.location);
|
|
url.searchParams.set('hospital', hospitalId);
|
|
|
|
// Reload form with selected hospital
|
|
window.location.href = url.toString();
|
|
});
|
|
}
|
|
|
|
// Department change handler - load staff
|
|
if (departmentSelect) {
|
|
departmentSelect.addEventListener('change', function() {
|
|
const departmentId = this.value;
|
|
|
|
// Clear staff dropdown
|
|
staffSelect.innerHTML = '<option value="">{{ _("Select staff")}}</option>';
|
|
|
|
if (departmentId) {
|
|
// Load staff via minimal AJAX
|
|
fetch(`/complaints/ajax/physicians/?department_id=${departmentId}`)
|
|
.then(response => response.json())
|
|
.then(data => {
|
|
staffSelect.innerHTML = '<option value="">{{ _("Select staff")}}</option>';
|
|
data.staff.forEach(staff => {
|
|
const option = document.createElement('option');
|
|
option.value = staff.id;
|
|
option.textContent = `${staff.first_name} ${staff.last_name} (${staff.job_title || staff.staff_type})`;
|
|
staffSelect.appendChild(option);
|
|
});
|
|
})
|
|
.catch(error => {
|
|
console.error('Error loading staff:', error);
|
|
});
|
|
}
|
|
});
|
|
}
|
|
|
|
// Form validation
|
|
const form = document.getElementById('complaintForm');
|
|
form.addEventListener('submit', function(e) {
|
|
if (!form.checkValidity()) {
|
|
e.preventDefault();
|
|
e.stopPropagation();
|
|
}
|
|
form.classList.add('was-validated');
|
|
});
|
|
});
|
|
</script>
|
|
{% endblock %}
|