# card-quiz

A quiz component that allows you to add as many questions and choices. This style is a a deck of cards.

This module is a work in progress.

To do:
  • Timer countdown
  • Card transition animations
  • Icons for each card

# Example

<template>
    <card-quiz
        :quizzes="quizzes"
        :correctImage="correctImage"
        :incorrectImage="incorrectImage"
    />
</template>

<script>
    export default {
        data() {
            return {
                correctImage: '/facts-quiz/checkmark.svg',
                incorrectImage: '/facts-quiz/x.svg',
                quizzes: [
                    {
                        toTheLeft: 'calc(-360px)',
                        isActive: true,
                        isInactive: false,
                        showTrue: false,
                        showFalse: false,
                        slide: false,
                        factTrue:
                            'Waste from cigarette/cigar butts release harmful chemicals into the environment that can damage your health, wildlife, and water supplies.',
                        outcomeTrue: 'Ding, ding ding.',
                        factFalse:
                            'Waste from cigar/cigarette butts release harmful chemicals into the environment that can damage your health, wildlife, and water supplies.',
                        outcomeFalse: 'Oops, that was a tricky one.',
                        question:
                            'Which part of the cigarette does the most harm in releasing chemicals into the environment?',
                        checks: [
                            {
                                response: 'THE TOBACCO INSIDE',
                                outcome: false,
                            },
                            {
                                response: 'THE PAPER WRAPPING',
                                outcome: false,
                            },
                            {
                                response: 'THE CIGARETTE BUTT',
                                outcome: true,
                            },
                        ],
                    },
                    {
                        toTheLeft: 'calc(-30px)',
                        isActive: false,
                        isInactive: true,
                        showTrue: false,
                        showFalse: false,
                        slide: false,
                        factTrue:
                            'Cigar/cigarette butts and packaging contribute to the millions of tons of litter and trash heaps across the U.S.',
                        outcomeTrue: 'You nailed it.',
                        factFalse:
                            'Cigar/cigarette butts and packaging contribute to the millions of tons of litter and trash heaps across the U.S',
                        outcomeFalse:
                            'All can be a problem, but cigarettes rise to the top.',
                        question:
                            'Which item creates the most litter and trash collected in the U.S. each year?',
                        checks: [
                            {
                                response: 'PLASTIC STRAWS',
                                outcome: false,
                            },
                            {
                                response: 'PLASTIC BAGS',
                                outcome: false,
                            },
                            {
                                response: 'CIGARETTES',
                                outcome: true,
                            },
                        ],
                    },
                    {
                        toTheLeft: '-30px',
                        isActive: false,
                        isInactive: true,
                        showTrue: false,
                        showFalse: false,
                        slide: false,
                        factTrue:
                            'Cigarette butts are the most commonly littered item on U.S. roads and beaches.',
                        outcomeTrue: 'You guessed it.',
                        factFalse:
                            'Cigarette butts are the most commonly littered item on U.S. roads and beaches',
                        outcomeFalse:
                            'All that litter must have tripped you up.',
                        question:
                            'What is the most littered item on U.S. roads and beaches?',
                        checks: [
                            {
                                response: 'PLASTIC CUPS',
                                outcome: false,
                            },
                            {
                                response: 'SUNSCREEN BOTTLES',
                                outcome: false,
                            },
                            {
                                response: 'CIGARETTE BUTTS',
                                outcome: true,
                            },
                        ],
                    },
                ],
            };
        },
    };
</script>

# Demo

01

Which part of the cigarette does the most harm in releasing chemicals into the environment?

02

Which item creates the most litter and trash collected in the U.S. each year?

03

What is the most littered item on U.S. roads and beaches?

question 1 of 3

# Usage

First import the component inside your script tags:

import { CardQuiz } from '@rescue/vue-modules';

Then, register the component:

export default {
    components: {
        CardQuiz,
    },
};

# props

  • correctImage (Optional) (String) The image that shows when the card is correctly asnwered.

  • incorrectImage (Optional) (String) The image that shows when the card is incorrectly asnwered.

  • quizzes (Required) (Array) Array of objects that make up the cards.

    • toTheLeft (Required) (String) The width used to move the card to the left once answered. Normally this is the same as with width of the individual card.

    • isActive (Required) (Boolean) If the card is active.

    • isInactive (Required) (Boolean) If the card is inactive.

    • showTrue (Required) (Boolean) Reveal the response if answered correctly.

    • showFalse (Required) (Boolean) Reveal the response if answered incorrectly.

    • slide (Required) (Boolean) Triggers sliding style effect.

    • factTrue (Required) (String) Copy response to the correct answer.

    • factFalse (Required) (String) Copy response to the incorrect answer.

    • question (Required) (String) individual card question.

  • checks (Required) (Array) nested array for the asnwers and which ones are the correct or incorrect answers.

    • response (Required) (String) Copy for the asnwer.

    • outcome (Required) (String) Whether the answer is true of false.

# Source Code

<template>
  <div class="quiz-main-wrapper">
    <div class="quiz-wrapper">
      <div
        v-bind:style="
                    slide
                        ? {
                              transition: '0.3s ease-in-out',
                              transform: 'translateX(' + quiz.toTheLeft + ')',
                              transitionDelay: '5s',
                              backgroundColor: 'white',
                          }
                        : null
                "
        v-bind:class="{
                    active: quiz.isActive,
                    inactive: quiz.isInactive,
                }"
        class="quiz-item"
        :id="'quiz-card-' + (parentIndex + 1)"
        v-for="(quiz, parentIndex) in quizzes"
        :key="parentIndex"
      >
        <!-- <div class="white-overlay" v-show="quiz.isInactive"></div> -->
        <div>
          <div class="question-container">
            <p class="quiz-number">0{{ parentIndex + 1 }}</p>
            <p class="quiz-q-p">{{ quiz.question }}</p>
          </div>

          <div class="button-container">
            <button
              class="quiz-button"
              v-for="(answer, index) in quiz.checks"
              :key="index"
              v-on:click="
                                answer.outcome
                                    ? onClickTrue(parentIndex)
                                    : onClickFalse(parentIndex)
                            "
            >{{ answer.response }}</button>
          </div>

          <div class="correct response" v-show="quiz.showTrue">
            <div class="asnwer-top">
              <img class="answer-img correct-img" :src="correctImage" alt="correct checkmark" />
              <p>{{ quiz.outcomeTrue }}</p>
            </div>
            <div class="outcome-answer">
              <p class="strong-fact">Fact</p>
              <p v-html="quiz.factTrue">{{ quiz.factTrue }}</p>
            </div>
            <!-- <button class="reset-btn" v-if="quiz.replay" :click="resetQuiz()">replay?</button> -->
          </div>
          <div class="incorrect response" v-show="quiz.showFalse">
            <img class="answer-img incorrect-img" :src="incorrectImage" alt="incorrect x" />
            <p>{{ quiz.outcomeFalse }}</p>
            <div class="outcome-answer">
              <p class="strong-fact">Fact</p>
              <p v-html="quiz.factFalse">{{ quiz.factFalse }}</p>
            </div>
            <!-- <button class="quiz-button" v-if="quiz.replay">replay?</button> -->
          </div>
        </div>
      </div>
    </div>
    <div class="amount-popup" v-if="incrementOn">
      <p>
        question
        <span class="light-timer">{{ activeAmount }} of {{ quizzes.length }}</span>
      </p>
    </div>

    <div class="countdown" v-if="countdown">
      <span>NEXT QUESTION IN</span> 4 SECONDS
    </div>
  </div>
</template>
<style lang="scss" scoped>
.quiz-main-wrapper {
  position: relative;
  max-width: 403px;
  min-height: 530px;
  display: flex;
  overflow: hidden;
  width: 100%;
  align-items: flex-start;

  @media screen and (max-width: 767px) {
    max-width: 345px;
    margin: 0 auto;
    margin-bottom: 40px !important;
    min-height: 529px;
  }

  .amount-popup {
    position: relative;
    margin: 0 auto;
    color: white;
    top: auto;
    z-index: 5;
    display: flex;
    align-items: flex-end;
    text-transform: uppercase;
    place-self: flex-end;
    font-weight: 600;
    margin-left: 140px;
    width: 100%;

    @media screen and (max-width: 767px) {
      margin-left: 120px;
    }

    .light-timer {
      font-weight: 100;
    }
  }

  .countdown {
    position: absolute;
    margin: 0 auto;
    color: white;
    top: auto;
    z-index: 5;
    display: flex;
    align-items: flex-end;
    text-transform: uppercase;
    place-self: flex-end;
    font-weight: 600;
    margin-left: 80px;
    width: 100%;
    margin-top: -18px;
    -webkit-animation-duration: 10s;
    animation-duration: 10s;
    -webkit-animation-fill-mode: both;
    animation-fill-mode: both;

    @media screen and (max-width: 767px) {
      margin-left: 70px;
    }

    span {
      font-weight: 100;
      margin-right: 6px;
    }
  }

  @-webkit-keyframes fadeIn {
    0% {
      opacity: 0;
    }
    100% {
      opacity: 1;
    }
  }

  @keyframes fadeIn {
    0% {
      opacity: 0;
    }
    100% {
      opacity: 1;
    }
  }

  .fadeIn {
    -webkit-animation-name: fadeIn;
    animation-name: fadeIn;
  }

  .elementToFadeInAndOut {
    width: 200px;
    height: 200px;
    background: red;
    -webkit-animation: fadeinout 5s linear forwards;
    animation: fadeinout 5s linear forwards;
  }

  @-webkit-keyframes fadeinout {
    0%,
    100% {
      opacity: 0;
    }
    50% {
      opacity: 1;
    }
  }

  @keyframes fadeinout {
    0%,
    100% {
      opacity: 0;
    }
    50% {
      opacity: 1;
    }
  }
  .slide {
    transition: 0.3s ease-in-out;
    -webkit-transition: 0.3s ease-in-out;
    transform: translateX(-360px);
    -webkit-transform: translateX(-360px);
    transition-delay: 5s;
  }

  .quiz-wrapper {
    display: flex;
    flex-direction: row;
    position: absolute;
    width: 1100px;

    .active {
      z-index: 4;
    }

    .inactive {
      z-index: 3;
      left: -30px;
      left: 10px;
      top: 10px;
    }

    #quiz-card-1 {
      z-index: 4;
    }
    #quiz-card-2 {
      z-index: 3;
      left: -350px;
      background: rgb(224, 224, 224);
    }
    #quiz-card-3 {
      top: 20px;
      z-index: 2;
      left: -702px;
      background: rgb(186, 186, 186);
    }

    .quiz-item {
      display: flex;
      flex-direction: column;
      justify-content: center;
      align-items: center;
      width: 100%;
      text-align: center;
      max-width: 350px;
      width: 100%;
      background: white;
      margin: 0 10px;
      position: relative;
      // position: absolute;
      padding: 37px 10px;
      -webkit-box-shadow: 10px 6px 13px -11px rgba(0, 0, 0, 0.46);
      -moz-box-shadow: 10px 6px 13px -11px rgba(0, 0, 0, 0.46);
      box-shadow: 10px 6px 13px -11px rgba(0, 0, 0, 0.46);

      @media screen and (max-width: 767px) {
        max-width: 319px;
      }

      .white-overlay {
        background: rgb(197, 197, 197);
        position: absolute;
        z-index: 1;
        top: 0;
        bottom: 0;
        right: 0;
        left: 0;
      }

      .response {
        position: absolute;
        top: 0;
        bottom: 0;
        right: 0;
        left: 0;
        display: flex;
        flex-direction: column;
        justify-content: space-between;
        align-items: center;
        z-index: 5;
        background: white;
        color: black;
        padding-top: 90px;

        .incorrect-img {
          max-width: 110px;
          width: 100%;
        }

        p {
          color: black;
        }

        .outcome-answer {
          background: #ffb71b;
          max-width: 100%;
          width: 90%;
          height: 170px;
          display: flex;
          flex-direction: column;
          justify-content: center;
          align-items: center;
          padding: 5%;

          p {
            color: black;
            margin: 0px;
          }

          p.strong-fact {
            font-weight: bold;
            text-transform: uppercase;
            font-size: 14px;
            margin: 0px;
          }
        }
        .asnwer-top {
          display: flex;
          flex-direction: column;
          width: 100%;
          align-items: center;
          justify-content: center;
          .answer-img {
            max-width: 120px;
            width: 100%;
            // margin-bottom: 23px;
          }

          .incorrect-img {
            max-width: 110px;
            width: 100%;
          }
          .correct-img {
            max-width: 110px;
            width: 100%;
          }
        }
      }

      .question-container {
        display: flex;
        flex-direction: row;
        max-width: 300px;
        width: 100%;
        justify-content: center;
        align-items: flex-start;

        .quiz-number {
          font-weight: bold;
        }

        .quiz-q-p {
          margin-bottom: 37px;
        }
      }

      .button-container {
        display: flex;
        flex-direction: column;
        width: 100%;
        justify-content: center;
        align-items: center;

        .quiz-button {
          max-width: 243px;
          width: 100%;
          background: #1a1a1a;
          color: white;
          padding: 26px 10px;
          border: none;
          margin-bottom: 18px;
          cursor: pointer;
        }
      }
    }
  }
}
</style>
<script>
export default {
  props: {
    quizzes: {
      type: Array,
      required: true
    },
    correctImage: {
      type: String,
      required: true
    },
    incorrectImage: {
      type: String,
      required: true
    }
  },
  data() {
    return {
      activeAmount: 1,
      toTheLeft: "",
      slide: false,
      countdown: false,
      incrementOn: true
    };
  },
  methods: {
    incrementCounter() {
      this.activeAmount++;
      if (this.activeAmount > this.quizzes.length) {
        this.activeAmount = this.quizzes.length;
      }
    },
    //clicking on buttons quizzes index determines if the answer is set to true or false
    onClickTrue(parentIndex) {
      let _this = this;
      _this.moveCard(parentIndex);
    },

    onClickFalse(parentIndex) {
      let _this = this;
      if (this.quizzes[parentIndex === this.quizzes.length]) {
        this.quizzes[parentIndex === this.quizzes.length].showFalse = true;
        this.quizzes[parentIndex === this.quizzes.length].isActive = false;
        this.quizzes[parentIndex === this.quizzes.length].isInactive = true;
        this.slide = true;
        return;
      } else {
        this.quizzes[parentIndex].showFalse = true;
        this.quizzes[parentIndex].isActive = false;
        _this.countdown = true;
        _this.incrementOn = false;
        if (this.quizzes[parentIndex === 2]) {
          _this.countdown = false;
          _this.incrementOn = true;
        } else {
          setTimeout(function() {
            _this.countdown = false;
            _this.incrementCounter();
            _this.incrementOn = true;
          }, 5000);
        }
        this.slide = true;
        this.toTheLeft = this.quizzes[parentIndex].toTheLeft;
        this.quizzes[parentIndex].toTheLeft = "-400px";
        if (this.quizzes[2].toTheLeft) {
          this.quizzes[2].toTheLeft = "-30px";
        }
      }
    },
    moveCard(parentIndex) {
      let _this = this;
      if (this.quizzes[parentIndex === this.quizzes.length]) {
        this.quizzes[parentIndex === this.quizzes.length].showTrue = true;
        this.quizzes[parentIndex === this.quizzes.length].isActive = false;
        this.quizzes[parentIndex === this.quizzes.length].isInactive = true;
        this.slide = true;
        return;
      } else {
        this.quizzes[parentIndex].showTrue = true;
        this.quizzes[parentIndex].isActive = false;
        _this.countdown = true;
        _this.incrementOn = false;

        if (this.quizzes[parentIndex === 2]) {
          _this.countdown = false;
          _this.incrementOn = true;
        } else {
          setTimeout(function() {
            _this.countdown = false;
            _this.incrementCounter();
            _this.incrementOn = true;
          }, 5000);
        }

        this.slide = true;
        this.toTheLeft = this.quizzes[parentIndex].toTheLeft;
        this.quizzes[parentIndex].toTheLeft = "-400px";
        if (this.quizzes[2].toTheLeft) {
          this.quizzes[2].toTheLeft = "-30px";
        }
      }
    }
  }
};
</script>