diff --git a/src/components/EcogestureForm/EcogestureFormView.tsx b/src/components/EcogestureForm/EcogestureFormView.tsx index 20c2f971947237b5d9edd447919309ad21786a1e..59442fe97e1d4512e131ef07c8f88254b155d7b6 100644 --- a/src/components/EcogestureForm/EcogestureFormView.tsx +++ b/src/components/EcogestureForm/EcogestureFormView.tsx @@ -10,7 +10,7 @@ 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.slice' -import { newProfileEcogestureEntry } from 'store/profileEcogesture/profileEcogesture.actions' +import { newProfileEcogestureEntry } from 'store/profileEcogesture/profileEcogesture.slice' import EcogestureFormEquipment from './EcogestureFormEquipment/EcogestureFormEquipment' import EcogestureFormSingleChoice from './EcogestureFormSingleChoice/EcogestureFormSingleChoice' import EcogestureLaunchFormModal from './EcogestureLaunchFormModal/EcogestureLaunchFormModal' diff --git a/src/components/Splash/SplashRoot.tsx b/src/components/Splash/SplashRoot.tsx index 24e1f4444c6e8aa8a1d4f22585dcdd1647a6d7e8..a0cfaf2a2ef13610a2851382e68d886d11ec2c64 100644 --- a/src/components/Splash/SplashRoot.tsx +++ b/src/components/Splash/SplashRoot.tsx @@ -50,7 +50,7 @@ import { import { useAppDispatch } from 'store/hooks' import { openPartnersModal, setCustomPopup } from 'store/modal/modal.slice' import { updateProfile } from 'store/profile/profile.slice' -import { updateProfileEcogestureSuccess } from 'store/profileEcogesture/profileEcogesture.actions' +import { setProfileEcogesture } from 'store/profileEcogesture/profileEcogesture.slice' import { setProfileType } from 'store/profileType/profileType.slice' import { logDuration } from 'utils/duration' import logApp from 'utils/logger' @@ -250,7 +250,7 @@ const SplashRoot = ({ fadeTimer = 1000, children }: SplashRootProps) => { await loadProfileType(profileType) } if (profileEcogesture) { - dispatch(updateProfileEcogestureSuccess(profileEcogesture)) + dispatch(setProfileEcogesture(profileEcogesture)) } dispatch(toggleAnalysisNotification(!profile.haveSeenLastAnalysis)) } diff --git a/src/store/profileEcogesture/profileEcogesture.action.spec.ts b/src/store/profileEcogesture/profileEcogesture.action.spec.ts deleted file mode 100644 index 3881312f88b287297ab41a65ede1685b076235c8..0000000000000000000000000000000000000000 --- a/src/store/profileEcogesture/profileEcogesture.action.spec.ts +++ /dev/null @@ -1,39 +0,0 @@ -import { mockProfileEcogesture } from 'tests/__mocks__/profileEcogesture.mock' -import { createMockEcolyoStore } from 'tests/__mocks__/store' -import { - UPDATE_PROFILE_ECOGESTURE, - updateProfileEcogesture, -} from './profileEcogesture.actions' - -const mockUpdateProfileEcogesture = jest.fn() -const mockNewProfileEcogestureEntry = jest.fn() -jest.mock('services/profileEcogesture.service', () => { - return jest.fn(() => ({ - updateProfileEcogesture: mockUpdateProfileEcogesture, - newProfileEcogestureEntry: mockNewProfileEcogestureEntry, - })) -}) - -describe('profileEcogesture actions', () => { - const store = createMockEcolyoStore() - beforeEach(() => { - store.clearActions() - }) - it('should create an UPDATE_PROFILE_ECOGESTURE action when ecogestureProfile is updated', async () => { - mockUpdateProfileEcogesture.mockResolvedValueOnce(mockProfileEcogesture) - const expectedActions = [ - { - type: UPDATE_PROFILE_ECOGESTURE, - payload: mockProfileEcogesture, - }, - ] - await store.dispatch(updateProfileEcogesture(mockProfileEcogesture)) - expect(store.getActions()).toEqual(expectedActions) - }) - - it('should not create action when ProfileEcogesture is not updated', async () => { - mockUpdateProfileEcogesture.mockResolvedValueOnce(null) - await store.dispatch(updateProfileEcogesture(mockProfileEcogesture)) - expect(store.getActions()).toEqual([]) - }) -}) diff --git a/src/store/profileEcogesture/profileEcogesture.actions.ts b/src/store/profileEcogesture/profileEcogesture.actions.ts deleted file mode 100644 index 95cbb3cf730002f2db7dc4999e9235a736e02b8c..0000000000000000000000000000000000000000 --- a/src/store/profileEcogesture/profileEcogesture.actions.ts +++ /dev/null @@ -1,70 +0,0 @@ -import { Client } from 'cozy-client' -import { PROFILEECOGESTURE_DOCTYPE } from 'doctypes' -import { ProfileEcogesture } from 'models' -import { Dispatch } from 'react' -import ProfileEcogestureService from 'services/profileEcogesture.service' -import { AppStore, defaultAction } from 'store/store' - -// TODO never used ? -export const CREATE_NEW_PROFILE_ECOGESTURE = 'CREATE_NEW_PROFILE_ECOGESTURE' -export const UPDATE_PROFILE_ECOGESTURE = 'UPDATE_PROFILE_ECOGESTURE' - -export interface UpdateProfileEcogesture { - type: typeof UPDATE_PROFILE_ECOGESTURE - payload?: ProfileEcogesture -} - -// TODO never used ? -export interface CreateNewProfileEcogesture { - type: typeof CREATE_NEW_PROFILE_ECOGESTURE - payload?: ProfileEcogesture -} - -export type ProfileEcogestureActionTypes = - | UpdateProfileEcogesture - | CreateNewProfileEcogesture - | typeof defaultAction - -export function updateProfileEcogestureSuccess( - updatedProfileEcogesture: ProfileEcogesture -): UpdateProfileEcogesture { - return { - type: UPDATE_PROFILE_ECOGESTURE, - payload: updatedProfileEcogesture, - } -} - -export function updateProfileEcogesture( - updates: Partial<ProfileEcogesture> -): any { - return async ( - dispatch: Dispatch<UpdateProfileEcogesture>, - getState: () => AppStore, - { client }: { client: Client } - ) => { - const profileEcogestureService = new ProfileEcogestureService(client) - const updatedProfileEcogesture = - await profileEcogestureService.updateProfileEcogesture(updates) - if (updatedProfileEcogesture) { - dispatch(updateProfileEcogestureSuccess(updatedProfileEcogesture)) - } - } -} - -export function newProfileEcogestureEntry( - updates: Partial<ProfileEcogesture> -): any { - return async ( - dispatch: Dispatch<UpdateProfileEcogesture>, - getState: () => AppStore, - { client }: { client: Client } - ) => { - const { data: newProfileEcogesture } = await client.create( - PROFILEECOGESTURE_DOCTYPE, - updates - ) - if (newProfileEcogesture) { - dispatch(updateProfileEcogestureSuccess(newProfileEcogesture)) - } - } -} diff --git a/src/store/profileEcogesture/profileEcogesture.reducer.spec.ts b/src/store/profileEcogesture/profileEcogesture.reducer.spec.ts deleted file mode 100644 index bd6e460239b73ac44d98e1a2081d45891e9fb9ad..0000000000000000000000000000000000000000 --- a/src/store/profileEcogesture/profileEcogesture.reducer.spec.ts +++ /dev/null @@ -1,29 +0,0 @@ -import { defaultAction } from 'store/store' -import { - mockProfileEcogesture, - mockProfileEcogestureUpdated, -} from 'tests/__mocks__/profileEcogesture.mock' -import { UPDATE_PROFILE_ECOGESTURE } from './profileEcogesture.actions' -import { profileEcogestureReducer } from './profileEcogesture.reducer' - -describe('profileEcogesture reducer', () => { - it('should return the initial state', () => { - const state = profileEcogestureReducer(undefined, { ...defaultAction }) - expect(state).toEqual(mockProfileEcogesture) - }) - - it('should handle UPDATE_PROFILE_ECOGESTURE with payload', () => { - const state = profileEcogestureReducer(mockProfileEcogesture, { - type: UPDATE_PROFILE_ECOGESTURE, - payload: mockProfileEcogestureUpdated, - }) - expect(state).toEqual(mockProfileEcogestureUpdated) - }) - - it('should handle UPDATE_PROFILE_ECOGESTURE without payload', () => { - const state = profileEcogestureReducer(mockProfileEcogesture, { - type: UPDATE_PROFILE_ECOGESTURE, - }) - expect(state).toEqual(mockProfileEcogesture) - }) -}) diff --git a/src/store/profileEcogesture/profileEcogesture.reducer.ts b/src/store/profileEcogesture/profileEcogesture.reducer.ts deleted file mode 100644 index 9a089edb8243d151a0687b1921e2cd9a44a9f733..0000000000000000000000000000000000000000 --- a/src/store/profileEcogesture/profileEcogesture.reducer.ts +++ /dev/null @@ -1,33 +0,0 @@ -import { IndividualOrCollective, WarmingType } from 'enums' -import { ProfileEcogesture } from 'models' -import { Reducer } from 'redux' -import { - CREATE_NEW_PROFILE_ECOGESTURE, - ProfileEcogestureActionTypes, - UPDATE_PROFILE_ECOGESTURE, -} from './profileEcogesture.actions' - -const initialState: ProfileEcogesture = { - heating: IndividualOrCollective.INDIVIDUAL, - warmingFluid: WarmingType.ELECTRICITY, - hotWater: IndividualOrCollective.INDIVIDUAL, - equipments: [], -} - -export const profileEcogestureReducer: Reducer< - ProfileEcogesture, - ProfileEcogestureActionTypes -> = (state = initialState, action) => { - if (action.payload == undefined) return state - - switch (action.type) { - case UPDATE_PROFILE_ECOGESTURE: - case CREATE_NEW_PROFILE_ECOGESTURE: - return { - ...state, - ...action.payload, - } - default: - return state - } -} diff --git a/src/store/profileEcogesture/profileEcogesture.slice.spec.ts b/src/store/profileEcogesture/profileEcogesture.slice.spec.ts new file mode 100644 index 0000000000000000000000000000000000000000..290c69278fd2419c3f13b74c406c84e742c92115 --- /dev/null +++ b/src/store/profileEcogesture/profileEcogesture.slice.spec.ts @@ -0,0 +1,24 @@ +import { + mockProfileEcogesture, + mockProfileEcogestureUpdated, +} from 'tests/__mocks__/profileEcogesture.mock' +import { profileEcogestureSlice } from './profileEcogesture.slice' + +describe('profileEcogesture slice', () => { + it('should return the initial state', () => { + const initialState = profileEcogestureSlice.reducer(undefined, { + type: undefined, + }) + expect(initialState).toEqual(mockProfileEcogesture) + }) + + it('should handle setProfileEcogesture', () => { + const state = profileEcogestureSlice.reducer( + mockProfileEcogesture, + profileEcogestureSlice.actions.setProfileEcogesture( + mockProfileEcogestureUpdated + ) + ) + expect(state).toEqual(mockProfileEcogestureUpdated) + }) +}) diff --git a/src/store/profileEcogesture/profileEcogesture.slice.ts b/src/store/profileEcogesture/profileEcogesture.slice.ts new file mode 100644 index 0000000000000000000000000000000000000000..70fbc788b6b3900b96c88879826716d9e03e5fbf --- /dev/null +++ b/src/store/profileEcogesture/profileEcogesture.slice.ts @@ -0,0 +1,53 @@ +import { PayloadAction, createAsyncThunk, createSlice } from '@reduxjs/toolkit' +import { Client } from 'cozy-client' +import { PROFILEECOGESTURE_DOCTYPE } from 'doctypes' +import { IndividualOrCollective, WarmingType } from 'enums' +import { ProfileEcogesture } from 'models' +import { AppDispatch, AppStore } from 'store/store' + +const initialState: ProfileEcogesture = { + heating: IndividualOrCollective.INDIVIDUAL, + warmingFluid: WarmingType.ELECTRICITY, + hotWater: IndividualOrCollective.INDIVIDUAL, + equipments: [], +} + +type UpdateProfileEcogesture = PayloadAction<ProfileEcogesture> + +export type ProfileEcogestureActionTypes = UpdateProfileEcogesture + +export const profileEcogestureSlice = createSlice({ + name: 'profileEcogesture', + initialState, + reducers: { + setProfileEcogesture: (state, action: UpdateProfileEcogesture) => { + Object.assign(state, action.payload) + }, + }, + extraReducers: builder => { + builder.addCase(newProfileEcogestureEntry.fulfilled, (state, action) => { + Object.assign(state, action.payload) + }) + }, +}) + +export const { setProfileEcogesture } = profileEcogestureSlice.actions + +/** + * Thunk creating a new profile ecogesture in couch DB. + * Then dispatch it to the app + */ +export const newProfileEcogestureEntry = createAsyncThunk< + ProfileEcogesture | void, + Partial<ProfileEcogesture>, + { dispatch: AppDispatch; state: AppStore; extra: { client: Client } } +>('profileEcogesture/newProfileEcogesture', async (updates, thunkAPI) => { + const client = thunkAPI.extra.client + const { data: newProfileEcogesture } = await client.create( + PROFILEECOGESTURE_DOCTYPE, + updates + ) + if (newProfileEcogesture) { + return newProfileEcogesture + } +}) diff --git a/src/store/store.ts b/src/store/store.ts index 7f0397fd81b1b4aee7af015ac91816ab5bddc04b..451808836b482523ec9819d76e5320a979975b2e 100644 --- a/src/store/store.ts +++ b/src/store/store.ts @@ -10,13 +10,7 @@ import { ProfileEcogesture, ProfileType, } from 'models' -import { - Store, - applyMiddleware, - combineReducers, - compose, - createStore, -} from 'redux' +import { applyMiddleware, combineReducers, compose, createStore } from 'redux' import { composeWithDevTools } from 'redux-devtools-extension' import thunkMiddleware from 'redux-thunk' import { AnalysisActionTypes, analysisSlice } from './analysis/analysis.slice' @@ -28,8 +22,10 @@ import { ChartActionTypes, chartSlice } from './chart/chart.slice' import { GlobalActionTypes, globalSlice } from './global/global.slice' import { ModalActionTypes, modalSlice } from './modal/modal.slice' import { profileSlice } from './profile/profile.slice' -import { ProfileEcogestureActionTypes } from './profileEcogesture/profileEcogesture.actions' -import { profileEcogestureReducer } from './profileEcogesture/profileEcogesture.reducer' +import { + ProfileEcogestureActionTypes, + profileEcogestureSlice, +} from './profileEcogesture/profileEcogesture.slice' import { ProfileTypeActionTypes, profileTypeSlice, @@ -67,7 +63,7 @@ const ecolyoReducer = combineReducers({ global: globalSlice.reducer, modal: modalSlice.reducer, profile: profileSlice.reducer, - profileEcogesture: profileEcogestureReducer, + profileEcogesture: profileEcogestureSlice.reducer, profileType: profileTypeSlice.reducer, }) @@ -80,10 +76,11 @@ const appActions = { ...analysisSlice.actions, ...challengeSlice.actions, ...chartSlice.actions, - ...modalSlice.actions, - ...profileTypeSlice.actions, ...globalSlice.actions, + ...modalSlice.actions, + ...profileEcogestureSlice.actions, ...profileSlice.actions, + ...profileTypeSlice.actions, } // TODO refactor types with AppActionsTypes = typeof appActions @@ -102,7 +99,7 @@ const configureStore = (client: Client, persistedState: any) => { const composeEnhancers = composeWithDevTools({ trace: true, actionCreators: appActions }) || compose - const store: Store<AppStore, AppActionsTypes> = createStore( + const store = createStore( combineReducers({ ecolyo: ecolyoReducer, cozy: client.reducer(),