Dani
Dani

Reputation: 2488

redux-auth-wrapper does not redirect after authentication

I've got the following react-router setup:

const UserIsAuthenticated = UserAuthWrapper({
  authSelector: state => state.get('user').toJS(),
  predicate: authData => !!authData.token,
  redirectAction: routerActions.replace,
  wrapperDisplayName: 'UserIsAuthenticated'
})

const Authenticated = UserIsAuthenticated(props => props.children)

const routes =
  <Route path="/">
    <IndexRoute component={UserIsAuthenticated(applyFrame(Catalog))} />
    <Route path="login" component={Login} />
    <Route component={applyFrame(Authenticated)}>
      <Route path="catalog" component={Catalog}>
        <Route path="overview" component={CatalogOverview} />
        <Route path="form" component={CatalogForm} />
        <Route path="confirmation" component={CatalogConfirmation} />
      </Route>
      <Route path="ive">
        <IndexRoute component={Page} />
        <Route path=":id" component={PageDetail} />
      </Route>
    </Route>
  </Route>

I want to achieve the following things: When a user is not authenticated and is accessing the root location (/) a login screen is shown and after logging in the user is redirected to the Catalog View. When a user is accessing another location (e.g. /catalog/overview) the user will be prompted to login and after a successful authentication the user will be redirected to /catalog/overview.

Thing is: the initial redirect works just fine. The login page is shown whenever I try to access a location. So we can state that the redirectAction is working. Also: the authSelector works just fine, because when I console.log state.get('user') I get the user object that usually is in my state. Furthermore: when I remove UserIsAuthenticated from the first IndexRoute navigation is working as it should be.

When I login, my Redux DevTools shows me that my token is being set and I would expect my react-router-redux routerActions.replace to respond to that.

My userReducer.js:

import { Map } from 'immutable'

import {
  USER_LOGGED_IN,
  USER_LOGGED_OUT
} from './consts'

export default function authenticationReducer (
  state: Map<*, *> = Map({}), action: Object
) {
  switch (action.type) {
    case USER_LOGGED_IN:
      return state
        .set('token', action.payload.get('token'))
    case USER_LOGGED_OUT:
      return state
        .set('token', undefined)
    default:
      return state
  }
}

And this is how I load my routes:

const renderApp = () => {
  ReactDOM.render(
    <AppContainer>
      <MuiThemeProvider muiTheme={muiTheme}>
        <Provider store={store}>
          <Router history={history} routes={routes} />
        </Provider>
      </MuiThemeProvider>
    </AppContainer>,
    document.getElementById('root')
  )
}

How can I make these routes re-trigger upon login?

Upvotes: 1

Views: 1103

Answers (1)

Anton Novik
Anton Novik

Reputation: 1837

I had the same problem, I have fixed it by adding redirection in Login component render (there is only one difference with your code, I check that user is authorized by checking user prop, not user.token):

export class Login extends React.PureComponent {
  static propTypes = {
    dispatchLogin: React.PropTypes.func,
    dispatchLogout: React.PropTypes.func,
    user: React.PropTypes.object,
    location: React.PropTypes.object,
    router: React.PropTypes.object,
  }

  render() {
    const { dispatchLogout, dispatchLogin, user, location, router } = this.props;

    // make redirect if user is logged in and redirect is required
    if (user) {
      if (location && location.query && location.query.redirect && router) {
        router.push(location.query.redirect);
      }
    }

    const handleLogin = (values) => new Promise((resolve, reject) => {
      dispatchLogin(values, { resolve, reject });
    });

    return (
      <div className={`${styles.loginPage} container`}>
        <Helmet title="Login" />
        <h2>Login</h2>
        {!user && <LoginForm onSubmit={handleLogin} />}
        {user &&
          <div>
            <p>You are currently logged in as {user.name}.</p>
            <button className="btn btn-danger" onClick={dispatchLogout}>
              <i className="fa fa-sign-out" />{' '}Log Out
            </button>
          </div>
        }
      </div>
    );
  }
}

Upvotes: 1

Related Questions