From e4d5ca64b903ddb6e66d18654413191a2ded456c Mon Sep 17 00:00:00 2001 From: lebaudantoine Date: Mon, 11 Aug 2025 10:17:39 +0200 Subject: [PATCH] =?UTF-8?q?=E2=99=BB=EF=B8=8F(frontend)=20refactor=20prejo?= =?UTF-8?q?in=20screen=20for=20room=20context=20flexibility?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Decouple prejoin components from conference context to enable different behaviors when inside vs outside room environments. Components can now evolve independently with lighter coupling. Refactor layout structure to prepare for upcoming speaker selector introduction. This decoupling allows for more flexible component evolution and cleaner architecture. --- .../src/features/rooms/components/Join.tsx | 72 +++++++++++------- .../rooms/components/join/SelectDevice.tsx | 74 +++++++++++++++++++ .../rooms/components/join/ToggleDevice.tsx | 38 ++++++++++ .../controls/SelectToggleDevice.tsx | 62 ++-------------- .../components/controls/ToggleDevice.tsx | 10 ++- .../livekit/config/ToggleDeviceConfig.ts | 52 +++++++++++++ src/frontend/src/locales/de/rooms.json | 3 + src/frontend/src/locales/en/rooms.json | 3 + src/frontend/src/locales/fr/rooms.json | 3 + src/frontend/src/locales/nl/rooms.json | 3 + src/frontend/src/primitives/buttonRecipe.ts | 14 ++++ 11 files changed, 251 insertions(+), 83 deletions(-) create mode 100644 src/frontend/src/features/rooms/components/join/SelectDevice.tsx create mode 100644 src/frontend/src/features/rooms/components/join/ToggleDevice.tsx create mode 100644 src/frontend/src/features/rooms/livekit/config/ToggleDeviceConfig.ts diff --git a/src/frontend/src/features/rooms/components/Join.tsx b/src/frontend/src/features/rooms/components/Join.tsx index 87354cc7..e4e2014a 100644 --- a/src/frontend/src/features/rooms/components/Join.tsx +++ b/src/frontend/src/features/rooms/components/Join.tsx @@ -5,7 +5,6 @@ import { Screen } from '@/layout/Screen' import { useEffect, useMemo, useRef, useState } from 'react' import { LocalVideoTrack, Track } from 'livekit-client' import { H } from '@/primitives/H' -import { SelectToggleDevice } from '../livekit/components/controls/SelectToggleDevice' import { Field } from '@/primitives/Field' import { Button, Dialog, Text, Form } from '@/primitives' import { VStack } from '@/styled-system/jsx' @@ -29,6 +28,8 @@ import { ApiAccessLevel } from '../api/ApiRoom' import { useLoginHint } from '@/hooks/useLoginHint' import { useSnapshot } from 'valtio' import { openPermissionsDialog, permissionsStore } from '@/stores/permissions' +import { ToggleDevice } from './join/ToggleDevice' +import { SelectDevice } from './join/SelectDevice' const onError = (e: Error) => console.error('ERROR', e) @@ -502,6 +503,33 @@ export const Join = ({ )} +
+ saveAudioInputEnabled(enabled)} + onDeviceError={(error) => console.error(error)} + /> + saveVideoInputEnabled(enabled)} + onDeviceError={(error) => console.error(error)} + /> +
-
- saveAudioInputEnabled(enabled)} - onDeviceError={(error) => console.error(error)} - onActiveDeviceChange={(deviceId) => - saveAudioInputDeviceId(deviceId ?? '') - } - variant="tertiary" +
+
-
- saveVideoInputEnabled(enabled)} - onDeviceError={(error) => console.error(error)} - onActiveDeviceChange={(deviceId) => - saveVideoInputDeviceId(deviceId ?? '') - } - variant="tertiary" +
+
diff --git a/src/frontend/src/features/rooms/components/join/SelectDevice.tsx b/src/frontend/src/features/rooms/components/join/SelectDevice.tsx new file mode 100644 index 00000000..67e17e58 --- /dev/null +++ b/src/frontend/src/features/rooms/components/join/SelectDevice.tsx @@ -0,0 +1,74 @@ +import { + RemixiconComponentType, + RiMicLine, + RiVideoOnLine, +} from '@remixicon/react' +import { useTranslation } from 'react-i18next' +import { useMediaDeviceSelect } from '@livekit/components-react' +import { useMemo } from 'react' +import { Select } from '@/primitives/Select' + +type DeviceItems = Array<{ value: string; label: string }> + +type DeviceConfig = { + icon: RemixiconComponentType +} + +type SelectDeviceProps = { + id?: string + onSubmit?: (id: string) => void + kind: MediaDeviceKind +} + +export const SelectDevice = ({ id, onSubmit, kind }: SelectDeviceProps) => { + const { t } = useTranslation('rooms', { keyPrefix: 'join' }) + + const config = useMemo(() => { + switch (kind) { + case 'audioinput': + return { + icon: RiMicLine, + } + case 'videoinput': + return { + icon: RiVideoOnLine, + } + } + }, [kind]) + + const getDefaultSelectedKey = (items: DeviceItems) => { + if (!items || items.length === 0) return + const defaultItem = + items.find((item) => item.value === 'default') || items[0] + return defaultItem.value + } + + const { + devices: devices, + activeDeviceId: activeDeviceId, + setActiveMediaDevice: setActiveMediaDevice, + } = useMediaDeviceSelect({ kind, requestPermissions: false }) + + const items: DeviceItems = devices + .filter((d) => !!d.deviceId) + .map((d) => ({ + value: d.deviceId, + label: d.label, + })) + + return ( +