From 189ea22fb98b6e02e6cda614bbbc99081ecda53a Mon Sep 17 00:00:00 2001 From: thePR0M3TH3AN <53631862+PR0M3TH3AN@users.noreply.github.com> Date: Mon, 20 Oct 2025 12:59:16 -0400 Subject: [PATCH] Add cooldown to upload modal publish button --- js/app.js | 8 ++- js/ui/components/UploadModal.js | 101 ++++++++++++++++++++++++++++++++ 2 files changed, 108 insertions(+), 1 deletion(-) diff --git a/js/app.js b/js/app.js index 7cc527b5..bb366e68 100644 --- a/js/app.js +++ b/js/app.js @@ -2777,7 +2777,7 @@ class Application { const payload = event?.detail?.payload || {}; try { - await this.authService.handleUploadSubmit(payload, { + const publishResult = await this.authService.handleUploadSubmit(payload, { publish: (data) => this.publishVideoNote(data, { onSuccess: () => { @@ -2787,7 +2787,13 @@ class Application { }, }), }); + if (!publishResult && this.uploadModal?.cancelCustomSubmitCooldown) { + this.uploadModal.cancelCustomSubmitCooldown(); + } } catch (error) { + if (this.uploadModal?.cancelCustomSubmitCooldown) { + this.uploadModal.cancelCustomSubmitCooldown(); + } const message = error && typeof error.message === "string" && error.message.trim() ? error.message.trim() diff --git a/js/ui/components/UploadModal.js b/js/ui/components/UploadModal.js index 1e2e78b3..697d2c7b 100644 --- a/js/ui/components/UploadModal.js +++ b/js/ui/components/UploadModal.js @@ -55,6 +55,11 @@ export class UploadModal { this.customForm = null; this.customFormInputs = {}; + this.customSubmitButton = null; + this.customSubmitButtonDefaultLabel = ""; + this.customSubmitBlockedUntil = 0; + this.customSubmitCooldownTimer = null; + this.customSubmitCooldownMs = 60000; this.cloudflareSettingsForm = null; this.cloudflareClearSettingsButton = null; @@ -234,6 +239,15 @@ export class UploadModal { isPrivate: context.querySelector("#uploadIsPrivate") || null }; + this.customSubmitButton = + this.customForm?.querySelector?.('button[type="submit"]') || null; + if (this.customSubmitButton && !this.customSubmitButtonDefaultLabel) { + const defaultLabel = this.customSubmitButton.textContent || ""; + this.customSubmitButtonDefaultLabel = + defaultLabel.trim() || defaultLabel || "Publish"; + } + this.updateCustomSubmitButtonState(); + this.closeButton = context.querySelector("#closeUploadModal") || null; this.cloudflareSettingsForm = @@ -374,6 +388,11 @@ export class UploadModal { if (this.customForm) { this.customForm.addEventListener("submit", (event) => { event.preventDefault(); + if (this.isCustomSubmitOnCooldown()) { + this.updateCustomSubmitButtonState(); + return; + } + this.startCustomSubmitCooldown(); this.handleCustomSubmit(); }); } @@ -442,6 +461,80 @@ export class UploadModal { this.nip71FormManager.bindSection("cloudflare"); } + clearCustomSubmitCooldownTimer() { + if (this.customSubmitCooldownTimer) { + clearInterval(this.customSubmitCooldownTimer); + this.customSubmitCooldownTimer = null; + } + } + + isCustomSubmitOnCooldown() { + if (!this.customSubmitBlockedUntil) { + return false; + } + return Date.now() < this.customSubmitBlockedUntil; + } + + updateCustomSubmitButtonState() { + const button = this.customSubmitButton; + if (!button) { + return; + } + + if (!this.customSubmitButtonDefaultLabel) { + const label = button.textContent || ""; + this.customSubmitButtonDefaultLabel = label.trim() || label || "Publish"; + } + + if (this.isCustomSubmitOnCooldown()) { + const remainingMs = Math.max( + 0, + this.customSubmitBlockedUntil - Date.now() + ); + const seconds = Math.max(1, Math.ceil(remainingMs / 1000)); + button.disabled = true; + button.setAttribute("aria-disabled", "true"); + button.dataset.cooldown = "true"; + button.textContent = `${this.customSubmitButtonDefaultLabel} (${seconds})`; + button.title = `Please wait ${seconds} seconds before sharing another video.`; + return; + } + + button.disabled = false; + button.removeAttribute("aria-disabled"); + delete button.dataset.cooldown; + button.textContent = + this.customSubmitButtonDefaultLabel || button.textContent || "Publish"; + button.removeAttribute("title"); + } + + startCustomSubmitCooldown() { + if (!this.customSubmitButton) { + return; + } + const now = Date.now(); + this.customSubmitBlockedUntil = now + this.customSubmitCooldownMs; + this.updateCustomSubmitButtonState(); + this.clearCustomSubmitCooldownTimer(); + this.customSubmitCooldownTimer = setInterval(() => { + if (!this.isCustomSubmitOnCooldown()) { + this.clearCustomSubmitCooldown(); + return; + } + this.updateCustomSubmitButtonState(); + }, 1000); + } + + clearCustomSubmitCooldown() { + this.clearCustomSubmitCooldownTimer(); + this.customSubmitBlockedUntil = 0; + this.updateCustomSubmitButtonState(); + } + + cancelCustomSubmitCooldown() { + this.clearCustomSubmitCooldown(); + } + setupModalAccessibility() { if (!this.root) { return; @@ -559,6 +652,7 @@ export class UploadModal { } this.isVisible = true; this.modalAccessibility?.activate({ triggerElement }); + this.updateCustomSubmitButtonState(); } close() { @@ -613,6 +707,8 @@ export class UploadModal { if (normalized === "cloudflare") { this.refreshCloudflareBucketPreview(); + } else { + this.updateCustomSubmitButtonState(); } } @@ -978,6 +1074,8 @@ export class UploadModal { } destroy() { + this.clearCustomSubmitCooldown(); + if (this.modalAccessibility?.destroy) { this.modalAccessibility.destroy(); } @@ -1010,6 +1108,9 @@ export class UploadModal { }); } this.r2Unsubscribes = []; + this.customSubmitButton = null; + this.customSubmitButtonDefaultLabel = ""; + this.customSubmitBlockedUntil = 0; this.eventsBound = false; this.loadPromise = null; this.root = null;