Add 6 online board route pages
Start page, flight/departure/arrival/route search pages, and flight details page. Each route is thin: parses URL params, lazy-loads the feature component with Suspense.
This commit is contained in:
@@ -0,0 +1,37 @@
|
|||||||
|
/**
|
||||||
|
* Online Board flight details route.
|
||||||
|
*
|
||||||
|
* Parses flight ID from URL, renders detailed flight info.
|
||||||
|
* URL: /{lang}/onlineboard/{carrier}{flightNumber}-{yyyyMMdd}
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { lazy, Suspense } from "react";
|
||||||
|
import { useParams } from "@modern-js/runtime/router";
|
||||||
|
import { parseFlightUrlParams } from "@/features/online-board/url.js";
|
||||||
|
import { FlightListSkeleton } from "@/ui/flights/FlightListSkeleton.js";
|
||||||
|
|
||||||
|
const OnlineBoardDetailsPage = lazy(() =>
|
||||||
|
import("@/features/online-board/components/OnlineBoardDetailsPage.js").then(
|
||||||
|
(m) => ({ default: m.OnlineBoardDetailsPage }),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
export default function FlightDetailsPage(): JSX.Element {
|
||||||
|
const routeParams = useParams<{ params: string }>();
|
||||||
|
const raw = routeParams.params ?? "";
|
||||||
|
const parsed = parseFlightUrlParams(raw);
|
||||||
|
|
||||||
|
if (!parsed) {
|
||||||
|
return (
|
||||||
|
<div data-testid="invalid-params">
|
||||||
|
<p>Invalid flight parameters.</p>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Suspense fallback={<FlightListSkeleton count={1} />}>
|
||||||
|
<OnlineBoardDetailsPage flightId={parsed} />
|
||||||
|
</Suspense>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -0,0 +1,46 @@
|
|||||||
|
/**
|
||||||
|
* Online Board arrival search route.
|
||||||
|
*
|
||||||
|
* Parses station params from URL, renders shared search page.
|
||||||
|
* URL: /{lang}/onlineboard/arrival/{station}-{yyyyMMdd}[-{timeRange}]
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { lazy, Suspense } from "react";
|
||||||
|
import { useParams } from "@modern-js/runtime/router";
|
||||||
|
import { parseStationUrlParams } from "@/features/online-board/url.js";
|
||||||
|
import { FlightListSkeleton } from "@/ui/flights/FlightListSkeleton.js";
|
||||||
|
|
||||||
|
const OnlineBoardSearchPage = lazy(() =>
|
||||||
|
import("@/features/online-board/components/OnlineBoardSearchPage.js").then(
|
||||||
|
(m) => ({ default: m.OnlineBoardSearchPage }),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
export default function ArrivalSearchPage(): JSX.Element {
|
||||||
|
const routeParams = useParams<{ params: string }>();
|
||||||
|
const raw = routeParams.params ?? "";
|
||||||
|
const parsed = parseStationUrlParams(raw);
|
||||||
|
|
||||||
|
if (!parsed) {
|
||||||
|
return (
|
||||||
|
<div data-testid="invalid-params">
|
||||||
|
<p>Invalid arrival parameters.</p>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const searchParams = {
|
||||||
|
type: "arrival" as const,
|
||||||
|
station: parsed.station,
|
||||||
|
date: parsed.date,
|
||||||
|
...(parsed.timeFrom !== undefined && parsed.timeTo !== undefined
|
||||||
|
? { timeFrom: parsed.timeFrom, timeTo: parsed.timeTo }
|
||||||
|
: {}),
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Suspense fallback={<FlightListSkeleton />}>
|
||||||
|
<OnlineBoardSearchPage params={searchParams} />
|
||||||
|
</Suspense>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -0,0 +1,46 @@
|
|||||||
|
/**
|
||||||
|
* Online Board departure search route.
|
||||||
|
*
|
||||||
|
* Parses station params from URL, renders shared search page.
|
||||||
|
* URL: /{lang}/onlineboard/departure/{station}-{yyyyMMdd}[-{timeRange}]
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { lazy, Suspense } from "react";
|
||||||
|
import { useParams } from "@modern-js/runtime/router";
|
||||||
|
import { parseStationUrlParams } from "@/features/online-board/url.js";
|
||||||
|
import { FlightListSkeleton } from "@/ui/flights/FlightListSkeleton.js";
|
||||||
|
|
||||||
|
const OnlineBoardSearchPage = lazy(() =>
|
||||||
|
import("@/features/online-board/components/OnlineBoardSearchPage.js").then(
|
||||||
|
(m) => ({ default: m.OnlineBoardSearchPage }),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
export default function DepartureSearchPage(): JSX.Element {
|
||||||
|
const routeParams = useParams<{ params: string }>();
|
||||||
|
const raw = routeParams.params ?? "";
|
||||||
|
const parsed = parseStationUrlParams(raw);
|
||||||
|
|
||||||
|
if (!parsed) {
|
||||||
|
return (
|
||||||
|
<div data-testid="invalid-params">
|
||||||
|
<p>Invalid departure parameters.</p>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const searchParams = {
|
||||||
|
type: "departure" as const,
|
||||||
|
station: parsed.station,
|
||||||
|
date: parsed.date,
|
||||||
|
...(parsed.timeFrom !== undefined && parsed.timeTo !== undefined
|
||||||
|
? { timeFrom: parsed.timeFrom, timeTo: parsed.timeTo }
|
||||||
|
: {}),
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Suspense fallback={<FlightListSkeleton />}>
|
||||||
|
<OnlineBoardSearchPage params={searchParams} />
|
||||||
|
</Suspense>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -0,0 +1,45 @@
|
|||||||
|
/**
|
||||||
|
* Online Board flight number search route.
|
||||||
|
*
|
||||||
|
* Parses flight params from URL, renders shared search page.
|
||||||
|
* URL: /{lang}/onlineboard/flight/{carrier}{flightNumber}-{yyyyMMdd}
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { lazy, Suspense } from "react";
|
||||||
|
import { useParams } from "@modern-js/runtime/router";
|
||||||
|
import { parseFlightUrlParams } from "@/features/online-board/url.js";
|
||||||
|
import { FlightListSkeleton } from "@/ui/flights/FlightListSkeleton.js";
|
||||||
|
|
||||||
|
const OnlineBoardSearchPage = lazy(() =>
|
||||||
|
import("@/features/online-board/components/OnlineBoardSearchPage.js").then(
|
||||||
|
(m) => ({ default: m.OnlineBoardSearchPage }),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
export default function FlightSearchPage(): JSX.Element {
|
||||||
|
const routeParams = useParams<{ params: string }>();
|
||||||
|
const raw = routeParams.params ?? "";
|
||||||
|
const parsed = parseFlightUrlParams(raw);
|
||||||
|
|
||||||
|
if (!parsed) {
|
||||||
|
return (
|
||||||
|
<div data-testid="invalid-params">
|
||||||
|
<p>Invalid flight parameters.</p>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Suspense fallback={<FlightListSkeleton />}>
|
||||||
|
<OnlineBoardSearchPage
|
||||||
|
params={{
|
||||||
|
type: "flight",
|
||||||
|
carrier: parsed.carrier,
|
||||||
|
flightNumber: parsed.flightNumber,
|
||||||
|
suffix: parsed.suffix,
|
||||||
|
date: parsed.date,
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</Suspense>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -0,0 +1,22 @@
|
|||||||
|
/**
|
||||||
|
* Online Board start page route.
|
||||||
|
*
|
||||||
|
* Renders the search form landing page. No API calls on load.
|
||||||
|
* URL: /{lang}/onlineboard
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { lazy, Suspense } from "react";
|
||||||
|
|
||||||
|
const OnlineBoardStartPage = lazy(() =>
|
||||||
|
import("@/features/online-board/components/OnlineBoardStartPage.js").then(
|
||||||
|
(m) => ({ default: m.OnlineBoardStartPage }),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
export default function OnlineBoardPage(): JSX.Element {
|
||||||
|
return (
|
||||||
|
<Suspense fallback={<div aria-busy="true">Loading...</div>}>
|
||||||
|
<OnlineBoardStartPage />
|
||||||
|
</Suspense>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -0,0 +1,47 @@
|
|||||||
|
/**
|
||||||
|
* Online Board route search page.
|
||||||
|
*
|
||||||
|
* Parses departure + arrival + date from URL, renders shared search page.
|
||||||
|
* URL: /{lang}/onlineboard/route/{dep}-{arr}-{yyyyMMdd}[-{timeRange}]
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { lazy, Suspense } from "react";
|
||||||
|
import { useParams } from "@modern-js/runtime/router";
|
||||||
|
import { parseRouteUrlParams } from "@/features/online-board/url.js";
|
||||||
|
import { FlightListSkeleton } from "@/ui/flights/FlightListSkeleton.js";
|
||||||
|
|
||||||
|
const OnlineBoardSearchPage = lazy(() =>
|
||||||
|
import("@/features/online-board/components/OnlineBoardSearchPage.js").then(
|
||||||
|
(m) => ({ default: m.OnlineBoardSearchPage }),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
export default function RouteSearchPage(): JSX.Element {
|
||||||
|
const routeParams = useParams<{ params: string }>();
|
||||||
|
const raw = routeParams.params ?? "";
|
||||||
|
const parsed = parseRouteUrlParams(raw);
|
||||||
|
|
||||||
|
if (!parsed) {
|
||||||
|
return (
|
||||||
|
<div data-testid="invalid-params">
|
||||||
|
<p>Invalid route parameters.</p>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const searchParams = {
|
||||||
|
type: "route" as const,
|
||||||
|
departure: parsed.departure,
|
||||||
|
arrival: parsed.arrival,
|
||||||
|
date: parsed.date,
|
||||||
|
...(parsed.timeFrom !== undefined && parsed.timeTo !== undefined
|
||||||
|
? { timeFrom: parsed.timeFrom, timeTo: parsed.timeTo }
|
||||||
|
: {}),
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Suspense fallback={<FlightListSkeleton />}>
|
||||||
|
<OnlineBoardSearchPage params={searchParams} />
|
||||||
|
</Suspense>
|
||||||
|
);
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user