|
|
|
@ -34,7 +34,7 @@ export type MultipleSubscriptionEvents<T> = {
|
|
|
|
|
|
|
|
|
|
interface EffectParams<T> {
|
|
|
|
|
guild: CombinedGuild;
|
|
|
|
|
onFetch: (value: T | null) => void;
|
|
|
|
|
onFetch: (value: T | null, valueGuild: CombinedGuild) => void;
|
|
|
|
|
onFetchError: (e: unknown) => void;
|
|
|
|
|
bindEventsFunc: () => void;
|
|
|
|
|
unbindEventsFunc: () => void;
|
|
|
|
@ -77,6 +77,7 @@ function useGuildSubscriptionEffect<T>(
|
|
|
|
|
|
|
|
|
|
const isMounted = useIsMountedRef();
|
|
|
|
|
const guildRef = useRef<CombinedGuild>(guild);
|
|
|
|
|
guildRef.current = guild;
|
|
|
|
|
|
|
|
|
|
const fetchManagerFunc = useCallback(async () => {
|
|
|
|
|
if (!isMounted.current) return;
|
|
|
|
@ -84,8 +85,8 @@ function useGuildSubscriptionEffect<T>(
|
|
|
|
|
try {
|
|
|
|
|
const value = await fetchFunc();
|
|
|
|
|
if (!isMounted.current) return;
|
|
|
|
|
if (guildRef.current !== guild) return; // Don't call onFetch if we changed guilds
|
|
|
|
|
onFetch(value);
|
|
|
|
|
if (guildRef.current !== guild) return; // Don't call onFetch if we changed guilds. TODO: Test this
|
|
|
|
|
onFetch(value, guild);
|
|
|
|
|
} catch (e: unknown) {
|
|
|
|
|
LOG.error('error fetching for subscription', e);
|
|
|
|
|
if (!isMounted.current) return;
|
|
|
|
@ -118,18 +119,22 @@ function useSingleGuildSubscription<T, UE extends keyof Connectable, CE extends
|
|
|
|
|
guild: CombinedGuild,
|
|
|
|
|
eventMappingParams: SingleEventMappingParams<T, UE, CE>,
|
|
|
|
|
fetchFunc: (() => Promise<T>) | (() => Promise<T | null>)
|
|
|
|
|
): [value: T | null, fetchError: unknown | null, events: EventEmitter<SingleSubscriptionEvents>] {
|
|
|
|
|
): [value: T | null, valueGuild: CombinedGuild | null, fetchError: unknown | null, events: EventEmitter<SingleSubscriptionEvents>] {
|
|
|
|
|
const { updatedEventName, updatedEventArgsMap, conflictEventName, conflictEventArgsMap } = eventMappingParams;
|
|
|
|
|
|
|
|
|
|
const isMounted = useIsMountedRef();
|
|
|
|
|
const guildRef = useRef<CombinedGuild>(guild);
|
|
|
|
|
guildRef.current = guild;
|
|
|
|
|
|
|
|
|
|
const [ fetchError, setFetchError ] = useState<unknown | null>(null);
|
|
|
|
|
const [ value, setValue ] = useState<T | null>(null);
|
|
|
|
|
const [ valueGuild, setValueGuild ] = useState<CombinedGuild | null>(null);
|
|
|
|
|
|
|
|
|
|
const events = useMemo(() => new EventEmitter<SingleSubscriptionEvents>(), []);
|
|
|
|
|
|
|
|
|
|
const onFetch = useCallback((fetchValue: T | null) => {
|
|
|
|
|
const onFetch = useCallback((fetchValue: T | null, fetchValueGuild: CombinedGuild) => {
|
|
|
|
|
setValue(fetchValue);
|
|
|
|
|
setValueGuild(fetchValueGuild);
|
|
|
|
|
setFetchError(null);
|
|
|
|
|
events.emit('fetch');
|
|
|
|
|
}, []);
|
|
|
|
@ -137,16 +142,23 @@ function useSingleGuildSubscription<T, UE extends keyof Connectable, CE extends
|
|
|
|
|
const onFetchError = useCallback((e: unknown) => {
|
|
|
|
|
setFetchError(e);
|
|
|
|
|
setValue(null);
|
|
|
|
|
setValueGuild(null);
|
|
|
|
|
events.emit('fetch-error');
|
|
|
|
|
}, []);
|
|
|
|
|
|
|
|
|
|
const onUpdated = useCallback((updateValue: T) => {
|
|
|
|
|
const onUpdated = useCallback((updateValue: T, updateValueGuild: CombinedGuild) => {
|
|
|
|
|
setValue(updateValue);
|
|
|
|
|
if (updateValueGuild !== guildRef.current) {
|
|
|
|
|
LOG.warn(`update guild (${updateValueGuild.id}) != current guild (${guildRef.current})`);
|
|
|
|
|
}
|
|
|
|
|
events.emit('updated');
|
|
|
|
|
}, []);
|
|
|
|
|
|
|
|
|
|
const onConflict = useCallback((conflictValue: T) => {
|
|
|
|
|
const onConflict = useCallback((conflictValue: T, conflictValueGuild: CombinedGuild) => {
|
|
|
|
|
setValue(conflictValue);
|
|
|
|
|
if (conflictValueGuild !== guildRef.current) {
|
|
|
|
|
LOG.warn(`conflict guild (${conflictValueGuild.id}) != current guild (${guildRef.current})`);
|
|
|
|
|
}
|
|
|
|
|
events.emit('conflict');
|
|
|
|
|
}, []);
|
|
|
|
|
|
|
|
|
@ -154,23 +166,25 @@ function useSingleGuildSubscription<T, UE extends keyof Connectable, CE extends
|
|
|
|
|
// otherwise, I may have done this wrong. Forcing it to work with these calls
|
|
|
|
|
const boundUpdateFunc = useCallback((...args: Arguments<Connectable[UE]>): void => {
|
|
|
|
|
if (!isMounted.current) return;
|
|
|
|
|
if (guildRef.current !== guild) return;
|
|
|
|
|
const value = updatedEventArgsMap(...args);
|
|
|
|
|
onUpdated(value);
|
|
|
|
|
}, []) as (Connectable & Conflictable)[UE];
|
|
|
|
|
onUpdated(value, guild);
|
|
|
|
|
}, [ guild ]) as (Connectable & Conflictable)[UE];
|
|
|
|
|
const boundConflictFunc = useCallback((...args: Arguments<Conflictable[CE]>): void => {
|
|
|
|
|
if (!isMounted.current) return;
|
|
|
|
|
if (guildRef.current !== guild) return;
|
|
|
|
|
const value = conflictEventArgsMap(...args);
|
|
|
|
|
onConflict(value);
|
|
|
|
|
}, []) as (Connectable & Conflictable)[CE];
|
|
|
|
|
onConflict(value, guild);
|
|
|
|
|
}, [ guild ]) as (Connectable & Conflictable)[CE];
|
|
|
|
|
|
|
|
|
|
const bindEventsFunc = useCallback(() => {
|
|
|
|
|
guild.on(updatedEventName, boundUpdateFunc);
|
|
|
|
|
guild.on(conflictEventName, boundConflictFunc);
|
|
|
|
|
}, []);
|
|
|
|
|
}, [ boundUpdateFunc, boundConflictFunc ]);
|
|
|
|
|
const unbindEventsFunc = useCallback(() => {
|
|
|
|
|
guild.off(updatedEventName, boundUpdateFunc);
|
|
|
|
|
guild.off(conflictEventName, boundConflictFunc);
|
|
|
|
|
}, []);
|
|
|
|
|
}, [ boundUpdateFunc, boundConflictFunc ]);
|
|
|
|
|
|
|
|
|
|
useGuildSubscriptionEffect({
|
|
|
|
|
guild,
|
|
|
|
@ -180,7 +194,7 @@ function useSingleGuildSubscription<T, UE extends keyof Connectable, CE extends
|
|
|
|
|
unbindEventsFunc
|
|
|
|
|
}, fetchFunc);
|
|
|
|
|
|
|
|
|
|
return [ value, fetchError, events ];
|
|
|
|
|
return [ value, valueGuild, fetchError, events ];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function useMultipleGuildSubscription<
|
|
|
|
@ -196,6 +210,7 @@ function useMultipleGuildSubscription<
|
|
|
|
|
): [
|
|
|
|
|
fetchRetryCallable: () => Promise<void>,
|
|
|
|
|
value: T[] | null,
|
|
|
|
|
valueGuild: CombinedGuild | null,
|
|
|
|
|
fetchError: unknown | null,
|
|
|
|
|
events: EventEmitter<MultipleSubscriptionEvents<T>>
|
|
|
|
|
] {
|
|
|
|
@ -208,15 +223,19 @@ function useMultipleGuildSubscription<
|
|
|
|
|
} = eventMappingParams;
|
|
|
|
|
|
|
|
|
|
const isMounted = useIsMountedRef();
|
|
|
|
|
const guildRef = useRef<CombinedGuild>(guild);
|
|
|
|
|
guildRef.current = guild;
|
|
|
|
|
|
|
|
|
|
const [ fetchError, setFetchError ] = useState<unknown | null>(null);
|
|
|
|
|
const [ value, setValue ] = useState<T[] | null>(null);
|
|
|
|
|
const [ valueGuild, setValueGuild ] = useState<CombinedGuild | null>(null);
|
|
|
|
|
|
|
|
|
|
const events = useMemo(() => new EventEmitter<MultipleSubscriptionEvents<T>>(), []);
|
|
|
|
|
|
|
|
|
|
const onFetch = useCallback((fetchValue: T[] | null) => {
|
|
|
|
|
const onFetch = useCallback((fetchValue: T[] | null, fetchValueGuild: CombinedGuild) => {
|
|
|
|
|
if (fetchValue) fetchValue.sort(sortFunc);
|
|
|
|
|
setValue(fetchValue);
|
|
|
|
|
setValueGuild(fetchValueGuild);
|
|
|
|
|
setFetchError(null);
|
|
|
|
|
events.emit('fetch');
|
|
|
|
|
}, [ sortFunc ]);
|
|
|
|
@ -227,30 +246,39 @@ function useMultipleGuildSubscription<
|
|
|
|
|
events.emit('fetch-error');
|
|
|
|
|
}, []);
|
|
|
|
|
|
|
|
|
|
const onNew = useCallback((newElements: T[]) => {
|
|
|
|
|
const onNew = useCallback((newElements: T[], newElementsGuild: CombinedGuild) => {
|
|
|
|
|
setValue(currentValue => {
|
|
|
|
|
if (currentValue === null) return null;
|
|
|
|
|
if (currentValue === null) return Array.from(newElements).sort(sortFunc);
|
|
|
|
|
return currentValue.concat(newElements).sort(sortFunc);
|
|
|
|
|
})
|
|
|
|
|
});
|
|
|
|
|
if (newElementsGuild !== guildRef.current) {
|
|
|
|
|
LOG.warn(`new elements guild (${newElementsGuild.id}) != current guild (${guildRef.current})`);
|
|
|
|
|
}
|
|
|
|
|
events.emit('new', newElements);
|
|
|
|
|
}, [ sortFunc ]);
|
|
|
|
|
const onUpdated = useCallback((updatedElements: T[]) => {
|
|
|
|
|
const onUpdated = useCallback((updatedElements: T[], updatedElementsGuild: CombinedGuild) => {
|
|
|
|
|
setValue(currentValue => {
|
|
|
|
|
if (currentValue === null) return null;
|
|
|
|
|
return currentValue.map(element => updatedElements.find(updatedElement => updatedElement.id === element.id) ?? element).sort(sortFunc);
|
|
|
|
|
});
|
|
|
|
|
if (updatedElementsGuild !== guildRef.current) {
|
|
|
|
|
LOG.warn(`updated elements guild (${updatedElementsGuild.id}) != current guild (${guildRef.current})`);
|
|
|
|
|
}
|
|
|
|
|
events.emit('updated', updatedElements);
|
|
|
|
|
}, [ sortFunc ]);
|
|
|
|
|
const onRemoved = useCallback((removedElements: T[]) => {
|
|
|
|
|
const onRemoved = useCallback((removedElements: T[], removedElementsGuild: CombinedGuild) => {
|
|
|
|
|
setValue(currentValue => {
|
|
|
|
|
if (currentValue === null) return null;
|
|
|
|
|
const deletedIds = new Set(removedElements.map(deletedElement => deletedElement.id));
|
|
|
|
|
return currentValue.filter(element => !deletedIds.has(element.id)).sort(sortFunc);
|
|
|
|
|
});
|
|
|
|
|
if (removedElementsGuild !== guildRef.current) {
|
|
|
|
|
LOG.warn(`removed elements guild (${removedElementsGuild.id}) != current guild (${guildRef.current})`);
|
|
|
|
|
}
|
|
|
|
|
events.emit('removed', removedElements);
|
|
|
|
|
}, [ sortFunc ]);
|
|
|
|
|
|
|
|
|
|
const onConflict = useCallback((changes: Changes<T>) => {
|
|
|
|
|
const onConflict = useCallback((changes: Changes<T>, changesGuild: CombinedGuild) => {
|
|
|
|
|
setValue(currentValue => {
|
|
|
|
|
if (currentValue === null) return null;
|
|
|
|
|
const deletedIds = new Set(changes.deleted.map(deletedElement => deletedElement.id));
|
|
|
|
@ -260,6 +288,10 @@ function useMultipleGuildSubscription<
|
|
|
|
|
.filter(element => !deletedIds.has(element.id))
|
|
|
|
|
.sort(sortFunc);
|
|
|
|
|
});
|
|
|
|
|
if (changesGuild !== guildRef.current) {
|
|
|
|
|
LOG.warn(`conflict changes guild (${changesGuild.id}) != current guild (${guildRef.current})`);
|
|
|
|
|
}
|
|
|
|
|
setValueGuild(changesGuild);
|
|
|
|
|
events.emit('conflict', changes);
|
|
|
|
|
}, [ sortFunc ]);
|
|
|
|
|
|
|
|
|
@ -267,20 +299,24 @@ function useMultipleGuildSubscription<
|
|
|
|
|
// otherwise, I may have done this wrong. Forcing it to work with these calls
|
|
|
|
|
const boundNewFunc = useCallback((...args: Arguments<Connectable[NE]>): void => {
|
|
|
|
|
if (!isMounted.current) return;
|
|
|
|
|
onNew(newEventArgsMap(...args));
|
|
|
|
|
}, [ onNew, newEventArgsMap ]) as (Connectable & Conflictable)[NE];
|
|
|
|
|
if (guildRef.current !== guild) return; // prevent changes from a different guild
|
|
|
|
|
onNew(newEventArgsMap(...args), guild);
|
|
|
|
|
}, [ guild, onNew, newEventArgsMap ]) as (Connectable & Conflictable)[NE];
|
|
|
|
|
const boundUpdateFunc = useCallback((...args: Arguments<Connectable[UE]>): void => {
|
|
|
|
|
if (!isMounted.current) return;
|
|
|
|
|
onUpdated(updatedEventArgsMap(...args));
|
|
|
|
|
}, [ onUpdated, updatedEventArgsMap ]) as (Connectable & Conflictable)[UE];
|
|
|
|
|
if (guildRef.current !== guild) return;
|
|
|
|
|
onUpdated(updatedEventArgsMap(...args), guild);
|
|
|
|
|
}, [ guild, onUpdated, updatedEventArgsMap ]) as (Connectable & Conflictable)[UE];
|
|
|
|
|
const boundRemovedFunc = useCallback((...args: Arguments<Connectable[RE]>): void => {
|
|
|
|
|
if (!isMounted.current) return;
|
|
|
|
|
onRemoved(removedEventArgsMap(...args));
|
|
|
|
|
}, [ onRemoved, removedEventArgsMap ]) as (Connectable & Conflictable)[RE];
|
|
|
|
|
if (guildRef.current !== guild) return;
|
|
|
|
|
onRemoved(removedEventArgsMap(...args), guild);
|
|
|
|
|
}, [ guild, onRemoved, removedEventArgsMap ]) as (Connectable & Conflictable)[RE];
|
|
|
|
|
const boundConflictFunc = useCallback((...args: Arguments<Conflictable[CE]>): void => {
|
|
|
|
|
if (!isMounted.current) return;
|
|
|
|
|
onConflict(conflictEventArgsMap(...args));
|
|
|
|
|
}, [ onConflict, conflictEventArgsMap ]) as (Connectable & Conflictable)[CE];
|
|
|
|
|
if (guildRef.current !== guild) return;
|
|
|
|
|
onConflict(conflictEventArgsMap(...args), guild);
|
|
|
|
|
}, [ guild, onConflict, conflictEventArgsMap ]) as (Connectable & Conflictable)[CE];
|
|
|
|
|
|
|
|
|
|
const bindEventsFunc = useCallback(() => {
|
|
|
|
|
guild.on(newEventName, boundNewFunc);
|
|
|
|
@ -303,7 +339,7 @@ function useMultipleGuildSubscription<
|
|
|
|
|
unbindEventsFunc
|
|
|
|
|
}, fetchFunc);
|
|
|
|
|
|
|
|
|
|
return [ fetchRetryCallable, value, fetchError, events ];
|
|
|
|
|
return [ fetchRetryCallable, value, valueGuild, fetchError, events ];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function useMultipleGuildSubscriptionScrolling<
|
|
|
|
@ -327,6 +363,7 @@ function useMultipleGuildSubscriptionScrolling<
|
|
|
|
|
setScrollRatio: Dispatch<SetStateAction<number>>,
|
|
|
|
|
fetchResult: { hasMoreAbove: boolean, hasMoreBelow: boolean } | null,
|
|
|
|
|
value: T[] | null,
|
|
|
|
|
valueGuild: CombinedGuild | null,
|
|
|
|
|
fetchError: unknown | null,
|
|
|
|
|
fetchAboveError: unknown | null,
|
|
|
|
|
fetchBelowError: unknown | null,
|
|
|
|
@ -341,8 +378,11 @@ function useMultipleGuildSubscriptionScrolling<
|
|
|
|
|
} = eventMappingParams;
|
|
|
|
|
|
|
|
|
|
const isMounted = useIsMountedRef();
|
|
|
|
|
const guildRef = useRef<CombinedGuild>(guild);
|
|
|
|
|
guildRef.current = guild;
|
|
|
|
|
|
|
|
|
|
const [ value, setValue ] = useState<T[] | null>(null);
|
|
|
|
|
const [ valueGuild, setValueGuild ] = useState<CombinedGuild | null>(null);
|
|
|
|
|
|
|
|
|
|
const [ fetchError, setFetchError ] = useState<unknown | null>(null);
|
|
|
|
|
const [ fetchAboveError, setFetchAboveError ] = useState<unknown | null>(null);
|
|
|
|
@ -376,11 +416,13 @@ function useMultipleGuildSubscriptionScrolling<
|
|
|
|
|
|
|
|
|
|
const fetchAboveCallable = useCallback(async (): Promise<{ hasMoreAbove: boolean, removedFromBottom: boolean }> => {
|
|
|
|
|
if (!isMounted.current) return { hasMoreAbove: false, removedFromBottom: false };
|
|
|
|
|
if (guildRef.current !== guild) return { hasMoreAbove: false, removedFromBottom: false };
|
|
|
|
|
if (!value || value.length === 0) return { hasMoreAbove: false, removedFromBottom: false };
|
|
|
|
|
try {
|
|
|
|
|
const reference = value[0] as T;
|
|
|
|
|
const aboveElements = await fetchAboveFunc(reference);
|
|
|
|
|
if (!isMounted.current) return { hasMoreAbove: false, removedFromBottom: false };
|
|
|
|
|
if (guildRef.current !== guild) return { hasMoreAbove: false, removedFromBottom: false };
|
|
|
|
|
setFetchAboveError(null);
|
|
|
|
|
if (aboveElements) {
|
|
|
|
|
const hasMoreAbove = aboveElements.length >= maxFetchElements;
|
|
|
|
@ -400,18 +442,21 @@ function useMultipleGuildSubscriptionScrolling<
|
|
|
|
|
} catch (e: unknown) {
|
|
|
|
|
LOG.error('error fetching above for subscription', e);
|
|
|
|
|
if (!isMounted.current) return { hasMoreAbove: false, removedFromBottom: false };
|
|
|
|
|
if (guildRef.current !== guild) return { hasMoreAbove: false, removedFromBottom: false };
|
|
|
|
|
setFetchAboveError(e);
|
|
|
|
|
return { hasMoreAbove: true, removedFromBottom: false };
|
|
|
|
|
}
|
|
|
|
|
}, [ value, fetchAboveFunc, maxFetchElements ]);
|
|
|
|
|
}, [ guild, value, fetchAboveFunc, maxFetchElements ]);
|
|
|
|
|
|
|
|
|
|
const fetchBelowCallable = useCallback(async (): Promise<{ hasMoreBelow: boolean, removedFromTop: boolean }> => {
|
|
|
|
|
if (!isMounted.current) return { hasMoreBelow: false, removedFromTop: false };
|
|
|
|
|
if (guildRef.current !== guild) return { hasMoreBelow: false, removedFromTop: false };
|
|
|
|
|
if (!value || value.length === 0) return { hasMoreBelow: false, removedFromTop: false };
|
|
|
|
|
try {
|
|
|
|
|
const reference = value[value.length - 1] as T;
|
|
|
|
|
const belowElements = await fetchBelowFunc(reference);
|
|
|
|
|
if (!isMounted.current) return { hasMoreBelow: false, removedFromTop: false };
|
|
|
|
|
if (guildRef.current !== guild) return { hasMoreBelow: false, removedFromTop: false };
|
|
|
|
|
setFetchBelowError(null);
|
|
|
|
|
if (belowElements) {
|
|
|
|
|
const hasMoreBelow = belowElements.length >= maxFetchElements;
|
|
|
|
@ -431,12 +476,13 @@ function useMultipleGuildSubscriptionScrolling<
|
|
|
|
|
} catch (e: unknown) {
|
|
|
|
|
LOG.error('error fetching below for subscription', e);
|
|
|
|
|
if (!isMounted.current) return { hasMoreBelow: false, removedFromTop: false };
|
|
|
|
|
if (guildRef.current !== guild) return { hasMoreBelow: false, removedFromTop: false };
|
|
|
|
|
setFetchBelowError(e);
|
|
|
|
|
return { hasMoreBelow: true, removedFromTop: false };
|
|
|
|
|
}
|
|
|
|
|
}, [ value, fetchBelowFunc, maxFetchElements ]);
|
|
|
|
|
|
|
|
|
|
const onFetch = useCallback((fetchValue: T[] | null) => {
|
|
|
|
|
const onFetch = useCallback((fetchValue: T[] | null, fetchValueGuild: CombinedGuild) => {
|
|
|
|
|
let hasMoreAbove = false;
|
|
|
|
|
if (fetchValue) {
|
|
|
|
|
if (fetchValue.length >= maxFetchElements) hasMoreAbove = true;
|
|
|
|
@ -444,6 +490,7 @@ function useMultipleGuildSubscriptionScrolling<
|
|
|
|
|
}
|
|
|
|
|
setFetchResult({ hasMoreAbove, hasMoreBelow: false });
|
|
|
|
|
setValue(fetchValue);
|
|
|
|
|
setValueGuild(fetchValueGuild);
|
|
|
|
|
setFetchError(null);
|
|
|
|
|
events.emit('fetch');
|
|
|
|
|
}, [ sortFunc, maxFetchElements, maxElements ]);
|
|
|
|
@ -451,10 +498,11 @@ function useMultipleGuildSubscriptionScrolling<
|
|
|
|
|
const onFetchError = useCallback((e: unknown) => {
|
|
|
|
|
setFetchError(e);
|
|
|
|
|
setValue(null);
|
|
|
|
|
setValueGuild(null);
|
|
|
|
|
events.emit('fetch-error');
|
|
|
|
|
}, []);
|
|
|
|
|
|
|
|
|
|
const onNew = useCallback((newElements: T[]) => {
|
|
|
|
|
const onNew = useCallback((newElements: T[], newElementsGuild: CombinedGuild) => {
|
|
|
|
|
setValue(currentValue => {
|
|
|
|
|
if (currentValue === null) return null;
|
|
|
|
|
let newValue = currentValue.concat(newElements).sort(sortFunc);
|
|
|
|
@ -462,26 +510,35 @@ function useMultipleGuildSubscriptionScrolling<
|
|
|
|
|
newValue = removeByCounts(newValue, getRemoveCounts(newValue.length - maxElements));
|
|
|
|
|
}
|
|
|
|
|
return newValue;
|
|
|
|
|
})
|
|
|
|
|
});
|
|
|
|
|
if (newElementsGuild !== guildRef.current) {
|
|
|
|
|
LOG.warn(`new elements guild (${newElementsGuild.id}) != current guild (${guildRef.current})`);
|
|
|
|
|
}
|
|
|
|
|
events.emit('new', newElements);
|
|
|
|
|
}, [ sortFunc, getRemoveCounts ]);
|
|
|
|
|
const onUpdated = useCallback((updatedElements: T[]) => {
|
|
|
|
|
const onUpdated = useCallback((updatedElements: T[], updatedElementsGuild: CombinedGuild) => {
|
|
|
|
|
setValue(currentValue => {
|
|
|
|
|
if (currentValue === null) return null;
|
|
|
|
|
return currentValue.map(element => updatedElements.find(updatedElement => updatedElement.id === element.id) ?? element).sort(sortFunc);
|
|
|
|
|
});
|
|
|
|
|
if (updatedElementsGuild !== guildRef.current) {
|
|
|
|
|
LOG.warn(`updated elements guild (${updatedElementsGuild.id}) != current guild (${guildRef.current})`);
|
|
|
|
|
}
|
|
|
|
|
events.emit('updated', updatedElements);
|
|
|
|
|
}, [ sortFunc ]);
|
|
|
|
|
const onRemoved = useCallback((removedElements: T[]) => {
|
|
|
|
|
const onRemoved = useCallback((removedElements: T[], removedElementsGuild: CombinedGuild) => {
|
|
|
|
|
setValue(currentValue => {
|
|
|
|
|
if (currentValue === null) return null;
|
|
|
|
|
const deletedIds = new Set(removedElements.map(deletedElement => deletedElement.id));
|
|
|
|
|
return currentValue.filter(element => !deletedIds.has(element.id)).sort(sortFunc);
|
|
|
|
|
});
|
|
|
|
|
if (removedElementsGuild !== guildRef.current) {
|
|
|
|
|
LOG.warn(`updated elements guild (${removedElementsGuild.id}) != current guild (${guildRef.current})`);
|
|
|
|
|
}
|
|
|
|
|
events.emit('removed', removedElements);
|
|
|
|
|
}, [ sortFunc ]);
|
|
|
|
|
|
|
|
|
|
const onConflict = useCallback((changes: Changes<T>) => {
|
|
|
|
|
const onConflict = useCallback((changes: Changes<T>, changesGuild: CombinedGuild) => {
|
|
|
|
|
setValue(currentValue => {
|
|
|
|
|
if (currentValue === null) return null;
|
|
|
|
|
const deletedIds = new Set(changes.deleted.map(deletedElement => deletedElement.id));
|
|
|
|
@ -495,6 +552,9 @@ function useMultipleGuildSubscriptionScrolling<
|
|
|
|
|
}
|
|
|
|
|
return newValue;
|
|
|
|
|
});
|
|
|
|
|
if (changesGuild !== guildRef.current) {
|
|
|
|
|
LOG.warn(`conflict changes guild (${changesGuild.id}) != current guild (${guildRef.current})`);
|
|
|
|
|
}
|
|
|
|
|
events.emit('conflict', changes);
|
|
|
|
|
}, [ sortFunc, getRemoveCounts ]);
|
|
|
|
|
|
|
|
|
@ -502,19 +562,23 @@ function useMultipleGuildSubscriptionScrolling<
|
|
|
|
|
// otherwise, I may have done this wrong. Forcing it to work with these calls
|
|
|
|
|
const boundNewFunc = useCallback((...args: Arguments<Connectable[NE]>): void => {
|
|
|
|
|
if (!isMounted.current) return;
|
|
|
|
|
onNew(newEventArgsMap(...args));
|
|
|
|
|
}, [ onNew, newEventArgsMap ]) as (Connectable & Conflictable)[NE];
|
|
|
|
|
if (guildRef.current !== guild) return; // Cancel calls when the guild changes
|
|
|
|
|
onNew(newEventArgsMap(...args), guild);
|
|
|
|
|
}, [ guild, onNew, newEventArgsMap ]) as (Connectable & Conflictable)[NE];
|
|
|
|
|
const boundUpdateFunc = useCallback((...args: Arguments<Connectable[UE]>): void => {
|
|
|
|
|
if (!isMounted.current) return;
|
|
|
|
|
onUpdated(updatedEventArgsMap(...args));
|
|
|
|
|
if (guildRef.current !== guild) return; // Cancel calls when the guild changes
|
|
|
|
|
onUpdated(updatedEventArgsMap(...args), guild);
|
|
|
|
|
}, [ onUpdated, updatedEventArgsMap ]) as (Connectable & Conflictable)[UE];
|
|
|
|
|
const boundRemovedFunc = useCallback((...args: Arguments<Connectable[RE]>): void => {
|
|
|
|
|
if (!isMounted.current) return;
|
|
|
|
|
onRemoved(removedEventArgsMap(...args));
|
|
|
|
|
if (guildRef.current !== guild) return; // Cancel calls when the guild changes
|
|
|
|
|
onRemoved(removedEventArgsMap(...args), guild);
|
|
|
|
|
}, [ onRemoved, removedEventArgsMap ]) as (Connectable & Conflictable)[RE];
|
|
|
|
|
const boundConflictFunc = useCallback((...args: Arguments<Conflictable[CE]>): void => {
|
|
|
|
|
if (!isMounted.current) return;
|
|
|
|
|
onConflict(conflictEventArgsMap(...args));
|
|
|
|
|
if (guildRef.current !== guild) return; // Cancel calls when the guild changes
|
|
|
|
|
onConflict(conflictEventArgsMap(...args), guild);
|
|
|
|
|
}, [ onConflict, conflictEventArgsMap ]) as (Connectable & Conflictable)[CE];
|
|
|
|
|
|
|
|
|
|
const bindEventsFunc = useCallback(() => {
|
|
|
|
@ -545,6 +609,7 @@ function useMultipleGuildSubscriptionScrolling<
|
|
|
|
|
setScrollRatio,
|
|
|
|
|
fetchResult,
|
|
|
|
|
value,
|
|
|
|
|
valueGuild,
|
|
|
|
|
fetchError,
|
|
|
|
|
fetchAboveError,
|
|
|
|
|
fetchBelowError,
|
|
|
|
@ -579,8 +644,8 @@ export function useResourceSubscription(guild: CombinedGuild, resourceId: string
|
|
|
|
|
}, fetchResourceFunc);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export function useSoftImageSrcResourceSubscription(guild: CombinedGuild, resourceId: string | null): [ imgSrc: string, resource: Resource | null, fetchError: unknown | null ] {
|
|
|
|
|
const [ resource, fetchError ] = useResourceSubscription(guild, resourceId);
|
|
|
|
|
export function useSoftImageSrcResourceSubscription(guild: CombinedGuild, resourceId: string | null): [ imgSrc: string, resource: Resource | null, resourceGuild: CombinedGuild | null, fetchError: unknown | null ] {
|
|
|
|
|
const [ resource, resourceGuild, fetchError ] = useResourceSubscription(guild, resourceId);
|
|
|
|
|
|
|
|
|
|
const [ imgSrc ] = useOneTimeAsyncAction(
|
|
|
|
|
async () => {
|
|
|
|
@ -592,7 +657,7 @@ export function useSoftImageSrcResourceSubscription(guild: CombinedGuild, resour
|
|
|
|
|
[ resource, fetchError ]
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
return [ imgSrc, resource, fetchError ];
|
|
|
|
|
return [ imgSrc, resource, resourceGuild, fetchError ];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export function useChannelsSubscription(guild: CombinedGuild) {
|
|
|
|
@ -629,8 +694,8 @@ export function useMembersSubscription(guild: CombinedGuild) {
|
|
|
|
|
}, fetchMembersFunc);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export function useSelfMemberSubscription(guild: CombinedGuild): [ selfMember: Member | null ] {
|
|
|
|
|
const [ fetchRetryCallable, members, fetchError ] = useMembersSubscription(guild);
|
|
|
|
|
export function useSelfMemberSubscription(guild: CombinedGuild): [ selfMember: Member | null, selfMemberGuild: CombinedGuild | null ] {
|
|
|
|
|
const [ fetchRetryCallable, members, membersGuild, fetchError ] = useMembersSubscription(guild);
|
|
|
|
|
|
|
|
|
|
// TODO: Show an error if we can't fetch and allow retry
|
|
|
|
|
|
|
|
|
@ -646,7 +711,7 @@ export function useSelfMemberSubscription(guild: CombinedGuild): [ selfMember: M
|
|
|
|
|
return null;
|
|
|
|
|
}, [ guild.memberId, members ]);
|
|
|
|
|
|
|
|
|
|
return [ selfMember ];
|
|
|
|
|
return [ selfMember, membersGuild ];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export function useTokensSubscription(guild: CombinedGuild) {
|
|
|
|
|