155 lines
4.9 KiB
TypeScript
155 lines
4.9 KiB
TypeScript
"use client";
|
||
|
||
import { useState } from "react";
|
||
import {
|
||
List,
|
||
FormInput,
|
||
Info,
|
||
Calendar,
|
||
Ticket,
|
||
Loader,
|
||
Heart,
|
||
Mail
|
||
} from "lucide-react";
|
||
|
||
import { Button } from "@/components/ui/button";
|
||
import {
|
||
Dialog,
|
||
DialogContent,
|
||
DialogDescription,
|
||
DialogHeader,
|
||
DialogTitle,
|
||
} from "@/components/ui/dialog";
|
||
import type { ScreenDefinition } from "@/lib/funnel/types";
|
||
|
||
interface AddScreenDialogProps {
|
||
open: boolean;
|
||
onOpenChange: (open: boolean) => void;
|
||
onAddScreen: (template: ScreenDefinition["template"]) => void;
|
||
}
|
||
|
||
const TEMPLATE_OPTIONS = [
|
||
{
|
||
template: "list" as const,
|
||
title: "Список",
|
||
description: "Выбор из списка вариантов (single/multi)",
|
||
icon: List,
|
||
color: "bg-blue-50 text-blue-600 dark:bg-blue-900/20 dark:text-blue-400",
|
||
},
|
||
{
|
||
template: "form" as const,
|
||
title: "Форма",
|
||
description: "Ввод текстовых данных в поля",
|
||
icon: FormInput,
|
||
color: "bg-purple-50 text-purple-600 dark:bg-purple-900/20 dark:text-purple-400",
|
||
},
|
||
{
|
||
template: "email" as const,
|
||
title: "Email",
|
||
description: "Ввод и валидация email адреса",
|
||
icon: Mail,
|
||
color: "bg-teal-50 text-teal-600 dark:bg-teal-900/20 dark:text-teal-400",
|
||
},
|
||
{
|
||
template: "info" as const,
|
||
title: "Информация",
|
||
description: "Отображение информации с кнопкой продолжить",
|
||
icon: Info,
|
||
color: "bg-gray-50 text-gray-600 dark:bg-gray-800 dark:text-gray-400",
|
||
},
|
||
{
|
||
template: "date" as const,
|
||
title: "Дата рождения",
|
||
description: "Выбор даты (месяц, день, год) + автоматический расчет возраста",
|
||
icon: Calendar,
|
||
color: "bg-green-50 text-green-600 dark:bg-green-900/20 dark:text-green-400",
|
||
},
|
||
{
|
||
template: "loaders" as const,
|
||
title: "Загрузка",
|
||
description: "Анимированные прогресс-бары с этапами обработки",
|
||
icon: Loader,
|
||
color: "bg-cyan-50 text-cyan-600 dark:bg-cyan-900/20 dark:text-cyan-400",
|
||
},
|
||
{
|
||
template: "soulmate" as const,
|
||
title: "Портрет партнера",
|
||
description: "Отображение результата анализа и портрета партнера",
|
||
icon: Heart,
|
||
color: "bg-pink-50 text-pink-600 dark:bg-pink-900/20 dark:text-pink-400",
|
||
},
|
||
{
|
||
template: "coupon" as const,
|
||
title: "Купон",
|
||
description: "Отображение промокода и предложения",
|
||
icon: Ticket,
|
||
color: "bg-orange-50 text-orange-600 dark:bg-orange-900/20 dark:text-orange-400",
|
||
},
|
||
] as const;
|
||
|
||
export function AddScreenDialog({ open, onOpenChange, onAddScreen }: AddScreenDialogProps) {
|
||
const [selectedTemplate, setSelectedTemplate] = useState<ScreenDefinition["template"] | null>(null);
|
||
|
||
const handleAdd = () => {
|
||
if (selectedTemplate) {
|
||
onAddScreen(selectedTemplate);
|
||
setSelectedTemplate(null);
|
||
onOpenChange(false);
|
||
}
|
||
};
|
||
|
||
const handleCancel = () => {
|
||
setSelectedTemplate(null);
|
||
onOpenChange(false);
|
||
};
|
||
|
||
return (
|
||
<Dialog open={open} onOpenChange={onOpenChange}>
|
||
<DialogContent className="max-w-2xl">
|
||
<DialogHeader>
|
||
<DialogTitle>Выберите тип экрана</DialogTitle>
|
||
<DialogDescription>
|
||
Выберите шаблон для нового экрана воронки
|
||
</DialogDescription>
|
||
</DialogHeader>
|
||
|
||
<div className="grid grid-cols-1 gap-3 py-4">
|
||
{TEMPLATE_OPTIONS.map((option) => {
|
||
const Icon = option.icon;
|
||
const isSelected = selectedTemplate === option.template;
|
||
|
||
return (
|
||
<button
|
||
key={option.template}
|
||
onClick={() => setSelectedTemplate(option.template)}
|
||
className={`flex items-start gap-4 rounded-lg border-2 p-4 text-left transition-all hover:bg-muted/50 ${
|
||
isSelected
|
||
? "border-primary bg-primary/5"
|
||
: "border-border hover:border-primary/40"
|
||
}`}
|
||
>
|
||
<div className={`flex h-10 w-10 items-center justify-center rounded-lg ${option.color}`}>
|
||
<Icon className="h-5 w-5" />
|
||
</div>
|
||
<div className="flex-1">
|
||
<h3 className="font-medium">{option.title}</h3>
|
||
<p className="text-sm text-muted-foreground">{option.description}</p>
|
||
</div>
|
||
</button>
|
||
);
|
||
})}
|
||
</div>
|
||
|
||
<div className="flex justify-end gap-2">
|
||
<Button variant="outline" onClick={handleCancel}>
|
||
Отмена
|
||
</Button>
|
||
<Button onClick={handleAdd} disabled={!selectedTemplate}>
|
||
Добавить экран
|
||
</Button>
|
||
</div>
|
||
</DialogContent>
|
||
</Dialog>
|
||
);
|
||
}
|