Skip to content

Commit f6c5289

Browse files
committed
feat(chat): Add disableChat configuration option
Introduces a comprehensive disableChat config option that disables the entire chat feature including button visibility, notifications, sounds, private messages, and keyboard shortcuts. When disabled, the chat tab is hidden from the chat panel while allowing other tabs (polls, files, CC) to remain accessible.
1 parent 11c8913 commit f6c5289

File tree

18 files changed

+225
-52
lines changed

18 files changed

+225
-52
lines changed

config.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -139,6 +139,9 @@ var config = {
139139
// Disables polls feature.
140140
// disablePolls: false,
141141

142+
// Disables chat feature entirely including notifications, sounds, and private messages.
143+
// disableChat: false,
144+
142145
// Disables demote button from self-view
143146
// disableSelfDemote: false,
144147

lang/main.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1464,8 +1464,8 @@
14641464
"openChat": "Open chat",
14651465
"openReactionsMenu": "Open reactions menu",
14661466
"participants": "Participants",
1467-
"polls": "Polls",
14681467
"pip": "Enter Picture-in-Picture mode",
1468+
"polls": "Polls",
14691469
"privateMessage": "Send private message",
14701470
"profile": "Edit your profile",
14711471
"raiseHand": "Raise your hand",

react/features/base/config/configType.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -285,6 +285,7 @@ export interface IConfig {
285285
disableAudioLevels?: boolean;
286286
disableBeforeUnloadHandlers?: boolean;
287287
disableCameraTintForeground?: boolean;
288+
disableChat?: boolean;
288289
disableChatSmileys?: boolean;
289290
disableDeepLinking?: boolean;
290291
disableFilmstripAutohiding?: boolean;

react/features/base/config/configWhitelist.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,7 @@ export default [
9494
'disableAudioLevels',
9595
'disableBeforeUnloadHandlers',
9696
'disableCameraTintForeground',
97+
'disableChat',
9798
'disableChatSmileys',
9899
'disableDeepLinking',
99100
'disabledNotifications',

react/features/chat/actions.any.ts

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -220,6 +220,34 @@ export function openCCPanel() {
220220
};
221221
}
222222

223+
/**
224+
* Opens the chat panel with polls tab active.
225+
*
226+
* @returns {Object} The redux action.
227+
*/
228+
export function openPollsPanel() {
229+
return async (dispatch: IStore['dispatch']) => {
230+
dispatch(setFocusedTab(ChatTabs.POLLS));
231+
dispatch({
232+
type: OPEN_CHAT
233+
});
234+
};
235+
}
236+
237+
/**
238+
* Opens the chat panel with file sharing tab active.
239+
*
240+
* @returns {Object} The redux action.
241+
*/
242+
export function openFileSharingPanel() {
243+
return async (dispatch: IStore['dispatch']) => {
244+
dispatch(setFocusedTab(ChatTabs.FILE_SHARING));
245+
dispatch({
246+
type: OPEN_CHAT
247+
});
248+
};
249+
}
250+
223251

224252
/**
225253
* Initiates the sending of messages between a moderator and a lobby attendee.
Lines changed: 15 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,30 +1,33 @@
1+
import { IStore } from '../app/types';
12
import { IParticipant } from '../base/participants/types';
23
import { navigate } from '../mobile/navigation/components/conference/ConferenceNavigationContainerRef';
34
import { screen } from '../mobile/navigation/routes';
45

56
import { OPEN_CHAT } from './actionTypes';
7+
import { setFocusedTab } from './actions.any';
8+
import { ChatTabs } from './constants';
69

710
export * from './actions.any';
811

912
/**
10-
* Displays the chat panel.
13+
* Displays the chat panel with the CHAT tab active.
1114
*
1215
* @param {Object} participant - The recipient for the private chat.
1316
* @param {boolean} disablePolls - Checks if polls are disabled.
1417
*
15-
* @returns {{
16-
* participant: participant,
17-
* type: OPEN_CHAT
18-
* }}
18+
* @returns {Function}
1919
*/
2020
export function openChat(participant?: IParticipant | undefined | Object, disablePolls?: boolean) {
21-
if (disablePolls) {
22-
navigate(screen.conference.chat);
23-
}
24-
navigate(screen.conference.chatandpolls.main);
21+
return (dispatch: IStore['dispatch']) => {
22+
if (disablePolls) {
23+
navigate(screen.conference.chat);
24+
}
25+
navigate(screen.conference.chatandpolls.main);
2526

26-
return {
27-
participant,
28-
type: OPEN_CHAT
27+
dispatch(setFocusedTab(ChatTabs.CHAT));
28+
dispatch({
29+
participant,
30+
type: OPEN_CHAT
31+
});
2932
};
3033
}

react/features/chat/actions.web.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,12 +8,13 @@ import {
88
SET_CHAT_WIDTH,
99
SET_USER_CHAT_WIDTH
1010
} from './actionTypes';
11-
import { closeChat } from './actions.any';
11+
import { closeChat, setFocusedTab } from './actions.any';
12+
import { ChatTabs } from './constants';
1213

1314
export * from './actions.any';
1415

1516
/**
16-
* Displays the chat panel.
17+
* Displays the chat panel with the CHAT tab active.
1718
*
1819
* @param {Object} participant - The recipient for the private chat.
1920
* @param {Object} _disablePolls - Used on native.
@@ -24,6 +25,7 @@ export * from './actions.any';
2425
*/
2526
export function openChat(participant?: Object, _disablePolls?: boolean) {
2627
return function(dispatch: IStore['dispatch']) {
28+
dispatch(setFocusedTab(ChatTabs.CHAT));
2729
dispatch({
2830
participant,
2931
type: OPEN_CHAT

react/features/chat/components/native/ChatButton.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ import { arePollsDisabled } from '../../../conference/functions.any';
1010
import { navigate } from '../../../mobile/navigation/components/conference/ConferenceNavigationContainerRef';
1111
import { screen } from '../../../mobile/navigation/routes';
1212
import { getUnreadPollCount } from '../../../polls/functions';
13-
import { getUnreadCount, getUnreadFilesCount } from '../../functions';
13+
import { getUnreadCount, getUnreadFilesCount, isChatDisabled } from '../../functions';
1414

1515
interface IProps extends AbstractButtonProps {
1616

@@ -65,7 +65,7 @@ class ChatButton extends AbstractButton<IProps> {
6565
* @returns {IProps}
6666
*/
6767
function _mapStateToProps(state: IReduxState, ownProps: any) {
68-
const enabled = getFeatureFlag(state, CHAT_ENABLED, true);
68+
const enabled = getFeatureFlag(state, CHAT_ENABLED, true) && !isChatDisabled(state);
6969
const { visible = enabled } = ownProps;
7070

7171
return {

react/features/chat/components/web/Chat.tsx

Lines changed: 32 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ import {
2424
toggleChat
2525
} from '../../actions.web';
2626
import { CHAT_SIZE, ChatTabs, OPTION_GROUPCHAT, SMALL_WIDTH_THRESHOLD } from '../../constants';
27-
import { getChatMaxSize } from '../../functions';
27+
import { getChatMaxSize, getFocusedTab, isChatDisabled } from '../../functions';
2828
import { IChatProps as AbstractProps } from '../../types';
2929

3030
import ChatHeader from './ChatHeader';
@@ -41,13 +41,18 @@ interface IProps extends AbstractProps {
4141
/**
4242
* The currently focused tab.
4343
*/
44-
_focusedTab: ChatTabs;
44+
_focusedTab?: ChatTabs;
4545

4646
/**
4747
* True if the CC tab is enabled and false otherwise.
4848
*/
4949
_isCCTabEnabled: boolean;
5050

51+
/**
52+
* True if chat is disabled.
53+
*/
54+
_isChatDisabled: boolean;
55+
5156
/**
5257
* True if file sharing tab is enabled.
5358
*/
@@ -217,6 +222,7 @@ const Chat = ({
217222
_isOpen,
218223
_isPollsEnabled,
219224
_isCCTabEnabled,
225+
_isChatDisabled,
220226
_isFileSharingTabEnabled,
221227
_focusedTab,
222228
_isResizing,
@@ -229,6 +235,11 @@ const Chat = ({
229235
dispatch,
230236
t
231237
}: IProps) => {
238+
// If no tabs are available, don't render the chat panel at all.
239+
if (_isChatDisabled && !_isPollsEnabled && !_isCCTabEnabled && !_isFileSharingTabEnabled) {
240+
return null;
241+
}
242+
232243
const { classes, cx } = useStyles({ _isResizing, width: _width });
233244
const [ isMouseDown, setIsMouseDown ] = useState(false);
234245
const [ mousePosition, setMousePosition ] = useState<number | null>(null);
@@ -416,7 +427,7 @@ const Chat = ({
416427
return (
417428
<>
418429
{renderTabs()}
419-
<div
430+
{!_isChatDisabled && (<div
420431
aria-labelledby = { ChatTabs.CHAT }
421432
className = { cx(
422433
classes.chatPanel,
@@ -442,7 +453,7 @@ const Chat = ({
442453
)}
443454
<ChatInput
444455
onSend = { onSendMessage } />
445-
</div>
456+
</div>) }
446457
{ _isPollsEnabled && (
447458
<>
448459
<div
@@ -484,17 +495,27 @@ const Chat = ({
484495
* @returns {ReactElement}
485496
*/
486497
function renderTabs() {
487-
let tabs = [
488-
{
498+
// The only way focused tab will be undefined is when no tab is enabled. Therefore this function won't be
499+
// executed because Chat component won't render anything. This should never happen but adding the check
500+
// here to make TS happy (when passing the _focusedTab in the selected prop for Tabs).
501+
if (!_focusedTab) {
502+
return null;
503+
}
504+
505+
let tabs = [];
506+
507+
// Only add chat tab if chat is not disabled.
508+
if (!_isChatDisabled) {
509+
tabs.push({
489510
accessibilityLabel: t('chat.tabs.chat'),
490511
countBadge:
491512
_focusedTab !== ChatTabs.CHAT && _unreadMessagesCount > 0 ? _unreadMessagesCount : undefined,
492513
id: ChatTabs.CHAT,
493514
controlsId: `${ChatTabs.CHAT}-panel`,
494515
icon: IconMessage,
495516
title: t('chat.tabs.chat')
496-
}
497-
];
517+
});
518+
}
498519

499520
if (_isPollsEnabled) {
500521
tabs.push({
@@ -602,7 +623,7 @@ const Chat = ({
602623
* }}
603624
*/
604625
function _mapStateToProps(state: IReduxState, _ownProps: any) {
605-
const { isOpen, focusedTab, messages, unreadMessagesCount, unreadFilesCount, width, isResizing } = state['features/chat'];
626+
const { isOpen, messages, unreadMessagesCount, unreadFilesCount, width, isResizing } = state['features/chat'];
606627
const { unreadPollsCount } = state['features/polls'];
607628
const _localParticipant = getLocalParticipant(state);
608629

@@ -611,8 +632,9 @@ function _mapStateToProps(state: IReduxState, _ownProps: any) {
611632
_isOpen: isOpen,
612633
_isPollsEnabled: !arePollsDisabled(state),
613634
_isCCTabEnabled: isCCTabEnabled(state),
635+
_isChatDisabled: isChatDisabled(state),
614636
_isFileSharingTabEnabled: isFileSharingEnabled(state),
615-
_focusedTab: focusedTab,
637+
_focusedTab: getFocusedTab(state),
616638
_messages: messages,
617639
_unreadMessagesCount: unreadMessagesCount,
618640
_unreadPollsCount: unreadPollsCount,

react/features/chat/components/web/ChatButton.tsx

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import { IconMessage } from '../../../base/icons/svg';
99
import AbstractButton, { IProps as AbstractButtonProps } from '../../../base/toolbox/components/AbstractButton';
1010
import { closeOverflowMenuIfOpen } from '../../../toolbox/actions.web';
1111
import { toggleChat } from '../../actions.web';
12+
import { isChatDisabled } from '../../functions';
1213

1314
import ChatCounter from './ChatCounter';
1415

@@ -91,7 +92,8 @@ class ChatButton extends AbstractButton<IProps> {
9192
*/
9293
const mapStateToProps = (state: IReduxState) => {
9394
return {
94-
_chatOpen: state['features/chat'].isOpen
95+
_chatOpen: state['features/chat'].isOpen,
96+
visible: !isChatDisabled(state)
9597
};
9698
};
9799

0 commit comments

Comments
 (0)