diff --git a/_locales/en/messages.json b/_locales/en/messages.json index 50f4ef57d12a..03eae924f2fa 100644 --- a/_locales/en/messages.json +++ b/_locales/en/messages.json @@ -7357,6 +7357,10 @@ "messageformat": "Approve all members", "description": "Call History > Call Link Details > Approve All Members > Label" }, + "icu:CallLinkDetails__SettingTooltip--disabled-for-active-call": { + "messageformat": "This setting can't be changed while the call is active", + "description": "Call History > Call Link Details > Approve All Members > Tooltip when disabled due to active call" + }, "icu:CallLinkDetails__CopyLink": { "messageformat": "Copy link", "description": "Call History > Call Link Details > Copy Link Button" @@ -7385,6 +7389,10 @@ "messageformat": "Delete", "description": "Call History > Call Link Details > Delete Link Modal > Delete Button" }, + "icu:CallLinkDetails__DeleteLinkTooltip--disabled-for-active-call": { + "messageformat": "This link can't be deleted while the call is active", + "description": "Call History > Call Link Details > Delete Link Button > Tooltip when disabled due to active call" + }, "icu:CallLinkEditModal__Title": { "messageformat": "Call link details", "description": "Call Link Edit Modal > Title" diff --git a/stylesheets/_mixins.scss b/stylesheets/_mixins.scss index e1f6e7630a87..f53de25bc17a 100644 --- a/stylesheets/_mixins.scss +++ b/stylesheets/_mixins.scss @@ -974,3 +974,50 @@ $rtl-icon-map: ( } } } + +@mixin button-active-call { + $background: $color-accent-green; + + @include font-body-2-bold; + @include rounded-corners; + + display: flex; + width: auto; + align-items: center; + background-color: $background; + color: $color-white; + outline: none; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + user-select: none; + + &:before { + $icon-size: 16px; + + @include color-svg( + '../images/icons/v3/video/video-compact-fill.svg', + $color-white + ); + content: ''; + display: block; + height: $icon-size; + margin-inline-end: 4px; + min-width: $icon-size; + width: $icon-size; + } + + &:not(:disabled) { + &:hover { + @include any-theme { + background-color: darken($background, 16%); + } + } + + &:focus { + @include keyboard-mode { + background-color: darken($background, 16%); + } + } + } +} diff --git a/stylesheets/components/CallLinkDetails.scss b/stylesheets/components/CallLinkDetails.scss index d6ee4855b024..ff5e7f879cfd 100644 --- a/stylesheets/components/CallLinkDetails.scss +++ b/stylesheets/components/CallLinkDetails.scss @@ -46,6 +46,10 @@ font-weight: 600; } +.CallLinkDetails__HeaderButton--active-call { + @include button-active-call; +} + .CallLinkDetails__DeleteLink { // Override the default icon color .ConversationDetails-icon__icon--trash::after { @@ -59,3 +63,19 @@ color: $color-accent-red; } } + +.CallLinkDetails__DeleteLink--disabled-for-active-call { + .ConversationDetails-icon__icon--trash::after { + @include any-theme { + background-color: $color-gray-45; + } + } + .ConversationDetails-panel-row__label { + color: $color-gray-45; + } +} + +.CallLinkDetails__ApproveAllMembersDisabledTooltip, +.CallLinkDetails__DeleteLinkTooltip { + @include tooltip; +} diff --git a/stylesheets/components/CallsTab.scss b/stylesheets/components/CallsTab.scss index 06fcee9ab412..921591403f28 100644 --- a/stylesheets/components/CallsTab.scss +++ b/stylesheets/components/CallsTab.scss @@ -356,53 +356,10 @@ } .CallsNewCall__ItemActionButton--join-call { - $background: $color-accent-green; - - @include font-body-2-bold; - @include rounded-corners; - - display: flex; - width: auto; + @include button-active-call; height: 26px; padding-block: 4px; padding-inline: 10px; - align-items: center; - background-color: $background; - color: $color-white; - outline: none; - overflow: hidden; - text-overflow: ellipsis; - white-space: nowrap; - user-select: none; - - &:before { - $icon-size: 16px; - - @include color-svg( - '../images/icons/v3/video/video-compact-fill.svg', - $color-white - ); - content: ''; - display: block; - height: $icon-size; - margin-inline-end: 4px; - min-width: $icon-size; - width: $icon-size; - } - - &:not(:disabled) { - &:hover { - @include any-theme { - background-color: darken($background, 16%); - } - } - - &:focus { - @include keyboard-mode { - background-color: darken($background, 16%); - } - } - } } .CallsNewCall__ItemActionButton--join-call-disabled { diff --git a/ts/components/CallLinkDetails.stories.tsx b/ts/components/CallLinkDetails.stories.tsx index 0662457c2bbd..38797634ca13 100644 --- a/ts/components/CallLinkDetails.stories.tsx +++ b/ts/components/CallLinkDetails.stories.tsx @@ -23,7 +23,9 @@ export default { i18n, callHistoryGroup: getFakeCallLinkHistoryGroup(), callLink: FAKE_CALL_LINK_WITH_ADMIN_KEY, - hasActiveCall: false, + isAnybodyInCall: false, + isInCall: false, + isInAnotherCall: false, onDeleteCallLink: action('onDeleteCallLink'), onOpenCallLinkAddNameModal: action('onOpenCallLinkAddNameModal'), onStartCallLinkLobby: action('onStartCallLinkLobby'), @@ -36,10 +38,39 @@ export function Admin(args: CallLinkDetailsProps): JSX.Element { return ; } +export function AdminAndCallActive(args: CallLinkDetailsProps): JSX.Element { + return ; +} + +export function AdminAndInCall(args: CallLinkDetailsProps): JSX.Element { + return ; +} + export function NonAdmin(args: CallLinkDetailsProps): JSX.Element { return ; } -export function InAnotherCall(args: CallLinkDetailsProps): JSX.Element { - return ; +export function NonAdminAndCallActive(args: CallLinkDetailsProps): JSX.Element { + return ( + + ); +} + +export function InAnotherCall(args: CallLinkDetailsProps): JSX.Element { + return ( + + ); +} + +export function InAnotherCallAndCallActive( + args: CallLinkDetailsProps +): JSX.Element { + return ( + + ); } diff --git a/ts/components/CallLinkDetails.tsx b/ts/components/CallLinkDetails.tsx index e42718b44305..fa32a9655322 100644 --- a/ts/components/CallLinkDetails.tsx +++ b/ts/components/CallLinkDetails.tsx @@ -1,6 +1,7 @@ // Copyright 2024 Signal Messenger, LLC // SPDX-License-Identifier: AGPL-3.0-only import React, { useState } from 'react'; +import classNames from 'classnames'; import type { CallHistoryGroup } from '../types/CallDisposition'; import type { LocalizerType } from '../types/I18N'; import { CallHistoryGroupPanelSection } from './conversation/conversation-details/CallHistoryGroupPanelSection'; @@ -21,6 +22,8 @@ import { isCallLinkAdmin } from '../types/CallLink'; import { CallLinkRestrictionsSelect } from './CallLinkRestrictionsSelect'; import { ConfirmationDialog } from './ConfirmationDialog'; import { InAnotherCallTooltip } from './conversation/InAnotherCallTooltip'; +import { offsetDistanceModifier } from '../util/popperUtil'; +import { Tooltip, TooltipPlacement } from './Tooltip'; function toUrlWithoutProtocol(url: URL): string { return `${url.hostname}${url.pathname}${url.search}${url.hash}`; @@ -29,7 +32,9 @@ function toUrlWithoutProtocol(url: URL): string { export type CallLinkDetailsProps = Readonly<{ callHistoryGroup: CallHistoryGroup; callLink: CallLinkType; - hasActiveCall: boolean; + isAnybodyInCall: boolean; + isInCall: boolean; + isInAnotherCall: boolean; i18n: LocalizerType; onDeleteCallLink: () => void; onOpenCallLinkAddNameModal: () => void; @@ -42,7 +47,9 @@ export function CallLinkDetails({ callHistoryGroup, callLink, i18n, - hasActiveCall, + isAnybodyInCall, + isInCall, + isInAnotherCall, onDeleteCallLink, onOpenCallLinkAddNameModal, onStartCallLinkLobby, @@ -56,15 +63,32 @@ export function CallLinkDetails({ }); const joinButton = ( ); + const callLinkRestrictionsSelect = ( + + ); return (
@@ -92,7 +116,7 @@ export function CallLinkDetails({

- {hasActiveCall ? ( + {isInAnotherCall ? ( {joinButton} @@ -130,11 +154,20 @@ export function CallLinkDetails({ } label={i18n('icu:CallLinkDetails__ApproveAllMembersLabel')} right={ - + isAnybodyInCall ? ( + + {callLinkRestrictionsSelect} + + ) : ( + callLinkRestrictionsSelect + ) } /> @@ -166,14 +199,34 @@ export function CallLinkDetails({ {isCallLinkAdmin(callLink) && ( } - label={i18n('icu:CallLinkDetails__DeleteLink')} + label={ + isAnybodyInCall ? ( + + {i18n('icu:CallLinkDetails__DeleteLink')} + + ) : ( + i18n('icu:CallLinkDetails__DeleteLink') + ) + } onClick={() => { setIsDeleteCallLinkModalOpen(true); }} diff --git a/ts/components/CallLinkRestrictionsSelect.tsx b/ts/components/CallLinkRestrictionsSelect.tsx index d9e03b6e3776..4434be4d7d5b 100644 --- a/ts/components/CallLinkRestrictionsSelect.tsx +++ b/ts/components/CallLinkRestrictionsSelect.tsx @@ -9,6 +9,7 @@ import type { LocalizerType } from '../types/I18N'; import { Select } from './Select'; export type CallLinkRestrictionsSelectProps = Readonly<{ + disabled?: boolean; i18n: LocalizerType; id?: string; value: CallLinkRestrictions; @@ -16,6 +17,7 @@ export type CallLinkRestrictionsSelectProps = Readonly<{ }>; export function CallLinkRestrictionsSelect({ + disabled, i18n, id, value, @@ -23,6 +25,7 @@ export function CallLinkRestrictionsSelect({ }: CallLinkRestrictionsSelectProps): JSX.Element { return (