From b8984e455c05d33652ffa9da6e5d24bc509c292d Mon Sep 17 00:00:00 2001 From: Adrien Date: Mon, 23 Jan 2023 21:16:47 +0100 Subject: [PATCH 1/8] =?UTF-8?q?=F0=9F=9A=9A=20Add=20a=20dedicated=20CSS=20?= =?UTF-8?q?file=20for=20NextPassagePanel=20component?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- frontend/src/nextPassagePanel.module.css | 128 +++++++++++++++++++ frontend/src/nextPassagesDisplay.module.css | 130 -------------------- frontend/src/nextPassagesPanel.tsx | 3 +- 3 files changed, 129 insertions(+), 132 deletions(-) create mode 100644 frontend/src/nextPassagePanel.module.css diff --git a/frontend/src/nextPassagePanel.module.css b/frontend/src/nextPassagePanel.module.css new file mode 100644 index 0000000..91cb046 --- /dev/null +++ b/frontend/src/nextPassagePanel.module.css @@ -0,0 +1,128 @@ +.nextPassagesContainer { + height: 100%; + width: 100%; + + display: none; + + position: relative; +} + +.displayed { + display: block; +} + +.nextPassagesContainer .line:last-child { + border-bottom: 0; + /* To make up for the bottom border deletion */ + padding-bottom: calc(2px); +} + +/* Idfm: 1880x176px (margin: 0px 20px) */ +.line { + width: calc(1880/1920*100%); + height: calc(100% / 5); + margin: 0 calc(20/1920*100%); + + display: flex; + align-items: center; + + /* TODO: compute the border weight according to the parent height */ + /* TODO: Disable border-bottom for the last .line */ + border-bottom: solid calc(2px); +} + +.line svg { + font-family: IDFVoyageur-bold; + max-width: 100%; + max-height: 100%; +} + +/* Idfm: 100x100px (margin: 0px 15px) */ +.transportMode { + aspect-ratio : 1 / 1; + height: calc(100/176*100%); + margin: 0 calc(15/1920*100%); +} + +.tramLinePicto { + aspect-ratio : 1 / 1; + height: calc(100/176*100%); + margin-right: calc(23/1920*100%); +} + +.busLinePicto { + aspect-ratio : 2.25; + height: calc(70/176*100%); + margin-right: calc(23/1920*100%); +} + +.destination { + height: calc(60/176*100%); + width: 50%; + + font-family: IDFVoyageur-bold; + text-align: left; +} + + +.trafficStatus { + height: calc(50/176*100%); + aspect-ratio: 35/50; + margin-left: auto; + + display: flex; + align-items: center; + justify-content: center; +} + +.trafficStatus svg { + width: 100%; +} + +.firstPassage { + height: calc(100/176*100%); + aspect-ratio: 2.5; + + display: flex; + align-items: center; + justify-content: center; + + padding-right: calc(30/1920*100%); + + /* TODO: compute the border weight according to the parent width */ + border-right: solid calc(5px); +} + +.unavailableFirstPassage { + height: calc(100/176*100%); + aspect-ratio: calc(230/100); + margin-right: calc(30/1920*100%); + + /* TODO: compute the border weight according to the parent width */ + border-right: solid calc(5px); +} + +.firstPassage svg { + aspect-ratio: 215/50; + height: calc(1/2*100%); +} + +.secondPassage { + height: calc(45/176*100%); + aspect-ratio: calc(230/45); + margin-right: calc(30/1920*100%); +} + +.secondPassage svg { + font-family: IDFVoyageur-regular; +} + +.unavailableSecondPassage { + height: calc(100/176*100%); + aspect-ratio: calc(230/100); + margin-right: calc(30/1920*100%); +} + +.unavailableSecondNextPassage svg { + font-family: IDFVoyageur-regular; +} diff --git a/frontend/src/nextPassagesDisplay.module.css b/frontend/src/nextPassagesDisplay.module.css index b24889f..bd13fc9 100644 --- a/frontend/src/nextPassagesDisplay.module.css +++ b/frontend/src/nextPassagesDisplay.module.css @@ -77,136 +77,6 @@ border-radius: calc(15/1920*100%); } -.nextPassagesContainer { - height: 100%; - width: 100%; - - display: none; - - position: relative; -} - -.nextPassagesContainer .line:last-child { - border-bottom: 0; - /* To make up for the bottom border deletion */ - padding-bottom: calc(2px); -} - -.displayed { - display: block; -} - - -/* Idfm: 1880x176px (margin: 0px 20px) */ -.line { - width: calc(1880/1920*100%); - height: calc(100% / 5); - margin: 0 calc(20/1920*100%); - - display: flex; - align-items: center; - - /* TODO: compute the border weight according to the parent height */ - /* TODO: Disable border-bottom for the last .line */ - border-bottom: solid calc(2px); -} - -.line svg { - font-family: IDFVoyageur-bold; - max-width: 100%; - max-height: 100%; -} - -/* Idfm: 100x100px (margin: 0px 15px) */ -.transportMode { - aspect-ratio : 1 / 1; - height: calc(100/176*100%); - margin: 0 calc(15/1920*100%); -} - -.tramLinePicto { - aspect-ratio : 1 / 1; - height: calc(100/176*100%); - margin-right: calc(23/1920*100%); -} - -.busLinePicto { - aspect-ratio : 2.25; - height: calc(70/176*100%); - margin-right: calc(23/1920*100%); -} - -.destination { - height: calc(60/176*100%); - width: 50%; - - font-family: IDFVoyageur-bold; - text-align: left; -} - - -.trafficStatus { - height: calc(50/176*100%); - aspect-ratio: 35/50; - margin-left: auto; - - display: flex; - align-items: center; - justify-content: center; -} - -.trafficStatus svg { - width: 100%; -} - -.firstPassage { - height: calc(100/176*100%); - aspect-ratio: 2.5; - - display: flex; - align-items: center; - justify-content: center; - - padding-right: calc(30/1920*100%); - - /* TODO: compute the border weight according to the parent width */ - border-right: solid calc(5px); -} - -.unavailableFirstPassage { - height: calc(100/176*100%); - aspect-ratio: calc(230/100); - margin-right: calc(30/1920*100%); - - /* TODO: compute the border weight according to the parent width */ - border-right: solid calc(5px); -} - -.firstPassage svg { - aspect-ratio: 215/50; - height: calc(1/2*100%); -} - -.secondPassage { - height: calc(45/176*100%); - aspect-ratio: calc(230/45); - margin-right: calc(30/1920*100%); -} - -.secondPassage svg { - font-family: IDFVoyageur-regular; -} - -.unavailableSecondPassage { - height: calc(100/176*100%); - aspect-ratio: calc(230/100); - margin-right: calc(30/1920*100%); -} - -.unavailableSecondNextPassage svg { - font-family: IDFVoyageur-regular; -} - /* Idfm: 1800x54px (margin: 0px 50px) */ .footer { width: calc(1820/1920*100%); diff --git a/frontend/src/nextPassagesPanel.tsx b/frontend/src/nextPassagesPanel.tsx index 7da6798..598dc75 100644 --- a/frontend/src/nextPassagesPanel.tsx +++ b/frontend/src/nextPassagesPanel.tsx @@ -1,12 +1,11 @@ import { Component } from 'solid-js'; -import { createStore } from 'solid-js/store'; import { createDateNow, getTime } from '@solid-primitives/date'; import { Motion } from "@motionone/solid"; import { TrafficStatus } from './types'; import { renderLineTransportMode, renderLinePicto } from './utils'; -import styles from './nextPassagesDisplay.module.css'; +import styles from "./nextPassagePanel.module.css"; export const NextPassagesPanel: Component = (props) => { From e96e7aeae0f0cde59a5f294db7d795bd5914fabd Mon Sep 17 00:00:00 2001 From: Adrien Date: Mon, 23 Jan 2023 22:34:33 +0100 Subject: [PATCH 2/8] =?UTF-8?q?=F0=9F=9A=9A=20Rename=20NextPassagesDisplay?= =?UTF-8?q?/NextPassagesPanel=20(remove=20Next=20prefix)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- frontend/src/App.tsx | 4 +-- ....module.css => passagesDisplay.module.css} | 2 +- ...assagesDisplay.tsx => passagesDisplay.tsx} | 35 ++++++++----------- ...el.module.css => passagesPanel.module.css} | 6 ++-- ...extPassagesPanel.tsx => passagesPanel.tsx} | 24 ++++++------- 5 files changed, 33 insertions(+), 38 deletions(-) rename frontend/src/{nextPassagesDisplay.module.css => passagesDisplay.module.css} (98%) rename frontend/src/{nextPassagesDisplay.tsx => passagesDisplay.tsx} (88%) rename frontend/src/{nextPassagePanel.module.css => passagesPanel.module.css} (95%) rename frontend/src/{nextPassagesPanel.tsx => passagesPanel.tsx} (79%) diff --git a/frontend/src/App.tsx b/frontend/src/App.tsx index c3083b3..5dad69b 100644 --- a/frontend/src/App.tsx +++ b/frontend/src/App.tsx @@ -6,7 +6,7 @@ import { HopeProvider } from "@hope-ui/solid"; import { BusinessDataProvider } from './businessData'; import { SearchProvider } from './search'; -import { NextPassagesDisplay } from './nextPassagesDisplay'; +import { PassagesDisplay } from './passagesDisplay'; import { StopsManager } from './stopsManager'; import styles from './App.module.css'; @@ -53,7 +53,7 @@ const App: Component = () => {
- +
diff --git a/frontend/src/nextPassagesDisplay.module.css b/frontend/src/passagesDisplay.module.css similarity index 98% rename from frontend/src/nextPassagesDisplay.module.css rename to frontend/src/passagesDisplay.module.css index bd13fc9..c42449b 100644 --- a/frontend/src/nextPassagesDisplay.module.css +++ b/frontend/src/passagesDisplay.module.css @@ -5,7 +5,7 @@ } /* Idfm: 1860x1080px */ -.NextPassagesDisplay { +.PassagesDisplay { aspect-ratio: 16/9; --reverse-aspect-ratio: 9/16; /* height is set according to the aspect-ratio, don´t touch it */ diff --git a/frontend/src/nextPassagesDisplay.tsx b/frontend/src/passagesDisplay.tsx similarity index 88% rename from frontend/src/nextPassagesDisplay.tsx rename to frontend/src/passagesDisplay.tsx index 4706dc1..761ad89 100644 --- a/frontend/src/nextPassagesDisplay.tsx +++ b/frontend/src/passagesDisplay.tsx @@ -5,19 +5,18 @@ import { format } from "date-fns"; import { getTransportModeSrc } from "./types"; import { BusinessDataContext } from "./businessData"; -import { NextPassagesPanel } from "./nextPassagesPanel"; +import { PassagesPanel } from "./passagesPanel"; import { SearchContext } from "./search"; -import styles from "./nextPassagesDisplay.module.css"; +import styles from "./passagesDisplay.module.css"; -export const NextPassagesDisplay: Component = () => { +export const PassagesDisplay: Component = () => { const maxPassagePerPanel = 5; const syncPeriodMsec = 20 * 1000; - const { passages, getLinePassages, addPassages, clearPassages, serverUrl } = - useContext(BusinessDataContext); + const { passages, getLinePassages, addPassages, clearPassages, serverUrl } = useContext(BusinessDataContext); const { getDisplayedStop } = useContext(SearchContext); const [panels, setPanels] = createStore([]); @@ -27,12 +26,11 @@ export const NextPassagesDisplay: Component = () => { const [dateNow] = createDateNow(1000); - const panelSwapInterval = setInterval(() => { + setInterval(() => { let nextPanelId = displayedPanelId() + 1; if (nextPanelId >= panels.length) { nextPanelId = 0; } - /* console.log(`Display panel #${nextPanelId}`); */ setDisplayedPanelId(nextPanelId); }, 4000); @@ -92,7 +90,6 @@ export const NextPassagesDisplay: Component = () => { } setInterval( - // const nextPassagesRequestsInterval = setTimeout( async () => { await requestPassages(); }, @@ -100,7 +97,7 @@ export const NextPassagesDisplay: Component = () => { ); // TODO: Sort transport modes by weight - // TODO: Split this method to isolate the nextPassagesPanel part. + // TODO: Split this method to isolate the passagesPanel part. function _computeHeader(title: string): JSX.Element { let transportModes = []; transportModes = new Set( @@ -184,7 +181,7 @@ export const NextPassagesDisplay: Component = () => { ); } - const mainDivClasses = `${styles.NextPassagesDisplay} ${styles.ar16x9}`; + const mainDivClasses = `${styles.PassagesDisplay} ${styles.ar16x9}`; return (
{_computeHeader("Prochains passages")} @@ -212,14 +209,13 @@ export const NextPassagesDisplay: Component = () => { chunkSize += byLinePassagesKeys.length; } else { console.log("chunk=", chunk); - const [store, setStore] = createStore(chunk); + const [store] = createStore(chunk); const panelid = index++; const panel = ( - + passages={store} + lines={_lines} /> ); newPanels.push(panel); positioneds.push({ position: panelid, panel }); @@ -231,13 +227,12 @@ export const NextPassagesDisplay: Component = () => { } if (chunkSize) { const panelId = index++; - const [store, setStore] = createStore(chunk); + const [store] = createStore(chunk); const panel = ( - + passages={store} + lines={_lines} /> ); newPanels.push(panel); positioneds.push({ position: panelId, panel }); diff --git a/frontend/src/nextPassagePanel.module.css b/frontend/src/passagesPanel.module.css similarity index 95% rename from frontend/src/nextPassagePanel.module.css rename to frontend/src/passagesPanel.module.css index 91cb046..88625e1 100644 --- a/frontend/src/nextPassagePanel.module.css +++ b/frontend/src/passagesPanel.module.css @@ -1,4 +1,4 @@ -.nextPassagesContainer { +.passagesContainer { height: 100%; width: 100%; @@ -11,7 +11,7 @@ display: block; } -.nextPassagesContainer .line:last-child { +.passagesContainer .line:last-child { border-bottom: 0; /* To make up for the bottom border deletion */ padding-bottom: calc(2px); @@ -123,6 +123,6 @@ margin-right: calc(30/1920*100%); } -.unavailableSecondNextPassage svg { +.unavailableSecondPassage svg { font-family: IDFVoyageur-regular; } diff --git a/frontend/src/nextPassagesPanel.tsx b/frontend/src/passagesPanel.tsx similarity index 79% rename from frontend/src/nextPassagesPanel.tsx rename to frontend/src/passagesPanel.tsx index 598dc75..a602efe 100644 --- a/frontend/src/nextPassagesPanel.tsx +++ b/frontend/src/passagesPanel.tsx @@ -5,10 +5,10 @@ import { Motion } from "@motionone/solid"; import { TrafficStatus } from './types'; import { renderLineTransportMode, renderLinePicto } from './utils'; -import styles from "./nextPassagePanel.module.css"; +import styles from "./passagesPanel.module.css"; -export const NextPassagesPanel: Component = (props) => { +export const PassagesPanel: Component = (props) => { /* TODO: Find where to get data to compute traffic status. */ const trafficStatusColor = new Map([ @@ -72,10 +72,10 @@ export const NextPassagesPanel: Component = (props) => { } /* TODO: Manage end of service */ - function _genNextPassages(nextPassages, line, destination) { - const nextPassagesLength = nextPassages.length; - const firstPassage = nextPassagesLength > 0 ? nextPassages[0] : undefined; - const secondPassage = nextPassagesLength > 1 ? nextPassages[1] : undefined; + function _genPassages(passages, line, destination) { + const passagesLength = passages.length; + const firstPassage = passagesLength > 0 ? passages[0] : undefined; + const secondPassage = passagesLength > 1 ? passages[1] : undefined; const trafficStatusStyle = { fill: trafficStatusColor.get(line.trafficStatus) }; return (
@@ -102,15 +102,15 @@ export const NextPassagesPanel: Component = (props) => { } return ( -
+
{() => { const ret = []; - for (const lineId of Object.keys(props.nextPassages)) { + for (const lineId of Object.keys(props.passages)) { const line = props.lines.get(lineId); - const byLineNextPassages = props.nextPassages[lineId]; - for (const destination of Object.keys(byLineNextPassages)) { - const nextPassages = byLineNextPassages[destination]; - ret.push(_genNextPassages(nextPassages, line, destination)); + const byLinePassages = props.passages[lineId]; + for (const destination of Object.keys(byLinePassages)) { + const passages = byLinePassages[destination]; + ret.push(_genPassages(passages, line, destination)); } } return ret; From 495b2bafe21dcfa5f316cb6098267014966af033 Mon Sep 17 00:00:00 2001 From: Adrien Date: Mon, 23 Jan 2023 22:50:29 +0100 Subject: [PATCH 3/8] =?UTF-8?q?=F0=9F=94=A5=20Remove=20ar16x9=20CSS=20clas?= =?UTF-8?q?s?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- frontend/src/passagesDisplay.module.css | 8 +------- frontend/src/passagesDisplay.tsx | 3 +-- frontend/src/passagesPanel.module.css | 1 + 3 files changed, 3 insertions(+), 9 deletions(-) diff --git a/frontend/src/passagesDisplay.module.css b/frontend/src/passagesDisplay.module.css index c42449b..49f0e39 100644 --- a/frontend/src/passagesDisplay.module.css +++ b/frontend/src/passagesDisplay.module.css @@ -1,11 +1,5 @@ - -/* TODO: Remove this class */ -.ar16x9 { - aspect-ratio: 16 / 9; -} - /* Idfm: 1860x1080px */ -.PassagesDisplay { +.passagesDisplay { aspect-ratio: 16/9; --reverse-aspect-ratio: 9/16; /* height is set according to the aspect-ratio, don´t touch it */ diff --git a/frontend/src/passagesDisplay.tsx b/frontend/src/passagesDisplay.tsx index 761ad89..a0f3737 100644 --- a/frontend/src/passagesDisplay.tsx +++ b/frontend/src/passagesDisplay.tsx @@ -181,9 +181,8 @@ export const PassagesDisplay: Component = () => { ); } - const mainDivClasses = `${styles.PassagesDisplay} ${styles.ar16x9}`; return ( -
+
{_computeHeader("Prochains passages")}
{() => { diff --git a/frontend/src/passagesPanel.module.css b/frontend/src/passagesPanel.module.css index 88625e1..0637557 100644 --- a/frontend/src/passagesPanel.module.css +++ b/frontend/src/passagesPanel.module.css @@ -11,6 +11,7 @@ display: block; } +/* TODO: Remove the bottom border only if there are 5 displayed lines. */ .passagesContainer .line:last-child { border-bottom: 0; /* To make up for the bottom border deletion */ From cc5205c3188c1dacee0168bcb66f6655a2973874 Mon Sep 17 00:00:00 2001 From: Adrien Date: Fri, 27 Jan 2023 20:20:17 +0100 Subject: [PATCH 4/8] =?UTF-8?q?=F0=9F=90=9B=20Fix=20PassageDisplay=20foote?= =?UTF-8?q?r=20bullets=20behavior?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The bullets was not updated according to the displayed panel. --- frontend/src/passagesDisplay.tsx | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/frontend/src/passagesDisplay.tsx b/frontend/src/passagesDisplay.tsx index a0f3737..bc03a34 100644 --- a/frontend/src/passagesDisplay.tsx +++ b/frontend/src/passagesDisplay.tsx @@ -3,12 +3,12 @@ import { createStore } from "solid-js/store"; import { createDateNow } from "@solid-primitives/date"; import { format } from "date-fns"; -import { getTransportModeSrc } from "./types"; import { BusinessDataContext } from "./businessData"; -import { PassagesPanel } from "./passagesPanel"; - import { SearchContext } from "./search"; +import { PassagesPanel } from "./passagesPanel"; +import { getTransportModeSrc } from "./utils"; + import styles from "./passagesDisplay.module.css"; @@ -156,11 +156,7 @@ export const PassagesDisplay: Component = () => {
{(positioned) => { - const { position, panel } = positioned; - const circleStyle = { - fill: `var(--idfm-${position == displayedPanelId() ? "white" : "black" - })`, - }; + const { position } = positioned; return (
@@ -170,7 +166,9 @@ export const PassagesDisplay: Component = () => { r="13" stroke="#ffffff" stroke-width="3" - style={circleStyle} + style={{ + fill: `var(--idfm-${position == displayedPanelId() ? "white" : "black"})`, + }} />
From 207fe128421c202d5e1885fbd8c59cd4314aa5b3 Mon Sep 17 00:00:00 2001 From: Adrien Date: Fri, 27 Jan 2023 20:23:43 +0100 Subject: [PATCH 5/8] =?UTF-8?q?=F0=9F=9A=9A=20Move=20utils=20function=20fr?= =?UTF-8?q?om=20types.tsx=20to=20utils.tsx?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- frontend/src/types.tsx | 10 ---------- frontend/src/utils.tsx | 11 ++++++++++- 2 files changed, 10 insertions(+), 11 deletions(-) diff --git a/frontend/src/types.tsx b/frontend/src/types.tsx index 73607c0..9428eca 100644 --- a/frontend/src/types.tsx +++ b/frontend/src/types.tsx @@ -1,13 +1,3 @@ -const validTransportModes = ["bus", "tram", "metro", "rer", "transilien", "funicular", "ter", "unknown"]; - -export function getTransportModeSrc(mode: string, color: bool = true): string { - let ret = null; - if (validTransportModes.includes(mode)) { - ret = `/public/symbole_${mode}_${color ? "" : "support_fonce_"}RVB.svg`; - } - return ret; -} - export enum TrafficStatus { UNKNOWN = 0, FLUID, diff --git a/frontend/src/utils.tsx b/frontend/src/utils.tsx index 64b9558..ac810be 100644 --- a/frontend/src/utils.tsx +++ b/frontend/src/utils.tsx @@ -1,4 +1,4 @@ -import { getTransportModeSrc } from './types'; +const validTransportModes = ["bus", "tram", "metro", "rer", "transilien", "funicular", "ter", "unknown"]; export const TransportModeWeights = { bus: 1, @@ -15,6 +15,15 @@ export function renderLineTransportMode(line): JSX.Element { return } +export function getTransportModeSrc(mode: string, color: bool = true): string { + let ret = null; + if (validTransportModes.includes(mode)) { + ret = `/public/symbole_${mode}_${color ? "" : "support_fonce_"}RVB.svg`; + } + return ret; +} + + function renderBusLinePicto(line, styles): JSX.Element { return (
From e141aa15e5ac1154936aae2cb0990a6f53051563 Mon Sep 17 00:00:00 2001 From: Adrien Date: Sat, 28 Jan 2023 16:18:55 +0100 Subject: [PATCH 6/8] =?UTF-8?q?=F0=9F=9A=9A=20Remove=20business=20logic=20?= =?UTF-8?q?from=20Component=20instances?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- frontend/src/businessData.tsx | 53 ++++++++++++++-------- frontend/src/passagesDisplay.tsx | 65 ++++++--------------------- frontend/src/search.tsx | 75 +++++++++++++------------------- frontend/src/stopsManager.tsx | 40 +++++------------ 4 files changed, 91 insertions(+), 142 deletions(-) diff --git a/frontend/src/businessData.tsx b/frontend/src/businessData.tsx index 8e6e617..7f8eec1 100644 --- a/frontend/src/businessData.tsx +++ b/frontend/src/businessData.tsx @@ -35,44 +35,59 @@ export function BusinessDataProvider(props: { children: JSX.Element }) { return line; } - const passages = () => { - return store.passages; - }; - const getLinePassages = (lineId: string) => { return store.passages[lineId]; }; + const passages = () => { + return store.passages; + } + + const refreshPassages = async (stopId: number) => { + const httpOptions = { headers: { "Content-Type": "application/json" } }; + console.log(`Fetching data for ${stopId}`); + const data = await fetch(`${serverUrl()}/stop/nextPassages/${stopId}`, httpOptions); + const response = await data.json(); + addPassages(response.passages); + } + const addPassages = (passages) => { setStore((s) => { - // console.log("s=", s); setStore('passages', passages); - // console.log("s=", s); }); } const clearPassages = () => { setStore((s) => { - // TODO: Really need to set to undefined to reset ? - console.log("s=", s); - console.log("s.passages=", s.passages); - // setStore('passages', undefined); - // setStore('passages', {}); - console.log("Object.keys(s.passages)=", Object.keys(s.passages)); for (const lineId of Object.keys(s.passages)) { - console.log("lineId=", lineId); setStore('passages', lineId, undefined); } - console.log("s=", s); }); - // setStore('passages', undefined); - // setStore('passages', {}); - // } - console.log("passages=", store.passages); + } + + const getStop = (stopId: int) => { + return store.stops[stopId]; + } + + const searchStopByName = async (name: string) => { + const data = await fetch(`${serverUrl()}/stop/?name=${name}`, { + headers: { 'Content-Type': 'application/json' } + }); + const stops = await data.json(); + + const byIdStops = {}; + for (const stop of stops) { + byIdStops[stop.id] = stop; + setStore('stops', stop.id, stop); + } + return byIdStops; } return ( - + {props.children} ); diff --git a/frontend/src/passagesDisplay.tsx b/frontend/src/passagesDisplay.tsx index bc03a34..9882623 100644 --- a/frontend/src/passagesDisplay.tsx +++ b/frontend/src/passagesDisplay.tsx @@ -16,13 +16,13 @@ export const PassagesDisplay: Component = () => { const maxPassagePerPanel = 5; const syncPeriodMsec = 20 * 1000; - const { passages, getLinePassages, addPassages, clearPassages, serverUrl } = useContext(BusinessDataContext); - const { getDisplayedStop } = useContext(SearchContext); + const { passages, getLine, getLinePassages, refreshPassages, clearPassages } = useContext(BusinessDataContext); + + // TODO: Use props instead + const { getDisplayedStops } = useContext(SearchContext); - const [panels, setPanels] = createStore([]); const [displayedPanelId, setDisplayedPanelId] = createSignal(0); - - let _lines = new Map(); + const [panels, setPanels] = createStore([]); const [dateNow] = createDateNow(1000); @@ -37,61 +37,24 @@ export const PassagesDisplay: Component = () => { createEffect(() => { console.log("######### onStopIdUpdate #########"); // Track local.stopIp to force dependency. - console.log("getDisplayedStop=", getDisplayedStop()); + console.log("getDisplayedStop=", getDisplayedStops()); clearPassages(); }); createEffect(async () => { console.log(`## OnPassageUpdate ${passages()} ##`); - /* console.log(passages()); */ - await requestPassages(); + const stops = getDisplayedStops(); + if (stops.length > 0) { + refreshPassages(stops[0].id); + } }); - async function _fetchLine(lineId: string) { - if (!_lines.has(lineId)) { - const data = await fetch(`${serverUrl()}/line/${lineId}`, { - headers: { "Content-Type": "application/json" }, - }); - const line = await data.json(); - _lines.set(line.id, line); - } - } - - async function requestPassages() { - console.log("### requestPassages ###"); - /* TODO: Manage several displays (one by stop) */ - const stops = getDisplayedStop(); - if (stops.length == 0) { - return; - } - const stop = stops[0]; - - const httpOptions = { headers: { "Content-Type": "application/json" } }; - if (stop !== undefined) { - const stopId = stop.id; - console.log(`Fetching data for ${stopId}`); - const url = `${serverUrl()}/stop/nextPassages/${stopId}`; - /* console.log(`url=${url}`); */ - const data = await fetch(url, httpOptions); - const response = await data.json(); - /* console.log(response); */ - const byLineByDstPassages = response.passages; - /* console.log(byLineByDstPassages); */ - const linePromises = []; - for (const lineId of Object.keys(byLineByDstPassages)) { - linePromises.push(_fetchLine(lineId)); - } - await Promise.all(linePromises); - console.log("byLineByDstPassages=", byLineByDstPassages); - // console.log("before addPassages passages=", passages()); - addPassages(byLineByDstPassages); - console.log("AFTER passages=", passages()); - } - } - setInterval( async () => { - await requestPassages(); + const stops = getDisplayedStops(); + if (stops.length > 0) { + refreshPassages(stops[0].id); + } }, syncPeriodMsec ); diff --git a/frontend/src/search.tsx b/frontend/src/search.tsx index c9e2163..02c73d6 100644 --- a/frontend/src/search.tsx +++ b/frontend/src/search.tsx @@ -21,55 +21,42 @@ export const SearchContext = createContext(); export function SearchProvider(props: { children: JSX.Element }) { - const [store, setStore] = createStore({stops: {}, markers: {}, displayedStop: []}); + const [store, setStore] = createStore({ stops: {}, markers: {}, displayedStops: [] }); - const getStops = () => { - return store.stops; - }; + const getDisplayedStops = () => { + return store.displayedStops; + } - const setStops = (stops) => { - setStore((s) => { - setStore('stops', stops); - }); - }; + const setDisplayedStops = (stops: Array) => { + setStore((s) => { + setStore('displayedStops', stops); + }); + } - const removeStops = (stopIds) => { - batch(() => { - for(const stopId of stopIds) { - setStore('stops', stopId, undefined); - setStore('markers', stopId, undefined); - } - }); - }; + const removeStops = (stopIds: Array) => { + batch(() => { + for (const stopId of stopIds) { + setStore('stops', stopId, undefined); + setStore('markers', stopId, undefined); + } + }); + } - const getMarkers = () => { - return store.markers; - }; + const getMarkers = () => { + return store.markers; + } - const addMarkers = (stopId, markers) => { - setStore('markers', stopId, markers); - }; + const addMarkers = (stopId: number, markers) => { + setStore('markers', stopId, markers); + } - const setMarkers = (markers) => { - setStore('markers', markers); - }; + const setMarkers = (markers) => { + setStore('markers', markers); + } - const getDisplayedStop = () => { - /* console.log(store.displayedStop); */ - return store.displayedStop; - }; - const setDisplayedStop = (stop: Stop) => { - /* console.log(stop); */ - setStore((s) => { - console.log("s.displayedStop=", s.displayedStop); - setStore('displayedStop', [stop]); - }); - /* console.log(store.displayedStop); */ - }; - - return ( - - {props.children} - - ); + return ( + + {props.children} + + ); } diff --git a/frontend/src/stopsManager.tsx b/frontend/src/stopsManager.tsx index db7ee00..f1c8910 100644 --- a/frontend/src/stopsManager.tsx +++ b/frontend/src/stopsManager.tsx @@ -94,7 +94,7 @@ const Map: Component = (props) => { const mapCenter = [48.853, 2.35]; - const { addMarkers, getStops } = useContext(SearchContext); + const { addMarkers } = useContext(SearchContext); let mapDiv: any; let map = null; @@ -147,40 +147,24 @@ const Map: Component = (props) => { export const StopsManager: Component = (props) => { - const [minCharactersNb, setMinCharactersNb] = createSignal(4); - const [_inProgress, _setInProgress] = createSignal(false); +export const StopsManager: Component = () => { - const { serverUrl } = useContext(BusinessDataContext); - const { getStops, removeStops, setStops, setDisplayedStop } = useContext(SearchContext); + const [minCharactersNb, setMinCharactersNb] = createSignal(4); + const [inProgress, setInProgress] = createSignal(false); + const [foundStops, setFoundStops] = createSignal>([]); - async function _fetchStopByName(name) { - const data = await fetch(`${serverUrl()}/stop/?name=${name}`, { - headers: { 'Content-Type': 'application/json' } - }); - const stops = await data.json(); - const stopIds = stops.map((stop) => stop.id); + const { getStop, searchStopByName } = useContext(BusinessDataContext); + const { setDisplayedStops } = useContext(SearchContext); - const stopIdsToRemove = Object.keys(getStops()).filter(stopId => !(stopId in stopIds)); - - const byIdStops = {}; - for (const stop of stops) { - byIdStops[stop.id] = stop; - } - - batch(() => { - removeStops(stopIdsToRemove); - setStops(byIdStops); - }); - } - - async function _onStopNameInput(event) { + const onStopNameInput = async (event) => { /* TODO: Add a tempo before fetching stop for giving time to user to finish his request */ const stopName = event.target.value; if (stopName.length >= minCharactersNb()) { console.log(`Fetching data for ${stopName}`); - _setInProgress(true); - await _fetchStopByName(stopName); - _setInProgress(false); + setInProgress(true); + const stopsById = await searchStopByName(stopName); + setFoundStops(Object.values(stopsById)); + setInProgress(false); } } From 29ba26e80bb994dc5ac4f5c2d4e2bbb19ceac283 Mon Sep 17 00:00:00 2001 From: Adrien Date: Sat, 28 Jan 2023 16:22:32 +0100 Subject: [PATCH 7/8] =?UTF-8?q?=E2=99=BB=EF=B8=8F=20Replace=20methods=20ca?= =?UTF-8?q?lled=20to=20render=20Component=20with=20small=20Components?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- frontend/src/passagesDisplay.tsx | 99 ++++++----------- frontend/src/passagesPanel.tsx | 183 ++++++++++++++++--------------- frontend/src/stopsManager.tsx | 20 ++-- 3 files changed, 141 insertions(+), 161 deletions(-) diff --git a/frontend/src/passagesDisplay.tsx b/frontend/src/passagesDisplay.tsx index 9882623..d56101e 100644 --- a/frontend/src/passagesDisplay.tsx +++ b/frontend/src/passagesDisplay.tsx @@ -60,78 +60,59 @@ export const PassagesDisplay: Component = () => { ); // TODO: Sort transport modes by weight - // TODO: Split this method to isolate the passagesPanel part. - function _computeHeader(title: string): JSX.Element { - let transportModes = []; - transportModes = new Set( - Object.keys(passages()).map((lineId) => { - const line = _lines.get(lineId); - if (line !== undefined) { - return getTransportModeSrc(line.transportMode, false); - } - return null; - }) - ); + const Header: Component = (props) => { + const computeTransportModes = async (lineIds: Array) => { + 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 (
- - {(transportMode) => { - return ( + + + {(url) =>
- +
- ); - }} -
+ } +
+
- - {title} + + {props.title}
- + {format(dateNow(), "HH:mm")}
-
+
); - } + }; - function _computeFooter(): JSX.Element { + const Footer: Component = (props) => { return (
- + {(positioned) => { const { position } = positioned; return (
-
@@ -144,7 +125,7 @@ export const PassagesDisplay: Component = () => { return (
- {_computeHeader("Prochains passages")} +
{() => { setPanels([]); @@ -167,16 +148,11 @@ export const PassagesDisplay: Component = () => { if (byLinePassagesKeys.length <= maxPassagePerPanel - chunkSize) { chunk[lineId] = byLinePassages; chunkSize += byLinePassagesKeys.length; - } else { - console.log("chunk=", chunk); + } + else { const [store] = createStore(chunk); const panelid = index++; - const panel = ( - - ); + const panel = ; newPanels.push(panel); positioneds.push({ position: panelid, panel }); @@ -188,12 +164,7 @@ export const PassagesDisplay: Component = () => { if (chunkSize) { const panelId = index++; const [store] = createStore(chunk); - const panel = ( - - ); + const panel = ; newPanels.push(panel); positioneds.push({ position: panelId, panel }); } @@ -202,7 +173,7 @@ export const PassagesDisplay: Component = () => { return newPanels; }}
- {_computeFooter()} +
); }; diff --git a/frontend/src/passagesPanel.tsx b/frontend/src/passagesPanel.tsx index a602efe..70c9624 100644 --- a/frontend/src/passagesPanel.tsx +++ b/frontend/src/passagesPanel.tsx @@ -1,14 +1,56 @@ -import { Component } from 'solid-js'; +import { Component, createEffect, createResource, createSignal, useContext } from 'solid-js'; import { createDateNow, getTime } from '@solid-primitives/date'; import { Motion } from "@motionone/solid"; import { TrafficStatus } from './types'; import { renderLineTransportMode, renderLinePicto } from './utils'; +import { BusinessDataContext } from "./businessData"; + import styles from "./passagesPanel.module.css"; -export const PassagesPanel: Component = (props) => { +const TtwPassage: Component = (props) => { + + const [dateNow] = createDateNow(5000); + + const refTs = props.passage.expectedDepartTs !== null ? props.passage.expectedDepartTs : props.passage.expectedArrivalTs; + const ttwSec = refTs - (getTime(dateNow()) / 1000); + const isApproaching = ttwSec <= 60; + + return ( +
+ + + {Math.floor(ttwSec / 60)} min + + +
+ ); +} + +const UnavailablePassage: Component = (props) => { + const textStyle = { fill: "#000000" }; + + return ( +
+ + Information + non + disponible + +
+ ); +} + +/* TODO: Manage end of service */ +const Passages: Component = (props) => { /* TODO: Find where to get data to compute traffic status. */ const trafficStatusColor = new Map([ @@ -19,102 +61,71 @@ export const PassagesPanel: Component = (props) => { [TrafficStatus.BYPASSED, "#ffffff"] ]); - const [dateNow] = createDateNow(5000); + const passagesLength = props.passages.length; + const firstPassage = passagesLength > 0 ? props.passages[0] : undefined; + const secondPassage = passagesLength > 1 ? props.passages[1] : undefined; + const trafficStatusStyle = { fill: trafficStatusColor.get(props.line.trafficStatus) }; - function _computeTtwPassage(class_, passage, fontSize) { - const refTs = passage.expectedDepartTs !== null ? passage.expectedDepartTs : passage.expectedArrivalTs; - const ttwSec = refTs - (getTime(dateNow()) / 1000); - const isApproaching = ttwSec <= 60; - return ( -
- - - {Math.floor(ttwSec / 60)} min - + return ( +
+
+ {renderLineTransportMode(props.line)} +
+ {renderLinePicto(props.line, styles)} +
+ + + {props.destination} +
- ); - } - - function _computeUnavailablePassage(class_) { - const textStyle = { fill: "#000000" }; - return ( -
- - Information - non - disponible +
+ +
- ); - } - - function _computeSecondPassage(passage): JSX.Element { - return ( - - {_computeTtwPassage(styles.secondPassage, passage, 45)} + > + - ); - } - - function _computeFirstPassage(passage): JSX.Element { - return ( - - {_computeTtwPassage(styles.firstPassage, passage, 50)} + > + - ); +
+ ); +} + +export const PassagesPanel: Component = (props) => { + + const { getLine } = useContext(BusinessDataContext); + + const getLines = async (lineIds: Array) => { + const lines = await Promise.all(lineIds.map((lineId) => getLine(lineId))); + return lines; } - /* TODO: Manage end of service */ - function _genPassages(passages, line, destination) { - const passagesLength = passages.length; - const firstPassage = passagesLength > 0 ? passages[0] : undefined; - const secondPassage = passagesLength > 1 ? passages[1] : undefined; - const trafficStatusStyle = { fill: trafficStatusColor.get(line.trafficStatus) }; - return ( -
-
- {renderLineTransportMode(line)} -
- {renderLinePicto(line, styles)} -
- - - {destination} - - -
-
- - - -
- {firstPassage ? _computeFirstPassage(firstPassage) : null} - {secondPassage ? _computeSecondPassage(secondPassage) : null} -
- ); - } + const [lineIds, setLinesIds] = createSignal([]); + const [lines] = createResource(lineIds, getLines); + + createEffect(async () => { + setLinesIds(Object.keys(props.passages)); + }); return (
- {() => { - const ret = []; - for (const lineId of Object.keys(props.passages)) { - const line = props.lines.get(lineId); - const byLinePassages = props.passages[lineId]; - for (const destination of Object.keys(byLinePassages)) { - const passages = byLinePassages[destination]; - ret.push(_genPassages(passages, line, destination)); + + {() => { + const ret = []; + for (const line of lines()) { + const byLinePassages = props.passages[line.id]; + if (byLinePassages !== undefined) { + for (const destination of Object.keys(byLinePassages)) { + ret.push(); + } + } } - } - return ret; - }} -
+ return ret; + }} + +
); } diff --git a/frontend/src/stopsManager.tsx b/frontend/src/stopsManager.tsx index f1c8910..9312a0d 100644 --- a/frontend/src/stopsManager.tsx +++ b/frontend/src/stopsManager.tsx @@ -45,9 +45,7 @@ const StopAreaRepr: Component = (props) => { const { getLine } = useContext(BusinessDataContext); - const [lineReprs] = createResource(props.stop, fetchLinesRepr); - - async function fetchLinesRepr(stop) { + const fetchLinesRepr = async (stop: Stop) => { const lineIds = new Set(stop.lines); const stops = stop.stops; for (const stop of stops) { @@ -81,6 +79,8 @@ const StopAreaRepr: Component = (props) => { return reprs; } + const [lineReprs] = createResource(props.stop, fetchLinesRepr); + return ( {props.stop.name} @@ -128,7 +128,7 @@ const Map: Component = (props) => { /* TODO: Avoid to clear all layers... */ stopsLayerGroup.clearLayers(); - for (const stop of Object.values(getStops())) { + for (const stop of props.stops) { const markers = setMarker(stop); addMarkers(stop.id, markers); for (const marker of markers) { @@ -145,8 +145,6 @@ const Map: Component = (props) => { return
; } -export const StopsManager: Component = (props) => { - export const StopsManager: Component = () => { const [minCharactersNb, setMinCharactersNb] = createSignal(4); @@ -172,21 +170,21 @@ export const StopsManager: Component = () => { 🚉 🚏 - + - + {() => { const items = []; - for (const stop of Object.values(getStops()).sort((x, y) => x.name.localeCompare(y.name))) { + for (const stop of foundStops().sort((x, y) => x.name.localeCompare(y.name))) { items.push(