From e98f84eb8fd11d7d824ebba0471e30a689a638b6 Mon Sep 17 00:00:00 2001 From: Half-Shot Date: Fri, 8 Nov 2024 12:52:05 +0000 Subject: [PATCH] Add error for failured to send reaction. --- public/locales/en-GB/app.json | 5 + src/button/ReactionToggleButton.module.css | 16 ++ src/button/ReactionToggleButton.tsx | 199 ++++++++++++--------- 3 files changed, 133 insertions(+), 87 deletions(-) diff --git a/public/locales/en-GB/app.json b/public/locales/en-GB/app.json index 69a1d105..22bfe646 100644 --- a/public/locales/en-GB/app.json +++ b/public/locales/en-GB/app.json @@ -4,11 +4,14 @@ }, "action": { "close": "Close", + "close_search": "Close search", "copy_link": "Copy link", "edit": "Edit", "go": "Go", "invite": "Invite", "no": "No", + "open_search": "Open search", + "pick_reaction": "Pick reaction", "raise_hand_or_send_reaction": "Raise hand or send reaction", "register": "Register", "remove": "Remove", @@ -58,6 +61,7 @@ "preferences": "Preferences", "profile": "Profile", "raise_hand": "Raise hand", + "search": "Search", "settings": "Settings", "unencrypted": "Not encrypted", "username": "Username", @@ -128,6 +132,7 @@ "rageshake_sending": "Sending…", "rageshake_sending_logs": "Sending debug logs…", "rageshake_sent": "Thanks!", + "reaction_search": "Search reactions…", "recaptcha_caption": "This site is protected by ReCAPTCHA and the Google <2>Privacy Policy and <6>Terms of Service apply.<9>By clicking \"Register\", you agree to our <12>End User Licensing Agreement (EULA)", "recaptcha_dismissed": "Recaptcha dismissed", "recaptcha_not_loaded": "Recaptcha not loaded", diff --git a/src/button/ReactionToggleButton.module.css b/src/button/ReactionToggleButton.module.css index 1919dd18..acb8bb25 100644 --- a/src/button/ReactionToggleButton.module.css +++ b/src/button/ReactionToggleButton.module.css @@ -64,3 +64,19 @@ .searchForm > label { flex: auto; } + +.alert { + margin-bottom: var(--cpd-space-3x); + animation: grow-in 200ms; + height: 2.5em; +} + +@keyframes grow-in { + from { + height: 0; + } + + to { + height: 2.5em; + } +} diff --git a/src/button/ReactionToggleButton.tsx b/src/button/ReactionToggleButton.tsx index 0b07f665..44ab7218 100644 --- a/src/button/ReactionToggleButton.tsx +++ b/src/button/ReactionToggleButton.tsx @@ -11,6 +11,7 @@ import { Separator, Search, Form, + Alert, } from "@vector-im/compound-web"; import { SearchIcon, @@ -25,6 +26,7 @@ import { KeyboardEventHandler, ReactNode, useCallback, + useEffect, useMemo, useState, } from "react"; @@ -72,9 +74,11 @@ export function ReactionPopupMenu({ toggleRaisedHand, isHandRaised, canReact, + errorText, }: { sendReaction: (reaction: ReactionOption) => void; toggleRaisedHand: () => void; + errorText?: string; isHandRaised: boolean; canReact: boolean; }): ReactNode { @@ -119,80 +123,91 @@ export function ReactionPopupMenu({ ); const label = isHandRaised ? t("common.raise_hand") : t("common.lower_hand"); return ( -
-
- - toggleRaisedHand()} - iconOnly - Icon={RaisedHandSolidIcon} - /> - -
-
-
- {isSearching ? ( - <> - - - setIsSearching(false)} - /> - - - - ) : null} - - {filteredReactionSet.map((reaction) => ( -
  • - + <> + {errorText && ( + + {errorText} + + )} +
    +
    + + toggleRaisedHand()} + iconOnly + Icon={RaisedHandSolidIcon} + /> + +
    +
    +
    + {isSearching ? ( + <> + + sendReaction(reaction)} - > - {reaction.emoji} - + Icon={CloseIcon} + aria-label={t("action.close_search")} + size="sm" + kind="destructive" + onClick={() => setIsSearching(false)} + /> + + + + ) : null} + + {filteredReactionSet.map((reaction) => ( +
  • + + sendReaction(reaction)} + > + {reaction.emoji} + + +
  • + ))} +
    +
    + {!isSearching ? ( +
    +
  • + + setIsSearching(true)} + />
  • - ))} -
  • -
    - {!isSearching ? ( -
    -
  • - - setIsSearching(true)} - /> - -
  • -
    - ) : null} -
    + + ) : null} +
    + ); } @@ -205,24 +220,30 @@ export function ReactionToggleButton({ client, rtcSession, }: ReactionToggleButtonProps): ReactNode { + const { t } = useTranslation(); const { raisedHands, lowerHand, reactions } = useReactions(); const [busy, setBusy] = useState(false); const userId = client.getUserId()!; const isHandRaised = !!raisedHands[userId]; const memberships = useMatrixRTCSessionMemberships(rtcSession); const [showReactionsMenu, setShowReactionsMenu] = useState(false); + const [errorText, setErrorText] = useState(); + + useEffect(() => { + // Clear whenever the reactions menu state changes. + setErrorText(undefined); + }, [showReactionsMenu]); const canReact = !reactions[userId]; const sendRelation = useCallback( async (reaction: ReactionOption) => { - const myMembership = memberships.find((m) => m.sender === userId); - if (!myMembership?.eventId) { - logger.error("Cannot find own membership event"); - return; - } - const parentEventId = myMembership.eventId; try { + const myMembership = memberships.find((m) => m.sender === userId); + if (!myMembership?.eventId) { + throw new Error("Cannot find own membership event"); + } + const parentEventId = myMembership.eventId; setBusy(true); await client.sendEvent( rtcSession.room.roomId, @@ -236,12 +257,14 @@ export function ReactionToggleButton({ name: reaction.name, }, ); + setErrorText(undefined); + setShowReactionsMenu(false); // Do NOT close the menu after this. } catch (ex) { + setErrorText(ex instanceof Error ? ex.message : "Unknown error"); logger.error("Failed to send reaction", ex); } finally { setBusy(false); - setShowReactionsMenu(false); } }, [memberships, client, userId, rtcSession], @@ -258,13 +281,12 @@ export function ReactionToggleButton({ setBusy(false); } } else { - const myMembership = memberships.find((m) => m.sender === userId); - if (!myMembership?.eventId) { - logger.error("Cannot find own membership event"); - return; - } - const parentEventId = myMembership.eventId; try { + const myMembership = memberships.find((m) => m.sender === userId); + if (!myMembership?.eventId) { + throw new Error("Cannot find own membership event"); + } + const parentEventId = myMembership.eventId; setBusy(true); const reaction = await client.sendEvent( rtcSession.room.roomId, @@ -278,11 +300,13 @@ export function ReactionToggleButton({ }, ); logger.debug("Sent raise hand event", reaction.event_id); + setErrorText(undefined); + setShowReactionsMenu(false); } catch (ex) { - logger.error("Failed to send reaction event", ex); + setErrorText(ex instanceof Error ? ex.message : "Unknown error"); + logger.error("Failed to raise hand", ex); } finally { setBusy(false); - setShowReactionsMenu(false); } } }; @@ -307,12 +331,13 @@ export function ReactionToggleButton({ /> setShowReactionsMenu(false)} > void sendRelation(reaction)}