diff --git a/src/components/main/MainUtm.jsx b/src/components/main/MainUtm.jsx index 41788c4..efd29a5 100644 --- a/src/components/main/MainUtm.jsx +++ b/src/components/main/MainUtm.jsx @@ -27,9 +27,6 @@ const DETAIL = { date: "2025-06-10 14:30", }; -const PHASES = ["list", "detail", "confirm", "done"]; -const PHASE_DURATION = { list: 1800, detail: 2200, confirm: 1800, done: 2000 }; - function UtmSystemPanel({ phase, activeRow }) { return (
@@ -72,13 +69,8 @@ function UtmSystemPanel({ phase, activeRow }) { ))}
- {/* 상세: 아래로 펼쳐짐 */}
비행계획 상세
@@ -109,9 +101,7 @@ function UtmSystemPanel({ phase, activeRow }) {
상태 {phase === "done" ? "승인" : "대기"} @@ -142,7 +132,6 @@ function UtmSystemPanel({ phase, activeRow }) {
- {/* 컨펌: 패널 안에서 블러 오버레이 */} {phase === "confirm" && ( { - if (!inView) return; - let t; - const run = (current) => { - const next = PHASES[(PHASES.indexOf(current) + 1) % PHASES.length]; - t = setTimeout(() => { - setPhase(next); - run(next); - }, PHASE_DURATION[current]); - }; - t = setTimeout(() => run("list"), 1000); - return () => clearTimeout(t); - }, [inView]); - - // 커서 이동 로직 + // ← useEffect 딱 하나만! useEffect(() => { if (!inView) return; @@ -207,7 +182,13 @@ function MainUtm() { const cursor = cursorRef.current; if (!showcase || !cursor) return; - let timers = []; + let stopped = false; + const ids = []; + + function sid(id) { + ids.push(id); + return id; + } function getPos(selector) { const el = ref.current?.querySelector(selector); @@ -224,64 +205,68 @@ function MainUtm() { cursor.style.transform = `translate(${x}px, ${y}px)`; } - function click() { + function doClick() { cursor.classList.add("utm-cursor--click"); - setTimeout(() => cursor.classList.remove("utm-cursor--click"), 250); + sid(setTimeout(() => cursor.classList.remove("utm-cursor--click"), 250)); } - function after(ms, fn) { - const t = setTimeout(fn, ms); - timers.push(t); + function schedule(ms, fn) { + sid( + setTimeout(() => { + if (!stopped) fn(); + }, ms), + ); } - function loop() { - timers.forEach(clearTimeout); - timers = []; + function run() { + if (stopped) return; setPhase("list"); - after(1000, () => { + moveTo(180, 160); + + // 상세보기로 이동 + schedule(1000, () => { const p = getPos(".utm-panel__row--active .utm-panel__btn"); if (p) moveTo(p.x, p.y); }); - after(2000, () => { - click(); - after(200, () => setPhase("detail")); - }); + // 상세보기 클릭 → detail + schedule(2000, () => doClick()); + schedule(2200, () => setPhase("detail")); - after(3200, () => { + // 승인처리로 이동 + schedule(3200, () => { const p = getPos(".utm-panel__approve-btn"); if (p) moveTo(p.x, p.y); }); - after(4200, () => { - click(); - after(200, () => setPhase("confirm")); - }); + // 승인처리 클릭 → confirm + schedule(4200, () => doClick()); + schedule(4400, () => setPhase("confirm")); - after(5000, () => { + // 확인 버튼으로 이동 + schedule(5000, () => { const p = getPos(".utm-confirm__ok"); if (p) moveTo(p.x, p.y); }); - after(5800, () => { - click(); - after(200, () => setPhase("done")); - }); + // 확인 클릭 → done + schedule(5800, () => doClick()); + schedule(6000, () => setPhase("done")); - after(7500, () => loop()); + // 반복 + schedule(7500, () => run()); } - moveTo(180, 160); - after(500, () => loop()); + run(); return () => { - timers.forEach(clearTimeout); - timers = []; + stopped = true; + ids.forEach(clearTimeout); cursor.classList.remove("utm-cursor--click"); - setPhase("list"); // ← cleanup에서만 호출 }; }, [inView]); + return (
@@ -349,7 +334,6 @@ function MainUtm() { - {/* 커서 */}