Files
boussole-pluss/frontend/pages/bundle/create.vue
Nicolas Doby 3ed425fc57 feat: review backend and frontend
- update to the latest version of Java/SpringBoot
- update to the latest version NuxtJS
- add account/password update
- add account creation
- add account password reset
- add bundle to regroup questions and add default questions on user creation
- add bundle creation
2024-07-16 10:50:46 +02:00

191 lines
5.5 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<script lang="ts" setup>
import {type QuestionCreation, useBundleStore} from "~/store/bundle";
import {useNotificationStore} from "~/store/notification";
import type {ApiError} from "~/composables/fetch-api";
import {type Axe, useAxeStore} from "~/store/axe";
import {type Question, useQuestionStore} from "~/store/question";
const axes = ref<Axe[]>();
const label = ref();
const questions = ref<Map<number, QuestionCreation[]>>(new Map());
const questionsExample = ref<Map<number, QuestionCreation[]>>(new Map());
const modalVisible = ref(false);
const currentAxe = ref<Axe>();
const currentQuestions = ref<Question[]>();
onMounted(() => {
useAxeStore().findAxes().then(response => {
response.forEach(axe => {
useQuestionStore().findDefaults(axe.id).then(response => {
questions.value.set(axe.id, response);
});
useQuestionStore().findAll(axe.id).then(response => {
questionsExample.value.set(axe.id, response);
});
});
axes.value = response;
});
});
function createBundle() {
const newQuestions = [];
let errors = [];
questions.value.forEach((value, axeId) => {
if (value.length === 0) {
const axeNumber = axes.value.filter(a => a.id === axeId)[0].identifier;
errors.push(`L'axe ${axeNumber} n'a pas de question.`);
}
value.forEach((q: Question, index)=> {
newQuestions.push({
axeId: axeId,
label: q.label,
description: q.description,
index: index+1
});
if (!q.label.trim()) {
const axeNumber = axes.value.filter(a => a.id === axeId)[0].identifier;
errors.push(`L'une des question de l'axe ${axeNumber} contient un libellé non rempli.`);
}
});
});
if (errors.length > 0) {
useNotificationStore().pushNotification("warn",
{message: `La boussole contient des erreurs !`, details: errors});
}else {
useBundleStore()
.create({
label: label.value,
questions: newQuestions
})
.then(() => {
useNotificationStore().pushNotification("success",{message: "La boussole a bien été créée."});
navigateTo("/bundle");
})
.catch((apiError: ApiError) => {
let details;
if (apiError.fieldErrors) {
details = apiError.fieldErrors.map(error => `${error.fields!.join(", ")} ${error.detail}`);
}
useNotificationStore().pushNotification("warn",{message: apiError.message, details});
});
}
}
// const questionsInput = computed<boolean>(() => {
// let emptyAxe = 0;
// for (const [key, value] of questions.value.entries()) {
// if (value.length === 0) {
// emptyAxe += 1;
// }
// console.log(`${key}: ${value.length}`);
// }
// return emptyAxe === questions.value.keys().length;
// });
function css(axe: Axe) {
return {
'--color': axe.color
}
}
function showAxeModal(axe: Axe) {
currentAxe.value = axe;
modalVisible.value = true;
currentQuestions.value = questions.value.get(axe.id);
document.body.style.overflowY = "hidden";
}
function hideAxeModal() {
currentAxe.value = undefined;
currentQuestions.value = undefined;
modalVisible.value = false;
document.body.style.overflowY = "auto";
}
function onQuestionsChange({axeId, newQuestions}) {
questions.value.set(axeId, newQuestions);
}
function numberOfQuestions(axe: Axe) {
const q = questions.value.get(axe.id)
return q ? q.length: 0;
}
</script>
<template>
<h1>Créer une nouvelle boussole</h1>
<section>
<form class="form" @submit.prevent="createBundle">
<label for="label">Nom de la boussole *</label>
<input id="label" v-model="label" type="text" required maxlength="50">
<ul class="axe-list">
<li class="axe-list__item" v-for="axe in axes" :style="css(axe)">
<h2>{{ axe.identifier }} - {{ axe.shortTitle }}</h2>
<div class="axe-list__item__content">
<div class="axe-list__item__content-text">
<p>{{ axe.title }}</p>
<p>{{ numberOfQuestions(axe) }} question{{numberOfQuestions(axe) > 1? 's': ''}} configurée{{numberOfQuestions(axe) > 1? 's': ''}}</p>
</div>
<button class="button blue" type="button" @click="showAxeModal(axe)">
Configurer
</button>
</div>
</li>
</ul>
<div class="button-container">
<nuxt-link class="button gray button-back" to="/bundle" aria-label="Précédent"></nuxt-link>
<button class="button orange">Valider</button>
</div>
</form>
</section>
<bundle-axe-modal v-if="currentAxe" :visible="modalVisible"
:axe="currentAxe"
:questions="questions.get(currentAxe.id)"
:questions-example="questionsExample.get(currentAxe.id)"
@close="hideAxeModal()"
@changed="(axeId, newQuestions) => onQuestionsChange(axeId, newQuestions)"/>
</template>
<style lang="scss" scoped>
@import "assets/css/color";
@import "assets/css/spacing";
@import "assets/css/font";
.axe-list {
display: flex;
flex-direction: column;
list-style: none;
gap: $xxx_small;
margin: 0;
&__item {
padding: $xx_small 0;
border-bottom: 2px solid var(--color);
h2 {
font-size: $secondary-font-size;
margin: 0;
}
&__content {
display: flex;
align-items: center;
justify-content: space-between;
gap: $xx_small;
&-text p + p {
margin: $xxx_small 0;
}
&-text p:last-child {
font-style: italic;
}
}
}
}
</style>