diff --git a/src/features/flights-map/calendarRange.test.ts b/src/features/flights-map/calendarRange.test.ts
index 3c2e3fce..7f5f0649 100644
--- a/src/features/flights-map/calendarRange.test.ts
+++ b/src/features/flights-map/calendarRange.test.ts
@@ -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", () => {
diff --git a/src/features/flights-map/calendarRange.ts b/src/features/flights-map/calendarRange.ts
index 6af20423..fbe3a32b 100644
--- a/src/features/flights-map/calendarRange.ts
+++ b/src/features/flights-map/calendarRange.ts
@@ -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;
+}
diff --git a/src/features/flights-map/components/FlightsMapFilter.test.tsx b/src/features/flights-map/components/FlightsMapFilter.test.tsx
index 0fc955d3..70fd8448 100644
--- a/src/features/flights-map/components/FlightsMapFilter.test.tsx
+++ b/src/features/flights-map/components/FlightsMapFilter.test.tsx
@@ -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(
+ ,
+ );
+
+ 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(
diff --git a/src/features/flights-map/components/FlightsMapFilter.tsx b/src/features/flights-map/components/FlightsMapFilter.tsx
index 2e8de136..d535cd36 100644
--- a/src/features/flights-map/components/FlightsMapFilter.tsx
+++ b/src/features/flights-map/components/FlightsMapFilter.tsx
@@ -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 = ({
value,
availableDays,
+ today: todayYmd,
onChange,
}) => {
const { t } = useTranslation();
@@ -76,8 +78,8 @@ export const FlightsMapFilter: FC = ({
);
}, [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 ?? []),
diff --git a/src/features/flights-map/components/FlightsMapStartPage.tsx b/src/features/flights-map/components/FlightsMapStartPage.tsx
index 0c13e3cf..0d063571 100644
--- a/src/features/flights-map/components/FlightsMapStartPage.tsx
+++ b/src/features/flights-map/components/FlightsMapStartPage.tsx
@@ -393,6 +393,7 @@ export const FlightsMapStartPage: FC = ({
}