diff --git a/.vscode/settings.json b/.vscode/settings.json index ce5597bb6c78fa4bf35605a1c3a43cc9609bae17..060adef4027ac3903b1d57c1580258f67b87706b 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -40,11 +40,14 @@ "authform", "backoffice", "barchart", + "camelcase", "CONSO", "cozycloud", "dacc", "Datachart", + "dataload", "Dataload", + "dataloads", "Dataloads", "defi", "depense", @@ -60,10 +63,12 @@ "Enedis", "ENEDIS", "enedissgegrandlyon", + "firstname", "fluidchart", "fluidchartslide", "fluidtype", "Gazpar", + "Gier", "grandlyon", "grdf", "GRDF", @@ -71,16 +76,20 @@ "Konnected", "konnector", "konnectors", + "lastname", + "Lugdunum", "luxon", "matomo", "Matomo", "MEGAUNIT", "monthlyanalysis", "MULTIFLUID", + "mutlifluid", "Picto", "PROFILETYPE", "Reinit", "splashscreen", - "testid" + "testid", + "UNSTARTED" ] } diff --git a/src/components/Connection/ConnectionResult.tsx b/src/components/Connection/ConnectionResult.tsx index c3560ac13c6d4128400fe0df8daa087362691340..755e9bf6fadcfb431bbb21466ab5dd139ff1e37e 100644 --- a/src/components/Connection/ConnectionResult.tsx +++ b/src/components/Connection/ConnectionResult.tsx @@ -132,6 +132,7 @@ const ConnectionResult: React.FC<ConnectionResultProps> = ({ dataConsent: true, pdlConfirm: true, shouldLaunchAccount: true, + openSGEForm: false, }) ) dispatch(setShouldRefreshConsent(true)) diff --git a/src/components/Connection/SGEConnect/SgeConnect.scss b/src/components/Connection/SGEConnect/SgeConnect.scss index e11551a7117b113c0a7c92b8f8ba894b63c0ca18..73e386abaa51eadb1f8b5fe376286496a5e90fdb 100644 --- a/src/components/Connection/SGEConnect/SgeConnect.scss +++ b/src/components/Connection/SGEConnect/SgeConnect.scss @@ -3,13 +3,24 @@ @import 'src/styles/base/breakpoint'; .sge-view { - box-sizing: border-box; - min-height: inherit; - width: inherit; display: flex; - flex: 1; flex-direction: column; justify-content: space-between; + background: $dark-light-2; + transition: all 0.5s ease-in; + position: fixed; + z-index: 25; + top: 4rem; + width: 100%; + height: 92vh; + @media (min-width: $width-large-phone) { + top: 8rem; + height: 85vh; + } + @media (min-width: $width-tablet) { + width: 85%; + } + .sge-container { padding: 1rem; @@ -60,12 +71,12 @@ -moz-appearance: textfield; } .pdl-hint { + display: inline-block; cursor: pointer; border-bottom: solid 1px $grey-bright; text-align: center; margin: 1rem auto auto; padding: 0.2rem; - width: 175px; @media (min-width: $width-tablet) { margin-left: 0; } diff --git a/src/components/Connection/SGEConnect/SgeConnectView.tsx b/src/components/Connection/SGEConnect/SgeConnectView.tsx index 83af4d4fce731892e76f5ecc5e75005e85326481..88c9b5f087f90f0719cacb93929b1c31f939a1e0 100644 --- a/src/components/Connection/SGEConnect/SgeConnectView.tsx +++ b/src/components/Connection/SGEConnect/SgeConnectView.tsx @@ -35,6 +35,7 @@ const SgeConnectView: React.FC = () => { const defineHeaderHeight = useCallback((height: number) => { setHeaderHeight(height) }, []) + const [isLoading, setIsLoading] = useState(false) const isNextValid = useCallback(() => { switch (currentStep) { @@ -74,19 +75,17 @@ const SgeConnectView: React.FC = () => { setCurrentStep(prev => prev + 1) dispatch(updateSgeStore(currentSgeState)) } - if (currentStep === SgeStep.Consent && isNextValid()) { + if (currentStep === SgeStep.Consent && isNextValid() && !isLoading) { + setIsLoading(true) const updatedState = { ...currentSgeState, city: currentSgeState.city.trim(), shouldLaunchAccount: true, - // switch to false in case the form fails and the user have to give its consent again - dataConsent: false, - pdlConfirm: false, } setCurrentSgeState(updatedState) dispatch(updateSgeStore(updatedState)) } - }, [currentSgeState, currentStep, dispatch, isNextValid]) + }, [currentSgeState, currentStep, dispatch, isNextValid, isLoading]) const handlePrev = useCallback(() => { if (currentStep !== SgeStep.IdentityAndPDL) { @@ -132,7 +131,13 @@ const SgeConnectView: React.FC = () => { return ( <> - <CozyBar titleKey={'common.title_sge_connect'} displayBackArrow={true} /> + <CozyBar + titleKey={'common.title_sge_connect'} + displayBackArrow={true} + backFunction={() => + dispatch(updateSgeStore({ ...sgeConnect, openSGEForm: false })) + } + /> <Header setHeaderHeight={defineHeaderHeight} desktopTitleKey={'common.title_sge_connect'} @@ -148,7 +153,8 @@ const SgeConnectView: React.FC = () => { step={currentStep} handlePrevious={handlePrev} handleNext={handleNext} - disableNextButton={!isNextValid()} + isLoading={isLoading} + disableNextButton={!isNextValid() || isLoading} disablePrevButton={currentStep === SgeStep.IdentityAndPDL} isLastConnectStep={currentStep === SgeStep.Consent} isEcogesture={false} diff --git a/src/components/Connection/SGEConnect/SgeInit.spec.tsx b/src/components/Connection/SGEConnect/SgeInit.spec.tsx index 1b093367e95dd2fbfb4c4bc9534f9b85330b76dd..0438327f0d93240f2ff0bee1ac8e7be70d105146 100644 --- a/src/components/Connection/SGEConnect/SgeInit.spec.tsx +++ b/src/components/Connection/SGEConnect/SgeInit.spec.tsx @@ -1,16 +1,18 @@ -import React from 'react' +import { Button } from '@material-ui/core' import { mount } from 'enzyme' -import configureStore from 'redux-mock-store' +import toJson from 'enzyme-to-json' +import { GlobalState } from 'models/global.model' +import React from 'react' import { Provider } from 'react-redux' -import SgeInit from './SgeInit' +import configureStore from 'redux-mock-store' +import { UpdateSGEConnect } from 'store/global/global.actions' import { fluidStatusData, - SgeStatusWithAccout, + SgeStatusWithAccount, } from '../../../../tests/__mocks__/fluidStatusData.mock' import { globalStateData } from '../../../../tests/__mocks__/globalStateData.mock' -import toJson from 'enzyme-to-json' -import { Button } from '@material-ui/core' import { waitForComponentToPaint } from '../../../../tests/__mocks__/testUtils' +import SgeInit from './SgeInit' jest.mock('cozy-ui/transpiled/react/I18n', () => { return { @@ -35,7 +37,7 @@ const mockUpdate = jest.fn() jest.mock('components/Hooks/useKonnectorAuth', () => jest.fn(() => [mockConnect, mockUpdate]) ) -const mockStore = configureStore([]) +const mockStore = configureStore<{ ecolyo: { global: GlobalState } }>([]) describe('SgeInit component', () => { it('should be rendered correctly', () => { @@ -63,14 +65,18 @@ describe('SgeInit component', () => { </Provider> ) wrapper.find(Button).first().simulate('click') - expect(mockHistoryPush).toHaveBeenCalled() + const updateSGEConnectAction: UpdateSGEConnect = store.getActions()[0] + expect(updateSGEConnectAction.payload?.openSGEForm).toBeTruthy() }) it('should launch account and trigger creation process', async () => { const store = mockStore({ ecolyo: { global: { ...globalStateData, - sgeConnect: { shouldLaunchAccount: true }, + sgeConnect: { + ...globalStateData.sgeConnect, + shouldLaunchAccount: true, + }, }, }, }) @@ -88,13 +94,16 @@ describe('SgeInit component', () => { ecolyo: { global: { ...globalStateData, - sgeConnect: { shouldLaunchAccount: true }, + sgeConnect: { + ...globalStateData.sgeConnect, + shouldLaunchAccount: true, + }, }, }, }) const wrapper = mount( <Provider store={store}> - <SgeInit fluidStatus={SgeStatusWithAccout} /> + <SgeInit fluidStatus={SgeStatusWithAccount} /> </Provider> ) await waitForComponentToPaint(wrapper) diff --git a/src/components/Connection/SGEConnect/SgeInit.tsx b/src/components/Connection/SGEConnect/SgeInit.tsx index b2a55732edc70b0db64b6de7a96fa7502d4312b7..6767e15ccf3caa149b1aec4709af8681aae99f01 100644 --- a/src/components/Connection/SGEConnect/SgeInit.tsx +++ b/src/components/Connection/SGEConnect/SgeInit.tsx @@ -1,25 +1,23 @@ -import React, { useEffect } from 'react' -import { Account, FluidStatus } from 'models' -import { useI18n } from 'cozy-ui/transpiled/react/I18n' import { Button } from '@material-ui/core' -import { decoreText } from 'utils/decoreText' import ElectricityBillIcon from 'assets/icons/visu/partnerSteps/electricity_bill.svg' import StyledIcon from 'components/CommonKit/Icon/StyledIcon' -import { useHistory } from 'react-router-dom' +import useKonnectorAuth from 'components/Hooks/useKonnectorAuth' +import { useI18n } from 'cozy-ui/transpiled/react/I18n' +import { Account, FluidStatus } from 'models' +import React, { useEffect } from 'react' import { useDispatch, useSelector } from 'react-redux' import { AppStore } from 'store' -import useKonnectorAuth from 'components/Hooks/useKonnectorAuth' import { setShouldRefreshConsent, updateSgeStore, } from 'store/global/global.actions' +import { decoreText } from 'utils/decoreText' interface SgeInitProps { fluidStatus: FluidStatus } const SgeInit: React.FC<SgeInitProps> = ({ fluidStatus }: SgeInitProps) => { const { t } = useI18n() - const history = useHistory() const konnectorSlug: string = fluidStatus.connection.konnectorConfig.slug const account: Account | null = fluidStatus.connection.account const { sgeConnect } = useSelector((state: AppStore) => state.ecolyo.global) @@ -56,7 +54,7 @@ const SgeInit: React.FC<SgeInitProps> = ({ fluidStatus }: SgeInitProps) => { <Button aria-label={t(`auth.${konnectorSlug}.accessibility.connect`)} onClick={() => { - history.push('/sge-connect') + dispatch(updateSgeStore({ ...sgeConnect, openSGEForm: true })) }} classes={{ root: 'btn-highlight', diff --git a/src/components/Connection/SGEConnect/StepAddress.tsx b/src/components/Connection/SGEConnect/StepAddress.tsx index 0b7ab8f4b7e289d1e38905d82592fe346feec912..73a405da655d1dd4033ad04e7ff0c9bb75a73518 100644 --- a/src/components/Connection/SGEConnect/StepAddress.tsx +++ b/src/components/Connection/SGEConnect/StepAddress.tsx @@ -26,7 +26,7 @@ const StepAddress: React.FC<StepAddressProps> = ({ id="address" name="address" value={sgeState.address} - onChange={e => onChange('address', e.target.value.trim())} + onChange={e => onChange('address', e.target.value)} /> <label htmlFor="zipCode" className="text-16-normal"> {t('auth.enedissgegrandlyon.zipCode')} diff --git a/src/components/Connection/SGEConnect/StepConsent.spec.tsx b/src/components/Connection/SGEConnect/StepConsent.spec.tsx index 985082b68f6aeea772e9df4dd723cb85fac38d72..09498f8b583a532e2bb823c9fc3a20ffcdf7bb3a 100644 --- a/src/components/Connection/SGEConnect/StepConsent.spec.tsx +++ b/src/components/Connection/SGEConnect/StepConsent.spec.tsx @@ -1,9 +1,10 @@ -import React from 'react' import { mount } from 'enzyme' -import configureStore from 'redux-mock-store' +import toJson from 'enzyme-to-json' +import { GlobalState } from 'models/global.model' +import React from 'react' import { Provider } from 'react-redux' +import configureStore from 'redux-mock-store' import { globalStateData } from '../../../../tests/__mocks__/globalStateData.mock' -import toJson from 'enzyme-to-json' import StepConsent from './StepConsent' jest.mock('cozy-ui/transpiled/react/I18n', () => { @@ -15,7 +16,7 @@ jest.mock('cozy-ui/transpiled/react/I18n', () => { }), } }) -const mockStore = configureStore([]) +const mockStore = configureStore<{ ecolyo: { global: GlobalState } }>([]) describe('StepConsent component', () => { it('should be rendered correctly', () => { diff --git a/src/components/Connection/SGEConnect/StepIdentityAndPdl.tsx b/src/components/Connection/SGEConnect/StepIdentityAndPdl.tsx index 06606e1f75c35dd68cf9c0f0609592566a5ae398..eebeb80f914f49dc01c5055fe3ab19c8c4bdedbf 100644 --- a/src/components/Connection/SGEConnect/StepIdentityAndPdl.tsx +++ b/src/components/Connection/SGEConnect/StepIdentityAndPdl.tsx @@ -66,6 +66,7 @@ const StepIdentityAndPdl: React.FC<StepIdentityAndPdlProps> = ({ inputMode="numeric" required /> + <br /> <div onClick={toggleModal} className="pdl-hint text-16-normal"> {t('auth.enedissgegrandlyon.pdlHint')} </div> diff --git a/src/components/Connection/SGEConnect/__snapshots__/SgeConnectView.spec.tsx.snap b/src/components/Connection/SGEConnect/__snapshots__/SgeConnectView.spec.tsx.snap index 4875200e3e8dde4ff5b23bb5a359017cb8c41d57..6b58abe11526cef0b868cef075968a8a410aded6 100644 --- a/src/components/Connection/SGEConnect/__snapshots__/SgeConnectView.spec.tsx.snap +++ b/src/components/Connection/SGEConnect/__snapshots__/SgeConnectView.spec.tsx.snap @@ -15,6 +15,7 @@ exports[`SgeConnectView component should be rendered correctly 1`] = ` > <SgeConnectView> <CozyBar + backFunction={[Function]} displayBackArrow={true} titleKey="common.title_sge_connect" > @@ -642,6 +643,7 @@ exports[`SgeConnectView component should be rendered correctly 1`] = ` "dataConsent": false, "firstName": "", "lastName": "", + "openSGEForm": false, "pdl": null, "pdlConfirm": false, "shouldLaunchAccount": false, @@ -705,6 +707,7 @@ exports[`SgeConnectView component should be rendered correctly 1`] = ` required={true} type="number" /> + <br /> <div className="pdl-hint text-16-normal" onClick={[Function]} @@ -1095,6 +1098,7 @@ exports[`SgeConnectView component should be rendered correctly 1`] = ` handlePrevious={[Function]} isEcogesture={false} isLastConnectStep={false} + isLoading={false} step={0} > <div diff --git a/src/components/Connection/SGEConnect/__snapshots__/StepAddress.spec.tsx.snap b/src/components/Connection/SGEConnect/__snapshots__/StepAddress.spec.tsx.snap index bffbbf9d0daf4c604fe6515786a9fa9d54a83c71..26812fdf7014e4a971b43a489b87dcd3202f7ece 100644 --- a/src/components/Connection/SGEConnect/__snapshots__/StepAddress.spec.tsx.snap +++ b/src/components/Connection/SGEConnect/__snapshots__/StepAddress.spec.tsx.snap @@ -23,6 +23,7 @@ exports[`StepAddress component should be rendered correctly 1`] = ` "dataConsent": false, "firstName": "", "lastName": "", + "openSGEForm": false, "pdl": null, "pdlConfirm": false, "shouldLaunchAccount": false, diff --git a/src/components/Connection/SGEConnect/__snapshots__/StepConsent.spec.tsx.snap b/src/components/Connection/SGEConnect/__snapshots__/StepConsent.spec.tsx.snap index f5fd68d492c79666b431eae5ce7719273b7005d1..b377c4e67e55737300f2a633b16de3503e32ade0 100644 --- a/src/components/Connection/SGEConnect/__snapshots__/StepConsent.spec.tsx.snap +++ b/src/components/Connection/SGEConnect/__snapshots__/StepConsent.spec.tsx.snap @@ -23,6 +23,7 @@ exports[`StepConsent component should be rendered correctly 1`] = ` "dataConsent": false, "firstName": "", "lastName": "", + "openSGEForm": false, "pdl": null, "pdlConfirm": false, "shouldLaunchAccount": false, diff --git a/src/components/Connection/SGEConnect/__snapshots__/StepIdentityAndPdl.spec.tsx.snap b/src/components/Connection/SGEConnect/__snapshots__/StepIdentityAndPdl.spec.tsx.snap index e5fd436186347e2a50eaf39f652ef27a388c17ae..d02da53ca004a9588d0971dfa7199fd70a289efc 100644 --- a/src/components/Connection/SGEConnect/__snapshots__/StepIdentityAndPdl.spec.tsx.snap +++ b/src/components/Connection/SGEConnect/__snapshots__/StepIdentityAndPdl.spec.tsx.snap @@ -23,6 +23,7 @@ exports[`StepIdentityAndPdl component should be rendered correctly 1`] = ` "dataConsent": false, "firstName": "", "lastName": "", + "openSGEForm": false, "pdl": null, "pdlConfirm": false, "shouldLaunchAccount": false, @@ -86,6 +87,7 @@ exports[`StepIdentityAndPdl component should be rendered correctly 1`] = ` required={true} type="number" /> + <br /> <div className="pdl-hint text-16-normal" onClick={[Function]} diff --git a/src/components/FormGlobal/FormNavigation.tsx b/src/components/FormGlobal/FormNavigation.tsx index d2711c30bb04c4f18c8360ea7e55836d582aa1fc..8a8bbf29b561d5500cad58918bf3f5bdbbb58902 100644 --- a/src/components/FormGlobal/FormNavigation.tsx +++ b/src/components/FormGlobal/FormNavigation.tsx @@ -1,11 +1,11 @@ -import React from 'react' -import 'components/FormGlobal/formNavigation.scss' +import Button from '@material-ui/core/Button' import classNames from 'classnames' +import 'components/FormGlobal/formNavigation.scss' import { useI18n } from 'cozy-ui/transpiled/react/I18n' -import Button from '@material-ui/core/Button' -import { ProfileTypeStepForm } from 'enum/profileType.enum' import { EcogestureStepForm } from 'enum/ecogestureForm.enum' +import { ProfileTypeStepForm } from 'enum/profileType.enum' import { SgeStep } from 'enum/sgeStep.enum' +import React, { useCallback } from 'react' import { useHistory } from 'react-router-dom' interface FormNavigationProps { @@ -16,6 +16,7 @@ interface FormNavigationProps { disablePrevButton?: boolean isEcogesture?: boolean isLastConnectStep?: boolean + isLoading?: boolean } const FormNavigation: React.FC<FormNavigationProps> = ({ @@ -26,6 +27,7 @@ const FormNavigation: React.FC<FormNavigationProps> = ({ disablePrevButton, isEcogesture, isLastConnectStep, + isLoading, }: FormNavigationProps) => { const { t } = useI18n() const history = useHistory() @@ -40,6 +42,20 @@ const FormNavigation: React.FC<FormNavigationProps> = ({ } } + const getSecondButtonLabel = useCallback(() => { + if (isLoading) { + return t('profile_type.form.button_loading') + } else if ( + isLastConnectStep || + step === ProfileTypeStepForm.UPDATE_DATE || + (step === EcogestureStepForm.EQUIPMENTS && isEcogesture) + ) { + return t('profile_type.form.button_end') + } else { + return `${t('profile_type.form.button_next')} >` + } + }, [isEcogesture, isLastConnectStep, isLoading, step, t]) + return ( <div className="profile-navigation"> <Button @@ -73,11 +89,7 @@ const FormNavigation: React.FC<FormNavigationProps> = ({ label: 'text-16-bold', }} > - {step === ProfileTypeStepForm.UPDATE_DATE || - isLastConnectStep || - (step === EcogestureStepForm.EQUIPMENTS && isEcogesture) - ? t('profile_type.form.button_end') - : `${t('profile_type.form.button_next')} >`} + {getSecondButtonLabel()} </Button> </div> ) diff --git a/src/components/Home/ConsumptionView.spec.tsx b/src/components/Home/ConsumptionView.spec.tsx index 9aae9a9603d0c59ee157bfc52692b83b9c014375..56a2cfbd578552c56d99802dca7eac5c14b8b0c7 100644 --- a/src/components/Home/ConsumptionView.spec.tsx +++ b/src/components/Home/ConsumptionView.spec.tsx @@ -2,10 +2,11 @@ import Loader from 'components/Loader/Loader' import { FluidState, FluidType } from 'enum/fluid.enum' import { TimeStep } from 'enum/timeStep.enum' import { mount } from 'enzyme' -import { FluidStatus } from 'models' +import { ChartState, FluidStatus, GlobalState } from 'models' import React from 'react' import * as reactRedux from 'react-redux' import { Provider } from 'react-redux' +import { MockStoreEnhanced } from 'redux-mock-store' import * as chartActions from 'store/chart/chart.actions' import { mockTestProfile1 } from '../../../tests/__mocks__/profileType.mock' import { @@ -52,14 +53,25 @@ jest.mock( ) jest.mock('components/CustomPopup/CustomPopupModal', () => 'mock-custompopup') jest.mock('components/Home/ReleaseNotesModal', () => 'mock-releasenotes') +jest.mock( + 'components/Connection/SGEConnect/SgeConnectView', + () => 'mock-SgeConnectView' +) const useSelectorSpy = jest.spyOn(reactRedux, 'useSelector') const useDispatchSpy = jest.spyOn(reactRedux, 'useDispatch') const setCurrentTimeStepSpy = jest.spyOn(chartActions, 'setCurrentTimeStep') describe('ConsumptionView component', () => { - // eslint-disable-next-line @typescript-eslint/no-explicit-any - let store: any + let store: MockStoreEnhanced< + { + ecolyo: { + global: GlobalState + chart?: ChartState + } + }, + {} + > beforeEach(() => { store = createMockStore(mockInitialEcolyoState) useDispatchSpy.mockClear() @@ -71,10 +83,14 @@ describe('ConsumptionView component', () => { mockInitialEcolyoState.global.fluidStatus mockFluidStatus[FluidType.ELECTRICITY].status = FluidState.DONE useSelectorSpy.mockReturnValue({ - currentTimeStep: TimeStep.WEEK, - loading: false, - fluidStatus: mockFluidStatus, - releaseNotes: mockInitialEcolyoState.global.releaseNotes, + chart: { + currentTimeStep: TimeStep.WEEK, + loading: true, + }, + global: { + fluidStatus: mockFluidStatus, + releaseNotes: mockInitialEcolyoState.global.releaseNotes, + }, }) const wrapper = mount( <Provider store={store}> @@ -94,10 +110,14 @@ describe('ConsumptionView component', () => { mockInitialEcolyoState.global.fluidStatus mockFluidStatus[FluidType.ELECTRICITY].status = FluidState.DONE useSelectorSpy.mockReturnValue({ - currentTimeStep: TimeStep.WEEK, - loading: true, - fluidStatus: mockFluidStatus, - releaseNotes: mockInitialEcolyoState.global.releaseNotes, + chart: { + currentTimeStep: TimeStep.WEEK, + loading: true, + }, + global: { + fluidStatus: mockFluidStatus, + releaseNotes: mockInitialEcolyoState.global.releaseNotes, + }, }) const wrapper = mount( <Provider store={store}> @@ -112,10 +132,14 @@ describe('ConsumptionView component', () => { it('should set CurrentTimeStep to WEEK when fluid != ELECTRICITY and timeStep = HALF_AN_HOUR', () => { useSelectorSpy.mockReturnValue({ - currentTimeStep: TimeStep.HALF_AN_HOUR, - loading: true, - fluidStatus: mockInitialEcolyoState.global.fluidStatus, - releaseNotes: mockInitialEcolyoState.global.releaseNotes, + chart: { + currentTimeStep: TimeStep.HALF_AN_HOUR, + loading: true, + }, + global: { + fluidStatus: mockInitialEcolyoState.global.fluidStatus, + releaseNotes: mockInitialEcolyoState.global.releaseNotes, + }, }) mount( <Provider store={store}> @@ -128,10 +152,15 @@ describe('ConsumptionView component', () => { it('should render konnector list when no fluid is connected', () => { useSelectorSpy.mockReturnValue({ - currentTimeStep: TimeStep.WEEK, - loading: true, - fluidStatus: mockInitialEcolyoState.global.fluidStatus, - releaseNotes: mockInitialEcolyoState.global.releaseNotes, + chart: { + currentTimeStep: TimeStep.WEEK, + loading: true, + }, + global: { + fluidStatus: [], + releaseNotes: mockInitialEcolyoState.global.releaseNotes, + }, + fluidStatus: [], }) const wrapper = mount( <Provider store={store}> @@ -146,10 +175,15 @@ describe('ConsumptionView component', () => { mockInitialEcolyoState.global.fluidStatus updatedStatus[1].status = FluidState.DONE useSelectorSpy.mockReturnValue({ - currentTimeStep: TimeStep.WEEK, - loading: true, + chart: { + currentTimeStep: TimeStep.WEEK, + loading: true, + }, + global: { + fluidStatus: updatedStatus, + releaseNotes: mockInitialEcolyoState.global.releaseNotes, + }, fluidStatus: updatedStatus, - releaseNotes: mockInitialEcolyoState.global.releaseNotes, }) const wrapper = mount( <Provider store={store}> @@ -164,10 +198,14 @@ describe('ConsumptionView component', () => { mockInitialEcolyoState.global.fluidStatus updatedStatus[0].status = FluidState.DONE useSelectorSpy.mockReturnValue({ - currentTimeStep: TimeStep.WEEK, - loading: true, - fluidStatus: updatedStatus, - releaseNotes: mockInitialEcolyoState.global.releaseNotes, + chart: { + currentTimeStep: TimeStep.WEEK, + loading: true, + }, + global: { + fluidStatus: updatedStatus, + releaseNotes: mockInitialEcolyoState.global.releaseNotes, + }, }) const wrapper = mount( <Provider store={store}> @@ -182,10 +220,14 @@ describe('ConsumptionView component', () => { mockInitialEcolyoState.global.fluidStatus updatedStatus[0] = mockExpiredElec useSelectorSpy.mockReturnValue({ - currentTimeStep: TimeStep.WEEK, - loading: true, - fluidStatus: updatedStatus, - releaseNotes: mockInitialEcolyoState.global.releaseNotes, + chart: { + currentTimeStep: TimeStep.WEEK, + loading: true, + }, + global: { + fluidStatus: updatedStatus, + releaseNotes: mockInitialEcolyoState.global.releaseNotes, + }, }) useDispatchSpy.mockReturnValue(jest.fn()) mockUpdateProfile.mockResolvedValue(mockTestProfile1) @@ -201,16 +243,20 @@ describe('ConsumptionView component', () => { mockInitialEcolyoState.global.fluidStatus updatedStatus[0] = mockExpiredGas useSelectorSpy.mockReturnValue({ - currentTimeStep: TimeStep.WEEK, - loading: true, - fluidStatus: updatedStatus, - releaseNotes: mockInitialEcolyoState.global.releaseNotes, - openPartnersIssueModal: false, + chart: { + currentTimeStep: TimeStep.WEEK, + loading: true, + }, + global: { + fluidStatus: updatedStatus, + releaseNotes: mockInitialEcolyoState.global.releaseNotes, + openPartnersIssueModal: false, + }, }) useDispatchSpy.mockReturnValue(jest.fn()) const wrapper = mount( <Provider store={store}> - <ConsumptionView fluidType={FluidType.MULTIFLUID} /> + <ConsumptionView fluidType={FluidType.GAS} /> </Provider> ) expect(wrapper.find('.title').text()).toBe('consent_outdated.title.2') @@ -220,15 +266,19 @@ describe('ConsumptionView component', () => { mockInitialEcolyoState.global.fluidStatus updatedStatus[0] = mockExpiredElec useSelectorSpy.mockReturnValue({ - currentTimeStep: TimeStep.WEEK, - loading: true, - fluidStatus: updatedStatus, - releaseNotes: mockInitialEcolyoState.global.releaseNotes, + chart: { + currentTimeStep: TimeStep.WEEK, + loading: true, + }, + global: { + fluidStatus: updatedStatus, + releaseNotes: mockInitialEcolyoState.global.releaseNotes, + }, }) useDispatchSpy.mockReturnValue(jest.fn()) const wrapper = mount( <Provider store={store}> - <ConsumptionView fluidType={FluidType.MULTIFLUID} /> + <ConsumptionView fluidType={FluidType.ELECTRICITY} /> </Provider> ) @@ -239,10 +289,14 @@ describe('ConsumptionView component', () => { mockInitialEcolyoState.global.fluidStatus updatedStatus[0] = mockExpiredElec useSelectorSpy.mockReturnValue({ - currentTimeStep: TimeStep.WEEK, - loading: true, - fluidStatus: updatedStatus, - releaseNotes: mockInitialEcolyoState.global.releaseNotes, + chart: { + currentTimeStep: TimeStep.WEEK, + loading: true, + }, + global: { + fluidStatus: updatedStatus, + releaseNotes: mockInitialEcolyoState.global.releaseNotes, + }, }) useDispatchSpy.mockReturnValue(jest.fn()) mockUpdateProfile.mockResolvedValue(mockTestProfile1) @@ -258,12 +312,16 @@ describe('ConsumptionView component', () => { mockInitialEcolyoState.global.fluidStatus updatedStatus[0] = mockExpiredElec useSelectorSpy.mockReturnValue({ - currentTimeStep: TimeStep.WEEK, - loading: true, - fluidStatus: updatedStatus, - releaseNotes: { - show: true, - notes: [{ description: 'description', title: 'title' }], + chart: { + currentTimeStep: TimeStep.WEEK, + loading: true, + }, + global: { + fluidStatus: updatedStatus, + releaseNotes: { + show: true, + notes: [{ description: 'description', title: 'title' }], + }, }, }) useDispatchSpy.mockReturnValue(jest.fn()) @@ -275,4 +333,28 @@ describe('ConsumptionView component', () => { ) expect(wrapper.find('mock-releasenotes').exists()).toBeTruthy() }) + + it('should render SGE connect form', () => { + useSelectorSpy.mockReturnValue({ + chart: { + currentTimeStep: TimeStep.WEEK, + loading: true, + }, + global: { + fluidStatus: mockInitialEcolyoState.global.fluidStatus, + releaseNotes: mockInitialEcolyoState.global.releaseNotes, + sgeConnect: { + openSGEForm: true, + }, + }, + }) + useDispatchSpy.mockReturnValue(jest.fn()) + mockUpdateProfile.mockResolvedValue(mockTestProfile1) + const wrapper = mount( + <Provider store={store}> + <ConsumptionView fluidType={FluidType.ELECTRICITY} /> + </Provider> + ) + expect(wrapper.find('mock-SgeConnectView').exists()).toBeTruthy() + }) }) diff --git a/src/components/Home/ConsumptionView.tsx b/src/components/Home/ConsumptionView.tsx index ae00f24586dd6041ec9c2c7e05c11380cefe1ec2..55dda6574a8808af5b73707fe57a702a11780c7c 100644 --- a/src/components/Home/ConsumptionView.tsx +++ b/src/components/Home/ConsumptionView.tsx @@ -1,12 +1,6 @@ -import { FluidType } from 'enum/fluid.enum' -import { TimeStep } from 'enum/timeStep.enum' -import React, { useCallback, useEffect, useState } from 'react' -import { useDispatch, useSelector } from 'react-redux' -import { AppStore } from 'store' -import './consumptionView.scss' - import classNames from 'classnames' import ExpiredConsentModal from 'components/Connection/ExpiredConsentModal' +import SgeConnectView from 'components/Connection/SGEConnect/SgeConnectView' import Content from 'components/Content/Content' import CustomPopupModal from 'components/CustomPopup/CustomPopupModal' import DateNavigator from 'components/DateNavigator/DateNavigator' @@ -20,9 +14,14 @@ import KonnectorViewerList from 'components/Konnector/KonnectorViewerList' import Loader from 'components/Loader/Loader' import PartnersIssueModal from 'components/PartnersIssue/PartnersIssueModal' import { useClient } from 'cozy-client' +import { FluidType } from 'enum/fluid.enum' +import { TimeStep } from 'enum/timeStep.enum' +import React, { useCallback, useEffect, useState } from 'react' +import { useDispatch, useSelector } from 'react-redux' import { useHistory } from 'react-router-dom' import ProfileService from 'services/profile.service' -import { setCurrentTimeStep, setLoading } from 'store/chart/chart.actions' +import { AppStore } from 'store' +import { setCurrentTimeStep } from 'store/chart/chart.actions' import { setCustomPopup, setPartnersIssue, @@ -33,6 +32,7 @@ import { getTodayDate, isKonnectorActive, } from 'utils/utils' +import './consumptionView.scss' import ReleaseNotesModal from './ReleaseNotesModal' interface ConsumptionViewProps { fluidType: FluidType @@ -44,15 +44,16 @@ const ConsumptionView: React.FC<ConsumptionViewProps> = ({ const client = useClient() const dispatch = useDispatch() const isMulti = fluidType !== FluidType.MULTIFLUID - const { currentTimeStep, loading } = useSelector( - (state: AppStore) => state.ecolyo.chart - ) const { - fluidStatus, - releaseNotes, - customPopupModal, - openPartnersIssueModal, - } = useSelector((state: AppStore) => state.ecolyo.global) + chart: { currentTimeStep, loading }, + global: { + fluidStatus, + releaseNotes, + customPopupModal, + openPartnersIssueModal, + sgeConnect, + }, + } = useSelector((state: AppStore) => state.ecolyo) const [isFluidKonnected, setIsFluidKonnected] = useState<boolean>(false) const [openReleaseNoteModal, setOpenReleaseNoteModal] = useState<boolean>( @@ -127,10 +128,6 @@ const ConsumptionView: React.FC<ConsumptionViewProps> = ({ } }, [dispatch, fluidType, currentTimeStep, fluidStatus]) - useEffect(() => { - dispatch(setLoading(true)) - }, [dispatch]) - useEffect(() => { let subscribed = true const expiredConsents: FluidType[] = [] @@ -213,6 +210,7 @@ const ConsumptionView: React.FC<ConsumptionViewProps> = ({ </div> )} </Content> + {sgeConnect?.openSGEForm && <SgeConnectView />} <PartnersIssueModal open={openPartnersIssueModal} diff --git a/src/components/Konnector/KonnectorModal.tsx b/src/components/Konnector/KonnectorModal.tsx index a71533554111eeff77da2b520d25bbcbb3cc8287..1b6dd8ddb1ae49e9c3313e1e38ec11349999f17f 100644 --- a/src/components/Konnector/KonnectorModal.tsx +++ b/src/components/Konnector/KonnectorModal.tsx @@ -58,7 +58,7 @@ const KonnectorModal: React.FC<KonnectorModalProps> = ({ ) const [showCommonErrors, setShowCommonErrors] = useState(false) - const getUpdatingText = useCallback((): JSX.Element => { + const getUpdatingText = useCallback(() => { return ( <div className="kmodal-waiting-text text-18-italic"> {shuffledWaitingTexts.map((text, idx) => ( @@ -76,7 +76,7 @@ const KonnectorModal: React.FC<KonnectorModalProps> = ({ ) }, [index, shuffledWaitingTexts]) - const getConnectionText = useCallback((): JSX.Element => { + const getConnectionText = useCallback(() => { return ( <div className="kmodal-waiting-text text-18-italic"> {isLogging ? ( @@ -101,7 +101,7 @@ const KonnectorModal: React.FC<KonnectorModalProps> = ({ useEffect(() => { const interval = setInterval(() => { if (open && !state) { - setIndex((prev: number) => prev + 1) + setIndex(prev => prev + 1) } }, 8000) return () => { diff --git a/src/components/Konnector/KonnectorModalFooter.spec.tsx b/src/components/Konnector/KonnectorModalFooter.spec.tsx index 53cb597641b9fba6a8500545a73a28420aee7031..9a07e71b6390229c9bcd11ea9c131d8484bc2f59 100644 --- a/src/components/Konnector/KonnectorModalFooter.spec.tsx +++ b/src/components/Konnector/KonnectorModalFooter.spec.tsx @@ -1,18 +1,20 @@ -import React from 'react' +import { Button } from '@material-ui/core' +import { ERROR_EVENT } from 'cozy-harvest-lib/dist/models/flowEvents' +import { FluidType } from 'enum/fluid.enum' +import { KonnectorError } from 'enum/konnectorError.enum' import { mount } from 'enzyme' +import toJson from 'enzyme-to-json' +import { GlobalState } from 'models/global.model' +import React from 'react' import { Provider } from 'react-redux' +import { MockStoreEnhanced } from 'redux-mock-store' +import { accountsData } from '../../../tests/__mocks__/accountsData.mock' import { createMockStore, mockInitialEcolyoState, } from '../../../tests/__mocks__/store' -import { ERROR_EVENT } from 'cozy-harvest-lib/dist/models/flowEvents' -import toJson from 'enzyme-to-json' -import KonnectorModalFooter from './KonnectorModalFooter' -import { FluidType } from 'enum/fluid.enum' -import { KonnectorError } from 'enum/konnectorError.enum' -import { Button } from '@material-ui/core' -import { accountsData } from '../../../tests/__mocks__/accountsData.mock' import { waitForComponentToPaint } from '../../../tests/__mocks__/testUtils' +import KonnectorModalFooter from './KonnectorModalFooter' jest.mock('cozy-ui/transpiled/react/I18n', () => { return { @@ -33,7 +35,14 @@ jest.mock('react-router-dom', () => ({ const mockClose = jest.fn() const mockDelete = jest.fn() describe('KonnectorModalFooter component', () => { - let store: any + let store: MockStoreEnhanced< + { + ecolyo: { + global: GlobalState + } + }, + {} + > beforeEach(() => { store = createMockStore(mockInitialEcolyoState) mockDelete.mockClear() @@ -148,7 +157,6 @@ describe('KonnectorModalFooter component', () => { wrapper.find(Button).at(1).simulate('click') await waitForComponentToPaint(wrapper) expect(mockDelete).toHaveBeenCalled() - expect(mockHistoryPush).toHaveBeenCalledTimes(1) }) it('should reset sge account and go back to login', async () => { const wrapper = mount( @@ -167,7 +175,6 @@ describe('KonnectorModalFooter component', () => { wrapper.find(Button).at(1).simulate('click') await waitForComponentToPaint(wrapper) expect(mockDelete).toHaveBeenCalled() - expect(mockHistoryPush).toHaveBeenCalledTimes(1) }) it('should not reset account if no account', () => { const wrapper = mount( @@ -184,7 +191,6 @@ describe('KonnectorModalFooter component', () => { </Provider> ) wrapper.find(Button).at(1).simulate('click') - expect(mockHistoryPush).toHaveBeenCalledTimes(1) expect(mockDelete).toHaveBeenCalledTimes(0) }) }) diff --git a/src/components/Konnector/KonnectorModalFooter.tsx b/src/components/Konnector/KonnectorModalFooter.tsx index 40b11039edd43a581182994d6e3fe7b5a37cf97b..81a92f638ec1053567e2bb8e89ac47f0c5049c0d 100644 --- a/src/components/Konnector/KonnectorModalFooter.tsx +++ b/src/components/Konnector/KonnectorModalFooter.tsx @@ -9,7 +9,6 @@ import { FluidType } from 'enum/fluid.enum' import { KonnectorError } from 'enum/konnectorError.enum' import { Account } from 'models' import React, { useCallback } from 'react' -import { useHistory } from 'react-router-dom' import AccountService from 'services/account.service' import './konnectorModal.scss' @@ -33,21 +32,18 @@ const KonnectorModalFooter: React.FC<KonnectorModalFooterProps> = ({ isUpdating, }: KonnectorModalFooterProps) => { const { t } = useI18n() - const history = useHistory() const client = useClient() const handleSGELoginRetry = useCallback(() => { handleCloseClick(state === SUCCESS_EVENT) - history.push('/sge-connect') - }, [handleCloseClick, history, state]) + }, [handleCloseClick, state]) const handleResetSGEAccount = useCallback(async () => { if (account) { const accountService = new AccountService(client) await accountService.deleteAccount(account) await handleAccountDeletion() - history.push('/sge-connect') } - }, [account, client, handleAccountDeletion, history]) + }, [account, client, handleAccountDeletion]) const errorButtons = () => { switch (error) { diff --git a/src/components/Konnector/KonnectorViewerCard.tsx b/src/components/Konnector/KonnectorViewerCard.tsx index c160dc6332b4f0f4b35bfd1cb950caf39af4f93a..91b264255c929628af449483c95d56afad76f9d9 100644 --- a/src/components/Konnector/KonnectorViewerCard.tsx +++ b/src/components/Konnector/KonnectorViewerCard.tsx @@ -1,65 +1,63 @@ -import React, { useState, useEffect, useCallback, useMemo } from 'react' -import { useI18n } from 'cozy-ui/transpiled/react/I18n' -import { useClient } from 'cozy-client' -import { useDispatch, useSelector } from 'react-redux' -import { AppStore } from 'store' -import classNames from 'classnames' -import './konnectorViewerCard.scss' - -import { FluidState, FluidType } from 'enum/fluid.enum' -import { UserChallengeState } from 'enum/userChallenge.enum' -import { UserDuelState } from 'enum/userDuel.enum' -import { - Account, - Konnector, - Trigger, - FluidStatus, - FluidConnection, - UsageEvent, - AccountAuthData, -} from 'models' -import { getAddPicto, getParamPicto } from 'utils/picto' -import { setChallengeConsumption } from 'store/challenge/challenge.actions' -import { - setFluidStatus, - toggleChallengeDuelNotification, - updatedFluidConnection, -} from 'store/global/global.actions' -import FluidService from 'services/fluid.service' -import ChallengeService from 'services/challenge.service' -import AccountService from 'services/account.service' - -import chevronDown from 'assets/icons/ico/chevron-down.svg' -import Icon from 'cozy-ui/transpiled/react/Icon' import { Accordion, - AccordionSummary, AccordionDetails, + AccordionSummary, } from '@material-ui/core' +import chevronDown from 'assets/icons/ico/chevron-down.svg' import ErrorNotif from 'assets/icons/ico/notif_error.svg' import PartnersIssueNotif from 'assets/icons/ico/notif_maintenance.svg' -import ConnectionNotFound from 'components/Connection/ConnectionNotFound' +import classNames from 'classnames' +import StyledIcon from 'components/CommonKit/Icon/StyledIcon' import Connection from 'components/Connection/Connection' +import ConnectionNotFound from 'components/Connection/ConnectionNotFound' import ConnectionResult from 'components/Connection/ConnectionResult' import KonnectorModal from 'components/Konnector/KonnectorModal' - +import { useClient } from 'cozy-client' import { isKonnectorRunning } from 'cozy-harvest-lib/dist/helpers/triggers' import ConnectionFlow from 'cozy-harvest-lib/dist/models/ConnectionFlow' import { ERROR_EVENT, - SUCCESS_EVENT, LOGIN_SUCCESS_EVENT, + SUCCESS_EVENT, } from 'cozy-harvest-lib/dist/models/flowEvents' +import { useI18n } from 'cozy-ui/transpiled/react/I18n' +import Icon from 'cozy-ui/transpiled/react/Icon' +import { FluidState, FluidType } from 'enum/fluid.enum' +import { FluidSlugType } from 'enum/fluidSlug.enum' +import { KonnectorError } from 'enum/konnectorError.enum' +import { UsageEventType } from 'enum/usageEvent.enum' +import { UserChallengeState } from 'enum/userChallenge.enum' +import { UserDuelState } from 'enum/userDuel.enum' import { DateTime } from 'luxon' -import { setSelectedDate } from 'store/chart/chart.actions' +import { + Account, + AccountAuthData, + FluidConnection, + FluidStatus, + Konnector, + Trigger, + UsageEvent, +} from 'models' +import { PartnersInfo } from 'models/partnersInfo.model' +import React, { useCallback, useEffect, useMemo, useState } from 'react' +import { useDispatch, useSelector } from 'react-redux' +import AccountService from 'services/account.service' +import ChallengeService from 'services/challenge.service' import DateChartService from 'services/dateChart.service' -import StyledIcon from 'components/CommonKit/Icon/StyledIcon' -import UsageEventService from 'services/usageEvent.service' -import { UsageEventType } from 'enum/usageEvent.enum' +import FluidService from 'services/fluid.service' import PartnersInfoService from 'services/partnersInfo.service' -import { PartnersInfo } from 'models/partnersInfo.model' -import { FluidSlugType } from 'enum/fluidSlug.enum' -import { KonnectorError } from 'enum/konnectorError.enum' +import UsageEventService from 'services/usageEvent.service' +import { AppStore } from 'store' +import { setChallengeConsumption } from 'store/challenge/challenge.actions' +import { setSelectedDate } from 'store/chart/chart.actions' +import { + setFluidStatus, + toggleChallengeDuelNotification, + updatedFluidConnection, + updateSgeStore, +} from 'store/global/global.actions' +import { getAddPicto, getParamPicto } from 'utils/picto' +import './konnectorViewerCard.scss' interface KonnectorViewerCardProps { fluidStatus: FluidStatus @@ -87,9 +85,11 @@ const KonnectorViewerCard: React.FC<KonnectorViewerCardProps> = ({ const konnector: Konnector | null = fluidStatus.connection.konnector const account: Account | null = fluidStatus.connection.account const trigger: Trigger | null = fluidStatus.connection.trigger - const { fluidStatus: statusArray, shouldRefreshConsent } = useSelector( - (state: AppStore) => state.ecolyo.global - ) + const { + fluidStatus: statusArray, + shouldRefreshConsent, + sgeConnect, + } = useSelector((state: AppStore) => state.ecolyo.global) const [openModal, setOpenModal] = useState(false) const [isUpdating, setIsUpdating] = useState(false) @@ -132,7 +132,7 @@ const KonnectorViewerCard: React.FC<KonnectorViewerCardProps> = ({ const _updatedFluidStatus: FluidStatus[] = await fluidService.getFluidStatus() setUpdatedFluidStatus(_updatedFluidStatus) - const refDate: DateTime = DateTime.fromISO('0001-01-01') + const refDate = DateTime.fromISO('0001-01-01') let _lastDataDate: DateTime | null = DateTime.fromISO('0001-01-01') for (const fluid of _updatedFluidStatus) { if (fluid && fluid?.lastDataDate && fluid?.lastDataDate > _lastDataDate) { @@ -347,11 +347,10 @@ const KonnectorViewerCard: React.FC<KonnectorViewerCardProps> = ({ const displayKonnectorIcon = useCallback(() => { return ( <div className="konnector-icon"> - {fluidStatus.connection.account ? ( - <Icon icon={iconType} size={49} /> - ) : ( - <Icon icon={iconAddType} size={49} /> - )} + <Icon + icon={fluidStatus.connection.account ? iconType : iconAddType} + size={49} + /> {fluidStatus.status === FluidState.PARTNER_ISSUE ? ( <StyledIcon icon={PartnersIssueNotif} @@ -395,7 +394,7 @@ const KonnectorViewerCard: React.FC<KonnectorViewerCardProps> = ({ </span> ) } else if (fluidStatus.connection.account && !isOutdatedData) { - return t('FLUID.' + FluidType[fluidStatus.fluidType] + '.LABEL') + return t(`FLUID.${FluidType[fluidStatus.fluidType]}.LABEL`) } else { return t( `konnector_options.label_connect_to_${FluidType[ @@ -423,6 +422,21 @@ const KonnectorViewerCard: React.FC<KonnectorViewerCardProps> = ({ deleteAccountForConsentRefresh() }, [account, client, handleAccountDeletion, shouldRefreshConsent]) + /** Closes SGE form if opened */ + const closeSGEForm = () => { + if (sgeConnect.openSGEForm) { + dispatch( + updateSgeStore({ + ...sgeConnect, + openSGEForm: false, + // switch to false in case the form fails and the user have to give its consent again + dataConsent: false, + pdlConfirm: false, + }) + ) + } + } + useEffect(() => { let subscribed = true async function getData() { @@ -438,6 +452,7 @@ const KonnectorViewerCard: React.FC<KonnectorViewerCardProps> = ({ const connectionFlow = new ConnectionFlow(client, trigger, konnector) await connectionFlow.launch() + closeSGEForm() connectionFlow.jobWatcher.on(ERROR_EVENT, () => { sendUsageEventError(fluidSlug, fluidStatus.lastDataDate === null) setKonnectorErrorDescription(connectionFlow.jobWatcher.on()._error) diff --git a/src/components/Navbar/navBar.scss b/src/components/Navbar/navBar.scss index eec9e331f0a42e72d97906fe970aa40d60de7d70..c65e38f0b3b078de768942f2148aa9ff90a78013 100644 --- a/src/components/Navbar/navBar.scss +++ b/src/components/Navbar/navBar.scss @@ -3,6 +3,7 @@ @import 'src/styles/base/z-index'; .o-sidebar { + width: 15%; background-color: $bottom-bar-grey; box-shadow: 0px 5px 5px rgba(0, 0, 0, 0.2), 0px 3px 14px rgba(0, 0, 0, 0.12), 0px 8px 10px rgba(0, 0, 0, 0.14); diff --git a/src/components/Routes/Routes.tsx b/src/components/Routes/Routes.tsx index 849967efedf6c84eb54c2adcf6bc48a99e99727d..2bcfc4fa87e609f8707a3e2d1711757bac39f4e2 100644 --- a/src/components/Routes/Routes.tsx +++ b/src/components/Routes/Routes.tsx @@ -1,17 +1,16 @@ -import React, { Suspense, lazy } from 'react' -import { Route, Switch, Redirect } from 'react-router-dom' -import { FluidType } from 'enum/fluid.enum' +import ActionView from 'components/Action/ActionView' import ChallengeView from 'components/Challenge/ChallengeView' import DuelView from 'components/Duel/DuelView' -import QuizView from 'components/Quiz/QuizView' +import EcogestureFormView from 'components/EcogestureForm/EcogestureFormView' +import EcogestureSelection from 'components/EcogestureSelection/EcogestureSelection' import ExplorationView from 'components/Exploration/ExplorationView' -import ActionView from 'components/Action/ActionView' import UnSubscribe from 'components/Options/Unsubscribe/UnSubscribe' +import QuizView from 'components/Quiz/QuizView' import TermsView from 'components/Terms/TermsView' +import { FluidType } from 'enum/fluid.enum' import { TermsStatus } from 'models' -import EcogestureFormView from 'components/EcogestureForm/EcogestureFormView' -import EcogestureSelection from 'components/EcogestureSelection/EcogestureSelection' -import SgeConnectView from 'components/Connection/SGEConnect/SgeConnectView' +import React, { lazy, Suspense } from 'react' +import { Redirect, Route, Switch } from 'react-router-dom' const ConsumptionView = lazy(() => import('components/Home/ConsumptionView')) @@ -59,7 +58,6 @@ const Routes: React.FC<RouteProps> = ({ termsStatus }: RouteProps) => { <ConsumptionView fluidType={FluidType.MULTIFLUID} /> </Route> - <Route path={`/sge-connect`} component={SgeConnectView} /> <Route path={`/challenges/duel`} component={DuelView} /> <Route path={`/challenges/quiz`} component={QuizView} /> <Route path={`/challenges/exploration`} component={ExplorationView} /> diff --git a/src/locales/fr.json b/src/locales/fr.json index df9681d7f780123a89eecffa6c3989afb85e524c..3a948a8c7fce48566e302c7326076ea47e69946e 100644 --- a/src/locales/fr.json +++ b/src/locales/fr.json @@ -1128,7 +1128,8 @@ "form": { "button_previous": "Précédent", "button_next": "Suivant", - "button_end": "Terminer" + "button_end": "Terminer", + "button_loading": "Chargement..." }, "finished": { "title": "Terminé !", diff --git a/src/models/sgeStore.model.ts b/src/models/sgeStore.model.ts index 59b30d9f42f3b5e912b4ad5b43838ce240e8f84e..9a28f5c6f7dea6cf4a652367323d7bcc8d156466 100644 --- a/src/models/sgeStore.model.ts +++ b/src/models/sgeStore.model.ts @@ -9,4 +9,5 @@ export interface SgeStore { dataConsent: boolean pdlConfirm: boolean shouldLaunchAccount: boolean + openSGEForm: boolean } diff --git a/src/services/profileType.service.spec.ts b/src/services/profileType.service.spec.ts index d13bb7b4ab16cbbedbb6096b582ee6cf8a204d94..01fbdce16b87e606f2121a3ca7d500b7b650f8b7 100644 --- a/src/services/profileType.service.spec.ts +++ b/src/services/profileType.service.spec.ts @@ -8,7 +8,9 @@ import { ThreeChoicesAnswer, WarmingType, } from 'enum/profileType.enum' +import { DateTime } from 'luxon' import { ProfileType } from 'models/profileType.model' +import mockClient from '../../tests/__mocks__/client' import { mockCorrectedConsumption, mockEstimatedConsumption, @@ -17,27 +19,25 @@ import { mockMonthConsumption1, mockMonthConsumption2, mockMonthCookingConsumption, - mockMonthElectricSpecificConsumption, mockMonthEcsConsumption1Solar, mockMonthEcsConsumptionOther, mockMonthEcsConsumptionThermo, + mockMonthElectricSpecificConsumption, + mockMonthlyForecastJanuaryTest1WithFullArrays, + mockMonthlyForecastJanuaryTestProfile1, + mockMonthlyForecastJanuaryTestProfile2, + mockMonthlyForecastJanuaryTestProfile3, mockProfileType, mockProfileType1, mockProfileType2, + mockProfileTypeAnswers, mockTestProfile1, mockTestProfile2, mockTestProfile3, - mockwaterRawNeeds, + mockWaterRawNeeds, mockWaterSpreadNeeds, - mockMonthlyForecastJanuaryTestProfile1, - mockMonthlyForecastJanuaryTestProfile2, - mockMonthlyForecastJanuaryTestProfile3, - mockProfileTypeAnswers, - mockMonthlyForecastJanuaryTest1WithFullArrays, } from '../../tests/__mocks__/profileType.mock' import ProfileTypeService from './profileType.service' -import mockClient from '../../tests/__mocks__/client' -import { DateTime } from 'luxon' import ProfileTypeFormService from './profileTypeForm.service' const wrongNumber = 99999 @@ -105,7 +105,7 @@ describe('ProfileType service', () => { mockProfileType, 1 ) - expect(waterRawNeeds).toEqual(mockwaterRawNeeds) + expect(waterRawNeeds).toEqual(mockWaterRawNeeds) }) it('should calculate the water spread needs Consumption', () => { diff --git a/src/store/global/global.actions.ts b/src/store/global/global.actions.ts index 49af36746e21f37acb0e68a5bd6bea35dd9a0b95..6ff372a55663811313847ddbe8a954c5c0e4fec2 100644 --- a/src/store/global/global.actions.ts +++ b/src/store/global/global.actions.ts @@ -80,7 +80,7 @@ interface SetShouldRefreshConsent { type: typeof SET_SHOULD_REFRESH_CONSENT payload?: boolean } -interface UpdateSGEConnect { +export interface UpdateSGEConnect { type: typeof UPDATE_SGE_CONNECT payload?: SgeStore } diff --git a/src/store/global/global.reducer.spec.ts b/src/store/global/global.reducer.spec.ts index b2fcbc29422955ce7a94b48902f5422d87921056..2ae4d0412ee7e8a07232de091fd43b9304868c08 100644 --- a/src/store/global/global.reducer.spec.ts +++ b/src/store/global/global.reducer.spec.ts @@ -1,22 +1,23 @@ -import { globalReducer } from './global.reducer' +import { FluidState, FluidType } from 'enum/fluid.enum' +import { FluidSlugType } from 'enum/fluidSlug.enum' +import { ScreenType } from 'enum/screen.enum' +import { DateTime } from 'luxon' +import { FluidStatus } from 'models' +import { accountsData } from '../../../tests/__mocks__/accountsData.mock' +import { mockCustomPopup } from '../../../tests/__mocks__/customPopup.mock' +import { konnectorsData } from '../../../tests/__mocks__/konnectorsData.mock' +import { mockInitialGlobalState } from '../../../tests/__mocks__/store' +import { triggersData } from '../../../tests/__mocks__/triggersData.mock' import { CHANGE_SCREEN_TYPE, - TOGGLE_CHALLENGE_EXPLORATION_NOTIFICATION, + SET_CUSTOM_POPUP, + SET_FLUID_STATUS, + TOGGLE_ANALYSIS_NOTIFICATION, TOGGLE_CHALLENGE_ACTION_NOTIFICATION, TOGGLE_CHALLENGE_DUEL_NOTIFICATION, - TOGGLE_ANALYSIS_NOTIFICATION, - SET_FLUID_STATUS, - SET_CUSTOM_POPUP, + TOGGLE_CHALLENGE_EXPLORATION_NOTIFICATION, } from './global.actions' -import { ScreenType } from 'enum/screen.enum' -import { FluidStatus } from 'models' -import { FluidState, FluidType } from 'enum/fluid.enum' -import { DateTime } from 'luxon' -import { konnectorsData } from '../../../tests/__mocks__/konnectorsData.mock' -import { accountsData } from '../../../tests/__mocks__/accountsData.mock' -import { triggersData } from '../../../tests/__mocks__/triggersData.mock' -import { mockInitialGlobalState } from '../../../tests/__mocks__/store' -import { mockCustomPopup } from '../../../tests/__mocks__/customPopup.mock' +import { globalReducer } from './global.reducer' const mockDataDates: (DateTime | null)[] = [ DateTime.local().setZone('utc', { @@ -143,7 +144,7 @@ describe('global reducer', () => { konnectorConfig: { name: 'Enedis', oauth: true, - slug: 'enedissgegrandlyon', + slug: FluidSlugType.ELECTRICITY, siteLink: 'https://mon-compte-particulier.enedis.fr/donnees/', activation: 'https://mon-compte-particulier.enedis.fr/donnees/', }, @@ -164,7 +165,7 @@ describe('global reducer', () => { konnectorConfig: { name: 'Eau du Grand Lyon', oauth: false, - slug: 'eglgrandlyon', + slug: FluidSlugType.WATER, siteLink: 'https://agence.eaudugrandlyon.com/inscription.aspx#subc-now', activation: '', @@ -186,7 +187,7 @@ describe('global reducer', () => { konnectorConfig: { name: 'GRDF', oauth: true, - slug: 'grdfgrandlyon', + slug: FluidSlugType.GAS, siteLink: 'https://monespace.grdf.fr/monespace/connexion', activation: '', }, diff --git a/src/store/global/global.reducer.ts b/src/store/global/global.reducer.ts index 855bf9ac131cefac73ba9650fd104a5fbd06a727..9a1e0abd4f9a655b6ad10201660e6203f8321d83 100644 --- a/src/store/global/global.reducer.ts +++ b/src/store/global/global.reducer.ts @@ -109,6 +109,7 @@ const initialState: GlobalState = { popupEnabled: false, title: '', description: '', + endDate: '', }, openPartnersIssueModal: false, shouldRefreshConsent: false, @@ -123,6 +124,7 @@ const initialState: GlobalState = { dataConsent: false, pdlConfirm: false, shouldLaunchAccount: false, + openSGEForm: false, }, } diff --git a/src/store/index.ts b/src/store/index.ts index c7e28758b3055e2cb11a7fe17c3a8a3784788f71..103f7e398aa28c36dcc79da2260c3faae486c129 100644 --- a/src/store/index.ts +++ b/src/store/index.ts @@ -1,30 +1,30 @@ +import * as Sentry from '@sentry/react' +import { Client } from 'cozy-client' +import { + ChallengeState, + GlobalState, + ModalState, + Profile, + ProfileType, +} from 'models' +import { ChartState } from 'models/chart.model' +import { ProfileEcogesture } from 'models/profileEcogesture.model' import { - createStore, - combineReducers, applyMiddleware, + combineReducers, compose, + createStore, Store, } from 'redux' -import thunkMiddleware from 'redux-thunk' import { composeWithDevTools } from 'redux-devtools-extension' +import thunkMiddleware from 'redux-thunk' import { globalReducer } from 'store/global/global.reducer' -import { profileReducer } from './profile/profile.reducer' -import { profileTypeReducer } from './profileType/profileType.reducer' -import { chartReducer } from './chart/chart.reducer' import { modalReducer } from 'store/modal/modal.reducer' import { challengeReducer } from './challenge/challenge.reducer' -import { - GlobalState, - ModalState, - Profile, - ChallengeState, - ProfileType, -} from 'models' -import { ChartState } from 'models/chart.model' -import { Client } from 'cozy-client' -import { ProfileEcogesture } from 'models/profileEcogesture.model' +import { chartReducer } from './chart/chart.reducer' +import { profileReducer } from './profile/profile.reducer' import { profileEcogestureReducer } from './profileEcogesture/profileEcogesture.reducer' -import * as Sentry from '@sentry/react' +import { profileTypeReducer } from './profileType/profileType.reducer' export interface EcolyoState { global: GlobalState @@ -58,7 +58,7 @@ const configureStore = ( persistedState: any ): Store<AppStore> => { const middlewares = [thunkMiddleware.withExtraArgument({ client })] - const composeEnhancers = composeWithDevTools || compose + const composeEnhancers = composeWithDevTools({ trace: true }) || compose const store: Store<AppStore> = createStore( combineReducers({ diff --git a/tests/__mocks__/accountsData.mock.ts b/tests/__mocks__/accountsData.mock.ts index 7b0a6ea948ef619c4360e29ea7525413433db07e..7775e8b618daa1705c820cedd3c6ce13ca193a9b 100644 --- a/tests/__mocks__/accountsData.mock.ts +++ b/tests/__mocks__/accountsData.mock.ts @@ -8,7 +8,7 @@ export const accountsData: Account[] = [ account_type: 'enedissgegrandlyon', name: '', oauth: { - access_token: 'MY_ACCESS_TOCKEN', + access_token: 'MY_ACCESS_TOKEN', expires_at: '2020-10-09T08:00:00.285910671+02:00', refresh_token: '', token_type: 'Bearer', @@ -16,7 +16,7 @@ export const accountsData: Account[] = [ oauth_callback_results: { issued_at: '1592232569642', refresh_token_issued_at: '1592232569642', - scope: '/my_eneids_scope', + scope: '/my_enedis_scope', usage_points_id: '', }, cozyMetadata: { @@ -52,13 +52,13 @@ export const accountsData: Account[] = [ account_type: 'grdfgrandlyon', name: '', oauth: { - access_token: 'MY_ACCESS_TOCKEN', + access_token: 'MY_ACCESS_TOKEN', expires_at: '2020-10-09T08:00:00.285910671+02:00', refresh_token: '', token_type: 'Bearer', }, oauth_callback_results: { - id_token: 'MY_ID_TOCKEN', + id_token: 'MY_ID_TOKEN', pce: '12345678987654', scope: '/my_grdf_scope', }, diff --git a/tests/__mocks__/explorationData.mock.ts b/tests/__mocks__/explorationData.mock.ts index dbc5c702d614817a7284f879841a0df6991b7d40..75e71ac1a5bccf66d8915c80f3003ff2ebfe1867 100644 --- a/tests/__mocks__/explorationData.mock.ts +++ b/tests/__mocks__/explorationData.mock.ts @@ -21,7 +21,7 @@ export const explorationEntity: ExplorationEntity = { export const explorationEntity4: ExplorationEntity = { id: 'EXPLORATION004', state: UserExplorationState.UNLOCKED, - description: 'Dévérouiller les données électricité à la demi-heure', + description: 'Déverrouiller les données électricité à la demi-heure', complementary_description: 'Consulter les données à la demi-heure si déjà fait', target: 1, @@ -30,7 +30,7 @@ export const explorationEntity4: ExplorationEntity = { ecogesture_id: '', fluid_condition: [0], message_success: - 'Vous avez dévérrouillé les données électricité à la demi-heure', + 'Vous avez déverrouillé les données électricité à la demi-heure', } export const explorationEntity4_0: ExplorationEntity = { id: 'EXPLORATION004_0', @@ -89,7 +89,7 @@ export const userExploration1: UserExploration = { export const userExploration4: UserExploration = { id: 'EXPLORATION004', state: 0, - description: 'Dévérrouillez les données électricité à la demi-heure', + description: 'Déverrouillez les données électricité à la demi-heure', complementary_description: 'Consulter les données à la demi-heure si déjà fait', target: 1, @@ -99,7 +99,7 @@ export const userExploration4: UserExploration = { fluid_condition: [0], progress: 0, message_success: - 'Vous avez dévérrouillé les données électricité à la demi-heure', + 'Vous avez déverrouillé les données électricité à la demi-heure', } export const userExploration4_0: UserExploration = { id: 'EXPLORATION004_0', @@ -155,7 +155,7 @@ export const allExplorationEntities: ExplorationEntity[] = [ { id: 'EXPLORATION004', state: 0, - description: 'Dévérrouillez les données électricité à la demi-heure', + description: 'Déverrouillez les données électricité à la demi-heure', complementary_description: 'Consulter les données à la demi-heure si déjà fait', target: 1, @@ -164,7 +164,7 @@ export const allExplorationEntities: ExplorationEntity[] = [ ecogesture_id: '', fluid_condition: [0], message_success: - 'Vous avez consulté ou déverouillé les données électricité à la demi-heure', + 'Vous avez consulté ou déverrouillé les données électricité à la demi-heure', }, { id: 'EXPLORATION005', diff --git a/tests/__mocks__/fluidStatusData.mock.ts b/tests/__mocks__/fluidStatusData.mock.ts index e9c340eba480380d237fdcc29665989eeab09d5b..b86ae51b88dc694cabb41b74bc34fe2426c17f26 100644 --- a/tests/__mocks__/fluidStatusData.mock.ts +++ b/tests/__mocks__/fluidStatusData.mock.ts @@ -183,7 +183,7 @@ export const fluidStatusConnectedData: FluidStatus[] = [ }, }, ] -export const SgeStatusWithAccout: FluidStatus = { +export const SgeStatusWithAccount: FluidStatus = { fluidType: 0, status: FluidState.KONNECTOR_NOT_FOUND, firstDataDate: DateTime.fromISO('2019-09-01T00:00:00.000Z', { @@ -202,7 +202,7 @@ export const SgeStatusWithAccout: FluidStatus = { account_type: 'enedissgegrandlyon', name: '', oauth: { - access_token: 'MY_ACCESS_TOCKEN', + access_token: 'MY_ACCESS_TOKEN', expires_at: '2020-10-09T08:00:00.285910671+02:00', refresh_token: '', token_type: 'Bearer', @@ -210,7 +210,7 @@ export const SgeStatusWithAccout: FluidStatus = { oauth_callback_results: { issued_at: '1592232569642', refresh_token_issued_at: '1592232569642', - scope: '/my_eneids_scope', + scope: '/my_enedis_scope', usage_points_id: '', }, cozyMetadata: { diff --git a/tests/__mocks__/globalStateData.mock.ts b/tests/__mocks__/globalStateData.mock.ts index 7f57f724b5cd20c78232b43538a5eff0c8dcd535..e2719ba60d8667a480ca1928c0c42066db653bc6 100644 --- a/tests/__mocks__/globalStateData.mock.ts +++ b/tests/__mocks__/globalStateData.mock.ts @@ -96,5 +96,12 @@ export const globalStateData: GlobalState = { dataConsent: false, pdlConfirm: false, shouldLaunchAccount: false, + openSGEForm: false, + }, + customPopupModal: { + title: '', + description: '', + popupEnabled: false, + endDate: '', }, } diff --git a/tests/__mocks__/profileType.mock.ts b/tests/__mocks__/profileType.mock.ts index 7262c68221dc88bd38669be611993480d7f97eb0..053abe45a2c98527349079023bf15af26b70a2a3 100644 --- a/tests/__mocks__/profileType.mock.ts +++ b/tests/__mocks__/profileType.mock.ts @@ -77,7 +77,7 @@ export const mockMonthCookingConsumption = 17 export const mockMonthElectricSpecificConsumption = 175 export const mockMonthColdWaterConsumption = 4247 -export const mockwaterRawNeeds = 2480 +export const mockWaterRawNeeds = 2480 export const mockWaterSpreadNeeds = 2701 export const mockMonthEcsConsumptionOther = 166 export const mockMonthEcsConsumptionThermo = 110 @@ -106,7 +106,7 @@ export const mockProfileType1: ProfileType = { } export const mockEstimatedConsumption1 = 6450 export const mockCorrectedConsumption1 = 6450 -//For the month of february +//For the month of February export const mockMonthConsumption1 = 1174 export const mockMonthEcsConsumption1Solar = 134 @@ -135,7 +135,7 @@ export const mockProfileType2: ProfileType = { } export const mockEstimatedConsumption2 = 16560 export const mockCorrectedConsumption2 = 15411 -//For the month of january +//For the month of January export const mockMonthConsumption2 = 3000 export const mockTestProfile1: ProfileType = { diff --git a/tests/__mocks__/store.ts b/tests/__mocks__/store.ts index f6b9cea2d9ceb8eb592d85cd37c00310c98d3931..bf2cf076c7f5472a94546bf3d2ad88658e969afd 100644 --- a/tests/__mocks__/store.ts +++ b/tests/__mocks__/store.ts @@ -43,6 +43,7 @@ export const mockInitialGlobalState: GlobalState = { popupEnabled: false, title: '', description: '', + endDate: '', }, openPartnersIssueModal: false, releaseNotes: { @@ -127,6 +128,7 @@ export const mockInitialGlobalState: GlobalState = { pdlConfirm: false, zipCode: null, shouldLaunchAccount: false, + openSGEForm: false, }, } export const mockExpiredElec: FluidStatus = { @@ -277,8 +279,10 @@ export const mockInitialEcolyoState = { } const middlewares = [thunkMiddleware.withExtraArgument({ mockClient })] -const mockStore = configureStore(middlewares) -const mockedStore: any = mockStore({ +const mockStore = configureStore<{ ecolyo: { global: GlobalState } }>( + middlewares +) +const mockedStore = mockStore({ ecolyo: mockInitialEcolyoState, }) diff --git a/tests/__mocks__/triggerStateData.mock.ts b/tests/__mocks__/triggerStateData.mock.ts index cb7db8fd0f7ef966313941d513a694a2a141d51c..b07bc01e16e60be62e70d63317504d38b9c6eb75 100644 --- a/tests/__mocks__/triggerStateData.mock.ts +++ b/tests/__mocks__/triggerStateData.mock.ts @@ -1,4 +1,4 @@ -/* eslint-disable @typescript-eslint/camelcase */ +/* eslint-disable camelcase */ import { TriggerState } from 'models' export const triggerStateData: TriggerState = { diff --git a/tests/__mocks__/userChallengeData.mock.ts b/tests/__mocks__/userChallengeData.mock.ts index b250eca1efeb87dba5bf98744ba0a02e3ad1fa00..ba363b126a758d8362d9fc85a19427da31a3a84a 100644 --- a/tests/__mocks__/userChallengeData.mock.ts +++ b/tests/__mocks__/userChallengeData.mock.ts @@ -349,7 +349,7 @@ export const userChallengeExplo4: UserChallenge = { exploration: { id: 'EXPLORATION004', state: 0, - description: 'Dévérrouillez les données électricité à la demi-heure', + description: 'Déverrouillez les données électricité à la demi-heure', complementary_description: 'Consulter les données à la demi-heure si déjà fait', target: 1,