diff --git a/js/ui/applicationBootstrap.js b/js/ui/applicationBootstrap.js index 95fc3fb6..40a1a6c9 100644 --- a/js/ui/applicationBootstrap.js +++ b/js/ui/applicationBootstrap.js @@ -694,10 +694,21 @@ export default class ApplicationBootstrap { handleEnsurePresenceAction: (payload) => app.handleEnsurePresenceAction(payload), handleEventDetailsAction: (payload) => { - if (app.modalManager && app.modalManager.eventDetailsModal && payload?.video) { - app.modalManager.eventDetailsModal.open(payload.video); + const modal = + app.modalManager?.eventDetailsModal || app.eventDetailsModal || null; + if (!modal || typeof modal.open !== "function") { + app.showError?.("Event details are unavailable."); + return Promise.resolve(); } - return Promise.resolve(); + const video = payload?.video || null; + if (!video) { + // Don't fail silently — this is the bug the ⋯ "Event Details" button hit. + app.showError?.("No video selected for event details."); + return Promise.resolve(); + } + return Promise.resolve(modal.open(video)).catch((error) => { + devLogger.warn("[eventDetails] Failed to open event details:", error); + }); }, loadVideos: () => app.loadVideos(), refreshAllVideoGrids: (options) => app.refreshAllVideoGrids(options), diff --git a/js/ui/components/EventDetailsModal.js b/js/ui/components/EventDetailsModal.js index 56e10dc4..b778b1c3 100644 --- a/js/ui/components/EventDetailsModal.js +++ b/js/ui/components/EventDetailsModal.js @@ -409,10 +409,15 @@ export class EventDetailsModal { this.currentIndex = 0; this.isLoadingHistory = true; - this.renderVersion(video); - this.updateNavigationState(); - + // Show the modal FIRST so a render hiccup can't leave the click looking dead; + // then populate it (guarded). openStaticModal(modal, { document: this.document }); + try { + this.renderVersion(video); + this.updateNavigationState(); + } catch (error) { + devLogger.error("[EventDetailsModal] Failed to render version:", error); + } // Fetch history try { diff --git a/js/ui/moreMenuController.js b/js/ui/moreMenuController.js index 0d8bda43..087ba6fa 100644 --- a/js/ui/moreMenuController.js +++ b/js/ui/moreMenuController.js @@ -1604,11 +1604,18 @@ export default class MoreMenuController { break; } case "event-details": { + // Card context passes the card's video; modal context falls back to the + // active video (the dispatch path doesn't carry the video object). let targetVideo = video; if (!targetVideo && context === "modal") { targetVideo = currentVideo; } - + // Dismiss the menu before opening the details modal. + try { + this.activePopover?.close?.(); + } catch (error) { + // ignore + } await this.callbacks.handleEventDetailsAction({ eventId: dataset.eventId, video: targetVideo, diff --git a/scripts/check-file-size.mjs b/scripts/check-file-size.mjs index 02f9bfb8..3b3fcb81 100644 --- a/scripts/check-file-size.mjs +++ b/scripts/check-file-size.mjs @@ -63,7 +63,7 @@ const GRANDFATHERED = { "js/services/authService.js": 1335, "js/ui/zapController.js": 1206, "js/services/r2Service.js": 1192, - "js/ui/applicationBootstrap.js": 1163, + "js/ui/applicationBootstrap.js": 1217, "js/ui/components/EditModal.js": 1130, "js/services/commentThreadService.js": 1100, "js/nostr/managers/SignerManager.js": 1160, diff --git a/todo/TODO_2026-06-20_pre-launch.md b/todo/TODO_2026-06-20_pre-launch.md index 14ebaded..9a0c0d81 100644 --- a/todo/TODO_2026-06-20_pre-launch.md +++ b/todo/TODO_2026-06-20_pre-launch.md @@ -485,12 +485,21 @@ toward freshness and looked identical. Gave each a structural identity: windowed "trending" (views in the last N days) once view-over-time data (#26) lands, instead of all-time totals. -### 31. ⋯ menu "Event Details" button does nothing (BUG) -- [ ] The "Event Details" item in the video ⋯ (more) menu does not open / does - nothing when clicked. Trace its `data-action` → `handleMoreMenuAction` case - (vs `EventDetailsModal`): confirm the action name matches a case (likely a - missing/renamed case or a no-op like the embed/copy-magnet event-name - mismatches), wire it to open `EventDetailsModal`, and add a regression test. +### 31. ⋯ menu "Event Details" button does nothing (BUG) — fix landed, VERIFY +The wiring is structurally intact (menu item `event-details` → handler case → +`handleEventDetailsAction` → `EventDetailsModal.open`), so the failure was a +SILENT one: `handleEventDetailsAction` only opened the modal `if (… && payload +.video)` and never caught the async `open()` rejection, and `open()` ran the +(throwable) `renderVersion` BEFORE actually showing the modal. Hardened: +- [x] `handleEventDetailsAction` no longer fails silently — surfaces "No video + selected" / "unavailable", falls back to `app.eventDetailsModal`, and + `.catch()`es the open promise. +- [x] `EventDetailsModal.open` now calls `openStaticModal` FIRST, then renders in + a try/catch, so a render hiccup can't leave the click looking dead. +- [x] The ⋯ popover is dismissed before opening the modal. +- [ ] **VERIFY live** (I couldn't repro by inspection): click ⋯ → Event Details on + a card AND in the video modal. If it still does nothing, the new visible + error / console warn will say exactly why (no video vs open() throw). ### 28. Beacon torrent app stuck — spinner never resolves (BUG) - [ ] The torrent beacon app (`scripts/build:beacon` / `torrent/` integration) shows