From 2fd6783534dfea576331afdae7127a690ce5ac0f Mon Sep 17 00:00:00 2001 From: Adrien Date: Mon, 30 Jan 2023 22:07:20 +0100 Subject: [PATCH] =?UTF-8?q?=F0=9F=9A=A8=20Try=20to=20make=20TS=20linter=20?= =?UTF-8?q?happy?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- frontend/package.json | 1 + frontend/src/App.tsx | 6 +- frontend/src/businessData.tsx | 72 +++++++++++++++--------- frontend/src/passagesDisplay.tsx | 73 ++++++++++++++++--------- frontend/src/passagesPanel.tsx | 56 +++++++++++-------- frontend/src/search.tsx | 38 +++++++------ frontend/src/stopsManager.tsx | 94 +++++++++++++++++++++----------- frontend/src/types.tsx | 22 ++++---- frontend/src/utils.tsx | 29 +++++----- frontend/tsconfig.json | 3 +- 10 files changed, 242 insertions(+), 152 deletions(-) diff --git a/frontend/package.json b/frontend/package.json index 71f07ee..11b2a8e 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -11,6 +11,7 @@ }, "license": "MIT", "devDependencies": { + "@types/leaflet": "^1.9.0", "@vitejs/plugin-basic-ssl": "^1.0.1", "eslint": "^8.32.0", "eslint-plugin-solid": "^0.9.3", diff --git a/frontend/src/App.tsx b/frontend/src/App.tsx index 5dad69b..9678daa 100644 --- a/frontend/src/App.tsx +++ b/frontend/src/App.tsx @@ -1,10 +1,8 @@ import { Component } from 'solid-js'; -import { MatrixCapabilities, WidgetApi, WidgetApiToWidgetAction, CustomEvent, IVisibilityActionRequest } from 'matrix-widget-api'; - +import { IVisibilityActionRequest, MatrixCapabilities, WidgetApi, WidgetApiToWidgetAction } from 'matrix-widget-api'; import { HopeProvider } from "@hope-ui/solid"; import { BusinessDataProvider } from './businessData'; - import { SearchProvider } from './search'; import { PassagesDisplay } from './passagesDisplay'; import { StopsManager } from './stopsManager'; @@ -28,7 +26,7 @@ const App: Component = () => { console.log("App: widgetId:" + widgetId); console.log("App: userId:" + userId); - const api = new WidgetApi(widgetId); + const api = new WidgetApi(widgetId != null ? widgetId : undefined); api.requestCapability(MatrixCapabilities.AlwaysOnScreen); api.start(); api.on("ready", function() { diff --git a/frontend/src/businessData.tsx b/frontend/src/businessData.tsx index 218cbd4..4383022 100644 --- a/frontend/src/businessData.tsx +++ b/frontend/src/businessData.tsx @@ -1,28 +1,37 @@ -import { createContext, createSignal } from 'solid-js'; +import { createContext, createSignal, JSX } from 'solid-js'; import { createStore } from 'solid-js/store'; -import { Passages, Stops } from './types'; +import { Line, Lines, Passage, Passages, Stop, Stops } from './types'; -interface Store { +export interface BusinessDataStore { + getLine: (lineId: string) => Promise; + getLinePassages: (lineId: string) => Record; + passages: () => Passages; - getLinePassages?: (lineId: string) => Passages; - addPassages?: (passages: Passages) => void; - clearPassages?: () => void; + refreshPassages: (stopId: number) => Promise; + addPassages: (passages: Passages) => void; + clearPassages: () => void; - stops: () => Stops; - addStops?: (stops: Stops) => void; + getStop: (stopId: number) => Stop | undefined; + searchStopByName: (name: string) => Promise; }; -export const BusinessDataContext = createContext(); +export const BusinessDataContext = createContext(); export function BusinessDataProvider(props: { children: JSX.Element }) { - const [serverUrl, setServerUrl] = createSignal("https://localhost:4443"); + const [serverUrl] = createSignal("https://localhost:4443"); - const [store, setStore] = createStore({ lines: {}, passages: {}, stops: {} }); + type Store = { + lines: Lines; + passages: Passages; + stops: Stops; + }; - const getLine: Line = async (lineId: string) => { + const [store, setStore] = createStore({ lines: {}, passages: {}, stops: {} }); + + const getLine = async (lineId: string): Promise => { let line = store.lines[lineId]; if (line === undefined) { console.log(`${lineId} not found... fetch it from backend.`); @@ -35,15 +44,15 @@ export function BusinessDataProvider(props: { children: JSX.Element }) { return line; } - const getLinePassages = (lineId: string) => { + const getLinePassages = (lineId: string): Record => { return store.passages[lineId]; }; - const passages = () => { + const passages = (): Passages => { return store.passages; } - const refreshPassages = async (stopId: number) => { + const refreshPassages = async (stopId: number): Promise => { const httpOptions = { headers: { "Content-Type": "application/json" } }; console.log(`Fetching data for ${stopId}`); const data = await fetch(`${serverUrl()}/stop/nextPassages/${stopId}`, httpOptions); @@ -51,31 +60,30 @@ export function BusinessDataProvider(props: { children: JSX.Element }) { addPassages(response.passages); } - const addPassages = (passages) => { - setStore((s) => { - setStore('passages', passages); - }); + const addPassages = (passages: Passages): void => { + setStore('passages', passages); } - const clearPassages = () => { - setStore((s) => { + const clearPassages = (): void => { + setStore((s: Store): Store => { for (const lineId of Object.keys(s.passages)) { setStore('passages', lineId, undefined); } + return s; }); } - const getStop = (stopId: int) => { + const getStop = (stopId: number): Stop | undefined => { return store.stops[stopId]; } - const searchStopByName = async (name: string) => { + const searchStopByName = async (name: string): Promise => { const data = await fetch(`${serverUrl()}/stop/?name=${name}`, { headers: { 'Content-Type': 'application/json' } }); const stops = await data.json(); - const byIdStops = {}; + const byIdStops: Stops = {}; for (const stop of stops) { byIdStops[stop.id] = stop; setStore('stops', stop.id, stop); @@ -85,10 +93,22 @@ export function BusinessDataProvider(props: { children: JSX.Element }) { return ( {props.children} ); } + +export interface BusinessDataStore { + getLine: (lineId: string) => Promise; + getLinePassages: (lineId: string) => Record; + + passages: () => Passages; + refreshPassages: (stopId: number) => Promise; + addPassages: (passages: Passages) => void; + clearPassages: () => void; + + getStop: (stopId: number) => Stop | undefined; + searchStopByName: (name: string) => Promise; +}; diff --git a/frontend/src/passagesDisplay.tsx b/frontend/src/passagesDisplay.tsx index a165a50..e3ee5ab 100644 --- a/frontend/src/passagesDisplay.tsx +++ b/frontend/src/passagesDisplay.tsx @@ -1,28 +1,43 @@ -import { Component, createEffect, createResource, createSignal, useContext } from "solid-js"; +import { createEffect, createResource, createSignal, For, JSX, ParentComponent, Show, useContext, VoidComponent } 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 { BusinessDataContext, BusinessDataStore } from "./businessData"; +import { SearchContext, SearchStore } from "./search"; -import { PassagesPanel } from "./passagesPanel"; +import { Passage, Passages } from "./types"; import { getTransportModeSrc } from "./utils"; +import { PassagesPanel } from "./passagesPanel"; + import styles from "./passagesDisplay.module.css"; -export const PassagesDisplay: Component = () => { +export const PassagesDisplay: ParentComponent = () => { + const maxPassagePerPanel = 5; const syncPeriodMsec = 20 * 1000; + const panelSwitchPeriodMsec = 4 * 1000; - const { passages, getLine, getLinePassages, refreshPassages, clearPassages } = useContext(BusinessDataContext); - + const businessDataStore: BusinessDataStore | undefined = useContext(BusinessDataContext); // TODO: Use props instead - const { getDisplayedStops } = useContext(SearchContext); + const searchStore: SearchStore | undefined = useContext(SearchContext); + + if (businessDataStore === undefined || searchStore === undefined) + return
; + + const { passages, getLine, getLinePassages, refreshPassages, clearPassages } = businessDataStore; + const { getDisplayedStops } = searchStore; const [displayedPanelId, setDisplayedPanelId] = createSignal(0); - const [panels, setPanels] = createStore([]); + + type PositionnedPanel = { + position: number; + // TODO: Should be PassagesPanelComponent ? + panel: JSX.Element; + }; + const [panels, setPanels] = createStore([]); const [dateNow] = createDateNow(1000); @@ -32,7 +47,7 @@ export const PassagesDisplay: Component = () => { nextPanelId = 0; } setDisplayedPanelId(nextPanelId); - }, 4000); + }, panelSwitchPeriodMsec); createEffect(() => { console.log("######### onStopIdUpdate #########"); @@ -60,14 +75,22 @@ export const PassagesDisplay: Component = () => { ); // TODO: Sort transport modes by weight - const Header: Component = (props) => { - const computeTransportModes = async (lineIds: Array) => { + const Header: VoidComponent<{ passages: Passages, title: string }> = (props) => { + + const computeTransportModes = async (lineIds: string[]): Promise => { const lines = await Promise.all(lineIds.map((lineId) => getLine(lineId))); - return new Set(lines.map((line) => getTransportModeSrc(line.transportMode, false))); + const urls: Set = new Set(); + for (const line of lines) { + const src = getTransportModeSrc(line.transportMode, false); + if (src !== undefined) { + urls.add(src); + } + } + return Array.from(urls); } - const [linesIds, setLinesIds] = createSignal([]); - const [transportModeUrls] = createResource(linesIds, computeTransportModes); + const [linesIds, setLinesIds] = createSignal([]); + const [transportModeUrls] = createResource(linesIds, computeTransportModes); createEffect(() => { setLinesIds(Object.keys(props.passages)); @@ -76,7 +99,7 @@ export const PassagesDisplay: Component = () => { return (
- + {(url) =>
@@ -85,14 +108,14 @@ export const PassagesDisplay: Component = () => {
- + {props.title}
- + {format(dateNow(), "HH:mm")} @@ -102,12 +125,12 @@ export const PassagesDisplay: Component = () => { ); }; - const Footer: Component = (props) => { + const Footer: VoidComponent<{ panels: PositionnedPanel[] }> = (props) => { return (
- {(positioned) => { - const { position } = positioned; + {(panel) => { + const position = panel.position; return (
@@ -131,10 +154,10 @@ export const PassagesDisplay: Component = () => { setPanels([]); let newPanels = []; - let positioneds = []; + let positioneds: PositionnedPanel[] = []; let index = 0; - let chunk = {}; + let chunk: Record> = {}; let chunkSize = 0; console.log("passages=", passages()); @@ -154,7 +177,7 @@ export const PassagesDisplay: Component = () => { const panelid = index++; const panel = ; newPanels.push(panel); - positioneds.push({ position: panelid, panel }); + positioneds.push({ position: panelid, panel: panel }); chunk = {}; chunk[lineId] = byLinePassages; @@ -166,7 +189,7 @@ export const PassagesDisplay: Component = () => { const [store] = createStore(chunk); const panel = ; newPanels.push(panel); - positioneds.push({ position: panelId, panel }); + positioneds.push({ position: panelId, panel: panel }); } setPanels(positioneds); diff --git a/frontend/src/passagesPanel.tsx b/frontend/src/passagesPanel.tsx index 70c9624..100639d 100644 --- a/frontend/src/passagesPanel.tsx +++ b/frontend/src/passagesPanel.tsx @@ -1,16 +1,16 @@ -import { Component, createEffect, createResource, createSignal, useContext } from 'solid-js'; +import { VoidComponent, createEffect, createResource, createSignal, ParentComponent, ParentProps, Show, useContext } from 'solid-js'; import { createDateNow, getTime } from '@solid-primitives/date'; +import { AnimationOptions } from '@motionone/types'; import { Motion } from "@motionone/solid"; -import { TrafficStatus } from './types'; +import { Line, Passage, Passages, TrafficStatus } from './types'; import { renderLineTransportMode, renderLinePicto } from './utils'; +import { BusinessDataContext, BusinessDataStore } from "./businessData"; -import { BusinessDataContext } from "./businessData"; - -import styles from "./passagesPanel.module.css"; +import styles from './passagesPanel.module.css'; -const TtwPassage: Component = (props) => { +const TtwPassage: VoidComponent<{ passage: Passage, style: string, fontSize: number }> = (props) => { const [dateNow] = createDateNow(5000); @@ -18,6 +18,7 @@ const TtwPassage: Component = (props) => { const ttwSec = refTs - (getTime(dateNow()) / 1000); const isApproaching = ttwSec <= 60; + const transition: AnimationOptions = { duration: 3, repeat: Infinity }; return (
@@ -25,9 +26,9 @@ const TtwPassage: Component = (props) => { x="100%" y="55%" dominant-baseline="middle" text-anchor="end" font-size={props.fontSize} style={{ fill: "#000000" }} - initial={isApproaching} + initial={isApproaching ? undefined : false} animate={{ opacity: [1, 0, 1] }} - transition={{ duration: 3, repeat: Infinity }}> + transition={transition}> {Math.floor(ttwSec / 60)} min @@ -35,12 +36,12 @@ const TtwPassage: Component = (props) => { ); } -const UnavailablePassage: Component = (props) => { +const UnavailablePassage: VoidComponent<{ style: string }> = (props) => { const textStyle = { fill: "#000000" }; return (
- + Information non disponible @@ -50,7 +51,7 @@ const UnavailablePassage: Component = (props) => { } /* TODO: Manage end of service */ -const Passages: Component = (props) => { +const DestinationPassages: VoidComponent<{ passages: Passage[], line: Line, destination: string }> = (props) => { /* TODO: Find where to get data to compute traffic status. */ const trafficStatusColor = new Map([ @@ -64,7 +65,10 @@ const Passages: Component = (props) => { 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) }; + + // TODO: Manage traffic status + // const trafficStatusStyle = { fill: trafficStatusColor.get(props.line.trafficStatus) }; + const trafficStatusStyle = { fill: trafficStatusColor.get(TrafficStatus.UNKNOWN) }; return (
@@ -73,7 +77,7 @@ const Passages: Component = (props) => {
{renderLinePicto(props.line, styles)}
- + {props.destination} @@ -85,33 +89,39 @@ const Passages: Component = (props) => {
> - + > - +
); } -export const PassagesPanel: Component = (props) => { +export type PassagesPanelComponentProps = ParentProps & { passages: Passages, show: boolean }; +export type PassagesPanelComponent = ParentComponent; +export const PassagesPanel: PassagesPanelComponent = (props) => { - const { getLine } = useContext(BusinessDataContext); + const businessDataContext: BusinessDataStore | undefined = useContext(BusinessDataContext); + if (businessDataContext === undefined) + return
; - const getLines = async (lineIds: Array) => { - const lines = await Promise.all(lineIds.map((lineId) => getLine(lineId))); + const { getLine } = businessDataContext; + + const getLines = async (lineIds: string[]): Promise => { + const lines = await Promise.all[]>(lineIds.map((lineId) => getLine(lineId))); return lines; } - const [lineIds, setLinesIds] = createSignal([]); - const [lines] = createResource(lineIds, getLines); + const [lineIds, setLinesIds] = createSignal([]); + const [lines] = createResource(lineIds, getLines); createEffect(async () => { setLinesIds(Object.keys(props.passages)); }); return ( -
+
{() => { const ret = []; @@ -119,7 +129,7 @@ export const PassagesPanel: Component = (props) => { const byLinePassages = props.passages[line.id]; if (byLinePassages !== undefined) { for (const destination of Object.keys(byLinePassages)) { - ret.push(); + ret.push(); } } } diff --git a/frontend/src/search.tsx b/frontend/src/search.tsx index 099140a..9c0e658 100644 --- a/frontend/src/search.tsx +++ b/frontend/src/search.tsx @@ -1,35 +1,39 @@ -import { batch, createContext } from 'solid-js'; +import { createContext, JSX } from 'solid-js'; import { createStore } from 'solid-js/store'; +import { Marker as LeafletMarker } from 'leaflet'; -import { Stop, Stops } from './types'; +import { Stop } from './types'; -interface Store { - getMarkers: () => Markers; - addMarkers?: (stopId, markers) => void; - setMarkers?: (markers) => void; +export type ByStopIdMarkers = Record; - getStops: () => Stops; - setStops?: (stops) => void; - removeStops?: (stopIds: Array) => void; +export interface SearchStore { + getDisplayedStops: () => Stop[]; + setDisplayedStops: (stops: Stop[]) => void; - getDisplayedStops: () => Array; - setDisplayedStops: (stops: Array) => void; + addMarkers: (stopId: number, markers: LeafletMarker[]) => void; }; -export const SearchContext = createContext(); +export const SearchContext = createContext(); export function SearchProvider(props: { children: JSX.Element }) { - const [store, setStore] = createStore({ stops: {}, markers: {}, displayedStops: [] }); + type Store = { + stops: Record; + markers: ByStopIdMarkers; + displayedStops: Stop[]; + }; - const getDisplayedStops = () => { + const [store, setStore] = createStore({ stops: {}, markers: {}, displayedStops: [] }); + + const getDisplayedStops = (): Stop[] => { return store.displayedStops; } - const setDisplayedStops = (stops: Array) => { - setStore((s) => { + const setDisplayedStops = (stops: Stop[]): void => { + setStore((s: Store) => { setStore('displayedStops', stops); + return s; }); } @@ -46,7 +50,7 @@ export function SearchProvider(props: { children: JSX.Element }) { return store.markers; } - const addMarkers = (stopId: number, markers) => { + const addMarkers = (stopId: number, markers: L.Marker[]): void => { setStore('markers', stopId, markers); } diff --git a/frontend/src/stopsManager.tsx b/frontend/src/stopsManager.tsx index dce13f2..e113fb8 100644 --- a/frontend/src/stopsManager.tsx +++ b/frontend/src/stopsManager.tsx @@ -1,11 +1,15 @@ -import { Component, createEffect, createResource, createSignal, onMount, Show, useContext } from 'solid-js'; +import { createEffect, createResource, createSignal, For, JSX, onMount, Show, useContext, VoidComponent } from 'solid-js'; import { Box, Button, Input, InputLeftAddon, InputGroup, HStack, List, ListItem, Progress, ProgressIndicator, VStack } from "@hope-ui/solid"; import 'leaflet/dist/leaflet.css'; -import L from 'leaflet'; -import { BusinessDataContext } from './businessData'; -import { SearchContext } from './search'; +import { + featureGroup as leafletFeatureGroup, LatLngLiteral as LeafletLatLngLiteral, Map as LeafletMap, + Marker as LeafletMarker, tileLayer as leafletTileLayer +} from 'leaflet'; + +import { BusinessDataContext, BusinessDataStore } from "./businessData"; +import { SearchContext, SearchStore } from './search'; import { Stop } from './types'; import { renderLineTransportMode, renderLinePicto, TransportModeWeights } from './utils'; @@ -13,13 +17,15 @@ import { renderLineTransportMode, renderLinePicto, TransportModeWeights } from ' import styles from './stopManager.module.css'; -const StopRepr: Component = (props) => { +const StopRepr: VoidComponent<{ stop: Stop }> = (props) => { - const { getLine } = useContext(BusinessDataContext); + const businessDataStore: BusinessDataStore | undefined = useContext(BusinessDataContext); + if (businessDataStore === undefined) + return
; - const [lineReprs] = createResource(props.stop.lines, fetchLinesRepr); + const { getLine } = businessDataStore; - const fetchLinesRepr = async (lineIds: Array) => { + const fetchLinesRepr = async (lineIds: string[]): Promise => { const reprs = []; for (const lineId of lineIds) { const line = await getLine(lineId); @@ -31,26 +37,37 @@ const StopRepr: Component = (props) => { return reprs; } + const [lineReprs] = createResource(props.stop.lines, fetchLinesRepr); + return ( {props.stop.name} - {(line) => line} + {(line: JSX.Element) => line} ); } -const StopAreaRepr: Component = (props) => { +const StopAreaRepr: VoidComponent<{ stop: Stop }> = (props) => { - const { getLine } = useContext(BusinessDataContext); + const businessDataStore: BusinessDataStore | undefined = useContext(BusinessDataContext); + if (businessDataStore === undefined) + return
; - const fetchLinesRepr = async (stop: Stop) => { + const { getLine } = businessDataStore; + + type ByTransportModeReprs = { + mode: JSX.Element | undefined; + [key: string]: JSX.Element | JSX.Element[] | undefined; + }; + + const fetchLinesRepr = async (stop: Stop): Promise => { const lineIds = new Set(stop.lines); const stops = stop.stops; for (const stop of stops) { stop.lines.forEach(lineIds.add, lineIds); } - const byModeReprs = {}; + const byModeReprs: Record = {}; for (const lineId of lineIds) { const line = await getLine(lineId); if (line !== undefined) { @@ -64,7 +81,7 @@ const StopAreaRepr: Component = (props) => { } const reprs = []; - const sortedTransportModes = Object.keys(byModeReprs).sort((x, y) => TransportModeWeights[x] < TransportModeWeights[y]); + const sortedTransportModes = Object.keys(byModeReprs).sort((x, y) => TransportModeWeights[x] < TransportModeWeights[y] ? 1 : -1); for (const transportMode of sortedTransportModes) { const lines = byModeReprs[transportMode]; const repr = [lines.mode]; @@ -88,29 +105,34 @@ const StopAreaRepr: Component = (props) => { } -const Map: Component = (props) => { +const Map: VoidComponent<{ stops: Stop[] }> = (props) => { - const mapCenter = [48.853, 2.35]; + const mapCenter: LeafletLatLngLiteral = { lat: 48.853, lng: 2.35 }; + + const searchStore: SearchStore | undefined = useContext(SearchContext); + if (searchStore === undefined) + return
; + + const { addMarkers } = searchStore; - const { addMarkers } = useContext(SearchContext); let mapDiv: any; - let map = null; - const stopsLayerGroup = L.featureGroup(); + let map: LeafletMap | undefined = undefined; + const stopsLayerGroup = leafletFeatureGroup(); const buildMap = (div: HTMLDivElement) => { - map = L.map(div).setView(mapCenter, 11); - L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', { + map = new LeafletMap(div).setView(mapCenter, 11); + leafletTileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', { attribution: '© OpenStreetMap contributors' }).addTo(map); stopsLayerGroup.addTo(map); } - const setMarker = (stop: Stop): Array => { + const setMarker = (stop: Stop): L.Marker[] => { const markers = []; if (stop.lat !== undefined && stop.lon !== undefined) { /* TODO: Add stop lines representation to popup. */ - markers.push(L.marker([stop.lat, stop.lon]).bindPopup(`${stop.name}`).openPopup()); + markers.push(new LeafletMarker([stop.lat, stop.lon]).bindPopup(`${stop.name}`).openPopup()); } else { for (const _stop of stop.stops) { @@ -135,7 +157,7 @@ const Map: Component = (props) => { } const stopsBound = stopsLayerGroup.getBounds(); - if (Object.keys(stopsBound).length) { + if (map !== undefined && Object.keys(stopsBound).length) { map.fitBounds(stopsBound); } }); @@ -143,18 +165,26 @@ const Map: Component = (props) => { return
; } -export const StopsManager: Component = () => { +export const StopsManager: VoidComponent = () => { + + const businessDataStore: BusinessDataStore | undefined = useContext(BusinessDataContext); + const searchStore: SearchStore | undefined = useContext(SearchContext); + + if (businessDataStore === undefined || searchStore === undefined) + return
; + + const { searchStopByName } = businessDataStore; + const { setDisplayedStops } = searchStore; + + // TODO: Use props instead + const [minCharactersNb] = createSignal(4); - const [minCharactersNb, setMinCharactersNb] = createSignal(4); const [inProgress, setInProgress] = createSignal(false); - const [foundStops, setFoundStops] = createSignal>([]); + const [foundStops, setFoundStops] = createSignal([]); - const { getStop, searchStopByName } = useContext(BusinessDataContext); - const { setDisplayedStops } = useContext(SearchContext); - - const onStopNameInput = async (event) => { + const onStopNameInput: JSX.EventHandler = async (event): Promise => { /* TODO: Add a tempo before fetching stop for giving time to user to finish his request */ - const stopName = event.target.value; + const stopName = event.currentTarget.value; if (stopName.length >= minCharactersNb()) { console.log(`Fetching data for ${stopName}`); setInProgress(true); diff --git a/frontend/src/types.tsx b/frontend/src/types.tsx index 8e12970..b4c07e5 100644 --- a/frontend/src/types.tsx +++ b/frontend/src/types.tsx @@ -6,12 +6,10 @@ export enum TrafficStatus { BYPASSED } -export class Passages { }; - export class Passage { line: number; operator: string; - destinations: Array; + destinations: string[]; atStop: boolean; aimedArrivalTs: number; expectedArrivalTs: number; @@ -21,7 +19,7 @@ export class Passage { arrivalStatus: string; departStatus: string; - constructor(line: number, operator: string, destinations: Array, atStop: boolean, aimedArrivalTs: number, + constructor(line: number, operator: string, destinations: string[], atStop: boolean, aimedArrivalTs: number, expectedArrivalTs: number, arrivalPlatformName: string, aimedDepartTs: number, expectedDepartTs: number, arrivalStatus: string, departStatus: string) { this.line = line; @@ -38,7 +36,7 @@ export class Passage { } }; -export class Stops { }; +export type Passages = Record>; export class Stop { id: number; @@ -46,10 +44,10 @@ export class Stop { town: string; lat: number; lon: number; - stops: Array; - lines: Array; + stops: Stop[]; + lines: string[]; - constructor(id: number, name: string, town: string, lat: number, lon: number, stops: Array, lines: Array) { + constructor(id: number, name: string, town: string, lat: number, lon: number, stops: Stop[], lines: string[]) { this.id = id; this.name = name; this.town = town; @@ -63,6 +61,8 @@ export class Stop { } }; +export type Stops = Record; + export class Line { id: string; shortName: string; @@ -75,11 +75,11 @@ export class Line { accessibility: boolean; visualSignsAvailable: string; // TODO: Use an enum audibleSignsAvailable: string; // TODO: Use an enum - stopIds: Array; + stopIds: number[]; constructor(id: string, shortName: string, name: string, status: string, transportMode: string, backColorHexa: string, foreColorHexa: string, operatorId: number, accessibility: boolean, visualSignsAvailable: string, - audibleSignsAvailable: string, stopIds: Array) { + audibleSignsAvailable: string, stopIds: number[]) { this.id = id; this.shortName = shortName; this.name = name; @@ -94,3 +94,5 @@ export class Line { this.stopIds = stopIds; } }; + +export type Lines = Record; diff --git a/frontend/src/utils.tsx b/frontend/src/utils.tsx index ff15bac..b9c0187 100644 --- a/frontend/src/utils.tsx +++ b/frontend/src/utils.tsx @@ -1,8 +1,10 @@ +import { JSX } from 'solid-js'; + import { Line } from './types'; const validTransportModes = ["bus", "tram", "metro", "rer", "transilien", "funicular", "ter", "unknown"]; -export const TransportModeWeights = { +export const TransportModeWeights: Record = { bus: 1, tram: 2, val: 3, @@ -13,20 +15,19 @@ export const TransportModeWeights = { ter: 8, }; -export function renderLineTransportMode(line: Line): JSX.Element { - return -} - -export function getTransportModeSrc(mode: string, color: boolean = true): string | null { - let ret = null; +export function getTransportModeSrc(mode: string, color: boolean = true): string | undefined { + let ret = undefined; if (validTransportModes.includes(mode)) { ret = `/public/symbole_${mode}_${color ? "" : "support_fonce_"}RVB.svg`; } return ret; } +export function renderLineTransportMode(line: Line): JSX.Element { + return +} -function renderBusLinePicto(line: Line, styles): JSX.Element { +function renderBusLinePicto(line: Line, styles: CSSModuleClasses): JSX.Element { return (
@@ -44,7 +45,7 @@ function renderBusLinePicto(line: Line, styles): JSX.Element { ); } -function renderTramLinePicto(line: Line, styles): JSX.Element { +function renderTramLinePicto(line: Line, styles: CSSModuleClasses): JSX.Element { const lineStyle = { fill: `#${line.backColorHexa}` }; return (
@@ -64,10 +65,10 @@ function renderTramLinePicto(line: Line, styles): JSX.Element { ); } -function renderMetroLinePicto(line: Line, styles): JSX.Element { +function renderMetroLinePicto(line: Line, styles: CSSModuleClasses): JSX.Element { return (
- + - +