Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found
Select Git revision
  • build
  • build-dev
  • build-test
  • dev
  • lint/testing-libraby-plugin
  • master
  • renovate/copy-webpack-plugin-13.x
  • renovate/couchdb-3.x
  • renovate/cozy-client-49.x
  • renovate/cozy-device-helper-3.x
  • renovate/cozy-flags-4.x
  • renovate/cozy-harvest-lib-32.x
  • renovate/cozy-harvest-lib-9.x
  • renovate/cozy-realtime-5.x
  • renovate/cozy-scripts-8.x
  • renovate/devdependencies-(non-major)
  • renovate/eslint-9.x
  • renovate/eslint-config-prettier-10.x
  • renovate/eslint-plugin-testing-library-7.x
  • renovate/major-react-monorepo
  • renovate/major-react-router-monorepo
  • renovate/major-typescript-eslint-monorepo
  • renovate/react-19.x
  • renovate/react-dom-19.x
  • renovate/react-inspector-6.x
  • renovate/sass-loader-16.x
  • 0.1.0
  • 0.1.1
  • 0.1.2
  • 0.1.6
  • 0.1.7
  • 1.0.2
  • 1.0.3
  • 1.0.5
  • 1.0.6
  • 1.0.7
  • 1.0.8
  • 1.0.9
  • 1.1.0
  • 1.2.0
  • 1.2.1
  • 1.2.4-beta.1
  • V1.11.0
  • v1.10.0
  • v1.10.1
  • v1.10.2
  • v1.12.0
  • v1.12.1
  • v1.2.0
  • v1.2.1
  • v1.2.2
  • v1.2.3
  • v1.2.4
  • v1.2.4-beta.1
  • v1.3.0
  • v1.4.0
  • v1.4.1
  • v1.4.2
  • v1.4.3
  • v1.4.4
  • v1.5.0
  • v1.5.1
  • v1.6.0
  • v1.6.1
  • v1.6.2
  • v1.6.3
  • v1.6.4
  • v1.6.5
  • v1.7.0
  • v1.7.1
  • v1.7.2
  • v1.7.3
  • v1.7.4
  • v1.8.0
  • v1.8.1
  • v1.8.2
  • v1.8.3
  • v1.9.0
  • v1.9.1
  • v1.9.2
  • v1.9.3
  • v1.9.4
  • v2.0.0
  • v2.0.1
  • v2.0.2
  • v2.1.0
  • v2.1.1
  • v2.2.0
  • v2.2.1
  • v2.2.2
  • v2.3.0
  • v2.3.1
  • v2.4.0
  • v2.5.0
  • v2.5.1
  • v2.6.0
  • v2.7.0
  • v2.7.1
  • v2.7.2
  • v2.8.0
  • v3.0.0
  • v3.1.0
  • v3.1.1
103 results

Target

Select target project
  • web-et-numerique/factory/llle_project/ecolyo
1 result
Select Git revision
  • build
  • build-dev
  • build-test
  • dev
  • lint/testing-libraby-plugin
  • master
  • renovate/copy-webpack-plugin-13.x
  • renovate/couchdb-3.x
  • renovate/cozy-client-49.x
  • renovate/cozy-device-helper-3.x
  • renovate/cozy-flags-4.x
  • renovate/cozy-harvest-lib-32.x
  • renovate/cozy-harvest-lib-9.x
  • renovate/cozy-realtime-5.x
  • renovate/cozy-scripts-8.x
  • renovate/devdependencies-(non-major)
  • renovate/eslint-9.x
  • renovate/eslint-config-prettier-10.x
  • renovate/eslint-plugin-testing-library-7.x
  • renovate/major-react-monorepo
  • renovate/major-react-router-monorepo
  • renovate/major-typescript-eslint-monorepo
  • renovate/react-19.x
  • renovate/react-dom-19.x
  • renovate/react-inspector-6.x
  • renovate/sass-loader-16.x
  • 0.1.0
  • 0.1.1
  • 0.1.2
  • 0.1.6
  • 0.1.7
  • 1.0.2
  • 1.0.3
  • 1.0.5
  • 1.0.6
  • 1.0.7
  • 1.0.8
  • 1.0.9
  • 1.1.0
  • 1.2.0
  • 1.2.1
  • 1.2.4-beta.1
  • V1.11.0
  • v1.10.0
  • v1.10.1
  • v1.10.2
  • v1.12.0
  • v1.12.1
  • v1.2.0
  • v1.2.1
  • v1.2.2
  • v1.2.3
  • v1.2.4
  • v1.2.4-beta.1
  • v1.3.0
  • v1.4.0
  • v1.4.1
  • v1.4.2
  • v1.4.3
  • v1.4.4
  • v1.5.0
  • v1.5.1
  • v1.6.0
  • v1.6.1
  • v1.6.2
  • v1.6.3
  • v1.6.4
  • v1.6.5
  • v1.7.0
  • v1.7.1
  • v1.7.2
  • v1.7.3
  • v1.7.4
  • v1.8.0
  • v1.8.1
  • v1.8.2
  • v1.8.3
  • v1.9.0
  • v1.9.1
  • v1.9.2
  • v1.9.3
  • v1.9.4
  • v2.0.0
  • v2.0.1
  • v2.0.2
  • v2.1.0
  • v2.1.1
  • v2.2.0
  • v2.2.1
  • v2.2.2
  • v2.3.0
  • v2.3.1
  • v2.4.0
  • v2.5.0
  • v2.5.1
  • v2.6.0
  • v2.7.0
  • v2.7.1
  • v2.7.2
  • v2.8.0
  • v3.0.0
  • v3.1.0
  • v3.1.1
103 results
Show changes
Commits on Source (6)
Showing
with 254 additions and 184 deletions
module.exports = { module.exports = {
plugins: [
'@typescript-eslint',
'react',
'react-hooks',
'jest',
'jsx-a11y',
'@eslint-react/eslint-plugin',
],
extends: [ extends: [
'eslint:recommended', 'eslint:recommended',
'plugin:react/recommended', // Uses the recommended rules from @eslint-plugin-react 'plugin:react/recommended', // Uses the recommended rules from @eslint-plugin-react
...@@ -15,6 +23,8 @@ module.exports = { ...@@ -15,6 +23,8 @@ module.exports = {
'plugin:@typescript-eslint/recommended', 'plugin:@typescript-eslint/recommended',
// Stylistic rule configurations, for consistent and predictable syntax usage // Stylistic rule configurations, for consistent and predictable syntax usage
'plugin:@typescript-eslint/stylistic-type-checked', 'plugin:@typescript-eslint/stylistic-type-checked',
// Eslint React plugin
'plugin:@eslint-react/recommended-legacy',
], ],
files: ['**/*.{ts,tsx}'], files: ['**/*.{ts,tsx}'],
parserOptions: { parserOptions: {
...@@ -61,6 +71,13 @@ module.exports = { ...@@ -61,6 +71,13 @@ module.exports = {
// Note: you must disable the base rule as it can report incorrect errors // Note: you must disable the base rule as it can report incorrect errors
'require-await': 'off', 'require-await': 'off',
'@typescript-eslint/require-await': 'error', '@typescript-eslint/require-await': 'error',
// disable recommandations
'@eslint-react/hooks-extra/no-redundant-custom-hook': 0, // great rule but should not be run in tests files
'@eslint-react/hooks-extra/no-direct-set-state-in-use-effect': 0, // to enable in another MR will have a lot of impact
'@eslint-react/dom/no-dangerously-set-innerhtml': 0, // used for for injecting html tags
'@eslint-react/no-array-index-key': 0,
'@eslint-react/no-unused-class-component-members': 0, // disabled for ".d.ts" files
}, },
}, },
{ {
...@@ -71,7 +88,6 @@ module.exports = { ...@@ -71,7 +88,6 @@ module.exports = {
}, },
}, },
], ],
plugins: ['@typescript-eslint', 'react', 'react-hooks', 'jest', 'jsx-a11y'],
parser: '@typescript-eslint/parser', // Specifies the ESLint parser parser: '@typescript-eslint/parser', // Specifies the ESLint parser
parserOptions: { parserOptions: {
ecmaVersion: 2020, // Allows for the parsing of modern ECMAScript features ecmaVersion: 2020, // Allows for the parsing of modern ECMAScript features
......
...@@ -46,6 +46,7 @@ const ChallengeCard = ({ ...@@ -46,6 +46,7 @@ const ChallengeCard = ({
return ( return (
<button <button
type="button"
aria-label={t('challenge.card.goto')} aria-label={t('challenge.card.goto')}
onClick={() => moveToSlide(index)} onClick={() => moveToSlide(index)}
className={indexSlider === index ? 'slide active' : 'slide inactive'} className={indexSlider === index ? 'slide active' : 'slide inactive'}
......
...@@ -6,6 +6,7 @@ exports[`ChallengeCard component should be rendered correctly 1`] = ` ...@@ -6,6 +6,7 @@ exports[`ChallengeCard component should be rendered correctly 1`] = `
aria-label="challenge.card.goto" aria-label="challenge.card.goto"
class="slide active" class="slide active"
style="min-width: 200px; max-width: 200px; min-height: 400px; background: none; padding: 0px;" style="min-width: 200px; max-width: 200px; min-height: 400px; background: none; padding: 0px;"
type="button"
> >
<div <div
class="cardContent cardDone" class="cardContent cardDone"
......
...@@ -68,7 +68,7 @@ describe('ExpiredConsentModal component', () => { ...@@ -68,7 +68,7 @@ describe('ExpiredConsentModal component', () => {
await act(async () => { await act(async () => {
await userEvent.click(screen.getByText('consent_outdated.yes')) await userEvent.click(screen.getByText('consent_outdated.yes'))
}) })
expect(mockAppDispatch).toHaveBeenCalledTimes(2) expect(mockAppDispatch).toHaveBeenCalledTimes(1)
expect(mockedNavigate).toHaveBeenCalledTimes(1) expect(mockedNavigate).toHaveBeenCalledTimes(1)
}) })
it('should click on close modal', async () => { it('should click on close modal', async () => {
......
...@@ -7,14 +7,10 @@ import StyledIcon from 'components/CommonKit/Icon/StyledIcon' ...@@ -7,14 +7,10 @@ import StyledIcon from 'components/CommonKit/Icon/StyledIcon'
import StyledIconButton from 'components/CommonKit/IconButton/StyledIconButton' import StyledIconButton from 'components/CommonKit/IconButton/StyledIconButton'
import { useI18n } from 'cozy-ui/transpiled/react/providers/I18n' import { useI18n } from 'cozy-ui/transpiled/react/providers/I18n'
import { FluidType } from 'enums' import { FluidType } from 'enums'
import { AccountSgeData } from 'models'
import React, { useCallback } from 'react' import React, { useCallback } from 'react'
import { useNavigate } from 'react-router-dom' import { useNavigate } from 'react-router-dom'
import { import { setShouldRefreshConsent } from 'store/global/global.slice'
setShouldRefreshConsent, import { useAppDispatch } from 'store/hooks'
updateSgeStore,
} from 'store/global/global.slice'
import { useAppDispatch, useAppSelector } from 'store/hooks'
import { getFluidName } from 'utils/utils' import { getFluidName } from 'utils/utils'
import './expiredConsentModal.scss' import './expiredConsentModal.scss'
...@@ -34,26 +30,8 @@ const ExpiredConsentModal = ({ ...@@ -34,26 +30,8 @@ const ExpiredConsentModal = ({
const { t } = useI18n() const { t } = useI18n()
const navigate = useNavigate() const navigate = useNavigate()
const dispatch = useAppDispatch() const dispatch = useAppDispatch()
const { fluidStatus } = useAppSelector(state => state.ecolyo.global)
const launchUpdateConsent = useCallback(() => { const launchUpdateConsent = useCallback(() => {
if (fluidType === FluidType.ELECTRICITY) { 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)) dispatch(setShouldRefreshConsent(true))
toggleModal() toggleModal()
navigate(`/consumption/${FluidType[fluidType].toLocaleLowerCase()}`) navigate(`/consumption/${FluidType[fluidType].toLocaleLowerCase()}`)
...@@ -62,7 +40,7 @@ const ExpiredConsentModal = ({ ...@@ -62,7 +40,7 @@ const ExpiredConsentModal = ({
toggleModal() toggleModal()
navigate(`/connect/${FluidType[fluidType].toLocaleLowerCase()}`) navigate(`/connect/${FluidType[fluidType].toLocaleLowerCase()}`)
} }
}, [dispatch, fluidStatus, fluidType, navigate, toggleModal]) }, [dispatch, fluidType, navigate, toggleModal])
return ( return (
<Dialog <Dialog
......
...@@ -5,12 +5,15 @@ import CozyBar from 'components/Header/CozyBar' ...@@ -5,12 +5,15 @@ import CozyBar from 'components/Header/CozyBar'
import Header from 'components/Header/Header' import Header from 'components/Header/Header'
import useKonnectorAuth from 'components/Hooks/useKonnectorAuth' import useKonnectorAuth from 'components/Hooks/useKonnectorAuth'
import useUserInstanceSettings from 'components/Hooks/useUserInstanceSettings' import useUserInstanceSettings from 'components/Hooks/useUserInstanceSettings'
import { useClient } from 'cozy-client'
import { FORM_DOCTYPE } from 'doctypes'
import { FluidType } from 'enums' import { FluidType } from 'enums'
import { AccountGRDFData } from 'models' import { AccountGRDFData } from 'models'
import React, { useCallback, useEffect, useRef, useState } from 'react' import React, { useCallback, useEffect, useRef, useState } from 'react'
import { useNavigate } from 'react-router-dom' import { useNavigate } from 'react-router-dom'
import { useAppSelector } from 'store/hooks' import { useAppSelector } from 'store/hooks'
import '../connection.scss' import '../connection.scss'
import { createInitialGrdfState, useFormData } from '../useForm'
import StepConsent from './StepConsent' import StepConsent from './StepConsent'
import { StepIdentity } from './StepIdentity' import { StepIdentity } from './StepIdentity'
...@@ -18,11 +21,14 @@ export enum GrdfStep { ...@@ -18,11 +21,14 @@ export enum GrdfStep {
Identity, Identity,
Consent, Consent,
} }
/** /**
* http://ecolyo.cozy.tools:8080/#/connect/gas * http://ecolyo.cozy.tools:8080/#/connect/gas
*/ */
export const GrdfConnectView = () => { export const GrdfConnectView = () => {
const client = useClient()
const navigate = useNavigate() const navigate = useNavigate()
const { formData } = useFormData()
const { instanceSettings } = useUserInstanceSettings() const { instanceSettings } = useUserInstanceSettings()
const { fluidStatus } = useAppSelector(state => state.ecolyo.global) const { fluidStatus } = useAppSelector(state => state.ecolyo.global)
const currentFluidStatus = fluidStatus[FluidType.GAS] const currentFluidStatus = fluidStatus[FluidType.GAS]
...@@ -30,13 +36,9 @@ export const GrdfConnectView = () => { ...@@ -30,13 +36,9 @@ export const GrdfConnectView = () => {
const [launchConnection, setLaunchConnection] = useState(false) const [launchConnection, setLaunchConnection] = useState(false)
const [currentStep, setCurrentStep] = useState<GrdfStep>(GrdfStep.Identity) const [currentStep, setCurrentStep] = useState<GrdfStep>(GrdfStep.Identity)
const [formData, setFormData] = useState<AccountGRDFData>({ const [grdfState, setGrdfState] = useState<AccountGRDFData>(
lastname: '', createInitialGrdfState()
firstname: '', )
email: '',
postalCode: '',
pce: '',
})
const [formConsent, setFormConsent] = useState({ const [formConsent, setFormConsent] = useState({
dataConsent: false, dataConsent: false,
pceConfirm: false, pceConfirm: false,
...@@ -48,23 +50,27 @@ export const GrdfConnectView = () => { ...@@ -48,23 +50,27 @@ export const GrdfConnectView = () => {
} }
const [connect, update] = useKonnectorAuth(FluidType.GAS, { const [connect, update] = useKonnectorAuth(FluidType.GAS, {
grdfAuthData: formData, grdfAuthData: grdfState,
}) })
useEffect(() => { useEffect(() => {
setFormData(prev => ({ ...prev, email: instanceSettings.email ?? '' })) setGrdfState(prev => ({
}, [instanceSettings]) ...prev,
...createInitialGrdfState(formData),
email: instanceSettings.email ?? '',
}))
}, [instanceSettings, formData])
useEffect(() => { useEffect(() => {
async function launchConnect() { async function launchConnect() {
if (launchConnection) { if (launchConnection) {
setLaunchConnection(false)
if (!account) { if (!account) {
await connect() await connect()
} else { } else {
await update() await update()
} }
setLaunchConnection(false)
navigate('/consumption/gas') navigate('/consumption/gas')
} }
} }
...@@ -74,11 +80,11 @@ export const GrdfConnectView = () => { ...@@ -74,11 +80,11 @@ export const GrdfConnectView = () => {
const isNextValid = useCallback(() => { const isNextValid = useCallback(() => {
if (currentStep === GrdfStep.Identity) { if (currentStep === GrdfStep.Identity) {
return ( return (
formData.firstname !== '' && grdfState.firstname !== '' &&
formData.lastname !== '' && grdfState.lastname !== '' &&
formData.postalCode !== '' && grdfState.postalCode !== '' &&
formData.email.includes('@') && grdfState.email.includes('@') &&
formData.pce.length === 14 grdfState.pce.length === 14
) )
} else if (currentStep === GrdfStep.Consent) { } else if (currentStep === GrdfStep.Consent) {
return formConsent.dataConsent && formConsent.pceConfirm return formConsent.dataConsent && formConsent.pceConfirm
...@@ -88,23 +94,40 @@ export const GrdfConnectView = () => { ...@@ -88,23 +94,40 @@ export const GrdfConnectView = () => {
currentStep, currentStep,
formConsent.dataConsent, formConsent.dataConsent,
formConsent.pceConfirm, formConsent.pceConfirm,
formData.email, grdfState.email,
formData.firstname, grdfState.firstname,
formData.lastname, grdfState.lastname,
formData.pce, grdfState.pce,
formData.postalCode, grdfState.postalCode,
]) ])
const handleNext = useCallback(() => { const handleNext = useCallback(() => {
if (!isNextValid()) return if (!isNextValid()) return
if (currentStep < GrdfStep.Consent) { if (currentStep < GrdfStep.Consent) {
setCurrentStep(prev => prev + 1) 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) { if (currentStep === GrdfStep.Consent) {
setLaunchConnection(true) setLaunchConnection(true)
} }
focusMainContent() focusMainContent()
}, [currentStep, isNextValid]) }, [
client,
currentStep,
formData,
grdfState.firstname,
grdfState.lastname,
grdfState.pce,
grdfState.postalCode,
isNextValid,
])
const handlePrev = () => { const handlePrev = () => {
setCurrentStep(prev => prev - 1) setCurrentStep(prev => prev - 1)
...@@ -113,7 +136,7 @@ export const GrdfConnectView = () => { ...@@ -113,7 +136,7 @@ export const GrdfConnectView = () => {
const renderStep = (step: GrdfStep) => { const renderStep = (step: GrdfStep) => {
if (step === GrdfStep.Identity) { if (step === GrdfStep.Identity) {
return <StepIdentity formData={formData} setFormData={setFormData} /> return <StepIdentity formData={grdfState} setFormData={setGrdfState} />
} else { } else {
return ( return (
<StepConsent <StepConsent
......
import { render, screen } from '@testing-library/react' import { render, screen } from '@testing-library/react'
import { SgeStore } from 'models'
import React from 'react' import React from 'react'
import { Provider } from 'react-redux' import { Provider } from 'react-redux'
import { BrowserRouter } from 'react-router-dom' import { BrowserRouter } from 'react-router-dom'
...@@ -18,6 +19,23 @@ jest.mock('components/Hooks/useKonnectorAuth', () => ...@@ -18,6 +19,23 @@ jest.mock('components/Hooks/useKonnectorAuth', () =>
jest.fn(() => [mockConnect, mockUpdate]) 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', () => { describe('SgeConnectView component', () => {
beforeEach(() => { beforeEach(() => {
jest.clearAllMocks() jest.clearAllMocks()
...@@ -57,16 +75,6 @@ describe('SgeConnectView component', () => { ...@@ -57,16 +75,6 @@ describe('SgeConnectView component', () => {
describe('should test methods from useKonnectorAuth hook', () => { describe('should test methods from useKonnectorAuth hook', () => {
it('should launch account and trigger creation process', () => { it('should launch account and trigger creation process', () => {
const store = createMockEcolyoStore({
global: {
...mockGlobalState,
sgeConnect: {
...mockGlobalState.sgeConnect,
shouldLaunchAccount: true,
},
},
})
render( render(
<Provider store={store}> <Provider store={store}>
<SgeConnectView /> <SgeConnectView />
...@@ -79,10 +87,6 @@ describe('SgeConnectView component', () => { ...@@ -79,10 +87,6 @@ describe('SgeConnectView component', () => {
global: { global: {
...mockGlobalState, ...mockGlobalState,
fluidStatus: [SgeStatusWithAccount], fluidStatus: [SgeStatusWithAccount],
sgeConnect: {
...mockGlobalState.sgeConnect,
shouldLaunchAccount: true,
},
}, },
}) })
render( render(
......
...@@ -4,16 +4,16 @@ import Content from 'components/Content/Content' ...@@ -4,16 +4,16 @@ import Content from 'components/Content/Content'
import CozyBar from 'components/Header/CozyBar' import CozyBar from 'components/Header/CozyBar'
import Header from 'components/Header/Header' import Header from 'components/Header/Header'
import useKonnectorAuth from 'components/Hooks/useKonnectorAuth' import useKonnectorAuth from 'components/Hooks/useKonnectorAuth'
import { useClient } from 'cozy-client'
import { FORM_DOCTYPE } from 'doctypes'
import { FluidType, SgeStep } from 'enums' import { FluidType, SgeStep } from 'enums'
import { SgeStore } from 'models' import { SgeStore } from 'models'
import React, { useCallback, useEffect, useRef, useState } from 'react' import React, { useCallback, useEffect, useRef, useState } from 'react'
import { useNavigate } from 'react-router-dom' import { useNavigate } from 'react-router-dom'
import { import { setShouldRefreshConsent } from 'store/global/global.slice'
setShouldRefreshConsent,
updateSgeStore,
} from 'store/global/global.slice'
import { useAppDispatch, useAppSelector } from 'store/hooks' import { useAppDispatch, useAppSelector } from 'store/hooks'
import '../connection.scss' import '../connection.scss'
import { createInitialSgeState, useFormData } from '../useForm'
import StepAddress from './StepAddress' import StepAddress from './StepAddress'
import StepConsent from './StepConsent' import StepConsent from './StepConsent'
import StepIdentityAndPdl from './StepIdentityAndPdl' import StepIdentityAndPdl from './StepIdentityAndPdl'
...@@ -32,11 +32,12 @@ export type SGEKeysForm = ...@@ -32,11 +32,12 @@ export type SGEKeysForm =
* http://ecolyo.cozy.tools:8080/#/connect/electricity * http://ecolyo.cozy.tools:8080/#/connect/electricity
*/ */
const SgeConnectView = () => { const SgeConnectView = () => {
const client = useClient()
const navigate = useNavigate() const navigate = useNavigate()
const dispatch = useAppDispatch() const dispatch = useAppDispatch()
const { sgeConnect } = useAppSelector(state => state.ecolyo.global) const { formData } = useFormData()
const [isLoading, setIsLoading] = useState(false) const [isLoading, setIsLoading] = useState(false)
const [currentSgeState, setCurrentSgeState] = useState<SgeStore>(sgeConnect) const [sgeState, setSgeState] = useState<SgeStore>(createInitialSgeState())
const [currentStep, setCurrentStep] = useState<SgeStep>( const [currentStep, setCurrentStep] = useState<SgeStep>(
SgeStep.IdentityAndPDL SgeStep.IdentityAndPDL
) )
...@@ -50,13 +51,25 @@ const SgeConnectView = () => { ...@@ -50,13 +51,25 @@ const SgeConnectView = () => {
} }
const [connect, update] = useKonnectorAuth(FluidType.ELECTRICITY, { const [connect, update] = useKonnectorAuth(FluidType.ELECTRICITY, {
sgeAuthData: sgeConnect, sgeAuthData: sgeState,
}) })
useEffect(
function applyFormData() {
if (formData) {
setSgeState(prevState => ({
...prevState,
...createInitialSgeState(formData),
}))
}
},
[formData]
)
useEffect(() => { useEffect(() => {
async function launchConnect() { async function launchConnect() {
if (sgeConnect.shouldLaunchAccount) { if (sgeState.shouldLaunchAccount) {
dispatch(updateSgeStore({ ...sgeConnect, shouldLaunchAccount: false })) setSgeState({ ...sgeState, shouldLaunchAccount: false })
dispatch(setShouldRefreshConsent(false)) dispatch(setShouldRefreshConsent(false))
if (!account) { if (!account) {
await connect() await connect()
...@@ -67,66 +80,74 @@ const SgeConnectView = () => { ...@@ -67,66 +80,74 @@ const SgeConnectView = () => {
} }
} }
launchConnect() launchConnect()
}, [account, connect, dispatch, navigate, sgeConnect, update]) }, [account, connect, sgeState, dispatch, navigate, update])
const isNextValid = useCallback(() => { const isNextValid = useCallback(() => {
switch (currentStep) { switch (currentStep) {
case SgeStep.IdentityAndPDL: case SgeStep.IdentityAndPDL:
return ( return (
currentSgeState.firstName !== '' && sgeState.firstName !== '' &&
currentSgeState.lastName !== '' && sgeState.lastName !== '' &&
currentSgeState.pdl !== null && sgeState.pdl !== null &&
currentSgeState.pdl.toString().length === 14 sgeState.pdl.toString().length === 14
) )
case SgeStep.Address: case SgeStep.Address:
return ( return (
currentSgeState.address !== '' && sgeState.address !== '' &&
currentSgeState.city !== '' && sgeState.city !== '' &&
currentSgeState.zipCode !== null && sgeState.zipCode !== null &&
currentSgeState.zipCode.toString().length === 5 sgeState.zipCode.toString().length === 5
) )
case SgeStep.Consent: case SgeStep.Consent:
return currentSgeState.dataConsent && currentSgeState.pdlConfirm return sgeState.dataConsent && sgeState.pdlConfirm
default: default:
return false return false
} }
}, [ }, [
currentSgeState.address, sgeState.address,
currentSgeState.city, sgeState.city,
currentSgeState.dataConsent, sgeState.dataConsent,
currentSgeState.firstName, sgeState.firstName,
currentSgeState.lastName, sgeState.lastName,
currentSgeState.pdl, sgeState.pdl,
currentSgeState.pdlConfirm, sgeState.pdlConfirm,
currentSgeState.zipCode, sgeState.zipCode,
currentStep, currentStep,
]) ])
const handleNext = useCallback(() => { const handleNext = useCallback(() => {
if (currentStep < SgeStep.Consent) { if (currentStep < SgeStep.Consent) {
setCurrentStep(prev => prev + 1) 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) { if (currentStep === SgeStep.Consent && !isLoading) {
setIsLoading(true) setIsLoading(true)
const updatedState = { const updatedState = {
...currentSgeState, ...sgeState,
city: currentSgeState.city.trim(), city: sgeState.city.trim(),
shouldLaunchAccount: true, shouldLaunchAccount: true,
} }
setCurrentSgeState(updatedState) setSgeState(updatedState)
dispatch(updateSgeStore(updatedState))
} }
focusMainContent() focusMainContent()
}, [currentStep, isLoading, dispatch, currentSgeState]) }, [currentStep, isLoading, client, formData, sgeState])
const handlePrev = useCallback(() => { const handlePrev = useCallback(() => {
if (currentStep !== SgeStep.IdentityAndPDL) { if (currentStep !== SgeStep.IdentityAndPDL) {
setCurrentStep(prev => prev - 1) setCurrentStep(prev => prev - 1)
} }
dispatch(updateSgeStore(currentSgeState))
focusMainContent() focusMainContent()
}, [currentSgeState, currentStep, dispatch]) }, [currentStep])
const onChange = useCallback( const onChange = useCallback(
( (
...@@ -137,25 +158,23 @@ const SgeConnectView = () => { ...@@ -137,25 +158,23 @@ const SgeConnectView = () => {
if (maxLength && value.toString().length > maxLength) return if (maxLength && value.toString().length > maxLength) return
const updatedState = { const updatedState = {
...currentSgeState, ...sgeState,
[key]: value, [key]: value,
} }
setCurrentSgeState(updatedState) setSgeState(updatedState)
}, },
[currentSgeState] [sgeState]
) )
const renderStep = (step: SgeStep) => { const renderStep = (step: SgeStep) => {
switch (step) { switch (step) {
case SgeStep.Address: case SgeStep.Address:
return <StepAddress sgeState={currentSgeState} onChange={onChange} /> return <StepAddress sgeState={sgeState} onChange={onChange} />
case SgeStep.Consent: case SgeStep.Consent:
return <StepConsent sgeState={currentSgeState} onChange={onChange} /> return <StepConsent sgeState={sgeState} onChange={onChange} />
case SgeStep.IdentityAndPDL: case SgeStep.IdentityAndPDL:
default: default:
return ( return <StepIdentityAndPdl sgeState={sgeState} onChange={onChange} />
<StepIdentityAndPdl sgeState={currentSgeState} onChange={onChange} />
)
} }
} }
......
import { act, render, screen } from '@testing-library/react' import { act, render, screen } from '@testing-library/react'
import { userEvent } from '@testing-library/user-event' import { userEvent } from '@testing-library/user-event'
import React from 'react' import React from 'react'
import { mockGlobalState } from 'tests/__mocks__/store' import { mockSgeState } from 'tests/__mocks__/forms.mock'
import StepAddress from './StepAddress' import StepAddress from './StepAddress'
const mockHandleChange = jest.fn() const mockHandleChange = jest.fn()
...@@ -9,10 +9,7 @@ const mockHandleChange = jest.fn() ...@@ -9,10 +9,7 @@ const mockHandleChange = jest.fn()
describe('StepAddress component', () => { describe('StepAddress component', () => {
it('should be rendered correctly', () => { it('should be rendered correctly', () => {
const { container } = render( const { container } = render(
<StepAddress <StepAddress sgeState={mockSgeState} onChange={mockHandleChange} />
sgeState={mockGlobalState.sgeConnect}
onChange={mockHandleChange}
/>
) )
expect(container).toMatchSnapshot() expect(container).toMatchSnapshot()
}) })
...@@ -20,10 +17,7 @@ describe('StepAddress component', () => { ...@@ -20,10 +17,7 @@ describe('StepAddress component', () => {
describe('should change inputs', () => { describe('should change inputs', () => {
beforeEach(() => { beforeEach(() => {
render( render(
<StepAddress <StepAddress sgeState={mockSgeState} onChange={mockHandleChange} />
sgeState={mockGlobalState.sgeConnect}
onChange={mockHandleChange}
/>
) )
}) })
it('should change address value', async () => { it('should change address value', async () => {
...@@ -40,9 +34,9 @@ describe('StepAddress component', () => { ...@@ -40,9 +34,9 @@ describe('StepAddress component', () => {
name: 'auth.enedissgegrandlyon.zipCode', name: 'auth.enedissgegrandlyon.zipCode',
}) })
await act(async () => { 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 () => { it('should change city value', async () => {
...@@ -58,7 +52,7 @@ describe('StepAddress component', () => { ...@@ -58,7 +52,7 @@ describe('StepAddress component', () => {
it('should have an existing zipCode value', () => { it('should have an existing zipCode value', () => {
render( render(
<StepAddress <StepAddress
sgeState={{ ...mockGlobalState.sgeConnect, zipCode: 69200 }} sgeState={{ ...mockSgeState, zipCode: 69200 }}
onChange={mockHandleChange} onChange={mockHandleChange}
/> />
) )
......
import { render, screen } from '@testing-library/react' import { render, screen } from '@testing-library/react'
import { userEvent } from '@testing-library/user-event' import { userEvent } from '@testing-library/user-event'
import React from 'react' import React from 'react'
import { mockGlobalState } from 'tests/__mocks__/store' import { mockSgeState } from 'tests/__mocks__/forms.mock'
import StepConsent from './StepConsent' import StepConsent from './StepConsent'
const mockHandleChange = jest.fn() const mockHandleChange = jest.fn()
...@@ -9,21 +9,13 @@ const mockHandleChange = jest.fn() ...@@ -9,21 +9,13 @@ const mockHandleChange = jest.fn()
describe('StepConsent component', () => { describe('StepConsent component', () => {
it('should be rendered correctly', () => { it('should be rendered correctly', () => {
const { container } = render( const { container } = render(
<StepConsent <StepConsent sgeState={mockSgeState} onChange={mockHandleChange} />
sgeState={mockGlobalState.sgeConnect}
onChange={mockHandleChange}
/>
) )
expect(container).toMatchSnapshot() expect(container).toMatchSnapshot()
}) })
it('should change dataConsent and pdlConfirm value', async () => { it('should change dataConsent and pdlConfirm value', async () => {
render( render(<StepConsent sgeState={mockSgeState} onChange={mockHandleChange} />)
<StepConsent
sgeState={mockGlobalState.sgeConnect}
onChange={mockHandleChange}
/>
)
const consentCheckbox = screen.getByLabelText( const consentCheckbox = screen.getByLabelText(
'auth.enedissgegrandlyon.consentCheck1' 'auth.enedissgegrandlyon.consentCheck1'
) )
......
import { act, render, screen } from '@testing-library/react' import { act, render, screen } from '@testing-library/react'
import userEvent from '@testing-library/user-event' import userEvent from '@testing-library/user-event'
import React from 'react' import React from 'react'
import { mockGlobalState } from 'tests/__mocks__/store' import { mockSgeState } from 'tests/__mocks__/forms.mock'
import StepIdentityAndPdl from './StepIdentityAndPdl' import StepIdentityAndPdl from './StepIdentityAndPdl'
const mockHandleChange = jest.fn() const mockHandleChange = jest.fn()
...@@ -9,20 +9,14 @@ const mockHandleChange = jest.fn() ...@@ -9,20 +9,14 @@ const mockHandleChange = jest.fn()
describe('StepIdentityAndPdl component', () => { describe('StepIdentityAndPdl component', () => {
it('should be rendered correctly', () => { it('should be rendered correctly', () => {
const { container } = render( const { container } = render(
<StepIdentityAndPdl <StepIdentityAndPdl sgeState={mockSgeState} onChange={mockHandleChange} />
sgeState={mockGlobalState.sgeConnect}
onChange={mockHandleChange}
/>
) )
expect(container).toMatchSnapshot() expect(container).toMatchSnapshot()
}) })
it('should be able to change fields', async () => { it('should be able to change fields', async () => {
render( render(
<StepIdentityAndPdl <StepIdentityAndPdl sgeState={mockSgeState} onChange={mockHandleChange} />
sgeState={mockGlobalState.sgeConnect}
onChange={mockHandleChange}
/>
) )
const firstNameInput = screen.getByRole('textbox', { const firstNameInput = screen.getByRole('textbox', {
name: 'auth.enedissgegrandlyon.firstName', name: 'auth.enedissgegrandlyon.firstName',
...@@ -51,10 +45,7 @@ describe('StepIdentityAndPdl component', () => { ...@@ -51,10 +45,7 @@ describe('StepIdentityAndPdl component', () => {
it('should open hint modal', async () => { it('should open hint modal', async () => {
render( render(
<StepIdentityAndPdl <StepIdentityAndPdl sgeState={mockSgeState} onChange={mockHandleChange} />
sgeState={mockGlobalState.sgeConnect}
onChange={mockHandleChange}
/>
) )
await act(async () => { await act(async () => {
await userEvent.click( await userEvent.click(
...@@ -68,7 +59,7 @@ describe('StepIdentityAndPdl component', () => { ...@@ -68,7 +59,7 @@ describe('StepIdentityAndPdl component', () => {
render( render(
<StepIdentityAndPdl <StepIdentityAndPdl
sgeState={{ sgeState={{
...mockGlobalState.sgeConnect, ...mockSgeState,
pdl: 11111111111111, pdl: 11111111111111,
firstName: 'Zack', firstName: 'Zack',
lastName: 'Ichan', lastName: 'Ichan',
......
...@@ -58,8 +58,8 @@ exports[`StepAddress component should be rendered correctly 1`] = ` ...@@ -58,8 +58,8 @@ exports[`StepAddress component should be rendered correctly 1`] = `
class="MuiFormControl-root MuiTextField-root" class="MuiFormControl-root MuiTextField-root"
> >
<label <label
class="MuiFormLabel-root MuiInputLabel-root MuiInputLabel-formControl MuiInputLabel-animated MuiInputLabel-outlined Mui-required Mui-required" class="MuiFormLabel-root MuiInputLabel-root MuiInputLabel-formControl MuiInputLabel-animated MuiInputLabel-shrink MuiInputLabel-outlined MuiFormLabel-filled Mui-required Mui-required"
data-shrink="false" data-shrink="true"
for="zipCode" for="zipCode"
id="zipCode-label" id="zipCode-label"
> >
...@@ -81,14 +81,14 @@ exports[`StepAddress component should be rendered correctly 1`] = ` ...@@ -81,14 +81,14 @@ exports[`StepAddress component should be rendered correctly 1`] = `
id="zipCode" id="zipCode"
required="" required=""
type="number" type="number"
value="" value="0"
/> />
<fieldset <fieldset
aria-hidden="true" aria-hidden="true"
class="PrivateNotchedOutline-root-1 MuiOutlinedInput-notchedOutline" class="PrivateNotchedOutline-root-1 MuiOutlinedInput-notchedOutline"
> >
<legend <legend
class="PrivateNotchedOutline-legendLabelled-3" class="PrivateNotchedOutline-legendLabelled-3 PrivateNotchedOutline-legendNotched-4"
> >
<span> <span>
auth.enedissgegrandlyon.zipCode auth.enedissgegrandlyon.zipCode
......
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: '',
})
...@@ -51,7 +51,7 @@ const EcogestureTabsView = () => { ...@@ -51,7 +51,7 @@ const EcogestureTabsView = () => {
const { profile, profileEcogesture, profileType } = useAppSelector( const { profile, profileEcogesture, profileType } = useAppSelector(
state => state.ecolyo state => state.ecolyo
) )
const [tabValue, setTabValue] = useState<EcogestureTab>( const [tabValue, setTabValue] = useState<EcogestureTab>(() =>
tab ? parseInt(tab) : EcogestureTab.OBJECTIVE tab ? parseInt(tab) : EcogestureTab.OBJECTIVE
) )
const [isLoading, setIsLoading] = useState<boolean>(true) const [isLoading, setIsLoading] = useState<boolean>(true)
......
...@@ -6,7 +6,7 @@ import { useClient } from 'cozy-client' ...@@ -6,7 +6,7 @@ import { useClient } from 'cozy-client'
import { useI18n } from 'cozy-ui/transpiled/react/providers/I18n' import { useI18n } from 'cozy-ui/transpiled/react/providers/I18n'
import { FluidType, KonnectorUpdate } from 'enums' import { FluidType, KonnectorUpdate } from 'enums'
import { DateTime } from 'luxon' import { DateTime } from 'luxon'
import { AccountSgeData, FluidConnection, FluidStatus } from 'models' import { FluidConnection, FluidStatus } from 'models'
import React, { useCallback, useEffect, useState } from 'react' import React, { useCallback, useEffect, useState } from 'react'
import AccountService from 'services/account.service' import AccountService from 'services/account.service'
import DateChartService from 'services/dateChart.service' import DateChartService from 'services/dateChart.service'
...@@ -14,7 +14,6 @@ import TriggerService from 'services/triggers.service' ...@@ -14,7 +14,6 @@ import TriggerService from 'services/triggers.service'
import { import {
setShouldRefreshConsent, setShouldRefreshConsent,
updateFluidConnection, updateFluidConnection,
updateSgeStore,
} from 'store/global/global.slice' } from 'store/global/global.slice'
import { useAppDispatch, useAppSelector } from 'store/hooks' import { useAppDispatch, useAppSelector } from 'store/hooks'
import { getKonnectorUpdateError } from 'utils/utils' import { getKonnectorUpdateError } from 'utils/utils'
...@@ -108,33 +107,11 @@ const ConnectionResult = ({ ...@@ -108,33 +107,11 @@ const ConnectionResult = ({
const handleRefreshConsent = useCallback(() => { const handleRefreshConsent = useCallback(() => {
if (fluidType == FluidType.ELECTRICITY) { 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)) dispatch(setShouldRefreshConsent(true))
} else { } else {
deleteAccountsAndTriggers() deleteAccountsAndTriggers()
} }
}, [ }, [fluidType, dispatch, deleteAccountsAndTriggers])
fluidType,
currentFluidStatus.connection.account?.auth,
dispatch,
deleteAccountsAndTriggers,
])
useEffect(() => { useEffect(() => {
if (currentFluidStatus.connection.triggerState?.last_success) { if (currentFluidStatus.connection.triggerState?.last_success) {
......
...@@ -65,11 +65,11 @@ const ExportLoadingModal = ({ ...@@ -65,11 +65,11 @@ const ExportLoadingModal = ({
fluidType: FluidType fluidType: FluidType
): Promise<ExportDataRow> => { ): Promise<ExportDataRow> => {
const dataRow: ExportDataRow = {} const dataRow: ExportDataRow = {}
const fluidName = getFluidName(fluidType) const FLUIDNAME = getFluidName(fluidType).toUpperCase()
dataRow[t('export.month')] = formatTwoDigits(dataload.date.month) dataRow[t('export.month')] = formatTwoDigits(dataload.date.month)
dataRow[t('export.year')] = dataload.date.year dataRow[t('export.year')] = dataload.date.year
dataRow[ dataRow[
`${t('export.consumption')} (${t('FLUID.' + fluidName + '.UNIT')})` `${t('export.consumption')} (${t('FLUID.' + FLUIDNAME + '.UNIT')})`
] = dataload.value ] = dataload.value
if (fluidType === FluidType.ELECTRICITY) { if (fluidType === FluidType.ELECTRICITY) {
const emas = new EnedisMonthlyAnalysisDataService(client) const emas = new EnedisMonthlyAnalysisDataService(client)
...@@ -137,6 +137,7 @@ const ExportLoadingModal = ({ ...@@ -137,6 +137,7 @@ const ExportLoadingModal = ({
useEffect(() => { useEffect(() => {
let subscribed = true let subscribed = true
const date = new Date() const date = new Date()
let timeout: ReturnType<typeof setTimeout>
const exportData = async (): Promise<void> => { const exportData = async (): Promise<void> => {
try { try {
...@@ -147,14 +148,15 @@ const ExportLoadingModal = ({ ...@@ -147,14 +148,15 @@ const ExportLoadingModal = ({
exportDataSheets.push(exportDataFluid) exportDataSheets.push(exportDataFluid)
} }
} }
await new Promise(r => setTimeout(r, 2000)) timeout = setTimeout(() => {
if (subscribed) { if (subscribed) {
exportToXlsx( exportToXlsx(
exportDataSheets, exportDataSheets,
'ecolyo_data_' + date.toLocaleDateString() 'ecolyo_data_' + date.toLocaleDateString()
) )
handleDone() handleDone()
} }
}, 2000)
} catch (e) { } catch (e) {
Sentry.captureException(e) Sentry.captureException(e)
handleDone(e) handleDone(e)
...@@ -166,6 +168,7 @@ const ExportLoadingModal = ({ ...@@ -166,6 +168,7 @@ const ExportLoadingModal = ({
} }
return () => { return () => {
subscribed = false subscribed = false
clearTimeout(timeout)
} }
}, [getExportDataSheet, handleDone, open, selectedFluids]) }, [getExportDataSheet, handleDone, open, selectedFluids])
......
...@@ -15,6 +15,7 @@ const MatomoOptOut = () => { ...@@ -15,6 +15,7 @@ const MatomoOptOut = () => {
{t('matomo.matomo_title')} {t('matomo.matomo_title')}
</div> </div>
<iframe <iframe
sandbox="allow-popups allow-scripts"
title="opt-out" title="opt-out"
style={{ height: '250px' }} style={{ height: '250px' }}
className="matomo-content" className="matomo-content"
......
...@@ -15,6 +15,7 @@ exports[`MatomoOptOut component should be rendered correctly 1`] = ` ...@@ -15,6 +15,7 @@ exports[`MatomoOptOut component should be rendered correctly 1`] = `
</div> </div>
<iframe <iframe
class="matomo-content" class="matomo-content"
sandbox="allow-popups allow-scripts"
src="http://localhost:9800/index.php?module=CoreAdminHome&action=optOut&language=fr&backgroundColor=121212&fontColor=e0e0e0&fontSize=&fontFamily=sans-serif" src="http://localhost:9800/index.php?module=CoreAdminHome&action=optOut&language=fr&backgroundColor=121212&fontColor=e0e0e0&fontSize=&fontFamily=sans-serif"
style="height: 250px;" style="height: 250px;"
title="opt-out" title="opt-out"
......
...@@ -378,6 +378,7 @@ exports[`OptionsView component should be rendered correctly 1`] = ` ...@@ -378,6 +378,7 @@ exports[`OptionsView component should be rendered correctly 1`] = `
</div> </div>
<iframe <iframe
class="matomo-content" class="matomo-content"
sandbox="allow-popups allow-scripts"
src="http://localhost:9800/index.php?module=CoreAdminHome&action=optOut&language=fr&backgroundColor=121212&fontColor=e0e0e0&fontSize=&fontFamily=sans-serif" src="http://localhost:9800/index.php?module=CoreAdminHome&action=optOut&language=fr&backgroundColor=121212&fontColor=e0e0e0&fontSize=&fontFamily=sans-serif"
style="height: 250px;" style="height: 250px;"
title="opt-out" title="opt-out"
......