Skip to content

Commit

Permalink
Merge branch 'dev' into weblate
Browse files Browse the repository at this point in the history
  • Loading branch information
binh-dam-ibigroup authored Dec 19, 2024
2 parents b832e45 + d4f9ba8 commit c15562b
Show file tree
Hide file tree
Showing 8 changed files with 371 additions and 340 deletions.
412 changes: 213 additions & 199 deletions __tests__/components/viewers/__snapshots__/nearby-view.js.snap

Large diffs are not rendered by default.

28 changes: 25 additions & 3 deletions lib/components/app/responsive-webapp.js
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,24 @@ class ResponsiveWebapp extends Component {

/** Lifecycle methods **/

// Check if the position has changed enough to update the currentPosition
// (prevent constant updates in nearby view)
// .001 works out to be about 94-300 ft depending on the longitude.
positionShouldUpdate = (position) => {
const { currentPosition } = this.props
if (!currentPosition.coords) return true
const latChanged =
Math.abs(
position?.coords?.latitude - currentPosition?.coords?.latitude
) >= 0.001
const lonChanged =
Math.abs(
position?.coords?.longitude - currentPosition?.coords?.longitude
) >= 0.001

return latChanged || lonChanged
}

/* eslint-disable-next-line complexity */
componentDidUpdate(prevProps) {
const {
Expand Down Expand Up @@ -179,11 +197,13 @@ class ResponsiveWebapp extends Component {
if (isMobile()) {
// Test location availability on load
getCurrentPosition(intl)
// Also, watch for changes in position on mobile
// Watch for position changing on mobile
navigator.geolocation.watchPosition(
// On success
(position) => {
receivedPositionResponse({ position })
if (this.positionShouldUpdate(position)) {
receivedPositionResponse({ position })
}
},
// On error
(error) => {
Expand Down Expand Up @@ -426,10 +446,12 @@ class RouterWrapperWithAuth0 extends Component {
}

const mapStateToWrapperProps = (state) => {
const { homeTimezone, map, persistence, reactRouter } = state.otp.config
const { homeTimezone, location, map, persistence, reactRouter } =
state.otp.config
return {
auth0Config: getAuth0Config(persistence),
autoFly: map.autoFlyOnTripFormUpdate,
currentPosition: location?.currentPosition,
defaultLocale: getDefaultLocale(state.otp.config, state.user.loggedInUser),
homeTimezone,
locale: state.otp.ui.locale,
Expand Down
2 changes: 1 addition & 1 deletion lib/components/mobile/navigation-bar.js
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ class MobileNavigationBar extends Component {
const backButtonText = intl.formatMessage({ id: 'common.forms.back' })

return (
<header>
<header style={{ height: '50px' }}>
<Navbar className="mobile-navbar-container" fixedTop fluid>
<Navbar.Header>
<Navbar.Brand>
Expand Down
79 changes: 61 additions & 18 deletions lib/components/viewers/nearby/nearby-view.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,21 @@ import { connect } from 'react-redux'
import { FormattedMessage, useIntl } from 'react-intl'
import { Location } from '@opentripplanner/types'
import { MapRef, useMap } from 'react-map-gl'
import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react'
import coreUtils from '@opentripplanner/core-utils'
import React, { useCallback, useEffect, useMemo, useState } from 'react'

import * as apiActions from '../../../actions/api'
import * as mapActions from '../../../actions/map'
import * as uiActions from '../../../actions/ui'
import { AppReduxState } from '../../../util/state-types'
import { getCurrentServiceWeek } from '../../../util/current-service-week'
import { SetLocationHandler, ZoomToPlaceHandler } from '../../util/types'
import { NearbyViewConfig } from '../../../util/config-types'
import {
PatternStopTime,
SetLocationHandler,
ZoomToPlaceHandler
} from '../../util/types'
import InvisibleA11yLabel from '../../util/invisible-a11y-label'
import Loading from '../../narrative/loading'
import MobileContainer from '../../mobile/container'
import MobileNavigationBar from '../../mobile/navigation-bar'
Expand All @@ -23,11 +30,11 @@ import {
} from './styled'
import FromToPicker from './from-to-picker'
import RentalStation from './rental-station'
import Stop from './stop'
import Stop, { fullTimestamp, patternArrayforStops } from './stop'
import Vehicle from './vehicle-rent'
import VehicleParking from './vehicle-parking'

const AUTO_REFRESH_INTERVAL = 15000
const AUTO_REFRESH_INTERVAL = 15000000

// TODO: use lonlat package
type LatLonObj = { lat: number; lon: number }
Expand All @@ -48,9 +55,12 @@ type Props = {
hideBackButton?: boolean
location: string
mobile?: boolean
// Todo: type nearby results
nearby: any
nearbyViewConfig?: NearbyViewConfig
nearbyViewCoords?: LatLonObj
radius?: number
routeSortComparator: (a: PatternStopTime, b: PatternStopTime) => number
setHighlightedLocation: (location: Location | null) => void
setLocation: SetLocationHandler
setMainPanelContent: (content: number) => void
Expand Down Expand Up @@ -117,8 +127,10 @@ function NearbyView({
location,
mobile,
nearby,
nearbyViewConfig,
nearbyViewCoords,
radius,
routeSortComparator,
setHighlightedLocation,
setMainPanelContent,
setViewedNearbyCoords,
Expand All @@ -127,7 +139,6 @@ function NearbyView({
const map = useMap().default
const intl = useIntl()
const [loading, setLoading] = useState(true)
const firstItemRef = useRef<HTMLDivElement>(null)
const finalNearbyCoords = useMemo(
() =>
getNearbyCoordsFromUrlOrLocationOrMapCenter(
Expand Down Expand Up @@ -179,9 +190,11 @@ function NearbyView({
}, [map, setViewedNearbyCoords, setHighlightedLocation])

useEffect(() => {
if (typeof firstItemRef.current?.scrollIntoView === 'function') {
firstItemRef.current?.scrollIntoView({ behavior: 'smooth' })
}
window.scrollTo({
behavior: 'smooth',
left: 0,
top: 0
})
if (finalNearbyCoords) {
fetchNearby(finalNearbyCoords, radius, currentServiceWeek)
setLoading(true)
Expand Down Expand Up @@ -222,9 +235,19 @@ function NearbyView({
.flat(Infinity)
)
)

// If configured, filter out stops that don't have any patterns
const filteredNearby = nearby?.filter((n: any) => {
if (n.place.__typename === 'Stop' && nearbyViewConfig?.hideEmptyStops) {
const patternArray = patternArrayforStops(n.place, routeSortComparator)
return !(patternArray?.length === 0)
}
return true
})

const nearbyItemList =
nearby?.map &&
nearby?.map((n: any) => (
filteredNearby?.map &&
filteredNearby?.map((n: any) => (
<li
className={
(n.place.gtfsId ?? n.place.id) === entityId ? 'highlighted' : ''
Expand All @@ -249,6 +272,11 @@ function NearbyView({
useEffect(() => {
if (!staleData) {
setLoading(false)
} else if (staleData) {
// If there's stale data, fetch again
setLoading(true)
finalNearbyCoords &&
fetchNearby(finalNearbyCoords, radius, currentServiceWeek)
}
}, [nearby, staleData])

Expand All @@ -273,19 +301,17 @@ function NearbyView({
/>
)}
{nearby && (
<h3 style={{ opacity: 0, position: 'absolute' }}>
<InvisibleA11yLabel as="h3" style={{ position: 'absolute' }}>
<FormattedMessage
id="components.NearbyView.nearbyListIntro"
values={{ count: nearby.length }}
/>
</h3>
</InvisibleA11yLabel>
)}
<NearbySidebarContainer
className="base-color-bg"
style={{ marginTop: mobile ? '50px' : 0 }}
style={{ marginBottom: 0 }}
>
{/* This is used to scroll to top */}
<div aria-hidden ref={firstItemRef} />
{loading && (
<FloatingLoadingIndicator>
<Loading extraSmall />
Expand All @@ -295,7 +321,7 @@ function NearbyView({
!staleData &&
(nearby.error ? (
intl.formatMessage({ id: 'components.NearbyView.error' })
) : nearby.length > 0 ? (
) : filteredNearby?.length > 0 ? (
nearbyItemList
) : (
<FormattedMessage id="components.NearbyView.nothingNearby" />
Expand All @@ -308,7 +334,8 @@ function NearbyView({

const mapStateToProps = (state: AppReduxState) => {
const { config, location, transitIndex, ui } = state.otp
const { map, routeViewer } = config
const { map, nearbyView: nearbyViewConfig, routeViewer } = config
const transitOperators = config?.transitOperators || []
const { nearbyViewCoords } = ui
const { nearby } = transitIndex
const { entityId } = state.router.location.query
Expand All @@ -321,6 +348,20 @@ const mapStateToProps = (state: AppReduxState) => {
? getCurrentServiceWeek()
: undefined

// TODO: Refine so we don't have this same thing in stops.tsx
// Default sort: departure time
let routeSortComparator = (a: PatternStopTime, b: PatternStopTime) =>
fullTimestamp(a.stoptimes?.[0]) - fullTimestamp(b.stoptimes?.[0])

if (nearbyViewConfig?.useRouteViewSort) {
routeSortComparator = (a: PatternStopTime, b: PatternStopTime) =>
coreUtils.route.makeRouteComparator(transitOperators)(
// @ts-expect-error core-utils types are wrong!
a.pattern.route,
b.pattern.route
)
}

return {
currentPosition,
currentServiceWeek,
Expand All @@ -330,8 +371,10 @@ const mapStateToProps = (state: AppReduxState) => {
homeTimezone: config.homeTimezone,
location: state.router.location.hash,
nearby: nearby?.data,
nearbyViewConfig,
nearbyViewCoords,
radius: config.nearbyView?.radius
radius: config.nearbyView?.radius,
routeSortComparator
}
}

Expand Down
75 changes: 40 additions & 35 deletions lib/components/viewers/nearby/stop.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ import StopCardHeader from './stop-card-header'

const { getUserTimezone } = coreUtils.time

const fullTimestamp = (stoptime: StopTime) =>
export const fullTimestamp = (stoptime: StopTime) =>
(stoptime.serviceDay || 0) + (stoptime.realtimeDeparture || 0)

type Props = {
Expand All @@ -27,14 +27,11 @@ type Props = {
stopData: StopData & { nearbyRoutes?: string[] }
}

const Stop = ({
fromToSlot,
homeTimezone,
nearbyViewConfig,
routeSortComparator,
stopData
}: Props): JSX.Element => {
const patternRows = (stopData.stoptimesForPatterns || [])
export const patternArrayforStops = (
stopData: StopData & { nearbyRoutes?: string[] },
routeSortComparator: (a: PatternStopTime, b: PatternStopTime) => number
): Array<PatternStopTime> | undefined => {
return stopData?.stoptimesForPatterns
?.reduce<PatternStopTime[]>((acc, cur) => {
const currentHeadsign = extractHeadsignFromPattern(cur.pattern)
const dupe = acc.findIndex((p) => {
Expand Down Expand Up @@ -65,39 +62,47 @@ const Stop = ({
return acc
}, [])
.sort(routeSortComparator)
.map((st: any, index: number) => {
const sortedStopTimes = st.stoptimes.sort(
(a: StopTime, b: StopTime) => fullTimestamp(a) - fullTimestamp(b)
)
if (
// NearbyRoutes if present is populated with a list of routes that appear
// in the current service period.
stopData.nearbyRoutes &&
!stopData.nearbyRoutes.includes(st?.pattern?.route?.gtfsId)
) {
return <></>
}
return (
<PatternRow
alwaysShowLongName={nearbyViewConfig?.alwaysShowLongName}
homeTimezone={homeTimezone}
key={index}
pattern={st.pattern}
roundedTop={false}
route={st.pattern.route}
stopTimes={sortedStopTimes}
/>
)
})
}

const Stop = ({
fromToSlot,
homeTimezone,
nearbyViewConfig,
routeSortComparator,
stopData
}: Props): JSX.Element => {
const patternArray = patternArrayforStops(stopData, routeSortComparator)
const patternRows = patternArray?.map((st: any, index: number) => {
const sortedStopTimes = st.stoptimes.sort(
(a: StopTime, b: StopTime) => fullTimestamp(a) - fullTimestamp(b)
)
if (
// NearbyRoutes if present is populated with a list of routes that appear
// in the current service period.
stopData.nearbyRoutes &&
!stopData.nearbyRoutes.includes(st?.pattern?.route?.gtfsId)
) {
return <></>
}
return (
<PatternRow
alwaysShowLongName={nearbyViewConfig?.alwaysShowLongName}
homeTimezone={homeTimezone}
key={index}
pattern={st.pattern}
roundedTop={false}
route={st.pattern.route}
stopTimes={sortedStopTimes}
/>
)
})
const inHomeTimezone = homeTimezone && homeTimezone === getUserTimezone()
const timezoneWarning = !inHomeTimezone && (
<StyledAlert>
<TimezoneWarning homeTimezone={homeTimezone} />
</StyledAlert>
)

if (nearbyViewConfig?.hideEmptyStops && patternRows.length === 0) return <></>

return (
<Card>
<StopCardHeader
Expand Down
12 changes: 12 additions & 0 deletions lib/components/viewers/nearby/styled.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,18 @@ export const NearbySidebarContainer = styled.ol`
gap: 1em;
padding: 0 1em;
list-style: none;
& > li:last-of-type {
margin-bottom: 1em;
}
& > li:first-of-type {
margin-top: 1em;
}
@media (max-width: 768px) {
min-height: calc(100vh - 50px);
}
`

export const Card = styled.div`
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@
"@opentripplanner/humanize-distance": "^1.2.0",
"@opentripplanner/icons": "3.0.1",
"@opentripplanner/location-field": "3.1.1",
"@opentripplanner/itinerary-body": "6.1.0",
"@opentripplanner/itinerary-body": "6.1.1",
"@opentripplanner/location-icon": "^1.4.1",
"@opentripplanner/map-popup": "5.1.1",
"@opentripplanner/otp2-tile-overlay": "2.1.1",
Expand Down
Loading

0 comments on commit c15562b

Please sign in to comment.