2022-02-28 18:00:30 +00:00
|
|
|
|
<script>
|
2022-09-02 10:25:32 +00:00
|
|
|
|
import { onDestroy } from 'svelte';
|
|
|
|
|
|
2022-11-18 14:38:50 +00:00
|
|
|
|
import { user } from '$lib/stores/user';
|
|
|
|
|
import { ToastsStore } from '$lib/stores/toasts';
|
2023-03-03 13:23:31 +00:00
|
|
|
|
import CorrectionPieChart from '$lib/components/CorrectionPieChart.svelte';
|
2022-11-18 14:38:50 +00:00
|
|
|
|
import QuestionForm from '$lib/components/QuestionForm.svelte';
|
2023-03-03 13:23:31 +00:00
|
|
|
|
import SurveyBadge from '$lib/components/SurveyBadge.svelte';
|
2022-11-18 14:38:50 +00:00
|
|
|
|
import { getQuestion } from '$lib/questions';
|
2022-02-28 18:00:30 +00:00
|
|
|
|
|
2022-12-12 09:24:30 +00:00
|
|
|
|
export let data;
|
2022-02-28 18:00:30 +00:00
|
|
|
|
let survey;
|
2022-12-12 09:24:30 +00:00
|
|
|
|
$: survey = data.survey;
|
2022-02-28 18:00:30 +00:00
|
|
|
|
|
|
|
|
|
let ws_up = false;
|
|
|
|
|
let show_question = null;
|
|
|
|
|
let value;
|
|
|
|
|
|
2022-03-01 12:03:16 +00:00
|
|
|
|
let req_question;
|
|
|
|
|
let nosend = false;
|
2022-03-01 15:38:52 +00:00
|
|
|
|
let timer_init = null;
|
|
|
|
|
let timer_end = null;
|
|
|
|
|
let timer = 0;
|
|
|
|
|
let timer_cancel = null;
|
2022-03-01 12:03:16 +00:00
|
|
|
|
|
|
|
|
|
function afterQUpdate(q) {
|
|
|
|
|
value = undefined;
|
|
|
|
|
if (q) {
|
|
|
|
|
q.getMyResponse().then((response) => {
|
|
|
|
|
if (response && response.value)
|
|
|
|
|
value = response.value;
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$: {
|
|
|
|
|
if (show_question) {
|
|
|
|
|
req_question = getQuestion(show_question);
|
|
|
|
|
req_question.then(afterQUpdate);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2022-03-01 15:38:52 +00:00
|
|
|
|
function updTimer() {
|
|
|
|
|
const now = new Date().getTime();
|
|
|
|
|
if (now > timer_end) {
|
|
|
|
|
timer = 100;
|
|
|
|
|
clearInterval(timer_cancel);
|
|
|
|
|
timer_cancel = null;
|
|
|
|
|
} else {
|
|
|
|
|
const dist1 = timer_end - timer_init;
|
|
|
|
|
const dist2 = timer_end - now;
|
|
|
|
|
timer = Math.ceil(100-dist2*100/dist1);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2022-09-02 10:25:32 +00:00
|
|
|
|
let ws = null;
|
|
|
|
|
let autoreconnect = true;
|
|
|
|
|
onDestroy(() => {
|
|
|
|
|
autoreconnect = false;
|
|
|
|
|
console.log("destroy", ws)
|
|
|
|
|
if (ws) {
|
|
|
|
|
ws.close();
|
|
|
|
|
}
|
|
|
|
|
});
|
2022-02-28 18:00:30 +00:00
|
|
|
|
function wsconnect() {
|
2022-12-12 09:24:30 +00:00
|
|
|
|
ws = new WebSocket((window.location.protocol == 'https:'?'wss://':'ws://') + window.location.host + `/api/surveys/${data.sid}/ws`);
|
2022-02-28 18:00:30 +00:00
|
|
|
|
|
|
|
|
|
ws.addEventListener("open", () => {
|
|
|
|
|
ws_up = true;
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
ws.addEventListener("close", (e) => {
|
|
|
|
|
ws_up = false;
|
|
|
|
|
show_question = false;
|
2022-09-02 10:25:32 +00:00
|
|
|
|
console.log('Socket is closed. Reconnect will be attempted in 1 second.', e.reason, e);
|
|
|
|
|
if (autoreconnect && e.reason != "end")
|
|
|
|
|
setTimeout(function() {
|
|
|
|
|
wsconnect();
|
|
|
|
|
}, 1500);
|
2022-02-28 18:00:30 +00:00
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
ws.addEventListener("error", (err) => {
|
|
|
|
|
ws_up = false;
|
|
|
|
|
console.log('Socket closed due to error.', err.message);
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
ws.addEventListener("message", (message) => {
|
|
|
|
|
const data = JSON.parse(message.data);
|
|
|
|
|
if (data.action && data.action == "new_question") {
|
|
|
|
|
show_question = data.question;
|
2022-09-01 17:14:57 +00:00
|
|
|
|
survey.corrected = data.corrected;
|
2023-03-03 13:23:31 +00:00
|
|
|
|
if (data.stats) {
|
|
|
|
|
stats = data.stats;
|
|
|
|
|
} else {
|
|
|
|
|
stats = null;
|
|
|
|
|
}
|
|
|
|
|
if(data.corrected) {
|
2022-09-02 09:54:58 +00:00
|
|
|
|
corrections = data.corrections;
|
|
|
|
|
} else {
|
|
|
|
|
corrections = null;
|
|
|
|
|
}
|
2022-03-01 15:38:52 +00:00
|
|
|
|
if (timer_cancel) {
|
|
|
|
|
clearInterval(timer_cancel);
|
|
|
|
|
timer_cancel = null;
|
|
|
|
|
}
|
|
|
|
|
if (data.timer) {
|
|
|
|
|
timer_init = new Date().getTime();;
|
|
|
|
|
timer_end = timer_init + data.timer;
|
|
|
|
|
updTimer();
|
|
|
|
|
timer_cancel = setInterval(updTimer, 150);
|
|
|
|
|
} else {
|
|
|
|
|
timer_init = null;
|
|
|
|
|
}
|
2022-09-06 17:26:05 +00:00
|
|
|
|
|
|
|
|
|
} else if (data.action && data.action == "where_are_you") {
|
|
|
|
|
ws.send('{"action":"myscroll", "value": "' + (window.scrollY/window.scrollMaxY) +'", "question": '+show_question+', "corrected": '+(survey.corrected==true)+'}')
|
2022-02-28 18:00:30 +00:00
|
|
|
|
} else {
|
|
|
|
|
show_question = null;
|
2022-03-01 15:38:52 +00:00
|
|
|
|
if (timer_cancel) {
|
|
|
|
|
clearInterval(timer_cancel);
|
|
|
|
|
timer_cancel = null;
|
|
|
|
|
}
|
|
|
|
|
timer_init = null;
|
2022-02-28 18:00:30 +00:00
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
wsconnect();
|
|
|
|
|
|
2022-09-02 11:35:16 +00:00
|
|
|
|
let displaySendInProgress = false;
|
2022-02-28 18:00:30 +00:00
|
|
|
|
function sendValue() {
|
2022-03-01 12:03:16 +00:00
|
|
|
|
if (show_question && value && !nosend) {
|
2022-09-02 11:35:16 +00:00
|
|
|
|
displaySendInProgress = true;
|
2022-02-28 18:00:30 +00:00
|
|
|
|
survey.submitAnswers([{"id_question": show_question, "value": value}], $user.id_user).then((response) => {
|
2022-09-02 11:35:16 +00:00
|
|
|
|
setTimeout(() => displaySendInProgress = false, 150);
|
2022-02-28 18:00:30 +00:00
|
|
|
|
console.log("Vos réponses ont bien étés sauvegardées.");
|
|
|
|
|
}, (error) => {
|
2022-09-02 11:35:16 +00:00
|
|
|
|
displaySendInProgress = false;
|
2022-02-28 18:00:30 +00:00
|
|
|
|
value = null;
|
2022-03-01 12:16:20 +00:00
|
|
|
|
ToastsStore.addErrorToast({
|
|
|
|
|
msg: "Une erreur s'est produite durant l'envoi de vos réponses : " + error + "\nVeuillez réessayer dans quelques instants.",
|
|
|
|
|
});
|
2022-02-28 18:00:30 +00:00
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
}
|
2022-03-01 14:26:30 +00:00
|
|
|
|
|
|
|
|
|
let myQuestion = "";
|
|
|
|
|
let submitQuestionInProgress = false;
|
|
|
|
|
function askQuestion() {
|
|
|
|
|
if (!myQuestion) {
|
|
|
|
|
ToastsStore.addErrorToast({
|
|
|
|
|
msg: "Quel est ta question ?",
|
|
|
|
|
});
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
submitQuestionInProgress = true;
|
|
|
|
|
fetch(`api/surveys/${survey.id}/ask`, {
|
|
|
|
|
method: 'POST',
|
|
|
|
|
headers: {'Accept': 'application/json'},
|
|
|
|
|
body: JSON.stringify({"content": myQuestion}),
|
|
|
|
|
}).then((r) => {
|
|
|
|
|
submitQuestionInProgress = false;
|
|
|
|
|
myQuestion = "";
|
|
|
|
|
ToastsStore.addToast({
|
|
|
|
|
msg: "Ta question a bien été envoyée.",
|
|
|
|
|
title: survey.title,
|
|
|
|
|
color: "success",
|
|
|
|
|
});
|
|
|
|
|
}, (error) => {
|
|
|
|
|
ToastsStore.addErrorToast({
|
|
|
|
|
msg: "Un problème est survenu : " + error.errmsg,
|
|
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
}
|
2022-09-01 20:09:14 +00:00
|
|
|
|
|
2022-09-02 09:54:58 +00:00
|
|
|
|
let corrections = null;
|
2023-03-03 13:23:31 +00:00
|
|
|
|
let stats = null;
|
2022-02-28 18:00:30 +00:00
|
|
|
|
</script>
|
|
|
|
|
|
2022-12-12 09:24:30 +00:00
|
|
|
|
<div
|
|
|
|
|
style={"transition: opacity 150ms ease-out; opacity: " + (displaySendInProgress?1:0)}
|
|
|
|
|
class="ms-2 float-end"
|
|
|
|
|
>
|
|
|
|
|
<div style="position: relative; left: 25%; top: 4px">
|
|
|
|
|
<div style="position: absolute">
|
|
|
|
|
<i class="bi bi-save"></i>
|
2022-09-02 11:35:16 +00:00
|
|
|
|
</div>
|
|
|
|
|
</div>
|
2022-12-12 09:24:30 +00:00
|
|
|
|
<div class="spinner-border text-primary" role="status"></div>
|
|
|
|
|
</div>
|
|
|
|
|
{#if $user && $user.is_admin}
|
|
|
|
|
<a href="surveys/{survey.id}/admin" class="btn btn-primary ms-1 float-end" title="Aller à l'interface d'administration"><i class="bi bi-pencil"></i></a>
|
|
|
|
|
<a href="surveys/{survey.id}/responses" class="btn btn-success ms-1 float-end" title="Voir les réponses"><i class="bi bi-files"></i></a>
|
|
|
|
|
{/if}
|
|
|
|
|
<div class="d-flex align-items-center mb-3 mb-md-4 mb-lg-5">
|
|
|
|
|
<h2>
|
|
|
|
|
<a href="surveys/" class="text-muted" style="text-decoration: none"><</a>
|
|
|
|
|
{survey.title}
|
|
|
|
|
</h2>
|
|
|
|
|
<div
|
|
|
|
|
class="badge rounded-pill ms-2"
|
|
|
|
|
class:bg-success={ws_up}
|
|
|
|
|
class:bg-danger={!ws_up}
|
|
|
|
|
>
|
|
|
|
|
{#if ws_up}Connecté{:else}Déconnecté{/if}
|
2022-02-28 18:00:30 +00:00
|
|
|
|
</div>
|
2022-12-12 09:24:30 +00:00
|
|
|
|
</div>
|
2022-02-28 18:00:30 +00:00
|
|
|
|
|
2022-12-12 09:24:30 +00:00
|
|
|
|
<form on:submit|preventDefault={sendValue}>
|
|
|
|
|
{#if show_question}
|
|
|
|
|
{#await req_question}
|
|
|
|
|
<div class="text-center">
|
|
|
|
|
<div class="spinner-border text-primary mx-3" role="status"></div>
|
|
|
|
|
<span>Chargement d'une nouvelle question …</span>
|
|
|
|
|
</div>
|
|
|
|
|
{:then question}
|
2023-03-03 13:23:31 +00:00
|
|
|
|
{#if stats != null}
|
|
|
|
|
<CorrectionPieChart
|
|
|
|
|
{question}
|
|
|
|
|
proposals={true}
|
|
|
|
|
data={stats}
|
|
|
|
|
/>
|
|
|
|
|
{/if}
|
2022-12-12 09:24:30 +00:00
|
|
|
|
<QuestionForm
|
|
|
|
|
{survey}
|
|
|
|
|
{question}
|
|
|
|
|
readonly={timer >= 100 || survey.corrected}
|
|
|
|
|
{corrections}
|
|
|
|
|
bind:value={value}
|
|
|
|
|
on:change={sendValue}
|
|
|
|
|
>
|
|
|
|
|
{#if timer_init}
|
|
|
|
|
<div class="progress" style="border-radius: 0; height: 4px">
|
|
|
|
|
<div class="progress-bar" class:bg-warning={timer > 85 && timer < 100} class:bg-danger={timer >= 100} role="progressbar" style="width: {timer}%"></div>
|
|
|
|
|
</div>
|
|
|
|
|
{/if}
|
|
|
|
|
</QuestionForm>
|
2023-03-03 13:23:31 +00:00
|
|
|
|
{#if !survey.corrected && question.kind != 'mcq' && question.kind != 'ucq' && question.kind != 'none'}
|
2022-12-12 09:24:30 +00:00
|
|
|
|
<button
|
|
|
|
|
class="btn btn-primary"
|
2022-02-28 18:00:30 +00:00
|
|
|
|
>
|
2022-12-12 09:24:30 +00:00
|
|
|
|
Soumettre cette réponse
|
|
|
|
|
</button>
|
|
|
|
|
{/if}
|
|
|
|
|
{/await}
|
|
|
|
|
{:else if ws_up}
|
|
|
|
|
<h2 class="text-center mb-4">
|
|
|
|
|
Pas de question actuellement.
|
|
|
|
|
</h2>
|
|
|
|
|
<form on:submit|preventDefault={askQuestion}>
|
|
|
|
|
<div class="row">
|
|
|
|
|
<div class="d-none d-sm-block col-sm">
|
|
|
|
|
<hr>
|
|
|
|
|
</div>
|
|
|
|
|
<h3 class="col-sm-auto text-center text-muted mb-3"><label for="askquestion">Vous avez une question ?</label></h3>
|
|
|
|
|
<div class="d-none d-sm-block col-sm">
|
|
|
|
|
<hr>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
<div class="row">
|
|
|
|
|
<div class="offset-md-1 col-md-10 offset-lg-2 col-lg-8 offset-xl-3 col-xl-6 mb-4">
|
|
|
|
|
<div class="input-group">
|
2022-12-15 14:15:38 +00:00
|
|
|
|
<!-- svelte-ignore a11y-autofocus -->
|
2022-12-12 09:24:30 +00:00
|
|
|
|
<textarea
|
|
|
|
|
id="askquestion"
|
|
|
|
|
class="form-control"
|
|
|
|
|
bind:value={myQuestion}
|
|
|
|
|
autofocus
|
|
|
|
|
placeholder="Remarques, soucis, choses pas claires ? Levez la main ou écrivez ici !"
|
|
|
|
|
></textarea>
|
2022-03-01 12:03:16 +00:00
|
|
|
|
<button
|
2022-12-12 09:24:30 +00:00
|
|
|
|
class="d-sm-none btn btn-primary"
|
|
|
|
|
disabled={!myQuestion || submitQuestionInProgress}
|
2022-03-01 12:03:16 +00:00
|
|
|
|
>
|
2022-12-12 09:24:30 +00:00
|
|
|
|
{#if submitQuestionInProgress}
|
|
|
|
|
<div class="spinner-border spinner-border-sm me-1" role="status"></div>
|
|
|
|
|
{/if}
|
|
|
|
|
Poser cette question
|
2022-03-01 12:03:16 +00:00
|
|
|
|
</button>
|
2022-03-01 15:54:04 +00:00
|
|
|
|
</div>
|
|
|
|
|
</div>
|
2022-12-12 09:24:30 +00:00
|
|
|
|
</div>
|
|
|
|
|
{#if myQuestion}
|
|
|
|
|
<div class="d-none d-sm-block text-center mb-4">
|
|
|
|
|
<button
|
|
|
|
|
class="btn btn-primary"
|
|
|
|
|
disabled={submitQuestionInProgress}
|
|
|
|
|
>
|
|
|
|
|
{#if submitQuestionInProgress}
|
|
|
|
|
<div class="spinner-border spinner-border-sm me-1" role="status"></div>
|
|
|
|
|
{/if}
|
|
|
|
|
Poser cette question
|
|
|
|
|
</button>
|
2022-03-01 14:26:30 +00:00
|
|
|
|
</div>
|
2022-12-12 09:24:30 +00:00
|
|
|
|
{/if}
|
|
|
|
|
</form>
|
|
|
|
|
{:else}
|
|
|
|
|
<h2 class="text-center">
|
|
|
|
|
La session est terminée. <small class="text-muted">On se retrouve une prochaine fois…</small>
|
|
|
|
|
</h2>
|
|
|
|
|
{/if}
|
|
|
|
|
</form>
|