reset_password.html
164 lignes · 6692 octets
{% extends "base.html" %} {% block title %}{{ page_title }} - {{ app_name }}{% endblock %} {% block content %} <div class="min-h-screen flex items-center justify-center bg-base-200 px-4"> <div class="max-w-lg w-full space-y-6"> <div class="text-center"> <div class="inline-flex items-center justify-center w-16 h-16 mb-4"> <img src="/static/images/logo.svg" alt="{{ app_name }} Logo" class="h-16 w-16"> </div> <h1 class="text-3xl font-bold text-base-content mb-2">{{ reset_password_title }}</h1> <p class="text-base-content/70"> {{ subtitle }} </p> </div> <div id="alert-error" class="hidden alert alert-error"> <svg xmlns="http://www.w3.org/2000/svg" class="stroke-current shrink-0 h-6 w-6" fill="none" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M10 14l2-2m0 0l2-2m-2 2l-2-2m2 2l2 2m7-2a9 9 0 11-18 0 9 9 0 0118 0z" /></svg> <span id="alert-error-text"></span> </div> <div id="alert-success" class="hidden alert alert-success"> <svg xmlns="http://www.w3.org/2000/svg" class="stroke-current shrink-0 h-6 w-6" fill="none" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 12l2 2 4-4m6 2a9 9 0 11-18 0 9 9 0 0118 0z" /></svg> <span id="alert-success-text"></span> </div> <div class="card bg-base-100 shadow-xl p-8"> <form id="reset-form" class="space-y-4"> <input type="hidden" id="token" name="token" value=""> <div class="form-control"> <label for="new_password" class="label"> <span class="label-text">{{ new_password_label }}</span> </label> <input type="password" id="new_password" name="new_password" required autocomplete="new-password" class="input input-bordered w-full" placeholder="{{ new_password_placeholder }}"> <label class="label"> <span class="label-text-alt text-base-content/70">{{ password_requirements }}</span> </label> </div> <div class="form-control"> <label for="confirm_password" class="label"> <span class="label-text">{{ confirm_password_label }}</span> </label> <input type="password" id="confirm_password" name="confirm_password" required autocomplete="new-password" class="input input-bordered w-full" placeholder="{{ confirm_password_placeholder }}"> </div> <div class="form-control mt-6"> <button type="submit" class="btn btn-primary w-full"> {{ submit_button }} </button> </div> </form> <div class="mt-4 text-sm text-base-content/70 text-center space-y-2"> <a href="/login" class="text-primary hover:underline">{{ back_to_login }}</a> </div> </div> </div> </div> <script> const MSG_MISSING_TOKEN_URL = "{{ missing_token_url }}"; const MSG_MISSING_TOKEN = "{{ missing_token }}"; const MSG_MISSING_NEW_PASSWORD = "{{ missing_new_password }}"; const MSG_PASSWORDS_NOT_MATCH = "{{ passwords_not_match }}"; const MSG_RESET_SUCCESS = "{{ reset_success_message }}"; const MSG_ERROR_LINK_INVALID = "{{ error_link_invalid }}"; const MSG_ERROR_GENERIC = "{{ error_generic }}"; const MSG_ERROR_DEFAULT = "{{ error_message }}"; const MSG_SUCCESS_DEFAULT = "{{ success_message }}"; const urlParams = new URLSearchParams(window.location.search); const token = urlParams.get('token'); if (token) { document.getElementById('token').value = token; } else { showError(MSG_MISSING_TOKEN_URL); } const form = document.getElementById('reset-form'); const alertError = document.getElementById('alert-error'); const alertErrorText = document.getElementById('alert-error-text'); const alertSuccess = document.getElementById('alert-success'); const alertSuccessText = document.getElementById('alert-success-text'); function showError(msg) { if (alertError && alertErrorText) { alertErrorText.textContent = msg || MSG_ERROR_DEFAULT; alertError.classList.remove('hidden'); } if (alertSuccess) alertSuccess.classList.add('hidden'); } function showSuccess(msg) { if (alertSuccess && alertSuccessText) { alertSuccessText.textContent = msg || MSG_SUCCESS_DEFAULT; alertSuccess.classList.remove('hidden'); } if (alertError) alertError.classList.add('hidden'); } form?.addEventListener('submit', (e) => { e.preventDefault(); const token = document.getElementById('token')?.value; const newPassword = document.getElementById('new_password')?.value; const confirmPassword = document.getElementById('confirm_password')?.value; if (!token) { showError(MSG_MISSING_TOKEN); return; } if (!newPassword) { showError(MSG_MISSING_NEW_PASSWORD); return; } if (newPassword !== confirmPassword) { showError(MSG_PASSWORDS_NOT_MATCH); return; } fetch('/api/v1/auth/reset-password', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ token, new_password: newPassword }), credentials: 'include' }) .then(async (resp) => { let msg = ''; try { const data = await resp.json(); msg = data.message || data.error || msg; } catch (_) {} if (resp.ok) { showSuccess(msg || MSG_RESET_SUCCESS); setTimeout(() => { window.location.href = '/login'; }, 3000); } else { showError(msg || MSG_ERROR_LINK_INVALID); } }) .catch(() => showError(MSG_ERROR_GENERIC)); }); </script> {% endblock %}
GitRust