diff --git a/package.json b/package.json index 91bb703..f963198 100644 --- a/package.json +++ b/package.json @@ -14,6 +14,7 @@ "react-router-dom": "^4.2.2", "react-scripts-ts": "2.8.0", "redux": "^3.7.2", + "redux-actions": "^2.2.1", "redux-logger": "^3.0.6", "redux-persist": "^5.4.0", "redux-thunk": "^2.2.0", @@ -37,6 +38,7 @@ "@types/react-redux": "^5.0.14", "@types/react-router": "^4.0.19", "@types/react-router-dom": "^4.2.3", + "@types/redux-actions": "^2.2.3", "@types/redux-logger": "^3.0.5", "@types/sjcl": "^1.0.28", "@types/urijs": "^1.15.34" diff --git a/src/JournalView.tsx b/src/JournalView.tsx index a5f2d30..44c50af 100644 --- a/src/JournalView.tsx +++ b/src/JournalView.tsx @@ -36,7 +36,7 @@ class JournalView extends React.Component { componentDidMount() { const journal = this.props.match.params.journalUid; - store.dispatch(fetchEntries(this.props.etesync, journal)); + store.dispatch(fetchEntries(this.props.etesync, journal, null)); } render() { diff --git a/src/promise-middleware.tsx b/src/promise-middleware.tsx new file mode 100644 index 0000000..1a8b662 --- /dev/null +++ b/src/promise-middleware.tsx @@ -0,0 +1,20 @@ +// Based on: https://github.com/acdlite/redux-promise/blob/master/src/index.js + +function isPromise(val: any) { + return val && typeof val.then === 'function'; +} + +export default function promiseMiddleware({ dispatch }: any) { + return (next: any) => (action: any) => { + if (isPromise(action.payload)) { + dispatch({...action, payload: undefined}); + + return action.payload.then( + (result: any) => dispatch({ ...action, payload: result }), + (error: Error) => dispatch({ ...action, payload: error, error: true }) + ); + } else { + return next(action); + } + }; +} diff --git a/src/store.tsx b/src/store.tsx index 1da6bf8..515ff04 100644 --- a/src/store.tsx +++ b/src/store.tsx @@ -4,6 +4,8 @@ import session from 'redux-persist/lib/storage/session'; import thunkMiddleware from 'redux-thunk'; import { createLogger } from 'redux-logger'; +import promiseMiddleware from './promise-middleware'; + import * as EteSync from './api/EteSync'; const loggerMiddleware = createLogger(); @@ -101,91 +103,26 @@ export function fetchCredentials(username: string, password: string, encryptionP }; } -function journalsSuccess(value: JournalsData) { - return { - type: Actions.FETCH_JOURNALS, - status: FetchStatus.Success, - journals: value, - }; -} - -function journalsRequest() { - return { - type: Actions.FETCH_JOURNALS, - status: FetchStatus.Request, - }; -} - -function journalsFailure(error: Error) { - return { - type: Actions.FETCH_JOURNALS, - status: FetchStatus.Failure, - error, - }; -} - export function fetchJournals(etesync: CredentialsData) { const creds = etesync.credentials; const apiBase = etesync.serviceApiUrl; + let journalManager = new EteSync.JournalManager(creds, apiBase); - return (dispatch: any) => { - dispatch(journalsRequest()); - - let journalManager = new EteSync.JournalManager(creds, apiBase); - journalManager.list().then( - (vals) => { - dispatch(journalsSuccess(vals)); - }, - (error) => { - dispatch(journalsFailure(error)); - } - ); - }; -} - -function entriesSuccess(journal: string, value: EntriesData) { - return { - type: Actions.FETCH_ENTRIES, - status: FetchStatus.Success, - entries: value, - journal, - }; -} - -function entriesRequest(journal: string) { return { - type: Actions.FETCH_ENTRIES, - status: FetchStatus.Request, - journal, - }; -} - -function entriesFailure(journal: string, error: Error) { - return { - type: Actions.FETCH_ENTRIES, - status: FetchStatus.Failure, - journal, - error, + type: Actions.FETCH_JOURNALS, + payload: journalManager.list(), }; } -export function fetchEntries(etesync: CredentialsData, journalUid: string) { +export function fetchEntries(etesync: CredentialsData, journalUid: string, prevUid: string | null) { const creds = etesync.credentials; const apiBase = etesync.serviceApiUrl; + let entryManager = new EteSync.EntryManager(creds, apiBase, journalUid); - return (dispatch: any) => { - const prevUid = null; - dispatch(entriesRequest(journalUid)); - - let entryManager = new EteSync.EntryManager(creds, apiBase, journalUid); - entryManager.list(prevUid).then( - (vals) => { - dispatch(entriesSuccess(journalUid, vals)); - }, - (error) => { - dispatch(entriesFailure(journalUid, error)); - } - ); + return { + type: Actions.FETCH_ENTRIES, + payload: entryManager.list(prevUid), + meta: { journal: journalUid, prevUid }, }; } @@ -226,23 +163,15 @@ function credentials(state: CredentialsType = {status: FetchStatus.Initial, valu function journals(state: JournalsType = {status: FetchStatus.Initial, value: null}, action: any) { switch (action.type) { case Actions.FETCH_JOURNALS: - switch (action.status) { - case FetchStatus.Success: - return { - status: action.status, - value: action.journals, - }; - case FetchStatus.Failure: - return { - status: action.status, - value: null, - error: action.error, - }; - default: - return { - status: action.status, - value: null, - }; + if (action.error) { + return { + value: null, + error: action.payload, + }; + } else { + return { + value: (action.payload === undefined) ? null : action.payload, + }; } default: return state; @@ -252,29 +181,19 @@ function journals(state: JournalsType = {status: FetchStatus.Initial, value: nul function entries(state: EntriesType = {}, action: any) { switch (action.type) { case Actions.FETCH_ENTRIES: - switch (action.status) { - case FetchStatus.Success: - return { ...state, - [action.journal]: { - status: action.status, - value: action.entries, - }, - }; - case FetchStatus.Failure: - return { ...state, - [action.journal]: { - status: action.status, + if (action.error) { + return { ...state, + [action.meta.journal]: { value: null, - error: action.error, + error: action.payload, }, - }; - default: - return { ...state, - [action.journal]: { - status: action.status, - value: null, + }; + } else { + return { ...state, + [action.meta.journal]: { + value: (action.payload === undefined) ? null : action.payload, }, - }; + }; } default: return state; @@ -282,18 +201,14 @@ function entries(state: EntriesType = {}, action: any) { } function fetchCount(state: number = 0, action: any) { - if ('status' in action) { - switch (action.status) { - case FetchStatus.Request: + switch (action.type) { + case Actions.FETCH_JOURNALS: + case Actions.FETCH_ENTRIES: + if (action.payload === undefined) { return state + 1; - case FetchStatus.Success: - case FetchStatus.Failure: + } else { return state - 1; - default: - return state; - } - } - switch (action.type) { + } default: return state; } @@ -318,6 +233,7 @@ export const store = createStore( reducers, applyMiddleware( thunkMiddleware, + promiseMiddleware, loggerMiddleware ) ); diff --git a/yarn.lock b/yarn.lock index 97063d6..2fa797e 100644 --- a/yarn.lock +++ b/yarn.lock @@ -74,6 +74,10 @@ version "16.0.25" resolved "https://registry.yarnpkg.com/@types/react/-/react-16.0.25.tgz#bf696b83fe480c5e0eff4335ee39ebc95884a1ed" +"@types/redux-actions@^2.2.3": + version "2.2.3" + resolved "https://registry.yarnpkg.com/@types/redux-actions/-/redux-actions-2.2.3.tgz#a11777808ec37ef7246f70bed770cab3510cf926" + "@types/redux-logger@^3.0.5": version "3.0.5" resolved "https://registry.yarnpkg.com/@types/redux-logger/-/redux-logger-3.0.5.tgz#d1a02758f90845899cd304aa0912daeba2028eb6" @@ -3257,7 +3261,7 @@ locate-path@^2.0.0: p-locate "^2.0.0" path-exists "^3.0.0" -lodash-es@^4.2.0, lodash-es@^4.2.1: +lodash-es@^4.17.4, lodash-es@^4.2.0, lodash-es@^4.2.1: version "4.17.4" resolved "https://registry.yarnpkg.com/lodash-es/-/lodash-es-4.17.4.tgz#dcc1d7552e150a0640073ba9cb31d70f032950e7" @@ -3302,7 +3306,7 @@ lodash.uniq@^4.5.0: version "4.5.0" resolved "https://registry.yarnpkg.com/lodash.uniq/-/lodash.uniq-4.5.0.tgz#d0225373aeb652adc1bc82e4945339a842754773" -"lodash@>=3.5 <5", lodash@^4.14.0, lodash@^4.17.2, lodash@^4.17.3, lodash@^4.17.4, lodash@^4.2.0, lodash@^4.2.1, lodash@^4.3.0: +"lodash@>=3.5 <5", lodash@^4.13.1, lodash@^4.14.0, lodash@^4.17.2, lodash@^4.17.3, lodash@^4.17.4, lodash@^4.2.0, lodash@^4.2.1, lodash@^4.3.0: version "4.17.4" resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.4.tgz#78203a4d1c328ae1d86dca6460e369b57f4055ae" @@ -4726,6 +4730,19 @@ reduce-function-call@^1.0.1: dependencies: balanced-match "^0.4.2" +reduce-reducers@^0.1.0: + version "0.1.2" + resolved "https://registry.yarnpkg.com/reduce-reducers/-/reduce-reducers-0.1.2.tgz#fa1b4718bc5292a71ddd1e5d839c9bea9770f14b" + +redux-actions@^2.2.1: + version "2.2.1" + resolved "https://registry.yarnpkg.com/redux-actions/-/redux-actions-2.2.1.tgz#d64186b25649a13c05478547d7cd7537b892410d" + dependencies: + invariant "^2.2.1" + lodash "^4.13.1" + lodash-es "^4.17.4" + reduce-reducers "^0.1.0" + redux-logger@^3.0.6: version "3.0.6" resolved "https://registry.yarnpkg.com/redux-logger/-/redux-logger-3.0.6.tgz#f7555966f3098f3c88604c449cf0baf5778274bf"