mirror of
https://github.com/temetro/temetro.git
synced 2026-08-28 11:27:40 +00:00
2c5624e049
Wire COSS's (Base UI) Sonner-style stacked toast into the app:
- Install @coss/toast (components/ui/toast.tsx) and mount <ToastProvider> in
the root layout; add a small notify.{success,error,info,warning} helper
(lib/toast.ts) over toastManager so callers don't repeat the toast shape.
- Toast on the events requested: clinic created (onboarding), auth actions
(sign in / sign up / sign out / password reset request + reset), patient
saved (create/edit), and all failure branches as error toasts (kept inline
errors as a fallback). New auth toast strings added to the en translation.
- Replace the logo everywhere: overwrite public/temetro-logo.png with the new
1024² square mark (same aspect ratio as the old 500², so existing 32×32
next/image usages stay undistorted; no reference changes needed).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
77 lines
2.3 KiB
TypeScript
77 lines
2.3 KiB
TypeScript
"use client";
|
|
|
|
import Link from "next/link";
|
|
import { type FormEvent, useState } from "react";
|
|
|
|
import { AuthShell, Field, FormAlert } from "@/components/auth/auth-ui";
|
|
import { Button } from "@/components/ui/button";
|
|
import { Input } from "@/components/ui/input";
|
|
import { authClient } from "@/lib/auth-client";
|
|
import { notify } from "@/lib/toast";
|
|
|
|
export default function ForgotPasswordPage() {
|
|
const [email, setEmail] = useState("");
|
|
const [sent, setSent] = useState(false);
|
|
const [error, setError] = useState<string | null>(null);
|
|
const [submitting, setSubmitting] = useState(false);
|
|
|
|
const onSubmit = async (event: FormEvent) => {
|
|
event.preventDefault();
|
|
if (submitting) return;
|
|
setSubmitting(true);
|
|
setError(null);
|
|
|
|
const { error: err } = await authClient.requestPasswordReset({
|
|
email: email.trim(),
|
|
redirectTo: `${window.location.origin}/reset-password`,
|
|
});
|
|
|
|
setSubmitting(false);
|
|
if (err) {
|
|
const message = err.message ?? "Could not send the reset email.";
|
|
setError(message);
|
|
notify.error("Couldn't send reset link", message);
|
|
return;
|
|
}
|
|
notify.success("Reset link sent", "Check your inbox for the link.");
|
|
setSent(true);
|
|
};
|
|
|
|
return (
|
|
<AuthShell
|
|
footer={
|
|
<Link className="text-foreground hover:underline" href="/login">
|
|
Back to sign in
|
|
</Link>
|
|
}
|
|
subtitle="We'll email you a link to reset your password"
|
|
title="Reset your password"
|
|
>
|
|
{sent ? (
|
|
<FormAlert tone="success">
|
|
If an account exists for {email}, a reset link is on its way. Check
|
|
your inbox.
|
|
</FormAlert>
|
|
) : (
|
|
<form className="flex flex-col gap-4" onSubmit={onSubmit}>
|
|
{error && <FormAlert>{error}</FormAlert>}
|
|
<Field htmlFor="email" label="Email">
|
|
<Input
|
|
autoComplete="email"
|
|
id="email"
|
|
onChange={(e) => setEmail(e.target.value)}
|
|
placeholder="you@clinic.org"
|
|
required
|
|
type="email"
|
|
value={email}
|
|
/>
|
|
</Field>
|
|
<Button className="mt-1 w-full" disabled={submitting} type="submit">
|
|
{submitting ? "Sending…" : "Send reset link"}
|
|
</Button>
|
|
</form>
|
|
)}
|
|
</AuthShell>
|
|
);
|
|
}
|