hospital-management/templates/core/notification_form.html
2025-08-12 13:33:25 +03:00

724 lines
38 KiB
HTML

{% extends "base.html" %}
{% load static %}
{% block title %}{% if object %}Edit Notification - {{ object.title }}{% else %}Create New Notification{% endif %}{% endblock %}
{% block content %}
<div class="container-fluid">
<!-- Breadcrumb -->
<div class="row">
<div class="col-12">
<div class="page-title-box d-sm-flex align-items-center justify-content-between">
<h4 class="mb-sm-0">{% if object %}Edit Notification{% else %}Create New Notification{% endif %}</h4>
<div class="page-title-right">
<ol class="breadcrumb m-0">
<li class="breadcrumb-item"><a href="{% url 'core:dashboard' %}">Dashboard</a></li>
<li class="breadcrumb-item"><a href="{% url 'core:system_notification_list' %}">Notifications</a></li>
<li class="breadcrumb-item active">{% if object %}Edit{% else %}Create{% endif %}</li>
</ol>
</div>
</div>
</div>
</div>
<div class="row">
<!-- Main Form -->
<div class="col-lg-8">
<div class="card">
<div class="card-header">
<h5 class="card-title mb-0">
<i class="fas fa-{% if object %}edit{% else %}plus{% endif %} me-2"></i>
Notification Information
</h5>
</div>
<div class="card-body">
<form method="post" id="notificationForm">
{% csrf_token %}
<!-- Basic Information -->
<div class="row mb-4">
{# <div class="col-md-6">#}
{# <div class="form-floating mb-3">#}
{# {{ form.category }}#}
{# <label for="{{ form.category.id_for_label }}">Category *</label>#}
{# {% if form.category.errors %}#}
{# <div class="invalid-feedback d-block">{{ form.category.errors.0 }}</div>#}
{# {% endif %}#}
{# </div>#}
{# </div>#}
<div class="col-md-6">
<div class="form-floating mb-3">
{{ form.title }}
<label for="{{ form.title.id_for_label }}">Title *</label>
{% if form.title.errors %}
<div class="invalid-feedback d-block">{{ form.title.errors.0 }}</div>
{% endif %}
</div>
</div>
<div class="col-md-6">
<div class="form-floating mb-3">
{{ form.priority }}
<label for="{{ form.priority.id_for_label }}">Priority *</label>
{% if form.priority.errors %}
<div class="invalid-feedback d-block">{{ form.priority.errors.0 }}</div>
{% endif %}
</div>
</div>
</div>
<div class="row mb-4">
<div class="col-12">
<div class="mb-3">
<label for="{{ form.message.id_for_label }}" class="form-label">Message *</label>
{{ form.message }}
{% if form.message.errors %}
<div class="invalid-feedback d-block">{{ form.message.errors.0 }}</div>
{% endif %}
</div>
</div>
</div>
<!-- Display Settings -->
<div class="card mb-4">
<div class="card-header">
<h6 class="card-title mb-0">Display Settings</h6>
</div>
<div class="card-body">
<div class="row mb-3">
{# <div class="col-md-6">#}
{# <div class="form-floating mb-3">#}
{# {{ form.display_location }}#}
{# <label for="{{ form.display_location.id_for_label }}">Display Location *</label>#}
{# {% if form.display_location.errors %}#}
{# <div class="invalid-feedback d-block">{{ form.display_location.errors.0 }}</div>#}
{# {% endif %}#}
{# </div>#}
{# </div>#}
</div>
<div class="row mb-3">
<div class="col-md-6">
<div class="form-floating mb-3">
{{ form.start_date }}
<label for="{{ form.start_date.id_for_label }}">Start Date *</label>
{% if form.start_date.errors %}
<div class="invalid-feedback d-block">{{ form.start_date.errors.0 }}</div>
{% endif %}
</div>
</div>
<div class="col-md-6">
<div class="form-floating mb-3">
{{ form.end_date }}
<label for="{{ form.end_date.id_for_label }}">End Date *</label>
{% if form.end_date.errors %}
<div class="invalid-feedback d-block">{{ form.end_date.errors.0 }}</div>
{% endif %}
</div>
</div>
</div>
</div>
<div class="row mb-3 p-1">
<div class="col-md-6">
<div class="form-check form-switch">
{{ form.is_dismissible }}
<label class="form-check-label" for="{{ form.is_dismissible.id_for_label }}">
Allow users to dismiss this notification
</label>
{% if form.is_dismissible.errors %}
<div class="invalid-feedback d-block">{{ form.is_dismissible.errors.0 }}</div>
{% endif %}
</div>
</div>
<div class="col-md-6">
<div class="form-check form-switch">
{{ form.is_active }}
<label class="form-check-label" for="{{ form.is_active.id_for_label }}">
Active Notification
</label>
{% if form.is_active.errors %}
<div class="invalid-feedback d-block">{{ form.is_active.errors.0 }}</div>
{% endif %}
</div>
</div>
</div>
</div>
<!-- Action Link -->
<div class="card mb-4">
<div class="card-header d-flex justify-content-between align-items-center">
<h6 class="card-title mb-0">Action Link (Optional)</h6>
<button class="btn btn-sm btn-link" type="button" data-bs-toggle="collapse" data-bs-target="#actionLinkSection">
<i class="fas fa-chevron-down"></i>
</button>
</div>
<div class="collapse" id="actionLinkSection">
<div class="card-body">
<div class="row mb-3">
<div class="col-md-6">
<div class="form-floating mb-3">
{{ form.action_url }}
<label for="{{ form.action_url.id_for_label }}">Link URL</label>
{% if form.action_url.errors %}
<div class="invalid-feedback d-block">{{ form.action_url.errors.0 }}</div>
{% endif %}
</div>
</div>
<div class="col-md-6">
<div class="form-floating mb-3">
{{ form.action_text }}
<label for="{{ form.action_text.id_for_label }}">Link Text</label>
{% if form.action_text.errors %}
<div class="invalid-feedback d-block">{{ form.action_text.errors.0 }}</div>
{% endif %}
</div>
</div>
</div>
</div>
</div>
</div>
<!-- Target Audience -->
<div class="card mb-4">
<div class="card-header d-flex justify-content-between align-items-center">
<h6 class="card-title mb-0">Target Audience (Optional)</h6>
<button class="btn btn-sm btn-link" type="button" data-bs-toggle="collapse" data-bs-target="#targetAudienceSection">
<i class="fas fa-chevron-down"></i>
</button>
</div>
<div class="collapse" id="targetAudienceSection">
<div class="card-body">
<div class="alert alert-info">
<div class="d-flex">
<div class="flex-shrink-0">
<i class="fas fa-info-circle"></i>
</div>
<div class="flex-grow-1 ms-3">
<p class="mb-0">If no specific targets are selected, the notification will be shown to all users.</p>
</div>
</div>
</div>
<div class="row mb-3">
<div class="col-md-6">
<label for="{{ form.target_roles.id_for_label }}" class="form-label">Target Roles</label>
{{ form.target_roles }}
{% if form.target_roles.errors %}
<div class="invalid-feedback d-block">{{ form.target_roles.errors.0 }}</div>
{% endif %}
<div class="form-text">Hold Ctrl/Cmd to select multiple roles</div>
</div>
<div class="col-md-6">
<label for="{{ form.target_departments.id_for_label }}" class="form-label">Target Departments</label>
{{ form.target_departments }}
{% if form.target_departments.errors %}
<div class="invalid-feedback d-block">{{ form.target_departments.errors.0 }}</div>
{% endif %}
<div class="form-text">Hold Ctrl/Cmd to select multiple departments</div>
</div>
</div>
</div>
</div>
</div>
<!-- Advanced Options -->
<div class="card mb-4">
<div class="card-header d-flex justify-content-between align-items-center">
<h6 class="card-title mb-0">Advanced Options</h6>
<button class="btn btn-sm btn-link" type="button" data-bs-toggle="collapse" data-bs-target="#advancedOptions">
<i class="fas fa-chevron-down"></i>
</button>
</div>
<div class="collapse" id="advancedOptions">
<div class="card-body">
<div class="row mb-3">
<div class="col-12">
<div class="mb-3">
<label for="{{ form.additional_data.id_for_label }}" class="form-label">Additional Data (JSON)</label>
{{ form.additional_data }}
{% if form.additional_data.errors %}
<div class="invalid-feedback d-block">{{ form.additional_data.errors.0 }}</div>
{% endif %}
<div class="form-text">Enter valid JSON format</div>
</div>
<div class="mb-3">
<button type="button" class="btn btn-sm btn-outline-secondary" onclick="validateJson()">
<i class="fas fa-check me-1"></i>
Validate JSON
</button>
<button type="button" class="btn btn-sm btn-outline-secondary ms-2" onclick="formatJson()">
<i class="fas fa-indent me-1"></i>
Format JSON
</button>
</div>
</div>
</div>
<div class="row mb-3">
{# <div class="col-md-6">#}
{# <div class="form-floating mb-3">#}
{# {{ form.icon_class }}#}
{# <label for="{{ form.icon_class.id_for_label }}">Icon Class</label>#}
{# {% if form.icon_class.errors %}#}
{# <div class="invalid-feedback d-block">{{ form.icon_class.errors.0 }}</div>#}
{# {% endif %}#}
{# </div>#}
{# <div class="form-text">FontAwesome icon class (e.g., fa-info-circle)</div>#}
{# </div>#}
<div class="col-md-6">
<div class="form-check form-switch mt-4">
{{ form.is_persistent }}
<label class="form-check-label" for="{{ form.is_persistent.id_for_label }}">
Persistent Notification
</label>
{% if form.is_persistent.errors %}
<div class="invalid-feedback d-block">{{ form.is_persistent.errors.0 }}</div>
{% endif %}
</div>
<div class="form-text">If enabled, notification will persist across sessions</div>
</div>
</div>
</div>
</div>
</div>
<!-- Form Actions -->
<div class="d-flex justify-content-between">
<a href="{% url 'core:system_notification_list' %}" class="btn btn-outline-secondary">
<i class="fas fa-arrow-left me-1"></i>
Cancel
</a>
<div>
<button type="button" class="btn btn-outline-primary me-2" onclick="previewNotification()">
<i class="fas fa-eye me-1"></i>
Preview
</button>
<button type="submit" class="btn btn-primary">
<i class="fas fa-save me-1"></i>
{% if object %}Update Notification{% else %}Create Notification{% endif %}
</button>
</div>
</div>
</form>
</div>
</div>
</div>
<!-- Help Sidebar -->
<div class="col-lg-4">
<!-- Live Preview -->
<div class="card mb-4">
<div class="card-header">
<h5 class="card-title mb-0">
<i class="fas fa-eye me-2"></i>
Live Preview
</h5>
</div>
<div class="card-body">
<div id="notificationPreview" class="alert alert-info">
<div class="d-flex">
<div class="flex-shrink-0">
<i class="fas fa-bell"></i>
</div>
<div class="flex-grow-1 ms-3">
<h5 class="alert-heading">Notification Title</h5>
<p class="mb-0">Notification message will appear here.</p>
<hr>
<p class="mb-0">
<a href="#" class="alert-link">Action Link</a>
</p>
</div>
</div>
</div>
<div class="text-center">
<small class="text-muted">This preview updates as you type</small>
</div>
</div>
</div>
<!-- Help & Guidelines -->
<div class="card">
<div class="card-header">
<h5 class="card-title mb-0">
<i class="fas fa-question-circle me-2"></i>
Help & Guidelines
</h5>
</div>
<div class="card-body">
<div class="accordion" id="helpAccordion">
<!-- Priority Levels -->
<div class="accordion-item">
<h2 class="accordion-header" id="priorityHelp">
<button class="accordion-button collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#priorityContent">
Priority Levels
</button>
</h2>
<div id="priorityContent" class="accordion-collapse collapse" data-bs-parent="#helpAccordion">
<div class="accordion-body">
<ul class="list-unstyled">
<li><span class="badge bg-success me-2">Low</span> Informational messages, tips, updates</li>
<li><span class="badge bg-info me-2">Medium</span> Important information, reminders</li>
<li><span class="badge bg-warning me-2">High</span> Urgent messages, warnings</li>
<li><span class="badge bg-danger me-2">Critical</span> Emergency alerts, system critical issues</li>
</ul>
</div>
</div>
</div>
<!-- Display Locations -->
<div class="accordion-item">
<h2 class="accordion-header" id="locationsHelp">
<button class="accordion-button collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#locationsContent">
Display Locations
</button>
</h2>
<div id="locationsContent" class="accordion-collapse collapse" data-bs-parent="#helpAccordion">
<div class="accordion-body">
<ul class="list-unstyled">
<li><strong>Dashboard:</strong> Appears on the main dashboard</li>
<li><strong>Header:</strong> Appears in the site header</li>
<li><strong>Sidebar:</strong> Appears in the navigation sidebar</li>
<li><strong>Modal:</strong> Appears as a popup modal</li>
<li><strong>Toast:</strong> Appears as a temporary toast notification</li>
<li><strong>Banner:</strong> Appears as a full-width banner</li>
</ul>
</div>
</div>
</div>
<!-- Message Formatting -->
<div class="accordion-item">
<h2 class="accordion-header" id="formattingHelp">
<button class="accordion-button collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#formattingContent">
Message Formatting
</button>
</h2>
<div id="formattingContent" class="accordion-collapse collapse" data-bs-parent="#helpAccordion">
<div class="accordion-body">
<p>Basic formatting is supported:</p>
<ul class="list-unstyled">
<li><code>**bold text**</code> - <strong>bold text</strong></li>
<li><code>*italic text*</code> - <em>italic text</em></li>
<li><code>[link text](url)</code> - <a href="#">link text</a></li>
<li><code>- list item</code> - bulleted list</li>
</ul>
<div class="alert alert-warning alert-sm">
<small>Keep messages concise and clear for better user experience.</small>
</div>
</div>
</div>
</div>
<!-- Best Practices -->
<div class="accordion-item">
<h2 class="accordion-header" id="practicesHelp">
<button class="accordion-button collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#practicesContent">
Best Practices
</button>
</h2>
<div id="practicesContent" class="accordion-collapse collapse" data-bs-parent="#helpAccordion">
<div class="accordion-body">
<ul class="list-unstyled">
<li><i class="fas fa-check-circle text-success me-2"></i> Keep titles short and descriptive</li>
<li><i class="fas fa-check-circle text-success me-2"></i> Use appropriate priority levels</li>
<li><i class="fas fa-check-circle text-success me-2"></i> Include clear action steps when needed</li>
<li><i class="fas fa-check-circle text-success me-2"></i> Target specific audiences when possible</li>
<li><i class="fas fa-times-circle text-danger me-2"></i> Avoid overusing high/critical priorities</li>
<li><i class="fas fa-times-circle text-danger me-2"></i> Don't create too many concurrent notifications</li>
</ul>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<!-- Preview Modal -->
<div class="modal fade" id="previewModal" tabindex="-1" aria-labelledby="previewModalLabel" aria-hidden="true">
<div class="modal-dialog modal-lg">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="previewModalLabel">Notification Preview</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div class="modal-body">
<div class="row">
<div class="col-12">
<h6 class="text-muted mb-3">Dashboard View</h6>
<div id="dashboardPreview" class="alert alert-info">
<div class="d-flex">
<div class="flex-shrink-0">
<i class="fas fa-bell fa-lg"></i>
</div>
<div class="flex-grow-1 ms-3">
<h5 class="alert-heading">Notification Title</h5>
<p class="mb-0">Notification message will appear here.</p>
<hr>
<p class="mb-0">
<a href="#" class="alert-link">Action Link</a>
</p>
</div>
</div>
</div>
</div>
</div>
<div class="row mt-4">
<div class="col-md-6">
<h6 class="text-muted mb-3">Toast View</h6>
<div class="toast show" role="alert" aria-live="assertive" aria-atomic="true">
<div class="toast-header">
<i id="toastIcon" class="fas fa-bell me-2"></i>
<strong class="me-auto" id="toastTitle">Notification Title</strong>
<small>Just now</small>
<button type="button" class="btn-close" data-bs-dismiss="toast" aria-label="Close"></button>
</div>
<div class="toast-body" id="toastMessage">
Notification message will appear here.
</div>
</div>
</div>
<div class="col-md-6">
<h6 class="text-muted mb-3">Banner View</h6>
<div id="bannerPreview" class="alert alert-info mb-0">
<div class="d-flex align-items-center">
<div class="flex-shrink-0">
<i class="fas fa-bell"></i>
</div>
<div class="flex-grow-1 ms-2" id="bannerTitle">
Notification Title
</div>
<div class="flex-shrink-0">
<a href="#" class="text-decoration-none" id="bannerLink">Action Link</a>
</div>
</div>
</div>
</div>
</div>
<div class="row mt-4">
<div class="col-12">
<h6 class="text-muted mb-3">Modal View</h6>
<div class="card">
<div class="card-header" id="modalTitle">
Notification Title
</div>
<div class="card-body">
<p class="card-text" id="modalMessage">Notification message will appear here.</p>
<a href="#" class="btn btn-primary btn-sm" id="modalLink">Action Link</a>
</div>
</div>
</div>
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Close</button>
</div>
</div>
</div>
</div>
{% endblock %}
{% block js %}
<script>
document.addEventListener('DOMContentLoaded', function() {
// Live preview updates
const titleInput = document.getElementById('{{ form.title.id_for_label }}');
const messageInput = document.getElementById('{{ form.message.id_for_label }}');
const prioritySelect = document.getElementById('{{ form.priority.id_for_label }}');
const linkUrlInput = document.getElementById('{{ form.action_url.id_for_label }}');
const linkTextInput = document.getElementById('{{ form.action_text.id_for_label }}');
{#const iconClassInput = document.getElementById('{{ form.icon_class.id_for_label }}');#}
// Initialize preview
updatePreview();
// Add event listeners
titleInput.addEventListener('input', updatePreview);
messageInput.addEventListener('input', updatePreview);
prioritySelect.addEventListener('change', updatePreview);
linkUrlInput.addEventListener('input', updatePreview);
linkTextInput.addEventListener('input', updatePreview);
iconClassInput.addEventListener('input', updatePreview);
// Initialize date pickers if needed
if (typeof flatpickr !== 'undefined') {
flatpickr('#{{ form.start_date.id_for_label }}', {
enableTime: false,
dateFormat: 'Y-m-d',
});
flatpickr('#{{ form.end_date.id_for_label }}', {
enableTime: false,
dateFormat: 'Y-m-d',
});
}
});
function updatePreview() {
const title = document.getElementById('{{ form.title.id_for_label }}').value || 'Notification Title';
const message = document.getElementById('{{ form.message.id_for_label }}').value || 'Notification message will appear here.';
const priority = document.getElementById('{{ form.priority.id_for_label }}').value;
const linkUrl = document.getElementById('{{ form.action_url.id_for_label }}').value;
const linkText = document.getElementById('{{ form.action_text.id_for_label }}').value || 'Action Link';
const iconClass = document.getElementById('{{ form.icon_class.id_for_label }}').value || 'fa-bell';
// Determine alert class based on priority
let alertClass = 'alert-info';
if (priority === 'LOW') alertClass = 'alert-success';
else if (priority === 'MEDIUM') alertClass = 'alert-info';
else if (priority === 'HIGH') alertClass = 'alert-warning';
else if (priority === 'CRITICAL') alertClass = 'alert-danger';
// Update live preview
const preview = document.getElementById('notificationPreview');
preview.className = `alert ${alertClass}`;
// Update icon
let icon = 'fa-bell';
if (priority === 'LOW') icon = 'fa-info-circle';
else if (priority === 'MEDIUM') icon = 'fa-exclamation-circle';
else if (priority === 'HIGH') icon = 'fa-exclamation-triangle';
else if (priority === 'CRITICAL') icon = 'fa-radiation';
if (iconClass) {
icon = iconClass;
}
// Update content
let previewContent = `
<div class="d-flex">
<div class="flex-shrink-0">
<i class="fas ${icon}"></i>
</div>
<div class="flex-grow-1 ms-3">
<h5 class="alert-heading">${title}</h5>
<p class="mb-0">${message}</p>
`;
if (linkUrl) {
previewContent += `
<hr>
<p class="mb-0">
<a href="${linkUrl}" class="alert-link">${linkText}</a>
</p>
`;
}
previewContent += `
</div>
</div>
`;
preview.innerHTML = previewContent;
}
function validateJson() {
const jsonField = document.getElementById('{{ form.additional_data.id_for_label }}');
const jsonValue = jsonField.value.trim();
if (!jsonValue) {
alert('Please enter JSON content to validate');
return;
}
try {
const parsedJson = JSON.parse(jsonValue);
alert('JSON is valid!');
} catch (error) {
alert('Invalid JSON: ' + error.message);
}
}
function formatJson() {
const jsonField = document.getElementById('{{ form.additional_data.id_for_label }}');
const jsonValue = jsonField.value.trim();
if (!jsonValue) {
alert('Please enter JSON content to format');
return;
}
try {
const parsedJson = JSON.parse(jsonValue);
jsonField.value = JSON.stringify(parsedJson, null, 2);
} catch (error) {
alert('Cannot format invalid JSON: ' + error.message);
}
}
function previewNotification() {
const title = document.getElementById('{{ form.title.id_for_label }}').value || 'Notification Title';
const message = document.getElementById('{{ form.message.id_for_label }}').value || 'Notification message will appear here.';
const priority = document.getElementById('{{ form.priority.id_for_label }}').value;
const linkUrl = document.getElementById('{{ form.action_url.id_for_label }}').value || '#';
const linkText = document.getElementById('{{ form.action_text.id_for_label }}').value || 'Action Link';
const iconClass = document.getElementById('{{ form.icon_class.id_for_label }}').value || 'fa-bell';
// Determine alert class based on priority
let alertClass = 'alert-info';
if (priority === 'LOW') alertClass = 'alert-success';
else if (priority === 'MEDIUM') alertClass = 'alert-info';
else if (priority === 'HIGH') alertClass = 'alert-warning';
else if (priority === 'CRITICAL') alertClass = 'alert-danger';
// Update icon
let icon = 'fa-bell';
if (priority === 'LOW') icon = 'fa-info-circle';
else if (priority === 'MEDIUM') icon = 'fa-exclamation-circle';
else if (priority === 'HIGH') icon = 'fa-exclamation-triangle';
else if (priority === 'CRITICAL') icon = 'fa-radiation';
if (iconClass) {
icon = iconClass;
}
// Update dashboard preview
const dashboardPreview = document.getElementById('dashboardPreview');
dashboardPreview.className = `alert ${alertClass}`;
dashboardPreview.innerHTML = `
<div class="d-flex">
<div class="flex-shrink-0">
<i class="fas ${icon} fa-lg"></i>
</div>
<div class="flex-grow-1 ms-3">
<h5 class="alert-heading">${title}</h5>
<p class="mb-0">${message}</p>
<hr>
<p class="mb-0">
<a href="${linkUrl}" class="alert-link">${linkText}</a>
</p>
</div>
</div>
`;
// Update toast preview
document.getElementById('toastIcon').className = `fas ${icon} me-2`;
document.getElementById('toastTitle').textContent = title;
document.getElementById('toastMessage').textContent = message;
// Update banner preview
const bannerPreview = document.getElementById('bannerPreview');
bannerPreview.className = `alert ${alertClass} mb-0`;
document.getElementById('bannerTitle').textContent = title;
document.getElementById('bannerLink').textContent = linkText;
document.getElementById('bannerLink').href = linkUrl;
// Update modal preview
document.getElementById('modalTitle').textContent = title;
document.getElementById('modalMessage').textContent = message;
document.getElementById('modalLink').textContent = linkText;
document.getElementById('modalLink').href = linkUrl;
// Show the modal
const previewModal = new bootstrap.Modal(document.getElementById('previewModal'));
previewModal.show();
}
</script>
{% endblock %}