From f1d4248123644d28513b776ef635233f8db7dc81 Mon Sep 17 00:00:00 2001 From: Arthurk12 Date: Fri, 15 May 2026 13:25:16 -0300 Subject: [PATCH 1/3] fix: filter out bot users from random selection Bot users can be randomly selected by the pick random user feature, which is not the desired behavior. Filter out users with the bot flag from the pool of selectable users. Inspired by 23a44d4f653d. --- src/components/pick-random-user-panel/component.tsx | 2 +- src/components/pick-random-user-panel/queries.ts | 4 +++- src/components/pick-random-user/types.ts | 1 + 3 files changed, 5 insertions(+), 2 deletions(-) diff --git a/src/components/pick-random-user-panel/component.tsx b/src/components/pick-random-user-panel/component.tsx index 91a4e84..80183fc 100644 --- a/src/components/pick-random-user-panel/component.tsx +++ b/src/components/pick-random-user-panel/component.tsx @@ -145,7 +145,7 @@ export function PickRandomUserPanelComponent(props: PickRandomUserPanelComponent includePickedUsers, ]); - const usersToBePicked: PickedUser[] = allUsers?.user + const usersToBePicked: PickedUser[] = (allUsers?.user ?? []).filter((user) => !user.bot) .filter((user) => { let roleFilter = true; if (!includeModerators) roleFilter = user.role === Role.VIEWER; diff --git a/src/components/pick-random-user-panel/queries.ts b/src/components/pick-random-user-panel/queries.ts index 95821a0..1d74b56 100644 --- a/src/components/pick-random-user-panel/queries.ts +++ b/src/components/pick-random-user-panel/queries.ts @@ -1,11 +1,13 @@ +// TODO: Replace this query with the useUsersBasicInfo once it's merged in export const USERS_MORE_INFORMATION = ` subscription usersMoreInformation { - user { + user(where: { bot: { _eq: false } }) { color name userId role presenter + bot } } `; diff --git a/src/components/pick-random-user/types.ts b/src/components/pick-random-user/types.ts index 9e73b4d..01d1338 100644 --- a/src/components/pick-random-user/types.ts +++ b/src/components/pick-random-user/types.ts @@ -8,6 +8,7 @@ export interface PickedUser { name: string; role: string; color: string; + bot: boolean; } export interface PickedUserWithEntryId { From 6035191db17f966bca01a6e9de1baa7ccc625aed Mon Sep 17 00:00:00 2001 From: Arthurk12 Date: Fri, 15 May 2026 13:48:57 -0300 Subject: [PATCH 2/3] fix: auto-close picked user modal for bot users When a user is picked, a modal is displayed for all participants, including bots. Bots cannot interact with the close button, leaving the modal open and covering other meeting elements indefinitely. Add a 5-second timeout to automatically close the modal for bot users. --- src/components/modal/component.tsx | 57 +++++++++++++++---- src/components/modal/styles.ts | 22 +++++++ src/components/modal/types.ts | 1 + src/components/pick-random-user/component.tsx | 6 ++ src/components/pick-random-user/queries.ts | 7 +++ src/components/pick-random-user/types.ts | 8 +++ 6 files changed, 90 insertions(+), 11 deletions(-) create mode 100644 src/components/pick-random-user/queries.ts diff --git a/src/components/modal/component.tsx b/src/components/modal/component.tsx index 41d73c4..ab9a14e 100644 --- a/src/components/modal/component.tsx +++ b/src/components/modal/component.tsx @@ -1,4 +1,5 @@ import * as React from 'react'; +import { useEffect, useState } from 'react'; import { PickUserModalProps } from './types'; import { PickedUserViewComponent } from './picked-user-view/component'; import Styled from './styles'; @@ -13,10 +14,37 @@ export function PickUserModal(props: PickUserModalProps) { updatePickedRandomUser, pickedUserWithEntryId, currentUser, + isBot, } = props; + const [progress, setProgress] = useState(0); + const isYou = (pickedUserWithEntryId?.pickedUser?.userId === currentUser?.userId); + useEffect(() => { + if (isBot && showModal) { + setProgress(0); + const startTime = Date.now(); + const duration = 5000; // Modal will be displayed for 5 seconds + + const interval = setInterval(() => { + const elapsed = Date.now() - startTime; + const newProgress = (elapsed / duration) * 100; + + if (newProgress >= 100) { + setProgress(100); + clearInterval(interval); + handleCloseModal(); + } else { + setProgress(newProgress); + } + }, 30); + + return () => clearInterval(interval); + } + return () => {}; + }, [isBot, showModal, handleCloseModal]); + const title = isYou ? intl.formatMessage(intlMessages.youWerePicked) : intl.formatMessage(intlMessages.pickedUser); @@ -28,17 +56,19 @@ export function PickUserModal(props: PickUserModalProps) { onRequestClose={handleCloseModal} > - { - handleCloseModal(); - }} - aria-label={intl.formatMessage(intlMessages.closeButton)} - > - - + {!isBot && ( + { + handleCloseModal(); + }} + aria-label={intl.formatMessage(intlMessages.closeButton)} + > + + + )} + {isBot && showModal && ( + + + + )} ); } diff --git a/src/components/modal/styles.ts b/src/components/modal/styles.ts index f19d6ed..8e3df84 100644 --- a/src/components/modal/styles.ts +++ b/src/components/modal/styles.ts @@ -1,5 +1,6 @@ import styled from 'styled-components'; import ReactModal from 'react-modal'; +import { colorGrayLightest, colorPrimary } from '../../styles/pallete'; const PluginModal = styled(ReactModal)` position: relative; @@ -95,9 +96,30 @@ const ButtonClose = styled.button` } `; +const ProgressBarContainer = styled.div` + position: absolute; + bottom: 0; + left: 0; + right: 0; + height: 4px; + background-color: ${colorGrayLightest}; + border-bottom-left-radius: 8px; + border-bottom-right-radius: 8px; + overflow: hidden; +`; + +const ProgressBarFill = styled.div<{ progress: number }>` + height: 100%; + background-color: ${colorPrimary}; + width: ${({ progress }) => `${progress}%`}; + transition: width 0.03s linear; +`; + export default { PluginModal, ModalOverlay, ModalContainer, ButtonClose, + ProgressBarContainer, + ProgressBarFill, }; diff --git a/src/components/modal/types.ts b/src/components/modal/types.ts index 564d2d5..2ed4937 100644 --- a/src/components/modal/types.ts +++ b/src/components/modal/types.ts @@ -10,4 +10,5 @@ export interface PickUserModalProps { handleCloseModal: () => void; pickedUserWithEntryId: PickedUserWithEntryId; currentUser: CurrentUserData; + isBot: boolean; } diff --git a/src/components/pick-random-user/component.tsx b/src/components/pick-random-user/component.tsx index 4069fd5..f3c4cb1 100644 --- a/src/components/pick-random-user/component.tsx +++ b/src/components/pick-random-user/component.tsx @@ -4,12 +4,14 @@ import * as ReactDOM from 'react-dom/client'; import { GenericContentSidekickArea } from 'bigbluebutton-html-plugin-sdk'; import { + BotDataWrapper, PickRandomUserPluginProps, PickedUser, PickedUserWithEntryId, } from './types'; import { PickUserModal } from '../modal/component'; import { Role } from './enums'; +import { BOT_SUBSCRIPTION } from './queries'; import { PickRandomUserPanelComponent } from '../pick-random-user-panel/component'; import { intlMessages } from '../../intlMessages'; @@ -23,6 +25,9 @@ function PickRandomUserPlugin({ pluginApi, intl }: PickRandomUserPluginProps) { const shouldPluginUnmount = pluginApi.useShouldUnmountPlugin(); const currentUserInfo = pluginApi.useCurrentUser(); const { data: currentUser } = currentUserInfo; + const { data: botData } = pluginApi + .useCustomSubscription!(BOT_SUBSCRIPTION) || {}; + const isBot = botData?.user_current?.[0]?.bot || false; const { data: pickedUserFromDataChannelResponse, @@ -105,6 +110,7 @@ function PickRandomUserPlugin({ pluginApi, intl }: PickRandomUserPluginProps) { if (!pickedUserWithEntryId) return null; return !shouldPluginUnmount && ( []; } + +export interface BotData { + bot: boolean +} + +export interface BotDataWrapper { + user_current: BotData[]; +} From 51cfdb007533a65a509fe9e33517f45dcd4a2731 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Victor?= Date: Thu, 4 Sep 2025 10:24:53 -0300 Subject: [PATCH 3/3] fix: Render modal in core container element with low priority --- src/components/modal/component.tsx | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/components/modal/component.tsx b/src/components/modal/component.tsx index ab9a14e..13ee0d0 100644 --- a/src/components/modal/component.tsx +++ b/src/components/modal/component.tsx @@ -49,9 +49,13 @@ export function PickUserModal(props: PickUserModalProps) { ? intl.formatMessage(intlMessages.youWerePicked) : intl.formatMessage(intlMessages.pickedUser); + if (!showModal) return null; + return ( document.querySelector('#modals-container') as HTMLElement} isOpen={showModal} onRequestClose={handleCloseModal} >