Fix call link delete to require inactive call
This commit is contained in:
parent
902c1f4634
commit
3f8b8bdb2d
5 changed files with 98 additions and 37 deletions
|
@ -24,6 +24,7 @@ export default {
|
||||||
callHistoryGroup: getFakeCallLinkHistoryGroup(),
|
callHistoryGroup: getFakeCallLinkHistoryGroup(),
|
||||||
callLink: FAKE_CALL_LINK_WITH_ADMIN_KEY,
|
callLink: FAKE_CALL_LINK_WITH_ADMIN_KEY,
|
||||||
isAnybodyInCall: false,
|
isAnybodyInCall: false,
|
||||||
|
isCallActiveOnServer: false,
|
||||||
isInCall: false,
|
isInCall: false,
|
||||||
isInAnotherCall: false,
|
isInAnotherCall: false,
|
||||||
onDeleteCallLink: action('onDeleteCallLink'),
|
onDeleteCallLink: action('onDeleteCallLink'),
|
||||||
|
@ -39,11 +40,19 @@ export function Admin(args: CallLinkDetailsProps): JSX.Element {
|
||||||
}
|
}
|
||||||
|
|
||||||
export function AdminAndCallActive(args: CallLinkDetailsProps): JSX.Element {
|
export function AdminAndCallActive(args: CallLinkDetailsProps): JSX.Element {
|
||||||
return <CallLinkDetails {...args} isAnybodyInCall />;
|
return <CallLinkDetails {...args} isAnybodyInCall isCallActiveOnServer />;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function AdminAndInCall(args: CallLinkDetailsProps): JSX.Element {
|
export function AdminAndInCall(args: CallLinkDetailsProps): JSX.Element {
|
||||||
return <CallLinkDetails {...args} isAnybodyInCall isInCall />;
|
return (
|
||||||
|
<CallLinkDetails {...args} isAnybodyInCall isCallActiveOnServer isInCall />
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function AdminRecentlyEndedCall(
|
||||||
|
args: CallLinkDetailsProps
|
||||||
|
): JSX.Element {
|
||||||
|
return <CallLinkDetails {...args} isCallActiveOnServer />;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function NonAdmin(args: CallLinkDetailsProps): JSX.Element {
|
export function NonAdmin(args: CallLinkDetailsProps): JSX.Element {
|
||||||
|
@ -52,13 +61,23 @@ export function NonAdmin(args: CallLinkDetailsProps): JSX.Element {
|
||||||
|
|
||||||
export function NonAdminAndCallActive(args: CallLinkDetailsProps): JSX.Element {
|
export function NonAdminAndCallActive(args: CallLinkDetailsProps): JSX.Element {
|
||||||
return (
|
return (
|
||||||
<CallLinkDetails {...args} callLink={FAKE_CALL_LINK} isAnybodyInCall />
|
<CallLinkDetails
|
||||||
|
{...args}
|
||||||
|
callLink={FAKE_CALL_LINK}
|
||||||
|
isAnybodyInCall
|
||||||
|
isCallActiveOnServer
|
||||||
|
/>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function InAnotherCall(args: CallLinkDetailsProps): JSX.Element {
|
export function InAnotherCall(args: CallLinkDetailsProps): JSX.Element {
|
||||||
return (
|
return (
|
||||||
<CallLinkDetails {...args} callLink={FAKE_CALL_LINK} isInAnotherCall />
|
<CallLinkDetails
|
||||||
|
{...args}
|
||||||
|
callLink={FAKE_CALL_LINK}
|
||||||
|
isInAnotherCall
|
||||||
|
isCallActiveOnServer
|
||||||
|
/>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -70,6 +89,7 @@ export function InAnotherCallAndCallActive(
|
||||||
{...args}
|
{...args}
|
||||||
callLink={FAKE_CALL_LINK}
|
callLink={FAKE_CALL_LINK}
|
||||||
isAnybodyInCall
|
isAnybodyInCall
|
||||||
|
isCallActiveOnServer
|
||||||
isInAnotherCall
|
isInAnotherCall
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
|
|
|
@ -33,6 +33,7 @@ export type CallLinkDetailsProps = Readonly<{
|
||||||
callHistoryGroup: CallHistoryGroup;
|
callHistoryGroup: CallHistoryGroup;
|
||||||
callLink: CallLinkType | undefined;
|
callLink: CallLinkType | undefined;
|
||||||
isAnybodyInCall: boolean;
|
isAnybodyInCall: boolean;
|
||||||
|
isCallActiveOnServer: boolean;
|
||||||
isInCall: boolean;
|
isInCall: boolean;
|
||||||
isInAnotherCall: boolean;
|
isInAnotherCall: boolean;
|
||||||
i18n: LocalizerType;
|
i18n: LocalizerType;
|
||||||
|
@ -48,6 +49,7 @@ export function CallLinkDetails({
|
||||||
callLink,
|
callLink,
|
||||||
i18n,
|
i18n,
|
||||||
isAnybodyInCall,
|
isAnybodyInCall,
|
||||||
|
isCallActiveOnServer,
|
||||||
isInCall,
|
isInCall,
|
||||||
isInAnotherCall,
|
isInAnotherCall,
|
||||||
onDeleteCallLink,
|
onDeleteCallLink,
|
||||||
|
@ -88,7 +90,7 @@ export function CallLinkDetails({
|
||||||
);
|
);
|
||||||
const callLinkRestrictionsSelect = (
|
const callLinkRestrictionsSelect = (
|
||||||
<CallLinkRestrictionsSelect
|
<CallLinkRestrictionsSelect
|
||||||
disabled={isAnybodyInCall}
|
disabled={isCallActiveOnServer}
|
||||||
i18n={i18n}
|
i18n={i18n}
|
||||||
value={callLink.restrictions}
|
value={callLink.restrictions}
|
||||||
onChange={onUpdateCallLinkRestrictions}
|
onChange={onUpdateCallLinkRestrictions}
|
||||||
|
@ -159,7 +161,7 @@ export function CallLinkDetails({
|
||||||
}
|
}
|
||||||
label={i18n('icu:CallLinkDetails__ApproveAllMembersLabel')}
|
label={i18n('icu:CallLinkDetails__ApproveAllMembersLabel')}
|
||||||
right={
|
right={
|
||||||
isAnybodyInCall ? (
|
isCallActiveOnServer ? (
|
||||||
<Tooltip
|
<Tooltip
|
||||||
className="CallLinkDetails__ApproveAllMembersDisabledTooltip"
|
className="CallLinkDetails__ApproveAllMembersDisabledTooltip"
|
||||||
content={i18n(
|
content={i18n(
|
||||||
|
@ -207,9 +209,9 @@ export function CallLinkDetails({
|
||||||
className={classNames({
|
className={classNames({
|
||||||
CallLinkDetails__DeleteLink: true,
|
CallLinkDetails__DeleteLink: true,
|
||||||
'CallLinkDetails__DeleteLink--disabled-for-active-call':
|
'CallLinkDetails__DeleteLink--disabled-for-active-call':
|
||||||
isAnybodyInCall,
|
isCallActiveOnServer,
|
||||||
})}
|
})}
|
||||||
disabled={isAnybodyInCall}
|
disabled={isCallActiveOnServer}
|
||||||
icon={
|
icon={
|
||||||
<ConversationDetailsIcon
|
<ConversationDetailsIcon
|
||||||
ariaLabel={i18n('icu:CallLinkDetails__DeleteLink')}
|
ariaLabel={i18n('icu:CallLinkDetails__DeleteLink')}
|
||||||
|
@ -217,7 +219,7 @@ export function CallLinkDetails({
|
||||||
/>
|
/>
|
||||||
}
|
}
|
||||||
label={
|
label={
|
||||||
isAnybodyInCall ? (
|
isCallActiveOnServer ? (
|
||||||
<Tooltip
|
<Tooltip
|
||||||
className="CallLinkDetails__DeleteLinkTooltip"
|
className="CallLinkDetails__DeleteLinkTooltip"
|
||||||
content={i18n(
|
content={i18n(
|
||||||
|
|
|
@ -311,32 +311,49 @@ export function CallsList({
|
||||||
|
|
||||||
const { mode, peerId } = callHistoryGroup;
|
const { mode, peerId } = callHistoryGroup;
|
||||||
const call = getCallByPeerId({ mode, peerId });
|
const call = getCallByPeerId({ mode, peerId });
|
||||||
if (!call) {
|
if (!call || !isGroupOrAdhocCallState(call)) {
|
||||||
|
// We can't tell from CallHistory alone whether a 1:1 call is active
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isGroupOrAdhocCallState(call)) {
|
// eraId indicates a group/call link call is active.
|
||||||
if (!isAnybodyInGroupCall(call.peekInfo)) {
|
const eraId = call.peekInfo?.eraId;
|
||||||
return false;
|
if (!eraId) {
|
||||||
}
|
return false;
|
||||||
|
|
||||||
if (mode === CallMode.Group) {
|
|
||||||
const eraId = call.peekInfo?.eraId;
|
|
||||||
if (!eraId) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
const callId = getCallIdFromEra(eraId);
|
|
||||||
return callHistoryGroup.children.some(
|
|
||||||
groupItem => groupItem.callId === callId
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// We can't tell from CallHistory alone whether a 1:1 call is active
|
// Group calls have multiple entries sharing a peerId. To distinguish them we need
|
||||||
return false;
|
// to compare the active callId (derived from eraId) with this item's callId set.
|
||||||
|
if (mode === CallMode.Group) {
|
||||||
|
const callId = getCallIdFromEra(eraId);
|
||||||
|
return callHistoryGroup.children.some(
|
||||||
|
groupItem => groupItem.callId === callId
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Call links only show once in the calls list, so we can just return active.
|
||||||
|
return true;
|
||||||
|
},
|
||||||
|
[getCallByPeerId]
|
||||||
|
);
|
||||||
|
|
||||||
|
const getIsAnybodyInCall = useCallback(
|
||||||
|
({
|
||||||
|
callHistoryGroup,
|
||||||
|
}: {
|
||||||
|
callHistoryGroup: CallHistoryGroup | null;
|
||||||
|
}): boolean => {
|
||||||
|
if (!callHistoryGroup) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const { mode, peerId } = callHistoryGroup;
|
||||||
|
const call = getCallByPeerId({ mode, peerId });
|
||||||
|
if (!call || !isGroupOrAdhocCallState(call)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return isAnybodyInGroupCall(call.peekInfo);
|
||||||
},
|
},
|
||||||
[getCallByPeerId]
|
[getCallByPeerId]
|
||||||
);
|
);
|
||||||
|
@ -370,7 +387,7 @@ export function CallsList({
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// For group and adhoc calls, a call has to have members in it (see getIsCallActive)
|
// For group and adhoc calls
|
||||||
return Boolean(
|
return Boolean(
|
||||||
isActive &&
|
isActive &&
|
||||||
conversation &&
|
conversation &&
|
||||||
|
@ -433,8 +450,9 @@ export function CallsList({
|
||||||
for (const item of callItems) {
|
for (const item of callItems) {
|
||||||
const { mode } = item;
|
const { mode } = item;
|
||||||
if (isGroupOrAdhocCallMode(mode)) {
|
if (isGroupOrAdhocCallMode(mode)) {
|
||||||
const isActive = getIsCallActive({ callHistoryGroup: item });
|
const isActive = getIsCallActive({
|
||||||
|
callHistoryGroup: item,
|
||||||
|
});
|
||||||
if (isActive) {
|
if (isActive) {
|
||||||
// Don't peek if you're already in the call.
|
// Don't peek if you're already in the call.
|
||||||
const activeCallConversationId = activeCall?.conversationId;
|
const activeCallConversationId = activeCall?.conversationId;
|
||||||
|
@ -711,6 +729,13 @@ export function CallsList({
|
||||||
const isActive = getIsCallActive({
|
const isActive = getIsCallActive({
|
||||||
callHistoryGroup: item,
|
callHistoryGroup: item,
|
||||||
});
|
});
|
||||||
|
// After everyone leaves a call, it remains active on the server for a little bit.
|
||||||
|
// We don't need to show the active call join button in this case.
|
||||||
|
const isAnybodyInCall =
|
||||||
|
isActive &&
|
||||||
|
getIsAnybodyInCall({
|
||||||
|
callHistoryGroup: item,
|
||||||
|
});
|
||||||
const isInCall = getIsInCall({
|
const isInCall = getIsInCall({
|
||||||
activeCallConversationId,
|
activeCallConversationId,
|
||||||
callHistoryGroup: item,
|
callHistoryGroup: item,
|
||||||
|
@ -722,7 +747,9 @@ export function CallsList({
|
||||||
const isCallButtonVisible = Boolean(
|
const isCallButtonVisible = Boolean(
|
||||||
!isAdhoc || (isAdhoc && getCallLink(item.peerId))
|
!isAdhoc || (isAdhoc && getCallLink(item.peerId))
|
||||||
);
|
);
|
||||||
const isActiveVisible = Boolean(isCallButtonVisible && item && isActive);
|
const isActiveVisible = Boolean(
|
||||||
|
isCallButtonVisible && item && isAnybodyInCall
|
||||||
|
);
|
||||||
|
|
||||||
if (searchPending || item == null || conversation == null) {
|
if (searchPending || item == null || conversation == null) {
|
||||||
return (
|
return (
|
||||||
|
@ -887,6 +914,7 @@ export function CallsList({
|
||||||
searchPending,
|
searchPending,
|
||||||
getCallLink,
|
getCallLink,
|
||||||
getConversationForItem,
|
getConversationForItem,
|
||||||
|
getIsAnybodyInCall,
|
||||||
getIsCallActive,
|
getIsCallActive,
|
||||||
getIsInCall,
|
getIsInCall,
|
||||||
selectedCallHistoryGroup,
|
selectedCallHistoryGroup,
|
||||||
|
|
|
@ -54,3 +54,9 @@ export const isAnybodyInGroupCall = (
|
||||||
}
|
}
|
||||||
return peekInfo.acis.length > 0;
|
return peekInfo.acis.length > 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const isGroupCallActiveOnServer = (
|
||||||
|
peekInfo: undefined | Readonly<Pick<GroupCallPeekInfoType, 'eraId'>>
|
||||||
|
): boolean => {
|
||||||
|
return Boolean(peekInfo?.eraId);
|
||||||
|
};
|
||||||
|
|
|
@ -14,7 +14,10 @@ import { useGlobalModalActions } from '../ducks/globalModals';
|
||||||
import { useCallingActions } from '../ducks/calling';
|
import { useCallingActions } from '../ducks/calling';
|
||||||
import { strictAssert } from '../../util/assert';
|
import { strictAssert } from '../../util/assert';
|
||||||
import type { CallLinkRestrictions } from '../../types/CallLink';
|
import type { CallLinkRestrictions } from '../../types/CallLink';
|
||||||
import { isAnybodyInGroupCall } from '../ducks/callingHelpers';
|
import {
|
||||||
|
isAnybodyInGroupCall,
|
||||||
|
isGroupCallActiveOnServer,
|
||||||
|
} from '../ducks/callingHelpers';
|
||||||
|
|
||||||
export type SmartCallLinkDetailsProps = Readonly<{
|
export type SmartCallLinkDetailsProps = Readonly<{
|
||||||
roomId: string;
|
roomId: string;
|
||||||
|
@ -66,7 +69,8 @@ export const SmartCallLinkDetails = memo(function SmartCallLinkDetails({
|
||||||
|
|
||||||
const adhocCallSelector = useSelector(getAdhocCallSelector);
|
const adhocCallSelector = useSelector(getAdhocCallSelector);
|
||||||
const adhocCall = adhocCallSelector(roomId);
|
const adhocCall = adhocCallSelector(roomId);
|
||||||
const hasActiveCall = isAnybodyInGroupCall(adhocCall?.peekInfo);
|
const isAnybodyInCall = isAnybodyInGroupCall(adhocCall?.peekInfo);
|
||||||
|
const isCallActiveOnServer = isGroupCallActiveOnServer(adhocCall?.peekInfo);
|
||||||
|
|
||||||
const activeCall = useSelector(getActiveCallState);
|
const activeCall = useSelector(getActiveCallState);
|
||||||
const isInAnotherCall = Boolean(
|
const isInAnotherCall = Boolean(
|
||||||
|
@ -80,7 +84,8 @@ export const SmartCallLinkDetails = memo(function SmartCallLinkDetails({
|
||||||
<CallLinkDetails
|
<CallLinkDetails
|
||||||
callHistoryGroup={callHistoryGroup}
|
callHistoryGroup={callHistoryGroup}
|
||||||
callLink={callLink}
|
callLink={callLink}
|
||||||
isAnybodyInCall={hasActiveCall}
|
isAnybodyInCall={isAnybodyInCall}
|
||||||
|
isCallActiveOnServer={isCallActiveOnServer}
|
||||||
isInCall={isInCall}
|
isInCall={isInCall}
|
||||||
isInAnotherCall={isInAnotherCall}
|
isInAnotherCall={isInAnotherCall}
|
||||||
i18n={i18n}
|
i18n={i18n}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue