mirror of
https://github.com/PR0M3TH3AN/bitvid.git
synced 2026-10-27 07:52:24 +00:00
Merge pull request #679 from PR0M3TH3AN/codex/update-zap-handler-and-test-for-login
Ensure zap dialog closes when login is required
This commit is contained in:
3 files changed
+203
-15
No files matched your search
@@ -692,12 +692,22 @@ class Application {
|
||||
};
|
||||
this.boundVideoModalZapOpenHandler = (event) => {
|
||||
const requiresLogin = Boolean(event?.detail?.requiresLogin);
|
||||
if (requiresLogin) {
|
||||
this.pendingModalZapOpen = true;
|
||||
} else {
|
||||
this.pendingModalZapOpen = false;
|
||||
this.pendingModalZapOpen = requiresLogin;
|
||||
|
||||
const openResult = this.zapController?.open({ requiresLogin });
|
||||
if (!openResult) {
|
||||
event?.preventDefault?.();
|
||||
if (!requiresLogin) {
|
||||
this.pendingModalZapOpen = false;
|
||||
}
|
||||
this.videoModal?.closeZapDialog?.({
|
||||
silent: true,
|
||||
restoreFocus: false,
|
||||
});
|
||||
return;
|
||||
}
|
||||
this.zapController?.open({ requiresLogin });
|
||||
|
||||
this.pendingModalZapOpen = false;
|
||||
};
|
||||
this.boundVideoModalZapCloseHandler = () => {
|
||||
this.zapController?.close();
|
||||
@@ -3029,7 +3039,19 @@ class Application {
|
||||
}
|
||||
|
||||
isUserLoggedIn() {
|
||||
return Boolean(this.normalizeHexPubkey(this.pubkey));
|
||||
const normalizedPubkey = this.normalizeHexPubkey(this.pubkey);
|
||||
if (!normalizedPubkey) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const sessionActorPubkey = this.normalizeHexPubkey(
|
||||
nostrClient?.sessionActor?.pubkey,
|
||||
);
|
||||
if (sessionActorPubkey && sessionActorPubkey === normalizedPubkey) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
async updateActiveNwcSettings(partial = {}) {
|
||||
|
||||
@@ -128,9 +128,14 @@ export class VideoModal {
|
||||
this.eventTarget.removeEventListener(type, listener, options);
|
||||
}
|
||||
|
||||
dispatch(type, detail) {
|
||||
const event = new CustomEvent(type, { detail });
|
||||
this.eventTarget.dispatchEvent(event);
|
||||
dispatch(type, detail, options = {}) {
|
||||
const config =
|
||||
options && typeof options === "object" ? { ...options } : Object.create(null);
|
||||
const event = new CustomEvent(type, {
|
||||
detail,
|
||||
cancelable: Boolean(config.cancelable),
|
||||
});
|
||||
return this.eventTarget.dispatchEvent(event);
|
||||
}
|
||||
|
||||
getRoot() {
|
||||
@@ -420,10 +425,14 @@ export class VideoModal {
|
||||
}
|
||||
|
||||
if (this.modalZapRequiresLogin) {
|
||||
this.dispatch("zap:open", {
|
||||
video: this.activeVideo,
|
||||
requiresLogin: true,
|
||||
});
|
||||
this.dispatch(
|
||||
"zap:open",
|
||||
{
|
||||
video: this.activeVideo,
|
||||
requiresLogin: true,
|
||||
},
|
||||
{ cancelable: false },
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -446,9 +455,17 @@ export class VideoModal {
|
||||
return;
|
||||
}
|
||||
|
||||
const allowed = this.dispatch(
|
||||
"zap:open",
|
||||
{ video: this.activeVideo },
|
||||
{ cancelable: true },
|
||||
);
|
||||
if (allowed === false) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.modalZapPendingToggle = null;
|
||||
this.openZapDialog();
|
||||
this.dispatch("zap:open", { video: this.activeVideo });
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1054,6 +1071,10 @@ export class VideoModal {
|
||||
}
|
||||
|
||||
async openZapDialog() {
|
||||
if (this.modalZapRequiresLogin) {
|
||||
return Promise.resolve(false);
|
||||
}
|
||||
|
||||
if (this.modalZapOpenPromise) {
|
||||
return this.modalZapOpenPromise;
|
||||
}
|
||||
|
||||
@@ -182,10 +182,26 @@ function createVideoModalStub() {
|
||||
return {
|
||||
setCopyEnabled: noop,
|
||||
setShareEnabled: noop,
|
||||
setZapVisibility: noop,
|
||||
setWalletPromptVisible: noop,
|
||||
zapVisibilityCalls: [],
|
||||
setZapVisibility(config) {
|
||||
const payload =
|
||||
config && typeof config === "object"
|
||||
? { ...config }
|
||||
: { visible: Boolean(config) };
|
||||
this.zapVisibilityCalls.push(payload);
|
||||
this.lastZapVisibility = payload;
|
||||
},
|
||||
dialogOpen: false,
|
||||
closeZapDialogCalls: [],
|
||||
closeZapDialog(options = {}) {
|
||||
this.closeZapDialogCalls.push(options);
|
||||
this.dialogOpen = false;
|
||||
},
|
||||
resetStats: noop,
|
||||
updateViewCountLabel: noop,
|
||||
setViewCountPointer: noop,
|
||||
completedStates: [],
|
||||
addEventListener(type, handler) {
|
||||
listeners.set(type, handler);
|
||||
},
|
||||
@@ -202,6 +218,9 @@ function createVideoModalStub() {
|
||||
setZapPending(value) {
|
||||
this.setZapPendingCalls.push(Boolean(value));
|
||||
},
|
||||
setZapCompleted(value) {
|
||||
this.completedStates.push(Boolean(value));
|
||||
},
|
||||
setZapStatus(message, tone) {
|
||||
this.statusMessages.push({ message, tone });
|
||||
},
|
||||
@@ -297,6 +316,132 @@ async function createApp({ splitAndZap }) {
|
||||
return { app, modalStub, creatorAddress, platformAddress };
|
||||
}
|
||||
|
||||
await (async () => {
|
||||
// Test: logged-out zap request closes modal and queues reopen
|
||||
const { app, modalStub } = await createApp({
|
||||
splitAndZap: async () => ({ receipts: [] }),
|
||||
});
|
||||
|
||||
let loginNotificationCount = 0;
|
||||
app.zapController.notifyLoginRequired = () => {
|
||||
loginNotificationCount += 1;
|
||||
};
|
||||
|
||||
modalStub.dialogOpen = true;
|
||||
modalStub.closeZapDialogCalls = [];
|
||||
|
||||
app.pendingModalZapOpen = false;
|
||||
|
||||
app.boundVideoModalZapOpenHandler({ detail: { requiresLogin: true } });
|
||||
|
||||
assert.equal(
|
||||
loginNotificationCount,
|
||||
1,
|
||||
"should request login notification when zapping logged out",
|
||||
);
|
||||
assert.equal(
|
||||
app.pendingModalZapOpen,
|
||||
true,
|
||||
"zap should remain pending for post-login reopen",
|
||||
);
|
||||
assert.equal(
|
||||
modalStub.closeZapDialogCalls.length,
|
||||
1,
|
||||
"zap dialog should close immediately when login required",
|
||||
);
|
||||
assert.deepEqual(modalStub.closeZapDialogCalls[0], {
|
||||
silent: true,
|
||||
restoreFocus: false,
|
||||
});
|
||||
assert.equal(modalStub.dialogOpen, false, "zap dialog should be closed");
|
||||
|
||||
app.destroy();
|
||||
})();
|
||||
|
||||
await (async () => {
|
||||
// Test: preventDefault is called when zap opening is rejected post-dispatch
|
||||
const { app, modalStub } = await createApp({
|
||||
splitAndZap: async () => ({ receipts: [] }),
|
||||
});
|
||||
|
||||
let loginNotificationCount = 0;
|
||||
app.zapController.notifyLoginRequired = () => {
|
||||
loginNotificationCount += 1;
|
||||
};
|
||||
|
||||
app.zapController.isUserLoggedIn = () => false;
|
||||
|
||||
modalStub.closeZapDialogCalls = [];
|
||||
|
||||
const preventCalls = [];
|
||||
const event = {
|
||||
detail: { requiresLogin: false },
|
||||
preventDefault: () => {
|
||||
preventCalls.push(true);
|
||||
},
|
||||
};
|
||||
|
||||
app.pendingModalZapOpen = true;
|
||||
|
||||
app.boundVideoModalZapOpenHandler(event);
|
||||
|
||||
assert.equal(
|
||||
loginNotificationCount,
|
||||
1,
|
||||
"should notify login requirement when zap open is rejected",
|
||||
);
|
||||
assert.equal(
|
||||
preventCalls.length,
|
||||
1,
|
||||
"should prevent default zap opening when controller rejects it",
|
||||
);
|
||||
assert.equal(
|
||||
app.pendingModalZapOpen,
|
||||
false,
|
||||
"pending zap reopen flag should clear when rejection wasn't login-gated",
|
||||
);
|
||||
assert.deepEqual(modalStub.closeZapDialogCalls[0], {
|
||||
silent: true,
|
||||
restoreFocus: false,
|
||||
});
|
||||
|
||||
app.destroy();
|
||||
})();
|
||||
|
||||
await (async () => {
|
||||
// Test: session actors should not be treated as logged-in users for zaps
|
||||
const { app, modalStub } = await createApp({
|
||||
splitAndZap: async () => ({ receipts: [] }),
|
||||
});
|
||||
|
||||
const { nostrClient } = await import("../js/nostr.js");
|
||||
const originalSessionActor = nostrClient.sessionActor;
|
||||
const sessionPubkey = "a".repeat(64);
|
||||
nostrClient.sessionActor = { pubkey: sessionPubkey, privateKey: "priv" };
|
||||
|
||||
app.pubkey = sessionPubkey;
|
||||
|
||||
modalStub.zapVisibilityCalls = [];
|
||||
app.zapController.setVisibility(true);
|
||||
|
||||
const lastVisibility =
|
||||
modalStub.zapVisibilityCalls[modalStub.zapVisibilityCalls.length - 1];
|
||||
assert.deepEqual(
|
||||
lastVisibility,
|
||||
{ visible: true, requiresLogin: true },
|
||||
"zap controller should require login when only a session actor is present",
|
||||
);
|
||||
assert.equal(
|
||||
app.isUserLoggedIn(),
|
||||
false,
|
||||
"session actor pubkeys should not count as logged-in users",
|
||||
);
|
||||
|
||||
app.pubkey = null;
|
||||
nostrClient.sessionActor = originalSessionActor;
|
||||
app.destroy();
|
||||
})();
|
||||
|
||||
await (async () => {
|
||||
// Test: wallet required before zapping
|
||||
const splitCalls = [];
|
||||
|
||||
Reference in new issue
Block a user