import React, { FormEventHandler, useCallback, useState } from 'react'; import { Box, Button, color, Input, Spinner, Text, } from 'folds'; import { SequenceCard } from '../../../components/sequence-card'; import { SequenceCardStyle } from '../../room-settings/styles.css'; import { SettingTile } from '../../../components/setting-tile'; import { useRoom } from '../../../hooks/useRoom'; import { useStateEvent } from '../../../hooks/useStateEvent'; import { AsyncStatus, useAsyncCallback } from '../../../hooks/useAsyncCallback'; import { useMatrixClient } from '../../../hooks/useMatrixClient'; import { usePowerLevels } from '../../../hooks/usePowerLevels'; import { useRoomCreators } from '../../../hooks/useRoomCreators'; import { useRoomPermissions } from '../../../hooks/useRoomPermissions'; import { StateEvent } from '../../../../types/matrix/room'; interface LivekitConfigContent { service_url?: string; } /** * Room-specific LiveKit configuration component. * Allows room admins to override the LiveKit service URL for calls in this room. */ export function LivekitConfig() { const mx = useMatrixClient(); const room = useRoom(); const powerLevels = usePowerLevels(room); const creators = useRoomCreators(room); const permissions = useRoomPermissions(creators, powerLevels); const stateEvent = useStateEvent(room, StateEvent.RoomLivekitConfig); const currentConfig = stateEvent?.getContent(); const currentUrl = currentConfig?.service_url || ''; const [urlValue, setUrlValue] = useState(currentUrl); const [urlError, setUrlError] = useState(); const [saveState, saveConfig] = useAsyncCallback( useCallback( async (serviceUrl: string) => { const content: LivekitConfigContent = serviceUrl ? { service_url: serviceUrl } : {}; await mx.sendStateEvent(room.roomId, StateEvent.RoomLivekitConfig as any, content, ''); }, [mx, room] ) ); const canEdit = permissions.stateEvent(StateEvent.RoomLivekitConfig, mx.getUserId()!); const handleSave: FormEventHandler = async (evt) => { evt.preventDefault(); const serviceUrl = urlValue.trim(); // Basic URL validation if (serviceUrl && !serviceUrl.startsWith('http://') && !serviceUrl.startsWith('https://')) { setUrlError('URL must start with http:// or https://'); return; } setUrlError(undefined); await saveConfig(serviceUrl); }; const handleClear = async () => { setUrlValue(''); setUrlError(undefined); await saveConfig(''); }; const hasChanges = urlValue !== currentUrl; const isSaving = saveState.status === AsyncStatus.Loading; return ( ) => { setUrlValue(e.target.value); setUrlError(undefined); }} placeholder="https://example.com/livekit/jwt" size="300" variant="Secondary" radii="300" disabled={!canEdit || isSaving} style={{ width: '100%' }} /> {urlError && ( {urlError} )} {saveState.status === AsyncStatus.Error && ( Failed to save: {saveState.error instanceof Error ? saveState.error.message : 'Unknown error'} )} {saveState.status === AsyncStatus.Success && !hasChanges && ( Configuration saved )} {currentUrl && ( )} {!canEdit && ( You don't have permission to change this setting )} ); }