Fix flights map calendar lower bound
This commit is contained in:
@@ -40,6 +40,25 @@ describe("getMinDate / getMaxDate", () => {
|
||||
const max = getMaxDate();
|
||||
expect(max.getTime()).toBe(expected.getTime());
|
||||
});
|
||||
|
||||
it("derives date-only bounds from the provided yyyyMMdd anchor", () => {
|
||||
const min = getMinDate("20260506");
|
||||
const max = getMaxDate("20260506");
|
||||
|
||||
expect(min.toISOString()).toBe(new Date(2026, 4, 5).toISOString());
|
||||
expect(max.toISOString()).toBe(new Date(2026, 10, 6).toISOString());
|
||||
expect(min.getHours()).toBe(0);
|
||||
expect(max.getHours()).toBe(0);
|
||||
});
|
||||
|
||||
it("falls back to the runtime clock when the provided anchor is invalid", () => {
|
||||
const min = getMinDate("20269999");
|
||||
const expected = addDays(new Date(), -1);
|
||||
|
||||
expect(min.getFullYear()).toBe(expected.getFullYear());
|
||||
expect(min.getMonth()).toBe(expected.getMonth());
|
||||
expect(min.getDate()).toBe(expected.getDate());
|
||||
});
|
||||
});
|
||||
|
||||
describe("buildDisabledDates", () => {
|
||||
|
||||
@@ -12,19 +12,33 @@
|
||||
import { mapWindowBounds } from "@/shared/dateWindow.js";
|
||||
|
||||
/** Today with time set to 00:00:00 local. */
|
||||
export function today(): Date {
|
||||
export function today(baseYyyymmdd?: string): Date {
|
||||
if (baseYyyymmdd) {
|
||||
const parsed = parseYyyymmdd(baseYyyymmdd);
|
||||
if (parsed) return parsed;
|
||||
}
|
||||
const d = new Date();
|
||||
d.setHours(0, 0, 0, 0);
|
||||
return d;
|
||||
}
|
||||
|
||||
/** minDate = today - 1 day (Angular parity). */
|
||||
export function getMinDate(): Date {
|
||||
export function getMinDate(baseYyyymmdd?: string): Date {
|
||||
if (baseYyyymmdd) {
|
||||
const d = today(baseYyyymmdd);
|
||||
d.setDate(d.getDate() - 1);
|
||||
return d;
|
||||
}
|
||||
return mapWindowBounds()[0];
|
||||
}
|
||||
|
||||
/** maxDate = today + 6 months (Angular parity). */
|
||||
export function getMaxDate(): Date {
|
||||
export function getMaxDate(baseYyyymmdd?: string): Date {
|
||||
if (baseYyyymmdd) {
|
||||
const d = today(baseYyyymmdd);
|
||||
d.setMonth(d.getMonth() + 6);
|
||||
return d;
|
||||
}
|
||||
return mapWindowBounds()[1];
|
||||
}
|
||||
|
||||
@@ -92,3 +106,20 @@ function toYyyymmdd(d: Date): string {
|
||||
const day = d.getDate().toString().padStart(2, "0");
|
||||
return `${y}${m}${day}`;
|
||||
}
|
||||
|
||||
function parseYyyymmdd(value: string): Date | null {
|
||||
if (!/^\d{8}$/.test(value)) return null;
|
||||
const y = Number(value.slice(0, 4));
|
||||
const m = Number(value.slice(4, 6));
|
||||
const d = Number(value.slice(6, 8));
|
||||
const parsed = new Date(y, m - 1, d);
|
||||
parsed.setHours(0, 0, 0, 0);
|
||||
if (
|
||||
parsed.getFullYear() !== y ||
|
||||
parsed.getMonth() !== m - 1 ||
|
||||
parsed.getDate() !== d
|
||||
) {
|
||||
return null;
|
||||
}
|
||||
return parsed;
|
||||
}
|
||||
|
||||
@@ -92,6 +92,25 @@ describe("FlightsMapFilter — Calendar wiring", () => {
|
||||
expect(max.getTime()).toBe(expectedMax.getTime());
|
||||
});
|
||||
|
||||
it("uses the provided SSR today anchor for date-only calendar bounds", () => {
|
||||
const onChange = vi.fn();
|
||||
render(
|
||||
<FlightsMapFilter
|
||||
value={filter()}
|
||||
today="20260506"
|
||||
onChange={onChange}
|
||||
/>,
|
||||
);
|
||||
|
||||
const min = lastCalendarProps!["minDate"] as Date;
|
||||
const max = lastCalendarProps!["maxDate"] as Date;
|
||||
|
||||
expect(min.toISOString()).toBe(new Date(2026, 4, 5).toISOString());
|
||||
expect(max.toISOString()).toBe(new Date(2026, 10, 6).toISOString());
|
||||
expect(min.getHours()).toBe(0);
|
||||
expect(min.getMinutes()).toBe(0);
|
||||
});
|
||||
|
||||
it("disables every date when availableDays is empty", () => {
|
||||
const onChange = vi.fn();
|
||||
render(
|
||||
|
||||
@@ -25,6 +25,7 @@ import type { IFlightsMapFilterState } from "../types.js";
|
||||
export interface FlightsMapFilterProps {
|
||||
value: IFlightsMapFilterState;
|
||||
availableDays?: string[];
|
||||
today?: string;
|
||||
onChange: (state: IFlightsMapFilterState) => void;
|
||||
}
|
||||
|
||||
@@ -50,6 +51,7 @@ function dateToYyyymmdd(value: Date): string {
|
||||
export const FlightsMapFilter: FC<FlightsMapFilterProps> = ({
|
||||
value,
|
||||
availableDays,
|
||||
today: todayYmd,
|
||||
onChange,
|
||||
}) => {
|
||||
const { t } = useTranslation();
|
||||
@@ -76,8 +78,8 @@ export const FlightsMapFilter: FC<FlightsMapFilterProps> = ({
|
||||
);
|
||||
}, [dictionaries, onChange, value]);
|
||||
|
||||
const minDate = useMemo(() => getMinDate(), []);
|
||||
const maxDate = useMemo(() => getMaxDate(), []);
|
||||
const minDate = useMemo(() => getMinDate(todayYmd), [todayYmd]);
|
||||
const maxDate = useMemo(() => getMaxDate(todayYmd), [todayYmd]);
|
||||
|
||||
const disabledDates = useMemo(
|
||||
() => buildDisabledDates(minDate, maxDate, availableDays ?? []),
|
||||
|
||||
@@ -393,6 +393,7 @@ export const FlightsMapStartPage: FC<FlightsMapStartPageProps> = ({
|
||||
<FlightsMapFilter
|
||||
value={filterState}
|
||||
availableDays={availableDays}
|
||||
today={todayYmd}
|
||||
onChange={handleFilterChange}
|
||||
/>
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user