mirror of
https://github.com/ilyakooo0/urbit.git
synced 2024-12-11 08:55:23 +03:00
interface: show unread counts on group tiles
This commit is contained in:
parent
ec580cf8c1
commit
fb09c36fbe
@ -61,6 +61,12 @@ export class HarkApi extends BaseApi<StoreState> {
|
||||
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);
|
||||
}
|
||||
|
@ -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<StoreState,
|
||||
"notificationsChatConfig"
|
||||
| "notificationsGroupConfig"
|
||||
| "notificationsGraphConfig"
|
||||
| "notifications"
|
||||
| "notificationsCount"
|
||||
| "archivedNotifications"
|
||||
| "unreads">;
|
||||
|
||||
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 }) => ({
|
||||
|
@ -107,7 +107,11 @@ export default class GlobalStore extends BaseStore<StoreState> {
|
||||
watching: [],
|
||||
},
|
||||
notificationsCount: 0,
|
||||
graphUnreads: {}
|
||||
unreads: {
|
||||
graph: {},
|
||||
group: {},
|
||||
chat: {},
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -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<Path, Envelope[]>;
|
||||
|
||||
archivedNotifications: Notifications;
|
||||
notifications: Notifications;
|
||||
notificationsGraphConfig: NotificationGraphConfig;
|
||||
notificationsGroupConfig: GroupNotificationsConfig;
|
||||
notificationsChatConfig: string[];
|
||||
notificationsCount: number,
|
||||
doNotDisturb: boolean;
|
||||
graphUnreads: Record<string, number>;
|
||||
unreads: Unreads;
|
||||
}
|
||||
|
@ -60,6 +60,11 @@ export interface NotificationGraphConfig {
|
||||
watching: WatchedIndex[]
|
||||
}
|
||||
|
||||
export interface Unreads {
|
||||
chat: Record<string, number>;
|
||||
group: Record<string, number>;
|
||||
graph: Record<string, number>;
|
||||
}
|
||||
|
||||
interface WatchedIndex {
|
||||
graph: string;
|
||||
|
@ -181,6 +181,7 @@ export default class ChatWindow extends Component<ChatWindowProps, ChatWindowSta
|
||||
if (this.state.fetchPending) return;
|
||||
if (this.props.unreadCount === 0) return;
|
||||
this.props.api.chat.read(this.props.station);
|
||||
this.props.api.hark.readIndex({ chat: { chat: this.props.station, mention: false }});
|
||||
}
|
||||
|
||||
fetchMessages(start, end, force = false): Promise<void> {
|
||||
|
@ -63,7 +63,7 @@ export default class LaunchApp extends React.Component {
|
||||
weather={props.weather}
|
||||
/>
|
||||
<Box display={["none", "block"]} width="100%" gridColumn="1 / -1"></Box>
|
||||
<Groups groups={props.groups} associations={props.associations} />
|
||||
<Groups unreads={props.unreads} groups={props.groups} associations={props.associations} />
|
||||
</Box>
|
||||
</ScrollbarLessBox>
|
||||
<Box
|
||||
|
@ -1,9 +1,11 @@
|
||||
import React from "react";
|
||||
import { Box, Text } from "@tlon/indigo-react";
|
||||
import { Box, Text, Col } from "@tlon/indigo-react";
|
||||
import f from "lodash/fp";
|
||||
import _ from "lodash";
|
||||
|
||||
import { Associations, Association } from "~/types";
|
||||
import { Associations, Association, Unreads } from "~/types";
|
||||
import { alphabeticalOrder } from "~/logic/lib/util";
|
||||
import Tile from '../components/tiles/tile';
|
||||
import Tile from "../components/tiles/tile";
|
||||
|
||||
interface GroupsProps {
|
||||
associations: Associations;
|
||||
@ -12,20 +14,57 @@ interface GroupsProps {
|
||||
const sortGroupsAlph = (a: Association, b: Association) =>
|
||||
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<typeof Box>[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) => (
|
||||
<Tile to={`/~landscape${group["group-path"]}`}>
|
||||
<Text>{group.metadata.title}</Text>
|
||||
</Tile>
|
||||
))}
|
||||
{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 (
|
||||
<Group
|
||||
unreads={unreadCount}
|
||||
path={group["group-path"]}
|
||||
title={group.metadata.title}
|
||||
/>
|
||||
);
|
||||
})}
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
interface GroupProps {
|
||||
path: string;
|
||||
title: string;
|
||||
unreads: number;
|
||||
}
|
||||
function Group(props: GroupProps) {
|
||||
const { path, title, unreads } = props;
|
||||
return (
|
||||
<Tile to={`/~landscape${path}`}>
|
||||
<Col height="100%" justifyContent="space-between">
|
||||
<Text>{title}</Text>
|
||||
{unreads > 0 && <Text gray>{unreads} unread </Text>}
|
||||
</Col>
|
||||
</Tile>
|
||||
);
|
||||
}
|
||||
|
@ -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,
|
||||
|
Loading…
Reference in New Issue
Block a user