diff --git a/app/products/calls/alerts.ts b/app/products/calls/alerts.ts index 86395da6b..9b8c20376 100644 --- a/app/products/calls/alerts.ts +++ b/app/products/calls/alerts.ts @@ -5,6 +5,7 @@ import {Alert} from 'react-native'; import {Navigation} from 'react-native-navigation'; import {hasMicrophonePermission, joinCall, leaveCall, unmuteMyself} from '@calls/actions'; +import {LimitRestrictedInfo} from '@calls/observers'; import {getCallsConfig, getCallsState, setMicPermissionsGranted} from '@calls/state'; import {errorAlert} from '@calls/utils'; import {Screens} from '@constants'; @@ -23,15 +24,21 @@ let recordingAlertLock = false; // Only unlock if/when the user starts a recording. let recordingWillBePostedLock = true; -export const showLimitRestrictedAlert = (maxParticipants: number, intl: IntlShape) => { +export const showLimitRestrictedAlert = (info: LimitRestrictedInfo, intl: IntlShape) => { const title = intl.formatMessage({ - id: 'mobile.calls_participant_limit_title', - defaultMessage: 'Participant limit reached', + id: 'mobile.calls_participant_limit_title_GA', + defaultMessage: 'This call is at capacity', }); - const message = intl.formatMessage({ + let message = intl.formatMessage({ id: 'mobile.calls_limit_msg', defaultMessage: 'The maximum number of participants per call is {maxParticipants}. Contact your System Admin to increase the limit.', - }, {maxParticipants}); + }, {maxParticipants: info.maxParticipants}); + if (info.isCloudStarter) { + message = intl.formatMessage({ + id: 'mobile.calls_limit_msg_GA', + defaultMessage: 'Upgrade to Cloud Professional or Cloud Enterprise to enable group calls with more than {maxParticipants} participants.', + }, {maxParticipants: info.maxParticipants}); + } const ok = intl.formatMessage({ id: 'mobile.calls_ok', defaultMessage: 'Okay', diff --git a/app/products/calls/components/calls_custom_message/calls_custom_message.tsx b/app/products/calls/components/calls_custom_message/calls_custom_message.tsx index 91fceb28c..16640f43f 100644 --- a/app/products/calls/components/calls_custom_message/calls_custom_message.tsx +++ b/app/products/calls/components/calls_custom_message/calls_custom_message.tsx @@ -126,7 +126,7 @@ export const CallsCustomMessage = ({ } if (isLimitRestricted) { - showLimitRestrictedAlert(limitRestrictedInfo!.maxParticipants, intl); + showLimitRestrictedAlert(limitRestrictedInfo!, intl); return; } diff --git a/app/products/calls/components/calls_custom_message/index.ts b/app/products/calls/components/calls_custom_message/index.ts index b12c125bf..e2fa8be68 100644 --- a/app/products/calls/components/calls_custom_message/index.ts +++ b/app/products/calls/components/calls_custom_message/index.ts @@ -76,7 +76,7 @@ const enhanced = withObservables(['post'], ({serverUrl, post, database}: OwnProp leaveChannelName, joinChannelName, joinChannelIsDMorGM, - limitRestrictedInfo: observeIsCallLimitRestricted(serverUrl, post.channelId), + limitRestrictedInfo: observeIsCallLimitRestricted(database, serverUrl, post.channelId), }; }); diff --git a/app/products/calls/components/channel_info_start/channel_info_start_button.tsx b/app/products/calls/components/channel_info_start/channel_info_start_button.tsx index d74e56bf4..9f2857456 100644 --- a/app/products/calls/components/channel_info_start/channel_info_start_button.tsx +++ b/app/products/calls/components/channel_info_start/channel_info_start_button.tsx @@ -44,7 +44,7 @@ const ChannelInfoStartButton = ({ if (alreadyInCall) { leaveCall(); } else if (isLimitRestricted) { - showLimitRestrictedAlert(limitRestrictedInfo.maxParticipants, intl); + showLimitRestrictedAlert(limitRestrictedInfo, intl); } else { leaveAndJoinWithAlert(intl, serverUrl, channelId, currentCallChannelName, displayName, confirmToJoin, !isACallInCurrentChannel, channelIsDMorGM); } diff --git a/app/products/calls/components/channel_info_start/index.ts b/app/products/calls/components/channel_info_start/index.ts index 62abb3001..cef55b487 100644 --- a/app/products/calls/components/channel_info_start/index.ts +++ b/app/products/calls/components/channel_info_start/index.ts @@ -58,7 +58,7 @@ const enhanced = withObservables([], ({serverUrl, channelId, database}: EnhanceP confirmToJoin, alreadyInCall, currentCallChannelName, - limitRestrictedInfo: observeIsCallLimitRestricted(serverUrl, channelId), + limitRestrictedInfo: observeIsCallLimitRestricted(database, serverUrl, channelId), }; }); diff --git a/app/products/calls/components/join_call_banner/index.ts b/app/products/calls/components/join_call_banner/index.ts index 339c0005f..efaa0c32f 100644 --- a/app/products/calls/components/join_call_banner/index.ts +++ b/app/products/calls/components/join_call_banner/index.ts @@ -68,7 +68,7 @@ const enhanced = withObservables(['serverUrl', 'channelId'], ({ inACall, currentCallChannelName, channelCallStartTime, - limitRestrictedInfo: observeIsCallLimitRestricted(serverUrl, channelId), + limitRestrictedInfo: observeIsCallLimitRestricted(database, serverUrl, channelId), }; }); diff --git a/app/products/calls/components/join_call_banner/join_call_banner.tsx b/app/products/calls/components/join_call_banner/join_call_banner.tsx index db419e54d..2f35fc596 100644 --- a/app/products/calls/components/join_call_banner/join_call_banner.tsx +++ b/app/products/calls/components/join_call_banner/join_call_banner.tsx @@ -101,7 +101,7 @@ const JoinCallBanner = ({ const joinHandler = async () => { if (isLimitRestricted) { - showLimitRestrictedAlert(limitRestrictedInfo.maxParticipants, intl); + showLimitRestrictedAlert(limitRestrictedInfo, intl); return; } leaveAndJoinWithAlert(intl, serverUrl, channelId, currentCallChannelName, displayName, inACall, false, channelIsDMorGM); diff --git a/app/products/calls/observers/index.ts b/app/products/calls/observers/index.ts index e27c6a7d6..3acefafd3 100644 --- a/app/products/calls/observers/index.ts +++ b/app/products/calls/observers/index.ts @@ -4,7 +4,8 @@ import {distinctUntilChanged, switchMap, combineLatest, Observable, of as of$} from 'rxjs'; import {observeCallsConfig, observeCallsState} from '@calls/state'; -import {observeConfigValue} from '@queries/servers/system'; +import {License} from '@constants'; +import {observeConfigValue, observeLicense} from '@queries/servers/system'; import {isMinimumServerVersion} from '@utils/helpers'; import type {Database} from '@nozbe/watermelondb'; @@ -12,6 +13,7 @@ import type {Database} from '@nozbe/watermelondb'; export type LimitRestrictedInfo = { limitRestricted: boolean; maxParticipants: number; + isCloudStarter: boolean; } export const observeIsCallsEnabledInChannel = (database: Database, serverUrl: string, channelId: Observable) => { @@ -36,7 +38,7 @@ export const observeIsCallsEnabledInChannel = (database: Database, serverUrl: st ) as Observable; }; -export const observeIsCallLimitRestricted = (serverUrl: string, channelId: string) => { +export const observeIsCallLimitRestricted = (database: Database, serverUrl: string, channelId: string) => { const maxParticipants = observeCallsConfig(serverUrl).pipe( switchMap((c) => of$(c.MaxCallParticipants)), distinctUntilChanged(), @@ -45,12 +47,21 @@ export const observeIsCallLimitRestricted = (serverUrl: string, channelId: strin switchMap((cs) => of$(Object.keys(cs.calls[channelId]?.participants || {}).length)), distinctUntilChanged(), ); - return combineLatest([maxParticipants, callNumOfParticipants]).pipe( - switchMap(([max, numParticipants]) => of$({ + const isCloud = observeLicense(database).pipe( + switchMap((l) => of$(l?.Cloud === 'true')), + distinctUntilChanged(), + ); + const skuShortName = observeCallsConfig(serverUrl).pipe( + switchMap((c) => of$(c.sku_short_name)), + distinctUntilChanged(), + ); + return combineLatest([maxParticipants, callNumOfParticipants, isCloud, skuShortName]).pipe( + switchMap(([max, numParticipants, cloud, sku]) => of$({ limitRestricted: max !== 0 && numParticipants >= max, maxParticipants: max, + isCloudStarter: cloud && sku === License.SKU_SHORT_NAME.Starter, })), distinctUntilChanged((prev, curr) => - prev.limitRestricted === curr.limitRestricted && prev.maxParticipants === curr.maxParticipants), + prev.limitRestricted === curr.limitRestricted && prev.maxParticipants === curr.maxParticipants && prev.isCloudStarter === curr.isCloudStarter), ) as Observable; }; diff --git a/assets/base/i18n/en.json b/assets/base/i18n/en.json index 160617d12..b413c8c1a 100644 --- a/assets/base/i18n/en.json +++ b/assets/base/i18n/en.json @@ -296,7 +296,7 @@ "general_settings.display": "Display", "general_settings.help": "Help", "general_settings.notifications": "Notifications", - "general_settings.report_problem": "Report a Problem", + "general_settings.report_problem": "Report a problem", "get_post_link_modal.title": "Copy Link", "global_threads.allThreads": "All Your Threads", "global_threads.emptyThreads.message": "Any threads you are mentioned in or have participated in will show here along with any threads you have followed.", @@ -393,6 +393,7 @@ "mobile.calls_leave": "Leave", "mobile.calls_leave_call": "Leave call", "mobile.calls_limit_msg": "The maximum number of participants per call is {maxParticipants}. Contact your System Admin to increase the limit.", + "mobile.calls_limit_msg_GA": "Upgrade to Cloud Professional or Cloud Enterprise to enable group calls with more than {maxParticipants} participants.", "mobile.calls_limit_reached": "Participant limit reached", "mobile.calls_lower_hand": "Lower hand", "mobile.calls_mic_error": "To participate, open Settings to grant Mattermost access to your microphone.", @@ -406,13 +407,15 @@ "mobile.calls_not_available_title": "Calls is not enabled", "mobile.calls_ok": "OK", "mobile.calls_okay": "Okay", - "mobile.calls_participant_limit_title": "Participant limit reached", + "mobile.calls_participant_limit_title_GA": "This call is at capacity", "mobile.calls_participant_rec": "The host has started recording this meeting. By staying in the meeting you give consent to being recorded.", "mobile.calls_participant_rec_title": "Recording is in progress", "mobile.calls_raise_hand": "Raise hand", "mobile.calls_react": "React", "mobile.calls_rec": "rec", "mobile.calls_record": "Record", + "mobile.calls_request_message": "Calls are currently running in test mode and only system admins can start them. Reach out directly to your system admin for assistance", + "mobile.calls_request_title": "Calls is not currently enabled", "mobile.calls_see_logs": "See server logs", "mobile.calls_speaker": "Speaker", "mobile.calls_start_call": "Start Call",