mirror of
https://github.com/temetro/temetro.git
synced 2026-09-01 13:29:16 +00:00
Add COSS toast notifications and swap in the new logo
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>
This commit is contained in:
@@ -7,6 +7,7 @@ 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("");
|
||||
@@ -27,9 +28,12 @@ export default function ForgotPasswordPage() {
|
||||
|
||||
setSubmitting(false);
|
||||
if (err) {
|
||||
setError(err.message ?? "Could not send the reset email.");
|
||||
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);
|
||||
};
|
||||
|
||||
|
||||
@@ -7,6 +7,7 @@ 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";
|
||||
|
||||
function slugify(value: string): string {
|
||||
return value
|
||||
@@ -45,12 +46,15 @@ export default function OnboardingPage() {
|
||||
);
|
||||
|
||||
if (createErr || !org) {
|
||||
setError(createErr?.message ?? "Could not create the clinic.");
|
||||
const message = createErr?.message ?? "Could not create the clinic.";
|
||||
setError(message);
|
||||
notify.error("Couldn't create clinic", message);
|
||||
setSubmitting(false);
|
||||
return;
|
||||
}
|
||||
|
||||
await authClient.organization.setActive({ organizationId: org.id });
|
||||
notify.success("Clinic created", `${org.name} is ready.`);
|
||||
router.push("/");
|
||||
};
|
||||
|
||||
|
||||
@@ -8,6 +8,7 @@ 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";
|
||||
|
||||
const MIN_PASSWORD = 12;
|
||||
|
||||
@@ -46,9 +47,12 @@ function ResetPasswordInner() {
|
||||
});
|
||||
setSubmitting(false);
|
||||
if (err) {
|
||||
setError(err.message ?? "Could not reset your password.");
|
||||
const message = err.message ?? "Could not reset your password.";
|
||||
setError(message);
|
||||
notify.error("Couldn't reset password", message);
|
||||
return;
|
||||
}
|
||||
notify.success("Password updated", "Redirecting you to sign in…");
|
||||
setDone(true);
|
||||
setTimeout(() => router.push("/login"), 1500);
|
||||
};
|
||||
|
||||
@@ -59,7 +59,51 @@
|
||||
background-position: -200% 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
--animate-toast-success-odd: toast-success-odd 0.32s cubic-bezier(0.5, 1, 0.89, 1);
|
||||
--animate-toast-success-even: toast-success-even 0.32s cubic-bezier(0.5, 1, 0.89, 1);
|
||||
--animate-toast-error-odd: toast-error-odd 0.28s cubic-bezier(0.5, 1, 0.89, 1);
|
||||
--animate-toast-error-even: toast-error-even 0.28s cubic-bezier(0.5, 1, 0.89, 1)
|
||||
;
|
||||
@keyframes toast-success-odd {
|
||||
0% {
|
||||
scale: 1;}
|
||||
30% {
|
||||
scale: 1.025;}
|
||||
60% {
|
||||
scale: 0.99;}
|
||||
100% {
|
||||
scale: 1;}}
|
||||
@keyframes toast-error-odd {
|
||||
0% {
|
||||
translate: 0 0;}
|
||||
25% {
|
||||
translate: -3px 0;}
|
||||
50% {
|
||||
translate: 3px 0;}
|
||||
75% {
|
||||
translate: -3px 0;}
|
||||
100% {
|
||||
translate: 0 0;}}
|
||||
@keyframes toast-success-even {
|
||||
0% {
|
||||
scale: 1;}
|
||||
30% {
|
||||
scale: 1.025;}
|
||||
60% {
|
||||
scale: 0.99;}
|
||||
100% {
|
||||
scale: 1;}}
|
||||
@keyframes toast-error-even {
|
||||
0% {
|
||||
translate: 0 0;}
|
||||
25% {
|
||||
translate: -3px 0;}
|
||||
50% {
|
||||
translate: 3px 0;}
|
||||
75% {
|
||||
translate: -3px 0;}
|
||||
100% {
|
||||
translate: 0 0;}}}
|
||||
|
||||
:root {
|
||||
--card: var(--color-white);
|
||||
|
||||
@@ -4,6 +4,7 @@ import "./globals.css";
|
||||
import { cn } from "@/lib/utils";
|
||||
import { ThemeProvider } from "@/components/theme-provider";
|
||||
import { I18nProvider } from "@/components/i18n-provider";
|
||||
import { ToastProvider } from "@/components/ui/toast";
|
||||
|
||||
// COSS font-variable contract: --font-sans, --font-heading, --font-mono.
|
||||
const inter = Inter({ subsets: ["latin"], variable: "--font-sans" });
|
||||
@@ -48,7 +49,9 @@ export default function RootLayout({
|
||||
enableSystem
|
||||
disableTransitionOnChange
|
||||
>
|
||||
<I18nProvider>{children}</I18nProvider>
|
||||
<ToastProvider>
|
||||
<I18nProvider>{children}</I18nProvider>
|
||||
</ToastProvider>
|
||||
</ThemeProvider>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
Reference in New Issue
Block a user