Restore to commit 74e578279624c6045ca440a3459ebfa1f8d54191
This commit is contained in:
185
chat/public/reset-password.html
Normal file
185
chat/public/reset-password.html
Normal file
@@ -0,0 +1,185 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Reset Password | Plugin Compass</title>
|
||||
<link rel="icon" type="image/png" href="/assets/Plugin.png">
|
||||
<script src="https://cdn.tailwindcss.com"></script>
|
||||
<link href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0/css/all.min.css" rel="stylesheet">
|
||||
|
||||
<!-- PostHog Analytics -->
|
||||
<script src="/posthog.js"></script>
|
||||
</head>
|
||||
<body class="bg-amber-50 text-gray-900 font-sans antialiased min-h-screen flex flex-col">
|
||||
<nav class="w-full">
|
||||
<div class="max-w-4xl mx-auto px-4 py-6 flex items-center justify-between">
|
||||
<a href="/" class="flex items-center gap-2 font-bold text-lg text-gray-800">
|
||||
<img src="/assets/Plugin.png" alt="Plugin Compass" class="w-8 h-8">
|
||||
Plugin Compass
|
||||
</a>
|
||||
<a href="/login" class="text-sm text-green-700 hover:underline font-semibold">Back to sign in</a>
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
<main class="flex-grow flex items-center justify-center px-4 py-12">
|
||||
<div class="max-w-xl w-full bg-white/80 border border-gray-200 rounded-2xl shadow-xl shadow-green-900/5 p-8">
|
||||
<div class="text-center mb-8">
|
||||
<div class="w-14 h-14 rounded-full bg-green-700 text-white flex items-center justify-center mx-auto mb-4">
|
||||
<i class="fa-solid fa-key text-2xl"></i>
|
||||
</div>
|
||||
<h1 class="text-2xl font-bold mb-2">Reset your password</h1>
|
||||
<p class="text-gray-600" id="subtitle">Enter your email to receive a reset link.</p>
|
||||
</div>
|
||||
|
||||
<div id="request-section" class="space-y-4">
|
||||
<label class="block text-sm font-medium text-gray-700 mb-1" for="reset-email">Email Address</label>
|
||||
<input id="reset-email" type="email" class="w-full px-4 py-3 rounded-xl border border-gray-200 focus:ring-2 focus:ring-green-700/20 focus:border-green-700 outline-none transition-all bg-white/50" placeholder="you@example.com">
|
||||
<button id="request-button" class="w-full bg-green-700 hover:bg-green-600 text-white font-bold py-3 rounded-xl transition-all">Send reset link</button>
|
||||
</div>
|
||||
|
||||
<div id="reset-section" class="space-y-4 hidden">
|
||||
<label class="block text-sm font-medium text-gray-700 mb-1" for="new-password">New password</label>
|
||||
<input id="new-password" type="password" class="w-full px-4 py-3 rounded-xl border border-gray-200 focus:ring-2 focus:ring-green-700/20 focus:border-green-700 outline-none transition-all bg-white/50" placeholder="••••••••">
|
||||
<label class="block text-sm font-medium text-gray-700 mb-1" for="confirm-password">Confirm password</label>
|
||||
<input id="confirm-password" type="password" class="w-full px-4 py-3 rounded-xl border border-gray-200 focus:ring-2 focus:ring-green-700/20 focus:border-green-700 outline-none transition-all bg-white/50" placeholder="••••••••">
|
||||
<button id="reset-button" class="w-full bg-green-700 hover:bg-green-600 text-white font-bold py-3 rounded-xl transition-all">Update password</button>
|
||||
</div>
|
||||
|
||||
<div id="reset-status" class="mt-4 text-sm text-gray-700 bg-amber-50 border border-amber-100 rounded-lg px-4 py-3 min-h-[48px]"></div>
|
||||
</div>
|
||||
</main>
|
||||
|
||||
<footer class="bg-white border-t border-green-200 pt-16 pb-8">
|
||||
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
|
||||
<div class="grid grid-cols-2 md:grid-cols-4 gap-12 mb-16">
|
||||
<div class="col-span-2 md:col-span-1">
|
||||
<div class="flex items-center gap-2 mb-6">
|
||||
<img src="/assets/Plugin.png" alt="Plugin Compass" class="w-8 h-8">
|
||||
<span class="font-bold text-xl tracking-tight text-gray-800">Plugin<span
|
||||
class="text-green-700">Compass</span></span>
|
||||
</div>
|
||||
<p class="text-gray-600 text-sm leading-relaxed">
|
||||
The smart way for WordPress site owners to replace expensive plugin subscriptions with custom
|
||||
solutions. Save thousands monthly.
|
||||
</p>
|
||||
</div>
|
||||
<div>
|
||||
<h4 class="font-bold text-gray-900 mb-6">Product</h4>
|
||||
<ul class="space-y-4 text-sm">
|
||||
<li><a href="/features" class="text-gray-600 hover:text-green-700">Features</a></li>
|
||||
<li><a href="/pricing" class="text-gray-600 hover:text-green-700">Pricing</a></li>
|
||||
<li><a href="#" class="text-gray-600 hover:text-green-700">Templates</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
<div>
|
||||
<h4 class="font-bold text-gray-900 mb-6">Resources</h4>
|
||||
<ul class="space-y-4 text-sm">
|
||||
<li><a href="/docs" class="text-gray-600 hover:text-green-700">Documentation</a></li>
|
||||
<li><a href="/faq" class="text-gray-600 hover:text-green-700">FAQ</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
<div>
|
||||
<h4 class="font-bold text-gray-900 mb-6">Legal</h4>
|
||||
<ul class="space-y-4 text-sm">
|
||||
<li><a href="/privacy.html" class="text-gray-600 hover:text-green-700">Privacy Policy</a></li>
|
||||
<li><a href="/terms" class="text-gray-600 hover:text-green-700">Terms of Service</a></li>
|
||||
<li><a href="/contact" class="text-gray-600 hover:text-green-700">Contact Us</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
<div class="border-t border-gray-100 pt-8 flex justify-center">
|
||||
<p class="text-gray-500 text-xs text-center">© 2026 Plugin Compass. All rights reserved.</p>
|
||||
</div>
|
||||
</div>
|
||||
</footer>
|
||||
|
||||
<script>
|
||||
const params = new URLSearchParams(window.location.search);
|
||||
const token = params.get('token');
|
||||
const requestSection = document.getElementById('request-section');
|
||||
const resetSection = document.getElementById('reset-section');
|
||||
const statusEl = document.getElementById('reset-status');
|
||||
const subtitleEl = document.getElementById('subtitle');
|
||||
const REDIRECT_DELAY_MS = 1200;
|
||||
const redirectTarget = params.get('next') || '/apps';
|
||||
|
||||
function setStatus(message, isError = false) {
|
||||
statusEl.textContent = message || '';
|
||||
statusEl.classList.toggle('text-red-700', isError);
|
||||
statusEl.classList.toggle('border-red-200', isError);
|
||||
statusEl.classList.toggle('bg-red-50', isError);
|
||||
statusEl.classList.toggle('text-green-700', !isError);
|
||||
statusEl.classList.toggle('border-green-100', !isError);
|
||||
statusEl.classList.toggle('bg-green-50', !isError);
|
||||
}
|
||||
|
||||
async function requestReset() {
|
||||
const email = (document.getElementById('reset-email').value || '').trim().toLowerCase();
|
||||
if (!email) {
|
||||
setStatus('Email is required', true);
|
||||
return;
|
||||
}
|
||||
setStatus('Sending reset link...', false);
|
||||
try {
|
||||
const resp = await fetch('/api/password/forgot', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ email })
|
||||
});
|
||||
const data = await resp.json().catch(() => ({}));
|
||||
if (!resp.ok) {
|
||||
setStatus(data.error || 'Unable to send reset email. Please try again.', true);
|
||||
return;
|
||||
}
|
||||
setStatus(data.message || 'If an account exists, a reset link has been sent.', false);
|
||||
} catch (_) {
|
||||
setStatus('Unable to send reset email. Please try again.', true);
|
||||
}
|
||||
}
|
||||
|
||||
async function submitReset() {
|
||||
const newPassword = (document.getElementById('new-password').value || '').trim();
|
||||
const confirmPassword = (document.getElementById('confirm-password').value || '').trim();
|
||||
if (!newPassword || newPassword.length < 6) {
|
||||
setStatus('Password must be at least 6 characters.', true);
|
||||
return;
|
||||
}
|
||||
if (newPassword !== confirmPassword) {
|
||||
setStatus('Passwords do not match.', true);
|
||||
return;
|
||||
}
|
||||
setStatus('Updating your password...', false);
|
||||
try {
|
||||
const resp = await fetch('/api/password/reset', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ token, password: newPassword })
|
||||
});
|
||||
const data = await resp.json().catch(() => ({}));
|
||||
if (!resp.ok) {
|
||||
setStatus(data.error || 'Unable to reset password. Please try again.', true);
|
||||
return;
|
||||
}
|
||||
setStatus('Password updated. Redirecting you to the app...', false);
|
||||
setTimeout(() => {
|
||||
window.location.href = redirectTarget;
|
||||
}, REDIRECT_DELAY_MS);
|
||||
} catch (_) {
|
||||
setStatus('Unable to reset password. Please try again.', true);
|
||||
}
|
||||
}
|
||||
|
||||
document.getElementById('request-button').addEventListener('click', requestReset);
|
||||
document.getElementById('reset-button').addEventListener('click', submitReset);
|
||||
|
||||
if (token) {
|
||||
requestSection.classList.add('hidden');
|
||||
resetSection.classList.remove('hidden');
|
||||
subtitleEl.textContent = 'Enter a new password to finish resetting your account.';
|
||||
} else {
|
||||
setStatus('Enter your email to receive a reset link.', false);
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
Reference in New Issue
Block a user