// MDM SORP — Enrichment Queue (the hero screen). // Keyboard-first: ↑/↓ navigate, A apply, E edit, R reject, D defer, → next. const { useState, useEffect, useMemo, useRef, useCallback: _useCallback } = React; function EnrichmentQueueScreen({ navigate }) { const { t, lang } = useI18n(); const toast = useToast(); const [filter, setFilter] = useState("all"); const [queue, setQueue] = useState(window.DATA.queue); const [activeId, setActiveId] = useState(queue[0]?.id); const [processed, setProcessed] = useState(34); const [editingField, setEditingField] = useState(null); const filtered = useMemo(() => { if (filter === "all") return queue; return queue.filter(q => q.kind === filter); }, [filter, queue]); const active = filtered.find(q => q.id === activeId) || filtered[0]; const goNext = _useCallback((removeCurrent = false) => { const cur = filtered.findIndex(q => q.id === activeId); if (removeCurrent) { setQueue(q => q.filter(x => x.id !== activeId)); setProcessed(p => p + 1); } const nextIdx = removeCurrent ? cur : cur + 1; const next = filtered[nextIdx + (removeCurrent ? 0 : 0)] || filtered[nextIdx + 1]; const remaining = (removeCurrent ? filtered.filter(x => x.id !== activeId) : filtered); setActiveId(remaining[Math.min(cur, remaining.length - 1)]?.id); }, [activeId, filtered]); const apply = () => { toast(`Применено: ${active?.party}`, { onUndo: () => setQueue(window.DATA.queue) }); goNext(true); }; const reject = () => { toast(`Отклонено: ${active?.party}`, { icon: "x", onUndo: () => setQueue(window.DATA.queue) }); goNext(true); }; const defer = () => { toast(`Отложено на 24ч`, { icon: "history" }); goNext(true); }; // Keyboard useEffect(() => { const h = (e) => { if (e.target.tagName === "INPUT" || e.target.tagName === "TEXTAREA") return; if (e.metaKey || e.ctrlKey) return; if (e.key === "a" || e.key === "A" || e.key === "ф" || e.key === "Ф") { e.preventDefault(); apply(); } else if (e.key === "r" || e.key === "R" || e.key === "к" || e.key === "К") { e.preventDefault(); reject(); } else if (e.key === "d" || e.key === "D" || e.key === "в" || e.key === "В") { e.preventDefault(); defer(); } else if (e.key === "e" || e.key === "E" || e.key === "у" || e.key === "У") { e.preventDefault(); setEditingField("inline"); } else if (e.key === "ArrowDown") { e.preventDefault(); const idx = filtered.findIndex(q => q.id === activeId); setActiveId(filtered[Math.min(filtered.length - 1, idx + 1)]?.id); } else if (e.key === "ArrowUp") { e.preventDefault(); const idx = filtered.findIndex(q => q.id === activeId); setActiveId(filtered[Math.max(0, idx - 1)]?.id); } else if (e.key === "ArrowRight"){ e.preventDefault(); goNext(false); } }; window.addEventListener("keydown", h); return () => window.removeEventListener("keydown", h); }, [activeId, filtered, apply, reject, defer, goNext]); const filters = [ { id: "all", label: t("queue_filter_all"), count: queue.length }, { id: "norm", label: t("queue_filter_norm"), count: queue.filter(q => q.kind === "norm").length }, { id: "dedup", label: t("queue_filter_dedup"), count: queue.filter(q => q.kind === "dedup").length }, { id: "ai", label: t("queue_filter_ai"), count: queue.filter(q => q.kind === "ai").length }, { id: "sourcing", label: t("queue_filter_sourcing"), count: queue.filter(q => q.kind === "sourcing").length }, ]; return (