Skip to content

Commit

Permalink
add query params to flight detail page
Browse files Browse the repository at this point in the history
  • Loading branch information
its-felix committed Oct 6, 2024
1 parent 7ba0deb commit 7c6c586
Show file tree
Hide file tree
Showing 4 changed files with 66 additions and 24 deletions.
10 changes: 8 additions & 2 deletions ui/src/components/common/flight-link.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,14 @@ import { RouterLink, RouterLinkProps } from './router-link';

export interface FlightLinkProps extends Omit<RouterLinkProps, 'to'> {
flightNumber: string;
query?: URLSearchParams;
}

export function FlightLink({ flightNumber, ...props }: FlightLinkProps) {
return <RouterLink {...props} to={`/flight/${encodeURIComponent(flightNumber)}`}>{props.children ?? flightNumber}</RouterLink>;
export function FlightLink({ flightNumber, query, ...props }: FlightLinkProps) {
let suffix = '';
if (query) {
suffix = '?' + query.toString();
}

return <RouterLink {...props} to={`/flight/${encodeURIComponent(flightNumber)}${suffix}`}>{props.children ?? flightNumber}</RouterLink>;
}
4 changes: 4 additions & 0 deletions ui/src/lib/api/api.model.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,10 @@ export function isJsonObject(v: JsonType): v is JsonObject {
return v !== null && typeof v === 'object' && !Array.isArray(v);
}

export function isJsonArray(v: JsonType): v is JsonArray {
return v !== null && typeof v === 'object' && Array.isArray(v);
}

export interface ApiErrorBody {
message: string;
}
Expand Down
48 changes: 44 additions & 4 deletions ui/src/pages/flight.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import React, { useCallback, useMemo, useState } from 'react';
import { useParams } from 'react-router-dom';
import { useParams, useSearchParams } from 'react-router-dom';
import {
Alert, Badge, Box, Calendar,
ColumnLayout, Container,
Expand Down Expand Up @@ -101,10 +101,11 @@ interface ProcessedFlightSchedule {
}

function FlightScheduleContent({ flightSchedule }: { flightSchedule: FlightSchedule }) {
const [searchParams] = useSearchParams();
const airportLookup = useAirportLookup();
const aircraftLookup = useAircraftLookup();

const [filterQuery, setFilterQuery] = useState<PropertyFilterProps.Query>({
const [filterQuery, setFilterQuery] = useState<PropertyFilterProps.Query>(parseSearchParams(searchParams) ?? {
operation: 'and',
tokens: [
{
Expand All @@ -130,6 +131,13 @@ function FlightScheduleContent({ flightSchedule }: { flightSchedule: FlightSched
pagination: { pageSize: 25 },
});

function queryForScheduledFlight(flight: ScheduledFlight) {
let query = new URLSearchParams();
query = withDepartureAirportFilter(query, flight.departureAirport.raw);
query = withDepartureDateFilter(query, flight.departureTime);
return query;
}

return (
<ColumnLayout columns={1}>
<Container>
Expand Down Expand Up @@ -237,7 +245,7 @@ function FlightScheduleContent({ flightSchedule }: { flightSchedule: FlightSched
header: 'Operated As',
cell: (v) => {
if (v.operatedAs !== flightNumber) {
return <FlightLink flightNumber={v.operatedAs} />;
return <FlightLink flightNumber={v.operatedAs} query={queryForScheduledFlight(v)} />;
}

return v.operatedAs;
Expand Down Expand Up @@ -281,7 +289,7 @@ function FlightScheduleContent({ flightSchedule }: { flightSchedule: FlightSched
header: 'Codeshares',
cell: (v) => (
<ColumnLayout columns={v.codeShares.length} variant={'text-grid'}>
{...v.codeShares.toSorted().map((v) => <FlightLink flightNumber={v} />)}
{...v.codeShares.toSorted().map((fn) => <FlightLink flightNumber={fn} query={queryForScheduledFlight(v)} />)}
</ColumnLayout>
),
}
Expand Down Expand Up @@ -674,4 +682,36 @@ function evaluateToken(flight: ScheduledFlight, token: PropertyFilterProps.Token
}

return false;
}

function parseSearchParams(v: URLSearchParams): PropertyFilterProps.Query | null {
const tokens: Array<PropertyFilterProps.Token> = [];
for (const prop of ['departure_time', 'aircraft', 'departure_airport', 'arrival_airport', 'operating_day']) {
for (const value of v.getAll(prop)) {
tokens.push({
propertyKey: prop,
value: value,
operator: '=',
});
}
}

if (tokens.length < 1) {
return null;
}

return {
operation: 'and',
tokens: tokens,
} satisfies PropertyFilterProps.Query;
}

export function withDepartureDateFilter(q: URLSearchParams, date: DateTime<true>): URLSearchParams {
q.append('departure_time', date.toISODate());
return q;
}

export function withDepartureAirportFilter(q: URLSearchParams, airport: string): URLSearchParams {
q.append('departure_airport', airport);
return q;
}
28 changes: 10 additions & 18 deletions ui/src/pages/tools/mm-quick-search.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,16 +20,16 @@ import {
Form,
FormField,
Grid,
Header, Link, Popover, Table
Header, Link, Table
} from '@cloudscape-design/components';
import { AirportMultiselect } from '../../components/select/airport-multiselect';
import { DateTime, Duration } from 'luxon';
import { catchNotify, useAppControls } from '../../components/util/context/app-controls';
import { useCollection } from '@cloudscape-design/collection-hooks';
import { useInterval } from '../../components/util/state/common';
import { useAirports, useFlight } from '../../components/util/state/data';
import { CodeView } from '@cloudscape-design/code-view';
import jsonHighlight from '@cloudscape-design/code-view/highlight/json';
import { useAirports } from '../../components/util/state/data';
import { FlightLink } from '../../components/common/flight-link';
import { withDepartureAirportFilter, withDepartureDateFilter } from '../flight';

export function MmQuickSearch() {
const { httpClient } = useHttpClient();
Expand Down Expand Up @@ -280,21 +280,13 @@ function AvailabilityTable({ items: rawItems, onClear }: { items: ReadonlyArray<
}

function FlightNumber({ flightNumber, departure }: { flightNumber: string, departure: ArrivalDeparture }) {
const date = DateTime.fromISO(departure.dateTime, { setZone: true });
if (!date.isValid) {
return flightNumber;
}
let query = new URLSearchParams();
query = withDepartureAirportFilter(query, departure.locationCode);

const flight = useFlight(flightNumber, departure.locationCode, date);
if (!flight.data) {
return flightNumber;
const date = DateTime.fromISO(departure.dateTime, { setZone: true });
if (date.isValid) {
query = withDepartureDateFilter(query, date);
}

return (
<Popover
size={'large'}
header={'Details'}
content={<CodeView content={JSON.stringify(flight.data, null, 2)} highlight={jsonHighlight} />}
>{flightNumber}</Popover>
);
return <FlightLink flightNumber={flightNumber} query={query} />;
}

0 comments on commit 7c6c586

Please sign in to comment.