| 
									
										
										
										
											2021-02-23 14:34:28 -06:00
										 |  |  | // Copyright 2021 Signal Messenger, LLC
 | 
					
						
							|  |  |  | // SPDX-License-Identifier: AGPL-3.0-only
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-10-26 14:15:33 -05:00
										 |  |  | import type { FunctionComponent } from 'react'; | 
					
						
							| 
									
										
										
										
											2023-04-05 13:48:00 -07:00
										 |  |  | import React, { useMemo, useState } from 'react'; | 
					
						
							| 
									
										
										
										
											2021-02-23 14:34:28 -06:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-01-25 16:51:08 -07:00
										 |  |  | import { HEADER_CONTACT_NAME_CLASS_NAME } from './BaseConversationListItem'; | 
					
						
							| 
									
										
										
										
											2021-10-26 14:15:33 -05:00
										 |  |  | import type { ConversationType } from '../../state/ducks/conversations'; | 
					
						
							| 
									
										
										
										
											2021-11-17 15:11:21 -06:00
										 |  |  | import type { BadgeType } from '../../badges/types'; | 
					
						
							|  |  |  | import type { LocalizerType, ThemeType } from '../../types/Util'; | 
					
						
							| 
									
										
										
										
											2021-02-23 14:34:28 -06:00
										 |  |  | import { ContactName } from '../conversation/ContactName'; | 
					
						
							|  |  |  | import { About } from '../conversation/About'; | 
					
						
							| 
									
										
										
										
											2023-01-25 16:51:08 -07:00
										 |  |  | import { ListTile } from '../ListTile'; | 
					
						
							|  |  |  | import { Avatar, AvatarSize } from '../Avatar'; | 
					
						
							| 
									
										
										
										
											2023-04-05 13:48:00 -07:00
										 |  |  | import { ContextMenu } from '../ContextMenu'; | 
					
						
							|  |  |  | import { Intl } from '../Intl'; | 
					
						
							|  |  |  | import { ConfirmationDialog } from '../ConfirmationDialog'; | 
					
						
							| 
									
										
										
										
											2022-11-08 21:38:19 -05:00
										 |  |  | import { isSignalConversation } from '../../util/isSignalConversation'; | 
					
						
							| 
									
										
										
										
											2023-04-05 13:48:00 -07:00
										 |  |  | import { isInSystemContacts } from '../../util/isInSystemContacts'; | 
					
						
							| 
									
										
										
										
											2021-02-23 14:34:28 -06:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-11-17 15:11:21 -06:00
										 |  |  | export type ContactListItemConversationType = Pick< | 
					
						
							| 
									
										
										
										
											2021-04-30 14:40:25 -05:00
										 |  |  |   ConversationType, | 
					
						
							|  |  |  |   | 'about' | 
					
						
							|  |  |  |   | 'acceptedMessageRequest' | 
					
						
							|  |  |  |   | 'avatarPath' | 
					
						
							| 
									
										
										
										
											2021-11-17 15:11:21 -06:00
										 |  |  |   | 'badges' | 
					
						
							| 
									
										
										
										
											2021-04-30 14:40:25 -05:00
										 |  |  |   | 'color' | 
					
						
							| 
									
										
										
										
											2023-01-12 19:24:59 -05:00
										 |  |  |   | 'groupId' | 
					
						
							| 
									
										
										
										
											2021-04-30 14:40:25 -05:00
										 |  |  |   | 'id' | 
					
						
							| 
									
										
										
										
											2023-04-05 13:48:00 -07:00
										 |  |  |   | 'name' | 
					
						
							| 
									
										
										
										
											2021-04-30 14:40:25 -05:00
										 |  |  |   | 'isMe' | 
					
						
							|  |  |  |   | 'phoneNumber' | 
					
						
							|  |  |  |   | 'profileName' | 
					
						
							|  |  |  |   | 'sharedGroupNames' | 
					
						
							| 
									
										
										
										
											2023-04-05 13:48:00 -07:00
										 |  |  |   | 'systemGivenName' | 
					
						
							|  |  |  |   | 'systemFamilyName' | 
					
						
							| 
									
										
										
										
											2021-04-30 14:40:25 -05:00
										 |  |  |   | 'title' | 
					
						
							|  |  |  |   | 'type' | 
					
						
							|  |  |  |   | 'unblurredAvatarPath' | 
					
						
							| 
									
										
										
										
											2022-06-16 17:38:28 -07:00
										 |  |  |   | 'username' | 
					
						
							| 
									
										
										
										
											2022-04-04 17:38:22 -07:00
										 |  |  |   | 'e164' | 
					
						
							| 
									
										
										
										
											2023-08-16 22:54:39 +02:00
										 |  |  |   | 'serviceId' | 
					
						
							| 
									
										
										
										
											2021-04-30 14:40:25 -05:00
										 |  |  | >; | 
					
						
							| 
									
										
										
										
											2021-02-23 14:34:28 -06:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-11-17 15:11:21 -06:00
										 |  |  | type PropsDataType = ContactListItemConversationType & { | 
					
						
							|  |  |  |   badge: undefined | BadgeType; | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-02-23 14:34:28 -06:00
										 |  |  | type PropsHousekeepingType = { | 
					
						
							|  |  |  |   i18n: LocalizerType; | 
					
						
							| 
									
										
										
										
											2021-03-03 14:09:58 -06:00
										 |  |  |   onClick?: (id: string) => void; | 
					
						
							| 
									
										
										
										
											2023-04-05 13:48:00 -07:00
										 |  |  |   onAudioCall?: (id: string) => void; | 
					
						
							|  |  |  |   onVideoCall?: (id: string) => void; | 
					
						
							|  |  |  |   onRemove?: (id: string) => void; | 
					
						
							|  |  |  |   onBlock?: (id: string) => void; | 
					
						
							|  |  |  |   hasContextMenu: boolean; | 
					
						
							| 
									
										
										
										
											2021-11-17 15:11:21 -06:00
										 |  |  |   theme: ThemeType; | 
					
						
							| 
									
										
										
										
											2021-02-23 14:34:28 -06:00
										 |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | type PropsType = PropsDataType & PropsHousekeepingType; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | export const ContactListItem: FunctionComponent<PropsType> = React.memo( | 
					
						
							| 
									
										
										
										
											2021-08-11 12:29:07 -07:00
										 |  |  |   function ContactListItem({ | 
					
						
							| 
									
										
										
										
											2021-02-23 14:34:28 -06:00
										 |  |  |     about, | 
					
						
							| 
									
										
										
										
											2021-04-30 14:40:25 -05:00
										 |  |  |     acceptedMessageRequest, | 
					
						
							| 
									
										
										
										
											2021-02-23 14:34:28 -06:00
										 |  |  |     avatarPath, | 
					
						
							| 
									
										
										
										
											2021-11-17 15:11:21 -06:00
										 |  |  |     badge, | 
					
						
							| 
									
										
										
										
											2021-02-23 14:34:28 -06:00
										 |  |  |     color, | 
					
						
							| 
									
										
										
										
											2023-04-05 13:48:00 -07:00
										 |  |  |     hasContextMenu, | 
					
						
							| 
									
										
										
										
											2021-02-23 14:34:28 -06:00
										 |  |  |     i18n, | 
					
						
							|  |  |  |     id, | 
					
						
							|  |  |  |     isMe, | 
					
						
							| 
									
										
										
										
											2023-04-05 13:48:00 -07:00
										 |  |  |     name, | 
					
						
							| 
									
										
										
										
											2021-02-23 14:34:28 -06:00
										 |  |  |     onClick, | 
					
						
							| 
									
										
										
										
											2023-04-05 13:48:00 -07:00
										 |  |  |     onAudioCall, | 
					
						
							|  |  |  |     onVideoCall, | 
					
						
							|  |  |  |     onRemove, | 
					
						
							|  |  |  |     onBlock, | 
					
						
							| 
									
										
										
										
											2021-02-23 14:34:28 -06:00
										 |  |  |     phoneNumber, | 
					
						
							|  |  |  |     profileName, | 
					
						
							| 
									
										
										
										
											2021-04-30 14:40:25 -05:00
										 |  |  |     sharedGroupNames, | 
					
						
							| 
									
										
										
										
											2023-04-05 13:48:00 -07:00
										 |  |  |     systemGivenName, | 
					
						
							|  |  |  |     systemFamilyName, | 
					
						
							| 
									
										
										
										
											2021-11-17 15:11:21 -06:00
										 |  |  |     theme, | 
					
						
							| 
									
										
										
										
											2021-02-23 14:34:28 -06:00
										 |  |  |     title, | 
					
						
							|  |  |  |     type, | 
					
						
							| 
									
										
										
										
											2021-04-30 14:40:25 -05:00
										 |  |  |     unblurredAvatarPath, | 
					
						
							| 
									
										
										
										
											2023-08-16 22:54:39 +02:00
										 |  |  |     serviceId, | 
					
						
							| 
									
										
										
										
											2021-08-11 12:29:07 -07:00
										 |  |  |   }) { | 
					
						
							| 
									
										
										
										
											2023-04-05 13:48:00 -07:00
										 |  |  |     const [isConfirmingBlocking, setConfirmingBlocking] = useState(false); | 
					
						
							|  |  |  |     const [isConfirmingRemoving, setConfirmingRemoving] = useState(false); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     const menuOptions = useMemo( | 
					
						
							|  |  |  |       () => [ | 
					
						
							|  |  |  |         ...(onClick | 
					
						
							|  |  |  |           ? [ | 
					
						
							|  |  |  |               { | 
					
						
							|  |  |  |                 icon: 'ContactListItem__context-menu__chat-icon', | 
					
						
							|  |  |  |                 label: i18n('icu:ContactListItem__menu__message'), | 
					
						
							|  |  |  |                 onClick: () => onClick(id), | 
					
						
							|  |  |  |               }, | 
					
						
							|  |  |  |             ] | 
					
						
							|  |  |  |           : []), | 
					
						
							| 
									
										
										
										
											2023-06-05 09:14:58 -07:00
										 |  |  |         ...(!isMe && onAudioCall | 
					
						
							| 
									
										
										
										
											2023-04-05 13:48:00 -07:00
										 |  |  |           ? [ | 
					
						
							|  |  |  |               { | 
					
						
							|  |  |  |                 icon: 'ContactListItem__context-menu__phone-icon', | 
					
						
							|  |  |  |                 label: i18n('icu:ContactListItem__menu__audio-call'), | 
					
						
							|  |  |  |                 onClick: () => onAudioCall(id), | 
					
						
							|  |  |  |               }, | 
					
						
							|  |  |  |             ] | 
					
						
							|  |  |  |           : []), | 
					
						
							| 
									
										
										
										
											2023-06-05 09:14:58 -07:00
										 |  |  |         ...(!isMe && onVideoCall | 
					
						
							| 
									
										
										
										
											2023-04-05 13:48:00 -07:00
										 |  |  |           ? [ | 
					
						
							|  |  |  |               { | 
					
						
							|  |  |  |                 icon: 'ContactListItem__context-menu__video-icon', | 
					
						
							|  |  |  |                 label: i18n('icu:ContactListItem__menu__video-call'), | 
					
						
							|  |  |  |                 onClick: () => onVideoCall(id), | 
					
						
							|  |  |  |               }, | 
					
						
							|  |  |  |             ] | 
					
						
							|  |  |  |           : []), | 
					
						
							| 
									
										
										
										
											2023-06-05 09:14:58 -07:00
										 |  |  |         ...(!isMe && onRemove | 
					
						
							| 
									
										
										
										
											2023-04-05 13:48:00 -07:00
										 |  |  |           ? [ | 
					
						
							|  |  |  |               { | 
					
						
							|  |  |  |                 icon: 'ContactListItem__context-menu__delete-icon', | 
					
						
							|  |  |  |                 label: i18n('icu:ContactListItem__menu__remove'), | 
					
						
							|  |  |  |                 onClick: () => setConfirmingRemoving(true), | 
					
						
							|  |  |  |               }, | 
					
						
							|  |  |  |             ] | 
					
						
							|  |  |  |           : []), | 
					
						
							| 
									
										
										
										
											2023-06-05 09:14:58 -07:00
										 |  |  |         ...(!isMe && onBlock | 
					
						
							| 
									
										
										
										
											2023-04-05 13:48:00 -07:00
										 |  |  |           ? [ | 
					
						
							|  |  |  |               { | 
					
						
							|  |  |  |                 icon: 'ContactListItem__context-menu__block-icon', | 
					
						
							|  |  |  |                 label: i18n('icu:ContactListItem__menu__block'), | 
					
						
							|  |  |  |                 onClick: () => setConfirmingBlocking(true), | 
					
						
							|  |  |  |               }, | 
					
						
							|  |  |  |             ] | 
					
						
							|  |  |  |           : []), | 
					
						
							|  |  |  |       ], | 
					
						
							| 
									
										
										
										
											2023-06-05 09:14:58 -07:00
										 |  |  |       [id, i18n, isMe, onClick, onAudioCall, onVideoCall, onRemove, onBlock] | 
					
						
							| 
									
										
										
										
											2023-04-05 13:48:00 -07:00
										 |  |  |     ); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-02-23 14:34:28 -06:00
										 |  |  |     const headerName = isMe ? ( | 
					
						
							| 
									
										
										
										
											2023-03-02 07:57:35 +01:00
										 |  |  |       <ContactName | 
					
						
							|  |  |  |         isMe={isMe} | 
					
						
							|  |  |  |         module={HEADER_CONTACT_NAME_CLASS_NAME} | 
					
						
							| 
									
										
										
										
											2023-03-29 17:03:25 -07:00
										 |  |  |         title={i18n('icu:noteToSelf')} | 
					
						
							| 
									
										
										
										
											2023-03-02 07:57:35 +01:00
										 |  |  |       /> | 
					
						
							| 
									
										
										
										
											2021-02-23 14:34:28 -06:00
										 |  |  |     ) : ( | 
					
						
							| 
									
										
										
										
											2022-11-08 21:38:19 -05:00
										 |  |  |       <ContactName | 
					
						
							| 
									
										
										
										
											2023-08-16 22:54:39 +02:00
										 |  |  |         isSignalConversation={isSignalConversation({ id, serviceId })} | 
					
						
							| 
									
										
										
										
											2022-11-08 21:38:19 -05:00
										 |  |  |         module={HEADER_CONTACT_NAME_CLASS_NAME} | 
					
						
							|  |  |  |         title={title} | 
					
						
							|  |  |  |       /> | 
					
						
							| 
									
										
										
										
											2021-02-23 14:34:28 -06:00
										 |  |  |     ); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     const messageText = | 
					
						
							| 
									
										
										
										
											2023-01-25 16:51:08 -07:00
										 |  |  |       about && !isMe ? <About className="" text={about} /> : undefined; | 
					
						
							| 
									
										
										
										
											2021-02-23 14:34:28 -06:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-04-05 13:48:00 -07:00
										 |  |  |     let trailing: JSX.Element | undefined; | 
					
						
							|  |  |  |     if (hasContextMenu) { | 
					
						
							|  |  |  |       trailing = ( | 
					
						
							|  |  |  |         <ContextMenu | 
					
						
							|  |  |  |           i18n={i18n} | 
					
						
							|  |  |  |           menuOptions={menuOptions} | 
					
						
							|  |  |  |           popperOptions={{ placement: 'bottom-start', strategy: 'absolute' }} | 
					
						
							|  |  |  |           moduleClassName="ContactListItem__context-menu" | 
					
						
							|  |  |  |           ariaLabel={i18n('icu:ContactListItem__menu')} | 
					
						
							|  |  |  |           portalToRoot | 
					
						
							|  |  |  |         /> | 
					
						
							|  |  |  |       ); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     let blockConfirmation: JSX.Element | undefined; | 
					
						
							|  |  |  |     let removeConfirmation: JSX.Element | undefined; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (isConfirmingBlocking) { | 
					
						
							|  |  |  |       blockConfirmation = ( | 
					
						
							|  |  |  |         <ConfirmationDialog | 
					
						
							|  |  |  |           dialogName="ContactListItem.blocking" | 
					
						
							|  |  |  |           i18n={i18n} | 
					
						
							|  |  |  |           onClose={() => setConfirmingBlocking(false)} | 
					
						
							|  |  |  |           title={ | 
					
						
							|  |  |  |             <Intl | 
					
						
							|  |  |  |               i18n={i18n} | 
					
						
							|  |  |  |               id="icu:MessageRequests--block-direct-confirm-title" | 
					
						
							|  |  |  |               components={{ | 
					
						
							|  |  |  |                 title: <ContactName key="name" title={title} />, | 
					
						
							|  |  |  |               }} | 
					
						
							|  |  |  |             /> | 
					
						
							|  |  |  |           } | 
					
						
							|  |  |  |           actions={[ | 
					
						
							|  |  |  |             { | 
					
						
							|  |  |  |               text: i18n('icu:MessageRequests--block'), | 
					
						
							|  |  |  |               action: () => onBlock?.(id), | 
					
						
							|  |  |  |               style: 'negative', | 
					
						
							|  |  |  |             }, | 
					
						
							|  |  |  |           ]} | 
					
						
							|  |  |  |         > | 
					
						
							|  |  |  |           {i18n('icu:MessageRequests--block-direct-confirm-body')} | 
					
						
							|  |  |  |         </ConfirmationDialog> | 
					
						
							|  |  |  |       ); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (isConfirmingRemoving) { | 
					
						
							|  |  |  |       if ( | 
					
						
							|  |  |  |         isInSystemContacts({ type, name, systemGivenName, systemFamilyName }) | 
					
						
							|  |  |  |       ) { | 
					
						
							|  |  |  |         removeConfirmation = ( | 
					
						
							|  |  |  |           <ConfirmationDialog | 
					
						
							|  |  |  |             key="ContactListItem.systemContact" | 
					
						
							|  |  |  |             dialogName="ContactListItem.systemContact" | 
					
						
							| 
									
										
										
										
											2023-01-25 16:51:08 -07:00
										 |  |  |             i18n={i18n} | 
					
						
							| 
									
										
										
										
											2023-04-05 13:48:00 -07:00
										 |  |  |             onClose={() => setConfirmingRemoving(false)} | 
					
						
							|  |  |  |             title={ | 
					
						
							|  |  |  |               <Intl | 
					
						
							|  |  |  |                 i18n={i18n} | 
					
						
							|  |  |  |                 id="icu:ContactListItem__remove-system--title" | 
					
						
							|  |  |  |                 components={{ | 
					
						
							|  |  |  |                   title: <ContactName key="name" title={title} />, | 
					
						
							|  |  |  |                 }} | 
					
						
							|  |  |  |               /> | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |             cancelText={i18n('icu:Confirmation--confirm')} | 
					
						
							|  |  |  |           > | 
					
						
							|  |  |  |             {i18n('icu:ContactListItem__remove-system--body')} | 
					
						
							|  |  |  |           </ConfirmationDialog> | 
					
						
							|  |  |  |         ); | 
					
						
							|  |  |  |       } else { | 
					
						
							|  |  |  |         removeConfirmation = ( | 
					
						
							|  |  |  |           <ConfirmationDialog | 
					
						
							|  |  |  |             key="ContactListItem.removing" | 
					
						
							|  |  |  |             dialogName="ContactListItem.removing" | 
					
						
							|  |  |  |             i18n={i18n} | 
					
						
							|  |  |  |             onClose={() => setConfirmingRemoving(false)} | 
					
						
							|  |  |  |             title={ | 
					
						
							|  |  |  |               <Intl | 
					
						
							|  |  |  |                 i18n={i18n} | 
					
						
							|  |  |  |                 id="icu:ContactListItem__remove--title" | 
					
						
							|  |  |  |                 components={{ | 
					
						
							|  |  |  |                   title: <ContactName key="name" title={title} />, | 
					
						
							|  |  |  |                 }} | 
					
						
							|  |  |  |               /> | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |             actions={[ | 
					
						
							|  |  |  |               { | 
					
						
							|  |  |  |                 text: i18n('icu:ContactListItem__remove--confirm'), | 
					
						
							|  |  |  |                 action: () => onRemove?.(id), | 
					
						
							|  |  |  |                 style: 'negative', | 
					
						
							|  |  |  |               }, | 
					
						
							|  |  |  |             ]} | 
					
						
							|  |  |  |           > | 
					
						
							|  |  |  |             {i18n('icu:ContactListItem__remove--body')} | 
					
						
							|  |  |  |           </ConfirmationDialog> | 
					
						
							|  |  |  |         ); | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     return ( | 
					
						
							|  |  |  |       <> | 
					
						
							|  |  |  |         <ListTile | 
					
						
							|  |  |  |           moduleClassName="ContactListItem" | 
					
						
							|  |  |  |           leading={ | 
					
						
							|  |  |  |             <Avatar | 
					
						
							|  |  |  |               acceptedMessageRequest={acceptedMessageRequest} | 
					
						
							|  |  |  |               avatarPath={avatarPath} | 
					
						
							|  |  |  |               color={color} | 
					
						
							|  |  |  |               conversationType={type} | 
					
						
							|  |  |  |               noteToSelf={Boolean(isMe)} | 
					
						
							|  |  |  |               i18n={i18n} | 
					
						
							|  |  |  |               isMe={isMe} | 
					
						
							|  |  |  |               phoneNumber={phoneNumber} | 
					
						
							|  |  |  |               profileName={profileName} | 
					
						
							|  |  |  |               title={title} | 
					
						
							|  |  |  |               sharedGroupNames={sharedGroupNames} | 
					
						
							|  |  |  |               size={AvatarSize.THIRTY_TWO} | 
					
						
							|  |  |  |               unblurredAvatarPath={unblurredAvatarPath} | 
					
						
							|  |  |  |               // This is here to appease the type checker.
 | 
					
						
							|  |  |  |               {...(badge ? { badge, theme } : { badge: undefined })} | 
					
						
							|  |  |  |             /> | 
					
						
							|  |  |  |           } | 
					
						
							|  |  |  |           trailing={trailing} | 
					
						
							|  |  |  |           title={headerName} | 
					
						
							|  |  |  |           subtitle={messageText} | 
					
						
							|  |  |  |           subtitleMaxLines={1} | 
					
						
							|  |  |  |           onClick={onClick ? () => onClick(id) : undefined} | 
					
						
							|  |  |  |         /> | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         {blockConfirmation} | 
					
						
							|  |  |  |         {removeConfirmation} | 
					
						
							|  |  |  |       </> | 
					
						
							| 
									
										
										
										
											2021-02-23 14:34:28 -06:00
										 |  |  |     ); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | ); |