diff --git a/apps/100ms-custom-app/package.json b/apps/100ms-custom-app/package.json index 4c91da56b0..8adce0b174 100644 --- a/apps/100ms-custom-app/package.json +++ b/apps/100ms-custom-app/package.json @@ -3,8 +3,8 @@ "version": "0.1.0", "private": true, "dependencies": { - "@100mslive/react-icons": "0.8.22", - "@100mslive/roomkit-react": "0.1.13", + "@100mslive/react-icons": "0.8.23", + "@100mslive/roomkit-react": "0.1.14", "axios": "^0.21.1", "js-cookies": "^1.0.4", "lodash.merge": "^4.6.2", diff --git a/apps/100ms-web/package.json b/apps/100ms-web/package.json index fd0c057a12..97022cd055 100644 --- a/apps/100ms-web/package.json +++ b/apps/100ms-web/package.json @@ -9,11 +9,11 @@ "src" ], "dependencies": { - "@100mslive/hls-player": "0.1.22", - "@100mslive/hms-virtual-background": "1.11.22", - "@100mslive/react-icons": "0.8.22", - "@100mslive/react-sdk": "0.8.22", - "@100mslive/roomkit-react": "0.1.13", + "@100mslive/hls-player": "0.1.23", + "@100mslive/hms-virtual-background": "1.11.23", + "@100mslive/react-icons": "0.8.23", + "@100mslive/react-sdk": "0.8.23", + "@100mslive/roomkit-react": "0.1.14", "@emoji-mart/data": "^1.0.6", "@emoji-mart/react": "^1.0.1", "@tldraw/tldraw": "^1.18.4", diff --git a/package.json b/package.json index 5a77d73e49..0f4bfd348e 100644 --- a/package.json +++ b/package.json @@ -62,7 +62,7 @@ "controller": "cd packages/hls-controller && yarn start", "storybook": "cd packages/roomkit-react && yarn storybook", "build-storybook": "cd packages/roomkit-react && yarn build-storybook", - "ybys": "yarn && yarn build && yarn storybook" + "ybys": "yarn && yarn build --no-private && yarn storybook" }, "resolutions": { "loader-utils": "^2.0.4" diff --git a/packages/hls-player/package.json b/packages/hls-player/package.json index bedadb737f..d2d77f12c8 100644 --- a/packages/hls-player/package.json +++ b/packages/hls-player/package.json @@ -1,6 +1,6 @@ { "name": "@100mslive/hls-player", - "version": "0.1.22", + "version": "0.1.23", "description": "HLS client library which uses HTML5 Video element and Media Source Extension for playback", "main": "dist/index.cjs.js", "module": "dist/index.js", @@ -31,7 +31,7 @@ "author": "100ms", "license": "MIT", "dependencies": { - "@100mslive/hls-stats": "0.2.22", + "@100mslive/hls-stats": "0.2.23", "eventemitter2": "^6.4.7", "hls.js": "1.4.12" } diff --git a/packages/hls-stats/package.json b/packages/hls-stats/package.json index 9bd77801e5..b7b731afed 100644 --- a/packages/hls-stats/package.json +++ b/packages/hls-stats/package.json @@ -1,6 +1,6 @@ { "name": "@100mslive/hls-stats", - "version": "0.2.22", + "version": "0.2.23", "description": "A simple library that provides stats for your hls stream", "main": "dist/index.cjs.js", "module": "dist/index.js", diff --git a/packages/hms-noise-suppression/package.json b/packages/hms-noise-suppression/package.json index fee8f8781e..7c2002b128 100644 --- a/packages/hms-noise-suppression/package.json +++ b/packages/hms-noise-suppression/package.json @@ -1,5 +1,5 @@ { - "version": "0.9.22", + "version": "0.9.23", "license": "MIT", "main": "dist/index.cjs.js", "typings": "dist/index.d.ts", @@ -37,6 +37,6 @@ "author": "vishaldhull09", "module": "dist/index.js", "devDependencies": { - "@100mslive/hms-video": "0.9.22" + "@100mslive/hms-video": "0.9.23" } } diff --git a/packages/hms-video-store/package.json b/packages/hms-video-store/package.json index 12572d4d0c..2c046dd376 100644 --- a/packages/hms-video-store/package.json +++ b/packages/hms-video-store/package.json @@ -1,5 +1,5 @@ { - "version": "0.10.22", + "version": "0.10.23", "license": "MIT", "main": "dist/index.cjs.js", "module": "dist/index.js", @@ -41,7 +41,7 @@ "author": "100ms", "sideEffects": false, "dependencies": { - "@100mslive/hms-video": "0.9.22", + "@100mslive/hms-video": "0.9.23", "eventemitter2": "^6.4.7", "immer": "^9.0.6", "reselect": "4.0.0", diff --git a/packages/hms-video-store/src/core/IHMSActions.ts b/packages/hms-video-store/src/core/IHMSActions.ts index f0a829d71a..f806f72c94 100644 --- a/packages/hms-video-store/src/core/IHMSActions.ts +++ b/packages/hms-video-store/src/core/IHMSActions.ts @@ -5,6 +5,7 @@ import { HMSConfig, HMSLogLevel, HMSMidCallPreviewConfig, + HMSPlaylistSettings, HMSPluginSupportResult, HMSPreferredSimulcastLayer, HMSPreviewConfig, @@ -514,4 +515,9 @@ export interface IHMSActions; getPeerListIterator(options?: HMSPeerListIteratorOptions): HMSPeerListIterator; + /** + * Method to override the default settings for playlist tracks + * @param {HMSPlaylistSettings} settings + */ + setPlaylistSettings(settings: HMSPlaylistSettings): void; } diff --git a/packages/hms-video-store/src/core/hmsSDKStore/HMSSDKActions.ts b/packages/hms-video-store/src/core/hmsSDKStore/HMSSDKActions.ts index 5f786bc455..014e22af95 100644 --- a/packages/hms-video-store/src/core/hmsSDKStore/HMSSDKActions.ts +++ b/packages/hms-video-store/src/core/hmsSDKStore/HMSSDKActions.ts @@ -134,6 +134,9 @@ export class HMSSDKActions !m.recipientPeer && !(m.recipientRoles && m.recipientRoles?.length > 0)); }); /** - * Select the nuber of unread broadcast messages + * Select the number of unread broadcast messages */ export const selectUnreadHMSBroadcastMessagesCount = createSelector(selectHMSBroadcastMessages, messages => { return messages.filter(m => !m.read).length; diff --git a/packages/hms-video-web/package.json b/packages/hms-video-web/package.json index 7b3f312e30..99dfe3b720 100644 --- a/packages/hms-video-web/package.json +++ b/packages/hms-video-web/package.json @@ -1,6 +1,6 @@ { "name": "@100mslive/hms-video", - "version": "0.9.22", + "version": "0.9.23", "license": "MIT", "main": "dist/index.cjs.js", "typings": "dist/index.d.ts", diff --git a/packages/hms-video-web/src/interfaces/hms.ts b/packages/hms-video-web/src/interfaces/hms.ts index 709d8a11a6..11e4003379 100644 --- a/packages/hms-video-web/src/interfaces/hms.ts +++ b/packages/hms-video-web/src/interfaces/hms.ts @@ -6,7 +6,7 @@ import { HLSConfig } from './hls-config'; import { HMSMessage } from './message'; import { HMSLocalPeer, HMSPeer } from './peer'; import { HMSPeerListIteratorOptions } from './peer-list-iterator'; -import { HMSPlaylistManager } from './playlist'; +import { HMSPlaylistManager, HMSPlaylistSettings } from './playlist'; import { HMSPreviewListener } from './preview-listener'; import { HMSRole } from './role'; import { HMSRoleChangeRequest } from './role-change-request'; @@ -99,4 +99,6 @@ export interface HMSInterface { lowerRemotePeerHand(peerId: string): Promise; getPeerListIterator(options?: HMSPeerListIteratorOptions): HMSPeerListIterator; + + updatePlaylistSettings(options: HMSPlaylistSettings): void; } diff --git a/packages/hms-video-web/src/interfaces/playlist.ts b/packages/hms-video-web/src/interfaces/playlist.ts index 0e65d13b81..c3bc82b5c8 100644 --- a/packages/hms-video-web/src/interfaces/playlist.ts +++ b/packages/hms-video-web/src/interfaces/playlist.ts @@ -105,3 +105,12 @@ export interface HMSPlaylistManager { */ setPlaybackRate(type: HMSPlaylistType, value: number): void; } + +export interface HMSPlaylistSettings { + video: { + bitrate: number; + }; + audio: { + bitrate: number; + }; +} diff --git a/packages/hms-video-web/src/sdk/index.ts b/packages/hms-video-web/src/sdk/index.ts index 9a35295e23..135b0d270a 100644 --- a/packages/hms-video-web/src/sdk/index.ts +++ b/packages/hms-video-web/src/sdk/index.ts @@ -28,6 +28,7 @@ import { HMSDeviceChangeEvent, HMSFrameworkInfo, HMSMessageInput, + HMSPlaylistSettings, HMSPlaylistType, HMSPreviewConfig, HMSRole, @@ -65,7 +66,11 @@ import { InitConfig } from '../signal/init/models'; import HMSTransport from '../transport'; import ITransportObserver from '../transport/ITransportObserver'; import { TransportState } from '../transport/models/TransportState'; -import { HAND_RAISE_GROUP_NAME } from '../utils/constants'; +import { + DEFAULT_PLAYLIST_AUDIO_BITRATE, + DEFAULT_PLAYLIST_VIDEO_BITRATE, + HAND_RAISE_GROUP_NAME, +} from '../utils/constants'; import { fetchWithRetry } from '../utils/fetch'; import decodeJWT from '../utils/jwt'; import HMSLogger, { HMSLogLevel } from '../utils/logger'; @@ -109,6 +114,14 @@ export class HMSSdk implements HMSInterface { private interactivityCenter!: InteractivityCenter; private sdkState = { ...INITIAL_STATE }; private frameworkInfo?: HMSFrameworkInfo; + private playlistSettings: HMSPlaylistSettings = { + video: { + bitrate: DEFAULT_PLAYLIST_VIDEO_BITRATE, + }, + audio: { + bitrate: DEFAULT_PLAYLIST_AUDIO_BITRATE, + }, + }; private initNotificationManager() { if (!this.notificationManager) { @@ -224,6 +237,15 @@ export class HMSSdk implements HMSInterface { return new HMSPeerListIterator(this.transport, this.store, options); } + updatePlaylistSettings(options: HMSPlaylistSettings) { + if (options.video) { + Object.assign(this.playlistSettings.video, options.video); + } + if (options.audio) { + Object.assign(this.playlistSettings.audio, options.audio); + } + } + private handleAutoplayError = (error: HMSException) => { this.errorListener?.onError?.(error); }; @@ -1151,9 +1173,9 @@ export class HMSSdk implements HMSInterface { if (source === 'videoplaylist') { const settings: { maxBitrate?: number; width?: number; height?: number } = {}; if (track.kind === 'audio') { - settings.maxBitrate = 64; + settings.maxBitrate = this.playlistSettings.audio?.bitrate || DEFAULT_PLAYLIST_AUDIO_BITRATE; } else { - settings.maxBitrate = 1000; + settings.maxBitrate = this.playlistSettings.video?.bitrate || DEFAULT_PLAYLIST_VIDEO_BITRATE; const { width, height } = track.getSettings(); settings.width = width; settings.height = height; diff --git a/packages/hms-video-web/src/utils/constants.ts b/packages/hms-video-web/src/utils/constants.ts index fe3868be7c..4603b0027e 100644 --- a/packages/hms-video-web/src/utils/constants.ts +++ b/packages/hms-video-web/src/utils/constants.ts @@ -60,3 +60,7 @@ export const PROTOCOL_VERSION = '2.5'; export const PROTOCOL_SPEC = '20231020'; export const HAND_RAISE_GROUP_NAME = '_handraise'; + +export const DEFAULT_PLAYLIST_VIDEO_BITRATE = 1000; + +export const DEFAULT_PLAYLIST_AUDIO_BITRATE = 64; diff --git a/packages/hms-virtual-background/package.json b/packages/hms-virtual-background/package.json index bbaf7ba407..597585fd00 100755 --- a/packages/hms-virtual-background/package.json +++ b/packages/hms-virtual-background/package.json @@ -1,5 +1,5 @@ { - "version": "1.11.22", + "version": "1.11.23", "license": "MIT", "main": "dist/index.cjs.js", "typings": "dist/index.d.ts", @@ -24,13 +24,13 @@ "format": "prettier --write src/**/*.ts" }, "peerDependencies": { - "@100mslive/hms-video": "0.9.22" + "@100mslive/hms-video": "0.9.23" }, "name": "@100mslive/hms-virtual-background", "author": "ashish17", "module": "dist/index.js", "devDependencies": { - "@100mslive/hms-video": "0.9.22" + "@100mslive/hms-video": "0.9.23" }, "dependencies": { "@mediapipe/selfie_segmentation": "^0.1.1632777926", diff --git a/packages/react-icons/assets/PersonIcon.svg b/packages/react-icons/assets/PersonIcon.svg index 3cd3d8695e..8340a8ba67 100644 --- a/packages/react-icons/assets/PersonIcon.svg +++ b/packages/react-icons/assets/PersonIcon.svg @@ -1,3 +1,3 @@ - - + + diff --git a/packages/react-icons/assets/UnpinIcon.svg b/packages/react-icons/assets/UnpinIcon.svg new file mode 100644 index 0000000000..3f37f4e491 --- /dev/null +++ b/packages/react-icons/assets/UnpinIcon.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/packages/react-icons/package.json b/packages/react-icons/package.json index 5a26f44281..5cc089bdd9 100644 --- a/packages/react-icons/package.json +++ b/packages/react-icons/package.json @@ -4,7 +4,7 @@ "main": "dist/index.cjs.js", "module": "dist/index.js", "typings": "dist/index.d.ts", - "version": "0.8.22", + "version": "0.8.23", "author": "100ms", "license": "MIT", "files": [ diff --git a/packages/react-icons/src/PersonIcon.tsx b/packages/react-icons/src/PersonIcon.tsx index fa633d04e3..c1016ee870 100644 --- a/packages/react-icons/src/PersonIcon.tsx +++ b/packages/react-icons/src/PersonIcon.tsx @@ -1,11 +1,11 @@ import * as React from 'react'; import { SVGProps } from 'react'; const SvgPersonIcon = (props: SVGProps) => ( - + diff --git a/packages/react-icons/src/UnpinIcon.tsx b/packages/react-icons/src/UnpinIcon.tsx new file mode 100644 index 0000000000..272a3a7239 --- /dev/null +++ b/packages/react-icons/src/UnpinIcon.tsx @@ -0,0 +1,14 @@ +import * as React from 'react'; +import { SVGProps } from 'react'; +const SvgUnpinIcon = (props: SVGProps) => ( + + + +); +export default SvgUnpinIcon; diff --git a/packages/react-icons/src/index.ts b/packages/react-icons/src/index.ts index 6dbc286ae4..6ef30f6ddf 100644 --- a/packages/react-icons/src/index.ts +++ b/packages/react-icons/src/index.ts @@ -242,6 +242,7 @@ export { default as ThumbsUpIcon } from './ThumbsUpIcon'; export { default as TranscriptIcon } from './TranscriptIcon'; export { default as TrashIcon } from './TrashIcon'; export { default as TwitterIcon } from './TwitterIcon'; +export { default as UnpinIcon } from './UnpinIcon'; export { default as UploadIcon } from './UploadIcon'; export { default as VerifiedIcon } from './VerifiedIcon'; export { default as VerticalMenuIcon } from './VerticalMenuIcon'; diff --git a/packages/react-sdk/package.json b/packages/react-sdk/package.json index 2642092503..4d820d1e85 100644 --- a/packages/react-sdk/package.json +++ b/packages/react-sdk/package.json @@ -4,7 +4,7 @@ "main": "dist/index.cjs.js", "module": "dist/index.js", "typings": "dist/index.d.ts", - "version": "0.8.22", + "version": "0.8.23", "author": "100ms", "license": "MIT", "files": [ @@ -43,7 +43,7 @@ "react": ">=16.8 <19.0.0" }, "dependencies": { - "@100mslive/hms-video-store": "0.10.22", + "@100mslive/hms-video-store": "0.10.23", "react-resize-detector": "^7.0.0", "zustand": "^3.6.2" } diff --git a/packages/roomkit-react/package.json b/packages/roomkit-react/package.json index 81404da029..7e559f4969 100644 --- a/packages/roomkit-react/package.json +++ b/packages/roomkit-react/package.json @@ -10,7 +10,7 @@ "prebuilt", "roomkit" ], - "version": "0.1.13", + "version": "0.1.14", "author": "100ms", "license": "MIT", "files": [ @@ -76,10 +76,10 @@ "react": ">=17.0.2 <19.0.0" }, "dependencies": { - "@100mslive/hls-player": "0.1.22", - "@100mslive/hms-virtual-background": "1.11.22", - "@100mslive/react-icons": "0.8.22", - "@100mslive/react-sdk": "0.8.22", + "@100mslive/hls-player": "0.1.23", + "@100mslive/hms-virtual-background": "1.11.23", + "@100mslive/react-icons": "0.8.23", + "@100mslive/react-sdk": "0.8.23", "@100mslive/types-prebuilt": "0.12.4", "@emoji-mart/data": "^1.0.6", "@emoji-mart/react": "^1.0.1", diff --git a/packages/roomkit-react/src/Prebuilt/common/constants.ts b/packages/roomkit-react/src/Prebuilt/common/constants.ts index 994d9345b9..f6f67b60c6 100644 --- a/packages/roomkit-react/src/Prebuilt/common/constants.ts +++ b/packages/roomkit-react/src/Prebuilt/common/constants.ts @@ -19,6 +19,7 @@ export const EMOJI_REACTION_TYPE = 'EMOJI_REACTION'; export const CHAT_SELECTOR = { PEER_ID: 'peer_id', ROLE: 'role', + EVERYONE: 'Everyone', }; export const APP_DATA = { diff --git a/packages/roomkit-react/src/Prebuilt/common/hooks.ts b/packages/roomkit-react/src/Prebuilt/common/hooks.ts index 78bfce0e7d..ea368b4723 100644 --- a/packages/roomkit-react/src/Prebuilt/common/hooks.ts +++ b/packages/roomkit-react/src/Prebuilt/common/hooks.ts @@ -55,21 +55,6 @@ export const useFilteredRoles = () => { return elements?.chat?.roles_whitelist || []; }; -export const useDefaultChatSelection = () => { - const { elements } = useRoomLayoutConferencingScreen(); - const roles = useFilteredRoles(); - // default is everyone for public chat - if (elements?.chat?.public_chat_enabled) { - return 'Everyone'; - } - // sending first role as default - if (roles.length > 0) { - return roles[0]; - } - // sending empty - return ''; -}; - export const useShowStreamingUI = () => { const layout = useRoomLayout(); const { join_form } = layout?.screens?.preview?.default?.elements || {}; diff --git a/packages/roomkit-react/src/Prebuilt/components/AuthToken.jsx b/packages/roomkit-react/src/Prebuilt/components/AuthToken.jsx index 2ce269423d..919c02da05 100644 --- a/packages/roomkit-react/src/Prebuilt/components/AuthToken.jsx +++ b/packages/roomkit-react/src/Prebuilt/components/AuthToken.jsx @@ -1,6 +1,6 @@ import React, { useEffect, useState } from 'react'; import { useSessionStorage } from 'react-use'; -import { v4 } from 'uuid'; +import { v4 as uuid } from 'uuid'; import { useHMSActions } from '@100mslive/react-sdk'; import { styled } from '../../Theme'; import { useHMSPrebuiltContext } from '../AppContext'; @@ -26,12 +26,6 @@ const AuthToken = React.memo(({ authTokenByRoomCodeEndpoint, defaultAuthToken }) const [, setAuthTokenInAppData] = useSetAppDataByKey(APP_DATA.authToken); const [savedUserId, setSavedUserId] = useSessionStorage(UserPreferencesKeys.USER_ID); - useEffect(() => { - if (!savedUserId && !userId) { - setSavedUserId(v4()); - } - }, [savedUserId, setSavedUserId, userId]); - useEffect(() => { if (authToken) { setAuthTokenInAppData(authToken); @@ -42,11 +36,25 @@ const AuthToken = React.memo(({ authTokenByRoomCodeEndpoint, defaultAuthToken }) return; } + if (!savedUserId && !userId) { + setSavedUserId(uuid()); + return; + } + hmsActions .getAuthTokenByRoomCode({ roomCode, userId: userId || savedUserId }, { endpoint: authTokenByRoomCodeEndpoint }) .then(token => setAuthTokenInAppData(token)) .catch(error => setError(convertError(error))); - }, [hmsActions, authToken, authTokenByRoomCodeEndpoint, setAuthTokenInAppData, roomCode, userId, savedUserId]); + }, [ + hmsActions, + authToken, + authTokenByRoomCodeEndpoint, + setAuthTokenInAppData, + roomCode, + userId, + savedUserId, + setSavedUserId, + ]); if (error.title) { return {error.body}; diff --git a/packages/roomkit-react/src/Prebuilt/components/Chat/Navigation.tsx b/packages/roomkit-react/src/Prebuilt/components/Chat/ArrowNavigation.tsx similarity index 65% rename from packages/roomkit-react/src/Prebuilt/components/Chat/Navigation.tsx rename to packages/roomkit-react/src/Prebuilt/components/Chat/ArrowNavigation.tsx index a3cae2fc31..a524af4dbb 100644 --- a/packages/roomkit-react/src/Prebuilt/components/Chat/Navigation.tsx +++ b/packages/roomkit-react/src/Prebuilt/components/Chat/ArrowNavigation.tsx @@ -1,40 +1,24 @@ import React from 'react'; import { ChevronDownIcon, ChevronUpIcon } from '@100mslive/react-icons'; -import { Box, Flex } from '../../../Layout'; +import { Flex } from '../../../Layout'; -export const Navigation = ({ +export const ArrowNavigation = ({ total, index, showPrevious, showNext, - isMobile, }: { total: number; index: number; showPrevious: () => void; showNext: () => void; - isMobile: boolean; }) => { - const sticksCount = Math.min(3, total); - if (total < 2) { return null; } - return isMobile ? ( + return ( - {[...Array(sticksCount)].map((_, i) => ( - - ))} - - ) : ( - { const hmsActions = useHMSActions(); const { removePinnedMessage } = useSetPinnedMessages(); const pinnedMessages = useHMSStore(selectSessionStore(SESSION_STORE_KEY.PINNED_MESSAGES)) || []; + const isPeerPresent = !!useHMSStore(selectPeerByID(selectedPeer)); useEffect(() => { if (notification && notification.data && selectedPeer === notification.data.id) { setPeerSelector(''); setRoleSelector(''); } - }, [notification, selectedPeer, setPeerSelector, setRoleSelector]); + if (selectedPeer && !isPeerPresent) { + setPeerSelector(''); + } + }, [notification, selectedPeer, setPeerSelector, setRoleSelector, isPeerPresent]); const blacklistedPeerIDs = useHMSStore(selectSessionStore(SESSION_STORE_KEY.CHAT_PEER_BLACKLIST)) || []; const blacklistedPeerIDSet = new Set(blacklistedPeerIDs); const isLocalPeerBlacklisted = blacklistedPeerIDSet.has(localPeer?.customerUserId); @@ -81,12 +85,7 @@ export const Chat = () => { )} - + diff --git a/packages/roomkit-react/src/Prebuilt/components/Chat/ChatBody.jsx b/packages/roomkit-react/src/Prebuilt/components/Chat/ChatBody.jsx index a101f5a1d7..d67f64cf51 100644 --- a/packages/roomkit-react/src/Prebuilt/components/Chat/ChatBody.jsx +++ b/packages/roomkit-react/src/Prebuilt/components/Chat/ChatBody.jsx @@ -70,22 +70,28 @@ const MessageTypeContainer = ({ left, right }) => { {left && ( - + {left} )} {right && ( - + {right} )} @@ -93,16 +99,13 @@ const MessageTypeContainer = ({ left, right }) => { ); }; -const MessageType = ({ role, hasCurrentUserSent, receiver }) => { - if (hasCurrentUserSent) { - return null; - } +const MessageType = ({ roles, receiver }) => { if (receiver) { return ; } - if (role) { - return ; + if (roles && roles.length > 0) { + return ; } return null; }; @@ -164,24 +167,20 @@ const ChatActions = ({ can_block_user: false, }; const [open, setOpen] = useState(false); - const blacklistedPeerIDs = useHMSStore(selectSessionStore(SESSION_STORE_KEY.CHAT_PEER_BLACKLIST)); const { blacklistItem: blacklistPeer } = useChatBlacklist(SESSION_STORE_KEY.CHAT_PEER_BLACKLIST); - const blacklistedMessageIDs = useHMSStore(selectSessionStore(SESSION_STORE_KEY.CHAT_MESSAGE_BLACKLIST)); - const { blacklistItem: blacklistMessage } = useChatBlacklist(SESSION_STORE_KEY.CHAT_MESSAGE_BLACKLIST); + const { blacklistItem: blacklistMessage, blacklistedIDs: blacklistedMessageIDs = [] } = useChatBlacklist( + SESSION_STORE_KEY.CHAT_MESSAGE_BLACKLIST, + ); const { unpinBlacklistedMessages } = useSetPinnedMessages(); const pinnedMessages = useHMSStore(selectSessionStore(SESSION_STORE_KEY.PINNED_MESSAGES)); const updatePinnedMessages = useCallback( - ({ messageID = '', peerID = '' }) => { - if (!(blacklistedPeerIDs?.length || blacklistedMessageIDs?.length)) { - return; - } + (messageID = '') => { const blacklistedMessageIDSet = new Set([...blacklistedMessageIDs, messageID]); - const blacklistedPeerIDSet = new Set([...blacklistedPeerIDs, peerID]); - unpinBlacklistedMessages(pinnedMessages, blacklistedPeerIDSet, blacklistedMessageIDSet); + unpinBlacklistedMessages(pinnedMessages, blacklistedMessageIDSet); }, - [blacklistedPeerIDs, blacklistedMessageIDs, unpinBlacklistedMessages, pinnedMessages], + [blacklistedMessageIDs, unpinBlacklistedMessages, pinnedMessages], ); const copyMessageContent = useCallback(() => { @@ -224,18 +223,15 @@ const ChatActions = ({ text: 'Hide for everyone', icon: , onClick: async () => { - blacklistMessage(blacklistedMessageIDs, message.id); - updatePinnedMessages({ messageID: message.id }); + blacklistMessage(message.id); + updatePinnedMessages(message.id); }, show: can_hide_message, }, block: { text: 'Block from chat', icon: , - onClick: async () => { - blacklistPeer(blacklistedPeerIDs, message?.senderUserId); - updatePinnedMessages({ peerID: message?.senderUserId }); - }, + onClick: async () => blacklistPeer(message?.senderUserId), color: '$alert_error_default', show: can_block_user && !sentByLocalPeer, }, @@ -291,7 +287,9 @@ const ChatActions = ({ borderRadius: '$1', p: '$2', opacity: open ? 1 : 0, - display: open ? 'flex' : 'none', + position: 'absolute', + right: 0, + zIndex: 1, '@md': { opacity: 1 }, }} > @@ -365,7 +363,7 @@ const SenderName = styled(Text, { overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap', - maxWidth: '24ch', + maxWidth: '16ch', minWidth: 0, color: '$on_surface_high', fontWeight: '$semiBold', @@ -419,7 +417,6 @@ const ChatMessage = React.memo( mt: '$4', '&:not(:hover} .chat_actions': { display: 'none' }, '&:hover .chat_actions': { display: 'flex', opacity: 1 }, - '&:hover .message_type_container': { display: 'none' }, }} style={style} > @@ -428,10 +425,16 @@ const ChatMessage = React.memo( align="center" css={{ flexWrap: 'wrap', + position: 'relative', // Theme independent color, token should not be used for transparent chat - bg: messageType ? (isOverlay ? 'rgba(0, 0, 0, 0.64)' : '$surface_default') : undefined, + bg: + messageType && !(selectedPeer || selectedRole) + ? isOverlay + ? 'rgba(0, 0, 0, 0.64)' + : '$surface_default' + : undefined, r: '$1', - p: '$1 $2', + p: '$4', userSelect: 'none', '@md': { cursor: 'pointer', @@ -452,21 +455,29 @@ const ChatMessage = React.memo( css={{ color: isOverlay ? '#FFF' : '$on_surface_high', fontWeight: '$semiBold', - display: 'inline-flex', + display: 'flex', alignItems: 'center', - justifyContent: 'space-between', + alignSelf: 'stretch', width: '100%', }} as="div" > {message.senderName === 'You' || !message.senderName ? ( - + {message.senderName || 'Anonymous'} ) : ( - + {message.senderName} @@ -474,9 +485,9 @@ const ChatMessage = React.memo( {!isOverlay ? ( {!(selectedPeer || selectedRole) && ( - 0)) - } - receiver={message.recipientPeer} - role={message.senderRole} - /> + )} { +export const ChatBody = React.forwardRef(({ scrollToBottom }, listRef) => { const selectedPeer = useSubscribeChatSelector(CHAT_SELECTOR.PEER_ID); const selectedRole = useSubscribeChatSelector(CHAT_SELECTOR.ROLE); let storeMessageSelector; @@ -632,15 +636,8 @@ export const ChatBody = React.forwardRef(({ scrollToBottom, blacklistedPeerIDs } const blacklistedMessageIDs = useHMSStore(selectSessionStore(SESSION_STORE_KEY.CHAT_MESSAGE_BLACKLIST)) || []; const getFilteredMessages = () => { const blacklistedMessageIDSet = new Set(blacklistedMessageIDs); - const blacklistedPeerIDSet = new Set(blacklistedPeerIDs); - return ( - messages?.filter( - message => - message.type === 'chat' && - !blacklistedMessageIDSet.has(message.id) && - !blacklistedPeerIDSet.has(message?.senderUserId), - ) || [] - ); + + return messages?.filter(message => message.type === 'chat' && !blacklistedMessageIDSet.has(message.id)) || []; }; const isMobile = useMedia(cssConfig.media.md); diff --git a/packages/roomkit-react/src/Prebuilt/components/Chat/ChatFooter.tsx b/packages/roomkit-react/src/Prebuilt/components/Chat/ChatFooter.tsx index c1edd7f44f..0f9121a627 100644 --- a/packages/roomkit-react/src/Prebuilt/components/Chat/ChatFooter.tsx +++ b/packages/roomkit-react/src/Prebuilt/components/Chat/ChatFooter.tsx @@ -8,17 +8,15 @@ import { Box, config as cssConfig, Flex, IconButton as BaseIconButton, Popover, import { IconButton } from '../../../IconButton'; // @ts-ignore import { ToastManager } from '../Toast/ToastManager'; -// @ts-ignore import { ChatSelectorContainer } from './ChatSelectorContainer'; import { useRoomLayoutConferencingScreen } from '../../provider/roomLayoutProvider/hooks/useRoomLayoutScreen'; // import { ChatSelectorContainer } from './ChatSelectorContainer'; // @ts-ignore import { useChatDraftMessage } from '../AppData/useChatState'; // @ts-ignore -import { useSetSubscribedChatSelector, useSubscribeChatSelector } from '../AppData/useUISettings'; +import { useSubscribeChatSelector } from '../AppData/useUISettings'; // @ts-ignore import { useEmojiPickerStyles } from './useEmojiPickerStyles'; -import { useDefaultChatSelection } from '../../common/hooks'; import { CHAT_SELECTOR, SESSION_STORE_KEY } from '../../common/constants'; const TextArea = styled('textarea', { @@ -82,17 +80,12 @@ export const ChatFooter = ({ onSend, children }: { onSend: () => void; children: const message_placeholder = elements?.chat?.message_placeholder || 'Send a message'; const localPeer = useHMSStore(selectLocalPeer); const isOverlayChat = elements?.chat?.is_overlay; - const can_disable_chat = !!elements?.chat?.real_time_controls?.can_disable_chat; + const canDisableChat = !!elements?.chat?.real_time_controls?.can_disable_chat; + const isPublicChatEnabled = !!elements?.chat?.public_chat_enabled; const selectedPeer = useSubscribeChatSelector(CHAT_SELECTOR.PEER_ID); - const [selectedRole, setRoleSelector] = useSetSubscribedChatSelector(CHAT_SELECTOR.ROLE); - const defaultSelection = useDefaultChatSelection(); + const selectedRole = useSubscribeChatSelector(CHAT_SELECTOR.ROLE); const selectorPeerName = useHMSStore(selectPeerNameByID(selectedPeer)); - const selection = selectorPeerName || selectedRole || defaultSelection; - useEffect(() => { - if (!selectedPeer && !selectedRole && !['Everyone', ''].includes(defaultSelection)) { - setRoleSelector(defaultSelection); - } - }, [defaultSelection, selectedPeer, selectedRole, setRoleSelector]); + const selection = selectorPeerName || selectedRole || CHAT_SELECTOR.EVERYONE; const sendMessage = useCallback(async () => { const message = inputRef?.current?.value; if (!message || !message.trim().length) { @@ -134,7 +127,7 @@ export const ChatFooter = ({ onSend, children }: { onSend: () => void; children: - {can_disable_chat ? ( + {canDisableChat && isMobile && isOverlayChat ? ( @@ -179,7 +172,7 @@ export const ChatFooter = ({ onSend, children }: { onSend: () => void; children: ) : null} - {selection && ( + {!(selection === CHAT_SELECTOR.EVERYONE && !isPublicChatEnabled) && ( void; unreadCount: number; + icon?: React.JSX.Element; }) => { + const isMobile = useMedia(cssConfig.media.md); + + const Root = !isMobile + ? Dropdown.Item + : ({ children, ...rest }: { children: React.ReactNode; css: CSS }) => ( + + {children} + + ); return ( - - {value} + + {icon} + {value} + {unreadCount > 0 && ( @@ -49,16 +68,19 @@ const SelectorItem = ({ )} {active && } - + ); }; const SelectorHeader = React.memo( - ({ isHorizontalDivider, children }: { isHorizontalDivider: boolean; children: React.ReactNode }) => { + ({ isHorizontalDivider = true, children }: { isHorizontalDivider?: boolean; children: React.ReactNode }) => { return ( {isHorizontalDivider && } - + {children} @@ -73,6 +95,7 @@ const Everyone = React.memo(({ active }: { active: boolean }) => { return ( } active={active} unreadCount={unreadCount} onClick={() => { @@ -123,15 +146,14 @@ const VirtualizedSelectItemList = ({ selectedRole, selectedPeerId, searchValue, - isPublicChatEnabled, }: { peers: HMSPeer[]; selectedRole: string; selectedPeerId: string; searchValue: string; - isPublicChatEnabled: boolean; }) => { const roles = useFilteredRoles(); + const isMobile = useMedia(cssConfig.media.md); const filteredPeers = useMemo( () => peers.filter( @@ -142,18 +164,15 @@ const VirtualizedSelectItemList = ({ ); const listItems = useMemo(() => { - const selectItems = isPublicChatEnabled ? [] : []; + const selectItems = !searchValue ? [] : []; - roles.length > 0 && - selectItems.push(Roles); - roles.forEach(userRole => - selectItems.push(), - ); - - filteredPeers.length > 0 && - selectItems.push( - 0}>Participants, + roles.length > 0 && !searchValue && selectItems.push(Roles); + !searchValue && + roles.forEach(userRole => + selectItems.push(), ); + + filteredPeers.length > 0 && selectItems.push(Participants); filteredPeers.forEach(peer => selectItems.push( , @@ -161,14 +180,23 @@ const VirtualizedSelectItemList = ({ ); return selectItems; - }, [isPublicChatEnabled, selectedRole, selectedPeerId, roles, filteredPeers]); + }, [searchValue, selectedRole, selectedPeerId, roles, filteredPeers]); + if (!isMobile) { + return ( + + {listItems.map((item, index) => ( + {item} + ))} + + ); + } return ( - + <> {listItems.map((item, index) => ( {item} ))} - + ); }; @@ -178,7 +206,6 @@ export const ChatSelector = ({ role, peerId }: { role: string; peerId: string }) const [search, setSearch] = useState(''); const isPrivateChatEnabled = !!elements?.chat?.private_chat_enabled; - const isPublicChatEnabled = !!elements?.chat?.public_chat_enabled; return ( <> @@ -191,7 +218,6 @@ export const ChatSelector = ({ role, peerId }: { role: string; peerId: string }) selectedRole={role} selectedPeerId={peerId} peers={isPrivateChatEnabled ? peers : []} - isPublicChatEnabled={isPublicChatEnabled} searchValue={search} /> diff --git a/packages/roomkit-react/src/Prebuilt/components/Chat/ChatSelectorContainer.tsx b/packages/roomkit-react/src/Prebuilt/components/Chat/ChatSelectorContainer.tsx index a3e92c2e28..e032f98bea 100644 --- a/packages/roomkit-react/src/Prebuilt/components/Chat/ChatSelectorContainer.tsx +++ b/packages/roomkit-react/src/Prebuilt/components/Chat/ChatSelectorContainer.tsx @@ -1,9 +1,9 @@ import React, { useState } from 'react'; import { useMedia } from 'react-use'; import { selectPeerNameByID, useHMSStore } from '@100mslive/react-sdk'; -import { ChevronDownIcon, ChevronUpIcon, CrossIcon, SearchIcon } from '@100mslive/react-icons'; +import { ChevronDownIcon, ChevronUpIcon, CrossIcon, PeopleIcon, PersonIcon } from '@100mslive/react-icons'; import { Dropdown } from '../../../Dropdown'; -import { Flex } from '../../../Layout'; +import { Box, Flex } from '../../../Layout'; import { Sheet } from '../../../Sheet'; import { Text } from '../../../Text'; import { config as cssConfig } from '../../../Theme'; @@ -11,8 +11,7 @@ import { ChatSelector } from './ChatSelector'; import { useRoomLayoutConferencingScreen } from '../../provider/roomLayoutProvider/hooks/useRoomLayoutScreen'; // @ts-ignore import { useSubscribeChatSelector } from '../AppData/useUISettings'; -import { useDefaultChatSelection, useFilteredRoles } from '../../common/hooks'; -import { textEllipsis } from '../../../utils'; +import { useFilteredRoles } from '../../common/hooks'; import { CHAT_SELECTOR } from '../../common/constants'; export const ChatSelectorContainer = () => { @@ -24,81 +23,136 @@ export const ChatSelectorContainer = () => { const roles = useFilteredRoles(); const selectedPeer = useSubscribeChatSelector(CHAT_SELECTOR.PEER_ID); const selectedRole = useSubscribeChatSelector(CHAT_SELECTOR.ROLE); - const defaultSelection = useDefaultChatSelection(); const selectorPeerName = useHMSStore(selectPeerNameByID(selectedPeer)); - const selection = selectorPeerName || selectedRole || defaultSelection; + const selection = selectorPeerName || selectedRole || CHAT_SELECTOR.EVERYONE; if (!(isPrivateChatEnabled || isPublicChatEnabled || roles.length > 0) && !isPrivateChatEnabled && !selection) { return null; } return ( - - - {selection ? 'To' : 'Choose Participant'} - + <> + + + {selection ? 'To' : 'Choose Participant'} + - setOpen(value)}> - - - {!selection && } + {isMobile ? ( + { + setOpen(value => !value); + e.stopPropagation(); + }} + > + {selection === CHAT_SELECTOR.EVERYONE ? ( + + ) : ( + + )} {selection || 'Search'} {selection && (open ? : )} - - - - {isMobile ? ( - setOpen(value)}> - - setOpen(value)}> + + + - Send message to - - - - - - - - ) : ( - - )} - - - + {selection === CHAT_SELECTOR.EVERYONE ? ( + + ) : ( + + )} + {selection} + + {selection && ( + + )} + + + + + + + + )} + + {isMobile ? ( + setOpen(value)}> + + + Chat with + + + + + { + setOpen(false); + }} + > + + + + + ) : null} + ); }; diff --git a/packages/roomkit-react/src/Prebuilt/components/Chat/PinnedMessage.tsx b/packages/roomkit-react/src/Prebuilt/components/Chat/PinnedMessage.tsx index 9ef1f287e6..9633f045df 100644 --- a/packages/roomkit-react/src/Prebuilt/components/Chat/PinnedMessage.tsx +++ b/packages/roomkit-react/src/Prebuilt/components/Chat/PinnedMessage.tsx @@ -1,35 +1,32 @@ -import React, { useEffect, useRef, useState } from 'react'; +import React, { useEffect, useState } from 'react'; import { useSwipeable } from 'react-swipeable'; import { useMedia } from 'react-use'; import { selectSessionStore, useHMSStore } from '@100mslive/react-sdk'; -import { CrossIcon, PinIcon } from '@100mslive/react-icons'; +import { PinIcon, UnpinIcon } from '@100mslive/react-icons'; import { Box, Flex } from '../../../Layout'; import { Text } from '../../../Text'; import { config as cssConfig } from '../../../Theme'; +import { ArrowNavigation } from './ArrowNavigation'; // @ts-ignore import { AnnotisedMessage } from './ChatBody'; -// @ts-ignore -import { Navigation } from './Navigation'; +import { StickIndicator } from './StickIndicator'; import { useRoomLayoutConferencingScreen } from '../../provider/roomLayoutProvider/hooks/useRoomLayoutScreen'; import { SESSION_STORE_KEY } from '../../common/constants'; const PINNED_MESSAGE_LENGTH = 75; export const PinnedMessage = ({ clearPinnedMessage }: { clearPinnedMessage: (index: number) => void }) => { - const pinnedMessages = useHMSStore(selectSessionStore(SESSION_STORE_KEY.PINNED_MESSAGES)) || []; + const pinnedMessages = useHMSStore(selectSessionStore(SESSION_STORE_KEY.PINNED_MESSAGES)); const [pinnedMessageIndex, setPinnedMessageIndex] = useState(0); const isMobile = useMedia(cssConfig.media.md); const { elements } = useRoomLayoutConferencingScreen(); const canUnpinMessage = !!elements?.chat?.allow_pinning_messages; - const [hideOverflow, setHideOverflow] = useState(false); - const canOverflow = pinnedMessages?.[pinnedMessageIndex]?.text?.length > PINNED_MESSAGE_LENGTH || false; - const formattedPinnedMessage = hideOverflow - ? `${pinnedMessages?.[pinnedMessageIndex]?.text.slice(0, PINNED_MESSAGE_LENGTH)}... ` - : pinnedMessages?.[pinnedMessageIndex]?.text; + const [hideOverflow, setHideOverflow] = useState(true); + const currentPinnedMessage = pinnedMessages?.[pinnedMessageIndex]?.text || ''; + const canOverflow = currentPinnedMessage.length > PINNED_MESSAGE_LENGTH; - const pinnedMessageRef = useRef(null); const showPreviousPinnedMessage = () => { const previousIndex = Math.max(pinnedMessageIndex - 1, 0); setHideOverflow(pinnedMessages[previousIndex].text.length > PINNED_MESSAGE_LENGTH); @@ -47,19 +44,30 @@ export const PinnedMessage = ({ clearPinnedMessage }: { clearPinnedMessage: (ind onSwipedDown: () => showPreviousPinnedMessage(), }); + // Scenario: User is on a particular index but an earlier message is removed by another peer useEffect(() => { - setHideOverflow( - !!( - pinnedMessages?.[pinnedMessageIndex]?.text?.length && - pinnedMessages?.[pinnedMessageIndex]?.text.length > PINNED_MESSAGE_LENGTH - ), - ); + const count = pinnedMessages?.length || 1; + if (pinnedMessageIndex >= count) { + setPinnedMessageIndex(count - 1); + } }, [pinnedMessageIndex, pinnedMessages]); - return pinnedMessages?.[pinnedMessageIndex]?.text ? ( - + if (!pinnedMessages || pinnedMessages.length === 0) { + return null; + } + + return ( + + {!isMobile ? ( + + ) : null} - - + {isMobile ? : null} - + {canOverflow ? ( setHideOverflow(prev => !prev)}> -  {hideOverflow ? 'See more' : 'Collapse'} +  {hideOverflow ? '... See more' : 'Collapse'} ) : null} @@ -110,12 +116,19 @@ export const PinnedMessage = ({ clearPinnedMessage }: { clearPinnedMessage: (ind clearPinnedMessage(pinnedMessageIndex); setPinnedMessageIndex(Math.max(0, pinnedMessageIndex - 1)); }} - css={{ cursor: 'pointer', color: '$on_surface_medium', '&:hover': { color: '$on_surface_high' } }} + css={{ + cursor: 'pointer', + color: '$on_surface_medium', + '&:hover': { color: '$on_surface_high' }, + '&:hover .hide-on-hover': { display: 'none !important' }, + '&:hover .show-on-hover': { display: 'block !important' }, + }} > - + + ) : null} - ) : null; + ); }; diff --git a/packages/roomkit-react/src/Prebuilt/components/Chat/StickIndicator.tsx b/packages/roomkit-react/src/Prebuilt/components/Chat/StickIndicator.tsx new file mode 100644 index 0000000000..b6b66901e0 --- /dev/null +++ b/packages/roomkit-react/src/Prebuilt/components/Chat/StickIndicator.tsx @@ -0,0 +1,24 @@ +import React from 'react'; +import { Box, Flex } from '../../../Layout'; + +export const StickIndicator = ({ total, index }: { total: number; index: number }) => { + const sticksCount = Math.min(3, total); + + if (total < 2) { + return null; + } + + return ( + + {[...Array(sticksCount)].map((_, i) => ( + + ))} + + ); +}; diff --git a/packages/roomkit-react/src/Prebuilt/components/ChatSettings.tsx b/packages/roomkit-react/src/Prebuilt/components/ChatSettings.tsx new file mode 100644 index 0000000000..ba2ac783d1 --- /dev/null +++ b/packages/roomkit-react/src/Prebuilt/components/ChatSettings.tsx @@ -0,0 +1,68 @@ +import React from 'react'; +import { selectLocalPeer, selectSessionStore, useHMSActions, useHMSStore } from '@100mslive/react-sdk'; +import { PauseCircleIcon, SettingsIcon } from '@100mslive/react-icons'; +import { Flex } from '../../Layout'; +import { Popover } from '../../Popover'; +import { Text } from '../../Text'; +import { useRoomLayoutConferencingScreen } from '../provider/roomLayoutProvider/hooks/useRoomLayoutScreen'; +import { SESSION_STORE_KEY } from '../common/constants'; + +export const ChatSettings = () => { + const hmsActions = useHMSActions(); + const localPeer = useHMSStore(selectLocalPeer); + const { elements } = useRoomLayoutConferencingScreen(); + const canPauseChat = !!elements?.chat?.real_time_controls?.can_disable_chat; + const { enabled: isChatEnabled = true } = useHMSStore(selectSessionStore(SESSION_STORE_KEY.CHAT_STATE)) || {}; + const showPause = canPauseChat && isChatEnabled; + + if (!showPause) { + return null; + } + + return ( + + + + + + + + { + const chatState = { + enabled: false, + updatedBy: { + peerId: localPeer?.id, + userId: localPeer?.customerUserId, + userName: localPeer?.name, + }, + updatedAt: Date.now(), + }; + hmsActions.sessionStore.set(SESSION_STORE_KEY.CHAT_STATE, chatState); + }} + css={{ + backgroundColor: '$surface_default', + display: 'flex', + alignItems: 'center', + gap: '$4', + borderRadius: '$1', + color: '$on_surface_high', + cursor: 'pointer', + '&:hover': { backgroundColor: '$surface_dim' }, + }} + > + + + Pause Chat + + + + + ); +}; diff --git a/packages/roomkit-react/src/Prebuilt/components/Footer/ParticipantList.jsx b/packages/roomkit-react/src/Prebuilt/components/Footer/ParticipantList.jsx index 4cf36042c9..29af5aa5c2 100644 --- a/packages/roomkit-react/src/Prebuilt/components/Footer/ParticipantList.jsx +++ b/packages/roomkit-react/src/Prebuilt/components/Footer/ParticipantList.jsx @@ -359,8 +359,9 @@ export const ParticipantSearch = ({ onSearch, placeholder, inSidePane = false }) color: '$on_surface_medium', mt: inSidePane ? '$4' : '', }} + onClick={e => e.stopPropagation()} > - + { const [open, setOpen] = useState(false); @@ -26,7 +27,7 @@ export const ParticipantFilter = ({ selection, onSelection, isConnected, roles } > - {selectionValue || 'Everyone'} + {selectionValue || CHAT_SELECTOR.EVERYONE} {open ? : } diff --git a/packages/roomkit-react/src/Prebuilt/components/Notifications/ChatNotifications.tsx b/packages/roomkit-react/src/Prebuilt/components/Notifications/ChatNotifications.tsx index 52c3a7c0b1..ad62a3ca04 100644 --- a/packages/roomkit-react/src/Prebuilt/components/Notifications/ChatNotifications.tsx +++ b/packages/roomkit-react/src/Prebuilt/components/Notifications/ChatNotifications.tsx @@ -29,6 +29,6 @@ export const ChatNotifications = () => { title: `Chat ${chatState.enabled ? 'resumed' : 'paused'} by ${chatState.updatedBy?.userName}`, }; ToastManager.addToast(notification); - }, [chatState]); + }, [chatState, localPeerId]); return <>; }; diff --git a/packages/roomkit-react/src/Prebuilt/components/SidePaneTabs.tsx b/packages/roomkit-react/src/Prebuilt/components/SidePaneTabs.tsx index dc8415021b..4b21d011cd 100644 --- a/packages/roomkit-react/src/Prebuilt/components/SidePaneTabs.tsx +++ b/packages/roomkit-react/src/Prebuilt/components/SidePaneTabs.tsx @@ -10,13 +10,13 @@ import { PaginatedParticipants } from './Footer/PaginatedParticipants'; import { ParticipantList } from './Footer/ParticipantList'; import { Box, config as cssConfig, Flex, IconButton, Tabs, Text } from '../..'; import { Tooltip } from '../../Tooltip'; +import { ChatSettings } from './ChatSettings'; // @ts-ignore: No implicit Any import { useRoomLayoutConferencingScreen } from '../provider/roomLayoutProvider/hooks/useRoomLayoutScreen'; // @ts-ignore: No implicit Any import { useIsSidepaneTypeOpen, useSidepaneReset, useSidepaneToggle } from './AppData/useSidepane'; // @ts-ignore: No implicit Any import { getFormattedCount } from '../common/utils'; -// @ts-ignore: No implicit Any import { SIDE_PANE_OPTIONS } from '../common/constants'; const tabTriggerCSS = { @@ -57,6 +57,7 @@ export const SidePaneTabs = React.memo<{ const isOverlayChat = !!elements?.chat?.is_overlay && isMobile; const { off_stage_roles = [] } = (elements as DefaultConferencingScreen_Elements)?.on_stage_exp || {}; const isChatOpen = useIsSidepaneTypeOpen(SIDE_PANE_OPTIONS.CHAT); + const showChatSettings = showChat && isChatOpen && (!isMobile || !isOverlayChat); useEffect(() => { if (activeTab === SIDE_PANE_OPTIONS.CHAT && !showChat && showParticipants) { @@ -128,28 +129,47 @@ export const SidePaneTabs = React.memo<{ size: '100%', }} > - - - {chat_title} - - - Participants   - - + + + + {chat_title} + + + Participants   + + + {showChatSettings ? : null} + {isOverlayChat && isChatOpen ? null : ( + { + e.stopPropagation(); + if (activeTab === SIDE_PANE_OPTIONS.CHAT) { + toggleChat(); + } else { + toggleParticipants(); + } + }} + data-testid="close_chat" + > + + + )} + @@ -160,23 +180,6 @@ export const SidePaneTabs = React.memo<{ )} )} - - {isOverlayChat && isChatOpen ? null : ( - { - e.stopPropagation(); - if (activeTab === SIDE_PANE_OPTIONS.CHAT) { - toggleChat(); - } else { - toggleParticipants(); - } - }} - data-testid="close_chat" - > - - - )} ); }); diff --git a/packages/roomkit-react/src/Prebuilt/components/VirtualBackground/VBCollection.tsx b/packages/roomkit-react/src/Prebuilt/components/VirtualBackground/VBCollection.tsx index 4dc32b498c..45882cbd05 100644 --- a/packages/roomkit-react/src/Prebuilt/components/VirtualBackground/VBCollection.tsx +++ b/packages/roomkit-react/src/Prebuilt/components/VirtualBackground/VBCollection.tsx @@ -30,8 +30,9 @@ export const VBCollection = ({ {title} - {options.map(option => ( + {options.map((option, index) => ( Promise; mediaURL?: string; isActive: boolean; children?: React.JSX.Element[]; + testid: string; }) => ( { return ( - + diff --git a/packages/roomkit-react/src/Prebuilt/components/hooks/useChatBlacklist.ts b/packages/roomkit-react/src/Prebuilt/components/hooks/useChatBlacklist.ts index 6bce8c86b9..329aea4816 100644 --- a/packages/roomkit-react/src/Prebuilt/components/hooks/useChatBlacklist.ts +++ b/packages/roomkit-react/src/Prebuilt/components/hooks/useChatBlacklist.ts @@ -1,5 +1,5 @@ import { useCallback } from 'react'; -import { useHMSActions } from '@100mslive/react-sdk'; +import { selectSessionStore, useHMSActions, useHMSStore } from '@100mslive/react-sdk'; // @ts-ignore import { ToastManager } from '../Toast/ToastManager'; import { SESSION_STORE_KEY } from '../../common/constants'; @@ -8,14 +8,16 @@ export const useChatBlacklist = ( sessionStoreKey: SESSION_STORE_KEY.CHAT_MESSAGE_BLACKLIST | SESSION_STORE_KEY.CHAT_PEER_BLACKLIST, ) => { const hmsActions = useHMSActions(); + const blacklistedIDs = useHMSStore(selectSessionStore(sessionStoreKey)); const blacklistItem = useCallback( - async (blacklistedIDs: string[], blacklistID: string) => + async (blacklistID: string) => { await hmsActions.sessionStore - .set(sessionStoreKey, [...blacklistedIDs, blacklistID]) - .catch(err => ToastManager.addToast({ title: err.description })), - [hmsActions, sessionStoreKey], + .set(sessionStoreKey, [...(blacklistedIDs || []), blacklistID]) + .catch(err => ToastManager.addToast({ title: err.description })); + }, + [hmsActions, sessionStoreKey, blacklistedIDs], ); - return { blacklistItem }; + return { blacklistItem, blacklistedIDs }; }; diff --git a/packages/roomkit-react/src/Prebuilt/components/hooks/useSetPinnedMessages.ts b/packages/roomkit-react/src/Prebuilt/components/hooks/useSetPinnedMessages.ts index 4a39bfd0c2..973a5ddb94 100644 --- a/packages/roomkit-react/src/Prebuilt/components/hooks/useSetPinnedMessages.ts +++ b/packages/roomkit-react/src/Prebuilt/components/hooks/useSetPinnedMessages.ts @@ -54,14 +54,9 @@ export const useSetPinnedMessages = () => { ); const unpinBlacklistedMessages = useCallback( - async ( - pinnedMessages: PinnedMessage[] = [], - blacklistedPeerIDSet: Set, - blacklistedMessageIDSet: Set, - ) => { + async (pinnedMessages: PinnedMessage[] = [], blacklistedMessageIDSet: Set) => { const filteredPinnedMessages = pinnedMessages?.filter( - pinnedMessage => - !blacklistedMessageIDSet?.has(pinnedMessage.id) && !blacklistedPeerIDSet.has(pinnedMessage.authorId), + pinnedMessage => !blacklistedMessageIDSet?.has(pinnedMessage.id), ); await hmsActions.sessionStore diff --git a/packages/roomkit-react/src/Prebuilt/layouts/SidePane.tsx b/packages/roomkit-react/src/Prebuilt/layouts/SidePane.tsx index ef656fd53e..e785c9e4e0 100644 --- a/packages/roomkit-react/src/Prebuilt/layouts/SidePane.tsx +++ b/packages/roomkit-react/src/Prebuilt/layouts/SidePane.tsx @@ -14,7 +14,6 @@ import { config as cssConfig } from '../../Theme'; import { useSidepaneReset } from '../components/AppData/useSidepane'; import { useRoomLayoutConferencingScreen } from '../provider/roomLayoutProvider/hooks/useRoomLayoutScreen'; import { translateAcross } from '../../utils'; -// @ts-ignore: No implicit Any import { APP_DATA, SIDE_PANE_OPTIONS } from '../common/constants'; const SidePane = ({ diff --git a/packages/roomkit-web/package.json b/packages/roomkit-web/package.json index d2c45a72fa..5e1524fd4b 100644 --- a/packages/roomkit-web/package.json +++ b/packages/roomkit-web/package.json @@ -1,6 +1,6 @@ { "name": "@100mslive/roomkit-web", - "version": "0.0.6", + "version": "0.0.7", "description": "A web component implementation of 100ms Prebuilt component", "keywords": [ "web-components", @@ -28,7 +28,7 @@ "build": "rm -rf dist && node ../../scripts/build-webapp" }, "dependencies": { - "@100mslive/roomkit-react": "0.1.13", + "@100mslive/roomkit-react": "0.1.14", "@r2wc/react-to-web-component": "2.0.2" } }