274 lines
9.6 KiB
HTML
274 lines
9.6 KiB
HTML
{% extends "base.html" %}
|
|
|
|
{% block title %}Register - {{ app_name }}{% endblock %}
|
|
|
|
{% block content %}
|
|
<div class="min-h-screen flex items-center justify-center -mt-8">
|
|
<div class="w-full max-w-md">
|
|
<div class="card p-6 md:p-8">
|
|
<h2 class="text-3xl font-bold mb-2 text-center">Create Account</h2>
|
|
<p class="text-center text-slate-400 mb-6">Join {{ app_name }} today</p>
|
|
|
|
<div id="errorMsg" class="hidden mb-4 alert alert-error"></div>
|
|
<div id="successMsg" class="hidden mb-4 alert alert-success"></div>
|
|
|
|
<form id="registerForm" class="space-y-4" novalidate>
|
|
<div class="form-group">
|
|
<label for="email" class="form-label">Email Address</label>
|
|
<input
|
|
type="email"
|
|
name="email"
|
|
id="email"
|
|
required
|
|
class="form-input"
|
|
placeholder="you@example.com"
|
|
autocomplete="email"
|
|
maxlength="254"
|
|
>
|
|
<span id="emailError" class="text-xs text-red-400 mt-1 hidden"></span>
|
|
</div>
|
|
|
|
<div class="form-group">
|
|
<label for="password" class="form-label">Password</label>
|
|
<input
|
|
type="password"
|
|
name="password"
|
|
id="password"
|
|
required
|
|
class="form-input"
|
|
placeholder="••••••••"
|
|
autocomplete="new-password"
|
|
minlength="8"
|
|
maxlength="128"
|
|
>
|
|
<p class="mt-2 text-xs text-slate-400">Minimum 8 characters</p>
|
|
<span id="passwordError" class="text-xs text-red-400 mt-1 hidden"></span>
|
|
</div>
|
|
|
|
<div class="form-group">
|
|
<label for="passwordConfirm" class="form-label">Confirm Password</label>
|
|
<input
|
|
type="password"
|
|
name="passwordConfirm"
|
|
id="passwordConfirm"
|
|
required
|
|
class="form-input"
|
|
placeholder="••••••••"
|
|
autocomplete="new-password"
|
|
minlength="8"
|
|
maxlength="128"
|
|
>
|
|
<span id="confirmError" class="text-xs text-red-400 mt-1 hidden"></span>
|
|
</div>
|
|
|
|
<div class="flex items-start">
|
|
<input
|
|
type="checkbox"
|
|
name="terms"
|
|
id="terms"
|
|
required
|
|
class="w-4 h-4 bg-slate-700 border border-slate-600 rounded cursor-pointer mt-1"
|
|
>
|
|
<label for="terms" class="ml-2 text-sm text-slate-400 cursor-pointer">
|
|
I agree to the Terms of Service
|
|
</label>
|
|
</div>
|
|
<span id="termsError" class="text-xs text-red-400 mt-1 hidden block"></span>
|
|
|
|
<button
|
|
type="submit"
|
|
class="btn-primary w-full mt-6"
|
|
id="submitBtn"
|
|
>
|
|
Create Account
|
|
</button>
|
|
</form>
|
|
|
|
<div class="mt-6 text-center">
|
|
<p class="text-slate-400">
|
|
Already have an account?
|
|
<a href="{{ url_for('login') }}" class="text-sky-400 hover:text-sky-300 font-semibold transition-colors">
|
|
Sign in
|
|
</a>
|
|
</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<script>
|
|
document.addEventListener('DOMContentLoaded', () => {
|
|
if (isAuthenticated()) {
|
|
window.location.href = "{{ url_for('dashboard') }}";
|
|
}
|
|
});
|
|
|
|
const registerForm = document.getElementById('registerForm');
|
|
const errorMsg = document.getElementById('errorMsg');
|
|
const successMsg = document.getElementById('successMsg');
|
|
const submitBtn = document.getElementById('submitBtn');
|
|
|
|
function showError(message) {
|
|
errorMsg.textContent = message;
|
|
errorMsg.classList.remove('hidden');
|
|
successMsg.classList.add('hidden');
|
|
}
|
|
|
|
function showSuccess(message) {
|
|
successMsg.textContent = message;
|
|
successMsg.classList.remove('hidden');
|
|
errorMsg.classList.add('hidden');
|
|
}
|
|
|
|
function clearMessages() {
|
|
errorMsg.classList.add('hidden');
|
|
successMsg.classList.add('hidden');
|
|
}
|
|
|
|
function validateEmail(email) {
|
|
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
|
|
return emailRegex.test(email) && email.length <= 254;
|
|
}
|
|
|
|
function validateForm() {
|
|
clearMessages();
|
|
const email = document.getElementById('email').value.trim();
|
|
const password = document.getElementById('password').value;
|
|
const passwordConfirm = document.getElementById('passwordConfirm').value;
|
|
const terms = document.getElementById('terms').checked;
|
|
|
|
const emailError = document.getElementById('emailError');
|
|
const passwordError = document.getElementById('passwordError');
|
|
const confirmError = document.getElementById('confirmError');
|
|
const termsError = document.getElementById('termsError');
|
|
|
|
let isValid = true;
|
|
|
|
// Validate email
|
|
if (!email) {
|
|
emailError.textContent = 'Email is required';
|
|
emailError.classList.remove('hidden');
|
|
isValid = false;
|
|
} else if (!validateEmail(email)) {
|
|
emailError.textContent = 'Please enter a valid email address';
|
|
emailError.classList.remove('hidden');
|
|
isValid = false;
|
|
} else {
|
|
emailError.classList.add('hidden');
|
|
}
|
|
|
|
// Validate password
|
|
if (!password) {
|
|
passwordError.textContent = 'Password is required';
|
|
passwordError.classList.remove('hidden');
|
|
isValid = false;
|
|
} else if (password.length < 8) {
|
|
passwordError.textContent = 'Password must be at least 8 characters';
|
|
passwordError.classList.remove('hidden');
|
|
isValid = false;
|
|
} else {
|
|
passwordError.classList.add('hidden');
|
|
}
|
|
|
|
// Validate password confirmation
|
|
if (!passwordConfirm) {
|
|
confirmError.textContent = 'Please confirm your password';
|
|
confirmError.classList.remove('hidden');
|
|
isValid = false;
|
|
} else if (password !== passwordConfirm) {
|
|
confirmError.textContent = 'Passwords do not match';
|
|
confirmError.classList.remove('hidden');
|
|
isValid = false;
|
|
} else {
|
|
confirmError.classList.add('hidden');
|
|
}
|
|
|
|
// Validate terms
|
|
if (!terms) {
|
|
termsError.textContent = 'You must agree to the Terms of Service';
|
|
termsError.classList.remove('hidden');
|
|
isValid = false;
|
|
} else {
|
|
termsError.classList.add('hidden');
|
|
}
|
|
|
|
return isValid;
|
|
}
|
|
|
|
registerForm.addEventListener('submit', async (e) => {
|
|
e.preventDefault();
|
|
|
|
// Validate form
|
|
if (!validateForm()) {
|
|
showError('Please correct the errors above');
|
|
return;
|
|
}
|
|
|
|
// Get form values
|
|
const email = document.getElementById('email').value.trim().toLowerCase();
|
|
const password = document.getElementById('password').value;
|
|
|
|
// Disable submit button
|
|
submitBtn.disabled = true;
|
|
submitBtn.textContent = 'Creating account...';
|
|
|
|
const data = {
|
|
email: email,
|
|
password: password
|
|
};
|
|
|
|
try {
|
|
const response = await fetch('/api/auth/register', {
|
|
method: 'POST',
|
|
headers: {
|
|
'Content-Type': 'application/json'
|
|
},
|
|
body: JSON.stringify(data)
|
|
});
|
|
|
|
if (response.ok) {
|
|
showSuccess('Account created successfully! Redirecting to login...');
|
|
setTimeout(() => {
|
|
window.location.href = "{{ url_for('login') }}";
|
|
}, 1500);
|
|
} else {
|
|
const error = await response.json();
|
|
const errorDetail = error.detail || 'Registration failed. Please try again.';
|
|
|
|
// Handle specific error cases
|
|
if (typeof errorDetail === 'string' && errorDetail.includes('already exists')) {
|
|
showError('This email is already registered. Please use a different email or try logging in.');
|
|
} else {
|
|
showError(errorDetail);
|
|
}
|
|
|
|
submitBtn.disabled = false;
|
|
submitBtn.textContent = 'Create Account';
|
|
}
|
|
} catch (error) {
|
|
console.error('Registration error:', error);
|
|
showError('An error occurred during registration. Please try again.');
|
|
submitBtn.disabled = false;
|
|
submitBtn.textContent = 'Create Account';
|
|
}
|
|
});
|
|
|
|
// Clear inline errors on input
|
|
document.getElementById('email').addEventListener('input', () => {
|
|
document.getElementById('emailError').classList.add('hidden');
|
|
});
|
|
|
|
document.getElementById('password').addEventListener('input', () => {
|
|
document.getElementById('passwordError').classList.add('hidden');
|
|
});
|
|
|
|
document.getElementById('passwordConfirm').addEventListener('input', () => {
|
|
document.getElementById('confirmError').classList.add('hidden');
|
|
});
|
|
|
|
document.getElementById('terms').addEventListener('change', () => {
|
|
document.getElementById('termsError').classList.add('hidden');
|
|
});
|
|
</script>
|
|
{% endblock %}
|