diff --git a/_locales/en/messages.json b/_locales/en/messages.json index 9a0fa82f23..9c7e171f4f 100644 --- a/_locales/en/messages.json +++ b/_locales/en/messages.json @@ -4664,10 +4664,22 @@ "messageformat": "Profile names are not verified", "description": "Label for profile names in the name verification warning in conversation hero" }, + "icu:ConversationHero--name-not-verified": { + "messageformat": "Name not verified", + "description": "Label for profile names and group names in the name verification warning in conversation hero" + }, "icu:ConversationHero--signal-official-chat": { "messageformat": "This is the official and only chat from Signal", "description": "Text indicating that this is the official Signal conversation" }, + "icu:ConversationHero--signal-official-account": { + "messageformat": "Official account", + "description": "Text indicating that this is the official Signal conversation" + }, + "icu:ConversationHero--signal-official-account--description": { + "messageformat": "The only official chat from Signal. Keep up to date with news and release notes.", + "description": "Description text at the top of the official Signal conversation" + }, "icu:ConversationHero--release-notes": { "messageformat": "Keep up to date with news and release notes.", "description": "Text explaining the purpose of the Signal official conversation" @@ -7033,6 +7045,10 @@ "messageformat": "Safety Tips", "description": "Shown on the message request warning. Clicking this button will open a dialog with safety tips" }, + "icu:MessageRequestWarning__safety-tips-v2": { + "messageformat": "Safety tips", + "description": "Shown on the message request warning. Clicking this button will open a dialog with safety tips" + }, "icu:ContactSpoofing__same-name--link": { "messageformat": "Review requests carefully. Signal found another contact with the same name. Review request", "description": "Shown in the timeline warning when you have a message request from someone with the same name as someone else" @@ -10188,6 +10204,23 @@ "messageformat": "Don't share personal information with people you don't know", "description": "Third list item in profile name warning modal for direct conversations" }, + "icu:ProfileNameWarningModal__warning--signal-cant-verify": { + "messageformat": "Signal can’t verify names and photos", + "description": "List item in profile name warning modal for direct conversations" + }, + "icu:ProfileNameWarningModal__warning--signal-wont-contact": { + "messageformat": "Signal will never contact you for your registration code, PIN, or recovery key", + "description": "List item in profile name warning modal for direct conversations" + }, + "icu:ProfileNameWarningModal__warning--be-cautious": { + "messageformat": "Be cautious of accounts that impersonate others", + "description": "Third list item in profile name warning modal for direct conversations" + }, + "icu:ProfileNameWarningModal__warning--dont-share-info": { + "messageformat": "Don't share personal information with people you don't know", + "description": "List item in profile name warning modal for direct conversations" + }, + "icu:ProfileNameWarningModal__description--group": { "messageformat": "Group names are chosen by members of the group.", "description": "Description of how group names work in the profile name warning modal for group conversations" diff --git a/stylesheets/components/ConversationHero.scss b/stylesheets/components/ConversationHero.scss deleted file mode 100644 index c2f5c5e5c2..0000000000 --- a/stylesheets/components/ConversationHero.scss +++ /dev/null @@ -1,263 +0,0 @@ -// Copyright 2022 Signal Messenger, LLC -// SPDX-License-Identifier: AGPL-3.0-only - -@use '../mixins'; -@use '../variables'; - -.module-conversation-hero { - padding-block: 32px 28px; - padding-inline: 0; - text-align: center; - - &__avatar { - margin-bottom: 12px; - } - - &__title { - @include mixins.button-reset(); - & { - cursor: pointer; - } - } - - &__title span { - @include mixins.font-title-1; - font-weight: 400; - } - - &__title__chevron { - display: inline-block; - height: 20px; - width: 20px; - - // Align with the text - position: relative; - inset-block-start: 2px; - - @include mixins.color-svg( - '../images/icons/v3/chevron/chevron-right-bold.svg', - light-dark(variables.$color-gray-90, variables.$color-gray-05) - ); - } - - &__profile-name { - display: flex; - align-items: center; - justify-content: center; - - @include mixins.font-title-1; - margin-bottom: 2px; - margin-top: 0; - - color: light-dark(variables.$color-gray-90, variables.$color-gray-05); - - .module-contact-name { - display: inline-flex; - align-items: center; - } - } - - &__with { - @include mixins.font-body-2; - margin-block: 0; - margin-inline: auto; - margin-bottom: 20px; - max-width: 500px; - - color: light-dark(variables.$color-gray-60, variables.$color-gray-25); - } - - &__note-to-self { - @include mixins.font-body-2; - - padding-block: 0; - padding-inline: 16px; - - color: light-dark(variables.$color-gray-60, variables.$color-gray-25); - } - - &__members-count__button { - @include mixins.button-reset; - & { - cursor: pointer; - text-decoration: underline; - text-underline-offset: 2px; - text-decoration-color: variables.$color-gray-25; - } - } - - &__safety-tips-button { - border-radius: 9999px; - padding-block: 6px; - padding-inline: 14px; - margin-top: 5px; - @include mixins.font-subtitle; - } - - &__review-carefully { - @include mixins.font-body-2-bold; - color: #a98b52; - } - - &__group-question-icon { - display: inline-block; - height: 16px; - width: 22px; - vertical-align: text-top; - margin-inline-end: 8px; - - @include mixins.color-svg( - '../images/icons/v3/group/group-questionmark-compact.svg', - light-dark(variables.$color-black, variables.$color-gray-05) - ); - } - - &__direct-question-icon { - display: inline-block; - height: 16px; - width: 16px; - vertical-align: text-top; - margin-inline-end: 8px; - - @include mixins.color-svg( - '../images/icons/v3/person/person-questionmark-compact.svg', - light-dark(variables.$color-black, variables.$color-gray-05) - ); - } - - &__name-not-verified__button { - @include mixins.button-reset; - & { - cursor: pointer; - text-decoration: underline; - text-underline-offset: 2px; - text-decoration-color: variables.$color-gray-25; - } - } - - &--release-notes-notice { - @include mixins.font-body-1; - - user-select: none; - - max-width: 255px; - margin-inline: auto; - margin-block-start: 10px; - padding-block: 16px; - padding-inline: 20px; - - border-radius: 18px; - background-color: light-dark(#eeefff, #3b3d50); - display: flex; - flex-direction: column; - gap: 8px; - color: light-dark(variables.$color-gray-75, variables.$color-gray-02); - } - - &__release-notes-notice-content { - text-align: center; - } - - &__release-notes-notice-check-icon { - display: inline-block; - height: 16px; - width: 16px; - margin-inline-end: 4px; - position: relative; - top: 3px; - - @include mixins.color-svg( - '../images/icons/v3/official/official-compact.svg', - light-dark(variables.$color-gray-75, variables.$color-gray-05) - ); - } - - &__release-notes-notice-bell-icon { - display: inline-block; - height: 16px; - width: 16px; - - margin-inline-end: 4px; - position: relative; - top: 3px; - - @include mixins.color-svg( - '../images/icons/v3/bell/bell-compact.svg', - light-dark(variables.$color-gray-75, variables.$color-gray-05) - ); - } - - &__membership { - @include mixins.font-body-2; - user-select: none; - - max-width: 255px; - margin-inline: auto; - margin-block-start: 10px; - padding-block: 16px; - padding-inline: 20px; - - border-radius: 18px; - border-style: solid; - border-width: 2.5px; - - display: flex; - flex-direction: column; - gap: 10px; - - border-color: light-dark( - variables.$color-gray-04, - variables.$color-gray-80 - ); - - color: light-dark(variables.$color-gray-90, variables.$color-gray-02); - - &__chevron { - display: inline-block; - height: 18px; - width: 18px; - vertical-align: text-top; - margin-inline-end: 8px; - - @include mixins.color-svg( - '../images/icons/v3/group/group.svg', - light-dark(variables.$color-black, variables.$color-gray-05) - ); - } - - &__name { - // Cancel bold - font-weight: normal; - } - - &__review-carefully-icon { - display: inline-block; - height: 18px; - width: 18px; - vertical-align: text-top; - margin-inline-end: 8px; - - @include mixins.color-svg( - '../images/icons/v3/error/error-triangle-fill-compact-bold.svg', - #a98b52 - ); - } - - &__warning { - line-height: 20px; - } - } - - &__members-count-icon { - display: inline-block; - height: 16px; - width: 16px; - vertical-align: text-top; - margin-inline-end: 8px; - - @include mixins.color-svg( - '../images/icons/v3/group/group-compact.svg', - light-dark(variables.$color-black, variables.$color-gray-05) - ); - } -} diff --git a/stylesheets/manifest.scss b/stylesheets/manifest.scss index 47659378ff..2505a38b3d 100644 --- a/stylesheets/manifest.scss +++ b/stylesheets/manifest.scss @@ -87,7 +87,6 @@ $is-storybook: false !default; @use 'components/ConversationDetails.scss'; @use 'components/ConversationDetailsHeader.scss'; @use 'components/ConversationHeader.scss'; -@use 'components/ConversationHero.scss'; @use 'components/ConversationMergeNotification.scss'; @use 'components/ConversationPanel.scss'; @use 'components/ConversationView.scss'; diff --git a/ts/components/GroupMembersNames.dom.tsx b/ts/components/GroupMembersNames.dom.tsx index a8d14bfdec..eac7aa20d2 100644 --- a/ts/components/GroupMembersNames.dom.tsx +++ b/ts/components/GroupMembersNames.dom.tsx @@ -27,7 +27,6 @@ function renderClickableButton( ): React.JSX.Element { return ( - - ) : null; - - const shouldShowReviewCarefully = - !acceptedMessageRequest && - (conversationType === 'group' || (sharedGroupNames?.length ?? 0) <= 1); - - const reviewCarefullyLabel = shouldShowReviewCarefully ? ( -
- - {i18n('icu:ConversationHero--review-carefully')} -
- ) : null; - - const sharedGroupsLabel = - conversationType === 'direct' ? ( -
- - -
- ) : null; - - const nameNotVerifiedLabel = - !fromOrAddedByTrustedContact && !isDirectConvoAndHasNickname ? ( -
- - ( - - ), - }} - i18n={i18n} - id={ - conversationType === 'group' - ? 'icu:ConversationHero--group-names' - : 'icu:ConversationHero--profile-names' - } - /> -
- ) : null; - - const membersCountLabel = - conversationType === 'group' ? ( -
- - -
- ) : null; - - if ( - conversationType === 'direct' && - (sharedGroupNames?.length ?? 0) === 0 && - acceptedMessageRequest && - phoneNumber - ) { - return null; - } - - // Check if we should show anything at all - const shouldShowAnything = - Boolean(reviewCarefullyLabel) || - Boolean(nameNotVerifiedLabel) || - Boolean(sharedGroupsLabel) || - Boolean(safetyTipsButton) || - Boolean(membersCountLabel); - - if (!shouldShowAnything) { - return null; - } - - return ( -
- {reviewCarefullyLabel} - {nameNotVerifiedLabel} - {sharedGroupsLabel} - {membersCountLabel} - {safetyTipsButton} -
- ); -}; - -function ReleaseNotesExtraInformation({ - i18n, -}: { - i18n: LocalizerType; -}): React.JSX.Element { - return ( -
-
- - {i18n('icu:ConversationHero--signal-official-chat')} -
-
- - {i18n('icu:ConversationHero--release-notes')} -
-
- ); -} +type DistributiveOmit = T extends unknown + ? Omit + : never; export function ConversationHero({ avatarPlaceholderGradient, i18n, - about, acceptedMessageRequest, avatarUrl, badge, @@ -241,26 +61,26 @@ export function ConversationHero({ fromOrAddedByTrustedContact, groupDescription, hasAvatar, + hasNickname, + hasProfileName, hasStories, id, - isDirectConvoAndHasNickname, + isInSystemContacts, isMe, invitesCount, openConversationDetails, isSignalConversation, - membersCount, memberships, pendingAvatarDownload, - sharedGroupNames = [], - phoneNumber, profileName, + sharedGroupNames = [], startAvatarDownload, theme, title, viewUserStories, toggleAboutContactModal, toggleProfileNameWarningModal, -}: Props): React.JSX.Element { +}: Props): React.JSX.Element | null { const [isShowingSafetyTips, setIsShowingSafetyTips] = useState(false); let avatarBlur: AvatarBlur = AvatarBlur.NoBlur; @@ -282,71 +102,129 @@ export function ConversationHero({ }; } - let titleElem: React.JSX.Element | undefined; + const maybeSafetyTips = isShowingSafetyTips ? ( + { + setIsShowingSafetyTips(false); + }} + /> + ) : null; + + const avatar = ( + + ); if (isMe) { - titleElem = ( - - ); - } else if (isSignalConversation || conversationType !== 'direct') { - titleElem = ( - - ); - } else if (title) { - titleElem = ( - + return ( + + {avatar} + + <div + className={tw( + 'mt-2 text-center type-body-medium text-label-secondary' + )} + > + {i18n('icu:noteToSelfHero')} + </div> + </Root> ); } - return ( - <> - <div className="module-conversation-hero"> - <Avatar - avatarPlaceholderGradient={avatarPlaceholderGradient} - avatarUrl={avatarUrl} - badge={badge} - blur={avatarBlur} - className="module-conversation-hero__avatar" - color={color} - conversationType={conversationType} - i18n={i18n} - hasAvatar={hasAvatar} - loading={pendingAvatarDownload && !avatarUrl} - noteToSelf={isMe} - onClick={avatarOnClick} - profileName={profileName} - size={AvatarSize.EIGHTY} - // user may have stories, but we don't show that on Note to Self conversation - storyRing={isMe ? undefined : hasStories} - theme={theme} + if (isSignalConversation) { + return ( + <Root> + {avatar} + <Title title={title} isSignalConversation /> + <div + className={tw( + 'my-2 rounded-3xl bg-color-fill-primary/12 px-2.5 py-1 type-body-medium font-medium text-color-fill-primary' + )} + > + <AxoSymbol.InlineGlyph symbol="officialbadge" label={null} /> +  {i18n('icu:ConversationHero--signal-official-account')} + </div> + <div className={tw('text-center type-body-medium text-label-primary')}> + {i18n('icu:ConversationHero--signal-official-account--description')} + </div> + </Root> + ); + } + + if (conversationType === 'direct') { + const nameIsVerified = hasNickname || isInSystemContacts; + return ( + <Root> + {avatar} + <Title title={title} + onClick={() => toggleAboutContactModal({ contactId: id })} /> - <h1 className="module-conversation-hero__profile-name">{titleElem}</h1> - {about && !isMe && ( - <div className="module-about__container"> - <About text={about} /> - </div> - )} - {!isMe && groupDescription ? ( - <div className="module-conversation-hero__with"> + + {hasProfileName && !nameIsVerified ? ( + <NameNotVerifiedWarning + conversationType={conversationType} + onClick={() => toggleProfileNameWarningModal(conversationType)} + i18n={i18n} + /> + ) : null} + + <div + className={tw( + 'mt-2.5 text-center type-body-medium text-label-primary' + )} + > + <AxoSymbol.InlineGlyph symbol="group" label={null} /> +   + <SharedGroupNames + i18n={i18n} + sharedGroupNames={sharedGroupNames ?? []} + /> + </div> + + {!acceptedMessageRequest ? ( + <SafetyTips + onShowSafetyTips={() => setIsShowingSafetyTips(true)} + i18n={i18n} + /> + ) : null} + {maybeSafetyTips} + </Root> + ); + } + + if (conversationType === 'group') { + const nameIsVerified = Boolean(fromOrAddedByTrustedContact); + return ( + <Root> + {avatar} + <Title title={title} /> + {!nameIsVerified ? ( + <NameNotVerifiedWarning + conversationType={conversationType} + onClick={() => toggleProfileNameWarningModal(conversationType)} + i18n={i18n} + /> + ) : null} + + {groupDescription ? ( + <div className={tw('mt-2 w-full text-center text-label-secondary')}> <GroupDescription i18n={i18n} title={title} @@ -354,38 +232,140 @@ export function ConversationHero({ /> </div> ) : null} - {!isSignalConversation && - renderExtraInformation({ - acceptedMessageRequest, - conversationType, - fromOrAddedByTrustedContact, - i18n, - isDirectConvoAndHasNickname, - isMe, - invitesCount, - membersCount, - memberships, - onClickProfileNameWarning() { - toggleProfileNameWarningModal(conversationType); - }, - onToggleSafetyTips(showSafetyTips: boolean) { - setIsShowingSafetyTips(showSafetyTips); - }, - openConversationDetails, - phoneNumber, - sharedGroupNames: sharedGroupNames ?? [], - })} - {isSignalConversation && <ReleaseNotesExtraInformation i18n={i18n} />} - </div> - {isShowingSafetyTips && ( - <SafetyTipsModal - i18n={i18n} - onClose={() => { - setIsShowingSafetyTips(false); - }} - /> - )} - </> - ); + <div + className={tw( + 'mt-2.5 w-full text-center type-body-medium text-label-primary' + )} + > + <AxoSymbol.InlineGlyph symbol="group" label={null} /> +   + <GroupMembersNames + i18n={i18n} + memberships={memberships} + invitesCount={invitesCount} + onOtherMembersClick={openConversationDetails} + /> + </div> + {!acceptedMessageRequest ? ( + <SafetyTips + onShowSafetyTips={() => setIsShowingSafetyTips(true)} + i18n={i18n} + /> + ) : null} + {maybeSafetyTips} + </Root> + ); + } + return null; } + +type RootProps = { + children: ReactNode; +}; +const Root: React.FC<RootProps> = props => { + return ( + <div + data-testid="conversation-hero" + className={tw( + 'flex w-3xs flex-col items-center rounded-4xl border-2 border-background-secondary p-5 pt-0' + )} + > + {props.children} + </div> + ); +}; + +const ConversationAvatar: React.FC< + DistributiveOmit<AvatarProps, 'size'> +> = props => { + return ( + <Avatar + {...props} + size={AvatarSize.SEVENTY_TWO} + className={tw('-mt-4.5')} + /> + ); +}; + +type TitleProps = { + isMe?: boolean; + isSignalConversation?: boolean; + title: string; + onClick?: () => void; +}; + +const Title: React.FC<TitleProps> = props => { + const className = tw('mt-3 text-center text-[20px] font-medium'); + const { onClick, title, isMe, isSignalConversation } = props; + const contactName = ( + <ContactName + title={title} + isMe={isMe} + isSignalConversation={isSignalConversation} + /> + ); + + if (onClick) { + return ( + <button + type="button" + className={className} + onClick={ev => { + ev.preventDefault(); + onClick(); + }} + > + {contactName} +   + <span className={tw('text-[18px] text-label-secondary')}> + <AxoSymbol.InlineGlyph symbol="chevron-[end]" label={null} /> + </span> + </button> + ); + } + + return <div className={className}>{contactName}</div>; +}; + +const NameNotVerifiedWarning: React.FC<{ + conversationType: 'direct' | 'group'; + onClick: () => void; + i18n: LocalizerType; +}> = ({ conversationType, onClick, i18n }) => { + return ( + <button + className={tw( + 'mt-2 rounded-3xl bg-color-fill-destructive/12 px-2.5 py-1', + // oxlint-disable-next-line better-tailwindcss/no-restricted-classes + 'type-body-medium font-medium text-[#C84118]' + )} + type="button" + onClick={ev => { + ev.preventDefault(); + onClick(); + }} + > + {conversationType === 'direct' ? ( + <AxoSymbol.InlineGlyph symbol="person-question" label={null} /> + ) : ( + // TODO: DESKTOP-10050 + <AxoSymbol.InlineGlyph symbol="person-question" label={null} /> + )} +   {i18n('icu:ConversationHero--name-not-verified')} + </button> + ); +}; + +const SafetyTips: React.FC<{ + onShowSafetyTips: () => void; + i18n: LocalizerType; +}> = ({ i18n, onShowSafetyTips }) => { + return ( + <div className={tw('mt-3')}> + <AxoButton.Root variant="secondary" size="md" onClick={onShowSafetyTips}> + {i18n('icu:MessageRequestWarning__safety-tips-v2')} + </AxoButton.Root> + </div> + ); +}; diff --git a/ts/components/conversation/ProfileNameWarningModal.dom.tsx b/ts/components/conversation/ProfileNameWarningModal.dom.tsx index b9a3814647..28fdc7b131 100644 --- a/ts/components/conversation/ProfileNameWarningModal.dom.tsx +++ b/ts/components/conversation/ProfileNameWarningModal.dom.tsx @@ -2,8 +2,10 @@ // SPDX-License-Identifier: AGPL-3.0-only import React from 'react'; -import { Modal } from '../Modal.dom.tsx'; import type { LocalizerType } from '../../types/Util.std.ts'; +import { AxoDialog } from '../../axo/AxoDialog.dom.tsx'; +import { AxoSymbol } from '../../axo/AxoSymbol.dom.tsx'; +import { tw } from '../../axo/tw.dom.tsx'; export type PropsType = Readonly<{ conversationType: 'group' | 'direct'; @@ -11,60 +13,80 @@ export type PropsType = Readonly<{ onClose: () => void; }>; -const DESCRIPTION_KEYS = { - direct: 'icu:ProfileNameWarningModal__description--direct', - group: 'icu:ProfileNameWarningModal__description--group', -} as const; - -const LIST_ITEM_KEYS = { - item1: { - direct: 'icu:ProfileNameWarningModal__list--item1--direct', - group: 'icu:ProfileNameWarningModal__list--item1--group', - }, - item2: { - direct: 'icu:ProfileNameWarningModal__list--item2--direct', - group: 'icu:ProfileNameWarningModal__list--item2--group', - }, - item3: { - direct: 'icu:ProfileNameWarningModal__list--item3--direct', - group: 'icu:ProfileNameWarningModal__list--item3--group', - }, -} as const; - export function ProfileNameWarningModal({ conversationType, i18n, onClose, }: PropsType): React.JSX.Element { return ( - <Modal - modalName="ProfileNameWarningModal" - moduleClassName="ProfileNameWarningModal" - hasXButton - i18n={i18n} - onClose={onClose} - > - <i className="ProfileNameWarningModal__header-icon" /> - <div className="ProfileNameWarningModal__description"> - {i18n(DESCRIPTION_KEYS[conversationType])} - </div> - <ul className="ProfileNameWarningModal__list"> - <li className="ProfileNameWarningModal__list-item"> - <span className="ProfileNameWarningModal__list-item-text"> - {i18n(LIST_ITEM_KEYS.item1[conversationType])} - </span> - </li> - <li className="ProfileNameWarningModal__list-item"> - <span className="ProfileNameWarningModal__list-item-text"> - {i18n(LIST_ITEM_KEYS.item2[conversationType])} - </span> - </li> - <li className="ProfileNameWarningModal__list-item"> - <span className="ProfileNameWarningModal__list-item-text"> - {i18n(LIST_ITEM_KEYS.item3[conversationType])} - </span> - </li> - </ul> - </Modal> + <AxoDialog.Root open onOpenChange={onClose}> + <AxoDialog.Content + size="sm" + escape="cancel-is-noop" + disableMissingAriaDescriptionWarning + > + <AxoDialog.Header> + <AxoDialog.Close aria-label={i18n('icu:close')} /> + </AxoDialog.Header> + <AxoDialog.Body padding="normal"> + <div className={tw('flex justify-center')}> + <div + className={tw( + // oxlint-disable-next-line better-tailwindcss/no-restricted-classes + 'rounded-3xl bg-color-fill-destructive/12 px-4 py-1.5 type-title-large font-regular text-[#C84118]' + )} + > + {conversationType === 'direct' ? ( + <AxoSymbol.InlineGlyph symbol="person-question" label={null} /> + ) : ( + <AxoSymbol.InlineGlyph symbol="person-question" label={null} /> + )} + </div> + </div> + <div className={tw('mt-5 mb-12 type-body-medium text-label-primary')}> + {conversationType === 'direct' ? ( + <> + {i18n('icu:ProfileNameWarningModal__description--direct')} + <ul className={tw('list-disc ps-4 [&>li]:mt-3')}> + <li> + {i18n( + 'icu:ProfileNameWarningModal__warning--signal-cant-verify' + )} + </li> + <li> + {i18n( + 'icu:ProfileNameWarningModal__warning--signal-wont-contact' + )} + </li> + <li> + {i18n('icu:ProfileNameWarningModal__warning--be-cautious')} + </li> + <li> + {i18n( + 'icu:ProfileNameWarningModal__warning--dont-share-info' + )} + </li> + </ul> + </> + ) : ( + <> + {i18n('icu:ProfileNameWarningModal__description--group')} + <ul className={tw('list-disc ps-4 [&>li]:mt-3')}> + <li> + {i18n('icu:ProfileNameWarningModal__list--item1--group')} + </li> + <li> + {i18n('icu:ProfileNameWarningModal__list--item2--group')} + </li> + <li> + {i18n('icu:ProfileNameWarningModal__list--item3--group')} + </li> + </ul> + </> + )} + </div> + </AxoDialog.Body> + </AxoDialog.Content> + </AxoDialog.Root> ); } diff --git a/ts/components/conversation/Timeline.dom.stories.tsx b/ts/components/conversation/Timeline.dom.stories.tsx index 4f22e0f570..358bcdc969 100644 --- a/ts/components/conversation/Timeline.dom.stories.tsx +++ b/ts/components/conversation/Timeline.dom.stories.tsx @@ -411,9 +411,12 @@ const renderHeroRow = () => { avatarUrl={getAvatarPath()} badge={undefined} conversationType="direct" + hasNickname={false} + hasProfileName id={getDefaultConversation().id} i18n={i18n} isMe={false} + isInSystemContacts={false} phoneNumber={getPhoneNumber()} profileName={getProfileName()} sharedGroupNames={['NYC Rock Climbers', 'Dinner Party']} diff --git a/ts/state/smart/HeroRow.preload.tsx b/ts/state/smart/HeroRow.preload.tsx index a65841936c..d136a9868b 100644 --- a/ts/state/smart/HeroRow.preload.tsx +++ b/ts/state/smart/HeroRow.preload.tsx @@ -23,6 +23,8 @@ import { useStoriesActions } from '../ducks/stories.preload.ts'; import { getAddedByForGroup } from '../../util/getAddedByForGroup.preload.ts'; import { getGroupMemberships } from '../../util/getGroupMemberships.dom.ts'; import { useNavActions } from '../ducks/nav.std.ts'; +import { tw } from '../../axo/tw.dom.tsx'; +import { isInSystemContacts } from '../../util/isInSystemContacts.std.ts'; type SmartHeroRowProps = Readonly<{ id: string; @@ -83,7 +85,6 @@ export const SmartHeroRow = memo(function SmartHeroRow({ const { viewUserStories } = useStoriesActions(); const { avatarPlaceholderGradient, - about, acceptedMessageRequest, avatarUrl, color, @@ -93,50 +94,46 @@ export const SmartHeroRow = memo(function SmartHeroRow({ membersCount, nicknameGivenName, nicknameFamilyName, - phoneNumber, profileName, title, type, } = conversation; - - const isDirectConvoAndHasNickname = - type === 'direct' && Boolean(nicknameGivenName || nicknameFamilyName); - const invitesCount = pendingMemberships.length + pendingApprovalMemberships.length; - return ( - <ConversationHero - avatarPlaceholderGradient={avatarPlaceholderGradient} - about={about} - acceptedMessageRequest={acceptedMessageRequest} - avatarUrl={avatarUrl} - badge={badge} - color={color} - conversationType={type} - fromOrAddedByTrustedContact={fromOrAddedByTrustedContact} - groupDescription={groupDescription} - hasAvatar={hasAvatar} - hasStories={hasStories} - i18n={i18n} - id={id} - isDirectConvoAndHasNickname={isDirectConvoAndHasNickname} - isMe={isMe} - invitesCount={invitesCount} - isSignalConversation={isSignalConversationValue} - membersCount={membersCount} - memberships={memberships} - openConversationDetails={openConversationDetails} - pendingAvatarDownload={isPendingAvatarDownload(id)} - phoneNumber={phoneNumber} - profileName={profileName} - sharedGroupNames={sharedGroupNames} - startAvatarDownload={() => startAvatarDownload(id)} - theme={theme} - title={title} - toggleAboutContactModal={toggleAboutContactModal} - toggleProfileNameWarningModal={toggleProfileNameWarningModal} - viewUserStories={viewUserStories} - /> + <div className={tw('mt-10 flex justify-center')}> + <ConversationHero + avatarPlaceholderGradient={avatarPlaceholderGradient} + acceptedMessageRequest={acceptedMessageRequest} + avatarUrl={avatarUrl} + badge={badge} + color={color} + conversationType={type} + fromOrAddedByTrustedContact={fromOrAddedByTrustedContact} + groupDescription={groupDescription} + hasAvatar={hasAvatar} + hasNickname={Boolean(nicknameGivenName || nicknameFamilyName)} + hasProfileName={Boolean(profileName)} + hasStories={hasStories} + i18n={i18n} + id={id} + isMe={isMe} + invitesCount={invitesCount} + isInSystemContacts={isInSystemContacts(conversation)} + isSignalConversation={isSignalConversationValue} + membersCount={membersCount} + memberships={memberships} + openConversationDetails={openConversationDetails} + pendingAvatarDownload={isPendingAvatarDownload(id)} + profileName={profileName} + sharedGroupNames={sharedGroupNames} + startAvatarDownload={() => startAvatarDownload(id)} + theme={theme} + title={title} + toggleAboutContactModal={toggleAboutContactModal} + toggleProfileNameWarningModal={toggleProfileNameWarningModal} + viewUserStories={viewUserStories} + /> + </div> ); }); diff --git a/ts/test-mock/messaging/edit_test.node.ts b/ts/test-mock/messaging/edit_test.node.ts index 93a26bc226..9ddfb93249 100644 --- a/ts/test-mock/messaging/edit_test.node.ts +++ b/ts/test-mock/messaging/edit_test.node.ts @@ -201,7 +201,7 @@ describe('editing', function (this: Mocha.Suite) { .locator('.module-conversation-list__item--contact-or-conversation') .first() .click(); - await window.locator('.module-conversation-hero').waitFor(); + await window.getByTestId('conversation-hero').waitFor(); debug('checking for message'); await window @@ -272,7 +272,7 @@ describe('editing', function (this: Mocha.Suite) { .locator('.module-conversation-list__item--contact-or-conversation') .first() .click(); - await window.locator('.module-conversation-hero').waitFor(); + await window.getByTestId('conversation-hero').waitFor(); debug('checking for message'); await window @@ -352,7 +352,7 @@ describe('editing', function (this: Mocha.Suite) { .locator('.module-conversation-list__item--contact-or-conversation') .first() .click(); - await window.locator('.module-conversation-hero').waitFor(); + await window.getByTestId('conversation-hero').waitFor(); debug('checking for message'); await window.locator('.module-message__text >> "hello"').waitFor(); @@ -494,7 +494,7 @@ describe('editing', function (this: Mocha.Suite) { .locator('.module-conversation-list__item--contact-or-conversation') .first() .click(); - await window.locator('.module-conversation-hero').waitFor(); + await window.getByTestId('conversation-hero').waitFor(); debug('checking for latest message'); await window.locator('.module-message__text >> "v5"').waitFor(); @@ -540,7 +540,7 @@ describe('editing', function (this: Mocha.Suite) { .locator('.module-conversation-list__item--contact-or-conversation') .first() .click(); - await window.locator('.module-conversation-hero').waitFor(); + await window.getByTestId('conversation-hero').waitFor(); debug('checking for latest message'); await window.locator('.module-message__text >> "v2"').waitFor(); @@ -583,7 +583,7 @@ describe('editing', function (this: Mocha.Suite) { .locator('.module-conversation-list__item--contact-or-conversation') .first() .click(); - await page.locator('.module-conversation-hero').waitFor(); + await page.getByTestId('conversation-hero').waitFor(); const { dataMessage: profileKeyMsg } = await friend.waitForMessage(); assert(profileKeyMsg.profileKey != null, 'Profile key message'); @@ -894,7 +894,7 @@ describe('editing', function (this: Mocha.Suite) { .locator('.module-conversation-list__item--contact-or-conversation') .first() .click(); - await window.locator('.module-conversation-hero').waitFor(); + await window.getByTestId('conversation-hero').waitFor(); debug('checking for latest message'); await window.locator('.module-message__text >> "v2"').waitFor(); @@ -966,7 +966,7 @@ describe('editing', function (this: Mocha.Suite) { .locator('.module-conversation-list__item--contact-or-conversation') .first() .click(); - await window.locator('.module-conversation-hero').waitFor(); + await window.getByTestId('conversation-hero').waitFor(); debug('checking for latest message'); await window.locator('.module-message__text >> "v5"').waitFor(); diff --git a/ts/test-mock/messaging/expire_timer_version_test.node.ts b/ts/test-mock/messaging/expire_timer_version_test.node.ts index 0bde8ed3a6..e8c365ee66 100644 --- a/ts/test-mock/messaging/expire_timer_version_test.node.ts +++ b/ts/test-mock/messaging/expire_timer_version_test.node.ts @@ -273,7 +273,7 @@ describe('messaging/expireTimerVersion', function (this: Mocha.Suite) { await expectSystemMessages(window, scenario.systemMessages); - await window.locator('.module-conversation-hero').waitFor(); + await window.getByTestId('conversation-hero').waitFor(); debug('Send message to merged contact'); { @@ -304,7 +304,7 @@ describe('messaging/expireTimerVersion', function (this: Mocha.Suite) { ) .click(); - await window.locator('.module-conversation-hero').waitFor(); + await window.getByTestId('conversation-hero').waitFor(); const conversationStack = window.locator('.Inbox__conversation-stack'); diff --git a/ts/test-mock/pnp/merge_test.node.ts b/ts/test-mock/pnp/merge_test.node.ts index cdbbe30c51..db98be9910 100644 --- a/ts/test-mock/pnp/merge_test.node.ts +++ b/ts/test-mock/pnp/merge_test.node.ts @@ -132,7 +132,7 @@ describe('pnp/merge', function (this: Mocha.Suite) { .locator(`[data-testid="${pniContact.device.aci}"]`) .click(); - await window.locator('.module-conversation-hero').waitFor(); + await window.getByTestId('conversation-hero').waitFor(); debug('Send message to ACI'); { @@ -148,7 +148,7 @@ describe('pnp/merge', function (this: Mocha.Suite) { .first() .click(); - await window.locator('.module-conversation-hero').waitFor(); + await window.getByTestId('conversation-hero').waitFor(); debug('Verify starting state'); { @@ -175,7 +175,7 @@ describe('pnp/merge', function (this: Mocha.Suite) { .locator(`[data-testid="${pniContact.device.aci}"]`) .click(); - await window.locator('.module-conversation-hero').waitFor(); + await window.getByTestId('conversation-hero').waitFor(); } debug( @@ -272,7 +272,7 @@ describe('pnp/merge', function (this: Mocha.Suite) { ) .click(); - await window.locator('.module-conversation-hero').waitFor(); + await window.getByTestId('conversation-hero').waitFor(); debug('Send message to merged contact'); { @@ -377,7 +377,7 @@ describe('pnp/merge', function (this: Mocha.Suite) { ) .click(); - await window.locator('.module-conversation-hero').waitFor(); + await window.getByTestId('conversation-hero').waitFor(); debug('Unregistering ACI'); server.unregister(pniContact); @@ -460,7 +460,8 @@ describe('pnp/merge', function (this: Mocha.Suite) { debug('Wait for ACI conversation to go away'); await window - .locator(`.module-conversation-hero >> "${pniContact.profileName}"`) + .getByTestId('conversation-hero') + .getByText(pniContact.profileName) .waitFor({ state: 'hidden', }); @@ -522,7 +523,7 @@ describe('pnp/merge', function (this: Mocha.Suite) { ) .click(); - await window.locator('.module-conversation-hero').waitFor(); + await window.getByTestId('conversation-hero').waitFor(); debug('Verify that the message is in the ACI conversation'); { @@ -638,7 +639,7 @@ describe('pnp/merge', function (this: Mocha.Suite) { ) .click(); - await window.locator('.module-conversation-hero').waitFor(); + await window.getByTestId('conversation-hero').waitFor(); debug('Send message to merged contact'); { diff --git a/ts/test-mock/pnp/phone_discovery_test.node.ts b/ts/test-mock/pnp/phone_discovery_test.node.ts index 46914a5682..25ddbb5d0c 100644 --- a/ts/test-mock/pnp/phone_discovery_test.node.ts +++ b/ts/test-mock/pnp/phone_discovery_test.node.ts @@ -127,18 +127,11 @@ describe('pnp/phone discovery', function (this: Mocha.Suite) { }); } - await window.locator('.module-conversation-hero').waitFor(); + await window.getByTestId('conversation-hero').waitFor(); debug('Open ACI conversation'); await leftPane.locator(`[data-testid="${pniContact.device.aci}"]`).click(); - debug('Wait for PNI conversation to go away'); - await window - .locator(`.module-conversation-hero >> ${pniContact.profileName}`) - .waitFor({ - state: 'hidden', - }); - debug('Verify final state'); { // Should have PNI message diff --git a/ts/test-mock/pnp/pni_change_test.node.ts b/ts/test-mock/pnp/pni_change_test.node.ts index d08573f282..95769a285e 100644 --- a/ts/test-mock/pnp/pni_change_test.node.ts +++ b/ts/test-mock/pnp/pni_change_test.node.ts @@ -93,7 +93,7 @@ describe('pnp/PNI Change', function (this: Mocha.Suite) { ) .click(); - await window.locator('.module-conversation-hero').waitFor(); + await window.getByTestId('conversation-hero').waitFor(); } debug('Verify starting state'); @@ -198,7 +198,7 @@ describe('pnp/PNI Change', function (this: Mocha.Suite) { ) .click(); - await window.locator('.module-conversation-hero').waitFor(); + await window.getByTestId('conversation-hero').waitFor(); } debug('Verify starting state'); @@ -307,7 +307,7 @@ describe('pnp/PNI Change', function (this: Mocha.Suite) { ) .click(); - await window.locator('.module-conversation-hero').waitFor(); + await window.getByTestId('conversation-hero').waitFor(); } debug('Verify starting state'); @@ -446,7 +446,7 @@ describe('pnp/PNI Change', function (this: Mocha.Suite) { ) .click(); - await window.locator('.module-conversation-hero').waitFor(); + await window.getByTestId('conversation-hero').waitFor(); } debug('Verify starting state'); diff --git a/ts/test-mock/pnp/username_test.node.ts b/ts/test-mock/pnp/username_test.node.ts index 3683219635..e36e0da8d3 100644 --- a/ts/test-mock/pnp/username_test.node.ts +++ b/ts/test-mock/pnp/username_test.node.ts @@ -381,7 +381,8 @@ describe('pnp/username', function (this: Mocha.Suite) { debug('waiting for conversation to open'); await window - .locator(`.module-conversation-hero >> "${CARL_USERNAME}"`) + .getByTestId('conversation-hero') + .getByText(CARL_USERNAME) .waitFor(); debug('sending a message');