From ddd15972aace845bd4932f1d64830ce3265f066b Mon Sep 17 00:00:00 2001 From: Michael Peters Date: Sun, 6 Feb 2022 19:24:25 -0600 Subject: [PATCH] archive old guild-subscriptions stuff --- .../guild-subscriptions-recoil.ts | 0 .../guild-subscriptions.ts | 8 +-- .../guilds-manager-subscriptions.ts | 2 +- archive/infinite-scroll.tsx | 64 +++++++++++++++++ archive/react-helper-partial.ts | 66 +++++++++++++++++ .../components/infinite-scroll-recoil.tsx | 36 ---------- .../elements/components/infinite-scroll.tsx | 70 ++++++------------- .../webapp/elements/lists/message-list.tsx | 7 +- .../webapp/elements/require/react-helper.tsx | 69 +----------------- 9 files changed, 164 insertions(+), 158 deletions(-) rename {src/client/webapp/elements/require => archive}/guild-subscriptions-recoil.ts (100%) rename {src/client/webapp/elements/require => archive}/guild-subscriptions.ts (99%) rename {src/client/webapp/elements/require => archive}/guilds-manager-subscriptions.ts (86%) create mode 100644 archive/infinite-scroll.tsx delete mode 100644 src/client/webapp/elements/components/infinite-scroll-recoil.tsx diff --git a/src/client/webapp/elements/require/guild-subscriptions-recoil.ts b/archive/guild-subscriptions-recoil.ts similarity index 100% rename from src/client/webapp/elements/require/guild-subscriptions-recoil.ts rename to archive/guild-subscriptions-recoil.ts diff --git a/src/client/webapp/elements/require/guild-subscriptions.ts b/archive/guild-subscriptions.ts similarity index 99% rename from src/client/webapp/elements/require/guild-subscriptions.ts rename to archive/guild-subscriptions.ts index 4a83c32..4efef36 100644 --- a/src/client/webapp/elements/require/guild-subscriptions.ts +++ b/archive/guild-subscriptions.ts @@ -42,13 +42,13 @@ interface EffectParams { type Arguments = T extends (...args: infer A) => unknown ? A : never; // The result of a general subscription. Includes the value and associated guild -export interface SubscriptionResult { +interface SubscriptionResult { value: T; guild: CombinedGuild; } // The result of a scrolling subscription. Includes the state of each end of the list, the list, and the associated guild -export interface ScrollingSubscriptionResult { +interface ScrollingSubscriptionResult { value: { ends: { hasMoreAbove: boolean, hasMoreBelow: boolean }; elements: T[]; @@ -57,7 +57,7 @@ export interface ScrollingSubscriptionResult { } // Ensures that a nullable subscriptionResult has a value and has been fetched -export function isNonNullAndHasValue(subscriptionResult: SubscriptionResult | null): subscriptionResult is SubscriptionResult { +function isNonNullAndHasValue(subscriptionResult: SubscriptionResult | null): subscriptionResult is SubscriptionResult { return !!(subscriptionResult !== null && subscriptionResult.value !== null); } @@ -902,7 +902,7 @@ function useTokensSubscription(guild: CombinedGuild) { * fetchBelowError: The error from fetching below * ] */ -export function useMessagesScrollingSubscription(guild: CombinedGuild, channel: Channel, channelGuild: CombinedGuild, scrollToBottomFunc: () => void) { +function useMessagesScrollingSubscription(guild: CombinedGuild, channel: Channel, channelGuild: CombinedGuild, scrollToBottomFunc: () => void) { const maxFetchElements = Globals.MESSAGES_PER_REQUEST; const maxElements = Globals.MAX_CURRENT_MESSAGES; const fetchMessagesFunc = useCallback(async () => { diff --git a/src/client/webapp/elements/require/guilds-manager-subscriptions.ts b/archive/guilds-manager-subscriptions.ts similarity index 86% rename from src/client/webapp/elements/require/guilds-manager-subscriptions.ts rename to archive/guilds-manager-subscriptions.ts index f4a68fd..efa53ee 100644 --- a/src/client/webapp/elements/require/guilds-manager-subscriptions.ts +++ b/archive/guilds-manager-subscriptions.ts @@ -4,7 +4,7 @@ import CombinedGuild from '../../guild-combined'; import GuildsManager from "../../guilds-manager"; // Subscribes to changes in the list of guilds in the manager -export function useGuildListSubscription(guildsManager: GuildsManager): [ guilds: CombinedGuild[] ] { +function useGuildListSubscription(guildsManager: GuildsManager): [ guilds: CombinedGuild[] ] { const [ refreshId, setRefreshId ] = useState(uuid.v4()); const refresh = useCallback(() => { diff --git a/archive/infinite-scroll.tsx b/archive/infinite-scroll.tsx new file mode 100644 index 0000000..9b0ec08 --- /dev/null +++ b/archive/infinite-scroll.tsx @@ -0,0 +1,64 @@ +import React, { Dispatch, FC, ReactNode, RefObject, SetStateAction } from 'react'; +import { useColumnReverseInfiniteScroll } from '../require/react-helper'; +import Retry from './retry'; + +export interface InfiniteScrollProps { + infiniteScrollElementRef: RefObject; + fetchRetryCallable: () => Promise; + fetchAboveCallable: () => Promise; + fetchBelowCallable: () => Promise; + setScrollRatio: Dispatch>; + ends: { hasMoreAbove: boolean, hasMoreBelow: boolean } | null; + fetchError: unknown | null; + fetchAboveError: unknown | null; + fetchBelowError: unknown | null; + fetchErrorMessage: string; + fetchAboveErrorMessage: string; + fetchBelowErrorMessage: string; + children: ReactNode; +} + +// Implements convenient features such as 'try again' components +const InfiniteScroll: FC = (props: InfiniteScrollProps) => { + const { + infiniteScrollElementRef, + fetchRetryCallable, + fetchAboveCallable, + fetchBelowCallable, + setScrollRatio, + ends, + fetchError, + fetchAboveError, + fetchBelowError, + fetchErrorMessage, + fetchAboveErrorMessage, + fetchBelowErrorMessage, + children + } = props; + + const [ + updateScrollCallable, + fetchAboveRetry, + fetchBelowRetry + ] = useColumnReverseInfiniteScroll( + 600, + ends, + fetchAboveCallable, + fetchBelowCallable, + setScrollRatio + ); + + return ( +
+
+ + {children} + + +
+
+ ) +}; + +export default InfiniteScroll; + diff --git a/archive/react-helper-partial.ts b/archive/react-helper-partial.ts index e69de29..9b6fb36 100644 --- a/archive/react-helper-partial.ts +++ b/archive/react-helper-partial.ts @@ -0,0 +1,66 @@ +/** Creates useful state for an infinite scroll subscription */ +export function useColumnReverseInfiniteScroll( + threshold: number, + ends: { hasMoreBelow: boolean, hasMoreAbove: boolean } | null, + loadMoreAbove: () => Promise, + loadMoreBelow: () => Promise, + setScrollRatio: Dispatch> +): [ + updateCallable: (event: UIEvent) => void, + loadAboveRetry: () => Promise, + loadBelowRetry: () => Promise +] { + const isMounted = useIsMountedRef(); + + const [ loadingAbove, setLoadingAbove ] = useState(false); + const [ loadingBelow, setLoadingBelow ] = useState(false); + + const loadAbove = useCallback(async () => { + if (loadingAbove) return; + if (!ends || !ends.hasMoreAbove) return; + setLoadingAbove(true); + await loadMoreAbove(); + if (!isMounted.current) return; + setLoadingAbove(false); + }, [ loadingAbove, loadMoreAbove, ends ]); + + const loadBelow = useCallback(async () => { + if (loadingBelow) return; + if (!ends || !ends.hasMoreBelow) return; + setLoadingBelow(true); + await loadMoreBelow(); + if (!isMounted.current) return; + setLoadingBelow(false); + }, [ loadingBelow, loadMoreBelow, ends ]); + + const onScrollCallable = useCallback(async (event: UIEvent) => { + const scrollTop = event.currentTarget.scrollTop; + const scrollHeight = event.currentTarget.scrollHeight; + const clientHeight = event.currentTarget.clientHeight; + + // WARNING + // There's likely an inconsistency between browsers on this so have fun when you're working + // on the cross-platform implementation of this + // scrollTop apparantly is negative for column-reverse divs (this actually kindof makes sense if you flip your head upside down) + // have to reverse this + // I expect this was a change with some version of chromium. + // MDN documentation issue: https://github.com/mdn/content/issues/10968 + + setScrollRatio(Math.abs(scrollTop / scrollHeight)); + + const distToTop = -(clientHeight - scrollHeight - scrollTop); // keep in mind scrollTop is negative >:] + const distToBottom = -scrollTop; + + //LOG.debug(`scroll callable update. to top: ${distToTop}, to bottom: ${distToBottom}`) + + if (distToTop < threshold) { + await loadAbove(); + } + + if (distToBottom < threshold) { + await loadBelow(); + } + }, [ setScrollRatio, loadAbove, loadBelow, threshold ]); + + return [ onScrollCallable, loadAbove, loadBelow ]; +} diff --git a/src/client/webapp/elements/components/infinite-scroll-recoil.tsx b/src/client/webapp/elements/components/infinite-scroll-recoil.tsx deleted file mode 100644 index 23ee498..0000000 --- a/src/client/webapp/elements/components/infinite-scroll-recoil.tsx +++ /dev/null @@ -1,36 +0,0 @@ -import React, { ReactNode } from 'react'; - -import { LoadableValueScrolling } from "../require/loadables"; -import { useScrollableCallables } from "../require/react-helper"; -import Retry from './retry'; - -export interface InfiniteScrollRecoilProps { - scrollable: LoadableValueScrolling; - initialErrorMessage: string; // For if there was a problem loading the initial messages - aboveErrorMessage: string; // For if there was a problem loading messages above the list - belowErrorMessage: string; // For if there was a problem loading messages below the list - children: ReactNode; -} -function InfiniteScrollRecoil(props: InfiniteScrollRecoilProps) { - const { scrollable, initialErrorMessage, aboveErrorMessage, belowErrorMessage, children } = props; - - const { - fetchAboveCallable, - fetchBelowCallable, - onScrollCallable - } = useScrollableCallables(scrollable, 600); // Activate fetch above/below when 600 client px from the top/bottom - - return ( -
-
- - {children} - {/* do nothing if we are unloaded */})} /> - -
-
- ); -} - -export default InfiniteScrollRecoil; - diff --git a/src/client/webapp/elements/components/infinite-scroll.tsx b/src/client/webapp/elements/components/infinite-scroll.tsx index 9b0ec08..23ee498 100644 --- a/src/client/webapp/elements/components/infinite-scroll.tsx +++ b/src/client/webapp/elements/components/infinite-scroll.tsx @@ -1,64 +1,36 @@ -import React, { Dispatch, FC, ReactNode, RefObject, SetStateAction } from 'react'; -import { useColumnReverseInfiniteScroll } from '../require/react-helper'; +import React, { ReactNode } from 'react'; + +import { LoadableValueScrolling } from "../require/loadables"; +import { useScrollableCallables } from "../require/react-helper"; import Retry from './retry'; -export interface InfiniteScrollProps { - infiniteScrollElementRef: RefObject; - fetchRetryCallable: () => Promise; - fetchAboveCallable: () => Promise; - fetchBelowCallable: () => Promise; - setScrollRatio: Dispatch>; - ends: { hasMoreAbove: boolean, hasMoreBelow: boolean } | null; - fetchError: unknown | null; - fetchAboveError: unknown | null; - fetchBelowError: unknown | null; - fetchErrorMessage: string; - fetchAboveErrorMessage: string; - fetchBelowErrorMessage: string; +export interface InfiniteScrollRecoilProps { + scrollable: LoadableValueScrolling; + initialErrorMessage: string; // For if there was a problem loading the initial messages + aboveErrorMessage: string; // For if there was a problem loading messages above the list + belowErrorMessage: string; // For if there was a problem loading messages below the list children: ReactNode; } - -// Implements convenient features such as 'try again' components -const InfiniteScroll: FC = (props: InfiniteScrollProps) => { +function InfiniteScrollRecoil(props: InfiniteScrollRecoilProps) { + const { scrollable, initialErrorMessage, aboveErrorMessage, belowErrorMessage, children } = props; + const { - infiniteScrollElementRef, - fetchRetryCallable, - fetchAboveCallable, - fetchBelowCallable, - setScrollRatio, - ends, - fetchError, - fetchAboveError, - fetchBelowError, - fetchErrorMessage, - fetchAboveErrorMessage, - fetchBelowErrorMessage, - children - } = props; - - const [ - updateScrollCallable, - fetchAboveRetry, - fetchBelowRetry - ] = useColumnReverseInfiniteScroll( - 600, - ends, fetchAboveCallable, fetchBelowCallable, - setScrollRatio - ); + onScrollCallable + } = useScrollableCallables(scrollable, 600); // Activate fetch above/below when 600 client px from the top/bottom return ( -
+
- + {children} - - + {/* do nothing if we are unloaded */})} /> +
- ) -}; + ); +} -export default InfiniteScroll; +export default InfiniteScrollRecoil; diff --git a/src/client/webapp/elements/lists/message-list.tsx b/src/client/webapp/elements/lists/message-list.tsx index 6a26309..778c1f9 100644 --- a/src/client/webapp/elements/lists/message-list.tsx +++ b/src/client/webapp/elements/lists/message-list.tsx @@ -9,7 +9,7 @@ import MessageElement from './components/message-element'; import { currGuildActiveChannelMessagesState, currGuildState } from '../require/atoms'; import { useRecoilValue } from 'recoil'; import { isFailed, isLoaded, isPended, isUnload } from '../require/loadables'; -import InfiniteScrollRecoil from '../components/infinite-scroll-recoil'; +import InfiniteScrollRecoil from '../components/infinite-scroll'; const MessageList: FC = () => { // const scrollToBottomFunc = useCallback(() => { @@ -19,6 +19,11 @@ const MessageList: FC = () => { const guild = useRecoilValue(currGuildState); const messages = useRecoilValue(currGuildActiveChannelMessagesState); + + // TODO: Show loading indicators if above/below are pending + // TODO: Show nicer retry buttons (and test the retry buttons) + + // Leaving this in for debugging purposes useEffect(() => { if (isUnload(messages)) { LOG.debug('recoilMessages unloaded'); diff --git a/src/client/webapp/elements/require/react-helper.tsx b/src/client/webapp/elements/require/react-helper.tsx index e92309a..2977605 100644 --- a/src/client/webapp/elements/require/react-helper.tsx +++ b/src/client/webapp/elements/require/react-helper.tsx @@ -255,73 +255,8 @@ export function useAsyncSubmitButton( return [ callable, text, shaking, result, errorMessage ]; } -/** Creates useful state for an infinite scroll subscription */ -export function useColumnReverseInfiniteScroll( - threshold: number, - ends: { hasMoreBelow: boolean, hasMoreAbove: boolean } | null, - loadMoreAbove: () => Promise, - loadMoreBelow: () => Promise, - setScrollRatio: Dispatch> -): [ - updateCallable: (event: UIEvent) => void, - loadAboveRetry: () => Promise, - loadBelowRetry: () => Promise -] { - const isMounted = useIsMountedRef(); - - const [ loadingAbove, setLoadingAbove ] = useState(false); - const [ loadingBelow, setLoadingBelow ] = useState(false); - - const loadAbove = useCallback(async () => { - if (loadingAbove) return; - if (!ends || !ends.hasMoreAbove) return; - setLoadingAbove(true); - await loadMoreAbove(); - if (!isMounted.current) return; - setLoadingAbove(false); - }, [ loadingAbove, loadMoreAbove, ends ]); - - const loadBelow = useCallback(async () => { - if (loadingBelow) return; - if (!ends || !ends.hasMoreBelow) return; - setLoadingBelow(true); - await loadMoreBelow(); - if (!isMounted.current) return; - setLoadingBelow(false); - }, [ loadingBelow, loadMoreBelow, ends ]); - - const onScrollCallable = useCallback(async (event: UIEvent) => { - const scrollTop = event.currentTarget.scrollTop; - const scrollHeight = event.currentTarget.scrollHeight; - const clientHeight = event.currentTarget.clientHeight; - - // WARNING - // There's likely an inconsistency between browsers on this so have fun when you're working - // on the cross-platform implementation of this - // scrollTop apparantly is negative for column-reverse divs (this actually kindof makes sense if you flip your head upside down) - // have to reverse this - // I expect this was a change with some version of chromium. - // MDN documentation issue: https://github.com/mdn/content/issues/10968 - - setScrollRatio(Math.abs(scrollTop / scrollHeight)); - - const distToTop = -(clientHeight - scrollHeight - scrollTop); // keep in mind scrollTop is negative >:] - const distToBottom = -scrollTop; - - //LOG.debug(`scroll callable update. to top: ${distToTop}, to bottom: ${distToBottom}`) - - if (distToTop < threshold) { - await loadAbove(); - } - - if (distToBottom < threshold) { - await loadBelow(); - } - }, [ setScrollRatio, loadAbove, loadBelow, threshold ]); - - return [ onScrollCallable, loadAbove, loadBelow ]; -} // Returns functions that can be used to fetch the elements above the top element / below the bottom element +// NOTE: This is for a column-reverse element export function useScrollableCallables(scrollable: LoadableValueScrolling, threshold: number): { fetchAboveCallable: () => Promise, // these fetch functions are returned for use in retry buttons fetchBelowCallable: () => Promise, @@ -378,7 +313,7 @@ export function useScrollableCallables(scrollable: LoadableValueScrolling:] const distToBottom = -scrollTop; - LOG.debug(`scroll callable update. to top: ${distToTop}, to bottom: ${distToBottom}`) + //LOG.debug(`scroll callable update. to top: ${distToTop}, to bottom: ${distToBottom}`) if (distToTop < threshold) { await fetchAboveCallable();