Completes the safety loop. useMuteList reads the viewer's kind-10000 mute list plus optimistic local mutes (lib/localMutes.ts); useMuteUser republishes the list with the target added, records it locally and invalidates content queries. useAdminModeration carries a new mutedPubkeys set, and the shared filterAdminHidden/filterAdminHiddenMixed drop muted authors — so every list hook filters them with no per-hook changes (admin tooling with includeHidden still sees them). The flagged notice gains a Mute action.
39 lines
1.2 KiB
TypeScript
39 lines
1.2 KiB
TypeScript
import { useQuery } from '@tanstack/react-query';
|
|
import { useNostr } from '@nostrify/react';
|
|
|
|
import { useCurrentUser } from './useCurrentUser';
|
|
import { onlyVerified } from '@/lib/verifyEvents';
|
|
import { getLocalMutes } from '@/lib/localMutes';
|
|
|
|
/** NIP-51 mute list. */
|
|
export const MUTE_LIST_KIND = 10000;
|
|
|
|
/**
|
|
* The viewer's muted pubkeys: their kind-10000 list plus any optimistic mutes
|
|
* made on this device. Returns an empty set when logged out.
|
|
*/
|
|
export function useMuteList() {
|
|
const { nostr } = useNostr();
|
|
const { user } = useCurrentUser();
|
|
const pubkey = user?.pubkey;
|
|
|
|
return useQuery({
|
|
queryKey: ['mute-list', pubkey],
|
|
enabled: !!pubkey,
|
|
staleTime: 5 * 60 * 1000,
|
|
queryFn: async (c): Promise<Set<string>> => {
|
|
const set = getLocalMutes();
|
|
if (!pubkey) return set;
|
|
|
|
const signal = AbortSignal.any([c.signal, AbortSignal.timeout(8000)]);
|
|
const events = onlyVerified(await nostr.query(
|
|
[{ kinds: [MUTE_LIST_KIND], authors: [pubkey], limit: 1 }],
|
|
{ signal },
|
|
));
|
|
for (const tag of events[0]?.tags ?? []) {
|
|
if (tag[0] === 'p' && tag[1]) set.add(tag[1]);
|
|
}
|
|
return set;
|
|
},
|
|
});
|
|
}
|