Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
142 changes: 142 additions & 0 deletions public/forgot-password.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,142 @@
<!DOCTYPE html>
<html lang="en" class="scroll-smooth">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta name="description" content="Alpha One Labs - Forgot Password">
<title>Forgot Password - Alpha One Labs</title>

<link rel="icon" type="image/png" href="https://alphaonelabs.com/static/images/logo.png" />
<script src="https://cdn.tailwindcss.com"></script>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0/css/all.min.css">

<script>
tailwind.config = { darkMode: 'class', theme: { extend: {} } }
const darkModeEnabled = localStorage.getItem('darkMode') === 'true';
if (darkModeEnabled) document.documentElement.classList.add('dark');
</script>

<style>
html, body { overflow-x: hidden; box-sizing: border-box; }
.dark { color-scheme: dark; }
:root { color-scheme: light; }
</style>
</head>

<body class="min-h-screen flex flex-col bg-white text-gray-900 dark:bg-black dark:text-gray-100 transition-colors duration-300">

<div id="site-navbar"></div>

<main class="flex-1 w-full flex items-center justify-center py-12 px-4">
<div class="w-full max-w-md">

<!-- Brand Header -->
<div class="text-center mb-8">
<a href="/" class="inline-flex items-center justify-center gap-3 mb-4 group">
<div class="w-12 h-12 rounded-xl flex items-center justify-center shadow-lg group-hover:shadow-xl transition-shadow">
<img src="https://alphaonelabs.com/static/images/logo.png" alt="Alpha One Labs Logo" class="w-6 h-6">
</div>
<span class="font-bold text-2xl bg-gradient-to-r from-teal-600 to-cyan-600 dark:from-teal-400 dark:to-cyan-400 bg-clip-text text-transparent">Alpha One Labs</span>
</a>
</div>

<!-- Card -->
<div class="rounded-2xl shadow-lg border border-gray-200 dark:border-gray-700 bg-white dark:bg-gray-800 overflow-hidden">

<!-- Form panel -->
<div id="panel-form" class="p-8">
<h2 class="text-xl font-bold text-gray-800 dark:text-gray-200 mb-2">Forgot your password?</h2>
<p class="text-gray-500 dark:text-gray-400 text-sm mb-6">
Enter the email address associated with your account and we'll send you a reset link.
</p>

<form id="forgot-form" class="space-y-4" novalidate>
<div>
<label class="block text-sm font-semibold text-gray-700 dark:text-gray-300 mb-2">
<i class="fas fa-envelope mr-1.5 text-teal-600 dark:text-teal-400"></i>Email Address
</label>
<input id="f-email" type="email" autocomplete="email" required
class="w-full px-4 py-2.5 rounded-xl border border-gray-300 dark:border-gray-600 focus:outline-none focus:ring-2 focus:ring-teal-500 dark:focus:ring-teal-400 dark:bg-gray-700 dark:text-white text-sm transition"
placeholder="you@example.com" />
</div>

<div id="forgot-err" class="hidden p-3 bg-red-50 dark:bg-red-900/30 border border-red-200 dark:border-red-800 rounded-lg text-red-700 dark:text-red-300 text-sm flex items-start gap-2">
<i class="fas fa-exclamation-circle mt-0.5 flex-shrink-0"></i>
<span id="forgot-err-msg"></span>
</div>

<button type="submit"
class="w-full bg-gradient-to-r from-teal-500 to-cyan-500 hover:from-teal-600 hover:to-cyan-600 text-white font-bold py-2.5 rounded-xl shadow-lg hover:shadow-xl transition-all duration-200 active:scale-95">
<i class="fas fa-paper-plane mr-2"></i>Send Reset Link
</button>
</form>
</div>

<!-- Success panel -->
<div id="panel-success" class="p-8 hidden text-center">
<div class="w-16 h-16 bg-teal-100 dark:bg-teal-900/40 rounded-full flex items-center justify-center mx-auto mb-4">
<i class="fas fa-envelope-open-text text-3xl text-teal-600 dark:text-teal-400"></i>
</div>
<h2 class="text-xl font-bold text-gray-800 dark:text-gray-200 mb-2">Check your inbox</h2>
<p id="success-msg" class="text-gray-600 dark:text-gray-400 text-sm mb-6">
If an account with that email exists, a password reset link has been sent.
</p>
<p class="text-xs text-gray-500 dark:text-gray-400">
The link expires in 1 hour. Didn't receive it? Check your spam folder.
</p>
</div>

</div>

<p class="text-center text-gray-500 dark:text-gray-400 text-xs mt-6">
<a href="/login" class="text-teal-600 dark:text-teal-400 hover:underline inline-flex items-center gap-1 font-semibold transition">
<i class="fas fa-arrow-left"></i>Back to sign in
</a>
</p>
</div>
</main>

<div id="site-footer"></div>

<script src="/js/layout.js" defer></script>
<script>
const API = '';

document.getElementById('forgot-form').addEventListener('submit', async e => {
e.preventDefault();
document.getElementById('forgot-err').classList.add('hidden');

const btn = e.target.querySelector('button[type=submit]');
const originalHTML = btn.innerHTML;
btn.innerHTML = '<i class="fas fa-spinner fa-spin mr-2"></i>Sending…';
btn.disabled = true;

try {
const email = document.getElementById('f-email').value.trim();
if (!email) throw new Error('Please enter your email address.');

const res = await fetch(`${API}/api/forgot-password`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ email }),
});
const data = await res.json();

if (!res.ok) throw new Error(data.error || 'Something went wrong.');

document.getElementById('success-msg').textContent =
data.message || 'If an account with that email exists, a password reset link has been sent.';
document.getElementById('panel-form').classList.add('hidden');
document.getElementById('panel-success').classList.remove('hidden');
} catch (err) {
const el = document.getElementById('forgot-err');
document.getElementById('forgot-err-msg').textContent = err.message;
el.classList.remove('hidden');
} finally {
btn.innerHTML = originalHTML;
btn.disabled = false;
}
});
</script>
</body>
</html>
62 changes: 59 additions & 3 deletions public/login.html
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,12 @@ <h2 class="text-xl font-bold text-gray-800 dark:text-gray-200 mb-2">Welcome back
</button>
</form>

<div class="mt-4 text-center">
<a href="/forgot-password" class="text-sm text-teal-600 dark:text-teal-400 hover:underline font-semibold">
<i class="fas fa-key mr-1"></i>Forgot your password?
</a>
</div>

<div class="mt-6 p-4 bg-blue-50 dark:bg-blue-900/30 border border-blue-200 dark:border-blue-800 rounded-lg">
<p class="text-xs font-semibold text-blue-700 dark:text-blue-300 mb-2 flex items-center">
<i class="fas fa-info-circle mr-2"></i>Demo Credentials
Expand Down Expand Up @@ -200,6 +206,15 @@ <h2 class="text-xl font-bold text-gray-800 dark:text-gray-200 mb-2">Create your
</p>
</div>

<div>
<label class="block text-sm font-semibold text-gray-700 dark:text-gray-300 mb-2">
<i class="fas fa-check-circle mr-1.5 text-cyan-600 dark:text-cyan-400"></i>Confirm Password
</label>
<input id="r-confirm-password" type="password" autocomplete="new-password" required minlength="6"
class="w-full px-4 py-2.5 rounded-xl border border-gray-300 dark:border-gray-600 focus:outline-none focus:ring-2 focus:ring-cyan-500 dark:focus:ring-cyan-400 dark:bg-gray-700 dark:text-white text-sm transition"
placeholder="confirm password" />
</div>

<div id="register-err" class="hidden p-3 bg-red-50 dark:bg-red-900/30 border border-red-200 dark:border-red-800 rounded-lg text-red-700 dark:text-red-300 text-sm flex items-start gap-2 animate-pulse">
<i class="fas fa-exclamation-circle mt-0.5 flex-shrink-0"></i>
<span id="register-err-msg"></span>
Expand Down Expand Up @@ -378,6 +393,7 @@ <h2 class="text-xl font-bold text-gray-800 dark:text-gray-200 mb-2">Create your
const username = document.getElementById('r-username').value.trim();
const email = document.getElementById('r-email').value.trim();
const password = document.getElementById('r-password').value;
const confirmPassword = document.getElementById('r-confirm-password').value;

if (!username || !email || !password) {
throw new Error('Please fill in all required fields');
Expand All @@ -386,6 +402,10 @@ <h2 class="text-xl font-bold text-gray-800 dark:text-gray-200 mb-2">Create your
if (password.length < 6) {
throw new Error('Password must be at least 6 characters');
}

if (password !== confirmPassword) {
throw new Error('Passwords do not match');
}

const res = await fetch(`${API}/api/register`, {
method: 'POST',
Expand All @@ -401,12 +421,13 @@ <h2 class="text-xl font-bold text-gray-800 dark:text-gray-200 mb-2">Create your
});

const data = await res.json();

if (!res.ok) {
throw new Error(data.error || 'Registration failed');
}

storeAuth(data.data);

// Account created — user must verify email before they can sign in.
showRegisterSuccess(data.message || 'Registration successful! Please check your email to verify your account.');
} catch (err) {
console.error('Register error:', err);
showErr('register-err', err.message);
Expand All @@ -415,6 +436,41 @@ <h2 class="text-xl font-bold text-gray-800 dark:text-gray-200 mb-2">Create your
btn.disabled = false;
}
});

function showRegisterSuccess(msg) {
// Replace the register form with a success banner
const panel = document.getElementById('panel-register');

// Build HTML structure safely using DOM APIs
const container = document.createElement('div');
container.className = 'text-center py-8';

const iconDiv = document.createElement('div');
iconDiv.className = 'w-16 h-16 bg-teal-100 dark:bg-teal-900/40 rounded-full flex items-center justify-center mx-auto mb-4';
const icon = document.createElement('i');
icon.className = 'fas fa-envelope-open-text text-3xl text-teal-600 dark:text-teal-400';
iconDiv.appendChild(icon);

const heading = document.createElement('h2');
heading.className = 'text-xl font-bold text-gray-800 dark:text-gray-200 mb-2';
heading.textContent = 'Check your email';

const msgPara = document.createElement('p');
msgPara.className = 'text-gray-600 dark:text-gray-400 text-sm mb-6';
msgPara.textContent = msg; // Safe: uses textContent for user message

const actionPara = document.createElement('p');
actionPara.className = 'text-xs text-gray-500 dark:text-gray-400';
actionPara.innerHTML = 'Once verified, you can <button onclick="switchTab(\'login\')" class="text-teal-600 dark:text-teal-400 hover:underline font-semibold">sign in here</button>.';

container.appendChild(iconDiv);
container.appendChild(heading);
container.appendChild(msgPara);
container.appendChild(actionPara);

panel.innerHTML = '';
panel.appendChild(container);
}
Comment thread
coderabbitai[bot] marked this conversation as resolved.
</script>
</body>
</html>
Loading
Loading