diff --git a/_locales/en/messages.json b/_locales/en/messages.json index be880e4457..211d0f5414 100644 --- a/_locales/en/messages.json +++ b/_locales/en/messages.json @@ -6240,6 +6240,18 @@ "messageformat": "Saving changes...", "description": "Accessibility label for button with spinner as we save the user's member label." }, + "icu:ConversationDetails--member-label--error-title": { + "messageformat": "Can’t save member label", + "description": "If save of member label failed, a dialog shows. Title of dialog." + }, + "icu:ConversationDetails--member-label--error-generic": { + "messageformat": "Check your connection and try again.", + "description": "If save of member label failed, a dialog shows. Description of dialog." + }, + "icu:ConversationDetails--member-label--error-permissions": { + "messageformat": "Only admins can set member labels in this group.", + "description": "If Desktop discovers that permissions have changed since entering the screen, it will show this in an error dialog and exit the pane." + }, "icu:ConversationDetails--disappearing-messages-label": { "messageformat": "Disappearing messages", "description": "This is the label for the disappearing messages setting panel" diff --git a/ts/components/conversation/conversation-details/GroupMemberLabelEditor.dom.stories.tsx b/ts/components/conversation/conversation-details/GroupMemberLabelEditor.dom.stories.tsx index 3fdfe8c7a5..9989889d5e 100644 --- a/ts/components/conversation/conversation-details/GroupMemberLabelEditor.dom.stories.tsx +++ b/ts/components/conversation/conversation-details/GroupMemberLabelEditor.dom.stories.tsx @@ -9,6 +9,9 @@ import { GroupMemberLabelEditor } from './GroupMemberLabelEditor.dom.js'; import { getDefaultConversation } from '../../../test-helpers/getDefaultConversation.std.js'; import { ThemeType } from '../../../types/Util.std.js'; import { getFakeBadge } from '../../../test-helpers/getFakeBadge.std.js'; +import { SECOND } from '../../../util/durations/constants.std.js'; +import { sleep } from '../../../util/sleep.std.js'; +import { SignalService as Proto } from '../../../protobuf/index.std.js'; const { i18n } = window.SignalContext; @@ -26,7 +29,14 @@ const createProps = (): PropsType => ({ ourColor: '160', popPanelForConversation: action('popPanelForConversation'), theme: ThemeType.light, - updateGroupMemberLabel: action('changeHasGroupLink'), + updateGroupMemberLabel: async ( + options, + callbacks?: { onSuccess?: () => unknown } + ) => { + action('updateGroupMemberLabel')(options); + await sleep(SECOND); + callbacks?.onSuccess?.(); + }, }); export function NoExistingLabel(): React.JSX.Element { @@ -62,3 +72,51 @@ export function WithBadge(): React.JSX.Element { return ; } + +export function ThrowsErrorOnSave(): React.JSX.Element { + const props: PropsType = { + ...createProps(), + updateGroupMemberLabel: async ( + options, + callbacks?: { onFailure?: () => unknown } + ) => { + action('updateGroupMemberLabel')(options); + await sleep(SECOND); + callbacks?.onFailure?.(); + }, + }; + + return ; +} + +export function PermissionsError(): React.JSX.Element { + const props: PropsType = createProps(); + + return ( + + ); +} + +export function PermissionsRestrictedButAdmin(): React.JSX.Element { + const props: PropsType = createProps(); + + return ( + + ); +} diff --git a/ts/components/conversation/conversation-details/GroupMemberLabelEditor.dom.tsx b/ts/components/conversation/conversation-details/GroupMemberLabelEditor.dom.tsx index 77706c138d..bd19a3fffc 100644 --- a/ts/components/conversation/conversation-details/GroupMemberLabelEditor.dom.tsx +++ b/ts/components/conversation/conversation-details/GroupMemberLabelEditor.dom.tsx @@ -1,7 +1,7 @@ // Copyright 2026 Signal Messenger, LLC // SPDX-License-Identifier: AGPL-3.0-only -import React, { useRef, useState } from 'react'; +import React, { useEffect, useRef, useState } from 'react'; import { noop } from 'lodash'; import { Input } from '../../Input.dom.js'; @@ -26,6 +26,8 @@ import { } from '../Message.dom.js'; import { ConversationColors } from '../../../types/Colors.std.js'; import { WidthBreakpoint } from '../../_util.std.js'; +import { AxoAlertDialog } from '../../../axo/AxoAlertDialog.dom.js'; +import { SignalService as Proto } from '../../../protobuf/index.std.js'; import type { EmojiVariantKey } from '../../fun/data/emojis.std.js'; import type { @@ -71,6 +73,11 @@ export function GroupMemberLabelEditor({ theme, updateGroupMemberLabel, }: PropsType): React.JSX.Element { + const [isShowingGeneralError, setIsShowingGeneralError] = + React.useState(false); + const [isShowingPermissionsError, setIsShowingPermissionsError] = + React.useState(false); + const messageContainer = useRef(null); const [labelEmoji, setLabelEmoji] = useState(existingLabelEmoji); @@ -94,6 +101,17 @@ export function GroupMemberLabelEditor({ ? { labelEmoji, labelString: labelString.trim() } : undefined; + useEffect(() => { + if ( + !group.areWeAdmin && + group.accessControlAttributes === + Proto.AccessControl.AccessRequired.ADMINISTRATOR && + !isShowingPermissionsError + ) { + setIsShowingPermissionsError(true); + } + }, [group, isShowingPermissionsError, setIsShowingPermissionsError]); + return (
@@ -245,7 +263,8 @@ export function GroupMemberLabelEditor({ popPanelForConversation(); }, onFailure() { - // TODO: DESKTOP-9710 + setIsSaving(false); + setIsShowingGeneralError(true); }, } ); @@ -254,6 +273,68 @@ export function GroupMemberLabelEditor({ {i18n('icu:save')}
+ { + if (!value) { + setIsShowingGeneralError(false); + } + }} + > + + + + {i18n('icu:ConversationDetails--member-label--error-title')} + + + {i18n('icu:ConversationDetails--member-label--error-generic')} + + + + { + setIsShowingGeneralError(false); + }} + > + {i18n('icu:ok')} + + + + + { + if (!value) { + setIsShowingPermissionsError(false); + popPanelForConversation(); + } + }} + > + + + + {i18n('icu:ConversationDetails--member-label--error-title')} + + + {i18n('icu:ConversationDetails--member-label--error-permissions')} + + + + { + popPanelForConversation(); + setIsShowingPermissionsError(false); + }} + > + {i18n('icu:ok')} + + + +
); }