From 2d40d0655bb9092e9d4c3f45c6c83e83110f909a Mon Sep 17 00:00:00 2001 From: Liam Fitzgerald Date: Mon, 14 Jun 2021 10:54:44 +1000 Subject: [PATCH] notifications: revive optimistic updates --- pkg/interface/src/logic/state/base.ts | 16 ++++++++++++++++ pkg/interface/src/logic/state/hark.ts | 16 +++++++++++++++- .../views/apps/notifications/notification.tsx | 10 ++++++---- pkg/npm/http-api/src/Urbit.ts | 1 - 4 files changed, 37 insertions(+), 6 deletions(-) diff --git a/pkg/interface/src/logic/state/base.ts b/pkg/interface/src/logic/state/base.ts index 558f65f4b..cf7e3a0a6 100644 --- a/pkg/interface/src/logic/state/base.ts +++ b/pkg/interface/src/logic/state/base.ts @@ -4,6 +4,8 @@ import _ from 'lodash'; import create, { GetState, SetState, UseStore } from 'zustand'; import { persist } from 'zustand/middleware'; import Urbit, { SubscriptionRequestInterface } from '@urbit/http-api'; +import { Poke } from '@urbit/api'; +import airlock from '~/logic/api'; setAutoFreeze(false); enablePatches(); @@ -155,3 +157,17 @@ export async function doOptimistically(state: UseStore(state: UseStore>, poke: Poke, reduce: ((a: A, fn: S & BaseState) => S & BaseState)[]) { + let num: string | undefined = undefined; + try { + num = optReduceState(state, poke.json, reduce); + await airlock.poke(poke); + state.getState().removePatch(num); + } catch (e) { + console.error(e); + if(num) { + state.getState().rollback(num); + } + } +} diff --git a/pkg/interface/src/logic/state/hark.ts b/pkg/interface/src/logic/state/hark.ts index cd2c8ae0c..5f6487998 100644 --- a/pkg/interface/src/logic/state/hark.ts +++ b/pkg/interface/src/logic/state/hark.ts @@ -1,5 +1,8 @@ import { + archive, NotificationGraphConfig, + NotifIndex, + readNote, Timebox, Unreads } from '@urbit/api'; @@ -9,8 +12,9 @@ import BigIntOrderedMap from '@urbit/api/lib/BigIntOrderedMap'; import api from '~/logic/api'; import { useCallback } from 'react'; -import { createState, createSubscription, reduceState, reduceStateN } from './base'; +import { createState, createSubscription, pokeOptimisticallyN, reduceState, reduceStateN } from './base'; import { reduce, reduceGraph, reduceGroup } from '../reducers/hark-update'; +import { BigInteger } from 'big-integer'; export const HARK_FETCH_MORE_COUNT = 3; @@ -26,6 +30,8 @@ export interface HarkState { notificationsGraphConfig: NotificationGraphConfig; // TODO unthread this everywhere notificationsGroupConfig: string[]; unreads: Unreads; + archive: (index: NotifIndex, time?: BigInteger) => Promise; + readNote: (index: NotifIndex) => Promise; } const useHarkState = createState( @@ -34,6 +40,13 @@ const useHarkState = createState( archivedNotifications: new BigIntOrderedMap(), doNotDisturb: false, unreadNotes: [], + archive: async (index: NotifIndex, time?: BigInteger) => { + const poke = archive(index, time); + await pokeOptimisticallyN(useHarkState, poke, [reduce]); + }, + readNote: async (index) => { + await pokeOptimisticallyN(useHarkState, readNote(index), [reduce]); + }, getMore: async (): Promise => { const state = get(); const offset = state.notifications.size || 0; @@ -49,6 +62,7 @@ const useHarkState = createState( }); reduceState(useHarkState, harkUpdate, [reduce]); }, + notifications: new BigIntOrderedMap(), notificationsCount: 0, notificationsGraphConfig: { diff --git a/pkg/interface/src/views/apps/notifications/notification.tsx b/pkg/interface/src/views/apps/notifications/notification.tsx index 6745d0de0..5d97fbe59 100644 --- a/pkg/interface/src/views/apps/notifications/notification.tsx +++ b/pkg/interface/src/views/apps/notifications/notification.tsx @@ -1,10 +1,8 @@ import { Box, Button, Icon, Row } from '@tlon/indigo-react'; import { - archive, GraphNotificationContents, GroupNotificationContents, - IndexedNotification, - readNote + IndexedNotification } from '@urbit/api'; import { BigInteger } from 'big-integer'; import React, { ReactNode, useCallback } from 'react'; @@ -16,6 +14,8 @@ import { SwipeMenu } from '~/views/components/SwipeMenu'; import { GraphNotification } from './graph'; import { GroupNotification } from './group'; import airlock from '~/logic/api'; +import useHarkState from '~/logic/state/hark'; +import shallow from 'zustand/shallow'; export interface NotificationProps { notification: IndexedNotification; @@ -33,12 +33,14 @@ export function NotificationWrapper(props: { const isMobile = useLocalState(s => s.mobile); + const [archive, readNote] = useHarkState(s => [s.archive, s.readNote], shallow); + const onArchive = useCallback(async (e) => { e.stopPropagation(); if (!notification) { return; } - await airlock.poke(archive(notification.index, time)); + await archive(notification.index, time); }, [time, notification]); const onClick = (e: any) => { diff --git a/pkg/npm/http-api/src/Urbit.ts b/pkg/npm/http-api/src/Urbit.ts index 4431d6586..7683b6d79 100644 --- a/pkg/npm/http-api/src/Urbit.ts +++ b/pkg/npm/http-api/src/Urbit.ts @@ -187,7 +187,6 @@ export class Urbit { return; // everything's good } else { reject(); - this.onError && this.onError(response?.statusText || 'Unknown Error'); throw new Error(); } },