diff --git a/_locales/en/messages.json b/_locales/en/messages.json index 53b17e8cb2..be880e4457 100644 --- a/_locales/en/messages.json +++ b/_locales/en/messages.json @@ -6304,6 +6304,18 @@ "messageformat": "Choose who can send messages to the group.", "description": "This is the additional info for the 'who can send messages' panel" }, + "icu:ConversationDetails--label-clear-warning--title": { + "messageformat": "Member labels will be cleared", + "description": "When the user changes the 'edit group info' permission to 'Admins only', this dialog shows. Title of dialog." + }, + "icu:ConversationDetails--label-clear-warning--description": { + "messageformat": "Changing this permission to β€œOnly admins” will clear member labels set by non-admins in this group.", + "description": "When the user changes the 'edit group info' permission to 'Admins only', this dialog shows. Description text of dialog." + }, + "icu:ConversationDetails--label-clear-warning--continue": { + "messageformat": "Continue", + "description": "When the user changes the 'edit group info' permission to 'Admins only', this dialog shows. Button to continue making the change." + }, "icu:ConversationDetails--requests-and-invites": { "messageformat": "Requests & Invites", "description": "This is a button to display which members have been invited but have not joined yet" diff --git a/stylesheets/components/AboutContactModal.scss b/stylesheets/components/AboutContactModal.scss index 5d37cc745d..5d4e3dae3d 100644 --- a/stylesheets/components/AboutContactModal.scss +++ b/stylesheets/components/AboutContactModal.scss @@ -125,6 +125,18 @@ display: flex; align-items: center; gap: 6px; + + max-width: 100%; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + } + + &__label-container__string { + min-width: 0px; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; } &__button { diff --git a/ts/components/conversation/AboutContactModal.dom.stories.tsx b/ts/components/conversation/AboutContactModal.dom.stories.tsx index 99ba52fc7a..d8d44d6452 100644 --- a/ts/components/conversation/AboutContactModal.dom.stories.tsx +++ b/ts/components/conversation/AboutContactModal.dom.stories.tsx @@ -103,6 +103,34 @@ export function MeWithLabel(args: PropsType): React.JSX.Element { ); } +export function LongLabel(args: PropsType): React.JSX.Element { + return ( + + ); +} + +export function LongLabelAllEmoji(args: PropsType): React.JSX.Element { + return ( + + ); +} + export function MeWithInvalidLabelEmoji(args: PropsType): React.JSX.Element { return ( {' '} @@ -316,7 +316,16 @@ export function AboutContactModal({
{labelEmojiElement} - {contactLabelString} + + +
)} diff --git a/ts/components/conversation/conversation-details/GroupV2Permissions.dom.stories.tsx b/ts/components/conversation/conversation-details/GroupV2Permissions.dom.stories.tsx index 0c4dffca21..c13439118b 100644 --- a/ts/components/conversation/conversation-details/GroupV2Permissions.dom.stories.tsx +++ b/ts/components/conversation/conversation-details/GroupV2Permissions.dom.stories.tsx @@ -8,6 +8,7 @@ import type { PropsType } from './GroupV2Permissions.dom.js'; import { GroupV2Permissions } from './GroupV2Permissions.dom.js'; import type { ConversationType } from '../../../state/ducks/conversations.preload.js'; import { getDefaultConversation } from '../../../test-helpers/getDefaultConversation.std.js'; +import { generateAci } from '../../../types/ServiceId.std.js'; const { i18n } = window.SignalContext; @@ -15,11 +16,9 @@ export default { title: 'Components/Conversation/ConversationDetails/GroupV2Permissions', } satisfies Meta; -const conversation: ConversationType = getDefaultConversation({ +const defaultConversation: ConversationType = getDefaultConversation({ id: '', lastUpdated: 0, - memberships: Array(32).fill({ member: getDefaultConversation({}) }), - pendingMemberships: Array(16).fill({ member: getDefaultConversation({}) }), title: 'Some Conversation', type: 'group', announcementsOnlyReady: true, @@ -27,7 +26,7 @@ const conversation: ConversationType = getDefaultConversation({ }); const createProps = (): PropsType => ({ - conversation, + conversation: defaultConversation, i18n, setAccessControlAttributesSetting: action( 'setAccessControlAttributesSetting' @@ -42,6 +41,64 @@ export function Basic(): React.JSX.Element { return ; } +export function BasicWithLabels(): React.JSX.Element { + const props = createProps(); + const conversation = { + ...defaultConversation, + memberships: [ + { + aci: generateAci(), + isAdmin: true, + labelString: undefined, + labelEmoji: undefined, + }, + { + aci: generateAci(), + isAdmin: true, + labelString: 'First', + labelEmoji: undefined, + }, + { + aci: generateAci(), + isAdmin: false, + labelString: 'Second', + labelEmoji: undefined, + }, + ], + }; + + return ; +} + +export function BasicWithNonAdminLabels(): React.JSX.Element { + const props = createProps(); + const conversation = { + ...defaultConversation, + memberships: [ + { + aci: generateAci(), + isAdmin: true, + labelString: undefined, + labelEmoji: undefined, + }, + { + aci: generateAci(), + isAdmin: true, + labelString: 'First', + labelEmoji: undefined, + }, + { + aci: generateAci(), + isAdmin: false, + labelString: 'Second', + labelEmoji: undefined, + }, + ], + }; + + return ; +} + export function NotAdmin(): React.JSX.Element { return ( !membership.isAdmin && membership.labelString + ); const updateAccessControlAttributes = (value: string) => { + const newValue = Number(value); + if (newValue === AccessControlEnum.ADMINISTRATOR && nonAdminsHaveLabels) { + setIsWarningAboutClearingLabels(true); + return; + } + setAccessControlAttributesSetting(conversation.id, Number(value)); }; const updateAccessControlMembers = (value: string) => { setAccessControlMembersSetting(conversation.id, Number(value)); }; - const AccessControlEnum = Proto.AccessControl.AccessRequired; const updateAnnouncementsOnly = (value: string) => { setAnnouncementsOnly( conversation.id, @@ -113,6 +126,51 @@ export function GroupV2Permissions({ } /> )} + { + if (!value) { + setIsWarningAboutClearingLabels(false); + } + }} + > + + + + {i18n('icu:ConversationDetails--label-clear-warning--title')} + + + {i18n( + 'icu:ConversationDetails--label-clear-warning--description' + )} + + + + { + setIsWarningAboutClearingLabels(false); + }} + > + {i18n('icu:cancel')} + + { + setAccessControlAttributesSetting( + conversation.id, + AccessControlEnum.ADMINISTRATOR + ); + setIsWarningAboutClearingLabels(false); + }} + > + {i18n('icu:ConversationDetails--label-clear-warning--continue')} + + + + ); } diff --git a/ts/util/groupMembershipUtils.preload.ts b/ts/util/groupMembershipUtils.preload.ts index 3859ed5431..b3c81804d1 100644 --- a/ts/util/groupMembershipUtils.preload.ts +++ b/ts/util/groupMembershipUtils.preload.ts @@ -195,7 +195,7 @@ export function getMemberships( aci: member.aci, labelEmoji: member.labelEmoji, labelString: member.labelString - ? truncateString(member.labelString, { + ? truncateString(member.labelString.trim(), { byteLimit: STRING_BYTE_LIMIT, graphemeLimit: STRING_GRAPHEME_LIMIT, })