Legalmind / templates /forgot_password.html
Nguyendat92929's picture
upload file
8a15958 verified
<!DOCTYPE html>
<html lang="vi" data-theme="dark">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="description" content="Đăng nhập tài khoản của bạn một cách dễ dàng và an toàn">
<title>Đăng Nhập</title>
<link href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css" rel="stylesheet">
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600&display=swap" rel="stylesheet">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.2/css/all.min.css">
<link href="https://cdnjs.cloudflare.com/ajax/libs/jarallax/2.2.1/jarallax.min.css" rel="stylesheet">
<style>
:root {
--primary-color: #6366F1;
--error-color: #dc3545;
--success-color: #28a745;
--text-muted: #adb5bd;
--input-text: #000000; /* Default input text color */
}
[data-theme="dark"] {
--card-bg: rgba(13, 27, 42, 0.95);
--input-bg: #2c3e50;
--input-border: #3b4a5e;
--input-focus-bg: #34495e;
--alert-bg: #1b263b;
--input-text: #ffffff; /* White text for dark mode */
}
[data-theme="light"] {
--card-bg: rgba(255, 255, 255, 0.95);
--input-bg: #ffffff;
--input-border: #ced4da;
--input-focus-bg: #f8f9fa;
--alert-bg: #e9ecef;
--text-muted: #6c757d;
--input-text: #000000; /* Black text for light mode */
}
body {
background-color: #000000;
min-height: 100vh;
margin: 0;
display: flex;
justify-content: center;
align-items: center;
}
.form-label {
color: var(--text-muted);
font-size: 0.85rem;
font-weight: 500;
margin-bottom: 0.5rem;
}
.jarallax {
position: relative;
z-index: 0;
background-color: #000000;
min-height: 100vh;
width: 100%;
display: flex;
justify-content: center;
align-items: center;
}
.text-muted {
color: #cbd2d7 !important;
font-size: 0.85rem;
}
.text-muted, .form-check-label {
color: #cbd2d7 !important;
font-size: 0.85rem;
}
.btn-google {
background-color: #6366F1;
color: #fff;
border: none;
padding: 0.5rem;
width: 100%;
margin-bottom: 1rem;
display: flex;
align-items: center;
justify-content: center;
}
.btn-google img {
width: 20px;
margin-right: 0.5rem;
}
.jarallax-img {
position: absolute;
object-fit: cover;
top: 0;
left: 0;
width: 100%;
height: 100%;
z-index: -1;
}
.login-container {
background: var(--card-bg);
padding: 2.5rem;
border-radius: 12px;
width: 100%;
max-width: 450px;
box-shadow: 0 4px 20px rgba(0, 0, 0, 0.3);
backdrop-filter: blur(5px);
transition: transform 0.3s ease;
position: relative;
z-index: 1;
}
.login-container:hover {
transform: translateY(-2px);
}
.login-container h2 {
font-size: 1.75rem;
font-weight: 600;
margin-bottom: 1rem;
text-align: center;
color: #fff;
}
.description {
font-size: 0.9rem;
text-align: center;
margin-bottom: 2rem;
line-height: 1.5;
color: white;
}
.form-label {
font-size: 0.85rem;
font-weight: 500;
margin-bottom: 0.5rem;
}
.form-control {
background-color: var(--input-bg);
border: 1px solid var(--input-border);
color: var(--input-text); /* Use theme-based text color */
border-radius: 6px;
padding: 0.75rem;
transition: all 0.2s ease;
}
.form-control:focus {
background-color: var(--input-focus-bg);
border-color: var(--primary-color);
box-shadow: 0 0 0 3px rgba(99, 102, 241, 0.2);
outline: none;
}
.form-control::placeholder {
color: var(--input-text); /* White placeholder text in dark mode */
opacity: 0.7; /* Slightly reduce opacity for better UX */
}
.form-control.is-invalid {
border-color: var(--error-color);
background-image: none;
}
.form-control[readonly] {
color: var(--input-text); /* Ensure readonly input text is white in dark mode */
opacity: 0.9; /* Slightly reduce opacity for readonly fields */
}
.invalid-feedback {
font-size: 0.8rem;
color: var(--error-color);
}
.alert {
background-color: var(--alert-bg);
color: var(--text-muted);
border: none;
margin-bottom: 1rem;
font-size: 0.9rem;
border-radius: 6px;
}
.alert-success {
background-color: var(--success-color);
color: #fff;
}
.alert-danger {
background-color: var(--error-color);
color: #fff;
}
.btn-submit,
.btn-login,
.btn-google {
background: var(--primary-color);
color: #fff;
border: none;
padding: 0.85rem;
border-radius: 6px;
width: 100%;
font-weight: 500;
transition: all 0.2s ease;
position: relative;
display: flex;
align-items: center;
justify-content: center;
}
.btn-submit:hover:not(:disabled),
.btn-login:hover:not(:disabled),
.btn-google:hover:not(:disabled) {
background: #4f46e5;
transform: translateY(-1px);
}
.btn-login:hover {
color: #fff;
}
.btn-submit:disabled,
.btn-login:disabled,
.btn-google:disabled {
opacity: 0.6;
cursor: not-allowed;
}
.btn-google img {
width: 20px;
margin-right: 0.5rem;
}
.text-muted {
font-size: 0.85rem;
}
.theme-toggle-btn {
position: absolute;
top: 1rem;
right: 1rem;
background: transparent;
border: none;
color: var(--text-muted);
font-size: 1.2rem;
cursor: pointer;
transition: color 0.2s ease;
}
.theme-toggle-btn:hover {
color: var(--primary-color);
}
.loading-spinner {
display: none;
border: 3px solid #f3f3f3;
border-top: 3px solid var(--primary-color);
border-radius: 50%;
width: 20px;
height: 20px;
animation: spin 1s linear infinite;
position: absolute;
right: 10px;
top: 50%;
transform: translateY(-50%);
}
@keyframes spin {
0% {
transform: translateY(-50%) rotate(0deg);
}
100% {
transform: translateY(-50%) rotate(360deg);
}
}
@media (max-width: 576px) {
.login-container {
margin: 1.5rem;
padding: 1.5rem;
}
.login-container h2 {
font-size: 1.5rem;
}
.description {
font-size: 0.85rem;
}
.btn-submit,
.btn-login,
.btn-google {
padding: 0.75rem;
}
}
.sr-only {
position: absolute;
width: 1px;
height: 1px;
padding: 0;
margin: -1px;
overflow: hidden;
clip: rect(0, 0, 0, 0);
border: 0;
}
.form-control{
color: white !important; /* Ensure input text is white in dark mode */
}
</style>
</head>
<body>
<div class="jarallax" data-jarallax data-speed="0.2">
<img class="jarallax-img" src="https://silicon.createx.studio/assets/img/landing/saas-5/hero-bg-pattern.png"
alt="Background">
<div class="login-container">
<h2>Quên mật khẩu</h2>
<p class="description">Nhập email và 4 số cuối của số điện thoại để nhận mật khẩu mới.</p>
<div id="forgot-password-message"></div>
<form onsubmit="event.preventDefault(); forgotPassword();">
<div class="form-group mb-3">
<label for="email" class="form-label">Email</label>
<input type="email" class="form-control" id="email" required>
</div>
<div class="form-group mb-3">
<label for="masked_phone" class="form-label">Số điện thoại đã đăng ký (Tự động)</label>
<input type="text" class="form-control" id="masked_phone" readonly
aria-describedby="maskedPhoneFeedback">
<div id="maskedPhoneFeedback" class="invalid-feedback"></div>
</div>
<div class="form-group mb-3">
<label for="last_four_digits" class="form-label">4 số cuối của số điện thoại</label>
<input type="text" class="form-control" id="last_four_digits" maxlength="4"
aria-describedby="lastThreeDigitsFeedback">
<div id="lastThreeDigitsFeedback" class="invalid-feedback">Vui lòng nhập đúng 3 số cuối của số điện
thoại.</div>
</div>
<div class="mb-3 form-group ">
<a href="/register" class="float-start text-muted">Đăng ký ngay</a>
<a href="/login" class="float-end text-muted">Đăng nhập ngay</a>
</div>
<br>
<button type="submit" class="btn btn-login" id="submit-btn">
Gửi yêu cầu
<span class="loading-spinner"></span>
</button>
</form>
</div>
</div>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/js/bootstrap.bundle.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jarallax/2.2.1/jarallax.min.js"></script>
<script>
// Show messages
function showMessage(elementId, message, type = 'success') {
const messageDiv = document.getElementById(elementId);
messageDiv.innerHTML = `<div class="alert alert-${type}">${message}</div>`;
setTimeout(() => messageDiv.innerHTML = '', 5000);
}
// Fetch masked phone number
async function fetchMaskedPhone(emailInput, maskedPhoneInput) {
const email = emailInput.value.trim();
if (!email || !/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email)) {
maskedPhoneInput.value = '';
document.getElementById('maskedPhoneFeedback').textContent = 'Vui lòng nhập email hợp lệ';
maskedPhoneInput.classList.add('is-invalid');
return;
}
try {
document.getElementById('submit-btn').disabled = true;
document.querySelector('.loading-spinner').classList.add('active');
const response = await fetch('/get_masked_phone', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ email })
});
const data = await response.json();
if (data.error) {
maskedPhoneInput.value = '';
document.getElementById('maskedPhoneFeedback').textContent = data.error;
maskedPhoneInput.classList.add('is-invalid');
} else {
maskedPhoneInput.classList.remove('is-invalid');
document.getElementById('maskedPhoneFeedback').textContent = '';
maskedPhoneInput.value = data.masked_phone;
}
} catch (error) {
maskedPhoneInput.value = '';
document.getElementById('maskedPhoneFeedback').textContent = _action
'Lỗi hệ thống, vui lòng thử lại';
maskedPhoneInput.classList.add('is-invalid');
console.error('Error:', error);
} finally {
document.getElementById('submit-btn').disabled = false;
document.querySelector('.loading-spinner').classList.remove('active');
}
}
// Check session on page load
function checkSession() {
fetch('/check_session', {
method: 'GET',
headers: { 'Content-Type': 'application/json' }
})
.then(response => response.json())
.then(data => {
const authNav = document.getElementById('auth-nav');
if (data.logged_in) {
authNav.innerHTML = `
<li class="nav-item">
<span class="nav-link">Xin chào, ${data.username}</span>
</li>
<li class="nav-item">
<a class="nav-link" href="/change_password">Đổi mật khẩu</a>
</li>
<li class="nav-item">
<a class="nav-link" href="#" onclick="logout()">Đăng xuất</a>
</li>
`;
} else {
authNav.innerHTML = `
<li class="nav-item">
<a class="nav-link" href="/login">Đăng nhập</a>
</li>
<li class="nav-item">
<a class="nav-link" href="/register">Đăng ký</a>
</li>
`;
}
})
.catch(error => console.error('Error checking session:', error));
}
// Register
function register() {
const username = document.getElementById('username')?.value;
const email = document.getElementById('email')?.value;
const password = document.getElementById('password')?.value;
const phone = document.getElementById('phone')?.value;
fetch('/register', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ username, email, password, phone })
})
.then(response => response.json())
.then(data => {
if (data.error) {
showMessage('register-message', data.error, 'danger');
} else {
showMessage('register-message', data.message, 'success');
setTimeout(() => {
window.location.href = `/verify_otp?user_id=${data.user_id}`;
}, 2000);
}
})
.catch(error => {
showMessage('register-message', 'Lỗi hệ thống, vui lòng thử lại', 'danger');
console.error('Error:', error);
});
}
// Verify OTP
function verifyOtp() {
const user_id = new URLSearchParams(window.location.search).get('user_id');
const otp = document.getElementById('otp')?.value;
fetch('/verify_otp', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ user_id, otp })
})
.then(response => response.json())
.then(data => {
if (data.error) {
showMessage('otp-message', data.error, 'danger');
} else {
showMessage('otp-message', 'Xác minh thành công', 'success');
setTimeout(() => window.location.href = '/login', 2000);
}
})
.catch(error => {
showMessage('otp-message', 'Lỗi hệ thống, vui lòng thử lại', ' Hambackend');
console.error('Error:', error);
});
}
// Login
function login() {
const email = document.getElementById('email')?.value;
const password = document.getElementById('password')?.value;
fetch('/login', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ email, password })
})
.then(response => response.json())
.then(data => {
if (data.error) {
showMessage('login-message', data.error, 'danger');
} else {
showMessage('login-message', 'Đăng nhập thành công', 'success');
setTimeout(() => window.location.href = '/home', 2000);
}
})
.catch(error => {
showMessage('login-message', 'Lỗi hệ thống, vui lòng thử lại', 'danger');
console.error('Error:', error);
});
}
// Forgot Password
function forgotPassword() {
const email = document.getElementById('email').value;
const last_four_digits = document.getElementById('last_four_digits').value;
if (!/^[0-9]{4}$/.test(last_four_digits)) {
document.getElementById('last_four_digits').classList.add('is-invalid');
return;
}
document.getElementById('submit-btn').disabled = true;
document.querySelector('.loading-spinner').classList.add('active');
fetch('/forgot_password', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ email, last_four_digits })
})
.then(response => response.json())
.then(data => {
if (data.error) {
showMessage('forgot-password-message', data.error, 'danger');
} else {
showMessage('forgot-password-message', data.message, 'success');
setTimeout(() => window.location.href = '/login', 2000);
}
})
.catch(error => {
showMessage('forgot-password-message', 'Lỗi hệ thống, vui lòng thử lại', 'danger');
console.error('Error:', error);
})
.finally(() => {
document.getElementById('submit-btn').disabled = false;
document.querySelector('.loading-spinner').classList.remove('active');
});
}
// Change Password
function changePassword() {
const current_password = document.getElementById('current_password').value;
const new_password = document.getElementById('new_password').value;
fetch('/change_password', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ current_password, new_password })
})
.then(response => response.json())
.then(data => {
if (data.error) {
showMessage('change-password-message', data.error, 'danger');
} else {
showMessage('change-password-message', data.message, 'success');
setTimeout(() => window.location.href = '/home', 2000);
}
})
.catch(error => {
showMessage('change-password-message', 'Lỗi hệ thống, vui lòng thử lại', 'danger');
console.error('Error:', error);
});
}
// Logout
function logout() {
fetch('/logout', {
method: 'POST',
headers: { 'Content-Type': 'application/json' }
})
.then(response => response.json())
.then(data => {
showMessage('auth-message', data.message, 'success');
setTimeout(() => window.location.href = '/', 1000);
})
.catch(error => {
showMessage('auth-message', 'Lỗi hệ thống, vui lòng thử lại', 'danger');
console.error('Error:', error);
});
}
// Event listener for email input
document.getElementById('email').addEventListener('input', () => {
const emailInput = document.getElementById('email');
const maskedPhoneInput = document.getElementById('masked_phone');
fetchMaskedPhone(emailInput, maskedPhoneInput);
});
</script>
</body>
</html>