From e6778f5aceb8b118ea54d2a80b9e477b412c128d Mon Sep 17 00:00:00 2001 From: Tom Hacohen Date: Thu, 7 Dec 2017 16:58:50 +0000 Subject: [PATCH] Make the sync gate render the complete address book. --- src/JournalFetcher.tsx | 57 -------------------- src/Root.tsx | 4 +- src/SyncGate.tsx | 107 +++++++++++++++++++++++++++++++++++++ src/journal-processors.tsx | 34 +++++++----- 4 files changed, 129 insertions(+), 73 deletions(-) delete mode 100644 src/JournalFetcher.tsx create mode 100644 src/SyncGate.tsx diff --git a/src/JournalFetcher.tsx b/src/JournalFetcher.tsx deleted file mode 100644 index 93abdbe..0000000 --- a/src/JournalFetcher.tsx +++ /dev/null @@ -1,57 +0,0 @@ -import * as React from 'react'; -import { connect } from 'react-redux'; -import { Switch, Route, withRouter } from 'react-router'; -import LoadingIndicator from './LoadingIndicator'; - -import Journal from './Journal'; - -import { routeResolver } from './App'; - -import { store, JournalsType, fetchJournals, StoreState, CredentialsData } from './store'; - -interface PropsType { - etesync: CredentialsData; -} - -interface PropsTypeInner extends PropsType { - journals: JournalsType; -} - -class JournalFetcher extends React.Component { - props: PropsTypeInner; - - constructor(props: any) { - super(props); - } - - componentDidMount() { - store.dispatch(fetchJournals(this.props.etesync)); - } - - render() { - if (this.props.journals.value === null) { - return (); - } - - const journals = this.props.journals.value; - - return ( - - } - /> - - ); - } -} - -const mapStateToProps = (state: StoreState, props: PropsType) => { - return { - journals: state.cache.journals, - }; -}; - -export default withRouter(connect( - mapStateToProps -)(JournalFetcher)); diff --git a/src/Root.tsx b/src/Root.tsx index 9b3d1ce..2eb8a17 100644 --- a/src/Root.tsx +++ b/src/Root.tsx @@ -3,7 +3,7 @@ import { connect } from 'react-redux'; import { withRouter } from 'react-router'; import Paper from 'material-ui/Paper'; -import JournalFetcher from './JournalFetcher'; +import SyncGate from './SyncGate'; import LoginForm from './LoginForm'; import LoadingIndicator from './LoadingIndicator'; @@ -43,7 +43,7 @@ class Root extends React.Component { } return ( - + ); } } diff --git a/src/SyncGate.tsx b/src/SyncGate.tsx new file mode 100644 index 0000000..d1d2d03 --- /dev/null +++ b/src/SyncGate.tsx @@ -0,0 +1,107 @@ +import * as React from 'react'; +import { connect } from 'react-redux'; +import { withRouter } from 'react-router'; +import LoadingIndicator from './LoadingIndicator'; + +import * as EteSync from './api/EteSync'; + +import AddressBook from './AddressBook'; + +import { store, JournalsType, EntriesType, fetchJournals, fetchEntries, StoreState, CredentialsData } from './store'; + +import { syncEntriesToItemMap } from './journal-processors'; + +interface PropsType { + etesync: CredentialsData; +} + +interface PropsTypeInner extends PropsType { + journals: JournalsType; + entries: EntriesType; +} + +class SyncGate extends React.Component { + props: PropsTypeInner; + + constructor(props: any) { + super(props); + this.contactClicked = this.contactClicked.bind(this); + } + + contactClicked(contact: any) { + // FIXME + } + + componentDidMount() { + store.dispatch(fetchJournals(this.props.etesync)); + } + + componentWillReceiveProps(nextProps: PropsTypeInner) { + if (nextProps.journals.value && (this.props.journals.value !== nextProps.journals.value)) { + for (const journal of nextProps.journals.value) { + store.dispatch(fetchEntries(this.props.etesync, journal.uid, null)); + } + } + } + + render() { + const entryArrays = Object.keys(this.props.entries).map((key) => { + return this.props.entries[key].value; + }); + + if ((this.props.journals.value === null) || + (entryArrays.length === 0) || !entryArrays.every((x: any) => (x !== null))) { + return (); + } + + const derived = this.props.etesync.encryptionKey; + + let syncEntries: EteSync.SyncEntry[] = []; + for (const journal of this.props.journals.value) { + const journalEntries = this.props.entries[journal.uid].value; + const cryptoManager = new EteSync.CryptoManager(derived, journal.uid, journal.version); + + let prevUid: string | null = null; + + if (!journalEntries) { + continue; + } + + // FIXME: Skip shared journals for now + if (journal.key) { + continue; + } + + const collectionInfo = journal.getInfo(cryptoManager); + + if (collectionInfo.type !== 'ADDRESS_BOOK') { + continue; + } + + syncEntries = syncEntries.concat(journalEntries.map((entry) => { + let syncEntry = entry.getSyncEntry(cryptoManager, prevUid); + prevUid = entry.uid; + + return syncEntry; + })); + + } + + let items = syncEntriesToItemMap(syncEntries); + + return ( + + ); + } +} + +const mapStateToProps = (state: StoreState, props: PropsType) => { + return { + journals: state.cache.journals, + entries: state.cache.entries, + }; +}; + +export default withRouter(connect( + mapStateToProps +)(SyncGate)); diff --git a/src/journal-processors.tsx b/src/journal-processors.tsx index eaee353..c8da9fb 100644 --- a/src/journal-processors.tsx +++ b/src/journal-processors.tsx @@ -4,26 +4,32 @@ import * as ICAL from 'ical.js'; import * as EteSync from './api/EteSync'; +export function syncEntriesToItemMap(entries: EteSync.SyncEntry[]) { + let items: Map = new Map(); + + for (const syncEntry of entries) { + let comp = new ICAL.Component(ICAL.parse(syncEntry.content)); + + const uid = comp.getFirstPropertyValue('uid'); + + if ((syncEntry.action === EteSync.SyncEntryAction.Add) || + (syncEntry.action === EteSync.SyncEntryAction.Change)) { + items.set(uid, comp); + } else if (syncEntry.action === EteSync.SyncEntryAction.Delete) { + items.delete(uid); + } + } + + return items; +} + // FIXME: Figure out how to correctly use the props type export function syncEntryToEntriesProps(WrappedComponent: any) { return class extends React.Component { props: any; render() { - let items: Map = new Map(); - - for (const syncEntry of this.props.entries) { - let comp = new ICAL.Component(ICAL.parse(syncEntry.content)); - - const uid = comp.getFirstPropertyValue('uid'); - - if ((syncEntry.action === EteSync.SyncEntryAction.Add) || - (syncEntry.action === EteSync.SyncEntryAction.Change)) { - items.set(uid, comp); - } else if (syncEntry.action === EteSync.SyncEntryAction.Delete) { - items.delete(uid); - } - } + let items = syncEntriesToItemMap(this.props.entries); return (