Update call link edit/add name modals
This commit is contained in:
parent
ba77ef7563
commit
b691e24d5c
20 changed files with 526 additions and 232 deletions
|
@ -7208,14 +7208,14 @@
|
|||
"messageformat": "Call link details",
|
||||
"description": "Call Link Edit Modal > Title"
|
||||
},
|
||||
"icu:CallLinkEditModal__InputLabel--Name--SrOnly": {
|
||||
"messageformat": "Name",
|
||||
"description": "Call Link Edit Modal > Name Input > Label (for screenreaders)"
|
||||
},
|
||||
"icu:CallLinkEditModal__JoinButtonLabel": {
|
||||
"messageformat": "Join",
|
||||
"description": "Call Link Edit Modal > Join Button > Label"
|
||||
},
|
||||
"icu:CallLinkEditModal__AddCallNameLabel": {
|
||||
"messageformat": "Add call name",
|
||||
"description": "Call Link Edit Modal > Add Call Name Button > Label"
|
||||
},
|
||||
"icu:CallLinkEditModal__InputLabel--ApproveAllMembers": {
|
||||
"messageformat": "Approve all members",
|
||||
"description": "Call Link Edit Modal > Approve All Members Checkbox > Label"
|
||||
|
@ -7228,6 +7228,14 @@
|
|||
"messageformat": "On",
|
||||
"description": "Call Link Edit Modal > Approve All Members Checkbox > Option > On"
|
||||
},
|
||||
"icu:CallLinkAddNameModal__Title": {
|
||||
"messageformat": "Add call name",
|
||||
"description": "Call Link Add Name Modal > Title"
|
||||
},
|
||||
"icu:CallLinkAddNameModal__NameLabel": {
|
||||
"messageformat": "Call name",
|
||||
"description": "Call Link Add Name Modal > Name Input > Label"
|
||||
},
|
||||
"icu:TypingBubble__avatar--overflow-count": {
|
||||
"messageformat": "{count, plural, one {# other is} other {# others are}} typing.",
|
||||
"description": "Group chat multiple person typing indicator when space isn't available to show every avatar, this is the count of avatars hidden."
|
||||
|
|
16
stylesheets/components/CallLinkAddNameModal.scss
Normal file
16
stylesheets/components/CallLinkAddNameModal.scss
Normal file
|
@ -0,0 +1,16 @@
|
|||
// Copyright 2024 Signal Messenger, LLC
|
||||
// SPDX-License-Identifier: AGPL-3.0-only
|
||||
|
||||
.CallLinkAddNameModal__Row {
|
||||
display: flex;
|
||||
gap: 12px;
|
||||
}
|
||||
|
||||
.CallLinkAddNameModal__SrOnly {
|
||||
@include sr-only;
|
||||
}
|
||||
|
||||
// Overriding the default styles for the input container
|
||||
.CallLinkAddNameModal__Input__container.Input__container {
|
||||
flex: 1;
|
||||
}
|
|
@ -1,6 +1,12 @@
|
|||
// Copyright 2024 Signal Messenger, LLC
|
||||
// SPDX-License-Identifier: AGPL-3.0-only
|
||||
|
||||
// Overriding default style
|
||||
.module-Modal__body.CallLinkEditModal__body {
|
||||
padding-inline: 12px 3px;
|
||||
scrollbar-gutter: stable;
|
||||
}
|
||||
|
||||
.CallLinkEditModal__SrOnly {
|
||||
@include sr-only;
|
||||
}
|
||||
|
@ -13,67 +19,80 @@
|
|||
}
|
||||
|
||||
.CallLinkEditModal__Header__Details {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 8px;
|
||||
gap: 0;
|
||||
min-width: 0; // fix overflow issue
|
||||
}
|
||||
|
||||
// Overriding default style
|
||||
.Input__container.CallLinkEditModal__Input--Name__container {
|
||||
margin: 0;
|
||||
.CallLinkEditModal__Header__Title {
|
||||
@include font-body-1-bold;
|
||||
}
|
||||
|
||||
.CallLinkEditModal__CallLinkAndJoinButton {
|
||||
.CallLinkEditModal__Header__CallLinkButton {
|
||||
@include button-reset;
|
||||
@include font-subtitle;
|
||||
|
||||
@include light-theme {
|
||||
color: $color-gray-60;
|
||||
}
|
||||
@include dark-theme {
|
||||
color: $color-gray-25;
|
||||
}
|
||||
}
|
||||
|
||||
.CallLinkEditModal__Header__CallLinkButton__Text {
|
||||
overflow: hidden;
|
||||
display: -webkit-box;
|
||||
-webkit-box-orient: vertical;
|
||||
-webkit-line-clamp: 2;
|
||||
}
|
||||
|
||||
.CallLinkEditModal__Header__Actions {
|
||||
display: flex;
|
||||
gap: 14px;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.CallLinkEditModal__CopyUrlTextButton {
|
||||
@include button-reset;
|
||||
border: none;
|
||||
padding-block: 10px;
|
||||
padding-inline: 8px;
|
||||
border-radius: 6px;
|
||||
flex: 1;
|
||||
|
||||
// truncate with ellipsis
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
|
||||
@include light-theme {
|
||||
background: $color-gray-02;
|
||||
color: $color-black;
|
||||
}
|
||||
@include dark-theme {
|
||||
background: $color-gray-75;
|
||||
color: $color-gray-15;
|
||||
}
|
||||
}
|
||||
|
||||
.CallLinkEditModal__JoinButton {
|
||||
@include font-body-1-bold;
|
||||
}
|
||||
|
||||
.CallLinkEditModal__ApproveAllMembers__Row {
|
||||
.CallLinkEditModal__Row {
|
||||
display: flex;
|
||||
padding: 12px;
|
||||
align-items: center;
|
||||
margin-bottom: 18px;
|
||||
gap: 16px;
|
||||
}
|
||||
|
||||
.CallLinkEditModal__ApproveAllMembers__Label {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.CallLinkEditModal__ActionButton {
|
||||
.CallLinkEditModal__RowButton {
|
||||
@include button-reset;
|
||||
width: 100%;
|
||||
padding-block: 1px;
|
||||
|
||||
.CallLinkEditModal__Row {
|
||||
border-radius: 8px;
|
||||
}
|
||||
|
||||
&:hover,
|
||||
&:focus {
|
||||
.CallLinkEditModal__Row {
|
||||
@include light-theme {
|
||||
background: $color-gray-02;
|
||||
}
|
||||
@include dark-theme {
|
||||
background: $color-gray-75;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.CallLinkEditModal__Row--Button {
|
||||
@include font-body-2;
|
||||
display: flex;
|
||||
gap: 8px;
|
||||
align-items: center;
|
||||
padding-block: 8px;
|
||||
width: 100%;
|
||||
|
||||
@include light-theme {
|
||||
|
@ -84,20 +103,17 @@
|
|||
}
|
||||
}
|
||||
|
||||
.CallLinkEditModal__ActionButton__Icon {
|
||||
.CallLinkEditModal__RowLabel {
|
||||
@include font-body-1;
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.CallLinkEditModal__RowIcon {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 36px;
|
||||
height: 36px;
|
||||
border-radius: 9999px;
|
||||
|
||||
@include light-theme {
|
||||
background: $color-gray-05;
|
||||
}
|
||||
@include dark-theme {
|
||||
background: $color-gray-65;
|
||||
}
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
|
||||
&::after {
|
||||
content: '';
|
||||
|
@ -110,30 +126,42 @@
|
|||
}
|
||||
}
|
||||
|
||||
.CallLinkEditModal__ActionButton__Icon--Copy {
|
||||
@mixin CallLinkEditModal__RowIcon($iconPath) {
|
||||
&::after {
|
||||
@include light-theme {
|
||||
@include color-svg('../images/icons/v3/copy/copy.svg', $color-gray-75);
|
||||
@include color-svg($iconPath, $color-gray-75);
|
||||
}
|
||||
@include dark-theme {
|
||||
@include color-svg('../images/icons/v3/copy/copy.svg', $color-gray-15);
|
||||
@include color-svg($iconPath, $color-gray-15);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.CallLinkEditModal__ActionButton__Icon--Share {
|
||||
&::after {
|
||||
@include light-theme {
|
||||
@include color-svg(
|
||||
'../images/icons/v3/forward/forward.svg',
|
||||
$color-gray-75
|
||||
);
|
||||
}
|
||||
@include dark-theme {
|
||||
@include color-svg(
|
||||
'../images/icons/v3/forward/forward.svg',
|
||||
$color-gray-15
|
||||
);
|
||||
}
|
||||
}
|
||||
.CallLinkEditModal__RowIcon--Edit {
|
||||
@include CallLinkEditModal__RowIcon('../images/icons/v3/edit/edit.svg');
|
||||
}
|
||||
|
||||
.CallLinkEditModal__RowIcon--Approve {
|
||||
@include CallLinkEditModal__RowIcon(
|
||||
'../images/icons/v3/person/person-check-compact.svg'
|
||||
);
|
||||
}
|
||||
|
||||
.CallLinkEditModal__RowIcon--Copy {
|
||||
@include CallLinkEditModal__RowIcon('../images/icons/v3/copy/copy.svg');
|
||||
}
|
||||
|
||||
.CallLinkEditModal__RowIcon--Share {
|
||||
@include CallLinkEditModal__RowIcon('../images/icons/v3/forward/forward.svg');
|
||||
}
|
||||
|
||||
.CallLinkEditModal__Hr {
|
||||
border: none;
|
||||
height: 1px;
|
||||
background: $color-black-alpha-12;
|
||||
}
|
||||
|
||||
// Overriding default style
|
||||
.CallLinkEditModal__RowSelect.module-select select {
|
||||
min-width: 0;
|
||||
}
|
||||
|
|
|
@ -50,6 +50,7 @@
|
|||
@import './components/CallingScreenSharingController.scss';
|
||||
@import './components/CallingSelectPresentingSourcesModal.scss';
|
||||
@import './components/CallingToast.scss';
|
||||
@import './components/CallLinkAddNameModal.scss';
|
||||
@import './components/CallLinkDetails.scss';
|
||||
@import './components/CallLinkEditModal.scss';
|
||||
@import './components/CallingRaisedHandsList.scss';
|
||||
|
|
28
ts/components/CallLinkAddNameModal.stories.tsx
Normal file
28
ts/components/CallLinkAddNameModal.stories.tsx
Normal file
|
@ -0,0 +1,28 @@
|
|||
// 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 { CallLinkAddNameModalProps } from './CallLinkAddNameModal';
|
||||
import { CallLinkAddNameModal } from './CallLinkAddNameModal';
|
||||
import type { ComponentMeta } from '../storybook/types';
|
||||
import { FAKE_CALL_LINK_WITH_ADMIN_KEY } from '../test-both/helpers/fakeCallLink';
|
||||
|
||||
const i18n = setupI18n('en', enMessages);
|
||||
|
||||
export default {
|
||||
title: 'Components/CallLinkAddNameModal',
|
||||
component: CallLinkAddNameModal,
|
||||
args: {
|
||||
i18n,
|
||||
callLink: FAKE_CALL_LINK_WITH_ADMIN_KEY,
|
||||
onClose: action('onClose'),
|
||||
onUpdateCallLinkName: action('onUpdateCallLinkName'),
|
||||
},
|
||||
} satisfies ComponentMeta<CallLinkAddNameModalProps>;
|
||||
|
||||
export function Basic(args: CallLinkAddNameModalProps): JSX.Element {
|
||||
return <CallLinkAddNameModal {...args} />;
|
||||
}
|
98
ts/components/CallLinkAddNameModal.tsx
Normal file
98
ts/components/CallLinkAddNameModal.tsx
Normal file
|
@ -0,0 +1,98 @@
|
|||
// Copyright 2024 Signal Messenger, LLC
|
||||
// SPDX-License-Identifier: AGPL-3.0-only
|
||||
import React, { useCallback, useState } from 'react';
|
||||
import { v4 as generateUuid } from 'uuid';
|
||||
import { Modal } from './Modal';
|
||||
import type { LocalizerType } from '../types/I18N';
|
||||
import { Button, ButtonVariant } from './Button';
|
||||
import { Avatar, AvatarSize } from './Avatar';
|
||||
import { Input } from './Input';
|
||||
import type { CallLinkType } from '../types/CallLink';
|
||||
|
||||
export type CallLinkAddNameModalProps = Readonly<{
|
||||
i18n: LocalizerType;
|
||||
callLink: CallLinkType;
|
||||
onClose: () => void;
|
||||
onUpdateCallLinkName: (name: string) => void;
|
||||
}>;
|
||||
|
||||
export function CallLinkAddNameModal({
|
||||
i18n,
|
||||
callLink,
|
||||
onClose,
|
||||
onUpdateCallLinkName,
|
||||
}: CallLinkAddNameModalProps): JSX.Element {
|
||||
const [formId] = useState(() => generateUuid());
|
||||
const [nameId] = useState(() => generateUuid());
|
||||
const [nameInput, setNameInput] = useState(callLink.name);
|
||||
|
||||
const handleNameInputChange = useCallback((nextNameInput: string) => {
|
||||
setNameInput(nextNameInput);
|
||||
}, []);
|
||||
|
||||
const handleSubmit = useCallback(() => {
|
||||
const nameValue = nameInput.trim();
|
||||
if (nameValue === callLink.name) {
|
||||
return;
|
||||
}
|
||||
onUpdateCallLinkName(nameValue);
|
||||
onClose();
|
||||
}, [nameInput, callLink, onUpdateCallLinkName, onClose]);
|
||||
|
||||
return (
|
||||
<Modal
|
||||
modalName="CallLinkAddNameModal"
|
||||
i18n={i18n}
|
||||
hasXButton
|
||||
noEscapeClose
|
||||
noMouseClose
|
||||
title={i18n('icu:CallLinkAddNameModal__Title')}
|
||||
onClose={onClose}
|
||||
moduleClassName="CallLinkAddNameModal"
|
||||
modalFooter={
|
||||
<>
|
||||
<Button onClick={onClose} variant={ButtonVariant.Secondary}>
|
||||
{i18n('icu:cancel')}
|
||||
</Button>
|
||||
<Button type="submit" form={formId} variant={ButtonVariant.Primary}>
|
||||
{i18n('icu:save')}
|
||||
</Button>
|
||||
</>
|
||||
}
|
||||
>
|
||||
<form
|
||||
id={formId}
|
||||
onSubmit={handleSubmit}
|
||||
className="CallLinkAddNameModal__Row"
|
||||
>
|
||||
<Avatar
|
||||
i18n={i18n}
|
||||
badge={undefined}
|
||||
conversationType="callLink"
|
||||
size={AvatarSize.SIXTY_FOUR}
|
||||
acceptedMessageRequest
|
||||
isMe={false}
|
||||
sharedGroupNames={[]}
|
||||
title={
|
||||
callLink.name === ''
|
||||
? i18n('icu:calling__call-link-default-title')
|
||||
: callLink.name
|
||||
}
|
||||
/>
|
||||
|
||||
<label htmlFor={nameId} className="CallLinkAddNameModal__SrOnly">
|
||||
{i18n('icu:CallLinkAddNameModal__NameLabel')}
|
||||
</label>
|
||||
<Input
|
||||
i18n={i18n}
|
||||
id={nameId}
|
||||
value={nameInput}
|
||||
placeholder={i18n('icu:CallLinkAddNameModal__NameLabel')}
|
||||
autoFocus
|
||||
onChange={handleNameInputChange}
|
||||
moduleClassName="CallLinkAddNameModal__Input"
|
||||
/>
|
||||
</form>
|
||||
</Modal>
|
||||
);
|
||||
}
|
|
@ -20,7 +20,7 @@ export default {
|
|||
callLink: FAKE_CALL_LINK_WITH_ADMIN_KEY,
|
||||
onClose: action('onClose'),
|
||||
onCopyCallLink: action('onCopyCallLink'),
|
||||
onUpdateCallLinkName: action('onUpdateCallLinkName'),
|
||||
onOpenCallLinkAddNameModal: action('onOpenCallLinkAddNameModal'),
|
||||
onUpdateCallLinkRestrictions: action('onUpdateCallLinkRestrictions'),
|
||||
onShareCallLinkViaSignal: action('onShareCallLinkViaSignal'),
|
||||
onStartCallLinkLobby: action('onStartCallLinkLobby'),
|
||||
|
|
|
@ -1,7 +1,8 @@
|
|||
// Copyright 2024 Signal Messenger, LLC
|
||||
// SPDX-License-Identifier: AGPL-3.0-only
|
||||
|
||||
import React, { useCallback, useMemo, useState } from 'react';
|
||||
import type { ReactNode } from 'react';
|
||||
import React, { useMemo, useState } from 'react';
|
||||
import { v4 as generateUuid } from 'uuid';
|
||||
import { Modal } from './Modal';
|
||||
import type { LocalizerType } from '../types/I18N';
|
||||
|
@ -10,19 +11,67 @@ import {
|
|||
toCallLinkRestrictions,
|
||||
type CallLinkType,
|
||||
} from '../types/CallLink';
|
||||
import { Input } from './Input';
|
||||
import { Select } from './Select';
|
||||
import { linkCallRoute } from '../util/signalRoutes';
|
||||
import { Button, ButtonSize, ButtonVariant } from './Button';
|
||||
import { Avatar, AvatarSize } from './Avatar';
|
||||
import { formatUrlWithoutProtocol } from '../util/url';
|
||||
|
||||
const CallLinkEditModalRowIconClasses = {
|
||||
Edit: 'CallLinkEditModal__RowIcon--Edit',
|
||||
Approve: 'CallLinkEditModal__RowIcon--Approve',
|
||||
Copy: 'CallLinkEditModal__RowIcon--Copy',
|
||||
Share: 'CallLinkEditModal__RowIcon--Share',
|
||||
} as const;
|
||||
|
||||
function RowIcon({
|
||||
icon,
|
||||
}: {
|
||||
icon: keyof typeof CallLinkEditModalRowIconClasses;
|
||||
}) {
|
||||
return (
|
||||
<i
|
||||
role="presentation"
|
||||
className={`CallLinkEditModal__RowIcon ${CallLinkEditModalRowIconClasses[icon]}`}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
function RowText({ children }: { children: ReactNode }) {
|
||||
return <div className="CallLinkEditModal__RowLabel">{children}</div>;
|
||||
}
|
||||
|
||||
function Row({ children }: { children: ReactNode }) {
|
||||
return <div className="CallLinkEditModal__Row">{children}</div>;
|
||||
}
|
||||
|
||||
function RowButton({
|
||||
onClick,
|
||||
children,
|
||||
}: {
|
||||
onClick: () => void;
|
||||
children: ReactNode;
|
||||
}) {
|
||||
return (
|
||||
<button
|
||||
className="CallLinkEditModal__RowButton"
|
||||
type="button"
|
||||
onClick={onClick}
|
||||
>
|
||||
{children}
|
||||
</button>
|
||||
);
|
||||
}
|
||||
|
||||
function Hr() {
|
||||
return <hr className="CallLinkEditModal__Hr" />;
|
||||
}
|
||||
|
||||
export type CallLinkEditModalProps = {
|
||||
i18n: LocalizerType;
|
||||
callLink: CallLinkType;
|
||||
onClose: () => void;
|
||||
onCopyCallLink: () => void;
|
||||
onUpdateCallLinkName: (name: string) => void;
|
||||
onOpenCallLinkAddNameModal: () => void;
|
||||
onUpdateCallLinkRestrictions: (restrictions: CallLinkRestrictions) => void;
|
||||
onShareCallLinkViaSignal: () => void;
|
||||
onStartCallLinkLobby: () => void;
|
||||
|
@ -33,64 +82,32 @@ export function CallLinkEditModal({
|
|||
callLink,
|
||||
onClose,
|
||||
onCopyCallLink,
|
||||
onUpdateCallLinkName,
|
||||
onOpenCallLinkAddNameModal,
|
||||
onUpdateCallLinkRestrictions,
|
||||
onShareCallLinkViaSignal,
|
||||
onStartCallLinkLobby,
|
||||
}: CallLinkEditModalProps): JSX.Element {
|
||||
const { name: savedName, restrictions: savedRestrictions } = callLink;
|
||||
|
||||
const [nameId] = useState(() => generateUuid());
|
||||
const [restrictionsId] = useState(() => generateUuid());
|
||||
|
||||
const [nameInput, setNameInput] = useState(savedName);
|
||||
const [restrictionsInput, setRestrictionsInput] = useState(savedRestrictions);
|
||||
|
||||
// We only want to use the default name "Signal Call" as a value if the user
|
||||
// modified the input and then chose that name. Doesn't revert when saved.
|
||||
const [nameTouched, setNameTouched] = useState(false);
|
||||
|
||||
const callLinkWebUrl = useMemo(() => {
|
||||
return formatUrlWithoutProtocol(
|
||||
linkCallRoute.toWebUrl({ key: callLink.rootKey })
|
||||
);
|
||||
return linkCallRoute.toWebUrl({ key: callLink.rootKey }).toString();
|
||||
}, [callLink.rootKey]);
|
||||
|
||||
const onSaveName = useCallback(
|
||||
(newName: string) => {
|
||||
if (!nameTouched) {
|
||||
return;
|
||||
}
|
||||
if (newName === savedName) {
|
||||
return;
|
||||
}
|
||||
onUpdateCallLinkName(newName);
|
||||
},
|
||||
[nameTouched, savedName, onUpdateCallLinkName]
|
||||
);
|
||||
|
||||
const onSaveRestrictions = useCallback(
|
||||
(newRestrictions: CallLinkRestrictions) => {
|
||||
if (newRestrictions === savedRestrictions) {
|
||||
return;
|
||||
}
|
||||
onUpdateCallLinkRestrictions(newRestrictions);
|
||||
},
|
||||
[savedRestrictions, onUpdateCallLinkRestrictions]
|
||||
);
|
||||
|
||||
return (
|
||||
<Modal
|
||||
i18n={i18n}
|
||||
modalName="CallLinkEditModal"
|
||||
moduleClassName="CallLinkEditModal"
|
||||
title={i18n('icu:CallLinkEditModal__Title')}
|
||||
hasXButton
|
||||
onClose={() => {
|
||||
// Save the modal in case the user hits escape
|
||||
onSaveName(nameInput);
|
||||
onClose();
|
||||
}}
|
||||
noEscapeClose
|
||||
noMouseClose
|
||||
padded={false}
|
||||
modalFooter={
|
||||
<Button type="submit" variant={ButtonVariant.Primary} onClick={onClose}>
|
||||
{i18n('icu:done')}
|
||||
</Button>
|
||||
}
|
||||
onClose={onClose}
|
||||
>
|
||||
<div className="CallLinkEditModal__Header">
|
||||
<Avatar
|
||||
|
@ -101,43 +118,30 @@ export function CallLinkEditModal({
|
|||
acceptedMessageRequest
|
||||
isMe={false}
|
||||
sharedGroupNames={[]}
|
||||
title={callLink.name ?? i18n('icu:calling__call-link-default-title')}
|
||||
title={
|
||||
callLink.name === ''
|
||||
? i18n('icu:calling__call-link-default-title')
|
||||
: callLink.name
|
||||
}
|
||||
/>
|
||||
<div className="CallLinkEditModal__Header__Details">
|
||||
<label htmlFor={nameId} className="CallLinkEditModal__SrOnly">
|
||||
{i18n('icu:CallLinkEditModal__InputLabel--Name--SrOnly')}
|
||||
</label>
|
||||
<Input
|
||||
moduleClassName="CallLinkEditModal__Input--Name"
|
||||
i18n={i18n}
|
||||
value={
|
||||
nameInput === '' && !nameTouched
|
||||
<div className="CallLinkEditModal__Header__Title">
|
||||
{callLink.name === ''
|
||||
? i18n('icu:calling__call-link-default-title')
|
||||
: nameInput
|
||||
}
|
||||
maxByteCount={120}
|
||||
onChange={value => {
|
||||
setNameTouched(true);
|
||||
setNameInput(value);
|
||||
}}
|
||||
onBlur={() => {
|
||||
onSaveName(nameInput);
|
||||
}}
|
||||
onEnter={() => {
|
||||
onSaveName(nameInput);
|
||||
}}
|
||||
placeholder={i18n('icu:calling__call-link-default-title')}
|
||||
/>
|
||||
|
||||
<div className="CallLinkEditModal__CallLinkAndJoinButton">
|
||||
: callLink.name}
|
||||
</div>
|
||||
<button
|
||||
className="CallLinkEditModal__CopyUrlTextButton"
|
||||
className="CallLinkEditModal__Header__CallLinkButton"
|
||||
type="button"
|
||||
onClick={onCopyCallLink}
|
||||
aria-label={i18n('icu:CallLinkDetails__CopyLink')}
|
||||
>
|
||||
<div className="CallLinkEditModal__Header__CallLinkButton__Text">
|
||||
{callLinkWebUrl}
|
||||
</div>
|
||||
</button>
|
||||
</div>
|
||||
<div className="CallLinkEditModal__Header__Actions">
|
||||
<Button
|
||||
onClick={onStartCallLinkLobby}
|
||||
size={ButtonSize.Small}
|
||||
|
@ -148,67 +152,62 @@ export function CallLinkEditModal({
|
|||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div
|
||||
className="CallLinkEditModal__ApproveAllMembers__Row"
|
||||
// For testing, to easily check the restrictions saved
|
||||
data-restrictions={savedRestrictions}
|
||||
>
|
||||
<label
|
||||
htmlFor={restrictionsId}
|
||||
className="CallLinkEditModal__ApproveAllMembers__Label"
|
||||
>
|
||||
<Hr />
|
||||
|
||||
<RowButton onClick={onOpenCallLinkAddNameModal}>
|
||||
<Row>
|
||||
<RowIcon icon="Edit" />
|
||||
<RowText>{i18n('icu:CallLinkEditModal__AddCallNameLabel')}</RowText>
|
||||
</Row>
|
||||
</RowButton>
|
||||
|
||||
<Row>
|
||||
<RowIcon icon="Approve" />
|
||||
<RowText>
|
||||
<label htmlFor={restrictionsId}>
|
||||
{i18n('icu:CallLinkEditModal__InputLabel--ApproveAllMembers')}
|
||||
</label>
|
||||
</RowText>
|
||||
<Select
|
||||
id={restrictionsId}
|
||||
value={restrictionsInput}
|
||||
value={String(callLink.restrictions)}
|
||||
moduleClassName="CallLinkEditModal__RowSelect"
|
||||
options={[
|
||||
{
|
||||
value: CallLinkRestrictions.None,
|
||||
value: String(CallLinkRestrictions.None),
|
||||
text: i18n(
|
||||
'icu:CallLinkEditModal__ApproveAllMembers__Option--Off'
|
||||
),
|
||||
},
|
||||
{
|
||||
value: CallLinkRestrictions.AdminApproval,
|
||||
value: String(CallLinkRestrictions.AdminApproval),
|
||||
text: i18n(
|
||||
'icu:CallLinkEditModal__ApproveAllMembers__Option--On'
|
||||
),
|
||||
},
|
||||
]}
|
||||
onChange={value => {
|
||||
const newRestrictions = toCallLinkRestrictions(value);
|
||||
setRestrictionsInput(newRestrictions);
|
||||
onSaveRestrictions(newRestrictions);
|
||||
onUpdateCallLinkRestrictions(toCallLinkRestrictions(value));
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
</Row>
|
||||
|
||||
<button
|
||||
type="button"
|
||||
className="CallLinkEditModal__ActionButton"
|
||||
onClick={onCopyCallLink}
|
||||
>
|
||||
<i
|
||||
role="presentation"
|
||||
className="CallLinkEditModal__ActionButton__Icon CallLinkEditModal__ActionButton__Icon--Copy"
|
||||
/>
|
||||
{i18n('icu:CallLinkDetails__CopyLink')}
|
||||
</button>
|
||||
<Hr />
|
||||
|
||||
<button
|
||||
type="button"
|
||||
className="CallLinkEditModal__ActionButton"
|
||||
onClick={onShareCallLinkViaSignal}
|
||||
>
|
||||
<i
|
||||
role="presentation"
|
||||
className="CallLinkEditModal__ActionButton__Icon CallLinkEditModal__ActionButton__Icon--Share"
|
||||
/>
|
||||
{i18n('icu:CallLinkDetails__ShareLinkViaSignal')}
|
||||
</button>
|
||||
<RowButton onClick={onCopyCallLink}>
|
||||
<Row>
|
||||
<RowIcon icon="Copy" />
|
||||
<RowText>{i18n('icu:CallLinkDetails__CopyLink')}</RowText>
|
||||
</Row>
|
||||
</RowButton>
|
||||
|
||||
<RowButton onClick={onShareCallLinkViaSignal}>
|
||||
<Row>
|
||||
<RowIcon icon="Share" />
|
||||
<RowText>{i18n('icu:CallLinkDetails__ShareLinkViaSignal')}</RowText>
|
||||
</Row>
|
||||
</RowButton>
|
||||
</Modal>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -76,7 +76,7 @@ export function EditNicknameAndNoteModal({
|
|||
}, [givenName, familyName, note]);
|
||||
|
||||
const handleSubmit = useCallback(
|
||||
(event: MouseEvent | FormEvent) => {
|
||||
(event: FormEvent) => {
|
||||
event.preventDefault();
|
||||
if (formResult.success) {
|
||||
onSave(formResult.data);
|
||||
|
@ -104,7 +104,6 @@ export function EditNicknameAndNoteModal({
|
|||
type="submit"
|
||||
form={formId}
|
||||
aria-disabled={!formResult.success}
|
||||
onClick={handleSubmit}
|
||||
>
|
||||
{i18n('icu:save')}
|
||||
</Button>
|
||||
|
@ -124,7 +123,7 @@ export function EditNicknameAndNoteModal({
|
|||
theme={undefined}
|
||||
/>
|
||||
</div>
|
||||
<form onSubmit={handleSubmit}>
|
||||
<form id={formId} onSubmit={handleSubmit}>
|
||||
<label
|
||||
htmlFor={givenNameId}
|
||||
className="EditNicknameAndNoteModal__Label"
|
||||
|
|
|
@ -29,6 +29,9 @@ export type PropsType = {
|
|||
// AddUserToAnotherGroupModal
|
||||
addUserToAnotherGroupModalContactId: string | undefined;
|
||||
renderAddUserToAnotherGroup: () => JSX.Element;
|
||||
// CallLinkAddNameModal
|
||||
callLinkAddNameModalRoomId: string | null;
|
||||
renderCallLinkAddNameModal: () => JSX.Element;
|
||||
// CallLinkEditModal
|
||||
callLinkEditModalRoomId: string | null;
|
||||
renderCallLinkEditModal: () => JSX.Element;
|
||||
|
@ -105,6 +108,9 @@ export function GlobalModalContainer({
|
|||
// AddUserToAnotherGroupModal
|
||||
addUserToAnotherGroupModalContactId,
|
||||
renderAddUserToAnotherGroup,
|
||||
// CallLinkAddNameModal
|
||||
callLinkAddNameModalRoomId,
|
||||
renderCallLinkAddNameModal,
|
||||
// CallLinkEditModal
|
||||
callLinkEditModalRoomId,
|
||||
renderCallLinkEditModal,
|
||||
|
@ -194,6 +200,10 @@ export function GlobalModalContainer({
|
|||
return renderAddUserToAnotherGroup();
|
||||
}
|
||||
|
||||
if (callLinkAddNameModalRoomId) {
|
||||
return renderCallLinkAddNameModal();
|
||||
}
|
||||
|
||||
if (callLinkEditModalRoomId) {
|
||||
return renderCallLinkEditModal();
|
||||
}
|
||||
|
|
|
@ -18,6 +18,7 @@ import { useRefMerger } from '../hooks/useRefMerger';
|
|||
import { byteLength } from '../Bytes';
|
||||
|
||||
export type PropsType = {
|
||||
autoFocus?: boolean;
|
||||
countBytes?: (value: string) => number;
|
||||
countLength?: (value: string) => number;
|
||||
disabled?: boolean;
|
||||
|
@ -63,6 +64,7 @@ export const Input = forwardRef<
|
|||
PropsType
|
||||
>(function InputInner(
|
||||
{
|
||||
autoFocus,
|
||||
countBytes = byteLength,
|
||||
countLength = grapheme.count,
|
||||
disabled,
|
||||
|
@ -206,6 +208,7 @@ export const Input = forwardRef<
|
|||
const isTextarea = expandable || forceTextarea;
|
||||
|
||||
const inputProps = {
|
||||
autoFocus,
|
||||
className: classNames(
|
||||
getClassName('__input'),
|
||||
icon && getClassName('__input--with-icon'),
|
||||
|
|
|
@ -43,6 +43,7 @@ type PropsType = {
|
|||
|
||||
export type ModalPropsType = PropsType & {
|
||||
noTransform?: boolean;
|
||||
noEscapeClose?: boolean;
|
||||
noMouseClose?: boolean;
|
||||
theme?: Theme;
|
||||
};
|
||||
|
@ -57,6 +58,7 @@ export function Modal({
|
|||
modalFooter,
|
||||
modalHeaderChildren,
|
||||
moduleClassName,
|
||||
noEscapeClose,
|
||||
noMouseClose,
|
||||
onBackButtonClick,
|
||||
onClose = noop,
|
||||
|
@ -114,6 +116,7 @@ export function Modal({
|
|||
<ModalHost
|
||||
modalName={modalName}
|
||||
moduleClassName={moduleClassName}
|
||||
noEscapeClose={noEscapeClose}
|
||||
noMouseClose={noMouseClose}
|
||||
onClose={close}
|
||||
onEscape={onBackButtonClick}
|
||||
|
|
|
@ -27,6 +27,7 @@ export type PropsType = Readonly<{
|
|||
children: React.ReactElement;
|
||||
modalName: string;
|
||||
moduleClassName?: string;
|
||||
noEscapeClose?: boolean;
|
||||
noMouseClose?: boolean;
|
||||
onClose: () => unknown;
|
||||
onEscape?: () => unknown;
|
||||
|
@ -40,6 +41,7 @@ export const ModalHost = React.memo(function ModalHostInner({
|
|||
children,
|
||||
modalName,
|
||||
moduleClassName,
|
||||
noEscapeClose,
|
||||
noMouseClose,
|
||||
onClose,
|
||||
onEscape,
|
||||
|
@ -72,7 +74,7 @@ export const ModalHost = React.memo(function ModalHostInner({
|
|||
};
|
||||
}, [modalContainer]);
|
||||
|
||||
useEscapeHandling(onEscape || onClose);
|
||||
useEscapeHandling(noEscapeClose ? noop : onEscape || onClose);
|
||||
useEffect(() => {
|
||||
if (noMouseClose) {
|
||||
return noop;
|
||||
|
|
|
@ -91,6 +91,7 @@ type MigrateToGV2PropsType = ReadonlyDeep<{
|
|||
export type GlobalModalsStateType = ReadonlyDeep<{
|
||||
addUserToAnotherGroupModalContactId?: string;
|
||||
aboutContactModalContactId?: string;
|
||||
callLinkAddNameModalRoomId: string | null;
|
||||
callLinkEditModalRoomId: string | null;
|
||||
contactModalState?: ContactModalStateType;
|
||||
deleteMessagesProps?: DeleteMessagesPropsType;
|
||||
|
@ -143,6 +144,8 @@ export const TOGGLE_PROFILE_EDITOR_ERROR =
|
|||
const TOGGLE_SAFETY_NUMBER_MODAL = 'globalModals/TOGGLE_SAFETY_NUMBER_MODAL';
|
||||
const TOGGLE_ADD_USER_TO_ANOTHER_GROUP_MODAL =
|
||||
'globalModals/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_ABOUT_MODAL = 'globalModals/TOGGLE_ABOUT_MODAL';
|
||||
const TOGGLE_SIGNAL_CONNECTIONS_MODAL =
|
||||
|
@ -244,6 +247,11 @@ type ToggleAddUserToAnotherGroupModalActionType = ReadonlyDeep<{
|
|||
payload: string | undefined;
|
||||
}>;
|
||||
|
||||
type ToggleCallLinkAddNameModalActionType = ReadonlyDeep<{
|
||||
type: typeof TOGGLE_CALL_LINK_ADD_NAME_MODAL;
|
||||
payload: string | null;
|
||||
}>;
|
||||
|
||||
type ToggleCallLinkEditModalActionType = ReadonlyDeep<{
|
||||
type: typeof TOGGLE_CALL_LINK_EDIT_MODAL;
|
||||
payload: string | null;
|
||||
|
@ -374,6 +382,7 @@ export type GlobalModalsActionType = ReadonlyDeep<
|
|||
| StartMigrationToGV2ActionType
|
||||
| ToggleAboutContactModalActionType
|
||||
| ToggleAddUserToAnotherGroupModalActionType
|
||||
| ToggleCallLinkAddNameModalActionType
|
||||
| ToggleCallLinkEditModalActionType
|
||||
| ToggleConfirmationModalActionType
|
||||
| ToggleDeleteMessagesModalActionType
|
||||
|
@ -414,6 +423,7 @@ export const actions = {
|
|||
showWhatsNewModal,
|
||||
toggleAboutContactModal,
|
||||
toggleAddUserToAnotherGroupModal,
|
||||
toggleCallLinkAddNameModal,
|
||||
toggleCallLinkEditModal,
|
||||
toggleConfirmationModal,
|
||||
toggleDeleteMessagesModal,
|
||||
|
@ -711,6 +721,15 @@ function toggleAddUserToAnotherGroupModal(
|
|||
};
|
||||
}
|
||||
|
||||
function toggleCallLinkAddNameModal(
|
||||
roomId: string | null
|
||||
): ToggleCallLinkAddNameModalActionType {
|
||||
return {
|
||||
type: TOGGLE_CALL_LINK_ADD_NAME_MODAL,
|
||||
payload: roomId,
|
||||
};
|
||||
}
|
||||
|
||||
function toggleCallLinkEditModal(
|
||||
roomId: string | null
|
||||
): ToggleCallLinkEditModalActionType {
|
||||
|
@ -935,6 +954,7 @@ function copyOverMessageAttributesIntoForwardMessages(
|
|||
export function getEmptyState(): GlobalModalsStateType {
|
||||
return {
|
||||
hasConfirmationModal: false,
|
||||
callLinkAddNameModalRoomId: null,
|
||||
callLinkEditModalRoomId: null,
|
||||
editNicknameAndNoteModalProps: null,
|
||||
isProfileEditorVisible: false,
|
||||
|
@ -1049,6 +1069,13 @@ export function reducer(
|
|||
};
|
||||
}
|
||||
|
||||
if (action.type === TOGGLE_CALL_LINK_ADD_NAME_MODAL) {
|
||||
return {
|
||||
...state,
|
||||
callLinkAddNameModalRoomId: action.payload,
|
||||
};
|
||||
}
|
||||
|
||||
if (action.type === TOGGLE_CALL_LINK_EDIT_MODAL) {
|
||||
return {
|
||||
...state,
|
||||
|
|
|
@ -27,6 +27,11 @@ export const getCallLinkEditModalRoomId = createSelector(
|
|||
({ callLinkEditModalRoomId }) => callLinkEditModalRoomId
|
||||
);
|
||||
|
||||
export const getCallLinkAddNameModalRoomId = createSelector(
|
||||
getGlobalModalsState,
|
||||
({ callLinkAddNameModalRoomId }) => callLinkAddNameModalRoomId
|
||||
);
|
||||
|
||||
export const getContactModalState = createSelector(
|
||||
getGlobalModalsState,
|
||||
({ contactModalState }) => contactModalState
|
||||
|
|
60
ts/state/smart/CallLinkAddNameModal.tsx
Normal file
60
ts/state/smart/CallLinkAddNameModal.tsx
Normal file
|
@ -0,0 +1,60 @@
|
|||
// Copyright 2024 Signal Messenger, LLC
|
||||
// SPDX-License-Identifier: AGPL-3.0-only
|
||||
import React, { memo, useCallback, useMemo } from 'react';
|
||||
import { useSelector } from 'react-redux';
|
||||
import { useCallingActions } from '../ducks/calling';
|
||||
import { getCallLinkSelector } from '../selectors/calling';
|
||||
import * as log from '../../logging/log';
|
||||
import { getIntl } from '../selectors/user';
|
||||
import { useGlobalModalActions } from '../ducks/globalModals';
|
||||
import { getCallLinkAddNameModalRoomId } from '../selectors/globalModals';
|
||||
import { strictAssert } from '../../util/assert';
|
||||
import { isCallLinksCreateEnabled } from '../../util/callLinks';
|
||||
import { CallLinkAddNameModal } from '../../components/CallLinkAddNameModal';
|
||||
|
||||
export const SmartCallLinkAddNameModal = memo(
|
||||
function SmartCallLinkAddNameModal(): JSX.Element | null {
|
||||
strictAssert(isCallLinksCreateEnabled(), 'Call links creation is disabled');
|
||||
|
||||
const roomId = useSelector(getCallLinkAddNameModalRoomId);
|
||||
strictAssert(roomId, 'Expected roomId to be set');
|
||||
|
||||
const i18n = useSelector(getIntl);
|
||||
const callLinkSelector = useSelector(getCallLinkSelector);
|
||||
|
||||
const { updateCallLinkName } = useCallingActions();
|
||||
const { toggleCallLinkAddNameModal } = useGlobalModalActions();
|
||||
|
||||
const callLink = useMemo(() => {
|
||||
return callLinkSelector(roomId);
|
||||
}, [callLinkSelector, roomId]);
|
||||
|
||||
const handleClose = useCallback(() => {
|
||||
toggleCallLinkAddNameModal(null);
|
||||
}, [toggleCallLinkAddNameModal]);
|
||||
|
||||
const handleUpdateCallLinkName = useCallback(
|
||||
(newName: string) => {
|
||||
updateCallLinkName(roomId, newName);
|
||||
},
|
||||
[roomId, updateCallLinkName]
|
||||
);
|
||||
|
||||
if (!callLink) {
|
||||
log.error(
|
||||
'SmartCallLinkEditModal: No call link found for roomId',
|
||||
roomId
|
||||
);
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<CallLinkAddNameModal
|
||||
i18n={i18n}
|
||||
callLink={callLink}
|
||||
onClose={handleClose}
|
||||
onUpdateCallLinkName={handleUpdateCallLinkName}
|
||||
/>
|
||||
);
|
||||
}
|
||||
);
|
|
@ -26,13 +26,13 @@ export const SmartCallLinkEditModal = memo(
|
|||
const i18n = useSelector(getIntl);
|
||||
const callLinkSelector = useSelector(getCallLinkSelector);
|
||||
|
||||
const { updateCallLinkRestrictions, startCallLinkLobby } =
|
||||
useCallingActions();
|
||||
const {
|
||||
updateCallLinkName,
|
||||
updateCallLinkRestrictions,
|
||||
startCallLinkLobby,
|
||||
} = useCallingActions();
|
||||
const { toggleCallLinkEditModal, showShareCallLinkViaSignal } =
|
||||
useGlobalModalActions();
|
||||
toggleCallLinkAddNameModal,
|
||||
toggleCallLinkEditModal,
|
||||
showShareCallLinkViaSignal,
|
||||
} = useGlobalModalActions();
|
||||
|
||||
const callLink = useMemo(() => {
|
||||
return callLinkSelector(roomId);
|
||||
|
@ -52,12 +52,9 @@ export const SmartCallLinkEditModal = memo(
|
|||
drop(copyCallLink(callLinkWebUrl));
|
||||
}, [callLink]);
|
||||
|
||||
const handleUpdateCallLinkName = useCallback(
|
||||
(newName: string) => {
|
||||
updateCallLinkName(roomId, newName);
|
||||
},
|
||||
[roomId, updateCallLinkName]
|
||||
);
|
||||
const handleOpenCallLinkAddNameModal = useCallback(() => {
|
||||
toggleCallLinkAddNameModal(roomId);
|
||||
}, [roomId, toggleCallLinkAddNameModal]);
|
||||
|
||||
const handleUpdateCallLinkRestrictions = useCallback(
|
||||
(newRestrictions: CallLinkRestrictions) => {
|
||||
|
@ -91,7 +88,7 @@ export const SmartCallLinkEditModal = memo(
|
|||
callLink={callLink}
|
||||
onClose={handleClose}
|
||||
onCopyCallLink={handleCopyCallLink}
|
||||
onUpdateCallLinkName={handleUpdateCallLinkName}
|
||||
onOpenCallLinkAddNameModal={handleOpenCallLinkAddNameModal}
|
||||
onUpdateCallLinkRestrictions={handleUpdateCallLinkRestrictions}
|
||||
onShareCallLinkViaSignal={handleShareCallLinkViaSignal}
|
||||
onStartCallLinkLobby={handleStartCallLinkLobby}
|
||||
|
|
|
@ -27,6 +27,11 @@ import { getGlobalModalsState } from '../selectors/globalModals';
|
|||
import { SmartEditNicknameAndNoteModal } from './EditNicknameAndNoteModal';
|
||||
import { SmartNotePreviewModal } from './NotePreviewModal';
|
||||
import { SmartCallLinkEditModal } from './CallLinkEditModal';
|
||||
import { SmartCallLinkAddNameModal } from './CallLinkAddNameModal';
|
||||
|
||||
function renderCallLinkAddNameModal(): JSX.Element {
|
||||
return <SmartCallLinkAddNameModal />;
|
||||
}
|
||||
|
||||
function renderCallLinkEditModal(): JSX.Element {
|
||||
return <SmartCallLinkEditModal />;
|
||||
|
@ -95,6 +100,7 @@ export const SmartGlobalModalContainer = memo(
|
|||
const {
|
||||
aboutContactModalContactId,
|
||||
addUserToAnotherGroupModalContactId,
|
||||
callLinkAddNameModalRoomId,
|
||||
callLinkEditModalRoomId,
|
||||
contactModalState,
|
||||
deleteMessagesProps,
|
||||
|
@ -174,6 +180,7 @@ export const SmartGlobalModalContainer = memo(
|
|||
addUserToAnotherGroupModalContactId={
|
||||
addUserToAnotherGroupModalContactId
|
||||
}
|
||||
callLinkAddNameModalRoomId={callLinkAddNameModalRoomId}
|
||||
callLinkEditModalRoomId={callLinkEditModalRoomId}
|
||||
contactModalState={contactModalState}
|
||||
editHistoryMessages={editHistoryMessages}
|
||||
|
@ -197,6 +204,7 @@ export const SmartGlobalModalContainer = memo(
|
|||
isWhatsNewVisible={isWhatsNewVisible}
|
||||
renderAboutContactModal={renderAboutContactModal}
|
||||
renderAddUserToAnotherGroup={renderAddUserToAnotherGroup}
|
||||
renderCallLinkAddNameModal={renderCallLinkAddNameModal}
|
||||
renderCallLinkEditModal={renderCallLinkEditModal}
|
||||
renderContactModal={renderContactModal}
|
||||
renderEditHistoryMessagesModal={renderEditHistoryMessagesModal}
|
||||
|
|
|
@ -42,23 +42,29 @@ describe('calling/callLinkAdmin', function (this: Mocha.Suite) {
|
|||
.getByText('Create a Call Link')
|
||||
.click();
|
||||
|
||||
const callLinkItem = window.locator('.CallsList__Item[data-type="Adhoc"]');
|
||||
const editModal = window.locator('.CallLinkEditModal');
|
||||
await editModal.waitFor();
|
||||
|
||||
const modal = window.locator('.CallLinkEditModal');
|
||||
await modal.waitFor();
|
||||
const restrictionsInput = editModal.getByLabel('Approve all members');
|
||||
|
||||
const row = modal.locator('.CallLinkEditModal__ApproveAllMembers__Row');
|
||||
await expect(restrictionsInput).toHaveJSProperty('value', '0');
|
||||
await restrictionsInput.selectOption({ label: 'On' });
|
||||
await expect(restrictionsInput).toHaveJSProperty('value', '1');
|
||||
|
||||
await expect(row).toHaveAttribute('data-restrictions', '0');
|
||||
await editModal.locator('button', { hasText: 'Add call name' }).click();
|
||||
|
||||
const select = modal.locator('select');
|
||||
await select.selectOption({ label: 'On' });
|
||||
await expect(row).toHaveAttribute('data-restrictions', '1');
|
||||
const addNameModal = window.locator('.CallLinkAddNameModal');
|
||||
await addNameModal.waitFor();
|
||||
|
||||
const nameInput = modal.locator('.CallLinkEditModal__Input--Name__input');
|
||||
const nameInput = addNameModal.getByLabel('Call name');
|
||||
await nameInput.fill('New Name');
|
||||
await nameInput.blur();
|
||||
|
||||
await expect(callLinkItem).toContainText('New Name');
|
||||
const saveBtn = addNameModal.getByText('Save');
|
||||
await saveBtn.click();
|
||||
|
||||
await editModal.waitFor();
|
||||
|
||||
const title = editModal.locator('.CallLinkEditModal__Header__Title');
|
||||
await expect(title).toContainText('New Name');
|
||||
});
|
||||
});
|
||||
|
|
|
@ -37,7 +37,3 @@ export function urlPathFromComponents(
|
|||
): string {
|
||||
return `/${components.filter(Boolean).map(encodeURIComponent).join('/')}`;
|
||||
}
|
||||
|
||||
export function formatUrlWithoutProtocol(url: Readonly<URL>): string {
|
||||
return `${url.hostname}${url.pathname}${url.search}${url.hash}`;
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue