From fb09c36fbea12fea071a5b5f3da0792a10cd5ea6 Mon Sep 17 00:00:00 2001 From: Liam Fitzgerald Date: Mon, 16 Nov 2020 12:23:42 +1000 Subject: [PATCH] interface: show unread counts on group tiles --- pkg/interface/src/logic/api/hark.ts | 6 ++ .../src/logic/reducers/hark-update.ts | 76 ++++++++++--------- pkg/interface/src/logic/store/store.ts | 6 +- pkg/interface/src/logic/store/type.ts | 6 +- pkg/interface/src/types/hark-update.ts | 5 ++ .../views/apps/chat/components/ChatWindow.tsx | 1 + pkg/interface/src/views/apps/launch/app.js | 2 +- .../views/apps/launch/components/Groups.tsx | 59 +++++++++++--- .../views/landscape/components/Skeleton.tsx | 2 +- 9 files changed, 111 insertions(+), 52 deletions(-) diff --git a/pkg/interface/src/logic/api/hark.ts b/pkg/interface/src/logic/api/hark.ts index d15ca9e10..4ab0356d5 100644 --- a/pkg/interface/src/logic/api/hark.ts +++ b/pkg/interface/src/logic/api/hark.ts @@ -61,6 +61,12 @@ export class HarkApi extends BaseApi { return this.actOnNotification('read', time, index); } + readIndex(index: NotifIndex) { + return this.harkAction({ + 'read-index': index + }); + } + unread(time: BigInteger, index: NotifIndex) { return this.actOnNotification('unread', time, index); } diff --git a/pkg/interface/src/logic/reducers/hark-update.ts b/pkg/interface/src/logic/reducers/hark-update.ts index d1c4a21ef..990bccfd6 100644 --- a/pkg/interface/src/logic/reducers/hark-update.ts +++ b/pkg/interface/src/logic/reducers/hark-update.ts @@ -6,19 +6,21 @@ import { } from "~/types"; import { makePatDa } from "~/logic/lib/util"; import _ from "lodash"; +import {StoreState} from "../store/type"; -type HarkState = { - notifications: Notifications; - archivedNotifications: Notifications; - notificationsCount: number; - notificationsGraphConfig: NotificationGraphConfig; - notificationsGroupConfig: GroupNotificationsConfig; - notificationsChatConfig: string[]; -}; +type HarkState = Pick; export const HarkReducer = (json: any, state: HarkState) => { const data = _.get(json, "harkUpdate", false); if (data) { + console.log(data); reduce(data, state); } const graphHookData = _.get(json, "hark-graph-hook-update", false); @@ -139,48 +141,56 @@ function reduce(data: any, state: HarkState) { timebox(data, state); more(data, state); dnd(data, state); - count(data, state); added(data, state); - graphUnreads(data, state); + unreads(data, state); } -function graphUnreads(json: any, state: HarkState) { - const data = _.get(json, 'graph-unreads'); +function unreads(json: any, state: HarkState) { + const data = _.get(json, 'unreads'); if(data) { - state.graphUnreads = data; + data.forEach(({ index, unread }) => { + updateUnreads(state, index, x => x + unread); + }); } } +function updateUnreads(state: HarkState, index: NotifIndex, f: (u: number) => number) { + state.notificationsCount = f(state.notificationsCount); + if('graph' in index) { + const curr = state.unreads.graph[index.graph.graph] || 0; + state.unreads.graph[index.graph.graph] = f(curr); + } else if('group' in index) { + const curr = state.unreads.group[index.group.group] || 0; + state.unreads.group[index.group.group] = f(curr); + } else if('chat' in index) { + const curr = state.unreads.chat[index.chat.chat] || 0 + state.unreads.chat[index.chat.chat] = f(curr); + } +} + function added(json: any, state: HarkState) { const data = _.get(json, "added", false); if (data) { const { index, notification } = data; const time = makePatDa(data.time); const timebox = state.notifications.get(time) || []; + const arrIdx = timebox.findIndex((idxNotif) => notifIdxEqual(index, idxNotif.index) ); if (arrIdx !== -1) { + if(timebox[arrIdx]?.notification?.read) { + updateUnreads(state, index, x => x+1); + } timebox[arrIdx] = { index, notification }; state.notifications.set(time, timebox); } else { + updateUnreads(state, index, x => x+1); state.notifications.set(time, [...timebox, { index, notification }]); - state.notificationsCount++; - if('graph' in index) { - const curr = state.graphUnreads[index.graph.graph] || 0; - state.graphUnreads[index.graph.graph] = curr+1; - } } } } -function count(json: any, state: HarkState) { - const data = _.get(json, "count", false); - if (data !== false) { - state.notificationsCount = data; - } -} - const dnd = (json: any, state: HarkState) => { const data = _.get(json, "set-dnd", undefined); if (!_.isUndefined(data)) { @@ -254,12 +264,7 @@ function read(json: any, state: HarkState) { const data = _.get(json, "read", false); if (data) { const { time, index } = data; - state.notificationsCount--; - if('graph' in index) { - const curr = state.graphUnreads[index.graph.graph] || 0; - state.graphUnreads[index.graph.graph] = curr-1; - } - + updateUnreads(state, index, x => x-1); setRead(time, index, true, state); } } @@ -268,11 +273,7 @@ function unread(json: any, state: HarkState) { const data = _.get(json, "unread", false); if (data) { const { time, index } = data; - state.notificationsCount++; - if('graph' in index) { - const curr = state.graphUnreads[index.graph.graph] || 0; - state.graphUnreads[index.graph.graph] = curr+1; - } + updateUnreads(state, index, x => x+1); setRead(time, index, false, state); } } @@ -292,9 +293,10 @@ function archive(json: any, state: HarkState) { ); state.notifications.set(time, unarchived); const archiveBox = state.archivedNotifications.get(time) || []; - state.notificationsCount -= archived.filter( + const readCount = archived.filter( ({ notification }) => !notification.read ).length; + updateUnreads(state, index, x => x - readCount); state.archivedNotifications.set(time, [ ...archiveBox, ...archived.map(({ notification, index }) => ({ diff --git a/pkg/interface/src/logic/store/store.ts b/pkg/interface/src/logic/store/store.ts index dd3526953..4b80ec83a 100644 --- a/pkg/interface/src/logic/store/store.ts +++ b/pkg/interface/src/logic/store/store.ts @@ -107,7 +107,11 @@ export default class GlobalStore extends BaseStore { watching: [], }, notificationsCount: 0, - graphUnreads: {} + unreads: { + graph: {}, + group: {}, + chat: {}, + } }; } diff --git a/pkg/interface/src/logic/store/type.ts b/pkg/interface/src/logic/store/type.ts index 405e7cfbc..88ef6d3ad 100644 --- a/pkg/interface/src/logic/store/type.ts +++ b/pkg/interface/src/logic/store/type.ts @@ -14,7 +14,8 @@ import { NotificationGraphConfig, GroupNotificationsConfig, LocalUpdateRemoteContentPolicy, - BackgroundConfig + BackgroundConfig, + Unreads } from "~/types"; export interface StoreState { @@ -59,11 +60,12 @@ export interface StoreState { inbox: Inbox; pendingMessages: Map; + archivedNotifications: Notifications; notifications: Notifications; notificationsGraphConfig: NotificationGraphConfig; notificationsGroupConfig: GroupNotificationsConfig; notificationsChatConfig: string[]; notificationsCount: number, doNotDisturb: boolean; - graphUnreads: Record; + unreads: Unreads; } diff --git a/pkg/interface/src/types/hark-update.ts b/pkg/interface/src/types/hark-update.ts index e43da4a55..44935831f 100644 --- a/pkg/interface/src/types/hark-update.ts +++ b/pkg/interface/src/types/hark-update.ts @@ -60,6 +60,11 @@ export interface NotificationGraphConfig { watching: WatchedIndex[] } +export interface Unreads { + chat: Record; + group: Record; + graph: Record; +} interface WatchedIndex { graph: string; diff --git a/pkg/interface/src/views/apps/chat/components/ChatWindow.tsx b/pkg/interface/src/views/apps/chat/components/ChatWindow.tsx index f7a6e4ff4..ee56242f7 100644 --- a/pkg/interface/src/views/apps/chat/components/ChatWindow.tsx +++ b/pkg/interface/src/views/apps/chat/components/ChatWindow.tsx @@ -181,6 +181,7 @@ export default class ChatWindow extends Component { diff --git a/pkg/interface/src/views/apps/launch/app.js b/pkg/interface/src/views/apps/launch/app.js index aa6baba22..69de0ba5f 100644 --- a/pkg/interface/src/views/apps/launch/app.js +++ b/pkg/interface/src/views/apps/launch/app.js @@ -63,7 +63,7 @@ export default class LaunchApp extends React.Component { weather={props.weather} /> - + alphabeticalOrder(a.metadata.title, b.metadata.title); +const getKindUnreads = (associations: Associations) => (path: string) => ( + kind: "chat" | "graph" +): ((unreads: Unreads) => number) => + f.flow( + (x) => x[kind], + f.pickBy((_v, key) => associations[kind]?.[key]["group-path"] === path), + f.values, + f.reduce(f.add, 0) + ); + export default function Groups(props: GroupsProps & Parameters[0]) { - const { associations, ...boxProps } = props; + const { associations, unreads, ...boxProps } = props; const groups = Object.values(associations?.contacts || {}) - .filter(e => e['group-path'] in props.groups) + .filter((e) => e["group-path"] in props.groups) .sort(sortGroupsAlph); + const getUnreads = getKindUnreads(associations || {}); return ( <> - {groups.map((group) => ( - - {group.metadata.title} - - ))} + {groups.map((group) => { + const path = group["group-path"]; + const unreadCount = (["chat", "graph"] as const) + .map(getUnreads(path)) + .map((f) => f(unreads)) + .reduce(f.add, 0); + return ( + + ); + })} ); } + +interface GroupProps { + path: string; + title: string; + unreads: number; +} +function Group(props: GroupProps) { + const { path, title, unreads } = props; + return ( + + + {title} + {unreads > 0 && {unreads} unread } + + + ); +} diff --git a/pkg/interface/src/views/landscape/components/Skeleton.tsx b/pkg/interface/src/views/landscape/components/Skeleton.tsx index e1e052f54..921be109e 100644 --- a/pkg/interface/src/views/landscape/components/Skeleton.tsx +++ b/pkg/interface/src/views/landscape/components/Skeleton.tsx @@ -43,7 +43,7 @@ interface SkeletonProps { export function Skeleton(props: SkeletonProps) { const chatConfig = useChat(props.inbox, props.chatSynced); - const graphConfig = useGraphModule(props.graphKeys, props.graphs, props.graphUnreads); + const graphConfig = useGraphModule(props.graphKeys, props.graphs, props.unreads.graph); const config = useMemo( () => ({ graph: graphConfig,