Skip to content

Commit

Permalink
basic subway bookmark (#107)
Browse files Browse the repository at this point in the history
* visible + clickable subway bookmark

* created a subway station name db
  • Loading branch information
thomassth authored Jun 2, 2024
1 parent 907bd56 commit 7aaf0e0
Show file tree
Hide file tree
Showing 14 changed files with 270 additions and 73 deletions.
4 changes: 2 additions & 2 deletions src/components/badges.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { Badge } from "@fluentui/react-components";

import { fluentStyles } from "../styles/fluent";
import { fluentStyles } from "../styles/fluent.js";

const badgeColor = (text: string) => {
switch (true) {
Expand Down Expand Up @@ -40,7 +40,7 @@ const badgeOutline = (text: string) => {
return "outline";
default:
for (const item of occasional) {
if (text.startsWith(item.toString())) {
if (text.toString().startsWith(item.toString())) {
return "outline";
}
}
Expand Down
22 changes: 17 additions & 5 deletions src/components/bookmarks/BookmarkCard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@ import { useCallback } from "react";

import { stopBookmarksRedux } from "../../models/etaObjects.js";
import { removeStopBookmark } from "../../store/bookmarks/slice.js";
import { useAppDispatch, useAppSelector } from "../../store/index.js";
import { store, useAppDispatch, useAppSelector } from "../../store/index.js";
import { subwayDbSelectors } from "../../store/suwbayDb/slice.js";
import { EtaCard } from "../etaCard/EtaCard.js";

export function BookmarkCard(props: { id: number }) {
Expand All @@ -16,16 +17,27 @@ export function BookmarkCard(props: { id: number }) {
dispatch(removeStopBookmark(props.id));
}, [stopBookmarks.ids]);

const item = stopBookmarks.entities[id];

const name =
item.type === "ttc-subway" && id
? subwayDbSelectors.selectById(store.getState().subwayDb, id)?.stop
?.name ?? item.name
: item.name;
return (
<EtaCard
enabled={stopBookmarks.entities[id].enabled}
enabled={item.enabled}
id={id.toString()}
etas={[]}
lines={stopBookmarks.entities[id].lines}
name={stopBookmarks.entities[id].name}
lines={item.lines}
name={name}
editable
onDelete={checkBookmarkStatus}
stopUrl={`/stops/${stopBookmarks.entities[id].stopId}`}
stopUrl={
item.type === "ttc-subway"
? `/ttc/lines/${item.lines[0]}/${item.stopId}`
: `/stops/${item.stopId}`
}
/>
);
}
32 changes: 26 additions & 6 deletions src/components/eta/BookmarkCardEta.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { LineStopEta, stopBookmarksRedux } from "../../models/etaObjects";
import { useAppSelector } from "../../store";
import { EtaCard } from "../etaCard/EtaCard";
import { LineStopEta, stopBookmarksRedux } from "../../models/etaObjects.js";
import { store, useAppSelector } from "../../store/index.js";
import { subwayDbSelectors } from "../../store/suwbayDb/slice.js";
import { EtaCard } from "../etaCard/EtaCard.js";

export function BookmarkCardEta(props: { item: LineStopEta }) {
const stopBookmarks: stopBookmarksRedux = useAppSelector(
Expand All @@ -15,14 +16,33 @@ export function BookmarkCardEta(props: { item: LineStopEta }) {
}
}

const item = props.item;

const name =
item.type === "ttc-subway" && props.item.stopTag
? subwayDbSelectors.selectById(
store.getState().subwayDb,
props.item.stopTag
)?.stop?.name ?? props.item.routeName
: props.item.routeName;

return (
<EtaCard
id={props.item.routeName + props.item.stopTag}
etas={props.item.etas}
lines={[props.item.etas[0].branch]}
name={props.item.routeName}
lines={[
props.item.type === "ttc-subway"
? props.item.line
: props.item.etas[0]?.branch,
]}
name={name}
editable={false}
onDelete={undefined}
stopUrl={stopUrl}
stopUrl={
item.type === "ttc-subway"
? `/ttc/lines/${item.line}/${item.stopTag}`
: stopUrl
}
/>
);
}
101 changes: 70 additions & 31 deletions src/components/eta/FavouriteEta.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,10 @@ import {
} from "../../models/etaObjects.js";
import { store, useAppSelector } from "../../store/index.js";
import { settingsSelectors } from "../../store/settings/slice.js";
import { subwayDbSelectors } from "../../store/suwbayDb/slice.js";
import Bookmark from "../bookmarks/Bookmark.js";
import { EtaCard } from "../etaCard/EtaCard.js";
import { FetchJSONWithCancelToken } from "../fetch/fetchUtils.js";
import { getTTCMultiRouteData } from "../fetch/fetchUtils.js";
import {
multiStopParser,
multiStopUnifier,
Expand All @@ -23,8 +24,15 @@ import { BookmarkCardEta } from "./BookmarkCardEta.js";
import style from "./FavouriteEta.module.css";

export default function FavouriteEta() {
const stopBookmarks: stopBookmarksRedux = useAppSelector(
(state) => state.stopBookmarks
const stopBookmarks = useAppSelector(
(state: { stopBookmarks: stopBookmarksRedux }) => state.stopBookmarks
);

const subwayBookmarks = useAppSelector(
(state: { stopBookmarks: stopBookmarksRedux }) =>
Object.values(state.stopBookmarks.entities).filter((item) => {
return item.type === "ttc-subway" && (item.enabled?.length ?? 0) > 0;
})
);
const { t } = useTranslation();
const [data, setData] = useState<EtaPredictionJson>();
Expand All @@ -46,37 +54,54 @@ export default function FavouriteEta() {

if (lines && lines.length > 0)
for (const line of lines) {
fetchUrl = fetchUrl.concat(`&stops=${parseInt(line)}|${ttcStop}`);
if (parseInt(line) > 6)
fetchUrl = fetchUrl.concat(`&stops=${parseInt(line)}|${ttcStop}`);
}
}

useEffect(() => {
const controller = new AbortController();

const fetchEtaData = async () => {
const { data, Error } = await FetchJSONWithCancelToken(
`https://retro.umoiq.com/service/publicJSONFeed?command=predictionsForMultiStops&a=ttc${fetchUrl}`,
{
signal: controller.signal,
method: "GET",
}
const setEtaDb = (data?: EtaPredictionJson) => {
if (unifiedEtaValue) {
if (data) {
setUnifiedEtaDb(multiStopUnifier(data, stopBookmarks));
} else
setUnifiedEtaDb(
subwayBookmarks.map((subwayStop) => {
return { ...subwayStop, etas: [] };
})
);
} else {
setSingleEtaDb(
(data ? multiStopParser(data) : []).concat(
subwayBookmarks.map((subwayStop) => {
return {
line: subwayStop.lines[0],
stopName: subwayStop.name,
routeName: subwayStop.name,
etas: [],
stopTag: subwayStop.stopId,
type: subwayStop.type,
};
})
)
);
}
};

return { parsedData: data, error: Error };
};
useEffect(() => {
const controller = new AbortController();
if (fetchUrl.length > 0) {
fetchEtaData().then(({ parsedData, error }) => {
if (error || !parsedData) {
return;
}
setData(parsedData);
setLastUpdatedAt(Date.now());
if (unifiedEtaValue) {
setUnifiedEtaDb(multiStopUnifier(parsedData, stopBookmarks));
} else {
setSingleEtaDb(multiStopParser(parsedData));
getTTCMultiRouteData(controller, fetchUrl).then(
({ parsedData, error }) => {
if (error || !parsedData) {
return;
}
setData(parsedData);
setLastUpdatedAt(Date.now());
setEtaDb(parsedData);
}
});
);
} else {
setEtaDb();
}

// when useEffect is called, the following clean-up fn will run first
Expand All @@ -88,26 +113,40 @@ export default function FavouriteEta() {
const EtaCards = [];
if (unifiedEtaValue) {
for (const item of unifiedEtaDb) {
if (item.etas.length > 0) {
if (
item.etas.length > 0 ||
(item.type === "ttc-subway" && item.enabled?.length)
) {
const id = item.stopId;

const name =
item.type === "ttc-subway" && id
? subwayDbSelectors.selectById(store.getState().subwayDb, id)?.stop
?.name ?? item.name
: item.name;

EtaCards.push(
<EtaCard
enabled={item.enabled}
key={id}
id={id.toString()}
etas={item.etas}
lines={item.enabled ? item.enabled : item.lines}
name={item.name}
name={name}
editable={false}
onDelete={undefined}
stopUrl={`/stops/${id}`}
stopUrl={
item.type === "ttc-subway"
? `/ttc/lines/${item.lines[0]}/${item.stopId}`
: `/stops/${id}`
}
/>
);
}
}
} else {
for (const item of singleEtaDb) {
if (item.etas.length > 0) {
if (item.etas.length > 0 || item.type === "ttc-subway") {
const id = `${item.line}-${item.stopTag}`;
EtaCards.push(<BookmarkCardEta item={item} key={id} />);
}
Expand Down
24 changes: 22 additions & 2 deletions src/components/fetch/FetchSubwayRoute.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@ import { Link as LinkFluent, Text, Title1 } from "@fluentui/react-components";
import { useCallback, useEffect, useState } from "react";
import { useTranslation } from "react-i18next";

import { SubwayStations } from "../../models/ttc.js";
import { SubwayStations, SubwayStopInfo } from "../../models/ttc.js";
import { useAppDispatch } from "../../store/index.js";
import { addStop } from "../../store/suwbayDb/slice.js";
import { SubwayAccordions } from "../accordions/SubwayAccordions.js";
import RawDisplay from "../rawDisplay/RawDisplay.js";
import styles from "./FetchSubwayRoute.module.css";
Expand All @@ -14,6 +16,8 @@ function RouteInfo(props: { line: number }): JSX.Element {
const [lastUpdatedAt, setLastUpdatedAt] = useState<number>(Date.now());
const { t } = useTranslation();

const dispatch = useAppDispatch();

useEffect(() => {
const controller = new AbortController();

Expand All @@ -22,9 +26,25 @@ function RouteInfo(props: { line: number }): JSX.Element {
return response;
};

const setSubwayDb = (subwayApiRes: SubwayStopInfo[]) => {
subwayApiRes
.filter((element) => element.routeBranch.headsign)
.forEach((route) => {
route.routeBranchStops.forEach((stop) => {
dispatch(
addStop({
id: parseInt(stop.code),
stop,
})
);
});
});
};

if (lineNum !== 3) {
fetchSubwayData().then((res) => {
fetchSubwayData().then((res: SubwayStations) => {
try {
setSubwayDb(res.routeBranchesWithStops);
setData(res);
} catch (error) {
setData({ routeBranchesWithStops: [], Error: true });
Expand Down
36 changes: 31 additions & 5 deletions src/components/fetch/FetchSubwayStop.tsx
Original file line number Diff line number Diff line change
@@ -1,14 +1,17 @@
import { Button, LargeTitle, Text } from "@fluentui/react-components";
import { Button, LargeTitle, Text, Title1 } from "@fluentui/react-components";
import { ArrowClockwise24Regular } from "@fluentui/react-icons";
import { useCallback, useEffect, useState } from "react";
import { useTranslation } from "react-i18next";

import { SubwayStop } from "../../models/ttc.js";
import { store } from "../../store/index.js";
import { subwayDbSelectors } from "../../store/suwbayDb/slice.js";
import { BookmarkButton } from "../bookmarks/BookmarkButton.js";
import { CountdownSec } from "../countdown/CountdownSec.js";
import RawDisplay from "../rawDisplay/RawDisplay.js";
import { getTTCSubwayPredictions } from "./fetchUtils.js";

function LineStopPredictionInfo(props: {
function SubwayStopPredictionInfo(props: {
line: number;
stopNum: number;
}): JSX.Element {
Expand Down Expand Up @@ -37,6 +40,11 @@ function LineStopPredictionInfo(props: {
);
}

const stationName = subwayDbSelectors.selectById(
store.getState().subwayDb,
props.stopNum
);

if (data !== undefined) {
if (data.Error !== undefined) {
return <LargeTitle>{t("reminder.failToLocate")}</LargeTitle>;
Expand All @@ -53,9 +61,18 @@ function LineStopPredictionInfo(props: {
});
return (
<div className="directionsList list">
<LargeTitle>{data.directionText}</LargeTitle>
<Title1>{stationName.stop.name.split(" - ")[0]}</Title1>
<br />
<Title1>{data.directionText}</Title1>
<div className="countdown-row">
<RefreshButton />
<BookmarkButton
stopId={props.stopNum}
name={data.directionText}
ttcId={props.stopNum}
lines={[props.line.toString()]}
type="ttc-subway"
/>
</div>
{listGroup}
<RawDisplay data={data} />
Expand All @@ -64,9 +81,18 @@ function LineStopPredictionInfo(props: {
} else {
return (
<div className="directionsList list">
<LargeTitle>{data.directionText}</LargeTitle>
<Title1>{stationName.stop.name.split(" - ")[0]}</Title1>
<br />
<Title1>{data.directionText}</Title1>
<div className="countdown-row">
<RefreshButton />
<BookmarkButton
stopId={props.stopNum}
name={data.directionText}
ttcId={props.stopNum}
lines={[props.line.toString()]}
type="ttc-subway"
/>
</div>
<Text> {t("reminder.noEta")}</Text>
<RawDisplay data={data} />
Expand All @@ -83,4 +109,4 @@ function LineStopPredictionInfo(props: {
);
}
}
export default LineStopPredictionInfo;
export default SubwayStopPredictionInfo;
Loading

0 comments on commit 7aaf0e0

Please sign in to comment.