-
}
- onlyIcon
- onClick={() => setIsShowMore((prev) => !prev)}
- className="group relative"
- >
- {tooltip &&
}
-
+
+
+
{user.name[0]?.toUpperCase()}
+ {user?.isControlAllowed && (
+
+ )}
+
+
{user.name}
+
+ {isMobile ? : }
+
- {isShowMore && (
-
-
diff --git a/src/main.tsx b/src/main.tsx
index 43cff56..f60c714 100644
--- a/src/main.tsx
+++ b/src/main.tsx
@@ -7,8 +7,7 @@ import App from "./App";
// import ErrorBoundary from "./ErrorBoundary";
import HistoryPage from "./HistoryPage";
import ScheduledPage from "./ScheduledPage";
-// import StreamPage2 from "./pages/StreamPage2";
-import StreamPage3 from "./pages/StreamPage3";
+import StreamPage from "./pages/StreamPage";
const router = createBrowserRouter([
{
@@ -18,7 +17,7 @@ const router = createBrowserRouter([
},
{
path: "/stream/:id",
- element:
,
+ element:
,
},
{
path: "/history",
diff --git a/src/pages/StreamPage3.tsx b/src/pages/StreamPage.tsx
similarity index 86%
rename from src/pages/StreamPage3.tsx
rename to src/pages/StreamPage.tsx
index 1ebe3e6..dd1a699 100644
--- a/src/pages/StreamPage3.tsx
+++ b/src/pages/StreamPage.tsx
@@ -43,13 +43,14 @@ import DesktopIcon from "../components/icons/DesktopIcon";
import MobileIcon from "../components/icons/MobileIcon";
import ChatIcon from "../components/icons/ChatIcon";
import useChatStore from "../stores/useChatStore";
+import User from "../components/User";
// import ChatIcon from "../components/icons/ChatIcon";
// import MoreIcon from "../components/icons/MoreIcon";
const userId = uuidv4();
-function StreamPage3() {
+function StreamPage() {
const params = useParams();
const [searchParams] = useSearchParams();
const [WSUrl, setWSUrl] = useState
("");
@@ -218,6 +219,17 @@ function StreamPage3() {
toast.info(`Вы получили разрешение на управление`);
});
+ socket.on("kick", (userId) => {
+ if (useStreamUserStore.getState().me?.id !== userId) return;
+
+ window.close();
+ socket.disconnect();
+ setPeerInstance(undefined);
+ setWSUrl("");
+ setUsers([]);
+ setRemoteStreams([]);
+ });
+
socket.on("message", ({ userId, text }) => {
setMessages([...useChatStore.getState().messages, { userId, text }]);
});
@@ -289,10 +301,13 @@ function StreamPage3() {
}
function requestControl(userId: string) {
- console.log("requestControl func", userId);
socket?.emit("request-control", userId);
}
+ function kick(userId: string) {
+ socket?.emit("kick", userId);
+ }
+
async function getActiveSession() {
const activeSession: any = await api
.get(`activeSessions/${params.id}`)
@@ -443,50 +458,22 @@ function StreamPage3() {
- {users.map((user) => {
- if (user.id !== userId) {
- return (
-
-
-
- {name[0]?.toUpperCase()}
-
- {user?.isControlAllowed && (
-
- )}
-
-
{user.name}
-
- {isMobile ? : }
-
-
- {me?.isAdmin && me?.isControlAllowed && (
-
- {/*
}
- onlyIcon
- /> */}
- {/*
*/}
-
- }
- onlyIcon
- onClick={() => transferControl(user.id)}
- />
-
-
- {/*
*/}
-
- )}
-
- );
- }
- })}
+ {me &&
+ users.map((user) => {
+ if (user.id !== userId) {
+ return (
+
transferControl(user.id)}
+ handleKick={() => kick(user.id)}
+ />
+ );
+ }
+ })}
-
@@ -607,4 +597,4 @@ function StreamPage3() {
);
}
-export default StreamPage3;
+export default StreamPage;
diff --git a/src/pages/StreamPage2.css b/src/pages/StreamPage2.css
deleted file mode 100644
index 991cda3..0000000
--- a/src/pages/StreamPage2.css
+++ /dev/null
@@ -1,33 +0,0 @@
-.entering {
- opacity: 1;
-}
-
-.entered {
- opacity: 1;
-}
-
-.exiting {
- opacity: 0;
-}
-
-.exited {
- opacity: 0;
-}
-
-:root {
- --toastify-toast-offset: 52px;
-}
-
-.Toastify__toast-body {
- padding: 0;
- margin: 0 4px 0 0;
- align-items: normal;
- font-family: "Inter", sans-serif;
- font-size: 14px;
- color: #111c26;
-}
-
-.Toastify__toast-icon {
- width: auto;
- margin-inline-end: 8px;
-}
diff --git a/src/pages/StreamPage2.tsx b/src/pages/StreamPage2.tsx
deleted file mode 100644
index 71fe581..0000000
--- a/src/pages/StreamPage2.tsx
+++ /dev/null
@@ -1,1234 +0,0 @@
-/* eslint-disable @typescript-eslint/no-unused-vars */
-/* eslint-disable react-hooks/rules-of-hooks */
-/* eslint-disable @typescript-eslint/no-non-null-assertion */
-/* eslint-disable @typescript-eslint/no-explicit-any */
-/* eslint-disable react-hooks/exhaustive-deps */
-import "./StreamPage2.css";
-import { PixelStreamingWrapper } from "../components/PixelStreamingWrapper";
-import { useParams, useSearchParams } from "react-router-dom";
-import { FormEvent, useEffect, useRef } from "react";
-import { Transition } from "react-transition-group";
-import Button from "../components/ui/Button";
-// import CloseIcon from "../components/icons/CloseIcon";
-import HandOffIcon from "../components/icons/HandOffIcon";
-// import MicroOffIcon from "../components/icons/MicroOffIcon";
-import PersonsIcon from "../components/icons/PersonsIcon";
-import MicroOnIcon from "../components/icons/MicroOnIcon";
-// import MoreIcon from "../components/icons/MoreIcon";
-import FullscreenIcon from "../components/icons/FullscreenIcon";
-import WindowIcon from "../components/icons/WindowIcon";
-import ChatIcon from "../components/icons/ChatIcon";
-import ShareIcon from "../components/icons/ShareIcon";
-// import GearIcon from "../components/icons/GearIcon";
-import { useFullscreen } from "ahooks";
-import api from "../utils/api";
-import { Socket, io } from "socket.io-client";
-import { v4 as uuidv4 } from "uuid";
-import HandOnIcon from "../components/icons/HandOnIcon";
-import User from "../components/User";
-import Tooltip from "../components/Tooltip";
-import { Bounce, ToastContainer, toast } from "react-toastify";
-import "react-toastify/dist/ReactToastify.css";
-import InfoBlueIcon from "../components/icons/InfoBlueIcon";
-import CloseIcon from "../components/icons/CloseIcon";
-import SendChatIcon from "../components/icons/SendChatIcon";
-import UserIcon from "../components/icons/UserIcon";
-import { isIOS, isMobile, useMobileOrientation } from "react-device-detect";
-import LinkIcon from "../components/icons/LinkIcon";
-import removeSpaces from "../utils/removeSpaces";
-import MobileIcon from "../components/icons/MobileIcon";
-import DesktopIcon from "../components/icons/DesktopIcon";
-import { format } from "date-fns";
-import IUser from "../types/IUser";
-import IMessage from "../types/IMessage";
-import InfoIcon from "../components/icons/InfoIcon";
-import Rotate64Icon from "../components/icons/Rotate64Icon";
-import { useClipboard } from "use-clipboard-copy";
-import QRCode from "react-qr-code";
-import Star12Icon from "../components/icons/Star12Icon";
-import { Trans, useTranslation } from "react-i18next";
-import Countdown from "react-countdown";
-import useStreamStore from "../stores/useStreamStore";
-import Peer from "peerjs";
-import Video from "../components/Video";
-import MicroOffIcon from "../components/icons/MicroOffIcon";
-import useIsAudioActive from "use-is-audio-active";
-import CameraOffIcon from "../components/icons/CameraOffIcon";
-import CameraOnIcon from "../components/icons/CameraOnIcon";
-import useState from "react-usestateref";
-
-const renderer = ({ minutes, seconds }: any) => {
- return (
- <>
- {String(minutes).padStart(2, "0")}:{String(seconds).padStart(2, "0")}
- >
- );
-};
-
-interface IRemoteStream {
- peerId: string;
- mediaStream: MediaStream;
-}
-
-function StreamPage2() {
- const { t, i18n } = useTranslation();
- const { isPortrait } = useMobileOrientation();
- const params = useParams();
- const [searchParams] = useSearchParams();
- const [socket, setSocket] = useState
();
- const [wsUrl, setWsUrl] = useState();
- const [isEnded, setIsEnded] = useState(false);
- const { name, setName } = useStreamStore();
- const userId = uuidv4();
- const [step, setStep] = useState(1);
- const nameRef = useRef(null!);
- const [users, setUsers] = useState([]);
- const fullscreenRef = useRef(null);
- const [isFullscreen, { toggleFullscreen }] = useFullscreen(fullscreenRef);
- const [isShowChat, setIsShowChat] = useState(false);
- const [isShowUsers, setIsShowUsers] = useState(false);
- const [isShowInviteModal, setIsShowInviteModal] = useState(false);
- const [isVideoInitialized, setIsVideoInitialized] = useState(false);
- const [messageText, setMessageText] = useState("");
- const [messages] = useState([]);
- const messagesRef = useRef(null);
- const messageTextRef = useRef(null);
- const parentElementRef = useRef(null);
- const clipboard = useClipboard();
- const link = window.location.origin + window.location.pathname;
- const [anyNewMessages, setAnyNewMessages] = useState(false);
- const [endAt, setEndAt] = useState();
-
- const localVideoRef = useRef(null);
- const [localStream, setLocalStream] = useState(
- new MediaStream()
- );
- const [remoteStreams, setRemoteStreams, remoteStreamsRef] = useState<
- IRemoteStream[]
- >([]);
- const [peerId, setPeerId] = useState("");
- const [peerInstance, setPeerInstance] = useState();
- const [permission, setPermission] = useState();
- const isSpeaking = useIsAudioActive({
- source: localStream.getTracks().length ? localStream : null,
- });
- const isCallInit = useRef(false);
-
- const [isVideoEnabled, setIsVideoEnabled] = useState(false);
- const [isAudioEnabled, setIsAudioEnabled] = useState(false);
-
- async function getLang() {
- const { countryCode, error }: { countryCode: string; error: string } =
- await api.get("getCountryCode").json();
-
- if (!error && countryCode !== "RU") {
- i18n.changeLanguage("en");
- }
- }
-
- function handleClickClipboard() {
- clipboard.copy();
-
- toast.info("Ссылка скопирована в буфер обмена", {
- icon: ,
- position: "top-center",
- autoClose: 3000,
- hideProgressBar: true,
- closeOnClick: true,
- pauseOnHover: true,
- draggable: true,
- progress: undefined,
- theme: "light",
- transition: Bounce,
- });
- }
-
- async function sendMessage(e: FormEvent) {
- e.preventDefault();
-
- const text = removeSpaces(messageText);
-
- if (text) {
- const name = users.find((user) => user.id === userId)?.name;
- socket?.emit("message", { name, text });
- }
-
- setMessageText("");
- messageTextRef.current?.focus();
- }
-
- async function getActiveSession() {
- const activeSession: any = await api
- .get(`activeSessions/${params.id}`)
- .json();
-
- if (activeSession?.endAt) {
- setEndAt(activeSession.endAt);
- }
-
- return activeSession;
- }
-
- async function checkSessionStatus() {
- const activeSession = await getActiveSession();
-
- if (!activeSession || activeSession.status === "error") {
- setIsEnded(true);
- return;
- }
- }
-
- async function getWsUrl() {
- const activeSession = await getActiveSession();
-
- if (!activeSession || activeSession.status === "error") {
- setIsEnded(true);
- return;
- }
-
- setIsEnded(false);
- setWsUrl(
- `wss://${activeSession.location}.sess.stream.graff.tech/${activeSession.name}/${activeSession.cirrusPort}/`
- );
-
- checkSessionStatus();
- }
-
- function handleSetName(e: FormEvent) {
- e.preventDefault();
-
- if (!name) {
- nameRef.current.focus();
- return;
- }
-
- setStep(2);
- }
-
- function setNameGuest() {
- i18n.language === "ru" ? setName("Гость") : setName("Guest");
-
- setStep(2);
- }
-
- function toggleVideo() {
- localStream.getVideoTracks().forEach((track) => {
- track.enabled = !track.enabled;
-
- if (!permission) return;
- setIsVideoEnabled(track.enabled);
- });
- }
-
- function toggleAudio() {
- localStream.getAudioTracks().forEach((track) => {
- track.enabled = !track.enabled;
-
- if (!permission) return;
- setIsAudioEnabled(track.enabled);
- });
- }
-
- function transferControl(userId: string) {
- socket?.emit("transferControl", userId);
- }
-
- function requestControl(userId: string) {
- socket?.emit("requestControl", userId);
-
- toast.info(`Вы запросили разрешение на управление`, {
- icon: ,
- position: "top-center",
- autoClose: 3000,
- hideProgressBar: false,
- closeOnClick: true,
- pauseOnHover: true,
- draggable: true,
- progress: undefined,
- theme: "light",
- transition: Bounce,
- });
- }
-
- function kickUser(userId: string) {
- socket?.emit("kickUser", userId);
- }
-
- async function startCall(remotePeerId: string) {
- if (!peerInstance) return;
-
- console.log("startCall", remotePeerId);
-
- const options = {
- constraints: {
- offerToReceiveVideo: true,
- offerToReceiveAudio: true,
- },
- };
-
- const call = peerInstance.call(remotePeerId, localStream, options as any);
-
- let accept = true;
- call.on("stream", (remoteStream) => {
- if (!accept) return;
- console.log("setRemoteStreams", remoteStream);
- setRemoteStreams((prev) => [
- ...prev,
- { peerId: remotePeerId, mediaStream: remoteStream },
- ]);
- accept = false;
- });
- }
-
- async function getUserMedia() {
- try {
- const mediaStream = await navigator.mediaDevices.getUserMedia({
- video: true,
- audio: true,
- });
-
- if (!localVideoRef.current) return;
-
- localVideoRef.current.srcObject = mediaStream;
- localVideoRef.current.onloadedmetadata = () => {
- localVideoRef.current?.play();
- };
-
- setLocalStream(mediaStream);
- setPermission(true);
- console.log("setLocalStream mediaStream", mediaStream);
- } catch (error) {
- setPermission(false);
- console.log("ERROR: ", error);
- }
- }
-
- function initPeer() {
- const peer = new Peer();
-
- peer.on("open", (id) => {
- setPeerId(id);
- });
-
- peer.on("call", (call) => {
- call.answer(localStream || undefined);
-
- let accept = true;
- call.on("stream", (remoteStream) => {
- if (!accept) return;
- setRemoteStreams((prev) => [
- ...prev,
- { peerId: call.peer, mediaStream: remoteStream },
- ]);
- accept = false;
- });
- });
-
- setPeerInstance(peer);
- }
-
- function initSocket() {
- const socket = io(import.meta.env.VITE_SOCKET_URL, {
- transports: ["websocket"],
- auth: {
- roomId: params.id,
- user: {
- id: userId,
- name: name,
- device: isMobile ? "mobile" : "desktop",
- isAdmin: searchParams.has("admin", true),
- peerId,
- },
- },
- });
-
- socket.on("update", async (users: IUser[]) => {
- console.log("isCallInit", isCallInit.current);
-
- if (!isCallInit.current) {
- for (const user of users) {
- if (userId === user.id) continue;
-
- await startCall(user.peerId);
- }
-
- isCallInit.current = true;
- }
-
- setUsers(users);
- });
-
- setSocket(socket);
- setStep(3);
- }
-
- useEffect(() => {
- console.log("users", users);
- }, [users]);
-
- function updateRemoteStreams() {
- setTimeout(() => {
- console.log("users", users);
-
- const newRemoteStreams = remoteStreamsRef.current.filter((remoteStream) =>
- users.some((user) => user.peerId === remoteStream.peerId)
- );
-
- setRemoteStreams(newRemoteStreams);
- }, 500);
- }
-
- useEffect(() => {
- getLang();
- getWsUrl();
- }, []);
-
- useEffect(() => {
- document.title = t("title");
- }, [i18n.language]);
-
- useEffect(() => {
- if (!name) return;
-
- setName(name.trim());
- }, [name]);
-
- useEffect(() => {
- if (!isShowChat || messagesRef.current?.scrollTop === undefined) return;
-
- messagesRef.current.scrollTop = messagesRef.current.scrollHeight;
- }, [messages, isShowChat]);
-
- useEffect(() => {
- if (!messages.length || isShowChat) return;
-
- setAnyNewMessages(true);
- }, [messages]);
-
- useEffect(() => {
- if (isShowChat) {
- setAnyNewMessages(false);
- }
- }, [isShowChat]);
-
- // useEffect(() => {
- // if (!peerId) return;
-
- // const socket = io(import.meta.env.VITE_SOCKET_URL, {
- // auth: {
- // roomId: params.id,
- // user: {
- // id: userId,
- // name: name,
- // device: isMobile ? "mobile" : "desktop",
- // isAdmin: searchParams.has("admin", true),
- // peerId,
- // },
- // },
- // });
-
- // // TODO
-
- // socket.on("message", (message: IMessage) => {
- // setMessages((prev) => [...prev, message]);
- // });
-
- // socket.on("requestControl", (user: IUser) => {
- // if (!usersRef.current.find((user) => user.id === userId)?.isAdmin) return;
-
- // toast.info(`${user.name} запрашивает разрешение на управление`, {
- // icon: ,
- // position: "top-center",
- // autoClose: 5000,
- // hideProgressBar: false,
- // closeOnClick: true,
- // pauseOnHover: true,
- // draggable: true,
- // progress: undefined,
- // theme: "light",
- // transition: Bounce,
- // });
- // });
-
- // socket.on("transferControl", (user: IUser) => {
- // if (user.id !== userId) return;
-
- // toast.info(`Вы получили разрешение на управление`, {
- // icon: ,
- // position: "top-center",
- // autoClose: 3000,
- // hideProgressBar: false,
- // closeOnClick: true,
- // pauseOnHover: true,
- // draggable: true,
- // progress: undefined,
- // theme: "light",
- // transition: Bounce,
- // });
- // });
-
- // socket.on("kickUser", (socketUserId: string) => {
- // if (socketUserId === userId) {
- // socket.disconnect();
- // window.close();
- // window.location.reload();
- // }
- // });
-
- // setSocket(socket);
- // }, [peerId]);
-
- useEffect(() => {
- if (!isMobile) return;
- if (isShowUsers) {
- setIsShowChat(false);
- }
- }, [isShowUsers]);
-
- useEffect(() => {
- if (!isMobile) return;
- if (isShowChat) {
- setIsShowUsers(false);
- }
- }, [isShowChat]);
-
- useEffect(() => {
- if (step === 3) {
- setInterval(async () => {
- await checkSessionStatus();
- }, 1000);
- }
- }, [step]);
-
- useEffect(() => {
- if (permission === undefined) return;
-
- initPeer();
- }, [permission]);
-
- useEffect(() => {
- if (!peerId) return;
-
- initSocket();
- }, [peerId]);
-
- useEffect(() => {
- if (!users.length) return;
-
- updateRemoteStreams();
- }, [users.length]);
-
- return (
- <>
- {isEnded === false ? (
-
-
-
-
-

-
-
-
- {name && name[0].toUpperCase()}
- {users.find((user) => user.id === userId)
- ?.isControlAllowed && (
-
- )}
- {users.find((user) => user.id === userId)?.isAdmin && (
-
-
-
- )}
-
-
{name}
-
-
- {users.find((user) => user.id === userId)?.isControlAllowed ? (
- } onlyIcon />
- ) : users.find((user) => user.id === userId)?.isAdmin ? (
- }
- onlyIcon
- onClick={() => transferControl(userId)}
- className="group relative"
- >
-
-
- ) : (
- }
- onlyIcon
- onClick={() => requestControl(userId)}
- className="group relative"
- >
-
-
- )}
- : }
- onlyIcon
- onClick={toggleVideo}
- />
- : }
- onlyIcon
- onClick={toggleAudio}
- />
-
-
-
- {users
- .filter((user) => user.id !== userId)
- .map(
- (user, index) =>
- index < 3 && (
-
-
- {user.name[0].toUpperCase()}
- {user.isControlAllowed && (
-
- )}
- {user.isAdmin && (
-
-
-
- )}
-
-
{user.name}
-
- {user.device === "mobile" ? (
-
- ) : (
-
- )}
-
- {users.find((user) => user.id === userId)
- ?.isAdmin && (
-
- transferControl(userId)
- }
- onKickUser={(userId) => {
- kickUser(userId);
- }}
- />
- )}
-
- )
- )}
-
- {users.length > 4 && (
-
}
- onlyIcon
- onClick={() => setIsShowUsers((prev) => !prev)}
- />
- )}
-
-
-
-
-
-
}
- onlyIcon
- onClick={() => setIsShowChat((prev) => !prev)}
- />
- {anyNewMessages && (
-
- )}
-
-
-
- {!isIOS && (
- : }
- onlyIcon
- onClick={toggleFullscreen}
- />
- )}
- }
- onlyIcon
- onClick={() => setIsShowInviteModal((prev) => !prev)}
- />
-
- {endAt && searchParams.has("admin", "true") && (
- <>
-
-
-
- До завершения сеанса
-
-
-
-
- {/*
Завершить */}
-
- >
- )}
-
-
-
-
-
-
-

-
- {!isIOS && (
-
:
}
- onlyIcon
- onClick={toggleFullscreen}
- />
- )}
-
-
-
}
- onlyIcon
- onClick={() => setIsShowUsers((prev) => !prev)}
- />
-
-
}
- onlyIcon
- onClick={() => setIsShowChat((prev) => !prev)}
- />
- {anyNewMessages && (
-
- )}
-
-
-
:
}
- onlyIcon
- onClick={toggleAudio}
- />
-
-
- }
- onlyIcon
- onClick={() => setIsShowInviteModal((prev) => !prev)}
- />
-
-
-
- {wsUrl && (
-
setIsVideoInitialized(true)}
- />
- )}
-
- {!users.find((user) => user.id === userId)?.isControlAllowed && (
-
- toast.error(
- `Запросите доступ на управление у администратора!`,
- {
- icon: ,
- position: "top-center",
- autoClose: 5000,
- hideProgressBar: false,
- closeOnClick: true,
- pauseOnHover: true,
- draggable: true,
- progress: undefined,
- theme: "light",
- transition: Bounce,
- }
- )
- }
- onMouseDown={() =>
- toast.error(
- `Запросите доступ на управление у администратора!`,
- {
- icon: ,
- position: "top-center",
- autoClose: 5000,
- hideProgressBar: false,
- closeOnClick: true,
- pauseOnHover: true,
- draggable: true,
- progress: undefined,
- theme: "light",
- transition: Bounce,
- }
- )
- }
- >
- )}
-
-
-
- {remoteStreams.map(({ peerId, mediaStream }) => (
-
- ))}
-
-
-
- {(isShowUsers || isShowChat) && (
-
- {isShowUsers && (
-
-
-
- Участники
-
-
}
- onlyIcon
- onClick={() => setIsShowUsers((prev) => !prev)}
- />
-
-
- {users.map((user) => (
-
-
- {user.name[0].toUpperCase()}
- {user.isControlAllowed && (
-
- )}
- {user.isAdmin && (
-
-
-
- )}
-
-
{user.name}
-
- {user.device === "mobile" ? (
-
- ) : (
-
- )}
-
-
- {users.find((user) => user.id === userId)
- ?.isAdmin && (
-
- transferControl(userId)
- }
- onKickUser={(userId) => {
- kickUser(userId);
- }}
- />
- )}
-
-
- ))}
-
-
- setIsShowInviteModal((prev) => !prev)}
- >
- Пригласить
-
-
-
- )}
- {isShowChat && (
-
-
-
- Чат
-
-
}
- onlyIcon
- onClick={() => setIsShowChat((prev) => !prev)}
- />
-
-
- {messages.map((message, index) => (
-
user.id === userId)?.name ===
- message.name
- ? "bg-[#C4DDF5]"
- : "bg-[#F0F1F2]"
- }`}
- >
- {users.find((user) => user.id === userId)?.name !==
- message.name && (
-
- {message.name}
-
- )}
-
-
{message.text}
-
- {format(new Date(), "HH:mm")}
-
-
- ))}
-
-
-
-
-
- )}
-
- )}
-
-
- {isShowInviteModal && (
-
-
-
-
- Пригласить
-
-
}
- onlyIcon
- onClick={() => setIsShowInviteModal(false)}
- />
-
-
-
-
-
-
- Отсканируйте QR-код,
-
- чтобы присоедениться
-
к демонстрации
-
-
-
-
- }
- fullWidth
- large
- onClick={handleClickClipboard}
- >
-
- Скопировать ссылку для подключения
-
-
-
-
-
-
-
- {/*
-
Участники
-
- {users.map((user) => (
-
-
-
- {user.name[0].toUpperCase()}
-
-
-
{user.name}
-
- ))}
-
-
*/}
-
-
-
- )}
-
-
- {(state) => (
-
-
- {(state) => (
-
- )}
-
-
-
- {(state) => (
-
-
-
-
-
- Хотите принять участие в обсуждении?
-
-
-
-
-
-
-
-
-
- Разрешите использование камеры и микрофона
-
-
-
-
-
-
- Выключить камеру и микрофон можно в любой момент
-
-
-
-
-
- {/*
- Пропустить
- */}
-
- Продолжить
-
-
-
- )}
-
-
-
- {(state) => (
-
-
-
-
- Пожалуйста, подождите
-
-
-
-
-

-
- Подключение
-
-
-
- )}
-
-
- )}
-
-
-
-
- {step === 3 && isMobile && isPortrait && (
-
-
-
-
-
- Поверните устройство
-
-
-
-
- )}
-
-
-
- ) : (
-
-
-
- Данная демонстрация была завершена
-
-
-
- )}
- >
- );
-}
-
-export default StreamPage2;