Fetched User data on Login, modified PrivateRoute logic
This commit is contained in:
parent
4cadf5df3a
commit
e69773ac8e
50
src/actions/user/reducer.actions.js
Normal file
50
src/actions/user/reducer.actions.js
Normal file
|
@ -0,0 +1,50 @@
|
||||||
|
import {
|
||||||
|
IS_SENDING_USER_REQUEST,
|
||||||
|
SET_USER_REQUEST_ERROR,
|
||||||
|
CLEAR_USER_REQUEST_ERROR,
|
||||||
|
SET_USER_REQUEST_SUCCESS,
|
||||||
|
CLEAR_USER_REQUEST_SUCCESS,
|
||||||
|
SET_SELF_USER
|
||||||
|
} from "../../constants/user.constants";
|
||||||
|
import { parseError } from "../common.actions";
|
||||||
|
|
||||||
|
export function isSendingUserRequest(sendingRequest) {
|
||||||
|
return {
|
||||||
|
type: IS_SENDING_USER_REQUEST,
|
||||||
|
data: sendingRequest
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export function setUserRequestError(exception) {
|
||||||
|
let error = parseError(exception);
|
||||||
|
return {
|
||||||
|
type: SET_USER_REQUEST_ERROR,
|
||||||
|
data: error
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export function clearUserRequestError() {
|
||||||
|
return {
|
||||||
|
type: CLEAR_USER_REQUEST_ERROR
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export function setUserRequestSuccess(response) {
|
||||||
|
return {
|
||||||
|
type: SET_USER_REQUEST_SUCCESS,
|
||||||
|
data: response.detail || response
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export function clearUserRequestSuccess() {
|
||||||
|
return {
|
||||||
|
type: CLEAR_USER_REQUEST_SUCCESS
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export function setSelfUser(selfUser) {
|
||||||
|
return {
|
||||||
|
type: SET_SELF_USER,
|
||||||
|
data: selfUser
|
||||||
|
};
|
||||||
|
}
|
7
src/actions/user/saga.actions.js
Normal file
7
src/actions/user/saga.actions.js
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
import { SEND_GET_SELF_USER_REQUEST } from "../../constants/user.constants";
|
||||||
|
|
||||||
|
export function sendGetSelfUserRequest() {
|
||||||
|
return {
|
||||||
|
type: SEND_GET_SELF_USER_REQUEST
|
||||||
|
};
|
||||||
|
}
|
5
src/api/user.api.js
Normal file
5
src/api/user.api.js
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
import { get } from "./baseApi";
|
||||||
|
|
||||||
|
export function getSelfUser() {
|
||||||
|
return get("/user/").then(resp => Promise.resolve(resp));
|
||||||
|
}
|
|
@ -7,6 +7,7 @@ import Register from "./Auth/Register";
|
||||||
import ResetPassword from "./Auth/ResetPassword";
|
import ResetPassword from "./Auth/ResetPassword";
|
||||||
import Settings from "./Auth/Settings";
|
import Settings from "./Auth/Settings";
|
||||||
import VerifyEmail from "./Auth/VerifyEmail";
|
import VerifyEmail from "./Auth/VerifyEmail";
|
||||||
|
import Profile from "./User/Profile";
|
||||||
import PrivateRoute from "./Shared/PrivateRoute";
|
import PrivateRoute from "./Shared/PrivateRoute";
|
||||||
import About from "./Static/About";
|
import About from "./Static/About";
|
||||||
import Footer from "./Static/Footer";
|
import Footer from "./Static/Footer";
|
||||||
|
@ -15,10 +16,6 @@ import NoMatch from "./Static/NoMatch";
|
||||||
import Navbar from "./Navbar";
|
import Navbar from "./Navbar";
|
||||||
|
|
||||||
class App extends Component {
|
class App extends Component {
|
||||||
componentDidMount() {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const footSmash = {
|
const footSmash = {
|
||||||
display: "flex",
|
display: "flex",
|
||||||
|
@ -39,13 +36,14 @@ class App extends Component {
|
||||||
path="/auth/verify-email/:emailKey"
|
path="/auth/verify-email/:emailKey"
|
||||||
component={VerifyEmail}
|
component={VerifyEmail}
|
||||||
/>
|
/>
|
||||||
<Route
|
<Route path="/auth/verify-email" component={VerifyEmail} />
|
||||||
path="/auth/verify-email"
|
|
||||||
component={VerifyEmail}
|
|
||||||
/>
|
|
||||||
<PrivateRoute path="/auth/settings" component={Settings} />
|
<PrivateRoute path="/auth/settings" component={Settings} />
|
||||||
<Route path="/auth/forgot-password" component={ForgotPassword} />
|
<Route path="/auth/forgot-password" component={ForgotPassword} />
|
||||||
<Route path="/auth/reset-password/:uid/:token" component={ResetPassword} />
|
<Route
|
||||||
|
path="/auth/reset-password/:uid/:token"
|
||||||
|
component={ResetPassword}
|
||||||
|
/>
|
||||||
|
<PrivateRoute path="/user/profile" component={Profile} />
|
||||||
<Route component={NoMatch} />
|
<Route component={NoMatch} />
|
||||||
</Switch>
|
</Switch>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -41,7 +41,7 @@ class Login extends Component {
|
||||||
password,
|
password,
|
||||||
userToken
|
userToken
|
||||||
} = this.props;
|
} = this.props;
|
||||||
if (userToken) return <Redirect to={"/"} />;
|
if (userToken) return <Redirect to={"/user/profile"} />;
|
||||||
return (
|
return (
|
||||||
<LoginView
|
<LoginView
|
||||||
isSendingAuthRequest={isSendingAuthRequest}
|
isSendingAuthRequest={isSendingAuthRequest}
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import React, { Component } from "react";
|
import React, { Component } from "react";
|
||||||
import { connect } from "react-redux";
|
import { connect } from "react-redux";
|
||||||
import { Link } from "react-router-dom";
|
import { Link, Redirect } from "react-router-dom";
|
||||||
import { Container, Form, Header, Message } from "semantic-ui-react";
|
import { Container, Form, Header, Message } from "semantic-ui-react";
|
||||||
|
|
||||||
import {
|
import {
|
||||||
|
@ -39,8 +39,10 @@ class VerifyEmail extends Component {
|
||||||
isSendingAuthRequest,
|
isSendingAuthRequest,
|
||||||
authRequestError,
|
authRequestError,
|
||||||
authRequestSuccess,
|
authRequestSuccess,
|
||||||
emailVerificationString
|
emailVerificationString,
|
||||||
|
userToken
|
||||||
} = this.props;
|
} = this.props;
|
||||||
|
if (userToken) return <Redirect to={"/"} />;
|
||||||
return (
|
return (
|
||||||
<VerifyEmailView
|
<VerifyEmailView
|
||||||
isSendingAuthRequest={isSendingAuthRequest}
|
isSendingAuthRequest={isSendingAuthRequest}
|
||||||
|
|
|
@ -46,9 +46,13 @@ const NavbarView = ({ isAuthenticated, dispatchLogoutRequest }) => (
|
||||||
<Menu.Menu position="right">
|
<Menu.Menu position="right">
|
||||||
<Dropdown item text="Account">
|
<Dropdown item text="Account">
|
||||||
<Dropdown.Menu>
|
<Dropdown.Menu>
|
||||||
|
<Dropdown.Item as={Link} to="/user/profile">
|
||||||
|
My Profile
|
||||||
|
</Dropdown.Item>
|
||||||
<Dropdown.Item as={Link} to="/auth/settings">
|
<Dropdown.Item as={Link} to="/auth/settings">
|
||||||
Settings
|
Settings
|
||||||
</Dropdown.Item>
|
</Dropdown.Item>
|
||||||
|
<Dropdown.Divider />
|
||||||
<Dropdown.Item onClick={dispatchLogoutRequest}>
|
<Dropdown.Item onClick={dispatchLogoutRequest}>
|
||||||
Logout
|
Logout
|
||||||
</Dropdown.Item>
|
</Dropdown.Item>
|
||||||
|
|
|
@ -1,15 +1,48 @@
|
||||||
import PropTypes from "prop-types";
|
import PropTypes from "prop-types";
|
||||||
import React from "react";
|
import React, { Component } from "react";
|
||||||
import { connect } from "react-redux";
|
import { connect } from "react-redux";
|
||||||
import { Redirect, Route } from "react-router-dom";
|
import { Redirect, Route } from "react-router-dom";
|
||||||
|
import { Loader } from "semantic-ui-react";
|
||||||
|
|
||||||
|
import { sendGetSelfUserRequest } from "../../actions/user/saga.actions";
|
||||||
|
|
||||||
const propTypes = {
|
const propTypes = {
|
||||||
path: PropTypes.string.isRequired,
|
|
||||||
userToken: PropTypes.string.isRequired,
|
userToken: PropTypes.string.isRequired,
|
||||||
component: PropTypes.oneOfType([PropTypes.element, PropTypes.func]).isRequired
|
selfUser: PropTypes.object.isRequired,
|
||||||
|
isSendingUserRequest: PropTypes.bool.isRequired,
|
||||||
|
path: PropTypes.string.isRequired,
|
||||||
|
component: PropTypes.oneOfType([PropTypes.element, PropTypes.func])
|
||||||
|
.isRequired,
|
||||||
|
dispatch: PropTypes.func.isRequired
|
||||||
};
|
};
|
||||||
|
|
||||||
const PrivateRoute = ({ userToken, component, ...rest }) => {
|
class PrivateRoute extends Component {
|
||||||
|
componentWillMount() {
|
||||||
|
const { dispatch, userToken, selfUser } = this.props;
|
||||||
|
// If the user token exists and the self user object isn't loaded, dispatch
|
||||||
|
if (userToken && Object.keys(selfUser).length === 0) {
|
||||||
|
dispatch(sendGetSelfUserRequest());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
const {
|
||||||
|
userToken,
|
||||||
|
selfUser,
|
||||||
|
isSendingUserRequest,
|
||||||
|
component,
|
||||||
|
...rest
|
||||||
|
} = this.props;
|
||||||
|
// If the user token exists and
|
||||||
|
// * self user object isn't loaded yet or
|
||||||
|
// * we are still sending user request
|
||||||
|
// show loading spinner
|
||||||
|
if (
|
||||||
|
!!userToken &&
|
||||||
|
(Object.keys(selfUser).length === 0 || isSendingUserRequest)
|
||||||
|
) {
|
||||||
|
return <Loader active />;
|
||||||
|
}
|
||||||
return (
|
return (
|
||||||
<Route
|
<Route
|
||||||
{...rest}
|
{...rest}
|
||||||
|
@ -19,12 +52,15 @@ const PrivateRoute = ({ userToken, component, ...rest }) => {
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
};
|
}
|
||||||
|
}
|
||||||
|
|
||||||
PrivateRoute.propTypes = propTypes;
|
PrivateRoute.propTypes = propTypes;
|
||||||
|
|
||||||
const mapStateToProps = state => ({
|
const mapStateToProps = state => ({
|
||||||
userToken: state.auth.userToken
|
userToken: state.auth.userToken,
|
||||||
|
selfUser: state.user.selfUser,
|
||||||
|
isSendingUserRequest: state.user.isSendingUserRequest
|
||||||
});
|
});
|
||||||
|
|
||||||
export default connect(mapStateToProps)(PrivateRoute);
|
export default connect(mapStateToProps)(PrivateRoute);
|
||||||
|
|
47
src/components/User/Profile.jsx
Normal file
47
src/components/User/Profile.jsx
Normal file
|
@ -0,0 +1,47 @@
|
||||||
|
import React, { Component } from "react";
|
||||||
|
import { connect } from "react-redux";
|
||||||
|
import { Card, Container, Header, Label, List } from "semantic-ui-react";
|
||||||
|
|
||||||
|
class Profile extends Component {
|
||||||
|
render() {
|
||||||
|
const { selfUser } = this.props;
|
||||||
|
return <ProfileView user={selfUser} />;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function mapStateToProps(state) {
|
||||||
|
return { ...state.user };
|
||||||
|
}
|
||||||
|
|
||||||
|
const ProfileView = ({ user }) => (
|
||||||
|
<Container>
|
||||||
|
<Header>Profile</Header>
|
||||||
|
<Card>
|
||||||
|
<Card.Content>
|
||||||
|
<Card.Header>{user.username || "No username!"}</Card.Header>
|
||||||
|
<Card.Meta>{user.email || "No email!"}</Card.Meta>
|
||||||
|
<Card.Description>
|
||||||
|
<span>
|
||||||
|
{user.client && "Client"}{user.provider && "Provider"}
|
||||||
|
{!user.client && !user.provider && "User Registration Not Completed"}
|
||||||
|
</span>
|
||||||
|
{user.first_name} {user.last_name}
|
||||||
|
{user.userinfo && <List>
|
||||||
|
{Object.keys(user.userinfo).map(function(key) {
|
||||||
|
return (<List.Item key={key}>
|
||||||
|
{user.userinfo[key]}
|
||||||
|
</List.Item>)
|
||||||
|
})}
|
||||||
|
</List>}
|
||||||
|
</Card.Description>
|
||||||
|
</Card.Content>
|
||||||
|
<Card.Content extra>
|
||||||
|
<Label color={user.is_active ? "teal" : "red"} size="tiny" tag>
|
||||||
|
{user.is_active ? "Active" : "Deactivated"}
|
||||||
|
</Label>
|
||||||
|
</Card.Content>
|
||||||
|
</Card>
|
||||||
|
</Container>
|
||||||
|
);
|
||||||
|
|
||||||
|
export default connect(mapStateToProps)(Profile);
|
10
src/constants/user.constants.js
Normal file
10
src/constants/user.constants.js
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
// Reducer User Action Constants
|
||||||
|
export const IS_SENDING_USER_REQUEST = "IS_SENDING_USER_REQUEST";
|
||||||
|
export const SET_USER_REQUEST_ERROR = "SET_USER_REQUEST_ERROR";
|
||||||
|
export const CLEAR_USER_REQUEST_ERROR = "CLEAR_USER_REQUEST_ERROR";
|
||||||
|
export const SET_USER_REQUEST_SUCCESS = "SET_USER_REQUEST_SUCCESS";
|
||||||
|
export const CLEAR_USER_REQUEST_SUCCESS = "CLEAR_USER_REQUEST_SUCCESS";
|
||||||
|
export const SET_SELF_USER = "SET_SELF_USER";
|
||||||
|
|
||||||
|
// Saga User Action Constants
|
||||||
|
export const SEND_GET_SELF_USER_REQUEST = "SEND_GET_SELF_USER_REQUEST";
|
|
@ -1,8 +1,10 @@
|
||||||
import { combineReducers } from "redux";
|
import { combineReducers } from "redux";
|
||||||
import authReducer from "./authReducer";
|
import authReducer from "./authReducer";
|
||||||
|
import userReducer from "./userReducer";
|
||||||
|
|
||||||
const reducer = combineReducers({
|
const reducer = combineReducers({
|
||||||
auth: authReducer
|
auth: authReducer,
|
||||||
|
user: userReducer
|
||||||
});
|
});
|
||||||
|
|
||||||
export default reducer;
|
export default reducer;
|
||||||
|
|
54
src/reducers/userReducer.js
Normal file
54
src/reducers/userReducer.js
Normal file
|
@ -0,0 +1,54 @@
|
||||||
|
import {
|
||||||
|
IS_SENDING_USER_REQUEST,
|
||||||
|
SET_USER_REQUEST_ERROR,
|
||||||
|
CLEAR_USER_REQUEST_ERROR,
|
||||||
|
SET_USER_REQUEST_SUCCESS,
|
||||||
|
CLEAR_USER_REQUEST_SUCCESS,
|
||||||
|
SET_SELF_USER
|
||||||
|
} from "../constants/user.constants";
|
||||||
|
|
||||||
|
const initialState = {
|
||||||
|
isSendingUserRequest: false,
|
||||||
|
userRequestError: "",
|
||||||
|
userRequestSuccess: "",
|
||||||
|
selfUser: {}
|
||||||
|
};
|
||||||
|
|
||||||
|
function userReducer(state = initialState, action) {
|
||||||
|
switch (action.type) {
|
||||||
|
case IS_SENDING_USER_REQUEST:
|
||||||
|
return {
|
||||||
|
...state,
|
||||||
|
isSendingUserRequest: action.data
|
||||||
|
};
|
||||||
|
case SET_USER_REQUEST_ERROR:
|
||||||
|
return {
|
||||||
|
...state,
|
||||||
|
userRequestError: action.data
|
||||||
|
};
|
||||||
|
case CLEAR_USER_REQUEST_ERROR:
|
||||||
|
return {
|
||||||
|
...state,
|
||||||
|
userRequestError: ""
|
||||||
|
};
|
||||||
|
case SET_USER_REQUEST_SUCCESS:
|
||||||
|
return {
|
||||||
|
...state,
|
||||||
|
userRequestSuccess: action.data
|
||||||
|
};
|
||||||
|
case CLEAR_USER_REQUEST_SUCCESS:
|
||||||
|
return {
|
||||||
|
...state,
|
||||||
|
userRequestSuccess: ""
|
||||||
|
};
|
||||||
|
case SET_SELF_USER:
|
||||||
|
return {
|
||||||
|
...state,
|
||||||
|
selfUser: action.data
|
||||||
|
};
|
||||||
|
default:
|
||||||
|
return state;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default userReducer;
|
|
@ -11,6 +11,7 @@ import {
|
||||||
setFormPasswordConfirmation,
|
setFormPasswordConfirmation,
|
||||||
setFormOldPassword
|
setFormOldPassword
|
||||||
} from "../actions/auth/reducer.actions";
|
} from "../actions/auth/reducer.actions";
|
||||||
|
import { setSelfUser } from "../actions/user/reducer.actions";
|
||||||
import {
|
import {
|
||||||
registerUser,
|
registerUser,
|
||||||
verifyEmail,
|
verifyEmail,
|
||||||
|
@ -156,6 +157,7 @@ export function* logoutUserFlow(request) {
|
||||||
yield effects.put(clearAuthRequestError());
|
yield effects.put(clearAuthRequestError());
|
||||||
yield effects.call(logoutUserCall);
|
yield effects.call(logoutUserCall);
|
||||||
yield effects.put(setSelfUserToken(""));
|
yield effects.put(setSelfUserToken(""));
|
||||||
|
yield effects.put(setSelfUser({}));
|
||||||
}
|
}
|
||||||
|
|
||||||
export function* changePasswordFlow(request) {
|
export function* changePasswordFlow(request) {
|
||||||
|
|
|
@ -17,6 +17,12 @@ import {
|
||||||
forgotPasswordFlow,
|
forgotPasswordFlow,
|
||||||
resetPasswordFlow,
|
resetPasswordFlow,
|
||||||
} from "./auth.sagas";
|
} from "./auth.sagas";
|
||||||
|
import {
|
||||||
|
SEND_GET_SELF_USER_REQUEST
|
||||||
|
} from "../constants/user.constants";
|
||||||
|
import {
|
||||||
|
getSelfUserFlow
|
||||||
|
} from "./user.sagas";
|
||||||
|
|
||||||
export default function* rootSaga() {
|
export default function* rootSaga() {
|
||||||
yield takeLatest(SEND_REGISTER_REQUEST, registerUserFlow);
|
yield takeLatest(SEND_REGISTER_REQUEST, registerUserFlow);
|
||||||
|
@ -26,4 +32,5 @@ export default function* rootSaga() {
|
||||||
yield takeLatest(SEND_CHANGE_PASSWORD_REQUEST, changePasswordFlow);
|
yield takeLatest(SEND_CHANGE_PASSWORD_REQUEST, changePasswordFlow);
|
||||||
yield takeLatest(SEND_FORGOT_PASSWORD_REQUEST, forgotPasswordFlow);
|
yield takeLatest(SEND_FORGOT_PASSWORD_REQUEST, forgotPasswordFlow);
|
||||||
yield takeLatest(SEND_RESET_PASSWORD_REQUEST, resetPasswordFlow);
|
yield takeLatest(SEND_RESET_PASSWORD_REQUEST, resetPasswordFlow);
|
||||||
|
yield takeLatest(SEND_GET_SELF_USER_REQUEST, getSelfUserFlow);
|
||||||
}
|
}
|
||||||
|
|
43
src/sagas/user.sagas.js
Normal file
43
src/sagas/user.sagas.js
Normal file
|
@ -0,0 +1,43 @@
|
||||||
|
import { effects } from "redux-saga";
|
||||||
|
import { setSelfUserToken } from "../actions/auth/reducer.actions";
|
||||||
|
import {
|
||||||
|
isSendingUserRequest,
|
||||||
|
setUserRequestError,
|
||||||
|
setUserRequestSuccess,
|
||||||
|
clearUserRequestError,
|
||||||
|
clearUserRequestSuccess,
|
||||||
|
setSelfUser
|
||||||
|
} from "../actions/user/reducer.actions";
|
||||||
|
import { getSelfUser } from "../api/user.api";
|
||||||
|
|
||||||
|
function* getSelfUserCall() {
|
||||||
|
yield effects.put(isSendingUserRequest(true));
|
||||||
|
try {
|
||||||
|
const wasSuccessful = yield effects.call(getSelfUser);
|
||||||
|
yield effects.put(setUserRequestSuccess(wasSuccessful));
|
||||||
|
yield effects.put(clearUserRequestError());
|
||||||
|
// Check if the user exists, if yes set the user, otherwise force logout
|
||||||
|
if (wasSuccessful.results && wasSuccessful.results.length) {
|
||||||
|
yield effects.put(setSelfUser(wasSuccessful.results[0]));
|
||||||
|
} else {
|
||||||
|
yield effects.put(setSelfUserToken(""));
|
||||||
|
yield effects.put(setSelfUser({}));
|
||||||
|
}
|
||||||
|
return wasSuccessful;
|
||||||
|
} catch (exception) {
|
||||||
|
yield effects.put(setUserRequestError(exception));
|
||||||
|
return false;
|
||||||
|
} finally {
|
||||||
|
yield effects.put(isSendingUserRequest(false));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function* getSelfUserFlow(request) {
|
||||||
|
yield effects.put(clearUserRequestSuccess());
|
||||||
|
yield effects.put(clearUserRequestError());
|
||||||
|
const wasSuccessful = yield effects.call(getSelfUserCall);
|
||||||
|
if (!wasSuccessful) {
|
||||||
|
yield effects.put(setSelfUserToken(""));
|
||||||
|
yield effects.put(setSelfUser({}));
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user