Skip to content

Commit

Permalink
feat: extend line filtering to support nfk (#261)
Browse files Browse the repository at this point in the history
* Addeing query and endpoint to search after all lines whithin an given organization.

* Adding useSWR to line-filter to only fetch lines from organization when needed. Also updated endpoint to map correctly between public code and number of lines.

* Update troms.json and add lines() to assistant.test.tsx.

* Remove exessive string around param.

* Add cache to lines().

* Rewrite endpoint to return one object. Also, rewrite to using Map instead of Record

* Fix logic to enable filtering on multiple line numbers.

* Remove dependencies from dependencies array to avoid bug.

* Rewrite back to using record insted of map. Also remove cache.

* Move mapFilterStateToLineCodes() out of useEffect().

* Add cache-first cache policy to endpoint and update transaltions.

* Add whitespace between line codes at refresh of page.
  • Loading branch information
jonasbrunvoll authored Mar 22, 2024
1 parent be394b2 commit 4bd12d0
Show file tree
Hide file tree
Showing 15 changed files with 134 additions and 26 deletions.
2 changes: 1 addition & 1 deletion orgs/atb.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"$schema": "./schema-validation.json",
"orgId": "atb",
"orgLineIdPrefix": "ATB:Line:2_",
"authorityId": "ATB:Authority:2",

"supportEmail": "kundeservice@atb.no",

Expand Down
2 changes: 1 addition & 1 deletion orgs/fram.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"$schema": "./schema-validation.json",

"orgId": "fram",
"orgLineIdPrefix": "MOR:Line:",
"authorityId": "MOR:Authority:MOR",

"supportEmail": "fram@mrfylke.no",

Expand Down
2 changes: 1 addition & 1 deletion orgs/nfk.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"$schema": "./schema-validation.json",
"orgId": "nfk",
"orgLineIdPrefix": "NOR:Line:12_",
"authorityId": "NOR:Authority:12",

"supportEmail": "sentrumsterminalen@boreal.no",

Expand Down
2 changes: 1 addition & 1 deletion orgs/schema-validation.json
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@
"enum": ["atb", "fram", "nfk", "troms"],
"type": "string"
},
"orgLineIdPrefix": {
"authorityId": {
"type": "string"
},
"$schema": {
Expand Down
2 changes: 1 addition & 1 deletion orgs/troms.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"$schema": "./schema-validation.json",
"orgId": "troms",
"orgLineIdPrefix": "TRO:Line:1_",
"authorityId": "TRO:Authority:1",

"supportEmail": "",

Expand Down
2 changes: 1 addition & 1 deletion src/modules/org-data/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ export type TranslatableUrl = { default: string } & Partial<{
}>;
export type OrgData = {
orgId: WEBSHOP_ORGS;
orgLineIdPrefix: string;
authorityId: string;
supportEmail: string;

fylkeskommune?: {
Expand Down
6 changes: 6 additions & 0 deletions src/page-modules/assistant/__tests__/assistant.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,9 @@ describe('assistant page', function () {
async singleTrip() {
return {} as any;
},
async lines() {
return {} as any;
},
client: null as any,
};

Expand Down Expand Up @@ -312,6 +315,9 @@ describe('assistant page', function () {
async singleTrip() {
return {} as any;
},
async lines() {
return {} as any;
},
client: null as any,
};

Expand Down
2 changes: 2 additions & 0 deletions src/page-modules/assistant/client/journey-planner/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,14 @@ import useSWRInfinite from 'swr/infinite';
import { createTripQuery, tripQueryToQueryString } from '../../utils';
import { useEffect, useState } from 'react';
import { formatLocalTimeToCET } from '@atb/utils/date';
import { LineData } from '../../server/journey-planner/validators';

const MAX_NUMBER_OF_INITIAL_SEARCH_ATTEMPTS = 3;
const INITIAL_NUMBER_OF_WANTED_TRIP_PATTERNS = 6;

export type TripApiReturnType = TripData;
export type NonTransitTripApiReturnType = NonTransitTripData;
export type LinesApiReturnType = LineData;

function createKeyGetterOfQuery(query: TripQuery) {
return (pageIndex: number, previousPageData: TripApiReturnType) => {
Expand Down
60 changes: 43 additions & 17 deletions src/page-modules/assistant/line-filter/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,10 @@ import LabeledInput, { LabeledInputProps } from '@atb/components/labled-input';
import { Typo } from '@atb/components/typography';
import { getOrgData } from '@atb/modules/org-data';
import { PageText, useTranslation } from '@atb/translations';
import { ChangeEvent, useState } from 'react';
import { ChangeEvent, useEffect, useState } from 'react';
import style from './line-filter.module.css';
import useSWR from 'swr';
import { swrFetcher } from '@atb/modules/api-browser';
type LineFilterProps = {
filterState: string[] | null;
onChange: (lineFilter: string[] | null) => void;
Expand All @@ -12,34 +14,58 @@ type LineFilterProps = {
export default function LineFilter({ filterState, onChange }: LineFilterProps) {
const { t } = useTranslation();

const { orgLineIdPrefix } = getOrgData();
const [error, setError] = useState<LabeledInputProps['validationError']>();
const [localFilterState, setLocalFilterState] = useState(
filterState?.map((line) => line.replace(orgLineIdPrefix, '')).join(', ') ??
'',
const { authorityId } = getOrgData();

const { data, error, isLoading } = useSWR(
`api/assistant/lines/${authorityId}`,
swrFetcher,
);
const [validationError, setValidationError] =
useState<LabeledInputProps['validationError']>();
const [localFilterState, setLocalFilterState] = useState('');
const [publicCodeLineMap, setPublicCodeLineMap] =
useState<Map<string, string[]>>();

const onChangeWrapper = (event: ChangeEvent<HTMLInputElement>) => {
const lineFilter = event.target.value;
setLocalFilterState(lineFilter);
setError(undefined);
const input = event.target.value;
setLocalFilterState(input);
setValidationError(undefined);

if (!isValidFilter(lineFilter)) {
setError(t(PageText.Assistant.search.lineFilter.error));
if (!isValidFilter(input)) {
setValidationError(t(PageText.Assistant.search.lineFilter.error));
return;
}

if (!lineFilter) {
if (!input) {
onChange(null);
} else {
const linesWithPrefix = lineFilter
const lines = input
.split(',')
.map((line) => `${orgLineIdPrefix}${line.trim()}`);

onChange(linesWithPrefix);
.flatMap((line) => data[line.trim()])
.filter(Boolean);
onChange(lines);
}
};

const mapFilterStateToLineCodes = () => {
if (!data || !filterState) return '';
return filterState
.map((line) => {
for (let id in data) {
if (data[id].includes(line)) {
return id;
}
}
return null;
})
.filter(Boolean)
.join(', ');
};

useEffect(() => {
setLocalFilterState(mapFilterStateToLineCodes());
}, [data]); // eslint-disable-line react-hooks/exhaustive-deps

return (
<div className={style.container}>
<Typo.h3 textType="body__primary--bold" className={style.heading}>
Expand All @@ -55,7 +81,7 @@ export default function LineFilter({ filterState, onChange }: LineFilterProps) {
pattern="[0-9, ]*"
value={localFilterState}
onChange={onChangeWrapper}
validationError={error}
validationError={validationError}
/>

<Typo.p textType="body__tertiary" className={style.infoText}>
Expand Down
35 changes: 35 additions & 0 deletions src/page-modules/assistant/server/journey-planner/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import {
TripsQueryVariables,
} from './journey-gql/trip.generated';
import {
LineData,
TripData,
TripPatternWithDetails,
nonTransitSchema,
Expand All @@ -21,6 +22,7 @@ import {
} from './validators';
import type {
FromToTripQuery,
LineInput,
NonTransitData,
NonTransitTripData,
NonTransitTripInput,
Expand Down Expand Up @@ -59,6 +61,12 @@ import {
addAssistantTripToCache,
getAssistantTripIfCached,
} from '../trip-cache';
import {
LineFragment,
LinesDocument,
LinesQuery,
LinesQueryVariables,
} from './journey-gql/lines.generated';

const DEFAULT_JOURNEY_CONFIG = {
numTripPatterns: 8, // The maximum number of trip patterns to return.
Expand All @@ -73,6 +81,7 @@ export type JourneyPlannerApi = {
trip(input: TripInput): Promise<TripData>;
nonTransitTrips(input: NonTransitTripInput): Promise<NonTransitTripData>;
singleTrip(input: string): Promise<TripPatternWithDetails | undefined>;
lines(input: LineInput): Promise<LineData>;
};

export function createJourneyApi(
Expand Down Expand Up @@ -156,6 +165,19 @@ export function createJourneyApi(
return nonTransits;
},

async lines(input) {
const result = await client.query<LinesQuery, LinesQueryVariables>({
query: LinesDocument,
variables: { authorities: input.authorities },
fetchPolicy: 'cache-first',
});

if (result.error || result.errors) {
throw result.error || result.errors;
}

return createLinesRecord(result.data.lines);
},
async trip(input) {
const journeyModes = {
accessMode: StreetMode.Foot,
Expand Down Expand Up @@ -802,3 +824,16 @@ async function getSortedViaTrips(
};
return sortedData;
}

function createLinesRecord(lines: LineFragment[]) {
const record: Record<string, string[]> = {};
for (const line of lines) {
if (!line.publicCode) continue;
if (!record[line.publicCode]) {
record[line.publicCode] = [];
}

record[line.publicCode].push(line.id);
}
return record;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
query Lines($authorities: [String]) {
lines(authorities: $authorities) {
...line
}
}

fragment line on Line {
id
publicCode
}
Original file line number Diff line number Diff line change
Expand Up @@ -158,6 +158,8 @@ export const tripPatternWithDetailsSchema = z.object({
),
});

export const linesSchema = z.record(z.array(z.string()));

export type TripData = z.infer<typeof tripSchema>;
export type NonTransitData = z.infer<typeof nonTransitSchema>;
export type TripPattern = z.infer<typeof tripPatternSchema>;
Expand All @@ -166,3 +168,4 @@ export type Quay = z.infer<typeof quaySchema>;
export type TripPatternWithDetails = z.infer<
typeof tripPatternWithDetailsSchema
>;
export type LineData = z.infer<typeof linesSchema>;
4 changes: 4 additions & 0 deletions src/page-modules/assistant/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -82,3 +82,7 @@ export type NonTransitTripData = {
footTrip?: NonTransitData;
bikeRentalTrip?: NonTransitData;
};

export type LineInput = {
authorities: string[];
};
22 changes: 22 additions & 0 deletions src/pages/api/assistant/lines/[authorityId].ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import { tryResult } from '@atb/modules/api-server';
import { LinesApiReturnType } from '@atb/page-modules/assistant/client';
import { handlerWithAssistantClient } from '@atb/page-modules/assistant/server';

export default handlerWithAssistantClient<LinesApiReturnType>({
async GET(req, res, { client, ok }) {
const { authorityId } = req.query;
const authorities: string[] = [];

if (typeof authorityId === 'string') {
authorities.push(authorityId);
}

return tryResult(req, res, async () => {
return ok(
await client.lines({
authorities: authorities,
}),
);
});
},
});
6 changes: 3 additions & 3 deletions src/translations/pages/assistant.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ const AssistantInternal = {
error: _(
'Linje må være tall eller liste av tall (f.eks. 2, 10)',
'Line must be a number or list of numbers (e.g. 2, 10)',
'Linje må vere tal eller liste av tal (t.d. 2, 10',
'Linje må vere tal eller liste av tal (t.d. 2, 10)',
),
lineSearch: {
label: _('Linje', 'Line', 'Linje'),
Expand Down Expand Up @@ -420,7 +420,7 @@ export const Assistant = orgSpecificTranslations(AssistantInternal, {
error: _(
'Linje må være tall eller liste av tall (f.eks. 100, 200)',
'Line must be a number or list of numbers (e.g. 100, 200)',
'Linje må vere tal eller liste av tal (t.d. 100, 200',
'Linje må vere tal eller liste av tal (t.d. 100, 200)',
),

example: _(
Expand All @@ -437,7 +437,7 @@ export const Assistant = orgSpecificTranslations(AssistantInternal, {
error: _(
'Linje må være tall eller liste av tall (f.eks. 905, 902)',
'Line must be a number or list of numbers (e.g. 905, 902)',
'Linje må vere tal eller liste av tal (t.d. 905, 902',
'Linje må vere tal eller liste av tal (t.d. 905, 902)',
),

example: _(
Expand Down

0 comments on commit 4bd12d0

Please sign in to comment.