This commit is contained in:
2023-10-06 18:26:51 +05:00
parent 5342b3b303
commit 44bae35cc9
5 changed files with 106 additions and 38 deletions
+1
View File
@@ -30,6 +30,7 @@
"react-qr-code": "^2.0.11", "react-qr-code": "^2.0.11",
"react-router-dom": "^6.11.2", "react-router-dom": "^6.11.2",
"react-timeit": "^1.2.12", "react-timeit": "^1.2.12",
"react-timer-hook": "^3.0.7",
"react-toastify": "^9.1.3", "react-toastify": "^9.1.3",
"react-transition-group": "^4.4.5", "react-transition-group": "^4.4.5",
"socket.io-client": "^4.6.2", "socket.io-client": "^4.6.2",
+62 -34
View File
@@ -31,6 +31,19 @@ import { LiveKitRoom, RoomAudioRenderer } from "@livekit/components-react";
import ToggleMic from "./components/ToggleMic"; import ToggleMic from "./components/ToggleMic";
import Chat from "./components/Chat"; import Chat from "./components/Chat";
import ChatIcon from "./components/icons/ChatIcon"; import ChatIcon from "./components/icons/ChatIcon";
import AFKTimerModal from "./components/modals/AFKTimerModal";
import {
differenceInMilliseconds,
differenceInSeconds,
format,
formatDuration,
getMinutes,
getSeconds,
intervalToDuration,
parseISO,
} from "date-fns";
import { ru } from "date-fns/locale";
import HandOnIcon from "./components/icons/HandOnIcon";
function StreamPage() { function StreamPage() {
const { t } = useTranslation(); const { t } = useTranslation();
@@ -39,6 +52,8 @@ function StreamPage() {
const [isStreamEnded, setIsStreamEnded] = useState<boolean>(false); const [isStreamEnded, setIsStreamEnded] = useState<boolean>(false);
const [isStreamLoaded, setStreamLoaded] = useState<boolean>(false); const [isStreamLoaded, setStreamLoaded] = useState<boolean>(false);
const [me, setMe] = useState<any>({}); const [me, setMe] = useState<any>({});
const meRef = useRef<any>({});
meRef.current = me;
const [modal, setModal] = useModalStore((state) => [ const [modal, setModal] = useModalStore((state) => [
state.modal, state.modal,
state.setModal, state.setModal,
@@ -59,6 +74,7 @@ function StreamPage() {
const [lastActivity, setLastActivity] = useState<Date>(new Date()); const [lastActivity, setLastActivity] = useState<Date>(new Date());
const lastActivityRef = useRef<Date>(); const lastActivityRef = useRef<Date>();
lastActivityRef.current = lastActivity; lastActivityRef.current = lastActivity;
const [stopwatch, setStopwatch] = useState<string>();
async function getToken() { async function getToken() {
if (!socket) return; if (!socket) return;
@@ -72,6 +88,17 @@ function StreamPage() {
setToken(token); setToken(token);
} }
function updateStartDate(date: Date) {
const diffMs = differenceInMilliseconds(new Date(), date);
setStopwatch(format(diffMs, "mm:ss"));
console.log();
setTimeout(() => {
updateStartDate(date);
}, 1000);
}
async function connect() { async function connect() {
const activeSession: any = await ky const activeSession: any = await ky
.get(`${import.meta.env.VITE_COORD_URL}/active_sessions/${params.id}`) .get(`${import.meta.env.VITE_COORD_URL}/active_sessions/${params.id}`)
@@ -82,6 +109,8 @@ function StreamPage() {
`wss://${activeSession.location}.sess.stream.graff.tech/${activeSession.server}/${activeSession.cirrusPort}/` `wss://${activeSession.location}.sess.stream.graff.tech/${activeSession.server}/${activeSession.cirrusPort}/`
); );
updateStartDate(parseISO(activeSession.createdAt));
setStreamLoaded(true); setStreamLoaded(true);
} else { } else {
setIsStreamEnded(true); setIsStreamEnded(true);
@@ -130,47 +159,35 @@ function StreamPage() {
// }); // });
// } // }
// function toastHandOn(text: string) { function toastHandOn(text: string) {
// toast.info(text, { toast.info(text, {
// position: "top-center", position: "top-center",
// autoClose: 2000, autoClose: 2000,
// hideProgressBar: true, hideProgressBar: true,
// closeOnClick: true, closeOnClick: true,
// pauseOnHover: true, pauseOnHover: true,
// draggable: true, draggable: true,
// theme: "dark", theme: "dark",
// icon: <HandOnIcon />, icon: <HandOnIcon />,
// closeButton: false, closeButton: false,
// }); });
// } }
const handleAction = () => { const handleAction = () => {
setLastActivity(new Date()); setLastActivity(new Date());
}; };
const updateLastActivity = async () => { function updateLastActivity() {
console.log("lastActivity: ", lastActivityRef.current); if (!socket) return;
try { if (meRef.current && meRef.current.admin) {
const result = await ky socket.emit("last-activity", socket.id, lastActivityRef.current);
.put(`${import.meta.env.VITE_COORD_URL}/active_sessions/${params.id}`, {
json: {
lastActivityAt: lastActivityRef.current,
},
})
.json();
console.log(result);
} catch (error) {
if (error instanceof Error) {
console.log(error.message);
}
} }
setTimeout(() => { setTimeout(() => {
updateLastActivity(); updateLastActivity();
}, 2000); }, 5000);
}; }
useEffect(() => { useEffect(() => {
connect(); connect();
@@ -189,6 +206,7 @@ function StreamPage() {
socket.on("join", (socketId, sockets) => { socket.on("join", (socketId, sockets) => {
console.log("User connected: ", socketId, sockets); console.log("User connected: ", socketId, sockets);
setUsers(sockets); setUsers(sockets);
toastHandOn(t("notification.newMember"));
}); });
socket.on("update", (socketId, data, sockets) => { socket.on("update", (socketId, data, sockets) => {
@@ -197,6 +215,7 @@ function StreamPage() {
}); });
socket.on("kick", () => { socket.on("kick", () => {
socket.close();
window.close(); window.close();
}); });
@@ -208,11 +227,15 @@ function StreamPage() {
); );
}); });
socket.on("notification", (type) => {
if (type === "afk-timer") {
setModal(<AFKTimerModal />);
}
});
document.addEventListener("mousemove", handleAction); document.addEventListener("mousemove", handleAction);
document.addEventListener("touchstart", handleAction); document.addEventListener("touchstart", handleAction);
updateLastActivity();
return () => { return () => {
socket.off("connect"); socket.off("connect");
socket.off("join"); socket.off("join");
@@ -230,6 +253,7 @@ function StreamPage() {
if (!socket) return; if (!socket) return;
getToken(); getToken();
updateLastActivity();
}, [socket]); }, [socket]);
useEffect(() => { useEffect(() => {
@@ -240,7 +264,7 @@ function StreamPage() {
useEffect(() => { useEffect(() => {
if (me && me.allowControl && !me.admin) { if (me && me.allowControl && !me.admin) {
// toastHandOn(t("notification.controlReceived")); toastHandOn(t("notification.controlReceived"));
} }
}, [me]); }, [me]);
@@ -368,6 +392,10 @@ function StreamPage() {
<RoomAudioRenderer /> <RoomAudioRenderer />
<ToggleMic socket={socket} handleUpdate={update} /> <ToggleMic socket={socket} handleUpdate={update} />
</LiveKitRoom> </LiveKitRoom>
<div className="relative group outline-none w-10 h-10 bg-[#131313] rounded-full shadow-lg shadow-[#131313] p-2 opacity-90 flex justify-center items-center">
<p className="text-xs">{stopwatch}</p>
</div>
</div> </div>
</div> </div>
+4 -4
View File
@@ -98,7 +98,7 @@ function Chat({ className, handleClose }: ChatProps) {
].join(" ")} ].join(" ")}
> >
<div className="border-b pb-3 border-y-neutral-800 flex justify-between"> <div className="border-b pb-3 border-y-neutral-800 flex justify-between">
<p className="text-2xl ">Chat</p> <p className="text-2xl font-gilroy">Чат</p>
<button onClick={handleClose}> <button onClick={handleClose}>
<CloseIcon /> <CloseIcon />
</button> </button>
@@ -109,7 +109,7 @@ function Chat({ className, handleClose }: ChatProps) {
> >
{messages.map((data, index) => ( {messages.map((data, index) => (
<p key={index} className="break-words"> <p key={index} className="break-words">
<b>{data.id}:</b> <span>{data.message}</span> <b>{data.city && data.city + ":"}</b> <span>{data.message}</span>
</p> </p>
))} ))}
@@ -141,7 +141,7 @@ function Chat({ className, handleClose }: ChatProps) {
<input <input
ref={inputRef} ref={inputRef}
type="text" type="text"
placeholder="Message" placeholder="Написать сообщение..."
autoFocus autoFocus
autoComplete="off" autoComplete="off"
value={message} value={message}
@@ -152,7 +152,7 @@ function Chat({ className, handleClose }: ChatProps) {
type="submit" type="submit"
className="p-2 bg-blue-700 hover:bg-blue-800 transition-colors outline-none rounded" className="p-2 bg-blue-700 hover:bg-blue-800 transition-colors outline-none rounded"
> >
Send Отправить
</button> </button>
</form> </form>
</div> </div>
+34
View File
@@ -0,0 +1,34 @@
import { useEffect, useState } from "react";
import useModalStore from "../../stores/useModalStore";
function AFKTimerModal() {
const setModal = useModalStore((state) => state.setModal);
const [afkTimer, setAfkTimer] = useState<number>(60);
useEffect(() => {
const interval = setInterval(() => {
setAfkTimer((prev) => prev - 1);
}, 1000);
return () => {
clearInterval(interval);
};
}, []);
return (
<div className="relative lg:p-10 p-6 bg-[#131317] rounded shadow-lg w-[320px]">
<div className="flex flex-col gap-4">
<p className="text-2xl">AFK Check</p>
<p>Session will end in {afkTimer} seconds</p>
<button
onClick={() => setModal(null)}
className="px-3 py-2 bg-blue-600 hover:bg-blue-700 transition-colors rounded"
>
I'm here
</button>
</div>
</div>
);
}
export default AFKTimerModal;
+5
View File
@@ -1912,6 +1912,11 @@ react-timeit@^1.2.12:
dependencies: dependencies:
react-jss "^10.9.0" react-jss "^10.9.0"
react-timer-hook@^3.0.7:
version "3.0.7"
resolved "https://registry.yarnpkg.com/react-timer-hook/-/react-timer-hook-3.0.7.tgz#ac42c43d0034b873cbf97b44eb34ccb2b11fe5e0"
integrity sha512-ATpNcU+PQRxxfNBPVqce2+REtjGAlwmfoNQfcEBMZFxPj0r3GYdKhyPHdStvqrejejEi0QvqaJZjy2lBlFvAsA==
react-toastify@^9.1.3: react-toastify@^9.1.3:
version "9.1.3" version "9.1.3"
resolved "https://registry.npmjs.org/react-toastify/-/react-toastify-9.1.3.tgz" resolved "https://registry.npmjs.org/react-toastify/-/react-toastify-9.1.3.tgz"