Commit 76f65841 authored by Andrew Hrdy's avatar Andrew Hrdy

Added routes

parent ffedfe28
Pipeline #4009 passed with stages
in 2 minutes and 3 seconds
This source diff could not be displayed because it is too large. You can view the blob instead.
import * as React from 'react';
import * as classNames from 'classnames';
import { removeBrackets } from '../utils/nameUtils';
import * as phoneFormatter from 'phone-formatter';
import { IFacility } from '../models/facility.model';
import { trackPiwikEvent } from '../piwik/piwik';
import { Link } from 'react-router-dom';
import TextwTitle from './TextwTitle';
import FacilitiesMap from '../containers/FacilitiesMap';
......@@ -15,7 +16,8 @@ import Typography from '@material-ui/core/Typography';
import Divider from '@material-ui/core/Divider';
import CloseIcon from '@material-ui/icons/Close';
import IconButton from '@material-ui/core/IconButton';
import { trackPiwikEvent } from '../piwik/piwik';
import FacilityDialog from './FacilityDialog';
import { History } from 'history';
class Sidebar extends React.Component<SidebarProps, SidebarState> {
......@@ -27,11 +29,6 @@ class Sidebar extends React.Component<SidebarProps, SidebarState> {
};
}
handleSidebarClose = () => {
this.props.setSelectedFacility(null);
this.props.setSidebar(false);
}
handleMapDialogClose = () => {
trackPiwikEvent('map-action', 'close');
......@@ -49,35 +46,40 @@ class Sidebar extends React.Component<SidebarProps, SidebarState> {
}
render() {
const {facility, isSidebarOpen, facilities} = this.props;
const {facility, facilities, history} = this.props;
const {mapDialogOpen} = this.state;
return (
<div
className={classNames(['card-container-offset', (isSidebarOpen && 'card-container-offset-open'), (!isSidebarOpen && 'card-container-offset-closed')])}>
<Paper
className={classNames(['sidebar-root', (isSidebarOpen && 'sidebar-open'), (!isSidebarOpen && 'sidebar-closed')])}>
<IconButton className={'sidebar-close-btn'} onClick={this.handleSidebarClose}>
<CloseIcon />
</IconButton>
<div className={'sidebar-container'}>
<Paper className={'sidebar-root'}>
<Link to="/">
<IconButton className={'sidebar-close-btn'}>
<CloseIcon />
</IconButton>
</Link>
<div className={'sidebar-row1'}>
<Avatar className={'sidebar-avatar'} src={facility.logo} />
<div className={'sidebar-title'}>
<Typography variant="h4">{removeBrackets(facility.facility_name)}</Typography>
</div>
</div>
<Divider className={'sidebar-divider'} />
<div className={'sidebar-scroll'}>
<div className={'sidebar-label-holder'}>
<TextwTitle label="Building"
content={facility.facility_location && facility.facility_location.building} />
content={facility.facility_location && facility.facility_location.building} />
<TextwTitle label="Address"
content={facility.facility_location && facility.facility_location.address} />
content={facility.facility_location && facility.facility_location.address} />
<TextwTitle label="Phone Number"
content={facility.phone_number ? phoneFormatter.format(facility.phone_number, '(NNN) NNN-NNNN') : 'Unknown'} />
content={facility.phone_number ? phoneFormatter.format(facility.phone_number, '(NNN) NNN-NNNN') : 'Unknown'} />
<TextwTitle label="Hours" content={<WeekHours facility={facility} />} />
</div>
</div>
<div className={'sidebar-row2'}>
<div className={'sidebar-map-container'} onClick={this.handleMapDialogOpen}>
<FacilitiesMap
......@@ -96,17 +98,17 @@ class Sidebar extends React.Component<SidebarProps, SidebarState> {
/>
</div>
</Paper>
<FacilityDialog facility={facility} facilities={facilities} isOpen={true} onClose={() => history.push('/')} />
</div>
);
}
}
export interface SidebarProps {
history: History;
facility: IFacility;
isSidebarOpen: boolean;
facilities: IFacility[];
setSelectedFacility: (facility: IFacility | null) => void;
setSidebar: (isOpen: boolean) => void;
}
export interface SidebarState {
......
......@@ -6,13 +6,14 @@ import FacilityUtils from '../utils/facilityUtils';
import { IFacility } from '../models/facility.model';
import { ApplicationState } from '../store';
import { Dispatch } from 'redux';
import { addFavoriteFacility, removeFavoriteFacility, setSelectedFacility, setSidebarExpansion } from '../store/ui/ui.actions';
import { trackPiwikEvent } from '../piwik/piwik';
import { addFavoriteFacility, removeFavoriteFacility } from '../store/ui/ui.actions';
import { NavLink } from 'react-router-dom';
import { withRouter, RouteComponentProps } from 'react-router';
import { Location } from 'history';
import FacilityStatus from '../components/FacilityStatus';
import FavoriteButton from '../components/FavoriteButton';
import FacilityCategory from '../components/FacilityCategory';
import FacilityDialog from '../components/FacilityDialog';
import Card from '@material-ui/core/Card';
import CardContent from '@material-ui/core/CardContent';
......@@ -30,8 +31,10 @@ class FacilityCard extends React.Component<FacilityCardProps, FacilityCardState>
};
}
getSlugFromLocation = (location: Location) => location.pathname.substring(10);
shouldComponentUpdate = (nextProps: FacilityCardProps) => {
if (this.isFacilitySelected() !== (nextProps.selectedFacility.slug === this.props.facility.slug)) {
if (this.isFacilitySelected() !== (this.getSlugFromLocation(nextProps.location) === this.props.facility.slug)) {
return true;
}
......@@ -48,21 +51,10 @@ class FacilityCard extends React.Component<FacilityCardProps, FacilityCardState>
return false;
}
isFacilitySelected = (): boolean => this.props.selectedFacility.slug === this.props.facility.slug;
handleCardClick = () => {
const newState = !this.isFacilitySelected();
trackPiwikEvent('card-action', 'click');
setTimeout(() => {
this.props.setSelectedFacility(newState ? this.props.facility : null);
this.props.setSidebarExpansion(newState);
}, 0);
}
isFacilitySelected = (): boolean => this.getSlugFromLocation(this.props.location) === this.props.facility.slug;
render() {
const {facility, facilities, favorites, addFavoriteFacility, removeFavoriteFacility} = this.props;
const {facility, favorites, addFavoriteFacility, removeFavoriteFacility} = this.props;
const dayOfWeek = [6, 0, 1, 2, 3, 4, 5][new Date().getDay()];
......@@ -87,72 +79,68 @@ class FacilityCard extends React.Component<FacilityCardProps, FacilityCardState>
facility.facility_location.building;
return (
<Card onClick={this.handleCardClick} className={classNames('fc-root', this.isFacilitySelected() && 'fc-selected')}
elevation={3}>
<div className={'fc-logo-container'}>
<img className={'fc-logo'}
alt={facility.slug} src={facility.logo} />
</div>
<FavoriteButton slug={facility.slug} initialState={favorites.includes(facility.slug)}
addFavoriteFacility={addFavoriteFacility}
removeFavoriteFacility={removeFavoriteFacility} />
<CardContent className={'fc-card-content'}>
<Grid container={true} alignItems={'center'} direction={'column'}>
<Grid item={true}
className={classNames('fc-small-grid-item-spacing', 'fc-ellipsis-container', 'fc-title-container')}>
<Typography variant={'subtitle1'} align={'center'}
className={classNames('fc-title', 'fc-one-line-ellipsis')}>
{removeBrackets(facility.facility_name)}
</Typography>
<NavLink to={this.isFacilitySelected() ? '/' : `/facility/${facility.slug}`} style={{textDecoration: 'none', color: 'black'}}>
<Card className={classNames('fc-root', this.isFacilitySelected() && 'fc-selected')}
elevation={3}>
<div className={'fc-logo-container'}>
<img className={'fc-logo'}
alt={facility.slug} src={facility.logo} />
</div>
<FavoriteButton slug={facility.slug} initialState={favorites.includes(facility.slug)}
addFavoriteFacility={addFavoriteFacility}
removeFavoriteFacility={removeFavoriteFacility} />
<CardContent className={'fc-card-content'}>
<Grid container={true} alignItems={'center'} direction={'column'}>
<Grid item={true}
className={classNames('fc-small-grid-item-spacing', 'fc-ellipsis-container', 'fc-title-container')}>
<Typography variant={'subtitle1'} align={'center'}
className={classNames('fc-title', 'fc-one-line-ellipsis')}>
{removeBrackets(facility.facility_name)}
</Typography>
</Grid>
<Grid item={true} className={'fc-small-grid-item-spacing'}>
<FacilityCategory category={facility.facility_category} />
</Grid>
<Grid item={true} className={'fc-small-grid-item-spacing fc-display-hours'}>
<Typography variant={'body1'}>
{`Today: ${getDisplayHours()}`}
</Typography>
</Grid>
</Grid>
<Grid item={true} className={'fc-small-grid-item-spacing'}>
<FacilityCategory category={facility.facility_category} />
</Grid>
<Grid item={true} className={'fc-small-grid-item-spacing fc-display-hours'}>
<Typography variant={'body1'}>
{`Today: ${getDisplayHours()}`}
</Typography>
<Grid container={true} justify={'space-around'}>
<Grid item={true} className={'fc-extra-info'}>
<FacilityStatus facility={facility} />
</Grid>
<Grid item={true} className={'fc-extra-info'}>
<Typography variant={'caption'}>
<LocationOnIcon className={'fc-card-map-marker-icon'} />
</Typography>
<Typography title={buildingName} variant={'caption'} align={'center'}
className={'fc-two-line-ellipsis'}>
{buildingName}
</Typography>
</Grid>
</Grid>
</Grid>
<Grid container={true} justify={'space-around'}>
<Grid item={true} className={'fc-extra-info'}>
<FacilityStatus facility={facility} />
</Grid>
<Grid item={true} className={'fc-extra-info'}>
<Typography variant={'caption'}>
<LocationOnIcon className={'fc-card-map-marker-icon'} />
</Typography>
<Typography title={buildingName} variant={'caption'} align={'center'}
className={'fc-two-line-ellipsis'}>
{buildingName}
</Typography>
</Grid>
</Grid>
</CardContent>
<FacilityDialog facility={facility} facilities={facilities} isOpen={this.isFacilitySelected()}
onClose={this.handleCardClick} />
</Card>
</CardContent>
</Card>
</NavLink>
);
}
}
export interface FacilityCardProps {
export interface FacilityCardProps extends RouteComponentProps<{slug: string}> {
facility: IFacility;
facilities: IFacility[];
favorites: string[];
selectedFacility: IFacility;
setSelectedFacility: (facility: IFacility) => void;
addFavoriteFacility: (slug: string) => void;
removeFavoriteFacility: (slug: string) => void;
setSidebarExpansion: (isOpen: boolean) => void;
}
export interface FacilityCardState {
......@@ -160,15 +148,12 @@ export interface FacilityCardState {
}
const mapStateToProps = (state: ApplicationState) => ({
favorites: state.ui.favorites,
selectedFacility: state.ui.selectedFacility
favorites: state.ui.favorites
});
const mapDispatchToProps = (dispatch: Dispatch) => ({
setSelectedFacility: (facility: IFacility) => dispatch(setSelectedFacility(facility)),
addFavoriteFacility: (slug: string) => dispatch(addFavoriteFacility(slug)),
removeFavoriteFacility: (slug: string) => dispatch(removeFavoriteFacility(slug)),
setSidebarExpansion: (isOpen: boolean) => dispatch(setSidebarExpansion(isOpen))
removeFavoriteFacility: (slug: string) => dispatch(removeFavoriteFacility(slug))
});
export default connect(mapStateToProps, mapDispatchToProps)(FacilityCard);
\ No newline at end of file
export default withRouter(connect(mapStateToProps, mapDispatchToProps)(FacilityCard));
\ No newline at end of file
......@@ -6,7 +6,7 @@ import { ApplicationState } from '../store';
import { Dispatch } from 'redux';
import { fetchFacilities } from '../store/facility/facility.actions';
import { fetchAlerts } from '../store/alert/alert.actions';
import { setSidebarExpansion, setSelectedFacility } from '../store/ui/ui.actions';
import { Route, withRouter, RouteComponentProps } from 'react-router-dom';
import CardContainer from '../components/CardContainer';
import AppBar from '../components/AppBar';
......@@ -23,11 +23,12 @@ class Layout extends React.Component<LayoutProps> {
}
render() {
const {isSidebarOpen, selectedFacility, facilities, searchTerm, campusRegion, setSidebarExpansion, setSelectedFacility} = this.props;
const {facilities, searchTerm, campusRegion, history} = this.props;
return (
<div className={'layout-root'}>
<AppBar />
<div className={'layout-container'}>
<div className={'layout-main-content'}>
<div className={'layout-card-container'}>
......@@ -36,26 +37,23 @@ class Layout extends React.Component<LayoutProps> {
</div>
</div>
<Sidebar facilities={facilities} facility={selectedFacility} isSidebarOpen={isSidebarOpen}
setSidebar={setSidebarExpansion} setSelectedFacility={setSelectedFacility}/>
<Route path="/facility/:slug" render={(props) => {
return <Sidebar facility={facilities.find(facility => facility.slug === props.match.params.slug)} facilities={facilities} history={history} />;
}} />
</div>
</div>
);
}
}
export interface LayoutProps {
export interface LayoutProps extends RouteComponentProps {
facilities: IFacility[];
alerts: IAlert[];
favorites: string[];
searchTerm: string;
campusRegion: CampusRegion;
selectedFacility: IFacility;
isSidebarOpen: boolean;
fetchFacilities: () => any;
fetchAlerts: () => any;
setSidebarExpansion: (isOpen: boolean) => any;
setSelectedFacility: (facility: IFacility) => any;
}
const mapStateToProps = (state: ApplicationState) => ({
......@@ -63,16 +61,12 @@ const mapStateToProps = (state: ApplicationState) => ({
alerts: state.alerts.alerts,
favorites: state.ui.favorites,
searchTerm: state.ui.search.searchTerm,
campusRegion: state.ui.search.campusRegion,
selectedFacility: state.ui.selectedFacility,
isSidebarOpen: state.ui.sidebar.isOpen
campusRegion: state.ui.search.campusRegion
});
const mapDispatchToProps = (dispatch: Dispatch) => ({
fetchFacilities: () => dispatch(fetchFacilities()),
fetchAlerts: () => dispatch(fetchAlerts()),
setSidebarExpansion: (isOpen: boolean) => dispatch(setSidebarExpansion(isOpen)),
setSelectedFacility: (facility: IFacility) => dispatch(setSelectedFacility(facility))
fetchAlerts: () => dispatch(fetchAlerts())
});
export default connect(mapStateToProps, mapDispatchToProps)(Layout);
export default withRouter(connect(mapStateToProps, mapDispatchToProps)(Layout));
......@@ -2,8 +2,6 @@ import { IFacility, CampusRegion } from '../../models/facility.model';
import { Action } from 'redux';
export enum UiActionTypes {
SET_SIDEBAR_EXPANSION = 'SET_SIDEBAR_EXPANSION',
SET_SELECTED_FACILITY = 'SET_SELECTED_FACILITY',
SET_SEARCH_TERM = 'SET_SEARCH_TERM',
SET_SELECTED_CAMPUS_REGION = 'SET_SELECTED_CAMPUS_REGION',
ADD_FAVORITE_FACILITY = 'ADD_FAVORITE_FACILITY',
......@@ -11,16 +9,6 @@ export enum UiActionTypes {
SET_FAVORITE_FACILITIES = 'SET_FAVORITE_FACILITIES'
}
export interface SetSidebarExpansion extends Action<UiActionTypes> {
type: UiActionTypes.SET_SIDEBAR_EXPANSION;
isOpen: boolean;
}
export interface SetSelectedFacility extends Action<UiActionTypes> {
type: UiActionTypes.SET_SELECTED_FACILITY;
facility: IFacility;
}
export interface SetSearchTerm extends Action<UiActionTypes> {
type: UiActionTypes.SET_SEARCH_TERM;
searchTerm: string;
......@@ -47,8 +35,6 @@ export interface SetFavoriteFacilities extends Action<UiActionTypes> {
}
export type UiAction =
SetSidebarExpansion |
SetSelectedFacility |
SetSearchTerm |
SetSelectedCampusRegion |
AddFavoriteFacility |
......
import { SetSidebarExpansion, UiActionTypes, SetSelectedFacility, SetSelectedCampusRegion, SetSearchTerm, AddFavoriteFacility, RemoveFavoriteFacility, SetFavoriteFacilities } from './ui.action-types';
import { IFacility, CampusRegion } from '../../models/facility.model';
export const setSidebarExpansion = (isOpen: boolean): SetSidebarExpansion => ({
type: UiActionTypes.SET_SIDEBAR_EXPANSION,
isOpen: isOpen
});
export const setSelectedFacility = (facility: IFacility): SetSelectedFacility => ({
type: UiActionTypes.SET_SELECTED_FACILITY,
facility: facility
});
import { UiActionTypes, SetSelectedCampusRegion, SetSearchTerm, AddFavoriteFacility, RemoveFavoriteFacility, SetFavoriteFacilities } from './ui.action-types';
import { CampusRegion } from '../../models/facility.model';
export const setSearchTerm = (searchTerm: string): SetSearchTerm => ({
type: UiActionTypes.SET_SEARCH_TERM,
......
......@@ -7,38 +7,12 @@ export interface SearchBarState {
campusRegion: CampusRegion;
}
export interface SidebarState {
isOpen: boolean;
}
export interface UiState {
selectedFacility: IFacility | {};
sidebar: SidebarState;
search: SearchBarState;
favorites: string[];
}
const selectedFacilityReducer = (state: IFacility | {} = {}, action: UiAction): IFacility | {} => {
switch (action.type) {
case UiActionTypes.SET_SELECTED_FACILITY:
return action.facility || {};
default:
return state;
}
};
const sidebarReducer = (state: SidebarState = {isOpen: false}, action: UiAction): SidebarState => {
switch (action.type) {
case UiActionTypes.SET_SIDEBAR_EXPANSION:
return {
...state,
isOpen: action.isOpen
};
default:
return state;
}
};
const searchReducer = (state: SearchBarState = {searchTerm: '', campusRegion: CampusRegion.Fairfax}, action: UiAction): SearchBarState => {
switch (action.type) {
case UiActionTypes.SET_SEARCH_TERM:
......@@ -68,8 +42,6 @@ const favoritesReducer = (state: string[] = [], action: UiAction): string[] => {
};
export const uiReducer = combineReducers<UiState>({
selectedFacility: selectedFacilityReducer,
sidebar: sidebarReducer,
search: searchReducer,
favorites: favoritesReducer
});
\ No newline at end of file
......@@ -14,14 +14,6 @@
margin-bottom: 16px;
}
.sidebar-open {
transform: translateX(0px);
}
.sidebar-closed {
transform: translateX(400px);
}
.sidebar-root {
overflow: hidden;
display: block;
......@@ -47,18 +39,8 @@
display: none;
}
.card-container-offset-open {
.sidebar-container {
flex: 1 0 400px;
}
.card-container-offset-closed {
flex: 1 0 0;
}
.card-container-offset {
transition-delay: 100ms;
}
.sidebar-divider {
......@@ -116,7 +98,7 @@
display: none !important;
}
.card-container-offset {
.sidebar-container {
display: none !important;
}
}
\ No newline at end of file
......@@ -11,5 +11,5 @@ module.exports = {
appBuild: resolveApp('build'),
appSrc: resolveApp('src'),
appOutputJs: 'static/js/bundle.js',
publicPath: ''
publicPath: '/'
};
\ No newline at end of file
......@@ -38,6 +38,7 @@ module.exports = {
contentBase: paths.appBuild,
hot: true,
port: 3000,
compress: true
compress: true,
historyApiFallback: true
}
};
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment