Skip to content

Commit d9cbeb7

Browse files
Feat: gbfs validator header navigation (#1406)
* gbfs validator feature flag * gbfs validator header nav * existing demo content * gtfs and gtfs rt external validators linked
1 parent 9c6daad commit d9cbeb7

File tree

12 files changed

+888
-6
lines changed

12 files changed

+888
-6
lines changed

web-app/public/locales/en/common.json

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -92,5 +92,9 @@
9292
"description": "Railway in which the track consists of a single rail or a beam."
9393
}
9494
}
95-
}
95+
},
96+
"validators": "Validators",
97+
"gbfsValidator": "GBFS Validator",
98+
"gtfsValidator": "GTFS Validator",
99+
"gtfsRtValidator": "GTFS RT Validator"
96100
}

web-app/src/app/components/Header.tsx

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import {
1212
MenuItem,
1313
Select,
1414
useTheme,
15+
Link,
1516
} from '@mui/material';
1617
import MenuIcon from '@mui/icons-material/Menu';
1718
import ArrowDropDownIcon from '@mui/icons-material/ArrowDropDown';
@@ -34,11 +35,13 @@ import { useRemoteConfig } from '../context/RemoteConfigProvider';
3435
import i18n from '../../i18n';
3536
import { NestedMenuItem } from 'mui-nested-menu';
3637
import DirectionsBusIcon from '@mui/icons-material/DirectionsBus';
38+
import DepartureBoardIcon from '@mui/icons-material/DepartureBoard';
3739
import { fontFamily } from '../Theme';
3840
import { defaultRemoteConfigValues } from '../interface/RemoteConfig';
3941
import { animatedButtonStyling } from './Header.style';
4042
import DrawerContent from './HeaderMobileDrawer';
4143
import ThemeToggle from './ThemeToggle';
44+
import { useTranslation } from 'react-i18next';
4245

4346
export default function DrawerAppBar(): React.ReactElement {
4447
const theme = useTheme();
@@ -53,6 +56,7 @@ export default function DrawerAppBar(): React.ReactElement {
5356
string | undefined
5457
>(i18n.language);
5558
const { config } = useRemoteConfig();
59+
const { t } = useTranslation('common');
5660

5761
i18n.on('languageChanged', (lang) => {
5862
setCurrentLanguage(i18n.language);
@@ -200,6 +204,67 @@ export default function DrawerAppBar(): React.ReactElement {
200204
{item.title}
201205
</Button>
202206
))}
207+
{config.gbfsValidator && (
208+
<>
209+
<Button
210+
aria-controls='validator-menu'
211+
aria-haspopup='true'
212+
endIcon={<ArrowDropDownIcon />}
213+
onClick={handleMenuOpen}
214+
sx={(theme) => ({
215+
...animatedButtonStyling(theme),
216+
color: theme.palette.text.primary,
217+
})}
218+
id='validator-button-menu'
219+
className={
220+
activeTab.includes('validator') ? 'active short' : ''
221+
}
222+
>
223+
{t('validators')}
224+
</Button>
225+
<Menu
226+
id='validator-menu'
227+
anchorEl={anchorEl}
228+
open={
229+
anchorEl !== null && anchorEl.id === 'validator-button-menu'
230+
}
231+
onClose={handleMenuClose}
232+
>
233+
<MenuItem
234+
key={'gbfs-validator'}
235+
onClick={() => {
236+
handleMenuItemClick('gbfs-validator');
237+
}}
238+
sx={{ display: 'flex', gap: 1 }}
239+
>
240+
<BikeScooterOutlined fontSize='small' />
241+
{t('gbfsValidator')}
242+
</MenuItem>
243+
<MenuItem
244+
key={'gtfs-validator'}
245+
component={Link}
246+
href='https://gtfs-validator.mobilitydata.org/'
247+
target='_blank'
248+
rel='noopener noreferrer'
249+
>
250+
<DirectionsBusIcon fontSize='small' sx={{ mr: 1 }} />
251+
{t('gtfsValidator')}
252+
<OpenInNew fontSize='small' sx={{ ml: 0.5 }} />
253+
</MenuItem>
254+
<MenuItem
255+
key={'gtfs-rt-validator'}
256+
component={Link}
257+
href='https://github.com/MobilityData/gtfs-realtime-validator'
258+
target='_blank'
259+
rel='noopener noreferrer'
260+
>
261+
<DepartureBoardIcon fontSize='small' sx={{ mr: 1 }} />
262+
{t('gtfsRtValidator')}
263+
<OpenInNew fontSize='small' sx={{ ml: 0.5 }} />
264+
</MenuItem>
265+
</Menu>
266+
</>
267+
)}
203268
{/* Allow users with mobilitydata.org email to access metrics */}
204269
{metricsOptionsEnabled && (
205270
<>

web-app/src/app/components/HeaderMobileDrawer.tsx

Lines changed: 54 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import {
99
AccordionSummary,
1010
AccordionDetails,
1111
useTheme,
12+
Link,
1213
} from '@mui/material';
1314
import { useSelector } from 'react-redux';
1415
import { useNavigate } from 'react-router-dom';
@@ -23,6 +24,8 @@ import { selectIsAuthenticated } from '../store/profile-selectors';
2324
import { fontFamily } from '../Theme';
2425
import { mobileNavElementStyle } from './Header.style';
2526
import ExpandMoreIcon from '@mui/icons-material/ExpandMore';
27+
import { useRemoteConfig } from '../context/RemoteConfigProvider';
28+
import { useTranslation } from 'react-i18next';
2629

2730
const websiteTile = 'Mobility Database';
2831

@@ -39,6 +42,8 @@ export default function DrawerContent({
3942
}: DrawerContentProps): JSX.Element {
4043
const isAuthenticated = useSelector(selectIsAuthenticated);
4144
const navigateTo = useNavigate();
45+
const { config } = useRemoteConfig();
46+
const { t } = useTranslation('common');
4247
const theme = useTheme();
4348

4449
return (
@@ -95,7 +100,55 @@ export default function DrawerContent({
95100
{item.title}
96101
</Button>
97102
))}
103+
98104
<Divider sx={{ mt: 2 }} />
105+
{config.gbfsValidator && (
106+
<Accordion disableGutters={true} sx={{ boxShadow: 'none' }}>
107+
<AccordionSummary
108+
expandIcon={<ExpandMoreIcon />}
109+
aria-controls='validators-content'
110+
id='validators-content'
111+
>
112+
<Typography
113+
variant={'subtitle1'}
114+
sx={{ fontFamily: fontFamily.secondary }}
115+
>
116+
{t('validators')}
117+
</Typography>
118+
</AccordionSummary>
119+
<AccordionDetails>
120+
<Button
121+
variant='text'
122+
sx={mobileNavElementStyle}
123+
href={'gbfs-validator'}
124+
>
125+
{t('gbfsValidator')}
126+
</Button>
127+
<Button
128+
variant='text'
129+
sx={mobileNavElementStyle}
130+
endIcon={<OpenInNew />}
131+
component={Link}
132+
href='https://gtfs-validator.mobilitydata.org/'
133+
target='_blank'
134+
rel='noopener noreferrer'
135+
>
136+
{t('gtfsValidator')}
137+
</Button>
138+
<Button
139+
variant='text'
140+
sx={mobileNavElementStyle}
141+
endIcon={<OpenInNew />}
142+
component={Link}
143+
href='https://github.com/MobilityData/gtfs-realtime-validator'
144+
target='_blank'
145+
rel='noopener noreferrer'
146+
>
147+
{t('gtfsRtValidator')}
148+
</Button>
149+
</AccordionDetails>
150+
</Accordion>
151+
)}
99152
{metricsOptionsEnabled && (
100153
<>
101154
<Accordion disableGutters={true} sx={{ boxShadow: 'none' }}>
@@ -185,11 +238,7 @@ export default function DrawerContent({
185238
</AccordionDetails>
186239
</Accordion>
187240
) : (
188-
<Button
189-
variant='text'
190-
sx={mobileNavElementStyle}
191-
href={SIGN_IN_TARGET}
192-
>
241+
<Button variant='contained' sx={{ ml: 2 }} href={SIGN_IN_TARGET}>
193242
Login
194243
</Button>
195244
)}

web-app/src/app/interface/RemoteConfig.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ export interface RemoteConfigValues extends FirebaseDefaultConfig {
4545
// 1- hides/shows the toggle button for gtfs feeds
4646
// 2- use bounding box view for GBFS instead of full covered area map
4747
enableDetailedCoveredArea: boolean;
48+
gbfsValidator: boolean;
4849
}
4950

5051
const featureByPassDefault: BypassConfig = {
@@ -74,6 +75,7 @@ export const defaultRemoteConfigValues: RemoteConfigValues = {
7475
visualizationMapFullDataLimit: 5,
7576
visualizationMapPreviewDataLimit: 3,
7677
enableDetailedCoveredArea: false,
78+
gbfsValidator: false,
7779
};
7880

7981
remoteConfig.defaultConfig = defaultRemoteConfigValues;

web-app/src/app/router/Router.tsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ import GBFSNoticeAnalytics from '../screens/Analytics/GBFSNoticeAnalytics';
3535
import GBFSVersionAnalytics from '../screens/Analytics/GBFSVersionAnalytics';
3636
import ContactUs from '../screens/ContactUs';
3737
import FullMapView from '../screens/Feed/components/FullMapView';
38+
import GbfsValidator from '../screens/GbfsValidator';
3839

3940
export const AppRouter: React.FC = () => {
4041
const navigateTo = useNavigate();
@@ -92,6 +93,7 @@ export const AppRouter: React.FC = () => {
9293
<Route path='about' element={<About />} />
9394
<Route path='contact-us' element={<ContactUs />} />
9495
<Route path='feeds' element={<Feeds />} />
96+
<Route path='gbfs-validator' element={<GbfsValidator />} />
9597
<Route
9698
path='feeds/gtfs'
9799
element={<Navigate to='/feeds?gtfs=true' replace />}

0 commit comments

Comments
 (0)