Skip to content

v2 onEnter with FailureComponent #206

Description

@dlong500

I'm trying to migrate from v1 to v2 of redux-auth-wrapper. I'm sticking with RR3 for the moment since I'm using SSR and it will be a larger undertaking to migrate everything to RR4 (though I do want to migrate eventually).

That being said, I'm running into some issues with getting everything working like it was under v1. To summarize, I'm not sure how to get a FailureComponent working under v2 and still support SSR with onEnter, as it appears createOnEnter only supports redirect actions. I might just be overlooking something simple, so I'd love some feedback since there isn't any documentation for precisely my type of scenario.

Here's some of my original v1 code utilizing wrappers for UserIsAuthenticated and UserIsAdmin (note that UserisAuthenticated redirects on failure, while UserIsAdmin displays a FailureComponent:

import React from 'react';
import { Route, IndexRoute } from 'react-router';
import { UserAuthWrapper } from 'redux-auth-wrapper';

import App from './app/base/App';
import NoMatch from './app/base/components/NoMatch';
import NotAuthorized from './app/base/components/NotAuthorized';

// import Auth components
import Login from './app/auth/Login';

// import Public components
import Home from './app/public/Home';

// import User components
import User from './app/user/User';
import DashboardUser from './app/user/DashboardUser';
import ProfileUser from './app/user/ProfileUser';
import StatusUser from './app/user/StatusUser';

// import Admin components
import Admin from './app/admin/Admin';
import DashboardAdmin from './app/admin/dashboard-admin';
import OperationsPanel from './app/admin/OperationsPanel';
import Overview from './app/admin/Overview';

const UserIsAuthenticated = UserAuthWrapper({
  authSelector: state => state.auth.login,
  predicate: login => login.status.isAuthenticated,
  wrapperDisplayName: 'UserIsAuthenticated',
})

const UserIsAdmin = UserAuthWrapper({
  authSelector: state => state.auth.login,
  predicate: login => login.userInfo.role === 9,
  allowRedirectBack: false,
  FailureComponent: NotAuthorized,
  wrapperDisplayName: 'UserIsAdmin',
})

export default (store) => {
  const connect = (fn) => (nextState, replaceState) => fn(store, nextState, replaceState)

  const onEnterChain = (...listOfOnEnters) => (store, nextState, replace) => {
    let redirected = false
    const wrappedReplace = (...args) => {
      replace(...args)
      redirected = true
    };
    listOfOnEnters.forEach((onEnter) => {
      if (!redirected) {
        onEnter(store, nextState, wrappedReplace);
      }
    })
  }

  return (
    <Route path="/" component={App}>
      <IndexRoute name="home" component={Home} show_title={false} />
      <Route name="Login" path="/login" component={Login} show_title={false} />
      <Route name="Admin" path="/admin" component={UserIsAuthenticated(UserIsAdmin(Admin))} onEnter={connect(onEnterChain(UserIsAuthenticated.onEnter, UserIsAdmin.onEnter))} title="Admin Dashboard">
        <Route name="dashboard-admin" component={DashboardAdmin}>
          <IndexRoute component={OperationsPanel} big_header={false} />
          <Route name="admin-operations" path="/admin/operations" component={OperationsPanel} big_header={false} />
          <Route name="admin-overview" path="/admin/overview" component={Overview} big_header={false} />
        </Route>
      </Route>
      <Route name="user" path="/user" component={UserIsAuthenticated(User)} onEnter={connect(UserIsAuthenticated.onEnter)} title="User Dashboard">
        <Route name="dashboard-user" component={DashboardUser}>
          <IndexRoute component={ProfileUser} />
          <Route name="profile-user" path="/user/profile" component={ProfileUser} />
          <Route name="status-user" path="/user/status" component={StatusUser} />
        </Route>
      </Route>
      <Route path="*" component={NoMatch} show_title="false" />
    </Route>
  )
}

And here's what I've got so far with v2, though obviously it will redirect if a user doesn't have admin rights instead of displaying a FailureComponent:

import React from 'react';
import { Route, IndexRoute } from 'react-router';
import connectedAuthWrapper from 'redux-auth-wrapper/connectedAuthWrapper';
import { connectedRouterRedirect, createOnEnter } from 'redux-auth-wrapper/history3/redirect';

import App from './app/base/App';
import NoMatch from './app/base/components/NoMatch';
import NotAuthorized from './app/base/components/NotAuthorized';

// import Auth and Registration components
import Login from './app/auth/Login';

// import Public components
import Home from './app/public/Home';

// import User components
import User from './app/user/User';
import DashboardUser from './app/user/DashboardUser';
import ProfileUser from './app/user/ProfileUser';
import StatusUser from './app/user/StatusUser';

// import Admin components
import Admin from './app/admin/Admin';
import DashboardAdmin from './app/admin/dashboard-admin';
import OperationsPanel from './app/admin/OperationsPanel';
import Overview from './app/admin/Overview';


const onEnterAuth = createOnEnter({
  redirectPath: '/login',
  authenticatedSelector: state => state.auth.login.status.isAuthenticated,
})

const UserIsAuthenticated = connectedRouterRedirect({
  redirectPath: '/login',
  authenticatedSelector: state => state.auth.login.status.isAuthenticated,
  wrapperDisplayName: 'UserIsAuthenticated',
})

const onEnterAdmin = createOnEnter({
  redirectPath: '/login',
  authenticatedSelector: state => state.auth.login.userInfo.role === 9,
})

const UserIsAdmin = connectedAuthWrapper({
  authenticatedSelector: state => state.auth.login.userInfo.role === 9,
  FailureComponent: NotAuthorized,
  wrapperDisplayName: 'UserIsAdmin',
})

export default (store) => {
  const connect = (fn) => (nextState, replaceState) => fn(store, nextState, replaceState)

  const onEnterChain = (...listOfOnEnters) => (store, nextState, replace) => {
    let redirected = false;
    const wrappedReplace = (...args) => {
      replace(...args);
      redirected = true;
    };
    listOfOnEnters.forEach((onEnter) => {
      if (!redirected) {
        onEnter(store, nextState, wrappedReplace);
      }
    });
  };

  return (
    <Route path="/" component={App}>
      <IndexRoute name="home" component={Home} show_title={false} />
      <Route name="Login" path="/login" component={Login} show_title={false} />
      <Route name="Admin" path="/admin" component={UserIsAuthenticated(UserIsAdmin(Admin))} onEnter={connect(onEnterChain(onEnterAuth, onEnterAdmin))} title="Admin Dashboard">
        <Route name="dashboard-admin" component={DashboardAdmin}>
          <IndexRoute component={OperationsPanel} big_header={false} />
          <Route name="admin-operations" path="/admin/operations" component={OperationsPanel} big_header={false} />
          <Route name="admin-overview" path="/admin/overview" component={Overview} big_header={false} />
        </Route>
      </Route>
      <Route name="user" path="/user" component={UserIsAuthenticated(User)} onEnter={connect(onEnterAuth)} title="User Dashboard">
        <Route name="dashboard-user" component={DashboardUser}>
          <IndexRoute component={ProfileUser} />
          <Route name="profile-user" path="/user/profile" component={ProfileUser} />
          <Route name="status-user" path="/user/status" component={StatusUser} />
        </Route>
      </Route>
      <Route path="*" component={NoMatch} show_title="false" />
    </Route>
  )
}

Metadata

Metadata

Assignees

No one assigned

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions