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-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
View File
@@ -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>
+4 -4
View File
@@ -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>
+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:
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"