From 587e59fe7634c0378e8d0621f9eb3902bbc6ce87 Mon Sep 17 00:00:00 2001
From: Bastien DUMONT <bdumont@grandlyon.com>
Date: Mon, 14 Oct 2024 06:55:14 +0000
Subject: [PATCH] feat(forms): re-use user values

---
 .../ExpiredConsentModal.spec.tsx              |   2 +-
 .../ExpiredConsentModal.tsx                   |  28 +----
 .../GRDFConnect/GrdfConnectView.tsx           |  69 ++++++++----
 .../SGEConnect/SgeConnectView.spec.tsx        |  32 +++---
 .../Connection/SGEConnect/SgeConnectView.tsx  | 105 +++++++++++-------
 .../SGEConnect/StepAddress.spec.tsx           |  18 +--
 .../SGEConnect/StepConsent.spec.tsx           |  14 +--
 .../SGEConnect/StepIdentityAndPdl.spec.tsx    |  19 +---
 .../__snapshots__/StepAddress.spec.tsx.snap   |   8 +-
 src/components/Connection/useForm.tsx         |  67 +++++++++++
 .../ConnectionResult/ConnectionResult.tsx     |  27 +----
 src/doctypes/com-grandlyon-ecolyo-form.ts     |   1 +
 src/doctypes/index.ts                         |   7 ++
 src/models/global.model.ts                    |   2 -
 src/store/global/global.slice.spec.ts         |  24 ----
 src/store/global/global.slice.ts              |  17 ---
 tests/__mocks__/forms.mock.ts                 |  14 +++
 tests/__mocks__/store/global.state.mock.ts    |  12 --
 18 files changed, 239 insertions(+), 227 deletions(-)
 create mode 100644 src/components/Connection/useForm.tsx
 create mode 100644 src/doctypes/com-grandlyon-ecolyo-form.ts
 create mode 100644 tests/__mocks__/forms.mock.ts

diff --git a/src/components/Connection/ExpiredConsentModal/ExpiredConsentModal.spec.tsx b/src/components/Connection/ExpiredConsentModal/ExpiredConsentModal.spec.tsx
index ced72db8d..c50602afd 100644
--- a/src/components/Connection/ExpiredConsentModal/ExpiredConsentModal.spec.tsx
+++ b/src/components/Connection/ExpiredConsentModal/ExpiredConsentModal.spec.tsx
@@ -68,7 +68,7 @@ describe('ExpiredConsentModal component', () => {
     await act(async () => {
       await userEvent.click(screen.getByText('consent_outdated.yes'))
     })
-    expect(mockAppDispatch).toHaveBeenCalledTimes(2)
+    expect(mockAppDispatch).toHaveBeenCalledTimes(1)
     expect(mockedNavigate).toHaveBeenCalledTimes(1)
   })
   it('should click on close modal', async () => {
diff --git a/src/components/Connection/ExpiredConsentModal/ExpiredConsentModal.tsx b/src/components/Connection/ExpiredConsentModal/ExpiredConsentModal.tsx
index 8959ba88e..b01fcb166 100644
--- a/src/components/Connection/ExpiredConsentModal/ExpiredConsentModal.tsx
+++ b/src/components/Connection/ExpiredConsentModal/ExpiredConsentModal.tsx
@@ -7,14 +7,10 @@ import StyledIcon from 'components/CommonKit/Icon/StyledIcon'
 import StyledIconButton from 'components/CommonKit/IconButton/StyledIconButton'
 import { useI18n } from 'cozy-ui/transpiled/react/providers/I18n'
 import { FluidType } from 'enums'
-import { AccountSgeData } from 'models'
 import React, { useCallback } from 'react'
 import { useNavigate } from 'react-router-dom'
-import {
-  setShouldRefreshConsent,
-  updateSgeStore,
-} from 'store/global/global.slice'
-import { useAppDispatch, useAppSelector } from 'store/hooks'
+import { setShouldRefreshConsent } from 'store/global/global.slice'
+import { useAppDispatch } from 'store/hooks'
 import { getFluidName } from 'utils/utils'
 import './expiredConsentModal.scss'
 
@@ -34,26 +30,8 @@ const ExpiredConsentModal = ({
   const { t } = useI18n()
   const navigate = useNavigate()
   const dispatch = useAppDispatch()
-  const { fluidStatus } = useAppSelector(state => state.ecolyo.global)
   const launchUpdateConsent = useCallback(() => {
     if (fluidType === FluidType.ELECTRICITY) {
-      const accountData = fluidStatus[FluidType.ELECTRICITY].connection.account
-        ?.auth as AccountSgeData
-      // store the previous account data since the onDelete will remove account from DB
-      dispatch(
-        updateSgeStore({
-          currentStep: 0,
-          firstName: accountData.firstname,
-          lastName: accountData.lastname,
-          pdl: parseInt(accountData.pointId),
-          address: accountData.address,
-          zipCode: parseInt(accountData.postalCode),
-          city: accountData.city,
-          dataConsent: true,
-          pdlConfirm: true,
-          shouldLaunchAccount: true,
-        })
-      )
       dispatch(setShouldRefreshConsent(true))
       toggleModal()
       navigate(`/consumption/${FluidType[fluidType].toLocaleLowerCase()}`)
@@ -62,7 +40,7 @@ const ExpiredConsentModal = ({
       toggleModal()
       navigate(`/connect/${FluidType[fluidType].toLocaleLowerCase()}`)
     }
-  }, [dispatch, fluidStatus, fluidType, navigate, toggleModal])
+  }, [dispatch, fluidType, navigate, toggleModal])
 
   return (
     <Dialog
diff --git a/src/components/Connection/GRDFConnect/GrdfConnectView.tsx b/src/components/Connection/GRDFConnect/GrdfConnectView.tsx
index 9661de4e1..814ca9007 100644
--- a/src/components/Connection/GRDFConnect/GrdfConnectView.tsx
+++ b/src/components/Connection/GRDFConnect/GrdfConnectView.tsx
@@ -5,12 +5,15 @@ import CozyBar from 'components/Header/CozyBar'
 import Header from 'components/Header/Header'
 import useKonnectorAuth from 'components/Hooks/useKonnectorAuth'
 import useUserInstanceSettings from 'components/Hooks/useUserInstanceSettings'
+import { useClient } from 'cozy-client'
+import { FORM_DOCTYPE } from 'doctypes'
 import { FluidType } from 'enums'
 import { AccountGRDFData } from 'models'
 import React, { useCallback, useEffect, useRef, useState } from 'react'
 import { useNavigate } from 'react-router-dom'
 import { useAppSelector } from 'store/hooks'
 import '../connection.scss'
+import { createInitialGrdfState, useFormData } from '../useForm'
 import StepConsent from './StepConsent'
 import { StepIdentity } from './StepIdentity'
 
@@ -18,11 +21,14 @@ export enum GrdfStep {
   Identity,
   Consent,
 }
+
 /**
  * http://ecolyo.cozy.tools:8080/#/connect/gas
  */
 export const GrdfConnectView = () => {
+  const client = useClient()
   const navigate = useNavigate()
+  const { formData } = useFormData()
   const { instanceSettings } = useUserInstanceSettings()
   const { fluidStatus } = useAppSelector(state => state.ecolyo.global)
   const currentFluidStatus = fluidStatus[FluidType.GAS]
@@ -30,13 +36,9 @@ export const GrdfConnectView = () => {
 
   const [launchConnection, setLaunchConnection] = useState(false)
   const [currentStep, setCurrentStep] = useState<GrdfStep>(GrdfStep.Identity)
-  const [formData, setFormData] = useState<AccountGRDFData>({
-    lastname: '',
-    firstname: '',
-    email: '',
-    postalCode: '',
-    pce: '',
-  })
+  const [grdfState, setGrdfState] = useState<AccountGRDFData>(
+    createInitialGrdfState()
+  )
   const [formConsent, setFormConsent] = useState({
     dataConsent: false,
     pceConfirm: false,
@@ -48,23 +50,27 @@ export const GrdfConnectView = () => {
   }
 
   const [connect, update] = useKonnectorAuth(FluidType.GAS, {
-    grdfAuthData: formData,
+    grdfAuthData: grdfState,
   })
 
   useEffect(() => {
-    setFormData(prev => ({ ...prev, email: instanceSettings.email ?? '' }))
-  }, [instanceSettings])
+    setGrdfState(prev => ({
+      ...prev,
+      ...createInitialGrdfState(formData),
+      email: instanceSettings.email ?? '',
+    }))
+  }, [instanceSettings, formData])
 
   useEffect(() => {
     async function launchConnect() {
       if (launchConnection) {
+        setLaunchConnection(false)
         if (!account) {
           await connect()
         } else {
           await update()
         }
 
-        setLaunchConnection(false)
         navigate('/consumption/gas')
       }
     }
@@ -74,11 +80,11 @@ export const GrdfConnectView = () => {
   const isNextValid = useCallback(() => {
     if (currentStep === GrdfStep.Identity) {
       return (
-        formData.firstname !== '' &&
-        formData.lastname !== '' &&
-        formData.postalCode !== '' &&
-        formData.email.includes('@') &&
-        formData.pce.length === 14
+        grdfState.firstname !== '' &&
+        grdfState.lastname !== '' &&
+        grdfState.postalCode !== '' &&
+        grdfState.email.includes('@') &&
+        grdfState.pce.length === 14
       )
     } else if (currentStep === GrdfStep.Consent) {
       return formConsent.dataConsent && formConsent.pceConfirm
@@ -88,23 +94,40 @@ export const GrdfConnectView = () => {
     currentStep,
     formConsent.dataConsent,
     formConsent.pceConfirm,
-    formData.email,
-    formData.firstname,
-    formData.lastname,
-    formData.pce,
-    formData.postalCode,
+    grdfState.email,
+    grdfState.firstname,
+    grdfState.lastname,
+    grdfState.pce,
+    grdfState.postalCode,
   ])
 
   const handleNext = useCallback(() => {
     if (!isNextValid()) return
     if (currentStep < GrdfStep.Consent) {
       setCurrentStep(prev => prev + 1)
+      client.save({
+        ...formData,
+        _type: FORM_DOCTYPE,
+        firstName: grdfState.firstname,
+        lastName: grdfState.lastname,
+        pce: grdfState.pce,
+        zipCode: grdfState.postalCode,
+      })
     }
     if (currentStep === GrdfStep.Consent) {
       setLaunchConnection(true)
     }
     focusMainContent()
-  }, [currentStep, isNextValid])
+  }, [
+    client,
+    currentStep,
+    formData,
+    grdfState.firstname,
+    grdfState.lastname,
+    grdfState.pce,
+    grdfState.postalCode,
+    isNextValid,
+  ])
 
   const handlePrev = () => {
     setCurrentStep(prev => prev - 1)
@@ -113,7 +136,7 @@ export const GrdfConnectView = () => {
 
   const renderStep = (step: GrdfStep) => {
     if (step === GrdfStep.Identity) {
-      return <StepIdentity formData={formData} setFormData={setFormData} />
+      return <StepIdentity formData={grdfState} setFormData={setGrdfState} />
     } else {
       return (
         <StepConsent
diff --git a/src/components/Connection/SGEConnect/SgeConnectView.spec.tsx b/src/components/Connection/SGEConnect/SgeConnectView.spec.tsx
index 3941573aa..ad4f5fc21 100644
--- a/src/components/Connection/SGEConnect/SgeConnectView.spec.tsx
+++ b/src/components/Connection/SGEConnect/SgeConnectView.spec.tsx
@@ -1,4 +1,5 @@
 import { render, screen } from '@testing-library/react'
+import { SgeStore } from 'models'
 import React from 'react'
 import { Provider } from 'react-redux'
 import { BrowserRouter } from 'react-router-dom'
@@ -18,6 +19,23 @@ jest.mock('components/Hooks/useKonnectorAuth', () =>
   jest.fn(() => [mockConnect, mockUpdate])
 )
 
+// mock sge state with shouldLaunchAccount set to true
+jest.mock('components/Connection/useForm', () => ({
+  useFormData: jest.fn().mockReturnValue({ formData: {} }),
+  createInitialSgeState: jest.fn<SgeStore, []>().mockReturnValue({
+    address: '',
+    lastName: '',
+    firstName: '',
+    pdl: 0,
+    zipCode: 0,
+    city: '',
+    currentStep: 0,
+    dataConsent: false,
+    shouldLaunchAccount: true,
+    pdlConfirm: false,
+  }),
+}))
+
 describe('SgeConnectView component', () => {
   beforeEach(() => {
     jest.clearAllMocks()
@@ -57,16 +75,6 @@ describe('SgeConnectView component', () => {
 
   describe('should test methods from useKonnectorAuth hook', () => {
     it('should launch account and trigger creation process', () => {
-      const store = createMockEcolyoStore({
-        global: {
-          ...mockGlobalState,
-          sgeConnect: {
-            ...mockGlobalState.sgeConnect,
-            shouldLaunchAccount: true,
-          },
-        },
-      })
-
       render(
         <Provider store={store}>
           <SgeConnectView />
@@ -79,10 +87,6 @@ describe('SgeConnectView component', () => {
         global: {
           ...mockGlobalState,
           fluidStatus: [SgeStatusWithAccount],
-          sgeConnect: {
-            ...mockGlobalState.sgeConnect,
-            shouldLaunchAccount: true,
-          },
         },
       })
       render(
diff --git a/src/components/Connection/SGEConnect/SgeConnectView.tsx b/src/components/Connection/SGEConnect/SgeConnectView.tsx
index 8f0a00d20..0f179a07b 100644
--- a/src/components/Connection/SGEConnect/SgeConnectView.tsx
+++ b/src/components/Connection/SGEConnect/SgeConnectView.tsx
@@ -4,16 +4,16 @@ import Content from 'components/Content/Content'
 import CozyBar from 'components/Header/CozyBar'
 import Header from 'components/Header/Header'
 import useKonnectorAuth from 'components/Hooks/useKonnectorAuth'
+import { useClient } from 'cozy-client'
+import { FORM_DOCTYPE } from 'doctypes'
 import { FluidType, SgeStep } from 'enums'
 import { SgeStore } from 'models'
 import React, { useCallback, useEffect, useRef, useState } from 'react'
 import { useNavigate } from 'react-router-dom'
-import {
-  setShouldRefreshConsent,
-  updateSgeStore,
-} from 'store/global/global.slice'
+import { setShouldRefreshConsent } from 'store/global/global.slice'
 import { useAppDispatch, useAppSelector } from 'store/hooks'
 import '../connection.scss'
+import { createInitialSgeState, useFormData } from '../useForm'
 import StepAddress from './StepAddress'
 import StepConsent from './StepConsent'
 import StepIdentityAndPdl from './StepIdentityAndPdl'
@@ -32,11 +32,12 @@ export type SGEKeysForm =
  * http://ecolyo.cozy.tools:8080/#/connect/electricity
  */
 const SgeConnectView = () => {
+  const client = useClient()
   const navigate = useNavigate()
   const dispatch = useAppDispatch()
-  const { sgeConnect } = useAppSelector(state => state.ecolyo.global)
+  const { formData } = useFormData()
   const [isLoading, setIsLoading] = useState(false)
-  const [currentSgeState, setCurrentSgeState] = useState<SgeStore>(sgeConnect)
+  const [sgeState, setSgeState] = useState<SgeStore>(createInitialSgeState())
   const [currentStep, setCurrentStep] = useState<SgeStep>(
     SgeStep.IdentityAndPDL
   )
@@ -50,13 +51,25 @@ const SgeConnectView = () => {
   }
 
   const [connect, update] = useKonnectorAuth(FluidType.ELECTRICITY, {
-    sgeAuthData: sgeConnect,
+    sgeAuthData: sgeState,
   })
 
+  useEffect(
+    function applyFormData() {
+      if (formData) {
+        setSgeState(prevState => ({
+          ...prevState,
+          ...createInitialSgeState(formData),
+        }))
+      }
+    },
+    [formData]
+  )
+
   useEffect(() => {
     async function launchConnect() {
-      if (sgeConnect.shouldLaunchAccount) {
-        dispatch(updateSgeStore({ ...sgeConnect, shouldLaunchAccount: false }))
+      if (sgeState.shouldLaunchAccount) {
+        setSgeState({ ...sgeState, shouldLaunchAccount: false })
         dispatch(setShouldRefreshConsent(false))
         if (!account) {
           await connect()
@@ -67,66 +80,74 @@ const SgeConnectView = () => {
       }
     }
     launchConnect()
-  }, [account, connect, dispatch, navigate, sgeConnect, update])
+  }, [account, connect, sgeState, dispatch, navigate, update])
 
   const isNextValid = useCallback(() => {
     switch (currentStep) {
       case SgeStep.IdentityAndPDL:
         return (
-          currentSgeState.firstName !== '' &&
-          currentSgeState.lastName !== '' &&
-          currentSgeState.pdl !== null &&
-          currentSgeState.pdl.toString().length === 14
+          sgeState.firstName !== '' &&
+          sgeState.lastName !== '' &&
+          sgeState.pdl !== null &&
+          sgeState.pdl.toString().length === 14
         )
       case SgeStep.Address:
         return (
-          currentSgeState.address !== '' &&
-          currentSgeState.city !== '' &&
-          currentSgeState.zipCode !== null &&
-          currentSgeState.zipCode.toString().length === 5
+          sgeState.address !== '' &&
+          sgeState.city !== '' &&
+          sgeState.zipCode !== null &&
+          sgeState.zipCode.toString().length === 5
         )
       case SgeStep.Consent:
-        return currentSgeState.dataConsent && currentSgeState.pdlConfirm
+        return sgeState.dataConsent && sgeState.pdlConfirm
       default:
         return false
     }
   }, [
-    currentSgeState.address,
-    currentSgeState.city,
-    currentSgeState.dataConsent,
-    currentSgeState.firstName,
-    currentSgeState.lastName,
-    currentSgeState.pdl,
-    currentSgeState.pdlConfirm,
-    currentSgeState.zipCode,
+    sgeState.address,
+    sgeState.city,
+    sgeState.dataConsent,
+    sgeState.firstName,
+    sgeState.lastName,
+    sgeState.pdl,
+    sgeState.pdlConfirm,
+    sgeState.zipCode,
     currentStep,
   ])
 
   const handleNext = useCallback(() => {
     if (currentStep < SgeStep.Consent) {
       setCurrentStep(prev => prev + 1)
-      dispatch(updateSgeStore(currentSgeState))
+
+      client.save({
+        ...formData,
+        _type: FORM_DOCTYPE,
+        firstName: sgeState.firstName,
+        lastName: sgeState.lastName,
+        pdl: sgeState.pdl,
+        address: sgeState.address,
+        city: sgeState.city,
+        zipCode: sgeState.zipCode,
+      })
     }
     if (currentStep === SgeStep.Consent && !isLoading) {
       setIsLoading(true)
       const updatedState = {
-        ...currentSgeState,
-        city: currentSgeState.city.trim(),
+        ...sgeState,
+        city: sgeState.city.trim(),
         shouldLaunchAccount: true,
       }
-      setCurrentSgeState(updatedState)
-      dispatch(updateSgeStore(updatedState))
+      setSgeState(updatedState)
     }
     focusMainContent()
-  }, [currentStep, isLoading, dispatch, currentSgeState])
+  }, [currentStep, isLoading, client, formData, sgeState])
 
   const handlePrev = useCallback(() => {
     if (currentStep !== SgeStep.IdentityAndPDL) {
       setCurrentStep(prev => prev - 1)
     }
-    dispatch(updateSgeStore(currentSgeState))
     focusMainContent()
-  }, [currentSgeState, currentStep, dispatch])
+  }, [currentStep])
 
   const onChange = useCallback(
     (
@@ -137,25 +158,23 @@ const SgeConnectView = () => {
       if (maxLength && value.toString().length > maxLength) return
 
       const updatedState = {
-        ...currentSgeState,
+        ...sgeState,
         [key]: value,
       }
-      setCurrentSgeState(updatedState)
+      setSgeState(updatedState)
     },
-    [currentSgeState]
+    [sgeState]
   )
 
   const renderStep = (step: SgeStep) => {
     switch (step) {
       case SgeStep.Address:
-        return <StepAddress sgeState={currentSgeState} onChange={onChange} />
+        return <StepAddress sgeState={sgeState} onChange={onChange} />
       case SgeStep.Consent:
-        return <StepConsent sgeState={currentSgeState} onChange={onChange} />
+        return <StepConsent sgeState={sgeState} onChange={onChange} />
       case SgeStep.IdentityAndPDL:
       default:
-        return (
-          <StepIdentityAndPdl sgeState={currentSgeState} onChange={onChange} />
-        )
+        return <StepIdentityAndPdl sgeState={sgeState} onChange={onChange} />
     }
   }
 
diff --git a/src/components/Connection/SGEConnect/StepAddress.spec.tsx b/src/components/Connection/SGEConnect/StepAddress.spec.tsx
index e7e1326c2..8ba9d9443 100644
--- a/src/components/Connection/SGEConnect/StepAddress.spec.tsx
+++ b/src/components/Connection/SGEConnect/StepAddress.spec.tsx
@@ -1,7 +1,7 @@
 import { act, render, screen } from '@testing-library/react'
 import { userEvent } from '@testing-library/user-event'
 import React from 'react'
-import { mockGlobalState } from 'tests/__mocks__/store'
+import { mockSgeState } from 'tests/__mocks__/forms.mock'
 import StepAddress from './StepAddress'
 
 const mockHandleChange = jest.fn()
@@ -9,10 +9,7 @@ const mockHandleChange = jest.fn()
 describe('StepAddress component', () => {
   it('should be rendered correctly', () => {
     const { container } = render(
-      <StepAddress
-        sgeState={mockGlobalState.sgeConnect}
-        onChange={mockHandleChange}
-      />
+      <StepAddress sgeState={mockSgeState} onChange={mockHandleChange} />
     )
     expect(container).toMatchSnapshot()
   })
@@ -20,10 +17,7 @@ describe('StepAddress component', () => {
   describe('should change inputs', () => {
     beforeEach(() => {
       render(
-        <StepAddress
-          sgeState={mockGlobalState.sgeConnect}
-          onChange={mockHandleChange}
-        />
+        <StepAddress sgeState={mockSgeState} onChange={mockHandleChange} />
       )
     })
     it('should change address value', async () => {
@@ -40,9 +34,9 @@ describe('StepAddress component', () => {
         name: 'auth.enedissgegrandlyon.zipCode',
       })
       await act(async () => {
-        await userEvent.type(input, '0')
+        await userEvent.type(input, '1')
       })
-      expect(mockHandleChange).toHaveBeenCalledWith('zipCode', '0', 5)
+      expect(mockHandleChange).toHaveBeenCalledWith('zipCode', '1', 5)
     })
 
     it('should change city value', async () => {
@@ -58,7 +52,7 @@ describe('StepAddress component', () => {
   it('should have an existing zipCode value', () => {
     render(
       <StepAddress
-        sgeState={{ ...mockGlobalState.sgeConnect, zipCode: 69200 }}
+        sgeState={{ ...mockSgeState, zipCode: 69200 }}
         onChange={mockHandleChange}
       />
     )
diff --git a/src/components/Connection/SGEConnect/StepConsent.spec.tsx b/src/components/Connection/SGEConnect/StepConsent.spec.tsx
index 642ebccb3..72fb90150 100644
--- a/src/components/Connection/SGEConnect/StepConsent.spec.tsx
+++ b/src/components/Connection/SGEConnect/StepConsent.spec.tsx
@@ -1,7 +1,7 @@
 import { render, screen } from '@testing-library/react'
 import { userEvent } from '@testing-library/user-event'
 import React from 'react'
-import { mockGlobalState } from 'tests/__mocks__/store'
+import { mockSgeState } from 'tests/__mocks__/forms.mock'
 import StepConsent from './StepConsent'
 
 const mockHandleChange = jest.fn()
@@ -9,21 +9,13 @@ const mockHandleChange = jest.fn()
 describe('StepConsent component', () => {
   it('should be rendered correctly', () => {
     const { container } = render(
-      <StepConsent
-        sgeState={mockGlobalState.sgeConnect}
-        onChange={mockHandleChange}
-      />
+      <StepConsent sgeState={mockSgeState} onChange={mockHandleChange} />
     )
     expect(container).toMatchSnapshot()
   })
 
   it('should change dataConsent and pdlConfirm value', async () => {
-    render(
-      <StepConsent
-        sgeState={mockGlobalState.sgeConnect}
-        onChange={mockHandleChange}
-      />
-    )
+    render(<StepConsent sgeState={mockSgeState} onChange={mockHandleChange} />)
     const consentCheckbox = screen.getByLabelText(
       'auth.enedissgegrandlyon.consentCheck1'
     )
diff --git a/src/components/Connection/SGEConnect/StepIdentityAndPdl.spec.tsx b/src/components/Connection/SGEConnect/StepIdentityAndPdl.spec.tsx
index 42846fe60..db0bb7e1d 100644
--- a/src/components/Connection/SGEConnect/StepIdentityAndPdl.spec.tsx
+++ b/src/components/Connection/SGEConnect/StepIdentityAndPdl.spec.tsx
@@ -1,7 +1,7 @@
 import { act, render, screen } from '@testing-library/react'
 import userEvent from '@testing-library/user-event'
 import React from 'react'
-import { mockGlobalState } from 'tests/__mocks__/store'
+import { mockSgeState } from 'tests/__mocks__/forms.mock'
 import StepIdentityAndPdl from './StepIdentityAndPdl'
 
 const mockHandleChange = jest.fn()
@@ -9,20 +9,14 @@ const mockHandleChange = jest.fn()
 describe('StepIdentityAndPdl component', () => {
   it('should be rendered correctly', () => {
     const { container } = render(
-      <StepIdentityAndPdl
-        sgeState={mockGlobalState.sgeConnect}
-        onChange={mockHandleChange}
-      />
+      <StepIdentityAndPdl sgeState={mockSgeState} onChange={mockHandleChange} />
     )
     expect(container).toMatchSnapshot()
   })
 
   it('should be able to change fields', async () => {
     render(
-      <StepIdentityAndPdl
-        sgeState={mockGlobalState.sgeConnect}
-        onChange={mockHandleChange}
-      />
+      <StepIdentityAndPdl sgeState={mockSgeState} onChange={mockHandleChange} />
     )
     const firstNameInput = screen.getByRole('textbox', {
       name: 'auth.enedissgegrandlyon.firstName',
@@ -51,10 +45,7 @@ describe('StepIdentityAndPdl component', () => {
 
   it('should open hint modal', async () => {
     render(
-      <StepIdentityAndPdl
-        sgeState={mockGlobalState.sgeConnect}
-        onChange={mockHandleChange}
-      />
+      <StepIdentityAndPdl sgeState={mockSgeState} onChange={mockHandleChange} />
     )
     await act(async () => {
       await userEvent.click(
@@ -68,7 +59,7 @@ describe('StepIdentityAndPdl component', () => {
     render(
       <StepIdentityAndPdl
         sgeState={{
-          ...mockGlobalState.sgeConnect,
+          ...mockSgeState,
           pdl: 11111111111111,
           firstName: 'Zack',
           lastName: 'Ichan',
diff --git a/src/components/Connection/SGEConnect/__snapshots__/StepAddress.spec.tsx.snap b/src/components/Connection/SGEConnect/__snapshots__/StepAddress.spec.tsx.snap
index 1e960609d..310b53b3a 100644
--- a/src/components/Connection/SGEConnect/__snapshots__/StepAddress.spec.tsx.snap
+++ b/src/components/Connection/SGEConnect/__snapshots__/StepAddress.spec.tsx.snap
@@ -58,8 +58,8 @@ exports[`StepAddress component should be rendered correctly 1`] = `
       class="MuiFormControl-root MuiTextField-root"
     >
       <label
-        class="MuiFormLabel-root MuiInputLabel-root MuiInputLabel-formControl MuiInputLabel-animated MuiInputLabel-outlined Mui-required Mui-required"
-        data-shrink="false"
+        class="MuiFormLabel-root MuiInputLabel-root MuiInputLabel-formControl MuiInputLabel-animated MuiInputLabel-shrink MuiInputLabel-outlined MuiFormLabel-filled Mui-required Mui-required"
+        data-shrink="true"
         for="zipCode"
         id="zipCode-label"
       >
@@ -81,14 +81,14 @@ exports[`StepAddress component should be rendered correctly 1`] = `
           id="zipCode"
           required=""
           type="number"
-          value=""
+          value="0"
         />
         <fieldset
           aria-hidden="true"
           class="PrivateNotchedOutline-root-1 MuiOutlinedInput-notchedOutline"
         >
           <legend
-            class="PrivateNotchedOutline-legendLabelled-3"
+            class="PrivateNotchedOutline-legendLabelled-3 PrivateNotchedOutline-legendNotched-4"
           >
             <span>
               auth.enedissgegrandlyon.zipCode
diff --git a/src/components/Connection/useForm.tsx b/src/components/Connection/useForm.tsx
new file mode 100644
index 000000000..1bf3be720
--- /dev/null
+++ b/src/components/Connection/useForm.tsx
@@ -0,0 +1,67 @@
+import { Q, QueryDefinition, useQuery } from 'cozy-client'
+import { QueryOptions } from 'cozy-client/types/types'
+import { FORM_DOCTYPE } from 'doctypes'
+import { SgeStep } from 'enums'
+import { AccountGRDFData, SgeStore } from 'models'
+
+export type QueryParams = (arg?: any) => {
+  definition: QueryDefinition
+  options: QueryOptions
+}
+
+interface FormData {
+  firstName: string
+  lastName: string
+  pdl: string
+  pce: string
+  zipCode: string
+  city: string
+  address: string
+}
+
+const getFormData: QueryParams = () => ({
+  definition: Q(FORM_DOCTYPE),
+  options: { as: 'form' },
+})
+
+/** Returns the form data from the form doctype */
+export const useFormData = () => {
+  const { definition, options } = getFormData()
+  // eslint-disable-next-line prefer-const
+  let { data, lastError, fetchStatus } = useQuery(definition, options)
+
+  if (data === null) {
+    data = []
+  }
+
+  const formData = data as [FormData]
+
+  return {
+    formData: formData[0],
+    isFetching: fetchStatus === 'loading',
+    lastError,
+  }
+}
+
+export const createInitialSgeState = (formData?: FormData): SgeStore => ({
+  address: formData?.address ?? '',
+  lastName: formData?.lastName ?? '',
+  firstName: formData?.firstName ?? '',
+  pdl: formData?.pdl ? parseInt(formData.pdl) : null,
+  zipCode: formData?.zipCode ? parseInt(formData.zipCode) : null,
+  city: formData?.city ?? '',
+  currentStep: SgeStep.Address,
+  dataConsent: false,
+  pdlConfirm: false,
+  shouldLaunchAccount: false,
+})
+
+export const createInitialGrdfState = (
+  formData?: FormData
+): AccountGRDFData => ({
+  lastname: formData?.lastName ?? '',
+  firstname: formData?.firstName ?? '',
+  pce: formData?.pce ?? '',
+  postalCode: formData?.zipCode ?? '',
+  email: '',
+})
diff --git a/src/components/Konnector/ConnectionResult/ConnectionResult.tsx b/src/components/Konnector/ConnectionResult/ConnectionResult.tsx
index d0e41143b..03db452ff 100644
--- a/src/components/Konnector/ConnectionResult/ConnectionResult.tsx
+++ b/src/components/Konnector/ConnectionResult/ConnectionResult.tsx
@@ -6,7 +6,7 @@ import { useClient } from 'cozy-client'
 import { useI18n } from 'cozy-ui/transpiled/react/providers/I18n'
 import { FluidType, KonnectorUpdate } from 'enums'
 import { DateTime } from 'luxon'
-import { AccountSgeData, FluidConnection, FluidStatus } from 'models'
+import { FluidConnection, FluidStatus } from 'models'
 import React, { useCallback, useEffect, useState } from 'react'
 import AccountService from 'services/account.service'
 import DateChartService from 'services/dateChart.service'
@@ -14,7 +14,6 @@ import TriggerService from 'services/triggers.service'
 import {
   setShouldRefreshConsent,
   updateFluidConnection,
-  updateSgeStore,
 } from 'store/global/global.slice'
 import { useAppDispatch, useAppSelector } from 'store/hooks'
 import { getKonnectorUpdateError } from 'utils/utils'
@@ -108,33 +107,11 @@ const ConnectionResult = ({
 
   const handleRefreshConsent = useCallback(() => {
     if (fluidType == FluidType.ELECTRICITY) {
-      const accountData = currentFluidStatus.connection.account
-        ?.auth as AccountSgeData
-      // store the previous account data since the onDelete will remove account from DB
-      dispatch(
-        updateSgeStore({
-          currentStep: 0,
-          firstName: accountData.firstname,
-          lastName: accountData.lastname,
-          pdl: parseInt(accountData.pointId),
-          address: accountData.address,
-          zipCode: parseInt(accountData.postalCode),
-          city: accountData.city,
-          dataConsent: true,
-          pdlConfirm: true,
-          shouldLaunchAccount: true,
-        })
-      )
       dispatch(setShouldRefreshConsent(true))
     } else {
       deleteAccountsAndTriggers()
     }
-  }, [
-    fluidType,
-    currentFluidStatus.connection.account?.auth,
-    dispatch,
-    deleteAccountsAndTriggers,
-  ])
+  }, [fluidType, dispatch, deleteAccountsAndTriggers])
 
   useEffect(() => {
     if (currentFluidStatus.connection.triggerState?.last_success) {
diff --git a/src/doctypes/com-grandlyon-ecolyo-form.ts b/src/doctypes/com-grandlyon-ecolyo-form.ts
new file mode 100644
index 000000000..45b9b49f6
--- /dev/null
+++ b/src/doctypes/com-grandlyon-ecolyo-form.ts
@@ -0,0 +1 @@
+export const FORM_DOCTYPE = 'com.grandlyon.ecolyo.form'
diff --git a/src/doctypes/index.ts b/src/doctypes/index.ts
index 3eded16b7..96ab63b22 100644
--- a/src/doctypes/index.ts
+++ b/src/doctypes/index.ts
@@ -3,6 +3,7 @@ import { DUEL_DOCTYPE } from './com-grandlyon-ecolyo-duel'
 import { ECOGESTURE_DOCTYPE } from './com-grandlyon-ecolyo-ecogesture'
 import { EXPLORATION_DOCTYPE } from './com-grandlyon-ecolyo-exploration'
 import { FLUIDSPRICES_DOCTYPE } from './com-grandlyon-ecolyo-fluidsprices'
+import { FORM_DOCTYPE } from './com-grandlyon-ecolyo-form'
 import { PROFILE_DOCTYPE } from './com-grandlyon-ecolyo-profile'
 import { PROFILEECOGESTURE_DOCTYPE } from './com-grandlyon-ecolyo-profileecogesture'
 import { PROFILETYPE_DOCTYPE } from './com-grandlyon-ecolyo-profiletype'
@@ -182,6 +183,11 @@ const doctypes = {
     attributes: {},
     relationships: {},
   },
+  form: {
+    doctype: FORM_DOCTYPE,
+    attributes: {},
+    relationships: {},
+  },
 }
 
 export default doctypes
@@ -192,6 +198,7 @@ export * from './com-grandlyon-ecolyo-duel'
 export * from './com-grandlyon-ecolyo-ecogesture'
 export * from './com-grandlyon-ecolyo-exploration'
 export * from './com-grandlyon-ecolyo-fluidsprices'
+export * from './com-grandlyon-ecolyo-form'
 export * from './com-grandlyon-ecolyo-profile'
 export * from './com-grandlyon-ecolyo-profileecogesture'
 export * from './com-grandlyon-ecolyo-profiletype'
diff --git a/src/models/global.model.ts b/src/models/global.model.ts
index d05429521..98f670d2a 100644
--- a/src/models/global.model.ts
+++ b/src/models/global.model.ts
@@ -3,7 +3,6 @@ import { TermsStatus } from 'models'
 import { FluidStatus } from './fluid.model'
 import { PartnersInfo } from './partnersInfo.model'
 import { ReleaseNotes } from './releaseNotes.model'
-import { SgeStore } from './sgeStore.model'
 
 export interface GlobalState {
   screenType: ScreenType
@@ -16,7 +15,6 @@ export interface GlobalState {
   fluidStatus: FluidStatus[]
   fluidTypes: FluidType[]
   shouldRefreshConsent: boolean
-  sgeConnect: SgeStore
   partnersInfo: PartnersInfo
   ecogestureFilter: Usage
   lastEpglLogin: string
diff --git a/src/store/global/global.slice.spec.ts b/src/store/global/global.slice.spec.ts
index ea4114529..608bd5f10 100644
--- a/src/store/global/global.slice.spec.ts
+++ b/src/store/global/global.slice.spec.ts
@@ -2,7 +2,6 @@
 import { FluidSlugType, FluidState, FluidType, ScreenType, Usage } from 'enums'
 import { DateTime } from 'luxon'
 import { FluidStatus, PartnersInfo, TermsStatus } from 'models'
-import { SgeStore } from 'models/sgeStore.model'
 import { accountsData } from 'tests/__mocks__/accountsData.mock'
 import { konnectorsData } from 'tests/__mocks__/konnectorsData.mock'
 import { mockGlobalState } from 'tests/__mocks__/store'
@@ -22,7 +21,6 @@ import {
   toggleChallengeExplorationNotification,
   updateEcogestureFilter,
   updateFluidConnection,
-  updateSgeStore,
   updateTermsStatus,
 } from './global.slice'
 
@@ -232,28 +230,6 @@ describe('globalSlice', () => {
       shouldRefreshConsent: true,
     })
   })
-  it('should handle setSgeConnect', () => {
-    const expectedSgeConnect: SgeStore = {
-      address: 'address',
-      city: 'city',
-      currentStep: 1,
-      dataConsent: true,
-      firstName: 'firstName',
-      lastName: 'lastName',
-      pdl: 12345678901234,
-      pdlConfirm: true,
-      shouldLaunchAccount: true,
-      zipCode: 99999,
-    }
-    const state = globalSlice.reducer(
-      mockGlobalState,
-      updateSgeStore(expectedSgeConnect)
-    )
-    expect(state).toEqual({
-      ...mockGlobalState,
-      sgeConnect: expectedSgeConnect,
-    })
-  })
   it('should handle updateFluidConnection', () => {
     const state = globalSlice.reducer(
       mockGlobalState,
diff --git a/src/store/global/global.slice.ts b/src/store/global/global.slice.ts
index f93aada9e..9b6acdedb 100644
--- a/src/store/global/global.slice.ts
+++ b/src/store/global/global.slice.ts
@@ -7,7 +7,6 @@ import {
   GlobalState,
   Notes,
   PartnersInfo,
-  SgeStore,
   TermsStatus,
 } from 'models'
 
@@ -107,18 +106,6 @@ const initialState: GlobalState = {
     notification_activated: false,
   },
   shouldRefreshConsent: false,
-  sgeConnect: {
-    currentStep: 0,
-    firstName: '',
-    lastName: '',
-    pdl: null,
-    address: '',
-    zipCode: null,
-    city: '',
-    dataConsent: false,
-    pdlConfirm: false,
-    shouldLaunchAccount: false,
-  },
   ecogestureFilter: Usage.ALL,
   lastEpglLogin: '',
 }
@@ -208,9 +195,6 @@ export const globalSlice = createSlice({
     setLastEpglLogin: (state, action: PayloadAction<string>) => {
       state.lastEpglLogin = action.payload
     },
-    updateSgeStore: (state, action: PayloadAction<SgeStore>) => {
-      state.sgeConnect = action.payload
-    },
     updateEcogestureFilter: (state, action: PayloadAction<Usage>) => {
       state.ecogestureFilter = action.payload
     },
@@ -231,6 +215,5 @@ export const {
   toggleChallengeExplorationNotification,
   updateEcogestureFilter,
   updateFluidConnection,
-  updateSgeStore,
   updateTermsStatus,
 } = globalSlice.actions
diff --git a/tests/__mocks__/forms.mock.ts b/tests/__mocks__/forms.mock.ts
new file mode 100644
index 000000000..9f3f43e67
--- /dev/null
+++ b/tests/__mocks__/forms.mock.ts
@@ -0,0 +1,14 @@
+import { SgeStore } from 'models'
+
+export const mockSgeState: SgeStore = {
+  address: '',
+  lastName: '',
+  firstName: '',
+  pdl: 0,
+  zipCode: 0,
+  city: '',
+  currentStep: 0,
+  dataConsent: false,
+  shouldLaunchAccount: false,
+  pdlConfirm: false,
+}
diff --git a/tests/__mocks__/store/global.state.mock.ts b/tests/__mocks__/store/global.state.mock.ts
index 3c19efac3..de8407406 100644
--- a/tests/__mocks__/store/global.state.mock.ts
+++ b/tests/__mocks__/store/global.state.mock.ts
@@ -94,17 +94,5 @@ export const mockGlobalState: GlobalState = {
   ],
   fluidTypes: [],
   shouldRefreshConsent: false,
-  sgeConnect: {
-    address: '',
-    city: '',
-    currentStep: 0,
-    dataConsent: false,
-    firstName: '',
-    lastName: '',
-    pdl: null,
-    pdlConfirm: false,
-    zipCode: null,
-    shouldLaunchAccount: false,
-  },
   ecogestureFilter: Usage.ALL,
 }
-- 
GitLab