Files
stream-demo-standalone/src/features/lead-form/LeadForm.tsx
T

156 lines
5.3 KiB
TypeScript

import { useMemo, useState } from "react";
import { useTranslation } from "react-i18next";
import { api } from "@/lib/api";
import { productOptionsFromT } from "@/lib/productLabels";
import type { Product } from "@/types";
import { Button } from "@/ui/Button";
import { CheckboxesGroup } from "@/ui/CheckboxesGroup";
import { PhoneInputRu } from "@/ui/PhoneInputRu";
import { useRefererStore } from "@/stores/useRefererStore";
import {
Controller,
FormProvider,
useForm,
type SubmitHandler,
} from "react-hook-form";
import type { LeadFormValues } from "./types";
export type { LeadFormValues } from "./types";
<<<<<<< HEAD
=======
const GENERIC_SUBMIT_ERROR = "Не удалось отправить заявку. Попробуйте позже.";
>>>>>>> 258568050cbcb3e46cc31416fc9a0ba7a21ac066
export function LeadForm({
defaultProducts,
idPrefix = "",
onSuccess,
phonePlaceholder,
formClassName = "lg:space-y-[1.944vw] md:max-lg:space-y-7 space-y-3",
}: {
defaultProducts: Product[];
/** Префикс для id полей (например `modal-`), чтобы избежать дублей в DOM */
idPrefix?: string;
onSuccess: (id: string) => void;
phonePlaceholder?: string;
formClassName?: string;
}) {
const { t } = useTranslation();
const { referer } = useRefererStore();
const [submitError, setSubmitError] = useState<string | null>(null);
const projectOptions = useMemo(() => productOptionsFromT(t), [t]);
const form = useForm<LeadFormValues>({
defaultValues: {
fullname: "",
email: "",
phone: "",
products: defaultProducts,
},
});
const { register, handleSubmit, formState, control } = form;
const nameId = idPrefix ? `${idPrefix}name` : "name";
const emailId = idPrefix ? `${idPrefix}email` : "email";
const onSubmit: SubmitHandler<LeadFormValues> = async (data) => {
setSubmitError(null);
try {
const { id } = await api
.post("mail", { json: { ...data, referer } })
.json<{ id: string }>();
onSuccess(id);
} catch {
setSubmitError(t("leadForm.submitError"));
}
};
return (
<FormProvider {...form}>
<form
className={formClassName}
onSubmit={handleSubmit(onSubmit)}
noValidate
>
{submitError ? (
<p className="text-sm text-red-400" role="alert">
{submitError}
</p>
) : null}
<div className="lg:space-y-[1.111vw] space-y-4">
<p className="heading2 font-medium">{t("leadForm.needTitle")}</p>
<CheckboxesGroup<LeadFormValues>
name="products"
options={projectOptions}
/>
</div>
<input
id={nameId}
autoComplete="none"
type="text"
required
placeholder={t("leadForm.namePlaceholder")}
{...register("fullname")}
className="bg-transparent border-b border-[#37393B] focus:border-white py-4 rounded-none outline-none transition-all w-full placeholder:btnl btnl placeholder:font-medium placeholder:select-none"
/>
<input
autoComplete="none"
required
id={emailId}
type="email"
placeholder={t("leadForm.emailPlaceholder")}
{...register("email")}
className="bg-transparent border-b border-[#37393B] focus:border-white py-4 rounded-none btnl outline-none transition-all w-full placeholder:btnl placeholder:font-medium placeholder:select-none"
/>
<div className="flex gap-x-3 py-2 border-[#3D425C] relative">
<Controller
name="phone"
control={control}
rules={{ required: true }}
render={({ field }) => (
<PhoneInputRu
value={field.value}
onChange={field.onChange}
onBlur={field.onBlur}
inputRef={field.ref}
placeholder={phonePlaceholder}
/>
)}
/>
<div className="bottom-0 absolute w-full border-b border-[#37393B] peer-focus:border-white -mb-2" />
</div>
<div className="md:flex items-stretch lg:gap-[0.833vw] gap-3 max-md:translate-y-2">
<Button
type="submit"
disabled={formState.isSubmitting}
className="btnl max-md:mb-3 max-md:w-full lg:px-[2.222vw] lg:py-[1.389vw] px-8 py-5 cursor-pointer lg:rounded-[1.111vw] rounded-2xl disabled:opacity-60"
>
{t("leadForm.submit")}
</Button>
<div className="text2 xl:max-w-[60%] md:max-lg:max-w-[40%] md:max-lg:py-1">
<span className="text-[#7A7A7A]">{t("leadForm.consentBefore")}</span>{" "}
<a
target="_blank"
rel="noopener noreferrer"
href="https://graff.estate/privacy-policy"
className="underline"
>
{t("leadForm.consentLinkData")}
</a>{" "}
<span className="text-[#7A7A7A]">{t("leadForm.consentMiddle")} </span>
<a
target="_blank"
rel="noopener noreferrer"
href="/policy"
className="underline"
>
{t("leadForm.consentLinkPolicy")}
</a>
</div>
</div>
</form>
</FormProvider>
);
}