From 4362589ba70b86732f17db01d54a323913affcb7 Mon Sep 17 00:00:00 2001
From: Hugo SUBTIL <ext.sopra.husubtil@grandlyon.com>
Date: Wed, 29 Sep 2021 16:33:28 +0200
Subject: [PATCH] feat(alert-consumption): water consumption alert notification

---
 manifest.webapp                               |   5 +
 src/components/Options/ReportOptions.spec.tsx |  32 ++++++
 src/components/Options/ReportOptions.tsx      |  58 +++++++++-
 src/components/Options/reportOptions.scss     |  33 +++++-
 src/db/profileData.json                       |  42 ++++----
 src/locales/fr.json                           |  10 +-
 src/models/profile.model.ts                   |  72 +++++++------
 src/services/consumption.service.ts           |  19 ++++
 src/store/profile/profile.reducer.ts          |  86 +++++++--------
 src/targets/services/consumptionAlert.ts      | 101 ++++++++++++++++++
 .../services/monthlyReportNotification.ts     |  30 ++----
 src/utils/utils.ts                            |  24 +++++
 tests/__mocks__/profile.mock.ts               |  58 +++++-----
 tests/__mocks__/store.ts                      |   2 +
 14 files changed, 416 insertions(+), 156 deletions(-)
 create mode 100644 src/targets/services/consumptionAlert.ts

diff --git a/manifest.webapp b/manifest.webapp
index c644824d1..5d5539a41 100644
--- a/manifest.webapp
+++ b/manifest.webapp
@@ -135,6 +135,11 @@
       "file": "services/monthlyReportNotification/ecolyo.js",
       "trigger": "@cron 0 0 10 3 * *"
     },
+    "consumptionAlert": {
+      "type": "node",
+      "file": "services/consumptionAlert/ecolyo.js",
+      "trigger": "@cron 0 3 * * *"
+    },
     "aggregatorUsageEvents": {
       "type": "node",
       "file": "services/aggregatorUsageEvents/ecolyo.js",
diff --git a/src/components/Options/ReportOptions.spec.tsx b/src/components/Options/ReportOptions.spec.tsx
index 8636d80be..3ca58f678 100644
--- a/src/components/Options/ReportOptions.spec.tsx
+++ b/src/components/Options/ReportOptions.spec.tsx
@@ -8,6 +8,7 @@ import {
 } from '../../../tests/__mocks__/store'
 import * as profileActions from 'store/profile/profile.actions'
 import { Button } from '@material-ui/core'
+import StyledSwitch from 'components/CommonKit/Switch/StyledSwitch'
 
 jest.mock('cozy-ui/transpiled/react/I18n', () => {
   return {
@@ -80,4 +81,35 @@ describe('ReportOptions component', () => {
       sendAnalysisNotification: true,
     })
   })
+
+  it('should be rendered with sendConsumptionAlert to false', () => {
+    const wrapper = mount(
+      <Provider store={store}>
+        <ReportOptions />
+      </Provider>
+    )
+    expect(wrapper.find(StyledSwitch)).toHaveLength(1)
+    expect(
+      wrapper
+        .find(StyledSwitch)
+        .first()
+        .props().checked
+    ).toBeFalsy()
+  })
+
+  it('should update the profile with sendConsumptionAlert to true', () => {
+    const wrapper = mount(
+      <Provider store={store}>
+        <ReportOptions />
+      </Provider>
+    )
+    wrapper
+      .find('input')
+      .first()
+      .simulate('change', { target: { checked: 'true' } })
+    expect(updateProfileSpy).toBeCalledTimes(1)
+    expect(updateProfileSpy).toHaveBeenCalledWith({
+      sendConsumptionAlert: true,
+    })
+  })
 })
diff --git a/src/components/Options/ReportOptions.tsx b/src/components/Options/ReportOptions.tsx
index b6edc1b0f..afae05dec 100644
--- a/src/components/Options/ReportOptions.tsx
+++ b/src/components/Options/ReportOptions.tsx
@@ -5,6 +5,7 @@ import { useSelector, useDispatch } from 'react-redux'
 import { AppStore } from 'store'
 import { updateProfile } from 'store/profile/profile.actions'
 import { Button } from '@material-ui/core'
+import StyledSwitch from 'components/CommonKit/Switch/StyledSwitch'
 
 const ReportOptions: React.FC = () => {
   const { t } = useI18n()
@@ -15,21 +16,36 @@ const ReportOptions: React.FC = () => {
     dispatch(updateProfile({ sendAnalysisNotification: value }))
   }
 
+  const updateProfileAlert = async (value: boolean) => {
+    dispatch(updateProfile({ sendConsumptionAlert: value }))
+  }
+
+  const setWaterLimit = (e: React.ChangeEvent<HTMLInputElement>) => {
+    dispatch(
+      updateProfile({ waterDailyConsumptionLimit: parseInt(e.target.value) })
+    )
+  }
+
   const toggleAnalysisNotification = () => {
     profile.sendAnalysisNotification
       ? updateProfileReport(false)
       : updateProfileReport(true)
   }
 
+  const handleAlertChange = (e: React.ChangeEvent<HTMLInputElement>) => {
+    e.target.checked ? updateProfileAlert(true) : updateProfileAlert(false)
+  }
+
   return (
     <div className="report-option-root">
       <div className="report-option-content">
         <div className="head text-16-normal-uppercase">
-          {t('profile.report.title')}
+          {t('profile.report.title_bilan')}
         </div>
-        <div className="switch-container">
+        {/* Monthly Report activation */}
+        <div className="switch-container-bilan">
           <span className="switch-label text-16-normal">
-            {t('profile.report.switch_label')}
+            {t('profile.report.switch_label_bilan')}
           </span>
           <div className="button-container">
             <Button
@@ -48,6 +64,42 @@ const ReportOptions: React.FC = () => {
             </Button>
           </div>
         </div>
+
+        <div className="head text-16-normal-uppercase">
+          {t('profile.report.title_alert')}
+        </div>
+        {/* Consumption Alert activation */}
+        <div className="switch-container-alert">
+          <StyledSwitch
+            checked={profile.sendConsumptionAlert}
+            onChange={handleAlertChange}
+            inputProps={{
+              'aria-label': t(
+                'profile.accessibility.button_toggle_consumption_alert'
+              ),
+            }}
+          />
+          <span className="switch-label text-16-normal">
+            {t('profile.report.switch_label_alert')}
+          </span>
+        </div>
+        {profile.sendConsumptionAlert && (
+          <div className="alert-inputs-display">
+            <div className="head text-16-normal">Eau</div>
+            <div className="switch-container-alert">
+              <input
+                className="input-style"
+                type={'number'}
+                defaultValue={profile.waterDailyConsumptionLimit}
+                onBlur={setWaterLimit}
+                aria-label={t('profile.accessibility.input_water_alert_report')}
+              />
+              <span className="switch-label text-16-normal">
+                Litre(s) par jour
+              </span>
+            </div>
+          </div>
+        )}
       </div>
     </div>
   )
diff --git a/src/components/Options/reportOptions.scss b/src/components/Options/reportOptions.scss
index c13b56949..63302fffb 100644
--- a/src/components/Options/reportOptions.scss
+++ b/src/components/Options/reportOptions.scss
@@ -17,7 +17,7 @@
     margin: 1rem 0;
     color: $grey-bright;
   }
-  .switch-container {
+  .switch-container-bilan {
     display: flex;
     flex-direction: column;
     color: $grey-bright;
@@ -28,9 +28,38 @@
     .button-container {
       max-width: 200px;
       button {
-        margin-top: 0.5rem;
         width: 125px;
       }
     }
   }
+
+  .switch-container-alert {
+    display: flex;
+    align-items: center;
+    color: $grey-bright;
+    .switch-label {
+      margin-left: 0.2rem;
+      padding-right: 0.8rem;
+    }
+    .input-style {
+      width: 45px;
+      text-align: center;
+      margin: 0.5rem;
+      background: $dark-light-2;
+      color: $white;
+      border: 1px solid $gold-shadow;
+      max-width: 5rem;
+      height: 2rem;
+      &:focus {
+        outline: $gold-shadow 1px;
+      }
+      &:disabled {
+        -webkit-text-fill-color: $white;
+        opacity: 1;
+      }
+    }
+  }
+  .alert-inputs-display {
+    padding: 0 1rem;
+  }
 }
diff --git a/src/db/profileData.json b/src/db/profileData.json
index 94d627979..b9576397f 100644
--- a/src/db/profileData.json
+++ b/src/db/profileData.json
@@ -1,20 +1,22 @@
-[
-  {
-    "ecogestureHash": "",
-    "challengeHash": "",
-    "mailToken": "",
-    "duelHash": "",
-    "quizHash": "",
-    "isFirstConnection": true,
-    "lastConnectionDate": "0000-01-01T00:00:00.000Z",
-    "haveSeenOldFluidModal": false,
-    "haveSeenLastAnalysis": true,
-    "sendAnalysisNotification": true,
-    "monthlyAnalysisDate": "0000-01-01T00:00:00.000Z",
-    "isLastTermAccepted": false,
-    "isProfileTypeCompleted": false,
-    "tutorial": {
-      "isWelcomeSeen": false
-    }
-  }
-]
+[
+  {
+    "ecogestureHash": "",
+    "challengeHash": "",
+    "mailToken": "",
+    "duelHash": "",
+    "quizHash": "",
+    "isFirstConnection": true,
+    "lastConnectionDate": "0000-01-01T00:00:00.000Z",
+    "haveSeenOldFluidModal": false,
+    "haveSeenLastAnalysis": true,
+    "sendAnalysisNotification": true,
+    "monthlyAnalysisDate": "0000-01-01T00:00:00.000Z",
+    "sendConsumptionAlert": false,
+    "waterDailyConsumptionLimit": 0,
+    "isLastTermAccepted": false,
+    "isProfileTypeCompleted": false,
+    "tutorial": {
+      "isWelcomeSeen": false
+    }
+  }
+]
diff --git a/src/locales/fr.json b/src/locales/fr.json
index 54aa6dadd..d4e27f7de 100644
--- a/src/locales/fr.json
+++ b/src/locales/fr.json
@@ -642,13 +642,17 @@
   },
   "profile": {
     "report": {
-      "title": "Notification par mail",
-      "switch_label": "Être prévenu de la parution de mon bilan mensuel",
+      "title_alert": "Notification par mail",
+      "title_bilan": "Bilan et conseils",
+      "switch_label_bilan": "Réception mensuelle d'un bilan des consommations, de conseils sur les économies d'énergie et d'eau ainsi que d'informations sur les évolutions du service.",
+      "switch_label_alert": "Être prévenu d'un dépassement de consommation",
       "activate": "Activer",
       "deactivate": "Désactiver"
     },
     "accessibility": {
-      "button_toggle_mail_report": "Activer les notifications par mail"
+      "button_toggle_mail_report": "Recevoir mon bilan mensuel par mail",
+      "button_toggle_consumption_alert": "Recevoir des alertes sur mes consommations journalières",
+      "input_water_alert_report": "Indiquer une limite de consommation d'eau journalière"
     }
   },
   "profile_type": {
diff --git a/src/models/profile.model.ts b/src/models/profile.model.ts
index 5852df8a3..2ace99cb9 100644
--- a/src/models/profile.model.ts
+++ b/src/models/profile.model.ts
@@ -1,35 +1,37 @@
-import { DateTime } from 'luxon'
-
-interface Tutorial {
-  isWelcomeSeen: boolean
-}
-
-export interface ProfileEntity {
-  id: string
-  ecogestureHash: string
-  challengeHash: string
-  duelHash: string
-  quizHash: string
-  explorationHash: string
-  isFirstConnection: boolean
-  lastConnectionDate: string
-  haveSeenLastAnalysis: boolean
-  haveSeenOldFluidModal: string | boolean
-  sendAnalysisNotification: boolean
-  monthlyAnalysisDate: string
-  isProfileTypeCompleted: boolean
-  tutorial: Tutorial
-  mailToken: string
-  _id?: string
-  _rev?: string
-}
-
-export interface Profile
-  extends Omit<
-    ProfileEntity,
-    'haveSeenOldFluidModal' | 'lastConnectionDate' | 'monthlyAnalysisDate'
-  > {
-  lastConnectionDate: DateTime
-  haveSeenOldFluidModal: DateTime | boolean
-  monthlyAnalysisDate: DateTime
-}
+import { DateTime } from 'luxon'
+
+interface Tutorial {
+  isWelcomeSeen: boolean
+}
+
+export interface ProfileEntity {
+  id: string
+  ecogestureHash: string
+  challengeHash: string
+  duelHash: string
+  quizHash: string
+  explorationHash: string
+  isFirstConnection: boolean
+  lastConnectionDate: string
+  haveSeenLastAnalysis: boolean
+  haveSeenOldFluidModal: string | boolean
+  sendAnalysisNotification: boolean
+  monthlyAnalysisDate: string
+  sendConsumptionAlert: boolean
+  waterDailyConsumptionLimit: number
+  isProfileTypeCompleted: boolean
+  tutorial: Tutorial
+  mailToken: string
+  _id?: string
+  _rev?: string
+}
+
+export interface Profile
+  extends Omit<
+    ProfileEntity,
+    'haveSeenOldFluidModal' | 'lastConnectionDate' | 'monthlyAnalysisDate'
+  > {
+  lastConnectionDate: DateTime
+  haveSeenOldFluidModal: DateTime | boolean
+  monthlyAnalysisDate: DateTime
+}
diff --git a/src/services/consumption.service.ts b/src/services/consumption.service.ts
index 27cf550fb..18138db76 100644
--- a/src/services/consumption.service.ts
+++ b/src/services/consumption.service.ts
@@ -130,6 +130,25 @@ export default class ConsumptionDataManager {
     }
   }
 
+  //  fetch last dataload available for a given fluid - return the daily data
+  public async getLastDataload(
+    fluidTypes: FluidType
+  ): Promise<Dataload[] | null> {
+    const timePeriod = {
+      startDate: DateTime.now()
+        .plus({ days: -3 })
+        .startOf('day'),
+      endDate: DateTime.now(),
+    }
+
+    const data = await this._queryRunnerService.fetchFluidData(
+      timePeriod,
+      TimeStep.DAY,
+      fluidTypes
+    )
+    return data
+  }
+
   public async getPerformanceIndicators(
     timePeriod: TimePeriod,
     timeStep: TimeStep,
diff --git a/src/store/profile/profile.reducer.ts b/src/store/profile/profile.reducer.ts
index df049b075..6fbcae1dc 100644
--- a/src/store/profile/profile.reducer.ts
+++ b/src/store/profile/profile.reducer.ts
@@ -1,42 +1,44 @@
-import { Reducer } from 'redux'
-import {
-  UPDATE_PROFILE,
-  ProfileActionTypes,
-} from 'store/profile/profile.actions'
-import { Profile } from 'models'
-import { DateTime } from 'luxon'
-
-const initialState: Profile = {
-  id: '',
-  ecogestureHash: '',
-  challengeHash: '',
-  duelHash: '',
-  quizHash: '',
-  explorationHash: '',
-  isFirstConnection: false,
-  lastConnectionDate: DateTime.fromISO('0000-01-01T00:00:00.000Z'),
-  haveSeenOldFluidModal: true,
-  haveSeenLastAnalysis: true,
-  sendAnalysisNotification: true,
-  mailToken: '',
-  monthlyAnalysisDate: DateTime.fromISO('0000-01-01T00:00:00.000Z'),
-  isProfileTypeCompleted: false,
-  tutorial: {
-    isWelcomeSeen: false,
-  },
-}
-
-export const profileReducer: Reducer<Profile> = (
-  state = initialState,
-  action: ProfileActionTypes
-): Profile => {
-  switch (action.type) {
-    case UPDATE_PROFILE:
-      return {
-        ...state,
-        ...action.payload,
-      }
-    default:
-      return state
-  }
-}
+import { Reducer } from 'redux'
+import {
+  UPDATE_PROFILE,
+  ProfileActionTypes,
+} from 'store/profile/profile.actions'
+import { Profile } from 'models'
+import { DateTime } from 'luxon'
+
+const initialState: Profile = {
+  id: '',
+  ecogestureHash: '',
+  challengeHash: '',
+  duelHash: '',
+  quizHash: '',
+  explorationHash: '',
+  isFirstConnection: false,
+  lastConnectionDate: DateTime.fromISO('0000-01-01T00:00:00.000Z'),
+  haveSeenOldFluidModal: true,
+  haveSeenLastAnalysis: true,
+  sendAnalysisNotification: true,
+  sendConsumptionAlert: false,
+  waterDailyConsumptionLimit: 0,
+  mailToken: '',
+  monthlyAnalysisDate: DateTime.fromISO('0000-01-01T00:00:00.000Z'),
+  isProfileTypeCompleted: false,
+  tutorial: {
+    isWelcomeSeen: false,
+  },
+}
+
+export const profileReducer: Reducer<Profile> = (
+  state = initialState,
+  action: ProfileActionTypes
+): Profile => {
+  switch (action.type) {
+    case UPDATE_PROFILE:
+      return {
+        ...state,
+        ...action.payload,
+      }
+    default:
+      return state
+  }
+}
diff --git a/src/targets/services/consumptionAlert.ts b/src/targets/services/consumptionAlert.ts
new file mode 100644
index 000000000..16e191c42
--- /dev/null
+++ b/src/targets/services/consumptionAlert.ts
@@ -0,0 +1,101 @@
+import logger from 'cozy-logger'
+import { Client } from 'cozy-client'
+import get from 'lodash/get'
+import { runService } from './service'
+import ProfileService from 'services/profile.service'
+import MailService from 'services/mail.service'
+import { DateTime } from 'luxon'
+const consumptionLimit = require('notifications/consumptionLimit.hbs')
+import mjml2html from 'mjml'
+import { FluidType } from 'enum/fluid.enum'
+import ConsumptionService from 'services/consumption.service'
+import { getMonthName } from 'utils/utils'
+
+const log = logger.namespace('alert')
+
+interface ConsumptionAlertProps {
+  client: Client
+}
+
+//  Only monitoring WATER fluid for now
+const consumptionAlert = async ({ client }: ConsumptionAlertProps) => {
+  log('info', 'Fetching user profile...')
+  const upm = new ProfileService(client)
+  const consumptionService = new ConsumptionService(client)
+  const userProfil = await upm.getProfile()
+  if (
+    !userProfil ||
+    !userProfil.sendConsumptionAlert ||
+    userProfil.waterDailyConsumptionLimit === 0
+  ) {
+    log(
+      'info',
+      'End of process - Alert report notification is disabled or lack informations from user profile to run'
+    )
+    return
+  }
+
+  let username = ''
+
+  log('info', 'water limit is :' + userProfil.waterDailyConsumptionLimit)
+
+  log('info', 'Fetching fluid data...')
+  // Retrieve public name from the stack
+  const settings = await client
+    .getStackClient()
+    .fetchJSON('GET', '/settings/instance')
+  const publicName = get(settings, 'data.attributes.public_name')
+  if (publicName) {
+    username = publicName
+  }
+
+  // Retrieve link to ecolyo app from the stack
+  const apps = await client.getStackClient().fetchJSON('GET', '/apps/ecolyo')
+  const appLink = get(apps, 'data.links.related')
+
+  const fetchedData = await consumptionService.getLastDataload(FluidType.WATER)
+  let lastDayValue = 0
+  if (fetchedData && fetchedData.length > 0) {
+    fetchedData.forEach(element => {
+      if (element.value) {
+        lastDayValue = element.value
+      }
+    })
+  }
+  if (lastDayValue <= userProfil.waterDailyConsumptionLimit) {
+    log(
+      'info',
+      'End of process - Limit consumption set by the user has not been passed.'
+    )
+    return
+  }
+
+  log('info', 'Creation of mail...')
+  const mailService = new MailService()
+  const today = DateTime.local().setZone('utc', { keepLocalTime: true })
+
+  const template = consumptionLimit({
+    title: 'Ça déborde !',
+    username: username,
+    clientUrl: appLink,
+    unsubscribeUrl: appLink + '/#/options',
+    userLimit: userProfil.waterDailyConsumptionLimit,
+    limitDate: `${today.day} ${getMonthName(today)}`,
+  })
+
+  const mailData = {
+    mode: 'noreply',
+    subject: '[Ecolyo] - Consommation maximale atteinte',
+    parts: [
+      {
+        type: 'text/html',
+        body: mjml2html(template).html,
+      },
+    ],
+  }
+
+  log('info', 'Sending mail...')
+  mailService.SendMail(client, mailData)
+}
+
+runService(consumptionAlert)
diff --git a/src/targets/services/monthlyReportNotification.ts b/src/targets/services/monthlyReportNotification.ts
index deb83f0bd..01b78d0c5 100644
--- a/src/targets/services/monthlyReportNotification.ts
+++ b/src/targets/services/monthlyReportNotification.ts
@@ -13,6 +13,7 @@ import { TimeStep } from 'enum/timeStep.enum'
 import ConsumptionService from 'services/consumption.service'
 import { MonthlReport } from 'models/monthlyReport.model'
 import EnvironementService from 'services/environement.service'
+import { getMonthName } from 'utils/utils'
 
 const log = logger.namespace('report')
 
@@ -110,28 +111,6 @@ const buildConsumptionText = async (client: Client) => {
   return text
 }
 
-const getMonthName = () => {
-  const monthNames = [
-    'janiver',
-    'février',
-    'mars',
-    'avril',
-    'mai',
-    'juin',
-    'juillet',
-    'août',
-    'septembre',
-    'octobre',
-    'novembre',
-    'décembre',
-  ]
-
-  const d = DateTime.local()
-    .setZone('utc', { keepLocalTime: true })
-    .minus({ month: 2 })
-  return monthNames[d.month]
-}
-
 /**
  * getMonthlyReport
  */
@@ -256,6 +235,11 @@ const monthlyReportNotification = async ({
 
   const isPoll: boolean =
     monthlyReport.question !== '' && monthlyReport.link !== ''
+
+  const date = DateTime.local()
+    .setZone('utc', { keepLocalTime: true })
+    .minus({ month: 2 })
+
   const template = monthlyReportTemplate({
     title: 'Du nouveau dans votre espace Ecolyo !',
     username: username,
@@ -277,7 +261,7 @@ const monthlyReportNotification = async ({
     ),
     pollText: monthlyReport.question.replace(/{cozyUrl}/g, appLink + '#/'),
     pollUrl: monthlyReport.link,
-    previousMonth: getMonthName(),
+    previousMonth: getMonthName(date),
     consoImageUrl:
       environementService.getPublicURL() + '/assets/multifluidConsumption.svg',
   })
diff --git a/src/utils/utils.ts b/src/utils/utils.ts
index 52aef321e..6a5cc5f12 100644
--- a/src/utils/utils.ts
+++ b/src/utils/utils.ts
@@ -2,6 +2,7 @@ import get from 'lodash/get'
 import { GetRelationshipsReturn, Relation } from 'models'
 import { FluidType } from '../enum/fluid.enum'
 import { KonnectorUpdate } from '../enum/konnectorUpdate.enum'
+import { DateTime } from 'luxon'
 
 export function getFluidType(type: string) {
   switch (type.toUpperCase()) {
@@ -96,3 +97,26 @@ export const importIconbyId = async (id: string, pathType: string) => {
     return importedChallengeIcon.default
   }
 }
+
+/**
+ * Return month string according to month index
+ * @param date - DateTime
+ * @returns month in french
+ */
+export const getMonthName = (date: DateTime) => {
+  const monthNames = [
+    'janiver',
+    'février',
+    'mars',
+    'avril',
+    'mai',
+    'juin',
+    'juillet',
+    'août',
+    'septembre',
+    'octobre',
+    'novembre',
+    'décembre',
+  ]
+  return monthNames[date.month]
+}
diff --git a/tests/__mocks__/profile.mock.ts b/tests/__mocks__/profile.mock.ts
index 6a0c50c69..46410205e 100644
--- a/tests/__mocks__/profile.mock.ts
+++ b/tests/__mocks__/profile.mock.ts
@@ -1,28 +1,30 @@
-import { DateTime } from 'luxon'
-import { Profile } from 'models'
-
-export const profileData: Profile = {
-  _id: '4d9403218ef13e65b2e3a8ad1700bc41',
-  _rev: '16-57473da4fc26315247c217083175dfa0',
-  id: '4d9403218ef13e65b2e3a8ad1700bc41',
-  ecogestureHash: '9798a0aaccb47cff906fc4931a2eff5f9371dd8b',
-  challengeHash: '1136feb6185c7643e071d14180c0e95782aa4ba3',
-  duelHash: '1136feb6185c7643e071d14180c0e95782aa4ba3',
-  quizHash: '1136feb6185c7643e071d14180c0e95782aa4ba3',
-  explorationHash: '1136feb6185c7643e071d14180c0e95782aa4ba3',
-  isFirstConnection: true,
-  mailToken: '',
-  lastConnectionDate: DateTime.fromISO('2020-11-03T00:00:00.000Z', {
-    zone: 'utc',
-  }),
-  haveSeenOldFluidModal: false,
-  haveSeenLastAnalysis: true,
-  monthlyAnalysisDate: DateTime.fromISO('2020-11-03T00:00:00.000Z', {
-    zone: 'utc',
-  }),
-  sendAnalysisNotification: false,
-  isProfileTypeCompleted: false,
-  tutorial: {
-    isWelcomeSeen: false,
-  },
-}
+import { DateTime } from 'luxon'
+import { Profile } from 'models'
+
+export const profileData: Profile = {
+  _id: '4d9403218ef13e65b2e3a8ad1700bc41',
+  _rev: '16-57473da4fc26315247c217083175dfa0',
+  id: '4d9403218ef13e65b2e3a8ad1700bc41',
+  ecogestureHash: '9798a0aaccb47cff906fc4931a2eff5f9371dd8b',
+  challengeHash: '1136feb6185c7643e071d14180c0e95782aa4ba3',
+  duelHash: '1136feb6185c7643e071d14180c0e95782aa4ba3',
+  quizHash: '1136feb6185c7643e071d14180c0e95782aa4ba3',
+  explorationHash: '1136feb6185c7643e071d14180c0e95782aa4ba3',
+  isFirstConnection: true,
+  sendConsumptionAlert: false,
+  waterDailyConsumptionLimit: 0,
+  mailToken: '',
+  lastConnectionDate: DateTime.fromISO('2020-11-03T00:00:00.000Z', {
+    zone: 'utc',
+  }),
+  haveSeenOldFluidModal: false,
+  haveSeenLastAnalysis: true,
+  monthlyAnalysisDate: DateTime.fromISO('2020-11-03T00:00:00.000Z', {
+    zone: 'utc',
+  }),
+  sendAnalysisNotification: false,
+  isProfileTypeCompleted: false,
+  tutorial: {
+    isWelcomeSeen: false,
+  },
+}
diff --git a/tests/__mocks__/store.ts b/tests/__mocks__/store.ts
index fa8a9e56d..1fe5285dc 100644
--- a/tests/__mocks__/store.ts
+++ b/tests/__mocks__/store.ts
@@ -108,6 +108,8 @@ export const mockInitialProfileState: Profile = {
   lastConnectionDate: DateTime.fromISO('0000-01-01T00:00:00.000Z'),
   haveSeenOldFluidModal: true,
   haveSeenLastAnalysis: true,
+  sendConsumptionAlert: false,
+  waterDailyConsumptionLimit: 0,
   sendAnalysisNotification: true,
   mailToken: '',
   monthlyAnalysisDate: DateTime.fromISO('0000-01-01T00:00:00.000Z'),
-- 
GitLab