434 lines
18 KiB
HTML
434 lines
18 KiB
HTML
{% extends 'base.html' %}
|
|
{% load static %}
|
|
|
|
{% block title %}{{ title }}{% endblock %}
|
|
|
|
{% block css %}
|
|
<link href="{% static 'plugins/bootstrap-datepicker/dist/css/bootstrap-datepicker.min.css' %}" rel="stylesheet" />
|
|
<link href="{% static 'plugins/select2/dist/css/select2.min.css' %}" rel="stylesheet" />
|
|
{% endblock %}
|
|
|
|
{% block content %}
|
|
<!-- BEGIN breadcrumb -->
|
|
<ol class="breadcrumb float-xl-end">
|
|
<li class="breadcrumb-item"><a href="{% url 'core:dashboard' %}">Home</a></li>
|
|
<li class="breadcrumb-item"><a href="{% url 'blood_bank:dashboard' %}">Blood Bank</a></li>
|
|
<li class="breadcrumb-item"><a href="{% url 'blood_bank:donor_list' %}">Donors</a></li>
|
|
<li class="breadcrumb-item active">{{ title }}</li>
|
|
</ol>
|
|
<!-- END breadcrumb -->
|
|
|
|
<!-- BEGIN page-header -->
|
|
<h1 class="page-header">{{ title }} <small>donor information management</small></h1>
|
|
<!-- END page-header -->
|
|
|
|
<!-- BEGIN panel -->
|
|
<div class="panel panel-inverse">
|
|
<div class="panel-heading">
|
|
<h4 class="panel-title">{{ title }}</h4>
|
|
<div class="panel-heading-btn">
|
|
<a href="{% url 'blood_bank:donor_list' %}" class="btn btn-default btn-sm">
|
|
<i class="fa fa-arrow-left"></i> Back to List
|
|
</a>
|
|
</div>
|
|
</div>
|
|
<div class="panel-body">
|
|
<form method="post" class="form-horizontal" id="donorForm">
|
|
{% csrf_token %}
|
|
|
|
<!-- BEGIN personal information -->
|
|
<fieldset>
|
|
<legend class="mb-3">
|
|
<i class="fa fa-user text-primary"></i> Personal Information
|
|
</legend>
|
|
|
|
<div class="row mb-3">
|
|
<div class="col-md-6">
|
|
<label class="form-label" for="{{ form.donor_id.id_for_label }}">
|
|
Donor ID <span class="text-danger">*</span>
|
|
</label>
|
|
{{ form.donor_id }}
|
|
{% if form.donor_id.errors %}
|
|
<div class="text-danger small">{{ form.donor_id.errors.0 }}</div>
|
|
{% endif %}
|
|
<div class="form-text">Unique identifier for the donor</div>
|
|
</div>
|
|
<div class="col-md-6">
|
|
<label class="form-label" for="{{ form.blood_group.id_for_label }}">
|
|
Blood Group <span class="text-danger">*</span>
|
|
</label>
|
|
{{ form.blood_group }}
|
|
{% if form.blood_group.errors %}
|
|
<div class="text-danger small">{{ form.blood_group.errors.0 }}</div>
|
|
{% endif %}
|
|
</div>
|
|
</div>
|
|
|
|
<div class="row mb-3">
|
|
<div class="col-md-6">
|
|
<label class="form-label" for="{{ form.first_name.id_for_label }}">
|
|
First Name <span class="text-danger">*</span>
|
|
</label>
|
|
{{ form.first_name }}
|
|
{% if form.first_name.errors %}
|
|
<div class="text-danger small">{{ form.first_name.errors.0 }}</div>
|
|
{% endif %}
|
|
</div>
|
|
<div class="col-md-6">
|
|
<label class="form-label" for="{{ form.last_name.id_for_label }}">
|
|
Last Name <span class="text-danger">*</span>
|
|
</label>
|
|
{{ form.last_name }}
|
|
{% if form.last_name.errors %}
|
|
<div class="text-danger small">{{ form.last_name.errors.0 }}</div>
|
|
{% endif %}
|
|
</div>
|
|
</div>
|
|
|
|
<div class="row mb-3">
|
|
<div class="col-md-4">
|
|
<label class="form-label" for="{{ form.date_of_birth.id_for_label }}">
|
|
Date of Birth <span class="text-danger">*</span>
|
|
</label>
|
|
{{ form.date_of_birth }}
|
|
{% if form.date_of_birth.errors %}
|
|
<div class="text-danger small">{{ form.date_of_birth.errors.0 }}</div>
|
|
{% endif %}
|
|
<div class="form-text">Must be 18-65 years old</div>
|
|
</div>
|
|
<div class="col-md-4">
|
|
<label class="form-label" for="{{ form.gender.id_for_label }}">
|
|
Gender <span class="text-danger">*</span>
|
|
</label>
|
|
{{ form.gender }}
|
|
{% if form.gender.errors %}
|
|
<div class="text-danger small">{{ form.gender.errors.0 }}</div>
|
|
{% endif %}
|
|
</div>
|
|
<div class="col-md-4">
|
|
<div id="ageDisplay" class="mt-4">
|
|
<span class="badge bg-info">Age will be calculated</span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="row mb-3">
|
|
<div class="col-md-6">
|
|
<label class="form-label" for="{{ form.weight.id_for_label }}">
|
|
Weight (kg) <span class="text-danger">*</span>
|
|
</label>
|
|
{{ form.weight }}
|
|
{% if form.weight.errors %}
|
|
<div class="text-danger small">{{ form.weight.errors.0 }}</div>
|
|
{% endif %}
|
|
<div class="form-text">Minimum 45 kg required for donation</div>
|
|
</div>
|
|
<div class="col-md-6">
|
|
<label class="form-label" for="{{ form.height.id_for_label }}">
|
|
Height (cm) <span class="text-danger">*</span>
|
|
</label>
|
|
{{ form.height }}
|
|
{% if form.height.errors %}
|
|
<div class="text-danger small">{{ form.height.errors.0 }}</div>
|
|
{% endif %}
|
|
</div>
|
|
</div>
|
|
</fieldset>
|
|
<!-- END personal information -->
|
|
|
|
<!-- BEGIN contact information -->
|
|
<fieldset>
|
|
<legend class="mb-3">
|
|
<i class="fa fa-phone text-primary"></i> Contact Information
|
|
</legend>
|
|
|
|
<div class="row mb-3">
|
|
<div class="col-md-6">
|
|
<label class="form-label" for="{{ form.phone.id_for_label }}">
|
|
Phone Number <span class="text-danger">*</span>
|
|
</label>
|
|
{{ form.phone }}
|
|
{% if form.phone.errors %}
|
|
<div class="text-danger small">{{ form.phone.errors.0 }}</div>
|
|
{% endif %}
|
|
</div>
|
|
<div class="col-md-6">
|
|
<label class="form-label" for="{{ form.email.id_for_label }}">
|
|
Email Address
|
|
</label>
|
|
{{ form.email }}
|
|
{% if form.email.errors %}
|
|
<div class="text-danger small">{{ form.email.errors.0 }}</div>
|
|
{% endif %}
|
|
<div class="form-text">Optional but recommended</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="row mb-3">
|
|
<div class="col-12">
|
|
<label class="form-label" for="{{ form.address.id_for_label }}">
|
|
Address <span class="text-danger">*</span>
|
|
</label>
|
|
{{ form.address }}
|
|
{% if form.address.errors %}
|
|
<div class="text-danger small">{{ form.address.errors.0 }}</div>
|
|
{% endif %}
|
|
</div>
|
|
</div>
|
|
</fieldset>
|
|
<!-- END contact information -->
|
|
|
|
<!-- BEGIN emergency contact -->
|
|
<fieldset>
|
|
<legend class="mb-3">
|
|
<i class="fa fa-exclamation-triangle text-primary"></i> Emergency Contact
|
|
</legend>
|
|
|
|
<div class="row mb-3">
|
|
<div class="col-md-6">
|
|
<label class="form-label" for="{{ form.emergency_contact_name.id_for_label }}">
|
|
Emergency Contact Name <span class="text-danger">*</span>
|
|
</label>
|
|
{{ form.emergency_contact_name }}
|
|
{% if form.emergency_contact_name.errors %}
|
|
<div class="text-danger small">{{ form.emergency_contact_name.errors.0 }}</div>
|
|
{% endif %}
|
|
</div>
|
|
<div class="col-md-6">
|
|
<label class="form-label" for="{{ form.emergency_contact_phone.id_for_label }}">
|
|
Emergency Contact Phone <span class="text-danger">*</span>
|
|
</label>
|
|
{{ form.emergency_contact_phone }}
|
|
{% if form.emergency_contact_phone.errors %}
|
|
<div class="text-danger small">{{ form.emergency_contact_phone.errors.0 }}</div>
|
|
{% endif %}
|
|
</div>
|
|
</div>
|
|
</fieldset>
|
|
<!-- END emergency contact -->
|
|
|
|
<!-- BEGIN donor status -->
|
|
<fieldset>
|
|
<legend class="mb-3">
|
|
<i class="fa fa-cog text-primary"></i> Donor Status
|
|
</legend>
|
|
|
|
<div class="row mb-3">
|
|
<div class="col-md-6">
|
|
<label class="form-label" for="{{ form.donor_type.id_for_label }}">
|
|
Donor Type <span class="text-danger">*</span>
|
|
</label>
|
|
{{ form.donor_type }}
|
|
{% if form.donor_type.errors %}
|
|
<div class="text-danger small">{{ form.donor_type.errors.0 }}</div>
|
|
{% endif %}
|
|
</div>
|
|
<div class="col-md-6">
|
|
<label class="form-label" for="{{ form.status.id_for_label }}">
|
|
Status <span class="text-danger">*</span>
|
|
</label>
|
|
{{ form.status }}
|
|
{% if form.status.errors %}
|
|
<div class="text-danger small">{{ form.status.errors.0 }}</div>
|
|
{% endif %}
|
|
</div>
|
|
</div>
|
|
|
|
<div class="row mb-3">
|
|
<div class="col-12">
|
|
<label class="form-label" for="{{ form.notes.id_for_label }}">
|
|
Notes
|
|
</label>
|
|
{{ form.notes }}
|
|
{% if form.notes.errors %}
|
|
<div class="text-danger small">{{ form.notes.errors.0 }}</div>
|
|
{% endif %}
|
|
<div class="form-text">Any additional information about the donor</div>
|
|
</div>
|
|
</div>
|
|
</fieldset>
|
|
<!-- END donor status -->
|
|
|
|
<!-- BEGIN form actions -->
|
|
<div class="row">
|
|
<div class="col-12">
|
|
<hr>
|
|
<div class="d-flex justify-content-between">
|
|
<a href="{% url 'blood_bank:donor_list' %}" class="btn btn-default">
|
|
<i class="fa fa-times"></i> Cancel
|
|
</a>
|
|
<div>
|
|
<button type="button" class="btn btn-info" onclick="validateForm()">
|
|
<i class="fa fa-check-circle"></i> Validate
|
|
</button>
|
|
<button type="submit" class="btn btn-primary">
|
|
<i class="fa fa-save"></i> Save Donor
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<!-- END form actions -->
|
|
</form>
|
|
</div>
|
|
</div>
|
|
<!-- END panel -->
|
|
{% endblock %}
|
|
|
|
{% block js %}
|
|
<script src="{% static 'plugins/bootstrap-datepicker/dist/js/bootstrap-datepicker.min.js' %}"></script>
|
|
<script src="{% static 'plugins/select2/dist/js/select2.min.js' %}"></script>
|
|
{#<script src="{% static 'plugins/jquery-mask/dist/jquery.mask.min.js' %}"></script>#}
|
|
|
|
<script>
|
|
$(document).ready(function() {
|
|
// Initialize Select2 for dropdowns
|
|
$('.form-select').select2({
|
|
theme: 'bootstrap-5',
|
|
width: '100%'
|
|
});
|
|
|
|
// Initialize date picker
|
|
$('#{{ form.date_of_birth.id_for_label }}').datepicker({
|
|
format: 'yyyy-mm-dd',
|
|
autoclose: true,
|
|
todayHighlight: true,
|
|
endDate: '-18y',
|
|
startDate: '-65y'
|
|
});
|
|
|
|
// Phone number masking
|
|
$('#{{ form.phone.id_for_label }}').mask('(000) 000-0000');
|
|
$('#{{ form.emergency_contact_phone.id_for_label }}').mask('(000) 000-0000');
|
|
|
|
// Calculate age when date of birth changes
|
|
$('#{{ form.date_of_birth.id_for_label }}').on('change', function() {
|
|
var dob = new Date($(this).val());
|
|
var today = new Date();
|
|
var age = Math.floor((today - dob) / (365.25 * 24 * 60 * 60 * 1000));
|
|
|
|
if (age >= 18 && age <= 65) {
|
|
$('#ageDisplay').html('<span class="badge bg-success">Age: ' + age + ' years (Eligible)</span>');
|
|
} else if (age < 18) {
|
|
$('#ageDisplay').html('<span class="badge bg-danger">Age: ' + age + ' years (Too Young)</span>');
|
|
} else {
|
|
$('#ageDisplay').html('<span class="badge bg-danger">Age: ' + age + ' years (Too Old)</span>');
|
|
}
|
|
});
|
|
|
|
// Weight validation
|
|
$('#{{ form.weight.id_for_label }}').on('input', function() {
|
|
var weight = parseFloat($(this).val());
|
|
var feedback = $(this).siblings('.form-text');
|
|
|
|
if (weight < 45) {
|
|
feedback.html('<span class="text-danger">Weight too low for donation (minimum 45 kg)</span>');
|
|
} else {
|
|
feedback.html('<span class="text-success">Weight acceptable for donation</span>');
|
|
}
|
|
});
|
|
|
|
// Auto-generate donor ID if empty
|
|
$('#{{ form.first_name.id_for_label }}, #{{ form.last_name.id_for_label }}').on('blur', function() {
|
|
var donorId = $('#{{ form.donor_id.id_for_label }}').val();
|
|
if (!donorId) {
|
|
var firstName = $('#{{ form.first_name.id_for_label }}').val();
|
|
var lastName = $('#{{ form.last_name.id_for_label }}').val();
|
|
|
|
if (firstName && lastName) {
|
|
var timestamp = new Date().getTime().toString().slice(-6);
|
|
var generatedId = 'D' + firstName.charAt(0).toUpperCase() +
|
|
lastName.charAt(0).toUpperCase() + timestamp;
|
|
$('#{{ form.donor_id.id_for_label }}').val(generatedId);
|
|
}
|
|
}
|
|
});
|
|
});
|
|
|
|
function validateForm() {
|
|
var isValid = true;
|
|
var errors = [];
|
|
|
|
// Check required fields
|
|
var requiredFields = [
|
|
'{{ form.donor_id.id_for_label }}',
|
|
'{{ form.first_name.id_for_label }}',
|
|
'{{ form.last_name.id_for_label }}',
|
|
'{{ form.date_of_birth.id_for_label }}',
|
|
'{{ form.gender.id_for_label }}',
|
|
'{{ form.blood_group.id_for_label }}',
|
|
'{{ form.weight.id_for_label }}',
|
|
'{{ form.height.id_for_label }}',
|
|
'{{ form.phone.id_for_label }}',
|
|
'{{ form.address.id_for_label }}',
|
|
'{{ form.emergency_contact_name.id_for_label }}',
|
|
'{{ form.emergency_contact_phone.id_for_label }}'
|
|
];
|
|
|
|
requiredFields.forEach(function(fieldId) {
|
|
var field = $('#' + fieldId);
|
|
if (!field.val()) {
|
|
isValid = false;
|
|
errors.push(field.prev('label').text().replace(' *', '') + ' is required');
|
|
field.addClass('is-invalid');
|
|
} else {
|
|
field.removeClass('is-invalid');
|
|
}
|
|
});
|
|
|
|
// Validate age
|
|
var dob = new Date($('#{{ form.date_of_birth.id_for_label }}').val());
|
|
var today = new Date();
|
|
var age = Math.floor((today - dob) / (365.25 * 24 * 60 * 60 * 1000));
|
|
|
|
if (age < 18 || age > 65) {
|
|
isValid = false;
|
|
errors.push('Donor must be between 18 and 65 years old');
|
|
}
|
|
|
|
// Validate weight
|
|
var weight = parseFloat($('#{{ form.weight.id_for_label }}').val());
|
|
if (weight < 45) {
|
|
isValid = false;
|
|
errors.push('Minimum weight for donation is 45 kg');
|
|
}
|
|
|
|
// Show validation results
|
|
if (isValid) {
|
|
Swal.fire({
|
|
icon: 'success',
|
|
title: 'Validation Successful',
|
|
text: 'All fields are valid. You can now save the donor.',
|
|
confirmButtonText: 'OK'
|
|
});
|
|
} else {
|
|
Swal.fire({
|
|
icon: 'error',
|
|
title: 'Validation Failed',
|
|
html: '<ul class="text-start"><li>' + errors.join('</li><li>') + '</li></ul>',
|
|
confirmButtonText: 'Fix Errors'
|
|
});
|
|
}
|
|
}
|
|
|
|
// Form submission validation
|
|
$('#donorForm').on('submit', function(e) {
|
|
var weight = parseFloat($('#{{ form.weight.id_for_label }}').val());
|
|
var dob = new Date($('#{{ form.date_of_birth.id_for_label }}').val());
|
|
var today = new Date();
|
|
var age = Math.floor((today - dob) / (365.25 * 24 * 60 * 60 * 1000));
|
|
|
|
if (weight < 45 || age < 18 || age > 65) {
|
|
e.preventDefault();
|
|
Swal.fire({
|
|
icon: 'warning',
|
|
title: 'Invalid Data',
|
|
text: 'Please check the donor eligibility criteria before saving.',
|
|
confirmButtonText: 'OK'
|
|
});
|
|
}
|
|
});
|
|
</script>
|
|
{% endblock %}
|
|
|