teecup/frontend/components/verify-email-form.tsx

100 lines
3.6 KiB
TypeScript

"use client"
import { useEffect, useState } from "react"
import Link from "next/link"
import { useSearchParams } from "next/navigation"
import { CheckCircle2, XCircle } from "lucide-react"
type Status = "verifying" | "success" | "error"
export function VerifyEmailForm() {
const searchParams = useSearchParams()
const token = searchParams.get("token")
const [status, setStatus] = useState<Status>(token ? "verifying" : "error")
const [email, setEmail] = useState<string | null>(null)
const [error, setError] = useState<string | null>(null)
useEffect(() => {
if (!token) {
setError("Mangler kode i lenken.")
return
}
async function verify() {
try {
const res = await fetch("/auth/profile/email/confirm", {
method: "POST",
headers: { "Content-Type": "application/json" },
credentials: "include",
body: JSON.stringify({ token }),
})
if (!res.ok) {
const body = await res.json().catch(() => null)
throw new Error(body?.detail?.message ?? "Lenken er ugyldig eller utløpt.")
}
const result: { email: string } = await res.json()
setEmail(result.email)
setStatus("success")
} catch (err) {
setError(err instanceof Error ? err.message : "Noe gikk galt. Prøv igjen.")
setStatus("error")
}
}
void verify()
}, [token])
if (status === "verifying") {
return (
<div className="flex w-full flex-col items-center gap-4 rounded-3xl border border-border bg-card p-8 text-center shadow-lg shadow-black/5">
<div
aria-hidden="true"
className="size-10 animate-spin rounded-full border-4 border-primary/20 border-t-primary"
/>
<p className="text-sm text-muted-foreground" role="status">
Bekrefter ny e-postadresse
</p>
</div>
)
}
if (status === "success") {
return (
<div className="flex w-full flex-col items-center gap-5 rounded-3xl border border-border bg-card p-6 text-center shadow-lg shadow-black/5 sm:p-8">
<div className="flex size-16 items-center justify-center rounded-2xl bg-primary/15">
<CheckCircle2 aria-hidden="true" className="size-8 text-primary" />
</div>
<div className="flex flex-col gap-2">
<h2 className="text-2xl font-extrabold tracking-tight text-balance">E-post oppdatert</h2>
{email && (
<p className="text-sm leading-relaxed text-muted-foreground text-pretty">
Du logger inn med <span className="font-semibold text-foreground">{email}</span>.
</p>
)}
</div>
<Link
href="/account"
className="text-sm font-semibold text-primary transition-colors hover:text-primary/80"
>
Til kontoinnstillinger
</Link>
</div>
)
}
return (
<div className="flex w-full flex-col items-center gap-5 rounded-3xl border border-border bg-card p-6 text-center shadow-lg shadow-black/5 sm:p-8">
<div className="flex size-16 items-center justify-center rounded-2xl bg-destructive/15">
<XCircle aria-hidden="true" className="size-8 text-destructive" />
</div>
<div className="flex flex-col gap-2">
<h2 className="text-2xl font-extrabold tracking-tight text-balance">Kunne ikke bekrefte</h2>
<p className="text-sm leading-relaxed text-muted-foreground text-pretty">{error}</p>
</div>
<Link
href="/account"
className="text-sm font-semibold text-primary transition-colors hover:text-primary/80"
>
Til kontoinnstillinger
</Link>
</div>
)
}