mirror of
https://github.com/HSLdevcom/digitransit-ui
synced 2025-11-29 17:03:33 +01:00
163 lines
4.3 KiB
JavaScript
163 lines
4.3 KiB
JavaScript
import PropTypes from 'prop-types';
|
|
import React, { useRef, useState } from 'react';
|
|
import { isAnyLegPropertyIdentical, isRental } from '../../../util/legUtils';
|
|
import { getRouteMode, transitIconName } from '../../../util/modeUtils';
|
|
import { configShape, legShape } from '../../../util/shapes';
|
|
import Icon from '../../Icon';
|
|
import NaviCardExtension from './NaviCardExtension';
|
|
import NaviInstructions from './NaviInstructions';
|
|
import { LEGTYPE } from './NaviUtils';
|
|
import usePrevious from './hooks/usePrevious';
|
|
|
|
const iconMap = {
|
|
BICYCLE: 'icon_cyclist',
|
|
CAR: 'icon_car',
|
|
SCOOTER: 'icon_scooter_rider',
|
|
WALK: 'icon_walk',
|
|
WAIT: 'icon_navigation_wait',
|
|
CALL: 'icon_call',
|
|
WAIT_IN_VEHICLE: 'icon_wait',
|
|
};
|
|
|
|
export default function NaviCard(
|
|
{
|
|
leg,
|
|
nextLeg,
|
|
legType,
|
|
time,
|
|
position,
|
|
tailLength,
|
|
cardAnimation,
|
|
platformUpdated,
|
|
},
|
|
{ config },
|
|
) {
|
|
const [cardExpanded, setCardExpanded] = useState(false);
|
|
const contentRef = useRef();
|
|
const { isEqual: legChanged } = usePrevious(leg, (prev, current) =>
|
|
isAnyLegPropertyIdentical(prev, current, ['legId', 'mode']),
|
|
);
|
|
|
|
const handleClick = () => {
|
|
setCardExpanded(prev => !prev);
|
|
};
|
|
|
|
if (legChanged) {
|
|
setCardExpanded(false);
|
|
}
|
|
|
|
if (
|
|
(!leg && !nextLeg) ||
|
|
legType === LEGTYPE.PENDING ||
|
|
legType === LEGTYPE.END
|
|
) {
|
|
return null;
|
|
}
|
|
|
|
let iconColor = 'currentColor';
|
|
let iconName;
|
|
let instructions = '';
|
|
|
|
if (legType === LEGTYPE.TRANSIT) {
|
|
const m = getRouteMode(leg.route, config);
|
|
iconColor = config.colors.iconColors[`mode-${m}`] || leg.route.color;
|
|
iconName = transitIconName(m, false);
|
|
instructions = `navileg-in-transit`;
|
|
} else if (
|
|
legType !== LEGTYPE.WAIT &&
|
|
legType !== LEGTYPE.WAIT_IN_VEHICLE &&
|
|
isRental(leg, nextLeg)
|
|
) {
|
|
if (leg.mode === 'WALK' && nextLeg?.mode === 'SCOOTER') {
|
|
instructions = `navileg-rent-scooter`;
|
|
} else {
|
|
instructions = 'navileg-rent-cycle';
|
|
}
|
|
iconName = iconMap[leg.mode];
|
|
} else if (legType === LEGTYPE.MOVE) {
|
|
instructions = `navileg-${leg.mode.toLowerCase()}`;
|
|
iconName = iconMap[leg.mode] || iconMap.WALK;
|
|
} else if (legType === LEGTYPE.WAIT) {
|
|
iconName = iconMap.WAIT;
|
|
} else if (legType === LEGTYPE.WAIT_IN_VEHICLE) {
|
|
iconName = iconMap.WAIT_IN_VEHICLE;
|
|
}
|
|
|
|
const maxHeight = cardExpanded
|
|
? `${contentRef.current?.scrollHeight}px`
|
|
: '0px';
|
|
|
|
return (
|
|
<button
|
|
type="button"
|
|
className={`navi-top-card ${cardAnimation}`}
|
|
onClick={handleClick}
|
|
aria-expanded={cardExpanded}
|
|
aria-controls={`navi-card-content-${leg?.legId}`}
|
|
>
|
|
<div className="main-card">
|
|
<div className="content">
|
|
<Icon img={iconName} className="mode" color={iconColor} omitViewBox />
|
|
<div className={`instructions ${cardExpanded ? 'expanded' : ''}`}>
|
|
<NaviInstructions
|
|
leg={leg}
|
|
nextLeg={nextLeg}
|
|
instructions={instructions}
|
|
legType={legType}
|
|
time={time}
|
|
position={position}
|
|
tailLength={tailLength}
|
|
/>
|
|
</div>
|
|
<div type="button" className="navi-top-card-arrow">
|
|
<Icon
|
|
img="icon_arrow-collapse"
|
|
className={`cursor-pointer ${cardExpanded ? 'inverted' : ''}`}
|
|
/>
|
|
</div>
|
|
</div>
|
|
<div
|
|
id={`navi-card-content-${leg?.legId}`}
|
|
className="extension"
|
|
style={{
|
|
maxHeight,
|
|
}}
|
|
ref={contentRef}
|
|
aria-hidden={!cardExpanded}
|
|
>
|
|
<NaviCardExtension
|
|
legType={legType}
|
|
leg={leg}
|
|
nextLeg={nextLeg}
|
|
time={time}
|
|
platformUpdated={platformUpdated}
|
|
/>
|
|
</div>
|
|
</div>
|
|
</button>
|
|
);
|
|
}
|
|
|
|
NaviCard.propTypes = {
|
|
leg: legShape,
|
|
nextLeg: legShape,
|
|
legType: PropTypes.string.isRequired,
|
|
time: PropTypes.number.isRequired,
|
|
position: PropTypes.shape({
|
|
lat: PropTypes.number,
|
|
lon: PropTypes.number,
|
|
}),
|
|
tailLength: PropTypes.number.isRequired,
|
|
cardAnimation: PropTypes.string.isRequired,
|
|
platformUpdated: PropTypes.bool,
|
|
};
|
|
NaviCard.defaultProps = {
|
|
leg: undefined,
|
|
nextLeg: undefined,
|
|
position: undefined,
|
|
platformUpdated: false,
|
|
};
|
|
|
|
NaviCard.contextTypes = {
|
|
config: configShape.isRequired,
|
|
};
|