diff --git a/src/component/BasicElements/SelectElement.tsx b/src/component/BasicElements/SelectElement.tsx index b728a61..e45c2cd 100644 --- a/src/component/BasicElements/SelectElement.tsx +++ b/src/component/BasicElements/SelectElement.tsx @@ -9,6 +9,7 @@ import { SelectValue, } from '@/component/ui/select' import { ElementDefinition } from '@/entitiy/element/model/interface' +import { useToast } from '@/lib/hooks/useToast' import { ElementOption } from '@/type/template' import { ChevronDown, Plus, Trash2 } from 'lucide-react' @@ -36,6 +37,8 @@ export const selectDefinition: ElementDefinition = { return cells.map(target => ({ target, value: value || '' })) }, Editor: ({ config, onChange }) => { + const { warning } = useToast() + const handleAddOption = () => { onChange({ ...config, @@ -48,6 +51,19 @@ export const selectDefinition: ElementDefinition = { field: 'value' | 'label', value: string ) => { + // Проверяем дублирование только для подписей (label) + if (field === 'label' && value.trim() !== '') { + const isDuplicate = config.options.some( + (option, i) => + i !== index && + option.label.trim().toLowerCase() === value.trim().toLowerCase() + ) + if (isDuplicate) { + warning(`Такая подпись уже существует: "${value.trim()}"`) + return + } + } + onChange({ ...config, options: config.options.map((option, i) => @@ -74,31 +90,59 @@ export const selectDefinition: ElementDefinition = {
- {config.options.map((option, index) => ( -
- - handleUpdateOption(index, 'value', e.target.value) - } - /> - - handleUpdateOption(index, 'label', e.target.value) - } - /> - -
- ))} + {config.options.map((option, index) => { + const isDuplicateLabel = config.options.some( + (otherOption, i) => + i !== index && + option.label.trim() !== '' && + otherOption.label.trim().toLowerCase() === + option.label.trim().toLowerCase() + ) + // Убираем проверку дублирования для значений + const isDuplicateValue = false + + return ( +
+
+ + handleUpdateOption(index, 'value', e.target.value) + } + className={isDuplicateValue ? 'border-red-500' : ''} + /> + {isDuplicateValue && ( +

+ Это значение уже используется +

+ )} +
+
+ + handleUpdateOption(index, 'label', e.target.value) + } + className={isDuplicateLabel ? 'border-red-500' : ''} + /> + {isDuplicateLabel && ( +

+ Такая подпись уже существует +

+ )} +
+ +
+ ) + })}
diff --git a/src/component/TemplateManager/ElementConstructor.tsx b/src/component/TemplateManager/ElementConstructor.tsx index db14f98..64df7ac 100644 --- a/src/component/TemplateManager/ElementConstructor.tsx +++ b/src/component/TemplateManager/ElementConstructor.tsx @@ -621,6 +621,7 @@ export const ElementConstructor: React.FC = ({ onLayoutSettingsChange={onLayoutSettingsChange || (() => {})} onElementEdit={handleEditElement} onElementAdd={handleElementCopy} + isDialogOpen={isAddDialogOpen || !!editingElement} /> diff --git a/src/component/TemplateManager/VisualLayoutEditor.tsx b/src/component/TemplateManager/VisualLayoutEditor.tsx index 9e21d8e..8088c03 100644 --- a/src/component/TemplateManager/VisualLayoutEditor.tsx +++ b/src/component/TemplateManager/VisualLayoutEditor.tsx @@ -25,19 +25,6 @@ const ELEMENT_MIN_SIZE: Record = { button_group: { width: 180, height: 80 }, } -interface VisualLayoutEditorProps { - elements: TemplateElement[] - layoutSettings: FormLayoutSettings - onElementUpdate: ( - elementId: string, - updates: Partial - ) => void - onElementDelete: (elementId: string) => void - onLayoutSettingsChange: (settings: FormLayoutSettings) => void - onElementEdit?: (element: TemplateElement) => void - onElementAdd?: (element: Omit) => void -} - interface DraggableElementProps { element: TemplateElement isSelected: boolean @@ -213,6 +200,20 @@ const DraggableElement: React.FC = React.memo( } ) +interface VisualLayoutEditorProps { + elements: TemplateElement[] + layoutSettings: FormLayoutSettings + onElementUpdate: ( + elementId: string, + updates: Partial + ) => void + onElementDelete: (elementId: string) => void + onLayoutSettingsChange: (settings: FormLayoutSettings) => void + onElementEdit?: (element: TemplateElement) => void + onElementAdd?: (element: Omit) => void + isDialogOpen?: boolean // Добавляем новый проп +} + export const VisualLayoutEditor: React.FC = ({ elements, layoutSettings, @@ -221,6 +222,7 @@ export const VisualLayoutEditor: React.FC = ({ onLayoutSettingsChange, onElementEdit, onElementAdd, + isDialogOpen = false, // Значение по умолчанию }) => { // console.log('VisualLayoutEditor render with elements:', elements) const [selectedElementId, setSelectedElementId] = useState( @@ -232,6 +234,11 @@ export const VisualLayoutEditor: React.FC = ({ // Обработчик клавиш для копирования/вставки useEffect(() => { + // Отключаем обработчики если открыт диалог + if (isDialogOpen) { + return + } + const handleKeyDown = (e: KeyboardEvent) => { if (e.ctrlKey || e.metaKey) { if (e.key === 'c' && selectedElementId) { @@ -248,6 +255,8 @@ export const VisualLayoutEditor: React.FC = ({ ...copiedElement.layout, x: (copiedElement.layout?.x || 0) + 20, y: (copiedElement.layout?.y || 0) + 20, + width: copiedElement.layout?.width || 300, + height: copiedElement.layout?.height || 80, }, } delete (newElement as any).id // Удаляем id чтобы создался новый @@ -258,7 +267,7 @@ export const VisualLayoutEditor: React.FC = ({ document.addEventListener('keydown', handleKeyDown) return () => document.removeEventListener('keydown', handleKeyDown) - }, [selectedElementId, elements, copiedElement, onElementAdd]) + }, [selectedElementId, elements, copiedElement, onElementAdd, isDialogOpen]) const canvasSize = useMemo(() => { const PADDING_Y = 200