HH/templates/core/public_submit.html

1307 lines
44 KiB
HTML

{% extends "layouts/public_base.html" %}
{% load i18n %}
{% block title %}{% trans "Submit Feedback" %}{% endblock %}
{% block extra_css %}
<style>
:root {
--hh-primary: #0086d2;
--hh-primary-dark: #005d93;
--hh-primary-light: #4caadf;
--hh-primary-lighter: #b2ebf2;
--hh-primary-bg: rgba(0, 151, 167, 0.1);
--primary-color: #0097a7;
--primary-dark: #00838f;
--primary-light: #4dd0e1;
--primary-lighter: #b2ebf2;
--primary-bg: rgba(0, 151, 167, 0.1);
--secondary-color: #1a237e;
--secondary-dark: #0d1642;
--accent-color: #c62828;
--success-color: #00897b;
--warning-color: #f9a825;
--danger-color: #c62828;
--text-dark: #263238;
--text-muted: #607d8b;
--border-color: #e0e6ed;
--bg-gradient: linear-gradient(180deg, #00838f 0%, #0097a7 50%, #00838f 100%);
--white: #ffffff;
--shadow-sm: 0 2px 8px rgba(0, 0, 0, 0.06);
--shadow-md: 0 4px 16px rgba(0, 0, 0, 0.08);
--shadow-lg: 0 8px 24px rgba(0, 0, 0, 0.12);
}
* {
box-sizing: border-box;
}
body {
background: var(--bg-gradient);
background: linear-gradient(180deg, var(--hh-primary-dark) 0%, var(--hh-primary) 50%, var(--hh-primary-dark) 100%);
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
min-height: 100vh;
}
.logo-section {
text-align: center;
margin-bottom: 2rem;
}
.logo-section img {
max-height: 80px;
max-width: 100%;
object-fit: contain;
}
.public-submit-container {
max-width: 1000px;
margin: 0 auto;
padding: 2rem 1rem;
}
/* Header */
.header-section {
text-align: center;
margin-bottom: 3rem;
padding: 1.5rem 2rem 2rem;
background: var(--white);
border-radius: 16px;
box-shadow: var(--shadow-md);
}
.header-section h1 {
color: var(--text-dark);
font-size: 2.25rem;
font-weight: 600;
margin-bottom: 1rem;
letter-spacing: -0.5px;
}
.header-section p {
color: var(--text-muted);
font-size: 1.05rem;
max-width: 500px;
margin: 0 auto;
line-height: 1.6;
}
/* Selection Cards */
.selection-cards {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
gap: 1.5rem;
margin-bottom: 2rem;
}
.selection-card {
background: var(--white);
border-radius: 16px;
padding: 2.5rem 2rem;
text-align: center;
cursor: pointer;
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
border: 2px solid transparent;
box-shadow: var(--shadow-sm);
position: relative;
overflow: hidden;
}
.selection-card::before {
content: '';
position: absolute;
top: 0;
left: 0;
right: 0;
height: 4px;
opacity: 0;
transition: opacity 0.3s;
}
.card-complaint::before { background: linear-gradient(90deg, #ff6b6b, #ee5a52); }
.card-observation::before { background: linear-gradient(90deg, #9b59b6, #8e44ad); }
.card-inquiry::before { background: linear-gradient(90deg, #0077b6, #005a8c); }
.selection-card:hover {
transform: translateY(-4px);
box-shadow: var(--shadow-lg);
}
.selection-card:hover::before {
opacity: 1;
}
.card-icon {
font-size: 3.5rem;
margin-bottom: 1.5rem;
transition: transform 0.3s;
}
.selection-card:hover .card-icon {
transform: scale(1.1);
}
.card-complaint .card-icon { color: #ff6b6b; }
.card-observation .card-icon { color: #9b59b6; }
.card-inquiry .card-icon { color: var(--primary-color); }
.card-title {
font-size: 1.35rem;
font-weight: 600;
color: var(--text-dark);
margin-bottom: 0.75rem;
}
.card-description {
color: var(--text-muted);
line-height: 1.6;
font-size: 0.95rem;
}
/* Form Container */
.form-container {
display: none;
background: var(--white);
border-radius: 16px;
padding: 2.5rem;
box-shadow: var(--shadow-md);
}
.form-container.active {
display: block;
animation: fadeIn 0.4s ease-out;
}
@keyframes fadeIn {
from {
opacity: 0;
transform: translateY(8px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
.back-button {
margin-bottom: 1.5rem;
}
.back-button .btn {
padding: 0.6rem 1.25rem;
font-size: 0.95rem;
border-radius: 8px;
}
/* Form Sections */
.form-section {
background: var(--white);
padding: 0;
margin-bottom: 0;
}
.form-section h3 {
color: var(--text-dark);
font-size: 1.5rem;
font-weight: 600;
margin-bottom: 1.5rem;
padding-bottom: 1rem;
border-bottom: 2px solid var(--primary-light);
}
.form-section > p {
color: var(--text-muted);
font-size: 0.95rem;
margin-bottom: 2rem;
line-height: 1.6;
}
/* Form Controls */
.form-group {
margin-bottom: 1.5rem;
}
.form-group label {
display: block;
font-weight: 500;
color: var(--text-dark);
margin-bottom: 0.5rem;
font-size: 0.95rem;
}
.form-group .form-control {
padding: 0.75rem 1rem;
border: 1px solid var(--border-color);
border-radius: 8px;
font-size: 0.95rem;
transition: all 0.2s;
background-color: var(--white);
}
.form-group .form-control:focus {
outline: none;
border-color: var(--primary-color);
box-shadow: 0 0 0 3px var(--primary-light);
}
.form-group textarea.form-control {
resize: vertical;
min-height: 120px;
}
.form-group small {
color: var(--text-muted);
font-size: 0.85rem;
margin-top: 0.35rem;
}
/* Required Mark */
.required-mark {
color: var(--danger-color);
font-weight: 600;
}
/* Buttons */
.btn {
padding: 0.75rem 1.5rem;
border-radius: 8px;
font-weight: 500;
font-size: 0.95rem;
transition: all 0.2s;
border: none;
}
.btn-primary {
background-color: var(--primary-color);
color: var(--white);
}
.btn-primary:hover {
background-color: var(--primary-dark);
transform: translateY(-1px);
box-shadow: var(--shadow-md);
}
.btn-primary:disabled {
background-color: var(--text-muted);
cursor: not-allowed;
transform: none;
box-shadow: none;
}
.btn-outline-secondary {
background-color: transparent;
border: 1.5px solid var(--border-color);
color: var(--text-muted);
}
.btn-outline-secondary:hover {
background-color: var(--bg-light);
border-color: var(--text-muted);
color: var(--text-dark);
}
.btn-lg {
padding: 1rem 2rem;
font-size: 1rem;
font-weight: 600;
}
/* Severity Options */
.severity-option {
padding: 1rem 1.25rem;
border-radius: 10px;
border: 2px solid var(--border-color);
cursor: pointer;
transition: all 0.2s;
font-weight: 500;
font-size: 0.9rem;
}
.severity-option:hover {
border-color: var(--primary-light);
background-color: var(--primary-light);
}
.severity-option.selected {
border-color: var(--primary-color);
background-color: var(--primary-light);
}
.severity-low.selected {
border-color: var(--success-color);
background-color: #d4edda;
}
.severity-medium.selected {
border-color: var(--warning-color);
background-color: #fff3cd;
}
.severity-high.selected {
border-color: #fd7e14;
background-color: #ffe5d0;
}
.severity-critical.selected {
border-color: var(--danger-color);
background-color: #f8d7da;
}
/* File Upload */
.file-upload-area {
border: 2px dashed var(--border-color);
border-radius: 12px;
padding: 2.5rem;
text-align: center;
cursor: pointer;
transition: all 0.2s;
background-color: var(--bg-light);
}
.file-upload-area:hover {
border-color: var(--primary-color);
background-color: var(--primary-light);
}
.file-upload-area i {
font-size: 2.5rem;
color: var(--primary-color);
margin-bottom: 1rem;
transition: transform 0.2s;
}
.file-upload-area:hover i {
transform: scale(1.1);
}
/* Category Description */
.category-description {
background-color: var(--primary-light);
border-left: 3px solid var(--primary-color);
padding: 1rem 1.25rem;
margin-top: 1rem;
border-radius: 0 8px 8px 0;
}
[dir="rtl"] .category-description {
border-left: none;
border-right: 3px solid var(--primary-color);
border-radius: 8px 0 0 8px;
}
.description-title {
font-weight: 600;
color: var(--text-dark);
margin-bottom: 0.5rem;
font-size: 0.9rem;
}
/* Track Links */
.track-links {
text-align: center;
margin-top: 3rem;
padding-top: 2rem;
border-top: 1px solid var(--border-color);
}
.track-links p {
color: var(--text-muted);
margin-bottom: 1rem;
font-size: 0.95rem;
}
.track-links a {
color: var(--primary-color);
text-decoration: none;
margin: 0 1rem;
display: inline-block;
font-weight: 500;
font-size: 0.95rem;
transition: color 0.2s;
}
.track-links a:hover {
color: var(--primary-dark);
text-decoration: underline;
}
/* Spinner */
.spinner {
display: inline-block;
width: 1rem;
height: 1rem;
border: 2px solid rgba(255,255,255,0.3);
border-radius: 50%;
border-top-color: white;
animation: spin 0.8s linear infinite;
margin-right: 0.5rem;
}
@keyframes spin {
to { transform: rotate(360deg); }
}
[dir="rtl"] .spinner {
margin-right: 0;
margin-left: 0.5rem;
}
.loading-spinner {
text-align: center;
padding: 4rem 2rem;
}
.loading-spinner i {
font-size: 2.5rem;
color: var(--primary-color);
animation: spin 1s linear infinite;
margin-bottom: 1.5rem;
}
.loading-spinner p {
color: var(--text-muted);
font-size: 0.95rem;
}
/* RTL Support */
[dir="rtl"] .selection-card::before {
left: auto;
}
[dir="rtl"] .card-icon {
margin-right: 0;
}
[dir="rtl"] .form-group .form-control {
text-align: right;
}
/* Responsive */
@media (max-width: 768px) {
.public-submit-container {
padding: 2rem 1rem;
}
.header-section h1 {
font-size: 1.75rem;
}
.form-container {
padding: 1.5rem;
border-radius: 12px;
}
.selection-card {
padding: 2rem 1.5rem;
}
.card-icon {
font-size: 3rem;
}
}
</style>
{% endblock %}
{% block content %}
{% load static %}
<div class="public-submit-container">
<!-- Logo -->
<div class="logo-section">
<img src="{% static 'img/logo.png' %}" alt="Al Hammadi Hospital Logo">
</div>
<!-- Header -->
<div class="header-section">
<h1>{% trans "We Value Your Feedback" %}</h1>
<p>{% trans "Your feedback helps us improve our services and provide better care for everyone." %}</p>
</div>
<!-- Selection Cards -->
<div class="selection-cards" id="selectionCards">
<!-- Complaint Card -->
<div class="selection-card card-complaint" data-type="complaint">
<div class="card-icon">
<i class="fas fa-exclamation-circle"></i>
</div>
<h3 class="card-title">{% trans "Complaint" %}</h3>
<p class="card-description">
{% trans "Report an issue with our services. We take all concerns seriously and will investigate thoroughly." %}
</p>
</div>
<!-- Observation Card -->
<div class="selection-card card-observation" data-type="observation">
<div class="card-icon">
<i class="fas fa-eye"></i>
</div>
<h3 class="card-title">{% trans "Observation" %}</h3>
<p class="card-description">
{% trans "Help us improve safety and quality by sharing what you've noticed. Submit anonymously." %}
</p>
</div>
<!-- Inquiry Card -->
<div class="selection-card card-inquiry" data-type="inquiry">
<div class="card-icon">
<i class="fas fa-question-circle"></i>
</div>
<h3 class="card-title">{% trans "Inquiry" %}</h3>
<p class="card-description">
{% trans "Have questions? We're here to help with appointments, services, or general information." %}
</p>
</div>
</div>
<!-- Form Container -->
<div class="form-container" id="publicFormContainer">
<!-- Back Button -->
<div class="back-button">
<button class="btn btn-outline-secondary" onclick="resetToSelection()">
<i class="fas fa-arrow-left me-2"></i>{% trans "Back to Selection" %}
</button>
</div>
<!-- Loading Spinner -->
<div class="loading-spinner" id="loadingSpinner" style="display: none;">
<i class="fas fa-circle-notch"></i>
<p>{% trans "Loading form..." %}</p>
</div>
<!-- Form Content (loaded via AJAX) -->
<div id="formContent"></div>
</div>
<!-- Track Links -->
<div class="track-links">
<p>{% trans "Already submitted something?" %}</p>
<a href="{% url 'complaints:public_complaint_success' 'lookup' %}">
<i class="fas fa-search me-1"></i>{% trans "Track Complaint" %}
</a>
<a href="{% url 'observations:observation_track' %}">
<i class="fas fa-search me-1"></i>{% trans "Track Observation" %}
</a>
</div>
</div>
<!-- Success Modal -->
<div class="modal fade" id="successModal" tabindex="-1" role="dialog" aria-hidden="true">
<div class="modal-dialog modal-dialog-centered" role="document">
<div class="modal-content">
<div class="modal-body text-center" style="padding: 3.5rem 2.5rem;">
<i class="fas fa-check-circle" style="font-size: 4.5rem; color: #28a745; margin-bottom: 1.5rem;"></i>
<h3 style="margin-bottom: 0.75rem; font-weight: 600;">{% trans "Submitted Successfully!" %}</h3>
<p style="color: #6c757d; margin-bottom: 1.5rem; line-height: 1.6;">
{% trans "Your submission has been received and is being processed." %}
</p>
<p style="margin-bottom: 0.5rem;">
<strong style="color: #2c3e50;">{% trans "Reference Number:" %}</strong>
</p>
<span id="referenceNumber" style="font-size: 1.75rem; color: #0077b6; font-weight: 600; letter-spacing: 0.5px;"></span>
<p style="color: #6c757d; margin-top: 1.5rem; font-size: 0.9rem;">
{% trans "Please save this reference number for your records." %}
</p>
</div>
</div>
</div>
</div>
{% endblock %}
{% block extra_js %}
<script src="https://cdn.jsdelivr.net/npm/sweetalert2@11"></script>
<script>
$(document).ready(function() {
let currentFormType = null;
// Handle card selection
$('.selection-card').on('click', function() {
const formType = $(this).data('type');
currentFormType = formType;
// Hide selection cards
$('#selectionCards').slideUp(300);
// Show form container
$('#publicFormContainer').fadeIn(300);
// Load the appropriate form
loadForm(formType);
});
// Load form via AJAX
function loadForm(formType) {
$('#loadingSpinner').show();
$('#formContent').hide();
let hospitals = [];
// Get hospitals for the form
$.ajax({
url: '/core/api/hospitals/',
type: 'GET',
async: false,
success: function(response) {
hospitals = response.hospitals || [];
}
});
if (formType === 'complaint') {
// Load complaint form via AJAX
$.ajax({
url: '{% url "complaints:public_complaint_submit" %}',
type: 'GET',
success: function(response) {
// Extract form from response
const formHtml = $('<div>').html(response).find('.complaint-form').html();
$('#formContent').html(formHtml);
// Initialize form functionality
if (typeof initializeComplaintForm === 'function') {
initializeComplaintForm();
}
showForm();
},
error: function() {
$('#loadingSpinner').hide();
Swal.fire({
icon: 'error',
title: '{% trans "Error" %}',
text: '{% trans "Failed to load form. Please try again." %}'
});
}
});
} else if (formType === 'observation') {
// Render observation form inline
fetchCategoriesAndRenderObservationForm();
} else if (formType === 'inquiry') {
// Render inquiry form template with context
renderInquiryForm(hospitals);
}
}
function fetchCategoriesAndRenderObservationForm() {
// Fetch observation categories
$.ajax({
url: '/core/api/observation-categories/',
type: 'GET',
success: function(response) {
renderObservationForm(response.categories || []);
},
error: function() {
$('#loadingSpinner').hide();
Swal.fire({
icon: 'error',
title: '{% trans "Error" %}',
text: '{% trans "Failed to load observation form. Please try again." %}'
});
}
});
}
function renderObservationForm(categories) {
// Build observation categories options
let categoriesOptions = '<option value="">{% trans "Select Category" %} ({% trans "optional" %})</option>';
categories.forEach(function(category) {
const lang = '{{ LANGUAGE_CODE }}';
const name = lang === 'ar' ? category.name_ar : category.name_en;
categoriesOptions += `<option value="${category.id}">${name}</option>`;
});
const formHtml = `
<form id="observationForm" enctype="multipart/form-data">
{% csrf_token %}
<div class="form-section">
<h3><i class="fas fa-eye me-2"></i>{% trans "Report an Observation" %}</h3>
<p>{% trans "Help us improve by reporting issues you notice. You can submit this anonymously." %}</p>
<div class="row">
<div class="col-md-6">
<div class="form-group">
<label>{% trans "Category" %} <span class="text-muted">({% trans "optional" %})</span></label>
<select class="form-control" name="category">
${categoriesOptions}
</select>
</div>
</div>
<div class="col-md-6">
<div class="form-group">
<label>{% trans "Severity" %} <span class="required-mark">*</span></label>
<div class="d-flex gap-2">
<div class="severity-option severity-low flex-1 text-center" data-value="low">
<i class="fas fa-info-circle me-1"></i>{% trans "Low" %}
</div>
<div class="severity-option severity-medium flex-1 text-center selected" data-value="medium">
<i class="fas fa-exclamation-circle me-1"></i>{% trans "Medium" %}
</div>
<div class="severity-option severity-high flex-1 text-center" data-value="high">
<i class="fas fa-exclamation-triangle me-1"></i>{% trans "High" %}
</div>
<div class="severity-option severity-critical flex-1 text-center" data-value="critical">
<i class="fas fa-exclamation-circle me-1"></i>{% trans "Critical" %}
</div>
</div>
<input type="hidden" name="severity" id="severityInput" value="medium">
</div>
</div>
</div>
<div class="form-group">
<label>{% trans "Title" %} <span class="text-muted">({% trans "optional" %})</span></label>
<input type="text" class="form-control" name="title" maxlength="200" placeholder="{% trans 'Brief title of your observation' %}">
</div>
<div class="form-group">
<label>{% trans "Description" %} <span class="required-mark">*</span></label>
<textarea class="form-control" name="description" rows="5" required placeholder="{% trans 'Please describe what you observed in detail...' %}"></textarea>
</div>
<div class="row">
<div class="col-md-6">
<div class="form-group">
<label>{% trans "Location" %} <span class="text-muted">({% trans "optional" %})</span></label>
<input type="text" class="form-control" name="location_text" maxlength="200" placeholder="{% trans 'Where did this occur?' %}">
</div>
</div>
<div class="col-md-6">
<div class="form-group">
<label>{% trans "When did this occur?" %} <span class="text-muted">({% trans "optional" %})</span></label>
<input type="datetime-local" class="form-control" name="incident_datetime">
</div>
</div>
</div>
<div class="form-group">
<label>{% trans "Attachments" %} <span class="text-muted">({% trans "optional" %})</span></label>
<div class="file-upload-area" onclick="document.getElementById('observationAttachments').click()">
<i class="fas fa-cloud-upload-alt"></i>
<p class="mb-0 mt-2">{% trans "Click to upload files" %}</p>
<small class="text-muted">{% trans "Images, PDF, Word, Excel (max 10MB each)" %}</small>
</div>
<input type="file" id="observationAttachments" name="attachments" multiple
accept=".jpg,.jpeg,.png,.gif,.pdf,.doc,.docx,.xls,.xlsx"
style="display: none;" onchange="updateObservationFileList()">
<div id="observationFileList" class="mt-2"></div>
</div>
<div class="form-group" style="margin-top: 2rem; padding-top: 2rem; border-top: 1px solid #dee2e6;">
<label style="margin-bottom: 1rem;">{% trans "Your Information" %} <span class="text-muted">({% trans "optional" %})</span></label>
<p class="text-muted small mb-3">{% trans "Providing your information helps us follow up if needed. Leave blank to submit anonymously." %}</p>
<div class="row">
<div class="col-md-6">
<div class="form-group">
<label>{% trans "Staff ID" %}</label>
<input type="text" class="form-control" name="reporter_staff_id" placeholder="{% trans 'Optional' %}">
</div>
</div>
<div class="col-md-6">
<div class="form-group">
<label>{% trans "Name" %}</label>
<input type="text" class="form-control" name="reporter_name" placeholder="{% trans 'Optional' %}">
</div>
</div>
</div>
<div class="row">
<div class="col-md-6">
<div class="form-group">
<label>{% trans "Phone" %}</label>
<input type="tel" class="form-control" name="reporter_phone" placeholder="{% trans 'Optional' %}">
</div>
</div>
<div class="col-md-6">
<div class="form-group">
<label>{% trans "Email" %}</label>
<input type="email" class="form-control" name="reporter_email" placeholder="{% trans 'Optional' %}">
</div>
</div>
</div>
</div>
<div class="text-center" style="margin-top: 2.5rem;">
<button type="submit" class="btn btn-primary btn-lg" id="observationSubmitBtn">
<i class="fas fa-paper-plane me-2"></i>{% trans "Submit Observation" %}
</button>
</div>
</div>
</form>
`;
$('#formContent').html(formHtml);
// Initialize severity selection
$('#formContent').on('click', '.severity-option', function() {
$('#formContent').find('.severity-option').removeClass('selected');
$(this).addClass('selected');
$('#severityInput').val($(this).data('value'));
});
// Attach form submission handler
$('#observationForm').on('submit', handleObservationSubmit);
showForm();
}
function updateObservationFileList() {
const input = document.getElementById('observationAttachments');
const fileList = document.getElementById('observationFileList');
fileList.innerHTML = '';
if (input.files.length > 0) {
const list = document.createElement('ul');
list.className = 'list-unstyled mb-0';
for (let i = 0; i < input.files.length; i++) {
const li = document.createElement('li');
li.className = 'small text-muted py-1';
li.innerHTML = '<i class="fas fa-file me-2"></i>' + input.files[i].name;
list.appendChild(li);
}
fileList.appendChild(list);
}
}
function handleObservationSubmit(e) {
e.preventDefault();
const submitBtn = $('#observationSubmitBtn');
const originalText = submitBtn.html();
submitBtn.prop('disabled', true).html(
'<span class="spinner"></span>{% trans "Submitting..." %}'
);
const formData = new FormData(this);
$.ajax({
url: '/core/public/observation/submit/',
type: 'POST',
data: formData,
processData: false,
contentType: false,
headers: {
'X-CSRFToken': getCSRFToken()
},
success: function(response) {
if (response.success) {
$('#referenceNumber').text(response.tracking_code);
$('#successModal').modal('show');
// Reset and go back
document.getElementById('observationForm').reset();
$('#successModal').on('hidden.bs.modal', function() {
resetToSelection();
});
} else {
let errorText = '{% trans "Failed to submit. Please try again." %}';
if (response.errors && response.errors.length > 0) {
errorText = response.errors.join('\\n');
}
Swal.fire({
icon: 'error',
title: '{% trans "Error" %}',
text: errorText
});
}
},
error: function(xhr) {
let errorMessage = '{% trans "Failed to submit. Please try again." %}';
if (xhr.responseJSON && xhr.responseJSON.errors) {
errorMessage = xhr.responseJSON.errors.join('\\n');
}
Swal.fire({
icon: 'error',
title: '{% trans "Error" %}',
text: errorMessage
});
},
complete: function() {
submitBtn.prop('disabled', false).html(originalText);
}
});
}
function renderInquiryForm(hospitals) {
// Build inquiry form HTML
let hospitalsOptions = '<option value="">{% trans "Select Hospital" %}</option>';
hospitals.forEach(function(hospital) {
hospitalsOptions += `<option value="${hospital.id}">${hospital.name}</option>`;
});
const formHtml = `
<form id="inquiryForm">
{% csrf_token %}
<div class="form-section">
<h3><i class="fas fa-question-circle me-2"></i>{% trans "Inquiry Details" %}</h3>
<p>{% trans "Ask a question or request information. We'll get back to you within 24-48 hours." %}</p>
<div class="row">
<div class="col-md-6">
<div class="form-group">
<label>{% trans "Name" %} <span class="required-mark">*</span></label>
<input type="text" class="form-control" name="name" required placeholder="{% trans 'Your name' %}">
</div>
</div>
<div class="col-md-6">
<div class="form-group">
<label>{% trans "Email Address" %} <span class="required-mark">*</span></label>
<input type="email" class="form-control" name="email" required placeholder="your@email.com">
</div>
</div>
</div>
<div class="row">
<div class="col-md-6">
<div class="form-group">
<label>{% trans "Phone Number" %} <span class="required-mark">*</span></label>
<input type="tel" class="form-control" name="phone" maxlength="20" required placeholder="{% trans 'Your phone number' %}">
</div>
</div>
<div class="col-md-6">
<div class="form-group">
<label>{% trans "Hospital" %} <span class="required-mark">*</span></label>
<select class="form-control" name="hospital" required>
${hospitalsOptions}
</select>
</div>
</div>
</div>
<div class="form-group">
<label>{% trans "Category" %} <span class="required-mark">*</span></label>
<select class="form-control" name="category" required>
<option value="">{% trans "Select Category" %}</option>
<option value="general">{% trans "General Information" %}</option>
<option value="appointment">{% trans "Appointment" %}</option>
<option value="billing">{% trans "Billing" %}</option>
<option value="medical_records">{% trans "Medical Records" %}</option>
<option value="other">{% trans "Other" %}</option>
</select>
</div>
<div class="form-group">
<label>{% trans "Subject" %} <span class="required-mark">*</span></label>
<input type="text" class="form-control" name="subject" maxlength="200" required placeholder="{% trans 'Brief subject of your inquiry' %}">
</div>
<div class="form-group">
<label>{% trans "Message" %} <span class="required-mark">*</span></label>
<textarea class="form-control" name="message" rows="6" required placeholder="{% trans 'Please describe your inquiry in detail...' %}"></textarea>
</div>
<div class="text-center" style="margin-top: 2.5rem;">
<button type="submit" class="btn btn-primary btn-lg" id="inquirySubmitBtn">
<i class="fas fa-paper-plane me-2"></i>{% trans "Submit Inquiry" %}
</button>
</div>
</div>
</form>
`;
$('#formContent').html(formHtml);
// Attach form submission handler
$('#inquiryForm').on('submit', handleInquirySubmit);
showForm();
}
function showForm() {
$('#loadingSpinner').hide();
$('#formContent').fadeIn(300);
}
// ============================================================================
// COMPLAINT FORM FUNCTIONS
// ============================================================================
let complaintAllCategories = [];
let complaintCurrentLanguage = 'en';
// Get complaint description based on current language
function getComplaintDescription(category) {
if (complaintCurrentLanguage === 'ar' && category.description_ar) {
return category.description_ar;
}
return category.description_en || '';
}
// Get complaint category name based on current language
function getComplaintName(category) {
if (complaintCurrentLanguage === 'ar' && category.name_ar) {
return category.name_ar;
}
return category.name_en;
}
// Load complaint categories
function loadComplaintCategories(hospitalId) {
if (!hospitalId) {
// Clear categories if no hospital selected
const categorySelect = $('#id_category');
categorySelect.find('option:not(:first)').remove();
$('#subcategory_container').hide();
$('#subcategory_description').hide();
$('#category_description').hide();
$('#id_subcategory').find('option:not(:first)').remove();
$('#id_subcategory').prop('required', false);
return;
}
$.ajax({
url: '{% url "complaints:api_load_categories" %}',
type: 'GET',
data: { hospital_id: hospitalId },
success: function(response) {
// Store all categories
complaintAllCategories = response.categories;
const categorySelect = $('#id_category');
categorySelect.find('option:not(:first)').remove();
// Only show parent categories (no parent_id)
complaintAllCategories.forEach(function(category) {
if (!category.parent_id) {
categorySelect.append($('<option>', {
value: category.id,
text: getComplaintName(category)
}));
}
});
},
error: function() {
console.error('Failed to load complaint categories');
}
});
}
// Show complaint category description
function showComplaintCategoryDescription(categoryId) {
const category = complaintAllCategories.find(c => c.id === categoryId);
const descriptionDiv = $('#category_description');
const descriptionText = $('#category_description_text');
if (category && getComplaintDescription(category)) {
descriptionText.text(getComplaintDescription(category));
descriptionDiv.show();
} else {
descriptionDiv.hide();
}
}
// Show complaint subcategory description
function showComplaintSubcategoryDescription(subcategoryId) {
const subcategory = complaintAllCategories.find(c => c.id === subcategoryId);
const descriptionDiv = $('#subcategory_description');
const descriptionText = $('#subcategory_description_text');
if (subcategory && getComplaintDescription(subcategory)) {
descriptionText.text(getComplaintDescription(subcategory));
descriptionDiv.show();
} else {
descriptionDiv.hide();
}
}
// Load complaint subcategories based on selected category
function loadComplaintSubcategories(categoryId) {
if (!categoryId) {
$('#subcategory_container').hide();
$('#subcategory_description').hide();
$('#id_subcategory').find('option:not(:first)').remove();
$('#id_subcategory').prop('required', false);
return;
}
const subcategorySelect = $('#id_subcategory');
subcategorySelect.find('option:not(:first)').remove();
// Filter subcategories for this parent category (match parent_id)
complaintAllCategories.forEach(function(category) {
if (category.parent_id == categoryId) {
subcategorySelect.append($('<option>', {
value: category.id,
text: getComplaintName(category)
}));
}
});
if (subcategorySelect.find('option').length > 1) {
$('#subcategory_container').show();
$('#id_subcategory').prop('required', true);
} else {
$('#subcategory_container').hide();
$('#subcategory_description').hide();
$('#id_subcategory').prop('required', false);
}
}
// Initialize complaint form - called when form is loaded via AJAX
function initializeComplaintForm() {
// Detect current language from HTML
const htmlLang = document.documentElement.lang;
if (htmlLang === 'ar') {
complaintCurrentLanguage = 'ar';
}
// Attach event handlers for complaint form
$('#formContent').on('change', '#id_hospital', function() {
const hospitalId = $(this).val();
loadComplaintCategories(hospitalId);
// Clear category and subcategory when hospital changes
$('#id_category').val('');
$('#id_subcategory').val('');
$('#subcategory_container').hide();
$('#subcategory_description').hide();
$('#category_description').hide();
});
$('#formContent').on('change', '#id_category', function() {
const categoryId = $(this).val();
loadComplaintSubcategories(categoryId);
showComplaintCategoryDescription(categoryId);
$('#subcategory_description').hide();
});
$('#formContent').on('change', '#id_subcategory', function() {
const subcategoryId = $(this).val();
showComplaintSubcategoryDescription(subcategoryId);
});
$('#formContent').on('submit', '#public_complaint_form', function(e) {
e.preventDefault();
const submitBtn = $('#submit_btn');
const originalText = submitBtn.html();
submitBtn.prop('disabled', true).html(
'<span class="spinner"></span>{% trans "Submitting..." %}'
);
const formData = new FormData(this);
$.ajax({
url: '{% url "complaints:public_complaint_submit" %}',
type: 'POST',
data: formData,
processData: false,
contentType: false,
headers: {
'X-CSRFToken': getCSRFToken()
},
success: function(response) {
if (response.success) {
$('#referenceNumber').text(response.reference_number);
$('#successModal').modal('show');
// Reset form
document.getElementById('public_complaint_form').reset();
$('#successModal').on('hidden.bs.modal', function() {
resetToSelection();
});
} else {
Swal.fire({
icon: 'error',
title: '{% trans "Error" %}',
text: response.message || '{% trans "Failed to submit complaint. Please try again." %}'
});
}
},
error: function(xhr) {
let errorMessage = '{% trans "Failed to submit complaint. Please try again." %}';
if (xhr.responseJSON && xhr.responseJSON.errors) {
errorMessage = xhr.responseJSON.errors.join('\\n');
}
Swal.fire({
icon: 'error',
title: '{% trans "Error" %}',
text: errorMessage
});
},
complete: function() {
submitBtn.prop('disabled', false).html(originalText);
}
});
});
}
function handleInquirySubmit(e) {
e.preventDefault();
const submitBtn = $('#inquirySubmitBtn');
const originalText = submitBtn.html();
submitBtn.prop('disabled', true).html(
'<span class="spinner"></span>{% trans "Submitting..." %}'
);
const formData = new FormData(this);
$.ajax({
url: '{% url "core:public_inquiry_submit" %}',
type: 'POST',
data: formData,
processData: false,
contentType: false,
headers: {
'X-CSRFToken': getCSRFToken()
},
success: function(response) {
if (response.success) {
$('#referenceNumber').text(response.reference_number);
$('#successModal').modal('show');
// Reset and go back
document.getElementById('inquiryForm').reset();
$('#successModal').on('hidden.bs.modal', function() {
resetToSelection();
});
} else {
Swal.fire({
icon: 'error',
title: '{% trans "Error" %}',
text: response.message || '{% trans "Failed to submit. Please try again." %}'
});
}
},
error: function(xhr) {
let errorMessage = '{% trans "Failed to submit. Please try again." %}';
if (xhr.responseJSON && xhr.responseJSON.errors) {
errorMessage = xhr.responseJSON.errors.join('\\n');
}
Swal.fire({
icon: 'error',
title: '{% trans "Error" %}',
text: errorMessage
});
},
complete: function() {
submitBtn.prop('disabled', false).html(originalText);
}
});
}
function getCSRFToken() {
const cookieValue = document.cookie
.split('; ')
.find(row => row.startsWith('csrftoken='))
?.split('=')[1];
return cookieValue || $('[name="csrfmiddlewaretoken"]').val();
}
// Global function to reset to selection
window.resetToSelection = function() {
$('#publicFormContainer').fadeOut(300);
setTimeout(function() {
$('#formContent').empty();
$('#selectionCards').slideDown(300);
}, 300);
currentFormType = null;
};
});
</script>
{% endblock %}