diff --git a/web/src/actions/index.js b/web/src/actions/index.js
deleted file mode 100644
index 38934311..00000000
--- a/web/src/actions/index.js
+++ /dev/null
@@ -1,253 +0,0 @@
-import WebDB from '../web-db';
-
-export const ACTION_LOGOUT = 'LOGOUT';
-export const ACTION_LOGIN_REQUEST = 'LOGIN_REQUEST';
-export const ACTION_LOGIN_SUCCESS = 'LOGIN_SUCCESS';
-export const ACTION_LOGIN_FAILURE = 'LOGIN_FAILURE';
-export const ACTION_LOGIN_ENABLE = 'ACTION_LOGIN_ENABLE';
-export const ACTION_LOGIN_DISABLE = 'ACTION_LOGIN_DISABLE';
-export const ACTION_LOGIN_CHECK_USERNAME_FAILED = 'ACTION_LOGIN_CHECK_USERNAME_FAILED';
-export const ACTION_LOGIN_CHECK_USERNAME_SUCCESS = 'ACTION_LOGIN_CHECK_USERNAME_SUCCESS';
-
-export const ACTION_ADD_LANGUAGE_REQUEST = 'ADD_LANGUAGE_REQUEST';
-export const ACTION_ADD_LANGUAGE_SUCCESS = 'ADD_LANGUAGE_SUCCESS';
-export const ACTION_ADD_LANGUAGE_FAILURE = 'ADD_LANGUAGE_FAILURE';
-
-export const ACTION_REMOVE_LANGUAGE_REQUEST = 'REMOVE_LANGUAGE_REQUEST';
-export const ACTION_REMOVE_LANGUAGE_SUCCESS = 'REMOVE_LANGUAGE_SUCCESS';
-export const ACTION_REMOVE_LANGUAGE_FAILURE = 'REMOVE_LANGUAGE_FAILURE';
-
-export const ACTION_SUBMIT_SENTENCES_REQUEST = 'SUBMIT_SENTENCES_REQUEST';
-export const ACTION_SUBMIT_SENTENCES_SUCCESS = 'SUBMIT_SENTENCES_SUCCESS';
-export const ACTION_SUBMIT_SENTENCES_FAILURE_SINGLE = 'SUBMIT_SENTENCES_FAILURE_SINGLE';
-
-export const ACTION_SETTINGS_CHANGED = 'ACTION_SETTINGS_CHANGED';
-export const ACTION_SETTINGS_CHANGED_FAILURE = 'ACTION_SETTINGS_CHANGED_FAILURE';
-
-const VALID_USERNAME_CHARACTERS = /^[a-zA-Z0-9]+$/;
-
-export function login(username, password) {
- return async function(dispatch) {
- try {
- dispatch(sendLoginRequest());
-
- const db = new WebDB(username, password);
- const user = await db.auth();
- dispatch(loginSuccess(username, password, user.languages, user.settings));
- } catch (err) {
- dispatch(loginFailure());
- }
- };
-}
-
-export function checkLoginInput(username, password) {
- return async function(dispatch) {
- const validUsername = checkUsername(username);
- const validPassword = checkPassword(password);
-
- const usernameAction = validUsername ? usernameSuccess() : usernameFailure();
- dispatch(usernameAction);
-
- if (!validUsername || !validPassword) {
- return dispatch(disableLogin());
- }
-
- return dispatch(enableLogin());
- };
-}
-
-function checkUsername(username) {
- return VALID_USERNAME_CHARACTERS.test(username);
-}
-
-function checkPassword(password) {
- return password !== '';
-}
-
-export function setSetting(key, value) {
- return async function(dispatch, getState) {
- try {
- const state = getState();
- const db = new WebDB(state.app.username, state.app.password);
- await db.setSetting(key, value);
- dispatch(settingsChanged({
- [key]: value,
- }));
- } catch (err) {
- dispatch(settingsChangedFailure());
- throw err;
- }
- };
-}
-
-export function addLanguage(language) {
- return async function(dispatch, getState) {
- try {
- dispatch(sendAddLanguage());
-
- const state = getState();
- const db = new WebDB(state.app.username, state.app.password);
- const updatedLanguages = await db.addLanguage(language);
- dispatch(addLanguageSuccess(updatedLanguages));
- } catch (err) {
- dispatch(addLanguageFailure());
- throw err;
- }
- };
-}
-
-export function removeLanguage(language) {
- return async function(dispatch, getState) {
- try {
- dispatch(sendRemoveLanguage());
-
- const state = getState();
- const db = new WebDB(state.app.username, state.app.password);
- const updatedLanguages = await db.removeLanguage(language);
- dispatch(removeLanguageSuccess(updatedLanguages));
- } catch (err) {
- dispatch(removeLanguageFailure());
- throw err;
- }
- };
-}
-
-export function submitSentences(language, sentences, source) {
- return async function(dispatch, getState) {
- dispatch(sendSubmitSentences());
-
- const state = getState();
- const db = new WebDB(state.app.username, state.app.password);
- const results = await db.submitSentences(language, sentences, source);
- dispatch(submitSentencesSuccess(results.sentences.slice(0)));
- const errorsWithSentenceInfo = results.errors.filter((error) => error.sentence);
- dispatch(submitSentencesFailureSingle(errorsWithSentenceInfo));
- if(!state.app.languages.includes(language)) {
- dispatch(addLanguage(language));
- }
- return results;
- };
-}
-
-export function usernameSuccess() {
- return {
- type: ACTION_LOGIN_CHECK_USERNAME_SUCCESS,
- };
-}
-
-export function usernameFailure() {
- return {
- type: ACTION_LOGIN_CHECK_USERNAME_FAILED,
- };
-}
-
-export function disableLogin() {
- return {
- type: ACTION_LOGIN_DISABLE,
- };
-}
-
-export function enableLogin() {
- return {
- type: ACTION_LOGIN_ENABLE,
- };
-}
-
-export function logout() {
- return {
- type: ACTION_LOGOUT,
- };
-}
-
-export function sendLoginRequest() {
- return {
- type: ACTION_LOGIN_REQUEST,
- };
-}
-
-export function loginSuccess(username, password, languages, settings) {
- return {
- type: ACTION_LOGIN_SUCCESS,
- username,
- password,
- languages,
- settings,
- };
-}
-
-export function loginFailure() {
- return {
- type: ACTION_LOGIN_FAILURE,
- };
-}
-
-export function settingsChanged(newSettings) {
- return {
- type: ACTION_SETTINGS_CHANGED,
- newSettings,
- };
-}
-
-export function settingsChangedFailure() {
- return {
- type: ACTION_SETTINGS_CHANGED_FAILURE,
- };
-}
-
-export function sendAddLanguage() {
- return {
- type: ACTION_ADD_LANGUAGE_REQUEST,
- };
-}
-
-export function addLanguageSuccess(languages) {
- return {
- type: ACTION_ADD_LANGUAGE_SUCCESS,
- languages,
- };
-}
-
-export function addLanguageFailure() {
- return {
- type: ACTION_ADD_LANGUAGE_FAILURE,
- };
-}
-
-export function sendRemoveLanguage() {
- return {
- type: ACTION_REMOVE_LANGUAGE_REQUEST,
- };
-}
-
-export function removeLanguageSuccess(languages) {
- return {
- type: ACTION_REMOVE_LANGUAGE_SUCCESS,
- languages,
- };
-}
-
-export function removeLanguageFailure() {
- return {
- type: ACTION_REMOVE_LANGUAGE_FAILURE,
- };
-}
-
-export function sendSubmitSentences() {
- return {
- type: ACTION_SUBMIT_SENTENCES_REQUEST,
- };
-}
-
-export function submitSentencesSuccess(sentences) {
- return {
- type: ACTION_SUBMIT_SENTENCES_SUCCESS,
- sentences,
- };
-}
-
-export function submitSentencesFailureSingle(errors) {
- return {
- type: ACTION_SUBMIT_SENTENCES_FAILURE_SINGLE,
- errors,
- };
-}
diff --git a/web/src/actions/languages.js b/web/src/actions/languages.js
new file mode 100644
index 00000000..3c3a098d
--- /dev/null
+++ b/web/src/actions/languages.js
@@ -0,0 +1,79 @@
+import WebDB from '../web-db';
+
+export const ACTION_ADD_LANGUAGE_REQUEST = 'ADD_LANGUAGE_REQUEST';
+export const ACTION_ADD_LANGUAGE_SUCCESS = 'ADD_LANGUAGE_SUCCESS';
+export const ACTION_ADD_LANGUAGE_FAILURE = 'ADD_LANGUAGE_FAILURE';
+
+export const ACTION_REMOVE_LANGUAGE_REQUEST = 'REMOVE_LANGUAGE_REQUEST';
+export const ACTION_REMOVE_LANGUAGE_SUCCESS = 'REMOVE_LANGUAGE_SUCCESS';
+export const ACTION_REMOVE_LANGUAGE_FAILURE = 'REMOVE_LANGUAGE_FAILURE';
+
+export function addLanguage(language) {
+ return async function(dispatch, getState) {
+ try {
+ dispatch(sendAddLanguage());
+
+ const state = getState();
+ const db = new WebDB(state.login.username, state.login.password);
+ const updatedLanguages = await db.addLanguage(language);
+ dispatch(addLanguageSuccess(updatedLanguages));
+ } catch (err) {
+ dispatch(addLanguageFailure());
+ throw err;
+ }
+ };
+}
+
+export function removeLanguage(language) {
+ return async function(dispatch, getState) {
+ try {
+ dispatch(sendRemoveLanguage());
+
+ const state = getState();
+ const db = new WebDB(state.login.username, state.login.password);
+ const updatedLanguages = await db.removeLanguage(language);
+ dispatch(removeLanguageSuccess(updatedLanguages));
+ } catch (err) {
+ dispatch(removeLanguageFailure());
+ throw err;
+ }
+ };
+}
+
+export function sendAddLanguage() {
+ return {
+ type: ACTION_ADD_LANGUAGE_REQUEST,
+ };
+}
+
+export function addLanguageSuccess(languages) {
+ return {
+ type: ACTION_ADD_LANGUAGE_SUCCESS,
+ languages,
+ };
+}
+
+export function addLanguageFailure() {
+ return {
+ type: ACTION_ADD_LANGUAGE_FAILURE,
+ };
+}
+
+export function sendRemoveLanguage() {
+ return {
+ type: ACTION_REMOVE_LANGUAGE_REQUEST,
+ };
+}
+
+export function removeLanguageSuccess(languages) {
+ return {
+ type: ACTION_REMOVE_LANGUAGE_SUCCESS,
+ languages,
+ };
+}
+
+export function removeLanguageFailure() {
+ return {
+ type: ACTION_REMOVE_LANGUAGE_FAILURE,
+ };
+}
diff --git a/web/src/actions/login.js b/web/src/actions/login.js
new file mode 100644
index 00000000..1dd0825c
--- /dev/null
+++ b/web/src/actions/login.js
@@ -0,0 +1,105 @@
+import WebDB from '../web-db';
+import { addLanguageSuccess } from './languages';
+import { settingsChanged } from './settings';
+
+export const ACTION_LOGOUT = 'LOGOUT';
+export const ACTION_LOGIN_REQUEST = 'LOGIN_REQUEST';
+export const ACTION_LOGIN_SUCCESS = 'LOGIN_SUCCESS';
+export const ACTION_LOGIN_FAILURE = 'LOGIN_FAILURE';
+export const ACTION_LOGIN_ENABLE = 'ACTION_LOGIN_ENABLE';
+export const ACTION_LOGIN_DISABLE = 'ACTION_LOGIN_DISABLE';
+export const ACTION_LOGIN_CHECK_USERNAME_FAILED = 'ACTION_LOGIN_CHECK_USERNAME_FAILED';
+export const ACTION_LOGIN_CHECK_USERNAME_SUCCESS = 'ACTION_LOGIN_CHECK_USERNAME_SUCCESS';
+
+const VALID_USERNAME_CHARACTERS = /^[a-zA-Z0-9]+$/;
+
+export function login(username, password) {
+ return async function(dispatch) {
+ try {
+ dispatch(sendLoginRequest());
+
+ const db = new WebDB(username, password);
+ const user = await db.auth();
+ dispatch(loginSuccess(username, password));
+ dispatch(addLanguageSuccess(user.languages));
+ dispatch(settingsChanged(user.settings));
+ } catch (err) {
+ console.log(err);
+ dispatch(loginFailure());
+ }
+ };
+}
+
+export function checkLoginInput(username, password) {
+ return async function(dispatch) {
+ const validUsername = checkUsername(username);
+ const validPassword = checkPassword(password);
+
+ const usernameAction = validUsername ? usernameSuccess() : usernameFailure();
+ dispatch(usernameAction);
+
+ if (!validUsername || !validPassword) {
+ return dispatch(disableLogin());
+ }
+
+ return dispatch(enableLogin());
+ };
+}
+
+function checkUsername(username) {
+ return VALID_USERNAME_CHARACTERS.test(username);
+}
+
+function checkPassword(password) {
+ return password !== '';
+}
+
+export function usernameSuccess() {
+ return {
+ type: ACTION_LOGIN_CHECK_USERNAME_SUCCESS,
+ };
+}
+
+export function usernameFailure() {
+ return {
+ type: ACTION_LOGIN_CHECK_USERNAME_FAILED,
+ };
+}
+
+export function disableLogin() {
+ return {
+ type: ACTION_LOGIN_DISABLE,
+ };
+}
+
+export function enableLogin() {
+ return {
+ type: ACTION_LOGIN_ENABLE,
+ };
+}
+
+export function logout() {
+ return {
+ type: ACTION_LOGOUT,
+ };
+}
+
+export function sendLoginRequest() {
+ return {
+ type: ACTION_LOGIN_REQUEST,
+ };
+}
+
+export function loginSuccess(username, password) {
+ return {
+ type: ACTION_LOGIN_SUCCESS,
+ username,
+ password,
+ };
+}
+
+export function loginFailure() {
+ return {
+ type: ACTION_LOGIN_FAILURE,
+ };
+}
diff --git a/web/src/actions/parsing.js b/web/src/actions/parsing.js
index 810e071d..b72bcf8a 100644
--- a/web/src/actions/parsing.js
+++ b/web/src/actions/parsing.js
@@ -10,8 +10,8 @@ export function parseSentences(language, text) {
try {
const state = getState();
const credentials = {
- username: state.app.username,
- password: state.app.password,
+ username: state.login.username,
+ password: state.login.password,
};
const sentences = text.split(SPLIT_ON).map(s => s.trim()).filter(Boolean);
diff --git a/web/src/actions/sentences.js b/web/src/actions/sentences.js
new file mode 100644
index 00000000..f86a9eea
--- /dev/null
+++ b/web/src/actions/sentences.js
@@ -0,0 +1,43 @@
+import WebDB from '../web-db';
+import languages from './languages';
+
+export const ACTION_SUBMIT_SENTENCES_REQUEST = 'SUBMIT_SENTENCES_REQUEST';
+export const ACTION_SUBMIT_SENTENCES_SUCCESS = 'SUBMIT_SENTENCES_SUCCESS';
+export const ACTION_SUBMIT_SENTENCES_FAILURE_SINGLE = 'SUBMIT_SENTENCES_FAILURE_SINGLE';
+
+export function submitSentences(language, sentences, source) {
+ return async function(dispatch, getState) {
+ dispatch(sendSubmitSentences());
+
+ const state = getState();
+ const db = new WebDB(state.login.username, state.login.password);
+ const results = await db.submitSentences(language, sentences, source);
+ dispatch(submitSentencesSuccess(results.sentences.slice(0)));
+ const errorsWithSentenceInfo = results.errors.filter((error) => error.sentence);
+ dispatch(submitSentencesFailureSingle(errorsWithSentenceInfo));
+ if(!state.languages.languages.includes(language)) {
+ dispatch(languages.addLanguage(language));
+ }
+ return results;
+ };
+}
+
+export function sendSubmitSentences() {
+ return {
+ type: ACTION_SUBMIT_SENTENCES_REQUEST,
+ };
+}
+
+export function submitSentencesSuccess(sentences) {
+ return {
+ type: ACTION_SUBMIT_SENTENCES_SUCCESS,
+ sentences,
+ };
+}
+
+export function submitSentencesFailureSingle(errors) {
+ return {
+ type: ACTION_SUBMIT_SENTENCES_FAILURE_SINGLE,
+ errors,
+ };
+}
diff --git a/web/src/actions/settings.js b/web/src/actions/settings.js
new file mode 100644
index 00000000..36cdb5bb
--- /dev/null
+++ b/web/src/actions/settings.js
@@ -0,0 +1,33 @@
+import WebDB from '../web-db';
+
+export const ACTION_SETTINGS_CHANGED = 'ACTION_SETTINGS_CHANGED';
+export const ACTION_SETTINGS_CHANGED_FAILURE = 'ACTION_SETTINGS_CHANGED_FAILURE';
+
+export function setSetting(key, value) {
+ return async function(dispatch, getState) {
+ try {
+ const state = getState();
+ const db = new WebDB(state.login.username, state.login.password);
+ await db.setSetting(key, value);
+ dispatch(settingsChanged({
+ [key]: value,
+ }));
+ } catch (err) {
+ dispatch(settingsChangedFailure());
+ throw err;
+ }
+ };
+}
+
+export function settingsChanged(newSettings) {
+ return {
+ type: ACTION_SETTINGS_CHANGED,
+ newSettings,
+ };
+}
+
+export function settingsChangedFailure() {
+ return {
+ type: ACTION_SETTINGS_CHANGED_FAILURE,
+ };
+}
diff --git a/web/src/components/app.jsx b/web/src/components/app.jsx
index 50d945a5..8f541490 100644
--- a/web/src/components/app.jsx
+++ b/web/src/components/app.jsx
@@ -75,7 +75,7 @@ const PrivateRoute = (props) => {
function mapStateToProps(state) {
return {
- authed: state.app.authed,
+ authed: state.login.authed,
};
}
diff --git a/web/src/components/header.jsx b/web/src/components/header.jsx
index 7444bdd6..a1f1f2c3 100644
--- a/web/src/components/header.jsx
+++ b/web/src/components/header.jsx
@@ -38,7 +38,7 @@ function mapStateToProps(state) {
return {
// force a re-render of header active links on location change.
location: state.router.location,
- authed: state.app.authed,
+ authed: state.login.authed,
};
}
diff --git a/web/src/components/page.jsx b/web/src/components/page.jsx
index a9a8fe54..8c1d005b 100644
--- a/web/src/components/page.jsx
+++ b/web/src/components/page.jsx
@@ -5,7 +5,7 @@ import HeaderBtn from './header-btn';
const DEFAULT_STATE = {
headerIsOpen: true,
-}
+};
export default class Page extends React.Component {
constructor(props) {
@@ -25,7 +25,7 @@ export default class Page extends React.Component {
return [
{settingsChangedFailureMessage}
+ {settings.errorMessage && ( +{settings.errorMessage}
)}Experimental: There are two different tools with which you can review sentences. The normal tool lists 5 sentences per page @@ -239,12 +238,11 @@ const LanguageInfo = (props) => ( function mapStateToProps(state) { return { - username: state.app.username, - password: state.app.password, - languages: state.app.languages, - pending: state.app.pendingLanguages, - settings: state.app.settings, - settingsChangedFailureMessage: state.app.settingsChangedFailureMessage, + username: state.login.username, + password: state.login.password, + languages: state.languages.languages, + pending: state.languages.pendingLanguages, + settings: state.settings, }; } diff --git a/web/src/components/pages/rejected.jsx b/web/src/components/pages/rejected.jsx index 8c30bf57..a580d40b 100644 --- a/web/src/components/pages/rejected.jsx +++ b/web/src/components/pages/rejected.jsx @@ -62,9 +62,9 @@ class Rejected extends React.Component { function mapStateToProps(state) { return { - username: state.app.username, - password: state.app.password, - languages: state.app.languages, + username: state.login.username, + password: state.login.password, + languages: state.languages.languages, }; } diff --git a/web/src/components/pages/review.jsx b/web/src/components/pages/review.jsx index 41156c47..96fe79ce 100644 --- a/web/src/components/pages/review.jsx +++ b/web/src/components/pages/review.jsx @@ -193,10 +193,10 @@ class Review extends React.Component { function mapStateToProps(state) { return { - languages: state.app.languages, - username: state.app.username, - password: state.app.password, - useSwipeReview: state.app.settings && state.app.settings.useSwipeReview, + languages: state.languages.languages, + password: state.login.password, + username: state.login.username, + useSwipeReview: state.settings.useSwipeReview, }; } diff --git a/web/src/components/profile-widget.jsx b/web/src/components/profile-widget.jsx index 87418de9..9cba78d4 100644 --- a/web/src/components/profile-widget.jsx +++ b/web/src/components/profile-widget.jsx @@ -2,7 +2,7 @@ import React from 'react'; import { connect } from 'react-redux'; import { Link } from 'react-router-dom'; -import { logout } from '../actions'; +import { logout } from '../actions/login'; class ProfileWidget extends React.Component { constructor(props) { @@ -30,8 +30,8 @@ class ProfileWidget extends React.Component { function mapStateToProps(state) { return { - authed: state.app.authed, - username: state.app.username, + authed: state.login.authed, + username: state.login.username, }; } diff --git a/web/src/components/store.jsx b/web/src/components/store.jsx index 036da13e..35b03c2b 100644 --- a/web/src/components/store.jsx +++ b/web/src/components/store.jsx @@ -7,7 +7,7 @@ import storage from 'redux-persist/lib/storage'; import thunk from 'redux-thunk'; import { routerMiddleware } from 'connected-react-router'; -import createRootReducer, { INITIAL_STATE } from '../reducers'; +import createRootReducer from '../reducers'; const ROOT_KEY = 'redux'; const persistConfig = { @@ -21,7 +21,7 @@ function getStore(history) { return createStore( persistedRecuder, - { app: INITIAL_STATE }, + {}, compose( applyMiddleware(thunk), applyMiddleware(routerMiddleware(history)) diff --git a/web/src/components/submit-form.jsx b/web/src/components/submit-form.jsx index d3c0459c..d0586de0 100644 --- a/web/src/components/submit-form.jsx +++ b/web/src/components/submit-form.jsx @@ -7,8 +7,8 @@ import SpinnerButton from './spinner-button'; function mapStateToProps(state) { return { - errorMessage: state.app.errorMessage, - sentenceSubmissionFailures: state.app.sentenceSubmissionFailures, + errorMessage: state.sentences.errorMessage, + sentenceSubmissionFailures: state.sentences.sentenceSubmissionFailures, }; } diff --git a/web/src/reducers/index.js b/web/src/reducers/index.js index 1aa10af8..eedc1f71 100644 --- a/web/src/reducers/index.js +++ b/web/src/reducers/index.js @@ -1,177 +1,17 @@ import { combineReducers } from 'redux'; import { connectRouter } from 'connected-react-router'; -import { - ACTION_LOGOUT, - ACTION_LOGIN_REQUEST, - ACTION_LOGIN_SUCCESS, - ACTION_LOGIN_FAILURE, - ACTION_LOGIN_CHECK_USERNAME_FAILED, - ACTION_LOGIN_ENABLE, - ACTION_LOGIN_DISABLE, - ACTION_LOGIN_CHECK_USERNAME_SUCCESS, - ACTION_ADD_LANGUAGE_REQUEST, - ACTION_ADD_LANGUAGE_SUCCESS, - ACTION_ADD_LANGUAGE_FAILURE, - ACTION_REMOVE_LANGUAGE_REQUEST, - ACTION_REMOVE_LANGUAGE_SUCCESS, - ACTION_REMOVE_LANGUAGE_FAILURE, - ACTION_SUBMIT_SENTENCES_REQUEST, - ACTION_SUBMIT_SENTENCES_SUCCESS, - ACTION_SUBMIT_SENTENCES_FAILURE_SINGLE, - ACTION_SETTINGS_CHANGED, - ACTION_SETTINGS_CHANGED_FAILURE, -} from '../actions'; - -import { - ACTION_PARSE_SENTENCES_FAILURE, -} from '../actions/parsing'; - -export const INITIAL_STATE = { - authed: false, - username: null, - password: null, - loginDisabled: true, - languages: [], - pendingLanguages: false, - sentences: [], - errorMessage: null, - sentenceSubmissionFailures: [], - settingsChangedFailureMessage: '', -}; - -function copyInto(oldObj, newObj) { - return Object.assign({}, oldObj, newObj); -} - -function mergeArray(arr1, arr2) { - arr1 && arr1.forEach(item => (arr2.indexOf(item) === -1 && arr2.push(item))); - return arr2; -} +import languages from './languages'; +import login from './login'; +import sentences from './sentences'; +import settings from './settings'; export default function(history) { return combineReducers({ router: connectRouter(history), - app: reducer, + languages, + login, + sentences, + settings, }); } - -function reducer(state = INITIAL_STATE, action) { - switch(action.type) { - case ACTION_LOGOUT: - return copyInto(state, INITIAL_STATE); - - case ACTION_LOGIN_CHECK_USERNAME_SUCCESS: - return copyInto(state, { - errorMessage: null, - }); - - case ACTION_LOGIN_CHECK_USERNAME_FAILED: - return Object.assign({}, state, INITIAL_STATE, { - errorMessage: 'Please only use alphanumeric usernames.', - }); - - case ACTION_LOGIN_DISABLE: - return copyInto(state, { - loginDisabled: true, - }); - - case ACTION_LOGIN_ENABLE: - return copyInto(state, { - loginDisabled: false, - }); - - case ACTION_LOGIN_SUCCESS: - return copyInto(state, { - authed: true, - loginDisabled: false, - username: action.username, - password: action.password, - languages: action.languages, - settings: action.settings, - errorMessage: null, - }); - - case ACTION_LOGIN_FAILURE: - return Object.assign({}, state, INITIAL_STATE, { - errorMessage: 'Login failed.', - loginDisabled: true, - }); - - case ACTION_LOGIN_REQUEST: - return copyInto(state, { - authed: false, - loginDisabled: true, - }); - - case ACTION_ADD_LANGUAGE_REQUEST: - return copyInto(state, { - pendingLanguages: true, - }); - - case ACTION_ADD_LANGUAGE_SUCCESS: - return copyInto(state, { - pendingLanguages: false, - languages: action.languages, - }); - - case ACTION_ADD_LANGUAGE_FAILURE: - return copyInto(state, { - pendingLanguages: false, - }); - - case ACTION_REMOVE_LANGUAGE_REQUEST: - return copyInto(state, { - pendingLanguages: true, - }); - - case ACTION_REMOVE_LANGUAGE_SUCCESS: - return copyInto(state, { - pendingLanguages: false, - languages: action.languages, - }); - - case ACTION_REMOVE_LANGUAGE_FAILURE: - return copyInto(state, { - pendingLanguages: false, - }); - - case ACTION_SUBMIT_SENTENCES_REQUEST: - return copyInto(state, { - sentenceSubmissionFailures: [], - }); - - case ACTION_SUBMIT_SENTENCES_FAILURE_SINGLE: - return copyInto(state, { - sentenceSubmissionFailures: action.errors, - }); - - case ACTION_SUBMIT_SENTENCES_SUCCESS: - return copyInto(state, { - sentences: mergeArray(state.sentences, action.sentences), - errorMessage: '', - }); - - case ACTION_PARSE_SENTENCES_FAILURE: - return copyInto(state, { - errorMessage: action.error.message, - }); - - case ACTION_SETTINGS_CHANGED: - return copyInto( - state, - { - settings: copyInto(state.settings, action.newSettings), - settingsChangedFailureMessage: '', - }, - ); - - case ACTION_SETTINGS_CHANGED_FAILURE: - return copyInto(state, { - settingsChangedFailureMessage: 'Could not change settings. Please try again.', - }); - - default: - return state; - } -} diff --git a/web/src/reducers/languages.js b/web/src/reducers/languages.js new file mode 100644 index 00000000..8c0b447a --- /dev/null +++ b/web/src/reducers/languages.js @@ -0,0 +1,52 @@ +import { + ACTION_ADD_LANGUAGE_REQUEST, + ACTION_ADD_LANGUAGE_SUCCESS, + ACTION_ADD_LANGUAGE_FAILURE, + ACTION_REMOVE_LANGUAGE_REQUEST, + ACTION_REMOVE_LANGUAGE_SUCCESS, + ACTION_REMOVE_LANGUAGE_FAILURE, +} from '../actions/languages'; + +export const INITIAL_STATE = { + languages: [], + pendingLanguages: false, +}; + +export default function(state = INITIAL_STATE, action) { + switch(action.type) { + case ACTION_ADD_LANGUAGE_REQUEST: + return Object.assign({}, state, { + pendingLanguages: true, + }); + + case ACTION_ADD_LANGUAGE_SUCCESS: + return Object.assign({}, state, { + pendingLanguages: false, + languages: action.languages, + }); + + case ACTION_ADD_LANGUAGE_FAILURE: + return Object.assign({}, state, { + pendingLanguages: false, + }); + + case ACTION_REMOVE_LANGUAGE_REQUEST: + return Object.assign({}, state, { + pendingLanguages: true, + }); + + case ACTION_REMOVE_LANGUAGE_SUCCESS: + return Object.assign({}, state, { + pendingLanguages: false, + languages: action.languages, + }); + + case ACTION_REMOVE_LANGUAGE_FAILURE: + return Object.assign({}, state, { + pendingLanguages: false, + }); + + default: + return state; + } +} diff --git a/web/src/reducers/login.js b/web/src/reducers/login.js new file mode 100644 index 00000000..8722208b --- /dev/null +++ b/web/src/reducers/login.js @@ -0,0 +1,69 @@ +import { + ACTION_LOGOUT, + ACTION_LOGIN_REQUEST, + ACTION_LOGIN_SUCCESS, + ACTION_LOGIN_FAILURE, + ACTION_LOGIN_CHECK_USERNAME_FAILED, + ACTION_LOGIN_ENABLE, + ACTION_LOGIN_DISABLE, + ACTION_LOGIN_CHECK_USERNAME_SUCCESS, +} from '../actions/login'; + +export const INITIAL_STATE = { + authed: false, + username: null, + password: null, + loginDisabled: true, + errorMessage: null, +}; + +export default function(state = INITIAL_STATE, action) { + switch(action.type) { + case ACTION_LOGOUT: + return Object.assign({}, state, INITIAL_STATE); + + case ACTION_LOGIN_CHECK_USERNAME_SUCCESS: + return Object.assign({}, state, { + errorMessage: null, + }); + + case ACTION_LOGIN_CHECK_USERNAME_FAILED: + return Object.assign({}, state, INITIAL_STATE, { + errorMessage: 'Please only use alphanumeric usernames.', + }); + + case ACTION_LOGIN_DISABLE: + return Object.assign({}, state, { + loginDisabled: true, + }); + + case ACTION_LOGIN_ENABLE: + return Object.assign({}, state, { + loginDisabled: false, + }); + + case ACTION_LOGIN_SUCCESS: + return Object.assign({}, state, { + authed: true, + loginDisabled: false, + username: action.username, + password: action.password, + errorMessage: null, + }); + + case ACTION_LOGIN_FAILURE: + return Object.assign({}, state, INITIAL_STATE, { + errorMessage: 'Login failed.', + loginDisabled: true, + }); + + case ACTION_LOGIN_REQUEST: + return Object.assign({}, state, { + authed: false, + loginDisabled: true, + }); + + default: + return state; + } +} diff --git a/web/src/reducers/sentences.js b/web/src/reducers/sentences.js new file mode 100644 index 00000000..224ae42b --- /dev/null +++ b/web/src/reducers/sentences.js @@ -0,0 +1,48 @@ +import { + ACTION_SUBMIT_SENTENCES_REQUEST, + ACTION_SUBMIT_SENTENCES_SUCCESS, + ACTION_SUBMIT_SENTENCES_FAILURE_SINGLE, +} from '../actions/sentences'; + +import { + ACTION_PARSE_SENTENCES_FAILURE, +} from '../actions/parsing'; + +export const INITIAL_STATE = { + sentences: [], + errorMessage: null, + sentenceSubmissionFailures: [], +}; + +function mergeArray(arr1, arr2) { + arr1 && arr1.forEach(item => (arr2.indexOf(item) === -1 && arr2.push(item))); + return arr2; +} + +export default function(state = INITIAL_STATE, action) { + switch(action.type) { + case ACTION_SUBMIT_SENTENCES_REQUEST: + return Object.assign({}, state, { + sentenceSubmissionFailures: [], + }); + + case ACTION_SUBMIT_SENTENCES_FAILURE_SINGLE: + return Object.assign({}, state, { + sentenceSubmissionFailures: action.errors, + }); + + case ACTION_SUBMIT_SENTENCES_SUCCESS: + return Object.assign({}, state, { + sentences: mergeArray(state.sentences, action.sentences), + errorMessage: '', + }); + + case ACTION_PARSE_SENTENCES_FAILURE: + return Object.assign({}, state, { + errorMessage: action.error.message, + }); + + default: + return state; + } +} diff --git a/web/src/reducers/settings.js b/web/src/reducers/settings.js new file mode 100644 index 00000000..26397dce --- /dev/null +++ b/web/src/reducers/settings.js @@ -0,0 +1,25 @@ +import { + ACTION_SETTINGS_CHANGED, + ACTION_SETTINGS_CHANGED_FAILURE, +} from '../actions/settings'; + +export const INITIAL_STATE = { + errorMessage: '', +}; + +export default function(state = INITIAL_STATE, action) { + switch(action.type) { + case ACTION_SETTINGS_CHANGED: + return Object.assign({}, state, action.newSettings, { + errorMessage: '', + }); + + case ACTION_SETTINGS_CHANGED_FAILURE: + return Object.assign({}, state, { + errorMessage: 'Could not change settings. Please try again.', + }); + + default: + return state; + } +} diff --git a/web/src/tests/login.test.js b/web/src/tests/login.test.js index 5a86489f..89c70b31 100644 --- a/web/src/tests/login.test.js +++ b/web/src/tests/login.test.js @@ -7,7 +7,7 @@ import { getStore } from './testUtils'; test('Login button is disabled without input values', () => { const initialState = { - app: { + login: { authed: false, username: null, errormessage: null,