Files
BagExchange/templates/reset_password.html
2026-02-15 17:09:19 +01:00

119 lines
8.9 KiB
HTML

<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>Bag Exchange | Reset Password</title>
<script src="https://cdn.tailwindcss.com"></script>
</head>
<body class="min-h-screen bg-gradient-to-br from-amber-50 via-orange-50 to-stone-200 text-zinc-800">
<main class="mx-auto grid min-h-screen w-full max-w-2xl place-items-center px-4 py-8">
<section class="w-full max-w-xl rounded-2xl border border-zinc-300/70 bg-amber-50/80 p-6 shadow-2xl shadow-stone-700/10 backdrop-blur-sm">
<div class="mb-4 flex justify-end">
<select id="language-select" class="rounded-lg border border-zinc-300 bg-white px-2 py-1 text-sm">
<option value="en">English</option>
<option value="it">Italiano</option>
<option value="fr">Français</option>
<option value="de">Deutsch</option>
<option value="es">Español</option>
</select>
</div>
<h1 class="mb-2 text-3xl font-bold tracking-tight" data-i18n="title">Set a new password</h1>
<p class="mb-4 text-sm text-zinc-700" data-i18n="subtitle">Create your new password to recover access to your Bag Exchange account.</p>
<form class="grid gap-3" id="reset-form">
<input class="w-full rounded-xl border border-zinc-400/40 bg-white px-3 py-3 text-sm outline-none ring-orange-300 transition focus:ring-2" id="password" type="password" minlength="8" required data-i18n-placeholder="passwordPlaceholder" placeholder="New password" />
<input class="w-full rounded-xl border border-zinc-400/40 bg-white px-3 py-3 text-sm outline-none ring-orange-300 transition focus:ring-2" id="confirm-password" type="password" minlength="8" required data-i18n-placeholder="confirmPlaceholder" placeholder="Confirm new password" />
<button class="rounded-xl bg-orange-500 px-4 py-3 text-sm font-semibold text-white transition hover:bg-orange-600 disabled:cursor-not-allowed disabled:opacity-60" id="submit-btn" type="submit" data-i18n="submit">Reset password</button>
</form>
<div class="mt-4 hidden rounded-xl px-3 py-2 text-sm leading-relaxed" id="feedback"></div>
<a class="mt-4 inline-block text-sm text-emerald-900 underline decoration-1 underline-offset-2" href="/login" data-lang-link data-i18n="loginLink">Back to login</a>
</section>
</main>
<script src="/static/js/simple_i18n.js"></script>
<script>
var i18n = window.initPageI18n({
en: { pageTitle: "Bag Exchange | Reset Password", title: "Set a new password", subtitle: "Create your new password to recover access to your Bag Exchange account.", passwordPlaceholder: "New password", confirmPlaceholder: "Confirm new password", submit: "Reset password", loginLink: "Back to login", msgInvalidToken: "Invalid reset token. Open the link from your email again.", msgShort: "Use at least 8 characters.", msgMismatch: "Passwords do not match.", msgOk: "Password updated successfully. You can now log in.", msgExpired: "Reset link is invalid or expired.", msgWeak: "Use at least 8 characters with letters and numbers.", msgError: "Unable to reset password. Try again." },
it: { pageTitle: "Bag Exchange | Reimposta Password", title: "Imposta una nuova password", subtitle: "Crea una nuova password per recuperare l'accesso al tuo account Bag Exchange.", passwordPlaceholder: "Nuova password", confirmPlaceholder: "Conferma nuova password", submit: "Reimposta password", loginLink: "Torna al login", msgInvalidToken: "Token di reset non valido. Apri di nuovo il link ricevuto via email.", msgShort: "Usa almeno 8 caratteri.", msgMismatch: "Le password non coincidono.", msgOk: "Password aggiornata con successo. Ora puoi accedere.", msgExpired: "Il link di reset non e valido o e scaduto.", msgWeak: "Usa almeno 8 caratteri con lettere e numeri.", msgError: "Impossibile reimpostare la password. Riprova." },
fr: { pageTitle: "Bag Exchange | Reinitialiser le mot de passe", title: "Definir un nouveau mot de passe", subtitle: "Creez un nouveau mot de passe pour recuperer l'acces a votre compte Bag Exchange.", passwordPlaceholder: "Nouveau mot de passe", confirmPlaceholder: "Confirmer le nouveau mot de passe", submit: "Reinitialiser", loginLink: "Retour a la connexion", msgInvalidToken: "Jeton de reinitialisation invalide. Ouvrez a nouveau le lien recu par email.", msgShort: "Utilisez au moins 8 caracteres.", msgMismatch: "Les mots de passe ne correspondent pas.", msgOk: "Mot de passe mis a jour. Vous pouvez maintenant vous connecter.", msgExpired: "Le lien de reinitialisation est invalide ou expire.", msgWeak: "Utilisez au moins 8 caracteres avec lettres et chiffres.", msgError: "Impossible de reinitialiser le mot de passe. Veuillez reessayer." },
de: { pageTitle: "Bag Exchange | Passwort zuruecksetzen", title: "Neues Passwort festlegen", subtitle: "Lege ein neues Passwort fest, um wieder Zugriff auf dein Bag Exchange Konto zu erhalten.", passwordPlaceholder: "Neues Passwort", confirmPlaceholder: "Neues Passwort bestaetigen", submit: "Passwort zuruecksetzen", loginLink: "Zurueck zum Login", msgInvalidToken: "Ungueltiger Reset-Token. Oeffne den Link aus der E-Mail erneut.", msgShort: "Mindestens 8 Zeichen verwenden.", msgMismatch: "Die Passwoerter stimmen nicht ueberein.", msgOk: "Passwort erfolgreich aktualisiert. Du kannst dich jetzt anmelden.", msgExpired: "Reset-Link ist ungueltig oder abgelaufen.", msgWeak: "Mindestens 8 Zeichen mit Buchstaben und Zahlen verwenden.", msgError: "Passwort konnte nicht zurueckgesetzt werden. Bitte erneut versuchen." },
es: { pageTitle: "Bag Exchange | Restablecer contrasena", title: "Define una nueva contrasena", subtitle: "Crea una nueva contrasena para recuperar el acceso a tu cuenta Bag Exchange.", passwordPlaceholder: "Nueva contrasena", confirmPlaceholder: "Confirmar nueva contrasena", submit: "Restablecer contrasena", loginLink: "Volver al login", msgInvalidToken: "Token de restablecimiento no valido. Abre de nuevo el enlace del correo.", msgShort: "Usa al menos 8 caracteres.", msgMismatch: "Las contrasenas no coinciden.", msgOk: "Contrasena actualizada correctamente. Ya puedes iniciar sesion.", msgExpired: "El enlace de restablecimiento no es valido o ha caducado.", msgWeak: "Usa al menos 8 caracteres con letras y numeros.", msgError: "No se pudo restablecer la contrasena. Intentalo de nuevo." }
});
(function () {
var token = "{{.Token}}";
var form = document.getElementById("reset-form");
var passwordInput = document.getElementById("password");
var confirmInput = document.getElementById("confirm-password");
var submitButton = document.getElementById("submit-btn");
var feedback = document.getElementById("feedback");
function showMessage(kind, text) {
feedback.className = "mt-4 rounded-xl px-3 py-2 text-sm leading-relaxed";
if (kind === "error") {
feedback.classList.add("bg-red-100", "text-red-800");
} else {
feedback.classList.add("bg-emerald-100", "text-emerald-900");
}
feedback.textContent = text;
}
if (!token) {
showMessage("error", i18n.t("msgInvalidToken"));
submitButton.disabled = true;
}
form.addEventListener("submit", async function (event) {
event.preventDefault();
var password = passwordInput.value;
var confirmPassword = confirmInput.value;
if (!password || password.length < 8) {
showMessage("error", i18n.t("msgShort"));
return;
}
if (password !== confirmPassword) {
showMessage("error", i18n.t("msgMismatch"));
return;
}
submitButton.disabled = true;
feedback.className = "mt-4 hidden rounded-xl px-3 py-2 text-sm leading-relaxed";
feedback.textContent = "";
try {
var response = await fetch("/api/auth/reset-password", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ token: token, password: password, confirmPassword: confirmPassword })
});
var payload = {};
try { payload = await response.json(); } catch (e) { payload = {}; }
if (response.ok) {
form.classList.add("hidden");
showMessage("ok", i18n.t("msgOk"));
} else if (payload.error === "invalid_or_expired_token" || payload.error === "invalid_token") {
showMessage("error", i18n.t("msgExpired"));
} else if (payload.error === "password_too_weak") {
showMessage("error", i18n.t("msgWeak"));
} else if (payload.error === "password_mismatch") {
showMessage("error", i18n.t("msgMismatch"));
} else {
showMessage("error", i18n.t("msgError"));
}
} catch (err) {
showMessage("error", i18n.t("msgError"));
} finally {
submitButton.disabled = false;
}
});
})();
</script>
</body>
</html>