// new-task-modal.jsx — модальне вікно створення задачі вручну function NewTaskModal({ onClose, onCreate, preset, onSwitchToVisit }) { const objects = window.DATA.OBJECTS || []; const team = window.DATA.TEAM || []; const days = window.WEEK_DAYS || []; const catalog = (window.PM && window.PM.SECTION_CATALOG) || {}; const sectionOptions = ["ГІП", ...Object.keys(catalog), "ТД"]; const [form, setForm] = React.useState({ title: "", kind: (preset && preset.objId) ? "object" : "object", // "object" | "admin" objId: (preset && preset.objId) || "", section: "ГІП", assignees: [], day: (days.find(d => d.isToday) || days[0] || {}).day || (window.TODAY ? window.TODAY.day : ""), time: "", est: "", status: (preset && preset.status) || "todo", note: "", checklist: [], }); const [clInput, setClInput] = React.useState(""); const update = (k, v) => setForm(prev => ({ ...prev, [k]: v })); const setKind = (kind) => setForm(prev => ({ ...prev, kind, objId: kind === "admin" ? "" : prev.objId })); const toggleAssignee = (id) => setForm(prev => ({ ...prev, assignees: prev.assignees.includes(id) ? prev.assignees.filter(x => x !== id) : [...prev.assignees, id], })); const addClItem = () => { const v = clInput.trim(); if (!v) return; setForm(prev => ({ ...prev, checklist: [...prev.checklist, v] })); setClInput(""); }; const removeClItem = (i) => setForm(prev => ({ ...prev, checklist: prev.checklist.filter((_, idx) => idx !== i) })); React.useEffect(() => { const onKey = (e) => e.key === "Escape" && onClose(); window.addEventListener("keydown", onKey); return () => window.removeEventListener("keydown", onKey); }, [onClose]); const selObj = form.objId ? objects.find(o => o.id === form.objId) : null; const isObject = form.kind === "object"; const canSubmit = form.title.trim().length > 0 && (!isObject || !!form.objId); const submit = () => { if (!canSubmit) return; const task = { id: "t-" + Math.random().toString(36).slice(2, 8), title: form.title.trim(), obj: isObject ? (form.objId || null) : null, stage: isObject && selObj ? (selObj.activeStage || "project") : null, assignee: form.assignees[0] || null, assignees: form.assignees.length ? form.assignees : null, section: isObject ? (form.section || null) : "АДМ", day: form.day, status: form.status, subs: form.checklist.map(t => ({ t, done: false })), }; if (form.time.trim()) task.time = form.time.trim(); if (form.est.trim()) task.est = form.est.trim(); if (form.note.trim()) task.note = form.note.trim(); onCreate && onCreate(task); }; const statusOpts = [ { id: "todo", label: "Заплановано" }, { id: "live", label: "У роботі" }, ]; return ( <>
Нова задача
Створити задачу вручну
update("title", e.target.value)} onKeyDown={(e) => { if (e.key === "Enter" && canSubmit) submit(); }} placeholder={isObject ? "Напр.: Розрахунок плит перекриття, Узгодження з ДСНС" : "Напр.: Підготувати авансовий звіт, Замовити КЕП" } />
{isObject &&
} {isObject &&
}
{team.map(p => { const on = form.assignees.includes(p.id); return ( ); })}
Можна обрати кількох. Перший — відповідальний.
День у тижневому розкладі (не дедлайн)
update("time", e.target.value)} placeholder="напр.: 10:30 — 12:00" />
update("est", e.target.value)} placeholder="напр.: 2 год" />
{statusOpts.map(s => ( ))}
{form.checklist.length > 0 && (
{form.checklist.map((item, i) => (
{item}
))}
)}
setClInput(e.target.value)} onKeyDown={(e) => { if (e.key === "Enter") { e.preventDefault(); addClItem(); } }} placeholder="Додати пункт чек-листа…" />
Прості пункти-галочки. Enter — додати наступний. Підзадачі з виконавцями додаються у картці задачі.