Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

561 add home breadcrumb #621

Open
wants to merge 5 commits into
base: master
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
240 changes: 145 additions & 95 deletions frontend/src/screens/RouteScreen.jsx
Original file line number Diff line number Diff line change
@@ -1,23 +1,20 @@
import React, { Fragment, useEffect } from 'react';

import { makeStyles } from '@material-ui/core/styles';
import Paper from '@material-ui/core/Paper';
import Grid from '@material-ui/core/Grid';
import HomeIcon from '@material-ui/icons/Home';
import Toolbar from '@material-ui/core/Toolbar';
import AppBar from '@material-ui/core/AppBar';
import IconButton from '@material-ui/core/IconButton';
import ArrowBackIcon from '@material-ui/icons/ArrowBack';
import Link, { NavLink } from 'redux-first-router-link';
import Link from 'redux-first-router-link';
import NavigateNextIcon from '@material-ui/icons/NavigateNext';
import Breadcrumbs from '@material-ui/core/Breadcrumbs';
import Typography from '@material-ui/core/Typography';

import { connect } from 'react-redux';
import AppBarLogo from '../components/AppBarLogo';
import Info from '../components/Info';
import MapStops from '../components/MapStops';
import DateTimePanel from '../components/DateTimePanel';

import SidebarButton from '../components/SidebarButton';
import { getAgency } from '../config';
import ControlPanel from '../components/ControlPanel';
import RouteSummary from '../components/RouteSummary';
Expand All @@ -37,48 +34,94 @@ const useStyles = makeStyles(theme => ({
padding: '1%',
paddingRight: '0',
},
homeIcon: {
color: 'gray',
fontSize: 20,
alignSelf: 'center',
marginRight: '5px',
},
linkContainer: {
display: 'flex',
flexDirection: 'row',
justifyContent: 'space-around',
alignSelf: 'flex-start',
textDecorationColor: theme.palette.primary.dark,
},
}));

function RouteScreen(props) {
const {
tripMetrics,
tripMetricsLoading,
tripMetricsError,
graphParams,
routes,
} = props;

const myFetchRoutes = props.fetchRoutes;
const agencyId = graphParams ? graphParams.agencyId : null;

useEffect(() => {
if (!routes && agencyId) {
myFetchRoutes({ agencyId });
}
}, [agencyId, routes, myFetchRoutes]); // like componentDidMount, this runs only on first render

const BreadCrumbHomeLink = props => {
const { agencyId } = props;
const { breadCrumbStyling, darkLinks, homeIcon, linkContainer } = useStyles();
const agency = getAgency(agencyId);
const agencyTitle = agency.title;
return (
<Fragment>
<Link
className={linkContainer}
to={{ type: 'DASHBOARD', query: props.query }}
exact
strict
>
<HomeIcon className={homeIcon} />
<Typography
variant="subtitle1"
className={`${breadCrumbStyling} ${darkLinks}`}
>
{agencyTitle}
</Typography>
</Link>
</Fragment>
);
};

const backArrowStyle = { color: '#ffffff' };
const BreadCrumbLink = props => {
const { hasNextValue, label, specialLabel, link, renderAsH1 } = props;
const { breadCrumbStyling, darkLinks } = useStyles();

const breadCrumbs = (paths, classes) => {
const { breadCrumbStyling, darkLinks } = classes;
return hasNextValue ? (
<Typography
variant="subtitle1"
className={`${breadCrumbStyling} ${darkLinks}`}
component={renderAsH1}
>
{' '}
{specialLabel}{' '}
<Link to={link} className={`${breadCrumbStyling} ${darkLinks}`}>
{' '}
{label}{' '}
</Link>{' '}
</Typography>
) : (
<Typography variant="subtitle1" className={breadCrumbStyling}>
{' '}
{specialLabel} {label}{' '}
</Typography>
);
};

function BreadCrumbBar(props) {
const { direction, selectedRoute, linkQuery, agencyId } = props;
const { startStopInfo, endStopInfo } = props;
const classes = useStyles();
const { breadCrumbStyling, breadCrumbsWrapper } = classes;

const renderBreadCrumbs = paths => {
let link = {
type: 'ROUTESCREEN',
query: props.query,
query: linkQuery,
};

const params = ['routeId', 'directionId', 'startStopId', 'endStopId'];
const labels = (param, title) => {
const getLabel = (param, title) => {
const specialLabels = {};
specialLabels.startStopId = 'from ';
specialLabels.endStopId = 'to ';
specialLabels.startStopId = 'from: ';
specialLabels.endStopId = 'to: ';
return {
label: title,
specialLabel: specialLabels[param] ? specialLabels[param] : null,
};
};
return paths
const bradCrumbLinks = paths
.filter(path => {
// return paths with non null values
return !!path;
Expand All @@ -90,42 +133,62 @@ function RouteScreen(props) {
payload[param] = path.id;
const updatedPayload = Object.assign({ ...link.payload }, payload);
link = Object.assign({ ...link }, { payload: updatedPayload });
const { label, specialLabel } = labels(param, path.title);
const { label, specialLabel } = getLabel(param, path.title);

// For SEO purposes, make the very first breadcrumb (which is the
// route name) render as an H1, but be styled like everything else
// (as a regular, small subtitle).
// if it's not the first one, render as default HTML tag.
const renderAsH1 = index === 0 ? 'h1' : null;

return hasNextValue ? (
<Typography
variant="subtitle1"
component={renderAsH1}
return (
<BreadCrumbLink
hasNextValue={hasNextValue}
label={label}
specialLabel={specialLabel}
link={link}
renderAsH1={renderAsH1}
key={label}
className={`${breadCrumbStyling} ${darkLinks}`}
>
{' '}
{specialLabel}{' '}
<Link to={link} className={`${breadCrumbStyling} ${darkLinks}`}>
{' '}
{label}{' '}
</Link>{' '}
</Typography>
) : (
<Typography
variant="subtitle1"
component={renderAsH1}
key={label}
className={breadCrumbStyling}
>
{' '}
{specialLabel} {label}{' '}
</Typography>
/>
);
});
return [<BreadCrumbHomeLink agencyId={agencyId} />, ...bradCrumbLinks];
};

return (
<Fragment>
<Paper className={breadCrumbsWrapper}>
<Breadcrumbs
separator={
<NavigateNextIcon
fontSize="default"
className={breadCrumbStyling}
/>
}
>
{renderBreadCrumbs([
selectedRoute,
direction,
startStopInfo,
endStopInfo,
])}
</Breadcrumbs>
</Paper>
</Fragment>
);
}

function RouteScreen(props) {
const {
tripMetrics,
tripMetricsLoading,
tripMetricsError,
graphParams,
routes,
} = props;
const myFetchRoutes = props.fetchRoutes;
const agencyId = graphParams ? graphParams.agencyId : null;
const linkQuery = props.query;
const selectedRoute =
routes && graphParams && graphParams.routeId
? routes.find(
Expand All @@ -140,62 +203,49 @@ function RouteScreen(props) {
myDirection => myDirection.id === graphParams.directionId,
)
: null;

const startStopInfo =
direction && graphParams.startStopId
? selectedRoute.stops[graphParams.startStopId]
? Object.assign(
{ ...selectedRoute.stops[graphParams.startStopId] },
{ id: graphParams.startStopId },
)
: null;
const endStopInfo =
direction && graphParams.endStopId
? selectedRoute.stops[graphParams.endStopId]
? Object.assign(
{ ...selectedRoute.stops[graphParams.endStopId] },
{ id: graphParams.endStopId },
)
: null;

const classes = useStyles();
const { breadCrumbStyling, breadCrumbsWrapper } = classes;
useEffect(() => {
if (!routes && agencyId) {
myFetchRoutes({ agencyId });
}
}, [agencyId, routes, myFetchRoutes]);

const agency = getAgency(agencyId);

return (
<Fragment>
<AppBar position="relative">
<Toolbar>
<NavLink to={{ type: 'DASHBOARD', query: props.query }} exact strict>
<IconButton aria-label="Back to dashboard" edge="start">
<ArrowBackIcon style={backArrowStyle} />
</IconButton>
</NavLink>
<SidebarButton />
<AppBarLogo />
<div className="page-title">{agency ? agency.title : null}</div>
<div style={{ flexGrow: 1 }} />
<DateTimePanel dateRangeSupported />
</Toolbar>
</AppBar>
<Paper className={breadCrumbsWrapper}>
<Breadcrumbs
separator={
<NavigateNextIcon
fontSize="default"
className={breadCrumbStyling}
/>
}
>
{breadCrumbs(
[
selectedRoute,
direction,
startStopInfo
? Object.assign(
{ ...startStopInfo },
{ id: graphParams.startStopId },
)
: null,
endStopInfo
? Object.assign(
{ ...endStopInfo },
{ id: graphParams.endStopInfo },
)
: null,
],
classes,
)}
</Breadcrumbs>
</Paper>
<BreadCrumbBar
selectedRoute={selectedRoute}
startStopInfo={startStopInfo}
endStopInfo={endStopInfo}
linkQuery={linkQuery}
direction={direction}
agencyId={agencyId}
/>
<Grid container spacing={0}>
<Grid item xs={12} sm={6}>
<MapStops routes={routes} />
Expand Down