Skip to content

Commit

Permalink
Merge e7fe532 into fd655d6
Browse files Browse the repository at this point in the history
  • Loading branch information
yurtaev committed Apr 15, 2017
2 parents fd655d6 + e7fe532 commit b3a2923
Show file tree
Hide file tree
Showing 17 changed files with 359 additions and 0 deletions.
3 changes: 3 additions & 0 deletions examples/basic-rrv4/.babelrc
@@ -0,0 +1,3 @@
{
"presets": ["es2015", "react", "stage-0"]
}
19 changes: 19 additions & 0 deletions examples/basic-rrv4/README.md
@@ -0,0 +1,19 @@
redux-auth-wrapper basic example
=================================

This is a basic example that demonstrates wrapping components
with authentication and authorization checks. It shows how to handle
nested checks and demonstrates redirect support.

This example uses React-Router 2.x and React-Router-Redux 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. (Link is hidden until logging in as admin)
Logout from any protected page to get redirect back to the login page.
14 changes: 14 additions & 0 deletions examples/basic-rrv4/actions/user.js
@@ -0,0 +1,14 @@
import * as constants from '../constants'

export function login(data) {
return {
type: constants.USER_LOGGED_IN,
payload: data
}
}

export function logout() {
return {
type: constants.USER_LOGGED_OUT
}
}
56 changes: 56 additions & 0 deletions examples/basic-rrv4/app.js
@@ -0,0 +1,56 @@
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 { Route, Switch } from 'react-router-dom'
import createHistory from 'history/createBrowserHistory'
import { ConnectedRouter, routerReducer, routerMiddleware } from 'react-router-redux'

import * as reducers from './reducers'
import { App, Home, Foo, Admin, Login } from './components'
import { UserIsAuthenticated, UserIsAdmin } from './util/wrappers.js'

const baseHistory = createHistory()
const routingMiddleware = routerMiddleware(baseHistory)
const reducer = combineReducers(Object.assign({}, reducers, {
router: routerReducer
}))

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(routingMiddleware),
DevTools.instrument()
)

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

ReactDOM.render(
<Provider store={store}>
<ConnectedRouter history={baseHistory}>
<div>
<App>
<Switch>
<Route exact path="/" component={Home} />
<Route path="/login" component={Login}/>
<Route path="/foo" component={UserIsAuthenticated(Foo)}/>
<Route path="/admin" component={UserIsAuthenticated(UserIsAdmin(Admin))}/>
</Switch>
</App>
<DevTools />
</div>
</ConnectedRouter>
</Provider>,
document.getElementById('mount')
)
9 changes: 9 additions & 0 deletions examples/basic-rrv4/components/Admin.js
@@ -0,0 +1,9 @@
import React from 'react'

export default function Admin({ authData }) {
return <div>
<p>{`Welcome admin user: ${authData.name}`}</p>
<p>Refreshing your page here will redirect you back to Login with a redirect back here once authenticated</p>
<p>See the local storage example for an example that doesn't log you out on refresh</p>
</div>
}
30 changes: 30 additions & 0 deletions examples/basic-rrv4/components/App.js
@@ -0,0 +1,30 @@
import React from 'react'
import { NavLink, withRouter } from 'react-router-dom'
import { connect } from 'react-redux'
import { logout } from '../actions/user'
import { VisibleOnlyAdmin } from '../util/wrappers'

const OnlyAdminLink = VisibleOnlyAdmin(() => <NavLink to="/admin">{'Admin'}</NavLink>)

function App({ children, logout }) {
return (
<div>
<header>
Links:
{' '}
<NavLink to="/">Home</NavLink>
{' '}
<NavLink to="/foo">{'Foo (Login Required)'}</NavLink>
{' '}
<OnlyAdminLink />
{' '}
<NavLink to="/login">Login</NavLink>
{' '}
<button onClick={() => logout()}>Logout</button>
</header>
<div style={{ marginTop: '1.5em' }}>{children}</div>
</div>
)
}

export default withRouter(connect(false, { logout })(App))
7 changes: 7 additions & 0 deletions examples/basic-rrv4/components/Foo.js
@@ -0,0 +1,7 @@
import React from 'react'

export default function Foo({ authData }) {
return (
<div>{`I am Foo! Welcome ${authData.name}`}</div>
)
}
12 changes: 12 additions & 0 deletions examples/basic-rrv4/components/Home.js
@@ -0,0 +1,12 @@
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 click Foo and you will be redirected"}</h4>
<h4>{"The Administrator link is hidden until you log in as an admin"}</h4>
<h4>{"Dont forget to try logging out on any page!"}</h4>
</div>
)
}
68 changes: 68 additions & 0 deletions examples/basic-rrv4/components/Login.js
@@ -0,0 +1,68 @@
import 'url-search-params-polyfill'

import React, { Component, PropTypes } from 'react'
import { routerActions } from 'react-router-redux'
import { connect } from 'react-redux'

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

function select(state, ownProps) {
const isAuthenticated = state.user.name || false
// https://github.com/mjrussell/redux-auth-wrapper/issues/127
// https://github.com/ReactTraining/react-router/issues/4410
const query = new URLSearchParams(ownProps.location.search)
const redirect = query.get('redirect') || '/'
return {
isAuthenticated,
redirect
}
}

class LoginContainer extends Component {

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

componentWillMount() {
const { isAuthenticated, replace, redirect } = this.props
if (isAuthenticated) {
replace(redirect)
}
}

componentWillReceiveProps(nextProps) {
const { isAuthenticated, replace, redirect } = nextProps
const { isAuthenticated: wasAuthenticated } = this.props

if (!wasAuthenticated && isAuthenticated) {
replace(redirect)
}
}

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(select, { login, replace: routerActions.replace })(LoginContainer)
7 changes: 7 additions & 0 deletions examples/basic-rrv4/components/index.js
@@ -0,0 +1,7 @@
import App from './App'
import Home from './Home'
import Foo from './Foo'
import Admin from './Admin'
import Login from './Login'

module.exports = { App, Home, Foo, Admin, Login }
2 changes: 2 additions & 0 deletions examples/basic-rrv4/constants.js
@@ -0,0 +1,2 @@
export const USER_LOGGED_IN = 'USER_LOGGED_IN'
export const USER_LOGGED_OUT = 'USER_LOGGED_OUT'
10 changes: 10 additions & 0 deletions examples/basic-rrv4/index.html
@@ -0,0 +1,10 @@
<!DOCTYPE html>
<html>
<head>
<title>redux-auth-wrapper basic example</title>
<meta charset="utf8"/>
</head>
<body>
<div id="mount"></div>
</body>
</html>
33 changes: 33 additions & 0 deletions examples/basic-rrv4/package.json
@@ -0,0 +1,33 @@
{
"name": "raw-basic-example",
"version": "0.0.0",
"dependencies": {
"react": "15.3.2",
"react-dom": "15.3.2",
"react-redux": "^5.0.3",
"react-router": "^4.0.0",
"react-router-dom": "^4.0.0",
"react-router-redux": "next",
"redux": "3.6.0",
"url-search-params-polyfill": "^1.1.0"
},
"devDependencies": {
"babel-core": "6.18.2",
"babel-loader": "6.2.7",
"babel-preset-es2015": "6.18.0",
"babel-preset-react": "6.16.0",
"babel-preset-stage-0": "6.16.0",
"eslint": "1.7.1",
"eslint-config-rackt": "1.1.1",
"eslint-plugin-react": "3.16.0",
"html-webpack-plugin": "2.24.1",
"redux-devtools": "3.3.1",
"redux-devtools-dock-monitor": "1.1.1",
"redux-devtools-log-monitor": "1.1.1",
"webpack": "1.13.3",
"webpack-dev-server": "1.16.2"
},
"scripts": {
"start": "webpack-dev-server --config webpack.config.babel.js --progress"
}
}
3 changes: 3 additions & 0 deletions examples/basic-rrv4/reducers/index.js
@@ -0,0 +1,3 @@
import user from './user'

module.exports = { user }
11 changes: 11 additions & 0 deletions examples/basic-rrv4/reducers/user.js
@@ -0,0 +1,11 @@
import * as constants from '../constants'

export default function userUpdate(state = {}, { type, payload }) {
if(type === constants.USER_LOGGED_IN) {
return payload
}
else if(type === constants.USER_LOGGED_OUT) {
return {}
}
return state
}
25 changes: 25 additions & 0 deletions examples/basic-rrv4/util/wrappers.js
@@ -0,0 +1,25 @@
import { UserAuthWrapper } from 'redux-auth-wrapper'
import { routerActions } from 'react-router-redux'

export const UserIsAuthenticated = UserAuthWrapper({
authSelector: state => state.user,
redirectAction: routerActions.replace,
wrapperDisplayName: 'UserIsAuthenticated'

})

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

export const VisibleOnlyAdmin = UserAuthWrapper({
authSelector: state => state.user,
wrapperDisplayName: 'VisibleOnlyAdmin',
predicate: user => user.isAdmin,
FailureComponent: null
})
50 changes: 50 additions & 0 deletions examples/basic-rrv4/webpack.config.babel.js
@@ -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 b3a2923

Please sign in to comment.