Contact info modal for call link join requests
This commit is contained in:
parent
390eab2556
commit
84896d0fbb
19 changed files with 519 additions and 6 deletions
|
@ -7437,6 +7437,14 @@
|
|||
"messageformat": "Require admin approval",
|
||||
"description": "Call Link Edit Modal > Require admin approval checkbox > Label"
|
||||
},
|
||||
"icu:CallLinkPendingParticipantModal__ApproveButtonLabel": {
|
||||
"messageformat": "Approve entry",
|
||||
"description": "Call Link Pending Participant Modal > Approve Join Request Button Label"
|
||||
},
|
||||
"icu:CallLinkPendingParticipantModal__DenyButtonLabel": {
|
||||
"messageformat": "Deny entry",
|
||||
"description": "Call Link Pending Participant Modal > Deny Join Request Button Label"
|
||||
},
|
||||
"icu:CallLinkRestrictionsSelect__Option--Off": {
|
||||
"messageformat": "Off",
|
||||
"description": "Call Link Edit Modal > Require admin approval checkbox > Option > Off"
|
||||
|
|
106
stylesheets/components/CallLinkPendingParticipantModal.scss
Normal file
106
stylesheets/components/CallLinkPendingParticipantModal.scss
Normal file
|
@ -0,0 +1,106 @@
|
|||
// Copyright 2024 Signal Messenger, LLC
|
||||
// SPDX-License-Identifier: AGPL-3.0-only
|
||||
|
||||
// Overriding default style
|
||||
.module-Modal__body_inner.CallLinkPendingParticipantModal__body_inner {
|
||||
align-items: center;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
margin-top: 4px;
|
||||
margin-bottom: 14px;
|
||||
padding-inline: 8px;
|
||||
}
|
||||
|
||||
.CallLinkPendingParticipantModal__NameButton {
|
||||
@include button-reset();
|
||||
@include font-title-1;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: baseline;
|
||||
max-width: 100%;
|
||||
margin-top: 12px;
|
||||
font-weight: 500;
|
||||
color: $color-gray-05;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.CallLinkPendingParticipantModal__InContactsIcon {
|
||||
height: 22px;
|
||||
width: 22px;
|
||||
@include any-theme {
|
||||
background-color: currentColor;
|
||||
}
|
||||
}
|
||||
|
||||
.CallLinkPendingParticipantModal__AboutIcon {
|
||||
display: inline-block;
|
||||
height: 20px;
|
||||
width: 20px;
|
||||
|
||||
position: relative;
|
||||
inset-block-start: 2px;
|
||||
|
||||
@include color-svg(
|
||||
'../images/icons/v3/chevron/chevron-right-bold.svg',
|
||||
$color-gray-25
|
||||
);
|
||||
}
|
||||
|
||||
.CallLinkPendingParticipantModal__SharedGroupInfo {
|
||||
margin-top: 10px;
|
||||
color: $color-gray-25;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.CallLinkPendingParticipantModal__Hr {
|
||||
width: 100%;
|
||||
margin-block: 24px;
|
||||
border: none;
|
||||
height: 1px;
|
||||
background: $color-gray-65;
|
||||
}
|
||||
|
||||
.CallLinkPendingParticipantModal__ActionButton {
|
||||
@include button-reset;
|
||||
|
||||
display: flex;
|
||||
padding-block: 6px;
|
||||
width: 100%;
|
||||
align-items: center;
|
||||
color: $color-gray-05;
|
||||
}
|
||||
|
||||
.CallLinkPendingParticipantModal__ActionButton:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.CallLinkPendingParticipantModal__ActionButton:focus {
|
||||
@include keyboard-mode {
|
||||
background: $color-gray-65;
|
||||
}
|
||||
}
|
||||
|
||||
.CallLinkPendingParticipantModal__ButtonIcon {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
margin-inline-end: 12px;
|
||||
width: 20px;
|
||||
}
|
||||
|
||||
.CallLinkPendingParticipantModal__ButtonIconContent {
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
}
|
||||
|
||||
.CallLinkPendingParticipantModal__ButtonIconContent--approve {
|
||||
@include color-svg(
|
||||
'../images/icons/v3/check/check-circle.svg',
|
||||
$color-gray-25
|
||||
);
|
||||
}
|
||||
|
||||
.CallLinkPendingParticipantModal__ButtonIconContent--deny {
|
||||
@include color-svg('../images/icons/v3/x/x-circle.svg', $color-gray-25);
|
||||
}
|
|
@ -34,11 +34,36 @@
|
|||
margin-inline-start: 8px;
|
||||
}
|
||||
|
||||
.CallingPendingParticipants__ParticipantButton {
|
||||
@include button-reset();
|
||||
}
|
||||
|
||||
.CallingPendingParticipants__ParticipantButton:focus {
|
||||
@include keyboard-mode {
|
||||
outline: 3px solid $color-ultramarine;
|
||||
outline-offset: 1px;
|
||||
}
|
||||
}
|
||||
|
||||
.CallingPendingParticipants__ParticipantName {
|
||||
@include font-body-1-bold;
|
||||
color: $color-gray-15;
|
||||
}
|
||||
|
||||
.CallingPendingParticipants__ParticipantAboutIcon {
|
||||
display: inline-block;
|
||||
height: 14px;
|
||||
width: 14px;
|
||||
|
||||
position: relative;
|
||||
inset-block-start: 3px;
|
||||
|
||||
@include color-svg(
|
||||
'../images/icons/v3/chevron/chevron-right-bold.svg',
|
||||
$color-gray-05
|
||||
);
|
||||
}
|
||||
|
||||
.CallingPendingParticipants__WouldLikeToJoin {
|
||||
@include font-body-2;
|
||||
color: $color-gray-20;
|
||||
|
|
|
@ -54,6 +54,7 @@
|
|||
@import './components/CallLinkAddNameModal.scss';
|
||||
@import './components/CallLinkDetails.scss';
|
||||
@import './components/CallLinkEditModal.scss';
|
||||
@import './components/CallLinkPendingParticipantModal.scss';
|
||||
@import './components/CallLinkRestrictionsSelect.scss';
|
||||
@import './components/CallingRaisedHandsList.scss';
|
||||
@import './components/CallingRaisedHandsToasts.scss';
|
||||
|
|
69
ts/components/CallLinkPendingParticipantModal.stories.tsx
Normal file
69
ts/components/CallLinkPendingParticipantModal.stories.tsx
Normal file
|
@ -0,0 +1,69 @@
|
|||
// Copyright 2024 Signal Messenger, LLC
|
||||
// SPDX-License-Identifier: AGPL-3.0-only
|
||||
|
||||
import React from 'react';
|
||||
import { action } from '@storybook/addon-actions';
|
||||
import { setupI18n } from '../util/setupI18n';
|
||||
import enMessages from '../../_locales/en/messages.json';
|
||||
import type { CallLinkPendingParticipantModalProps } from './CallLinkPendingParticipantModal';
|
||||
import { CallLinkPendingParticipantModal } from './CallLinkPendingParticipantModal';
|
||||
import type { ComponentMeta } from '../storybook/types';
|
||||
import { getDefaultConversation } from '../test-both/helpers/getDefaultConversation';
|
||||
|
||||
const i18n = setupI18n('en', enMessages);
|
||||
|
||||
const conversation = getDefaultConversation({
|
||||
acceptedMessageRequest: true,
|
||||
hasMessages: true,
|
||||
});
|
||||
const conversationWithSharedGroups = getDefaultConversation({
|
||||
acceptedMessageRequest: true,
|
||||
aboutText: 'likes to chat',
|
||||
hasMessages: true,
|
||||
sharedGroupNames: ['Axolotl lovers'],
|
||||
});
|
||||
const systemContact = getDefaultConversation({
|
||||
acceptedMessageRequest: true,
|
||||
systemGivenName: 'Alice',
|
||||
phoneNumber: '+1 555 123-4567',
|
||||
hasMessages: true,
|
||||
});
|
||||
|
||||
export default {
|
||||
title: 'Components/CallLinkPendingParticipantModal',
|
||||
component: CallLinkPendingParticipantModal,
|
||||
args: {
|
||||
i18n,
|
||||
conversation,
|
||||
approveUser: action('approveUser'),
|
||||
denyUser: action('denyUser'),
|
||||
toggleAboutContactModal: action('toggleAboutContactModal'),
|
||||
onClose: action('onClose'),
|
||||
updateSharedGroups: action('updateSharedGroups'),
|
||||
},
|
||||
} satisfies ComponentMeta<CallLinkPendingParticipantModalProps>;
|
||||
|
||||
export function Default(
|
||||
args: CallLinkPendingParticipantModalProps
|
||||
): JSX.Element {
|
||||
return <CallLinkPendingParticipantModal {...args} />;
|
||||
}
|
||||
|
||||
export function SystemContact(
|
||||
args: CallLinkPendingParticipantModalProps
|
||||
): JSX.Element {
|
||||
return (
|
||||
<CallLinkPendingParticipantModal {...args} conversation={systemContact} />
|
||||
);
|
||||
}
|
||||
|
||||
export function WithSharedGroups(
|
||||
args: CallLinkPendingParticipantModalProps
|
||||
): JSX.Element {
|
||||
return (
|
||||
<CallLinkPendingParticipantModal
|
||||
{...args}
|
||||
conversation={conversationWithSharedGroups}
|
||||
/>
|
||||
);
|
||||
}
|
140
ts/components/CallLinkPendingParticipantModal.tsx
Normal file
140
ts/components/CallLinkPendingParticipantModal.tsx
Normal file
|
@ -0,0 +1,140 @@
|
|||
// Copyright 2024 Signal Messenger, LLC
|
||||
// SPDX-License-Identifier: AGPL-3.0-only
|
||||
|
||||
import React, { useCallback, useEffect, useMemo } from 'react';
|
||||
import { Modal } from './Modal';
|
||||
import type { LocalizerType } from '../types/I18N';
|
||||
import { Avatar, AvatarSize } from './Avatar';
|
||||
import type { PendingUserActionPayloadType } from '../state/ducks/calling';
|
||||
import type { ConversationType } from '../state/ducks/conversations';
|
||||
import { InContactsIcon } from './InContactsIcon';
|
||||
import { isInSystemContacts } from '../util/isInSystemContacts';
|
||||
import { ThemeType } from '../types/Util';
|
||||
import { Theme } from '../util/theme';
|
||||
import { UserText } from './UserText';
|
||||
import { SharedGroupNames } from './SharedGroupNames';
|
||||
|
||||
export type CallLinkPendingParticipantModalProps = {
|
||||
readonly i18n: LocalizerType;
|
||||
readonly conversation: ConversationType;
|
||||
readonly approveUser: (payload: PendingUserActionPayloadType) => void;
|
||||
readonly denyUser: (payload: PendingUserActionPayloadType) => void;
|
||||
readonly onClose: () => void;
|
||||
readonly toggleAboutContactModal: (conversationId: string) => void;
|
||||
readonly updateSharedGroups: (conversationId: string) => void;
|
||||
};
|
||||
|
||||
export function CallLinkPendingParticipantModal({
|
||||
i18n,
|
||||
conversation,
|
||||
approveUser,
|
||||
denyUser,
|
||||
onClose,
|
||||
toggleAboutContactModal,
|
||||
updateSharedGroups,
|
||||
}: CallLinkPendingParticipantModalProps): JSX.Element {
|
||||
useEffect(() => {
|
||||
// Kick off the expensive hydration of the current sharedGroupNames
|
||||
updateSharedGroups(conversation.id);
|
||||
}, [conversation.id, updateSharedGroups]);
|
||||
|
||||
const serviceId = useMemo(() => {
|
||||
return conversation.serviceId;
|
||||
}, [conversation]);
|
||||
|
||||
const handleApprove = useCallback(() => {
|
||||
approveUser({ serviceId });
|
||||
onClose();
|
||||
}, [approveUser, onClose, serviceId]);
|
||||
|
||||
const handleDeny = useCallback(() => {
|
||||
denyUser({ serviceId });
|
||||
onClose();
|
||||
}, [denyUser, onClose, serviceId]);
|
||||
|
||||
return (
|
||||
<Modal
|
||||
modalName="CallLinkPendingParticipantModal"
|
||||
moduleClassName="CallLinkPendingParticipantModal"
|
||||
hasXButton
|
||||
i18n={i18n}
|
||||
onClose={onClose}
|
||||
theme={Theme.Dark}
|
||||
>
|
||||
<Avatar
|
||||
acceptedMessageRequest={conversation.acceptedMessageRequest}
|
||||
avatarUrl={conversation.avatarUrl}
|
||||
badge={undefined}
|
||||
color={conversation.color}
|
||||
conversationType="direct"
|
||||
i18n={i18n}
|
||||
isMe={conversation.isMe}
|
||||
profileName={conversation.profileName}
|
||||
sharedGroupNames={conversation.sharedGroupNames}
|
||||
size={AvatarSize.EIGHTY}
|
||||
title={conversation.title}
|
||||
theme={ThemeType.dark}
|
||||
unblurredAvatarUrl={conversation.unblurredAvatarUrl}
|
||||
/>
|
||||
|
||||
<button
|
||||
type="button"
|
||||
onClick={ev => {
|
||||
ev.preventDefault();
|
||||
ev.stopPropagation();
|
||||
toggleAboutContactModal(conversation.id);
|
||||
}}
|
||||
className="CallLinkPendingParticipantModal__NameButton"
|
||||
>
|
||||
<div className="CallLinkPendingParticipantModal__Title">
|
||||
<UserText text={conversation.title} />
|
||||
{isInSystemContacts(conversation) && (
|
||||
<span>
|
||||
{' '}
|
||||
<InContactsIcon
|
||||
className="module-in-contacts-icon__icon CallLinkPendingParticipantModal__InContactsIcon"
|
||||
i18n={i18n}
|
||||
/>
|
||||
</span>
|
||||
)}
|
||||
<span className="CallLinkPendingParticipantModal__AboutIcon" />
|
||||
</div>
|
||||
</button>
|
||||
|
||||
<div className="CallLinkPendingParticipantModal__SharedGroupInfo">
|
||||
{conversation.sharedGroupNames?.length ? (
|
||||
<SharedGroupNames
|
||||
i18n={i18n}
|
||||
sharedGroupNames={conversation.sharedGroupNames || []}
|
||||
/>
|
||||
) : (
|
||||
i18n('icu:no-groups-in-common-warning')
|
||||
)}
|
||||
</div>
|
||||
|
||||
<div className="CallLinkPendingParticipantModal__Hr" />
|
||||
|
||||
<button
|
||||
type="button"
|
||||
className="CallLinkPendingParticipantModal__ActionButton"
|
||||
onClick={handleApprove}
|
||||
>
|
||||
<div className="CallLinkPendingParticipantModal__ButtonIcon">
|
||||
<div className="CallLinkPendingParticipantModal__ButtonIconContent CallLinkPendingParticipantModal__ButtonIconContent--approve" />
|
||||
</div>
|
||||
{i18n('icu:CallLinkPendingParticipantModal__ApproveButtonLabel')}
|
||||
</button>
|
||||
|
||||
<button
|
||||
type="button"
|
||||
className="CallLinkPendingParticipantModal__ActionButton"
|
||||
onClick={handleDeny}
|
||||
>
|
||||
<div className="CallLinkPendingParticipantModal__ButtonIcon">
|
||||
<div className="CallLinkPendingParticipantModal__ButtonIconContent CallLinkPendingParticipantModal__ButtonIconContent--deny" />
|
||||
</div>
|
||||
{i18n('icu:CallLinkPendingParticipantModal__DenyButtonLabel')}
|
||||
</button>
|
||||
</Modal>
|
||||
);
|
||||
}
|
|
@ -139,6 +139,9 @@ const createProps = (storyProps: Partial<PropsType> = {}): PropsType => ({
|
|||
stopRingtone: action('stop-ringtone'),
|
||||
switchToPresentationView: action('switch-to-presentation-view'),
|
||||
switchFromPresentationView: action('switch-from-presentation-view'),
|
||||
toggleCallLinkPendingParticipantModal: action(
|
||||
'toggle-call-link-pending-participant-modal'
|
||||
),
|
||||
toggleParticipants: action('toggle-participants'),
|
||||
togglePip: action('toggle-pip'),
|
||||
toggleScreenRecordingPermissionsDialog: action(
|
||||
|
|
|
@ -139,6 +139,7 @@ export type PropsType = {
|
|||
switchFromPresentationView: () => void;
|
||||
hangUpActiveCall: (reason: string) => void;
|
||||
togglePip: () => void;
|
||||
toggleCallLinkPendingParticipantModal: (contactId: string) => void;
|
||||
toggleScreenRecordingPermissionsDialog: () => unknown;
|
||||
toggleSettings: () => void;
|
||||
isConversationTooBigToRing: boolean;
|
||||
|
@ -199,6 +200,7 @@ function ActiveCallManager({
|
|||
startCall,
|
||||
switchToPresentationView,
|
||||
switchFromPresentationView,
|
||||
toggleCallLinkPendingParticipantModal,
|
||||
toggleParticipants,
|
||||
togglePip,
|
||||
toggleScreenRecordingPermissionsDialog,
|
||||
|
@ -475,6 +477,9 @@ function ActiveCallManager({
|
|||
stickyControls={showParticipantsList}
|
||||
switchToPresentationView={switchToPresentationView}
|
||||
switchFromPresentationView={switchFromPresentationView}
|
||||
toggleCallLinkPendingParticipantModal={
|
||||
toggleCallLinkPendingParticipantModal
|
||||
}
|
||||
toggleScreenRecordingPermissionsDialog={
|
||||
toggleScreenRecordingPermissionsDialog
|
||||
}
|
||||
|
@ -571,6 +576,7 @@ export function CallManager({
|
|||
switchToPresentationView,
|
||||
toggleParticipants,
|
||||
togglePip,
|
||||
toggleCallLinkPendingParticipantModal,
|
||||
toggleScreenRecordingPermissionsDialog,
|
||||
toggleSettings,
|
||||
}: PropsType): JSX.Element | null {
|
||||
|
@ -661,6 +667,9 @@ export function CallManager({
|
|||
startCall={startCall}
|
||||
switchFromPresentationView={switchFromPresentationView}
|
||||
switchToPresentationView={switchToPresentationView}
|
||||
toggleCallLinkPendingParticipantModal={
|
||||
toggleCallLinkPendingParticipantModal
|
||||
}
|
||||
toggleParticipants={toggleParticipants}
|
||||
togglePip={togglePip}
|
||||
toggleScreenRecordingPermissionsDialog={
|
||||
|
|
|
@ -217,6 +217,9 @@ const createProps = (
|
|||
stickyControls: false,
|
||||
switchToPresentationView: action('switch-to-presentation-view'),
|
||||
switchFromPresentationView: action('switch-from-presentation-view'),
|
||||
toggleCallLinkPendingParticipantModal: action(
|
||||
'toggle-call-link-pending-participant-modal'
|
||||
),
|
||||
toggleParticipants: action('toggle-participants'),
|
||||
togglePip: action('toggle-pip'),
|
||||
toggleScreenRecordingPermissionsDialog: action(
|
||||
|
|
|
@ -125,6 +125,7 @@ export type PropsType = {
|
|||
stickyControls: boolean;
|
||||
switchToPresentationView: () => void;
|
||||
switchFromPresentationView: () => void;
|
||||
toggleCallLinkPendingParticipantModal: (contactId: string) => void;
|
||||
toggleParticipants: () => void;
|
||||
togglePip: () => void;
|
||||
toggleScreenRecordingPermissionsDialog: () => unknown;
|
||||
|
@ -214,6 +215,7 @@ export function CallScreen({
|
|||
stickyControls,
|
||||
switchToPresentationView,
|
||||
switchFromPresentationView,
|
||||
toggleCallLinkPendingParticipantModal,
|
||||
toggleParticipants,
|
||||
togglePip,
|
||||
toggleScreenRecordingPermissionsDialog,
|
||||
|
@ -864,6 +866,9 @@ export function CallScreen({
|
|||
approveUser={approveUser}
|
||||
batchUserAction={batchUserAction}
|
||||
denyUser={denyUser}
|
||||
toggleCallLinkPendingParticipantModal={
|
||||
toggleCallLinkPendingParticipantModal
|
||||
}
|
||||
/>
|
||||
) : null}
|
||||
{/* We render the local preview first and set the footer flex direction to row-reverse
|
||||
|
|
|
@ -18,6 +18,9 @@ const createProps = (storyProps: Partial<PropsType> = {}): PropsType => ({
|
|||
approveUser: action('approve-user'),
|
||||
batchUserAction: action('batch-user-action'),
|
||||
denyUser: action('deny-user'),
|
||||
toggleCallLinkPendingParticipantModal: action(
|
||||
'toggle-call-link-pending-participant-modal'
|
||||
),
|
||||
...storyProps,
|
||||
});
|
||||
|
||||
|
|
|
@ -35,6 +35,9 @@ export type PropsType = {
|
|||
readonly approveUser: (payload: PendingUserActionPayloadType) => void;
|
||||
readonly batchUserAction: (payload: BatchUserActionPayloadType) => void;
|
||||
readonly denyUser: (payload: PendingUserActionPayloadType) => void;
|
||||
readonly toggleCallLinkPendingParticipantModal: (
|
||||
conversationId: string
|
||||
) => void;
|
||||
};
|
||||
|
||||
export function CallingPendingParticipants({
|
||||
|
@ -44,6 +47,7 @@ export function CallingPendingParticipants({
|
|||
approveUser,
|
||||
batchUserAction,
|
||||
denyUser,
|
||||
toggleCallLinkPendingParticipantModal,
|
||||
}: PropsType): JSX.Element | null {
|
||||
const [isExpanded, setIsExpanded] = useState(defaultIsExpanded ?? false);
|
||||
const [confirmDialogState, setConfirmDialogState] =
|
||||
|
@ -241,7 +245,15 @@ export function CallingPendingParticipants({
|
|||
className="module-calling-participants-list__contact"
|
||||
key={index}
|
||||
>
|
||||
<div className="module-calling-participants-list__avatar-and-name">
|
||||
<button
|
||||
type="button"
|
||||
onClick={ev => {
|
||||
ev.preventDefault();
|
||||
ev.stopPropagation();
|
||||
toggleCallLinkPendingParticipantModal(participant.id);
|
||||
}}
|
||||
className="module-calling-participants-list__avatar-and-name CallingPendingParticipants__ParticipantButton"
|
||||
>
|
||||
<Avatar
|
||||
acceptedMessageRequest={participant.acceptedMessageRequest}
|
||||
avatarUrl={participant.avatarUrl}
|
||||
|
@ -268,7 +280,7 @@ export function CallingPendingParticipants({
|
|||
/>
|
||||
</span>
|
||||
) : null}
|
||||
</div>
|
||||
</button>
|
||||
{renderApprovalButtons(participant)}
|
||||
</li>
|
||||
))}
|
||||
|
@ -303,7 +315,15 @@ export function CallingPendingParticipants({
|
|||
return (
|
||||
<div className="CallingPendingParticipants CallingPendingParticipants--Compact module-calling-participants-list">
|
||||
<div className="CallingPendingParticipants__CompactParticipant">
|
||||
<div className="module-calling-participants-list__avatar-and-name">
|
||||
<button
|
||||
type="button"
|
||||
onClick={ev => {
|
||||
ev.preventDefault();
|
||||
ev.stopPropagation();
|
||||
toggleCallLinkPendingParticipantModal(participant.id);
|
||||
}}
|
||||
className="module-calling-participants-list__avatar-and-name CallingPendingParticipants__ParticipantButton"
|
||||
>
|
||||
<Avatar
|
||||
acceptedMessageRequest={participant.acceptedMessageRequest}
|
||||
avatarUrl={participant.avatarUrl}
|
||||
|
@ -326,12 +346,13 @@ export function CallingPendingParticipants({
|
|||
i18n={i18n}
|
||||
/>
|
||||
) : null}
|
||||
<span className="CallingPendingParticipants__ParticipantAboutIcon" />
|
||||
</div>
|
||||
<div className="CallingPendingParticipants__WouldLikeToJoin">
|
||||
{i18n('icu:CallingPendingParticipants__WouldLikeToJoin')}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</button>
|
||||
{renderApprovalButtons(participant)}
|
||||
</div>
|
||||
{participants.length > 1 && (
|
||||
|
|
|
@ -36,6 +36,9 @@ export type PropsType = {
|
|||
// CallLinkEditModal
|
||||
callLinkEditModalRoomId: string | null;
|
||||
renderCallLinkEditModal: () => JSX.Element;
|
||||
// CallLinkPendingParticipantModal
|
||||
callLinkPendingParticipantContactId: string | undefined;
|
||||
renderCallLinkPendingParticipantModal: () => JSX.Element;
|
||||
// ConfirmLeaveCallModal
|
||||
confirmLeaveCallModalState: StartCallData | null;
|
||||
renderConfirmLeaveCallModal: () => JSX.Element;
|
||||
|
@ -118,6 +121,9 @@ export function GlobalModalContainer({
|
|||
// CallLinkEditModal
|
||||
callLinkEditModalRoomId,
|
||||
renderCallLinkEditModal,
|
||||
// CallLinkPendingParticipantModal
|
||||
callLinkPendingParticipantContactId,
|
||||
renderCallLinkPendingParticipantModal,
|
||||
// ConfirmLeaveCallModal
|
||||
confirmLeaveCallModalState,
|
||||
renderConfirmLeaveCallModal,
|
||||
|
@ -268,6 +274,12 @@ export function GlobalModalContainer({
|
|||
return renderContactModal();
|
||||
}
|
||||
|
||||
// This needs to be after the about contact modal because the pending participant modal
|
||||
// opens the about contact modal
|
||||
if (callLinkPendingParticipantContactId) {
|
||||
return renderCallLinkPendingParticipantModal();
|
||||
}
|
||||
|
||||
if (isStoriesSettingsVisible) {
|
||||
return renderStoriesSettings();
|
||||
}
|
||||
|
|
|
@ -38,6 +38,12 @@ const conversationWithAbout = getDefaultConversation({
|
|||
aboutText: '😀 About Me',
|
||||
hasMessages: true,
|
||||
});
|
||||
const conversationWithSharedGroups = getDefaultConversation({
|
||||
acceptedMessageRequest: true,
|
||||
aboutText: 'likes to chat',
|
||||
hasMessages: true,
|
||||
sharedGroupNames: ['Axolotl lovers'],
|
||||
});
|
||||
const systemContact = getDefaultConversation({
|
||||
acceptedMessageRequest: true,
|
||||
systemGivenName: 'Alice',
|
||||
|
@ -110,3 +116,13 @@ export function SystemContact(args: PropsType): JSX.Element {
|
|||
/>
|
||||
);
|
||||
}
|
||||
|
||||
export function WithSharedGroups(args: PropsType): JSX.Element {
|
||||
return (
|
||||
<AboutContactModal
|
||||
{...args}
|
||||
conversation={conversationWithSharedGroups}
|
||||
isSignalConnection
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -94,6 +94,7 @@ export type GlobalModalsStateType = ReadonlyDeep<{
|
|||
aboutContactModalContactId?: string;
|
||||
callLinkAddNameModalRoomId: string | null;
|
||||
callLinkEditModalRoomId: string | null;
|
||||
callLinkPendingParticipantContactId: string | undefined;
|
||||
confirmLeaveCallModalState: StartCallData | null;
|
||||
contactModalState?: ContactModalStateType;
|
||||
deleteMessagesProps?: DeleteMessagesPropsType;
|
||||
|
@ -149,6 +150,8 @@ const TOGGLE_ADD_USER_TO_ANOTHER_GROUP_MODAL =
|
|||
const TOGGLE_CALL_LINK_ADD_NAME_MODAL =
|
||||
'globalModals/TOGGLE_CALL_LINK_ADD_NAME_MODAL';
|
||||
const TOGGLE_CALL_LINK_EDIT_MODAL = 'globalModals/TOGGLE_CALL_LINK_EDIT_MODAL';
|
||||
const TOGGLE_CALL_LINK_PENDING_PARTICIPANT_MODAL =
|
||||
'globalModals/TOGGLE_CALL_LINK_PENDING_PARTICIPANT_MODAL';
|
||||
const TOGGLE_ABOUT_MODAL = 'globalModals/TOGGLE_ABOUT_MODAL';
|
||||
const TOGGLE_SIGNAL_CONNECTIONS_MODAL =
|
||||
'globalModals/TOGGLE_SIGNAL_CONNECTIONS_MODAL';
|
||||
|
@ -266,6 +269,11 @@ type ToggleCallLinkEditModalActionType = ReadonlyDeep<{
|
|||
payload: string | null;
|
||||
}>;
|
||||
|
||||
type ToggleCallLinkPendingParticipantModalActionType = ReadonlyDeep<{
|
||||
type: typeof TOGGLE_CALL_LINK_PENDING_PARTICIPANT_MODAL;
|
||||
payload: string | undefined;
|
||||
}>;
|
||||
|
||||
type ToggleAboutContactModalActionType = ReadonlyDeep<{
|
||||
type: typeof TOGGLE_ABOUT_MODAL;
|
||||
payload: string | undefined;
|
||||
|
@ -393,6 +401,7 @@ export type GlobalModalsActionType = ReadonlyDeep<
|
|||
| ToggleAddUserToAnotherGroupModalActionType
|
||||
| ToggleCallLinkAddNameModalActionType
|
||||
| ToggleCallLinkEditModalActionType
|
||||
| ToggleCallLinkPendingParticipantModalActionType
|
||||
| ToggleConfirmationModalActionType
|
||||
| ToggleConfirmLeaveCallModalActionType
|
||||
| ToggleDeleteMessagesModalActionType
|
||||
|
@ -435,6 +444,7 @@ export const actions = {
|
|||
toggleAddUserToAnotherGroupModal,
|
||||
toggleCallLinkAddNameModal,
|
||||
toggleCallLinkEditModal,
|
||||
toggleCallLinkPendingParticipantModal,
|
||||
toggleConfirmationModal,
|
||||
toggleConfirmLeaveCallModal,
|
||||
toggleDeleteMessagesModal,
|
||||
|
@ -757,6 +767,15 @@ function toggleCallLinkEditModal(
|
|||
};
|
||||
}
|
||||
|
||||
function toggleCallLinkPendingParticipantModal(
|
||||
contactId?: string
|
||||
): ToggleCallLinkPendingParticipantModalActionType {
|
||||
return {
|
||||
type: TOGGLE_CALL_LINK_PENDING_PARTICIPANT_MODAL,
|
||||
payload: contactId,
|
||||
};
|
||||
}
|
||||
|
||||
function toggleAboutContactModal(
|
||||
contactId?: string
|
||||
): ToggleAboutContactModalActionType {
|
||||
|
@ -974,6 +993,7 @@ export function getEmptyState(): GlobalModalsStateType {
|
|||
hasConfirmationModal: false,
|
||||
callLinkAddNameModalRoomId: null,
|
||||
callLinkEditModalRoomId: null,
|
||||
callLinkPendingParticipantContactId: undefined,
|
||||
confirmLeaveCallModalState: null,
|
||||
editNicknameAndNoteModalProps: null,
|
||||
isProfileEditorVisible: false,
|
||||
|
@ -1109,6 +1129,13 @@ export function reducer(
|
|||
};
|
||||
}
|
||||
|
||||
if (action.type === TOGGLE_CALL_LINK_PENDING_PARTICIPANT_MODAL) {
|
||||
return {
|
||||
...state,
|
||||
callLinkPendingParticipantContactId: action.payload,
|
||||
};
|
||||
}
|
||||
|
||||
if (action.type === TOGGLE_DELETE_MESSAGES_MODAL) {
|
||||
return {
|
||||
...state,
|
||||
|
|
|
@ -32,6 +32,12 @@ export const getCallLinkAddNameModalRoomId = createSelector(
|
|||
({ callLinkAddNameModalRoomId }) => callLinkAddNameModalRoomId
|
||||
);
|
||||
|
||||
export const getCallLinkPendingParticipantContactId = createSelector(
|
||||
getGlobalModalsState,
|
||||
({ callLinkPendingParticipantContactId }) =>
|
||||
callLinkPendingParticipantContactId
|
||||
);
|
||||
|
||||
export const getConfirmLeaveCallModalState = createSelector(
|
||||
getGlobalModalsState,
|
||||
({ confirmLeaveCallModalState }) => confirmLeaveCallModalState
|
||||
|
|
41
ts/state/smart/CallLinkPendingParticipantModal.tsx
Normal file
41
ts/state/smart/CallLinkPendingParticipantModal.tsx
Normal file
|
@ -0,0 +1,41 @@
|
|||
// Copyright 2024 Signal Messenger, LLC
|
||||
// SPDX-License-Identifier: AGPL-3.0-only
|
||||
import React, { memo } from 'react';
|
||||
import { useSelector } from 'react-redux';
|
||||
import { CallLinkPendingParticipantModal } from '../../components/CallLinkPendingParticipantModal';
|
||||
import { useCallingActions } from '../ducks/calling';
|
||||
import { getIntl } from '../selectors/user';
|
||||
import { useConversationsActions } from '../ducks/conversations';
|
||||
import { useGlobalModalActions } from '../ducks/globalModals';
|
||||
import { getConversationSelector } from '../selectors/conversations';
|
||||
import { getCallLinkPendingParticipantContactId } from '../selectors/globalModals';
|
||||
import { strictAssert } from '../../util/assert';
|
||||
|
||||
export const SmartCallLinkPendingParticipantModal = memo(
|
||||
function SmartCallLinkPendingParticipantModal(): JSX.Element | null {
|
||||
const contactId = useSelector(getCallLinkPendingParticipantContactId);
|
||||
strictAssert(contactId, 'Expected contactId to be set');
|
||||
|
||||
const i18n = useSelector(getIntl);
|
||||
const getConversation = useSelector(getConversationSelector);
|
||||
|
||||
const { updateSharedGroups } = useConversationsActions();
|
||||
const { approveUser, denyUser } = useCallingActions();
|
||||
const { toggleAboutContactModal, toggleCallLinkPendingParticipantModal } =
|
||||
useGlobalModalActions();
|
||||
|
||||
const conversation = getConversation(contactId);
|
||||
|
||||
return (
|
||||
<CallLinkPendingParticipantModal
|
||||
i18n={i18n}
|
||||
conversation={conversation}
|
||||
approveUser={approveUser}
|
||||
denyUser={denyUser}
|
||||
onClose={toggleCallLinkPendingParticipantModal}
|
||||
updateSharedGroups={updateSharedGroups}
|
||||
toggleAboutContactModal={toggleAboutContactModal}
|
||||
/>
|
||||
);
|
||||
}
|
||||
);
|
|
@ -458,8 +458,11 @@ export const SmartCallManager = memo(function SmartCallManager() {
|
|||
toggleSettings,
|
||||
} = useCallingActions();
|
||||
const { pauseVoiceNotePlayer } = useAudioPlayerActions();
|
||||
const { showContactModal, showShareCallLinkViaSignal } =
|
||||
useGlobalModalActions();
|
||||
const {
|
||||
showContactModal,
|
||||
showShareCallLinkViaSignal,
|
||||
toggleCallLinkPendingParticipantModal,
|
||||
} = useGlobalModalActions();
|
||||
|
||||
return (
|
||||
<CallManager
|
||||
|
@ -513,6 +516,9 @@ export const SmartCallManager = memo(function SmartCallManager() {
|
|||
stopRingtone={stopRingtone}
|
||||
switchFromPresentationView={switchFromPresentationView}
|
||||
switchToPresentationView={switchToPresentationView}
|
||||
toggleCallLinkPendingParticipantModal={
|
||||
toggleCallLinkPendingParticipantModal
|
||||
}
|
||||
toggleParticipants={toggleParticipants}
|
||||
togglePip={togglePip}
|
||||
toggleScreenRecordingPermissionsDialog={
|
||||
|
|
|
@ -29,6 +29,7 @@ import { SmartNotePreviewModal } from './NotePreviewModal';
|
|||
import { SmartCallLinkEditModal } from './CallLinkEditModal';
|
||||
import { SmartCallLinkAddNameModal } from './CallLinkAddNameModal';
|
||||
import { SmartConfirmLeaveCallModal } from './ConfirmLeaveCallModal';
|
||||
import { SmartCallLinkPendingParticipantModal } from './CallLinkPendingParticipantModal';
|
||||
|
||||
function renderCallLinkAddNameModal(): JSX.Element {
|
||||
return <SmartCallLinkAddNameModal />;
|
||||
|
@ -38,6 +39,10 @@ function renderCallLinkEditModal(): JSX.Element {
|
|||
return <SmartCallLinkEditModal />;
|
||||
}
|
||||
|
||||
function renderCallLinkPendingParticipantModal(): JSX.Element {
|
||||
return <SmartCallLinkPendingParticipantModal />;
|
||||
}
|
||||
|
||||
function renderConfirmLeaveCallModal(): JSX.Element {
|
||||
return <SmartConfirmLeaveCallModal />;
|
||||
}
|
||||
|
@ -107,6 +112,7 @@ export const SmartGlobalModalContainer = memo(
|
|||
addUserToAnotherGroupModalContactId,
|
||||
callLinkAddNameModalRoomId,
|
||||
callLinkEditModalRoomId,
|
||||
callLinkPendingParticipantContactId,
|
||||
confirmLeaveCallModalState,
|
||||
contactModalState,
|
||||
deleteMessagesProps,
|
||||
|
@ -188,6 +194,9 @@ export const SmartGlobalModalContainer = memo(
|
|||
}
|
||||
callLinkAddNameModalRoomId={callLinkAddNameModalRoomId}
|
||||
callLinkEditModalRoomId={callLinkEditModalRoomId}
|
||||
callLinkPendingParticipantContactId={
|
||||
callLinkPendingParticipantContactId
|
||||
}
|
||||
confirmLeaveCallModalState={confirmLeaveCallModalState}
|
||||
contactModalState={contactModalState}
|
||||
editHistoryMessages={editHistoryMessages}
|
||||
|
@ -213,6 +222,9 @@ export const SmartGlobalModalContainer = memo(
|
|||
renderAddUserToAnotherGroup={renderAddUserToAnotherGroup}
|
||||
renderCallLinkAddNameModal={renderCallLinkAddNameModal}
|
||||
renderCallLinkEditModal={renderCallLinkEditModal}
|
||||
renderCallLinkPendingParticipantModal={
|
||||
renderCallLinkPendingParticipantModal
|
||||
}
|
||||
renderConfirmLeaveCallModal={renderConfirmLeaveCallModal}
|
||||
renderContactModal={renderContactModal}
|
||||
renderEditHistoryMessagesModal={renderEditHistoryMessagesModal}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue