diff --git a/example.js b/example.js index 0f4484e8c..9c42dafe0 100644 --- a/example.js +++ b/example.js @@ -49,6 +49,23 @@ if (useCustomIcons) { MyModeIcon = CustomIcons.CustomModeIcon } +// Stubs for terms of service/storage for development purposes only. +// They are required if otpConfig.persistence.strategy === 'otp_middleware' +// (otherwise, a "Content not found" box will be shown). +// These components should be placed in their own files with appropriate content. +const TermsOfService = () => ( + <> +

Terms of Service

+

Content for terms of service.

+ +) +const TermsOfStorage = () => ( + <> +

Terms of Storage

+

Content for terms of storage.

+ +) + // define some application-wide components that should be used in // various places. The following components can be provided here: // - defaultMobileTitle (required) @@ -60,6 +77,8 @@ if (useCustomIcons) { // - MapWindows (optional) // - MobileSearchScreen (required) // - ModeIcon (required) +// - TermsOfService (required if otpConfig.persistence.strategy === 'otp_middleware') +// - TermsOfStorage (required if otpConfig.persistence.strategy === 'otp_middleware') const components = { defaultMobileTitle: () =>
OpenTripPlanner
, ItineraryBody: DefaultItinerary, @@ -74,7 +93,9 @@ const components = { MobileSearchScreen: isBatchRoutingEnabled ? BatchSearchScreen : MobileSearchScreen, - ModeIcon: MyModeIcon + ModeIcon: MyModeIcon, + TermsOfService, + TermsOfStorage } const history = createHashHistory() diff --git a/lib/components/app/app-frame.js b/lib/components/app/app-frame.js new file mode 100644 index 000000000..30aa4776f --- /dev/null +++ b/lib/components/app/app-frame.js @@ -0,0 +1,41 @@ +import React from 'react' +import { Col, Row } from 'react-bootstrap' + +import DesktopNav from './desktop-nav' +import NotFound from './not-found' + +/** + * This component defines the general application frame, to which + * content and an optional sub-navigation component can be inserted. + */ +const AppFrame = ({ children, SubNav }) => ( +
+ {/* TODO: Do mobile view. */} + + {SubNav && } +
+ + + {children} + + +
+
+) + +/** + * Creates a simple wrapper component consisting of an AppFrame that surrounds + * the provided component. (Displays "Content not found" if none provided.) + */ +export function frame (Component) { + return () => ( + + {Component + ? + : + } + + ) +} + +export default AppFrame diff --git a/lib/components/app/not-found.js b/lib/components/app/not-found.js new file mode 100644 index 000000000..4733b08b7 --- /dev/null +++ b/lib/components/app/not-found.js @@ -0,0 +1,19 @@ +import React from 'react' +import { Alert, Glyphicon } from 'react-bootstrap' +import styled from 'styled-components' + +const StyledAlert = styled(Alert)` + margin-top: 25px; +` + +/** + * Displays a not-found alert if some content is not found. + */ +const NotFound = () => ( + +

Content not found

+

The content you requested is not available.

+
+) + +export default NotFound diff --git a/lib/components/app/responsive-webapp.js b/lib/components/app/responsive-webapp.js index 707e9846e..8dfd7f934 100644 --- a/lib/components/app/responsive-webapp.js +++ b/lib/components/app/responsive-webapp.js @@ -10,7 +10,6 @@ import { Col, Grid, Row } from 'react-bootstrap' import { connect } from 'react-redux' import { Route, Switch, withRouter } from 'react-router' -import PrintLayout from './print-layout' import * as authActions from '../../actions/auth' import * as callTakerActions from '../../actions/call-taker' import * as configActions from '../../actions/config' @@ -18,10 +17,12 @@ import * as formActions from '../../actions/form' import * as locationActions from '../../actions/location' import * as mapActions from '../../actions/map' import * as uiActions from '../../actions/ui' +import { frame } from '../app/app-frame' +import DesktopNav from './desktop-nav' import { RedirectWithQuery } from '../form/connected-links' import Map from '../map/map' import MobileMain from '../mobile/main' -import DesktopNav from './desktop-nav' +import PrintLayout from './print-layout' import { getAuth0Config } from '../../util/auth' import { ACCOUNT_PATH, @@ -32,6 +33,8 @@ import { CREATE_ACCOUNT_PLACES_PATH, CREATE_ACCOUNT_VERIFY_PATH, PLACES_PATH, + TERMS_OF_SERVICE_PATH, + TERMS_OF_STORAGE_PATH, TRIPS_PATH, URL_ROOT } from '../../util/constants' @@ -320,6 +323,14 @@ class RouterWrapperWithAuth0 extends Component { component={UserAccountScreen} path={[`${CREATE_ACCOUNT_PATH}/:step`, ACCOUNT_SETTINGS_PATH]} /> + + - {/* TODO: Do mobile view. */} - - {subnav && } -
- - - {children} - - -
- + + {children} + ) } } diff --git a/lib/components/user/terms-of-use-pane.js b/lib/components/user/terms-of-use-pane.js index e220d4588..fa723c582 100644 --- a/lib/components/user/terms-of-use-pane.js +++ b/lib/components/user/terms-of-use-pane.js @@ -1,6 +1,8 @@ import React from 'react' import { Checkbox, ControlLabel, FormGroup } from 'react-bootstrap' +import { TERMS_OF_SERVICE_PATH, TERMS_OF_STORAGE_PATH } from '../../util/constants' + /** * User terms of use pane. */ @@ -28,7 +30,7 @@ const TermsOfUsePane = ({ onChange={disableCheckTerms ? null : handleChange} > {/* TODO: Implement the link */} - I have read and consent to the Terms of Service for using the Trip Planner. + I have read and consent to the Terms of Service for using the Trip Planner. @@ -41,7 +43,7 @@ const TermsOfUsePane = ({ > {/* TODO: Implement the link */} Optional: I consent to the Trip Planner storing my historical planned trips in order to - improve transit services in my area. More info... + improve transit services in my area. More info... diff --git a/lib/util/constants.js b/lib/util/constants.js index 2d5f69964..b37da6ead 100644 --- a/lib/util/constants.js +++ b/lib/util/constants.js @@ -19,6 +19,8 @@ export const CREATE_ACCOUNT_TERMS_PATH = `${CREATE_ACCOUNT_PATH}/terms` export const CREATE_ACCOUNT_VERIFY_PATH = `${CREATE_ACCOUNT_PATH}/verify` export const CREATE_ACCOUNT_PLACES_PATH = `${CREATE_ACCOUNT_PATH}/places` export const CREATE_TRIP_PATH = `${TRIPS_PATH}/new` +export const TERMS_OF_SERVICE_PATH = `/terms-of-service` +export const TERMS_OF_STORAGE_PATH = `/terms-of-storage` // Gets the root URL, e.g. https://otp-instance.example.com:8080, computed once for all. // TODO: support root URLs that involve paths or subfolders, as in https://otp-ui.example.com/path-to-ui/