diff --git a/src/JournalView.tsx b/src/JournalView.tsx index 4962147..36ec632 100644 --- a/src/JournalView.tsx +++ b/src/JournalView.tsx @@ -1,5 +1,7 @@ import * as React from 'react'; const Fragment = (React as any).Fragment; +import { connect } from 'react-redux'; +import { withRouter } from 'react-router'; import { Tabs, Tab } from 'material-ui/Tabs'; import { EteSyncContextType } from './EteSyncContext'; @@ -9,56 +11,77 @@ import JournalViewEntries from './JournalViewEntries'; import JournalViewAddressBook from './JournalViewAddressBook'; import JournalViewCalendar from './JournalViewCalendar'; +import * as store from './store'; + +interface PropsType { + etesync: EteSyncContextType; + match: any; +} + +interface PropsTypeInner extends PropsType { + journals: store.JournalsType; + entries: store.EntriesType; +} + +function fetchEntries(etesync: EteSyncContextType, journalUid: string) { + const credentials = etesync.credentials; + const apiBase = etesync.serviceApiUrl; + + return (dispatch: any) => { + const prevUid = null; + dispatch(store.entriesRequest(journalUid)); + + let entryManager = new EteSync.EntryManager(credentials, apiBase, journalUid); + entryManager.list(prevUid).then( + (entries) => { + dispatch(store.entriesSuccess(journalUid, entries)); + }, + (error) => { + dispatch(store.entriesFailure(journalUid, error)); + } + ); + }; +} + class JournalView extends React.Component { static defaultProps = { prevUid: null, }; - state: { - journal?: EteSync.Journal, - entries: Array, - }; - props: { - etesync: EteSyncContextType - match: any, - prevUid?: string | null, - }; + props: PropsTypeInner; constructor(props: any) { super(props); - this.state = { - entries: [], - }; } componentDidMount() { - const credentials = this.props.etesync.credentials; - const apiBase = this.props.etesync.serviceApiUrl; const journal = this.props.match.params.journalUid; - let journalManager = new EteSync.JournalManager(credentials, apiBase); - journalManager.fetch(journal).then((journalInstance) => { - this.setState({ journal: journalInstance }); - }); - - let entryManager = new EteSync.EntryManager(credentials, apiBase, journal); - entryManager.list(this.props.prevUid || null).then((entries) => { - this.setState({ entries }); - }); + store.store.dispatch(fetchEntries(this.props.etesync, journal)); } render() { - if (this.state.journal === undefined) { + const journalUid = this.props.match.params.journalUid; + const entries = this.props.entries[journalUid]; + + (window as any).me = this.props.entries; + if ((this.props.journals.value === null) || + (!entries) || (entries.value === null)) { return (
Loading
); } + const journal = this.props.journals.value.find((x) => (x.uid === journalUid)); + + if (journal === undefined) { + return (
Journal not found!
); + } + const derived = this.props.etesync.encryptionKey; - const journal = this.state.journal; - let prevUid = this.props.prevUid || null; + let prevUid: string | null = null; const cryptoManager = new EteSync.CryptoManager(derived, journal.uid, journal.version); const collectionInfo = journal.getInfo(cryptoManager); - const syncEntries = this.state.entries.map((entry) => { + const syncEntries = entries.value.map((entry) => { let syncEntry = entry.getSyncEntry(cryptoManager, prevUid); prevUid = entry.uid; @@ -99,4 +122,13 @@ class JournalView extends React.Component { } } -export default JournalView; +const mapStateToProps = (state: store.StoreState, props: PropsType) => { + return { + journals: state.cache.journals, + entries: state.cache.entries, + }; +}; + +export default withRouter(connect( + mapStateToProps +)(JournalView)); diff --git a/src/store.tsx b/src/store.tsx index 77e0046..c821804 100644 --- a/src/store.tsx +++ b/src/store.tsx @@ -11,6 +11,7 @@ const loggerMiddleware = createLogger(); enum Actions { FETCH_CREDENTIALS = 'FETCH_CREDENTIALS', FETCH_JOURNALS = 'FETCH_JOURNALS', + FETCH_ENTRIES = 'FETCH_ENTRIES', } export enum FetchStatus { @@ -38,11 +39,16 @@ export type JournalsData = Array; export type JournalsType = FetchType; +export type EntriesData = Array; + +export type EntriesType = {[key: string]: FetchType}; + export interface StoreState { fetchCount: number; credentials: CredentialsType; cache: { journals: JournalsType; + entries: EntriesType; }; } @@ -88,7 +94,33 @@ export function journalsFailure(error: Error) { return { type: Actions.FETCH_JOURNALS, status: FetchStatus.Failure, - error + error, + }; +} + +export function entriesSuccess(journal: string, value: EntriesData) { + return { + type: Actions.FETCH_ENTRIES, + status: FetchStatus.Success, + entries: value, + journal, + }; +} + +export function entriesRequest(journal: string) { + return { + type: Actions.FETCH_ENTRIES, + status: FetchStatus.Request, + journal, + }; +} + +export function entriesFailure(journal: string, error: Error) { + return { + type: Actions.FETCH_ENTRIES, + status: FetchStatus.Failure, + journal, + error, }; } @@ -152,6 +184,38 @@ 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, + value: null, + error: action.error, + }, + }; + default: + return { ...state, + [action.journal]: { + status: action.status, + value: null, + }, + }; + } + default: + return state; + } +} + function fetchCount(state: number = 0, action: any) { if ('status' in action) { switch (action.status) { @@ -180,7 +244,8 @@ const reducers = combineReducers({ fetchCount, credentials: persistReducer(credentialsPersistConfig, credentials), cache: combineReducers({ - journals + journals, + entries, }) });