SkateSpots/src/hooks/useMuteList.ts
SkateSpots e66888128f feat(trust): a real mute (NIP-51 kind 10000) that hides content
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.
2026-10-09 18:23:04 +07:00

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;
},
});
}