diff --git a/js/app.js b/js/app.js index 73dff5fa..8fa09e81 100644 --- a/js/app.js +++ b/js/app.js @@ -6465,7 +6465,8 @@ class bitvidApp { const nextActivePubkey = normalizedPubkey || (typeof pubkey === "string" ? pubkey.trim() : ""); - if (previousActivePubkey !== nextActivePubkey) { + const identityChanged = previousActivePubkey !== nextActivePubkey; + if (identityChanged) { this.resetViewLoggingState(); } @@ -6476,6 +6477,21 @@ class bitvidApp { } this.currentUserNpub = this.safeEncodeNpub(this.pubkey); + if ( + identityChanged && + typeof window !== "undefined" && + typeof window.dispatchEvent === "function" + ) { + window.dispatchEvent( + new CustomEvent("bitvid:auth-changed", { + detail: { + pubkey: nextActivePubkey || null, + previousPubkey: previousActivePubkey || null, + }, + }) + ); + } + let savedProfilesMutated = false; if (normalizedPubkey) { const cacheEntry = this.profileCache.get(normalizedPubkey); @@ -6537,10 +6553,28 @@ class bitvidApp { */ async logout() { nostrClient.logout(); + const previousPubkey = + this.normalizeHexPubkey(this.pubkey) || + (typeof this.pubkey === "string" ? this.pubkey.trim() : ""); this.resetViewLoggingState(); this.pubkey = null; this.currentUserNpub = null; + if ( + previousPubkey && + typeof window !== "undefined" && + typeof window.dispatchEvent === "function" + ) { + window.dispatchEvent( + new CustomEvent("bitvid:auth-changed", { + detail: { + pubkey: null, + previousPubkey, + }, + }) + ); + } + this.persistActiveProfileSelection(null, { persist: true }); userBlocks.reset(); diff --git a/js/historyView.js b/js/historyView.js index 13fa4ff5..4c306b39 100644 --- a/js/historyView.js +++ b/js/historyView.js @@ -484,6 +484,48 @@ export function createWatchHistoryRenderer(config = {}) { const providedBeforeInitialLoad = mergedConfig.beforeInitialLoad; const providedGetSnapshotFingerprint = mergedConfig.getSnapshotFingerprint; + let authChangeListener = null; + let authRefreshPromise = null; + let scheduleAuthRefresh = null; + + const normalizeActorHint = (actorHint) => { + if (typeof actorHint === "string") { + const trimmed = actorHint.trim(); + if (trimmed) { + return trimmed; + } + } + return null; + }; + + const attachAuthChangeListener = () => { + if (authChangeListener || typeof window === "undefined") { + return; + } + + authChangeListener = (event) => { + const detail = event?.detail || {}; + const actorHint = + typeof detail.pubkey === "string" ? detail.pubkey : null; + try { + scheduleAuthRefresh?.(actorHint ?? null); + } catch (error) { + console.warn("[historyView] Failed to schedule auth refresh:", error); + } + }; + + window.addEventListener("bitvid:auth-changed", authChangeListener); + }; + + const detachAuthChangeListener = () => { + if (!authChangeListener || typeof window === "undefined") { + return; + } + + window.removeEventListener("bitvid:auth-changed", authChangeListener); + authChangeListener = null; + }; + const selectors = { view: viewSelector, grid: gridSelector, @@ -1106,6 +1148,51 @@ export function createWatchHistoryRenderer(config = {}) { }); }; + scheduleAuthRefresh = (actorHint) => { + const normalizedActor = normalizeActorHint(actorHint); + + const perform = async () => { + const nextActor = normalizedActor || null; + + try { + const { view } = getElements(); + if (!view) { + state.actor = nextActor; + state.snapshotFingerprint = null; + state.initialized = false; + state.resolvedVideos = []; + state.hasMore = true; + state.isLoading = false; + cleanupObservers(); + return; + } + + await runInitialLoad({ actor: nextActor }); + } catch (error) { + console.error( + "[historyView] Failed to refresh watch history after auth change:", + error + ); + } + }; + + const pendingRefresh = + authRefreshPromise !== null + ? authRefreshPromise.then(perform, perform) + : perform(); + + let currentPromise; + const finalize = () => { + if (authRefreshPromise === currentPromise) { + authRefreshPromise = null; + } + }; + + currentPromise = pendingRefresh.finally(finalize); + authRefreshPromise = currentPromise; + return currentPromise; + }; + const runInitialLoad = async (options = {}) => { const { actor: actorHint = null, prefetched = null, fingerprintOverride } = typeof options === "object" && options !== null ? options : {}; @@ -1204,6 +1291,8 @@ export function createWatchHistoryRenderer(config = {}) { }); }; + attachAuthChangeListener(); + return { async init() { debugLog("init called"); @@ -1313,6 +1402,7 @@ export function createWatchHistoryRenderer(config = {}) { debugLog("destroy called"); cleanupObservers(); cleanupGridHandler(); + detachAuthChangeListener(); state.initialized = false; state.resolvedVideos = []; state.hasMore = true; @@ -1322,6 +1412,9 @@ export function createWatchHistoryRenderer(config = {}) { resetUiState(); setLoadingVisible(false); }, + async refresh(actorHint = null) { + await scheduleAuthRefresh(actorHint); + }, render() { renderResolvedVideos(); }, @@ -1340,7 +1433,10 @@ export async function initHistoryView() { await watchHistoryRenderer.init(); } -if (!window.bitvid) { - window.bitvid = {}; +if (typeof window !== "undefined") { + if (!window.bitvid) { + window.bitvid = {}; + } + window.bitvid.initHistoryView = initHistoryView; + window.bitvid.watchHistoryRenderer = watchHistoryRenderer; } -window.bitvid.initHistoryView = initHistoryView;