Files
eranos/src/lib/invalidateEventStats.ts
T
mkfain df5c08ef27 Fix query invalidation gaps so UI updates without page refresh
Several mutations published Nostr events but invalidated cache keys that
no live query subscribed to, leaving the UI showing stale counts and
missing entries until the user manually refreshed.

* Campaign donations: useDonateCampaign and CampaignDetailPage invalidated
  ['campaign-donations', aTag], but useCampaignDonations subscribes to
  ['campaign-donations', 'events', aTag]. Use the correct key, cascade to
  organization-activity / campaigns lists, and broaden via prefix sweep.

* Reactions / reposts / quotes: ReactionButton, RepostMenu, QuickReactMenu,
  ComposeBox quote path, VinesFeedPage and ListDetailPage all wrote to
  ['event-stats', id], which no query reads. Counts are served by
  useNip85EventStats / useNip85AddrStats at ['nip85-event-stats', id,
  statsPubkey] and ['nip85-addr-stats', addr, statsPubkey]. Route
  optimistic writes and invalidations through a new invalidateEventStats
  helper that handles both the regular and addressable variants.

* Top-level posts on country pages: ComposeBox's createEvent path
  invalidated ['feed'], but country pages subscribe to
  ['agora-feed-paginated', countryCode, ...] and
  ['agora-feed-new-posts', countryCode, ...]. Add the country-feed
  invalidations to the kind 1, voice, and poll handlers — matching the
  pattern usePostComment already uses for kind 1111 comments.

* Follow All inline reimplementations: FollowPage's FollowPackView,
  TeamSoapboxCard, and FollowPackDetailContent published kind 3 events
  inline with no invalidation, so follow buttons and the user's feed
  stayed unchanged. Replace each with useFollowActions.followMany, which
  already invalidates ['follow-list'], ['feed'], and ['following-feed'].
2026-05-22 15:03:30 -05:00

48 lines
2.0 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import type { QueryClient } from '@tanstack/react-query';
import type { NostrEvent } from '@nostrify/nostrify';
/**
* Invalidate the NIP-85 stats queries for a given event so that
* reaction / repost / comment / zap counts update in the UI after the
* user performs an action against it.
*
* Handles both regular events (`['nip85-event-stats', eventId, statsPubkey]`)
* and addressable events (`['nip85-addr-stats', '<kind>:<pubkey>:<d>', statsPubkey]`).
*
* Pass `statsPubkey` from `useAppContext().config.nip85StatsPubkey`. When the
* configured pubkey isn't known, the function still issues a prefix-match
* invalidation so any cached entry refreshes.
*
* `eventOrId` accepts either a hex event id (regular event) or a full
* `NostrEvent`. Passing the event allows us to detect addressable kinds
* (1000019999, 3000039999) and invalidate the matching `nip85-addr-stats`
* key too.
*/
export function invalidateEventStats(
queryClient: QueryClient,
eventOrId: NostrEvent | string,
statsPubkey?: string,
): void {
if (typeof eventOrId === 'string') {
queryClient.invalidateQueries({ queryKey: ['nip85-event-stats', eventOrId, statsPubkey] });
// Also a prefix sweep, in case statsPubkey was undefined when the cache
// entry was created (e.g. early load before config hydration).
queryClient.invalidateQueries({ queryKey: ['nip85-event-stats', eventOrId] });
return;
}
const event = eventOrId;
queryClient.invalidateQueries({ queryKey: ['nip85-event-stats', event.id, statsPubkey] });
queryClient.invalidateQueries({ queryKey: ['nip85-event-stats', event.id] });
const isAddressable =
(event.kind >= 30000 && event.kind < 40000) ||
(event.kind >= 10000 && event.kind < 20000);
if (isAddressable) {
const d = event.tags.find(([n]) => n === 'd')?.[1] ?? '';
const addr = `${event.kind}:${event.pubkey}:${d}`;
queryClient.invalidateQueries({ queryKey: ['nip85-addr-stats', addr, statsPubkey] });
queryClient.invalidateQueries({ queryKey: ['nip85-addr-stats', addr] });
}
}