344 lines
8.5 KiB
Svelte
344 lines
8.5 KiB
Svelte
<script lang="ts">
|
|
import type {
|
|
Challenge,
|
|
Member,
|
|
ParcoursInfos,
|
|
Room,
|
|
Note as NoteType
|
|
} from "../../types/room.type";
|
|
import { getContext, onDestroy, onMount } from "svelte";
|
|
import { writable, type Writable } from "svelte/store";
|
|
import { challenge, corrigeChallenge, getChallenge, getParcours, sendChallenge } from "../../requests/room.request";
|
|
import { goto } from "$app/navigation";
|
|
import { page } from "$app/stores";
|
|
import InputChallenge from "./InputChallenge.svelte";
|
|
import { parseTimer } from "../../utils/utils";
|
|
import FaUndo from "svelte-icons/fa/FaUndo.svelte";
|
|
|
|
const room: Writable<Room> = getContext("room");
|
|
const member: Writable<Member> = getContext("member");
|
|
|
|
const challengeStore: Writable<{
|
|
challenge: Challenge[];
|
|
id_code: string;
|
|
parcours: ParcoursInfos;
|
|
corriged: boolean;
|
|
mistakes?: number
|
|
validated?: boolean;
|
|
challenger?: { name: string };
|
|
isCorriged?: boolean,
|
|
} | null> = writable(null);
|
|
|
|
export let id_code: string;
|
|
export let corrige: boolean = false;
|
|
|
|
onMount(() => {
|
|
if (!corrige) {
|
|
challenge($room.id_code, id_code, !$member.isUser ? $member.clientId : null).then((p) => {
|
|
challengeStore.set({ ...p, corriged: false });
|
|
});
|
|
} else {
|
|
getChallenge($room.id_code, id_code, !$member.isUser ? $member.clientId : null).then((p) => {
|
|
challengeStore.set({ ...p, challenge: p.data, note: { ...p.note, temporary: !p.isCorriged }, corriged: true });
|
|
remaining = p.time;
|
|
});
|
|
}
|
|
});
|
|
|
|
|
|
let timer: number | null = null;
|
|
let remaining: number | null = null;
|
|
const {error, success} = getContext("notif");
|
|
$: {
|
|
if (!corrige && $challengeStore != null && remaining == null) {
|
|
remaining = $challengeStore.parcours.time * 60;
|
|
}
|
|
}
|
|
|
|
$: {
|
|
if (!corrige && $challengeStore != null && timer == null && remaining != null) {
|
|
timer = window.setInterval(() => {
|
|
remaining = remaining! - 1;
|
|
}, 1000);
|
|
}
|
|
}
|
|
|
|
onDestroy(() => {
|
|
if (timer != null) {
|
|
clearInterval(timer);
|
|
}
|
|
});
|
|
</script>
|
|
|
|
<div class="full">
|
|
{#if $challengeStore != null}
|
|
<div class="head">
|
|
<h1>
|
|
{$challengeStore.parcours.name}
|
|
|
|
{#if corrige && !!$challengeStore.challenger && remaining != null}
|
|
<span class="correction-info">
|
|
Correction de <span class="italic">{$challengeStore.parcours.name}</span> par
|
|
<span class="italic underline">{$challengeStore.challenger.name}</span>
|
|
en {parseTimer(remaining)} (cliquez sur les réponses pour voir)</span
|
|
>
|
|
{:else}
|
|
<span
|
|
class="icon"
|
|
on:click={() => {
|
|
challenge($room.id_code, id_code, !$member.isUser ? $member.clientId : null).then(
|
|
(p) => {
|
|
challengeStore.set({ ...p, corriged: false });
|
|
remaining = null;
|
|
if (timer != null) {
|
|
clearInterval(timer);
|
|
timer = null;
|
|
}
|
|
}
|
|
);
|
|
}}
|
|
title={'Réessayer'}
|
|
on:keydown={() => {}}><FaUndo /></span
|
|
>
|
|
{/if}
|
|
</h1>
|
|
|
|
{#if $challengeStore.mistakes}
|
|
<p class="mistakes" class:validated={$challengeStore.validated}>{$challengeStore.mistakes} fautes</p>
|
|
{/if}
|
|
|
|
{#if !corrige}
|
|
<p
|
|
class="timer"
|
|
class:oneminute={remaining != null && remaining < 60}
|
|
class:late={(remaining != null && remaining < 0) ||
|
|
[9, 7, 5, 3, 1].includes(remaining != null ? remaining : 0)}
|
|
>
|
|
{remaining != null && parseTimer(remaining)}
|
|
</p>
|
|
{/if}
|
|
</div>
|
|
|
|
{#each $challengeStore.challenge as e, d (`${$challengeStore.id_code}_${d}`)}
|
|
<div class="exo">
|
|
<div class="infos">
|
|
<h2>Exercice {d + 1} : <span>{e.exo.name}</span></h2>
|
|
{#if e.exo.consigne != null}
|
|
<p>
|
|
{e.exo.consigne}
|
|
</p>
|
|
{/if}
|
|
</div>
|
|
<div class="data">
|
|
{#each e.data as c, a}
|
|
<div class="calcul">
|
|
{#each c.calcul.replace(']', '] ').replace('[', ' [').split(' ') as i, b}
|
|
{#if i.startsWith('[') && i.endsWith(']')}
|
|
<InputChallenge
|
|
bind:value={c.inputs[parseInt(i.replace('[', '').replace(']', ''))].value}
|
|
bind:correction={c.inputs[parseInt(i.replace('[', '').replace(']', ''))]
|
|
.correction}
|
|
corriged={$challengeStore.corriged}
|
|
bind:valid={c.inputs[parseInt(i.replace('[', '').replace(']', ''))].valid}
|
|
corrigeable={corrige}
|
|
admin={$member.isAdmin}
|
|
/>
|
|
{:else}
|
|
{i}{' '}
|
|
{/if}
|
|
{/each}
|
|
</div>
|
|
{/each}
|
|
</div>
|
|
</div>
|
|
{/each}
|
|
<div>
|
|
{#if !corrige}
|
|
<button
|
|
hidden={$challengeStore.corriged}
|
|
class="primary-btn"
|
|
on:click={() => {
|
|
if ($challengeStore == null || remaining == null) return;
|
|
sendChallenge(
|
|
$room.id_code,
|
|
id_code,
|
|
$challengeStore.id_code,
|
|
{
|
|
challenge: $challengeStore.challenge,
|
|
time: $challengeStore.parcours.time * 60 - remaining
|
|
},
|
|
!$member.isUser ? $member.clientId : null
|
|
).then((r) => {
|
|
if ($challengeStore != null) {
|
|
$challengeStore.challenge = r.data;
|
|
$challengeStore.corriged = true;
|
|
$challengeStore.mistakes = r.mistakes
|
|
$challengeStore.validated = r.validated;
|
|
}
|
|
if (timer != null) {
|
|
clearInterval(timer);
|
|
}
|
|
});
|
|
}}>Valider !
|
|
</button
|
|
>
|
|
<button
|
|
hidden={!$challengeStore.corriged}
|
|
class="primary-btn"
|
|
on:click={() => {
|
|
console.log('RETRY CLICKED')
|
|
challenge($room.id_code, id_code, !$member.isUser ? $member.clientId : null).then((p) => {
|
|
challengeStore.set({ ...p, corriged: false });
|
|
remaining = null;
|
|
if (timer != null) {
|
|
clearInterval(timer);
|
|
timer = null;
|
|
}
|
|
});
|
|
}}>Réessayer !
|
|
</button
|
|
>
|
|
{:else if $member.isAdmin}
|
|
<button
|
|
hidden={!$challengeStore.corriged}
|
|
class="primary-btn"
|
|
on:click={() => {
|
|
corrigeChallenge($room.id_code, id_code,$challengeStore?.challenge, !$member.isUser ? $member.clientId : null).then((p) => {
|
|
if($challengeStore == null) return
|
|
$challengeStore.challenge = p.data
|
|
$challengeStore.mistakes = p.mistakes
|
|
$challengeStore.validated = p.validated
|
|
success('Corrigé !', 'Le challenge a été corrigé avec succès !')
|
|
}).catch(()=>{
|
|
error('Erreur', 'Une erreur est survenue lors de la correction du challenge')
|
|
});
|
|
}}>Valider !
|
|
</button
|
|
>
|
|
{/if}
|
|
|
|
<button
|
|
class="danger-btn"
|
|
on:click={() => {
|
|
if ($challengeStore == null) return;
|
|
goto(`?${new URLSearchParams({p: $challengeStore.parcours.id_code}).toString()}`);
|
|
}}>{!$challengeStore.corriged ? "Annuler !" : "Retour"}</button
|
|
>
|
|
</div>
|
|
{/if}
|
|
</div>
|
|
<style lang="scss">
|
|
@import "../../mixins";
|
|
|
|
.full {
|
|
padding: 7px 15px;
|
|
}
|
|
|
|
.timer {
|
|
font-size: 2em;
|
|
color: $green;
|
|
font-weight: 800;
|
|
}
|
|
|
|
.oneminute {
|
|
color: $orange;
|
|
}
|
|
|
|
.head {
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: space-between;
|
|
margin: 40px 0;
|
|
min-height: 70px;
|
|
@include down(800px) {
|
|
flex-direction: column;
|
|
text-align: center;
|
|
h1{
|
|
flex-direction: column;
|
|
}
|
|
}
|
|
|
|
@include up(800px) {
|
|
.correction-info::before{
|
|
content: " - ";
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
.late {
|
|
color: $red;
|
|
}
|
|
|
|
.calcul {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 10px;
|
|
position: relative;
|
|
}
|
|
|
|
.data {
|
|
display: grid;
|
|
grid-template-columns: repeat(auto-fill, minmax(250px, 1fr));
|
|
gap: 10px;
|
|
}
|
|
|
|
.infos {
|
|
h2 {
|
|
font-size: 1.2em;
|
|
|
|
span {
|
|
font-style: italic;
|
|
}
|
|
}
|
|
|
|
p {
|
|
font-size: 1em;
|
|
font-style: italic;
|
|
text-decoration: underline;
|
|
}
|
|
|
|
margin-bottom: 10px;
|
|
}
|
|
|
|
.exo {
|
|
margin-bottom: 30px;
|
|
margin-top: 20px;
|
|
}
|
|
|
|
.icon {
|
|
height: 20px;
|
|
width: 20px;
|
|
cursor: pointer;
|
|
display: flex;
|
|
transition: 0.2s;
|
|
|
|
&:hover {
|
|
transform: rotate(360deg);
|
|
}
|
|
}
|
|
|
|
h1 {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 20px;
|
|
font-size: 2.3em;
|
|
}
|
|
|
|
.correction-info {
|
|
font-size: 0.6em;
|
|
color: grey;
|
|
font-weight: 600;
|
|
}
|
|
|
|
.mistakes {
|
|
font-weight: 700;
|
|
font-size: 2em;
|
|
color: $red;
|
|
}
|
|
|
|
.validated {
|
|
color: $green;
|
|
}
|
|
</style>
|