949 lines
35 KiB
HTML
949 lines
35 KiB
HTML
{% extends "layouts/public_base.html" %}
|
|
{% load i18n %}
|
|
|
|
{% block title %}{% trans "Submit Feedback" %}{% endblock %}
|
|
|
|
{% block extra_css %}
|
|
<style>
|
|
.public-submit-container {
|
|
max-width: 1200px;
|
|
margin: 0 auto;
|
|
padding: 2rem 0;
|
|
}
|
|
|
|
.header-section {
|
|
text-align: center;
|
|
margin-bottom: 3rem;
|
|
}
|
|
|
|
.header-section h1 {
|
|
color: #2c3e50;
|
|
font-size: 2.5rem;
|
|
font-weight: 700;
|
|
margin-bottom: 1rem;
|
|
}
|
|
|
|
.header-section p {
|
|
color: #6c757d;
|
|
font-size: 1.1rem;
|
|
}
|
|
|
|
.selection-cards {
|
|
display: grid;
|
|
grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
|
|
gap: 2rem;
|
|
margin-bottom: 3rem;
|
|
}
|
|
|
|
.selection-card {
|
|
background: white;
|
|
border-radius: 12px;
|
|
padding: 2.5rem;
|
|
text-align: center;
|
|
cursor: pointer;
|
|
transition: all 0.3s ease;
|
|
border: 2px solid transparent;
|
|
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
|
|
}
|
|
|
|
.selection-card:hover {
|
|
transform: translateY(-5px);
|
|
box-shadow: 0 8px 15px rgba(0, 0, 0, 0.15);
|
|
border-color: #3498db;
|
|
}
|
|
|
|
.card-icon {
|
|
font-size: 4rem;
|
|
margin-bottom: 1.5rem;
|
|
}
|
|
|
|
.card-complaint .card-icon { color: #e74c3c; }
|
|
.card-observation .card-icon { color: #9b59b6; }
|
|
.card-inquiry .card-icon { color: #3498db; }
|
|
|
|
.card-title {
|
|
font-size: 1.5rem;
|
|
font-weight: 600;
|
|
color: #2c3e50;
|
|
margin-bottom: 1rem;
|
|
}
|
|
|
|
.card-description {
|
|
color: #6c757d;
|
|
line-height: 1.6;
|
|
}
|
|
|
|
.form-container {
|
|
display: none;
|
|
background: white;
|
|
border-radius: 12px;
|
|
padding: 2rem;
|
|
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
|
|
}
|
|
|
|
.form-container.active {
|
|
display: block;
|
|
animation: fadeIn 0.3s ease-in;
|
|
}
|
|
|
|
@keyframes fadeIn {
|
|
from { opacity: 0; transform: translateY(10px); }
|
|
to { opacity: 1; transform: translateY(0); }
|
|
}
|
|
|
|
.back-button {
|
|
margin-bottom: 1.5rem;
|
|
}
|
|
|
|
.required-mark {
|
|
color: #dc3545;
|
|
}
|
|
|
|
.form-section {
|
|
background: white;
|
|
border-radius: 8px;
|
|
padding: 2rem;
|
|
margin-bottom: 2rem;
|
|
}
|
|
|
|
.form-section h3 {
|
|
color: #2c3e50;
|
|
margin-bottom: 1.5rem;
|
|
padding-bottom: 0.5rem;
|
|
border-bottom: 2px solid #3498db;
|
|
}
|
|
|
|
.track-links {
|
|
text-align: center;
|
|
margin-top: 3rem;
|
|
padding-top: 2rem;
|
|
border-top: 1px solid #dee2e6;
|
|
}
|
|
|
|
.track-links a {
|
|
color: #3498db;
|
|
text-decoration: none;
|
|
margin: 0 1rem;
|
|
display: inline-block;
|
|
}
|
|
|
|
.track-links a:hover {
|
|
text-decoration: underline;
|
|
}
|
|
|
|
.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 1s ease-in-out 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: 3rem;
|
|
}
|
|
|
|
.loading-spinner i {
|
|
font-size: 3rem;
|
|
color: #3498db;
|
|
animation: spin 1s linear infinite;
|
|
}
|
|
</style>
|
|
{% endblock %}
|
|
|
|
{% block content %}
|
|
<div class="public-submit-container">
|
|
<!-- Header -->
|
|
<div class="header-section">
|
|
<h1><i class="fas fa-comments"></i> {% trans "We Value Your Feedback" %}</h1>
|
|
<p>{% trans "Choose how you'd like to reach us and we'll respond promptly" %}</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 issues with services, staff, or facilities. We take your 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 "Report incidents or issues anonymously. Help us improve safety and quality by sharing what you've noticed." %}
|
|
</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 "Ask questions or request information. Need help understanding services, appointments, or policies?" %}
|
|
</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"></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 class="mt-3">{% trans "Loading form..." %}</p>
|
|
</div>
|
|
|
|
<!-- Form Content (loaded via AJAX) -->
|
|
<div id="formContent"></div>
|
|
</div>
|
|
|
|
<!-- Track Links -->
|
|
<div class="track-links">
|
|
<p class="text-muted">{% 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: 3rem;">
|
|
<i class="fas fa-check-circle" style="font-size: 5rem; color: #28a745; margin-bottom: 1.5rem;"></i>
|
|
<h3 style="margin-bottom: 1rem;">{% trans "Submitted Successfully!" %}</h3>
|
|
<p class="lead" style="margin-bottom: 1rem;">
|
|
{% trans "Your submission has been received and is being processed." %}
|
|
</p>
|
|
<p>
|
|
<strong>{% trans "Reference Number:" %}</strong>
|
|
<span id="referenceNumber" style="font-size: 1.5rem; color: #3498db;"></span>
|
|
</p>
|
|
<p class="text-muted">
|
|
{% 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 templateUrl = '';
|
|
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"></i> {% trans "Report an Observation" %}</h3>
|
|
<p class="text-muted">{% trans "Help us improve by reporting issues you notice. You can submit this anonymously." %}</p>
|
|
|
|
<!-- Category -->
|
|
<div class="form-group">
|
|
<label>{% trans "Category" %} <span class="text-muted">({% trans "optional" %})</span></label>
|
|
<select class="form-control" name="category">
|
|
${categoriesOptions}
|
|
</select>
|
|
</div>
|
|
|
|
<!-- Severity -->
|
|
<div class="form-group mt-4">
|
|
<label>{% trans "Severity" %} <span class="required-mark">*</span></label>
|
|
<div class="row g-2 mt-1">
|
|
<div class="col-6 col-md-3">
|
|
<div class="severity-option severity-low p-3 text-center border rounded cursor-pointer" data-value="low">
|
|
<i class="fas fa-info-circle text-success"></i>
|
|
<div class="small mt-1">{% trans "Low" %}</div>
|
|
</div>
|
|
</div>
|
|
<div class="col-6 col-md-3">
|
|
<div class="severity-option severity-medium p-3 text-center border rounded cursor-pointer selected" data-value="medium">
|
|
<i class="fas fa-exclamation-circle text-warning"></i>
|
|
<div class="small mt-1">{% trans "Medium" %}</div>
|
|
</div>
|
|
</div>
|
|
<div class="col-6 col-md-3">
|
|
<div class="severity-option severity-high p-3 text-center border rounded cursor-pointer" data-value="high">
|
|
<i class="fas fa-exclamation-triangle text-danger"></i>
|
|
<div class="small mt-1">{% trans "High" %}</div>
|
|
</div>
|
|
</div>
|
|
<div class="col-6 col-md-3">
|
|
<div class="severity-option severity-critical p-3 text-center border rounded cursor-pointer" data-value="critical">
|
|
<i class="fas fa-exclamation-circle text-dark"></i>
|
|
<div class="small mt-1">{% trans "Critical" %}</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<input type="hidden" name="severity" id="severityInput" value="medium">
|
|
</div>
|
|
|
|
<!-- Title -->
|
|
<div class="form-group mt-4">
|
|
<label>{% trans "Title" %} <span class="text-muted">({% trans "optional" %})</span></label>
|
|
<input type="text" class="form-control" name="title" maxlength="200">
|
|
</div>
|
|
|
|
<!-- Description -->
|
|
<div class="form-group mt-4">
|
|
<label>{% trans "Description" %} <span class="required-mark">*</span></label>
|
|
<textarea class="form-control" name="description" rows="5" required></textarea>
|
|
<small class="text-muted">{% trans "Please describe what you observed in detail." %}</small>
|
|
</div>
|
|
|
|
<!-- Location -->
|
|
<div class="form-group mt-4">
|
|
<label>{% trans "Location" %} <span class="text-muted">({% trans "optional" %})</span></label>
|
|
<input type="text" class="form-control" name="location_text" maxlength="200">
|
|
</div>
|
|
|
|
<!-- Incident Date/Time -->
|
|
<div class="form-group mt-4">
|
|
<label>{% trans "When did this occur?" %}</label>
|
|
<input type="datetime-local" class="form-control" name="incident_datetime">
|
|
</div>
|
|
|
|
<!-- Attachments -->
|
|
<div class="form-group mt-4">
|
|
<label>{% trans "Attachments" %} <span class="text-muted">({% trans "optional" %})</span></label>
|
|
<div class="file-upload-area border-2 border-dashed rounded p-4 text-center cursor-pointer" onclick="document.getElementById('observationAttachments').click()">
|
|
<i class="fas fa-cloud-upload-alt fa-2x text-primary"></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>
|
|
|
|
<!-- Reporter Information (Optional) -->
|
|
<div class="form-group mt-4">
|
|
<label>{% trans "Your Information" %} <span class="text-muted">({% trans "optional" %})</span></label>
|
|
<p class="text-muted small">{% 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">
|
|
</div>
|
|
</div>
|
|
<div class="col-md-6">
|
|
<div class="form-group">
|
|
<label>{% trans "Name" %}</label>
|
|
<input type="text" class="form-control" name="reporter_name">
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="row mt-3">
|
|
<div class="col-md-6">
|
|
<div class="form-group">
|
|
<label>{% trans "Phone" %}</label>
|
|
<input type="tel" class="form-control" name="reporter_phone">
|
|
</div>
|
|
</div>
|
|
<div class="col-md-6">
|
|
<div class="form-group">
|
|
<label>{% trans "Email" %}</label>
|
|
<input type="email" class="form-control" name="reporter_email">
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Submit -->
|
|
<div class="text-center mt-4">
|
|
<button type="submit" class="btn btn-primary btn-lg" id="observationSubmitBtn">
|
|
<i class="fas fa-paper-plane"></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 border-primary bg-light');
|
|
$(this).addClass('selected border-primary bg-light');
|
|
$('#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';
|
|
li.innerHTML = '<i class="fas fa-file me-1"></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 {
|
|
Swal.fire({
|
|
icon: 'error',
|
|
title: '{% trans "Error" %}',
|
|
text: response.errors ? response.errors.join('\\n') : '{% 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 renderInquiryForm(hospitals) {
|
|
// Build the 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"></i> {% trans "Inquiry Details" %}</h3>
|
|
<p class="text-muted">{% trans "Ask a question or request information. We'll get back to you within 24-48 hours." %}</p>
|
|
|
|
<div class="row mt-4">
|
|
<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>
|
|
</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>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="row mt-3">
|
|
<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>
|
|
</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 mt-4">
|
|
<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 mt-3">
|
|
<label>{% trans "Subject" %} <span class="required-mark">*</span></label>
|
|
<input type="text" class="form-control" name="subject" maxlength="200" required>
|
|
</div>
|
|
|
|
<div class="form-group mt-3">
|
|
<label>{% trans "Message" %} <span class="required-mark">*</span></label>
|
|
<textarea class="form-control" name="message" rows="6" required></textarea>
|
|
</div>
|
|
|
|
<div class="text-center mt-4">
|
|
<button type="submit" class="btn btn-primary btn-lg" id="inquirySubmitBtn">
|
|
<i class="fas fa-paper-plane"></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() {
|
|
$.ajax({
|
|
url: '{% url "complaints:api_load_categories" %}',
|
|
type: 'GET',
|
|
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';
|
|
}
|
|
|
|
// Load categories immediately
|
|
loadComplaintCategories();
|
|
|
|
// Attach event handlers for complaint form
|
|
$('#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 %}
|