diff --git a/app/products/calls/components/call_message/call_message.tsx b/app/products/calls/components/call_message/call_message.tsx
index 54426cfd421..4be378fdd2e 100644
--- a/app/products/calls/components/call_message/call_message.tsx
+++ b/app/products/calls/components/call_message/call_message.tsx
@@ -32,7 +32,7 @@ type CallMessageProps = {
currentChannelName: string;
callChannelName: string;
intl: typeof IntlShape;
- isCloudLimitRestricted: boolean;
+ isLimitRestricted: boolean;
}
const getStyleSheet = makeStyleSheetFromTheme((theme: Theme) => {
@@ -121,11 +121,11 @@ const CallMessage = ({
currentChannelName,
callChannelName,
intl,
- isCloudLimitRestricted,
+ isLimitRestricted,
}: CallMessageProps) => {
const style = getStyleSheet(theme);
const joinHandler = () => {
- if (alreadyInTheCall || isCloudLimitRestricted) {
+ if (alreadyInTheCall || isLimitRestricted) {
return;
}
leaveAndJoinWithAlert(intl, post.channel_id, callChannelName, currentChannelName, confirmToJoin, actions.joinCall);
@@ -187,15 +187,15 @@ const CallMessage = ({
-
+
{joinCallButtonText}
diff --git a/app/products/calls/components/call_message/index.ts b/app/products/calls/components/call_message/index.ts
index e82eca7742e..647f302e555 100644
--- a/app/products/calls/components/call_message/index.ts
+++ b/app/products/calls/components/call_message/index.ts
@@ -11,7 +11,7 @@ import {isTimezoneEnabled} from '@mm-redux/selectors/entities/timezone';
import {getUser, getCurrentUser} from '@mm-redux/selectors/entities/users';
import {getUserCurrentTimezone} from '@mm-redux/utils/timezone_utils';
import {joinCall} from '@mmproducts/calls/store/actions/calls';
-import {getCalls, getCurrentCall, isCloudLimitRestricted} from '@mmproducts/calls/store/selectors/calls';
+import {getCalls, getCurrentCall, isLimitRestricted} from '@mmproducts/calls/store/selectors/calls';
import CallMessage from './call_message';
@@ -41,7 +41,7 @@ function mapStateToProps(state: GlobalState, ownProps: OwnProps) {
userTimezone: enableTimezone ? getUserCurrentTimezone(currentUser.timezone) : undefined,
currentChannelName: getChannel(state, post.channel_id)?.display_name,
callChannelName: currentCall ? getChannel(state, currentCall.channelId)?.display_name : '',
- isCloudLimitRestricted: isCloudLimitRestricted(state, post.channel_id),
+ isLimitRestricted: isLimitRestricted(state, post.channel_id),
};
}
diff --git a/app/products/calls/components/channel_info/start_call.tsx b/app/products/calls/components/channel_info/start_call.tsx
index e1091c89c3c..ab7ed9f4392 100644
--- a/app/products/calls/components/channel_info/start_call.tsx
+++ b/app/products/calls/components/channel_info/start_call.tsx
@@ -10,7 +10,7 @@ import {GlobalState} from '@mm-redux/types/store';
import {Theme} from '@mm-redux/types/theme';
import leaveAndJoinWithAlert from '@mmproducts/calls/components/leave_and_join_alert';
import {useTryCallsFunction} from '@mmproducts/calls/hooks';
-import {getCalls, getCurrentCall, isCloudLimitRestricted} from '@mmproducts/calls/store/selectors/calls';
+import {getCalls, getCurrentCall, isLimitRestricted} from '@mmproducts/calls/store/selectors/calls';
import ChannelInfoRow from '@screens/channel_info/channel_info_row';
import Separator from '@screens/channel_info/separator';
import {preventDoubleTap} from '@utils/tap';
@@ -28,7 +28,7 @@ const StartCall = ({testID, theme, intl, joinCall}: Props) => {
const currentCall = useSelector(getCurrentCall);
const currentCallChannelId = currentCall?.channelId || '';
const callChannelName = useSelector((state: GlobalState) => getChannel(state, currentCallChannelId)?.display_name) || '';
- const cloudLimitRestricted = useSelector(isCloudLimitRestricted);
+ const limitRestricted = useSelector(isLimitRestricted);
const confirmToJoin = Boolean(currentCall && currentCall.channelId !== currentChannel.id);
const alreadyInTheCall = Boolean(currentCall && call && currentCall.channelId === call.channelId);
@@ -40,7 +40,7 @@ const StartCall = ({testID, theme, intl, joinCall}: Props) => {
const [tryLeaveAndJoin, msgPostfix] = useTryCallsFunction(leaveAndJoin);
const handleStartCall = useCallback(preventDoubleTap(tryLeaveAndJoin), [tryLeaveAndJoin]);
- if (alreadyInTheCall || cloudLimitRestricted) {
+ if (alreadyInTheCall || limitRestricted) {
return null;
}
diff --git a/app/products/calls/components/join_call/index.ts b/app/products/calls/components/join_call/index.ts
index 10c8d8999b0..e7275e52f13 100644
--- a/app/products/calls/components/join_call/index.ts
+++ b/app/products/calls/components/join_call/index.ts
@@ -6,7 +6,7 @@ import {bindActionCreators, Dispatch} from 'redux';
import {getChannel, getCurrentChannelId} from '@mm-redux/selectors/entities/channels';
import {getTheme} from '@mm-redux/selectors/entities/preferences';
import {joinCall} from '@mmproducts/calls/store/actions/calls';
-import {getCalls, getCurrentCall, isCloudLimitRestricted} from '@mmproducts/calls/store/selectors/calls';
+import {getCalls, getCurrentCall, isLimitRestricted} from '@mmproducts/calls/store/selectors/calls';
import JoinCall from './join_call';
@@ -23,7 +23,7 @@ function mapStateToProps(state: GlobalState) {
alreadyInTheCall: Boolean(currentCall && call && currentCall.channelId === call.channelId),
currentChannelName: getChannel(state, currentChannelId)?.display_name,
callChannelName: currentCall ? getChannel(state, currentCall.channelId)?.display_name : '',
- isCloudLimitRestricted: isCloudLimitRestricted(state),
+ isLimitRestricted: isLimitRestricted(state),
};
}
diff --git a/app/products/calls/components/join_call/join_call.test.js b/app/products/calls/components/join_call/join_call.test.js
index 535175c8d17..08821d28b30 100644
--- a/app/products/calls/components/join_call/join_call.test.js
+++ b/app/products/calls/components/join_call/join_call.test.js
@@ -38,7 +38,7 @@ describe('JoinCall', () => {
alreadyInTheCall: false,
currentChannelName: 'Current Channel',
callChannelName: 'Call Channel',
- isCloudLimitRestricted: false,
+ isLimitRestricted: false,
};
test('should match snapshot', () => {
diff --git a/app/products/calls/components/join_call/join_call.tsx b/app/products/calls/components/join_call/join_call.tsx
index 102c2a19137..2068078d75a 100644
--- a/app/products/calls/components/join_call/join_call.tsx
+++ b/app/products/calls/components/join_call/join_call.tsx
@@ -26,7 +26,7 @@ type Props = {
alreadyInTheCall: boolean;
currentChannelName: string;
callChannelName: string;
- isCloudLimitRestricted: boolean;
+ isLimitRestricted: boolean;
intl: typeof IntlShape;
}
@@ -96,7 +96,7 @@ const JoinCall = (props: Props) => {
}, [props.call, props.alreadyInTheCall]);
const joinHandler = () => {
- if (props.isCloudLimitRestricted) {
+ if (props.isLimitRestricted) {
return;
}
leaveAndJoinWithAlert(props.intl, props.call.channelId, props.callChannelName, props.currentChannelName, props.confirmToJoin, props.actions.joinCall);
@@ -114,7 +114,7 @@ const JoinCall = (props: Props) => {
return (
{
style={style.joinCallIcon}
/>
{'Join Call'}
- {props.isCloudLimitRestricted ?
+ {props.isLimitRestricted ?
{'Participant limit reached'}
:
diff --git a/app/products/calls/store/selectors/calls.test.js b/app/products/calls/store/selectors/calls.test.js
index a1f5271af83..9b98d68e87e 100644
--- a/app/products/calls/store/selectors/calls.test.js
+++ b/app/products/calls/store/selectors/calls.test.js
@@ -4,11 +4,12 @@
import assert from 'assert';
import deepFreezeAndThrowOnMutation from '@mm-redux/utils/deep_freeze';
+import {DefaultServerConfig} from '@mmproducts/calls/store/types/calls';
import * as Selectors from './calls';
describe('Selectors.Calls', () => {
- const call1 = {id: 'call1'};
+ const call1 = {id: 'call1', participants: [{id: 'me'}]};
const call2 = {id: 'call2'};
const testState = deepFreezeAndThrowOnMutation({
entities: {
@@ -20,6 +21,10 @@ describe('Selectors.Calls', () => {
joined: 'call1',
enabled: {'channel-1': true, 'channel-2': false},
screenShareURL: 'screenshare-url',
+ config: DefaultServerConfig,
+ },
+ general: {
+ license: {},
},
},
});
@@ -77,4 +82,119 @@ describe('Selectors.Calls', () => {
it('getScreenShareURL', () => {
assert.equal(Selectors.getScreenShareURL(testState), 'screenshare-url');
});
+
+ it('isLimitRestricted', () => {
+ // Default, no limit
+ assert.equal(Selectors.isLimitRestricted(testState, 'call1'), false);
+
+ let newState = {
+ ...testState,
+ entities: {
+ ...testState.entities,
+ calls: {
+ ...testState.entities.calls,
+ config: {
+ ...testState.entities.calls.config,
+ MaxCallParticipants: 1,
+ },
+ },
+ },
+ };
+
+ // Limit to 1 and one participant already in call.
+ assert.equal(Selectors.isLimitRestricted(newState, 'call1'), true);
+
+ // Limit to 1 but no call ongoing.
+ assert.equal(Selectors.isLimitRestricted(newState), false);
+
+ newState = {
+ ...testState,
+ entities: {
+ ...testState.entities,
+ general: {
+ license: {Cloud: 'true'},
+ },
+ },
+ };
+
+ // On cloud, no limit.
+ assert.equal(Selectors.isLimitRestricted(newState, 'call1'), false);
+
+ newState = {
+ ...testState,
+ entities: {
+ ...testState.entities,
+ calls: {
+ ...testState.entities.calls,
+ config: {
+ ...testState.entities.calls.config,
+ MaxCallParticipants: 1,
+ },
+ },
+ general: {
+ license: {Cloud: 'true'},
+ },
+ },
+ };
+
+ // On cloud, with limit.
+ assert.equal(Selectors.isLimitRestricted(newState, 'call1'), true);
+
+ const call = {id: 'call1',
+ participants: [
+ {},
+ {},
+ {},
+ {},
+ {},
+ {},
+ {},
+ ]};
+ newState = {
+ ...testState,
+ entities: {
+ ...testState.entities,
+ calls: {
+ ...testState.entities.calls,
+ calls: {call1: call},
+ },
+ general: {
+ license: {Cloud: 'true'},
+ },
+ },
+ };
+ delete newState.entities.calls.config.MaxCallParticipants;
+
+ // On cloud, MaxCallParticipants missing, default should be used.
+ assert.equal(Selectors.isLimitRestricted(newState, 'call1'), false);
+
+ const newCall = {id: 'call1',
+ participants: [
+ {},
+ {},
+ {},
+ {},
+ {},
+ {},
+ {},
+ {},
+ ]};
+ newState = {
+ ...testState,
+ entities: {
+ ...testState.entities,
+ calls: {
+ ...testState.entities.calls,
+ calls: {call1: newCall},
+ },
+ general: {
+ license: {Cloud: 'true'},
+ },
+ },
+ };
+ delete newState.entities.calls.config.MaxCallParticipants;
+
+ // On cloud, MaxCallParticipants missing, default should be used.
+ assert.equal(Selectors.isLimitRestricted(newState, 'call1'), true);
+ });
});
diff --git a/app/products/calls/store/selectors/calls.ts b/app/products/calls/store/selectors/calls.ts
index 9c5828b6b17..d456ee34ca2 100644
--- a/app/products/calls/store/selectors/calls.ts
+++ b/app/products/calls/store/selectors/calls.ts
@@ -92,37 +92,25 @@ const isCloud: (state: GlobalState) => boolean = createSelector(
(license) => license?.Cloud === 'true',
);
-// NOTE: Calls v0.5.3 will not return sku_short_name in config, so this will fail
-const isCloudProfessionalOrEnterprise: (state: GlobalState) => boolean = createSelector(
+export const isLimitRestricted: (state: GlobalState, channelId?: string) => boolean = createSelector(
isCloud,
- getLicense,
- getConfig,
- (cloud, license, config) => {
- return cloud && (config.sku_short_name === 'professional' || config.sku_short_name === 'enterprise');
- },
-);
-
-export const isCloudLimitRestricted: (state: GlobalState, channelId?: string) => boolean = createSelector(
- isCloud,
- isCloudProfessionalOrEnterprise,
(state: GlobalState, channelId: string) => (channelId ? getCalls(state)[channelId] : getCallInCurrentChannel(state)),
getConfig,
- (cloud, isCloudPaid, call, config) => {
- if (!call || !cloud) {
+ (cloud, call, config) => {
+ if (!call) {
return false;
}
+ const numParticipants = Object.keys(call.participants || {}).length;
+
// TODO: The next block is used for case when cloud server is using Calls v0.5.3. This can be removed
// when v0.5.4 is prepackaged in cloud. Then replace the max in the return statement with
- // config.cloud_max_participants, and replace cloudPaid with isCloudPaid
- let max = config.cloud_max_participants;
- let cloudPaid = isCloudPaid;
+ // config.MaxCallParticipants.
+ let max = config.MaxCallParticipants;
if (cloud && !max) {
- // We're not sure if we're in cloud paid because this could be v0.5.3, so assume we are for now (the server will prevent calls)
- cloudPaid = true;
max = Calls.DefaultCloudMaxParticipants;
}
- return cloudPaid && Object.keys(call.participants || {}).length >= max;
+ return max !== 0 && numParticipants >= max;
},
);
diff --git a/app/products/calls/store/types/calls.ts b/app/products/calls/store/types/calls.ts
index fb3b85f4214..83dcdfdcbdd 100644
--- a/app/products/calls/store/types/calls.ts
+++ b/app/products/calls/store/types/calls.ts
@@ -62,8 +62,8 @@ export type ServerConfig = {
ICEServers: string[];
AllowEnableCalls: boolean;
DefaultEnabled: boolean;
+ MaxCallParticipants: number;
sku_short_name: string;
- cloud_max_participants: number;
last_retrieved_at: number;
}
@@ -71,7 +71,7 @@ export const DefaultServerConfig = {
ICEServers: [],
AllowEnableCalls: false,
DefaultEnabled: false,
+ MaxCallParticipants: 0,
sku_short_name: '',
- cloud_max_participants: 0,
last_retrieved_at: 0,
} as ServerConfig;