vtdung23's picture
Enhanced app with Dark Mode, Toast Notifications, SHAP Explanation, N-gram Analysis, Keyword Highlighting
92db116
{% extends "base.html" %}
{% block title %}Login - Rating Predictor{% endblock %}
{% block content %}
<div class="flex items-center justify-center min-h-[calc(100vh-200px)]">
<div class="bg-white dark:bg-slate-800 rounded-2xl shadow-xl p-8 w-full max-w-md fade-in">
<div class="text-center mb-8">
<i class="fas fa-sign-in-alt text-5xl text-indigo-600 mb-4"></i>
<h2 class="text-3xl font-bold text-gray-800 dark:text-gray-100">Đăng Nhập</h2>
<p class="text-gray-600 dark:text-gray-400 mt-2">Welcome back to Rating Predictor</p>
</div>
<form id="loginForm" class="space-y-6">
<div>
<label class="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-2">
<i class="fas fa-user mr-2"></i>Username
</label>
<input
type="text"
id="username"
name="username"
required
class="w-full px-4 py-3 border border-gray-300 dark:border-slate-600 rounded-lg focus:ring-2 focus:ring-indigo-500 focus:border-transparent transition bg-white dark:bg-slate-700 text-gray-900 dark:text-gray-100"
placeholder="Enter your username"
>
</div>
<div>
<label class="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-2">
<i class="fas fa-lock mr-2"></i>Password
</label>
<input
type="password"
id="password"
name="password"
required
class="w-full px-4 py-3 border border-gray-300 dark:border-slate-600 rounded-lg focus:ring-2 focus:ring-indigo-500 focus:border-transparent transition bg-white dark:bg-slate-700 text-gray-900 dark:text-gray-100"
placeholder="Enter your password"
>
</div>
<button
type="submit"
id="login-btn"
class="w-full bg-indigo-600 text-white py-3 rounded-lg hover:bg-indigo-700 transition font-medium shadow-lg hover:shadow-xl"
>
<i class="fas fa-sign-in-alt mr-2"></i>Login
</button>
</form>
<div class="mt-6 text-center">
<p class="text-gray-600 dark:text-gray-400">
Don't have an account?
<a href="/register" class="text-indigo-600 hover:text-indigo-800 dark:text-indigo-400 dark:hover:text-indigo-300 font-medium">
Register here
</a>
</p>
</div>
</div>
</div>
{% endblock %}
{% block scripts %}
<script>
document.getElementById('loginForm').addEventListener('submit', async (e) => {
e.preventDefault();
const username = document.getElementById('username').value;
const password = document.getElementById('password').value;
const loginBtn = document.getElementById('login-btn');
// Show loading state
loginBtn.disabled = true;
loginBtn.innerHTML = '<i class="fas fa-spinner fa-spin mr-2"></i>Logging in...';
try {
// Create form data for OAuth2
const formData = new URLSearchParams();
formData.append('username', username);
formData.append('password', password);
const response = await fetch('/api/auth/login', {
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
},
body: formData
});
const data = await response.json();
if (response.ok) {
// Save token
localStorage.setItem('access_token', data.access_token);
localStorage.setItem('username', username);
// Show success toast
toast.success('Login Successful', 'Welcome back, ' + username + '!');
// Redirect to dashboard
setTimeout(() => {
window.location.href = '/dashboard';
}, 1000);
} else {
// Show error toast
toast.error('Login Failed', data.detail || 'Invalid credentials. Please try again.');
loginBtn.disabled = false;
loginBtn.innerHTML = '<i class="fas fa-sign-in-alt mr-2"></i>Login';
}
} catch (error) {
toast.error('Error', 'An error occurred. Please try again.');
loginBtn.disabled = false;
loginBtn.innerHTML = '<i class="fas fa-sign-in-alt mr-2"></i>Login';
}
});
</script>
{% endblock %}