feat(auth): welcome/landing page + email-password login UI (5b)
Replace the old Google-only login card with a public landing page (Welcome.tsx): hero + auth card (email+password Sign in / Create account / Forgot password, Continue with Google, explicit Try-the-demo) over a feature pitch (6 pain->solution cards) and demo-account screenshot slots (graceful placeholder until the images are dropped into frontend/public/welcome/). Auth forms wire to the 5a endpoints; errors show inline via a new req() quiet flag (no global modal for a wrong password). Handles ?verify, ?reset (set-new-password form), ?access banners. EN/HU/DE. Verified end-to-end on a fresh load: render, register->approve->password-login.
This commit is contained in:
parent
732acfce52
commit
a81734b4d6
7 changed files with 602 additions and 124 deletions
|
|
@ -194,6 +194,9 @@ const delay = (ms: number) => new Promise((res) => window.setTimeout(res, ms));
|
|||
// are safe to repeat). Used to recover from the keepalive race without surfacing a 502.
|
||||
interface ReqConfig {
|
||||
idempotent?: boolean;
|
||||
// Suppress the global error modal for 4xx/5xx so the caller can show the error inline
|
||||
// (used by the auth forms — a wrong password shouldn't pop a blocking dialog).
|
||||
quiet?: boolean;
|
||||
}
|
||||
|
||||
async function req(url: string, opts: RequestInit = {}, cfg: ReqConfig = {}): Promise<any> {
|
||||
|
|
@ -248,6 +251,8 @@ async function req(url: string, opts: RequestInit = {}, cfg: ReqConfig = {}): Pr
|
|||
// 400/409/422 (validation/conflict). 401/403/404 are caller-handled control flow.
|
||||
if (RETRIABLE_GATEWAY.has(r.status)) {
|
||||
markConnectivityLost();
|
||||
} else if (cfg.quiet) {
|
||||
/* caller handles the error inline — no global modal */
|
||||
} else if (r.status >= 500) {
|
||||
reportError(detail || `${i18n.t("errors.server")} (${r.status})`);
|
||||
} else if (r.status === 400 || r.status === 409 || r.status === 422) {
|
||||
|
|
@ -608,6 +613,15 @@ export const api = {
|
|||
body: JSON.stringify({ revalidate_batch: revalidateBatch }),
|
||||
}),
|
||||
|
||||
// --- auth: email + password (errors handled inline via quiet) ---
|
||||
register: (email: string, password: string): Promise<{ status: string }> =>
|
||||
req("/auth/register", { method: "POST", body: JSON.stringify({ email, password }) }, { quiet: true }),
|
||||
passwordLogin: (email: string, password: string): Promise<{ ok: boolean }> =>
|
||||
req("/auth/password-login", { method: "POST", body: JSON.stringify({ email, password }) }, { quiet: true }),
|
||||
requestPasswordReset: (email: string): Promise<{ status: string }> =>
|
||||
req("/auth/password-reset/request", { method: "POST", body: JSON.stringify({ email }) }, { quiet: true }),
|
||||
confirmPasswordReset: (token: string, password: string): Promise<{ ok: boolean }> =>
|
||||
req("/auth/password-reset/confirm", { method: "POST", body: JSON.stringify({ token, password }) }, { quiet: true }),
|
||||
// --- onboarding / admin ---
|
||||
requestAccess: (email: string): Promise<{ status: string }> =>
|
||||
req("/auth/request-access", { method: "POST", body: JSON.stringify({ email }) }),
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue