Inbox: make useLazyScroll account for archived notifications

useLazyScroll was not accounting for the case where a notification would
be archived. This would mean that archiving a lot of notifications
without scrolling would erroneously not load more. Accounts for this
case by passing a count argument to useLazyScroll, which is then
compared against its previous value. If the previous value is greater
than the new value, (i.e. a notification was archived) then check if we
should load more.
This commit is contained in:
Liam Fitzgerald 2021-02-08 14:04:55 +10:00
parent 71ae452132
commit 003738f95a
No known key found for this signature in database
GPG Key ID: D390E12C61D1CFFB
3 changed files with 52 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

@ -385,7 +385,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

@ -1,7 +1,7 @@
import React, { useEffect, useCallback, useRef, useState } from "react";
import f from "lodash/fp";
import _ from "lodash";
import { Icon, Col, Row, Box, Text, Anchor, Rule, Center } from "@tlon/indigo-react";
import { Icon, Col, Row, Box, Text, Anchor, Rule, Center, LoadingSpinner } from "@tlon/indigo-react";
import moment from "moment";
import { Notifications, Rolodex, Timebox, IndexedNotification, Groups, GroupNotificationsConfig, NotificationGraphConfig } from "~/types";
import { MOMENT_CALENDAR_DATE, daToUnix, resourceAsPath } from "~/logic/lib/util";
@ -35,6 +35,7 @@ function filterNotification(associations: Associations, groups: string[]) {
export default function Inbox(props: {
notifications: Notifications;
notificationsSize: number;
archive: Notifications;
groups: Groups;
showArchive?: boolean;
@ -99,7 +100,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 (
@ -122,11 +128,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>
);
}