Skip to content

Commit 70374d5

Browse files
kagiurazwliew
authored andcommitted
refactor: ♻️ refactoring bus apis / util functions
1 parent f1e5b47 commit 70374d5

File tree

4 files changed

+58
-112
lines changed

4 files changed

+58
-112
lines changed

website/src/apis/nextbus-new.ts

Lines changed: 19 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -1,60 +1,22 @@
1-
import axios from 'axios';
2-
import { BusStop } from 'types/buses';
3-
4-
import { NextBus, NextBusTime, NextBusTimings } from 'types/venues';
5-
6-
const baseUrl = 'https://nnextbus.nus.edu.sg';
7-
8-
interface ShuttleServiceResult {
9-
caption: string;
10-
name: string;
11-
shuttles: Shuttle[];
12-
}
13-
14-
interface Shuttle {
15-
arrivalTime: string;
16-
name: string;
17-
nextArrivalTime: string;
18-
nextPassengers: string;
19-
passengers: string;
20-
}
21-
22-
function convertArrivalTime(arrivalTime: string): NextBusTime {
23-
const numericTime = +arrivalTime;
24-
if (!Number.isNaN(numericTime)) return numericTime;
25-
if (arrivalTime === 'Arr' || arrivalTime === '-') return arrivalTime;
26-
throw new Error(`Unknown arrival time ${arrivalTime}`);
27-
}
28-
29-
export function getStops(): Promise<BusStop[]> {
30-
const url = `${baseUrl}/BusStops`;
31-
return axios
32-
.get(url, {
1+
const baseURL = 'https://nusmods.com'; // TODO: wait until we have an api proxy
2+
3+
export const getStopTimings = async (
4+
stop: string,
5+
setState: (state: ShuttleServiceResult) => void,
6+
) => {
7+
if (!stop) return;
8+
const API_AUTH = ''; // TODO: wait until we have an api proxy
9+
try {
10+
const response = await fetch(`${baseURL}/ShuttleService?busstopname=${stop}`, {
3311
headers: {
34-
Authorization: process.env?.NEXTBUS_API_AUTH || '',
12+
authorization: API_AUTH,
13+
accept: 'application/json',
3514
},
36-
})
37-
.then((response) => response.data.BusStopsResult.busstops);
38-
}
39-
40-
export function nextBus(code: string): Promise<any> {
41-
const url = `${baseUrl}/arrival`;
42-
return axios
43-
.get<{
44-
ShuttleServiceResult: ShuttleServiceResult;
45-
}>(url, { params: { busstopname: code } })
46-
.then((response) => {
47-
const shuttles: NextBusTimings = {};
48-
49-
response.data.ShuttleServiceResult.shuttles.forEach((arrival: Shuttle) => {
50-
const timing: NextBus = {
51-
arrivalTime: convertArrivalTime(arrival.arrivalTime),
52-
nextArrivalTime: convertArrivalTime(arrival.nextArrivalTime),
53-
};
54-
55-
shuttles[arrival.name] = timing;
56-
});
57-
58-
return shuttles;
5915
});
60-
}
16+
const data = await response.json();
17+
// console.log(data);
18+
setState(data.ShuttleServiceResult);
19+
} catch (e) {
20+
console.error(e);
21+
}
22+
};

website/src/utils/mobility.ts

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,3 +63,33 @@ export const getServiceStatus = (period: 'term' | 'vacation' = 'term') => {
6363
});
6464
return serviceStatuses;
6565
};
66+
67+
export const getArrivalTime = (eta: number) => {
68+
const date = new Date();
69+
date.setSeconds(date.getSeconds() + eta);
70+
return date;
71+
};
72+
73+
export const getShownArrivalTime = (eta: number, forceTime = false) => {
74+
const date = getArrivalTime(eta);
75+
if (!forceTime && eta < 60 * 60) {
76+
if (eta < 60) return 'Arriving';
77+
return `${Math.floor(eta / 60)} mins`;
78+
}
79+
return date.toLocaleTimeString([], {
80+
hour: '2-digit',
81+
minute: '2-digit',
82+
hour12: false,
83+
// time in SGT
84+
timeZone: 'Asia/Singapore',
85+
});
86+
};
87+
88+
export const getDepartAndArriveTiming = (timings = [] as NUSShuttle[], isEnd: boolean) => {
89+
if (isEnd) {
90+
const departTiming = timings.find((t) => t.busstopcode.endsWith('-S'));
91+
const arriveTiming = timings.find((t) => t.busstopcode.endsWith('-E')) || timings[0];
92+
return { departTiming, arriveTiming };
93+
}
94+
return { departTiming: timings[0], arriveTiming: undefined };
95+
};

website/src/views/mobility/StopDetails.tsx

Lines changed: 8 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@ import { Fragment, useEffect, useMemo, useState } from 'react';
55
import classNames from 'classnames';
66
import { ChevronDown, ChevronRight, ChevronUp, ExternalLink, MoreVertical } from 'react-feather';
77
import { current } from 'immer';
8+
import { getDepartAndArriveTiming, getShownArrivalTime } from 'utils/mobility';
9+
import { getStopTimings } from 'apis/nextbus-new';
810
import isbServicesJSON from '../../data/isb-services.json';
911
import isbStopsJSON from '../../data/isb-stops.json';
1012
import publicBusJSON from '../../data/public-bus.json';
@@ -15,61 +17,11 @@ const isbServices = isbServicesJSON as ISBService[];
1517
const isbStops = isbStopsJSON as ISBStop[];
1618
const publicBus = publicBusJSON as Record<number, string>;
1719

18-
const baseURL = 'https://nusmods.com'; // TODO: wait until we have an api proxy
19-
2020
type Props = {
2121
stop: string;
2222
setSelectedService: (service: ISBService) => void;
2323
};
2424

25-
const getArrivalTime = (eta: number) => {
26-
const date = new Date();
27-
date.setSeconds(date.getSeconds() + eta);
28-
return date;
29-
};
30-
31-
const getShownArrivalTime = (eta: number, forceTime = false) => {
32-
const date = getArrivalTime(eta);
33-
if (!forceTime && eta < 60 * 60) {
34-
if (eta < 60) return 'Arriving';
35-
return `${Math.floor(eta / 60)} mins`;
36-
}
37-
return date.toLocaleTimeString([], {
38-
hour: '2-digit',
39-
minute: '2-digit',
40-
hour12: false,
41-
// time in SGT
42-
timeZone: 'Asia/Singapore',
43-
});
44-
};
45-
46-
const getStopTimings = async (stop: string, setState: (state: ShuttleServiceResult) => void) => {
47-
if (!stop) return;
48-
const API_AUTH = ''; // TODO: wait until we have an api proxy
49-
try {
50-
const response = await fetch(`${baseURL}/ShuttleService?busstopname=${stop}`, {
51-
headers: {
52-
authorization: API_AUTH,
53-
accept: 'application/json',
54-
},
55-
});
56-
const data = await response.json();
57-
// console.log(data);
58-
setState(data.ShuttleServiceResult);
59-
} catch (e) {
60-
console.error(e);
61-
}
62-
};
63-
64-
const getDepartAndArriveTiming = (timings = [] as NUSShuttle[], isEnd: boolean) => {
65-
if (isEnd) {
66-
const departTiming = timings.find((t) => t.busstopcode.endsWith('-S'));
67-
const arriveTiming = timings.find((t) => t.busstopcode.endsWith('-E')) || timings[0];
68-
return { departTiming, arriveTiming };
69-
}
70-
return { departTiming: timings[0], arriveTiming: undefined };
71-
};
72-
7325
function ServiceStop(props: { stop: ISBStop; className?: string }) {
7426
const { stop } = props;
7527
return (
@@ -418,7 +370,9 @@ function StopDetails(props: Props) {
418370
const serviceDetail = isbServices.find((s) => s.id === shuttle.name.toLocaleLowerCase());
419371
if (!serviceDetail) return;
420372
const isEnd = stopDetails.name === serviceDetail.stops[serviceDetail.stops.length - 1];
421-
const serviceShuttles = selectedStopTiming?.shuttles.filter((s) => s.name === shuttle.name);
373+
const serviceShuttles = selectedStopTiming?.shuttles.filter(
374+
(s) => s.name === shuttle.name,
375+
) as NUSShuttle[];
422376
const timings = getDepartAndArriveTiming(serviceShuttles, isEnd);
423377
const timing = timings.departTiming;
424378

@@ -433,15 +387,12 @@ function StopDetails(props: Props) {
433387
incomingBuses.sort((a, b) => a.arrivingInSeconds - b.arrivingInSeconds);
434388
incomingBuses.splice(4);
435389
const incomingBusGroups = incomingBuses.reduce((acc, bus) => {
436-
// above but avoid param-reassign error
437390
const shownTime = getShownArrivalTime(bus.arrivingInSeconds);
438-
// console.log('bus', bus, shownTime, bus.service.name);
439391
const newAcc = { ...acc };
440392
if (!newAcc[shownTime]) newAcc[shownTime] = [];
441393
newAcc[shownTime].push(bus);
442394
return newAcc;
443395
}, {} as Record<string, typeof incomingBuses>);
444-
// console.log('IBG', incomingBusGroups);
445396

446397
const publicShuttles = shuttles
447398
.filter((shuttle) => shuttle.name.startsWith('PUB:'))
@@ -497,7 +448,9 @@ function StopDetails(props: Props) {
497448

498449
{nusShuttles.map((shuttle) => {
499450
const service = isbServices.find((s) => s.id === shuttle.name.toLocaleLowerCase());
500-
const timings = selectedStopTiming?.shuttles.filter((s) => s.name === shuttle.name);
451+
const timings = selectedStopTiming?.shuttles.filter(
452+
(s) => s.name === shuttle.name,
453+
) as NUSShuttle[];
501454
if (!service) return <Fragment key={shuttle.name} />;
502455
return (
503456
<StopServiceDetails

website/src/views/mobility/isb.d.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ interface ShuttleServiceResult {
77
shuttles: Shuttle[];
88
caption: string;
99
}
10+
1011
type NUSShuttle = {
1112
passengers: string;
1213
name: string;

0 commit comments

Comments
 (0)