diff --git a/README.md b/README.md
index d866719..c5ec467 100644
--- a/README.md
+++ b/README.md
@@ -13,12 +13,12 @@ Now you can visit `localhost:3000` from your browser.
## Environment Variables
-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.
+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 |
+| `REACT_APP_REDUX_LOGGING` | ` ` | Set for Redux Log |
## Testing
diff --git a/src/actions/auth/reducer.actions.js b/src/actions/auth/reducer.actions.js
index 63d8e79..c5f9f9a 100644
--- a/src/actions/auth/reducer.actions.js
+++ b/src/actions/auth/reducer.actions.js
@@ -4,10 +4,15 @@ import {
CLEAR_AUTH_REQUEST_ERROR,
SET_AUTH_REQUEST_SUCCESS,
CLEAR_AUTH_REQUEST_SUCCESS,
+ SET_EMAIL_VERIFICATION_SUCCESS,
+ CLEAR_EMAIL_VERIFICATION_SUCCESS,
+ SET_EMAIL_VERIFICATION_ERROR,
+ CLEAR_EMAIL_VERIFICATION_ERROR,
SET_SELF_USER,
SET_FORM_EMAIL,
SET_FORM_PASSWORD,
- SET_FORM_PASSWORD_CONFIRMATION
+ SET_FORM_PASSWORD_CONFIRMATION,
+ SET_FORM_EMAIL_VERIFICATION
} from "../../constants/auth.constants";
import { parseError } from "../common.actions";
@@ -19,27 +24,27 @@ export function isSendingAuthRequest(sendingRequest) {
}
export function setAuthRequestError(exception) {
- let rawError = parseError(exception);
- if (rawError.email) {
- rawError["Email"] = rawError.email;
- delete rawError["email"];
+ let error = parseError(exception);
+ if (error.email) {
+ error["Email"] = error.email;
+ delete error["email"];
}
- if (rawError.password1) {
- rawError["Password"] = rawError.password1;
- delete rawError["password1"];
+ if (error.password1) {
+ error["Password"] = error.password1;
+ delete error["password1"];
}
- if (rawError.password2) {
- rawError["Password Confirmation"] = rawError.password2;
- delete rawError["password2"];
+ if (error.password2) {
+ error["Password Confirmation"] = error.password2;
+ delete error["password2"];
}
- if (rawError.non_field_errors) {
- rawError["Non Field Errors"] = rawError.non_field_errors;
- delete rawError["non_field_errors"];
+ if (error.non_field_errors) {
+ error["Non Field Errors"] = error.non_field_errors;
+ delete error["non_field_errors"];
}
return {
type: SET_AUTH_REQUEST_ERROR,
- data: parseError(exception)
+ data: error
};
}
@@ -53,13 +58,49 @@ export function setAuthRequestSuccess(response) {
return {
type: SET_AUTH_REQUEST_SUCCESS,
data: response.detail || response
- }
+ };
}
export function clearAuthRequestSuccess() {
return {
type: CLEAR_AUTH_REQUEST_SUCCESS
+ };
+}
+
+export function setEmailVerificationError(exception) {
+ let error = parseError(exception);
+ if (error.detail) {
+ error["Email"] = error.detail;
+ delete error["detail"];
+ }
+ if (error.key) {
+ error["Verification Key"] = error.key;
+ delete error["key"];
}
+
+ return {
+ type: SET_EMAIL_VERIFICATION_ERROR,
+ data: error
+ };
+}
+
+export function clearEmailVerificationError() {
+ return {
+ type: CLEAR_EMAIL_VERIFICATION_ERROR
+ };
+}
+
+export function setEmailVerificationSuccess(response) {
+ return {
+ type: SET_EMAIL_VERIFICATION_SUCCESS,
+ data: response.detail || response
+ };
+}
+
+export function clearEmailVerificationSuccess() {
+ return {
+ type: CLEAR_EMAIL_VERIFICATION_SUCCESS
+ };
}
export function setSelfUser(selfUser) {
@@ -89,3 +130,10 @@ export function setFormPasswordConfirmation(passwordConfirmation) {
data: passwordConfirmation
};
}
+
+export function setFormEmailVerification(emailKey) {
+ return {
+ type: SET_FORM_EMAIL_VERIFICATION,
+ data: emailKey
+ };
+}
diff --git a/src/actions/auth/saga.actions.js b/src/actions/auth/saga.actions.js
index c887c72..523877a 100644
--- a/src/actions/auth/saga.actions.js
+++ b/src/actions/auth/saga.actions.js
@@ -1,10 +1,18 @@
import {
- SEND_REGISTER_REQUEST
+ SEND_REGISTER_REQUEST,
+ SEND_EMAIL_VERIFICATION_REQUEST
} from "../../constants/auth.constants";
export function sendRegisterRequest(postbody) {
return {
type: SEND_REGISTER_REQUEST,
data: postbody
- }
+ };
+}
+
+export function sendEmailVerificationRequest(postbody) {
+ return {
+ type: SEND_EMAIL_VERIFICATION_REQUEST,
+ data: postbody
+ };
}
diff --git a/src/api/auth.api.js b/src/api/auth.api.js
index ca11449..769e935 100644
--- a/src/api/auth.api.js
+++ b/src/api/auth.api.js
@@ -15,3 +15,11 @@ export function registerUser(email, password1, password2) {
return Promise.resolve(response);
});
}
+
+export function verifyEmail(emailKey) {
+ return post("/rest-auth/registration/verify-email/", {
+ key: emailKey
+ }).then(response => {
+ return Promise.resolve(response);
+ });
+}
diff --git a/src/components/App.jsx b/src/components/App.jsx
index b5d96e6..30a3ebf 100644
--- a/src/components/App.jsx
+++ b/src/components/App.jsx
@@ -3,6 +3,7 @@ import { Route, Switch } from "react-router-dom";
import Login from "./Auth/Login";
import Register from "./Auth/Register";
+import VerifyEmail from "./Auth/VerifyEmail";
import About from "./Static/About";
import Footer from "./Static/Footer";
import Home from "./Static/Home";
@@ -26,6 +27,10 @@ class App extends Component {
+
diff --git a/src/components/Auth/Register.jsx b/src/components/Auth/Register.jsx
index 490eac6..3ac7730 100644
--- a/src/components/Auth/Register.jsx
+++ b/src/components/Auth/Register.jsx
@@ -1,9 +1,10 @@
import React, { Component } from "react";
import { connect } from "react-redux";
-import { Container, Form, Header, Message } from "semantic-ui-react";
+import { Container, Form, Header, Message } from "semantic-ui-react";
import {
clearAuthRequestError,
+ clearAuthRequestSuccess,
setFormEmail,
setFormPassword,
setFormPasswordConfirmation
@@ -15,6 +16,7 @@ class Register extends Component {
constructor(props) {
super(props);
this.props.dispatch(clearAuthRequestError());
+ this.props.dispatch(clearAuthRequestSuccess());
}
changeEmail = event => {
@@ -122,12 +124,11 @@ const RegisterView = ({
/>
-
-
Submit
+
+ Confirmation Email Sent!
+ Please check your email to confirm your registration.
+
+ Register
);
diff --git a/src/components/Auth/VerifyEmail.jsx b/src/components/Auth/VerifyEmail.jsx
new file mode 100644
index 0000000..c962873
--- /dev/null
+++ b/src/components/Auth/VerifyEmail.jsx
@@ -0,0 +1,97 @@
+import React, { Component } from "react";
+import { connect } from "react-redux";
+import { Link } from "react-router-dom";
+import { Container, Form, Header, Message } from "semantic-ui-react";
+
+import {
+ clearEmailVerificationError,
+ clearEmailVerificationSuccess,
+ setFormEmailVerification
+} from "../../actions/auth/reducer.actions";
+import { sendEmailVerificationRequest } from "../../actions/auth/saga.actions";
+import Error from "../Shared/Error";
+
+class VerifyEmail extends Component {
+ constructor(props) {
+ super(props);
+ const emailKey = this.props.match.params.emailKey;
+ this.props.dispatch(clearEmailVerificationError());
+ this.props.dispatch(clearEmailVerificationSuccess());
+ this.props.dispatch(setFormEmailVerification(emailKey));
+ }
+
+ changeEmailKey = event => {
+ this.props.dispatch(setFormEmailVerification(event.target.value));
+ };
+
+ onSubmitEmailVerification = event => {
+ event.preventDefault();
+ const { dispatch, emailVerificationString } = this.props;
+ dispatch(
+ sendEmailVerificationRequest({ emailKey: emailVerificationString })
+ );
+ };
+
+ render() {
+ const {
+ isSendingAuthRequest,
+ emailVerificationRequestError,
+ emailVerificationRequestSuccess,
+ emailVerificationString
+ } = this.props;
+ return (
+
+ );
+ }
+}
+
+function mapStateToProps(state) {
+ return { ...state.auth };
+}
+
+const VerifyEmailView = ({
+ isSendingAuthRequest,
+ emailVerificationRequestError,
+ emailVerificationRequestSuccess,
+ emailVerificationString,
+ changeEmailKey,
+ onSubmitEmailVerification
+}) => (
+
+
+
+
+
+
+
+
+ Email Verified!
+ Please proceed to log in.
+
+ Verify Email
+
+
+);
+
+export default connect(mapStateToProps)(VerifyEmail);
diff --git a/src/constants/auth.constants.js b/src/constants/auth.constants.js
index 22b1946..c40e6d2 100644
--- a/src/constants/auth.constants.js
+++ b/src/constants/auth.constants.js
@@ -4,10 +4,18 @@ export const SET_AUTH_REQUEST_ERROR = "SET_AUTH_REQUEST_ERROR";
export const CLEAR_AUTH_REQUEST_ERROR = "CLEAR_AUTH_REQUEST_ERROR";
export const SET_AUTH_REQUEST_SUCCESS = "SET_AUTH_REQUEST_SUCCESS";
export const CLEAR_AUTH_REQUEST_SUCCESS = "CLEAR_AUTH_REQUEST_SUCCESS";
+export const SET_EMAIL_VERIFICATION_SUCCESS = "SET_EMAIL_VERIFICATION_SUCCESS";
+export const CLEAR_EMAIL_VERIFICATION_SUCCESS =
+ "CLEAR_EMAIL_VERIFICATION_SUCCESS";
+export const SET_EMAIL_VERIFICATION_ERROR = "SET_EMAIL_VERIFICATION_ERROR";
+export const CLEAR_EMAIL_VERIFICATION_ERROR = "CLEAR_EMAIL_VERIFICATION_ERROR";
export const SET_SELF_USER = "SET_SELF_USER";
export const SET_FORM_EMAIL = "SET_FORM_EMAIL";
export const SET_FORM_PASSWORD = "SET_FORM_PASSWORD";
export const SET_FORM_PASSWORD_CONFIRMATION = "SET_FORM_PASSWORD_CONFIRMATION";
+export const SET_FORM_EMAIL_VERIFICATION = "SET_FORM_EMAIL_VERIFICATION";
// Saga Auth Action Constants
export const SEND_REGISTER_REQUEST = "SEND_REGISTER_REQUEST";
+export const SEND_EMAIL_VERIFICATION_REQUEST =
+ "SEND_EMAIL_VERIFICATION_REQUEST";
diff --git a/src/reducers/authReducer.js b/src/reducers/authReducer.js
index 21325f2..6bce905 100644
--- a/src/reducers/authReducer.js
+++ b/src/reducers/authReducer.js
@@ -4,20 +4,28 @@ import {
CLEAR_AUTH_REQUEST_ERROR,
SET_AUTH_REQUEST_SUCCESS,
CLEAR_AUTH_REQUEST_SUCCESS,
+ SET_EMAIL_VERIFICATION_ERROR,
+ CLEAR_EMAIL_VERIFICATION_ERROR,
+ SET_EMAIL_VERIFICATION_SUCCESS,
+ CLEAR_EMAIL_VERIFICATION_SUCCESS,
SET_SELF_USER,
SET_FORM_EMAIL,
SET_FORM_PASSWORD,
- SET_FORM_PASSWORD_CONFIRMATION
+ SET_FORM_PASSWORD_CONFIRMATION,
+ SET_FORM_EMAIL_VERIFICATION
} from "../constants/auth.constants";
const initialState = {
isSendingAuthRequest: false,
authRequestError: "",
authRequestSuccess: "",
+ emailVerificationRequestError: "",
+ emailVerificationRequestSuccess: "",
currentUser: {},
email: "",
password: "",
- passwordConfirmation: ""
+ passwordConfirmation: "",
+ emailVerificationString: ""
};
function authReducer(state = initialState, action) {
@@ -47,6 +55,26 @@ function authReducer(state = initialState, action) {
...state,
authRequestSuccess: ""
};
+ case SET_EMAIL_VERIFICATION_ERROR:
+ return {
+ ...state,
+ emailVerificationRequestError: action.data
+ };
+ case CLEAR_EMAIL_VERIFICATION_ERROR:
+ return {
+ ...state,
+ emailVerificationRequestError: ""
+ };
+ case SET_EMAIL_VERIFICATION_SUCCESS:
+ return {
+ ...state,
+ emailVerificationRequestSuccess: action.data
+ };
+ case CLEAR_EMAIL_VERIFICATION_SUCCESS:
+ return {
+ ...state,
+ emailVerificationRequestSuccess: ""
+ };
case SET_SELF_USER:
return {
...state,
@@ -67,6 +95,11 @@ function authReducer(state = initialState, action) {
...state,
passwordConfirmation: action.data
};
+ case SET_FORM_EMAIL_VERIFICATION:
+ return {
+ ...state,
+ emailVerificationString: action.data
+ };
default:
return state;
}
diff --git a/src/sagas/auth.sagas.js b/src/sagas/auth.sagas.js
index 2ec22fd..e730650 100644
--- a/src/sagas/auth.sagas.js
+++ b/src/sagas/auth.sagas.js
@@ -3,17 +3,19 @@ import {
isSendingAuthRequest,
setAuthRequestError,
setAuthRequestSuccess,
+ setEmailVerificationError,
+ setEmailVerificationSuccess,
clearAuthRequestError,
+ clearEmailVerificationError,
+ clearAuthRequestSuccess,
+ clearEmailVerificationSuccess,
setFormEmail,
setFormPassword,
- setFormPasswordConfirmation
+ setFormPasswordConfirmation,
+ setFormEmailVerification
} from "../actions/auth/reducer.actions";
-import { registerUser } from "../api/auth.api";
+import { registerUser, verifyEmail } from "../api/auth.api";
-/**
- * Saga for registering a new user.
- * @param {*} postBody
- */
function* registerUserCall(postBody) {
yield effects.put(isSendingAuthRequest(true));
const { email, password1, password2 } = postBody;
@@ -27,7 +29,22 @@ function* registerUserCall(postBody) {
}
}
+function* verifyEmailCall(postBody) {
+ yield effects.put(isSendingAuthRequest(true));
+ const { emailKey } = postBody;
+ try {
+ return yield effects.call(verifyEmail, emailKey);
+ } catch (exception) {
+ yield effects.put(setEmailVerificationError(exception));
+ return false;
+ } finally {
+ yield effects.put(isSendingAuthRequest(false));
+ }
+}
+
export function* registerUserFlow(request) {
+ yield effects.put(clearAuthRequestSuccess());
+ yield effects.put(clearAuthRequestError());
const wasSucessful = yield effects.call(registerUserCall, request.data);
if (wasSucessful) {
yield effects.put(setAuthRequestSuccess(wasSucessful));
@@ -37,3 +54,14 @@ export function* registerUserFlow(request) {
yield effects.put(setFormPasswordConfirmation(""));
}
}
+
+export function* verifyEmailFlow(request) {
+ yield effects.put(clearEmailVerificationSuccess());
+ yield effects.put(clearEmailVerificationError());
+ const wasSucessful = yield effects.call(verifyEmailCall, request.data);
+ if (wasSucessful) {
+ yield effects.put(setEmailVerificationSuccess(wasSucessful));
+ yield effects.put(clearEmailVerificationError());
+ yield effects.put(setFormEmailVerification(""));
+ }
+}
diff --git a/src/sagas/index.js b/src/sagas/index.js
index 4a981c6..6d852db 100644
--- a/src/sagas/index.js
+++ b/src/sagas/index.js
@@ -1,7 +1,8 @@
import { takeLatest } from "redux-saga/effects";
-import { SEND_REGISTER_REQUEST } from "../constants/auth.constants";
-import { registerUserFlow } from "./auth.sagas";
+import { SEND_REGISTER_REQUEST, SEND_EMAIL_VERIFICATION_REQUEST } from "../constants/auth.constants";
+import { registerUserFlow, verifyEmailFlow } from "./auth.sagas";
export default function* rootSaga() {
yield takeLatest(SEND_REGISTER_REQUEST, registerUserFlow);
+ yield takeLatest(SEND_EMAIL_VERIFICATION_REQUEST, verifyEmailFlow);
}