Redux state: Allow multiple calls to be stored

This commit is contained in:
Evan Hahn 2020-11-06 11:36:37 -06:00 committed by GitHub
parent 753e0279c6
commit 3468de255d
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
21 changed files with 1191 additions and 515 deletions

View file

@ -13,11 +13,7 @@ import enMessages from '../../_locales/en/messages.json';
const i18n = setupI18n('en', enMessages);
const callDetails = {
callId: 0,
isIncoming: true,
isVideoCall: true,
const conversation = {
id: '3051234567',
avatarPath: undefined,
color: 'ultramarine' as ColorType,
@ -30,27 +26,20 @@ const callDetails = {
const defaultProps = {
availableCameras: [],
acceptCall: action('accept-call'),
callDetails,
callState: CallState.Accepted,
cancelCall: action('cancel-call'),
closeNeedPermissionScreen: action('close-need-permission-screen'),
declineCall: action('decline-call'),
hangUp: action('hang-up'),
hasLocalAudio: true,
hasLocalVideo: true,
hasRemoteVideo: true,
i18n,
me: {
color: 'ultramarine' as ColorType,
title: 'Morty Smith',
},
pip: false,
renderDeviceSelection: () => <div />,
setLocalAudio: action('set-local-audio'),
setLocalPreview: action('set-local-preview'),
setLocalVideo: action('set-local-video'),
setRendererCanvas: action('set-renderer-canvas'),
settingsDialogOpen: false,
startCall: action('start-call'),
toggleParticipants: action('toggle-participants'),
togglePip: action('toggle-pip'),
@ -59,20 +48,71 @@ const defaultProps = {
const permutations = [
{
title: 'Call Manager (ongoing)',
title: 'Call Manager (no call)',
props: {},
},
{
title: 'Call Manager (ongoing)',
props: {
activeCall: {
call: {
conversationId: '3051234567',
callState: CallState.Accepted,
isIncoming: false,
isVideoCall: true,
hasRemoteVideo: true,
},
activeCallState: {
conversationId: '3051234567',
joinedAt: Date.now(),
hasLocalAudio: true,
hasLocalVideo: false,
participantsList: false,
pip: false,
settingsDialogOpen: false,
},
conversation,
},
},
},
{
title: 'Call Manager (ringing)',
props: {
callState: CallState.Ringing,
incomingCall: {
call: {
conversationId: '3051234567',
callState: CallState.Ringing,
isIncoming: true,
isVideoCall: true,
hasRemoteVideo: true,
},
conversation,
},
},
},
{
title: 'Call Manager (call request needed)',
props: {
callState: CallState.Ended,
callEndedReason: CallEndedReason.RemoteHangupNeedPermission,
activeCall: {
call: {
conversationId: '3051234567',
callState: CallState.Ended,
callEndedReason: CallEndedReason.RemoteHangupNeedPermission,
isIncoming: false,
isVideoCall: true,
hasRemoteVideo: true,
},
activeCallState: {
conversationId: '3051234567',
joinedAt: Date.now(),
hasLocalAudio: true,
hasLocalVideo: false,
participantsList: false,
pip: false,
settingsDialogOpen: false,
},
conversation,
},
},
},
];

View file

@ -5,112 +5,156 @@ import React from 'react';
import { CallingPip } from './CallingPip';
import { CallNeedPermissionScreen } from './CallNeedPermissionScreen';
import { CallingLobby } from './CallingLobby';
import { CallScreen, PropsType as CallScreenPropsType } from './CallScreen';
import {
IncomingCallBar,
PropsType as IncomingCallBarPropsType,
} from './IncomingCallBar';
import { CallScreen } from './CallScreen';
import { IncomingCallBar } from './IncomingCallBar';
import { CallState, CallEndedReason } from '../types/Calling';
import { CallDetailsType, OutgoingCallType } from '../state/ducks/calling';
import {
ActiveCallStateType,
AcceptCallType,
DeclineCallType,
DirectCallStateType,
StartCallType,
SetLocalAudioType,
HangUpType,
SetLocalPreviewType,
SetLocalVideoType,
SetRendererCanvasType,
} from '../state/ducks/calling';
import { LocalizerType } from '../types/Util';
import { ColorType } from '../types/Colors';
type CallManagerPropsType = {
interface PropsType {
activeCall?: {
call: DirectCallStateType;
activeCallState: ActiveCallStateType;
conversation: {
id: string;
avatarPath?: string;
color?: ColorType;
title: string;
name?: string;
phoneNumber?: string;
profileName?: string;
};
};
availableCameras: Array<MediaDeviceInfo>;
callDetails?: CallDetailsType;
callEndedReason?: CallEndedReason;
callState?: CallState;
cancelCall: () => void;
pip: boolean;
closeNeedPermissionScreen: () => void;
incomingCall?: {
call: DirectCallStateType;
conversation: {
id: string;
avatarPath?: string;
color?: ColorType;
title: string;
name?: string;
phoneNumber?: string;
profileName?: string;
};
};
renderDeviceSelection: () => JSX.Element;
settingsDialogOpen: boolean;
startCall: (payload: OutgoingCallType) => void;
startCall: (payload: StartCallType) => void;
toggleParticipants: () => void;
};
type PropsType = IncomingCallBarPropsType &
CallScreenPropsType &
CallManagerPropsType;
acceptCall: (_: AcceptCallType) => void;
declineCall: (_: DeclineCallType) => void;
i18n: LocalizerType;
me: {
avatarPath?: string;
color?: ColorType;
name?: string;
phoneNumber?: string;
profileName?: string;
title: string;
};
setLocalAudio: (_: SetLocalAudioType) => void;
setLocalVideo: (_: SetLocalVideoType) => void;
setLocalPreview: (_: SetLocalPreviewType) => void;
setRendererCanvas: (_: SetRendererCanvasType) => void;
hangUp: (_: HangUpType) => void;
togglePip: () => void;
toggleSettings: () => void;
}
export const CallManager = ({
acceptCall,
activeCall,
availableCameras,
callDetails,
callState,
callEndedReason,
cancelCall,
closeNeedPermissionScreen,
declineCall,
hangUp,
hasLocalAudio,
hasLocalVideo,
hasRemoteVideo,
i18n,
incomingCall,
me,
pip,
renderDeviceSelection,
setLocalAudio,
setLocalPreview,
setLocalVideo,
setRendererCanvas,
settingsDialogOpen,
startCall,
toggleParticipants,
togglePip,
toggleSettings,
}: PropsType): JSX.Element | null => {
if (!callDetails) {
return null;
}
const incoming = callDetails.isIncoming;
const outgoing = !incoming;
const ongoing =
callState === CallState.Accepted || callState === CallState.Reconnecting;
const ringing = callState === CallState.Ringing;
const ended = callState === CallState.Ended;
if (activeCall) {
const { call, activeCallState, conversation } = activeCall;
const { callState, callEndedReason } = call;
const {
joinedAt,
hasLocalAudio,
hasLocalVideo,
settingsDialogOpen,
pip,
} = activeCallState;
if (ended) {
if (callEndedReason === CallEndedReason.RemoteHangupNeedPermission) {
const ended = callState === CallState.Ended;
if (ended) {
if (callEndedReason === CallEndedReason.RemoteHangupNeedPermission) {
return (
<CallNeedPermissionScreen
close={closeNeedPermissionScreen}
conversation={conversation}
i18n={i18n}
/>
);
}
}
if (!callState) {
return (
<CallNeedPermissionScreen
close={closeNeedPermissionScreen}
callDetails={callDetails}
i18n={i18n}
/>
<>
<CallingLobby
availableCameras={availableCameras}
conversation={conversation}
hasLocalAudio={hasLocalAudio}
hasLocalVideo={hasLocalVideo}
i18n={i18n}
isGroupCall={false}
onCallCanceled={cancelCall}
onJoinCall={() => {
startCall({
conversationId: conversation.id,
hasLocalAudio,
hasLocalVideo,
});
}}
setLocalPreview={setLocalPreview}
setLocalAudio={setLocalAudio}
setLocalVideo={setLocalVideo}
toggleParticipants={toggleParticipants}
toggleSettings={toggleSettings}
/>
{settingsDialogOpen && renderDeviceSelection()}
</>
);
}
return null;
}
if (!callState) {
return (
<>
<CallingLobby
availableCameras={availableCameras}
callDetails={callDetails}
hasLocalAudio={hasLocalAudio}
hasLocalVideo={hasLocalVideo}
i18n={i18n}
isGroupCall={false}
onCallCanceled={cancelCall}
onJoinCall={() => {
startCall({ callDetails });
}}
setLocalPreview={setLocalPreview}
setLocalAudio={setLocalAudio}
setLocalVideo={setLocalVideo}
toggleParticipants={toggleParticipants}
toggleSettings={toggleSettings}
/>
{settingsDialogOpen && renderDeviceSelection()}
</>
);
}
const hasRemoteVideo = Boolean(call.hasRemoteVideo);
if (outgoing || ongoing) {
if (pip) {
return (
<CallingPip
callDetails={callDetails}
conversation={conversation}
hangUp={hangUp}
hasLocalVideo={hasLocalVideo}
hasRemoteVideo={hasRemoteVideo}
@ -125,12 +169,13 @@ export const CallManager = ({
return (
<>
<CallScreen
callDetails={callDetails}
conversation={conversation}
callState={callState}
hangUp={hangUp}
hasLocalAudio={hasLocalAudio}
hasLocalVideo={hasLocalVideo}
i18n={i18n}
joinedAt={joinedAt}
me={me}
hasRemoteVideo={hasRemoteVideo}
setLocalPreview={setLocalPreview}
@ -145,17 +190,18 @@ export const CallManager = ({
);
}
if (incoming && ringing) {
// In the future, we may want to show the incoming call bar when a call is active.
if (incomingCall) {
return (
<IncomingCallBar
acceptCall={acceptCall}
callDetails={callDetails}
declineCall={declineCall}
i18n={i18n}
call={incomingCall.call}
conversation={incomingCall.conversation}
/>
);
}
// Incoming && Prering
return null;
};

View file

@ -2,14 +2,21 @@
// SPDX-License-Identifier: AGPL-3.0-only
import React, { useRef, useEffect } from 'react';
import { CallDetailsType } from '../state/ducks/calling';
import { LocalizerType } from '../types/Util';
import { Avatar } from './Avatar';
import { Intl } from './Intl';
import { ContactName } from './conversation/ContactName';
import { ColorType } from '../types/Colors';
interface Props {
callDetails: CallDetailsType;
conversation: {
avatarPath?: string;
color?: ColorType;
name?: string;
phoneNumber?: string;
profileName?: string;
title: string;
};
i18n: LocalizerType;
close: () => void;
}
@ -17,11 +24,11 @@ interface Props {
const AUTO_CLOSE_MS = 10000;
export const CallNeedPermissionScreen: React.FC<Props> = ({
callDetails,
conversation,
i18n,
close,
}) => {
const title = callDetails.title || i18n('unknownContact');
const title = conversation.title || i18n('unknownContact');
const autoCloseAtRef = useRef<number>(Date.now() + AUTO_CLOSE_MS);
useEffect(() => {
@ -32,15 +39,15 @@ export const CallNeedPermissionScreen: React.FC<Props> = ({
return (
<div className="module-call-need-permission-screen">
<Avatar
avatarPath={callDetails.avatarPath}
color={callDetails.color || 'ultramarine'}
avatarPath={conversation.avatarPath}
color={conversation.color || 'ultramarine'}
noteToSelf={false}
conversationType="direct"
i18n={i18n}
name={callDetails.name}
phoneNumber={callDetails.phoneNumber}
profileName={callDetails.profileName}
title={callDetails.title}
name={conversation.name}
phoneNumber={conversation.phoneNumber}
profileName={conversation.profileName}
title={conversation.title}
size={112}
/>

View file

@ -14,23 +14,16 @@ import enMessages from '../../_locales/en/messages.json';
const i18n = setupI18n('en', enMessages);
const callDetails = {
acceptedTime: Date.now(),
callId: 0,
isIncoming: true,
isVideoCall: true,
id: '3051234567',
avatarPath: undefined,
color: 'ultramarine' as ColorType,
title: 'Rick Sanchez',
name: 'Rick Sanchez',
phoneNumber: '3051234567',
profileName: 'Rick Sanchez',
};
const createProps = (overrideProps: Partial<PropsType> = {}): PropsType => ({
callDetails,
conversation: {
id: '3051234567',
avatarPath: undefined,
color: 'ultramarine' as ColorType,
title: 'Rick Sanchez',
name: 'Rick Sanchez',
phoneNumber: '3051234567',
profileName: 'Rick Sanchez',
},
callState: select(
'callState',
CallState,
@ -44,6 +37,7 @@ const createProps = (overrideProps: Partial<PropsType> = {}): PropsType => ({
overrideProps.hasRemoteVideo || false
),
i18n,
joinedAt: Date.now(),
me: {
color: 'ultramarine' as ColorType,
name: 'Morty Smith',

View file

@ -5,7 +5,6 @@ import React, { useState, useRef, useEffect, useCallback } from 'react';
import { noop } from 'lodash';
import classNames from 'classnames';
import {
CallDetailsType,
HangUpType,
SetLocalAudioType,
SetLocalPreviewType,
@ -20,13 +19,22 @@ import { ColorType } from '../types/Colors';
import { LocalizerType } from '../types/Util';
export type PropsType = {
callDetails?: CallDetailsType;
callState?: CallState;
conversation: {
id: string;
avatarPath?: string;
color?: ColorType;
title: string;
name?: string;
phoneNumber?: string;
profileName?: string;
};
callState: CallState;
hangUp: (_: HangUpType) => void;
hasLocalAudio: boolean;
hasLocalVideo: boolean;
hasRemoteVideo: boolean;
i18n: LocalizerType;
joinedAt?: number;
me: {
avatarPath?: string;
color?: ColorType;
@ -44,13 +52,14 @@ export type PropsType = {
};
export const CallScreen: React.FC<PropsType> = ({
callDetails,
callState,
conversation,
hangUp,
hasLocalAudio,
hasLocalVideo,
hasRemoteVideo,
i18n,
joinedAt,
me,
setLocalAudio,
setLocalVideo,
@ -59,29 +68,17 @@ export const CallScreen: React.FC<PropsType> = ({
togglePip,
toggleSettings,
}) => {
const { acceptedTime, callId } = callDetails || {};
const toggleAudio = useCallback(() => {
if (!callId) {
return;
}
setLocalAudio({
callId,
enabled: !hasLocalAudio,
});
}, [callId, setLocalAudio, hasLocalAudio]);
}, [setLocalAudio, hasLocalAudio]);
const toggleVideo = useCallback(() => {
if (!callId) {
return;
}
setLocalVideo({
callId,
enabled: !hasLocalVideo,
});
}, [callId, setLocalVideo, hasLocalVideo]);
}, [setLocalVideo, hasLocalVideo]);
const [acceptedDuration, setAcceptedDuration] = useState<number | null>(null);
const [showControls, setShowControls] = useState(true);
@ -100,15 +97,15 @@ export const CallScreen: React.FC<PropsType> = ({
}, [setLocalPreview, setRendererCanvas]);
useEffect(() => {
if (!acceptedTime) {
if (!joinedAt) {
return noop;
}
// It's really jumpy with a value of 500ms.
const interval = setInterval(() => {
setAcceptedDuration(Date.now() - acceptedTime);
setAcceptedDuration(Date.now() - joinedAt);
}, 100);
return clearInterval.bind(null, interval);
}, [acceptedTime]);
}, [joinedAt]);
useEffect(() => {
if (!showControls) {
@ -147,10 +144,6 @@ export const CallScreen: React.FC<PropsType> = ({
const isAudioOnly = !hasLocalVideo && !hasRemoteVideo;
if (!callDetails || !callState) {
return null;
}
const controlsFadeClass = classNames({
'module-ongoing-call__controls--fadeIn':
(showControls || isAudioOnly) && callState !== CallState.Accepted,
@ -181,7 +174,7 @@ export const CallScreen: React.FC<PropsType> = ({
)}
>
<div className="module-calling__header--header-name">
{callDetails.title}
{conversation.title}
</div>
{renderHeaderMessage(i18n, callState, acceptedDuration)}
<div className="module-calling-tools">
@ -205,7 +198,7 @@ export const CallScreen: React.FC<PropsType> = ({
ref={remoteVideoRef}
/>
) : (
renderAvatar(i18n, callDetails)
renderAvatar(i18n, conversation)
)}
<div className="module-ongoing-call__footer">
{/* This layout-only element is not ideal.
@ -233,7 +226,7 @@ export const CallScreen: React.FC<PropsType> = ({
buttonType={CallingButtonType.HANG_UP}
i18n={i18n}
onClick={() => {
hangUp({ callId });
hangUp({ conversationId: conversation.id });
}}
tooltipDistance={24}
/>
@ -269,16 +262,22 @@ export const CallScreen: React.FC<PropsType> = ({
function renderAvatar(
i18n: LocalizerType,
callDetails: CallDetailsType
): JSX.Element {
const {
{
avatarPath,
color,
name,
phoneNumber,
profileName,
title,
} = callDetails;
}: {
avatarPath?: string;
color?: ColorType;
title: string;
name?: string;
phoneNumber?: string;
profileName?: string;
}
): JSX.Element {
return (
<div className="module-ongoing-call__remote-video-disabled">
<Avatar

View file

@ -13,11 +13,7 @@ import enMessages from '../../_locales/en/messages.json';
const i18n = setupI18n('en', enMessages);
const callDetails = {
callId: 0,
isIncoming: true,
isVideoCall: true,
const conversation = {
id: '3051234567',
avatarPath: undefined,
color: 'ultramarine' as ColorType,
@ -39,7 +35,7 @@ const camera = {
const createProps = (overrideProps: Partial<PropsType> = {}): PropsType => ({
availableCameras: overrideProps.availableCameras || [camera],
callDetails,
conversation,
hasLocalAudio: boolean('hasLocalAudio', overrideProps.hasLocalAudio || false),
hasLocalVideo: boolean('hasLocalVideo', overrideProps.hasLocalVideo || false),
i18n,
@ -60,8 +56,8 @@ story.add('Default', () => {
return (
<CallingLobby
{...props}
callDetails={{
...callDetails,
conversation={{
...conversation,
avatarPath: 'https://www.stevensegallery.com/600/600',
}}
/>

View file

@ -3,7 +3,6 @@
import React from 'react';
import {
CallDetailsType,
SetLocalAudioType,
SetLocalPreviewType,
SetLocalVideoType,
@ -15,10 +14,15 @@ import {
} from './CallingButton';
import { CallBackgroundBlur } from './CallBackgroundBlur';
import { LocalizerType } from '../types/Util';
import { ColorType } from '../types/Colors';
export type PropsType = {
availableCameras: Array<MediaDeviceInfo>;
callDetails: CallDetailsType;
conversation: {
avatarPath?: string;
color?: ColorType;
title: string;
};
hasLocalAudio: boolean;
hasLocalVideo: boolean;
i18n: LocalizerType;
@ -34,7 +38,7 @@ export type PropsType = {
export const CallingLobby = ({
availableCameras,
callDetails,
conversation,
hasLocalAudio,
hasLocalVideo,
i18n,
@ -50,20 +54,12 @@ export const CallingLobby = ({
const localVideoRef = React.useRef(null);
const toggleAudio = React.useCallback((): void => {
if (!callDetails) {
return;
}
setLocalAudio({ enabled: !hasLocalAudio });
}, [callDetails, hasLocalAudio, setLocalAudio]);
}, [hasLocalAudio, setLocalAudio]);
const toggleVideo = React.useCallback((): void => {
if (!callDetails) {
return;
}
setLocalVideo({ enabled: !hasLocalVideo });
}, [callDetails, hasLocalVideo, setLocalVideo]);
}, [hasLocalVideo, setLocalVideo]);
React.useEffect(() => {
setLocalPreview({ element: localVideoRef });
@ -112,7 +108,7 @@ export const CallingLobby = ({
<div className="module-calling__container">
<div className="module-calling__header">
<div className="module-calling__header--header-name">
{callDetails.title}
{conversation.title}
</div>
<div className="module-calling-tools">
{isGroupCall ? (
@ -136,8 +132,8 @@ export const CallingLobby = ({
<video ref={localVideoRef} autoPlay />
) : (
<CallBackgroundBlur
avatarPath={callDetails.avatarPath}
color={callDetails.color}
avatarPath={conversation.avatarPath}
color={conversation.color}
>
<div className="module-calling-lobby__video-off--icon" />
<span className="module-calling-lobby__video-off--text">

View file

@ -13,11 +13,7 @@ import enMessages from '../../_locales/en/messages.json';
const i18n = setupI18n('en', enMessages);
const callDetails = {
callId: 0,
isIncoming: true,
isVideoCall: true,
const conversation = {
id: '3051234567',
avatarPath: undefined,
color: 'ultramarine' as ColorType,
@ -28,7 +24,7 @@ const callDetails = {
};
const createProps = (overrideProps: Partial<PropsType> = {}): PropsType => ({
callDetails: overrideProps.callDetails || callDetails,
conversation: overrideProps.conversation || conversation,
hangUp: action('hang-up'),
hasLocalVideo: boolean('hasLocalVideo', overrideProps.hasLocalVideo || false),
hasRemoteVideo: boolean(
@ -50,8 +46,8 @@ story.add('Default', () => {
story.add('Contact (with avatar)', () => {
const props = createProps({
callDetails: {
...callDetails,
conversation: {
...conversation,
avatarPath: 'https://www.fillmurray.com/64/64',
},
});
@ -60,8 +56,8 @@ story.add('Contact (with avatar)', () => {
story.add('Contact (no color)', () => {
const props = createProps({
callDetails: {
...callDetails,
conversation: {
...conversation,
color: undefined,
},
});

View file

@ -3,28 +3,33 @@
import React from 'react';
import {
CallDetailsType,
HangUpType,
SetLocalPreviewType,
SetRendererCanvasType,
} from '../state/ducks/calling';
import { Avatar } from './Avatar';
import { CallBackgroundBlur } from './CallBackgroundBlur';
import { ColorType } from '../types/Colors';
import { LocalizerType } from '../types/Util';
function renderAvatar(
callDetails: CallDetailsType,
i18n: LocalizerType
): JSX.Element {
const {
{
avatarPath,
color,
name,
phoneNumber,
profileName,
title,
} = callDetails;
}: {
avatarPath?: string;
color?: ColorType;
title: string;
name?: string;
phoneNumber?: string;
profileName?: string;
},
i18n: LocalizerType
): JSX.Element {
return (
<div className="module-calling-pip__video--remote">
<CallBackgroundBlur avatarPath={avatarPath} color={color}>
@ -48,7 +53,15 @@ function renderAvatar(
}
export type PropsType = {
callDetails: CallDetailsType;
conversation: {
id: string;
avatarPath?: string;
color?: ColorType;
title: string;
name?: string;
phoneNumber?: string;
profileName?: string;
};
hangUp: (_: HangUpType) => void;
hasLocalVideo: boolean;
hasRemoteVideo: boolean;
@ -64,7 +77,7 @@ const PIP_DEFAULT_Y = 56;
const PIP_PADDING = 8;
export const CallingPip = ({
callDetails,
conversation,
hangUp,
hasLocalVideo,
hasRemoteVideo,
@ -204,7 +217,7 @@ export const CallingPip = ({
ref={remoteVideoRef}
/>
) : (
renderAvatar(callDetails, i18n)
renderAvatar(conversation, i18n)
)}
{hasLocalVideo ? (
<video
@ -219,7 +232,7 @@ export const CallingPip = ({
aria-label={i18n('calling__hangup')}
className="module-calling-pip__button--hangup"
onClick={() => {
hangUp({ callId: callDetails.callId });
hangUp({ conversationId: conversation.id });
}}
/>
<button

View file

@ -15,11 +15,13 @@ const i18n = setupI18n('en', enMessages);
const defaultProps = {
acceptCall: action('accept-call'),
callDetails: {
call: {
conversationId: 'fake-conversation-id',
callId: 0,
isIncoming: true,
isVideoCall: true,
},
conversation: {
id: '3051234567',
avatarPath: undefined,
contactColor: 'ultramarine' as ColorType,
@ -33,24 +35,15 @@ const defaultProps = {
};
const permutations = [
{
title: 'Incoming Call Bar (no call details)',
props: {},
},
{
title: 'Incoming Call Bar (video)',
props: {
callDetails: {
...defaultProps.callDetails,
isVideoCall: true,
},
},
props: {},
},
{
title: 'Incoming Call Bar (audio)',
props: {
callDetails: {
...defaultProps.callDetails,
call: {
...defaultProps.call,
isVideoCall: false,
},
},
@ -69,10 +62,13 @@ storiesOf('Components/IncomingCallBar', module)
return (
<IncomingCallBar
{...defaultProps}
callDetails={{
...defaultProps.callDetails,
color,
call={{
...defaultProps.call,
isVideoCall,
}}
conversation={{
...defaultProps.conversation,
color,
name,
}}
/>

View file

@ -6,17 +6,25 @@ import Tooltip from 'react-tooltip-lite';
import { Avatar } from './Avatar';
import { ContactName } from './conversation/ContactName';
import { LocalizerType } from '../types/Util';
import {
AcceptCallType,
CallDetailsType,
DeclineCallType,
} from '../state/ducks/calling';
import { ColorType } from '../types/Colors';
import { AcceptCallType, DeclineCallType } from '../state/ducks/calling';
export type PropsType = {
acceptCall: (_: AcceptCallType) => void;
callDetails?: CallDetailsType;
declineCall: (_: DeclineCallType) => void;
i18n: LocalizerType;
call: {
isVideoCall: boolean;
};
conversation: {
id: string;
avatarPath?: string;
color?: ColorType;
title: string;
name?: string;
phoneNumber?: string;
profileName?: string;
};
};
type CallButtonProps = {
@ -54,23 +62,21 @@ const CallButton = ({
export const IncomingCallBar = ({
acceptCall,
callDetails,
declineCall,
i18n,
call,
conversation,
}: PropsType): JSX.Element | null => {
if (!callDetails) {
return null;
}
const { isVideoCall } = call;
const {
id: conversationId,
avatarPath,
callId,
color,
title,
name,
phoneNumber,
profileName,
} = callDetails;
} = conversation;
return (
<div className="module-incoming-call">
@ -103,21 +109,17 @@ export const IncomingCallBar = ({
dir="auto"
className="module-incoming-call__contact--message-text"
>
{i18n(
callDetails.isVideoCall
? 'incomingVideoCall'
: 'incomingAudioCall'
)}
{i18n(isVideoCall ? 'incomingVideoCall' : 'incomingAudioCall')}
</div>
</div>
</div>
<div className="module-incoming-call__actions">
{callDetails.isVideoCall ? (
{isVideoCall ? (
<>
<CallButton
classSuffix="decline"
onClick={() => {
declineCall({ callId });
declineCall({ conversationId });
}}
tabIndex={0}
tooltipContent={i18n('declineCall')}
@ -125,7 +127,7 @@ export const IncomingCallBar = ({
<CallButton
classSuffix="accept-video-as-audio"
onClick={() => {
acceptCall({ callId, asVideoCall: false });
acceptCall({ conversationId, asVideoCall: false });
}}
tabIndex={0}
tooltipContent={i18n('acceptCallWithoutVideo')}
@ -133,7 +135,7 @@ export const IncomingCallBar = ({
<CallButton
classSuffix="accept-video"
onClick={() => {
acceptCall({ callId, asVideoCall: true });
acceptCall({ conversationId, asVideoCall: true });
}}
tabIndex={0}
tooltipContent={i18n('acceptCall')}
@ -144,7 +146,7 @@ export const IncomingCallBar = ({
<CallButton
classSuffix="decline"
onClick={() => {
declineCall({ callId });
declineCall({ conversationId });
}}
tabIndex={0}
tooltipContent={i18n('declineCall')}
@ -152,7 +154,7 @@ export const IncomingCallBar = ({
<CallButton
classSuffix="accept-audio"
onClick={() => {
acceptCall({ callId, asVideoCall: false });
acceptCall({ conversationId, asVideoCall: false });
}}
tabIndex={0}
tooltipContent={i18n('acceptCall')}