Merge pull request #4393 from urbit/lf/hark-loading

Inbox: make useLazyScroll account for archived notifications
This commit is contained in:
matildepark 2021-02-08 21:12:44 -05:00 committed by GitHub
commit 29a1e33505
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 74 additions and 20 deletions

View File

@ -1,5 +1,6 @@
import { useEffect, RefObject, useRef, useState } from "react";
import _ from "lodash";
import usePreviousValue from "./usePreviousValue";
export function distanceToBottom(el: HTMLElement) {
const { scrollTop, scrollHeight, clientHeight } = el;
@ -11,28 +12,41 @@ export function distanceToBottom(el: HTMLElement) {
export function useLazyScroll(
ref: RefObject<HTMLElement>,
margin: number,
count: number,
loadMore: () => Promise<boolean>
) {
const [isDone, setIsDone] = useState(false);
const [isLoading, setIsLoading] = useState(false);
const oldCount = usePreviousValue(count);
const loadUntil = (el: HTMLElement) => {
if (!isDone && distanceToBottom(el) < margin) {
setIsLoading(true);
return loadMore().then((done) => {
setIsLoading(false);
if (done) {
setIsDone(true);
return Promise.resolve();
}
return loadUntil(el);
});
}
setIsLoading(false);
return Promise.resolve();
};
useEffect(() => {
if((oldCount > count) && ref.current) {
loadUntil(ref.current);
}
}, [count]);
useEffect(() => {
if (!ref.current) {
return;
}
setIsDone(false);
const scroll = ref.current;
const loadUntil = (el: HTMLElement) => {
if (!isDone && distanceToBottom(el) < margin) {
return loadMore().then((done) => {
if (done) {
setIsDone(true);
return Promise.resolve();
}
return loadUntil(el);
});
}
return Promise.resolve();
};
loadUntil(scroll);
const onScroll = (e: Event) => {
@ -40,12 +54,13 @@ export function useLazyScroll(
loadUntil(el);
};
ref.current.addEventListener("scroll", onScroll);
ref.current.addEventListener("scroll", onScroll, { passive: true });
return () => {
ref.current?.removeEventListener("scroll", onScroll);
};
}, [ref?.current]);
}, [ref?.current, count]);
return isDone;
return { isDone, isLoading };
}

View File

@ -0,0 +1,20 @@
import { useRef } from "react";
import { Primitive } from "~/types";
export default function usePreviousValue<T extends Primitive>(value: T): T {
const prev = useRef<T | null>(null);
const curr = useRef<T | null>(null);
if (prev?.current !== curr?.current) {
prev.current = curr?.current;
}
if (curr.current !== value) {
curr.current = value;
}
return prev.current!;
}

View File

@ -350,7 +350,12 @@ function archive(json: any, state: HarkState) {
const [archived, unarchived] = _.partition(timebox, (idxNotif) =>
notifIdxEqual(index, idxNotif.index)
);
state.notifications.set(time, unarchived);
if(unarchived.length === 0) {
console.log('deleting entire timebox');
state.notifications.delete(time);
} else {
state.notifications.set(time, unarchived);
}
const newlyRead = archived.filter(x => !x.notification.read).length;
updateNotificationStats(state, index, 'notifications', (x) => x - newlyRead);
}

View File

@ -13,3 +13,4 @@ export * from './metadata-update';
export * from './noun';
export * from './s3-update';
export * from './workspace';
export * from './util';

View File

@ -1,4 +1,5 @@
import { Icon } from "@tlon/indigo-react";
export type PropFunc<T extends (...args: any[]) => any> = Parameters<T>[0];
export type Primitive = string | number | undefined | symbol | null | boolean;
export type IconRef = PropFunc<typeof Icon>['icon'];

View File

@ -1,7 +1,7 @@
import React, { useEffect, useCallback, useRef, useState } from "react";
import f from "lodash/fp";
import _ from "lodash";
import { Icon, Col, Center, Row, Box, Text, Anchor, Rule } from "@tlon/indigo-react";
import { Icon, Col, Center, Row, Box, Text, Anchor, Rule, LoadingSpinner } from "@tlon/indigo-react";
import moment from "moment";
import { Notifications, Rolodex, Timebox, IndexedNotification, Groups, joinProgress, JoinRequests, GroupNotificationsConfig, NotificationGraphConfig } from "~/types";
import { MOMENT_CALENDAR_DATE, daToUnix, resourceAsPath } from "~/logic/lib/util";
@ -38,6 +38,7 @@ function filterNotification(associations: Associations, groups: string[]) {
export default function Inbox(props: {
notifications: Notifications;
notificationsSize: number;
archive: Notifications;
groups: Groups;
showArchive?: boolean;
@ -103,7 +104,12 @@ export default function Inbox(props: {
return api.hark.getMore();
}, [api]);
const loadedAll = useLazyScroll(scrollRef, 0.2, loadMore);
const { isDone, isLoading } = useLazyScroll(
scrollRef,
0.2,
_.flatten(notifications).length,
loadMore
);
return (
@ -126,11 +132,17 @@ export default function Inbox(props: {
/>
);
})}
{loadedAll && (
{isDone && (
<Center mt="2" borderTop={notifications.length !== 0 ? 1 : 0} borderTopColor="washedGray" width="100%" height="96px">
<Text gray fontSize="1">No more notifications</Text>
</Center>
)}
{isLoading && (
<Center mt="2" borderTop={notifications.length !== 0 ? 1 : 0} borderTopColor="washedGray" width="100%" height="96px">
<LoadingSpinner />
</Center>
)}
</Col>
);
}