mirror of
https://github.com/ilyakooo0/urbit.git
synced 2024-12-02 15:13:25 +03:00
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:
parent
71ae452132
commit
003738f95a
@ -1,5 +1,6 @@
|
|||||||
import { useEffect, RefObject, useRef, useState } from "react";
|
import { useEffect, RefObject, useRef, useState } from "react";
|
||||||
import _ from "lodash";
|
import _ from "lodash";
|
||||||
|
import usePreviousValue from "./usePreviousValue";
|
||||||
|
|
||||||
export function distanceToBottom(el: HTMLElement) {
|
export function distanceToBottom(el: HTMLElement) {
|
||||||
const { scrollTop, scrollHeight, clientHeight } = el;
|
const { scrollTop, scrollHeight, clientHeight } = el;
|
||||||
@ -11,28 +12,41 @@ export function distanceToBottom(el: HTMLElement) {
|
|||||||
export function useLazyScroll(
|
export function useLazyScroll(
|
||||||
ref: RefObject<HTMLElement>,
|
ref: RefObject<HTMLElement>,
|
||||||
margin: number,
|
margin: number,
|
||||||
|
count: number,
|
||||||
loadMore: () => Promise<boolean>
|
loadMore: () => Promise<boolean>
|
||||||
) {
|
) {
|
||||||
const [isDone, setIsDone] = useState(false);
|
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(() => {
|
useEffect(() => {
|
||||||
if (!ref.current) {
|
if (!ref.current) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
setIsDone(false);
|
setIsDone(false);
|
||||||
const scroll = ref.current;
|
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);
|
loadUntil(scroll);
|
||||||
|
|
||||||
const onScroll = (e: Event) => {
|
const onScroll = (e: Event) => {
|
||||||
@ -40,12 +54,13 @@ export function useLazyScroll(
|
|||||||
loadUntil(el);
|
loadUntil(el);
|
||||||
};
|
};
|
||||||
|
|
||||||
ref.current.addEventListener("scroll", onScroll);
|
ref.current.addEventListener("scroll", onScroll, { passive: true });
|
||||||
|
|
||||||
return () => {
|
return () => {
|
||||||
ref.current?.removeEventListener("scroll", onScroll);
|
ref.current?.removeEventListener("scroll", onScroll);
|
||||||
};
|
};
|
||||||
}, [ref?.current]);
|
}, [ref?.current, count]);
|
||||||
|
|
||||||
|
|
||||||
return isDone;
|
return { isDone, isLoading };
|
||||||
}
|
}
|
||||||
|
@ -385,7 +385,12 @@ function archive(json: any, state: HarkState) {
|
|||||||
const [archived, unarchived] = _.partition(timebox, (idxNotif) =>
|
const [archived, unarchived] = _.partition(timebox, (idxNotif) =>
|
||||||
notifIdxEqual(index, idxNotif.index)
|
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;
|
const newlyRead = archived.filter(x => !x.notification.read).length;
|
||||||
updateNotificationStats(state, index, 'notifications', (x) => x - newlyRead);
|
updateNotificationStats(state, index, 'notifications', (x) => x - newlyRead);
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import React, { useEffect, useCallback, useRef, useState } from "react";
|
import React, { useEffect, useCallback, useRef, useState } from "react";
|
||||||
import f from "lodash/fp";
|
import f from "lodash/fp";
|
||||||
import _ from "lodash";
|
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 moment from "moment";
|
||||||
import { Notifications, Rolodex, Timebox, IndexedNotification, Groups, GroupNotificationsConfig, NotificationGraphConfig } from "~/types";
|
import { Notifications, Rolodex, Timebox, IndexedNotification, Groups, GroupNotificationsConfig, NotificationGraphConfig } from "~/types";
|
||||||
import { MOMENT_CALENDAR_DATE, daToUnix, resourceAsPath } from "~/logic/lib/util";
|
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: {
|
export default function Inbox(props: {
|
||||||
notifications: Notifications;
|
notifications: Notifications;
|
||||||
|
notificationsSize: number;
|
||||||
archive: Notifications;
|
archive: Notifications;
|
||||||
groups: Groups;
|
groups: Groups;
|
||||||
showArchive?: boolean;
|
showArchive?: boolean;
|
||||||
@ -99,7 +100,12 @@ export default function Inbox(props: {
|
|||||||
return api.hark.getMore();
|
return api.hark.getMore();
|
||||||
}, [api]);
|
}, [api]);
|
||||||
|
|
||||||
const loadedAll = useLazyScroll(scrollRef, 0.2, loadMore);
|
const { isDone, isLoading } = useLazyScroll(
|
||||||
|
scrollRef,
|
||||||
|
0.2,
|
||||||
|
_.flatten(notifications).length,
|
||||||
|
loadMore
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
return (
|
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">
|
<Center mt="2" borderTop={notifications.length !== 0 ? 1 : 0} borderTopColor="washedGray" width="100%" height="96px">
|
||||||
<Text gray fontSize="1">No more notifications</Text>
|
<Text gray fontSize="1">No more notifications</Text>
|
||||||
</Center>
|
</Center>
|
||||||
|
)}
|
||||||
|
{isLoading && (
|
||||||
|
<Center mt="2" borderTop={notifications.length !== 0 ? 1 : 0} borderTopColor="washedGray" width="100%" height="96px">
|
||||||
|
<LoadingSpinner />
|
||||||
|
</Center>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
</Col>
|
</Col>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user