diff --git a/src/gui/src/UI/UIWindowAppFeedback.js b/src/gui/src/UI/UIWindowAppFeedback.js index 66f789213..8fba932a4 100644 --- a/src/gui/src/UI/UIWindowAppFeedback.js +++ b/src/gui/src/UI/UIWindowAppFeedback.js @@ -142,7 +142,13 @@ async function UIWindowAppFeedback (options) { $overlay.on('mousedown', (e) => { if ( e.target === $overlay.get(0) && ! sending ) close(); }); - $overlay.find('.app-feedback-x, .app-feedback-close-btn, .app-feedback-cancel-btn').on('click', close); + // Same in-flight gate as Escape/backdrop: closing while the POST is + // pending would settle false for a submission that still lands + // server-side — the developer gets the email while the app is told + // nothing was sent. + $overlay.find('.app-feedback-x, .app-feedback-close-btn, .app-feedback-cancel-btn').on('click', () => { + if ( ! sending ) close(); + }); $overlay.find('.app-feedback-message').on('input', function () { $overlay.find('.app-feedback-counter').text(`${this.value.length} / ${MESSAGE_MAX_LENGTH}`); @@ -155,6 +161,7 @@ async function UIWindowAppFeedback (options) { if ( ! message || sending ) return; sending = true; $btn.prop('disabled', true); + $overlay.find('.app-feedback-x, .app-feedback-cancel-btn').prop('disabled', true); $overlay.find('.app-feedback-error').hide(); try { const res = await fetch(`${window.api_origin}/app-feedback`, { @@ -193,6 +200,7 @@ async function UIWindowAppFeedback (options) { $overlay.find('.app-feedback-error').text(i18n('app_feedback_error')).show(); } finally { sending = false; + $overlay.find('.app-feedback-x, .app-feedback-cancel-btn').prop('disabled', false); $overlay.find('.app-feedback-send-btn').prop('disabled', settled || String($overlay.find('.app-feedback-message').val() || '').trim() === ''); } diff --git a/src/gui/src/css/dashboard.css b/src/gui/src/css/dashboard.css index 20c0669cb..618704a1f 100644 --- a/src/gui/src/css/dashboard.css +++ b/src/gui/src/css/dashboard.css @@ -1619,7 +1619,7 @@ input.myapps-group-name:focus { height: 16px; } @media (hover: hover) { - .app-feedback-x:hover { + .app-feedback-x:hover:not(:disabled) { background: var(--afb-hover); color: var(--afb-fg); } @@ -1727,7 +1727,7 @@ input.myapps-group-name:focus { transition: background-color 0.12s ease, opacity 0.12s ease, filter 0.12s ease; } @media (hover: hover) { - .app-feedback-btn:hover { + .app-feedback-btn:hover:not(:disabled) { background: var(--afb-hover); } } @@ -1747,6 +1747,12 @@ input.myapps-group-name:focus { cursor: default; filter: none; } +/* Cancel/X are disabled while a submit is in flight. */ +.app-feedback-btn:disabled, +.app-feedback-x:disabled { + opacity: 0.5; + cursor: default; +} .app-feedback-success { text-align: center;