ldc-ovoteam/resources/ts/front/Components/Base/RecaptchaForm.tsx
2026-04-08 14:05:46 +02:00

120 lines
3.3 KiB
TypeScript

/** REACT / INERTIA */
import React, { FormEvent } from "react";
import { usePage } from "@inertiajs/react";
/** LUCIDE */
import { InfoIcon } from "lucide-react";
/** SHADCN */
import { Button } from "@/components/ui/button";
/** BASE */
import { useRecaptcha } from "@/front/providers/RecaptchaProvider";
import InputError from "$/base/InputError";
import useTrans from "@/hooks/use-translations";
import { cn } from "@/lib/utils";
interface CustomData {
"g-recaptcha-response"?: string;
}
type BannerClassName = {
classNames?: {
wrapperClassName?: string;
btnClassName?: string;
};
};
type Props<TFormData> = {
/* eslint-disable no-unused-vars, @typescript-eslint/no-unused-vars */
onSubmit: (e: FormEvent<HTMLFormElement>) => void;
data: TFormData & CustomData;
children: React.ReactNode;
footer?: React.ReactNode;
banner?: BannerClassName;
classNames?: {
wrapperClassName?: string;
formClassName?: string;
};
};
function RecaptchaNotice({ banner }: { banner?: BannerClassName }) {
const { enabled } = useRecaptcha();
const title = useTrans("cookie-notice.custom.recaptcha.title");
const warning = useTrans("cookie-notice.custom.recaptcha.warning");
const label = useTrans("cookie-notice.custom.recaptcha.accept");
const handleAccept = () => {
// @ts-expect-error External library
window.WebCookieNotice?.acceptCookie("recaptcha");
};
if (enabled) return null;
return (
<div
data-cookie-name="recaptcha"
className={cn(
"cn-cookie-activate flex flex-col rounded-lg border border-destructive/50 bg-card text-card-foreground shadow-sm gap-4 mb-4 p-6",
banner?.classNames?.wrapperClassName,
)}
>
<p className="text-2xl font-semibold leading-none tracking-tight flex flex-row w-full items-start">
<InfoIcon className="mr-1" />
{title}
</p>
<div className="flex flex-row justify-between items-center">
<small className="text-success fw-normal fs-5">{warning}</small>
<Button
className={cn(banner?.classNames?.btnClassName)}
id="recaptcha-accept"
type="button"
onClick={handleAccept}
>
{label}
</Button>
</div>
</div>
);
}
export default function RecaptchaForm<TFormData>({
onSubmit,
classNames,
banner,
data,
children,
footer,
}: Props<TFormData>) {
const { getToken, formRef, enabled } = useRecaptcha();
const { errors } = usePage().props;
const recaptchaKey = usePage().props.recaptchaKey as string;
const handleSubmit = (e: FormEvent<HTMLFormElement>) => {
e.preventDefault();
if (!enabled) return;
const token = getToken();
// eslint-disable-next-line no-param-reassign
data["g-recaptcha-response"] = token;
onSubmit(e);
};
return (
<div className={cn(classNames?.wrapperClassName)}>
<RecaptchaNotice banner={banner} />
<form
className={cn(classNames?.formClassName)}
ref={formRef}
onSubmit={handleSubmit}
data-recaptcha-key={recaptchaKey}
inert={!enabled}
>
{children}
{enabled && (
<>
<InputError message={errors["g-recaptcha-response"]} />
<div className="r_captcha flex justify-center mt-8" />
</>
)}
{footer}
</form>
</div>
);
}