From e2d1647100ebf9864face87cf09418d006bc7ff4 Mon Sep 17 00:00:00 2001 From: jwkim Date: Fri, 14 Aug 2026 15:04:17 +0900 Subject: [PATCH] =?UTF-8?q?fix(sched):=20=EB=82=A0=EC=A7=9C=20=EA=B8=B0?= =?UTF-8?q?=EB=B3=B8=20=EC=84=A0=ED=83=9D=C2=B7=EA=B0=80=EC=9A=B4=EB=8D=B0?= =?UTF-8?q?=20=EC=A0=95=EB=A0=AC=20=EC=A0=84=20=EB=A6=AC=EA=B7=B8=20?= =?UTF-8?q?=ED=86=B5=EC=9D=BC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 기본 날짜: 오늘 → 경기 없으면 다음 경기일 → 시즌 종료면 마지막 날짜 (기존엔 첫 날짜(가장 과거)로 떨어져 백필 후 3주 전이 기본 선택되던 문제) - '오늘' 을 KST 로 계산 (기존 UTC — KST 오전 9시 전엔 어제로 잡힘) - 선택 칩 가운데 정렬을 리그/탭 전환뿐 아니라 선택 변경·비동기 로드에도 적용 - 목록 비동기 로드 시에도 세션 저장 선택 복원 동작 Co-Authored-By: Claude Opus 5 --- frontend/src/components/ScheduleBoard.tsx | 37 ++++++++++++++++++----- 1 file changed, 30 insertions(+), 7 deletions(-) diff --git a/frontend/src/components/ScheduleBoard.tsx b/frontend/src/components/ScheduleBoard.tsx index e002d56..627a53c 100644 --- a/frontend/src/components/ScheduleBoard.tsx +++ b/frontend/src/components/ScheduleBoard.tsx @@ -99,13 +99,19 @@ export default function ScheduleBoard({ ); }, [matches, isBaseball, lang]); - // 기본 선택: 오늘(없으면 첫 날짜) / A조 / 현재 진행 라운드. + // 기본 선택: 오늘(경기 없으면 다음 경기일, 시즌 종료면 마지막 날짜) / A조 / 현재 진행 라운드. // 단, 직전 세션 선택을 sessionStorage 에 보관 → 상세 진입 후 뒤로가기 시 그대로 복원(오늘로 초기화 X). - const todayKey = useMemo(() => new Date().toISOString().slice(0, 10), []); + // 사이트 전체가 KST 기준이라 "오늘"도 클라이언트 시간대와 무관하게 KST 로 계산. + const todayKey = useMemo( + () => new Date(Date.now() + 9 * 3600_000).toISOString().slice(0, 10), + [], + ); + const defaultDate = (ds: string[], today: string) => + (ds.includes(today) ? today : ds.find((d) => d > today) ?? ds[ds.length - 1]) ?? ""; const [selDate, setSelDate] = useState(() => { const saved = sessionStorage.getItem("tp.sched.date"); if (saved && dates.includes(saved)) return saved; - return (dates.includes(todayKey) ? todayKey : dates[0]) ?? ""; + return defaultDate(dates, todayKey); }); const [selGroup, setSelGroup] = useState(() => { const saved = sessionStorage.getItem("tp.sched.group"); @@ -140,7 +146,11 @@ export default function ScheduleBoard({ useEffect(() => { if (dates.length && !dates.includes(selDate)) { - setSelDate(dates.includes(todayKey) ? todayKey : dates[0]); + // 목록이 비동기 로드될 때도 세션 복원이 동작하게 saved 를 우선 확인 + const saved = sessionStorage.getItem("tp.sched.date"); + setSelDate( + saved && dates.includes(saved) ? saved : defaultDate(dates, todayKey), + ); } }, [dates, selDate, todayKey]); // 리그 전환 시 목록에 없는 팀이면 첫 팀으로 @@ -216,7 +226,18 @@ export default function ScheduleBoard({ {/* 칩: 날짜 / 조 / 라운드 — 단일 줄 가로 스크롤 + 양 끝 화살표(PC에서 마우스로 넘김, 끝 도달 시 숨김) */} {effTab !== "rank" && ( - + {effTab === "date" ? dates.map((d) => ( setSelDate(d)}> @@ -274,9 +295,11 @@ export default function ScheduleBoard({ function ChipScroller({ children, resetKey, + centerKey, }: { children: React.ReactNode; resetKey?: string | number; + centerKey?: string; // 현재 선택값 — 바뀔 때마다 선택 칩을 가운데로 (비동기 로드·칩 클릭 포함) }) { const ref = useRef(null); const [atStart, setAtStart] = useState(true); @@ -290,7 +313,7 @@ function ChipScroller({ setAtEnd(el.scrollLeft >= max - 1); }; - // 탭/목록 변경 시: 선택된 칩을 가운데로 + 재측정 (레이아웃 확정 후) + // 탭/목록/선택 변경 시: 선택된 칩을 가운데로 + 재측정 (레이아웃 확정 후) // 선택 칩이 없으면 맨 앞으로 되감는다. useLayoutEffect(() => { const el = ref.current; @@ -301,7 +324,7 @@ function ChipScroller({ : 0; } measure(); - }, [resetKey]); + }, [resetKey, centerKey]); useEffect(() => { measure();