diff --git a/email_app/app/actions/actionTypes.js b/email_app/app/actions/actionTypes.js
index 2915ad6..a156af1 100644
--- a/email_app/app/actions/actionTypes.js
+++ b/email_app/app/actions/actionTypes.js
@@ -15,7 +15,6 @@ const ACTION_TYPES = {
// Mail Inbox
PUSH_MAIL: 'PUSH_MAIL',
MAIL_PROCESSING: 'MAIL_PROCESSING',
- CLEAR_MAIL_PROCESSING: 'CLEAR_MAIL_PROCESSING',
SET_ACTIVE_MAIL: 'SET_ACTIVE_MAIL',
CANCEL_COMPOSE: 'CANCEL_COMPOSE',
diff --git a/email_app/app/actions/create_account_actions.js b/email_app/app/actions/create_account_actions.js
index cb920ea..37f0c35 100644
--- a/email_app/app/actions/create_account_actions.js
+++ b/email_app/app/actions/create_account_actions.js
@@ -12,6 +12,6 @@ export const createAccount = (emailId) => {
};
export const createAccountError = (error) => ({
- type: ACTION_TYPES.CREATE_ACCOUNT_ERROR,
- error
+ type: ACTION_TYPES.CREATE_ACCOUNT,
+ payload: Promise.reject(error)
});
diff --git a/email_app/app/actions/mail_actions.js b/email_app/app/actions/mail_actions.js
index 13fec7f..ae164b0 100644
--- a/email_app/app/actions/mail_actions.js
+++ b/email_app/app/actions/mail_actions.js
@@ -6,9 +6,8 @@ export const sendEmail = (email, to) => {
let app = getState().initializer.app;
return dispatch({
type: ACTION_TYPES.MAIL_PROCESSING,
+ msg: 'Sending email...',
payload: storeEmail(app, email, to)
- .then(() => dispatch(clearMailProcessing))
- .then(() => Promise.resolve())
});
};
};
@@ -18,9 +17,8 @@ export const saveEmail = (account, key) => {
let app = getState().initializer.app;
return dispatch({
type: ACTION_TYPES.MAIL_PROCESSING,
+ msg: 'Saving email...',
payload: archiveEmail(app, account, key)
- .then(() => dispatch(clearMailProcessing))
- .then(() => Promise.resolve())
});
};
};
@@ -30,17 +28,12 @@ export const deleteEmail = (container, key) => {
let app = getState().initializer.app;
return dispatch({
type: ACTION_TYPES.MAIL_PROCESSING,
+ msg: 'Deleting email...',
payload: removeEmail(app, container, key)
- .then(() => dispatch(clearMailProcessing))
- .then(() => Promise.resolve())
});
};
};
-export const clearMailProcessing = _ => ({
- type: ACTION_TYPES.CLEAR_MAIL_PROCESSING
-});
-
export const cancelCompose = _ => ({
type: ACTION_TYPES.CANCEL_COMPOSE
});
diff --git a/email_app/app/components/create_account.js b/email_app/app/components/create_account.js
index ff6d113..b64e571 100644
--- a/email_app/app/components/create_account.js
+++ b/email_app/app/components/create_account.js
@@ -41,7 +41,6 @@ export default class CreateAccount extends Component {
render() {
const { processing, error } = this.props;
-
return (
@@ -54,7 +53,7 @@ export default class CreateAccount extends Component {
Email Id must be less than {CONSTANTS.EMAIL_ID_MAX_LENGTH} characters. (This is just a restriction in this tutorial)
-
+
{error.message}
diff --git a/email_app/app/components/home.js b/email_app/app/components/home.js
index d73c43b..11bf3d5 100755
--- a/email_app/app/components/home.js
+++ b/email_app/app/components/home.js
@@ -1,59 +1,63 @@
import React, { Component } from 'react';
import PropTypes from 'prop-types';
import { Link, IndexLink } from 'react-router';
-import Modal from 'react-modal';
+import {ModalDialog, ModalPortal, ModalBackground} from 'react-modal-dialog';
+import ReactSpinner from 'react-spinjs';
import className from 'classnames';
import pkg from '../../package.json';
import { CONSTANTS } from '../constants';
-const modalStyles = {
- content : {
- top : '50%',
- left : '50%',
- right : 'auto',
- bottom : 'auto',
- marginRight : '-50%',
- transform : 'translate(-50%, -50%)'
- }
-};
-
export default class Home extends Component {
constructor() {
super();
- this.state = {
- reconnecting: false
- };
this.reconnect = this.reconnect.bind(this);
}
reconnect() {
- this.setState({reconnecting: true});
- return this.props.reconnectApplication()
- .catch((err) => 'not reconnected')
- .then(() => this.setState({reconnecting: false}))
+ const { reconnectApplication, accounts, refreshEmail } = this.props;
+ return reconnectApplication()
+ .then(() => refreshEmail(accounts),
+ (err) => 'failed reconnecting');
}
render() {
const { router } = this.context;
- const { coreData, inboxSize, savedSize, network_status } = this.props;
+ const { coreData, inboxSize, savedSize, network_status, processing } = this.props;
- const isNetworkDisconnected = (network_status !== CONSTANTS.NET_STATUS_CONNECTED);
+ const isModalOpen = processing.state || (network_status !== CONSTANTS.NET_STATUS_CONNECTED);
+ const spinnerBackgroundStyle = {
+ zIndex: '5',
+ position: 'fixed',
+ height: '100%',
+ width: '100%',
+ opacity: '0.75',
+ backgroundColor: 'white'
+ }
return (
-
-
-
The application hast lost network connection.
-
Make sure the network link is up before trying to reconnect.
-
-
-
+ {
+ isModalOpen &&
+
+ {
+ processing.state ?
+
+
+
+ :
+
+
+
+
The application hast lost network connection.
+
Make sure the network link is up before trying to reconnect.
+
+
+
+
+ }
+
+ }
diff --git a/email_app/app/components/initializer.js b/email_app/app/components/initializer.js
index 53c98be..a1f2e3c 100644
--- a/email_app/app/components/initializer.js
+++ b/email_app/app/components/initializer.js
@@ -28,6 +28,7 @@ export default class Initializer extends Component {
refreshConfig() {
const { setInitializerTask, refreshConfig } = this.props;
setInitializerTask(MESSAGES.INITIALIZE.CHECK_CONFIGURATION);
+
return refreshConfig()
.then((_) => {
if (Object.keys(this.props.accounts).length > 0) {
diff --git a/email_app/app/components/mail_list.js b/email_app/app/components/mail_list.js
index c680375..8a92c55 100644
--- a/email_app/app/components/mail_list.js
+++ b/email_app/app/components/mail_list.js
@@ -9,27 +9,12 @@ export default class MailList extends Component {
super();
this.listColors = {};
this.activeType = null;
- this.goBack = this.goBack.bind(this);
this.refreshEmail = this.refreshEmail.bind(this);
this.handleDeleteFromInbox = this.handleDeleteFromInbox.bind(this);
this.handleDeleteSaved = this.handleDeleteSaved.bind(this);
this.handleSave = this.handleSave.bind(this);
}
- goBack() {
- const { router } = this.context;
-
- switch (this.activeType) {
- case CONSTANTS.HOME_TABS.INBOX: {
- return this.props.refreshEmail();
- }
- case CONSTANTS.HOME_TABS.SAVED: {
- router.push('/home');
- return router.push('/saved');
- }
- }
- }
-
refreshEmail(account) {
this.props.refreshEmail(account)
.catch((error) => {
@@ -76,87 +61,82 @@ export default class MailList extends Component {
render() {
const self = this;
- const { processing, coreData, error, inboxSize, inbox, savedSize, saved } = this.props;
+ const { coreData, error, inboxSize, inbox, savedSize, saved } = this.props;
let container = null;
- if (processing) {
- container =
Loading...
- } else if (Object.keys(error).length > 0) {
- container =
Error in fetching emails!
- } else {
- if (inbox) {
- this.activeType = CONSTANTS.HOME_TABS.INBOX;
- container = (
-
- {
- inboxSize === 0 ?
Inbox empty : Object.keys(coreData.inbox).map((key) => {
- let mail = coreData.inbox[key];
- if (!self.listColors.hasOwnProperty(mail.from)) {
- self.listColors[mail.from] = `bg-color-${Object.keys(self.listColors).length % 10}`
- }
- return (
-
-
- {mail.from[0]}
-
-
-
{mail.from}
-
{dateformat(new Date(mail.time), CONSTANTS.DATE_FORMAT)}
-
{mail.subject}
-
{mail.body}
+ if (inbox) {
+ this.activeType = CONSTANTS.HOME_TABS.INBOX;
+ container = (
+
+ {
+ inboxSize === 0 ?
Inbox empty : Object.keys(coreData.inbox).map((key) => {
+ let mail = coreData.inbox[key];
+ if (!self.listColors.hasOwnProperty(mail.from)) {
+ self.listColors[mail.from] = `bg-color-${Object.keys(self.listColors).length % 10}`
+ }
+ return (
+
+
+ {mail.from[0]}
+
+
+
{mail.from}
+
{dateformat(new Date(mail.time), CONSTANTS.DATE_FORMAT)}
+
{mail.subject}
+
{mail.body}
+
+
+
+
-
-
-
-
-
-
-
+
+
-
- )
- })
- }
-
- );
- }
- if (saved) {
- this.activeType = CONSTANTS.HOME_TABS.SAVED;
- container = (
-
- {
- savedSize === 0 ?
Saved empty : Object.keys(coreData.saved).map((key) => {
- let mail = coreData.saved[key];
- if (!mail) {
- return;
- }
- if (!self.listColors.hasOwnProperty(mail.from)) {
- self.listColors[mail.from] = `bg-color-${Object.keys(self.listColors).length % 10}`
- }
- return (
-
-
- {mail.from[0]}
-
-
-
{mail.from}
-
{dateformat(new Date(mail.time), CONSTANTS.DATE_FORMAT)}
-
{mail.subject}
-
{mail.body}
-
-
+
+ )
+ })
+ }
+
+ );
+ }
+ if (saved) {
+ this.activeType = CONSTANTS.HOME_TABS.SAVED;
+ container = (
+
+ {
+ savedSize === 0 ?
Saved empty : Object.keys(coreData.saved).map((key) => {
+ let mail = coreData.saved[key];
+ if (!mail) {
+ return;
+ }
+ if (!self.listColors.hasOwnProperty(mail.from)) {
+ self.listColors[mail.from] = `bg-color-${Object.keys(self.listColors).length % 10}`
+ }
+ return (
+
+
+ {mail.from[0]}
+
+
+
{mail.from}
+
{dateformat(new Date(mail.time), CONSTANTS.DATE_FORMAT)}
+
{mail.subject}
+
{mail.body}
+
+
+
+
-
- )
- })
- }
-
- );
- }
+
+
+ )
+ })
+ }
+
+ );
}
+
return (
{container}
diff --git a/email_app/app/containers/compose_mail_container.js b/email_app/app/containers/compose_mail_container.js
index 11ae136..4430b14 100644
--- a/email_app/app/containers/compose_mail_container.js
+++ b/email_app/app/containers/compose_mail_container.js
@@ -1,20 +1,18 @@
import { connect } from 'react-redux';
import ComposeMail from '../components/compose_mail';
-import { cancelCompose, sendEmail, clearMailProcessing } from '../actions/mail_actions';
+import { cancelCompose, sendEmail } from '../actions/mail_actions';
const mapStateToProps = state => {
return {
app: state.initializer.app,
fromMail: state.initializer.coreData.id,
- error: state.mail.error,
- processing: state.mail.processing
+ error: state.mail.error
};
};
const mapDispatchToProps = dispatch => {
return {
sendEmail: (email, to) => (dispatch(sendEmail(email, to))),
- clearMailProcessing: _ => (dispatch(clearMailProcessing())),
cancelCompose: _ => dispatch(cancelCompose())
};
};
diff --git a/email_app/app/containers/create_account_container.js b/email_app/app/containers/create_account_container.js
index 3012740..bb74fd6 100644
--- a/email_app/app/containers/create_account_container.js
+++ b/email_app/app/containers/create_account_container.js
@@ -6,7 +6,7 @@ import { storeNewAccount } from '../actions/initializer_actions';
const mapStateToProps = state => {
return {
error: state.createAccount.error,
- processing: state.createAccount.processing,
+ processing: state.initializer.processing,
newAccount: state.createAccount.newAccount,
coreData: state.initializer.coreData
};
diff --git a/email_app/app/containers/home_container.js b/email_app/app/containers/home_container.js
index 6c38f0c..4644919 100644
--- a/email_app/app/containers/home_container.js
+++ b/email_app/app/containers/home_container.js
@@ -1,19 +1,22 @@
import { connect } from 'react-redux';
import Home from '../components/home';
-import { reconnectApplication } from '../actions/initializer_actions';
+import { reconnectApplication, refreshEmail } from '../actions/initializer_actions';
const mapStateToProps = state => {
return {
coreData: state.initializer.coreData,
+ accounts: state.initializer.accounts,
inboxSize: state.initializer.inboxSize,
savedSize: state.initializer.savedSize,
- network_status: state.initializer.network_status
+ network_status: state.initializer.network_status,
+ processing: state.initializer.processing
};
};
const mapDispatchToProps = dispatch => {
return {
reconnectApplication: () => (dispatch(reconnectApplication())),
+ refreshEmail: (account) => (dispatch(refreshEmail(account))),
};
};
diff --git a/email_app/app/containers/mail_inbox_container.js b/email_app/app/containers/mail_inbox_container.js
index 752ae40..9f19423 100644
--- a/email_app/app/containers/mail_inbox_container.js
+++ b/email_app/app/containers/mail_inbox_container.js
@@ -1,11 +1,10 @@
import { connect } from 'react-redux';
import MailInbox from '../components/mail_inbox';
-import { refreshInbox, clearMailProcessing, deleteEmail, saveEmail } from '../actions/mail_actions';
+import { refreshInbox, deleteEmail, saveEmail } from '../actions/mail_actions';
import { refreshEmail } from '../actions/initializer_actions';
const mapStateToProps = state => {
return {
- processing: state.mail.processing,
error: state.mail.error,
coreData: state.initializer.coreData,
inboxSize: state.initializer.inboxSize,
@@ -19,7 +18,6 @@ const mapDispatchToProps = dispatch => {
return {
refreshEmail: (account) => (dispatch(refreshEmail(account))),
deleteEmail: (account, key) => (dispatch(deleteEmail(account, key))),
- clearMailProcessing: () => (dispatch(clearMailProcessing())),
saveEmail: (account, key) => (dispatch(saveEmail(account, key)))
};
};
diff --git a/email_app/app/less/authenticate.less b/email_app/app/less/authenticate.less
index 585bfc8..bfa7ef1 100644
--- a/email_app/app/less/authenticate.less
+++ b/email_app/app/less/authenticate.less
@@ -1,3 +1,5 @@
+@import "variables.less";
+
.create-account {
width: 100%;
height: 100%;
diff --git a/email_app/app/less/base.less b/email_app/app/less/base.less
index cffcd19..02eb74f 100644
--- a/email_app/app/less/base.less
+++ b/email_app/app/less/base.less
@@ -1,3 +1,5 @@
+@import "variables.less";
+
.noselect {
-webkit-touch-callout: none; /* iOS Safari */
-webkit-user-select: none; /* Chrome/Safari/Opera */
diff --git a/email_app/app/less/buttons.less b/email_app/app/less/buttons.less
index cbdff7a..c4328a9 100644
--- a/email_app/app/less/buttons.less
+++ b/email_app/app/less/buttons.less
@@ -1,3 +1,5 @@
+@import "variables.less";
+
.btn {
margin: 0;
padding: 8px 16px;
@@ -27,5 +29,3 @@
opacity: 0.5;
}
}
-
-
diff --git a/email_app/app/less/compose_mail.less b/email_app/app/less/compose_mail.less
index 671f9bd..6523108 100644
--- a/email_app/app/less/compose_mail.less
+++ b/email_app/app/less/compose_mail.less
@@ -1,3 +1,5 @@
+@import "variables.less";
+
.compose-mail {
padding: 0;
.compose-mail-b {
diff --git a/email_app/app/less/form.less b/email_app/app/less/form.less
index f8bf811..391c57e 100644
--- a/email_app/app/less/form.less
+++ b/email_app/app/less/form.less
@@ -1,3 +1,5 @@
+@import "variables.less";
+
.form {
.inp-grp {
margin: 40px 0;
diff --git a/email_app/app/less/home.less b/email_app/app/less/home.less
index 10be0ab..23f7dd2 100755
--- a/email_app/app/less/home.less
+++ b/email_app/app/less/home.less
@@ -1,3 +1,5 @@
+@import "variables.less";
+
.home {
background-color: @gray-200;
position: relative;
diff --git a/email_app/app/less/list.less b/email_app/app/less/list.less
index 2a59ed4..58122e4 100644
--- a/email_app/app/less/list.less
+++ b/email_app/app/less/list.less
@@ -1,3 +1,5 @@
+@import "variables.less";
+
.mail-list {
padding-bottom: 126px;
.mail-list-head {
diff --git a/email_app/app/less/variables.less b/email_app/app/less/variables.less
index 2a12152..581e61d 100644
--- a/email_app/app/less/variables.less
+++ b/email_app/app/less/variables.less
@@ -7,3 +7,19 @@
@gray-200: #EEEEEE;
@red-100: #e26464;
+
+// The clearfix mixin
+.clearfix() {
+ &:after {
+ content: ".";
+ display: block;
+ height: 0;
+ clear: both;
+ visibility: hidden;
+ }
+}
+
+// Apply clearfix on .parent
+.parent {
+ .clearfix();
+}
diff --git a/email_app/app/less/view_mail.less b/email_app/app/less/view_mail.less
index ba8c11b..25cbb73 100644
--- a/email_app/app/less/view_mail.less
+++ b/email_app/app/less/view_mail.less
@@ -1,3 +1,5 @@
+@import "variables.less";
+
.view-mail {
background-color: @gray-200;
position: absolute;
diff --git a/email_app/app/reducers/create_account.js b/email_app/app/reducers/create_account.js
index 80a2df6..deaae75 100644
--- a/email_app/app/reducers/create_account.js
+++ b/email_app/app/reducers/create_account.js
@@ -1,22 +1,20 @@
import ACTION_TYPES from '../actions/actionTypes';
const initialState = {
- processing: false,
error: {},
newAccount: null
};
const createAccount = (state = initialState, action) => {
switch (action.type) {
- case `${ACTION_TYPES.CREATE_ACCOUNT}_LOADING`:
- return { ...state, processing: true };
+ case `${ACTION_TYPES.CREATE_ACCOUNT}_ERROR`:
+ return { ...state, error: action.payload };
break;
- case `${ACTION_TYPES.CREATE_ACCOUNT}_SUCCESS`: {
- return { ...state, processing: false, newAccount: action.payload };
+ case `${ACTION_TYPES.CREATE_ACCOUNT}_SUCCESS`:
+ return { ...state, newAccount: action.payload };
break;
- }
- case ACTION_TYPES.CREATE_ACCOUNT_ERROR:
- return { ...state, error: action.error, processing: false };
+ case `${ACTION_TYPES.STORE_NEW_ACCOUNT}_ERROR`:
+ return { ...state, error: action.payload };
break;
default:
return state;
diff --git a/email_app/app/reducers/initialiser.js b/email_app/app/reducers/initialiser.js
index 243a43a..6c3b6b4 100644
--- a/email_app/app/reducers/initialiser.js
+++ b/email_app/app/reducers/initialiser.js
@@ -4,6 +4,10 @@ import { MESSAGES, APP_STATUS, CONSTANTS, SAFE_APP_ERROR_CODES } from '../consta
const initialState = {
app_status: null,
network_status: null,
+ processing: {
+ state: false,
+ msg: null
+ },
app: null,
tasks: [],
accounts: [],
@@ -44,8 +48,17 @@ const initializer = (state = initialState, action) => {
case ACTION_TYPES.NET_STATUS_CHANGED:
return { ...state, network_status: action.payload };
break;
+ case `${ACTION_TYPES.RECONNECT_APP}_LOADING`:
+ return { ...state, processing: { state: true, msg: 'Reconnecting...' } };
+ break;
+ case `${ACTION_TYPES.RECONNECT_APP}_ERROR`:
+ return { ...state, processing: { state: false, msg: null } };
+ break;
case `${ACTION_TYPES.RECONNECT_APP}_SUCCESS`:
- return { ...state, network_status: CONSTANTS.NET_STATUS_CONNECTED };
+ return { ...state,
+ network_status: CONSTANTS.NET_STATUS_CONNECTED,
+ processing: { state: false, msg: null }
+ };
break;
case `${ACTION_TYPES.GET_CONFIG}_LOADING`:
return { ...state, app_status: APP_STATUS.READING_CONFIG };
@@ -57,19 +70,45 @@ const initializer = (state = initialState, action) => {
app_status: APP_STATUS.READY
};
break;
+ case `${ACTION_TYPES.CREATE_ACCOUNT}_LOADING`:
+ return { ...state, processing: { state: true, msg: 'Creating email ID...' } };
+ break;
+ case `${ACTION_TYPES.CREATE_ACCOUNT}_ERROR`:
+ case `${ACTION_TYPES.CREATE_ACCOUNT}_SUCCESS`:
+ return { ...state, processing: { state: false, msg: null } };
+ break;
+ case `${ACTION_TYPES.STORE_NEW_ACCOUNT}_LOADING`:
+ return { ...state, processing: { state: true, msg: 'Storing email info...' } };
+ break;
case `${ACTION_TYPES.STORE_NEW_ACCOUNT}_SUCCESS`:
return { ...state,
accounts: action.payload,
- coreData: { ...state.coreData, id: action.payload.id }
+ coreData: { ...state.coreData, id: action.payload.id },
+ processing: { state: false, msg: null }
};
break;
+ case `${ACTION_TYPES.STORE_NEW_ACCOUNT}_ERROR`:
+ return { ...state, processing: { state: false, msg: null } };
+ break;
case `${ACTION_TYPES.REFRESH_EMAIL}_LOADING`:
return { ...state,
coreData: { ...state.coreData, inbox: [], saved: [] },
inboxSize: 0,
- savedSize: 0
+ savedSize: 0,
+ processing: { state: true, msg: 'Reading emails...' }
};
break;
+ case `${ACTION_TYPES.REFRESH_EMAIL}_SUCCESS`:
+ case `${ACTION_TYPES.REFRESH_EMAIL}_ERROR`:
+ return { ...state, processing: { state: false, msg: null } };
+ break;
+ case `${ACTION_TYPES.MAIL_PROCESSING}_LOADING`:
+ return { ...state, processing: { state: true, msg: action.msg } };
+ break;
+ case `${ACTION_TYPES.MAIL_PROCESSING}_SUCCESS`:
+ case `${ACTION_TYPES.MAIL_PROCESSING}_ERROR`:
+ return { ...state, processing: { state: false, msg: null } };
+ break;
case ACTION_TYPES.PUSH_TO_INBOX: {
let inbox = Object.assign({}, state.coreData.inbox, action.payload);
return { ...state,
diff --git a/email_app/app/reducers/mail.js b/email_app/app/reducers/mail.js
index bef2630..aafa1d2 100644
--- a/email_app/app/reducers/mail.js
+++ b/email_app/app/reducers/mail.js
@@ -1,18 +1,11 @@
import ACTION_TYPES from '../actions/actionTypes';
const initialState = {
- processing: false,
error: {}
};
const mail = (state = initialState, action) => {
switch (action.type) {
- case ACTION_TYPES.MAIL_PROCESSING:
- return { ...state, processing: true };
- break;
- case ACTION_TYPES.CLEAR_MAIL_PROCESSING:
- return { ...state, processing: false };
- break;
case ACTION_TYPES.CANCEL_COMPOSE:
return { ...state, error: Object.assign({}) };
break;
diff --git a/email_app/package.json b/email_app/package.json
index 01d67f4..5d93271 100644
--- a/email_app/package.json
+++ b/email_app/package.json
@@ -114,10 +114,11 @@
"react": "^15.4.2",
"react-dom": "^15.4.2",
"react-hot-loader": "^3.0.0-beta.6",
- "react-modal": "^2.1.0",
+ "react-modal-dialog": "^4.0.7",
"react-redux": "^5.0.3",
"react-router": "^3.0.2",
"react-router-redux": "^4.0.8",
+ "react-spinjs": "^3.0.0",
"redux": "^3.6.0",
"redux-axios-middleware": "^2.0.0",
"redux-promise-middleware": "^4.2.0",