Skip to content

Instantly share code, notes, and snippets.

@chrisabrams
Created May 1, 2018 14:41
Show Gist options
  • Save chrisabrams/a975867321238b37c90b5965902e2dd2 to your computer and use it in GitHub Desktop.
Save chrisabrams/a975867321238b37c90b5965902e2dd2 to your computer and use it in GitHub Desktop.

Revisions

  1. chrisabrams created this gist May 1, 2018.
    116 changes: 116 additions & 0 deletions ProtectedRoute.js
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,116 @@
    import React, {Component} from 'react'
    import {Route, Redirect} from 'react-router-dom'
    import userProvider from 'store/providers/user'

    export default class ProtectedRoute extends Component {

    constructor(props) {
    super(props)

    this.inProgress = false

    /*
    NOTE: Can't render a route with a both component & render property
    */
    this.rProps = Object.assign({}, props)
    delete this.rProps.component

    this.state = {
    authed: false,
    completed: false,
    redirectPathname: this.props.redirectPathname || '/auth/login', // Default path to send on redirect
    props: this.rProps
    }

    }

    auth() {
    this.inProgress = true

    const user = userProvider.get()
    if(!user.__loaded) {
    return setTimeout(this.auth.bind(this), 100)
    }

    let authed = (user && user.id) ? true : false

    if(this.props.roles instanceof Array) {
    let roleAuthed = false

    for(let i = 0, l = this.props.roles.length; i < l; i++) {
    const role = this.props.roles[i]

    if(user.roles && user.roles.includes(role)) {
    roleAuthed = true
    continue
    }
    }

    if(!roleAuthed) {
    authed = false
    }

    this.setState({
    authed,
    completed: true,
    redirectPathname: '/dashboard'
    })
    }
    else {
    this.setState({
    authed,
    completed: true
    })
    }

    this.inProgress = false

    }

    componentWillMount() {
    this.auth()
    }

    componentWillReceiveProps(nextProps) {

    /*
    This is a Component that was mounted from another route; let the component know that the route has changed
    */
    if(this.state.completed && this.props.computedMatch.path != nextProps.computedMatch.path) {
    this.setState({props: nextProps})
    }
    }

    redirect = (props, pathname) => {
    const options = {pathname, state: {from: props.location}}
    return <Redirect to={options} />
    }

    renderComponent = (props) => {
    const authed = this.state.authed
    const Component = this.props.component

    if(authed === true) {
    return <Component {...props} />
    }

    return this.redirect(props, this.state.redirectPathname)

    }

    render() {

    // Can use this to create an optional spinner component while waiting for async function to complete
    const spinner = null

    return this.state.completed
    ? <Route
    {...this.state.props}
    ref='route'
    render={this.renderComponent}
    />
    : spinner

    }

    }