238 lines
9.9 KiB
HTML
238 lines
9.9 KiB
HTML
{% extends "layouts/base.html" %}
|
|
{% load i18n %}
|
|
|
|
{% block title %}{% trans "Account Activation" %}{% endblock %}
|
|
|
|
{% block content %}
|
|
<div class="container-fluid py-5">
|
|
<div class="row justify-content-center">
|
|
<div class="col-lg-6">
|
|
<div class="card shadow-lg border-0">
|
|
<div class="card-header bg-success text-white">
|
|
<h4 class="mb-0 text-center">
|
|
<i class="bi bi-person-check me-2"></i>
|
|
{% trans "Create Your Account" %}
|
|
</h4>
|
|
</div>
|
|
<div class="card-body p-5">
|
|
<div class="alert alert-success mb-4">
|
|
<i class="bi bi-check-circle me-2"></i>
|
|
{% trans "Congratulations! You have completed the onboarding process. Now create your account credentials to get started." %}
|
|
</div>
|
|
|
|
<form id="activationForm">
|
|
<div class="mb-3">
|
|
<label for="username" class="form-label">
|
|
<i class="bi bi-person me-2"></i>{% trans "Username" %}
|
|
</label>
|
|
<input type="text"
|
|
class="form-control form-control-lg"
|
|
id="username"
|
|
name="username"
|
|
required
|
|
minlength="3"
|
|
pattern="[a-zA-Z0-9_-]+"
|
|
title="{% trans 'Username can only contain letters, numbers, underscores, and hyphens' %}">
|
|
<div class="form-text">
|
|
{% trans "Choose a unique username (3+ characters)" %}
|
|
</div>
|
|
</div>
|
|
|
|
<div class="mb-3">
|
|
<label for="emailDisplay" class="form-label">
|
|
<i class="bi bi-envelope me-2"></i>{% trans "Email" %}
|
|
</label>
|
|
<input type="email"
|
|
class="form-control form-control-lg"
|
|
id="emailDisplay"
|
|
name="emailDisplay"
|
|
value="{{ user.email }}"
|
|
readonly
|
|
style="background-color: #f8f9fa;">
|
|
</div>
|
|
|
|
<div class="mb-3">
|
|
<label for="password" class="form-label">
|
|
<i class="bi bi-lock me-2"></i>{% trans "Password" %}
|
|
</label>
|
|
<input type="password"
|
|
class="form-control form-control-lg"
|
|
id="password"
|
|
name="password"
|
|
required
|
|
minlength="8">
|
|
<div class="form-text">
|
|
{% trans "Minimum 8 characters" %}
|
|
</div>
|
|
|
|
<!-- Password Strength Indicator -->
|
|
<div class="progress mt-2" style="height: 5px;">
|
|
<div id="passwordStrength" class="progress-bar"
|
|
style="width: 0%"
|
|
role="progressbar"></div>
|
|
</div>
|
|
<small id="passwordStrengthText" class="text-muted"></small>
|
|
</div>
|
|
|
|
<div class="mb-3">
|
|
<label for="password_confirm" class="form-label">
|
|
<i class="bi bi-lock me-2"></i>{% trans "Confirm Password" %}
|
|
</label>
|
|
<input type="password"
|
|
class="form-control form-control-lg"
|
|
id="password_confirm"
|
|
name="password_confirm"
|
|
required
|
|
oninput="checkPasswordMatch()">
|
|
<div id="passwordMatch" class="form-text"></div>
|
|
</div>
|
|
|
|
<div class="mb-4">
|
|
<div class="alert alert-info">
|
|
<i class="bi bi-info-circle me-2"></i>
|
|
{% trans "Your digital signature from the previous step will be attached to your account activation for compliance records." %}
|
|
</div>
|
|
</div>
|
|
|
|
<div class="d-grid gap-2">
|
|
<button type="submit" id="activateBtn" class="btn btn-success btn-lg">
|
|
<i class="bi bi-rocket-takeoff me-2"></i>
|
|
{% trans "Activate Account" %}
|
|
</button>
|
|
<button type="button" onclick="goBack()" class="btn btn-outline-secondary">
|
|
<i class="bi bi-arrow-left me-2"></i>
|
|
{% trans "Back" %}
|
|
</button>
|
|
</div>
|
|
</form>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<script>
|
|
document.addEventListener('DOMContentLoaded', function() {
|
|
const passwordInput = document.getElementById('password');
|
|
const passwordStrength = document.getElementById('passwordStrength');
|
|
const passwordStrengthText = document.getElementById('passwordStrengthText');
|
|
|
|
passwordInput.addEventListener('input', function() {
|
|
const password = this.value;
|
|
let strength = 0;
|
|
let text = '';
|
|
let color = '';
|
|
|
|
if (password.length >= 8) strength += 25;
|
|
if (password.match(/[a-z]/)) strength += 25;
|
|
if (password.match(/[A-Z]/)) strength += 25;
|
|
if (password.match(/[0-9]/)) strength += 25;
|
|
|
|
if (strength < 25) {
|
|
text = '{% trans "Very Weak" %}';
|
|
color = 'bg-danger';
|
|
} else if (strength < 50) {
|
|
text = '{% trans "Weak" %}';
|
|
color = 'bg-warning';
|
|
} else if (strength < 75) {
|
|
text = '{% trans "Good" %}';
|
|
color = 'bg-info';
|
|
} else {
|
|
text = '{% trans "Strong" %}';
|
|
color = 'bg-success';
|
|
}
|
|
|
|
passwordStrength.style.width = strength + '%';
|
|
passwordStrength.className = 'progress-bar ' + color;
|
|
passwordStrengthText.textContent = text;
|
|
});
|
|
|
|
document.getElementById('activationForm').addEventListener('submit', function(e) {
|
|
e.preventDefault();
|
|
activateAccount();
|
|
});
|
|
});
|
|
|
|
function checkPasswordMatch() {
|
|
const password = document.getElementById('password').value;
|
|
const confirm = document.getElementById('password_confirm').value;
|
|
const matchDiv = document.getElementById('passwordMatch');
|
|
|
|
if (confirm) {
|
|
if (password === confirm) {
|
|
matchDiv.innerHTML = '<span class="text-success"><i class="bi bi-check"></i> {% trans "Passwords match" %}</span>';
|
|
return true;
|
|
} else {
|
|
matchDiv.innerHTML = '<span class="text-danger"><i class="bi bi-x"></i> {% trans "Passwords do not match" %}</span>';
|
|
return false;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
function activateAccount() {
|
|
const form = document.getElementById('activationForm');
|
|
const username = document.getElementById('username').value;
|
|
const password = document.getElementById('password').value;
|
|
const password_confirm = document.getElementById('password_confirm').value;
|
|
const signature = localStorage.getItem('onboardingSignature') || '';
|
|
|
|
if (!username || !password || !password_confirm) {
|
|
alert('{% trans "Please fill in all fields" %}');
|
|
return;
|
|
}
|
|
|
|
if (password !== password_confirm) {
|
|
alert('{% trans "Passwords do not match" %}');
|
|
return;
|
|
}
|
|
|
|
if (password.length < 8) {
|
|
alert('{% trans "Password must be at least 8 characters" %}');
|
|
return;
|
|
}
|
|
|
|
const activateBtn = document.getElementById('activateBtn');
|
|
activateBtn.disabled = true;
|
|
activateBtn.innerHTML = '<i class="bi bi-arrow-clockwise fa-spin me-2"></i>{% trans "Activating..." %}';
|
|
|
|
fetch('/api/accounts/users/onboarding/complete/', {
|
|
method: 'POST',
|
|
headers: {
|
|
'Content-Type': 'application/json',
|
|
'Authorization': 'Bearer ' + localStorage.getItem('token')
|
|
},
|
|
body: JSON.stringify({
|
|
username: username,
|
|
password: password,
|
|
password_confirm: password_confirm,
|
|
signature: signature
|
|
})
|
|
})
|
|
.then(response => response.json())
|
|
.then(data => {
|
|
if (data.message === 'Account activated successfully') {
|
|
// Clear stored signature
|
|
localStorage.removeItem('onboardingSignature');
|
|
|
|
// Show success message and redirect
|
|
window.location.href = '/accounts/onboarding/complete/';
|
|
} else {
|
|
activateBtn.disabled = false;
|
|
activateBtn.innerHTML = '<i class="bi bi-rocket-takeoff me-2"></i>{% trans "Activate Account" %}';
|
|
alert('Error: ' + (data.error || 'Failed to activate account'));
|
|
}
|
|
})
|
|
.catch(error => {
|
|
activateBtn.disabled = false;
|
|
activateBtn.innerHTML = '<i class="bi bi-rocket-takeoff me-2"></i>{% trans "Activate Account" %}';
|
|
alert('{% trans "An error occurred. Please try again." %}');
|
|
});
|
|
}
|
|
|
|
function goBack() {
|
|
window.location.href = '/accounts/onboarding/wizard/checklist/';
|
|
}
|
|
</script>
|
|
{% endblock %}
|