- Updated translation utility to improve consistency and reduce redundancy. - Removed deprecated useTrans hook and related code. - Introduced a new Zustand store for managing translations and locale settings. - Cleaned up unused hooks and files related to localization.
120 lines
3.3 KiB
TypeScript
120 lines
3.3 KiB
TypeScript
/** REACT / INERTIA */
|
|
import { usePage } from "@inertiajs/react";
|
|
import React, { SubmitEventHandler } from "react";
|
|
/** LUCIDE */
|
|
import { InfoIcon } from "lucide-react";
|
|
/** SHADCN */
|
|
import { Button } from "@/components/ui/button";
|
|
/** BASE */
|
|
import InputError from "$/base/InputError";
|
|
import { useRecaptcha } from "@/front/providers/RecaptchaProvider";
|
|
import trans 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: SubmitEventHandler<HTMLFormElement>;
|
|
data: TFormData & CustomData;
|
|
children: React.ReactNode;
|
|
footer?: React.ReactNode;
|
|
banner?: BannerClassName;
|
|
classNames?: {
|
|
wrapperClassName?: string;
|
|
formClassName?: string;
|
|
};
|
|
};
|
|
|
|
function RecaptchaNotice({ banner }: Readonly<{ banner?: BannerClassName }>) {
|
|
const { enabled } = useRecaptcha();
|
|
|
|
const title = trans("cookie-notice.custom.recaptcha.title");
|
|
const warning = trans("cookie-notice.custom.recaptcha.warning");
|
|
const label = trans("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,
|
|
}: Readonly<Props<TFormData>>) {
|
|
const { getToken, formRef, enabled } = useRecaptcha();
|
|
const { errors } = usePage().props;
|
|
const { recaptchaKey } = usePage().props.cookieEnv as CookieEnv;
|
|
const handleSubmit: SubmitEventHandler<HTMLFormElement> = (e) => {
|
|
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 ?? undefined}
|
|
inert={!enabled}
|
|
>
|
|
{children}
|
|
{enabled && (
|
|
<>
|
|
<InputError message={errors["g-recaptcha-response"]} />
|
|
<div className="r_captcha flex justify-center mt-8" />
|
|
</>
|
|
)}
|
|
{footer}
|
|
</form>
|
|
</div>
|
|
);
|
|
}
|