- /card gains a fourth type: Event. Renders an event (kind 31923) you organise
or RSVP'd going/interested to (useMyRsvpCoords, kind 31925) as a passport/
wristband: title, date/time, venue, cover, who it admits, going count.
Derived from the event's own signed event — its QR verifies that event;
/verify/:naddr renders kind 31923 too. React + canvas renderers; i18n.
- /review gains a dedicated Claims tab (pending private-spot ownership claims),
replacing the banner that sat above the tabs.
Audited the RSVP / event-update notification flow end to end. The data
layer was already solid and secure — RSVPs p-tag the host, updates
p-tag every RSVPer, and useActivityNotifications guards event-update
spoofing by requiring the author to be the event's host (from the `a`
coordinate) or an admin. The gap was on the rendering side.
Fixes:
- ActivityNotificationCard hardwired every notification to link to the
ACTOR's profile. For an RSVP ("Alice is going to your event") the host
wants the event + attendee list, and for an event update ("moved to
Sunday") the attendee wants to READ the update — not visit a profile.
Both events carry the event's `a` coordinate (31923:pubkey:identifier),
so these two types now route to /event/:pubkey/:identifier. Everything
else still lands on the actor's profile. d-tags containing ':' are
reconstructed correctly.
- useRsvp only invalidated the single-event RSVP query, so the grid /
calendar "going" counts lagged behind by up to the 30s staleTime after
RSVPing. Now also invalidates the batch-event-rsvps query so counts
update promptly.
- Social-tab empty-state copy omitted RSVPs and host updates even though
they land there; made it honest.
Co-authored-by: shakespeare.diy <assistant@shakespeare.diy>
UX (all participants):
- EventCard now shows a live status pill (In 2 days / HAPPENING NOW / ENDED) on
both the full and compact variants — the at-a-glance signal was previously
detail-page only
- EventCard shows a "Presented by <sponsor>" ribbon so paid sponsor placements
get real visibility in the discovery feed (not just after a click)
- Added a bottom legibility gradient so overlays stay readable on any cover
FIX (crash risk): EventsPage getTrustScore did `trustScores?.map.get` — since
useBatchTrustScores returns a plain Map (no `.map`), this threw TypeError once
scores loaded. Now reads the Map directly.
PERF (N+1 query storm): rendering the grid fired one RSVP query PER card
(~100 queries on a full page). Added useBatchEventRsvps — a single #a-filtered
query for all event coordinates — and thread goingCount into EventCard as a prop.
Cards without the prop (detail page, hosting dashboard) keep their own query.
Removed now-dead getRelativeTime/relativeTime/isUpcoming (superseded by the
EventCountdown pill).
Co-authored-by: shakespeare.diy <assistant@shakespeare.diy>
- FIX: EventCountdown label never updated (memo ignored the interval tick) — now recomputes every 30s for both EventCountdown and useEventStatus
- Add loud cancelled / rescheduled banner on EventDetailPage derived from host updates; close RSVP + dim hero when cancelled so attendees don't show up to a dead jam
- Clean up non-standard NIP-52 `a` tags (['a', coord, '', ''] → ['a', coord]) in RSVP and host-update publishing
- Correct misleading kind comment in useEventRsvps
Co-authored-by: shakespeare.diy <assistant@shakespeare.diy>