hospital-management/templates/patients/consents/consent_template_form.html
Marwan Alwali 610e165e17 update
2025-09-04 19:19:52 +03:00

680 lines
30 KiB
HTML

{% extends 'base.html' %}
{% load static %}
{% block title %}{% if template %}Edit{% else %}Create{% endif %} Consent Template{% endblock %}
{% block extra_css %}
<link href="{% static 'assets/plugins/summernote/summernote-lite.min.css' %}" rel="stylesheet" />
<link href="{% static 'assets/plugins/bootstrap-tagsinput/bootstrap-tagsinput.css' %}" rel="stylesheet" />
<style>
.form-section {
background: white;
border-radius: 15px;
box-shadow: 0 5px 15px rgba(0, 0, 0, 0.08);
padding: 2rem;
margin-bottom: 2rem;
}
.section-header {
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
color: white;
padding: 1rem 1.5rem;
border-radius: 10px;
margin-bottom: 1.5rem;
}
.variable-builder {
background: #f8f9fa;
border-radius: 10px;
padding: 1.5rem;
margin-bottom: 1.5rem;
}
.variable-item {
background: white;
border: 1px solid #dee2e6;
border-radius: 8px;
padding: 1rem;
margin-bottom: 1rem;
position: relative;
}
.variable-tag {
background: #007bff;
color: white;
padding: 0.25rem 0.5rem;
border-radius: 15px;
font-size: 0.75rem;
cursor: pointer;
margin: 0.25rem;
display: inline-block;
}
.variable-tag:hover {
background: #0056b3;
}
.template-preview {
border: 2px dashed #dee2e6;
border-radius: 10px;
padding: 2rem;
background: #f8f9fa;
min-height: 300px;
}
.preview-toggle {
position: sticky;
top: 20px;
z-index: 100;
}
.form-tabs {
border-bottom: 2px solid #e9ecef;
margin-bottom: 2rem;
}
.form-tabs .nav-link {
border: none;
border-bottom: 3px solid transparent;
color: #6c757d;
font-weight: 500;
padding: 1rem 1.5rem;
}
.form-tabs .nav-link.active {
color: #007bff;
border-bottom-color: #007bff;
background: none;
}
.auto-save-indicator {
position: fixed;
top: 20px;
right: 20px;
z-index: 1050;
padding: 0.5rem 1rem;
border-radius: 25px;
font-size: 0.875rem;
transition: all 0.3s ease;
}
.content-editor {
min-height: 400px;
}
.template-settings {
background: #e3f2fd;
border-radius: 10px;
padding: 1.5rem;
}
.quick-insert {
background: #fff3cd;
border-radius: 10px;
padding: 1rem;
margin-bottom: 1rem;
}
.insert-button {
background: #ffc107;
border: none;
color: #212529;
padding: 0.375rem 0.75rem;
border-radius: 20px;
font-size: 0.875rem;
margin: 0.25rem;
cursor: pointer;
transition: all 0.3s ease;
}
.insert-button:hover {
background: #e0a800;
transform: translateY(-1px);
}
</style>
{% endblock %}
{% block content %}
<div id="content" class="app-content">
<!-- Page Header -->
<div class="d-flex align-items-center mb-4">
<div>
<ol class="breadcrumb">
<li class="breadcrumb-item"><a href="{% url 'core:dashboard' %}">Dashboard</a></li>
<li class="breadcrumb-item"><a href="{% url 'patients:patient_list' %}">Patients</a></li>
<li class="breadcrumb-item"><a href="{% url 'patients:consent_template_list' %}">Consent Templates</a></li>
<li class="breadcrumb-item active">{% if template %}Edit{% else %}Create{% endif %} Template</li>
</ol>
<h1 class="page-header mb-0">
<i class="fas fa-{% if template %}edit{% else %}plus{% endif %} me-3"></i>
{% if template %}Edit Template{% else %}Create New Template{% endif %}
</h1>
<p class="text-muted mb-0">{% if template %}Modify the existing consent template{% else %}Create a new consent form template for patient care{% endif %}</p>
</div>
<div class="ms-auto">
<div class="btn-group">
<button type="button" class="btn btn-outline-secondary" onclick="saveDraft()">
<i class="fas fa-save me-2"></i>Save Draft
</button>
<button type="button" class="btn btn-info" onclick="previewTemplate()">
<i class="fas fa-eye me-2"></i>Preview
</button>
<a href="{% url 'patients:consent_template_list' %}" class="btn btn-secondary">
<i class="fas fa-times me-2"></i>Cancel
</a>
</div>
</div>
</div>
<!-- Auto-save Indicator -->
<div id="autoSaveIndicator" class="auto-save-indicator bg-success text-white d-none">
<i class="fas fa-check me-2"></i>Saved
</div>
<form id="templateForm" method="post" enctype="multipart/form-data">
{% csrf_token %}
<!-- Form Tabs -->
<ul class="nav nav-tabs form-tabs" role="tablist">
<li class="nav-item">
<a class="nav-link active" data-bs-toggle="tab" href="#basicInfo" role="tab">
<i class="fas fa-info-circle me-2"></i>Basic Information
</a>
</li>
<li class="nav-item">
<a class="nav-link" data-bs-toggle="tab" href="#contentEditor" role="tab">
<i class="fas fa-edit me-2"></i>Content Editor
</a>
</li>
<li class="nav-item">
<a class="nav-link" data-bs-toggle="tab" href="#variables" role="tab">
<i class="fas fa-code me-2"></i>Variables
</a>
</li>
<li class="nav-item">
<a class="nav-link" data-bs-toggle="tab" href="#settings" role="tab">
<i class="fas fa-cog me-2"></i>Settings
</a>
</li>
<li class="nav-item">
<a class="nav-link" data-bs-toggle="tab" href="#preview" role="tab">
<i class="fas fa-eye me-2"></i>Preview
</a>
</li>
</ul>
<div class="tab-content">
<!-- Basic Information Tab -->
<div class="tab-pane fade show active" id="basicInfo" role="tabpanel">
<div class="form-section">
<div class="section-header">
<h5 class="mb-0">
<i class="fas fa-info-circle me-2"></i>Template Information
</h5>
</div>
<div class="row g-3">
<div class="col-md-8">
<label class="form-label">Template Name <span class="text-danger">*</span></label>
<input type="text" class="form-control" name="name" value="{{ template.name|default:'' }}" required>
<div class="form-text">Enter a descriptive name for this consent template</div>
</div>
<div class="col-md-4">
<label class="form-label">Version</label>
<input type="text" class="form-control" name="version" value="{{ template.version|default:'1.0' }}">
<div class="form-text">Template version number</div>
</div>
<div class="col-12">
<label class="form-label">Description</label>
<textarea class="form-control" name="description" rows="3" placeholder="Describe the purpose and usage of this template">{{ template.description|default:'' }}</textarea>
</div>
<div class="col-md-4">
<label class="form-label">Category <span class="text-danger">*</span></label>
<select class="form-select" name="category" required>
<option value="">Select Category</option>
<option value="general" {% if template.category == 'general' %}selected{% endif %}>General Consent</option>
<option value="surgical" {% if template.category == 'surgical' %}selected{% endif %}>Surgical Procedures</option>
<option value="anesthesia" {% if template.category == 'anesthesia' %}selected{% endif %}>Anesthesia</option>
<option value="research" {% if template.category == 'research' %}selected{% endif %}>Research Participation</option>
<option value="treatment" {% if template.category == 'treatment' %}selected{% endif %}>Treatment Consent</option>
<option value="discharge" {% if template.category == 'discharge' %}selected{% endif %}>Discharge Instructions</option>
<option value="privacy" {% if template.category == 'privacy' %}selected{% endif %}>Privacy & Data</option>
</select>
</div>
<div class="col-md-4">
<label class="form-label">Language <span class="text-danger">*</span></label>
<select class="form-select" name="language" required>
<option value="">Select Language</option>
<option value="en" {% if template.language == 'en' %}selected{% endif %}>English</option>
<option value="ar" {% if template.language == 'ar' %}selected{% endif %}>Arabic</option>
<option value="ur" {% if template.language == 'ur' %}selected{% endif %}>Urdu</option>
<option value="hi" {% if template.language == 'hi' %}selected{% endif %}>Hindi</option>
</select>
</div>
<div class="col-md-4">
<label class="form-label">Status</label>
<select class="form-select" name="status">
<option value="draft" {% if template.status == 'draft' %}selected{% endif %}>Draft</option>
<option value="active" {% if template.status == 'active' %}selected{% endif %}>Active</option>
<option value="under_review" {% if template.status == 'under_review' %}selected{% endif %}>Under Review</option>
<option value="archived" {% if template.status == 'archived' %}selected{% endif %}>Archived</option>
</select>
</div>
<div class="col-12">
<label class="form-label">Tags</label>
<input type="text" class="form-control" name="tags" value="{{ template.tags|join:',' }}" data-role="tagsinput" placeholder="Add tags separated by commas">
<div class="form-text">Add relevant tags to help organize and search templates</div>
</div>
</div>
</div>
</div>
<!-- Content Editor Tab -->
<div class="tab-pane fade" id="contentEditor" role="tabpanel">
<div class="form-section">
<div class="section-header">
<h5 class="mb-0">
<i class="fas fa-edit me-2"></i>Template Content
</h5>
</div>
<!-- Quick Insert Buttons -->
<div class="quick-insert">
<h6 class="mb-2">
<i class="fas fa-magic me-2"></i>Quick Insert
</h6>
<button type="button" class="insert-button" onclick="insertText('{{patient_name}}')">Patient Name</button>
<button type="button" class="insert-button" onclick="insertText('{{patient_id}}')">Patient ID</button>
<button type="button" class="insert-button" onclick="insertText('{{date}}')">Date</button>
<button type="button" class="insert-button" onclick="insertText('{{doctor_name}}')">Doctor Name</button>
<button type="button" class="insert-button" onclick="insertText('{{procedure_name}}')">Procedure Name</button>
<button type="button" class="insert-button" onclick="insertText('{{hospital_name}}')">Hospital Name</button>
<button type="button" class="insert-button" onclick="insertText('{{signature_date}}')">Signature Date</button>
<button type="button" class="insert-button" onclick="insertText('{{witness_name}}')">Witness Name</button>
</div>
<div class="row">
<div class="col-12">
<label class="form-label">Template Content <span class="text-danger">*</span></label>
<textarea id="contentEditor" name="content" class="form-control content-editor">{{ template.content|default:'' }}</textarea>
<div class="form-text">Use the rich text editor to create your consent form content. Insert variables using the buttons above.</div>
</div>
</div>
</div>
</div>
<!-- Variables Tab -->
<div class="tab-pane fade" id="variables" role="tabpanel">
<div class="form-section">
<div class="section-header">
<h5 class="mb-0">
<i class="fas fa-code me-2"></i>Template Variables
</h5>
</div>
<div class="variable-builder">
<div class="d-flex justify-content-between align-items-center mb-3">
<h6 class="mb-0">Variable Manager</h6>
<button type="button" class="btn btn-primary btn-sm" onclick="addVariable()">
<i class="fas fa-plus me-1"></i>Add Variable
</button>
</div>
<div id="variablesList">
<!-- Variables will be dynamically added here -->
</div>
<div class="mt-3">
<h6>Available Variables:</h6>
<div id="availableVariables">
<span class="variable-tag" onclick="insertVariable('patient_name')">{{patient_name}}</span>
<span class="variable-tag" onclick="insertVariable('patient_id')">{{patient_id}}</span>
<span class="variable-tag" onclick="insertVariable('date')">{{date}}</span>
<span class="variable-tag" onclick="insertVariable('doctor_name')">{{doctor_name}}</span>
<span class="variable-tag" onclick="insertVariable('procedure_name')">{{procedure_name}}</span>
<span class="variable-tag" onclick="insertVariable('hospital_name')">{{hospital_name}}</span>
<span class="variable-tag" onclick="insertVariable('signature_date')">{{signature_date}}</span>
<span class="variable-tag" onclick="insertVariable('witness_name')">{{witness_name}}</span>
</div>
</div>
</div>
</div>
</div>
<!-- Settings Tab -->
<div class="tab-pane fade" id="settings" role="tabpanel">
<div class="form-section">
<div class="section-header">
<h5 class="mb-0">
<i class="fas fa-cog me-2"></i>Template Settings
</h5>
</div>
<div class="template-settings">
<div class="row g-3">
<div class="col-md-6">
<div class="form-check form-switch">
<input class="form-check-input" type="checkbox" name="requires_signature" id="requiresSignature" {% if template.requires_signature %}checked{% endif %}>
<label class="form-check-label" for="requiresSignature">
Requires Digital Signature
</label>
</div>
</div>
<div class="col-md-6">
<div class="form-check form-switch">
<input class="form-check-input" type="checkbox" name="requires_witness" id="requiresWitness" {% if template.requires_witness %}checked{% endif %}>
<label class="form-check-label" for="requiresWitness">
Requires Witness Signature
</label>
</div>
</div>
<div class="col-md-6">
<div class="form-check form-switch">
<input class="form-check-input" type="checkbox" name="is_mandatory" id="isMandatory" {% if template.is_mandatory %}checked{% endif %}>
<label class="form-check-label" for="isMandatory">
Mandatory Template
</label>
</div>
</div>
<div class="col-md-6">
<div class="form-check form-switch">
<input class="form-check-input" type="checkbox" name="allow_modifications" id="allowModifications" {% if template.allow_modifications %}checked{% endif %}>
<label class="form-check-label" for="allowModifications">
Allow Content Modifications
</label>
</div>
</div>
<div class="col-md-6">
<label class="form-label">Expiry Period (Days)</label>
<input type="number" class="form-control" name="expiry_days" value="{{ template.expiry_days|default:'' }}" min="1" max="365">
<div class="form-text">Leave blank for no expiry</div>
</div>
<div class="col-md-6">
<label class="form-label">Reminder Days</label>
<input type="number" class="form-control" name="reminder_days" value="{{ template.reminder_days|default:'' }}" min="1" max="30">
<div class="form-text">Days before expiry to send reminder</div>
</div>
<div class="col-12">
<label class="form-label">Legal Disclaimer</label>
<textarea class="form-control" name="legal_disclaimer" rows="3" placeholder="Enter any legal disclaimer or additional terms">{{ template.legal_disclaimer|default:'' }}</textarea>
</div>
</div>
</div>
</div>
</div>
<!-- Preview Tab -->
<div class="tab-pane fade" id="preview" role="tabpanel">
<div class="form-section">
<div class="section-header">
<h5 class="mb-0">
<i class="fas fa-eye me-2"></i>Template Preview
</h5>
</div>
<div class="preview-toggle mb-3">
<div class="btn-group" role="group">
<input type="radio" class="btn-check" name="previewMode" id="previewFormatted" checked>
<label class="btn btn-outline-primary" for="previewFormatted">
<i class="fas fa-file-alt me-1"></i>Formatted
</label>
<input type="radio" class="btn-check" name="previewMode" id="previewPrint">
<label class="btn btn-outline-secondary" for="previewPrint">
<i class="fas fa-print me-1"></i>Print View
</label>
<input type="radio" class="btn-check" name="previewMode" id="previewMobile">
<label class="btn btn-outline-info" for="previewMobile">
<i class="fas fa-mobile-alt me-1"></i>Mobile
</label>
</div>
<button type="button" class="btn btn-success ms-2" onclick="updatePreview()">
<i class="fas fa-sync me-1"></i>Update Preview
</button>
</div>
<div id="templatePreview" class="template-preview">
<div class="text-center text-muted py-5">
<i class="fas fa-eye fa-3x mb-3"></i>
<h6>Template Preview</h6>
<p>Click "Update Preview" to see how your template will look</p>
</div>
</div>
</div>
</div>
</div>
<!-- Form Actions -->
<div class="form-section">
<div class="d-flex justify-content-between align-items-center">
<div>
<button type="button" class="btn btn-outline-secondary" onclick="saveDraft()">
<i class="fas fa-save me-2"></i>Save as Draft
</button>
<button type="button" class="btn btn-outline-info" onclick="validateTemplate()">
<i class="fas fa-check-circle me-2"></i>Validate
</button>
</div>
<div>
<a href="{% url 'patients:consent_template_list' %}" class="btn btn-secondary me-2">
<i class="fas fa-times me-2"></i>Cancel
</a>
<button type="submit" class="btn btn-primary">
<i class="fas fa-save me-2"></i>{% if template %}Update{% else %}Create{% endif %} Template
</button>
</div>
</div>
</div>
</form>
</div>
{% endblock %}
{% block extra_js %}
<script src="{% static 'assets/plugins/summernote/summernote-lite.min.js' %}"></script>
<script src="{% static 'assets/plugins/bootstrap-tagsinput/bootstrap-tagsinput.min.js' %}"></script>
<script>
let autoSaveTimer;
let variableCounter = 0;
$(document).ready(function() {
// Initialize Summernote
$('#contentEditor').summernote({
height: 400,
toolbar: [
['style', ['style']],
['font', ['bold', 'underline', 'clear']],
['fontname', ['fontname']],
['color', ['color']],
['para', ['ul', 'ol', 'paragraph']],
['table', ['table']],
['insert', ['link', 'picture', 'video']],
['view', ['fullscreen', 'codeview', 'help']]
],
callbacks: {
onChange: function(contents, $editable) {
scheduleAutoSave();
}
}
});
// Initialize tags input
$('[data-role="tagsinput"]').tagsinput({
trimValue: true,
confirmKeys: [13, 44], // Enter and comma
focusClass: 'focus'
});
// Auto-save functionality
$('#templateForm input, #templateForm select, #templateForm textarea').on('input change', function() {
scheduleAutoSave();
});
// Load existing variables if editing
{% if template.variables %}
{% for variable in template.variables %}
addVariable('{{ variable.name }}', '{{ variable.description }}', '{{ variable.type }}', '{{ variable.default_value }}');
{% endfor %}
{% endif %}
// Preview mode toggle
$('input[name="previewMode"]').change(function() {
updatePreview();
});
});
function scheduleAutoSave() {
clearTimeout(autoSaveTimer);
autoSaveTimer = setTimeout(function() {
saveDraft(true);
}, 5000); // Auto-save after 5 seconds of inactivity
}
function saveDraft(isAutoSave = false) {
const formData = new FormData($('#templateForm')[0]);
formData.append('save_as_draft', 'true');
$.ajax({
url: window.location.href,
method: 'POST',
data: formData,
processData: false,
contentType: false,
success: function(response) {
if (response.success) {
showAutoSaveIndicator(isAutoSave ? 'Auto-saved' : 'Draft saved');
}
},
error: function() {
if (!isAutoSave) {
alert('Error saving draft.');
}
}
});
}
function showAutoSaveIndicator(message) {
const indicator = $('#autoSaveIndicator');
indicator.html('<i class="fas fa-check me-2"></i>' + message);
indicator.removeClass('d-none');
setTimeout(function() {
indicator.addClass('d-none');
}, 3000);
}
function insertText(text) {
$('#contentEditor').summernote('editor.insertText', text);
}
function insertVariable(variableName) {
const variableText = '{{' + variableName + '}}';
$('#contentEditor').summernote('editor.insertText', variableText);
}
function addVariable(name = '', description = '', type = 'text', defaultValue = '') {
variableCounter++;
const variableHtml = `
<div class="variable-item" id="variable-${variableCounter}">
<div class="row g-3">
<div class="col-md-3">
<label class="form-label">Variable Name</label>
<input type="text" class="form-control" name="variables[${variableCounter}][name]" value="${name}" placeholder="e.g., patient_age">
</div>
<div class="col-md-3">
<label class="form-label">Type</label>
<select class="form-select" name="variables[${variableCounter}][type]">
<option value="text" ${type === 'text' ? 'selected' : ''}>Text</option>
<option value="number" ${type === 'number' ? 'selected' : ''}>Number</option>
<option value="date" ${type === 'date' ? 'selected' : ''}>Date</option>
<option value="boolean" ${type === 'boolean' ? 'selected' : ''}>Yes/No</option>
</select>
</div>
<div class="col-md-4">
<label class="form-label">Description</label>
<input type="text" class="form-control" name="variables[${variableCounter}][description]" value="${description}" placeholder="Variable description">
</div>
<div class="col-md-2">
<label class="form-label">Actions</label>
<div>
<button type="button" class="btn btn-outline-danger btn-sm" onclick="removeVariable(${variableCounter})">
<i class="fas fa-trash"></i>
</button>
</div>
</div>
<div class="col-12">
<label class="form-label">Default Value</label>
<input type="text" class="form-control" name="variables[${variableCounter}][default_value]" value="${defaultValue}" placeholder="Optional default value">
</div>
</div>
</div>
`;
$('#variablesList').append(variableHtml);
}
function removeVariable(id) {
$(`#variable-${id}`).remove();
}
function updatePreview() {
const formData = new FormData($('#templateForm')[0]);
const previewMode = $('input[name="previewMode"]:checked').attr('id');
formData.append('preview_mode', previewMode);
formData.append('action', 'preview');
$.ajax({
url: '{% url "patients:consent_template_preview" %}',
method: 'POST',
data: formData,
processData: false,
contentType: false,
success: function(response) {
$('#templatePreview').html(response);
},
error: function() {
$('#templatePreview').html('<div class="alert alert-danger">Error generating preview</div>');
}
});
}
function validateTemplate() {
const formData = new FormData($('#templateForm')[0]);
formData.append('action', 'validate');
$.ajax({
url: window.location.href,
method: 'POST',
data: formData,
processData: false,
contentType: false,
success: function(response) {
if (response.valid) {
alert('Template validation successful!');
} else {
alert('Validation errors:\n' + response.errors.join('\n'));
}
},
error: function() {
alert('Error validating template.');
}
});
}
function previewTemplate() {
updatePreview();
$('a[href="#preview"]').tab('show');
}
// Form submission
$('#templateForm').on('submit', function(e) {
e.preventDefault();
// Validate required fields
const requiredFields = ['name', 'category', 'language'];
let isValid = true;
requiredFields.forEach(function(field) {
const input = $(`[name="${field}"]`);
if (!input.val().trim()) {
input.addClass('is-invalid');
isValid = false;
} else {
input.removeClass('is-invalid');
}
});
if (!isValid) {
alert('Please fill in all required fields.');
return;
}
// Submit form
this.submit();
});
</script>
{% endblock %}