Files
carrramba-encore-rate/frontend/src/passagesDisplay.tsx

180 lines
5.0 KiB
TypeScript

import { Component, createEffect, createSignal, useContext } from "solid-js";
import { createStore } from "solid-js/store";
import { createDateNow } from "@solid-primitives/date";
import { format } from "date-fns";
import { BusinessDataContext } from "./businessData";
import { SearchContext } from "./search";
import { PassagesPanel } from "./passagesPanel";
import { getTransportModeSrc } from "./utils";
import styles from "./passagesDisplay.module.css";
export const PassagesDisplay: Component = () => {
const maxPassagePerPanel = 5;
const syncPeriodMsec = 20 * 1000;
const { passages, getLine, getLinePassages, refreshPassages, clearPassages } = useContext(BusinessDataContext);
// TODO: Use props instead
const { getDisplayedStops } = useContext(SearchContext);
const [displayedPanelId, setDisplayedPanelId] = createSignal<number>(0);
const [panels, setPanels] = createStore([]);
const [dateNow] = createDateNow(1000);
setInterval(() => {
let nextPanelId = displayedPanelId() + 1;
if (nextPanelId >= panels.length) {
nextPanelId = 0;
}
setDisplayedPanelId(nextPanelId);
}, 4000);
createEffect(() => {
console.log("######### onStopIdUpdate #########");
// Track local.stopIp to force dependency.
console.log("getDisplayedStop=", getDisplayedStops());
clearPassages();
});
createEffect(async () => {
console.log(`## OnPassageUpdate ${passages()} ##`);
const stops = getDisplayedStops();
if (stops.length > 0) {
refreshPassages(stops[0].id);
}
});
setInterval(
async () => {
const stops = getDisplayedStops();
if (stops.length > 0) {
refreshPassages(stops[0].id);
}
},
syncPeriodMsec
);
// TODO: Sort transport modes by weight
const Header: Component = (props) => {
const computeTransportModes = async (lineIds: Array<number>) => {
const lines = await Promise.all(lineIds.map((lineId) => getLine(lineId)));
return new Set(lines.map((line) => getTransportModeSrc(line.transportMode, false)));
}
const [linesIds, setLinesIds] = createSignal([]);
const [transportModeUrls] = createResource(linesIds, computeTransportModes);
createEffect(() => {
setLinesIds(Object.keys(props.passages));
});
return (
<div class={styles.header}>
<Show when={transportModeUrls() !== undefined} >
<For each={Array.from(transportModeUrls())}>
{(url) =>
<div class={styles.transportMode}>
<img src={url} />
</div>
}
</For>
</Show>
<div class={styles.title}>
<svg viewbox="0 0 1260 50">
<text x="0" y="50%" dominant-baseline="middle" font-size="50" style="fill: #ffffff">
{props.title}
</text>
</svg>
</div>
<div class={styles.clock}>
<svg viewbox="0 0 115 43">
<text x="50%" y="55%" dominant-baseline="middle" text-anchor="middle" font-size="43" style="fill: #ffffff">
{format(dateNow(), "HH:mm")}
</text>
</svg>
</div>
</div >
);
};
const Footer: Component = (props) => {
return (
<div class={styles.footer}>
<For each={props.panels}>
{(positioned) => {
const { position } = positioned;
return (
<div>
<svg viewBox="0 0 29 29">
<circle cx="50%" cy="50%" r="13" stroke="#ffffff" stroke-width="3"
style={{ fill: `var(--idfm-${position == displayedPanelId() ? "white" : "black"})` }}
/>
</svg>
</div>
);
}}
</For>
</div>
);
}
return (
<div class={styles.passagesDisplay}>
<Header title="Prochains passages" passages={passages()} />
<div class={styles.panelsContainer}>
{() => {
setPanels([]);
let newPanels = [];
let positioneds = [];
let index = 0;
let chunk = {};
let chunkSize = 0;
console.log("passages=", passages());
for (const lineId of Object.keys(passages())) {
console.log("lineId=", lineId);
const byLinePassages = getLinePassages(lineId);
console.log("byLinePassages=", byLinePassages);
const byLinePassagesKeys = Object.keys(byLinePassages);
console.log("byLinePassagesKeys=", byLinePassagesKeys);
if (byLinePassagesKeys.length <= maxPassagePerPanel - chunkSize) {
chunk[lineId] = byLinePassages;
chunkSize += byLinePassagesKeys.length;
}
else {
const [store] = createStore(chunk);
const panelid = index++;
const panel = <PassagesPanel show={panelid == displayedPanelId()} passages={store} />;
newPanels.push(panel);
positioneds.push({ position: panelid, panel });
chunk = {};
chunk[lineId] = byLinePassages;
chunkSize = byLinePassagesKeys.length;
}
}
if (chunkSize) {
const panelId = index++;
const [store] = createStore(chunk);
const panel = <PassagesPanel show={panelId == displayedPanelId()} passages={store} />;
newPanels.push(panel);
positioneds.push({ position: panelId, panel });
}
setPanels(positioneds);
return newPanels;
}}
</div>
<Footer panels={panels} />
</div>
);
};