124 lines
3.6 KiB
TypeScript
124 lines
3.6 KiB
TypeScript
import { usePage } from "@inertiajs/react";
|
|
import { InfoIcon } from "lucide-react";
|
|
import type React from "react";
|
|
import { type SubmitEvent } from "react";
|
|
|
|
import { Button } from "@/components/ui/button";
|
|
import { cnServices } from "@/front/Components/cookie/constants";
|
|
import InputError from "@/front/Components/cookie/InputError";
|
|
import { useRecaptcha } from "@/front/Components/cookie/recaptcha/RecaptchaProvider";
|
|
import { type CookieEnv } from "@/front/types/cookie";
|
|
import useCookieNotice from "@/hooks/use-cookie-notice";
|
|
import useTrans from "@/hooks/use-translations";
|
|
import { cn } from "@/lib/utils";
|
|
|
|
interface CustomData {
|
|
"g-recaptcha-response"?: string;
|
|
}
|
|
|
|
interface BannerClassName {
|
|
classNames?: {
|
|
wrapperClassName?: string;
|
|
btnClassName?: string;
|
|
};
|
|
}
|
|
|
|
interface Props<TFormData> {
|
|
onSubmit: (e: SubmitEvent<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 { accept } = useCookieNotice(cnServices.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={accept}
|
|
>
|
|
{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, recaptchaBypassKey } = usePage().props
|
|
.cookieEnv as CookieEnv;
|
|
const { mode } = usePage().props.appEnv as AppEnv;
|
|
|
|
const isTestingEnv = mode === "testing";
|
|
|
|
const formIsEnabled = isTestingEnv || enabled;
|
|
|
|
const handleSubmit = (e: SubmitEvent<HTMLFormElement>) => {
|
|
e.preventDefault();
|
|
if (!formIsEnabled) return;
|
|
const token = getToken();
|
|
// eslint-disable-next-line react-hooks/immutability
|
|
data["g-recaptcha-response"] = isTestingEnv ? recaptchaBypassKey : 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}
|
|
{...(!formIsEnabled ? { inert: true } : {})}
|
|
>
|
|
{children}
|
|
{formIsEnabled && (
|
|
<>
|
|
<InputError message={errors["g-recaptcha-response"]} />
|
|
<div className="r_captcha flex justify-center mt-8" />
|
|
</>
|
|
)}
|
|
{footer}
|
|
</form>
|
|
</div>
|
|
);
|
|
}
|