Block users from joining call links
This commit is contained in:
parent
71ae6ea93a
commit
4ae563cc95
9 changed files with 137 additions and 5 deletions
|
@ -3694,6 +3694,18 @@
|
||||||
"messageformat": "Remove this person from the call",
|
"messageformat": "Remove this person from the call",
|
||||||
"description": "Button in the in-call info popup for call link calls showing all participants. The action is to remove the participant from the call."
|
"description": "Button in the in-call info popup for call link calls showing all participants. The action is to remove the participant from the call."
|
||||||
},
|
},
|
||||||
|
"icu:CallingAdhocCallInfo__RemoveClientDialogBody": {
|
||||||
|
"messageformat": "Remove {name} from the call?",
|
||||||
|
"description": "Info text in confirmation dialog when removing or blocking someone from an ongoing call for a call link."
|
||||||
|
},
|
||||||
|
"icu:CallingAdhocCallInfo__RemoveClientDialogButton--remove": {
|
||||||
|
"messageformat": "Remove",
|
||||||
|
"description": "Button in confirmation dialog when removing or blocking someone from an ongoing call for a call link."
|
||||||
|
},
|
||||||
|
"icu:CallingAdhocCallInfo__RemoveClientDialogButton--block": {
|
||||||
|
"messageformat": "Block from call",
|
||||||
|
"description": "Button in confirmation dialog when removing or blocking someone from an ongoing call for a call link."
|
||||||
|
},
|
||||||
"icu:CallingAdhocCallInfo__UnknownContactLabel": {
|
"icu:CallingAdhocCallInfo__UnknownContactLabel": {
|
||||||
"messageformat": "{count, plural, one {# person} other {# people}}",
|
"messageformat": "{count, plural, one {# person} other {# people}}",
|
||||||
"description": "Label showing number of unknown contacts in the in-call participant info popup for call links."
|
"description": "Label showing number of unknown contacts in the in-call participant info popup for call links."
|
||||||
|
|
|
@ -137,3 +137,7 @@
|
||||||
// Should match background of .module-calling-participants-list__contact:hover
|
// Should match background of .module-calling-participants-list__contact:hover
|
||||||
outline-color: $color-gray-62;
|
outline-color: $color-gray-62;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.CallingAdhocCallInfo__RemoveClientDialog {
|
||||||
|
width: 440px;
|
||||||
|
}
|
||||||
|
|
|
@ -100,6 +100,7 @@ const createProps = (storyProps: Partial<PropsType> = {}): PropsType => ({
|
||||||
openSystemPreferencesAction: action('open-system-preferences-action'),
|
openSystemPreferencesAction: action('open-system-preferences-action'),
|
||||||
playRingtone: action('play-ringtone'),
|
playRingtone: action('play-ringtone'),
|
||||||
removeClient: action('remove-client'),
|
removeClient: action('remove-client'),
|
||||||
|
blockClient: action('block-client'),
|
||||||
renderDeviceSelection: () => <div />,
|
renderDeviceSelection: () => <div />,
|
||||||
renderEmojiPicker: () => <>EmojiPicker</>,
|
renderEmojiPicker: () => <>EmojiPicker</>,
|
||||||
renderReactionPicker: () => <div />,
|
renderReactionPicker: () => <div />,
|
||||||
|
|
|
@ -117,6 +117,7 @@ export type PropsType = {
|
||||||
openSystemPreferencesAction: () => unknown;
|
openSystemPreferencesAction: () => unknown;
|
||||||
playRingtone: () => unknown;
|
playRingtone: () => unknown;
|
||||||
removeClient: (payload: RemoveClientType) => void;
|
removeClient: (payload: RemoveClientType) => void;
|
||||||
|
blockClient: (payload: RemoveClientType) => void;
|
||||||
sendGroupCallRaiseHand: (payload: SendGroupCallRaiseHandType) => void;
|
sendGroupCallRaiseHand: (payload: SendGroupCallRaiseHandType) => void;
|
||||||
sendGroupCallReaction: (payload: SendGroupCallReactionType) => void;
|
sendGroupCallReaction: (payload: SendGroupCallReactionType) => void;
|
||||||
setGroupCallVideoRequest: (_: SetGroupCallVideoRequestType) => void;
|
setGroupCallVideoRequest: (_: SetGroupCallVideoRequestType) => void;
|
||||||
|
@ -163,6 +164,7 @@ function ActiveCallManager({
|
||||||
activeCall,
|
activeCall,
|
||||||
approveUser,
|
approveUser,
|
||||||
availableCameras,
|
availableCameras,
|
||||||
|
blockClient,
|
||||||
callLink,
|
callLink,
|
||||||
cancelCall,
|
cancelCall,
|
||||||
changeCallView,
|
changeCallView,
|
||||||
|
@ -397,6 +399,7 @@ function ActiveCallManager({
|
||||||
onCopyCallLink={onCopyCallLink}
|
onCopyCallLink={onCopyCallLink}
|
||||||
onShareCallLinkViaSignal={handleShareCallLinkViaSignal}
|
onShareCallLinkViaSignal={handleShareCallLinkViaSignal}
|
||||||
removeClient={removeClient}
|
removeClient={removeClient}
|
||||||
|
blockClient={blockClient}
|
||||||
showContactModal={showContactModal}
|
showContactModal={showContactModal}
|
||||||
/>
|
/>
|
||||||
) : (
|
) : (
|
||||||
|
@ -494,6 +497,7 @@ function ActiveCallManager({
|
||||||
onCopyCallLink={onCopyCallLink}
|
onCopyCallLink={onCopyCallLink}
|
||||||
onShareCallLinkViaSignal={handleShareCallLinkViaSignal}
|
onShareCallLinkViaSignal={handleShareCallLinkViaSignal}
|
||||||
removeClient={removeClient}
|
removeClient={removeClient}
|
||||||
|
blockClient={blockClient}
|
||||||
showContactModal={showContactModal}
|
showContactModal={showContactModal}
|
||||||
/>
|
/>
|
||||||
) : (
|
) : (
|
||||||
|
@ -515,6 +519,7 @@ export function CallManager({
|
||||||
activeCall,
|
activeCall,
|
||||||
approveUser,
|
approveUser,
|
||||||
availableCameras,
|
availableCameras,
|
||||||
|
blockClient,
|
||||||
bounceAppIconStart,
|
bounceAppIconStart,
|
||||||
bounceAppIconStop,
|
bounceAppIconStop,
|
||||||
callLink,
|
callLink,
|
||||||
|
@ -613,6 +618,7 @@ export function CallManager({
|
||||||
activeCall={activeCall}
|
activeCall={activeCall}
|
||||||
availableCameras={availableCameras}
|
availableCameras={availableCameras}
|
||||||
approveUser={approveUser}
|
approveUser={approveUser}
|
||||||
|
blockClient={blockClient}
|
||||||
callLink={callLink}
|
callLink={callLink}
|
||||||
cancelCall={cancelCall}
|
cancelCall={cancelCall}
|
||||||
changeCallView={changeCallView}
|
changeCallView={changeCallView}
|
||||||
|
|
|
@ -68,6 +68,7 @@ const createProps = (overrideProps: Partial<PropsType> = {}): PropsType => ({
|
||||||
onCopyCallLink: action('on-copy-call-link'),
|
onCopyCallLink: action('on-copy-call-link'),
|
||||||
onShareCallLinkViaSignal: action('on-share-call-link-via-signal'),
|
onShareCallLinkViaSignal: action('on-share-call-link-via-signal'),
|
||||||
removeClient: overrideProps.removeClient || action('remove-client'),
|
removeClient: overrideProps.removeClient || action('remove-client'),
|
||||||
|
blockClient: overrideProps.blockClient || action('block-client'),
|
||||||
showContactModal: action('show-contact-modal'),
|
showContactModal: action('show-contact-modal'),
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -140,3 +141,35 @@ export function Overflow(): JSX.Element {
|
||||||
});
|
});
|
||||||
return <CallingAdhocCallInfo {...props} />;
|
return <CallingAdhocCallInfo {...props} />;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function AsAdmin(): JSX.Element {
|
||||||
|
const props = createProps({
|
||||||
|
participants: [
|
||||||
|
createParticipant({
|
||||||
|
title: 'Son Goku',
|
||||||
|
}),
|
||||||
|
createParticipant({
|
||||||
|
hasRemoteAudio: true,
|
||||||
|
hasRemoteVideo: true,
|
||||||
|
presenting: true,
|
||||||
|
name: 'Rage Trunks',
|
||||||
|
title: 'Rage Trunks',
|
||||||
|
}),
|
||||||
|
createParticipant({
|
||||||
|
hasRemoteAudio: true,
|
||||||
|
title: 'Prince Vegeta',
|
||||||
|
}),
|
||||||
|
createParticipant({
|
||||||
|
hasRemoteAudio: true,
|
||||||
|
hasRemoteVideo: true,
|
||||||
|
name: 'Goku',
|
||||||
|
title: 'Goku',
|
||||||
|
}),
|
||||||
|
createParticipant({
|
||||||
|
title: 'Someone With A Really Long Name',
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
isCallLinkAdmin: true,
|
||||||
|
});
|
||||||
|
return <CallingAdhocCallInfo {...props} />;
|
||||||
|
}
|
||||||
|
|
|
@ -20,6 +20,7 @@ import { AVATAR_COLOR_COUNT, AvatarColors } from '../types/Colors';
|
||||||
import { Button } from './Button';
|
import { Button } from './Button';
|
||||||
import { Modal } from './Modal';
|
import { Modal } from './Modal';
|
||||||
import { Theme } from '../util/theme';
|
import { Theme } from '../util/theme';
|
||||||
|
import { ConfirmationDialog } from './ConfirmationDialog';
|
||||||
|
|
||||||
const MAX_UNKNOWN_AVATARS_COUNT = 3;
|
const MAX_UNKNOWN_AVATARS_COUNT = 3;
|
||||||
|
|
||||||
|
@ -40,7 +41,8 @@ export type PropsType = {
|
||||||
readonly onClose: () => void;
|
readonly onClose: () => void;
|
||||||
readonly onCopyCallLink: () => void;
|
readonly onCopyCallLink: () => void;
|
||||||
readonly onShareCallLinkViaSignal: () => void;
|
readonly onShareCallLinkViaSignal: () => void;
|
||||||
readonly removeClient: ((payload: RemoveClientType) => void) | null;
|
readonly removeClient: (payload: RemoveClientType) => void;
|
||||||
|
readonly blockClient: (payload: RemoveClientType) => void;
|
||||||
readonly showContactModal: (
|
readonly showContactModal: (
|
||||||
contactId: string,
|
contactId: string,
|
||||||
conversationId?: string
|
conversationId?: string
|
||||||
|
@ -145,6 +147,7 @@ export function CallingAdhocCallInfo({
|
||||||
isCallLinkAdmin,
|
isCallLinkAdmin,
|
||||||
ourServiceId,
|
ourServiceId,
|
||||||
participants,
|
participants,
|
||||||
|
blockClient,
|
||||||
onClose,
|
onClose,
|
||||||
onCopyCallLink,
|
onCopyCallLink,
|
||||||
onShareCallLinkViaSignal,
|
onShareCallLinkViaSignal,
|
||||||
|
@ -153,6 +156,11 @@ export function CallingAdhocCallInfo({
|
||||||
}: PropsType): JSX.Element | null {
|
}: PropsType): JSX.Element | null {
|
||||||
const [isUnknownContactDialogVisible, setIsUnknownContactDialogVisible] =
|
const [isUnknownContactDialogVisible, setIsUnknownContactDialogVisible] =
|
||||||
React.useState(false);
|
React.useState(false);
|
||||||
|
const [removeClientDialogState, setRemoveClientDialogState] = React.useState<{
|
||||||
|
demuxId: number;
|
||||||
|
name: string;
|
||||||
|
} | null>(null);
|
||||||
|
|
||||||
const hideUnknownContactDialog = React.useCallback(
|
const hideUnknownContactDialog = React.useCallback(
|
||||||
() => setIsUnknownContactDialogVisible(false),
|
() => setIsUnknownContactDialogVisible(false),
|
||||||
[setIsUnknownContactDialogVisible]
|
[setIsUnknownContactDialogVisible]
|
||||||
|
@ -256,7 +264,6 @@ export function CallingAdhocCallInfo({
|
||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
{isCallLinkAdmin &&
|
{isCallLinkAdmin &&
|
||||||
removeClient &&
|
|
||||||
participant.demuxId &&
|
participant.demuxId &&
|
||||||
!(ourServiceId && participant.serviceId === ourServiceId) ? (
|
!(ourServiceId && participant.serviceId === ourServiceId) ? (
|
||||||
<button
|
<button
|
||||||
|
@ -273,7 +280,10 @@ export function CallingAdhocCallInfo({
|
||||||
|
|
||||||
event.stopPropagation();
|
event.stopPropagation();
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
removeClient({ demuxId: participant.demuxId });
|
setRemoveClientDialogState({
|
||||||
|
demuxId: participant.demuxId,
|
||||||
|
name: participant.title,
|
||||||
|
});
|
||||||
}}
|
}}
|
||||||
type="button"
|
type="button"
|
||||||
/>
|
/>
|
||||||
|
@ -285,13 +295,45 @@ export function CallingAdhocCallInfo({
|
||||||
isCallLinkAdmin,
|
isCallLinkAdmin,
|
||||||
onClose,
|
onClose,
|
||||||
ourServiceId,
|
ourServiceId,
|
||||||
removeClient,
|
setRemoveClientDialogState,
|
||||||
showContactModal,
|
showContactModal,
|
||||||
]
|
]
|
||||||
);
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
|
{removeClientDialogState != null ? (
|
||||||
|
<ConfirmationDialog
|
||||||
|
dialogName="CallingAdhocCallInfo.removeClientDialog"
|
||||||
|
moduleClassName="CallingAdhocCallInfo__RemoveClientDialog"
|
||||||
|
actions={[
|
||||||
|
{
|
||||||
|
action: () =>
|
||||||
|
blockClient({ demuxId: removeClientDialogState.demuxId }),
|
||||||
|
style: 'negative',
|
||||||
|
text: i18n(
|
||||||
|
'icu:CallingAdhocCallInfo__RemoveClientDialogButton--block'
|
||||||
|
),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
action: () =>
|
||||||
|
removeClient({ demuxId: removeClientDialogState.demuxId }),
|
||||||
|
style: 'negative',
|
||||||
|
text: i18n(
|
||||||
|
'icu:CallingAdhocCallInfo__RemoveClientDialogButton--remove'
|
||||||
|
),
|
||||||
|
},
|
||||||
|
]}
|
||||||
|
cancelText={i18n('icu:cancel')}
|
||||||
|
i18n={i18n}
|
||||||
|
theme={Theme.Dark}
|
||||||
|
onClose={() => setRemoveClientDialogState(null)}
|
||||||
|
>
|
||||||
|
{i18n('icu:CallingAdhocCallInfo__RemoveClientDialogBody', {
|
||||||
|
name: removeClientDialogState.name,
|
||||||
|
})}
|
||||||
|
</ConfirmationDialog>
|
||||||
|
) : null}
|
||||||
{isUnknownContactDialogVisible ? (
|
{isUnknownContactDialogVisible ? (
|
||||||
<Modal
|
<Modal
|
||||||
modalName="CallingAdhocCallInfo.UnknownContactInfo"
|
modalName="CallingAdhocCallInfo.UnknownContactInfo"
|
||||||
|
|
|
@ -1592,6 +1592,15 @@ export class CallingClass {
|
||||||
groupCall.removeClient(demuxId);
|
groupCall.removeClient(demuxId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public blockClient(conversationId: string, demuxId: number): void {
|
||||||
|
const groupCall = this.getGroupCall(conversationId);
|
||||||
|
if (!groupCall) {
|
||||||
|
throw new Error('Could not find matching call');
|
||||||
|
}
|
||||||
|
|
||||||
|
groupCall.blockClient(demuxId);
|
||||||
|
}
|
||||||
|
|
||||||
// See the comment in types/Calling.ts to explain why we have to do this conversion.
|
// See the comment in types/Calling.ts to explain why we have to do this conversion.
|
||||||
private convertRingRtcConnectionState(
|
private convertRingRtcConnectionState(
|
||||||
connectionState: ConnectionState
|
connectionState: ConnectionState
|
||||||
|
|
|
@ -574,6 +574,7 @@ const doGroupCallPeek = ({
|
||||||
|
|
||||||
const ACCEPT_CALL_PENDING = 'calling/ACCEPT_CALL_PENDING';
|
const ACCEPT_CALL_PENDING = 'calling/ACCEPT_CALL_PENDING';
|
||||||
const APPROVE_USER = 'calling/APPROVE_USER';
|
const APPROVE_USER = 'calling/APPROVE_USER';
|
||||||
|
const BLOCK_CLIENT = 'calling/BLOCK_CLIENT';
|
||||||
const CANCEL_CALL = 'calling/CANCEL_CALL';
|
const CANCEL_CALL = 'calling/CANCEL_CALL';
|
||||||
const CANCEL_INCOMING_GROUP_CALL_RING =
|
const CANCEL_INCOMING_GROUP_CALL_RING =
|
||||||
'calling/CANCEL_INCOMING_GROUP_CALL_RING';
|
'calling/CANCEL_INCOMING_GROUP_CALL_RING';
|
||||||
|
@ -801,6 +802,10 @@ type RemoveClientActionType = ReadonlyDeep<{
|
||||||
type: 'calling/REMOVE_CLIENT';
|
type: 'calling/REMOVE_CLIENT';
|
||||||
}>;
|
}>;
|
||||||
|
|
||||||
|
type BlockClientActionType = ReadonlyDeep<{
|
||||||
|
type: 'calling/BLOCK_CLIENT';
|
||||||
|
}>;
|
||||||
|
|
||||||
type ReturnToActiveCallActionType = ReadonlyDeep<{
|
type ReturnToActiveCallActionType = ReadonlyDeep<{
|
||||||
type: 'calling/RETURN_TO_ACTIVE_CALL';
|
type: 'calling/RETURN_TO_ACTIVE_CALL';
|
||||||
}>;
|
}>;
|
||||||
|
@ -1002,7 +1007,7 @@ function removeClient(
|
||||||
const activeCall = getActiveCall(getState().calling);
|
const activeCall = getActiveCall(getState().calling);
|
||||||
if (!activeCall || !isGroupOrAdhocCallMode(activeCall.callMode)) {
|
if (!activeCall || !isGroupOrAdhocCallMode(activeCall.callMode)) {
|
||||||
log.warn(
|
log.warn(
|
||||||
'approveUser: Trying to approve pending user without active group or adhoc call'
|
'removeClient: Trying to remove client without active group or adhoc call'
|
||||||
);
|
);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -1012,6 +1017,23 @@ function removeClient(
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function blockClient(
|
||||||
|
payload: RemoveClientType
|
||||||
|
): ThunkAction<void, RootStateType, unknown, BlockClientActionType> {
|
||||||
|
return (dispatch, getState) => {
|
||||||
|
const activeCall = getActiveCall(getState().calling);
|
||||||
|
if (!activeCall || !isGroupOrAdhocCallMode(activeCall.callMode)) {
|
||||||
|
log.warn(
|
||||||
|
'blockClient: Trying to block client without active group or adhoc call'
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
calling.blockClient(activeCall.conversationId, payload.demuxId);
|
||||||
|
dispatch({ type: BLOCK_CLIENT });
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
function callStateChange(
|
function callStateChange(
|
||||||
payload: CallStateChangeType
|
payload: CallStateChangeType
|
||||||
): ThunkAction<
|
): ThunkAction<
|
||||||
|
@ -2274,6 +2296,7 @@ function switchFromPresentationView(): SwitchFromPresentationViewActionType {
|
||||||
export const actions = {
|
export const actions = {
|
||||||
acceptCall,
|
acceptCall,
|
||||||
approveUser,
|
approveUser,
|
||||||
|
blockClient,
|
||||||
callStateChange,
|
callStateChange,
|
||||||
cancelCall,
|
cancelCall,
|
||||||
cancelIncomingGroupCallRing,
|
cancelIncomingGroupCallRing,
|
||||||
|
|
|
@ -437,6 +437,7 @@ export const SmartCallManager = memo(function SmartCallManager() {
|
||||||
declineCall,
|
declineCall,
|
||||||
openSystemPreferencesAction,
|
openSystemPreferencesAction,
|
||||||
removeClient,
|
removeClient,
|
||||||
|
blockClient,
|
||||||
sendGroupCallRaiseHand,
|
sendGroupCallRaiseHand,
|
||||||
sendGroupCallReaction,
|
sendGroupCallReaction,
|
||||||
setGroupCallVideoRequest,
|
setGroupCallVideoRequest,
|
||||||
|
@ -464,6 +465,7 @@ export const SmartCallManager = memo(function SmartCallManager() {
|
||||||
activeCall={activeCall}
|
activeCall={activeCall}
|
||||||
approveUser={approveUser}
|
approveUser={approveUser}
|
||||||
availableCameras={availableCameras}
|
availableCameras={availableCameras}
|
||||||
|
blockClient={blockClient}
|
||||||
bounceAppIconStart={bounceAppIconStart}
|
bounceAppIconStart={bounceAppIconStart}
|
||||||
bounceAppIconStop={bounceAppIconStop}
|
bounceAppIconStop={bounceAppIconStop}
|
||||||
callLink={callLink}
|
callLink={callLink}
|
||||||
|
|
Loading…
Reference in a new issue