refactor(planner): the weekday index of a plan day lives with the place opening state

This commit is contained in:
Maurice
2026-10-12 21:14:20 +00:00
parent 7b023c6b54
commit 8f6dab30a2
3 changed files with 22 additions and 9 deletions
@@ -39,7 +39,7 @@ import { navigationTargetLabel, getNavigationTargets, openNavigationTarget } fro
import { TRANSPORT_TYPES, getPlaceBookings } from '../../utils/dayMerge'
import { NavigationMenu } from '../shared/NavigationMenu'
import { centredMapCardBox } from '../Map/centredMapCard'
import { resolveOpenNow, resolvePlaceTimeZone, placeWeekdayIndex, type OpeningPeriod } from './placeOpenState'
import { resolveOpenNow, resolvePlaceTimeZone, getWeekdayIndex, type OpeningPeriod } from './placeOpenState'
import { convertHoursLine } from './placeHoursFormat'
import type { EndDayControlProps } from '../Roadtrip/EndDayControl'
import VisitControls, { type RoadtripStayControl } from '../Roadtrip/VisitControls'
@@ -136,13 +136,6 @@ function usePlaceDetails(googlePlaceId, osmId, language) {
return details
}
function getWeekdayIndex(dateStr, timeZone) {
// weekdayDescriptions[0] = Monday … [6] = Sunday
if (!dateStr) return placeWeekdayIndex(new Date(), timeZone)
const jsDay = new Date(dateStr + 'T12:00:00').getDay()
return jsDay === 0 ? 6 : jsDay - 1
}
function formatFileSize(bytes) {
if (!bytes) return ''
if (bytes < 1024) return `${bytes} B`
@@ -1,4 +1,4 @@
import { resolveOpenNow, resolvePlaceTimeZone, placeWeekdayIndex } from './placeOpenState';
import { getWeekdayIndex, resolveOpenNow, resolvePlaceTimeZone, placeWeekdayIndex } from './placeOpenState';
import type { OpeningPeriod } from './placeOpenState';
// Seoul is UTC+9, Paris UTC+2 in summer — far enough apart that a viewer's clock and
@@ -56,6 +56,18 @@ describe('placeWeekdayIndex', () => {
});
});
describe('getWeekdayIndex', () => {
it('FE-PLANNER-OPENSTATE-023: reads a plan day by its own date, Monday first', () => {
expect(getWeekdayIndex('2026-07-27', 'Asia/Seoul')).toBe(0);
expect(getWeekdayIndex('2026-08-02', null)).toBe(6);
});
it('FE-PLANNER-OPENSTATE-024: a day without a date reads today in the place timezone', () => {
expect(getWeekdayIndex(null, 'UTC')).toBe(placeWeekdayIndex(new Date(), 'UTC'));
expect(getWeekdayIndex(undefined, null)).toBe(placeWeekdayIndex(new Date(), null));
});
});
describe('resolveOpenNow', () => {
it('FE-PLANNER-OPENSTATE-010: judges the periods in the place timezone, not the viewer one', () => {
// Sunday 20:00 UTC → Monday 05:00 in Seoul. The server said closed.
@@ -51,6 +51,14 @@ export function placeWeekdayIndex(now: Date, timeZone: string | null): number {
return jsDay === 0 ? 6 : jsDay - 1
}
/** Monday-based weekday index of a plan day's date; for a day without one, today's in `timeZone`. */
export function getWeekdayIndex(dateStr: string | null | undefined, timeZone: string | null): number {
// weekdayDescriptions[0] = Monday … [6] = Sunday
if (!dateStr) return placeWeekdayIndex(new Date(), timeZone)
const jsDay = new Date(dateStr + 'T12:00:00').getDay()
return jsDay === 0 ? 6 : jsDay - 1
}
/** Weekday (Sunday = 0), minute of day and calendar date of `now` in `timeZone`. */
function localParts(now: Date, timeZone: string | null): { day: number; minutes: number; date: string } | null {
if (!timeZone) return null