HH/templates/notifications/settings.html

488 lines
14 KiB
HTML

{% extends 'layouts/base.html' %}
{% load i18n static %}
{% load notification_tags %}
{% block title %}{% trans "Notification Settings" %} - {{ hospital.name }}{% endblock %}
{% block extra_css %}
<style>
.notification-category {
border-radius: 12px;
border: 1px solid #e9ecef;
margin-bottom: 1.5rem;
overflow: hidden;
transition: all 0.3s ease;
}
.notification-category:hover {
box-shadow: 0 4px 20px rgba(0,0,0,0.08);
}
.category-header {
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
color: white;
padding: 1rem 1.5rem;
display: flex;
align-items: center;
gap: 0.75rem;
}
.category-header i {
font-size: 1.5rem;
}
.category-header h5 {
margin: 0;
font-weight: 600;
}
.category-description {
padding: 0.75rem 1.5rem;
background: #f8f9fa;
border-bottom: 1px solid #e9ecef;
color: #6c757d;
font-size: 0.9rem;
}
.notification-event {
padding: 1.25rem 1.5rem;
border-bottom: 1px solid #f0f0f0;
display: flex;
align-items: center;
justify-content: space-between;
flex-wrap: wrap;
gap: 1rem;
}
.notification-event:last-child {
border-bottom: none;
}
.notification-event:hover {
background: #fafbfc;
}
.event-info {
flex: 1;
min-width: 250px;
}
.event-info h6 {
margin: 0 0 0.25rem 0;
font-weight: 600;
color: #333;
display: flex;
align-items: center;
gap: 0.5rem;
}
.event-info p {
margin: 0;
font-size: 0.85rem;
color: #6c757d;
}
.event-toggles {
display: flex;
gap: 1.5rem;
align-items: center;
}
.channel-toggle {
display: flex;
flex-direction: column;
align-items: center;
gap: 0.25rem;
}
.channel-toggle label {
font-size: 0.75rem;
color: #6c757d;
text-transform: uppercase;
letter-spacing: 0.5px;
}
.form-check-input {
width: 2.5rem;
height: 1.25rem;
cursor: pointer;
}
.form-check-input:checked {
background-color: #667eea;
border-color: #667eea;
}
.master-switch-card {
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
color: white;
border-radius: 12px;
padding: 1.5rem;
margin-bottom: 2rem;
}
.master-switch-card .form-check-input {
background-color: rgba(255,255,255,0.3);
border-color: rgba(255,255,255,0.5);
}
.master-switch-card .form-check-input:checked {
background-color: #fff;
border-color: #fff;
}
.master-switch-card .form-check-input:checked::after {
background-color: #667eea;
}
.quiet-hours-card {
background: #fff;
border: 1px solid #e9ecef;
border-radius: 12px;
padding: 1.5rem;
margin-bottom: 2rem;
}
.change-log {
background: #fff;
border: 1px solid #e9ecef;
border-radius: 12px;
padding: 1.5rem;
}
.change-log-item {
padding: 0.75rem 0;
border-bottom: 1px solid #f0f0f0;
display: flex;
align-items: center;
gap: 1rem;
}
.change-log-item:last-child {
border-bottom: none;
}
.change-indicator {
width: 8px;
height: 8px;
border-radius: 50%;
}
.change-indicator.enabled {
background: #28a745;
}
.change-indicator.disabled {
background: #dc3545;
}
.test-notification-card {
background: #f8f9fa;
border: 1px dashed #dee2e6;
border-radius: 12px;
padding: 1.5rem;
margin-top: 2rem;
}
.channel-icon {
font-size: 1.1rem;
}
.channel-icon.email { color: #ea4335; }
.channel-icon.sms { color: #34a853; }
.channel-icon.whatsapp { color: #25d366; }
.settings-saved-toast {
position: fixed;
top: 20px;
right: 20px;
z-index: 1050;
min-width: 250px;
}
</style>
{% endblock %}
{% block content %}
<div class="container-fluid py-4">
<!-- Header -->
<div class="d-flex justify-content-between align-items-center mb-4">
<div>
<h4 class="mb-1">
<i class="bi bi-bell-gear me-2"></i>{% trans "Notification Settings" %}
</h4>
<p class="text-muted mb-0">{{ hospital.name }}</p>
</div>
<div class="d-flex gap-2">
<a href="{% url 'notifications:settings' %}" class="btn btn-outline-secondary">
<i class="bi bi-arrow-clockwise me-1"></i>{% trans "Refresh" %}
</a>
<button type="button" class="btn btn-primary" data-bs-toggle="modal" data-bs-target="#testModal">
<i class="bi bi-send me-1"></i>{% trans "Test Notification" %}
</button>
</div>
</div>
<!-- Master Switch -->
<div class="master-switch-card">
<div class="d-flex justify-content-between align-items-center">
<div>
<h5 class="mb-1"><i class="bi bi-power me-2"></i>{% trans "Master Switch" %}</h5>
<p class="mb-0 opacity-75">{% trans "Enable or disable all notifications for this hospital" %}</p>
</div>
<form method="post" action="{% url 'notifications:settings_update_with_hospital' hospital_id=hospital.id %}">
{% csrf_token %}
<div class="form-check form-switch">
<input class="form-check-input" type="checkbox" name="notifications_enabled"
id="masterSwitch" {% if settings.notifications_enabled %}checked{% endif %}
onchange="this.form.submit()" style="transform: scale(1.3);">
<label class="form-check-label ms-2" for="masterSwitch">
{{ settings.notifications_enabled|yesno:"Enabled,Disabled" }}
</label>
</div>
</form>
</div>
</div>
{% if settings.notifications_enabled %}
<!-- Notification Categories -->
{% for category in categories %}
<div class="notification-category">
<div class="category-header">
<i class="bi {{ category.icon }}"></i>
<div>
<h5>{{ category.name }}</h5>
</div>
</div>
<div class="category-description">
{{ category.description }}
</div>
<div class="notification-events">
{% for event in category.events %}
<div class="notification-event" data-event="{{ event.key }}">
<div class="event-info">
<h6>
<i class="bi {{ event.icon }} text-primary"></i>
{{ event.name }}
</h6>
<p>{{ event.description }}</p>
</div>
<div class="event-toggles">
{% for channel in event.channels %}
{% with field_name=event.key|add:"_"|add:channel %}
<div class="channel-toggle">
<i class="bi
{% if channel == 'email' %}bi-envelope channel-icon email
{% elif channel == 'sms' %}bi-chat-text channel-icon sms
{% else %}bi-whatsapp channel-icon whatsapp{% endif %}"></i>
<div class="form-check form-switch">
<input class="form-check-input toggle-setting" type="checkbox"
data-field="{{ field_name }}"
{% if settings|get_attr:field_name %}checked{% endif %}
id="{{ field_name }}">
</div>
</div>
{% endwith %}
{% endfor %}
</div>
</div>
{% endfor %}
{% if category.extra_settings %}
{% for extra in category.extra_settings %}
<div class="notification-event bg-light">
<div class="event-info">
<h6>
<i class="bi {{ extra.icon }} text-secondary"></i>
{{ extra.name }}
</h6>
<p>{{ extra.description }}</p>
</div>
<div class="event-toggles">
<div class="form-check form-switch">
<input class="form-check-input toggle-setting" type="checkbox"
data-field="{{ extra.key }}"
{% if settings|get_attr:extra.key %}checked{% endif %}
id="{{ extra.key }}">
</div>
</div>
</div>
{% endfor %}
{% endif %}
</div>
</div>
{% endfor %}
<!-- Quiet Hours -->
<div class="quiet-hours-card">
<h6 class="mb-3"><i class="bi bi-moon-stars me-2"></i>{% trans "Quiet Hours" %}</h6>
<p class="text-muted small mb-3">
{% trans "During quiet hours, SMS and WhatsApp notifications will be queued and sent after the quiet period ends." %}
</p>
<form method="post" action="{% url 'notifications:update_quiet_hours_with_hospital' hospital_id=hospital.id %}">
{% csrf_token %}
<div class="row g-3 align-items-end">
<div class="col-md-3">
<div class="form-check form-switch">
<input class="form-check-input" type="checkbox" name="quiet_hours_enabled"
id="quietHoursEnabled" {% if settings.quiet_hours_enabled %}checked{% endif %}>
<label class="form-check-label" for="quietHoursEnabled">
{% trans "Enable Quiet Hours" %}
</label>
</div>
</div>
<div class="col-md-3">
<label class="form-label">{% trans "Start Time" %}</label>
<input type="time" name="quiet_hours_start" class="form-control"
value="{{ settings.quiet_hours_start|time:'H:i' }}" required>
</div>
<div class="col-md-3">
<label class="form-label">{% trans "End Time" %}</label>
<input type="time" name="quiet_hours_end" class="form-control"
value="{{ settings.quiet_hours_end|time:'H:i' }}" required>
</div>
<div class="col-md-3">
<button type="submit" class="btn btn-primary w-100">
{% trans "Save Quiet Hours" %}
</button>
</div>
</div>
</form>
</div>
{% else %}
<!-- Notifications Disabled Message -->
<div class="text-center py-5">
<i class="bi bi-bell-slash display-1 text-muted mb-3"></i>
<h5 class="text-muted">{% trans "Notifications are currently disabled" %}</h5>
<p class="text-muted">{% trans "Enable the master switch above to configure notification settings." %}</p>
</div>
{% endif %}
<!-- Change Log -->
<div class="change-log mt-4">
<h6 class="mb-3"><i class="bi bi-clock-history me-2"></i>{% trans "Recent Changes" %}</h6>
{% if change_logs %}
{% for log in change_logs %}
<div class="change-log-item">
<div class="change-indicator {% if log.new_value %}enabled{% else %}disabled{% endif %}"></div>
<div class="flex-grow-1">
<small class="text-muted">{{ log.created_at|date:"M d, Y H:i" }}</small>
<div>
<strong>{{ log.changed_by.get_full_name|default:log.changed_by.email }}</strong>
{{ log.new_value|yesno:"enabled,disabled" }} <code>{{ log.field_name }}</code>
</div>
</div>
</div>
{% endfor %}
{% else %}
<p class="text-muted mb-0">{% trans "No recent changes" %}</p>
{% endif %}
</div>
</div>
<!-- Test Notification Modal -->
<div class="modal fade" id="testModal" tabindex="-1">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title">{% trans "Send Test Notification" %}</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
</div>
<form method="post" action="{% url 'notifications:test_notification_with_hospital' hospital_id=hospital.id %}">
{% csrf_token %}
<div class="modal-body">
<div class="mb-3">
<label class="form-label">{% trans "Channel" %}</label>
<select name="channel" class="form-select" id="testChannel">
<option value="email">{% trans "Email" %}</option>
<option value="sms">{% trans "SMS" %}</option>
</select>
</div>
<div class="mb-3" id="phoneField" style="display: none;">
<label class="form-label">{% trans "Phone Number" %}</label>
<input type="tel" name="test_phone" class="form-control" placeholder="+966501234567">
</div>
<div class="alert alert-info">
<i class="bi bi-info-circle me-1"></i>
{% trans "A test notification will be sent to verify your settings." %}
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">{% trans "Cancel" %}</button>
<button type="submit" class="btn btn-primary">{% trans "Send Test" %}</button>
</div>
</form>
</div>
</div>
</div>
<!-- Success Toast -->
<div class="toast align-items-center text-white bg-success settings-saved-toast" role="alert" id="successToast">
<div class="d-flex">
<div class="toast-body">
<i class="bi bi-check-circle me-2"></i>{% trans "Setting saved successfully!" %}
</div>
<button type="button" class="btn-close btn-close-white me-2 m-auto" data-bs-dismiss="toast"></button>
</div>
</div>
{% endblock %}
{% block extra_js %}
<script>
document.addEventListener('DOMContentLoaded', function() {
// Handle toggle switches
const toggles = document.querySelectorAll('.toggle-setting');
const successToast = new bootstrap.Toast(document.getElementById('successToast'));
toggles.forEach(function(toggle) {
toggle.addEventListener('change', function() {
const field = this.dataset.field;
const value = this.checked;
// Send AJAX request
fetch('{% url "notifications:settings_update_with_hospital" hospital_id=hospital.id %}', {
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
'X-CSRFToken': '{{ csrf_token }}',
'X-Requested-With': 'XMLHttpRequest'
},
body: 'field=' + encodeURIComponent(field) + '&value=' + value
})
.then(response => response.json())
.then(data => {
if (data.success) {
successToast.show();
} else {
// Revert toggle on error
toggle.checked = !value;
alert('{% trans "Failed to update setting" %}');
}
})
.catch(error => {
console.error('Error:', error);
toggle.checked = !value;
alert('{% trans "Failed to update setting" %}');
});
});
});
// Test notification modal - show/hide phone field
const testChannel = document.getElementById('testChannel');
const phoneField = document.getElementById('phoneField');
testChannel.addEventListener('change', function() {
if (this.value === 'sms') {
phoneField.style.display = 'block';
} else {
phoneField.style.display = 'none';
}
});
});
</script>
{% endblock %}