Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

debug client: support stop ids in from / to inputs #6133

Merged
Merged
16 changes: 10 additions & 6 deletions client/src/components/MapView/NavigationMarkers.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { TripQueryVariables } from '../../gql/graphql.ts';
import { Marker } from 'react-map-gl';
import markerFlagStart from '../../static/img/marker-flag-start-shadowed.png';
import markerFlagEnd from '../../static/img/marker-flag-end-shadowed.png';
import { useCoordinateResolver } from './useCoordinateResolver.ts';

export function NavigationMarkers({
setCursor,
Expand All @@ -14,13 +15,16 @@ export function NavigationMarkers({
setTripQueryVariables: (variables: TripQueryVariables) => void;
loading: boolean;
}) {
const fromCoordinates = useCoordinateResolver(tripQueryVariables.from);
const toCoordinates = useCoordinateResolver(tripQueryVariables.to);

return (
<>
{tripQueryVariables.from.coordinates && (
{fromCoordinates && (
<Marker
draggable
latitude={tripQueryVariables.from.coordinates?.latitude}
longitude={tripQueryVariables.from.coordinates?.longitude}
latitude={fromCoordinates.latitude}
longitude={fromCoordinates.longitude}
onDragStart={() => setCursor('grabbing')}
onDragEnd={(e) => {
setCursor('auto');
Expand All @@ -36,11 +40,11 @@ export function NavigationMarkers({
<img alt="" src={markerFlagStart} height={48} width={49} />
</Marker>
)}
{tripQueryVariables.to.coordinates && (
{toCoordinates && (
<Marker
draggable
latitude={tripQueryVariables.to.coordinates?.latitude}
longitude={tripQueryVariables.to.coordinates?.longitude}
latitude={toCoordinates.latitude}
longitude={toCoordinates.longitude}
onDragStart={() => setCursor('grabbing')}
onDragEnd={(e) => {
setCursor('auto');
Expand Down
30 changes: 30 additions & 0 deletions client/src/components/MapView/useCoordinateResolver.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import { Location } from '../../gql/graphql.ts';
import { useQuayCoordinateQuery } from '../../hooks/useQuayCoordinateQuery.ts';

interface Coordinates {
latitude: number;
longitude: number;
}

export function useCoordinateResolver(location: Location): Coordinates | undefined {
const quay = useQuayCoordinateQuery(location);

if (quay) {
const { latitude, longitude } = quay;

if (latitude && longitude) {
return {
latitude,
longitude,
};
}
}

if (location.coordinates) {
return {
...location.coordinates,
};
}

return undefined;
}
52 changes: 39 additions & 13 deletions client/src/components/SearchBar/LocationInputField.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,37 @@
import { Form } from 'react-bootstrap';
import { COORDINATE_PRECISION } from './constants.ts';
import { Location } from '../../gql/graphql.ts';
import { toString, parseLocation } from '../../util/locationConverter.ts';
import { Location, TripQueryVariables } from '../../gql/graphql.ts';
import { useCallback, useEffect, useState } from 'react';

interface Props {
id: string;
label: string;
tripQueryVariables: TripQueryVariables;
setTripQueryVariables: (tripQueryVariables: TripQueryVariables) => void;
locationFieldKey: 'from' | 'to';
}

export function LocationInputField({ id, label, tripQueryVariables, setTripQueryVariables, locationFieldKey }: Props) {
const [value, setValue] = useState('');

useEffect(() => {
const initialLocation: Location = tripQueryVariables[locationFieldKey];

setValue(toString(initialLocation) || '');
}, [tripQueryVariables, locationFieldKey]);

const onLocationChange = useCallback(
(value: string) => {
const newLocation = parseLocation(value) || {};

setTripQueryVariables({
...tripQueryVariables,
[locationFieldKey]: newLocation,
});
},
[tripQueryVariables, setTripQueryVariables, locationFieldKey],
);

export function LocationInputField({ location, id, label }: { location: Location; id: string; label: string }) {
return (
<Form.Group>
<Form.Label column="sm" htmlFor={id}>
Expand All @@ -14,16 +43,13 @@ export function LocationInputField({ location, id, label }: { location: Location
size="sm"
placeholder="[Click in map]"
className="input-medium"
// Intentionally empty for now, but needed because of
// https://react.dev/reference/react-dom/components/input#controlling-an-input-with-a-state-variable
onChange={() => {}}
value={
location.coordinates
? `${location.coordinates?.latitude.toPrecision(
COORDINATE_PRECISION,
)} ${location.coordinates?.longitude.toPrecision(COORDINATE_PRECISION)}`
: ''
}
onChange={(e) => {
setValue(e.target.value);
}}
onBlur={(event) => {
onLocationChange(event.target.value);
}}
value={value}
/>
</Form.Group>
);
Expand Down
16 changes: 14 additions & 2 deletions client/src/components/SearchBar/SearchBar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -38,9 +38,21 @@ export function SearchBar({ onRoute, tripQueryVariables, setTripQueryVariables,
{showServerInfo && <ServerInfoTooltip serverInfo={serverInfo} target={target} />}
</div>
</Navbar.Brand>
<LocationInputField location={tripQueryVariables.from} label="From" id="fromInputField" />
<LocationInputField
label="From"
id="fromInputField"
locationFieldKey="from"
tripQueryVariables={tripQueryVariables}
setTripQueryVariables={setTripQueryVariables}
/>
<SwapLocationsButton tripQueryVariables={tripQueryVariables} setTripQueryVariables={setTripQueryVariables} />
<LocationInputField location={tripQueryVariables.to} label="To" id="toInputField" />
<LocationInputField
label="To"
id="toInputField"
locationFieldKey="to"
tripQueryVariables={tripQueryVariables}
setTripQueryVariables={setTripQueryVariables}
/>
<DepartureArrivalSelect tripQueryVariables={tripQueryVariables} setTripQueryVariables={setTripQueryVariables} />
<DateTimeInputField tripQueryVariables={tripQueryVariables} setTripQueryVariables={setTripQueryVariables} />
<NumTripPatternsInput tripQueryVariables={tripQueryVariables} setTripQueryVariables={setTripQueryVariables} />
Expand Down
36 changes: 36 additions & 0 deletions client/src/hooks/useQuayCoordinateQuery.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import { useEffect, useState } from 'react';
import { request } from 'graphql-request';
import { Location, QueryType } from '../gql/graphql.ts';
import { getApiUrl } from '../util/getApiUrl.ts';
import { graphql } from '../gql';

const query = graphql(`
query quayCoordinate($id: String!) {
quay(id: $id) {
latitude
longitude
}
}
`);

export const useQuayCoordinateQuery = (location: Location) => {
const [data, setData] = useState<QueryType | null>(null);

useEffect(() => {
const fetchData = async () => {
if (location.place) {
const variables = { id: location.place };
try {
setData((await request(getApiUrl(), query, variables)) as QueryType);
} catch (e) {
console.error('Error at useQuayCoordinateQuery', e);
}
} else {
setData(null);
}
};
fetchData();
}, [location]);

return data?.quay;
};
20 changes: 14 additions & 6 deletions client/src/hooks/useTripQuery.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { useCallback, useEffect, useState } from 'react';
import { request } from 'graphql-request';
import { QueryType, TripQueryVariables } from '../gql/graphql.ts';
import { Location, QueryType, TripQueryVariables } from '../gql/graphql.ts';
import { getApiUrl } from '../util/getApiUrl.ts';
import { query } from '../static/query/tripQuery.tsx';

Expand All @@ -22,10 +22,14 @@ export const useTripQuery: TripQueryHook = (variables) => {
} else {
if (variables) {
setLoading(true);
if (pageCursor) {
setData((await request(getApiUrl(), query, { ...variables, pageCursor })) as QueryType);
} else {
setData((await request(getApiUrl(), query, variables)) as QueryType);
try {
if (pageCursor) {
setData((await request(getApiUrl(), query, { ...variables, pageCursor })) as QueryType);
} else {
setData((await request(getApiUrl(), query, variables)) as QueryType);
}
} catch (e) {
console.error('Error at useTripQuery', e);
}
setLoading(false);
} else {
Expand All @@ -37,10 +41,14 @@ export const useTripQuery: TripQueryHook = (variables) => {
);

useEffect(() => {
if (variables?.from.coordinates && variables?.to.coordinates) {
if (validLocation(variables?.from) && validLocation(variables?.to)) {
callback();
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [variables?.from, variables?.to]);
return [data, loading, callback];
};

function validLocation(location: Location | undefined) {
return location && (location.coordinates || location.place);
}
37 changes: 37 additions & 0 deletions client/src/util/locationConverter.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import { COORDINATE_PRECISION } from '../components/SearchBar/constants.ts';
import { Location } from '../gql/graphql.ts';

const DOUBLE_PATTERN = '-{0,1}\\d+(\\.\\d+){0,1}';

const LAT_LON_PATTERN = '(' + DOUBLE_PATTERN + ')(\\s+)(' + DOUBLE_PATTERN + ')';

export function parseLocation(value: string): Location | null {
testower marked this conversation as resolved.
Show resolved Hide resolved
const latLonMatch = value.match(LAT_LON_PATTERN);

if (latLonMatch) {
return {
coordinates: {
latitude: +latLonMatch[1],
testower marked this conversation as resolved.
Show resolved Hide resolved
longitude: +latLonMatch[4],
},
};
}

return {
place: value,
};
}

export function toString(location: Location): string | null {
if (location.coordinates) {
return `${location.coordinates?.latitude.toPrecision(
COORDINATE_PRECISION,
)} ${location.coordinates?.longitude.toPrecision(COORDINATE_PRECISION)}`;
}

if (location.place) {
return location.place;
}

return null;
}
Loading