// Interactive weekly schedule builder mock — the product visual const { useState: useStateS, useEffect: useEffectS, useRef: useRefS, useCallback } = React; const SHIFTS = { M: { code: "M", label: "Manhã", time: "06–14h", cls: "sh--m" }, T: { code: "T", label: "Tarde", time: "14–22h", cls: "sh--t" }, N: { code: "N", label: "Noite", time: "22–06h", cls: "sh--n" }, F: { code: "F", label: "Folga", time: "—", cls: "sh--f" }, }; const CYCLE = ["M", "T", "N", "F"]; const TEAM = [ { name: "Ana Souza", role: "Atendimento", init: "AS", tone: 0 }, { name: "Bruno Lima", role: "Caixa", init: "BL", tone: 1 }, { name: "Carla Dias", role: "Estoque", init: "CD", tone: 2 }, { name: "Diego Reis", role: "Atendimento", init: "DR", tone: 3 }, { name: "Elena Castro", role: "Supervisão", init: "EC", tone: 4 }, { name: "Felipe Nunes", role: "Caixa", init: "FN", tone: 5 }, ]; const DAYS = [ { d: "Seg", n: "12" }, { d: "Ter", n: "13" }, { d: "Qua", n: "14" }, { d: "Qui", n: "15" }, { d: "Sex", n: "16" }, { d: "Sáb", n: "17" }, { d: "Dom", n: "18" }, ]; // Target generated schedule (rows x 7 days) const TARGET = [ ["M", "M", "T", "F", "M", "T", "F"], ["T", "F", "M", "M", "T", "F", "N"], ["F", "T", "T", "N", "F", "M", "M"], ["N", "N", "F", "T", "M", "M", "T"], ["M", "T", "M", "F", "T", "N", "F"], ["F", "M", "N", "T", "N", "F", "T"], ]; function emptyGrid() { return TEAM.map(() => DAYS.map(() => null)); } function ScheduleApp({ compact = false }) { const [grid, setGrid] = useStateS(emptyGrid); const [generating, setGenerating] = useStateS(false); const [done, setDone] = useStateS(false); const rootRef = useRefS(null); const ranRef = useRefS(false); const timers = useRefS([]); const clearTimers = () => { timers.current.forEach(clearTimeout); timers.current = []; }; const generate = useCallback(() => { clearTimers(); setDone(false); setGenerating(true); setGrid(emptyGrid()); const order = []; for (let c = 0; c < DAYS.length; c++) for (let r = 0; r < TEAM.length; r++) order.push([r, c]); order.forEach(([r, c], i) => { const t = setTimeout(() => { setGrid((g) => { const ng = g.map((row) => row.slice()); ng[r][c] = TARGET[r][c]; return ng; }); if (i === order.length - 1) { setGenerating(false); setDone(true); } }, 90 + i * 28); timers.current.push(t); }); }, []); // auto-run when scrolled into view (once), with fallbacks for unreliable observers useEffectS(() => { const el = rootRef.current; if (!el) return; const run = () => { if (!ranRef.current) { ranRef.current = true; generate(); return true; } return false; }; const inView = () => { const r = el.getBoundingClientRect(); const vh = window.innerHeight || document.documentElement.clientHeight; return r.top < vh * 0.85 && r.bottom > 0; }; if (inView()) { run(); return () => clearTimers(); } let io; if ("IntersectionObserver" in window) { io = new IntersectionObserver((entries) => { entries.forEach((e) => { if (e.isIntersecting) run(); }); }, { threshold: 0.3 }); io.observe(el); } const onScroll = () => { if (inView()) { run(); window.removeEventListener("scroll", onScroll); } }; window.addEventListener("scroll", onScroll, { passive: true }); const t = setTimeout(run, 1800); return () => { if (io) io.disconnect(); window.removeEventListener("scroll", onScroll); clearTimeout(t); clearTimers(); }; }, [generate]); const cycleCell = (r, c) => { if (generating) return; setGrid((g) => { const ng = g.map((row) => row.slice()); const cur = ng[r][c]; const idx = cur ? CYCLE.indexOf(cur) : -1; ng[r][c] = CYCLE[(idx + 1) % CYCLE.length]; return ng; }); }; // coverage = people working (not folga / not empty) per day const coverage = DAYS.map((_, c) => grid.reduce((s, row) => s + (row[c] && row[c] !== "F" ? 1 : 0), 0)); return (