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