import type { TypographyProps } from "@/components/ui/Typography/Typography"; import type { MainButtonProps } from "@/components/ui/MainButton/MainButton"; import type { HeaderDefinition, HeaderProgressDefinition, ListOptionDefinition, SelectionType, TypographyVariant, BottomActionButtonDefinition, ScreenDefinition, } from "./types"; import type { LayoutQuestionProps } from "@/components/layout/LayoutQuestion/LayoutQuestion"; import type { ActionButtonProps } from "@/components/ui/ActionButton/ActionButton"; import type { BottomActionButtonProps } from "@/components/widgets/BottomActionButton/BottomActionButton"; type TypographyAs = "span" | "p" | "h1" | "h2" | "h3" | "h4" | "h5" | "h6" | "div"; interface TypographyDefaults { font?: TypographyVariant["font"]; weight?: TypographyVariant["weight"]; size?: TypographyVariant["size"]; align?: TypographyVariant["align"]; color?: TypographyVariant["color"]; } interface BuildTypographyOptions { as: T; defaults?: TypographyDefaults; } export function buildTypographyProps( variant: TypographyVariant | undefined, options: BuildTypographyOptions ): TypographyProps | undefined { if (!variant) { return undefined; } const { as, defaults } = options; return { as, children: variant.text, font: variant.font ?? defaults?.font, weight: variant.weight ?? defaults?.weight, size: variant.size ?? defaults?.size, align: variant.align ?? defaults?.align, color: variant.color ?? defaults?.color, className: variant.className, } as TypographyProps; } export function buildHeaderProgress(progress?: HeaderProgressDefinition) { if (!progress) { return undefined; } const { current, total, value, label, className } = progress; const computedValue = value ?? (current !== undefined && total ? (current / total) * 100 : undefined); return { value: computedValue, label, className, }; } export function buildAutoHeaderProgress( currentScreenId: string, totalScreens: number, currentPosition: number, explicitProgress?: HeaderProgressDefinition ) { // If explicit progress is provided, use it if (explicitProgress) { return buildHeaderProgress(explicitProgress); } // Otherwise, auto-calculate const autoProgress: HeaderProgressDefinition = { current: currentPosition, total: totalScreens, label: `${currentPosition} of ${totalScreens}`, }; return buildHeaderProgress(autoProgress); } export function mapListOptionsToButtons( options: ListOptionDefinition[], selectionType: SelectionType ): MainButtonProps[] { return options.map((option) => ({ id: option.id, children: option.label, emoji: option.emoji, isCheckbox: selectionType === "multi", disabled: option.disabled, })); } export function shouldShowBackButton(header?: HeaderDefinition, canGoBack?: boolean) { if (header?.showBackButton === false) { return false; } return Boolean(canGoBack); } export function shouldShowHeader(header?: HeaderDefinition) { return header?.show !== false; } interface BuildActionButtonOptions { defaultText?: string; disabled?: boolean; onClick: () => void; } export function buildActionButtonProps( options: BuildActionButtonOptions, buttonDef?: BottomActionButtonDefinition ): ActionButtonProps { const { defaultText = "Continue", disabled = false, onClick } = options; return { children: buttonDef?.text ?? defaultText, cornerRadius: buttonDef?.cornerRadius, disabled: disabled, // disabled управляется только логикой экрана, не админкой onClick: disabled ? undefined : onClick, }; } export function buildBottomActionButtonProps( options: BuildActionButtonOptions, buttonDef?: BottomActionButtonDefinition ): BottomActionButtonProps | undefined { // Если кнопка отключена (show: false) - не показывать ничего if (buttonDef?.show === false) { return undefined; } // В остальных случаях показать кнопку с градиентом const actionButtonProps = buildActionButtonProps(options, buttonDef); return { actionButtonProps, showGradientBlur: true, // Градиент всегда включен (как требовалось) }; } interface BuildLayoutQuestionOptions { screen: ScreenDefinition; titleDefaults?: TypographyDefaults; subtitleDefaults?: TypographyDefaults; canGoBack: boolean; onBack: () => void; actionButtonOptions?: BuildActionButtonOptions; screenProgress?: { current: number; total: number }; } export function buildLayoutQuestionProps( options: BuildLayoutQuestionOptions ): Omit { const { screen, titleDefaults = { font: "manrope", weight: "bold", align: "left" }, subtitleDefaults = { font: "inter", weight: "medium", color: "muted", align: "left" }, canGoBack, onBack, actionButtonOptions, screenProgress } = options; const showBackButton = shouldShowBackButton(screen.header, canGoBack); const showHeader = shouldShowHeader(screen.header); const bottomActionButtonProps = actionButtonOptions ? buildBottomActionButtonProps( actionButtonOptions, // Если передаются actionButtonOptions, это означает что кнопка должна показываться // Если кнопка отключена (show: false), принудительно включаем её 'bottomActionButton' in screen ? (screen.bottomActionButton?.show === false ? { ...screen.bottomActionButton, show: true } : screen.bottomActionButton) : undefined ) : undefined; return { headerProps: showHeader ? { progressProps: screenProgress ? buildHeaderProgress({ current: screenProgress.current, total: screenProgress.total, label: `${screenProgress.current} of ${screenProgress.total}` }) : buildHeaderProgress(screen.header?.progress), onBack: showBackButton ? onBack : undefined, showBackButton, } : undefined, title: buildTypographyProps(screen.title, { as: "h2", defaults: titleDefaults, }) ?? { as: "h2", children: screen.title.text, }, subtitle: 'subtitle' in screen ? buildTypographyProps(screen.subtitle, { as: "p", defaults: subtitleDefaults, }) : undefined, bottomActionButtonProps, }; }