import { useState, useEffect } from 'react' import { Plus, Trash2, ChevronUp, ChevronDown, Pencil, Check, X, Loader2, ListChecks, ToggleLeft, ToggleRight } from 'lucide-react' import { api, type ChecklistTemplate, type ChecklistItem } from '../lib/api' import { useAuth } from '../contexts/AuthContext' import { cn } from '../lib/utils' const TASK_TYPE_LABELS: Record = { checkout: 'После выезда', daily: 'Ежедневная', deep: 'Генеральная', } function InlineEdit({ value, onSave, onCancel }: { value: string onSave: (v: string) => void onCancel: () => void }) { const [v, setV] = useState(value) return (
setV(e.target.value)} onKeyDown={e => { if (e.key === 'Enter') onSave(v.trim()) if (e.key === 'Escape') onCancel() }} className="input flex-1 py-1 text-sm" />
) } export function ChecklistSettingsPage() { const { user } = useAuth() const slug = user?.hotelSlug ?? '' const [templates, setTemplates] = useState([]) const [loading, setLoading] = useState(true) const [error, setError] = useState(null) // New template form const [newName, setNewName] = useState('') const [newType, setNewType] = useState('') const [adding, setAdding] = useState(false) // Editing states const [editingTemplateId, setEditingTemplateId] = useState(null) const [editingItemId, setEditingItemId] = useState(null) const [newItemText, setNewItemText] = useState>({}) useEffect(() => { if (!slug) return api.checklists.listTemplates(slug) .then(t => setTemplates(t)) .catch(() => setError('Не удалось загрузить шаблоны')) .finally(() => setLoading(false)) }, [slug]) const addTemplate = async () => { if (!newName.trim()) return setAdding(true) try { const tpl = await api.checklists.createTemplate(slug, { name: newName.trim(), taskType: newType || undefined, }) setTemplates(prev => [...prev, tpl]) setNewName('') setNewType('') } catch { setError('Не удалось создать шаблон') } finally { setAdding(false) } } const updateTemplateName = async (id: string, name: string) => { try { const updated = await api.checklists.updateTemplate(slug, id, { name }) setTemplates(prev => prev.map(t => t.id === id ? { ...t, name: updated.name } : t)) } catch { /* ignore */ } setEditingTemplateId(null) } const toggleActive = async (t: ChecklistTemplate) => { try { const updated = await api.checklists.updateTemplate(slug, t.id, { isActive: !t.isActive }) setTemplates(prev => prev.map(x => x.id === t.id ? { ...x, isActive: updated.isActive } : x)) } catch { /* ignore */ } } const deleteTemplate = async (id: string) => { if (!confirm('Удалить шаблон вместе со всеми пунктами?')) return try { await api.checklists.deleteTemplate(slug, id) setTemplates(prev => prev.filter(t => t.id !== id)) } catch { /* ignore */ } } const addItem = async (templateId: string) => { const text = newItemText[templateId]?.trim() if (!text) return try { const item = await api.checklists.addItem(slug, templateId, { text }) setTemplates(prev => prev.map(t => t.id === templateId ? { ...t, items: [...t.items, item] } : t, )) setNewItemText(prev => ({ ...prev, [templateId]: '' })) } catch { /* ignore */ } } const updateItemText = async (templateId: string, item: ChecklistItem, text: string) => { try { const updated = await api.checklists.updateItem(slug, templateId, item.id, { text }) setTemplates(prev => prev.map(t => t.id === templateId ? { ...t, items: t.items.map(i => i.id === item.id ? { ...i, text: updated.text } : i) } : t, )) } catch { /* ignore */ } setEditingItemId(null) } const deleteItem = async (templateId: string, itemId: string) => { try { await api.checklists.deleteItem(slug, templateId, itemId) setTemplates(prev => prev.map(t => t.id === templateId ? { ...t, items: t.items.filter(i => i.id !== itemId) } : t, )) } catch { /* ignore */ } } const moveItem = async (templateId: string, itemId: string, dir: 'up' | 'down') => { const tpl = templates.find(t => t.id === templateId) if (!tpl) return const idx = tpl.items.findIndex(i => i.id === itemId) if (dir === 'up' && idx === 0) return if (dir === 'down' && idx === tpl.items.length - 1) return const newItems = [...tpl.items] const swapIdx = dir === 'up' ? idx - 1 : idx + 1 ;[newItems[idx], newItems[swapIdx]] = [newItems[swapIdx], newItems[idx]] // Update sort_order for both const a = newItems[idx] const b = newItems[swapIdx] const sortA = a.sortOrder const sortB = b.sortOrder setTemplates(prev => prev.map(t => t.id === templateId ? { ...t, items: newItems } : t)) try { await Promise.all([ api.checklists.updateItem(slug, templateId, a.id, { sortOrder: sortA }), api.checklists.updateItem(slug, templateId, b.id, { sortOrder: sortB }), ]) } catch { /* ignore */ } } if (loading) { return (
) } return (

Шаблоны чек-листов

Настройте пункты проверки для задач уборки. Шаблон применяется автоматически по типу задачи.

{error && (
{error}
)} {/* Add template form */}

Новый шаблон

setNewName(e.target.value)} placeholder="Название шаблона" className="input flex-1" onKeyDown={e => e.key === 'Enter' && addTemplate()} />
{/* Templates list */}
{templates.length === 0 && (
Нет шаблонов. Создайте первый шаблон чек-листа.
)} {templates.map(tpl => (
{/* Template header */}
{editingTemplateId === tpl.id ? ( updateTemplateName(tpl.id, name)} onCancel={() => setEditingTemplateId(null)} /> ) : ( <> {tpl.name} {tpl.taskType && ( {TASK_TYPE_LABELS[tpl.taskType] ?? tpl.taskType} )} {!tpl.taskType && ( Любой тип )} )}
{/* Items */}
{tpl.items.map((item, idx) => (
{idx + 1}. {editingItemId === item.id ? ( updateItemText(tpl.id, item, text)} onCancel={() => setEditingItemId(null)} /> ) : ( <> {item.text}
)}
))} {/* Add item */}
setNewItemText(prev => ({ ...prev, [tpl.id]: e.target.value }))} placeholder="Новый пункт..." className="input flex-1 py-1.5 text-sm" onKeyDown={e => e.key === 'Enter' && addItem(tpl.id)} />
))}
) }