fix(events): keep event detail's ticket counts live (subscribe even when cached)

useEventDetail.load() early-returned when the event was already in the
store, so arriving from the feed (cached) set up no live subscription.
NIP-52 calendar events are replaceable and the events extension
republishes them when a ticket sells (updating tickets_sold/available),
but with no subscription the detail page never received the update —
counts went stale until a manual reload.

Always open the dTag-scoped subscription (only the one-shot query +
loading state are skipped on a cache hit), and unsubscribe a prior sub
before re-subscribing so reload() can't leak one. The reactive `event`
computed then reflects republished counts without a reload.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Padreug 2026-06-17 19:16:19 +02:00
commit dce55f0c0c

View file

@ -19,19 +19,12 @@ export function useEventDetail(eventId: string) {
)
async function load() {
// Already in cache
if (event.value) return
const nostrService = tryInjectService<EventsNostrService>(SERVICE_TOKENS.EVENTS_NOSTR_SERVICE)
if (!nostrService) {
error.value = 'Events service not available'
return
}
try {
isLoading.value = true
error.value = null
// Scope both the subscription and the one-shot query to this
// event's d-tag. Without this scope, the query asks every
// relay for every kind-31922/31923 event and races a 5s timeout
@ -39,6 +32,15 @@ export function useEventDetail(eventId: string) {
// even when the event is reachable.
const detailFilters = { dTags: [eventId] }
// Subscribe for LIVE updates regardless of cache state. NIP-52
// calendar events are replaceable, so when the events extension
// republishes after a ticket sells (updating tickets_sold /
// tickets_available — see events services.py), the new version
// arrives here and the reactive `event` (and its ticket counts)
// updates without a reload. Subscribing only on a cache miss meant
// arriving from the feed (event already cached) left the detail
// page with no live subscription, so counts went stale until reload.
if (unsubscribe) unsubscribe() // avoid leaking a sub if load() re-runs
unsubscribe = nostrService.subscribeToCalendarEvents(
(incoming) => {
store.upsertEvent(incoming)
@ -49,6 +51,14 @@ export function useEventDetail(eventId: string) {
detailFilters
)
// Already cached — the subscription above keeps it fresh; skip the
// one-shot query + loading state.
if (event.value) return
try {
isLoading.value = true
error.value = null
const results = await nostrService.queryCalendarEvents(detailFilters)
store.upsertEvents(results)