w-funnel/src/components/funnel/templates/SoulmatePortraitTemplate/SoulmatePortraitTemplate.tsx
2025-10-07 00:48:23 +02:00

150 lines
4.9 KiB
TypeScript

"use client";
import type {
SoulmatePortraitScreenDefinition,
DefaultTexts,
} from "@/lib/funnel/types";
import { TemplateLayout } from "../layouts/TemplateLayout";
import { createTemplateLayoutProps } from "@/lib/funnel/templateHelpers";
import Typography from "@/components/ui/Typography/Typography";
import { buildTypographyProps } from "@/lib/funnel/mappers";
import SoulmatePortraitsDelivered from "@/components/widgets/SoulmatePortraitsDelivered/SoulmatePortraitsDelivered";
import { cn } from "@/lib/utils";
interface SoulmatePortraitTemplateProps {
screen: SoulmatePortraitScreenDefinition;
onContinue: () => void;
canGoBack: boolean;
onBack: () => void;
screenProgress?: { current: number; total: number };
defaultTexts?: DefaultTexts;
}
export function SoulmatePortraitTemplate({
screen,
onContinue,
canGoBack,
onBack,
screenProgress,
defaultTexts,
}: SoulmatePortraitTemplateProps) {
// Скрываем subtitle как ненужный для этого экрана
const screenForLayout: SoulmatePortraitScreenDefinition = {
...screen,
subtitle: undefined,
};
const layoutProps = createTemplateLayoutProps(
screenForLayout,
{ canGoBack, onBack },
screenProgress,
{
preset: "center",
titleDefaults: {
font: "manrope",
weight: "bold",
align: "center",
size: "xl",
className: "leading-[125%] text-primary text-xl",
},
subtitleDefaults: undefined,
actionButton: {
defaultText: defaultTexts?.nextButton || "Continue",
disabled: false,
onClick: onContinue,
},
}
);
return (
<TemplateLayout {...layoutProps}>
<div className="max-w-[560px] mx-auto flex flex-col items-center gap-[30px]">
{screen.soulmatePortraitsDelivered && (
<SoulmatePortraitsDelivered
image={screen.soulmatePortraitsDelivered.image}
textProps={
screen.soulmatePortraitsDelivered.text
? buildTypographyProps(screen.soulmatePortraitsDelivered.text, {
as: "p",
defaults: { font: "inter", size: "sm", color: "primary" },
})
: undefined
}
avatarsProps={
screen.soulmatePortraitsDelivered.avatars
? {
avatars: screen.soulmatePortraitsDelivered.avatars.map(
(a) => ({
imageProps: a.src
? { src: a.src, alt: a.alt ?? "" }
: undefined,
fallbackProps: a.fallbackText
? {
children: (
<Typography
size="xs"
weight="bold"
className="text-[#FF6B9D]"
>
{a.fallbackText}
</Typography>
),
className: "bg-background",
}
: undefined,
className: a.fallbackText ? "w-fit px-1" : undefined,
})
),
}
: undefined
}
/>
)}
<div className="w-full flex flex-col items-center gap-2.5">
{screen.description &&
(() => {
const descProps = buildTypographyProps(screen.description, {
as: "p",
defaults: {
align: "center",
font: "inter",
size: "md",
weight: "bold",
className: "text-[25px] font-bold",
},
});
if (!descProps) return null;
const { children, ...rest } = descProps;
return (
<Typography {...rest} enableMarkup>
{children}
</Typography>
);
})()}
{screen.textList && (
<ul className={cn("list-disc pl-6 w-full")}>
{screen.textList.items.map((item, index) => {
const itemProps = buildTypographyProps(item, {
as: "li",
defaults: { font: "inter", weight: "medium", size: "md" },
});
if (!itemProps) return null;
const { children, ...rest } = itemProps;
return (
<Typography
key={index}
{...rest}
className={cn("list-item text-[17px] leading-[26px]")}
>
{children}
</Typography>
);
})}
</ul>
)}
</div>
</div>
</TemplateLayout>
);
}