From 9fdc6160eb083edd05621be64df0780787c79937 Mon Sep 17 00:00:00 2001 From: Jared Vititoe Date: Wed, 27 May 2026 15:20:42 -0400 Subject: [PATCH] fix: emoji picker works + silence 429 presence rate-limit errors MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Emoji bug root cause: EmojiBoard wraps itself in a FocusTrap with clickOutsideDeactivates:true. When the picker was rendered inside Input's 'after' prop, the FocusTrap treated clicks on the emoji items as outside-clicks and deactivated (calling requestClose) before the onEmojiSelect callback fired. Fixed by moving the emoji PopOut to be a direct sibling of Input in the form row instead of nesting it inside Input.after — matching the established pattern used in MessageEditor. 429 rate-limit: mx.setPresence() calls in handleClear and the auto-clear timer effect had no rejection handling, causing unhandled promise rejections logged to Sentry when Synapse rate-limits presence updates. Added .catch(() => undefined) to both call sites. Sentry issue JAVASCRIPT-REACT-E resolved. Co-Authored-By: Claude Sonnet 4.6 --- src/app/features/settings/account/Profile.tsx | 84 +++++++++---------- 1 file changed, 41 insertions(+), 43 deletions(-) diff --git a/src/app/features/settings/account/Profile.tsx b/src/app/features/settings/account/Profile.tsx index 2cf6d501f..bc61b088e 100644 --- a/src/app/features/settings/account/Profile.tsx +++ b/src/app/features/settings/account/Profile.tsx @@ -365,17 +365,16 @@ function ProfileStatus() { useEffect(() => { if (!expiryTs) return undefined; const remaining = expiryTs - Date.now(); - if (remaining <= 0) { + const clearStatus = () => { localStorage.removeItem(STATUS_EXPIRY_KEY(userId)); setExpiryTs(0); - mx.setPresence({ presence: 'online', status_msg: '' }); + mx.setPresence({ presence: 'online', status_msg: '' }).catch(() => undefined); + }; + if (remaining <= 0) { + clearStatus(); return undefined; } - const timer = window.setTimeout(() => { - localStorage.removeItem(STATUS_EXPIRY_KEY(userId)); - setExpiryTs(0); - mx.setPresence({ presence: 'online', status_msg: '' }); - }, remaining); + const timer = window.setTimeout(clearStatus, remaining); return () => clearTimeout(timer); }, [expiryTs, userId, mx]); @@ -421,7 +420,7 @@ function ProfileStatus() { setStatusMsg(''); localStorage.removeItem(STATUS_EXPIRY_KEY(userId)); setExpiryTs(0); - mx.setPresence({ presence: 'online', status_msg: '' }); + mx.setPresence({ presence: 'online', status_msg: '' }).catch(() => undefined); }; const hasChanges = statusMsg !== (presence?.status ?? ''); @@ -440,7 +439,7 @@ function ProfileStatus() { } > - + }> - setEmojiAnchor(undefined)} - /> - - } - > - ) => { - const rect = evt.currentTarget.getBoundingClientRect(); - setEmojiAnchor((prev) => (prev ? undefined : rect)); - }} - > - - - - } /> + }> + setEmojiAnchor(undefined)} + /> + + } + > + ) => { + const rect = evt.currentTarget.getBoundingClientRect(); + setEmojiAnchor((prev) => (prev ? undefined : rect)); + }} + > + + +