mirror of
https://github.com/HSLdevcom/digitransit-ui
synced 2025-07-05 16:30:37 +02:00
147 lines
3.8 KiB
JavaScript
147 lines
3.8 KiB
JavaScript
import PropTypes from 'prop-types';
|
|
import React from 'react';
|
|
import { createFragmentContainer, graphql } from 'react-relay';
|
|
import connectToStores from 'fluxible-addons-react/connectToStores';
|
|
import isEmpty from 'lodash/isEmpty';
|
|
import { configShape, alertShape } from '../util/shapes';
|
|
import { isAlertValid } from '../util/alertUtils';
|
|
import DisruptionBannerAlert from './DisruptionBannerAlert';
|
|
import SwipeableTabs from './SwipeableTabs';
|
|
import withBreakpoint from '../util/withBreakpoint';
|
|
import { AlertEntityType } from '../constants';
|
|
|
|
class DisruptionBanner extends React.Component {
|
|
constructor(props) {
|
|
super(props);
|
|
this.state = {
|
|
allAlertsOpen: false,
|
|
tabIndex: 0,
|
|
isOpen: true,
|
|
};
|
|
}
|
|
|
|
static propTypes = {
|
|
alerts: PropTypes.arrayOf(alertShape).isRequired,
|
|
currentTime: PropTypes.number.isRequired,
|
|
language: PropTypes.string.isRequired,
|
|
mode: PropTypes.string.isRequired,
|
|
breakpoint: PropTypes.string.isRequired,
|
|
};
|
|
|
|
static contextTypes = {
|
|
config: configShape.isRequired,
|
|
};
|
|
|
|
openAllAlerts = () => {
|
|
this.setState({ allAlertsOpen: true });
|
|
};
|
|
|
|
onSwipe = i => {
|
|
this.setState({ tabIndex: i });
|
|
};
|
|
|
|
getAlerts() {
|
|
const { alerts } = this.props;
|
|
const activeAlerts = [];
|
|
alerts.forEach(alert => {
|
|
if (
|
|
alert?.entities.some(
|
|
e =>
|
|
// eslint-disable-next-line no-underscore-dangle
|
|
e.__typename === AlertEntityType.Route &&
|
|
e.mode === this.props.mode,
|
|
) &&
|
|
!isEmpty(alert.alertDescriptionText) &&
|
|
isAlertValid(alert, this.props.currentTime)
|
|
) {
|
|
if (
|
|
!activeAlerts.find(
|
|
activeAlert =>
|
|
activeAlert.alertDescriptionText === alert.alertDescriptionText,
|
|
)
|
|
) {
|
|
activeAlerts.push(alert);
|
|
}
|
|
}
|
|
});
|
|
return activeAlerts;
|
|
}
|
|
|
|
renderAlert = alert => {
|
|
return (
|
|
<div key={alert.id}>
|
|
<DisruptionBannerAlert
|
|
language={this.props.language}
|
|
alert={alert}
|
|
truncate={!this.state.allAlertsOpen}
|
|
openAllAlerts={this.openAllAlerts}
|
|
onClose={() => this.setState({ isOpen: false })}
|
|
/>
|
|
</div>
|
|
);
|
|
};
|
|
|
|
render() {
|
|
const activeAlerts = this.getAlerts();
|
|
|
|
if (!activeAlerts.length || !this.state.isOpen) {
|
|
return null;
|
|
}
|
|
const tabs = activeAlerts.map(alert => this.renderAlert(alert));
|
|
|
|
return (
|
|
<div className="disruption-banner-container">
|
|
{tabs.length > 1 ? (
|
|
<SwipeableTabs
|
|
tabs={tabs}
|
|
tabIndex={this.state.tabIndex}
|
|
onSwipe={this.onSwipe}
|
|
classname="disruption-banner"
|
|
hideArrows={this.props.breakpoint !== 'large'}
|
|
navigationOnBottom
|
|
ariaFrom="swipe-disruption-info"
|
|
ariaFromHeader="swipe-disruption-info-header"
|
|
/>
|
|
) : (
|
|
this.renderAlert(activeAlerts[0])
|
|
)}
|
|
</div>
|
|
);
|
|
}
|
|
}
|
|
const DisruptionBannerWithBreakpoint = withBreakpoint(DisruptionBanner);
|
|
|
|
const containerComponent = createFragmentContainer(
|
|
connectToStores(
|
|
DisruptionBannerWithBreakpoint,
|
|
['TimeStore', 'PreferencesStore'],
|
|
({ getStore }) => ({
|
|
currentTime: getStore('TimeStore').getCurrentTime(),
|
|
language: getStore('PreferencesStore').getLanguage(),
|
|
}),
|
|
),
|
|
{
|
|
alerts: graphql`
|
|
fragment DisruptionBanner_alerts on Alert @relay(plural: true) {
|
|
feed
|
|
id
|
|
alertSeverityLevel
|
|
alertHeaderText
|
|
alertEffect
|
|
alertCause
|
|
alertDescriptionText
|
|
effectiveStartDate
|
|
effectiveEndDate
|
|
entities {
|
|
__typename
|
|
... on Route {
|
|
mode
|
|
shortName
|
|
}
|
|
}
|
|
}
|
|
`,
|
|
},
|
|
);
|
|
|
|
export { containerComponent as default, DisruptionBanner as Component };
|