-
Bastien DUMONT authoredBastien DUMONT authored
Challenge
This section explain all the functionalities in the challenge part
Quiz
A quiz includes 4 basic questions and one custom question.
Process
Questions and answers are generated in random order.
At the beginning of the quiz, the user have to select an answer and click validate.
Then, he sees the right answer and a modal with the explanation. After this modal, he goes to the next question.
Depending on the answer, the question result state is set either to correct or incorrect. If it is a right answer, the quiz result is incremented by one.
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.
Basic Question
All basics Questions are created in the quizEntity.json. We have to add :
Field | Description |
---|---|
questionLabel | Label of the question |
answers | Array of 3 answers (answerLabel, isTrue) |
description | Explains the question |
source | Source of the explanation |
Custom Question
At the end of every quiz, we're creating a custom question. Here are the fields used to create a custom question
Field | Type | Description |
---|---|---|
type | CustomQuestionType | Type of custom question: DATE or MAXLOAD or AVERAGE. |
timeStep | TimeStep | Time step of the result value (DAY / WEEK / MONTH / YEAR). For MAXLOAD or AVERAGE type, it represents daily / weekly / monthly / yearly average. |
interval | TimeStep | Interval in which the data will be searched (DAY / WEEK / MONTH / YEAR) |
period | CustomPeriod | Case day / month / year: Use to define a specific period for the interval { day? / month? / year? } . Case weekday: 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. 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. 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 |
result | UserQuizState | Indicate the state of the custom question (UNLOCKED, CORRECT, INCORRECT) |
Calculation of custom question is done by combination of all parameters:
Type DATE
-
If period is empty.
Retrieve the date of day/month/year (define by timeStep) from the last week, month, year (define by interval), if there is no data in this interval, then it will go back to a previous interval, up to a maximum of 6 months
// example: What day did I consumme the most on the last week ?
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;
-
If period is not empty
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 ?
type = CustomQuestionType.DATA;
timeStep = TimeStep.MONTH;
interval = TimeStep.YEAR;
period = { year: 2020 };
singleFluid = false;
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;
- 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;
Type AVERAGE
- If period is empty
Retrieve the average of day/month/year (define by timeStep) from the last week, month, year (define by interval).
// example: Which is your daily average consumption on last week ?
type = CustomQuestionType.AVERAGE;
timeStep = TimeStep.DAY;
interval = TimeStep.WEEK;
period = {};
singleFluid = false;
- If period is not empty
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;
timeStep = TimeStep.DAY;
interval = TimeStep.MONTH;
period = { month: 1, year: 2020 };
singleFluid = false;
- 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 Wednesday of last month?
type = CustomQuestionType.AVERAGE;
timeStep = TimeStep.DAY;
interval = TimeStep.MONTH;
period = { weekday: 3 };
singleFluid = false;
Wrong answers
After defining the right answer, two random answers are generated depending of the custom question type:
- type DATE
Two dates is generated one, a day before the correct date and the other, a day after.
- type MAXLOAD or AVERAGE
Two random value is generated by applying a coefficient based on the correct answer. This coefficient is randomly included between 0.7 and 0.9 (for the first value) or between 1.1 and 1.3 (for the second value)
Exploration
Exploration is a feature where the user has to do an action in order to help him discover all features from ecolyo. They are 4 types of actions:
- 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 within the app. When the user finishes he gets a notification.
- CONSUMPTION : He has to do something in his consumption view.
- ECOGESTURE : He needs to look at a specific Ecogesture.
In order to check if an exploration (which is not declarative) is done, a hook called userExploration 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 parameters (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.
When the user finish the exploration, he gets a success message and five more stars are added to his challenge progression.
Action
Action is a feature which in the user has to apply an ecogesture for a given duration in order to reduce his consumption. An action refers to the model UserAction in the app, and is an extension of an ecogesture to which we add an startDate and a userActionState, allowing user to manage the action state depending on user's progress.
UserAction {
ecogesture: Ecogesture | null
state: UserActionState
startDate: DateTime | null
}
Unlike the exploration, duel and quiz, there is no relationship for an action in the ChallengeEntity model, given that the action is picked by the user. So once it is picked, it is directly stored in the current UserChallenge.
When a user launches an action, there is several possible cases :
The user has not completed his consumption profile
If the user's profile has never been completed, the application will purpose him the default action list which is defined in the action service. The first one of this list will be shown at first, and if the user wants to pick another one, he'll have the choice between the three ecogestures of the default list.
The user has completed his consumption profile
If the user has completed his profile, the application will purpose him a list of three custom ecogestures. The list is built the following way :
- First we look for the action that haven't been done yet
- We pick only the actions that are available for the user's connected fluids
- We pick actions that are applicable during the current season. At this moment, if the list is smaller than 3, we complete it with actions whose value for property Season is NONE
- If the list is still smaller than 3 after this, we complete with default actions (This case is rare)
- Finally, we sort the list of action by efficiency and then difficulty. We put the most efficient actions and with the lowest difficulty in first.
At any moment of an action, a user can consult his progress through a clock icon and the ending date of his action. The accomplishment of an action is only conditioned by the duration. Once the user completes an action, he'll see a notification on the app and then win his five stars when he comes back to the action screen.
Duel
On launch
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 time if the ones before got missing values.
We also define a threshold for a maximum old period
:::info
6 months for the moment - hard coded.
:::
If the threshold 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.
On going
Every time the user goes into the duel mode, we are checking if the duel is finished. if we have retrieved all data to calculate the user consumption on the duel duration, the duel is done.
:::note
In order to not block the user if a value is missing, we are also setting 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.
:::
On finish
Once the state of the duel is set to DONE, we save the user result and determine if he wins (userConsumption < threshold of the reference period) or if he loses. Then the user sees his earned badge.
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.
For more precision about the data management system you can refer the picture in the Initialization section