diff --git a/src/components/Connection/ConnectionResult.tsx b/src/components/Connection/ConnectionResult.tsx index fcd29bd19c42fd9ed53bafb4cd65057920f2d273..f41fa87fe37227f2d43b89aff24cbc34e51f1185 100644 --- a/src/components/Connection/ConnectionResult.tsx +++ b/src/components/Connection/ConnectionResult.tsx @@ -5,6 +5,7 @@ import Loader from 'components/Loader/Loader' import { useClient } from 'cozy-client' import { useI18n } from 'cozy-ui/transpiled/react/I18n' import { FluidType } from 'enum/fluid.enum' +import { KonnectorUpdate } from 'enum/konnectorUpdate.enum' import { DateTime } from 'luxon' import { Account, @@ -177,6 +178,10 @@ const ConnectionResult: React.FC<ConnectionResultProps> = ({ } } + const consentError = + konnectorError === KonnectorUpdate.ERROR_CONSENT_FORM_GAS || + konnectorError === KonnectorUpdate.ERROR_UPDATE_OAUTH + return ( <div className="connection-update-result"> <div @@ -199,6 +204,7 @@ const ConnectionResult: React.FC<ConnectionResultProps> = ({ // Else check if konnector is in error state <DisplayKonnectorErrorState konnectorError={konnectorError} + consentRelatedError={consentError} lastExecutionDate={lastExecutionDate} fluidConcerned={getFluidTypeTranslation(fluidType)} /> @@ -218,27 +224,29 @@ const ConnectionResult: React.FC<ConnectionResultProps> = ({ )} </div> <div className="inline-buttons"> - <Button - aria-label={t('konnector_form.accessibility.button_delete')} - onClick={ - fluidType === FluidType.GAS - ? toggleGRDFDeletionModal - : deleteAccountsAndTriggers - } - disabled={updating || deleting} - classes={{ - root: 'btn-secondary-positive', - label: 'text-16-normal', - }} - > - {deleting - ? t('konnector_form.loading') - : t('konnector_form.button_delete')} - </Button> + {!consentError && ( + <Button + aria-label={t('konnector_form.accessibility.button_delete')} + onClick={ + fluidType === FluidType.GAS + ? toggleGRDFDeletionModal + : deleteAccountsAndTriggers + } + disabled={updating || deleting} + classes={{ + root: 'btn-secondary-positive', + label: 'text-16-normal', + }} + > + {deleting + ? t('konnector_form.loading') + : t('konnector_form.button_delete')} + </Button> + )} <Button aria-label={t('konnector_form.accessibility.button_update')} onClick={ - konnectorError === 'error_update_oauth' + consentError ? () => handleRefreshConsent(fluidType) : updateKonnector } @@ -251,7 +259,7 @@ const ConnectionResult: React.FC<ConnectionResultProps> = ({ {updating && <Loader color="black" />} {!updating && ( <div> - {konnectorError === 'error_update_oauth' + {consentError ? t('konnector_form.button_oauth_reload') : t('konnector_form.button_update')} </div> @@ -271,10 +279,12 @@ const ConnectionResult: React.FC<ConnectionResultProps> = ({ const DisplayKonnectorErrorState = ({ konnectorError, + consentRelatedError, lastExecutionDate, fluidConcerned, }: { konnectorError: string + consentRelatedError: boolean lastExecutionDate: string | DateTime fluidConcerned: string }) => { @@ -296,7 +306,7 @@ const DisplayKonnectorErrorState = ({ {t(`konnector_form.${konnectorError}`, { fluid: fluidConcerned, })} - {konnectorError !== 'error_update_oauth' && ( + {!consentRelatedError && ( <> <div className="connection-caption"> {t('konnector_form.label_updated_at')} diff --git a/src/components/Connection/connectionResult.scss b/src/components/Connection/connectionResult.scss index 6d46ca06831d704e396c84b8be352823cfe9cb19..f508a239956b1128166a2ea10e6913f22186fcef 100644 --- a/src/components/Connection/connectionResult.scss +++ b/src/components/Connection/connectionResult.scss @@ -20,6 +20,7 @@ } .warning-icon { + min-width: 20px; margin-right: 1rem; } .warning-white { diff --git a/src/components/Konnector/KonnectorModal.tsx b/src/components/Konnector/KonnectorModal.tsx index 01790943820cf713b4f663b5c85d05dcad2ddfb0..ec1294a18137b6332cb63b40e5c2c8751a44c17e 100644 --- a/src/components/Konnector/KonnectorModal.tsx +++ b/src/components/Konnector/KonnectorModal.tsx @@ -240,8 +240,30 @@ const KonnectorModal: React.FC<KonnectorModalProps> = ({ </div> </div> )} + {error === KonnectorError.CHALLENGE_ASKED && + fluidType === FluidType.GAS && ( + // CONSENT FORM ERROR GRDF + <div className="konnector-config"> + <Icon icon={errorIcon} size={48} /> + <div className="kce-picto-txt text-20-bold"> + {t('konnector_modal.error_txt')} + </div> + <div className="title text-20-bold"> + {t('konnector_modal.error_consent_form_gas_title')} + </div> + <div className="err-data-2"> + {t('konnector_modal.error_consent_form_gas_content')} + </div> + <div className="err-data-2"> + {t( + 'konnector_modal.error_consent_form_gas_content_2' + )} + </div> + </div> + )} {error !== KonnectorError.LOGIN_FAILED && - error !== KonnectorError.TERMS_VERSION_MISMATCH && ( + error !== KonnectorError.TERMS_VERSION_MISMATCH && + error !== KonnectorError.CHALLENGE_ASKED && ( // DEFAULT CASE <div className="konnector-config"> {console.log('errortype', error)} @@ -267,7 +289,6 @@ const KonnectorModal: React.FC<KonnectorModalProps> = ({ <KonnectorModalFooter state={state} error={error} - fluidType={fluidType} handleCloseClick={handleCloseClick} handleAccountDeletion={handleAccountDeletion} account={account} diff --git a/src/components/Konnector/KonnectorModalFooter.spec.tsx b/src/components/Konnector/KonnectorModalFooter.spec.tsx index 1a2d2dd879ad7f43a7f0afdc8562234b70182465..2502794d98d3dc758f077d25ad401f679f2921bd 100644 --- a/src/components/Konnector/KonnectorModalFooter.spec.tsx +++ b/src/components/Konnector/KonnectorModalFooter.spec.tsx @@ -4,10 +4,8 @@ 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' import React from 'react' import { Provider } from 'react-redux' -import { MockStoreEnhanced } from 'redux-mock-store' import { accountsData } from '../../../tests/__mocks__/accountsData.mock' import { createMockEcolyoStore } from '../../../tests/__mocks__/store' import { waitForComponentToPaint } from '../../../tests/__mocks__/testUtils' @@ -74,7 +72,7 @@ describe('KonnectorModalFooter component', () => { ) }) - it('should render "come back later" for enedis sge when address / name / pdl are not matching (LOGIN_FAILED)', () => { + it('should render "try again" for enedis sge when address / name / pdl are not matching (LOGIN_FAILED)', () => { const wrapper = mount( <Provider store={store}> <KonnectorModalFooter @@ -88,9 +86,7 @@ describe('KonnectorModalFooter component', () => { /> </Provider> ) - expect(wrapper.find(Button).text()).toBe( - 'konnector_modal.button_come_back_later' - ) + expect(wrapper.find(Button).text()).toBe('konnector_modal.button_try_again') }) it('should render "later" and "Verify infos" for enedis sge encountering an error on contract (TERMS_VERSION_MISMATCH)', () => { diff --git a/src/components/Konnector/KonnectorModalFooter.tsx b/src/components/Konnector/KonnectorModalFooter.tsx index c8e14e357a442a2fbb47278a991d5498a92b48f9..7ebc8434aa6c45f056c3a0649e1a710c0e95f307 100644 --- a/src/components/Konnector/KonnectorModalFooter.tsx +++ b/src/components/Konnector/KonnectorModalFooter.tsx @@ -5,7 +5,6 @@ import { SUCCESS_EVENT, } from 'cozy-harvest-lib/dist/models/flowEvents' import { useI18n } from 'cozy-ui/transpiled/react/I18n' -import { FluidType } from 'enum/fluid.enum' import { KonnectorError } from 'enum/konnectorError.enum' import { Account } from 'models' import React, { useCallback } from 'react' @@ -16,7 +15,6 @@ import './konnectorModal.scss' interface KonnectorModalFooterProps { state: string | null error: KonnectorError | null - fluidType: FluidType handleCloseClick: (isSuccess?: boolean) => void handleAccountDeletion: () => Promise<void> account: Account | null @@ -26,7 +24,6 @@ interface KonnectorModalFooterProps { const KonnectorModalFooter: React.FC<KonnectorModalFooterProps> = ({ state, error, - fluidType, handleCloseClick, handleAccountDeletion, account, @@ -49,6 +46,20 @@ const KonnectorModalFooter: React.FC<KonnectorModalFooterProps> = ({ } }, [account, client, handleAccountDeletion, navigate]) + const defaultButton = ( + <Button + aria-label={t('konnector_modal.accessibility.button_close')} + onClick={() => handleCloseClick(state === SUCCESS_EVENT)} + classes={{ + root: 'btn-highlight', + label: 'text-16-bold', + }} + style={{ height: '40px' }} + > + <div>{t('konnector_modal.button_validate')}</div> + </Button> + ) + const errorButtons = () => { switch (error) { case KonnectorError.USER_ACTION_NEEDED: @@ -67,7 +78,8 @@ const KonnectorModalFooter: React.FC<KonnectorModalFooterProps> = ({ </Button> ) case KonnectorError.LOGIN_FAILED: - // MISMATCH NAME / ADDRESS / PDL + case KonnectorError.CHALLENGE_ASKED: + // INCOMPLETE CONSENT FORM - GRDF return ( <Button aria-label={t('konnector_modal.accessibility.button_close')} @@ -78,7 +90,7 @@ const KonnectorModalFooter: React.FC<KonnectorModalFooterProps> = ({ }} style={{ height: '40px' }} > - <div>{t('konnector_modal.button_come_back_later')}</div> + <div>{t('konnector_modal.button_try_again')}</div> </Button> ) case KonnectorError.TERMS_VERSION_MISMATCH: @@ -112,46 +124,11 @@ const KonnectorModalFooter: React.FC<KonnectorModalFooterProps> = ({ ) default: // DEFAULT FOOTER BUTTONS - // TODO change default button - return ( - <Button - aria-label={t('konnector_modal.accessibility.button_close')} - onClick={() => handleCloseClick(state === SUCCESS_EVENT)} - classes={{ - root: 'btn-highlight', - label: 'text-16-bold', - }} - style={{ height: '40px' }} - > - <div>{t('konnector_modal.button_validate')}</div> - </Button> - ) + return defaultButton } } - const successButton = () => { - // DEFAULT FOOTER BUTTONS - return ( - <Button - aria-label={t('konnector_modal.accessibility.button_close')} - onClick={() => handleCloseClick(state === SUCCESS_EVENT)} - classes={{ - root: 'btn-highlight', - label: 'text-16-bold', - }} - > - <div>{t('konnector_modal.button_validate')}</div> - </Button> - ) - } - - return ( - <> - {state === ERROR_EVENT && fluidType === FluidType.ELECTRICITY - ? errorButtons() - : successButton()} - </> - ) + return <>{state === ERROR_EVENT ? errorButtons() : defaultButton}</> } export default KonnectorModalFooter diff --git a/src/components/Konnector/KonnectorViewerCard.tsx b/src/components/Konnector/KonnectorViewerCard.tsx index 6a2b9e196554d3cb74c8a2e4a935a108faf6c860..9d4d51715dc4e34abebae9f459171a93d8353a96 100644 --- a/src/components/Konnector/KonnectorViewerCard.tsx +++ b/src/components/Konnector/KonnectorViewerCard.tsx @@ -187,27 +187,30 @@ const KonnectorViewerCard: React.FC<KonnectorViewerCardProps> = ({ const handleConnectionEnd = useCallback( async (isSuccess?: boolean) => { - if ( - // CASE FOR GLOBAL LOGIN FAILED - (account && - !isSuccess && - (konnectorErrorDescription === KonnectorError.LOGIN_FAILED || - konnectorErrorDescription === KonnectorError.UNKNOWN_ERROR || - konnectorErrorDescription == KonnectorError.CRITICAL) && - fluidStatus !== null && - fluidStatus.connection.account !== null && - fluidStatus.connection.account.auth !== undefined) || - // CASE FOR ENEDIS CODE INSEE ERROR - (account && - !isSuccess && - !isUpdating && - fluidType === FluidType.ELECTRICITY && - fluidStatus !== null && - fluidStatus.connection.account !== null && - fluidStatus.connection.account.auth !== undefined) - ) { + // CASE FOR GLOBAL LOGIN FAILED + const isGlobalLoginFailed = + konnectorErrorDescription === KonnectorError.LOGIN_FAILED || + konnectorErrorDescription === KonnectorError.UNKNOWN_ERROR || + konnectorErrorDescription === KonnectorError.CHALLENGE_ASKED || + konnectorErrorDescription === KonnectorError.CRITICAL + + // CASE FOR ENEDIS CODE INSEE ERROR + const isEnedisCodeInseeError = + !isUpdating && fluidType === FluidType.ELECTRICITY + + const shouldDeleteAccount = + account && + !isSuccess && + fluidStatus && + fluidStatus.connection.account && + (isGlobalLoginFailed || isEnedisCodeInseeError) + + if (shouldDeleteAccount) { // KEEP CREDENTIALS FOR EGL - if (fluidSlug === FluidSlugType.WATER) { + if ( + fluidSlug === FluidSlugType.WATER && + fluidStatus.connection.account?.auth + ) { const auth = fluidStatus.connection.account.auth as AccountAuthData fluidStatus.connection.konnectorConfig.lastKnownCredentials = auth.login @@ -250,8 +253,8 @@ const KonnectorViewerCard: React.FC<KonnectorViewerCardProps> = ({ client, handleAccountDeletion, updatedFluidStatus.length, - partnersInfoService, fluidService, + partnersInfo, dispatch, ] ) diff --git a/src/components/Konnector/__snapshots__/KonnectorModalFooter.spec.tsx.snap b/src/components/Konnector/__snapshots__/KonnectorModalFooter.spec.tsx.snap index 527aa6f28cc29dd6db93240fe135b592d52877e6..729e3c5d13d8721ad2e9fe24dbc4223c7940dad3 100644 --- a/src/components/Konnector/__snapshots__/KonnectorModalFooter.spec.tsx.snap +++ b/src/components/Konnector/__snapshots__/KonnectorModalFooter.spec.tsx.snap @@ -31,6 +31,11 @@ exports[`KonnectorModalFooter component should be rendered correctly 1`] = ` } } onClick={[Function]} + style={ + Object { + "height": "40px", + } + } > <ForwardRef(Button) aria-label="konnector_modal.accessibility.button_close" @@ -68,6 +73,11 @@ exports[`KonnectorModalFooter component should be rendered correctly 1`] = ` } } onClick={[Function]} + style={ + Object { + "height": "40px", + } + } > <WithStyles(ForwardRef(ButtonBase)) aria-label="konnector_modal.accessibility.button_close" @@ -77,6 +87,11 @@ exports[`KonnectorModalFooter component should be rendered correctly 1`] = ` focusRipple={true} focusVisibleClassName="Mui-focusVisible" onClick={[Function]} + style={ + Object { + "height": "40px", + } + } type="button" > <ForwardRef(ButtonBase) @@ -94,6 +109,11 @@ exports[`KonnectorModalFooter component should be rendered correctly 1`] = ` focusRipple={true} focusVisibleClassName="Mui-focusVisible" onClick={[Function]} + style={ + Object { + "height": "40px", + } + } type="button" > <button @@ -112,6 +132,11 @@ exports[`KonnectorModalFooter component should be rendered correctly 1`] = ` onTouchEnd={[Function]} onTouchMove={[Function]} onTouchStart={[Function]} + style={ + Object { + "height": "40px", + } + } tabIndex={0} type="button" > diff --git a/src/enum/konnectorError.enum.ts b/src/enum/konnectorError.enum.ts index 17411d2a0e1933974511cc809049cd73329631f8..090a513caafdfc5b964c22c0ec86ab1e0cc98867 100644 --- a/src/enum/konnectorError.enum.ts +++ b/src/enum/konnectorError.enum.ts @@ -2,6 +2,7 @@ export enum KonnectorError { LOGIN_FAILED = 'LOGIN_FAILED', USER_ACTION_NEEDED = 'USER_ACTION_NEEDED', TERMS_VERSION_MISMATCH = 'TERMS_VERSION_MISMATCH', + CHALLENGE_ASKED = 'CHALLENGE_ASKED', UNKNOWN_ERROR = 'UNKNOWN_ERROR', CRITICAL = 'exit status 1', } diff --git a/src/enum/konnectorUpdate.enum.ts b/src/enum/konnectorUpdate.enum.ts index 9d932853d7858d74d900f4af644f0fd4f7c61003..d9b5dd8d71ce6bd1a2220069394358f976f7374e 100644 --- a/src/enum/konnectorUpdate.enum.ts +++ b/src/enum/konnectorUpdate.enum.ts @@ -2,4 +2,5 @@ export enum KonnectorUpdate { ERROR_UPDATE = 'error_update', ERROR_UPDATE_OAUTH = 'error_update_oauth', LOGIN_FAILED = 'login_failed', + ERROR_CONSENT_FORM_GAS = 'error_consent_form_gas', } diff --git a/src/locales/fr.json b/src/locales/fr.json index 6152e58bbd4ee9d5ba77e6a8729b2ed60c1c4d1f..ffb2a14990af24743e91194d1fefcaa0129d84fa 100644 --- a/src/locales/fr.json +++ b/src/locales/fr.json @@ -738,6 +738,7 @@ "error_login_failed": "Identifiants invalides", "error_update": "Un problème est survenu lors du rapatriement de vos données.", "error_update_oauth": "Votre autorisation pour afficher vos données %{fluid} a expiré.", + "error_consent_form_gas": "Vos données ne peuvent être récupérées car vous n'avez pas coché l'autorisation d'accès aux données informatives lors de votre partage de consentement.", "button_oauth_reload": "Redonner mon consentement", "OK": "Ok", "konnector_delta": { @@ -778,7 +779,7 @@ "success_update_txt": "Connexion réussie !", "success_data_update_electricity": "Ecolyo est bien connecté à votre compteur d'électricité.", "success_data_update_water": "Ecolyo est bien connecté à votre compteur d'eau.", - "success_data_update_gaz": "Ecolyo est bien connecté à votre compteur de gaz.", + "success_data_update_gas": "Ecolyo est bien connecté à votre compteur de gaz.", "success_data_additional_update_electricity": "Sachez que la donnée de consommation d'électricité arrive entre J+1 et J+2.<br /><br />S'il vous manque encore des données, c'est qu'elles n'ont pas encore été mises à disposition par le gestionnaire de votre compteur. Merci pour votre patience\u00a0!", "success_data_additional_update_water": "Sachez que la donnée de consommation d'eau arrive entre J+3 et J+5.<br /><br />S'il vous manque encore des données, c'est qu'elles n'ont pas encore été mises à disposition par le gestionnaire de votre compteur. Merci pour votre patience\u00a0!", "success_data_additional_update_gas": "Sachez que la donnée de consommation de gaz arrive entre J+3 et J+5.<br /><br />S'il vous manque encore des données, c'est qu'elles n'ont pas encore été mises à disposition par le gestionnaire de votre compteur. Merci pour votre patience\u00a0!", @@ -798,13 +799,16 @@ "error_credentials_update_electricity": "Un problème a lieu lors de la récupération de vos données. Merci de supprimer votre connecteur et vous reconnecter.", "error_credentials_update_gas": "Un problème a lieu lors de la récupération de vos données. Merci de supprimer votre connecteur et vous reconnecter.", "error_data_gas": "Un problème est survenu. Vos données de consommation de gaz ne seront pas chargées.", + "error_consent_form_gas_title": "Nous n'avons pas pu connecter vos données de consommation de gaz à Ecolyo.", + "error_consent_form_gas_content": "En effet, le partage de vos données de consommation de gaz \"informatives\" doit être accepté.", + "error_consent_form_gas_content_2": "Merci de cocher \"OUI\" au partage de vos données de consommation de gaz, et à \"Autoriser l'accès à mes données informatives\".", "error_data_update_electricity": "Un problème est survenu. Vos données de consommation d’électricité n’ont pas été mises à jour.", "error_data_update_water": "Un problème est survenu. Vos données de consommation d’eau n’ont pas été mises à jour.", "error_data_update_gas": "Un problème est survenu. Vos données de consommation de gaz n’ont pas été mises à jour.", "error_data_2": "Merci de réessayer plus tard.", "button_validate": "Ok", "button_understood": "J'ai compris", - "button_come_back_later": "Revenir plus tard", + "button_try_again": "Réessayer", "show_common_error": "Voir les erreurs récurrentes", "show_common_error_list": "<span style=\"text-align:left; font-weight:700;\">Le problème peut provenir des cas suivants :</span> <ul style=\"text-align:left;\"><li>Vous avez un co-titulaire sur votre contrat. Veillez à bien entrer le nom du <span style=\"color:#E3B82A; font-weight:700;\">titulaire du contrat</span> et non le co-titulaire.</li><li> Votre nom comporte un tiret\u00a0? Tentez sans le tiret.</li><li> Entrez bien le nom de votre commune de résidence en entier (tirets et accents inclus)</li><li> Avez-vous bien entré le <span style=\"color:#E3B82A; font-weight:700;\">numéro de votre compteur</span> (PDL)\u00a0? Tout autre numéro (de contrat, de client) ne fonctionne pas.</li></ul><p style=\"text-align:center; font-style: italic; font-weight:400; font-size: 0.9rem;\">Si vous rencontrez toujours des difficultés, contactez notre service d'aide </p><div style=\"text-align:center; font-weight:700;\">Avez-vous pensez à vérifier ces informations\u00a0?</div>", "accessibility": { diff --git a/src/utils/utils.ts b/src/utils/utils.ts index 8e4d6e79cda2f6656f282f373c431b898e99dbc0..4386dde74532ec779566ec7e83160797b1a96cab 100644 --- a/src/utils/utils.ts +++ b/src/utils/utils.ts @@ -24,11 +24,12 @@ export function getKonnectorUpdateError(type: string) { return KonnectorUpdate.ERROR_UPDATE_OAUTH case 'LOGIN_FAILED': return KonnectorUpdate.LOGIN_FAILED + case 'CHALLENGE_ASKED': + return KonnectorUpdate.ERROR_CONSENT_FORM_GAS default: return KonnectorUpdate.ERROR_UPDATE } } - export function isKonnectorActive( fluidStatus: FluidStatus[], fluidType: FluidType