diff --git a/src/App.tsx b/src/App.tsx index d16e502..872b96d 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -11,6 +11,12 @@ export const routeResolver = new RouteResolver({ _base: 'journals', _id: { _base: ':journalUid', + items: { + _base: 'items', + _id: { + _base: ':entryUid', + }, + }, entries: { _base: 'entries', _id: { diff --git a/src/JournalView.tsx b/src/JournalView.tsx index 662fa25..422045b 100644 --- a/src/JournalView.tsx +++ b/src/JournalView.tsx @@ -7,6 +7,8 @@ import * as EteSync from './api/EteSync'; import { routeResolver } from './App'; import { JournalViewEntries } from './JournalViewEntries'; +import { JournalViewAddressBook } from './JournalViewAddressBook'; +import { JournalViewCalendar } from './JournalViewCalendar'; export class JournalView extends React.Component { static defaultProps = { @@ -54,8 +56,10 @@ export class JournalView extends React.Component { const derived = this.props.etesync.encryptionKey; const journal = this.state.journal; let prevUid = this.props.prevUid || null; + const cryptoManager = new EteSync.CryptoManager(derived, journal.uid, journal.version); + const collectionInfo = journal.getInfo(cryptoManager); + const syncEntries = this.state.entries.map((entry) => { - let cryptoManager = new EteSync.CryptoManager(derived, journal.uid, journal.version); let syncEntry = entry.getSyncEntry(cryptoManager, prevUid); prevUid = entry.uid; @@ -76,6 +80,19 @@ export class JournalView extends React.Component { } /> + { + if (collectionInfo.type === 'CALENDAR') { + return ; + } else if (collectionInfo.type === 'ADDRESS_BOOK') { + return ; + } else { + return
Unsupported type
; + } + } + } + /> ); } diff --git a/src/JournalViewAddressBook.tsx b/src/JournalViewAddressBook.tsx new file mode 100644 index 0000000..cb8be9e --- /dev/null +++ b/src/JournalViewAddressBook.tsx @@ -0,0 +1,66 @@ +import * as React from 'react'; + +import * as ICAL from 'ical.js'; + +import * as EteSync from './api/EteSync'; + +export class JournalViewAddressBook extends React.Component { + static defaultProps = { + prevUid: null, + }; + + props: { + journal: EteSync.Journal, + entries: Array, + }; + + render() { + if (this.props.journal === undefined) { + return (
Loading
); + } + + 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); + } + } + + // FIXME: should be ICAL.component + let entries: Array = Array.from(items.values()).sort((_a: any, _b: any) => { + const a = _a.getFirstPropertyValue('fn'); + const b = _b.getFirstPropertyValue('fn'); + + if (a < b) { + return -1; + } else if (a > b) { + return 1; + } else { + return 0; + } + }); + + let itemList = entries.map((entry, idx) => { + const name = entry.getFirstPropertyValue('fn'); + return ( +
  • {name}
  • + ); + }); + + return ( +
    +
      + {itemList} +
    +
    + ); + } +} diff --git a/src/JournalViewCalendar.tsx b/src/JournalViewCalendar.tsx new file mode 100644 index 0000000..f4bc790 --- /dev/null +++ b/src/JournalViewCalendar.tsx @@ -0,0 +1,64 @@ +import * as React from 'react'; + +import * as ICAL from 'ical.js'; + +import * as EteSync from './api/EteSync'; + +export class JournalViewCalendar extends React.Component { + static defaultProps = { + prevUid: null, + }; + + props: { + journal: EteSync.Journal, + entries: Array, + }; + + render() { + if (this.props.journal === undefined) { + return (
    Loading
    ); + } + + let items: Map = new Map(); + + for (const syncEntry of this.props.entries) { + let comp = new ICAL.Component(ICAL.parse(syncEntry.content)).getFirstSubcomponent('vevent'); + + 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); + } + } + + // FIXME: should be ICAL.component + let entries: Array = Array.from(items.values()).map((value: string) => ( + new ICAL.Event(value) + )).sort((a: any, b: any) => { + if (a.summary < b.summary) { + return -1; + } else if (a.summary > b.summary) { + return 1; + } else { + return 0; + } + }); + + let itemList = entries.map((entry, idx) => { + return ( +
  • {entry.summary}
  • + ); + }); + + return ( +
    +
      + {itemList} +
    +
    + ); + } +} diff --git a/src/api/EteSync.tsx b/src/api/EteSync.tsx index c745b50..4fc43bf 100644 --- a/src/api/EteSync.tsx +++ b/src/api/EteSync.tsx @@ -163,14 +163,14 @@ export class Journal extends BaseJournal { } } -enum SyncEntryType { +export enum SyncEntryAction { Add = 'ADD', Delete = 'DEL', Change = 'CHANGE', } export class SyncEntry { - action: SyncEntryType; + action: SyncEntryAction; content: string; constructor(json?: any) {