diff --git a/client/src/components/ModalWrapper.tsx b/client/src/components/ModalWrapper.tsx index 7e625ea..d6d1873 100644 --- a/client/src/components/ModalWrapper.tsx +++ b/client/src/components/ModalWrapper.tsx @@ -17,7 +17,9 @@ function ModalWrapper({ return (
-
{children}
+
+ {children} +
); } diff --git a/client/src/components/SessionUsersPanel.tsx b/client/src/components/SessionUsersPanel.tsx index 2ab738f..eb9fec7 100644 --- a/client/src/components/SessionUsersPanel.tsx +++ b/client/src/components/SessionUsersPanel.tsx @@ -1,3 +1,4 @@ +/* eslint-disable react-hooks/exhaustive-deps */ import { useState, useRef, useEffect } from "react"; import UserCamera from "./ui/UserCamera"; import UserDevicesControls from "./ui/UserDevicesControls"; @@ -98,7 +99,7 @@ export default function SessionUsersPanel() { window.removeEventListener("mousemove", handleMouseMove); window.removeEventListener("mouseup", handleMouseUp); }; - }, [isDragging]); + }, [handleMouseMove, handleMouseUp, isDragging]); const getStyle = (): React.CSSProperties => { if (isDragging) { diff --git a/client/src/components/modals/SettingsModal.tsx b/client/src/components/modals/SettingsModal.tsx index 457af3b..283aedf 100644 --- a/client/src/components/modals/SettingsModal.tsx +++ b/client/src/components/modals/SettingsModal.tsx @@ -13,6 +13,7 @@ import useModalStore from "../../store/modalStore"; import SoundCheckModal from "./SoundCheckModal"; import VoiceCheckModal from "./VoiceCheckModal"; import LoaderIcon from "../icons/LoaderIcon"; +import { isMediaDevicesSupported } from "../../lib/mediaDevices"; interface MediaDevice { deviceId: string; @@ -34,6 +35,7 @@ function SettingsModal() { const [selectedCamera, setSelectedCamera] = useState(""); const [mediaType, setMediaType] = useState<"sound" | "video">("sound"); + const [mediaApiUnavailable, setMediaApiUnavailable] = useState(false); const [participantsVideosHidden, setParticipantsVideosHidden] = useState(false); @@ -66,6 +68,17 @@ function SettingsModal() { setIsLoadingMicrophones(true); setIsLoadingSpeakers(true); + // Проверяем доступность API + if (!isMediaDevicesSupported()) { + console.error( + "navigator.mediaDevices недоступен. Возможно, требуется HTTPS или поддержка браузера." + ); + setMediaApiUnavailable(true); + setIsLoadingMicrophones(false); + setIsLoadingSpeakers(false); + return; + } + try { // Запрашиваем разрешения на аудио const stream = await navigator.mediaDevices.getUserMedia({ @@ -150,6 +163,15 @@ function SettingsModal() { async function loadVideoDevices() { setIsLoadingCameras(true); + // Проверяем доступность API + if (!isMediaDevicesSupported()) { + console.error( + "navigator.mediaDevices недоступен. Возможно, требуется HTTPS или поддержка браузера." + ); + setIsLoadingCameras(false); + return; + } + try { // Запрашиваем разрешения на видео const stream = await navigator.mediaDevices.getUserMedia({ @@ -214,6 +236,15 @@ function SettingsModal() { // Запуск видео async function startVideoTest() { + // Проверяем доступность API + if (!isMediaDevicesSupported()) { + console.error( + "navigator.mediaDevices недоступен. Возможно, требуется HTTPS или поддержка браузера." + ); + setIsVideoTestingError(true); + return; + } + try { setIsVideoTestingLoading(true); setIsVideoTestingError(false); @@ -257,14 +288,20 @@ function SettingsModal() { } }; - navigator.mediaDevices.addEventListener("devicechange", handleDeviceChange); - - return () => { - navigator.mediaDevices.removeEventListener( + // Добавляем слушатель только если API доступен + if (isMediaDevicesSupported()) { + navigator.mediaDevices.addEventListener( "devicechange", handleDeviceChange ); - }; + + return () => { + navigator.mediaDevices.removeEventListener( + "devicechange", + handleDeviceChange + ); + }; + } }, [mediaType]); // Загружаем видео устройства и запускаем видео при переключении на вкладку "Видео" @@ -358,6 +395,17 @@ function SettingsModal() {

Видео

+ {mediaApiUnavailable && ( +
+

+ MediaDevices API недоступен +

+

+ Для работы с медиа-устройствами требуется безопасное соединение + (HTTPS) или localhost. Проверьте настройки сервера и браузера. +

+
+ )} {mediaType === "sound" && (
diff --git a/client/src/components/modals/SoundCheckModal.tsx b/client/src/components/modals/SoundCheckModal.tsx index df287b8..a786f10 100644 --- a/client/src/components/modals/SoundCheckModal.tsx +++ b/client/src/components/modals/SoundCheckModal.tsx @@ -64,7 +64,7 @@ function SoundCheckModal({ return ( -
+

Динамик