diff --git a/README.md b/README.md index c5ec467..b52568d 100644 --- a/README.md +++ b/README.md @@ -15,10 +15,23 @@ Now you can visit `localhost:3000` from your browser. The environment variables are embedded during the build time. For more information, please refer to the [docs](https://github.com/facebookincubator/create-react-app/blob/master/packages/react-scripts/template/README.md#adding-custom-environment-variables). -| Environment Variable | Default Value | Description | -| ------------------------- |:-------------------------:| -------------------:| -| `REACT_APP_API_ENDPOINT` | `"http://localhost:8000"` | Server API endpoint | -| `REACT_APP_REDUX_LOGGING` | ` ` | Set for Redux Log | +| Environment Variable | Default Value | Description | +| ------------------------- |:-------------------------:| -------------------------------:| +| `REACT_APP_API_ENDPOINT` | `"http://localhost:8000"` | Server API endpoint | +| `REACT_APP_REDUX_LOGGING` | ` ` | Set any value for Redux logging | + + +## Production + +To build the production instance of this application, run the following: + +```bash +export REACT_APP_API_ENDPOINT="http://dev.tannercollin.com:8000/" && yarn build + +# then, to serve the production site locally +yarn global add serve +serve -s build --port 3000 +``` ## Testing diff --git a/src/actions/user/reducer.actions.js b/src/actions/user/reducer.actions.js index ed4316b..f53527b 100644 --- a/src/actions/user/reducer.actions.js +++ b/src/actions/user/reducer.actions.js @@ -4,7 +4,12 @@ import { CLEAR_USER_REQUEST_ERROR, SET_USER_REQUEST_SUCCESS, CLEAR_USER_REQUEST_SUCCESS, - SET_SELF_USER + SET_SELF_USER, + SET_COMPLETE_REGISTRATION_STEP, + SET_COMPLETE_REGISTRATION_CLIENT_OR_PROVIDER, + SET_FORM_PHONE_NUMBER, + SET_FORM_BUSINESS_NUMBER, + SET_FORM_SOCIAL_INSURANCE_NUMBER } from "../../constants/user.constants"; import { parseError } from "../common.actions"; @@ -48,3 +53,38 @@ export function setSelfUser(selfUser) { data: selfUser }; } + +export function setCompleteRegistrationStep(step) { + return { + type: SET_COMPLETE_REGISTRATION_STEP, + data: step + }; +} + +export function setCompleteRegistrationClientOrProvider(clientOrProvider) { + return { + type: SET_COMPLETE_REGISTRATION_CLIENT_OR_PROVIDER, + data: clientOrProvider + }; +} + +export function setFormPhoneNumber(phoneNumber) { + return { + type: SET_FORM_PHONE_NUMBER, + data: phoneNumber + }; +} + +export function setFormBusinessNumber(businessNumber) { + return { + type: SET_FORM_BUSINESS_NUMBER, + data: businessNumber + }; +} + +export function setFormSocialInsuranceNumber(socialInsuranceNumber) { + return { + type: SET_FORM_SOCIAL_INSURANCE_NUMBER, + data: socialInsuranceNumber + }; +} diff --git a/src/components/App.jsx b/src/components/App.jsx index 2130649..cad0395 100644 --- a/src/components/App.jsx +++ b/src/components/App.jsx @@ -7,6 +7,7 @@ import Register from "./Auth/Register"; import ResetPassword from "./Auth/ResetPassword"; import Settings from "./Auth/Settings"; import VerifyEmail from "./Auth/VerifyEmail"; +import CompleteRegistration from "./User/CompleteRegistration"; import Profile from "./User/Profile"; import PrivateRoute from "./Shared/PrivateRoute"; import About from "./Static/About"; @@ -17,15 +18,16 @@ import Navbar from "./Navbar"; class App extends Component { render() { - const footSmash = { - display: "flex", - minHeight: "calc(100vh - 1px)", - flexDirection: "column" - }; return (
-
+
@@ -44,8 +46,10 @@ class App extends Component { component={ResetPassword} /> + +
diff --git a/src/components/Navbar.jsx b/src/components/Navbar.jsx index 31728b2..1c2a602 100644 --- a/src/components/Navbar.jsx +++ b/src/components/Navbar.jsx @@ -3,9 +3,18 @@ import { connect } from "react-redux"; import { Link } from "react-router-dom"; import { Dropdown, Menu } from "semantic-ui-react"; +import { sendGetSelfUserRequest } from "../actions/user/saga.actions"; import { sendLogoutRequest } from "../actions/auth/saga.actions"; class Navbar 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()); + } + } + dispatchLogoutRequest = () => { this.props.dispatch(sendLogoutRequest()); }; @@ -22,7 +31,10 @@ class Navbar extends Component { } function mapStateToProps(state) { - return { ...state.auth }; + return { + userToken: state.auth.userToken, + selfUser: state.user.selfUser + }; } const NavbarView = ({ isAuthenticated, dispatchLogoutRequest }) => ( diff --git a/src/components/Shared/PrivateRoute.jsx b/src/components/Shared/PrivateRoute.jsx index 1665d43..460fa8c 100644 --- a/src/components/Shared/PrivateRoute.jsx +++ b/src/components/Shared/PrivateRoute.jsx @@ -33,16 +33,23 @@ class PrivateRoute extends Component { component, ...rest } = this.props; - // If the user token exists and + // 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) + userToken && (Object.keys(selfUser).length === 0 || isSendingUserRequest) ) { return ; } + // If the user exists but they aren't a client or provider yet, confirm-registration + if ( + userToken && + Object.keys(selfUser).length && + (!selfUser.client || !selfUser.provider) + ) { + return ; + } return ( { + event.preventDefault(); + this.props.dispatch(setCompleteRegistrationStep(data.step)); + }; + + render() { + const { + userToken, + completeRegistrationCurrentStep, + completeRegistrationMaxStep, + completeRegistrationClientOrProvider + } = this.props; + if (!userToken) return ; + return ( + + ); + } +} + +function mapStateToProps(state) { + return { + ...state.user, + userToken: state.auth.userToken + }; +} + +const CompleteRegistrationView = ({ + currentStep, + maxStep, + completeRegistrationClientOrProvider, + onChangeStep +}) => ( + + Complete Registration + + + + + + USER_INFO_STEP} + active={currentStep === USER_INFO_STEP} + title="Basic User Info" + description="Fill out your user information" + onClick={onChangeStep} + disabled={maxStep < USER_INFO_STEP} + step={USER_INFO_STEP} + /> + CLIENT_OR_PROVIDER_STEP} + active={currentStep === CLIENT_OR_PROVIDER_STEP} + title="Client or Provider" + description="Choose to be a Client or a Provider" + onClick={onChangeStep} + disabled={maxStep < CLIENT_OR_PROVIDER_STEP} + step={CLIENT_OR_PROVIDER_STEP} + /> + COMPLETE_INFORMATION_STEP} + active={currentStep === COMPLETE_INFORMATION_STEP} + title="Complete Information" + description="Fill out the client or provider information" + onClick={onChangeStep} + disabled={maxStep < COMPLETE_INFORMATION_STEP} + step={COMPLETE_INFORMATION_STEP} + /> + + + + + {currentStep === USER_INFO_STEP &&

User Info

} + {currentStep === CLIENT_OR_PROVIDER_STEP &&

Client or Provider

} + {currentStep === COMPLETE_INFORMATION_STEP &&

Complete Info

} +
+
+
+
+); + +export default connect(mapStateToProps)(CompleteRegistration); diff --git a/src/components/User/Profile.jsx b/src/components/User/Profile.jsx index ba3ed08..c83c03f 100644 --- a/src/components/User/Profile.jsx +++ b/src/components/User/Profile.jsx @@ -29,7 +29,7 @@ const ProfileView = ({ user }) => ( {user.userinfo && {Object.keys(user.userinfo).map(function(key) { return ( - {user.userinfo[key]} + {key}: {user.userinfo[key]} ) })} } diff --git a/src/constants/user.constants.js b/src/constants/user.constants.js index 54ee206..7cf5ae8 100644 --- a/src/constants/user.constants.js +++ b/src/constants/user.constants.js @@ -5,6 +5,20 @@ 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"; +export const SET_COMPLETE_REGISTRATION_STEP = "SET_COMPLETE_REGISTRATION_STEP"; +export const SET_COMPLETE_REGISTRATION_CLIENT_OR_PROVIDER = + "SET_COMPLETE_REGISTRATION_CLIENT_OR_PROVIDER"; +export const SET_FORM_PHONE_NUMBER = "SET_FORM_PHONE_NUMBER"; +export const SET_FORM_BUSINESS_NUMBER = "SET_FORM_BUSINESS_NUMBER"; +export const SET_FORM_SOCIAL_INSURANCE_NUMBER = + "SET_FORM_SOCIAL_INSURANCE_NUMBER"; // Saga User Action Constants export const SEND_GET_SELF_USER_REQUEST = "SEND_GET_SELF_USER_REQUEST"; + +// Misc. User Constants (int so we can mark prior as completed) +export const USER_INFO_STEP = 1; +export const CLIENT_OR_PROVIDER_STEP = 2; +export const COMPLETE_INFORMATION_STEP = 3; +export const CLIENT = "CLIENT"; +export const PROVIDER = "PROVIDER"; diff --git a/src/reducers/userReducer.js b/src/reducers/userReducer.js index 23c7df5..d484a7b 100644 --- a/src/reducers/userReducer.js +++ b/src/reducers/userReducer.js @@ -4,14 +4,26 @@ import { CLEAR_USER_REQUEST_ERROR, SET_USER_REQUEST_SUCCESS, CLEAR_USER_REQUEST_SUCCESS, - SET_SELF_USER + SET_SELF_USER, + SET_COMPLETE_REGISTRATION_STEP, + SET_COMPLETE_REGISTRATION_CLIENT_OR_PROVIDER, + SET_FORM_PHONE_NUMBER, + SET_FORM_BUSINESS_NUMBER, + SET_FORM_SOCIAL_INSURANCE_NUMBER, + USER_INFO_STEP } from "../constants/user.constants"; const initialState = { isSendingUserRequest: false, userRequestError: "", userRequestSuccess: "", - selfUser: {} + selfUser: {}, + completeRegistrationCurrentStep: USER_INFO_STEP, + completeRegistrationMaxStep: USER_INFO_STEP, + completeRegistrationClientOrProvider: "", + phoneNumber: "", + businessNumber: "", + socialInsuranceNumber: "" }; function userReducer(state = initialState, action) { @@ -46,6 +58,35 @@ function userReducer(state = initialState, action) { ...state, selfUser: action.data }; + case SET_COMPLETE_REGISTRATION_STEP: + return { + ...state, + completeRegistrationCurrentStep: action.data, + completeRegistrationMaxStep: Math.max( + action.data, + state.completeRegistrationMaxStep + ) + }; + case SET_COMPLETE_REGISTRATION_CLIENT_OR_PROVIDER: + return { + ...state, + completeRegistrationClientOrProvider: action.data + }; + case SET_FORM_PHONE_NUMBER: + return { + ...state, + phoneNumber: action.data + }; + case SET_FORM_BUSINESS_NUMBER: + return { + ...state, + businessNumber: action.data + }; + case SET_FORM_SOCIAL_INSURANCE_NUMBER: + return { + ...state, + socialInsuranceNumber: action.data + }; default: return state; }