import { useEffect, useState } from 'react' import { createPortal } from 'react-dom' import { Plus, Trash2, X } from 'lucide-react' import { useLocale } from '@meshkee/dashboard-ui' import { useToast } from '../context/ToastContext' import { useT } from '../i18n/useT' import { ApiError } from '../lib/api' import { createRollCall, updateRollCall, type RollCall, type RollCallInput, } from '../services/rollCallService' import modalStyles from './VariationsModal.module.css' import styles from './RollCallFormModal.module.css' interface RollCallFormModalProps { open: boolean rollCall: RollCall | null onClose: () => void onSaved: (rollCall: RollCall) => void } const ANIMATION_MS = 220 function emptyTasks() { return [''] } export function RollCallFormModal({ open, rollCall, onClose, onSaved, }: RollCallFormModalProps) { const t = useT() const { locale, dir } = useLocale() const { showToast } = useToast() const [mounted, setMounted] = useState(open) const [closing, setClosing] = useState(false) const [workDate, setWorkDate] = useState('') const [startTime, setStartTime] = useState('09:00') const [endTime, setEndTime] = useState('17:00') const [tasks, setTasks] = useState(emptyTasks()) const [saving, setSaving] = useState(false) const [error, setError] = useState('') useEffect(() => { if (open) { setMounted(true) setClosing(false) setError('') if (rollCall) { setWorkDate(rollCall.workDate) setStartTime(rollCall.startTime) setEndTime(rollCall.endTime) setTasks( rollCall.tasks.length > 0 ? rollCall.tasks.map((task) => task.title) : emptyTasks(), ) } else { setWorkDate(new Date().toISOString().slice(0, 10)) setStartTime('09:00') setEndTime('17:00') setTasks(emptyTasks()) } } else if (mounted) { setClosing(true) const timer = setTimeout(() => { setMounted(false) setClosing(false) }, ANIMATION_MS) return () => clearTimeout(timer) } }, [open, mounted, rollCall]) useEffect(() => { if (!mounted || closing) return const prevOverflow = document.body.style.overflow document.body.style.overflow = 'hidden' const onKey = (e: KeyboardEvent) => { if (e.key === 'Escape') onClose() } document.addEventListener('keydown', onKey) return () => { document.body.style.overflow = prevOverflow document.removeEventListener('keydown', onKey) } }, [mounted, closing, onClose]) if (!mounted) return null const isEdit = Boolean(rollCall?.id) function updateTask(index: number, value: string) { setTasks((prev) => prev.map((task, i) => (i === index ? value : task))) } function addTask() { setTasks((prev) => [...prev, '']) } function removeTask(index: number) { setTasks((prev) => { if (prev.length <= 1) return [''] return prev.filter((_, i) => i !== index) }) } async function handleSubmit(e: React.FormEvent) { e.preventDefault() setError('') const cleanedTasks = tasks.map((task) => task.trim()).filter(Boolean) if (!workDate || !startTime || !endTime) { setError(t('rollCall.error.incomplete')) return } if (cleanedTasks.length === 0) { setError(t('rollCall.error.tasksRequired')) return } const input: RollCallInput = { workDate, startTime, endTime, tasks: cleanedTasks.map((title) => ({ title })), } setSaving(true) try { const result = rollCall ? await updateRollCall(rollCall.id, input) : await createRollCall(input) onSaved(result.rollCall) showToast( rollCall ? t('rollCall.toast.updated') : t('rollCall.toast.created'), 'success', ) onClose() } catch (err) { const message = err instanceof ApiError ? err.message : t('rollCall.error.save') setError(message) showToast(message, 'error') } finally { setSaving(false) } } return createPortal(
e.stopPropagation()} role="dialog" aria-modal="true" aria-labelledby="roll-call-form-title" lang={locale} dir={dir} >

{isEdit ? t('rollCall.modal.editTitle') : t('rollCall.modal.addTitle')}

{t('rollCall.modal.subtitle')}

{error && (
{error}
)}
setWorkDate(e.target.value)} required />
setStartTime(e.target.value)} required />
setEndTime(e.target.value)} required />
{t('rollCall.field.tasks')}
{tasks.map((task, index) => (
updateTask(index, e.target.value)} placeholder={t('rollCall.field.taskPlaceholder')} aria-label={t('rollCall.field.taskN', { n: index + 1 })} />
))}
, document.body, ) }