From 24ab5b0ae337b2de2456b460142378b8702305ab Mon Sep 17 00:00:00 2001 From: lebaudantoine Date: Tue, 28 Jul 2026 10:02:39 +0200 Subject: [PATCH] introduce a promote menu item --- .../components/ParticipantRow.tsx | 8 +++- .../components/menu/ParticipantMenu.tsx | 32 +++++++++++-- .../components/menu/ParticipantMenuButton.tsx | 3 -- .../components/menu/items/PromoteMenuItem.tsx | 47 +++++++++++++++++++ .../components/menu/items/RemoveMenuItem.tsx | 47 +++++++++++-------- .../features/rooms/api/removeParticipant.ts | 5 +- src/frontend/src/locales/de/rooms.json | 9 ++++ src/frontend/src/locales/en/rooms.json | 9 ++++ src/frontend/src/locales/fr/rooms.json | 9 ++++ src/frontend/src/locales/nl/rooms.json | 9 ++++ 10 files changed, 146 insertions(+), 32 deletions(-) create mode 100644 src/frontend/src/features/participants/components/menu/items/PromoteMenuItem.tsx diff --git a/src/frontend/src/features/participants/components/ParticipantRow.tsx b/src/frontend/src/features/participants/components/ParticipantRow.tsx index a5ddd2a5..45204231 100644 --- a/src/frontend/src/features/participants/components/ParticipantRow.tsx +++ b/src/frontend/src/features/participants/components/ParticipantRow.tsx @@ -5,7 +5,10 @@ import { Text } from '@/primitives/Text' import { useTranslation } from 'react-i18next' import { Avatar } from '@/components/Avatar' import { getParticipantColor } from '@/features/rooms/utils/getParticipantColor' -import { getParticipantIsRoomOwner } from '@/features/rooms/utils/getParticipantIsRoomAdminOrOwner' +import { + getParticipantIsRoomAdmin, + getParticipantIsRoomOwner, +} from '@/features/rooms/utils/getParticipantIsRoomAdminOrOwner' import { type LocalParticipant, type Participant, Track } from 'livekit-client' import { isLocal } from '@/utils/livekit' import { @@ -149,6 +152,9 @@ export const ParticipantRow = ({ participant }: ParticipantListItemProps) => { {getParticipantIsRoomOwner(participant) && ( {t('participants.host')} )} + {getParticipantIsRoomAdmin(participant) && ( + {t('participants.cohost')} + )} diff --git a/src/frontend/src/features/participants/components/menu/ParticipantMenu.tsx b/src/frontend/src/features/participants/components/menu/ParticipantMenu.tsx index 2cc6397e..bdba8cbd 100644 --- a/src/frontend/src/features/participants/components/menu/ParticipantMenu.tsx +++ b/src/frontend/src/features/participants/components/menu/ParticipantMenu.tsx @@ -1,24 +1,46 @@ import { Menu as RACMenu } from 'react-aria-components' import type { Participant } from 'livekit-client' -import { useIsAdminOrOwner } from '@/features/rooms/livekit/hooks/useIsAdminOrOwner' import { PinMenuItem } from './items/PinMenuItem' import { RemoveMenuItem } from './items/RemoveMenuItem' +import { PromoteMenuItem } from './items/PromoteMenuItem' +import { useIsAdminOrOwner } from '@/features/rooms/livekit/hooks/useIsAdminOrOwner' +import { useParticipantAttributes } from '@livekit/components-react' export const ParticipantMenu = ({ participant, }: { participant: Participant }) => { - const isAdminOrOwner = useIsAdminOrOwner() - const canModerateParticipant = !participant.isLocal && isAdminOrOwner + const isLocalUserAdminOrOwner = useIsAdminOrOwner() + + const { attributes } = useParticipantAttributes({ participant }) + + const isAdmin = attributes?.room_role === 'administrator' + const isOwner = attributes?.room_role === 'owner' + const isAuthenticated = attributes?.is_authenticated == 'true' + + const canManage = !participant.isLocal && isLocalUserAdminOrOwner && !isOwner + return ( - {canModerateParticipant && } + {canManage && ( + + )} + {canManage && isAuthenticated && ( + + )} ) } diff --git a/src/frontend/src/features/participants/components/menu/ParticipantMenuButton.tsx b/src/frontend/src/features/participants/components/menu/ParticipantMenuButton.tsx index 900fd2a8..197b1244 100644 --- a/src/frontend/src/features/participants/components/menu/ParticipantMenuButton.tsx +++ b/src/frontend/src/features/participants/components/menu/ParticipantMenuButton.tsx @@ -1,7 +1,6 @@ import { Button, Menu } from '@/primitives' import { RiMore2Fill } from '@remixicon/react' import { ParticipantMenu } from './ParticipantMenu' -import { useIsAdminOrOwner } from '@/features/rooms/livekit/hooks/useIsAdminOrOwner' import type { Participant } from 'livekit-client' import { useTranslation } from 'react-i18next' @@ -11,8 +10,6 @@ export const ParticipantMenuButton = ({ participant: Participant }) => { const { t } = useTranslation('rooms', { keyPrefix: 'participants' }) - const isAdminOrOwner = useIsAdminOrOwner() - if (!isAdminOrOwner) return null return (