488 lines
14 KiB
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 %}
|