Skip to content

Commit 3ff05bd

Browse files
authored
DBC22-5929: support for out-of-bc locations (#1281)
1 parent e035348 commit 3ff05bd

4 files changed

Lines changed: 81 additions & 15 deletions

File tree

.env.example

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@ REACT_APP_ROUTE_PLANNER=<route planner url>
5454
REACT_APP_ROUTE_PLANNER_KEY=<route planner auth key>
5555
REACT_APP_GEOCODER_HOST=<geocoder url>
5656
REACT_APP_GEOCODER_API_AUTH_KEY=<api auth key>
57+
REACT_APP_ROUTABLE_LOCATIONS_HOST=<routable locations api url>
5758
REACT_APP_RECAPTCHA_CLIENT_ID=<reCAPTCHA client ID>
5859
REACT_APP_SURVEY_LINK=<exit survey link>
5960
REACT_APP_REPORT_WMS_LAYER=<report wms layer url>

compose/frontend/generate-config.sh

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ window.API_HOST='${REACT_APP_API_HOST}';
3737
window.REPORT_WMS_LAYER='${REACT_APP_REPORT_WMS_LAYER}';
3838
window.GEOCODER_HOST='${REACT_APP_GEOCODER_HOST}';
3939
window.GEOCODER_API_CLIENT_ID='${REACT_APP_GEOCODER_API_CLIENT_ID}';
40+
window.ROUTABLE_LOCATIONS_HOST='${REACT_APP_ROUTABLE_LOCATIONS_HOST}';
4041
window.ROUTE_PLANNER='${REACT_APP_ROUTE_PLANNER}';
4142
window.ROUTE_PLANNER_CLIENT_ID='${REACT_APP_ROUTE_PLANNER_CLIENT_ID}';
4243
window.REPLAY_THE_DAY='${REACT_APP_REPLAY_THE_DAY}';
@@ -107,4 +108,4 @@ fi
107108

108109

109110
echo "Configuration and assets ready in ${SHARED_CONFIG}:"
110-
ls -la "${SHARED_CONFIG}/"
111+
ls -la "${SHARED_CONFIG}/"
Lines changed: 77 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,81 @@
11
import { get } from "./helper.js";
22

3+
function escapeCqlString(value) {
4+
return String(value).replace(/'/g, "''");
5+
}
6+
7+
function sanitizeForILikePrefix(value) {
8+
return String(value).replace(/%/g, "").replace(/_/g, "");
9+
}
10+
11+
function normalizeRoutableLocationFeature(feature) {
12+
const props = feature.properties || {};
13+
const displayName = props.name != null ? String(props.name) : "";
14+
return {
15+
...feature,
16+
properties: {
17+
...props,
18+
fullAddress: displayName,
19+
},
20+
};
21+
}
22+
23+
export function getExtraLocations(addressInput) {
24+
// return empty promise if address input is less than 2 characters
25+
const trimmed = (addressInput || "").trim();
26+
if (trimmed.length < 2) {
27+
return Promise.resolve({ type: "FeatureCollection", features: [] });
28+
}
29+
30+
// escape CQL string and sanitize for ILike prefix
31+
const literal = escapeCqlString(sanitizeForILikePrefix(trimmed));
32+
return get(
33+
`${window.ROUTABLE_LOCATIONS_HOST}`,
34+
{
35+
service: "WFS",
36+
version: "1.0.0",
37+
request: "GetFeature",
38+
typeName: "public:routable-locations",
39+
outputFormat: "application/json",
40+
maxFeatures: 5,
41+
cql_filter: `authority='DriveBC' and name ilike '${literal}%'`,
42+
},
43+
{},
44+
false,
45+
);
46+
}
47+
348
export function getLocations(addressInput) {
4-
return get(`${window.GEOCODER_HOST}/addresses.json`, {
5-
minScore: 50,
6-
maxResults: 7,
7-
echo: 'false',
8-
brief: true,
9-
autoComplete: true,
10-
addressString: addressInput,
11-
exactSpelling: false,
12-
locationDescriptor: 'routingPoint',
13-
fuzzyMatch: true,
14-
}, {
15-
'apiKey': `${window.GEOCODER_API_CLIENT_ID}`,
16-
}
17-
).then((data) => data);
49+
const geocoderPromise = get(`${window.GEOCODER_HOST}/addresses.json`, {
50+
minScore: 50,
51+
maxResults: 7,
52+
echo: "false",
53+
brief: true,
54+
autoComplete: true,
55+
addressString: addressInput,
56+
exactSpelling: false,
57+
locationDescriptor: "routingPoint",
58+
fuzzyMatch: true,
59+
}, {
60+
apiKey: `${window.GEOCODER_API_CLIENT_ID}`,
61+
});
62+
63+
const extraPromise = getExtraLocations(addressInput).catch(() => ({
64+
type: "FeatureCollection",
65+
features: [],
66+
}));
67+
68+
// return all features from geocoder and extra locations
69+
return Promise.all([geocoderPromise, extraPromise]).then(
70+
([geoData, extraData]) => {
71+
const extraFeatures = (extraData.features || []).map(
72+
normalizeRoutableLocationFeature,
73+
);
74+
const geoFeatures = geoData.features || [];
75+
return {
76+
...geoData,
77+
features: [...extraFeatures, ...geoFeatures],
78+
};
79+
},
80+
);
1881
}

src/frontend/src/env.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ window.MAP_STYLE = `${process.env.REACT_APP_MAP_STYLE}`;
1818
window.REPLAY_THE_DAY = `${process.env.REACT_APP_REPLAY_THE_DAY}`;
1919
window.GEOCODER_HOST = `${process.env.REACT_APP_GEOCODER_HOST}`;
2020
window.GEOCODER_API_CLIENT_ID = `${process.env.REACT_APP_GEOCODER_API_CLIENT_ID}`;
21+
window.ROUTABLE_LOCATIONS_HOST = `${process.env.REACT_APP_ROUTABLE_LOCATIONS_HOST}`;
2122
window.ROUTE_PLANNER = `${process.env.REACT_APP_ROUTE_PLANNER}`;
2223
window.ROUTE_PLANNER_CLIENT_ID = `${process.env.REACT_APP_ROUTE_PLANNER_CLIENT_ID}`;
2324
window.PRIMARY_ROUTE_GDF = `${process.env.REACT_APP_PRIMARY_ROUTE_GDF}`;

0 commit comments

Comments
 (0)