Skip to content

Commit

Permalink
Loading example port to react router 4
Browse files Browse the repository at this point in the history
  • Loading branch information
mjrussell committed Mar 29, 2017
1 parent 53c29ad commit fd655d6
Show file tree
Hide file tree
Showing 17 changed files with 346 additions and 0 deletions.
3 changes: 3 additions & 0 deletions examples/loading-rrv4/.babelrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"presets": ["es2015", "react", "stage-0"]
}
19 changes: 19 additions & 0 deletions examples/loading-rrv4/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
redux-auth-wrapper loading RRV4 example
=================================

This is a more advanced example of redux-auth-wrapper that uses `authenticatingSelector` with `LoadingComponent`
to show a loading screen while the user logs in. This example also demonstrates how to use the UserAuthWrapper for
wrapping the Login Component in an HOC.

This example uses React-Router 4.x

**To run, follow these steps:**

1. Install dependencies with `npm install` in this directory (make sure it creates a local node_modules)
2. By default, it uses the local version from `src` of redux-auth-wrapper, so you need to run `npm install` from there first.
3. `npm start`
4. `Browse to http://localhost:8080`

Login as any user to access the protected page `foo`.
Login with the admin box check to access the admin section.
Logout from any protected page to get redirect back to the login page.
20 changes: 20 additions & 0 deletions examples/loading-rrv4/actions/user.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import * as constants from '../constants'

export const login = data => dispatch => {
dispatch({
type: constants.USER_LOGGING_IN
})
// Wait 2 seconds before "logging in"
setTimeout(() => {
dispatch({
type: constants.USER_LOGGED_IN,
payload: data
})
}, 2000)
}

export function logout() {
return {
type: constants.USER_LOGGED_OUT
}
}
40 changes: 40 additions & 0 deletions examples/loading-rrv4/app.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import { createDevTools } from 'redux-devtools'
import LogMonitor from 'redux-devtools-log-monitor'
import DockMonitor from 'redux-devtools-dock-monitor'

import React from 'react'
import ReactDOM from 'react-dom'
import { createStore, combineReducers, applyMiddleware, compose } from 'redux'
import { Provider } from 'react-redux'
import thunkMiddleware from 'redux-thunk'

import * as reducers from './reducers'
import App from './components/App'

const reducer = combineReducers(Object.assign({}, reducers, {}))

const DevTools = createDevTools(
<DockMonitor toggleVisibilityKey="ctrl-h"
changePositionKey="ctrl-q">
<LogMonitor theme="tomorrow" />
</DockMonitor>
)

const enhancer = compose(
// Middleware you want to use in development:
applyMiddleware(thunkMiddleware),
DevTools.instrument()
)

// Note: passing enhancer as the last argument requires redux@>=3.1.0
const store = createStore(reducer, enhancer)

ReactDOM.render(
<Provider store={store}>
<div>
<App />
{/* <DevTools /> */}
</div>
</Provider>,
document.getElementById('mount')
)
37 changes: 37 additions & 0 deletions examples/loading-rrv4/auth.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import Loading from './components/Loading'

import { UserAuthWrapper } from 'redux-auth-wrapper'

export const UserIsAuthenticated = UserAuthWrapper({
authSelector: state => state.user.data,
authenticatingSelector: state => state.user.isLoading,
LoadingComponent: Loading,
wrapperDisplayName: 'UserIsAuthenticated'
})

export const UserIsAdmin = UserAuthWrapper({
authSelector: state => state.user.data,
failureRedirectPath: '/',
wrapperDisplayName: 'UserIsAdmin',
predicate: user => user.isAdmin,
allowRedirectBack: false
})

export const UserIsNotAuthenticated = UserAuthWrapper({
authSelector: state => state.user,
wrapperDisplayName: 'UserIsNotAuthenticated',
// Want to redirect the user when they are done loading and authenticated
predicate: user => user.data === null && user.isLoading === false,
failureRedirectPath: (state, ownProps) => {
let path
if (ownProps.location.query) {
path = ownProps.location.query.redirect
}
if (path === undefined) {
path = '/foo'
}
return path
},
// ownProps.location.query.redirect || '/foo',
allowRedirectBack: false
})
5 changes: 5 additions & 0 deletions examples/loading-rrv4/components/Admin.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import React from 'react'

export default function Admin({ authData }) {
return <div>{`Welcome admin user: ${authData.name}`}</div>
}
46 changes: 46 additions & 0 deletions examples/loading-rrv4/components/App.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import React from 'react'
import { BrowserRouter as Router, Route, Link } from 'react-router-dom'
import { connect } from 'react-redux'

import { logout } from '../actions/user'
import { UserIsAuthenticated, UserIsNotAuthenticated, UserIsAdmin } from '../auth'

import AdminComponent from './Admin'
import FooComponent from './Foo'
import LoginComponent from './Login'
import Home from './Home'

// Need to apply the hocs here to avoid applying them inside the render method
const Login = UserIsNotAuthenticated(LoginComponent)
const Foo = UserIsAuthenticated(FooComponent)
const Admin = UserIsAuthenticated(UserIsAdmin(AdminComponent))

function App({ logout }) {
return (
<Router>
<div>
<header>
Links:
{' '}
<Link to="/">Home</Link>
{' '}
<Link to="/foo">{'Foo (Login Required)'}</Link>
{' '}
<Link to="/admin">{'Admin'}</Link>
{' '}
<Link to="/login">Login</Link>
{' '}
<button onClick={() => logout()}>Logout</button>
</header>
<div style={{ marginTop: '1.5em' }}>
<Route exact path="/" component={Home}/>
<Route path="/login" component={Login}/>
<Route path="/foo" component={Foo}/>
<Route path="/admin" component={Admin}/>
</div>
</div>
</Router>
)
}

export default connect(false, { logout })(App)
7 changes: 7 additions & 0 deletions examples/loading-rrv4/components/Foo.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import React from 'react'

export default function Foo({ authData }) {
return (
<div>{`I am Foo! Welcome ${authData.name}`}</div>
)
}
11 changes: 11 additions & 0 deletions examples/loading-rrv4/components/Home.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import React from 'react'

export default function Home() {
return (
<div>
<h4>{"Welcome! Why dont you login and check out Foo? Or log in as an admin and click Admin"}</h4>
<h4>{"Or just try to navigate there and you will be redirected"}</h4>
<h4>{"Dont forget to try logging out on any page!"}</h4>
</div>
)
}
5 changes: 5 additions & 0 deletions examples/loading-rrv4/components/Loading.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import React from 'react'

export default function Loading() {
return <div>Logging you in...</div>
}
35 changes: 35 additions & 0 deletions examples/loading-rrv4/components/Login.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import React, { Component, PropTypes } from 'react'
import { connect } from 'react-redux'

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

export class LoginContainer extends Component {

static propTypes = {
login: PropTypes.func.isRequired
};

onClick = (e) => {
e.preventDefault()
this.props.login({
name: this.refs.name.value,
isAdmin: this.refs.admin.checked
})
};

render() {
return (
<div>
<h2>Enter your name</h2>
<input type="text" ref="name" />
<br/>
{'Admin?'}
<input type="checkbox" ref="admin" />
<br/>
<button onClick={this.onClick}>Login</button>
</div>
)
}

}
export default connect(null, { login })(LoginContainer)
3 changes: 3 additions & 0 deletions examples/loading-rrv4/constants.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export const USER_LOGGING_IN = 'USER_LOGGING_IN'
export const USER_LOGGED_IN = 'USER_LOGGED_IN'
export const USER_LOGGED_OUT = 'USER_LOGGED_OUT'
10 changes: 10 additions & 0 deletions examples/loading-rrv4/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<!DOCTYPE html>
<html>
<head>
<title>redux-auth-wrapper loading rrv4 example</title>
<meta charset="utf8"/>
</head>
<body>
<div id="mount"></div>
</body>
</html>
31 changes: 31 additions & 0 deletions examples/loading-rrv4/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
{
"name": "raw-loading-rrv4-example",
"version": "0.0.0",
"dependencies": {
"react": "^15.4.2",
"react-dom": "^15.4.2",
"react-redux": "^5.0.3",
"react-router": "^4.0.0",
"redux": "3.6.0",
"redux-thunk": "^2.1.0"
},
"devDependencies": {
"babel-core": "^6.24.0",
"babel-loader": "^6.4.1",
"babel-preset-es2015": "^6.24.0",
"babel-preset-react": "^6.23.0",
"babel-preset-stage-0": "^6.22.0",
"eslint": "1.7.1",
"eslint-config-rackt": "1.1.1",
"eslint-plugin-react": "3.16.0",
"html-webpack-plugin": "^2.28.0",
"redux-devtools": "^3.3.2",
"redux-devtools-dock-monitor": "1.1.1",
"redux-devtools-log-monitor": "^1.2.0",
"webpack": "1.13.3",
"webpack-dev-server": "1.16.2"
},
"scripts": {
"start": "webpack-dev-server --config webpack.config.babel.js --progress"
}
}
5 changes: 5 additions & 0 deletions examples/loading-rrv4/reducers/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import user from './user'

module.exports = {
user
}
19 changes: 19 additions & 0 deletions examples/loading-rrv4/reducers/user.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import * as constants from '../constants'

const initialState = {
data: null,
isLoading: false
}

export default function userUpdate(state = initialState, { type, payload }) {
switch (type) {
case constants.USER_LOGGING_IN:
return { ...initialState, isLoading: true }
case constants.USER_LOGGED_IN:
return { data: payload, isLoading: false }
case constants.USER_LOGGED_OUT:
return initialState
default:
return state
}
}
50 changes: 50 additions & 0 deletions examples/loading-rrv4/webpack.config.babel.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
import path from 'path'
import fs from 'fs'
import HtmlWebpackPlugin from 'html-webpack-plugin'

module.exports = {
entry: './app.js',
output: {
path: path.join(__dirname, 'dist'),
filename: 'bundle.js'
},
devServer: {
inline: true,
historyApiFallback: true,
stats: {
colors: true,
hash: false,
version: false,
chunks: false,
children: false
}
},
module: {
loaders: [ {
test: /\.js$/,
loaders: [ 'babel' ],
exclude: /node_modules/,
include: __dirname
} ]
},
plugins: [
new HtmlWebpackPlugin({
template: 'index.html', // Load a custom template
inject: 'body' // Inject all scripts into the body
})
]
}

// This will make the redux-auth-wrapper module resolve to the
// latest src instead of using it from npm. Remove this if running
// outside of the source.
const src = path.join(__dirname, '..', '..', 'src')
if (fs.existsSync(src)) {
// Use the latest src
module.exports.resolve = { alias: { 'redux-auth-wrapper': src } }
module.exports.module.loaders.push({
test: /\.js$/,
loaders: [ 'babel' ],
include: src
})
}

0 comments on commit fd655d6

Please sign in to comment.