Skip to content
Merged
Show file tree
Hide file tree
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
70 changes: 13 additions & 57 deletions example.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,21 +11,15 @@ import { Provider } from 'react-redux'
import thunk from 'redux-thunk'
import createLogger from 'redux-logger'

// Auth0
import { Auth0Provider } from 'use-auth0-hooks'
import { accountLinks, getAuth0Callbacks, getAuth0Config } from './lib/util/auth'
import { AUTH0_AUDIENCE, AUTH0_SCOPE, URL_ROOT } from './lib/util/constants'

// import Bootstrap Grid components for layout
import { Nav, Navbar, Grid, Row, Col } from 'react-bootstrap'
import { Grid, Row, Col } from 'react-bootstrap'

// import OTP-RR components
import {
AppMenu,
DefaultMainPanel,
DesktopNav,
Map,
MobileMain,
NavLoginButtonAuth0,
ResponsiveWebapp,
createOtpReducer,
createUserReducer
Expand Down Expand Up @@ -81,37 +75,13 @@ const store = createStore(
compose(applyMiddleware(...middleware))
)

// Auth0 config and callbacks.
const auth0Config = getAuth0Config(otpConfig.persistence)
const auth0Callbacks = getAuth0Callbacks(store)

// define a simple responsive UI using Bootstrap and OTP-RR
class OtpRRExample extends Component {
render () {
/** desktop view **/
const desktopView = (
<div className='otp'>
<Navbar fluid inverse>
<Navbar.Header>
<Navbar.Brand>
<div style={{ float: 'left', color: 'white', fontSize: 28 }}>
<AppMenu />
</div>
<div className='navbar-title' style={{ marginLeft: 50 }}>OpenTripPlanner</div>
</Navbar.Brand>
</Navbar.Header>

{auth0Config && (
<Navbar.Collapse>
<Nav pullRight>
<NavLoginButtonAuth0
id='login-control'
links={accountLinks}
/>
</Nav>
</Navbar.Collapse>
)}
</Navbar>
<DesktopNav />
<Grid>
<Row className='main-row'>
<Col sm={6} md={4} className='sidebar'>
Expand Down Expand Up @@ -146,34 +116,20 @@ class OtpRRExample extends Component {
}
}

const innerProvider = (
<Provider store={store}>
{ /**
// render the app
render(
(
<Provider store={store}>
{ /**
* If not using router history, simply include OtpRRExample here:
* e.g.
* <OtpRRExample />
*/
}
<OtpRRExample />
</Provider>
)

// render the app
render(auth0Config
? (
<Auth0Provider
audience={AUTH0_AUDIENCE}
scope={AUTH0_SCOPE}
domain={auth0Config.domain}
clientId={auth0Config.clientId}
redirectUri={URL_ROOT}
{...auth0Callbacks}
>
{innerProvider}
</Auth0Provider>
}
<OtpRRExample />
</Provider>
)
: innerProvider
,
,

document.getElementById('root')
document.getElementById('root')
)
59 changes: 59 additions & 0 deletions lib/actions/auth.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
import { push } from 'connected-react-router'

import { setPathBeforeSignIn } from '../actions/user'

/**
* This function is called by the Auth0Provider component, with the described parameter(s),
* when a new access token could not be retrieved.
* @param {Error} err
* @param {AccessTokenRequestOptions} options
*/
export function showAccessTokenError (err, options) {
return function (dispatch, getState) {
// TODO: improve this.
console.error('Failed to retrieve access token: ', err)
}
}

/**
* This function is called by the Auth0Provider component, with the described parameter(s),
* when signing-in fails for some reason.
* @param {Error} err
*/
export function showLoginError (err) {
return function (dispatch, getState) {
// TODO: improve this.
if (err) dispatch(push('/oops'))
}
}

/**
* This function is called by the Auth0Provider component, with the described parameter(s),
* after the user signs in.
* @param {Object} appState The state that was stored when calling useAuth().login().
*/
export function processSignIn (appState) {
return function (dispatch, getState) {
if (appState && appState.urlHash) {
// At this stage after login, Auth0 has already redirected to /signedin (Auth0-whitelisted)
// which shows the AfterLoginScreen.
//
// Here, we save the URL hash prior to login (contains a combination of itinerary search, stop/trip view, etc.),
// so that the AfterLoginScreen can redirect back there when logged-in user info is fetched.
// (For routing, it is easier to deal with the path without the hash sign.)
const hashIndex = appState.urlHash.indexOf('#')
const urlHashWithoutHash = hashIndex >= 0
? appState.urlHash.substr(hashIndex + 1)
: '/'
dispatch(setPathBeforeSignIn(urlHashWithoutHash))
} else if (appState && appState.returnTo) {
// TODO: Handle other after-login situations.
// Note that when redirecting from a login-protected (e.g. account) page while logged out,
// then returnTo is set by Auth0 to this object format:
// {
// pathname: "/"
// query: { ... }
// }
}
}
}
55 changes: 0 additions & 55 deletions lib/components/app/app-nav.js

This file was deleted.

81 changes: 81 additions & 0 deletions lib/components/app/desktop-nav.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
import React from 'react'
import { Nav, Navbar } from 'react-bootstrap'
import { connect } from 'react-redux'

import NavLoginButtonAuth0 from '../user/nav-login-button-auth0.js'
import { accountLinks, getAuth0Config } from '../../util/auth'
import { DEFAULT_APP_TITLE } from '../../util/constants'
import AppMenu from './app-menu'

/**
* The desktop navigation bar, featuring a `branding` logo or a `title` text
* defined in config.yml, and a sign-in button/menu with account links.
*
* The `branding` and `title` parameters in config.yml are handled
* and shown in this order in the navigation bar:
* 1. If `branding` is defined, it is shown, and no title is displayed.
* 2. If `branding` is not defined but if `title` is, then `title` is shown.
* 3. If neither is defined, just show 'OpenTripPlanner' (DEFAULT_APP_TITLE).
*
* TODO: merge with the mobile navigation bar.
*/
const DesktopNav = ({ otpConfig }) => {
const { branding, persistence, title = DEFAULT_APP_TITLE } = otpConfig
const showLogin = Boolean(getAuth0Config(persistence))

// Display branding and title in the order as described in the class summary.
let brandingOrTitle
if (branding) {
brandingOrTitle = (
<div
className={`icon-${branding}`}
// FIXME: Style hack for desktop view.
style={{ marginLeft: 50 }}
/>
)
} else {
brandingOrTitle = (
<div className='navbar-title' style={{ marginLeft: 50 }}>{title}</div>
)
}

return (
<Navbar fluid inverse>
<Navbar.Header>
<Navbar.Brand>
{/* TODO: Reconcile CSS class and inline style. */}
<div className='app-menu-container' style={{ float: 'left', color: 'white', fontSize: 28 }}>
<AppMenu />
</div>

{brandingOrTitle}

</Navbar.Brand>
</Navbar.Header>

{showLogin && (
<Navbar.Collapse>
<Nav pullRight>
<NavLoginButtonAuth0
id='login-control'
links={accountLinks}
/>
</Nav>
</Navbar.Collapse>
)}
</Navbar>
)
}

// connect to the redux store

const mapStateToProps = (state, ownProps) => {
return {
otpConfig: state.otp.config
}
}

const mapDispatchToProps = {
}

export default connect(mapStateToProps, mapDispatchToProps)(DesktopNav)
Loading