"use client";
import type { JSX } from "react";
import {
ListTemplate,
InfoTemplate,
DateTemplate,
CouponTemplate,
FormTemplate,
EmailTemplate,
LoadersTemplate,
SoulmatePortraitTemplate,
TrialPaymentTemplate,
} from "@/components/funnel/templates";
import type {
ListScreenDefinition,
DateScreenDefinition,
FormScreenDefinition,
CouponScreenDefinition,
InfoScreenDefinition,
EmailScreenDefinition,
LoadersScreenDefinition,
SoulmatePortraitScreenDefinition,
TrialPaymentScreenDefinition,
ScreenDefinition,
DefaultTexts,
FunnelDefinition,
FunnelAnswers,
} from "@/lib/funnel/types";
export interface ScreenRenderProps {
funnel: FunnelDefinition;
screen: ScreenDefinition;
selectedOptionIds: string[];
onSelectionChange: (ids: string[]) => void;
onContinue: () => void;
canGoBack: boolean;
onBack: () => void;
screenProgress: { current: number; total: number };
defaultTexts?: DefaultTexts;
answers: FunnelAnswers;
}
export type TemplateRenderer = (props: ScreenRenderProps) => JSX.Element;
const TEMPLATE_REGISTRY: Record<
ScreenDefinition["template"],
TemplateRenderer
> = {
info: ({
screen,
onContinue,
canGoBack,
onBack,
screenProgress,
defaultTexts,
answers,
}) => {
const infoScreen = screen as InfoScreenDefinition;
return (
);
},
date: ({
screen,
selectedOptionIds,
onSelectionChange,
onContinue,
canGoBack,
onBack,
screenProgress,
defaultTexts,
}) => {
const dateScreen = screen as DateScreenDefinition;
// For date screens, we store date components as array: [month, day, year]
const currentDateArray = selectedOptionIds;
const selectedDate = {
month: currentDateArray[0] || "",
day: currentDateArray[1] || "",
year: currentDateArray[2] || "",
};
const handleDateChange = (date: {
month?: string;
day?: string;
year?: string;
}) => {
const dateArray = [date.month || "", date.day || "", date.year || ""];
onSelectionChange(dateArray);
};
return (
);
},
form: ({
screen,
selectedOptionIds,
onSelectionChange,
onContinue,
canGoBack,
onBack,
screenProgress,
defaultTexts,
}) => {
const formScreen = screen as FormScreenDefinition;
// For form screens, we store form data as JSON string in the first element
const formDataJson = selectedOptionIds[0] || "{}";
let formData: Record = {};
try {
formData = JSON.parse(formDataJson);
} catch {
formData = {};
}
const handleFormDataChange = (data: Record) => {
const dataJson = JSON.stringify(data);
onSelectionChange([dataJson]);
};
return (
);
},
coupon: ({
screen,
onContinue,
canGoBack,
onBack,
screenProgress,
defaultTexts,
}) => {
const couponScreen = screen as CouponScreenDefinition;
return (
);
},
list: ({
screen,
selectedOptionIds,
onSelectionChange,
onContinue,
canGoBack,
onBack,
screenProgress,
defaultTexts,
}) => {
const listScreen = screen as ListScreenDefinition;
const isSelectionEmpty = selectedOptionIds.length === 0;
// Используем только общую кнопку экрана
const bottomActionButton = listScreen.bottomActionButton;
const isButtonDisabled = bottomActionButton?.show === false;
// Простая логика: кнопка есть если не отключена (show: false)
const hasActionButton = !isButtonDisabled;
// Правильная логика приоритетов для текста кнопки:
// 1. bottomActionButton.text (настройка экрана)
// 2. defaultTexts.nextButton (глобальная настройка воронки)
// 3. "Next" (хардкод fallback)
const buttonText =
bottomActionButton?.text || defaultTexts?.nextButton || "Next";
const actionDisabled = hasActionButton && isSelectionEmpty;
return (
);
},
email: ({
screen,
selectedOptionIds,
onSelectionChange,
onContinue,
canGoBack,
onBack,
screenProgress,
defaultTexts,
funnel,
}) => {
const emailScreen = screen as EmailScreenDefinition;
// For email screens, we store email as single string in first element
const selectedEmail = selectedOptionIds[0] || "";
const handleEmailChange = (email: string) => {
onSelectionChange([email]);
};
return (
);
},
loaders: ({
screen,
onContinue,
canGoBack,
onBack,
screenProgress,
defaultTexts,
}) => {
const loadersScreen = screen as LoadersScreenDefinition;
return (
);
},
soulmate: ({
screen,
onContinue,
canGoBack,
onBack,
screenProgress,
defaultTexts,
}) => {
const soulmateScreen = screen as SoulmatePortraitScreenDefinition;
return (
);
},
trialPayment: ({
screen,
onContinue,
canGoBack,
onBack,
screenProgress,
defaultTexts,
funnel,
}) => {
const trialPaymentScreen = screen as TrialPaymentScreenDefinition;
return (
);
},
};
export function renderScreen(props: ScreenRenderProps): JSX.Element {
const renderer = TEMPLATE_REGISTRY[props.screen.template];
if (!renderer) {
throw new Error(`Unsupported template: ${props.screen.template}`);
}
return renderer(props);
}
export function getTemplateRenderer(
screen: ScreenDefinition
): TemplateRenderer {
const renderer = TEMPLATE_REGISTRY[screen.template];
if (!renderer) {
throw new Error(`Unsupported template: ${screen.template}`);
}
return renderer;
}