Skip to content

Commit

Permalink
iteration
Browse files Browse the repository at this point in the history
  • Loading branch information
thomassth committed Feb 18, 2025
1 parent e8f3b7f commit 10e13d7
Show file tree
Hide file tree
Showing 5 changed files with 99 additions and 57 deletions.
28 changes: 28 additions & 0 deletions src/components/alerts/TtcAlertList.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import { useQuery } from "@tanstack/react-query";

import { ttcAlerts } from "../fetch/queries.js";
import { SkeetList } from "./SkeetList.js";

export function TtcAlertList({ lineNum }: { lineNum: number[] }) {
const bskyAlerts = useQuery(ttcAlerts);

const filteredBskyAlerts =
bskyAlerts.data?.feed.filter(
(skeet: { post: { record: { text: string } } }) =>
lineNum.some((line) => {
return line < 6
? skeet.post.record.text.match(`Line ${line}`)
: skeet.post.record.text.startsWith(`${line}`);
})
) ?? [];
return (
<>
{filteredBskyAlerts.length > 0 && (
<SkeetList
skeetList={filteredBskyAlerts}
line={lineNum.length > 1 ? "all" : `${lineNum[0]}`}
/>
)}
</>
);
}
84 changes: 46 additions & 38 deletions src/components/fetch/FetchStop.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
import { Button, Title1 } from "@fluentui/react-components";
import { ArrowClockwise24Regular } from "@fluentui/react-icons";
import { useQuery } from "@tanstack/react-query";
import { useCallback, useEffect, useState } from "react";
import { useTranslation } from "react-i18next";

import { EtaPredictionJson } from "../../models/etaJson.js";
import { EtaBusWithID, LineStopEta } from "../../models/etaObjects.js";
import { store } from "../../store/index.js";
import { settingsSelectors } from "../../store/settings/slice.js";
import { TtcAlertList } from "../alerts/TtcAlertList.js";
import { DirectionBadge } from "../badges.js";
import { BookmarkButton } from "../bookmarks/BookmarkButton.js";
import CountdownGroup from "../countdown/CountdownGroup.js";
Expand All @@ -15,15 +17,32 @@ import SMSButton from "../eta/SMSButton.js";
import { etaParser } from "../parser/etaParser.js";
import RawDisplay from "../rawDisplay/RawDisplay.js";
import style from "./FetchStop.module.css";
import { getStopPredictions } from "./fetchUtils.js";
import { ttcStops } from "./queries.js";

function RefreshButton({
handleRefreshClick,
}: {
handleRefreshClick: () => void;
}) {
const { t } = useTranslation();

return (
<Button onClick={handleRefreshClick} icon={<ArrowClockwise24Regular />}>
{t("buttons.refresh")}
</Button>
);
}
function StopPredictionInfo(props: { stopId: number }): JSX.Element {
const [data, setData] = useState<EtaPredictionJson>();
const [stopId] = useState(props.stopId);
const stopId = props.stopId;
const [etaDb, setEtaDb] = useState<LineStopEta[]>([]);
const [lastUpdatedAt, setLastUpdatedAt] = useState<number>(Date.now());
const { t } = useTranslation();
const [unifiedEta, setUnifiedEta] = useState<EtaBusWithID[]>([]);
const [lineList, setLineList] = useState<number[]>([]);
const ttcStopPrediction = useQuery<EtaPredictionJson, Error>({
...ttcStops(stopId),
queryKey: [`ttc-stop-${stopId}`, lastUpdatedAt.toString()],
});

const handleRefreshClick = useCallback(() => {
setLastUpdatedAt(Date.now());
Expand All @@ -33,40 +52,28 @@ function StopPredictionInfo(props: { stopId: number }): JSX.Element {
settingsSelectors.selectById(store.getState().settings, "unifiedEta")
?.value === "true";

function RefreshButton() {
return (
<Button onClick={handleRefreshClick} icon={<ArrowClockwise24Regular />}>
{t("buttons.refresh")}
</Button>
);
}

useEffect(() => {
const controller = new AbortController();
if (ttcStopPrediction.data) {
setEtaDb(etaParser(ttcStopPrediction.data));
}
}, [ttcStopPrediction]);

getStopPredictions(stopId, { signal: controller.signal }).then((data) => {
if (data) {
setData(data);
setEtaDb(etaParser(data));
useEffect(() => {
setLineList([
...new Set(etaDb.map((item) => parseInt(item.line.toString()))),
]);
if (unifiedEtaValue) {
let templist: EtaBusWithID[] = [];
for (const list of etaDb) {
templist = templist.concat(list.etas ?? []);
}
});

// when useEffect is called, the following clean-up fn will run first
return () => {
controller.abort();
};
}, [lastUpdatedAt]);

useEffect(() => {
let templist: EtaBusWithID[] = [];
for (const list of etaDb) {
templist = templist.concat(list.etas ?? []);
setUnifiedEta(templist.sort((a, b) => a.epochTime - b.epochTime));
}
setUnifiedEta(templist.sort((a, b) => a.epochTime - b.epochTime));
}, [etaDb]);
}, [etaDb, unifiedEtaValue]);

if (data) {
if (data.Error === undefined) {
if (ttcStopPrediction.data) {
if (ttcStopPrediction.data.Error === undefined) {
let listContent: JSX.Element[] = [];
if (unifiedEtaValue) {
listContent = unifiedEta.map((element, index) => {
Expand Down Expand Up @@ -96,6 +103,7 @@ function StopPredictionInfo(props: { stopId: number }): JSX.Element {
});
return (
<div className="countdown-list-container">
<TtcAlertList lineNum={lineList} />
{etaDb[0] && (
<>
<span className={style["top-row"]}>
Expand All @@ -114,7 +122,7 @@ function StopPredictionInfo(props: { stopId: number }): JSX.Element {
</>
)}
<div className="countdown-button-group">
<RefreshButton />
<RefreshButton handleRefreshClick={handleRefreshClick} />
{etaDb[0] && (
<BookmarkButton
stopId={stopId}
Expand All @@ -137,7 +145,7 @@ function StopPredictionInfo(props: { stopId: number }): JSX.Element {
<SMSButton stopId={stopId} />
</>
)}
<RawDisplay data={data} />
<RawDisplay data={ttcStopPrediction.data} />
</div>
);
} else {
Expand All @@ -146,18 +154,18 @@ function StopPredictionInfo(props: { stopId: number }): JSX.Element {
<div>
<Title1>{t("reminder.failToLocate")}</Title1>
<div className="countdown-button-group">
<RefreshButton />
<RefreshButton handleRefreshClick={handleRefreshClick} />
<SMSButton stopId={stopId} />
</div>
<span>{data.Error["#text"]}</span>
<RawDisplay data={data} />
<span>{ttcStopPrediction.data.Error["#text"]}</span>
<RawDisplay data={ttcStopPrediction.data} />
</div>
);
}
} else {
return (
<div>
{navigator.onLine ? (
{ttcStopPrediction.status === "pending" ? (
<Title1>{t("reminder.loading")}</Title1>
) : (
<>
Expand All @@ -167,7 +175,7 @@ function StopPredictionInfo(props: { stopId: number }): JSX.Element {
</>
)}
<div className="countdown-button-group">
<RefreshButton />
<RefreshButton handleRefreshClick={handleRefreshClick} />
<SMSButton stopId={stopId} />
</div>
</div>
Expand Down
2 changes: 2 additions & 0 deletions src/components/fetch/FetchSubwayStop.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ 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 { TtcAlertList } from "../alerts/TtcAlertList.js";
import { BookmarkButton } from "../bookmarks/BookmarkButton.js";
import { CountdownSec } from "../countdown/CountdownSec.js";
import RawDisplay from "../rawDisplay/RawDisplay.js";
Expand Down Expand Up @@ -75,6 +76,7 @@ function SubwayStopPredictionInfo(props: {
</>
)}
<Title1>{data.directionText}</Title1>
<TtcAlertList lineNum={[props.line]} />
<div className="countdown-row">
<RefreshButton onRefresh={fetchPredictionClick} />
<BookmarkButton
Expand Down
24 changes: 21 additions & 3 deletions src/components/fetch/queries.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
// import GtfsRealtimeBindings from "gtfs-realtime-bindings";
import { queryOptions } from "@tanstack/react-query";

export const ttcAlerts = {
export const ttcAlerts = queryOptions({
queryKey: ["bsky"],
queryFn: async () => {
const response = await fetch(
Expand All @@ -14,9 +15,26 @@ export const ttcAlerts = {
},
staleTime: 60 * 1000,
refetchInterval: 60 * 1000,
});

export const ttcStops = (stopId: number) => {
return {
queryKey: [`ttc-stop-${stopId}`],
queryFn: async () => {
const response = await fetch(
`https://webservices.umoiq.com/service/publicJSONFeed?command=predictions&a=ttc&stopId=${stopId}`
);
if (!response.ok) {
throw new Error("Network response was not ok");
}

return response.json();
},
placeholderData: (prev: any) => prev,
};
};

export const ttcLines = {
export const ttcLines = queryOptions({
queryKey: ["ttc-lines"],
queryFn: async () => {
const response = await fetch(
Expand All @@ -30,7 +48,7 @@ export const ttcLines = {
},
staleTime: 24 * 60 * 60 * 1000,
refetchInterval: 60 * 1000,
};
});

// inaccessible; CORS Missing Allow Origin
// export const ttcGtfsAlerts = {
Expand Down
18 changes: 2 additions & 16 deletions src/routes/Line.tsx
Original file line number Diff line number Diff line change
@@ -1,39 +1,25 @@
import { Accordion, Title1 } from "@fluentui/react-components";
import { useQuery } from "@tanstack/react-query";
import { useEffect } from "react";
import { useTranslation } from "react-i18next";
import { useParams } from "react-router-dom";

import { SkeetList } from "../components/alerts/SkeetList.js";
import { TtcAlertList } from "../components/alerts/TtcAlertList.js";
import RouteInfo from "../components/fetch/FetchRoute.js";
import SubwayRouteInfo from "../components/fetch/FetchSubwayRoute.js";
import { ttcAlerts } from "../components/fetch/queries.js";

export default function Line() {
const params = useParams();
const { t } = useTranslation();

const lineNum = parseInt(`${params.lineId}`);

const bskyAlerts = useQuery(ttcAlerts);

const filteredBskyAlerts =
bskyAlerts.data?.feed.filter(
(skeet: { post: { record: { text: string } } }) =>
lineNum < 6
? skeet.post.record.text.match(`Line ${lineNum}`)
: skeet.post.record.text.startsWith(`${lineNum}`)
) ?? [];

useEffect(() => {
document.title = t("lines.browserTitle", { lineNum });
});

return (
<main className="line-page">
{filteredBskyAlerts.length > 0 && (
<SkeetList skeetList={filteredBskyAlerts} line={`${lineNum}`} />
)}
<TtcAlertList lineNum={[lineNum]} />
<Title1>{t("lines.number", { lineNum })}</Title1>
<Accordion defaultOpenItems collapsible>
{lineNum < 6 && <SubwayRouteInfo line={lineNum} />}
Expand Down

0 comments on commit 10e13d7

Please sign in to comment.