signal-desktop/ts/state/smart/CallsTab.tsx

268 lines
8.2 KiB
TypeScript
Raw Normal View History

2023-08-09 00:53:06 +00:00
// Copyright 2023 Signal Messenger, LLC
// SPDX-License-Identifier: AGPL-3.0-only
2024-06-10 15:23:43 +00:00
import React, { memo, useCallback, useEffect, useMemo } from 'react';
2023-08-09 00:53:06 +00:00
import { useSelector } from 'react-redux';
2024-07-22 18:16:33 +00:00
import { DataReader } from '../../sql/Client';
2023-08-09 00:53:06 +00:00
import { useItemsActions } from '../ducks/items';
import {
getNavTabsCollapsed,
getPreferredLeftPaneWidth,
} from '../selectors/items';
import { getIntl, getRegionCode } from '../selectors/user';
import type { WidthBreakpoint } from '../../components/_util';
2023-08-09 00:53:06 +00:00
import { CallsTab } from '../../components/CallsTab';
import {
getAllConversations,
getConversationSelector,
} from '../selectors/conversations';
import { filterAndSortConversations } from '../../util/filterAndSortConversations';
2023-08-09 00:53:06 +00:00
import type {
CallHistoryFilter,
CallHistoryFilterOptions,
CallHistoryGroup,
CallHistoryPagination,
} from '../../types/CallDisposition';
import type { ConversationType } from '../ducks/conversations';
import { SmartConversationDetails } from './ConversationDetails';
import { SmartToastManager } from './ToastManager';
2023-08-09 00:53:06 +00:00
import { useCallingActions } from '../ducks/calling';
import {
getActiveCallState,
getAdhocCallSelector,
2024-05-17 23:22:51 +00:00
getAllCallLinks,
getCallSelector,
getCallLinkSelector,
} from '../selectors/calling';
2023-08-09 00:53:06 +00:00
import { useCallHistoryActions } from '../ducks/callHistory';
import { getCallHistoryEdition } from '../selectors/callHistory';
import { getHasPendingUpdate } from '../selectors/updates';
import { getHasAnyFailedStorySends } from '../selectors/stories';
2023-08-21 20:12:27 +00:00
import { getOtherTabsUnreadStats } from '../selectors/nav';
2024-05-22 16:24:27 +00:00
import { SmartCallLinkDetails } from './CallLinkDetails';
2024-05-17 23:22:51 +00:00
import type { CallLinkType } from '../../types/CallLink';
import { filterCallLinks } from '../../util/filterCallLinks';
2024-06-10 15:23:43 +00:00
import { useGlobalModalActions } from '../ducks/globalModals';
import { isCallLinksCreateEnabled } from '../../util/callLinks';
2024-05-17 23:22:51 +00:00
function getCallHistoryFilter({
allCallLinks,
allConversations,
regionCode,
options,
}: {
allConversations: Array<ConversationType>;
allCallLinks: Array<CallLinkType>;
regionCode: string | undefined;
options: CallHistoryFilterOptions;
}): CallHistoryFilter | null {
const { status } = options;
2023-08-09 00:53:06 +00:00
const query = options.query.normalize().trim();
2024-05-17 23:22:51 +00:00
if (query === '') {
return {
status,
callLinkRoomIds: null,
conversationIds: null,
};
}
2023-08-09 00:53:06 +00:00
2024-05-17 23:22:51 +00:00
let callLinkRoomIds = null;
let conversationIds = null;
2023-08-09 00:53:06 +00:00
2024-05-17 23:22:51 +00:00
const currentConversations = allConversations.filter(conversation => {
return conversation.removalStage == null;
});
2023-08-09 00:53:06 +00:00
2024-05-17 23:22:51 +00:00
const filteredConversations = filterAndSortConversations(
currentConversations,
query,
regionCode
);
if (filteredConversations.length > 0) {
conversationIds = filteredConversations.map(conversation => {
return conversation.id;
});
}
const filteredCallLinks = filterCallLinks(allCallLinks, query);
if (filteredCallLinks.length > 0) {
callLinkRoomIds = filteredCallLinks.map(callLink => {
return callLink.roomId;
});
}
// If the search query resulted in no matching call links or conversations, then
// no calls will match.
if (callLinkRoomIds == null && conversationIds == null) {
return null;
2023-08-09 00:53:06 +00:00
}
return {
2024-05-17 23:22:51 +00:00
status,
callLinkRoomIds,
conversationIds,
2023-08-09 00:53:06 +00:00
};
}
2024-05-22 16:24:27 +00:00
function renderCallLinkDetails(
roomId: string,
callHistoryGroup: CallHistoryGroup,
onClose: () => void
2024-05-22 16:24:27 +00:00
): JSX.Element {
return (
<SmartCallLinkDetails
roomId={roomId}
callHistoryGroup={callHistoryGroup}
onClose={onClose}
/>
2024-05-22 16:24:27 +00:00
);
}
2023-08-09 00:53:06 +00:00
function renderConversationDetails(
conversationId: string,
callHistoryGroup: CallHistoryGroup | null
): JSX.Element {
return (
<SmartConversationDetails
conversationId={conversationId}
callHistoryGroup={callHistoryGroup}
/>
);
}
function renderToastManager(props: {
containerWidthBreakpoint: WidthBreakpoint;
}): JSX.Element {
return <SmartToastManager disableMegaphone {...props} />;
}
export const SmartCallsTab = memo(function SmartCallsTab() {
2023-08-09 00:53:06 +00:00
const i18n = useSelector(getIntl);
const navTabsCollapsed = useSelector(getNavTabsCollapsed);
const preferredLeftPaneWidth = useSelector(getPreferredLeftPaneWidth);
const { savePreferredLeftPaneWidth, toggleNavTabsCollapse } =
useItemsActions();
2024-05-17 23:22:51 +00:00
const allCallLinks = useSelector(getAllCallLinks);
2023-08-09 00:53:06 +00:00
const allConversations = useSelector(getAllConversations);
const regionCode = useSelector(getRegionCode);
const getConversation = useSelector(getConversationSelector);
const getAdhocCall = useSelector(getAdhocCallSelector);
const getCall = useSelector(getCallSelector);
2024-04-01 19:19:35 +00:00
const getCallLink = useSelector(getCallLinkSelector);
2023-08-09 00:53:06 +00:00
const activeCall = useSelector(getActiveCallState);
const callHistoryEdition = useSelector(getCallHistoryEdition);
const hasPendingUpdate = useSelector(getHasPendingUpdate);
const hasFailedStorySends = useSelector(getHasAnyFailedStorySends);
2023-08-21 20:12:27 +00:00
const otherTabsUnreadStats = useSelector(getOtherTabsUnreadStats);
2024-06-10 15:23:43 +00:00
const canCreateCallLinks = useMemo(() => {
return isCallLinksCreateEnabled();
}, []);
2023-08-09 00:53:06 +00:00
const {
2024-06-10 15:23:43 +00:00
createCallLink,
hangUpActiveCall,
2023-08-09 00:53:06 +00:00
onOutgoingAudioCallInConversation,
onOutgoingVideoCallInConversation,
peekNotConnectedGroupCall,
2024-04-01 19:19:35 +00:00
startCallLinkLobbyByRoomId,
togglePip,
2023-08-09 00:53:06 +00:00
} = useCallingActions();
const { clearAllCallHistory, markCallHistoryRead, markCallsTabViewed } =
useCallHistoryActions();
const { toggleCallLinkEditModal, toggleConfirmLeaveCallModal } =
useGlobalModalActions();
2023-08-09 00:53:06 +00:00
const getCallHistoryGroupsCount = useCallback(
async (options: CallHistoryFilterOptions) => {
2024-05-17 23:22:51 +00:00
const callHistoryFilter = getCallHistoryFilter({
allCallLinks,
2023-08-09 00:53:06 +00:00
allConversations,
regionCode,
2024-05-17 23:22:51 +00:00
options,
});
2023-08-09 00:53:06 +00:00
if (callHistoryFilter == null) {
return 0;
}
2024-07-24 00:31:40 +00:00
const count =
await DataReader.getCallHistoryGroupsCount(callHistoryFilter);
2023-08-09 00:53:06 +00:00
return count;
},
2024-05-17 23:22:51 +00:00
[allCallLinks, allConversations, regionCode]
2023-08-09 00:53:06 +00:00
);
const getCallHistoryGroups = useCallback(
async (
options: CallHistoryFilterOptions,
pagination: CallHistoryPagination
) => {
2024-05-17 23:22:51 +00:00
const callHistoryFilter = getCallHistoryFilter({
allCallLinks,
2023-08-09 00:53:06 +00:00
allConversations,
regionCode,
2024-05-17 23:22:51 +00:00
options,
});
2023-08-09 00:53:06 +00:00
if (callHistoryFilter == null) {
return [];
}
2024-07-22 18:16:33 +00:00
const results = await DataReader.getCallHistoryGroups(
2023-08-09 00:53:06 +00:00
callHistoryFilter,
pagination
);
return results;
},
2024-05-17 23:22:51 +00:00
[allCallLinks, allConversations, regionCode]
2023-08-09 00:53:06 +00:00
);
2024-06-10 15:23:43 +00:00
const handleCreateCallLink = useCallback(() => {
createCallLink(roomId => {
toggleCallLinkEditModal(roomId);
});
}, [createCallLink, toggleCallLinkEditModal]);
useEffect(() => {
markCallsTabViewed();
}, [markCallsTabViewed]);
2023-08-09 00:53:06 +00:00
return (
<CallsTab
activeCall={activeCall}
allConversations={allConversations}
2023-08-21 20:12:27 +00:00
otherTabsUnreadStats={otherTabsUnreadStats}
2023-08-09 00:53:06 +00:00
getConversation={getConversation}
getCallHistoryGroupsCount={getCallHistoryGroupsCount}
getCallHistoryGroups={getCallHistoryGroups}
getAdhocCall={getAdhocCall}
getCall={getCall}
2024-04-01 19:19:35 +00:00
getCallLink={getCallLink}
callHistoryEdition={callHistoryEdition}
2024-06-10 15:23:43 +00:00
canCreateCallLinks={canCreateCallLinks}
hangUpActiveCall={hangUpActiveCall}
hasFailedStorySends={hasFailedStorySends}
hasPendingUpdate={hasPendingUpdate}
2023-08-09 00:53:06 +00:00
i18n={i18n}
navTabsCollapsed={navTabsCollapsed}
onClearCallHistory={clearAllCallHistory}
onMarkCallHistoryRead={markCallHistoryRead}
2023-08-09 00:53:06 +00:00
onToggleNavTabsCollapse={toggleNavTabsCollapse}
2024-06-10 15:23:43 +00:00
onCreateCallLink={handleCreateCallLink}
2023-08-09 00:53:06 +00:00
onOutgoingAudioCallInConversation={onOutgoingAudioCallInConversation}
onOutgoingVideoCallInConversation={onOutgoingVideoCallInConversation}
peekNotConnectedGroupCall={peekNotConnectedGroupCall}
2023-08-09 00:53:06 +00:00
preferredLeftPaneWidth={preferredLeftPaneWidth}
2024-05-22 16:24:27 +00:00
renderCallLinkDetails={renderCallLinkDetails}
2023-08-09 00:53:06 +00:00
renderConversationDetails={renderConversationDetails}
renderToastManager={renderToastManager}
2023-08-09 00:53:06 +00:00
regionCode={regionCode}
savePreferredLeftPaneWidth={savePreferredLeftPaneWidth}
2024-04-01 19:19:35 +00:00
startCallLinkLobbyByRoomId={startCallLinkLobbyByRoomId}
toggleConfirmLeaveCallModal={toggleConfirmLeaveCallModal}
togglePip={togglePip}
2023-08-09 00:53:06 +00:00
/>
);
});