157 lines
4.3 KiB
TypeScript
157 lines
4.3 KiB
TypeScript
"use client";
|
|
|
|
import { useState, useEffect } from "react";
|
|
import Image from "next/image";
|
|
import PrivacySecurityBanner from "@/components/widgets/PrivacySecurityBanner/PrivacySecurityBanner";
|
|
import { TextInput } from "@/components/ui/TextInput/TextInput";
|
|
import type {
|
|
EmailScreenDefinition,
|
|
DefaultTexts,
|
|
FunnelDefinition,
|
|
FunnelAnswers,
|
|
} from "@/lib/funnel/types";
|
|
import { buildRegistrationDataFromAnswers } from "@/lib/funnel/registrationHelpers";
|
|
import { TemplateLayout } from "../layouts/TemplateLayout";
|
|
import { createTemplateLayoutProps } from "@/lib/funnel/templateHelpers";
|
|
import { zodResolver } from "@hookform/resolvers/zod";
|
|
import { useForm } from "react-hook-form";
|
|
import { z } from "zod";
|
|
import { Spinner } from "@/components/ui/spinner";
|
|
import { useAuth } from "@/hooks/auth/useAuth";
|
|
|
|
const formSchema = z.object({
|
|
email: z.email({
|
|
message: "Please enter a valid email address",
|
|
}),
|
|
});
|
|
|
|
interface EmailTemplateProps {
|
|
funnel: FunnelDefinition;
|
|
screen: EmailScreenDefinition;
|
|
selectedEmail: string;
|
|
onEmailChange: (email: string) => void;
|
|
onContinue: () => void;
|
|
canGoBack: boolean;
|
|
onBack: () => void;
|
|
screenProgress?: { current: number; total: number };
|
|
defaultTexts?: DefaultTexts;
|
|
answers: FunnelAnswers;
|
|
}
|
|
|
|
export function EmailTemplate({
|
|
funnel,
|
|
screen,
|
|
selectedEmail,
|
|
onEmailChange,
|
|
onContinue,
|
|
canGoBack,
|
|
onBack,
|
|
screenProgress,
|
|
defaultTexts,
|
|
answers,
|
|
}: EmailTemplateProps) {
|
|
// Собираем данные для регистрации из ответов воронки
|
|
const registrationData = buildRegistrationDataFromAnswers(funnel, answers);
|
|
|
|
const { authorization, isLoading, error } = useAuth({
|
|
funnelId: funnel?.meta?.id ?? "preview",
|
|
registrationData,
|
|
});
|
|
|
|
const [isTouched, setIsTouched] = useState(false);
|
|
|
|
const form = useForm<z.infer<typeof formSchema>>({
|
|
resolver: zodResolver(formSchema),
|
|
defaultValues: {
|
|
email: selectedEmail || "",
|
|
},
|
|
});
|
|
|
|
useEffect(() => {
|
|
form.setValue("email", selectedEmail || "");
|
|
}, [selectedEmail, form]);
|
|
|
|
const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {
|
|
const value = e.target.value;
|
|
form.setValue("email", value);
|
|
form.trigger("email");
|
|
onEmailChange(value);
|
|
};
|
|
|
|
const handleContinue = async () => {
|
|
const email = form.getValues("email");
|
|
|
|
if (!email || !form.formState.isValid || isLoading) {
|
|
return;
|
|
}
|
|
|
|
try {
|
|
const token = await authorization(email);
|
|
if (token) {
|
|
onContinue();
|
|
}
|
|
} catch (err) {
|
|
console.error("Authorization failed:", err);
|
|
}
|
|
};
|
|
|
|
const isFormValid = form.formState.isValid && form.getValues("email");
|
|
|
|
const layoutProps = createTemplateLayoutProps(
|
|
screen,
|
|
{ canGoBack, onBack },
|
|
screenProgress,
|
|
{
|
|
preset: "center",
|
|
actionButton: {
|
|
children: isLoading ? <Spinner className="size-6" /> : undefined,
|
|
defaultText: defaultTexts?.nextButton || "Continue",
|
|
disabled: !isFormValid,
|
|
onClick: handleContinue,
|
|
},
|
|
}
|
|
);
|
|
|
|
return (
|
|
<TemplateLayout {...layoutProps}>
|
|
<div className="w-full flex flex-col items-center gap-[26px]">
|
|
<TextInput
|
|
label={screen.emailInput?.label || "Email"}
|
|
placeholder={screen.emailInput?.placeholder || "Enter your Email"}
|
|
type="email"
|
|
value={selectedEmail}
|
|
onChange={handleChange}
|
|
onBlur={() => {
|
|
setIsTouched(true);
|
|
form.trigger("email");
|
|
}}
|
|
aria-invalid={(isTouched && !!form.formState.errors.email) || !!error}
|
|
aria-errormessage={
|
|
(isTouched ? form.formState.errors.email?.message : undefined) ||
|
|
(error ? "Something went wrong" : undefined)
|
|
}
|
|
/>
|
|
|
|
{screen.image && (
|
|
<Image
|
|
src={screen.image.src}
|
|
alt="portrait"
|
|
width={164}
|
|
height={245}
|
|
className="mt-3.5 rounded-[50px] blur-sm"
|
|
/>
|
|
)}
|
|
|
|
<PrivacySecurityBanner
|
|
className="mt-[26px]"
|
|
text={{
|
|
children:
|
|
defaultTexts?.privacyBanner ||
|
|
"Мы не передаем личную информацию, она остаётся в безопасности и под вашим контролем.",
|
|
}}
|
|
/>
|
|
</div>
|
|
</TemplateLayout>
|
|
);
|
|
}
|