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
This commit is contained in:
190
frontend/pages/bundle/create.vue
Normal file
190
frontend/pages/bundle/create.vue
Normal file
@@ -0,0 +1,190 @@
|
||||
<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>
|
Reference in New Issue
Block a user