742 lines
25 KiB
JavaScript
742 lines
25 KiB
JavaScript
import { useRouter } from "next/router";
|
|
import { useContext, useEffect, useState } from "react";
|
|
import {
|
|
AiFillEyeInvisible,
|
|
AiFillUnlock,
|
|
AiOutlineCheck,
|
|
AiOutlineClose,
|
|
} from "react-icons/ai";
|
|
import ReconnectingWebSocket from "reconnecting-websocket";
|
|
import { AlertType, useAlert } from "../../context/alert.context.js";
|
|
import { useWebsocketContext } from "../../context/websocket.context.js";
|
|
import {
|
|
changeRoomName,
|
|
deleteParcours,
|
|
deleteRoom,
|
|
getRoom,
|
|
togglePublicResult,
|
|
toggleRoomLock,
|
|
} from "../../requests/requests.room.js";
|
|
import styles from "../../styles/room/roomView.module.scss";
|
|
import { isBrowser, isEmpty, parseClassName } from "../../utils/utils.js";
|
|
import Layout from "../Layout.js";
|
|
import { BsCheckLg } from "react-icons/bs";
|
|
import { BiTrash } from "react-icons/bi";
|
|
import { MdRefresh, MdExitToApp, MdEdit } from "react-icons/md";
|
|
import { IoMdExit, IoMdReturnLeft } from "react-icons/io";
|
|
import { BiEdit, BiUndo } from "react-icons/bi";
|
|
import { notificationService } from "../../services/notification.service.js";
|
|
import { AiFillLock, AiFillEye } from "react-icons/ai";
|
|
export default function RoomView({ user, id_code }) {
|
|
const [dataRoom, setDataRoom] = useState();
|
|
|
|
useEffect(() => {
|
|
if (user != undefined && (dataRoom == undefined || isEmpty(dataRoom))) {
|
|
getRoom(id_code, user.clientId)
|
|
.then((res) => {
|
|
setDataRoom(res.room);
|
|
})
|
|
.catch((err) => {
|
|
if (err.response.data.code == 111) {
|
|
setJoined(false);
|
|
router.push({ pathname: "/room/join" });
|
|
}
|
|
});
|
|
}
|
|
}, [user, dataRoom]);
|
|
|
|
const router = useRouter();
|
|
const {
|
|
ws,
|
|
send,
|
|
connect,
|
|
addMessageHandler,
|
|
removeMessageHandler,
|
|
isConnected,
|
|
disconnect,
|
|
} = useWebsocketContext();
|
|
|
|
useEffect(() => {
|
|
let handler = (e) => {
|
|
let data = JSON.parse(e.data);
|
|
let type = data.type;
|
|
switch (type) {
|
|
case "joined": {
|
|
if (dataRoom) {
|
|
let nick = data.nick;
|
|
let owner = data.owner;
|
|
let online = data.online;
|
|
let code = data.code;
|
|
|
|
let oldParticipants = dataRoom.participants;
|
|
let oldWaiters = dataRoom.waiters;
|
|
setDataRoom({
|
|
...dataRoom,
|
|
participants: [
|
|
...oldParticipants,
|
|
{ nick: nick, owner: owner, online: online, code: code },
|
|
],
|
|
waiters: [...oldWaiters.filter((w) => w.code != code)],
|
|
});
|
|
}
|
|
break;
|
|
}
|
|
case "disconnect_participant": {
|
|
if (dataRoom) {
|
|
let oldParticipants = dataRoom.participants;
|
|
let nick = data.nick;
|
|
setDataRoom({
|
|
...dataRoom,
|
|
participants: [
|
|
...oldParticipants.map((p) => {
|
|
if (p.nick == nick) {
|
|
return { ...p, online: false };
|
|
}
|
|
return p;
|
|
}),
|
|
],
|
|
});
|
|
}
|
|
break;
|
|
}
|
|
case "reconnect_participant": {
|
|
if (dataRoom) {
|
|
let oldParticipants = dataRoom.participants;
|
|
let nick = data.nick;
|
|
let participant = oldParticipants.filter((p) => p.nick == nick)[0];
|
|
participant.online = true;
|
|
setDataRoom({
|
|
...dataRoom,
|
|
participants: [
|
|
...oldParticipants.filter((p) => p.nick != nick),
|
|
participant,
|
|
],
|
|
});
|
|
}
|
|
break;
|
|
}
|
|
case "add_waiter": {
|
|
if (dataRoom) {
|
|
let nick = data.nick;
|
|
let code = data.code;
|
|
let status = data.status;
|
|
|
|
let oldWaiters = dataRoom.waiters;
|
|
setDataRoom({
|
|
...dataRoom,
|
|
waiters: [
|
|
...oldWaiters,
|
|
{ nick: nick, code: code, status: status },
|
|
],
|
|
});
|
|
}
|
|
break;
|
|
}
|
|
case "del_waiter": {
|
|
if (dataRoom) {
|
|
let code = data.code;
|
|
|
|
let oldWaiters = dataRoom.waiters;
|
|
setDataRoom({
|
|
...dataRoom,
|
|
waiters: [...oldWaiters.filter((w) => w.code != code)],
|
|
});
|
|
}
|
|
break;
|
|
}
|
|
case "banned": {
|
|
if (dataRoom) {
|
|
let nick = data.nick;
|
|
let code = data.code;
|
|
|
|
if (user.user.code != code) {
|
|
let oldParticipants = dataRoom.participants;
|
|
let oldParcours = dataRoom.parcours;
|
|
setDataRoom({
|
|
...dataRoom,
|
|
participants: [
|
|
...oldParticipants.filter((p) => p.nick != nick),
|
|
],
|
|
});
|
|
} else if (user.user.code == code) {
|
|
router.push({ pathname: "/room/join" });
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
|
|
case "add_parcours": {
|
|
if (dataRoom) {
|
|
let new_parcours = data.parcours;
|
|
let id_code = dataRoom.id_code;
|
|
let oldParcours = dataRoom.parcours;
|
|
setDataRoom({
|
|
...dataRoom,
|
|
parcours: [...oldParcours, new_parcours],
|
|
});
|
|
}
|
|
break;
|
|
}
|
|
case "delete_parcours": {
|
|
if (dataRoom) {
|
|
setDataRoom({
|
|
...dataRoom,
|
|
parcours: [
|
|
...dataRoom.parcours.filter((p) => p.id_code != data.id_code),
|
|
],
|
|
});
|
|
}
|
|
break;
|
|
}
|
|
case "edit_parcours": {
|
|
if (dataRoom) {
|
|
let new_parcours = data.parcours;
|
|
let id_code = dataRoom.id_code;
|
|
let oldParcours = dataRoom.parcours;
|
|
|
|
setDataRoom({
|
|
...dataRoom,
|
|
parcours: [
|
|
...oldParcours.map((p) => {
|
|
if (p.id_code == new_parcours.id_code) {
|
|
return new_parcours;
|
|
}
|
|
return p;
|
|
}),
|
|
],
|
|
});
|
|
}
|
|
break;
|
|
}
|
|
|
|
default:
|
|
break;
|
|
}
|
|
};
|
|
addMessageHandler(handler);
|
|
return () => {
|
|
removeMessageHandler(handler);
|
|
};
|
|
}, [dataRoom]);
|
|
|
|
const alert = useAlert();
|
|
const [edit, setEdit] = useState(null);
|
|
useEffect(() => {
|
|
window.addEventListener("click", () => {
|
|
if (edit) {
|
|
setEdit(null);
|
|
}
|
|
});
|
|
});
|
|
|
|
useEffect(() => {
|
|
return () => {
|
|
disconnect();
|
|
};
|
|
}, []);
|
|
|
|
return (
|
|
<Layout page={dataRoom && dataRoom.name ? dataRoom.name : "..."}>
|
|
{isEmpty(dataRoom) && <><span className='loader'></span></>}
|
|
{dataRoom && !isEmpty(dataRoom) && (
|
|
<div className={styles["full-container"]}>
|
|
<div className={styles["head"]}>
|
|
{(edit === null || edit == false) && edit != "" && (
|
|
<h1
|
|
onClick={() => {
|
|
if (navigator.clipboard) {
|
|
navigator.clipboard.write(router.asPath).then((res) => {
|
|
notificationService.success("Lien", "Lien copié !");
|
|
});
|
|
}
|
|
}}
|
|
>
|
|
<p
|
|
className={styles.title}
|
|
onDoubleClick={(e) => {
|
|
if (user.user.owner) {
|
|
setEdit(dataRoom.name);
|
|
}
|
|
}}
|
|
title={"Double click pour modifier"}
|
|
>
|
|
{dataRoom.name}
|
|
</p>
|
|
<span>#{dataRoom.id_code}</span>
|
|
</h1>
|
|
)}
|
|
{((edit !== null && edit != false) || edit == "") && (
|
|
<div
|
|
className={styles["title-form"]}
|
|
onClick={(e) => {
|
|
e.stopPropagation();
|
|
}}
|
|
>
|
|
<input
|
|
type="text"
|
|
className="exo-input"
|
|
value={edit}
|
|
onChange={(e) => {
|
|
if (e.target.value == "") {
|
|
setEdit("");
|
|
} else {
|
|
setEdit(e.target.value);
|
|
}
|
|
}}
|
|
onKeyDown={(e) => {
|
|
if (e.code == "Enter") {
|
|
changeRoomName({
|
|
id_code: dataRoom.id_code,
|
|
clientId: sessionStorage.getItem("clientId"),
|
|
name: edit,
|
|
})
|
|
.then((res) => {
|
|
setDataRoom({ ...dataRoom, name: res.name });
|
|
setEdit(null);
|
|
})
|
|
.catch((err) => {
|
|
notificationService.error(
|
|
"Erreur",
|
|
"Erreur lors de la modification"
|
|
);
|
|
});
|
|
} else if (e.code == "Escape") {
|
|
setEdit(null);
|
|
}
|
|
}}
|
|
autoFocus={true}
|
|
/>
|
|
</div>
|
|
)}
|
|
|
|
<div className={styles["icons-container"]}>
|
|
<MdRefresh
|
|
title={"Actualiser"}
|
|
onClick={() => {
|
|
setDataRoom();
|
|
if (!isConnected) {
|
|
connect("/ws/room/" + id_code);
|
|
}
|
|
}}
|
|
className={styles.refresh}
|
|
/>
|
|
<BiUndo
|
|
onClick={() => {
|
|
disconnect();
|
|
router.push("/room", undefined, {shallow:true});
|
|
}}
|
|
className={styles.exit}
|
|
title={"Retour à l'acceuil"}
|
|
/>
|
|
{!user.user.owner && (
|
|
<IoMdExit
|
|
className={styles.exit}
|
|
title={"Quitter"}
|
|
onClick={() => {
|
|
alert.alert({
|
|
title: "Êtes-vous sûr ?",
|
|
active: true,
|
|
message: `Voulez vous quitter le salle ? Cela effacera toute vos données sur les parcours`,
|
|
type: AlertType.Warning,
|
|
validate: () => {
|
|
send({
|
|
data: {
|
|
type: "leave",
|
|
code: user.user.code,
|
|
nick: user.user.nick,
|
|
clientId: sessionStorage.getItem("clientId"),
|
|
},
|
|
});
|
|
},
|
|
});
|
|
}}
|
|
/>
|
|
)}
|
|
{user.user.owner && (
|
|
<BiTrash
|
|
className={styles.exit}
|
|
onClick={() => {
|
|
alert.alert({
|
|
title: "Êtes-vous sûr ?",
|
|
active: true,
|
|
message: `Voulez vous supprimer le salle ?`,
|
|
type: AlertType.Warning,
|
|
validate: () => {
|
|
deleteRoom({
|
|
clientId:
|
|
isBrowser && sessionStorage.getItem("clientId"),
|
|
id_code,
|
|
})
|
|
.then((res) => {
|
|
router.push("/room/", undefined, { shallow: true });
|
|
notificationService.success(
|
|
"Suppression",
|
|
`Salle "${dataRoom.name}" supprimée`,
|
|
{ keepAfterRouteChange: true }
|
|
);
|
|
})
|
|
.catch((err) => {
|
|
notificationService.error(
|
|
"Suppression",
|
|
`Erreur lors de la suppression de la salle "${dataRoom.name}"`,
|
|
{ keepAfterRouteChange: true }
|
|
);
|
|
});
|
|
},
|
|
});
|
|
}}
|
|
/>
|
|
)}
|
|
</div>
|
|
</div>
|
|
|
|
<div className={styles["parcours-container"]}>
|
|
<div className={styles["cat-title"]}>
|
|
<p className={styles["parcours-title"]}>
|
|
{" "}
|
|
{user.user.owner &&
|
|
(dataRoom.public_result ? (
|
|
<AiFillEye
|
|
onClick={() => {
|
|
togglePublicResult({
|
|
id_code: dataRoom.id_code,
|
|
clientId: sessionStorage.getItem("clientId"),
|
|
})
|
|
.then((res) => {
|
|
setDataRoom({
|
|
...dataRoom,
|
|
public_result: res.private,
|
|
});
|
|
})
|
|
.catch((err) => {
|
|
notificationService.error(
|
|
"Erreur",
|
|
"Erreur lors de la modification"
|
|
);
|
|
});
|
|
}}
|
|
title="Appuyer pour rendre les résultats privé (les membres ne pourront voir que leurs propres résultats)"
|
|
/>
|
|
) : (
|
|
<AiFillEyeInvisible
|
|
onClick={() => {
|
|
togglePublicResult({
|
|
id_code: dataRoom.id_code,
|
|
clientId: sessionStorage.getItem("clientId"),
|
|
})
|
|
.then((res) => {
|
|
setDataRoom({
|
|
...dataRoom,
|
|
public_result: res.private,
|
|
});
|
|
})
|
|
.catch((err) => {
|
|
notificationService.error(
|
|
"Erreur",
|
|
"Erreur lors de la modification"
|
|
);
|
|
});
|
|
}}
|
|
title="Appuyer pour rendre les résultats public (les membres pourront voir les résultats des autres)"
|
|
/>
|
|
))}
|
|
Parcours{" "}
|
|
</p>
|
|
{user.user.owner && (
|
|
<button
|
|
className="exo-btn"
|
|
onClick={() => {
|
|
router.push(
|
|
{
|
|
pathname: `/room/${dataRoom.id_code}/new_parcours`,
|
|
},
|
|
undefined,
|
|
{ shallow: true }
|
|
);
|
|
}}
|
|
>
|
|
Nouveau
|
|
</button>
|
|
)}
|
|
</div>
|
|
{dataRoom.parcours.map((p) => {
|
|
return (
|
|
<div
|
|
className={styles["parcours-item"]}
|
|
onClick={() => {
|
|
router.push(
|
|
{
|
|
pathname: `/room/${dataRoom.id_code}/${p.id_code}`,
|
|
},
|
|
undefined,
|
|
{ shallow: true }
|
|
);
|
|
}}
|
|
>
|
|
<div>
|
|
{p.is_validate && <BsCheckLg />}
|
|
<p>{p.name}</p>{" "}
|
|
</div>
|
|
|
|
{user.user.owner == true && (
|
|
<BiTrash
|
|
onClick={(e) => {
|
|
e.stopPropagation();
|
|
console.log("CLICK SVG");
|
|
alert.alert({
|
|
title: "Êtes-vous sûr ?",
|
|
active: true,
|
|
message: `Voulez vous supprimer le parcours "${p.name}"`,
|
|
type: AlertType.Warning,
|
|
validate: () => {
|
|
deleteParcours({
|
|
id_code: p.id_code,
|
|
code: user.user.code,
|
|
}).then((r) => {
|
|
setDataRoom({
|
|
...dataRoom,
|
|
parcours: [
|
|
...dataRoom.parcours.filter(
|
|
(pp) => pp.id_code != r.id_code
|
|
),
|
|
],
|
|
});
|
|
});
|
|
},
|
|
});
|
|
}}
|
|
/>
|
|
)}
|
|
</div>
|
|
);
|
|
})}
|
|
{dataRoom.parcours.length == 0 && (
|
|
<p className={styles["no-parcours"]}>Aucun parcours</p>
|
|
)}
|
|
</div>
|
|
<div className={styles["participants-container"]}>
|
|
<div className={styles["cat-title"]}>
|
|
Participants{" "}
|
|
{user.user.owner &&
|
|
(dataRoom.private ? (
|
|
<AiFillLock
|
|
className={styles.lock}
|
|
title={"Rendre la salle publique"}
|
|
onClick={() => {
|
|
toggleRoomLock({
|
|
id_code: dataRoom.id_code,
|
|
clientId: sessionStorage.getItem("clientId"),
|
|
})
|
|
.then((res) => {
|
|
setDataRoom({ ...dataRoom, private: res.private });
|
|
})
|
|
.catch((err) => {
|
|
notificationService.error(
|
|
"Erreur",
|
|
"Erreur lors de la modification"
|
|
);
|
|
});
|
|
}}
|
|
/>
|
|
) : (
|
|
<AiFillUnlock
|
|
className={styles.lock}
|
|
title={"Rendre la salle privée"}
|
|
onClick={() => {
|
|
toggleRoomLock({
|
|
id_code: dataRoom.id_code,
|
|
clientId: sessionStorage.getItem("clientId"),
|
|
})
|
|
.then((res) => {
|
|
setDataRoom({ ...dataRoom, private: res.private });
|
|
})
|
|
.catch((err) => {
|
|
notificationService.error(
|
|
"Erreur",
|
|
"Erreur lors de la modification"
|
|
);
|
|
});
|
|
}}
|
|
/>
|
|
))}
|
|
</div>
|
|
<p className={parseClassName([styles.owner, styles.partCat])}>
|
|
En ligne :
|
|
</p>
|
|
{dataRoom.participants
|
|
.filter((p) => p.online)
|
|
.map((p) => {
|
|
return (
|
|
<p
|
|
className={
|
|
p.nick == user.user.nick ? styles["owner"] : undefined
|
|
}
|
|
>
|
|
<span
|
|
onClick={() => {
|
|
if (user.user.owner && p.nick != user.user.nick) {
|
|
alert.alert({
|
|
title: "Êtes-vous sûr ?",
|
|
active: true,
|
|
message: `Vous aller bannir ${p.nick}`,
|
|
type: AlertType.Warning,
|
|
validate: () => {
|
|
send({
|
|
data: {
|
|
type: "ban",
|
|
code: p.code,
|
|
nick: p.nick,
|
|
status: p.status,
|
|
},
|
|
});
|
|
},
|
|
});
|
|
}
|
|
}}
|
|
title="Bannir"
|
|
className={parseClassName([
|
|
user.user.owner ? styles["nick"] : undefined,
|
|
p.owner || user.user.nick == p.nick
|
|
? styles["isOwner"]
|
|
: undefined,
|
|
])}
|
|
>
|
|
{p.nick}
|
|
</span>
|
|
{p.nick == user.user.nick &&
|
|
isBrowser &&
|
|
localStorage.getItem("token") == null && (
|
|
<span className={styles["code"]}>
|
|
#{user.user.code}
|
|
</span>
|
|
)}
|
|
|
|
{p.owner == true && (
|
|
<span className={styles["admin"]}>Administrateur</span>
|
|
)}
|
|
{user.user.owner &&
|
|
p.nick != user.user.nick &&
|
|
p.code.length == 6 && (
|
|
<span className={styles["code"]}>#{p.code}</span>
|
|
)}
|
|
</p>
|
|
);
|
|
})}
|
|
<p className={parseClassName([styles.owner, styles.partCat])}>
|
|
Hors-ligne :
|
|
</p>
|
|
{dataRoom.participants
|
|
.filter((p) => !p.online)
|
|
.map((p) => {
|
|
return (
|
|
<p
|
|
className={
|
|
p.nick == user.user.nick ? styles["owner"] : undefined
|
|
}
|
|
>
|
|
<span
|
|
onClick={() => {
|
|
if (user.user.owner && p.nick != user.user.nick) {
|
|
alert.alert({
|
|
title: "Êtes-vous sûr ?",
|
|
active: true,
|
|
message: `Vous aller bannir ${p.nick}`,
|
|
type: AlertType.Warning,
|
|
validate: () => {
|
|
send({
|
|
data: {
|
|
type: "ban",
|
|
code: p.code,
|
|
nick: p.nick,
|
|
status: p.status,
|
|
},
|
|
});
|
|
},
|
|
});
|
|
}
|
|
}}
|
|
title="Bannir"
|
|
className={parseClassName([
|
|
user.user.owner ? styles["nick"] : undefined,
|
|
p.owner || user.user.nick == p.nick
|
|
? styles["isOwner"]
|
|
: undefined,
|
|
])}
|
|
>
|
|
{p.nick}
|
|
</span>
|
|
{p.nick == user.user.nick &&
|
|
isBrowser &&
|
|
localStorage.getItem("token") == null && (
|
|
<span className={styles["code"]}>
|
|
#{user.user.code}
|
|
</span>
|
|
)}
|
|
|
|
{p.owner == true && (
|
|
<span className={styles["admin"]}>Administrateur</span>
|
|
)}
|
|
{user.user.owner &&
|
|
p.nick != user.user.nick &&
|
|
p.code.length == 6 && (
|
|
<span className={styles["code"]}>#{p.code}</span>
|
|
)}
|
|
</p>
|
|
);
|
|
})}
|
|
{dataRoom.waiters.length != 0 && (
|
|
<>
|
|
<p className={parseClassName([styles.owner, styles.partCat])}>
|
|
En attente :
|
|
</p>
|
|
{dataRoom.waiters.map((p) => {
|
|
|
|
return (
|
|
<p>
|
|
{p.nick}
|
|
<AiOutlineCheck
|
|
className={styles["accept"]}
|
|
onClick={() => {
|
|
send({
|
|
data: {
|
|
type: "acceptParticipant",
|
|
code: p.code,
|
|
nick: p.nick,
|
|
status: p.status,
|
|
},
|
|
});
|
|
setDataRoom({
|
|
...dataRoom,
|
|
waiters: dataRoom.waiters.filter(
|
|
(w) => w.code != p.code
|
|
),
|
|
});
|
|
}}
|
|
/>
|
|
|
|
<AiOutlineClose
|
|
className={styles["refuse"]}
|
|
onClick={() => {
|
|
send({
|
|
data: { type: "refusedParticipant", code: p.code },
|
|
});
|
|
setDataRoom({
|
|
...dataRoom,
|
|
waiters: dataRoom.waiters.filter(
|
|
(w) => w.code != p.code
|
|
),
|
|
});
|
|
}}
|
|
/>
|
|
</p>
|
|
);
|
|
})}{" "}
|
|
</>
|
|
)}
|
|
</div>
|
|
</div>
|
|
)}
|
|
</Layout>
|
|
);
|
|
}
|