Improve zap popover toggling and logout handling

This commit is contained in:
thePR0M3TH3AN committed 2025-10-18 14:51:51 -04:00
1 parent d7b0faffa2
commit 19957d398f
4 files changed
+178 -17

No files matched your search

+77
View File
@@ -1338,6 +1338,21 @@ class Application {
}
}
dispatchAuthChange(detail = {}) {
if (typeof window === "undefined" || typeof window.dispatchEvent !== "function") {
return false;
}
try {
const payload = { ...(typeof detail === "object" && detail ? detail : {}) };
window.dispatchEvent(new CustomEvent("bitvid:auth-changed", { detail: payload }));
return true;
} catch (error) {
devLogger.warn("[Application] Failed to dispatch auth change event:", error);
return false;
}
}
normalizeModalTrigger(candidate) {
if (!candidate) {
return null;
@@ -3107,6 +3122,23 @@ class Application {
identityChanged: Boolean(detail?.identityChanged),
};
if (this.zapController) {
try {
this.zapController.setVisibility(
Boolean(this.currentVideo?.lightningAddress),
);
} catch (error) {
devLogger.warn("[Application] Failed to refresh zap visibility after login:", error);
}
}
this.dispatchAuthChange({
status: "login",
loggedIn: true,
pubkey: loginContext.pubkey || null,
previousPubkey: loginContext.previousPubkey || null,
});
const nwcPromise = Promise.resolve()
.then(() => this.nwcSettingsService.onLogin(loginContext))
.catch((error) => {
@@ -3198,6 +3230,51 @@ class Application {
this.applyLoggedOutUiState();
if (this.videoModal?.closeZapDialog) {
try {
this.videoModal.closeZapDialog({ silent: true, restoreFocus: false });
} catch (error) {
devLogger.warn("Failed to close zap dialog during logout:", error);
}
}
if (this.zapController) {
try {
this.zapController.resetState();
this.zapController.setVisibility(Boolean(this.currentVideo?.lightningAddress));
} catch (error) {
devLogger.warn("Failed to reset zap controller during logout:", error);
}
}
if (typeof this.nostrService?.clearVideoSubscription === "function") {
try {
this.nostrService.clearVideoSubscription();
} catch (error) {
devLogger.warn("Failed to clear video subscription during logout:", error);
}
}
if (typeof this.nostrService?.resetVideosCache === "function") {
try {
this.nostrService.resetVideosCache();
} catch (error) {
devLogger.warn("Failed to reset cached videos during logout:", error);
}
}
await this.renderVideoList({
videos: [],
metadata: { reason: "auth:logout" },
});
this.dispatchAuthChange({
status: "logout",
loggedIn: false,
pubkey: detail?.pubkey || null,
previousPubkey: detail?.previousPubkey || null,
});
try {
await this.loadVideos(true);
} catch (error) {
+45
View File
@@ -3745,6 +3745,51 @@ window.addEventListener("bitvid:access-control-updated", () => {
});
});
window.addEventListener("bitvid:auth-changed", (event) => {
const hashParams = new URLSearchParams(window.location.hash.slice(1));
if (hashParams.get("view") !== "channel-profile") {
return;
}
if (!currentChannelHex) {
return;
}
const activeNpub = hashParams.get("npub");
if (currentChannelNpub && activeNpub && activeNpub !== currentChannelNpub) {
return;
}
setChannelZapVisibility(Boolean(currentChannelLightningAddress));
syncChannelShareButtonState();
const detail = event?.detail;
if (!detail || typeof detail !== "object") {
return;
}
if (detail.status === "logout") {
zapInFlight = false;
zapPopoverOpenPromise = null;
zapShouldFocusOnOpen = false;
resetZapRetryState();
setZapStatus("", "neutral");
clearZapReceipts();
const amountInput = getZapAmountInput();
if (amountInput) {
amountInput.value = "";
}
return;
}
if (detail.status === "login") {
zapInFlight = false;
resetZapRetryState();
setZapStatus("", "neutral");
return;
}
});
/**
* Keep only the newest version of each video root.
*/
+7
View File
@@ -218,6 +218,13 @@ export class NostrService {
this.emit("videos:cache", { size: map.size });
}
resetVideosCache() {
const map = new Map();
this.videosMap = map;
setStoredVideosMap(map);
this.emit("videos:cache", { size: 0 });
}
shouldIncludeVideo(video, {
blacklistedEventIds = new Set(),
isAuthorBlocked = () => false,
+49 -17
View File
@@ -79,6 +79,8 @@ export class VideoModal {
this.modalZapPending = false;
this.modalZapRequiresLogin = false;
this.modalZapPopover = null;
this.modalZapOpenPromise = null;
this.modalZapPendingToggle = null;
this.modalMorePopover = null;
this.modalMoreMenuPanel = null;
@@ -238,6 +240,8 @@ export class VideoModal {
this.modalMorePopover.destroy();
}
this.modalZapPopover = null;
this.modalZapOpenPromise = null;
this.modalZapPendingToggle = null;
this.modalMorePopover = null;
this.modalMoreMenuPanel = null;
@@ -428,6 +432,11 @@ export class VideoModal {
? this.modalZapPopover.isOpen()
: this.modalZapDialogOpen === true;
if (this.modalZapOpenPromise) {
this.modalZapPendingToggle = "close";
return;
}
if (popoverIsOpen) {
if (this.modalZapPending) {
return;
@@ -437,6 +446,7 @@ export class VideoModal {
return;
}
this.modalZapPendingToggle = null;
this.openZapDialog();
this.dispatch("zap:open", { video: this.activeVideo });
});
@@ -587,6 +597,8 @@ export class VideoModal {
const wasOpen = popover.isOpen?.() === true;
const result = originalClose(rest);
if (wasOpen && result) {
this.modalZapPendingToggle = null;
this.modalZapOpenPromise = null;
this.modalZapDialog.dataset.state = "closed";
this.modalZapDialog.setAttribute("aria-hidden", "true");
this.modalZapDialog.hidden = true;
@@ -1042,8 +1054,12 @@ export class VideoModal {
}
async openZapDialog() {
if (this.modalZapPopover?.open) {
try {
if (this.modalZapOpenPromise) {
return this.modalZapOpenPromise;
}
const runOpen = async () => {
if (this.modalZapPopover?.open) {
const opened = await this.modalZapPopover.open();
if (opened) {
this.modalZapDialogOpen = true;
@@ -1054,27 +1070,43 @@ export class VideoModal {
}
this.focusZapAmount();
}
return;
} catch (error) {
this.log("[VideoModal] Failed to open zap popover", error);
return opened;
}
}
if (!this.modalZapDialog) {
return;
}
if (!this.modalZapDialog) {
return false;
}
this.modalZapDialog.hidden = false;
this.modalZapDialog.dataset.state = "open";
this.modalZapDialog.setAttribute("aria-hidden", "false");
this.modalZapDialogOpen = true;
if (this.modalZapBtn) {
this.modalZapBtn.setAttribute("aria-expanded", "true");
}
this.focusZapAmount();
this.modalZapDialog.hidden = false;
this.modalZapDialog.dataset.state = "open";
this.modalZapDialog.setAttribute("aria-hidden", "false");
this.modalZapDialogOpen = true;
if (this.modalZapBtn) {
this.modalZapBtn.setAttribute("aria-expanded", "true");
}
this.focusZapAmount();
return true;
};
const promise = runOpen().catch((error) => {
this.log("[VideoModal] Failed to open zap popover", error);
return false;
});
this.modalZapOpenPromise = promise.finally(() => {
const shouldClose = this.modalZapPendingToggle === "close";
this.modalZapOpenPromise = null;
this.modalZapPendingToggle = null;
if (shouldClose && !this.modalZapPending) {
this.closeZapDialog();
}
});
return this.modalZapOpenPromise;
}
closeZapDialog({ silent = false, restoreFocus } = {}) {
this.modalZapPendingToggle = null;
if (this.modalZapPopover?.close) {
const options = { silent };
if (restoreFocus !== undefined) {