upd
This commit is contained in:
@@ -30,6 +30,7 @@
|
||||
"react-qr-code": "^2.0.11",
|
||||
"react-router-dom": "^6.11.2",
|
||||
"react-timeit": "^1.2.12",
|
||||
"react-timer-hook": "^3.0.7",
|
||||
"react-toastify": "^9.1.3",
|
||||
"react-transition-group": "^4.4.5",
|
||||
"socket.io-client": "^4.6.2",
|
||||
|
||||
+62
-34
@@ -31,6 +31,19 @@ import { LiveKitRoom, RoomAudioRenderer } from "@livekit/components-react";
|
||||
import ToggleMic from "./components/ToggleMic";
|
||||
import Chat from "./components/Chat";
|
||||
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() {
|
||||
const { t } = useTranslation();
|
||||
@@ -39,6 +52,8 @@ function StreamPage() {
|
||||
const [isStreamEnded, setIsStreamEnded] = useState<boolean>(false);
|
||||
const [isStreamLoaded, setStreamLoaded] = useState<boolean>(false);
|
||||
const [me, setMe] = useState<any>({});
|
||||
const meRef = useRef<any>({});
|
||||
meRef.current = me;
|
||||
const [modal, setModal] = useModalStore((state) => [
|
||||
state.modal,
|
||||
state.setModal,
|
||||
@@ -59,6 +74,7 @@ function StreamPage() {
|
||||
const [lastActivity, setLastActivity] = useState<Date>(new Date());
|
||||
const lastActivityRef = useRef<Date>();
|
||||
lastActivityRef.current = lastActivity;
|
||||
const [stopwatch, setStopwatch] = useState<string>();
|
||||
|
||||
async function getToken() {
|
||||
if (!socket) return;
|
||||
@@ -72,6 +88,17 @@ function StreamPage() {
|
||||
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() {
|
||||
const activeSession: any = await ky
|
||||
.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}/`
|
||||
);
|
||||
|
||||
updateStartDate(parseISO(activeSession.createdAt));
|
||||
|
||||
setStreamLoaded(true);
|
||||
} else {
|
||||
setIsStreamEnded(true);
|
||||
@@ -130,47 +159,35 @@ function StreamPage() {
|
||||
// });
|
||||
// }
|
||||
|
||||
// function toastHandOn(text: string) {
|
||||
// toast.info(text, {
|
||||
// position: "top-center",
|
||||
// autoClose: 2000,
|
||||
// hideProgressBar: true,
|
||||
// closeOnClick: true,
|
||||
// pauseOnHover: true,
|
||||
// draggable: true,
|
||||
// theme: "dark",
|
||||
// icon: <HandOnIcon />,
|
||||
// closeButton: false,
|
||||
// });
|
||||
// }
|
||||
function toastHandOn(text: string) {
|
||||
toast.info(text, {
|
||||
position: "top-center",
|
||||
autoClose: 2000,
|
||||
hideProgressBar: true,
|
||||
closeOnClick: true,
|
||||
pauseOnHover: true,
|
||||
draggable: true,
|
||||
theme: "dark",
|
||||
icon: <HandOnIcon />,
|
||||
closeButton: false,
|
||||
});
|
||||
}
|
||||
|
||||
const handleAction = () => {
|
||||
setLastActivity(new Date());
|
||||
};
|
||||
|
||||
const updateLastActivity = async () => {
|
||||
console.log("lastActivity: ", lastActivityRef.current);
|
||||
function updateLastActivity() {
|
||||
if (!socket) return;
|
||||
|
||||
try {
|
||||
const result = await ky
|
||||
.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);
|
||||
}
|
||||
if (meRef.current && meRef.current.admin) {
|
||||
socket.emit("last-activity", socket.id, lastActivityRef.current);
|
||||
}
|
||||
|
||||
setTimeout(() => {
|
||||
updateLastActivity();
|
||||
}, 2000);
|
||||
};
|
||||
}, 5000);
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
connect();
|
||||
@@ -189,6 +206,7 @@ function StreamPage() {
|
||||
socket.on("join", (socketId, sockets) => {
|
||||
console.log("User connected: ", socketId, sockets);
|
||||
setUsers(sockets);
|
||||
toastHandOn(t("notification.newMember"));
|
||||
});
|
||||
|
||||
socket.on("update", (socketId, data, sockets) => {
|
||||
@@ -197,6 +215,7 @@ function StreamPage() {
|
||||
});
|
||||
|
||||
socket.on("kick", () => {
|
||||
socket.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("touchstart", handleAction);
|
||||
|
||||
updateLastActivity();
|
||||
|
||||
return () => {
|
||||
socket.off("connect");
|
||||
socket.off("join");
|
||||
@@ -230,6 +253,7 @@ function StreamPage() {
|
||||
if (!socket) return;
|
||||
|
||||
getToken();
|
||||
updateLastActivity();
|
||||
}, [socket]);
|
||||
|
||||
useEffect(() => {
|
||||
@@ -240,7 +264,7 @@ function StreamPage() {
|
||||
|
||||
useEffect(() => {
|
||||
if (me && me.allowControl && !me.admin) {
|
||||
// toastHandOn(t("notification.controlReceived"));
|
||||
toastHandOn(t("notification.controlReceived"));
|
||||
}
|
||||
}, [me]);
|
||||
|
||||
@@ -368,6 +392,10 @@ function StreamPage() {
|
||||
<RoomAudioRenderer />
|
||||
<ToggleMic socket={socket} handleUpdate={update} />
|
||||
</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>
|
||||
|
||||
|
||||
@@ -98,7 +98,7 @@ function Chat({ className, handleClose }: ChatProps) {
|
||||
].join(" ")}
|
||||
>
|
||||
<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}>
|
||||
<CloseIcon />
|
||||
</button>
|
||||
@@ -109,7 +109,7 @@ function Chat({ className, handleClose }: ChatProps) {
|
||||
>
|
||||
{messages.map((data, index) => (
|
||||
<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>
|
||||
))}
|
||||
|
||||
@@ -141,7 +141,7 @@ function Chat({ className, handleClose }: ChatProps) {
|
||||
<input
|
||||
ref={inputRef}
|
||||
type="text"
|
||||
placeholder="Message"
|
||||
placeholder="Написать сообщение..."
|
||||
autoFocus
|
||||
autoComplete="off"
|
||||
value={message}
|
||||
@@ -152,7 +152,7 @@ function Chat({ className, handleClose }: ChatProps) {
|
||||
type="submit"
|
||||
className="p-2 bg-blue-700 hover:bg-blue-800 transition-colors outline-none rounded"
|
||||
>
|
||||
Send
|
||||
Отправить
|
||||
</button>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
@@ -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;
|
||||
@@ -1912,6 +1912,11 @@ react-timeit@^1.2.12:
|
||||
dependencies:
|
||||
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:
|
||||
version "9.1.3"
|
||||
resolved "https://registry.npmjs.org/react-toastify/-/react-toastify-9.1.3.tgz"
|
||||
|
||||
Reference in New Issue
Block a user