241 lines
7.4 KiB
TypeScript
241 lines
7.4 KiB
TypeScript
import { Plus, Wrench } from 'lucide-react'
|
||
import { FC, useState } from 'react'
|
||
import { useNavigate } from 'react-router-dom'
|
||
import { ElementConstructor } from '../../../../components/TemplateManager/ElementConstructor'
|
||
import { Button } from '../../../../components/ui/button'
|
||
import {
|
||
Card,
|
||
CardContent,
|
||
CardDescription,
|
||
CardHeader,
|
||
CardTitle,
|
||
} from '../../../../components/ui/card'
|
||
import { useTemplateContext } from '../../../../contexts/TemplateContext'
|
||
import {
|
||
FormLayoutSettings,
|
||
Template,
|
||
TemplateElement,
|
||
} from '../../../../types/template'
|
||
|
||
export const ElementsCreation: FC = () => {
|
||
const navigate = useNavigate()
|
||
const { templates, updateTemplate } = useTemplateContext()
|
||
const [selectedTemplate, setSelectedTemplate] = useState<Template | null>(
|
||
null,
|
||
)
|
||
|
||
const handleTemplateSelect = (template: Template) => {
|
||
setSelectedTemplate(template)
|
||
}
|
||
|
||
const handleElementAdd = (element: TemplateElement) => {
|
||
console.log('handleElementAdd called with element:', element)
|
||
|
||
if (!selectedTemplate) {
|
||
console.log('No selected template')
|
||
return
|
||
}
|
||
|
||
const updatedTemplate = {
|
||
...selectedTemplate,
|
||
elements: [...selectedTemplate.elements, element],
|
||
updatedAt: new Date(),
|
||
}
|
||
|
||
console.log('Updated template:', updatedTemplate)
|
||
console.log('Elements count:', updatedTemplate.elements.length)
|
||
|
||
updateTemplate(updatedTemplate)
|
||
setSelectedTemplate(updatedTemplate)
|
||
}
|
||
|
||
const handleElementUpdate = (
|
||
elementId: string,
|
||
updates: Partial<TemplateElement>,
|
||
) => {
|
||
if (!selectedTemplate) return
|
||
|
||
const updatedTemplate = {
|
||
...selectedTemplate,
|
||
elements: selectedTemplate.elements.map((el) =>
|
||
el.id === elementId ? { ...el, ...updates } : el,
|
||
),
|
||
updatedAt: new Date(),
|
||
}
|
||
|
||
updateTemplate(updatedTemplate)
|
||
setSelectedTemplate(updatedTemplate)
|
||
}
|
||
|
||
const handleElementDelete = (elementId: string) => {
|
||
if (!selectedTemplate) return
|
||
|
||
const updatedTemplate = {
|
||
...selectedTemplate,
|
||
elements: selectedTemplate.elements.filter((el) => el.id !== elementId),
|
||
updatedAt: new Date(),
|
||
}
|
||
|
||
updateTemplate(updatedTemplate)
|
||
setSelectedTemplate(updatedTemplate)
|
||
}
|
||
|
||
const handleElementsReorder = (reorderedElements: TemplateElement[]) => {
|
||
if (!selectedTemplate) return
|
||
|
||
// Обновляем порядок элементов
|
||
const elementsWithOrder = reorderedElements.map((element, index) => ({
|
||
...element,
|
||
order: index,
|
||
}))
|
||
|
||
const updatedTemplate = {
|
||
...selectedTemplate,
|
||
elements: elementsWithOrder,
|
||
updatedAt: new Date(),
|
||
}
|
||
|
||
updateTemplate(updatedTemplate)
|
||
setSelectedTemplate(updatedTemplate)
|
||
}
|
||
|
||
const handleLayoutSettingsChange = (settings: FormLayoutSettings) => {
|
||
if (!selectedTemplate) return
|
||
|
||
const updatedTemplate = {
|
||
...selectedTemplate,
|
||
layoutSettings: settings,
|
||
updatedAt: new Date(),
|
||
}
|
||
|
||
updateTemplate(updatedTemplate)
|
||
setSelectedTemplate(updatedTemplate)
|
||
}
|
||
|
||
const handleBack = () => {
|
||
setSelectedTemplate(null)
|
||
}
|
||
|
||
// Настройки отображения по умолчанию
|
||
const defaultLayoutSettings: FormLayoutSettings = {
|
||
gridSize: 20,
|
||
showGrid: true,
|
||
}
|
||
|
||
if (selectedTemplate) {
|
||
return (
|
||
<div className="h-full">
|
||
<div className="sticky top-0 z-50 border-b border-gray-200 bg-white p-4">
|
||
<div className="flex items-center justify-between">
|
||
<div className="flex items-center gap-4">
|
||
<Button variant="ghost" onClick={handleBack}>
|
||
← Назад
|
||
</Button>
|
||
<div>
|
||
<h1 className="text-xl font-semibold text-gray-800">
|
||
Конструктор элементов: {selectedTemplate.name}
|
||
</h1>
|
||
<p className="mt-1 text-sm text-gray-600">
|
||
Создайте элементы формы и разместите их на холсте
|
||
перетаскиванием
|
||
</p>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div className="h-[calc(100vh-104px)]">
|
||
<ElementConstructor
|
||
elements={selectedTemplate.elements}
|
||
layoutSettings={
|
||
selectedTemplate.layoutSettings || defaultLayoutSettings
|
||
}
|
||
onElementAdd={handleElementAdd}
|
||
onElementUpdate={handleElementUpdate}
|
||
onElementDelete={handleElementDelete}
|
||
onElementsReorder={handleElementsReorder}
|
||
onLayoutSettingsChange={handleLayoutSettingsChange}
|
||
/>
|
||
</div>
|
||
</div>
|
||
)
|
||
}
|
||
|
||
return (
|
||
<div className="mx-auto max-w-7xl p-6">
|
||
<div className="mb-6 flex items-center justify-between">
|
||
<div>
|
||
<h1 className="text-3xl font-bold text-gray-900">
|
||
Создание элементов
|
||
</h1>
|
||
<p className="mt-2 text-gray-600">
|
||
Выберите шаблон для создания элементов интерфейса
|
||
</p>
|
||
</div>
|
||
|
||
<Button
|
||
variant="outline"
|
||
onClick={() => navigate('/templates')}
|
||
className="flex items-center gap-2"
|
||
>
|
||
<Plus className="h-4 w-4" />
|
||
Создать шаблон
|
||
</Button>
|
||
</div>
|
||
|
||
{templates.length === 0 ? (
|
||
<div className="py-12 text-center">
|
||
<Wrench className="mx-auto mb-4 h-16 w-16 text-gray-400" />
|
||
<h3 className="mb-2 text-lg font-medium text-gray-900">
|
||
Нет доступных шаблонов
|
||
</h3>
|
||
<p className="mb-6 text-gray-600">
|
||
Создайте шаблон протокола для начала работы с элементами
|
||
</p>
|
||
<Button onClick={() => navigate('/templates')}>
|
||
<Plus className="mr-2 h-4 w-4" />
|
||
Создать шаблон
|
||
</Button>
|
||
</div>
|
||
) : (
|
||
<div className="grid grid-cols-1 gap-6 md:grid-cols-2 lg:grid-cols-3">
|
||
{templates.map((template) => (
|
||
<Card
|
||
key={template.id}
|
||
className="cursor-pointer transition-shadow hover:shadow-lg"
|
||
>
|
||
<CardHeader>
|
||
<CardTitle className="text-lg">{template.name}</CardTitle>
|
||
{template.description && (
|
||
<CardDescription className="mt-1">
|
||
{template.description}
|
||
</CardDescription>
|
||
)}
|
||
</CardHeader>
|
||
<CardContent>
|
||
<div className="space-y-2 text-sm text-gray-600">
|
||
<div className="flex items-center gap-2">
|
||
<Wrench className="h-4 w-4" />
|
||
<span>{template.elements.length} элементов создано</span>
|
||
</div>
|
||
<div className="mt-2 text-xs text-gray-500">
|
||
Обновлен: {template.updatedAt.toLocaleDateString('ru-RU')}
|
||
</div>
|
||
</div>
|
||
<div className="mt-4">
|
||
<Button
|
||
className="w-full"
|
||
onClick={() => handleTemplateSelect(template)}
|
||
>
|
||
Создать элементы
|
||
</Button>
|
||
</div>
|
||
</CardContent>
|
||
</Card>
|
||
))}
|
||
</div>
|
||
)}
|
||
</div>
|
||
)
|
||
}
|