HH/templates/complaints/public_complaint_form.html
2026-01-06 18:26:17 +03:00

519 lines
17 KiB
HTML

{% extends "layouts/public_base.html" %}
{% load i18n %}
{% block title %}{% trans "Submit a Complaint" %}{% endblock %}
{% block extra_css %}
<style>
.complaint-form {
max-width: 900px;
margin: 0 auto;
padding: 2rem 0;
}
.form-section {
background: white;
border-radius: 8px;
padding: 2rem;
margin-bottom: 2rem;
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
}
.form-section h3 {
color: #2c3e50;
margin-bottom: 1.5rem;
padding-bottom: 0.5rem;
border-bottom: 2px solid #3498db;
}
.alert-box {
padding: 1rem;
border-radius: 8px;
margin-bottom: 2rem;
}
.alert-box.success {
background-color: #d4edda;
color: #155724;
border: 1px solid #c3e6cb;
}
.alert-box.info {
background-color: #cce5ff;
color: #004085;
border: 1px solid #b8daff;
}
.required-mark {
color: #dc3545;
}
.btn-submit {
background: linear-gradient(135deg, #3498db 0%, #2980b9 100%);
border: none;
padding: 1rem 2rem;
border-radius: 8px;
color: white;
font-weight: 600;
font-size: 1.1rem;
cursor: pointer;
transition: all 0.3s;
}
.btn-submit:hover {
transform: translateY(-2px);
box-shadow: 0 4px 8px rgba(52, 152, 219, 0.3);
}
.btn-submit:disabled {
background: #6c757d;
cursor: not-allowed;
transform: none;
box-shadow: none;
}
.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;
}
.category-description {
background-color: #f8f9fa;
border-left: 4px solid #3498db;
padding: 1rem;
margin-top: 0.5rem;
border-radius: 4px;
font-size: 0.95rem;
color: #495057;
}
[dir="rtl"] .category-description {
border-left: none;
border-right: 4px solid #3498db;
}
.description-title {
font-weight: 600;
color: #2c3e50;
margin-bottom: 0.5rem;
}
</style>
{% endblock %}
{% block content %}
<div class="complaint-form">
<div class="alert-box info">
<h4 style="margin-top: 0;">
<i class="fas fa-info-circle"></i> {% trans "About This Form" %}
</h4>
<p style="margin-bottom: 0;">
{% trans "Use this form to submit a complaint about your experience at one of our hospitals. We will review your complaint and get back to you as soon as possible." %}
</p>
</div>
<form id="public_complaint_form" method="post">
{% csrf_token %}
<!-- Contact Information Section -->
<div class="form-section">
<h3><i class="fas fa-user"></i> {% trans "Contact Information" %}</h3>
<div class="form-group">
<label for="id_name">
{% trans "Name" %} <span class="required-mark">*</span>
</label>
<input type="text"
class="form-control"
id="id_name"
name="name"
maxlength="200"
placeholder="{% trans 'Your full name' %}"
required>
<small class="form-text text-muted">
{% trans "Please provide your full name." %}
</small>
</div>
<div class="row mt-3">
<div class="col-md-6">
<div class="form-group">
<label for="id_email">
{% trans "Email Address" %} <span class="required-mark">*</span>
</label>
<input type="email"
class="form-control"
id="id_email"
name="email"
placeholder="your@email.com"
required>
<small class="form-text text-muted">
{% trans "We will use this to contact you about your complaint." %}
</small>
</div>
</div>
<div class="col-md-6">
<div class="form-group">
<label for="id_phone">
{% trans "Phone Number" %} <span class="required-mark">*</span>
</label>
<input type="tel"
class="form-control"
id="id_phone"
name="phone"
maxlength="20"
placeholder="{% trans 'Your phone number' %}"
required>
<small class="form-text text-muted">
{% trans "We may contact you by phone if needed." %}
</small>
</div>
</div>
</div>
</div>
<!-- Complaint Details Section -->
<div class="form-section">
<h3><i class="fas fa-file-alt"></i> {% trans "Complaint Details" %}</h3>
<div class="form-group">
<label for="id_hospital">
{% trans "Hospital" %} <span class="required-mark">*</span>
</label>
<select class="form-control"
id="id_hospital"
name="hospital"
required>
<option value="">{% trans "Select Hospital" %}</option>
{% for hospital in hospitals %}
<option value="{{ hospital.id }}">{{ hospital.name }}</option>
{% endfor %}
</select>
</div>
<div class="form-group mt-3">
<label for="id_category">
{% trans "Category" %} <span class="required-mark">*</span>
</label>
<select class="form-control"
id="id_category"
name="category"
required>
<option value="">{% trans "Select Category" %}</option>
</select>
<small class="form-text text-muted">
{% trans "Select the category that best describes your complaint." %}
</small>
<div id="category_description" class="category-description" style="display: none;">
<div class="description-title">{% trans "About this category:" %}</div>
<span id="category_description_text"></span>
</div>
</div>
<div class="form-group mt-3" id="subcategory_container" style="display: none;">
<label for="id_subcategory">
{% trans "Subcategory" %} <span class="required-mark">*</span>
</label>
<select class="form-control"
id="id_subcategory"
name="subcategory"
required>
<option value="">{% trans "Select Subcategory" %}</option>
</select>
<small class="form-text text-muted">
{% trans "Select the specific subcategory within the chosen category." %}
</small>
<div id="subcategory_description" class="category-description" style="display: none;">
<div class="description-title">{% trans "About this subcategory:" %}</div>
<span id="subcategory_description_text"></span>
</div>
</div>
<div class="form-group mt-3">
<label for="id_description">
{% trans "Complaint Description" %} <span class="required-mark">*</span>
</label>
<textarea class="form-control"
id="id_description"
name="description"
rows="6"
placeholder="{% trans 'Please describe your complaint in detail. Include dates, names of staff involved, and any other relevant information.' %}"
required></textarea>
</div>
</div>
<!-- Submit Section -->
<div class="form-section">
<div class="alert-box info">
<p style="margin-bottom: 0;">
<i class="fas fa-clock"></i>
<strong>{% trans "Response Time:" %}</strong>
{% trans "We typically respond to complaints within 24-48 hours depending on severity." %}
</p>
</div>
<div class="text-center">
<button type="submit" class="btn btn-submit btn-lg" id="submit_btn">
<i class="fas fa-paper-plane"></i> {% trans "Submit Complaint" %}
</button>
</div>
</div>
</form>
</div>
<!-- Modal for success -->
<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 "Complaint Submitted Successfully!" %}</h3>
<p class="lead" style="margin-bottom: 1rem;">
{% trans "Your complaint has been received and is being reviewed." %}
</p>
<p>
<strong>{% trans "Reference Number:" %}</strong>
<span id="complaint_reference" style="font-size: 1.5rem; color: #3498db;"></span>
</p>
<p class="text-muted">
{% trans "Please save this reference number for your records." %}
</p>
<a href="{% url 'complaints:public_complaint_submit' %}" class="btn btn-primary">
{% trans "Submit Another Complaint" %}
</a>
</div>
</div>
</div>
</div>
{% endblock %}
{% block extra_js %}
<script src="https://cdn.jsdelivr.net/npm/sweetalert2@11"></script>
<script>
// Store all categories data globally for easy access
let allCategories = [];
let currentLanguage = 'en';
// Get CSRF token
function getCSRFToken() {
// Try to get from cookie first
const cookieValue = document.cookie
.split('; ')
.find(row => row.startsWith('csrftoken='))
?.split('=')[1];
if (cookieValue) {
return cookieValue;
}
// Fallback to hidden input
return $('[name="csrfmiddlewaretoken"]').val();
}
// Get description based on current language
function getDescription(category) {
if (currentLanguage === 'ar' && category.description_ar) {
return category.description_ar;
}
return category.description_en || '';
}
// Get name based on current language
function getName(category) {
if (currentLanguage === 'ar' && category.name_ar) {
return category.name_ar;
}
return category.name_en;
}
// Load categories
function loadCategories() {
$.ajax({
url: '{% url "complaints:api_load_categories" %}',
type: 'GET',
success: function(response) {
// Store all categories
allCategories = response.categories;
const categorySelect = $('#id_category');
categorySelect.find('option:not(:first)').remove();
// Only show parent categories (no parent_id)
allCategories.forEach(function(category) {
if (!category.parent_id) {
categorySelect.append($('<option>', {
value: category.id,
text: getName(category)
}));
}
});
},
error: function() {
console.error('Failed to load categories');
}
});
}
// Show category description
function showCategoryDescription(categoryId) {
const category = allCategories.find(c => c.id === categoryId);
const descriptionDiv = $('#category_description');
const descriptionText = $('#category_description_text');
if (category && getDescription(category)) {
descriptionText.text(getDescription(category));
descriptionDiv.show();
} else {
descriptionDiv.hide();
}
}
// Show subcategory description
function showSubcategoryDescription(subcategoryId) {
const subcategory = allCategories.find(c => c.id === subcategoryId);
const descriptionDiv = $('#subcategory_description');
const descriptionText = $('#subcategory_description_text');
if (subcategory && getDescription(subcategory)) {
descriptionText.text(getDescription(subcategory));
descriptionDiv.show();
} else {
descriptionDiv.hide();
}
}
// Load subcategories based on selected category
function loadSubcategories(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)
allCategories.forEach(function(category) {
if (category.parent_id == categoryId) {
subcategorySelect.append($('<option>', {
value: category.id,
text: getName(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
function initializeComplaintForm() {
// Detect current language from HTML
const htmlLang = document.documentElement.lang;
if (htmlLang === 'ar') {
currentLanguage = 'ar';
}
// Load categories immediately
loadCategories();
}
// Handle category change
$('#id_category').on('change', function() {
const categoryId = $(this).val();
loadSubcategories(categoryId);
showCategoryDescription(categoryId);
$('#subcategory_description').hide(); // Hide subcategory description when category changes
});
// Handle subcategory change
$('#id_subcategory').on('change', function() {
const subcategoryId = $(this).val();
showSubcategoryDescription(subcategoryId);
});
// Form submission
$('#public_complaint_form').on('submit', 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) {
$('#complaint_reference').text(response.reference_number);
$('#successModal').modal('show');
// Reset form
document.getElementById('public_complaint_form').reset();
} 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);
}
});
});
// Initialize form on page load
initializeComplaintForm();
});
</script>
{% endblock %}