Commit Graph

4 Commits

Author SHA1 Message Date
mkfain 7f7db43910 Broaden deletion + moderation invalidation to refresh every feed surface
Phase 3 of the invalidation cleanup.

* useDeleteEvent previously invalidated only ['feed'], ['profile-feed'],
  ['profile-likes-infinite'], ['replies'], and ['notifications']. A
  deleted event can sit in many other surfaces — country feeds
  (agora-feed-paginated / agora-feed-new-posts), comment threads
  (['nostr', 'comments', ...], ['event-comments', ...], wall-comments),
  campaign and pledge lists, community / organization activity feeds,
  trending, and per-event caches. Switch to a predicate that sweeps a
  curated allow-list of feed-shaped query-key prefixes so the deleted
  post drops off every visible surface in a single refetch wave.

* useCampaignModeration only invalidated its own ['campaign-moderation']
  cache. Moderation labels (approve / hide / feature) gate which
  campaigns surface on the home page, discover shelf, and community
  grids, so the list queries need refetching too. Cascade to
  ['campaigns'], ['campaigns-all'], and ['campaigns-all-scores'].

ReportDialog (kind 1984) and useRequestToVanish (kind 62) were reviewed
and intentionally left alone: ReportDialog has no UI consequence inside
Agora (reports only show up to external moderators), and Request to
Vanish logs the user out, after which any cached state is cleared
anyway.
2026-05-22 15:53:15 -05:00
mkfain 9fd585ebdd Moderator-curated featured organizations
Replace the hardcoded FEATURED_ORGANIZATION_AUTHORS allowlist with the
same NIP-32 label flow that curates featured campaigns: Team Soapbox
pack members publish kind 1985 labels in the agora.moderation namespace
tagging an organization's 34550:<pubkey>:<d> coordinate as featured,
hidden, or approved, and useFeaturedOrganizations folds those labels
into the /communities Featured shelf.

The campaign and organization label streams share a single namespace
and a single moderator pack — they're separated purely by which kind
prefix the 'a' tag carries. To keep that contract enforced in one
place, the constants, types, and folding logic are now in
src/lib/agoraModeration.ts; useCampaignModeration and the new
useOrganizationModeration both call foldModerationLabels with their
respective kind. The campaign hook's external surface
(AGORA_MODERATION_NAMESPACE, ModerationLabel, CampaignModerationData)
is preserved via re-exports so existing call sites don't move.

Moderators see a CommunityModerationMenu kebab overlaid on every
CommunityMiniCard exposing approve/unapprove, hide/unhide, and
feature/unfeature. Mounting reads moderation state once per page from
the shared TanStack cache, mirroring CampaignCard. Non-moderators see
no overlay (the menu returns null) and no card affordances change.

The 'My organizations' shelf intentionally ignores moderation — a
user's own founded, moderated, or followed organizations always render
regardless of label state. Only the Featured shelf consumes the
curation rollup.

The Featured grid is uncapped: moderators control how many orgs
surface by labeling, and ordering follows the recency of each
'featured' label so re-publishing bumps an org to the top.

NIP.md's 'Campaign Moderation Labels' section is renamed to 'Agora
Moderation Labels' and documents the kind-34550 coord form and the
'My organizations ignores moderation' rule.

Note: existing surfaced organizations will disappear from the shelf
until a moderator publishes featured labels for them.
2026-05-21 21:12:33 -05:00
mkfain 09bd4096e2 Make Featured a moderation axis and add an All Campaigns page
Featured was a hardcoded array of naddrs in src/lib/featuredCampaigns.ts.
Promote it to a third moderation axis (`featured` / `unfeatured`)
alongside `approved` and `hidden`, managed by Team Soapbox pack members
through the same kebab menu on each campaign card.

The Featured row on the homepage now:
- Reads from `moderation.featuredCoords`, ordered newest-featured-label first.
- Caps at 4 campaigns.
- Adapts its grid to 1/2/3/4 desktop columns based on count (mobile stays
  one column), collapses when nothing is featured, and surfaces the hero
  `variant="featured"` card only when exactly one campaign is featured.
- Hide still wins: a featured-then-hidden campaign disappears from the row.

Rename the homepage's second section from "All campaigns" to "Community
Campaigns", which more accurately reflects that it's the approved-not-
hidden set with featured campaigns deduplicated out.

Add a new /campaigns/all page that lists every campaign found on relays
(approved, pending, and unmoderated alike), with a "Show hidden" toggle
that adds hidden campaigns back in. The Discover page's "All campaigns"
link now points here instead of /, since the homepage is no longer a
truly-all view post-moderation. Also surface a small "Browse all
campaigns" link beneath the Community Campaigns grid so the new page is
discoverable from home.

Update NIP.md to document the third axis and the home-page surfacing
rules (Featured row, Community Campaigns grid, Discover shelf).

Delete src/lib/featuredCampaigns.ts entirely — there's no longer a build-
time list to maintain.
2026-05-19 18:04:28 -05:00
Chad Curtis d065580e47 Curate the campaigns homepage with Team Soapbox labels
Move campaign curation from a hardcoded HIDDEN_CAMPAIGN_COORDS set to a
real moderation system. Team Soapbox (kind 39089 follow pack
k4p5w0n22suf) is the moderator roster; each member signs NIP-32 kind
1985 labels in the agora.moderation namespace to approve or hide a
campaign. The home page and Discore shelf render the approved-and-
not-hidden set; moderators additionally see Pending + Hidden sections
and a per-card kebab menu. Non-moderator authors get a Your Campaigns
section explaining their campaign is live on Nostr but awaiting a
homepage approval.
2026-05-19 16:14:45 -05:00