Skip to content
Snippets Groups Projects
challenge.md 9.31 KiB
Newer Older
  • Learn to ignore specific revisions
  • This section explain all the functionnalities in the challenge part
    
    ## Quiz
    
    
    A quiz includes 4 basic questions and one custom question.
    
    Rémi PAPIN's avatar
    Rémi PAPIN committed
    ### Basic Question
    
    
    HAUTBOIS Aurelie's avatar
    HAUTBOIS Aurelie committed
    All basics Questions are created in the quizEntity.json. We have to add :
    
    - questionLabel => Label of the question
    - Answers => An array of three answers (answerLabel, isTrue)
    - description => Explain the question
    - source => Source of the explanaition
    
    Rémi PAPIN's avatar
    Rémi PAPIN committed
    
    
    This questions and answers are in random order.
    
    
    HAUTBOIS Aurelie's avatar
    HAUTBOIS Aurelie committed
    In the question page the user have to select an answer and click validate.
    Then, he sees the right answer and a modal with the explanation and the source. After this modal, he goes to the next question.
    
    Depends on the answer, the question result state is set either correct or incorrect.
    
    If it is a right answer, the quiz result is incremented by one.
    
    Rémi PAPIN's avatar
    Rémi PAPIN committed
    
    ### Custom Question
    
    
    Yoan VALLET's avatar
    Yoan VALLET committed
    At the end of every quiz, we're creating a custom question. 
    Here are the fields used to create a custom question
    
    Yoan VALLET's avatar
    Yoan VALLET committed
    | Field      | Type               | Description                                                      |
    | ---------- | ------------------ | ---------------------------------------------------------------- |
    
    | type       | CustomQuestionType | Type of custom qusetion: DATE or MAXLOAD or AVERAGE.                                              |
    
    Yoan VALLET's avatar
    Yoan VALLET committed
    | timeStep   | TimeStep           | Time step of the result value (DAY / WEEK / MONTH / YEAR). For MAXLOAD or AVERAGE type, it represents daily / weekly  / monthly / yearly average.                          |
    
    Yoan VALLET's avatar
    Yoan VALLET committed
    | interval   | TimeStep           | Interval in which the data will be searched (DAY / WEEK / MONTH / YEAR)                                               |
    
    Yoan VALLET's avatar
    Yoan VALLET committed
    | period     | CustomPeriod       | Case day / month / year:<br/>Use to define a specific period for the interval { day? / month? / year? }. <br/>Case weekday:<br/>Only usable with AVERAGE type and DAY timestep: Allow to specify a weekday on which average is made. If used with another type, period will not be taken into account.<br/>If not assigned the period will be the last interval (example: last week)                                                |
    
    | singleFluid | boolean           | Indicate if all connected fluid should be taken into account.<br/>If set to true only the first connected fluid will be taken into account in this order: electricity, gas, water. #unit and #fluid in the question label will be replace by the unit and the name of the fluid       |
    
    Yoan VALLET's avatar
    Yoan VALLET committed
    | result     | UserQuizState      | Indicate the state of the custom question (UNLOCKED, CORRECT, UNCORRECT)       |
    
    Calculation of custom question is done by conbinaison of all parameters:
    
    
    Yoan VALLET's avatar
    Yoan VALLET committed
    
      - If *period* is empty.
    
    
    Yoan VALLET's avatar
    Yoan VALLET committed
      Retrieve the **date** of day/month/year (define by *timeStep*) from the last week, month, year (define by *interval*).
      ```
      example: What day did I consumme the most on the last week ?
    
    Yoan VALLET's avatar
    Yoan VALLET committed
      type = CustomQuestionType.DATA
      timeStep = TimeStep.DAY
      interval = TimeStep.WEEK
      period = {}
    
      singleFluid = false
      ```
    
      ```
      example: What day did I consumme the most #fluid in #unit on the last week ?
      type = CustomQuestionType.DATA
      timeStep = TimeStep.DAY
      interval = TimeStep.WEEK
      period = {}
      singleFluid = true
    
    Yoan VALLET's avatar
    Yoan VALLET committed
      ```
    
    Yoan VALLET's avatar
    Yoan VALLET committed
    
      - If *period* is not empty
    
    
    Yoan VALLET's avatar
    Yoan VALLET committed
      Retrieve the **date** of day/month/year (define by *timeStep*) from a week, month, year (define by *interval*) of *period*
      ```
      example: What month did I consumme the most on year 2020 ?
    
    Yoan VALLET's avatar
    Yoan VALLET committed
      type = CustomQuestionType.DATA
      timeStep = TimeStep.MONTH
      interval = TimeStep.YEAR
    
    Yoan VALLET's avatar
    Yoan VALLET committed
      period = { year: 2020 }
    
      singleFluid = false
    
    Yoan VALLET's avatar
    Yoan VALLET committed
      ```
    
    Yoan VALLET's avatar
    Yoan VALLET committed
    - Type MAXLOAD
    
      - If *period* is empty
    
      Retrieve the **maxload** value of day/month/year (define by *timeStep*) from the last week, month, year (define by *interval*).
      ```
      example: Which is your daily max consumption on the last week ?
      type = CustomQuestionType.MAXLOAD
      timeStep = TimeStep.DAY
      interval = TimeStep.WEEK
      period = {}
    
      singleFluid = false
    
    Yoan VALLET's avatar
    Yoan VALLET committed
      ```
    
      - If *period* is not empty
      
      Retrieve the **maxload** value of day/month/year (define by *timeStep*) from a week, month, year (define by *interval*) of *period*
      ```
      example: Which is your daily max consumption on january 2020 ?
      type = CustomQuestionType.MAXLOAD
      timeStep = TimeStep.DAY
      interval = TimeStep.MONTH
      period = { month: 1, year: 2020 }
    
      singleFluid = false
    
    Yoan VALLET's avatar
    Yoan VALLET committed
      ```
    
    - Type AVERAGE
    
    Yoan VALLET's avatar
    Yoan VALLET committed
    
      - If *period* is empty
    
      Retrieve the **average** of day/month/year (define by *timeStep*) from the last week, month, year (define by *interval*).
    
    Yoan VALLET's avatar
    Yoan VALLET committed
      ```
      example: Which is your daily average consumption on last week ?
      type = CustomQuestionType.AVERAGE
    
    Yoan VALLET's avatar
    Yoan VALLET committed
      timeStep = TimeStep.DAY
      interval = TimeStep.WEEK
      period = {}
    
      singleFluid = false
    
    Yoan VALLET's avatar
    Yoan VALLET committed
      ```
    
    Yoan VALLET's avatar
    Yoan VALLET committed
    
      - If *period* is not empty
      
    
    Yoan VALLET's avatar
    Yoan VALLET committed
      Retrieve the **average** of day/month/year (define by *timeStep*) from a week, month, year (define by *interval*) of *period*
      ```
      example: Which is your daily average consumption on january 2020 ?
      type = CustomQuestionType.AVERAGE
    
    Yoan VALLET's avatar
    Yoan VALLET committed
      timeStep = TimeStep.DAY
      interval = TimeStep.MONTH
    
    Yoan VALLET's avatar
    Yoan VALLET committed
      period = { month: 1, year: 2020 }
    
      singleFluid = false
    
    Yoan VALLET's avatar
    Yoan VALLET committed
      ```
    
    Yoan VALLET's avatar
    Yoan VALLET committed
      - If *period* is weekday
      
      Retrieve the **average** of the *weekday* from a week, month, year (define by *interval*).
      ```
      example: Which is your daily average consumption on wednesdays of last month?
      type = CustomQuestionType.AVERAGE
      timeStep = TimeStep.DAY
      interval = TimeStep.MONTH
      period = { weekday: 3 }
    
      singleFluid = false
    
    Yoan VALLET's avatar
    Yoan VALLET committed
      ```
    
    Yoan VALLET's avatar
    Yoan VALLET committed
    
    Then, two randoms answers are generated after defining the right answer.
    
    Rémi PAPIN's avatar
    Rémi PAPIN committed
    
    
    A user can stop during a quiz and picks up where he left off. To define where the user left off, we have to check if at least one of the question result status is unlocked.
    
    
    Once the custom question is answered, the quiz state is set to done. Then, the user sees his result and his earned stars. He can also retry or go back to the challenge page.
    
    Rémi PAPIN's avatar
    Rémi PAPIN committed
    ## Exploration
    
    Rémi PAPIN's avatar
    Rémi PAPIN committed
    Exploration is a feature which in the user got to do an action in order to help him to discover all features of this app.
    
    HAUTBOIS Aurelie's avatar
    HAUTBOIS Aurelie committed
    They are 4 types of action :
    
    
    Rémi PAPIN's avatar
    Rémi PAPIN committed
    - DECLARATIVE : The user has to do something outside of the app => No way for the app to know if the user did it so we trust him.
    - ACTION : Action whitin the app. When the user finish he got a notification.
    - CONSUMPTION : He got to do something in his consumption view.
    - ECOGESTURE : He need to have a look to a specific Ecogesture.
    
    
    HAUTBOIS Aurelie's avatar
    HAUTBOIS Aurelie committed
    In order to check if an exploration (which is not declarative) is done, a hook called useExploration is used.It is called on component that has to check if an exploration is done.
    
    This hook called exploration service to check exploration by passing two parameter(the current challenge and the user exploration id associated with the exploration id of the current challenge). This check is done only if:
    
    - There is a current challenge
    - exploration.id of the current challenge is equal to the user exploration id
    - exploration.state is ONGOING
    
    Depends on the type of an exploration, either the exploration remains in progress until it is fully done or it ends.
    
    
    HAUTBOIS Aurelie's avatar
    HAUTBOIS Aurelie committed
    When the user finish the exploration, he got a success message and five more stars on his challenge progression.
    
    
    Guilhem CARRON's avatar
    Guilhem CARRON committed
    ### On launch
    
    HAUTBOIS Aurelie's avatar
    HAUTBOIS Aurelie committed
    In order to find a valid reference period we search for a period which is defined by the duel duration.  
     We check the most recent period first if it's complete and then we go farther and farther in the time if the ones before got missing values.  
     We also define a threshold for a maximum old period (6 months for the moment determined in the code ==> hardcoding).
    If the thresold is reached and no valid period was found, we alert the user that he can't launch the duel and have to wait before he can retry this process.
    
    Guilhem CARRON's avatar
    Guilhem CARRON committed
    ### On going
    
    Guilhem CARRON's avatar
    Guilhem CARRON committed
    Every time the user go into the duel mode, we are checking if the duel is finished.
    
    if we have retrieve all data to calculate the user consumption on the duel duration, the duel is done
    
    !!! info "In order to not block the user is a value is mising, we are also set the duel as done when we reach the startDate + delay in day to retrieve the data (based on the fluid) + 1 day. In this case the user consumption is done on known values."
    
    
    Guilhem CARRON's avatar
    Guilhem CARRON committed
    ### On finish
    
    Guilhem CARRON's avatar
    Guilhem CARRON committed
    Once the state of the duel is set to DONE, we save the user result and determine if he wins (userComsumption < threshold of the reference period) or if he loses. Then the user sees his earned badge.
    
    Guilhem CARRON's avatar
    Guilhem CARRON committed
    ## Challenges
    
    We can find the file challengeEntity.json in the /db folder. This file contains an array of challenges, and each of them includes relationships to duels, quiz, missions and actions.
    
    ### UserData creation
    
    Once a user launch a challenge in the Ecolyo app, we create a userChallenge and store it in the couchDB under the doctype '**com.grandlyon.ecolyo.userchallenge'.** During this process, the objects related to the challenge (quiz, duel, mission, action) will be be converted to an user version which contains informations about the user progress, the fluids connected and so on. So we have now a userChallenge that contains a userQuiz, a userDuel, etc. instead of relations.
    
    To illustrate this, let's show the conversion of quizEntity to userQuiz :
    
    ```jsx
    DuelEntity {
      id: string
      title: string
      description: string
      duration: Duration
    }
    ```
    
    Becomes :
    
    ```jsx
    UserQuiz {
      id: string
      title: string
      description: string
    	duration: Duration
      threshold: number
      state: UserDuelState
      startDate: string | null
      fluidTypes: FluidType[]
      userConsumption: number
    }
    ```
    
    ### Data managment schema
    
    ![Data Scheme](/img/challengeFlow.png)