feat: Séparation du code spécifique aux questions
This commit is contained in:
		
							
								
								
									
										99
									
								
								src/components/Question.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										99
									
								
								src/components/Question.vue
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,99 @@
 | 
			
		||||
<script setup>
 | 
			
		||||
import { ref } from "vue";
 | 
			
		||||
import { Splide, SplideSlide } from "@splidejs/vue-splide";
 | 
			
		||||
import "@splidejs/splide/dist/css/splide.min.css";
 | 
			
		||||
 | 
			
		||||
const props = defineProps({
 | 
			
		||||
  question: {
 | 
			
		||||
    type: Object,
 | 
			
		||||
    required: true,
 | 
			
		||||
  },
 | 
			
		||||
});
 | 
			
		||||
defineEmits(["answerSelected"]);
 | 
			
		||||
 | 
			
		||||
const slides = ref();
 | 
			
		||||
const answerWeight = ref(props.question.answers[0].weight);
 | 
			
		||||
 | 
			
		||||
function selectAnswer(answer) {
 | 
			
		||||
  const answerIndex = props.question.answers.findIndex(
 | 
			
		||||
    (a) => a.id === answer.id
 | 
			
		||||
  );
 | 
			
		||||
  slides.value.splide.go(answerIndex);
 | 
			
		||||
}
 | 
			
		||||
function slideMove(splide, newIndex) {
 | 
			
		||||
  answerWeight.value = props.question.answers[newIndex].weight;
 | 
			
		||||
}
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
<template>
 | 
			
		||||
  <div class="main">
 | 
			
		||||
    <div class="top">
 | 
			
		||||
      <legend>{{ question.title }}</legend>
 | 
			
		||||
      <template v-if="question.answers">
 | 
			
		||||
        <div class="choice" v-for="answer in question.answers" :key="answer.id">
 | 
			
		||||
          <label>
 | 
			
		||||
            <input
 | 
			
		||||
              type="radio"
 | 
			
		||||
              :data-answerId="answer.id"
 | 
			
		||||
              :name="`question_${question.id}`"
 | 
			
		||||
              :value="answer.weight"
 | 
			
		||||
              v-model="answerWeight"
 | 
			
		||||
              @click="selectAnswer(answer)"
 | 
			
		||||
            />
 | 
			
		||||
            {{ answer.title }}
 | 
			
		||||
          </label>
 | 
			
		||||
        </div>
 | 
			
		||||
      </template>
 | 
			
		||||
    </div>
 | 
			
		||||
    <div class="bottom">
 | 
			
		||||
      <template v-if="question.answers">
 | 
			
		||||
        <Splide
 | 
			
		||||
          @splide:move="slideMove"
 | 
			
		||||
          class="answers"
 | 
			
		||||
          :id="`question_${question.id}`"
 | 
			
		||||
          ref="slides"
 | 
			
		||||
        >
 | 
			
		||||
          <SplideSlide
 | 
			
		||||
            v-for="answer in question.answers"
 | 
			
		||||
            :key="answer.id"
 | 
			
		||||
            @click="$emit('answerSelected', question, answerWeight)"
 | 
			
		||||
          >
 | 
			
		||||
            <img
 | 
			
		||||
              width="200"
 | 
			
		||||
              height="200"
 | 
			
		||||
              :src="`/answers/${answer.image}.png`"
 | 
			
		||||
            />
 | 
			
		||||
          </SplideSlide>
 | 
			
		||||
        </Splide>
 | 
			
		||||
      </template>
 | 
			
		||||
    </div>
 | 
			
		||||
  </div>
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<style lang="sass" scoped>
 | 
			
		||||
input[type=radio]
 | 
			
		||||
  margin-right: .5rem
 | 
			
		||||
 | 
			
		||||
.main
 | 
			
		||||
  height: 100%
 | 
			
		||||
  max-width: 100%
 | 
			
		||||
  display: flex
 | 
			
		||||
  flex-direction: column
 | 
			
		||||
  justify-content: space-around
 | 
			
		||||
  align-items: center
 | 
			
		||||
 | 
			
		||||
  .bottom
 | 
			
		||||
    width: 400px
 | 
			
		||||
    max-width: 100%
 | 
			
		||||
    min-width: 280px
 | 
			
		||||
 | 
			
		||||
.answers
 | 
			
		||||
  text-align: center
 | 
			
		||||
 | 
			
		||||
@media only screen and (orientation : landscape)
 | 
			
		||||
  .main
 | 
			
		||||
    flex-direction: row
 | 
			
		||||
 | 
			
		||||
    .bottom
 | 
			
		||||
      max-width: 50%
 | 
			
		||||
</style>
 | 
			
		||||
@@ -6,6 +6,7 @@ import { ref, computed } from "vue";
 | 
			
		||||
import { useStore } from "@/stores";
 | 
			
		||||
 | 
			
		||||
import { Splide, SplideSlide } from "@splidejs/vue-splide";
 | 
			
		||||
import Question from "./Question.vue";
 | 
			
		||||
import "@splidejs/splide/dist/css/splide.min.css";
 | 
			
		||||
import ScoreHeader from "./ScoreHeader.vue";
 | 
			
		||||
 | 
			
		||||
@@ -60,9 +61,6 @@ function formatScore(score) {
 | 
			
		||||
const title = score ? score.title : "";
 | 
			
		||||
const questions = ref(formatScore(score));
 | 
			
		||||
 | 
			
		||||
function nextQuestion() {
 | 
			
		||||
  setTimeout(() => slides.value.go(">"), 100);
 | 
			
		||||
}
 | 
			
		||||
const scoreSum = computed(() => {
 | 
			
		||||
  return questions.value
 | 
			
		||||
    .map((question) => question.weight)
 | 
			
		||||
@@ -97,21 +95,16 @@ const result = computed(() =>
 | 
			
		||||
        .filter((r) => !r.max || r.max >= scoreSum.value)[0]
 | 
			
		||||
    : null
 | 
			
		||||
);
 | 
			
		||||
function selectImage(event, question, answer) {
 | 
			
		||||
  const input = document.querySelector(
 | 
			
		||||
    `input[name='question_${question.id}'][value='${answer.weight}']`
 | 
			
		||||
  );
 | 
			
		||||
  if (input) {
 | 
			
		||||
    input.checked = true;
 | 
			
		||||
    input.dispatchEvent(new Event("change"));
 | 
			
		||||
  }
 | 
			
		||||
  nextQuestion();
 | 
			
		||||
}
 | 
			
		||||
function geQuestionSlide(question) {
 | 
			
		||||
function goQuestionSlide(question) {
 | 
			
		||||
  console.log(slides.value);
 | 
			
		||||
  slides.value.go(
 | 
			
		||||
    questions.value.findIndex((element) => element.id === question.id)
 | 
			
		||||
  );
 | 
			
		||||
}
 | 
			
		||||
function answerSelected(question, answerWeight) {
 | 
			
		||||
  questions.value.find((q) => q.id === question.id).weight = answerWeight;
 | 
			
		||||
  setTimeout(() => slides.value.go(">"), 100);
 | 
			
		||||
}
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
<template>
 | 
			
		||||
@@ -131,57 +124,7 @@ function geQuestionSlide(question) {
 | 
			
		||||
    }"
 | 
			
		||||
  >
 | 
			
		||||
    <SplideSlide v-for="question in questions" :key="question.id">
 | 
			
		||||
      <div class="main">
 | 
			
		||||
        <div class="top">
 | 
			
		||||
          <legend>{{ question.title }}</legend>
 | 
			
		||||
          <template v-if="question.answers">
 | 
			
		||||
            <div
 | 
			
		||||
              class="choice"
 | 
			
		||||
              v-for="answer in question.answers"
 | 
			
		||||
              :key="answer.id"
 | 
			
		||||
            >
 | 
			
		||||
              <label>
 | 
			
		||||
                <input
 | 
			
		||||
                  type="radio"
 | 
			
		||||
                  :data-answerId="answer.id"
 | 
			
		||||
                  :name="`question_${question.id}`"
 | 
			
		||||
                  :value="answer.weight"
 | 
			
		||||
                  @change="
 | 
			
		||||
                    (event) => {
 | 
			
		||||
                      question.weight = parseFloat(event.target.value);
 | 
			
		||||
                    }
 | 
			
		||||
                  "
 | 
			
		||||
                  @click="nextQuestion"
 | 
			
		||||
                />
 | 
			
		||||
                {{ answer.title }}
 | 
			
		||||
              </label>
 | 
			
		||||
            </div>
 | 
			
		||||
          </template>
 | 
			
		||||
        </div>
 | 
			
		||||
        <div class="bottom">
 | 
			
		||||
          <template v-if="question.answers">
 | 
			
		||||
            <Splide
 | 
			
		||||
              class="answers"
 | 
			
		||||
              :id="`question_${question.id}`"
 | 
			
		||||
              ref="question.splide"
 | 
			
		||||
            >
 | 
			
		||||
              <SplideSlide
 | 
			
		||||
                v-for="answer in question.answers"
 | 
			
		||||
                :key="answer.id"
 | 
			
		||||
                @click="
 | 
			
		||||
                  (event) => selectImage(event, { ...question }, { ...answer })
 | 
			
		||||
                "
 | 
			
		||||
              >
 | 
			
		||||
                <img
 | 
			
		||||
                  width="200"
 | 
			
		||||
                  height="200"
 | 
			
		||||
                  :src="`/answers/${answer.image}.png`"
 | 
			
		||||
                />
 | 
			
		||||
              </SplideSlide>
 | 
			
		||||
            </Splide>
 | 
			
		||||
          </template>
 | 
			
		||||
        </div>
 | 
			
		||||
      </div>
 | 
			
		||||
      <Question :question="question" @answerSelected="answerSelected" />
 | 
			
		||||
    </SplideSlide>
 | 
			
		||||
    <SplideSlide class="latest">
 | 
			
		||||
      <template v-if="displayScoreResult && result">
 | 
			
		||||
@@ -216,7 +159,7 @@ function geQuestionSlide(question) {
 | 
			
		||||
              <a
 | 
			
		||||
                @click="
 | 
			
		||||
                  (event) => {
 | 
			
		||||
                    geQuestionSlide(question);
 | 
			
		||||
                    goQuestionSlide(question);
 | 
			
		||||
                    return false;
 | 
			
		||||
                  }
 | 
			
		||||
                "
 | 
			
		||||
@@ -254,9 +197,6 @@ function geQuestionSlide(question) {
 | 
			
		||||
  bottom: 0
 | 
			
		||||
  background: transparent
 | 
			
		||||
 | 
			
		||||
  input[type=radio]
 | 
			
		||||
    margin-right: .5rem
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
.splide__slide
 | 
			
		||||
  background: transparent
 | 
			
		||||
@@ -313,29 +253,6 @@ label
 | 
			
		||||
      top: 0
 | 
			
		||||
      line-height: .7rem
 | 
			
		||||
 | 
			
		||||
.main
 | 
			
		||||
  height: 100%
 | 
			
		||||
  max-width: 100%
 | 
			
		||||
  display: flex
 | 
			
		||||
  flex-direction: column
 | 
			
		||||
  justify-content: space-around
 | 
			
		||||
  align-items: center
 | 
			
		||||
 | 
			
		||||
  .bottom
 | 
			
		||||
    width: 400px
 | 
			
		||||
    max-width: 100%
 | 
			
		||||
    min-width: 280px
 | 
			
		||||
 | 
			
		||||
.answers
 | 
			
		||||
  text-align: center
 | 
			
		||||
 | 
			
		||||
.splide__arrows
 | 
			
		||||
  position: inherit
 | 
			
		||||
 | 
			
		||||
@media only screen and (orientation : landscape)
 | 
			
		||||
  .main
 | 
			
		||||
    flex-direction: row
 | 
			
		||||
 | 
			
		||||
    .bottom
 | 
			
		||||
      max-width: 50%
 | 
			
		||||
</style>
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user