fix(sched): 날짜 기본 선택·가운데 정렬 전 리그 통일

- 기본 날짜: 오늘 → 경기 없으면 다음 경기일 → 시즌 종료면 마지막 날짜
  (기존엔 첫 날짜(가장 과거)로 떨어져 백필 후 3주 전이 기본 선택되던 문제)
- '오늘' 을 KST 로 계산 (기존 UTC — KST 오전 9시 전엔 어제로 잡힘)
- 선택 칩 가운데 정렬을 리그/탭 전환뿐 아니라 선택 변경·비동기 로드에도 적용
- 목록 비동기 로드 시에도 세션 저장 선택 복원 동작

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
jwkim 2026-08-14 15:04:17 +09:00
parent eecc9829b4
commit e2d1647100

View File

@ -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" && (
<ChipScroller resetKey={`${league}:${effTab}`}>
<ChipScroller
resetKey={`${league}:${effTab}`}
centerKey={
effTab === "date"
? selDate
: effTab === "team"
? selTeam
: effTab === "group"
? selGroup
: selRound
}
>
{effTab === "date"
? dates.map((d) => (
<Chip key={d} active={d === selDate} onClick={() => 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<HTMLDivElement>(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();