This commit is contained in:
Shusui MOYATANI
2023-06-03 20:44:22 +09:00
parent 26700c0cae
commit 5db35d7028
33 changed files with 1227 additions and 717 deletions

View File

@@ -1,3 +1,85 @@
import { useReactions } from '@/nostr/useBatchedEvents';
import { createMemo, observable } from 'solid-js';
import { createQuery, useQueryClient, type CreateQueryResult } from '@tanstack/solid-query';
import { Event as NostrEvent } from 'nostr-tools';
import { exec } from '@/nostr/useBatchedEvents';
import timeout from '@/utils/timeout';
export type UseReactionsProps = {
eventId: string;
};
export type UseReactions = {
reactions: () => NostrEvent[];
reactionsGroupedByContent: () => Map<string, NostrEvent[]>;
isReactedBy: (pubkey: string) => boolean;
isReactedByWithEmoji: (pubkey: string) => boolean;
invalidateReactions: () => Promise<void>;
query: CreateQueryResult<NostrEvent[]>;
};
const EmojiRegex = /\p{Emoji_Presentation}/u;
const useReactions = (propsProvider: () => UseReactionsProps | null): UseReactions => {
const queryClient = useQueryClient();
const props = createMemo(propsProvider);
const genQueryKey = createMemo(() => ['useReactions', props()] as const);
const query = createQuery(
genQueryKey,
({ queryKey, signal }) => {
const [, currentProps] = queryKey;
if (currentProps == null) return [];
const { eventId: mentionedEventId } = currentProps;
const promise = exec({ type: 'Reactions', mentionedEventId }, signal).then(
(batchedEvents) => {
const events = () => batchedEvents().events;
observable(batchedEvents).subscribe(() => {
queryClient.setQueryData(queryKey, events());
});
return events();
},
);
return timeout(15000, `useReactions: ${mentionedEventId}`)(promise);
},
{
staleTime: 1 * 60 * 1000, // 1 min
cacheTime: 4 * 60 * 60 * 1000, // 4 hour
refetchInterval: 1 * 60 * 1000, // 1 min
},
);
const reactions = () => query.data ?? [];
const reactionsGroupedByContent = () => {
const result = new Map<string, NostrEvent[]>();
reactions().forEach((event) => {
const events = result.get(event.content) ?? [];
events.push(event);
result.set(event.content, events);
});
return result;
};
const isReactedBy = (pubkey: string): boolean =>
reactions().findIndex((event) => event.pubkey === pubkey) !== -1;
const isReactedByWithEmoji = (pubkey: string): boolean =>
reactions().findIndex((event) => event.pubkey === pubkey && EmojiRegex.test(event.content)) !==
-1;
const invalidateReactions = (): Promise<void> => queryClient.invalidateQueries(genQueryKey());
return {
reactions,
reactionsGroupedByContent,
isReactedBy,
isReactedByWithEmoji,
invalidateReactions,
query,
};
};
export default useReactions;