Completed full user profile editing functionality

This commit is contained in:
Alexander Wong 2017-09-04 12:29:51 -06:00
parent 4ee5670cfb
commit fc8747d295
11 changed files with 272 additions and 13 deletions

View File

@ -9,7 +9,8 @@ import {
SET_COMPLETE_REGISTRATION_CLIENT_OR_PROVIDER, SET_COMPLETE_REGISTRATION_CLIENT_OR_PROVIDER,
SET_FORM_PHONE_NUMBER, SET_FORM_PHONE_NUMBER,
SET_FORM_BUSINESS_NUMBER, SET_FORM_BUSINESS_NUMBER,
SET_FORM_SOCIAL_INSURANCE_NUMBER SET_FORM_SOCIAL_INSURANCE_NUMBER,
SET_EDIT_PROFILE_TAB_ACTIVE_INDEX
} from "../../constants/user.constants"; } from "../../constants/user.constants";
import { parseError } from "../common.actions"; import { parseError } from "../common.actions";
@ -94,3 +95,10 @@ export function setFormSocialInsuranceNumber(socialInsuranceNumber) {
data: socialInsuranceNumber data: socialInsuranceNumber
}; };
} }
export function setEditProfileTabActiveIndex(indexVal) {
return {
type: SET_EDIT_PROFILE_TAB_ACTIVE_INDEX,
data: indexVal
};
}

View File

@ -8,6 +8,7 @@ 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 CompleteRegistration from "./User/CompleteRegistration"; import CompleteRegistration from "./User/CompleteRegistration";
import EditProfile from "./User/EditProfile";
import Profile from "./User/Profile"; 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";
@ -45,6 +46,7 @@ class App extends Component {
path="/auth/reset-password/:uid/:token" path="/auth/reset-password/:uid/:token"
component={ResetPassword} component={ResetPassword}
/> />
<PrivateRoute path="/user/profile/edit" component={EditProfile} />
<PrivateRoute path="/user/profile" component={Profile} /> <PrivateRoute path="/user/profile" component={Profile} />
<Route path='/user/complete-registration' component={Profile} /> <Route path='/user/complete-registration' component={Profile} />
<Route component={NoMatch} /> <Route component={NoMatch} />

View File

@ -0,0 +1,59 @@
import React, { Component } from "react";
import { connect } from "react-redux";
import {
clearUserRequestError,
clearUserRequestSuccess,
setFormBusinessNumber
} from "../../actions/user/reducer.actions";
import { updateClientRequest } from "../../actions/user/saga.actions";
import ClientFormView from "./ClientFormView";
class EditClientForm extends Component {
changeBusinessNumber = event => {
this.props.dispatch(setFormBusinessNumber(event.target.value));
this.props.dispatch(clearUserRequestError());
this.props.dispatch(clearUserRequestSuccess());
};
onSubmitClient = event => {
event.preventDefault();
const { selfUser, businessNumber } = this.props;
const businessNumberVal =
businessNumber || (selfUser.client || {}).business_number;
this.props.dispatch(
updateClientRequest({
username: selfUser.username,
business_number: businessNumberVal
})
);
};
render() {
const {
isSendingUserRequest,
userRequestError,
userRequestSuccess,
businessNumber,
selfUser
} = this.props;
const businessNumberVal =
businessNumber || (selfUser.client || {}).business_number;
return (
<ClientFormView
isSendingUserRequest={isSendingUserRequest}
userRequestError={userRequestError}
userRequestSuccess={userRequestSuccess}
businessNumber={businessNumberVal}
changeBusinessNumber={this.changeBusinessNumber}
onSubmitClient={this.onSubmitClient}
/>
);
}
}
function mapStateToProps(state) {
return { ...state.user };
}
export default connect(mapStateToProps)(EditClientForm);

View File

@ -0,0 +1,59 @@
import React, { Component } from "react";
import { connect } from "react-redux";
import { Container, Header, Tab } from "semantic-ui-react";
import {
setEditProfileTabActiveIndex,
clearUserRequestError,
clearUserRequestSuccess
} from "../../actions/user/reducer.actions";
import EditClientForm from "./EditClientForm";
import EditProviderForm from "./EditProviderForm";
import EditUserInfoForm from "./EditUserInfoForm";
class EditProfile extends Component {
onTabChange = (event, { activeIndex }) => {
if (this.props.editProfileActiveIndex !== activeIndex) {
this.props.dispatch(clearUserRequestError());
this.props.dispatch(clearUserRequestSuccess());
}
this.props.dispatch(setEditProfileTabActiveIndex(activeIndex));
};
render() {
const { selfUser, editProfileActiveIndex } = this.props;
const panes = [
{
menuItem: "User Information",
render: () => <Tab.Pane><EditUserInfoForm /></Tab.Pane>
}
];
if (selfUser.client) {
panes.push({
menuItem: "Client Information",
render: () => <Tab.Pane><EditClientForm /></Tab.Pane>
});
} else if (selfUser.provider) {
panes.push({
menuItem: "Provider Information",
render: () => <Tab.Pane><EditProviderForm /></Tab.Pane>
});
}
return (
<Container>
<Header>Edit Profile</Header>
<Tab
panes={panes}
onTabChange={this.onTabChange}
activeIndex={editProfileActiveIndex}
/>
</Container>
);
}
}
function mapStateToProps(state) {
return { ...state.user };
}
export default connect(mapStateToProps)(EditProfile);

View File

@ -0,0 +1,56 @@
import React, { Component } from "react";
import { connect } from "react-redux";
import {
clearUserRequestError,
clearUserRequestSuccess,
setFormSocialInsuranceNumber
} from "../../actions/user/reducer.actions";
import { updateProviderRequest } from "../../actions/user/saga.actions";
import ProviderFormView from "./ProviderFormView";
class EditProviderForm extends Component {
changeSocialInsuranceNumber = event => {
this.props.dispatch(setFormSocialInsuranceNumber(event.target.value));
this.props.dispatch(clearUserRequestError());
this.props.dispatch(clearUserRequestSuccess());
};
onSubmitProvider = event => {
event.preventDefault();
const { selfUser, socialInsuranceNumber } = this.props;
const socialInsuranceNumberVal =
socialInsuranceNumber || (selfUser.provider || {}).sin;
this.props.dispatch(
updateProviderRequest({ username: selfUser.username, sin: socialInsuranceNumberVal })
);
};
render() {
const {
isSendingUserRequest,
userRequestError,
userRequestSuccess,
socialInsuranceNumber,
selfUser
} = this.props;
const socialInsuranceNumberVal =
socialInsuranceNumber || (selfUser.provider || {}).sin;
return (
<ProviderFormView
isSendingUserRequest={isSendingUserRequest}
userRequestError={userRequestError}
userRequestSuccess={userRequestSuccess}
socialInsuranceNumber={socialInsuranceNumberVal}
changeSocialInsuranceNumber={this.changeSocialInsuranceNumber}
onSubmitProvider={this.onSubmitProvider}
/>
);
}
}
function mapStateToProps(state) {
return { ...state.user };
}
export default connect(mapStateToProps)(EditProviderForm);

View File

@ -0,0 +1,62 @@
import React, { Component } from "react";
import { connect } from "react-redux";
import {
clearUserRequestError,
clearUserRequestSuccess,
setFormPhoneNumber
} from "../../actions/user/reducer.actions";
import { updateUserInfoRequest } from "../../actions/user/saga.actions";
import UserInfoFormView from "./UserInfoFormView";
class EditUserInfoForm extends Component {
changePhoneNumber = event => {
this.props.dispatch(setFormPhoneNumber(event.target.value));
this.props.dispatch(clearUserRequestError());
this.props.dispatch(clearUserRequestSuccess());
};
onSubmitUserInfo = event => {
event.preventDefault();
const { selfUser, phoneNumber } = this.props;
const phoneNumberVal =
phoneNumber || (selfUser.userinfo || {}).phone_number;
this.props.dispatch(
updateUserInfoRequest({
...selfUser.userinfo,
username: selfUser.username,
phone_number: phoneNumberVal
})
);
};
render() {
const {
isSendingUserRequest,
userRequestError,
userRequestSuccess,
selfUser,
phoneNumber
} = this.props;
const phoneNumberVal =
phoneNumber || (selfUser.userinfo || {}).phone_number;
return (
<UserInfoFormView
isSendingUserRequest={isSendingUserRequest}
userRequestError={userRequestError}
userRequestSuccess={userRequestSuccess}
phoneNumber={phoneNumberVal}
changePhoneNumber={this.changePhoneNumber}
onSubmitUserInfo={this.onSubmitUserInfo}
/>
);
}
}
function mapStateToProps(state) {
return { ...state.user };
}
export default connect(mapStateToProps)(EditUserInfoForm);

View File

@ -1,5 +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 { Card, Container, Header, Label, List } from "semantic-ui-react"; import { Card, Container, Header, Label, List } from "semantic-ui-react";
class Profile extends Component { class Profile extends Component {
@ -16,10 +17,17 @@ function mapStateToProps(state) {
const ProfileView = ({ user }) => ( const ProfileView = ({ user }) => (
<Container> <Container>
<Header>Profile</Header> <Header>Profile</Header>
<Card> <Card fluid={true}>
<Card.Content> <Card.Content>
<Card.Header>{user.username || "No username!"}</Card.Header> <Card.Header>{user.username || "No username!"}</Card.Header>
<Card.Meta>{user.email || "No email!"}</Card.Meta> <Card.Meta>
{user.client && <Label color="blue" size="tiny">Client</Label>}
{user.provider && <Label color="orange" size="tiny">Provider</Label>}
<Label color={user.is_active ? "teal" : "red"} size="tiny">
{user.is_active ? "Active" : "Deactivated"}
</Label>
{" "}{user.email || "No email!"}
</Card.Meta>
<Card.Description> <Card.Description>
<span> <span>
{!user.client && {!user.client &&
@ -56,11 +64,7 @@ const ProfileView = ({ user }) => (
</Card.Description> </Card.Description>
</Card.Content> </Card.Content>
<Card.Content extra> <Card.Content extra>
{user.client && <Label color="blue">Client</Label>} <Link to="/user/profile/edit">Edit Profile</Link>
{user.provider && <Label color="orange">Provider</Label>}
<Label color={user.is_active ? "teal" : "red"}>
{user.is_active ? "Active" : "Deactivated"}
</Label>
</Card.Content> </Card.Content>
</Card> </Card>
</Container> </Container>

View File

@ -22,7 +22,7 @@ const UserInfoFormView = ({
<Form.Field> <Form.Field>
<label>Phone Number</label> <label>Phone Number</label>
<input <input
placeholder="780-999-9999" placeholder="7809999999"
type="tel" type="tel"
value={phoneNumber} value={phoneNumber}
onChange={changePhoneNumber} onChange={changePhoneNumber}

View File

@ -12,6 +12,8 @@ export const SET_FORM_PHONE_NUMBER = "SET_FORM_PHONE_NUMBER";
export const SET_FORM_BUSINESS_NUMBER = "SET_FORM_BUSINESS_NUMBER"; export const SET_FORM_BUSINESS_NUMBER = "SET_FORM_BUSINESS_NUMBER";
export const SET_FORM_SOCIAL_INSURANCE_NUMBER = export const SET_FORM_SOCIAL_INSURANCE_NUMBER =
"SET_FORM_SOCIAL_INSURANCE_NUMBER"; "SET_FORM_SOCIAL_INSURANCE_NUMBER";
export const SET_EDIT_PROFILE_TAB_ACTIVE_INDEX =
"SET_EDIT_PROFILE_TAB_ACTIVE_INDEX";
// Saga User Action Constants // Saga User Action Constants
export const GET_SELF_USER_REQUEST = "GET_SELF_USER_REQUEST"; export const GET_SELF_USER_REQUEST = "GET_SELF_USER_REQUEST";

View File

@ -10,6 +10,7 @@ import {
SET_FORM_PHONE_NUMBER, SET_FORM_PHONE_NUMBER,
SET_FORM_BUSINESS_NUMBER, SET_FORM_BUSINESS_NUMBER,
SET_FORM_SOCIAL_INSURANCE_NUMBER, SET_FORM_SOCIAL_INSURANCE_NUMBER,
SET_EDIT_PROFILE_TAB_ACTIVE_INDEX,
USER_INFO_STEP, USER_INFO_STEP,
CLIENT CLIENT
} from "../constants/user.constants"; } from "../constants/user.constants";
@ -24,7 +25,8 @@ const initialState = {
completeRegistrationClientOrProvider: CLIENT, completeRegistrationClientOrProvider: CLIENT,
phoneNumber: "", phoneNumber: "",
businessNumber: "", businessNumber: "",
socialInsuranceNumber: "" socialInsuranceNumber: "",
editProfileActiveIndex: 0
}; };
function userReducer(state = initialState, action) { function userReducer(state = initialState, action) {
@ -88,6 +90,11 @@ function userReducer(state = initialState, action) {
...state, ...state,
socialInsuranceNumber: action.data socialInsuranceNumber: action.data
}; };
case SET_EDIT_PROFILE_TAB_ACTIVE_INDEX:
return {
...state,
editProfileActiveIndex: action.data
};
default: default:
return state; return state;
} }

View File

@ -17,7 +17,6 @@ function* getSelfUserCall() {
yield effects.put(isSendingUserRequest(true)); yield effects.put(isSendingUserRequest(true));
try { try {
const wasSuccessful = yield effects.call(getSelfUser); const wasSuccessful = yield effects.call(getSelfUser);
yield effects.put(setUserRequestSuccess(wasSuccessful));
yield effects.put(clearUserRequestError()); yield effects.put(clearUserRequestError());
// Check if the user exists, if yes set the user, otherwise force logout // Check if the user exists, if yes set the user, otherwise force logout
if (wasSuccessful.results && wasSuccessful.results.length) { if (wasSuccessful.results && wasSuccessful.results.length) {
@ -114,8 +113,6 @@ function* updateProviderCall(payload) {
} }
export function* getSelfUserFlow(request) { export function* getSelfUserFlow(request) {
yield effects.put(clearUserRequestSuccess());
yield effects.put(clearUserRequestError());
const wasSuccessful = yield effects.call(getSelfUserCall); const wasSuccessful = yield effects.call(getSelfUserCall);
if (!wasSuccessful) { if (!wasSuccessful) {
yield effects.put(setSelfUserToken("")); yield effects.put(setSelfUserToken(""));
@ -139,6 +136,7 @@ export function* updateUserInfoFlow(request) {
yield effects.put(clearUserRequestError()); yield effects.put(clearUserRequestError());
const wasSuccessful = yield effects.call(updateUserInfoCall, request.data); const wasSuccessful = yield effects.call(updateUserInfoCall, request.data);
if (wasSuccessful) { if (wasSuccessful) {
yield effects.put(setUserRequestSuccess(wasSuccessful));
yield effects.put(clearUserRequestError()); yield effects.put(clearUserRequestError());
yield effects.put(setCompleteRegistrationStep(CLIENT_OR_PROVIDER_STEP)); yield effects.put(setCompleteRegistrationStep(CLIENT_OR_PROVIDER_STEP));
yield effects.put(getSelfUserRequest()); yield effects.put(getSelfUserRequest());
@ -160,6 +158,7 @@ export function* updateClientFlow(request) {
yield effects.put(clearUserRequestError()); yield effects.put(clearUserRequestError());
const wasSuccessful = yield effects.call(updateClientCall, request.data); const wasSuccessful = yield effects.call(updateClientCall, request.data);
if (wasSuccessful) { if (wasSuccessful) {
yield effects.put(setUserRequestSuccess(wasSuccessful));
yield effects.put(clearUserRequestError()); yield effects.put(clearUserRequestError());
yield effects.put(getSelfUserRequest()); yield effects.put(getSelfUserRequest());
} }
@ -180,6 +179,7 @@ export function* updateProviderFlow(request) {
yield effects.put(clearUserRequestError()); yield effects.put(clearUserRequestError());
const wasSuccessful = yield effects.call(updateProviderCall, request.data); const wasSuccessful = yield effects.call(updateProviderCall, request.data);
if (wasSuccessful) { if (wasSuccessful) {
yield effects.put(setUserRequestSuccess(wasSuccessful));
yield effects.put(clearUserRequestError()); yield effects.put(clearUserRequestError());
yield effects.put(getSelfUserRequest()); yield effects.put(getSelfUserRequest());
} }