boussole-pluss/frontend/components/QuizPart.vue

174 lines
3.9 KiB
Vue

<template>
<article :style="cssVars">
<header>
<quiz-progress :number-steps=totalAxes :current-step=axeNumber :color="color"/>
<h1 class="title">
<span class="part-number">{{ axeNumber }}</span>
<span>{{ title }}</span>
</h1>
<div class="icon">
<img :src="icon" width="200px" alt="" aria-hidden="true"/>
</div>
</header>
<section v-for="question in questions" :key="question._links.self.href" class="question">
<details>
<summary> {{ question.label }}</summary>
<p>{{ question.description }}</p>
</details>
<div class="rating">
<rating :color="color" :initial-value="getCurrentScore(question)" @rate="rate => onRate(rate, question)" />
</div>
<input :value="getCurrentComment(question)" type="text" placeholder="Commentaire" maxlength="500" @input="event => onComment(event.target.value, question)"/>
</section>
</article>
</template>
<script lang="ts">
import {Component, Prop, Vue} from "nuxt-property-decorator";
import {Question} from "~/repositories/models/question.model";
import {quizStore} from "~/utils/store-accessor";
import {QuizRate} from "~/repositories/models/quiz.model";
@Component
export default class Quiz extends Vue {
@Prop({
required: true
})
private title!: string;
@Prop({
required: true
})
private axeNumber!: number;
@Prop({
required: true
})
private totalAxes!: number;
@Prop({
required: true,
type: String,
})
public icon !: string;
@Prop({
required: true,
type: Array<Question>
})
private questions!: Array<Question>;
@Prop({
required: true,
type: String,
})
public color !: string;
// private responses = new Map<string, {
// score?: number;
// comment?: string | null
// }>();
get cssVars() {
return {
'--color': this.color
}
}
onRate(score: number, question: Question) {
quizStore.updateScoreResponse({axeId: this.axeNumber, questionId: question._links.self.href, score});
this.emitRatingState();
}
onComment(comment: string, question: Question) {
quizStore.updateCommentResponse({axeId: this.axeNumber, questionId: question._links.self.href, comment});
}
getCurrentScore(question: Question): number | undefined {
const rate = quizStore.responses.get(question._links.self.href) as QuizRate;
return rate ? rate.score : undefined;
}
getCurrentComment(question: Question): string | undefined {
const rate = quizStore.responses.get(question._links.self.href) as QuizRate;
return rate ? rate.comment : undefined;
}
emitRatingState() {
const questions = quizStore.questionsRatedPerAxe.get(this.axeNumber);
const unratedQuestions = questions ? questions.filter(value => !value.rated) : [];
this.$emit('rate', {
isFullRated: unratedQuestions.length === 0
})
}
}
</script>
<style lang="scss" scoped>
@import "assets/css/color";
@import "assets/css/font";
@import "assets/css/spacing";
$size: 31px;
.part-number {
display: inline-flex;
justify-content: center;
align-items: center;
color: var(--color);
border: 3px solid var(--color);
font-size: 1rem;
line-height: $size;
width: $size;
height: $size;
}
.title {
display: flex;
flex-direction: row;
text-align: left;
> span {
padding: 0 $x_small;
}
}
.icon {
text-align: center;
margin: $small;
}
.question {
width: 100%;
}
.question details {
margin-bottom: $x_small;
}
.question details summary {
font-weight: 700;
font-size: $title-font-size;
margin-bottom: $xxx_small;
}
.question details p {
font-size: $secondary-font-size;
color: $gray_4;
margin-left: $x_small;
}
.question .rating {
margin: 0 auto;
max-width: 401px;
}
.question input[type="text"] {
width: 100%;
border: 1px solid $gray_2;
border-radius: 8px;
background: none;
margin: $small 0;
font-weight: 400;
font-size: $tertiary-font-size;
}
</style>