2025-08-12 13:33:25 +03:00

467 lines
21 KiB
HTML

{% extends "base.html" %}
{% load static %}
{% block title %}{% if object %}Edit{% else %}Create{% endif %} Consent Form - Patients{% endblock %}
{% block css %}
<link href="{% static 'assets/plugins/summernote/dist/summernote-lite.min.css' %}" rel="stylesheet" />
{% endblock %}
{% block content %}
<!-- BEGIN breadcrumb -->
<ol class="breadcrumb float-xl-end">
<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_form_list' %}">Consent Forms</a></li>
{% if object %}
<li class="breadcrumb-item"><a href="{% url 'patients:consent_form_detail' object.pk %}">{{ object.title|truncatechars:20 }}</a></li>
<li class="breadcrumb-item active">Edit</li>
{% else %}
<li class="breadcrumb-item active">Create</li>
{% endif %}
</ol>
<!-- END breadcrumb -->
<!-- BEGIN page-header -->
<h1 class="page-header">
{% if object %}Edit Consent Form{% else %}Create Consent Form{% endif %}
<small>{% if object %}{{ object.title }}{% else %}New consent form template{% endif %}</small>
</h1>
<!-- END page-header -->
<div class="row">
<div class="col-xl-8">
<!-- BEGIN panel -->
<div class="panel panel-inverse">
<div class="panel-heading">
<h4 class="panel-title">Form Details</h4>
<div class="panel-heading-btn">
<button type="button" class="btn btn-xs btn-info me-2" onclick="saveDraft()">
<i class="fa fa-save"></i> Save Draft
</button>
<button type="button" class="btn btn-xs btn-secondary me-2" onclick="previewForm()">
<i class="fa fa-eye"></i> Preview
</button>
<a href="javascript:;" class="btn btn-xs btn-icon btn-default" data-toggle="panel-expand"><i class="fa fa-expand"></i></a>
</div>
</div>
<div class="panel-body">
<form method="post" id="consent-form" novalidate>
{% csrf_token %}
<div class="row mb-3">
<div class="col-md-8">
<div class="form-floating">
{{ form.title }}
<label for="{{ form.title.id_for_label }}">Form Title <span class="text-danger">*</span></label>
{% if form.title.errors %}
<div class="invalid-feedback d-block">{{ form.title.errors.0 }}</div>
{% endif %}
</div>
</div>
<div class="col-md-4">
<div class="form-floating">
{{ form.category }}
<label for="{{ form.category.id_for_label }}">Category <span class="text-danger">*</span></label>
{% if form.category.errors %}
<div class="invalid-feedback d-block">{{ form.category.errors.0 }}</div>
{% endif %}
</div>
</div>
</div>
<div class="mb-3">
<label for="{{ form.description.id_for_label }}" class="form-label">Description <span class="text-danger">*</span></label>
{{ form.description }}
{% if form.description.errors %}
<div class="invalid-feedback d-block">{{ form.description.errors.0 }}</div>
{% endif %}
<div class="form-text">Brief description of what this consent form covers.</div>
</div>
<div class="row mb-3">
<div class="col-md-4">
<div class="form-floating">
{{ form.version }}
<label for="{{ form.version.id_for_label }}">Version</label>
{% if form.version.errors %}
<div class="invalid-feedback d-block">{{ form.version.errors.0 }}</div>
{% endif %}
</div>
</div>
<div class="col-md-4">
<div class="form-floating">
{{ form.status }}
<label for="{{ form.status.id_for_label }}">Status <span class="text-danger">*</span></label>
{% if form.status.errors %}
<div class="invalid-feedback d-block">{{ form.status.errors.0 }}</div>
{% endif %}
</div>
</div>
<div class="col-md-4">
<div class="form-floating">
{{ form.effective_date }}
<label for="{{ form.effective_date.id_for_label }}">Effective Date</label>
{% if form.effective_date.errors %}
<div class="invalid-feedback d-block">{{ form.effective_date.errors.0 }}</div>
{% endif %}
</div>
</div>
</div>
<div class="row mb-3">
<div class="col-md-6">
<div class="form-check">
{{ form.is_required }}
<label class="form-check-label" for="{{ form.is_required.id_for_label }}">
<i class="fa fa-exclamation-triangle text-danger me-1"></i>Required for all patients
</label>
{% if form.is_required.errors %}
<div class="invalid-feedback d-block">{{ form.is_required.errors.0 }}</div>
{% endif %}
<div class="form-text">If checked, this form must be signed by all patients.</div>
</div>
</div>
<div class="col-md-6">
<div class="form-check">
{{ form.has_expiration }}
<label class="form-check-label" for="{{ form.has_expiration.id_for_label }}">
<i class="fa fa-clock text-warning me-1"></i>Has expiration date
</label>
{% if form.has_expiration.errors %}
<div class="invalid-feedback d-block">{{ form.has_expiration.errors.0 }}</div>
{% endif %}
<div class="form-text">If checked, signed forms will expire after a set period.</div>
</div>
</div>
</div>
<div class="row mb-3" id="expiration-fields" style="display: none;">
<div class="col-md-6">
<div class="form-floating">
{{ form.expiration_days }}
<label for="{{ form.expiration_days.id_for_label }}">Expiration Days</label>
{% if form.expiration_days.errors %}
<div class="invalid-feedback d-block">{{ form.expiration_days.errors.0 }}</div>
{% endif %}
</div>
</div>
<div class="col-md-6">
<div class="form-floating">
{{ form.renewal_reminder_days }}
<label for="{{ form.renewal_reminder_days.id_for_label }}">Reminder Days</label>
{% if form.renewal_reminder_days.errors %}
<div class="invalid-feedback d-block">{{ form.renewal_reminder_days.errors.0 }}</div>
{% endif %}
</div>
</div>
</div>
<div class="mb-3">
<label for="{{ form.content.id_for_label }}" class="form-label">Form Content <span class="text-danger">*</span></label>
{{ form.content }}
{% if form.content.errors %}
<div class="invalid-feedback d-block">{{ form.content.errors.0 }}</div>
{% endif %}
<div class="form-text">Use the rich text editor to create the consent form content. Include all necessary legal language and patient information fields.</div>
</div>
<div class="mb-3">
<label for="{{ form.signature_requirements.id_for_label }}" class="form-label">Signature Requirements</label>
{{ form.signature_requirements }}
{% if form.signature_requirements.errors %}
<div class="invalid-feedback d-block">{{ form.signature_requirements.errors.0 }}</div>
{% endif %}
<div class="form-text">Specify who needs to sign this form (patient, guardian, witness, etc.).</div>
</div>
<div class="mb-3">
<label for="{{ form.legal_notes.id_for_label }}" class="form-label">Legal Notes</label>
{{ form.legal_notes }}
{% if form.legal_notes.errors %}
<div class="invalid-feedback d-block">{{ form.legal_notes.errors.0 }}</div>
{% endif %}
<div class="form-text">Internal notes about legal requirements, compliance, or special considerations.</div>
</div>
<!-- Form Actions -->
<div class="d-flex justify-content-between">
<div>
<a href="{% if object %}{% url 'patients:consent_form_detail' object.pk %}{% else %}{% url 'patients:consent_form_list' %}{% endif %}" class="btn btn-secondary">
<i class="fa fa-arrow-left me-2"></i>Cancel
</a>
</div>
<div>
<button type="button" class="btn btn-info me-2" onclick="saveDraft()">
<i class="fa fa-save me-2"></i>Save Draft
</button>
<button type="submit" class="btn btn-primary">
<i class="fa fa-check me-2"></i>{% if object %}Update{% else %}Create{% endif %} Form
</button>
</div>
</div>
</form>
</div>
</div>
<!-- END panel -->
</div>
<div class="col-xl-4">
<!-- BEGIN panel -->
<div class="panel panel-inverse">
<div class="panel-heading">
<h4 class="panel-title">Form Templates</h4>
</div>
<div class="panel-body">
<div class="alert alert-info">
<h6 class="alert-heading">Standard Templates</h6>
<p class="mb-2">Choose from pre-built templates:</p>
<div class="d-grid gap-2">
<button type="button" class="btn btn-outline-primary btn-sm" onclick="loadTemplate('general')">
General Consent
</button>
<button type="button" class="btn btn-outline-primary btn-sm" onclick="loadTemplate('surgical')">
Surgical Consent
</button>
<button type="button" class="btn btn-outline-primary btn-sm" onclick="loadTemplate('treatment')">
Treatment Consent
</button>
<button type="button" class="btn btn-outline-primary btn-sm" onclick="loadTemplate('research')">
Research Consent
</button>
<button type="button" class="btn btn-outline-primary btn-sm" onclick="loadTemplate('privacy')">
Privacy Agreement
</button>
</div>
</div>
</div>
</div>
<!-- END panel -->
<!-- BEGIN panel -->
<div class="panel panel-inverse">
<div class="panel-heading">
<h4 class="panel-title">Form Guidelines</h4>
</div>
<div class="panel-body">
<div class="alert alert-warning">
<h6 class="alert-heading">Legal Requirements</h6>
<ul class="mb-0 small">
<li>Include clear description of procedures/treatments</li>
<li>List all risks and benefits</li>
<li>Provide alternative treatment options</li>
<li>Include patient rights and withdrawal options</li>
<li>Ensure language is clear and understandable</li>
<li>Include contact information for questions</li>
</ul>
</div>
<div class="card border-success mb-3">
<div class="card-header bg-success text-white">
<h6 class="card-title mb-0">Best Practices</h6>
</div>
<div class="card-body">
<ul class="list-unstyled mb-0 small">
<li><i class="fa fa-check text-success me-2"></i>Use simple, clear language</li>
<li><i class="fa fa-check text-success me-2"></i>Avoid medical jargon</li>
<li><i class="fa fa-check text-success me-2"></i>Include visual aids if helpful</li>
<li><i class="fa fa-check text-success me-2"></i>Provide adequate white space</li>
<li><i class="fa fa-check text-success me-2"></i>Test readability level</li>
</ul>
</div>
</div>
</div>
</div>
<!-- END panel -->
<!-- BEGIN panel -->
<div class="panel panel-inverse">
<div class="panel-heading">
<h4 class="panel-title">Form Status</h4>
</div>
<div class="panel-body">
<div id="form-status">
<div class="alert alert-secondary">
<i class="fa fa-info-circle me-2"></i>
<span id="status-text">Form not saved</span>
</div>
</div>
<div class="small text-muted">
<div>Last saved: <span id="last-saved">Never</span></div>
<div>Auto-save: <span class="text-success">Enabled</span></div>
<div>Word count: <span id="word-count">0</span></div>
</div>
</div>
</div>
<!-- END panel -->
</div>
</div>
{% endblock %}
{% block js %}
<script src="{% static 'assets/plugins/summernote/dist/summernote-lite.min.js' %}"></script>
<script>
var autoSaveTimer;
$(document).ready(function() {
// Initialize Summernote
$('#{{ form.content.id_for_label }}').summernote({
height: 400,
toolbar: [
['style', ['style']],
['font', ['bold', 'underline', 'clear']],
['color', ['color']],
['para', ['ul', 'ol', 'paragraph']],
['table', ['table']],
['insert', ['link']],
['view', ['fullscreen', 'codeview', 'help']]
],
callbacks: {
onChange: function(contents, $editable) {
updateWordCount(contents);
clearTimeout(autoSaveTimer);
autoSaveTimer = setTimeout(function() {
saveDraft();
}, 5000);
}
}
});
// Expiration fields toggle
$('#{{ form.has_expiration.id_for_label }}').on('change', function() {
if ($(this).is(':checked')) {
$('#expiration-fields').show();
} else {
$('#expiration-fields').hide();
}
});
// Initial state
if ($('#{{ form.has_expiration.id_for_label }}').is(':checked')) {
$('#expiration-fields').show();
}
// Form validation
$('#consent-form').on('submit', function(e) {
if (!validateForm()) {
e.preventDefault();
}
});
// Auto-save functionality
$('#consent-form input, #consent-form select, #consent-form textarea').on('change input', function() {
clearTimeout(autoSaveTimer);
autoSaveTimer = setTimeout(function() {
saveDraft();
}, 5000);
});
// Initial word count
updateWordCount($('#{{ form.content.id_for_label }}').summernote('code'));
});
function validateForm() {
var isValid = true;
var errors = [];
// Required field validation
var requiredFields = ['{{ form.title.id_for_label }}', '{{ form.category.id_for_label }}', '{{ form.description.id_for_label }}', '{{ form.status.id_for_label }}'];
requiredFields.forEach(function(fieldId) {
var field = $('#' + fieldId);
if (!field.val()) {
field.addClass('is-invalid');
errors.push(field.closest('.form-floating').find('label').text().replace(' *', '') + ' is required');
isValid = false;
} else {
field.removeClass('is-invalid');
}
});
// Content validation
var content = $('#{{ form.content.id_for_label }}').summernote('code');
if (!content || content.trim() === '' || content === '<p><br></p>') {
$('#{{ form.content.id_for_label }}').addClass('is-invalid');
errors.push('Form content is required');
isValid = false;
} else {
$('#{{ form.content.id_for_label }}').removeClass('is-invalid');
}
if (!isValid) {
toastr.error('Please fix the following errors:\n' + errors.join('\n'));
}
return isValid;
}
function updateWordCount(content) {
var text = $(content).text();
var wordCount = text.trim() === '' ? 0 : text.trim().split(/\s+/).length;
$('#word-count').text(wordCount);
}
function saveDraft() {
var formData = $('#consent-form').serialize();
var content = $('#{{ form.content.id_for_label }}').summernote('code');
formData += '&content=' + encodeURIComponent(content);
$.ajax({
url: '{% url "patients:save_consent_form_draft" %}',
method: 'POST',
data: formData,
success: function(response) {
updateFormStatus('Draft saved', 'success');
$('#last-saved').text(new Date().toLocaleTimeString());
},
error: function() {
updateFormStatus('Failed to save draft', 'danger');
}
});
}
function updateFormStatus(message, type) {
var alertClass = 'alert-' + type;
$('#form-status').html('<div class="alert ' + alertClass + '"><i class="fa fa-info-circle me-2"></i>' + message + '</div>');
}
function previewForm() {
var content = $('#{{ form.content.id_for_label }}').summernote('code');
var title = $('#{{ form.title.id_for_label }}').val();
var previewWindow = window.open('', '_blank');
previewWindow.document.write('<html><head><title>' + title + '</title></head><body>' + content + '</body></html>');
previewWindow.document.close();
}
function loadTemplate(templateType) {
if (confirm('Load template? This will replace the current content.')) {
$.ajax({
url: '{% url "patients:get_consent_form_template" %}',
method: 'GET',
data: { template_type: templateType },
success: function(response) {
$('#{{ form.title.id_for_label }}').val(response.title);
$('#{{ form.category.id_for_label }}').val(response.category);
$('#{{ form.description.id_for_label }}').val(response.description);
$('#{{ form.content.id_for_label }}').summernote('code', response.content);
$('#{{ form.signature_requirements.id_for_label }}').val(response.signature_requirements);
if (response.is_required) {
$('#{{ form.is_required.id_for_label }}').prop('checked', true);
}
toastr.success('Template loaded successfully');
},
error: function() {
toastr.error('Failed to load template');
}
});
}
}
</script>
{% endblock %}