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 (