archive old guild-subscriptions stuff
This commit is contained in:
parent
fb0981e92b
commit
ddd15972aa
@ -42,13 +42,13 @@ interface EffectParams<T> {
|
||||
type Arguments<T> = T extends (...args: infer A) => unknown ? A : never;
|
||||
|
||||
// The result of a general subscription. Includes the value and associated guild
|
||||
export interface SubscriptionResult<T> {
|
||||
interface SubscriptionResult<T> {
|
||||
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<T> {
|
||||
interface ScrollingSubscriptionResult<T> {
|
||||
value: {
|
||||
ends: { hasMoreAbove: boolean, hasMoreBelow: boolean };
|
||||
elements: T[];
|
||||
@ -57,7 +57,7 @@ export interface ScrollingSubscriptionResult<T> {
|
||||
}
|
||||
|
||||
// Ensures that a nullable subscriptionResult has a value and has been fetched
|
||||
export function isNonNullAndHasValue<T>(subscriptionResult: SubscriptionResult<T | null> | null): subscriptionResult is SubscriptionResult<T> {
|
||||
function isNonNullAndHasValue<T>(subscriptionResult: SubscriptionResult<T | null> | null): subscriptionResult is SubscriptionResult<T> {
|
||||
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 () => {
|
@ -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<string>(uuid.v4());
|
||||
|
||||
const refresh = useCallback(() => {
|
64
archive/infinite-scroll.tsx
Normal file
64
archive/infinite-scroll.tsx
Normal file
@ -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<HTMLDivElement>;
|
||||
fetchRetryCallable: () => Promise<void>;
|
||||
fetchAboveCallable: () => Promise<void>;
|
||||
fetchBelowCallable: () => Promise<void>;
|
||||
setScrollRatio: Dispatch<SetStateAction<number>>;
|
||||
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<InfiniteScrollProps> = (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 (
|
||||
<div className="infinite-scroll-scroll-base" ref={infiniteScrollElementRef} onScroll={updateScrollCallable}>
|
||||
<div className="infinite-scroll-elements">
|
||||
<Retry error={fetchAboveError} text={fetchAboveErrorMessage} retryFunc={fetchAboveRetry} />
|
||||
{children}
|
||||
<Retry error={fetchError} text={fetchErrorMessage} retryFunc={fetchRetryCallable} />
|
||||
<Retry error={fetchBelowError} text={fetchBelowErrorMessage} retryFunc={fetchBelowRetry} />
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
};
|
||||
|
||||
export default InfiniteScroll;
|
||||
|
@ -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<void>,
|
||||
loadMoreBelow: () => Promise<void>,
|
||||
setScrollRatio: Dispatch<SetStateAction<number>>
|
||||
): [
|
||||
updateCallable: (event: UIEvent<HTMLElement>) => void,
|
||||
loadAboveRetry: () => Promise<void>,
|
||||
loadBelowRetry: () => Promise<void>
|
||||
] {
|
||||
const isMounted = useIsMountedRef();
|
||||
|
||||
const [ loadingAbove, setLoadingAbove ] = useState<boolean>(false);
|
||||
const [ loadingBelow, setLoadingBelow ] = useState<boolean>(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<HTMLElement>) => {
|
||||
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 ];
|
||||
}
|
@ -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<T, E> {
|
||||
scrollable: LoadableValueScrolling<T, E>;
|
||||
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<T>(props: InfiniteScrollRecoilProps<T[], T>) {
|
||||
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 (
|
||||
<div className="infinite-scroll-scroll-base" onScroll={onScrollCallable}>
|
||||
<div className="infinite-scroll-elements">
|
||||
<Retry error={scrollable?.above?.error} text={aboveErrorMessage} retryFunc={fetchAboveCallable} />
|
||||
{children}
|
||||
<Retry error={scrollable.error} text={initialErrorMessage} retryFunc={scrollable.retry ?? (async () => {/* do nothing if we are unloaded */})} />
|
||||
<Retry error={scrollable?.below?.error} text={belowErrorMessage} retryFunc={fetchBelowCallable} />
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default InfiniteScrollRecoil;
|
||||
|
@ -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<HTMLDivElement>;
|
||||
fetchRetryCallable: () => Promise<void>;
|
||||
fetchAboveCallable: () => Promise<void>;
|
||||
fetchBelowCallable: () => Promise<void>;
|
||||
setScrollRatio: Dispatch<SetStateAction<number>>;
|
||||
ends: { hasMoreAbove: boolean, hasMoreBelow: boolean } | null;
|
||||
fetchError: unknown | null;
|
||||
fetchAboveError: unknown | null;
|
||||
fetchBelowError: unknown | null;
|
||||
fetchErrorMessage: string;
|
||||
fetchAboveErrorMessage: string;
|
||||
fetchBelowErrorMessage: string;
|
||||
export interface InfiniteScrollRecoilProps<T, E> {
|
||||
scrollable: LoadableValueScrolling<T, E>;
|
||||
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<InfiniteScrollProps> = (props: InfiniteScrollProps) => {
|
||||
function InfiniteScrollRecoil<T>(props: InfiniteScrollRecoilProps<T[], T>) {
|
||||
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 (
|
||||
<div className="infinite-scroll-scroll-base" ref={infiniteScrollElementRef} onScroll={updateScrollCallable}>
|
||||
<div className="infinite-scroll-scroll-base" onScroll={onScrollCallable}>
|
||||
<div className="infinite-scroll-elements">
|
||||
<Retry error={fetchAboveError} text={fetchAboveErrorMessage} retryFunc={fetchAboveRetry} />
|
||||
<Retry error={scrollable?.above?.error} text={aboveErrorMessage} retryFunc={fetchAboveCallable} />
|
||||
{children}
|
||||
<Retry error={fetchError} text={fetchErrorMessage} retryFunc={fetchRetryCallable} />
|
||||
<Retry error={fetchBelowError} text={fetchBelowErrorMessage} retryFunc={fetchBelowRetry} />
|
||||
<Retry error={scrollable.error} text={initialErrorMessage} retryFunc={scrollable.retry ?? (async () => {/* do nothing if we are unloaded */})} />
|
||||
<Retry error={scrollable?.below?.error} text={belowErrorMessage} retryFunc={fetchBelowCallable} />
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
};
|
||||
);
|
||||
}
|
||||
|
||||
export default InfiniteScroll;
|
||||
export default InfiniteScrollRecoil;
|
||||
|
||||
|
@ -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');
|
||||
|
@ -255,73 +255,8 @@ export function useAsyncSubmitButton<ResultType>(
|
||||
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<void>,
|
||||
loadMoreBelow: () => Promise<void>,
|
||||
setScrollRatio: Dispatch<SetStateAction<number>>
|
||||
): [
|
||||
updateCallable: (event: UIEvent<HTMLElement>) => void,
|
||||
loadAboveRetry: () => Promise<void>,
|
||||
loadBelowRetry: () => Promise<void>
|
||||
] {
|
||||
const isMounted = useIsMountedRef();
|
||||
|
||||
const [ loadingAbove, setLoadingAbove ] = useState<boolean>(false);
|
||||
const [ loadingBelow, setLoadingBelow ] = useState<boolean>(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<HTMLElement>) => {
|
||||
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<T>(scrollable: LoadableValueScrolling<T[], T>, threshold: number): {
|
||||
fetchAboveCallable: () => Promise<void>, // these fetch functions are returned for use in retry buttons
|
||||
fetchBelowCallable: () => Promise<void>,
|
||||
@ -378,7 +313,7 @@ export function useScrollableCallables<T>(scrollable: LoadableValueScrolling<T[]
|
||||
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}`)
|
||||
//LOG.debug(`scroll callable update. to top: ${distToTop}, to bottom: ${distToBottom}`)
|
||||
|
||||
if (distToTop < threshold) {
|
||||
await fetchAboveCallable();
|
||||
|
Loading…
Reference in New Issue
Block a user