Skip to content

Commit

Permalink
Merge pull request #518 from ibi-group/otp2-tile-overlay-prereq
Browse files Browse the repository at this point in the history
OTP2 Tile Overlay Prerequisites
  • Loading branch information
miles-grant-ibigroup authored Dec 29, 2022
2 parents b676fd3 + 2f4419a commit 87d045d
Show file tree
Hide file tree
Showing 17 changed files with 1,045 additions and 4 deletions.
589 changes: 589 additions & 0 deletions __snapshots__/storybook.test.ts.snap

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion packages/base-map/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
"react-map-gl": "^7.0.15"
},
"peerDependencies": {
"@opentripplanner/types": "^4.0.2",
"@opentripplanner/types": "^4.0.4",
"react": "^16.14.0",
"styled-components": "^5.3.0"
},
Expand Down
12 changes: 9 additions & 3 deletions packages/base-map/src/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -94,8 +94,14 @@ const BaseMap = ({

const toggleableLayers = Array.isArray(children)
? children
.flat()
.filter(child => child?.props?.id !== undefined)
.flat(10)
.filter(
child =>
child?.props?.id !== undefined &&
// Some sources will not have layers as children, and should be ignored
// from the list.
child?.props?.alwaysShow !== true
)
.map(child => {
const { id: layerId, name, visible } = child.props;
return { id: layerId, name, visible };
Expand Down Expand Up @@ -203,7 +209,7 @@ const BaseMap = ({
)}
{Array.isArray(children)
? children
.flat()
.flat(10)
.filter(child => !hiddenLayers.includes(child?.props?.id))
: children}
</Map>
Expand Down
23 changes: 23 additions & 0 deletions packages/map-popup/i18n/en-US.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
# Default messages for the MapPopup component.
# To use from a react-intl application:
# - merge the content of this file into the messages object
# that has your other localized strings,
# - flatten the ids, i.e. convert a structure such as
# otpUi > MapPopup > stopViewer
# into "otpUi.MapPopup.stopViewer" (see TripDetail story for an example),
# - pass the resulting object to the messages prop of IntlProvider.
#
# The meaning of the pseudo <tags> used in the strings below is as follows:
# - <dietaryLink>: The link to the Dietary Guidelines for Americans will surround the text enclosed by the tag.
# - <strong>: The enclosed text will be rendered as strong (bold) text (same meaning as in HTML).

otpUi:
MapPopup:
availableBikes: "Available bikes: {value}"
availableDocks: "Available docks: {value}"
floatingBike: "Free-floating bike: {name}"
floatingCar: "{company} {name}" # as in "CarCompany Veh1234a"
floatingEScooter: "E-scooter: {name}"

stopId: "Stop ID: {stopId}"
stopViewer: Stop Viewer
10 changes: 10 additions & 0 deletions packages/map-popup/i18n/es.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
otpUi:
MapPopup:
availableBikes: "Bicicletas disponibles: {value}"
availableDocks: "Estaciones de carga disponibles: {value}"
floatingBike: "Bicicleta flotante: {name}"
floatingCar: "{company} {name}"
floatingEScooter: "{company} E-scooter"

stopId: ID de Parada {stopId}
stopViewer: Visor de paradas
10 changes: 10 additions & 0 deletions packages/map-popup/i18n/fr.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
otpUi:
MapPopup:
availableBikes: "Vélos disponibles : {value}"
availableDocks: "Bornes disponibles : {value}"
floatingBike: "Vélo flottant : {name}"
floatingCar: "{company} {name}" # as in "CarCompany Veh1234a"
floatingEScooter: "Trottinette {company}"

stopId: Arrêt n°{stopId}
stopViewer: Info arrêt
10 changes: 10 additions & 0 deletions packages/map-popup/i18n/ko.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
otpUi:
MapPopup:
floatingEScooter: "{company} 전기 스쿠터"
availableDocks: "사용 가능한 독: {value}"
availableBikes: "사용 가능한 자전거: {value}"
floatingCar: "{company} {name}"
floatingBike: "프리 플로팅 자전거: {name}"

stopViewer: 뷰어 중지하기
stopId: "중지 ID: {stopId}"
9 changes: 9 additions & 0 deletions packages/map-popup/i18n/vi.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
otpUi:
MapPopup:
availableBikes: "Xe đạp có sẵn: {value}"
availableDocks: "Đế sạc có sẵn: {value}"
floatingBike: "Xe đạp nổi tự do: {name}"
floatingCar: "{company} {name}"
floatingEScooter: "{company} Xe tay ga điện"
stopViewer: Trình xem trạm dừng
stopId: "ID điểm dừng: {stopId}"
10 changes: 10 additions & 0 deletions packages/map-popup/i18n/zh_Hans.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
otpUi:
MapPopup:
availableBikes: "可用的自行车: {value}"
availableDocks: "可用的充电座: {value}"
floatingBike: "自由浮动的自行车: {name}"
floatingCar: "{company} {name}" # as in "CarCompany Veh1234a"
floatingEScooter: "{company} 电动滑板车"

stopId: 车站查看器
stopViewer: "车站 ID: {stopId}"
33 changes: 33 additions & 0 deletions packages/map-popup/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
{
"name": "@opentripplanner/map-popup",
"version": "0.0.1",
"description": "A component for displaying map popup contents",
"main": "lib/index.js",
"module": "esm/index.js",
"types": "lib/index.d.js",
"repository": "https://github.com/opentripplanner/otp-ui.git",
"homepage": "https://github.com/opentripplanner/otp-ui#readme",
"author": "Evan Siroky",
"license": "MIT",
"private": false,
"dependencies": {
"@opentripplanner/base-map": "^3.0.7",
"@opentripplanner/core-utils": "^8.0.0",
"@opentripplanner/from-to-location-picker": "^2.1.5",
"flat": "^5.0.2"
},
"devDependencies": {
"@opentripplanner/types": "^4.0.4"
},
"peerDependencies": {
"react": "^16.14.0",
"react-intl": "^5.24.6",
"styled-components": "^5.3.0"
},
"bugs": {
"url": "https://github.com/opentripplanner/otp-ui/issues"
},
"scripts": {
"tsc": "tsc"
}
}
83 changes: 83 additions & 0 deletions packages/map-popup/src/MapPopup.story.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
import React from "react";
import { action } from "@storybook/addon-actions";
import MapPopupContents from "./index";

export default {
title: "Map Popup"
};

const STOP = {
flex: false,
id: "9526",
lat: 45.523009,
lon: -122.672529,
name: "W Burnside & SW 2nd"
};

const STATION = {
"stroke-width": 2,
allowDropoff: true,
allowPickup: true,
bikesAvailable: 6,
color: "#f00",
id: '"hub_1580"',
isCarStation: false,
isFloatingBike: false,
name: "SW Morrison at 18th",
networks: ["BIKETOWN"],
realTimeData: true,
spacesAvailable: 11,
x: -122.6896771788597,
y: 45.5219604810172
};

const FLOATING_VEHICLE = {
"stroke-width": 1,
allowDropoff: false,
allowPickup: true,
bikesAvailable: 1,
color: "#f00",
id: '"bike_6861"',
isCarStation: false,
isFloatingBike: true,
name: "0541 BIKETOWN",
networks: ["BIKETOWN"],
realTimeData: true,
spacesAvailable: 0,
x: -122.70486,
y: 45.525486666666666
};

export const StopEntity = (): JSX.Element => {
return (
<MapPopupContents
entity={STOP}
setLocation={action("setLocation")}
setViewedStop={action("setViewedStop")}
/>
);
};

export const StopEntityNoHandlers = (): JSX.Element => {
return <MapPopupContents entity={STOP} />;
};

export const StationEntity = (): JSX.Element => {
return (
<MapPopupContents
entity={STATION}
setLocation={action("setLocation")}
setViewedStop={action("setViewedStop")}
/>
);
};

export const FloatingVehicleEntity = (): JSX.Element => {
return (
<MapPopupContents
entity={FLOATING_VEHICLE}
setLocation={action("setLocation")}
setViewedStop={action("setViewedStop")}
/>
);
};
2 changes: 2 additions & 0 deletions packages/map-popup/src/__unpublished__/messages.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
// Generic module definition for all YAML file imports.
declare module "*.yml";
136 changes: 136 additions & 0 deletions packages/map-popup/src/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,136 @@
import React from "react";

import { Styled as BaseMapStyled } from "@opentripplanner/base-map";
import FromToLocationPicker from "@opentripplanner/from-to-location-picker";
// eslint-disable-next-line prettier/prettier
import type { Company, ConfiguredCompany, Location, Station, Stop } from "@opentripplanner/types";

import { FormattedMessage, useIntl } from "react-intl";
import { flatten } from "flat";
import * as S from "./styled";

// Load the default messages.
import defaultEnglishMessages from "../i18n/en-US.yml";
import { makeDefaultGetEntityName } from "./util";

// HACK: We should flatten the messages loaded above because
// the YAML loaders behave differently between webpack and our version of jest:
// - the yaml loader for webpack returns a nested object,
// - the yaml loader for jest returns messages with flattened ids.
export const defaultMessages: { [key: string]: string } = flatten(defaultEnglishMessages);


const generateLocation = (entity: Entity, name: string) => {
// @ts-expect-error some of these values may be null, but that's ok
const { lon: entityLon, lat: entityLat, x, y } = entity

const lat = entityLat || x
const lon = entityLon || y
if (!lat || !lon) return null

return { lat, lon, name };
}

const StationHubDetails = ({ station }: { station: Station }) => {
return (
<BaseMapStyled.PopupRow>
<div>
<FormattedMessage
defaultMessage={
defaultMessages["otpUi.MapPopup.availableBikes"]
}
description="Label text for the number of bikes available"
id="otpUi.MapPopup.availableBikes"
values={{ value: station.bikesAvailable }}
/>
</div>
<div>
<FormattedMessage
defaultMessage={
defaultMessages["otpUi.MapPopup.availableDocks"]
}
description="Label text for the number of docks available"
id="otpUi.MapPopup.availableDocks"
values={{ value: station.spacesAvailable }}
/>
</div>
</BaseMapStyled.PopupRow>
)
}

const StopDetails = ({ id, setViewedStop }: { id: string, setViewedStop: ({ stopId }: { stopId: string }) => void; }) => {
return (
<BaseMapStyled.PopupRow>
<strong>
<FormattedMessage
defaultMessage={defaultMessages["otpUi.MapPopup.stopId"]}
description="Displays the stop id"
id="otpUi.MapPopup.stopId"
values={{
stopId: id
}}
/>
</strong>
<S.ViewStopButton onClick={() => setViewedStop({ stopId: id })}>
<FormattedMessage
defaultMessage={defaultMessages["otpUi.MapPopup.stopViewer"]}
description="Text for link that opens the stop viewer"
id="otpUi.MapPopup.stopViewer"
/>
</S.ViewStopButton>
</BaseMapStyled.PopupRow>
)
}

type Entity = Stop | Station
type Props = {
configCompanies?: ConfiguredCompany[];
entity: Entity
getEntityName?: (entity: Entity, configCompanies: Company[],) => string;
setLocation?: ({ location, locationType }: { location: Location, locationType: string }) => void;
setViewedStop?: ({ stopId }: { stopId: string }) => void;
};

/**
* Renders a map popup for a stop, scooter, or shared bike
*/
export function MapPopup({ configCompanies, entity, getEntityName, setLocation, setViewedStop, }: Props): JSX.Element {
const intl = useIntl()
if (!entity) return <></>

const getNameFunc = getEntityName || makeDefaultGetEntityName(intl, defaultMessages);
const name = getNameFunc(entity, configCompanies);


const bikesAvailablePresent = "bikesAvailable" in entity
const entityIsStationHub = bikesAvailablePresent && entity?.bikesAvailable !== undefined && !entity?.isFloatingBike;
// @ts-expect-error ts doesn't understand entityIsStop
const stopId = !bikesAvailablePresent && entity?.code || entity.id.split(":")[1] || entity.id

return (
<BaseMapStyled.MapOverlayPopup>
<BaseMapStyled.PopupTitle>{name}</BaseMapStyled.PopupTitle>
{/* render dock info if it is available */}
{entityIsStationHub && <StationHubDetails station={entity} />}

{/* render stop viewer link if available */}
{setViewedStop && !bikesAvailablePresent && <StopDetails id={stopId} setViewedStop={setViewedStop} />}

{/* The "Set as [from/to]" ButtonGroup */}
{setLocation && (
<BaseMapStyled.PopupRow>
<FromToLocationPicker
label
location={generateLocation(entity, name)}
setLocation={setLocation}
/>
</BaseMapStyled.PopupRow>
)}
</BaseMapStyled.MapOverlayPopup>
);
}

export default MapPopup;

// Rename styled components for export
export { S as Styled };
14 changes: 14 additions & 0 deletions packages/map-popup/src/styled.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import styled from "styled-components";

/* eslint-disable-next-line import/prefer-default-export */
export const ViewStopButton = styled.button`
background: none;
border-bottom: none;
border-left: 1px solid #000;
border-right: none;
border-top: none;
color: #008;
font-family: inherit;
margin-left: 5px;
padding-top: 0;
`;
Loading

0 comments on commit 87d045d

Please sign in to comment.