import { BBox } from 'geojson' ; import React , { ReactElement , useCallback , useContext } from 'react' ; import { useTranslation } from 'react-i18next' ; import { WebMercatorViewport } from 'react-map-gl' ; import { useNavigate , useParams } from 'react-router-dom' ; import { createPOIsEndpoint , defaultViewportConfig , embedInCollection , locationName , MapViewViewport , NotFoundError , pathnameFromRouteInformation , PoiFeature , PoiModel , POIS_ROUTE , useLoadFromEndpoint } from 'api-client' ; import { CityRouteProps } from '../CityContentSwitcher' ; import Caption from '../components/Caption' ; import FailureSwitcher from '../components/FailureSwitcher' ; import { FeedbackRatingType } from '../components/FeedbackToolbarItem' ; import Helmet from '../components/Helmet' ; import List from '../components/List' ; import LoadingSpinner from '../components/LoadingSpinner' ; import LocationLayout from '../components/LocationLayout' ; import LocationToolbar from '../components/LocationToolbar' ; import MapView from '../components/MapView' ; import Page from '../components/Page' ; import PageDetail from '../components/PageDetail' ; import PoiListItem from '../components/PoiListItem' ; import { cmsApiBaseUrl } from '../constants/urls' ; import DateFormatterContext from '../contexts/DateFormatterContext' ; import useWindowDimensions from '../hooks/useWindowDimensions' ; const moveViewToBBox = ( bBox , defaultVp ) : MapViewViewport => { const mercatorVp = new WebMercatorViewport ( defaultVp ) ; return mercatorVp . fitBounds ( [ [ bBox [ 0 ] , bBox [ 1 ] ] , [ bBox [ 2 ] , bBox [ 3 ] ] ] ) ; } ; const PoisPage = ( { cityCode , languageCode , cityModel , pathname , languages } ) : ReactElement => { const { poiId } = useParams ( ) ; const { t } = useTranslation ( 'pois' ) ; const formatter = useContext ( DateFormatterContext ) ; const { viewportSmall } = useWindowDimensions ( ) ; const navigate = useNavigate ( ) ; console . log ( 'To use geolocation in a development build you have to start the dev server with\n "yarn start --https"' ) ; const requestPois = useCallback ( async ( ) => createPOIsEndpoint ( cmsApiBaseUrl ) . request ( { city : cityCode , language : languageCode } ) , [ cityCode , languageCode ] ) ; const { data : pois , loading , error : poisError } = useLoadFromEndpoint ( requestPois ) ; const poi = poiId && pois ?. find ( ( poi ) => poi . path === pathname ) ; const toolbar = ( openFeedback ) => ( < LocationToolbar openFeedbackModal = { openFeedback } viewportSmall = { false } / > ) ; const languageChangePaths = languages . map ( ( { code , name } ) => { const isCurrentLanguage = code === languageCode ; const path = poi ? poi . availableLanguages . get ( code ) || null : pathnameFromRouteInformation ( { route : POIS_ROUTE , cityCode , languageCode : code } ) ; return { path : isCurrentLanguage ? pathname : path , name , code } ; } ) ; const locationLayoutParams = { cityModel , viewportSmall , feedbackTargetInformation : poi ? { path : poi . path } : null , languageChangePaths , route : POIS_ROUTE , languageCode , toolbar } ; if ( loading ) { return ( < LocationLayout isLoading { ... locationLayoutParams } > < LoadingSpinner /> < /LocationLayout>); } if ( ! pois || ( poiId && ! poi ) ) { const error = poisError || new NotFoundError ( { type : 'poi' , id : pathname , city : cityCode , language : languageCode } ) ; return ( < LocationLayout isLoading = { false } { ... locationLayoutParams } > < FailureSwitcher error = { error } /> < /LocationLayout>); } if ( poi ) { const { thumbnail , lastUpdate , content , title , location , featureLocation , urlSlug } = poi ; const pageTitle = `${ title } - ${ cityModel . name }` ; const mapUrlParams = new URLSearchParams ( { [ locationName ] : urlSlug } ) ; const mapLink = `${ pathnameFromRouteInformation ( { route : POIS_ROUTE , cityCode , languageCode } ) }?${ mapUrlParams }` ; return ( < LocationLayout isLoading = { false } { ... locationLayoutParams } > < Helmet pageTitle = { pageTitle } languageChangePaths = { languageChangePaths } cityModel = { cityModel } / > < Page defaultThumbnailSrc = { thumbnail } lastUpdate = { lastUpdate } content = { content } title = { title } formatter = { formatter } onInternalLinkClick = { navigate } > { location . location && ( < PageDetail identifier = { t ( 'location' ) } information = { location . location } link = { featureLocation ? mapLink : undefined } linkLabel = { t ( 'map' ) } / > ) } < /Page> < /LocationLayout>); } const sortedPois = pois . sort ( ( poi1 , poi2 ) => poi1 . title . localeCompare ( poi2 . title ) ) ; const renderPoiListItem = ( poi ) => < PoiListItem key = { poi . path } poi = { poi } / > ; const pageTitle = `${ t ( 'pageTitle' ) } - ${ cityModel . name }` ; const featureLocations = pois . map ( poi => poi . featureLocation ) . filter ( ( feature ) : feature is PoiFeature => ! ! feature ) ; return ( < LocationLayout isLoading = { false } { ... locationLayoutParams } > < Helmet pageTitle = { pageTitle } languageChangePaths = { languageChangePaths } cityModel = { cityModel } / > < Caption title = { t ( 'pois' ) } /> { cityModel . boundingBox && ( < MapView featureCollection = { embedInCollection ( featureLocations ) } bboxViewport = { moveViewToBBox ( cityModel . boundingBox , defaultViewportConfig ) } / > ) } < List noItemsMessage = { t ( 'noPois' ) } items = { sortedPois } renderItem = { renderPoiListItem } / > < /LocationLayout>); } ; export default PoisPage ;