generateur_v3/frontend/src/routes/room/[...slug]/+page.svelte

566 lines
16 KiB
Svelte

<script lang="ts">
import { page } from "$app/stores";
import {
getRoom
} from "../../../requests/room.request";
import { getContext, onDestroy, onMount, setContext } from "svelte";
import { writable, type Writable } from "svelte/store";
import { messages, connect, events, handlers } from "../../../store/ws";
import type { Member, ParcoursRead, Room } from "../../../types/room.type";
import { afterNavigate, beforeNavigate, goto } from "$app/navigation";
import AskPseudo from "../../../components/rooms/AskPseudo.svelte";
import Members from "../../../components/rooms/Members.svelte";
import ExerciceSelector from "../../../components/exos/ExerciceSelector.svelte";
import RoomHead from "../../../components/rooms/RoomHead.svelte";
import ParcoursList from "../../../components/rooms/ParcoursList.svelte";
import ParcoursCreate from "../../../components/rooms/ParcoursCreate.svelte";
import ParcoursDetails from "../../../components/rooms/ParcoursDetails.svelte";
import Challenge from "../../../components/rooms/Challenge.svelte";
import { refreshRequest } from "../../../requests/auth.request";
import Waiting from "../../../components/rooms/Waiting.svelte";
import { env } from "$env/dynamic/public";
const p = "p";
const { isAuth } = getContext<{ isAuth: Writable<boolean> }>("auth");
const room = writable<Room | null>(null);
const member = writable<Member | null>(null);
const parcours = writable<ParcoursRead | null>(null);
const ws = connect(`${env.PUBLIC_WS_BASE}room/${$page.params.slug}`);
setContext("room", room);
setContext("member", member);
setContext("parcours", parcours);
setContext("ws", { send: (type: string, data: Object) => ws.send({ type, data }), ws: ws.ws });
const { error, info } = getContext("notif");
const onMessage = (payload: { type: string; data: any }) => {
if (payload == undefined) return;
const { type, data } = payload;
switch (type) {
case "loggedIn":
close();
member.set(data.member);
if (data.member.reconnect_code != "") {
sessionStorage.setItem("reconnect", data.member.reconnect_code);
}
getRoom($page.params.slug, !$isAuth ? data.member.clientId : null).then((r) => {
room.set(r);
});
const parcoursId =
$page.url.searchParams.get("p") ||
$page.url.searchParams.get("corr") ||
$page.url.searchParams.get("c");
if (parcoursId != null) {
ws.send({ type: "sub_parcours", data: { parcours_id: parcoursId } });
}
return;
case "accepted":
close();
if ($page.url.searchParams.get("a") == "waiting") {
goto(`?`);
}
member.set(data.member);
getRoom($page.params.slug, !$isAuth ? data.member.clientId : null).then((r) => {
room.set(r);
});
if (!$isAuth) {
sessionStorage.setItem("reconnect", data.member.reconnect_code);
}
const parcours_id =
$page.url.searchParams.get("p") ||
$page.url.searchParams.get("corr") ||
$page.url.searchParams.get("c");
if (parcours_id != null) {
ws.send({ type: "sub_parcours", data: { parcours_id: parcours_id } });
}
return;
case "waiting":
close();
$member = { ...data.waiter, room: data.room };
goto(`?${new URLSearchParams({ a: "waiting" })}`);
return;
case "refused":
error("Refusé", "L'administrateur a refusé votre demande");
close();
ws?.close(1000);
goto("/room/join");
return;
case "leaved":
if (data.member.id_code == $member!.id_code) {
ws?.close(1000);
goto("/room/join");
sessionStorage.removeItem("reconnect");
return;
}
if ($room != null) {
info("Départ", `*${data.member.username}* n'est plus dans la salle`);
$room.members = [
...$room.members.filter((r) => "waiter_id" in r || r.id_code != data.member.id_code)
];
}
return;
case "banned":
error("Ban", "Vous avez été banni de la salle par l'administrateur");
ws?.close(1000);
goto("/room/join");
sessionStorage.removeItem("reconnect");
return;
case "deleted":
info("Suppression", "La salle a été supprimée par l'administrateur");
ws.close(1000);
goto("/room/join");
return;
case "error":
const { code, msg } = data;
if (code == 401) {
if ($isAuth) {
ws.send({ type: "join", data: { token: localStorage.getItem("token") } });
} else {
show(
//Ask for pseudo and try join
AskPseudo,
{
validate: (p: string) => {
if (p.startsWith("#")) {
ws.send({ type: "login", data: { reconnect_code: p.replace("#", "") } });
} else {
ws.send({ type: "join", data: { username: p } });
}
//close();
}
},
() => {
}
);
}
}
if (code == 422 && msg.toLowerCase().indexOf("signature expired") > -1) {
const refresh = localStorage.getItem("refresh");
if (refresh == null) return;
refreshRequest(refresh).then((r) => {
localStorage.setItem("access", r.access_token);
ws.send({ type: "join", data: { token: r.access_token } });
});
} else {
error("Erreur", "Message : " + msg);
}
if (code == 404) {
ws.close(1000);
goto("/room/join");
}
return;
case "waiter":
if ($room != null) {
$room.members = [...$room?.members, data.waiter];
}
return;
case "disconnect_waiter":
if ($room != null) {
$room.members = [
...$room?.members.filter((m) => "id_code" in m || m.waiter_id != data.waiter.waiter_id)
];
}
return;
case "successfullyRefused":
if ($room != null) {
$room.members = [
...$room?.members.filter((m) => "id_code" in m || m.waiter_id != data.waiter_id)
];
}
return;
case "update_parcours":
if ($room != null) {
$room.parcours = [
...$room.parcours.map((c) => {
if (c.id_code == data.parcours.id_code) {
return data.parcours;
}
return c;
})
];
}
return;
case "parcours_stats":
if ($room != null) {
$room.parcours = [
...$room.parcours.map((c) => {
if (c.id_code == data.parcours.id_code) {
return data.parcours;
}
return c;
})
];
}
return;
case "joined":
if ($room != null) {
info("Arrivée", `*${data.member.username}* a rejoint la salle`)
$room.members = [
...$room?.members.filter(
(m) =>
("id_code" in m && m.id_code != data.member.id_code) ||
("waiter_id" in m && m.waiter_id != data.member.id_code)
),
data.member
];
}
return;
case "connect":
if ($room != null) {
$room.members = [
...$room?.members.map((r) => {
if ("id_code" in r && r.id_code == data.member.id_code) {
return data.member;
}
return r;
})
];
}
return;
case "disconnect":
if ($room != null) {
$room.members = [
...$room?.members.map((r) => {
if ("id_code" in r && r.id_code == data.member.id_code) {
return data.member;
}
return r;
})
];
}
return;
case "add_parcours":
if ($room != null) {
$room.parcours = [...$room?.parcours, data.parcours];
}
return;
case "del_parcours":
if ($room != null) {
$room.parcours = [...$room?.parcours.filter((p) => p.id_code != data.parcours_id)];
}
return;
case "new_visibility":
if ($room != null) {
$room.public = data.public;
}
return;
case "new_name":
if ($room != null) {
$room.name = data.name;
}
return;
}
};
const { show, close } = getContext<{ show: Function; close: Function }>("modal");
const onEvent = (event: { type: string; e: Event | CloseEvent }) => {
if (event == undefined) return;
const { type, e } = event;
if (type == "open") {
//On the open of ws
if ($isAuth) {
ws.send({ type: "login", data: { token: localStorage.getItem("token") } }); // try to login, if denied the message handler tries to join
} else {
const reconnect_code = sessionStorage.getItem("reconnect");
if (reconnect_code !== null) {
// Try to log in if a reconnect code is found
ws.send({ type: "login", data: { reconnect_code } });
return;
}
show(
//Ask for pseudo and try join
AskPseudo,
{
validate: (p: string) => {
if (p.startsWith("#")) {
ws.send({ type: "login", data: { reconnect_code: p.replace("#", "") } });
} else {
ws.send({ type: "join", data: { username: p } });
}
//close();
}
},
() => {
}
);
}
}
};
const parcoursMessage = (payload: { type: string; data: any }) => {
if (payload == undefined || ($parcours == null && $member == null)) return;
const { type, data } = payload;
switch (type) {
case "challenge":
if ($parcours != null && $member != null) {
if (!!$parcours.challenges[data.challenger.id_code]) {
$parcours.challenges[data.challenger.id_code].challenges = [
...$parcours.challenges[data.challenger.id_code].challenges,
{ ...data.challenges[0] }
];
} else {
$parcours.challenges[data.challenger.id_code] = { ...data };
}
if (data.challenges[0].validated == true && data.challenger.id_code == $member.id_code) {
$parcours.validated = true;
}
}
return;
case "newRanks":
if ($parcours != null) {
$parcours.rank = data.rank;
$parcours.memberRank = data.avgRank;
}
return;
case "newTops":
if ($parcours != null) {
$parcours.tops = data.tops;
$parcours.ranking = data.avgTops;
}
return;
case "edit_parcours":
if ($parcours != null && data.parcours.id_code == $parcours.id_code) {
parcours.update((p) => {
if (p == null) return p;
return {
...p,
name: data.parcours.name,
time: data.parcours.time,
max_mistakes: data.parcours.max_mistakes
};
});
if (data.parcours.update_challenges) {
$parcours.exercices = data.parcours.exercices;
$parcours.challenges = {};
$parcours.tops = [];
$parcours.ranking = [];
$parcours.validated = false;
} else {
$parcours.validated = $parcours.pb.mistakes <= $parcours.max_mistakes;
}
}
return
case "challenge_change":
if ($parcours != null && $member != null && !!$parcours.challenges[data.member]) {
$parcours.challenges[data.member].challenges = $parcours.challenges[
data.member
].challenges.map((c) => {
if (c.id_code == data.challenge.id_code) {
return data.challenge;
}
return c;
});
$parcours.challenges[data.member].challenger.validated = data.validated;
if (data.member == $member.id_code) {
$parcours.validated = data.validated;
}
}
return;
case "update_challenges":
if ($parcours != null && $member != null) {
const { challenger, challenges } = data;
if (challenges.length != 0) {
$parcours.challenges[challenger.id_code] = data;
}
if (challenger.id_code == $member.id_code) {
$parcours.validated = data.challenger.validated;
}
}
return;
}
};
handlers.update((h) => {
return { ...h, [$page.params.slug]: onMessage };
});
handlers.update((h) => {
return { ...h, parcours: parcoursMessage };
});
onDestroy(() => {
handlers.update((h) => {
return { ...h, [$page.params.slug]: null };
});
handlers.update((h) => {
return { ...h, parcours: null };
});
});
$: onEvent($events[0]);
let fade = false;
beforeNavigate((n) => {
if(!n.from || !n.to) return;
console.log('NAVIGATION', n.to.url)
if (fade == false && !!n.to?.url) {
fade = true;
n.cancel();
setTimeout(() => {
if (!!n.to?.url) {
goto(n.to?.url);
}
}, 100);
} else {
fade = false;
}
});
afterNavigate((n) => {
if(!n.from || !n.to) return;
let oldParcoursId =
n.from?.url.searchParams.get("p") ||
n.from?.url.searchParams.get("corr") ||
n.from?.url.searchParams.get("c");
let newParcoursId =
n.to?.url.searchParams.get("p") ||
n.to?.url.searchParams.get("corr") ||
n.to?.url.searchParams.get("c");
oldParcoursId = oldParcoursId == "new" ? null : oldParcoursId;
newParcoursId = newParcoursId == "new" ? null : newParcoursId;
if (oldParcoursId != null && newParcoursId == null) {
ws.send({ type: "unsub_parcours", data: { parcours_id: oldParcoursId } });
$parcours = null;
}
/* if (oldParcoursId == newParcoursId) return;
if (oldParcoursId == null && newParcoursId != null) {
//ws.send({ type: 'sub_parcours', data: { parcours_id: newParcoursId } });
} else */
});
onDestroy(() => {
ws.close(1000);
});
$: console.log($page.url.searchParams.toString(),$page.url.searchParams.get('p'))
</script>
<svelte:head>
<title>{$room != null ? $room.name: "Salle - Chargement"}</title>
</svelte:head>
<div class="container">
<div class="full" class:fade>
{#if $page.url.searchParams.get('a') == "waiting"}
<Waiting />
{/if}
{#if $room != null}
{#if $page.url.searchParams.get("p") == null && $page.url.searchParams.get('c') == null && $page.url.searchParams.get('corr') == null}
<div class="room">
<div class="head">
<RoomHead />
</div>
<div class="parcours">
<ParcoursList />
</div>
<div class="members">
<Members />
</div>
</div>
{/if}
{#if $page.url.searchParams.get('p') == 'new'}
<ParcoursCreate />
{:else if $page.url.searchParams.get('p') != 'new' && $page.url.searchParams.get('p') != null}
{#if $page.url.searchParams.get('edit') != '1'}
<ParcoursDetails id_code={$page.url.searchParams.get('p')} />
{:else}
<ParcoursCreate id_code={$page.url.searchParams.get('p')} />
{/if}
{/if}
{#if $page.url.searchParams.get('c') != null}
<Challenge id_code={$page.url.searchParams.get('c')} />
{/if}
{#if $page.url.searchParams.get('corr') != null}
<Challenge id_code={$page.url.searchParams.get('corr')} corrige />
{/if}
{/if}
</div>
</div>
<style lang="scss">
@import "../../../mixins.scss";
.full {
width: 100%;
height: 100%;
transition: 0.2s;
opacity: 1;
}
.fade {
opacity: 0;
transform: translateX(-50px);
transform: scale(0.95);
}
.co {
color: red;
}
.head {
grid-row: 1/2;
grid-column: 1/3;
}
.members {
grid-row: 2/3;
grid-column: 1/2;
}
.parcours {
grid-row: 2/2;
grid-column: 2/2;
}
.room {
display: grid;
grid-template-columns: 1fr 3fr;
grid-template-rows: 60px 1fr;
column-gap: 50px;
row-gap: 10px;
height: 100%;
padding: 7px 15px;
@include down(800) {
display: flex;
flex-direction: column;
padding: 13px;
gap: 10px;
}
}
</style>