2023-01-03 19:55:46 +00:00
|
|
|
// Copyright 2021 Signal Messenger, LLC
|
2021-01-29 21:19:24 +00:00
|
|
|
// SPDX-License-Identifier: AGPL-3.0-only
|
|
|
|
|
2022-09-26 16:24:52 +00:00
|
|
|
import { sortBy } from 'lodash';
|
2024-03-13 20:44:13 +00:00
|
|
|
import React, { memo } from 'react';
|
|
|
|
import { useSelector } from 'react-redux';
|
2021-10-26 19:15:33 +00:00
|
|
|
import { ConversationDetails } from '../../components/conversation/conversation-details/ConversationDetails';
|
2021-03-11 21:29:31 +00:00
|
|
|
import {
|
2024-03-13 20:44:13 +00:00
|
|
|
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,
|
2021-04-29 18:32:38 +00:00
|
|
|
getConversationByIdSelector,
|
2023-08-16 20:54:39 +00:00
|
|
|
getConversationByServiceIdSelector,
|
2021-03-11 21:29:31 +00:00
|
|
|
} from '../selectors/conversations';
|
2023-09-01 17:03:44 +00:00
|
|
|
import {
|
|
|
|
getAreWeASubscriber,
|
|
|
|
getDefaultConversationColor,
|
|
|
|
} from '../selectors/items';
|
2024-03-13 20:44:13 +00:00
|
|
|
import { getSelectedNavTab } from '../selectors/nav';
|
2021-11-02 23:01:13 +00:00
|
|
|
import { getIntl, getTheme } from '../selectors/user';
|
2022-04-05 00:38:22 +00:00
|
|
|
import type { SmartChooseGroupMembersModalPropsType } from './ChooseGroupMembersModal';
|
|
|
|
import { SmartChooseGroupMembersModal } from './ChooseGroupMembersModal';
|
|
|
|
import type { SmartConfirmAdditionsModalPropsType } from './ConfirmAdditionsModal';
|
|
|
|
import { SmartConfirmAdditionsModal } from './ConfirmAdditionsModal';
|
2024-03-13 20:44:13 +00:00
|
|
|
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';
|
2021-01-29 21:19:24 +00:00
|
|
|
|
|
|
|
export type SmartConversationDetailsProps = {
|
|
|
|
conversationId: string;
|
2023-08-09 00:53:06 +00:00
|
|
|
callHistoryGroup?: CallHistoryGroup | null;
|
2021-01-29 21:19:24 +00:00
|
|
|
};
|
|
|
|
|
2021-08-17 14:10:27 +00:00
|
|
|
const ACCESS_ENUM = Proto.AccessControl.AccessRequired;
|
|
|
|
|
2022-04-05 00:38:22 +00:00
|
|
|
const renderChooseGroupMembersModal = (
|
|
|
|
props: SmartChooseGroupMembersModalPropsType
|
|
|
|
) => {
|
|
|
|
return <SmartChooseGroupMembersModal {...props} />;
|
|
|
|
};
|
|
|
|
|
|
|
|
const renderConfirmAdditionsModal = (
|
|
|
|
props: SmartConfirmAdditionsModalPropsType
|
|
|
|
) => {
|
|
|
|
return <SmartConfirmAdditionsModal {...props} />;
|
|
|
|
};
|
|
|
|
|
2024-03-13 20:44:13 +00:00
|
|
|
function getGroupsInCommonSorted(
|
|
|
|
conversation: ConversationType,
|
|
|
|
allComposableConversations: ReadonlyArray<ConversationType>
|
|
|
|
) {
|
|
|
|
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,
|
|
|
|
} = useConversationsActions();
|
|
|
|
const {
|
|
|
|
onOutgoingAudioCallInConversation,
|
|
|
|
onOutgoingVideoCallInConversation,
|
|
|
|
} = useCallingActions();
|
|
|
|
const { searchInConversation } = useSearchActions();
|
|
|
|
const {
|
|
|
|
showContactModal,
|
|
|
|
toggleAboutContactModal,
|
|
|
|
toggleAddUserToAnotherGroupModal,
|
|
|
|
toggleSafetyNumberModal,
|
|
|
|
} = useGlobalModalActions();
|
|
|
|
const { showLightboxWithMedia } = useLightboxActions();
|
|
|
|
|
|
|
|
const conversation = conversationSelector(conversationId);
|
2022-09-15 19:17:15 +00:00
|
|
|
assertDev(
|
2021-04-29 18:32:38 +00:00
|
|
|
conversation,
|
|
|
|
'<SmartConversationDetails> expected a conversation to be found'
|
|
|
|
);
|
2024-03-13 20:44:13 +00:00
|
|
|
const conversationWithColorAttributes = {
|
|
|
|
...conversation,
|
|
|
|
...getConversationColorAttributes(conversation, defaultConversationColor),
|
|
|
|
};
|
2021-04-29 18:32:38 +00:00
|
|
|
|
2021-11-02 23:01:13 +00:00
|
|
|
const groupMemberships = getGroupMemberships(
|
|
|
|
conversation,
|
2023-08-16 20:54:39 +00:00
|
|
|
conversationByServiceIdSelector
|
2021-11-02 23:01:13 +00:00
|
|
|
);
|
|
|
|
|
2024-03-13 20:44:13 +00:00
|
|
|
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;
|
|
|
|
const hasGroupLink =
|
|
|
|
conversation.groupLink != null &&
|
|
|
|
conversation.accessControlAddFromInviteLink !== ACCESS_ENUM.UNSATISFIABLE;
|
|
|
|
const isAdmin = conversation.areWeAdmin ?? false;
|
|
|
|
const isGroup = conversation.type === 'group';
|
2022-10-24 20:46:36 +00:00
|
|
|
const maxGroupSize = getGroupSizeHardLimit(1001);
|
|
|
|
const maxRecommendedGroupSize = getGroupSizeRecommendedLimit(151);
|
2024-03-13 20:44:13 +00:00
|
|
|
const userAvatarData = conversation.avatars ?? [];
|
|
|
|
|
|
|
|
return (
|
|
|
|
<ConversationDetails
|
|
|
|
acceptConversation={acceptConversation}
|
|
|
|
addMembersToGroup={addMembersToGroup}
|
|
|
|
areWeASubscriber={areWeASubscriber}
|
|
|
|
badges={badges}
|
|
|
|
blockConversation={blockConversation}
|
|
|
|
callHistoryGroup={callHistoryGroup}
|
|
|
|
canAddNewMembers={canAddNewMembers}
|
|
|
|
canEditGroupInfo={canEditGroupInfo}
|
|
|
|
conversation={conversationWithColorAttributes}
|
|
|
|
deleteAvatarFromDisk={deleteAvatarFromDisk}
|
|
|
|
getPreferredBadge={getPreferredBadge}
|
|
|
|
getProfilesForConversation={getProfilesForConversation}
|
|
|
|
groupsInCommon={groupsInCommon}
|
|
|
|
hasActiveCall={hasActiveCall}
|
|
|
|
hasGroupLink={hasGroupLink}
|
|
|
|
i18n={i18n}
|
|
|
|
isAdmin={isAdmin}
|
|
|
|
isGroup={isGroup}
|
|
|
|
leaveGroup={leaveGroup}
|
|
|
|
loadRecentMediaItems={loadRecentMediaItems}
|
|
|
|
maxGroupSize={maxGroupSize}
|
|
|
|
maxRecommendedGroupSize={maxRecommendedGroupSize}
|
|
|
|
memberships={memberships}
|
|
|
|
onOutgoingAudioCallInConversation={onOutgoingAudioCallInConversation}
|
|
|
|
onOutgoingVideoCallInConversation={onOutgoingVideoCallInConversation}
|
|
|
|
pendingApprovalMemberships={pendingApprovalMemberships}
|
|
|
|
pendingMemberships={pendingMemberships}
|
|
|
|
pushPanelForConversation={pushPanelForConversation}
|
|
|
|
renderChooseGroupMembersModal={renderChooseGroupMembersModal}
|
|
|
|
renderConfirmAdditionsModal={renderConfirmAdditionsModal}
|
|
|
|
replaceAvatar={replaceAvatar}
|
|
|
|
saveAvatarToDisk={saveAvatarToDisk}
|
|
|
|
searchInConversation={searchInConversation}
|
|
|
|
selectedNavTab={selectedNavTab}
|
|
|
|
setDisappearingMessages={setDisappearingMessages}
|
|
|
|
setMuteExpiration={setMuteExpiration}
|
|
|
|
showContactModal={showContactModal}
|
|
|
|
showConversation={showConversation}
|
|
|
|
showLightboxWithMedia={showLightboxWithMedia}
|
|
|
|
theme={theme}
|
|
|
|
toggleAboutContactModal={toggleAboutContactModal}
|
|
|
|
toggleAddUserToAnotherGroupModal={toggleAddUserToAnotherGroupModal}
|
|
|
|
toggleSafetyNumberModal={toggleSafetyNumberModal}
|
|
|
|
updateGroupAttributes={updateGroupAttributes}
|
|
|
|
userAvatarData={userAvatarData}
|
|
|
|
/>
|
|
|
|
);
|
|
|
|
});
|