diff --git a/lang/main.json b/lang/main.json index 8eac4ee7ee..7a0b006704 100644 --- a/lang/main.json +++ b/lang/main.json @@ -67,7 +67,8 @@ "renameBreakoutRoom": "Rename breakout room", "sendToBreakoutRoom": "Send participant to:" }, - "breakoutList": "breakout list", + "breakoutList": "Breakout list", + "buttonLabel": "Breakout rooms", "defaultName": "Breakout room #{{index}}", "hideParticipantList": "Hide participant list", "mainRoom": "Main room", @@ -76,7 +77,8 @@ "joinedMainRoom": "Joining the main room", "joinedTitle": "Breakout Rooms" }, - "showParticipantList": "Show participant list" + "showParticipantList": "Show participant list", + "title": "Breakout Rooms" }, "calendarSync": { "addMeetingURL": "Add a meeting link", @@ -811,6 +813,7 @@ "askUnmute": "Ask to unmute", "audioModeration": "Unmute themselves", "blockEveryoneMicCamera": "Block everyone's mic and camera", + "breakoutRooms": "Breakout rooms", "invite": "Invite Someone", "moreModerationActions": "More moderation options", "moreModerationControls": "More moderation controls", @@ -1157,7 +1160,7 @@ "audioOnly": "Toggle audio only", "audioRoute": "Select the sound device", "boo": "Boo", - "breakoutRoom": "Join/leave breakout room", + "breakoutRooms": "Breakout rooms", "callQuality": "Manage video quality", "carmode": "Car Mode", "cc": "Toggle subtitles", diff --git a/react/features/base/flags/constants.ts b/react/features/base/flags/constants.ts index 38b8293328..17673e1681 100644 --- a/react/features/base/flags/constants.ts +++ b/react/features/base/flags/constants.ts @@ -23,6 +23,12 @@ export const AUDIO_MUTE_BUTTON_ENABLED = 'audio-mute.enabled'; */ export const AUDIO_ONLY_BUTTON_ENABLED = 'audio-only.enabled'; +/** + * Flag indicating that the Breakout Rooms button in the overflow menu is enabled. + * Default: enabled (true). + */ +export const BREAKOUT_ROOMS_BUTTON_ENABLED = 'breakout-rooms.enabled'; + /** * Flag indicating if calendar integration should be enabled. * Default: enabled (true) on Android, auto-detected on iOS. diff --git a/react/features/participants-pane/components/breakout-rooms/components/native/AddBreakoutRoomButton.tsx b/react/features/breakout-rooms/components/native/AddBreakoutRoomButton.tsx similarity index 76% rename from react/features/participants-pane/components/breakout-rooms/components/native/AddBreakoutRoomButton.tsx rename to react/features/breakout-rooms/components/native/AddBreakoutRoomButton.tsx index c60930ed38..4a3b522a2c 100644 --- a/react/features/participants-pane/components/breakout-rooms/components/native/AddBreakoutRoomButton.tsx +++ b/react/features/breakout-rooms/components/native/AddBreakoutRoomButton.tsx @@ -1,9 +1,9 @@ import React, { useCallback } from 'react'; import { useDispatch } from 'react-redux'; -import Button from '../../../../../base/ui/components/native/Button'; -import { BUTTON_TYPES } from '../../../../../base/ui/constants.native'; -import { createBreakoutRoom } from '../../../../../breakout-rooms/actions'; +import Button from '../../../base/ui/components/native/Button'; +import { BUTTON_TYPES } from '../../../base/ui/constants.native'; +import { createBreakoutRoom } from '../../actions'; import styles from './styles'; diff --git a/react/features/participants-pane/components/breakout-rooms/components/native/AutoAssignButton.tsx b/react/features/breakout-rooms/components/native/AutoAssignButton.tsx similarity index 78% rename from react/features/participants-pane/components/breakout-rooms/components/native/AutoAssignButton.tsx rename to react/features/breakout-rooms/components/native/AutoAssignButton.tsx index 12be92ed0d..085446a447 100644 --- a/react/features/participants-pane/components/breakout-rooms/components/native/AutoAssignButton.tsx +++ b/react/features/breakout-rooms/components/native/AutoAssignButton.tsx @@ -1,9 +1,9 @@ import React, { useCallback } from 'react'; import { useDispatch } from 'react-redux'; -import Button from '../../../../../base/ui/components/native/Button'; -import { BUTTON_TYPES } from '../../../../../base/ui/constants.native'; -import { autoAssignToBreakoutRooms } from '../../../../../breakout-rooms/actions'; +import Button from '../../../base/ui/components/native/Button'; +import { BUTTON_TYPES } from '../../../base/ui/constants.native'; +import { autoAssignToBreakoutRooms } from '../../actions'; import styles from './styles'; diff --git a/react/features/participants-pane/components/breakout-rooms/components/native/BreakoutRoomContextMenu.tsx b/react/features/breakout-rooms/components/native/BreakoutRoomContextMenu.tsx similarity index 80% rename from react/features/participants-pane/components/breakout-rooms/components/native/BreakoutRoomContextMenu.tsx rename to react/features/breakout-rooms/components/native/BreakoutRoomContextMenu.tsx index 06b624951c..47994b1cd3 100644 --- a/react/features/participants-pane/components/breakout-rooms/components/native/BreakoutRoomContextMenu.tsx +++ b/react/features/breakout-rooms/components/native/BreakoutRoomContextMenu.tsx @@ -4,22 +4,23 @@ import { TouchableOpacity, ViewStyle } from 'react-native'; import { Text } from 'react-native-paper'; import { useDispatch, useSelector } from 'react-redux'; -import { createBreakoutRoomsEvent } from '../../../../../analytics/AnalyticsEvents'; -import { sendAnalytics } from '../../../../../analytics/functions'; -import { hideSheet, openDialog } from '../../../../../base/dialog/actions'; -import BottomSheet from '../../../../../base/dialog/components/native/BottomSheet'; -import Icon from '../../../../../base/icons/components/Icon'; -import { IconCloseLarge, IconEdit, IconRingGroup } from '../../../../../base/icons/svg'; -import { isLocalParticipantModerator } from '../../../../../base/participants/functions'; -import { closeBreakoutRoom, moveToRoom, removeBreakoutRoom } from '../../../../../breakout-rooms/actions'; -import { getBreakoutRoomsConfig } from '../../../../../breakout-rooms/functions'; -import { IRoom } from '../../../../../breakout-rooms/types'; -import { isBreakoutRoomRenameAllowed } from '../../../../functions'; -import { BREAKOUT_CONTEXT_MENU_ACTIONS as ACTIONS } from '../../../../types'; -import styles from '../../../native/styles'; +import { createBreakoutRoomsEvent } from '../../../analytics/AnalyticsEvents'; +import { sendAnalytics } from '../../../analytics/functions'; +import { hideSheet, openDialog } from '../../../base/dialog/actions'; +import BottomSheet from '../../../base/dialog/components/native/BottomSheet'; +import Icon from '../../../base/icons/components/Icon'; +import { IconCloseLarge, IconEdit, IconRingGroup } from '../../../base/icons/svg'; +import { isLocalParticipantModerator } from '../../../base/participants/functions'; +import styles from '../../../participants-pane/components/native/styles'; +import { isBreakoutRoomRenameAllowed } from '../../../participants-pane/functions'; +import { BREAKOUT_CONTEXT_MENU_ACTIONS as ACTIONS } from '../../../participants-pane/types'; +import { closeBreakoutRoom, moveToRoom, removeBreakoutRoom } from '../../actions'; +import { getBreakoutRoomsConfig } from '../../functions'; +import { IRoom } from '../../types'; import BreakoutRoomNamePrompt from './BreakoutRoomNamePrompt'; + /** * An array with all possible breakout rooms actions. */ @@ -85,7 +86,8 @@ const BreakoutRoomContextMenu = ({ room, actions = ALL_ACTIONS }: IProps) => { ) } - {!room?.isMainRoom && actions.includes(ACTIONS.RENAME) && _isBreakoutRoomRenameAllowed + { + !room?.isMainRoom && actions.includes(ACTIONS.RENAME) && _isBreakoutRoomRenameAllowed && @@ -95,7 +97,8 @@ const BreakoutRoomContextMenu = ({ room, actions = ALL_ACTIONS }: IProps) => { {t('breakoutRooms.actions.rename')} } - {!room?.isMainRoom && isLocalModerator && actions.includes(ACTIONS.REMOVE) + { + !room?.isMainRoom && isLocalModerator && actions.includes(ACTIONS.REMOVE) && (room?.participants && Object.keys(room.participants).length > 0 ? { + const currentRoomId = useSelector(getCurrentRoomId); + const inBreakoutRoom = useSelector(isInBreakoutRoom); + const isBreakoutRoomsSupported = useSelector((state: IReduxState) => + state['features/base/conference'].conference?.getBreakoutRooms()?.isSupported()); + const isLocalModerator = useSelector(isLocalParticipantModerator); + const keyExtractor = useCallback((e: undefined, i: number) => i.toString(), []); + const rooms = Object.values(useSelector(getBreakoutRooms, equals)) + .filter(room => room.id !== currentRoomId) + .sort((p1, p2) => (p1?.name || '').localeCompare(p2?.name || '')); + const showAddBreakoutRoom = useSelector(isAddBreakoutRoomButtonVisible); + const showAutoAssign = useSelector(isAutoAssignParticipantsVisible); + + return ( + + + { /* Fixes warning regarding nested lists */ } + ( + <> + { showAutoAssign && } + { inBreakoutRoom && } + { + isBreakoutRoomsSupported + && rooms.map(room => ()) + } + + ) } + data = { [] as ReadonlyArray } + keyExtractor = { keyExtractor } + renderItem = { null } + windowSize = { 2 } /> + + ); +}; + +export default BreakoutRooms; diff --git a/react/features/breakout-rooms/components/native/BreakoutRoomsButton.tsx b/react/features/breakout-rooms/components/native/BreakoutRoomsButton.tsx new file mode 100644 index 0000000000..54363c56ce --- /dev/null +++ b/react/features/breakout-rooms/components/native/BreakoutRoomsButton.tsx @@ -0,0 +1,53 @@ +import { connect } from 'react-redux'; + +import { IReduxState } from '../../../app/types'; +import { + BREAKOUT_ROOMS_BUTTON_ENABLED +} from '../../../base/flags/constants'; +import { getFeatureFlag } from '../../../base/flags/functions'; +import { translate } from '../../../base/i18n/functions'; +import { IconRingGroup } from '../../../base/icons/svg'; +import AbstractButton, +{ + IProps as AbstractButtonProps +} from '../../../base/toolbox/components/AbstractButton'; +import { + navigate +} from '../../../mobile/navigation/components/conference/ConferenceNavigationContainerRef'; +import { screen } from '../../../mobile/navigation/routes'; + + +/** + * Implements an {@link AbstractButton} to open the breakout room screen. + */ +class BreakoutRoomsButton extends AbstractButton { + accessibilityLabel = 'toolbar.accessibilityLabel.breakoutRooms'; + icon = IconRingGroup; + label = 'breakoutRooms.buttonLabel'; + + /** + * Handles clicking / pressing the button and opens the breakout rooms screen. + * + * @private + * @returns {void} + */ + _handleClick() { + return navigate(screen.conference.breakoutRooms); + } +} + +/** + * Maps part of the redux state to the component's props. + * + * @param {IReduxState} state - The Redux state. + * @returns {Object} + */ +function _mapStateToProps(state: IReduxState) { + const enabled = getFeatureFlag(state, BREAKOUT_ROOMS_BUTTON_ENABLED, true); + + return { + visible: enabled + }; +} + +export default translate(connect(_mapStateToProps)(BreakoutRoomsButton)); diff --git a/react/features/participants-pane/components/breakout-rooms/components/native/CollapsibleRoom.tsx b/react/features/breakout-rooms/components/native/CollapsibleRoom.tsx similarity index 58% rename from react/features/participants-pane/components/breakout-rooms/components/native/CollapsibleRoom.tsx rename to react/features/breakout-rooms/components/native/CollapsibleRoom.tsx index f71f787b9f..d379ab4406 100644 --- a/react/features/participants-pane/components/breakout-rooms/components/native/CollapsibleRoom.tsx +++ b/react/features/breakout-rooms/components/native/CollapsibleRoom.tsx @@ -3,11 +3,9 @@ import { useTranslation } from 'react-i18next'; import { FlatList } from 'react-native'; import { useDispatch } from 'react-redux'; -import { openSheet } from '../../../../../base/dialog/actions'; -import { IRoom } from '../../../../../breakout-rooms/types'; -import { participantMatchesSearch } from '../../../../functions'; -import CollapsibleList from '../../../native/CollapsibleList'; -import styles from '../../../native/styles'; +import { openSheet } from '../../../base/dialog/actions'; +import CollapsibleList from '../../../participants-pane/components/native/CollapsibleList'; +import { IRoom } from '../../types'; import BreakoutRoomContextMenu from './BreakoutRoomContextMenu'; import BreakoutRoomParticipantItem from './BreakoutRoomParticipantItem'; @@ -19,10 +17,7 @@ interface IProps { */ room: IRoom; - /** - * Participants search string. - */ - searchString: string; + roomId: string; } /** @@ -35,7 +30,7 @@ function _keyExtractor(item: any) { return item.jid; } -export const CollapsibleRoom = ({ room, searchString }: IProps) => { +export const CollapsibleRoom = ({ room, roomId }: IProps) => { const dispatch = useDispatch(); const { t } = useTranslation(); const _openContextMenu = useCallback(() => { @@ -46,29 +41,22 @@ export const CollapsibleRoom = ({ room, searchString }: IProps) => { = `${room.name || t('breakoutRooms.mainRoom')} (${roomParticipantsNr})`; - // Regarding the fact that we have 3 sections, we apply - // a certain height percentage for every section in order for all to fit - // inside the participants pane container - const containerStyle - = roomParticipantsNr > 2 ? styles.collapsibleRoomContainer : undefined; - return ( participantMatchesSearch(participant, searchString) - ? ( + - : null } - scrollEnabled = { true } + ) } + scrollEnabled = { false } showsHorizontalScrollIndicator = { false } windowSize = { 2 } /> diff --git a/react/features/participants-pane/components/breakout-rooms/components/native/LeaveBreakoutRoomButton.tsx b/react/features/breakout-rooms/components/native/LeaveBreakoutRoomButton.tsx similarity index 68% rename from react/features/participants-pane/components/breakout-rooms/components/native/LeaveBreakoutRoomButton.tsx rename to react/features/breakout-rooms/components/native/LeaveBreakoutRoomButton.tsx index 0dc5eb09b3..f82472d0ba 100644 --- a/react/features/participants-pane/components/breakout-rooms/components/native/LeaveBreakoutRoomButton.tsx +++ b/react/features/breakout-rooms/components/native/LeaveBreakoutRoomButton.tsx @@ -1,11 +1,11 @@ import React, { useCallback } from 'react'; import { useDispatch } from 'react-redux'; -import { createBreakoutRoomsEvent } from '../../../../../analytics/AnalyticsEvents'; -import { sendAnalytics } from '../../../../../analytics/functions'; -import Button from '../../../../../base/ui/components/native/Button'; -import { BUTTON_TYPES } from '../../../../../base/ui/constants.native'; -import { moveToRoom } from '../../../../../breakout-rooms/actions'; +import { createBreakoutRoomsEvent } from '../../../analytics/AnalyticsEvents'; +import { sendAnalytics } from '../../../analytics/functions'; +import Button from '../../../base/ui/components/native/Button'; +import { BUTTON_TYPES } from '../../../base/ui/constants.native'; +import { moveToRoom } from '../../actions'; import styles from './styles'; diff --git a/react/features/participants-pane/components/breakout-rooms/components/native/styles.ts b/react/features/breakout-rooms/components/native/styles.ts similarity index 63% rename from react/features/participants-pane/components/breakout-rooms/components/native/styles.ts rename to react/features/breakout-rooms/components/native/styles.ts index c38802bc51..250c5147f4 100644 --- a/react/features/participants-pane/components/breakout-rooms/components/native/styles.ts +++ b/react/features/breakout-rooms/components/native/styles.ts @@ -1,12 +1,5 @@ -import BaseTheme from '../../../../../base/ui/components/BaseTheme.native'; +import BaseTheme from '../../../base/ui/components/BaseTheme.native'; -const baseButton = { - borderRadius: BaseTheme.shape.borderRadius, - height: BaseTheme.spacing[7], - marginTop: BaseTheme.spacing[3], - marginLeft: BaseTheme.spacing[3], - marginRight: BaseTheme.spacing[3] -}; /** * The styles of the native components of the feature {@code breakout rooms}. @@ -14,16 +7,8 @@ const baseButton = { export default { button: { - marginTop: BaseTheme.spacing[3], - marginLeft: BaseTheme.spacing[3], - marginRight: BaseTheme.spacing[3] - }, - - collapsibleRoom: { - ...baseButton, - display: 'flex', - flexDirection: 'row', - alignItems: 'center' + marginBottom: BaseTheme.spacing[4], + marginHorizontal: BaseTheme.spacing[2] }, collapsibleList: { @@ -32,7 +17,7 @@ export default { display: 'flex', flexDirection: 'row', height: BaseTheme.spacing[7], - marginHorizontal: BaseTheme.spacing[3], + marginHorizontal: BaseTheme.spacing[2], marginTop: BaseTheme.spacing[3] }, @@ -68,5 +53,24 @@ export default { alignSelf: 'center', justifyContent: 'center', marginTop: BaseTheme.spacing[3] + }, + + breakoutRoomsContainer: { + backgroundColor: BaseTheme.palette.ui01, + flex: 1, + flexDirection: 'column', + height: 'auto', + paddingHorizontal: BaseTheme.spacing[3] + }, + + inputContainer: { + marginLeft: BaseTheme.spacing[2], + marginRight: BaseTheme.spacing[2], + marginTop: BaseTheme.spacing[4] + }, + + centerInput: { + paddingRight: BaseTheme.spacing[3], + textAlign: 'center' } }; diff --git a/react/features/mobile/navigation/components/conference/components/ConferenceNavigationContainer.tsx b/react/features/mobile/navigation/components/conference/components/ConferenceNavigationContainer.tsx index 3711f49b7b..7c27edbf74 100644 --- a/react/features/mobile/navigation/components/conference/components/ConferenceNavigationContainer.tsx +++ b/react/features/mobile/navigation/components/conference/components/ConferenceNavigationContainer.tsx @@ -6,6 +6,9 @@ import React from 'react'; import { useTranslation } from 'react-i18next'; import { useSelector } from 'react-redux'; +import BreakoutRooms +// @ts-ignore + from '../../../../../breakout-rooms/components/native/BreakoutRooms'; // @ts-ignore import Chat from '../../../../../chat/components/native/Chat'; // @ts-ignore @@ -43,6 +46,7 @@ import LanguageSelectorDialog // @ts-ignore import { screen } from '../../../routes'; import { + breakoutRoomsScreenOptions, carmodeScreenOptions, chatScreenOptions, conferenceScreenOptions, @@ -72,6 +76,7 @@ import { // @ts-ignore } from '../ConferenceNavigationContainerRef'; + const ConferenceStack = createStackNavigator(); @@ -202,6 +207,13 @@ const ConferenceNavigationContainer = () => { ...subtitlesScreenOptions, title: t('transcribing.subtitles') }} /> + ); diff --git a/react/features/mobile/navigation/routes.ts b/react/features/mobile/navigation/routes.ts index 09f37c4c06..62315e4cfa 100644 --- a/react/features/mobile/navigation/routes.ts +++ b/react/features/mobile/navigation/routes.ts @@ -1,17 +1,6 @@ export const screen = { - welcome: { - main: 'Welcome', - tabs: { - recent: 'Recent', - calendar: 'Calendar' - } - }, - dialInSummary: 'Dial-In Info', - connecting: 'Connecting', - preJoin: 'Pre-Join', conference: { - root: 'Conference root', - main: 'Conference', + breakoutRooms: 'Breakout Rooms', carmode: 'Car Mode', chat: 'Chat', chatandpolls: { @@ -22,31 +11,43 @@ export const screen = { } }, container: 'Conference container', - security: 'Security Options', - recording: 'Recording', - liveStream: 'Live stream', - speakerStats: 'Speaker Stats', - salesforce: 'Link to Salesforce', - participants: 'Participants', gifsMenu: 'GIPHY', invite: 'Invite', + liveStream: 'Live stream', + main: 'Conference', + participants: 'Participants', + root: 'Conference root', + recording: 'Recording', + salesforce: 'Link to Salesforce', + security: 'Security Options', sharedDocument: 'Shared document', + speakerStats: 'Speaker Stats', subtitles: 'Subtitles' }, + connecting: 'Connecting', + dialInSummary: 'Dial-In Info', + preJoin: 'Pre-Join', lobby: { - root: 'Lobby root', + chat: 'Lobby chat', main: 'Lobby', - chat: 'Lobby chat' + root: 'Lobby root' }, settings: { - main: 'Settings', + language: 'Language', links: { help: 'Help', privacy: 'Privacy', terms: 'Terms' }, - profile: 'Profile', - language: 'Language' + main: 'Settings', + profile: 'Profile' }, - unsafeRoomWarning: 'Unsafe Room Warning' + unsafeRoomWarning: 'Unsafe Room Warning', + welcome: { + main: 'Welcome', + tabs: { + calendar: 'Calendar', + recent: 'Recent' + } + } }; diff --git a/react/features/mobile/navigation/screenOptions.ts b/react/features/mobile/navigation/screenOptions.ts index 0136c30746..326d4d4df9 100644 --- a/react/features/mobile/navigation/screenOptions.ts +++ b/react/features/mobile/navigation/screenOptions.ts @@ -86,6 +86,11 @@ export const presentationScreenOptions = { } }; +/** + * Screen options for breakout rooms screen. + */ +export const breakoutRoomsScreenOptions = presentationScreenOptions; + /** * Screen options for car mode. */ @@ -109,6 +114,11 @@ export const dialInSummaryScreenOptions = { */ export const inviteScreenOptions = presentationScreenOptions; +/** + * Screen options for live stream modal. + */ +export const liveStreamScreenOptions = presentationScreenOptions; + /** * Screen options for participants modal. */ @@ -129,11 +139,6 @@ export const securityScreenOptions = presentationScreenOptions; */ export const recordingScreenOptions = presentationScreenOptions; -/** - * Screen options for live stream modal. - */ -export const liveStreamScreenOptions = presentationScreenOptions; - /** * Screen options for subtitles modal. */ diff --git a/react/features/participants-pane/components/native/CollapsibleList.tsx b/react/features/participants-pane/components/native/CollapsibleList.tsx index 83d1a204b8..e0adf3f180 100644 --- a/react/features/participants-pane/components/native/CollapsibleList.tsx +++ b/react/features/participants-pane/components/native/CollapsibleList.tsx @@ -3,8 +3,7 @@ import { GestureResponderEvent, Text, TextStyle, TouchableOpacity, View, ViewSty import Icon from '../../../base/icons/components/Icon'; import { IconArrowDown, IconArrowUp } from '../../../base/icons/svg'; -import { StyleType } from '../../../base/styles/functions.native'; -import styles from '../breakout-rooms/components/native/styles'; +import styles from '../../../breakout-rooms/components/native/styles'; interface IProps { @@ -13,11 +12,6 @@ interface IProps { */ children: React.ReactNode; - /** - * Additional style to be appended to the CollapsibleList container. - */ - containerStyle?: StyleType; - /** * Callback to invoke when the {@code CollapsibleList} is long pressed. */ @@ -29,14 +23,14 @@ interface IProps { title: Object; } -const CollapsibleList = ({ children, containerStyle, onLongPress, title }: IProps) => { +const CollapsibleList = ({ children, onLongPress, title }: IProps) => { const [ collapsed, setCollapsed ] = useState(false); const _toggleCollapsed = useCallback(() => { setCollapsed(!collapsed); }, [ collapsed ]); return ( - + - { - title - } + { title } - { - !collapsed && children - } + { !collapsed && children } ); }; diff --git a/react/features/participants-pane/components/native/LobbyParticipantList.tsx b/react/features/participants-pane/components/native/LobbyParticipantList.tsx index d7a1be5a1c..6d2c32a875 100644 --- a/react/features/participants-pane/components/native/LobbyParticipantList.tsx +++ b/react/features/participants-pane/components/native/LobbyParticipantList.tsx @@ -1,70 +1,56 @@ import React, { useCallback } from 'react'; import { useTranslation } from 'react-i18next'; -import { ScrollView, Text, TextStyle, View, ViewStyle } from 'react-native'; +import { Text, TextStyle, View, ViewStyle } from 'react-native'; import { useDispatch, useSelector } from 'react-redux'; import Button from '../../../base/ui/components/native/Button'; -import { BUTTON_TYPES } from '../../../base/ui/constants.native'; +import { BUTTON_MODES, BUTTON_TYPES } from '../../../base/ui/constants.native'; import { admitMultiple } from '../../../lobby/actions.native'; import { getKnockingParticipants, getLobbyEnabled } from '../../../lobby/functions'; -import CollapsibleList from './CollapsibleList'; import { LobbyParticipantItem } from './LobbyParticipantItem'; import styles from './styles'; const LobbyParticipantList = () => { + const dispatch = useDispatch(); const lobbyEnabled = useSelector(getLobbyEnabled); const participants = useSelector(getKnockingParticipants); - - const dispatch = useDispatch(); const admitAll = useCallback(() => dispatch(admitMultiple(participants)), [ dispatch, participants ]); const { t } = useTranslation(); + const title = t('participantsPane.headings.waitingLobby', + { count: participants.length }); if (!lobbyEnabled || !participants.length) { return null; } - const title = ( - - - { t('participantsPane.headings.waitingLobby', - { count: participants.length }) } - - { - participants.length > 1 && ( -