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",
|
||||
"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": {
|
||||
"messageformat": "{count, plural, one {# person} other {# people}}",
|
||||
"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
|
||||
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'),
|
||||
playRingtone: action('play-ringtone'),
|
||||
removeClient: action('remove-client'),
|
||||
blockClient: action('block-client'),
|
||||
renderDeviceSelection: () => <div />,
|
||||
renderEmojiPicker: () => <>EmojiPicker</>,
|
||||
renderReactionPicker: () => <div />,
|
||||
|
|
|
@ -117,6 +117,7 @@ export type PropsType = {
|
|||
openSystemPreferencesAction: () => unknown;
|
||||
playRingtone: () => unknown;
|
||||
removeClient: (payload: RemoveClientType) => void;
|
||||
blockClient: (payload: RemoveClientType) => void;
|
||||
sendGroupCallRaiseHand: (payload: SendGroupCallRaiseHandType) => void;
|
||||
sendGroupCallReaction: (payload: SendGroupCallReactionType) => void;
|
||||
setGroupCallVideoRequest: (_: SetGroupCallVideoRequestType) => void;
|
||||
|
@ -163,6 +164,7 @@ function ActiveCallManager({
|
|||
activeCall,
|
||||
approveUser,
|
||||
availableCameras,
|
||||
blockClient,
|
||||
callLink,
|
||||
cancelCall,
|
||||
changeCallView,
|
||||
|
@ -397,6 +399,7 @@ function ActiveCallManager({
|
|||
onCopyCallLink={onCopyCallLink}
|
||||
onShareCallLinkViaSignal={handleShareCallLinkViaSignal}
|
||||
removeClient={removeClient}
|
||||
blockClient={blockClient}
|
||||
showContactModal={showContactModal}
|
||||
/>
|
||||
) : (
|
||||
|
@ -494,6 +497,7 @@ function ActiveCallManager({
|
|||
onCopyCallLink={onCopyCallLink}
|
||||
onShareCallLinkViaSignal={handleShareCallLinkViaSignal}
|
||||
removeClient={removeClient}
|
||||
blockClient={blockClient}
|
||||
showContactModal={showContactModal}
|
||||
/>
|
||||
) : (
|
||||
|
@ -515,6 +519,7 @@ export function CallManager({
|
|||
activeCall,
|
||||
approveUser,
|
||||
availableCameras,
|
||||
blockClient,
|
||||
bounceAppIconStart,
|
||||
bounceAppIconStop,
|
||||
callLink,
|
||||
|
@ -613,6 +618,7 @@ export function CallManager({
|
|||
activeCall={activeCall}
|
||||
availableCameras={availableCameras}
|
||||
approveUser={approveUser}
|
||||
blockClient={blockClient}
|
||||
callLink={callLink}
|
||||
cancelCall={cancelCall}
|
||||
changeCallView={changeCallView}
|
||||
|
|
|
@ -68,6 +68,7 @@ const createProps = (overrideProps: Partial<PropsType> = {}): PropsType => ({
|
|||
onCopyCallLink: action('on-copy-call-link'),
|
||||
onShareCallLinkViaSignal: action('on-share-call-link-via-signal'),
|
||||
removeClient: overrideProps.removeClient || action('remove-client'),
|
||||
blockClient: overrideProps.blockClient || action('block-client'),
|
||||
showContactModal: action('show-contact-modal'),
|
||||
});
|
||||
|
||||
|
@ -140,3 +141,35 @@ export function Overflow(): JSX.Element {
|
|||
});
|
||||
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 { Modal } from './Modal';
|
||||
import { Theme } from '../util/theme';
|
||||
import { ConfirmationDialog } from './ConfirmationDialog';
|
||||
|
||||
const MAX_UNKNOWN_AVATARS_COUNT = 3;
|
||||
|
||||
|
@ -40,7 +41,8 @@ export type PropsType = {
|
|||
readonly onClose: () => void;
|
||||
readonly onCopyCallLink: () => void;
|
||||
readonly onShareCallLinkViaSignal: () => void;
|
||||
readonly removeClient: ((payload: RemoveClientType) => void) | null;
|
||||
readonly removeClient: (payload: RemoveClientType) => void;
|
||||
readonly blockClient: (payload: RemoveClientType) => void;
|
||||
readonly showContactModal: (
|
||||
contactId: string,
|
||||
conversationId?: string
|
||||
|
@ -145,6 +147,7 @@ export function CallingAdhocCallInfo({
|
|||
isCallLinkAdmin,
|
||||
ourServiceId,
|
||||
participants,
|
||||
blockClient,
|
||||
onClose,
|
||||
onCopyCallLink,
|
||||
onShareCallLinkViaSignal,
|
||||
|
@ -153,6 +156,11 @@ export function CallingAdhocCallInfo({
|
|||
}: PropsType): JSX.Element | null {
|
||||
const [isUnknownContactDialogVisible, setIsUnknownContactDialogVisible] =
|
||||
React.useState(false);
|
||||
const [removeClientDialogState, setRemoveClientDialogState] = React.useState<{
|
||||
demuxId: number;
|
||||
name: string;
|
||||
} | null>(null);
|
||||
|
||||
const hideUnknownContactDialog = React.useCallback(
|
||||
() => setIsUnknownContactDialogVisible(false),
|
||||
[setIsUnknownContactDialogVisible]
|
||||
|
@ -256,7 +264,6 @@ export function CallingAdhocCallInfo({
|
|||
)}
|
||||
/>
|
||||
{isCallLinkAdmin &&
|
||||
removeClient &&
|
||||
participant.demuxId &&
|
||||
!(ourServiceId && participant.serviceId === ourServiceId) ? (
|
||||
<button
|
||||
|
@ -273,7 +280,10 @@ export function CallingAdhocCallInfo({
|
|||
|
||||
event.stopPropagation();
|
||||
event.preventDefault();
|
||||
removeClient({ demuxId: participant.demuxId });
|
||||
setRemoveClientDialogState({
|
||||
demuxId: participant.demuxId,
|
||||
name: participant.title,
|
||||
});
|
||||
}}
|
||||
type="button"
|
||||
/>
|
||||
|
@ -285,13 +295,45 @@ export function CallingAdhocCallInfo({
|
|||
isCallLinkAdmin,
|
||||
onClose,
|
||||
ourServiceId,
|
||||
removeClient,
|
||||
setRemoveClientDialogState,
|
||||
showContactModal,
|
||||
]
|
||||
);
|
||||
|
||||
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 ? (
|
||||
<Modal
|
||||
modalName="CallingAdhocCallInfo.UnknownContactInfo"
|
||||
|
|
|
@ -1592,6 +1592,15 @@ export class CallingClass {
|
|||
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.
|
||||
private convertRingRtcConnectionState(
|
||||
connectionState: ConnectionState
|
||||
|
|
|
@ -574,6 +574,7 @@ const doGroupCallPeek = ({
|
|||
|
||||
const ACCEPT_CALL_PENDING = 'calling/ACCEPT_CALL_PENDING';
|
||||
const APPROVE_USER = 'calling/APPROVE_USER';
|
||||
const BLOCK_CLIENT = 'calling/BLOCK_CLIENT';
|
||||
const CANCEL_CALL = 'calling/CANCEL_CALL';
|
||||
const CANCEL_INCOMING_GROUP_CALL_RING =
|
||||
'calling/CANCEL_INCOMING_GROUP_CALL_RING';
|
||||
|
@ -801,6 +802,10 @@ type RemoveClientActionType = ReadonlyDeep<{
|
|||
type: 'calling/REMOVE_CLIENT';
|
||||
}>;
|
||||
|
||||
type BlockClientActionType = ReadonlyDeep<{
|
||||
type: 'calling/BLOCK_CLIENT';
|
||||
}>;
|
||||
|
||||
type ReturnToActiveCallActionType = ReadonlyDeep<{
|
||||
type: 'calling/RETURN_TO_ACTIVE_CALL';
|
||||
}>;
|
||||
|
@ -1002,7 +1007,7 @@ function removeClient(
|
|||
const activeCall = getActiveCall(getState().calling);
|
||||
if (!activeCall || !isGroupOrAdhocCallMode(activeCall.callMode)) {
|
||||
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;
|
||||
}
|
||||
|
@ -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(
|
||||
payload: CallStateChangeType
|
||||
): ThunkAction<
|
||||
|
@ -2274,6 +2296,7 @@ function switchFromPresentationView(): SwitchFromPresentationViewActionType {
|
|||
export const actions = {
|
||||
acceptCall,
|
||||
approveUser,
|
||||
blockClient,
|
||||
callStateChange,
|
||||
cancelCall,
|
||||
cancelIncomingGroupCallRing,
|
||||
|
|
|
@ -437,6 +437,7 @@ export const SmartCallManager = memo(function SmartCallManager() {
|
|||
declineCall,
|
||||
openSystemPreferencesAction,
|
||||
removeClient,
|
||||
blockClient,
|
||||
sendGroupCallRaiseHand,
|
||||
sendGroupCallReaction,
|
||||
setGroupCallVideoRequest,
|
||||
|
@ -464,6 +465,7 @@ export const SmartCallManager = memo(function SmartCallManager() {
|
|||
activeCall={activeCall}
|
||||
approveUser={approveUser}
|
||||
availableCameras={availableCameras}
|
||||
blockClient={blockClient}
|
||||
bounceAppIconStart={bounceAppIconStart}
|
||||
bounceAppIconStop={bounceAppIconStop}
|
||||
callLink={callLink}
|
||||
|
|
Loading…
Reference in a new issue