// Auto-rezerwacja — CRUD zadań const { useState: uSA, useEffect: uEA, useMemo: uMA } = React; function AutoTaskForm({ initial, words, onSave, onCancel, saving }) { const [form, setForm] = uSA(initial || { name: "", active: true, category: "A", exam_type: "praktyka", date_from: new Date().toISOString().slice(0, 10), date_to: new Date(Date.now() + 45 * 86400_000).toISOString().slice(0, 10), check_interval_s: 60, word_ids: [], }); const [voivFilter, setVoivFilter] = uSA(""); const voivs = uMA(() => ["", ...Array.from(new Set(words.map(w => w.voivodeship))).sort()], [words]); const wordList = uMA(() => voivFilter ? words.filter(w => w.voivodeship === voivFilter) : words , [words, voivFilter]); const toggle = (id) => { setForm(f => ({ ...f, word_ids: f.word_ids.includes(id) ? f.word_ids.filter(x => x !== id) : [...f.word_ids, id], })); }; const submit = (e) => { e.preventDefault(); onSave(form); }; return (
{initial?.id ? "Edytuj zadanie" : "Nowe zadanie auto-rezerwacji"}
WORDy ({form.word_ids.length} wybranych):
{wordList.length === 0 &&
Brak WORDów — odśwież listę w widoku „Sprawdź"
} {wordList.map(w => ( ))}
); } function AutoTasksView({ toast }) { const [tasks, setTasks] = uSA([]); const [words, setWords] = uSA([]); const [loading, setLoading] = uSA(true); const [editing, setEditing] = uSA(null); // null | "new" | task obj const [saving, setSaving] = uSA(false); const load = async () => { setLoading(true); try { const [t, w] = await Promise.all([ window.ZlapApi.listAutoTasks(), window.ZlapApi.listWords(), ]); setTasks(t); setWords(w); } catch (e) { toast(`Błąd: ${e.message}`, "err"); } finally { setLoading(false); } }; uEA(() => { load(); }, []); const save = async (form) => { setSaving(true); try { if (editing && editing.id) { await window.ZlapApi.updateAutoTask(editing.id, form); toast("Zaktualizowano zadanie", "ok"); } else { await window.ZlapApi.createAutoTask(form); toast("Utworzono zadanie", "ok"); } setEditing(null); await load(); } catch (e) { toast(`Błąd: ${e.message}`, "err"); } finally { setSaving(false); } }; const toggleActive = async (task) => { try { await window.ZlapApi.updateAutoTask(task.id, { active: !task.active }); await load(); } catch (e) { toast(`Błąd: ${e.message}`, "err"); } }; const del = async (task) => { if (!confirm(`Usunąć zadanie „${task.name}"?`)) return; try { await window.ZlapApi.deleteAutoTask(task.id); toast("Usunięto", "ok"); await load(); } catch (e) { toast(`Błąd: ${e.message}`, "err"); } }; const wordName = (id) => words.find(w => w.id === id)?.name || `#${id}`; return (
Auto-rezerwacja
Bot sprawdza wybrane WORDy co ustalony czas i rezerwuje przy znalezieniu pasującego slota.
{editing === null && ( )}
{editing !== null && ( setEditing(null)} saving={saving} /> )} {loading &&
Ładowanie…
} {!loading && tasks.length === 0 && editing === null && (
Brak zadań. Utwórz pierwsze klikając „Nowe zadanie".
)}
{tasks.map(t => (
{t.name} {t.active ? aktywne : wstrzymane}
kat. {t.category} · {t.exam_type} · {t.date_from} → {t.date_to} · co {t.check_interval_s}s
WORDy: {t.word_ids.map(wordName).join(", ")}
))}
); } window.AutoTasksView = AutoTasksView;