From 3d3242e148f946fa11bd877c7139b5a4880d4e23 Mon Sep 17 00:00:00 2001 From: lebaudantoine Date: Thu, 28 Aug 2025 15:47:06 +0200 Subject: [PATCH] =?UTF-8?q?=F0=9F=9A=B8(frontend)=20disable=20device=20con?= =?UTF-8?q?trols=20when=20user=20lacks=20room=20permissions?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Update user experience by clearly marking device toggle and control components as disabled when users have insufficient room permissions. Prevents confusion by providing visual feedback that device controls are unavailable, improving clarity about what actions users can perform in their current role. --- src/frontend/panda.config.ts | 1 + .../controls/Device/AudioDevicesControl.tsx | 11 +++++++++-- .../components/controls/Device/ToggleDevice.tsx | 11 +++++++++-- .../controls/Device/VideoDeviceControl.tsx | 8 +++++++- .../components/controls/ScreenShareToggle.tsx | 5 +++++ .../rooms/livekit/hooks/useCanPublishTrack.ts | 17 +++++++++++++++++ src/frontend/src/primitives/buttonRecipe.ts | 8 ++++++-- 7 files changed, 54 insertions(+), 7 deletions(-) create mode 100644 src/frontend/src/features/rooms/livekit/hooks/useCanPublishTrack.ts diff --git a/src/frontend/panda.config.ts b/src/frontend/panda.config.ts index e083b055..aba8d84c 100644 --- a/src/frontend/panda.config.ts +++ b/src/frontend/panda.config.ts @@ -124,6 +124,7 @@ const config: Config = { ...pandaPreset.theme.tokens.colors, primaryDark: { 50: { value: '#161622' }, + 75: { value: '#222234' }, 100: { value: '#2D2D46' }, 200: { value: '#43436A' }, 300: { value: '#5A5A8F' }, diff --git a/src/frontend/src/features/rooms/livekit/components/controls/Device/AudioDevicesControl.tsx b/src/frontend/src/features/rooms/livekit/components/controls/Device/AudioDevicesControl.tsx index 39ecde7d..ca6e9548 100644 --- a/src/frontend/src/features/rooms/livekit/components/controls/Device/AudioDevicesControl.tsx +++ b/src/frontend/src/features/rooms/livekit/components/controls/Device/AudioDevicesControl.tsx @@ -7,12 +7,14 @@ import { Track } from 'livekit-client' import { ToggleDevice } from './ToggleDevice' import { css } from '@/styled-system/css' import { usePersistentUserChoices } from '../../../hooks/usePersistentUserChoices' +import { useCanPublishTrack } from '../../../hooks/useCanPublishTrack' import { useCannotUseDevice } from '../../../hooks/useCannotUseDevice' -import Source = Track.Source import * as React from 'react' import { SelectDevice } from './SelectDevice' import { SettingsButton } from './SettingsButton' import { SettingsDialogExtendedKey } from '@/features/settings/type' +import { TrackSource } from '@livekit/protocol' +import Source = Track.Source type AudioDevicesControlProps = Omit< UseTrackToggleProps, @@ -50,6 +52,8 @@ export const AudioDevicesControl = ({ const cannotUseDevice = useCannotUseDevice(kind) const selectLabel = t(`settings.${SettingsDialogExtendedKey.AUDIO}`) + const canPublishTrack = useCanPublishTrack(TrackSource.MICROPHONE) + return (
Promise} overrideToggleButtonProps={{ @@ -77,7 +82,9 @@ export const AudioDevicesControl = ({ groupPosition="right" square variant={ - trackProps.enabled && !cannotUseDevice ? 'primaryDark' : 'error2' + !canPublishTrack || !trackProps.enabled || cannotUseDevice + ? 'error2' + : 'primaryDark' } > diff --git a/src/frontend/src/features/rooms/livekit/components/controls/Device/ToggleDevice.tsx b/src/frontend/src/features/rooms/livekit/components/controls/Device/ToggleDevice.tsx index b6770ca3..bd77f87d 100644 --- a/src/frontend/src/features/rooms/livekit/components/controls/Device/ToggleDevice.tsx +++ b/src/frontend/src/features/rooms/livekit/components/controls/Device/ToggleDevice.tsx @@ -27,6 +27,7 @@ type ToggleDeviceStyleProps = { export type ToggleDeviceProps = { enabled: boolean + isDisabled?: boolean toggle: ( forceState?: boolean, captureOptions?: CaptureOptionsBySource @@ -39,6 +40,7 @@ export type ToggleDeviceProps = { export const ToggleDevice = ({ kind, enabled, + isDisabled, toggle, context = 'room', overrideToggleButtonProps, @@ -105,7 +107,9 @@ export const ToggleDevice = ({ }, [enabled, kind, deviceShortcut, t]) const Icon = - enabled && !cannotUseDevice ? deviceIcons.toggleOn : deviceIcons.toggleOff + isDisabled || cannotUseDevice || !enabled + ? deviceIcons.toggleOff + : deviceIcons.toggleOn const roomContext = useMaybeRoomContext() if (kind === 'audioinput' && pushToTalk && roomContext) { @@ -117,7 +121,10 @@ export const ToggleDevice = ({ {cannotUseDevice && } (cannotUseDevice ? openPermissionsDialog() : toggle())} aria-label={toggleLabel} diff --git a/src/frontend/src/features/rooms/livekit/components/controls/Device/VideoDeviceControl.tsx b/src/frontend/src/features/rooms/livekit/components/controls/Device/VideoDeviceControl.tsx index 8b821705..918bab5e 100644 --- a/src/frontend/src/features/rooms/livekit/components/controls/Device/VideoDeviceControl.tsx +++ b/src/frontend/src/features/rooms/livekit/components/controls/Device/VideoDeviceControl.tsx @@ -7,6 +7,7 @@ import { Track, VideoCaptureOptions } from 'livekit-client' import { ToggleDevice } from './ToggleDevice' import { css } from '@/styled-system/css' import { usePersistentUserChoices } from '../../../hooks/usePersistentUserChoices' +import { useCanPublishTrack } from '../../../hooks/useCanPublishTrack' import { useCannotUseDevice } from '../../../hooks/useCannotUseDevice' import { useSidePanel } from '../../../hooks/useSidePanel' import { BackgroundProcessorFactory } from '../../blur' @@ -15,6 +16,7 @@ import * as React from 'react' import { SelectDevice } from './SelectDevice' import { SettingsButton } from './SettingsButton' import { SettingsDialogExtendedKey } from '@/features/settings/type' +import { TrackSource } from '@livekit/protocol' const EffectsButton = ({ onPress }: { onPress: () => void }) => { const { t } = useTranslation('rooms', { keyPrefix: 'selectDevice' }) @@ -95,6 +97,7 @@ export const VideoDeviceControl = ({ } const selectLabel = t(`settings.${SettingsDialogExtendedKey.VIDEO}`) + const canPublishTrack = useCanPublishTrack(TrackSource.CAMERA) return (
diff --git a/src/frontend/src/features/rooms/livekit/components/controls/ScreenShareToggle.tsx b/src/frontend/src/features/rooms/livekit/components/controls/ScreenShareToggle.tsx index 1ac1c905..620f12de 100644 --- a/src/frontend/src/features/rooms/livekit/components/controls/ScreenShareToggle.tsx +++ b/src/frontend/src/features/rooms/livekit/components/controls/ScreenShareToggle.tsx @@ -6,6 +6,8 @@ import { Track } from 'livekit-client' import React from 'react' import { type ButtonRecipeProps } from '@/primitives/buttonRecipe' import { ToggleButtonProps } from '@/primitives/ToggleButton' +import { TrackSource } from '@livekit/protocol' +import { useCanPublishTrack } from '@/features/rooms/livekit/hooks/useCanPublishTrack' type Props = Omit< UseTrackToggleProps, @@ -29,10 +31,13 @@ export const ScreenShareToggle = ({ const tooltipLabel = enabled ? 'stop' : 'start' const Icon = enabled ? RiCloseFill : RiArrowUpLine + const canShareScreen = useCanPublishTrack(TrackSource.SCREEN_SHARE) + // fixme - remove ToggleButton custom styles when we design a proper icon return (