Add Sonner-based notifications and UX polish
This commit is contained in:
@@ -40,9 +40,15 @@ const contactErrorMessages = {
|
||||
},
|
||||
} as const;
|
||||
|
||||
function withError(pathname: string, message: string) {
|
||||
const contactSuccessMessages = {
|
||||
ar: "شكراً على رسالتك.",
|
||||
en: "Thank you for your message.",
|
||||
de: "Vielen Dank fuer deine Nachricht.",
|
||||
} as const;
|
||||
|
||||
function withMessage(pathname: string, type: "success" | "error", message: string) {
|
||||
const params = new URLSearchParams();
|
||||
params.set("error", message);
|
||||
params.set(type, message);
|
||||
|
||||
return `${pathname}?${params.toString()}`;
|
||||
}
|
||||
@@ -80,18 +86,18 @@ export async function submitContactFormAction(formData: FormData) {
|
||||
message: values.message,
|
||||
});
|
||||
|
||||
redirect(getLocalizedPath(locale, "/success"));
|
||||
redirect(withMessage(getLocalizedPath(locale, "/success"), "success", contactSuccessMessages[locale]));
|
||||
} catch (error) {
|
||||
if (isRedirectError(error)) {
|
||||
throw error;
|
||||
}
|
||||
|
||||
if (error instanceof z.ZodError) {
|
||||
redirect(withError(contactPath, contactErrorMessages[locale].invalid));
|
||||
redirect(withMessage(contactPath, "error", contactErrorMessages[locale].invalid));
|
||||
}
|
||||
|
||||
if (error instanceof Error && error.message === "Too many contact requests. Please try again later.") {
|
||||
redirect(withError(contactPath, contactErrorMessages[locale].blocked));
|
||||
redirect(withMessage(contactPath, "error", contactErrorMessages[locale].blocked));
|
||||
}
|
||||
|
||||
if (
|
||||
@@ -100,10 +106,10 @@ export async function submitContactFormAction(formData: FormData) {
|
||||
error.message === "Turnstile verification failed." ||
|
||||
error.message === "Turnstile verification request failed.")
|
||||
) {
|
||||
redirect(withError(contactPath, contactErrorMessages[locale].verification));
|
||||
redirect(withMessage(contactPath, "error", contactErrorMessages[locale].verification));
|
||||
}
|
||||
|
||||
console.error("Contact form delivery failed.", error);
|
||||
redirect(withError(contactPath, contactErrorMessages[locale].failed));
|
||||
redirect(withMessage(contactPath, "error", contactErrorMessages[locale].failed));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,7 +5,6 @@ import { getTranslations } from "next-intl/server";
|
||||
import { Container } from "@/components/layout/container";
|
||||
import { PageHero } from "@/components/layout/page-hero";
|
||||
import { MotionFade } from "@/components/motion-fade";
|
||||
import { FlashMessage } from "@/components/root/flash-message";
|
||||
import { ContactForm } from "@/components/site/contact-form";
|
||||
import { buildLocalizedMetadata } from "@/lib/metadata";
|
||||
import { getPublicContactProtectionSettings } from "@/lib/app-config";
|
||||
@@ -19,9 +18,6 @@ type ContactPageProps = {
|
||||
params: {
|
||||
locale: string;
|
||||
};
|
||||
searchParams?: {
|
||||
error?: string;
|
||||
};
|
||||
};
|
||||
|
||||
export async function generateMetadata({
|
||||
@@ -38,10 +34,7 @@ export async function generateMetadata({
|
||||
});
|
||||
}
|
||||
|
||||
export default async function ContactPage({
|
||||
params: { locale },
|
||||
searchParams,
|
||||
}: ContactPageProps) {
|
||||
export default async function ContactPage({ params: { locale } }: ContactPageProps) {
|
||||
const localeKey = resolveLocale(locale);
|
||||
const [t, protection] = await Promise.all([
|
||||
getTranslations({ locale: localeKey, namespace: "contactPage" }),
|
||||
@@ -86,11 +79,6 @@ export default async function ContactPage({
|
||||
<MotionFade delay={0.05}>
|
||||
<AppCard>
|
||||
<CardContent className="pt-6">
|
||||
{searchParams?.error ? (
|
||||
<div className="mb-4">
|
||||
<FlashMessage type="error" message={searchParams.error} />
|
||||
</div>
|
||||
) : null}
|
||||
<ContactForm
|
||||
action={submitContactFormAction}
|
||||
locale={localeKey}
|
||||
|
||||
Reference in New Issue
Block a user