From 7bf1b2b8783a86acf56bce8790f762cd2c992a5f Mon Sep 17 00:00:00 2001 From: Alexander Zinchuk Date: Fri, 8 Mar 2024 12:48:44 +0100 Subject: [PATCH] Contact: New design for shared contact (#4333) --- src/components/common/PeerColorWrapper.tsx | 35 ++++++++ .../middle/message/Contact.module.scss | 83 ++++++++++++++++++ src/components/middle/message/Contact.scss | 38 --------- src/components/middle/message/Contact.tsx | 85 ++++++++++++++----- 4 files changed, 184 insertions(+), 57 deletions(-) create mode 100644 src/components/common/PeerColorWrapper.tsx create mode 100644 src/components/middle/message/Contact.module.scss delete mode 100644 src/components/middle/message/Contact.scss diff --git a/src/components/common/PeerColorWrapper.tsx b/src/components/common/PeerColorWrapper.tsx new file mode 100644 index 000000000..8f0b3e83e --- /dev/null +++ b/src/components/common/PeerColorWrapper.tsx @@ -0,0 +1,35 @@ +import React, { memo } from '../../lib/teact/teact'; + +import type { ApiPeer } from '../../api/types'; + +import buildClassName from '../../util/buildClassName'; +import { getPeerColorClass } from './helpers/peerColor'; + +import EmojiIconBackground from './embedded/EmojiIconBackground'; + +type OwnProps = { + peer?: ApiPeer; + noUserColors?: boolean; + shoudReset?: boolean; + className?: string; + emojiIconClassName?: string; + children: React.ReactNode; +}; + +function PeerColorWrapper({ + peer, noUserColors, shoudReset, className, emojiIconClassName, children, +}: OwnProps) { + return ( +
+ {peer?.color?.backgroundEmojiId && ( + + )} + {children} +
+ ); +} + +export default memo(PeerColorWrapper); diff --git a/src/components/middle/message/Contact.module.scss b/src/components/middle/message/Contact.module.scss new file mode 100644 index 000000000..e3c67136a --- /dev/null +++ b/src/components/middle/message/Contact.module.scss @@ -0,0 +1,83 @@ +.root { + position: relative; + margin: 0.25rem 0.25rem 0.875rem 0.25rem; + border-radius: 0.25rem; + overflow: hidden; + background-color: var(--accent-background-color); + color: var(--accent-color); + + &::before { + content: ""; + display: block; + position: absolute; + top: 0; + bottom: 0; + inset-inline-start: 0; + width: 0.1875rem; + background: var(--bar-gradient, var(--accent-color)); + } +} + +.info-container { + display: flex; + padding: 0.5rem 1.5rem 0.5rem 0.75rem; + cursor: var(--custom-cursor, pointer); +} + +.info { + display: flex; + flex-direction: column; + align-self: center; + margin-left: 0.5rem; +} + +.name { + font-size: 1rem; + margin-bottom: 0.25rem; + font-weight: 500; + max-width: 12.5rem; +} + +.phone { + color: var(--color-text); +} + +.name, +.phone { + line-height: 1rem; + overflow: hidden; + white-space: nowrap; + text-overflow: ellipsis; +} + +.divider { + height: 0.0625rem; + margin: 0 0.5rem; + background: var(--accent-color); + filter: opacity(0.4) +} + +.buttons { + display: flex; + + .button { + width: auto; + flex: 1; + height: 2.25rem; + border-radius: 0; + font-weight: 500; + background-color: transparent; + color: var(--accent-color); + --ripple-color: var(--accent-background-active-color); + + &:not(.disabled):not(:disabled):hover { + color: var(--accent-color); + background-color: transparent; + } + } +} + +.emoji-icon-background { + margin-bottom: 2.25rem; +} + \ No newline at end of file diff --git a/src/components/middle/message/Contact.scss b/src/components/middle/message/Contact.scss deleted file mode 100644 index a57e0f815..000000000 --- a/src/components/middle/message/Contact.scss +++ /dev/null @@ -1,38 +0,0 @@ -.Contact { - display: flex; - align-items: center; - padding: 0.25rem; - - &.interactive { - cursor: var(--custom-cursor, pointer); - } - - .Avatar { - margin-right: 0.8125rem; - } - - .contact-info { - padding: 0.5rem; - padding-left: 0; - white-space: nowrap; - overflow: hidden; - - .contact-name { - font-size: 1rem; - margin-bottom: 0.25rem; - font-weight: 500; - } - - .contact-phone { - color: var(--secondary-color); - } - - .contact-name, - .contact-phone { - line-height: 1rem; - overflow: hidden; - white-space: nowrap; - text-overflow: ellipsis; - } - } -} diff --git a/src/components/middle/message/Contact.tsx b/src/components/middle/message/Contact.tsx index 6bff7fd96..cdd617af4 100644 --- a/src/components/middle/message/Contact.tsx +++ b/src/components/middle/message/Contact.tsx @@ -4,15 +4,19 @@ import { getActions, withGlobal } from '../../../global'; import type { ApiContact, ApiCountryCode, ApiUser } from '../../../api/types'; +import { getCanAddContact, getUserFullName } from '../../../global/helpers'; import { selectUser } from '../../../global/selectors'; -import buildClassName from '../../../util/buildClassName'; +import { copyTextToClipboard } from '../../../util/clipboard'; import { formatPhoneNumberWithCode } from '../../../util/phoneNumber'; +import useLang from '../../../hooks/useLang'; import useLastCallback from '../../../hooks/useLastCallback'; import Avatar from '../../common/Avatar'; +import PeerColorWrapper from '../../common/PeerColorWrapper'; +import Button from '../../ui/Button'; -import './Contact.scss'; +import styles from './Contact.module.scss'; type OwnProps = { contact: ApiContact; @@ -28,38 +32,81 @@ const UNREGISTERED_CONTACT_ID = '0'; const Contact: FC = ({ contact, user, phoneCodeList, }) => { - const { openChat } = getActions(); + const lang = useLang(); + const { + openChat, openAddContactDialog, showNotification, openChatWithInfo, + } = getActions(); const { - firstName, - lastName, phoneNumber, userId, } = contact; const isRegistered = userId !== UNREGISTERED_CONTACT_ID; + const canAddContact = isRegistered && user && getCanAddContact(user); - const handleClick = useLastCallback(() => { + const handleOpenChat = useLastCallback(() => { openChat({ id: userId }); }); + const handleAddContact = useLastCallback(() => { + openAddContactDialog({ userId: user?.id }); + }); + + const handleClick = useLastCallback(() => { + if (user) { + openChatWithInfo({ id: userId }); + } else { + copyTextToClipboard(phoneNumber); + showNotification({ message: lang('PhoneCopied') }); + } + }); + return ( -
- -
-
{firstName} {lastName}
-
{formatPhoneNumberWithCode(phoneCodeList, phoneNumber)}
+ +
+ +
+
+ {user ? getUserFullName(user) : getContactName(contact)} +
+
{formatPhoneNumberWithCode(phoneCodeList, phoneNumber)}
+
-
+ {isRegistered && ( + <> +
+
+ + {canAddContact && ( + + )} +
+ + )} + ); }; +function getContactName(contact: ApiContact) { + if (contact.firstName && contact.lastName) { + return `${contact.firstName} ${contact.lastName}`; + } + + if (contact.firstName) { + return contact.firstName; + } + + if (contact.lastName) { + return contact.lastName; + } + + return ''; +} + export default withGlobal( (global, { contact }): StateProps => { const { countryList: { phoneCodes: phoneCodeList } } = global;