Compare commits

..

No commits in common. "e0cd502c352a2fe5e7f5f016cc2cc5e343793af9" and "fdceb2547ca9df521f35db2cb6fbe92163c64dad" have entirely different histories.

11 changed files with 64 additions and 381 deletions

View File

@ -98,16 +98,9 @@ func msgCurrentState(survey *Survey) (msg WSMessage) {
Action: "pause", Action: "pause",
} }
} else { } else {
var correction map[string]int
if survey.Corrected {
correction = getCorrectionString(*survey.Direct)
}
msg = WSMessage{ msg = WSMessage{
Action: "new_question", Action: "new_question",
QuestionId: survey.Direct, QuestionId: survey.Direct,
Corrected: survey.Corrected,
Corrections: correction,
} }
} }
return return
@ -153,15 +146,13 @@ func WSWriteAll(message WSMessage) {
} }
type WSMessage struct { type WSMessage struct {
Action string `json:"action"` Action string `json:"action"`
SurveyId *int64 `json:"survey,omitempty"` SurveyId *int64 `json:"survey,omitempty"`
QuestionId *int64 `json:"question,omitempty"` QuestionId *int64 `json:"question,omitempty"`
Stats map[string]interface{} `json:"stats,omitempty"` Stats map[string]interface{} `json:"stats,omitempty"`
UserId *int64 `json:"user,omitempty"` UserId *int64 `json:"user,omitempty"`
Response string `json:"value,omitempty"` Response string `json:"value,omitempty"`
Corrected bool `json:"corrected,omitempty"` Timer uint `json:"timer,omitempty"`
Corrections map[string]int `json:"corrections,omitempty"`
Timer uint `json:"timer,omitempty"`
} }
func (s *Survey) WSWriteAll(message WSMessage) { func (s *Survey) WSWriteAll(message WSMessage) {
@ -238,25 +229,6 @@ loopadmin:
log.Println(u.Login, "admin disconnected") log.Println(u.Login, "admin disconnected")
} }
func getCorrectionString(qid int64) (ret map[string]int) {
q, err := getQuestion(int(qid))
if err != nil {
return
}
cts, err := q.GetCorrectionTemplates()
if err != nil {
return
}
ret = map[string]int{}
for _, ct := range cts {
ret[ct.RegExp] = ct.Score
}
return
}
func SurveyWSAdmin(c *gin.Context) { func SurveyWSAdmin(c *gin.Context) {
u := c.MustGet("LoggedUser").(*User) u := c.MustGet("LoggedUser").(*User)
survey := c.MustGet("survey").(*Survey) survey := c.MustGet("survey").(*Survey)
@ -302,29 +274,15 @@ func SurveyWSAdmin(c *gin.Context) {
if *survey.Direct != 0 { if *survey.Direct != 0 {
var z int64 = 0 var z int64 = 0
survey.Direct = &z survey.Direct = &z
survey.Corrected = false
survey.Update() survey.Update()
} }
go func(corrected bool) { go func() {
time.Sleep(time.Duration(OffsetQuestionTimer+v.Timer) * time.Millisecond) time.Sleep(time.Duration(OffsetQuestionTimer+v.Timer) * time.Millisecond)
survey.WSWriteAll(WSMessage{Action: "pause"})
if corrected { WSAdminWriteAll(WSMessage{Action: "pause", SurveyId: &survey.Id})
survey.Corrected = v.Corrected }()
survey.Update()
survey.WSWriteAll(WSMessage{Action: "new_question", QuestionId: v.QuestionId, Corrected: true, Corrections: getCorrectionString(*v.QuestionId)})
} else {
survey.WSWriteAll(WSMessage{Action: "pause"})
WSAdminWriteAll(WSMessage{Action: "pause", SurveyId: &survey.Id})
}
}(v.Corrected)
v.Corrected = false
} else { } else {
survey.Direct = v.QuestionId survey.Direct = v.QuestionId
survey.Corrected = v.Corrected
if v.Corrected {
v.Corrections = getCorrectionString(*v.QuestionId)
}
} }
_, err = survey.Update() _, err = survey.Update()
if err != nil { if err != nil {

50
help.go
View File

@ -1,10 +1,8 @@
package main package main
import ( import (
"fmt"
"log" "log"
"net/http" "net/http"
"strconv"
"time" "time"
"github.com/gin-gonic/gin" "github.com/gin-gonic/gin"
@ -12,7 +10,7 @@ import (
func declareAPIAdminHelpRoutes(router *gin.RouterGroup) { func declareAPIAdminHelpRoutes(router *gin.RouterGroup) {
router.GET("/help", func(c *gin.Context) { router.GET("/help", func(c *gin.Context) {
nhs, err := getNeedHelps("WHERE date_treated IS NULL") nhs, err := getNeedHelps()
if err != nil { if err != nil {
log.Println("Unable to getNeedHelps:", err) log.Println("Unable to getNeedHelps:", err)
c.AbortWithStatusJSON(http.StatusInternalServerError, gin.H{"errmsg": "An error occurs during need helps retrieval. Please retry."}) c.AbortWithStatusJSON(http.StatusInternalServerError, gin.H{"errmsg": "An error occurs during need helps retrieval. Please retry."})
@ -21,29 +19,6 @@ func declareAPIAdminHelpRoutes(router *gin.RouterGroup) {
c.JSON(http.StatusOK, nhs) c.JSON(http.StatusOK, nhs)
}) })
needhelpsRoutes := router.Group("/help/:hid")
needhelpsRoutes.Use(needHelpHandler)
needhelpsRoutes.PUT("", func(c *gin.Context) {
current := c.MustGet("needhelp").(*NeedHelp)
var new NeedHelp
if err := c.ShouldBindJSON(&new); err != nil {
c.AbortWithStatusJSON(http.StatusBadRequest, gin.H{"errmsg": err.Error()})
return
}
new.Id = current.Id
if err := new.Update(); err != nil {
log.Println("Unable to Update needhelp:", err)
c.AbortWithStatusJSON(http.StatusInternalServerError, gin.H{"errmsg": fmt.Sprintf("An error occurs during needhelp entry updation: %s", err.Error())})
return
} else {
c.JSON(http.StatusOK, new)
}
})
} }
func declareAPIAuthHelpRoutes(router *gin.RouterGroup) { func declareAPIAuthHelpRoutes(router *gin.RouterGroup) {
@ -61,19 +36,6 @@ func declareAPIAuthHelpRoutes(router *gin.RouterGroup) {
}) })
} }
func needHelpHandler(c *gin.Context) {
if hid, err := strconv.Atoi(string(c.Param("hid"))); err != nil {
c.AbortWithStatusJSON(http.StatusBadRequest, gin.H{"errmsg": "Bad need help identifier."})
return
} else if nh, err := getNeedHelp(hid); err != nil {
c.AbortWithStatusJSON(http.StatusNotFound, gin.H{"errmsg": "Need help entry not found."})
return
} else {
c.Set("needhelp", nh)
c.Next()
}
}
type NeedHelp struct { type NeedHelp struct {
Id int64 `json:"id"` Id int64 `json:"id"`
IdUser int64 `json:"id_user"` IdUser int64 `json:"id_user"`
@ -82,8 +44,8 @@ type NeedHelp struct {
DateTreated *time.Time `json:"treated,omitempty"` DateTreated *time.Time `json:"treated,omitempty"`
} }
func getNeedHelps(cond string) (nh []NeedHelp, err error) { func getNeedHelps() (nh []NeedHelp, err error) {
if rows, errr := DBQuery("SELECT id_need_help, id_user, date, comment, date_treated FROM user_need_help " + cond); errr != nil { if rows, errr := DBQuery("SELECT id_need_help, id_user, date, comment, date_treated FROM user_need_help"); errr != nil {
return nil, errr return nil, errr
} else { } else {
defer rows.Close() defer rows.Close()
@ -103,12 +65,6 @@ func getNeedHelps(cond string) (nh []NeedHelp, err error) {
} }
} }
func getNeedHelp(id int) (n *NeedHelp, err error) {
n = new(NeedHelp)
err = DBQueryRow("SELECT id_need_help, id_user, date, comment, date_treated FROM user_need_help WHERE id_need_help=?", id).Scan(&n.Id, &n.IdUser, &n.Date, &n.Comment, &n.DateTreated)
return
}
func (u *User) NewNeedHelp() (NeedHelp, error) { func (u *User) NewNeedHelp() (NeedHelp, error) {
if res, err := DBExec("INSERT INTO user_need_help (id_user, comment) VALUES (?, ?)", u.Id, ""); err != nil { if res, err := DBExec("INSERT INTO user_need_help (id_user, comment) VALUES (?, ?)", u.Id, ""); err != nil {
return NeedHelp{}, err return NeedHelp{}, err

View File

@ -1,8 +1,6 @@
package main package main
import ( import (
"database/sql"
"errors"
"log" "log"
"net/http" "net/http"
"strconv" "strconv"
@ -29,7 +27,7 @@ func declareAPIAuthResponsesRoutes(router *gin.RouterGroup) {
} }
var responses []Response var responses []Response
if err := c.ShouldBindJSON(&responses); err != nil { if err := c.ShouldBindJSON(responses); err != nil {
c.AbortWithStatusJSON(http.StatusBadRequest, gin.H{"errmsg": err.Error()}) c.AbortWithStatusJSON(http.StatusBadRequest, gin.H{"errmsg": err.Error()})
return return
} }
@ -47,7 +45,7 @@ func declareAPIAuthResponsesRoutes(router *gin.RouterGroup) {
} }
for _, response := range responses { for _, response := range responses {
if !uauth.IsAdmin && !s.Shown && (s.Corrected || s.Direct == nil || *s.Direct != response.IdQuestion) { if !uauth.IsAdmin && !s.Shown && (s.Direct == nil || *s.Direct != response.IdQuestion) {
c.AbortWithStatusJSON(http.StatusForbidden, gin.H{"errmsg": "Cette question n'est pas disponible"}) c.AbortWithStatusJSON(http.StatusForbidden, gin.H{"errmsg": "Cette question n'est pas disponible"})
return return
} else if len(response.Answer) > 0 { } else if len(response.Answer) > 0 {
@ -144,7 +142,7 @@ func declareAPIAuthQuestionResponsesRoutes(router *gin.RouterGroup) {
q := c.MustGet("question").(*Question) q := c.MustGet("question").(*Question)
res, err := q.GetMyResponse(u, false) res, err := q.GetMyResponse(u, false)
if err != nil && !errors.Is(err, sql.ErrNoRows) { if err != nil {
log.Printf("Unable to GetMyResponse(uid=%d;qid=%d;false): %s", u.Id, q.Id, err.Error()) log.Printf("Unable to GetMyResponse(uid=%d;qid=%d;false): %s", u.Id, q.Id, err.Error())
c.AbortWithStatusJSON(http.StatusInternalServerError, gin.H{"errmsg": "An error occurs during response retrieval."}) c.AbortWithStatusJSON(http.StatusInternalServerError, gin.H{"errmsg": "An error occurs during response retrieval."})
return return

View File

@ -31,41 +31,34 @@
return req; return req;
} }
let req_proposals = null; let req_proposals = null;
export let proposals = null;
let req_responses = null; let req_responses = null;
let mean = null;
export let data = { if (question.kind == "int") {
req_responses = question.getResponses();
req_responses.then((responses) => {
const proposal_idx = { };
for (const res of responses) {
if (proposal_idx[res.value]) {
data.datasets[0].values[proposal_idx[res.value]] += 1;
} else {
data.labels.push(res.value);
data.datasets[0].values.push(1);
proposal_idx[res.value] = new String(data.labels.length - 1);
}
}
});
} else {
req_proposals = refreshProposals();
}
let data = {
labels: [], labels: [],
datasets: [ datasets: [
{ {
values: [] values: []
} }
] ]
}; };
if (!proposals) {
if (question.kind == "int") {
req_responses = question.getResponses();
req_responses.then((responses) => {
const values = [];
const proposal_idx = { };
for (const res of responses) {
if (proposal_idx[res.value]) {
data.datasets[0].values[proposal_idx[res.value]] += 1;
values.push(Number(res.value));
} else {
data.labels.push(res.value);
data.datasets[0].values.push(1);
proposal_idx[res.value] = new String(data.labels.length - 1);
}
}
mean = Math.trunc(values.reduce((p, e) => p + e) / values.length*10)/10;
});
} else {
req_proposals = refreshProposals();
}
}
</script> </script>
<div class="{className}"> <div class="{className}">
@ -81,16 +74,7 @@
<span>Récupération des réponses&hellip;</span> <span>Récupération des réponses&hellip;</span>
</div> </div>
{:then} {:then}
{#if mean !== null} <Chart data={data} type="pie" maxSlices="9" />
<div class="text-center">
Moyenne représentative&nbsp;: <strong>{mean}</strong>
</div>
{/if}
{#if question.kind === "mcq"}
<Chart data={data} type="bar" />
{:else}
<Chart data={data} type="pie" maxSlices="9" />
{/if}
{/await} {/await}
{/await} {/await}
</div> </div>

View File

@ -19,35 +19,6 @@
templates = templates; templates = templates;
} }
function genTemplates() {
question.getProposals().then((proposals) => {
let i = 0;
for (const p of proposals) {
// Search proposal in templates
let found = false;
for (const tpl of templates) {
if (tpl.regexp.indexOf(p.id.toString()) !== -1) {
found = true;
break;
}
}
if (!found) {
const ct = new CorrectionTemplate()
ct.id_question = question.id;
ct.regexp = p.id.toString();
ct.label = String.fromCharCode(97 + i);
ct.save().then((ct) => {
templates.push(ct);
templates = templates;
});
}
i++;
}
})
}
function delTemplate(tpl) { function delTemplate(tpl) {
tpl.delete().then(() => { tpl.delete().then(() => {
const idx = templates.findIndex((e) => e.id === tpl.id); const idx = templates.findIndex((e) => e.id === tpl.id);
@ -138,13 +109,4 @@
> >
<i class="bi bi-plus"></i> Ajouter un template <i class="bi bi-plus"></i> Ajouter un template
</button> </button>
{#if question.kind == "mcq" || question.kind == "ucq"}
<button
type="button"
class="btn btn-outline-info me-1"
on:click={genTemplates}
>
<i class="bi bi-magic"></i> Générer les templates
</button>
{/if}
</div> </div>

View File

@ -14,7 +14,6 @@
export let qid; export let qid;
export let response_history = null; export let response_history = null;
export let readonly = false; export let readonly = false;
export let corrections = {};
export let survey = null; export let survey = null;
export let value = ""; export let value = "";
@ -92,8 +91,6 @@
kind={question.kind} kind={question.kind}
{proposals} {proposals}
readonly readonly
live={survey.direct !== null}
{corrections}
bind:value={value} bind:value={value}
on:change={() => { dispatch("change"); }} on:change={() => { dispatch("change"); }}
/> />
@ -111,8 +108,6 @@
kind={question.kind} kind={question.kind}
{proposals} {proposals}
{readonly} {readonly}
live={survey.direct !== null}
{corrections}
bind:value={value} bind:value={value}
on:change={() => { dispatch("change"); }} on:change={() => { dispatch("change"); }}
/> />
@ -137,7 +132,7 @@
></textarea> ></textarea>
{/if} {/if}
{#if survey && survey.corrected && response_history} {#if survey && survey.corrected}
<ResponseCorrected <ResponseCorrected
response={response_history} response={response_history}
{survey} {survey}

View File

@ -5,11 +5,9 @@
export let edit = false; export let edit = false;
export let proposals = []; export let proposals = [];
export let live = false;
export let kind = 'mcq'; export let kind = 'mcq';
export let prefixid = ''; export let prefixid = '';
export let readonly = false; export let readonly = false;
export let corrections = {};
export let id_question = 0; export let id_question = 0;
export let value; export let value;
@ -30,14 +28,12 @@
} }
</script> </script>
<div class:d-flex={live} class:justify-content-around={live}>
{#each proposals as proposal, pid (proposal.id)} {#each proposals as proposal, pid (proposal.id)}
<div class="form-check"> <div class="form-check">
{#if kind == 'mcq'} {#if kind == 'mcq'}
<input <input
type="checkbox" type="checkbox"
class:btn-check={live} class="form-check-input"
class:form-check-input={!live}
disabled={readonly} disabled={readonly}
name={prefixid + 'proposal' + proposal.id_question} name={prefixid + 'proposal' + proposal.id_question}
id={prefixid + 'p' + proposal.id} id={prefixid + 'p' + proposal.id}
@ -48,8 +44,7 @@
{:else} {:else}
<input <input
type="radio" type="radio"
class:btn-check={live} class="form-check-input"
class:form-check-input={!live}
disabled={readonly} disabled={readonly}
name={prefixid + 'proposal' + proposal.id_question} name={prefixid + 'proposal' + proposal.id_question}
id={prefixid + 'p' + proposal.id} id={prefixid + 'p' + proposal.id}
@ -89,14 +84,7 @@
</form> </form>
{:else} {:else}
<label <label
class:form-check-label={!live} class="form-check-label"
class:btn={live}
class:btn-lg={live}
class:btn-primary={live && !corrections && value.indexOf(proposal.id.toString()) != -1}
class:btn-outline-primary={live && !corrections && value.indexOf(proposal.id.toString()) == -1}
class:btn-success={live && corrections && corrections[proposal.id] == 0}
class:btn-outline-warning={live && corrections && corrections[proposal.id] != 0 && corrections[proposal.id] != -100}
class:btn-outline-danger={live && corrections && corrections[proposal.id] == -100}
for={prefixid + 'p' + proposal.id} for={prefixid + 'p' + proposal.id}
> >
{proposal.label} {proposal.label}
@ -104,7 +92,6 @@
{/if} {/if}
</div> </div>
{/each} {/each}
</div>
{#if edit} {#if edit}
{#if kind == 'mcq'} {#if kind == 'mcq'}
<input <input

View File

@ -51,51 +51,10 @@ export async function getUserScore(uid, survey) {
} }
} }
export class UserNeedingHelp {
constructor(res) {
if (res) {
this.update(res);
}
}
update({ id, id_user, date, comment, treated }) {
this.id = id;
this.id_user = id_user;
this.date = new Date(date);
this.comment = comment;
if (treated) {
this.treated = new Date(treated);
} else {
this.treated = null;
}
}
mark_treated() {
this.treated = new Date();
}
async save() {
const res = await fetch(this.id?`api/help/${this.id}`:'api/help', {
method: this.id?'PUT':'POST',
headers: {'Accept': 'application/json'},
body: JSON.stringify(this),
});
if (res.status == 200) {
const data = await res.json()
this.update(data);
return data;
} else {
throw new Error((await res.json()).errmsg);
}
}
}
export async function getUserNeedingHelp() { export async function getUserNeedingHelp() {
const res = await fetch(`api/help`, {headers: {'Accept': 'application/json'}}) const res = await fetch(`api/help`, {headers: {'Accept': 'application/json'}})
if (res.status == 200) { if (res.status == 200) {
return (await res.json()).map((nh) => { return await res.json();
return new UserNeedingHelp(nh)
});
} else { } else {
throw new Error((await res.json()).errmsg); throw new Error((await res.json()).errmsg);
} }

View File

@ -1,24 +1,10 @@
<script lang="ts"> <script lang="ts">
import { user } from '../stores/user'; import { user } from '../stores/user';
import { getUser, getUserNeedingHelp } from '../lib/users'; import { getUser, getUserNeedingHelp } from '../lib/users';
import DateFormat from '../components/DateFormat.svelte';
import SurveyList from '../components/SurveyList.svelte'; import SurveyList from '../components/SurveyList.svelte';
import ValidateSubmissions from '../components/ValidateSubmissions.svelte'; import ValidateSubmissions from '../components/ValidateSubmissions.svelte';
let direct = null; let direct = null;
let users_needing_help = [];
$: if ($user && $user.is_admin) {
users_needing_help = getUserNeedingHelp();
}
async function mark_needhelp_treated(unh) {
unh.mark_treated();
unh.save().then(() => {
users_needing_help = getUserNeedingHelp();
});
}
</script> </script>
<div class="card bg-light"> <div class="card bg-light">
@ -43,7 +29,7 @@
{#if $user.is_admin} {#if $user.is_admin}
<p class="lead">Demande d'aide&nbsp;:</p> <p class="lead">Demande d'aide&nbsp;:</p>
{#await users_needing_help} {#await getUserNeedingHelp()}
<span class="spinner-border spinner-border" role="status" aria-hidden="true"></span> <span class="spinner-border spinner-border" role="status" aria-hidden="true"></span>
{:then nhs} {:then nhs}
<ul style="columns: 2"> <ul style="columns: 2">
@ -54,14 +40,7 @@
{:then u} {:then u}
<a href="users/{u.id}">{u.login}</a> <a href="users/{u.id}">{u.login}</a>
{/await} {/await}
(<DateFormat date={user.date} dateStyle="medium" timeStyle="medium" />) ({user.date})
<button
type="button"
class="btn btn-sm btn-info"
on:click={e => {mark_needhelp_treated(user)}}
>
<i class="bi bi-check" title="Marquer la demande d'aide comme traîtée"></i>
</button>
</li> </li>
{/each} {/each}
</ul> </ul>

View File

@ -11,7 +11,6 @@
<script> <script>
import { user } from '../../../stores/user'; import { user } from '../../../stores/user';
import CorrectionPieChart from '../../../components/CorrectionPieChart.svelte';
import SurveyAdmin from '../../../components/SurveyAdmin.svelte'; import SurveyAdmin from '../../../components/SurveyAdmin.svelte';
import SurveyBadge from '../../../components/SurveyBadge.svelte'; import SurveyBadge from '../../../components/SurveyBadge.svelte';
import { getSurvey } from '../../../lib/surveys'; import { getSurvey } from '../../../lib/surveys';
@ -44,8 +43,7 @@
let wsstats = null; let wsstats = null;
let current_question = null; let current_question = null;
let responses = {}; let responses = {};
let corrected = false; let timer = 20000;
let timer = 20;
let timer_end = null; let timer_end = null;
let timer_remain = 0; let timer_remain = 0;
let timer_cancel = null; let timer_cancel = null;
@ -85,52 +83,6 @@
responsesbyid = tmp; responsesbyid = tmp;
} }
let graph_data = {labels:[]};
async function reset_graph_data(questionid) {
if (questionid) {
const labels = [];
const flabels = [];
let question = null;
for (const q of await req_questions) {
if (q.id == current_question) {
question = q;
}
}
if (question) {
for (const p of await question.getProposals()) {
flabels.push(p.id.toString());
labels.push(p.label);
}
}
graph_data = {
labels,
flabels,
datasets: [
{
values: labels.map(() => 0)
}
]
}
}
if (current_question && responses[current_question] && graph_data.labels.length != 0) {
const values = graph_data.datasets[0].values.map(() => 0);
for (const u in responses[current_question]) {
const res = responses[current_question][u];
for (const r of res.split(',')) {
let idx = graph_data.flabels.indexOf(r);
values[idx] += 1;
}
}
graph_data.datasets[0].values = values;
}
}
let asks = []; let asks = [];
function wsconnect() { function wsconnect() {
if (ws !== null) return; if (ws !== null) return;
@ -146,7 +98,7 @@
ws.addEventListener("close", (e) => { ws.addEventListener("close", (e) => {
ws_up = false; ws_up = false;
console.log('Socket is closed. Reconnect will be attempted in 1 second.'); console.log('Socket is closed. Reconnect will be attempted in 1 second.', e);
ws = null; ws = null;
updateSurvey(); updateSurvey();
setTimeout(function() { setTimeout(function() {
@ -154,6 +106,10 @@
}, 1500); }, 1500);
}); });
ws.onerror((evt) => {
console.log('onerror', evt)
})
ws.addEventListener("error", (err) => { ws.addEventListener("error", (err) => {
ws_up = false; ws_up = false;
console.log('Socket closed due to error.', err); console.log('Socket closed due to error.', err);
@ -162,6 +118,7 @@
ws.addEventListener("message", (message) => { ws.addEventListener("message", (message) => {
const data = JSON.parse(message.data); const data = JSON.parse(message.data);
console.log(data);
if (data.action && data.action == "new_question") { if (data.action && data.action == "new_question") {
current_question = data.question; current_question = data.question;
if (timer_cancel) { if (timer_cancel) {
@ -174,14 +131,11 @@
} else { } else {
timer_end = null; timer_end = null;
} }
reset_graph_data(data.question);
} else if (data.action && data.action == "stats") { } else if (data.action && data.action == "stats") {
wsstats = data.stats; wsstats = data.stats;
} else if (data.action && data.action == "new_response") { } else if (data.action && data.action == "new_response") {
if (!responses[data.question]) responses[data.question] = { }; if (!responses[data.question]) responses[data.question] = {};
responses[data.question][data.user] = data.value; responses[data.question][data.user] = data.value;
reset_graph_data();
} else if (data.action && data.action == "new_ask") { } else if (data.action && data.action == "new_ask") {
asks.push({"id": data.question, "content": data.value, "userid": data.user}); asks.push({"id": data.question, "content": data.value, "userid": data.user});
asks = asks; asks = asks;
@ -267,7 +221,7 @@
disabled disabled
value={timer_remain} value={timer_remain}
> >
<span class="input-group-text">s</span> <span class="input-group-text">ms</span>
</div> </div>
{:else} {:else}
<div class="input-group input-group-sm float-end" style="max-width: 150px;"> <div class="input-group input-group-sm float-end" style="max-width: 150px;">
@ -277,7 +231,7 @@
bind:value={timer} bind:value={timer}
placeholder="Valeur du timer" placeholder="Valeur du timer"
> >
<span class="input-group-text">s</span> <span class="input-group-text">ms</span>
</div> </div>
{/if} {/if}
<button <button
@ -299,20 +253,9 @@
class="btn btn-sm btn-primary" class="btn btn-sm btn-primary"
disabled={!current_question || !ws_up} disabled={!current_question || !ws_up}
on:click={() => { ws.send('{"action":"pause"}')} } on:click={() => { ws.send('{"action":"pause"}')} }
title="Passer sur une scène sans question"
> >
<i class="bi bi-pause-fill"></i> <i class="bi bi-pause-fill"></i>
</button> </button>
<button
type="button"
class="btn btn-sm"
class:btn-outline-success={!corrected}
class:btn-success={corrected}
on:click={() => { corrected = !corrected } }
title="La prochaine question est affichée corrigée"
>
<i class="bi bi-eye"></i>
</button>
</th> </th>
</tr> </tr>
</thead> </thead>
@ -339,11 +282,9 @@
<td> <td>
<button <button
type="button" type="button"
class="btn btn-sm" class="btn btn-sm btn-primary"
class:btn-primary={!corrected}
class:btn-success={corrected}
disabled={question.id === current_question || !ws_up} disabled={question.id === current_question || !ws_up}
on:click={() => { ws.send('{"action":"new_question", "corrected": ' + corrected + ', "timer": 0, "question":' + question.id + '}')} } on:click={() => { ws.send('{"action":"new_question", "timer": 0, "question":' + question.id + '}')} }
> >
<i class="bi bi-play-fill"></i> <i class="bi bi-play-fill"></i>
</button> </button>
@ -351,18 +292,10 @@
type="button" type="button"
class="btn btn-sm btn-danger" class="btn btn-sm btn-danger"
disabled={question.id === current_question || !ws_up} disabled={question.id === current_question || !ws_up}
on:click={() => { ws.send('{"action":"new_question", "corrected": ' + corrected + ', "timer": ' + timer * 1000 + ',"question":' + question.id + '}')} } on:click={() => { ws.send('{"action":"new_question", "timer": ' + timer + ',"question":' + question.id + '}')} }
> >
<i class="bi bi-stopwatch-fill"></i> <i class="bi bi-stopwatch-fill"></i>
</button> </button>
<a
href="/surveys/{survey.id}/responses/{question.id}"
target="_blank"
type="button"
class="btn btn-sm btn-success"
>
<i class="bi bi-files"></i>
</a>
</td> </td>
</tr> </tr>
{/each} {/each}
@ -468,17 +401,6 @@
<span>Chargement des propositions &hellip;</span> <span>Chargement des propositions &hellip;</span>
</div> </div>
{:then proposals} {:then proposals}
{#if current_question == question.id}
<CorrectionPieChart
{question}
{proposals}
data={graph_data}
/>
{:else}
<CorrectionPieChart
{question}
/>
{/if}
<div class="card mb-4"> <div class="card mb-4">
<table class="table table-sm table-striped table-hover mb-0"> <table class="table table-sm table-striped table-hover mb-0">
<tbody> <tbody>
@ -506,17 +428,6 @@
<span>Chargement des propositions &hellip;</span> <span>Chargement des propositions &hellip;</span>
</div> </div>
{:then proposals} {:then proposals}
{#if current_question == question.id}
<CorrectionPieChart
{question}
{proposals}
data={graph_data}
/>
{:else}
<CorrectionPieChart
{question}
/>
{/if}
<div class="card mb-4"> <div class="card mb-4">
<table class="table table-sm table-striped table-hover mb-0"> <table class="table table-sm table-striped table-hover mb-0">
<tbody> <tbody>

View File

@ -89,8 +89,6 @@
console.log(data); console.log(data);
if (data.action && data.action == "new_question") { if (data.action && data.action == "new_question") {
show_question = data.question; show_question = data.question;
survey.corrected = data.corrected;
corrections = data.corrections;
if (timer_cancel) { if (timer_cancel) {
clearInterval(timer_cancel); clearInterval(timer_cancel);
timer_cancel = null; timer_cancel = null;
@ -157,11 +155,9 @@
}); });
}); });
} }
let corrections = {};
</script> </script>
{#await surveyP then unused} {#await surveyP then survey}
{#if $user && $user.is_admin} {#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}/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> <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>
@ -189,10 +185,8 @@
</div> </div>
{:then question} {:then question}
<QuestionForm <QuestionForm
{survey}
{question} {question}
readonly={timer >= 100 || survey.corrected} readonly={timer >= 100}
{corrections}
bind:value={value} bind:value={value}
on:change={sendValue} on:change={sendValue}
> >
@ -206,7 +200,7 @@
<button <button
class="btn btn-primary" class="btn btn-primary"
> >
Soumettre cette réponse Soumettre la réponse
</button> </button>
{/if} {/if}
{/await} {/await}
@ -232,7 +226,7 @@
class="form-control" class="form-control"
bind:value={myQuestion} bind:value={myQuestion}
autofocus autofocus
placeholder="Remarques, soucis, choses pas claires? Levez la main ou écrivez ici!" placeholder="Remarques, soucis, choses pas claires? Demandez!"
></textarea> ></textarea>
<button <button
class="d-sm-none btn btn-primary" class="d-sm-none btn btn-primary"