From 179f76200232db0e0a41c06a34b16d5a0b3acfbd Mon Sep 17 00:00:00 2001
From: Bastien DUMONT <bdumont@grandlyon.com>
Date: Wed, 23 Aug 2023 11:57:42 +0000
Subject: [PATCH] refactor(redux-rtk): profile

---
 package.json                                  |   1 +
 src/components/Analysis/AnalysisView.spec.tsx |   2 +-
 src/components/Analysis/AnalysisView.tsx      |   8 +-
 .../Ecogesture/EcogestureTabsView.spec.tsx    |   2 +-
 .../Ecogesture/EcogestureTabsView.tsx         |   2 +-
 .../EcogestureForm/EcogestureFormView.tsx     |   2 +-
 .../ReportOptions/ReportOptions.spec.tsx      |   2 +-
 .../Options/ReportOptions/ReportOptions.tsx   |  10 +-
 .../Unsubscribe/UnSubscribeView.spec.tsx      |   2 +-
 .../Options/Unsubscribe/UnSubscribeView.tsx   |   2 +-
 .../ProfileTypeFinished.tsx                   |   2 +-
 src/components/Splash/SplashRoot.tsx          |   2 +-
 .../WelcomeModal/WelcomeModal.spec.tsx        |   2 +-
 src/components/WelcomeModal/WelcomeModal.tsx  |   7 +-
 src/store/hooks.ts                            |  13 +-
 src/store/profile/profile.action.spec.ts      |  35 -----
 src/store/profile/profile.actions.ts          |  35 -----
 src/store/profile/profile.reducer.spec.ts     |  26 ----
 src/store/profile/profile.slice.spec.ts       |  11 ++
 .../{profile.reducer.ts => profile.slice.ts}  | 144 ++++++++++--------
 src/store/store.ts                            |  11 +-
 21 files changed, 124 insertions(+), 197 deletions(-)
 delete mode 100644 src/store/profile/profile.action.spec.ts
 delete mode 100644 src/store/profile/profile.actions.ts
 delete mode 100644 src/store/profile/profile.reducer.spec.ts
 create mode 100644 src/store/profile/profile.slice.spec.ts
 rename src/store/profile/{profile.reducer.ts => profile.slice.ts} (54%)

diff --git a/package.json b/package.json
index 8120d00fe..b7f05b0d2 100644
--- a/package.json
+++ b/package.json
@@ -82,6 +82,7 @@
     "react-swipeable-views": "0.14.0",
     "redux-devtools-extension": "^2.13.8",
     "redux-logger": "^3.0.6",
+    "redux-thunk": "^2.4.2",
     "xlsx": "^0.18.5"
   },
   "devDependencies": {
diff --git a/src/components/Analysis/AnalysisView.spec.tsx b/src/components/Analysis/AnalysisView.spec.tsx
index ed211248c..1481e2c88 100644
--- a/src/components/Analysis/AnalysisView.spec.tsx
+++ b/src/components/Analysis/AnalysisView.spec.tsx
@@ -4,7 +4,7 @@ import React from 'react'
 import { Provider } from 'react-redux'
 import * as globalActions from 'store/global/global.slice'
 import * as storeHooks from 'store/hooks'
-import * as profileActions from 'store/profile/profile.actions'
+import * as profileActions from 'store/profile/profile.slice'
 import {
   createMockEcolyoStore,
   mockAnalysisState,
diff --git a/src/components/Analysis/AnalysisView.tsx b/src/components/Analysis/AnalysisView.tsx
index 048a04a54..6f8421d9a 100644
--- a/src/components/Analysis/AnalysisView.tsx
+++ b/src/components/Analysis/AnalysisView.tsx
@@ -13,7 +13,7 @@ import UsageEventService from 'services/usageEvent.service'
 import { setAnalysisMonth } from 'store/analysis/analysis.slice'
 import { toggleAnalysisNotification } from 'store/global/global.slice'
 import { useAppDispatch, useAppSelector } from 'store/hooks'
-import { updateProfile } from 'store/profile/profile.actions'
+import { updateProfile } from 'store/profile/profile.slice'
 import { isLastDateReached } from 'utils/date'
 import './analysisView.scss'
 
@@ -49,11 +49,7 @@ const AnalysisView = () => {
   useEffect(() => {
     const updateAnalysisNotification = () => {
       if (analysisNotification) {
-        dispatch(
-          updateProfile({
-            haveSeenLastAnalysis: true,
-          })
-        )
+        dispatch(updateProfile({ haveSeenLastAnalysis: true }))
         dispatch(toggleAnalysisNotification(false))
       }
 
diff --git a/src/components/Ecogesture/EcogestureTabsView.spec.tsx b/src/components/Ecogesture/EcogestureTabsView.spec.tsx
index 30c9db5e4..17d8c832f 100644
--- a/src/components/Ecogesture/EcogestureTabsView.spec.tsx
+++ b/src/components/Ecogesture/EcogestureTabsView.spec.tsx
@@ -5,7 +5,7 @@ import { mount } from 'enzyme'
 import toJson from 'enzyme-to-json'
 import React from 'react'
 import { Provider } from 'react-redux'
-import * as profileActions from 'store/profile/profile.actions'
+import * as profileActions from 'store/profile/profile.slice'
 import { mockedEcogesturesData } from 'tests/__mocks__/ecogesturesData.mock'
 import { createMockEcolyoStore } from 'tests/__mocks__/store'
 import { waitForComponentToPaint } from 'tests/__mocks__/testUtils'
diff --git a/src/components/Ecogesture/EcogestureTabsView.tsx b/src/components/Ecogesture/EcogestureTabsView.tsx
index 7f2581807..d3c8b3a72 100644
--- a/src/components/Ecogesture/EcogestureTabsView.tsx
+++ b/src/components/Ecogesture/EcogestureTabsView.tsx
@@ -12,7 +12,7 @@ import React, { useCallback, useEffect, useState } from 'react'
 import { useLocation, useNavigate } from 'react-router-dom'
 import EcogestureService from 'services/ecogesture.service'
 import { useAppDispatch, useAppSelector } from 'store/hooks'
-import { updateProfile } from 'store/profile/profile.actions'
+import { updateProfile } from 'store/profile/profile.slice'
 import EcogestureEmptyList from './EcogestureEmptyList/EcogestureEmptyList'
 import EcogestureInitModal from './EcogestureInitModal/EcogestureInitModal'
 import EcogestureList from './EcogestureList/EcogestureList'
diff --git a/src/components/EcogestureForm/EcogestureFormView.tsx b/src/components/EcogestureForm/EcogestureFormView.tsx
index 908701794..20c2f9719 100644
--- a/src/components/EcogestureForm/EcogestureFormView.tsx
+++ b/src/components/EcogestureForm/EcogestureFormView.tsx
@@ -9,7 +9,7 @@ import React, { useCallback, useEffect, useState } from 'react'
 import { useLocation, useNavigate } from 'react-router-dom'
 import ProfileEcogestureFormService from 'services/profileEcogestureForm.service'
 import { useAppDispatch, useAppSelector } from 'store/hooks'
-import { updateProfile } from 'store/profile/profile.actions'
+import { updateProfile } from 'store/profile/profile.slice'
 import { newProfileEcogestureEntry } from 'store/profileEcogesture/profileEcogesture.actions'
 import EcogestureFormEquipment from './EcogestureFormEquipment/EcogestureFormEquipment'
 import EcogestureFormSingleChoice from './EcogestureFormSingleChoice/EcogestureFormSingleChoice'
diff --git a/src/components/Options/ReportOptions/ReportOptions.spec.tsx b/src/components/Options/ReportOptions/ReportOptions.spec.tsx
index 8284ab494..070689330 100644
--- a/src/components/Options/ReportOptions/ReportOptions.spec.tsx
+++ b/src/components/Options/ReportOptions/ReportOptions.spec.tsx
@@ -5,7 +5,7 @@ import { FluidState, FluidType } from 'enums'
 import { mount } from 'enzyme'
 import React from 'react'
 import { Provider } from 'react-redux'
-import * as profileActions from 'store/profile/profile.actions'
+import * as profileActions from 'store/profile/profile.slice'
 import {
   createMockEcolyoStore,
   mockInitialEcolyoState,
diff --git a/src/components/Options/ReportOptions/ReportOptions.tsx b/src/components/Options/ReportOptions/ReportOptions.tsx
index 9a3af3318..893eb0066 100644
--- a/src/components/Options/ReportOptions/ReportOptions.tsx
+++ b/src/components/Options/ReportOptions/ReportOptions.tsx
@@ -8,7 +8,7 @@ import { Dataload, TimePeriod } from 'models'
 import React, { useCallback, useEffect, useState } from 'react'
 import ConsumptionDataManager from 'services/consumption.service'
 import { useAppDispatch, useAppSelector } from 'store/hooks'
-import { updateProfile } from 'store/profile/profile.actions'
+import { updateProfile } from 'store/profile/profile.slice'
 import './reportOptions.scss'
 
 const ReportOptions = () => {
@@ -21,12 +21,12 @@ const ReportOptions = () => {
   } = useAppSelector(state => state.ecolyo)
   const [maxDayData, setLastSemesterMaxDay] = useState<Dataload | null>(null)
 
-  const updateProfileReport = async (value: boolean) => {
+  const updateProfileReport = (value: boolean) => {
     dispatch(updateProfile({ sendAnalysisNotification: value }))
   }
 
   const updateProfileAlert = useCallback(
-    async (value: boolean) => {
+    (value: boolean) => {
       dispatch(updateProfile({ sendConsumptionAlert: value }))
     },
     [dispatch]
@@ -35,7 +35,9 @@ const ReportOptions = () => {
   const setWaterLimit = (e: React.ChangeEvent<HTMLInputElement>) => {
     if (e.target.value !== null && parseInt(e.target.value) > 0) {
       dispatch(
-        updateProfile({ waterDailyConsumptionLimit: parseInt(e.target.value) })
+        updateProfile({
+          waterDailyConsumptionLimit: parseInt(e.target.value),
+        })
       )
     } else {
       updateProfileAlert(false)
diff --git a/src/components/Options/Unsubscribe/UnSubscribeView.spec.tsx b/src/components/Options/Unsubscribe/UnSubscribeView.spec.tsx
index 2ef010932..f5534ba25 100644
--- a/src/components/Options/Unsubscribe/UnSubscribeView.spec.tsx
+++ b/src/components/Options/Unsubscribe/UnSubscribeView.spec.tsx
@@ -3,7 +3,7 @@ import { mount } from 'enzyme'
 import toJson from 'enzyme-to-json'
 import React from 'react'
 import { Provider } from 'react-redux'
-import * as profileActions from 'store/profile/profile.actions'
+import * as profileActions from 'store/profile/profile.slice'
 import { createMockEcolyoStore } from 'tests/__mocks__/store'
 import UnSubscribeView from './UnSubscribeView'
 
diff --git a/src/components/Options/Unsubscribe/UnSubscribeView.tsx b/src/components/Options/Unsubscribe/UnSubscribeView.tsx
index 2a2f74e98..b73ad7d53 100644
--- a/src/components/Options/Unsubscribe/UnSubscribeView.tsx
+++ b/src/components/Options/Unsubscribe/UnSubscribeView.tsx
@@ -8,7 +8,7 @@ import { useI18n } from 'cozy-ui/transpiled/react/I18n'
 import React, { useState } from 'react'
 import { useNavigate } from 'react-router-dom'
 import { useAppDispatch } from 'store/hooks'
-import { updateProfile } from 'store/profile/profile.actions'
+import { updateProfile } from 'store/profile/profile.slice'
 import './unSubscribeView.scss'
 
 const UnSubscribeView = () => {
diff --git a/src/components/ProfileType/ProfileTypeFinished/ProfileTypeFinished.tsx b/src/components/ProfileType/ProfileTypeFinished/ProfileTypeFinished.tsx
index 38973bed6..41688501c 100644
--- a/src/components/ProfileType/ProfileTypeFinished/ProfileTypeFinished.tsx
+++ b/src/components/ProfileType/ProfileTypeFinished/ProfileTypeFinished.tsx
@@ -15,7 +15,7 @@ import ProfileTypeService from 'services/profileType.service'
 import ProfileTypeEntityService from 'services/profileTypeEntity.service'
 import UsageEventService from 'services/usageEvent.service'
 import { useAppDispatch, useAppSelector } from 'store/hooks'
-import { updateProfile } from 'store/profile/profile.actions'
+import { updateProfile } from 'store/profile/profile.slice'
 import { setProfileType } from 'store/profileType/profileType.slice'
 import './profileTypeFinished.scss'
 
diff --git a/src/components/Splash/SplashRoot.tsx b/src/components/Splash/SplashRoot.tsx
index 0cedc5b42..24e1f4444 100644
--- a/src/components/Splash/SplashRoot.tsx
+++ b/src/components/Splash/SplashRoot.tsx
@@ -49,7 +49,7 @@ import {
 } from 'store/global/global.slice'
 import { useAppDispatch } from 'store/hooks'
 import { openPartnersModal, setCustomPopup } from 'store/modal/modal.slice'
-import { updateProfile } from 'store/profile/profile.actions'
+import { updateProfile } from 'store/profile/profile.slice'
 import { updateProfileEcogestureSuccess } from 'store/profileEcogesture/profileEcogesture.actions'
 import { setProfileType } from 'store/profileType/profileType.slice'
 import { logDuration } from 'utils/duration'
diff --git a/src/components/WelcomeModal/WelcomeModal.spec.tsx b/src/components/WelcomeModal/WelcomeModal.spec.tsx
index d22a87a29..8bce59cfc 100644
--- a/src/components/WelcomeModal/WelcomeModal.spec.tsx
+++ b/src/components/WelcomeModal/WelcomeModal.spec.tsx
@@ -3,7 +3,7 @@ import { mount } from 'enzyme'
 import toJson from 'enzyme-to-json'
 import React from 'react'
 import { Provider } from 'react-redux'
-import * as profileActions from 'store/profile/profile.actions'
+import * as profileActions from 'store/profile/profile.slice'
 import mockClient from 'tests/__mocks__/client'
 import { createMockEcolyoStore } from 'tests/__mocks__/store'
 import WelcomeModal from './WelcomeModal'
diff --git a/src/components/WelcomeModal/WelcomeModal.tsx b/src/components/WelcomeModal/WelcomeModal.tsx
index 3e8fdf83b..a7dfddae9 100644
--- a/src/components/WelcomeModal/WelcomeModal.tsx
+++ b/src/components/WelcomeModal/WelcomeModal.tsx
@@ -9,7 +9,7 @@ import React, { useCallback } from 'react'
 import EnvironmentService from 'services/environment.service'
 import MailService from 'services/mail.service'
 import { useAppDispatch } from 'store/hooks'
-import { updateProfile } from 'store/profile/profile.actions'
+import { updateProfile } from 'store/profile/profile.slice'
 import './welcomeModal.scss'
 
 const welcomeTemplate = require('notifications/welcome.hbs')
@@ -62,13 +62,10 @@ const WelcomeModal = ({ open }: WelcomeModalProps) => {
     }
 
     mailService.SendMail(client, mailData)
-
     dispatch(
       updateProfile({
         isFirstConnection: false,
-        onboarding: {
-          isWelcomeSeen: true,
-        },
+        onboarding: { isWelcomeSeen: true },
       })
     )
   }, [client, dispatch, instanceSettings])
diff --git a/src/store/hooks.ts b/src/store/hooks.ts
index 0bca4f1d3..10ca3366a 100644
--- a/src/store/hooks.ts
+++ b/src/store/hooks.ts
@@ -1,9 +1,16 @@
+import { Client } from 'cozy-client'
 import { TypedUseSelectorHook, useDispatch, useSelector } from 'react-redux'
-import { AppDispatch, AppStore } from './store'
-
+import { ThunkDispatch } from 'redux-thunk'
+import { AppActionsTypes, AppStore } from './store'
 // Typed hooks
 // https://redux.js.org/tutorials/typescript-quick-start#define-typed-hooks
 
-export const useAppDispatch: () => AppDispatch = useDispatch
+/** Combine classic actions and thunk actions */
+type TypedDispatch = ThunkDispatch<
+  AppStore,
+  { client: Client },
+  AppActionsTypes
+>
+export const useAppDispatch = () => useDispatch<TypedDispatch>()
 // TODO maybe use AppEcolyoStore
 export const useAppSelector: TypedUseSelectorHook<AppStore> = useSelector
diff --git a/src/store/profile/profile.action.spec.ts b/src/store/profile/profile.action.spec.ts
deleted file mode 100644
index 3514e50ca..000000000
--- a/src/store/profile/profile.action.spec.ts
+++ /dev/null
@@ -1,35 +0,0 @@
-import { createMockEcolyoStore, mockProfileState } from 'tests/__mocks__/store'
-import { UPDATE_PROFILE, updateProfile } from './profile.actions'
-
-const mockUpdateProfile = jest.fn()
-jest.mock('services/profile.service', () => {
-  return jest.fn(() => {
-    return {
-      updateProfile: mockUpdateProfile,
-    }
-  })
-})
-
-describe('profile actions', () => {
-  const store = createMockEcolyoStore()
-  beforeEach(() => {
-    store.clearActions()
-  })
-  it('should create an UPDATE_PROFILE action when profile is updated', async () => {
-    mockUpdateProfile.mockResolvedValueOnce(mockProfileState)
-    const expectedActions = [
-      {
-        type: UPDATE_PROFILE,
-        payload: mockProfileState,
-      },
-    ]
-    await store.dispatch(updateProfile(mockProfileState))
-    expect(store.getActions()).toEqual(expectedActions)
-  })
-
-  it('should not create action when profile is not updated', async () => {
-    mockUpdateProfile.mockResolvedValueOnce(null)
-    await store.dispatch(updateProfile(mockProfileState))
-    expect(store.getActions()).toEqual([])
-  })
-})
diff --git a/src/store/profile/profile.actions.ts b/src/store/profile/profile.actions.ts
deleted file mode 100644
index a05d598b5..000000000
--- a/src/store/profile/profile.actions.ts
+++ /dev/null
@@ -1,35 +0,0 @@
-import { Client } from 'cozy-client'
-import { Profile } from 'models'
-import { Dispatch } from 'react'
-import ProfileService from 'services/profile.service'
-import { AppStore, defaultAction } from 'store/store'
-
-export const UPDATE_PROFILE = 'UPDATE_PROFILE'
-
-export interface UpdateProfile {
-  type: typeof UPDATE_PROFILE
-  payload?: Profile
-}
-
-export type ProfileActionTypes = UpdateProfile | typeof defaultAction
-
-function updateProfileSuccess(updatedProfile: Profile): UpdateProfile {
-  return {
-    type: UPDATE_PROFILE,
-    payload: updatedProfile,
-  }
-}
-
-export function updateProfile(updates: Partial<Profile>): any {
-  return async (
-    dispatch: Dispatch<UpdateProfile>,
-    getState: () => AppStore,
-    { client }: { client: Client }
-  ) => {
-    const profileService = new ProfileService(client)
-    const updatedProfile = await profileService.updateProfile(updates)
-    if (updatedProfile) {
-      dispatch(updateProfileSuccess(updatedProfile))
-    }
-  }
-}
diff --git a/src/store/profile/profile.reducer.spec.ts b/src/store/profile/profile.reducer.spec.ts
deleted file mode 100644
index 637260069..000000000
--- a/src/store/profile/profile.reducer.spec.ts
+++ /dev/null
@@ -1,26 +0,0 @@
-import { defaultAction } from 'store/store'
-import { mockProfileState } from 'tests/__mocks__/store'
-import { UPDATE_PROFILE } from './profile.actions'
-import { profileReducer } from './profile.reducer'
-
-describe('profile reducer', () => {
-  it('should return the initial state', () => {
-    const state = profileReducer(undefined, { ...defaultAction })
-    expect(state).toEqual(mockProfileState)
-  })
-
-  it('should handle UPDATE_PROFILE with payload', () => {
-    const state = profileReducer(mockProfileState, {
-      type: UPDATE_PROFILE,
-      payload: mockProfileState,
-    })
-    expect(state).toEqual(mockProfileState)
-  })
-
-  it('should handle UPDATE_PROFILE without payload', () => {
-    const state = profileReducer(mockProfileState, {
-      type: UPDATE_PROFILE,
-    })
-    expect(state).toEqual(mockProfileState)
-  })
-})
diff --git a/src/store/profile/profile.slice.spec.ts b/src/store/profile/profile.slice.spec.ts
new file mode 100644
index 000000000..aca5f4bbd
--- /dev/null
+++ b/src/store/profile/profile.slice.spec.ts
@@ -0,0 +1,11 @@
+import { mockProfileState } from '../../../tests/__mocks__/store'
+import { profileSlice } from './profile.slice'
+
+describe('profile slice', () => {
+  it('should return the initial state', () => {
+    const initialState = profileSlice.reducer(undefined, {
+      type: undefined,
+    })
+    expect(initialState).toEqual(mockProfileState)
+  })
+})
diff --git a/src/store/profile/profile.reducer.ts b/src/store/profile/profile.slice.ts
similarity index 54%
rename from src/store/profile/profile.reducer.ts
rename to src/store/profile/profile.slice.ts
index 5277a42a8..1cc32cf33 100644
--- a/src/store/profile/profile.reducer.ts
+++ b/src/store/profile/profile.slice.ts
@@ -1,66 +1,78 @@
-import { DateTime } from 'luxon'
-import { Profile } from 'models'
-import { Reducer } from 'redux'
-import {
-  ProfileActionTypes,
-  UPDATE_PROFILE,
-} from 'store/profile/profile.actions'
-
-const initialState: Profile = {
-  id: '',
-  ecogestureHash: '',
-  challengeHash: '',
-  duelHash: '',
-  quizHash: '',
-  explorationHash: '',
-  isFirstConnection: false,
-  partnersIssueSeenDate: {
-    enedis: DateTime.fromISO('0000-01-01T00:00:00.000Z', {
-      zone: 'utc',
-    }),
-    egl: DateTime.fromISO('0000-01-01T00:00:00.000Z', {
-      zone: 'utc',
-    }),
-    grdf: DateTime.fromISO('0000-01-01T00:00:00.000Z', {
-      zone: 'utc',
-    }),
-  },
-  lastConnectionDate: DateTime.fromISO('0000-01-01T00:00:00.000Z', {
-    zone: 'utc',
-  }),
-  customPopupDate: DateTime.fromISO('0000-01-01T00:00:00.000Z', {
-    zone: 'utc',
-  }),
-  haveSeenLastAnalysis: true,
-  sendAnalysisNotification: true,
-  sendConsumptionAlert: false,
-  waterDailyConsumptionLimit: 0,
-  mailToken: '',
-  monthlyAnalysisDate: DateTime.fromISO('0000-01-01T00:00:00.000Z', {
-    zone: 'utc',
-  }),
-  isProfileTypeCompleted: false,
-  isProfileEcogestureCompleted: false,
-  onboarding: {
-    isWelcomeSeen: true,
-  },
-  haveSeenEcogestureModal: false,
-  activateHalfHourDate: DateTime.fromISO('0000-01-01T00:00:00.000Z', {
-    zone: 'utc',
-  }),
-}
-
-export const profileReducer: Reducer<Profile, ProfileActionTypes> = (
-  state = initialState,
-  action
-) => {
-  switch (action.type) {
-    case UPDATE_PROFILE:
-      return {
-        ...state,
-        ...action.payload,
-      }
-    default:
-      return state
-  }
-}
+import { createAsyncThunk, createSlice } from '@reduxjs/toolkit'
+import { Client } from 'cozy-client'
+import { DateTime } from 'luxon'
+import { Profile } from 'models'
+import ProfileService from 'services/profile.service'
+import { AppDispatch, AppStore } from 'store/store'
+
+const initialState: Profile = {
+  id: '',
+  ecogestureHash: '',
+  challengeHash: '',
+  duelHash: '',
+  quizHash: '',
+  explorationHash: '',
+  isFirstConnection: false,
+  partnersIssueSeenDate: {
+    enedis: DateTime.fromISO('0000-01-01T00:00:00.000Z', {
+      zone: 'utc',
+    }),
+    egl: DateTime.fromISO('0000-01-01T00:00:00.000Z', {
+      zone: 'utc',
+    }),
+    grdf: DateTime.fromISO('0000-01-01T00:00:00.000Z', {
+      zone: 'utc',
+    }),
+  },
+  lastConnectionDate: DateTime.fromISO('0000-01-01T00:00:00.000Z', {
+    zone: 'utc',
+  }),
+  customPopupDate: DateTime.fromISO('0000-01-01T00:00:00.000Z', {
+    zone: 'utc',
+  }),
+  haveSeenLastAnalysis: true,
+  sendAnalysisNotification: true,
+  sendConsumptionAlert: false,
+  waterDailyConsumptionLimit: 0,
+  mailToken: '',
+  monthlyAnalysisDate: DateTime.fromISO('0000-01-01T00:00:00.000Z', {
+    zone: 'utc',
+  }),
+  isProfileTypeCompleted: false,
+  isProfileEcogestureCompleted: false,
+  onboarding: {
+    isWelcomeSeen: true,
+  },
+  haveSeenEcogestureModal: false,
+  activateHalfHourDate: DateTime.fromISO('0000-01-01T00:00:00.000Z', {
+    zone: 'utc',
+  }),
+}
+
+export const profileSlice = createSlice({
+  name: 'profile',
+  initialState,
+  reducers: {},
+  extraReducers: builder => {
+    builder.addCase(updateProfile.fulfilled, (state, action) => {
+      Object.assign(state, action.payload)
+    })
+  },
+})
+
+/**
+ * Thunk updating profile in couch DB.
+ * If the profile has an update, dispatch it to the app
+ */
+export const updateProfile = createAsyncThunk<
+  Profile | void,
+  Partial<Profile>,
+  { dispatch: AppDispatch; state: AppStore; extra: { client: Client } }
+>('profile/updateProfile', async (profileUpdates, thunkAPI) => {
+  const client = thunkAPI.extra.client
+  const profileService = new ProfileService(client)
+  const updatedProfile = await profileService.updateProfile(profileUpdates)
+  if (updatedProfile) {
+    return updatedProfile
+  }
+})
diff --git a/src/store/store.ts b/src/store/store.ts
index 6e8579848..7f0397fd8 100644
--- a/src/store/store.ts
+++ b/src/store/store.ts
@@ -27,8 +27,7 @@ import {
 import { ChartActionTypes, chartSlice } from './chart/chart.slice'
 import { GlobalActionTypes, globalSlice } from './global/global.slice'
 import { ModalActionTypes, modalSlice } from './modal/modal.slice'
-import { ProfileActionTypes } from './profile/profile.actions'
-import { profileReducer } from './profile/profile.reducer'
+import { profileSlice } from './profile/profile.slice'
 import { ProfileEcogestureActionTypes } from './profileEcogesture/profileEcogesture.actions'
 import { profileEcogestureReducer } from './profileEcogesture/profileEcogesture.reducer'
 import {
@@ -67,7 +66,7 @@ const ecolyoReducer = combineReducers({
   chart: chartSlice.reducer,
   global: globalSlice.reducer,
   modal: modalSlice.reducer,
-  profile: profileReducer,
+  profile: profileSlice.reducer,
   profileEcogesture: profileEcogestureReducer,
   profileType: profileTypeSlice.reducer,
 })
@@ -84,6 +83,7 @@ const appActions = {
   ...modalSlice.actions,
   ...profileTypeSlice.actions,
   ...globalSlice.actions,
+  ...profileSlice.actions,
 }
 
 // TODO refactor types with AppActionsTypes = typeof appActions
@@ -93,14 +93,12 @@ export type AppActionsTypes =
   | ChartActionTypes
   | GlobalActionTypes
   | ModalActionTypes
-  | ProfileActionTypes
   | ProfileEcogestureActionTypes
   | ProfileTypeActionTypes
 
 const sentryReduxEnhancer = Sentry.createReduxEnhancer({})
 
 const configureStore = (client: Client, persistedState: any) => {
-  const middlewares = [thunkMiddleware.withExtraArgument({ client })]
   const composeEnhancers =
     composeWithDevTools({ trace: true, actionCreators: appActions }) || compose
 
@@ -111,8 +109,7 @@ const configureStore = (client: Client, persistedState: any) => {
       persistedState,
     }),
     composeEnhancers(
-      // eslint-disable-next-line prefer-spread
-      applyMiddleware.apply(null, middlewares),
+      applyMiddleware(thunkMiddleware.withExtraArgument({ client })),
       sentryReduxEnhancer
     )
   )
-- 
GitLab