import React, { useCallback } from "react";
import FromToLocationPicker from "@opentripplanner/from-to-location-picker";
import { RentalVehicle, VehicleRentalStation } from "@opentripplanner/types/otp2";
// eslint-disable-next-line prettier/prettier
import type {
Company,
ConfiguredCompany,
Location,
Stop,
StopEventHandler,
} from "@opentripplanner/types";
import { FocusTrapWrapper } from "@opentripplanner/building-blocks";
import { flatten } from "flat";
import { FormattedMessage, useIntl } from "react-intl";
import { Styled } from "@opentripplanner/base-map";
import coreUtils from "@opentripplanner/core-utils";
import { makeDefaultGetEntityName, type StopIdAgencyMap } from "./util";
import { ViewStopButton } from "./styled";
// Load the default messages.
import defaultEnglishMessages from "../i18n/en-US.yml";
// 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);
export type Feed = {
feedId: string;
publisher: {
name: string;
};
};
const generateLocation = (entity: MapPopupEntity, 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 || y
const lon = entityLon || x
if (!lat || !lon) return null
return { lat, lon, name };
}
const StationHubDetails = ({ availableVehicles, availableSpaces }: { availableVehicles: number, availableSpaces: number }) => {
return (
)
}
const StopDetails = ({ id, feedName, setViewedStop }: { id: string, feedName?: string, setViewedStop: () => void; }) => {
return (
{id &&
}
)
}
type MapPopupEntity = Stop | VehicleRentalStation | RentalVehicle
type Props = {
closePopup?: (arg?: boolean) => void
configCompanies?: ConfiguredCompany[];
entity: MapPopupEntity
getEntityName?: (entity: MapPopupEntity, configCompanies: Company[], feedName?: string, includeParenthetical?: boolean) => string;
getEntityPrefix?: (entity: MapPopupEntity) => JSX.Element
feeds?: Feed[]
setLocation?: ({ location, locationType }: { location: Location, locationType: string }) => void;
setViewedStop?: StopEventHandler;
};
const entityIsStop = (entity: MapPopupEntity): entity is Stop => "gtfsId" in entity;
/**
* Renders a map popup for a stop, scooter, or shared bike
*/
export function MapPopup({
closePopup = () => {},
configCompanies,
entity,
getEntityName,
getEntityPrefix,
setLocation,
setViewedStop,
feeds,
}: Props): JSX.Element {
const intl = useIntl()
if (!entity) return <>>
const getNameFunc = getEntityName || makeDefaultGetEntityName(intl, defaultMessages);
// Find the feed name using the logic from generateLabel in otp.ts
let feedName: string | undefined;
if (feeds && entity.id) {
const feedId = entity.id.split(":")[0];
const feed = feeds.find(f => f.feedId === feedId);
feedName = feed?.publisher?.name;
}
const name = getNameFunc(entity, configCompanies, feedName);
const titleName = getNameFunc(entity, configCompanies, feedName, false);
const stationNetwork = "rentalNetwork" in entity && (coreUtils.itinerary.getCompaniesLabelFromNetworks(entity?.rentalNetwork?.networkId, configCompanies) || entity?.rentalNetwork?.networkId);
const vehiclesAvailable = "availableVehicles" in entity;
const entityIsStationHub = vehiclesAvailable && entity?.availableVehicles !== undefined;
const stopId = entityIsStop(entity) ? entity.code : "";
const id = `focus-${encodeURIComponent(entity.id).replace(/%/g, "")}-popup`
return (
{getEntityPrefix && getEntityPrefix(entity)}
{/* render dock info if it is available */}
{entityIsStationHub && }
{/* render stop viewer link if available */}
{setViewedStop && entityIsStop(entity) && (
setViewedStop(entity as Stop), [entity])}
/>
)}
{/* The "Set as [from/to]" ButtonGroup */}
{setLocation && (
)}
);
}
export default MapPopup;
export { type StopIdAgencyMap };