w-funnel/src/components/admin/builder/templates/InfoScreenConfig.tsx
gofnnp 2f1d71d26d payment
add solmate portrait page
2025-10-06 23:01:31 +04:00

168 lines
5.8 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

"use client";
import { useState } from "react";
import { ChevronDown, ChevronRight } from "lucide-react";
import { TextInput } from "@/components/ui/TextInput/TextInput";
import { ImageUpload } from "@/components/admin/builder/forms/ImageUpload";
import { VariablesConfig } from "./VariablesConfig";
import { useBuilderState } from "@/lib/admin/builder/context";
import type { InfoScreenDefinition } from "@/lib/funnel/types";
import type { BuilderScreen } from "@/lib/admin/builder/types";
interface InfoScreenConfigProps {
screen: BuilderScreen & { template: "info" };
onUpdate: (updates: Partial<InfoScreenDefinition>) => void;
}
function CollapsibleSection({
title,
children,
defaultExpanded = false,
}: {
title: string;
children: React.ReactNode;
defaultExpanded?: boolean;
}) {
const storageKey = `info-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 (
<div className="space-y-3">
<button
type="button"
onClick={handleToggle}
className="flex w-full items-center gap-2 text-left text-sm font-medium text-foreground hover:text-primary transition-colors"
>
{isExpanded ? (
<ChevronDown className="h-4 w-4" />
) : (
<ChevronRight className="h-4 w-4" />
)}
{title}
</button>
{isExpanded && <div className="ml-6 space-y-3">{children}</div>}
</div>
);
}
export function InfoScreenConfig({ screen, onUpdate }: InfoScreenConfigProps) {
const infoScreen = screen as InfoScreenDefinition;
const state = useBuilderState();
// Получаем доступные экраны для настройки условий переменных
const availableScreens = state.screens;
const handleIconChange = <T extends keyof NonNullable<InfoScreenDefinition["icon"]>>(
field: T,
value: NonNullable<InfoScreenDefinition["icon"]>[T] | undefined
) => {
const baseIcon = infoScreen.icon ?? { type: "emoji", value: "✨", size: "lg" };
if (field === "value") {
if (!value) {
onUpdate({ icon: undefined });
} else {
onUpdate({ icon: { ...baseIcon, value } });
}
return;
}
// При изменении типа иконки сбрасываем значение
if (field === "type") {
const defaultValue = value === "emoji" ? "✨" : "";
onUpdate({ icon: { ...baseIcon, type: value as "emoji" | "image", value: defaultValue } });
return;
}
onUpdate({ icon: { ...baseIcon, [field]: value } });
};
return (
<div className="space-y-4">
{/* Иконка */}
<CollapsibleSection title="Иконка" defaultExpanded={true}>
<div className="space-y-3">
<div className="space-y-2 text-xs">
<label className="flex flex-col gap-1 text-muted-foreground">
Тип иконки
<select
className="rounded-lg border border-border bg-background px-2 py-1"
value={infoScreen.icon?.type ?? "emoji"}
onChange={(event) => handleIconChange("type", event.target.value as "emoji" | "image")}
>
<option value="emoji">Emoji</option>
<option value="image">Изображение</option>
</select>
</label>
<label className="flex flex-col gap-1 text-muted-foreground">
Размер
<select
className="rounded-lg border border-border bg-background px-2 py-1"
value={infoScreen.icon?.size ?? "lg"}
onChange={(event) =>
handleIconChange("size", event.target.value as "sm" | "md" | "lg" | "xl")
}
>
<option value="sm">Маленький</option>
<option value="md">Средний</option>
<option value="lg">Большой</option>
<option value="xl">Огромный</option>
</select>
</label>
</div>
{infoScreen.icon?.type === "image" ? (
<div>
<span className="text-xs font-medium text-muted-foreground mb-2 block">
Изображение иконки
</span>
<ImageUpload
currentValue={infoScreen.icon?.value}
onImageSelect={(url) => handleIconChange("value", url)}
onImageRemove={() => handleIconChange("value", undefined)}
funnelId={screen.id}
/>
</div>
) : (
<label className="flex flex-col gap-2 text-sm">
<span className="text-xs font-medium text-muted-foreground">
Emoji символ
</span>
<TextInput
placeholder="Например, ✨"
value={infoScreen.icon?.value ?? ""}
onChange={(event) => handleIconChange("value", event.target.value || undefined)}
/>
</label>
)}
</div>
</CollapsibleSection>
{/* Переменные */}
<CollapsibleSection title="Переменные">
<VariablesConfig
variables={infoScreen.variables}
onUpdate={(variables) => onUpdate({ variables })}
availableScreens={availableScreens}
/>
</CollapsibleSection>
</div>
);
}