"use client"; import React, { useState, useEffect } from "react"; import { ChevronDown, ChevronRight } from "lucide-react"; import { InfoScreenConfig } from "./InfoScreenConfig"; import { DateScreenConfig } from "./DateScreenConfig"; import { CouponScreenConfig } from "./CouponScreenConfig"; import { FormScreenConfig } from "./FormScreenConfig"; import { ListScreenConfig } from "./ListScreenConfig"; import { EmailScreenConfig } from "./EmailScreenConfig"; import { LoadersScreenConfig } from "./LoadersScreenConfig"; import { SoulmatePortraitScreenConfig } from "./SoulmatePortraitScreenConfig"; import { TextInput } from "@/components/ui/TextInput/TextInput"; import { TextAreaInput } from "@/components/ui/TextAreaInput/TextAreaInput"; import type { BuilderScreen } from "@/lib/admin/builder/types"; import type { ScreenDefinition, InfoScreenDefinition, DateScreenDefinition, CouponScreenDefinition, FormScreenDefinition, ListScreenDefinition, EmailScreenDefinition, LoadersScreenDefinition, SoulmatePortraitScreenDefinition, TypographyVariant, BottomActionButtonDefinition, HeaderDefinition, } from "@/lib/funnel/types"; const RADIUS_OPTIONS: ("3xl" | "full")[] = ["3xl", "full"]; interface TemplateConfigProps { screen: BuilderScreen; onUpdate: (updates: Partial) => void; } function CollapsibleSection({ title, children, defaultExpanded = false, }: { title: string; children: React.ReactNode; defaultExpanded?: boolean; }) { const storageKey = `template-section-${title.toLowerCase().replace(/\s+/g, '-')}`; const [isExpanded, setIsExpanded] = useState(() => { if (typeof window === 'undefined') return defaultExpanded; const stored = sessionStorage.getItem(storageKey); return stored !== null ? JSON.parse(stored) : defaultExpanded; }); const handleToggle = () => { const newExpanded = !isExpanded; setIsExpanded(newExpanded); if (typeof window !== 'undefined') { sessionStorage.setItem(storageKey, JSON.stringify(newExpanded)); } }; return (
{isExpanded &&
{children}
}
); } interface TypographyControlsProps { label: string; value: (TypographyVariant & { show?: boolean }) | undefined; onChange: (value: (TypographyVariant & { show?: boolean }) | undefined) => void; allowRemove?: boolean; showToggle?: boolean; // Показывать ли чекбокс "Показывать" } function TypographyControls({ label, value, onChange, allowRemove = false, showToggle = false }: TypographyControlsProps) { const storageKey = `typography-advanced-${label.toLowerCase().replace(/\s+/g, '-')}`; const [showAdvanced, setShowAdvanced] = useState(false); const [isHydrated, setIsHydrated] = useState(false); useEffect(() => { const stored = sessionStorage.getItem(storageKey); if (stored !== null) { setShowAdvanced(JSON.parse(stored)); } setIsHydrated(true); }, [storageKey]); const handleTextChange = (text: string) => { if (text.trim() === "" && allowRemove) { onChange(undefined); return; } // Сохраняем существующие настройки или используем минимальные дефолты onChange({ ...value, text, }); }; const handleAdvancedChange = (field: keyof TypographyVariant, fieldValue: string) => { onChange({ ...value, text: value?.text || "", [field]: fieldValue || undefined, }); }; const handleShowToggle = (show: boolean) => { onChange({ ...value, text: value?.text || "", show, }); }; return (
{showToggle && ( )}
handleTextChange(event.target.value)} rows={2} className="resize-y" />
{value?.text && (
{(isHydrated ? showAdvanced : false) && (
)}
)}
); } interface HeaderControlsProps { header: HeaderDefinition | undefined; onChange: (value: HeaderDefinition | undefined) => void; } function HeaderControls({ header, onChange }: HeaderControlsProps) { const activeHeader = header ?? { show: true, showBackButton: true }; const handleToggle = (field: "show" | "showBackButton", checked: boolean) => { if (field === "show" && !checked) { onChange({ ...activeHeader, show: false, showBackButton: false, }); return; } onChange({ ...activeHeader, [field]: checked, }); }; return (
{activeHeader.show !== false && (
)}
); } interface ActionButtonControlsProps { label: string; value: BottomActionButtonDefinition | undefined; onChange: (value: BottomActionButtonDefinition | undefined) => void; } function ActionButtonControls({ label, value, onChange }: ActionButtonControlsProps) { // По умолчанию кнопка включена (show !== false) const isEnabled = value?.show !== false; const buttonText = value?.text || ''; const cornerRadius = value?.cornerRadius; const showPrivacyTermsConsent = value?.showPrivacyTermsConsent ?? false; const handleToggle = (enabled: boolean) => { if (enabled) { // Включаем кнопку - убираем show: false или создаем объект const newValue = value ? { ...value, show: true } : { show: true }; // Если show: true по умолчанию, можем убрать это поле if (newValue.show === true && !newValue.text && !newValue.cornerRadius) { onChange(undefined); // Дефолтное состояние } else { const { show, ...rest } = newValue; onChange(Object.keys(rest).length > 0 ? { show, ...rest } : undefined); } } else { // Отключаем кнопку onChange({ show: false }); } }; const handleTextChange = (text: string) => { if (!isEnabled) return; const trimmedText = text.trim(); const newValue = { ...value, text: trimmedText || undefined, }; // Убираем undefined поля для чистоты if (!newValue.text && !newValue.cornerRadius && newValue.show !== false) { onChange(undefined); } else { onChange(newValue); } }; const handleRadiusChange = (radius: string) => { if (!isEnabled) return; const newRadius = (radius as "3xl" | "full") || undefined; const newValue = { ...value, cornerRadius: newRadius, }; // Убираем undefined поля для чистоты if (!newValue.text && !newValue.cornerRadius && newValue.show !== false && !newValue.showPrivacyTermsConsent) { onChange(undefined); } else { onChange(newValue); } }; const handlePrivacyTermsToggle = (checked: boolean) => { if (!isEnabled) return; const newValue = { ...value, showPrivacyTermsConsent: checked || undefined, }; // Убираем undefined поля для чистоты if (!newValue.text && !newValue.cornerRadius && newValue.show !== false && !newValue.showPrivacyTermsConsent) { onChange(undefined); } else { onChange(newValue); } }; return (
{isEnabled && (
)}
); } export function TemplateConfig({ screen, onUpdate }: TemplateConfigProps) { const { template } = screen; const handleTitleChange = (value: TypographyVariant | undefined) => { if (!value) { return; } onUpdate({ title: value }); }; const handleSubtitleChange = (value: TypographyVariant | undefined) => { onUpdate({ subtitle: value }); }; const handleHeaderChange = (value: HeaderDefinition | undefined) => { onUpdate({ header: value }); }; const handleButtonChange = (value: BottomActionButtonDefinition | undefined) => { onUpdate({ bottomActionButton: value }); }; return (
{template === "info" && ( ) => void} /> )} {template === "date" && ( ) => void} /> )} {template === "coupon" && ( ) => void} /> )} {template === "form" && ( ) => void} /> )} {template === "list" && ( ) => void} /> )} {template === "email" && ( ) => void} /> )} {template === "loaders" && ( ) => void} /> )} {template === "soulmate" && ( ) => void} /> )}
); }