Skip to content

Commit c3aefa6

Browse files
kagiurazwliew
authored andcommitted
refactor: ♻️ refactored + optimized the isb pages
1 parent 35aebf7 commit c3aefa6

File tree

6 files changed

+275
-353
lines changed

6 files changed

+275
-353
lines changed

website/src/views/components/bus-map/ISBServices.tsx

Lines changed: 54 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -1,29 +1,33 @@
1-
import { PureComponent, useEffect, useState } from 'react';
2-
import { DivIcon, DragEndEventHandlerFn, LatLngBoundsExpression } from 'leaflet';
3-
import { Marker, Popup, SVGOverlay, useMapEvents } from 'react-leaflet';
1+
import { useEffect, useMemo, useState } from 'react';
2+
import { DivIcon, LatLngBoundsExpression } from 'leaflet';
3+
import { Marker, SVGOverlay, useMapEvents } from 'react-leaflet';
44
import classnames from 'classnames';
5-
import produce from 'immer';
65

7-
// import type { BusStop, BusTiming } from 'types/venues';
8-
import type { EmptyProps } from 'types/utils';
9-
10-
import busStopJSON from 'data/bus-stops.json';
116
import isbStopJson from 'data/isb-stops.json';
12-
import { allowBusStopEditing } from 'utils/debug';
13-
import { nextBus } from 'apis/nextbus';
147
import isbServicesJSON from 'data/isb-services.json';
158
import { getRouteSegments, segmentsToClasses } from 'utils/mobility';
169
import styles from './ISBServices.scss';
17-
import { ArrivalTimes } from './ArrivalTimes';
10+
11+
// these eslint warnings are disabled because we're doing some convoluted svg importing as react components :,)
12+
// SHOULD be changed into using polyline instead, as that's the correct way to do it
13+
// but i am but a stupid graphic designer who knows how to use illustrator and not how to use GIS software
14+
1815
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
1916
// @ts-ignore
2017
import KRC from './routes/KRC.svg?svgr';
2118
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
2219
// @ts-ignore
2320
import BTC from './routes/BTC.svg?svgr';
2421

22+
const BTCStops = ['CG', 'OTH', 'BG-MRT'];
23+
2524
type Props =
26-
| { mapMode: 'all'; onStopClicked: (stop: string | null) => void; focusStop: string | null }
25+
| {
26+
mapMode: 'all';
27+
onStopClicked: (stop: string | null) => void;
28+
focusStop: string | null;
29+
campus: 'KRC' | 'BTC';
30+
}
2731
| {
2832
mapMode: 'selected';
2933
selectedSegments: {
@@ -37,6 +41,7 @@ type Props =
3741
}[];
3842
onStopClicked: (stop: string | null) => void;
3943
focusStop: string | null;
44+
campus: 'KRC' | 'BTC';
4045
};
4146

4247
const KRCBounds: LatLngBoundsExpression = [
@@ -48,7 +53,6 @@ const BTCBounds: LatLngBoundsExpression = [
4853
[1.3289028289795464, 103.83893751900072],
4954
];
5055

51-
const btcStops = ['CG', 'OTH', 'BG-MRT'];
5256
const isbServices = isbServicesJSON;
5357

5458
export default function ISBStops(props: Props) {
@@ -66,34 +70,33 @@ export default function ISBStops(props: Props) {
6670
},
6771
});
6872

69-
let selectedSegments: { classes: string[]; color: string }[] = [];
70-
let selectedStops: { name: string; color: string; subtext?: string }[] = [];
71-
if (props.mapMode === 'selected') {
72-
selectedSegments = segmentsToClasses(props.selectedSegments);
73-
selectedStops = props.selectedStops;
74-
} else if (props.mapMode === 'all' && currentFocusStop) {
75-
const currentFocusStopDetails = isbStopJson.find((stop) => stop.name === currentFocusStop);
76-
if (currentFocusStopDetails) {
77-
// get all services passing by this stop
78-
const passingServices = currentFocusStopDetails.shuttles
79-
.map((service) => {
80-
const serviceDetails = isbServices.find((s) => s.name === service.name);
81-
if (!serviceDetails) return null;
82-
return serviceDetails;
83-
})
84-
.filter(Boolean) as (typeof isbServices)[number][];
85-
86-
// for each service, get the route segments, and merge it into selectedSegments
87-
// selectedSegments returns an array of segments, so do not use map
88-
passingServices.forEach((service) => {
89-
selectedSegments = selectedSegments.concat(
90-
segmentsToClasses(getRouteSegments(service.stops, '#3087d8')),
91-
);
92-
});
93-
94-
// console.log('selectedSegments', selectedSegments);
73+
const selection = useMemo(() => {
74+
let selectedSegments: { classes: string[]; color: string }[] = [];
75+
let selectedStops: { name: string; color: string; subtext?: string }[] = [];
76+
if (props.mapMode === 'selected') {
77+
selectedSegments = segmentsToClasses(props.selectedSegments);
78+
selectedStops = props.selectedStops;
79+
} else if (props.mapMode === 'all' && currentFocusStop) {
80+
const currentFocusStopDetails = isbStopJson.find((stop) => stop.name === currentFocusStop);
81+
if (currentFocusStopDetails) {
82+
const passingServices = currentFocusStopDetails.shuttles
83+
.map((service) => {
84+
const serviceDetails = isbServices.find((s) => s.name === service.name);
85+
if (!serviceDetails) return null;
86+
return serviceDetails;
87+
})
88+
.filter(Boolean) as (typeof isbServices)[number][];
89+
passingServices.forEach((service) => {
90+
selectedSegments = selectedSegments.concat(
91+
segmentsToClasses(getRouteSegments(service.stops, '#3087d8')),
92+
);
93+
});
94+
}
9595
}
96-
}
96+
return { selectedSegments, selectedStops };
97+
}, [props, currentFocusStop]);
98+
99+
const { selectedSegments, selectedStops } = selection;
97100

98101
return (
99102
<>
@@ -103,6 +106,13 @@ export default function ISBStops(props: Props) {
103106
return null;
104107
}
105108

109+
if (
110+
(props.campus === 'KRC' && BTCStops.includes(stop.name)) ||
111+
(props.campus === 'BTC' && !BTCStops.includes(stop.name))
112+
) {
113+
return null;
114+
}
115+
106116
let hasPairAndIsTheOpposite = false;
107117
let displayType: 'normal' | 'interchange' | 'no-label' | 'hidden' = 'normal';
108118
let subtext = '';
@@ -138,7 +148,6 @@ export default function ISBStops(props: Props) {
138148
hasPairAndIsTheOpposite = true;
139149
}
140150
}
141-
142151
break;
143152
default:
144153
break;
@@ -167,7 +176,6 @@ export default function ISBStops(props: Props) {
167176
isLeft && styles.left,
168177
isFocused && styles.focused,
169178
);
170-
// [styles.left]: stop.displayRoutesLeft,
171179

172180
const routeNameClass = classnames(styles.stopName);
173181

@@ -195,6 +203,7 @@ export default function ISBStops(props: Props) {
195203
.join('')}</div>`
196204
: '';
197205

206+
// for the love of god if anyone knows a better way that defining RAW HTML
198207
const icon = new DivIcon({
199208
// language=HTML
200209
html: `
@@ -218,8 +227,6 @@ export default function ISBStops(props: Props) {
218227
}`,
219228
className: styles.iconWrapper,
220229
iconSize: [30, 30],
221-
// Move the popup a bit higher so it won't cover the bus stop icon
222-
popupAnchor: [0, -5],
223230
});
224231

225232
return (
@@ -230,14 +237,11 @@ export default function ISBStops(props: Props) {
230237
eventHandlers={{
231238
click: () => {
232239
if (props.onStopClicked) {
233-
// setCurrentFocusStop(stop.name);
234240
props.onStopClicked(stop.name);
235-
map.flyTo([stop.latitude, stop.longitude], 17);
241+
map.flyTo([stop.latitude, stop.longitude], 16);
236242
}
237243
},
238244
}}
239-
// draggable={allowEditing}
240-
// autoPan={allowEditing}
241245
/>
242246
);
243247
})}
@@ -281,7 +285,7 @@ export default function ISBStops(props: Props) {
281285
.join(' ')}
282286
</style>
283287

284-
{/* background */}
288+
{/* background (lines' stroke) */}
285289
<SVGOverlay bounds={KRCBounds} className="overlay_bg">
286290
<KRC className={mapMode === 'all' && !currentFocusStop ? 'allRoutes' : ''} />
287291
</SVGOverlay>
@@ -290,7 +294,7 @@ export default function ISBStops(props: Props) {
290294
<BTC className={mapMode === 'all' && !currentFocusStop ? 'allRoutes' : ''} />
291295
</SVGOverlay>
292296

293-
{/* foreground */}
297+
{/* foreground (lines fill) */}
294298
<SVGOverlay bounds={KRCBounds} className="overlay_fg">
295299
<KRC className={mapMode === 'all' && !currentFocusStop ? 'allRoutes' : ''} />
296300
</SVGOverlay>

0 commit comments

Comments
 (0)