signal-desktop/ts/components/conversation/CallingNotification.tsx

180 lines
4.9 KiB
TypeScript
Raw Normal View History

2023-01-03 19:55:46 +00:00
// Copyright 2020 Signal Messenger, LLC
2020-10-30 20:34:04 +00:00
// SPDX-License-Identifier: AGPL-3.0-only
import type { ReactNode } from 'react';
import React from 'react';
2021-08-26 20:51:55 +00:00
import { noop } from 'lodash';
2020-06-04 18:16:19 +00:00
import { SystemMessage, SystemMessageKind } from './SystemMessage';
2021-08-26 20:51:55 +00:00
import { Button, ButtonSize, ButtonVariant } from '../Button';
2022-01-26 23:05:26 +00:00
import { MessageTimestamp } from './MessageTimestamp';
import type { LocalizerType } from '../../types/Util';
import { CallMode } from '../../types/Calling';
import type { CallingNotificationType } from '../../util/callingNotification';
import {
2021-08-26 20:51:55 +00:00
getCallingIcon,
getCallingNotificationText,
} from '../../util/callingNotification';
import { missingCaseError } from '../../util/missingCaseError';
import { Tooltip, TooltipPlacement } from '../Tooltip';
import * as log from '../../logging/log';
2023-08-09 00:53:06 +00:00
import {
CallDirection,
CallType,
DirectCallStatus,
GroupCallStatus,
} from '../../types/CallDisposition';
2020-06-04 18:16:19 +00:00
export type PropsActionsType = {
onOutgoingAudioCallInConversation: (conversationId: string) => void;
onOutgoingVideoCallInConversation: (conversationId: string) => void;
returnToActiveCall: () => void;
};
2020-06-04 18:16:19 +00:00
type PropsHousekeeping = {
i18n: LocalizerType;
conversationId: string;
isNextItemCallingNotification: boolean;
2020-06-04 18:16:19 +00:00
};
2023-08-09 00:53:06 +00:00
export type PropsType = CallingNotificationType &
PropsActionsType &
PropsHousekeeping;
2020-06-04 18:16:19 +00:00
2022-11-18 00:45:19 +00:00
export const CallingNotification: React.FC<PropsType> = React.memo(
function CallingNotificationInner(props) {
const { i18n } = props;
if (props.callHistory == null) {
return null;
}
2023-08-09 00:53:06 +00:00
const { type, direction, status, timestamp } = props.callHistory;
const icon = getCallingIcon(type, direction, status);
2022-11-18 00:45:19 +00:00
return (
<SystemMessage
button={renderCallingNotificationButton(props)}
contents={
<>
{getCallingNotificationText(props, i18n)} &middot;{' '}
<MessageTimestamp
direction="outgoing"
i18n={i18n}
timestamp={timestamp}
withImageNoCaption={false}
withSticker={false}
withTapToViewExpired={false}
/>
</>
}
icon={icon}
2023-08-09 00:53:06 +00:00
kind={
status === DirectCallStatus.Missed ||
status === GroupCallStatus.Missed
? SystemMessageKind.Danger
: SystemMessageKind.Normal
}
2022-11-18 00:45:19 +00:00
/>
);
}
);
function renderCallingNotificationButton(
props: Readonly<PropsType>
): ReactNode {
const {
conversationId,
i18n,
isNextItemCallingNotification,
onOutgoingAudioCallInConversation,
onOutgoingVideoCallInConversation,
returnToActiveCall,
} = props;
if (isNextItemCallingNotification) {
return null;
}
let buttonText: string;
let disabledTooltipText: undefined | string;
2021-08-26 20:51:55 +00:00
let onClick: () => void;
if (props.callHistory == null) {
return null;
}
2023-08-09 00:53:06 +00:00
switch (props.callHistory.mode) {
case CallMode.Direct: {
2023-08-09 00:53:06 +00:00
const { direction, type } = props.callHistory;
buttonText =
direction === CallDirection.Incoming
? i18n('icu:calling__call-back')
: i18n('icu:calling__call-again');
if (props.activeConversationId != null) {
2023-03-30 00:03:25 +00:00
disabledTooltipText = i18n('icu:calling__in-another-call-tooltip');
onClick = noop;
} else {
onClick = () => {
if (type === CallType.Video) {
onOutgoingVideoCallInConversation(conversationId);
} else {
onOutgoingAudioCallInConversation(conversationId);
}
};
}
break;
}
case CallMode.Group: {
if (props.groupCallEnded) {
return null;
}
if (props.activeConversationId != null) {
if (props.activeConversationId === conversationId) {
buttonText = i18n('icu:calling__return');
onClick = returnToActiveCall;
} else {
buttonText = i18n('icu:calling__join');
disabledTooltipText = i18n('icu:calling__in-another-call-tooltip');
onClick = noop;
}
} else if (props.deviceCount > props.maxDevices) {
2023-03-30 00:03:25 +00:00
buttonText = i18n('icu:calling__call-is-full');
disabledTooltipText = i18n(
2023-03-30 00:03:25 +00:00
'icu:calling__call-notification__button__call-full-tooltip',
2023-03-27 23:37:39 +00:00
{
2023-08-09 00:53:06 +00:00
max: props.maxDevices,
2023-03-27 23:37:39 +00:00
}
);
onClick = noop;
} else {
2023-03-30 00:03:25 +00:00
buttonText = i18n('icu:calling__join');
onClick = () => {
onOutgoingVideoCallInConversation(conversationId);
};
}
break;
}
default:
2023-08-09 00:53:06 +00:00
log.error(missingCaseError(props.callHistory.mode));
return null;
}
const button = (
2021-08-26 20:51:55 +00:00
<Button
disabled={Boolean(disabledTooltipText)}
onClick={onClick}
2021-08-26 20:51:55 +00:00
size={ButtonSize.Small}
variant={ButtonVariant.SystemMessage}
2020-06-04 18:16:19 +00:00
>
{buttonText}
2021-08-26 20:51:55 +00:00
</Button>
2020-06-04 18:16:19 +00:00
);
if (disabledTooltipText) {
return (
<Tooltip content={disabledTooltipText} direction={TooltipPlacement.Top}>
{button}
</Tooltip>
);
}
return button;
}