Skip to content

Commit ae3c44d

Browse files
Merge pull request #175 from opentripplanner/auth0provider-inside-router
improvement(example): Move Auth0Provider plumbing out of example.js a…
2 parents 5f39e30 + bb9f9e8 commit ae3c44d

11 files changed

+237
-191
lines changed

Diff for: example.js

+13-57
Original file line numberDiff line numberDiff line change
@@ -11,21 +11,15 @@ import { Provider } from 'react-redux'
1111
import thunk from 'redux-thunk'
1212
import createLogger from 'redux-logger'
1313

14-
// Auth0
15-
import { Auth0Provider } from 'use-auth0-hooks'
16-
import { accountLinks, getAuth0Callbacks, getAuth0Config } from './lib/util/auth'
17-
import { AUTH0_AUDIENCE, AUTH0_SCOPE, URL_ROOT } from './lib/util/constants'
18-
1914
// import Bootstrap Grid components for layout
20-
import { Nav, Navbar, Grid, Row, Col } from 'react-bootstrap'
15+
import { Grid, Row, Col } from 'react-bootstrap'
2116

2217
// import OTP-RR components
2318
import {
24-
AppMenu,
2519
DefaultMainPanel,
20+
DesktopNav,
2621
Map,
2722
MobileMain,
28-
NavLoginButtonAuth0,
2923
ResponsiveWebapp,
3024
createOtpReducer,
3125
createUserReducer
@@ -81,37 +75,13 @@ const store = createStore(
8175
compose(applyMiddleware(...middleware))
8276
)
8377

84-
// Auth0 config and callbacks.
85-
const auth0Config = getAuth0Config(otpConfig.persistence)
86-
const auth0Callbacks = getAuth0Callbacks(store)
87-
8878
// define a simple responsive UI using Bootstrap and OTP-RR
8979
class OtpRRExample extends Component {
9080
render () {
9181
/** desktop view **/
9282
const desktopView = (
9383
<div className='otp'>
94-
<Navbar fluid inverse>
95-
<Navbar.Header>
96-
<Navbar.Brand>
97-
<div style={{ float: 'left', color: 'white', fontSize: 28 }}>
98-
<AppMenu />
99-
</div>
100-
<div className='navbar-title' style={{ marginLeft: 50 }}>OpenTripPlanner</div>
101-
</Navbar.Brand>
102-
</Navbar.Header>
103-
104-
{auth0Config && (
105-
<Navbar.Collapse>
106-
<Nav pullRight>
107-
<NavLoginButtonAuth0
108-
id='login-control'
109-
links={accountLinks}
110-
/>
111-
</Nav>
112-
</Navbar.Collapse>
113-
)}
114-
</Navbar>
84+
<DesktopNav />
11585
<Grid>
11686
<Row className='main-row'>
11787
<Col sm={6} md={4} className='sidebar'>
@@ -146,34 +116,20 @@ class OtpRRExample extends Component {
146116
}
147117
}
148118

149-
const innerProvider = (
150-
<Provider store={store}>
151-
{ /**
119+
// render the app
120+
render(
121+
(
122+
<Provider store={store}>
123+
{ /**
152124
* If not using router history, simply include OtpRRExample here:
153125
* e.g.
154126
* <OtpRRExample />
155127
*/
156-
}
157-
<OtpRRExample />
158-
</Provider>
159-
)
160-
161-
// render the app
162-
render(auth0Config
163-
? (
164-
<Auth0Provider
165-
audience={AUTH0_AUDIENCE}
166-
scope={AUTH0_SCOPE}
167-
domain={auth0Config.domain}
168-
clientId={auth0Config.clientId}
169-
redirectUri={URL_ROOT}
170-
{...auth0Callbacks}
171-
>
172-
{innerProvider}
173-
</Auth0Provider>
128+
}
129+
<OtpRRExample />
130+
</Provider>
174131
)
175-
: innerProvider
176-
,
132+
,
177133

178-
document.getElementById('root')
134+
document.getElementById('root')
179135
)

Diff for: lib/actions/auth.js

+59
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
import { push } from 'connected-react-router'
2+
3+
import { setPathBeforeSignIn } from '../actions/user'
4+
5+
/**
6+
* This function is called by the Auth0Provider component, with the described parameter(s),
7+
* when a new access token could not be retrieved.
8+
* @param {Error} err
9+
* @param {AccessTokenRequestOptions} options
10+
*/
11+
export function showAccessTokenError (err, options) {
12+
return function (dispatch, getState) {
13+
// TODO: improve this.
14+
console.error('Failed to retrieve access token: ', err)
15+
}
16+
}
17+
18+
/**
19+
* This function is called by the Auth0Provider component, with the described parameter(s),
20+
* when signing-in fails for some reason.
21+
* @param {Error} err
22+
*/
23+
export function showLoginError (err) {
24+
return function (dispatch, getState) {
25+
// TODO: improve this.
26+
if (err) dispatch(push('/oops'))
27+
}
28+
}
29+
30+
/**
31+
* This function is called by the Auth0Provider component, with the described parameter(s),
32+
* after the user signs in.
33+
* @param {Object} appState The state that was stored when calling useAuth().login().
34+
*/
35+
export function processSignIn (appState) {
36+
return function (dispatch, getState) {
37+
if (appState && appState.urlHash) {
38+
// At this stage after login, Auth0 has already redirected to /signedin (Auth0-whitelisted)
39+
// which shows the AfterLoginScreen.
40+
//
41+
// Here, we save the URL hash prior to login (contains a combination of itinerary search, stop/trip view, etc.),
42+
// so that the AfterLoginScreen can redirect back there when logged-in user info is fetched.
43+
// (For routing, it is easier to deal with the path without the hash sign.)
44+
const hashIndex = appState.urlHash.indexOf('#')
45+
const urlHashWithoutHash = hashIndex >= 0
46+
? appState.urlHash.substr(hashIndex + 1)
47+
: '/'
48+
dispatch(setPathBeforeSignIn(urlHashWithoutHash))
49+
} else if (appState && appState.returnTo) {
50+
// TODO: Handle other after-login situations.
51+
// Note that when redirecting from a login-protected (e.g. account) page while logged out,
52+
// then returnTo is set by Auth0 to this object format:
53+
// {
54+
// pathname: "/"
55+
// query: { ... }
56+
// }
57+
}
58+
}
59+
}

Diff for: lib/components/app/app-nav.js

-55
This file was deleted.

Diff for: lib/components/app/desktop-nav.js

+81
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
import React from 'react'
2+
import { Nav, Navbar } from 'react-bootstrap'
3+
import { connect } from 'react-redux'
4+
5+
import NavLoginButtonAuth0 from '../user/nav-login-button-auth0.js'
6+
import { accountLinks, getAuth0Config } from '../../util/auth'
7+
import { DEFAULT_APP_TITLE } from '../../util/constants'
8+
import AppMenu from './app-menu'
9+
10+
/**
11+
* The desktop navigation bar, featuring a `branding` logo or a `title` text
12+
* defined in config.yml, and a sign-in button/menu with account links.
13+
*
14+
* The `branding` and `title` parameters in config.yml are handled
15+
* and shown in this order in the navigation bar:
16+
* 1. If `branding` is defined, it is shown, and no title is displayed.
17+
* 2. If `branding` is not defined but if `title` is, then `title` is shown.
18+
* 3. If neither is defined, just show 'OpenTripPlanner' (DEFAULT_APP_TITLE).
19+
*
20+
* TODO: merge with the mobile navigation bar.
21+
*/
22+
const DesktopNav = ({ otpConfig }) => {
23+
const { branding, persistence, title = DEFAULT_APP_TITLE } = otpConfig
24+
const showLogin = Boolean(getAuth0Config(persistence))
25+
26+
// Display branding and title in the order as described in the class summary.
27+
let brandingOrTitle
28+
if (branding) {
29+
brandingOrTitle = (
30+
<div
31+
className={`icon-${branding}`}
32+
// FIXME: Style hack for desktop view.
33+
style={{ marginLeft: 50 }}
34+
/>
35+
)
36+
} else {
37+
brandingOrTitle = (
38+
<div className='navbar-title' style={{ marginLeft: 50 }}>{title}</div>
39+
)
40+
}
41+
42+
return (
43+
<Navbar fluid inverse>
44+
<Navbar.Header>
45+
<Navbar.Brand>
46+
{/* TODO: Reconcile CSS class and inline style. */}
47+
<div className='app-menu-container' style={{ float: 'left', color: 'white', fontSize: 28 }}>
48+
<AppMenu />
49+
</div>
50+
51+
{brandingOrTitle}
52+
53+
</Navbar.Brand>
54+
</Navbar.Header>
55+
56+
{showLogin && (
57+
<Navbar.Collapse>
58+
<Nav pullRight>
59+
<NavLoginButtonAuth0
60+
id='login-control'
61+
links={accountLinks}
62+
/>
63+
</Nav>
64+
</Navbar.Collapse>
65+
)}
66+
</Navbar>
67+
)
68+
}
69+
70+
// connect to the redux store
71+
72+
const mapStateToProps = (state, ownProps) => {
73+
return {
74+
otpConfig: state.otp.config
75+
}
76+
}
77+
78+
const mapDispatchToProps = {
79+
}
80+
81+
export default connect(mapStateToProps, mapDispatchToProps)(DesktopNav)

0 commit comments

Comments
 (0)