274 lines
11 KiB
HTML
274 lines
11 KiB
HTML
{% extends "layouts/base.html" %}
|
|
{% load i18n %}
|
|
|
|
{% block title %}{% trans "Acknowledgement Checklist" %}{% endblock %}
|
|
|
|
{% block content %}
|
|
<div class="container-fluid py-4">
|
|
<div class="row">
|
|
<!-- Progress Sidebar -->
|
|
<div class="col-lg-3 mb-4">
|
|
<div class="card">
|
|
<div class="card-body">
|
|
<h5 class="card-title mb-3">{% trans "Progress" %}</h5>
|
|
|
|
<div class="progress mb-3" style="height: 10px;">
|
|
<div class="progress-bar bg-success" role="progressbar"
|
|
style="width: {{ progress_percentage }}%"
|
|
aria-valuenow="{{ progress_percentage }}"
|
|
aria-valuemin="0" aria-valuemax="100">
|
|
{{ progress_percentage }}%
|
|
</div>
|
|
</div>
|
|
|
|
<div class="alert alert-info small">
|
|
<strong>{% trans "Completed" %}:</strong> {{ acknowledged_count }} / {{ total_count }}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Checklist -->
|
|
<div class="col-lg-9">
|
|
<div class="card shadow-sm">
|
|
<div class="card-header bg-primary text-white">
|
|
<h4 class="mb-0">
|
|
<i class="bi bi-clipboard-check me-2"></i>
|
|
{% trans "Acknowledgement Checklist" %}
|
|
</h4>
|
|
</div>
|
|
<div class="card-body p-5">
|
|
<div class="alert alert-warning mb-4">
|
|
<i class="bi bi-exclamation-triangle me-2"></i>
|
|
{% trans "Please review and acknowledge all required items below. Your digital signature will be recorded for compliance purposes." %}
|
|
</div>
|
|
|
|
<form id="checklistForm">
|
|
<div class="list-group mb-4">
|
|
{% for item in checklist_items %}
|
|
<div class="list-group-item {% if item.is_required %}list-group-item-action{% endif %}">
|
|
<div class="d-flex align-items-start">
|
|
<div class="form-check flex-grow-1">
|
|
<input class="form-check-input"
|
|
type="checkbox"
|
|
id="item_{{ item.id }}"
|
|
value="{{ item.id }}"
|
|
{% if item.is_acknowledged %}checked disabled{% endif %}
|
|
onchange="toggleItem(this, '{{ item.id }}')"
|
|
{% if not item.is_required %}data-required="false"{% endif %}>
|
|
<label class="form-check-label" for="item_{{ item.id }}">
|
|
<strong>
|
|
{% if request.user.language == 'ar' %}{{ item.text_ar }}{% else %}{{ item.text_en }}{% endif %}
|
|
</strong>
|
|
{% if item.is_required %}
|
|
<span class="badge bg-danger ms-2">{% trans "Required" %}</span>
|
|
{% endif %}
|
|
</label>
|
|
|
|
{% if item.description_en %}
|
|
<p class="text-muted small mt-2 mb-0">
|
|
{% if request.user.language == 'ar' %}{{ item.description_ar }}{% else %}{{ item.description_en }}{% endif %}
|
|
</p>
|
|
{% endif %}
|
|
|
|
{% if item.content %}
|
|
<p class="text-info small mb-0">
|
|
<i class="bi bi-link me-1"></i>
|
|
{% if request.user.language == 'ar' %}{{ item.content.title_ar }}{% else %}{{ item.content.title_en }}{% endif %}
|
|
</p>
|
|
{% endif %}
|
|
</div>
|
|
|
|
{% if item.is_acknowledged %}
|
|
<i class="bi bi-check-circle text-success fa-2x ms-3"></i>
|
|
{% endif %}
|
|
</div>
|
|
</div>
|
|
{% endfor %}
|
|
</div>
|
|
|
|
<div id="signatureSection" class="mb-4" style="display: none;">
|
|
<hr class="my-4">
|
|
<h5 class="mb-3">{% trans "Digital Signature" %}</h5>
|
|
<div class="alert alert-info">
|
|
{% trans "By providing your digital signature below, you acknowledge that you have read, understood, and agreed to all the items listed above." %}
|
|
</div>
|
|
|
|
<canvas id="signatureCanvas" class="border rounded"
|
|
style="width: 100%; height: 200px; cursor: crosshair;"></canvas>
|
|
|
|
<div class="mt-2">
|
|
<button type="button" onclick="clearSignature()" class="btn btn-sm btn-outline-secondary">
|
|
<i class="bi bi-eraser me-1"></i> {% trans "Clear" %}
|
|
</button>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="d-grid gap-2">
|
|
<button type="button" id="proceedBtn"
|
|
onclick="proceedToActivation()"
|
|
class="btn btn-primary btn-lg"
|
|
disabled>
|
|
<i class="bi bi-arrow-right me-2"></i>
|
|
{% trans "Proceed to Account Setup" %}
|
|
</button>
|
|
<button type="button" onclick="goBack()" class="btn btn-outline-secondary">
|
|
<i class="bi bi-arrow-left me-2"></i>
|
|
{% trans "Back to Content" %}
|
|
</button>
|
|
</div>
|
|
</form>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<script>
|
|
let requiredItems = {{ required_items_json|safe }};
|
|
let acknowledgedItems = new Set();
|
|
let isSigning = false;
|
|
|
|
// Initialize
|
|
document.addEventListener('DOMContentLoaded', function() {
|
|
// Load acknowledged items
|
|
{% for item in checklist_items %}
|
|
{% if item.is_acknowledged %}
|
|
acknowledgedItems.add('{{ item.id }}');
|
|
{% endif %}
|
|
{% endfor %}
|
|
|
|
checkProgress();
|
|
initSignaturePad();
|
|
});
|
|
|
|
function toggleItem(checkbox, itemId) {
|
|
if (checkbox.checked) {
|
|
acknowledgedItems.add(itemId);
|
|
} else {
|
|
acknowledgedItems.delete(itemId);
|
|
}
|
|
|
|
// Save acknowledgement
|
|
fetch('/api/accounts/users/onboarding/acknowledge/', {
|
|
method: 'POST',
|
|
headers: {
|
|
'Content-Type': 'application/json',
|
|
'Authorization': 'Bearer ' + localStorage.getItem('token')
|
|
},
|
|
body: JSON.stringify({
|
|
checklist_item_id: itemId
|
|
})
|
|
})
|
|
.then(response => response.json())
|
|
.then(data => {
|
|
if (!data.success) {
|
|
checkbox.checked = !checkbox.checked;
|
|
alert('Error: ' + (data.error || 'Failed to save acknowledgement'));
|
|
}
|
|
checkProgress();
|
|
});
|
|
}
|
|
|
|
function checkProgress() {
|
|
let allRequiredAck = true;
|
|
requiredItems.forEach(id => {
|
|
if (!acknowledgedItems.has(id)) {
|
|
allRequiredAck = false;
|
|
}
|
|
});
|
|
|
|
const proceedBtn = document.getElementById('proceedBtn');
|
|
const signatureSection = document.getElementById('signatureSection');
|
|
|
|
if (allRequiredAck) {
|
|
proceedBtn.disabled = false;
|
|
signatureSection.style.display = 'block';
|
|
} else {
|
|
proceedBtn.disabled = true;
|
|
signatureSection.style.display = 'none';
|
|
}
|
|
}
|
|
|
|
function initSignaturePad() {
|
|
const canvas = document.getElementById('signatureCanvas');
|
|
const ctx = canvas.getContext('2d');
|
|
let isDrawing = false;
|
|
|
|
// Set canvas size
|
|
canvas.width = canvas.offsetWidth;
|
|
canvas.height = canvas.offsetHeight;
|
|
|
|
canvas.addEventListener('mousedown', startDrawing);
|
|
canvas.addEventListener('mousemove', draw);
|
|
canvas.addEventListener('mouseup', stopDrawing);
|
|
canvas.addEventListener('mouseout', stopDrawing);
|
|
|
|
// Touch support
|
|
canvas.addEventListener('touchstart', handleTouch);
|
|
canvas.addEventListener('touchmove', handleTouch);
|
|
canvas.addEventListener('touchend', stopDrawing);
|
|
|
|
function startDrawing(e) {
|
|
isDrawing = true;
|
|
draw(e);
|
|
}
|
|
|
|
function draw(e) {
|
|
if (!isDrawing) return;
|
|
|
|
const rect = canvas.getBoundingClientRect();
|
|
const x = e.clientX - rect.left;
|
|
const y = e.clientY - rect.top;
|
|
|
|
ctx.lineWidth = 2;
|
|
ctx.lineCap = 'round';
|
|
ctx.strokeStyle = '#000';
|
|
|
|
ctx.lineTo(x, y);
|
|
ctx.stroke();
|
|
ctx.beginPath();
|
|
ctx.moveTo(x, y);
|
|
}
|
|
|
|
function stopDrawing() {
|
|
isDrawing = false;
|
|
ctx.beginPath();
|
|
}
|
|
|
|
function handleTouch(e) {
|
|
e.preventDefault();
|
|
const touch = e.touches[0];
|
|
const mouseEvent = new MouseEvent(e.type === 'touchstart' ? 'mousedown' : 'mousemove', {
|
|
clientX: touch.clientX,
|
|
clientY: touch.clientY
|
|
});
|
|
canvas.dispatchEvent(mouseEvent);
|
|
}
|
|
|
|
window.signatureCanvas = canvas;
|
|
window.signatureCtx = ctx;
|
|
}
|
|
|
|
function clearSignature() {
|
|
const canvas = window.signatureCanvas;
|
|
const ctx = window.signatureCtx;
|
|
ctx.clearRect(0, 0, canvas.width, canvas.height);
|
|
}
|
|
|
|
function proceedToActivation() {
|
|
const canvas = window.signatureCanvas;
|
|
const signatureData = canvas.toDataURL('image/png');
|
|
|
|
// Store signature for final submission
|
|
localStorage.setItem('onboardingSignature', signatureData);
|
|
|
|
window.location.href = '/accounts/onboarding/wizard/activation/';
|
|
}
|
|
|
|
function goBack() {
|
|
window.location.href = '/accounts/onboarding/wizard/step/1/';
|
|
}
|
|
</script>
|
|
{% endblock %}
|