// Copyright 2021 Signal Messenger, LLC // SPDX-License-Identifier: AGPL-3.0-only import { sortBy } from 'lodash'; import React, { memo, useCallback } from 'react'; import { useSelector } from 'react-redux'; import { ConversationDetails } from '../../components/conversation/conversation-details/ConversationDetails'; import { getGroupSizeHardLimit, getGroupSizeRecommendedLimit, } from '../../groups/limits'; import { SignalService as Proto } from '../../protobuf'; import type { CallHistoryGroup } from '../../types/CallDisposition'; import { assertDev } from '../../util/assert'; import { getConversationColorAttributes } from '../../util/getConversationColorAttributes'; import { getGroupMemberships } from '../../util/getGroupMemberships'; import { getBadgesSelector, getPreferredBadgeSelector, } from '../selectors/badges'; import { getActiveCallState } from '../selectors/calling'; import { getAllComposableConversations, getConversationByIdSelector, getConversationByServiceIdSelector, } from '../selectors/conversations'; import { getAreWeASubscriber, getDefaultConversationColor, } from '../selectors/items'; import { getSelectedNavTab } from '../selectors/nav'; import { getIntl, getTheme } from '../selectors/user'; import type { SmartChooseGroupMembersModalPropsType } from './ChooseGroupMembersModal'; import { SmartChooseGroupMembersModal } from './ChooseGroupMembersModal'; import type { SmartConfirmAdditionsModalPropsType } from './ConfirmAdditionsModal'; import { SmartConfirmAdditionsModal } from './ConfirmAdditionsModal'; import type { ConversationType } from '../ducks/conversations'; import { useConversationsActions } from '../ducks/conversations'; import { useCallingActions } from '../ducks/calling'; import { useSearchActions } from '../ducks/search'; import { useGlobalModalActions } from '../ducks/globalModals'; import { useLightboxActions } from '../ducks/lightbox'; export type SmartConversationDetailsProps = { conversationId: string; callHistoryGroup?: CallHistoryGroup | null; }; const ACCESS_ENUM = Proto.AccessControl.AccessRequired; const renderChooseGroupMembersModal = ( props: SmartChooseGroupMembersModalPropsType ) => { return ; }; const renderConfirmAdditionsModal = ( props: SmartConfirmAdditionsModalPropsType ) => { return ; }; function getGroupsInCommonSorted( conversation: ConversationType, allComposableConversations: ReadonlyArray ) { if (conversation.type !== 'direct') { return []; } const groupsInCommonUnsorted = allComposableConversations.filter( otherConversation => { if (otherConversation.type !== 'group') { return false; } return otherConversation.memberships?.some(member => { return member.aci === conversation.serviceId; }); } ); return sortBy(groupsInCommonUnsorted, 'title'); } export const SmartConversationDetails = memo(function SmartConversationDetails({ conversationId, callHistoryGroup, }: SmartConversationDetailsProps) { const i18n = useSelector(getIntl); const theme = useSelector(getTheme); const activeCall = useSelector(getActiveCallState); const allComposableConversations = useSelector(getAllComposableConversations); const areWeASubscriber = useSelector(getAreWeASubscriber); const badgesSelector = useSelector(getBadgesSelector); const conversationByServiceIdSelector = useSelector( getConversationByServiceIdSelector ); const conversationSelector = useSelector(getConversationByIdSelector); const defaultConversationColor = useSelector(getDefaultConversationColor); const getPreferredBadge = useSelector(getPreferredBadgeSelector); const selectedNavTab = useSelector(getSelectedNavTab); const { acceptConversation, addMembersToGroup, blockConversation, deleteAvatarFromDisk, getProfilesForConversation, leaveGroup, loadRecentMediaItems, pushPanelForConversation, replaceAvatar, saveAvatarToDisk, setDisappearingMessages, setMuteExpiration, showConversation, updateGroupAttributes, updateNicknameAndNote, } = useConversationsActions(); const { onOutgoingAudioCallInConversation, onOutgoingVideoCallInConversation, } = useCallingActions(); const { searchInConversation } = useSearchActions(); const { showContactModal, toggleAboutContactModal, toggleAddUserToAnotherGroupModal, toggleEditNicknameAndNoteModal, toggleSafetyNumberModal, } = useGlobalModalActions(); const { showLightbox } = useLightboxActions(); const conversation = conversationSelector(conversationId); assertDev( conversation, ' expected a conversation to be found' ); const conversationWithColorAttributes = { ...conversation, ...getConversationColorAttributes(conversation, defaultConversationColor), }; const groupMemberships = getGroupMemberships( conversation, conversationByServiceIdSelector ); const { memberships, pendingApprovalMemberships, pendingMemberships } = groupMemberships; const badges = badgesSelector(conversation.badges); const canAddNewMembers = conversation.canAddNewMembers ?? false; const canEditGroupInfo = conversation.canEditGroupInfo ?? false; const groupsInCommon = getGroupsInCommonSorted( conversation, allComposableConversations ); const hasActiveCall = activeCall != null && activeCall.conversationId !== conversationId; const hasGroupLink = conversation.groupLink != null && conversation.accessControlAddFromInviteLink !== ACCESS_ENUM.UNSATISFIABLE; const isAdmin = conversation.areWeAdmin ?? false; const isGroup = conversation.type === 'group'; const maxGroupSize = getGroupSizeHardLimit(1001); const maxRecommendedGroupSize = getGroupSizeRecommendedLimit(151); const userAvatarData = conversation.avatars ?? []; const handleDeleteNicknameAndNote = useCallback(() => { updateNicknameAndNote(conversationId, { nickname: null, note: null }); }, [conversationId, updateNicknameAndNote]); const handleOpenEditNicknameAndNoteModal = useCallback(() => { toggleEditNicknameAndNoteModal({ conversationId }); }, [conversationId, toggleEditNicknameAndNoteModal]); return ( ); });