Files
Mohamed Mathar Irfan ed6610d5d8 Initial project upload
2026-07-28 17:57:02 +05:30

87 lines
3.5 KiB
TypeScript

"use client";
import { Suspense, useEffect, useState } from "react";
import Link from "next/link";
import { useSearchParams, useRouter } from "next/navigation";
import AuthShell from "@/components/AuthShell";
import { api } from "@/lib/api";
function Inner() {
const sp = useSearchParams();
const r = useRouter();
const token = sp.get("token");
const email = sp.get("email") ?? "";
const [code, setCode] = useState("");
const [err, setErr] = useState("");
const [msg, setMsg] = useState("");
const [busy, setBusy] = useState(false);
const [linkState, setLinkState] = useState<"idle" | "ok" | "err">("idle");
// If arriving via the email link, verify by token automatically.
useEffect(() => {
if (token) {
api(`/auth/verify-email?token=${token}`)
.then(() => { setLinkState("ok"); setTimeout(() => r.push("/onboarding"), 1200); })
.catch(() => setLinkState("err"));
}
}, [token, r]);
async function submit(e: React.FormEvent) {
e.preventDefault();
setErr(""); setBusy(true);
try {
await api("/auth/verify-code", { method: "POST", body: JSON.stringify({ email, code }) });
r.push("/onboarding");
} catch (e: any) {
setErr(typeof e.detail === "string" ? e.detail : "Verification failed");
} finally { setBusy(false); }
}
async function resend() {
setMsg(""); setErr("");
await api("/auth/resend-code", { method: "POST", body: JSON.stringify({ email }) }).catch(() => {});
setMsg("A new code has been sent.");
}
// Token-link flow display
if (token) {
return (
<AuthShell title="Verifying your email">
{linkState === "ok" && <p className="text-emerald-600 font-medium"> Verified. Redirecting</p>}
{linkState === "err" && <p className="text-rose-600">This link is invalid or expired. Enter your code below instead.</p>}
{linkState === "idle" && <p className="text-slate-500">Verifying</p>}
<Link href="/login" className="text-brand-600 text-sm mt-4 inline-block">Back to login</Link>
</AuthShell>
);
}
return (
<AuthShell title="Verify your email" subtitle={email ? `We sent a 6-digit code to ${email}` : "Enter the 6-digit code we emailed you"}>
<form onSubmit={submit}>
<label className="block mb-4">
<span className="text-sm font-medium text-slate-700">Verification code</span>
<input value={code} onChange={(e) => setCode(e.target.value.replace(/\D/g, "").slice(0, 6))}
inputMode="numeric" placeholder="123456"
className="mt-1 w-full text-center tracking-[0.5em] text-lg px-3 py-3 rounded-lg border border-slate-200 focus:outline-none focus:ring-2 focus:ring-brand-500/30" />
</label>
{err && <p className="text-sm text-rose-600 mb-3">{err}</p>}
{msg && <p className="text-sm text-emerald-600 mb-3">{msg}</p>}
<button disabled={busy || code.length < 6}
className="w-full bg-brand-600 text-white py-3 rounded-full font-semibold disabled:opacity-50">
{busy ? "Verifying…" : "Verify email"}
</button>
</form>
<div className="flex justify-between mt-4 text-sm">
<button onClick={resend} className="text-brand-600">Resend code</button>
<Link href="/login" className="text-slate-500">Back to login</Link>
</div>
<p className="text-xs text-slate-400 mt-4">
In local dev (MOCK_EMAIL), the code is printed in the backend console.
</p>
</AuthShell>
);
}
export default function VerifyEmail() {
return <Suspense><Inner /></Suspense>;
}