diff --git a/.eslintrc.js b/.eslintrc.js index 88b5bcd2da30e71fc6f341274fcf999c65197e13..d044e9dbe7f0116e07d124bddcd786d1e411e75b 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -9,6 +9,7 @@ module.exports = { overrides: [ { extends: [ + 'plugin:jsdoc/recommended', 'plugin:@typescript-eslint/recommended', 'plugin:@typescript-eslint/eslint-recommended', // Uses the recommended rules from @typescript-eslint/eslint-plugin // This enables a lot of type checking @@ -27,10 +28,29 @@ module.exports = { '@typescript-eslint/prefer-as-const': 'error', '@typescript-eslint/await-thenable': 'error', '@typescript-eslint/no-var-requires': 'off', + + // JSDOC extends overrides: disable some of extends rules + // JSdoc is not always needed + 'jsdoc/require-jsdoc': 0, + // Prefer declaring types with typescript + 'jsdoc/require-returns': 0, + 'jsdoc/require-returns-type': 0, + 'jsdoc/require-param': 0, + 'jsdoc/require-param-type': 0, + + // Allow some params to be described and some to be omitted + 'jsdoc/check-param-names': 0, + }, + }, + { + files: ['**/*.spec.{ts,tsx}'], + extends: ['plugin:jest/recommended'], + rules: { + 'jest/no-mocks-import': 0, }, }, ], - plugins: ['@typescript-eslint', 'react', 'react-hooks'], + plugins: ['@typescript-eslint', 'react', 'react-hooks', 'jest'], parser: '@typescript-eslint/parser', // Specifies the ESLint parser parserOptions: { ecmaVersion: 2020, // Allows for the parsing of modern ECMAScript features @@ -50,6 +70,19 @@ module.exports = { 'no-param-reassign': 'warn', 'spaced-comment': ['error', 'always', { block: { exceptions: ['*'] } }], 'react/self-closing-comp': 'warn', + 'react/jsx-curly-brace-presence': ['error'], + + // Rule to suggest using useAppDispatch instead of regular useDispatch + 'no-restricted-imports': 'off', + '@typescript-eslint/no-restricted-imports': [ + 'warn', + { + name: 'react-redux', + importNames: ['useSelector', 'useDispatch'], + message: + 'Use typed hooks `useAppDispatch` and `useAppSelector` instead.', + }, + ], }, root: true, settings: { diff --git a/.gitlab/issue_templates/[QA] Ecolyo.md b/.gitlab/merge_request_templates/[QA] Ecolyo.md similarity index 78% rename from .gitlab/issue_templates/[QA] Ecolyo.md rename to .gitlab/merge_request_templates/[QA] Ecolyo.md index 7ec66c90b79af79f92bcb5b31781aca49d672289..9ead54a6c85a35271412decffa5fd9b10f4d3bae 100644 --- a/.gitlab/issue_templates/[QA] Ecolyo.md +++ b/.gitlab/merge_request_templates/[QA] Ecolyo.md @@ -1,4 +1,3 @@ -/assign @hnouts /confidential true [TOC] @@ -7,14 +6,9 @@ 🚀 _Milestone(s) concernée(s)_ : -- [celle-ci]() -- [et celle-là ]() - ## Tests de non régression -### Nouvelle instance - -💬 _l'instance devrait s'appeler **ecolyo-x-x**.cozy.self-data.alpha.grandlyon.com_ +### [Nouvelle instance](https://ecolyo.ecolyo-x-x.cozy.self-data.alpha.grandlyon.com/#/) --- @@ -37,7 +31,8 @@ *** 5. **Analyse et conso** - [ ] La profondeur de données va jusqu'à 1 an dans la conso pour les pas de temps journalier - - [ ] La profondeur de données à la 1/2h va jusqu'à 3 mois. + - [ ] La profondeur de données à la 1/2h va jusqu'à 1 semaine au premier lancement, puis 1 mois le lendemain. + - [ ] La profondeur de données à la 1/2h va jusqu'à 1 mois le lendemain. - [ ] La profondeur de données va jusqu'à 3 mois antérieur dans l'analyse - [ ] Les modules de l'analyse sont tous fonctionnels (à l'exception du special elec qui devra être déclenché par un service) *** @@ -56,17 +51,15 @@ *** 8. **Icône raccourci** - [ ] L'utilisateur peut ajouter l'application en raccourci (pwa android) - - [ ] L'utilisateur peut ajouter l'application en raccourci (pwa iphone) + - [ ] L'utilisateur peut ajouter l'application en raccourci (pwa iPhone) *** 9. **Autres** - [ ] Les informations de navigation remontent dans le matomo recette - > 💡 Aller consulter des ecogestes en particulier, repérer leurs id et vérifier dans le détails des pages sur matomo + > 💡 Aller consulter des écogestes en particulier, repérer leurs id et vérifier dans le détails des pages sur matomo --- -### Instance historique - -💬 _ici ecolyodemo.cozy.self-data.alpha.grandlyon.com_ +### [Instance historique](https://ecolyo.ecolyodemo.cozy.self-data.alpha.grandlyon.com) --- @@ -75,6 +68,12 @@ --- -## Tests des nouvelles fonctionalités +## Tests des nouvelles fonctionnalités 📝 _À mettre à jour selon les derniers développements_ + +## Autres évolutions associées + +🔄 _connecteurs, backoffice..._ + +# 🚀🚀 diff --git a/.vscode/settings.json b/.vscode/settings.json index 744ba2f959c9b84531a5fdfd830bb49e9083c9da..e0492b20994d9ddccd35028d4ca65a1fec28ff0d 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -35,6 +35,9 @@ ], "gitlab.instanceUrl": "https://forge.grandlyon.com/web-et-numerique/llle_project/ecolyo", "gitlab.ignoreCertificateErrors": true, + "gitlens.remotes": [ + { "type": "GitLab", "domain": "forge.grandlyon.com", "name": "Forge" } + ], "editor.codeActionsOnSave": { "source.fixAll.eslint": true, "source.fixAll": true, @@ -44,6 +47,7 @@ "sonarlint.connectedMode.project": { "projectKey": "ecolyo" }, + "gitlens.remotes": [{ "type": "GitLab", "domain": "forge.grandlyon.com" }], "cSpell.language": "fr,en", "cSpell.words": [ "authform", @@ -52,6 +56,7 @@ "camelcase", "cicid", "CONSO", + "cozybar", "cozycloud", "d’éco", "dacc", diff --git a/CHANGELOG.md b/CHANGELOG.md index b1187f2311733a9d8206a3d2130096f95e36479b..17dcda450d2b685a2cb80f53ed2a9109e59316e9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,36 @@ All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines. +## [2.6.0](https://forge.grandlyon.com/web-et-numerique/factory/llle_project/ecolyo/compare/v2.5.1...v2.6.0) (2023-10-02) + + +### Features + +* add transitions ([4cb0fe0](https://forge.grandlyon.com/web-et-numerique/factory/llle_project/ecolyo/commit/4cb0fe0ece885956c073cbd26436f2c1eca88ba3)) +* **analysis:** incomplete data warning ([d2ec2e8](https://forge.grandlyon.com/web-et-numerique/factory/llle_project/ecolyo/commit/d2ec2e877555a7d696e89e6e780a88961432b9c7)) +* **analysis:** show analysis with offline konnector ([122cc59](https://forge.grandlyon.com/web-et-numerique/factory/llle_project/ecolyo/commit/122cc59825a0487edb3592351462ef5f7b6e7d43)) +* **challenge:** reset duel ([525af23](https://forge.grandlyon.com/web-et-numerique/factory/llle_project/ecolyo/commit/525af23881ba8d880c35ad1e16423abf609e1c67)) +* **conso:** add consumption placeholder bar & change bar animation ([cd26743](https://forge.grandlyon.com/web-et-numerique/factory/llle_project/ecolyo/commit/cd26743dde7d76bf9501d73c084a61e7f76f2437)) +* **ecogestures:** animate ecogesture details ([562be40](https://forge.grandlyon.com/web-et-numerique/factory/llle_project/ecolyo/commit/562be40a2af196793b52ca040eb373c99bbffdd5)) +* **ecogestures:** keep ecogestures filter ([997b4de](https://forge.grandlyon.com/web-et-numerique/factory/llle_project/ecolyo/commit/997b4de19487053a50409d9cd5b487453fbb984a)) +* **ecogestures:** rework selection ([062d953](https://forge.grandlyon.com/web-et-numerique/factory/llle_project/ecolyo/commit/062d953e09bdbe583ce816cf632c69837fd3080f)) +* improve loading ui ([2cdcc7d](https://forge.grandlyon.com/web-et-numerique/factory/llle_project/ecolyo/commit/2cdcc7d524ee1f58efda4c8c1173c422e9b8951a)) +* **KonnectorCard:** simplify status icon to throw warnings and not only errors ([c87bdad](https://forge.grandlyon.com/web-et-numerique/factory/llle_project/ecolyo/commit/c87bdadfb06ea8cc7da70c08d6016e510d126fd5)) +* launch fluidPrices service during initialization ([0142cb3](https://forge.grandlyon.com/web-et-numerique/factory/llle_project/ecolyo/commit/0142cb3f5ef6cd0049398e43036a453749da06ce)) + + +### Bug Fixes + +* **analysis:** disable comparison in graph max data ([fbce999](https://forge.grandlyon.com/web-et-numerique/factory/llle_project/ecolyo/commit/fbce9998d8ba5baba225855fad71c4c2632eb7f7)) +* **analysis:** modal no konnector ([041e56d](https://forge.grandlyon.com/web-et-numerique/factory/llle_project/ecolyo/commit/041e56d6f4bd50d1797c95f8aa1374f96e742274)) +* **astuces:** back mobile ([97201db](https://forge.grandlyon.com/web-et-numerique/factory/llle_project/ecolyo/commit/97201db51b3d0fcef473a626b2beb030d9a47294)) +* **challenge:** request loop in action selection ([eef5342](https://forge.grandlyon.com/web-et-numerique/factory/llle_project/ecolyo/commit/eef534200aa213eb54deb1d6dccab3489521b495)) +* **ecogesture:** display loader correctly ([5d6f7f3](https://forge.grandlyon.com/web-et-numerique/factory/llle_project/ecolyo/commit/5d6f7f32c2c9793632e81cddfc427840045d36b9)) +* **ecogestures:** fix small profile ([448c106](https://forge.grandlyon.com/web-et-numerique/factory/llle_project/ecolyo/commit/448c1069725fab95b751b80eaffab20b9e78a762)) +* **fluidchart:** enable right swipe on year timestep with smooth return ([70472ca](https://forge.grandlyon.com/web-et-numerique/factory/llle_project/ecolyo/commit/70472ca32446d6281b9645aa7d0d7f1e65bae26a)) +* launching konnector error ([1b79584](https://forge.grandlyon.com/web-et-numerique/factory/llle_project/ecolyo/commit/1b7958435a6eb4ce725a607e6d6c98e93fc46935)) +* **splashScreen:** loading bar hatched design ([c2435be](https://forge.grandlyon.com/web-et-numerique/factory/llle_project/ecolyo/commit/c2435be6517b6682a67f2f6d3ddd15a2bb31cd63)) + ### [2.5.1](https://forge.grandlyon.com/web-et-numerique/factory/llle_project/ecolyo/compare/v2.5.0...v2.5.1) (2023-06-30) ## [2.5.0](https://forge.grandlyon.com/web-et-numerique/factory/llle_project/ecolyo/compare/v2.4.0...v2.5.0) (2023-06-29) diff --git a/app.config.react.js b/app.config.react.js index 58047c1d2be07c2a62879477f9978c1091d6d818..7dba378a9311428eefd03c8b39dfb743be15bee0 100644 --- a/app.config.react.js +++ b/app.config.react.js @@ -42,11 +42,7 @@ module.exports = { }, { test: /\.scss$/, - loaders: [ - require.resolve('style-loader'), - require.resolve('css-loader'), - require.resolve('sass-loader'), - ], + use: ['style-loader', 'css-loader', 'sass-loader'], }, ], }, diff --git a/jest.config.js b/jest.config.js index fa3e2586f69e2a0ee6608cfffed34b95f8c210f8..6358f0010306c4fbb8435f2f88795297250e0e5e 100644 --- a/jest.config.js +++ b/jest.config.js @@ -1,8 +1,10 @@ -module.exports = { +/** @type {import('jest').Config} */ +const config = { testURL: 'http://localhost/', moduleFileExtensions: ['js', 'jsx', 'ts', 'tsx', 'json', 'styl'], - setupFiles: ['<rootDir>/tests/jestLib/setup.js'], - moduleDirectories: ['src', 'node_modules'], + setupFiles: ['<rootDir>/tests/jestLib/setupTests.ts'], + moduleDirectories: ['<rootDir>', 'node_modules'], + modulePaths: ['<rootDir>/src'], moduleNameMapper: { '\\.(png|gif|jpe?g|svg|hbs)$': '<rootDir>/tests/__mocks__/fileMock.js', // identity-obj-proxy module is installed by cozy-scripts @@ -26,3 +28,5 @@ module.exports = { cozy: {}, }, } + +module.exports = config diff --git a/manifest.webapp b/manifest.webapp index c9d4957512496ef9c9d6c22151cbd2a2c94e99bd..bc9e43b6e7eb3dcf624e2024d010bf1ccf4078e3 100644 --- a/manifest.webapp +++ b/manifest.webapp @@ -3,7 +3,7 @@ "slug": "ecolyo", "icon": "icon.svg", "categories": ["energy"], - "version": "2.5.1", + "version": "2.6", "licence": "AGPL-3.0", "editor": "Métropole de Lyon", "default_locale": "fr", diff --git a/package.json b/package.json index 8120d00fe90a331330725b7608588fcd41cb0dee..77321704923d9d63390cece65f1fa506bf089f0a 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "ecolyo", - "version": "2.5.1", + "version": "2.6.0", "engines": { "node": ">=16.0.0" }, @@ -8,7 +8,7 @@ "build": "yarn run build:css && yarn run build:browser", "build:browser": "cs build --browser ", "build:cs": "build:browser", - "build:css": "sass -c ./src/styles", + "build:css": "sass -c ./src/styles:build", "build-dev": "yarn run build:css && yarn run build-dev:browser", "build-dev:browser": "cs build --browser --config app.config.alpha.js", "build-dev:mobile": "cs build --mobile --config app.config.alpha.js", @@ -49,10 +49,11 @@ "@cozy/minilog": "^1.0.0", "@material-ui/core": "~4.12.0", "@material-ui/styles": "^4.11.3", - "@reduxjs/toolkit": "^1.9.3", + "@reduxjs/toolkit": "^1.9.5", "@sentry/react": "^7.21.1", "@sentry/tracing": "^7.21.1", "@simbathesailor/use-what-changed": "^2.0.0", + "classnames": "^2.3.2", "cozy-bar": "8.15.0", "cozy-client": "35.6.0", "cozy-device-helper": ">=2.1.0", @@ -77,19 +78,20 @@ "object-hash": "^3.0.0", "react": "16.14.0", "react-dom": "16.14.0", - "react-redux": "^7.2.2", + "react-redux": "^8.1.2", "react-router-dom": "^6.6.1", "react-swipeable-views": "0.14.0", "redux-devtools-extension": "^2.13.8", "redux-logger": "^3.0.6", + "redux-thunk": "^2.4.2", "xlsx": "^0.18.5" }, "devDependencies": { "@babel/preset-typescript": "^7.7.4", "@testing-library/react-hooks": "^8.0.0", - "@types/classnames": "^2.2.10", "@types/d3": "^6.0.0", "@types/enzyme": "^3.10.8", + "@types/enzyme-adapter-react-16": "^1.0.6", "@types/file-saver": "^2.0.5", "@types/history": "^5.0.0", "@types/jest": "^29.4.0", @@ -100,7 +102,6 @@ "@types/react": "^16.9.15", "@types/react-dom": "^16.9.8", "@types/react-lottie": "^1.2.3", - "@types/react-redux": "^7.1.11", "@types/react-router-dom": "^5.3.3", "@types/redux-mock-store": "^1.0.2", "@typescript-eslint/eslint-plugin": "^5.56.0", @@ -114,8 +115,10 @@ "enzyme": "3.11.0", "enzyme-adapter-react-16": "1.15.6", "enzyme-to-json": "^3.6.2", - "eslint": "^8.36.0", + "eslint": "^8.49.0", "eslint-config-prettier": "^8.8.0", + "eslint-plugin-jest": "^27.2.3", + "eslint-plugin-jsdoc": "^46.8.2", "eslint-plugin-prettier": "^4.2.1", "eslint-plugin-react": "7.32.2", "eslint-plugin-react-hooks": "^4.6.0", diff --git a/scripts/config.template.js b/scripts/config.template.js index cabc3165ec669ac7323634e921f51a0ce79f28c9..5988a8518c26e209466edbd60a6d6dd19637c901 100644 --- a/scripts/config.template.js +++ b/scripts/config.template.js @@ -8,6 +8,7 @@ const cookie = const startingdate = DateTime.local().plus({ days: -120 }).startOf('day') const endingDate = DateTime.local().plus({ days: -1 }).startOf('day') +/** Elec starting date */ const halfHourStartingdate = DateTime.local().plus({ days: -15 }).startOf('day') module.exports = { diff --git a/src/assets/icons/ico/notif_warning.svg b/src/assets/icons/ico/notif_warning.svg new file mode 100644 index 0000000000000000000000000000000000000000..d34d265600b376a4d18ee0b33d45b285420ab159 --- /dev/null +++ b/src/assets/icons/ico/notif_warning.svg @@ -0,0 +1,19 @@ +<svg width="27" height="26" viewBox="0 0 27 26" fill="none" xmlns="http://www.w3.org/2000/svg"> +<g filter="url(#filter0_d_15041_508)"> +<circle cx="13.5" cy="11" r="11" fill="#E3B82A"/> +<circle cx="13.5" cy="11" r="10.5" stroke="white"/> +</g> +<path d="M12.634 4.5C13.0189 3.83333 13.9811 3.83333 14.366 4.5L20.4282 15C20.8131 15.6667 20.332 16.5 19.5622 16.5H7.43782C6.66802 16.5 6.1869 15.6667 6.5718 15L12.634 4.5Z" fill="#1B1C22"/> +<path fill-rule="evenodd" clip-rule="evenodd" d="M14.4001 7.5001C14.4001 7.00304 13.9972 6.6001 13.5001 6.6001C13.003 6.6001 12.6001 7.00304 12.6001 7.5001V12.0001C12.6001 12.4972 13.003 12.9001 13.5001 12.9001C13.9972 12.9001 14.4001 12.4972 14.4001 12.0001L14.4001 7.5001ZM14.4001 14.7001C14.4001 14.203 13.9972 13.8001 13.5001 13.8001C13.003 13.8001 12.6001 14.203 12.6001 14.7001C12.6001 15.1972 13.003 15.6001 13.5001 15.6001C13.9972 15.6001 14.4001 15.1972 14.4001 14.7001Z" fill="#E3B82A"/> +<defs> +<filter id="filter0_d_15041_508" x="0.5" y="0" width="26" height="26" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB"> +<feFlood flood-opacity="0" result="BackgroundImageFix"/> +<feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha"/> +<feOffset dy="2"/> +<feGaussianBlur stdDeviation="1"/> +<feColorMatrix type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.7 0"/> +<feBlend mode="normal" in2="BackgroundImageFix" result="effect1_dropShadow_15041_508"/> +<feBlend mode="normal" in="SourceGraphic" in2="effect1_dropShadow_15041_508" result="shape"/> +</filter> +</defs> +</svg> diff --git a/src/assets/icons/ico/warning-dark.svg b/src/assets/icons/ico/warning-dark.svg new file mode 100644 index 0000000000000000000000000000000000000000..95597cf93e2a311cbb3f92139be928311a5fb218 --- /dev/null +++ b/src/assets/icons/ico/warning-dark.svg @@ -0,0 +1,3 @@ +<svg width="30" height="27" viewBox="0 0 30 27" fill="none" xmlns="http://www.w3.org/2000/svg"> +<path fill-rule="evenodd" clip-rule="evenodd" d="M16.5142 0.874208C15.8412 -0.2914 14.1588 -0.291404 13.4858 0.874204L0.236852 23.8221C-0.436112 24.9877 0.405088 26.4447 1.75102 26.4447H28.249C29.5949 26.4447 30.4361 24.9877 29.7632 23.8221L16.5142 0.874208ZM13.8973 15.3611V9.61627H16.058V15.3611C16.058 15.834 16.0307 16.3043 15.976 16.772C15.9214 17.2346 15.8494 17.7075 15.76 18.1906H14.1953C14.1059 17.7075 14.0339 17.2346 13.9793 16.772C13.9246 16.3043 13.8973 15.834 13.8973 15.3611ZM16.2145 20.4573C16.279 20.6166 16.3113 20.7888 16.3113 20.9739C16.3113 21.1589 16.279 21.3337 16.2145 21.4981C16.1449 21.6575 16.053 21.7962 15.9388 21.9145C15.8196 22.0327 15.6805 22.1252 15.5215 22.192C15.3626 22.2588 15.1888 22.2922 15 22.2922C14.8162 22.2922 14.6449 22.2588 14.4859 22.192C14.327 22.1252 14.1879 22.0327 14.0687 21.9145C13.9495 21.7962 13.8576 21.6575 13.793 21.4981C13.7235 21.3337 13.6887 21.1589 13.6887 20.9739C13.6887 20.7888 13.7235 20.6166 13.793 20.4573C13.8576 20.298 13.9495 20.1592 14.0687 20.041C14.1879 19.9228 14.327 19.8302 14.4859 19.7634C14.6449 19.6915 14.8162 19.6555 15 19.6555C15.1888 19.6555 15.3626 19.6915 15.5215 19.7634C15.6805 19.8302 15.8196 19.9228 15.9388 20.041C16.053 20.1592 16.1449 20.298 16.2145 20.4573Z" fill="#1B1C22"/> +</svg> diff --git a/src/components/Action/ActionBegin.spec.tsx b/src/components/Action/ActionBegin/ActionBegin.spec.tsx similarity index 51% rename from src/components/Action/ActionBegin.spec.tsx rename to src/components/Action/ActionBegin/ActionBegin.spec.tsx index 6ea2ba74bb4a5aa6324c5b30b25a258677552b48..68c77e405bf58032d455c5e847fa934e0987fa9b 100644 --- a/src/components/Action/ActionBegin.spec.tsx +++ b/src/components/Action/ActionBegin/ActionBegin.spec.tsx @@ -3,59 +3,37 @@ import { mount } from 'enzyme' import toJson from 'enzyme-to-json' import React from 'react' import { Provider } from 'react-redux' -import configureStore from 'redux-mock-store' import { AllEcogestureData, defaultEcogestureData, -} from '../../../tests/__mocks__/actionData.mock' -import { mockedEcogesturesData } from '../../../tests/__mocks__/ecogesturesData.mock' -import { globalStateData } from '../../../tests/__mocks__/globalStateData.mock' -import { profileData } from '../../../tests/__mocks__/profileData.mock' -import { waitForComponentToPaint } from '../../../tests/__mocks__/testUtils' -import { userChallengeData } from '../../../tests/__mocks__/userChallengeData.mock' +} from 'tests/__mocks__/actionData.mock' +import { mockedEcogesturesData } from 'tests/__mocks__/ecogesturesData.mock' +import { + createMockEcolyoStore, + mockGlobalState, + mockProfileState, +} from 'tests/__mocks__/store' +import { waitForComponentToPaint } from 'tests/__mocks__/testUtils' +import { userChallengeData } from 'tests/__mocks__/userChallengeData.mock' +import ActionModal from '../ActionModal/ActionModal' import ActionBegin from './ActionBegin' -import ActionModal from './ActionModal' -jest.mock('cozy-ui/transpiled/react/I18n', () => { - return { - useI18n: jest.fn(() => { - return { - t: (str: string) => str, - } - }), - } -}) const mockgetCustomActions = jest.fn() const mockgetDefaultActions = jest.fn() jest.mock('services/action.service', () => { - return jest.fn(() => { - return { - getCustomActions: mockgetCustomActions, - getDefaultActions: mockgetDefaultActions, - } - }) -}) -const mockImportIconById = jest.fn() -jest.mock('utils/utils', () => { - return { - importIconById: jest.fn(() => { - return mockImportIconById - }), - } + return jest.fn(() => ({ + getCustomActions: mockgetCustomActions, + getDefaultActions: mockgetDefaultActions, + })) }) -const mockStore = configureStore([]) describe('ActionBegin component', () => { it('should render correctly', async () => { - const store = mockStore({ - ecolyo: { - challenge: userChallengeData[1], - global: { ...globalStateData, fluidTypes: [0, 1, 2] }, - profile: profileData, - }, + const store = createMockEcolyoStore({ + global: { ...mockGlobalState, fluidTypes: [0, 1, 2] }, + profile: mockProfileState, }) - mockImportIconById.mockReturnValue('') const wrapper = mount( <Provider store={store}> @@ -75,13 +53,9 @@ describe('ActionBegin component', () => { AllEcogestureData[5], AllEcogestureData[2], ]) - mockImportIconById.mockReturnValue('') - const store = mockStore({ - ecolyo: { - challenge: userChallengeData[1], - global: { ...globalStateData, fluidTypes: [0, 1, 2] }, - profile: { ...profileData, isProfileTypeCompleted: true }, - }, + const store = createMockEcolyoStore({ + global: { ...mockGlobalState, fluidTypes: [0, 1, 2] }, + profile: { ...mockProfileState, isProfileTypeCompleted: true }, }) const wrapper = mount( <Provider store={store}> @@ -95,15 +69,11 @@ describe('ActionBegin component', () => { await waitForComponentToPaint(wrapper) expect(wrapper.find('.action-title').text()).toBe('Coup de vent') }) - it('should render chosen action ', async () => { - const store = mockStore({ - ecolyo: { - challenge: userChallengeData[1], - global: { ...globalStateData, fluidTypes: [0, 1, 2] }, - profile: profileData, - }, + it('should render chosen action', async () => { + const store = createMockEcolyoStore({ + global: { ...mockGlobalState, fluidTypes: [0, 1, 2] }, + profile: mockProfileState, }) - mockImportIconById.mockReturnValue('') const wrapper = mount( <Provider store={store}> @@ -117,15 +87,11 @@ describe('ActionBegin component', () => { await waitForComponentToPaint(wrapper) expect(wrapper.find(ActionBegin).exists()).toBeTruthy() }) - it('should open launch Modal ', async () => { - const store = mockStore({ - ecolyo: { - challenge: userChallengeData[1], - global: { ...globalStateData, fluidTypes: [0, 1, 2] }, - profile: profileData, - }, + it('should open launch Modal', async () => { + const store = createMockEcolyoStore({ + global: { ...mockGlobalState, fluidTypes: [0, 1, 2] }, + profile: mockProfileState, }) - mockImportIconById.mockReturnValue('') const wrapper = mount( <Provider store={store}> @@ -141,15 +107,11 @@ describe('ActionBegin component', () => { expect(wrapper.find(ActionModal).exists()).toBeTruthy() expect(wrapper.find(ActionModal).prop('open')).toBeTruthy() }) - it('should go to the list ', async () => { - const store = mockStore({ - ecolyo: { - challenge: userChallengeData[1], - global: { ...globalStateData, fluidTypes: [0, 1, 2] }, - profile: profileData, - }, + it('should go to the list', async () => { + const store = createMockEcolyoStore({ + global: { ...mockGlobalState, fluidTypes: [0, 1, 2] }, + profile: mockProfileState, }) - mockImportIconById.mockReturnValue('') const wrapper = mount( <Provider store={store}> diff --git a/src/components/Action/ActionBegin.tsx b/src/components/Action/ActionBegin/ActionBegin.tsx similarity index 84% rename from src/components/Action/ActionBegin.tsx rename to src/components/Action/ActionBegin/ActionBegin.tsx index f039432d32f51e9730e63b429b794135cfd00e86..c2a39a4a75c3bbb6cc19f34611bad7e687b4523a 100644 --- a/src/components/Action/ActionBegin.tsx +++ b/src/components/Action/ActionBegin/ActionBegin.tsx @@ -1,15 +1,14 @@ import { Button } from '@material-ui/core' import defaultIcon from 'assets/icons/visu/ecogesture/default.svg' -import ActionModal from 'components/Action/ActionModal' -import StarsContainer from 'components/Challenge/StarsContainer' +import ActionModal from 'components/Action/ActionModal/ActionModal' import StyledIcon from 'components/CommonKit/Icon/StyledIcon' +import StarsContainer from 'components/CommonKit/StarsContainer/StarsContainer' import { Client, useClient } from 'cozy-client' import { useI18n } from 'cozy-ui/transpiled/react/I18n' import { Ecogesture, UserChallenge } from 'models' import React, { useCallback, useEffect, useState } from 'react' -import { useSelector } from 'react-redux' import ActionService from 'services/action.service' -import { AppStore } from 'store' +import { useAppSelector } from 'store/hooks' import { importIconById } from 'utils/utils' import './actionBegin.scss' @@ -29,7 +28,7 @@ const ActionBegin = ({ const { global: { fluidTypes }, profile: { isProfileTypeCompleted }, - } = useSelector((state: AppStore) => state.ecolyo) + } = useAppSelector(state => state.ecolyo) const [currentAction, setCurrentAction] = useState<Ecogesture>() const [actionIcon, setActionIcon] = useState<string>('') const [openLaunchModal, setOpenLaunchModal] = useState<boolean>(false) @@ -37,9 +36,6 @@ const ActionBegin = ({ const toggleLaunchModal = useCallback(() => { setOpenLaunchModal(prev => !prev) }, []) - const goToList = useCallback(() => { - setShowList(true) - }, [setShowList]) useEffect(() => { let subscribed = true @@ -63,17 +59,13 @@ const ActionBegin = ({ return () => { subscribed = false } - }, [client, isProfileTypeCompleted, fluidTypes, action, currentAction]) + }, [action, client, fluidTypes, isProfileTypeCompleted]) useEffect(() => { async function handleEcogestureIcon() { if (currentAction) { const icon = await importIconById(currentAction.id, 'ecogesture') - if (icon) { - setActionIcon(icon) - } else { - setActionIcon(defaultIcon) - } + setActionIcon(icon || defaultIcon) } } handleEcogestureIcon() @@ -100,8 +92,7 @@ const ActionBegin = ({ </div> <div className="action-duration text-18"> {t('action.duration', { - // eslint-disable-next-line camelcase - smart_count: currentAction.actionDuration, + smartCount: currentAction.actionDuration, })} </div> <div className="action-text text-18-bold"> @@ -118,7 +109,7 @@ const ActionBegin = ({ {t('action.apply')} </Button> <Button - onClick={goToList} + onClick={() => setShowList(true)} classes={{ root: 'btn-secondary-negative', label: 'text-16-normal', diff --git a/src/components/Action/__snapshots__/ActionBegin.spec.tsx.snap b/src/components/Action/ActionBegin/__snapshots__/ActionBegin.spec.tsx.snap similarity index 99% rename from src/components/Action/__snapshots__/ActionBegin.spec.tsx.snap rename to src/components/Action/ActionBegin/__snapshots__/ActionBegin.spec.tsx.snap index bc15c74764a44b76d7ae970ce1e889f84b8708c5..72c90f35e2cbce3c8ffb4a40d599b0ffc929dc63 100644 --- a/src/components/Action/__snapshots__/ActionBegin.spec.tsx.snap +++ b/src/components/Action/ActionBegin/__snapshots__/ActionBegin.spec.tsx.snap @@ -203,13 +203,13 @@ exports[`ActionBegin component should render correctly 1`] = ` > <StyledIcon className="action-icon" - icon="" + icon="test-file-stub" size={100} > <Icon aria-hidden={true} className="action-icon" - icon="" + icon="test-file-stub" size={100} spin={false} > @@ -228,7 +228,7 @@ exports[`ActionBegin component should render correctly 1`] = ` width={100} > <use - xlinkHref="#" + xlinkHref="#test-file-stub" /> </svg> </Component> diff --git a/src/components/Action/actionBegin.scss b/src/components/Action/ActionBegin/actionBegin.scss similarity index 95% rename from src/components/Action/actionBegin.scss rename to src/components/Action/ActionBegin/actionBegin.scss index 8acf26de8cfdcecb1fb86f806ef72cd3b17e310f..06c170409b17adcaaea2736f0c89dac2573d6dda 100644 --- a/src/components/Action/actionBegin.scss +++ b/src/components/Action/ActionBegin/actionBegin.scss @@ -1,5 +1,5 @@ -@import '../../styles/base/color'; -@import '../../styles/base/breakpoint'; +@import 'src/styles/base/color'; +@import 'src/styles/base/breakpoint'; .action-begin { margin: auto; diff --git a/src/components/Action/ActionCard.spec.tsx b/src/components/Action/ActionCard.spec.tsx deleted file mode 100644 index 2ae077fe99117ec54816805fd08b8a01da2c5620..0000000000000000000000000000000000000000 --- a/src/components/Action/ActionCard.spec.tsx +++ /dev/null @@ -1,77 +0,0 @@ -import { Button } from '@material-ui/core' -import defaultIcon from 'assets/icons/visu/duel/default.svg' -import EcogestureModal from 'components/Ecogesture/EcogestureModal' -import { mount } from 'enzyme' -import toJson from 'enzyme-to-json' -import React from 'react' -import { Provider } from 'react-redux' -import configureStore from 'redux-mock-store' -import { defaultEcogestureData } from '../../../tests/__mocks__/actionData.mock' -import { globalStateData } from '../../../tests/__mocks__/globalStateData.mock' -import { profileData } from '../../../tests/__mocks__/profileData.mock' -import { waitForComponentToPaint } from '../../../tests/__mocks__/testUtils' -import { userChallengeData } from '../../../tests/__mocks__/userChallengeData.mock' -import ActionCard from './ActionCard' - -const mockStore = configureStore([]) - -jest.mock('cozy-ui/transpiled/react/I18n', () => { - return { - useI18n: jest.fn(() => { - return { - t: (str: string) => str, - } - }), - } -}) - -const mockImportIconById = jest.fn(() => defaultIcon) -jest.mock('utils/utils', () => { - return { - importIconById: jest.fn(() => { - return mockImportIconById - }), - } -}) -describe('ActionCard component', () => { - it('should be rendered correctly', async () => { - const store = mockStore({ - ecolyo: { - challenge: userChallengeData[1], - global: { ...globalStateData, fluidTypes: [0, 1, 2] }, - profile: profileData, - }, - }) - const wrapper = mount( - <Provider store={store}> - <ActionCard - setShowList={jest.fn()} - setSelectedAction={jest.fn()} - action={defaultEcogestureData[1]} - /> - </Provider> - ) - await waitForComponentToPaint(wrapper) - expect(toJson(wrapper)).toMatchSnapshot() - }) - it('should open modal', () => { - const store = mockStore({ - ecolyo: { - challenge: userChallengeData[1], - global: { ...globalStateData, fluidTypes: [0, 1, 2] }, - profile: profileData, - }, - }) - const wrapper = mount( - <Provider store={store}> - <ActionCard - setShowList={jest.fn()} - setSelectedAction={jest.fn()} - action={defaultEcogestureData[1]} - /> - </Provider> - ) - wrapper.find(Button).first().simulate('click') - expect(wrapper.find(EcogestureModal).exists()).toBeTruthy() - }) -}) diff --git a/src/components/Action/ActionCard/ActionCard.spec.tsx b/src/components/Action/ActionCard/ActionCard.spec.tsx new file mode 100644 index 0000000000000000000000000000000000000000..fee4477b804e9af5d1fbc67c7d044293ecaa758e --- /dev/null +++ b/src/components/Action/ActionCard/ActionCard.spec.tsx @@ -0,0 +1,46 @@ +import { Button } from '@material-ui/core' +import EcogestureModal from 'components/Ecogesture/EcogestureModal/EcogestureModal' +import { mount } from 'enzyme' +import toJson from 'enzyme-to-json' +import React from 'react' +import { Provider } from 'react-redux' +import { defaultEcogestureData } from 'tests/__mocks__/actionData.mock' +import { createMockEcolyoStore } from 'tests/__mocks__/store' +import { waitForComponentToPaint } from 'tests/__mocks__/testUtils' +import { userChallengeData } from 'tests/__mocks__/userChallengeData.mock' +import ActionCard from './ActionCard' + +describe('ActionCard component', () => { + const store = createMockEcolyoStore({ + challenge: { + currentChallenge: userChallengeData[1], + }, + }) + it('should be rendered correctly', async () => { + const wrapper = mount( + <Provider store={store}> + <ActionCard + setShowList={jest.fn()} + setSelectedAction={jest.fn()} + action={defaultEcogestureData[1]} + /> + </Provider> + ) + await waitForComponentToPaint(wrapper) + expect(toJson(wrapper)).toMatchSnapshot() + }) + it('should open modal', async () => { + const wrapper = mount( + <Provider store={store}> + <ActionCard + setShowList={jest.fn()} + setSelectedAction={jest.fn()} + action={defaultEcogestureData[1]} + /> + </Provider> + ) + await waitForComponentToPaint(wrapper) + wrapper.find(Button).first().simulate('click') + expect(wrapper.find(EcogestureModal).exists()).toBeTruthy() + }) +}) diff --git a/src/components/Action/ActionCard.tsx b/src/components/Action/ActionCard/ActionCard.tsx similarity index 85% rename from src/components/Action/ActionCard.tsx rename to src/components/Action/ActionCard/ActionCard.tsx index 9b491e035b0c55d4bd4a7484e9bf5fd38e5970ad..7c4fa8b98a06bd6182b84a2ba640c7a0be66bd96 100644 --- a/src/components/Action/ActionCard.tsx +++ b/src/components/Action/ActionCard/ActionCard.tsx @@ -1,16 +1,15 @@ import { Button } from '@material-ui/core' import defaultIcon from 'assets/icons/visu/ecogesture/default.svg' import StyledIcon from 'components/CommonKit/Icon/StyledIcon' -import EcogestureModal from 'components/Ecogesture/EcogestureModal' +import EcogestureModal from 'components/Ecogesture/EcogestureModal/EcogestureModal' import { useClient } from 'cozy-client' -import { UsageEventType } from 'enum/usageEvent.enum' +import { UsageEventType } from 'enums' import { Ecogesture } from 'models' import React, { useCallback, useEffect, useState } from 'react' -import { useSelector } from 'react-redux' import UsageEventService from 'services/usageEvent.service' -import { AppStore } from 'store' +import { useAppSelector } from 'store/hooks' import { importIconById } from 'utils/utils' -import './actionList.scss' +import './actionCard.scss' interface ActionCardProps { action: Ecogesture @@ -26,9 +25,7 @@ const ActionCard = ({ const [actionIcon, setActionIcon] = useState<string>('') const [openEcogestureModal, setOpenEcogestureModal] = useState<boolean>(false) const client = useClient() - const { currentChallenge } = useSelector( - (state: AppStore) => state.ecolyo.challenge - ) + const { currentChallenge } = useAppSelector(state => state.ecolyo.challenge) const toggleModal = useCallback(() => { setOpenEcogestureModal(prev => !prev) }, []) @@ -54,11 +51,7 @@ const ActionCard = ({ useEffect(() => { async function handleEcogestureIcon() { const icon = await importIconById(action.id, 'ecogesture') - if (icon) { - setActionIcon(icon) - } else { - setActionIcon(defaultIcon) - } + setActionIcon(icon || defaultIcon) } handleEcogestureIcon() }, [action]) diff --git a/src/components/Action/__snapshots__/ActionCard.spec.tsx.snap b/src/components/Action/ActionCard/__snapshots__/ActionCard.spec.tsx.snap similarity index 100% rename from src/components/Action/__snapshots__/ActionCard.spec.tsx.snap rename to src/components/Action/ActionCard/__snapshots__/ActionCard.spec.tsx.snap diff --git a/src/components/Action/actionList.scss b/src/components/Action/ActionCard/actionCard.scss similarity index 61% rename from src/components/Action/actionList.scss rename to src/components/Action/ActionCard/actionCard.scss index 4b4c65a2f9f66f5cbac5928d4be39fc04702fb75..ad7e7498bdd83f5d1623e815386c432c387babae 100644 --- a/src/components/Action/actionList.scss +++ b/src/components/Action/ActionCard/actionCard.scss @@ -1,17 +1,5 @@ -@import '../../styles/base/color'; +@import 'src/styles/base/color'; -.action-list-container { - display: flex; - flex-direction: column; - align-items: center; - justify-content: center; - max-width: 600px; - margin: auto; - gap: 1rem; - width: 100%; - box-sizing: border-box; - padding: 0 1.5rem; -} button.action-card { width: 100%; box-sizing: border-box; diff --git a/src/components/Action/ActionChoose.spec.tsx b/src/components/Action/ActionChoose.spec.tsx deleted file mode 100644 index 90c43e9aa9782a844c0032111c67dfda64fb671b..0000000000000000000000000000000000000000 --- a/src/components/Action/ActionChoose.spec.tsx +++ /dev/null @@ -1,65 +0,0 @@ -import { mount } from 'enzyme' -import toJson from 'enzyme-to-json' -import React from 'react' -import { Provider } from 'react-redux' -import configureStore from 'redux-mock-store' -import { globalStateData } from '../../../tests/__mocks__/globalStateData.mock' -import { profileData } from '../../../tests/__mocks__/profileData.mock' -import { waitForComponentToPaint } from '../../../tests/__mocks__/testUtils' -import { userChallengeData } from '../../../tests/__mocks__/userChallengeData.mock' -import ActionBegin from './ActionBegin' -import ActionChoose from './ActionChoose' - -jest.mock('cozy-ui/transpiled/react/I18n', () => { - return { - useI18n: jest.fn(() => { - return { - t: (str: string) => str, - } - }), - } -}) - -const mockGetEcogesturesByIds = jest.fn(() => []) -jest.mock('services/ecogesture.service', () => { - return jest.fn(() => { - return { - getEcogesturesByIds: mockGetEcogesturesByIds, - } - }) -}) -const mockStore = configureStore([]) - -describe('ActionChoose component', () => { - it('should render correctly', async () => { - const store = mockStore({ - ecolyo: { - challenge: userChallengeData[1], - global: { ...globalStateData, fluidTypes: [0, 1, 2] }, - profile: profileData, - }, - }) - const wrapper = mount( - <Provider store={store}> - <ActionChoose userChallenge={userChallengeData[1]} /> - </Provider> - ) - await waitForComponentToPaint(wrapper) - expect(toJson(wrapper)).toMatchSnapshot() - }) - it('should render ActionBegin component', async () => { - const store = mockStore({ - ecolyo: { - challenge: userChallengeData[1], - global: { ...globalStateData, fluidTypes: [0, 1, 2] }, - profile: profileData, - }, - }) - const wrapper = mount( - <Provider store={store}> - <ActionChoose userChallenge={userChallengeData[1]} /> - </Provider> - ) - expect(wrapper.find(ActionBegin).exists()).toBeTruthy() - }) -}) diff --git a/src/components/Action/ActionChoose/ActionChoose.spec.tsx b/src/components/Action/ActionChoose/ActionChoose.spec.tsx new file mode 100644 index 0000000000000000000000000000000000000000..93f2bcdac3ccd81c76135f09db10b4a2ba320ef7 --- /dev/null +++ b/src/components/Action/ActionChoose/ActionChoose.spec.tsx @@ -0,0 +1,44 @@ +import { mount } from 'enzyme' +import toJson from 'enzyme-to-json' +import React from 'react' +import { Provider } from 'react-redux' +import { + createMockEcolyoStore, + mockGlobalState, + mockProfileState, +} from 'tests/__mocks__/store' +import { waitForComponentToPaint } from 'tests/__mocks__/testUtils' +import { userChallengeData } from 'tests/__mocks__/userChallengeData.mock' +import ActionBegin from '../ActionBegin/ActionBegin' +import ActionChoose from './ActionChoose' + +const mockGetEcogesturesByIds = jest.fn(() => []) +jest.mock('services/ecogesture.service', () => { + return jest.fn(() => ({ + getEcogesturesByIds: mockGetEcogesturesByIds, + })) +}) + +describe('ActionChoose component', () => { + const store = createMockEcolyoStore({ + global: { ...mockGlobalState, fluidTypes: [0, 1, 2] }, + profile: mockProfileState, + }) + it('should render correctly', async () => { + const wrapper = mount( + <Provider store={store}> + <ActionChoose userChallenge={userChallengeData[1]} /> + </Provider> + ) + await waitForComponentToPaint(wrapper) + expect(toJson(wrapper)).toMatchSnapshot() + }) + it('should render ActionBegin component', async () => { + const wrapper = mount( + <Provider store={store}> + <ActionChoose userChallenge={userChallengeData[1]} /> + </Provider> + ) + expect(wrapper.find(ActionBegin).exists()).toBeTruthy() + }) +}) diff --git a/src/components/Action/ActionChoose.tsx b/src/components/Action/ActionChoose/ActionChoose.tsx similarity index 86% rename from src/components/Action/ActionChoose.tsx rename to src/components/Action/ActionChoose/ActionChoose.tsx index c137680a92c4bcc5e4c320062beac5bf3d11544e..b1e7d3ad7da0a3e597a1281a0b25a2121b73d474 100644 --- a/src/components/Action/ActionChoose.tsx +++ b/src/components/Action/ActionChoose/ActionChoose.tsx @@ -1,7 +1,7 @@ -import ActionBegin from 'components/Action/ActionBegin' -import ActionList from 'components/Action/ActionList' import { Ecogesture, UserChallenge } from 'models' import React, { useState } from 'react' +import ActionBegin from '../ActionBegin/ActionBegin' +import ActionList from '../ActionList/ActionList' const ActionChoose = ({ userChallenge }: { userChallenge: UserChallenge }) => { const [selectedAction, setSelectedAction] = useState<Ecogesture | null>(null) diff --git a/src/components/Action/__snapshots__/ActionChoose.spec.tsx.snap b/src/components/Action/ActionChoose/__snapshots__/ActionChoose.spec.tsx.snap similarity index 100% rename from src/components/Action/__snapshots__/ActionChoose.spec.tsx.snap rename to src/components/Action/ActionChoose/__snapshots__/ActionChoose.spec.tsx.snap diff --git a/src/components/Action/ActionDone.spec.tsx b/src/components/Action/ActionDone.spec.tsx deleted file mode 100644 index 42092cfa722331bf38ffbaad04891c275257d0aa..0000000000000000000000000000000000000000 --- a/src/components/Action/ActionDone.spec.tsx +++ /dev/null @@ -1,85 +0,0 @@ -import { Button } from '@material-ui/core' -import { mount } from 'enzyme' -import toJson from 'enzyme-to-json' -import React from 'react' -import * as reactRedux from 'react-redux' -import { Provider } from 'react-redux' -import configureStore from 'redux-mock-store' -import UsageEventService from 'services/usageEvent.service' -import * as challengeActions from 'store/challenge/challenge.slice' -import { globalStateData } from '../../../tests/__mocks__/globalStateData.mock' -import { profileData } from '../../../tests/__mocks__/profileData.mock' -import { waitForComponentToPaint } from '../../../tests/__mocks__/testUtils' -import { userChallengeData } from '../../../tests/__mocks__/userChallengeData.mock' -import ActionDone from './ActionDone' - -const mockStore = configureStore([]) -jest.mock('cozy-ui/transpiled/react/I18n', () => { - return { - useI18n: jest.fn(() => { - return { - t: (str: string) => str, - } - }), - } -}) -jest.mock('services/usageEvent.service') -const mockAddEvent = jest.fn() -UsageEventService.addEvent = mockAddEvent - -const mockedNavigate = jest.fn() -jest.mock('react-router-dom', () => ({ - ...jest.requireActual('react-router-dom'), - useNavigate: () => mockedNavigate, -})) -const mockupdateUserChallenge = jest.fn() -jest.mock('services/challenge.service', () => { - return jest.fn(() => { - return { - updateUserChallenge: mockupdateUserChallenge, - } - }) -}) - -describe('ActionDone component', () => { - it('should be rendered correctly', async () => { - const store = mockStore({ - ecolyo: { - challenge: userChallengeData[1], - global: { ...globalStateData, fluidTypes: [0, 1, 2] }, - profile: profileData, - }, - }) - const wrapper = mount( - <Provider store={store}> - <ActionDone currentChallenge={userChallengeData[1]} /> - </Provider> - ) - await waitForComponentToPaint(wrapper) - expect(toJson(wrapper)).toMatchSnapshot() - }) - it('should click on button and update action to done', async () => { - const useDispatchSpy = jest.spyOn(reactRedux, 'useDispatch') - const updateChallengeSpy = jest.spyOn( - challengeActions, - 'updateUserChallengeList' - ) - const store = mockStore({ - ecolyo: { - challenge: userChallengeData[1], - global: { ...globalStateData, fluidTypes: [0, 1, 2] }, - profile: profileData, - }, - }) - mockupdateUserChallenge.mockResolvedValueOnce(userChallengeData[1]) - useDispatchSpy.mockReturnValue(jest.fn()) - const wrapper = mount( - <Provider store={store}> - <ActionDone currentChallenge={userChallengeData[1]} /> - </Provider> - ) - wrapper.find(Button).first().simulate('click') - await waitForComponentToPaint(wrapper) - expect(updateChallengeSpy).toBeCalledTimes(1) - }) -}) diff --git a/src/components/Action/ActionDone/ActionDone.spec.tsx b/src/components/Action/ActionDone/ActionDone.spec.tsx new file mode 100644 index 0000000000000000000000000000000000000000..768da199887dc48d1a6ca651b3a44471b085fb8b --- /dev/null +++ b/src/components/Action/ActionDone/ActionDone.spec.tsx @@ -0,0 +1,50 @@ +import { Button } from '@material-ui/core' +import { mount } from 'enzyme' +import toJson from 'enzyme-to-json' +import React from 'react' +import { Provider } from 'react-redux' +import UsageEventService from 'services/usageEvent.service' +import * as challengeActions from 'store/challenge/challenge.slice' +import { createMockEcolyoStore } from 'tests/__mocks__/store' +import { waitForComponentToPaint } from 'tests/__mocks__/testUtils' +import { userChallengeData } from 'tests/__mocks__/userChallengeData.mock' +import ActionDone from './ActionDone' + +jest.mock('services/usageEvent.service') +const mockAddEvent = jest.fn() +UsageEventService.addEvent = mockAddEvent + +const mockUpdateUserChallenge = jest.fn() +jest.mock('services/challenge.service', () => { + return jest.fn(() => ({ + updateUserChallenge: mockUpdateUserChallenge, + })) +}) + +describe('ActionDone component', () => { + const store = createMockEcolyoStore() + it('should be rendered correctly', async () => { + const wrapper = mount( + <Provider store={store}> + <ActionDone currentChallenge={userChallengeData[1]} /> + </Provider> + ) + await waitForComponentToPaint(wrapper) + expect(toJson(wrapper)).toMatchSnapshot() + }) + it('should click on button and update action to done', async () => { + const updateChallengeSpy = jest.spyOn( + challengeActions, + 'updateUserChallengeList' + ) + mockUpdateUserChallenge.mockResolvedValueOnce(userChallengeData[1]) + const wrapper = mount( + <Provider store={store}> + <ActionDone currentChallenge={userChallengeData[1]} /> + </Provider> + ) + wrapper.find(Button).first().simulate('click') + await waitForComponentToPaint(wrapper) + expect(updateChallengeSpy).toHaveBeenCalledTimes(1) + }) +}) diff --git a/src/components/Action/ActionDone.tsx b/src/components/Action/ActionDone/ActionDone.tsx similarity index 88% rename from src/components/Action/ActionDone.tsx rename to src/components/Action/ActionDone/ActionDone.tsx index 099c9465febbb923f08efee022b1547078387524..0fb8bf669abe747d9cb6589a0ae79a38c5627ad6 100644 --- a/src/components/Action/ActionDone.tsx +++ b/src/components/Action/ActionDone/ActionDone.tsx @@ -3,17 +3,15 @@ import starFilled from 'assets/icons/visu/challenge/starFilled.svg' import StyledIcon from 'components/CommonKit/Icon/StyledIcon' import { useClient } from 'cozy-client' import { useI18n } from 'cozy-ui/transpiled/react/I18n' -import { UsageEventType } from 'enum/usageEvent.enum' -import { UserChallengeUpdateFlag } from 'enum/userChallenge.enum' +import { UsageEventType, UserChallengeUpdateFlag } from 'enums' import { UserChallenge } from 'models' -import React, { Dispatch, useCallback } from 'react' -import { useDispatch } from 'react-redux' +import React, { useCallback } from 'react' import { useNavigate } from 'react-router-dom' import ChallengeService from 'services/challenge.service' import UsageEventService from 'services/usageEvent.service' -import { AppActionsTypes } from 'store' import { updateUserChallengeList } from 'store/challenge/challenge.slice' -import { toggleChallengeActionNotification } from 'store/global/global.actions' +import { toggleChallengeActionNotification } from 'store/global/global.slice' +import { useAppDispatch } from 'store/hooks' import './actionDone.scss' const ActionDone = ({ @@ -23,7 +21,7 @@ const ActionDone = ({ }) => { const { t } = useI18n() const client = useClient() - const dispatch = useDispatch<Dispatch<AppActionsTypes>>() + const dispatch = useAppDispatch() const navigate = useNavigate() const handleEndAction = useCallback(async () => { const challengeService = new ChallengeService(client) diff --git a/src/components/Action/__snapshots__/ActionDone.spec.tsx.snap b/src/components/Action/ActionDone/__snapshots__/ActionDone.spec.tsx.snap similarity index 100% rename from src/components/Action/__snapshots__/ActionDone.spec.tsx.snap rename to src/components/Action/ActionDone/__snapshots__/ActionDone.spec.tsx.snap diff --git a/src/components/Action/actionDone.scss b/src/components/Action/ActionDone/actionDone.scss similarity index 91% rename from src/components/Action/actionDone.scss rename to src/components/Action/ActionDone/actionDone.scss index 4a5de7d211b0b6e4d5015e55bb6eb9122e79fb99..ce2f02bcfcc24ce0030964bb18aa0da532c267e4 100644 --- a/src/components/Action/actionDone.scss +++ b/src/components/Action/ActionDone/actionDone.scss @@ -1,5 +1,5 @@ -@import '../../styles/base/color'; -@import '../../styles/base/breakpoint'; +@import 'src/styles/base/color'; +@import 'src/styles/base/breakpoint'; .action-done-container { max-width: 600px; diff --git a/src/components/Action/ActionList.spec.tsx b/src/components/Action/ActionList.spec.tsx deleted file mode 100644 index 85516527b9cc7b8cbba8b9bf854dc0f5be14063a..0000000000000000000000000000000000000000 --- a/src/components/Action/ActionList.spec.tsx +++ /dev/null @@ -1,53 +0,0 @@ -import { mount } from 'enzyme' -import React from 'react' -import { Provider } from 'react-redux' -import configureStore from 'redux-mock-store' -import { defaultEcogestureData } from '../../../tests/__mocks__/actionData.mock' -import { globalStateData } from '../../../tests/__mocks__/globalStateData.mock' -import { profileData } from '../../../tests/__mocks__/profileData.mock' -import { userChallengeData } from '../../../tests/__mocks__/userChallengeData.mock' -import ActionCard from './ActionCard' -import ActionList from './ActionList' - -const mockStore = configureStore([]) - -const mockgetCustomActions = jest.fn() -const mockgetDefaultActions = jest.fn() - -jest.mock('services/action.service', () => { - return jest.fn(() => { - return { - getCustomActions: mockgetCustomActions, - getDefaultActions: mockgetDefaultActions, - } - }) -}) - -jest.mock('cozy-ui/transpiled/react/I18n', () => { - return { - useI18n: jest.fn(() => { - return { - t: (str: string) => str, - } - }), - } -}) - -describe('ActionList component', () => { - it('should be rendered correctly', () => { - mockgetDefaultActions.mockResolvedValueOnce(defaultEcogestureData) - const store = mockStore({ - ecolyo: { - challenge: userChallengeData[1], - global: { ...globalStateData, fluidTypes: [0, 1, 2] }, - profile: profileData, - }, - }) - const wrapper = mount( - <Provider store={store}> - <ActionList setSelectedAction={jest.fn()} setShowList={jest.fn()} /> - </Provider> - ) - expect(wrapper.find(ActionCard).exists()) - }) -}) diff --git a/src/components/Action/ActionList/ActionList.spec.tsx b/src/components/Action/ActionList/ActionList.spec.tsx new file mode 100644 index 0000000000000000000000000000000000000000..aad7a7a4c8c1a3be11d95e0535f18849194a303b --- /dev/null +++ b/src/components/Action/ActionList/ActionList.spec.tsx @@ -0,0 +1,40 @@ +import { mount } from 'enzyme' +import React from 'react' +import { Provider } from 'react-redux' +import { defaultEcogestureData } from 'tests/__mocks__/actionData.mock' +import { + createMockEcolyoStore, + mockChallengeState, + mockProfileState, +} from 'tests/__mocks__/store' +import { waitForComponentToPaint } from 'tests/__mocks__/testUtils' +import ActionCard from '../ActionCard/ActionCard' +import ActionList from './ActionList' + +const mockGetCustomActions = jest.fn() +const mockGetDefaultActions = jest.fn() + +jest.mock('services/action.service', () => { + return jest.fn(() => ({ + getCustomActions: mockGetCustomActions, + getDefaultActions: mockGetDefaultActions, + })) +}) + +describe('ActionList component', () => { + it('should be rendered correctly', async () => { + mockGetDefaultActions.mockResolvedValueOnce(defaultEcogestureData) + const store = createMockEcolyoStore({ + challenge: { ...mockChallengeState }, + global: { fluidTypes: [0, 1, 2] }, + profile: mockProfileState, + }) + const wrapper = mount( + <Provider store={store}> + <ActionList setSelectedAction={jest.fn()} setShowList={jest.fn()} /> + </Provider> + ) + await waitForComponentToPaint(wrapper) + expect(wrapper.find(ActionCard)).toBeTruthy() + }) +}) diff --git a/src/components/Action/ActionList.tsx b/src/components/Action/ActionList/ActionList.tsx similarity index 88% rename from src/components/Action/ActionList.tsx rename to src/components/Action/ActionList/ActionList.tsx index b218dd7b11acd4343b427657b4f45b6673c2f996..a9ff78bb19ceecae75a24f23cd949fcb92aef6f1 100644 --- a/src/components/Action/ActionList.tsx +++ b/src/components/Action/ActionList/ActionList.tsx @@ -1,11 +1,10 @@ -import ActionCard from 'components/Action/ActionCard' +import ActionCard from 'components/Action/ActionCard/ActionCard' import { Client, useClient } from 'cozy-client' import { Ecogesture } from 'models' import React, { useEffect, useState } from 'react' -import { useSelector } from 'react-redux' import ActionService from 'services/action.service' -import { AppStore } from 'store' -import './actionBegin.scss' +import { useAppSelector } from 'store/hooks' +import './actionList.scss' interface ActionListProps { setSelectedAction: React.Dispatch<React.SetStateAction<Ecogesture | null>> @@ -17,7 +16,7 @@ const ActionList = ({ setSelectedAction, setShowList }: ActionListProps) => { const { global: { fluidTypes }, profile: { isProfileTypeCompleted }, - } = useSelector((state: AppStore) => state.ecolyo) + } = useAppSelector(state => state.ecolyo) const [actions, setActions] = useState<Ecogesture[]>() useEffect(() => { diff --git a/src/components/Action/ActionList/actionList.scss b/src/components/Action/ActionList/actionList.scss new file mode 100644 index 0000000000000000000000000000000000000000..038a216c511e134d97407763266980321ab56f58 --- /dev/null +++ b/src/components/Action/ActionList/actionList.scss @@ -0,0 +1,14 @@ +@import 'src/styles/base/color'; + +.action-list-container { + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + max-width: 600px; + margin: auto; + gap: 1rem; + width: 100%; + box-sizing: border-box; + padding: 0 1.5rem; +} diff --git a/src/components/Action/ActionModal.spec.tsx b/src/components/Action/ActionModal/ActionModal.spec.tsx similarity index 51% rename from src/components/Action/ActionModal.spec.tsx rename to src/components/Action/ActionModal/ActionModal.spec.tsx index 23002a23f01e36f785fbace2c052742ab8bdbb46..4507b4c42146b6cae0d2cf481ba60fee067887fb 100644 --- a/src/components/Action/ActionModal.spec.tsx +++ b/src/components/Action/ActionModal/ActionModal.spec.tsx @@ -2,49 +2,28 @@ import { Button } from '@material-ui/core' import { mount } from 'enzyme' import toJson from 'enzyme-to-json' import React from 'react' -import * as reactRedux from 'react-redux' import { Provider } from 'react-redux' -import configureStore from 'redux-mock-store' import UsageEventService from 'services/usageEvent.service' import * as challengeActions from 'store/challenge/challenge.slice' -import { defaultEcogestureData } from '../../../tests/__mocks__/actionData.mock' -import { globalStateData } from '../../../tests/__mocks__/globalStateData.mock' -import { profileData } from '../../../tests/__mocks__/profileData.mock' -import { waitForComponentToPaint } from '../../../tests/__mocks__/testUtils' -import { userChallengeData } from '../../../tests/__mocks__/userChallengeData.mock' +import { defaultEcogestureData } from 'tests/__mocks__/actionData.mock' +import { createMockEcolyoStore } from 'tests/__mocks__/store' +import { waitForComponentToPaint } from 'tests/__mocks__/testUtils' +import { userChallengeData } from 'tests/__mocks__/userChallengeData.mock' import ActionModal from './ActionModal' -jest.mock('cozy-ui/transpiled/react/I18n', () => { - return { - useI18n: jest.fn(() => { - return { - t: (str: string) => str, - } - }), - } -}) -const mockupdateUserChallenge = jest.fn() +const mockUpdateUserChallenge = jest.fn() jest.mock('services/challenge.service', () => { - return jest.fn(() => { - return { - updateUserChallenge: mockupdateUserChallenge, - } - }) + return jest.fn(() => ({ + updateUserChallenge: mockUpdateUserChallenge, + })) }) jest.mock('services/usageEvent.service') const mockAddEvent = jest.fn() UsageEventService.addEvent = mockAddEvent -const mockStore = configureStore([]) describe('ActionModal component', () => { + const store = createMockEcolyoStore() it('should render correctly', async () => { - const store = mockStore({ - ecolyo: { - challenge: userChallengeData[1], - global: { ...globalStateData, fluidTypes: [0, 1, 2] }, - profile: profileData, - }, - }) const wrapper = mount( <Provider store={store}> <ActionModal @@ -59,21 +38,11 @@ describe('ActionModal component', () => { expect(toJson(wrapper)).toMatchSnapshot() }) it('should click on button and update action to ongoing', async () => { - const useDispatchSpy = jest.spyOn(reactRedux, 'useDispatch') const updateChallengeSpy = jest.spyOn( challengeActions, 'updateUserChallengeList' ) - - const store = mockStore({ - ecolyo: { - challenge: userChallengeData[1], - global: { ...globalStateData, fluidTypes: [0, 1, 2] }, - profile: profileData, - }, - }) - mockupdateUserChallenge.mockResolvedValueOnce(userChallengeData[1]) - useDispatchSpy.mockReturnValue(jest.fn()) + mockUpdateUserChallenge.mockResolvedValueOnce(userChallengeData[1]) const wrapper = mount( <Provider store={store}> @@ -87,6 +56,6 @@ describe('ActionModal component', () => { ) wrapper.find(Button).first().simulate('click') await waitForComponentToPaint(wrapper) - expect(updateChallengeSpy).toBeCalledTimes(1) + expect(updateChallengeSpy).toHaveBeenCalledTimes(1) }) }) diff --git a/src/components/Action/ActionModal.tsx b/src/components/Action/ActionModal/ActionModal.tsx similarity index 84% rename from src/components/Action/ActionModal.tsx rename to src/components/Action/ActionModal/ActionModal.tsx index b58e54f40a0fe4dee367da8ab58d2bc9c89c38e2..c8de7f28d15013698ac854b46ab1c4b21e31ac94 100644 --- a/src/components/Action/ActionModal.tsx +++ b/src/components/Action/ActionModal/ActionModal.tsx @@ -4,13 +4,12 @@ import chronoMini from 'assets/icons/visu/action/chrono-mini.svg' import { useClient } from 'cozy-client' import { useI18n } from 'cozy-ui/transpiled/react/I18n' import Icon from 'cozy-ui/transpiled/react/Icon' -import { UserChallengeUpdateFlag } from 'enum/userChallenge.enum' +import { UserChallengeUpdateFlag } from 'enums' import { Ecogesture, UserChallenge } from 'models' -import React, { Dispatch, useCallback } from 'react' -import { useDispatch } from 'react-redux' +import React, { useCallback } from 'react' import ChallengeService from 'services/challenge.service' -import { AppActionsTypes } from 'store' import { updateUserChallengeList } from 'store/challenge/challenge.slice' +import { useAppDispatch } from 'store/hooks' import './actionModal.scss' interface ActionModalProps { @@ -26,9 +25,9 @@ const ActionModal = ({ handleCloseClick, userChallenge, }: ActionModalProps) => { - const dispatch = useDispatch<Dispatch<AppActionsTypes>>() const client = useClient() const { t } = useI18n() + const dispatch = useAppDispatch() const launchAction = useCallback(async () => { const challengeService = new ChallengeService(client) const updatedChallenge: UserChallenge = @@ -46,21 +45,20 @@ const ActionModal = ({ <Dialog open={open} onClose={handleCloseClick} - aria-labelledby={'accessibility-title'} + aria-labelledby="accessibility-title" classes={{ root: 'modal-root', paper: 'modal-paper', }} > - <div id={'accessibility-title'}> + <div id="accessibility-title"> {t('action_modal.accessibility.window_title')} </div> <div className="action-modal"> <Icon icon={chronoMini} size={75} /> <div className="action-title text-16-normal"> {t('action.duration', { - // eslint-disable-next-line camelcase - smart_count: action.actionDuration, + smartCount: action.actionDuration, })} </div> <div className="action-text text-16-normal">{action.longName}</div> diff --git a/src/components/Action/__snapshots__/ActionModal.spec.tsx.snap b/src/components/Action/ActionModal/__snapshots__/ActionModal.spec.tsx.snap similarity index 100% rename from src/components/Action/__snapshots__/ActionModal.spec.tsx.snap rename to src/components/Action/ActionModal/__snapshots__/ActionModal.spec.tsx.snap diff --git a/src/components/Action/actionModal.scss b/src/components/Action/ActionModal/actionModal.scss similarity index 91% rename from src/components/Action/actionModal.scss rename to src/components/Action/ActionModal/actionModal.scss index 5b35affa4321f50e90f2e3970945b3bc1e88df62..ff9d610dd92a77744ee8286fee2793ae44da5f62 100644 --- a/src/components/Action/actionModal.scss +++ b/src/components/Action/ActionModal/actionModal.scss @@ -1,4 +1,4 @@ -@import '../../styles/base/color'; +@import 'src/styles/base/color'; .action-modal { display: flex; diff --git a/src/components/Action/ActionOnGoing.spec.tsx b/src/components/Action/ActionOnGoing/ActionOnGoing.spec.tsx similarity index 53% rename from src/components/Action/ActionOnGoing.spec.tsx rename to src/components/Action/ActionOnGoing/ActionOnGoing.spec.tsx index 3929b747111b4194ba52c3f4b71f4805a20a0efb..de69a0814379f8b24950e6235fc664908603cf8c 100644 --- a/src/components/Action/ActionOnGoing.spec.tsx +++ b/src/components/Action/ActionOnGoing/ActionOnGoing.spec.tsx @@ -1,41 +1,21 @@ import { Button } from '@material-ui/core' -import EcogestureModal from 'components/Ecogesture/EcogestureModal' -import { UserActionState } from 'enum/userAction.enum' +import EcogestureModal from 'components/Ecogesture/EcogestureModal/EcogestureModal' +import { UserActionState } from 'enums' import { mount } from 'enzyme' import toJson from 'enzyme-to-json' import { DateTime } from 'luxon' import { UserAction } from 'models' import React from 'react' import { Provider } from 'react-redux' -import configureStore from 'redux-mock-store' -import { defaultEcogestureData } from '../../../tests/__mocks__/actionData.mock' -import { globalStateData } from '../../../tests/__mocks__/globalStateData.mock' -import { profileData } from '../../../tests/__mocks__/profileData.mock' -import { waitForComponentToPaint } from '../../../tests/__mocks__/testUtils' -import { userChallengeData } from '../../../tests/__mocks__/userChallengeData.mock' +import { defaultEcogestureData } from 'tests/__mocks__/actionData.mock' +import { createMockEcolyoStore } from 'tests/__mocks__/store' +import { waitForComponentToPaint } from 'tests/__mocks__/testUtils' import ActionOnGoing from './ActionOnGoing' -jest.mock('cozy-ui/transpiled/react/I18n', () => { - return { - useI18n: jest.fn(() => { - return { - t: (str: string) => str, - } - }), - } -}) -const mockImportIconById = jest.fn() -jest.mock('utils/utils', () => { - return { - importIconById: jest.fn(() => { - return mockImportIconById - }), - } -}) -const mockStore = configureStore([]) - describe('ActionOnGoing component', () => { + const store = createMockEcolyoStore() const userAction: UserAction = { + // TODO if ecogesture is null snapshot test is useless ecogesture: null, startDate: DateTime.local(2020, 1, 1) .setZone('utc', { @@ -45,14 +25,6 @@ describe('ActionOnGoing component', () => { state: UserActionState.ONGOING, } it('should render correctly', async () => { - const store = mockStore({ - ecolyo: { - challenge: userChallengeData[1], - global: { ...globalStateData, fluidTypes: [0, 1, 2] }, - profile: profileData, - }, - }) - const wrapper = mount( <Provider store={store}> <ActionOnGoing userAction={userAction} /> @@ -67,13 +39,7 @@ describe('ActionOnGoing component', () => { startDate: null, state: UserActionState.ONGOING, } - const store = mockStore({ - ecolyo: { - challenge: userChallengeData[1], - global: { ...globalStateData, fluidTypes: [0, 1, 2] }, - profile: profileData, - }, - }) + const wrapper = mount( <Provider store={store}> <ActionOnGoing userAction={userAction1} /> diff --git a/src/components/Action/ActionOnGoing.tsx b/src/components/Action/ActionOnGoing/ActionOnGoing.tsx similarity index 97% rename from src/components/Action/ActionOnGoing.tsx rename to src/components/Action/ActionOnGoing/ActionOnGoing.tsx index 28d7042995cbb41288b42d0db910c883b71bf685..5e869ec44ac786f1566741342d72d6b0f2030141 100644 --- a/src/components/Action/ActionOnGoing.tsx +++ b/src/components/Action/ActionOnGoing/ActionOnGoing.tsx @@ -1,7 +1,7 @@ import { Button } from '@material-ui/core' import ClockIcon from 'assets/icons/visu/action/duration-clock.svg' import StyledIcon from 'components/CommonKit/Icon/StyledIcon' -import EcogestureModal from 'components/Ecogesture/EcogestureModal' +import EcogestureModal from 'components/Ecogesture/EcogestureModal/EcogestureModal' import { useI18n } from 'cozy-ui/transpiled/react/I18n' import { DateTime } from 'luxon' import { UserAction } from 'models' @@ -71,8 +71,7 @@ const ActionOnGoing = ({ userAction }: { userAction: UserAction }) => { <> <div className="duration text-18-normal"> {t('action.duration', { - // eslint-disable-next-line camelcase - smart_count: userAction.ecogesture.actionDuration, + smartCount: userAction.ecogesture.actionDuration, })} </div> <div className="description text-18-bold"> diff --git a/src/components/Action/__snapshots__/ActionOnGoing.spec.tsx.snap b/src/components/Action/ActionOnGoing/__snapshots__/ActionOnGoing.spec.tsx.snap similarity index 100% rename from src/components/Action/__snapshots__/ActionOnGoing.spec.tsx.snap rename to src/components/Action/ActionOnGoing/__snapshots__/ActionOnGoing.spec.tsx.snap diff --git a/src/components/Action/actionOnGoing.scss b/src/components/Action/ActionOnGoing/actionOnGoing.scss similarity index 96% rename from src/components/Action/actionOnGoing.scss rename to src/components/Action/ActionOnGoing/actionOnGoing.scss index c1f31851b985d3d79505823d26731969c9e8d816..8aa859eb56f35ce0c9e9a2923e9b8ea8ddea80d2 100644 --- a/src/components/Action/actionOnGoing.scss +++ b/src/components/Action/ActionOnGoing/actionOnGoing.scss @@ -1,4 +1,4 @@ -@import '../../styles/base/color'; +@import 'src/styles/base/color'; .action-ongoing { box-sizing: border-box; diff --git a/src/components/Action/ActionView.spec.tsx b/src/components/Action/ActionView.spec.tsx index 70d6e9e24f7f15364d9d9291c9b2b9c9aef302d5..8f8936c0d3cf2af2b1ed9abf4ccbc39efda0fb70 100644 --- a/src/components/Action/ActionView.spec.tsx +++ b/src/components/Action/ActionView.spec.tsx @@ -1,52 +1,35 @@ import ActionView from 'components/Action/ActionView' -import { UserActionState } from 'enum/userAction.enum' +import { UserActionState } from 'enums' import { mount } from 'enzyme' import toJson from 'enzyme-to-json' import React from 'react' import { Provider } from 'react-redux' -import configureStore from 'redux-mock-store' -import { globalStateData } from '../../../tests/__mocks__/globalStateData.mock' -import { profileData } from '../../../tests/__mocks__/profileData.mock' -import { waitForComponentToPaint } from '../../../tests/__mocks__/testUtils' -import { userChallengeData } from '../../../tests/__mocks__/userChallengeData.mock' -import ActionChoose from './ActionChoose' -import ActionDone from './ActionDone' -import ActionOnGoing from './ActionOnGoing' +import { createMockEcolyoStore } from 'tests/__mocks__/store' +import { waitForComponentToPaint } from 'tests/__mocks__/testUtils' +import { userChallengeData } from 'tests/__mocks__/userChallengeData.mock' +import ActionChoose from './ActionChoose/ActionChoose' +import ActionDone from './ActionDone/ActionDone' +import ActionOnGoing from './ActionOnGoing/ActionOnGoing' -jest.mock('cozy-ui/transpiled/react/I18n', () => { - return { - useI18n: jest.fn(() => { - return { - t: (str: string) => str, - } - }), - } -}) -const mockedNavigate = jest.fn() -jest.mock('react-router-dom', () => ({ - ...jest.requireActual('react-router-dom'), - useNavigate: () => mockedNavigate, -})) jest.mock('components/Header/CozyBar', () => 'mock-cozybar') jest.mock('components/Header/Header', () => 'mock-header') jest.mock('components/Content/Content', () => 'mock-content') -jest.mock('components/Action/ActionBegin', () => 'mock-action-begin') +jest.mock( + 'components/Action/ActionBegin/ActionBegin.tsx', + () => 'mock-action-begin' +) -const mockStore = configureStore([]) describe('ActionView component', () => { it('should render ActionChoose component', async () => { - const userChallenge = { - ...userChallengeData[1], - action: { - ...userChallengeData[1].action, - state: UserActionState.UNSTARTED, - }, - } - const store = mockStore({ - ecolyo: { - challenge: { currentChallenge: userChallenge }, - global: { ...globalStateData, fluidTypes: [0, 1, 2] }, - profile: profileData, + const store = createMockEcolyoStore({ + challenge: { + currentChallenge: { + ...userChallengeData[1], + action: { + ...userChallengeData[1].action, + state: UserActionState.UNSTARTED, + }, + }, }, }) const wrapper = mount( @@ -59,18 +42,15 @@ describe('ActionView component', () => { expect(toJson(wrapper)).toMatchSnapshot() }) it('should render ActionDone component', () => { - const userChallenge = { - ...userChallengeData[1], - action: { - ...userChallengeData[1].action, - state: UserActionState.NOTIFICATION, - }, - } - const store = mockStore({ - ecolyo: { - challenge: { currentChallenge: userChallenge }, - global: { ...globalStateData, fluidTypes: [0, 1, 2] }, - profile: profileData, + const store = createMockEcolyoStore({ + challenge: { + currentChallenge: { + ...userChallengeData[1], + action: { + ...userChallengeData[1].action, + state: UserActionState.NOTIFICATION, + }, + }, }, }) const wrapper = mount( @@ -81,18 +61,15 @@ describe('ActionView component', () => { expect(wrapper.find(ActionDone).exists()).toBeTruthy() }) it('should render ActionOnGoing component', () => { - const userChallenge = { - ...userChallengeData[1], - action: { - ...userChallengeData[1].action, - state: UserActionState.ONGOING, - }, - } - const store = mockStore({ - ecolyo: { - challenge: { currentChallenge: userChallenge }, - global: { ...globalStateData, fluidTypes: [0, 1, 2] }, - profile: profileData, + const store = createMockEcolyoStore({ + challenge: { + currentChallenge: { + ...userChallengeData[1], + action: { + ...userChallengeData[1].action, + state: UserActionState.ONGOING, + }, + }, }, }) const wrapper = mount( diff --git a/src/components/Action/ActionView.tsx b/src/components/Action/ActionView.tsx index 03ecb1cb19bb7539d422dcb87bc06a55015e0884..705a66031d0b2d791d1041f7bc8f874c019f5ace 100644 --- a/src/components/Action/ActionView.tsx +++ b/src/components/Action/ActionView.tsx @@ -1,23 +1,17 @@ -import ActionChoose from 'components/Action/ActionChoose' -import ActionDone from 'components/Action/ActionDone' -import ActionOnGoing from 'components/Action/ActionOnGoing' import Content from 'components/Content/Content' import CozyBar from 'components/Header/CozyBar' import Header from 'components/Header/Header' -import { UserActionState } from 'enum/userAction.enum' +import { UserActionState } from 'enums' import { UserChallenge } from 'models' -import React, { useCallback, useState } from 'react' -import { useSelector } from 'react-redux' -import { AppStore } from 'store' +import React, { useState } from 'react' +import { useAppSelector } from 'store/hooks' +import ActionChoose from './ActionChoose/ActionChoose' +import ActionDone from './ActionDone/ActionDone' +import ActionOnGoing from './ActionOnGoing/ActionOnGoing' const ActionView = () => { + const { currentChallenge } = useAppSelector(state => state.ecolyo.challenge) const [headerHeight, setHeaderHeight] = useState<number>(0) - const { currentChallenge } = useSelector( - (state: AppStore) => state.ecolyo.challenge - ) - const defineHeaderHeight = useCallback((height: number) => { - setHeaderHeight(height) - }, []) const renderAction = (challenge: UserChallenge) => { switch (challenge.action.state) { @@ -34,13 +28,13 @@ const ActionView = () => { return ( <> - <CozyBar titleKey={'common.title_action'} displayBackArrow={true} /> + <CozyBar titleKey="common.title_action" displayBackArrow={true} /> <Header - setHeaderHeight={defineHeaderHeight} - desktopTitleKey={'common.title_action'} + setHeaderHeight={setHeaderHeight} + desktopTitleKey="common.title_action" displayBackArrow={true} /> - <Content height={headerHeight}> + <Content heightOffset={headerHeight}> {currentChallenge && renderAction(currentChallenge)} </Content> </> diff --git a/src/components/Action/__snapshots__/ActionView.spec.tsx.snap b/src/components/Action/__snapshots__/ActionView.spec.tsx.snap index ec1ba3e6c35f9cfd16362702059d7640b08b3c70..1136e5081d41803e638e3814c6f018eb3c839794 100644 --- a/src/components/Action/__snapshots__/ActionView.spec.tsx.snap +++ b/src/components/Action/__snapshots__/ActionView.spec.tsx.snap @@ -24,7 +24,7 @@ exports[`ActionView component should render ActionChoose component 1`] = ` setHeaderHeight={[Function]} /> <mock-content - height={0} + heightOffset={0} > <ActionChoose userChallenge={ diff --git a/src/components/Analysis/AnalysisError.spec.tsx b/src/components/Analysis/AnalysisError.spec.tsx deleted file mode 100644 index 1c8fbc8f087afe197f7844743f6b5de44176edbf..0000000000000000000000000000000000000000 --- a/src/components/Analysis/AnalysisError.spec.tsx +++ /dev/null @@ -1,71 +0,0 @@ -import Button from '@material-ui/core/Button' -import Dialog from '@material-ui/core/Dialog' -import AnalysisErrorModal from 'components/Analysis/AnalysisErrorModal' -import { mount } from 'enzyme' -import React from 'react' -import { Provider } from 'react-redux' -import configureStore from 'redux-mock-store' -import { globalStateData } from '../../../tests/__mocks__/globalStateData.mock' -import { profileData } from '../../../tests/__mocks__/profileData.mock' - -jest.mock('cozy-ui/transpiled/react/I18n', () => { - return { - useI18n: jest.fn(() => { - return { - t: (str: string) => str, - } - }), - } -}) -const mockedNavigate = jest.fn() -jest.mock('react-router-dom', () => ({ - ...jest.requireActual('react-router-dom'), - useNavigate: () => mockedNavigate, -})) -const mockStore = configureStore([]) - -describe('AnalysisErrorModal component', () => { - it('should be rendered correctly', () => { - const store = mockStore({ - ecolyo: { - profile: profileData, - global: globalStateData, - }, - }) - const wrapper = mount( - <Provider store={store}> - <AnalysisErrorModal /> - </Provider> - ) - expect(wrapper.find(Dialog).exists()).toBeTruthy() - expect(wrapper.find(Button).exists()).toBeTruthy() - }) - it('should redirect to previous page', () => { - const store = mockStore({ - ecolyo: { - profile: profileData, - global: globalStateData, - }, - }) - const wrapper = mount( - <Provider store={store}> - <AnalysisErrorModal /> - </Provider> - ) - wrapper.find('.btn-secondary-positive').first().simulate('click') - }) - it('should redirect to options', () => { - const store = mockStore({ - ecolyo: { - profile: profileData, - global: globalStateData, - }, - }) - const wrapper = mount( - <Provider store={store}> - <AnalysisErrorModal /> - </Provider> - ) - wrapper.find('.btn-highlight').first().simulate('click') - }) -}) diff --git a/src/components/Analysis/AnalysisErrorModal.tsx b/src/components/Analysis/AnalysisErrorModal.tsx deleted file mode 100644 index 0372cd591be4ab90f8e7b5e5461e701e22408190..0000000000000000000000000000000000000000 --- a/src/components/Analysis/AnalysisErrorModal.tsx +++ /dev/null @@ -1,75 +0,0 @@ -import Button from '@material-ui/core/Button' -import Dialog from '@material-ui/core/Dialog' -import { useI18n } from 'cozy-ui/transpiled/react/I18n' -import React from 'react' -import { useNavigate } from 'react-router-dom' -import './analysisError.scss' - -const AnalysisErrorModal = () => { - const { t } = useI18n() - const navigate = useNavigate() - const goToConsumption = () => { - navigate('/consumption') - } - const goBack = () => { - if (history.length <= 2) { - navigate('/consumption') - } else navigate(-1) - } - return ( - <Dialog - open={true} - onClose={(event, reason): void => { - event && reason !== 'backdropClick' && goBack() - }} - disableEscapeKeyDown - aria-labelledby={'accessibility-title'} - classes={{ - root: 'modal-root', - paper: 'modal-paper', - }} - > - <div id={'accessibility-title'}> - {t('analysis_error_modal.accessibility.window_title')} - </div> - <div className="em-root analysis-error-container"> - <div className="em-content"> - <div className="analysis-error-title text-20-bold"> - {t('analysis_error_modal.title')} - </div> - <div className="analysis-error-message text-16-normal"> - {t('analysis_error_modal.message')} - </div> - <div className="analysis-error-button"> - <Button - aria-label={t( - 'analysis_error_modal.accessibility.button_go_back' - )} - onClick={goBack} - classes={{ - root: 'btn-secondary-positive', - label: 'text-16-normal', - }} - > - {t('analysis_error_modal.go_back')} - </Button> - <Button - aria-label={t( - 'analysis_error_modal.accessibility.button_goto_konnector' - )} - onClick={goToConsumption} - classes={{ - root: 'btn-highlight', - label: 'text-16-bold', - }} - > - {t('analysis_error_modal.go_to_options')} - </Button> - </div> - </div> - </div> - </Dialog> - ) -} - -export default AnalysisErrorModal diff --git a/src/components/Analysis/AnalysisView.spec.tsx b/src/components/Analysis/AnalysisView.spec.tsx index 26f19004286e1d84ef8bf7c62570f21d7ff3577c..6c2515b5bddbd28e139821fb3c3f6486befa8453 100644 --- a/src/components/Analysis/AnalysisView.spec.tsx +++ b/src/components/Analysis/AnalysisView.spec.tsx @@ -1,27 +1,17 @@ import AnalysisView from 'components/Analysis/AnalysisView' import { mount } from 'enzyme' import React from 'react' -import * as reactRedux from 'react-redux' import { Provider } from 'react-redux' -import * as globalActions from 'store/global/global.actions' -import * as profileActions from 'store/profile/profile.actions' -import { globalStateData } from '../../../tests/__mocks__/globalStateData.mock' -import { profileData } from '../../../tests/__mocks__/profileData.mock' +import * as globalActions from 'store/global/global.slice' +import * as storeHooks from 'store/hooks' +import * as profileActions from 'store/profile/profile.slice' import { createMockEcolyoStore, mockAnalysisState, - mockInitialChartState, -} from '../../../tests/__mocks__/store' + mockChartState, + mockProfileState, +} from 'tests/__mocks__/store' -jest.mock('cozy-ui/transpiled/react/I18n', () => { - return { - useI18n: jest.fn(() => { - return { - t: (str: string) => str, - } - }), - } -}) jest.mock('components/Header/CozyBar', () => 'mock-cozybar') jest.mock('components/Header/Header', () => 'mock-header') jest.mock('components/Content/Content', () => 'mock-content') @@ -35,8 +25,7 @@ jest.mock('react-router-dom', () => ({ }), })) -const useSelectorSpy = jest.spyOn(reactRedux, 'useSelector') -const useDispatchSpy = jest.spyOn(reactRedux, 'useDispatch') +const mockAppDispatch = jest.spyOn(storeHooks, 'useAppDispatch') const toggleAnalysisNotificationSpy = jest.spyOn( globalActions, 'toggleAnalysisNotification' @@ -46,21 +35,10 @@ const updateProfileSpy = jest.spyOn(profileActions, 'updateProfile') describe('AnalysisView component', () => { const store = createMockEcolyoStore() beforeEach(() => { - store.clearActions() - useSelectorSpy.mockClear() - useDispatchSpy.mockClear() - toggleAnalysisNotificationSpy.mockClear() - updateProfileSpy.mockClear() + jest.clearAllMocks() }) it('should be rendered correctly', () => { - useSelectorSpy.mockReturnValue({ - global: globalStateData, - profile: profileData, - chart: mockInitialChartState, - analysis: mockAnalysisState, - }) - useDispatchSpy.mockReturnValue(jest.fn()) const wrapper = mount( <Provider store={store}> <AnalysisView /> @@ -73,19 +51,13 @@ describe('AnalysisView component', () => { }) it('should update profile and toggle analysis notification to false if notification is true', () => { - useSelectorSpy.mockReturnValue({ - global: { - ...globalStateData, - analysisNotification: true, - }, - profile: { - ...profileData, - haveSeenLastAnalysis: false, - }, - chart: mockInitialChartState, + const store = createMockEcolyoStore({ analysis: mockAnalysisState, + chart: mockChartState, + global: { analysisNotification: true }, + profile: { ...mockProfileState, haveSeenLastAnalysis: true }, }) - useDispatchSpy.mockReturnValue(jest.fn()) + mockAppDispatch.mockReturnValue(jest.fn()) const wrapper = mount( <Provider store={store}> <AnalysisView /> @@ -95,11 +67,11 @@ describe('AnalysisView component', () => { expect(wrapper.find('mock-header').exists()).toBeTruthy() expect(wrapper.find('mock-datenavigator').exists()).toBeTruthy() expect(wrapper.find('mock-monthlyanalysis').exists()).toBeTruthy() - expect(updateProfileSpy).toBeCalledTimes(1) + expect(updateProfileSpy).toHaveBeenCalledTimes(1) expect(updateProfileSpy).toHaveBeenCalledWith({ haveSeenLastAnalysis: true, }) - expect(toggleAnalysisNotificationSpy).toBeCalledTimes(1) + expect(toggleAnalysisNotificationSpy).toHaveBeenCalledTimes(1) expect(toggleAnalysisNotificationSpy).toHaveBeenCalledWith(false) }) }) diff --git a/src/components/Analysis/AnalysisView.tsx b/src/components/Analysis/AnalysisView.tsx index b807f35b6b9204cbb533969191bad2940094c66c..424dcb2f2ee56666b019cecdd4d36673ff59e146 100644 --- a/src/components/Analysis/AnalysisView.tsx +++ b/src/components/Analysis/AnalysisView.tsx @@ -4,30 +4,31 @@ import DateNavigator from 'components/DateNavigator/DateNavigator' import CozyBar from 'components/Header/CozyBar' import Header from 'components/Header/Header' import { useClient } from 'cozy-client' -import { UsageEventType } from 'enum/usageEvent.enum' +import { TimeStep, UsageEventType } from 'enums' import { DateTime } from 'luxon' -import React, { Dispatch, useCallback, useEffect, useState } from 'react' -import { useDispatch, useSelector } from 'react-redux' +import React, { useCallback, useEffect, useState } from 'react' import { useLocation } from 'react-router-dom' +import DateChartService from 'services/dateChart.service' import UsageEventService from 'services/usageEvent.service' -import { AppActionsTypes, AppStore } from 'store' -import { toggleAnalysisNotification } from 'store/global/global.actions' -import { updateProfile } from 'store/profile/profile.actions' +import { setAnalysisMonth } from 'store/analysis/analysis.slice' +import { toggleAnalysisNotification } from 'store/global/global.slice' +import { useAppDispatch, useAppSelector } from 'store/hooks' +import { updateProfile } from 'store/profile/profile.slice' +import { isLastDateReached } from 'utils/date' import './analysisView.scss' const AnalysisView = () => { const client = useClient() - const [headerHeight, setHeaderHeight] = useState<number>(0) const { analysis: { analysisMonth }, chart: { selectedDate }, global: { analysisNotification }, profile: { monthlyAnalysisDate, mailToken }, - } = useSelector((state: AppStore) => state.ecolyo) - const dispatch = useDispatch<Dispatch<AppActionsTypes>>() - const defineHeaderHeight = useCallback((height: number) => { - setHeaderHeight(height) - }, []) + } = useAppSelector(state => state.ecolyo) + const dispatch = useAppDispatch() + const [headerHeight, setHeaderHeight] = useState<number>(0) + + const dateChartService = new DateChartService() // Handle email report comeback const { search } = useLocation() @@ -48,11 +49,7 @@ const AnalysisView = () => { useEffect(() => { const updateAnalysisNotification = () => { if (analysisNotification) { - dispatch( - updateProfile({ - haveSeenLastAnalysis: true, - }) - ) + dispatch(updateProfile({ haveSeenLastAnalysis: true })) dispatch(toggleAnalysisNotification(false)) } @@ -97,19 +94,39 @@ const AnalysisView = () => { client, ]) + const disablePrev = + analysisMonth < + DateTime.local(0, 1, 1).setZone('utc', { + keepLocalTime: true, + }) + + const handleMoveDate = (increment: number) => { + const updatedDate = dateChartService.incrementDate( + TimeStep.MONTH, + analysisMonth, + increment + ) + dispatch(setAnalysisMonth(updatedDate)) + } + return ( <> - <CozyBar titleKey={'common.title_analysis'} /> + <CozyBar titleKey="common.title_analysis" /> <Header - setHeaderHeight={defineHeaderHeight} - desktopTitleKey={'common.title_analysis'} + setHeaderHeight={setHeaderHeight} + desktopTitleKey="common.title_analysis" > <DateNavigator - currentAnalysisDate={analysisMonth} + disableNext={isLastDateReached(analysisMonth, TimeStep.MONTH)} + disablePrev={disablePrev} + handleNextDate={() => handleMoveDate(1)} + handlePrevDate={() => handleMoveDate(-1)} inlineDateDisplay={true} + navigatorDate={analysisMonth.minus({ month: 1 })} + timeStep={TimeStep.MONTH} /> </Header> - <Content height={headerHeight}> + <Content heightOffset={headerHeight}> <MonthlyAnalysis saveLastScrollPosition={saveLastScrollPosition} scrollPosition={scrollPosition} diff --git a/src/components/Analysis/Comparison/Comparison.tsx b/src/components/Analysis/Comparison/Comparison.tsx new file mode 100644 index 0000000000000000000000000000000000000000..f488816e361e183b81eee65bf2b1fc6c512ff24e --- /dev/null +++ b/src/components/Analysis/Comparison/Comparison.tsx @@ -0,0 +1,155 @@ +import { Button } from '@material-ui/core' +import Loader from 'components/Loader/Loader' +import { useClient } from 'cozy-client' +import { useI18n } from 'cozy-ui/transpiled/react/I18n' +import { FluidType, TimeStep } from 'enums' +import { PerformanceIndicator } from 'models' +import React, { useEffect, useMemo, useState } from 'react' +import ConsumptionService from 'services/consumption.service' +import { setPeriod } from 'store/analysis/analysis.slice' +import { useAppDispatch, useAppSelector } from 'store/hooks' +import FluidPerformanceIndicator from './FluidPerformanceIndicator' +import './comparison.scss' + +const Comparison = ({ + fluidsWithData, + monthPerformanceIndicators, +}: { + fluidsWithData: FluidType[] + monthPerformanceIndicators: PerformanceIndicator[] +}) => { + const { t } = useI18n() + const client = useClient() + const { + global: { fluidTypes }, + analysis: { period, analysisMonth }, + } = useAppSelector(state => state.ecolyo) + const dispatch = useAppDispatch() + const [yearPerformanceIndicators, setYearPerformanceIndicators] = useState< + PerformanceIndicator[] + >([]) + const [isLoading, setIsLoading] = useState<boolean>(true) + const consumptionService = useMemo( + () => new ConsumptionService(client), + [client] + ) + const periods = useMemo(() => { + return { + monthPeriod: { + startDate: analysisMonth.minus({ month: 1 }).startOf('month'), + endDate: analysisMonth.minus({ month: 1 }).endOf('month'), + }, + previousMonthPeriod: { + startDate: analysisMonth.minus({ month: 2 }).startOf('month'), + endDate: analysisMonth.minus({ month: 2 }).endOf('month'), + }, + previousYearPeriod: { + startDate: analysisMonth.minus({ year: 1, month: 1 }).startOf('month'), + endDate: analysisMonth.minus({ year: 1, month: 1 }).endOf('month'), + }, + } + }, [analysisMonth]) + + const loaderPlaceholderHeight = + fluidsWithData.length * 84 + (fluidsWithData.length - 1) * 10 + + useEffect(() => { + let subscribed = true + async function populateData() { + if (subscribed) { + const fetchedYearIndicators = + await consumptionService.getPerformanceIndicators( + periods.monthPeriod, + TimeStep.MONTH, + fluidsWithData, + periods.previousYearPeriod + ) + if (fetchedYearIndicators) { + setYearPerformanceIndicators(fetchedYearIndicators) + } + setIsLoading(false) + } + } + populateData() + + return () => { + subscribed = false + } + }, [ + client, + fluidTypes, + analysisMonth, + consumptionService, + fluidsWithData, + periods.monthPeriod, + periods.previousYearPeriod, + ]) + + return ( + <div className="comparison"> + <div className="tabs"> + <Button + className={period === 'month' ? 'active' : ''} + onClick={() => dispatch(setPeriod('month'))} + > + {t('analysis.compare.month_tab')} + </Button> + <Button + className={period === 'year' ? 'active' : ''} + onClick={() => dispatch(setPeriod('year'))} + > + {t('analysis.compare.year_tab')} + </Button> + </div> + <div className="performanceIndicators"> + {isLoading && ( + <div + style={{ + height: `${loaderPlaceholderHeight}px`, + display: 'flex', + justifyContent: 'center', + }} + > + <Loader /> + </div> + )} + + {/* Placeholder when no data is found */} + {!isLoading && + fluidsWithData.length === 0 && + [FluidType.ELECTRICITY, FluidType.WATER, FluidType.GAS].map(fluid => ( + <FluidPerformanceIndicator + key={fluid} + fluidType={fluid} + performanceIndicator={{ + value: 0, + compareValue: 0, + percentageVariation: 0, + }} + comparisonDate={periods.previousMonthPeriod.startDate} + /> + ))} + + {!isLoading && + fluidsWithData.map(fluid => ( + <FluidPerformanceIndicator + key={fluid} + fluidType={fluid} + performanceIndicator={ + period === 'month' + ? monthPerformanceIndicators[fluid] + : yearPerformanceIndicators[fluid] + } + comparisonDate={ + period === 'month' + ? periods.previousMonthPeriod.startDate + : periods.previousYearPeriod.startDate + } + /> + ))} + </div> + </div> + ) +} + +export default Comparison diff --git a/src/components/PerformanceIndicator/FluidPerformanceIndicator.tsx b/src/components/Analysis/Comparison/FluidPerformanceIndicator.tsx similarity index 94% rename from src/components/PerformanceIndicator/FluidPerformanceIndicator.tsx rename to src/components/Analysis/Comparison/FluidPerformanceIndicator.tsx index d5af35ce3f974fba88a3ab4f929fa1a0c3e5ce88..84ede422be562056cbcffbd4f54222ce1ebed52d 100644 --- a/src/components/PerformanceIndicator/FluidPerformanceIndicator.tsx +++ b/src/components/Analysis/Comparison/FluidPerformanceIndicator.tsx @@ -1,6 +1,6 @@ import StyledIcon from 'components/CommonKit/Icon/StyledIcon' import { useI18n } from 'cozy-ui/transpiled/react/I18n' -import { FluidType } from 'enum/fluid.enum' +import { FluidType } from 'enums' import { DateTime } from 'luxon' import { PerformanceIndicator } from 'models' import React from 'react' @@ -49,7 +49,7 @@ const FluidPerformanceIndicator = ({ <div className="fpi-value"> <span className="fpi-load">{displayedValue}</span> <span className="fpi-unit"> - {t('FLUID.' + FluidType[fluidType] + '.UNIT')} + {t(`FLUID.${FluidType[fluidType]}.UNIT`)} </span> </div> {performanceIndicator?.percentageVariation === null && ( @@ -58,7 +58,7 @@ const FluidPerformanceIndicator = ({ </span> )} {performanceIndicator?.percentageVariation !== null && ( - <div className={`fpi-comparison`}> + <div className="fpi-comparison"> <span className={`percent ${positive ? 'positive' : 'negative'}`} > diff --git a/src/components/Analysis/comparisonView.scss b/src/components/Analysis/Comparison/comparison.scss similarity index 97% rename from src/components/Analysis/comparisonView.scss rename to src/components/Analysis/Comparison/comparison.scss index 12271b7131b329d67853f6b65dc8b1d64dd468c0..ad321b9c06d3afe6598b6c5d800ad3136736caa9 100644 --- a/src/components/Analysis/comparisonView.scss +++ b/src/components/Analysis/Comparison/comparison.scss @@ -1,4 +1,4 @@ -.comparisonView { +.comparison { display: flex; flex-direction: column; .tabs { diff --git a/src/components/PerformanceIndicator/fluidPerformanceIndicator.scss b/src/components/Analysis/Comparison/fluidPerformanceIndicator.scss similarity index 91% rename from src/components/PerformanceIndicator/fluidPerformanceIndicator.scss rename to src/components/Analysis/Comparison/fluidPerformanceIndicator.scss index ec138c814f56d564d163093c16f00fa46265f0e7..6213c8fdc63a80db0122e252487db98e19b5f4fb 100644 --- a/src/components/PerformanceIndicator/fluidPerformanceIndicator.scss +++ b/src/components/Analysis/Comparison/fluidPerformanceIndicator.scss @@ -1,5 +1,5 @@ -@import '../../styles/base/color'; -@import '../../styles/base/breakpoint'; +@import 'src/styles/base/color'; +@import 'src/styles/base/breakpoint'; //FluidIndicator .fi-root { @@ -36,6 +36,7 @@ padding: 16px 22px; gap: 1rem; align-items: center; + box-shadow: 0px 4px 16px 0px $black-shadow; .fpi-content { .fpi-value { diff --git a/src/components/Analysis/ComparisonView.tsx b/src/components/Analysis/ComparisonView.tsx deleted file mode 100644 index db8032078ca2ccbd234308d955a34579e812cc4f..0000000000000000000000000000000000000000 --- a/src/components/Analysis/ComparisonView.tsx +++ /dev/null @@ -1,151 +0,0 @@ -import { Button } from '@material-ui/core' -import Loader from 'components/Loader/Loader' -import FluidPerformanceIndicator from 'components/PerformanceIndicator/FluidPerformanceIndicator' -import { useClient } from 'cozy-client' -import { useI18n } from 'cozy-ui/transpiled/react/I18n' -import { TimeStep } from 'enum/timeStep.enum' -import { FluidConfig, PerformanceIndicator } from 'models' -import React, { Dispatch, useEffect, useMemo, useState } from 'react' -import { useDispatch, useSelector } from 'react-redux' -import ConsumptionService from 'services/consumption.service' -import { AppActionsTypes, AppStore } from 'store' -import { setPeriod } from 'store/analysis/analysis.slice' -import './comparisonView.scss' - -const ComparisonView = ({ fluidConfig }: { fluidConfig: FluidConfig[] }) => { - const { t } = useI18n() - const client = useClient() - const { - global: { fluidTypes }, - analysis: { period, analysisMonth }, - } = useSelector((state: AppStore) => state.ecolyo) - const dispatch = useDispatch<Dispatch<AppActionsTypes>>() - const [monthPerformanceIndicators, setMonthPerformanceIndicators] = useState< - PerformanceIndicator[] - >([]) - const [yearPerformanceIndicators, setYearPerformanceIndicators] = useState< - PerformanceIndicator[] - >([]) - const [isLoading, setIsLoading] = useState<boolean>(true) - const consumptionService = useMemo( - () => new ConsumptionService(client), - [client] - ) - const monthPeriod = useMemo(() => { - return { - startDate: analysisMonth.minus({ month: 1 }).startOf('month'), - endDate: analysisMonth.minus({ month: 1 }).endOf('month'), - } - }, [analysisMonth]) - const previousMonthPeriod = useMemo(() => { - return { - startDate: analysisMonth.minus({ month: 2 }).startOf('month'), - endDate: analysisMonth.minus({ month: 2 }).endOf('month'), - } - }, [analysisMonth]) - const previousYearPeriod = useMemo(() => { - return { - startDate: analysisMonth.minus({ year: 1, month: 1 }).startOf('month'), - endDate: analysisMonth.minus({ year: 1, month: 1 }).endOf('month'), - } - }, [analysisMonth]) - - const loaderPlaceholderHeight = - fluidTypes.length * 84 + (fluidTypes.length - 1) * 10 - - useEffect(() => { - let subscribed = true - async function populateData() { - if (subscribed) { - const fetchedMonthIndicators = - await consumptionService.getPerformanceIndicators( - monthPeriod, - TimeStep.MONTH, - fluidTypes, - previousMonthPeriod - ) - const fetchedYearIndicators = - await consumptionService.getPerformanceIndicators( - monthPeriod, - TimeStep.MONTH, - fluidTypes, - previousYearPeriod - ) - if (fetchedMonthIndicators) { - setMonthPerformanceIndicators(fetchedMonthIndicators) - } - if (fetchedYearIndicators) { - setYearPerformanceIndicators(fetchedYearIndicators) - } - setIsLoading(false) - } - } - populateData() - - return () => { - subscribed = false - } - }, [ - client, - fluidTypes, - analysisMonth, - consumptionService, - monthPeriod, - previousMonthPeriod, - previousYearPeriod, - ]) - - return ( - <div className="comparisonView"> - <div className="tabs"> - <Button - className={period === 'month' ? 'active' : ''} - onClick={() => dispatch(setPeriod('month'))} - > - {t('analysis.compare.month_tab')} - </Button> - <Button - className={period === 'year' ? 'active' : ''} - onClick={() => dispatch(setPeriod('year'))} - > - {t('analysis.compare.year_tab')} - </Button> - </div> - <div className="performanceIndicators"> - {isLoading && ( - <div - style={{ - height: `${loaderPlaceholderHeight}px`, - display: 'flex', - justifyContent: 'center', - }} - > - <Loader /> - </div> - )} - {!isLoading && - fluidConfig.map( - fluid => - fluidTypes.includes(fluid.fluidTypeId) && ( - <FluidPerformanceIndicator - key={fluid.konnectorConfig.slug} - fluidType={fluid.fluidTypeId} - performanceIndicator={ - period === 'month' - ? monthPerformanceIndicators[fluid.fluidTypeId] - : yearPerformanceIndicators[fluid.fluidTypeId] - } - comparisonDate={ - period === 'month' - ? previousMonthPeriod.startDate - : previousYearPeriod.startDate - } - /> - ) - )} - </div> - </div> - ) -} - -export default ComparisonView diff --git a/src/components/Analysis/ElecHalfHourChart.spec.tsx b/src/components/Analysis/ElecHalfHourChart.spec.tsx deleted file mode 100644 index b9e16b2aad2297cddd3812ace4998e06aff0ecdb..0000000000000000000000000000000000000000 --- a/src/components/Analysis/ElecHalfHourChart.spec.tsx +++ /dev/null @@ -1,69 +0,0 @@ -import { mount } from 'enzyme' -import toJson from 'enzyme-to-json' -import { DateTime } from 'luxon' -import React from 'react' -import * as reactRedux from 'react-redux' -import { Provider } from 'react-redux' -import configureStore from 'redux-mock-store' -import { dataLoadArray } from '../../../tests/__mocks__/chartData.mock' -import { globalStateData } from '../../../tests/__mocks__/globalStateData.mock' -import ElecHalfHourChart from './ElecHalfHourChart' - -jest.mock('cozy-ui/transpiled/react/I18n', () => { - return { - useI18n: jest.fn(() => { - return { - t: (str: string) => str, - } - }), - } -}) -const mockcompareStepDate = jest.fn() -jest.mock('services/dateChart.service', () => { - return jest.fn(() => { - return { - compareStepDate: mockcompareStepDate, - } - }) -}) -const mockStore = configureStore([]) -const mockUseSelector = jest.spyOn(reactRedux, 'useSelector') - -describe('ElecHalfHourChart component', () => { - it('should be rendered correctly', () => { - const store = mockStore({ - ecolyo: { - global: globalStateData, - }, - }) - mockUseSelector.mockReturnValue( - DateTime.fromISO('2021-07-01T00:00:00.000Z', { - zone: 'utc', - }) - ) - const wrapper = mount( - <Provider store={store}> - <ElecHalfHourChart dataLoad={dataLoadArray} isWeekend={true} /> - </Provider> - ) - expect(toJson(wrapper)).toMatchSnapshot() - }) - it('should render week data', () => { - const store = mockStore({ - ecolyo: { - global: globalStateData, - }, - }) - mockUseSelector.mockReturnValue( - DateTime.fromISO('2021-07-01T00:00:00.000Z', { - zone: 'utc', - }) - ) - const wrapper = mount( - <Provider store={store}> - <ElecHalfHourChart dataLoad={dataLoadArray} isWeekend={false} /> - </Provider> - ) - expect(wrapper.find('.week')).toBeTruthy() - }) -}) diff --git a/src/components/Analysis/ElecHalfHourMonthlyAnalysis/ElecHalfHourChart.spec.tsx b/src/components/Analysis/ElecHalfHourMonthlyAnalysis/ElecHalfHourChart.spec.tsx new file mode 100644 index 0000000000000000000000000000000000000000..58ecd0b3ad642f3c2f5a56a1b92fb606a45aeb30 --- /dev/null +++ b/src/components/Analysis/ElecHalfHourMonthlyAnalysis/ElecHalfHourChart.spec.tsx @@ -0,0 +1,41 @@ +import { mount } from 'enzyme' +import toJson from 'enzyme-to-json' +import { DateTime } from 'luxon' +import React from 'react' +import { Provider } from 'react-redux' +import { dataLoadArray } from 'tests/__mocks__/chartData.mock' +import { createMockEcolyoStore, mockGlobalState } from 'tests/__mocks__/store' +import ElecHalfHourChart from './ElecHalfHourChart' + +jest.mock('services/dateChart.service', () => { + return jest.fn(() => ({ + compareStepDate: jest.fn(), + })) +}) + +describe('ElecHalfHourChart component', () => { + const store = createMockEcolyoStore({ + chart: { + selectedDate: DateTime.fromISO('2021-07-01T00:00:00.000Z', { + zone: 'utc', + }), + }, + global: mockGlobalState, + }) + it('should be rendered correctly', () => { + const wrapper = mount( + <Provider store={store}> + <ElecHalfHourChart dataLoad={dataLoadArray} isWeekend={true} /> + </Provider> + ) + expect(toJson(wrapper)).toMatchSnapshot() + }) + it('should render week data', () => { + const wrapper = mount( + <Provider store={store}> + <ElecHalfHourChart dataLoad={dataLoadArray} isWeekend={false} /> + </Provider> + ) + expect(wrapper.find('.week')).toBeTruthy() + }) +}) diff --git a/src/components/Analysis/ElecHalfHourChart.tsx b/src/components/Analysis/ElecHalfHourMonthlyAnalysis/ElecHalfHourChart.tsx similarity index 96% rename from src/components/Analysis/ElecHalfHourChart.tsx rename to src/components/Analysis/ElecHalfHourMonthlyAnalysis/ElecHalfHourChart.tsx index b63408d3b05ae42ff1fd32550ae16c7b529407c1..1911da91c9b913697383a83c73f6b13aab9b21cb 100644 --- a/src/components/Analysis/ElecHalfHourChart.tsx +++ b/src/components/Analysis/ElecHalfHourMonthlyAnalysis/ElecHalfHourChart.tsx @@ -3,8 +3,7 @@ import AxisRight from 'components/Charts/AxisRight' import Bar from 'components/Charts/Bar' import { useChartResize } from 'components/Hooks/useChartResize' import { scaleBand, ScaleBand, scaleLinear, ScaleLinear } from 'd3-scale' -import { FluidType } from 'enum/fluid.enum' -import { TimeStep } from 'enum/timeStep.enum' +import { FluidType, TimeStep } from 'enums' import { DateTime } from 'luxon' import { Dataload } from 'models' import React, { useRef } from 'react' diff --git a/src/components/Analysis/ElecHalfHourMonthlyAnalysis.spec.tsx b/src/components/Analysis/ElecHalfHourMonthlyAnalysis/ElecHalfHourMonthlyAnalysis.spec.tsx similarity index 74% rename from src/components/Analysis/ElecHalfHourMonthlyAnalysis.spec.tsx rename to src/components/Analysis/ElecHalfHourMonthlyAnalysis/ElecHalfHourMonthlyAnalysis.spec.tsx index 2cff5c734e2090bc063c9e31bb3c4ec05352e982..88c4aa8ec70d728fbe32848d9bc463299b0af6e5 100644 --- a/src/components/Analysis/ElecHalfHourMonthlyAnalysis.spec.tsx +++ b/src/components/Analysis/ElecHalfHourMonthlyAnalysis/ElecHalfHourMonthlyAnalysis.spec.tsx @@ -4,52 +4,41 @@ import toJson from 'enzyme-to-json' import { PerformanceIndicator } from 'models' import React from 'react' import { Provider } from 'react-redux' -import configureStore from 'redux-mock-store' import { mockDataLoadEnedisAnalysis, mockEnedisMonthlyAnalysisArray, -} from '../../../tests/__mocks__/enedisMonthlyAnalysisData.mock' -import { allLastFluidPrices } from '../../../tests/__mocks__/fluidPrice.mock' -import { mockAnalysisState } from '../../../tests/__mocks__/store' -import { waitForComponentToPaint } from '../../../tests/__mocks__/testUtils' +} from 'tests/__mocks__/enedisMonthlyAnalysisData.mock' +import { allLastFluidPrices } from 'tests/__mocks__/fluidPrice.mock' +import { createMockEcolyoStore } from 'tests/__mocks__/store' +import { waitForComponentToPaint } from 'tests/__mocks__/testUtils' import ElecHalfHourMonthlyAnalysis from './ElecHalfHourMonthlyAnalysis' -jest.mock('cozy-ui/transpiled/react/I18n', () => { - return { - useI18n: jest.fn(() => { - return { - t: (str: string) => str, - } - }), - } -}) jest.mock('components/Hooks/useExploration', () => { return () => ['', jest.fn()] }) jest.mock( - 'components/Analysis/ElecHalfHourChart', + 'components/Analysis/ElecHalfHourMonthlyAnalysis/ElecHalfHourChart', () => 'mock-elechalfhourchart' ) -jest.mock('components/Analysis/ElecInfoModal', () => 'mock-elecinfomodal') +jest.mock( + 'components/Analysis/ElecHalfHourMonthlyAnalysis/ElecInfoModal', + () => 'mock-elecinfomodal' +) const mockCheckDoctypeEntries = jest.fn() jest.mock('services/consumption.service', () => { - return jest.fn(() => { - return { - checkDoctypeEntries: mockCheckDoctypeEntries, - } - }) + return jest.fn(() => ({ + checkDoctypeEntries: mockCheckDoctypeEntries, + })) }) const mockGetEnedisMonthlyAnalysisByDate = jest.fn() const mockAggregateValuesToDataLoad = jest.fn() jest.mock('services/enedisMonthlyAnalysisData.service', () => { - return jest.fn(() => { - return { - getEnedisMonthlyAnalysisByDate: mockGetEnedisMonthlyAnalysisByDate, - aggregateValuesToDataLoad: mockAggregateValuesToDataLoad, - } - }) + return jest.fn(() => ({ + getEnedisMonthlyAnalysisByDate: mockGetEnedisMonthlyAnalysisByDate, + aggregateValuesToDataLoad: mockAggregateValuesToDataLoad, + })) }) const mockPerfIndicator: PerformanceIndicator = { value: 10, @@ -59,25 +48,15 @@ const mockPerfIndicator: PerformanceIndicator = { } const mockGetPrices = jest.fn() jest.mock('services/fluidsPrices.service', () => { - return jest.fn(() => { - return { - getPrices: mockGetPrices, - } - }) -}) - -const mockStore = configureStore([]) -const store = mockStore({ - ecolyo: { - analysis: mockAnalysisState, - }, + return jest.fn(() => ({ + getPrices: mockGetPrices, + })) }) describe('ElecHalfHourMonthlyAnalysis component', () => { + const store = createMockEcolyoStore() beforeEach(() => { - mockCheckDoctypeEntries.mockClear() - mockGetEnedisMonthlyAnalysisByDate.mockClear() - mockAggregateValuesToDataLoad.mockClear() + jest.clearAllMocks() }) it('should be rendered correctly when isHalfHourActivated is false', async () => { diff --git a/src/components/Analysis/ElecHalfHourMonthlyAnalysis.tsx b/src/components/Analysis/ElecHalfHourMonthlyAnalysis/ElecHalfHourMonthlyAnalysis.tsx similarity index 94% rename from src/components/Analysis/ElecHalfHourMonthlyAnalysis.tsx rename to src/components/Analysis/ElecHalfHourMonthlyAnalysis/ElecHalfHourMonthlyAnalysis.tsx index b6fc4072005f7f60765a9f3401bcf9f8467762a6..362cfc35ad3ad2907fb2db7dcfe974675f658d17 100644 --- a/src/components/Analysis/ElecHalfHourMonthlyAnalysis.tsx +++ b/src/components/Analysis/ElecHalfHourMonthlyAnalysis/ElecHalfHourMonthlyAnalysis.tsx @@ -3,25 +3,24 @@ import LeftArrowIcon from 'assets/icons/ico/left-arrow.svg' import MaxPowerIcon from 'assets/icons/ico/maxPower.svg' import MinIcon from 'assets/icons/ico/minimum.svg' import RightArrowIcon from 'assets/icons/ico/right-arrow.svg' -import ElecHalfHourChart from 'components/Analysis/ElecHalfHourChart' import Loader from 'components/Loader/Loader' import { useClient } from 'cozy-client' import { useI18n } from 'cozy-ui/transpiled/react/I18n' import Icon from 'cozy-ui/transpiled/react/Icon' -import { FluidType } from 'enum/fluid.enum' -import { TimeStep } from 'enum/timeStep.enum' -import { FluidPrice, PerformanceIndicator } from 'models' +import { FluidType, TimeStep } from 'enums' import { AggregatedEnedisMonthlyDataloads, EnedisMonthlyAnalysisData, -} from 'models/enedisMonthlyAnalysis' + FluidPrice, + PerformanceIndicator, +} from 'models' import React, { useCallback, useEffect, useState } from 'react' -import { useSelector } from 'react-redux' import ConsumptionService from 'services/consumption.service' import EnedisMonthlyAnalysisDataService from 'services/enedisMonthlyAnalysisData.service' import FluidPricesService from 'services/fluidsPrices.service' -import { AppStore } from 'store' +import { useAppSelector } from 'store/hooks' import { getNavPicto } from 'utils/picto' +import ElecHalfHourChart from './ElecHalfHourChart' import ElecInfoModal from './ElecInfoModal' import './elecHalfHourMonthlyAnalysis.scss' @@ -32,9 +31,7 @@ const ElecHalfHourMonthlyAnalysis = ({ }) => { const { t } = useI18n() const client = useClient() - const { analysisMonth } = useSelector( - (state: AppStore) => state.ecolyo.analysis - ) + const { analysisMonth } = useAppSelector(state => state.ecolyo.analysis) const [isWeekend, setIsWeekend] = useState<boolean>(true) const [isHalfHourActivated, setIsHalfHourActivated] = useState<boolean>(true) const [isLoading, setIsLoading] = useState<boolean>(true) @@ -73,7 +70,7 @@ const ElecHalfHourMonthlyAnalysis = ({ /> ) } else { - return <p className={`text-20-bold no_data`}>{t('analysis.no_data')}</p> + return <p className="text-20-bold no_data">{t('analysis.no_data')}</p> } }, [isDataFullyComplete, isWeekend, monthDataloads, t]) diff --git a/src/components/Analysis/ElecInfoModal.spec.tsx b/src/components/Analysis/ElecHalfHourMonthlyAnalysis/ElecInfoModal.spec.tsx similarity index 70% rename from src/components/Analysis/ElecInfoModal.spec.tsx rename to src/components/Analysis/ElecHalfHourMonthlyAnalysis/ElecInfoModal.spec.tsx index a3207082fa69a5d0ee49f4bcf92aa7bf47a84057..9524348096134b9c11095febedd2255ee79e62ab 100644 --- a/src/components/Analysis/ElecInfoModal.spec.tsx +++ b/src/components/Analysis/ElecHalfHourMonthlyAnalysis/ElecInfoModal.spec.tsx @@ -3,16 +3,6 @@ import toJson from 'enzyme-to-json' import React from 'react' import ElecInfoModal from './ElecInfoModal' -jest.mock('cozy-ui/transpiled/react/I18n', () => { - return { - useI18n: jest.fn(() => { - return { - t: (str: string) => str, - } - }), - } -}) - describe('ElecInfoModal component', () => { it('should be rendered correctly', () => { const component = mount( diff --git a/src/components/Analysis/ElecInfoModal.tsx b/src/components/Analysis/ElecHalfHourMonthlyAnalysis/ElecInfoModal.tsx similarity index 94% rename from src/components/Analysis/ElecInfoModal.tsx rename to src/components/Analysis/ElecHalfHourMonthlyAnalysis/ElecInfoModal.tsx index 97275ab60d837a21e36b4e91ca134a1d9fd39549..8f61f8aff2116494afb98998e1b2158a5c9f975d 100644 --- a/src/components/Analysis/ElecInfoModal.tsx +++ b/src/components/Analysis/ElecHalfHourMonthlyAnalysis/ElecInfoModal.tsx @@ -18,13 +18,13 @@ const ElecInfoModal = ({ open, handleCloseClick }: ElecInfoModalProps) => { <Dialog open={open} onClose={handleCloseClick} - aria-labelledby={'accessibility-title'} + aria-labelledby="accessibility-title" classes={{ root: 'modal-root', paper: 'modal-paper', }} > - <div id={'accessibility-title'}> + <div id="accessibility-title"> {t('elec_info_modal.accessibility.window_title')} </div> <IconButton diff --git a/src/components/Analysis/__snapshots__/ElecHalfHourChart.spec.tsx.snap b/src/components/Analysis/ElecHalfHourMonthlyAnalysis/__snapshots__/ElecHalfHourChart.spec.tsx.snap similarity index 90% rename from src/components/Analysis/__snapshots__/ElecHalfHourChart.spec.tsx.snap rename to src/components/Analysis/ElecHalfHourMonthlyAnalysis/__snapshots__/ElecHalfHourChart.spec.tsx.snap index d6dfbc1e3aabc44cddbda56d180971a0e6da58bc..1e7bcab26ddfd1f3f6c32c02827d8e24dfb1e12d 100644 --- a/src/components/Analysis/__snapshots__/ElecHalfHourChart.spec.tsx.snap +++ b/src/components/Analysis/ElecHalfHourMonthlyAnalysis/__snapshots__/ElecHalfHourChart.spec.tsx.snap @@ -109,7 +109,7 @@ exports[`ElecHalfHourChart component should be rendered correctly 1`] = ` > <defs> <linearGradient - className="bar-ELECTRICITY weekend bounce-3 delay--0 " + className="bar-ELECTRICITY weekend bounce-3 delay--0" id="gradient" x1="0" x2="0" @@ -127,9 +127,15 @@ exports[`ElecHalfHourChart component should be rendered correctly 1`] = ` </linearGradient> </defs> <path - className="bar-ELECTRICITY weekend bounce-3 delay--0 " - d="M0,4 a4,4 0 0 1 4,-4h-5a4,4 0 0 1 4,4v136h-3z" - fill="url(#gradient)" + className="bar-ELECTRICITY weekend bounce-3 delay--0" + d=" + M0,4 + a4,4 0 0 1 4,-4 + h-5 + a4,4 0 0 1 4,4 + v136 + h-3 + z" onAnimationEnd={[Function]} onClick={[Function]} /> @@ -178,7 +184,7 @@ exports[`ElecHalfHourChart component should be rendered correctly 1`] = ` > <defs> <linearGradient - className="bar-ELECTRICITY weekend bounce-3 delay--1 " + className="bar-ELECTRICITY weekend bounce-3 delay--1" id="gradient" x1="0" x2="0" @@ -196,9 +202,15 @@ exports[`ElecHalfHourChart component should be rendered correctly 1`] = ` </linearGradient> </defs> <path - className="bar-ELECTRICITY weekend bounce-3 delay--1 " - d="M0,4 a4,4 0 0 1 4,-4h-5a4,4 0 0 1 4,4v136h-3z" - fill="url(#gradient)" + className="bar-ELECTRICITY weekend bounce-3 delay--1" + d=" + M0,4 + a4,4 0 0 1 4,-4 + h-5 + a4,4 0 0 1 4,4 + v136 + h-3 + z" onAnimationEnd={[Function]} onClick={[Function]} /> @@ -247,7 +259,7 @@ exports[`ElecHalfHourChart component should be rendered correctly 1`] = ` > <defs> <linearGradient - className="bar-ELECTRICITY weekend bounce-3 delay--2 " + className="bar-ELECTRICITY weekend bounce-3 delay--2" id="gradient" x1="0" x2="0" @@ -265,9 +277,15 @@ exports[`ElecHalfHourChart component should be rendered correctly 1`] = ` </linearGradient> </defs> <path - className="bar-ELECTRICITY weekend bounce-3 delay--2 " - d="M0,4 a4,4 0 0 1 4,-4h-5a4,4 0 0 1 4,4v136h-3z" - fill="url(#gradient)" + className="bar-ELECTRICITY weekend bounce-3 delay--2" + d=" + M0,4 + a4,4 0 0 1 4,-4 + h-5 + a4,4 0 0 1 4,4 + v136 + h-3 + z" onAnimationEnd={[Function]} onClick={[Function]} /> @@ -316,7 +334,7 @@ exports[`ElecHalfHourChart component should be rendered correctly 1`] = ` > <defs> <linearGradient - className="bar-ELECTRICITY weekend bounce-3 delay--3 " + className="bar-ELECTRICITY weekend bounce-3 delay--3" id="gradient" x1="0" x2="0" @@ -334,9 +352,15 @@ exports[`ElecHalfHourChart component should be rendered correctly 1`] = ` </linearGradient> </defs> <path - className="bar-ELECTRICITY weekend bounce-3 delay--3 " - d="M0,4 a4,4 0 0 1 4,-4h-5a4,4 0 0 1 4,4v136h-3z" - fill="url(#gradient)" + className="bar-ELECTRICITY weekend bounce-3 delay--3" + d=" + M0,4 + a4,4 0 0 1 4,-4 + h-5 + a4,4 0 0 1 4,4 + v136 + h-3 + z" onAnimationEnd={[Function]} onClick={[Function]} /> @@ -401,6 +425,7 @@ exports[`ElecHalfHourChart component should be rendered correctly 1`] = ` } displayAllDays={false} index={0} + selectedDate={"2021-07-01T00:00:00.000Z"} timeStep={10} width={355.9090909090909} > @@ -435,6 +460,7 @@ exports[`ElecHalfHourChart component should be rendered correctly 1`] = ` } displayAllDays={false} index={1} + selectedDate={"2021-07-01T00:00:00.000Z"} timeStep={10} width={355.9090909090909} /> @@ -456,6 +482,7 @@ exports[`ElecHalfHourChart component should be rendered correctly 1`] = ` } displayAllDays={false} index={2} + selectedDate={"2021-07-01T00:00:00.000Z"} timeStep={10} width={355.9090909090909} /> @@ -477,6 +504,7 @@ exports[`ElecHalfHourChart component should be rendered correctly 1`] = ` } displayAllDays={false} index={3} + selectedDate={"2021-07-01T00:00:00.000Z"} timeStep={10} width={355.9090909090909} /> diff --git a/src/components/Analysis/__snapshots__/ElecHalfHourMonthlyAnalysis.spec.tsx.snap b/src/components/Analysis/ElecHalfHourMonthlyAnalysis/__snapshots__/ElecHalfHourMonthlyAnalysis.spec.tsx.snap similarity index 100% rename from src/components/Analysis/__snapshots__/ElecHalfHourMonthlyAnalysis.spec.tsx.snap rename to src/components/Analysis/ElecHalfHourMonthlyAnalysis/__snapshots__/ElecHalfHourMonthlyAnalysis.spec.tsx.snap diff --git a/src/components/Analysis/__snapshots__/ElecInfoModal.spec.tsx.snap b/src/components/Analysis/ElecHalfHourMonthlyAnalysis/__snapshots__/ElecInfoModal.spec.tsx.snap similarity index 100% rename from src/components/Analysis/__snapshots__/ElecInfoModal.spec.tsx.snap rename to src/components/Analysis/ElecHalfHourMonthlyAnalysis/__snapshots__/ElecInfoModal.spec.tsx.snap diff --git a/src/components/Analysis/elecHalfHourMonthlyAnalysis.scss b/src/components/Analysis/ElecHalfHourMonthlyAnalysis/elecHalfHourMonthlyAnalysis.scss similarity index 97% rename from src/components/Analysis/elecHalfHourMonthlyAnalysis.scss rename to src/components/Analysis/ElecHalfHourMonthlyAnalysis/elecHalfHourMonthlyAnalysis.scss index 4ea1ba5dec4ce4995302569192dfcc10ea6741ce..582ffd247a66d746c36f5af83ad4a139fa3f1638 100644 --- a/src/components/Analysis/elecHalfHourMonthlyAnalysis.scss +++ b/src/components/Analysis/ElecHalfHourMonthlyAnalysis/elecHalfHourMonthlyAnalysis.scss @@ -1,4 +1,4 @@ -@import '../../styles/base/color'; +@import 'src/styles/base/color'; .special-elec-container { color: white; diff --git a/src/components/Analysis/elecInfoModal.scss b/src/components/Analysis/ElecHalfHourMonthlyAnalysis/elecInfoModal.scss similarity index 100% rename from src/components/Analysis/elecInfoModal.scss rename to src/components/Analysis/ElecHalfHourMonthlyAnalysis/elecInfoModal.scss diff --git a/src/components/Analysis/IncompleteDataWarning/IncompleteDataWarning.spec.tsx b/src/components/Analysis/IncompleteDataWarning/IncompleteDataWarning.spec.tsx new file mode 100644 index 0000000000000000000000000000000000000000..85a452c6db5e384be71fdd6129a52102096fbf82 --- /dev/null +++ b/src/components/Analysis/IncompleteDataWarning/IncompleteDataWarning.spec.tsx @@ -0,0 +1,15 @@ +import { FluidType } from 'enums' +import { mount } from 'enzyme' +import React from 'react' +import IncompleteDataWarning from './IncompleteDataWarning' + +describe('IncompleteDataWarning', () => { + it('renders component correctly', () => { + const incompleteFluidTypes = [FluidType.ELECTRICITY, FluidType.GAS] + const wrapper = mount( + <IncompleteDataWarning incompleteDataFluids={incompleteFluidTypes} /> + ) + expect(wrapper.find('h1').text()).toBe('analysis.warning_title') + expect(wrapper.find('p').text()).toBe('analysis.warning_text') + }) +}) diff --git a/src/components/Analysis/IncompleteDataWarning/IncompleteDataWarning.tsx b/src/components/Analysis/IncompleteDataWarning/IncompleteDataWarning.tsx new file mode 100644 index 0000000000000000000000000000000000000000..10fb96acb4314971829e4319a738e615c61bdd53 --- /dev/null +++ b/src/components/Analysis/IncompleteDataWarning/IncompleteDataWarning.tsx @@ -0,0 +1,38 @@ +import warningDark from 'assets/icons/ico/warning-dark.svg' +import StyledIcon from 'components/CommonKit/Icon/StyledIcon' +import { useI18n } from 'cozy-ui/transpiled/react/I18n' +import { FluidType } from 'enums' +import React from 'react' +import { formatListWithAnd } from 'utils/utils' +import './incompleteDataWarning.scss' + +const IncompleteDataWarning = ({ + incompleteDataFluids, +}: { + incompleteDataFluids: FluidType[] +}) => { + const { t } = useI18n() + + const formattedFluidList = formatListWithAnd( + incompleteDataFluids.map(fluidType => + t(`FLUID.${FluidType[fluidType]}.LABEL_PREPOSITION`) + ) + ) + return ( + <div className="analysis-warning"> + <div className="warning-header"> + <StyledIcon icon={warningDark} size={30} /> + <h1>{t('analysis.warning_title')}</h1> + </div> + <div className="warning-content"> + <p> + {t('analysis.warning_text', { + fluidList: formattedFluidList, + })} + </p> + </div> + </div> + ) +} + +export default IncompleteDataWarning diff --git a/src/components/Analysis/IncompleteDataWarning/incompleteDataWarning.scss b/src/components/Analysis/IncompleteDataWarning/incompleteDataWarning.scss new file mode 100644 index 0000000000000000000000000000000000000000..8b5c72b10823e578a0a71f30643ffc19ae3f410d --- /dev/null +++ b/src/components/Analysis/IncompleteDataWarning/incompleteDataWarning.scss @@ -0,0 +1,30 @@ +@import 'src/styles/base/color'; + +.analysis-warning { + background: $grey-linear-gradient-background; + border: 1px solid $multi-color; + border-radius: 4px; + + .warning-header { + display: flex; + align-items: center; + padding: 0 1rem; + background-color: $multi-color; + gap: 0.5rem; + h1 { + color: black; + font-size: 1rem; + font-weight: normal; + } + } + + .warning-content { + padding: 1rem; + p { + margin: 0; + font-size: 1rem; + font-weight: bold; + color: $grey-bright; + } + } +} diff --git a/src/components/Analysis/MaxConsumptionCard.spec.tsx b/src/components/Analysis/MaxConsumptionCard/MaxConsumptionCard.spec.tsx similarity index 58% rename from src/components/Analysis/MaxConsumptionCard.spec.tsx rename to src/components/Analysis/MaxConsumptionCard/MaxConsumptionCard.spec.tsx index a4273b052c65a19f899ac98be22551f7225a1421..8dda881935a9c200430556bf76648e16b79fa0f0 100644 --- a/src/components/Analysis/MaxConsumptionCard.spec.tsx +++ b/src/components/Analysis/MaxConsumptionCard/MaxConsumptionCard.spec.tsx @@ -1,61 +1,32 @@ -import { FluidType } from 'enum/fluid.enum' +import { FluidType } from 'enums' import { mount } from 'enzyme' import toJson from 'enzyme-to-json' import React from 'react' import { Provider } from 'react-redux' -import configureStore from 'redux-mock-store' -import { graphData } from '../../../tests/__mocks__/chartData.mock' -import mockClient from '../../../tests/__mocks__/client' -import { mockAnalysisState } from '../../../tests/__mocks__/store' -import { waitForComponentToPaint } from '../../../tests/__mocks__/testUtils' +import { graphData } from 'tests/__mocks__/chartData.mock' +import { createMockEcolyoStore } from 'tests/__mocks__/store' +import { waitForComponentToPaint } from 'tests/__mocks__/testUtils' import MaxConsumptionCard from './MaxConsumptionCard' -jest.mock('cozy-ui/transpiled/react/I18n', () => { - return { - useI18n: jest.fn(() => { - return { - t: (str: string) => str, - } - }), - } -}) - const mockGetMaxLoad = jest.fn(() => 0) const mockGetGraphData = jest.fn(() => graphData) jest.mock('services/consumption.service', () => { - return jest.fn(() => { - return { - getMaxLoad: mockGetMaxLoad, - getGraphData: mockGetGraphData, - } - }) -}) -jest.mock('cozy-client', () => { - return { - useClient: jest.fn(() => { - return mockClient - }), - } + return jest.fn(() => ({ + getMaxLoad: mockGetMaxLoad, + getGraphData: mockGetGraphData, + })) }) jest.mock('components/Charts/BarChart', () => 'mock-BarChart') -const mockStore = configureStore([]) - describe('MaxConsumptionCard component', () => { + const store = createMockEcolyoStore() it('should be rendered correctly', async () => { - const store = mockStore({ - ecolyo: { - global: { - fluidTypes: [FluidType.ELECTRICITY, FluidType.GAS], - }, - analysis: mockAnalysisState, - }, - }) - const wrapper = mount( <Provider store={store}> - <MaxConsumptionCard /> + <MaxConsumptionCard + fluidsWithData={[FluidType.ELECTRICITY, FluidType.GAS]} + /> </Provider> ) await waitForComponentToPaint(wrapper) @@ -63,30 +34,20 @@ describe('MaxConsumptionCard component', () => { expect(wrapper.find('mock-BarChart').exists()).toBeTruthy() }) it('should be rendered with one fluid and not display arrows', async () => { - const store = mockStore({ - ecolyo: { - global: { fluidTypes: [FluidType.ELECTRICITY] }, - analysis: mockAnalysisState, - }, - }) const wrapper = mount( <Provider store={store}> - <MaxConsumptionCard /> + <MaxConsumptionCard fluidsWithData={[FluidType.ELECTRICITY]} /> </Provider> ) await waitForComponentToPaint(wrapper) expect(wrapper.find('.arrow').exists()).toBeFalsy() }) it('should be rendered with several fluids and click navigate between fluid', async () => { - const store = mockStore({ - ecolyo: { - global: { fluidTypes: [FluidType.ELECTRICITY, FluidType.GAS] }, - analysis: mockAnalysisState, - }, - }) const wrapper = mount( <Provider store={store}> - <MaxConsumptionCard /> + <MaxConsumptionCard + fluidsWithData={[FluidType.ELECTRICITY, FluidType.GAS]} + /> </Provider> ) await waitForComponentToPaint(wrapper) diff --git a/src/components/Analysis/MaxConsumptionCard.tsx b/src/components/Analysis/MaxConsumptionCard/MaxConsumptionCard.tsx similarity index 74% rename from src/components/Analysis/MaxConsumptionCard.tsx rename to src/components/Analysis/MaxConsumptionCard/MaxConsumptionCard.tsx index 3fde2da22acabb35915ab79d8433c9327d37551d..3f71b5b1e9143890683e03ac244492606594c03f 100644 --- a/src/components/Analysis/MaxConsumptionCard.tsx +++ b/src/components/Analysis/MaxConsumptionCard/MaxConsumptionCard.tsx @@ -10,27 +10,24 @@ import Loader from 'components/Loader/Loader' import { useClient } from 'cozy-client' import { useI18n } from 'cozy-ui/transpiled/react/I18n' import Icon from 'cozy-ui/transpiled/react/Icon' -import { DataloadSectionType } from 'enum/dataload.enum' -import { FluidType } from 'enum/fluid.enum' -import { TimeStep } from 'enum/timeStep.enum' +import { DataloadSectionType, FluidType, TimeStep } from 'enums' import { Datachart, Dataload, TimePeriod } from 'models' -import React, { Dispatch, useEffect, useRef, useState } from 'react' -import { useDispatch, useSelector } from 'react-redux' +import React, { useEffect, useRef, useState } from 'react' import ConsumptionDataManager from 'services/consumption.service' -import { AppActionsTypes, AppStore } from 'store' import { setSelectedDate } from 'store/chart/chart.slice' +import { useAppDispatch, useAppSelector } from 'store/hooks' import './maxConsumptionCard.scss' -const MaxConsumptionCard = () => { +const MaxConsumptionCard = ({ + fluidsWithData, +}: { + fluidsWithData: FluidType[] +}) => { const { t } = useI18n() const client = useClient() - const dispatch = useDispatch<Dispatch<AppActionsTypes>>() - const { - global: { fluidTypes }, - analysis: { analysisMonth }, - } = useSelector((state: AppStore) => state.ecolyo) - const [index, setIndex] = useState<number>(0) - const [isLoading, setIsLoading] = useState<boolean>(true) + const dispatch = useAppDispatch() + const { analysisMonth } = useAppSelector(state => state.ecolyo.analysis) + const [isLoading, setIsLoading] = useState<boolean>(false) const [maxDayData, setMaxDayData] = useState<Dataload | null>(null) const [chartData, setChartData] = useState<Datachart>({ actualData: [], @@ -38,27 +35,33 @@ const MaxConsumptionCard = () => { }) const containerRef = useRef<HTMLDivElement>(null) const { height, width } = useChartResize(containerRef, isLoading, 250, 940) + const [currentFluid, setCurrentFluid] = useState<FluidType | undefined>() - const currentFluidType = FluidType[fluidTypes[index]] as + useEffect(() => { + setCurrentFluid(fluidsWithData[0]) + }, [fluidsWithData]) + + const currentFluidSlug = FluidType[currentFluid || 0] as | 'ELECTRICITY' | 'WATER' | 'GAZ' - const fluidColor = currentFluidType.toLowerCase() const handleFluidChange = (direction: number) => { + if (currentFluid === undefined) return setIsLoading(true) - let newIndex = index + direction - if (newIndex >= fluidTypes.length) { + let newIndex = fluidsWithData.indexOf(currentFluid) + direction + if (newIndex >= fluidsWithData.length) { newIndex = 0 } else if (newIndex < 0) { - newIndex = fluidTypes.length - 1 + newIndex = fluidsWithData.length - 1 } - setIndex(newIndex) + setCurrentFluid(fluidsWithData[newIndex]) } useEffect(() => { let subscribed = true async function getMaxLoadData() { + if (currentFluid === undefined) return setIsLoading(true) const timePeriod: TimePeriod = { startDate: analysisMonth.minus({ month: 1 }).startOf('month'), @@ -68,7 +71,7 @@ const MaxConsumptionCard = () => { const monthlyData = await consumptionService.getGraphData( timePeriod, TimeStep.DAY, - [fluidTypes[index]] + [currentFluid] ) if (monthlyData && monthlyData?.actualData.length > 0) { @@ -89,7 +92,7 @@ const MaxConsumptionCard = () => { return () => { subscribed = false } - }, [analysisMonth, client, fluidTypes, index, dispatch]) + }, [analysisMonth, client, fluidsWithData, currentFluid, dispatch]) const getMaxConsumptionDay = (dataload: Dataload[]) => { let maxIndex = -1 @@ -129,25 +132,25 @@ const MaxConsumptionCard = () => { <StyledIcon icon={GraphIcon} size={38} /> <div className="text-16-normal title">{t('analysis.max_day')}</div> <div className="fluid-navigation"> - {fluidTypes.length > 1 && buttonPrev()} - <div className={`text-20-bold fluid ${fluidColor}`}> - {t(`FLUID.${currentFluidType}.LABEL`)} + {fluidsWithData.length > 1 && buttonPrev()} + <div className={`text-20-bold fluid ${currentFluidSlug.toLowerCase()}`}> + {t(`FLUID.${currentFluidSlug}.LABEL`)} </div> - {fluidTypes.length > 1 && buttonNext()} + {fluidsWithData.length > 1 && buttonNext()} </div> <div className="data-container"> {isLoading && ( <div className="loaderContainer"> - <Loader fluidType={fluidTypes[index]} /> + <Loader fluidType={currentFluid} /> </div> )} {!isLoading && ( <> {!maxDayData && ( - <p className={`text-20-bold no_data`}>{t('analysis.no_data')}</p> + <p className="text-20-bold no_data">{t('analysis.no_data')}</p> )} - {maxDayData && ( + {maxDayData && currentFluid !== undefined && ( <> <div className="text-24-bold maxDay-date"> {maxDayData.date.setLocale('fr').toFormat('cccc dd LLLL')} @@ -155,15 +158,16 @@ const MaxConsumptionCard = () => { <div> <DataloadSection dataload={maxDayData} - fluidType={fluidTypes[index]} + fluidType={currentFluid} dataloadSectionType={DataloadSectionType.NO_COMPARE} toggleEstimationModal={() => null} /> </div> <BarChart chartData={chartData} - fluidType={fluidTypes[index]} + fluidType={currentFluid} timeStep={TimeStep.DAY} + showCompare={false} height={height} width={width} isSwitching={false} diff --git a/src/components/Analysis/__snapshots__/MaxConsumptionCard.spec.tsx.snap b/src/components/Analysis/MaxConsumptionCard/__snapshots__/MaxConsumptionCard.spec.tsx.snap similarity index 99% rename from src/components/Analysis/__snapshots__/MaxConsumptionCard.spec.tsx.snap rename to src/components/Analysis/MaxConsumptionCard/__snapshots__/MaxConsumptionCard.spec.tsx.snap index 8a146488c5ec22dcd6575e849da9afab08d37e36..10886a7a5e2e3a63fc7d358651ab0e4b56f360b9 100644 --- a/src/components/Analysis/__snapshots__/MaxConsumptionCard.spec.tsx.snap +++ b/src/components/Analysis/MaxConsumptionCard/__snapshots__/MaxConsumptionCard.spec.tsx.snap @@ -13,7 +13,14 @@ exports[`MaxConsumptionCard component should be rendered correctly 1`] = ` } } > - <MaxConsumptionCard> + <MaxConsumptionCard + fluidsWithData={ + Array [ + 0, + 2, + ] + } + > <div className="max-consumption-container" > @@ -522,6 +529,7 @@ exports[`MaxConsumptionCard component should be rendered correctly 1`] = ` fluidType={0} height={250} isSwitching={false} + showCompare={false} timeStep={20} width={940} /> diff --git a/src/components/Analysis/maxConsumptionCard.scss b/src/components/Analysis/MaxConsumptionCard/maxConsumptionCard.scss similarity index 97% rename from src/components/Analysis/maxConsumptionCard.scss rename to src/components/Analysis/MaxConsumptionCard/maxConsumptionCard.scss index 66ac47a38804821d41f9026d16341d8fa1a9e6b5..b6df1c622636a132aed514da63148843e0bd2bd4 100644 --- a/src/components/Analysis/maxConsumptionCard.scss +++ b/src/components/Analysis/MaxConsumptionCard/maxConsumptionCard.scss @@ -1,4 +1,4 @@ -@import '../../styles/base/color'; +@import 'src/styles/base/color'; .max-consumption-container { display: flex; diff --git a/src/components/Analysis/MonthlyAnalysis.spec.tsx b/src/components/Analysis/MonthlyAnalysis.spec.tsx index 673cc0132691d514f30ff008be9ca3c5ffd33aa4..b6f18e5460fa79ce0379d5e9560cfb91fee9f7f3 100644 --- a/src/components/Analysis/MonthlyAnalysis.spec.tsx +++ b/src/components/Analysis/MonthlyAnalysis.spec.tsx @@ -1,35 +1,51 @@ import MonthlyAnalysis from 'components/Analysis/MonthlyAnalysis' -import { FluidType } from 'enum/fluid.enum' import { mount } from 'enzyme' +import toJson from 'enzyme-to-json' +import { PerformanceIndicator } from 'models' import React from 'react' import { Provider } from 'react-redux' import { BrowserRouter } from 'react-router-dom' -import configureStore from 'redux-mock-store' -import { mockAnalysisState } from '../../../tests/__mocks__/store' +import { createMockEcolyoStore } from 'tests/__mocks__/store' +import { waitForComponentToPaint } from 'tests/__mocks__/testUtils' -jest.mock('cozy-ui/transpiled/react/I18n', () => { - return { - useI18n: jest.fn(() => { - return { - t: (str: string) => str, - } - }), - } +const mockPI: PerformanceIndicator[] = [ + { value: 5, compareValue: 10, percentageVariation: 50 }, + { value: 5, compareValue: 10, percentageVariation: 50 }, +] + +jest.mock('services/consumption.service', () => { + return jest.fn(() => { + return { + getFluidsWithDataForTimePeriod: jest.fn(() => [0, 1, 2]), + getFluidsWithIncompleteData: jest.fn(() => [0]), + getPerformanceIndicators: jest.fn(() => mockPI), + } + }) }) -jest.mock('services/consumption.service') -jest.mock('components/Analysis/ComparisonView', () => 'mock-comparison-view') -jest.mock('components/Analysis/AnalysisConsumption', () => 'mock-analysis') -const mockStore = configureStore([]) +jest.mock('components/Analysis/Comparison/Comparison', () => 'mock-comparison') +jest.mock( + 'components/Analysis/TotalAnalysisChart/TotalAnalysisChart', + () => 'mock-total-analysis' +) +jest.mock( + 'components/Analysis/MaxConsumptionCard/MaxConsumptionCard', + () => 'mock-max-consumption' +) +jest.mock( + 'components/Analysis/ProfileComparator/ProfileComparator', + () => 'mock-analysis' +) +jest.mock( + 'components/Analysis/ElecHalfHourMonthlyAnalysis/ElecHalfHourMonthlyAnalysis', + () => 'mock-half-hour-analysis' +) + +window.scrollTo = jest.fn() describe('MonthlyAnalysis component', () => { it('should be rendered correctly', async () => { - const store = mockStore({ - ecolyo: { - global: { fluidTypes: [FluidType.ELECTRICITY, FluidType.GAS] }, - analysis: mockAnalysisState, - }, - }) + const store = createMockEcolyoStore() const wrapper = mount( <BrowserRouter> <Provider store={store}> @@ -39,7 +55,8 @@ describe('MonthlyAnalysis component', () => { /> </Provider> </BrowserRouter> - ).getElement() - expect(wrapper).toMatchSnapshot() + ) + await waitForComponentToPaint(wrapper) + expect(toJson(wrapper)).toMatchSnapshot() }) }) diff --git a/src/components/Analysis/MonthlyAnalysis.tsx b/src/components/Analysis/MonthlyAnalysis.tsx index 6c8ff0f11940e6ede604cb82217e248c03313c10..90e2d0253851d8285065acfa4a45f59b088564d9 100644 --- a/src/components/Analysis/MonthlyAnalysis.tsx +++ b/src/components/Analysis/MonthlyAnalysis.tsx @@ -1,20 +1,19 @@ +import { Fade } from '@material-ui/core' import Loader from 'components/Loader/Loader' import { useClient } from 'cozy-client' -import { FluidType } from 'enum/fluid.enum' -import { TimeStep } from 'enum/timeStep.enum' -import { PerformanceIndicator } from 'models' -import React, { useEffect, useState } from 'react' -import { useSelector } from 'react-redux' +import { FluidState, FluidType, TimeStep } from 'enums' +import { PerformanceIndicator, TimePeriod } from 'models' +import React, { useEffect, useMemo, useState } from 'react' import ConsumptionService from 'services/consumption.service' -import ConfigService from 'services/fluidConfig.service' import PerformanceIndicatorService from 'services/performanceIndicator.service' -import { AppStore } from 'store' -import AnalysisConsumption from './AnalysisConsumption' -import AnalysisErrorModal from './AnalysisErrorModal' -import ComparisonView from './ComparisonView' -import ElecHalfHourMonthlyAnalysis from './ElecHalfHourMonthlyAnalysis' -import MaxConsumptionCard from './MaxConsumptionCard' -import TotalAnalysisChart from './TotalAnalysisChart' +import { useAppSelector } from 'store/hooks' +import Comparison from './Comparison/Comparison' +import ElecHalfHourMonthlyAnalysis from './ElecHalfHourMonthlyAnalysis/ElecHalfHourMonthlyAnalysis' +import IncompleteDataWarning from './IncompleteDataWarning/IncompleteDataWarning' +import MaxConsumptionCard from './MaxConsumptionCard/MaxConsumptionCard' +import NoAnalysisModal from './NoKonnector/NoAnalysisModal' +import ProfileComparator from './ProfileComparator/ProfileComparator' +import TotalAnalysisChart from './TotalAnalysisChart/TotalAnalysisChart' import './monthlyanalysis.scss' interface MonthlyAnalysisProps { @@ -29,8 +28,28 @@ const MonthlyAnalysis = ({ const client = useClient() const { analysis: { analysisMonth }, - global: { fluidTypes }, - } = useSelector((state: AppStore) => state.ecolyo) + global: { fluidStatus }, + } = useAppSelector(state => state.ecolyo) + + const consumptionService = useMemo( + () => new ConsumptionService(client), + [client] + ) + const performanceIndicatorService = useMemo( + () => new PerformanceIndicatorService(), + [] + ) + + const allKonnectorDisconnected = fluidStatus.some( + fluid => fluid.status === FluidState.NOT_CONNECTED + ) + + const [loadAnalysis, setLoadAnalysis] = useState<boolean>(true) + const [openNoDataModal, setOpenNoDataModal] = useState(false) + const [fluidsWithData, setFluidsWithData] = useState<FluidType[]>([]) + const [incompleteDataFluids, setIncompleteDataFluids] = useState<FluidType[]>( + [] + ) const [performanceIndicators, setPerformanceIndicators] = useState< PerformanceIndicator[] >([]) @@ -40,56 +59,73 @@ const MonthlyAnalysis = ({ compareValue: 0, percentageVariation: 0, }) - const [loadAnalysis, setLoadAnalysis] = useState<boolean>(true) - const configService = new ConfigService() - const fluidConfig = configService.getFluidConfig() useEffect(() => { let subscribed = true - async function populateData() { + + const populateData = async () => { setLoadAnalysis(true) - const consumptionService = new ConsumptionService(client) - const performanceIndicatorService = new PerformanceIndicatorService() - const periods = { - timePeriod: { - startDate: analysisMonth.minus({ month: 1 }).startOf('month'), - endDate: analysisMonth.minus({ month: 1 }).endOf('month'), - }, - comparisonTimePeriod: { - startDate: analysisMonth.minus({ month: 2 }).startOf('month'), - endDate: analysisMonth.minus({ month: 2 }).endOf('month'), - }, + + const timePeriod: TimePeriod = { + startDate: analysisMonth.minus({ month: 1 }).startOf('month'), + endDate: analysisMonth.minus({ month: 1 }).endOf('month'), + } + const comparisonTimePeriod: TimePeriod = { + startDate: analysisMonth.minus({ month: 2 }).startOf('month'), + endDate: analysisMonth.minus({ month: 2 }).endOf('month'), } + const resultFluids = + await consumptionService.getFluidsWithDataForTimePeriod( + [FluidType.ELECTRICITY, FluidType.WATER, FluidType.GAS], + timePeriod + ) + + const fetchedIncompleteDataFluids = + await consumptionService.getFluidsWithIncompleteData( + [FluidType.ELECTRICITY, FluidType.WATER, FluidType.GAS], + timePeriod.startDate + ) + setIncompleteDataFluids(fetchedIncompleteDataFluids) + const fetchedPerformanceIndicators = await consumptionService.getPerformanceIndicators( - periods.timePeriod, + timePeriod, TimeStep.MONTH, - fluidTypes, - periods.comparisonTimePeriod + resultFluids, + comparisonTimePeriod ) - if (subscribed) { - if (fetchedPerformanceIndicators) { - setPerformanceIndicators(fetchedPerformanceIndicators) - setLoadAnalysis(false) - const hasValidPI = fetchedPerformanceIndicators.some(pi => pi?.value) - if (hasValidPI) setLoadAnalysis(true) - - setAggregatedPerformanceIndicators( - performanceIndicatorService.aggregatePerformanceIndicators( - fetchedPerformanceIndicators - ) - ) - } + + if (fetchedPerformanceIndicators) { + setPerformanceIndicators(fetchedPerformanceIndicators) setLoadAnalysis(false) + setAggregatedPerformanceIndicators( + performanceIndicatorService.aggregatePerformanceIndicators( + fetchedPerformanceIndicators + ) + ) } + if (resultFluids.length === 0 && allKonnectorDisconnected) { + setOpenNoDataModal(true) + } + setFluidsWithData(resultFluids) + setLoadAnalysis(false) + } + + if (subscribed) { + populateData() } - populateData() return () => { saveLastScrollPosition() subscribed = false } - }, [client, fluidTypes, analysisMonth, saveLastScrollPosition]) + }, [ + allKonnectorDisconnected, + analysisMonth, + consumptionService, + performanceIndicatorService, + saveLastScrollPosition, + ]) useEffect(() => { if (!loadAnalysis) { @@ -102,53 +138,59 @@ const MonthlyAnalysis = ({ return ( <> {loadAnalysis && ( - <div className="analysis-container-spinner" aria-busy="true"> + <div className="loaderContainer"> <Loader /> </div> )} + <NoAnalysisModal open={openNoDataModal} onClose={setOpenNoDataModal} /> {!loadAnalysis && ( - <div className="analysis-root black"> - {fluidTypes.length >= 1 ? ( - <> + <Fade in={!loadAnalysis}> + <div className="analysis-root"> + {incompleteDataFluids.length !== 0 && ( <div className="analysis-content"> - <ComparisonView fluidConfig={fluidConfig} /> + <IncompleteDataWarning + incompleteDataFluids={incompleteDataFluids} + /> </div> - <div className="analysis-content"> - <div className="card rich-card"> - <TotalAnalysisChart fluidTypes={fluidTypes} /> - </div> + )} + <div className="analysis-content"> + <Comparison + fluidsWithData={fluidsWithData} + monthPerformanceIndicators={performanceIndicators} + /> + </div> + + <div className="analysis-content"> + <div className="card rich-card"> + <TotalAnalysisChart fluidsWithData={fluidsWithData} /> </div> - <div className="analysis-content"> - <div className="card rich-card"> - <MaxConsumptionCard /> - </div> + </div> + <div className="analysis-content"> + <div className="card rich-card"> + <MaxConsumptionCard fluidsWithData={fluidsWithData} /> </div> + </div> + <div className="analysis-content"> + <div className="card rich-card"> + <ProfileComparator + aggregatedPerformanceIndicator={ + aggregatedPerformanceIndicators + } + performanceIndicators={performanceIndicators} + /> + </div> + </div> + {fluidsWithData.includes(FluidType.ELECTRICITY) && ( <div className="analysis-content"> - <div className="card rich-card"> - <AnalysisConsumption - aggregatedPerformanceIndicator={ - aggregatedPerformanceIndicators - } - performanceIndicators={performanceIndicators} + <div className="card"> + <ElecHalfHourMonthlyAnalysis + perfIndicator={performanceIndicators[FluidType.ELECTRICITY]} /> </div> </div> - {fluidTypes.includes(FluidType.ELECTRICITY) && ( - <div className="analysis-content"> - <div className="card"> - <ElecHalfHourMonthlyAnalysis - perfIndicator={ - performanceIndicators[FluidType.ELECTRICITY] - } - /> - </div> - </div> - )} - </> - ) : ( - <AnalysisErrorModal /> - )} - </div> + )} + </div> + </Fade> )} </> ) diff --git a/src/components/Analysis/NoKonnector/NoAnalysisModal.spec.tsx b/src/components/Analysis/NoKonnector/NoAnalysisModal.spec.tsx new file mode 100644 index 0000000000000000000000000000000000000000..fd629dca0cdd45dd563fb49607c3840e39e1ceb3 --- /dev/null +++ b/src/components/Analysis/NoKonnector/NoAnalysisModal.spec.tsx @@ -0,0 +1,13 @@ +import Button from '@material-ui/core/Button' +import Dialog from '@material-ui/core/Dialog' +import { mount } from 'enzyme' +import React from 'react' +import NoAnalysisModal from './NoAnalysisModal' + +describe('NoAnalysisModal component', () => { + it('should be rendered correctly', () => { + const wrapper = mount(<NoAnalysisModal open={true} onClose={jest.fn()} />) + expect(wrapper.find(Dialog).exists()).toBeTruthy() + expect(wrapper.find(Button).exists()).toBeTruthy() + }) +}) diff --git a/src/components/Analysis/NoKonnector/NoAnalysisModal.tsx b/src/components/Analysis/NoKonnector/NoAnalysisModal.tsx new file mode 100644 index 0000000000000000000000000000000000000000..09e0b8c749d2b0e44d236dc1870d29b0a3a9a834 --- /dev/null +++ b/src/components/Analysis/NoKonnector/NoAnalysisModal.tsx @@ -0,0 +1,77 @@ +import Button from '@material-ui/core/Button' +import Dialog from '@material-ui/core/Dialog' +import { useI18n } from 'cozy-ui/transpiled/react/I18n' +import React from 'react' +import { useNavigate } from 'react-router-dom' +import './noAnalysisModal.scss' + +const NoAnalysisModal = ({ + open, + onClose, +}: { + open: boolean + onClose: React.Dispatch<React.SetStateAction<boolean>> +}) => { + const { t } = useI18n() + const navigate = useNavigate() + + const goToConsumption = () => { + navigate('/consumption') + } + + const close = () => { + onClose(false) + } + + return ( + <Dialog + open={open} + onClose={close} + aria-labelledby="accessibility-title" + classes={{ + root: 'modal-root', + paper: 'modal-paper', + }} + > + <div id="accessibility-title"> + {t('analysis_error_modal.accessibility.window_title')} + </div> + <div className="em-root analysis-error-container"> + <div className="analysis-error-title text-20-bold"> + {t('analysis_error_modal.title')} + </div> + <div className="analysis-error-message text-16-normal"> + {t('analysis_error_modal.message')} + </div> + <div className="analysis-error-button"> + <Button + aria-label={t( + 'analysis_error_modal.accessibility.button_understood' + )} + onClick={close} + classes={{ + root: 'btn-secondary-positive', + label: 'text-16-normal', + }} + > + {t('analysis_error_modal.understood')} + </Button> + <Button + aria-label={t( + 'analysis_error_modal.accessibility.button_goto_konnector' + )} + onClick={goToConsumption} + classes={{ + root: 'btn-highlight', + label: 'text-16-bold', + }} + > + {t('analysis_error_modal.go_to_conso')} + </Button> + </div> + </div> + </Dialog> + ) +} + +export default NoAnalysisModal diff --git a/src/components/Analysis/NoKonnector/noAnalysisModal.scss b/src/components/Analysis/NoKonnector/noAnalysisModal.scss new file mode 100644 index 0000000000000000000000000000000000000000..4f89990b3f6f2be0af45c5f253e741fd9c5e9122 --- /dev/null +++ b/src/components/Analysis/NoKonnector/noAnalysisModal.scss @@ -0,0 +1,31 @@ +@import 'src/styles/base/color'; +@import 'src/styles/base/breakpoint'; + +.analysis-error-container { + color: $grey-bright; + text-align: center; + display: flex; + flex-direction: column; + gap: 1.5rem; + .analysis-error-title { + color: $gold-shadow; + } + .analysis-error-button { + display: flex; + justify-content: space-between; + gap: 1rem; + button { + margin: 0; + height: 45px; + &.btn-secondary-positive { + margin-bottom: 0; + } + } + @media #{$large-phone} { + flex-direction: column-reverse; + button { + width: 100%; + } + } + } +} diff --git a/src/components/Analysis/PieChart.spec.tsx b/src/components/Analysis/PieChart.spec.tsx deleted file mode 100644 index 130cf415b532f5325ac4bd2b7dcdf7765fe2f154..0000000000000000000000000000000000000000 --- a/src/components/Analysis/PieChart.spec.tsx +++ /dev/null @@ -1,85 +0,0 @@ -import { DataloadState } from 'enum/dataload.enum' -import { mount } from 'enzyme' -import toJson from 'enzyme-to-json' -import { DateTime } from 'luxon' -import { DataloadValueDetail } from 'models' -import React from 'react' -import { Provider } from 'react-redux' -import configureStore from 'redux-mock-store' -import { globalStateData } from '../../../tests/__mocks__/globalStateData.mock' -import PieChart from './PieChart' - -jest.mock('cozy-ui/transpiled/react/I18n', () => { - return { - useI18n: jest.fn(() => { - return { - t: (str: string) => str, - } - }), - } -}) - -const mockGetAllLastPrices = jest.fn() -jest.mock('services/fluidsPrices.service', () => { - return jest.fn(() => { - return { - getAllLastPrices: mockGetAllLastPrices, - } - }) -}) - -const mockStore = configureStore([]) - -describe('PieChart component', () => { - const mockDataloadValueDetailArray: DataloadValueDetail[] = [ - { value: 10, state: DataloadState.VALID }, - { value: 20, state: DataloadState.VALID }, - { value: 30, state: DataloadState.VALID }, - ] - it('should be rendered correctly', () => { - const store = mockStore({ - ecolyo: { - global: globalStateData, - }, - }) - const wrapper = mount( - <Provider store={store}> - <PieChart - width={300} - height={300} - outerRadius={300} - innerRadius={300} - currentAnalysisDate={DateTime.fromISO('2021-07-01T00:00:00.000Z', { - zone: 'utc', - })} - totalValue={60} - dataloadValueDetailArray={mockDataloadValueDetailArray} - /> - </Provider> - ) - expect(toJson(wrapper)).toMatchSnapshot() - }) - it('should open estimation modal', () => { - const store = mockStore({ - ecolyo: { - global: globalStateData, - }, - }) - const wrapper = mount( - <Provider store={store}> - <PieChart - width={300} - height={300} - outerRadius={300} - innerRadius={300} - currentAnalysisDate={DateTime.fromISO('2021-07-01T00:00:00.000Z', { - zone: 'utc', - })} - totalValue={60} - dataloadValueDetailArray={mockDataloadValueDetailArray} - /> - </Provider> - ) - expect(wrapper.find('.estimation-text').simulate('click')) - }) -}) diff --git a/src/components/Analysis/AnalysisConsumption.spec.tsx b/src/components/Analysis/ProfileComparator/ProfileComparator.spec.tsx similarity index 63% rename from src/components/Analysis/AnalysisConsumption.spec.tsx rename to src/components/Analysis/ProfileComparator/ProfileComparator.spec.tsx index 0e19f2b8e709232f442aba2b6aed2625c2b177f5..8bb603abffedaf7fcc092ff60504c77e2440f05c 100644 --- a/src/components/Analysis/AnalysisConsumption.spec.tsx +++ b/src/components/Analysis/ProfileComparator/ProfileComparator.spec.tsx @@ -1,31 +1,19 @@ /* eslint-disable react/display-name */ import { Accordion } from '@material-ui/core' import Button from '@material-ui/core/Button' -import AnalysisConsumption from 'components/Analysis/AnalysisConsumption' -import { FluidType } from 'enum/fluid.enum' +import { FluidType } from 'enums' import { mount } from 'enzyme' import { PerformanceIndicator } from 'models' import React from 'react' import { Provider } from 'react-redux' -import configureStore from 'redux-mock-store' -import { globalStateData } from '../../../tests/__mocks__/globalStateData.mock' -import { profileData } from '../../../tests/__mocks__/profileData.mock' +import { profileData } from 'tests/__mocks__/profileData.mock' import { mockMonthlyForecastJanuaryTestProfile1, profileTypeData, -} from '../../../tests/__mocks__/profileType.mock' -import { mockAnalysisState } from '../../../tests/__mocks__/store' -import { waitForComponentToPaint } from '../../../tests/__mocks__/testUtils' - -jest.mock('cozy-ui/transpiled/react/I18n', () => { - return { - useI18n: jest.fn(() => { - return { - t: (str: string) => str, - } - }), - } -}) +} from 'tests/__mocks__/profileType.mock' +import { createMockEcolyoStore, mockAnalysisState } from 'tests/__mocks__/store' +import { waitForComponentToPaint } from 'tests/__mocks__/testUtils' +import ProfileComparator from './ProfileComparator' const mockedNavigate = jest.fn() jest.mock('react-router-dom', () => ({ @@ -33,37 +21,29 @@ jest.mock('react-router-dom', () => ({ useNavigate: () => mockedNavigate, })) -const mockgetMonthlyForecast = jest.fn() +const mockGetMonthlyForecast = jest.fn() jest.mock('services/profileType.service', () => { - return jest.fn(() => { - return { - getMonthlyForecast: mockgetMonthlyForecast, - } - }) + return jest.fn(() => ({ + getMonthlyForecast: mockGetMonthlyForecast, + })) }) -const mockgetProfileTypeData = jest.fn() +const mockGetProfileTypeData = jest.fn() jest.mock('services/profileTypeEntity.service', () => { - return jest.fn(() => { - return { - getProfileType: mockgetProfileTypeData, - } - }) + return jest.fn(() => ({ + getProfileType: mockGetProfileTypeData, + })) }) -jest.mock('components/Analysis/AnalysisConsumptionRow', () => () => ( - <div id="analysisconsumptionrow" /> -)) +jest.mock( + 'components/Analysis/ProfileComparator/ProfileComparatorRow', + () => 'mock-profileComparatorRow' +) const modifiedProfile = { ...profileData, isProfileTypeCompleted: true } -const mockStore = configureStore([]) -const store = mockStore({ - ecolyo: { - profile: modifiedProfile, - profileType: profileTypeData, - global: globalStateData, - analysis: mockAnalysisState, - }, +const store = createMockEcolyoStore({ + profile: modifiedProfile, + analysis: mockAnalysisState, }) const performanceIndicator = { @@ -93,7 +73,7 @@ describe('AnalysisConsumption component', () => { it('should be rendered correctly', async () => { const wrapper = mount( <Provider store={store}> - <AnalysisConsumption + <ProfileComparator aggregatedPerformanceIndicator={performanceIndicator} performanceIndicators={performanceIndicators} /> @@ -101,7 +81,7 @@ describe('AnalysisConsumption component', () => { ) await waitForComponentToPaint(wrapper) expect(wrapper.find(Accordion).exists()).toBeTruthy() - expect(wrapper.find('#analysisconsumptionrow').length).toBe(4) + expect(wrapper.find('mock-profileComparatorRow').length).toBe(4) }) it('should be rendered correctly with no profil set', async () => { @@ -112,7 +92,7 @@ describe('AnalysisConsumption component', () => { } const wrapper = mount( <Provider store={store}> - <AnalysisConsumption + <ProfileComparator aggregatedPerformanceIndicator={mockAggregatedPerformanceIndicator} performanceIndicators={performanceIndicators} /> @@ -130,7 +110,7 @@ describe('AnalysisConsumption component', () => { } const wrapper = mount( <Provider store={store}> - <AnalysisConsumption + <ProfileComparator aggregatedPerformanceIndicator={mockAggregatedPerformanceIndicator} performanceIndicators={performanceIndicators} /> @@ -138,13 +118,13 @@ describe('AnalysisConsumption component', () => { ) await waitForComponentToPaint(wrapper) expect(wrapper.find(Accordion).exists()).toBeTruthy() - expect(wrapper.find('#analysisconsumptionrow').length).toBe(4) + expect(wrapper.find('mock-profileComparatorRow').length).toBe(4) }) it('should be rendered correctly without fluid', async () => { const wrapper = mount( <Provider store={store}> - <AnalysisConsumption + <ProfileComparator aggregatedPerformanceIndicator={performanceIndicator} performanceIndicators={performanceIndicators} /> @@ -152,76 +132,72 @@ describe('AnalysisConsumption component', () => { ) await waitForComponentToPaint(wrapper) expect( - wrapper.find('#analysisconsumptionrow').first().parent().prop('fluid') + wrapper.find('mock-profileComparatorRow').first().prop('fluid') ).toBe(FluidType.MULTIFLUID) }) it('should be rendered correctly with all fluids connected', async () => { - const store = mockStore({ - ecolyo: { - profile: modifiedProfile, - profileType: profileTypeData, - global: { - fluidTypes: [FluidType.ELECTRICITY, FluidType.WATER, FluidType.GAS], - }, - analysis: { - ...mockAnalysisState, - analysisMonth: profileData.monthlyAnalysisDate, - }, + const store = createMockEcolyoStore({ + profile: modifiedProfile, + profileType: profileTypeData, + global: { + fluidTypes: [FluidType.ELECTRICITY, FluidType.WATER, FluidType.GAS], + }, + analysis: { + ...mockAnalysisState, + analysisMonth: profileData.monthlyAnalysisDate, }, }) - mockgetMonthlyForecast.mockReturnValue( + mockGetMonthlyForecast.mockReturnValue( mockMonthlyForecastJanuaryTestProfile1 ) const wrapper = mount( <Provider store={store}> - <AnalysisConsumption + <ProfileComparator aggregatedPerformanceIndicator={performanceIndicator} performanceIndicators={performanceIndicators} /> </Provider> ) await waitForComponentToPaint(wrapper) - expect(mockgetMonthlyForecast).toHaveBeenCalledWith( + expect(mockGetMonthlyForecast).toHaveBeenCalledWith( profileData.monthlyAnalysisDate.month - 1 ) expect( - wrapper.find('#analysisconsumptionrow').first().parent().prop('fluid') + wrapper.find('mock-profileComparatorRow').first().prop('fluid') ).toBe(FluidType.MULTIFLUID) }) it('should be rendered correctly with 2 fluids connected', async () => { - const store = mockStore({ - ecolyo: { - profile: modifiedProfile, - global: { fluidTypes: [FluidType.ELECTRICITY, FluidType.WATER] }, - analysis: { analysisMonth: profileData.monthlyAnalysisDate }, - }, + const store = createMockEcolyoStore({ + profile: modifiedProfile, + global: { fluidTypes: [FluidType.ELECTRICITY, FluidType.WATER] }, + analysis: { analysisMonth: profileData.monthlyAnalysisDate }, }) - mockgetMonthlyForecast.mockReturnValue( + mockGetMonthlyForecast.mockReturnValue( mockMonthlyForecastJanuaryTestProfile1 ) const wrapper = mount( <Provider store={store}> - <AnalysisConsumption + <ProfileComparator aggregatedPerformanceIndicator={performanceIndicator} performanceIndicators={performanceIndicators} /> </Provider> ) await waitForComponentToPaint(wrapper) - expect(mockgetMonthlyForecast).toHaveBeenCalledWith( + expect(mockGetMonthlyForecast).toHaveBeenCalledWith( profileData.monthlyAnalysisDate.month - 1 ) expect( - wrapper.find('#analysisconsumptionrow').first().parent().prop('fluid') + wrapper.find('mock-profileComparatorRow').first().prop('fluid') ).toBe(FluidType.MULTIFLUID) }) it('should redirect to profileType form when click on mui button', async () => { const wrapper = mount( <Provider store={store}> - <AnalysisConsumption + <ProfileComparator aggregatedPerformanceIndicator={performanceIndicator} performanceIndicators={performanceIndicators} /> @@ -229,6 +205,6 @@ describe('AnalysisConsumption component', () => { ) await waitForComponentToPaint(wrapper) wrapper.find(Button).first().simulate('click') - expect(mockedNavigate).toBeCalledWith('/profileType') + expect(mockedNavigate).toHaveBeenCalledWith('/profileType') }) }) diff --git a/src/components/Analysis/AnalysisConsumption.tsx b/src/components/Analysis/ProfileComparator/ProfileComparator.tsx similarity index 71% rename from src/components/Analysis/AnalysisConsumption.tsx rename to src/components/Analysis/ProfileComparator/ProfileComparator.tsx index 80c8c93bf400a58bf11af6527525aba834d9dda7..29ae370e40395e327ba1fa1a89fa5518dbd771fc 100644 --- a/src/components/Analysis/AnalysisConsumption.tsx +++ b/src/components/Analysis/ProfileComparator/ProfileComparator.tsx @@ -10,39 +10,36 @@ import AnalysisIcon from 'assets/icons/visu/analysis/analysis.svg' import PlaceHolderIcon from 'assets/icons/visu/analysis/no-profile-placeholder.svg' import StyledIcon from 'components/CommonKit/Icon/StyledIcon' import Loader from 'components/Loader/Loader' -import { Client, useClient } from 'cozy-client' +import { useClient } from 'cozy-client' import { useI18n } from 'cozy-ui/transpiled/react/I18n' import Icon from 'cozy-ui/transpiled/react/Icon' -import { FluidType } from 'enum/fluid.enum' -import { PerformanceIndicator } from 'models' -import { MonthlyForecast, ProfileType } from 'models/profileType.model' +import { FluidType } from 'enums' +import { MonthlyForecast, PerformanceIndicator, ProfileType } from 'models' import React, { useCallback, useEffect, useState } from 'react' -import { useSelector } from 'react-redux' import { useNavigate } from 'react-router-dom' import ProfileTypeService from 'services/profileType.service' import ProfileTypeEntityService from 'services/profileTypeEntity.service' -import { AppStore } from 'store' -import AnalysisConsumptionRow from './AnalysisConsumptionRow' -import './analysisConsumption.scss' +import { useAppSelector } from 'store/hooks' +import ProfileComparatorRow from './ProfileComparatorRow' +import './profileComparator.scss' -interface AnalysisConsumptionProps { +interface ProfileComparatorProps { aggregatedPerformanceIndicator: PerformanceIndicator performanceIndicators: PerformanceIndicator[] } -const AnalysisConsumption = ({ +const ProfileComparator = ({ aggregatedPerformanceIndicator, performanceIndicators, -}: AnalysisConsumptionProps) => { +}: ProfileComparatorProps) => { const { t } = useI18n() + const client = useClient() const navigate = useNavigate() - const client: Client = useClient() const userPriceConsumption: number = aggregatedPerformanceIndicator.value || 0 const { analysis: { analysisMonth }, - global: { fluidTypes }, profile, - } = useSelector((state: AppStore) => state.ecolyo) + } = useAppSelector(state => state.ecolyo) const [homePriceConsumption, setHomePriceConsumption] = useState<number>(0) const [forecast, setForecast] = useState<MonthlyForecast | null>(null) const [isLoading, setIsLoading] = useState<boolean>(true) @@ -63,41 +60,34 @@ const AnalysisConsumption = ({ } } - // Disconnected + empty fluids to show in AnalysisConsumptionRow - const disconnectedFluidTypes: FluidType[] = [ - FluidType.ELECTRICITY, - FluidType.WATER, - FluidType.GAS, - ].filter(fluidType => !fluidTypes.includes(fluidType)) - const emptyFluidTypes: FluidType[] = [] - - for (let i = 0; i < performanceIndicators.length; i++) { - if (!performanceIndicators[i]?.value && fluidTypes[i]) { - emptyFluidTypes.push(fluidTypes[i]) + if (performanceIndicators.length === 0) { + // If no indicators add all fluids for component placeholder + emptyFluidTypes.push(FluidType.ELECTRICITY, FluidType.WATER, FluidType.GAS) + } else { + for (let i = 0; i < performanceIndicators.length; i++) { + if (!performanceIndicators[i]?.value) { + emptyFluidTypes.push(i) + } } } const getTotalValueWithConnectedFluids = useCallback( (monthlyForecast: MonthlyForecast) => { - if (fluidTypes.length === 3) { + if (performanceIndicators.length === 3) { setHomePriceConsumption(monthlyForecast.totalValue) } else { let totalPrice = 0 - fluidTypes.forEach(fluid => { - if (monthlyForecast.fluidForecast[fluid].value) - totalPrice += monthlyForecast.fluidForecast[fluid].value + performanceIndicators.forEach((fluid, index) => { + if (monthlyForecast.fluidForecast[index].value) + totalPrice += monthlyForecast.fluidForecast[index].value }) setHomePriceConsumption(totalPrice) } }, - [fluidTypes] + [performanceIndicators] ) - const goToForm = () => { - navigate('/profileType') - } - useEffect(() => { let subscribed = true async function loadAverageConsumption() { @@ -144,7 +134,7 @@ const AnalysisConsumption = ({ </div> <Button aria-label={t('analysis.accessibility.button_go_to_profil')} - onClick={goToForm} + onClick={() => navigate('/profileType')} classes={{ root: 'btn-highlight', label: 'text-18-bold', @@ -165,55 +155,42 @@ const AnalysisConsumption = ({ <div className="analysis-graph"> {isLoading ? ( <div className="loader-container"> - <Loader color="elec" /> + <Loader /> </div> ) : ( <> <div className="consumption-title text-20-bold"> <div className="user-title">{t('analysis.user_consumption')}</div> - <div className={`average-title`}>{t(`analysis.comparison`)}</div> - </div> - <div className="consumption-price"> - <AnalysisConsumptionRow - fluid={FluidType.MULTIFLUID} - userPriceConsumption={userPriceConsumption} - homePriceConsumption={homePriceConsumption} - performanceValue={null} - forecast={forecast} - connected={fluidTypes.length > 0} - noData={false} - /> + <div /> + <div className="average-title">{t(`analysis.comparison`)}</div> </div> - {fluidTypes.map( - fluid => - Boolean(performanceIndicators[fluid]?.value) && ( - <AnalysisConsumptionRow - key={fluid} - fluid={fluid} + <ProfileComparatorRow + fluid={FluidType.MULTIFLUID} + userPriceConsumption={userPriceConsumption} + homePriceConsumption={homePriceConsumption} + performanceValue={null} + forecast={forecast} + connected={performanceIndicators.length > 0} + noData={false} + /> + {performanceIndicators.map( + (indicator, index) => + indicator.value && ( + <ProfileComparatorRow + key={index} + fluid={index} userPriceConsumption={userPriceConsumption} homePriceConsumption={homePriceConsumption} - performanceValue={performanceIndicators[fluid].value} + performanceValue={indicator.value} forecast={forecast} connected={true} noData={false} /> ) )} - {fluidTypes.length < 3 && <hr className="consumption-sep" />} - {disconnectedFluidTypes.map(fluid => ( - <AnalysisConsumptionRow - key={fluid} - fluid={fluid} - userPriceConsumption={userPriceConsumption} - homePriceConsumption={homePriceConsumption} - performanceValue={null} - forecast={forecast} - connected={false} - noData={false} - /> - ))} + {emptyFluidTypes.length > 0 && <hr className="consumption-sep" />} {emptyFluidTypes.map(fluid => ( - <AnalysisConsumptionRow + <ProfileComparatorRow key={fluid} fluid={fluid} userPriceConsumption={userPriceConsumption} @@ -273,7 +250,7 @@ const AnalysisConsumption = ({ {profile.isProfileTypeCompleted && ( <Button aria-label={t('analysis.accessibility.button_go_to_profil')} - onClick={goToForm} + onClick={() => navigate('/profileType')} classes={{ root: 'btn-secondary-negative', label: 'text-16-normal', @@ -292,4 +269,4 @@ const AnalysisConsumption = ({ ) } -export default AnalysisConsumption +export default ProfileComparator diff --git a/src/components/Analysis/AnalysisConsumptionRow.spec.tsx b/src/components/Analysis/ProfileComparator/ProfileComparatorRow.spec.tsx similarity index 90% rename from src/components/Analysis/AnalysisConsumptionRow.spec.tsx rename to src/components/Analysis/ProfileComparator/ProfileComparatorRow.spec.tsx index b147d31cf440dafc9f9cd73c09e4a28cd448649f..bf62f78673d796a587fb730f9716389a48084137 100644 --- a/src/components/Analysis/AnalysisConsumptionRow.spec.tsx +++ b/src/components/Analysis/ProfileComparator/ProfileComparatorRow.spec.tsx @@ -1,19 +1,9 @@ -import { FluidType } from 'enum/fluid.enum' +import { FluidType } from 'enums' import { mount } from 'enzyme' import { MonthlyForecast } from 'models' import React from 'react' -import { mockMonthlyForecastJanuaryTestProfile1 } from '../../../tests/__mocks__/profileType.mock' -import AnalysisConsumptionRow from './AnalysisConsumptionRow' - -jest.mock('cozy-ui/transpiled/react/I18n', () => { - return { - useI18n: jest.fn(() => { - return { - t: (str: string) => str, - } - }), - } -}) +import { mockMonthlyForecastJanuaryTestProfile1 } from 'tests/__mocks__/profileType.mock' +import ProfileComparatorRow from './ProfileComparatorRow' describe('AnalysisConsumptionRow component', () => { const userPriceConsumption = 20 @@ -26,7 +16,7 @@ describe('AnalysisConsumptionRow component', () => { it('should be rendered correctly for Multifluid and at least fluid connected', async () => { const mockPerformanceValue: number | null = null const wrapper = mount( - <AnalysisConsumptionRow + <ProfileComparatorRow fluid={FluidType.MULTIFLUID} userPriceConsumption={userPriceConsumption} homePriceConsumption={homePriceConsumption} @@ -47,7 +37,7 @@ describe('AnalysisConsumptionRow component', () => { const mockPerformanceValue: number | null = null const mockConnected = false const wrapper = mount( - <AnalysisConsumptionRow + <ProfileComparatorRow fluid={FluidType.MULTIFLUID} userPriceConsumption={userPriceConsumption} homePriceConsumption={homePriceConsumption} @@ -58,7 +48,7 @@ describe('AnalysisConsumptionRow component', () => { /> ) expect(wrapper.find('.consumption-multifluid').exists()).toBeTruthy() - expect(wrapper.find('.price').first().text()).toBe('analysis.not_connected') + expect(wrapper.find('.price').first().text()).toBe('analysis.no_data') expect(wrapper.find('.price').last().text()).toBe('18,00 €') expect(wrapper.find('.graph').exists()).toBeFalsy() expect(wrapper.find('.not-connected').exists()).toBeTruthy() @@ -66,7 +56,7 @@ describe('AnalysisConsumptionRow component', () => { it('should be rendered correctly for singleFluid connected for average', async () => { const wrapper = mount( - <AnalysisConsumptionRow + <ProfileComparatorRow fluid={FluidType.ELECTRICITY} userPriceConsumption={userPriceConsumption} homePriceConsumption={homePriceConsumption} @@ -90,7 +80,7 @@ describe('AnalysisConsumptionRow component', () => { it('should be rendered correctly for singleFluid not connected', async () => { const mockConnected = false const wrapper = mount( - <AnalysisConsumptionRow + <ProfileComparatorRow fluid={FluidType.ELECTRICITY} userPriceConsumption={userPriceConsumption} homePriceConsumption={homePriceConsumption} @@ -101,7 +91,7 @@ describe('AnalysisConsumptionRow component', () => { /> ) expect(wrapper.find('.consumption-electricity').exists()).toBeTruthy() - expect(wrapper.find('.price').first().text()).toBe('analysis.not_connected') + expect(wrapper.find('.price').first().text()).toBe('analysis.no_data') expect(wrapper.find('.price').last().text()).toBe( '4340 FLUID.ELECTRICITY.UNIT' ) @@ -112,7 +102,7 @@ describe('AnalysisConsumptionRow component', () => { it('should be rendered correctly for singleFluid with none performance value', async () => { const mockPerformanceValue: number | null = null const wrapper = mount( - <AnalysisConsumptionRow + <ProfileComparatorRow fluid={FluidType.ELECTRICITY} userPriceConsumption={userPriceConsumption} homePriceConsumption={homePriceConsumption} @@ -146,7 +136,7 @@ describe('AnalysisConsumptionRow component', () => { ], } const wrapper = mount( - <AnalysisConsumptionRow + <ProfileComparatorRow fluid={FluidType.ELECTRICITY} userPriceConsumption={userPriceConsumption} homePriceConsumption={homePriceConsumption} diff --git a/src/components/Analysis/AnalysisConsumptionRow.tsx b/src/components/Analysis/ProfileComparator/ProfileComparatorRow.tsx similarity index 87% rename from src/components/Analysis/AnalysisConsumptionRow.tsx rename to src/components/Analysis/ProfileComparator/ProfileComparatorRow.tsx index 451ffab1b3c804f7d2a60ca3730a231cb4175761..adea63d2cefc1d774c9a6ab354ec8227e64d318e 100644 --- a/src/components/Analysis/AnalysisConsumptionRow.tsx +++ b/src/components/Analysis/ProfileComparator/ProfileComparatorRow.tsx @@ -2,15 +2,15 @@ import EuroIcon from 'assets/icons/ico/euro-icon.svg' import classNames from 'classnames' import StyledIcon from 'components/CommonKit/Icon/StyledIcon' import { useI18n } from 'cozy-ui/transpiled/react/I18n' -import { FluidType } from 'enum/fluid.enum' +import { FluidType } from 'enums' import { MonthlyForecast } from 'models' import React from 'react' import ConverterService from 'services/converter.service' import { getPicto } from 'utils/picto' import { formatNumberValues } from 'utils/utils' -import './analysisConsumptionRow.scss' +import './profileComparatorRow.scss' -interface AnalysisConsumptionRowProps { +interface ProfileComparatorRowProps { fluid: FluidType userPriceConsumption: number homePriceConsumption: number @@ -20,7 +20,7 @@ interface AnalysisConsumptionRowProps { noData: boolean } -const AnalysisConsumptionRow = ({ +const ProfileComparatorRow = ({ fluid, userPriceConsumption, homePriceConsumption, @@ -28,7 +28,7 @@ const AnalysisConsumptionRow = ({ forecast, connected, noData, -}: AnalysisConsumptionRowProps) => { +}: ProfileComparatorRowProps) => { const { t } = useI18n() const converterService: ConverterService = new ConverterService() const maxPriceConsumption: number = Math.max( @@ -105,18 +105,13 @@ const AnalysisConsumptionRow = ({ } } - let comparaisonText: string - if (connected) { - comparaisonText = formatFluidConsumptionForConso(fluid) - } else if (noData) { - comparaisonText = t(`analysis.no_data_2`) - } else { - comparaisonText = t(`analysis.not_connected`) - } + const comparaisonText = connected + ? formatFluidConsumptionForConso(fluid) + : t(`analysis.no_data`) return ( <div - className={`consumption-${FluidType[fluid].toLowerCase()} analysisRow`} + className={`analysisRow consumption-${FluidType[fluid].toLowerCase()}`} > <div className="user-graph"> <div @@ -126,16 +121,16 @@ const AnalysisConsumptionRow = ({ > {comparaisonText} </div> - <div className="container-graph"> - {connected && ( + {connected && ( + <div className="container-graph"> <div className="graph" style={{ width: getWidthForConso(fluid), }} /> - )} - </div> + </div> + )} </div> <div className="icon-container"> <StyledIcon @@ -143,6 +138,7 @@ const AnalysisConsumptionRow = ({ fluid === FluidType.MULTIFLUID ? EuroIcon : getPicto(fluid, true) } size={22} + className={noData ? 'noData' : ''} /> </div> <div className="average-graph"> @@ -168,4 +164,4 @@ const AnalysisConsumptionRow = ({ ) } -export default AnalysisConsumptionRow +export default ProfileComparatorRow diff --git a/src/components/Analysis/analysisConsumption.scss b/src/components/Analysis/ProfileComparator/profileComparator.scss similarity index 67% rename from src/components/Analysis/analysisConsumption.scss rename to src/components/Analysis/ProfileComparator/profileComparator.scss index 510244040a68e994aa9c95f1512a3a9b9016ac4f..65a183b8473c8bbe3e2f5f743bebdd8d8b813d9a 100644 --- a/src/components/Analysis/analysisConsumption.scss +++ b/src/components/Analysis/ProfileComparator/profileComparator.scss @@ -1,18 +1,19 @@ -@import '../../styles/base/color'; -@import '../../styles/base/breakpoint'; +@import 'src/styles/base/color'; +@import 'src/styles/base/breakpoint'; .analysis-graph { - margin-top: 1.5rem; .consumption-title { display: flex; justify-content: space-between; - margin-bottom: 2rem; - gap: 2rem; + margin-bottom: 1rem; .user-title, .average-title { - flex-basis: 50%; + flex-basis: 45%; + line-height: 3rem; } + .user-title { + line-height: 3rem; text-align: right; color: $multi-color; } @@ -20,9 +21,15 @@ color: $blue-grey; } } + .consumption-sep { + border: 1px solid $grey-dark; + margin: 1rem 0; + } div.expansion-panel-root { border: solid 2px $blue-grey; color: $blue-grey; + margin-block: 0 !important; + box-shadow: 0px 4px 16px 0px $black-shadow; } .accordion-title { font-weight: bold; @@ -58,21 +65,3 @@ margin-top: 0; } } - -.grid-align { - div { - display: grid; - grid-template-columns: 20px 1fr; - grid-gap: 10px; - padding: 0 10px; - align-items: center; - height: 32px; - @media #{$large-phone} { - height: 48px; - } - } - span:first-child { - grid-column: 1; - align-self: center; - } -} diff --git a/src/components/Analysis/analysisConsumptionRow.scss b/src/components/Analysis/ProfileComparator/profileComparatorRow.scss similarity index 79% rename from src/components/Analysis/analysisConsumptionRow.scss rename to src/components/Analysis/ProfileComparator/profileComparatorRow.scss index 5d0171f1f6468965c2e8394e11f0548bbcc808a1..898ca8eb40d1a8541e16051a0fa3d7e9f948ba02 100644 --- a/src/components/Analysis/analysisConsumptionRow.scss +++ b/src/components/Analysis/ProfileComparator/profileComparatorRow.scss @@ -1,15 +1,15 @@ -@import '../../styles/base/color'; -@import '../../styles/base/breakpoint'; +@import 'src/styles/base/color'; +@import 'src/styles/base/breakpoint'; -.consumption-multifluid, -.consumption-electricity, -.consumption-water, -.consumption-gas { +.analysisRow { display: flex; margin-bottom: 1rem; .user-graph { - .graph { - border-radius: 0.35rem 0 0 0.35rem; + .container-graph { + justify-content: flex-end; + .graph { + border-radius: 0.35rem 0 0 0.35rem; + } } .price { &.not-connected { @@ -21,6 +21,18 @@ } } } + .icon-container { + flex-basis: 10%; + display: flex; + justify-content: center; + svg { + align-self: center; + width: 40px; + &.noData { + opacity: 0.6; + } + } + } .average-graph { color: $blue-grey; .price { @@ -34,10 +46,7 @@ } } } -.consumption-sep { - border-top: 1px solid $grey-dark; - margin: 1rem 0; -} + .user-graph, .average-graph { display: flex; @@ -77,27 +86,11 @@ } } } -.analysisRow { - .icon-container { - flex-basis: 10%; - display: flex; - justify-content: center; - svg { - align-self: center; - width: 40px; - } - } -} .container-graph { flex-basis: 50%; display: flex; } -.user-graph { - .container-graph { - justify-content: flex-end; - } -} .price { min-width: 5.25rem; } diff --git a/src/components/Analysis/TotalAnalysisChart.tsx b/src/components/Analysis/TotalAnalysisChart.tsx deleted file mode 100644 index 1166bbc8c9a25d014691ddec1e664168244b33e4..0000000000000000000000000000000000000000 --- a/src/components/Analysis/TotalAnalysisChart.tsx +++ /dev/null @@ -1,107 +0,0 @@ -import { useClient } from 'cozy-client' -import { useI18n } from 'cozy-ui/transpiled/react/I18n' -import Icon from 'cozy-ui/transpiled/react/Icon' -import { FluidType } from 'enum/fluid.enum' -import { TimeStep } from 'enum/timeStep.enum' -import { DataloadValueDetail, TimePeriod } from 'models' -import React, { useEffect, useState } from 'react' -import { useSelector } from 'react-redux' -import ConsumptionDataManager from 'services/consumption.service' -import { AppStore } from 'store' -import { getNavPicto } from 'utils/picto' -import { formatNumberValues } from 'utils/utils' -import PieChart from './PieChart' -import './analysisView.scss' -import './totalAnalysisChart.scss' - -const TotalAnalysisChart = ({ fluidTypes }: { fluidTypes: FluidType[] }) => { - const { analysisMonth } = useSelector( - (state: AppStore) => state.ecolyo.analysis - ) - const [dataLoadValueDetailArray, setDataLoadValueDetailArray] = useState< - DataloadValueDetail[] | null - >(null) - const [totalLoadValue, setTotalLoadValue] = useState<number>(0) - const client = useClient() - const { t } = useI18n() - const arcWidth = 30 - const radius = Math.min(375, innerWidth - 100) - const outerRadius = radius / 2 - const innerRadius = outerRadius - arcWidth - - useEffect(() => { - let subscribed = true - async function getTotalData() { - const timePeriod: TimePeriod = { - startDate: analysisMonth.minus({ month: 1 }).startOf('month'), - endDate: analysisMonth.minus({ month: 1 }).endOf('month'), - } - const consumptionService = new ConsumptionDataManager(client) - const monthTotalData = await consumptionService.getGraphData( - timePeriod, - TimeStep.MONTH, - fluidTypes, - undefined, - undefined, - true - ) - if (monthTotalData?.actualData) { - setDataLoadValueDetailArray(monthTotalData.actualData[0].valueDetail) - setTotalLoadValue(monthTotalData.actualData[0].value) - } - } - if (subscribed) { - getTotalData() - } - return () => { - subscribed = false - } - }, [analysisMonth, client, fluidTypes]) - - return ( - <div - className="totalAnalysis-container" - style={{ - minHeight: radius + 100, - }} - > - <div className="text-24-normal title">{t('analysis_pie.total')}</div> - {dataLoadValueDetailArray && ( - <PieChart - dataloadValueDetailArray={dataLoadValueDetailArray} - totalValue={totalLoadValue} - width={radius} - height={radius} - innerRadius={innerRadius} - outerRadius={outerRadius} - currentAnalysisDate={analysisMonth} - /> - )} - {dataLoadValueDetailArray && fluidTypes.length > 1 && ( - <div className="total-card-container"> - {dataLoadValueDetailArray.map((dataload, index) => { - return ( - <div key={index} className="total-card"> - <div className="text-18-bold fluidconso"> - {dataload.value !== -1 - ? `${formatNumberValues(dataload.value)} €` - : '--- €'} - </div> - <Icon - className="euro-fluid-icon" - icon={getNavPicto(index, true, true)} - size={38} - /> - <div className="text-16-normal"> - {t('FLUID.' + FluidType[index] + '.LABEL')} - </div> - </div> - ) - })} - </div> - )} - </div> - ) -} - -export default TotalAnalysisChart diff --git a/src/components/Analysis/TotalAnalysisChart/PieChart.spec.tsx b/src/components/Analysis/TotalAnalysisChart/PieChart.spec.tsx new file mode 100644 index 0000000000000000000000000000000000000000..c866cabdfc46bb9b18fb06bc7a13fe3ceb9305ca --- /dev/null +++ b/src/components/Analysis/TotalAnalysisChart/PieChart.spec.tsx @@ -0,0 +1,27 @@ +import { DataloadState } from 'enums' +import { mount } from 'enzyme' +import toJson from 'enzyme-to-json' +import { DataloadValueDetail } from 'models' +import React from 'react' +import PieChart from './PieChart' + +describe('PieChart component', () => { + const mockDataloadValueDetailArray: DataloadValueDetail[] = [ + { value: 10, state: DataloadState.VALID }, + { value: 20, state: DataloadState.VALID }, + { value: 30, state: DataloadState.VALID }, + ] + it('should be rendered correctly', () => { + const wrapper = mount( + <PieChart + radius={300} + outerRadius={300} + innerRadius={300} + dataloadValueDetailArray={mockDataloadValueDetailArray} + > + child with value and text to render + </PieChart> + ) + expect(toJson(wrapper)).toMatchSnapshot() + }) +}) diff --git a/src/components/Analysis/PieChart.tsx b/src/components/Analysis/TotalAnalysisChart/PieChart.tsx similarity index 56% rename from src/components/Analysis/PieChart.tsx rename to src/components/Analysis/TotalAnalysisChart/PieChart.tsx index 5a215454d830a7bd54e8a22dd65b6172260ff7ee..ad96a96122221cf037ac4e0ab48d0bb088e6e7cb 100644 --- a/src/components/Analysis/PieChart.tsx +++ b/src/components/Analysis/TotalAnalysisChart/PieChart.tsx @@ -1,39 +1,26 @@ -import EstimatedConsumptionModal from 'components/ConsumptionVisualizer/EstimatedConsumptionModal' -import { useI18n } from 'cozy-ui/transpiled/react/I18n' import * as d3 from 'd3' -import { DateTime } from 'luxon' import { DataloadValueDetail } from 'models' -import React, { useCallback, useEffect, useRef, useState } from 'react' -import { formatNumberValues, getMonthNameWithPrep } from 'utils/utils' +import React, { useEffect, useRef } from 'react' import './totalAnalysisChart.scss' interface PieProps { innerRadius: number outerRadius: number dataloadValueDetailArray: DataloadValueDetail[] - width: number - height: number - totalValue: number - currentAnalysisDate: DateTime + radius: number + children: React.ReactNode } const PieChart = ({ innerRadius, outerRadius, dataloadValueDetailArray, - width, - height, - totalValue, - currentAnalysisDate, + radius, + children, }: PieProps) => { const ref = useRef(null) - const { t } = useI18n() const createPie = d3.pie().sort(null) const arcWidth = outerRadius - innerRadius - const [openEstimationModal, setOpenEstimationModal] = useState<boolean>(false) - const toggleEstimationModal = useCallback(() => { - setOpenEstimationModal(prev => !prev) - }, []) useEffect(() => { const dataloadArray: number[] = dataloadValueDetailArray.map( @@ -70,11 +57,11 @@ const PieChart = ({ <div className="pie-container" style={{ - width: width, - height: height, + width: radius, + height: radius, }} > - <svg width={width} height={height}> + <svg width={radius} height={radius}> <defs> <filter id="glow" height="300%" width="300%" x="-75%" y="-75%"> <feGaussianBlur stdDeviation="10" result="coloredBlur" /> @@ -89,41 +76,23 @@ const PieChart = ({ <div className="pie-center" style={{ - width: width - arcWidth, - height: height - arcWidth, + width: radius - arcWidth, + height: radius - arcWidth, top: arcWidth / 2, left: arcWidth - arcWidth / 2, }} > - <div className="text-36-bold"> - {formatNumberValues(totalValue)} - <span className="euro-unit">{`${t('FLUID.MULTIFLUID.UNIT')}`}</span> - </div> - <div className="text-16-normal date"> - {t('analysis_pie.month') + - getMonthNameWithPrep(currentAnalysisDate.minus({ month: 1 }))} - </div> - <div - className="text-14-normal estimation-text" - onClick={toggleEstimationModal} - > - <span className="estimated">{t('analysis_pie.estimation')}</span> - <span className="estimated">{t('analysis_pie.estimation2')}</span> - </div> + {children} <div className="circle" style={{ - width: width - arcWidth * 2, - height: height - arcWidth * 2, + width: radius - arcWidth * 2, + height: radius - arcWidth * 2, top: arcWidth / 2, left: arcWidth - arcWidth / 2, }} /> </div> - <EstimatedConsumptionModal - open={openEstimationModal} - handleCloseClick={toggleEstimationModal} - /> </div> ) } diff --git a/src/components/Analysis/TotalAnalysisChart.spec.tsx b/src/components/Analysis/TotalAnalysisChart/TotalAnalysisChart.spec.tsx similarity index 61% rename from src/components/Analysis/TotalAnalysisChart.spec.tsx rename to src/components/Analysis/TotalAnalysisChart/TotalAnalysisChart.spec.tsx index bff43f5a94771ea8312207b0fc5a8cec6e91d2d2..4bcfcc3a643b781db65fc4cb74f4a0d43d3d1f1e 100644 --- a/src/components/Analysis/TotalAnalysisChart.spec.tsx +++ b/src/components/Analysis/TotalAnalysisChart/TotalAnalysisChart.spec.tsx @@ -1,57 +1,51 @@ -import { DataloadState } from 'enum/dataload.enum' -import { FluidType } from 'enum/fluid.enum' +import { DataloadState, FluidType } from 'enums' import { mount } from 'enzyme' import toJson from 'enzyme-to-json' import { DateTime } from 'luxon' import { Datachart } from 'models' import React from 'react' import { Provider } from 'react-redux' -import configureStore from 'redux-mock-store' -import { graphMonthData } from '../../../tests/__mocks__/chartData.mock' -import { mockAnalysisState } from '../../../tests/__mocks__/store' -import { waitForComponentToPaint } from '../../../tests/__mocks__/testUtils' +import { graphMonthData } from 'tests/__mocks__/chartData.mock' +import { createMockEcolyoStore } from 'tests/__mocks__/store' +import { waitForComponentToPaint } from 'tests/__mocks__/testUtils' import TotalAnalysisChart from './TotalAnalysisChart' -jest.mock('cozy-ui/transpiled/react/I18n', () => { - return { - useI18n: jest.fn(() => { - return { - t: (str: string) => str, - } - }), - } -}) -const mockgetGraphData = jest.fn() +const mockGetGraphData = jest.fn() jest.mock('services/consumption.service', () => { - return jest.fn(() => { - return { - getGraphData: mockgetGraphData, - } - }) + return jest.fn(() => ({ + getGraphData: mockGetGraphData, + })) }) -jest.mock('components/Analysis/PieChart', () => 'mock-piechart') +jest.mock( + 'components/Analysis/TotalAnalysisChart/PieChart', + () => 'mock-piechart' +) +jest.mock( + 'components/ConsumptionVisualizer/EstimatedConsumptionModal', + () => 'mock-estimatedmodal' +) -const mockStore = configureStore([]) -const store = mockStore({ - ecolyo: { - analysis: mockAnalysisState, - }, -}) describe('TotalAnalysisChart component', () => { - it('should be rendered correctly', () => { + const store = createMockEcolyoStore() + it('should be rendered correctly', async () => { const wrapper = mount( <Provider store={store}> - <TotalAnalysisChart fluidTypes={[FluidType.ELECTRICITY]} /> + <TotalAnalysisChart fluidsWithData={[FluidType.ELECTRICITY]} /> </Provider> ) + await waitForComponentToPaint(wrapper) expect(toJson(wrapper)).toMatchSnapshot() }) it('should render several fluids and display month data', async () => { - mockgetGraphData.mockResolvedValueOnce(graphMonthData) + mockGetGraphData.mockResolvedValue(graphMonthData) const wrapper = mount( <Provider store={store}> <TotalAnalysisChart - fluidTypes={[FluidType.ELECTRICITY, FluidType.WATER, FluidType.GAS]} + fluidsWithData={[ + FluidType.ELECTRICITY, + FluidType.WATER, + FluidType.GAS, + ]} /> </Provider> ) @@ -72,11 +66,11 @@ describe('TotalAnalysisChart component', () => { ], comparisonData: null, } - mockgetGraphData.mockResolvedValueOnce(emptyData) + mockGetGraphData.mockResolvedValue(emptyData) const wrapper = mount( <Provider store={store}> <TotalAnalysisChart - fluidTypes={[FluidType.ELECTRICITY, FluidType.WATER]} + fluidsWithData={[FluidType.ELECTRICITY, FluidType.WATER]} /> </Provider> ) @@ -97,10 +91,10 @@ describe('TotalAnalysisChart component', () => { ], comparisonData: null, } - mockgetGraphData.mockResolvedValueOnce(emptyData) + mockGetGraphData.mockResolvedValue(emptyData) const wrapper = mount( <Provider store={store}> - <TotalAnalysisChart fluidTypes={[FluidType.ELECTRICITY]} /> + <TotalAnalysisChart fluidsWithData={[FluidType.ELECTRICITY]} /> </Provider> ) await waitForComponentToPaint(wrapper) diff --git a/src/components/Analysis/TotalAnalysisChart/TotalAnalysisChart.tsx b/src/components/Analysis/TotalAnalysisChart/TotalAnalysisChart.tsx new file mode 100644 index 0000000000000000000000000000000000000000..f2b7e412e65a908505e1c4a28341377f72bde2d7 --- /dev/null +++ b/src/components/Analysis/TotalAnalysisChart/TotalAnalysisChart.tsx @@ -0,0 +1,152 @@ +import EstimatedConsumptionModal from 'components/ConsumptionVisualizer/EstimatedConsumptionModal' +import Loader from 'components/Loader/Loader' +import { useClient } from 'cozy-client' +import { useI18n } from 'cozy-ui/transpiled/react/I18n' +import Icon from 'cozy-ui/transpiled/react/Icon' +import { FluidType, TimeStep } from 'enums' +import { DataloadValueDetail, TimePeriod } from 'models' +import React, { useEffect, useState } from 'react' +import ConsumptionDataManager from 'services/consumption.service' +import { useAppSelector } from 'store/hooks' +import { getNavPicto } from 'utils/picto' +import { formatNumberValues, getMonthNameWithPrep } from 'utils/utils' +import PieChart from './PieChart' +import './totalAnalysisChart.scss' + +const TotalAnalysisChart = ({ + fluidsWithData, +}: { + fluidsWithData: FluidType[] +}) => { + const { t } = useI18n() + const client = useClient() + const { analysisMonth } = useAppSelector(state => state.ecolyo.analysis) + const [isLoading, setIsLoading] = useState(true) + const [dataLoadValueDetailArray, setDataLoadValueDetailArray] = useState< + DataloadValueDetail[] | null + >(null) + const [totalLoadValue, setTotalLoadValue] = useState<number>(0) + const [openEstimationModal, setOpenEstimationModal] = useState<boolean>(false) + const arcWidth = 30 + const radius = Math.min(375, innerWidth - 100) + const outerRadius = radius / 2 + const innerRadius = outerRadius - arcWidth + + useEffect(() => { + let subscribed = true + async function getTotalData() { + const timePeriod: TimePeriod = { + startDate: analysisMonth.minus({ month: 1 }).startOf('month'), + endDate: analysisMonth.minus({ month: 1 }).endOf('month'), + } + const consumptionService = new ConsumptionDataManager(client) + const monthTotalData = await consumptionService.getGraphData( + timePeriod, + TimeStep.MONTH, + fluidsWithData, + undefined, + undefined, + true + ) + if (monthTotalData?.actualData) { + setDataLoadValueDetailArray(monthTotalData.actualData[0].valueDetail) + setTotalLoadValue(monthTotalData.actualData[0].value) + } + setIsLoading(false) + } + if (subscribed) { + getTotalData() + } + return () => { + subscribed = false + } + }, [analysisMonth, client, fluidsWithData]) + + const emptyPieChart = () => ( + <PieChart + dataloadValueDetailArray={[]} + radius={radius} + innerRadius={innerRadius} + outerRadius={outerRadius} + > + <div className="text-36-bold"> + {formatNumberValues(0)} + <span className="euro-unit">{t('FLUID.MULTIFLUID.UNIT')}</span> + </div> + <div className="text-20-bold no_data">{t('analysis.no_data')}</div> + </PieChart> + ) + + return ( + <> + <div + className="totalAnalysis-container" + style={{ + minHeight: radius + 100, + }} + > + <div className="text-24-normal title">{t('analysis_pie.total')}</div> + + {isLoading && <Loader />} + {!isLoading && !dataLoadValueDetailArray && emptyPieChart()} + {!isLoading && dataLoadValueDetailArray && ( + <> + <PieChart + dataloadValueDetailArray={dataLoadValueDetailArray} + radius={radius} + innerRadius={innerRadius} + outerRadius={outerRadius} + > + <div className="text-36-bold"> + {formatNumberValues(totalLoadValue)} + <span className="euro-unit">{t('FLUID.MULTIFLUID.UNIT')}</span> + </div> + <div className="text-16-normal date"> + {t('analysis_pie.month') + + getMonthNameWithPrep(analysisMonth.minus({ month: 1 }))} + </div> + <div + className="text-14-normal estimation-text" + onClick={() => setOpenEstimationModal(true)} + > + <span + className="estimated" + dangerouslySetInnerHTML={{ + __html: t('analysis_pie.estimation'), + }} + /> + </div> + </PieChart> + <EstimatedConsumptionModal + open={openEstimationModal} + handleCloseClick={() => setOpenEstimationModal(false)} + /> + {dataLoadValueDetailArray && fluidsWithData.length > 1 && ( + <div className="total-card-container"> + {dataLoadValueDetailArray.map((dataload, index) => ( + <div key={index} className="total-card"> + <div className="text-18-bold fluidconso"> + {dataload.value !== -1 + ? `${formatNumberValues(dataload.value)} €` + : '--- €'} + </div> + <Icon + className="euro-fluid-icon" + icon={getNavPicto(index, true, true)} + size={38} + /> + <div className="text-16-normal"> + {t(`FLUID.${FluidType[index]}.LABEL`)} + </div> + </div> + ))} + </div> + )} + </> + )} + </div> + </> + ) +} + +export default TotalAnalysisChart diff --git a/src/components/Analysis/TotalAnalysisChart/__snapshots__/PieChart.spec.tsx.snap b/src/components/Analysis/TotalAnalysisChart/__snapshots__/PieChart.spec.tsx.snap new file mode 100644 index 0000000000000000000000000000000000000000..03b1ba56bc4c61e0cb75e8ac3c6e4ce7d50fc623 --- /dev/null +++ b/src/components/Analysis/TotalAnalysisChart/__snapshots__/PieChart.spec.tsx.snap @@ -0,0 +1,90 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`PieChart component should be rendered correctly 1`] = ` +<PieChart + dataloadValueDetailArray={ + Array [ + Object { + "state": "VALID", + "value": 10, + }, + Object { + "state": "VALID", + "value": 20, + }, + Object { + "state": "VALID", + "value": 30, + }, + ] + } + innerRadius={300} + outerRadius={300} + radius={300} +> + <div + className="pie-container" + style={ + Object { + "height": 300, + "width": 300, + } + } + > + <svg + height={300} + width={300} + > + <defs> + <filter + height="300%" + id="glow" + width="300%" + x="-75%" + y="-75%" + > + <feGaussianBlur + result="coloredBlur" + stdDeviation="10" + /> + <feMerge> + <feMergeNode + in="coloredBlur" + /> + <feMergeNode + in="SourceGraphic" + /> + </feMerge> + </filter> + </defs> + <g + transform="translate(300 300)" + /> + </svg> + <div + className="pie-center" + style={ + Object { + "height": 300, + "left": 0, + "top": 0, + "width": 300, + } + } + > + child with value and text to render + <div + className="circle" + style={ + Object { + "height": 300, + "left": 0, + "top": 0, + "width": 300, + } + } + /> + </div> + </div> +</PieChart> +`; diff --git a/src/components/Analysis/__snapshots__/TotalAnalysisChart.spec.tsx.snap b/src/components/Analysis/TotalAnalysisChart/__snapshots__/TotalAnalysisChart.spec.tsx.snap similarity index 58% rename from src/components/Analysis/__snapshots__/TotalAnalysisChart.spec.tsx.snap rename to src/components/Analysis/TotalAnalysisChart/__snapshots__/TotalAnalysisChart.spec.tsx.snap index c5f2907e27ed682ca5092e5687f7db37e7b2d7b5..9daddac9757bf7b5981c9b335677645cebeb6137 100644 --- a/src/components/Analysis/__snapshots__/TotalAnalysisChart.spec.tsx.snap +++ b/src/components/Analysis/TotalAnalysisChart/__snapshots__/TotalAnalysisChart.spec.tsx.snap @@ -14,7 +14,7 @@ exports[`TotalAnalysisChart component should be rendered correctly 1`] = ` } > <TotalAnalysisChart - fluidTypes={ + fluidsWithData={ Array [ 0, ] @@ -33,6 +33,28 @@ exports[`TotalAnalysisChart component should be rendered correctly 1`] = ` > analysis_pie.total </div> + <mock-piechart + dataloadValueDetailArray={Array []} + innerRadius={157.5} + outerRadius={187.5} + radius={375} + > + <div + className="text-36-bold" + > + 0,00 + <span + className="euro-unit" + > + FLUID.MULTIFLUID.UNIT + </span> + </div> + <div + className="text-20-bold no_data" + > + analysis.no_data + </div> + </mock-piechart> </div> </TotalAnalysisChart> </Provider> diff --git a/src/components/Analysis/totalAnalysisChart.scss b/src/components/Analysis/TotalAnalysisChart/totalAnalysisChart.scss similarity index 90% rename from src/components/Analysis/totalAnalysisChart.scss rename to src/components/Analysis/TotalAnalysisChart/totalAnalysisChart.scss index 348f80301afc486e3072d34f954603d51a093bb5..efe2023b8a502e6598304d6322a9a460b913d65b 100644 --- a/src/components/Analysis/totalAnalysisChart.scss +++ b/src/components/Analysis/TotalAnalysisChart/totalAnalysisChart.scss @@ -1,10 +1,10 @@ -@import '../../styles/base/color'; -@import '../../styles/base/breakpoint'; -@import '../../styles/base/z-index'; +@import 'src/styles/base/color'; +@import 'src/styles/base/breakpoint'; +@import 'src/styles/base/z-index'; .totalAnalysis-container { display: flex; - justify-content: center; + justify-content: space-around; flex-direction: column; color: white; .title { @@ -12,6 +12,10 @@ color: $grey-bright; margin-bottom: 1.5rem; } + .no_data { + color: $grey-bright; + margin-top: 1rem; + } .pie-container { text-align: center; position: relative; diff --git a/src/components/Analysis/__snapshots__/MonthlyAnalysis.spec.tsx.snap b/src/components/Analysis/__snapshots__/MonthlyAnalysis.spec.tsx.snap index 58f132c9cc13dd48fdcb95e671b7b7eeffc0fada..e6d74e926365b96a4f8ac6ff342c75b182eb9806 100644 --- a/src/components/Analysis/__snapshots__/MonthlyAnalysis.spec.tsx.snap +++ b/src/components/Analysis/__snapshots__/MonthlyAnalysis.spec.tsx.snap @@ -2,22 +2,631 @@ exports[`MonthlyAnalysis component should be rendered correctly 1`] = ` <BrowserRouter> - <Provider - store={ + <Router + location={ Object { - "clearActions": [Function], - "dispatch": [Function], - "getActions": [Function], - "getState": [Function], - "replaceReducer": [Function], - "subscribe": [Function], + "hash": "", + "key": "default", + "pathname": "/", + "search": "", + "state": null, + } + } + navigationType="POP" + navigator={ + Object { + "action": "POP", + "createHref": [Function], + "encodeLocation": [Function], + "go": [Function], + "listen": [Function], + "location": Object { + "hash": "", + "key": "default", + "pathname": "/", + "search": "", + "state": null, + }, + "push": [Function], + "replace": [Function], } } > - <MonthlyAnalysis - saveLastScrollPosition={[MockFunction]} - scrollPosition={0} - /> - </Provider> + <Provider + store={ + Object { + "clearActions": [Function], + "dispatch": [Function], + "getActions": [Function], + "getState": [Function], + "replaceReducer": [Function], + "subscribe": [Function], + } + } + > + <MonthlyAnalysis + saveLastScrollPosition={[MockFunction]} + scrollPosition={0} + > + <NoAnalysisModal + onClose={[Function]} + open={false} + > + <WithStyles(ForwardRef(Dialog)) + aria-labelledby="accessibility-title" + classes={ + Object { + "paper": "modal-paper", + "root": "modal-root", + } + } + onClose={[Function]} + open={false} + > + <ForwardRef(Dialog) + aria-labelledby="accessibility-title" + classes={ + Object { + "container": "MuiDialog-container", + "paper": "MuiDialog-paper modal-paper", + "paperFullScreen": "MuiDialog-paperFullScreen", + "paperFullWidth": "MuiDialog-paperFullWidth", + "paperScrollBody": "MuiDialog-paperScrollBody", + "paperScrollPaper": "MuiDialog-paperScrollPaper", + "paperWidthFalse": "MuiDialog-paperWidthFalse", + "paperWidthLg": "MuiDialog-paperWidthLg", + "paperWidthMd": "MuiDialog-paperWidthMd", + "paperWidthSm": "MuiDialog-paperWidthSm", + "paperWidthXl": "MuiDialog-paperWidthXl", + "paperWidthXs": "MuiDialog-paperWidthXs", + "root": "MuiDialog-root modal-root", + "scrollBody": "MuiDialog-scrollBody", + "scrollPaper": "MuiDialog-scrollPaper", + } + } + onClose={[Function]} + open={false} + > + <ForwardRef(Modal) + BackdropComponent={ + Object { + "$$typeof": Symbol(react.forward_ref), + "Naked": Object { + "$$typeof": Symbol(react.forward_ref), + "propTypes": Object { + "children": [Function], + "className": [Function], + "classes": [Function], + "invisible": [Function], + "open": [Function], + "transitionDuration": [Function], + }, + "render": [Function], + }, + "displayName": "WithStyles(ForwardRef(Backdrop))", + "options": Object { + "defaultTheme": Object { + "breakpoints": Object { + "between": [Function], + "down": [Function], + "keys": Array [ + "xs", + "sm", + "md", + "lg", + "xl", + ], + "only": [Function], + "up": [Function], + "values": Object { + "lg": 1280, + "md": 960, + "sm": 600, + "xl": 1920, + "xs": 0, + }, + "width": [Function], + }, + "direction": "ltr", + "mixins": Object { + "gutters": [Function], + "toolbar": Object { + "@media (min-width:0px) and (orientation: landscape)": Object { + "minHeight": 48, + }, + "@media (min-width:600px)": Object { + "minHeight": 64, + }, + "minHeight": 56, + }, + }, + "overrides": Object {}, + "palette": Object { + "action": Object { + "activatedOpacity": 0.12, + "active": "rgba(0, 0, 0, 0.54)", + "disabled": "rgba(0, 0, 0, 0.26)", + "disabledBackground": "rgba(0, 0, 0, 0.12)", + "disabledOpacity": 0.38, + "focus": "rgba(0, 0, 0, 0.12)", + "focusOpacity": 0.12, + "hover": "rgba(0, 0, 0, 0.04)", + "hoverOpacity": 0.04, + "selected": "rgba(0, 0, 0, 0.08)", + "selectedOpacity": 0.08, + }, + "augmentColor": [Function], + "background": Object { + "default": "#fafafa", + "paper": "#fff", + }, + "common": Object { + "black": "#000", + "white": "#fff", + }, + "contrastThreshold": 3, + "divider": "rgba(0, 0, 0, 0.12)", + "error": Object { + "contrastText": "#fff", + "dark": "#d32f2f", + "light": "#e57373", + "main": "#f44336", + }, + "getContrastText": [Function], + "grey": Object { + "100": "#f5f5f5", + "200": "#eeeeee", + "300": "#e0e0e0", + "400": "#bdbdbd", + "50": "#fafafa", + "500": "#9e9e9e", + "600": "#757575", + "700": "#616161", + "800": "#424242", + "900": "#212121", + "A100": "#d5d5d5", + "A200": "#aaaaaa", + "A400": "#303030", + "A700": "#616161", + }, + "info": Object { + "contrastText": "#fff", + "dark": "#1976d2", + "light": "#64b5f6", + "main": "#2196f3", + }, + "primary": Object { + "contrastText": "#fff", + "dark": "#303f9f", + "light": "#7986cb", + "main": "#3f51b5", + }, + "secondary": Object { + "contrastText": "#fff", + "dark": "#c51162", + "light": "#ff4081", + "main": "#f50057", + }, + "success": Object { + "contrastText": "rgba(0, 0, 0, 0.87)", + "dark": "#388e3c", + "light": "#81c784", + "main": "#4caf50", + }, + "text": Object { + "disabled": "rgba(0, 0, 0, 0.38)", + "hint": "rgba(0, 0, 0, 0.38)", + "primary": "rgba(0, 0, 0, 0.87)", + "secondary": "rgba(0, 0, 0, 0.54)", + }, + "tonalOffset": 0.2, + "type": "light", + "warning": Object { + "contrastText": "rgba(0, 0, 0, 0.87)", + "dark": "#f57c00", + "light": "#ffb74d", + "main": "#ff9800", + }, + }, + "props": Object {}, + "shadows": Array [ + "none", + "0px 2px 1px -1px rgba(0,0,0,0.2),0px 1px 1px 0px rgba(0,0,0,0.14),0px 1px 3px 0px rgba(0,0,0,0.12)", + "0px 3px 1px -2px rgba(0,0,0,0.2),0px 2px 2px 0px rgba(0,0,0,0.14),0px 1px 5px 0px rgba(0,0,0,0.12)", + "0px 3px 3px -2px rgba(0,0,0,0.2),0px 3px 4px 0px rgba(0,0,0,0.14),0px 1px 8px 0px rgba(0,0,0,0.12)", + "0px 2px 4px -1px rgba(0,0,0,0.2),0px 4px 5px 0px rgba(0,0,0,0.14),0px 1px 10px 0px rgba(0,0,0,0.12)", + "0px 3px 5px -1px rgba(0,0,0,0.2),0px 5px 8px 0px rgba(0,0,0,0.14),0px 1px 14px 0px rgba(0,0,0,0.12)", + "0px 3px 5px -1px rgba(0,0,0,0.2),0px 6px 10px 0px rgba(0,0,0,0.14),0px 1px 18px 0px rgba(0,0,0,0.12)", + "0px 4px 5px -2px rgba(0,0,0,0.2),0px 7px 10px 1px rgba(0,0,0,0.14),0px 2px 16px 1px rgba(0,0,0,0.12)", + "0px 5px 5px -3px rgba(0,0,0,0.2),0px 8px 10px 1px rgba(0,0,0,0.14),0px 3px 14px 2px rgba(0,0,0,0.12)", + "0px 5px 6px -3px rgba(0,0,0,0.2),0px 9px 12px 1px rgba(0,0,0,0.14),0px 3px 16px 2px rgba(0,0,0,0.12)", + "0px 6px 6px -3px rgba(0,0,0,0.2),0px 10px 14px 1px rgba(0,0,0,0.14),0px 4px 18px 3px rgba(0,0,0,0.12)", + "0px 6px 7px -4px rgba(0,0,0,0.2),0px 11px 15px 1px rgba(0,0,0,0.14),0px 4px 20px 3px rgba(0,0,0,0.12)", + "0px 7px 8px -4px rgba(0,0,0,0.2),0px 12px 17px 2px rgba(0,0,0,0.14),0px 5px 22px 4px rgba(0,0,0,0.12)", + "0px 7px 8px -4px rgba(0,0,0,0.2),0px 13px 19px 2px rgba(0,0,0,0.14),0px 5px 24px 4px rgba(0,0,0,0.12)", + "0px 7px 9px -4px rgba(0,0,0,0.2),0px 14px 21px 2px rgba(0,0,0,0.14),0px 5px 26px 4px rgba(0,0,0,0.12)", + "0px 8px 9px -5px rgba(0,0,0,0.2),0px 15px 22px 2px rgba(0,0,0,0.14),0px 6px 28px 5px rgba(0,0,0,0.12)", + "0px 8px 10px -5px rgba(0,0,0,0.2),0px 16px 24px 2px rgba(0,0,0,0.14),0px 6px 30px 5px rgba(0,0,0,0.12)", + "0px 8px 11px -5px rgba(0,0,0,0.2),0px 17px 26px 2px rgba(0,0,0,0.14),0px 6px 32px 5px rgba(0,0,0,0.12)", + "0px 9px 11px -5px rgba(0,0,0,0.2),0px 18px 28px 2px rgba(0,0,0,0.14),0px 7px 34px 6px rgba(0,0,0,0.12)", + "0px 9px 12px -6px rgba(0,0,0,0.2),0px 19px 29px 2px rgba(0,0,0,0.14),0px 7px 36px 6px rgba(0,0,0,0.12)", + "0px 10px 13px -6px rgba(0,0,0,0.2),0px 20px 31px 3px rgba(0,0,0,0.14),0px 8px 38px 7px rgba(0,0,0,0.12)", + "0px 10px 13px -6px rgba(0,0,0,0.2),0px 21px 33px 3px rgba(0,0,0,0.14),0px 8px 40px 7px rgba(0,0,0,0.12)", + "0px 10px 14px -6px rgba(0,0,0,0.2),0px 22px 35px 3px rgba(0,0,0,0.14),0px 8px 42px 7px rgba(0,0,0,0.12)", + "0px 11px 14px -7px rgba(0,0,0,0.2),0px 23px 36px 3px rgba(0,0,0,0.14),0px 9px 44px 8px rgba(0,0,0,0.12)", + "0px 11px 15px -7px rgba(0,0,0,0.2),0px 24px 38px 3px rgba(0,0,0,0.14),0px 9px 46px 8px rgba(0,0,0,0.12)", + ], + "shape": Object { + "borderRadius": 4, + }, + "spacing": [Function], + "transitions": Object { + "create": [Function], + "duration": Object { + "complex": 375, + "enteringScreen": 225, + "leavingScreen": 195, + "short": 250, + "shorter": 200, + "shortest": 150, + "standard": 300, + }, + "easing": Object { + "easeIn": "cubic-bezier(0.4, 0, 1, 1)", + "easeInOut": "cubic-bezier(0.4, 0, 0.2, 1)", + "easeOut": "cubic-bezier(0.0, 0, 0.2, 1)", + "sharp": "cubic-bezier(0.4, 0, 0.6, 1)", + }, + "getAutoHeightDuration": [Function], + }, + "typography": Object { + "body1": Object { + "fontFamily": "\\"Roboto\\", \\"Helvetica\\", \\"Arial\\", sans-serif", + "fontSize": "1rem", + "fontWeight": 400, + "letterSpacing": "0.00938em", + "lineHeight": 1.5, + }, + "body2": Object { + "fontFamily": "\\"Roboto\\", \\"Helvetica\\", \\"Arial\\", sans-serif", + "fontSize": "0.875rem", + "fontWeight": 400, + "letterSpacing": "0.01071em", + "lineHeight": 1.43, + }, + "button": Object { + "fontFamily": "\\"Roboto\\", \\"Helvetica\\", \\"Arial\\", sans-serif", + "fontSize": "0.875rem", + "fontWeight": 500, + "letterSpacing": "0.02857em", + "lineHeight": 1.75, + "textTransform": "uppercase", + }, + "caption": Object { + "fontFamily": "\\"Roboto\\", \\"Helvetica\\", \\"Arial\\", sans-serif", + "fontSize": "0.75rem", + "fontWeight": 400, + "letterSpacing": "0.03333em", + "lineHeight": 1.66, + }, + "fontFamily": "\\"Roboto\\", \\"Helvetica\\", \\"Arial\\", sans-serif", + "fontSize": 14, + "fontWeightBold": 700, + "fontWeightLight": 300, + "fontWeightMedium": 500, + "fontWeightRegular": 400, + "h1": Object { + "fontFamily": "\\"Roboto\\", \\"Helvetica\\", \\"Arial\\", sans-serif", + "fontSize": "6rem", + "fontWeight": 300, + "letterSpacing": "-0.01562em", + "lineHeight": 1.167, + }, + "h2": Object { + "fontFamily": "\\"Roboto\\", \\"Helvetica\\", \\"Arial\\", sans-serif", + "fontSize": "3.75rem", + "fontWeight": 300, + "letterSpacing": "-0.00833em", + "lineHeight": 1.2, + }, + "h3": Object { + "fontFamily": "\\"Roboto\\", \\"Helvetica\\", \\"Arial\\", sans-serif", + "fontSize": "3rem", + "fontWeight": 400, + "letterSpacing": "0em", + "lineHeight": 1.167, + }, + "h4": Object { + "fontFamily": "\\"Roboto\\", \\"Helvetica\\", \\"Arial\\", sans-serif", + "fontSize": "2.125rem", + "fontWeight": 400, + "letterSpacing": "0.00735em", + "lineHeight": 1.235, + }, + "h5": Object { + "fontFamily": "\\"Roboto\\", \\"Helvetica\\", \\"Arial\\", sans-serif", + "fontSize": "1.5rem", + "fontWeight": 400, + "letterSpacing": "0em", + "lineHeight": 1.334, + }, + "h6": Object { + "fontFamily": "\\"Roboto\\", \\"Helvetica\\", \\"Arial\\", sans-serif", + "fontSize": "1.25rem", + "fontWeight": 500, + "letterSpacing": "0.0075em", + "lineHeight": 1.6, + }, + "htmlFontSize": 16, + "overline": Object { + "fontFamily": "\\"Roboto\\", \\"Helvetica\\", \\"Arial\\", sans-serif", + "fontSize": "0.75rem", + "fontWeight": 400, + "letterSpacing": "0.08333em", + "lineHeight": 2.66, + "textTransform": "uppercase", + }, + "pxToRem": [Function], + "round": [Function], + "subtitle1": Object { + "fontFamily": "\\"Roboto\\", \\"Helvetica\\", \\"Arial\\", sans-serif", + "fontSize": "1rem", + "fontWeight": 400, + "letterSpacing": "0.00938em", + "lineHeight": 1.75, + }, + "subtitle2": Object { + "fontFamily": "\\"Roboto\\", \\"Helvetica\\", \\"Arial\\", sans-serif", + "fontSize": "0.875rem", + "fontWeight": 500, + "letterSpacing": "0.00714em", + "lineHeight": 1.57, + }, + }, + "zIndex": Object { + "appBar": 1100, + "drawer": 1200, + "mobileStepper": 1000, + "modal": 1300, + "snackbar": 1400, + "speedDial": 1050, + "tooltip": 1500, + }, + }, + "name": "MuiBackdrop", + }, + "propTypes": Object { + "classes": [Function], + "innerRef": [Function], + }, + "render": [Function], + "useStyles": [Function], + } + } + BackdropProps={ + Object { + "transitionDuration": Object { + "enter": 225, + "exit": 195, + }, + } + } + className="MuiDialog-root modal-root" + closeAfterTransition={true} + disableEscapeKeyDown={false} + onClose={[Function]} + open={false} + /> + </ForwardRef(Dialog)> + </WithStyles(ForwardRef(Dialog))> + </NoAnalysisModal> + <ForwardRef(Fade) + in={true} + > + <Transition + appear={true} + enter={true} + exit={true} + in={true} + mountOnEnter={false} + onEnter={[Function]} + onEntered={[Function]} + onEntering={[Function]} + onExit={[Function]} + onExited={[Function]} + onExiting={[Function]} + timeout={ + Object { + "enter": 225, + "exit": 195, + } + } + unmountOnExit={false} + > + <div + className="analysis-root" + style={ + Object { + "opacity": 1, + "visibility": undefined, + } + } + > + <div + className="analysis-content" + > + <IncompleteDataWarning + incompleteDataFluids={ + Array [ + 0, + ] + } + > + <div + className="analysis-warning" + > + <div + className="warning-header" + > + <StyledIcon + icon="test-file-stub" + size={30} + > + <Icon + aria-hidden={true} + icon="test-file-stub" + size={30} + spin={false} + > + <Component + aria-hidden={true} + className="styles__icon___23x3R" + height={30} + style={Object {}} + width={30} + > + <svg + aria-hidden={true} + className="styles__icon___23x3R" + height={30} + style={Object {}} + width={30} + > + <use + xlinkHref="#test-file-stub" + /> + </svg> + </Component> + </Icon> + </StyledIcon> + <h1> + analysis.warning_title + </h1> + </div> + <div + className="warning-content" + > + <p> + analysis.warning_text + </p> + </div> + </div> + </IncompleteDataWarning> + </div> + <div + className="analysis-content" + > + <mock-comparison + fluidsWithData={ + Array [ + 0, + 1, + 2, + ] + } + monthPerformanceIndicators={ + Array [ + Object { + "compareValue": 10, + "percentageVariation": 50, + "value": 5, + }, + Object { + "compareValue": 10, + "percentageVariation": 50, + "value": 5, + }, + ] + } + /> + </div> + <div + className="analysis-content" + > + <div + className="card rich-card" + > + <mock-total-analysis + fluidsWithData={ + Array [ + 0, + 1, + 2, + ] + } + /> + </div> + </div> + <div + className="analysis-content" + > + <div + className="card rich-card" + > + <mock-max-consumption + fluidsWithData={ + Array [ + 0, + 1, + 2, + ] + } + /> + </div> + </div> + <div + className="analysis-content" + > + <div + className="card rich-card" + > + <mock-analysis + aggregatedPerformanceIndicator={ + Object { + "compareValue": 1.7718999999999998, + "percentageVariation": -0.5, + "value": 0.8859499999999999, + } + } + performanceIndicators={ + Array [ + Object { + "compareValue": 10, + "percentageVariation": 50, + "value": 5, + }, + Object { + "compareValue": 10, + "percentageVariation": 50, + "value": 5, + }, + ] + } + /> + </div> + </div> + <div + className="analysis-content" + > + <div + className="card" + > + <mock-half-hour-analysis + perfIndicator={ + Object { + "compareValue": 10, + "percentageVariation": 50, + "value": 5, + } + } + /> + </div> + </div> + </div> + </Transition> + </ForwardRef(Fade)> + </MonthlyAnalysis> + </Provider> + </Router> </BrowserRouter> `; diff --git a/src/components/Analysis/__snapshots__/PieChart.spec.tsx.snap b/src/components/Analysis/__snapshots__/PieChart.spec.tsx.snap deleted file mode 100644 index 068b2c5beea6874e586213b5186fc2958ef45d50..0000000000000000000000000000000000000000 --- a/src/components/Analysis/__snapshots__/PieChart.spec.tsx.snap +++ /dev/null @@ -1,507 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`PieChart component should be rendered correctly 1`] = ` -<Provider - store={ - Object { - "clearActions": [Function], - "dispatch": [Function], - "getActions": [Function], - "getState": [Function], - "replaceReducer": [Function], - "subscribe": [Function], - } - } -> - <PieChart - currentAnalysisDate={"2021-07-01T00:00:00.000Z"} - dataloadValueDetailArray={ - Array [ - Object { - "state": "VALID", - "value": 10, - }, - Object { - "state": "VALID", - "value": 20, - }, - Object { - "state": "VALID", - "value": 30, - }, - ] - } - height={300} - innerRadius={300} - outerRadius={300} - totalValue={60} - width={300} - > - <div - className="pie-container" - style={ - Object { - "height": 300, - "width": 300, - } - } - > - <svg - height={300} - width={300} - > - <defs> - <filter - height="300%" - id="glow" - width="300%" - x="-75%" - y="-75%" - > - <feGaussianBlur - result="coloredBlur" - stdDeviation="10" - /> - <feMerge> - <feMergeNode - in="coloredBlur" - /> - <feMergeNode - in="SourceGraphic" - /> - </feMerge> - </filter> - </defs> - <g - transform="translate(300 300)" - /> - </svg> - <div - className="pie-center" - style={ - Object { - "height": 300, - "left": 0, - "top": 0, - "width": 300, - } - } - > - <div - className="text-36-bold" - > - 60,00 - <span - className="euro-unit" - > - FLUID.MULTIFLUID.UNIT - </span> - </div> - <div - className="text-16-normal date" - > - analysis_pie.monthde juin - </div> - <div - className="text-14-normal estimation-text" - onClick={[Function]} - > - <span - className="estimated" - > - analysis_pie.estimation - </span> - <span - className="estimated" - > - analysis_pie.estimation2 - </span> - </div> - <div - className="circle" - style={ - Object { - "height": 300, - "left": 0, - "top": 0, - "width": 300, - } - } - /> - </div> - <EstimatedConsumptionModal - handleCloseClick={[Function]} - open={false} - > - <WithStyles(ForwardRef(Dialog)) - aria-labelledby="accessibility-title" - classes={ - Object { - "paper": "modal-paper", - "root": "modal-root", - } - } - onClose={[Function]} - open={false} - > - <ForwardRef(Dialog) - aria-labelledby="accessibility-title" - classes={ - Object { - "container": "MuiDialog-container", - "paper": "MuiDialog-paper modal-paper", - "paperFullScreen": "MuiDialog-paperFullScreen", - "paperFullWidth": "MuiDialog-paperFullWidth", - "paperScrollBody": "MuiDialog-paperScrollBody", - "paperScrollPaper": "MuiDialog-paperScrollPaper", - "paperWidthFalse": "MuiDialog-paperWidthFalse", - "paperWidthLg": "MuiDialog-paperWidthLg", - "paperWidthMd": "MuiDialog-paperWidthMd", - "paperWidthSm": "MuiDialog-paperWidthSm", - "paperWidthXl": "MuiDialog-paperWidthXl", - "paperWidthXs": "MuiDialog-paperWidthXs", - "root": "MuiDialog-root modal-root", - "scrollBody": "MuiDialog-scrollBody", - "scrollPaper": "MuiDialog-scrollPaper", - } - } - onClose={[Function]} - open={false} - > - <ForwardRef(Modal) - BackdropComponent={ - Object { - "$$typeof": Symbol(react.forward_ref), - "Naked": Object { - "$$typeof": Symbol(react.forward_ref), - "propTypes": Object { - "children": [Function], - "className": [Function], - "classes": [Function], - "invisible": [Function], - "open": [Function], - "transitionDuration": [Function], - }, - "render": [Function], - }, - "displayName": "WithStyles(ForwardRef(Backdrop))", - "options": Object { - "defaultTheme": Object { - "breakpoints": Object { - "between": [Function], - "down": [Function], - "keys": Array [ - "xs", - "sm", - "md", - "lg", - "xl", - ], - "only": [Function], - "up": [Function], - "values": Object { - "lg": 1280, - "md": 960, - "sm": 600, - "xl": 1920, - "xs": 0, - }, - "width": [Function], - }, - "direction": "ltr", - "mixins": Object { - "gutters": [Function], - "toolbar": Object { - "@media (min-width:0px) and (orientation: landscape)": Object { - "minHeight": 48, - }, - "@media (min-width:600px)": Object { - "minHeight": 64, - }, - "minHeight": 56, - }, - }, - "overrides": Object {}, - "palette": Object { - "action": Object { - "activatedOpacity": 0.12, - "active": "rgba(0, 0, 0, 0.54)", - "disabled": "rgba(0, 0, 0, 0.26)", - "disabledBackground": "rgba(0, 0, 0, 0.12)", - "disabledOpacity": 0.38, - "focus": "rgba(0, 0, 0, 0.12)", - "focusOpacity": 0.12, - "hover": "rgba(0, 0, 0, 0.04)", - "hoverOpacity": 0.04, - "selected": "rgba(0, 0, 0, 0.08)", - "selectedOpacity": 0.08, - }, - "augmentColor": [Function], - "background": Object { - "default": "#fafafa", - "paper": "#fff", - }, - "common": Object { - "black": "#000", - "white": "#fff", - }, - "contrastThreshold": 3, - "divider": "rgba(0, 0, 0, 0.12)", - "error": Object { - "contrastText": "#fff", - "dark": "#d32f2f", - "light": "#e57373", - "main": "#f44336", - }, - "getContrastText": [Function], - "grey": Object { - "100": "#f5f5f5", - "200": "#eeeeee", - "300": "#e0e0e0", - "400": "#bdbdbd", - "50": "#fafafa", - "500": "#9e9e9e", - "600": "#757575", - "700": "#616161", - "800": "#424242", - "900": "#212121", - "A100": "#d5d5d5", - "A200": "#aaaaaa", - "A400": "#303030", - "A700": "#616161", - }, - "info": Object { - "contrastText": "#fff", - "dark": "#1976d2", - "light": "#64b5f6", - "main": "#2196f3", - }, - "primary": Object { - "contrastText": "#fff", - "dark": "#303f9f", - "light": "#7986cb", - "main": "#3f51b5", - }, - "secondary": Object { - "contrastText": "#fff", - "dark": "#c51162", - "light": "#ff4081", - "main": "#f50057", - }, - "success": Object { - "contrastText": "rgba(0, 0, 0, 0.87)", - "dark": "#388e3c", - "light": "#81c784", - "main": "#4caf50", - }, - "text": Object { - "disabled": "rgba(0, 0, 0, 0.38)", - "hint": "rgba(0, 0, 0, 0.38)", - "primary": "rgba(0, 0, 0, 0.87)", - "secondary": "rgba(0, 0, 0, 0.54)", - }, - "tonalOffset": 0.2, - "type": "light", - "warning": Object { - "contrastText": "rgba(0, 0, 0, 0.87)", - "dark": "#f57c00", - "light": "#ffb74d", - "main": "#ff9800", - }, - }, - "props": Object {}, - "shadows": Array [ - "none", - "0px 2px 1px -1px rgba(0,0,0,0.2),0px 1px 1px 0px rgba(0,0,0,0.14),0px 1px 3px 0px rgba(0,0,0,0.12)", - "0px 3px 1px -2px rgba(0,0,0,0.2),0px 2px 2px 0px rgba(0,0,0,0.14),0px 1px 5px 0px rgba(0,0,0,0.12)", - "0px 3px 3px -2px rgba(0,0,0,0.2),0px 3px 4px 0px rgba(0,0,0,0.14),0px 1px 8px 0px rgba(0,0,0,0.12)", - "0px 2px 4px -1px rgba(0,0,0,0.2),0px 4px 5px 0px rgba(0,0,0,0.14),0px 1px 10px 0px rgba(0,0,0,0.12)", - "0px 3px 5px -1px rgba(0,0,0,0.2),0px 5px 8px 0px rgba(0,0,0,0.14),0px 1px 14px 0px rgba(0,0,0,0.12)", - "0px 3px 5px -1px rgba(0,0,0,0.2),0px 6px 10px 0px rgba(0,0,0,0.14),0px 1px 18px 0px rgba(0,0,0,0.12)", - "0px 4px 5px -2px rgba(0,0,0,0.2),0px 7px 10px 1px rgba(0,0,0,0.14),0px 2px 16px 1px rgba(0,0,0,0.12)", - "0px 5px 5px -3px rgba(0,0,0,0.2),0px 8px 10px 1px rgba(0,0,0,0.14),0px 3px 14px 2px rgba(0,0,0,0.12)", - "0px 5px 6px -3px rgba(0,0,0,0.2),0px 9px 12px 1px rgba(0,0,0,0.14),0px 3px 16px 2px rgba(0,0,0,0.12)", - "0px 6px 6px -3px rgba(0,0,0,0.2),0px 10px 14px 1px rgba(0,0,0,0.14),0px 4px 18px 3px rgba(0,0,0,0.12)", - "0px 6px 7px -4px rgba(0,0,0,0.2),0px 11px 15px 1px rgba(0,0,0,0.14),0px 4px 20px 3px rgba(0,0,0,0.12)", - "0px 7px 8px -4px rgba(0,0,0,0.2),0px 12px 17px 2px rgba(0,0,0,0.14),0px 5px 22px 4px rgba(0,0,0,0.12)", - "0px 7px 8px -4px rgba(0,0,0,0.2),0px 13px 19px 2px rgba(0,0,0,0.14),0px 5px 24px 4px rgba(0,0,0,0.12)", - "0px 7px 9px -4px rgba(0,0,0,0.2),0px 14px 21px 2px rgba(0,0,0,0.14),0px 5px 26px 4px rgba(0,0,0,0.12)", - "0px 8px 9px -5px rgba(0,0,0,0.2),0px 15px 22px 2px rgba(0,0,0,0.14),0px 6px 28px 5px rgba(0,0,0,0.12)", - "0px 8px 10px -5px rgba(0,0,0,0.2),0px 16px 24px 2px rgba(0,0,0,0.14),0px 6px 30px 5px rgba(0,0,0,0.12)", - "0px 8px 11px -5px rgba(0,0,0,0.2),0px 17px 26px 2px rgba(0,0,0,0.14),0px 6px 32px 5px rgba(0,0,0,0.12)", - "0px 9px 11px -5px rgba(0,0,0,0.2),0px 18px 28px 2px rgba(0,0,0,0.14),0px 7px 34px 6px rgba(0,0,0,0.12)", - "0px 9px 12px -6px rgba(0,0,0,0.2),0px 19px 29px 2px rgba(0,0,0,0.14),0px 7px 36px 6px rgba(0,0,0,0.12)", - "0px 10px 13px -6px rgba(0,0,0,0.2),0px 20px 31px 3px rgba(0,0,0,0.14),0px 8px 38px 7px rgba(0,0,0,0.12)", - "0px 10px 13px -6px rgba(0,0,0,0.2),0px 21px 33px 3px rgba(0,0,0,0.14),0px 8px 40px 7px rgba(0,0,0,0.12)", - "0px 10px 14px -6px rgba(0,0,0,0.2),0px 22px 35px 3px rgba(0,0,0,0.14),0px 8px 42px 7px rgba(0,0,0,0.12)", - "0px 11px 14px -7px rgba(0,0,0,0.2),0px 23px 36px 3px rgba(0,0,0,0.14),0px 9px 44px 8px rgba(0,0,0,0.12)", - "0px 11px 15px -7px rgba(0,0,0,0.2),0px 24px 38px 3px rgba(0,0,0,0.14),0px 9px 46px 8px rgba(0,0,0,0.12)", - ], - "shape": Object { - "borderRadius": 4, - }, - "spacing": [Function], - "transitions": Object { - "create": [Function], - "duration": Object { - "complex": 375, - "enteringScreen": 225, - "leavingScreen": 195, - "short": 250, - "shorter": 200, - "shortest": 150, - "standard": 300, - }, - "easing": Object { - "easeIn": "cubic-bezier(0.4, 0, 1, 1)", - "easeInOut": "cubic-bezier(0.4, 0, 0.2, 1)", - "easeOut": "cubic-bezier(0.0, 0, 0.2, 1)", - "sharp": "cubic-bezier(0.4, 0, 0.6, 1)", - }, - "getAutoHeightDuration": [Function], - }, - "typography": Object { - "body1": Object { - "fontFamily": "\\"Roboto\\", \\"Helvetica\\", \\"Arial\\", sans-serif", - "fontSize": "1rem", - "fontWeight": 400, - "letterSpacing": "0.00938em", - "lineHeight": 1.5, - }, - "body2": Object { - "fontFamily": "\\"Roboto\\", \\"Helvetica\\", \\"Arial\\", sans-serif", - "fontSize": "0.875rem", - "fontWeight": 400, - "letterSpacing": "0.01071em", - "lineHeight": 1.43, - }, - "button": Object { - "fontFamily": "\\"Roboto\\", \\"Helvetica\\", \\"Arial\\", sans-serif", - "fontSize": "0.875rem", - "fontWeight": 500, - "letterSpacing": "0.02857em", - "lineHeight": 1.75, - "textTransform": "uppercase", - }, - "caption": Object { - "fontFamily": "\\"Roboto\\", \\"Helvetica\\", \\"Arial\\", sans-serif", - "fontSize": "0.75rem", - "fontWeight": 400, - "letterSpacing": "0.03333em", - "lineHeight": 1.66, - }, - "fontFamily": "\\"Roboto\\", \\"Helvetica\\", \\"Arial\\", sans-serif", - "fontSize": 14, - "fontWeightBold": 700, - "fontWeightLight": 300, - "fontWeightMedium": 500, - "fontWeightRegular": 400, - "h1": Object { - "fontFamily": "\\"Roboto\\", \\"Helvetica\\", \\"Arial\\", sans-serif", - "fontSize": "6rem", - "fontWeight": 300, - "letterSpacing": "-0.01562em", - "lineHeight": 1.167, - }, - "h2": Object { - "fontFamily": "\\"Roboto\\", \\"Helvetica\\", \\"Arial\\", sans-serif", - "fontSize": "3.75rem", - "fontWeight": 300, - "letterSpacing": "-0.00833em", - "lineHeight": 1.2, - }, - "h3": Object { - "fontFamily": "\\"Roboto\\", \\"Helvetica\\", \\"Arial\\", sans-serif", - "fontSize": "3rem", - "fontWeight": 400, - "letterSpacing": "0em", - "lineHeight": 1.167, - }, - "h4": Object { - "fontFamily": "\\"Roboto\\", \\"Helvetica\\", \\"Arial\\", sans-serif", - "fontSize": "2.125rem", - "fontWeight": 400, - "letterSpacing": "0.00735em", - "lineHeight": 1.235, - }, - "h5": Object { - "fontFamily": "\\"Roboto\\", \\"Helvetica\\", \\"Arial\\", sans-serif", - "fontSize": "1.5rem", - "fontWeight": 400, - "letterSpacing": "0em", - "lineHeight": 1.334, - }, - "h6": Object { - "fontFamily": "\\"Roboto\\", \\"Helvetica\\", \\"Arial\\", sans-serif", - "fontSize": "1.25rem", - "fontWeight": 500, - "letterSpacing": "0.0075em", - "lineHeight": 1.6, - }, - "htmlFontSize": 16, - "overline": Object { - "fontFamily": "\\"Roboto\\", \\"Helvetica\\", \\"Arial\\", sans-serif", - "fontSize": "0.75rem", - "fontWeight": 400, - "letterSpacing": "0.08333em", - "lineHeight": 2.66, - "textTransform": "uppercase", - }, - "pxToRem": [Function], - "round": [Function], - "subtitle1": Object { - "fontFamily": "\\"Roboto\\", \\"Helvetica\\", \\"Arial\\", sans-serif", - "fontSize": "1rem", - "fontWeight": 400, - "letterSpacing": "0.00938em", - "lineHeight": 1.75, - }, - "subtitle2": Object { - "fontFamily": "\\"Roboto\\", \\"Helvetica\\", \\"Arial\\", sans-serif", - "fontSize": "0.875rem", - "fontWeight": 500, - "letterSpacing": "0.00714em", - "lineHeight": 1.57, - }, - }, - "zIndex": Object { - "appBar": 1100, - "drawer": 1200, - "mobileStepper": 1000, - "modal": 1300, - "snackbar": 1400, - "speedDial": 1050, - "tooltip": 1500, - }, - }, - "name": "MuiBackdrop", - }, - "propTypes": Object { - "classes": [Function], - "innerRef": [Function], - }, - "render": [Function], - "useStyles": [Function], - } - } - BackdropProps={ - Object { - "transitionDuration": Object { - "enter": 225, - "exit": 195, - }, - } - } - className="MuiDialog-root modal-root" - closeAfterTransition={true} - disableEscapeKeyDown={false} - onClose={[Function]} - open={false} - /> - </ForwardRef(Dialog)> - </WithStyles(ForwardRef(Dialog))> - </EstimatedConsumptionModal> - </div> - </PieChart> -</Provider> -`; diff --git a/src/components/Analysis/analysisError.scss b/src/components/Analysis/analysisError.scss deleted file mode 100644 index 20fe6495e9c43389f0307b1071a18210eba3eabd..0000000000000000000000000000000000000000 --- a/src/components/Analysis/analysisError.scss +++ /dev/null @@ -1,56 +0,0 @@ -@import '../../styles/base/color'; -@import '../../styles/base/breakpoint'; - -.analysis-root.black { - .modal-overlay { - .modal-close-button { - display: none; - } - } -} - -.analysis-error-container { - border-radius: 4px; - margin-bottom: 1rem; - color: $grey-bright; - text-align: center; - .analysis-error-title { - color: $gold-shadow; - margin-bottom: 2rem; - } - .analysis-error-button { - display: flex; - justify-content: space-between; - gap: 1rem; - margin-top: 2rem; - button { - margin: 0; - &.btn-highlight, - &.btn-secondary-positive { - width: 45%; - margin-bottom: 0; - } - &.btn-secondary-positive { - padding: 0.5rem 1rem; - } - &.btn-highlight { - padding: 0.25rem 0.5rem; - } - } - @media #{$large-phone} { - flex-direction: column-reverse; - button { - &.btn-highlight, - &.btn-secondary-positive { - margin-bottom: 0; - width: 100%; - height: 45px; - } - } - } - } -} - -#accessibility-title { - display: none; -} diff --git a/src/components/Analysis/analysisView.scss b/src/components/Analysis/analysisView.scss index 7022598c93fe5fac3c2d7b865d753f652c82639d..2b60ed6ff89b5ce799b3aa222e6357d2ec2b9d10 100644 --- a/src/components/Analysis/analysisView.scss +++ b/src/components/Analysis/analysisView.scss @@ -1,4 +1,4 @@ -@import '../../styles/base/color'; +@import 'src/styles/base/color'; .analysis-view-title { color: $grey-bright; text-align: center; diff --git a/src/components/Analysis/monthlyanalysis.scss b/src/components/Analysis/monthlyanalysis.scss index 7f775f6408d871a7f952fc55c9cc53b8ce7e1b78..10241fe3a73757a53172831b2ae2bb92f351b897 100644 --- a/src/components/Analysis/monthlyanalysis.scss +++ b/src/components/Analysis/monthlyanalysis.scss @@ -1,19 +1,13 @@ -@import '../../styles/base/color'; -@import '../../styles/base/breakpoint'; +@import 'src/styles/base/color'; +@import 'src/styles/base/breakpoint'; .analysis-root { display: flex; flex-direction: column; align-items: center; - justify-content: space-around; padding: 1rem 1rem 1.5rem; gap: 1rem; - &.black { - background: var(--darkLight2); - } - @media #{$large-phone} { - margin-bottom: 0; - } + .analysis-content { width: 45.75rem; @@ -27,6 +21,9 @@ grid-gap: 0.5rem; justify-content: end; color: $grey-bright !important; + p { + color: $grey-bright; + } div { align-items: center; display: flex; @@ -47,10 +44,3 @@ } } } -.analysis-container-spinner { - position: absolute; - top: 50%; - left: 50%; - transform: translate(-50%, -50%); - text-align: center; -} diff --git a/src/components/App.tsx b/src/components/App.tsx index e3ffd41d0636c51f923d58942248df61f0862159..5cfeb0f21cd9c288dd8b4c81fadedac567abdc3d 100644 --- a/src/components/App.tsx +++ b/src/components/App.tsx @@ -5,9 +5,8 @@ import WelcomeModal from 'components/WelcomeModal/WelcomeModal' import { useWebviewIntent } from 'cozy-intent' import { Layout } from 'cozy-ui/transpiled/react/Layout' import React, { useEffect } from 'react' -import { useSelector } from 'react-redux' import { useLocation } from 'react-router-dom' -import { AppStore } from 'store' +import { useAppSelector } from 'store/hooks' import MatomoTracker from 'utils/matomoTracker' interface AppProps { @@ -19,7 +18,7 @@ export const App = ({ tracker }: AppProps) => { const { global: { termsStatus }, profile: { onboarding }, - } = useSelector((state: AppStore) => state.ecolyo) + } = useAppSelector(state => state.ecolyo) const webviewIntent = useWebviewIntent() useEffect(() => { diff --git a/src/components/Challenge/ChallengeCard.spec.tsx b/src/components/Challenge/ChallengeCard/ChallengeCard.spec.tsx similarity index 79% rename from src/components/Challenge/ChallengeCard.spec.tsx rename to src/components/Challenge/ChallengeCard/ChallengeCard.spec.tsx index 9519e7e99752c02f3c2ee0f63afecbfd833e1c90..9c4a0a2f27cd73a15d69acde9b1ad4786a9582ee 100644 --- a/src/components/Challenge/ChallengeCard.spec.tsx +++ b/src/components/Challenge/ChallengeCard/ChallengeCard.spec.tsx @@ -1,20 +1,10 @@ import { shallow } from 'enzyme' import React from 'react' -import { userChallengeData } from '../../../tests/__mocks__/userChallengeData.mock' +import { userChallengeData } from 'tests/__mocks__/userChallengeData.mock' +import ChallengeCardLocked from '../ChallengeCardLocked/ChallengeCardLocked' +import ChallengeCardOnGoing from '../ChallengeCardOnGoing/ChallengeCardOnGoing' +import ChallengeCardUnlocked from '../ChallengeCardUnlocked/ChallengeCardUnlocked' import ChallengeCard from './ChallengeCard' -import ChallengeCardLocked from './ChallengeCardLocked' -import ChallengeCardOnGoing from './ChallengeCardOnGoing' -import ChallengeCardUnlocked from './ChallengeCardUnlocked' - -jest.mock('cozy-ui/transpiled/react/I18n', () => { - return { - useI18n: jest.fn(() => { - return { - t: (str: string) => str, - } - }), - } -}) const mockMoveToSlide = jest.fn() diff --git a/src/components/Challenge/ChallengeCard.tsx b/src/components/Challenge/ChallengeCard/ChallengeCard.tsx similarity index 78% rename from src/components/Challenge/ChallengeCard.tsx rename to src/components/Challenge/ChallengeCard/ChallengeCard.tsx index a6788d190ade10f3defc8b7bbe3f389b94aa2b2c..dc44d0da9da2d967f59135f2f4d3ab1bd356f528 100644 --- a/src/components/Challenge/ChallengeCard.tsx +++ b/src/components/Challenge/ChallengeCard/ChallengeCard.tsx @@ -1,11 +1,11 @@ -import { UserChallengeState } from 'enum/userChallenge.enum' +import { UserChallengeState } from 'enums' import { UserChallenge } from 'models' import React from 'react' -import ChallengeCardDone from './ChallengeCardDone' -import ChallengeCardLast from './ChallengeCardLast' -import ChallengeCardLocked from './ChallengeCardLocked' -import ChallengeCardOnGoing from './ChallengeCardOnGoing' -import ChallengeCardUnlocked from './ChallengeCardUnlocked' +import ChallengeCardDone from '../ChallengeCardDone/ChallengeCardDone' +import ChallengeCardLast from '../ChallengeCardLast/ChallengeCardLast' +import ChallengeCardLocked from '../ChallengeCardLocked/ChallengeCardLocked' +import ChallengeCardOnGoing from '../ChallengeCardOnGoing/ChallengeCardOnGoing' +import ChallengeCardUnlocked from '../ChallengeCardUnlocked/ChallengeCardUnlocked' import './challengeCard.scss' interface ChallengeCardProps { diff --git a/src/components/Challenge/__snapshots__/ChallengeCard.spec.tsx.snap b/src/components/Challenge/ChallengeCard/__snapshots__/ChallengeCard.spec.tsx.snap similarity index 100% rename from src/components/Challenge/__snapshots__/ChallengeCard.spec.tsx.snap rename to src/components/Challenge/ChallengeCard/__snapshots__/ChallengeCard.spec.tsx.snap diff --git a/src/components/Challenge/challengeCard.scss b/src/components/Challenge/ChallengeCard/challengeCard.scss similarity index 90% rename from src/components/Challenge/challengeCard.scss rename to src/components/Challenge/ChallengeCard/challengeCard.scss index 8088fe285dec927eb17a824e23342866fcc29239..ac7c9ebca6f8563570e67e724fe3529ca81ba5e3 100644 --- a/src/components/Challenge/challengeCard.scss +++ b/src/components/Challenge/ChallengeCard/challengeCard.scss @@ -1,4 +1,4 @@ -@import '../../styles/base/color'; +@import 'src/styles/base/color'; .slide { margin: 0 1rem 0 0; @@ -8,6 +8,7 @@ color: white; display: flex; flex-direction: column; + height: 100%; &.active { transform: scale(1); } diff --git a/src/components/Challenge/ChallengeCardDone.spec.tsx b/src/components/Challenge/ChallengeCardDone.spec.tsx deleted file mode 100644 index e447ca39f94588f1d0fee157b1a693b61826d331..0000000000000000000000000000000000000000 --- a/src/components/Challenge/ChallengeCardDone.spec.tsx +++ /dev/null @@ -1,38 +0,0 @@ -import ChallengeCardDone from 'components/Challenge/ChallengeCardDone' -import { shallow } from 'enzyme' -import React from 'react' -import { userChallengeData } from '../../../tests/__mocks__/userChallengeData.mock' - -jest.mock('cozy-ui/transpiled/react/I18n', () => { - return { - useI18n: jest.fn(() => { - return { - t: (str: string) => str, - } - }), - } -}) -const mockImportIconById = jest.fn() -const mockFormatNumberValues = jest.fn() -jest.mock('utils/utils', () => { - return { - importIconById: jest.fn(() => mockImportIconById), - formatNumberValues: jest.fn(() => mockFormatNumberValues), - getChallengeTitleWithLineReturn: jest.fn(() => 'Challenge 1'), - } -}) - -const mockedNavigate = jest.fn() -jest.mock('react-router-dom', () => ({ - ...jest.requireActual('react-router-dom'), - useNavigate: () => mockedNavigate, -})) - -describe('ChallengeCardDone component', () => { - it('should be rendered correctly', () => { - const component = shallow( - <ChallengeCardDone userChallenge={userChallengeData[0]} /> - ).getElement() - expect(component).toMatchSnapshot() - }) -}) diff --git a/src/components/Challenge/ChallengeCardDone/ChallengeCardDone.spec.tsx b/src/components/Challenge/ChallengeCardDone/ChallengeCardDone.spec.tsx new file mode 100644 index 0000000000000000000000000000000000000000..21a0b674c6d80993b88513fccaa4060c288f00e6 --- /dev/null +++ b/src/components/Challenge/ChallengeCardDone/ChallengeCardDone.spec.tsx @@ -0,0 +1,96 @@ +import { Button } from '@material-ui/core' +import ChallengeCardDone from 'components/Challenge/ChallengeCardDone/ChallengeCardDone' +import { mount } from 'enzyme' +import toJson from 'enzyme-to-json' +import React from 'react' +import { Provider } from 'react-redux' +import configureStore from 'redux-mock-store' +import * as storeHooks from 'store/hooks' +import { waitForComponentToPaint } from 'tests/__mocks__/testUtils' +import { userChallengeData } from 'tests/__mocks__/userChallengeData.mock' + +const mockUpdateUserChallenge = jest.fn() +jest.mock('services/challenge.service', () => { + return jest.fn(() => ({ + updateUserChallenge: mockUpdateUserChallenge, + })) +}) + +const mockStore = configureStore([]) +const mockDispatch = jest.fn() +const mockAppDispatch = jest.spyOn(storeHooks, 'useAppDispatch') + +describe('ChallengeCardDone component', () => { + const storeNoCurrentChallenge = mockStore({ + ecolyo: { + challenge: { currentChallenge: null }, + }, + }) + it('should be rendered correctly', async () => { + const wrapper = mount( + <Provider store={storeNoCurrentChallenge}> + <ChallengeCardDone userChallenge={userChallengeData[0]} /> + </Provider> + ) + await waitForComponentToPaint(wrapper) + expect(toJson(wrapper)).toMatchSnapshot() + }) + + describe('Reset final challenge', () => { + beforeEach(() => { + jest.clearAllMocks() + }) + it('should reset challenge if no other challenge is on going', async () => { + mockAppDispatch.mockImplementationOnce(() => mockDispatch) + const wrapper = mount( + <Provider store={storeNoCurrentChallenge}> + <ChallengeCardDone userChallenge={userChallengeData[0]} /> + </Provider> + ) + wrapper.find(Button).last().simulate('click') + await waitForComponentToPaint(wrapper) + expect(mockDispatch).toHaveBeenCalledTimes(1) + expect(mockDispatch).toHaveBeenCalledWith({ + type: 'challenge/updateUserChallengeList', + }) + expect(mockUpdateUserChallenge).toHaveBeenCalledTimes(1) + }) + it('should not reset challenge if another challenge is on going', async () => { + mockAppDispatch.mockImplementationOnce(() => mockDispatch) + const store = mockStore({ + ecolyo: { + challenge: { currentChallenge: userChallengeData[1] }, + }, + }) + const wrapper = mount( + <Provider store={store}> + <ChallengeCardDone userChallenge={userChallengeData[0]} /> + </Provider> + ) + wrapper.find(Button).last().simulate('click') + await waitForComponentToPaint(wrapper) + expect(mockDispatch).toHaveBeenCalledTimes(0) + expect(mockUpdateUserChallenge).toHaveBeenCalledTimes(0) + }) + it('should be primary button is challenge is lost', async () => { + const wrapper = mount( + <Provider store={storeNoCurrentChallenge}> + <ChallengeCardDone userChallenge={userChallengeData[1]} /> + </Provider> + ) + await waitForComponentToPaint(wrapper) + const resetButton = wrapper.find('button').last() + expect(resetButton.hasClass('btn-primary-challenge')).toBe(true) + }) + it('should be secondary button is challenge is won', async () => { + const wrapper = mount( + <Provider store={storeNoCurrentChallenge}> + <ChallengeCardDone userChallenge={userChallengeData[0]} /> + </Provider> + ) + await waitForComponentToPaint(wrapper) + const resetButton = wrapper.find('button').last() + expect(resetButton.hasClass('btn-secondary-negative')).toBe(true) + }) + }) +}) diff --git a/src/components/Challenge/ChallengeCardDone.tsx b/src/components/Challenge/ChallengeCardDone/ChallengeCardDone.tsx similarity index 64% rename from src/components/Challenge/ChallengeCardDone.tsx rename to src/components/Challenge/ChallengeCardDone/ChallengeCardDone.tsx index 9430da1fbfba471072a8763eb91278819e8d9315..59e2c9e272a1334bd9a70876578837457e0601c3 100644 --- a/src/components/Challenge/ChallengeCardDone.tsx +++ b/src/components/Challenge/ChallengeCardDone/ChallengeCardDone.tsx @@ -2,11 +2,15 @@ import { Button } from '@material-ui/core' import defaultIcon from 'assets/icons/visu/duelResult/default.svg' import classNames from 'classnames' import StyledIcon from 'components/CommonKit/Icon/StyledIcon' +import { useClient } from 'cozy-client' import { useI18n } from 'cozy-ui/transpiled/react/I18n' -import { UserChallengeSuccess } from 'enum/userChallenge.enum' +import { UserChallengeSuccess, UserChallengeUpdateFlag } from 'enums' import { UserChallenge } from 'models' import React, { useEffect, useState } from 'react' import { useNavigate } from 'react-router-dom' +import ChallengeService from 'services/challenge.service' +import { updateUserChallengeList } from 'store/challenge/challenge.slice' +import { useAppDispatch, useAppSelector } from 'store/hooks' import { formatNumberValues, getChallengeTitleWithLineReturn, @@ -21,6 +25,9 @@ const ChallengeCardDone = ({ }) => { const { t } = useI18n() const navigate = useNavigate() + const client = useClient() + const dispatch = useAppDispatch() + const { currentChallenge } = useAppSelector(state => state.ecolyo.challenge) const [winIcon, setWinIcon] = useState<string>(defaultIcon) const [lossIcon, setLossIcon] = useState<string>(defaultIcon) @@ -52,20 +59,21 @@ const ChallengeCardDone = ({ navigate('/challenges/duel?id=' + userChallenge.id) } + const handleChallengeReset = async () => { + const challengeService = new ChallengeService(client) + const updatedChallenge = await challengeService.updateUserChallenge( + userChallenge, + UserChallengeUpdateFlag.DUEL_RESET + ) + dispatch(updateUserChallengeList(updatedChallenge)) + } + useEffect(() => { async function handleEcogestureIcon() { const icon = await importIconById(userChallenge.id + '-1', 'duelResult') - if (icon) { - setWinIcon(icon) - } else { - setWinIcon(defaultIcon) - } + setWinIcon(icon || defaultIcon) const icon2 = await importIconById(userChallenge.id + '-0', 'duelResult') - if (icon2) { - setLossIcon(icon2) - } else { - setLossIcon(defaultIcon) - } + setLossIcon(icon2 || defaultIcon) } handleEcogestureIcon() }, [userChallenge]) @@ -106,16 +114,32 @@ const ChallengeCardDone = ({ {t('challenge.card_done.final_defi')} </span> </div> - <Button - aria-label={t('challenge.card_done.final_defi_view')} - onClick={goDuel} - classes={{ - root: 'btn-secondary-negative review-btn', - label: 'text-15-bold', - }} - > - {t('challenge.card_done.final_defi_view')} - </Button> + <div className="buttons"> + <Button + aria-label={t('challenge.card_done.final_defi_view')} + onClick={goDuel} + classes={{ + root: 'btn-secondary-negative grey-border', + label: 'text-15-bold', + }} + > + {t('challenge.card_done.final_defi_view')} + </Button> + <Button + aria-label={t('challenge.card_done.reset_defi')} + onClick={handleChallengeReset} + classes={{ + root: + userChallenge.success === UserChallengeSuccess.WIN + ? 'btn-secondary-negative grey-border' + : 'btn-primary-challenge', + label: 'text-15-bold', + }} + disabled={currentChallenge !== null} + > + {t('challenge.card_done.reset_defi')} + </Button> + </div> </div> ) } diff --git a/src/components/Challenge/ChallengeCardDone/__snapshots__/ChallengeCardDone.spec.tsx.snap b/src/components/Challenge/ChallengeCardDone/__snapshots__/ChallengeCardDone.spec.tsx.snap new file mode 100644 index 0000000000000000000000000000000000000000..5395d8e193876cc7176b2022e6717eac11544c5e --- /dev/null +++ b/src/components/Challenge/ChallengeCardDone/__snapshots__/ChallengeCardDone.spec.tsx.snap @@ -0,0 +1,500 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`ChallengeCardDone component should be rendered correctly 1`] = ` +<Provider + store={ + Object { + "clearActions": [Function], + "dispatch": [Function], + "getActions": [Function], + "getState": [Function], + "replaceReducer": [Function], + "subscribe": [Function], + } + } +> + <ChallengeCardDone + userChallenge={ + Object { + "action": Object { + "ecogesture": null, + "startDate": null, + "state": 0, + }, + "description": "Description challenge 1", + "duel": Object { + "description": "Je parie un ours polaire que vous ne pouvez pas consommer moins que #CONSUMPTION € en 1 semaine", + "duration": "P30D", + "fluidTypes": Array [], + "id": "DUEL001", + "startDate": null, + "state": 0, + "threshold": 0, + "title": "Title DUEL001", + "userConsumption": 0, + }, + "endingDate": null, + "exploration": Object { + "complementary_description": "Refaire un tour dans son profil si déjà fait", + "date": null, + "description": "Avoir complété son profil", + "ecogesture_id": "", + "fluid_condition": Array [], + "id": "EXPLORATION001", + "message_success": "Vous avez complété votre profil ou refait un tour dans votre profil", + "progress": 0, + "state": 0, + "target": 1, + "type": 1, + }, + "id": "CHALLENGE0001", + "progress": Object { + "actionProgress": 0, + "explorationProgress": 0, + "quizProgress": 0, + }, + "quiz": Object { + "customQuestion": Object { + "interval": 20, + "period": Object {}, + "questionLabel": "Custom1", + "result": 0, + "singleFluid": false, + "timeStep": 20, + "type": 0, + }, + "id": "QUIZ001", + "questions": Array [ + Object { + "answers": Array [ + Object { + "answerLabel": "86 km", + "isTrue": true, + }, + Object { + "answerLabel": "78 km", + "isTrue": false, + }, + Object { + "answerLabel": "56 km", + "isTrue": false, + }, + ], + "explanation": "L’aqueduc du Gier est un des aqueducs antiques de Lyon desservant la ville antique de Lugdunum. Avec ses 86 km il est le plus long des quatre aqueducs ayant alimenté la ville en eau, et celui dont les structures sont le mieux conservées. Il doit son nom au fait qu'il puise aux sources du Gier, affluent du Rhône", + "questionLabel": "Quelle longueur faisait l’aqueduc du Gier pour acheminer l’eau sur Lyon à l’époque romaine ?", + "result": 0, + "source": "string", + }, + Object { + "answers": Array [ + Object { + "answerLabel": "1 point d’eau public pour 800 habitants.", + "isTrue": true, + }, + Object { + "answerLabel": "1 point d’eau public pour 400 habitants.", + "isTrue": false, + }, + Object { + "answerLabel": "1 point d’eau public pour 200 habitants.", + "isTrue": false, + }, + ], + "explanation": "string", + "questionLabel": "En 1800 à Lyon, combien de points d'eau y avait-il par habitants ?", + "result": 0, + "source": "string", + }, + Object { + "answers": Array [ + Object { + "answerLabel": "François Mitterrand", + "isTrue": false, + }, + Object { + "answerLabel": "Napoléon Ier", + "isTrue": true, + }, + Object { + "answerLabel": "Napoléon III", + "isTrue": false, + }, + ], + "explanation": "string", + "questionLabel": "Qui officialise la création de la Compagnie Générale des eaux ?", + "result": 0, + "source": "string", + }, + Object { + "answers": Array [ + Object { + "answerLabel": "string", + "isTrue": false, + }, + Object { + "answerLabel": "string", + "isTrue": false, + }, + Object { + "answerLabel": "Aristide Dumont", + "isTrue": true, + }, + ], + "explanation": "string", + "questionLabel": "Quel ingénieur est à l’origine du projet d’alimentation en eau en 1856 ?", + "result": 0, + "source": "string", + }, + ], + "result": 0, + "startDate": null, + "state": 0, + }, + "startDate": null, + "state": 4, + "success": 2, + "target": 15, + "title": "Challenge 1", + } + } + > + <div + className="cardContent cardDone" + > + <div + className="challengeName text-22-bold" + > + Simone +VEILLE + </div> + <div + className="iconResult" + > + <StyledIcon + className="imgResult" + icon="test-file-stub" + size={180} + > + <Icon + aria-hidden={true} + className="imgResult" + icon="test-file-stub" + size={180} + spin={false} + > + <Component + aria-hidden={true} + className="imgResult styles__icon___23x3R" + height={180} + style={Object {}} + width={180} + > + <svg + aria-hidden={true} + className="imgResult styles__icon___23x3R" + height={180} + style={Object {}} + width={180} + > + <use + xlinkHref="#test-file-stub" + /> + </svg> + </Component> + </Icon> + </StyledIcon> + </div> + <div + className="statsResult" + > + <div + className="labelResult win" + > + challenge.card_done.win + </div> + <span + className="text-18" + > + challenge.card_done.saving + <span + className="text-18-bold" + > + 0,00 + € + </span> + <br /> + challenge.card_done.final_defi + </span> + </div> + <div + className="buttons" + > + <WithStyles(ForwardRef(Button)) + aria-label="challenge.card_done.final_defi_view" + classes={ + Object { + "label": "text-15-bold", + "root": "btn-secondary-negative grey-border", + } + } + onClick={[Function]} + > + <ForwardRef(Button) + aria-label="challenge.card_done.final_defi_view" + classes={ + Object { + "colorInherit": "MuiButton-colorInherit", + "contained": "MuiButton-contained", + "containedPrimary": "MuiButton-containedPrimary", + "containedSecondary": "MuiButton-containedSecondary", + "containedSizeLarge": "MuiButton-containedSizeLarge", + "containedSizeSmall": "MuiButton-containedSizeSmall", + "disableElevation": "MuiButton-disableElevation", + "disabled": "Mui-disabled", + "endIcon": "MuiButton-endIcon", + "focusVisible": "Mui-focusVisible", + "fullWidth": "MuiButton-fullWidth", + "iconSizeLarge": "MuiButton-iconSizeLarge", + "iconSizeMedium": "MuiButton-iconSizeMedium", + "iconSizeSmall": "MuiButton-iconSizeSmall", + "label": "MuiButton-label text-15-bold", + "outlined": "MuiButton-outlined", + "outlinedPrimary": "MuiButton-outlinedPrimary", + "outlinedSecondary": "MuiButton-outlinedSecondary", + "outlinedSizeLarge": "MuiButton-outlinedSizeLarge", + "outlinedSizeSmall": "MuiButton-outlinedSizeSmall", + "root": "MuiButton-root btn-secondary-negative grey-border", + "sizeLarge": "MuiButton-sizeLarge", + "sizeSmall": "MuiButton-sizeSmall", + "startIcon": "MuiButton-startIcon", + "text": "MuiButton-text", + "textPrimary": "MuiButton-textPrimary", + "textSecondary": "MuiButton-textSecondary", + "textSizeLarge": "MuiButton-textSizeLarge", + "textSizeSmall": "MuiButton-textSizeSmall", + } + } + onClick={[Function]} + > + <WithStyles(ForwardRef(ButtonBase)) + aria-label="challenge.card_done.final_defi_view" + className="MuiButton-root btn-secondary-negative grey-border MuiButton-text" + component="button" + disabled={false} + focusRipple={true} + focusVisibleClassName="Mui-focusVisible" + onClick={[Function]} + type="button" + > + <ForwardRef(ButtonBase) + aria-label="challenge.card_done.final_defi_view" + className="MuiButton-root btn-secondary-negative grey-border MuiButton-text" + classes={ + Object { + "disabled": "Mui-disabled", + "focusVisible": "Mui-focusVisible", + "root": "MuiButtonBase-root", + } + } + component="button" + disabled={false} + focusRipple={true} + focusVisibleClassName="Mui-focusVisible" + onClick={[Function]} + type="button" + > + <button + aria-label="challenge.card_done.final_defi_view" + className="MuiButtonBase-root MuiButton-root btn-secondary-negative grey-border MuiButton-text" + disabled={false} + onBlur={[Function]} + onClick={[Function]} + onDragLeave={[Function]} + onFocus={[Function]} + onKeyDown={[Function]} + onKeyUp={[Function]} + onMouseDown={[Function]} + onMouseLeave={[Function]} + onMouseUp={[Function]} + onTouchEnd={[Function]} + onTouchMove={[Function]} + onTouchStart={[Function]} + tabIndex={0} + type="button" + > + <span + className="MuiButton-label text-15-bold" + > + challenge.card_done.final_defi_view + </span> + <WithStyles(memo) + center={false} + > + <ForwardRef(TouchRipple) + center={false} + classes={ + Object { + "child": "MuiTouchRipple-child", + "childLeaving": "MuiTouchRipple-childLeaving", + "childPulsate": "MuiTouchRipple-childPulsate", + "ripple": "MuiTouchRipple-ripple", + "ripplePulsate": "MuiTouchRipple-ripplePulsate", + "rippleVisible": "MuiTouchRipple-rippleVisible", + "root": "MuiTouchRipple-root", + } + } + > + <span + className="MuiTouchRipple-root" + > + <TransitionGroup + childFactory={[Function]} + component={null} + exit={true} + /> + </span> + </ForwardRef(TouchRipple)> + </WithStyles(memo)> + </button> + </ForwardRef(ButtonBase)> + </WithStyles(ForwardRef(ButtonBase))> + </ForwardRef(Button)> + </WithStyles(ForwardRef(Button))> + <WithStyles(ForwardRef(Button)) + aria-label="challenge.card_done.reset_defi" + classes={ + Object { + "label": "text-15-bold", + "root": "btn-secondary-negative grey-border", + } + } + disabled={false} + onClick={[Function]} + > + <ForwardRef(Button) + aria-label="challenge.card_done.reset_defi" + classes={ + Object { + "colorInherit": "MuiButton-colorInherit", + "contained": "MuiButton-contained", + "containedPrimary": "MuiButton-containedPrimary", + "containedSecondary": "MuiButton-containedSecondary", + "containedSizeLarge": "MuiButton-containedSizeLarge", + "containedSizeSmall": "MuiButton-containedSizeSmall", + "disableElevation": "MuiButton-disableElevation", + "disabled": "Mui-disabled", + "endIcon": "MuiButton-endIcon", + "focusVisible": "Mui-focusVisible", + "fullWidth": "MuiButton-fullWidth", + "iconSizeLarge": "MuiButton-iconSizeLarge", + "iconSizeMedium": "MuiButton-iconSizeMedium", + "iconSizeSmall": "MuiButton-iconSizeSmall", + "label": "MuiButton-label text-15-bold", + "outlined": "MuiButton-outlined", + "outlinedPrimary": "MuiButton-outlinedPrimary", + "outlinedSecondary": "MuiButton-outlinedSecondary", + "outlinedSizeLarge": "MuiButton-outlinedSizeLarge", + "outlinedSizeSmall": "MuiButton-outlinedSizeSmall", + "root": "MuiButton-root btn-secondary-negative grey-border", + "sizeLarge": "MuiButton-sizeLarge", + "sizeSmall": "MuiButton-sizeSmall", + "startIcon": "MuiButton-startIcon", + "text": "MuiButton-text", + "textPrimary": "MuiButton-textPrimary", + "textSecondary": "MuiButton-textSecondary", + "textSizeLarge": "MuiButton-textSizeLarge", + "textSizeSmall": "MuiButton-textSizeSmall", + } + } + disabled={false} + onClick={[Function]} + > + <WithStyles(ForwardRef(ButtonBase)) + aria-label="challenge.card_done.reset_defi" + className="MuiButton-root btn-secondary-negative grey-border MuiButton-text" + component="button" + disabled={false} + focusRipple={true} + focusVisibleClassName="Mui-focusVisible" + onClick={[Function]} + type="button" + > + <ForwardRef(ButtonBase) + aria-label="challenge.card_done.reset_defi" + className="MuiButton-root btn-secondary-negative grey-border MuiButton-text" + classes={ + Object { + "disabled": "Mui-disabled", + "focusVisible": "Mui-focusVisible", + "root": "MuiButtonBase-root", + } + } + component="button" + disabled={false} + focusRipple={true} + focusVisibleClassName="Mui-focusVisible" + onClick={[Function]} + type="button" + > + <button + aria-label="challenge.card_done.reset_defi" + className="MuiButtonBase-root MuiButton-root btn-secondary-negative grey-border MuiButton-text" + disabled={false} + onBlur={[Function]} + onClick={[Function]} + onDragLeave={[Function]} + onFocus={[Function]} + onKeyDown={[Function]} + onKeyUp={[Function]} + onMouseDown={[Function]} + onMouseLeave={[Function]} + onMouseUp={[Function]} + onTouchEnd={[Function]} + onTouchMove={[Function]} + onTouchStart={[Function]} + tabIndex={0} + type="button" + > + <span + className="MuiButton-label text-15-bold" + > + challenge.card_done.reset_defi + </span> + <WithStyles(memo) + center={false} + > + <ForwardRef(TouchRipple) + center={false} + classes={ + Object { + "child": "MuiTouchRipple-child", + "childLeaving": "MuiTouchRipple-childLeaving", + "childPulsate": "MuiTouchRipple-childPulsate", + "ripple": "MuiTouchRipple-ripple", + "ripplePulsate": "MuiTouchRipple-ripplePulsate", + "rippleVisible": "MuiTouchRipple-rippleVisible", + "root": "MuiTouchRipple-root", + } + } + > + <span + className="MuiTouchRipple-root" + > + <TransitionGroup + childFactory={[Function]} + component={null} + exit={true} + /> + </span> + </ForwardRef(TouchRipple)> + </WithStyles(memo)> + </button> + </ForwardRef(ButtonBase)> + </WithStyles(ForwardRef(ButtonBase))> + </ForwardRef(Button)> + </WithStyles(ForwardRef(Button))> + </div> + </div> + </ChallengeCardDone> +</Provider> +`; diff --git a/src/components/Challenge/challengeCardDone.scss b/src/components/Challenge/ChallengeCardDone/challengeCardDone.scss similarity index 70% rename from src/components/Challenge/challengeCardDone.scss rename to src/components/Challenge/ChallengeCardDone/challengeCardDone.scss index 1b7fd3ba8d9e505f853c63afce38cf8ecf4a6718..d4ff21eb97b218ed8b8f6936b84a6d7bf176e641 100644 --- a/src/components/Challenge/challengeCardDone.scss +++ b/src/components/Challenge/ChallengeCardDone/challengeCardDone.scss @@ -1,5 +1,5 @@ -@import '../../styles/base/typo-variables'; -@import '../../styles/base/color'; +@import 'src/styles/base/typo-variables'; +@import 'src/styles/base/color'; .cardContent { &.cardDone { @@ -41,10 +41,19 @@ .statsResult { text-align: center; } - .review-btn { - padding: 0.625rem; - margin: 0; - border: 1px solid $grey-bright; + .buttons { + display: flex; + flex-direction: column; + gap: 8px; + width: 100%; + + button { + padding: 0.625rem; + margin: 0; + &.grey-border { + border: 1px solid $grey-bright; + } + } } } } diff --git a/src/components/Challenge/ChallengeCardLast.spec.tsx b/src/components/Challenge/ChallengeCardLast.spec.tsx deleted file mode 100644 index be445a7a2433ef341f63e569ae1b5e09c0df31ef..0000000000000000000000000000000000000000 --- a/src/components/Challenge/ChallengeCardLast.spec.tsx +++ /dev/null @@ -1,56 +0,0 @@ -import { mount } from 'enzyme' -import toJson from 'enzyme-to-json' -import React from 'react' -import { Provider } from 'react-redux' -import configureStore from 'redux-mock-store' -import { globalStateData } from '../../../tests/__mocks__/globalStateData.mock' -import { waitForComponentToPaint } from '../../../tests/__mocks__/testUtils' -import ChallengeCardLast from './ChallengeCardLast' - -// Value coming from jest.config -declare let __SAU_IDEA_DIRECT_LINK__: string - -jest.mock('cozy-ui/transpiled/react/I18n', () => { - return { - useI18n: jest.fn(() => { - return { - t: (str: string) => str, - } - }), - } -}) - -const mockStore = configureStore([]) - -describe('ChallengeCardLast component', () => { - const store = mockStore({ - ecolyo: { - global: globalStateData, - }, - }) - - it('should be rendered correctly', async () => { - const wrapper = mount( - <Provider store={store}> - <ChallengeCardLast /> - </Provider> - ) - await waitForComponentToPaint(wrapper) - expect(toJson(wrapper)).toMatchSnapshot() - }) - - it('should open SAU new idea link', () => { - global.open = jest.fn() - - const wrapper = mount( - <Provider store={store}> - <ChallengeCardLast /> - </Provider> - ) - wrapper.find('.btn_lastCard').first().simulate('click') - expect(window.open).toBeCalledTimes(1) - expect(global.open).toHaveBeenCalledWith( - `${__SAU_IDEA_DIRECT_LINK__}?version=0.0.0` - ) - }) -}) diff --git a/src/components/Challenge/ChallengeCardLast/ChallengeCardLast.spec.tsx b/src/components/Challenge/ChallengeCardLast/ChallengeCardLast.spec.tsx new file mode 100644 index 0000000000000000000000000000000000000000..7cd4d37df410927a86fa7683458f2d2a8465521e --- /dev/null +++ b/src/components/Challenge/ChallengeCardLast/ChallengeCardLast.spec.tsx @@ -0,0 +1,25 @@ +import { mount } from 'enzyme' +import toJson from 'enzyme-to-json' +import React from 'react' +import ChallengeCardLast from './ChallengeCardLast' + +// Value coming from jest.config +declare let __SAU_IDEA_DIRECT_LINK__: string + +describe('ChallengeCardLast component', () => { + it('should be rendered correctly', async () => { + const wrapper = mount(<ChallengeCardLast />) + expect(toJson(wrapper)).toMatchSnapshot() + }) + + it('should open SAU new idea link', () => { + global.open = jest.fn() + + const wrapper = mount(<ChallengeCardLast />) + wrapper.find('.btn_lastCard').first().simulate('click') + expect(window.open).toHaveBeenCalledTimes(1) + expect(global.open).toHaveBeenCalledWith( + `${__SAU_IDEA_DIRECT_LINK__}?version=0.0.0` + ) + }) +}) diff --git a/src/components/Challenge/ChallengeCardLast.tsx b/src/components/Challenge/ChallengeCardLast/ChallengeCardLast.tsx similarity index 100% rename from src/components/Challenge/ChallengeCardLast.tsx rename to src/components/Challenge/ChallengeCardLast/ChallengeCardLast.tsx diff --git a/src/components/Challenge/ChallengeCardLast/__snapshots__/ChallengeCardLast.spec.tsx.snap b/src/components/Challenge/ChallengeCardLast/__snapshots__/ChallengeCardLast.spec.tsx.snap new file mode 100644 index 0000000000000000000000000000000000000000..2242865caf89c2e64c3b73bf1ffd5d778fcfb83a --- /dev/null +++ b/src/components/Challenge/ChallengeCardLast/__snapshots__/ChallengeCardLast.spec.tsx.snap @@ -0,0 +1,188 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`ChallengeCardLast component should be rendered correctly 1`] = ` +<ChallengeCardLast> + <div + className="cardLast" + > + <StyledIcon + icon="test-file-stub" + size={62} + > + <Icon + aria-hidden={true} + icon="test-file-stub" + size={62} + spin={false} + > + <Component + aria-hidden={true} + className="styles__icon___23x3R" + height={62} + style={Object {}} + width={62} + > + <svg + aria-hidden={true} + className="styles__icon___23x3R" + height={62} + style={Object {}} + width={62} + > + <use + xlinkHref="#test-file-stub" + /> + </svg> + </Component> + </Icon> + </StyledIcon> + <div + className="content" + > + <div + className="text-22-bold title-last" + > + challenge.card_last.title + </div> + <div + className="text-18-normal message" + > + challenge.card_last.message1 + </div> + </div> + <WithStyles(ForwardRef(Button)) + aria-label="challenge.card_last.button" + className="btn1" + classes={ + Object { + "label": "text-15-bold", + "root": "btn-secondary-negative btn_lastCard", + } + } + onClick={[Function]} + > + <ForwardRef(Button) + aria-label="challenge.card_last.button" + className="btn1" + classes={ + Object { + "colorInherit": "MuiButton-colorInherit", + "contained": "MuiButton-contained", + "containedPrimary": "MuiButton-containedPrimary", + "containedSecondary": "MuiButton-containedSecondary", + "containedSizeLarge": "MuiButton-containedSizeLarge", + "containedSizeSmall": "MuiButton-containedSizeSmall", + "disableElevation": "MuiButton-disableElevation", + "disabled": "Mui-disabled", + "endIcon": "MuiButton-endIcon", + "focusVisible": "Mui-focusVisible", + "fullWidth": "MuiButton-fullWidth", + "iconSizeLarge": "MuiButton-iconSizeLarge", + "iconSizeMedium": "MuiButton-iconSizeMedium", + "iconSizeSmall": "MuiButton-iconSizeSmall", + "label": "MuiButton-label text-15-bold", + "outlined": "MuiButton-outlined", + "outlinedPrimary": "MuiButton-outlinedPrimary", + "outlinedSecondary": "MuiButton-outlinedSecondary", + "outlinedSizeLarge": "MuiButton-outlinedSizeLarge", + "outlinedSizeSmall": "MuiButton-outlinedSizeSmall", + "root": "MuiButton-root btn-secondary-negative btn_lastCard", + "sizeLarge": "MuiButton-sizeLarge", + "sizeSmall": "MuiButton-sizeSmall", + "startIcon": "MuiButton-startIcon", + "text": "MuiButton-text", + "textPrimary": "MuiButton-textPrimary", + "textSecondary": "MuiButton-textSecondary", + "textSizeLarge": "MuiButton-textSizeLarge", + "textSizeSmall": "MuiButton-textSizeSmall", + } + } + onClick={[Function]} + > + <WithStyles(ForwardRef(ButtonBase)) + aria-label="challenge.card_last.button" + className="MuiButton-root btn-secondary-negative btn_lastCard MuiButton-text btn1" + component="button" + disabled={false} + focusRipple={true} + focusVisibleClassName="Mui-focusVisible" + onClick={[Function]} + type="button" + > + <ForwardRef(ButtonBase) + aria-label="challenge.card_last.button" + className="MuiButton-root btn-secondary-negative btn_lastCard MuiButton-text btn1" + classes={ + Object { + "disabled": "Mui-disabled", + "focusVisible": "Mui-focusVisible", + "root": "MuiButtonBase-root", + } + } + component="button" + disabled={false} + focusRipple={true} + focusVisibleClassName="Mui-focusVisible" + onClick={[Function]} + type="button" + > + <button + aria-label="challenge.card_last.button" + className="MuiButtonBase-root MuiButton-root btn-secondary-negative btn_lastCard MuiButton-text btn1" + disabled={false} + onBlur={[Function]} + onClick={[Function]} + onDragLeave={[Function]} + onFocus={[Function]} + onKeyDown={[Function]} + onKeyUp={[Function]} + onMouseDown={[Function]} + onMouseLeave={[Function]} + onMouseUp={[Function]} + onTouchEnd={[Function]} + onTouchMove={[Function]} + onTouchStart={[Function]} + tabIndex={0} + type="button" + > + <span + className="MuiButton-label text-15-bold" + > + challenge.card_last.button + </span> + <WithStyles(memo) + center={false} + > + <ForwardRef(TouchRipple) + center={false} + classes={ + Object { + "child": "MuiTouchRipple-child", + "childLeaving": "MuiTouchRipple-childLeaving", + "childPulsate": "MuiTouchRipple-childPulsate", + "ripple": "MuiTouchRipple-ripple", + "ripplePulsate": "MuiTouchRipple-ripplePulsate", + "rippleVisible": "MuiTouchRipple-rippleVisible", + "root": "MuiTouchRipple-root", + } + } + > + <span + className="MuiTouchRipple-root" + > + <TransitionGroup + childFactory={[Function]} + component={null} + exit={true} + /> + </span> + </ForwardRef(TouchRipple)> + </WithStyles(memo)> + </button> + </ForwardRef(ButtonBase)> + </WithStyles(ForwardRef(ButtonBase))> + </ForwardRef(Button)> + </WithStyles(ForwardRef(Button))> + </div> +</ChallengeCardLast> +`; diff --git a/src/components/Challenge/challengeCardLast.scss b/src/components/Challenge/ChallengeCardLast/challengeCardLast.scss similarity index 88% rename from src/components/Challenge/challengeCardLast.scss rename to src/components/Challenge/ChallengeCardLast/challengeCardLast.scss index b74e69be70cb5314442ea74c54cfcb517b46ac3f..261e1bd0c3943cf0963800bd0ab74fb3c9c95790 100644 --- a/src/components/Challenge/challengeCardLast.scss +++ b/src/components/Challenge/ChallengeCardLast/challengeCardLast.scss @@ -1,5 +1,5 @@ -@import '../../styles/base/typo-variables'; -@import '../../styles/base/color'; +@import 'src/styles/base/typo-variables'; +@import 'src/styles/base/color'; .cardLast { width: 100%; diff --git a/src/components/Challenge/ChallengeCardLocked.spec.tsx b/src/components/Challenge/ChallengeCardLocked/ChallengeCardLocked.spec.tsx similarity index 58% rename from src/components/Challenge/ChallengeCardLocked.spec.tsx rename to src/components/Challenge/ChallengeCardLocked/ChallengeCardLocked.spec.tsx index e1a908384465a0664bf0cbaeaea20359df89cb31..0cf83e9a1b06f17772d8146401b3366ac861c282 100644 --- a/src/components/Challenge/ChallengeCardLocked.spec.tsx +++ b/src/components/Challenge/ChallengeCardLocked/ChallengeCardLocked.spec.tsx @@ -1,18 +1,8 @@ import { shallow } from 'enzyme' import React from 'react' -import { userChallengeData } from '../../../tests/__mocks__/userChallengeData.mock' +import { userChallengeData } from 'tests/__mocks__/userChallengeData.mock' import ChallengeCardLocked from './ChallengeCardLocked' -jest.mock('cozy-ui/transpiled/react/I18n', () => { - return { - useI18n: jest.fn(() => { - return { - t: (str: string) => str, - } - }), - } -}) - describe('ChallengeCardLocked component', () => { it('should be rendered correctly', () => { const component = shallow( diff --git a/src/components/Challenge/ChallengeCardLocked.tsx b/src/components/Challenge/ChallengeCardLocked/ChallengeCardLocked.tsx similarity index 100% rename from src/components/Challenge/ChallengeCardLocked.tsx rename to src/components/Challenge/ChallengeCardLocked/ChallengeCardLocked.tsx diff --git a/src/components/Challenge/__snapshots__/ChallengeCardLocked.spec.tsx.snap b/src/components/Challenge/ChallengeCardLocked/__snapshots__/ChallengeCardLocked.spec.tsx.snap similarity index 100% rename from src/components/Challenge/__snapshots__/ChallengeCardLocked.spec.tsx.snap rename to src/components/Challenge/ChallengeCardLocked/__snapshots__/ChallengeCardLocked.spec.tsx.snap diff --git a/src/components/Challenge/challengeCardLocked.scss b/src/components/Challenge/ChallengeCardLocked/challengeCardLocked.scss similarity index 88% rename from src/components/Challenge/challengeCardLocked.scss rename to src/components/Challenge/ChallengeCardLocked/challengeCardLocked.scss index 279b8f1acfdac4be950684ba27e303a0078009d4..df07cacadc4ab83b783913ca28f299e2578d5dbe 100644 --- a/src/components/Challenge/challengeCardLocked.scss +++ b/src/components/Challenge/ChallengeCardLocked/challengeCardLocked.scss @@ -1,4 +1,4 @@ -@import '../../styles/base/color'; +@import 'src/styles/base/color'; .cardLocked { filter: drop-shadow(0px 4px 16px rgba(0, 0, 0, 0.55)); diff --git a/src/components/Challenge/ChallengeCardOnGoing.tsx b/src/components/Challenge/ChallengeCardOnGoing/ChallengeCardOnGoing.tsx similarity index 92% rename from src/components/Challenge/ChallengeCardOnGoing.tsx rename to src/components/Challenge/ChallengeCardOnGoing/ChallengeCardOnGoing.tsx index 54eeab6a7d2bceb6d7d9874a3d591ad045c40ba4..9d449c427f23834fe7568d805ffb4982e8608e4f 100644 --- a/src/components/Challenge/ChallengeCardOnGoing.tsx +++ b/src/components/Challenge/ChallengeCardOnGoing/ChallengeCardOnGoing.tsx @@ -7,24 +7,25 @@ import defaultIcon from 'assets/icons/visu/duel/default.svg' import lockedDuel from 'assets/icons/visu/duel/locked.svg' import classNames from 'classnames' import StyledIcon from 'components/CommonKit/Icon/StyledIcon' +import StarsContainer from 'components/CommonKit/StarsContainer/StarsContainer' import Loader from 'components/Loader/Loader' -import { Client, useClient } from 'cozy-client' +import { useClient } from 'cozy-client' import { useI18n } from 'cozy-ui/transpiled/react/I18n' -import { UserActionState } from 'enum/userAction.enum' -import { UserChallengeUpdateFlag } from 'enum/userChallenge.enum' -import { UserDuelState } from 'enum/userDuel.enum' -import { UserExplorationState } from 'enum/userExploration.enum' -import { UserQuizState } from 'enum/userQuiz.enum' +import { + UserActionState, + UserChallengeUpdateFlag, + UserDuelState, + UserExplorationState, + UserQuizState, +} from 'enums' import { UserChallenge } from 'models' -import React, { Dispatch, useCallback, useEffect, useState } from 'react' -import { useDispatch, useSelector } from 'react-redux' +import React, { useCallback, useEffect, useState } from 'react' import { useNavigate } from 'react-router-dom' import ChallengeService from 'services/challenge.service' -import { AppActionsTypes, AppStore } from 'store' import { updateUserChallengeList } from 'store/challenge/challenge.slice' +import { useAppDispatch, useAppSelector } from 'store/hooks' import { getChallengeTitleWithLineReturn, importIconById } from 'utils/utils' -import ChallengeNoFluidModal from './ChallengeNoFluidModal' -import StarsContainer from './StarsContainer' +import ChallengeNoFluidModal from '../ChallengeNoFluidModal/ChallengeNoFluidModal' import './challengeCardOnGoing.scss' const ChallengeCardOnGoing = ({ @@ -32,18 +33,18 @@ const ChallengeCardOnGoing = ({ }: { userChallenge: UserChallenge }) => { - const client: Client = useClient() const { t } = useI18n() - const dispatch = useDispatch<Dispatch<AppActionsTypes>>() + const client = useClient() const navigate = useNavigate() + const dispatch = useAppDispatch() + const { + challenge: { currentDataload }, + global: { fluidTypes, fluidStatus }, + } = useAppSelector(state => state.ecolyo) const [isOneFluidUp, setIsOneFluidUp] = useState<boolean>(true) const [challengeIcon, setChallengeIcon] = useState<string>(defaultIcon) const [isDone, setIsDone] = useState<boolean>(false) const [isLoading, setIsLoading] = useState<boolean>(false) - const { - challenge: { currentDataload }, - global: { fluidTypes, fluidStatus }, - } = useSelector((state: AppStore) => state.ecolyo) const { progress: { actionProgress, explorationProgress, quizProgress }, target, @@ -292,7 +293,7 @@ const ChallengeCardOnGoing = ({ ) } else { return ( - <Button className={`smallCard duelCard duelLocked`} disabled> + <Button className="smallCard duelCard duelLocked" disabled> <div className="starCount"> <StyledIcon icon={circleStar} size={30} /> <span className="blueNumber"> diff --git a/src/components/Challenge/challengeCardOnGoing.scss b/src/components/Challenge/ChallengeCardOnGoing/challengeCardOnGoing.scss similarity index 96% rename from src/components/Challenge/challengeCardOnGoing.scss rename to src/components/Challenge/ChallengeCardOnGoing/challengeCardOnGoing.scss index ee4236859799c6886e1fcd39d931126570c0a7e0..7c00250c8078cc0077acb4a9ab0151b781e68a59 100644 --- a/src/components/Challenge/challengeCardOnGoing.scss +++ b/src/components/Challenge/ChallengeCardOnGoing/challengeCardOnGoing.scss @@ -1,10 +1,10 @@ -@import '../../styles/base/typo-variables'; -@import '../../styles/base/color'; +@import 'src/styles/base/typo-variables'; +@import 'src/styles/base/color'; .cardContent { background: transparent; &.onGoing { - border: 1px solid #e0e0e0; + border: 1px solid $grey-bright; background: inherit !important; .challengeTitle { margin-top: 0; diff --git a/src/components/Challenge/ChallengeCardUnlocked.spec.tsx b/src/components/Challenge/ChallengeCardUnlocked/ChallengeCardUnlocked.spec.tsx similarity index 58% rename from src/components/Challenge/ChallengeCardUnlocked.spec.tsx rename to src/components/Challenge/ChallengeCardUnlocked/ChallengeCardUnlocked.spec.tsx index d705c58d051219aff5aecefd1eb41bc1e62b1409..04014cf96f27ac15071b2dab80342001f909dbdf 100644 --- a/src/components/Challenge/ChallengeCardUnlocked.spec.tsx +++ b/src/components/Challenge/ChallengeCardUnlocked/ChallengeCardUnlocked.spec.tsx @@ -1,72 +1,45 @@ -import defaultIcon from 'assets/icons/visu/challenge/challengeLocked.svg' -import { FluidType } from 'enum/fluid.enum' +import { Button } from '@material-ui/core' +import { FluidType } from 'enums' import { mount } from 'enzyme' import React from 'react' import { Provider } from 'react-redux' -import configureStore from 'redux-mock-store' import UsageEventService from 'services/usageEvent.service' -import { globalStateData } from '../../../tests/__mocks__/globalStateData.mock' -import { userChallengeData } from '../../../tests/__mocks__/userChallengeData.mock' +import { + createMockEcolyoStore, + mockChallengeState, + mockGlobalState, +} from 'tests/__mocks__/store' +import { waitForComponentToPaint } from 'tests/__mocks__/testUtils' +import { userChallengeData } from 'tests/__mocks__/userChallengeData.mock' +import ChallengeNoFluidModal from '../ChallengeNoFluidModal/ChallengeNoFluidModal' import ChallengeCardUnlocked from './ChallengeCardUnlocked' -import ChallengeNoFluidModal from './ChallengeNoFluidModal' - -jest.mock('cozy-ui/transpiled/react/I18n', () => { - return { - useI18n: jest.fn(() => { - return { - t: (str: string) => str, - } - }), - } -}) const mockStartUserChallenge = jest.fn() jest.mock('services/challenge.service', () => { - return jest.fn(() => { - return { - startUserChallenge: mockStartUserChallenge, - } - }) -}) -const mockImportIconById = jest.fn(() => defaultIcon) -jest.mock('utils/utils', () => { - return { - importIconById: jest.fn(() => mockImportIconById), - getChallengeTitleWithLineReturn: jest.fn(() => 'Challenge 1'), - } + return jest.fn(() => ({ + startUserChallenge: mockStartUserChallenge, + })) }) + jest.mock('services/usageEvent.service') const mockAddEvent = jest.fn() UsageEventService.addEvent = mockAddEvent -const mockStore = configureStore([]) - describe('ChallengeCardUnlocked component', () => { + const store = createMockEcolyoStore() it('should be rendered correctly', () => { - const store = mockStore({ - ecolyo: { - global: globalStateData, - }, - }) const wrapper = mount( <Provider store={store}> <ChallengeCardUnlocked userChallenge={userChallengeData[0]} /> </Provider> ) - expect(wrapper.find('.challengeTitle').text()).toEqual( - userChallengeData[0].title - ) + expect(wrapper.find('.challengeTitle').text()).toEqual('Simone\nVEILLE') expect(wrapper.find('.btn-duel-active').exists()).toBeTruthy() expect(wrapper.find(ChallengeNoFluidModal).exists()).toBeTruthy() expect(wrapper.find(ChallengeNoFluidModal).prop('open')).toBeFalsy() }) it('should display ChallengeNoFluidModal when launching challenge without configured fluid', () => { - const store = mockStore({ - ecolyo: { - global: globalStateData, - }, - }) const wrapper = mount( <Provider store={store}> <ChallengeCardUnlocked userChallenge={userChallengeData[0]} /> @@ -78,15 +51,12 @@ describe('ChallengeCardUnlocked component', () => { }) it('should not display ChallengeNoFluidModal and update userChallenge when launching challenge with configured fluid', () => { - const updateGlobalStoreData = { - ...globalStateData, - fluidTypes: [FluidType.ELECTRICITY], - fluidStatus: [{ status: 200 }], - } - const store = mockStore({ - ecolyo: { - global: updateGlobalStoreData, + const store = createMockEcolyoStore({ + global: { + fluidTypes: [FluidType.ELECTRICITY], + fluidStatus: [{ ...mockGlobalState.fluidStatus[0], status: 200 }], }, + challenge: mockChallengeState, }) const wrapper = mount( <Provider store={store}> @@ -98,4 +68,22 @@ describe('ChallengeCardUnlocked component', () => { expect(wrapper.find(ChallengeNoFluidModal).prop('open')).toBeFalsy() expect(mockStartUserChallenge).toHaveBeenCalledWith(userChallengeData[0]) }) + + it('should not be able to launch challenge if another one is active', () => { + const store = createMockEcolyoStore({ + global: mockGlobalState, + challenge: { + ...mockChallengeState, + currentChallenge: userChallengeData[1], + }, + }) + const wrapper = mount( + <Provider store={store}> + <ChallengeCardUnlocked userChallenge={userChallengeData[0]} /> + </Provider> + ) + waitForComponentToPaint(wrapper) + const resetButton = wrapper.find(Button).last() + expect(resetButton.prop('disabled')).toBe(true) + }) }) diff --git a/src/components/Challenge/ChallengeCardUnlocked.tsx b/src/components/Challenge/ChallengeCardUnlocked/ChallengeCardUnlocked.tsx similarity index 83% rename from src/components/Challenge/ChallengeCardUnlocked.tsx rename to src/components/Challenge/ChallengeCardUnlocked/ChallengeCardUnlocked.tsx index 7d65fbab8ad380eee976e14b2135261760da04d4..97aad463f6ff9bdea280ea1e81ab68f3144b027e 100644 --- a/src/components/Challenge/ChallengeCardUnlocked.tsx +++ b/src/components/Challenge/ChallengeCardUnlocked/ChallengeCardUnlocked.tsx @@ -1,19 +1,17 @@ import Button from '@material-ui/core/Button' import defaultIcon from 'assets/icons/visu/challenge/challengeLocked.svg' import StyledIcon from 'components/CommonKit/Icon/StyledIcon' -import { Client, useClient } from 'cozy-client' +import { useClient } from 'cozy-client' import { useI18n } from 'cozy-ui/transpiled/react/I18n' -import { FluidState } from 'enum/fluid.enum' -import { UsageEventType } from 'enum/usageEvent.enum' +import { FluidState, UsageEventType } from 'enums' import { UserChallenge } from 'models' -import React, { Dispatch, useCallback, useEffect, useState } from 'react' -import { useDispatch, useSelector } from 'react-redux' +import React, { useCallback, useEffect, useState } from 'react' import ChallengeService from 'services/challenge.service' import UsageEventService from 'services/usageEvent.service' -import { AppActionsTypes, AppStore } from 'store' import { updateUserChallengeList } from 'store/challenge/challenge.slice' +import { useAppDispatch, useAppSelector } from 'store/hooks' import { getChallengeTitleWithLineReturn, importIconById } from 'utils/utils' -import ChallengeNoFluidModal from './ChallengeNoFluidModal' +import ChallengeNoFluidModal from '../ChallengeNoFluidModal/ChallengeNoFluidModal' import './challengeCardUnlocked.scss' const ChallengeCardUnlocked = ({ @@ -21,14 +19,14 @@ const ChallengeCardUnlocked = ({ }: { userChallenge: UserChallenge }) => { - const client: Client = useClient() - const dispatch = useDispatch<Dispatch<AppActionsTypes>>() const { t } = useI18n() - + const client = useClient() + const { + challenge: { currentChallenge }, + global: { fluidTypes, fluidStatus }, + } = useAppSelector(state => state.ecolyo) + const dispatch = useAppDispatch() const [openNoFluidModal, setopenNoFluidModal] = useState(false) - const { fluidTypes, fluidStatus } = useSelector( - (state: AppStore) => state.ecolyo.global - ) const [challengeIcon, setChallengeIcon] = useState(defaultIcon) let statusRequirementOk = false @@ -94,6 +92,7 @@ const ChallengeCardUnlocked = ({ root: 'btn-duel-active', label: 'text-16-bold', }} + disabled={currentChallenge !== null} > {t('challenge.card_unlocked.button_launch')} </Button> diff --git a/src/components/Challenge/challengeCardUnlocked.scss b/src/components/Challenge/ChallengeCardUnlocked/challengeCardUnlocked.scss similarity index 87% rename from src/components/Challenge/challengeCardUnlocked.scss rename to src/components/Challenge/ChallengeCardUnlocked/challengeCardUnlocked.scss index 16e4bf2bbf4e99045335009969c4fd28afe40420..8bfb434765f3c984b73688c66c7404f51adb41a1 100644 --- a/src/components/Challenge/challengeCardUnlocked.scss +++ b/src/components/Challenge/ChallengeCardUnlocked/challengeCardUnlocked.scss @@ -1,4 +1,4 @@ -@import '../../styles/base/color'; +@import 'src/styles/base/color'; .modal-overlay { width: 100%; @@ -10,7 +10,6 @@ filter: drop-shadow(0px 4px 16px rgba(0, 0, 0, 0.55)); button.btn-duel-active { - margin: auto; padding: 1.2rem 1.5rem; } .challengeIcon { diff --git a/src/components/Challenge/ChallengeNoFluidModal.spec.tsx b/src/components/Challenge/ChallengeNoFluidModal/ChallengeNoFluidModal.spec.tsx similarity index 69% rename from src/components/Challenge/ChallengeNoFluidModal.spec.tsx rename to src/components/Challenge/ChallengeNoFluidModal/ChallengeNoFluidModal.spec.tsx index 8e92291ead926ea84d3e21d875936e2f310ce18a..310572994d34e6d7e4e3a479e080c996d8c603fc 100644 --- a/src/components/Challenge/ChallengeNoFluidModal.spec.tsx +++ b/src/components/Challenge/ChallengeNoFluidModal/ChallengeNoFluidModal.spec.tsx @@ -2,16 +2,6 @@ import { shallow } from 'enzyme' import React from 'react' import ChallengeNoFluidModal from './ChallengeNoFluidModal' -jest.mock('cozy-ui/transpiled/react/I18n', () => { - return { - useI18n: jest.fn(() => { - return { - t: (str: string) => str, - } - }), - } -}) - describe('ChallengeNoFluidModal component', () => { it('should be rendered correctly opened', () => { const handleClose = jest.fn() diff --git a/src/components/Challenge/ChallengeNoFluidModal.tsx b/src/components/Challenge/ChallengeNoFluidModal/ChallengeNoFluidModal.tsx similarity index 94% rename from src/components/Challenge/ChallengeNoFluidModal.tsx rename to src/components/Challenge/ChallengeNoFluidModal/ChallengeNoFluidModal.tsx index 46d0057675c15f5364de798f37f15ec6d2183ca4..b696d9722b077d6c40d0a711658e2a2f47fc215a 100644 --- a/src/components/Challenge/ChallengeNoFluidModal.tsx +++ b/src/components/Challenge/ChallengeNoFluidModal/ChallengeNoFluidModal.tsx @@ -22,13 +22,13 @@ const ChallengeNoFluidModal = ({ onClose={(event, reason): void => { event && reason !== 'backdropClick' && handleCloseClick() }} - aria-labelledby={'accessibility-title'} + aria-labelledby="accessibility-title" classes={{ root: 'modal-root', paper: 'modal-paper', }} > - <div id={'accessibility-title'}> + <div id="accessibility-title"> {t('challenge_no_fluid_modal.accessibility.window_title')} </div> <div className="noFluidModal"> diff --git a/src/components/Challenge/__snapshots__/ChallengeNoFluidModal.spec.tsx.snap b/src/components/Challenge/ChallengeNoFluidModal/__snapshots__/ChallengeNoFluidModal.spec.tsx.snap similarity index 100% rename from src/components/Challenge/__snapshots__/ChallengeNoFluidModal.spec.tsx.snap rename to src/components/Challenge/ChallengeNoFluidModal/__snapshots__/ChallengeNoFluidModal.spec.tsx.snap diff --git a/src/components/Challenge/challengeNoFluidModal.scss b/src/components/Challenge/ChallengeNoFluidModal/challengeNoFluidModal.scss similarity index 93% rename from src/components/Challenge/challengeNoFluidModal.scss rename to src/components/Challenge/ChallengeNoFluidModal/challengeNoFluidModal.scss index e956f006f55cc12f10ff93987397e9ec987738fd..01b40b1757680f8a4f4ecf4f5bcdd2fe6c5ec132 100644 --- a/src/components/Challenge/challengeNoFluidModal.scss +++ b/src/components/Challenge/ChallengeNoFluidModal/challengeNoFluidModal.scss @@ -1,4 +1,4 @@ -@import '../../styles/base/typo-variables'; +@import 'src/styles/base/typo-variables'; .noFluidModal { padding: 1rem; diff --git a/src/components/Challenge/ChallengeView.spec.tsx b/src/components/Challenge/ChallengeView.spec.tsx index 1410759a78c71acb190803b725d7442d14ba91d3..1d8f8cb1abce23621b028e2b7b91bbe4d4f0db25 100644 --- a/src/components/Challenge/ChallengeView.spec.tsx +++ b/src/components/Challenge/ChallengeView.spec.tsx @@ -2,40 +2,34 @@ import ChallengeView from 'components/Challenge/ChallengeView' import { mount } from 'enzyme' import toJson from 'enzyme-to-json' import React from 'react' -import * as reactRedux from 'react-redux' -import { challengeStateDataFull } from '../../../tests/__mocks__/challengeStateData.mock' -import { createMockEcolyoStore } from '../../../tests/__mocks__/store' - -const mockUseSelector = jest.spyOn(reactRedux, 'useSelector') - -jest.mock('cozy-ui/transpiled/react/I18n', () => { - return { - useI18n: jest.fn(() => { - return { - t: (str: string) => str, - } - }), - } -}) +import { Provider } from 'react-redux' +import { challengeStateDataFull } from 'tests/__mocks__/challengeStateData.mock' +import { createMockEcolyoStore } from 'tests/__mocks__/store' jest.mock('components/Header/CozyBar', () => 'mock-cozybar') jest.mock('components/Header/Header', () => 'mock-header') jest.mock('components/Content/Content', () => 'mock-content') -jest.mock('components/Challenge/ChallengeCard', () => 'mock-challengecard') +jest.mock( + 'components/Challenge/ChallengeCard/ChallengeCard', + () => 'mock-challengecard' +) +jest.mock( + 'components/Challenge/ChallengeCard/ChallengeCard', + () => 'mock-challengecard' +) describe('ChallengeView component', () => { - const store = createMockEcolyoStore() - beforeEach(() => { - store.clearActions() + const store = createMockEcolyoStore({ + challenge: challengeStateDataFull, }) it('should be rendered correctly', () => { - mockUseSelector.mockReturnValue(challengeStateDataFull) const wrapper = mount( - <reactRedux.Provider store={store}> + <Provider store={store}> <ChallengeView /> - </reactRedux.Provider> + </Provider> ) + expect(toJson(wrapper)).toMatchSnapshot() }) }) diff --git a/src/components/Challenge/ChallengeView.tsx b/src/components/Challenge/ChallengeView.tsx index 95f526de73d4673de4b050e9e3567ca74837688f..b2de63cc4a49ac93f02b48fa8f90b73a2b9c3165 100644 --- a/src/components/Challenge/ChallengeView.tsx +++ b/src/components/Challenge/ChallengeView.tsx @@ -5,35 +5,27 @@ import Content from 'components/Content/Content' import CozyBar from 'components/Header/CozyBar' import Header from 'components/Header/Header' import { useI18n } from 'cozy-ui/transpiled/react/I18n' -import { UserChallengeState } from 'enum/userChallenge.enum' -import { UserChallenge } from 'models' +import { UserChallengeState } from 'enums' import React, { useCallback, useEffect, useState } from 'react' -import { useSelector } from 'react-redux' -import { AppStore } from 'store' -import ChallengeCard from './ChallengeCard' +import { useAppSelector } from 'store/hooks' +import ChallengeCard from './ChallengeCard/ChallengeCard' import './challengeView.scss' const ChallengeView = () => { const { t } = useI18n() - const { userChallengeList } = useSelector( - (state: AppStore) => state.ecolyo.challenge - ) + const { userChallengeList } = useAppSelector(state => state.ecolyo.challenge) const marginPx = 16 const cardWidth = window.outerWidth < 500 ? window.outerWidth - marginPx * 6 : 285 - const cardHeight = window.outerHeight * 0.6 + const cardHeight = window.outerHeight * 0.65 const [headerHeight, setHeaderHeight] = useState<number>(0) const [touchStart, setTouchStart] = useState<number>() const [touchEnd, setTouchEnd] = useState<number>() const [index, setIndex] = useState<number>(0) - const [lastChallengeIndex, setLastChallengeIndex] = useState<number>(0) const [isLastDuelDone, setIsLastDuelDone] = useState<boolean>(false) const [containerTranslation, setContainerTranslation] = useState<number>(marginPx) - const defineHeaderHeight = (height: number) => { - setHeaderHeight(height) - } const resetValues = () => { // Method used to cancel a swipe on a simple click @@ -46,22 +38,14 @@ const ChallengeView = () => { index < userChallengeList.length - 1 || (isLastDuelDone && index < userChallengeList.length) ) { - if (index === 0) - setContainerTranslation( - (prev: number) => prev - cardWidth - marginPx * 1.2 - ) - else if (index >= 1) - setContainerTranslation((prev: number) => prev - cardWidth - marginPx) - else setContainerTranslation((prev: number) => prev - cardWidth) + setContainerTranslation(prev => prev - cardWidth - marginPx) setIndex(prev => prev + 1) } - }, [cardWidth, index, userChallengeList.length]) + }, [cardWidth, index, isLastDuelDone, userChallengeList.length]) const moveSliderLeft = useCallback(() => { if (index > 0) { - if (index >= 1) - setContainerTranslation((prev: number) => prev + cardWidth + marginPx) - else setContainerTranslation((prev: number) => prev + cardWidth) + setContainerTranslation(prev => prev + cardWidth + marginPx) setIndex(prev => prev - 1) } if (index <= 1) { @@ -95,28 +79,20 @@ const ChallengeView = () => { } useEffect(() => { - userChallengeList.forEach((challenge: UserChallenge, i: number) => { - if ( + let currentChallengeIndex = userChallengeList.findIndex( + challenge => challenge.state === UserChallengeState.UNLOCKED || challenge.state === UserChallengeState.ONGOING || challenge.state === UserChallengeState.DUEL - ) { - setLastChallengeIndex(i) - if (lastChallengeIndex === 0) return - else if (lastChallengeIndex === 1) { - setContainerTranslation(0 - cardWidth * lastChallengeIndex) - } else { - setContainerTranslation( - 0 - cardWidth * lastChallengeIndex - marginPx * 1.2 - ) - } - if (isLastDuelDone) { - setLastChallengeIndex(i + 1) - } - setIndex(i) - } - }) - }, [userChallengeList, lastChallengeIndex, cardWidth, isLastDuelDone]) + ) + if (currentChallengeIndex === -1) { + currentChallengeIndex = isLastDuelDone ? userChallengeList.length : 0 + } + setContainerTranslation( + -currentChallengeIndex * (cardWidth + marginPx) + marginPx + ) + setIndex(currentChallengeIndex) + }, [userChallengeList, cardWidth, isLastDuelDone]) useEffect(() => { if ( @@ -129,12 +105,12 @@ const ChallengeView = () => { return ( <> - <CozyBar titleKey={'common.title_challenge'} /> + <CozyBar titleKey="common.title_challenge" /> <Header - setHeaderHeight={defineHeaderHeight} - desktopTitleKey={'common.title_challenge'} + setHeaderHeight={setHeaderHeight} + desktopTitleKey="common.title_challenge" /> - <Content height={headerHeight}> + <Content heightOffset={headerHeight}> <div className="challengeSlider" onClick={resetValues} @@ -166,7 +142,7 @@ const ChallengeView = () => { {isLastDuelDone && ( <ChallengeCard indexSlider={index} - index={5} + index={userChallengeList.length} cardWidth={cardWidth} cardHeight={cardHeight} isChallengeCardLast={true} diff --git a/src/components/Challenge/__snapshots__/ChallengeCardDone.spec.tsx.snap b/src/components/Challenge/__snapshots__/ChallengeCardDone.spec.tsx.snap deleted file mode 100644 index 54a1e470aabfe564142211875f79cde6e1102c84..0000000000000000000000000000000000000000 --- a/src/components/Challenge/__snapshots__/ChallengeCardDone.spec.tsx.snap +++ /dev/null @@ -1,58 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`ChallengeCardDone component should be rendered correctly 1`] = ` -<div - className="cardContent cardDone" -> - <div - className="challengeName text-22-bold" - > - Challenge 1 - </div> - <div - className="iconResult" - > - <StyledIcon - className="imgResult" - icon="test-file-stub" - size={180} - /> - </div> - <div - className="statsResult" - > - <div - className="labelResult win" - > - challenge.card_done.win - </div> - <span - className="text-18" - > - challenge.card_done.saving - <span - className="text-18-bold" - > - function () { - return fn.apply(this, arguments); - } - € - </span> - <br /> - challenge.card_done.final_defi - </span> - </div> - <WithStyles(ForwardRef(Button)) - aria-label="challenge.card_done.final_defi_view" - classes={ - Object { - "label": "text-15-bold", - "root": "btn-secondary-negative review-btn", - } - } - onClick={[Function]} - > - challenge.card_done.final_defi_view - </WithStyles(ForwardRef(Button))> -</div> -`; diff --git a/src/components/Challenge/__snapshots__/ChallengeView.spec.tsx.snap b/src/components/Challenge/__snapshots__/ChallengeView.spec.tsx.snap index 3ddca6ea025581559a79db5eacfab2fa73695af8..7736d9c4a786f8ec1dd48586ae88ad01b4aefce4 100644 --- a/src/components/Challenge/__snapshots__/ChallengeView.spec.tsx.snap +++ b/src/components/Challenge/__snapshots__/ChallengeView.spec.tsx.snap @@ -22,7 +22,7 @@ exports[`ChallengeView component should be rendered correctly 1`] = ` setHeaderHeight={[Function]} /> <mock-content - height={0} + heightOffset={0} > <div className="challengeSlider" @@ -38,15 +38,15 @@ exports[`ChallengeView component should be rendered correctly 1`] = ` className="challenge-container" style={ Object { - "transform": "translateX(-874.2px)", + "transform": "translateX(-586px)", } } > <mock-challengecard - cardHeight={460.79999999999995} + cardHeight={499.20000000000005} cardWidth={285} index={0} - indexSlider={3} + indexSlider={2} key="CHALLENGE0001" moveToSlide={[Function]} userChallenge={ @@ -194,10 +194,10 @@ exports[`ChallengeView component should be rendered correctly 1`] = ` } /> <mock-challengecard - cardHeight={460.79999999999995} + cardHeight={499.20000000000005} cardWidth={285} index={1} - indexSlider={3} + indexSlider={2} key="CHALLENGE0002" moveToSlide={[Function]} userChallenge={ @@ -345,10 +345,10 @@ exports[`ChallengeView component should be rendered correctly 1`] = ` } /> <mock-challengecard - cardHeight={460.79999999999995} + cardHeight={499.20000000000005} cardWidth={285} index={2} - indexSlider={3} + indexSlider={2} key="CHALLENGE0003" moveToSlide={[Function]} userChallenge={ @@ -496,10 +496,10 @@ exports[`ChallengeView component should be rendered correctly 1`] = ` } /> <mock-challengecard - cardHeight={460.79999999999995} + cardHeight={499.20000000000005} cardWidth={285} index={3} - indexSlider={3} + indexSlider={2} key="CHALLENGE0004" moveToSlide={[Function]} userChallenge={ @@ -647,10 +647,10 @@ exports[`ChallengeView component should be rendered correctly 1`] = ` } /> <mock-challengecard - cardHeight={460.79999999999995} + cardHeight={499.20000000000005} cardWidth={285} index={4} - indexSlider={3} + indexSlider={2} key="CHALLENGE0005" moveToSlide={[Function]} userChallenge={ @@ -798,10 +798,10 @@ exports[`ChallengeView component should be rendered correctly 1`] = ` } /> <mock-challengecard - cardHeight={460.79999999999995} + cardHeight={499.20000000000005} cardWidth={285} index={5} - indexSlider={3} + indexSlider={2} key="CHALLENGE0006" moveToSlide={[Function]} userChallenge={ diff --git a/src/components/Challenge/challengeView.scss b/src/components/Challenge/challengeView.scss index b0cc2a8fab8d77ed19e2060f891d2840ea20abef..f603c9148f031625f56ccec47458cbec0275e291 100644 --- a/src/components/Challenge/challengeView.scss +++ b/src/components/Challenge/challengeView.scss @@ -1,7 +1,7 @@ -@import '../../styles/base/breakpoint'; -@import '../../styles/base/typo-variables'; -@import '../../styles/base/color'; -@import '../../styles/base/z-index'; +@import 'src/styles/base/breakpoint'; +@import 'src/styles/base/typo-variables'; +@import 'src/styles/base/color'; +@import 'src/styles/base/z-index'; .challengeSlider { position: relative; @@ -23,6 +23,9 @@ .cardContent { margin: auto; cursor: pointer; + &.onGoing { + padding-top: 2.5rem; + } .title { font-weight: 400; text-align: center; diff --git a/src/components/Charts/AxisBottom.spec.tsx b/src/components/Charts/AxisBottom.spec.tsx index e6e5a7f13c77b92e4eaa707dc522ccf9b2b0dbd4..c10ede15c1f41fca123b0f9e5473e1845e292fad 100644 --- a/src/components/Charts/AxisBottom.spec.tsx +++ b/src/components/Charts/AxisBottom.spec.tsx @@ -1,12 +1,11 @@ import { scaleBand, ScaleBand } from 'd3-scale' -import { TimeStep } from 'enum/timeStep.enum' +import { TimeStep } from 'enums' import { mount } from 'enzyme' import { DateTime } from 'luxon' import React from 'react' -import * as reactRedux from 'react-redux' import { Provider } from 'react-redux' -import { graphData } from '../../../tests/__mocks__/chartData.mock' -import { createMockEcolyoStore } from '../../../tests/__mocks__/store' +import { graphData } from 'tests/__mocks__/chartData.mock' +import { createMockEcolyoStore } from 'tests/__mocks__/store' import AxisBottom from './AxisBottom' const mockXScale: ScaleBand<string> = scaleBand() @@ -22,20 +21,13 @@ const mockProps = { marginBottom: 10, } -const useSelectorSpy = jest.spyOn(reactRedux, 'useSelector') -const useDispatchSpy = jest.spyOn(reactRedux, 'useDispatch') - describe('AxisBottom component test', () => { - const store = createMockEcolyoStore() - beforeEach(() => { - store.clearActions() - useDispatchSpy.mockClear() - }) - - useSelectorSpy.mockReturnValue({ - selectedDate: DateTime.fromISO('2020-10-01T00:00:00.000Z', { - zone: 'utc', - }), + const store = createMockEcolyoStore({ + chart: { + selectedDate: DateTime.fromISO('2020-10-01T00:00:00.000Z', { + zone: 'utc', + }), + }, }) it('should correctly render YEAR format of AxisBottom', () => { diff --git a/src/components/Charts/AxisBottom.tsx b/src/components/Charts/AxisBottom.tsx index 0fcdc71c016200d196c21ee80a8b32b7f117327e..66724b1de05cd7b9e818e6e51b566c6c8ed9a440 100644 --- a/src/components/Charts/AxisBottom.tsx +++ b/src/components/Charts/AxisBottom.tsx @@ -1,12 +1,11 @@ import { ScaleBand } from 'd3-scale' -import { TimeStep } from 'enum/timeStep.enum' +import { TimeStep } from 'enums' import { capitalize } from 'lodash' import { DateTime } from 'luxon' import { Dataload } from 'models' import React from 'react' -import { useSelector } from 'react-redux' import DateChartService from 'services/dateChart.service' -import { AppStore } from 'store' +import { useAppSelector } from 'store/hooks' interface TextTypeProps { index: number @@ -113,7 +112,7 @@ function TextAxis({ return ( <text x={width} y="10" dy="0.71em"> <tspan className={style} textAnchor="middle"> - {'-'} + - </tspan> </text> ) @@ -139,7 +138,7 @@ const AxisBottom = ({ marginBottom, isDuel = false, }: AxisBottomProps) => { - const { selectedDate } = useSelector((state: AppStore) => state.ecolyo.chart) + const { selectedDate } = useAppSelector(state => state.ecolyo.chart) const dashArray = `${height / 30} ${height / 30}` const dateChartService = new DateChartService() const displayAllDays: boolean = isDuel && data.length <= 15 diff --git a/src/components/Charts/AxisRight.spec.tsx b/src/components/Charts/AxisRight.spec.tsx index 668eb4e85347ac357817fadbc1188848c7f8ed74..0ff617522637e524d35052ef38840788e4c87b1e 100644 --- a/src/components/Charts/AxisRight.spec.tsx +++ b/src/components/Charts/AxisRight.spec.tsx @@ -1,19 +1,9 @@ import { scaleLinear } from 'd3' -import { FluidType } from 'enum/fluid.enum' +import { FluidType } from 'enums' import { mount } from 'enzyme' import React from 'react' import AxisRight from './AxisRight' -jest.mock('cozy-ui/transpiled/react/I18n', () => { - return { - useI18n: jest.fn(() => { - return { - t: (str: string) => str, - } - }), - } -}) - const mockProps = { yScale: scaleLinear(), fluidType: FluidType.ELECTRICITY, diff --git a/src/components/Charts/AxisRight.tsx b/src/components/Charts/AxisRight.tsx index 7ba81a2e94c7a921985dd33332974c52b3d8fcfd..d7257ec00b3f5989849258748324968c858a8e12 100644 --- a/src/components/Charts/AxisRight.tsx +++ b/src/components/Charts/AxisRight.tsx @@ -2,7 +2,7 @@ import { useI18n } from 'cozy-ui/transpiled/react/I18n' import { axisRight } from 'd3-axis' import { ScaleLinear } from 'd3-scale' import { select, selectAll } from 'd3-selection' -import { FluidType } from 'enum/fluid.enum' +import { FluidType } from 'enums' import React, { useEffect, useRef } from 'react' interface AxisRightProps { @@ -39,13 +39,11 @@ const AxisRight = ({ .tickFormat(d => Number(d) >= 1000 && fluidStyle !== 'MULTIFLUID' ? typeof d === 'number' - ? `${d / 1000} ${t('FLUID.' + fluidStyle + '.MEGAUNIT')}` - : `${d.valueOf() / 1000} ${t( - 'FLUID.' + fluidStyle + '.MEGAUNIT' - )}` + ? `${d / 1000} ${t(`FLUID.${fluidStyle}.MEGAUNIT`)}` + : `${d.valueOf() / 1000} ${t(`FLUID.${fluidStyle}.MEGAUNIT`)}` : d === 0 ? `${d}` - : `${d} ${t('FLUID.' + fluidStyle + '.UNIT')}` + : `${d} ${t(`FLUID.${fluidStyle}.UNIT`)}` ) ) selectAll('.tick text').attr('class', 'chart-ticks-y-text') diff --git a/src/components/Charts/Bar.spec.tsx b/src/components/Charts/Bar.spec.tsx index 0694b98f8e7f99a4a38e408e92a21b5752ca37b6..e1de4c716c79e7bca1c5baa56278d45bbf06960f 100644 --- a/src/components/Charts/Bar.spec.tsx +++ b/src/components/Charts/Bar.spec.tsx @@ -1,14 +1,12 @@ import { scaleBand, ScaleBand, scaleLinear } from 'd3' -import { FluidType } from 'enum/fluid.enum' -import { TimeStep } from 'enum/timeStep.enum' +import { FluidType, TimeStep } from 'enums' import { mount } from 'enzyme' import { DateTime } from 'luxon' import React from 'react' -import * as reactRedux from 'react-redux' import { Provider } from 'react-redux' import * as chartActions from 'store/chart/chart.slice' -import { graphData } from '../../../tests/__mocks__/chartData.mock' -import { createMockEcolyoStore } from '../../../tests/__mocks__/store' +import { graphData } from 'tests/__mocks__/chartData.mock' +import { createMockEcolyoStore, mockGlobalState } from 'tests/__mocks__/store' import Bar from './Bar' const mockXScale: ScaleBand<string> = scaleBand() @@ -34,27 +32,16 @@ const mockParam = { isDuel: false, } -const useSelectorSpy = jest.spyOn(reactRedux, 'useSelector') -const useDispatchSpy = jest.spyOn(reactRedux, 'useDispatch') const setSelectedDateSpy = jest.spyOn(chartActions, 'setSelectedDate') -const setCurrentDatachartIndexSpy = jest.spyOn( - chartActions, - 'setCurrentDataChartIndex' -) describe('Bar component test', () => { - const store = createMockEcolyoStore() - beforeEach(() => { - store.clearActions() - useDispatchSpy.mockClear() - setSelectedDateSpy.mockClear() - setCurrentDatachartIndexSpy.mockClear() - }) - - useSelectorSpy.mockReturnValue({ - selectedDate: DateTime.fromISO('2020-10-01T00:00:00.000Z', { - zone: 'utc', - }), + const store = createMockEcolyoStore({ + chart: { + selectedDate: DateTime.fromISO('2020-10-01T00:00:00.000Z', { + zone: 'utc', + }), + }, + global: mockGlobalState, }) it('should correctly render Multifluid Bar', () => { @@ -143,7 +130,7 @@ describe('Bar component test', () => { </Provider> ) wrapper.find('rect').first().simulate('click') - expect(setSelectedDateSpy).toBeCalledTimes(1) + expect(setSelectedDateSpy).toHaveBeenCalledTimes(1) expect(setSelectedDateSpy).toHaveBeenCalledWith( graphData.actualData[0].date ) diff --git a/src/components/Charts/Bar.tsx b/src/components/Charts/Bar.tsx index 57f86f31795bfd07f5f6b49479b6b62e8eb6f689..d0ccd177170d02496e14e84a7c5f146569861175 100644 --- a/src/components/Charts/Bar.tsx +++ b/src/components/Charts/Bar.tsx @@ -1,25 +1,23 @@ import { ScaleBand, ScaleLinear } from 'd3-scale' import { detect } from 'detect-browser' -import { FluidType } from 'enum/fluid.enum' -import { TimeStep } from 'enum/timeStep.enum' +import { FluidType, TimeStep } from 'enums' import { DateTime } from 'luxon' import { Dataload } from 'models' -import React, { Dispatch, useEffect, useState } from 'react' -import { useDispatch, useSelector } from 'react-redux' +import React, { useEffect, useState } from 'react' import DateChartService from 'services/dateChart.service' -import { AppActionsTypes, AppStore } from 'store' import { setCurrentDataChartIndex, setSelectedDate, } from 'store/chart/chart.slice' +import { useAppDispatch, useAppSelector } from 'store/hooks' interface BarProps { index: number dataload: Dataload + compare: boolean compareDataload: Dataload | null fluidType: FluidType timeStep: TimeStep - compare: boolean xScale: ScaleBand<string> yScale: ScaleLinear<number, number> height: number @@ -28,15 +26,16 @@ interface BarProps { isMultiMissingFluid?: boolean weekdays?: 'week' | 'weekend' clickable?: boolean + average?: number } const Bar = ({ index, dataload, + compare, compareDataload, fluidType, timeStep, - compare, xScale, yScale, height, @@ -45,9 +44,13 @@ const Bar = ({ isMultiMissingFluid, weekdays, clickable = true, + average, }: BarProps) => { - const dispatch = useDispatch<Dispatch<AppActionsTypes>>() - const { selectedDate } = useSelector((state: AppStore) => state.ecolyo.chart) + const dispatch = useAppDispatch() + const { + chart: { selectedDate }, + global: { fluidStatus }, + } = useAppSelector(state => state.ecolyo) const [clicked, setClicked] = useState(false) const [animationEnded, setAnimationEnded] = useState(false) const [compareAnimationEnded, setCompareAnimationEnded] = useState(false) @@ -73,16 +76,19 @@ const Bar = ({ setCompareAnimationEnded(true) } - const tempYScale: number | undefined = yScale(dataload.value) - const yScaleValue: number = tempYScale ? tempYScale : 0 - const tempCompareYScale: number | undefined = yScale( - compareDataload ? compareDataload.value : 0 - ) - const yScaleCompareValue: number = tempCompareYScale ? tempCompareYScale : 0 - const tempXScale: number | undefined = xScale( - dataload.date.toLocaleString(DateTime.DATETIME_SHORT) - ) - const xScaleValue: number = tempXScale ? tempXScale : 0 + let value = dataload.value + /** + * Use 10% of average as the placeholder if average is above 1, + * otherwise use a minimum of 1 as the placeholder. + */ + if (value === -1 && average) { + value = average > 1 ? average * 0.1 : 1 + } + const yScaleValue = yScale(value) ?? 0 + const yScaleCompareValue = yScale(compareDataload?.value ?? 0) ?? 0 + + const xScaleValue = + xScale(dataload.date.toLocaleString(DateTime.DATETIME_SHORT)) ?? 0 const isSelectedDate = isDuel ? false @@ -92,89 +98,63 @@ const Bar = ({ dataload.date ) - const delayIndex = index % 13 - const edgeBrowser = browser && browser.name !== 'edge' - const selected = isSelectedDate ? ' selected' : '' - const bounce = edgeBrowser ? '1' : '3' - const disabled = `${clickable ? '' : 'disabled'}` + const clickedAnim = clicked ? 'bounce-2 delay' : '' + const disabled = clickable ? '' : 'disabled' + const selected = isSelectedDate ? 'selected' : '' const getBarClass = () => { - const bounceDelay = ` bounce-${bounce} delay--${delayIndex}` - const fluidWeekdays = `bar-${fluidStyle} ${weekdays}` + const upcoming = dataload.value === -1 ? 'bar-UNCOMING' : '' + const edgeBrowser = browser && browser.name !== 'edge' + const bounce = edgeBrowser ? '1' : '3' + const baseStyles = `bar-${fluidStyle} ${upcoming} ${weekdays} ${selected} ${disabled}` if (clicked) { - return `${fluidWeekdays}${selected} bounce-2 delay` - } else if (animationEnded) { - return `${fluidWeekdays}${selected} ${disabled}` + return `${baseStyles} ${clickedAnim}` } - return `${fluidWeekdays}${bounceDelay}${selected} ${disabled}` + if (animationEnded) { + return baseStyles + } + return `${baseStyles} bounce-${bounce} delay--${index}` } const getCompareBarClass = () => { - const bounceValue = clicked ? (edgeBrowser ? '2' : '3') : bounce - const bounceDelay = ` bounce-${bounceValue} delay--${ - clicked ? 0 : delayIndex - }` - const fluidStyleClass = `bar-compare-${fluidStyle}` + const animate = `bounce-2 delay--${clicked ? 0 : index}` + const animationClass = compareAnimationEnded ? '' : animate - if (clicked) { - return `${fluidStyleClass} ${selected}${bounceDelay}` - } - if (isSelectedDate) { - return compareAnimationEnded - ? `${fluidStyleClass} ${selected}` - : `${fluidStyleClass} ${selected}${bounceDelay}` - } - return compareAnimationEnded - ? fluidStyleClass - : `${fluidStyleClass} ${bounceDelay}` + return `bar-compare-${fluidStyle} ${selected} ${animationClass} ${clickedAnim}` } - const compareBarClass = getCompareBarClass() - const barClass = getBarClass() - const barBackgroundClass = isSelectedDate const getBandWidth = (): number => { return compare ? xScale.bandwidth() / 2 : xScale.bandwidth() } + const lastDataDate = + fluidType !== FluidType.MULTIFLUID && fluidStatus[fluidType].lastDataDate + + const dataMissingUpcoming = Boolean( + lastDataDate && + dataload.date > lastDataDate && + dataload.date < DateTime.local() + ) + const topRoundedRect = ( - _x: number, - _y: number, - _width: number, - _height: number + x: number, + y: number, + width: number, + height: number ): string => { - const radius = _height > 4 ? 4 : _height / 4 - return ( - 'M' + - _x + - ',' + - (_y + radius) + - ' a' + - radius + - ',' + - radius + - ' 0 0 1 ' + - radius + - ',' + - -radius + - 'h' + - (_width - 2 * radius) + - 'a' + - radius + - ',' + - radius + - ' 0 0 1 ' + - radius + - ',' + - radius + - 'v' + - (_height - radius) + - 'h' + - -_width + - 'z' - ) + const radius = height > 4 ? 4 : height / 4 + + return ` + M${x},${y + radius} + a${radius},${radius} 0 0 1 ${radius},${-radius} + h${width - 2 * radius} + a${radius},${radius} 0 0 1 ${radius},${radius} + v${height - radius} + h${-width} + z` } useEffect(() => { @@ -186,6 +166,7 @@ const Bar = ({ return ( <g> + {/* selected background bar */} {height > 0 && ( <g transform={`translate(${xScaleValue}, -40)`} @@ -202,6 +183,32 @@ const Bar = ({ /> </g> )} + {/* placeholder bar for upcoming values */} + {height > 0 && dataMissingUpcoming && ( + <g + transform={`translate(${xScaleValue}, ${yScaleValue})`} + className="barFill" + > + <defs> + <linearGradient id="gradient" x1="0" x2="0" y1="0" y2="1"> + <stop id="stop-color-1" offset="0%" /> + <stop id="stop-color-2" offset="100%" /> + </linearGradient> + </defs> + <path + d={topRoundedRect( + compare ? getBandWidth() : 0, + 0, + weekdays ? 3 : getBandWidth(), + height - yScaleValue + )} + className={getBarClass()} + onClick={!weekdays ? handleClick : () => undefined} + onAnimationEnd={onAnimationEnd} + /> + </g> + )} + {/* hashed bars */} {height > 0 && dataload.value >= 0 && isMultiMissingFluid ? ( <g transform={`translate(${xScaleValue}, ${yScaleValue})`} @@ -211,7 +218,7 @@ const Bar = ({ <defs> <linearGradient id="gradient" - className={barClass} + className={getBarClass()} x1="0" x2="0" y1="0" @@ -254,7 +261,6 @@ const Bar = ({ ? 'url(#diagonalHatchSelected)' : 'url(#diagonalHatch)' } - // className={isDuel ? 'bar-duel' : barClass} onClick={!weekdays ? handleClick : () => undefined} onAnimationEnd={onAnimationEnd} /> @@ -263,11 +269,12 @@ const Bar = ({ height > 0 && dataload.value && dataload.value >= 0 && ( + // default colored bar <g transform={`translate(${xScaleValue}, ${yScaleValue})`}> <defs> <linearGradient id="gradient" - className={barClass} + className={getBarClass()} x1="0" x2="0" y1="0" @@ -284,8 +291,7 @@ const Bar = ({ weekdays ? 3 : getBandWidth(), height - yScaleValue )} - fill="url(#gradient)" - className={isDuel ? 'bar-duel' : barClass} + className={isDuel ? 'bar-duel' : getBarClass()} onClick={!weekdays ? handleClick : () => undefined} onAnimationEnd={onAnimationEnd} /> @@ -298,7 +304,7 @@ const Bar = ({ <defs> <linearGradient id="gradient-compare" - className={compareBarClass} + className={getCompareBarClass()} x1="0" x2="0" y1="0" @@ -315,8 +321,7 @@ const Bar = ({ getBandWidth(), height - yScaleCompareValue )} - fill="url(#gradient-compare)" - className={compareBarClass} + className={getCompareBarClass()} onClick={handleClick} onAnimationEnd={onCompareAnimationEnd} /> diff --git a/src/components/Charts/BarChart.tsx b/src/components/Charts/BarChart.tsx index 9483e03da8756f0359fb2eba52e6975a8d59834e..bc3e796cc49aad8a4b842e4bc45c5abc4dcdab0a 100644 --- a/src/components/Charts/BarChart.tsx +++ b/src/components/Charts/BarChart.tsx @@ -2,19 +2,17 @@ import AxisBottom from 'components/Charts/AxisBottom' import AxisRight from 'components/Charts/AxisRight' import Bar from 'components/Charts/Bar' import { scaleBand, ScaleBand, scaleLinear, ScaleLinear } from 'd3-scale' -import { DataloadState } from 'enum/dataload.enum' -import { FluidType } from 'enum/fluid.enum' -import { TimeStep } from 'enum/timeStep.enum' +import { DataloadState, FluidType, TimeStep } from 'enums' import { DateTime } from 'luxon' import { Datachart } from 'models' import React from 'react' -import { useSelector } from 'react-redux' -import { AppStore } from 'store' -export interface BarChartProps { +interface BarChartProps { chartData: Datachart fluidType: FluidType timeStep: TimeStep + /** showCompare should be false for analysis view */ + showCompare: boolean width?: number height?: number marginLeft?: number @@ -29,6 +27,7 @@ const BarChart = ({ chartData, fluidType, timeStep, + showCompare, width = 600, height = 400, marginLeft = 10, @@ -38,7 +37,6 @@ const BarChart = ({ isSwitching, clickable = true, }: BarChartProps) => { - const { showCompare } = useSelector((state: AppStore) => state.ecolyo.chart) const getContentWidth = () => { return width - marginLeft - marginRight } @@ -79,6 +77,9 @@ const BarChart = ({ .domain([0, getMaxLoad()]) .range([getContentHeight(), 0]) + const sum = chartData.actualData.reduce((a, b) => a + b.value, 0) + const averageConsumption = sum / chartData.actualData.length + return ( <svg width={width} height={height}> <AxisRight @@ -90,11 +91,11 @@ const BarChart = ({ /> <g transform={`translate(${marginLeft},${marginTop})`}> - {chartData.actualData.map((d, index) => ( + {chartData.actualData.map((data, index) => ( <Bar key={index} index={index} - dataload={d} + dataload={data} compareDataload={ chartData.comparisonData?.[index] ? chartData.comparisonData[index] @@ -108,13 +109,12 @@ const BarChart = ({ height={getContentHeight()} isSwitching={isSwitching} isMultiMissingFluid={ - d.state === DataloadState.AGGREGATED_WITH_EMPTY || - d.state === DataloadState.AGGREGATED_WITH_COMING || - d.state === DataloadState.AGGREGATED_WITH_HOLE_OR_MISSING - ? true - : false + data.state === DataloadState.AGGREGATED_WITH_EMPTY || + data.state === DataloadState.AGGREGATED_WITH_COMING || + data.state === DataloadState.AGGREGATED_WITH_HOLE_OR_MISSING } clickable={clickable} + average={averageConsumption} /> ))} </g> diff --git a/src/components/Charts/UncomingBar.tsx b/src/components/Charts/UncomingBar.tsx index 3a252cb967e7dfb7bfbf363a57276966fa34e2ef..7f0380b878bdfcfd61fdbfc062d1fb5f15589860 100644 --- a/src/components/Charts/UncomingBar.tsx +++ b/src/components/Charts/UncomingBar.tsx @@ -87,7 +87,7 @@ const UncomingBar = ({ y="0" width={getBandWidth()} height={height + 40} - className={`background-false`} + className="background-false" fill="#E0E0E0" /> </g> @@ -107,7 +107,7 @@ const UncomingBar = ({ )} fill="url(#gradient)" strokeDasharray="5" - stroke={'#61f0f2'} + stroke="#61f0f2" onAnimationEnd={onAnimationEnd} className={barClass} /> diff --git a/src/components/CommonKit/Card/StyledCard.spec.tsx b/src/components/CommonKit/Card/StyledCard.spec.tsx index e302e4f5c08be287a9fce2982230e7e25cd841cc..0ef9813d20279296deef175ef9da1b8e0f11dce4 100644 --- a/src/components/CommonKit/Card/StyledCard.spec.tsx +++ b/src/components/CommonKit/Card/StyledCard.spec.tsx @@ -1,21 +1,27 @@ -import { FluidType } from 'enum/fluid.enum' +import { FluidType } from 'enums' import { mount } from 'enzyme' import React from 'react' import StyledCard from './StyledCard' describe('StyledCard component test', () => { it('should render correctly Electricity StyledCard', () => { - const wrapper = mount(<StyledCard fluidType={FluidType.ELECTRICITY} />) + const wrapper = mount( + <StyledCard fluidType={FluidType.ELECTRICITY}>children</StyledCard> + ) expect(wrapper.getElement()).toMatchSnapshot() }) it('should render correctly Water StyledCard', () => { - const wrapper = mount(<StyledCard fluidType={FluidType.WATER} />) + const wrapper = mount( + <StyledCard fluidType={FluidType.WATER}>children</StyledCard> + ) expect(wrapper.getElement()).toMatchSnapshot() }) it('should render correctly Gas StyledCard', () => { - const wrapper = mount(<StyledCard fluidType={FluidType.GAS} />) + const wrapper = mount( + <StyledCard fluidType={FluidType.GAS}>children</StyledCard> + ) expect(wrapper.getElement()).toMatchSnapshot() }) }) diff --git a/src/components/CommonKit/Card/StyledCard.tsx b/src/components/CommonKit/Card/StyledCard.tsx index 39e472c59d9876587c7923c6f51cde1eaa5626a8..562050fb393ef8e2c51225a3cac4f7813f64b59c 100644 --- a/src/components/CommonKit/Card/StyledCard.tsx +++ b/src/components/CommonKit/Card/StyledCard.tsx @@ -3,7 +3,7 @@ import CardActionArea, { } from '@material-ui/core/CardActionArea' import CardContent from '@material-ui/core/CardContent' import { withStyles } from '@material-ui/core/styles' -import { FluidType } from 'enum/fluid.enum' +import { FluidType } from 'enums' import React, { ReactNode } from 'react' import { getFluidName } from 'utils/utils' diff --git a/src/components/CommonKit/Card/__snapshots__/StyledCard.spec.tsx.snap b/src/components/CommonKit/Card/__snapshots__/StyledCard.spec.tsx.snap index 52bb45d8bd676b5fb217f3ea9195340af328efaf..520b007502483267ab35c3da4be31661e364b39d 100644 --- a/src/components/CommonKit/Card/__snapshots__/StyledCard.spec.tsx.snap +++ b/src/components/CommonKit/Card/__snapshots__/StyledCard.spec.tsx.snap @@ -3,17 +3,23 @@ exports[`StyledCard component test should render correctly Electricity StyledCard 1`] = ` <StyledCard fluidType={0} -/> +> + children +</StyledCard> `; exports[`StyledCard component test should render correctly Gas StyledCard 1`] = ` <StyledCard fluidType={2} -/> +> + children +</StyledCard> `; exports[`StyledCard component test should render correctly Water StyledCard 1`] = ` <StyledCard fluidType={1} -/> +> + children +</StyledCard> `; diff --git a/src/components/CommonKit/ErrorPage/ErrorPage.spec.tsx b/src/components/CommonKit/ErrorPage/ErrorPage.spec.tsx deleted file mode 100644 index c916c501d205d86d1816d257d4a58441a74d1d55..0000000000000000000000000000000000000000 --- a/src/components/CommonKit/ErrorPage/ErrorPage.spec.tsx +++ /dev/null @@ -1,63 +0,0 @@ -/* eslint-disable react/display-name */ -import { Button } from '@material-ui/core' -import { mount } from 'enzyme' -import toJson from 'enzyme-to-json' -import React from 'react' -import { Provider } from 'react-redux' -import configureStore from 'redux-mock-store' -import { globalStateData } from '../../../../tests/__mocks__/globalStateData.mock' -import ErrorPage from './ErrorPage' - -jest.mock('cozy-ui/transpiled/react/I18n', () => { - return { - useI18n: jest.fn(() => { - return { - t: (str: string) => str, - } - }), - } -}) -const mockedNavigate = jest.fn() -jest.mock('react-router-dom', () => ({ - ...jest.requireActual('react-router-dom'), - useNavigate: () => mockedNavigate, -})) - -jest.mock('components/Header/Header', () => () => <div id="Header" />) -jest.mock('components/Header/CozyBar', () => () => <div id="CozyBar" />) -// eslint-disable-next-line @typescript-eslint/no-explicit-any -jest.mock('components/Content/Content', () => (props: any) => ( - <div id="content">{props.children}</div> -)) -const mockStore = configureStore([]) - -describe('ErrorPage component', () => { - it('should be rendered correctly', async () => { - const store = mockStore({ - ecolyo: { - global: globalStateData, - }, - }) - const wrapper = mount( - <Provider store={store}> - <ErrorPage text={'test'} returnPage={'ecogestures'} /> - </Provider> - ) - - expect(toJson(wrapper)).toMatchSnapshot() - }) - it('should click on button and be redirected', () => { - const store = mockStore({ - ecolyo: { - global: globalStateData, - }, - }) - const wrapper = mount( - <Provider store={store}> - <ErrorPage text={'test'} returnPage={'ecogestures'} /> - </Provider> - ) - wrapper.find(Button).simulate('click') - expect(mockedNavigate).toHaveBeenCalledWith('/ecogestures') - }) -}) diff --git a/src/components/CommonKit/ErrorPage/__snapshots__/ErrorPage.spec.tsx.snap b/src/components/CommonKit/ErrorPage/__snapshots__/ErrorPage.spec.tsx.snap deleted file mode 100644 index c64f4b6b02e307fe810c4422e6e978a7efce4eae..0000000000000000000000000000000000000000 --- a/src/components/CommonKit/ErrorPage/__snapshots__/ErrorPage.spec.tsx.snap +++ /dev/null @@ -1,222 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`ErrorPage component should be rendered correctly 1`] = ` -<Provider - store={ - Object { - "clearActions": [Function], - "dispatch": [Function], - "getActions": [Function], - "getState": [Function], - "replaceReducer": [Function], - "subscribe": [Function], - } - } -> - <ErrorPage - returnPage="ecogestures" - text="test" - > - <Component - titleKey="error_page.main" - > - <div - id="CozyBar" - /> - </Component> - <Component - desktopTitleKey="error_page.main" - setHeaderHeight={[Function]} - > - <div - id="Header" - /> - </Component> - <Component - height={0} - > - <div - id="content" - > - <div - className="error-container" - > - <StyledIcon - className="profile-icon" - icon="test-file-stub" - size={250} - > - <Icon - aria-hidden={true} - className="profile-icon" - icon="test-file-stub" - size={250} - spin={false} - > - <Component - aria-hidden={true} - className="profile-icon styles__icon___23x3R" - height={250} - style={Object {}} - width={250} - > - <svg - aria-hidden={true} - className="profile-icon styles__icon___23x3R" - height={250} - style={Object {}} - width={250} - > - <use - xlinkHref="#test-file-stub" - /> - </svg> - </Component> - </Icon> - </StyledIcon> - <div - className="text-18-bold head" - > - test - </div> - <WithStyles(ForwardRef(Button)) - aria-label="error_page.back" - classes={ - Object { - "label": "text-18-bold", - "root": "btn-highlight", - } - } - onClick={[Function]} - type="submit" - variant="contained" - > - <ForwardRef(Button) - aria-label="error_page.back" - classes={ - Object { - "colorInherit": "MuiButton-colorInherit", - "contained": "MuiButton-contained", - "containedPrimary": "MuiButton-containedPrimary", - "containedSecondary": "MuiButton-containedSecondary", - "containedSizeLarge": "MuiButton-containedSizeLarge", - "containedSizeSmall": "MuiButton-containedSizeSmall", - "disableElevation": "MuiButton-disableElevation", - "disabled": "Mui-disabled", - "endIcon": "MuiButton-endIcon", - "focusVisible": "Mui-focusVisible", - "fullWidth": "MuiButton-fullWidth", - "iconSizeLarge": "MuiButton-iconSizeLarge", - "iconSizeMedium": "MuiButton-iconSizeMedium", - "iconSizeSmall": "MuiButton-iconSizeSmall", - "label": "MuiButton-label text-18-bold", - "outlined": "MuiButton-outlined", - "outlinedPrimary": "MuiButton-outlinedPrimary", - "outlinedSecondary": "MuiButton-outlinedSecondary", - "outlinedSizeLarge": "MuiButton-outlinedSizeLarge", - "outlinedSizeSmall": "MuiButton-outlinedSizeSmall", - "root": "MuiButton-root btn-highlight", - "sizeLarge": "MuiButton-sizeLarge", - "sizeSmall": "MuiButton-sizeSmall", - "startIcon": "MuiButton-startIcon", - "text": "MuiButton-text", - "textPrimary": "MuiButton-textPrimary", - "textSecondary": "MuiButton-textSecondary", - "textSizeLarge": "MuiButton-textSizeLarge", - "textSizeSmall": "MuiButton-textSizeSmall", - } - } - onClick={[Function]} - type="submit" - variant="contained" - > - <WithStyles(ForwardRef(ButtonBase)) - aria-label="error_page.back" - className="MuiButton-root btn-highlight MuiButton-contained" - component="button" - disabled={false} - focusRipple={true} - focusVisibleClassName="Mui-focusVisible" - onClick={[Function]} - type="submit" - > - <ForwardRef(ButtonBase) - aria-label="error_page.back" - className="MuiButton-root btn-highlight MuiButton-contained" - classes={ - Object { - "disabled": "Mui-disabled", - "focusVisible": "Mui-focusVisible", - "root": "MuiButtonBase-root", - } - } - component="button" - disabled={false} - focusRipple={true} - focusVisibleClassName="Mui-focusVisible" - onClick={[Function]} - type="submit" - > - <button - aria-label="error_page.back" - className="MuiButtonBase-root MuiButton-root btn-highlight MuiButton-contained" - disabled={false} - onBlur={[Function]} - onClick={[Function]} - onDragLeave={[Function]} - onFocus={[Function]} - onKeyDown={[Function]} - onKeyUp={[Function]} - onMouseDown={[Function]} - onMouseLeave={[Function]} - onMouseUp={[Function]} - onTouchEnd={[Function]} - onTouchMove={[Function]} - onTouchStart={[Function]} - tabIndex={0} - type="submit" - > - <span - className="MuiButton-label text-18-bold" - > - error_page.back - </span> - <WithStyles(memo) - center={false} - > - <ForwardRef(TouchRipple) - center={false} - classes={ - Object { - "child": "MuiTouchRipple-child", - "childLeaving": "MuiTouchRipple-childLeaving", - "childPulsate": "MuiTouchRipple-childPulsate", - "ripple": "MuiTouchRipple-ripple", - "ripplePulsate": "MuiTouchRipple-ripplePulsate", - "rippleVisible": "MuiTouchRipple-rippleVisible", - "root": "MuiTouchRipple-root", - } - } - > - <span - className="MuiTouchRipple-root" - > - <TransitionGroup - childFactory={[Function]} - component={null} - exit={true} - /> - </span> - </ForwardRef(TouchRipple)> - </WithStyles(memo)> - </button> - </ForwardRef(ButtonBase)> - </WithStyles(ForwardRef(ButtonBase))> - </ForwardRef(Button)> - </WithStyles(ForwardRef(Button))> - </div> - </div> - </Component> - </ErrorPage> -</Provider> -`; diff --git a/src/components/CommonKit/FormNavigation/FormNavigation.spec.tsx b/src/components/CommonKit/FormNavigation/FormNavigation.spec.tsx new file mode 100644 index 0000000000000000000000000000000000000000..27cd6d1eed3ab8978b06f3d21398a5890c2fce85 --- /dev/null +++ b/src/components/CommonKit/FormNavigation/FormNavigation.spec.tsx @@ -0,0 +1,32 @@ +import Button from '@material-ui/core/Button' +import { ProfileTypeStepForm } from 'enums' +import { mount } from 'enzyme' +import React from 'react' +import { Provider } from 'react-redux' +import { createMockEcolyoStore } from 'tests/__mocks__/store' +import FormNavigation from './FormNavigation' + +describe('FormNavigation component', () => { + const store = createMockEcolyoStore() + + it('should be rendered correctly', () => { + const mockHandlePrevious = jest.fn() + const mockHandleNext = jest.fn() + const wrapper = mount( + <Provider store={store}> + <FormNavigation + step={ProfileTypeStepForm.COOKING_FLUID} + handlePrevious={mockHandlePrevious} + handleNext={mockHandleNext} + disableNextButton={false} + /> + </Provider> + ) + wrapper.find(Button).at(0).simulate('click') + wrapper.find(Button).at(1).simulate('click') + expect(wrapper.find('profile-navigation')).toBeTruthy() + expect(wrapper.find(Button)).toBeTruthy() + expect(mockHandlePrevious.mock.calls.length).toEqual(1) + expect(mockHandleNext.mock.calls.length).toEqual(1) + }) +}) diff --git a/src/components/FormGlobal/FormNavigation.tsx b/src/components/CommonKit/FormNavigation/FormNavigation.tsx similarity index 90% rename from src/components/FormGlobal/FormNavigation.tsx rename to src/components/CommonKit/FormNavigation/FormNavigation.tsx index 7fab173bf4a8ba170aa9aca3d90ececc45fb8f71..7669a380caa421d978f7225640163710e32ca60b 100644 --- a/src/components/FormGlobal/FormNavigation.tsx +++ b/src/components/CommonKit/FormNavigation/FormNavigation.tsx @@ -1,12 +1,10 @@ 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 { EcogestureStepForm } from 'enum/ecogestureForm.enum' -import { ProfileTypeStepForm } from 'enum/profileType.enum' -import { SgeStep } from 'enum/sgeStep.enum' +import { EcogestureStepForm, ProfileTypeStepForm, SgeStep } from 'enums' import React, { useCallback } from 'react' import { useNavigate } from 'react-router-dom' +import './formNavigation.scss' interface FormNavigationProps { step: ProfileTypeStepForm | EcogestureStepForm | SgeStep @@ -61,7 +59,7 @@ const FormNavigation = ({ <Button aria-label={t('profile_type.accessibility.button_previous')} onClick={handlePreviousClick} - className={'profile-navigation-button'} + className="profile-navigation-button" disabled={ disablePrevButton || step === ProfileTypeStepForm.HOUSING_TYPE } diff --git a/src/components/FormGlobal/formNavigation.scss b/src/components/CommonKit/FormNavigation/formNavigation.scss similarity index 83% rename from src/components/FormGlobal/formNavigation.scss rename to src/components/CommonKit/FormNavigation/formNavigation.scss index 827eb3c93414073fa34204a33e3a0984fd155d53..92c4c331090d526d53c4e9d77dfdd01a41c16be4 100644 --- a/src/components/FormGlobal/formNavigation.scss +++ b/src/components/CommonKit/FormNavigation/formNavigation.scss @@ -1,5 +1,5 @@ -@import '../../styles/base/color'; -@import '../../styles/base/breakpoint'; +@import 'src/styles/base/color'; +@import 'src/styles/base/breakpoint'; .profile-navigation { border-top: 1px solid $grey-dark; diff --git a/src/components/FormGlobal/FormProgress.tsx b/src/components/CommonKit/FormProgress/FormProgress.tsx similarity index 59% rename from src/components/FormGlobal/FormProgress.tsx rename to src/components/CommonKit/FormProgress/FormProgress.tsx index 5971e430756d9f4cc4addd159d6a0b6685b4c652..103e6305a72b80eee37158e5db0414c0c2d2ac49 100644 --- a/src/components/FormGlobal/FormProgress.tsx +++ b/src/components/CommonKit/FormProgress/FormProgress.tsx @@ -1,7 +1,6 @@ -import 'components/FormGlobal/formProgress.scss' -import { ProfileTypeStepForm } from 'enum/profileType.enum' -import { SgeStep } from 'enum/sgeStep.enum' +import { ProfileTypeStepForm, SgeStep } from 'enums' import React from 'react' +import './formProgress.scss' interface FormProgressProps { step: ProfileTypeStepForm | SgeStep @@ -17,11 +16,11 @@ const FormProgress = ({ step, formType }: FormProgressProps) => { return progress } return ( - <div className={'profile-type-progress'}> - <div className={'profile-type-progress-label'}>{getProgress()}%</div> - <div className={'profile-type-progress-bar-container'}> + <div className="profile-type-progress"> + <div className="profile-type-progress-label">{getProgress()}%</div> + <div className="profile-type-progress-bar-container"> <div - className={'profile-type-progress-bar-content'} + className="profile-type-progress-bar-content" style={{ width: `${getProgress()}%` }} /> </div> diff --git a/src/components/FormGlobal/formProgress.scss b/src/components/CommonKit/FormProgress/formProgress.scss similarity index 93% rename from src/components/FormGlobal/formProgress.scss rename to src/components/CommonKit/FormProgress/formProgress.scss index d14628b00b61b1a07769ddd104ad634db475a383..dd1f500a85c283e899f54be9a04d1b5963755057 100644 --- a/src/components/FormGlobal/formProgress.scss +++ b/src/components/CommonKit/FormProgress/formProgress.scss @@ -1,4 +1,4 @@ -@import '../../styles/base/color'; +@import 'src/styles/base/color'; .profile-type-progress { display: flex; diff --git a/src/components/Challenge/StarsContainer.tsx b/src/components/CommonKit/StarsContainer/StarsContainer.tsx similarity index 100% rename from src/components/Challenge/StarsContainer.tsx rename to src/components/CommonKit/StarsContainer/StarsContainer.tsx diff --git a/src/components/CommonKit/Switch/StyledSwitch.spec.tsx b/src/components/CommonKit/Switch/StyledSwitch.spec.tsx index b3605a86cb94e5fc6e909b6f83b65692c7006bb6..8af7bc846b26a09e14909a28e083b2aaa2fa8de1 100644 --- a/src/components/CommonKit/Switch/StyledSwitch.spec.tsx +++ b/src/components/CommonKit/Switch/StyledSwitch.spec.tsx @@ -1,4 +1,4 @@ -import { FluidType } from 'enum/fluid.enum' +import { FluidType } from 'enums' import { mount } from 'enzyme' import React from 'react' import StyledSwitch from './StyledSwitch' diff --git a/src/components/CommonKit/Switch/StyledSwitch.tsx b/src/components/CommonKit/Switch/StyledSwitch.tsx index 87535cd0b1c9a312f4aa54685896f354386e7e62..d8136853ef6452b872454f953f6f3ba6c8db0088 100644 --- a/src/components/CommonKit/Switch/StyledSwitch.tsx +++ b/src/components/CommonKit/Switch/StyledSwitch.tsx @@ -1,6 +1,6 @@ import { withStyles } from '@material-ui/core/styles' import Switch, { SwitchProps } from '@material-ui/core/Switch' -import { FluidType } from 'enum/fluid.enum' +import { FluidType } from 'enums' import React from 'react' const SwitchBase = withStyles({ diff --git a/src/components/Connection/Connection.spec.tsx b/src/components/Connection/Connection.spec.tsx index d339c9b712e517eca65902f26761e3e337ae0533..ba59c476150e5239a40ca42fe343f9305220116f 100644 --- a/src/components/Connection/Connection.spec.tsx +++ b/src/components/Connection/Connection.spec.tsx @@ -1,63 +1,30 @@ import Connection from 'components/Connection/Connection' +import { FluidType } from 'enums' import { mount } from 'enzyme' import toJson from 'enzyme-to-json' import React from 'react' -import * as reactRedux from 'react-redux' import { Provider } from 'react-redux' -import configureStore from 'redux-mock-store' -import { fluidStatusConnectedData } from '../../../tests/__mocks__/fluidStatusData.mock' -import { globalStateData } from '../../../tests/__mocks__/globalStateData.mock' +import { createMockEcolyoStore } from 'tests/__mocks__/store' -jest.mock('components/Connection/EPGLConnect/EpglInit', () => { - return jest.fn(() => { - return <div id="EpglInit" /> - }) -}) +jest.mock('components/Connection/EPGLConnect/EpglInit', () => 'mock-EpglInit') -jest.mock('components/Connection/GRDFConnect/GrdfInit', () => { - return jest.fn(() => { - return <div id="GrdfInit" /> - }) -}) +jest.mock('components/Connection/GRDFConnect/GrdfInit', () => 'mock-GrdfInit') -jest.mock('cozy-ui/transpiled/react/I18n', () => { - return { - useI18n: jest.fn(() => { - return { - t: (str: string) => str, - } - }), - } -}) -const mockedNavigate = jest.fn() -jest.mock('react-router-dom', () => ({ - ...jest.requireActual('react-router-dom'), - useNavigate: () => mockedNavigate, -})) -const mockStore = configureStore([]) -const useDispatchSpy = jest.spyOn(reactRedux, 'useDispatch') -const useSelectorSpy = jest.spyOn(reactRedux, 'useSelector') describe('Connection component test', () => { - const store = mockStore({ - ecolyo: { - global: globalStateData, - }, - }) + const store = createMockEcolyoStore() it('should call GrdfInit', () => { const wrapper = mount( <Provider store={store}> - <Connection fluidStatus={fluidStatusConnectedData[2]} /> + <Connection fluidType={FluidType.GAS} /> </Provider> ) expect(toJson(wrapper)).toMatchSnapshot() }) it('should call EpglInit', () => { - useDispatchSpy.mockReturnValue(jest.fn()) - useSelectorSpy.mockReturnValue(globalStateData) const wrapper = mount( <Provider store={store}> - <Connection fluidStatus={fluidStatusConnectedData[0]} /> + <Connection fluidType={FluidType.WATER} /> </Provider> ) expect(toJson(wrapper)).toMatchSnapshot() diff --git a/src/components/Connection/Connection.tsx b/src/components/Connection/Connection.tsx index 3e0aedc0f10ce68b2ec0df6c396c7be7b5f58bc8..04513039f6f7c9d959eefa6649142fb884619e5b 100644 --- a/src/components/Connection/Connection.tsx +++ b/src/components/Connection/Connection.tsx @@ -1,35 +1,35 @@ -import { FluidType } from 'enum/fluid.enum' -import { FluidConnection, FluidStatus } from 'models' -import React, { Dispatch, useCallback } from 'react' -import { useDispatch } from 'react-redux' -import { AppActionsTypes } from 'store' -import { updatedFluidConnection } from 'store/global/global.actions' +import { FluidType } from 'enums' +import { FluidConnection } from 'models' +import React, { useCallback } from 'react' +import { updateFluidConnection } from 'store/global/global.slice' +import { useAppDispatch, useAppSelector } from 'store/hooks' import EpglInit from './EPGLConnect/EpglInit' import GrdfInit from './GRDFConnect/GrdfInit' import SgeInit from './SGEConnect/SgeInit' import './connection.scss' -const Connection = ({ fluidStatus }: { fluidStatus: FluidStatus }) => { - const dispatch = useDispatch<Dispatch<AppActionsTypes>>() +const Connection = ({ fluidType }: { fluidType: FluidType }) => { + const { fluidStatus } = useAppSelector(state => state.ecolyo.global) + const currentFluidStatus = fluidStatus[fluidType] + const dispatch = useAppDispatch() const handleSuccess = useCallback(async () => { const updatedConnection: FluidConnection = { - ...fluidStatus.connection, + ...currentFluidStatus.connection, shouldLaunchKonnector: true, } - dispatch(updatedFluidConnection(fluidStatus.fluidType, updatedConnection)) - }, [dispatch, fluidStatus.fluidType, fluidStatus.connection]) + dispatch( + updateFluidConnection({ + fluidType: fluidType, + fluidConnection: updatedConnection, + }) + ) + }, [dispatch, fluidType, currentFluidStatus.connection]) return ( <div className="konnector-form"> - {fluidStatus.fluidType === FluidType.ELECTRICITY && ( - <SgeInit fluidStatus={fluidStatus} /> - )} - {fluidStatus.fluidType === FluidType.WATER && ( - <EpglInit fluidStatus={fluidStatus} /> - )} - {fluidStatus.fluidType === FluidType.GAS && ( - <GrdfInit fluidStatus={fluidStatus} onSuccess={handleSuccess} /> - )} + {fluidType === FluidType.ELECTRICITY && <SgeInit />} + {fluidType === FluidType.WATER && <EpglInit />} + {fluidType === FluidType.GAS && <GrdfInit onSuccess={handleSuccess} />} </div> ) } diff --git a/src/components/Connection/EPGLConnect/EpglBill.tsx b/src/components/Connection/EPGLConnect/EpglBill.tsx index ae01998eb4b042ecc3ab9e13e29d318eb2653066..2141111af9f9473bb61c88c65462e8dd4061918d 100644 --- a/src/components/Connection/EPGLConnect/EpglBill.tsx +++ b/src/components/Connection/EPGLConnect/EpglBill.tsx @@ -2,18 +2,18 @@ import Button from '@material-ui/core/Button' import WaterBillIcon from 'assets/icons/visu/onboarding/water_bill.svg' import StyledIcon from 'components/CommonKit/Icon/StyledIcon' import { useI18n } from 'cozy-ui/transpiled/react/I18n' -import { FluidStatus } from 'models' -import React, { Dispatch } from 'react' -import { useDispatch } from 'react-redux' -import { AppActionsTypes } from 'store' +import { FluidType } from 'enums' +import React from 'react' import { setShowOfflineData } from 'store/chart/chart.slice' +import { useAppDispatch, useAppSelector } from 'store/hooks' import { openConnectionModal } from 'store/modal/modal.slice' -import { decoreText } from 'utils/decoreText' import '../connection.scss' -const EpglBill = ({ fluidStatus }: { fluidStatus: FluidStatus }) => { +const EpglBill = () => { const { t } = useI18n() - const dispatch = useDispatch<Dispatch<AppActionsTypes>>() + const dispatch = useAppDispatch() + const { fluidStatus } = useAppSelector(state => state.ecolyo.global) + const currentFluidStatus = fluidStatus[FluidType.WATER] return ( <div className="connection-form"> @@ -22,9 +22,10 @@ const EpglBill = ({ fluidStatus }: { fluidStatus: FluidStatus }) => { </p> <StyledIcon icon={WaterBillIcon} size={180} /> - <p className={'connection-form-subtitle eglgrandlyon text-16-regular'}> - {decoreText(t('auth.eglgrandlyon.bill'))} - </p> + <p + className="connection-form-subtitle eglgrandlyon text-16-regular" + dangerouslySetInnerHTML={{ __html: t('auth.eglgrandlyon.bill') }} + /> <div className="connection-form-button"> <Button @@ -37,7 +38,7 @@ const EpglBill = ({ fluidStatus }: { fluidStatus: FluidStatus }) => { > {t('auth.eglgrandlyon.connect')} </Button> - {fluidStatus.firstDataDate && ( + {currentFluidStatus.firstDataDate && ( <Button classes={{ root: 'btn-secondary', diff --git a/src/components/Connection/EPGLConnect/EpglForm.tsx b/src/components/Connection/EPGLConnect/EpglForm.tsx index 670f7f222a9baa4fcc7e132783c8d83d9244fa1e..7626152639d743c4bfd23c1ba892c365bedd1387 100644 --- a/src/components/Connection/EPGLConnect/EpglForm.tsx +++ b/src/components/Connection/EPGLConnect/EpglForm.tsx @@ -1,15 +1,9 @@ -import FormLogin from 'components/Connection/FormLogin' import { useI18n } from 'cozy-ui/transpiled/react/I18n' -import { FluidStatus } from 'models' import React from 'react' import '../connection.scss' +import FormLogin from './FormLogin/FormLogin' -interface EpglFormProps { - fluidStatus: FluidStatus - hasCreatedAccount: boolean -} - -const EpglForm = ({ fluidStatus, hasCreatedAccount }: EpglFormProps) => { +const EpglForm = ({ hasCreatedAccount }: { hasCreatedAccount: boolean }) => { const { t } = useI18n() return ( @@ -22,7 +16,7 @@ const EpglForm = ({ fluidStatus, hasCreatedAccount }: EpglFormProps) => { <div className="connection-form-subtitle text-18-bold"> {t('auth.eglgrandlyon.with_account.subtitle1')} </div> - <FormLogin fluidStatus={fluidStatus} /> + <FormLogin /> </div> ) } diff --git a/src/components/Connection/EPGLConnect/EpglInit.tsx b/src/components/Connection/EPGLConnect/EpglInit.tsx index be04c95c0c4aaad34b39624357d7a7b71942480c..d79dd4a9d07517da49bed11e57cc3d59342c7bf5 100644 --- a/src/components/Connection/EPGLConnect/EpglInit.tsx +++ b/src/components/Connection/EPGLConnect/EpglInit.tsx @@ -1,19 +1,21 @@ import EpglConnectModal from 'components/Connection/PartnerConnectModal/EpglConnectModal' -import { FluidStatus } from 'models' -import React, { Dispatch, useCallback, useState } from 'react' -import { useDispatch, useSelector } from 'react-redux' -import { AppActionsTypes, AppStore } from 'store' +import { FluidType } from 'enums' +import React, { useCallback, useState } from 'react' +import { useAppDispatch, useAppSelector } from 'store/hooks' import { openConnectionModal } from 'store/modal/modal.slice' import '../connection.scss' import EpglBill from './EpglBill' import EpglForm from './EpglForm' -const EpglInit = ({ fluidStatus }: { fluidStatus: FluidStatus }) => { - const dispatch = useDispatch<Dispatch<AppActionsTypes>>() +const EpglInit = () => { + const dispatch = useAppDispatch() const { modal: { isConnectionModalOpen }, - } = useSelector((state: AppStore) => state.ecolyo) - const siteLink: string = fluidStatus.connection.konnectorConfig.siteLink + global: { fluidStatus }, + } = useAppSelector(state => state.ecolyo) + const currentFluidStatus = fluidStatus[FluidType.WATER] + const siteLink: string = + currentFluidStatus.connection.konnectorConfig.siteLink const [showForm, setShowForm] = useState(false) const [hasCreatedAccount, setHasCreatedAccount] = useState(false) @@ -25,12 +27,9 @@ const EpglInit = ({ fluidStatus }: { fluidStatus: FluidStatus }) => { return ( <> {!showForm ? ( - <EpglBill fluidStatus={fluidStatus} /> + <EpglBill /> ) : ( - <EpglForm - fluidStatus={fluidStatus} - hasCreatedAccount={hasCreatedAccount} - /> + <EpglForm hasCreatedAccount={hasCreatedAccount} /> )} <EpglConnectModal open={isConnectionModalOpen} diff --git a/src/components/Connection/FormLogin.tsx b/src/components/Connection/EPGLConnect/FormLogin/FormLogin.tsx similarity index 79% rename from src/components/Connection/FormLogin.tsx rename to src/components/Connection/EPGLConnect/FormLogin/FormLogin.tsx index e3c88579cf078e8d94dffb5e154617be6309c1ac..f2216ea1d7d6e144ec27a8af7b580c00e280168a 100644 --- a/src/components/Connection/FormLogin.tsx +++ b/src/components/Connection/EPGLConnect/FormLogin/FormLogin.tsx @@ -5,19 +5,24 @@ import StyledIcon from 'components/CommonKit/Icon/StyledIcon' import StyledIconButton from 'components/CommonKit/IconButton/StyledIconButton' import useKonnectorAuth from 'components/Hooks/useKonnectorAuth' import { useI18n } from 'cozy-ui/transpiled/react/I18n' -import { FluidType } from 'enum/fluid.enum' -import { Account, AccountAuthData, FluidStatus } from 'models' +import { FluidType } from 'enums' +import { Account, AccountAuthData } from 'models' import React, { useEffect, useState } from 'react' +import { useAppSelector } from 'store/hooks' +import logApp from 'utils/logger' import { getPartnerPicto } from 'utils/picto' import './formLogin.scss' -const FormLogin = ({ fluidStatus }: { fluidStatus: FluidStatus }) => { +const FormLogin = () => { const { t } = useI18n() - const konnectorSlug: string = fluidStatus.connection.konnectorConfig.slug - const lastKnownCredentials: string | undefined = - fluidStatus.connection.konnectorConfig.lastKnownCredentials - const fluidName: string = FluidType[fluidStatus.fluidType] - const account: Account | null = fluidStatus.connection.account + const { fluidStatus, lastEpglLogin } = useAppSelector( + state => state.ecolyo.global + ) + const currentFluidStatus = fluidStatus[FluidType.WATER] + const konnectorSlug: string = + currentFluidStatus.connection.konnectorConfig.slug + const fluidName: string = FluidType[currentFluidStatus.fluidType] + const account: Account | null = currentFluidStatus.connection.account const [login, setLogin] = useState<string>('') const [password, setPassword] = useState<string>('') @@ -26,7 +31,7 @@ const FormLogin = ({ fluidStatus }: { fluidStatus: FluidStatus }) => { const icon = getPartnerPicto(konnectorSlug) const [connect, update, connectError] = useKonnectorAuth( - fluidStatus, + currentFluidStatus.fluidType, login, password ) @@ -71,7 +76,8 @@ const FormLogin = ({ fluidStatus }: { fluidStatus: FluidStatus }) => { await update() } } catch (error) { - Sentry.captureException(JSON.stringify({ error })) + logApp.error(error) + Sentry.captureException(error) setLoading(false) } } @@ -87,11 +93,11 @@ const FormLogin = ({ fluidStatus }: { fluidStatus: FluidStatus }) => { if (authData.login) { setLogin(authData.login) } - } else if (lastKnownCredentials) { - setLogin(lastKnownCredentials) + } else if (lastEpglLogin) { + setLogin(lastEpglLogin) setError(t('konnector_form.error_login_failed')) } - }, [account, lastKnownCredentials, t]) + }, [account, lastEpglLogin, t]) return ( <form @@ -107,8 +113,8 @@ const FormLogin = ({ fluidStatus }: { fluidStatus: FluidStatus }) => { ? 'form-control form-input' : 'form-control form-input --error' } - aria-label={t('auth.' + konnectorSlug + '.connect_form.login')} - placeholder={t('auth.' + konnectorSlug + '.connect_form.login')} + aria-label={t(`auth.${konnectorSlug}.connect_form.login`)} + placeholder={t(`auth.${konnectorSlug}.connect_form.login`)} name="login" onChange={(e: React.ChangeEvent<HTMLInputElement>) => changeLogin(e.target.value) @@ -126,8 +132,8 @@ const FormLogin = ({ fluidStatus }: { fluidStatus: FluidStatus }) => { ? 'form-control form-input' : 'form-control form-input --error' } - aria-label={t('auth.' + konnectorSlug + '.connect_form.password')} - placeholder={t('auth.' + konnectorSlug + '.connect_form.password')} + aria-label={t(`auth.${konnectorSlug}.connect_form.password`)} + placeholder={t(`auth.${konnectorSlug}.connect_form.password`)} name="password" onChange={(e: React.ChangeEvent<HTMLInputElement>) => changePassword(e.target.value) @@ -160,7 +166,7 @@ const FormLogin = ({ fluidStatus }: { fluidStatus: FluidStatus }) => { {icon && <StyledIcon icon={icon} size={80} />} </div> <div className="connection-form-connect-button-text text-18-bold"> - <div>{t('auth.' + konnectorSlug + '.connect_form.label')}</div> + <div>{t(`auth.${konnectorSlug}.connect_form.label`)}</div> </div> </div> </Button> diff --git a/src/components/Connection/formLogin.scss b/src/components/Connection/EPGLConnect/FormLogin/formLogin.scss similarity index 100% rename from src/components/Connection/formLogin.scss rename to src/components/Connection/EPGLConnect/FormLogin/formLogin.scss diff --git a/src/components/Connection/ExpiredConsentModal.spec.tsx b/src/components/Connection/ExpiredConsentModal/ExpiredConsentModal.spec.tsx similarity index 67% rename from src/components/Connection/ExpiredConsentModal.spec.tsx rename to src/components/Connection/ExpiredConsentModal/ExpiredConsentModal.spec.tsx index 74ba58c51bf9595adbf60df0ba2ba655e6a8edc6..de738abe48d8e42a4f067e58b9190c7e04879028 100644 --- a/src/components/Connection/ExpiredConsentModal.spec.tsx +++ b/src/components/Connection/ExpiredConsentModal/ExpiredConsentModal.spec.tsx @@ -1,41 +1,27 @@ import { Button } from '@material-ui/core' -import { FluidType } from 'enum/fluid.enum' +import { FluidType } from 'enums' import { mount } from 'enzyme' import toJson from 'enzyme-to-json' import React from 'react' -import * as reactRedux from 'react-redux' import { Provider } from 'react-redux' -import configureStore from 'redux-mock-store' -import { fluidStatusConnectedData } from '../../../tests/__mocks__/fluidStatusData.mock' -import { globalStateData } from '../../../tests/__mocks__/globalStateData.mock' +import * as storeHooks from 'store/hooks' +import { fluidStatusConnectedData } from 'tests/__mocks__/fluidStatusData.mock' +import { createMockEcolyoStore } from 'tests/__mocks__/store' import ExpiredConsentModal from './ExpiredConsentModal' -jest.mock('cozy-ui/transpiled/react/I18n', () => { - return { - useI18n: jest.fn(() => { - return { - t: (str: string) => str, - } - }), - } -}) const mockedNavigate = jest.fn() jest.mock('react-router-dom', () => ({ ...jest.requireActual('react-router-dom'), useNavigate: () => mockedNavigate, })) +const mockAppDispatch = jest.spyOn(storeHooks, 'useAppDispatch') const mockToggleModal = jest.fn() const mockHandleCloseClick = jest.fn() -const mockStore = configureStore([]) describe('ExpiredConsentModal component', () => { - const store = mockStore({ - ecolyo: { - global: globalStateData, - }, - }) + const store = createMockEcolyoStore() beforeEach(() => { - mockedNavigate.mockReset() + jest.clearAllMocks() }) it('should be rendered correctly', () => { const component = mount( @@ -51,9 +37,6 @@ describe('ExpiredConsentModal component', () => { expect(toJson(component)).toMatchSnapshot() }) it('should launch the update consent process for GRDF', () => { - const useDispatchSpy = jest.spyOn(reactRedux, 'useDispatch') - useDispatchSpy.mockReturnValue(jest.fn()) - const component = mount( <Provider store={store}> <ExpiredConsentModal @@ -65,14 +48,13 @@ describe('ExpiredConsentModal component', () => { </Provider> ) component.find(Button).at(1).simulate('click') - expect(useDispatchSpy).toHaveBeenCalledTimes(1) + expect(mockAppDispatch).toHaveBeenCalledTimes(1) expect(mockedNavigate).toHaveBeenCalledTimes(1) }) it('should launch the update consent process for Enedis', () => { - const useDispatchSpy = jest.spyOn(reactRedux, 'useDispatch') - useDispatchSpy.mockReturnValue(jest.fn()) - const useSelectorSpy = jest.spyOn(reactRedux, 'useSelector') - useSelectorSpy.mockReturnValue({ fluidStatus: fluidStatusConnectedData }) + const store = createMockEcolyoStore({ + global: { fluidStatus: fluidStatusConnectedData }, + }) const component = mount( <Provider store={store}> <ExpiredConsentModal @@ -84,7 +66,7 @@ describe('ExpiredConsentModal component', () => { </Provider> ) component.find(Button).at(1).simulate('click') - expect(useDispatchSpy).toHaveBeenCalledTimes(2) + expect(mockAppDispatch).toHaveBeenCalledTimes(1) expect(mockedNavigate).toHaveBeenCalledTimes(1) }) it('should click on close modal', () => { diff --git a/src/components/Connection/ExpiredConsentModal.tsx b/src/components/Connection/ExpiredConsentModal/ExpiredConsentModal.tsx similarity index 89% rename from src/components/Connection/ExpiredConsentModal.tsx rename to src/components/Connection/ExpiredConsentModal/ExpiredConsentModal.tsx index 194ee25246f29f482eded5ffa267aa9fceaeb08e..6060c4ecea8c7fcde90ac452a1816db1e4fa476b 100644 --- a/src/components/Connection/ExpiredConsentModal.tsx +++ b/src/components/Connection/ExpiredConsentModal/ExpiredConsentModal.tsx @@ -5,16 +5,15 @@ import EnedisIcon from 'assets/icons/ico/consent-outdated-enedis.svg' import GrdfIcon from 'assets/icons/ico/consent-outdated-grdf.svg' import { useI18n } from 'cozy-ui/transpiled/react/I18n' import Icon from 'cozy-ui/transpiled/react/Icon' -import { FluidType } from 'enum/fluid.enum' +import { FluidType } from 'enums' import { AccountSgeData } from 'models' -import React, { Dispatch, useCallback } from 'react' -import { useDispatch, useSelector } from 'react-redux' +import React, { useCallback } from 'react' import { useNavigate } from 'react-router-dom' -import { AppActionsTypes, AppStore } from 'store' import { setShouldRefreshConsent, updateSgeStore, -} from 'store/global/global.actions' +} from 'store/global/global.slice' +import { useAppDispatch, useAppSelector } from 'store/hooks' import { getFluidName } from 'utils/utils' import './expiredConsentModal.scss' @@ -33,9 +32,8 @@ const ExpiredConsentModal = ({ }: ExpiredConsentModalProps) => { const { t } = useI18n() const navigate = useNavigate() - const dispatch = useDispatch<Dispatch<AppActionsTypes>>() - const { fluidStatus } = useSelector((state: AppStore) => state.ecolyo.global) - + const dispatch = useAppDispatch() + const { fluidStatus } = useAppSelector(state => state.ecolyo.global) const launchUpdateConsent = useCallback(() => { if (fluidType === FluidType.ELECTRICITY) { const accountData = fluidStatus[FluidType.ELECTRICITY].connection.account @@ -65,13 +63,13 @@ const ExpiredConsentModal = ({ <Dialog open={open} onClose={toggleModal} - aria-labelledby={'accessibility-title'} + aria-labelledby="accessibility-title" classes={{ root: 'modal-root', paper: 'modal-paper', }} > - <div id={'accessibility-title'}> + <div id="accessibility-title"> {t('consumption_visualizer.modal.window_title')} </div> <IconButton diff --git a/src/components/Connection/__snapshots__/ExpiredConsentModal.spec.tsx.snap b/src/components/Connection/ExpiredConsentModal/__snapshots__/ExpiredConsentModal.spec.tsx.snap similarity index 100% rename from src/components/Connection/__snapshots__/ExpiredConsentModal.spec.tsx.snap rename to src/components/Connection/ExpiredConsentModal/__snapshots__/ExpiredConsentModal.spec.tsx.snap diff --git a/src/components/Connection/expiredConsentModal.scss b/src/components/Connection/ExpiredConsentModal/expiredConsentModal.scss similarity index 91% rename from src/components/Connection/expiredConsentModal.scss rename to src/components/Connection/ExpiredConsentModal/expiredConsentModal.scss index 1c67d8684f3e1987194936bc92ba0cc272df55e3..c98e678e88aee9d88611af579fc0f3cfcfab04fc 100644 --- a/src/components/Connection/expiredConsentModal.scss +++ b/src/components/Connection/ExpiredConsentModal/expiredConsentModal.scss @@ -1,4 +1,4 @@ -@import '../../styles/base/color'; +@import 'src/styles/base/color'; .expired-consent-modal { .icon-main { diff --git a/src/components/Connection/GRDFConnect/GrdfBill.tsx b/src/components/Connection/GRDFConnect/GrdfBill.tsx index ad07fb26ee9cf63f400865201332c19f50a01f00..37a52dd2b6dbdb51127424dcc9ea802d408a1b7c 100644 --- a/src/components/Connection/GRDFConnect/GrdfBill.tsx +++ b/src/components/Connection/GRDFConnect/GrdfBill.tsx @@ -2,28 +2,29 @@ import Button from '@material-ui/core/Button' import GasBillIcon from 'assets/icons/visu/onboarding/gas_bill.svg' import StyledIcon from 'components/CommonKit/Icon/StyledIcon' import { useI18n } from 'cozy-ui/transpiled/react/I18n' -import { FluidStatus } from 'models' -import React, { Dispatch } from 'react' -import { useDispatch } from 'react-redux' -import { AppActionsTypes } from 'store' +import { FluidType } from 'enums' +import React from 'react' import { setShowOfflineData } from 'store/chart/chart.slice' +import { useAppDispatch, useAppSelector } from 'store/hooks' import { openConnectionModal } from 'store/modal/modal.slice' -import { decoreText } from 'utils/decoreText' import '../connection.scss' -const GrdfBill = ({ fluidStatus }: { fluidStatus: FluidStatus }) => { +const GrdfBill = () => { const { t } = useI18n() - const dispatch = useDispatch<Dispatch<AppActionsTypes>>() + const dispatch = useAppDispatch() + const { fluidStatus } = useAppSelector(state => state.ecolyo.global) + const currentFluidStatus = fluidStatus[FluidType.GAS] return ( <div className="connection-form"> - <p className={'connection-form-title grdfgrandlyon text-20-bold'}> + <p className="connection-form-title grdfgrandlyon text-20-bold"> {t('auth.grdfgrandlyon.no_account.title')} </p> <StyledIcon icon={GasBillIcon} size={180} /> - <p className={'connection-form-subtitle grdfgrandlyon text-16-regular'}> - {decoreText(t('auth.grdfgrandlyon.bill'))} - </p> + <p + className="connection-form-subtitle grdfgrandlyon text-16-regular" + dangerouslySetInnerHTML={{ __html: t('auth.grdfgrandlyon.bill') }} + /> <div className="connection-form-button"> <Button @@ -36,7 +37,7 @@ const GrdfBill = ({ fluidStatus }: { fluidStatus: FluidStatus }) => { > {t('auth.grdfgrandlyon.connect')} </Button> - {fluidStatus.firstDataDate && ( + {currentFluidStatus.firstDataDate && ( <Button classes={{ root: 'btn-secondary', diff --git a/src/components/Connection/GRDFConnect/GrdfForm.tsx b/src/components/Connection/GRDFConnect/GrdfForm.tsx index b2f699e71838058c94363ef0388d709edcfdba60..070083929ac756efb6df51a5af879f4d8b00ab2a 100644 --- a/src/components/Connection/GRDFConnect/GrdfForm.tsx +++ b/src/components/Connection/GRDFConnect/GrdfForm.tsx @@ -2,15 +2,14 @@ import Button from '@material-ui/core/Button' import iconGrdfLogo from 'assets/icons/visu/grdf-logo.svg' import StyledIcon from 'components/CommonKit/Icon/StyledIcon' import { useI18n } from 'cozy-ui/transpiled/react/I18n' -import React, { Dispatch } from 'react' -import { useDispatch } from 'react-redux' -import { AppActionsTypes } from 'store' +import React from 'react' +import { useAppDispatch } from 'store/hooks' import { openConnectionModal } from 'store/modal/modal.slice' import '../connection.scss' const GrdfForm = () => { const { t } = useI18n() - const dispatch = useDispatch<Dispatch<AppActionsTypes>>() + const dispatch = useAppDispatch() return ( <div className="connection-form"> diff --git a/src/components/Connection/GRDFConnect/GrdfInit.tsx b/src/components/Connection/GRDFConnect/GrdfInit.tsx index d47625171b37b485ac722f1e80bfdb00734d81f0..8761ee395e1bac7ac8fbcc9a15b075cb798a7731 100644 --- a/src/components/Connection/GRDFConnect/GrdfInit.tsx +++ b/src/components/Connection/GRDFConnect/GrdfInit.tsx @@ -1,36 +1,34 @@ import GrdfConnectModal from 'components/Connection/PartnerConnectModal/GrdfConnectModal' import { useClient } from 'cozy-client' -import { UsageEventType } from 'enum/usageEvent.enum' -import { FluidConnection, FluidStatus, Konnector, Trigger } from 'models' -import React, { Dispatch, useCallback, useState } from 'react' -import { useDispatch, useSelector } from 'react-redux' +import { FluidType, UsageEventType } from 'enums' +import { FluidConnection, Konnector, Trigger } from 'models' +import React, { useCallback, useState } from 'react' import AccountService from 'services/account.service' import TriggerService from 'services/triggers.service' import UsageEventService from 'services/usageEvent.service' -import { AppActionsTypes, AppStore } from 'store' -import { updatedFluidConnection } from 'store/global/global.actions' +import { updateFluidConnection } from 'store/global/global.slice' +import { useAppDispatch, useAppSelector } from 'store/hooks' import { openConnectionModal } from 'store/modal/modal.slice' import '../connection.scss' import GrdfBill from './GrdfBill' import GrdfForm from './GrdfForm' -interface GrdfInitProps { - fluidStatus: FluidStatus - onSuccess: () => Promise<void> -} - -const GrdfInit = ({ fluidStatus, onSuccess }: GrdfInitProps) => { +const GrdfInit = ({ onSuccess }: { onSuccess: () => Promise<void> }) => { const client = useClient() - const dispatch = useDispatch<Dispatch<AppActionsTypes>>() + const dispatch = useAppDispatch() const { modal: { isConnectionModalOpen }, - } = useSelector((state: AppStore) => state.ecolyo) + global: { fluidStatus }, + } = useAppSelector(state => state.ecolyo) const [showForm, setShowForm] = useState(false) - const konnectorSlug: string = fluidStatus.connection.konnectorConfig.slug - const siteLink: string = fluidStatus.connection.konnectorConfig.siteLink - const konnector: Konnector | null = fluidStatus.connection.konnector + const currentFluidStatus = fluidStatus[FluidType.GAS] + const konnectorSlug: string = + currentFluidStatus.connection.konnectorConfig.slug + const siteLink: string = + currentFluidStatus.connection.konnectorConfig.siteLink + const konnector: Konnector | null = currentFluidStatus.connection.konnector const handleSuccess = useCallback( async (accountId: string) => { @@ -39,12 +37,15 @@ const GrdfInit = ({ fluidStatus, onSuccess }: GrdfInitProps) => { const account = await accountService.getAccount(accountId) if (!account) { const updatedConnection: FluidConnection = { - ...fluidStatus.connection, + ...currentFluidStatus.connection, account: null, trigger: null, } dispatch( - updatedFluidConnection(fluidStatus.fluidType, updatedConnection) + updateFluidConnection({ + fluidType: currentFluidStatus.fluidType, + fluidConnection: updatedConnection, + }) ) await UsageEventService.addEvent(client, { type: UsageEventType.KONNECTOR_CONNECT_EVENT, @@ -58,12 +59,15 @@ const GrdfInit = ({ fluidStatus, onSuccess }: GrdfInitProps) => { konnector ) const updatedConnection: FluidConnection = { - ...fluidStatus.connection, + ...currentFluidStatus.connection, account: account, trigger: trigger, } dispatch( - updatedFluidConnection(fluidStatus.fluidType, updatedConnection) + updateFluidConnection({ + fluidType: currentFluidStatus.fluidType, + fluidConnection: updatedConnection, + }) ) onSuccess() } @@ -73,8 +77,8 @@ const GrdfInit = ({ fluidStatus, onSuccess }: GrdfInitProps) => { client, konnector, dispatch, - fluidStatus.fluidType, - fluidStatus.connection, + currentFluidStatus.fluidType, + currentFluidStatus.connection, onSuccess, konnectorSlug, ] @@ -86,12 +90,10 @@ const GrdfInit = ({ fluidStatus, onSuccess }: GrdfInitProps) => { return ( <> - {!showForm ? <GrdfBill fluidStatus={fluidStatus} /> : <GrdfForm />} + {!showForm ? <GrdfBill /> : <GrdfForm />} <GrdfConnectModal open={isConnectionModalOpen} showForm={showForm} - konnector={konnector} - fluidStatus={fluidStatus} handleCloseClick={() => dispatch(openConnectionModal(false))} setShowForm={setShowForm} goToPartnerSite={goToPartnerSite} diff --git a/src/components/Connection/DeleteGRDFAccountModal.spec.tsx b/src/components/Connection/GRDFDeleteAccountModal/DeleteGRDFAccountModal.spec.tsx similarity index 84% rename from src/components/Connection/DeleteGRDFAccountModal.spec.tsx rename to src/components/Connection/GRDFDeleteAccountModal/DeleteGRDFAccountModal.spec.tsx index 9450e052f8a28c8daeebbbeb3f00adabe959275d..ea767693397e0a5b816c5b3b0929a703902c491b 100644 --- a/src/components/Connection/DeleteGRDFAccountModal.spec.tsx +++ b/src/components/Connection/GRDFDeleteAccountModal/DeleteGRDFAccountModal.spec.tsx @@ -4,16 +4,6 @@ import toJson from 'enzyme-to-json' import React from 'react' import DeleteGRDFAccountModal from './DeleteGRDFAccountModal' -jest.mock('cozy-ui/transpiled/react/I18n', () => { - return { - useI18n: jest.fn(() => { - return { - t: (str: string) => str, - } - }), - } -}) - describe('DeleteGRDFAccountModal component', () => { it('should be rendered correctly', () => { const component = mount( diff --git a/src/components/Connection/DeleteGRDFAccountModal.tsx b/src/components/Connection/GRDFDeleteAccountModal/DeleteGRDFAccountModal.tsx similarity index 94% rename from src/components/Connection/DeleteGRDFAccountModal.tsx rename to src/components/Connection/GRDFDeleteAccountModal/DeleteGRDFAccountModal.tsx index d2464efca8c40d70a2b41a90fc34348c995a8e33..ace29175463e200c4de63077f52ecaf906930b70 100644 --- a/src/components/Connection/DeleteGRDFAccountModal.tsx +++ b/src/components/Connection/GRDFDeleteAccountModal/DeleteGRDFAccountModal.tsx @@ -29,13 +29,13 @@ const DeleteGRDFAccountModal = ({ <Dialog open={open} onClose={handleCloseClick} - aria-labelledby={'accessibility-title'} + aria-labelledby="accessibility-title" classes={{ root: 'modal-root', paper: 'modal-paper', }} > - <div id={'accessibility-title'}> + <div id="accessibility-title"> {t('consumption_visualizer.modal.window_title')} </div> <IconButton @@ -50,7 +50,7 @@ const DeleteGRDFAccountModal = ({ <Icon icon={GrdfIcon} size={135} /> </div> - <div className={`text-15-normal text1`}> + <div className="text-15-normal text1"> {t(`delete_grdf_modal.text1`)} </div> <div className="text-16-normal text2"> diff --git a/src/components/Connection/__snapshots__/DeleteGRDFAccountModal.spec.tsx.snap b/src/components/Connection/GRDFDeleteAccountModal/__snapshots__/DeleteGRDFAccountModal.spec.tsx.snap similarity index 100% rename from src/components/Connection/__snapshots__/DeleteGRDFAccountModal.spec.tsx.snap rename to src/components/Connection/GRDFDeleteAccountModal/__snapshots__/DeleteGRDFAccountModal.spec.tsx.snap diff --git a/src/components/Connection/deleteGRDFAccountModal.scss b/src/components/Connection/GRDFDeleteAccountModal/deleteGRDFAccountModal.scss similarity index 90% rename from src/components/Connection/deleteGRDFAccountModal.scss rename to src/components/Connection/GRDFDeleteAccountModal/deleteGRDFAccountModal.scss index be8f7158ed857f66f5ddbdc5549aa64e364c4b45..aafc248d0f1e42c872a9726d4401f4de802ed8c9 100644 --- a/src/components/Connection/deleteGRDFAccountModal.scss +++ b/src/components/Connection/GRDFDeleteAccountModal/deleteGRDFAccountModal.scss @@ -1,4 +1,4 @@ -@import '../../styles/base/color'; +@import 'src/styles/base/color'; .delete-grdf-modal { .icon-main { diff --git a/src/components/Connection/PartnerConnectModal/EpglConnectModal.tsx b/src/components/Connection/PartnerConnectModal/EpglConnectModal.tsx index 2442a5f028eedcb7d50f775c3f0e900789192002..f32093cd6c8e96f72beb6a0a660eb86546f343dd 100644 --- a/src/components/Connection/PartnerConnectModal/EpglConnectModal.tsx +++ b/src/components/Connection/PartnerConnectModal/EpglConnectModal.tsx @@ -2,9 +2,9 @@ import { Button, Dialog, IconButton } from '@material-ui/core' import CloseIcon from 'assets/icons/ico/close.svg' import { useI18n } from 'cozy-ui/transpiled/react/I18n' import Icon from 'cozy-ui/transpiled/react/Icon' -import { Step } from 'models/step.model' -import React, { useCallback, useEffect, useState } from 'react' +import React, { useEffect, useState } from 'react' import './PartnerConnectModal.scss' +import { StepContent } from './StepContent.interface' import EpglCreateAccount from './Steps/EpglCreateAccount' import EpglDoYouHaveAccount from './Steps/EpglDoYouHaveAccount' @@ -36,29 +36,24 @@ const EpglConnectModal = ({ } }, [open]) - const goToCreateAccountStep = useCallback(() => { - setCurrentStep(StepEnum.CreateAccount) - }, []) - const goToDoYouHaveAccountStep = useCallback(() => { - setCurrentStep(StepEnum.DoYouHaveAccount) - }, []) - const handleGoToPartnerSite = useCallback(() => { + const handleGoToPartnerSite = () => { goToPartnerSite() setHasCreatedAccount(true) setShowForm(true) handleCloseClick() - }, [goToPartnerSite, handleCloseClick, setHasCreatedAccount, setShowForm]) - const handleShowForm = useCallback(() => { + } + + const handleShowForm = () => { setShowForm(true) handleCloseClick() - }, [handleCloseClick, setShowForm]) + } - const steps: Record<StepEnum, Step> = { + const steps: Record<StepEnum, StepContent> = { [StepEnum.DoYouHaveAccount]: { content: <EpglDoYouHaveAccount />, leftButton: ( <Button - onClick={goToCreateAccountStep} + onClick={() => setCurrentStep(StepEnum.CreateAccount)} classes={{ root: 'btn-profile-back', label: 'text-16-bold', @@ -83,7 +78,7 @@ const EpglConnectModal = ({ content: <EpglCreateAccount />, leftButton: ( <Button - onClick={goToDoYouHaveAccountStep} + onClick={() => setCurrentStep(StepEnum.DoYouHaveAccount)} classes={{ root: 'btn-profile-back', label: 'text-16-bold', diff --git a/src/components/Connection/PartnerConnectModal/GrdfConnectModal.tsx b/src/components/Connection/PartnerConnectModal/GrdfConnectModal.tsx index 871172766e322945ed6fc05f0f6b36b2c9c7a249..20d12143ecc8e46692e03c81caf9f32a4c0fd192 100644 --- a/src/components/Connection/PartnerConnectModal/GrdfConnectModal.tsx +++ b/src/components/Connection/PartnerConnectModal/GrdfConnectModal.tsx @@ -1,15 +1,14 @@ import { Button, Dialog, IconButton } from '@material-ui/core' import CloseIcon from 'assets/icons/ico/close.svg' import StyledIcon from 'components/CommonKit/Icon/StyledIcon' -import FormOAuth from 'components/Connection/FormOAuth' +import GrdfFormOAuth from 'components/Connection/PartnerConnectModal/Steps/GrdfFormOAuth' import { useI18n } from 'cozy-ui/transpiled/react/I18n' -import { FluidStatus, Konnector } from 'models' -import { Step } from 'models/step.model' -import React, { useCallback, useEffect, useState } from 'react' +import React, { useEffect, useState } from 'react' import './PartnerConnectModal.scss' +import { StepContent } from './StepContent.interface' import GrdfCreateAccount from './Steps/GrdfCreateAccount' import GrdfDoYouHaveAccount from './Steps/GrdfDoYouHaveAccount' -import GiveConsent from './Steps/GrdfGiveConsent' +import GrdfGiveConsent from './Steps/GrdfGiveConsent' enum StepEnum { DoYouHaveAccount, @@ -20,8 +19,6 @@ enum StepEnum { interface GrdfConnectModalProps { open: boolean showForm: boolean - konnector: Konnector | null - fluidStatus: FluidStatus handleCloseClick: () => void setShowForm: (value: boolean) => void goToPartnerSite: () => void @@ -31,8 +28,6 @@ interface GrdfConnectModalProps { const GrdfConnectModal = ({ open, showForm, - konnector, - fluidStatus, handleCloseClick, setShowForm, goToPartnerSite, @@ -40,6 +35,7 @@ const GrdfConnectModal = ({ }: GrdfConnectModalProps) => { const { t } = useI18n() const [currentStep, setCurrentStep] = useState(StepEnum.DoYouHaveAccount) + useEffect(() => { if (open) { showForm @@ -48,32 +44,21 @@ const GrdfConnectModal = ({ } }, [showForm, open]) - const goToCreateAccountStep = useCallback(() => { - setCurrentStep(StepEnum.CreateAccount) - }, []) - const goToGiveConsentStep = useCallback(() => { - setCurrentStep(StepEnum.GiveConsent) - }, []) - const goToDoYouHaveAccountStep = useCallback(() => { - setCurrentStep(StepEnum.DoYouHaveAccount) - }, []) - const handleGoToPartnerSite = useCallback(() => { + const handleGoToPartnerSite = () => { goToPartnerSite() setShowForm(true) handleCloseClick() - }, [goToPartnerSite, handleCloseClick, setShowForm]) - const handleGiveConsentPrevious = useCallback( - () => - showForm ? handleCloseClick() : setCurrentStep(StepEnum.DoYouHaveAccount), - [handleCloseClick, showForm] - ) + } + const handleGiveConsentPrevious = () => { + showForm ? handleCloseClick() : setCurrentStep(StepEnum.DoYouHaveAccount) + } - const steps: Record<StepEnum, Step> = { + const steps: Record<StepEnum, StepContent> = { [StepEnum.DoYouHaveAccount]: { content: <GrdfDoYouHaveAccount />, leftButton: ( <Button - onClick={goToCreateAccountStep} + onClick={() => setCurrentStep(StepEnum.CreateAccount)} classes={{ root: 'btn-profile-back', label: 'text-16-bold', @@ -84,7 +69,7 @@ const GrdfConnectModal = ({ ), rightButton: ( <Button - onClick={goToGiveConsentStep} + onClick={() => setCurrentStep(StepEnum.GiveConsent)} classes={{ root: 'btn-profile-next', label: 'text-16-bold', @@ -98,7 +83,7 @@ const GrdfConnectModal = ({ content: <GrdfCreateAccount />, leftButton: ( <Button - onClick={goToDoYouHaveAccountStep} + onClick={() => setCurrentStep(StepEnum.DoYouHaveAccount)} classes={{ root: 'btn-profile-back', label: 'text-16-bold', @@ -120,7 +105,7 @@ const GrdfConnectModal = ({ ), }, [StepEnum.GiveConsent]: { - content: <GiveConsent />, + content: <GrdfGiveConsent />, leftButton: ( <Button onClick={handleGiveConsentPrevious} @@ -132,13 +117,7 @@ const GrdfConnectModal = ({ {`< ${t('auth.button_previous')}`} </Button> ), - rightButton: ( - <FormOAuth - konnector={konnector} - onSuccess={handleSuccess} - fluidStatus={fluidStatus} - /> - ), + rightButton: <GrdfFormOAuth onSuccess={handleSuccess} />, }, } diff --git a/src/models/step.model.ts b/src/components/Connection/PartnerConnectModal/StepContent.interface.ts similarity index 71% rename from src/models/step.model.ts rename to src/components/Connection/PartnerConnectModal/StepContent.interface.ts index f4255471e7ded797677abddbebc65aea81d1de96..636a1283d26f7a2ff05a211541362bdfb7229a2b 100644 --- a/src/models/step.model.ts +++ b/src/components/Connection/PartnerConnectModal/StepContent.interface.ts @@ -1,4 +1,4 @@ -export interface Step { +export interface StepContent { content: JSX.Element leftButton: JSX.Element rightButton: JSX.Element diff --git a/src/components/Connection/PartnerConnectModal/Steps/EpglCreateAccount.tsx b/src/components/Connection/PartnerConnectModal/Steps/EpglCreateAccount.tsx index 7c362975af1fda45504b97594457f8946271681c..83bd2c6eaece03529ea5c74087093e5515440df9 100644 --- a/src/components/Connection/PartnerConnectModal/Steps/EpglCreateAccount.tsx +++ b/src/components/Connection/PartnerConnectModal/Steps/EpglCreateAccount.tsx @@ -2,7 +2,6 @@ import EglIcon from 'assets/icons/visu/onboarding/egl.svg' import StyledIcon from 'components/CommonKit/Icon/StyledIcon' import { useI18n } from 'cozy-ui/transpiled/react/I18n' import React from 'react' -import { decoreText } from 'utils/decoreText' import './stepDetail.scss' const EpglCreateAccount = () => { @@ -12,9 +11,12 @@ const EpglCreateAccount = () => { <div className="step-detail-info"> <StyledIcon className="info-icon" icon={EglIcon} size={220} /> <div className="info-content text-18-normal"> - <div className="info-content-text"> - {decoreText(t('auth.eglgrandlyon.step2.info1'))} - </div> + <div + className="info-content-text" + dangerouslySetInnerHTML={{ + __html: t('auth.eglgrandlyon.step2.info1'), + }} + /> </div> </div> ) diff --git a/src/components/Connection/PartnerConnectModal/Steps/EpglDoYouHaveAccount.tsx b/src/components/Connection/PartnerConnectModal/Steps/EpglDoYouHaveAccount.tsx index db1e1a186bee9c727d05fff097b1c3a8d844794b..58c6c40de06d7880c0f56204b2971df405c1cc6e 100644 --- a/src/components/Connection/PartnerConnectModal/Steps/EpglDoYouHaveAccount.tsx +++ b/src/components/Connection/PartnerConnectModal/Steps/EpglDoYouHaveAccount.tsx @@ -2,7 +2,6 @@ import BrowserEgl from 'assets/icons/visu/onboarding/browser_egl.svg' import StyledIcon from 'components/CommonKit/Icon/StyledIcon' import { useI18n } from 'cozy-ui/transpiled/react/I18n' import React from 'react' -import { decoreText } from 'utils/decoreText' import './stepDetail.scss' const EpglDoYouHaveAccount = () => { @@ -12,12 +11,18 @@ const EpglDoYouHaveAccount = () => { <div className="step-detail-info"> <StyledIcon className="info-icon" icon={BrowserEgl} size={150} /> <div className="info-content text-18-normal"> - <div className="info-content-text"> - {decoreText(t('auth.eglgrandlyon.step1.info1'))} - </div> - <div className="info-content-text"> - {decoreText(t('auth.eglgrandlyon.step1.info2'))} - </div> + <div + className="info-content-text" + dangerouslySetInnerHTML={{ + __html: t('auth.eglgrandlyon.step1.info1'), + }} + /> + <div + className="info-content-text" + dangerouslySetInnerHTML={{ + __html: t('auth.eglgrandlyon.step1.info2'), + }} + /> </div> </div> ) diff --git a/src/components/Connection/PartnerConnectModal/Steps/GrdfCreateAccount.tsx b/src/components/Connection/PartnerConnectModal/Steps/GrdfCreateAccount.tsx index 1751a430928764263e04c595b5e4944a15c48f8d..3d945808cb5b30cf220bb8fd02b769b2f066be11 100644 --- a/src/components/Connection/PartnerConnectModal/Steps/GrdfCreateAccount.tsx +++ b/src/components/Connection/PartnerConnectModal/Steps/GrdfCreateAccount.tsx @@ -2,7 +2,6 @@ import GrdfIcon from 'assets/icons/visu/onboarding/grdf.svg' import { useI18n } from 'cozy-ui/transpiled/react/I18n' import Icon from 'cozy-ui/transpiled/react/Icon' import React from 'react' -import { decoreText } from 'utils/decoreText' import './stepDetail.scss' const GrdfCreateAccount = () => { @@ -12,9 +11,12 @@ const GrdfCreateAccount = () => { <div className="step-detail-info"> <Icon className="info-icon" icon={GrdfIcon} size={220} /> <div className="info-content text-18-normal"> - <div className="info-content-text"> - {decoreText(t('auth.grdfgrandlyon.step2.info1'))} - </div> + <div + className="info-content-text" + dangerouslySetInnerHTML={{ + __html: t('auth.grdfgrandlyon.step2.info1'), + }} + /> </div> </div> ) diff --git a/src/components/Connection/PartnerConnectModal/Steps/GrdfDoYouHaveAccount.tsx b/src/components/Connection/PartnerConnectModal/Steps/GrdfDoYouHaveAccount.tsx index 680d15184fc472155fee743138f14edf90a1fc9c..aadcc4ee4c5a5657d1bfb933eacb2c3b3f616445 100644 --- a/src/components/Connection/PartnerConnectModal/Steps/GrdfDoYouHaveAccount.tsx +++ b/src/components/Connection/PartnerConnectModal/Steps/GrdfDoYouHaveAccount.tsx @@ -2,7 +2,6 @@ import BrowserGrdf from 'assets/icons/visu/onboarding/browser_grdf.svg' import { useI18n } from 'cozy-ui/transpiled/react/I18n' import Icon from 'cozy-ui/transpiled/react/Icon' import React from 'react' -import { decoreText } from 'utils/decoreText' import './stepDetail.scss' const GrdfDoYouHaveAccount = () => { @@ -12,16 +11,24 @@ const GrdfDoYouHaveAccount = () => { <div className="step-detail-info"> <Icon className="info-icon" icon={BrowserGrdf} size={150} /> <div className="info-content text-18-normal"> - <div className="info-content-text"> - {decoreText(t('auth.grdfgrandlyon.step1.info1'))} - {decoreText(t('auth.grdfgrandlyon.step1.info2'))} - </div> - <div className="info-content-text"> - {decoreText(t('auth.grdfgrandlyon.step1.info3'))} - </div> - <div className="info-content-text"> - {decoreText(t('auth.grdfgrandlyon.step1.info4'))} - </div> + <div + className="info-content-text" + dangerouslySetInnerHTML={{ + __html: t('auth.grdfgrandlyon.step1.info1'), + }} + /> + <div + className="info-content-text" + dangerouslySetInnerHTML={{ + __html: t('auth.grdfgrandlyon.step1.info2'), + }} + /> + <div + className="info-content-text" + dangerouslySetInnerHTML={{ + __html: t('auth.grdfgrandlyon.step1.info3'), + }} + /> </div> </div> ) diff --git a/src/components/Connection/FormOAuth.tsx b/src/components/Connection/PartnerConnectModal/Steps/GrdfFormOAuth.tsx similarity index 70% rename from src/components/Connection/FormOAuth.tsx rename to src/components/Connection/PartnerConnectModal/Steps/GrdfFormOAuth.tsx index 736bd4ab02b1ac37523fa4b95ed769afae25ea14..287f55d0d558879517fbc87f6f9a2b3612936975 100644 --- a/src/components/Connection/FormOAuth.tsx +++ b/src/components/Connection/PartnerConnectModal/Steps/GrdfFormOAuth.tsx @@ -2,31 +2,30 @@ import Button from '@material-ui/core/Button' import { useClient } from 'cozy-client' import { OAuthWindow } from 'cozy-harvest-lib/dist/components/OAuthWindow' import { useI18n } from 'cozy-ui/transpiled/react/I18n' -import { UsageEventType } from 'enum/usageEvent.enum' -import { FluidStatus, Konnector } from 'models' -import React, { Dispatch, useCallback, useEffect, useState } from 'react' -import { useDispatch, useSelector } from 'react-redux' +import { FluidType, UsageEventType } from 'enums' +import { Konnector } from 'models' +import React, { useCallback, useEffect, useState } from 'react' import UsageEventService from 'services/usageEvent.service' -import { AppActionsTypes, AppStore } from 'store' -import { setShouldRefreshConsent } from 'store/global/global.actions' +import { setShouldRefreshConsent } from 'store/global/global.slice' +import { useAppDispatch, useAppSelector } from 'store/hooks' -interface FormOAuthProps { - konnector: Konnector | null +const GrdfFormOAuth = ({ + onSuccess, +}: { onSuccess: (accountId: string) => Promise<void> - fluidStatus: FluidStatus -} - -const FormOAuth = ({ konnector, onSuccess, fluidStatus }: FormOAuthProps) => { +}) => { const IDLE = 'idle' const WAITING = 'waiting' const { t } = useI18n() const client = useClient() - const [status, setStatus] = useState<string>(IDLE) - const { shouldRefreshConsent } = useSelector( - (state: AppStore) => state.ecolyo.global + const { shouldRefreshConsent, fluidStatus } = useAppSelector( + state => state.ecolyo.global ) - const dispatch = useDispatch<Dispatch<AppActionsTypes>>() + const currentFluidStatus = fluidStatus[FluidType.GAS] + const konnector: Konnector | null = currentFluidStatus.connection.konnector + const dispatch = useAppDispatch() + const [status, setStatus] = useState<string>(IDLE) const endOAuth = useCallback(() => { setStatus(IDLE) // Set back to false the variable that allows to automatically refresh the consent (deletes and recreates the account) @@ -35,7 +34,7 @@ const FormOAuth = ({ konnector, onSuccess, fluidStatus }: FormOAuthProps) => { const startOAuth = useCallback(async () => { // If first connexion, send the usage event - if (konnector?.slug && fluidStatus.lastDataDate === null) { + if (konnector?.slug && currentFluidStatus.lastDataDate === null) { await UsageEventService.addEvent(client, { type: UsageEventType.KONNECTOR_ATTEMPT_EVENT, target: konnector.slug, @@ -43,7 +42,7 @@ const FormOAuth = ({ konnector, onSuccess, fluidStatus }: FormOAuthProps) => { }) } setStatus(WAITING) - }, [client, fluidStatus.lastDataDate, konnector]) + }, [client, currentFluidStatus.lastDataDate, konnector]) const handleAccountId = useCallback( (accountId: string) => { @@ -53,10 +52,6 @@ const FormOAuth = ({ konnector, onSuccess, fluidStatus }: FormOAuthProps) => { [endOAuth, onSuccess] ) - const handleOAuthCancel = useCallback(() => { - endOAuth() - }, [endOAuth]) - const isWaiting = status === WAITING useEffect(() => { @@ -91,7 +86,7 @@ const FormOAuth = ({ konnector, onSuccess, fluidStatus }: FormOAuthProps) => { konnector={konnector} redirectSlug={client.appMetadata.slug} onSuccess={handleAccountId} - onCancel={handleOAuthCancel} + onCancel={endOAuth} t={t} /> )} @@ -99,4 +94,4 @@ const FormOAuth = ({ konnector, onSuccess, fluidStatus }: FormOAuthProps) => { ) } -export default FormOAuth +export default GrdfFormOAuth diff --git a/src/components/Connection/PartnerConnectModal/Steps/GrdfGiveConsent.tsx b/src/components/Connection/PartnerConnectModal/Steps/GrdfGiveConsent.tsx index 79e5bcbc547c74f55440b5bce613390307bb6569..64bebd7590a0caeeb1a2bf0c09018abed3a6712d 100644 --- a/src/components/Connection/PartnerConnectModal/Steps/GrdfGiveConsent.tsx +++ b/src/components/Connection/PartnerConnectModal/Steps/GrdfGiveConsent.tsx @@ -2,7 +2,6 @@ import GrdfConsent from 'assets/icons/visu/onboarding/grdf_consent.svg' import { useI18n } from 'cozy-ui/transpiled/react/I18n' import Icon from 'cozy-ui/transpiled/react/Icon' import React from 'react' -import { decoreText } from 'utils/decoreText' import './stepDetail.scss' const GrdfGiveConsent = () => { @@ -12,15 +11,24 @@ const GrdfGiveConsent = () => { <div className="step-detail-info"> <Icon className="info-icon" icon={GrdfConsent} size={220} /> <div className="info-content text-18-normal"> - <div className="info-content-text"> - {decoreText(t('auth.grdfgrandlyon.step3.info1'))} - </div> - <div className="info-content-text"> - {decoreText(t('auth.grdfgrandlyon.step3.info2'))} - </div> - <div className="info-content-text"> - {decoreText(t('auth.grdfgrandlyon.step3.info3'))} - </div> + <div + className="info-content-text" + dangerouslySetInnerHTML={{ + __html: t('auth.grdfgrandlyon.step3.info1'), + }} + /> + <div + className="info-content-text" + dangerouslySetInnerHTML={{ + __html: t('auth.grdfgrandlyon.step3.info2'), + }} + /> + <div + className="info-content-text" + dangerouslySetInnerHTML={{ + __html: t('auth.grdfgrandlyon.step3.info3'), + }} + /> </div> </div> ) diff --git a/src/components/Connection/SGEConnect/SgeConnectView.spec.tsx b/src/components/Connection/SGEConnect/SgeConnectView.spec.tsx index 5bace90a60e5d63d31c0d705b8e15514151877cc..30d79f957431c78317760898f2ea0b05bba533f6 100644 --- a/src/components/Connection/SGEConnect/SgeConnectView.spec.tsx +++ b/src/components/Connection/SGEConnect/SgeConnectView.spec.tsx @@ -1,44 +1,23 @@ -import { SgeStep } from 'enum/sgeStep.enum' +import { SgeStep } from 'enums' import { mount } from 'enzyme' import toJson from 'enzyme-to-json' import React from 'react' -import * as reactRedux from 'react-redux' import { Provider } from 'react-redux' -import configureStore from 'redux-mock-store' -import { globalStateData } from '../../../../tests/__mocks__/globalStateData.mock' +import * as storeHooks from 'store/hooks' +import { createMockEcolyoStore, mockGlobalState } from 'tests/__mocks__/store' import SgeConnectView from './SgeConnectView' -jest.mock('cozy-ui/transpiled/react/I18n', () => { - return { - useI18n: jest.fn(() => { - return { - t: (str: string) => str, - } - }), - } -}) -const mockedNavigate = jest.fn() -jest.mock('react-router-dom', () => ({ - ...jest.requireActual('react-router-dom'), - useNavigate: () => mockedNavigate, -})) jest.mock('components/Content/Content', () => 'mock-content') -jest.mock('components/FormGlobal/FormProgress', () => 'mock-formprogress') jest.mock('components/Header/CozyBar', () => 'mock-cozybar') -const mockStore = configureStore([]) -const useDispatchSpy = jest.spyOn(reactRedux, 'useDispatch') +const mockAppDispatch = jest.spyOn(storeHooks, 'useAppDispatch') describe('SgeConnectView component', () => { beforeEach(() => { - useDispatchSpy.mockReset() + jest.clearAllMocks() }) it('should be rendered correctly', () => { - const store = mockStore({ - ecolyo: { - global: globalStateData, - }, - }) + const store = createMockEcolyoStore() const wrapper = mount( <Provider store={store}> <SgeConnectView /> @@ -47,14 +26,11 @@ describe('SgeConnectView component', () => { expect(toJson(wrapper)).toMatchSnapshot() }) it('should render address Step', () => { - const store = mockStore({ - ecolyo: { - global: { - ...globalStateData, - sgeConnect: { - ...globalStateData.sgeConnect, - currentStep: SgeStep.Address, - }, + const store = createMockEcolyoStore({ + global: { + sgeConnect: { + ...mockGlobalState.sgeConnect, + currentStep: SgeStep.Address, }, }, }) @@ -66,14 +42,11 @@ describe('SgeConnectView component', () => { expect(wrapper.find('.stepAddress')).toBeTruthy() }) it('should render identity Step', () => { - const store = mockStore({ - ecolyo: { - global: { - ...globalStateData, - sgeConnect: { - ...globalStateData.sgeConnect, - currentStep: SgeStep.IdentityAndPDL, - }, + const store = createMockEcolyoStore({ + global: { + sgeConnect: { + ...mockGlobalState.sgeConnect, + currentStep: SgeStep.IdentityAndPDL, }, }, }) @@ -85,14 +58,11 @@ describe('SgeConnectView component', () => { expect(wrapper.find('.stepIdentity')).toBeTruthy() }) it('should render consent Step', () => { - const store = mockStore({ - ecolyo: { - global: { - ...globalStateData, - sgeConnect: { - ...globalStateData.sgeConnect, - currentStep: SgeStep.Consent, - }, + const store = createMockEcolyoStore({ + global: { + sgeConnect: { + ...mockGlobalState.sgeConnect, + currentStep: SgeStep.Consent, }, }, }) @@ -104,14 +74,11 @@ describe('SgeConnectView component', () => { expect(wrapper.find('.stepConsent')).toBeTruthy() }) it('should render default Step', () => { - const store = mockStore({ - ecolyo: { - global: { - ...globalStateData, - sgeConnect: { - ...globalStateData.sgeConnect, - currentStep: 99, - }, + const store = createMockEcolyoStore({ + global: { + sgeConnect: { + ...mockGlobalState.sgeConnect, + currentStep: 99, }, }, }) @@ -123,36 +90,24 @@ describe('SgeConnectView component', () => { expect(wrapper.find('.stepIdentity')).toBeTruthy() }) describe('SgeConnectView Navigation methods', () => { - beforeEach(() => { - useDispatchSpy.mockReset() - }) + const store = createMockEcolyoStore() it('should call nextStep method', () => { - const store = mockStore({ - ecolyo: { - global: globalStateData, - }, - }) const wrapper = mount( <Provider store={store}> <SgeConnectView /> </Provider> ) wrapper.find('.profile-navigation-button').last().simulate('click') - expect(useDispatchSpy).toHaveBeenCalled() + expect(mockAppDispatch).toHaveBeenCalled() }) - it('shouldnt call disabled nextStep method', () => { - const store = mockStore({ - ecolyo: { - global: globalStateData, - }, - }) + it('should not call disabled nextStep method', () => { const wrapper = mount( <Provider store={store}> <SgeConnectView /> </Provider> ) wrapper.find('.profile-navigation-button').last().simulate('click') - expect(useDispatchSpy).toHaveBeenCalled() + expect(mockAppDispatch).toHaveBeenCalled() }) }) }) diff --git a/src/components/Connection/SGEConnect/SgeConnectView.tsx b/src/components/Connection/SGEConnect/SgeConnectView.tsx index c2e0c11cb5e007a0bc673c5de238a245bd71e110..c59382fa73b47645795e15980b7a733f95e96510 100644 --- a/src/components/Connection/SGEConnect/SgeConnectView.tsx +++ b/src/components/Connection/SGEConnect/SgeConnectView.tsx @@ -1,14 +1,13 @@ +import FormNavigation from 'components/CommonKit/FormNavigation/FormNavigation' +import FormProgress from 'components/CommonKit/FormProgress/FormProgress' import Content from 'components/Content/Content' -import FormNavigation from 'components/FormGlobal/FormNavigation' -import FormProgress from 'components/FormGlobal/FormProgress' import CozyBar from 'components/Header/CozyBar' import Header from 'components/Header/Header' -import { SgeStep } from 'enum/sgeStep.enum' -import { SgeStore } from 'models/sgeStore.model' -import React, { Dispatch, useCallback, useState } from 'react' -import { useDispatch, useSelector } from 'react-redux' -import { AppActionsTypes, AppStore } from 'store' -import { updateSgeStore } from 'store/global/global.actions' +import { SgeStep } from 'enums' +import { SgeStore } from 'models' +import React, { useCallback, useState } from 'react' +import { updateSgeStore } from 'store/global/global.slice' +import { useAppDispatch, useAppSelector } from 'store/hooks' import './SgeConnect.scss' import StepAddress from './StepAddress' import StepConsent from './StepConsent' @@ -25,17 +24,14 @@ export type SGEKeysForm = | 'pdlConfirm' const SgeConnectView = () => { - const [headerHeight, setHeaderHeight] = useState<number>(0) - const { sgeConnect } = useSelector((state: AppStore) => state.ecolyo.global) - const dispatch = useDispatch<Dispatch<AppActionsTypes>>() + const dispatch = useAppDispatch() + const { sgeConnect } = useAppSelector(state => state.ecolyo.global) + const [isLoading, setIsLoading] = useState(false) + const [currentSgeState, setCurrentSgeState] = useState<SgeStore>(sgeConnect) const [currentStep, setCurrentStep] = useState<SgeStep>( sgeConnect.currentStep ) - const [currentSgeState, setCurrentSgeState] = useState<SgeStore>(sgeConnect) - const defineHeaderHeight = useCallback((height: number) => { - setHeaderHeight(height) - }, []) - const [isLoading, setIsLoading] = useState(false) + const [headerHeight, setHeaderHeight] = useState<number>(0) const isNextValid = useCallback(() => { switch (currentStep) { @@ -132,16 +128,16 @@ const SgeConnectView = () => { return ( <> - <CozyBar titleKey={'common.title_sge_connect'} displayBackArrow={true} /> + <CozyBar titleKey="common.title_sge_connect" displayBackArrow={true} /> <Header - setHeaderHeight={defineHeaderHeight} - desktopTitleKey={'common.title_sge_connect'} + setHeaderHeight={setHeaderHeight} + desktopTitleKey="common.title_sge_connect" displayBackArrow={true} /> - <Content height={headerHeight}> + <Content heightOffset={headerHeight}> <div className="sge-view"> <div className="sge-container"> - <FormProgress step={currentStep} formType={'sge'} /> + <FormProgress step={currentStep} formType="sge" /> {renderStep(currentStep)} </div> <FormNavigation diff --git a/src/components/Connection/SGEConnect/SgeInit.spec.tsx b/src/components/Connection/SGEConnect/SgeInit.spec.tsx index dc745f6f3c1f841fe5c7c51ff2b327ccbe8755e2..cd01cfb542a872b7cc810cc3e3db94545f6b4fad 100644 --- a/src/components/Connection/SGEConnect/SgeInit.spec.tsx +++ b/src/components/Connection/SGEConnect/SgeInit.spec.tsx @@ -1,27 +1,13 @@ import { Button } from '@material-ui/core' 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 configureStore from 'redux-mock-store' -import { - fluidStatusData, - SgeStatusWithAccount, -} from '../../../../tests/__mocks__/fluidStatusData.mock' -import { globalStateData } from '../../../../tests/__mocks__/globalStateData.mock' -import { waitForComponentToPaint } from '../../../../tests/__mocks__/testUtils' +import { SgeStatusWithAccount } from 'tests/__mocks__/fluidStatusData.mock' +import { createMockEcolyoStore, mockGlobalState } from 'tests/__mocks__/store' +import { waitForComponentToPaint } from 'tests/__mocks__/testUtils' import SgeInit from './SgeInit' -jest.mock('cozy-ui/transpiled/react/I18n', () => { - return { - useI18n: jest.fn(() => { - return { - t: (str: string) => str, - } - }), - } -}) const mockedNavigate = jest.fn() jest.mock('react-router-dom', () => ({ ...jest.requireActual('react-router-dom'), @@ -34,72 +20,59 @@ const mockUpdate = jest.fn() jest.mock('components/Hooks/useKonnectorAuth', () => jest.fn(() => [mockConnect, mockUpdate]) ) -const mockStore = configureStore<{ ecolyo: { global: GlobalState } }>([]) describe('SgeInit component', () => { + const store = createMockEcolyoStore() it('should be rendered correctly', () => { - const store = mockStore({ - ecolyo: { - global: globalStateData, - }, - }) const wrapper = mount( <Provider store={store}> - <SgeInit fluidStatus={fluidStatusData[0]} /> + <SgeInit /> </Provider> ) expect(toJson(wrapper)).toMatchSnapshot() }) it('should go to sge connect steps', () => { - const store = mockStore({ - ecolyo: { - global: globalStateData, - }, - }) const wrapper = mount( <Provider store={store}> - <SgeInit fluidStatus={fluidStatusData[0]} /> + <SgeInit /> </Provider> ) wrapper.find(Button).first().simulate('click') expect(mockedNavigate).toHaveBeenCalled() }) it('should launch account and trigger creation process', async () => { - const store = mockStore({ - ecolyo: { - global: { - ...globalStateData, - sgeConnect: { - ...globalStateData.sgeConnect, - shouldLaunchAccount: true, - }, + const store = createMockEcolyoStore({ + global: { + ...mockGlobalState, + sgeConnect: { + ...mockGlobalState.sgeConnect, + shouldLaunchAccount: true, }, }, }) const wrapper = mount( <Provider store={store}> - <SgeInit fluidStatus={fluidStatusData[0]} /> + <SgeInit /> </Provider> ) await waitForComponentToPaint(wrapper) expect(mockConnect).toHaveBeenCalled() }) it('should launch existing account update process', async () => { - const store = mockStore({ - ecolyo: { - global: { - ...globalStateData, - sgeConnect: { - ...globalStateData.sgeConnect, - shouldLaunchAccount: true, - }, + const store = createMockEcolyoStore({ + global: { + ...mockGlobalState, + fluidStatus: [SgeStatusWithAccount], + sgeConnect: { + ...mockGlobalState.sgeConnect, + shouldLaunchAccount: true, }, }, }) const wrapper = mount( <Provider store={store}> - <SgeInit fluidStatus={SgeStatusWithAccount} /> + <SgeInit /> </Provider> ) await waitForComponentToPaint(wrapper) diff --git a/src/components/Connection/SGEConnect/SgeInit.tsx b/src/components/Connection/SGEConnect/SgeInit.tsx index 530045358d0eb2b7be18a649e5640dfb10e0ca61..c36fecbf61a44c02b469b72473c5870a1ca12600 100644 --- a/src/components/Connection/SGEConnect/SgeInit.tsx +++ b/src/components/Connection/SGEConnect/SgeInit.tsx @@ -3,27 +3,28 @@ import ElectricityBillIcon from 'assets/icons/visu/onboarding/electricity_bill.s import StyledIcon from 'components/CommonKit/Icon/StyledIcon' import useKonnectorAuth from 'components/Hooks/useKonnectorAuth' import { useI18n } from 'cozy-ui/transpiled/react/I18n' -import { Account, FluidStatus } from 'models' -import React, { Dispatch, useEffect } from 'react' -import { useDispatch, useSelector } from 'react-redux' +import { FluidType } from 'enums' +import { Account } from 'models' +import React, { useEffect } from 'react' import { useNavigate } from 'react-router-dom' -import { AppActionsTypes, AppStore } from 'store' import { setShowOfflineData } from 'store/chart/chart.slice' import { setShouldRefreshConsent, updateSgeStore, -} from 'store/global/global.actions' -import { decoreText } from 'utils/decoreText' +} from 'store/global/global.slice' +import { useAppDispatch, useAppSelector } from 'store/hooks' -const SgeInit = ({ fluidStatus }: { fluidStatus: FluidStatus }) => { +const SgeInit = () => { const { t } = useI18n() const navigate = useNavigate() - const konnectorSlug: string = fluidStatus.connection.konnectorConfig.slug - const account: Account | null = fluidStatus.connection.account - const { sgeConnect } = useSelector((state: AppStore) => state.ecolyo.global) - - const dispatch = useDispatch<Dispatch<AppActionsTypes>>() - const [connect, update] = useKonnectorAuth(fluidStatus) + const { fluidStatus } = useAppSelector(state => state.ecolyo.global) + const currentFluidStatus = fluidStatus[FluidType.ELECTRICITY] + const konnectorSlug: string = + currentFluidStatus.connection.konnectorConfig.slug + const account: Account | null = currentFluidStatus.connection.account + const { sgeConnect } = useAppSelector(state => state.ecolyo.global) + const dispatch = useAppDispatch() + const [connect, update] = useKonnectorAuth(currentFluidStatus.fluidType) useEffect(() => { async function launchConnect() { @@ -48,9 +49,8 @@ const SgeInit = ({ fluidStatus }: { fluidStatus: FluidStatus }) => { <StyledIcon icon={ElectricityBillIcon} size={180} /> <p className={`connection-form-subtitle ${konnectorSlug} text-16-regular`} - > - {decoreText(t('auth.' + `${konnectorSlug}` + '.bill'))} - </p> + dangerouslySetInnerHTML={{ __html: t(`auth.${konnectorSlug}.bill`) }} + /> <div className="connection-form-button"> <Button @@ -65,7 +65,7 @@ const SgeInit = ({ fluidStatus }: { fluidStatus: FluidStatus }) => { > {t(`auth.${konnectorSlug}.connect`)} </Button> - {fluidStatus.firstDataDate && ( + {currentFluidStatus.firstDataDate && ( <Button classes={{ root: 'btn-secondary', diff --git a/src/components/Connection/SGEConnect/SgeModalHint.spec.tsx b/src/components/Connection/SGEConnect/SgeModalHint.spec.tsx index 86efcf12d591964811923a9b982b963b0c45abb0..eab06f6c662dab4514e4bfa2d2700f528cade3c2 100644 --- a/src/components/Connection/SGEConnect/SgeModalHint.spec.tsx +++ b/src/components/Connection/SGEConnect/SgeModalHint.spec.tsx @@ -2,29 +2,13 @@ import { mount } from 'enzyme' import toJson from 'enzyme-to-json' import React from 'react' import { Provider } from 'react-redux' -import configureStore from 'redux-mock-store' -import { globalStateData } from '../../../../tests/__mocks__/globalStateData.mock' +import { createMockEcolyoStore } from 'tests/__mocks__/store' import SgeModalHint from './SgeModalHint' -jest.mock('cozy-ui/transpiled/react/I18n', () => { - return { - useI18n: jest.fn(() => { - return { - t: (str: string) => str, - } - }), - } -}) -const mockStore = configureStore([]) - describe('SgeModalHint component', () => { it('should be rendered correctly', () => { const mockClose = jest.fn() - const store = mockStore({ - ecolyo: { - global: globalStateData, - }, - }) + const store = createMockEcolyoStore() const wrapper = mount( <Provider store={store}> <SgeModalHint open={true} handleCloseClick={mockClose} /> diff --git a/src/components/Connection/SGEConnect/SgeModalHint.tsx b/src/components/Connection/SGEConnect/SgeModalHint.tsx index 2e5b34872fe7d16cded12d1415244ab538a41a35..9b2696e1d98ee16fd8be8385802ad8b9fac7a911 100644 --- a/src/components/Connection/SGEConnect/SgeModalHint.tsx +++ b/src/components/Connection/SGEConnect/SgeModalHint.tsx @@ -21,13 +21,13 @@ const SgeModalHint = ({ open, handleCloseClick }: SgeModalHintProps) => { open={open} disableEscapeKeyDown onClose={handleCloseClick} - aria-labelledby={'accessibility-title'} + aria-labelledby="accessibility-title" classes={{ root: 'modal-root', paper: 'modal-paper', }} > - <div id={'accessibility-title'}> + <div id="accessibility-title"> {t('challenge_no_fluid_modal.accessibility.window_title')} </div> <IconButton diff --git a/src/components/Connection/SGEConnect/StepAddress.spec.tsx b/src/components/Connection/SGEConnect/StepAddress.spec.tsx index 4874eaee45fa946607e3a3d1cd7efcb6ef1e6a38..785ca968a3de16578d2baa84243cf8257fdbf9a8 100644 --- a/src/components/Connection/SGEConnect/StepAddress.spec.tsx +++ b/src/components/Connection/SGEConnect/StepAddress.spec.tsx @@ -2,33 +2,18 @@ import { mount } from 'enzyme' import toJson from 'enzyme-to-json' import React from 'react' import { Provider } from 'react-redux' -import configureStore from 'redux-mock-store' -import { globalStateData } from '../../../../tests/__mocks__/globalStateData.mock' +import { createMockEcolyoStore, mockGlobalState } from 'tests/__mocks__/store' import StepAddress from './StepAddress' -jest.mock('cozy-ui/transpiled/react/I18n', () => { - return { - useI18n: jest.fn(() => { - return { - t: (str: string) => str, - } - }), - } -}) -const mockStore = configureStore([]) +const mockHandleChange = jest.fn() describe('StepAddress component', () => { + const store = createMockEcolyoStore() it('should be rendered correctly', () => { - const mockHandleChange = jest.fn() - const store = mockStore({ - ecolyo: { - global: globalStateData, - }, - }) const wrapper = mount( <Provider store={store}> <StepAddress - sgeState={globalStateData.sgeConnect} + sgeState={mockGlobalState.sgeConnect} onChange={mockHandleChange} /> </Provider> @@ -36,16 +21,10 @@ describe('StepAddress component', () => { expect(toJson(wrapper)).toMatchSnapshot() }) it('should change address value', () => { - const mockHandleChange = jest.fn() - const store = mockStore({ - ecolyo: { - global: globalStateData, - }, - }) const wrapper = mount( <Provider store={store}> <StepAddress - sgeState={globalStateData.sgeConnect} + sgeState={mockGlobalState.sgeConnect} onChange={mockHandleChange} /> </Provider> @@ -54,16 +33,10 @@ describe('StepAddress component', () => { expect(mockHandleChange).toHaveBeenCalledWith('address', '') }) it('should change zipCode value', () => { - const mockHandleChange = jest.fn() - const store = mockStore({ - ecolyo: { - global: globalStateData, - }, - }) const wrapper = mount( <Provider store={store}> <StepAddress - sgeState={globalStateData.sgeConnect} + sgeState={mockGlobalState.sgeConnect} onChange={mockHandleChange} /> </Provider> @@ -72,16 +45,10 @@ describe('StepAddress component', () => { expect(mockHandleChange).toHaveBeenCalledWith('zipCode', '', 5) }) it('should have an existing zipCode value', () => { - const mockHandleChange = jest.fn() - const store = mockStore({ - ecolyo: { - global: globalStateData, - }, - }) const wrapper = mount( <Provider store={store}> <StepAddress - sgeState={{ ...globalStateData.sgeConnect, zipCode: 69200 }} + sgeState={{ ...mockGlobalState.sgeConnect, zipCode: 69200 }} onChange={mockHandleChange} /> </Provider> @@ -89,16 +56,10 @@ describe('StepAddress component', () => { expect(wrapper.find('#zipCode').first().props().value).toBe(69200) }) it('should change city value', () => { - const mockHandleChange = jest.fn() - const store = mockStore({ - ecolyo: { - global: globalStateData, - }, - }) const wrapper = mount( <Provider store={store}> <StepAddress - sgeState={globalStateData.sgeConnect} + sgeState={mockGlobalState.sgeConnect} onChange={mockHandleChange} /> </Provider> diff --git a/src/components/Connection/SGEConnect/StepAddress.tsx b/src/components/Connection/SGEConnect/StepAddress.tsx index 8fe99e04d6d963fcec29b65ff2778f2132375ccc..da040f5010bbc81bc832fd9af18beb223045ee85 100644 --- a/src/components/Connection/SGEConnect/StepAddress.tsx +++ b/src/components/Connection/SGEConnect/StepAddress.tsx @@ -1,5 +1,5 @@ import { useI18n } from 'cozy-ui/transpiled/react/I18n' -import { SgeStore } from 'models/sgeStore.model' +import { SgeStore } from 'models' import React from 'react' import { SGEKeysForm } from './SgeConnectView' diff --git a/src/components/Connection/SGEConnect/StepConsent.spec.tsx b/src/components/Connection/SGEConnect/StepConsent.spec.tsx index 09498f8b583a532e2bb823c9fc3a20ffcdf7bb3a..c2ca84554bed9594ee4cbedefd83143ca964127e 100644 --- a/src/components/Connection/SGEConnect/StepConsent.spec.tsx +++ b/src/components/Connection/SGEConnect/StepConsent.spec.tsx @@ -1,35 +1,19 @@ 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 configureStore from 'redux-mock-store' -import { globalStateData } from '../../../../tests/__mocks__/globalStateData.mock' +import { createMockEcolyoStore, mockGlobalState } from 'tests/__mocks__/store' import StepConsent from './StepConsent' -jest.mock('cozy-ui/transpiled/react/I18n', () => { - return { - useI18n: jest.fn(() => { - return { - t: (str: string) => str, - } - }), - } -}) -const mockStore = configureStore<{ ecolyo: { global: GlobalState } }>([]) +const mockHandleChange = jest.fn() describe('StepConsent component', () => { + const store = createMockEcolyoStore() it('should be rendered correctly', () => { - const mockHandleChange = jest.fn() - const store = mockStore({ - ecolyo: { - global: globalStateData, - }, - }) const wrapper = mount( <Provider store={store}> <StepConsent - sgeState={globalStateData.sgeConnect} + sgeState={mockGlobalState.sgeConnect} onChange={mockHandleChange} /> </Provider> @@ -37,16 +21,10 @@ describe('StepConsent component', () => { expect(toJson(wrapper)).toMatchSnapshot() }) it('should change pdlConfirm value', () => { - const mockHandleChange = jest.fn() - const store = mockStore({ - ecolyo: { - global: globalStateData, - }, - }) const wrapper = mount( <Provider store={store}> <StepConsent - sgeState={globalStateData.sgeConnect} + sgeState={mockGlobalState.sgeConnect} onChange={mockHandleChange} /> </Provider> @@ -55,16 +33,10 @@ describe('StepConsent component', () => { expect(mockHandleChange).toHaveBeenCalledWith('pdlConfirm', false) }) it('should change dataConsent value', () => { - const mockHandleChange = jest.fn() - const store = mockStore({ - ecolyo: { - global: globalStateData, - }, - }) const wrapper = mount( <Provider store={store}> <StepConsent - sgeState={globalStateData.sgeConnect} + sgeState={mockGlobalState.sgeConnect} onChange={mockHandleChange} /> </Provider> diff --git a/src/components/Connection/SGEConnect/StepConsent.tsx b/src/components/Connection/SGEConnect/StepConsent.tsx index 4997b3b812d2664f6dd04c3eea2e141229dc9159..c8dc887a81d7c938d9d26ea228109240375686d8 100644 --- a/src/components/Connection/SGEConnect/StepConsent.tsx +++ b/src/components/Connection/SGEConnect/StepConsent.tsx @@ -1,20 +1,14 @@ import classNames from 'classnames' import { useI18n } from 'cozy-ui/transpiled/react/I18n' -import { SgeStore } from 'models/sgeStore.model' +import { SgeStore } from 'models' import React from 'react' -import { decoreText } from 'utils/decoreText' import { SGEKeysForm } from './SgeConnectView' interface StepConsentProps { sgeState: SgeStore onChange: (key: SGEKeysForm, value: boolean) => void } -const StepConsent = ( - { - sgeState, - onChange - }: StepConsentProps -) => { +const StepConsent = ({ sgeState, onChange }: StepConsentProps) => { const { t } = useI18n() return ( @@ -45,7 +39,11 @@ const StepConsent = ( } checked={sgeState.dataConsent} /> - <span>{decoreText(t('auth.enedissgegrandlyon.consentCheck1'))}</span> + <span + dangerouslySetInnerHTML={{ + __html: t('auth.enedissgegrandlyon.consentCheck1'), + }} + /> </label> <label className={classNames('checkbox', { @@ -61,7 +59,11 @@ const StepConsent = ( } checked={sgeState.pdlConfirm} /> - {decoreText(t('auth.enedissgegrandlyon.consentCheck2'))} + <span + dangerouslySetInnerHTML={{ + __html: t('auth.enedissgegrandlyon.consentCheck2'), + }} + /> </label> </div> ) diff --git a/src/components/Connection/SGEConnect/StepIdentityAndPdl.spec.tsx b/src/components/Connection/SGEConnect/StepIdentityAndPdl.spec.tsx index dba57dc00833286368cf785304f4713498147679..562541f5d959e1480967fe4c37ccec4fe39de638 100644 --- a/src/components/Connection/SGEConnect/StepIdentityAndPdl.spec.tsx +++ b/src/components/Connection/SGEConnect/StepIdentityAndPdl.spec.tsx @@ -2,33 +2,18 @@ import { mount } from 'enzyme' import toJson from 'enzyme-to-json' import React from 'react' import { Provider } from 'react-redux' -import configureStore from 'redux-mock-store' -import { globalStateData } from '../../../../tests/__mocks__/globalStateData.mock' +import { createMockEcolyoStore, mockGlobalState } from 'tests/__mocks__/store' import StepIdentityAndPdl from './StepIdentityAndPdl' -jest.mock('cozy-ui/transpiled/react/I18n', () => { - return { - useI18n: jest.fn(() => { - return { - t: (str: string) => str, - } - }), - } -}) -const mockStore = configureStore([]) +const mockHandleChange = jest.fn() describe('StepIdentityAndPdl component', () => { + const store = createMockEcolyoStore() it('should be rendered correctly', () => { - const mockHandleChange = jest.fn() - const store = mockStore({ - ecolyo: { - global: globalStateData, - }, - }) const wrapper = mount( <Provider store={store}> <StepIdentityAndPdl - sgeState={globalStateData.sgeConnect} + sgeState={mockGlobalState.sgeConnect} onChange={mockHandleChange} /> </Provider> @@ -36,16 +21,10 @@ describe('StepIdentityAndPdl component', () => { expect(toJson(wrapper)).toMatchSnapshot() }) it('should change firstName value', () => { - const mockHandleChange = jest.fn() - const store = mockStore({ - ecolyo: { - global: globalStateData, - }, - }) const wrapper = mount( <Provider store={store}> <StepIdentityAndPdl - sgeState={globalStateData.sgeConnect} + sgeState={mockGlobalState.sgeConnect} onChange={mockHandleChange} /> </Provider> @@ -54,16 +33,10 @@ describe('StepIdentityAndPdl component', () => { expect(mockHandleChange).toHaveBeenCalledWith('firstName', '') }) it('should change lastName value', () => { - const mockHandleChange = jest.fn() - const store = mockStore({ - ecolyo: { - global: globalStateData, - }, - }) const wrapper = mount( <Provider store={store}> <StepIdentityAndPdl - sgeState={globalStateData.sgeConnect} + sgeState={mockGlobalState.sgeConnect} onChange={mockHandleChange} /> </Provider> @@ -72,16 +45,10 @@ describe('StepIdentityAndPdl component', () => { expect(mockHandleChange).toHaveBeenCalledWith('lastName', '') }) it('should change pdl value', () => { - const mockHandleChange = jest.fn() - const store = mockStore({ - ecolyo: { - global: globalStateData, - }, - }) const wrapper = mount( <Provider store={store}> <StepIdentityAndPdl - sgeState={globalStateData.sgeConnect} + sgeState={mockGlobalState.sgeConnect} onChange={mockHandleChange} /> </Provider> @@ -90,16 +57,10 @@ describe('StepIdentityAndPdl component', () => { expect(mockHandleChange).toHaveBeenCalledWith('pdl', '', 14) }) it('should open hint modal', () => { - const mockHandleChange = jest.fn() - const store = mockStore({ - ecolyo: { - global: globalStateData, - }, - }) const wrapper = mount( <Provider store={store}> <StepIdentityAndPdl - sgeState={globalStateData.sgeConnect} + sgeState={mockGlobalState.sgeConnect} onChange={mockHandleChange} /> </Provider> @@ -108,16 +69,10 @@ describe('StepIdentityAndPdl component', () => { expect(wrapper.find('.sgeHintModal')).toBeTruthy() }) it('should have an existing pdl value', () => { - const mockHandleChange = jest.fn() - const store = mockStore({ - ecolyo: { - global: globalStateData, - }, - }) const wrapper = mount( <Provider store={store}> <StepIdentityAndPdl - sgeState={{ ...globalStateData.sgeConnect, pdl: 11111111111111 }} + sgeState={{ ...mockGlobalState.sgeConnect, pdl: 11111111111111 }} onChange={mockHandleChange} /> </Provider> diff --git a/src/components/Connection/SGEConnect/StepIdentityAndPdl.tsx b/src/components/Connection/SGEConnect/StepIdentityAndPdl.tsx index 0012020f79887df5097ba64806d96f8ee7b12c0a..b0e067d66c88ff44b32814311e056a8f006b8ebe 100644 --- a/src/components/Connection/SGEConnect/StepIdentityAndPdl.tsx +++ b/src/components/Connection/SGEConnect/StepIdentityAndPdl.tsx @@ -1,6 +1,6 @@ import SgeModalHint from 'components/Connection/SGEConnect/SgeModalHint' import { useI18n } from 'cozy-ui/transpiled/react/I18n' -import { SgeStore } from 'models/sgeStore.model' +import { SgeStore } from 'models' import React, { useCallback, useState } from 'react' import { SGEKeysForm } from './SgeConnectView' diff --git a/src/components/Connection/SGEConnect/__snapshots__/SgeConnectView.spec.tsx.snap b/src/components/Connection/SGEConnect/__snapshots__/SgeConnectView.spec.tsx.snap index 03e2a662a5bfbfc1209389f0aa60d02644b1d099..7d7e809cf6dcae84cdda6e96df7c7a7c53340240 100644 --- a/src/components/Connection/SGEConnect/__snapshots__/SgeConnectView.spec.tsx.snap +++ b/src/components/Connection/SGEConnect/__snapshots__/SgeConnectView.spec.tsx.snap @@ -301,7 +301,7 @@ exports[`SgeConnectView component should be rendered correctly 1`] = ` </div> </Header> <mock-content - height={-48} + heightOffset={-48} > <div className="sge-view" @@ -309,10 +309,33 @@ exports[`SgeConnectView component should be rendered correctly 1`] = ` <div className="sge-container" > - <mock-formprogress + <FormProgress formType="sge" step={0} - /> + > + <div + className="profile-type-progress" + > + <div + className="profile-type-progress-label" + > + 1 + % + </div> + <div + className="profile-type-progress-bar-container" + > + <div + className="profile-type-progress-bar-content" + style={ + Object { + "width": "1%", + } + } + /> + </div> + </div> + </FormProgress> <StepIdentityAndPdl onChange={[Function]} sgeState={ diff --git a/src/components/Connection/SGEConnect/__snapshots__/SgeInit.spec.tsx.snap b/src/components/Connection/SGEConnect/__snapshots__/SgeInit.spec.tsx.snap index 83745b2d942937a2c53d419c8039e6f8213db030..d59746e33a69f42117eff9e6430a81fa8788b571 100644 --- a/src/components/Connection/SGEConnect/__snapshots__/SgeInit.spec.tsx.snap +++ b/src/components/Connection/SGEConnect/__snapshots__/SgeInit.spec.tsx.snap @@ -13,32 +13,7 @@ exports[`SgeInit component should be rendered correctly 1`] = ` } } > - <SgeInit - fluidStatus={ - Object { - "connection": Object { - "account": null, - "isUpdating": false, - "konnector": null, - "konnectorConfig": Object { - "activation": "", - "name": "", - "oauth": false, - "siteLink": "", - "slug": "enedissgegrandlyon", - }, - "shouldLaunchKonnector": false, - "trigger": null, - "triggerState": null, - }, - "firstDataDate": "2019-09-01T00:00:00.000Z", - "fluidType": 0, - "lastDataDate": "2020-09-01T00:00:00.000Z", - "maintenance": false, - "status": 0, - } - } - > + <SgeInit> <div className="connection-form" > @@ -80,9 +55,12 @@ exports[`SgeInit component should be rendered correctly 1`] = ` </StyledIcon> <p className="connection-form-subtitle enedissgegrandlyon text-16-regular" - > - auth.enedissgegrandlyon.bill - </p> + dangerouslySetInnerHTML={ + Object { + "__html": "auth.enedissgegrandlyon.bill", + } + } + /> <div className="connection-form-button" > @@ -217,132 +195,6 @@ exports[`SgeInit component should be rendered correctly 1`] = ` </WithStyles(ForwardRef(ButtonBase))> </ForwardRef(Button)> </WithStyles(ForwardRef(Button))> - <WithStyles(ForwardRef(Button)) - classes={ - Object { - "label": "text-16-bold", - "root": "btn-secondary", - } - } - onClick={[Function]} - > - <ForwardRef(Button) - classes={ - Object { - "colorInherit": "MuiButton-colorInherit", - "contained": "MuiButton-contained", - "containedPrimary": "MuiButton-containedPrimary", - "containedSecondary": "MuiButton-containedSecondary", - "containedSizeLarge": "MuiButton-containedSizeLarge", - "containedSizeSmall": "MuiButton-containedSizeSmall", - "disableElevation": "MuiButton-disableElevation", - "disabled": "Mui-disabled", - "endIcon": "MuiButton-endIcon", - "focusVisible": "Mui-focusVisible", - "fullWidth": "MuiButton-fullWidth", - "iconSizeLarge": "MuiButton-iconSizeLarge", - "iconSizeMedium": "MuiButton-iconSizeMedium", - "iconSizeSmall": "MuiButton-iconSizeSmall", - "label": "MuiButton-label text-16-bold", - "outlined": "MuiButton-outlined", - "outlinedPrimary": "MuiButton-outlinedPrimary", - "outlinedSecondary": "MuiButton-outlinedSecondary", - "outlinedSizeLarge": "MuiButton-outlinedSizeLarge", - "outlinedSizeSmall": "MuiButton-outlinedSizeSmall", - "root": "MuiButton-root btn-secondary", - "sizeLarge": "MuiButton-sizeLarge", - "sizeSmall": "MuiButton-sizeSmall", - "startIcon": "MuiButton-startIcon", - "text": "MuiButton-text", - "textPrimary": "MuiButton-textPrimary", - "textSecondary": "MuiButton-textSecondary", - "textSizeLarge": "MuiButton-textSizeLarge", - "textSizeSmall": "MuiButton-textSizeSmall", - } - } - onClick={[Function]} - > - <WithStyles(ForwardRef(ButtonBase)) - className="MuiButton-root btn-secondary MuiButton-text" - component="button" - disabled={false} - focusRipple={true} - focusVisibleClassName="Mui-focusVisible" - onClick={[Function]} - type="button" - > - <ForwardRef(ButtonBase) - className="MuiButton-root btn-secondary MuiButton-text" - classes={ - Object { - "disabled": "Mui-disabled", - "focusVisible": "Mui-focusVisible", - "root": "MuiButtonBase-root", - } - } - component="button" - disabled={false} - focusRipple={true} - focusVisibleClassName="Mui-focusVisible" - onClick={[Function]} - type="button" - > - <button - className="MuiButtonBase-root MuiButton-root btn-secondary MuiButton-text" - disabled={false} - onBlur={[Function]} - onClick={[Function]} - onDragLeave={[Function]} - onFocus={[Function]} - onKeyDown={[Function]} - onKeyUp={[Function]} - onMouseDown={[Function]} - onMouseLeave={[Function]} - onMouseUp={[Function]} - onTouchEnd={[Function]} - onTouchMove={[Function]} - onTouchStart={[Function]} - tabIndex={0} - type="button" - > - <span - className="MuiButton-label text-16-bold" - > - auth.button_showOfflineData - </span> - <WithStyles(memo) - center={false} - > - <ForwardRef(TouchRipple) - center={false} - classes={ - Object { - "child": "MuiTouchRipple-child", - "childLeaving": "MuiTouchRipple-childLeaving", - "childPulsate": "MuiTouchRipple-childPulsate", - "ripple": "MuiTouchRipple-ripple", - "ripplePulsate": "MuiTouchRipple-ripplePulsate", - "rippleVisible": "MuiTouchRipple-rippleVisible", - "root": "MuiTouchRipple-root", - } - } - > - <span - className="MuiTouchRipple-root" - > - <TransitionGroup - childFactory={[Function]} - component={null} - exit={true} - /> - </span> - </ForwardRef(TouchRipple)> - </WithStyles(memo)> - </button> - </ForwardRef(ButtonBase)> - </WithStyles(ForwardRef(ButtonBase))> - </ForwardRef(Button)> - </WithStyles(ForwardRef(Button))> </div> </div> </SgeInit> diff --git a/src/components/Connection/SGEConnect/__snapshots__/StepConsent.spec.tsx.snap b/src/components/Connection/SGEConnect/__snapshots__/StepConsent.spec.tsx.snap index f5fd68d492c79666b431eae5ce7719273b7005d1..d474fdf8d8147abb417524d5915fac4afaab15fe 100644 --- a/src/components/Connection/SGEConnect/__snapshots__/StepConsent.spec.tsx.snap +++ b/src/components/Connection/SGEConnect/__snapshots__/StepConsent.spec.tsx.snap @@ -69,9 +69,13 @@ exports[`StepConsent component should be rendered correctly 1`] = ` onChange={[Function]} type="checkbox" /> - <span> - auth.enedissgegrandlyon.consentCheck1 - </span> + <span + dangerouslySetInnerHTML={ + Object { + "__html": "auth.enedissgegrandlyon.consentCheck1", + } + } + /> </label> <label className="checkbox" @@ -83,7 +87,13 @@ exports[`StepConsent component should be rendered correctly 1`] = ` onChange={[Function]} type="checkbox" /> - auth.enedissgegrandlyon.consentCheck2 + <span + dangerouslySetInnerHTML={ + Object { + "__html": "auth.enedissgegrandlyon.consentCheck2", + } + } + /> </label> </div> </StepConsent> diff --git a/src/components/Connection/__snapshots__/Connection.spec.tsx.snap b/src/components/Connection/__snapshots__/Connection.spec.tsx.snap index 731f690ea9508bb29eabd329fb39f5e21c35b182..231973b119e83bc5c5972c545c7242f1beec4092 100644 --- a/src/components/Connection/__snapshots__/Connection.spec.tsx.snap +++ b/src/components/Connection/__snapshots__/Connection.spec.tsx.snap @@ -14,389 +14,12 @@ exports[`Connection component test should call EpglInit 1`] = ` } > <Connection - fluidStatus={ - Object { - "connection": Object { - "account": Object { - "_id": "test", - "account_type": "test", - "auth": Object { - "address": "address", - "city": "Lyon", - "firstname": "Jane", - "lastname": "Doe", - "pointId": "testid", - "postalCode": "69200", - }, - }, - "isUpdating": false, - "konnector": null, - "konnectorConfig": Object { - "activation": "", - "name": "", - "oauth": false, - "siteLink": "", - "slug": "enedissgegrandlyon", - }, - "shouldLaunchKonnector": false, - "trigger": null, - "triggerState": null, - }, - "firstDataDate": "2019-09-01T00:00:00.000Z", - "fluidType": 0, - "lastDataDate": "2020-09-01T00:00:00.000Z", - "maintenance": false, - "status": 200, - } - } + fluidType={1} > <div className="konnector-form" > - <SgeInit - fluidStatus={ - Object { - "connection": Object { - "account": Object { - "_id": "test", - "account_type": "test", - "auth": Object { - "address": "address", - "city": "Lyon", - "firstname": "Jane", - "lastname": "Doe", - "pointId": "testid", - "postalCode": "69200", - }, - }, - "isUpdating": false, - "konnector": null, - "konnectorConfig": Object { - "activation": "", - "name": "", - "oauth": false, - "siteLink": "", - "slug": "enedissgegrandlyon", - }, - "shouldLaunchKonnector": false, - "trigger": null, - "triggerState": null, - }, - "firstDataDate": "2019-09-01T00:00:00.000Z", - "fluidType": 0, - "lastDataDate": "2020-09-01T00:00:00.000Z", - "maintenance": false, - "status": 200, - } - } - > - <div - className="connection-form" - > - <p - className="connection-form-title enedissgegrandlyon text-20-bold" - > - auth.enedissgegrandlyon.title - </p> - <StyledIcon - icon="test-file-stub" - size={180} - > - <Icon - aria-hidden={true} - icon="test-file-stub" - size={180} - spin={false} - > - <Component - aria-hidden={true} - className="styles__icon___23x3R" - height={180} - style={Object {}} - width={180} - > - <svg - aria-hidden={true} - className="styles__icon___23x3R" - height={180} - style={Object {}} - width={180} - > - <use - xlinkHref="#test-file-stub" - /> - </svg> - </Component> - </Icon> - </StyledIcon> - <p - className="connection-form-subtitle enedissgegrandlyon text-16-regular" - > - auth.enedissgegrandlyon.bill - </p> - <div - className="connection-form-button" - > - <WithStyles(ForwardRef(Button)) - aria-label="auth.enedissgegrandlyon.accessibility.connect" - classes={ - Object { - "label": "text-16-bold", - "root": "btn-highlight", - } - } - onClick={[Function]} - > - <ForwardRef(Button) - aria-label="auth.enedissgegrandlyon.accessibility.connect" - classes={ - Object { - "colorInherit": "MuiButton-colorInherit", - "contained": "MuiButton-contained", - "containedPrimary": "MuiButton-containedPrimary", - "containedSecondary": "MuiButton-containedSecondary", - "containedSizeLarge": "MuiButton-containedSizeLarge", - "containedSizeSmall": "MuiButton-containedSizeSmall", - "disableElevation": "MuiButton-disableElevation", - "disabled": "Mui-disabled", - "endIcon": "MuiButton-endIcon", - "focusVisible": "Mui-focusVisible", - "fullWidth": "MuiButton-fullWidth", - "iconSizeLarge": "MuiButton-iconSizeLarge", - "iconSizeMedium": "MuiButton-iconSizeMedium", - "iconSizeSmall": "MuiButton-iconSizeSmall", - "label": "MuiButton-label text-16-bold", - "outlined": "MuiButton-outlined", - "outlinedPrimary": "MuiButton-outlinedPrimary", - "outlinedSecondary": "MuiButton-outlinedSecondary", - "outlinedSizeLarge": "MuiButton-outlinedSizeLarge", - "outlinedSizeSmall": "MuiButton-outlinedSizeSmall", - "root": "MuiButton-root btn-highlight", - "sizeLarge": "MuiButton-sizeLarge", - "sizeSmall": "MuiButton-sizeSmall", - "startIcon": "MuiButton-startIcon", - "text": "MuiButton-text", - "textPrimary": "MuiButton-textPrimary", - "textSecondary": "MuiButton-textSecondary", - "textSizeLarge": "MuiButton-textSizeLarge", - "textSizeSmall": "MuiButton-textSizeSmall", - } - } - onClick={[Function]} - > - <WithStyles(ForwardRef(ButtonBase)) - aria-label="auth.enedissgegrandlyon.accessibility.connect" - className="MuiButton-root btn-highlight MuiButton-text" - component="button" - disabled={false} - focusRipple={true} - focusVisibleClassName="Mui-focusVisible" - onClick={[Function]} - type="button" - > - <ForwardRef(ButtonBase) - aria-label="auth.enedissgegrandlyon.accessibility.connect" - className="MuiButton-root btn-highlight MuiButton-text" - classes={ - Object { - "disabled": "Mui-disabled", - "focusVisible": "Mui-focusVisible", - "root": "MuiButtonBase-root", - } - } - component="button" - disabled={false} - focusRipple={true} - focusVisibleClassName="Mui-focusVisible" - onClick={[Function]} - type="button" - > - <button - aria-label="auth.enedissgegrandlyon.accessibility.connect" - className="MuiButtonBase-root MuiButton-root btn-highlight MuiButton-text" - disabled={false} - onBlur={[Function]} - onClick={[Function]} - onDragLeave={[Function]} - onFocus={[Function]} - onKeyDown={[Function]} - onKeyUp={[Function]} - onMouseDown={[Function]} - onMouseLeave={[Function]} - onMouseUp={[Function]} - onTouchEnd={[Function]} - onTouchMove={[Function]} - onTouchStart={[Function]} - tabIndex={0} - type="button" - > - <span - className="MuiButton-label text-16-bold" - > - auth.enedissgegrandlyon.connect - </span> - <WithStyles(memo) - center={false} - > - <ForwardRef(TouchRipple) - center={false} - classes={ - Object { - "child": "MuiTouchRipple-child", - "childLeaving": "MuiTouchRipple-childLeaving", - "childPulsate": "MuiTouchRipple-childPulsate", - "ripple": "MuiTouchRipple-ripple", - "ripplePulsate": "MuiTouchRipple-ripplePulsate", - "rippleVisible": "MuiTouchRipple-rippleVisible", - "root": "MuiTouchRipple-root", - } - } - > - <span - className="MuiTouchRipple-root" - > - <TransitionGroup - childFactory={[Function]} - component={null} - exit={true} - /> - </span> - </ForwardRef(TouchRipple)> - </WithStyles(memo)> - </button> - </ForwardRef(ButtonBase)> - </WithStyles(ForwardRef(ButtonBase))> - </ForwardRef(Button)> - </WithStyles(ForwardRef(Button))> - <WithStyles(ForwardRef(Button)) - classes={ - Object { - "label": "text-16-bold", - "root": "btn-secondary", - } - } - onClick={[Function]} - > - <ForwardRef(Button) - classes={ - Object { - "colorInherit": "MuiButton-colorInherit", - "contained": "MuiButton-contained", - "containedPrimary": "MuiButton-containedPrimary", - "containedSecondary": "MuiButton-containedSecondary", - "containedSizeLarge": "MuiButton-containedSizeLarge", - "containedSizeSmall": "MuiButton-containedSizeSmall", - "disableElevation": "MuiButton-disableElevation", - "disabled": "Mui-disabled", - "endIcon": "MuiButton-endIcon", - "focusVisible": "Mui-focusVisible", - "fullWidth": "MuiButton-fullWidth", - "iconSizeLarge": "MuiButton-iconSizeLarge", - "iconSizeMedium": "MuiButton-iconSizeMedium", - "iconSizeSmall": "MuiButton-iconSizeSmall", - "label": "MuiButton-label text-16-bold", - "outlined": "MuiButton-outlined", - "outlinedPrimary": "MuiButton-outlinedPrimary", - "outlinedSecondary": "MuiButton-outlinedSecondary", - "outlinedSizeLarge": "MuiButton-outlinedSizeLarge", - "outlinedSizeSmall": "MuiButton-outlinedSizeSmall", - "root": "MuiButton-root btn-secondary", - "sizeLarge": "MuiButton-sizeLarge", - "sizeSmall": "MuiButton-sizeSmall", - "startIcon": "MuiButton-startIcon", - "text": "MuiButton-text", - "textPrimary": "MuiButton-textPrimary", - "textSecondary": "MuiButton-textSecondary", - "textSizeLarge": "MuiButton-textSizeLarge", - "textSizeSmall": "MuiButton-textSizeSmall", - } - } - onClick={[Function]} - > - <WithStyles(ForwardRef(ButtonBase)) - className="MuiButton-root btn-secondary MuiButton-text" - component="button" - disabled={false} - focusRipple={true} - focusVisibleClassName="Mui-focusVisible" - onClick={[Function]} - type="button" - > - <ForwardRef(ButtonBase) - className="MuiButton-root btn-secondary MuiButton-text" - classes={ - Object { - "disabled": "Mui-disabled", - "focusVisible": "Mui-focusVisible", - "root": "MuiButtonBase-root", - } - } - component="button" - disabled={false} - focusRipple={true} - focusVisibleClassName="Mui-focusVisible" - onClick={[Function]} - type="button" - > - <button - className="MuiButtonBase-root MuiButton-root btn-secondary MuiButton-text" - disabled={false} - onBlur={[Function]} - onClick={[Function]} - onDragLeave={[Function]} - onFocus={[Function]} - onKeyDown={[Function]} - onKeyUp={[Function]} - onMouseDown={[Function]} - onMouseLeave={[Function]} - onMouseUp={[Function]} - onTouchEnd={[Function]} - onTouchMove={[Function]} - onTouchStart={[Function]} - tabIndex={0} - type="button" - > - <span - className="MuiButton-label text-16-bold" - > - auth.button_showOfflineData - </span> - <WithStyles(memo) - center={false} - > - <ForwardRef(TouchRipple) - center={false} - classes={ - Object { - "child": "MuiTouchRipple-child", - "childLeaving": "MuiTouchRipple-childLeaving", - "childPulsate": "MuiTouchRipple-childPulsate", - "ripple": "MuiTouchRipple-ripple", - "ripplePulsate": "MuiTouchRipple-ripplePulsate", - "rippleVisible": "MuiTouchRipple-rippleVisible", - "root": "MuiTouchRipple-root", - } - } - > - <span - className="MuiTouchRipple-root" - > - <TransitionGroup - childFactory={[Function]} - component={null} - exit={true} - /> - </span> - </ForwardRef(TouchRipple)> - </WithStyles(memo)> - </button> - </ForwardRef(ButtonBase)> - </WithStyles(ForwardRef(ButtonBase))> - </ForwardRef(Button)> - </WithStyles(ForwardRef(Button))> - </div> - </div> - </SgeInit> + <mock-EpglInit /> </div> </Connection> </Provider> @@ -416,65 +39,14 @@ exports[`Connection component test should call GrdfInit 1`] = ` } > <Connection - fluidStatus={ - Object { - "connection": Object { - "account": null, - "isUpdating": false, - "konnector": null, - "konnectorConfig": Object { - "activation": "", - "name": "", - "oauth": true, - "siteLink": "", - "slug": "grdfgrandlyon", - }, - "shouldLaunchKonnector": false, - "trigger": null, - "triggerState": null, - }, - "firstDataDate": "2019-09-01T00:00:00.000Z", - "fluidType": 2, - "lastDataDate": "2020-09-01T00:00:00.000Z", - "maintenance": false, - "status": 200, - } - } + fluidType={2} > <div className="konnector-form" > - <mockConstructor - fluidStatus={ - Object { - "connection": Object { - "account": null, - "isUpdating": false, - "konnector": null, - "konnectorConfig": Object { - "activation": "", - "name": "", - "oauth": true, - "siteLink": "", - "slug": "grdfgrandlyon", - }, - "shouldLaunchKonnector": false, - "trigger": null, - "triggerState": null, - }, - "firstDataDate": "2019-09-01T00:00:00.000Z", - "fluidType": 2, - "lastDataDate": "2020-09-01T00:00:00.000Z", - "maintenance": false, - "status": 200, - } - } + <mock-GrdfInit onSuccess={[Function]} - > - <div - id="GrdfInit" - /> - </mockConstructor> + /> </div> </Connection> </Provider> diff --git a/src/components/Consumption/ConsumptionDetails/ConsumptionDetails.spec.tsx b/src/components/Consumption/ConsumptionDetails/ConsumptionDetails.spec.tsx new file mode 100644 index 0000000000000000000000000000000000000000..939ab0b35537bc2dce47ce8195a6ae29ec30f0db --- /dev/null +++ b/src/components/Consumption/ConsumptionDetails/ConsumptionDetails.spec.tsx @@ -0,0 +1,47 @@ +import { FluidType } from 'enums' +import { mount } from 'enzyme' +import toJson from 'enzyme-to-json' +import React from 'react' +import { Provider } from 'react-redux' +import { createMockEcolyoStore } from 'tests/__mocks__/store' +import { waitForComponentToPaint } from 'tests/__mocks__/testUtils' +import ConsumptionDetails from './ConsumptionDetails' + +describe('ConsumptionDetails component', () => { + const store = createMockEcolyoStore() + + it('should be rendered correctly', async () => { + const wrapper = mount( + <Provider store={store}> + <ConsumptionDetails fluidType={FluidType.ELECTRICITY} /> + </Provider> + ) + await waitForComponentToPaint(wrapper) + expect(toJson(wrapper)).toMatchSnapshot() + }) + + it('should not render connection card', () => { + const wrapper = mount( + <Provider store={store}> + <ConsumptionDetails fluidType={FluidType.MULTIFLUID} /> + </Provider> + ) + expect(wrapper.contains('.fluidcard-link')).toBeFalsy() + }) + it('should render one connection card', () => { + const wrapper = mount( + <Provider store={store}> + <ConsumptionDetails fluidType={FluidType.MULTIFLUID} /> + </Provider> + ) + expect(wrapper.find('.fluidcard-link')).toBeTruthy() + }) + it('should not render connection card and show multifluid link', () => { + const wrapper = mount( + <Provider store={store}> + <ConsumptionDetails fluidType={FluidType.ELECTRICITY} /> + </Provider> + ) + expect(wrapper.find('.multi-link')).toBeTruthy() + }) +}) diff --git a/src/components/Home/ConsumptionDetails.tsx b/src/components/Consumption/ConsumptionDetails/ConsumptionDetails.tsx similarity index 86% rename from src/components/Home/ConsumptionDetails.tsx rename to src/components/Consumption/ConsumptionDetails/ConsumptionDetails.tsx index 3d17fc62059044c64b543d436f9da187b4dc75b5..01c5077addf3b167981450552b80adeb48e86a91 100644 --- a/src/components/Home/ConsumptionDetails.tsx +++ b/src/components/Consumption/ConsumptionDetails/ConsumptionDetails.tsx @@ -1,17 +1,15 @@ import TotalConsumption from 'components/TotalConsumption/TotalConsumption' import { useI18n } from 'cozy-ui/transpiled/react/I18n' -import { FluidType } from 'enum/fluid.enum' -import { TimeStep } from 'enum/timeStep.enum' +import { FluidType, TimeStep } from 'enums' import React from 'react' -import { useSelector } from 'react-redux' -import { AppStore } from 'store' +import { useAppSelector } from 'store/hooks' import { convertDateToShortDateString } from 'utils/date' import './consumptionDetails.scss' const ConsumptionDetails = ({ fluidType }: { fluidType: FluidType }) => { const { t } = useI18n() - const { currentTimeStep, currentDatachart, showCompare } = useSelector( - (state: AppStore) => state.ecolyo.chart + const { currentTimeStep, currentDatachart, showCompare } = useAppSelector( + state => state.ecolyo.chart ) return ( diff --git a/src/components/Consumption/ConsumptionDetails/__snapshots__/ConsumptionDetails.spec.tsx.snap b/src/components/Consumption/ConsumptionDetails/__snapshots__/ConsumptionDetails.spec.tsx.snap new file mode 100644 index 0000000000000000000000000000000000000000..77eb4e2b0d3fb4d9348ff85138d62a5014dad889 --- /dev/null +++ b/src/components/Consumption/ConsumptionDetails/__snapshots__/ConsumptionDetails.spec.tsx.snap @@ -0,0 +1,85 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`ConsumptionDetails component should be rendered correctly 1`] = ` +<Provider + store={ + Object { + "clearActions": [Function], + "dispatch": [Function], + "getActions": [Function], + "getState": [Function], + "replaceReducer": [Function], + "subscribe": [Function], + } + } +> + <ConsumptionDetails + fluidType={0} + > + <div + className="consumption-details-root" + > + <div + className="consumption-details-content" + > + <div + className="consumption-details-header text-16-normal-uppercase details-title" + /> + <TotalConsumption + fluidType={0} + > + <div + className="icon-line " + > + <StyledIcon + className="pile-icon" + icon="test-file-stub" + size={36} + > + <Icon + aria-hidden={true} + className="pile-icon" + icon="test-file-stub" + size={36} + spin={false} + > + <Component + aria-hidden={true} + className="pile-icon styles__icon___23x3R" + height={36} + style={Object {}} + width={36} + > + <svg + aria-hidden={true} + className="pile-icon styles__icon___23x3R" + height={36} + style={Object {}} + width={36} + > + <use + xlinkHref="#test-file-stub" + /> + </svg> + </Component> + </Icon> + </StyledIcon> + <div> + <span + className="euro-value" + > + ----- + </span> + <span + className="euro-symbol" + > + € + </span> + </div> + </div> + </TotalConsumption> + </div> + </div> + </ConsumptionDetails> +</Provider> +`; diff --git a/src/components/Home/consumptionDetails.scss b/src/components/Consumption/ConsumptionDetails/consumptionDetails.scss similarity index 100% rename from src/components/Home/consumptionDetails.scss rename to src/components/Consumption/ConsumptionDetails/consumptionDetails.scss diff --git a/src/components/Home/ConsumptionView.spec.tsx b/src/components/Consumption/ConsumptionView.spec.tsx similarity index 51% rename from src/components/Home/ConsumptionView.spec.tsx rename to src/components/Consumption/ConsumptionView.spec.tsx index 1fe128cadf0d202e2d308e2c282741e79a2fc053..75ce5755c9f38d4c15dd4d29afa7687580e14fc0 100644 --- a/src/components/Home/ConsumptionView.spec.tsx +++ b/src/components/Consumption/ConsumptionView.spec.tsx @@ -1,101 +1,82 @@ import Loader from 'components/Loader/Loader' -import { FluidState, FluidType } from 'enum/fluid.enum' -import { TimeStep } from 'enum/timeStep.enum' +import { FluidState, FluidType, TimeStep } from 'enums' import { mount } from 'enzyme' -import { FluidStatus } from 'models' import React from 'react' -import * as reactRedux from 'react-redux' import { Provider } from 'react-redux' import * as chartActions from 'store/chart/chart.slice' -import { mockCustomPopup } from '../../../tests/__mocks__/customPopup.mock' -import { mockTestProfile1 } from '../../../tests/__mocks__/profileType.mock' +import { mockCustomPopup } from 'tests/__mocks__/customPopup.mock' import { - createMockEcolyoStore, mockExpiredElec, mockExpiredGas, +} from 'tests/__mocks__/fluidStatusData.mock' +import { mockTestProfile1 } from 'tests/__mocks__/profileType.mock' +import { + createMockEcolyoStore, + mockChartState, mockInitialEcolyoState, -} from '../../../tests/__mocks__/store' + mockModalState, +} from 'tests/__mocks__/store' import ConsumptionView from './ConsumptionView' -jest.mock('cozy-ui/transpiled/react/I18n', () => { - return { - useI18n: jest.fn(() => { - return { - t: (str: string) => str, - } - }), - } -}) const mockUpdateProfile = jest.fn() jest.mock('services/profile.service', () => { - return jest.fn(() => { - return { - updateProfile: mockUpdateProfile, - } - }) + return jest.fn(() => ({ + updateProfile: mockUpdateProfile, + })) }) -const mockedNavigate = jest.fn() -jest.mock('react-router-dom', () => ({ - ...jest.requireActual('react-router-dom'), - useNavigate: () => mockedNavigate, -})) jest.mock('components/Header/CozyBar', () => 'mock-cozybar') jest.mock('components/Header/Header', () => 'mock-header') -jest.mock('components/DateNavigator/DateNavigator', () => 'mock-datenavigator') +jest.mock('components/DateNavigator/DateNavigator', () => 'mock-dateNavigator') jest.mock('components/Content/Content', () => 'mock-content') -jest.mock('components/Home/FluidButtons', () => 'mock-fluidbuttons') +jest.mock( + 'components/Consumption/FluidButtons/FluidButtons', + () => 'mock-fluidButtons' +) jest.mock('components/FluidChart/FluidChart', () => 'mock-fluidchart') -jest.mock('components/Home/ConsumptionDetails', () => 'mock-consumptiondetails') +jest.mock( + 'components/Consumption/ConsumptionDetails/ConsumptionDetails', + () => 'mock-consumptionDetails' +) jest.mock('components/Connection/Connection', () => 'mock-connection') jest.mock( 'components/Konnector/KonnectorViewerCard', - () => 'mock-konnectorviewercard' + () => 'mock-konnectorViewerCard' ) jest.mock( 'components/PartnerIssue/PartnerIssueModal', - () => 'mock-partnerissuemodal' + () => 'mock-partnerIssueModal' +) +jest.mock('components/CustomPopup/CustomPopupModal', () => 'mock-customPopup') +jest.mock( + 'components/ReleaseNotesModal/ReleaseNotesModal', + () => 'mock-releaseNotes' ) -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') -const mockedPartnersIssueModal = { - enedis: false, - egl: false, - grdf: false, -} +const mockFluidStatus = mockInitialEcolyoState.global.fluidStatus +mockFluidStatus[FluidType.ELECTRICITY].status = FluidState.DONE -describe('ConsumptionView component', () => { - const store = createMockEcolyoStore() - beforeEach(() => { - store.clearActions() - useDispatchSpy.mockClear() - setCurrentTimeStepSpy.mockClear() - }) +const mockChartStateShowOffline = { ...mockChartState, showOfflineData: true } +describe('ConsumptionView component', () => { it('should be rendered correctly', async () => { - const mockFluidStatus: FluidStatus[] = - mockInitialEcolyoState.global.fluidStatus - mockFluidStatus[FluidType.ELECTRICITY].status = FluidState.DONE - useSelectorSpy.mockReturnValue({ + const store = createMockEcolyoStore({ chart: { - currentTimeStep: TimeStep.WEEK, - loading: true, + ...mockChartState, + loading: false, showOfflineData: true, }, global: { fluidStatus: mockFluidStatus, releaseNotes: mockInitialEcolyoState.global.releaseNotes, }, - modal: { partnersIssueModal: mockedPartnersIssueModal }, + modal: mockModalState, }) const wrapper = mount( <Provider store={store}> @@ -104,19 +85,16 @@ describe('ConsumptionView component', () => { ) expect(wrapper.find('mock-cozybar').exists()).toBeTruthy() expect(wrapper.find('mock-header').exists()).toBeTruthy() - expect(wrapper.find('mock-datenavigator').exists()).toBeTruthy() - expect(wrapper.find('mock-fluidbuttons').exists()).toBeTruthy() + expect(wrapper.find('mock-dateNavigator').exists()).toBeTruthy() + expect(wrapper.find('mock-fluidButtons').exists()).toBeTruthy() expect(wrapper.find('mock-fluidchart').exists()).toBeTruthy() - expect(wrapper.find('mock-consumptiondetails').exists()).toBeTruthy() + expect(wrapper.find('mock-consumptionDetails').exists()).toBeTruthy() }) it('should display a spinner when fluid connected and is loading', () => { - const mockFluidStatus: FluidStatus[] = - mockInitialEcolyoState.global.fluidStatus - mockFluidStatus[FluidType.ELECTRICITY].status = FluidState.DONE - useSelectorSpy.mockReturnValue({ + const store = createMockEcolyoStore({ chart: { - currentTimeStep: TimeStep.WEEK, + ...mockChartState, loading: true, showOfflineData: true, }, @@ -124,7 +102,7 @@ describe('ConsumptionView component', () => { fluidStatus: mockFluidStatus, releaseNotes: mockInitialEcolyoState.global.releaseNotes, }, - modal: { partnersIssueModal: mockedPartnersIssueModal }, + modal: mockModalState, }) const wrapper = mount( <Provider store={store}> @@ -133,69 +111,56 @@ describe('ConsumptionView component', () => { ) expect(wrapper.find('mock-cozybar').exists()).toBeTruthy() expect(wrapper.find('mock-header').exists()).toBeTruthy() - expect(wrapper.find('mock-datenavigator').exists()).toBeTruthy() + expect(wrapper.find('mock-dateNavigator').exists()).toBeTruthy() expect(wrapper.find(Loader).exists()).toBeTruthy() }) it('should set CurrentTimeStep to WEEK when fluid != ELECTRICITY and timeStep = HALF_AN_HOUR', () => { - useSelectorSpy.mockReturnValue({ + const store = createMockEcolyoStore({ chart: { + ...mockChartState, currentTimeStep: TimeStep.HALF_AN_HOUR, - loading: true, }, global: { fluidStatus: mockInitialEcolyoState.global.fluidStatus, releaseNotes: mockInitialEcolyoState.global.releaseNotes, }, - modal: { partnersIssueModal: mockedPartnersIssueModal }, + modal: mockModalState, }) mount( <Provider store={store}> <ConsumptionView fluidType={FluidType.GAS} /> </Provider> ) - expect(setCurrentTimeStepSpy).toBeCalledTimes(1) + expect(setCurrentTimeStepSpy).toHaveBeenCalledTimes(1) expect(setCurrentTimeStepSpy).toHaveBeenCalledWith(TimeStep.WEEK) }) it('should render konnector list when no fluid is connected', () => { - useSelectorSpy.mockReturnValue({ - chart: { - currentTimeStep: TimeStep.WEEK, - loading: true, - showOfflineData: true, - }, + const store = createMockEcolyoStore({ + chart: mockChartStateShowOffline, global: { fluidStatus: [], releaseNotes: mockInitialEcolyoState.global.releaseNotes, }, - modal: { partnersIssueModal: mockedPartnersIssueModal }, - fluidStatus: [], + modal: mockModalState, }) const wrapper = mount( <Provider store={store}> <ConsumptionView fluidType={FluidType.MULTIFLUID} /> </Provider> ) - expect(wrapper.find('mock-consumptiondetails').exists()).toBeTruthy() + expect(wrapper.find('mock-consumptionDetails').exists()).toBeTruthy() }) it('should render mutlifluid consumption if at least one fluid is connected', () => { - const updatedStatus: FluidStatus[] = - mockInitialEcolyoState.global.fluidStatus - updatedStatus[1].status = FluidState.DONE - useSelectorSpy.mockReturnValue({ - chart: { - currentTimeStep: TimeStep.WEEK, - loading: true, - showOfflineData: true, - }, + const store = createMockEcolyoStore({ + chart: mockChartStateShowOffline, global: { - fluidStatus: updatedStatus, + fluidStatus: mockFluidStatus, releaseNotes: mockInitialEcolyoState.global.releaseNotes, }, - modal: { partnersIssueModal: mockedPartnersIssueModal }, - fluidStatus: updatedStatus, + modal: mockModalState, }) const wrapper = mount( <Provider store={store}> @@ -206,20 +171,13 @@ describe('ConsumptionView component', () => { }) it('should render Electricity when elec is connected', () => { - const updatedStatus: FluidStatus[] = - mockInitialEcolyoState.global.fluidStatus - updatedStatus[0].status = FluidState.DONE - useSelectorSpy.mockReturnValue({ - chart: { - currentTimeStep: TimeStep.WEEK, - loading: true, - showOfflineData: true, - }, + const store = createMockEcolyoStore({ + chart: mockChartStateShowOffline, global: { - fluidStatus: updatedStatus, + fluidStatus: mockFluidStatus, releaseNotes: mockInitialEcolyoState.global.releaseNotes, }, - modal: { partnersIssueModal: mockedPartnersIssueModal }, + modal: mockModalState, }) const wrapper = mount( <Provider store={store}> @@ -227,50 +185,40 @@ describe('ConsumptionView component', () => { </Provider> ) expect(wrapper.find('.consumptionview-content').exists()).toBeTruthy() - expect(wrapper.find('mock-consumptiondetails').exists()).toBeTruthy() + expect(wrapper.find('mock-consumptionDetails').exists()).toBeTruthy() }) // todo describe and add multiple fluids ? it('should render partner issue Modal', async () => { - const updatedStatus: FluidStatus[] = - mockInitialEcolyoState.global.fluidStatus + const updatedStatus = mockInitialEcolyoState.global.fluidStatus updatedStatus[0] = mockExpiredElec - useSelectorSpy.mockReturnValue({ - chart: { - currentTimeStep: TimeStep.WEEK, - loading: true, - }, + const store = createMockEcolyoStore({ + chart: mockChartStateShowOffline, global: { fluidStatus: updatedStatus, releaseNotes: mockInitialEcolyoState.global.releaseNotes, }, - modal: { partnersIssueModal: { ...mockedPartnersIssueModal, egl: true } }, + modal: { partnersIssueModal: { enedis: false, grdf: false, egl: true } }, }) - useDispatchSpy.mockReturnValue(jest.fn()) mockUpdateProfile.mockResolvedValue(mockTestProfile1) const wrapper = mount( <Provider store={store}> <ConsumptionView fluidType={FluidType.ELECTRICITY} /> </Provider> ) - expect(wrapper.find('mock-partnerissuemodal').exists()).toBeTruthy() + expect(wrapper.find('mock-partnerIssueModal').exists()).toBeTruthy() }) it('should show expired modal when a GRDF consent is expired', () => { - const updatedStatus: FluidStatus[] = - mockInitialEcolyoState.global.fluidStatus + const updatedStatus = mockInitialEcolyoState.global.fluidStatus updatedStatus[0] = mockExpiredGas - useSelectorSpy.mockReturnValue({ - chart: { - currentTimeStep: TimeStep.WEEK, - loading: true, - }, + const store = createMockEcolyoStore({ + chart: mockChartStateShowOffline, global: { fluidStatus: updatedStatus, releaseNotes: mockInitialEcolyoState.global.releaseNotes, }, - modal: { partnersIssueModal: mockedPartnersIssueModal }, + modal: mockModalState, }) - useDispatchSpy.mockReturnValue(jest.fn()) const wrapper = mount( <Provider store={store}> <ConsumptionView fluidType={FluidType.GAS} /> @@ -279,21 +227,16 @@ describe('ConsumptionView component', () => { expect(wrapper.find('.title').text()).toBe('consent_outdated.title.2') }) it('should show expired modal when a Enedis consent is expired', () => { - const updatedStatus: FluidStatus[] = - mockInitialEcolyoState.global.fluidStatus + const updatedStatus = mockInitialEcolyoState.global.fluidStatus updatedStatus[0] = mockExpiredElec - useSelectorSpy.mockReturnValue({ - chart: { - currentTimeStep: TimeStep.WEEK, - loading: true, - }, + const store = createMockEcolyoStore({ + chart: mockChartStateShowOffline, global: { fluidStatus: updatedStatus, releaseNotes: mockInitialEcolyoState.global.releaseNotes, }, - modal: { partnersIssueModal: mockedPartnersIssueModal }, + modal: mockModalState, }) - useDispatchSpy.mockReturnValue(jest.fn()) const wrapper = mount( <Provider store={store}> <ConsumptionView fluidType={FluidType.ELECTRICITY} /> @@ -303,57 +246,43 @@ describe('ConsumptionView component', () => { expect(wrapper.find('.title').text()).toBe('consent_outdated.title.0') }) it('should render customPopup Modal', async () => { - const updatedStatus: FluidStatus[] = - mockInitialEcolyoState.global.fluidStatus - updatedStatus[0] = mockExpiredElec - useSelectorSpy.mockReturnValue({ - chart: { - currentTimeStep: TimeStep.WEEK, - loading: true, - }, + const store = createMockEcolyoStore({ + chart: mockChartStateShowOffline, global: { - fluidStatus: updatedStatus, + fluidStatus: mockFluidStatus, releaseNotes: mockInitialEcolyoState.global.releaseNotes, }, modal: { - partnersIssueModal: mockedPartnersIssueModal, + ...mockModalState, customPopupModal: mockCustomPopup, }, }) - useDispatchSpy.mockReturnValue(jest.fn()) mockUpdateProfile.mockResolvedValue(mockTestProfile1) const wrapper = mount( <Provider store={store}> <ConsumptionView fluidType={FluidType.ELECTRICITY} /> </Provider> ) - expect(wrapper.find('mock-custompopup').exists()).toBeTruthy() + expect(wrapper.find('mock-customPopup').exists()).toBeTruthy() }) it('should render releaseNotesModal if releaseNotes.show is true', async () => { - const updatedStatus: FluidStatus[] = - mockInitialEcolyoState.global.fluidStatus - updatedStatus[0] = mockExpiredElec - useSelectorSpy.mockReturnValue({ - chart: { - currentTimeStep: TimeStep.WEEK, - loading: true, - }, + const store = createMockEcolyoStore({ + chart: mockChartStateShowOffline, global: { - fluidStatus: updatedStatus, + fluidStatus: mockFluidStatus, releaseNotes: { show: true, notes: [{ description: 'description', title: 'title' }], }, }, - modal: { partnersIssueModal: mockedPartnersIssueModal }, + modal: mockModalState, }) - useDispatchSpy.mockReturnValue(jest.fn()) mockUpdateProfile.mockResolvedValue(mockTestProfile1) const wrapper = mount( <Provider store={store}> <ConsumptionView fluidType={FluidType.ELECTRICITY} /> </Provider> ) - expect(wrapper.find('mock-releasenotes').exists()).toBeTruthy() + expect(wrapper.find('mock-releaseNotes').exists()).toBeTruthy() }) }) diff --git a/src/components/Home/ConsumptionView.tsx b/src/components/Consumption/ConsumptionView.tsx similarity index 74% rename from src/components/Home/ConsumptionView.tsx rename to src/components/Consumption/ConsumptionView.tsx index d6d6373561ad2b59f0bf53ef7f4bbbca26d398bd..a8658aaf03e96f441098b87cd5ca1b0de822083f 100644 --- a/src/components/Home/ConsumptionView.tsx +++ b/src/components/Consumption/ConsumptionView.tsx @@ -1,46 +1,60 @@ import classNames from 'classnames' -import ExpiredConsentModal from 'components/Connection/ExpiredConsentModal' +import ExpiredConsentModal from 'components/Connection/ExpiredConsentModal/ExpiredConsentModal' import Content from 'components/Content/Content' import CustomPopupModal from 'components/CustomPopup/CustomPopupModal' import DateNavigator from 'components/DateNavigator/DateNavigator' import FluidChart from 'components/FluidChart/FluidChart' import CozyBar from 'components/Header/CozyBar' import Header from 'components/Header/Header' -import ConsumptionDetails from 'components/Home/ConsumptionDetails' -import FluidButtons from 'components/Home/FluidButtons' import KonnectorViewerCard from 'components/Konnector/KonnectorViewerCard' import KonnectorViewerList from 'components/Konnector/KonnectorViewerList' import Loader from 'components/Loader/Loader' import PartnerIssueModal from 'components/PartnerIssue/PartnerIssueModal' +import ReleaseNotesModal from 'components/ReleaseNotesModal/ReleaseNotesModal' import { useClient } from 'cozy-client' -import { FluidType } from 'enum/fluid.enum' -import { TimeStep } from 'enum/timeStep.enum' -import React, { Dispatch, useCallback, useEffect, useState } from 'react' -import { useDispatch, useSelector } from 'react-redux' +import { FluidType, TimeStep } from 'enums' +import { DateTime } from 'luxon' +import React, { useCallback, useEffect, useState } from 'react' import { useNavigate } from 'react-router-dom' +import DateChartService from 'services/dateChart.service' import ProfileService from 'services/profile.service' -import { AppActionsTypes, AppStore } from 'store' -import { setCurrentTimeStep, setShowOfflineData } from 'store/chart/chart.slice' -import { showReleaseNotes } from 'store/global/global.actions' +import { + setCurrentIndex, + setCurrentTimeStep, + setSelectedDate, + setShowOfflineData, +} from 'store/chart/chart.slice' +import { showReleaseNotes } from 'store/global/global.slice' +import { useAppDispatch, useAppSelector } from 'store/hooks' import { openPartnersModal, setCustomPopup } from 'store/modal/modal.slice' +import { isLastDateReached } from 'utils/date' import { getKonnectorUpdateError, getTodayDate, isKonnectorActive, } from 'utils/utils' -import ReleaseNotesModal from './ReleaseNotesModal' +import ConsumptionDetails from './ConsumptionDetails/ConsumptionDetails' +import FluidButtons from './FluidButtons/FluidButtons' import './consumptionView.scss' const ConsumptionView = ({ fluidType }: { fluidType: FluidType }) => { const navigate = useNavigate() const client = useClient() - const dispatch = useDispatch<Dispatch<AppActionsTypes>>() + const dispatch = useAppDispatch() const isMulti = fluidType === FluidType.MULTIFLUID const { - chart: { currentTimeStep, loading, showOfflineData }, + chart: { + currentTimeStep, + loading, + showOfflineData, + selectedDate, + currentIndex, + }, global: { fluidStatus, releaseNotes }, modal: { partnersIssueModal, customPopupModal }, - } = useSelector((state: AppStore) => state.ecolyo) + } = useAppSelector(state => state.ecolyo) + + const dateChartService = new DateChartService() const [openReleaseNoteModal, setOpenReleaseNoteModal] = useState<boolean>( releaseNotes.show @@ -65,14 +79,14 @@ const ConsumptionView = ({ fluidType }: { fluidType: FluidType }) => { ? `${fluidStatus[fluidType].lastDataDate!.toLocaleString() + fluidType}` : '' - const defineHeaderHeight = useCallback((height: number) => { - setHeaderHeight(height) - }, []) - const handleCloseReleaseNoteModal = useCallback(() => { setOpenReleaseNoteModal(false) dispatch( - showReleaseNotes(false, releaseNotes.notes, releaseNotes.redirectLink) + showReleaseNotes({ + show: false, + notes: releaseNotes.notes, + redirectLink: releaseNotes.redirectLink, + }) ) if (releaseNotes.redirectLink) { navigate(releaseNotes.redirectLink) @@ -167,16 +181,57 @@ const ConsumptionView = ({ fluidType }: { fluidType: FluidType }) => { } }, [fluidStatus]) + const disablePrev = + selectedDate < + DateTime.local(0, 1, 1).setZone('utc', { + keepLocalTime: true, + }) && !isKonnectorActive(fluidStatus, FluidType.MULTIFLUID) + + const getIncrement = (next: boolean) => + next + ? dateChartService.defineIncrementForNextIndex( + currentTimeStep, + selectedDate, + currentIndex + ) + : dateChartService.defineIncrementForPreviousIndex( + currentTimeStep, + selectedDate, + currentIndex + ) + + const handleClickMove = (next: boolean) => { + const increment = getIncrement(next) + const updatedDate = dateChartService.incrementDate( + currentTimeStep, + selectedDate, + increment + ) + const updatedIndex = dateChartService.defineDateIndex( + currentTimeStep, + updatedDate + ) + dispatch(setSelectedDate(updatedDate)) + dispatch(setCurrentIndex(updatedIndex)) + } + return ( <> - <CozyBar titleKey={'common.title_consumption'} /> + <CozyBar titleKey="common.title_consumption" /> <Header - setHeaderHeight={defineHeaderHeight} - desktopTitleKey={'common.title_consumption'} + setHeaderHeight={setHeaderHeight} + desktopTitleKey="common.title_consumption" > - <DateNavigator /> + <DateNavigator + disableNext={isLastDateReached(selectedDate, currentTimeStep)} + disablePrev={disablePrev} + handleNextDate={() => handleClickMove(true)} + handlePrevDate={() => handleClickMove(false)} + navigatorDate={selectedDate} + timeStep={currentTimeStep} + /> </Header> - <Content height={headerHeight}> + <Content heightOffset={headerHeight}> <FluidButtons activeFluid={fluidType} key={updateKey} /> {openReleaseNoteModal && ( @@ -188,7 +243,7 @@ const ConsumptionView = ({ fluidType }: { fluidType: FluidType }) => { {showOfflineData && ( <> {loading && ( - <div className={'consumptionview-loading'} aria-busy="true"> + <div className="consumptionview-loading"> <Loader fluidType={fluidType} /> </div> )} @@ -207,9 +262,7 @@ const ConsumptionView = ({ fluidType }: { fluidType: FluidType }) => { {!isMulti && ( <div className="konnector-section"> <KonnectorViewerCard - fluidStatus={fluidStatus[fluidType]} fluidType={fluidType} - isParam={true} isDisconnected={false} showOfflineData={true} setActive={setActive} @@ -226,9 +279,7 @@ const ConsumptionView = ({ fluidType }: { fluidType: FluidType }) => { <KonnectorViewerList /> ) : ( <KonnectorViewerCard - fluidStatus={fluidStatus[fluidType]} fluidType={fluidType} - isParam={false} isDisconnected={true} showOfflineData={false} setActive={setActive} @@ -245,7 +296,7 @@ const ConsumptionView = ({ fluidType }: { fluidType: FluidType }) => { .map(issuedFluid => ( <PartnerIssueModal key={issuedFluid.fluidType} - issuedFluid={issuedFluid} + issuedFluid={issuedFluid.fluidType} open={partnersIssueModal[getPartnerKey(issuedFluid.fluidType)]} handleCloseClick={handleClosePartnerIssueModal} /> diff --git a/src/components/Home/FluidButton.spec.tsx b/src/components/Consumption/FluidButtons/FluidButton.spec.tsx similarity index 65% rename from src/components/Home/FluidButton.spec.tsx rename to src/components/Consumption/FluidButtons/FluidButton.spec.tsx index 9799a3d51470408cfc6047466283aaee891797d3..28699710e7d5fa9239d9b75d879c894a85d1104a 100644 --- a/src/components/Home/FluidButton.spec.tsx +++ b/src/components/Consumption/FluidButtons/FluidButton.spec.tsx @@ -1,38 +1,16 @@ -import { FluidState, FluidType } from 'enum/fluid.enum' +import { FluidState, FluidType } from 'enums' import { mount } from 'enzyme' import toJson from 'enzyme-to-json' import { GlobalState } from 'models' import React from 'react' import { Provider } from 'react-redux' -import configureStore from 'redux-mock-store' import UsageEventService from 'services/usageEvent.service' -import { - createMockEcolyoStore, - mockInitialGlobalState, -} from '../../../tests/__mocks__/store' -import { waitForComponentToPaint } from '../../../tests/__mocks__/testUtils' +import { createMockEcolyoStore, mockGlobalState } from 'tests/__mocks__/store' +import { waitForComponentToPaint } from 'tests/__mocks__/testUtils' import FluidButton from './FluidButton' -jest.mock('cozy-ui/transpiled/react/I18n', () => { - return { - useI18n: jest.fn(() => { - return { - t: (str: string) => str, - } - }), - } -}) -const mockedNavigate = jest.fn() -jest.mock('react-router-dom', () => ({ - ...jest.requireActual('react-router-dom'), - useNavigate: () => mockedNavigate, -})) - describe('FluidButton component', () => { const store = createMockEcolyoStore() - beforeEach(() => { - store.clearActions() - }) it('should be rendered correctly', async () => { const wrapper = mount( @@ -75,19 +53,15 @@ describe('FluidButton component', () => { }) it('should render errored button', () => { - const mockStore = configureStore([]) - - const updatedInitalState: GlobalState = { - ...mockInitialGlobalState, + const updatedInitialState: GlobalState = { + ...mockGlobalState, } - updatedInitalState.fluidStatus[FluidType.GAS].status = FluidState.ERROR - const store2 = mockStore({ - ecolyo: { - global: updatedInitalState, - }, + updatedInitialState.fluidStatus[FluidType.GAS].status = FluidState.ERROR + const store = createMockEcolyoStore({ + global: updatedInitialState, }) const wrapper = mount( - <Provider store={store2}> + <Provider store={store}> <FluidButton fluidType={FluidType.GAS} isActive={false} /> </Provider> ) diff --git a/src/components/Home/FluidButton.tsx b/src/components/Consumption/FluidButtons/FluidButton.tsx similarity index 77% rename from src/components/Home/FluidButton.tsx rename to src/components/Consumption/FluidButtons/FluidButton.tsx index dcc93f5344cb85a26f2b9f95753b5e68ed24e731..0d78a7cc350dc20b364284efcd6bb63cd8968dda 100644 --- a/src/components/Home/FluidButton.tsx +++ b/src/components/Consumption/FluidButtons/FluidButton.tsx @@ -3,14 +3,11 @@ import PartnerIssueNotif from 'assets/icons/ico/notif_maintenance.svg' import StyledIcon from 'components/CommonKit/Icon/StyledIcon' import { useClient } from 'cozy-client' import { useI18n } from 'cozy-ui/transpiled/react/I18n' -import { FluidState, FluidType } from 'enum/fluid.enum' -import { UsageEventType } from 'enum/usageEvent.enum' +import { FluidState, FluidType, UsageEventType } from 'enums' import React, { useCallback, useEffect, useState } from 'react' -import { useSelector } from 'react-redux' import { useNavigate } from 'react-router-dom' -import DateChartService from 'services/dateChart.service' import UsageEventService from 'services/usageEvent.service' -import { AppStore } from 'store' +import { useAppSelector } from 'store/hooks' import { getNavPicto } from 'utils/picto' import { getFluidName, isKonnectorActive } from 'utils/utils' @@ -21,9 +18,9 @@ interface FluidButtonProps { const FluidButton = ({ fluidType, isActive }: FluidButtonProps) => { const { t } = useI18n() - const navigate = useNavigate() - const { fluidStatus } = useSelector((state: AppStore) => state.ecolyo.global) const client = useClient() + const navigate = useNavigate() + const { fluidStatus } = useAppSelector(state => state.ecolyo.global) const [showError, setShowError] = useState<boolean>(false) const isConnected = useCallback(() => { @@ -44,15 +41,6 @@ const FluidButton = ({ fluidType, isActive }: FluidButtonProps) => { return false }, [fluidStatus, fluidType]) - const isOutdated = useCallback(() => { - const dateChartService = new DateChartService() - - return dateChartService.isDataOutdated( - fluidStatus[fluidType].lastDataDate, - fluidType - ) - }, [fluidStatus, fluidType]) - const iconType = getNavPicto(fluidType, isActive, isConnected()) const goToFluid = useCallback(async () => { @@ -71,13 +59,10 @@ const FluidButton = ({ fluidType, isActive }: FluidButtonProps) => { useEffect(() => { // Show errors only on connected konnectors that are in error, outdated, with no data (specific case), and not in multifluid - if ( - (fluidType !== FluidType.MULTIFLUID && isConnected() && isErrored()) || - (fluidType !== FluidType.MULTIFLUID && isConnected() && isOutdated()) - ) { + if (fluidType !== FluidType.MULTIFLUID && isConnected() && isErrored()) { setShowError(true) } - }, [fluidStatus, fluidType, isConnected, isErrored, isOutdated]) + }, [fluidStatus, fluidType, isConnected, isErrored]) return ( <div className={`fluid-title ${FluidType[ @@ -106,7 +91,7 @@ const FluidButton = ({ fluidType, isActive }: FluidButtonProps) => { isActive && 'active' } text-14-normal`} > - {t('FLUID.' + FluidType[fluidType] + '.LABEL')} + {t(`FLUID.${FluidType[fluidType]}.LABEL`)} </div> </div> ) diff --git a/src/components/Consumption/FluidButtons/FluidButtons.spec.tsx b/src/components/Consumption/FluidButtons/FluidButtons.spec.tsx new file mode 100644 index 0000000000000000000000000000000000000000..4517997e1748978a089adc3a5dcf152e6c69f8ee --- /dev/null +++ b/src/components/Consumption/FluidButtons/FluidButtons.spec.tsx @@ -0,0 +1,22 @@ +import { FluidType } from 'enums' +import { mount } from 'enzyme' +import toJson from 'enzyme-to-json' +import React from 'react' +import { Provider } from 'react-redux' +import { createMockEcolyoStore } from 'tests/__mocks__/store' +import { waitForComponentToPaint } from 'tests/__mocks__/testUtils' +import FluidButtons from './FluidButtons' + +describe('FluidButtons component', () => { + const store = createMockEcolyoStore() + + it('should be rendered correctly', async () => { + const wrapper = mount( + <Provider store={store}> + <FluidButtons activeFluid={FluidType.ELECTRICITY} /> + </Provider> + ) + await waitForComponentToPaint(wrapper) + expect(toJson(wrapper)).toMatchSnapshot() + }) +}) diff --git a/src/components/Home/FluidButtons.tsx b/src/components/Consumption/FluidButtons/FluidButtons.tsx similarity index 93% rename from src/components/Home/FluidButtons.tsx rename to src/components/Consumption/FluidButtons/FluidButtons.tsx index 62bcae8bfdbf25a7467e19f466f215151dca1b90..09ec44d26b5e6364eb28d3d8ab7de5ae5aa38d18 100644 --- a/src/components/Home/FluidButtons.tsx +++ b/src/components/Consumption/FluidButtons/FluidButtons.tsx @@ -1,4 +1,4 @@ -import { FluidType } from 'enum/fluid.enum' +import { FluidType } from 'enums' import React from 'react' import FluidButton from './FluidButton' import './fluidButtons.scss' diff --git a/src/components/Home/__snapshots__/FluidButton.spec.tsx.snap b/src/components/Consumption/FluidButtons/__snapshots__/FluidButton.spec.tsx.snap similarity index 100% rename from src/components/Home/__snapshots__/FluidButton.spec.tsx.snap rename to src/components/Consumption/FluidButtons/__snapshots__/FluidButton.spec.tsx.snap diff --git a/src/components/Home/__snapshots__/FluidButtons.spec.tsx.snap b/src/components/Consumption/FluidButtons/__snapshots__/FluidButtons.spec.tsx.snap similarity index 100% rename from src/components/Home/__snapshots__/FluidButtons.spec.tsx.snap rename to src/components/Consumption/FluidButtons/__snapshots__/FluidButtons.spec.tsx.snap diff --git a/src/components/Home/fluidButtons.scss b/src/components/Consumption/FluidButtons/fluidButtons.scss similarity index 100% rename from src/components/Home/fluidButtons.scss rename to src/components/Consumption/FluidButtons/fluidButtons.scss diff --git a/src/components/Home/consumptionView.scss b/src/components/Consumption/consumptionView.scss similarity index 100% rename from src/components/Home/consumptionView.scss rename to src/components/Consumption/consumptionView.scss diff --git a/src/components/ConsumptionVisualizer/ConsumptionVisualizer.tsx b/src/components/ConsumptionVisualizer/ConsumptionVisualizer.tsx index d497f4279740b55cac3eb60cc1527c10f54b5aca..3abf83ce6491136f93ef9c8e1b8c661eff2907ba 100644 --- a/src/components/ConsumptionVisualizer/ConsumptionVisualizer.tsx +++ b/src/components/ConsumptionVisualizer/ConsumptionVisualizer.tsx @@ -1,10 +1,9 @@ import DataloadConsumptionVisualizer from 'components/ConsumptionVisualizer/DataloadConsumptionVisualizer' -import { FluidType } from 'enum/fluid.enum' +import { FluidType } from 'enums' import { DateTime } from 'luxon' import { Dataload } from 'models' import React from 'react' -import { useSelector } from 'react-redux' -import { AppStore } from 'store' +import { useAppSelector } from 'store/hooks' import InfoDataConsumptionVisualizer from './InfoDataConsumptionVisualizer' import './consumptionVisualizer.scss' @@ -19,7 +18,7 @@ const ConsumptionVisualizer = ({ const { chart: { currentDatachart, currentDatachartIndex }, global: { fluidStatus, fluidTypes }, - } = useSelector((state: AppStore) => state.ecolyo) + } = useAppSelector(state => state.ecolyo) const dataload: Dataload = currentDatachart.actualData[currentDatachartIndex] const compareDataload: Dataload | null = currentDatachart.comparisonData diff --git a/src/components/ConsumptionVisualizer/DataloadConsumptionVisualizer.spec.tsx b/src/components/ConsumptionVisualizer/DataloadConsumptionVisualizer.spec.tsx index 83fa79f6b3e31125182c1deda1a0b861a7783b86..7dda1e01b6dc024cb11e920b99b21fda890d103e 100644 --- a/src/components/ConsumptionVisualizer/DataloadConsumptionVisualizer.spec.tsx +++ b/src/components/ConsumptionVisualizer/DataloadConsumptionVisualizer.spec.tsx @@ -1,42 +1,32 @@ -import { DataloadState } from 'enum/dataload.enum' -import { FluidType } from 'enum/fluid.enum' +import { DataloadState, FluidType } from 'enums' import { mount } from 'enzyme' import toJson from 'enzyme-to-json' +import { DateTime } from 'luxon' import { Dataload } from 'models' import React from 'react' import { Provider } from 'react-redux' import { BrowserRouter } from 'react-router-dom' -import configureStore from 'redux-mock-store' import UsageEventService from 'services/usageEvent.service' -import { baseDataLoad } from '../../../tests/__mocks__/chartData.mock' -import { - mockInitialChartState, - mockInitialEcolyoState, -} from '../../../tests/__mocks__/store' -import { waitForComponentToPaint } from '../../../tests/__mocks__/testUtils' +import { baseDataLoad } from 'tests/__mocks__/chartData.mock' +import { createMockEcolyoStore, mockChartState } from 'tests/__mocks__/store' +import { waitForComponentToPaint } from 'tests/__mocks__/testUtils' import DataloadConsumptionVisualizer from './DataloadConsumptionVisualizer' -jest.mock('cozy-ui/transpiled/react/I18n', () => { - return { - useI18n: jest.fn(() => { - return { - t: (str: string) => str, - } - }), - } -}) - -const mockGetAllLastPrices = jest.fn() jest.mock('services/fluidsPrices.service', () => { - return jest.fn(() => { - return { - getAllLastPrices: mockGetAllLastPrices, - } - }) + return jest.fn(() => ({ + getAllLastPrices: jest.fn(), + })) }) -const mockStore = configureStore([]) -const mockChartStateLoaded = { ...mockInitialChartState, loading: false } +jest.mock( + 'components/ConsumptionVisualizer/DataloadNoValue.tsx', + () => 'mock-DataloadNoValue' +) +jest.mock( + 'components/ConsumptionVisualizer/EstimatedConsumptionModal.tsx', + () => 'mock-EstimatedConsumptionModal' +) + const emptyDataLoad = { ...baseDataLoad, value: -1 } const dataLoadWithValueDetailEmpty: Dataload = { ...baseDataLoad, @@ -52,12 +42,55 @@ const dataLoadWithValueDetail: Dataload = { } describe('Dataload consumption visualizer component', () => { - it('should render with single fluid', async () => { - const store = mockStore({ - ecolyo: { - chart: mockChartStateLoaded, - }, + const store = createMockEcolyoStore() + describe('should render nothing', () => { + it('should render nothing if dataload is null', () => { + const wrapper = mount( + <Provider store={store}> + <DataloadConsumptionVisualizer + fluidType={FluidType.ELECTRICITY} + dataload={null as unknown as Dataload} + compareDataload={baseDataLoad} + setActive={jest.fn()} + /> + </Provider> + ) + expect(wrapper.find('.dataloadvisualizer-root').children()).toHaveLength( + 0 + ) + }) + it('should render nothing if dataload is in the future', () => { + const wrapper = mount( + <Provider store={store}> + <DataloadConsumptionVisualizer + fluidType={FluidType.ELECTRICITY} + dataload={{ ...baseDataLoad, date: DateTime.local(9999, 1, 1) }} + compareDataload={baseDataLoad} + setActive={jest.fn()} + /> + </Provider> + ) + expect(wrapper.find('.dataloadvisualizer-root').children()).toHaveLength( + 0 + ) }) + }) + + it('should render DataloadNoValue if dataload.state is not valid', () => { + const wrapper = mount( + <Provider store={store}> + <DataloadConsumptionVisualizer + fluidType={FluidType.ELECTRICITY} + dataload={{ ...baseDataLoad, state: DataloadState.MISSING }} + compareDataload={baseDataLoad} + setActive={jest.fn()} + /> + </Provider> + ) + expect(wrapper.find('mock-DataloadNoValue').exists()).toBeTruthy() + }) + + it('should render with single fluid', async () => { const wrapper = mount( <Provider store={store}> <DataloadConsumptionVisualizer @@ -72,9 +105,7 @@ describe('Dataload consumption visualizer component', () => { expect(toJson(wrapper)).toMatchSnapshot() }) it('should render correctly multifluid and 3 clickable links', () => { - const store = mockStore({ - ecolyo: mockInitialEcolyoState, - }) + const store = createMockEcolyoStore() const wrapper = mount( <Provider store={store}> <BrowserRouter> @@ -91,10 +122,8 @@ describe('Dataload consumption visualizer component', () => { }) it('should render with no value to compare available', async () => { - const store = mockStore({ - ecolyo: { - chart: { ...mockChartStateLoaded, showCompare: true }, - }, + const store = createMockEcolyoStore({ + chart: { ...mockChartState, showCompare: true }, }) const wrapper = mount( <Provider store={store}> @@ -109,10 +138,8 @@ describe('Dataload consumption visualizer component', () => { expect(wrapper.find('.dataloadvisualizer-novalue').exists()).toBeTruthy() }) it('should render with water comparison data', async () => { - const store = mockStore({ - ecolyo: { - chart: { ...mockChartStateLoaded, showCompare: true }, - }, + const store = createMockEcolyoStore({ + chart: { ...mockChartState, showCompare: true }, }) const wrapper = mount( <Provider store={store}> @@ -127,12 +154,6 @@ describe('Dataload consumption visualizer component', () => { expect(wrapper.find('.water-compare').exists()).toBeTruthy() }) it('should render multifluid with no compare and display estimation modal', async () => { - const store = mockStore({ - ecolyo: { - chart: mockChartStateLoaded, - }, - }) - const wrapper = mount( <Provider store={store}> <DataloadConsumptionVisualizer @@ -143,21 +164,13 @@ describe('Dataload consumption visualizer component', () => { /> </Provider> ) - expect(wrapper.find('.estimated').first().simulate('click')) + expect(wrapper.find('mock-EstimatedConsumptionModal').exists()).toBeTruthy() }) it('should render multifluid with no compare and navigate to singleFluid page', async () => { - const store = mockStore({ - ecolyo: { - chart: mockChartStateLoaded, - }, - }) - const mockLoadToEuro = jest.fn() jest.mock('services/converter.service', () => { - return jest.fn(() => { - return { - LoadToEuro: mockLoadToEuro, - } - }) + return jest.fn(() => ({ + LoadToEuro: jest.fn(), + })) }) const wrapper = mount( diff --git a/src/components/ConsumptionVisualizer/DataloadConsumptionVisualizer.tsx b/src/components/ConsumptionVisualizer/DataloadConsumptionVisualizer.tsx index be0f81676b33701aa787dcf8c0556fb5519ccf95..b7bc960a35d140af1f14870a7c04f70b0006a962 100644 --- a/src/components/ConsumptionVisualizer/DataloadConsumptionVisualizer.tsx +++ b/src/components/ConsumptionVisualizer/DataloadConsumptionVisualizer.tsx @@ -1,9 +1,8 @@ -import { DataloadSectionType, DataloadState } from 'enum/dataload.enum' -import { FluidType } from 'enum/fluid.enum' +import { DataloadSectionType, DataloadState, FluidType } from 'enums' +import { DateTime } from 'luxon' import { Dataload } from 'models' import React, { useCallback, useState } from 'react' -import { useSelector } from 'react-redux' -import { AppStore } from 'store' +import { useAppSelector } from 'store/hooks' import DataloadNoValue from './DataloadNoValue' import DataloadSection from './DataloadSection' import EstimatedConsumptionModal from './EstimatedConsumptionModal' @@ -21,13 +20,13 @@ const DataloadConsumptionVisualizer = ({ compareDataload, setActive, }: DataloadConsumptionVisualizerProps) => { - const { showCompare } = useSelector((state: AppStore) => state.ecolyo.chart) + const { showCompare } = useAppSelector(state => state.ecolyo.chart) const [openEstimationModal, setOpenEstimationModal] = useState<boolean>(false) const toggleEstimationModal = useCallback(() => { setOpenEstimationModal(prev => !prev) }, []) - if (!dataload) { + if (!dataload || dataload.date > DateTime.local()) { return <div className="dataloadvisualizer-root" /> } diff --git a/src/components/ConsumptionVisualizer/DataloadNoValue.spec.tsx b/src/components/ConsumptionVisualizer/DataloadNoValue.spec.tsx index 8dff84828bf4e4d4803c9035969db86858c99a8e..8d9f0618371c50cd34c33e139e928162ce35aa4d 100644 --- a/src/components/ConsumptionVisualizer/DataloadNoValue.spec.tsx +++ b/src/components/ConsumptionVisualizer/DataloadNoValue.spec.tsx @@ -1,21 +1,11 @@ -import { DataloadState } from 'enum/dataload.enum' -import { FluidType } from 'enum/fluid.enum' +import { DataloadState, FluidType } from 'enums' import { mount } from 'enzyme' import toJson from 'enzyme-to-json' import { Dataload } from 'models' import React from 'react' -import { baseDataLoad } from '../../../tests/__mocks__/chartData.mock' +import { baseDataLoad } from 'tests/__mocks__/chartData.mock' import DataloadNoValue from './DataloadNoValue' -jest.mock('cozy-ui/transpiled/react/I18n', () => { - return { - useI18n: jest.fn(() => { - return { - t: (str: string) => str, - } - }), - } -}) const mockSetActive = jest.fn() describe('DataloadNoValue component', () => { @@ -119,6 +109,6 @@ describe('DataloadNoValue component', () => { /> ) wrapper.find('.dataloadvisualizer-content').simulate('click') - expect(mockSetActive).toBeCalledWith(true) + expect(mockSetActive).toHaveBeenCalledWith(true) }) }) diff --git a/src/components/ConsumptionVisualizer/DataloadNoValue.tsx b/src/components/ConsumptionVisualizer/DataloadNoValue.tsx index 65aee657bcf1604731a8530053e77a10a8264841..6133a012ded8eb94843dbea17730bed04adfc79b 100644 --- a/src/components/ConsumptionVisualizer/DataloadNoValue.tsx +++ b/src/components/ConsumptionVisualizer/DataloadNoValue.tsx @@ -1,7 +1,6 @@ import classNames from 'classnames' import { useI18n } from 'cozy-ui/transpiled/react/I18n' -import { DataloadState } from 'enum/dataload.enum' -import { FluidType } from 'enum/fluid.enum' +import { DataloadState, FluidType } from 'enums' import { Dataload } from 'models' import React, { useCallback } from 'react' import './consumptionVisualizer.scss' @@ -46,7 +45,7 @@ const DataloadNoValue = ({ dataload.state === DataloadState.AGGREGATED_EMPTY ) { return ( - <div className={`dataloadvisualizer-content text-22-normal`}> + <div className="dataloadvisualizer-content text-22-normal"> <div className="dataloadvisualizer-section"> <div className={`dataloadvisualizer-value ${FluidType[ @@ -67,9 +66,7 @@ const DataloadNoValue = ({ return ( <div onClick={handleToggleKonnectionCard} - className={classNames('dataloadvisualizer-content text-22-normal', { - ['error']: fluidType !== FluidType.MULTIFLUID, - })} + className={classNames('dataloadvisualizer-content text-22-normal')} > {t('consumption_visualizer.missing_data')} </div> @@ -77,7 +74,7 @@ const DataloadNoValue = ({ } return ( - <div className={`dataloadvisualizer-content text-22-normal`}> + <div className="dataloadvisualizer-content text-22-normal"> <div className="dataloadvisualizer-section"> <div className={`dataloadvisualizer-value ${FluidType[ diff --git a/src/components/ConsumptionVisualizer/DataloadSection.spec.tsx b/src/components/ConsumptionVisualizer/DataloadSection.spec.tsx index 32f5bea2191f47acaaf765256569cfb3aeb34cb8..aef6fc33e7a13cfca6e51e8647c945e6ce906d91 100644 --- a/src/components/ConsumptionVisualizer/DataloadSection.spec.tsx +++ b/src/components/ConsumptionVisualizer/DataloadSection.spec.tsx @@ -1,22 +1,11 @@ -import { DataloadSectionType } from 'enum/dataload.enum' -import { FluidType } from 'enum/fluid.enum' +import { DataloadSectionType, FluidType } from 'enums' import { mount } from 'enzyme' import toJson from 'enzyme-to-json' import { Dataload } from 'models' import React from 'react' -import { baseDataLoad } from '../../../tests/__mocks__/chartData.mock' +import { baseDataLoad } from 'tests/__mocks__/chartData.mock' import DataloadSection from './DataloadSection' -jest.mock('cozy-ui/transpiled/react/I18n', () => { - return { - useI18n: jest.fn(() => { - return { - t: (str: string) => str, - } - }), - } -}) - jest.mock( 'components/ConsumptionVisualizer/DataloadSectionValue', () => 'mock-dataloadsectionvalue' diff --git a/src/components/ConsumptionVisualizer/DataloadSection.tsx b/src/components/ConsumptionVisualizer/DataloadSection.tsx index 85ddd0648f5e3fb88217789b499d4bc7d413247e..19d7739bdac8e14ee7fd4a8dff7a654131a40c13 100644 --- a/src/components/ConsumptionVisualizer/DataloadSection.tsx +++ b/src/components/ConsumptionVisualizer/DataloadSection.tsx @@ -1,7 +1,6 @@ import classNames from 'classnames' import { useI18n } from 'cozy-ui/transpiled/react/I18n' -import { DataloadSectionType } from 'enum/dataload.enum' -import { FluidType } from 'enum/fluid.enum' +import { DataloadSectionType, FluidType } from 'enums' import { Dataload } from 'models' import React from 'react' import { getFluidName } from 'utils/utils' diff --git a/src/components/ConsumptionVisualizer/DataloadSectionDetail.spec.tsx b/src/components/ConsumptionVisualizer/DataloadSectionDetail.spec.tsx index 677ebe1a5dc112445d9509ef8287f27630155f2f..144cbc4d6b1f190b943ee7654f0139a6f7a306aa 100644 --- a/src/components/ConsumptionVisualizer/DataloadSectionDetail.spec.tsx +++ b/src/components/ConsumptionVisualizer/DataloadSectionDetail.spec.tsx @@ -1,22 +1,11 @@ -import { DataloadSectionType, DataloadState } from 'enum/dataload.enum' -import { FluidType } from 'enum/fluid.enum' +import { DataloadSectionType, DataloadState, FluidType } from 'enums' import { mount } from 'enzyme' import toJson from 'enzyme-to-json' import { Dataload } from 'models' import React from 'react' -import { baseDataLoad } from '../../../tests/__mocks__/chartData.mock' +import { baseDataLoad } from 'tests/__mocks__/chartData.mock' import DataloadSectionDetail from './DataloadSectionDetail' -jest.mock('cozy-ui/transpiled/react/I18n', () => { - return { - useI18n: jest.fn(() => { - return { - t: (str: string) => str, - } - }), - } -}) - describe('DataloadSectionDetail component', () => { const mockDataload: Dataload = baseDataLoad diff --git a/src/components/ConsumptionVisualizer/DataloadSectionDetail.tsx b/src/components/ConsumptionVisualizer/DataloadSectionDetail.tsx index 78861f7447c7eacecafa07f88a61f561afd9a039..18a607e312cae5990e94fd6c33cd4d02c31e042a 100644 --- a/src/components/ConsumptionVisualizer/DataloadSectionDetail.tsx +++ b/src/components/ConsumptionVisualizer/DataloadSectionDetail.tsx @@ -2,9 +2,12 @@ import classNames from 'classnames' import { useClient } from 'cozy-client' import { useI18n } from 'cozy-ui/transpiled/react/I18n' import Icon from 'cozy-ui/transpiled/react/Icon' -import { DataloadSectionType, DataloadState } from 'enum/dataload.enum' -import { FluidType } from 'enum/fluid.enum' -import { UsageEventType } from 'enum/usageEvent.enum' +import { + DataloadSectionType, + DataloadState, + FluidType, + UsageEventType, +} from 'enums' import { Dataload } from 'models' import React, { useCallback } from 'react' import { NavLink } from 'react-router-dom' diff --git a/src/components/ConsumptionVisualizer/DataloadSectionValue.spec.tsx b/src/components/ConsumptionVisualizer/DataloadSectionValue.spec.tsx index 1604ac509cbe4eb41c061242906a9f84c8ac6a78..f29778adad0504ebdeef92f847779da38c684715 100644 --- a/src/components/ConsumptionVisualizer/DataloadSectionValue.spec.tsx +++ b/src/components/ConsumptionVisualizer/DataloadSectionValue.spec.tsx @@ -1,5 +1,4 @@ -import { DataloadSectionType } from 'enum/dataload.enum' -import { FluidType } from 'enum/fluid.enum' +import { DataloadSectionType, FluidType } from 'enums' import { mount } from 'enzyme' import toJson from 'enzyme-to-json' import { Dataload } from 'models' @@ -7,19 +6,9 @@ import React from 'react' import { baseDataLoad, baseMultiFluidDataLoad, -} from '../../../tests/__mocks__/chartData.mock' +} from 'tests/__mocks__/chartData.mock' import DataloadSectionValue from './DataloadSectionValue' -jest.mock('cozy-ui/transpiled/react/I18n', () => { - return { - useI18n: jest.fn(() => { - return { - t: (str: string) => str, - } - }), - } -}) - const mockToggleEstimationModal = jest.fn() describe('DataloadSectionValue component', () => { @@ -116,7 +105,7 @@ describe('DataloadSectionValue component', () => { /> ) wrapper.find('.estimated').simulate('click') - expect(mockToggleEstimationModal).toBeCalled() + expect(mockToggleEstimationModal).toHaveBeenCalled() }) }) }) diff --git a/src/components/ConsumptionVisualizer/DataloadSectionValue.tsx b/src/components/ConsumptionVisualizer/DataloadSectionValue.tsx index 72ed67a78d4c991c0b00965ff0010ae6014464d8..649f993e2221af0e9a3aa7b5ae3a9f38e90fbf7a 100644 --- a/src/components/ConsumptionVisualizer/DataloadSectionValue.tsx +++ b/src/components/ConsumptionVisualizer/DataloadSectionValue.tsx @@ -1,6 +1,5 @@ import { useI18n } from 'cozy-ui/transpiled/react/I18n' -import { DataloadSectionType } from 'enum/dataload.enum' -import { FluidType } from 'enum/fluid.enum' +import { DataloadSectionType, FluidType } from 'enums' import { Dataload } from 'models' import React from 'react' import { formatNumberValues } from 'utils/utils' @@ -24,8 +23,8 @@ const DataloadSectionValue = ({ return ( <> {formatNumberValues(dataload.value)} - <span className={'text-18-normal euroUnit'}> - {`${t('FLUID.' + FluidType[fluidType] + '.UNIT')}`} + <span className="text-18-normal euroUnit"> + {t(`FLUID.${FluidType[fluidType]}.UNIT`)} </span> {dataloadSectionType === DataloadSectionType.NO_COMPARE && ( <span @@ -51,14 +50,14 @@ const DataloadSectionValue = ({ <> {formatNumberValues(dataload.value, FluidType[fluidType])} <span className="text-18-normal"> - {`${t('FLUID.' + FluidType[fluidType] + '.MEGAUNIT')}`} + {t(`FLUID.${FluidType[fluidType]}.MEGAUNIT`)} </span> </> ) : ( <> {formatNumberValues(dataload.value)} - <span className={'text-18-normal'}> - {`${t('FLUID.' + FluidType[fluidType] + '.UNIT')}`} + <span className="text-18-normal"> + {t(`FLUID.${FluidType[fluidType]}.UNIT`)} </span> </> )} diff --git a/src/components/ConsumptionVisualizer/EstimatedConsumptionModal.spec.tsx b/src/components/ConsumptionVisualizer/EstimatedConsumptionModal.spec.tsx index 789d44b5bfbe4deabde615a843b853362005a2e7..b7e0256198e84b91442a3e4a8a8a911d0c760cff 100644 --- a/src/components/ConsumptionVisualizer/EstimatedConsumptionModal.spec.tsx +++ b/src/components/ConsumptionVisualizer/EstimatedConsumptionModal.spec.tsx @@ -1,47 +1,20 @@ import { mount } from 'enzyme' import toJson from 'enzyme-to-json' import React from 'react' -import { Provider } from 'react-redux' -import configureStore from 'redux-mock-store' -import { mockInitialEcolyoState } from '../../../tests/__mocks__/store' -import { waitForComponentToPaint } from '../../../tests/__mocks__/testUtils' import EstimatedConsumptionModal from './EstimatedConsumptionModal' -jest.mock('cozy-ui/transpiled/react/I18n', () => { - return { - useI18n: jest.fn(() => { - return { - t: (str: string) => str, - } - }), - } -}) - const mockGetAllLastPrices = jest.fn() jest.mock('services/fluidsPrices.service', () => { - return jest.fn(() => { - return { - getAllLastPrices: mockGetAllLastPrices, - } - }) + return jest.fn(() => ({ + getAllLastPrices: mockGetAllLastPrices, + })) }) -const mockStore = configureStore([]) -const mockHandleClose = jest.fn() describe('EstimatedConsumptionModal component', () => { it('should render correctly', async () => { - const store = mockStore({ - ecolyo: mockInitialEcolyoState, - }) const wrapper = mount( - <Provider store={store}> - <EstimatedConsumptionModal - open={true} - handleCloseClick={mockHandleClose} - /> - </Provider> + <EstimatedConsumptionModal open={true} handleCloseClick={jest.fn()} /> ) - await waitForComponentToPaint(wrapper) expect(toJson(wrapper)).toMatchSnapshot() }) }) diff --git a/src/components/ConsumptionVisualizer/EstimatedConsumptionModal.tsx b/src/components/ConsumptionVisualizer/EstimatedConsumptionModal.tsx index 94a30953d04311e1a8ba23824bd07a3d2b718e28..a2dfa28b7ca4cf69670b7d9a251cce79fb29e23d 100644 --- a/src/components/ConsumptionVisualizer/EstimatedConsumptionModal.tsx +++ b/src/components/ConsumptionVisualizer/EstimatedConsumptionModal.tsx @@ -4,7 +4,7 @@ import CloseIcon from 'assets/icons/ico/close.svg' import { useClient } from 'cozy-client' import { useI18n } from 'cozy-ui/transpiled/react/I18n' import Icon from 'cozy-ui/transpiled/react/Icon' -import { FluidType } from 'enum/fluid.enum' +import { FluidType } from 'enums' import { DateTime } from 'luxon' import { FluidPrice } from 'models' import React, { useEffect, useState } from 'react' @@ -44,13 +44,13 @@ const EstimatedConsumptionModal = ({ <Dialog open={open} onClose={handleCloseClick} - aria-labelledby={'accessibility-title'} + aria-labelledby="accessibility-title" classes={{ root: 'modal-root', paper: 'modal-paper', }} > - <div id={'accessibility-title'}> + <div id="accessibility-title"> {t('consumption_visualizer.modal.window_title')} </div> <IconButton diff --git a/src/components/ConsumptionVisualizer/InfoDataConsumptionVisualizer.spec.tsx b/src/components/ConsumptionVisualizer/InfoDataConsumptionVisualizer.spec.tsx index 37aa7ad42b7580f173ff0c8d9ab26549e7184375..820c51c87f34f60aae8393d871386b55e919efca 100644 --- a/src/components/ConsumptionVisualizer/InfoDataConsumptionVisualizer.spec.tsx +++ b/src/components/ConsumptionVisualizer/InfoDataConsumptionVisualizer.spec.tsx @@ -1,28 +1,17 @@ -import { DataloadState } from 'enum/dataload.enum' -import { FluidType } from 'enum/fluid.enum' +import { DataloadState, FluidType } from 'enums' import { mount } from 'enzyme' import toJson from 'enzyme-to-json' import { DateTime } from 'luxon' import { Dataload } from 'models' import React from 'react' -import * as reactRedux from 'react-redux' import { Provider } from 'react-redux' -import { baseDataLoad } from '../../../tests/__mocks__/chartData.mock' -import { createMockEcolyoStore } from '../../../tests/__mocks__/store' +import * as storeHooks from 'store/hooks' +import { baseDataLoad } from 'tests/__mocks__/chartData.mock' +import { createMockEcolyoStore } from 'tests/__mocks__/store' import InfoDataConsumptionVisualizer from './InfoDataConsumptionVisualizer' import NoDataModal from './NoDataModal' -jest.mock('cozy-ui/transpiled/react/I18n', () => { - return { - useI18n: jest.fn(() => { - return { - t: (str: string) => str, - } - }), - } -}) - -const mockUseDispatch = jest.spyOn(reactRedux, 'useDispatch') +const mockAppDispatch = jest.spyOn(storeHooks, 'useAppDispatch') describe('InfoDataConsumptionVisualizer component', () => { const mockLastDataDate = DateTime.fromISO('2020-10-01T00:00:00.000Z', { @@ -31,9 +20,6 @@ describe('InfoDataConsumptionVisualizer component', () => { const mockDataload: Dataload = baseDataLoad const store = createMockEcolyoStore() - beforeEach(() => { - store.clearActions() - }) it('should render correctly when data valid', () => { const wrapper = mount( @@ -61,7 +47,7 @@ describe('InfoDataConsumptionVisualizer component', () => { </Provider> ) expect(wrapper.find('span').text()).toBe( - 'consumption_visualizer.last_available_data : 01/10/20' + 'consumption_visualizer.last_available_data' ) }) it('case state UPCOMING', () => { @@ -76,7 +62,7 @@ describe('InfoDataConsumptionVisualizer component', () => { </Provider> ) expect(wrapper.find('span').text()).toBe( - 'consumption_visualizer.last_available_data : 01/10/20' + 'consumption_visualizer.last_available_data' ) }) it('case state COMING', () => { @@ -94,7 +80,7 @@ describe('InfoDataConsumptionVisualizer component', () => { </Provider> ) expect(wrapper.find('span').text()).toBe( - 'consumption_visualizer.last_available_data : 01/10/20' + 'consumption_visualizer.last_available_data' ) }) it('case state AGGREGATED_HOLE_OR_MISSING', () => { @@ -112,7 +98,7 @@ describe('InfoDataConsumptionVisualizer component', () => { </Provider> ) expect(wrapper.find('span').text()).toBe( - 'consumption_visualizer.last_valid_data_multi : 01/10/20' + 'consumption_visualizer.last_valid_data_multi' ) }) it('case state AGGREGATED_WITH_HOLE_OR_MISSING', () => { @@ -130,7 +116,7 @@ describe('InfoDataConsumptionVisualizer component', () => { </Provider> ) expect(wrapper.find('span').text()).toBe( - 'consumption_visualizer.last_valid_data_multi : 01/10/20' + 'consumption_visualizer.last_valid_data_multi' ) }) it('case state AGGREGATED_COMING', () => { @@ -148,7 +134,7 @@ describe('InfoDataConsumptionVisualizer component', () => { </Provider> ) expect(wrapper.find('span').text()).toBe( - 'consumption_visualizer.last_valid_data_multi : 01/10/20' + 'consumption_visualizer.last_valid_data_multi' ) }) }) @@ -231,6 +217,6 @@ describe('InfoDataConsumptionVisualizer component', () => { </Provider> ) wrapper.find('.error-line').simulate('click') - expect(mockUseDispatch).toHaveBeenCalled() + expect(mockAppDispatch).toHaveBeenCalled() }) }) diff --git a/src/components/ConsumptionVisualizer/InfoDataConsumptionVisualizer.tsx b/src/components/ConsumptionVisualizer/InfoDataConsumptionVisualizer.tsx index 4ac3bd9668d0f33d1072d2af5031e31b66b670af..27968b8c50078c589e374fe34b5bea7fe07eb02d 100644 --- a/src/components/ConsumptionVisualizer/InfoDataConsumptionVisualizer.tsx +++ b/src/components/ConsumptionVisualizer/InfoDataConsumptionVisualizer.tsx @@ -1,13 +1,11 @@ import { useI18n } from 'cozy-ui/transpiled/react/I18n' -import { DataloadState } from 'enum/dataload.enum' -import { FluidType } from 'enum/fluid.enum' +import { DataloadState, FluidType } from 'enums' import { DateTime } from 'luxon' import { Dataload } from 'models' -import React, { Dispatch, useCallback, useState } from 'react' -import { useDispatch, useSelector } from 'react-redux' +import React, { useCallback, useState } from 'react' import DateChartService from 'services/dateChart.service' -import { AppActionsTypes, AppStore } from 'store' import { setCurrentIndex, setSelectedDate } from 'store/chart/chart.slice' +import { useAppDispatch, useAppSelector } from 'store/hooks' import NoDataModal from './NoDataModal' import './infoDataConsumptionVisualizer.scss' @@ -23,10 +21,8 @@ const InfoDataConsumptionVisualizer = ({ lastDataDate, }: InfoDataConsumptionVisualizerProps) => { const { t } = useI18n() - const dispatch = useDispatch<Dispatch<AppActionsTypes>>() - const { currentTimeStep } = useSelector( - (state: AppStore) => state.ecolyo.chart - ) + const dispatch = useAppDispatch() + const { currentTimeStep } = useAppSelector(state => state.ecolyo.chart) const [openNodataModal, setopenNodataModal] = useState<boolean>(false) const toggleNoDataModal = useCallback(() => { @@ -57,13 +53,17 @@ const InfoDataConsumptionVisualizer = ({ dataload.state === DataloadState.AGGREGATED_WITH_HOLE_OR_MISSING || dataload.state === DataloadState.AGGREGATED_COMING ) { + const lastDate = lastDataDate ? lastDataDate.toFormat("dd'/'MM'/'yy") : '-' return ( <div onClick={() => moveToDate()} className="error-line"> - <span className={`text-16-normal underlined-error`}> - {(fluidType === FluidType.MULTIFLUID - ? `${t('consumption_visualizer.last_valid_data_multi')}` - : `${t('consumption_visualizer.last_available_data')}`) + - ` : ${lastDataDate ? lastDataDate.toFormat("dd'/'MM'/'yy") : '-'}`} + <span className="text-16-bold underlined-error"> + {fluidType === FluidType.MULTIFLUID + ? t('consumption_visualizer.last_valid_data_multi', { + date: lastDate, + }) + : t('consumption_visualizer.last_available_data', { + date: lastDate, + })} </span> </div> ) @@ -77,7 +77,7 @@ const InfoDataConsumptionVisualizer = ({ return ( <> <div className="error-line" onClick={toggleNoDataModal}> - <span className={`text-16-normal underlined-error`}> + <span className="text-16-normal underlined-error"> {t('consumption_visualizer.why_no_data')} </span> </div> diff --git a/src/components/ConsumptionVisualizer/NoDataModal.spec.tsx b/src/components/ConsumptionVisualizer/NoDataModal.spec.tsx index 85e4f86bafbcd303ce130ab2784c3493fea55886..3f79b27a926a75fb72caf145534616e1c18385fb 100644 --- a/src/components/ConsumptionVisualizer/NoDataModal.spec.tsx +++ b/src/components/ConsumptionVisualizer/NoDataModal.spec.tsx @@ -1,35 +1,13 @@ import { mount } from 'enzyme' import toJson from 'enzyme-to-json' import React from 'react' -import { Provider } from 'react-redux' -import configureStore from 'redux-mock-store' -import { mockInitialEcolyoState } from '../../../tests/__mocks__/store' -import { waitForComponentToPaint } from '../../../tests/__mocks__/testUtils' import NoDataModal from './NoDataModal' -jest.mock('cozy-ui/transpiled/react/I18n', () => { - return { - useI18n: jest.fn(() => { - return { - t: (str: string) => str, - } - }), - } -}) - -const mockStore = configureStore([]) -const mockHandleClose = jest.fn() describe('NoDataModal component', () => { it('should render correctly', async () => { - const store = mockStore({ - ecolyo: mockInitialEcolyoState, - }) const wrapper = mount( - <Provider store={store}> - <NoDataModal open={true} handleCloseClick={mockHandleClose} /> - </Provider> + <NoDataModal open={true} handleCloseClick={jest.fn()} /> ) - await waitForComponentToPaint(wrapper) expect(toJson(wrapper)).toMatchSnapshot() }) }) diff --git a/src/components/ConsumptionVisualizer/NoDataModal.tsx b/src/components/ConsumptionVisualizer/NoDataModal.tsx index 98112d8f7eaa8dddd35673abbf820fe22e08b618..964bccfd787ee26252643056c3d339a3537f0884 100644 --- a/src/components/ConsumptionVisualizer/NoDataModal.tsx +++ b/src/components/ConsumptionVisualizer/NoDataModal.tsx @@ -19,13 +19,13 @@ const NoDataModal = ({ open, handleCloseClick }: NoDataModalProps) => { <Dialog open={open} onClose={handleCloseClick} - aria-labelledby={'accessibility-title'} + aria-labelledby="accessibility-title" classes={{ root: 'modal-root', paper: 'modal-paper', }} > - <div id={'accessibility-title'}> + <div id="accessibility-title"> {t('consumption_visualizer.modal.window_title')} </div> <IconButton @@ -46,22 +46,12 @@ const NoDataModal = ({ open, handleCloseClick }: NoDataModalProps) => { <div className="text-16-normal"> {t('consumption_visualizer.dataModal.list_title')} </div> - <div className="text-16-normal justified-text"> - <span>• </span> - {t('consumption_visualizer.dataModal.item1')} - </div> - <div className="text-16-normal justified-text"> - <span>• </span> - {t('consumption_visualizer.dataModal.item2')} - </div> - <div className="text-16-normal justified-text"> - <span>• </span> - {t('consumption_visualizer.dataModal.item3')} - </div> - <div className="text-16-normal justified-text"> - <span>• </span> - {t('consumption_visualizer.dataModal.item4')} - </div> + <ul> + <li>{t('consumption_visualizer.dataModal.item1')}</li> + <li>{t('consumption_visualizer.dataModal.item2')}</li> + <li>{t('consumption_visualizer.dataModal.item3')}</li> + <li>{t('consumption_visualizer.dataModal.item4')}</li> + </ul> <Button aria-label={t('ecogesture_info_modal.button_close')} onClick={handleCloseClick} diff --git a/src/components/ConsumptionVisualizer/__snapshots__/DataloadConsumptionVisualizer.spec.tsx.snap b/src/components/ConsumptionVisualizer/__snapshots__/DataloadConsumptionVisualizer.spec.tsx.snap index 3161ddaa1c875e273f2f2cd14cb21dea4af246e9..b4d99a41bedd42fec249565c4f81d93a3ba58130 100644 --- a/src/components/ConsumptionVisualizer/__snapshots__/DataloadConsumptionVisualizer.spec.tsx.snap +++ b/src/components/ConsumptionVisualizer/__snapshots__/DataloadConsumptionVisualizer.spec.tsx.snap @@ -100,378 +100,10 @@ exports[`Dataload consumption visualizer component should render with single flu </div> </DataloadSection> </div> - <EstimatedConsumptionModal + <mock-EstimatedConsumptionModal handleCloseClick={[Function]} open={false} - > - <WithStyles(ForwardRef(Dialog)) - aria-labelledby="accessibility-title" - classes={ - Object { - "paper": "modal-paper", - "root": "modal-root", - } - } - onClose={[Function]} - open={false} - > - <ForwardRef(Dialog) - aria-labelledby="accessibility-title" - classes={ - Object { - "container": "MuiDialog-container", - "paper": "MuiDialog-paper modal-paper", - "paperFullScreen": "MuiDialog-paperFullScreen", - "paperFullWidth": "MuiDialog-paperFullWidth", - "paperScrollBody": "MuiDialog-paperScrollBody", - "paperScrollPaper": "MuiDialog-paperScrollPaper", - "paperWidthFalse": "MuiDialog-paperWidthFalse", - "paperWidthLg": "MuiDialog-paperWidthLg", - "paperWidthMd": "MuiDialog-paperWidthMd", - "paperWidthSm": "MuiDialog-paperWidthSm", - "paperWidthXl": "MuiDialog-paperWidthXl", - "paperWidthXs": "MuiDialog-paperWidthXs", - "root": "MuiDialog-root modal-root", - "scrollBody": "MuiDialog-scrollBody", - "scrollPaper": "MuiDialog-scrollPaper", - } - } - onClose={[Function]} - open={false} - > - <ForwardRef(Modal) - BackdropComponent={ - Object { - "$$typeof": Symbol(react.forward_ref), - "Naked": Object { - "$$typeof": Symbol(react.forward_ref), - "propTypes": Object { - "children": [Function], - "className": [Function], - "classes": [Function], - "invisible": [Function], - "open": [Function], - "transitionDuration": [Function], - }, - "render": [Function], - }, - "displayName": "WithStyles(ForwardRef(Backdrop))", - "options": Object { - "defaultTheme": Object { - "breakpoints": Object { - "between": [Function], - "down": [Function], - "keys": Array [ - "xs", - "sm", - "md", - "lg", - "xl", - ], - "only": [Function], - "up": [Function], - "values": Object { - "lg": 1280, - "md": 960, - "sm": 600, - "xl": 1920, - "xs": 0, - }, - "width": [Function], - }, - "direction": "ltr", - "mixins": Object { - "gutters": [Function], - "toolbar": Object { - "@media (min-width:0px) and (orientation: landscape)": Object { - "minHeight": 48, - }, - "@media (min-width:600px)": Object { - "minHeight": 64, - }, - "minHeight": 56, - }, - }, - "overrides": Object {}, - "palette": Object { - "action": Object { - "activatedOpacity": 0.12, - "active": "rgba(0, 0, 0, 0.54)", - "disabled": "rgba(0, 0, 0, 0.26)", - "disabledBackground": "rgba(0, 0, 0, 0.12)", - "disabledOpacity": 0.38, - "focus": "rgba(0, 0, 0, 0.12)", - "focusOpacity": 0.12, - "hover": "rgba(0, 0, 0, 0.04)", - "hoverOpacity": 0.04, - "selected": "rgba(0, 0, 0, 0.08)", - "selectedOpacity": 0.08, - }, - "augmentColor": [Function], - "background": Object { - "default": "#fafafa", - "paper": "#fff", - }, - "common": Object { - "black": "#000", - "white": "#fff", - }, - "contrastThreshold": 3, - "divider": "rgba(0, 0, 0, 0.12)", - "error": Object { - "contrastText": "#fff", - "dark": "#d32f2f", - "light": "#e57373", - "main": "#f44336", - }, - "getContrastText": [Function], - "grey": Object { - "100": "#f5f5f5", - "200": "#eeeeee", - "300": "#e0e0e0", - "400": "#bdbdbd", - "50": "#fafafa", - "500": "#9e9e9e", - "600": "#757575", - "700": "#616161", - "800": "#424242", - "900": "#212121", - "A100": "#d5d5d5", - "A200": "#aaaaaa", - "A400": "#303030", - "A700": "#616161", - }, - "info": Object { - "contrastText": "#fff", - "dark": "#1976d2", - "light": "#64b5f6", - "main": "#2196f3", - }, - "primary": Object { - "contrastText": "#fff", - "dark": "#303f9f", - "light": "#7986cb", - "main": "#3f51b5", - }, - "secondary": Object { - "contrastText": "#fff", - "dark": "#c51162", - "light": "#ff4081", - "main": "#f50057", - }, - "success": Object { - "contrastText": "rgba(0, 0, 0, 0.87)", - "dark": "#388e3c", - "light": "#81c784", - "main": "#4caf50", - }, - "text": Object { - "disabled": "rgba(0, 0, 0, 0.38)", - "hint": "rgba(0, 0, 0, 0.38)", - "primary": "rgba(0, 0, 0, 0.87)", - "secondary": "rgba(0, 0, 0, 0.54)", - }, - "tonalOffset": 0.2, - "type": "light", - "warning": Object { - "contrastText": "rgba(0, 0, 0, 0.87)", - "dark": "#f57c00", - "light": "#ffb74d", - "main": "#ff9800", - }, - }, - "props": Object {}, - "shadows": Array [ - "none", - "0px 2px 1px -1px rgba(0,0,0,0.2),0px 1px 1px 0px rgba(0,0,0,0.14),0px 1px 3px 0px rgba(0,0,0,0.12)", - "0px 3px 1px -2px rgba(0,0,0,0.2),0px 2px 2px 0px rgba(0,0,0,0.14),0px 1px 5px 0px rgba(0,0,0,0.12)", - "0px 3px 3px -2px rgba(0,0,0,0.2),0px 3px 4px 0px rgba(0,0,0,0.14),0px 1px 8px 0px rgba(0,0,0,0.12)", - "0px 2px 4px -1px rgba(0,0,0,0.2),0px 4px 5px 0px rgba(0,0,0,0.14),0px 1px 10px 0px rgba(0,0,0,0.12)", - "0px 3px 5px -1px rgba(0,0,0,0.2),0px 5px 8px 0px rgba(0,0,0,0.14),0px 1px 14px 0px rgba(0,0,0,0.12)", - "0px 3px 5px -1px rgba(0,0,0,0.2),0px 6px 10px 0px rgba(0,0,0,0.14),0px 1px 18px 0px rgba(0,0,0,0.12)", - "0px 4px 5px -2px rgba(0,0,0,0.2),0px 7px 10px 1px rgba(0,0,0,0.14),0px 2px 16px 1px rgba(0,0,0,0.12)", - "0px 5px 5px -3px rgba(0,0,0,0.2),0px 8px 10px 1px rgba(0,0,0,0.14),0px 3px 14px 2px rgba(0,0,0,0.12)", - "0px 5px 6px -3px rgba(0,0,0,0.2),0px 9px 12px 1px rgba(0,0,0,0.14),0px 3px 16px 2px rgba(0,0,0,0.12)", - "0px 6px 6px -3px rgba(0,0,0,0.2),0px 10px 14px 1px rgba(0,0,0,0.14),0px 4px 18px 3px rgba(0,0,0,0.12)", - "0px 6px 7px -4px rgba(0,0,0,0.2),0px 11px 15px 1px rgba(0,0,0,0.14),0px 4px 20px 3px rgba(0,0,0,0.12)", - "0px 7px 8px -4px rgba(0,0,0,0.2),0px 12px 17px 2px rgba(0,0,0,0.14),0px 5px 22px 4px rgba(0,0,0,0.12)", - "0px 7px 8px -4px rgba(0,0,0,0.2),0px 13px 19px 2px rgba(0,0,0,0.14),0px 5px 24px 4px rgba(0,0,0,0.12)", - "0px 7px 9px -4px rgba(0,0,0,0.2),0px 14px 21px 2px rgba(0,0,0,0.14),0px 5px 26px 4px rgba(0,0,0,0.12)", - "0px 8px 9px -5px rgba(0,0,0,0.2),0px 15px 22px 2px rgba(0,0,0,0.14),0px 6px 28px 5px rgba(0,0,0,0.12)", - "0px 8px 10px -5px rgba(0,0,0,0.2),0px 16px 24px 2px rgba(0,0,0,0.14),0px 6px 30px 5px rgba(0,0,0,0.12)", - "0px 8px 11px -5px rgba(0,0,0,0.2),0px 17px 26px 2px rgba(0,0,0,0.14),0px 6px 32px 5px rgba(0,0,0,0.12)", - "0px 9px 11px -5px rgba(0,0,0,0.2),0px 18px 28px 2px rgba(0,0,0,0.14),0px 7px 34px 6px rgba(0,0,0,0.12)", - "0px 9px 12px -6px rgba(0,0,0,0.2),0px 19px 29px 2px rgba(0,0,0,0.14),0px 7px 36px 6px rgba(0,0,0,0.12)", - "0px 10px 13px -6px rgba(0,0,0,0.2),0px 20px 31px 3px rgba(0,0,0,0.14),0px 8px 38px 7px rgba(0,0,0,0.12)", - "0px 10px 13px -6px rgba(0,0,0,0.2),0px 21px 33px 3px rgba(0,0,0,0.14),0px 8px 40px 7px rgba(0,0,0,0.12)", - "0px 10px 14px -6px rgba(0,0,0,0.2),0px 22px 35px 3px rgba(0,0,0,0.14),0px 8px 42px 7px rgba(0,0,0,0.12)", - "0px 11px 14px -7px rgba(0,0,0,0.2),0px 23px 36px 3px rgba(0,0,0,0.14),0px 9px 44px 8px rgba(0,0,0,0.12)", - "0px 11px 15px -7px rgba(0,0,0,0.2),0px 24px 38px 3px rgba(0,0,0,0.14),0px 9px 46px 8px rgba(0,0,0,0.12)", - ], - "shape": Object { - "borderRadius": 4, - }, - "spacing": [Function], - "transitions": Object { - "create": [Function], - "duration": Object { - "complex": 375, - "enteringScreen": 225, - "leavingScreen": 195, - "short": 250, - "shorter": 200, - "shortest": 150, - "standard": 300, - }, - "easing": Object { - "easeIn": "cubic-bezier(0.4, 0, 1, 1)", - "easeInOut": "cubic-bezier(0.4, 0, 0.2, 1)", - "easeOut": "cubic-bezier(0.0, 0, 0.2, 1)", - "sharp": "cubic-bezier(0.4, 0, 0.6, 1)", - }, - "getAutoHeightDuration": [Function], - }, - "typography": Object { - "body1": Object { - "fontFamily": "\\"Roboto\\", \\"Helvetica\\", \\"Arial\\", sans-serif", - "fontSize": "1rem", - "fontWeight": 400, - "letterSpacing": "0.00938em", - "lineHeight": 1.5, - }, - "body2": Object { - "fontFamily": "\\"Roboto\\", \\"Helvetica\\", \\"Arial\\", sans-serif", - "fontSize": "0.875rem", - "fontWeight": 400, - "letterSpacing": "0.01071em", - "lineHeight": 1.43, - }, - "button": Object { - "fontFamily": "\\"Roboto\\", \\"Helvetica\\", \\"Arial\\", sans-serif", - "fontSize": "0.875rem", - "fontWeight": 500, - "letterSpacing": "0.02857em", - "lineHeight": 1.75, - "textTransform": "uppercase", - }, - "caption": Object { - "fontFamily": "\\"Roboto\\", \\"Helvetica\\", \\"Arial\\", sans-serif", - "fontSize": "0.75rem", - "fontWeight": 400, - "letterSpacing": "0.03333em", - "lineHeight": 1.66, - }, - "fontFamily": "\\"Roboto\\", \\"Helvetica\\", \\"Arial\\", sans-serif", - "fontSize": 14, - "fontWeightBold": 700, - "fontWeightLight": 300, - "fontWeightMedium": 500, - "fontWeightRegular": 400, - "h1": Object { - "fontFamily": "\\"Roboto\\", \\"Helvetica\\", \\"Arial\\", sans-serif", - "fontSize": "6rem", - "fontWeight": 300, - "letterSpacing": "-0.01562em", - "lineHeight": 1.167, - }, - "h2": Object { - "fontFamily": "\\"Roboto\\", \\"Helvetica\\", \\"Arial\\", sans-serif", - "fontSize": "3.75rem", - "fontWeight": 300, - "letterSpacing": "-0.00833em", - "lineHeight": 1.2, - }, - "h3": Object { - "fontFamily": "\\"Roboto\\", \\"Helvetica\\", \\"Arial\\", sans-serif", - "fontSize": "3rem", - "fontWeight": 400, - "letterSpacing": "0em", - "lineHeight": 1.167, - }, - "h4": Object { - "fontFamily": "\\"Roboto\\", \\"Helvetica\\", \\"Arial\\", sans-serif", - "fontSize": "2.125rem", - "fontWeight": 400, - "letterSpacing": "0.00735em", - "lineHeight": 1.235, - }, - "h5": Object { - "fontFamily": "\\"Roboto\\", \\"Helvetica\\", \\"Arial\\", sans-serif", - "fontSize": "1.5rem", - "fontWeight": 400, - "letterSpacing": "0em", - "lineHeight": 1.334, - }, - "h6": Object { - "fontFamily": "\\"Roboto\\", \\"Helvetica\\", \\"Arial\\", sans-serif", - "fontSize": "1.25rem", - "fontWeight": 500, - "letterSpacing": "0.0075em", - "lineHeight": 1.6, - }, - "htmlFontSize": 16, - "overline": Object { - "fontFamily": "\\"Roboto\\", \\"Helvetica\\", \\"Arial\\", sans-serif", - "fontSize": "0.75rem", - "fontWeight": 400, - "letterSpacing": "0.08333em", - "lineHeight": 2.66, - "textTransform": "uppercase", - }, - "pxToRem": [Function], - "round": [Function], - "subtitle1": Object { - "fontFamily": "\\"Roboto\\", \\"Helvetica\\", \\"Arial\\", sans-serif", - "fontSize": "1rem", - "fontWeight": 400, - "letterSpacing": "0.00938em", - "lineHeight": 1.75, - }, - "subtitle2": Object { - "fontFamily": "\\"Roboto\\", \\"Helvetica\\", \\"Arial\\", sans-serif", - "fontSize": "0.875rem", - "fontWeight": 500, - "letterSpacing": "0.00714em", - "lineHeight": 1.57, - }, - }, - "zIndex": Object { - "appBar": 1100, - "drawer": 1200, - "mobileStepper": 1000, - "modal": 1300, - "snackbar": 1400, - "speedDial": 1050, - "tooltip": 1500, - }, - }, - "name": "MuiBackdrop", - }, - "propTypes": Object { - "classes": [Function], - "innerRef": [Function], - }, - "render": [Function], - "useStyles": [Function], - } - } - BackdropProps={ - Object { - "transitionDuration": Object { - "enter": 225, - "exit": 195, - }, - } - } - className="MuiDialog-root modal-root" - closeAfterTransition={true} - disableEscapeKeyDown={false} - onClose={[Function]} - open={false} - /> - </ForwardRef(Dialog)> - </WithStyles(ForwardRef(Dialog))> - </EstimatedConsumptionModal> + /> </div> </DataloadConsumptionVisualizer> </Provider> diff --git a/src/components/ConsumptionVisualizer/__snapshots__/EstimatedConsumptionModal.spec.tsx.snap b/src/components/ConsumptionVisualizer/__snapshots__/EstimatedConsumptionModal.spec.tsx.snap index 3d48d7e5101088f20e3f7f903aae9b541f5261c7..c4aa35b596c03103bd7e812d7b7348f7b45778eb 100644 --- a/src/components/ConsumptionVisualizer/__snapshots__/EstimatedConsumptionModal.spec.tsx.snap +++ b/src/components/ConsumptionVisualizer/__snapshots__/EstimatedConsumptionModal.spec.tsx.snap @@ -1,525 +1,529 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP exports[`EstimatedConsumptionModal component should render correctly 1`] = ` -<Provider - store={ - Object { - "clearActions": [Function], - "dispatch": [Function], - "getActions": [Function], - "getState": [Function], - "replaceReducer": [Function], - "subscribe": [Function], - } - } +<EstimatedConsumptionModal + handleCloseClick={[MockFunction]} + open={true} > - <EstimatedConsumptionModal - handleCloseClick={[MockFunction]} + <WithStyles(ForwardRef(Dialog)) + aria-labelledby="accessibility-title" + classes={ + Object { + "paper": "modal-paper", + "root": "modal-root", + } + } + onClose={[MockFunction]} open={true} > - <WithStyles(ForwardRef(Dialog)) + <ForwardRef(Dialog) aria-labelledby="accessibility-title" classes={ Object { - "paper": "modal-paper", - "root": "modal-root", + "container": "MuiDialog-container", + "paper": "MuiDialog-paper modal-paper", + "paperFullScreen": "MuiDialog-paperFullScreen", + "paperFullWidth": "MuiDialog-paperFullWidth", + "paperScrollBody": "MuiDialog-paperScrollBody", + "paperScrollPaper": "MuiDialog-paperScrollPaper", + "paperWidthFalse": "MuiDialog-paperWidthFalse", + "paperWidthLg": "MuiDialog-paperWidthLg", + "paperWidthMd": "MuiDialog-paperWidthMd", + "paperWidthSm": "MuiDialog-paperWidthSm", + "paperWidthXl": "MuiDialog-paperWidthXl", + "paperWidthXs": "MuiDialog-paperWidthXs", + "root": "MuiDialog-root modal-root", + "scrollBody": "MuiDialog-scrollBody", + "scrollPaper": "MuiDialog-scrollPaper", } } onClose={[MockFunction]} open={true} > - <ForwardRef(Dialog) - aria-labelledby="accessibility-title" - classes={ + <ForwardRef(Modal) + BackdropComponent={ Object { - "container": "MuiDialog-container", - "paper": "MuiDialog-paper modal-paper", - "paperFullScreen": "MuiDialog-paperFullScreen", - "paperFullWidth": "MuiDialog-paperFullWidth", - "paperScrollBody": "MuiDialog-paperScrollBody", - "paperScrollPaper": "MuiDialog-paperScrollPaper", - "paperWidthFalse": "MuiDialog-paperWidthFalse", - "paperWidthLg": "MuiDialog-paperWidthLg", - "paperWidthMd": "MuiDialog-paperWidthMd", - "paperWidthSm": "MuiDialog-paperWidthSm", - "paperWidthXl": "MuiDialog-paperWidthXl", - "paperWidthXs": "MuiDialog-paperWidthXs", - "root": "MuiDialog-root modal-root", - "scrollBody": "MuiDialog-scrollBody", - "scrollPaper": "MuiDialog-scrollPaper", - } - } - onClose={[MockFunction]} - open={true} - > - <ForwardRef(Modal) - BackdropComponent={ - Object { + "$$typeof": Symbol(react.forward_ref), + "Naked": Object { "$$typeof": Symbol(react.forward_ref), - "Naked": Object { - "$$typeof": Symbol(react.forward_ref), - "propTypes": Object { - "children": [Function], - "className": [Function], - "classes": [Function], - "invisible": [Function], - "open": [Function], - "transitionDuration": [Function], - }, - "render": [Function], + "propTypes": Object { + "children": [Function], + "className": [Function], + "classes": [Function], + "invisible": [Function], + "open": [Function], + "transitionDuration": [Function], }, - "displayName": "WithStyles(ForwardRef(Backdrop))", - "options": Object { - "defaultTheme": Object { - "breakpoints": Object { - "between": [Function], - "down": [Function], - "keys": Array [ - "xs", - "sm", - "md", - "lg", - "xl", - ], - "only": [Function], - "up": [Function], - "values": Object { - "lg": 1280, - "md": 960, - "sm": 600, - "xl": 1920, - "xs": 0, - }, - "width": [Function], - }, - "direction": "ltr", - "mixins": Object { - "gutters": [Function], - "toolbar": Object { - "@media (min-width:0px) and (orientation: landscape)": Object { - "minHeight": 48, - }, - "@media (min-width:600px)": Object { - "minHeight": 64, - }, - "minHeight": 56, - }, + "render": [Function], + }, + "displayName": "WithStyles(ForwardRef(Backdrop))", + "options": Object { + "defaultTheme": Object { + "breakpoints": Object { + "between": [Function], + "down": [Function], + "keys": Array [ + "xs", + "sm", + "md", + "lg", + "xl", + ], + "only": [Function], + "up": [Function], + "values": Object { + "lg": 1280, + "md": 960, + "sm": 600, + "xl": 1920, + "xs": 0, }, - "overrides": Object {}, - "palette": Object { - "action": Object { - "activatedOpacity": 0.12, - "active": "rgba(0, 0, 0, 0.54)", - "disabled": "rgba(0, 0, 0, 0.26)", - "disabledBackground": "rgba(0, 0, 0, 0.12)", - "disabledOpacity": 0.38, - "focus": "rgba(0, 0, 0, 0.12)", - "focusOpacity": 0.12, - "hover": "rgba(0, 0, 0, 0.04)", - "hoverOpacity": 0.04, - "selected": "rgba(0, 0, 0, 0.08)", - "selectedOpacity": 0.08, - }, - "augmentColor": [Function], - "background": Object { - "default": "#fafafa", - "paper": "#fff", - }, - "common": Object { - "black": "#000", - "white": "#fff", - }, - "contrastThreshold": 3, - "divider": "rgba(0, 0, 0, 0.12)", - "error": Object { - "contrastText": "#fff", - "dark": "#d32f2f", - "light": "#e57373", - "main": "#f44336", - }, - "getContrastText": [Function], - "grey": Object { - "100": "#f5f5f5", - "200": "#eeeeee", - "300": "#e0e0e0", - "400": "#bdbdbd", - "50": "#fafafa", - "500": "#9e9e9e", - "600": "#757575", - "700": "#616161", - "800": "#424242", - "900": "#212121", - "A100": "#d5d5d5", - "A200": "#aaaaaa", - "A400": "#303030", - "A700": "#616161", - }, - "info": Object { - "contrastText": "#fff", - "dark": "#1976d2", - "light": "#64b5f6", - "main": "#2196f3", - }, - "primary": Object { - "contrastText": "#fff", - "dark": "#303f9f", - "light": "#7986cb", - "main": "#3f51b5", - }, - "secondary": Object { - "contrastText": "#fff", - "dark": "#c51162", - "light": "#ff4081", - "main": "#f50057", - }, - "success": Object { - "contrastText": "rgba(0, 0, 0, 0.87)", - "dark": "#388e3c", - "light": "#81c784", - "main": "#4caf50", - }, - "text": Object { - "disabled": "rgba(0, 0, 0, 0.38)", - "hint": "rgba(0, 0, 0, 0.38)", - "primary": "rgba(0, 0, 0, 0.87)", - "secondary": "rgba(0, 0, 0, 0.54)", + "width": [Function], + }, + "direction": "ltr", + "mixins": Object { + "gutters": [Function], + "toolbar": Object { + "@media (min-width:0px) and (orientation: landscape)": Object { + "minHeight": 48, }, - "tonalOffset": 0.2, - "type": "light", - "warning": Object { - "contrastText": "rgba(0, 0, 0, 0.87)", - "dark": "#f57c00", - "light": "#ffb74d", - "main": "#ff9800", + "@media (min-width:600px)": Object { + "minHeight": 64, }, + "minHeight": 56, }, - "props": Object {}, - "shadows": Array [ - "none", - "0px 2px 1px -1px rgba(0,0,0,0.2),0px 1px 1px 0px rgba(0,0,0,0.14),0px 1px 3px 0px rgba(0,0,0,0.12)", - "0px 3px 1px -2px rgba(0,0,0,0.2),0px 2px 2px 0px rgba(0,0,0,0.14),0px 1px 5px 0px rgba(0,0,0,0.12)", - "0px 3px 3px -2px rgba(0,0,0,0.2),0px 3px 4px 0px rgba(0,0,0,0.14),0px 1px 8px 0px rgba(0,0,0,0.12)", - "0px 2px 4px -1px rgba(0,0,0,0.2),0px 4px 5px 0px rgba(0,0,0,0.14),0px 1px 10px 0px rgba(0,0,0,0.12)", - "0px 3px 5px -1px rgba(0,0,0,0.2),0px 5px 8px 0px rgba(0,0,0,0.14),0px 1px 14px 0px rgba(0,0,0,0.12)", - "0px 3px 5px -1px rgba(0,0,0,0.2),0px 6px 10px 0px rgba(0,0,0,0.14),0px 1px 18px 0px rgba(0,0,0,0.12)", - "0px 4px 5px -2px rgba(0,0,0,0.2),0px 7px 10px 1px rgba(0,0,0,0.14),0px 2px 16px 1px rgba(0,0,0,0.12)", - "0px 5px 5px -3px rgba(0,0,0,0.2),0px 8px 10px 1px rgba(0,0,0,0.14),0px 3px 14px 2px rgba(0,0,0,0.12)", - "0px 5px 6px -3px rgba(0,0,0,0.2),0px 9px 12px 1px rgba(0,0,0,0.14),0px 3px 16px 2px rgba(0,0,0,0.12)", - "0px 6px 6px -3px rgba(0,0,0,0.2),0px 10px 14px 1px rgba(0,0,0,0.14),0px 4px 18px 3px rgba(0,0,0,0.12)", - "0px 6px 7px -4px rgba(0,0,0,0.2),0px 11px 15px 1px rgba(0,0,0,0.14),0px 4px 20px 3px rgba(0,0,0,0.12)", - "0px 7px 8px -4px rgba(0,0,0,0.2),0px 12px 17px 2px rgba(0,0,0,0.14),0px 5px 22px 4px rgba(0,0,0,0.12)", - "0px 7px 8px -4px rgba(0,0,0,0.2),0px 13px 19px 2px rgba(0,0,0,0.14),0px 5px 24px 4px rgba(0,0,0,0.12)", - "0px 7px 9px -4px rgba(0,0,0,0.2),0px 14px 21px 2px rgba(0,0,0,0.14),0px 5px 26px 4px rgba(0,0,0,0.12)", - "0px 8px 9px -5px rgba(0,0,0,0.2),0px 15px 22px 2px rgba(0,0,0,0.14),0px 6px 28px 5px rgba(0,0,0,0.12)", - "0px 8px 10px -5px rgba(0,0,0,0.2),0px 16px 24px 2px rgba(0,0,0,0.14),0px 6px 30px 5px rgba(0,0,0,0.12)", - "0px 8px 11px -5px rgba(0,0,0,0.2),0px 17px 26px 2px rgba(0,0,0,0.14),0px 6px 32px 5px rgba(0,0,0,0.12)", - "0px 9px 11px -5px rgba(0,0,0,0.2),0px 18px 28px 2px rgba(0,0,0,0.14),0px 7px 34px 6px rgba(0,0,0,0.12)", - "0px 9px 12px -6px rgba(0,0,0,0.2),0px 19px 29px 2px rgba(0,0,0,0.14),0px 7px 36px 6px rgba(0,0,0,0.12)", - "0px 10px 13px -6px rgba(0,0,0,0.2),0px 20px 31px 3px rgba(0,0,0,0.14),0px 8px 38px 7px rgba(0,0,0,0.12)", - "0px 10px 13px -6px rgba(0,0,0,0.2),0px 21px 33px 3px rgba(0,0,0,0.14),0px 8px 40px 7px rgba(0,0,0,0.12)", - "0px 10px 14px -6px rgba(0,0,0,0.2),0px 22px 35px 3px rgba(0,0,0,0.14),0px 8px 42px 7px rgba(0,0,0,0.12)", - "0px 11px 14px -7px rgba(0,0,0,0.2),0px 23px 36px 3px rgba(0,0,0,0.14),0px 9px 44px 8px rgba(0,0,0,0.12)", - "0px 11px 15px -7px rgba(0,0,0,0.2),0px 24px 38px 3px rgba(0,0,0,0.14),0px 9px 46px 8px rgba(0,0,0,0.12)", - ], - "shape": Object { - "borderRadius": 4, + }, + "overrides": Object {}, + "palette": Object { + "action": Object { + "activatedOpacity": 0.12, + "active": "rgba(0, 0, 0, 0.54)", + "disabled": "rgba(0, 0, 0, 0.26)", + "disabledBackground": "rgba(0, 0, 0, 0.12)", + "disabledOpacity": 0.38, + "focus": "rgba(0, 0, 0, 0.12)", + "focusOpacity": 0.12, + "hover": "rgba(0, 0, 0, 0.04)", + "hoverOpacity": 0.04, + "selected": "rgba(0, 0, 0, 0.08)", + "selectedOpacity": 0.08, }, - "spacing": [Function], - "transitions": Object { - "create": [Function], - "duration": Object { - "complex": 375, - "enteringScreen": 225, - "leavingScreen": 195, - "short": 250, - "shorter": 200, - "shortest": 150, - "standard": 300, - }, - "easing": Object { - "easeIn": "cubic-bezier(0.4, 0, 1, 1)", - "easeInOut": "cubic-bezier(0.4, 0, 0.2, 1)", - "easeOut": "cubic-bezier(0.0, 0, 0.2, 1)", - "sharp": "cubic-bezier(0.4, 0, 0.6, 1)", - }, - "getAutoHeightDuration": [Function], + "augmentColor": [Function], + "background": Object { + "default": "#fafafa", + "paper": "#fff", }, - "typography": Object { - "body1": Object { - "fontFamily": "\\"Roboto\\", \\"Helvetica\\", \\"Arial\\", sans-serif", - "fontSize": "1rem", - "fontWeight": 400, - "letterSpacing": "0.00938em", - "lineHeight": 1.5, - }, - "body2": Object { - "fontFamily": "\\"Roboto\\", \\"Helvetica\\", \\"Arial\\", sans-serif", - "fontSize": "0.875rem", - "fontWeight": 400, - "letterSpacing": "0.01071em", - "lineHeight": 1.43, - }, - "button": Object { - "fontFamily": "\\"Roboto\\", \\"Helvetica\\", \\"Arial\\", sans-serif", - "fontSize": "0.875rem", - "fontWeight": 500, - "letterSpacing": "0.02857em", - "lineHeight": 1.75, - "textTransform": "uppercase", - }, - "caption": Object { - "fontFamily": "\\"Roboto\\", \\"Helvetica\\", \\"Arial\\", sans-serif", - "fontSize": "0.75rem", - "fontWeight": 400, - "letterSpacing": "0.03333em", - "lineHeight": 1.66, - }, + "common": Object { + "black": "#000", + "white": "#fff", + }, + "contrastThreshold": 3, + "divider": "rgba(0, 0, 0, 0.12)", + "error": Object { + "contrastText": "#fff", + "dark": "#d32f2f", + "light": "#e57373", + "main": "#f44336", + }, + "getContrastText": [Function], + "grey": Object { + "100": "#f5f5f5", + "200": "#eeeeee", + "300": "#e0e0e0", + "400": "#bdbdbd", + "50": "#fafafa", + "500": "#9e9e9e", + "600": "#757575", + "700": "#616161", + "800": "#424242", + "900": "#212121", + "A100": "#d5d5d5", + "A200": "#aaaaaa", + "A400": "#303030", + "A700": "#616161", + }, + "info": Object { + "contrastText": "#fff", + "dark": "#1976d2", + "light": "#64b5f6", + "main": "#2196f3", + }, + "primary": Object { + "contrastText": "#fff", + "dark": "#303f9f", + "light": "#7986cb", + "main": "#3f51b5", + }, + "secondary": Object { + "contrastText": "#fff", + "dark": "#c51162", + "light": "#ff4081", + "main": "#f50057", + }, + "success": Object { + "contrastText": "rgba(0, 0, 0, 0.87)", + "dark": "#388e3c", + "light": "#81c784", + "main": "#4caf50", + }, + "text": Object { + "disabled": "rgba(0, 0, 0, 0.38)", + "hint": "rgba(0, 0, 0, 0.38)", + "primary": "rgba(0, 0, 0, 0.87)", + "secondary": "rgba(0, 0, 0, 0.54)", + }, + "tonalOffset": 0.2, + "type": "light", + "warning": Object { + "contrastText": "rgba(0, 0, 0, 0.87)", + "dark": "#f57c00", + "light": "#ffb74d", + "main": "#ff9800", + }, + }, + "props": Object {}, + "shadows": Array [ + "none", + "0px 2px 1px -1px rgba(0,0,0,0.2),0px 1px 1px 0px rgba(0,0,0,0.14),0px 1px 3px 0px rgba(0,0,0,0.12)", + "0px 3px 1px -2px rgba(0,0,0,0.2),0px 2px 2px 0px rgba(0,0,0,0.14),0px 1px 5px 0px rgba(0,0,0,0.12)", + "0px 3px 3px -2px rgba(0,0,0,0.2),0px 3px 4px 0px rgba(0,0,0,0.14),0px 1px 8px 0px rgba(0,0,0,0.12)", + "0px 2px 4px -1px rgba(0,0,0,0.2),0px 4px 5px 0px rgba(0,0,0,0.14),0px 1px 10px 0px rgba(0,0,0,0.12)", + "0px 3px 5px -1px rgba(0,0,0,0.2),0px 5px 8px 0px rgba(0,0,0,0.14),0px 1px 14px 0px rgba(0,0,0,0.12)", + "0px 3px 5px -1px rgba(0,0,0,0.2),0px 6px 10px 0px rgba(0,0,0,0.14),0px 1px 18px 0px rgba(0,0,0,0.12)", + "0px 4px 5px -2px rgba(0,0,0,0.2),0px 7px 10px 1px rgba(0,0,0,0.14),0px 2px 16px 1px rgba(0,0,0,0.12)", + "0px 5px 5px -3px rgba(0,0,0,0.2),0px 8px 10px 1px rgba(0,0,0,0.14),0px 3px 14px 2px rgba(0,0,0,0.12)", + "0px 5px 6px -3px rgba(0,0,0,0.2),0px 9px 12px 1px rgba(0,0,0,0.14),0px 3px 16px 2px rgba(0,0,0,0.12)", + "0px 6px 6px -3px rgba(0,0,0,0.2),0px 10px 14px 1px rgba(0,0,0,0.14),0px 4px 18px 3px rgba(0,0,0,0.12)", + "0px 6px 7px -4px rgba(0,0,0,0.2),0px 11px 15px 1px rgba(0,0,0,0.14),0px 4px 20px 3px rgba(0,0,0,0.12)", + "0px 7px 8px -4px rgba(0,0,0,0.2),0px 12px 17px 2px rgba(0,0,0,0.14),0px 5px 22px 4px rgba(0,0,0,0.12)", + "0px 7px 8px -4px rgba(0,0,0,0.2),0px 13px 19px 2px rgba(0,0,0,0.14),0px 5px 24px 4px rgba(0,0,0,0.12)", + "0px 7px 9px -4px rgba(0,0,0,0.2),0px 14px 21px 2px rgba(0,0,0,0.14),0px 5px 26px 4px rgba(0,0,0,0.12)", + "0px 8px 9px -5px rgba(0,0,0,0.2),0px 15px 22px 2px rgba(0,0,0,0.14),0px 6px 28px 5px rgba(0,0,0,0.12)", + "0px 8px 10px -5px rgba(0,0,0,0.2),0px 16px 24px 2px rgba(0,0,0,0.14),0px 6px 30px 5px rgba(0,0,0,0.12)", + "0px 8px 11px -5px rgba(0,0,0,0.2),0px 17px 26px 2px rgba(0,0,0,0.14),0px 6px 32px 5px rgba(0,0,0,0.12)", + "0px 9px 11px -5px rgba(0,0,0,0.2),0px 18px 28px 2px rgba(0,0,0,0.14),0px 7px 34px 6px rgba(0,0,0,0.12)", + "0px 9px 12px -6px rgba(0,0,0,0.2),0px 19px 29px 2px rgba(0,0,0,0.14),0px 7px 36px 6px rgba(0,0,0,0.12)", + "0px 10px 13px -6px rgba(0,0,0,0.2),0px 20px 31px 3px rgba(0,0,0,0.14),0px 8px 38px 7px rgba(0,0,0,0.12)", + "0px 10px 13px -6px rgba(0,0,0,0.2),0px 21px 33px 3px rgba(0,0,0,0.14),0px 8px 40px 7px rgba(0,0,0,0.12)", + "0px 10px 14px -6px rgba(0,0,0,0.2),0px 22px 35px 3px rgba(0,0,0,0.14),0px 8px 42px 7px rgba(0,0,0,0.12)", + "0px 11px 14px -7px rgba(0,0,0,0.2),0px 23px 36px 3px rgba(0,0,0,0.14),0px 9px 44px 8px rgba(0,0,0,0.12)", + "0px 11px 15px -7px rgba(0,0,0,0.2),0px 24px 38px 3px rgba(0,0,0,0.14),0px 9px 46px 8px rgba(0,0,0,0.12)", + ], + "shape": Object { + "borderRadius": 4, + }, + "spacing": [Function], + "transitions": Object { + "create": [Function], + "duration": Object { + "complex": 375, + "enteringScreen": 225, + "leavingScreen": 195, + "short": 250, + "shorter": 200, + "shortest": 150, + "standard": 300, + }, + "easing": Object { + "easeIn": "cubic-bezier(0.4, 0, 1, 1)", + "easeInOut": "cubic-bezier(0.4, 0, 0.2, 1)", + "easeOut": "cubic-bezier(0.0, 0, 0.2, 1)", + "sharp": "cubic-bezier(0.4, 0, 0.6, 1)", + }, + "getAutoHeightDuration": [Function], + }, + "typography": Object { + "body1": Object { "fontFamily": "\\"Roboto\\", \\"Helvetica\\", \\"Arial\\", sans-serif", - "fontSize": 14, - "fontWeightBold": 700, - "fontWeightLight": 300, - "fontWeightMedium": 500, - "fontWeightRegular": 400, - "h1": Object { - "fontFamily": "\\"Roboto\\", \\"Helvetica\\", \\"Arial\\", sans-serif", - "fontSize": "6rem", - "fontWeight": 300, - "letterSpacing": "-0.01562em", - "lineHeight": 1.167, - }, - "h2": Object { - "fontFamily": "\\"Roboto\\", \\"Helvetica\\", \\"Arial\\", sans-serif", - "fontSize": "3.75rem", - "fontWeight": 300, - "letterSpacing": "-0.00833em", - "lineHeight": 1.2, - }, - "h3": Object { - "fontFamily": "\\"Roboto\\", \\"Helvetica\\", \\"Arial\\", sans-serif", - "fontSize": "3rem", - "fontWeight": 400, - "letterSpacing": "0em", - "lineHeight": 1.167, - }, - "h4": Object { - "fontFamily": "\\"Roboto\\", \\"Helvetica\\", \\"Arial\\", sans-serif", - "fontSize": "2.125rem", - "fontWeight": 400, - "letterSpacing": "0.00735em", - "lineHeight": 1.235, - }, - "h5": Object { - "fontFamily": "\\"Roboto\\", \\"Helvetica\\", \\"Arial\\", sans-serif", - "fontSize": "1.5rem", - "fontWeight": 400, - "letterSpacing": "0em", - "lineHeight": 1.334, - }, - "h6": Object { - "fontFamily": "\\"Roboto\\", \\"Helvetica\\", \\"Arial\\", sans-serif", - "fontSize": "1.25rem", - "fontWeight": 500, - "letterSpacing": "0.0075em", - "lineHeight": 1.6, - }, - "htmlFontSize": 16, - "overline": Object { - "fontFamily": "\\"Roboto\\", \\"Helvetica\\", \\"Arial\\", sans-serif", - "fontSize": "0.75rem", - "fontWeight": 400, - "letterSpacing": "0.08333em", - "lineHeight": 2.66, - "textTransform": "uppercase", - }, - "pxToRem": [Function], - "round": [Function], - "subtitle1": Object { - "fontFamily": "\\"Roboto\\", \\"Helvetica\\", \\"Arial\\", sans-serif", - "fontSize": "1rem", - "fontWeight": 400, - "letterSpacing": "0.00938em", - "lineHeight": 1.75, - }, - "subtitle2": Object { - "fontFamily": "\\"Roboto\\", \\"Helvetica\\", \\"Arial\\", sans-serif", - "fontSize": "0.875rem", - "fontWeight": 500, - "letterSpacing": "0.00714em", - "lineHeight": 1.57, - }, + "fontSize": "1rem", + "fontWeight": 400, + "letterSpacing": "0.00938em", + "lineHeight": 1.5, + }, + "body2": Object { + "fontFamily": "\\"Roboto\\", \\"Helvetica\\", \\"Arial\\", sans-serif", + "fontSize": "0.875rem", + "fontWeight": 400, + "letterSpacing": "0.01071em", + "lineHeight": 1.43, + }, + "button": Object { + "fontFamily": "\\"Roboto\\", \\"Helvetica\\", \\"Arial\\", sans-serif", + "fontSize": "0.875rem", + "fontWeight": 500, + "letterSpacing": "0.02857em", + "lineHeight": 1.75, + "textTransform": "uppercase", + }, + "caption": Object { + "fontFamily": "\\"Roboto\\", \\"Helvetica\\", \\"Arial\\", sans-serif", + "fontSize": "0.75rem", + "fontWeight": 400, + "letterSpacing": "0.03333em", + "lineHeight": 1.66, + }, + "fontFamily": "\\"Roboto\\", \\"Helvetica\\", \\"Arial\\", sans-serif", + "fontSize": 14, + "fontWeightBold": 700, + "fontWeightLight": 300, + "fontWeightMedium": 500, + "fontWeightRegular": 400, + "h1": Object { + "fontFamily": "\\"Roboto\\", \\"Helvetica\\", \\"Arial\\", sans-serif", + "fontSize": "6rem", + "fontWeight": 300, + "letterSpacing": "-0.01562em", + "lineHeight": 1.167, + }, + "h2": Object { + "fontFamily": "\\"Roboto\\", \\"Helvetica\\", \\"Arial\\", sans-serif", + "fontSize": "3.75rem", + "fontWeight": 300, + "letterSpacing": "-0.00833em", + "lineHeight": 1.2, }, - "zIndex": Object { - "appBar": 1100, - "drawer": 1200, - "mobileStepper": 1000, - "modal": 1300, - "snackbar": 1400, - "speedDial": 1050, - "tooltip": 1500, + "h3": Object { + "fontFamily": "\\"Roboto\\", \\"Helvetica\\", \\"Arial\\", sans-serif", + "fontSize": "3rem", + "fontWeight": 400, + "letterSpacing": "0em", + "lineHeight": 1.167, + }, + "h4": Object { + "fontFamily": "\\"Roboto\\", \\"Helvetica\\", \\"Arial\\", sans-serif", + "fontSize": "2.125rem", + "fontWeight": 400, + "letterSpacing": "0.00735em", + "lineHeight": 1.235, + }, + "h5": Object { + "fontFamily": "\\"Roboto\\", \\"Helvetica\\", \\"Arial\\", sans-serif", + "fontSize": "1.5rem", + "fontWeight": 400, + "letterSpacing": "0em", + "lineHeight": 1.334, + }, + "h6": Object { + "fontFamily": "\\"Roboto\\", \\"Helvetica\\", \\"Arial\\", sans-serif", + "fontSize": "1.25rem", + "fontWeight": 500, + "letterSpacing": "0.0075em", + "lineHeight": 1.6, + }, + "htmlFontSize": 16, + "overline": Object { + "fontFamily": "\\"Roboto\\", \\"Helvetica\\", \\"Arial\\", sans-serif", + "fontSize": "0.75rem", + "fontWeight": 400, + "letterSpacing": "0.08333em", + "lineHeight": 2.66, + "textTransform": "uppercase", + }, + "pxToRem": [Function], + "round": [Function], + "subtitle1": Object { + "fontFamily": "\\"Roboto\\", \\"Helvetica\\", \\"Arial\\", sans-serif", + "fontSize": "1rem", + "fontWeight": 400, + "letterSpacing": "0.00938em", + "lineHeight": 1.75, + }, + "subtitle2": Object { + "fontFamily": "\\"Roboto\\", \\"Helvetica\\", \\"Arial\\", sans-serif", + "fontSize": "0.875rem", + "fontWeight": 500, + "letterSpacing": "0.00714em", + "lineHeight": 1.57, }, }, - "name": "MuiBackdrop", - }, - "propTypes": Object { - "classes": [Function], - "innerRef": [Function], + "zIndex": Object { + "appBar": 1100, + "drawer": 1200, + "mobileStepper": 1000, + "modal": 1300, + "snackbar": 1400, + "speedDial": 1050, + "tooltip": 1500, + }, }, - "render": [Function], - "useStyles": [Function], - } + "name": "MuiBackdrop", + }, + "propTypes": Object { + "classes": [Function], + "innerRef": [Function], + }, + "render": [Function], + "useStyles": [Function], } - BackdropProps={ - Object { - "transitionDuration": Object { - "enter": 225, - "exit": 195, - }, - } + } + BackdropProps={ + Object { + "transitionDuration": Object { + "enter": 225, + "exit": 195, + }, } - className="MuiDialog-root modal-root" - closeAfterTransition={true} - disableEscapeKeyDown={false} - onClose={[MockFunction]} - open={true} + } + className="MuiDialog-root modal-root" + closeAfterTransition={true} + disableEscapeKeyDown={false} + onClose={[MockFunction]} + open={true} + > + <ForwardRef(Portal) + disablePortal={false} > - <ForwardRef(Portal) - disablePortal={false} - > - <Portal - containerInfo={ - <body - style="padding-right: 0px; overflow: hidden;" + <Portal + containerInfo={ + <body + style="padding-right: 0px; overflow: hidden;" + > + <div + class="MuiDialog-root modal-root" + role="presentation" + style="position: fixed; z-index: 1300; right: 0px; bottom: 0px; top: 0px; left: 0px;" > <div - class="MuiDialog-root modal-root" - role="presentation" - style="position: fixed; z-index: 1300; right: 0px; bottom: 0px; top: 0px; left: 0px;" + aria-hidden="true" + class="MuiBackdrop-root" + style="opacity: 1; webkit-transition: opacity 225ms cubic-bezier(0.4, 0, 0.2, 1) 0ms; transition: opacity 225ms cubic-bezier(0.4, 0, 0.2, 1) 0ms;" + /> + <div + data-test="sentinelStart" + tabindex="0" + /> + <div + class="MuiDialog-container MuiDialog-scrollPaper" + role="none presentation" + style="opacity: 1; webkit-transition: opacity 225ms cubic-bezier(0.4, 0, 0.2, 1) 0ms; transition: opacity 225ms cubic-bezier(0.4, 0, 0.2, 1) 0ms;" + tabindex="-1" > <div - aria-hidden="true" - class="MuiBackdrop-root" - style="opacity: 1; webkit-transition: opacity 225ms cubic-bezier(0.4, 0, 0.2, 1) 0ms; transition: opacity 225ms cubic-bezier(0.4, 0, 0.2, 1) 0ms;" - /> - <div - data-test="sentinelStart" - tabindex="0" - /> - <div - class="MuiDialog-container MuiDialog-scrollPaper" - role="none presentation" - style="opacity: 1; webkit-transition: opacity 225ms cubic-bezier(0.4, 0, 0.2, 1) 0ms; transition: opacity 225ms cubic-bezier(0.4, 0, 0.2, 1) 0ms;" - tabindex="-1" + aria-labelledby="accessibility-title" + class="MuiPaper-root MuiDialog-paper modal-paper MuiDialog-paperScrollPaper MuiDialog-paperWidthSm MuiPaper-elevation24 MuiPaper-rounded" + role="dialog" > <div - aria-labelledby="accessibility-title" - class="MuiPaper-root MuiDialog-paper modal-paper MuiDialog-paperScrollPaper MuiDialog-paperWidthSm MuiPaper-elevation24 MuiPaper-rounded" - role="dialog" + id="accessibility-title" + > + consumption_visualizer.modal.window_title + </div> + <button + aria-label="consumption_visualizer.modal.close" + class="MuiButtonBase-root MuiIconButton-root modal-paper-close-button" + tabindex="0" + type="button" + > + <span + class="MuiIconButton-label" + > + <svg + class="styles__icon___23x3R" + height="16" + width="16" + > + <use + xlink:href="#test-file-stub" + /> + </svg> + </span> + <span + class="MuiTouchRipple-root" + /> + </button> + <div + class="estimation-modal" > <div - id="accessibility-title" + class="text-20-normal modal-title" > - consumption_visualizer.modal.window_title + consumption_visualizer.modal.title </div> - <button - aria-label="consumption_visualizer.modal.close" - class="MuiButtonBase-root MuiIconButton-root modal-paper-close-button" - tabindex="0" - type="button" + <div + class="text-16-normal" > - <span - class="MuiIconButton-label" - > - <svg - class="styles__icon___23x3R" - height="16" - width="16" + consumption_visualizer.modal.part1 + </div> + <br /> + <div + class="text-16-normal" + > + consumption_visualizer.modal.part2 + </div> + <ul> + <li> + <span + class="electricity" + > + FLUID.ELECTRICITY.LABEL + </span> + consumption_visualizer.modal.list1 + </li> + <li> + <span + class="water" + > + FLUID.WATER.LABEL + </span> + consumption_visualizer.modal.list3 + </li> + <li> + <span + class="gas" > - <use - xlink:href="#test-file-stub" - /> - </svg> - </span> - <span - class="MuiTouchRipple-root" - /> - </button> + FLUID.GAS.LABEL + </span> + consumption_visualizer.modal.list2 + </li> + </ul> <div - class="estimation-modal" + class="text-16-normal" > - <div - class="text-20-normal modal-title" - > - consumption_visualizer.modal.title - </div> - <div - class="text-16-normal" - > - consumption_visualizer.modal.part1 - </div> - <br /> - <div - class="text-16-normal" - > - consumption_visualizer.modal.part2 - </div> - <ul> - <li> - <span - class="electricity" - > - FLUID.ELECTRICITY.LABEL - </span> - consumption_visualizer.modal.list1 - </li> - <li> - <span - class="water" - > - FLUID.WATER.LABEL - </span> - consumption_visualizer.modal.list3 - </li> - <li> - <span - class="gas" - > - FLUID.GAS.LABEL - </span> - consumption_visualizer.modal.list2 - </li> - </ul> - <div - class="text-16-normal" - > - consumption_visualizer.modal.part3 - </div> + consumption_visualizer.modal.part3 </div> </div> </div> - <div - data-test="sentinelEnd" - tabindex="0" - /> </div> - </body> + <div + data-test="sentinelEnd" + tabindex="0" + /> + </div> + </body> + } + > + <div + className="MuiDialog-root modal-root" + onKeyDown={[Function]} + role="presentation" + style={ + Object { + "bottom": 0, + "left": 0, + "position": "fixed", + "right": 0, + "top": 0, + "zIndex": 1300, + } } > - <div - className="MuiDialog-root modal-root" - onKeyDown={[Function]} - role="presentation" - style={ + <WithStyles(ForwardRef(Backdrop)) + onClick={[Function]} + open={true} + transitionDuration={ Object { - "bottom": 0, - "left": 0, - "position": "fixed", - "right": 0, - "top": 0, - "zIndex": 1300, + "enter": 225, + "exit": 195, } } > - <WithStyles(ForwardRef(Backdrop)) + <ForwardRef(Backdrop) + classes={ + Object { + "invisible": "MuiBackdrop-invisible", + "root": "MuiBackdrop-root", + } + } onClick={[Function]} open={true} transitionDuration={ @@ -529,85 +533,90 @@ exports[`EstimatedConsumptionModal component should render correctly 1`] = ` } } > - <ForwardRef(Backdrop) - classes={ - Object { - "invisible": "MuiBackdrop-invisible", - "root": "MuiBackdrop-root", - } - } + <ForwardRef(Fade) + in={true} onClick={[Function]} - open={true} - transitionDuration={ + timeout={ Object { "enter": 225, "exit": 195, } } > - <ForwardRef(Fade) + <Transition + appear={true} + enter={true} + exit={true} in={true} + mountOnEnter={false} onClick={[Function]} + onEnter={[Function]} + onEntered={[Function]} + onEntering={[Function]} + onExit={[Function]} + onExited={[Function]} + onExiting={[Function]} timeout={ Object { "enter": 225, "exit": 195, } } + unmountOnExit={false} > - <Transition - appear={true} - enter={true} - exit={true} - in={true} - mountOnEnter={false} + <div + aria-hidden={true} + className="MuiBackdrop-root" onClick={[Function]} - onEnter={[Function]} - onEntered={[Function]} - onEntering={[Function]} - onExit={[Function]} - onExited={[Function]} - onExiting={[Function]} - timeout={ + style={ Object { - "enter": 225, - "exit": 195, + "opacity": 1, + "visibility": undefined, } } - unmountOnExit={false} - > - <div - aria-hidden={true} - className="MuiBackdrop-root" - onClick={[Function]} - style={ - Object { - "opacity": 1, - "visibility": undefined, - } - } - /> - </Transition> - </ForwardRef(Fade)> - </ForwardRef(Backdrop)> - </WithStyles(ForwardRef(Backdrop))> - <Unstable_TrapFocus - disableAutoFocus={false} - disableEnforceFocus={false} - disableRestoreFocus={false} - getDoc={[Function]} - isEnabled={[Function]} - open={true} + /> + </Transition> + </ForwardRef(Fade)> + </ForwardRef(Backdrop)> + </WithStyles(ForwardRef(Backdrop))> + <Unstable_TrapFocus + disableAutoFocus={false} + disableEnforceFocus={false} + disableRestoreFocus={false} + getDoc={[Function]} + isEnabled={[Function]} + open={true} + > + <div + data-test="sentinelStart" + tabIndex={0} + /> + <ForwardRef(Fade) + appear={true} + in={true} + onEnter={[Function]} + onExited={[Function]} + role="none presentation" + tabIndex="-1" + timeout={ + Object { + "enter": 225, + "exit": 195, + } + } > - <div - data-test="sentinelStart" - tabIndex={0} - /> - <ForwardRef(Fade) + <Transition appear={true} + enter={true} + exit={true} in={true} + mountOnEnter={false} onEnter={[Function]} + onEntered={[Function]} + onEntering={[Function]} + onExit={[Function]} onExited={[Function]} + onExiting={[Function]} role="none presentation" tabIndex="-1" timeout={ @@ -616,289 +625,267 @@ exports[`EstimatedConsumptionModal component should render correctly 1`] = ` "exit": 195, } } + unmountOnExit={false} > - <Transition - appear={true} - enter={true} - exit={true} - in={true} - mountOnEnter={false} - onEnter={[Function]} - onEntered={[Function]} - onEntering={[Function]} - onExit={[Function]} - onExited={[Function]} - onExiting={[Function]} + <div + className="MuiDialog-container MuiDialog-scrollPaper" + onMouseDown={[Function]} + onMouseUp={[Function]} role="none presentation" - tabIndex="-1" - timeout={ + style={ Object { - "enter": 225, - "exit": 195, + "opacity": 1, + "visibility": undefined, } } - unmountOnExit={false} + tabIndex="-1" > - <div - className="MuiDialog-container MuiDialog-scrollPaper" - onMouseDown={[Function]} - onMouseUp={[Function]} - role="none presentation" - style={ - Object { - "opacity": 1, - "visibility": undefined, - } - } - tabIndex="-1" + <WithStyles(ForwardRef(Paper)) + aria-labelledby="accessibility-title" + className="MuiDialog-paper modal-paper MuiDialog-paperScrollPaper MuiDialog-paperWidthSm" + elevation={24} + role="dialog" > - <WithStyles(ForwardRef(Paper)) + <ForwardRef(Paper) aria-labelledby="accessibility-title" className="MuiDialog-paper modal-paper MuiDialog-paperScrollPaper MuiDialog-paperWidthSm" + classes={ + Object { + "elevation0": "MuiPaper-elevation0", + "elevation1": "MuiPaper-elevation1", + "elevation10": "MuiPaper-elevation10", + "elevation11": "MuiPaper-elevation11", + "elevation12": "MuiPaper-elevation12", + "elevation13": "MuiPaper-elevation13", + "elevation14": "MuiPaper-elevation14", + "elevation15": "MuiPaper-elevation15", + "elevation16": "MuiPaper-elevation16", + "elevation17": "MuiPaper-elevation17", + "elevation18": "MuiPaper-elevation18", + "elevation19": "MuiPaper-elevation19", + "elevation2": "MuiPaper-elevation2", + "elevation20": "MuiPaper-elevation20", + "elevation21": "MuiPaper-elevation21", + "elevation22": "MuiPaper-elevation22", + "elevation23": "MuiPaper-elevation23", + "elevation24": "MuiPaper-elevation24", + "elevation3": "MuiPaper-elevation3", + "elevation4": "MuiPaper-elevation4", + "elevation5": "MuiPaper-elevation5", + "elevation6": "MuiPaper-elevation6", + "elevation7": "MuiPaper-elevation7", + "elevation8": "MuiPaper-elevation8", + "elevation9": "MuiPaper-elevation9", + "outlined": "MuiPaper-outlined", + "root": "MuiPaper-root", + "rounded": "MuiPaper-rounded", + } + } elevation={24} role="dialog" > - <ForwardRef(Paper) + <div aria-labelledby="accessibility-title" - className="MuiDialog-paper modal-paper MuiDialog-paperScrollPaper MuiDialog-paperWidthSm" - classes={ - Object { - "elevation0": "MuiPaper-elevation0", - "elevation1": "MuiPaper-elevation1", - "elevation10": "MuiPaper-elevation10", - "elevation11": "MuiPaper-elevation11", - "elevation12": "MuiPaper-elevation12", - "elevation13": "MuiPaper-elevation13", - "elevation14": "MuiPaper-elevation14", - "elevation15": "MuiPaper-elevation15", - "elevation16": "MuiPaper-elevation16", - "elevation17": "MuiPaper-elevation17", - "elevation18": "MuiPaper-elevation18", - "elevation19": "MuiPaper-elevation19", - "elevation2": "MuiPaper-elevation2", - "elevation20": "MuiPaper-elevation20", - "elevation21": "MuiPaper-elevation21", - "elevation22": "MuiPaper-elevation22", - "elevation23": "MuiPaper-elevation23", - "elevation24": "MuiPaper-elevation24", - "elevation3": "MuiPaper-elevation3", - "elevation4": "MuiPaper-elevation4", - "elevation5": "MuiPaper-elevation5", - "elevation6": "MuiPaper-elevation6", - "elevation7": "MuiPaper-elevation7", - "elevation8": "MuiPaper-elevation8", - "elevation9": "MuiPaper-elevation9", - "outlined": "MuiPaper-outlined", - "root": "MuiPaper-root", - "rounded": "MuiPaper-rounded", - } - } - elevation={24} + className="MuiPaper-root MuiDialog-paper modal-paper MuiDialog-paperScrollPaper MuiDialog-paperWidthSm MuiPaper-elevation24 MuiPaper-rounded" role="dialog" > <div - aria-labelledby="accessibility-title" - className="MuiPaper-root MuiDialog-paper modal-paper MuiDialog-paperScrollPaper MuiDialog-paperWidthSm MuiPaper-elevation24 MuiPaper-rounded" - role="dialog" + id="accessibility-title" > - <div - id="accessibility-title" - > - consumption_visualizer.modal.window_title - </div> - <WithStyles(ForwardRef(IconButton)) + consumption_visualizer.modal.window_title + </div> + <WithStyles(ForwardRef(IconButton)) + aria-label="consumption_visualizer.modal.close" + className="modal-paper-close-button" + onClick={[MockFunction]} + > + <ForwardRef(IconButton) aria-label="consumption_visualizer.modal.close" className="modal-paper-close-button" + classes={ + Object { + "colorInherit": "MuiIconButton-colorInherit", + "colorPrimary": "MuiIconButton-colorPrimary", + "colorSecondary": "MuiIconButton-colorSecondary", + "disabled": "Mui-disabled", + "edgeEnd": "MuiIconButton-edgeEnd", + "edgeStart": "MuiIconButton-edgeStart", + "label": "MuiIconButton-label", + "root": "MuiIconButton-root", + "sizeSmall": "MuiIconButton-sizeSmall", + } + } onClick={[MockFunction]} > - <ForwardRef(IconButton) + <WithStyles(ForwardRef(ButtonBase)) aria-label="consumption_visualizer.modal.close" - className="modal-paper-close-button" - classes={ - Object { - "colorInherit": "MuiIconButton-colorInherit", - "colorPrimary": "MuiIconButton-colorPrimary", - "colorSecondary": "MuiIconButton-colorSecondary", - "disabled": "Mui-disabled", - "edgeEnd": "MuiIconButton-edgeEnd", - "edgeStart": "MuiIconButton-edgeStart", - "label": "MuiIconButton-label", - "root": "MuiIconButton-root", - "sizeSmall": "MuiIconButton-sizeSmall", - } - } + centerRipple={true} + className="MuiIconButton-root modal-paper-close-button" + disabled={false} + focusRipple={true} onClick={[MockFunction]} > - <WithStyles(ForwardRef(ButtonBase)) + <ForwardRef(ButtonBase) aria-label="consumption_visualizer.modal.close" centerRipple={true} className="MuiIconButton-root modal-paper-close-button" + classes={ + Object { + "disabled": "Mui-disabled", + "focusVisible": "Mui-focusVisible", + "root": "MuiButtonBase-root", + } + } disabled={false} focusRipple={true} onClick={[MockFunction]} > - <ForwardRef(ButtonBase) + <button aria-label="consumption_visualizer.modal.close" - centerRipple={true} - className="MuiIconButton-root modal-paper-close-button" - classes={ - Object { - "disabled": "Mui-disabled", - "focusVisible": "Mui-focusVisible", - "root": "MuiButtonBase-root", - } - } + className="MuiButtonBase-root MuiIconButton-root modal-paper-close-button" disabled={false} - focusRipple={true} + onBlur={[Function]} onClick={[MockFunction]} + onDragLeave={[Function]} + onFocus={[Function]} + onKeyDown={[Function]} + onKeyUp={[Function]} + onMouseDown={[Function]} + onMouseLeave={[Function]} + onMouseUp={[Function]} + onTouchEnd={[Function]} + onTouchMove={[Function]} + onTouchStart={[Function]} + tabIndex={0} + type="button" > - <button - aria-label="consumption_visualizer.modal.close" - className="MuiButtonBase-root MuiIconButton-root modal-paper-close-button" - disabled={false} - onBlur={[Function]} - onClick={[MockFunction]} - onDragLeave={[Function]} - onFocus={[Function]} - onKeyDown={[Function]} - onKeyUp={[Function]} - onMouseDown={[Function]} - onMouseLeave={[Function]} - onMouseUp={[Function]} - onTouchEnd={[Function]} - onTouchMove={[Function]} - onTouchStart={[Function]} - tabIndex={0} - type="button" + <span + className="MuiIconButton-label" > - <span - className="MuiIconButton-label" + <Icon + icon="test-file-stub" + size={16} + spin={false} > - <Icon - icon="test-file-stub" - size={16} - spin={false} + <Component + className="styles__icon___23x3R" + height={16} + style={Object {}} + width={16} > - <Component + <svg className="styles__icon___23x3R" height={16} style={Object {}} width={16} > - <svg - className="styles__icon___23x3R" - height={16} - style={Object {}} - width={16} - > - <use - xlinkHref="#test-file-stub" - /> - </svg> - </Component> - </Icon> - </span> - <WithStyles(memo) + <use + xlinkHref="#test-file-stub" + /> + </svg> + </Component> + </Icon> + </span> + <WithStyles(memo) + center={true} + > + <ForwardRef(TouchRipple) center={true} - > - <ForwardRef(TouchRipple) - center={true} - classes={ - Object { - "child": "MuiTouchRipple-child", - "childLeaving": "MuiTouchRipple-childLeaving", - "childPulsate": "MuiTouchRipple-childPulsate", - "ripple": "MuiTouchRipple-ripple", - "ripplePulsate": "MuiTouchRipple-ripplePulsate", - "rippleVisible": "MuiTouchRipple-rippleVisible", - "root": "MuiTouchRipple-root", - } + classes={ + Object { + "child": "MuiTouchRipple-child", + "childLeaving": "MuiTouchRipple-childLeaving", + "childPulsate": "MuiTouchRipple-childPulsate", + "ripple": "MuiTouchRipple-ripple", + "ripplePulsate": "MuiTouchRipple-ripplePulsate", + "rippleVisible": "MuiTouchRipple-rippleVisible", + "root": "MuiTouchRipple-root", } + } + > + <span + className="MuiTouchRipple-root" > - <span - className="MuiTouchRipple-root" - > - <TransitionGroup - childFactory={[Function]} - component={null} - exit={true} - /> - </span> - </ForwardRef(TouchRipple)> - </WithStyles(memo)> - </button> - </ForwardRef(ButtonBase)> - </WithStyles(ForwardRef(ButtonBase))> - </ForwardRef(IconButton)> - </WithStyles(ForwardRef(IconButton))> + <TransitionGroup + childFactory={[Function]} + component={null} + exit={true} + /> + </span> + </ForwardRef(TouchRipple)> + </WithStyles(memo)> + </button> + </ForwardRef(ButtonBase)> + </WithStyles(ForwardRef(ButtonBase))> + </ForwardRef(IconButton)> + </WithStyles(ForwardRef(IconButton))> + <div + className="estimation-modal" + > <div - className="estimation-modal" + className="text-20-normal modal-title" > - <div - className="text-20-normal modal-title" - > - consumption_visualizer.modal.title - </div> - <div - className="text-16-normal" - > - consumption_visualizer.modal.part1 - </div> - <br /> - <div - className="text-16-normal" - > - consumption_visualizer.modal.part2 - </div> - <ul> - <li> - <span - className="electricity" - > - FLUID.ELECTRICITY.LABEL - </span> - consumption_visualizer.modal.list1 - </li> - <li> - <span - className="water" - > - FLUID.WATER.LABEL - </span> - consumption_visualizer.modal.list3 - </li> - <li> - <span - className="gas" - > - FLUID.GAS.LABEL - </span> - consumption_visualizer.modal.list2 - </li> - </ul> - <div - className="text-16-normal" - > - consumption_visualizer.modal.part3 - </div> + consumption_visualizer.modal.title + </div> + <div + className="text-16-normal" + > + consumption_visualizer.modal.part1 + </div> + <br /> + <div + className="text-16-normal" + > + consumption_visualizer.modal.part2 + </div> + <ul> + <li> + <span + className="electricity" + > + FLUID.ELECTRICITY.LABEL + </span> + consumption_visualizer.modal.list1 + </li> + <li> + <span + className="water" + > + FLUID.WATER.LABEL + </span> + consumption_visualizer.modal.list3 + </li> + <li> + <span + className="gas" + > + FLUID.GAS.LABEL + </span> + consumption_visualizer.modal.list2 + </li> + </ul> + <div + className="text-16-normal" + > + consumption_visualizer.modal.part3 </div> </div> - </ForwardRef(Paper)> - </WithStyles(ForwardRef(Paper))> - </div> - </Transition> - </ForwardRef(Fade)> - <div - data-test="sentinelEnd" - tabIndex={0} - /> - </Unstable_TrapFocus> - </div> - </Portal> - </ForwardRef(Portal)> - </ForwardRef(Modal)> - </ForwardRef(Dialog)> - </WithStyles(ForwardRef(Dialog))> - </EstimatedConsumptionModal> -</Provider> + </div> + </ForwardRef(Paper)> + </WithStyles(ForwardRef(Paper))> + </div> + </Transition> + </ForwardRef(Fade)> + <div + data-test="sentinelEnd" + tabIndex={0} + /> + </Unstable_TrapFocus> + </div> + </Portal> + </ForwardRef(Portal)> + </ForwardRef(Modal)> + </ForwardRef(Dialog)> + </WithStyles(ForwardRef(Dialog))> +</EstimatedConsumptionModal> `; diff --git a/src/components/ConsumptionVisualizer/__snapshots__/NoDataModal.spec.tsx.snap b/src/components/ConsumptionVisualizer/__snapshots__/NoDataModal.spec.tsx.snap index 5f65ba1f1858d93da1a1b0fcdd92f36235e358b1..e36ce72786e54b7fb820a9a8c2c1a126fefef6ae 100644 --- a/src/components/ConsumptionVisualizer/__snapshots__/NoDataModal.spec.tsx.snap +++ b/src/components/ConsumptionVisualizer/__snapshots__/NoDataModal.spec.tsx.snap @@ -1,548 +1,534 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP exports[`NoDataModal component should render correctly 1`] = ` -<Provider - store={ - Object { - "clearActions": [Function], - "dispatch": [Function], - "getActions": [Function], - "getState": [Function], - "replaceReducer": [Function], - "subscribe": [Function], - } - } +<NoDataModal + handleCloseClick={[MockFunction]} + open={true} > - <NoDataModal - handleCloseClick={[MockFunction]} + <WithStyles(ForwardRef(Dialog)) + aria-labelledby="accessibility-title" + classes={ + Object { + "paper": "modal-paper", + "root": "modal-root", + } + } + onClose={[MockFunction]} open={true} > - <WithStyles(ForwardRef(Dialog)) + <ForwardRef(Dialog) aria-labelledby="accessibility-title" classes={ Object { - "paper": "modal-paper", - "root": "modal-root", + "container": "MuiDialog-container", + "paper": "MuiDialog-paper modal-paper", + "paperFullScreen": "MuiDialog-paperFullScreen", + "paperFullWidth": "MuiDialog-paperFullWidth", + "paperScrollBody": "MuiDialog-paperScrollBody", + "paperScrollPaper": "MuiDialog-paperScrollPaper", + "paperWidthFalse": "MuiDialog-paperWidthFalse", + "paperWidthLg": "MuiDialog-paperWidthLg", + "paperWidthMd": "MuiDialog-paperWidthMd", + "paperWidthSm": "MuiDialog-paperWidthSm", + "paperWidthXl": "MuiDialog-paperWidthXl", + "paperWidthXs": "MuiDialog-paperWidthXs", + "root": "MuiDialog-root modal-root", + "scrollBody": "MuiDialog-scrollBody", + "scrollPaper": "MuiDialog-scrollPaper", } } onClose={[MockFunction]} open={true} > - <ForwardRef(Dialog) - aria-labelledby="accessibility-title" - classes={ + <ForwardRef(Modal) + BackdropComponent={ Object { - "container": "MuiDialog-container", - "paper": "MuiDialog-paper modal-paper", - "paperFullScreen": "MuiDialog-paperFullScreen", - "paperFullWidth": "MuiDialog-paperFullWidth", - "paperScrollBody": "MuiDialog-paperScrollBody", - "paperScrollPaper": "MuiDialog-paperScrollPaper", - "paperWidthFalse": "MuiDialog-paperWidthFalse", - "paperWidthLg": "MuiDialog-paperWidthLg", - "paperWidthMd": "MuiDialog-paperWidthMd", - "paperWidthSm": "MuiDialog-paperWidthSm", - "paperWidthXl": "MuiDialog-paperWidthXl", - "paperWidthXs": "MuiDialog-paperWidthXs", - "root": "MuiDialog-root modal-root", - "scrollBody": "MuiDialog-scrollBody", - "scrollPaper": "MuiDialog-scrollPaper", - } - } - onClose={[MockFunction]} - open={true} - > - <ForwardRef(Modal) - BackdropComponent={ - Object { + "$$typeof": Symbol(react.forward_ref), + "Naked": Object { "$$typeof": Symbol(react.forward_ref), - "Naked": Object { - "$$typeof": Symbol(react.forward_ref), - "propTypes": Object { - "children": [Function], - "className": [Function], - "classes": [Function], - "invisible": [Function], - "open": [Function], - "transitionDuration": [Function], - }, - "render": [Function], + "propTypes": Object { + "children": [Function], + "className": [Function], + "classes": [Function], + "invisible": [Function], + "open": [Function], + "transitionDuration": [Function], }, - "displayName": "WithStyles(ForwardRef(Backdrop))", - "options": Object { - "defaultTheme": Object { - "breakpoints": Object { - "between": [Function], - "down": [Function], - "keys": Array [ - "xs", - "sm", - "md", - "lg", - "xl", - ], - "only": [Function], - "up": [Function], - "values": Object { - "lg": 1280, - "md": 960, - "sm": 600, - "xl": 1920, - "xs": 0, - }, - "width": [Function], - }, - "direction": "ltr", - "mixins": Object { - "gutters": [Function], - "toolbar": Object { - "@media (min-width:0px) and (orientation: landscape)": Object { - "minHeight": 48, - }, - "@media (min-width:600px)": Object { - "minHeight": 64, - }, - "minHeight": 56, - }, + "render": [Function], + }, + "displayName": "WithStyles(ForwardRef(Backdrop))", + "options": Object { + "defaultTheme": Object { + "breakpoints": Object { + "between": [Function], + "down": [Function], + "keys": Array [ + "xs", + "sm", + "md", + "lg", + "xl", + ], + "only": [Function], + "up": [Function], + "values": Object { + "lg": 1280, + "md": 960, + "sm": 600, + "xl": 1920, + "xs": 0, }, - "overrides": Object {}, - "palette": Object { - "action": Object { - "activatedOpacity": 0.12, - "active": "rgba(0, 0, 0, 0.54)", - "disabled": "rgba(0, 0, 0, 0.26)", - "disabledBackground": "rgba(0, 0, 0, 0.12)", - "disabledOpacity": 0.38, - "focus": "rgba(0, 0, 0, 0.12)", - "focusOpacity": 0.12, - "hover": "rgba(0, 0, 0, 0.04)", - "hoverOpacity": 0.04, - "selected": "rgba(0, 0, 0, 0.08)", - "selectedOpacity": 0.08, - }, - "augmentColor": [Function], - "background": Object { - "default": "#fafafa", - "paper": "#fff", - }, - "common": Object { - "black": "#000", - "white": "#fff", - }, - "contrastThreshold": 3, - "divider": "rgba(0, 0, 0, 0.12)", - "error": Object { - "contrastText": "#fff", - "dark": "#d32f2f", - "light": "#e57373", - "main": "#f44336", - }, - "getContrastText": [Function], - "grey": Object { - "100": "#f5f5f5", - "200": "#eeeeee", - "300": "#e0e0e0", - "400": "#bdbdbd", - "50": "#fafafa", - "500": "#9e9e9e", - "600": "#757575", - "700": "#616161", - "800": "#424242", - "900": "#212121", - "A100": "#d5d5d5", - "A200": "#aaaaaa", - "A400": "#303030", - "A700": "#616161", - }, - "info": Object { - "contrastText": "#fff", - "dark": "#1976d2", - "light": "#64b5f6", - "main": "#2196f3", - }, - "primary": Object { - "contrastText": "#fff", - "dark": "#303f9f", - "light": "#7986cb", - "main": "#3f51b5", - }, - "secondary": Object { - "contrastText": "#fff", - "dark": "#c51162", - "light": "#ff4081", - "main": "#f50057", - }, - "success": Object { - "contrastText": "rgba(0, 0, 0, 0.87)", - "dark": "#388e3c", - "light": "#81c784", - "main": "#4caf50", - }, - "text": Object { - "disabled": "rgba(0, 0, 0, 0.38)", - "hint": "rgba(0, 0, 0, 0.38)", - "primary": "rgba(0, 0, 0, 0.87)", - "secondary": "rgba(0, 0, 0, 0.54)", + "width": [Function], + }, + "direction": "ltr", + "mixins": Object { + "gutters": [Function], + "toolbar": Object { + "@media (min-width:0px) and (orientation: landscape)": Object { + "minHeight": 48, }, - "tonalOffset": 0.2, - "type": "light", - "warning": Object { - "contrastText": "rgba(0, 0, 0, 0.87)", - "dark": "#f57c00", - "light": "#ffb74d", - "main": "#ff9800", + "@media (min-width:600px)": Object { + "minHeight": 64, }, + "minHeight": 56, }, - "props": Object {}, - "shadows": Array [ - "none", - "0px 2px 1px -1px rgba(0,0,0,0.2),0px 1px 1px 0px rgba(0,0,0,0.14),0px 1px 3px 0px rgba(0,0,0,0.12)", - "0px 3px 1px -2px rgba(0,0,0,0.2),0px 2px 2px 0px rgba(0,0,0,0.14),0px 1px 5px 0px rgba(0,0,0,0.12)", - "0px 3px 3px -2px rgba(0,0,0,0.2),0px 3px 4px 0px rgba(0,0,0,0.14),0px 1px 8px 0px rgba(0,0,0,0.12)", - "0px 2px 4px -1px rgba(0,0,0,0.2),0px 4px 5px 0px rgba(0,0,0,0.14),0px 1px 10px 0px rgba(0,0,0,0.12)", - "0px 3px 5px -1px rgba(0,0,0,0.2),0px 5px 8px 0px rgba(0,0,0,0.14),0px 1px 14px 0px rgba(0,0,0,0.12)", - "0px 3px 5px -1px rgba(0,0,0,0.2),0px 6px 10px 0px rgba(0,0,0,0.14),0px 1px 18px 0px rgba(0,0,0,0.12)", - "0px 4px 5px -2px rgba(0,0,0,0.2),0px 7px 10px 1px rgba(0,0,0,0.14),0px 2px 16px 1px rgba(0,0,0,0.12)", - "0px 5px 5px -3px rgba(0,0,0,0.2),0px 8px 10px 1px rgba(0,0,0,0.14),0px 3px 14px 2px rgba(0,0,0,0.12)", - "0px 5px 6px -3px rgba(0,0,0,0.2),0px 9px 12px 1px rgba(0,0,0,0.14),0px 3px 16px 2px rgba(0,0,0,0.12)", - "0px 6px 6px -3px rgba(0,0,0,0.2),0px 10px 14px 1px rgba(0,0,0,0.14),0px 4px 18px 3px rgba(0,0,0,0.12)", - "0px 6px 7px -4px rgba(0,0,0,0.2),0px 11px 15px 1px rgba(0,0,0,0.14),0px 4px 20px 3px rgba(0,0,0,0.12)", - "0px 7px 8px -4px rgba(0,0,0,0.2),0px 12px 17px 2px rgba(0,0,0,0.14),0px 5px 22px 4px rgba(0,0,0,0.12)", - "0px 7px 8px -4px rgba(0,0,0,0.2),0px 13px 19px 2px rgba(0,0,0,0.14),0px 5px 24px 4px rgba(0,0,0,0.12)", - "0px 7px 9px -4px rgba(0,0,0,0.2),0px 14px 21px 2px rgba(0,0,0,0.14),0px 5px 26px 4px rgba(0,0,0,0.12)", - "0px 8px 9px -5px rgba(0,0,0,0.2),0px 15px 22px 2px rgba(0,0,0,0.14),0px 6px 28px 5px rgba(0,0,0,0.12)", - "0px 8px 10px -5px rgba(0,0,0,0.2),0px 16px 24px 2px rgba(0,0,0,0.14),0px 6px 30px 5px rgba(0,0,0,0.12)", - "0px 8px 11px -5px rgba(0,0,0,0.2),0px 17px 26px 2px rgba(0,0,0,0.14),0px 6px 32px 5px rgba(0,0,0,0.12)", - "0px 9px 11px -5px rgba(0,0,0,0.2),0px 18px 28px 2px rgba(0,0,0,0.14),0px 7px 34px 6px rgba(0,0,0,0.12)", - "0px 9px 12px -6px rgba(0,0,0,0.2),0px 19px 29px 2px rgba(0,0,0,0.14),0px 7px 36px 6px rgba(0,0,0,0.12)", - "0px 10px 13px -6px rgba(0,0,0,0.2),0px 20px 31px 3px rgba(0,0,0,0.14),0px 8px 38px 7px rgba(0,0,0,0.12)", - "0px 10px 13px -6px rgba(0,0,0,0.2),0px 21px 33px 3px rgba(0,0,0,0.14),0px 8px 40px 7px rgba(0,0,0,0.12)", - "0px 10px 14px -6px rgba(0,0,0,0.2),0px 22px 35px 3px rgba(0,0,0,0.14),0px 8px 42px 7px rgba(0,0,0,0.12)", - "0px 11px 14px -7px rgba(0,0,0,0.2),0px 23px 36px 3px rgba(0,0,0,0.14),0px 9px 44px 8px rgba(0,0,0,0.12)", - "0px 11px 15px -7px rgba(0,0,0,0.2),0px 24px 38px 3px rgba(0,0,0,0.14),0px 9px 46px 8px rgba(0,0,0,0.12)", - ], - "shape": Object { - "borderRadius": 4, + }, + "overrides": Object {}, + "palette": Object { + "action": Object { + "activatedOpacity": 0.12, + "active": "rgba(0, 0, 0, 0.54)", + "disabled": "rgba(0, 0, 0, 0.26)", + "disabledBackground": "rgba(0, 0, 0, 0.12)", + "disabledOpacity": 0.38, + "focus": "rgba(0, 0, 0, 0.12)", + "focusOpacity": 0.12, + "hover": "rgba(0, 0, 0, 0.04)", + "hoverOpacity": 0.04, + "selected": "rgba(0, 0, 0, 0.08)", + "selectedOpacity": 0.08, }, - "spacing": [Function], - "transitions": Object { - "create": [Function], - "duration": Object { - "complex": 375, - "enteringScreen": 225, - "leavingScreen": 195, - "short": 250, - "shorter": 200, - "shortest": 150, - "standard": 300, - }, - "easing": Object { - "easeIn": "cubic-bezier(0.4, 0, 1, 1)", - "easeInOut": "cubic-bezier(0.4, 0, 0.2, 1)", - "easeOut": "cubic-bezier(0.0, 0, 0.2, 1)", - "sharp": "cubic-bezier(0.4, 0, 0.6, 1)", - }, - "getAutoHeightDuration": [Function], + "augmentColor": [Function], + "background": Object { + "default": "#fafafa", + "paper": "#fff", }, - "typography": Object { - "body1": Object { - "fontFamily": "\\"Roboto\\", \\"Helvetica\\", \\"Arial\\", sans-serif", - "fontSize": "1rem", - "fontWeight": 400, - "letterSpacing": "0.00938em", - "lineHeight": 1.5, - }, - "body2": Object { - "fontFamily": "\\"Roboto\\", \\"Helvetica\\", \\"Arial\\", sans-serif", - "fontSize": "0.875rem", - "fontWeight": 400, - "letterSpacing": "0.01071em", - "lineHeight": 1.43, - }, - "button": Object { - "fontFamily": "\\"Roboto\\", \\"Helvetica\\", \\"Arial\\", sans-serif", - "fontSize": "0.875rem", - "fontWeight": 500, - "letterSpacing": "0.02857em", - "lineHeight": 1.75, - "textTransform": "uppercase", - }, - "caption": Object { - "fontFamily": "\\"Roboto\\", \\"Helvetica\\", \\"Arial\\", sans-serif", - "fontSize": "0.75rem", - "fontWeight": 400, - "letterSpacing": "0.03333em", - "lineHeight": 1.66, - }, + "common": Object { + "black": "#000", + "white": "#fff", + }, + "contrastThreshold": 3, + "divider": "rgba(0, 0, 0, 0.12)", + "error": Object { + "contrastText": "#fff", + "dark": "#d32f2f", + "light": "#e57373", + "main": "#f44336", + }, + "getContrastText": [Function], + "grey": Object { + "100": "#f5f5f5", + "200": "#eeeeee", + "300": "#e0e0e0", + "400": "#bdbdbd", + "50": "#fafafa", + "500": "#9e9e9e", + "600": "#757575", + "700": "#616161", + "800": "#424242", + "900": "#212121", + "A100": "#d5d5d5", + "A200": "#aaaaaa", + "A400": "#303030", + "A700": "#616161", + }, + "info": Object { + "contrastText": "#fff", + "dark": "#1976d2", + "light": "#64b5f6", + "main": "#2196f3", + }, + "primary": Object { + "contrastText": "#fff", + "dark": "#303f9f", + "light": "#7986cb", + "main": "#3f51b5", + }, + "secondary": Object { + "contrastText": "#fff", + "dark": "#c51162", + "light": "#ff4081", + "main": "#f50057", + }, + "success": Object { + "contrastText": "rgba(0, 0, 0, 0.87)", + "dark": "#388e3c", + "light": "#81c784", + "main": "#4caf50", + }, + "text": Object { + "disabled": "rgba(0, 0, 0, 0.38)", + "hint": "rgba(0, 0, 0, 0.38)", + "primary": "rgba(0, 0, 0, 0.87)", + "secondary": "rgba(0, 0, 0, 0.54)", + }, + "tonalOffset": 0.2, + "type": "light", + "warning": Object { + "contrastText": "rgba(0, 0, 0, 0.87)", + "dark": "#f57c00", + "light": "#ffb74d", + "main": "#ff9800", + }, + }, + "props": Object {}, + "shadows": Array [ + "none", + "0px 2px 1px -1px rgba(0,0,0,0.2),0px 1px 1px 0px rgba(0,0,0,0.14),0px 1px 3px 0px rgba(0,0,0,0.12)", + "0px 3px 1px -2px rgba(0,0,0,0.2),0px 2px 2px 0px rgba(0,0,0,0.14),0px 1px 5px 0px rgba(0,0,0,0.12)", + "0px 3px 3px -2px rgba(0,0,0,0.2),0px 3px 4px 0px rgba(0,0,0,0.14),0px 1px 8px 0px rgba(0,0,0,0.12)", + "0px 2px 4px -1px rgba(0,0,0,0.2),0px 4px 5px 0px rgba(0,0,0,0.14),0px 1px 10px 0px rgba(0,0,0,0.12)", + "0px 3px 5px -1px rgba(0,0,0,0.2),0px 5px 8px 0px rgba(0,0,0,0.14),0px 1px 14px 0px rgba(0,0,0,0.12)", + "0px 3px 5px -1px rgba(0,0,0,0.2),0px 6px 10px 0px rgba(0,0,0,0.14),0px 1px 18px 0px rgba(0,0,0,0.12)", + "0px 4px 5px -2px rgba(0,0,0,0.2),0px 7px 10px 1px rgba(0,0,0,0.14),0px 2px 16px 1px rgba(0,0,0,0.12)", + "0px 5px 5px -3px rgba(0,0,0,0.2),0px 8px 10px 1px rgba(0,0,0,0.14),0px 3px 14px 2px rgba(0,0,0,0.12)", + "0px 5px 6px -3px rgba(0,0,0,0.2),0px 9px 12px 1px rgba(0,0,0,0.14),0px 3px 16px 2px rgba(0,0,0,0.12)", + "0px 6px 6px -3px rgba(0,0,0,0.2),0px 10px 14px 1px rgba(0,0,0,0.14),0px 4px 18px 3px rgba(0,0,0,0.12)", + "0px 6px 7px -4px rgba(0,0,0,0.2),0px 11px 15px 1px rgba(0,0,0,0.14),0px 4px 20px 3px rgba(0,0,0,0.12)", + "0px 7px 8px -4px rgba(0,0,0,0.2),0px 12px 17px 2px rgba(0,0,0,0.14),0px 5px 22px 4px rgba(0,0,0,0.12)", + "0px 7px 8px -4px rgba(0,0,0,0.2),0px 13px 19px 2px rgba(0,0,0,0.14),0px 5px 24px 4px rgba(0,0,0,0.12)", + "0px 7px 9px -4px rgba(0,0,0,0.2),0px 14px 21px 2px rgba(0,0,0,0.14),0px 5px 26px 4px rgba(0,0,0,0.12)", + "0px 8px 9px -5px rgba(0,0,0,0.2),0px 15px 22px 2px rgba(0,0,0,0.14),0px 6px 28px 5px rgba(0,0,0,0.12)", + "0px 8px 10px -5px rgba(0,0,0,0.2),0px 16px 24px 2px rgba(0,0,0,0.14),0px 6px 30px 5px rgba(0,0,0,0.12)", + "0px 8px 11px -5px rgba(0,0,0,0.2),0px 17px 26px 2px rgba(0,0,0,0.14),0px 6px 32px 5px rgba(0,0,0,0.12)", + "0px 9px 11px -5px rgba(0,0,0,0.2),0px 18px 28px 2px rgba(0,0,0,0.14),0px 7px 34px 6px rgba(0,0,0,0.12)", + "0px 9px 12px -6px rgba(0,0,0,0.2),0px 19px 29px 2px rgba(0,0,0,0.14),0px 7px 36px 6px rgba(0,0,0,0.12)", + "0px 10px 13px -6px rgba(0,0,0,0.2),0px 20px 31px 3px rgba(0,0,0,0.14),0px 8px 38px 7px rgba(0,0,0,0.12)", + "0px 10px 13px -6px rgba(0,0,0,0.2),0px 21px 33px 3px rgba(0,0,0,0.14),0px 8px 40px 7px rgba(0,0,0,0.12)", + "0px 10px 14px -6px rgba(0,0,0,0.2),0px 22px 35px 3px rgba(0,0,0,0.14),0px 8px 42px 7px rgba(0,0,0,0.12)", + "0px 11px 14px -7px rgba(0,0,0,0.2),0px 23px 36px 3px rgba(0,0,0,0.14),0px 9px 44px 8px rgba(0,0,0,0.12)", + "0px 11px 15px -7px rgba(0,0,0,0.2),0px 24px 38px 3px rgba(0,0,0,0.14),0px 9px 46px 8px rgba(0,0,0,0.12)", + ], + "shape": Object { + "borderRadius": 4, + }, + "spacing": [Function], + "transitions": Object { + "create": [Function], + "duration": Object { + "complex": 375, + "enteringScreen": 225, + "leavingScreen": 195, + "short": 250, + "shorter": 200, + "shortest": 150, + "standard": 300, + }, + "easing": Object { + "easeIn": "cubic-bezier(0.4, 0, 1, 1)", + "easeInOut": "cubic-bezier(0.4, 0, 0.2, 1)", + "easeOut": "cubic-bezier(0.0, 0, 0.2, 1)", + "sharp": "cubic-bezier(0.4, 0, 0.6, 1)", + }, + "getAutoHeightDuration": [Function], + }, + "typography": Object { + "body1": Object { "fontFamily": "\\"Roboto\\", \\"Helvetica\\", \\"Arial\\", sans-serif", - "fontSize": 14, - "fontWeightBold": 700, - "fontWeightLight": 300, - "fontWeightMedium": 500, - "fontWeightRegular": 400, - "h1": Object { - "fontFamily": "\\"Roboto\\", \\"Helvetica\\", \\"Arial\\", sans-serif", - "fontSize": "6rem", - "fontWeight": 300, - "letterSpacing": "-0.01562em", - "lineHeight": 1.167, - }, - "h2": Object { - "fontFamily": "\\"Roboto\\", \\"Helvetica\\", \\"Arial\\", sans-serif", - "fontSize": "3.75rem", - "fontWeight": 300, - "letterSpacing": "-0.00833em", - "lineHeight": 1.2, - }, - "h3": Object { - "fontFamily": "\\"Roboto\\", \\"Helvetica\\", \\"Arial\\", sans-serif", - "fontSize": "3rem", - "fontWeight": 400, - "letterSpacing": "0em", - "lineHeight": 1.167, - }, - "h4": Object { - "fontFamily": "\\"Roboto\\", \\"Helvetica\\", \\"Arial\\", sans-serif", - "fontSize": "2.125rem", - "fontWeight": 400, - "letterSpacing": "0.00735em", - "lineHeight": 1.235, - }, - "h5": Object { - "fontFamily": "\\"Roboto\\", \\"Helvetica\\", \\"Arial\\", sans-serif", - "fontSize": "1.5rem", - "fontWeight": 400, - "letterSpacing": "0em", - "lineHeight": 1.334, - }, - "h6": Object { - "fontFamily": "\\"Roboto\\", \\"Helvetica\\", \\"Arial\\", sans-serif", - "fontSize": "1.25rem", - "fontWeight": 500, - "letterSpacing": "0.0075em", - "lineHeight": 1.6, - }, - "htmlFontSize": 16, - "overline": Object { - "fontFamily": "\\"Roboto\\", \\"Helvetica\\", \\"Arial\\", sans-serif", - "fontSize": "0.75rem", - "fontWeight": 400, - "letterSpacing": "0.08333em", - "lineHeight": 2.66, - "textTransform": "uppercase", - }, - "pxToRem": [Function], - "round": [Function], - "subtitle1": Object { - "fontFamily": "\\"Roboto\\", \\"Helvetica\\", \\"Arial\\", sans-serif", - "fontSize": "1rem", - "fontWeight": 400, - "letterSpacing": "0.00938em", - "lineHeight": 1.75, - }, - "subtitle2": Object { - "fontFamily": "\\"Roboto\\", \\"Helvetica\\", \\"Arial\\", sans-serif", - "fontSize": "0.875rem", - "fontWeight": 500, - "letterSpacing": "0.00714em", - "lineHeight": 1.57, - }, + "fontSize": "1rem", + "fontWeight": 400, + "letterSpacing": "0.00938em", + "lineHeight": 1.5, + }, + "body2": Object { + "fontFamily": "\\"Roboto\\", \\"Helvetica\\", \\"Arial\\", sans-serif", + "fontSize": "0.875rem", + "fontWeight": 400, + "letterSpacing": "0.01071em", + "lineHeight": 1.43, + }, + "button": Object { + "fontFamily": "\\"Roboto\\", \\"Helvetica\\", \\"Arial\\", sans-serif", + "fontSize": "0.875rem", + "fontWeight": 500, + "letterSpacing": "0.02857em", + "lineHeight": 1.75, + "textTransform": "uppercase", + }, + "caption": Object { + "fontFamily": "\\"Roboto\\", \\"Helvetica\\", \\"Arial\\", sans-serif", + "fontSize": "0.75rem", + "fontWeight": 400, + "letterSpacing": "0.03333em", + "lineHeight": 1.66, + }, + "fontFamily": "\\"Roboto\\", \\"Helvetica\\", \\"Arial\\", sans-serif", + "fontSize": 14, + "fontWeightBold": 700, + "fontWeightLight": 300, + "fontWeightMedium": 500, + "fontWeightRegular": 400, + "h1": Object { + "fontFamily": "\\"Roboto\\", \\"Helvetica\\", \\"Arial\\", sans-serif", + "fontSize": "6rem", + "fontWeight": 300, + "letterSpacing": "-0.01562em", + "lineHeight": 1.167, + }, + "h2": Object { + "fontFamily": "\\"Roboto\\", \\"Helvetica\\", \\"Arial\\", sans-serif", + "fontSize": "3.75rem", + "fontWeight": 300, + "letterSpacing": "-0.00833em", + "lineHeight": 1.2, + }, + "h3": Object { + "fontFamily": "\\"Roboto\\", \\"Helvetica\\", \\"Arial\\", sans-serif", + "fontSize": "3rem", + "fontWeight": 400, + "letterSpacing": "0em", + "lineHeight": 1.167, + }, + "h4": Object { + "fontFamily": "\\"Roboto\\", \\"Helvetica\\", \\"Arial\\", sans-serif", + "fontSize": "2.125rem", + "fontWeight": 400, + "letterSpacing": "0.00735em", + "lineHeight": 1.235, + }, + "h5": Object { + "fontFamily": "\\"Roboto\\", \\"Helvetica\\", \\"Arial\\", sans-serif", + "fontSize": "1.5rem", + "fontWeight": 400, + "letterSpacing": "0em", + "lineHeight": 1.334, + }, + "h6": Object { + "fontFamily": "\\"Roboto\\", \\"Helvetica\\", \\"Arial\\", sans-serif", + "fontSize": "1.25rem", + "fontWeight": 500, + "letterSpacing": "0.0075em", + "lineHeight": 1.6, + }, + "htmlFontSize": 16, + "overline": Object { + "fontFamily": "\\"Roboto\\", \\"Helvetica\\", \\"Arial\\", sans-serif", + "fontSize": "0.75rem", + "fontWeight": 400, + "letterSpacing": "0.08333em", + "lineHeight": 2.66, + "textTransform": "uppercase", + }, + "pxToRem": [Function], + "round": [Function], + "subtitle1": Object { + "fontFamily": "\\"Roboto\\", \\"Helvetica\\", \\"Arial\\", sans-serif", + "fontSize": "1rem", + "fontWeight": 400, + "letterSpacing": "0.00938em", + "lineHeight": 1.75, }, - "zIndex": Object { - "appBar": 1100, - "drawer": 1200, - "mobileStepper": 1000, - "modal": 1300, - "snackbar": 1400, - "speedDial": 1050, - "tooltip": 1500, + "subtitle2": Object { + "fontFamily": "\\"Roboto\\", \\"Helvetica\\", \\"Arial\\", sans-serif", + "fontSize": "0.875rem", + "fontWeight": 500, + "letterSpacing": "0.00714em", + "lineHeight": 1.57, }, }, - "name": "MuiBackdrop", - }, - "propTypes": Object { - "classes": [Function], - "innerRef": [Function], + "zIndex": Object { + "appBar": 1100, + "drawer": 1200, + "mobileStepper": 1000, + "modal": 1300, + "snackbar": 1400, + "speedDial": 1050, + "tooltip": 1500, + }, }, - "render": [Function], - "useStyles": [Function], - } + "name": "MuiBackdrop", + }, + "propTypes": Object { + "classes": [Function], + "innerRef": [Function], + }, + "render": [Function], + "useStyles": [Function], } - BackdropProps={ - Object { - "transitionDuration": Object { - "enter": 225, - "exit": 195, - }, - } + } + BackdropProps={ + Object { + "transitionDuration": Object { + "enter": 225, + "exit": 195, + }, } - className="MuiDialog-root modal-root" - closeAfterTransition={true} - disableEscapeKeyDown={false} - onClose={[MockFunction]} - open={true} + } + className="MuiDialog-root modal-root" + closeAfterTransition={true} + disableEscapeKeyDown={false} + onClose={[MockFunction]} + open={true} + > + <ForwardRef(Portal) + disablePortal={false} > - <ForwardRef(Portal) - disablePortal={false} - > - <Portal - containerInfo={ - <body - style="padding-right: 0px; overflow: hidden;" + <Portal + containerInfo={ + <body + style="padding-right: 0px; overflow: hidden;" + > + <div + class="MuiDialog-root modal-root" + role="presentation" + style="position: fixed; z-index: 1300; right: 0px; bottom: 0px; top: 0px; left: 0px;" > <div - class="MuiDialog-root modal-root" - role="presentation" - style="position: fixed; z-index: 1300; right: 0px; bottom: 0px; top: 0px; left: 0px;" + aria-hidden="true" + class="MuiBackdrop-root" + style="opacity: 1; webkit-transition: opacity 225ms cubic-bezier(0.4, 0, 0.2, 1) 0ms; transition: opacity 225ms cubic-bezier(0.4, 0, 0.2, 1) 0ms;" + /> + <div + data-test="sentinelStart" + tabindex="0" + /> + <div + class="MuiDialog-container MuiDialog-scrollPaper" + role="none presentation" + style="opacity: 1; webkit-transition: opacity 225ms cubic-bezier(0.4, 0, 0.2, 1) 0ms; transition: opacity 225ms cubic-bezier(0.4, 0, 0.2, 1) 0ms;" + tabindex="-1" > <div - aria-hidden="true" - class="MuiBackdrop-root" - style="opacity: 1; webkit-transition: opacity 225ms cubic-bezier(0.4, 0, 0.2, 1) 0ms; transition: opacity 225ms cubic-bezier(0.4, 0, 0.2, 1) 0ms;" - /> - <div - data-test="sentinelStart" - tabindex="0" - /> - <div - class="MuiDialog-container MuiDialog-scrollPaper" - role="none presentation" - style="opacity: 1; webkit-transition: opacity 225ms cubic-bezier(0.4, 0, 0.2, 1) 0ms; transition: opacity 225ms cubic-bezier(0.4, 0, 0.2, 1) 0ms;" - tabindex="-1" + aria-labelledby="accessibility-title" + class="MuiPaper-root MuiDialog-paper modal-paper MuiDialog-paperScrollPaper MuiDialog-paperWidthSm MuiPaper-elevation24 MuiPaper-rounded" + role="dialog" > <div - aria-labelledby="accessibility-title" - class="MuiPaper-root MuiDialog-paper modal-paper MuiDialog-paperScrollPaper MuiDialog-paperWidthSm MuiPaper-elevation24 MuiPaper-rounded" - role="dialog" + id="accessibility-title" > + consumption_visualizer.modal.window_title + </div> + <button + aria-label="consumption_visualizer.modal.close" + class="MuiButtonBase-root MuiIconButton-root modal-paper-close-button" + tabindex="0" + type="button" + > + <span + class="MuiIconButton-label" + > + <svg + class="styles__icon___23x3R" + height="16" + width="16" + > + <use + xlink:href="#test-file-stub" + /> + </svg> + </span> + <span + class="MuiTouchRipple-root" + /> + </button> + <div + class="nodata-modal" + > + <div + class="question-mark" + > + <svg + class="styles__icon___23x3R" + height="36" + width="36" + > + <use + xlink:href="#test-file-stub" + /> + </svg> + </div> <div - id="accessibility-title" + class="text-20-normal title" > - consumption_visualizer.modal.window_title + consumption_visualizer.why_no_data </div> + <div + class="text-16-normal" + > + consumption_visualizer.dataModal.list_title + </div> + <ul> + <li> + consumption_visualizer.dataModal.item1 + </li> + <li> + consumption_visualizer.dataModal.item2 + </li> + <li> + consumption_visualizer.dataModal.item3 + </li> + <li> + consumption_visualizer.dataModal.item4 + </li> + </ul> <button - aria-label="consumption_visualizer.modal.close" - class="MuiButtonBase-root MuiIconButton-root modal-paper-close-button" + aria-label="ecogesture_info_modal.button_close" + class="MuiButtonBase-root MuiButton-root btn-highlight MuiButton-text" tabindex="0" type="button" > <span - class="MuiIconButton-label" + class="MuiButton-label text-16-bold" > - <svg - class="styles__icon___23x3R" - height="16" - width="16" - > - <use - xlink:href="#test-file-stub" - /> - </svg> + ecogesture_info_modal.button_close </span> <span class="MuiTouchRipple-root" /> </button> - <div - class="nodata-modal" - > - <div - class="question-mark" - > - <svg - class="styles__icon___23x3R" - height="36" - width="36" - > - <use - xlink:href="#test-file-stub" - /> - </svg> - </div> - <div - class="text-20-normal title" - > - consumption_visualizer.why_no_data - </div> - <div - class="text-16-normal" - > - consumption_visualizer.dataModal.list_title - </div> - <div - class="text-16-normal justified-text" - > - <span> - • - </span> - consumption_visualizer.dataModal.item1 - </div> - <div - class="text-16-normal justified-text" - > - <span> - • - </span> - consumption_visualizer.dataModal.item2 - </div> - <div - class="text-16-normal justified-text" - > - <span> - • - </span> - consumption_visualizer.dataModal.item3 - </div> - <div - class="text-16-normal justified-text" - > - <span> - • - </span> - consumption_visualizer.dataModal.item4 - </div> - <button - aria-label="ecogesture_info_modal.button_close" - class="MuiButtonBase-root MuiButton-root btn-highlight MuiButton-text" - tabindex="0" - type="button" - > - <span - class="MuiButton-label text-16-bold" - > - ecogesture_info_modal.button_close - </span> - <span - class="MuiTouchRipple-root" - /> - </button> - </div> </div> </div> - <div - data-test="sentinelEnd" - tabindex="0" - /> </div> - </body> + <div + data-test="sentinelEnd" + tabindex="0" + /> + </div> + </body> + } + > + <div + className="MuiDialog-root modal-root" + onKeyDown={[Function]} + role="presentation" + style={ + Object { + "bottom": 0, + "left": 0, + "position": "fixed", + "right": 0, + "top": 0, + "zIndex": 1300, + } } > - <div - className="MuiDialog-root modal-root" - onKeyDown={[Function]} - role="presentation" - style={ + <WithStyles(ForwardRef(Backdrop)) + onClick={[Function]} + open={true} + transitionDuration={ Object { - "bottom": 0, - "left": 0, - "position": "fixed", - "right": 0, - "top": 0, - "zIndex": 1300, + "enter": 225, + "exit": 195, } } > - <WithStyles(ForwardRef(Backdrop)) + <ForwardRef(Backdrop) + classes={ + Object { + "invisible": "MuiBackdrop-invisible", + "root": "MuiBackdrop-root", + } + } onClick={[Function]} open={true} transitionDuration={ @@ -552,85 +538,90 @@ exports[`NoDataModal component should render correctly 1`] = ` } } > - <ForwardRef(Backdrop) - classes={ - Object { - "invisible": "MuiBackdrop-invisible", - "root": "MuiBackdrop-root", - } - } + <ForwardRef(Fade) + in={true} onClick={[Function]} - open={true} - transitionDuration={ + timeout={ Object { "enter": 225, "exit": 195, } } > - <ForwardRef(Fade) + <Transition + appear={true} + enter={true} + exit={true} in={true} + mountOnEnter={false} onClick={[Function]} + onEnter={[Function]} + onEntered={[Function]} + onEntering={[Function]} + onExit={[Function]} + onExited={[Function]} + onExiting={[Function]} timeout={ Object { "enter": 225, "exit": 195, } } + unmountOnExit={false} > - <Transition - appear={true} - enter={true} - exit={true} - in={true} - mountOnEnter={false} + <div + aria-hidden={true} + className="MuiBackdrop-root" onClick={[Function]} - onEnter={[Function]} - onEntered={[Function]} - onEntering={[Function]} - onExit={[Function]} - onExited={[Function]} - onExiting={[Function]} - timeout={ + style={ Object { - "enter": 225, - "exit": 195, + "opacity": 1, + "visibility": undefined, } } - unmountOnExit={false} - > - <div - aria-hidden={true} - className="MuiBackdrop-root" - onClick={[Function]} - style={ - Object { - "opacity": 1, - "visibility": undefined, - } - } - /> - </Transition> - </ForwardRef(Fade)> - </ForwardRef(Backdrop)> - </WithStyles(ForwardRef(Backdrop))> - <Unstable_TrapFocus - disableAutoFocus={false} - disableEnforceFocus={false} - disableRestoreFocus={false} - getDoc={[Function]} - isEnabled={[Function]} - open={true} + /> + </Transition> + </ForwardRef(Fade)> + </ForwardRef(Backdrop)> + </WithStyles(ForwardRef(Backdrop))> + <Unstable_TrapFocus + disableAutoFocus={false} + disableEnforceFocus={false} + disableRestoreFocus={false} + getDoc={[Function]} + isEnabled={[Function]} + open={true} + > + <div + data-test="sentinelStart" + tabIndex={0} + /> + <ForwardRef(Fade) + appear={true} + in={true} + onEnter={[Function]} + onExited={[Function]} + role="none presentation" + tabIndex="-1" + timeout={ + Object { + "enter": 225, + "exit": 195, + } + } > - <div - data-test="sentinelStart" - tabIndex={0} - /> - <ForwardRef(Fade) + <Transition appear={true} + enter={true} + exit={true} in={true} + mountOnEnter={false} onEnter={[Function]} + onEntered={[Function]} + onEntering={[Function]} + onExit={[Function]} onExited={[Function]} + onExiting={[Function]} role="none presentation" tabIndex="-1" timeout={ @@ -639,131 +630,314 @@ exports[`NoDataModal component should render correctly 1`] = ` "exit": 195, } } + unmountOnExit={false} > - <Transition - appear={true} - enter={true} - exit={true} - in={true} - mountOnEnter={false} - onEnter={[Function]} - onEntered={[Function]} - onEntering={[Function]} - onExit={[Function]} - onExited={[Function]} - onExiting={[Function]} + <div + className="MuiDialog-container MuiDialog-scrollPaper" + onMouseDown={[Function]} + onMouseUp={[Function]} role="none presentation" - tabIndex="-1" - timeout={ + style={ Object { - "enter": 225, - "exit": 195, + "opacity": 1, + "visibility": undefined, } } - unmountOnExit={false} + tabIndex="-1" > - <div - className="MuiDialog-container MuiDialog-scrollPaper" - onMouseDown={[Function]} - onMouseUp={[Function]} - role="none presentation" - style={ - Object { - "opacity": 1, - "visibility": undefined, - } - } - tabIndex="-1" + <WithStyles(ForwardRef(Paper)) + aria-labelledby="accessibility-title" + className="MuiDialog-paper modal-paper MuiDialog-paperScrollPaper MuiDialog-paperWidthSm" + elevation={24} + role="dialog" > - <WithStyles(ForwardRef(Paper)) + <ForwardRef(Paper) aria-labelledby="accessibility-title" className="MuiDialog-paper modal-paper MuiDialog-paperScrollPaper MuiDialog-paperWidthSm" + classes={ + Object { + "elevation0": "MuiPaper-elevation0", + "elevation1": "MuiPaper-elevation1", + "elevation10": "MuiPaper-elevation10", + "elevation11": "MuiPaper-elevation11", + "elevation12": "MuiPaper-elevation12", + "elevation13": "MuiPaper-elevation13", + "elevation14": "MuiPaper-elevation14", + "elevation15": "MuiPaper-elevation15", + "elevation16": "MuiPaper-elevation16", + "elevation17": "MuiPaper-elevation17", + "elevation18": "MuiPaper-elevation18", + "elevation19": "MuiPaper-elevation19", + "elevation2": "MuiPaper-elevation2", + "elevation20": "MuiPaper-elevation20", + "elevation21": "MuiPaper-elevation21", + "elevation22": "MuiPaper-elevation22", + "elevation23": "MuiPaper-elevation23", + "elevation24": "MuiPaper-elevation24", + "elevation3": "MuiPaper-elevation3", + "elevation4": "MuiPaper-elevation4", + "elevation5": "MuiPaper-elevation5", + "elevation6": "MuiPaper-elevation6", + "elevation7": "MuiPaper-elevation7", + "elevation8": "MuiPaper-elevation8", + "elevation9": "MuiPaper-elevation9", + "outlined": "MuiPaper-outlined", + "root": "MuiPaper-root", + "rounded": "MuiPaper-rounded", + } + } elevation={24} role="dialog" > - <ForwardRef(Paper) + <div aria-labelledby="accessibility-title" - className="MuiDialog-paper modal-paper MuiDialog-paperScrollPaper MuiDialog-paperWidthSm" - classes={ - Object { - "elevation0": "MuiPaper-elevation0", - "elevation1": "MuiPaper-elevation1", - "elevation10": "MuiPaper-elevation10", - "elevation11": "MuiPaper-elevation11", - "elevation12": "MuiPaper-elevation12", - "elevation13": "MuiPaper-elevation13", - "elevation14": "MuiPaper-elevation14", - "elevation15": "MuiPaper-elevation15", - "elevation16": "MuiPaper-elevation16", - "elevation17": "MuiPaper-elevation17", - "elevation18": "MuiPaper-elevation18", - "elevation19": "MuiPaper-elevation19", - "elevation2": "MuiPaper-elevation2", - "elevation20": "MuiPaper-elevation20", - "elevation21": "MuiPaper-elevation21", - "elevation22": "MuiPaper-elevation22", - "elevation23": "MuiPaper-elevation23", - "elevation24": "MuiPaper-elevation24", - "elevation3": "MuiPaper-elevation3", - "elevation4": "MuiPaper-elevation4", - "elevation5": "MuiPaper-elevation5", - "elevation6": "MuiPaper-elevation6", - "elevation7": "MuiPaper-elevation7", - "elevation8": "MuiPaper-elevation8", - "elevation9": "MuiPaper-elevation9", - "outlined": "MuiPaper-outlined", - "root": "MuiPaper-root", - "rounded": "MuiPaper-rounded", - } - } - elevation={24} + className="MuiPaper-root MuiDialog-paper modal-paper MuiDialog-paperScrollPaper MuiDialog-paperWidthSm MuiPaper-elevation24 MuiPaper-rounded" role="dialog" > <div - aria-labelledby="accessibility-title" - className="MuiPaper-root MuiDialog-paper modal-paper MuiDialog-paperScrollPaper MuiDialog-paperWidthSm MuiPaper-elevation24 MuiPaper-rounded" - role="dialog" + id="accessibility-title" > - <div - id="accessibility-title" - > - consumption_visualizer.modal.window_title - </div> - <WithStyles(ForwardRef(IconButton)) + consumption_visualizer.modal.window_title + </div> + <WithStyles(ForwardRef(IconButton)) + aria-label="consumption_visualizer.modal.close" + className="modal-paper-close-button" + onClick={[MockFunction]} + > + <ForwardRef(IconButton) aria-label="consumption_visualizer.modal.close" className="modal-paper-close-button" + classes={ + Object { + "colorInherit": "MuiIconButton-colorInherit", + "colorPrimary": "MuiIconButton-colorPrimary", + "colorSecondary": "MuiIconButton-colorSecondary", + "disabled": "Mui-disabled", + "edgeEnd": "MuiIconButton-edgeEnd", + "edgeStart": "MuiIconButton-edgeStart", + "label": "MuiIconButton-label", + "root": "MuiIconButton-root", + "sizeSmall": "MuiIconButton-sizeSmall", + } + } onClick={[MockFunction]} > - <ForwardRef(IconButton) + <WithStyles(ForwardRef(ButtonBase)) aria-label="consumption_visualizer.modal.close" - className="modal-paper-close-button" + centerRipple={true} + className="MuiIconButton-root modal-paper-close-button" + disabled={false} + focusRipple={true} + onClick={[MockFunction]} + > + <ForwardRef(ButtonBase) + aria-label="consumption_visualizer.modal.close" + centerRipple={true} + className="MuiIconButton-root modal-paper-close-button" + classes={ + Object { + "disabled": "Mui-disabled", + "focusVisible": "Mui-focusVisible", + "root": "MuiButtonBase-root", + } + } + disabled={false} + focusRipple={true} + onClick={[MockFunction]} + > + <button + aria-label="consumption_visualizer.modal.close" + className="MuiButtonBase-root MuiIconButton-root modal-paper-close-button" + disabled={false} + onBlur={[Function]} + onClick={[MockFunction]} + onDragLeave={[Function]} + onFocus={[Function]} + onKeyDown={[Function]} + onKeyUp={[Function]} + onMouseDown={[Function]} + onMouseLeave={[Function]} + onMouseUp={[Function]} + onTouchEnd={[Function]} + onTouchMove={[Function]} + onTouchStart={[Function]} + tabIndex={0} + type="button" + > + <span + className="MuiIconButton-label" + > + <Icon + icon="test-file-stub" + size={16} + spin={false} + > + <Component + className="styles__icon___23x3R" + height={16} + style={Object {}} + width={16} + > + <svg + className="styles__icon___23x3R" + height={16} + style={Object {}} + width={16} + > + <use + xlinkHref="#test-file-stub" + /> + </svg> + </Component> + </Icon> + </span> + <WithStyles(memo) + center={true} + > + <ForwardRef(TouchRipple) + center={true} + classes={ + Object { + "child": "MuiTouchRipple-child", + "childLeaving": "MuiTouchRipple-childLeaving", + "childPulsate": "MuiTouchRipple-childPulsate", + "ripple": "MuiTouchRipple-ripple", + "ripplePulsate": "MuiTouchRipple-ripplePulsate", + "rippleVisible": "MuiTouchRipple-rippleVisible", + "root": "MuiTouchRipple-root", + } + } + > + <span + className="MuiTouchRipple-root" + > + <TransitionGroup + childFactory={[Function]} + component={null} + exit={true} + /> + </span> + </ForwardRef(TouchRipple)> + </WithStyles(memo)> + </button> + </ForwardRef(ButtonBase)> + </WithStyles(ForwardRef(ButtonBase))> + </ForwardRef(IconButton)> + </WithStyles(ForwardRef(IconButton))> + <div + className="nodata-modal" + > + <div + className="question-mark" + > + <Icon + icon="test-file-stub" + size={36} + spin={false} + > + <Component + className="styles__icon___23x3R" + height={36} + style={Object {}} + width={36} + > + <svg + className="styles__icon___23x3R" + height={36} + style={Object {}} + width={36} + > + <use + xlinkHref="#test-file-stub" + /> + </svg> + </Component> + </Icon> + </div> + <div + className="text-20-normal title" + > + consumption_visualizer.why_no_data + </div> + <div + className="text-16-normal" + > + consumption_visualizer.dataModal.list_title + </div> + <ul> + <li> + consumption_visualizer.dataModal.item1 + </li> + <li> + consumption_visualizer.dataModal.item2 + </li> + <li> + consumption_visualizer.dataModal.item3 + </li> + <li> + consumption_visualizer.dataModal.item4 + </li> + </ul> + <WithStyles(ForwardRef(Button)) + aria-label="ecogesture_info_modal.button_close" + classes={ + Object { + "label": "text-16-bold", + "root": "btn-highlight", + } + } + onClick={[MockFunction]} + > + <ForwardRef(Button) + aria-label="ecogesture_info_modal.button_close" classes={ Object { - "colorInherit": "MuiIconButton-colorInherit", - "colorPrimary": "MuiIconButton-colorPrimary", - "colorSecondary": "MuiIconButton-colorSecondary", + "colorInherit": "MuiButton-colorInherit", + "contained": "MuiButton-contained", + "containedPrimary": "MuiButton-containedPrimary", + "containedSecondary": "MuiButton-containedSecondary", + "containedSizeLarge": "MuiButton-containedSizeLarge", + "containedSizeSmall": "MuiButton-containedSizeSmall", + "disableElevation": "MuiButton-disableElevation", "disabled": "Mui-disabled", - "edgeEnd": "MuiIconButton-edgeEnd", - "edgeStart": "MuiIconButton-edgeStart", - "label": "MuiIconButton-label", - "root": "MuiIconButton-root", - "sizeSmall": "MuiIconButton-sizeSmall", + "endIcon": "MuiButton-endIcon", + "focusVisible": "Mui-focusVisible", + "fullWidth": "MuiButton-fullWidth", + "iconSizeLarge": "MuiButton-iconSizeLarge", + "iconSizeMedium": "MuiButton-iconSizeMedium", + "iconSizeSmall": "MuiButton-iconSizeSmall", + "label": "MuiButton-label text-16-bold", + "outlined": "MuiButton-outlined", + "outlinedPrimary": "MuiButton-outlinedPrimary", + "outlinedSecondary": "MuiButton-outlinedSecondary", + "outlinedSizeLarge": "MuiButton-outlinedSizeLarge", + "outlinedSizeSmall": "MuiButton-outlinedSizeSmall", + "root": "MuiButton-root btn-highlight", + "sizeLarge": "MuiButton-sizeLarge", + "sizeSmall": "MuiButton-sizeSmall", + "startIcon": "MuiButton-startIcon", + "text": "MuiButton-text", + "textPrimary": "MuiButton-textPrimary", + "textSecondary": "MuiButton-textSecondary", + "textSizeLarge": "MuiButton-textSizeLarge", + "textSizeSmall": "MuiButton-textSizeSmall", } } onClick={[MockFunction]} > <WithStyles(ForwardRef(ButtonBase)) - aria-label="consumption_visualizer.modal.close" - centerRipple={true} - className="MuiIconButton-root modal-paper-close-button" + aria-label="ecogesture_info_modal.button_close" + className="MuiButton-root btn-highlight MuiButton-text" + component="button" disabled={false} focusRipple={true} + focusVisibleClassName="Mui-focusVisible" onClick={[MockFunction]} + type="button" > <ForwardRef(ButtonBase) - aria-label="consumption_visualizer.modal.close" - centerRipple={true} - className="MuiIconButton-root modal-paper-close-button" + aria-label="ecogesture_info_modal.button_close" + className="MuiButton-root btn-highlight MuiButton-text" classes={ Object { "disabled": "Mui-disabled", @@ -771,13 +945,16 @@ exports[`NoDataModal component should render correctly 1`] = ` "root": "MuiButtonBase-root", } } + component="button" disabled={false} focusRipple={true} + focusVisibleClassName="Mui-focusVisible" onClick={[MockFunction]} + type="button" > <button - aria-label="consumption_visualizer.modal.close" - className="MuiButtonBase-root MuiIconButton-root modal-paper-close-button" + aria-label="ecogesture_info_modal.button_close" + className="MuiButtonBase-root MuiButton-root btn-highlight MuiButton-text" disabled={false} onBlur={[Function]} onClick={[MockFunction]} @@ -795,37 +972,15 @@ exports[`NoDataModal component should render correctly 1`] = ` type="button" > <span - className="MuiIconButton-label" + className="MuiButton-label text-16-bold" > - <Icon - icon="test-file-stub" - size={16} - spin={false} - > - <Component - className="styles__icon___23x3R" - height={16} - style={Object {}} - width={16} - > - <svg - className="styles__icon___23x3R" - height={16} - style={Object {}} - width={16} - > - <use - xlinkHref="#test-file-stub" - /> - </svg> - </Component> - </Icon> + ecogesture_info_modal.button_close </span> <WithStyles(memo) - center={true} + center={false} > <ForwardRef(TouchRipple) - center={true} + center={false} classes={ Object { "child": "MuiTouchRipple-child", @@ -852,229 +1007,25 @@ exports[`NoDataModal component should render correctly 1`] = ` </button> </ForwardRef(ButtonBase)> </WithStyles(ForwardRef(ButtonBase))> - </ForwardRef(IconButton)> - </WithStyles(ForwardRef(IconButton))> - <div - className="nodata-modal" - > - <div - className="question-mark" - > - <Icon - icon="test-file-stub" - size={36} - spin={false} - > - <Component - className="styles__icon___23x3R" - height={36} - style={Object {}} - width={36} - > - <svg - className="styles__icon___23x3R" - height={36} - style={Object {}} - width={36} - > - <use - xlinkHref="#test-file-stub" - /> - </svg> - </Component> - </Icon> - </div> - <div - className="text-20-normal title" - > - consumption_visualizer.why_no_data - </div> - <div - className="text-16-normal" - > - consumption_visualizer.dataModal.list_title - </div> - <div - className="text-16-normal justified-text" - > - <span> - • - </span> - consumption_visualizer.dataModal.item1 - </div> - <div - className="text-16-normal justified-text" - > - <span> - • - </span> - consumption_visualizer.dataModal.item2 - </div> - <div - className="text-16-normal justified-text" - > - <span> - • - </span> - consumption_visualizer.dataModal.item3 - </div> - <div - className="text-16-normal justified-text" - > - <span> - • - </span> - consumption_visualizer.dataModal.item4 - </div> - <WithStyles(ForwardRef(Button)) - aria-label="ecogesture_info_modal.button_close" - classes={ - Object { - "label": "text-16-bold", - "root": "btn-highlight", - } - } - onClick={[MockFunction]} - > - <ForwardRef(Button) - aria-label="ecogesture_info_modal.button_close" - classes={ - Object { - "colorInherit": "MuiButton-colorInherit", - "contained": "MuiButton-contained", - "containedPrimary": "MuiButton-containedPrimary", - "containedSecondary": "MuiButton-containedSecondary", - "containedSizeLarge": "MuiButton-containedSizeLarge", - "containedSizeSmall": "MuiButton-containedSizeSmall", - "disableElevation": "MuiButton-disableElevation", - "disabled": "Mui-disabled", - "endIcon": "MuiButton-endIcon", - "focusVisible": "Mui-focusVisible", - "fullWidth": "MuiButton-fullWidth", - "iconSizeLarge": "MuiButton-iconSizeLarge", - "iconSizeMedium": "MuiButton-iconSizeMedium", - "iconSizeSmall": "MuiButton-iconSizeSmall", - "label": "MuiButton-label text-16-bold", - "outlined": "MuiButton-outlined", - "outlinedPrimary": "MuiButton-outlinedPrimary", - "outlinedSecondary": "MuiButton-outlinedSecondary", - "outlinedSizeLarge": "MuiButton-outlinedSizeLarge", - "outlinedSizeSmall": "MuiButton-outlinedSizeSmall", - "root": "MuiButton-root btn-highlight", - "sizeLarge": "MuiButton-sizeLarge", - "sizeSmall": "MuiButton-sizeSmall", - "startIcon": "MuiButton-startIcon", - "text": "MuiButton-text", - "textPrimary": "MuiButton-textPrimary", - "textSecondary": "MuiButton-textSecondary", - "textSizeLarge": "MuiButton-textSizeLarge", - "textSizeSmall": "MuiButton-textSizeSmall", - } - } - onClick={[MockFunction]} - > - <WithStyles(ForwardRef(ButtonBase)) - aria-label="ecogesture_info_modal.button_close" - className="MuiButton-root btn-highlight MuiButton-text" - component="button" - disabled={false} - focusRipple={true} - focusVisibleClassName="Mui-focusVisible" - onClick={[MockFunction]} - type="button" - > - <ForwardRef(ButtonBase) - aria-label="ecogesture_info_modal.button_close" - className="MuiButton-root btn-highlight MuiButton-text" - classes={ - Object { - "disabled": "Mui-disabled", - "focusVisible": "Mui-focusVisible", - "root": "MuiButtonBase-root", - } - } - component="button" - disabled={false} - focusRipple={true} - focusVisibleClassName="Mui-focusVisible" - onClick={[MockFunction]} - type="button" - > - <button - aria-label="ecogesture_info_modal.button_close" - className="MuiButtonBase-root MuiButton-root btn-highlight MuiButton-text" - disabled={false} - onBlur={[Function]} - onClick={[MockFunction]} - onDragLeave={[Function]} - onFocus={[Function]} - onKeyDown={[Function]} - onKeyUp={[Function]} - onMouseDown={[Function]} - onMouseLeave={[Function]} - onMouseUp={[Function]} - onTouchEnd={[Function]} - onTouchMove={[Function]} - onTouchStart={[Function]} - tabIndex={0} - type="button" - > - <span - className="MuiButton-label text-16-bold" - > - ecogesture_info_modal.button_close - </span> - <WithStyles(memo) - center={false} - > - <ForwardRef(TouchRipple) - center={false} - classes={ - Object { - "child": "MuiTouchRipple-child", - "childLeaving": "MuiTouchRipple-childLeaving", - "childPulsate": "MuiTouchRipple-childPulsate", - "ripple": "MuiTouchRipple-ripple", - "ripplePulsate": "MuiTouchRipple-ripplePulsate", - "rippleVisible": "MuiTouchRipple-rippleVisible", - "root": "MuiTouchRipple-root", - } - } - > - <span - className="MuiTouchRipple-root" - > - <TransitionGroup - childFactory={[Function]} - component={null} - exit={true} - /> - </span> - </ForwardRef(TouchRipple)> - </WithStyles(memo)> - </button> - </ForwardRef(ButtonBase)> - </WithStyles(ForwardRef(ButtonBase))> - </ForwardRef(Button)> - </WithStyles(ForwardRef(Button))> - </div> + </ForwardRef(Button)> + </WithStyles(ForwardRef(Button))> </div> - </ForwardRef(Paper)> - </WithStyles(ForwardRef(Paper))> - </div> - </Transition> - </ForwardRef(Fade)> - <div - data-test="sentinelEnd" - tabIndex={0} - /> - </Unstable_TrapFocus> - </div> - </Portal> - </ForwardRef(Portal)> - </ForwardRef(Modal)> - </ForwardRef(Dialog)> - </WithStyles(ForwardRef(Dialog))> - </NoDataModal> -</Provider> + </div> + </ForwardRef(Paper)> + </WithStyles(ForwardRef(Paper))> + </div> + </Transition> + </ForwardRef(Fade)> + <div + data-test="sentinelEnd" + tabIndex={0} + /> + </Unstable_TrapFocus> + </div> + </Portal> + </ForwardRef(Portal)> + </ForwardRef(Modal)> + </ForwardRef(Dialog)> + </WithStyles(ForwardRef(Dialog))> +</NoDataModal> `; diff --git a/src/components/ConsumptionVisualizer/noDataModal.scss b/src/components/ConsumptionVisualizer/noDataModal.scss index bbb047c844054b312f2c0e4da61d0eabc997792d..cec39c2fb28facfe06cc26d0c86b5107128cfb4e 100644 --- a/src/components/ConsumptionVisualizer/noDataModal.scss +++ b/src/components/ConsumptionVisualizer/noDataModal.scss @@ -20,4 +20,10 @@ display: flex; justify-content: start; } + ul { + padding-left: 1rem; + li { + margin-block: 0.5rem; + } + } } diff --git a/src/components/Content/Content.tsx b/src/components/Content/Content.tsx index caf29cd956b6185a27e3130d7256889265622533..c3674fab4235568755913bb00c4ff131373ea883 100644 --- a/src/components/Content/Content.tsx +++ b/src/components/Content/Content.tsx @@ -1,35 +1,21 @@ import FeedbackModal from 'components/Feedback/FeedbackModal' -import { ScreenType } from 'enum/screen.enum' -import React, { Dispatch, useCallback, useEffect } from 'react' -import { useDispatch, useSelector } from 'react-redux' -import { AppActionsTypes, AppStore } from 'store' -import { changeScreenType } from 'store/global/global.actions' -import { openFeedbackModal } from 'store/modal/modal.slice' +import { ScreenType } from 'enums' +import React, { useEffect } from 'react' +import { changeScreenType } from 'store/global/global.slice' +import { useAppDispatch, useAppSelector } from 'store/hooks' import './content.scss' interface ContentProps { children: React.ReactNode - height?: number - background?: string + heightOffset?: number } -const Content = ({ - children, - height = 0, - background = 'inherit', -}: ContentProps) => { - const dispatch = useDispatch<Dispatch<AppActionsTypes>>() - const { - global: { screenType }, - modal: { isFeedbacksOpen }, - } = useSelector((state: AppStore) => state.ecolyo) +const Content = ({ children, heightOffset = 0 }: ContentProps) => { + const dispatch = useAppDispatch() + const { screenType } = useAppSelector(state => state.ecolyo.global) const cozyBarHeight = 48 const cozyNavHeight = 56 - const handleFeedbackModalClose = useCallback(() => { - dispatch(openFeedbackModal(false)) - }, [dispatch]) - // Set listeners for scroll useEffect(() => { window.scrollTo(0, 0) @@ -54,20 +40,16 @@ const Content = ({ return ( <> - <FeedbackModal - open={isFeedbacksOpen} - handleCloseClick={handleFeedbackModalClose} - /> + <FeedbackModal /> <div - className={'content-view'} + className="content-view" style={{ - marginTop: height, + marginTop: heightOffset, paddingBottom: 0, minHeight: screenType !== ScreenType.DESKTOP - ? `calc(100vh - ${height}px - ${cozyBarHeight}px - ${cozyNavHeight}px - env(safe-area-inset-top) - env(safe-area-inset-bottom) - env(safe-area-inset-bottom))` + ? `calc(100vh - ${heightOffset}px - ${cozyBarHeight}px - ${cozyNavHeight}px - env(safe-area-inset-top) - env(safe-area-inset-bottom) - env(safe-area-inset-bottom))` : `unset`, - background: background, }} > {children} diff --git a/src/components/CustomPopup/CustomPopupModal.spec.tsx b/src/components/CustomPopup/CustomPopupModal.spec.tsx index 845c8722cc606e65cba16fefc2ef938b3af8aa3a..5c7a807be742818b637fdd9bbfdf7363de51112e 100644 --- a/src/components/CustomPopup/CustomPopupModal.spec.tsx +++ b/src/components/CustomPopup/CustomPopupModal.spec.tsx @@ -6,19 +6,9 @@ import { mockCustomPopup, mockCustomPopupOff, mockCustomPopupOutdated, -} from '../../../tests/__mocks__/customPopup.mock' +} from 'tests/__mocks__/customPopup.mock' import CustomPopupModal from './CustomPopupModal' -jest.mock('cozy-ui/transpiled/react/I18n', () => { - return { - useI18n: jest.fn(() => { - return { - t: (str: string) => str, - } - }), - } -}) - const mockHandleClose = jest.fn() describe('CustomPopupModal component', () => { diff --git a/src/components/CustomPopup/CustomPopupModal.tsx b/src/components/CustomPopup/CustomPopupModal.tsx index f3e5fb338bd45502119dbd5719abb86d145756e0..3dcc5e49aa0597994118ab204e480c94a69df3c3 100644 --- a/src/components/CustomPopup/CustomPopupModal.tsx +++ b/src/components/CustomPopup/CustomPopupModal.tsx @@ -7,7 +7,7 @@ import StyledIcon from 'components/CommonKit/Icon/StyledIcon' import { useI18n } from 'cozy-ui/transpiled/react/I18n' import Icon from 'cozy-ui/transpiled/react/Icon' import { DateTime } from 'luxon' -import { CustomPopup } from 'models/customPopup.model' +import { CustomPopup } from 'models' import React from 'react' import './customPopupModal.scss' @@ -31,7 +31,7 @@ const CustomPopupModal = ({ onClose={(event, reason): void => { event && reason !== 'backdropClick' && handleCloseClick() }} - aria-labelledby={'accessibility-title'} + aria-labelledby="accessibility-title" classes={{ root: 'modal-root', paper: 'modal-paper customPopupRoot', diff --git a/src/components/CustomPopup/customPopupModal.scss b/src/components/CustomPopup/customPopupModal.scss index c780b1363d19185ad268e008180db4042f348e52..d0b9c013d1771554a0f0a10dc030c2c803424d1e 100644 --- a/src/components/CustomPopup/customPopupModal.scss +++ b/src/components/CustomPopup/customPopupModal.scss @@ -1,5 +1,5 @@ -@import '../../styles/base/typo-variables'; -@import '../../styles/base/color'; +@import 'src/styles/base/typo-variables'; +@import 'src/styles/base/color'; .customPopupRoot { border: 1px solid $gold-euro; diff --git a/src/components/DateNavigator/DateNavigator.spec.tsx b/src/components/DateNavigator/DateNavigator.spec.tsx index 60020958c4661d0fc0bbf2df6835ac022838dc78..8cd2494ef27ec449db23f6afc6184dce346eb196 100644 --- a/src/components/DateNavigator/DateNavigator.spec.tsx +++ b/src/components/DateNavigator/DateNavigator.spec.tsx @@ -1,118 +1,106 @@ import { IconButton } from '@material-ui/core' +import { TimeStep } from 'enums' import { mount } from 'enzyme' import toJson from 'enzyme-to-json' import { DateTime } from 'luxon' import React from 'react' -import * as reactRedux from 'react-redux' -import { Provider } from 'react-redux' -import configureStore from 'redux-mock-store' -import { globalStateData } from '../../../tests/__mocks__/globalStateData.mock' -import { mockInitialChartState } from '../../../tests/__mocks__/store' -import { waitForComponentToPaint } from '../../../tests/__mocks__/testUtils' +import { waitForComponentToPaint } from 'tests/__mocks__/testUtils' import DateNavigator from './DateNavigator' -jest.mock('cozy-ui/transpiled/react/I18n', () => { - return { - useI18n: jest.fn(() => { - return { - t: (str: string) => str, - } - }), - } -}) -const mockStore = configureStore([]) - jest.mock( 'components/DateNavigator/DateNavigatorFormat', () => 'mock-date-navigator-format' ) -const mockUseDispatch = jest.spyOn(reactRedux, 'useDispatch') - +const mockedDate = DateTime.local(2021, 7, 1) + .setZone('utc', { + keepLocalTime: true, + }) + .startOf('day') describe('DateNavigator component', () => { - const mockedDate = DateTime.local(2021, 7, 1) - .setZone('utc', { - keepLocalTime: true, - }) - .startOf('day') + const mockHandleNextDate = jest.fn() + const mockHandlePrevDate = jest.fn() + beforeEach(() => { + jest.clearAllMocks() + }) it('should be rendered correctly', async () => { - const store = mockStore({ - ecolyo: { - global: globalStateData, - chart: mockInitialChartState, - }, - }) const wrapper = mount( - <Provider store={store}> - <DateNavigator currentAnalysisDate={mockedDate} /> - </Provider> + <DateNavigator + disableNext={false} + disablePrev={false} + handleNextDate={mockHandleNextDate} + handlePrevDate={mockHandlePrevDate} + navigatorDate={mockedDate} + timeStep={TimeStep.MONTH} + /> ) await waitForComponentToPaint(wrapper) expect(toJson(wrapper)).toMatchSnapshot() }) - it('should click on left arrow and change date', async () => { - const store = mockStore({ - ecolyo: { - global: globalStateData, - chart: mockInitialChartState, - }, - }) - const wrapper = mount( - <Provider store={store}> - <DateNavigator currentAnalysisDate={mockedDate} /> - </Provider> - ) - await waitForComponentToPaint(wrapper) - wrapper.find(IconButton).first().simulate('click') - expect(mockUseDispatch).toHaveBeenCalledTimes(2) - }) - it('should click on right arrow and change date', async () => { - const store = mockStore({ - ecolyo: { - global: globalStateData, - chart: mockInitialChartState, - }, - }) - const wrapper = mount( - <Provider store={store}> - <DateNavigator currentAnalysisDate={mockedDate} /> - </Provider> - ) - await waitForComponentToPaint(wrapper) - wrapper.find(IconButton).at(1).simulate('click') - expect(mockUseDispatch).toHaveBeenCalledTimes(3) - }) - it('should be rendered without analysis date and change to previous index', async () => { - const store = mockStore({ - ecolyo: { - global: globalStateData, - chart: mockInitialChartState, - }, + describe('should test navigation functions', () => { + describe('should test previous arrow', () => { + it('should call handlePrevDate', async () => { + const wrapper = mount( + <DateNavigator + disableNext={false} + disablePrev={false} + handleNextDate={mockHandleNextDate} + handlePrevDate={mockHandlePrevDate} + navigatorDate={mockedDate} + timeStep={TimeStep.MONTH} + /> + ) + wrapper.find(IconButton).first().simulate('click') + expect(mockHandlePrevDate).toHaveBeenCalledTimes(1) + }) + + it('should NOT call handlePrevDate if disablePrev is true', async () => { + const wrapper = mount( + <DateNavigator + disableNext={false} + disablePrev={true} + handleNextDate={mockHandleNextDate} + handlePrevDate={mockHandlePrevDate} + navigatorDate={mockedDate} + timeStep={TimeStep.MONTH} + /> + ) + wrapper.find(IconButton).first().simulate('click') + expect(mockHandlePrevDate).toHaveBeenCalledTimes(0) + }) }) - const wrapper = mount( - <Provider store={store}> - <DateNavigator /> - </Provider> - ) - await waitForComponentToPaint(wrapper) - wrapper.find(IconButton).at(0).simulate('click') - expect(mockUseDispatch).toHaveBeenCalledTimes(4) - }) - it('should be rendered without analysis date and change to next index', async () => { - const store = mockStore({ - ecolyo: { - global: globalStateData, - chart: mockInitialChartState, - }, + + describe('should test next arrow', () => { + it('should call mockHandleNextDate', async () => { + const wrapper = mount( + <DateNavigator + disableNext={false} + disablePrev={false} + handleNextDate={mockHandleNextDate} + handlePrevDate={mockHandlePrevDate} + navigatorDate={mockedDate} + timeStep={TimeStep.MONTH} + /> + ) + wrapper.find(IconButton).at(1).simulate('click') + expect(mockHandleNextDate).toHaveBeenCalledTimes(1) + }) + + it('should NOT call mockHandleNextDate if disableNext is true', async () => { + const wrapper = mount( + <DateNavigator + disableNext={true} + disablePrev={false} + handleNextDate={mockHandleNextDate} + handlePrevDate={mockHandlePrevDate} + navigatorDate={mockedDate} + timeStep={TimeStep.MONTH} + /> + ) + wrapper.find(IconButton).at(1).simulate('click') + expect(mockHandleNextDate).toHaveBeenCalledTimes(0) + }) }) - const wrapper = mount( - <Provider store={store}> - <DateNavigator /> - </Provider> - ) - await waitForComponentToPaint(wrapper) - wrapper.find(IconButton).at(1).simulate('click') - expect(mockUseDispatch).toHaveBeenCalledTimes(5) }) }) diff --git a/src/components/DateNavigator/DateNavigator.tsx b/src/components/DateNavigator/DateNavigator.tsx index 97a2a39ec089523dd957dae2b4eed0c79503aff8..b23c9ae51343a0ac6a33044c08da0fb791ecab24 100644 --- a/src/components/DateNavigator/DateNavigator.tsx +++ b/src/components/DateNavigator/DateNavigator.tsx @@ -5,135 +5,59 @@ import classNames from 'classnames' import DateNavigatorFormat from 'components/DateNavigator/DateNavigatorFormat' import { useI18n } from 'cozy-ui/transpiled/react/I18n' import Icon from 'cozy-ui/transpiled/react/Icon' -import { FluidType } from 'enum/fluid.enum' -import { TimeStep } from 'enum/timeStep.enum' +import { TimeStep } from 'enums' import { DateTime } from 'luxon' -import React, { Dispatch } from 'react' -import { useDispatch, useSelector } from 'react-redux' -import DateChartService from 'services/dateChart.service' -import { AppActionsTypes, AppStore } from 'store' -import { setAnalysisMonth } from 'store/analysis/analysis.slice' -import { setCurrentIndex, setSelectedDate } from 'store/chart/chart.slice' -import { isLastDateReached } from 'utils/date' -import { isKonnectorActive } from 'utils/utils' +import React from 'react' import './datenavigator.scss' interface DateNavigatorProps { - /** If a value is given, Navigator is for Analysis view */ - currentAnalysisDate?: DateTime + disableNext: boolean + disablePrev: boolean + handleNextDate: () => void + handlePrevDate: () => void inlineDateDisplay?: boolean + navigatorDate: DateTime + timeStep: TimeStep } const DateNavigator = ({ - currentAnalysisDate, + disableNext, + disablePrev, + handleNextDate, + handlePrevDate, inlineDateDisplay = false, + navigatorDate, + timeStep, }: DateNavigatorProps) => { const { t } = useI18n() - const dispatch = useDispatch<Dispatch<AppActionsTypes>>() - const { - chart: { currentTimeStep, selectedDate, currentIndex }, - global: { fluidStatus }, - } = useSelector((state: AppStore) => state.ecolyo) - - const disablePrev = - selectedDate < - DateTime.local(0, 1, 1).setZone('utc', { - keepLocalTime: true, - }) - const disableNext: boolean = currentAnalysisDate - ? isLastDateReached(currentAnalysisDate, TimeStep.MONTH) - : isLastDateReached(selectedDate, currentTimeStep) - - const dateChartService = new DateChartService() - - /** Handle date navigation from ConsumptionView and Analysis view, not ideal though */ - const handleClickMove = (increment: number) => { - if (!currentAnalysisDate) { - const updatedDate: DateTime = dateChartService.incrementDate( - currentTimeStep, - selectedDate, - increment - ) - const updatedIndex: number = dateChartService.defineDateIndex( - currentTimeStep, - updatedDate - ) - dispatch(setSelectedDate(updatedDate)) - dispatch(setCurrentIndex(updatedIndex)) - } else { - const updatedDate: DateTime = dateChartService.incrementDate( - TimeStep.MONTH, - currentAnalysisDate, - increment - ) - dispatch(setAnalysisMonth(updatedDate)) - } - } - - const handleChangePrevIndex = () => { - if (!disablePrev && isKonnectorActive(fluidStatus, FluidType.MULTIFLUID)) { - const increment: number = - dateChartService.defineIncrementForPreviousIndex( - currentTimeStep, - selectedDate, - currentIndex - ) - if (currentAnalysisDate) { - handleClickMove(-1) - } else handleClickMove(increment) - } - } - const handleChangeNextIndex = () => { - if (!disableNext && isKonnectorActive(fluidStatus, FluidType.MULTIFLUID)) { - const increment: number = dateChartService.defineIncrementForNextIndex( - currentTimeStep, - selectedDate, - currentIndex - ) - if (currentAnalysisDate) { - handleClickMove(1) - } else handleClickMove(increment) - } - } return ( <div className="date-navigator"> - <div> - <IconButton - aria-label={t('consumption.accessibility.button_previous_value')} - className={classNames('date-navigator-button', { - ['disable']: - disablePrev || - !isKonnectorActive(fluidStatus, FluidType.MULTIFLUID), - })} - onClick={() => handleChangePrevIndex()} - > - <Icon icon={LeftArrowIcon} size={16} /> - </IconButton> - </div> + <IconButton + disabled={disablePrev} + onClick={handlePrevDate} + className={classNames('date-navigator-button', { + ['disable']: disablePrev, + })} + aria-label={t('consumption.accessibility.button_previous_value')} + > + <Icon icon={LeftArrowIcon} size={16} /> + </IconButton> <DateNavigatorFormat - timeStep={currentAnalysisDate ? TimeStep.MONTH : currentTimeStep} - date={ - currentAnalysisDate - ? currentAnalysisDate.minus({ month: 1 }) - : selectedDate - } + timeStep={timeStep} + date={navigatorDate} inline={inlineDateDisplay} /> - - <div> - <IconButton - aria-label={t('consumption.accessibility.button_next_value')} - className={classNames('date-navigator-button', { - ['disable']: - disableNext || - !isKonnectorActive(fluidStatus, FluidType.MULTIFLUID), - })} - onClick={() => handleChangeNextIndex()} - > - <Icon icon={RightArrowIcon} size={16} /> - </IconButton> - </div> + <IconButton + disabled={disableNext} + onClick={handleNextDate} + className={classNames('date-navigator-button', { + ['disable']: disableNext, + })} + aria-label={t('consumption.accessibility.button_next_value')} + > + <Icon icon={RightArrowIcon} size={16} /> + </IconButton> </div> ) } diff --git a/src/components/DateNavigator/DateNavigatorFormat.tsx b/src/components/DateNavigator/DateNavigatorFormat.tsx index d3052d2440d42674c8bb84d45a0156a99bdaed02..d5c835b35eb04908ab9051f8f92d3ece610abba7 100644 --- a/src/components/DateNavigator/DateNavigatorFormat.tsx +++ b/src/components/DateNavigator/DateNavigatorFormat.tsx @@ -1,4 +1,4 @@ -import { TimeStep } from 'enum/timeStep.enum' +import { TimeStep } from 'enums' import { DateTime } from 'luxon' import React from 'react' import './datenavigatorformat.scss' diff --git a/src/components/DateNavigator/__snapshots__/DateNavigator.spec.tsx.snap b/src/components/DateNavigator/__snapshots__/DateNavigator.spec.tsx.snap index 387873be42031c45326461c64db8e7ccba2da098..8daf2089343eeaee62c17f6c24f86038176a0d71 100644 --- a/src/components/DateNavigator/__snapshots__/DateNavigator.spec.tsx.snap +++ b/src/components/DateNavigator/__snapshots__/DateNavigator.spec.tsx.snap @@ -1,284 +1,276 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP exports[`DateNavigator component should be rendered correctly 1`] = ` -<Provider - store={ - Object { - "clearActions": [Function], - "dispatch": [Function], - "getActions": [Function], - "getState": [Function], - "replaceReducer": [Function], - "subscribe": [Function], - } - } +<DateNavigator + disableNext={false} + disablePrev={false} + handleNextDate={[MockFunction]} + handlePrevDate={[MockFunction]} + navigatorDate={"2021-07-01T00:00:00.000Z"} + timeStep={40} > - <DateNavigator - currentAnalysisDate={"2021-07-01T00:00:00.000Z"} + <div + className="date-navigator" > - <div - className="date-navigator" + <WithStyles(ForwardRef(IconButton)) + aria-label="consumption.accessibility.button_previous_value" + className="date-navigator-button" + disabled={false} + onClick={[MockFunction]} > - <div> - <WithStyles(ForwardRef(IconButton)) + <ForwardRef(IconButton) + aria-label="consumption.accessibility.button_previous_value" + className="date-navigator-button" + classes={ + Object { + "colorInherit": "MuiIconButton-colorInherit", + "colorPrimary": "MuiIconButton-colorPrimary", + "colorSecondary": "MuiIconButton-colorSecondary", + "disabled": "Mui-disabled", + "edgeEnd": "MuiIconButton-edgeEnd", + "edgeStart": "MuiIconButton-edgeStart", + "label": "MuiIconButton-label", + "root": "MuiIconButton-root", + "sizeSmall": "MuiIconButton-sizeSmall", + } + } + disabled={false} + onClick={[MockFunction]} + > + <WithStyles(ForwardRef(ButtonBase)) aria-label="consumption.accessibility.button_previous_value" - className="date-navigator-button disable" - onClick={[Function]} + centerRipple={true} + className="MuiIconButton-root date-navigator-button" + disabled={false} + focusRipple={true} + onClick={[MockFunction]} > - <ForwardRef(IconButton) + <ForwardRef(ButtonBase) aria-label="consumption.accessibility.button_previous_value" - className="date-navigator-button disable" + centerRipple={true} + className="MuiIconButton-root date-navigator-button" classes={ Object { - "colorInherit": "MuiIconButton-colorInherit", - "colorPrimary": "MuiIconButton-colorPrimary", - "colorSecondary": "MuiIconButton-colorSecondary", "disabled": "Mui-disabled", - "edgeEnd": "MuiIconButton-edgeEnd", - "edgeStart": "MuiIconButton-edgeStart", - "label": "MuiIconButton-label", - "root": "MuiIconButton-root", - "sizeSmall": "MuiIconButton-sizeSmall", + "focusVisible": "Mui-focusVisible", + "root": "MuiButtonBase-root", } } - onClick={[Function]} + disabled={false} + focusRipple={true} + onClick={[MockFunction]} > - <WithStyles(ForwardRef(ButtonBase)) + <button aria-label="consumption.accessibility.button_previous_value" - centerRipple={true} - className="MuiIconButton-root date-navigator-button disable" + className="MuiButtonBase-root MuiIconButton-root date-navigator-button" disabled={false} - focusRipple={true} - onClick={[Function]} + onBlur={[Function]} + onClick={[MockFunction]} + onDragLeave={[Function]} + onFocus={[Function]} + onKeyDown={[Function]} + onKeyUp={[Function]} + onMouseDown={[Function]} + onMouseLeave={[Function]} + onMouseUp={[Function]} + onTouchEnd={[Function]} + onTouchMove={[Function]} + onTouchStart={[Function]} + tabIndex={0} + type="button" > - <ForwardRef(ButtonBase) - aria-label="consumption.accessibility.button_previous_value" - centerRipple={true} - className="MuiIconButton-root date-navigator-button disable" - classes={ - Object { - "disabled": "Mui-disabled", - "focusVisible": "Mui-focusVisible", - "root": "MuiButtonBase-root", - } - } - disabled={false} - focusRipple={true} - onClick={[Function]} + <span + className="MuiIconButton-label" > - <button - aria-label="consumption.accessibility.button_previous_value" - className="MuiButtonBase-root MuiIconButton-root date-navigator-button disable" - disabled={false} - onBlur={[Function]} - onClick={[Function]} - onDragLeave={[Function]} - onFocus={[Function]} - onKeyDown={[Function]} - onKeyUp={[Function]} - onMouseDown={[Function]} - onMouseLeave={[Function]} - onMouseUp={[Function]} - onTouchEnd={[Function]} - onTouchMove={[Function]} - onTouchStart={[Function]} - tabIndex={0} - type="button" + <Icon + icon="test-file-stub" + size={16} + spin={false} > - <span - className="MuiIconButton-label" + <Component + className="styles__icon___23x3R" + height={16} + style={Object {}} + width={16} > - <Icon - icon="test-file-stub" - size={16} - spin={false} + <svg + className="styles__icon___23x3R" + height={16} + style={Object {}} + width={16} > - <Component - className="styles__icon___23x3R" - height={16} - style={Object {}} - width={16} - > - <svg - className="styles__icon___23x3R" - height={16} - style={Object {}} - width={16} - > - <use - xlinkHref="#test-file-stub" - /> - </svg> - </Component> - </Icon> - </span> - <WithStyles(memo) - center={true} + <use + xlinkHref="#test-file-stub" + /> + </svg> + </Component> + </Icon> + </span> + <WithStyles(memo) + center={true} + > + <ForwardRef(TouchRipple) + center={true} + classes={ + Object { + "child": "MuiTouchRipple-child", + "childLeaving": "MuiTouchRipple-childLeaving", + "childPulsate": "MuiTouchRipple-childPulsate", + "ripple": "MuiTouchRipple-ripple", + "ripplePulsate": "MuiTouchRipple-ripplePulsate", + "rippleVisible": "MuiTouchRipple-rippleVisible", + "root": "MuiTouchRipple-root", + } + } + > + <span + className="MuiTouchRipple-root" > - <ForwardRef(TouchRipple) - center={true} - classes={ - Object { - "child": "MuiTouchRipple-child", - "childLeaving": "MuiTouchRipple-childLeaving", - "childPulsate": "MuiTouchRipple-childPulsate", - "ripple": "MuiTouchRipple-ripple", - "ripplePulsate": "MuiTouchRipple-ripplePulsate", - "rippleVisible": "MuiTouchRipple-rippleVisible", - "root": "MuiTouchRipple-root", - } - } - > - <span - className="MuiTouchRipple-root" - > - <TransitionGroup - childFactory={[Function]} - component={null} - exit={true} - /> - </span> - </ForwardRef(TouchRipple)> - </WithStyles(memo)> - </button> - </ForwardRef(ButtonBase)> - </WithStyles(ForwardRef(ButtonBase))> - </ForwardRef(IconButton)> - </WithStyles(ForwardRef(IconButton))> - </div> - <mock-date-navigator-format - date={"2021-06-01T00:00:00.000Z"} - inline={false} - timeStep={40} - /> - <div> - <WithStyles(ForwardRef(IconButton)) + <TransitionGroup + childFactory={[Function]} + component={null} + exit={true} + /> + </span> + </ForwardRef(TouchRipple)> + </WithStyles(memo)> + </button> + </ForwardRef(ButtonBase)> + </WithStyles(ForwardRef(ButtonBase))> + </ForwardRef(IconButton)> + </WithStyles(ForwardRef(IconButton))> + <mock-date-navigator-format + date={"2021-07-01T00:00:00.000Z"} + inline={false} + timeStep={40} + /> + <WithStyles(ForwardRef(IconButton)) + aria-label="consumption.accessibility.button_next_value" + className="date-navigator-button" + disabled={false} + onClick={[MockFunction]} + > + <ForwardRef(IconButton) + aria-label="consumption.accessibility.button_next_value" + className="date-navigator-button" + classes={ + Object { + "colorInherit": "MuiIconButton-colorInherit", + "colorPrimary": "MuiIconButton-colorPrimary", + "colorSecondary": "MuiIconButton-colorSecondary", + "disabled": "Mui-disabled", + "edgeEnd": "MuiIconButton-edgeEnd", + "edgeStart": "MuiIconButton-edgeStart", + "label": "MuiIconButton-label", + "root": "MuiIconButton-root", + "sizeSmall": "MuiIconButton-sizeSmall", + } + } + disabled={false} + onClick={[MockFunction]} + > + <WithStyles(ForwardRef(ButtonBase)) aria-label="consumption.accessibility.button_next_value" - className="date-navigator-button disable" - onClick={[Function]} + centerRipple={true} + className="MuiIconButton-root date-navigator-button" + disabled={false} + focusRipple={true} + onClick={[MockFunction]} > - <ForwardRef(IconButton) + <ForwardRef(ButtonBase) aria-label="consumption.accessibility.button_next_value" - className="date-navigator-button disable" + centerRipple={true} + className="MuiIconButton-root date-navigator-button" classes={ Object { - "colorInherit": "MuiIconButton-colorInherit", - "colorPrimary": "MuiIconButton-colorPrimary", - "colorSecondary": "MuiIconButton-colorSecondary", "disabled": "Mui-disabled", - "edgeEnd": "MuiIconButton-edgeEnd", - "edgeStart": "MuiIconButton-edgeStart", - "label": "MuiIconButton-label", - "root": "MuiIconButton-root", - "sizeSmall": "MuiIconButton-sizeSmall", + "focusVisible": "Mui-focusVisible", + "root": "MuiButtonBase-root", } } - onClick={[Function]} + disabled={false} + focusRipple={true} + onClick={[MockFunction]} > - <WithStyles(ForwardRef(ButtonBase)) + <button aria-label="consumption.accessibility.button_next_value" - centerRipple={true} - className="MuiIconButton-root date-navigator-button disable" + className="MuiButtonBase-root MuiIconButton-root date-navigator-button" disabled={false} - focusRipple={true} - onClick={[Function]} + onBlur={[Function]} + onClick={[MockFunction]} + onDragLeave={[Function]} + onFocus={[Function]} + onKeyDown={[Function]} + onKeyUp={[Function]} + onMouseDown={[Function]} + onMouseLeave={[Function]} + onMouseUp={[Function]} + onTouchEnd={[Function]} + onTouchMove={[Function]} + onTouchStart={[Function]} + tabIndex={0} + type="button" > - <ForwardRef(ButtonBase) - aria-label="consumption.accessibility.button_next_value" - centerRipple={true} - className="MuiIconButton-root date-navigator-button disable" - classes={ - Object { - "disabled": "Mui-disabled", - "focusVisible": "Mui-focusVisible", - "root": "MuiButtonBase-root", - } - } - disabled={false} - focusRipple={true} - onClick={[Function]} + <span + className="MuiIconButton-label" > - <button - aria-label="consumption.accessibility.button_next_value" - className="MuiButtonBase-root MuiIconButton-root date-navigator-button disable" - disabled={false} - onBlur={[Function]} - onClick={[Function]} - onDragLeave={[Function]} - onFocus={[Function]} - onKeyDown={[Function]} - onKeyUp={[Function]} - onMouseDown={[Function]} - onMouseLeave={[Function]} - onMouseUp={[Function]} - onTouchEnd={[Function]} - onTouchMove={[Function]} - onTouchStart={[Function]} - tabIndex={0} - type="button" + <Icon + icon="test-file-stub" + size={16} + spin={false} > - <span - className="MuiIconButton-label" + <Component + className="styles__icon___23x3R" + height={16} + style={Object {}} + width={16} > - <Icon - icon="test-file-stub" - size={16} - spin={false} + <svg + className="styles__icon___23x3R" + height={16} + style={Object {}} + width={16} > - <Component - className="styles__icon___23x3R" - height={16} - style={Object {}} - width={16} - > - <svg - className="styles__icon___23x3R" - height={16} - style={Object {}} - width={16} - > - <use - xlinkHref="#test-file-stub" - /> - </svg> - </Component> - </Icon> - </span> - <WithStyles(memo) - center={true} + <use + xlinkHref="#test-file-stub" + /> + </svg> + </Component> + </Icon> + </span> + <WithStyles(memo) + center={true} + > + <ForwardRef(TouchRipple) + center={true} + classes={ + Object { + "child": "MuiTouchRipple-child", + "childLeaving": "MuiTouchRipple-childLeaving", + "childPulsate": "MuiTouchRipple-childPulsate", + "ripple": "MuiTouchRipple-ripple", + "ripplePulsate": "MuiTouchRipple-ripplePulsate", + "rippleVisible": "MuiTouchRipple-rippleVisible", + "root": "MuiTouchRipple-root", + } + } + > + <span + className="MuiTouchRipple-root" > - <ForwardRef(TouchRipple) - center={true} - classes={ - Object { - "child": "MuiTouchRipple-child", - "childLeaving": "MuiTouchRipple-childLeaving", - "childPulsate": "MuiTouchRipple-childPulsate", - "ripple": "MuiTouchRipple-ripple", - "ripplePulsate": "MuiTouchRipple-ripplePulsate", - "rippleVisible": "MuiTouchRipple-rippleVisible", - "root": "MuiTouchRipple-root", - } - } - > - <span - className="MuiTouchRipple-root" - > - <TransitionGroup - childFactory={[Function]} - component={null} - exit={true} - /> - </span> - </ForwardRef(TouchRipple)> - </WithStyles(memo)> - </button> - </ForwardRef(ButtonBase)> - </WithStyles(ForwardRef(ButtonBase))> - </ForwardRef(IconButton)> - </WithStyles(ForwardRef(IconButton))> - </div> - </div> - </DateNavigator> -</Provider> + <TransitionGroup + childFactory={[Function]} + component={null} + exit={true} + /> + </span> + </ForwardRef(TouchRipple)> + </WithStyles(memo)> + </button> + </ForwardRef(ButtonBase)> + </WithStyles(ForwardRef(ButtonBase))> + </ForwardRef(IconButton)> + </WithStyles(ForwardRef(IconButton))> + </div> +</DateNavigator> `; diff --git a/src/components/DateNavigator/datenavigator.scss b/src/components/DateNavigator/datenavigator.scss index 8751ba7e3204f9be5c43a90dedf0ca587f77a16f..101639886b6f06d89edd528592c346d33e32ee3a 100644 --- a/src/components/DateNavigator/datenavigator.scss +++ b/src/components/DateNavigator/datenavigator.scss @@ -1,5 +1,5 @@ -@import '../../styles/base/color'; -@import '../../styles/base/breakpoint'; +@import 'src/styles/base/color'; +@import 'src/styles/base/breakpoint'; .date-navigator { display: flex; diff --git a/src/components/DateNavigator/datenavigatorformat.scss b/src/components/DateNavigator/datenavigatorformat.scss index e964a71685463124326cc49aed07041b4b130125..b8dddbc5cb60e5be15a7f51609328d6eabe156f3 100644 --- a/src/components/DateNavigator/datenavigatorformat.scss +++ b/src/components/DateNavigator/datenavigatorformat.scss @@ -1,5 +1,5 @@ -@import '../../styles/base/color'; -@import '../../styles/base/breakpoint'; +@import 'src/styles/base/color'; +@import 'src/styles/base/breakpoint'; .date-navigator-format { display: flex; diff --git a/src/components/Duel/DuelBar.tsx b/src/components/Duel/DuelChart/DuelBar.tsx similarity index 92% rename from src/components/Duel/DuelBar.tsx rename to src/components/Duel/DuelChart/DuelBar.tsx index 99cfce82752506906ef1cd3b18b888763c52a89c..70485c60aeef70cab163f8c3b1ed1b9486d91ff4 100644 --- a/src/components/Duel/DuelBar.tsx +++ b/src/components/Duel/DuelChart/DuelBar.tsx @@ -3,15 +3,13 @@ import AxisRight from 'components/Charts/AxisRight' import Bar from 'components/Charts/Bar' import UncomingBar from 'components/Charts/UncomingBar' import { scaleBand, ScaleBand, scaleLinear, ScaleLinear } from 'd3-scale' -import { FluidType } from 'enum/fluid.enum' -import { TimeStep } from 'enum/timeStep.enum' +import { FluidType, TimeStep } from 'enums' import { DateTime } from 'luxon' import { Dataload, UserChallenge } from 'models' import React from 'react' -import { useSelector } from 'react-redux' -import { AppStore } from 'store' +import { useAppSelector } from 'store/hooks' -export interface BarChartProps { +interface BarChartProps { userChallenge: UserChallenge finishedDataLoad?: Dataload[] average: number @@ -36,9 +34,7 @@ const DuelBar = ({ marginTop = 20, marginBottom = 50, }: BarChartProps) => { - const { currentDataload } = useSelector( - (state: AppStore) => state.ecolyo.challenge - ) + const { currentDataload } = useAppSelector(state => state.ecolyo.challenge) const dataload: Dataload[] = finishedDataLoad ? finishedDataLoad : currentDataload @@ -136,9 +132,9 @@ const DuelBar = ({ transform={`translate(0, ${yScale(average)})`} strokeDasharray="10" x1="0" - y1={`0`} + y1="0" x2={width - marginRight} - y2={`0`} + y2="0" className="bar-average" /> </g> diff --git a/src/components/Duel/DuelChart.tsx b/src/components/Duel/DuelChart/DuelChart.tsx similarity index 90% rename from src/components/Duel/DuelChart.tsx rename to src/components/Duel/DuelChart/DuelChart.tsx index 5e3b76882bc691117a73baf1e81ded9a923fb68e..993328d4911ba67af59cc6318e38ef791c96301a 100644 --- a/src/components/Duel/DuelChart.tsx +++ b/src/components/Duel/DuelChart/DuelChart.tsx @@ -1,5 +1,5 @@ -import DuelBar from 'components/Duel/DuelBar' -import { TimeStep } from 'enum/timeStep.enum' +import DuelBar from 'components/Duel/DuelChart/DuelBar' +import { TimeStep } from 'enums' import { Dataload, UserChallenge } from 'models' import React, { useEffect, useState } from 'react' import './duelChart.scss' diff --git a/src/components/Duel/DuelChart/duelChart.scss b/src/components/Duel/DuelChart/duelChart.scss new file mode 100644 index 0000000000000000000000000000000000000000..481fd7e81d7ca1809f4740dd23ccb2ef5b054ec9 --- /dev/null +++ b/src/components/Duel/DuelChart/duelChart.scss @@ -0,0 +1,7 @@ +@import 'src/styles/base/color'; +@import 'src/styles/base/breakpoint'; + +.chart-root { + margin-bottom: 1rem; + max-width: 400px; +} diff --git a/src/components/Duel/DuelEmptyValueModal.tsx b/src/components/Duel/DuelEmptyValueModal/DuelEmptyValueModal.tsx similarity index 90% rename from src/components/Duel/DuelEmptyValueModal.tsx rename to src/components/Duel/DuelEmptyValueModal/DuelEmptyValueModal.tsx index cc39de14f720b650d1405f0e0604969e5230e1ea..6eac38bd25668b6de9e1bc76c52e6565303bfa60 100644 --- a/src/components/Duel/DuelEmptyValueModal.tsx +++ b/src/components/Duel/DuelEmptyValueModal/DuelEmptyValueModal.tsx @@ -21,11 +21,7 @@ const DuelEmptyValueModal = ({ useEffect(() => { async function handleEcogestureIcon() { const icon = await importIconById('emptyValue', 'duel') - if (icon) { - setEmptyIcon(icon) - } else { - setEmptyIcon(defaultIcon) - } + setEmptyIcon(icon || defaultIcon) } handleEcogestureIcon() @@ -35,13 +31,13 @@ const DuelEmptyValueModal = ({ <Dialog open={open} onClose={handleCloseClick} - aria-labelledby={'accessibility-title'} + aria-labelledby="accessibility-title" classes={{ root: 'modal-root', paper: 'modal-paper blue-border', }} > - <div id={'accessibility-title'}> + <div id="accessibility-title"> {t('duel_empty_value_modal.accessibility.window_title')} </div> <div className="modal-empty-value-root"> diff --git a/src/components/Duel/duelEmptyValueModal.scss b/src/components/Duel/DuelEmptyValueModal/duelEmptyValueModal.scss similarity index 85% rename from src/components/Duel/duelEmptyValueModal.scss rename to src/components/Duel/DuelEmptyValueModal/duelEmptyValueModal.scss index e0b34f0ec3f3592799701877b2745ce04043594f..1c515d4f2ced42d3491f45fc09b40843fdbf763f 100644 --- a/src/components/Duel/duelEmptyValueModal.scss +++ b/src/components/Duel/DuelEmptyValueModal/duelEmptyValueModal.scss @@ -1,4 +1,4 @@ -@import '../../styles/base/color'; +@import 'src/styles/base/color'; .modal-empty-value-root { display: flex; diff --git a/src/components/Duel/DuelError.spec.tsx b/src/components/Duel/DuelError.spec.tsx deleted file mode 100644 index 1e7314f2457cb4d7e78f7b0a44400177df4bd1ef..0000000000000000000000000000000000000000 --- a/src/components/Duel/DuelError.spec.tsx +++ /dev/null @@ -1,26 +0,0 @@ -import DuelError from 'components/Duel/DuelError' -import { shallow } from 'enzyme' -import React from 'react' - -jest.mock('cozy-ui/transpiled/react/I18n', () => { - return { - useI18n: jest.fn(() => { - return { - t: (str: string) => str, - } - }), - } -}) - -const mockedNavigate = jest.fn() -jest.mock('react-router-dom', () => ({ - ...jest.requireActual('react-router-dom'), - useNavigate: () => mockedNavigate, -})) - -describe('DuelError component', () => { - it('should be rendered correctly', () => { - const component = shallow(<DuelError />).getElement() - expect(component).toMatchSnapshot() - }) -}) diff --git a/src/components/Duel/DuelError/DuelError.spec.tsx b/src/components/Duel/DuelError/DuelError.spec.tsx new file mode 100644 index 0000000000000000000000000000000000000000..c8763df63e5fbb524b73033abcabce425d044f75 --- /dev/null +++ b/src/components/Duel/DuelError/DuelError.spec.tsx @@ -0,0 +1,10 @@ +import { shallow } from 'enzyme' +import React from 'react' +import DuelError from './DuelError' + +describe('DuelError component', () => { + it('should be rendered correctly', () => { + const component = shallow(<DuelError />).getElement() + expect(component).toMatchSnapshot() + }) +}) diff --git a/src/components/Duel/DuelError.tsx b/src/components/Duel/DuelError/DuelError.tsx similarity index 100% rename from src/components/Duel/DuelError.tsx rename to src/components/Duel/DuelError/DuelError.tsx diff --git a/src/components/Duel/__snapshots__/DuelError.spec.tsx.snap b/src/components/Duel/DuelError/__snapshots__/DuelError.spec.tsx.snap similarity index 100% rename from src/components/Duel/__snapshots__/DuelError.spec.tsx.snap rename to src/components/Duel/DuelError/__snapshots__/DuelError.spec.tsx.snap diff --git a/src/components/Duel/duelError.scss b/src/components/Duel/DuelError/duelError.scss similarity index 89% rename from src/components/Duel/duelError.scss rename to src/components/Duel/DuelError/duelError.scss index 870895cd6a79ccdebd718fccd9ea835bd5d6c5c0..b51f25abb394f5c3a0289d844872621613b5f13b 100644 --- a/src/components/Duel/duelError.scss +++ b/src/components/Duel/DuelError/duelError.scss @@ -1,4 +1,4 @@ -@import '../../styles/base/color'; +@import 'src/styles/base/color'; .duel-error-container { display: flex; diff --git a/src/components/Duel/DuelOngoing.spec.tsx b/src/components/Duel/DuelOngoing.spec.tsx deleted file mode 100644 index 45ff068e8769c537eca05c35e7deb76e220d798b..0000000000000000000000000000000000000000 --- a/src/components/Duel/DuelOngoing.spec.tsx +++ /dev/null @@ -1,114 +0,0 @@ -import DuelOngoing from 'components/Duel/DuelOngoing' -import { UserChallengeState } from 'enum/userChallenge.enum' -import { mount } from 'enzyme' -import { DateTime } from 'luxon' -import { UserChallenge } from 'models' -import React from 'react' -import { Provider } from 'react-redux' -import configureStore from 'redux-mock-store' -import { challengeStateData } from '../../../tests/__mocks__/challengeStateData.mock' -import { globalStateData } from '../../../tests/__mocks__/globalStateData.mock' -import { waitForComponentToPaint } from '../../../tests/__mocks__/testUtils' -import { userChallengeData } from '../../../tests/__mocks__/userChallengeData.mock' -import DuelResultModal from './DuelResultModal' - -jest.mock('cozy-ui/transpiled/react/I18n', () => { - return { - useI18n: jest.fn(() => { - return { - t: (str: string) => str, - } - }), - } -}) - -const mockUserChallengeUpdateFlag = jest.fn() -const mockIsChallengeDone = jest.fn() -jest.mock('services/challenge.service', () => { - return jest.fn(() => { - return { - updateUserChallenge: mockUserChallengeUpdateFlag, - isChallengeDone: mockIsChallengeDone, - } - }) -}) - -const mockHistoryPush = jest.fn() -jest.mock('react-router-dom', () => ({ - ...jest.requireActual('react-router-dom'), - useNavigate: () => ({ - push: mockHistoryPush, - }), -})) -const mockImportIconById = jest.fn() -const mockFormatNumberValues = jest.fn() -jest.mock('utils/utils', () => { - return { - importIconById: jest.fn(() => { - return mockImportIconById - }), - formatNumberValues: jest.fn(() => { - return mockFormatNumberValues - }), - } -}) -jest.mock('components/Duel/DuelChart', () => 'mock-duelchart') -jest.mock('components/Duel/DuelResultModal', () => 'mock-duelModal') - -const mockStore = configureStore([]) - -describe('DuelOngoing component', () => { - it('should be rendered correctly', async () => { - const store = mockStore({ - ecolyo: { - global: globalStateData, - challenge: challengeStateData, - }, - }) - mockIsChallengeDone.mockResolvedValue({ - isDone: false, - isWin: false, - isEmpty: false, - }) - mockFormatNumberValues.mockReturnValue('20') - const wrapper = mount( - <Provider store={store}> - <DuelOngoing userChallenge={userChallengeData[0]} /> - </Provider> - ) - await waitForComponentToPaint(wrapper) - expect(wrapper.find('.duel-title').text()).toEqual( - userChallengeData[1].duel.title - ) - expect(wrapper.find('.duel-goal').exists()).toBeTruthy() - expect(wrapper.find('.duel-consumption').exists()).toBeTruthy() - expect(wrapper.find('.duel-chart').exists()).toBeTruthy() - expect(wrapper.find('.caption-icon').exists()).toBeTruthy() - }) - - it('should display the result Modal when duel is done', async () => { - const store = mockStore({ - ecolyo: { - global: globalStateData, - challenge: challengeStateData, - }, - }) - const updatedUserChallenge: UserChallenge = { - ...userChallengeData[0], - state: UserChallengeState.DUEL, - startDate: DateTime.local().setZone('utc', { keepLocalTime: true }), - } - mockIsChallengeDone.mockResolvedValue({ - isDone: true, - isWin: true, - }) - mockUserChallengeUpdateFlag.mockResolvedValue(updatedUserChallenge) - const wrapper = mount( - <Provider store={store}> - <DuelOngoing userChallenge={updatedUserChallenge} /> - </Provider> - ) - await waitForComponentToPaint(wrapper) - expect(wrapper.find(DuelResultModal).exists()).toBeTruthy() - }) -}) diff --git a/src/components/Duel/DuelOngoing/DuelOngoing.spec.tsx b/src/components/Duel/DuelOngoing/DuelOngoing.spec.tsx new file mode 100644 index 0000000000000000000000000000000000000000..2f9eb9c8db8afaa204d5f76f903226a6592ed7e4 --- /dev/null +++ b/src/components/Duel/DuelOngoing/DuelOngoing.spec.tsx @@ -0,0 +1,70 @@ +import { UserChallengeState } from 'enums' +import { mount } from 'enzyme' +import { DateTime } from 'luxon' +import { UserChallenge } from 'models' +import React from 'react' +import { Provider } from 'react-redux' +import { createMockEcolyoStore } from 'tests/__mocks__/store' +import { waitForComponentToPaint } from 'tests/__mocks__/testUtils' +import { userChallengeData } from 'tests/__mocks__/userChallengeData.mock' +import DuelResultModal from '../DuelResultModal/DuelResultModal' +import DuelOngoing from './DuelOngoing' + +const mockUserChallengeUpdateFlag = jest.fn() +const mockIsChallengeDone = jest.fn() +jest.mock('services/challenge.service', () => { + return jest.fn(() => ({ + updateUserChallenge: mockUserChallengeUpdateFlag, + isChallengeDone: mockIsChallengeDone, + })) +}) + +jest.mock('components/Duel/DuelChart/DuelChart', () => 'mock-duelchart') +jest.mock( + 'components/Duel/DuelResultModal/DuelResultModal', + () => 'mock-duelModal' +) + +describe('DuelOngoing component', () => { + const store = createMockEcolyoStore() + it('should be rendered correctly', async () => { + mockIsChallengeDone.mockResolvedValue({ + isDone: false, + isWin: false, + isEmpty: false, + }) + const wrapper = mount( + <Provider store={store}> + <DuelOngoing userChallenge={userChallengeData[0]} /> + </Provider> + ) + await waitForComponentToPaint(wrapper) + expect(wrapper.find('.duel-title').text()).toEqual( + userChallengeData[1].duel.title + ) + expect(wrapper.find('.duel-goal').exists()).toBeTruthy() + expect(wrapper.find('.duel-consumption').exists()).toBeTruthy() + expect(wrapper.find('.duel-chart').exists()).toBeTruthy() + expect(wrapper.find('.caption-icon').exists()).toBeTruthy() + }) + + it('should display the result Modal when duel is done', async () => { + const updatedUserChallenge: UserChallenge = { + ...userChallengeData[0], + state: UserChallengeState.DUEL, + startDate: DateTime.local().setZone('utc', { keepLocalTime: true }), + } + mockIsChallengeDone.mockResolvedValue({ + isDone: true, + isWin: true, + }) + mockUserChallengeUpdateFlag.mockResolvedValue(updatedUserChallenge) + const wrapper = mount( + <Provider store={store}> + <DuelOngoing userChallenge={updatedUserChallenge} /> + </Provider> + ) + await waitForComponentToPaint(wrapper) + expect(wrapper.find(DuelResultModal).exists()).toBeTruthy() + }) +}) diff --git a/src/components/Duel/DuelOngoing.tsx b/src/components/Duel/DuelOngoing/DuelOngoing.tsx similarity index 84% rename from src/components/Duel/DuelOngoing.tsx rename to src/components/Duel/DuelOngoing/DuelOngoing.tsx index 2b9eef56d7f14ae68c3c88dd54efa43485acc919..dc8073ada3b6b20a648693155d83922dac95a69d 100644 --- a/src/components/Duel/DuelOngoing.tsx +++ b/src/components/Duel/DuelOngoing/DuelOngoing.tsx @@ -2,38 +2,30 @@ import CaptionAverageIcon from 'assets/icons/visu/duel/captionAverage.svg' import CaptionConsumptionIcon from 'assets/icons/visu/duel/captionConsumption.svg' import CaptionIncomingIcon from 'assets/icons/visu/duel/captionIncoming.svg' import StyledIcon from 'components/CommonKit/Icon/StyledIcon' -import DuelChart from 'components/Duel/DuelChart' -import DuelResultModal from 'components/Duel/DuelResultModal' -import LastDuelModal from 'components/Duel/lastDuelModal' import { useChartResize } from 'components/Hooks/useChartResize' -import { Client, useClient } from 'cozy-client' +import { useClient } from 'cozy-client' import { useI18n } from 'cozy-ui/transpiled/react/I18n' -import { UsageEventType } from 'enum/usageEvent.enum' import { + UsageEventType, UserChallengeSuccess, UserChallengeUpdateFlag, -} from 'enum/userChallenge.enum' -import { UserDuelState } from 'enum/userDuel.enum' + UserDuelState, +} from 'enums' import { Dataload, UserChallenge, UserDuel } from 'models' -import React, { - Dispatch, - useCallback, - useEffect, - useMemo, - useRef, - useState, -} from 'react' -import { useDispatch, useSelector } from 'react-redux' +import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react' import { useNavigate } from 'react-router-dom' import ChallengeService from 'services/challenge.service' import UsageEventService from 'services/usageEvent.service' -import { AppActionsTypes, AppStore } from 'store' import { unlockNextUserChallenge, updateUserChallengeList, } from 'store/challenge/challenge.slice' -import { toggleChallengeDuelNotification } from 'store/global/global.actions' +import { toggleChallengeDuelNotification } from 'store/global/global.slice' +import { useAppDispatch, useAppSelector } from 'store/hooks' import { formatNumberValues } from 'utils/utils' +import DuelChart from '../DuelChart/DuelChart' +import DuelResultModal from '../DuelResultModal/DuelResultModal' +import LastDuelModal from '../LastDuelModal/lastDuelModal' import './duelOngoing.scss' interface DuelOngoingProps { @@ -42,12 +34,12 @@ interface DuelOngoingProps { } const DuelOngoing = ({ userChallenge, isFinished }: DuelOngoingProps) => { - const client: Client = useClient() const { t } = useI18n() - const { currentDataload, userChallengeList } = useSelector( - (state: AppStore) => state.ecolyo.challenge + const client = useClient() + const { currentDataload, userChallengeList } = useAppSelector( + state => state.ecolyo.challenge ) - const dispatch = useDispatch<Dispatch<AppActionsTypes>>() + const dispatch = useAppDispatch() const navigate = useNavigate() const [resultModal, setResultModal] = useState<boolean>(false) const [winChallenge, setWinChallenge] = useState<boolean>(false) @@ -107,10 +99,6 @@ const DuelOngoing = ({ userChallenge, isFinished }: DuelOngoingProps) => { navigate, ]) - const setLastResult = useCallback(async () => { - navigate('/challenges') - }, [navigate]) - useEffect(() => { let subscribed = true async function setChallengeResult() { @@ -160,14 +148,12 @@ const DuelOngoing = ({ userChallenge, isFinished }: DuelOngoingProps) => { <div className="duel-goal text-18-normal"> {t('duel.goal1', { durationInDays, - // eslint-disable-next-line camelcase - smart_count: durationInDays, + smartCount: durationInDays, })} <span> </span> {t('duel.goal2', { title, - // eslint-disable-next-line camelcase - smart_count: title, + smartCount: title, })} </div> )} @@ -216,7 +202,10 @@ const DuelOngoing = ({ userChallenge, isFinished }: DuelOngoingProps) => { win={winChallenge} handleCloseClick={setResult} /> - <LastDuelModal open={isLastDuel} handleCloseClick={setLastResult} /> + <LastDuelModal + open={isLastDuel} + handleCloseClick={() => navigate('/challenges')} + /> </> ) } diff --git a/src/components/Duel/duelOngoing.scss b/src/components/Duel/DuelOngoing/duelOngoing.scss similarity index 91% rename from src/components/Duel/duelOngoing.scss rename to src/components/Duel/DuelOngoing/duelOngoing.scss index 5ac9623f753e25d3962a885299f3843bb43411cf..27de1c0bfe3b85505e63a744e64b7d1ebbc0a43c 100644 --- a/src/components/Duel/duelOngoing.scss +++ b/src/components/Duel/DuelOngoing/duelOngoing.scss @@ -1,5 +1,5 @@ -@import '../../styles/base/color'; -@import '../../styles/base/breakpoint'; +@import 'src/styles/base/color'; +@import 'src/styles/base/breakpoint'; .duel-ongoing-container { display: flex; diff --git a/src/components/Duel/DuelResultModal.spec.tsx b/src/components/Duel/DuelResultModal.spec.tsx deleted file mode 100644 index 42447533ee09f713330965e1a46d75f9629b7244..0000000000000000000000000000000000000000 --- a/src/components/Duel/DuelResultModal.spec.tsx +++ /dev/null @@ -1,81 +0,0 @@ -import { mount } from 'enzyme' -import toJson from 'enzyme-to-json' -import React from 'react' -import { Provider } from 'react-redux' -import configureStore from 'redux-mock-store' -import { globalStateData } from '../../../tests/__mocks__/globalStateData.mock' -import { profileData } from '../../../tests/__mocks__/profileData.mock' -import { waitForComponentToPaint } from '../../../tests/__mocks__/testUtils' -import { userChallengeData } from '../../../tests/__mocks__/userChallengeData.mock' -import DuelResultModal from './DuelResultModal' - -jest.mock('cozy-ui/transpiled/react/I18n', () => { - return { - useI18n: jest.fn(() => { - return { - t: (str: string) => str, - } - }), - } -}) -const mockImportIconById = jest.fn() -const mockFormatNumberValues = jest.fn() -jest.mock('utils/utils', () => { - return { - importIconById: jest.fn(() => { - return mockImportIconById - }), - formatNumberValues: jest.fn(() => { - return mockFormatNumberValues - }), - } -}) -const mockStore = configureStore([]) - -describe('DuelResultModal component', () => { - it('should render correctly', async () => { - const store = mockStore({ - ecolyo: { - challenge: userChallengeData[1], - global: { ...globalStateData, fluidTypes: [0, 1, 2] }, - profile: profileData, - }, - }) - mockImportIconById.mockReturnValue('') - const wrapper = mount( - <Provider store={store}> - <DuelResultModal - open={true} - handleCloseClick={jest.fn()} - userChallenge={userChallengeData[1]} - win={true} - /> - </Provider> - ) - await waitForComponentToPaint(wrapper) - expect(toJson(wrapper)).toMatchSnapshot() - }) - it('should render a loss modal', async () => { - const store = mockStore({ - ecolyo: { - challenge: userChallengeData[1], - global: { ...globalStateData, fluidTypes: [0, 1, 2] }, - profile: profileData, - }, - }) - mockImportIconById.mockReturnValue('') - - const wrapper = mount( - <Provider store={store}> - <DuelResultModal - open={true} - handleCloseClick={jest.fn()} - userChallenge={userChallengeData[1]} - win={false} - /> - </Provider> - ) - await waitForComponentToPaint(wrapper) - expect(wrapper.find('.title').text()).toBe('duel_result_modal.lost.title') - }) -}) diff --git a/src/components/Duel/DuelResultModal/DuelResultModal.spec.tsx b/src/components/Duel/DuelResultModal/DuelResultModal.spec.tsx new file mode 100644 index 0000000000000000000000000000000000000000..4a73f4cf35e6d2c5551678bb6a8639c2fdf4607c --- /dev/null +++ b/src/components/Duel/DuelResultModal/DuelResultModal.spec.tsx @@ -0,0 +1,33 @@ +import { mount } from 'enzyme' +import toJson from 'enzyme-to-json' +import React from 'react' +import { waitForComponentToPaint } from 'tests/__mocks__/testUtils' +import { userChallengeData } from 'tests/__mocks__/userChallengeData.mock' +import DuelResultModal from './DuelResultModal' + +describe('DuelResultModal component', () => { + it('should render correctly', async () => { + const wrapper = mount( + <DuelResultModal + open={true} + handleCloseClick={jest.fn()} + userChallenge={userChallengeData[1]} + win={true} + /> + ) + await waitForComponentToPaint(wrapper) + expect(toJson(wrapper)).toMatchSnapshot() + }) + it('should render a loss modal', async () => { + const wrapper = mount( + <DuelResultModal + open={true} + handleCloseClick={jest.fn()} + userChallenge={userChallengeData[1]} + win={false} + /> + ) + await waitForComponentToPaint(wrapper) + expect(wrapper.find('.title').text()).toBe('duel_result_modal.lost.title') + }) +}) diff --git a/src/components/Duel/DuelResultModal.tsx b/src/components/Duel/DuelResultModal/DuelResultModal.tsx similarity index 67% rename from src/components/Duel/DuelResultModal.tsx rename to src/components/Duel/DuelResultModal/DuelResultModal.tsx index 3295124400eefc2004957b1540929be235aa229f..b6d946bf69d5cdeac94f3439e7fafcef4f06bff2 100644 --- a/src/components/Duel/DuelResultModal.tsx +++ b/src/components/Duel/DuelResultModal/DuelResultModal.tsx @@ -4,7 +4,7 @@ import challengeWon from 'assets/icons/visu/duelResult/challengeWon.svg' import defaultIcon from 'assets/icons/visu/duelResult/default.svg' import { useI18n } from 'cozy-ui/transpiled/react/I18n' import Icon from 'cozy-ui/transpiled/react/Icon' -import { UserChallenge } from 'models/challenge.model' +import { UserChallenge } from 'models' import React, { useEffect, useState } from 'react' import { formatNumberValues, importIconById } from 'utils/utils' import './duelResultModal.scss' @@ -25,24 +25,18 @@ const DuelResultModal = ({ const { t } = useI18n() const [winIcon, setWinIcon] = useState<string>(defaultIcon) const [lossIcon, setLossIcon] = useState<string>(defaultIcon) - const result: string | number = formatNumberValues( + const result = formatNumberValues( Math.abs(userChallenge.duel.threshold - userChallenge.duel.userConsumption) ) + const statusKey = win ? 'success' : 'lost' + useEffect(() => { async function handleEcogestureIcon() { const icon = await importIconById(userChallenge.id + '-1', 'duelResult') - if (icon) { - setWinIcon(icon) - } else { - setWinIcon(defaultIcon) - } + setWinIcon(icon || defaultIcon) const icon2 = await importIconById(userChallenge.id + '-0', 'duelResult') - if (icon2) { - setLossIcon(icon2) - } else { - setLossIcon(defaultIcon) - } + setLossIcon(icon2 || defaultIcon) } handleEcogestureIcon() }, [userChallenge]) @@ -51,13 +45,13 @@ const DuelResultModal = ({ <Dialog open={open} onClose={handleCloseClick} - aria-labelledby={'accessibility-title'} + aria-labelledby="accessibility-title" classes={{ root: 'modal-root', paper: 'modal-paper blue-border', }} > - <div id={'accessibility-title'}> + <div id="accessibility-title"> {t('duel_result_modal.accessibility.window_title')} </div> <div className="duel-result-modal-root "> @@ -72,34 +66,26 @@ const DuelResultModal = ({ /> </div> <div className="text-28-normal-uppercase title"> - {win - ? t('duel_result_modal.sucess.title') - : t('duel_result_modal.lost.title')} + {t(`duel_result_modal.${statusKey}.title`)} </div> - <div className="text-18-normal"> - {win - ? t('duel_result_modal.sucess.message1') + result + ' €' - : t('duel_result_modal.lost.message1') + result + ' €'} + <div className="text-18-bold"> + {t(`duel_result_modal.${statusKey}.message1`, { value: result })} </div> - <div className="text-18-normal"> - {win - ? t('duel_result_modal.sucess.message2') + userChallenge.title - : t('duel_result_modal.lost.message2') + - userChallenge.title + - '...'} + <div className="text-18-bold"> + {t(`duel_result_modal.${statusKey}.message2`, { + title: userChallenge.title, + })} </div> <Button aria-label={t('duel_result_modal.accessibility.button_validate')} - className="button" + className="buttonCloseModal" onClick={handleCloseClick} classes={{ root: 'btn-secondary-negative', label: 'text-16-normal', }} > - {win - ? t('duel_result_modal.sucess.button_validate') - : t('duel_result_modal.lost.button_validate')} + {t(`duel_result_modal.${statusKey}.button_validate`)} </Button> </div> </Dialog> diff --git a/src/components/Duel/DuelResultModal/__snapshots__/DuelResultModal.spec.tsx.snap b/src/components/Duel/DuelResultModal/__snapshots__/DuelResultModal.spec.tsx.snap new file mode 100644 index 0000000000000000000000000000000000000000..c56eab4eef66848d8bb71598d8b4557e534f5822 --- /dev/null +++ b/src/components/Duel/DuelResultModal/__snapshots__/DuelResultModal.spec.tsx.snap @@ -0,0 +1,1045 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`DuelResultModal component should render correctly 1`] = ` +<DuelResultModal + handleCloseClick={[MockFunction]} + open={true} + userChallenge={ + Object { + "action": Object { + "ecogesture": null, + "startDate": null, + "state": 0, + }, + "description": "Description challenge 2", + "duel": Object { + "description": "Je parie un ours polaire que vous ne pouvez pas consommer moins que #CONSUMPTION € en 1 semaine", + "duration": "P30D", + "fluidTypes": Array [], + "id": "DUEL001", + "startDate": null, + "state": 0, + "threshold": 0, + "title": "Title DUEL001", + "userConsumption": 0, + }, + "endingDate": null, + "exploration": Object { + "complementary_description": "Refaire un tour dans son profil si déjà fait", + "date": null, + "description": "Avoir complété son profil", + "ecogesture_id": "", + "fluid_condition": Array [], + "id": "EXPLORATION001", + "message_success": "Vous avez complété votre profil ou refait un tour dans votre profil", + "progress": 0, + "state": 0, + "target": 1, + "type": 1, + }, + "id": "CHALLENGE0002", + "progress": Object { + "actionProgress": 0, + "explorationProgress": 0, + "quizProgress": 0, + }, + "quiz": Object { + "customQuestion": Object { + "interval": 20, + "period": Object {}, + "questionLabel": "Custom1", + "result": 0, + "singleFluid": false, + "timeStep": 20, + "type": 0, + }, + "id": "QUIZ001", + "questions": Array [ + Object { + "answers": Array [ + Object { + "answerLabel": "86 km", + "isTrue": true, + }, + Object { + "answerLabel": "78 km", + "isTrue": false, + }, + Object { + "answerLabel": "56 km", + "isTrue": false, + }, + ], + "explanation": "L’aqueduc du Gier est un des aqueducs antiques de Lyon desservant la ville antique de Lugdunum. Avec ses 86 km il est le plus long des quatre aqueducs ayant alimenté la ville en eau, et celui dont les structures sont le mieux conservées. Il doit son nom au fait qu'il puise aux sources du Gier, affluent du Rhône", + "questionLabel": "Quelle longueur faisait l’aqueduc du Gier pour acheminer l’eau sur Lyon à l’époque romaine ?", + "result": 0, + "source": "string", + }, + Object { + "answers": Array [ + Object { + "answerLabel": "1 point d’eau public pour 800 habitants.", + "isTrue": true, + }, + Object { + "answerLabel": "1 point d’eau public pour 400 habitants.", + "isTrue": false, + }, + Object { + "answerLabel": "1 point d’eau public pour 200 habitants.", + "isTrue": false, + }, + ], + "explanation": "string", + "questionLabel": "En 1800 à Lyon, combien de points d'eau y avait-il par habitants ?", + "result": 0, + "source": "string", + }, + Object { + "answers": Array [ + Object { + "answerLabel": "François Mitterrand", + "isTrue": false, + }, + Object { + "answerLabel": "Napoléon Ier", + "isTrue": true, + }, + Object { + "answerLabel": "Napoléon III", + "isTrue": false, + }, + ], + "explanation": "string", + "questionLabel": "Qui officialise la création de la Compagnie Générale des eaux ?", + "result": 0, + "source": "string", + }, + Object { + "answers": Array [ + Object { + "answerLabel": "string", + "isTrue": false, + }, + Object { + "answerLabel": "string", + "isTrue": false, + }, + Object { + "answerLabel": "Aristide Dumont", + "isTrue": true, + }, + ], + "explanation": "string", + "questionLabel": "Quel ingénieur est à l’origine du projet d’alimentation en eau en 1856 ?", + "result": 0, + "source": "string", + }, + ], + "result": 0, + "startDate": null, + "state": 0, + }, + "startDate": null, + "state": 4, + "success": 1, + "target": 15, + "title": "Challenge 2", + } + } + win={true} +> + <WithStyles(ForwardRef(Dialog)) + aria-labelledby="accessibility-title" + classes={ + Object { + "paper": "modal-paper blue-border", + "root": "modal-root", + } + } + onClose={[MockFunction]} + open={true} + > + <ForwardRef(Dialog) + aria-labelledby="accessibility-title" + classes={ + Object { + "container": "MuiDialog-container", + "paper": "MuiDialog-paper modal-paper blue-border", + "paperFullScreen": "MuiDialog-paperFullScreen", + "paperFullWidth": "MuiDialog-paperFullWidth", + "paperScrollBody": "MuiDialog-paperScrollBody", + "paperScrollPaper": "MuiDialog-paperScrollPaper", + "paperWidthFalse": "MuiDialog-paperWidthFalse", + "paperWidthLg": "MuiDialog-paperWidthLg", + "paperWidthMd": "MuiDialog-paperWidthMd", + "paperWidthSm": "MuiDialog-paperWidthSm", + "paperWidthXl": "MuiDialog-paperWidthXl", + "paperWidthXs": "MuiDialog-paperWidthXs", + "root": "MuiDialog-root modal-root", + "scrollBody": "MuiDialog-scrollBody", + "scrollPaper": "MuiDialog-scrollPaper", + } + } + onClose={[MockFunction]} + open={true} + > + <ForwardRef(Modal) + BackdropComponent={ + Object { + "$$typeof": Symbol(react.forward_ref), + "Naked": Object { + "$$typeof": Symbol(react.forward_ref), + "propTypes": Object { + "children": [Function], + "className": [Function], + "classes": [Function], + "invisible": [Function], + "open": [Function], + "transitionDuration": [Function], + }, + "render": [Function], + }, + "displayName": "WithStyles(ForwardRef(Backdrop))", + "options": Object { + "defaultTheme": Object { + "breakpoints": Object { + "between": [Function], + "down": [Function], + "keys": Array [ + "xs", + "sm", + "md", + "lg", + "xl", + ], + "only": [Function], + "up": [Function], + "values": Object { + "lg": 1280, + "md": 960, + "sm": 600, + "xl": 1920, + "xs": 0, + }, + "width": [Function], + }, + "direction": "ltr", + "mixins": Object { + "gutters": [Function], + "toolbar": Object { + "@media (min-width:0px) and (orientation: landscape)": Object { + "minHeight": 48, + }, + "@media (min-width:600px)": Object { + "minHeight": 64, + }, + "minHeight": 56, + }, + }, + "overrides": Object {}, + "palette": Object { + "action": Object { + "activatedOpacity": 0.12, + "active": "rgba(0, 0, 0, 0.54)", + "disabled": "rgba(0, 0, 0, 0.26)", + "disabledBackground": "rgba(0, 0, 0, 0.12)", + "disabledOpacity": 0.38, + "focus": "rgba(0, 0, 0, 0.12)", + "focusOpacity": 0.12, + "hover": "rgba(0, 0, 0, 0.04)", + "hoverOpacity": 0.04, + "selected": "rgba(0, 0, 0, 0.08)", + "selectedOpacity": 0.08, + }, + "augmentColor": [Function], + "background": Object { + "default": "#fafafa", + "paper": "#fff", + }, + "common": Object { + "black": "#000", + "white": "#fff", + }, + "contrastThreshold": 3, + "divider": "rgba(0, 0, 0, 0.12)", + "error": Object { + "contrastText": "#fff", + "dark": "#d32f2f", + "light": "#e57373", + "main": "#f44336", + }, + "getContrastText": [Function], + "grey": Object { + "100": "#f5f5f5", + "200": "#eeeeee", + "300": "#e0e0e0", + "400": "#bdbdbd", + "50": "#fafafa", + "500": "#9e9e9e", + "600": "#757575", + "700": "#616161", + "800": "#424242", + "900": "#212121", + "A100": "#d5d5d5", + "A200": "#aaaaaa", + "A400": "#303030", + "A700": "#616161", + }, + "info": Object { + "contrastText": "#fff", + "dark": "#1976d2", + "light": "#64b5f6", + "main": "#2196f3", + }, + "primary": Object { + "contrastText": "#fff", + "dark": "#303f9f", + "light": "#7986cb", + "main": "#3f51b5", + }, + "secondary": Object { + "contrastText": "#fff", + "dark": "#c51162", + "light": "#ff4081", + "main": "#f50057", + }, + "success": Object { + "contrastText": "rgba(0, 0, 0, 0.87)", + "dark": "#388e3c", + "light": "#81c784", + "main": "#4caf50", + }, + "text": Object { + "disabled": "rgba(0, 0, 0, 0.38)", + "hint": "rgba(0, 0, 0, 0.38)", + "primary": "rgba(0, 0, 0, 0.87)", + "secondary": "rgba(0, 0, 0, 0.54)", + }, + "tonalOffset": 0.2, + "type": "light", + "warning": Object { + "contrastText": "rgba(0, 0, 0, 0.87)", + "dark": "#f57c00", + "light": "#ffb74d", + "main": "#ff9800", + }, + }, + "props": Object {}, + "shadows": Array [ + "none", + "0px 2px 1px -1px rgba(0,0,0,0.2),0px 1px 1px 0px rgba(0,0,0,0.14),0px 1px 3px 0px rgba(0,0,0,0.12)", + "0px 3px 1px -2px rgba(0,0,0,0.2),0px 2px 2px 0px rgba(0,0,0,0.14),0px 1px 5px 0px rgba(0,0,0,0.12)", + "0px 3px 3px -2px rgba(0,0,0,0.2),0px 3px 4px 0px rgba(0,0,0,0.14),0px 1px 8px 0px rgba(0,0,0,0.12)", + "0px 2px 4px -1px rgba(0,0,0,0.2),0px 4px 5px 0px rgba(0,0,0,0.14),0px 1px 10px 0px rgba(0,0,0,0.12)", + "0px 3px 5px -1px rgba(0,0,0,0.2),0px 5px 8px 0px rgba(0,0,0,0.14),0px 1px 14px 0px rgba(0,0,0,0.12)", + "0px 3px 5px -1px rgba(0,0,0,0.2),0px 6px 10px 0px rgba(0,0,0,0.14),0px 1px 18px 0px rgba(0,0,0,0.12)", + "0px 4px 5px -2px rgba(0,0,0,0.2),0px 7px 10px 1px rgba(0,0,0,0.14),0px 2px 16px 1px rgba(0,0,0,0.12)", + "0px 5px 5px -3px rgba(0,0,0,0.2),0px 8px 10px 1px rgba(0,0,0,0.14),0px 3px 14px 2px rgba(0,0,0,0.12)", + "0px 5px 6px -3px rgba(0,0,0,0.2),0px 9px 12px 1px rgba(0,0,0,0.14),0px 3px 16px 2px rgba(0,0,0,0.12)", + "0px 6px 6px -3px rgba(0,0,0,0.2),0px 10px 14px 1px rgba(0,0,0,0.14),0px 4px 18px 3px rgba(0,0,0,0.12)", + "0px 6px 7px -4px rgba(0,0,0,0.2),0px 11px 15px 1px rgba(0,0,0,0.14),0px 4px 20px 3px rgba(0,0,0,0.12)", + "0px 7px 8px -4px rgba(0,0,0,0.2),0px 12px 17px 2px rgba(0,0,0,0.14),0px 5px 22px 4px rgba(0,0,0,0.12)", + "0px 7px 8px -4px rgba(0,0,0,0.2),0px 13px 19px 2px rgba(0,0,0,0.14),0px 5px 24px 4px rgba(0,0,0,0.12)", + "0px 7px 9px -4px rgba(0,0,0,0.2),0px 14px 21px 2px rgba(0,0,0,0.14),0px 5px 26px 4px rgba(0,0,0,0.12)", + "0px 8px 9px -5px rgba(0,0,0,0.2),0px 15px 22px 2px rgba(0,0,0,0.14),0px 6px 28px 5px rgba(0,0,0,0.12)", + "0px 8px 10px -5px rgba(0,0,0,0.2),0px 16px 24px 2px rgba(0,0,0,0.14),0px 6px 30px 5px rgba(0,0,0,0.12)", + "0px 8px 11px -5px rgba(0,0,0,0.2),0px 17px 26px 2px rgba(0,0,0,0.14),0px 6px 32px 5px rgba(0,0,0,0.12)", + "0px 9px 11px -5px rgba(0,0,0,0.2),0px 18px 28px 2px rgba(0,0,0,0.14),0px 7px 34px 6px rgba(0,0,0,0.12)", + "0px 9px 12px -6px rgba(0,0,0,0.2),0px 19px 29px 2px rgba(0,0,0,0.14),0px 7px 36px 6px rgba(0,0,0,0.12)", + "0px 10px 13px -6px rgba(0,0,0,0.2),0px 20px 31px 3px rgba(0,0,0,0.14),0px 8px 38px 7px rgba(0,0,0,0.12)", + "0px 10px 13px -6px rgba(0,0,0,0.2),0px 21px 33px 3px rgba(0,0,0,0.14),0px 8px 40px 7px rgba(0,0,0,0.12)", + "0px 10px 14px -6px rgba(0,0,0,0.2),0px 22px 35px 3px rgba(0,0,0,0.14),0px 8px 42px 7px rgba(0,0,0,0.12)", + "0px 11px 14px -7px rgba(0,0,0,0.2),0px 23px 36px 3px rgba(0,0,0,0.14),0px 9px 44px 8px rgba(0,0,0,0.12)", + "0px 11px 15px -7px rgba(0,0,0,0.2),0px 24px 38px 3px rgba(0,0,0,0.14),0px 9px 46px 8px rgba(0,0,0,0.12)", + ], + "shape": Object { + "borderRadius": 4, + }, + "spacing": [Function], + "transitions": Object { + "create": [Function], + "duration": Object { + "complex": 375, + "enteringScreen": 225, + "leavingScreen": 195, + "short": 250, + "shorter": 200, + "shortest": 150, + "standard": 300, + }, + "easing": Object { + "easeIn": "cubic-bezier(0.4, 0, 1, 1)", + "easeInOut": "cubic-bezier(0.4, 0, 0.2, 1)", + "easeOut": "cubic-bezier(0.0, 0, 0.2, 1)", + "sharp": "cubic-bezier(0.4, 0, 0.6, 1)", + }, + "getAutoHeightDuration": [Function], + }, + "typography": Object { + "body1": Object { + "fontFamily": "\\"Roboto\\", \\"Helvetica\\", \\"Arial\\", sans-serif", + "fontSize": "1rem", + "fontWeight": 400, + "letterSpacing": "0.00938em", + "lineHeight": 1.5, + }, + "body2": Object { + "fontFamily": "\\"Roboto\\", \\"Helvetica\\", \\"Arial\\", sans-serif", + "fontSize": "0.875rem", + "fontWeight": 400, + "letterSpacing": "0.01071em", + "lineHeight": 1.43, + }, + "button": Object { + "fontFamily": "\\"Roboto\\", \\"Helvetica\\", \\"Arial\\", sans-serif", + "fontSize": "0.875rem", + "fontWeight": 500, + "letterSpacing": "0.02857em", + "lineHeight": 1.75, + "textTransform": "uppercase", + }, + "caption": Object { + "fontFamily": "\\"Roboto\\", \\"Helvetica\\", \\"Arial\\", sans-serif", + "fontSize": "0.75rem", + "fontWeight": 400, + "letterSpacing": "0.03333em", + "lineHeight": 1.66, + }, + "fontFamily": "\\"Roboto\\", \\"Helvetica\\", \\"Arial\\", sans-serif", + "fontSize": 14, + "fontWeightBold": 700, + "fontWeightLight": 300, + "fontWeightMedium": 500, + "fontWeightRegular": 400, + "h1": Object { + "fontFamily": "\\"Roboto\\", \\"Helvetica\\", \\"Arial\\", sans-serif", + "fontSize": "6rem", + "fontWeight": 300, + "letterSpacing": "-0.01562em", + "lineHeight": 1.167, + }, + "h2": Object { + "fontFamily": "\\"Roboto\\", \\"Helvetica\\", \\"Arial\\", sans-serif", + "fontSize": "3.75rem", + "fontWeight": 300, + "letterSpacing": "-0.00833em", + "lineHeight": 1.2, + }, + "h3": Object { + "fontFamily": "\\"Roboto\\", \\"Helvetica\\", \\"Arial\\", sans-serif", + "fontSize": "3rem", + "fontWeight": 400, + "letterSpacing": "0em", + "lineHeight": 1.167, + }, + "h4": Object { + "fontFamily": "\\"Roboto\\", \\"Helvetica\\", \\"Arial\\", sans-serif", + "fontSize": "2.125rem", + "fontWeight": 400, + "letterSpacing": "0.00735em", + "lineHeight": 1.235, + }, + "h5": Object { + "fontFamily": "\\"Roboto\\", \\"Helvetica\\", \\"Arial\\", sans-serif", + "fontSize": "1.5rem", + "fontWeight": 400, + "letterSpacing": "0em", + "lineHeight": 1.334, + }, + "h6": Object { + "fontFamily": "\\"Roboto\\", \\"Helvetica\\", \\"Arial\\", sans-serif", + "fontSize": "1.25rem", + "fontWeight": 500, + "letterSpacing": "0.0075em", + "lineHeight": 1.6, + }, + "htmlFontSize": 16, + "overline": Object { + "fontFamily": "\\"Roboto\\", \\"Helvetica\\", \\"Arial\\", sans-serif", + "fontSize": "0.75rem", + "fontWeight": 400, + "letterSpacing": "0.08333em", + "lineHeight": 2.66, + "textTransform": "uppercase", + }, + "pxToRem": [Function], + "round": [Function], + "subtitle1": Object { + "fontFamily": "\\"Roboto\\", \\"Helvetica\\", \\"Arial\\", sans-serif", + "fontSize": "1rem", + "fontWeight": 400, + "letterSpacing": "0.00938em", + "lineHeight": 1.75, + }, + "subtitle2": Object { + "fontFamily": "\\"Roboto\\", \\"Helvetica\\", \\"Arial\\", sans-serif", + "fontSize": "0.875rem", + "fontWeight": 500, + "letterSpacing": "0.00714em", + "lineHeight": 1.57, + }, + }, + "zIndex": Object { + "appBar": 1100, + "drawer": 1200, + "mobileStepper": 1000, + "modal": 1300, + "snackbar": 1400, + "speedDial": 1050, + "tooltip": 1500, + }, + }, + "name": "MuiBackdrop", + }, + "propTypes": Object { + "classes": [Function], + "innerRef": [Function], + }, + "render": [Function], + "useStyles": [Function], + } + } + BackdropProps={ + Object { + "transitionDuration": Object { + "enter": 225, + "exit": 195, + }, + } + } + className="MuiDialog-root modal-root" + closeAfterTransition={true} + disableEscapeKeyDown={false} + onClose={[MockFunction]} + open={true} + > + <ForwardRef(Portal) + disablePortal={false} + > + <Portal + containerInfo={ + <body + style="padding-right: 0px; overflow: hidden;" + > + <div + class="MuiDialog-root modal-root" + role="presentation" + style="position: fixed; z-index: 1300; right: 0px; bottom: 0px; top: 0px; left: 0px;" + > + <div + aria-hidden="true" + class="MuiBackdrop-root" + style="opacity: 1; webkit-transition: opacity 225ms cubic-bezier(0.4, 0, 0.2, 1) 0ms; transition: opacity 225ms cubic-bezier(0.4, 0, 0.2, 1) 0ms;" + /> + <div + data-test="sentinelStart" + tabindex="0" + /> + <div + class="MuiDialog-container MuiDialog-scrollPaper" + role="none presentation" + style="opacity: 1; webkit-transition: opacity 225ms cubic-bezier(0.4, 0, 0.2, 1) 0ms; transition: opacity 225ms cubic-bezier(0.4, 0, 0.2, 1) 0ms;" + tabindex="-1" + > + <div + aria-labelledby="accessibility-title" + class="MuiPaper-root MuiDialog-paper modal-paper blue-border MuiDialog-paperScrollPaper MuiDialog-paperWidthSm MuiPaper-elevation24 MuiPaper-rounded" + role="dialog" + > + <div + id="accessibility-title" + > + duel_result_modal.accessibility.window_title + </div> + <div + class="duel-result-modal-root " + > + <div + class="imgResultContainer" + > + <svg + class="challengeWon styles__icon___23x3R" + height="300" + width="300" + > + <use + xlink:href="#test-file-stub" + /> + </svg> + <svg + class="imgResult styles__icon___23x3R" + height="180" + width="180" + > + <use + xlink:href="#test-file-stub" + /> + </svg> + </div> + <div + class="text-28-normal-uppercase title" + > + duel_result_modal.success.title + </div> + <div + class="text-18-bold" + > + duel_result_modal.success.message1 + </div> + <div + class="text-18-bold" + > + duel_result_modal.success.message2 + </div> + <button + aria-label="duel_result_modal.accessibility.button_validate" + class="MuiButtonBase-root MuiButton-root btn-secondary-negative MuiButton-text buttonCloseModal" + tabindex="0" + type="button" + > + <span + class="MuiButton-label text-16-normal" + > + duel_result_modal.success.button_validate + </span> + <span + class="MuiTouchRipple-root" + /> + </button> + </div> + </div> + </div> + <div + data-test="sentinelEnd" + tabindex="0" + /> + </div> + </body> + } + > + <div + className="MuiDialog-root modal-root" + onKeyDown={[Function]} + role="presentation" + style={ + Object { + "bottom": 0, + "left": 0, + "position": "fixed", + "right": 0, + "top": 0, + "zIndex": 1300, + } + } + > + <WithStyles(ForwardRef(Backdrop)) + onClick={[Function]} + open={true} + transitionDuration={ + Object { + "enter": 225, + "exit": 195, + } + } + > + <ForwardRef(Backdrop) + classes={ + Object { + "invisible": "MuiBackdrop-invisible", + "root": "MuiBackdrop-root", + } + } + onClick={[Function]} + open={true} + transitionDuration={ + Object { + "enter": 225, + "exit": 195, + } + } + > + <ForwardRef(Fade) + in={true} + onClick={[Function]} + timeout={ + Object { + "enter": 225, + "exit": 195, + } + } + > + <Transition + appear={true} + enter={true} + exit={true} + in={true} + mountOnEnter={false} + onClick={[Function]} + onEnter={[Function]} + onEntered={[Function]} + onEntering={[Function]} + onExit={[Function]} + onExited={[Function]} + onExiting={[Function]} + timeout={ + Object { + "enter": 225, + "exit": 195, + } + } + unmountOnExit={false} + > + <div + aria-hidden={true} + className="MuiBackdrop-root" + onClick={[Function]} + style={ + Object { + "opacity": 1, + "visibility": undefined, + } + } + /> + </Transition> + </ForwardRef(Fade)> + </ForwardRef(Backdrop)> + </WithStyles(ForwardRef(Backdrop))> + <Unstable_TrapFocus + disableAutoFocus={false} + disableEnforceFocus={false} + disableRestoreFocus={false} + getDoc={[Function]} + isEnabled={[Function]} + open={true} + > + <div + data-test="sentinelStart" + tabIndex={0} + /> + <ForwardRef(Fade) + appear={true} + in={true} + onEnter={[Function]} + onExited={[Function]} + role="none presentation" + tabIndex="-1" + timeout={ + Object { + "enter": 225, + "exit": 195, + } + } + > + <Transition + appear={true} + enter={true} + exit={true} + in={true} + mountOnEnter={false} + onEnter={[Function]} + onEntered={[Function]} + onEntering={[Function]} + onExit={[Function]} + onExited={[Function]} + onExiting={[Function]} + role="none presentation" + tabIndex="-1" + timeout={ + Object { + "enter": 225, + "exit": 195, + } + } + unmountOnExit={false} + > + <div + className="MuiDialog-container MuiDialog-scrollPaper" + onMouseDown={[Function]} + onMouseUp={[Function]} + role="none presentation" + style={ + Object { + "opacity": 1, + "visibility": undefined, + } + } + tabIndex="-1" + > + <WithStyles(ForwardRef(Paper)) + aria-labelledby="accessibility-title" + className="MuiDialog-paper modal-paper blue-border MuiDialog-paperScrollPaper MuiDialog-paperWidthSm" + elevation={24} + role="dialog" + > + <ForwardRef(Paper) + aria-labelledby="accessibility-title" + className="MuiDialog-paper modal-paper blue-border MuiDialog-paperScrollPaper MuiDialog-paperWidthSm" + classes={ + Object { + "elevation0": "MuiPaper-elevation0", + "elevation1": "MuiPaper-elevation1", + "elevation10": "MuiPaper-elevation10", + "elevation11": "MuiPaper-elevation11", + "elevation12": "MuiPaper-elevation12", + "elevation13": "MuiPaper-elevation13", + "elevation14": "MuiPaper-elevation14", + "elevation15": "MuiPaper-elevation15", + "elevation16": "MuiPaper-elevation16", + "elevation17": "MuiPaper-elevation17", + "elevation18": "MuiPaper-elevation18", + "elevation19": "MuiPaper-elevation19", + "elevation2": "MuiPaper-elevation2", + "elevation20": "MuiPaper-elevation20", + "elevation21": "MuiPaper-elevation21", + "elevation22": "MuiPaper-elevation22", + "elevation23": "MuiPaper-elevation23", + "elevation24": "MuiPaper-elevation24", + "elevation3": "MuiPaper-elevation3", + "elevation4": "MuiPaper-elevation4", + "elevation5": "MuiPaper-elevation5", + "elevation6": "MuiPaper-elevation6", + "elevation7": "MuiPaper-elevation7", + "elevation8": "MuiPaper-elevation8", + "elevation9": "MuiPaper-elevation9", + "outlined": "MuiPaper-outlined", + "root": "MuiPaper-root", + "rounded": "MuiPaper-rounded", + } + } + elevation={24} + role="dialog" + > + <div + aria-labelledby="accessibility-title" + className="MuiPaper-root MuiDialog-paper modal-paper blue-border MuiDialog-paperScrollPaper MuiDialog-paperWidthSm MuiPaper-elevation24 MuiPaper-rounded" + role="dialog" + > + <div + id="accessibility-title" + > + duel_result_modal.accessibility.window_title + </div> + <div + className="duel-result-modal-root " + > + <div + className="imgResultContainer" + > + <Icon + className="challengeWon" + icon="test-file-stub" + size={300} + spin={false} + > + <Component + className="challengeWon styles__icon___23x3R" + height={300} + style={Object {}} + width={300} + > + <svg + className="challengeWon styles__icon___23x3R" + height={300} + style={Object {}} + width={300} + > + <use + xlinkHref="#test-file-stub" + /> + </svg> + </Component> + </Icon> + <Icon + className="imgResult" + icon="test-file-stub" + size={180} + spin={false} + > + <Component + className="imgResult styles__icon___23x3R" + height={180} + style={Object {}} + width={180} + > + <svg + className="imgResult styles__icon___23x3R" + height={180} + style={Object {}} + width={180} + > + <use + xlinkHref="#test-file-stub" + /> + </svg> + </Component> + </Icon> + </div> + <div + className="text-28-normal-uppercase title" + > + duel_result_modal.success.title + </div> + <div + className="text-18-bold" + > + duel_result_modal.success.message1 + </div> + <div + className="text-18-bold" + > + duel_result_modal.success.message2 + </div> + <WithStyles(ForwardRef(Button)) + aria-label="duel_result_modal.accessibility.button_validate" + className="buttonCloseModal" + classes={ + Object { + "label": "text-16-normal", + "root": "btn-secondary-negative", + } + } + onClick={[MockFunction]} + > + <ForwardRef(Button) + aria-label="duel_result_modal.accessibility.button_validate" + className="buttonCloseModal" + classes={ + Object { + "colorInherit": "MuiButton-colorInherit", + "contained": "MuiButton-contained", + "containedPrimary": "MuiButton-containedPrimary", + "containedSecondary": "MuiButton-containedSecondary", + "containedSizeLarge": "MuiButton-containedSizeLarge", + "containedSizeSmall": "MuiButton-containedSizeSmall", + "disableElevation": "MuiButton-disableElevation", + "disabled": "Mui-disabled", + "endIcon": "MuiButton-endIcon", + "focusVisible": "Mui-focusVisible", + "fullWidth": "MuiButton-fullWidth", + "iconSizeLarge": "MuiButton-iconSizeLarge", + "iconSizeMedium": "MuiButton-iconSizeMedium", + "iconSizeSmall": "MuiButton-iconSizeSmall", + "label": "MuiButton-label text-16-normal", + "outlined": "MuiButton-outlined", + "outlinedPrimary": "MuiButton-outlinedPrimary", + "outlinedSecondary": "MuiButton-outlinedSecondary", + "outlinedSizeLarge": "MuiButton-outlinedSizeLarge", + "outlinedSizeSmall": "MuiButton-outlinedSizeSmall", + "root": "MuiButton-root btn-secondary-negative", + "sizeLarge": "MuiButton-sizeLarge", + "sizeSmall": "MuiButton-sizeSmall", + "startIcon": "MuiButton-startIcon", + "text": "MuiButton-text", + "textPrimary": "MuiButton-textPrimary", + "textSecondary": "MuiButton-textSecondary", + "textSizeLarge": "MuiButton-textSizeLarge", + "textSizeSmall": "MuiButton-textSizeSmall", + } + } + onClick={[MockFunction]} + > + <WithStyles(ForwardRef(ButtonBase)) + aria-label="duel_result_modal.accessibility.button_validate" + className="MuiButton-root btn-secondary-negative MuiButton-text buttonCloseModal" + component="button" + disabled={false} + focusRipple={true} + focusVisibleClassName="Mui-focusVisible" + onClick={[MockFunction]} + type="button" + > + <ForwardRef(ButtonBase) + aria-label="duel_result_modal.accessibility.button_validate" + className="MuiButton-root btn-secondary-negative MuiButton-text buttonCloseModal" + classes={ + Object { + "disabled": "Mui-disabled", + "focusVisible": "Mui-focusVisible", + "root": "MuiButtonBase-root", + } + } + component="button" + disabled={false} + focusRipple={true} + focusVisibleClassName="Mui-focusVisible" + onClick={[MockFunction]} + type="button" + > + <button + aria-label="duel_result_modal.accessibility.button_validate" + className="MuiButtonBase-root MuiButton-root btn-secondary-negative MuiButton-text buttonCloseModal" + disabled={false} + onBlur={[Function]} + onClick={[MockFunction]} + onDragLeave={[Function]} + onFocus={[Function]} + onKeyDown={[Function]} + onKeyUp={[Function]} + onMouseDown={[Function]} + onMouseLeave={[Function]} + onMouseUp={[Function]} + onTouchEnd={[Function]} + onTouchMove={[Function]} + onTouchStart={[Function]} + tabIndex={0} + type="button" + > + <span + className="MuiButton-label text-16-normal" + > + duel_result_modal.success.button_validate + </span> + <WithStyles(memo) + center={false} + > + <ForwardRef(TouchRipple) + center={false} + classes={ + Object { + "child": "MuiTouchRipple-child", + "childLeaving": "MuiTouchRipple-childLeaving", + "childPulsate": "MuiTouchRipple-childPulsate", + "ripple": "MuiTouchRipple-ripple", + "ripplePulsate": "MuiTouchRipple-ripplePulsate", + "rippleVisible": "MuiTouchRipple-rippleVisible", + "root": "MuiTouchRipple-root", + } + } + > + <span + className="MuiTouchRipple-root" + > + <TransitionGroup + childFactory={[Function]} + component={null} + exit={true} + /> + </span> + </ForwardRef(TouchRipple)> + </WithStyles(memo)> + </button> + </ForwardRef(ButtonBase)> + </WithStyles(ForwardRef(ButtonBase))> + </ForwardRef(Button)> + </WithStyles(ForwardRef(Button))> + </div> + </div> + </ForwardRef(Paper)> + </WithStyles(ForwardRef(Paper))> + </div> + </Transition> + </ForwardRef(Fade)> + <div + data-test="sentinelEnd" + tabIndex={0} + /> + </Unstable_TrapFocus> + </div> + </Portal> + </ForwardRef(Portal)> + </ForwardRef(Modal)> + </ForwardRef(Dialog)> + </WithStyles(ForwardRef(Dialog))> +</DuelResultModal> +`; diff --git a/src/components/Duel/duelResultModal.scss b/src/components/Duel/DuelResultModal/duelResultModal.scss similarity index 72% rename from src/components/Duel/duelResultModal.scss rename to src/components/Duel/DuelResultModal/duelResultModal.scss index ba90fa755ea6d27f55b8bdf887ca4ded86bb2154..0c34d5c749566b0d3ca14c16aef87a990e85d396 100644 --- a/src/components/Duel/duelResultModal.scss +++ b/src/components/Duel/DuelResultModal/duelResultModal.scss @@ -1,8 +1,11 @@ +@import 'src/styles/base/color'; + .duel-result-modal-root { text-align: center; overflow-x: hidden; .title { margin: 2rem 0 1rem; + color: $grey-bright; } } @@ -24,3 +27,7 @@ transform: translate(-50%, 32%); } } + +.buttonCloseModal { + margin-top: 1rem !important; +} diff --git a/src/components/Duel/DuelUnlocked.spec.tsx b/src/components/Duel/DuelUnlocked.spec.tsx deleted file mode 100644 index cf155a120faac08c69d2141685bf8e48968b2b42..0000000000000000000000000000000000000000 --- a/src/components/Duel/DuelUnlocked.spec.tsx +++ /dev/null @@ -1,111 +0,0 @@ -import Button from '@material-ui/core/Button' -import defaultIcon from 'assets/icons/visu/duel/default.svg' -import StyledIcon from 'components/CommonKit/Icon/StyledIcon' -import DuelUnlocked from 'components/Duel/DuelUnlocked' -import { FluidType } from 'enum/fluid.enum' -import { UserChallengeUpdateFlag } from 'enum/userChallenge.enum' -import { mount } from 'enzyme' -import React from 'react' -import { Provider } from 'react-redux' -import configureStore from 'redux-mock-store' -import UsageEventService from 'services/usageEvent.service' -import { formatNumberValues } from 'utils/utils' -import { globalStateData } from '../../../tests/__mocks__/globalStateData.mock' -import { userChallengeData } from '../../../tests/__mocks__/userChallengeData.mock' - -jest.mock('cozy-ui/transpiled/react/I18n', () => { - return { - useI18n: jest.fn(() => { - return { - t: (str: string) => str, - } - }), - } -}) -const mockImportIconById = jest.fn(() => defaultIcon) -const mockFormatNumberValues = jest.fn() -jest.mock('utils/utils', () => { - return { - importIconById: jest.fn(() => { - return mockImportIconById - }), - formatNumberValues: jest.fn(() => { - return mockFormatNumberValues - }), - } -}) -const mockUserChallengeUpdateFlag = jest.fn() -const mockGetUserChallengeDataload = jest.fn() -jest.mock('services/challenge.service', () => { - return jest.fn(() => { - return { - updateUserChallenge: mockUserChallengeUpdateFlag, - getUserChallengeDataload: mockGetUserChallengeDataload, - } - }) -}) - -const mockAddEvent = jest.fn() -jest.mock('services/usageEvent.service') -UsageEventService.addEvent = mockAddEvent - -const mockStore = configureStore([]) - -describe('DuelUnlocked component', () => { - beforeAll(() => { - jest.useFakeTimers() - }) - - afterAll(() => { - jest.useRealTimers() - }) - - it('should be rendered correctly', () => { - const store = mockStore({ - ecolyo: { - global: globalStateData, - }, - }) - const average: string = formatNumberValues( - userChallengeData[1].duel.threshold - ).toString() - const description: string = - '"' + - userChallengeData[1].duel.description.replace('#CONSUMPTION', average) + - '"' - const wrapper = mount( - <Provider store={store}> - <DuelUnlocked userChallenge={userChallengeData[0]} /> - </Provider> - ) - expect(wrapper.find('.duel-title').text()).toEqual( - userChallengeData[1].duel.title - ) - expect(wrapper.find(StyledIcon).exists()).toBeTruthy() - expect(wrapper.find('.duel-description').text()).toEqual(description) - expect(wrapper.find('.duel-average-info').exists()).toBeTruthy() - expect(wrapper.find('.button-start').exists()).toBeTruthy() - }) - - it('should update userChallenge when launching duel with configured fluid', () => { - const updateGlobalStoreData = { - ...globalStateData, - fluidTypes: [FluidType.ELECTRICITY], - } - const store = mockStore({ - ecolyo: { - global: updateGlobalStoreData, - }, - }) - const wrapper = mount( - <Provider store={store}> - <DuelUnlocked userChallenge={userChallengeData[0]} /> - </Provider> - ) - wrapper.find('.button-start').find(Button).simulate('click') - expect(mockUserChallengeUpdateFlag).toHaveBeenCalledWith( - userChallengeData[0], - UserChallengeUpdateFlag.DUEL_START - ) - }) -}) diff --git a/src/components/Duel/DuelUnlocked/DuelUnlocked.spec.tsx b/src/components/Duel/DuelUnlocked/DuelUnlocked.spec.tsx new file mode 100644 index 0000000000000000000000000000000000000000..822eff26b405e9e7c99bc755697de2a10d4f7583 --- /dev/null +++ b/src/components/Duel/DuelUnlocked/DuelUnlocked.spec.tsx @@ -0,0 +1,66 @@ +import Button from '@material-ui/core/Button' +import StyledIcon from 'components/CommonKit/Icon/StyledIcon' +import { FluidType, UserChallengeUpdateFlag } from 'enums' +import { mount } from 'enzyme' +import React from 'react' +import { Provider } from 'react-redux' +import { createMockEcolyoStore, mockGlobalState } from 'tests/__mocks__/store' +import { userChallengeData } from 'tests/__mocks__/userChallengeData.mock' +import { formatNumberValues } from 'utils/utils' +import DuelUnlocked from './DuelUnlocked' + +const mockUserChallengeUpdateFlag = jest.fn() +const mockGetUserChallengeDataload = jest.fn() +jest.mock('services/challenge.service', () => { + return jest.fn(() => ({ + updateUserChallenge: mockUserChallengeUpdateFlag, + getUserChallengeDataload: mockGetUserChallengeDataload, + })) +}) + +jest.mock('services/usageEvent.service') + +describe('DuelUnlocked component', () => { + const store = createMockEcolyoStore() + + it('should be rendered correctly', () => { + const average: string = formatNumberValues( + userChallengeData[1].duel.threshold + ).toString() + const description: string = + '"' + + userChallengeData[1].duel.description.replace('#CONSUMPTION', average) + + '"' + const wrapper = mount( + <Provider store={store}> + <DuelUnlocked userChallenge={userChallengeData[0]} /> + </Provider> + ) + expect(wrapper.find('.duel-title').text()).toEqual( + userChallengeData[1].duel.title + ) + expect(wrapper.find(StyledIcon).exists()).toBeTruthy() + expect(wrapper.find('.duel-description').text()).toEqual(description) + expect(wrapper.find('.duel-average-info').exists()).toBeTruthy() + expect(wrapper.find('.button-start').exists()).toBeTruthy() + }) + + it('should update userChallenge when launching duel with configured fluid', () => { + const store = createMockEcolyoStore({ + global: { + ...mockGlobalState, + fluidTypes: [FluidType.ELECTRICITY], + }, + }) + const wrapper = mount( + <Provider store={store}> + <DuelUnlocked userChallenge={userChallengeData[0]} /> + </Provider> + ) + wrapper.find('.button-start').find(Button).simulate('click') + expect(mockUserChallengeUpdateFlag).toHaveBeenCalledWith( + userChallengeData[0], + UserChallengeUpdateFlag.DUEL_START + ) + }) +}) diff --git a/src/components/Duel/DuelUnlocked.tsx b/src/components/Duel/DuelUnlocked/DuelUnlocked.tsx similarity index 80% rename from src/components/Duel/DuelUnlocked.tsx rename to src/components/Duel/DuelUnlocked/DuelUnlocked.tsx index c4b16b9e0b10dc7818ed75cbb7cdfa12a01fd4c8..c5da4d74ed98df664d3aa769f0033eb33fcd92ff 100644 --- a/src/components/Duel/DuelUnlocked.tsx +++ b/src/components/Duel/DuelUnlocked/DuelUnlocked.tsx @@ -2,24 +2,22 @@ import Button from '@material-ui/core/Button' import defaultDuelIcon from 'assets/icons/visu/challenge/CHALLENGE0001.svg' import defaultIcon from 'assets/icons/visu/duel/default.svg' import StyledIcon from 'components/CommonKit/Icon/StyledIcon' -import { Client, useClient } from 'cozy-client' +import { useClient } from 'cozy-client' import { useI18n } from 'cozy-ui/transpiled/react/I18n' -import { UsageEventType } from 'enum/usageEvent.enum' -import { UserChallengeUpdateFlag } from 'enum/userChallenge.enum' +import { UsageEventType, UserChallengeUpdateFlag } from 'enums' import { UserChallenge } from 'models' -import React, { Dispatch, useCallback, useEffect, useState } from 'react' -import { useDispatch } from 'react-redux' +import React, { useCallback, useEffect, useState } from 'react' import ChallengeService from 'services/challenge.service' import UsageEventService from 'services/usageEvent.service' -import { AppActionsTypes } from 'store' import { setChallengeConsumption } from 'store/challenge/challenge.slice' +import { useAppDispatch } from 'store/hooks' import { formatNumberValues, importIconById } from 'utils/utils' import './duelUnlocked.scss' const DuelUnlocked = ({ userChallenge }: { userChallenge: UserChallenge }) => { - const client: Client = useClient() - const dispatch = useDispatch<Dispatch<AppActionsTypes>>() const { t } = useI18n() + const client = useClient() + const dispatch = useAppDispatch() const [duelIcon, setDuelIcon] = useState(defaultIcon) const average: string = formatNumberValues( @@ -55,11 +53,7 @@ const DuelUnlocked = ({ userChallenge }: { userChallenge: UserChallenge }) => { useEffect(() => { async function handleEcogestureIcon() { const icon = await importIconById(userChallenge.id, 'challenge') - if (icon) { - setDuelIcon(icon) - } else { - setDuelIcon(defaultDuelIcon) - } + setDuelIcon(icon || defaultDuelIcon) } handleEcogestureIcon() }, [userChallenge]) @@ -73,11 +67,10 @@ const DuelUnlocked = ({ userChallenge }: { userChallenge: UserChallenge }) => { {userChallenge.duel.title} </div> <div className="duel-average-info text-18-normal"> - {`${t('duel.average_info', { + {t('duel.average_info', { average, - // eslint-disable-next-line camelcase - smart_count: average, - })}`} + smartCount: average, + })} </div> <div className="button-start"> <Button diff --git a/src/components/Duel/duelUnlocked.scss b/src/components/Duel/DuelUnlocked/duelUnlocked.scss similarity index 76% rename from src/components/Duel/duelUnlocked.scss rename to src/components/Duel/DuelUnlocked/duelUnlocked.scss index 077c1eed988fa2c8797b9610d87350a3b3eefd71..a7a72ad803bc2bd2584c2ee865c954d14d4cf10a 100644 --- a/src/components/Duel/duelUnlocked.scss +++ b/src/components/Duel/DuelUnlocked/duelUnlocked.scss @@ -1,4 +1,4 @@ -@import '../../styles/base/color'; +@import 'src/styles/base/color'; .duel-unlocked-container { display: flex; @@ -25,4 +25,10 @@ } .button-start { margin-top: 1rem; + width: 100%; + max-width: 175px; +} +button.btn-secondary-negative { + margin: 0; + padding: 0.5rem; } diff --git a/src/components/Duel/DuelView.spec.tsx b/src/components/Duel/DuelView.spec.tsx index 4f079d5f26c4e3c06e912b6c8710856be9e95987..9908eb501c43b047fdac9f60389f55d9c344847e 100644 --- a/src/components/Duel/DuelView.spec.tsx +++ b/src/components/Duel/DuelView.spec.tsx @@ -1,33 +1,34 @@ import DuelView from 'components/Duel/DuelView' -import { UserChallengeState } from 'enum/userChallenge.enum' -import { UserDuelState } from 'enum/userDuel.enum' -import { shallow } from 'enzyme' +import { UserChallengeState, UserDuelState } from 'enums' +import { mount } from 'enzyme' import React from 'react' -import * as reactRedux from 'react-redux' -import { challengeStateData } from '../../../tests/__mocks__/challengeStateData.mock' -import { userChallengeData } from '../../../tests/__mocks__/userChallengeData.mock' -import DuelError from './DuelError' -import DuelOngoing from './DuelOngoing' -import DuelUnlocked from './DuelUnlocked' +import { Provider } from 'react-redux' +import { challengeStateData } from 'tests/__mocks__/challengeStateData.mock' +import { createMockEcolyoStore, mockChartState } from 'tests/__mocks__/store' +import { userChallengeData } from 'tests/__mocks__/userChallengeData.mock' +import DuelError from './DuelError/DuelError' +import DuelOngoing from './DuelOngoing/DuelOngoing' +import DuelUnlocked from './DuelUnlocked/DuelUnlocked' jest.mock('components/Header/CozyBar', () => 'mock-cozybar') jest.mock('components/Header/Header', () => 'mock-header') jest.mock('components/Content/Content', () => 'mock-content') -const mockUseSelector = jest.spyOn(reactRedux, 'useSelector') - -const mockedNavigate = jest.fn() jest.mock('react-router-dom', () => ({ useLocation: () => ({ search: '?id=CHALLENGE0002', }), - useNavigate: () => mockedNavigate, + useNavigate: () => jest.fn(), })) describe('DuelView component', () => { it('should be rendered with DuelError component when no current challenge', () => { - mockUseSelector.mockReturnValue(challengeStateData) - const wrapper = shallow(<DuelView />) + const store = createMockEcolyoStore({ challenge: challengeStateData }) + const wrapper = mount( + <Provider store={store}> + <DuelView /> + </Provider> + ) expect(wrapper.find(DuelError).exists()).toBeTruthy() }) @@ -43,8 +44,15 @@ describe('DuelView component', () => { currentChallenge: updatedUserChallenge, } updatedChallengeState.userChallengeList[1] = updatedUserChallenge - mockUseSelector.mockReturnValue(updatedChallengeState) - const wrapper = shallow(<DuelView />) + const store = createMockEcolyoStore({ + challenge: updatedChallengeState, + chart: mockChartState, + }) + const wrapper = mount( + <Provider store={store}> + <DuelView /> + </Provider> + ) expect(wrapper.find(DuelOngoing).exists()).toBeTruthy() }) @@ -60,12 +68,16 @@ describe('DuelView component', () => { currentChallenge: updatedUserChallenge, } updatedChallengeState.userChallengeList[1] = updatedUserChallenge - mockUseSelector.mockReturnValue(updatedChallengeState) - const wrapper = shallow(<DuelView />) + const store = createMockEcolyoStore({ challenge: updatedChallengeState }) + const wrapper = mount( + <Provider store={store}> + <DuelView /> + </Provider> + ) expect(wrapper.find(DuelError).exists()).toBeTruthy() }) - it('should be rendered with DuelError component when current challenge with state != duel ', () => { + it('should be rendered with DuelError component when current challenge with state != duel', () => { const updatedUserChallenge = { ...userChallengeData[1], state: UserChallengeState.ONGOING, @@ -76,8 +88,12 @@ describe('DuelView component', () => { currentChallenge: updatedUserChallenge, } updatedChallengeState.userChallengeList[1] = updatedUserChallenge - mockUseSelector.mockReturnValue(updatedChallengeState) - const wrapper = shallow(<DuelView />) + const store = createMockEcolyoStore({ challenge: updatedChallengeState }) + const wrapper = mount( + <Provider store={store}> + <DuelView /> + </Provider> + ) expect(wrapper.find(DuelError).exists()).toBeTruthy() }) @@ -93,8 +109,12 @@ describe('DuelView component', () => { currentChallenge: updatedUserChallenge, } updatedChallengeState.userChallengeList[1] = updatedUserChallenge - mockUseSelector.mockReturnValue(updatedChallengeState) - const wrapper = shallow(<DuelView />) + const store = createMockEcolyoStore({ challenge: updatedChallengeState }) + const wrapper = mount( + <Provider store={store}> + <DuelView /> + </Provider> + ) expect(wrapper.find(DuelUnlocked).exists()).toBeTruthy() }) @@ -110,8 +130,15 @@ describe('DuelView component', () => { currentChallenge: updatedUserChallenge, } updatedChallengeState.userChallengeList[1] = updatedUserChallenge - mockUseSelector.mockReturnValue(updatedChallengeState) - const wrapper = shallow(<DuelView />) + const store = createMockEcolyoStore({ + challenge: updatedChallengeState, + chart: mockChartState, + }) + const wrapper = mount( + <Provider store={store}> + <DuelView /> + </Provider> + ) expect(wrapper.find(DuelOngoing).exists()).toBeTruthy() }) }) diff --git a/src/components/Duel/DuelView.tsx b/src/components/Duel/DuelView.tsx index b5a269f172684c9e3c6bd968026265ff6e6b911f..5e29d720c8f6bd2e45a47d42b0a722f5178fbf3b 100644 --- a/src/components/Duel/DuelView.tsx +++ b/src/components/Duel/DuelView.tsx @@ -1,32 +1,25 @@ import Content from 'components/Content/Content' -import DuelError from 'components/Duel/DuelError' -import DuelUnlocked from 'components/Duel/DuelUnlocked' import CozyBar from 'components/Header/CozyBar' import Header from 'components/Header/Header' -import { UserChallengeState } from 'enum/userChallenge.enum' -import { UserDuelState } from 'enum/userDuel.enum' +import { UserChallengeState, UserDuelState } from 'enums' import { UserChallenge } from 'models' -import React, { useCallback, useState } from 'react' -import { useSelector } from 'react-redux' +import React, { useState } from 'react' import { useLocation, useNavigate } from 'react-router-dom' -import { AppStore } from 'store' -import DuelEmptyValueModal from './DuelEmptyValueModal' -import DuelOngoing from './DuelOngoing' +import { useAppSelector } from 'store/hooks' +import DuelEmptyValueModal from './DuelEmptyValueModal/DuelEmptyValueModal' +import DuelError from './DuelError/DuelError' +import DuelOngoing from './DuelOngoing/DuelOngoing' +import DuelUnlocked from './DuelUnlocked/DuelUnlocked' const DuelView = () => { + const navigate = useNavigate() + const { userChallengeList } = useAppSelector(state => state.ecolyo.challenge) const [headerHeight, setHeaderHeight] = useState<number>(0) - const { userChallengeList } = useSelector( - (state: AppStore) => state.ecolyo.challenge - ) const id = new URLSearchParams(useLocation().search).get('id') const challengeToDisplay: UserChallenge | undefined = userChallengeList.find( challenge => challenge.id === id ) - const navigate = useNavigate() - const defineHeaderHeight = useCallback((height: number) => { - setHeaderHeight(height) - }, []) const goBackToChallenge = () => { navigate('/challenges') } @@ -52,13 +45,13 @@ const DuelView = () => { return ( <> - <CozyBar titleKey={'common.title_duel'} displayBackArrow={true} /> + <CozyBar titleKey="common.title_duel" displayBackArrow={true} /> <Header - setHeaderHeight={defineHeaderHeight} - desktopTitleKey={'common.title_duel'} + setHeaderHeight={setHeaderHeight} + desktopTitleKey="common.title_duel" displayBackArrow={true} /> - <Content height={headerHeight}> + <Content heightOffset={headerHeight}> <div> {challengeToDisplay && (challengeToDisplay.state === UserChallengeState.DUEL || diff --git a/src/components/Duel/__snapshots__/lastDuelModal.spec.tsx.snap b/src/components/Duel/LastDuelModal/__snapshots__/lastDuelModal.spec.tsx.snap similarity index 100% rename from src/components/Duel/__snapshots__/lastDuelModal.spec.tsx.snap rename to src/components/Duel/LastDuelModal/__snapshots__/lastDuelModal.spec.tsx.snap diff --git a/src/components/Duel/lastDuelModal.scss b/src/components/Duel/LastDuelModal/lastDuelModal.scss similarity index 84% rename from src/components/Duel/lastDuelModal.scss rename to src/components/Duel/LastDuelModal/lastDuelModal.scss index dcd32cb494061695845daf6986f9f69eefb09aa6..05a14432af96c886a876407a8e54f65b0d6f4c60 100644 --- a/src/components/Duel/lastDuelModal.scss +++ b/src/components/Duel/LastDuelModal/lastDuelModal.scss @@ -1,4 +1,4 @@ -@import '../../styles/base/color'; +@import 'src/styles/base/color'; .duel-last-modal-root { text-align: center; diff --git a/src/components/Duel/lastDuelModal.spec.tsx b/src/components/Duel/LastDuelModal/lastDuelModal.spec.tsx similarity index 63% rename from src/components/Duel/lastDuelModal.spec.tsx rename to src/components/Duel/LastDuelModal/lastDuelModal.spec.tsx index f0b613baf54bda9ad27aeb6d248071f35b1cf210..ed1f8b01bfd824f6031c9d867e765570efac1432 100644 --- a/src/components/Duel/lastDuelModal.spec.tsx +++ b/src/components/Duel/LastDuelModal/lastDuelModal.spec.tsx @@ -1,19 +1,9 @@ import { mount } from 'enzyme' import toJson from 'enzyme-to-json' import React from 'react' -import { waitForComponentToPaint } from '../../../tests/__mocks__/testUtils' +import { waitForComponentToPaint } from 'tests/__mocks__/testUtils' import LastDuelModal from './lastDuelModal' -jest.mock('cozy-ui/transpiled/react/I18n', () => { - return { - useI18n: jest.fn(() => { - return { - t: (str: string) => str, - } - }), - } -}) - describe('lastDuelModal component', () => { it('should render correctly', async () => { const wrapper = mount( diff --git a/src/components/Duel/lastDuelModal.tsx b/src/components/Duel/LastDuelModal/lastDuelModal.tsx similarity index 92% rename from src/components/Duel/lastDuelModal.tsx rename to src/components/Duel/LastDuelModal/lastDuelModal.tsx index ad57fd6cb853f422e67146c4b7bbbf787610af81..92deec333ef696c3f46f3c09f511108eaa2c3148 100644 --- a/src/components/Duel/lastDuelModal.tsx +++ b/src/components/Duel/LastDuelModal/lastDuelModal.tsx @@ -18,13 +18,13 @@ const LastDuelModal = ({ open, handleCloseClick }: LastDuelModalProps) => { <Dialog open={open} onClose={handleCloseClick} - aria-labelledby={'accessibility-title'} + aria-labelledby="accessibility-title" classes={{ root: 'modal-root', paper: 'modal-paper blue-light-border', }} > - <div id={'accessibility-title'}>{t('last_duel_modal.title')}</div> + <div id="accessibility-title">{t('last_duel_modal.title')}</div> <div className="duel-last-modal-root"> <div onClick={handleCloseClick}> <StyledIcon className="closeIcon" icon={CloseIcon} size={16} /> diff --git a/src/components/Duel/__snapshots__/DuelResultModal.spec.tsx.snap b/src/components/Duel/__snapshots__/DuelResultModal.spec.tsx.snap deleted file mode 100644 index bbffacde1a57ab55f3afd6bc6b30be2ffc60281d..0000000000000000000000000000000000000000 --- a/src/components/Duel/__snapshots__/DuelResultModal.spec.tsx.snap +++ /dev/null @@ -1,1062 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`DuelResultModal component should render correctly 1`] = ` -<Provider - store={ - Object { - "clearActions": [Function], - "dispatch": [Function], - "getActions": [Function], - "getState": [Function], - "replaceReducer": [Function], - "subscribe": [Function], - } - } -> - <DuelResultModal - handleCloseClick={[MockFunction]} - open={true} - userChallenge={ - Object { - "action": Object { - "ecogesture": null, - "startDate": null, - "state": 0, - }, - "description": "Description challenge 2", - "duel": Object { - "description": "Je parie un ours polaire que vous ne pouvez pas consommer moins que #CONSUMPTION € en 1 semaine", - "duration": "P30D", - "fluidTypes": Array [], - "id": "DUEL001", - "startDate": null, - "state": 0, - "threshold": 0, - "title": "Title DUEL001", - "userConsumption": 0, - }, - "endingDate": null, - "exploration": Object { - "complementary_description": "Refaire un tour dans son profil si déjà fait", - "date": null, - "description": "Avoir complété son profil", - "ecogesture_id": "", - "fluid_condition": Array [], - "id": "EXPLORATION001", - "message_success": "Vous avez complété votre profil ou refait un tour dans votre profil", - "progress": 0, - "state": 0, - "target": 1, - "type": 1, - }, - "id": "CHALLENGE0002", - "progress": Object { - "actionProgress": 0, - "explorationProgress": 0, - "quizProgress": 0, - }, - "quiz": Object { - "customQuestion": Object { - "interval": 20, - "period": Object {}, - "questionLabel": "Custom1", - "result": 0, - "singleFluid": false, - "timeStep": 20, - "type": 0, - }, - "id": "QUIZ001", - "questions": Array [ - Object { - "answers": Array [ - Object { - "answerLabel": "86 km", - "isTrue": true, - }, - Object { - "answerLabel": "78 km", - "isTrue": false, - }, - Object { - "answerLabel": "56 km", - "isTrue": false, - }, - ], - "explanation": "L’aqueduc du Gier est un des aqueducs antiques de Lyon desservant la ville antique de Lugdunum. Avec ses 86 km il est le plus long des quatre aqueducs ayant alimenté la ville en eau, et celui dont les structures sont le mieux conservées. Il doit son nom au fait qu'il puise aux sources du Gier, affluent du Rhône", - "questionLabel": "Quelle longueur faisait l’aqueduc du Gier pour acheminer l’eau sur Lyon à l’époque romaine ?", - "result": 0, - "source": "string", - }, - Object { - "answers": Array [ - Object { - "answerLabel": "1 point d’eau public pour 800 habitants.", - "isTrue": true, - }, - Object { - "answerLabel": "1 point d’eau public pour 400 habitants.", - "isTrue": false, - }, - Object { - "answerLabel": "1 point d’eau public pour 200 habitants.", - "isTrue": false, - }, - ], - "explanation": "string", - "questionLabel": "En 1800 à Lyon, combien de points d'eau y avait-il par habitants ?", - "result": 0, - "source": "string", - }, - Object { - "answers": Array [ - Object { - "answerLabel": "François Mitterrand", - "isTrue": false, - }, - Object { - "answerLabel": "Napoléon Ier", - "isTrue": true, - }, - Object { - "answerLabel": "Napoléon III", - "isTrue": false, - }, - ], - "explanation": "string", - "questionLabel": "Qui officialise la création de la Compagnie Générale des eaux ?", - "result": 0, - "source": "string", - }, - Object { - "answers": Array [ - Object { - "answerLabel": "string", - "isTrue": false, - }, - Object { - "answerLabel": "string", - "isTrue": false, - }, - Object { - "answerLabel": "Aristide Dumont", - "isTrue": true, - }, - ], - "explanation": "string", - "questionLabel": "Quel ingénieur est à l’origine du projet d’alimentation en eau en 1856 ?", - "result": 0, - "source": "string", - }, - ], - "result": 0, - "startDate": null, - "state": 0, - }, - "startDate": null, - "state": 4, - "success": 1, - "target": 15, - "title": "Challenge 2", - } - } - win={true} - > - <WithStyles(ForwardRef(Dialog)) - aria-labelledby="accessibility-title" - classes={ - Object { - "paper": "modal-paper blue-border", - "root": "modal-root", - } - } - onClose={[MockFunction]} - open={true} - > - <ForwardRef(Dialog) - aria-labelledby="accessibility-title" - classes={ - Object { - "container": "MuiDialog-container", - "paper": "MuiDialog-paper modal-paper blue-border", - "paperFullScreen": "MuiDialog-paperFullScreen", - "paperFullWidth": "MuiDialog-paperFullWidth", - "paperScrollBody": "MuiDialog-paperScrollBody", - "paperScrollPaper": "MuiDialog-paperScrollPaper", - "paperWidthFalse": "MuiDialog-paperWidthFalse", - "paperWidthLg": "MuiDialog-paperWidthLg", - "paperWidthMd": "MuiDialog-paperWidthMd", - "paperWidthSm": "MuiDialog-paperWidthSm", - "paperWidthXl": "MuiDialog-paperWidthXl", - "paperWidthXs": "MuiDialog-paperWidthXs", - "root": "MuiDialog-root modal-root", - "scrollBody": "MuiDialog-scrollBody", - "scrollPaper": "MuiDialog-scrollPaper", - } - } - onClose={[MockFunction]} - open={true} - > - <ForwardRef(Modal) - BackdropComponent={ - Object { - "$$typeof": Symbol(react.forward_ref), - "Naked": Object { - "$$typeof": Symbol(react.forward_ref), - "propTypes": Object { - "children": [Function], - "className": [Function], - "classes": [Function], - "invisible": [Function], - "open": [Function], - "transitionDuration": [Function], - }, - "render": [Function], - }, - "displayName": "WithStyles(ForwardRef(Backdrop))", - "options": Object { - "defaultTheme": Object { - "breakpoints": Object { - "between": [Function], - "down": [Function], - "keys": Array [ - "xs", - "sm", - "md", - "lg", - "xl", - ], - "only": [Function], - "up": [Function], - "values": Object { - "lg": 1280, - "md": 960, - "sm": 600, - "xl": 1920, - "xs": 0, - }, - "width": [Function], - }, - "direction": "ltr", - "mixins": Object { - "gutters": [Function], - "toolbar": Object { - "@media (min-width:0px) and (orientation: landscape)": Object { - "minHeight": 48, - }, - "@media (min-width:600px)": Object { - "minHeight": 64, - }, - "minHeight": 56, - }, - }, - "overrides": Object {}, - "palette": Object { - "action": Object { - "activatedOpacity": 0.12, - "active": "rgba(0, 0, 0, 0.54)", - "disabled": "rgba(0, 0, 0, 0.26)", - "disabledBackground": "rgba(0, 0, 0, 0.12)", - "disabledOpacity": 0.38, - "focus": "rgba(0, 0, 0, 0.12)", - "focusOpacity": 0.12, - "hover": "rgba(0, 0, 0, 0.04)", - "hoverOpacity": 0.04, - "selected": "rgba(0, 0, 0, 0.08)", - "selectedOpacity": 0.08, - }, - "augmentColor": [Function], - "background": Object { - "default": "#fafafa", - "paper": "#fff", - }, - "common": Object { - "black": "#000", - "white": "#fff", - }, - "contrastThreshold": 3, - "divider": "rgba(0, 0, 0, 0.12)", - "error": Object { - "contrastText": "#fff", - "dark": "#d32f2f", - "light": "#e57373", - "main": "#f44336", - }, - "getContrastText": [Function], - "grey": Object { - "100": "#f5f5f5", - "200": "#eeeeee", - "300": "#e0e0e0", - "400": "#bdbdbd", - "50": "#fafafa", - "500": "#9e9e9e", - "600": "#757575", - "700": "#616161", - "800": "#424242", - "900": "#212121", - "A100": "#d5d5d5", - "A200": "#aaaaaa", - "A400": "#303030", - "A700": "#616161", - }, - "info": Object { - "contrastText": "#fff", - "dark": "#1976d2", - "light": "#64b5f6", - "main": "#2196f3", - }, - "primary": Object { - "contrastText": "#fff", - "dark": "#303f9f", - "light": "#7986cb", - "main": "#3f51b5", - }, - "secondary": Object { - "contrastText": "#fff", - "dark": "#c51162", - "light": "#ff4081", - "main": "#f50057", - }, - "success": Object { - "contrastText": "rgba(0, 0, 0, 0.87)", - "dark": "#388e3c", - "light": "#81c784", - "main": "#4caf50", - }, - "text": Object { - "disabled": "rgba(0, 0, 0, 0.38)", - "hint": "rgba(0, 0, 0, 0.38)", - "primary": "rgba(0, 0, 0, 0.87)", - "secondary": "rgba(0, 0, 0, 0.54)", - }, - "tonalOffset": 0.2, - "type": "light", - "warning": Object { - "contrastText": "rgba(0, 0, 0, 0.87)", - "dark": "#f57c00", - "light": "#ffb74d", - "main": "#ff9800", - }, - }, - "props": Object {}, - "shadows": Array [ - "none", - "0px 2px 1px -1px rgba(0,0,0,0.2),0px 1px 1px 0px rgba(0,0,0,0.14),0px 1px 3px 0px rgba(0,0,0,0.12)", - "0px 3px 1px -2px rgba(0,0,0,0.2),0px 2px 2px 0px rgba(0,0,0,0.14),0px 1px 5px 0px rgba(0,0,0,0.12)", - "0px 3px 3px -2px rgba(0,0,0,0.2),0px 3px 4px 0px rgba(0,0,0,0.14),0px 1px 8px 0px rgba(0,0,0,0.12)", - "0px 2px 4px -1px rgba(0,0,0,0.2),0px 4px 5px 0px rgba(0,0,0,0.14),0px 1px 10px 0px rgba(0,0,0,0.12)", - "0px 3px 5px -1px rgba(0,0,0,0.2),0px 5px 8px 0px rgba(0,0,0,0.14),0px 1px 14px 0px rgba(0,0,0,0.12)", - "0px 3px 5px -1px rgba(0,0,0,0.2),0px 6px 10px 0px rgba(0,0,0,0.14),0px 1px 18px 0px rgba(0,0,0,0.12)", - "0px 4px 5px -2px rgba(0,0,0,0.2),0px 7px 10px 1px rgba(0,0,0,0.14),0px 2px 16px 1px rgba(0,0,0,0.12)", - "0px 5px 5px -3px rgba(0,0,0,0.2),0px 8px 10px 1px rgba(0,0,0,0.14),0px 3px 14px 2px rgba(0,0,0,0.12)", - "0px 5px 6px -3px rgba(0,0,0,0.2),0px 9px 12px 1px rgba(0,0,0,0.14),0px 3px 16px 2px rgba(0,0,0,0.12)", - "0px 6px 6px -3px rgba(0,0,0,0.2),0px 10px 14px 1px rgba(0,0,0,0.14),0px 4px 18px 3px rgba(0,0,0,0.12)", - "0px 6px 7px -4px rgba(0,0,0,0.2),0px 11px 15px 1px rgba(0,0,0,0.14),0px 4px 20px 3px rgba(0,0,0,0.12)", - "0px 7px 8px -4px rgba(0,0,0,0.2),0px 12px 17px 2px rgba(0,0,0,0.14),0px 5px 22px 4px rgba(0,0,0,0.12)", - "0px 7px 8px -4px rgba(0,0,0,0.2),0px 13px 19px 2px rgba(0,0,0,0.14),0px 5px 24px 4px rgba(0,0,0,0.12)", - "0px 7px 9px -4px rgba(0,0,0,0.2),0px 14px 21px 2px rgba(0,0,0,0.14),0px 5px 26px 4px rgba(0,0,0,0.12)", - "0px 8px 9px -5px rgba(0,0,0,0.2),0px 15px 22px 2px rgba(0,0,0,0.14),0px 6px 28px 5px rgba(0,0,0,0.12)", - "0px 8px 10px -5px rgba(0,0,0,0.2),0px 16px 24px 2px rgba(0,0,0,0.14),0px 6px 30px 5px rgba(0,0,0,0.12)", - "0px 8px 11px -5px rgba(0,0,0,0.2),0px 17px 26px 2px rgba(0,0,0,0.14),0px 6px 32px 5px rgba(0,0,0,0.12)", - "0px 9px 11px -5px rgba(0,0,0,0.2),0px 18px 28px 2px rgba(0,0,0,0.14),0px 7px 34px 6px rgba(0,0,0,0.12)", - "0px 9px 12px -6px rgba(0,0,0,0.2),0px 19px 29px 2px rgba(0,0,0,0.14),0px 7px 36px 6px rgba(0,0,0,0.12)", - "0px 10px 13px -6px rgba(0,0,0,0.2),0px 20px 31px 3px rgba(0,0,0,0.14),0px 8px 38px 7px rgba(0,0,0,0.12)", - "0px 10px 13px -6px rgba(0,0,0,0.2),0px 21px 33px 3px rgba(0,0,0,0.14),0px 8px 40px 7px rgba(0,0,0,0.12)", - "0px 10px 14px -6px rgba(0,0,0,0.2),0px 22px 35px 3px rgba(0,0,0,0.14),0px 8px 42px 7px rgba(0,0,0,0.12)", - "0px 11px 14px -7px rgba(0,0,0,0.2),0px 23px 36px 3px rgba(0,0,0,0.14),0px 9px 44px 8px rgba(0,0,0,0.12)", - "0px 11px 15px -7px rgba(0,0,0,0.2),0px 24px 38px 3px rgba(0,0,0,0.14),0px 9px 46px 8px rgba(0,0,0,0.12)", - ], - "shape": Object { - "borderRadius": 4, - }, - "spacing": [Function], - "transitions": Object { - "create": [Function], - "duration": Object { - "complex": 375, - "enteringScreen": 225, - "leavingScreen": 195, - "short": 250, - "shorter": 200, - "shortest": 150, - "standard": 300, - }, - "easing": Object { - "easeIn": "cubic-bezier(0.4, 0, 1, 1)", - "easeInOut": "cubic-bezier(0.4, 0, 0.2, 1)", - "easeOut": "cubic-bezier(0.0, 0, 0.2, 1)", - "sharp": "cubic-bezier(0.4, 0, 0.6, 1)", - }, - "getAutoHeightDuration": [Function], - }, - "typography": Object { - "body1": Object { - "fontFamily": "\\"Roboto\\", \\"Helvetica\\", \\"Arial\\", sans-serif", - "fontSize": "1rem", - "fontWeight": 400, - "letterSpacing": "0.00938em", - "lineHeight": 1.5, - }, - "body2": Object { - "fontFamily": "\\"Roboto\\", \\"Helvetica\\", \\"Arial\\", sans-serif", - "fontSize": "0.875rem", - "fontWeight": 400, - "letterSpacing": "0.01071em", - "lineHeight": 1.43, - }, - "button": Object { - "fontFamily": "\\"Roboto\\", \\"Helvetica\\", \\"Arial\\", sans-serif", - "fontSize": "0.875rem", - "fontWeight": 500, - "letterSpacing": "0.02857em", - "lineHeight": 1.75, - "textTransform": "uppercase", - }, - "caption": Object { - "fontFamily": "\\"Roboto\\", \\"Helvetica\\", \\"Arial\\", sans-serif", - "fontSize": "0.75rem", - "fontWeight": 400, - "letterSpacing": "0.03333em", - "lineHeight": 1.66, - }, - "fontFamily": "\\"Roboto\\", \\"Helvetica\\", \\"Arial\\", sans-serif", - "fontSize": 14, - "fontWeightBold": 700, - "fontWeightLight": 300, - "fontWeightMedium": 500, - "fontWeightRegular": 400, - "h1": Object { - "fontFamily": "\\"Roboto\\", \\"Helvetica\\", \\"Arial\\", sans-serif", - "fontSize": "6rem", - "fontWeight": 300, - "letterSpacing": "-0.01562em", - "lineHeight": 1.167, - }, - "h2": Object { - "fontFamily": "\\"Roboto\\", \\"Helvetica\\", \\"Arial\\", sans-serif", - "fontSize": "3.75rem", - "fontWeight": 300, - "letterSpacing": "-0.00833em", - "lineHeight": 1.2, - }, - "h3": Object { - "fontFamily": "\\"Roboto\\", \\"Helvetica\\", \\"Arial\\", sans-serif", - "fontSize": "3rem", - "fontWeight": 400, - "letterSpacing": "0em", - "lineHeight": 1.167, - }, - "h4": Object { - "fontFamily": "\\"Roboto\\", \\"Helvetica\\", \\"Arial\\", sans-serif", - "fontSize": "2.125rem", - "fontWeight": 400, - "letterSpacing": "0.00735em", - "lineHeight": 1.235, - }, - "h5": Object { - "fontFamily": "\\"Roboto\\", \\"Helvetica\\", \\"Arial\\", sans-serif", - "fontSize": "1.5rem", - "fontWeight": 400, - "letterSpacing": "0em", - "lineHeight": 1.334, - }, - "h6": Object { - "fontFamily": "\\"Roboto\\", \\"Helvetica\\", \\"Arial\\", sans-serif", - "fontSize": "1.25rem", - "fontWeight": 500, - "letterSpacing": "0.0075em", - "lineHeight": 1.6, - }, - "htmlFontSize": 16, - "overline": Object { - "fontFamily": "\\"Roboto\\", \\"Helvetica\\", \\"Arial\\", sans-serif", - "fontSize": "0.75rem", - "fontWeight": 400, - "letterSpacing": "0.08333em", - "lineHeight": 2.66, - "textTransform": "uppercase", - }, - "pxToRem": [Function], - "round": [Function], - "subtitle1": Object { - "fontFamily": "\\"Roboto\\", \\"Helvetica\\", \\"Arial\\", sans-serif", - "fontSize": "1rem", - "fontWeight": 400, - "letterSpacing": "0.00938em", - "lineHeight": 1.75, - }, - "subtitle2": Object { - "fontFamily": "\\"Roboto\\", \\"Helvetica\\", \\"Arial\\", sans-serif", - "fontSize": "0.875rem", - "fontWeight": 500, - "letterSpacing": "0.00714em", - "lineHeight": 1.57, - }, - }, - "zIndex": Object { - "appBar": 1100, - "drawer": 1200, - "mobileStepper": 1000, - "modal": 1300, - "snackbar": 1400, - "speedDial": 1050, - "tooltip": 1500, - }, - }, - "name": "MuiBackdrop", - }, - "propTypes": Object { - "classes": [Function], - "innerRef": [Function], - }, - "render": [Function], - "useStyles": [Function], - } - } - BackdropProps={ - Object { - "transitionDuration": Object { - "enter": 225, - "exit": 195, - }, - } - } - className="MuiDialog-root modal-root" - closeAfterTransition={true} - disableEscapeKeyDown={false} - onClose={[MockFunction]} - open={true} - > - <ForwardRef(Portal) - disablePortal={false} - > - <Portal - containerInfo={ - <body - style="padding-right: 0px; overflow: hidden;" - > - <div - class="MuiDialog-root modal-root" - role="presentation" - style="position: fixed; z-index: 1300; right: 0px; bottom: 0px; top: 0px; left: 0px;" - > - <div - aria-hidden="true" - class="MuiBackdrop-root" - style="opacity: 1; webkit-transition: opacity 225ms cubic-bezier(0.4, 0, 0.2, 1) 0ms; transition: opacity 225ms cubic-bezier(0.4, 0, 0.2, 1) 0ms;" - /> - <div - data-test="sentinelStart" - tabindex="0" - /> - <div - class="MuiDialog-container MuiDialog-scrollPaper" - role="none presentation" - style="opacity: 1; webkit-transition: opacity 225ms cubic-bezier(0.4, 0, 0.2, 1) 0ms; transition: opacity 225ms cubic-bezier(0.4, 0, 0.2, 1) 0ms;" - tabindex="-1" - > - <div - aria-labelledby="accessibility-title" - class="MuiPaper-root MuiDialog-paper modal-paper blue-border MuiDialog-paperScrollPaper MuiDialog-paperWidthSm MuiPaper-elevation24 MuiPaper-rounded" - role="dialog" - > - <div - id="accessibility-title" - > - duel_result_modal.accessibility.window_title - </div> - <div - class="duel-result-modal-root " - > - <div - class="imgResultContainer" - > - <svg - class="challengeWon styles__icon___23x3R" - height="300" - width="300" - > - <use - xlink:href="#test-file-stub" - /> - </svg> - <svg - class="imgResult styles__icon___23x3R" - height="180" - width="180" - > - <use - xlink:href="#" - /> - </svg> - </div> - <div - class="text-28-normal-uppercase title" - > - duel_result_modal.sucess.title - </div> - <div - class="text-18-normal" - > - duel_result_modal.sucess.message1function () { - return fn.apply(this, arguments); - } € - </div> - <div - class="text-18-normal" - > - duel_result_modal.sucess.message2Challenge 2 - </div> - <button - aria-label="duel_result_modal.accessibility.button_validate" - class="MuiButtonBase-root MuiButton-root btn-secondary-negative MuiButton-text button" - tabindex="0" - type="button" - > - <span - class="MuiButton-label text-16-normal" - > - duel_result_modal.sucess.button_validate - </span> - <span - class="MuiTouchRipple-root" - /> - </button> - </div> - </div> - </div> - <div - data-test="sentinelEnd" - tabindex="0" - /> - </div> - </body> - } - > - <div - className="MuiDialog-root modal-root" - onKeyDown={[Function]} - role="presentation" - style={ - Object { - "bottom": 0, - "left": 0, - "position": "fixed", - "right": 0, - "top": 0, - "zIndex": 1300, - } - } - > - <WithStyles(ForwardRef(Backdrop)) - onClick={[Function]} - open={true} - transitionDuration={ - Object { - "enter": 225, - "exit": 195, - } - } - > - <ForwardRef(Backdrop) - classes={ - Object { - "invisible": "MuiBackdrop-invisible", - "root": "MuiBackdrop-root", - } - } - onClick={[Function]} - open={true} - transitionDuration={ - Object { - "enter": 225, - "exit": 195, - } - } - > - <ForwardRef(Fade) - in={true} - onClick={[Function]} - timeout={ - Object { - "enter": 225, - "exit": 195, - } - } - > - <Transition - appear={true} - enter={true} - exit={true} - in={true} - mountOnEnter={false} - onClick={[Function]} - onEnter={[Function]} - onEntered={[Function]} - onEntering={[Function]} - onExit={[Function]} - onExited={[Function]} - onExiting={[Function]} - timeout={ - Object { - "enter": 225, - "exit": 195, - } - } - unmountOnExit={false} - > - <div - aria-hidden={true} - className="MuiBackdrop-root" - onClick={[Function]} - style={ - Object { - "opacity": 1, - "visibility": undefined, - } - } - /> - </Transition> - </ForwardRef(Fade)> - </ForwardRef(Backdrop)> - </WithStyles(ForwardRef(Backdrop))> - <Unstable_TrapFocus - disableAutoFocus={false} - disableEnforceFocus={false} - disableRestoreFocus={false} - getDoc={[Function]} - isEnabled={[Function]} - open={true} - > - <div - data-test="sentinelStart" - tabIndex={0} - /> - <ForwardRef(Fade) - appear={true} - in={true} - onEnter={[Function]} - onExited={[Function]} - role="none presentation" - tabIndex="-1" - timeout={ - Object { - "enter": 225, - "exit": 195, - } - } - > - <Transition - appear={true} - enter={true} - exit={true} - in={true} - mountOnEnter={false} - onEnter={[Function]} - onEntered={[Function]} - onEntering={[Function]} - onExit={[Function]} - onExited={[Function]} - onExiting={[Function]} - role="none presentation" - tabIndex="-1" - timeout={ - Object { - "enter": 225, - "exit": 195, - } - } - unmountOnExit={false} - > - <div - className="MuiDialog-container MuiDialog-scrollPaper" - onMouseDown={[Function]} - onMouseUp={[Function]} - role="none presentation" - style={ - Object { - "opacity": 1, - "visibility": undefined, - } - } - tabIndex="-1" - > - <WithStyles(ForwardRef(Paper)) - aria-labelledby="accessibility-title" - className="MuiDialog-paper modal-paper blue-border MuiDialog-paperScrollPaper MuiDialog-paperWidthSm" - elevation={24} - role="dialog" - > - <ForwardRef(Paper) - aria-labelledby="accessibility-title" - className="MuiDialog-paper modal-paper blue-border MuiDialog-paperScrollPaper MuiDialog-paperWidthSm" - classes={ - Object { - "elevation0": "MuiPaper-elevation0", - "elevation1": "MuiPaper-elevation1", - "elevation10": "MuiPaper-elevation10", - "elevation11": "MuiPaper-elevation11", - "elevation12": "MuiPaper-elevation12", - "elevation13": "MuiPaper-elevation13", - "elevation14": "MuiPaper-elevation14", - "elevation15": "MuiPaper-elevation15", - "elevation16": "MuiPaper-elevation16", - "elevation17": "MuiPaper-elevation17", - "elevation18": "MuiPaper-elevation18", - "elevation19": "MuiPaper-elevation19", - "elevation2": "MuiPaper-elevation2", - "elevation20": "MuiPaper-elevation20", - "elevation21": "MuiPaper-elevation21", - "elevation22": "MuiPaper-elevation22", - "elevation23": "MuiPaper-elevation23", - "elevation24": "MuiPaper-elevation24", - "elevation3": "MuiPaper-elevation3", - "elevation4": "MuiPaper-elevation4", - "elevation5": "MuiPaper-elevation5", - "elevation6": "MuiPaper-elevation6", - "elevation7": "MuiPaper-elevation7", - "elevation8": "MuiPaper-elevation8", - "elevation9": "MuiPaper-elevation9", - "outlined": "MuiPaper-outlined", - "root": "MuiPaper-root", - "rounded": "MuiPaper-rounded", - } - } - elevation={24} - role="dialog" - > - <div - aria-labelledby="accessibility-title" - className="MuiPaper-root MuiDialog-paper modal-paper blue-border MuiDialog-paperScrollPaper MuiDialog-paperWidthSm MuiPaper-elevation24 MuiPaper-rounded" - role="dialog" - > - <div - id="accessibility-title" - > - duel_result_modal.accessibility.window_title - </div> - <div - className="duel-result-modal-root " - > - <div - className="imgResultContainer" - > - <Icon - className="challengeWon" - icon="test-file-stub" - size={300} - spin={false} - > - <Component - className="challengeWon styles__icon___23x3R" - height={300} - style={Object {}} - width={300} - > - <svg - className="challengeWon styles__icon___23x3R" - height={300} - style={Object {}} - width={300} - > - <use - xlinkHref="#test-file-stub" - /> - </svg> - </Component> - </Icon> - <Icon - className="imgResult" - icon="" - size={180} - spin={false} - > - <Component - className="imgResult styles__icon___23x3R" - height={180} - style={Object {}} - width={180} - > - <svg - className="imgResult styles__icon___23x3R" - height={180} - style={Object {}} - width={180} - > - <use - xlinkHref="#" - /> - </svg> - </Component> - </Icon> - </div> - <div - className="text-28-normal-uppercase title" - > - duel_result_modal.sucess.title - </div> - <div - className="text-18-normal" - > - duel_result_modal.sucess.message1function () { - return fn.apply(this, arguments); - } € - </div> - <div - className="text-18-normal" - > - duel_result_modal.sucess.message2Challenge 2 - </div> - <WithStyles(ForwardRef(Button)) - aria-label="duel_result_modal.accessibility.button_validate" - className="button" - classes={ - Object { - "label": "text-16-normal", - "root": "btn-secondary-negative", - } - } - onClick={[MockFunction]} - > - <ForwardRef(Button) - aria-label="duel_result_modal.accessibility.button_validate" - className="button" - classes={ - Object { - "colorInherit": "MuiButton-colorInherit", - "contained": "MuiButton-contained", - "containedPrimary": "MuiButton-containedPrimary", - "containedSecondary": "MuiButton-containedSecondary", - "containedSizeLarge": "MuiButton-containedSizeLarge", - "containedSizeSmall": "MuiButton-containedSizeSmall", - "disableElevation": "MuiButton-disableElevation", - "disabled": "Mui-disabled", - "endIcon": "MuiButton-endIcon", - "focusVisible": "Mui-focusVisible", - "fullWidth": "MuiButton-fullWidth", - "iconSizeLarge": "MuiButton-iconSizeLarge", - "iconSizeMedium": "MuiButton-iconSizeMedium", - "iconSizeSmall": "MuiButton-iconSizeSmall", - "label": "MuiButton-label text-16-normal", - "outlined": "MuiButton-outlined", - "outlinedPrimary": "MuiButton-outlinedPrimary", - "outlinedSecondary": "MuiButton-outlinedSecondary", - "outlinedSizeLarge": "MuiButton-outlinedSizeLarge", - "outlinedSizeSmall": "MuiButton-outlinedSizeSmall", - "root": "MuiButton-root btn-secondary-negative", - "sizeLarge": "MuiButton-sizeLarge", - "sizeSmall": "MuiButton-sizeSmall", - "startIcon": "MuiButton-startIcon", - "text": "MuiButton-text", - "textPrimary": "MuiButton-textPrimary", - "textSecondary": "MuiButton-textSecondary", - "textSizeLarge": "MuiButton-textSizeLarge", - "textSizeSmall": "MuiButton-textSizeSmall", - } - } - onClick={[MockFunction]} - > - <WithStyles(ForwardRef(ButtonBase)) - aria-label="duel_result_modal.accessibility.button_validate" - className="MuiButton-root btn-secondary-negative MuiButton-text button" - component="button" - disabled={false} - focusRipple={true} - focusVisibleClassName="Mui-focusVisible" - onClick={[MockFunction]} - type="button" - > - <ForwardRef(ButtonBase) - aria-label="duel_result_modal.accessibility.button_validate" - className="MuiButton-root btn-secondary-negative MuiButton-text button" - classes={ - Object { - "disabled": "Mui-disabled", - "focusVisible": "Mui-focusVisible", - "root": "MuiButtonBase-root", - } - } - component="button" - disabled={false} - focusRipple={true} - focusVisibleClassName="Mui-focusVisible" - onClick={[MockFunction]} - type="button" - > - <button - aria-label="duel_result_modal.accessibility.button_validate" - className="MuiButtonBase-root MuiButton-root btn-secondary-negative MuiButton-text button" - disabled={false} - onBlur={[Function]} - onClick={[MockFunction]} - onDragLeave={[Function]} - onFocus={[Function]} - onKeyDown={[Function]} - onKeyUp={[Function]} - onMouseDown={[Function]} - onMouseLeave={[Function]} - onMouseUp={[Function]} - onTouchEnd={[Function]} - onTouchMove={[Function]} - onTouchStart={[Function]} - tabIndex={0} - type="button" - > - <span - className="MuiButton-label text-16-normal" - > - duel_result_modal.sucess.button_validate - </span> - <WithStyles(memo) - center={false} - > - <ForwardRef(TouchRipple) - center={false} - classes={ - Object { - "child": "MuiTouchRipple-child", - "childLeaving": "MuiTouchRipple-childLeaving", - "childPulsate": "MuiTouchRipple-childPulsate", - "ripple": "MuiTouchRipple-ripple", - "ripplePulsate": "MuiTouchRipple-ripplePulsate", - "rippleVisible": "MuiTouchRipple-rippleVisible", - "root": "MuiTouchRipple-root", - } - } - > - <span - className="MuiTouchRipple-root" - > - <TransitionGroup - childFactory={[Function]} - component={null} - exit={true} - /> - </span> - </ForwardRef(TouchRipple)> - </WithStyles(memo)> - </button> - </ForwardRef(ButtonBase)> - </WithStyles(ForwardRef(ButtonBase))> - </ForwardRef(Button)> - </WithStyles(ForwardRef(Button))> - </div> - </div> - </ForwardRef(Paper)> - </WithStyles(ForwardRef(Paper))> - </div> - </Transition> - </ForwardRef(Fade)> - <div - data-test="sentinelEnd" - tabIndex={0} - /> - </Unstable_TrapFocus> - </div> - </Portal> - </ForwardRef(Portal)> - </ForwardRef(Modal)> - </ForwardRef(Dialog)> - </WithStyles(ForwardRef(Dialog))> - </DuelResultModal> -</Provider> -`; diff --git a/src/components/Duel/duelChart.scss b/src/components/Duel/duelChart.scss deleted file mode 100644 index 459de5914467eb9afd79a0154100b896ceefd453..0000000000000000000000000000000000000000 --- a/src/components/Duel/duelChart.scss +++ /dev/null @@ -1,7 +0,0 @@ -@import '../../styles/base/color'; -@import '../../styles/base/breakpoint'; - -.chart-root { - margin-bottom: 1rem; - max-width: 400px; -} diff --git a/src/components/Ecogesture/EcogestureCard.spec.tsx b/src/components/Ecogesture/EcogestureCard.spec.tsx deleted file mode 100644 index 45f8113272c3f07718ed010846ee7ce822608361..0000000000000000000000000000000000000000 --- a/src/components/Ecogesture/EcogestureCard.spec.tsx +++ /dev/null @@ -1,73 +0,0 @@ -/* eslint-disable react/display-name */ -import EcogestureCard from 'components/Ecogesture/EcogestureCard' -import { mount } from 'enzyme' -import toJson from 'enzyme-to-json' -import React from 'react' -import { Provider } from 'react-redux' -import { BrowserRouter } from 'react-router-dom' -import configureStore from 'redux-mock-store' -import { mockedEcogesturesData } from '../../../tests/__mocks__/ecogesturesData.mock' -import { globalStateData } from '../../../tests/__mocks__/globalStateData.mock' -import { waitForComponentToPaint } from '../../../tests/__mocks__/testUtils' - -jest.mock('cozy-ui/transpiled/react/I18n', () => { - return { - useI18n: jest.fn(() => { - return { - t: (str: string) => str, - } - }), - } -}) -jest.mock('components/CommonKit/Icon/StyledIcon', () => () => ( - <div id="StyledIcon" /> -)) -const mockImportIconById = jest.fn() -jest.mock('utils/utils', () => { - return { - importIconById: jest.fn(() => { - return mockImportIconById - }), - } -}) - -const mockStore = configureStore([]) - -describe('EcogestureCard component', () => { - it('should be rendered correctly', async () => { - const store = mockStore({ - ecolyo: { - global: globalStateData, - }, - }) - mockImportIconById.mockReturnValueOnce('') - const wrapper = mount( - <Provider store={store}> - <BrowserRouter> - <EcogestureCard ecogesture={mockedEcogesturesData[0]} /> - </BrowserRouter> - </Provider> - ) - await waitForComponentToPaint(wrapper) - - expect(toJson(wrapper)).toMatchSnapshot() - }) - it('should be with default icon', async () => { - const store = mockStore({ - ecolyo: { - global: globalStateData, - }, - }) - mockImportIconById.mockReturnValue(undefined) - const wrapper = mount( - <Provider store={store}> - <BrowserRouter> - <EcogestureCard ecogesture={mockedEcogesturesData[0]} /> - </BrowserRouter> - </Provider> - ) - await waitForComponentToPaint(wrapper) - - expect(wrapper.find('.Icon').exists()).toBeTruthy() - }) -}) diff --git a/src/components/Ecogesture/EcogestureCard/EcogestureCard.spec.tsx b/src/components/Ecogesture/EcogestureCard/EcogestureCard.spec.tsx new file mode 100644 index 0000000000000000000000000000000000000000..836668c817c2485778f5debce45af380ada292d5 --- /dev/null +++ b/src/components/Ecogesture/EcogestureCard/EcogestureCard.spec.tsx @@ -0,0 +1,29 @@ +/* eslint-disable react/display-name */ +import EcogestureCard from 'components/Ecogesture/EcogestureCard/EcogestureCard' +import { mount } from 'enzyme' +import toJson from 'enzyme-to-json' +import React from 'react' +import { BrowserRouter } from 'react-router-dom' +import { mockedEcogesturesData } from 'tests/__mocks__/ecogesturesData.mock' +import { waitForComponentToPaint } from 'tests/__mocks__/testUtils' + +describe('EcogestureCard component', () => { + it('should be rendered correctly', async () => { + const wrapper = mount( + <BrowserRouter> + <EcogestureCard ecogesture={mockedEcogesturesData[0]} /> + </BrowserRouter> + ) + await waitForComponentToPaint(wrapper) + expect(toJson(wrapper)).toMatchSnapshot() + }) + it('should be with default icon', async () => { + const wrapper = mount( + <BrowserRouter> + <EcogestureCard ecogesture={mockedEcogesturesData[0]} /> + </BrowserRouter> + ) + await waitForComponentToPaint(wrapper) + expect(wrapper.find('.Icon').exists()).toBeTruthy() + }) +}) diff --git a/src/components/Ecogesture/EcogestureCard.tsx b/src/components/Ecogesture/EcogestureCard/EcogestureCard.tsx similarity index 77% rename from src/components/Ecogesture/EcogestureCard.tsx rename to src/components/Ecogesture/EcogestureCard/EcogestureCard.tsx index cf8a69b2da5517748e8a22e7188453028965920e..cb5842537012afc4ff28f714d8563779b9262e46 100644 --- a/src/components/Ecogesture/EcogestureCard.tsx +++ b/src/components/Ecogesture/EcogestureCard/EcogestureCard.tsx @@ -6,27 +6,15 @@ import { Ecogesture } from 'models' import React, { useEffect, useState } from 'react' import { Link as RouterLink } from 'react-router-dom' import { importIconById } from 'utils/utils' -import EfficiencyRating from './EfficiencyRating' +import EfficiencyRating from '../EfficiencyRating/EfficiencyRating' import './ecogestureCard.scss' -interface EcogestureCardProps { - ecogesture: Ecogesture - selectionCompleted?: boolean -} - -const EcogestureCard = ({ - ecogesture, - selectionCompleted = false, -}: EcogestureCardProps) => { +const EcogestureCard = ({ ecogesture }: { ecogesture: Ecogesture }) => { const [ecogestureIcon, setEcogestureIcon] = useState<string>('') useEffect(() => { async function handleEcogestureIcon() { const icon = await importIconById(ecogesture.id, 'ecogesture') - if (icon) { - setEcogestureIcon(icon) - } else { - setEcogestureIcon(defaultIcon) - } + setEcogestureIcon(icon || defaultIcon) } if (ecogesture) { handleEcogestureIcon() @@ -38,7 +26,6 @@ const EcogestureCard = ({ to={{ pathname: `/ecogesture/${ecogesture.id}`, }} - state={{ selectionCompleted }} component={RouterLink} className="ecogesture-list-item" > diff --git a/src/components/Ecogesture/EcogestureCard/__snapshots__/EcogestureCard.spec.tsx.snap b/src/components/Ecogesture/EcogestureCard/__snapshots__/EcogestureCard.spec.tsx.snap new file mode 100644 index 0000000000000000000000000000000000000000..67ce554e79c991ea674a77a280ee4997b9e497da --- /dev/null +++ b/src/components/Ecogesture/EcogestureCard/__snapshots__/EcogestureCard.spec.tsx.snap @@ -0,0 +1,538 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`EcogestureCard component should be rendered correctly 1`] = ` +<BrowserRouter> + <Router + location={ + Object { + "hash": "", + "key": "default", + "pathname": "/", + "search": "", + "state": null, + } + } + navigationType="POP" + navigator={ + Object { + "action": "POP", + "createHref": [Function], + "encodeLocation": [Function], + "go": [Function], + "listen": [Function], + "location": Object { + "hash": "", + "key": "default", + "pathname": "/", + "search": "", + "state": null, + }, + "push": [Function], + "replace": [Function], + } + } + > + <EcogestureCard + ecogesture={ + Object { + "_id": "ECOGESTURE001", + "_rev": "1-67f1ea36efdd892c96bf64a8943154cd", + "_type": "com.grandlyon.ecolyo.ecogesture", + "action": false, + "actionDuration": 3, + "actionName": null, + "difficulty": 1, + "doing": false, + "efficiency": 4, + "equipment": false, + "equipmentInstallation": true, + "equipmentType": Array [], + "fluidTypes": Array [ + 0, + 2, + ], + "id": "ECOGESTURE001", + "impactLevel": 8, + "investment": null, + "longDescription": "On se demande parfois si cela vaut le coup de \\"couper le chauffage\\" quand on s’absente… dès qu’il s’agit d’un week-end la réponse est « oui sûrement » ! Attention cependant au retour à ne pas faire de la surchauffe ! L’idéal est bien évidemment de régler sa programmation pour que le chauffage se relance quelques heures avant votre retour…", + "longName": "Je baisse le chauffage en mode hors gel lorsque je m'absente plus de 2 jours.", + "objective": false, + "room": Array [ + 0, + ], + "season": "Hiver", + "shortName": "Bonhomme de neige", + "usage": 1, + "viewedInSelection": false, + } + } + > + <WithStyles(ForwardRef(Link)) + className="ecogesture-list-item" + component={ + Object { + "$$typeof": Symbol(react.forward_ref), + "displayName": "Link", + "render": [Function], + } + } + to={ + Object { + "pathname": "/ecogesture/ECOGESTURE001", + } + } + > + <ForwardRef(Link) + className="ecogesture-list-item" + classes={ + Object { + "button": "MuiLink-button", + "focusVisible": "Mui-focusVisible", + "root": "MuiLink-root", + "underlineAlways": "MuiLink-underlineAlways", + "underlineHover": "MuiLink-underlineHover", + "underlineNone": "MuiLink-underlineNone", + } + } + component={ + Object { + "$$typeof": Symbol(react.forward_ref), + "displayName": "Link", + "render": [Function], + } + } + to={ + Object { + "pathname": "/ecogesture/ECOGESTURE001", + } + } + > + <WithStyles(ForwardRef(Typography)) + className="MuiLink-root MuiLink-underlineHover ecogesture-list-item" + color="primary" + component={ + Object { + "$$typeof": Symbol(react.forward_ref), + "displayName": "Link", + "render": [Function], + } + } + onBlur={[Function]} + onFocus={[Function]} + to={ + Object { + "pathname": "/ecogesture/ECOGESTURE001", + } + } + variant="inherit" + > + <ForwardRef(Typography) + className="MuiLink-root MuiLink-underlineHover ecogesture-list-item" + classes={ + Object { + "alignCenter": "MuiTypography-alignCenter", + "alignJustify": "MuiTypography-alignJustify", + "alignLeft": "MuiTypography-alignLeft", + "alignRight": "MuiTypography-alignRight", + "body1": "MuiTypography-body1", + "body2": "MuiTypography-body2", + "button": "MuiTypography-button", + "caption": "MuiTypography-caption", + "colorError": "MuiTypography-colorError", + "colorInherit": "MuiTypography-colorInherit", + "colorPrimary": "MuiTypography-colorPrimary", + "colorSecondary": "MuiTypography-colorSecondary", + "colorTextPrimary": "MuiTypography-colorTextPrimary", + "colorTextSecondary": "MuiTypography-colorTextSecondary", + "displayBlock": "MuiTypography-displayBlock", + "displayInline": "MuiTypography-displayInline", + "gutterBottom": "MuiTypography-gutterBottom", + "h1": "MuiTypography-h1", + "h2": "MuiTypography-h2", + "h3": "MuiTypography-h3", + "h4": "MuiTypography-h4", + "h5": "MuiTypography-h5", + "h6": "MuiTypography-h6", + "noWrap": "MuiTypography-noWrap", + "overline": "MuiTypography-overline", + "paragraph": "MuiTypography-paragraph", + "root": "MuiTypography-root", + "srOnly": "MuiTypography-srOnly", + "subtitle1": "MuiTypography-subtitle1", + "subtitle2": "MuiTypography-subtitle2", + } + } + color="primary" + component={ + Object { + "$$typeof": Symbol(react.forward_ref), + "displayName": "Link", + "render": [Function], + } + } + onBlur={[Function]} + onFocus={[Function]} + to={ + Object { + "pathname": "/ecogesture/ECOGESTURE001", + } + } + variant="inherit" + > + <Link + className="MuiTypography-root MuiLink-root MuiLink-underlineHover ecogesture-list-item MuiTypography-colorPrimary" + onBlur={[Function]} + onFocus={[Function]} + to={ + Object { + "pathname": "/ecogesture/ECOGESTURE001", + } + } + > + <a + className="MuiTypography-root MuiLink-root MuiLink-underlineHover ecogesture-list-item MuiTypography-colorPrimary" + href="/ecogesture/ECOGESTURE001" + onBlur={[Function]} + onClick={[Function]} + onFocus={[Function]} + > + <StyledEcogestureCard> + <WithStyles(WithStyles(ForwardRef(CardActionArea)))> + <WithStyles(ForwardRef(CardActionArea)) + classes={ + Object { + "root": "WithStyles(ForwardRef(CardActionArea))-root-1", + } + } + > + <ForwardRef(CardActionArea) + classes={ + Object { + "focusHighlight": "MuiCardActionArea-focusHighlight", + "focusVisible": "Mui-focusVisible", + "root": "MuiCardActionArea-root WithStyles(ForwardRef(CardActionArea))-root-1", + } + } + > + <WithStyles(ForwardRef(ButtonBase)) + className="MuiCardActionArea-root WithStyles(ForwardRef(CardActionArea))-root-1" + focusVisibleClassName="Mui-focusVisible" + > + <ForwardRef(ButtonBase) + className="MuiCardActionArea-root WithStyles(ForwardRef(CardActionArea))-root-1" + classes={ + Object { + "disabled": "Mui-disabled", + "focusVisible": "Mui-focusVisible", + "root": "MuiButtonBase-root", + } + } + focusVisibleClassName="Mui-focusVisible" + > + <button + className="MuiButtonBase-root MuiCardActionArea-root WithStyles(ForwardRef(CardActionArea))-root-1" + disabled={false} + onBlur={[Function]} + onDragLeave={[Function]} + onFocus={[Function]} + onKeyDown={[Function]} + onKeyUp={[Function]} + onMouseDown={[Function]} + onMouseLeave={[Function]} + onMouseUp={[Function]} + onTouchEnd={[Function]} + onTouchMove={[Function]} + onTouchStart={[Function]} + tabIndex={0} + type="button" + > + <WithStyles(WithStyles(ForwardRef(CardContent)))> + <WithStyles(ForwardRef(CardContent)) + classes={ + Object { + "root": "WithStyles(ForwardRef(CardContent))-root-2", + } + } + > + <ForwardRef(CardContent) + classes={ + Object { + "root": "MuiCardContent-root WithStyles(ForwardRef(CardContent))-root-2", + } + } + > + <div + className="MuiCardContent-root WithStyles(ForwardRef(CardContent))-root-2" + > + <div + className="ec-content" + > + <StyledIcon + className="Icon" + icon="test-file-stub" + size={50} + > + <Icon + aria-hidden={true} + className="Icon" + icon="test-file-stub" + size={50} + spin={false} + > + <Component + aria-hidden={true} + className="Icon styles__icon___23x3R" + height={50} + style={Object {}} + width={50} + > + <svg + aria-hidden={true} + className="Icon styles__icon___23x3R" + height={50} + style={Object {}} + width={50} + > + <use + xlinkHref="#test-file-stub" + /> + </svg> + </Component> + </Icon> + </StyledIcon> + <div + className="ec-content-short-name text-15-bold" + > + Bonhomme de neige + </div> + <EfficiencyRating + result={4} + > + <div + className="thunder" + > + <StyledIcon + className="star" + icon="test-file-stub" + key="1" + size={15} + > + <Icon + aria-hidden={true} + className="star" + icon="test-file-stub" + size={15} + spin={false} + > + <Component + aria-hidden={true} + className="star styles__icon___23x3R" + height={15} + style={Object {}} + width={15} + > + <svg + aria-hidden={true} + className="star styles__icon___23x3R" + height={15} + style={Object {}} + width={15} + > + <use + xlinkHref="#test-file-stub" + /> + </svg> + </Component> + </Icon> + </StyledIcon> + <StyledIcon + className="star" + icon="test-file-stub" + key="2" + size={15} + > + <Icon + aria-hidden={true} + className="star" + icon="test-file-stub" + size={15} + spin={false} + > + <Component + aria-hidden={true} + className="star styles__icon___23x3R" + height={15} + style={Object {}} + width={15} + > + <svg + aria-hidden={true} + className="star styles__icon___23x3R" + height={15} + style={Object {}} + width={15} + > + <use + xlinkHref="#test-file-stub" + /> + </svg> + </Component> + </Icon> + </StyledIcon> + <StyledIcon + className="star" + icon="test-file-stub" + key="3" + size={15} + > + <Icon + aria-hidden={true} + className="star" + icon="test-file-stub" + size={15} + spin={false} + > + <Component + aria-hidden={true} + className="star styles__icon___23x3R" + height={15} + style={Object {}} + width={15} + > + <svg + aria-hidden={true} + className="star styles__icon___23x3R" + height={15} + style={Object {}} + width={15} + > + <use + xlinkHref="#test-file-stub" + /> + </svg> + </Component> + </Icon> + </StyledIcon> + <StyledIcon + className="star" + icon="test-file-stub" + key="4" + size={15} + > + <Icon + aria-hidden={true} + className="star" + icon="test-file-stub" + size={15} + spin={false} + > + <Component + aria-hidden={true} + className="star styles__icon___23x3R" + height={15} + style={Object {}} + width={15} + > + <svg + aria-hidden={true} + className="star styles__icon___23x3R" + height={15} + style={Object {}} + width={15} + > + <use + xlinkHref="#test-file-stub" + /> + </svg> + </Component> + </Icon> + </StyledIcon> + <StyledIcon + className="star" + icon="test-file-stub" + key="5" + size={15} + > + <Icon + aria-hidden={true} + className="star" + icon="test-file-stub" + size={15} + spin={false} + > + <Component + aria-hidden={true} + className="star styles__icon___23x3R" + height={15} + style={Object {}} + width={15} + > + <svg + aria-hidden={true} + className="star styles__icon___23x3R" + height={15} + style={Object {}} + width={15} + > + <use + xlinkHref="#test-file-stub" + /> + </svg> + </Component> + </Icon> + </StyledIcon> + </div> + </EfficiencyRating> + </div> + </div> + </ForwardRef(CardContent)> + </WithStyles(ForwardRef(CardContent))> + </WithStyles(WithStyles(ForwardRef(CardContent)))> + <span + className="MuiCardActionArea-focusHighlight" + /> + <WithStyles(memo) + center={false} + > + <ForwardRef(TouchRipple) + center={false} + classes={ + Object { + "child": "MuiTouchRipple-child", + "childLeaving": "MuiTouchRipple-childLeaving", + "childPulsate": "MuiTouchRipple-childPulsate", + "ripple": "MuiTouchRipple-ripple", + "ripplePulsate": "MuiTouchRipple-ripplePulsate", + "rippleVisible": "MuiTouchRipple-rippleVisible", + "root": "MuiTouchRipple-root", + } + } + > + <span + className="MuiTouchRipple-root" + > + <TransitionGroup + childFactory={[Function]} + component={null} + exit={true} + /> + </span> + </ForwardRef(TouchRipple)> + </WithStyles(memo)> + </button> + </ForwardRef(ButtonBase)> + </WithStyles(ForwardRef(ButtonBase))> + </ForwardRef(CardActionArea)> + </WithStyles(ForwardRef(CardActionArea))> + </WithStyles(WithStyles(ForwardRef(CardActionArea)))> + </StyledEcogestureCard> + </a> + </Link> + </ForwardRef(Typography)> + </WithStyles(ForwardRef(Typography))> + </ForwardRef(Link)> + </WithStyles(ForwardRef(Link))> + </EcogestureCard> + </Router> +</BrowserRouter> +`; diff --git a/src/components/Ecogesture/ecogestureCard.scss b/src/components/Ecogesture/EcogestureCard/ecogestureCard.scss similarity index 100% rename from src/components/Ecogesture/ecogestureCard.scss rename to src/components/Ecogesture/EcogestureCard/ecogestureCard.scss diff --git a/src/components/Ecogesture/EcogestureEmptyList.spec.tsx b/src/components/Ecogesture/EcogestureEmptyList.spec.tsx deleted file mode 100644 index 8f609d629c3b62ba524decca7241f2095893852b..0000000000000000000000000000000000000000 --- a/src/components/Ecogesture/EcogestureEmptyList.spec.tsx +++ /dev/null @@ -1,132 +0,0 @@ -import Button from '@material-ui/core/Button' -import { mount } from 'enzyme' -import toJson from 'enzyme-to-json' -import React from 'react' -import { Provider } from 'react-redux' -import configureStore from 'redux-mock-store' -import { globalStateData } from '../../../tests/__mocks__/globalStateData.mock' -import { profileData } from '../../../tests/__mocks__/profileData.mock' -import EcogestureEmptyList from './EcogestureEmptyList' - -jest.mock('cozy-ui/transpiled/react/I18n', () => { - return { - useI18n: jest.fn(() => { - return { - t: (str: string) => str, - } - }), - } -}) -jest.mock('react-router-dom', () => ({ - ...jest.requireActual('react-router-dom'), - useNavigate: () => mockedNavigate, -})) -const mockStore = configureStore([]) -const mockedNavigate = jest.fn() -const mockChangeTab = jest.fn() -const mockHandleClick = jest.fn() -describe('EcogestureEmptyList component', () => { - it('should be rendered correctly', () => { - const store = mockStore({ - ecolyo: { - profile: profileData, - global: globalStateData, - }, - }) - const wrapper = mount( - <Provider store={store}> - <EcogestureEmptyList - setTab={mockChangeTab} - isObjective={true} - isSelectionDone={false} - handleReinitClick={mockHandleClick} - /> - </Provider> - ) - expect(toJson(wrapper)).toMatchSnapshot() - }) - it('should return to all ecogestures', () => { - const store = mockStore({ - ecolyo: { - profile: profileData, - global: globalStateData, - }, - }) - const wrapper = mount( - <Provider store={store}> - <EcogestureEmptyList - setTab={mockChangeTab} - isObjective={false} - isSelectionDone={true} - handleReinitClick={mockHandleClick} - /> - </Provider> - ) - wrapper.find(Button).first().simulate('click') - expect(mockChangeTab).toHaveBeenCalledTimes(1) - }) - it('should launch ecogesture form', () => { - const store = mockStore({ - ecolyo: { - profile: profileData, - global: globalStateData, - }, - }) - const wrapper = mount( - <Provider store={store}> - <EcogestureEmptyList - setTab={mockChangeTab} - isObjective={false} - isSelectionDone={false} - handleReinitClick={mockHandleClick} - /> - </Provider> - ) - wrapper.find(Button).at(1).simulate('click') - expect(mockedNavigate).toHaveBeenCalledWith('/ecogesture-form') - }) - it('should render doing text with empty list on completed selection', () => { - const store = mockStore({ - ecolyo: { - profile: profileData, - global: globalStateData, - }, - }) - const wrapper = mount( - <Provider store={store}> - <EcogestureEmptyList - setTab={mockChangeTab} - isObjective={false} - isSelectionDone={true} - handleReinitClick={mockHandleClick} - /> - </Provider> - ) - - expect(wrapper.find('.text').first().text()).toBe( - 'ecogesture.emptyList.doing1_done' - ) - }) - it('should render objective text with empty list on completed selection', () => { - const store = mockStore({ - ecolyo: { - profile: profileData, - global: globalStateData, - }, - }) - const wrapper = mount( - <Provider store={store}> - <EcogestureEmptyList - setTab={mockChangeTab} - isObjective={true} - isSelectionDone={true} - handleReinitClick={mockHandleClick} - /> - </Provider> - ) - - expect(wrapper.find('.text').first().text()).toBe( - 'ecogesture.emptyList.obj1_done' - ) - }) -}) diff --git a/src/components/Ecogesture/EcogestureEmptyList/EcogestureEmptyList.spec.tsx b/src/components/Ecogesture/EcogestureEmptyList/EcogestureEmptyList.spec.tsx new file mode 100644 index 0000000000000000000000000000000000000000..d2cdc41219c4946089271ceae696567d599ad5a8 --- /dev/null +++ b/src/components/Ecogesture/EcogestureEmptyList/EcogestureEmptyList.spec.tsx @@ -0,0 +1,77 @@ +import Button from '@material-ui/core/Button' +import { mount } from 'enzyme' +import toJson from 'enzyme-to-json' +import React from 'react' +import EcogestureEmptyList from './EcogestureEmptyList' + +const mockedNavigate = jest.fn() +jest.mock('react-router-dom', () => ({ + ...jest.requireActual('react-router-dom'), + useNavigate: () => mockedNavigate, +})) +const mockChangeTab = jest.fn() +const mockHandleClick = jest.fn() + +describe('EcogestureEmptyList component', () => { + it('should be rendered correctly', () => { + const wrapper = mount( + <EcogestureEmptyList + setTab={mockChangeTab} + isObjective={true} + isSelectionDone={false} + handleReinitClick={mockHandleClick} + /> + ) + expect(toJson(wrapper)).toMatchSnapshot() + }) + it('should return to all ecogestures', () => { + const wrapper = mount( + <EcogestureEmptyList + setTab={mockChangeTab} + isObjective={false} + isSelectionDone={true} + handleReinitClick={mockHandleClick} + /> + ) + wrapper.find(Button).first().simulate('click') + expect(mockChangeTab).toHaveBeenCalledTimes(1) + }) + it('should launch ecogesture form', () => { + const wrapper = mount( + <EcogestureEmptyList + setTab={mockChangeTab} + isObjective={false} + isSelectionDone={false} + handleReinitClick={mockHandleClick} + /> + ) + wrapper.find(Button).at(1).simulate('click') + expect(mockedNavigate).toHaveBeenCalledWith('/ecogesture-form') + }) + it('should render doing text with empty list on completed selection', () => { + const wrapper = mount( + <EcogestureEmptyList + setTab={mockChangeTab} + isObjective={false} + isSelectionDone={true} + handleReinitClick={mockHandleClick} + /> + ) + expect(wrapper.find('.text').first().text()).toBe( + 'ecogesture.emptyList.doing1_done' + ) + }) + it('should render objective text with empty list on completed selection', () => { + const wrapper = mount( + <EcogestureEmptyList + setTab={mockChangeTab} + isObjective={true} + isSelectionDone={true} + handleReinitClick={mockHandleClick} + /> + ) + expect(wrapper.find('.text').first().text()).toBe( + 'ecogesture.emptyList.obj1_done' + ) + }) +}) diff --git a/src/components/Ecogesture/EcogestureEmptyList.tsx b/src/components/Ecogesture/EcogestureEmptyList/EcogestureEmptyList.tsx similarity index 100% rename from src/components/Ecogesture/EcogestureEmptyList.tsx rename to src/components/Ecogesture/EcogestureEmptyList/EcogestureEmptyList.tsx diff --git a/src/components/Ecogesture/EcogestureEmptyList/__snapshots__/EcogestureEmptyList.spec.tsx.snap b/src/components/Ecogesture/EcogestureEmptyList/__snapshots__/EcogestureEmptyList.spec.tsx.snap new file mode 100644 index 0000000000000000000000000000000000000000..d7e63538735ae0ed4c37e42a3cd0d8cab07eb0b0 --- /dev/null +++ b/src/components/Ecogesture/EcogestureEmptyList/__snapshots__/EcogestureEmptyList.spec.tsx.snap @@ -0,0 +1,328 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`EcogestureEmptyList component should be rendered correctly 1`] = ` +<EcogestureEmptyList + handleReinitClick={[MockFunction]} + isObjective={true} + isSelectionDone={false} + setTab={[MockFunction]} +> + <div + className="ec-empty-container" + > + <div + className="ec-empty-content" + > + <StyledIcon + className="icon-big" + icon="test-file-stub" + size={150} + > + <Icon + aria-hidden={true} + className="icon-big" + icon="test-file-stub" + size={150} + spin={false} + > + <Component + aria-hidden={true} + className="icon-big styles__icon___23x3R" + height={150} + style={Object {}} + width={150} + > + <svg + aria-hidden={true} + className="icon-big styles__icon___23x3R" + height={150} + style={Object {}} + width={150} + > + <use + xlinkHref="#test-file-stub" + /> + </svg> + </Component> + </Icon> + </StyledIcon> + <div + className="text-16-normal text" + > + ecogesture.emptyList.obj1 + </div> + <div + className="text-16-normal text" + > + ecogesture.emptyList.obj2 + </div> + <div + className="btn-container" + > + <WithStyles(ForwardRef(Button)) + aria-label="ecogesture.emptyList.btn1" + classes={ + Object { + "label": "text-16-bold", + "root": "btn-secondary-negative btn1", + } + } + onClick={[Function]} + > + <ForwardRef(Button) + aria-label="ecogesture.emptyList.btn1" + classes={ + Object { + "colorInherit": "MuiButton-colorInherit", + "contained": "MuiButton-contained", + "containedPrimary": "MuiButton-containedPrimary", + "containedSecondary": "MuiButton-containedSecondary", + "containedSizeLarge": "MuiButton-containedSizeLarge", + "containedSizeSmall": "MuiButton-containedSizeSmall", + "disableElevation": "MuiButton-disableElevation", + "disabled": "Mui-disabled", + "endIcon": "MuiButton-endIcon", + "focusVisible": "Mui-focusVisible", + "fullWidth": "MuiButton-fullWidth", + "iconSizeLarge": "MuiButton-iconSizeLarge", + "iconSizeMedium": "MuiButton-iconSizeMedium", + "iconSizeSmall": "MuiButton-iconSizeSmall", + "label": "MuiButton-label text-16-bold", + "outlined": "MuiButton-outlined", + "outlinedPrimary": "MuiButton-outlinedPrimary", + "outlinedSecondary": "MuiButton-outlinedSecondary", + "outlinedSizeLarge": "MuiButton-outlinedSizeLarge", + "outlinedSizeSmall": "MuiButton-outlinedSizeSmall", + "root": "MuiButton-root btn-secondary-negative btn1", + "sizeLarge": "MuiButton-sizeLarge", + "sizeSmall": "MuiButton-sizeSmall", + "startIcon": "MuiButton-startIcon", + "text": "MuiButton-text", + "textPrimary": "MuiButton-textPrimary", + "textSecondary": "MuiButton-textSecondary", + "textSizeLarge": "MuiButton-textSizeLarge", + "textSizeSmall": "MuiButton-textSizeSmall", + } + } + onClick={[Function]} + > + <WithStyles(ForwardRef(ButtonBase)) + aria-label="ecogesture.emptyList.btn1" + className="MuiButton-root btn-secondary-negative btn1 MuiButton-text" + component="button" + disabled={false} + focusRipple={true} + focusVisibleClassName="Mui-focusVisible" + onClick={[Function]} + type="button" + > + <ForwardRef(ButtonBase) + aria-label="ecogesture.emptyList.btn1" + className="MuiButton-root btn-secondary-negative btn1 MuiButton-text" + classes={ + Object { + "disabled": "Mui-disabled", + "focusVisible": "Mui-focusVisible", + "root": "MuiButtonBase-root", + } + } + component="button" + disabled={false} + focusRipple={true} + focusVisibleClassName="Mui-focusVisible" + onClick={[Function]} + type="button" + > + <button + aria-label="ecogesture.emptyList.btn1" + className="MuiButtonBase-root MuiButton-root btn-secondary-negative btn1 MuiButton-text" + disabled={false} + onBlur={[Function]} + onClick={[Function]} + onDragLeave={[Function]} + onFocus={[Function]} + onKeyDown={[Function]} + onKeyUp={[Function]} + onMouseDown={[Function]} + onMouseLeave={[Function]} + onMouseUp={[Function]} + onTouchEnd={[Function]} + onTouchMove={[Function]} + onTouchStart={[Function]} + tabIndex={0} + type="button" + > + <span + className="MuiButton-label text-16-bold" + > + ecogesture.emptyList.btn1 + </span> + <WithStyles(memo) + center={false} + > + <ForwardRef(TouchRipple) + center={false} + classes={ + Object { + "child": "MuiTouchRipple-child", + "childLeaving": "MuiTouchRipple-childLeaving", + "childPulsate": "MuiTouchRipple-childPulsate", + "ripple": "MuiTouchRipple-ripple", + "ripplePulsate": "MuiTouchRipple-ripplePulsate", + "rippleVisible": "MuiTouchRipple-rippleVisible", + "root": "MuiTouchRipple-root", + } + } + > + <span + className="MuiTouchRipple-root" + > + <TransitionGroup + childFactory={[Function]} + component={null} + exit={true} + /> + </span> + </ForwardRef(TouchRipple)> + </WithStyles(memo)> + </button> + </ForwardRef(ButtonBase)> + </WithStyles(ForwardRef(ButtonBase))> + </ForwardRef(Button)> + </WithStyles(ForwardRef(Button))> + <WithStyles(ForwardRef(Button)) + aria-label="ecogesture.emptyList.btn2" + classes={ + Object { + "label": "text-16-bold", + "root": "btn-highlight", + } + } + onClick={[Function]} + > + <ForwardRef(Button) + aria-label="ecogesture.emptyList.btn2" + classes={ + Object { + "colorInherit": "MuiButton-colorInherit", + "contained": "MuiButton-contained", + "containedPrimary": "MuiButton-containedPrimary", + "containedSecondary": "MuiButton-containedSecondary", + "containedSizeLarge": "MuiButton-containedSizeLarge", + "containedSizeSmall": "MuiButton-containedSizeSmall", + "disableElevation": "MuiButton-disableElevation", + "disabled": "Mui-disabled", + "endIcon": "MuiButton-endIcon", + "focusVisible": "Mui-focusVisible", + "fullWidth": "MuiButton-fullWidth", + "iconSizeLarge": "MuiButton-iconSizeLarge", + "iconSizeMedium": "MuiButton-iconSizeMedium", + "iconSizeSmall": "MuiButton-iconSizeSmall", + "label": "MuiButton-label text-16-bold", + "outlined": "MuiButton-outlined", + "outlinedPrimary": "MuiButton-outlinedPrimary", + "outlinedSecondary": "MuiButton-outlinedSecondary", + "outlinedSizeLarge": "MuiButton-outlinedSizeLarge", + "outlinedSizeSmall": "MuiButton-outlinedSizeSmall", + "root": "MuiButton-root btn-highlight", + "sizeLarge": "MuiButton-sizeLarge", + "sizeSmall": "MuiButton-sizeSmall", + "startIcon": "MuiButton-startIcon", + "text": "MuiButton-text", + "textPrimary": "MuiButton-textPrimary", + "textSecondary": "MuiButton-textSecondary", + "textSizeLarge": "MuiButton-textSizeLarge", + "textSizeSmall": "MuiButton-textSizeSmall", + } + } + onClick={[Function]} + > + <WithStyles(ForwardRef(ButtonBase)) + aria-label="ecogesture.emptyList.btn2" + className="MuiButton-root btn-highlight MuiButton-text" + component="button" + disabled={false} + focusRipple={true} + focusVisibleClassName="Mui-focusVisible" + onClick={[Function]} + type="button" + > + <ForwardRef(ButtonBase) + aria-label="ecogesture.emptyList.btn2" + className="MuiButton-root btn-highlight MuiButton-text" + classes={ + Object { + "disabled": "Mui-disabled", + "focusVisible": "Mui-focusVisible", + "root": "MuiButtonBase-root", + } + } + component="button" + disabled={false} + focusRipple={true} + focusVisibleClassName="Mui-focusVisible" + onClick={[Function]} + type="button" + > + <button + aria-label="ecogesture.emptyList.btn2" + className="MuiButtonBase-root MuiButton-root btn-highlight MuiButton-text" + disabled={false} + onBlur={[Function]} + onClick={[Function]} + onDragLeave={[Function]} + onFocus={[Function]} + onKeyDown={[Function]} + onKeyUp={[Function]} + onMouseDown={[Function]} + onMouseLeave={[Function]} + onMouseUp={[Function]} + onTouchEnd={[Function]} + onTouchMove={[Function]} + onTouchStart={[Function]} + tabIndex={0} + type="button" + > + <span + className="MuiButton-label text-16-bold" + > + ecogesture.emptyList.btn2 + </span> + <WithStyles(memo) + center={false} + > + <ForwardRef(TouchRipple) + center={false} + classes={ + Object { + "child": "MuiTouchRipple-child", + "childLeaving": "MuiTouchRipple-childLeaving", + "childPulsate": "MuiTouchRipple-childPulsate", + "ripple": "MuiTouchRipple-ripple", + "ripplePulsate": "MuiTouchRipple-ripplePulsate", + "rippleVisible": "MuiTouchRipple-rippleVisible", + "root": "MuiTouchRipple-root", + } + } + > + <span + className="MuiTouchRipple-root" + > + <TransitionGroup + childFactory={[Function]} + component={null} + exit={true} + /> + </span> + </ForwardRef(TouchRipple)> + </WithStyles(memo)> + </button> + </ForwardRef(ButtonBase)> + </WithStyles(ForwardRef(ButtonBase))> + </ForwardRef(Button)> + </WithStyles(ForwardRef(Button))> + </div> + </div> + </div> +</EcogestureEmptyList> +`; diff --git a/src/components/Ecogesture/ecogestureEmptyList.scss b/src/components/Ecogesture/EcogestureEmptyList/ecogestureEmptyList.scss similarity index 88% rename from src/components/Ecogesture/ecogestureEmptyList.scss rename to src/components/Ecogesture/EcogestureEmptyList/ecogestureEmptyList.scss index a072890654d9629babe8c4a94abbf687ef71efda..746d17b55f3de5c55a80ee82117a6843da3d17ab 100644 --- a/src/components/Ecogesture/ecogestureEmptyList.scss +++ b/src/components/Ecogesture/EcogestureEmptyList/ecogestureEmptyList.scss @@ -1,5 +1,5 @@ -@import '../../styles/base/color'; -@import '../../styles/base/breakpoint'; +@import 'src/styles/base/color'; +@import 'src/styles/base/breakpoint'; .ec-empty-container { margin-top: 6rem; diff --git a/src/components/Ecogesture/EcogestureInitModal.spec.tsx b/src/components/Ecogesture/EcogestureInitModal.spec.tsx deleted file mode 100644 index b6f92fd6d00ef463f5ca951ae84d52e057d3a4c5..0000000000000000000000000000000000000000 --- a/src/components/Ecogesture/EcogestureInitModal.spec.tsx +++ /dev/null @@ -1,103 +0,0 @@ -import { Button } from '@material-ui/core' -import { mount } from 'enzyme' -import toJson from 'enzyme-to-json' -import React from 'react' -import { Provider } from 'react-redux' -import configureStore from 'redux-mock-store' -import { challengeStateData } from '../../../tests/__mocks__/challengeStateData.mock' -import { globalStateData } from '../../../tests/__mocks__/globalStateData.mock' -import { mockInitialProfileState } from '../../../tests/__mocks__/store' -import EcogestureInitModal from './EcogestureInitModal' - -jest.mock('cozy-ui/transpiled/react/I18n', () => { - return { - useI18n: jest.fn(() => { - return { - t: (str: string) => str, - } - }), - } -}) -const mockImportIconById = jest.fn() -jest.mock('utils/utils', () => { - return { - importIconById: jest.fn(() => { - return mockImportIconById - }), - } -}) -const mockHistoryPush = jest.fn() -jest.mock('react-router-dom', () => ({ - ...jest.requireActual('react-router-dom'), - useNavigate: () => ({ - push: mockHistoryPush, - }), -})) - -const mockStore = configureStore([]) -const mockHandleClose = jest.fn() -const mockHandleLaunchForm = jest.fn() -describe('EcogestureInitModal component', () => { - it('should be rendered correctly', () => { - const store = mockStore({ - ecolyo: { - global: globalStateData, - profile: mockInitialProfileState, - challenge: challengeStateData, - }, - }) - - const wrapper = mount( - <Provider store={store}> - <EcogestureInitModal - open={true} - handleCloseClick={mockHandleClose} - handleLaunchForm={mockHandleLaunchForm} - /> - </Provider> - ) - expect(toJson(wrapper)).toMatchSnapshot() - }) - it('should close modal ', () => { - const store = mockStore({ - ecolyo: { - global: globalStateData, - challenge: challengeStateData, - profile: mockInitialProfileState, - }, - }) - - const wrapper = mount( - <Provider store={store}> - <EcogestureInitModal - open={true} - handleCloseClick={mockHandleClose} - handleLaunchForm={mockHandleLaunchForm} - /> - </Provider> - ) - wrapper.find(Button).first().simulate('click') - expect(mockHandleClose).toHaveBeenCalledTimes(1) - }) - it('should close modal and maunch form', async () => { - const store = mockStore({ - ecolyo: { - global: globalStateData, - profile: mockInitialProfileState, - challenge: challengeStateData, - }, - }) - - const wrapper = mount( - <Provider store={store}> - <EcogestureInitModal - open={true} - handleCloseClick={mockHandleClose} - handleLaunchForm={mockHandleLaunchForm} - /> - </Provider> - ) - wrapper.find(Button).at(1).simulate('click') - expect(mockHandleLaunchForm).toHaveBeenCalledTimes(1) - }) -}) diff --git a/src/components/Ecogesture/EcogestureInitModal/EcogestureInitModal.spec.tsx b/src/components/Ecogesture/EcogestureInitModal/EcogestureInitModal.spec.tsx new file mode 100644 index 0000000000000000000000000000000000000000..7f04115005180020e5dbc90cd4dda9735670ef71 --- /dev/null +++ b/src/components/Ecogesture/EcogestureInitModal/EcogestureInitModal.spec.tsx @@ -0,0 +1,42 @@ +import { Button } from '@material-ui/core' +import { mount } from 'enzyme' +import toJson from 'enzyme-to-json' +import React from 'react' +import EcogestureInitModal from './EcogestureInitModal' + +const mockHandleClose = jest.fn() +const mockHandleLaunchForm = jest.fn() +describe('EcogestureInitModal component', () => { + it('should be rendered correctly', () => { + const wrapper = mount( + <EcogestureInitModal + open={true} + handleCloseClick={mockHandleClose} + handleLaunchForm={mockHandleLaunchForm} + /> + ) + expect(toJson(wrapper)).toMatchSnapshot() + }) + it('should close modal', () => { + const wrapper = mount( + <EcogestureInitModal + open={true} + handleCloseClick={mockHandleClose} + handleLaunchForm={mockHandleLaunchForm} + /> + ) + wrapper.find(Button).first().simulate('click') + expect(mockHandleClose).toHaveBeenCalledTimes(1) + }) + it('should close modal and launch form', async () => { + const wrapper = mount( + <EcogestureInitModal + open={true} + handleCloseClick={mockHandleClose} + handleLaunchForm={mockHandleLaunchForm} + /> + ) + wrapper.find(Button).at(1).simulate('click') + expect(mockHandleLaunchForm).toHaveBeenCalledTimes(1) + }) +}) diff --git a/src/components/Ecogesture/EcogestureInitModal.tsx b/src/components/Ecogesture/EcogestureInitModal/EcogestureInitModal.tsx similarity index 94% rename from src/components/Ecogesture/EcogestureInitModal.tsx rename to src/components/Ecogesture/EcogestureInitModal/EcogestureInitModal.tsx index e20e0a60e9030e4e5365c6c7c2b1e302421560bf..17894f0caa1bd2b827fecb408d2c83e3592e4148 100644 --- a/src/components/Ecogesture/EcogestureInitModal.tsx +++ b/src/components/Ecogesture/EcogestureInitModal/EcogestureInitModal.tsx @@ -5,11 +5,13 @@ import { useI18n } from 'cozy-ui/transpiled/react/I18n' import Icon from 'cozy-ui/transpiled/react/Icon' import React from 'react' import './ecogestureInitModal.scss' + interface EcogestureInitModalProps { open: boolean handleCloseClick: () => void handleLaunchForm: () => void } + const EcogestureInitModal = ({ open, handleCloseClick, @@ -20,13 +22,13 @@ const EcogestureInitModal = ({ <Dialog open={open} onClose={handleCloseClick} - aria-labelledby={'accessibility-title'} + aria-labelledby="accessibility-title" classes={{ root: 'modal-root', paper: 'modal-paper', }} > - <div id={'accessibility-title'}> + <div id="accessibility-title"> {t('feedback.accessibility.window_title')} </div> <IconButton @@ -50,7 +52,6 @@ const EcogestureInitModal = ({ <Button aria-label={t('ecogesture.initModal.btn1')} onClick={handleCloseClick} - className="btn1" classes={{ root: 'btn-secondary-negative', label: 'text-16-bold', diff --git a/src/components/Ecogesture/EcogestureInitModal/__snapshots__/EcogestureInitModal.spec.tsx.snap b/src/components/Ecogesture/EcogestureInitModal/__snapshots__/EcogestureInitModal.spec.tsx.snap new file mode 100644 index 0000000000000000000000000000000000000000..17cb411330be9a6b0aa4f5975b6646eb88d16879 --- /dev/null +++ b/src/components/Ecogesture/EcogestureInitModal/__snapshots__/EcogestureInitModal.spec.tsx.snap @@ -0,0 +1,1128 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`EcogestureInitModal component should be rendered correctly 1`] = ` +<EcogestureInitModal + handleCloseClick={[MockFunction]} + handleLaunchForm={[MockFunction]} + open={true} +> + <WithStyles(ForwardRef(Dialog)) + aria-labelledby="accessibility-title" + classes={ + Object { + "paper": "modal-paper", + "root": "modal-root", + } + } + onClose={[MockFunction]} + open={true} + > + <ForwardRef(Dialog) + aria-labelledby="accessibility-title" + classes={ + Object { + "container": "MuiDialog-container", + "paper": "MuiDialog-paper modal-paper", + "paperFullScreen": "MuiDialog-paperFullScreen", + "paperFullWidth": "MuiDialog-paperFullWidth", + "paperScrollBody": "MuiDialog-paperScrollBody", + "paperScrollPaper": "MuiDialog-paperScrollPaper", + "paperWidthFalse": "MuiDialog-paperWidthFalse", + "paperWidthLg": "MuiDialog-paperWidthLg", + "paperWidthMd": "MuiDialog-paperWidthMd", + "paperWidthSm": "MuiDialog-paperWidthSm", + "paperWidthXl": "MuiDialog-paperWidthXl", + "paperWidthXs": "MuiDialog-paperWidthXs", + "root": "MuiDialog-root modal-root", + "scrollBody": "MuiDialog-scrollBody", + "scrollPaper": "MuiDialog-scrollPaper", + } + } + onClose={[MockFunction]} + open={true} + > + <ForwardRef(Modal) + BackdropComponent={ + Object { + "$$typeof": Symbol(react.forward_ref), + "Naked": Object { + "$$typeof": Symbol(react.forward_ref), + "propTypes": Object { + "children": [Function], + "className": [Function], + "classes": [Function], + "invisible": [Function], + "open": [Function], + "transitionDuration": [Function], + }, + "render": [Function], + }, + "displayName": "WithStyles(ForwardRef(Backdrop))", + "options": Object { + "defaultTheme": Object { + "breakpoints": Object { + "between": [Function], + "down": [Function], + "keys": Array [ + "xs", + "sm", + "md", + "lg", + "xl", + ], + "only": [Function], + "up": [Function], + "values": Object { + "lg": 1280, + "md": 960, + "sm": 600, + "xl": 1920, + "xs": 0, + }, + "width": [Function], + }, + "direction": "ltr", + "mixins": Object { + "gutters": [Function], + "toolbar": Object { + "@media (min-width:0px) and (orientation: landscape)": Object { + "minHeight": 48, + }, + "@media (min-width:600px)": Object { + "minHeight": 64, + }, + "minHeight": 56, + }, + }, + "overrides": Object {}, + "palette": Object { + "action": Object { + "activatedOpacity": 0.12, + "active": "rgba(0, 0, 0, 0.54)", + "disabled": "rgba(0, 0, 0, 0.26)", + "disabledBackground": "rgba(0, 0, 0, 0.12)", + "disabledOpacity": 0.38, + "focus": "rgba(0, 0, 0, 0.12)", + "focusOpacity": 0.12, + "hover": "rgba(0, 0, 0, 0.04)", + "hoverOpacity": 0.04, + "selected": "rgba(0, 0, 0, 0.08)", + "selectedOpacity": 0.08, + }, + "augmentColor": [Function], + "background": Object { + "default": "#fafafa", + "paper": "#fff", + }, + "common": Object { + "black": "#000", + "white": "#fff", + }, + "contrastThreshold": 3, + "divider": "rgba(0, 0, 0, 0.12)", + "error": Object { + "contrastText": "#fff", + "dark": "#d32f2f", + "light": "#e57373", + "main": "#f44336", + }, + "getContrastText": [Function], + "grey": Object { + "100": "#f5f5f5", + "200": "#eeeeee", + "300": "#e0e0e0", + "400": "#bdbdbd", + "50": "#fafafa", + "500": "#9e9e9e", + "600": "#757575", + "700": "#616161", + "800": "#424242", + "900": "#212121", + "A100": "#d5d5d5", + "A200": "#aaaaaa", + "A400": "#303030", + "A700": "#616161", + }, + "info": Object { + "contrastText": "#fff", + "dark": "#1976d2", + "light": "#64b5f6", + "main": "#2196f3", + }, + "primary": Object { + "contrastText": "#fff", + "dark": "#303f9f", + "light": "#7986cb", + "main": "#3f51b5", + }, + "secondary": Object { + "contrastText": "#fff", + "dark": "#c51162", + "light": "#ff4081", + "main": "#f50057", + }, + "success": Object { + "contrastText": "rgba(0, 0, 0, 0.87)", + "dark": "#388e3c", + "light": "#81c784", + "main": "#4caf50", + }, + "text": Object { + "disabled": "rgba(0, 0, 0, 0.38)", + "hint": "rgba(0, 0, 0, 0.38)", + "primary": "rgba(0, 0, 0, 0.87)", + "secondary": "rgba(0, 0, 0, 0.54)", + }, + "tonalOffset": 0.2, + "type": "light", + "warning": Object { + "contrastText": "rgba(0, 0, 0, 0.87)", + "dark": "#f57c00", + "light": "#ffb74d", + "main": "#ff9800", + }, + }, + "props": Object {}, + "shadows": Array [ + "none", + "0px 2px 1px -1px rgba(0,0,0,0.2),0px 1px 1px 0px rgba(0,0,0,0.14),0px 1px 3px 0px rgba(0,0,0,0.12)", + "0px 3px 1px -2px rgba(0,0,0,0.2),0px 2px 2px 0px rgba(0,0,0,0.14),0px 1px 5px 0px rgba(0,0,0,0.12)", + "0px 3px 3px -2px rgba(0,0,0,0.2),0px 3px 4px 0px rgba(0,0,0,0.14),0px 1px 8px 0px rgba(0,0,0,0.12)", + "0px 2px 4px -1px rgba(0,0,0,0.2),0px 4px 5px 0px rgba(0,0,0,0.14),0px 1px 10px 0px rgba(0,0,0,0.12)", + "0px 3px 5px -1px rgba(0,0,0,0.2),0px 5px 8px 0px rgba(0,0,0,0.14),0px 1px 14px 0px rgba(0,0,0,0.12)", + "0px 3px 5px -1px rgba(0,0,0,0.2),0px 6px 10px 0px rgba(0,0,0,0.14),0px 1px 18px 0px rgba(0,0,0,0.12)", + "0px 4px 5px -2px rgba(0,0,0,0.2),0px 7px 10px 1px rgba(0,0,0,0.14),0px 2px 16px 1px rgba(0,0,0,0.12)", + "0px 5px 5px -3px rgba(0,0,0,0.2),0px 8px 10px 1px rgba(0,0,0,0.14),0px 3px 14px 2px rgba(0,0,0,0.12)", + "0px 5px 6px -3px rgba(0,0,0,0.2),0px 9px 12px 1px rgba(0,0,0,0.14),0px 3px 16px 2px rgba(0,0,0,0.12)", + "0px 6px 6px -3px rgba(0,0,0,0.2),0px 10px 14px 1px rgba(0,0,0,0.14),0px 4px 18px 3px rgba(0,0,0,0.12)", + "0px 6px 7px -4px rgba(0,0,0,0.2),0px 11px 15px 1px rgba(0,0,0,0.14),0px 4px 20px 3px rgba(0,0,0,0.12)", + "0px 7px 8px -4px rgba(0,0,0,0.2),0px 12px 17px 2px rgba(0,0,0,0.14),0px 5px 22px 4px rgba(0,0,0,0.12)", + "0px 7px 8px -4px rgba(0,0,0,0.2),0px 13px 19px 2px rgba(0,0,0,0.14),0px 5px 24px 4px rgba(0,0,0,0.12)", + "0px 7px 9px -4px rgba(0,0,0,0.2),0px 14px 21px 2px rgba(0,0,0,0.14),0px 5px 26px 4px rgba(0,0,0,0.12)", + "0px 8px 9px -5px rgba(0,0,0,0.2),0px 15px 22px 2px rgba(0,0,0,0.14),0px 6px 28px 5px rgba(0,0,0,0.12)", + "0px 8px 10px -5px rgba(0,0,0,0.2),0px 16px 24px 2px rgba(0,0,0,0.14),0px 6px 30px 5px rgba(0,0,0,0.12)", + "0px 8px 11px -5px rgba(0,0,0,0.2),0px 17px 26px 2px rgba(0,0,0,0.14),0px 6px 32px 5px rgba(0,0,0,0.12)", + "0px 9px 11px -5px rgba(0,0,0,0.2),0px 18px 28px 2px rgba(0,0,0,0.14),0px 7px 34px 6px rgba(0,0,0,0.12)", + "0px 9px 12px -6px rgba(0,0,0,0.2),0px 19px 29px 2px rgba(0,0,0,0.14),0px 7px 36px 6px rgba(0,0,0,0.12)", + "0px 10px 13px -6px rgba(0,0,0,0.2),0px 20px 31px 3px rgba(0,0,0,0.14),0px 8px 38px 7px rgba(0,0,0,0.12)", + "0px 10px 13px -6px rgba(0,0,0,0.2),0px 21px 33px 3px rgba(0,0,0,0.14),0px 8px 40px 7px rgba(0,0,0,0.12)", + "0px 10px 14px -6px rgba(0,0,0,0.2),0px 22px 35px 3px rgba(0,0,0,0.14),0px 8px 42px 7px rgba(0,0,0,0.12)", + "0px 11px 14px -7px rgba(0,0,0,0.2),0px 23px 36px 3px rgba(0,0,0,0.14),0px 9px 44px 8px rgba(0,0,0,0.12)", + "0px 11px 15px -7px rgba(0,0,0,0.2),0px 24px 38px 3px rgba(0,0,0,0.14),0px 9px 46px 8px rgba(0,0,0,0.12)", + ], + "shape": Object { + "borderRadius": 4, + }, + "spacing": [Function], + "transitions": Object { + "create": [Function], + "duration": Object { + "complex": 375, + "enteringScreen": 225, + "leavingScreen": 195, + "short": 250, + "shorter": 200, + "shortest": 150, + "standard": 300, + }, + "easing": Object { + "easeIn": "cubic-bezier(0.4, 0, 1, 1)", + "easeInOut": "cubic-bezier(0.4, 0, 0.2, 1)", + "easeOut": "cubic-bezier(0.0, 0, 0.2, 1)", + "sharp": "cubic-bezier(0.4, 0, 0.6, 1)", + }, + "getAutoHeightDuration": [Function], + }, + "typography": Object { + "body1": Object { + "fontFamily": "\\"Roboto\\", \\"Helvetica\\", \\"Arial\\", sans-serif", + "fontSize": "1rem", + "fontWeight": 400, + "letterSpacing": "0.00938em", + "lineHeight": 1.5, + }, + "body2": Object { + "fontFamily": "\\"Roboto\\", \\"Helvetica\\", \\"Arial\\", sans-serif", + "fontSize": "0.875rem", + "fontWeight": 400, + "letterSpacing": "0.01071em", + "lineHeight": 1.43, + }, + "button": Object { + "fontFamily": "\\"Roboto\\", \\"Helvetica\\", \\"Arial\\", sans-serif", + "fontSize": "0.875rem", + "fontWeight": 500, + "letterSpacing": "0.02857em", + "lineHeight": 1.75, + "textTransform": "uppercase", + }, + "caption": Object { + "fontFamily": "\\"Roboto\\", \\"Helvetica\\", \\"Arial\\", sans-serif", + "fontSize": "0.75rem", + "fontWeight": 400, + "letterSpacing": "0.03333em", + "lineHeight": 1.66, + }, + "fontFamily": "\\"Roboto\\", \\"Helvetica\\", \\"Arial\\", sans-serif", + "fontSize": 14, + "fontWeightBold": 700, + "fontWeightLight": 300, + "fontWeightMedium": 500, + "fontWeightRegular": 400, + "h1": Object { + "fontFamily": "\\"Roboto\\", \\"Helvetica\\", \\"Arial\\", sans-serif", + "fontSize": "6rem", + "fontWeight": 300, + "letterSpacing": "-0.01562em", + "lineHeight": 1.167, + }, + "h2": Object { + "fontFamily": "\\"Roboto\\", \\"Helvetica\\", \\"Arial\\", sans-serif", + "fontSize": "3.75rem", + "fontWeight": 300, + "letterSpacing": "-0.00833em", + "lineHeight": 1.2, + }, + "h3": Object { + "fontFamily": "\\"Roboto\\", \\"Helvetica\\", \\"Arial\\", sans-serif", + "fontSize": "3rem", + "fontWeight": 400, + "letterSpacing": "0em", + "lineHeight": 1.167, + }, + "h4": Object { + "fontFamily": "\\"Roboto\\", \\"Helvetica\\", \\"Arial\\", sans-serif", + "fontSize": "2.125rem", + "fontWeight": 400, + "letterSpacing": "0.00735em", + "lineHeight": 1.235, + }, + "h5": Object { + "fontFamily": "\\"Roboto\\", \\"Helvetica\\", \\"Arial\\", sans-serif", + "fontSize": "1.5rem", + "fontWeight": 400, + "letterSpacing": "0em", + "lineHeight": 1.334, + }, + "h6": Object { + "fontFamily": "\\"Roboto\\", \\"Helvetica\\", \\"Arial\\", sans-serif", + "fontSize": "1.25rem", + "fontWeight": 500, + "letterSpacing": "0.0075em", + "lineHeight": 1.6, + }, + "htmlFontSize": 16, + "overline": Object { + "fontFamily": "\\"Roboto\\", \\"Helvetica\\", \\"Arial\\", sans-serif", + "fontSize": "0.75rem", + "fontWeight": 400, + "letterSpacing": "0.08333em", + "lineHeight": 2.66, + "textTransform": "uppercase", + }, + "pxToRem": [Function], + "round": [Function], + "subtitle1": Object { + "fontFamily": "\\"Roboto\\", \\"Helvetica\\", \\"Arial\\", sans-serif", + "fontSize": "1rem", + "fontWeight": 400, + "letterSpacing": "0.00938em", + "lineHeight": 1.75, + }, + "subtitle2": Object { + "fontFamily": "\\"Roboto\\", \\"Helvetica\\", \\"Arial\\", sans-serif", + "fontSize": "0.875rem", + "fontWeight": 500, + "letterSpacing": "0.00714em", + "lineHeight": 1.57, + }, + }, + "zIndex": Object { + "appBar": 1100, + "drawer": 1200, + "mobileStepper": 1000, + "modal": 1300, + "snackbar": 1400, + "speedDial": 1050, + "tooltip": 1500, + }, + }, + "name": "MuiBackdrop", + }, + "propTypes": Object { + "classes": [Function], + "innerRef": [Function], + }, + "render": [Function], + "useStyles": [Function], + } + } + BackdropProps={ + Object { + "transitionDuration": Object { + "enter": 225, + "exit": 195, + }, + } + } + className="MuiDialog-root modal-root" + closeAfterTransition={true} + disableEscapeKeyDown={false} + onClose={[MockFunction]} + open={true} + > + <ForwardRef(Portal) + disablePortal={false} + > + <Portal + containerInfo={ + <body + style="padding-right: 0px; overflow: hidden;" + > + <div + class="MuiDialog-root modal-root" + role="presentation" + style="position: fixed; z-index: 1300; right: 0px; bottom: 0px; top: 0px; left: 0px;" + > + <div + aria-hidden="true" + class="MuiBackdrop-root" + style="opacity: 1; webkit-transition: opacity 225ms cubic-bezier(0.4, 0, 0.2, 1) 0ms; transition: opacity 225ms cubic-bezier(0.4, 0, 0.2, 1) 0ms;" + /> + <div + data-test="sentinelStart" + tabindex="0" + /> + <div + class="MuiDialog-container MuiDialog-scrollPaper" + role="none presentation" + style="opacity: 1; webkit-transition: opacity 225ms cubic-bezier(0.4, 0, 0.2, 1) 0ms; transition: opacity 225ms cubic-bezier(0.4, 0, 0.2, 1) 0ms;" + tabindex="-1" + > + <div + aria-labelledby="accessibility-title" + class="MuiPaper-root MuiDialog-paper modal-paper MuiDialog-paperScrollPaper MuiDialog-paperWidthSm MuiPaper-elevation24 MuiPaper-rounded" + role="dialog" + > + <div + id="accessibility-title" + > + feedback.accessibility.window_title + </div> + <button + aria-label="feedback.accessibility.button_close" + class="MuiButtonBase-root MuiIconButton-root modal-paper-close-button" + tabindex="0" + type="button" + > + <span + class="MuiIconButton-label" + > + <svg + class="styles__icon___23x3R" + height="16" + width="16" + > + <use + xlink:href="#test-file-stub" + /> + </svg> + </span> + <span + class="MuiTouchRipple-root" + /> + </button> + <div + class="eg-init-modal" + > + <div + class="title text-20-bold" + > + ecogesture.initModal.title + </div> + <div + class="text-16-normal text" + > + ecogesture.initModal.text1 + </div> + <div + class="text-16-normal text" + > + ecogesture.initModal.text2 + </div> + <div + class="buttons-container" + > + <button + aria-label="ecogesture.initModal.btn1" + class="MuiButtonBase-root MuiButton-root btn-secondary-negative MuiButton-text" + tabindex="0" + type="button" + > + <span + class="MuiButton-label text-16-bold" + > + ecogesture.initModal.btn1 + </span> + <span + class="MuiTouchRipple-root" + /> + </button> + <button + aria-label="ecogesture.initModal.btn2" + class="MuiButtonBase-root MuiButton-root btn-profile-next rounded MuiButton-text" + tabindex="0" + type="button" + > + <span + class="MuiButton-label text-16-bold" + > + ecogesture.initModal.btn2 + </span> + <span + class="MuiTouchRipple-root" + /> + </button> + </div> + </div> + </div> + </div> + <div + data-test="sentinelEnd" + tabindex="0" + /> + </div> + </body> + } + > + <div + className="MuiDialog-root modal-root" + onKeyDown={[Function]} + role="presentation" + style={ + Object { + "bottom": 0, + "left": 0, + "position": "fixed", + "right": 0, + "top": 0, + "zIndex": 1300, + } + } + > + <WithStyles(ForwardRef(Backdrop)) + onClick={[Function]} + open={true} + transitionDuration={ + Object { + "enter": 225, + "exit": 195, + } + } + > + <ForwardRef(Backdrop) + classes={ + Object { + "invisible": "MuiBackdrop-invisible", + "root": "MuiBackdrop-root", + } + } + onClick={[Function]} + open={true} + transitionDuration={ + Object { + "enter": 225, + "exit": 195, + } + } + > + <ForwardRef(Fade) + in={true} + onClick={[Function]} + timeout={ + Object { + "enter": 225, + "exit": 195, + } + } + > + <Transition + appear={true} + enter={true} + exit={true} + in={true} + mountOnEnter={false} + onClick={[Function]} + onEnter={[Function]} + onEntered={[Function]} + onEntering={[Function]} + onExit={[Function]} + onExited={[Function]} + onExiting={[Function]} + timeout={ + Object { + "enter": 225, + "exit": 195, + } + } + unmountOnExit={false} + > + <div + aria-hidden={true} + className="MuiBackdrop-root" + onClick={[Function]} + style={ + Object { + "opacity": 1, + "visibility": undefined, + } + } + /> + </Transition> + </ForwardRef(Fade)> + </ForwardRef(Backdrop)> + </WithStyles(ForwardRef(Backdrop))> + <Unstable_TrapFocus + disableAutoFocus={false} + disableEnforceFocus={false} + disableRestoreFocus={false} + getDoc={[Function]} + isEnabled={[Function]} + open={true} + > + <div + data-test="sentinelStart" + tabIndex={0} + /> + <ForwardRef(Fade) + appear={true} + in={true} + onEnter={[Function]} + onExited={[Function]} + role="none presentation" + tabIndex="-1" + timeout={ + Object { + "enter": 225, + "exit": 195, + } + } + > + <Transition + appear={true} + enter={true} + exit={true} + in={true} + mountOnEnter={false} + onEnter={[Function]} + onEntered={[Function]} + onEntering={[Function]} + onExit={[Function]} + onExited={[Function]} + onExiting={[Function]} + role="none presentation" + tabIndex="-1" + timeout={ + Object { + "enter": 225, + "exit": 195, + } + } + unmountOnExit={false} + > + <div + className="MuiDialog-container MuiDialog-scrollPaper" + onMouseDown={[Function]} + onMouseUp={[Function]} + role="none presentation" + style={ + Object { + "opacity": 1, + "visibility": undefined, + } + } + tabIndex="-1" + > + <WithStyles(ForwardRef(Paper)) + aria-labelledby="accessibility-title" + className="MuiDialog-paper modal-paper MuiDialog-paperScrollPaper MuiDialog-paperWidthSm" + elevation={24} + role="dialog" + > + <ForwardRef(Paper) + aria-labelledby="accessibility-title" + className="MuiDialog-paper modal-paper MuiDialog-paperScrollPaper MuiDialog-paperWidthSm" + classes={ + Object { + "elevation0": "MuiPaper-elevation0", + "elevation1": "MuiPaper-elevation1", + "elevation10": "MuiPaper-elevation10", + "elevation11": "MuiPaper-elevation11", + "elevation12": "MuiPaper-elevation12", + "elevation13": "MuiPaper-elevation13", + "elevation14": "MuiPaper-elevation14", + "elevation15": "MuiPaper-elevation15", + "elevation16": "MuiPaper-elevation16", + "elevation17": "MuiPaper-elevation17", + "elevation18": "MuiPaper-elevation18", + "elevation19": "MuiPaper-elevation19", + "elevation2": "MuiPaper-elevation2", + "elevation20": "MuiPaper-elevation20", + "elevation21": "MuiPaper-elevation21", + "elevation22": "MuiPaper-elevation22", + "elevation23": "MuiPaper-elevation23", + "elevation24": "MuiPaper-elevation24", + "elevation3": "MuiPaper-elevation3", + "elevation4": "MuiPaper-elevation4", + "elevation5": "MuiPaper-elevation5", + "elevation6": "MuiPaper-elevation6", + "elevation7": "MuiPaper-elevation7", + "elevation8": "MuiPaper-elevation8", + "elevation9": "MuiPaper-elevation9", + "outlined": "MuiPaper-outlined", + "root": "MuiPaper-root", + "rounded": "MuiPaper-rounded", + } + } + elevation={24} + role="dialog" + > + <div + aria-labelledby="accessibility-title" + className="MuiPaper-root MuiDialog-paper modal-paper MuiDialog-paperScrollPaper MuiDialog-paperWidthSm MuiPaper-elevation24 MuiPaper-rounded" + role="dialog" + > + <div + id="accessibility-title" + > + feedback.accessibility.window_title + </div> + <WithStyles(ForwardRef(IconButton)) + aria-label="feedback.accessibility.button_close" + className="modal-paper-close-button" + onClick={[MockFunction]} + > + <ForwardRef(IconButton) + aria-label="feedback.accessibility.button_close" + className="modal-paper-close-button" + classes={ + Object { + "colorInherit": "MuiIconButton-colorInherit", + "colorPrimary": "MuiIconButton-colorPrimary", + "colorSecondary": "MuiIconButton-colorSecondary", + "disabled": "Mui-disabled", + "edgeEnd": "MuiIconButton-edgeEnd", + "edgeStart": "MuiIconButton-edgeStart", + "label": "MuiIconButton-label", + "root": "MuiIconButton-root", + "sizeSmall": "MuiIconButton-sizeSmall", + } + } + onClick={[MockFunction]} + > + <WithStyles(ForwardRef(ButtonBase)) + aria-label="feedback.accessibility.button_close" + centerRipple={true} + className="MuiIconButton-root modal-paper-close-button" + disabled={false} + focusRipple={true} + onClick={[MockFunction]} + > + <ForwardRef(ButtonBase) + aria-label="feedback.accessibility.button_close" + centerRipple={true} + className="MuiIconButton-root modal-paper-close-button" + classes={ + Object { + "disabled": "Mui-disabled", + "focusVisible": "Mui-focusVisible", + "root": "MuiButtonBase-root", + } + } + disabled={false} + focusRipple={true} + onClick={[MockFunction]} + > + <button + aria-label="feedback.accessibility.button_close" + className="MuiButtonBase-root MuiIconButton-root modal-paper-close-button" + disabled={false} + onBlur={[Function]} + onClick={[MockFunction]} + onDragLeave={[Function]} + onFocus={[Function]} + onKeyDown={[Function]} + onKeyUp={[Function]} + onMouseDown={[Function]} + onMouseLeave={[Function]} + onMouseUp={[Function]} + onTouchEnd={[Function]} + onTouchMove={[Function]} + onTouchStart={[Function]} + tabIndex={0} + type="button" + > + <span + className="MuiIconButton-label" + > + <Icon + icon="test-file-stub" + size={16} + spin={false} + > + <Component + className="styles__icon___23x3R" + height={16} + style={Object {}} + width={16} + > + <svg + className="styles__icon___23x3R" + height={16} + style={Object {}} + width={16} + > + <use + xlinkHref="#test-file-stub" + /> + </svg> + </Component> + </Icon> + </span> + <WithStyles(memo) + center={true} + > + <ForwardRef(TouchRipple) + center={true} + classes={ + Object { + "child": "MuiTouchRipple-child", + "childLeaving": "MuiTouchRipple-childLeaving", + "childPulsate": "MuiTouchRipple-childPulsate", + "ripple": "MuiTouchRipple-ripple", + "ripplePulsate": "MuiTouchRipple-ripplePulsate", + "rippleVisible": "MuiTouchRipple-rippleVisible", + "root": "MuiTouchRipple-root", + } + } + > + <span + className="MuiTouchRipple-root" + > + <TransitionGroup + childFactory={[Function]} + component={null} + exit={true} + /> + </span> + </ForwardRef(TouchRipple)> + </WithStyles(memo)> + </button> + </ForwardRef(ButtonBase)> + </WithStyles(ForwardRef(ButtonBase))> + </ForwardRef(IconButton)> + </WithStyles(ForwardRef(IconButton))> + <div + className="eg-init-modal" + > + <div + className="title text-20-bold" + > + ecogesture.initModal.title + </div> + <div + className="text-16-normal text" + > + ecogesture.initModal.text1 + </div> + <div + className="text-16-normal text" + > + ecogesture.initModal.text2 + </div> + <div + className="buttons-container" + > + <WithStyles(ForwardRef(Button)) + aria-label="ecogesture.initModal.btn1" + classes={ + Object { + "label": "text-16-bold", + "root": "btn-secondary-negative", + } + } + onClick={[MockFunction]} + > + <ForwardRef(Button) + aria-label="ecogesture.initModal.btn1" + classes={ + Object { + "colorInherit": "MuiButton-colorInherit", + "contained": "MuiButton-contained", + "containedPrimary": "MuiButton-containedPrimary", + "containedSecondary": "MuiButton-containedSecondary", + "containedSizeLarge": "MuiButton-containedSizeLarge", + "containedSizeSmall": "MuiButton-containedSizeSmall", + "disableElevation": "MuiButton-disableElevation", + "disabled": "Mui-disabled", + "endIcon": "MuiButton-endIcon", + "focusVisible": "Mui-focusVisible", + "fullWidth": "MuiButton-fullWidth", + "iconSizeLarge": "MuiButton-iconSizeLarge", + "iconSizeMedium": "MuiButton-iconSizeMedium", + "iconSizeSmall": "MuiButton-iconSizeSmall", + "label": "MuiButton-label text-16-bold", + "outlined": "MuiButton-outlined", + "outlinedPrimary": "MuiButton-outlinedPrimary", + "outlinedSecondary": "MuiButton-outlinedSecondary", + "outlinedSizeLarge": "MuiButton-outlinedSizeLarge", + "outlinedSizeSmall": "MuiButton-outlinedSizeSmall", + "root": "MuiButton-root btn-secondary-negative", + "sizeLarge": "MuiButton-sizeLarge", + "sizeSmall": "MuiButton-sizeSmall", + "startIcon": "MuiButton-startIcon", + "text": "MuiButton-text", + "textPrimary": "MuiButton-textPrimary", + "textSecondary": "MuiButton-textSecondary", + "textSizeLarge": "MuiButton-textSizeLarge", + "textSizeSmall": "MuiButton-textSizeSmall", + } + } + onClick={[MockFunction]} + > + <WithStyles(ForwardRef(ButtonBase)) + aria-label="ecogesture.initModal.btn1" + className="MuiButton-root btn-secondary-negative MuiButton-text" + component="button" + disabled={false} + focusRipple={true} + focusVisibleClassName="Mui-focusVisible" + onClick={[MockFunction]} + type="button" + > + <ForwardRef(ButtonBase) + aria-label="ecogesture.initModal.btn1" + className="MuiButton-root btn-secondary-negative MuiButton-text" + classes={ + Object { + "disabled": "Mui-disabled", + "focusVisible": "Mui-focusVisible", + "root": "MuiButtonBase-root", + } + } + component="button" + disabled={false} + focusRipple={true} + focusVisibleClassName="Mui-focusVisible" + onClick={[MockFunction]} + type="button" + > + <button + aria-label="ecogesture.initModal.btn1" + className="MuiButtonBase-root MuiButton-root btn-secondary-negative MuiButton-text" + disabled={false} + onBlur={[Function]} + onClick={[MockFunction]} + onDragLeave={[Function]} + onFocus={[Function]} + onKeyDown={[Function]} + onKeyUp={[Function]} + onMouseDown={[Function]} + onMouseLeave={[Function]} + onMouseUp={[Function]} + onTouchEnd={[Function]} + onTouchMove={[Function]} + onTouchStart={[Function]} + tabIndex={0} + type="button" + > + <span + className="MuiButton-label text-16-bold" + > + ecogesture.initModal.btn1 + </span> + <WithStyles(memo) + center={false} + > + <ForwardRef(TouchRipple) + center={false} + classes={ + Object { + "child": "MuiTouchRipple-child", + "childLeaving": "MuiTouchRipple-childLeaving", + "childPulsate": "MuiTouchRipple-childPulsate", + "ripple": "MuiTouchRipple-ripple", + "ripplePulsate": "MuiTouchRipple-ripplePulsate", + "rippleVisible": "MuiTouchRipple-rippleVisible", + "root": "MuiTouchRipple-root", + } + } + > + <span + className="MuiTouchRipple-root" + > + <TransitionGroup + childFactory={[Function]} + component={null} + exit={true} + /> + </span> + </ForwardRef(TouchRipple)> + </WithStyles(memo)> + </button> + </ForwardRef(ButtonBase)> + </WithStyles(ForwardRef(ButtonBase))> + </ForwardRef(Button)> + </WithStyles(ForwardRef(Button))> + <WithStyles(ForwardRef(Button)) + aria-label="ecogesture.initModal.btn2" + classes={ + Object { + "label": "text-16-bold", + "root": "btn-profile-next rounded", + } + } + onClick={[MockFunction]} + > + <ForwardRef(Button) + aria-label="ecogesture.initModal.btn2" + classes={ + Object { + "colorInherit": "MuiButton-colorInherit", + "contained": "MuiButton-contained", + "containedPrimary": "MuiButton-containedPrimary", + "containedSecondary": "MuiButton-containedSecondary", + "containedSizeLarge": "MuiButton-containedSizeLarge", + "containedSizeSmall": "MuiButton-containedSizeSmall", + "disableElevation": "MuiButton-disableElevation", + "disabled": "Mui-disabled", + "endIcon": "MuiButton-endIcon", + "focusVisible": "Mui-focusVisible", + "fullWidth": "MuiButton-fullWidth", + "iconSizeLarge": "MuiButton-iconSizeLarge", + "iconSizeMedium": "MuiButton-iconSizeMedium", + "iconSizeSmall": "MuiButton-iconSizeSmall", + "label": "MuiButton-label text-16-bold", + "outlined": "MuiButton-outlined", + "outlinedPrimary": "MuiButton-outlinedPrimary", + "outlinedSecondary": "MuiButton-outlinedSecondary", + "outlinedSizeLarge": "MuiButton-outlinedSizeLarge", + "outlinedSizeSmall": "MuiButton-outlinedSizeSmall", + "root": "MuiButton-root btn-profile-next rounded", + "sizeLarge": "MuiButton-sizeLarge", + "sizeSmall": "MuiButton-sizeSmall", + "startIcon": "MuiButton-startIcon", + "text": "MuiButton-text", + "textPrimary": "MuiButton-textPrimary", + "textSecondary": "MuiButton-textSecondary", + "textSizeLarge": "MuiButton-textSizeLarge", + "textSizeSmall": "MuiButton-textSizeSmall", + } + } + onClick={[MockFunction]} + > + <WithStyles(ForwardRef(ButtonBase)) + aria-label="ecogesture.initModal.btn2" + className="MuiButton-root btn-profile-next rounded MuiButton-text" + component="button" + disabled={false} + focusRipple={true} + focusVisibleClassName="Mui-focusVisible" + onClick={[MockFunction]} + type="button" + > + <ForwardRef(ButtonBase) + aria-label="ecogesture.initModal.btn2" + className="MuiButton-root btn-profile-next rounded MuiButton-text" + classes={ + Object { + "disabled": "Mui-disabled", + "focusVisible": "Mui-focusVisible", + "root": "MuiButtonBase-root", + } + } + component="button" + disabled={false} + focusRipple={true} + focusVisibleClassName="Mui-focusVisible" + onClick={[MockFunction]} + type="button" + > + <button + aria-label="ecogesture.initModal.btn2" + className="MuiButtonBase-root MuiButton-root btn-profile-next rounded MuiButton-text" + disabled={false} + onBlur={[Function]} + onClick={[MockFunction]} + onDragLeave={[Function]} + onFocus={[Function]} + onKeyDown={[Function]} + onKeyUp={[Function]} + onMouseDown={[Function]} + onMouseLeave={[Function]} + onMouseUp={[Function]} + onTouchEnd={[Function]} + onTouchMove={[Function]} + onTouchStart={[Function]} + tabIndex={0} + type="button" + > + <span + className="MuiButton-label text-16-bold" + > + ecogesture.initModal.btn2 + </span> + <WithStyles(memo) + center={false} + > + <ForwardRef(TouchRipple) + center={false} + classes={ + Object { + "child": "MuiTouchRipple-child", + "childLeaving": "MuiTouchRipple-childLeaving", + "childPulsate": "MuiTouchRipple-childPulsate", + "ripple": "MuiTouchRipple-ripple", + "ripplePulsate": "MuiTouchRipple-ripplePulsate", + "rippleVisible": "MuiTouchRipple-rippleVisible", + "root": "MuiTouchRipple-root", + } + } + > + <span + className="MuiTouchRipple-root" + > + <TransitionGroup + childFactory={[Function]} + component={null} + exit={true} + /> + </span> + </ForwardRef(TouchRipple)> + </WithStyles(memo)> + </button> + </ForwardRef(ButtonBase)> + </WithStyles(ForwardRef(ButtonBase))> + </ForwardRef(Button)> + </WithStyles(ForwardRef(Button))> + </div> + </div> + </div> + </ForwardRef(Paper)> + </WithStyles(ForwardRef(Paper))> + </div> + </Transition> + </ForwardRef(Fade)> + <div + data-test="sentinelEnd" + tabIndex={0} + /> + </Unstable_TrapFocus> + </div> + </Portal> + </ForwardRef(Portal)> + </ForwardRef(Modal)> + </ForwardRef(Dialog)> + </WithStyles(ForwardRef(Dialog))> +</EcogestureInitModal> +`; diff --git a/src/components/Ecogesture/ecogestureInitModal.scss b/src/components/Ecogesture/EcogestureInitModal/ecogestureInitModal.scss similarity index 62% rename from src/components/Ecogesture/ecogestureInitModal.scss rename to src/components/Ecogesture/EcogestureInitModal/ecogestureInitModal.scss index 3088fd8fd08b7122aed896d9cdf995fa8697b16e..b074b8d940c397c12d03cb3e3dc1e9f08c77fa32 100644 --- a/src/components/Ecogesture/ecogestureInitModal.scss +++ b/src/components/Ecogesture/EcogestureInitModal/ecogestureInitModal.scss @@ -1,4 +1,4 @@ -@import '../../styles/base/color'; +@import 'src/styles/base/color'; .eg-init-modal { color: $grey-bright; @@ -12,12 +12,9 @@ } .buttons-container { display: flex; + gap: 1rem; button { - min-height: 45px; - cursor: pointer; - } - button.btn1 { - margin-right: 1rem; + margin: 0; } } } diff --git a/src/components/Ecogesture/EcogestureList.tsx b/src/components/Ecogesture/EcogestureList.tsx deleted file mode 100644 index 1d54a0d67b74f6f750fcad9c8cdcb81af3d38dcf..0000000000000000000000000000000000000000 --- a/src/components/Ecogesture/EcogestureList.tsx +++ /dev/null @@ -1,211 +0,0 @@ -import { ListItemIcon, Menu, MenuItem } from '@material-ui/core/' -import Button from '@material-ui/core/Button' -import CheckIcon from 'assets/icons/ico/check.svg' -import SortIcon from 'assets/icons/ico/sort.svg' -import StyledIcon from 'components/CommonKit/Icon/StyledIcon' -import EcogestureCard from 'components/Ecogesture/EcogestureCard' -import { useI18n } from 'cozy-ui/transpiled/react/I18n' -import { Usage } from 'enum/ecogesture.enum' -import { Ecogesture } from 'models' -import React, { useState } from 'react' -import { useNavigate } from 'react-router-dom' -import './ecogestureList.scss' - -interface EcogestureListProps { - list: Ecogesture[] - displaySelection: boolean - selectionTotal: number - selectionViewed: number - handleReinitClick?: () => void -} - -const EcogestureList = ({ - list, - displaySelection, - selectionTotal, - selectionViewed, - handleReinitClick, -}: EcogestureListProps) => { - const { t } = useI18n() - const navigate = useNavigate() - const [activeFilter, setActiveFilter] = useState<string>(Usage[Usage.ALL]) - const [openDropDown, setOpenDropDown] = useState<boolean>(false) - const [anchorEl, setAnchorEl] = useState<null | HTMLElement>(null) - - const toggleDropDown = () => { - setOpenDropDown(prev => !prev) - } - - const toggleMenu = (event: React.MouseEvent<HTMLButtonElement>) => { - setAnchorEl(event.currentTarget) - } - - const closeMenu = (usage?: string) => { - usage && setActiveFilter(usage) - setAnchorEl(null) - } - - const filterEcogesture = (ecogestures: Ecogesture[]) => { - const filtered = ecogestures - .filter(ecogesture => Usage[ecogesture.usage] === activeFilter) - .map(ecogesture => ( - <EcogestureCard - key={ecogesture.id} - ecogesture={ecogesture} - selectionCompleted={selectionViewed === selectionTotal} - /> - )) - if (filtered.length > 0) { - return filtered - } else { - return ( - <div className="ec-filter-error"> - <div className="text-20-normal"> - {t('ecogesture.no_ecogesture_filter.text1')} - </div> - <div className="text-16-italic"> - {t('ecogesture.no_ecogesture_filter.text2')} - </div> - </div> - ) - } - } - - const renderEcogestureContent = () => { - if (list.length > 0) { - if (activeFilter === Usage[Usage.ALL]) { - return list.map(ecogesture => ( - <EcogestureCard - key={ecogesture.id} - ecogesture={ecogesture} - selectionCompleted={selectionViewed === selectionTotal} - /> - )) - } else { - return filterEcogesture(list) - } - } else if (!displaySelection) { - return ( - <div className="ec-filter-error"> - <div className="text-20-normal"> - {t('ecogesture.no_ecogesture_filter.text1')} - </div> - <div className="text-16-italic"> - {t('ecogesture.no_ecogesture_filter.text2')} - </div> - </div> - ) - } - } - - return ( - <div className="ecogesture-root"> - <div className="efficiency-button-content"> - {displaySelection ? ( - <div className="selection text-16-normal"> - <span>{t('ecogesture.selection')}</span> - <span> - {`(${selectionViewed} ${t( - 'ecogesture.selection_2' - )} ${selectionTotal})`} - </span> - <Button - aria-label={t('ecogesture.accessibility.button_selection')} - classes={{ - root: 'btn-highlight', - label: 'text-16-bold', - }} - onClick={() => navigate('/ecogesture-selection')} - > - {t('ecogesture.button_selection')} - </Button> - </div> - ) : ( - <div className="filters text-16-normal"> - <div - className="filter-button" - onClick={() => toggleDropDown()} - tabIndex={0} - onBlur={e => { - if (e.relatedTarget === null) toggleDropDown() - }} - > - <Button - classes={{ - root: 'btn-secondary-negative', - label: 'text-14-normal', - }} - aria-controls="simple-menu" - aria-haspopup="true" - aria-label={t(`ecogesture.MENU_TITLE`)} - onClick={toggleMenu} - variant="contained" - > - <StyledIcon icon={SortIcon} size={20} /> - <span - className={ - openDropDown ? 'ecogestures opened' : 'ecogestures' - } - > - {activeFilter === 'ALL' - ? t(`ecogesture.MENU_TITLE`) - : t(`ecogesture.${activeFilter}`)} - </span> - </Button> - <Menu - anchorEl={anchorEl} - keepMounted - open={Boolean(anchorEl)} - onClose={() => closeMenu()} - PopoverClasses={{ - paper: 'filter-menu', - }} - variant="menu" - MenuListProps={{ className: 'filter-menu-list' }} - > - {Object.values(Usage).map( - (usage, key) => - typeof usage !== 'number' && ( - <MenuItem - classes={{ - root: `${ - usage === activeFilter ? 'item-active' : '' - }`, - }} - key={key} - selected={usage === activeFilter} - onClick={() => closeMenu(usage)} - > - {t(`ecogesture.${usage}`)} - {usage === activeFilter && ( - <ListItemIcon classes={{ root: 'filter-menu-icon' }}> - <StyledIcon icon={CheckIcon} size={13} /> - </ListItemIcon> - )} - </MenuItem> - ) - )} - </Menu> - </div> - </div> - )} - </div> - <div className="ecogesture-content"> - {renderEcogestureContent()} - {!displaySelection && handleReinitClick && ( - <Button - onClick={handleReinitClick} - classes={{ - root: 'btn-secondary-negative', - label: 'text-16-normal', - }} - > - {t('ecogesture.reinit')} - </Button> - )} - </div> - </div> - ) -} - -export default EcogestureList diff --git a/src/components/Ecogesture/EcogestureList.spec.tsx b/src/components/Ecogesture/EcogestureList/EcogestureList.spec.tsx similarity index 62% rename from src/components/Ecogesture/EcogestureList.spec.tsx rename to src/components/Ecogesture/EcogestureList/EcogestureList.spec.tsx index 68b746407c4278427102d5e704fffea726c7ad9a..10780f017df3e596dc1cbbf8c8d4ed4c73fb1f2d 100644 --- a/src/components/Ecogesture/EcogestureList.spec.tsx +++ b/src/components/Ecogesture/EcogestureList/EcogestureList.spec.tsx @@ -1,38 +1,32 @@ import { Button, MenuItem } from '@material-ui/core' -import EcogestureList from 'components/Ecogesture/EcogestureList' import { mount } from 'enzyme' import toJson from 'enzyme-to-json' import React from 'react' import { Provider } from 'react-redux' import { BrowserRouter } from 'react-router-dom' -import configureStore from 'redux-mock-store' -import { challengeStateData } from '../../../tests/__mocks__/challengeStateData.mock' -import { mockedEcogesturesData } from '../../../tests/__mocks__/ecogesturesData.mock' -import { globalStateData } from '../../../tests/__mocks__/globalStateData.mock' -import { waitForComponentToPaint } from '../../../tests/__mocks__/testUtils' +import * as storeHooks from 'store/hooks' +import { mockedEcogesturesData } from 'tests/__mocks__/ecogesturesData.mock' +import { createMockEcolyoStore } from 'tests/__mocks__/store' +import { waitForComponentToPaint } from 'tests/__mocks__/testUtils' +import EcogestureList from './EcogestureList' -jest.mock('cozy-ui/transpiled/react/I18n', () => { - return { - useI18n: jest.fn(() => { - return { - t: (str: string) => str, - } - }), - } -}) -jest.mock('components/Ecogesture/EcogestureCard', () => 'mock-ecogesturecard') +jest.mock( + 'components/Ecogesture/EcogestureCard/EcogestureCard', + () => 'mock-ecogesturecard' +) -const mockStore = configureStore([]) const mockHandleReinit = jest.fn() +const updateEcogestureFilter = jest.fn() +const mockAppDispatch = jest.spyOn(storeHooks, 'useAppDispatch') +mockAppDispatch.mockImplementation(() => updateEcogestureFilter) + +const store = createMockEcolyoStore() describe('EcogesturesList component', () => { + beforeAll(() => { + mockAppDispatch.mockClear() + }) it('should be rendered correctly', async () => { - const store = mockStore({ - ecolyo: { - global: globalStateData, - challenge: challengeStateData, - }, - }) const wrapper = mount( <Provider store={store}> <BrowserRouter> @@ -51,12 +45,6 @@ describe('EcogesturesList component', () => { }) it('should open the filter menu and select all ecogesture', async () => { - const store = mockStore({ - ecolyo: { - global: globalStateData, - challenge: challengeStateData, - }, - }) const wrapper = mount( <Provider store={store}> <BrowserRouter> @@ -74,16 +62,10 @@ describe('EcogesturesList component', () => { wrapper.find(Button).first().simulate('click') expect(wrapper.find('.filter-menu').exists()).toBeTruthy() wrapper.find(MenuItem).at(1).simulate('click') - expect(wrapper.find('.ecogestures').text()).toBe('ecogesture.HEATING') + expect(updateEcogestureFilter).toHaveBeenCalledTimes(1) }) it('should display the selection section', async () => { - const store = mockStore({ - ecolyo: { - global: globalStateData, - challenge: challengeStateData, - }, - }) const wrapper = mount( <Provider store={store}> <BrowserRouter> diff --git a/src/components/Ecogesture/EcogestureList/EcogestureList.tsx b/src/components/Ecogesture/EcogestureList/EcogestureList.tsx new file mode 100644 index 0000000000000000000000000000000000000000..37818161e5d62941bf12fd2ca89c3d0c3100bdb9 --- /dev/null +++ b/src/components/Ecogesture/EcogestureList/EcogestureList.tsx @@ -0,0 +1,189 @@ +import { Grow, ListItemIcon, Menu, MenuItem } from '@material-ui/core/' +import Button from '@material-ui/core/Button' +import CheckIcon from 'assets/icons/ico/check.svg' +import SortIcon from 'assets/icons/ico/sort.svg' +import StyledIcon from 'components/CommonKit/Icon/StyledIcon' +import EcogestureCard from 'components/Ecogesture/EcogestureCard/EcogestureCard' +import { useI18n } from 'cozy-ui/transpiled/react/I18n' +import { Usage } from 'enums' +import { Ecogesture } from 'models' +import React, { useState } from 'react' +import { useNavigate } from 'react-router-dom' +import { updateEcogestureFilter } from 'store/global/global.slice' +import { useAppDispatch, useAppSelector } from 'store/hooks' +import './ecogestureList.scss' + +interface EcogestureListProps { + list: Ecogesture[] + displaySelection: boolean + selectionTotal: number + selectionViewed: number + handleReinitClick?: () => void +} + +const EcogestureList = ({ + list, + displaySelection, + selectionTotal, + selectionViewed, + handleReinitClick, +}: EcogestureListProps) => { + const { t } = useI18n() + const navigate = useNavigate() + const dispatch = useAppDispatch() + const { ecogestureFilter } = useAppSelector(state => state.ecolyo.global) + const [openDropDown, setOpenDropDown] = useState<boolean>(false) + const [anchorEl, setAnchorEl] = useState<null | HTMLElement>(null) + + const toggleDropDown = () => { + setOpenDropDown(prev => !prev) + } + + const toggleMenu = (event: React.MouseEvent<HTMLButtonElement>) => { + setAnchorEl(event.currentTarget) + } + + const closeMenu = (usage?: Usage) => { + usage !== undefined && dispatch(updateEcogestureFilter(usage)) + setAnchorEl(null) + } + + const renderEcogestureContent = () => { + const isAllUsage = ecogestureFilter === Usage.ALL + const filteredEcogestures = list.filter(ecogesture => + isAllUsage ? true : ecogesture.usage === ecogestureFilter + ) + + if (filteredEcogestures.length > 0) { + return filteredEcogestures.map(ecogesture => ( + <EcogestureCard key={ecogesture.id} ecogesture={ecogesture} /> + )) + } + + return ( + <div className="ec-filter-error"> + <div className="text-20-normal"> + {t('ecogesture.no_ecogesture_filter.text1')} + </div> + <div className="text-16-italic"> + {t('ecogesture.no_ecogesture_filter.text2')} + </div> + </div> + ) + } + + const selectFilters = () => ( + <div className="filters text-16-normal"> + <div + className="filter-button" + onClick={() => toggleDropDown()} + tabIndex={0} + onBlur={e => { + if (e.relatedTarget === null) toggleDropDown() + }} + > + <Button + classes={{ + root: 'btn-secondary-negative', + label: 'text-14-normal', + }} + aria-controls="simple-menu" + aria-haspopup="true" + aria-label={t(`ecogesture.MENU_TITLE`)} + onClick={toggleMenu} + variant="contained" + > + <StyledIcon icon={SortIcon} size={20} /> + <span className={openDropDown ? 'ecogestures opened' : 'ecogestures'}> + {ecogestureFilter === Usage.ALL + ? t(`ecogesture.MENU_TITLE`) + : t(`ecogesture.${Usage[ecogestureFilter]}`)} + </span> + </Button> + <Menu + anchorEl={anchorEl} + keepMounted + open={Boolean(anchorEl)} + onClose={() => closeMenu()} + PopoverClasses={{ + paper: 'filter-menu', + }} + variant="menu" + MenuListProps={{ className: 'filter-menu-list' }} + > + {Object.values(Usage).map((usage, key) => { + const active = usage === ecogestureFilter + return ( + typeof usage === 'number' && ( + <MenuItem + classes={{ + root: `${active ? 'item-active' : ''}`, + }} + key={key} + selected={active} + onClick={() => closeMenu(usage)} + > + {t(`ecogesture.${Usage[usage]}`)} + {active && ( + <ListItemIcon classes={{ root: 'filter-menu-icon' }}> + <StyledIcon icon={CheckIcon} size={13} /> + </ListItemIcon> + )} + </MenuItem> + ) + ) + })} + </Menu> + </div> + </div> + ) + + const continueSelection = () => ( + <Grow in={displaySelection}> + <div className="selection text-16-normal"> + <span>{t('ecogesture.selection')}</span> + <span> + {`(${selectionViewed} ${t( + 'ecogesture.selection_2' + )} ${selectionTotal})`} + </span> + <Button + aria-label={t('ecogesture.accessibility.button_selection')} + classes={{ + root: 'btn-highlight', + label: 'text-16-bold', + }} + onClick={() => navigate('/ecogesture-selection')} + > + {t('ecogesture.button_selection')} + </Button> + </div> + </Grow> + ) + + return ( + <div className="ecogesture-root"> + <div className="efficiency-button-content"> + {selectFilters()} + {displaySelection && continueSelection()} + </div> + + <div className="ecogesture-content"> + {renderEcogestureContent()} + {!displaySelection && handleReinitClick && ( + <Button + onClick={handleReinitClick} + classes={{ + root: 'btn-secondary-negative', + label: 'text-16-normal', + }} + > + {t('ecogesture.reinit')} + </Button> + )} + </div> + </div> + ) +} + +export default EcogestureList diff --git a/src/components/Ecogesture/__snapshots__/EcogestureList.spec.tsx.snap b/src/components/Ecogesture/EcogestureList/__snapshots__/EcogestureList.spec.tsx.snap similarity index 99% rename from src/components/Ecogesture/__snapshots__/EcogestureList.spec.tsx.snap rename to src/components/Ecogesture/EcogestureList/__snapshots__/EcogestureList.spec.tsx.snap index a534041ec392820102f3f47f100e0e5bb46e0671..e26cfd313fe94e7a2017bbdbcb37eccef2133469 100644 --- a/src/components/Ecogesture/__snapshots__/EcogestureList.spec.tsx.snap +++ b/src/components/Ecogesture/EcogestureList/__snapshots__/EcogestureList.spec.tsx.snap @@ -775,7 +775,7 @@ exports[`EcogesturesList component should be rendered correctly 1`] = ` "root": "item-active", } } - key=".$.$0" + key=".$.$7" onClick={[Function]} selected={true} > @@ -969,7 +969,7 @@ exports[`EcogesturesList component should be rendered correctly 1`] = ` "root": "", } } - key=".$.$1" + key=".$.$8" onClick={[Function]} selected={false} > @@ -1110,7 +1110,7 @@ exports[`EcogesturesList component should be rendered correctly 1`] = ` "root": "", } } - key=".$.$2" + key=".$.$9" onClick={[Function]} selected={false} > @@ -1251,7 +1251,7 @@ exports[`EcogesturesList component should be rendered correctly 1`] = ` "root": "", } } - key=".$.$3" + key=".$.$10" onClick={[Function]} selected={false} > @@ -1392,7 +1392,7 @@ exports[`EcogesturesList component should be rendered correctly 1`] = ` "root": "", } } - key=".$.$4" + key=".$.$11" onClick={[Function]} selected={false} > @@ -1533,7 +1533,7 @@ exports[`EcogesturesList component should be rendered correctly 1`] = ` "root": "", } } - key=".$.$5" + key=".$.$12" onClick={[Function]} selected={false} > @@ -1674,7 +1674,7 @@ exports[`EcogesturesList component should be rendered correctly 1`] = ` "root": "", } } - key=".$.$6" + key=".$.$13" onClick={[Function]} selected={false} > @@ -1872,7 +1872,6 @@ exports[`EcogesturesList component should be rendered correctly 1`] = ` } } key="ECOGESTURE001" - selectionCompleted={true} /> <mock-ecogesturecard ecogesture={ @@ -1910,7 +1909,6 @@ exports[`EcogesturesList component should be rendered correctly 1`] = ` } } key="ECOGESTURE002" - selectionCompleted={true} /> <mock-ecogesturecard ecogesture={ @@ -1951,7 +1949,6 @@ exports[`EcogesturesList component should be rendered correctly 1`] = ` } } key="ECOGESTURE0013" - selectionCompleted={true} /> <WithStyles(ForwardRef(Button)) classes={ diff --git a/src/components/Ecogesture/ecogestureList.scss b/src/components/Ecogesture/EcogestureList/ecogestureList.scss similarity index 98% rename from src/components/Ecogesture/ecogestureList.scss rename to src/components/Ecogesture/EcogestureList/ecogestureList.scss index 6f3b3edcc046fb1067f6c41a6a116300e4eaf427..b2785b9d4711053f4e4ea958f56a931b54769add 100644 --- a/src/components/Ecogesture/ecogestureList.scss +++ b/src/components/Ecogesture/EcogestureList/ecogestureList.scss @@ -13,13 +13,15 @@ .efficiency-button-content { max-width: 52rem; width: 100%; + display: flex; + flex-direction: column; + gap: 1rem; .selection { display: flex; align-items: center; flex-direction: column; color: white; text-align: center; - margin: 1rem auto; button.btn-highlight { padding: 0.625rem; } diff --git a/src/components/Ecogesture/EcogestureModal.spec.tsx b/src/components/Ecogesture/EcogestureModal.spec.tsx deleted file mode 100644 index d54252aaeda2ac388973358e010a749b9777e3d6..0000000000000000000000000000000000000000 --- a/src/components/Ecogesture/EcogestureModal.spec.tsx +++ /dev/null @@ -1,55 +0,0 @@ -import EcogestureModal from 'components/Ecogesture/EcogestureModal' -import { mount } from 'enzyme' -import React from 'react' -import { Provider } from 'react-redux' -import configureStore from 'redux-mock-store' -import { challengeStateData } from '../../../tests/__mocks__/challengeStateData.mock' -import { mockedEcogesturesData } from '../../../tests/__mocks__/ecogesturesData.mock' -import { globalStateData } from '../../../tests/__mocks__/globalStateData.mock' -import { waitForComponentToPaint } from '../../../tests/__mocks__/testUtils' - -jest.mock('cozy-ui/transpiled/react/I18n', () => { - return { - useI18n: jest.fn(() => { - return { - t: (str: string) => str, - } - }), - } -}) -const mockImportIconById = jest.fn() -jest.mock('utils/utils', () => { - return { - importIconById: jest.fn(() => { - return mockImportIconById - }), - } -}) - -const mockStore = configureStore([]) - -describe('EcogestureModal component', () => { - it('should be rendered correctly', async () => { - const store = mockStore({ - ecolyo: { - global: globalStateData, - challenge: challengeStateData, - }, - }) - - const wrapper = mount( - <Provider store={store}> - <EcogestureModal - open={true} - ecogesture={mockedEcogesturesData[0]} - isAction={false} - handleCloseClick={jest.fn()} - /> - </Provider> - ) - await waitForComponentToPaint(wrapper) - expect(wrapper.find('.em-title').text()).toEqual( - mockedEcogesturesData[0].shortName - ) - }) -}) diff --git a/src/components/Ecogesture/EcogestureModal/EcogestureModal.spec.tsx b/src/components/Ecogesture/EcogestureModal/EcogestureModal.spec.tsx new file mode 100644 index 0000000000000000000000000000000000000000..8cfd17faf6db498327f1a08d2520afb395bdd7c4 --- /dev/null +++ b/src/components/Ecogesture/EcogestureModal/EcogestureModal.spec.tsx @@ -0,0 +1,27 @@ +import EcogestureModal from 'components/Ecogesture/EcogestureModal/EcogestureModal' +import { mount } from 'enzyme' +import React from 'react' +import { Provider } from 'react-redux' +import { mockedEcogesturesData } from 'tests/__mocks__/ecogesturesData.mock' +import { createMockEcolyoStore } from 'tests/__mocks__/store' +import { waitForComponentToPaint } from 'tests/__mocks__/testUtils' + +describe('EcogestureModal component', () => { + it('should be rendered correctly', async () => { + const store = createMockEcolyoStore() + const wrapper = mount( + <Provider store={store}> + <EcogestureModal + open={true} + ecogesture={mockedEcogesturesData[0]} + isAction={false} + handleCloseClick={jest.fn()} + /> + </Provider> + ) + await waitForComponentToPaint(wrapper) + expect(wrapper.find('.em-title').text()).toEqual( + mockedEcogesturesData[0].shortName + ) + }) +}) diff --git a/src/components/Ecogesture/EcogestureModal.tsx b/src/components/Ecogesture/EcogestureModal/EcogestureModal.tsx similarity index 80% rename from src/components/Ecogesture/EcogestureModal.tsx rename to src/components/Ecogesture/EcogestureModal/EcogestureModal.tsx index 64f363d9a26ab7bbc6e36a2c2b63aab8b431dfd0..7fa5418c050ce00a88afbfae0cb31fa04b18b9ba 100644 --- a/src/components/Ecogesture/EcogestureModal.tsx +++ b/src/components/Ecogesture/EcogestureModal/EcogestureModal.tsx @@ -1,20 +1,19 @@ +import { Collapse } from '@material-ui/core' import Button from '@material-ui/core/Button' import Dialog from '@material-ui/core/Dialog' import IconButton from '@material-ui/core/IconButton' import CloseIcon from 'assets/icons/ico/close.svg' import defaultIcon from 'assets/icons/visu/ecogesture/default.svg' -import classNames from 'classnames' import StyledIcon from 'components/CommonKit/Icon/StyledIcon' import useExploration from 'components/Hooks/useExploration' import { useI18n } from 'cozy-ui/transpiled/react/I18n' import Icon from 'cozy-ui/transpiled/react/Icon' import { Ecogesture } from 'models' import React, { useEffect, useState } from 'react' -import { useSelector } from 'react-redux' -import { AppStore } from 'store' +import { useAppSelector } from 'store/hooks' import { getPicto } from 'utils/picto' import { importIconById } from 'utils/utils' -import EfficiencyRating from './EfficiencyRating' +import EfficiencyRating from '../EfficiencyRating/EfficiencyRating' import './ecogestureModal.scss' interface EcogestureModalProps { @@ -33,24 +32,16 @@ const EcogestureModal = ({ selectEcogesture, }: EcogestureModalProps) => { const { t } = useI18n() + const { currentChallenge } = useAppSelector(state => state.ecolyo.challenge) const [ecogestureIcon, setEcogestureIcon] = useState('') - const [isMoreDetail, setIsMoreDetail] = useState(false) - const { currentChallenge } = useSelector( - (state: AppStore) => state.ecolyo.challenge - ) + const [showDetails, setShowDetails] = useState(false) const [, setValidExploration] = useExploration() - const toggleMoreDetail = () => { - setIsMoreDetail(prev => !prev) - } + useEffect(() => { async function handleEcogestureIcon() { const icon = await importIconById(ecogesture.id, 'ecogesture') - if (icon) { - setEcogestureIcon(icon) - } else { - setEcogestureIcon(defaultIcon) - } + setEcogestureIcon(icon || defaultIcon) if (currentChallenge?.exploration.ecogesture_id === ecogesture._id) { setValidExploration(currentChallenge.exploration.id) } @@ -64,13 +55,13 @@ const EcogestureModal = ({ <Dialog open={open} onClose={handleCloseClick} - aria-labelledby={'accessibility-title'} + aria-labelledby="accessibility-title" classes={{ root: 'modal-root', paper: 'modal-paper no-padding blue-border', }} > - <div id={'accessibility-title'}> + <div id="accessibility-title"> {isAction ? t('ecogesture_modal.accessibility.window_title_action') : t('ecogesture_modal.accessibility.window_title_ecogesture')} @@ -131,26 +122,22 @@ const EcogestureModal = ({ </Button> ) : ( <> - <div - className={classNames('em-description text-16-normal-150', { - ['block']: isMoreDetail === true, - })} - > - {ecogesture.longDescription} - </div> + <Collapse in={showDetails}> + <div className="em-description text-16-normal-150"> + {ecogesture.longDescription} + </div> + </Collapse> <Button aria-label={t( 'ecogesture_modal.accessibility.button_see_more_detail' )} - onClick={toggleMoreDetail} + onClick={() => setShowDetails(prev => !prev)} classes={{ root: 'btn-secondary-negative', label: 'text-14-normal', }} > - {isMoreDetail - ? t('ecogesture_modal.show_less') - : t('ecogesture_modal.show_more')} + {t(`ecogesture_modal.show_${showDetails ? 'less' : 'more'}`)} </Button> </> )} diff --git a/src/components/Ecogesture/ecogestureModal.scss b/src/components/Ecogesture/EcogestureModal/ecogestureModal.scss similarity index 96% rename from src/components/Ecogesture/ecogestureModal.scss rename to src/components/Ecogesture/EcogestureModal/ecogestureModal.scss index 1e95283c966cc380368f103f3c025e8d47c8c98e..1be2ce155464e3999491cf261bb78433fd904596 100644 --- a/src/components/Ecogesture/ecogestureModal.scss +++ b/src/components/Ecogesture/EcogestureModal/ecogestureModal.scss @@ -84,11 +84,7 @@ text-align: center; margin: 1.5rem 0 1rem; } - .em-description { - display: none; - margin: 0.5rem; - text-align: left; - } + button.btn-action-launch { background: $blue-radial-gradient; border: none; diff --git a/src/components/Ecogesture/EcogestureNotFound/EcogestureNotFound.spec.tsx b/src/components/Ecogesture/EcogestureNotFound/EcogestureNotFound.spec.tsx new file mode 100644 index 0000000000000000000000000000000000000000..9be727a778cd04ebaf2e275cca80ad241fe8f4b4 --- /dev/null +++ b/src/components/Ecogesture/EcogestureNotFound/EcogestureNotFound.spec.tsx @@ -0,0 +1,33 @@ +/* eslint-disable react/display-name */ +import { Button } from '@material-ui/core' +import { mount } from 'enzyme' +import toJson from 'enzyme-to-json' +import React from 'react' +import EcogestureNotFound from './EcogestureNotFound' + +const mockedNavigate = jest.fn() +jest.mock('react-router-dom', () => ({ + ...jest.requireActual('react-router-dom'), + useNavigate: () => mockedNavigate, +})) + +jest.mock('components/Header/Header', () => 'mock-header') +jest.mock('components/Header/CozyBar', () => 'mock-cozybar') +jest.mock('components/Content/Content', () => 'mock-content') + +describe('EcogestureNotFound component', () => { + it('should be rendered correctly', async () => { + const wrapper = mount( + <EcogestureNotFound text="test" returnPage="ecogestures" /> + ) + + expect(toJson(wrapper)).toMatchSnapshot() + }) + it('should click on button and be redirected', () => { + const wrapper = mount( + <EcogestureNotFound text="test" returnPage="ecogestures" /> + ) + wrapper.find(Button).simulate('click') + expect(mockedNavigate).toHaveBeenCalledWith('/ecogestures') + }) +}) diff --git a/src/components/CommonKit/ErrorPage/ErrorPage.tsx b/src/components/Ecogesture/EcogestureNotFound/EcogestureNotFound.tsx similarity index 64% rename from src/components/CommonKit/ErrorPage/ErrorPage.tsx rename to src/components/Ecogesture/EcogestureNotFound/EcogestureNotFound.tsx index 69136c0867bc9beab069d7499a636c7e74920492..3c1ac059eac4a6918cee3f152da6ee5628a524ec 100644 --- a/src/components/CommonKit/ErrorPage/ErrorPage.tsx +++ b/src/components/Ecogesture/EcogestureNotFound/EcogestureNotFound.tsx @@ -5,42 +5,37 @@ import Content from 'components/Content/Content' import CozyBar from 'components/Header/CozyBar' import Header from 'components/Header/Header' import { useI18n } from 'cozy-ui/transpiled/react/I18n' -import React, { useCallback, useState } from 'react' +import React, { useState } from 'react' import { useNavigate } from 'react-router-dom' -import './errorPage.scss' +import './ecogestureNotFound.scss' -interface ErrorPageProps { +const EcogestureNotFound = ({ + text, + returnPage, +}: { text: string returnPage: string -} - -const ErrorPage = ({ text, returnPage }: ErrorPageProps) => { - const navigate = useNavigate() +}) => { const { t } = useI18n() - + const navigate = useNavigate() const [headerHeight, setHeaderHeight] = useState<number>(0) - const defineHeaderHeight = (height: number) => { - setHeaderHeight(height) - } - const handleClick = useCallback(() => { - navigate(`/${returnPage}`) - }, [navigate, returnPage]) + return ( <> - <CozyBar titleKey={'error_page.main'} /> + <CozyBar titleKey="error_page.main" /> <Header - setHeaderHeight={defineHeaderHeight} - desktopTitleKey={'error_page.main'} + setHeaderHeight={setHeaderHeight} + desktopTitleKey="error_page.main" /> - <Content height={headerHeight}> + <Content heightOffset={headerHeight}> <div className="error-container"> <StyledIcon className="profile-icon" icon={BearIcon} size={250} /> <div className="text-18-bold head">{text}</div> <Button aria-label={t('error_page.back')} - onClick={handleClick} - variant={'contained'} + onClick={() => navigate(`/${returnPage}`)} + variant="contained" classes={{ root: 'btn-highlight', label: 'text-18-bold', @@ -55,4 +50,4 @@ const ErrorPage = ({ text, returnPage }: ErrorPageProps) => { ) } -export default ErrorPage +export default EcogestureNotFound diff --git a/src/components/Challenge/__snapshots__/ChallengeCardLast.spec.tsx.snap b/src/components/Ecogesture/EcogestureNotFound/__snapshots__/EcogestureNotFound.spec.tsx.snap similarity index 73% rename from src/components/Challenge/__snapshots__/ChallengeCardLast.spec.tsx.snap rename to src/components/Ecogesture/EcogestureNotFound/__snapshots__/EcogestureNotFound.spec.tsx.snap index 5f80b30e60723bb66d88a833aa052deaeb5d18d8..fe29324f57d34c47b991df4cbeb5524913c797b5 100644 --- a/src/components/Challenge/__snapshots__/ChallengeCardLast.spec.tsx.snap +++ b/src/components/Ecogesture/EcogestureNotFound/__snapshots__/EcogestureNotFound.spec.tsx.snap @@ -1,45 +1,48 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[`ChallengeCardLast component should be rendered correctly 1`] = ` -<Provider - store={ - Object { - "clearActions": [Function], - "dispatch": [Function], - "getActions": [Function], - "getState": [Function], - "replaceReducer": [Function], - "subscribe": [Function], - } - } +exports[`EcogestureNotFound component should be rendered correctly 1`] = ` +<EcogestureNotFound + returnPage="ecogestures" + text="test" > - <ChallengeCardLast> + <mock-cozybar + titleKey="error_page.main" + /> + <mock-header + desktopTitleKey="error_page.main" + setHeaderHeight={[Function]} + /> + <mock-content + heightOffset={0} + > <div - className="cardLast" + className="error-container" > <StyledIcon + className="profile-icon" icon="test-file-stub" - size={62} + size={250} > <Icon aria-hidden={true} + className="profile-icon" icon="test-file-stub" - size={62} + size={250} spin={false} > <Component aria-hidden={true} - className="styles__icon___23x3R" - height={62} + className="profile-icon styles__icon___23x3R" + height={250} style={Object {}} - width={62} + width={250} > <svg aria-hidden={true} - className="styles__icon___23x3R" - height={62} + className="profile-icon styles__icon___23x3R" + height={250} style={Object {}} - width={62} + width={250} > <use xlinkHref="#test-file-stub" @@ -49,33 +52,24 @@ exports[`ChallengeCardLast component should be rendered correctly 1`] = ` </Icon> </StyledIcon> <div - className="content" + className="text-18-bold head" > - <div - className="text-22-bold title-last" - > - challenge.card_last.title - </div> - <div - className="text-18-normal message" - > - challenge.card_last.message1 - </div> + test </div> <WithStyles(ForwardRef(Button)) - aria-label="challenge.card_last.button" - className="btn1" + aria-label="error_page.back" classes={ Object { - "label": "text-15-bold", - "root": "btn-secondary-negative btn_lastCard", + "label": "text-18-bold", + "root": "btn-highlight", } } onClick={[Function]} + type="submit" + variant="contained" > <ForwardRef(Button) - aria-label="challenge.card_last.button" - className="btn1" + aria-label="error_page.back" classes={ Object { "colorInherit": "MuiButton-colorInherit", @@ -92,13 +86,13 @@ exports[`ChallengeCardLast component should be rendered correctly 1`] = ` "iconSizeLarge": "MuiButton-iconSizeLarge", "iconSizeMedium": "MuiButton-iconSizeMedium", "iconSizeSmall": "MuiButton-iconSizeSmall", - "label": "MuiButton-label text-15-bold", + "label": "MuiButton-label text-18-bold", "outlined": "MuiButton-outlined", "outlinedPrimary": "MuiButton-outlinedPrimary", "outlinedSecondary": "MuiButton-outlinedSecondary", "outlinedSizeLarge": "MuiButton-outlinedSizeLarge", "outlinedSizeSmall": "MuiButton-outlinedSizeSmall", - "root": "MuiButton-root btn-secondary-negative btn_lastCard", + "root": "MuiButton-root btn-highlight", "sizeLarge": "MuiButton-sizeLarge", "sizeSmall": "MuiButton-sizeSmall", "startIcon": "MuiButton-startIcon", @@ -110,20 +104,22 @@ exports[`ChallengeCardLast component should be rendered correctly 1`] = ` } } onClick={[Function]} + type="submit" + variant="contained" > <WithStyles(ForwardRef(ButtonBase)) - aria-label="challenge.card_last.button" - className="MuiButton-root btn-secondary-negative btn_lastCard MuiButton-text btn1" + aria-label="error_page.back" + className="MuiButton-root btn-highlight MuiButton-contained" component="button" disabled={false} focusRipple={true} focusVisibleClassName="Mui-focusVisible" onClick={[Function]} - type="button" + type="submit" > <ForwardRef(ButtonBase) - aria-label="challenge.card_last.button" - className="MuiButton-root btn-secondary-negative btn_lastCard MuiButton-text btn1" + aria-label="error_page.back" + className="MuiButton-root btn-highlight MuiButton-contained" classes={ Object { "disabled": "Mui-disabled", @@ -136,11 +132,11 @@ exports[`ChallengeCardLast component should be rendered correctly 1`] = ` focusRipple={true} focusVisibleClassName="Mui-focusVisible" onClick={[Function]} - type="button" + type="submit" > <button - aria-label="challenge.card_last.button" - className="MuiButtonBase-root MuiButton-root btn-secondary-negative btn_lastCard MuiButton-text btn1" + aria-label="error_page.back" + className="MuiButtonBase-root MuiButton-root btn-highlight MuiButton-contained" disabled={false} onBlur={[Function]} onClick={[Function]} @@ -155,12 +151,12 @@ exports[`ChallengeCardLast component should be rendered correctly 1`] = ` onTouchMove={[Function]} onTouchStart={[Function]} tabIndex={0} - type="button" + type="submit" > <span - className="MuiButton-label text-15-bold" + className="MuiButton-label text-18-bold" > - challenge.card_last.button + error_page.back </span> <WithStyles(memo) center={false} @@ -196,6 +192,6 @@ exports[`ChallengeCardLast component should be rendered correctly 1`] = ` </ForwardRef(Button)> </WithStyles(ForwardRef(Button))> </div> - </ChallengeCardLast> -</Provider> + </mock-content> +</EcogestureNotFound> `; diff --git a/src/components/CommonKit/ErrorPage/errorPage.scss b/src/components/Ecogesture/EcogestureNotFound/ecogestureNotFound.scss similarity index 100% rename from src/components/CommonKit/ErrorPage/errorPage.scss rename to src/components/Ecogesture/EcogestureNotFound/ecogestureNotFound.scss diff --git a/src/components/Ecogesture/EcogestureReinitModal.spec.tsx b/src/components/Ecogesture/EcogestureReinitModal.spec.tsx deleted file mode 100644 index 8dce007bf23265432d1a2184f8e7e700de355d02..0000000000000000000000000000000000000000 --- a/src/components/Ecogesture/EcogestureReinitModal.spec.tsx +++ /dev/null @@ -1,50 +0,0 @@ -import { mount } from 'enzyme' -import toJson from 'enzyme-to-json' -import React from 'react' -import { Provider } from 'react-redux' -import configureStore from 'redux-mock-store' -import { challengeStateData } from '../../../tests/__mocks__/challengeStateData.mock' -import { globalStateData } from '../../../tests/__mocks__/globalStateData.mock' -import EcogestureReinitModal from './EcogestureReinitModal' - -jest.mock('cozy-ui/transpiled/react/I18n', () => { - return { - useI18n: jest.fn(() => { - return { - t: (str: string) => str, - } - }), - } -}) -const mockImportIconById = jest.fn() -jest.mock('utils/utils', () => { - return { - importIconById: jest.fn(() => { - return mockImportIconById - }), - } -}) - -const mockStore = configureStore([]) - -describe('EcogestureReinitModal component', () => { - it('should be rendered correctly', async () => { - const store = mockStore({ - ecolyo: { - global: globalStateData, - challenge: challengeStateData, - }, - }) - - const wrapper = mount( - <Provider store={store}> - <EcogestureReinitModal - open={true} - handleCloseClick={jest.fn()} - handleLaunchReinit={jest.fn()} - /> - </Provider> - ) - expect(toJson(wrapper)).toMatchSnapshot() - }) -}) diff --git a/src/components/Ecogesture/EcogestureReinitModal/EcogestureReinitModal.spec.tsx b/src/components/Ecogesture/EcogestureReinitModal/EcogestureReinitModal.spec.tsx new file mode 100644 index 0000000000000000000000000000000000000000..5f9148b0379bd6bb81982b521e23bd2b3e489304 --- /dev/null +++ b/src/components/Ecogesture/EcogestureReinitModal/EcogestureReinitModal.spec.tsx @@ -0,0 +1,17 @@ +import { mount } from 'enzyme' +import toJson from 'enzyme-to-json' +import React from 'react' +import EcogestureReinitModal from './EcogestureReinitModal' + +describe('EcogestureReinitModal component', () => { + it('should be rendered correctly', async () => { + const wrapper = mount( + <EcogestureReinitModal + open={true} + handleCloseClick={jest.fn()} + handleLaunchReinit={jest.fn()} + /> + ) + expect(toJson(wrapper)).toMatchSnapshot() + }) +}) diff --git a/src/components/Ecogesture/EcogestureReinitModal.tsx b/src/components/Ecogesture/EcogestureReinitModal/EcogestureReinitModal.tsx similarity index 97% rename from src/components/Ecogesture/EcogestureReinitModal.tsx rename to src/components/Ecogesture/EcogestureReinitModal/EcogestureReinitModal.tsx index 25f3ea63ebfc1ea31f7a2600331536c168836e60..c924c3e4d9c1fa90db03b4bd82faaf481593aebf 100644 --- a/src/components/Ecogesture/EcogestureReinitModal.tsx +++ b/src/components/Ecogesture/EcogestureReinitModal/EcogestureReinitModal.tsx @@ -6,11 +6,13 @@ import { useI18n } from 'cozy-ui/transpiled/react/I18n' import Icon from 'cozy-ui/transpiled/react/Icon' import React from 'react' import './ecogestureReinitModal.scss' + interface EcogestureReinitModalProps { open: boolean handleCloseClick: () => void handleLaunchReinit: () => void } + const EcogestureReinitModal = ({ open, handleCloseClick, @@ -21,13 +23,13 @@ const EcogestureReinitModal = ({ <Dialog open={open} onClose={handleCloseClick} - aria-labelledby={'accessibility-title'} + aria-labelledby="accessibility-title" classes={{ root: 'modal-root', paper: 'modal-paper', }} > - <div id={'accessibility-title'}> + <div id="accessibility-title"> {t('feedback.accessibility.window_title')} </div> <IconButton diff --git a/src/components/Ecogesture/EcogestureReinitModal/__snapshots__/EcogestureReinitModal.spec.tsx.snap b/src/components/Ecogesture/EcogestureReinitModal/__snapshots__/EcogestureReinitModal.spec.tsx.snap new file mode 100644 index 0000000000000000000000000000000000000000..12cb41c346cf16d5b767e330745da2065ccb2577 --- /dev/null +++ b/src/components/Ecogesture/EcogestureReinitModal/__snapshots__/EcogestureReinitModal.spec.tsx.snap @@ -0,0 +1,1196 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`EcogestureReinitModal component should be rendered correctly 1`] = ` +<EcogestureReinitModal + handleCloseClick={[MockFunction]} + handleLaunchReinit={[MockFunction]} + open={true} +> + <WithStyles(ForwardRef(Dialog)) + aria-labelledby="accessibility-title" + classes={ + Object { + "paper": "modal-paper", + "root": "modal-root", + } + } + onClose={[MockFunction]} + open={true} + > + <ForwardRef(Dialog) + aria-labelledby="accessibility-title" + classes={ + Object { + "container": "MuiDialog-container", + "paper": "MuiDialog-paper modal-paper", + "paperFullScreen": "MuiDialog-paperFullScreen", + "paperFullWidth": "MuiDialog-paperFullWidth", + "paperScrollBody": "MuiDialog-paperScrollBody", + "paperScrollPaper": "MuiDialog-paperScrollPaper", + "paperWidthFalse": "MuiDialog-paperWidthFalse", + "paperWidthLg": "MuiDialog-paperWidthLg", + "paperWidthMd": "MuiDialog-paperWidthMd", + "paperWidthSm": "MuiDialog-paperWidthSm", + "paperWidthXl": "MuiDialog-paperWidthXl", + "paperWidthXs": "MuiDialog-paperWidthXs", + "root": "MuiDialog-root modal-root", + "scrollBody": "MuiDialog-scrollBody", + "scrollPaper": "MuiDialog-scrollPaper", + } + } + onClose={[MockFunction]} + open={true} + > + <ForwardRef(Modal) + BackdropComponent={ + Object { + "$$typeof": Symbol(react.forward_ref), + "Naked": Object { + "$$typeof": Symbol(react.forward_ref), + "propTypes": Object { + "children": [Function], + "className": [Function], + "classes": [Function], + "invisible": [Function], + "open": [Function], + "transitionDuration": [Function], + }, + "render": [Function], + }, + "displayName": "WithStyles(ForwardRef(Backdrop))", + "options": Object { + "defaultTheme": Object { + "breakpoints": Object { + "between": [Function], + "down": [Function], + "keys": Array [ + "xs", + "sm", + "md", + "lg", + "xl", + ], + "only": [Function], + "up": [Function], + "values": Object { + "lg": 1280, + "md": 960, + "sm": 600, + "xl": 1920, + "xs": 0, + }, + "width": [Function], + }, + "direction": "ltr", + "mixins": Object { + "gutters": [Function], + "toolbar": Object { + "@media (min-width:0px) and (orientation: landscape)": Object { + "minHeight": 48, + }, + "@media (min-width:600px)": Object { + "minHeight": 64, + }, + "minHeight": 56, + }, + }, + "overrides": Object {}, + "palette": Object { + "action": Object { + "activatedOpacity": 0.12, + "active": "rgba(0, 0, 0, 0.54)", + "disabled": "rgba(0, 0, 0, 0.26)", + "disabledBackground": "rgba(0, 0, 0, 0.12)", + "disabledOpacity": 0.38, + "focus": "rgba(0, 0, 0, 0.12)", + "focusOpacity": 0.12, + "hover": "rgba(0, 0, 0, 0.04)", + "hoverOpacity": 0.04, + "selected": "rgba(0, 0, 0, 0.08)", + "selectedOpacity": 0.08, + }, + "augmentColor": [Function], + "background": Object { + "default": "#fafafa", + "paper": "#fff", + }, + "common": Object { + "black": "#000", + "white": "#fff", + }, + "contrastThreshold": 3, + "divider": "rgba(0, 0, 0, 0.12)", + "error": Object { + "contrastText": "#fff", + "dark": "#d32f2f", + "light": "#e57373", + "main": "#f44336", + }, + "getContrastText": [Function], + "grey": Object { + "100": "#f5f5f5", + "200": "#eeeeee", + "300": "#e0e0e0", + "400": "#bdbdbd", + "50": "#fafafa", + "500": "#9e9e9e", + "600": "#757575", + "700": "#616161", + "800": "#424242", + "900": "#212121", + "A100": "#d5d5d5", + "A200": "#aaaaaa", + "A400": "#303030", + "A700": "#616161", + }, + "info": Object { + "contrastText": "#fff", + "dark": "#1976d2", + "light": "#64b5f6", + "main": "#2196f3", + }, + "primary": Object { + "contrastText": "#fff", + "dark": "#303f9f", + "light": "#7986cb", + "main": "#3f51b5", + }, + "secondary": Object { + "contrastText": "#fff", + "dark": "#c51162", + "light": "#ff4081", + "main": "#f50057", + }, + "success": Object { + "contrastText": "rgba(0, 0, 0, 0.87)", + "dark": "#388e3c", + "light": "#81c784", + "main": "#4caf50", + }, + "text": Object { + "disabled": "rgba(0, 0, 0, 0.38)", + "hint": "rgba(0, 0, 0, 0.38)", + "primary": "rgba(0, 0, 0, 0.87)", + "secondary": "rgba(0, 0, 0, 0.54)", + }, + "tonalOffset": 0.2, + "type": "light", + "warning": Object { + "contrastText": "rgba(0, 0, 0, 0.87)", + "dark": "#f57c00", + "light": "#ffb74d", + "main": "#ff9800", + }, + }, + "props": Object {}, + "shadows": Array [ + "none", + "0px 2px 1px -1px rgba(0,0,0,0.2),0px 1px 1px 0px rgba(0,0,0,0.14),0px 1px 3px 0px rgba(0,0,0,0.12)", + "0px 3px 1px -2px rgba(0,0,0,0.2),0px 2px 2px 0px rgba(0,0,0,0.14),0px 1px 5px 0px rgba(0,0,0,0.12)", + "0px 3px 3px -2px rgba(0,0,0,0.2),0px 3px 4px 0px rgba(0,0,0,0.14),0px 1px 8px 0px rgba(0,0,0,0.12)", + "0px 2px 4px -1px rgba(0,0,0,0.2),0px 4px 5px 0px rgba(0,0,0,0.14),0px 1px 10px 0px rgba(0,0,0,0.12)", + "0px 3px 5px -1px rgba(0,0,0,0.2),0px 5px 8px 0px rgba(0,0,0,0.14),0px 1px 14px 0px rgba(0,0,0,0.12)", + "0px 3px 5px -1px rgba(0,0,0,0.2),0px 6px 10px 0px rgba(0,0,0,0.14),0px 1px 18px 0px rgba(0,0,0,0.12)", + "0px 4px 5px -2px rgba(0,0,0,0.2),0px 7px 10px 1px rgba(0,0,0,0.14),0px 2px 16px 1px rgba(0,0,0,0.12)", + "0px 5px 5px -3px rgba(0,0,0,0.2),0px 8px 10px 1px rgba(0,0,0,0.14),0px 3px 14px 2px rgba(0,0,0,0.12)", + "0px 5px 6px -3px rgba(0,0,0,0.2),0px 9px 12px 1px rgba(0,0,0,0.14),0px 3px 16px 2px rgba(0,0,0,0.12)", + "0px 6px 6px -3px rgba(0,0,0,0.2),0px 10px 14px 1px rgba(0,0,0,0.14),0px 4px 18px 3px rgba(0,0,0,0.12)", + "0px 6px 7px -4px rgba(0,0,0,0.2),0px 11px 15px 1px rgba(0,0,0,0.14),0px 4px 20px 3px rgba(0,0,0,0.12)", + "0px 7px 8px -4px rgba(0,0,0,0.2),0px 12px 17px 2px rgba(0,0,0,0.14),0px 5px 22px 4px rgba(0,0,0,0.12)", + "0px 7px 8px -4px rgba(0,0,0,0.2),0px 13px 19px 2px rgba(0,0,0,0.14),0px 5px 24px 4px rgba(0,0,0,0.12)", + "0px 7px 9px -4px rgba(0,0,0,0.2),0px 14px 21px 2px rgba(0,0,0,0.14),0px 5px 26px 4px rgba(0,0,0,0.12)", + "0px 8px 9px -5px rgba(0,0,0,0.2),0px 15px 22px 2px rgba(0,0,0,0.14),0px 6px 28px 5px rgba(0,0,0,0.12)", + "0px 8px 10px -5px rgba(0,0,0,0.2),0px 16px 24px 2px rgba(0,0,0,0.14),0px 6px 30px 5px rgba(0,0,0,0.12)", + "0px 8px 11px -5px rgba(0,0,0,0.2),0px 17px 26px 2px rgba(0,0,0,0.14),0px 6px 32px 5px rgba(0,0,0,0.12)", + "0px 9px 11px -5px rgba(0,0,0,0.2),0px 18px 28px 2px rgba(0,0,0,0.14),0px 7px 34px 6px rgba(0,0,0,0.12)", + "0px 9px 12px -6px rgba(0,0,0,0.2),0px 19px 29px 2px rgba(0,0,0,0.14),0px 7px 36px 6px rgba(0,0,0,0.12)", + "0px 10px 13px -6px rgba(0,0,0,0.2),0px 20px 31px 3px rgba(0,0,0,0.14),0px 8px 38px 7px rgba(0,0,0,0.12)", + "0px 10px 13px -6px rgba(0,0,0,0.2),0px 21px 33px 3px rgba(0,0,0,0.14),0px 8px 40px 7px rgba(0,0,0,0.12)", + "0px 10px 14px -6px rgba(0,0,0,0.2),0px 22px 35px 3px rgba(0,0,0,0.14),0px 8px 42px 7px rgba(0,0,0,0.12)", + "0px 11px 14px -7px rgba(0,0,0,0.2),0px 23px 36px 3px rgba(0,0,0,0.14),0px 9px 44px 8px rgba(0,0,0,0.12)", + "0px 11px 15px -7px rgba(0,0,0,0.2),0px 24px 38px 3px rgba(0,0,0,0.14),0px 9px 46px 8px rgba(0,0,0,0.12)", + ], + "shape": Object { + "borderRadius": 4, + }, + "spacing": [Function], + "transitions": Object { + "create": [Function], + "duration": Object { + "complex": 375, + "enteringScreen": 225, + "leavingScreen": 195, + "short": 250, + "shorter": 200, + "shortest": 150, + "standard": 300, + }, + "easing": Object { + "easeIn": "cubic-bezier(0.4, 0, 1, 1)", + "easeInOut": "cubic-bezier(0.4, 0, 0.2, 1)", + "easeOut": "cubic-bezier(0.0, 0, 0.2, 1)", + "sharp": "cubic-bezier(0.4, 0, 0.6, 1)", + }, + "getAutoHeightDuration": [Function], + }, + "typography": Object { + "body1": Object { + "fontFamily": "\\"Roboto\\", \\"Helvetica\\", \\"Arial\\", sans-serif", + "fontSize": "1rem", + "fontWeight": 400, + "letterSpacing": "0.00938em", + "lineHeight": 1.5, + }, + "body2": Object { + "fontFamily": "\\"Roboto\\", \\"Helvetica\\", \\"Arial\\", sans-serif", + "fontSize": "0.875rem", + "fontWeight": 400, + "letterSpacing": "0.01071em", + "lineHeight": 1.43, + }, + "button": Object { + "fontFamily": "\\"Roboto\\", \\"Helvetica\\", \\"Arial\\", sans-serif", + "fontSize": "0.875rem", + "fontWeight": 500, + "letterSpacing": "0.02857em", + "lineHeight": 1.75, + "textTransform": "uppercase", + }, + "caption": Object { + "fontFamily": "\\"Roboto\\", \\"Helvetica\\", \\"Arial\\", sans-serif", + "fontSize": "0.75rem", + "fontWeight": 400, + "letterSpacing": "0.03333em", + "lineHeight": 1.66, + }, + "fontFamily": "\\"Roboto\\", \\"Helvetica\\", \\"Arial\\", sans-serif", + "fontSize": 14, + "fontWeightBold": 700, + "fontWeightLight": 300, + "fontWeightMedium": 500, + "fontWeightRegular": 400, + "h1": Object { + "fontFamily": "\\"Roboto\\", \\"Helvetica\\", \\"Arial\\", sans-serif", + "fontSize": "6rem", + "fontWeight": 300, + "letterSpacing": "-0.01562em", + "lineHeight": 1.167, + }, + "h2": Object { + "fontFamily": "\\"Roboto\\", \\"Helvetica\\", \\"Arial\\", sans-serif", + "fontSize": "3.75rem", + "fontWeight": 300, + "letterSpacing": "-0.00833em", + "lineHeight": 1.2, + }, + "h3": Object { + "fontFamily": "\\"Roboto\\", \\"Helvetica\\", \\"Arial\\", sans-serif", + "fontSize": "3rem", + "fontWeight": 400, + "letterSpacing": "0em", + "lineHeight": 1.167, + }, + "h4": Object { + "fontFamily": "\\"Roboto\\", \\"Helvetica\\", \\"Arial\\", sans-serif", + "fontSize": "2.125rem", + "fontWeight": 400, + "letterSpacing": "0.00735em", + "lineHeight": 1.235, + }, + "h5": Object { + "fontFamily": "\\"Roboto\\", \\"Helvetica\\", \\"Arial\\", sans-serif", + "fontSize": "1.5rem", + "fontWeight": 400, + "letterSpacing": "0em", + "lineHeight": 1.334, + }, + "h6": Object { + "fontFamily": "\\"Roboto\\", \\"Helvetica\\", \\"Arial\\", sans-serif", + "fontSize": "1.25rem", + "fontWeight": 500, + "letterSpacing": "0.0075em", + "lineHeight": 1.6, + }, + "htmlFontSize": 16, + "overline": Object { + "fontFamily": "\\"Roboto\\", \\"Helvetica\\", \\"Arial\\", sans-serif", + "fontSize": "0.75rem", + "fontWeight": 400, + "letterSpacing": "0.08333em", + "lineHeight": 2.66, + "textTransform": "uppercase", + }, + "pxToRem": [Function], + "round": [Function], + "subtitle1": Object { + "fontFamily": "\\"Roboto\\", \\"Helvetica\\", \\"Arial\\", sans-serif", + "fontSize": "1rem", + "fontWeight": 400, + "letterSpacing": "0.00938em", + "lineHeight": 1.75, + }, + "subtitle2": Object { + "fontFamily": "\\"Roboto\\", \\"Helvetica\\", \\"Arial\\", sans-serif", + "fontSize": "0.875rem", + "fontWeight": 500, + "letterSpacing": "0.00714em", + "lineHeight": 1.57, + }, + }, + "zIndex": Object { + "appBar": 1100, + "drawer": 1200, + "mobileStepper": 1000, + "modal": 1300, + "snackbar": 1400, + "speedDial": 1050, + "tooltip": 1500, + }, + }, + "name": "MuiBackdrop", + }, + "propTypes": Object { + "classes": [Function], + "innerRef": [Function], + }, + "render": [Function], + "useStyles": [Function], + } + } + BackdropProps={ + Object { + "transitionDuration": Object { + "enter": 225, + "exit": 195, + }, + } + } + className="MuiDialog-root modal-root" + closeAfterTransition={true} + disableEscapeKeyDown={false} + onClose={[MockFunction]} + open={true} + > + <ForwardRef(Portal) + disablePortal={false} + > + <Portal + containerInfo={ + <body + style="padding-right: 0px; overflow: hidden;" + > + <div + class="MuiDialog-root modal-root" + role="presentation" + style="position: fixed; z-index: 1300; right: 0px; bottom: 0px; top: 0px; left: 0px;" + > + <div + aria-hidden="true" + class="MuiBackdrop-root" + style="opacity: 1; webkit-transition: opacity 225ms cubic-bezier(0.4, 0, 0.2, 1) 0ms; transition: opacity 225ms cubic-bezier(0.4, 0, 0.2, 1) 0ms;" + /> + <div + data-test="sentinelStart" + tabindex="0" + /> + <div + class="MuiDialog-container MuiDialog-scrollPaper" + role="none presentation" + style="opacity: 1; webkit-transition: opacity 225ms cubic-bezier(0.4, 0, 0.2, 1) 0ms; transition: opacity 225ms cubic-bezier(0.4, 0, 0.2, 1) 0ms;" + tabindex="-1" + > + <div + aria-labelledby="accessibility-title" + class="MuiPaper-root MuiDialog-paper modal-paper MuiDialog-paperScrollPaper MuiDialog-paperWidthSm MuiPaper-elevation24 MuiPaper-rounded" + role="dialog" + > + <div + id="accessibility-title" + > + feedback.accessibility.window_title + </div> + <button + aria-label="feedback.accessibility.button_close" + class="MuiButtonBase-root MuiIconButton-root modal-paper-close-button" + tabindex="0" + type="button" + > + <span + class="MuiIconButton-label" + > + <svg + class="styles__icon___23x3R" + height="16" + width="16" + > + <use + xlink:href="#test-file-stub" + /> + </svg> + </span> + <span + class="MuiTouchRipple-root" + /> + </button> + <div + class="eg-reinit-modal" + > + <svg + class="styles__icon___23x3R" + height="63" + width="63" + > + <use + xlink:href="#test-file-stub" + /> + </svg> + <div + class="title text-20-bold" + > + ecogesture.reinitModal.title_part1 + <span + class="warn-title" + > + ecogesture.reinitModal.title_part2 + </span> + ecogesture.reinitModal.title_part3 + <span + class="warn-title" + > + ecogesture.reinitModal.title_part4 + </span> + ecogesture.reinitModal.title_part5 + <span + class="warn-title" + > + ecogesture.reinitModal.title_part6 + </span> + </div> + <div + class="text-16-normal text" + > + ecogesture.reinitModal.text1 + </div> + <div + class="text-16-bold text" + > + ecogesture.reinitModal.text2 + </div> + <div + class="buttons-container" + > + <button + aria-label="ecogesture.reinitModal.btn1" + class="MuiButtonBase-root MuiButton-root btn-secondary-negative MuiButton-text btn1" + tabindex="0" + type="button" + > + <span + class="MuiButton-label text-16-bold" + > + ecogesture.reinitModal.btn1 + </span> + <span + class="MuiTouchRipple-root" + /> + </button> + <button + aria-label="ecogesture.reinitModal.btn2" + class="MuiButtonBase-root MuiButton-root btn-profile-next rounded MuiButton-text" + tabindex="0" + type="button" + > + <span + class="MuiButton-label text-16-bold" + > + ecogesture.reinitModal.btn2 + </span> + <span + class="MuiTouchRipple-root" + /> + </button> + </div> + </div> + </div> + </div> + <div + data-test="sentinelEnd" + tabindex="0" + /> + </div> + </body> + } + > + <div + className="MuiDialog-root modal-root" + onKeyDown={[Function]} + role="presentation" + style={ + Object { + "bottom": 0, + "left": 0, + "position": "fixed", + "right": 0, + "top": 0, + "zIndex": 1300, + } + } + > + <WithStyles(ForwardRef(Backdrop)) + onClick={[Function]} + open={true} + transitionDuration={ + Object { + "enter": 225, + "exit": 195, + } + } + > + <ForwardRef(Backdrop) + classes={ + Object { + "invisible": "MuiBackdrop-invisible", + "root": "MuiBackdrop-root", + } + } + onClick={[Function]} + open={true} + transitionDuration={ + Object { + "enter": 225, + "exit": 195, + } + } + > + <ForwardRef(Fade) + in={true} + onClick={[Function]} + timeout={ + Object { + "enter": 225, + "exit": 195, + } + } + > + <Transition + appear={true} + enter={true} + exit={true} + in={true} + mountOnEnter={false} + onClick={[Function]} + onEnter={[Function]} + onEntered={[Function]} + onEntering={[Function]} + onExit={[Function]} + onExited={[Function]} + onExiting={[Function]} + timeout={ + Object { + "enter": 225, + "exit": 195, + } + } + unmountOnExit={false} + > + <div + aria-hidden={true} + className="MuiBackdrop-root" + onClick={[Function]} + style={ + Object { + "opacity": 1, + "visibility": undefined, + } + } + /> + </Transition> + </ForwardRef(Fade)> + </ForwardRef(Backdrop)> + </WithStyles(ForwardRef(Backdrop))> + <Unstable_TrapFocus + disableAutoFocus={false} + disableEnforceFocus={false} + disableRestoreFocus={false} + getDoc={[Function]} + isEnabled={[Function]} + open={true} + > + <div + data-test="sentinelStart" + tabIndex={0} + /> + <ForwardRef(Fade) + appear={true} + in={true} + onEnter={[Function]} + onExited={[Function]} + role="none presentation" + tabIndex="-1" + timeout={ + Object { + "enter": 225, + "exit": 195, + } + } + > + <Transition + appear={true} + enter={true} + exit={true} + in={true} + mountOnEnter={false} + onEnter={[Function]} + onEntered={[Function]} + onEntering={[Function]} + onExit={[Function]} + onExited={[Function]} + onExiting={[Function]} + role="none presentation" + tabIndex="-1" + timeout={ + Object { + "enter": 225, + "exit": 195, + } + } + unmountOnExit={false} + > + <div + className="MuiDialog-container MuiDialog-scrollPaper" + onMouseDown={[Function]} + onMouseUp={[Function]} + role="none presentation" + style={ + Object { + "opacity": 1, + "visibility": undefined, + } + } + tabIndex="-1" + > + <WithStyles(ForwardRef(Paper)) + aria-labelledby="accessibility-title" + className="MuiDialog-paper modal-paper MuiDialog-paperScrollPaper MuiDialog-paperWidthSm" + elevation={24} + role="dialog" + > + <ForwardRef(Paper) + aria-labelledby="accessibility-title" + className="MuiDialog-paper modal-paper MuiDialog-paperScrollPaper MuiDialog-paperWidthSm" + classes={ + Object { + "elevation0": "MuiPaper-elevation0", + "elevation1": "MuiPaper-elevation1", + "elevation10": "MuiPaper-elevation10", + "elevation11": "MuiPaper-elevation11", + "elevation12": "MuiPaper-elevation12", + "elevation13": "MuiPaper-elevation13", + "elevation14": "MuiPaper-elevation14", + "elevation15": "MuiPaper-elevation15", + "elevation16": "MuiPaper-elevation16", + "elevation17": "MuiPaper-elevation17", + "elevation18": "MuiPaper-elevation18", + "elevation19": "MuiPaper-elevation19", + "elevation2": "MuiPaper-elevation2", + "elevation20": "MuiPaper-elevation20", + "elevation21": "MuiPaper-elevation21", + "elevation22": "MuiPaper-elevation22", + "elevation23": "MuiPaper-elevation23", + "elevation24": "MuiPaper-elevation24", + "elevation3": "MuiPaper-elevation3", + "elevation4": "MuiPaper-elevation4", + "elevation5": "MuiPaper-elevation5", + "elevation6": "MuiPaper-elevation6", + "elevation7": "MuiPaper-elevation7", + "elevation8": "MuiPaper-elevation8", + "elevation9": "MuiPaper-elevation9", + "outlined": "MuiPaper-outlined", + "root": "MuiPaper-root", + "rounded": "MuiPaper-rounded", + } + } + elevation={24} + role="dialog" + > + <div + aria-labelledby="accessibility-title" + className="MuiPaper-root MuiDialog-paper modal-paper MuiDialog-paperScrollPaper MuiDialog-paperWidthSm MuiPaper-elevation24 MuiPaper-rounded" + role="dialog" + > + <div + id="accessibility-title" + > + feedback.accessibility.window_title + </div> + <WithStyles(ForwardRef(IconButton)) + aria-label="feedback.accessibility.button_close" + className="modal-paper-close-button" + onClick={[MockFunction]} + > + <ForwardRef(IconButton) + aria-label="feedback.accessibility.button_close" + className="modal-paper-close-button" + classes={ + Object { + "colorInherit": "MuiIconButton-colorInherit", + "colorPrimary": "MuiIconButton-colorPrimary", + "colorSecondary": "MuiIconButton-colorSecondary", + "disabled": "Mui-disabled", + "edgeEnd": "MuiIconButton-edgeEnd", + "edgeStart": "MuiIconButton-edgeStart", + "label": "MuiIconButton-label", + "root": "MuiIconButton-root", + "sizeSmall": "MuiIconButton-sizeSmall", + } + } + onClick={[MockFunction]} + > + <WithStyles(ForwardRef(ButtonBase)) + aria-label="feedback.accessibility.button_close" + centerRipple={true} + className="MuiIconButton-root modal-paper-close-button" + disabled={false} + focusRipple={true} + onClick={[MockFunction]} + > + <ForwardRef(ButtonBase) + aria-label="feedback.accessibility.button_close" + centerRipple={true} + className="MuiIconButton-root modal-paper-close-button" + classes={ + Object { + "disabled": "Mui-disabled", + "focusVisible": "Mui-focusVisible", + "root": "MuiButtonBase-root", + } + } + disabled={false} + focusRipple={true} + onClick={[MockFunction]} + > + <button + aria-label="feedback.accessibility.button_close" + className="MuiButtonBase-root MuiIconButton-root modal-paper-close-button" + disabled={false} + onBlur={[Function]} + onClick={[MockFunction]} + onDragLeave={[Function]} + onFocus={[Function]} + onKeyDown={[Function]} + onKeyUp={[Function]} + onMouseDown={[Function]} + onMouseLeave={[Function]} + onMouseUp={[Function]} + onTouchEnd={[Function]} + onTouchMove={[Function]} + onTouchStart={[Function]} + tabIndex={0} + type="button" + > + <span + className="MuiIconButton-label" + > + <Icon + icon="test-file-stub" + size={16} + spin={false} + > + <Component + className="styles__icon___23x3R" + height={16} + style={Object {}} + width={16} + > + <svg + className="styles__icon___23x3R" + height={16} + style={Object {}} + width={16} + > + <use + xlinkHref="#test-file-stub" + /> + </svg> + </Component> + </Icon> + </span> + <WithStyles(memo) + center={true} + > + <ForwardRef(TouchRipple) + center={true} + classes={ + Object { + "child": "MuiTouchRipple-child", + "childLeaving": "MuiTouchRipple-childLeaving", + "childPulsate": "MuiTouchRipple-childPulsate", + "ripple": "MuiTouchRipple-ripple", + "ripplePulsate": "MuiTouchRipple-ripplePulsate", + "rippleVisible": "MuiTouchRipple-rippleVisible", + "root": "MuiTouchRipple-root", + } + } + > + <span + className="MuiTouchRipple-root" + > + <TransitionGroup + childFactory={[Function]} + component={null} + exit={true} + /> + </span> + </ForwardRef(TouchRipple)> + </WithStyles(memo)> + </button> + </ForwardRef(ButtonBase)> + </WithStyles(ForwardRef(ButtonBase))> + </ForwardRef(IconButton)> + </WithStyles(ForwardRef(IconButton))> + <div + className="eg-reinit-modal" + > + <Icon + icon="test-file-stub" + size={63} + spin={false} + > + <Component + className="styles__icon___23x3R" + height={63} + style={Object {}} + width={63} + > + <svg + className="styles__icon___23x3R" + height={63} + style={Object {}} + width={63} + > + <use + xlinkHref="#test-file-stub" + /> + </svg> + </Component> + </Icon> + <div + className="title text-20-bold" + > + ecogesture.reinitModal.title_part1 + <span + className="warn-title" + > + ecogesture.reinitModal.title_part2 + </span> + ecogesture.reinitModal.title_part3 + <span + className="warn-title" + > + ecogesture.reinitModal.title_part4 + </span> + ecogesture.reinitModal.title_part5 + <span + className="warn-title" + > + ecogesture.reinitModal.title_part6 + </span> + </div> + <div + className="text-16-normal text" + > + ecogesture.reinitModal.text1 + </div> + <div + className="text-16-bold text" + > + ecogesture.reinitModal.text2 + </div> + <div + className="buttons-container" + > + <WithStyles(ForwardRef(Button)) + aria-label="ecogesture.reinitModal.btn1" + className="btn1" + classes={ + Object { + "label": "text-16-bold", + "root": "btn-secondary-negative", + } + } + onClick={[MockFunction]} + > + <ForwardRef(Button) + aria-label="ecogesture.reinitModal.btn1" + className="btn1" + classes={ + Object { + "colorInherit": "MuiButton-colorInherit", + "contained": "MuiButton-contained", + "containedPrimary": "MuiButton-containedPrimary", + "containedSecondary": "MuiButton-containedSecondary", + "containedSizeLarge": "MuiButton-containedSizeLarge", + "containedSizeSmall": "MuiButton-containedSizeSmall", + "disableElevation": "MuiButton-disableElevation", + "disabled": "Mui-disabled", + "endIcon": "MuiButton-endIcon", + "focusVisible": "Mui-focusVisible", + "fullWidth": "MuiButton-fullWidth", + "iconSizeLarge": "MuiButton-iconSizeLarge", + "iconSizeMedium": "MuiButton-iconSizeMedium", + "iconSizeSmall": "MuiButton-iconSizeSmall", + "label": "MuiButton-label text-16-bold", + "outlined": "MuiButton-outlined", + "outlinedPrimary": "MuiButton-outlinedPrimary", + "outlinedSecondary": "MuiButton-outlinedSecondary", + "outlinedSizeLarge": "MuiButton-outlinedSizeLarge", + "outlinedSizeSmall": "MuiButton-outlinedSizeSmall", + "root": "MuiButton-root btn-secondary-negative", + "sizeLarge": "MuiButton-sizeLarge", + "sizeSmall": "MuiButton-sizeSmall", + "startIcon": "MuiButton-startIcon", + "text": "MuiButton-text", + "textPrimary": "MuiButton-textPrimary", + "textSecondary": "MuiButton-textSecondary", + "textSizeLarge": "MuiButton-textSizeLarge", + "textSizeSmall": "MuiButton-textSizeSmall", + } + } + onClick={[MockFunction]} + > + <WithStyles(ForwardRef(ButtonBase)) + aria-label="ecogesture.reinitModal.btn1" + className="MuiButton-root btn-secondary-negative MuiButton-text btn1" + component="button" + disabled={false} + focusRipple={true} + focusVisibleClassName="Mui-focusVisible" + onClick={[MockFunction]} + type="button" + > + <ForwardRef(ButtonBase) + aria-label="ecogesture.reinitModal.btn1" + className="MuiButton-root btn-secondary-negative MuiButton-text btn1" + classes={ + Object { + "disabled": "Mui-disabled", + "focusVisible": "Mui-focusVisible", + "root": "MuiButtonBase-root", + } + } + component="button" + disabled={false} + focusRipple={true} + focusVisibleClassName="Mui-focusVisible" + onClick={[MockFunction]} + type="button" + > + <button + aria-label="ecogesture.reinitModal.btn1" + className="MuiButtonBase-root MuiButton-root btn-secondary-negative MuiButton-text btn1" + disabled={false} + onBlur={[Function]} + onClick={[MockFunction]} + onDragLeave={[Function]} + onFocus={[Function]} + onKeyDown={[Function]} + onKeyUp={[Function]} + onMouseDown={[Function]} + onMouseLeave={[Function]} + onMouseUp={[Function]} + onTouchEnd={[Function]} + onTouchMove={[Function]} + onTouchStart={[Function]} + tabIndex={0} + type="button" + > + <span + className="MuiButton-label text-16-bold" + > + ecogesture.reinitModal.btn1 + </span> + <WithStyles(memo) + center={false} + > + <ForwardRef(TouchRipple) + center={false} + classes={ + Object { + "child": "MuiTouchRipple-child", + "childLeaving": "MuiTouchRipple-childLeaving", + "childPulsate": "MuiTouchRipple-childPulsate", + "ripple": "MuiTouchRipple-ripple", + "ripplePulsate": "MuiTouchRipple-ripplePulsate", + "rippleVisible": "MuiTouchRipple-rippleVisible", + "root": "MuiTouchRipple-root", + } + } + > + <span + className="MuiTouchRipple-root" + > + <TransitionGroup + childFactory={[Function]} + component={null} + exit={true} + /> + </span> + </ForwardRef(TouchRipple)> + </WithStyles(memo)> + </button> + </ForwardRef(ButtonBase)> + </WithStyles(ForwardRef(ButtonBase))> + </ForwardRef(Button)> + </WithStyles(ForwardRef(Button))> + <WithStyles(ForwardRef(Button)) + aria-label="ecogesture.reinitModal.btn2" + classes={ + Object { + "label": "text-16-bold", + "root": "btn-profile-next rounded", + } + } + onClick={[MockFunction]} + > + <ForwardRef(Button) + aria-label="ecogesture.reinitModal.btn2" + classes={ + Object { + "colorInherit": "MuiButton-colorInherit", + "contained": "MuiButton-contained", + "containedPrimary": "MuiButton-containedPrimary", + "containedSecondary": "MuiButton-containedSecondary", + "containedSizeLarge": "MuiButton-containedSizeLarge", + "containedSizeSmall": "MuiButton-containedSizeSmall", + "disableElevation": "MuiButton-disableElevation", + "disabled": "Mui-disabled", + "endIcon": "MuiButton-endIcon", + "focusVisible": "Mui-focusVisible", + "fullWidth": "MuiButton-fullWidth", + "iconSizeLarge": "MuiButton-iconSizeLarge", + "iconSizeMedium": "MuiButton-iconSizeMedium", + "iconSizeSmall": "MuiButton-iconSizeSmall", + "label": "MuiButton-label text-16-bold", + "outlined": "MuiButton-outlined", + "outlinedPrimary": "MuiButton-outlinedPrimary", + "outlinedSecondary": "MuiButton-outlinedSecondary", + "outlinedSizeLarge": "MuiButton-outlinedSizeLarge", + "outlinedSizeSmall": "MuiButton-outlinedSizeSmall", + "root": "MuiButton-root btn-profile-next rounded", + "sizeLarge": "MuiButton-sizeLarge", + "sizeSmall": "MuiButton-sizeSmall", + "startIcon": "MuiButton-startIcon", + "text": "MuiButton-text", + "textPrimary": "MuiButton-textPrimary", + "textSecondary": "MuiButton-textSecondary", + "textSizeLarge": "MuiButton-textSizeLarge", + "textSizeSmall": "MuiButton-textSizeSmall", + } + } + onClick={[MockFunction]} + > + <WithStyles(ForwardRef(ButtonBase)) + aria-label="ecogesture.reinitModal.btn2" + className="MuiButton-root btn-profile-next rounded MuiButton-text" + component="button" + disabled={false} + focusRipple={true} + focusVisibleClassName="Mui-focusVisible" + onClick={[MockFunction]} + type="button" + > + <ForwardRef(ButtonBase) + aria-label="ecogesture.reinitModal.btn2" + className="MuiButton-root btn-profile-next rounded MuiButton-text" + classes={ + Object { + "disabled": "Mui-disabled", + "focusVisible": "Mui-focusVisible", + "root": "MuiButtonBase-root", + } + } + component="button" + disabled={false} + focusRipple={true} + focusVisibleClassName="Mui-focusVisible" + onClick={[MockFunction]} + type="button" + > + <button + aria-label="ecogesture.reinitModal.btn2" + className="MuiButtonBase-root MuiButton-root btn-profile-next rounded MuiButton-text" + disabled={false} + onBlur={[Function]} + onClick={[MockFunction]} + onDragLeave={[Function]} + onFocus={[Function]} + onKeyDown={[Function]} + onKeyUp={[Function]} + onMouseDown={[Function]} + onMouseLeave={[Function]} + onMouseUp={[Function]} + onTouchEnd={[Function]} + onTouchMove={[Function]} + onTouchStart={[Function]} + tabIndex={0} + type="button" + > + <span + className="MuiButton-label text-16-bold" + > + ecogesture.reinitModal.btn2 + </span> + <WithStyles(memo) + center={false} + > + <ForwardRef(TouchRipple) + center={false} + classes={ + Object { + "child": "MuiTouchRipple-child", + "childLeaving": "MuiTouchRipple-childLeaving", + "childPulsate": "MuiTouchRipple-childPulsate", + "ripple": "MuiTouchRipple-ripple", + "ripplePulsate": "MuiTouchRipple-ripplePulsate", + "rippleVisible": "MuiTouchRipple-rippleVisible", + "root": "MuiTouchRipple-root", + } + } + > + <span + className="MuiTouchRipple-root" + > + <TransitionGroup + childFactory={[Function]} + component={null} + exit={true} + /> + </span> + </ForwardRef(TouchRipple)> + </WithStyles(memo)> + </button> + </ForwardRef(ButtonBase)> + </WithStyles(ForwardRef(ButtonBase))> + </ForwardRef(Button)> + </WithStyles(ForwardRef(Button))> + </div> + </div> + </div> + </ForwardRef(Paper)> + </WithStyles(ForwardRef(Paper))> + </div> + </Transition> + </ForwardRef(Fade)> + <div + data-test="sentinelEnd" + tabIndex={0} + /> + </Unstable_TrapFocus> + </div> + </Portal> + </ForwardRef(Portal)> + </ForwardRef(Modal)> + </ForwardRef(Dialog)> + </WithStyles(ForwardRef(Dialog))> +</EcogestureReinitModal> +`; diff --git a/src/components/Ecogesture/ecogestureReinitModal.scss b/src/components/Ecogesture/EcogestureReinitModal/ecogestureReinitModal.scss similarity index 91% rename from src/components/Ecogesture/ecogestureReinitModal.scss rename to src/components/Ecogesture/EcogestureReinitModal/ecogestureReinitModal.scss index 01939fe7946009a67ee1dd35755ebca3c87bd958..5abb4e16a82c810101f570129d11d60611df53dc 100644 --- a/src/components/Ecogesture/ecogestureReinitModal.scss +++ b/src/components/Ecogesture/EcogestureReinitModal/ecogestureReinitModal.scss @@ -1,4 +1,4 @@ -@import '../../styles/base/color'; +@import 'src/styles/base/color'; .eg-reinit-modal { display: flex; diff --git a/src/components/Ecogesture/EcogestureTabsView.spec.tsx b/src/components/Ecogesture/EcogestureTabsView.spec.tsx new file mode 100644 index 0000000000000000000000000000000000000000..f9eb724daac10611df25dc09f03a69a68ea564eb --- /dev/null +++ b/src/components/Ecogesture/EcogestureTabsView.spec.tsx @@ -0,0 +1,109 @@ +import { IconButton, Tab } from '@material-ui/core' +import EcogestureTabsView from 'components/Ecogesture/EcogestureTabsView' +import { mount } from 'enzyme' +import toJson from 'enzyme-to-json' +import React from 'react' +import { Provider } from 'react-redux' +import * as profileActions from 'store/profile/profile.slice' +import { mockedEcogesturesData } from 'tests/__mocks__/ecogesturesData.mock' +import { createMockEcolyoStore } from 'tests/__mocks__/store' +import { waitForComponentToPaint } from 'tests/__mocks__/testUtils' +import EcogestureEmptyList from './EcogestureEmptyList/EcogestureEmptyList' +import EcogestureInitModal from './EcogestureInitModal/EcogestureInitModal' + +const mockGetAllEcogestures = jest.fn() +const mockGetEcogestureListByProfile = jest.fn().mockResolvedValue([]) +const mockInitEcogesture = jest.fn().mockResolvedValue(mockedEcogesturesData) +jest.mock('services/ecogesture.service', () => { + return jest.fn(() => ({ + getAllEcogestures: mockGetAllEcogestures, + getEcogestureListByProfile: mockGetEcogestureListByProfile, + initEcogesture: mockInitEcogesture, + })) +}) +const mockGetProfile = jest.fn() +const mockUpdateProfile = jest.fn() +jest.mock('services/profile.service', () => { + return jest.fn(() => ({ + getProfile: mockGetProfile, + updateProfile: mockUpdateProfile, + })) +}) + +jest.mock('components/Header/CozyBar', () => 'mock-cozybar') +jest.mock('components/Header/Header', () => 'mock-header') +jest.mock( + 'components/Ecogesture/EcogestureList/EcogestureList', + () => 'mock-ecogesturelist' +) +jest.mock('components/Content/Content', () => 'mock-content') + +jest.mock('react-router-dom', () => ({ + ...jest.requireActual('react-router-dom'), + useLocation: () => ({ + search: '', + }), + useNavigate: () => jest.fn(), +})) + +describe('EcogestureView component', () => { + const store = createMockEcolyoStore() + + it('should be rendered correctly', async () => { + const wrapper = mount( + <Provider store={store}> + <EcogestureTabsView /> + </Provider> + ) + await waitForComponentToPaint(wrapper) + + expect(wrapper.find(Tab).length).toBe(3) + expect(toJson(wrapper)).toMatchSnapshot() + }) + + it('should render ecogesture init modal', async () => { + const updateProfileSpy = jest.spyOn(profileActions, 'updateProfile') + + const wrapper = mount( + <Provider store={store}> + <EcogestureTabsView /> + </Provider> + ) + await waitForComponentToPaint(wrapper) + + expect(wrapper.find(EcogestureInitModal).exists()).toBeTruthy() + wrapper.find(IconButton).first().simulate('click') + await waitForComponentToPaint(wrapper) + + expect(updateProfileSpy).toHaveBeenCalledWith({ + haveSeenEcogestureModal: true, + }) + }) + + it('should render empty list', async () => { + const wrapper = mount( + <Provider store={store}> + <EcogestureTabsView /> + </Provider> + ) + await waitForComponentToPaint(wrapper) + + expect(wrapper.find(EcogestureEmptyList).exists()).toBeTruthy() + }) + + it('should change tab', async () => { + const wrapper = mount( + <Provider store={store}> + <EcogestureTabsView /> + </Provider> + ) + await waitForComponentToPaint(wrapper) + + wrapper.find(Tab).first().simulate('click') + mockGetAllEcogestures.mockResolvedValueOnce([]) + + await waitForComponentToPaint(wrapper) + + expect(wrapper.find(EcogestureEmptyList).exists()).toBeTruthy() + }) +}) diff --git a/src/components/Ecogesture/EcogestureView.tsx b/src/components/Ecogesture/EcogestureTabsView.tsx similarity index 71% rename from src/components/Ecogesture/EcogestureView.tsx rename to src/components/Ecogesture/EcogestureTabsView.tsx index afc1e1fe9bddcb1ac9fa0b80273b70bb54950668..2cd5f92b7a15fd4f7f964c17531e5548f0c9f3e2 100644 --- a/src/components/Ecogesture/EcogestureView.tsx +++ b/src/components/Ecogesture/EcogestureTabsView.tsx @@ -1,24 +1,23 @@ import { Tab, Tabs } from '@material-ui/core' import classNames from 'classnames' import Content from 'components/Content/Content' -import EcogestureList from 'components/Ecogesture/EcogestureList' import CozyBar from 'components/Header/CozyBar' import Header from 'components/Header/Header' import Loader from 'components/Loader/Loader' import { useClient } from 'cozy-client' import { useI18n } from 'cozy-ui/transpiled/react/I18n' -import { EcogestureTab } from 'enum/ecogesture.enum' +import { EcogestureTab } from 'enums' import { Ecogesture } from 'models' -import React, { Dispatch, useCallback, useEffect, useState } from 'react' -import { useDispatch, useSelector } from 'react-redux' +import React, { useCallback, useEffect, useState } from 'react' import { useLocation, useNavigate } from 'react-router-dom' import EcogestureService from 'services/ecogesture.service' -import { AppActionsTypes, AppStore } from 'store' -import { updateProfile } from 'store/profile/profile.actions' -import EcogestureEmptyList from './EcogestureEmptyList' -import EcogestureInitModal from './EcogestureInitModal' -import EcogestureReinitModal from './EcogestureReinitModal' -import './ecogestureView.scss' +import { useAppDispatch, useAppSelector } from 'store/hooks' +import { updateProfile } from 'store/profile/profile.slice' +import EcogestureEmptyList from './EcogestureEmptyList/EcogestureEmptyList' +import EcogestureInitModal from './EcogestureInitModal/EcogestureInitModal' +import EcogestureList from './EcogestureList/EcogestureList' +import EcogestureReinitModal from './EcogestureReinitModal/EcogestureReinitModal' +import './ecogestureTabsView.scss' interface TabPanelProps { children: React.ReactNode @@ -38,20 +37,16 @@ const TabPanel = ({ children, tab, value }: TabPanelProps) => { ) } -const EcogestureView = () => { - const [headerHeight, setHeaderHeight] = useState<number>(0) - const defineHeaderHeight = (height: number) => { - setHeaderHeight(height) - } +const EcogestureTabsView = () => { const { t } = useI18n() const client = useClient() - const dispatch = useDispatch<Dispatch<AppActionsTypes>>() const tab = new URLSearchParams(useLocation().search).get('tab') - - const { profile, profileEcogesture, profileType } = useSelector( - (state: AppStore) => state.ecolyo + const dispatch = useAppDispatch() + const { profile, profileEcogesture, profileType } = useAppSelector( + state => state.ecolyo ) + const [headerHeight, setHeaderHeight] = useState<number>(0) const [tabValue, setTabValue] = useState<EcogestureTab>( tab ? parseInt(tab) : EcogestureTab.OBJECTIVE ) @@ -113,13 +108,6 @@ const EcogestureView = () => { [navigate] ) - const tabProps = useCallback((index: number) => { - return { - id: `simple-tab-${index}`, - 'aria-controls': `simple-tabpanel-${index}`, - } - }, []) - const getTabLabel = useCallback( (tab: EcogestureTab) => { const tabCounts = { @@ -185,53 +173,57 @@ const EcogestureView = () => { return ( <> - <CozyBar titleKey={'common.title_ecogestures'} /> - {isLoading && ( - <Content height={headerHeight}> - <div className="ecogesture-spinner" aria-busy="true"> + <CozyBar titleKey="common.title_ecogestures" /> + <Header + setHeaderHeight={setHeaderHeight} + desktopTitleKey="common.title_ecogestures" + > + <Tabs + value={tabValue} + className="ecogestures-tabs" + aria-label="ecogestures-tabs" + onChange={handleChange} + TabIndicatorProps={{ className: 'indicator-tab' }} + centered={true} + > + <Tab + label={getTabLabel(EcogestureTab.OBJECTIVE)} + className={classNames('single-tab', { + ['active']: tabValue === EcogestureTab.OBJECTIVE, + })} + id={`simple-tab-${EcogestureTab.OBJECTIVE}`} + aria-controls={`simple-tabpanel-${EcogestureTab.OBJECTIVE}`} + tabIndex={0} + /> + <Tab + label={getTabLabel(EcogestureTab.DOING)} + className={classNames('single-tab', { + ['active']: tabValue === EcogestureTab.DOING, + })} + id={`simple-tab-${EcogestureTab.DOING}`} + aria-controls={`simple-tabpanel-${EcogestureTab.DOING}`} + tabIndex={0} + /> + <Tab + label={getTabLabel(EcogestureTab.ALL)} + className={classNames('single-tab', { + ['active']: tabValue === EcogestureTab.ALL, + })} + id={`simple-tab-${EcogestureTab.ALL}`} + aria-controls={`simple-tabpanel-${EcogestureTab.ALL}`} + tabIndex={0} + /> + </Tabs> + </Header> + + <Content heightOffset={headerHeight}> + {isLoading && ( + <div className="loaderContainer"> <Loader text={t('ecogestures.loading')} /> </div> - </Content> - )} - {!isLoading && ( - <> - <Header - setHeaderHeight={defineHeaderHeight} - desktopTitleKey={'common.title_ecogestures'} - > - <Tabs - value={tabValue} - className="ecogestures-tabs" - aria-label="ecogestures-tabs" - onChange={handleChange} - TabIndicatorProps={{ className: 'indicator-tab' }} - centered={true} - > - <Tab - label={getTabLabel(EcogestureTab.OBJECTIVE)} - className={classNames('single-tab', { - ['active']: tabValue === EcogestureTab.OBJECTIVE, - })} - {...tabProps(EcogestureTab.OBJECTIVE)} - /> - <Tab - label={getTabLabel(EcogestureTab.DOING)} - className={classNames('single-tab', { - ['active']: tabValue === EcogestureTab.DOING, - })} - {...tabProps(EcogestureTab.DOING)} - /> - <Tab - label={getTabLabel(EcogestureTab.ALL)} - className={classNames('single-tab', { - ['active']: tabValue === EcogestureTab.ALL, - })} - {...tabProps(EcogestureTab.ALL)} - /> - </Tabs> - </Header> - - <Content height={headerHeight}> + )} + {!isLoading && ( + <> <TabPanel value={tabValue} tab={EcogestureTab.OBJECTIVE}> {profile.isProfileEcogestureCompleted && (totalAvailable === totalViewed && @@ -300,25 +292,25 @@ const EcogestureView = () => { /> )} </TabPanel> - </Content> - </> - )} - {openEcogestureInitModal && ( - <EcogestureInitModal - open={openEcogestureInitModal} - handleCloseClick={handleCloseEcogestureInitModal} - handleLaunchForm={handleLaunchForm} - /> - )} - {openEcogestureReinitModal && ( - <EcogestureReinitModal - open={openEcogestureReinitModal} - handleCloseClick={handleCloseEcogestureReinitModal} - handleLaunchReinit={handleLaunchReinit} - /> - )} + </> + )} + {openEcogestureInitModal && ( + <EcogestureInitModal + open={openEcogestureInitModal} + handleCloseClick={handleCloseEcogestureInitModal} + handleLaunchForm={handleLaunchForm} + /> + )} + {openEcogestureReinitModal && ( + <EcogestureReinitModal + open={openEcogestureReinitModal} + handleCloseClick={handleCloseEcogestureReinitModal} + handleLaunchReinit={handleLaunchReinit} + /> + )} + </Content> </> ) } -export default EcogestureView +export default EcogestureTabsView diff --git a/src/components/Ecogesture/EcogestureView.spec.tsx b/src/components/Ecogesture/EcogestureView.spec.tsx deleted file mode 100644 index 3a2c6b13180b4639a7693fff03a1c56bbf97840f..0000000000000000000000000000000000000000 --- a/src/components/Ecogesture/EcogestureView.spec.tsx +++ /dev/null @@ -1,151 +0,0 @@ -import { IconButton, Tab } from '@material-ui/core' -import EcogestureView from 'components/Ecogesture/EcogestureView' -import { Season } from 'enum/ecogesture.enum' -import { mount } from 'enzyme' -import toJson from 'enzyme-to-json' -import React from 'react' -import * as reactRedux from 'react-redux' -import { Provider } from 'react-redux' -import * as profileActions from 'store/profile/profile.actions' -import { mockedEcogesturesData } from '../../../tests/__mocks__/ecogesturesData.mock' -import { - createMockEcolyoStore, - mockInitialProfileState, -} from '../../../tests/__mocks__/store' -import { waitForComponentToPaint } from '../../../tests/__mocks__/testUtils' -import EcogestureEmptyList from './EcogestureEmptyList' -import EcogestureInitModal from './EcogestureInitModal' - -jest.mock('cozy-ui/transpiled/react/I18n', () => { - return { - useI18n: jest.fn(() => { - return { - t: (str: string) => str, - } - }), - } -}) -const mockGetAllEcogestures = jest.fn() -const mockGetEcogestureListByProfile = jest.fn() -const mockInitEcogesture = jest.fn() -jest.mock('services/ecogesture.service', () => { - return jest.fn(() => { - return { - getAllEcogestures: mockGetAllEcogestures, - getEcogestureListByProfile: mockGetEcogestureListByProfile, - initEcogesture: mockInitEcogesture, - } - }) -}) -const mockGetProfile = jest.fn() -const mockUpdateProfile = jest.fn() -jest.mock('services/profile.service', () => { - return jest.fn(() => { - return { - getProfile: mockGetProfile, - updateProfile: mockUpdateProfile, - } - }) -}) - -jest.mock('components/Header/CozyBar', () => 'mock-cozybar') -jest.mock('components/Header/Header', () => 'mock-header') -jest.mock('components/Ecogesture/EcogestureList', () => 'mock-ecogesturelist') -jest.mock('components/Content/Content', () => 'mock-content') -const mockGetSeason = jest.fn() -jest.mock('utils/utils', () => { - return { - getSeason: jest.fn(() => { - return mockGetSeason - }), - } -}) -const useSelectorSpy = jest.spyOn(reactRedux, 'useSelector') -const mockedNavigate = jest.fn() -jest.mock('react-router-dom', () => ({ - ...jest.requireActual('react-router-dom'), - useLocation: () => { - return { - search: '', - } - }, - useNavigate: () => mockedNavigate, -})) - -describe('EcogestureView component', () => { - const store = createMockEcolyoStore() - beforeEach(() => { - store.clearActions() - mockGetSeason.mockClear() - mockGetAllEcogestures.mockClear() - mockGetEcogestureListByProfile.mockClear() - - useSelectorSpy.mockReturnValue({ - profile: mockInitialProfileState, - isProfileTypeCompleted: true, - haveSeenEcogestureModal: true, - }) - - mockInitEcogesture.mockResolvedValue(mockedEcogesturesData) - mockGetSeason.mockReturnValue(Season.WINTER) - mockGetEcogestureListByProfile.mockResolvedValue([]) - }) - - it('should be rendered correctly', async () => { - const wrapper = mount( - <Provider store={store}> - <EcogestureView /> - </Provider> - ) - await waitForComponentToPaint(wrapper) - - expect(wrapper.find(Tab).length).toBe(3) - expect(toJson(wrapper)).toMatchSnapshot() - }) - - it('should render ecogesture init modal', async () => { - const updateProfileSpy = jest.spyOn(profileActions, 'updateProfile') - - const wrapper = mount( - <Provider store={store}> - <EcogestureView /> - </Provider> - ) - await waitForComponentToPaint(wrapper) - - expect(wrapper.find(EcogestureInitModal).exists()).toBeTruthy() - wrapper.find(IconButton).first().simulate('click') - await waitForComponentToPaint(wrapper) - - expect(updateProfileSpy).toHaveBeenCalledWith({ - haveSeenEcogestureModal: true, - }) - }) - - it('should render empty list', async () => { - const wrapper = mount( - <Provider store={store}> - <EcogestureView /> - </Provider> - ) - await waitForComponentToPaint(wrapper) - - expect(wrapper.find(EcogestureEmptyList).exists()).toBeTruthy() - }) - - it('should change tab', async () => { - const wrapper = mount( - <Provider store={store}> - <EcogestureView /> - </Provider> - ) - await waitForComponentToPaint(wrapper) - - wrapper.find(Tab).first().simulate('click') - mockGetAllEcogestures.mockResolvedValueOnce([]) - - await waitForComponentToPaint(wrapper) - - expect(wrapper.find(EcogestureEmptyList).exists()).toBeTruthy() - }) -}) diff --git a/src/components/Ecogesture/EfficiencyRating.spec.tsx b/src/components/Ecogesture/EfficiencyRating.spec.tsx deleted file mode 100644 index 4cf025b1fafee98dc16614d1a033a5267263a39c..0000000000000000000000000000000000000000 --- a/src/components/Ecogesture/EfficiencyRating.spec.tsx +++ /dev/null @@ -1,37 +0,0 @@ -import EfficiencyRating from 'components/Ecogesture/EfficiencyRating' -import { mount } from 'enzyme' -import toJson from 'enzyme-to-json' -import React from 'react' -import { Provider } from 'react-redux' -import configureStore from 'redux-mock-store' -import { challengeStateData } from '../../../tests/__mocks__/challengeStateData.mock' -import { globalStateData } from '../../../tests/__mocks__/globalStateData.mock' - -jest.mock('cozy-ui/transpiled/react/I18n', () => { - return { - useI18n: jest.fn(() => { - return { - t: (str: string) => str, - } - }), - } -}) - -const mockStore = configureStore([]) - -describe('EfficiencyRating component', () => { - it('should be rendered correctly', () => { - const store = mockStore({ - ecolyo: { - global: globalStateData, - challenge: challengeStateData, - }, - }) - const wrapper = mount( - <Provider store={store}> - <EfficiencyRating result={3} /> - </Provider> - ) - expect(toJson(wrapper)).toMatchSnapshot() - }) -}) diff --git a/src/components/Ecogesture/EfficiencyRating/EfficiencyRating.spec.tsx b/src/components/Ecogesture/EfficiencyRating/EfficiencyRating.spec.tsx new file mode 100644 index 0000000000000000000000000000000000000000..0ac6b73e5884385bfddb078699cf61d6c1a1de39 --- /dev/null +++ b/src/components/Ecogesture/EfficiencyRating/EfficiencyRating.spec.tsx @@ -0,0 +1,11 @@ +import EfficiencyRating from 'components/Ecogesture/EfficiencyRating/EfficiencyRating' +import { mount } from 'enzyme' +import toJson from 'enzyme-to-json' +import React from 'react' + +describe('EfficiencyRating component', () => { + it('should be rendered correctly', () => { + const wrapper = mount(<EfficiencyRating result={3} />) + expect(toJson(wrapper)).toMatchSnapshot() + }) +}) diff --git a/src/components/Ecogesture/EfficiencyRating.tsx b/src/components/Ecogesture/EfficiencyRating/EfficiencyRating.tsx similarity index 100% rename from src/components/Ecogesture/EfficiencyRating.tsx rename to src/components/Ecogesture/EfficiencyRating/EfficiencyRating.tsx diff --git a/src/components/Ecogesture/EfficiencyRating/__snapshots__/EfficiencyRating.spec.tsx.snap b/src/components/Ecogesture/EfficiencyRating/__snapshots__/EfficiencyRating.spec.tsx.snap new file mode 100644 index 0000000000000000000000000000000000000000..9b1d8405abc6fc7a30d13bd2375d2472bdd79414 --- /dev/null +++ b/src/components/Ecogesture/EfficiencyRating/__snapshots__/EfficiencyRating.spec.tsx.snap @@ -0,0 +1,182 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`EfficiencyRating component should be rendered correctly 1`] = ` +<EfficiencyRating + result={3} +> + <div + className="thunder" + > + <StyledIcon + className="star" + icon="test-file-stub" + key="1" + size={15} + > + <Icon + aria-hidden={true} + className="star" + icon="test-file-stub" + size={15} + spin={false} + > + <Component + aria-hidden={true} + className="star styles__icon___23x3R" + height={15} + style={Object {}} + width={15} + > + <svg + aria-hidden={true} + className="star styles__icon___23x3R" + height={15} + style={Object {}} + width={15} + > + <use + xlinkHref="#test-file-stub" + /> + </svg> + </Component> + </Icon> + </StyledIcon> + <StyledIcon + className="star" + icon="test-file-stub" + key="2" + size={15} + > + <Icon + aria-hidden={true} + className="star" + icon="test-file-stub" + size={15} + spin={false} + > + <Component + aria-hidden={true} + className="star styles__icon___23x3R" + height={15} + style={Object {}} + width={15} + > + <svg + aria-hidden={true} + className="star styles__icon___23x3R" + height={15} + style={Object {}} + width={15} + > + <use + xlinkHref="#test-file-stub" + /> + </svg> + </Component> + </Icon> + </StyledIcon> + <StyledIcon + className="star" + icon="test-file-stub" + key="3" + size={15} + > + <Icon + aria-hidden={true} + className="star" + icon="test-file-stub" + size={15} + spin={false} + > + <Component + aria-hidden={true} + className="star styles__icon___23x3R" + height={15} + style={Object {}} + width={15} + > + <svg + aria-hidden={true} + className="star styles__icon___23x3R" + height={15} + style={Object {}} + width={15} + > + <use + xlinkHref="#test-file-stub" + /> + </svg> + </Component> + </Icon> + </StyledIcon> + <StyledIcon + className="star" + icon="test-file-stub" + key="4" + size={15} + > + <Icon + aria-hidden={true} + className="star" + icon="test-file-stub" + size={15} + spin={false} + > + <Component + aria-hidden={true} + className="star styles__icon___23x3R" + height={15} + style={Object {}} + width={15} + > + <svg + aria-hidden={true} + className="star styles__icon___23x3R" + height={15} + style={Object {}} + width={15} + > + <use + xlinkHref="#test-file-stub" + /> + </svg> + </Component> + </Icon> + </StyledIcon> + <StyledIcon + className="star" + icon="test-file-stub" + key="5" + size={15} + > + <Icon + aria-hidden={true} + className="star" + icon="test-file-stub" + size={15} + spin={false} + > + <Component + aria-hidden={true} + className="star styles__icon___23x3R" + height={15} + style={Object {}} + width={15} + > + <svg + aria-hidden={true} + className="star styles__icon___23x3R" + height={15} + style={Object {}} + width={15} + > + <use + xlinkHref="#test-file-stub" + /> + </svg> + </Component> + </Icon> + </StyledIcon> + </div> +</EfficiencyRating> +`; diff --git a/src/components/Ecogesture/SingleEcogesture.spec.tsx b/src/components/Ecogesture/SingleEcogesture.spec.tsx deleted file mode 100644 index 38942976a83bac1aa333a1b34d34796e897bf6c4..0000000000000000000000000000000000000000 --- a/src/components/Ecogesture/SingleEcogesture.spec.tsx +++ /dev/null @@ -1,153 +0,0 @@ -/* eslint-disable react/display-name */ -import SingleEcogesture from 'components/Ecogesture/SingleEcogesture' -import { mount } from 'enzyme' -import toJson from 'enzyme-to-json' -import React from 'react' -import { Provider } from 'react-redux' -import configureStore from 'redux-mock-store' -import { challengeStateData } from '../../../tests/__mocks__/challengeStateData.mock' -import { mockedEcogesturesData } from '../../../tests/__mocks__/ecogesturesData.mock' -import { globalStateData } from '../../../tests/__mocks__/globalStateData.mock' -import { waitForComponentToPaint } from '../../../tests/__mocks__/testUtils' - -jest.mock('cozy-ui/transpiled/react/I18n', () => { - return { - useI18n: jest.fn(() => { - return { - t: (str: string) => str, - } - }), - } -}) -const mockedNavigate = jest.fn() - -jest.mock('react-router-dom', () => ({ - ...jest.requireActual('react-router-dom'), - useNavigate: () => mockedNavigate, - useParams: () => - jest.fn().mockReturnValue({ ecogestureID: 'ECOGESTURE0001' }), - useLocation: jest.fn().mockReturnValue({ - state: { selectionCompleted: true }, - }), -})) -const mockImportIconById = jest.fn() -jest.mock('utils/utils', () => { - return { - importIconById: () => mockImportIconById, - } -}) - -jest.mock('components/Ecogesture/EfficiencyRating', () => () => ( - <div id="EfficiencyRating" /> -)) -jest.mock('components/Header/Header', () => () => <div id="Header" />) -jest.mock('components/Header/CozyBar', () => () => <div id="CozyBar" />) -jest.mock('components/Loader/Loader', () => () => <div id="spinner" />) -// eslint-disable-next-line @typescript-eslint/no-explicit-any -jest.mock('components/Content/Content', () => (props: any) => ( - <div id="content">{props.children}</div> -)) - -const mockGetEcogesturesByIds = jest.fn() -const mockUpdateEcogesture = jest.fn() -jest.mock('services/ecogesture.service', () => { - return jest.fn(() => { - return { - getEcogesturesByIds: mockGetEcogesturesByIds, - updateEcogesture: mockUpdateEcogesture, - } - }) -}) - -const mockStore = configureStore([]) - -describe('SingleEcogesture component', () => { - it('should be rendered correctly', async () => { - const store = mockStore({ - ecolyo: { - global: globalStateData, - challenge: challengeStateData, - }, - }) - - mockGetEcogesturesByIds.mockResolvedValue([mockedEcogesturesData[0]]) - const wrapper = mount( - <Provider store={store}> - <SingleEcogesture /> - </Provider> - ) - await waitForComponentToPaint(wrapper) - expect(toJson(wrapper)).toMatchSnapshot() - }) - - it('should change doing status', async () => { - const store = mockStore({ - ecolyo: { - global: globalStateData, - challenge: challengeStateData, - }, - }) - - mockGetEcogesturesByIds.mockResolvedValue([mockedEcogesturesData[0]]) - mockImportIconById.mockReturnValue('') - const updatedEcogesture = { ...mockedEcogesturesData[0], doing: true } - mockUpdateEcogesture.mockResolvedValueOnce(updatedEcogesture) - const wrapper = mount( - <Provider store={store}> - <SingleEcogesture /> - </Provider> - ) - await waitForComponentToPaint(wrapper) - wrapper.find('.doing-btn').first().simulate('click') - await waitForComponentToPaint(wrapper) - expect(mockUpdateEcogesture).toHaveBeenCalledWith(updatedEcogesture) - }) - it('should change objective status', async () => { - const store = mockStore({ - ecolyo: { - global: globalStateData, - challenge: challengeStateData, - }, - }) - - mockGetEcogesturesByIds.mockResolvedValue([mockedEcogesturesData[0]]) - mockImportIconById.mockReturnValue('icontest') - const updatedEcogesture = { ...mockedEcogesturesData[0], objective: true } - mockUpdateEcogesture.mockResolvedValueOnce(updatedEcogesture) - - const wrapper = mount( - <Provider store={store}> - <SingleEcogesture /> - </Provider> - ) - await waitForComponentToPaint(wrapper) - wrapper.find('.objective-btn').first().simulate('click') - await waitForComponentToPaint(wrapper) - expect(mockUpdateEcogesture).toHaveBeenCalledWith(updatedEcogesture) - }) - it('should toggle more details', async () => { - const store = mockStore({ - ecolyo: { - global: globalStateData, - challenge: challengeStateData, - }, - }) - - mockGetEcogesturesByIds.mockResolvedValue([mockedEcogesturesData[0]]) - mockImportIconById.mockReturnValue(undefined) - - const wrapper = mount( - <Provider store={store}> - <SingleEcogesture /> - </Provider> - ) - await waitForComponentToPaint(wrapper) - - wrapper.find('.toggle-text').first().simulate('click') - await waitForComponentToPaint(wrapper) - - expect(wrapper.find('.toggle-text').text()).toBe( - 'ecogesture_modal.show_less' - ) - }) -}) diff --git a/src/components/Ecogesture/SingleEcogesture.tsx b/src/components/Ecogesture/SingleEcogesture.tsx deleted file mode 100644 index 2dfef67887c5fbf4dbb76facec4ce16027a29eb2..0000000000000000000000000000000000000000 --- a/src/components/Ecogesture/SingleEcogesture.tsx +++ /dev/null @@ -1,241 +0,0 @@ -import IconButton from '@material-ui/core/IconButton' -import doingDisabledIcon from 'assets/icons/ico/doing-disabled.svg' -import doingEnabledIcon from 'assets/icons/ico/doing-enabled.svg' -import objectiveDisabledIcon from 'assets/icons/ico/objective-disabled.svg' -import objectiveEnabledIcon from 'assets/icons/ico/objective-enabled.svg' -import defaultIcon from 'assets/icons/visu/ecogesture/default.svg' -import classNames from 'classnames' -import ErrorPage from 'components/CommonKit/ErrorPage/ErrorPage' -import StyledIcon from 'components/CommonKit/Icon/StyledIcon' -import Content from 'components/Content/Content' -import CozyBar from 'components/Header/CozyBar' -import Header from 'components/Header/Header' -import useExploration from 'components/Hooks/useExploration' -import Loader from 'components/Loader/Loader' -import { useClient } from 'cozy-client' -import { useI18n } from 'cozy-ui/transpiled/react/I18n' -import Icon from 'cozy-ui/transpiled/react/Icon' -import { Ecogesture } from 'models' -import React, { useCallback, useEffect, useMemo, useState } from 'react' -import { useSelector } from 'react-redux' -import { Location, useLocation, useNavigate, useParams } from 'react-router-dom' -import EcogestureService from 'services/ecogesture.service' -import { AppStore } from 'store' -import { importIconById } from 'utils/utils' -import EfficiencyRating from './EfficiencyRating' -import './singleEcogesture.scss' - -interface EcogestureLocation extends Location { - state: { - selectionCompleted: boolean - } -} - -const SingleEcogesture = () => { - const { t } = useI18n() - const client = useClient() - const navigate = useNavigate() - const location: EcogestureLocation = useLocation() - const [ecogesture, setEcogesture] = useState<Ecogesture>() - const [ecogestureIcon, setEcogestureIcon] = useState<string>('') - const [isMoreDetail, setIsMoreDetail] = useState<boolean>(false) - const [isDoing, setIsDoing] = useState<boolean>(false) - const [isObjective, setIsObjective] = useState<boolean>(false) - const [isLoading, setIsLoading] = useState<boolean>(true) - const { ecogestureID } = useParams<{ ecogestureID: string }>() - const selectionCompleted = location?.state?.selectionCompleted - - const ecogestureService = useMemo( - () => new EcogestureService(client), - [client] - ) - const { currentChallenge } = useSelector( - (state: AppStore) => state.ecolyo.challenge - ) - const [headerHeight, setHeaderHeight] = useState<number>(0) - const defineHeaderHeight = (height: number) => { - setHeaderHeight(height) - } - const [, setValidExploration] = useExploration() - const toggleMoreDetail = () => { - setIsMoreDetail(prev => !prev) - } - const toggleObjective = useCallback(async () => { - if (ecogesture) { - const toUpdate: Ecogesture = { ...ecogesture, objective: !isObjective } - const updatedEcogesture = await ecogestureService.updateEcogesture( - toUpdate - ) - if (updatedEcogesture) { - setIsObjective(prev => !prev) - setEcogesture(updatedEcogesture) - } - } - }, [ecogesture, ecogestureService, isObjective]) - - const toggleDoing = useCallback(async () => { - if (ecogesture) { - const toUpdate: Ecogesture = { ...ecogesture, doing: !isDoing } - const updatedEcogesture = await ecogestureService.updateEcogesture( - toUpdate - ) - if (updatedEcogesture) { - setIsDoing(prev => !prev) - setEcogesture(updatedEcogesture) - } - } - }, [ecogesture, ecogestureService, isDoing]) - - useEffect(() => { - let subscribed = true - async function getSingleEcogesture() { - const data = await ecogestureService.getEcogesturesByIds([ - ecogestureID || '', - ]) - if (subscribed) { - if (data?.[0]) { - setEcogesture(data[0]) - // Prevent case this key doesn't exist in doctype - setIsObjective(data[0].objective) - setIsDoing(data[0].doing) - const icon = await importIconById(data[0].id, 'ecogesture') - if (subscribed) { - setEcogestureIcon(icon || defaultIcon) - if (currentChallenge?.exploration.ecogesture_id === data[0]._id) { - setValidExploration(currentChallenge.exploration.id) - } - } - } - setIsLoading(false) - } - } - getSingleEcogesture() - - return () => { - subscribed = false - } - }, [ - client, - currentChallenge, - ecogestureID, - ecogestureService, - setValidExploration, - ]) - - if (isLoading) { - return ( - <Content height={headerHeight}> - <Loader /> - </Content> - ) - } - - if (ecogesture) { - return ( - <> - <CozyBar - titleKey={'common.title_ecogesture'} - displayBackArrow={true} - backFunction={() => navigate('/ecogestures')} - /> - <Header - setHeaderHeight={defineHeaderHeight} - desktopTitleKey={'common.title_ecogesture'} - displayBackArrow={true} - /> - <Content height={headerHeight}> - <div className="single-ecogesture"> - <div className="icon-container"> - {ecogestureIcon && ( - <StyledIcon - className="icon-big" - icon={ecogestureIcon} - size={220} - /> - )} - </div> - <div className="details"> - <div className="text-22 title">{ecogesture.shortName}</div> - <div className="efficiency"> - <span className="text text-14-normal"> - {t('ecogesture_modal.efficiency')} - </span> - <EfficiencyRating result={Math.round(ecogesture.efficiency)} /> - </div> - </div> - <div className="styled-container"> - <div className="long-name text-18-bold"> - {ecogesture.longName} - </div> - <div - className="toggle-text text-15-normal" - onClick={toggleMoreDetail} - role="button" - > - {isMoreDetail - ? t('ecogesture_modal.show_less') - : t('ecogesture_modal.show_more')} - </div> - <div - className={classNames('description text-16-normal-150', { - ['block']: isMoreDetail === true, - })} - > - {ecogesture.longDescription} - </div> - </div> - {selectionCompleted && ( - <div className="buttons-selection"> - <IconButton - aria-label={t('ecogesture.objective')} - onClick={toggleObjective} - classes={{ - root: `btn-secondary-negative objective-btn ${ - isObjective && 'active' - }`, - label: 'text-15-normal', - }} - > - <Icon - className="status-icon" - icon={ - isObjective ? objectiveEnabledIcon : objectiveDisabledIcon - } - size={40} - /> - <span>{t('ecogesture.objective')}</span> - </IconButton> - <IconButton - aria-label={t('ecogesture.doing')} - onClick={toggleDoing} - classes={{ - root: `btn-secondary-negative doing-btn ${ - isDoing && 'active' - }`, - label: 'text-15-normal', - }} - > - <Icon - className="status-icon" - icon={isDoing ? doingEnabledIcon : doingDisabledIcon} - size={40} - /> - <span>{t('ecogesture.doing')}</span> - </IconButton> - </div> - )} - </div> - </Content> - </> - ) - } - - return ( - <ErrorPage - text={t('error_page.no_ecogesture')} - returnPage={'ecogestures'} - /> - ) -} - -export default SingleEcogesture diff --git a/src/components/Ecogesture/SingleEcogestureView.spec.tsx b/src/components/Ecogesture/SingleEcogestureView.spec.tsx new file mode 100644 index 0000000000000000000000000000000000000000..35e2ff90e7dcbe2855822c4b7922b3e43d04ddf1 --- /dev/null +++ b/src/components/Ecogesture/SingleEcogestureView.spec.tsx @@ -0,0 +1,87 @@ +/* eslint-disable react/display-name */ +import { mount } from 'enzyme' +import toJson from 'enzyme-to-json' +import React from 'react' +import { Provider } from 'react-redux' +import { mockedEcogesturesData } from 'tests/__mocks__/ecogesturesData.mock' +import { createMockEcolyoStore } from 'tests/__mocks__/store' +import { waitForComponentToPaint } from 'tests/__mocks__/testUtils' +import SingleEcogestureView from './SingleEcogestureView' + +jest.mock( + 'components/Ecogesture/EfficiencyRating/EfficiencyRating', + () => 'mock-EfficiencyRating' +) +jest.mock('components/Header/CozyBar', () => 'mock-cozybar') +jest.mock('components/Header/Header', () => 'mock-header') +jest.mock('components/Content/Content', () => 'mock-content') + +const mockGetEcogesturesByIds = jest.fn() +const mockUpdateEcogesture = jest.fn() +jest.mock('services/ecogesture.service', () => { + return jest.fn(() => ({ + getEcogesturesByIds: mockGetEcogesturesByIds, + updateEcogesture: mockUpdateEcogesture, + })) +}) + +describe('SingleEcogesture component', () => { + const store = createMockEcolyoStore() + it('should be rendered correctly', async () => { + mockGetEcogesturesByIds.mockResolvedValue([mockedEcogesturesData[0]]) + const wrapper = mount( + <Provider store={store}> + <SingleEcogestureView /> + </Provider> + ) + await waitForComponentToPaint(wrapper) + expect(toJson(wrapper)).toMatchSnapshot() + }) + + it('should change doing status', async () => { + mockGetEcogesturesByIds.mockResolvedValue([mockedEcogesturesData[0]]) + + const updatedEcogesture = { ...mockedEcogesturesData[0], doing: true } + mockUpdateEcogesture.mockResolvedValueOnce(updatedEcogesture) + const wrapper = mount( + <Provider store={store}> + <SingleEcogestureView /> + </Provider> + ) + await waitForComponentToPaint(wrapper) + wrapper.find('.doing-btn').first().simulate('click') + await waitForComponentToPaint(wrapper) + expect(mockUpdateEcogesture).toHaveBeenCalledWith(updatedEcogesture) + }) + it('should change objective status', async () => { + mockGetEcogesturesByIds.mockResolvedValue([mockedEcogesturesData[0]]) + + const updatedEcogesture = { ...mockedEcogesturesData[0], objective: true } + mockUpdateEcogesture.mockResolvedValueOnce(updatedEcogesture) + + const wrapper = mount( + <Provider store={store}> + <SingleEcogestureView /> + </Provider> + ) + await waitForComponentToPaint(wrapper) + wrapper.find('.objective-btn').first().simulate('click') + await waitForComponentToPaint(wrapper) + expect(mockUpdateEcogesture).toHaveBeenCalledWith(updatedEcogesture) + }) + it('should toggle more details', async () => { + mockGetEcogesturesByIds.mockResolvedValue([mockedEcogesturesData[0]]) + + const wrapper = mount( + <Provider store={store}> + <SingleEcogestureView /> + </Provider> + ) + await waitForComponentToPaint(wrapper) + + wrapper.find('.showMore').first().simulate('click') + await waitForComponentToPaint(wrapper) + + expect(wrapper.find('.showMore').text()).toBe('ecogesture_modal.show_less') + }) +}) diff --git a/src/components/Ecogesture/SingleEcogestureView.tsx b/src/components/Ecogesture/SingleEcogestureView.tsx new file mode 100644 index 0000000000000000000000000000000000000000..3f9b7cefb326293d6dc88a4ff15f014c28a7a903 --- /dev/null +++ b/src/components/Ecogesture/SingleEcogestureView.tsx @@ -0,0 +1,218 @@ +import { Collapse } from '@material-ui/core' +import IconButton from '@material-ui/core/IconButton' +import * as Sentry from '@sentry/react' +import doingDisabledIcon from 'assets/icons/ico/doing-disabled.svg' +import doingEnabledIcon from 'assets/icons/ico/doing-enabled.svg' +import objectiveDisabledIcon from 'assets/icons/ico/objective-disabled.svg' +import objectiveEnabledIcon from 'assets/icons/ico/objective-enabled.svg' +import defaultIcon from 'assets/icons/visu/ecogesture/default.svg' +import StyledIcon from 'components/CommonKit/Icon/StyledIcon' +import Content from 'components/Content/Content' +import ErrorPage from 'components/Ecogesture/EcogestureNotFound/EcogestureNotFound' +import CozyBar from 'components/Header/CozyBar' +import Header from 'components/Header/Header' +import useExploration from 'components/Hooks/useExploration' +import Loader from 'components/Loader/Loader' +import { useClient } from 'cozy-client' +import { useI18n } from 'cozy-ui/transpiled/react/I18n' +import Icon from 'cozy-ui/transpiled/react/Icon' +import { Ecogesture } from 'models' +import React, { useCallback, useEffect, useMemo, useState } from 'react' +import { useParams } from 'react-router-dom' +import EcogestureService from 'services/ecogesture.service' +import { useAppSelector } from 'store/hooks' +import logApp from 'utils/logger' +import { importIconById } from 'utils/utils' +import EfficiencyRating from './EfficiencyRating/EfficiencyRating' +import './singleEcogestureView.scss' + +const SingleEcogestureView = () => { + const { t } = useI18n() + const client = useClient() + const [ecogesture, setEcogesture] = useState<Ecogesture>() + const [ecogestureIcon, setEcogestureIcon] = useState<string>('') + const [showDetails, setShowDetails] = useState<boolean>(false) + const [isDoing, setIsDoing] = useState<boolean>(false) + const [isObjective, setIsObjective] = useState<boolean>(false) + const [isLoading, setIsLoading] = useState<boolean>(true) + const { ecogestureID } = useParams<{ ecogestureID: string }>() + + const ecogestureService = useMemo( + () => new EcogestureService(client), + [client] + ) + const { currentChallenge } = useAppSelector(state => state.ecolyo.challenge) + const [headerHeight, setHeaderHeight] = useState<number>(0) + const [, setValidExploration] = useExploration() + + const updateEcogesture = useCallback( + async (objective, doing) => { + if (ecogesture) { + const updates: Ecogesture = { + ...ecogesture, + objective: objective, + doing: doing, + } + const result = await ecogestureService.updateEcogesture(updates) + if (result) { + setIsObjective(result.objective) + setIsDoing(result.doing) + setEcogesture(result) + } + } + }, + [ecogesture, ecogestureService] + ) + + const toggleObjective = useCallback(() => { + updateEcogesture(!isObjective, false) + }, [isObjective, updateEcogesture]) + + const toggleDoing = useCallback(() => { + updateEcogesture(false, !isDoing) + }, [isDoing, updateEcogesture]) + + useEffect(() => { + let subscribed = true + async function getSingleEcogesture() { + const data = await ecogestureService.getEcogesturesByIds([ + ecogestureID || '', + ]) + if (subscribed) { + if (data?.[0]) { + setEcogesture(data[0]) + // Prevent case this key doesn't exist in doctype + setIsObjective(data[0].objective) + setIsDoing(data[0].doing) + const icon = await importIconById(data[0].id, 'ecogesture') + if (subscribed) { + setEcogestureIcon(icon || defaultIcon) + if (currentChallenge?.exploration.ecogesture_id === data[0]._id) { + setValidExploration(currentChallenge.exploration.id) + } + } + } else { + logApp.error(`Could not find ecogesture ${ecogestureID}`) + Sentry.captureException(new Error('Could not find ecogesture')) + } + setIsLoading(false) + } + } + getSingleEcogesture() + + return () => { + subscribed = false + } + }, [ + client, + currentChallenge, + ecogestureID, + ecogestureService, + setValidExploration, + ]) + + return ( + <> + <CozyBar titleKey="common.title_ecogesture" displayBackArrow={true} /> + <Header + setHeaderHeight={setHeaderHeight} + desktopTitleKey="common.title_ecogesture" + displayBackArrow={true} + /> + <Content heightOffset={headerHeight}> + {isLoading && ( + <div className="loaderContainer"> + <Loader /> + </div> + )} + {!isLoading && !ecogesture && ( + <ErrorPage + text={t('error_page.no_ecogesture')} + returnPage="ecogestures" + /> + )} + {!isLoading && ecogesture && ( + <div className="single-ecogesture"> + <div className="icon-container"> + {ecogestureIcon && ( + <StyledIcon + className="icon-big" + icon={ecogestureIcon} + size={220} + /> + )} + </div> + <div className="details"> + <div className="text-22 title">{ecogesture.shortName}</div> + <div className="efficiency"> + <span className="text text-14-normal"> + {t('ecogesture_modal.efficiency')} + </span> + <EfficiencyRating result={Math.round(ecogesture.efficiency)} /> + </div> + </div> + <div className="styled-container"> + <div className="long-name text-18-bold"> + {ecogesture.longName} + </div> + <div + className="showMore text-15-normal" + onClick={() => setShowDetails(prev => !prev)} + role="button" + > + {t(`ecogesture_modal.show_${showDetails ? 'less' : 'more'}`)} + </div> + + <Collapse in={showDetails}> + <div className="longDescription text-16-normal-150"> + {ecogesture.longDescription} + </div> + </Collapse> + </div> + + <div className="buttons-selection"> + <IconButton + aria-label={t('ecogesture.objective')} + onClick={toggleObjective} + classes={{ + root: `btn-secondary-negative objective-btn ${ + isObjective && 'active' + }`, + label: 'text-15-normal', + }} + > + <Icon + className="status-icon" + icon={ + isObjective ? objectiveEnabledIcon : objectiveDisabledIcon + } + size={40} + /> + <span>{t('ecogesture.objective')}</span> + </IconButton> + <IconButton + aria-label={t('ecogesture.doing')} + onClick={toggleDoing} + classes={{ + root: `btn-secondary-negative doing-btn ${ + isDoing && 'active' + }`, + label: 'text-15-normal', + }} + > + <Icon + className="status-icon" + icon={isDoing ? doingEnabledIcon : doingDisabledIcon} + size={40} + /> + <span>{t('ecogesture.doing')}</span> + </IconButton> + </div> + </div> + )} + </Content> + </> + ) +} + +export default SingleEcogestureView diff --git a/src/components/Ecogesture/__snapshots__/EcogestureCard.spec.tsx.snap b/src/components/Ecogesture/__snapshots__/EcogestureCard.spec.tsx.snap deleted file mode 100644 index 0b7982f2b08cbc50e0630f0f786ca712212234d9..0000000000000000000000000000000000000000 --- a/src/components/Ecogesture/__snapshots__/EcogestureCard.spec.tsx.snap +++ /dev/null @@ -1,432 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`EcogestureCard component should be rendered correctly 1`] = ` -<Provider - store={ - Object { - "clearActions": [Function], - "dispatch": [Function], - "getActions": [Function], - "getState": [Function], - "replaceReducer": [Function], - "subscribe": [Function], - } - } -> - <BrowserRouter> - <Router - location={ - Object { - "hash": "", - "key": "default", - "pathname": "/", - "search": "", - "state": null, - } - } - navigationType="POP" - navigator={ - Object { - "action": "POP", - "createHref": [Function], - "encodeLocation": [Function], - "go": [Function], - "listen": [Function], - "location": Object { - "hash": "", - "key": "default", - "pathname": "/", - "search": "", - "state": null, - }, - "push": [Function], - "replace": [Function], - } - } - > - <EcogestureCard - ecogesture={ - Object { - "_id": "ECOGESTURE001", - "_rev": "1-67f1ea36efdd892c96bf64a8943154cd", - "_type": "com.grandlyon.ecolyo.ecogesture", - "action": false, - "actionDuration": 3, - "actionName": null, - "difficulty": 1, - "doing": false, - "efficiency": 4, - "equipment": false, - "equipmentInstallation": true, - "equipmentType": Array [], - "fluidTypes": Array [ - 0, - 2, - ], - "id": "ECOGESTURE001", - "impactLevel": 8, - "investment": null, - "longDescription": "On se demande parfois si cela vaut le coup de \\"couper le chauffage\\" quand on s’absente… dès qu’il s’agit d’un week-end la réponse est « oui sûrement » ! Attention cependant au retour à ne pas faire de la surchauffe ! L’idéal est bien évidemment de régler sa programmation pour que le chauffage se relance quelques heures avant votre retour…", - "longName": "Je baisse le chauffage en mode hors gel lorsque je m'absente plus de 2 jours.", - "objective": false, - "room": Array [ - 0, - ], - "season": "Hiver", - "shortName": "Bonhomme de neige", - "usage": 1, - "viewedInSelection": false, - } - } - > - <WithStyles(ForwardRef(Link)) - className="ecogesture-list-item" - component={ - Object { - "$$typeof": Symbol(react.forward_ref), - "displayName": "Link", - "render": [Function], - } - } - state={ - Object { - "selectionCompleted": false, - } - } - to={ - Object { - "pathname": "/ecogesture/ECOGESTURE001", - } - } - > - <ForwardRef(Link) - className="ecogesture-list-item" - classes={ - Object { - "button": "MuiLink-button", - "focusVisible": "Mui-focusVisible", - "root": "MuiLink-root", - "underlineAlways": "MuiLink-underlineAlways", - "underlineHover": "MuiLink-underlineHover", - "underlineNone": "MuiLink-underlineNone", - } - } - component={ - Object { - "$$typeof": Symbol(react.forward_ref), - "displayName": "Link", - "render": [Function], - } - } - state={ - Object { - "selectionCompleted": false, - } - } - to={ - Object { - "pathname": "/ecogesture/ECOGESTURE001", - } - } - > - <WithStyles(ForwardRef(Typography)) - className="MuiLink-root MuiLink-underlineHover ecogesture-list-item" - color="primary" - component={ - Object { - "$$typeof": Symbol(react.forward_ref), - "displayName": "Link", - "render": [Function], - } - } - onBlur={[Function]} - onFocus={[Function]} - state={ - Object { - "selectionCompleted": false, - } - } - to={ - Object { - "pathname": "/ecogesture/ECOGESTURE001", - } - } - variant="inherit" - > - <ForwardRef(Typography) - className="MuiLink-root MuiLink-underlineHover ecogesture-list-item" - classes={ - Object { - "alignCenter": "MuiTypography-alignCenter", - "alignJustify": "MuiTypography-alignJustify", - "alignLeft": "MuiTypography-alignLeft", - "alignRight": "MuiTypography-alignRight", - "body1": "MuiTypography-body1", - "body2": "MuiTypography-body2", - "button": "MuiTypography-button", - "caption": "MuiTypography-caption", - "colorError": "MuiTypography-colorError", - "colorInherit": "MuiTypography-colorInherit", - "colorPrimary": "MuiTypography-colorPrimary", - "colorSecondary": "MuiTypography-colorSecondary", - "colorTextPrimary": "MuiTypography-colorTextPrimary", - "colorTextSecondary": "MuiTypography-colorTextSecondary", - "displayBlock": "MuiTypography-displayBlock", - "displayInline": "MuiTypography-displayInline", - "gutterBottom": "MuiTypography-gutterBottom", - "h1": "MuiTypography-h1", - "h2": "MuiTypography-h2", - "h3": "MuiTypography-h3", - "h4": "MuiTypography-h4", - "h5": "MuiTypography-h5", - "h6": "MuiTypography-h6", - "noWrap": "MuiTypography-noWrap", - "overline": "MuiTypography-overline", - "paragraph": "MuiTypography-paragraph", - "root": "MuiTypography-root", - "srOnly": "MuiTypography-srOnly", - "subtitle1": "MuiTypography-subtitle1", - "subtitle2": "MuiTypography-subtitle2", - } - } - color="primary" - component={ - Object { - "$$typeof": Symbol(react.forward_ref), - "displayName": "Link", - "render": [Function], - } - } - onBlur={[Function]} - onFocus={[Function]} - state={ - Object { - "selectionCompleted": false, - } - } - to={ - Object { - "pathname": "/ecogesture/ECOGESTURE001", - } - } - variant="inherit" - > - <Link - className="MuiTypography-root MuiLink-root MuiLink-underlineHover ecogesture-list-item MuiTypography-colorPrimary" - onBlur={[Function]} - onFocus={[Function]} - state={ - Object { - "selectionCompleted": false, - } - } - to={ - Object { - "pathname": "/ecogesture/ECOGESTURE001", - } - } - > - <a - className="MuiTypography-root MuiLink-root MuiLink-underlineHover ecogesture-list-item MuiTypography-colorPrimary" - href="/ecogesture/ECOGESTURE001" - onBlur={[Function]} - onClick={[Function]} - onFocus={[Function]} - > - <StyledEcogestureCard> - <WithStyles(WithStyles(ForwardRef(CardActionArea)))> - <WithStyles(ForwardRef(CardActionArea)) - classes={ - Object { - "root": "WithStyles(ForwardRef(CardActionArea))-root-1", - } - } - > - <ForwardRef(CardActionArea) - classes={ - Object { - "focusHighlight": "MuiCardActionArea-focusHighlight", - "focusVisible": "Mui-focusVisible", - "root": "MuiCardActionArea-root WithStyles(ForwardRef(CardActionArea))-root-1", - } - } - > - <WithStyles(ForwardRef(ButtonBase)) - className="MuiCardActionArea-root WithStyles(ForwardRef(CardActionArea))-root-1" - focusVisibleClassName="Mui-focusVisible" - > - <ForwardRef(ButtonBase) - className="MuiCardActionArea-root WithStyles(ForwardRef(CardActionArea))-root-1" - classes={ - Object { - "disabled": "Mui-disabled", - "focusVisible": "Mui-focusVisible", - "root": "MuiButtonBase-root", - } - } - focusVisibleClassName="Mui-focusVisible" - > - <button - className="MuiButtonBase-root MuiCardActionArea-root WithStyles(ForwardRef(CardActionArea))-root-1" - disabled={false} - onBlur={[Function]} - onDragLeave={[Function]} - onFocus={[Function]} - onKeyDown={[Function]} - onKeyUp={[Function]} - onMouseDown={[Function]} - onMouseLeave={[Function]} - onMouseUp={[Function]} - onTouchEnd={[Function]} - onTouchMove={[Function]} - onTouchStart={[Function]} - tabIndex={0} - type="button" - > - <WithStyles(WithStyles(ForwardRef(CardContent)))> - <WithStyles(ForwardRef(CardContent)) - classes={ - Object { - "root": "WithStyles(ForwardRef(CardContent))-root-2", - } - } - > - <ForwardRef(CardContent) - classes={ - Object { - "root": "MuiCardContent-root WithStyles(ForwardRef(CardContent))-root-2", - } - } - > - <div - className="MuiCardContent-root WithStyles(ForwardRef(CardContent))-root-2" - > - <div - className="ec-content" - > - <Component - className="Icon" - icon="" - size={50} - > - <div - id="StyledIcon" - /> - </Component> - <div - className="ec-content-short-name text-15-bold" - > - Bonhomme de neige - </div> - <EfficiencyRating - result={4} - > - <div - className="thunder" - > - <Component - className="star" - icon="test-file-stub" - key="1" - size={15} - > - <div - id="StyledIcon" - /> - </Component> - <Component - className="star" - icon="test-file-stub" - key="2" - size={15} - > - <div - id="StyledIcon" - /> - </Component> - <Component - className="star" - icon="test-file-stub" - key="3" - size={15} - > - <div - id="StyledIcon" - /> - </Component> - <Component - className="star" - icon="test-file-stub" - key="4" - size={15} - > - <div - id="StyledIcon" - /> - </Component> - <Component - className="star" - icon="test-file-stub" - key="5" - size={15} - > - <div - id="StyledIcon" - /> - </Component> - </div> - </EfficiencyRating> - </div> - </div> - </ForwardRef(CardContent)> - </WithStyles(ForwardRef(CardContent))> - </WithStyles(WithStyles(ForwardRef(CardContent)))> - <span - className="MuiCardActionArea-focusHighlight" - /> - <WithStyles(memo) - center={false} - > - <ForwardRef(TouchRipple) - center={false} - classes={ - Object { - "child": "MuiTouchRipple-child", - "childLeaving": "MuiTouchRipple-childLeaving", - "childPulsate": "MuiTouchRipple-childPulsate", - "ripple": "MuiTouchRipple-ripple", - "ripplePulsate": "MuiTouchRipple-ripplePulsate", - "rippleVisible": "MuiTouchRipple-rippleVisible", - "root": "MuiTouchRipple-root", - } - } - > - <span - className="MuiTouchRipple-root" - > - <TransitionGroup - childFactory={[Function]} - component={null} - exit={true} - /> - </span> - </ForwardRef(TouchRipple)> - </WithStyles(memo)> - </button> - </ForwardRef(ButtonBase)> - </WithStyles(ForwardRef(ButtonBase))> - </ForwardRef(CardActionArea)> - </WithStyles(ForwardRef(CardActionArea))> - </WithStyles(WithStyles(ForwardRef(CardActionArea)))> - </StyledEcogestureCard> - </a> - </Link> - </ForwardRef(Typography)> - </WithStyles(ForwardRef(Typography))> - </ForwardRef(Link)> - </WithStyles(ForwardRef(Link))> - </EcogestureCard> - </Router> - </BrowserRouter> -</Provider> -`; diff --git a/src/components/Ecogesture/__snapshots__/EcogestureEmptyList.spec.tsx.snap b/src/components/Ecogesture/__snapshots__/EcogestureEmptyList.spec.tsx.snap deleted file mode 100644 index a97c14eaea5675b7f44b101a8f1dc6b701e1a8e6..0000000000000000000000000000000000000000 --- a/src/components/Ecogesture/__snapshots__/EcogestureEmptyList.spec.tsx.snap +++ /dev/null @@ -1,341 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`EcogestureEmptyList component should be rendered correctly 1`] = ` -<Provider - store={ - Object { - "clearActions": [Function], - "dispatch": [Function], - "getActions": [Function], - "getState": [Function], - "replaceReducer": [Function], - "subscribe": [Function], - } - } -> - <EcogestureEmptyList - handleReinitClick={[MockFunction]} - isObjective={true} - isSelectionDone={false} - setTab={[MockFunction]} - > - <div - className="ec-empty-container" - > - <div - className="ec-empty-content" - > - <StyledIcon - className="icon-big" - icon="test-file-stub" - size={150} - > - <Icon - aria-hidden={true} - className="icon-big" - icon="test-file-stub" - size={150} - spin={false} - > - <Component - aria-hidden={true} - className="icon-big styles__icon___23x3R" - height={150} - style={Object {}} - width={150} - > - <svg - aria-hidden={true} - className="icon-big styles__icon___23x3R" - height={150} - style={Object {}} - width={150} - > - <use - xlinkHref="#test-file-stub" - /> - </svg> - </Component> - </Icon> - </StyledIcon> - <div - className="text-16-normal text" - > - ecogesture.emptyList.obj1 - </div> - <div - className="text-16-normal text" - > - ecogesture.emptyList.obj2 - </div> - <div - className="btn-container" - > - <WithStyles(ForwardRef(Button)) - aria-label="ecogesture.emptyList.btn1" - classes={ - Object { - "label": "text-16-bold", - "root": "btn-secondary-negative btn1", - } - } - onClick={[Function]} - > - <ForwardRef(Button) - aria-label="ecogesture.emptyList.btn1" - classes={ - Object { - "colorInherit": "MuiButton-colorInherit", - "contained": "MuiButton-contained", - "containedPrimary": "MuiButton-containedPrimary", - "containedSecondary": "MuiButton-containedSecondary", - "containedSizeLarge": "MuiButton-containedSizeLarge", - "containedSizeSmall": "MuiButton-containedSizeSmall", - "disableElevation": "MuiButton-disableElevation", - "disabled": "Mui-disabled", - "endIcon": "MuiButton-endIcon", - "focusVisible": "Mui-focusVisible", - "fullWidth": "MuiButton-fullWidth", - "iconSizeLarge": "MuiButton-iconSizeLarge", - "iconSizeMedium": "MuiButton-iconSizeMedium", - "iconSizeSmall": "MuiButton-iconSizeSmall", - "label": "MuiButton-label text-16-bold", - "outlined": "MuiButton-outlined", - "outlinedPrimary": "MuiButton-outlinedPrimary", - "outlinedSecondary": "MuiButton-outlinedSecondary", - "outlinedSizeLarge": "MuiButton-outlinedSizeLarge", - "outlinedSizeSmall": "MuiButton-outlinedSizeSmall", - "root": "MuiButton-root btn-secondary-negative btn1", - "sizeLarge": "MuiButton-sizeLarge", - "sizeSmall": "MuiButton-sizeSmall", - "startIcon": "MuiButton-startIcon", - "text": "MuiButton-text", - "textPrimary": "MuiButton-textPrimary", - "textSecondary": "MuiButton-textSecondary", - "textSizeLarge": "MuiButton-textSizeLarge", - "textSizeSmall": "MuiButton-textSizeSmall", - } - } - onClick={[Function]} - > - <WithStyles(ForwardRef(ButtonBase)) - aria-label="ecogesture.emptyList.btn1" - className="MuiButton-root btn-secondary-negative btn1 MuiButton-text" - component="button" - disabled={false} - focusRipple={true} - focusVisibleClassName="Mui-focusVisible" - onClick={[Function]} - type="button" - > - <ForwardRef(ButtonBase) - aria-label="ecogesture.emptyList.btn1" - className="MuiButton-root btn-secondary-negative btn1 MuiButton-text" - classes={ - Object { - "disabled": "Mui-disabled", - "focusVisible": "Mui-focusVisible", - "root": "MuiButtonBase-root", - } - } - component="button" - disabled={false} - focusRipple={true} - focusVisibleClassName="Mui-focusVisible" - onClick={[Function]} - type="button" - > - <button - aria-label="ecogesture.emptyList.btn1" - className="MuiButtonBase-root MuiButton-root btn-secondary-negative btn1 MuiButton-text" - disabled={false} - onBlur={[Function]} - onClick={[Function]} - onDragLeave={[Function]} - onFocus={[Function]} - onKeyDown={[Function]} - onKeyUp={[Function]} - onMouseDown={[Function]} - onMouseLeave={[Function]} - onMouseUp={[Function]} - onTouchEnd={[Function]} - onTouchMove={[Function]} - onTouchStart={[Function]} - tabIndex={0} - type="button" - > - <span - className="MuiButton-label text-16-bold" - > - ecogesture.emptyList.btn1 - </span> - <WithStyles(memo) - center={false} - > - <ForwardRef(TouchRipple) - center={false} - classes={ - Object { - "child": "MuiTouchRipple-child", - "childLeaving": "MuiTouchRipple-childLeaving", - "childPulsate": "MuiTouchRipple-childPulsate", - "ripple": "MuiTouchRipple-ripple", - "ripplePulsate": "MuiTouchRipple-ripplePulsate", - "rippleVisible": "MuiTouchRipple-rippleVisible", - "root": "MuiTouchRipple-root", - } - } - > - <span - className="MuiTouchRipple-root" - > - <TransitionGroup - childFactory={[Function]} - component={null} - exit={true} - /> - </span> - </ForwardRef(TouchRipple)> - </WithStyles(memo)> - </button> - </ForwardRef(ButtonBase)> - </WithStyles(ForwardRef(ButtonBase))> - </ForwardRef(Button)> - </WithStyles(ForwardRef(Button))> - <WithStyles(ForwardRef(Button)) - aria-label="ecogesture.emptyList.btn2" - classes={ - Object { - "label": "text-16-bold", - "root": "btn-highlight", - } - } - onClick={[Function]} - > - <ForwardRef(Button) - aria-label="ecogesture.emptyList.btn2" - classes={ - Object { - "colorInherit": "MuiButton-colorInherit", - "contained": "MuiButton-contained", - "containedPrimary": "MuiButton-containedPrimary", - "containedSecondary": "MuiButton-containedSecondary", - "containedSizeLarge": "MuiButton-containedSizeLarge", - "containedSizeSmall": "MuiButton-containedSizeSmall", - "disableElevation": "MuiButton-disableElevation", - "disabled": "Mui-disabled", - "endIcon": "MuiButton-endIcon", - "focusVisible": "Mui-focusVisible", - "fullWidth": "MuiButton-fullWidth", - "iconSizeLarge": "MuiButton-iconSizeLarge", - "iconSizeMedium": "MuiButton-iconSizeMedium", - "iconSizeSmall": "MuiButton-iconSizeSmall", - "label": "MuiButton-label text-16-bold", - "outlined": "MuiButton-outlined", - "outlinedPrimary": "MuiButton-outlinedPrimary", - "outlinedSecondary": "MuiButton-outlinedSecondary", - "outlinedSizeLarge": "MuiButton-outlinedSizeLarge", - "outlinedSizeSmall": "MuiButton-outlinedSizeSmall", - "root": "MuiButton-root btn-highlight", - "sizeLarge": "MuiButton-sizeLarge", - "sizeSmall": "MuiButton-sizeSmall", - "startIcon": "MuiButton-startIcon", - "text": "MuiButton-text", - "textPrimary": "MuiButton-textPrimary", - "textSecondary": "MuiButton-textSecondary", - "textSizeLarge": "MuiButton-textSizeLarge", - "textSizeSmall": "MuiButton-textSizeSmall", - } - } - onClick={[Function]} - > - <WithStyles(ForwardRef(ButtonBase)) - aria-label="ecogesture.emptyList.btn2" - className="MuiButton-root btn-highlight MuiButton-text" - component="button" - disabled={false} - focusRipple={true} - focusVisibleClassName="Mui-focusVisible" - onClick={[Function]} - type="button" - > - <ForwardRef(ButtonBase) - aria-label="ecogesture.emptyList.btn2" - className="MuiButton-root btn-highlight MuiButton-text" - classes={ - Object { - "disabled": "Mui-disabled", - "focusVisible": "Mui-focusVisible", - "root": "MuiButtonBase-root", - } - } - component="button" - disabled={false} - focusRipple={true} - focusVisibleClassName="Mui-focusVisible" - onClick={[Function]} - type="button" - > - <button - aria-label="ecogesture.emptyList.btn2" - className="MuiButtonBase-root MuiButton-root btn-highlight MuiButton-text" - disabled={false} - onBlur={[Function]} - onClick={[Function]} - onDragLeave={[Function]} - onFocus={[Function]} - onKeyDown={[Function]} - onKeyUp={[Function]} - onMouseDown={[Function]} - onMouseLeave={[Function]} - onMouseUp={[Function]} - onTouchEnd={[Function]} - onTouchMove={[Function]} - onTouchStart={[Function]} - tabIndex={0} - type="button" - > - <span - className="MuiButton-label text-16-bold" - > - ecogesture.emptyList.btn2 - </span> - <WithStyles(memo) - center={false} - > - <ForwardRef(TouchRipple) - center={false} - classes={ - Object { - "child": "MuiTouchRipple-child", - "childLeaving": "MuiTouchRipple-childLeaving", - "childPulsate": "MuiTouchRipple-childPulsate", - "ripple": "MuiTouchRipple-ripple", - "ripplePulsate": "MuiTouchRipple-ripplePulsate", - "rippleVisible": "MuiTouchRipple-rippleVisible", - "root": "MuiTouchRipple-root", - } - } - > - <span - className="MuiTouchRipple-root" - > - <TransitionGroup - childFactory={[Function]} - component={null} - exit={true} - /> - </span> - </ForwardRef(TouchRipple)> - </WithStyles(memo)> - </button> - </ForwardRef(ButtonBase)> - </WithStyles(ForwardRef(ButtonBase))> - </ForwardRef(Button)> - </WithStyles(ForwardRef(Button))> - </div> - </div> - </div> - </EcogestureEmptyList> -</Provider> -`; diff --git a/src/components/Ecogesture/__snapshots__/EcogestureInitModal.spec.tsx.snap b/src/components/Ecogesture/__snapshots__/EcogestureInitModal.spec.tsx.snap deleted file mode 100644 index ab830dd0628564a7762dc2ba9277159e7ddf21a1..0000000000000000000000000000000000000000 --- a/src/components/Ecogesture/__snapshots__/EcogestureInitModal.spec.tsx.snap +++ /dev/null @@ -1,1143 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`EcogestureInitModal component should be rendered correctly 1`] = ` -<Provider - store={ - Object { - "clearActions": [Function], - "dispatch": [Function], - "getActions": [Function], - "getState": [Function], - "replaceReducer": [Function], - "subscribe": [Function], - } - } -> - <EcogestureInitModal - handleCloseClick={[MockFunction]} - handleLaunchForm={[MockFunction]} - open={true} - > - <WithStyles(ForwardRef(Dialog)) - aria-labelledby="accessibility-title" - classes={ - Object { - "paper": "modal-paper", - "root": "modal-root", - } - } - onClose={[MockFunction]} - open={true} - > - <ForwardRef(Dialog) - aria-labelledby="accessibility-title" - classes={ - Object { - "container": "MuiDialog-container", - "paper": "MuiDialog-paper modal-paper", - "paperFullScreen": "MuiDialog-paperFullScreen", - "paperFullWidth": "MuiDialog-paperFullWidth", - "paperScrollBody": "MuiDialog-paperScrollBody", - "paperScrollPaper": "MuiDialog-paperScrollPaper", - "paperWidthFalse": "MuiDialog-paperWidthFalse", - "paperWidthLg": "MuiDialog-paperWidthLg", - "paperWidthMd": "MuiDialog-paperWidthMd", - "paperWidthSm": "MuiDialog-paperWidthSm", - "paperWidthXl": "MuiDialog-paperWidthXl", - "paperWidthXs": "MuiDialog-paperWidthXs", - "root": "MuiDialog-root modal-root", - "scrollBody": "MuiDialog-scrollBody", - "scrollPaper": "MuiDialog-scrollPaper", - } - } - onClose={[MockFunction]} - open={true} - > - <ForwardRef(Modal) - BackdropComponent={ - Object { - "$$typeof": Symbol(react.forward_ref), - "Naked": Object { - "$$typeof": Symbol(react.forward_ref), - "propTypes": Object { - "children": [Function], - "className": [Function], - "classes": [Function], - "invisible": [Function], - "open": [Function], - "transitionDuration": [Function], - }, - "render": [Function], - }, - "displayName": "WithStyles(ForwardRef(Backdrop))", - "options": Object { - "defaultTheme": Object { - "breakpoints": Object { - "between": [Function], - "down": [Function], - "keys": Array [ - "xs", - "sm", - "md", - "lg", - "xl", - ], - "only": [Function], - "up": [Function], - "values": Object { - "lg": 1280, - "md": 960, - "sm": 600, - "xl": 1920, - "xs": 0, - }, - "width": [Function], - }, - "direction": "ltr", - "mixins": Object { - "gutters": [Function], - "toolbar": Object { - "@media (min-width:0px) and (orientation: landscape)": Object { - "minHeight": 48, - }, - "@media (min-width:600px)": Object { - "minHeight": 64, - }, - "minHeight": 56, - }, - }, - "overrides": Object {}, - "palette": Object { - "action": Object { - "activatedOpacity": 0.12, - "active": "rgba(0, 0, 0, 0.54)", - "disabled": "rgba(0, 0, 0, 0.26)", - "disabledBackground": "rgba(0, 0, 0, 0.12)", - "disabledOpacity": 0.38, - "focus": "rgba(0, 0, 0, 0.12)", - "focusOpacity": 0.12, - "hover": "rgba(0, 0, 0, 0.04)", - "hoverOpacity": 0.04, - "selected": "rgba(0, 0, 0, 0.08)", - "selectedOpacity": 0.08, - }, - "augmentColor": [Function], - "background": Object { - "default": "#fafafa", - "paper": "#fff", - }, - "common": Object { - "black": "#000", - "white": "#fff", - }, - "contrastThreshold": 3, - "divider": "rgba(0, 0, 0, 0.12)", - "error": Object { - "contrastText": "#fff", - "dark": "#d32f2f", - "light": "#e57373", - "main": "#f44336", - }, - "getContrastText": [Function], - "grey": Object { - "100": "#f5f5f5", - "200": "#eeeeee", - "300": "#e0e0e0", - "400": "#bdbdbd", - "50": "#fafafa", - "500": "#9e9e9e", - "600": "#757575", - "700": "#616161", - "800": "#424242", - "900": "#212121", - "A100": "#d5d5d5", - "A200": "#aaaaaa", - "A400": "#303030", - "A700": "#616161", - }, - "info": Object { - "contrastText": "#fff", - "dark": "#1976d2", - "light": "#64b5f6", - "main": "#2196f3", - }, - "primary": Object { - "contrastText": "#fff", - "dark": "#303f9f", - "light": "#7986cb", - "main": "#3f51b5", - }, - "secondary": Object { - "contrastText": "#fff", - "dark": "#c51162", - "light": "#ff4081", - "main": "#f50057", - }, - "success": Object { - "contrastText": "rgba(0, 0, 0, 0.87)", - "dark": "#388e3c", - "light": "#81c784", - "main": "#4caf50", - }, - "text": Object { - "disabled": "rgba(0, 0, 0, 0.38)", - "hint": "rgba(0, 0, 0, 0.38)", - "primary": "rgba(0, 0, 0, 0.87)", - "secondary": "rgba(0, 0, 0, 0.54)", - }, - "tonalOffset": 0.2, - "type": "light", - "warning": Object { - "contrastText": "rgba(0, 0, 0, 0.87)", - "dark": "#f57c00", - "light": "#ffb74d", - "main": "#ff9800", - }, - }, - "props": Object {}, - "shadows": Array [ - "none", - "0px 2px 1px -1px rgba(0,0,0,0.2),0px 1px 1px 0px rgba(0,0,0,0.14),0px 1px 3px 0px rgba(0,0,0,0.12)", - "0px 3px 1px -2px rgba(0,0,0,0.2),0px 2px 2px 0px rgba(0,0,0,0.14),0px 1px 5px 0px rgba(0,0,0,0.12)", - "0px 3px 3px -2px rgba(0,0,0,0.2),0px 3px 4px 0px rgba(0,0,0,0.14),0px 1px 8px 0px rgba(0,0,0,0.12)", - "0px 2px 4px -1px rgba(0,0,0,0.2),0px 4px 5px 0px rgba(0,0,0,0.14),0px 1px 10px 0px rgba(0,0,0,0.12)", - "0px 3px 5px -1px rgba(0,0,0,0.2),0px 5px 8px 0px rgba(0,0,0,0.14),0px 1px 14px 0px rgba(0,0,0,0.12)", - "0px 3px 5px -1px rgba(0,0,0,0.2),0px 6px 10px 0px rgba(0,0,0,0.14),0px 1px 18px 0px rgba(0,0,0,0.12)", - "0px 4px 5px -2px rgba(0,0,0,0.2),0px 7px 10px 1px rgba(0,0,0,0.14),0px 2px 16px 1px rgba(0,0,0,0.12)", - "0px 5px 5px -3px rgba(0,0,0,0.2),0px 8px 10px 1px rgba(0,0,0,0.14),0px 3px 14px 2px rgba(0,0,0,0.12)", - "0px 5px 6px -3px rgba(0,0,0,0.2),0px 9px 12px 1px rgba(0,0,0,0.14),0px 3px 16px 2px rgba(0,0,0,0.12)", - "0px 6px 6px -3px rgba(0,0,0,0.2),0px 10px 14px 1px rgba(0,0,0,0.14),0px 4px 18px 3px rgba(0,0,0,0.12)", - "0px 6px 7px -4px rgba(0,0,0,0.2),0px 11px 15px 1px rgba(0,0,0,0.14),0px 4px 20px 3px rgba(0,0,0,0.12)", - "0px 7px 8px -4px rgba(0,0,0,0.2),0px 12px 17px 2px rgba(0,0,0,0.14),0px 5px 22px 4px rgba(0,0,0,0.12)", - "0px 7px 8px -4px rgba(0,0,0,0.2),0px 13px 19px 2px rgba(0,0,0,0.14),0px 5px 24px 4px rgba(0,0,0,0.12)", - "0px 7px 9px -4px rgba(0,0,0,0.2),0px 14px 21px 2px rgba(0,0,0,0.14),0px 5px 26px 4px rgba(0,0,0,0.12)", - "0px 8px 9px -5px rgba(0,0,0,0.2),0px 15px 22px 2px rgba(0,0,0,0.14),0px 6px 28px 5px rgba(0,0,0,0.12)", - "0px 8px 10px -5px rgba(0,0,0,0.2),0px 16px 24px 2px rgba(0,0,0,0.14),0px 6px 30px 5px rgba(0,0,0,0.12)", - "0px 8px 11px -5px rgba(0,0,0,0.2),0px 17px 26px 2px rgba(0,0,0,0.14),0px 6px 32px 5px rgba(0,0,0,0.12)", - "0px 9px 11px -5px rgba(0,0,0,0.2),0px 18px 28px 2px rgba(0,0,0,0.14),0px 7px 34px 6px rgba(0,0,0,0.12)", - "0px 9px 12px -6px rgba(0,0,0,0.2),0px 19px 29px 2px rgba(0,0,0,0.14),0px 7px 36px 6px rgba(0,0,0,0.12)", - "0px 10px 13px -6px rgba(0,0,0,0.2),0px 20px 31px 3px rgba(0,0,0,0.14),0px 8px 38px 7px rgba(0,0,0,0.12)", - "0px 10px 13px -6px rgba(0,0,0,0.2),0px 21px 33px 3px rgba(0,0,0,0.14),0px 8px 40px 7px rgba(0,0,0,0.12)", - "0px 10px 14px -6px rgba(0,0,0,0.2),0px 22px 35px 3px rgba(0,0,0,0.14),0px 8px 42px 7px rgba(0,0,0,0.12)", - "0px 11px 14px -7px rgba(0,0,0,0.2),0px 23px 36px 3px rgba(0,0,0,0.14),0px 9px 44px 8px rgba(0,0,0,0.12)", - "0px 11px 15px -7px rgba(0,0,0,0.2),0px 24px 38px 3px rgba(0,0,0,0.14),0px 9px 46px 8px rgba(0,0,0,0.12)", - ], - "shape": Object { - "borderRadius": 4, - }, - "spacing": [Function], - "transitions": Object { - "create": [Function], - "duration": Object { - "complex": 375, - "enteringScreen": 225, - "leavingScreen": 195, - "short": 250, - "shorter": 200, - "shortest": 150, - "standard": 300, - }, - "easing": Object { - "easeIn": "cubic-bezier(0.4, 0, 1, 1)", - "easeInOut": "cubic-bezier(0.4, 0, 0.2, 1)", - "easeOut": "cubic-bezier(0.0, 0, 0.2, 1)", - "sharp": "cubic-bezier(0.4, 0, 0.6, 1)", - }, - "getAutoHeightDuration": [Function], - }, - "typography": Object { - "body1": Object { - "fontFamily": "\\"Roboto\\", \\"Helvetica\\", \\"Arial\\", sans-serif", - "fontSize": "1rem", - "fontWeight": 400, - "letterSpacing": "0.00938em", - "lineHeight": 1.5, - }, - "body2": Object { - "fontFamily": "\\"Roboto\\", \\"Helvetica\\", \\"Arial\\", sans-serif", - "fontSize": "0.875rem", - "fontWeight": 400, - "letterSpacing": "0.01071em", - "lineHeight": 1.43, - }, - "button": Object { - "fontFamily": "\\"Roboto\\", \\"Helvetica\\", \\"Arial\\", sans-serif", - "fontSize": "0.875rem", - "fontWeight": 500, - "letterSpacing": "0.02857em", - "lineHeight": 1.75, - "textTransform": "uppercase", - }, - "caption": Object { - "fontFamily": "\\"Roboto\\", \\"Helvetica\\", \\"Arial\\", sans-serif", - "fontSize": "0.75rem", - "fontWeight": 400, - "letterSpacing": "0.03333em", - "lineHeight": 1.66, - }, - "fontFamily": "\\"Roboto\\", \\"Helvetica\\", \\"Arial\\", sans-serif", - "fontSize": 14, - "fontWeightBold": 700, - "fontWeightLight": 300, - "fontWeightMedium": 500, - "fontWeightRegular": 400, - "h1": Object { - "fontFamily": "\\"Roboto\\", \\"Helvetica\\", \\"Arial\\", sans-serif", - "fontSize": "6rem", - "fontWeight": 300, - "letterSpacing": "-0.01562em", - "lineHeight": 1.167, - }, - "h2": Object { - "fontFamily": "\\"Roboto\\", \\"Helvetica\\", \\"Arial\\", sans-serif", - "fontSize": "3.75rem", - "fontWeight": 300, - "letterSpacing": "-0.00833em", - "lineHeight": 1.2, - }, - "h3": Object { - "fontFamily": "\\"Roboto\\", \\"Helvetica\\", \\"Arial\\", sans-serif", - "fontSize": "3rem", - "fontWeight": 400, - "letterSpacing": "0em", - "lineHeight": 1.167, - }, - "h4": Object { - "fontFamily": "\\"Roboto\\", \\"Helvetica\\", \\"Arial\\", sans-serif", - "fontSize": "2.125rem", - "fontWeight": 400, - "letterSpacing": "0.00735em", - "lineHeight": 1.235, - }, - "h5": Object { - "fontFamily": "\\"Roboto\\", \\"Helvetica\\", \\"Arial\\", sans-serif", - "fontSize": "1.5rem", - "fontWeight": 400, - "letterSpacing": "0em", - "lineHeight": 1.334, - }, - "h6": Object { - "fontFamily": "\\"Roboto\\", \\"Helvetica\\", \\"Arial\\", sans-serif", - "fontSize": "1.25rem", - "fontWeight": 500, - "letterSpacing": "0.0075em", - "lineHeight": 1.6, - }, - "htmlFontSize": 16, - "overline": Object { - "fontFamily": "\\"Roboto\\", \\"Helvetica\\", \\"Arial\\", sans-serif", - "fontSize": "0.75rem", - "fontWeight": 400, - "letterSpacing": "0.08333em", - "lineHeight": 2.66, - "textTransform": "uppercase", - }, - "pxToRem": [Function], - "round": [Function], - "subtitle1": Object { - "fontFamily": "\\"Roboto\\", \\"Helvetica\\", \\"Arial\\", sans-serif", - "fontSize": "1rem", - "fontWeight": 400, - "letterSpacing": "0.00938em", - "lineHeight": 1.75, - }, - "subtitle2": Object { - "fontFamily": "\\"Roboto\\", \\"Helvetica\\", \\"Arial\\", sans-serif", - "fontSize": "0.875rem", - "fontWeight": 500, - "letterSpacing": "0.00714em", - "lineHeight": 1.57, - }, - }, - "zIndex": Object { - "appBar": 1100, - "drawer": 1200, - "mobileStepper": 1000, - "modal": 1300, - "snackbar": 1400, - "speedDial": 1050, - "tooltip": 1500, - }, - }, - "name": "MuiBackdrop", - }, - "propTypes": Object { - "classes": [Function], - "innerRef": [Function], - }, - "render": [Function], - "useStyles": [Function], - } - } - BackdropProps={ - Object { - "transitionDuration": Object { - "enter": 225, - "exit": 195, - }, - } - } - className="MuiDialog-root modal-root" - closeAfterTransition={true} - disableEscapeKeyDown={false} - onClose={[MockFunction]} - open={true} - > - <ForwardRef(Portal) - disablePortal={false} - > - <Portal - containerInfo={ - <body - style="padding-right: 0px; overflow: hidden;" - > - <div - class="MuiDialog-root modal-root" - role="presentation" - style="position: fixed; z-index: 1300; right: 0px; bottom: 0px; top: 0px; left: 0px;" - > - <div - aria-hidden="true" - class="MuiBackdrop-root" - style="opacity: 1; webkit-transition: opacity 225ms cubic-bezier(0.4, 0, 0.2, 1) 0ms; transition: opacity 225ms cubic-bezier(0.4, 0, 0.2, 1) 0ms;" - /> - <div - data-test="sentinelStart" - tabindex="0" - /> - <div - class="MuiDialog-container MuiDialog-scrollPaper" - role="none presentation" - style="opacity: 1; webkit-transition: opacity 225ms cubic-bezier(0.4, 0, 0.2, 1) 0ms; transition: opacity 225ms cubic-bezier(0.4, 0, 0.2, 1) 0ms;" - tabindex="-1" - > - <div - aria-labelledby="accessibility-title" - class="MuiPaper-root MuiDialog-paper modal-paper MuiDialog-paperScrollPaper MuiDialog-paperWidthSm MuiPaper-elevation24 MuiPaper-rounded" - role="dialog" - > - <div - id="accessibility-title" - > - feedback.accessibility.window_title - </div> - <button - aria-label="feedback.accessibility.button_close" - class="MuiButtonBase-root MuiIconButton-root modal-paper-close-button" - tabindex="0" - type="button" - > - <span - class="MuiIconButton-label" - > - <svg - class="styles__icon___23x3R" - height="16" - width="16" - > - <use - xlink:href="#test-file-stub" - /> - </svg> - </span> - <span - class="MuiTouchRipple-root" - /> - </button> - <div - class="eg-init-modal" - > - <div - class="title text-20-bold" - > - ecogesture.initModal.title - </div> - <div - class="text-16-normal text" - > - ecogesture.initModal.text1 - </div> - <div - class="text-16-normal text" - > - ecogesture.initModal.text2 - </div> - <div - class="buttons-container" - > - <button - aria-label="ecogesture.initModal.btn1" - class="MuiButtonBase-root MuiButton-root btn-secondary-negative MuiButton-text btn1" - tabindex="0" - type="button" - > - <span - class="MuiButton-label text-16-bold" - > - ecogesture.initModal.btn1 - </span> - <span - class="MuiTouchRipple-root" - /> - </button> - <button - aria-label="ecogesture.initModal.btn2" - class="MuiButtonBase-root MuiButton-root btn-profile-next rounded MuiButton-text" - tabindex="0" - type="button" - > - <span - class="MuiButton-label text-16-bold" - > - ecogesture.initModal.btn2 - </span> - <span - class="MuiTouchRipple-root" - /> - </button> - </div> - </div> - </div> - </div> - <div - data-test="sentinelEnd" - tabindex="0" - /> - </div> - </body> - } - > - <div - className="MuiDialog-root modal-root" - onKeyDown={[Function]} - role="presentation" - style={ - Object { - "bottom": 0, - "left": 0, - "position": "fixed", - "right": 0, - "top": 0, - "zIndex": 1300, - } - } - > - <WithStyles(ForwardRef(Backdrop)) - onClick={[Function]} - open={true} - transitionDuration={ - Object { - "enter": 225, - "exit": 195, - } - } - > - <ForwardRef(Backdrop) - classes={ - Object { - "invisible": "MuiBackdrop-invisible", - "root": "MuiBackdrop-root", - } - } - onClick={[Function]} - open={true} - transitionDuration={ - Object { - "enter": 225, - "exit": 195, - } - } - > - <ForwardRef(Fade) - in={true} - onClick={[Function]} - timeout={ - Object { - "enter": 225, - "exit": 195, - } - } - > - <Transition - appear={true} - enter={true} - exit={true} - in={true} - mountOnEnter={false} - onClick={[Function]} - onEnter={[Function]} - onEntered={[Function]} - onEntering={[Function]} - onExit={[Function]} - onExited={[Function]} - onExiting={[Function]} - timeout={ - Object { - "enter": 225, - "exit": 195, - } - } - unmountOnExit={false} - > - <div - aria-hidden={true} - className="MuiBackdrop-root" - onClick={[Function]} - style={ - Object { - "opacity": 1, - "visibility": undefined, - } - } - /> - </Transition> - </ForwardRef(Fade)> - </ForwardRef(Backdrop)> - </WithStyles(ForwardRef(Backdrop))> - <Unstable_TrapFocus - disableAutoFocus={false} - disableEnforceFocus={false} - disableRestoreFocus={false} - getDoc={[Function]} - isEnabled={[Function]} - open={true} - > - <div - data-test="sentinelStart" - tabIndex={0} - /> - <ForwardRef(Fade) - appear={true} - in={true} - onEnter={[Function]} - onExited={[Function]} - role="none presentation" - tabIndex="-1" - timeout={ - Object { - "enter": 225, - "exit": 195, - } - } - > - <Transition - appear={true} - enter={true} - exit={true} - in={true} - mountOnEnter={false} - onEnter={[Function]} - onEntered={[Function]} - onEntering={[Function]} - onExit={[Function]} - onExited={[Function]} - onExiting={[Function]} - role="none presentation" - tabIndex="-1" - timeout={ - Object { - "enter": 225, - "exit": 195, - } - } - unmountOnExit={false} - > - <div - className="MuiDialog-container MuiDialog-scrollPaper" - onMouseDown={[Function]} - onMouseUp={[Function]} - role="none presentation" - style={ - Object { - "opacity": 1, - "visibility": undefined, - } - } - tabIndex="-1" - > - <WithStyles(ForwardRef(Paper)) - aria-labelledby="accessibility-title" - className="MuiDialog-paper modal-paper MuiDialog-paperScrollPaper MuiDialog-paperWidthSm" - elevation={24} - role="dialog" - > - <ForwardRef(Paper) - aria-labelledby="accessibility-title" - className="MuiDialog-paper modal-paper MuiDialog-paperScrollPaper MuiDialog-paperWidthSm" - classes={ - Object { - "elevation0": "MuiPaper-elevation0", - "elevation1": "MuiPaper-elevation1", - "elevation10": "MuiPaper-elevation10", - "elevation11": "MuiPaper-elevation11", - "elevation12": "MuiPaper-elevation12", - "elevation13": "MuiPaper-elevation13", - "elevation14": "MuiPaper-elevation14", - "elevation15": "MuiPaper-elevation15", - "elevation16": "MuiPaper-elevation16", - "elevation17": "MuiPaper-elevation17", - "elevation18": "MuiPaper-elevation18", - "elevation19": "MuiPaper-elevation19", - "elevation2": "MuiPaper-elevation2", - "elevation20": "MuiPaper-elevation20", - "elevation21": "MuiPaper-elevation21", - "elevation22": "MuiPaper-elevation22", - "elevation23": "MuiPaper-elevation23", - "elevation24": "MuiPaper-elevation24", - "elevation3": "MuiPaper-elevation3", - "elevation4": "MuiPaper-elevation4", - "elevation5": "MuiPaper-elevation5", - "elevation6": "MuiPaper-elevation6", - "elevation7": "MuiPaper-elevation7", - "elevation8": "MuiPaper-elevation8", - "elevation9": "MuiPaper-elevation9", - "outlined": "MuiPaper-outlined", - "root": "MuiPaper-root", - "rounded": "MuiPaper-rounded", - } - } - elevation={24} - role="dialog" - > - <div - aria-labelledby="accessibility-title" - className="MuiPaper-root MuiDialog-paper modal-paper MuiDialog-paperScrollPaper MuiDialog-paperWidthSm MuiPaper-elevation24 MuiPaper-rounded" - role="dialog" - > - <div - id="accessibility-title" - > - feedback.accessibility.window_title - </div> - <WithStyles(ForwardRef(IconButton)) - aria-label="feedback.accessibility.button_close" - className="modal-paper-close-button" - onClick={[MockFunction]} - > - <ForwardRef(IconButton) - aria-label="feedback.accessibility.button_close" - className="modal-paper-close-button" - classes={ - Object { - "colorInherit": "MuiIconButton-colorInherit", - "colorPrimary": "MuiIconButton-colorPrimary", - "colorSecondary": "MuiIconButton-colorSecondary", - "disabled": "Mui-disabled", - "edgeEnd": "MuiIconButton-edgeEnd", - "edgeStart": "MuiIconButton-edgeStart", - "label": "MuiIconButton-label", - "root": "MuiIconButton-root", - "sizeSmall": "MuiIconButton-sizeSmall", - } - } - onClick={[MockFunction]} - > - <WithStyles(ForwardRef(ButtonBase)) - aria-label="feedback.accessibility.button_close" - centerRipple={true} - className="MuiIconButton-root modal-paper-close-button" - disabled={false} - focusRipple={true} - onClick={[MockFunction]} - > - <ForwardRef(ButtonBase) - aria-label="feedback.accessibility.button_close" - centerRipple={true} - className="MuiIconButton-root modal-paper-close-button" - classes={ - Object { - "disabled": "Mui-disabled", - "focusVisible": "Mui-focusVisible", - "root": "MuiButtonBase-root", - } - } - disabled={false} - focusRipple={true} - onClick={[MockFunction]} - > - <button - aria-label="feedback.accessibility.button_close" - className="MuiButtonBase-root MuiIconButton-root modal-paper-close-button" - disabled={false} - onBlur={[Function]} - onClick={[MockFunction]} - onDragLeave={[Function]} - onFocus={[Function]} - onKeyDown={[Function]} - onKeyUp={[Function]} - onMouseDown={[Function]} - onMouseLeave={[Function]} - onMouseUp={[Function]} - onTouchEnd={[Function]} - onTouchMove={[Function]} - onTouchStart={[Function]} - tabIndex={0} - type="button" - > - <span - className="MuiIconButton-label" - > - <Icon - icon="test-file-stub" - size={16} - spin={false} - > - <Component - className="styles__icon___23x3R" - height={16} - style={Object {}} - width={16} - > - <svg - className="styles__icon___23x3R" - height={16} - style={Object {}} - width={16} - > - <use - xlinkHref="#test-file-stub" - /> - </svg> - </Component> - </Icon> - </span> - <WithStyles(memo) - center={true} - > - <ForwardRef(TouchRipple) - center={true} - classes={ - Object { - "child": "MuiTouchRipple-child", - "childLeaving": "MuiTouchRipple-childLeaving", - "childPulsate": "MuiTouchRipple-childPulsate", - "ripple": "MuiTouchRipple-ripple", - "ripplePulsate": "MuiTouchRipple-ripplePulsate", - "rippleVisible": "MuiTouchRipple-rippleVisible", - "root": "MuiTouchRipple-root", - } - } - > - <span - className="MuiTouchRipple-root" - > - <TransitionGroup - childFactory={[Function]} - component={null} - exit={true} - /> - </span> - </ForwardRef(TouchRipple)> - </WithStyles(memo)> - </button> - </ForwardRef(ButtonBase)> - </WithStyles(ForwardRef(ButtonBase))> - </ForwardRef(IconButton)> - </WithStyles(ForwardRef(IconButton))> - <div - className="eg-init-modal" - > - <div - className="title text-20-bold" - > - ecogesture.initModal.title - </div> - <div - className="text-16-normal text" - > - ecogesture.initModal.text1 - </div> - <div - className="text-16-normal text" - > - ecogesture.initModal.text2 - </div> - <div - className="buttons-container" - > - <WithStyles(ForwardRef(Button)) - aria-label="ecogesture.initModal.btn1" - className="btn1" - classes={ - Object { - "label": "text-16-bold", - "root": "btn-secondary-negative", - } - } - onClick={[MockFunction]} - > - <ForwardRef(Button) - aria-label="ecogesture.initModal.btn1" - className="btn1" - classes={ - Object { - "colorInherit": "MuiButton-colorInherit", - "contained": "MuiButton-contained", - "containedPrimary": "MuiButton-containedPrimary", - "containedSecondary": "MuiButton-containedSecondary", - "containedSizeLarge": "MuiButton-containedSizeLarge", - "containedSizeSmall": "MuiButton-containedSizeSmall", - "disableElevation": "MuiButton-disableElevation", - "disabled": "Mui-disabled", - "endIcon": "MuiButton-endIcon", - "focusVisible": "Mui-focusVisible", - "fullWidth": "MuiButton-fullWidth", - "iconSizeLarge": "MuiButton-iconSizeLarge", - "iconSizeMedium": "MuiButton-iconSizeMedium", - "iconSizeSmall": "MuiButton-iconSizeSmall", - "label": "MuiButton-label text-16-bold", - "outlined": "MuiButton-outlined", - "outlinedPrimary": "MuiButton-outlinedPrimary", - "outlinedSecondary": "MuiButton-outlinedSecondary", - "outlinedSizeLarge": "MuiButton-outlinedSizeLarge", - "outlinedSizeSmall": "MuiButton-outlinedSizeSmall", - "root": "MuiButton-root btn-secondary-negative", - "sizeLarge": "MuiButton-sizeLarge", - "sizeSmall": "MuiButton-sizeSmall", - "startIcon": "MuiButton-startIcon", - "text": "MuiButton-text", - "textPrimary": "MuiButton-textPrimary", - "textSecondary": "MuiButton-textSecondary", - "textSizeLarge": "MuiButton-textSizeLarge", - "textSizeSmall": "MuiButton-textSizeSmall", - } - } - onClick={[MockFunction]} - > - <WithStyles(ForwardRef(ButtonBase)) - aria-label="ecogesture.initModal.btn1" - className="MuiButton-root btn-secondary-negative MuiButton-text btn1" - component="button" - disabled={false} - focusRipple={true} - focusVisibleClassName="Mui-focusVisible" - onClick={[MockFunction]} - type="button" - > - <ForwardRef(ButtonBase) - aria-label="ecogesture.initModal.btn1" - className="MuiButton-root btn-secondary-negative MuiButton-text btn1" - classes={ - Object { - "disabled": "Mui-disabled", - "focusVisible": "Mui-focusVisible", - "root": "MuiButtonBase-root", - } - } - component="button" - disabled={false} - focusRipple={true} - focusVisibleClassName="Mui-focusVisible" - onClick={[MockFunction]} - type="button" - > - <button - aria-label="ecogesture.initModal.btn1" - className="MuiButtonBase-root MuiButton-root btn-secondary-negative MuiButton-text btn1" - disabled={false} - onBlur={[Function]} - onClick={[MockFunction]} - onDragLeave={[Function]} - onFocus={[Function]} - onKeyDown={[Function]} - onKeyUp={[Function]} - onMouseDown={[Function]} - onMouseLeave={[Function]} - onMouseUp={[Function]} - onTouchEnd={[Function]} - onTouchMove={[Function]} - onTouchStart={[Function]} - tabIndex={0} - type="button" - > - <span - className="MuiButton-label text-16-bold" - > - ecogesture.initModal.btn1 - </span> - <WithStyles(memo) - center={false} - > - <ForwardRef(TouchRipple) - center={false} - classes={ - Object { - "child": "MuiTouchRipple-child", - "childLeaving": "MuiTouchRipple-childLeaving", - "childPulsate": "MuiTouchRipple-childPulsate", - "ripple": "MuiTouchRipple-ripple", - "ripplePulsate": "MuiTouchRipple-ripplePulsate", - "rippleVisible": "MuiTouchRipple-rippleVisible", - "root": "MuiTouchRipple-root", - } - } - > - <span - className="MuiTouchRipple-root" - > - <TransitionGroup - childFactory={[Function]} - component={null} - exit={true} - /> - </span> - </ForwardRef(TouchRipple)> - </WithStyles(memo)> - </button> - </ForwardRef(ButtonBase)> - </WithStyles(ForwardRef(ButtonBase))> - </ForwardRef(Button)> - </WithStyles(ForwardRef(Button))> - <WithStyles(ForwardRef(Button)) - aria-label="ecogesture.initModal.btn2" - classes={ - Object { - "label": "text-16-bold", - "root": "btn-profile-next rounded", - } - } - onClick={[MockFunction]} - > - <ForwardRef(Button) - aria-label="ecogesture.initModal.btn2" - classes={ - Object { - "colorInherit": "MuiButton-colorInherit", - "contained": "MuiButton-contained", - "containedPrimary": "MuiButton-containedPrimary", - "containedSecondary": "MuiButton-containedSecondary", - "containedSizeLarge": "MuiButton-containedSizeLarge", - "containedSizeSmall": "MuiButton-containedSizeSmall", - "disableElevation": "MuiButton-disableElevation", - "disabled": "Mui-disabled", - "endIcon": "MuiButton-endIcon", - "focusVisible": "Mui-focusVisible", - "fullWidth": "MuiButton-fullWidth", - "iconSizeLarge": "MuiButton-iconSizeLarge", - "iconSizeMedium": "MuiButton-iconSizeMedium", - "iconSizeSmall": "MuiButton-iconSizeSmall", - "label": "MuiButton-label text-16-bold", - "outlined": "MuiButton-outlined", - "outlinedPrimary": "MuiButton-outlinedPrimary", - "outlinedSecondary": "MuiButton-outlinedSecondary", - "outlinedSizeLarge": "MuiButton-outlinedSizeLarge", - "outlinedSizeSmall": "MuiButton-outlinedSizeSmall", - "root": "MuiButton-root btn-profile-next rounded", - "sizeLarge": "MuiButton-sizeLarge", - "sizeSmall": "MuiButton-sizeSmall", - "startIcon": "MuiButton-startIcon", - "text": "MuiButton-text", - "textPrimary": "MuiButton-textPrimary", - "textSecondary": "MuiButton-textSecondary", - "textSizeLarge": "MuiButton-textSizeLarge", - "textSizeSmall": "MuiButton-textSizeSmall", - } - } - onClick={[MockFunction]} - > - <WithStyles(ForwardRef(ButtonBase)) - aria-label="ecogesture.initModal.btn2" - className="MuiButton-root btn-profile-next rounded MuiButton-text" - component="button" - disabled={false} - focusRipple={true} - focusVisibleClassName="Mui-focusVisible" - onClick={[MockFunction]} - type="button" - > - <ForwardRef(ButtonBase) - aria-label="ecogesture.initModal.btn2" - className="MuiButton-root btn-profile-next rounded MuiButton-text" - classes={ - Object { - "disabled": "Mui-disabled", - "focusVisible": "Mui-focusVisible", - "root": "MuiButtonBase-root", - } - } - component="button" - disabled={false} - focusRipple={true} - focusVisibleClassName="Mui-focusVisible" - onClick={[MockFunction]} - type="button" - > - <button - aria-label="ecogesture.initModal.btn2" - className="MuiButtonBase-root MuiButton-root btn-profile-next rounded MuiButton-text" - disabled={false} - onBlur={[Function]} - onClick={[MockFunction]} - onDragLeave={[Function]} - onFocus={[Function]} - onKeyDown={[Function]} - onKeyUp={[Function]} - onMouseDown={[Function]} - onMouseLeave={[Function]} - onMouseUp={[Function]} - onTouchEnd={[Function]} - onTouchMove={[Function]} - onTouchStart={[Function]} - tabIndex={0} - type="button" - > - <span - className="MuiButton-label text-16-bold" - > - ecogesture.initModal.btn2 - </span> - <WithStyles(memo) - center={false} - > - <ForwardRef(TouchRipple) - center={false} - classes={ - Object { - "child": "MuiTouchRipple-child", - "childLeaving": "MuiTouchRipple-childLeaving", - "childPulsate": "MuiTouchRipple-childPulsate", - "ripple": "MuiTouchRipple-ripple", - "ripplePulsate": "MuiTouchRipple-ripplePulsate", - "rippleVisible": "MuiTouchRipple-rippleVisible", - "root": "MuiTouchRipple-root", - } - } - > - <span - className="MuiTouchRipple-root" - > - <TransitionGroup - childFactory={[Function]} - component={null} - exit={true} - /> - </span> - </ForwardRef(TouchRipple)> - </WithStyles(memo)> - </button> - </ForwardRef(ButtonBase)> - </WithStyles(ForwardRef(ButtonBase))> - </ForwardRef(Button)> - </WithStyles(ForwardRef(Button))> - </div> - </div> - </div> - </ForwardRef(Paper)> - </WithStyles(ForwardRef(Paper))> - </div> - </Transition> - </ForwardRef(Fade)> - <div - data-test="sentinelEnd" - tabIndex={0} - /> - </Unstable_TrapFocus> - </div> - </Portal> - </ForwardRef(Portal)> - </ForwardRef(Modal)> - </ForwardRef(Dialog)> - </WithStyles(ForwardRef(Dialog))> - </EcogestureInitModal> -</Provider> -`; diff --git a/src/components/Ecogesture/__snapshots__/EcogestureReinitModal.spec.tsx.snap b/src/components/Ecogesture/__snapshots__/EcogestureReinitModal.spec.tsx.snap deleted file mode 100644 index 9539b429090cbf3829daebb4201acf11754c729b..0000000000000000000000000000000000000000 --- a/src/components/Ecogesture/__snapshots__/EcogestureReinitModal.spec.tsx.snap +++ /dev/null @@ -1,1209 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`EcogestureReinitModal component should be rendered correctly 1`] = ` -<Provider - store={ - Object { - "clearActions": [Function], - "dispatch": [Function], - "getActions": [Function], - "getState": [Function], - "replaceReducer": [Function], - "subscribe": [Function], - } - } -> - <EcogestureReinitModal - handleCloseClick={[MockFunction]} - handleLaunchReinit={[MockFunction]} - open={true} - > - <WithStyles(ForwardRef(Dialog)) - aria-labelledby="accessibility-title" - classes={ - Object { - "paper": "modal-paper", - "root": "modal-root", - } - } - onClose={[MockFunction]} - open={true} - > - <ForwardRef(Dialog) - aria-labelledby="accessibility-title" - classes={ - Object { - "container": "MuiDialog-container", - "paper": "MuiDialog-paper modal-paper", - "paperFullScreen": "MuiDialog-paperFullScreen", - "paperFullWidth": "MuiDialog-paperFullWidth", - "paperScrollBody": "MuiDialog-paperScrollBody", - "paperScrollPaper": "MuiDialog-paperScrollPaper", - "paperWidthFalse": "MuiDialog-paperWidthFalse", - "paperWidthLg": "MuiDialog-paperWidthLg", - "paperWidthMd": "MuiDialog-paperWidthMd", - "paperWidthSm": "MuiDialog-paperWidthSm", - "paperWidthXl": "MuiDialog-paperWidthXl", - "paperWidthXs": "MuiDialog-paperWidthXs", - "root": "MuiDialog-root modal-root", - "scrollBody": "MuiDialog-scrollBody", - "scrollPaper": "MuiDialog-scrollPaper", - } - } - onClose={[MockFunction]} - open={true} - > - <ForwardRef(Modal) - BackdropComponent={ - Object { - "$$typeof": Symbol(react.forward_ref), - "Naked": Object { - "$$typeof": Symbol(react.forward_ref), - "propTypes": Object { - "children": [Function], - "className": [Function], - "classes": [Function], - "invisible": [Function], - "open": [Function], - "transitionDuration": [Function], - }, - "render": [Function], - }, - "displayName": "WithStyles(ForwardRef(Backdrop))", - "options": Object { - "defaultTheme": Object { - "breakpoints": Object { - "between": [Function], - "down": [Function], - "keys": Array [ - "xs", - "sm", - "md", - "lg", - "xl", - ], - "only": [Function], - "up": [Function], - "values": Object { - "lg": 1280, - "md": 960, - "sm": 600, - "xl": 1920, - "xs": 0, - }, - "width": [Function], - }, - "direction": "ltr", - "mixins": Object { - "gutters": [Function], - "toolbar": Object { - "@media (min-width:0px) and (orientation: landscape)": Object { - "minHeight": 48, - }, - "@media (min-width:600px)": Object { - "minHeight": 64, - }, - "minHeight": 56, - }, - }, - "overrides": Object {}, - "palette": Object { - "action": Object { - "activatedOpacity": 0.12, - "active": "rgba(0, 0, 0, 0.54)", - "disabled": "rgba(0, 0, 0, 0.26)", - "disabledBackground": "rgba(0, 0, 0, 0.12)", - "disabledOpacity": 0.38, - "focus": "rgba(0, 0, 0, 0.12)", - "focusOpacity": 0.12, - "hover": "rgba(0, 0, 0, 0.04)", - "hoverOpacity": 0.04, - "selected": "rgba(0, 0, 0, 0.08)", - "selectedOpacity": 0.08, - }, - "augmentColor": [Function], - "background": Object { - "default": "#fafafa", - "paper": "#fff", - }, - "common": Object { - "black": "#000", - "white": "#fff", - }, - "contrastThreshold": 3, - "divider": "rgba(0, 0, 0, 0.12)", - "error": Object { - "contrastText": "#fff", - "dark": "#d32f2f", - "light": "#e57373", - "main": "#f44336", - }, - "getContrastText": [Function], - "grey": Object { - "100": "#f5f5f5", - "200": "#eeeeee", - "300": "#e0e0e0", - "400": "#bdbdbd", - "50": "#fafafa", - "500": "#9e9e9e", - "600": "#757575", - "700": "#616161", - "800": "#424242", - "900": "#212121", - "A100": "#d5d5d5", - "A200": "#aaaaaa", - "A400": "#303030", - "A700": "#616161", - }, - "info": Object { - "contrastText": "#fff", - "dark": "#1976d2", - "light": "#64b5f6", - "main": "#2196f3", - }, - "primary": Object { - "contrastText": "#fff", - "dark": "#303f9f", - "light": "#7986cb", - "main": "#3f51b5", - }, - "secondary": Object { - "contrastText": "#fff", - "dark": "#c51162", - "light": "#ff4081", - "main": "#f50057", - }, - "success": Object { - "contrastText": "rgba(0, 0, 0, 0.87)", - "dark": "#388e3c", - "light": "#81c784", - "main": "#4caf50", - }, - "text": Object { - "disabled": "rgba(0, 0, 0, 0.38)", - "hint": "rgba(0, 0, 0, 0.38)", - "primary": "rgba(0, 0, 0, 0.87)", - "secondary": "rgba(0, 0, 0, 0.54)", - }, - "tonalOffset": 0.2, - "type": "light", - "warning": Object { - "contrastText": "rgba(0, 0, 0, 0.87)", - "dark": "#f57c00", - "light": "#ffb74d", - "main": "#ff9800", - }, - }, - "props": Object {}, - "shadows": Array [ - "none", - "0px 2px 1px -1px rgba(0,0,0,0.2),0px 1px 1px 0px rgba(0,0,0,0.14),0px 1px 3px 0px rgba(0,0,0,0.12)", - "0px 3px 1px -2px rgba(0,0,0,0.2),0px 2px 2px 0px rgba(0,0,0,0.14),0px 1px 5px 0px rgba(0,0,0,0.12)", - "0px 3px 3px -2px rgba(0,0,0,0.2),0px 3px 4px 0px rgba(0,0,0,0.14),0px 1px 8px 0px rgba(0,0,0,0.12)", - "0px 2px 4px -1px rgba(0,0,0,0.2),0px 4px 5px 0px rgba(0,0,0,0.14),0px 1px 10px 0px rgba(0,0,0,0.12)", - "0px 3px 5px -1px rgba(0,0,0,0.2),0px 5px 8px 0px rgba(0,0,0,0.14),0px 1px 14px 0px rgba(0,0,0,0.12)", - "0px 3px 5px -1px rgba(0,0,0,0.2),0px 6px 10px 0px rgba(0,0,0,0.14),0px 1px 18px 0px rgba(0,0,0,0.12)", - "0px 4px 5px -2px rgba(0,0,0,0.2),0px 7px 10px 1px rgba(0,0,0,0.14),0px 2px 16px 1px rgba(0,0,0,0.12)", - "0px 5px 5px -3px rgba(0,0,0,0.2),0px 8px 10px 1px rgba(0,0,0,0.14),0px 3px 14px 2px rgba(0,0,0,0.12)", - "0px 5px 6px -3px rgba(0,0,0,0.2),0px 9px 12px 1px rgba(0,0,0,0.14),0px 3px 16px 2px rgba(0,0,0,0.12)", - "0px 6px 6px -3px rgba(0,0,0,0.2),0px 10px 14px 1px rgba(0,0,0,0.14),0px 4px 18px 3px rgba(0,0,0,0.12)", - "0px 6px 7px -4px rgba(0,0,0,0.2),0px 11px 15px 1px rgba(0,0,0,0.14),0px 4px 20px 3px rgba(0,0,0,0.12)", - "0px 7px 8px -4px rgba(0,0,0,0.2),0px 12px 17px 2px rgba(0,0,0,0.14),0px 5px 22px 4px rgba(0,0,0,0.12)", - "0px 7px 8px -4px rgba(0,0,0,0.2),0px 13px 19px 2px rgba(0,0,0,0.14),0px 5px 24px 4px rgba(0,0,0,0.12)", - "0px 7px 9px -4px rgba(0,0,0,0.2),0px 14px 21px 2px rgba(0,0,0,0.14),0px 5px 26px 4px rgba(0,0,0,0.12)", - "0px 8px 9px -5px rgba(0,0,0,0.2),0px 15px 22px 2px rgba(0,0,0,0.14),0px 6px 28px 5px rgba(0,0,0,0.12)", - "0px 8px 10px -5px rgba(0,0,0,0.2),0px 16px 24px 2px rgba(0,0,0,0.14),0px 6px 30px 5px rgba(0,0,0,0.12)", - "0px 8px 11px -5px rgba(0,0,0,0.2),0px 17px 26px 2px rgba(0,0,0,0.14),0px 6px 32px 5px rgba(0,0,0,0.12)", - "0px 9px 11px -5px rgba(0,0,0,0.2),0px 18px 28px 2px rgba(0,0,0,0.14),0px 7px 34px 6px rgba(0,0,0,0.12)", - "0px 9px 12px -6px rgba(0,0,0,0.2),0px 19px 29px 2px rgba(0,0,0,0.14),0px 7px 36px 6px rgba(0,0,0,0.12)", - "0px 10px 13px -6px rgba(0,0,0,0.2),0px 20px 31px 3px rgba(0,0,0,0.14),0px 8px 38px 7px rgba(0,0,0,0.12)", - "0px 10px 13px -6px rgba(0,0,0,0.2),0px 21px 33px 3px rgba(0,0,0,0.14),0px 8px 40px 7px rgba(0,0,0,0.12)", - "0px 10px 14px -6px rgba(0,0,0,0.2),0px 22px 35px 3px rgba(0,0,0,0.14),0px 8px 42px 7px rgba(0,0,0,0.12)", - "0px 11px 14px -7px rgba(0,0,0,0.2),0px 23px 36px 3px rgba(0,0,0,0.14),0px 9px 44px 8px rgba(0,0,0,0.12)", - "0px 11px 15px -7px rgba(0,0,0,0.2),0px 24px 38px 3px rgba(0,0,0,0.14),0px 9px 46px 8px rgba(0,0,0,0.12)", - ], - "shape": Object { - "borderRadius": 4, - }, - "spacing": [Function], - "transitions": Object { - "create": [Function], - "duration": Object { - "complex": 375, - "enteringScreen": 225, - "leavingScreen": 195, - "short": 250, - "shorter": 200, - "shortest": 150, - "standard": 300, - }, - "easing": Object { - "easeIn": "cubic-bezier(0.4, 0, 1, 1)", - "easeInOut": "cubic-bezier(0.4, 0, 0.2, 1)", - "easeOut": "cubic-bezier(0.0, 0, 0.2, 1)", - "sharp": "cubic-bezier(0.4, 0, 0.6, 1)", - }, - "getAutoHeightDuration": [Function], - }, - "typography": Object { - "body1": Object { - "fontFamily": "\\"Roboto\\", \\"Helvetica\\", \\"Arial\\", sans-serif", - "fontSize": "1rem", - "fontWeight": 400, - "letterSpacing": "0.00938em", - "lineHeight": 1.5, - }, - "body2": Object { - "fontFamily": "\\"Roboto\\", \\"Helvetica\\", \\"Arial\\", sans-serif", - "fontSize": "0.875rem", - "fontWeight": 400, - "letterSpacing": "0.01071em", - "lineHeight": 1.43, - }, - "button": Object { - "fontFamily": "\\"Roboto\\", \\"Helvetica\\", \\"Arial\\", sans-serif", - "fontSize": "0.875rem", - "fontWeight": 500, - "letterSpacing": "0.02857em", - "lineHeight": 1.75, - "textTransform": "uppercase", - }, - "caption": Object { - "fontFamily": "\\"Roboto\\", \\"Helvetica\\", \\"Arial\\", sans-serif", - "fontSize": "0.75rem", - "fontWeight": 400, - "letterSpacing": "0.03333em", - "lineHeight": 1.66, - }, - "fontFamily": "\\"Roboto\\", \\"Helvetica\\", \\"Arial\\", sans-serif", - "fontSize": 14, - "fontWeightBold": 700, - "fontWeightLight": 300, - "fontWeightMedium": 500, - "fontWeightRegular": 400, - "h1": Object { - "fontFamily": "\\"Roboto\\", \\"Helvetica\\", \\"Arial\\", sans-serif", - "fontSize": "6rem", - "fontWeight": 300, - "letterSpacing": "-0.01562em", - "lineHeight": 1.167, - }, - "h2": Object { - "fontFamily": "\\"Roboto\\", \\"Helvetica\\", \\"Arial\\", sans-serif", - "fontSize": "3.75rem", - "fontWeight": 300, - "letterSpacing": "-0.00833em", - "lineHeight": 1.2, - }, - "h3": Object { - "fontFamily": "\\"Roboto\\", \\"Helvetica\\", \\"Arial\\", sans-serif", - "fontSize": "3rem", - "fontWeight": 400, - "letterSpacing": "0em", - "lineHeight": 1.167, - }, - "h4": Object { - "fontFamily": "\\"Roboto\\", \\"Helvetica\\", \\"Arial\\", sans-serif", - "fontSize": "2.125rem", - "fontWeight": 400, - "letterSpacing": "0.00735em", - "lineHeight": 1.235, - }, - "h5": Object { - "fontFamily": "\\"Roboto\\", \\"Helvetica\\", \\"Arial\\", sans-serif", - "fontSize": "1.5rem", - "fontWeight": 400, - "letterSpacing": "0em", - "lineHeight": 1.334, - }, - "h6": Object { - "fontFamily": "\\"Roboto\\", \\"Helvetica\\", \\"Arial\\", sans-serif", - "fontSize": "1.25rem", - "fontWeight": 500, - "letterSpacing": "0.0075em", - "lineHeight": 1.6, - }, - "htmlFontSize": 16, - "overline": Object { - "fontFamily": "\\"Roboto\\", \\"Helvetica\\", \\"Arial\\", sans-serif", - "fontSize": "0.75rem", - "fontWeight": 400, - "letterSpacing": "0.08333em", - "lineHeight": 2.66, - "textTransform": "uppercase", - }, - "pxToRem": [Function], - "round": [Function], - "subtitle1": Object { - "fontFamily": "\\"Roboto\\", \\"Helvetica\\", \\"Arial\\", sans-serif", - "fontSize": "1rem", - "fontWeight": 400, - "letterSpacing": "0.00938em", - "lineHeight": 1.75, - }, - "subtitle2": Object { - "fontFamily": "\\"Roboto\\", \\"Helvetica\\", \\"Arial\\", sans-serif", - "fontSize": "0.875rem", - "fontWeight": 500, - "letterSpacing": "0.00714em", - "lineHeight": 1.57, - }, - }, - "zIndex": Object { - "appBar": 1100, - "drawer": 1200, - "mobileStepper": 1000, - "modal": 1300, - "snackbar": 1400, - "speedDial": 1050, - "tooltip": 1500, - }, - }, - "name": "MuiBackdrop", - }, - "propTypes": Object { - "classes": [Function], - "innerRef": [Function], - }, - "render": [Function], - "useStyles": [Function], - } - } - BackdropProps={ - Object { - "transitionDuration": Object { - "enter": 225, - "exit": 195, - }, - } - } - className="MuiDialog-root modal-root" - closeAfterTransition={true} - disableEscapeKeyDown={false} - onClose={[MockFunction]} - open={true} - > - <ForwardRef(Portal) - disablePortal={false} - > - <Portal - containerInfo={ - <body - style="padding-right: 0px; overflow: hidden;" - > - <div - class="MuiDialog-root modal-root" - role="presentation" - style="position: fixed; z-index: 1300; right: 0px; bottom: 0px; top: 0px; left: 0px;" - > - <div - aria-hidden="true" - class="MuiBackdrop-root" - style="opacity: 1; webkit-transition: opacity 225ms cubic-bezier(0.4, 0, 0.2, 1) 0ms; transition: opacity 225ms cubic-bezier(0.4, 0, 0.2, 1) 0ms;" - /> - <div - data-test="sentinelStart" - tabindex="0" - /> - <div - class="MuiDialog-container MuiDialog-scrollPaper" - role="none presentation" - style="opacity: 1; webkit-transition: opacity 225ms cubic-bezier(0.4, 0, 0.2, 1) 0ms; transition: opacity 225ms cubic-bezier(0.4, 0, 0.2, 1) 0ms;" - tabindex="-1" - > - <div - aria-labelledby="accessibility-title" - class="MuiPaper-root MuiDialog-paper modal-paper MuiDialog-paperScrollPaper MuiDialog-paperWidthSm MuiPaper-elevation24 MuiPaper-rounded" - role="dialog" - > - <div - id="accessibility-title" - > - feedback.accessibility.window_title - </div> - <button - aria-label="feedback.accessibility.button_close" - class="MuiButtonBase-root MuiIconButton-root modal-paper-close-button" - tabindex="0" - type="button" - > - <span - class="MuiIconButton-label" - > - <svg - class="styles__icon___23x3R" - height="16" - width="16" - > - <use - xlink:href="#test-file-stub" - /> - </svg> - </span> - <span - class="MuiTouchRipple-root" - /> - </button> - <div - class="eg-reinit-modal" - > - <svg - class="styles__icon___23x3R" - height="63" - width="63" - > - <use - xlink:href="#test-file-stub" - /> - </svg> - <div - class="title text-20-bold" - > - ecogesture.reinitModal.title_part1 - <span - class="warn-title" - > - ecogesture.reinitModal.title_part2 - </span> - ecogesture.reinitModal.title_part3 - <span - class="warn-title" - > - ecogesture.reinitModal.title_part4 - </span> - ecogesture.reinitModal.title_part5 - <span - class="warn-title" - > - ecogesture.reinitModal.title_part6 - </span> - </div> - <div - class="text-16-normal text" - > - ecogesture.reinitModal.text1 - </div> - <div - class="text-16-bold text" - > - ecogesture.reinitModal.text2 - </div> - <div - class="buttons-container" - > - <button - aria-label="ecogesture.reinitModal.btn1" - class="MuiButtonBase-root MuiButton-root btn-secondary-negative MuiButton-text btn1" - tabindex="0" - type="button" - > - <span - class="MuiButton-label text-16-bold" - > - ecogesture.reinitModal.btn1 - </span> - <span - class="MuiTouchRipple-root" - /> - </button> - <button - aria-label="ecogesture.reinitModal.btn2" - class="MuiButtonBase-root MuiButton-root btn-profile-next rounded MuiButton-text" - tabindex="0" - type="button" - > - <span - class="MuiButton-label text-16-bold" - > - ecogesture.reinitModal.btn2 - </span> - <span - class="MuiTouchRipple-root" - /> - </button> - </div> - </div> - </div> - </div> - <div - data-test="sentinelEnd" - tabindex="0" - /> - </div> - </body> - } - > - <div - className="MuiDialog-root modal-root" - onKeyDown={[Function]} - role="presentation" - style={ - Object { - "bottom": 0, - "left": 0, - "position": "fixed", - "right": 0, - "top": 0, - "zIndex": 1300, - } - } - > - <WithStyles(ForwardRef(Backdrop)) - onClick={[Function]} - open={true} - transitionDuration={ - Object { - "enter": 225, - "exit": 195, - } - } - > - <ForwardRef(Backdrop) - classes={ - Object { - "invisible": "MuiBackdrop-invisible", - "root": "MuiBackdrop-root", - } - } - onClick={[Function]} - open={true} - transitionDuration={ - Object { - "enter": 225, - "exit": 195, - } - } - > - <ForwardRef(Fade) - in={true} - onClick={[Function]} - timeout={ - Object { - "enter": 225, - "exit": 195, - } - } - > - <Transition - appear={true} - enter={true} - exit={true} - in={true} - mountOnEnter={false} - onClick={[Function]} - onEnter={[Function]} - onEntered={[Function]} - onEntering={[Function]} - onExit={[Function]} - onExited={[Function]} - onExiting={[Function]} - timeout={ - Object { - "enter": 225, - "exit": 195, - } - } - unmountOnExit={false} - > - <div - aria-hidden={true} - className="MuiBackdrop-root" - onClick={[Function]} - style={ - Object { - "opacity": 1, - "visibility": undefined, - } - } - /> - </Transition> - </ForwardRef(Fade)> - </ForwardRef(Backdrop)> - </WithStyles(ForwardRef(Backdrop))> - <Unstable_TrapFocus - disableAutoFocus={false} - disableEnforceFocus={false} - disableRestoreFocus={false} - getDoc={[Function]} - isEnabled={[Function]} - open={true} - > - <div - data-test="sentinelStart" - tabIndex={0} - /> - <ForwardRef(Fade) - appear={true} - in={true} - onEnter={[Function]} - onExited={[Function]} - role="none presentation" - tabIndex="-1" - timeout={ - Object { - "enter": 225, - "exit": 195, - } - } - > - <Transition - appear={true} - enter={true} - exit={true} - in={true} - mountOnEnter={false} - onEnter={[Function]} - onEntered={[Function]} - onEntering={[Function]} - onExit={[Function]} - onExited={[Function]} - onExiting={[Function]} - role="none presentation" - tabIndex="-1" - timeout={ - Object { - "enter": 225, - "exit": 195, - } - } - unmountOnExit={false} - > - <div - className="MuiDialog-container MuiDialog-scrollPaper" - onMouseDown={[Function]} - onMouseUp={[Function]} - role="none presentation" - style={ - Object { - "opacity": 1, - "visibility": undefined, - } - } - tabIndex="-1" - > - <WithStyles(ForwardRef(Paper)) - aria-labelledby="accessibility-title" - className="MuiDialog-paper modal-paper MuiDialog-paperScrollPaper MuiDialog-paperWidthSm" - elevation={24} - role="dialog" - > - <ForwardRef(Paper) - aria-labelledby="accessibility-title" - className="MuiDialog-paper modal-paper MuiDialog-paperScrollPaper MuiDialog-paperWidthSm" - classes={ - Object { - "elevation0": "MuiPaper-elevation0", - "elevation1": "MuiPaper-elevation1", - "elevation10": "MuiPaper-elevation10", - "elevation11": "MuiPaper-elevation11", - "elevation12": "MuiPaper-elevation12", - "elevation13": "MuiPaper-elevation13", - "elevation14": "MuiPaper-elevation14", - "elevation15": "MuiPaper-elevation15", - "elevation16": "MuiPaper-elevation16", - "elevation17": "MuiPaper-elevation17", - "elevation18": "MuiPaper-elevation18", - "elevation19": "MuiPaper-elevation19", - "elevation2": "MuiPaper-elevation2", - "elevation20": "MuiPaper-elevation20", - "elevation21": "MuiPaper-elevation21", - "elevation22": "MuiPaper-elevation22", - "elevation23": "MuiPaper-elevation23", - "elevation24": "MuiPaper-elevation24", - "elevation3": "MuiPaper-elevation3", - "elevation4": "MuiPaper-elevation4", - "elevation5": "MuiPaper-elevation5", - "elevation6": "MuiPaper-elevation6", - "elevation7": "MuiPaper-elevation7", - "elevation8": "MuiPaper-elevation8", - "elevation9": "MuiPaper-elevation9", - "outlined": "MuiPaper-outlined", - "root": "MuiPaper-root", - "rounded": "MuiPaper-rounded", - } - } - elevation={24} - role="dialog" - > - <div - aria-labelledby="accessibility-title" - className="MuiPaper-root MuiDialog-paper modal-paper MuiDialog-paperScrollPaper MuiDialog-paperWidthSm MuiPaper-elevation24 MuiPaper-rounded" - role="dialog" - > - <div - id="accessibility-title" - > - feedback.accessibility.window_title - </div> - <WithStyles(ForwardRef(IconButton)) - aria-label="feedback.accessibility.button_close" - className="modal-paper-close-button" - onClick={[MockFunction]} - > - <ForwardRef(IconButton) - aria-label="feedback.accessibility.button_close" - className="modal-paper-close-button" - classes={ - Object { - "colorInherit": "MuiIconButton-colorInherit", - "colorPrimary": "MuiIconButton-colorPrimary", - "colorSecondary": "MuiIconButton-colorSecondary", - "disabled": "Mui-disabled", - "edgeEnd": "MuiIconButton-edgeEnd", - "edgeStart": "MuiIconButton-edgeStart", - "label": "MuiIconButton-label", - "root": "MuiIconButton-root", - "sizeSmall": "MuiIconButton-sizeSmall", - } - } - onClick={[MockFunction]} - > - <WithStyles(ForwardRef(ButtonBase)) - aria-label="feedback.accessibility.button_close" - centerRipple={true} - className="MuiIconButton-root modal-paper-close-button" - disabled={false} - focusRipple={true} - onClick={[MockFunction]} - > - <ForwardRef(ButtonBase) - aria-label="feedback.accessibility.button_close" - centerRipple={true} - className="MuiIconButton-root modal-paper-close-button" - classes={ - Object { - "disabled": "Mui-disabled", - "focusVisible": "Mui-focusVisible", - "root": "MuiButtonBase-root", - } - } - disabled={false} - focusRipple={true} - onClick={[MockFunction]} - > - <button - aria-label="feedback.accessibility.button_close" - className="MuiButtonBase-root MuiIconButton-root modal-paper-close-button" - disabled={false} - onBlur={[Function]} - onClick={[MockFunction]} - onDragLeave={[Function]} - onFocus={[Function]} - onKeyDown={[Function]} - onKeyUp={[Function]} - onMouseDown={[Function]} - onMouseLeave={[Function]} - onMouseUp={[Function]} - onTouchEnd={[Function]} - onTouchMove={[Function]} - onTouchStart={[Function]} - tabIndex={0} - type="button" - > - <span - className="MuiIconButton-label" - > - <Icon - icon="test-file-stub" - size={16} - spin={false} - > - <Component - className="styles__icon___23x3R" - height={16} - style={Object {}} - width={16} - > - <svg - className="styles__icon___23x3R" - height={16} - style={Object {}} - width={16} - > - <use - xlinkHref="#test-file-stub" - /> - </svg> - </Component> - </Icon> - </span> - <WithStyles(memo) - center={true} - > - <ForwardRef(TouchRipple) - center={true} - classes={ - Object { - "child": "MuiTouchRipple-child", - "childLeaving": "MuiTouchRipple-childLeaving", - "childPulsate": "MuiTouchRipple-childPulsate", - "ripple": "MuiTouchRipple-ripple", - "ripplePulsate": "MuiTouchRipple-ripplePulsate", - "rippleVisible": "MuiTouchRipple-rippleVisible", - "root": "MuiTouchRipple-root", - } - } - > - <span - className="MuiTouchRipple-root" - > - <TransitionGroup - childFactory={[Function]} - component={null} - exit={true} - /> - </span> - </ForwardRef(TouchRipple)> - </WithStyles(memo)> - </button> - </ForwardRef(ButtonBase)> - </WithStyles(ForwardRef(ButtonBase))> - </ForwardRef(IconButton)> - </WithStyles(ForwardRef(IconButton))> - <div - className="eg-reinit-modal" - > - <Icon - icon="test-file-stub" - size={63} - spin={false} - > - <Component - className="styles__icon___23x3R" - height={63} - style={Object {}} - width={63} - > - <svg - className="styles__icon___23x3R" - height={63} - style={Object {}} - width={63} - > - <use - xlinkHref="#test-file-stub" - /> - </svg> - </Component> - </Icon> - <div - className="title text-20-bold" - > - ecogesture.reinitModal.title_part1 - <span - className="warn-title" - > - ecogesture.reinitModal.title_part2 - </span> - ecogesture.reinitModal.title_part3 - <span - className="warn-title" - > - ecogesture.reinitModal.title_part4 - </span> - ecogesture.reinitModal.title_part5 - <span - className="warn-title" - > - ecogesture.reinitModal.title_part6 - </span> - </div> - <div - className="text-16-normal text" - > - ecogesture.reinitModal.text1 - </div> - <div - className="text-16-bold text" - > - ecogesture.reinitModal.text2 - </div> - <div - className="buttons-container" - > - <WithStyles(ForwardRef(Button)) - aria-label="ecogesture.reinitModal.btn1" - className="btn1" - classes={ - Object { - "label": "text-16-bold", - "root": "btn-secondary-negative", - } - } - onClick={[MockFunction]} - > - <ForwardRef(Button) - aria-label="ecogesture.reinitModal.btn1" - className="btn1" - classes={ - Object { - "colorInherit": "MuiButton-colorInherit", - "contained": "MuiButton-contained", - "containedPrimary": "MuiButton-containedPrimary", - "containedSecondary": "MuiButton-containedSecondary", - "containedSizeLarge": "MuiButton-containedSizeLarge", - "containedSizeSmall": "MuiButton-containedSizeSmall", - "disableElevation": "MuiButton-disableElevation", - "disabled": "Mui-disabled", - "endIcon": "MuiButton-endIcon", - "focusVisible": "Mui-focusVisible", - "fullWidth": "MuiButton-fullWidth", - "iconSizeLarge": "MuiButton-iconSizeLarge", - "iconSizeMedium": "MuiButton-iconSizeMedium", - "iconSizeSmall": "MuiButton-iconSizeSmall", - "label": "MuiButton-label text-16-bold", - "outlined": "MuiButton-outlined", - "outlinedPrimary": "MuiButton-outlinedPrimary", - "outlinedSecondary": "MuiButton-outlinedSecondary", - "outlinedSizeLarge": "MuiButton-outlinedSizeLarge", - "outlinedSizeSmall": "MuiButton-outlinedSizeSmall", - "root": "MuiButton-root btn-secondary-negative", - "sizeLarge": "MuiButton-sizeLarge", - "sizeSmall": "MuiButton-sizeSmall", - "startIcon": "MuiButton-startIcon", - "text": "MuiButton-text", - "textPrimary": "MuiButton-textPrimary", - "textSecondary": "MuiButton-textSecondary", - "textSizeLarge": "MuiButton-textSizeLarge", - "textSizeSmall": "MuiButton-textSizeSmall", - } - } - onClick={[MockFunction]} - > - <WithStyles(ForwardRef(ButtonBase)) - aria-label="ecogesture.reinitModal.btn1" - className="MuiButton-root btn-secondary-negative MuiButton-text btn1" - component="button" - disabled={false} - focusRipple={true} - focusVisibleClassName="Mui-focusVisible" - onClick={[MockFunction]} - type="button" - > - <ForwardRef(ButtonBase) - aria-label="ecogesture.reinitModal.btn1" - className="MuiButton-root btn-secondary-negative MuiButton-text btn1" - classes={ - Object { - "disabled": "Mui-disabled", - "focusVisible": "Mui-focusVisible", - "root": "MuiButtonBase-root", - } - } - component="button" - disabled={false} - focusRipple={true} - focusVisibleClassName="Mui-focusVisible" - onClick={[MockFunction]} - type="button" - > - <button - aria-label="ecogesture.reinitModal.btn1" - className="MuiButtonBase-root MuiButton-root btn-secondary-negative MuiButton-text btn1" - disabled={false} - onBlur={[Function]} - onClick={[MockFunction]} - onDragLeave={[Function]} - onFocus={[Function]} - onKeyDown={[Function]} - onKeyUp={[Function]} - onMouseDown={[Function]} - onMouseLeave={[Function]} - onMouseUp={[Function]} - onTouchEnd={[Function]} - onTouchMove={[Function]} - onTouchStart={[Function]} - tabIndex={0} - type="button" - > - <span - className="MuiButton-label text-16-bold" - > - ecogesture.reinitModal.btn1 - </span> - <WithStyles(memo) - center={false} - > - <ForwardRef(TouchRipple) - center={false} - classes={ - Object { - "child": "MuiTouchRipple-child", - "childLeaving": "MuiTouchRipple-childLeaving", - "childPulsate": "MuiTouchRipple-childPulsate", - "ripple": "MuiTouchRipple-ripple", - "ripplePulsate": "MuiTouchRipple-ripplePulsate", - "rippleVisible": "MuiTouchRipple-rippleVisible", - "root": "MuiTouchRipple-root", - } - } - > - <span - className="MuiTouchRipple-root" - > - <TransitionGroup - childFactory={[Function]} - component={null} - exit={true} - /> - </span> - </ForwardRef(TouchRipple)> - </WithStyles(memo)> - </button> - </ForwardRef(ButtonBase)> - </WithStyles(ForwardRef(ButtonBase))> - </ForwardRef(Button)> - </WithStyles(ForwardRef(Button))> - <WithStyles(ForwardRef(Button)) - aria-label="ecogesture.reinitModal.btn2" - classes={ - Object { - "label": "text-16-bold", - "root": "btn-profile-next rounded", - } - } - onClick={[MockFunction]} - > - <ForwardRef(Button) - aria-label="ecogesture.reinitModal.btn2" - classes={ - Object { - "colorInherit": "MuiButton-colorInherit", - "contained": "MuiButton-contained", - "containedPrimary": "MuiButton-containedPrimary", - "containedSecondary": "MuiButton-containedSecondary", - "containedSizeLarge": "MuiButton-containedSizeLarge", - "containedSizeSmall": "MuiButton-containedSizeSmall", - "disableElevation": "MuiButton-disableElevation", - "disabled": "Mui-disabled", - "endIcon": "MuiButton-endIcon", - "focusVisible": "Mui-focusVisible", - "fullWidth": "MuiButton-fullWidth", - "iconSizeLarge": "MuiButton-iconSizeLarge", - "iconSizeMedium": "MuiButton-iconSizeMedium", - "iconSizeSmall": "MuiButton-iconSizeSmall", - "label": "MuiButton-label text-16-bold", - "outlined": "MuiButton-outlined", - "outlinedPrimary": "MuiButton-outlinedPrimary", - "outlinedSecondary": "MuiButton-outlinedSecondary", - "outlinedSizeLarge": "MuiButton-outlinedSizeLarge", - "outlinedSizeSmall": "MuiButton-outlinedSizeSmall", - "root": "MuiButton-root btn-profile-next rounded", - "sizeLarge": "MuiButton-sizeLarge", - "sizeSmall": "MuiButton-sizeSmall", - "startIcon": "MuiButton-startIcon", - "text": "MuiButton-text", - "textPrimary": "MuiButton-textPrimary", - "textSecondary": "MuiButton-textSecondary", - "textSizeLarge": "MuiButton-textSizeLarge", - "textSizeSmall": "MuiButton-textSizeSmall", - } - } - onClick={[MockFunction]} - > - <WithStyles(ForwardRef(ButtonBase)) - aria-label="ecogesture.reinitModal.btn2" - className="MuiButton-root btn-profile-next rounded MuiButton-text" - component="button" - disabled={false} - focusRipple={true} - focusVisibleClassName="Mui-focusVisible" - onClick={[MockFunction]} - type="button" - > - <ForwardRef(ButtonBase) - aria-label="ecogesture.reinitModal.btn2" - className="MuiButton-root btn-profile-next rounded MuiButton-text" - classes={ - Object { - "disabled": "Mui-disabled", - "focusVisible": "Mui-focusVisible", - "root": "MuiButtonBase-root", - } - } - component="button" - disabled={false} - focusRipple={true} - focusVisibleClassName="Mui-focusVisible" - onClick={[MockFunction]} - type="button" - > - <button - aria-label="ecogesture.reinitModal.btn2" - className="MuiButtonBase-root MuiButton-root btn-profile-next rounded MuiButton-text" - disabled={false} - onBlur={[Function]} - onClick={[MockFunction]} - onDragLeave={[Function]} - onFocus={[Function]} - onKeyDown={[Function]} - onKeyUp={[Function]} - onMouseDown={[Function]} - onMouseLeave={[Function]} - onMouseUp={[Function]} - onTouchEnd={[Function]} - onTouchMove={[Function]} - onTouchStart={[Function]} - tabIndex={0} - type="button" - > - <span - className="MuiButton-label text-16-bold" - > - ecogesture.reinitModal.btn2 - </span> - <WithStyles(memo) - center={false} - > - <ForwardRef(TouchRipple) - center={false} - classes={ - Object { - "child": "MuiTouchRipple-child", - "childLeaving": "MuiTouchRipple-childLeaving", - "childPulsate": "MuiTouchRipple-childPulsate", - "ripple": "MuiTouchRipple-ripple", - "ripplePulsate": "MuiTouchRipple-ripplePulsate", - "rippleVisible": "MuiTouchRipple-rippleVisible", - "root": "MuiTouchRipple-root", - } - } - > - <span - className="MuiTouchRipple-root" - > - <TransitionGroup - childFactory={[Function]} - component={null} - exit={true} - /> - </span> - </ForwardRef(TouchRipple)> - </WithStyles(memo)> - </button> - </ForwardRef(ButtonBase)> - </WithStyles(ForwardRef(ButtonBase))> - </ForwardRef(Button)> - </WithStyles(ForwardRef(Button))> - </div> - </div> - </div> - </ForwardRef(Paper)> - </WithStyles(ForwardRef(Paper))> - </div> - </Transition> - </ForwardRef(Fade)> - <div - data-test="sentinelEnd" - tabIndex={0} - /> - </Unstable_TrapFocus> - </div> - </Portal> - </ForwardRef(Portal)> - </ForwardRef(Modal)> - </ForwardRef(Dialog)> - </WithStyles(ForwardRef(Dialog))> - </EcogestureReinitModal> -</Provider> -`; diff --git a/src/components/Ecogesture/__snapshots__/EcogestureView.spec.tsx.snap b/src/components/Ecogesture/__snapshots__/EcogestureTabsView.spec.tsx.snap similarity index 57% rename from src/components/Ecogesture/__snapshots__/EcogestureView.spec.tsx.snap rename to src/components/Ecogesture/__snapshots__/EcogestureTabsView.spec.tsx.snap index 50965b8272031fe0d5d756ebda4d77811f41f39c..f6432521d2f775a377e0f8cb56c35b1371064a41 100644 --- a/src/components/Ecogesture/__snapshots__/EcogestureView.spec.tsx.snap +++ b/src/components/Ecogesture/__snapshots__/EcogestureTabsView.spec.tsx.snap @@ -13,7 +13,7 @@ exports[`EcogestureView component should be rendered correctly 1`] = ` } } > - <EcogestureView> + <EcogestureTabsView> <mock-cozybar titleKey="common.title_ecogestures" /> @@ -95,6 +95,7 @@ exports[`EcogestureView component should be rendered correctly 1`] = ` } onChange={[Function]} selected={true} + tabIndex={0} textColor="inherit" value={0} > @@ -127,6 +128,7 @@ exports[`EcogestureView component should be rendered correctly 1`] = ` } onChange={[Function]} selected={true} + tabIndex={0} textColor="inherit" value={0} > @@ -239,6 +241,7 @@ exports[`EcogestureView component should be rendered correctly 1`] = ` } onChange={[Function]} selected={false} + tabIndex={0} textColor="inherit" value={1} > @@ -271,6 +274,7 @@ exports[`EcogestureView component should be rendered correctly 1`] = ` } onChange={[Function]} selected={false} + tabIndex={0} textColor="inherit" value={1} > @@ -284,7 +288,7 @@ exports[`EcogestureView component should be rendered correctly 1`] = ` onClick={[Function]} onFocus={[Function]} role="tab" - tabIndex={-1} + tabIndex={0} > <ForwardRef(ButtonBase) aria-controls="simple-tabpanel-1" @@ -303,7 +307,7 @@ exports[`EcogestureView component should be rendered correctly 1`] = ` onClick={[Function]} onFocus={[Function]} role="tab" - tabIndex={-1} + tabIndex={0} > <button aria-controls="simple-tabpanel-1" @@ -324,7 +328,7 @@ exports[`EcogestureView component should be rendered correctly 1`] = ` onTouchMove={[Function]} onTouchStart={[Function]} role="tab" - tabIndex={-1} + tabIndex={0} type="button" > <span @@ -383,6 +387,7 @@ exports[`EcogestureView component should be rendered correctly 1`] = ` } onChange={[Function]} selected={false} + tabIndex={0} textColor="inherit" value={2} > @@ -415,6 +420,7 @@ exports[`EcogestureView component should be rendered correctly 1`] = ` } onChange={[Function]} selected={false} + tabIndex={0} textColor="inherit" value={2} > @@ -428,7 +434,7 @@ exports[`EcogestureView component should be rendered correctly 1`] = ` onClick={[Function]} onFocus={[Function]} role="tab" - tabIndex={-1} + tabIndex={0} > <ForwardRef(ButtonBase) aria-controls="simple-tabpanel-2" @@ -447,7 +453,7 @@ exports[`EcogestureView component should be rendered correctly 1`] = ` onClick={[Function]} onFocus={[Function]} role="tab" - tabIndex={-1} + tabIndex={0} > <button aria-controls="simple-tabpanel-2" @@ -468,7 +474,7 @@ exports[`EcogestureView component should be rendered correctly 1`] = ` onTouchMove={[Function]} onTouchStart={[Function]} role="tab" - tabIndex={-1} + tabIndex={0} type="button" > <span @@ -559,7 +565,7 @@ exports[`EcogestureView component should be rendered correctly 1`] = ` </WithStyles(ForwardRef(Tabs))> </mock-header> <mock-content - height={0} + heightOffset={0} > <TabPanel tab={0} @@ -1244,533 +1250,516 @@ exports[`EcogestureView component should be rendered correctly 1`] = ` role="tabpanel" /> </TabPanel> - </mock-content> - <EcogestureInitModal - handleCloseClick={[Function]} - handleLaunchForm={[Function]} - open={true} - > - <WithStyles(ForwardRef(Dialog)) - aria-labelledby="accessibility-title" - classes={ - Object { - "paper": "modal-paper", - "root": "modal-root", - } - } - onClose={[Function]} + <EcogestureInitModal + handleCloseClick={[Function]} + handleLaunchForm={[Function]} open={true} > - <ForwardRef(Dialog) + <WithStyles(ForwardRef(Dialog)) aria-labelledby="accessibility-title" classes={ Object { - "container": "MuiDialog-container", - "paper": "MuiDialog-paper modal-paper", - "paperFullScreen": "MuiDialog-paperFullScreen", - "paperFullWidth": "MuiDialog-paperFullWidth", - "paperScrollBody": "MuiDialog-paperScrollBody", - "paperScrollPaper": "MuiDialog-paperScrollPaper", - "paperWidthFalse": "MuiDialog-paperWidthFalse", - "paperWidthLg": "MuiDialog-paperWidthLg", - "paperWidthMd": "MuiDialog-paperWidthMd", - "paperWidthSm": "MuiDialog-paperWidthSm", - "paperWidthXl": "MuiDialog-paperWidthXl", - "paperWidthXs": "MuiDialog-paperWidthXs", - "root": "MuiDialog-root modal-root", - "scrollBody": "MuiDialog-scrollBody", - "scrollPaper": "MuiDialog-scrollPaper", + "paper": "modal-paper", + "root": "modal-root", } } onClose={[Function]} open={true} > - <ForwardRef(Modal) - BackdropComponent={ + <ForwardRef(Dialog) + aria-labelledby="accessibility-title" + classes={ Object { - "$$typeof": Symbol(react.forward_ref), - "Naked": Object { + "container": "MuiDialog-container", + "paper": "MuiDialog-paper modal-paper", + "paperFullScreen": "MuiDialog-paperFullScreen", + "paperFullWidth": "MuiDialog-paperFullWidth", + "paperScrollBody": "MuiDialog-paperScrollBody", + "paperScrollPaper": "MuiDialog-paperScrollPaper", + "paperWidthFalse": "MuiDialog-paperWidthFalse", + "paperWidthLg": "MuiDialog-paperWidthLg", + "paperWidthMd": "MuiDialog-paperWidthMd", + "paperWidthSm": "MuiDialog-paperWidthSm", + "paperWidthXl": "MuiDialog-paperWidthXl", + "paperWidthXs": "MuiDialog-paperWidthXs", + "root": "MuiDialog-root modal-root", + "scrollBody": "MuiDialog-scrollBody", + "scrollPaper": "MuiDialog-scrollPaper", + } + } + onClose={[Function]} + open={true} + > + <ForwardRef(Modal) + BackdropComponent={ + Object { "$$typeof": Symbol(react.forward_ref), - "propTypes": Object { - "children": [Function], - "className": [Function], - "classes": [Function], - "invisible": [Function], - "open": [Function], - "transitionDuration": [Function], - }, - "render": [Function], - }, - "displayName": "WithStyles(ForwardRef(Backdrop))", - "options": Object { - "defaultTheme": Object { - "breakpoints": Object { - "between": [Function], - "down": [Function], - "keys": Array [ - "xs", - "sm", - "md", - "lg", - "xl", - ], - "only": [Function], - "up": [Function], - "values": Object { - "lg": 1280, - "md": 960, - "sm": 600, - "xl": 1920, - "xs": 0, - }, - "width": [Function], + "Naked": Object { + "$$typeof": Symbol(react.forward_ref), + "propTypes": Object { + "children": [Function], + "className": [Function], + "classes": [Function], + "invisible": [Function], + "open": [Function], + "transitionDuration": [Function], }, - "direction": "ltr", - "mixins": Object { - "gutters": [Function], - "toolbar": Object { - "@media (min-width:0px) and (orientation: landscape)": Object { - "minHeight": 48, - }, - "@media (min-width:600px)": Object { - "minHeight": 64, + "render": [Function], + }, + "displayName": "WithStyles(ForwardRef(Backdrop))", + "options": Object { + "defaultTheme": Object { + "breakpoints": Object { + "between": [Function], + "down": [Function], + "keys": Array [ + "xs", + "sm", + "md", + "lg", + "xl", + ], + "only": [Function], + "up": [Function], + "values": Object { + "lg": 1280, + "md": 960, + "sm": 600, + "xl": 1920, + "xs": 0, }, - "minHeight": 56, - }, - }, - "overrides": Object {}, - "palette": Object { - "action": Object { - "activatedOpacity": 0.12, - "active": "rgba(0, 0, 0, 0.54)", - "disabled": "rgba(0, 0, 0, 0.26)", - "disabledBackground": "rgba(0, 0, 0, 0.12)", - "disabledOpacity": 0.38, - "focus": "rgba(0, 0, 0, 0.12)", - "focusOpacity": 0.12, - "hover": "rgba(0, 0, 0, 0.04)", - "hoverOpacity": 0.04, - "selected": "rgba(0, 0, 0, 0.08)", - "selectedOpacity": 0.08, - }, - "augmentColor": [Function], - "background": Object { - "default": "#fafafa", - "paper": "#fff", - }, - "common": Object { - "black": "#000", - "white": "#fff", - }, - "contrastThreshold": 3, - "divider": "rgba(0, 0, 0, 0.12)", - "error": Object { - "contrastText": "#fff", - "dark": "#d32f2f", - "light": "#e57373", - "main": "#f44336", - }, - "getContrastText": [Function], - "grey": Object { - "100": "#f5f5f5", - "200": "#eeeeee", - "300": "#e0e0e0", - "400": "#bdbdbd", - "50": "#fafafa", - "500": "#9e9e9e", - "600": "#757575", - "700": "#616161", - "800": "#424242", - "900": "#212121", - "A100": "#d5d5d5", - "A200": "#aaaaaa", - "A400": "#303030", - "A700": "#616161", - }, - "info": Object { - "contrastText": "#fff", - "dark": "#1976d2", - "light": "#64b5f6", - "main": "#2196f3", - }, - "primary": Object { - "contrastText": "#fff", - "dark": "#303f9f", - "light": "#7986cb", - "main": "#3f51b5", - }, - "secondary": Object { - "contrastText": "#fff", - "dark": "#c51162", - "light": "#ff4081", - "main": "#f50057", - }, - "success": Object { - "contrastText": "rgba(0, 0, 0, 0.87)", - "dark": "#388e3c", - "light": "#81c784", - "main": "#4caf50", - }, - "text": Object { - "disabled": "rgba(0, 0, 0, 0.38)", - "hint": "rgba(0, 0, 0, 0.38)", - "primary": "rgba(0, 0, 0, 0.87)", - "secondary": "rgba(0, 0, 0, 0.54)", - }, - "tonalOffset": 0.2, - "type": "light", - "warning": Object { - "contrastText": "rgba(0, 0, 0, 0.87)", - "dark": "#f57c00", - "light": "#ffb74d", - "main": "#ff9800", - }, - }, - "props": Object {}, - "shadows": Array [ - "none", - "0px 2px 1px -1px rgba(0,0,0,0.2),0px 1px 1px 0px rgba(0,0,0,0.14),0px 1px 3px 0px rgba(0,0,0,0.12)", - "0px 3px 1px -2px rgba(0,0,0,0.2),0px 2px 2px 0px rgba(0,0,0,0.14),0px 1px 5px 0px rgba(0,0,0,0.12)", - "0px 3px 3px -2px rgba(0,0,0,0.2),0px 3px 4px 0px rgba(0,0,0,0.14),0px 1px 8px 0px rgba(0,0,0,0.12)", - "0px 2px 4px -1px rgba(0,0,0,0.2),0px 4px 5px 0px rgba(0,0,0,0.14),0px 1px 10px 0px rgba(0,0,0,0.12)", - "0px 3px 5px -1px rgba(0,0,0,0.2),0px 5px 8px 0px rgba(0,0,0,0.14),0px 1px 14px 0px rgba(0,0,0,0.12)", - "0px 3px 5px -1px rgba(0,0,0,0.2),0px 6px 10px 0px rgba(0,0,0,0.14),0px 1px 18px 0px rgba(0,0,0,0.12)", - "0px 4px 5px -2px rgba(0,0,0,0.2),0px 7px 10px 1px rgba(0,0,0,0.14),0px 2px 16px 1px rgba(0,0,0,0.12)", - "0px 5px 5px -3px rgba(0,0,0,0.2),0px 8px 10px 1px rgba(0,0,0,0.14),0px 3px 14px 2px rgba(0,0,0,0.12)", - "0px 5px 6px -3px rgba(0,0,0,0.2),0px 9px 12px 1px rgba(0,0,0,0.14),0px 3px 16px 2px rgba(0,0,0,0.12)", - "0px 6px 6px -3px rgba(0,0,0,0.2),0px 10px 14px 1px rgba(0,0,0,0.14),0px 4px 18px 3px rgba(0,0,0,0.12)", - "0px 6px 7px -4px rgba(0,0,0,0.2),0px 11px 15px 1px rgba(0,0,0,0.14),0px 4px 20px 3px rgba(0,0,0,0.12)", - "0px 7px 8px -4px rgba(0,0,0,0.2),0px 12px 17px 2px rgba(0,0,0,0.14),0px 5px 22px 4px rgba(0,0,0,0.12)", - "0px 7px 8px -4px rgba(0,0,0,0.2),0px 13px 19px 2px rgba(0,0,0,0.14),0px 5px 24px 4px rgba(0,0,0,0.12)", - "0px 7px 9px -4px rgba(0,0,0,0.2),0px 14px 21px 2px rgba(0,0,0,0.14),0px 5px 26px 4px rgba(0,0,0,0.12)", - "0px 8px 9px -5px rgba(0,0,0,0.2),0px 15px 22px 2px rgba(0,0,0,0.14),0px 6px 28px 5px rgba(0,0,0,0.12)", - "0px 8px 10px -5px rgba(0,0,0,0.2),0px 16px 24px 2px rgba(0,0,0,0.14),0px 6px 30px 5px rgba(0,0,0,0.12)", - "0px 8px 11px -5px rgba(0,0,0,0.2),0px 17px 26px 2px rgba(0,0,0,0.14),0px 6px 32px 5px rgba(0,0,0,0.12)", - "0px 9px 11px -5px rgba(0,0,0,0.2),0px 18px 28px 2px rgba(0,0,0,0.14),0px 7px 34px 6px rgba(0,0,0,0.12)", - "0px 9px 12px -6px rgba(0,0,0,0.2),0px 19px 29px 2px rgba(0,0,0,0.14),0px 7px 36px 6px rgba(0,0,0,0.12)", - "0px 10px 13px -6px rgba(0,0,0,0.2),0px 20px 31px 3px rgba(0,0,0,0.14),0px 8px 38px 7px rgba(0,0,0,0.12)", - "0px 10px 13px -6px rgba(0,0,0,0.2),0px 21px 33px 3px rgba(0,0,0,0.14),0px 8px 40px 7px rgba(0,0,0,0.12)", - "0px 10px 14px -6px rgba(0,0,0,0.2),0px 22px 35px 3px rgba(0,0,0,0.14),0px 8px 42px 7px rgba(0,0,0,0.12)", - "0px 11px 14px -7px rgba(0,0,0,0.2),0px 23px 36px 3px rgba(0,0,0,0.14),0px 9px 44px 8px rgba(0,0,0,0.12)", - "0px 11px 15px -7px rgba(0,0,0,0.2),0px 24px 38px 3px rgba(0,0,0,0.14),0px 9px 46px 8px rgba(0,0,0,0.12)", - ], - "shape": Object { - "borderRadius": 4, - }, - "spacing": [Function], - "transitions": Object { - "create": [Function], - "duration": Object { - "complex": 375, - "enteringScreen": 225, - "leavingScreen": 195, - "short": 250, - "shorter": 200, - "shortest": 150, - "standard": 300, - }, - "easing": Object { - "easeIn": "cubic-bezier(0.4, 0, 1, 1)", - "easeInOut": "cubic-bezier(0.4, 0, 0.2, 1)", - "easeOut": "cubic-bezier(0.0, 0, 0.2, 1)", - "sharp": "cubic-bezier(0.4, 0, 0.6, 1)", - }, - "getAutoHeightDuration": [Function], - }, - "typography": Object { - "body1": Object { - "fontFamily": "\\"Roboto\\", \\"Helvetica\\", \\"Arial\\", sans-serif", - "fontSize": "1rem", - "fontWeight": 400, - "letterSpacing": "0.00938em", - "lineHeight": 1.5, - }, - "body2": Object { - "fontFamily": "\\"Roboto\\", \\"Helvetica\\", \\"Arial\\", sans-serif", - "fontSize": "0.875rem", - "fontWeight": 400, - "letterSpacing": "0.01071em", - "lineHeight": 1.43, - }, - "button": Object { - "fontFamily": "\\"Roboto\\", \\"Helvetica\\", \\"Arial\\", sans-serif", - "fontSize": "0.875rem", - "fontWeight": 500, - "letterSpacing": "0.02857em", - "lineHeight": 1.75, - "textTransform": "uppercase", - }, - "caption": Object { - "fontFamily": "\\"Roboto\\", \\"Helvetica\\", \\"Arial\\", sans-serif", - "fontSize": "0.75rem", - "fontWeight": 400, - "letterSpacing": "0.03333em", - "lineHeight": 1.66, - }, - "fontFamily": "\\"Roboto\\", \\"Helvetica\\", \\"Arial\\", sans-serif", - "fontSize": 14, - "fontWeightBold": 700, - "fontWeightLight": 300, - "fontWeightMedium": 500, - "fontWeightRegular": 400, - "h1": Object { - "fontFamily": "\\"Roboto\\", \\"Helvetica\\", \\"Arial\\", sans-serif", - "fontSize": "6rem", - "fontWeight": 300, - "letterSpacing": "-0.01562em", - "lineHeight": 1.167, - }, - "h2": Object { - "fontFamily": "\\"Roboto\\", \\"Helvetica\\", \\"Arial\\", sans-serif", - "fontSize": "3.75rem", - "fontWeight": 300, - "letterSpacing": "-0.00833em", - "lineHeight": 1.2, - }, - "h3": Object { - "fontFamily": "\\"Roboto\\", \\"Helvetica\\", \\"Arial\\", sans-serif", - "fontSize": "3rem", - "fontWeight": 400, - "letterSpacing": "0em", - "lineHeight": 1.167, + "width": [Function], }, - "h4": Object { - "fontFamily": "\\"Roboto\\", \\"Helvetica\\", \\"Arial\\", sans-serif", - "fontSize": "2.125rem", - "fontWeight": 400, - "letterSpacing": "0.00735em", - "lineHeight": 1.235, + "direction": "ltr", + "mixins": Object { + "gutters": [Function], + "toolbar": Object { + "@media (min-width:0px) and (orientation: landscape)": Object { + "minHeight": 48, + }, + "@media (min-width:600px)": Object { + "minHeight": 64, + }, + "minHeight": 56, + }, }, - "h5": Object { - "fontFamily": "\\"Roboto\\", \\"Helvetica\\", \\"Arial\\", sans-serif", - "fontSize": "1.5rem", - "fontWeight": 400, - "letterSpacing": "0em", - "lineHeight": 1.334, + "overrides": Object {}, + "palette": Object { + "action": Object { + "activatedOpacity": 0.12, + "active": "rgba(0, 0, 0, 0.54)", + "disabled": "rgba(0, 0, 0, 0.26)", + "disabledBackground": "rgba(0, 0, 0, 0.12)", + "disabledOpacity": 0.38, + "focus": "rgba(0, 0, 0, 0.12)", + "focusOpacity": 0.12, + "hover": "rgba(0, 0, 0, 0.04)", + "hoverOpacity": 0.04, + "selected": "rgba(0, 0, 0, 0.08)", + "selectedOpacity": 0.08, + }, + "augmentColor": [Function], + "background": Object { + "default": "#fafafa", + "paper": "#fff", + }, + "common": Object { + "black": "#000", + "white": "#fff", + }, + "contrastThreshold": 3, + "divider": "rgba(0, 0, 0, 0.12)", + "error": Object { + "contrastText": "#fff", + "dark": "#d32f2f", + "light": "#e57373", + "main": "#f44336", + }, + "getContrastText": [Function], + "grey": Object { + "100": "#f5f5f5", + "200": "#eeeeee", + "300": "#e0e0e0", + "400": "#bdbdbd", + "50": "#fafafa", + "500": "#9e9e9e", + "600": "#757575", + "700": "#616161", + "800": "#424242", + "900": "#212121", + "A100": "#d5d5d5", + "A200": "#aaaaaa", + "A400": "#303030", + "A700": "#616161", + }, + "info": Object { + "contrastText": "#fff", + "dark": "#1976d2", + "light": "#64b5f6", + "main": "#2196f3", + }, + "primary": Object { + "contrastText": "#fff", + "dark": "#303f9f", + "light": "#7986cb", + "main": "#3f51b5", + }, + "secondary": Object { + "contrastText": "#fff", + "dark": "#c51162", + "light": "#ff4081", + "main": "#f50057", + }, + "success": Object { + "contrastText": "rgba(0, 0, 0, 0.87)", + "dark": "#388e3c", + "light": "#81c784", + "main": "#4caf50", + }, + "text": Object { + "disabled": "rgba(0, 0, 0, 0.38)", + "hint": "rgba(0, 0, 0, 0.38)", + "primary": "rgba(0, 0, 0, 0.87)", + "secondary": "rgba(0, 0, 0, 0.54)", + }, + "tonalOffset": 0.2, + "type": "light", + "warning": Object { + "contrastText": "rgba(0, 0, 0, 0.87)", + "dark": "#f57c00", + "light": "#ffb74d", + "main": "#ff9800", + }, }, - "h6": Object { - "fontFamily": "\\"Roboto\\", \\"Helvetica\\", \\"Arial\\", sans-serif", - "fontSize": "1.25rem", - "fontWeight": 500, - "letterSpacing": "0.0075em", - "lineHeight": 1.6, + "props": Object {}, + "shadows": Array [ + "none", + "0px 2px 1px -1px rgba(0,0,0,0.2),0px 1px 1px 0px rgba(0,0,0,0.14),0px 1px 3px 0px rgba(0,0,0,0.12)", + "0px 3px 1px -2px rgba(0,0,0,0.2),0px 2px 2px 0px rgba(0,0,0,0.14),0px 1px 5px 0px rgba(0,0,0,0.12)", + "0px 3px 3px -2px rgba(0,0,0,0.2),0px 3px 4px 0px rgba(0,0,0,0.14),0px 1px 8px 0px rgba(0,0,0,0.12)", + "0px 2px 4px -1px rgba(0,0,0,0.2),0px 4px 5px 0px rgba(0,0,0,0.14),0px 1px 10px 0px rgba(0,0,0,0.12)", + "0px 3px 5px -1px rgba(0,0,0,0.2),0px 5px 8px 0px rgba(0,0,0,0.14),0px 1px 14px 0px rgba(0,0,0,0.12)", + "0px 3px 5px -1px rgba(0,0,0,0.2),0px 6px 10px 0px rgba(0,0,0,0.14),0px 1px 18px 0px rgba(0,0,0,0.12)", + "0px 4px 5px -2px rgba(0,0,0,0.2),0px 7px 10px 1px rgba(0,0,0,0.14),0px 2px 16px 1px rgba(0,0,0,0.12)", + "0px 5px 5px -3px rgba(0,0,0,0.2),0px 8px 10px 1px rgba(0,0,0,0.14),0px 3px 14px 2px rgba(0,0,0,0.12)", + "0px 5px 6px -3px rgba(0,0,0,0.2),0px 9px 12px 1px rgba(0,0,0,0.14),0px 3px 16px 2px rgba(0,0,0,0.12)", + "0px 6px 6px -3px rgba(0,0,0,0.2),0px 10px 14px 1px rgba(0,0,0,0.14),0px 4px 18px 3px rgba(0,0,0,0.12)", + "0px 6px 7px -4px rgba(0,0,0,0.2),0px 11px 15px 1px rgba(0,0,0,0.14),0px 4px 20px 3px rgba(0,0,0,0.12)", + "0px 7px 8px -4px rgba(0,0,0,0.2),0px 12px 17px 2px rgba(0,0,0,0.14),0px 5px 22px 4px rgba(0,0,0,0.12)", + "0px 7px 8px -4px rgba(0,0,0,0.2),0px 13px 19px 2px rgba(0,0,0,0.14),0px 5px 24px 4px rgba(0,0,0,0.12)", + "0px 7px 9px -4px rgba(0,0,0,0.2),0px 14px 21px 2px rgba(0,0,0,0.14),0px 5px 26px 4px rgba(0,0,0,0.12)", + "0px 8px 9px -5px rgba(0,0,0,0.2),0px 15px 22px 2px rgba(0,0,0,0.14),0px 6px 28px 5px rgba(0,0,0,0.12)", + "0px 8px 10px -5px rgba(0,0,0,0.2),0px 16px 24px 2px rgba(0,0,0,0.14),0px 6px 30px 5px rgba(0,0,0,0.12)", + "0px 8px 11px -5px rgba(0,0,0,0.2),0px 17px 26px 2px rgba(0,0,0,0.14),0px 6px 32px 5px rgba(0,0,0,0.12)", + "0px 9px 11px -5px rgba(0,0,0,0.2),0px 18px 28px 2px rgba(0,0,0,0.14),0px 7px 34px 6px rgba(0,0,0,0.12)", + "0px 9px 12px -6px rgba(0,0,0,0.2),0px 19px 29px 2px rgba(0,0,0,0.14),0px 7px 36px 6px rgba(0,0,0,0.12)", + "0px 10px 13px -6px rgba(0,0,0,0.2),0px 20px 31px 3px rgba(0,0,0,0.14),0px 8px 38px 7px rgba(0,0,0,0.12)", + "0px 10px 13px -6px rgba(0,0,0,0.2),0px 21px 33px 3px rgba(0,0,0,0.14),0px 8px 40px 7px rgba(0,0,0,0.12)", + "0px 10px 14px -6px rgba(0,0,0,0.2),0px 22px 35px 3px rgba(0,0,0,0.14),0px 8px 42px 7px rgba(0,0,0,0.12)", + "0px 11px 14px -7px rgba(0,0,0,0.2),0px 23px 36px 3px rgba(0,0,0,0.14),0px 9px 44px 8px rgba(0,0,0,0.12)", + "0px 11px 15px -7px rgba(0,0,0,0.2),0px 24px 38px 3px rgba(0,0,0,0.14),0px 9px 46px 8px rgba(0,0,0,0.12)", + ], + "shape": Object { + "borderRadius": 4, }, - "htmlFontSize": 16, - "overline": Object { - "fontFamily": "\\"Roboto\\", \\"Helvetica\\", \\"Arial\\", sans-serif", - "fontSize": "0.75rem", - "fontWeight": 400, - "letterSpacing": "0.08333em", - "lineHeight": 2.66, - "textTransform": "uppercase", + "spacing": [Function], + "transitions": Object { + "create": [Function], + "duration": Object { + "complex": 375, + "enteringScreen": 225, + "leavingScreen": 195, + "short": 250, + "shorter": 200, + "shortest": 150, + "standard": 300, + }, + "easing": Object { + "easeIn": "cubic-bezier(0.4, 0, 1, 1)", + "easeInOut": "cubic-bezier(0.4, 0, 0.2, 1)", + "easeOut": "cubic-bezier(0.0, 0, 0.2, 1)", + "sharp": "cubic-bezier(0.4, 0, 0.6, 1)", + }, + "getAutoHeightDuration": [Function], }, - "pxToRem": [Function], - "round": [Function], - "subtitle1": Object { + "typography": Object { + "body1": Object { + "fontFamily": "\\"Roboto\\", \\"Helvetica\\", \\"Arial\\", sans-serif", + "fontSize": "1rem", + "fontWeight": 400, + "letterSpacing": "0.00938em", + "lineHeight": 1.5, + }, + "body2": Object { + "fontFamily": "\\"Roboto\\", \\"Helvetica\\", \\"Arial\\", sans-serif", + "fontSize": "0.875rem", + "fontWeight": 400, + "letterSpacing": "0.01071em", + "lineHeight": 1.43, + }, + "button": Object { + "fontFamily": "\\"Roboto\\", \\"Helvetica\\", \\"Arial\\", sans-serif", + "fontSize": "0.875rem", + "fontWeight": 500, + "letterSpacing": "0.02857em", + "lineHeight": 1.75, + "textTransform": "uppercase", + }, + "caption": Object { + "fontFamily": "\\"Roboto\\", \\"Helvetica\\", \\"Arial\\", sans-serif", + "fontSize": "0.75rem", + "fontWeight": 400, + "letterSpacing": "0.03333em", + "lineHeight": 1.66, + }, "fontFamily": "\\"Roboto\\", \\"Helvetica\\", \\"Arial\\", sans-serif", - "fontSize": "1rem", - "fontWeight": 400, - "letterSpacing": "0.00938em", - "lineHeight": 1.75, + "fontSize": 14, + "fontWeightBold": 700, + "fontWeightLight": 300, + "fontWeightMedium": 500, + "fontWeightRegular": 400, + "h1": Object { + "fontFamily": "\\"Roboto\\", \\"Helvetica\\", \\"Arial\\", sans-serif", + "fontSize": "6rem", + "fontWeight": 300, + "letterSpacing": "-0.01562em", + "lineHeight": 1.167, + }, + "h2": Object { + "fontFamily": "\\"Roboto\\", \\"Helvetica\\", \\"Arial\\", sans-serif", + "fontSize": "3.75rem", + "fontWeight": 300, + "letterSpacing": "-0.00833em", + "lineHeight": 1.2, + }, + "h3": Object { + "fontFamily": "\\"Roboto\\", \\"Helvetica\\", \\"Arial\\", sans-serif", + "fontSize": "3rem", + "fontWeight": 400, + "letterSpacing": "0em", + "lineHeight": 1.167, + }, + "h4": Object { + "fontFamily": "\\"Roboto\\", \\"Helvetica\\", \\"Arial\\", sans-serif", + "fontSize": "2.125rem", + "fontWeight": 400, + "letterSpacing": "0.00735em", + "lineHeight": 1.235, + }, + "h5": Object { + "fontFamily": "\\"Roboto\\", \\"Helvetica\\", \\"Arial\\", sans-serif", + "fontSize": "1.5rem", + "fontWeight": 400, + "letterSpacing": "0em", + "lineHeight": 1.334, + }, + "h6": Object { + "fontFamily": "\\"Roboto\\", \\"Helvetica\\", \\"Arial\\", sans-serif", + "fontSize": "1.25rem", + "fontWeight": 500, + "letterSpacing": "0.0075em", + "lineHeight": 1.6, + }, + "htmlFontSize": 16, + "overline": Object { + "fontFamily": "\\"Roboto\\", \\"Helvetica\\", \\"Arial\\", sans-serif", + "fontSize": "0.75rem", + "fontWeight": 400, + "letterSpacing": "0.08333em", + "lineHeight": 2.66, + "textTransform": "uppercase", + }, + "pxToRem": [Function], + "round": [Function], + "subtitle1": Object { + "fontFamily": "\\"Roboto\\", \\"Helvetica\\", \\"Arial\\", sans-serif", + "fontSize": "1rem", + "fontWeight": 400, + "letterSpacing": "0.00938em", + "lineHeight": 1.75, + }, + "subtitle2": Object { + "fontFamily": "\\"Roboto\\", \\"Helvetica\\", \\"Arial\\", sans-serif", + "fontSize": "0.875rem", + "fontWeight": 500, + "letterSpacing": "0.00714em", + "lineHeight": 1.57, + }, }, - "subtitle2": Object { - "fontFamily": "\\"Roboto\\", \\"Helvetica\\", \\"Arial\\", sans-serif", - "fontSize": "0.875rem", - "fontWeight": 500, - "letterSpacing": "0.00714em", - "lineHeight": 1.57, + "zIndex": Object { + "appBar": 1100, + "drawer": 1200, + "mobileStepper": 1000, + "modal": 1300, + "snackbar": 1400, + "speedDial": 1050, + "tooltip": 1500, }, }, - "zIndex": Object { - "appBar": 1100, - "drawer": 1200, - "mobileStepper": 1000, - "modal": 1300, - "snackbar": 1400, - "speedDial": 1050, - "tooltip": 1500, - }, + "name": "MuiBackdrop", }, - "name": "MuiBackdrop", - }, - "propTypes": Object { - "classes": [Function], - "innerRef": [Function], - }, - "render": [Function], - "useStyles": [Function], + "propTypes": Object { + "classes": [Function], + "innerRef": [Function], + }, + "render": [Function], + "useStyles": [Function], + } } - } - BackdropProps={ - Object { - "transitionDuration": Object { - "enter": 225, - "exit": 195, - }, + BackdropProps={ + Object { + "transitionDuration": Object { + "enter": 225, + "exit": 195, + }, + } } - } - className="MuiDialog-root modal-root" - closeAfterTransition={true} - disableEscapeKeyDown={false} - onClose={[Function]} - open={true} - > - <ForwardRef(Portal) - disablePortal={false} + className="MuiDialog-root modal-root" + closeAfterTransition={true} + disableEscapeKeyDown={false} + onClose={[Function]} + open={true} > - <Portal - containerInfo={ - <body - style="padding-right: 0px; overflow: hidden;" - > - <div - class="MuiDialog-root modal-root" - role="presentation" - style="position: fixed; z-index: 1300; right: 0px; bottom: 0px; top: 0px; left: 0px;" + <ForwardRef(Portal) + disablePortal={false} + > + <Portal + containerInfo={ + <body + style="padding-right: 0px; overflow: hidden;" > <div - aria-hidden="true" - class="MuiBackdrop-root" - style="opacity: 1; webkit-transition: opacity 225ms cubic-bezier(0.4, 0, 0.2, 1) 0ms; transition: opacity 225ms cubic-bezier(0.4, 0, 0.2, 1) 0ms;" - /> - <div - data-test="sentinelStart" - tabindex="0" - /> - <div - class="MuiDialog-container MuiDialog-scrollPaper" - role="none presentation" - style="opacity: 1; webkit-transition: opacity 225ms cubic-bezier(0.4, 0, 0.2, 1) 0ms; transition: opacity 225ms cubic-bezier(0.4, 0, 0.2, 1) 0ms;" - tabindex="-1" + class="MuiDialog-root modal-root" + role="presentation" + style="position: fixed; z-index: 1300; right: 0px; bottom: 0px; top: 0px; left: 0px;" > <div - aria-labelledby="accessibility-title" - class="MuiPaper-root MuiDialog-paper modal-paper MuiDialog-paperScrollPaper MuiDialog-paperWidthSm MuiPaper-elevation24 MuiPaper-rounded" - role="dialog" + aria-hidden="true" + class="MuiBackdrop-root" + style="opacity: 1; webkit-transition: opacity 225ms cubic-bezier(0.4, 0, 0.2, 1) 0ms; transition: opacity 225ms cubic-bezier(0.4, 0, 0.2, 1) 0ms;" + /> + <div + data-test="sentinelStart" + tabindex="0" + /> + <div + class="MuiDialog-container MuiDialog-scrollPaper" + role="none presentation" + style="opacity: 1; webkit-transition: opacity 225ms cubic-bezier(0.4, 0, 0.2, 1) 0ms; transition: opacity 225ms cubic-bezier(0.4, 0, 0.2, 1) 0ms;" + tabindex="-1" > <div - id="accessibility-title" - > - feedback.accessibility.window_title - </div> - <button - aria-label="feedback.accessibility.button_close" - class="MuiButtonBase-root MuiIconButton-root modal-paper-close-button" - tabindex="0" - type="button" - > - <span - class="MuiIconButton-label" - > - <svg - class="styles__icon___23x3R" - height="16" - width="16" - > - <use - xlink:href="#test-file-stub" - /> - </svg> - </span> - <span - class="MuiTouchRipple-root" - /> - </button> - <div - class="eg-init-modal" + aria-labelledby="accessibility-title" + class="MuiPaper-root MuiDialog-paper modal-paper MuiDialog-paperScrollPaper MuiDialog-paperWidthSm MuiPaper-elevation24 MuiPaper-rounded" + role="dialog" > <div - class="title text-20-bold" + id="accessibility-title" > - ecogesture.initModal.title + feedback.accessibility.window_title </div> - <div - class="text-16-normal text" + <button + aria-label="feedback.accessibility.button_close" + class="MuiButtonBase-root MuiIconButton-root modal-paper-close-button" + tabindex="0" + type="button" > - ecogesture.initModal.text1 - </div> - <div - class="text-16-normal text" - > - ecogesture.initModal.text2 - </div> + <span + class="MuiIconButton-label" + > + <svg + class="styles__icon___23x3R" + height="16" + width="16" + > + <use + xlink:href="#test-file-stub" + /> + </svg> + </span> + <span + class="MuiTouchRipple-root" + /> + </button> <div - class="buttons-container" + class="eg-init-modal" > - <button - aria-label="ecogesture.initModal.btn1" - class="MuiButtonBase-root MuiButton-root btn-secondary-negative MuiButton-text btn1" - tabindex="0" - type="button" + <div + class="title text-20-bold" > - <span - class="MuiButton-label text-16-bold" - > - ecogesture.initModal.btn1 - </span> - <span - class="MuiTouchRipple-root" - /> - </button> - <button - aria-label="ecogesture.initModal.btn2" - class="MuiButtonBase-root MuiButton-root btn-profile-next rounded MuiButton-text" - tabindex="0" - type="button" + ecogesture.initModal.title + </div> + <div + class="text-16-normal text" > - <span - class="MuiButton-label text-16-bold" + ecogesture.initModal.text1 + </div> + <div + class="text-16-normal text" + > + ecogesture.initModal.text2 + </div> + <div + class="buttons-container" + > + <button + aria-label="ecogesture.initModal.btn1" + class="MuiButtonBase-root MuiButton-root btn-secondary-negative MuiButton-text" + tabindex="0" + type="button" > - ecogesture.initModal.btn2 - </span> - <span - class="MuiTouchRipple-root" - /> - </button> + <span + class="MuiButton-label text-16-bold" + > + ecogesture.initModal.btn1 + </span> + <span + class="MuiTouchRipple-root" + /> + </button> + <button + aria-label="ecogesture.initModal.btn2" + class="MuiButtonBase-root MuiButton-root btn-profile-next rounded MuiButton-text" + tabindex="0" + type="button" + > + <span + class="MuiButton-label text-16-bold" + > + ecogesture.initModal.btn2 + </span> + <span + class="MuiTouchRipple-root" + /> + </button> + </div> </div> </div> </div> + <div + data-test="sentinelEnd" + tabindex="0" + /> </div> - <div - data-test="sentinelEnd" - tabindex="0" - /> - </div> - </body> - } - > - <div - className="MuiDialog-root modal-root" - onKeyDown={[Function]} - role="presentation" - style={ - Object { - "bottom": 0, - "left": 0, - "position": "fixed", - "right": 0, - "top": 0, - "zIndex": 1300, - } + </body> } > - <WithStyles(ForwardRef(Backdrop)) - onClick={[Function]} - open={true} - transitionDuration={ + <div + className="MuiDialog-root modal-root" + onKeyDown={[Function]} + role="presentation" + style={ Object { - "enter": 225, - "exit": 195, + "bottom": 0, + "left": 0, + "position": "fixed", + "right": 0, + "top": 0, + "zIndex": 1300, } } > - <ForwardRef(Backdrop) - classes={ - Object { - "invisible": "MuiBackdrop-invisible", - "root": "MuiBackdrop-root", - } - } + <WithStyles(ForwardRef(Backdrop)) onClick={[Function]} open={true} transitionDuration={ @@ -1780,90 +1769,85 @@ exports[`EcogestureView component should be rendered correctly 1`] = ` } } > - <ForwardRef(Fade) - in={true} + <ForwardRef(Backdrop) + classes={ + Object { + "invisible": "MuiBackdrop-invisible", + "root": "MuiBackdrop-root", + } + } onClick={[Function]} - timeout={ + open={true} + transitionDuration={ Object { "enter": 225, "exit": 195, } } > - <Transition - appear={true} - enter={true} - exit={true} + <ForwardRef(Fade) in={true} - mountOnEnter={false} onClick={[Function]} - onEnter={[Function]} - onEntered={[Function]} - onEntering={[Function]} - onExit={[Function]} - onExited={[Function]} - onExiting={[Function]} timeout={ Object { "enter": 225, "exit": 195, } } - unmountOnExit={false} > - <div - aria-hidden={true} - className="MuiBackdrop-root" + <Transition + appear={true} + enter={true} + exit={true} + in={true} + mountOnEnter={false} onClick={[Function]} - style={ + onEnter={[Function]} + onEntered={[Function]} + onEntering={[Function]} + onExit={[Function]} + onExited={[Function]} + onExiting={[Function]} + timeout={ Object { - "opacity": 1, - "visibility": undefined, + "enter": 225, + "exit": 195, } } - /> - </Transition> - </ForwardRef(Fade)> - </ForwardRef(Backdrop)> - </WithStyles(ForwardRef(Backdrop))> - <Unstable_TrapFocus - disableAutoFocus={false} - disableEnforceFocus={false} - disableRestoreFocus={false} - getDoc={[Function]} - isEnabled={[Function]} - open={true} - > - <div - data-test="sentinelStart" - tabIndex={0} - /> - <ForwardRef(Fade) - appear={true} - in={true} - onEnter={[Function]} - onExited={[Function]} - role="none presentation" - tabIndex="-1" - timeout={ - Object { - "enter": 225, - "exit": 195, - } - } + unmountOnExit={false} + > + <div + aria-hidden={true} + className="MuiBackdrop-root" + onClick={[Function]} + style={ + Object { + "opacity": 1, + "visibility": undefined, + } + } + /> + </Transition> + </ForwardRef(Fade)> + </ForwardRef(Backdrop)> + </WithStyles(ForwardRef(Backdrop))> + <Unstable_TrapFocus + disableAutoFocus={false} + disableEnforceFocus={false} + disableRestoreFocus={false} + getDoc={[Function]} + isEnabled={[Function]} + open={true} > - <Transition + <div + data-test="sentinelStart" + tabIndex={0} + /> + <ForwardRef(Fade) appear={true} - enter={true} - exit={true} in={true} - mountOnEnter={false} onEnter={[Function]} - onEntered={[Function]} - onEntering={[Function]} - onExit={[Function]} onExited={[Function]} - onExiting={[Function]} role="none presentation" tabIndex="-1" timeout={ @@ -1872,290 +1856,292 @@ exports[`EcogestureView component should be rendered correctly 1`] = ` "exit": 195, } } - unmountOnExit={false} > - <div - className="MuiDialog-container MuiDialog-scrollPaper" - onMouseDown={[Function]} - onMouseUp={[Function]} + <Transition + appear={true} + enter={true} + exit={true} + in={true} + mountOnEnter={false} + onEnter={[Function]} + onEntered={[Function]} + onEntering={[Function]} + onExit={[Function]} + onExited={[Function]} + onExiting={[Function]} role="none presentation" - style={ + tabIndex="-1" + timeout={ Object { - "opacity": 1, - "visibility": undefined, + "enter": 225, + "exit": 195, } } - tabIndex="-1" + unmountOnExit={false} > - <WithStyles(ForwardRef(Paper)) - aria-labelledby="accessibility-title" - className="MuiDialog-paper modal-paper MuiDialog-paperScrollPaper MuiDialog-paperWidthSm" - elevation={24} - role="dialog" + <div + className="MuiDialog-container MuiDialog-scrollPaper" + onMouseDown={[Function]} + onMouseUp={[Function]} + role="none presentation" + style={ + Object { + "opacity": 1, + "visibility": undefined, + } + } + tabIndex="-1" > - <ForwardRef(Paper) + <WithStyles(ForwardRef(Paper)) aria-labelledby="accessibility-title" className="MuiDialog-paper modal-paper MuiDialog-paperScrollPaper MuiDialog-paperWidthSm" - classes={ - Object { - "elevation0": "MuiPaper-elevation0", - "elevation1": "MuiPaper-elevation1", - "elevation10": "MuiPaper-elevation10", - "elevation11": "MuiPaper-elevation11", - "elevation12": "MuiPaper-elevation12", - "elevation13": "MuiPaper-elevation13", - "elevation14": "MuiPaper-elevation14", - "elevation15": "MuiPaper-elevation15", - "elevation16": "MuiPaper-elevation16", - "elevation17": "MuiPaper-elevation17", - "elevation18": "MuiPaper-elevation18", - "elevation19": "MuiPaper-elevation19", - "elevation2": "MuiPaper-elevation2", - "elevation20": "MuiPaper-elevation20", - "elevation21": "MuiPaper-elevation21", - "elevation22": "MuiPaper-elevation22", - "elevation23": "MuiPaper-elevation23", - "elevation24": "MuiPaper-elevation24", - "elevation3": "MuiPaper-elevation3", - "elevation4": "MuiPaper-elevation4", - "elevation5": "MuiPaper-elevation5", - "elevation6": "MuiPaper-elevation6", - "elevation7": "MuiPaper-elevation7", - "elevation8": "MuiPaper-elevation8", - "elevation9": "MuiPaper-elevation9", - "outlined": "MuiPaper-outlined", - "root": "MuiPaper-root", - "rounded": "MuiPaper-rounded", - } - } elevation={24} role="dialog" > - <div + <ForwardRef(Paper) aria-labelledby="accessibility-title" - className="MuiPaper-root MuiDialog-paper modal-paper MuiDialog-paperScrollPaper MuiDialog-paperWidthSm MuiPaper-elevation24 MuiPaper-rounded" + className="MuiDialog-paper modal-paper MuiDialog-paperScrollPaper MuiDialog-paperWidthSm" + classes={ + Object { + "elevation0": "MuiPaper-elevation0", + "elevation1": "MuiPaper-elevation1", + "elevation10": "MuiPaper-elevation10", + "elevation11": "MuiPaper-elevation11", + "elevation12": "MuiPaper-elevation12", + "elevation13": "MuiPaper-elevation13", + "elevation14": "MuiPaper-elevation14", + "elevation15": "MuiPaper-elevation15", + "elevation16": "MuiPaper-elevation16", + "elevation17": "MuiPaper-elevation17", + "elevation18": "MuiPaper-elevation18", + "elevation19": "MuiPaper-elevation19", + "elevation2": "MuiPaper-elevation2", + "elevation20": "MuiPaper-elevation20", + "elevation21": "MuiPaper-elevation21", + "elevation22": "MuiPaper-elevation22", + "elevation23": "MuiPaper-elevation23", + "elevation24": "MuiPaper-elevation24", + "elevation3": "MuiPaper-elevation3", + "elevation4": "MuiPaper-elevation4", + "elevation5": "MuiPaper-elevation5", + "elevation6": "MuiPaper-elevation6", + "elevation7": "MuiPaper-elevation7", + "elevation8": "MuiPaper-elevation8", + "elevation9": "MuiPaper-elevation9", + "outlined": "MuiPaper-outlined", + "root": "MuiPaper-root", + "rounded": "MuiPaper-rounded", + } + } + elevation={24} role="dialog" > <div - id="accessibility-title" + aria-labelledby="accessibility-title" + className="MuiPaper-root MuiDialog-paper modal-paper MuiDialog-paperScrollPaper MuiDialog-paperWidthSm MuiPaper-elevation24 MuiPaper-rounded" + role="dialog" > - feedback.accessibility.window_title - </div> - <WithStyles(ForwardRef(IconButton)) - aria-label="feedback.accessibility.button_close" - className="modal-paper-close-button" - onClick={[Function]} - > - <ForwardRef(IconButton) + <div + id="accessibility-title" + > + feedback.accessibility.window_title + </div> + <WithStyles(ForwardRef(IconButton)) aria-label="feedback.accessibility.button_close" className="modal-paper-close-button" - classes={ - Object { - "colorInherit": "MuiIconButton-colorInherit", - "colorPrimary": "MuiIconButton-colorPrimary", - "colorSecondary": "MuiIconButton-colorSecondary", - "disabled": "Mui-disabled", - "edgeEnd": "MuiIconButton-edgeEnd", - "edgeStart": "MuiIconButton-edgeStart", - "label": "MuiIconButton-label", - "root": "MuiIconButton-root", - "sizeSmall": "MuiIconButton-sizeSmall", - } - } onClick={[Function]} > - <WithStyles(ForwardRef(ButtonBase)) + <ForwardRef(IconButton) aria-label="feedback.accessibility.button_close" - centerRipple={true} - className="MuiIconButton-root modal-paper-close-button" - disabled={false} - focusRipple={true} + className="modal-paper-close-button" + classes={ + Object { + "colorInherit": "MuiIconButton-colorInherit", + "colorPrimary": "MuiIconButton-colorPrimary", + "colorSecondary": "MuiIconButton-colorSecondary", + "disabled": "Mui-disabled", + "edgeEnd": "MuiIconButton-edgeEnd", + "edgeStart": "MuiIconButton-edgeStart", + "label": "MuiIconButton-label", + "root": "MuiIconButton-root", + "sizeSmall": "MuiIconButton-sizeSmall", + } + } onClick={[Function]} > - <ForwardRef(ButtonBase) + <WithStyles(ForwardRef(ButtonBase)) aria-label="feedback.accessibility.button_close" centerRipple={true} className="MuiIconButton-root modal-paper-close-button" - classes={ - Object { - "disabled": "Mui-disabled", - "focusVisible": "Mui-focusVisible", - "root": "MuiButtonBase-root", - } - } disabled={false} focusRipple={true} onClick={[Function]} > - <button + <ForwardRef(ButtonBase) aria-label="feedback.accessibility.button_close" - className="MuiButtonBase-root MuiIconButton-root modal-paper-close-button" + centerRipple={true} + className="MuiIconButton-root modal-paper-close-button" + classes={ + Object { + "disabled": "Mui-disabled", + "focusVisible": "Mui-focusVisible", + "root": "MuiButtonBase-root", + } + } disabled={false} - onBlur={[Function]} + focusRipple={true} onClick={[Function]} - onDragLeave={[Function]} - onFocus={[Function]} - onKeyDown={[Function]} - onKeyUp={[Function]} - onMouseDown={[Function]} - onMouseLeave={[Function]} - onMouseUp={[Function]} - onTouchEnd={[Function]} - onTouchMove={[Function]} - onTouchStart={[Function]} - tabIndex={0} - type="button" > - <span - className="MuiIconButton-label" + <button + aria-label="feedback.accessibility.button_close" + className="MuiButtonBase-root MuiIconButton-root modal-paper-close-button" + disabled={false} + onBlur={[Function]} + onClick={[Function]} + onDragLeave={[Function]} + onFocus={[Function]} + onKeyDown={[Function]} + onKeyUp={[Function]} + onMouseDown={[Function]} + onMouseLeave={[Function]} + onMouseUp={[Function]} + onTouchEnd={[Function]} + onTouchMove={[Function]} + onTouchStart={[Function]} + tabIndex={0} + type="button" > - <Icon - icon="test-file-stub" - size={16} - spin={false} + <span + className="MuiIconButton-label" > - <Component - className="styles__icon___23x3R" - height={16} - style={Object {}} - width={16} + <Icon + icon="test-file-stub" + size={16} + spin={false} > - <svg + <Component className="styles__icon___23x3R" height={16} style={Object {}} width={16} > - <use - xlinkHref="#test-file-stub" - /> - </svg> - </Component> - </Icon> - </span> - <WithStyles(memo) - center={true} - > - <ForwardRef(TouchRipple) + <svg + className="styles__icon___23x3R" + height={16} + style={Object {}} + width={16} + > + <use + xlinkHref="#test-file-stub" + /> + </svg> + </Component> + </Icon> + </span> + <WithStyles(memo) center={true} - classes={ - Object { - "child": "MuiTouchRipple-child", - "childLeaving": "MuiTouchRipple-childLeaving", - "childPulsate": "MuiTouchRipple-childPulsate", - "ripple": "MuiTouchRipple-ripple", - "ripplePulsate": "MuiTouchRipple-ripplePulsate", - "rippleVisible": "MuiTouchRipple-rippleVisible", - "root": "MuiTouchRipple-root", - } - } > - <span - className="MuiTouchRipple-root" + <ForwardRef(TouchRipple) + center={true} + classes={ + Object { + "child": "MuiTouchRipple-child", + "childLeaving": "MuiTouchRipple-childLeaving", + "childPulsate": "MuiTouchRipple-childPulsate", + "ripple": "MuiTouchRipple-ripple", + "ripplePulsate": "MuiTouchRipple-ripplePulsate", + "rippleVisible": "MuiTouchRipple-rippleVisible", + "root": "MuiTouchRipple-root", + } + } > - <TransitionGroup - childFactory={[Function]} - component={null} - exit={true} - /> - </span> - </ForwardRef(TouchRipple)> - </WithStyles(memo)> - </button> - </ForwardRef(ButtonBase)> - </WithStyles(ForwardRef(ButtonBase))> - </ForwardRef(IconButton)> - </WithStyles(ForwardRef(IconButton))> - <div - className="eg-init-modal" - > - <div - className="title text-20-bold" - > - ecogesture.initModal.title - </div> - <div - className="text-16-normal text" - > - ecogesture.initModal.text1 - </div> - <div - className="text-16-normal text" - > - ecogesture.initModal.text2 - </div> + <span + className="MuiTouchRipple-root" + > + <TransitionGroup + childFactory={[Function]} + component={null} + exit={true} + /> + </span> + </ForwardRef(TouchRipple)> + </WithStyles(memo)> + </button> + </ForwardRef(ButtonBase)> + </WithStyles(ForwardRef(ButtonBase))> + </ForwardRef(IconButton)> + </WithStyles(ForwardRef(IconButton))> <div - className="buttons-container" + className="eg-init-modal" > - <WithStyles(ForwardRef(Button)) - aria-label="ecogesture.initModal.btn1" - className="btn1" - classes={ - Object { - "label": "text-16-bold", - "root": "btn-secondary-negative", - } - } - onClick={[Function]} + <div + className="title text-20-bold" + > + ecogesture.initModal.title + </div> + <div + className="text-16-normal text" + > + ecogesture.initModal.text1 + </div> + <div + className="text-16-normal text" > - <ForwardRef(Button) + ecogesture.initModal.text2 + </div> + <div + className="buttons-container" + > + <WithStyles(ForwardRef(Button)) aria-label="ecogesture.initModal.btn1" - className="btn1" classes={ Object { - "colorInherit": "MuiButton-colorInherit", - "contained": "MuiButton-contained", - "containedPrimary": "MuiButton-containedPrimary", - "containedSecondary": "MuiButton-containedSecondary", - "containedSizeLarge": "MuiButton-containedSizeLarge", - "containedSizeSmall": "MuiButton-containedSizeSmall", - "disableElevation": "MuiButton-disableElevation", - "disabled": "Mui-disabled", - "endIcon": "MuiButton-endIcon", - "focusVisible": "Mui-focusVisible", - "fullWidth": "MuiButton-fullWidth", - "iconSizeLarge": "MuiButton-iconSizeLarge", - "iconSizeMedium": "MuiButton-iconSizeMedium", - "iconSizeSmall": "MuiButton-iconSizeSmall", - "label": "MuiButton-label text-16-bold", - "outlined": "MuiButton-outlined", - "outlinedPrimary": "MuiButton-outlinedPrimary", - "outlinedSecondary": "MuiButton-outlinedSecondary", - "outlinedSizeLarge": "MuiButton-outlinedSizeLarge", - "outlinedSizeSmall": "MuiButton-outlinedSizeSmall", - "root": "MuiButton-root btn-secondary-negative", - "sizeLarge": "MuiButton-sizeLarge", - "sizeSmall": "MuiButton-sizeSmall", - "startIcon": "MuiButton-startIcon", - "text": "MuiButton-text", - "textPrimary": "MuiButton-textPrimary", - "textSecondary": "MuiButton-textSecondary", - "textSizeLarge": "MuiButton-textSizeLarge", - "textSizeSmall": "MuiButton-textSizeSmall", + "label": "text-16-bold", + "root": "btn-secondary-negative", } } onClick={[Function]} > - <WithStyles(ForwardRef(ButtonBase)) + <ForwardRef(Button) aria-label="ecogesture.initModal.btn1" - className="MuiButton-root btn-secondary-negative MuiButton-text btn1" - component="button" - disabled={false} - focusRipple={true} - focusVisibleClassName="Mui-focusVisible" + classes={ + Object { + "colorInherit": "MuiButton-colorInherit", + "contained": "MuiButton-contained", + "containedPrimary": "MuiButton-containedPrimary", + "containedSecondary": "MuiButton-containedSecondary", + "containedSizeLarge": "MuiButton-containedSizeLarge", + "containedSizeSmall": "MuiButton-containedSizeSmall", + "disableElevation": "MuiButton-disableElevation", + "disabled": "Mui-disabled", + "endIcon": "MuiButton-endIcon", + "focusVisible": "Mui-focusVisible", + "fullWidth": "MuiButton-fullWidth", + "iconSizeLarge": "MuiButton-iconSizeLarge", + "iconSizeMedium": "MuiButton-iconSizeMedium", + "iconSizeSmall": "MuiButton-iconSizeSmall", + "label": "MuiButton-label text-16-bold", + "outlined": "MuiButton-outlined", + "outlinedPrimary": "MuiButton-outlinedPrimary", + "outlinedSecondary": "MuiButton-outlinedSecondary", + "outlinedSizeLarge": "MuiButton-outlinedSizeLarge", + "outlinedSizeSmall": "MuiButton-outlinedSizeSmall", + "root": "MuiButton-root btn-secondary-negative", + "sizeLarge": "MuiButton-sizeLarge", + "sizeSmall": "MuiButton-sizeSmall", + "startIcon": "MuiButton-startIcon", + "text": "MuiButton-text", + "textPrimary": "MuiButton-textPrimary", + "textSecondary": "MuiButton-textSecondary", + "textSizeLarge": "MuiButton-textSizeLarge", + "textSizeSmall": "MuiButton-textSizeSmall", + } + } onClick={[Function]} - type="button" > - <ForwardRef(ButtonBase) + <WithStyles(ForwardRef(ButtonBase)) aria-label="ecogesture.initModal.btn1" - className="MuiButton-root btn-secondary-negative MuiButton-text btn1" - classes={ - Object { - "disabled": "Mui-disabled", - "focusVisible": "Mui-focusVisible", - "root": "MuiButtonBase-root", - } - } + className="MuiButton-root btn-secondary-negative MuiButton-text" component="button" disabled={false} focusRipple={true} @@ -2163,130 +2149,130 @@ exports[`EcogestureView component should be rendered correctly 1`] = ` onClick={[Function]} type="button" > - <button + <ForwardRef(ButtonBase) aria-label="ecogesture.initModal.btn1" - className="MuiButtonBase-root MuiButton-root btn-secondary-negative MuiButton-text btn1" + className="MuiButton-root btn-secondary-negative MuiButton-text" + classes={ + Object { + "disabled": "Mui-disabled", + "focusVisible": "Mui-focusVisible", + "root": "MuiButtonBase-root", + } + } + component="button" disabled={false} - onBlur={[Function]} + focusRipple={true} + focusVisibleClassName="Mui-focusVisible" onClick={[Function]} - onDragLeave={[Function]} - onFocus={[Function]} - onKeyDown={[Function]} - onKeyUp={[Function]} - onMouseDown={[Function]} - onMouseLeave={[Function]} - onMouseUp={[Function]} - onTouchEnd={[Function]} - onTouchMove={[Function]} - onTouchStart={[Function]} - tabIndex={0} type="button" > - <span - className="MuiButton-label text-16-bold" + <button + aria-label="ecogesture.initModal.btn1" + className="MuiButtonBase-root MuiButton-root btn-secondary-negative MuiButton-text" + disabled={false} + onBlur={[Function]} + onClick={[Function]} + onDragLeave={[Function]} + onFocus={[Function]} + onKeyDown={[Function]} + onKeyUp={[Function]} + onMouseDown={[Function]} + onMouseLeave={[Function]} + onMouseUp={[Function]} + onTouchEnd={[Function]} + onTouchMove={[Function]} + onTouchStart={[Function]} + tabIndex={0} + type="button" > - ecogesture.initModal.btn1 - </span> - <WithStyles(memo) - center={false} - > - <ForwardRef(TouchRipple) + <span + className="MuiButton-label text-16-bold" + > + ecogesture.initModal.btn1 + </span> + <WithStyles(memo) center={false} - classes={ - Object { - "child": "MuiTouchRipple-child", - "childLeaving": "MuiTouchRipple-childLeaving", - "childPulsate": "MuiTouchRipple-childPulsate", - "ripple": "MuiTouchRipple-ripple", - "ripplePulsate": "MuiTouchRipple-ripplePulsate", - "rippleVisible": "MuiTouchRipple-rippleVisible", - "root": "MuiTouchRipple-root", - } - } > - <span - className="MuiTouchRipple-root" + <ForwardRef(TouchRipple) + center={false} + classes={ + Object { + "child": "MuiTouchRipple-child", + "childLeaving": "MuiTouchRipple-childLeaving", + "childPulsate": "MuiTouchRipple-childPulsate", + "ripple": "MuiTouchRipple-ripple", + "ripplePulsate": "MuiTouchRipple-ripplePulsate", + "rippleVisible": "MuiTouchRipple-rippleVisible", + "root": "MuiTouchRipple-root", + } + } > - <TransitionGroup - childFactory={[Function]} - component={null} - exit={true} - /> - </span> - </ForwardRef(TouchRipple)> - </WithStyles(memo)> - </button> - </ForwardRef(ButtonBase)> - </WithStyles(ForwardRef(ButtonBase))> - </ForwardRef(Button)> - </WithStyles(ForwardRef(Button))> - <WithStyles(ForwardRef(Button)) - aria-label="ecogesture.initModal.btn2" - classes={ - Object { - "label": "text-16-bold", - "root": "btn-profile-next rounded", - } - } - onClick={[Function]} - > - <ForwardRef(Button) + <span + className="MuiTouchRipple-root" + > + <TransitionGroup + childFactory={[Function]} + component={null} + exit={true} + /> + </span> + </ForwardRef(TouchRipple)> + </WithStyles(memo)> + </button> + </ForwardRef(ButtonBase)> + </WithStyles(ForwardRef(ButtonBase))> + </ForwardRef(Button)> + </WithStyles(ForwardRef(Button))> + <WithStyles(ForwardRef(Button)) aria-label="ecogesture.initModal.btn2" classes={ Object { - "colorInherit": "MuiButton-colorInherit", - "contained": "MuiButton-contained", - "containedPrimary": "MuiButton-containedPrimary", - "containedSecondary": "MuiButton-containedSecondary", - "containedSizeLarge": "MuiButton-containedSizeLarge", - "containedSizeSmall": "MuiButton-containedSizeSmall", - "disableElevation": "MuiButton-disableElevation", - "disabled": "Mui-disabled", - "endIcon": "MuiButton-endIcon", - "focusVisible": "Mui-focusVisible", - "fullWidth": "MuiButton-fullWidth", - "iconSizeLarge": "MuiButton-iconSizeLarge", - "iconSizeMedium": "MuiButton-iconSizeMedium", - "iconSizeSmall": "MuiButton-iconSizeSmall", - "label": "MuiButton-label text-16-bold", - "outlined": "MuiButton-outlined", - "outlinedPrimary": "MuiButton-outlinedPrimary", - "outlinedSecondary": "MuiButton-outlinedSecondary", - "outlinedSizeLarge": "MuiButton-outlinedSizeLarge", - "outlinedSizeSmall": "MuiButton-outlinedSizeSmall", - "root": "MuiButton-root btn-profile-next rounded", - "sizeLarge": "MuiButton-sizeLarge", - "sizeSmall": "MuiButton-sizeSmall", - "startIcon": "MuiButton-startIcon", - "text": "MuiButton-text", - "textPrimary": "MuiButton-textPrimary", - "textSecondary": "MuiButton-textSecondary", - "textSizeLarge": "MuiButton-textSizeLarge", - "textSizeSmall": "MuiButton-textSizeSmall", + "label": "text-16-bold", + "root": "btn-profile-next rounded", } } onClick={[Function]} > - <WithStyles(ForwardRef(ButtonBase)) + <ForwardRef(Button) aria-label="ecogesture.initModal.btn2" - className="MuiButton-root btn-profile-next rounded MuiButton-text" - component="button" - disabled={false} - focusRipple={true} - focusVisibleClassName="Mui-focusVisible" + classes={ + Object { + "colorInherit": "MuiButton-colorInherit", + "contained": "MuiButton-contained", + "containedPrimary": "MuiButton-containedPrimary", + "containedSecondary": "MuiButton-containedSecondary", + "containedSizeLarge": "MuiButton-containedSizeLarge", + "containedSizeSmall": "MuiButton-containedSizeSmall", + "disableElevation": "MuiButton-disableElevation", + "disabled": "Mui-disabled", + "endIcon": "MuiButton-endIcon", + "focusVisible": "Mui-focusVisible", + "fullWidth": "MuiButton-fullWidth", + "iconSizeLarge": "MuiButton-iconSizeLarge", + "iconSizeMedium": "MuiButton-iconSizeMedium", + "iconSizeSmall": "MuiButton-iconSizeSmall", + "label": "MuiButton-label text-16-bold", + "outlined": "MuiButton-outlined", + "outlinedPrimary": "MuiButton-outlinedPrimary", + "outlinedSecondary": "MuiButton-outlinedSecondary", + "outlinedSizeLarge": "MuiButton-outlinedSizeLarge", + "outlinedSizeSmall": "MuiButton-outlinedSizeSmall", + "root": "MuiButton-root btn-profile-next rounded", + "sizeLarge": "MuiButton-sizeLarge", + "sizeSmall": "MuiButton-sizeSmall", + "startIcon": "MuiButton-startIcon", + "text": "MuiButton-text", + "textPrimary": "MuiButton-textPrimary", + "textSecondary": "MuiButton-textSecondary", + "textSizeLarge": "MuiButton-textSizeLarge", + "textSizeSmall": "MuiButton-textSizeSmall", + } + } onClick={[Function]} - type="button" > - <ForwardRef(ButtonBase) + <WithStyles(ForwardRef(ButtonBase)) aria-label="ecogesture.initModal.btn2" className="MuiButton-root btn-profile-next rounded MuiButton-text" - classes={ - Object { - "disabled": "Mui-disabled", - "focusVisible": "Mui-focusVisible", - "root": "MuiButtonBase-root", - } - } component="button" disabled={false} focusRipple={true} @@ -2294,83 +2280,101 @@ exports[`EcogestureView component should be rendered correctly 1`] = ` onClick={[Function]} type="button" > - <button + <ForwardRef(ButtonBase) aria-label="ecogesture.initModal.btn2" - className="MuiButtonBase-root MuiButton-root btn-profile-next rounded MuiButton-text" + className="MuiButton-root btn-profile-next rounded MuiButton-text" + classes={ + Object { + "disabled": "Mui-disabled", + "focusVisible": "Mui-focusVisible", + "root": "MuiButtonBase-root", + } + } + component="button" disabled={false} - onBlur={[Function]} + focusRipple={true} + focusVisibleClassName="Mui-focusVisible" onClick={[Function]} - onDragLeave={[Function]} - onFocus={[Function]} - onKeyDown={[Function]} - onKeyUp={[Function]} - onMouseDown={[Function]} - onMouseLeave={[Function]} - onMouseUp={[Function]} - onTouchEnd={[Function]} - onTouchMove={[Function]} - onTouchStart={[Function]} - tabIndex={0} type="button" > - <span - className="MuiButton-label text-16-bold" - > - ecogesture.initModal.btn2 - </span> - <WithStyles(memo) - center={false} + <button + aria-label="ecogesture.initModal.btn2" + className="MuiButtonBase-root MuiButton-root btn-profile-next rounded MuiButton-text" + disabled={false} + onBlur={[Function]} + onClick={[Function]} + onDragLeave={[Function]} + onFocus={[Function]} + onKeyDown={[Function]} + onKeyUp={[Function]} + onMouseDown={[Function]} + onMouseLeave={[Function]} + onMouseUp={[Function]} + onTouchEnd={[Function]} + onTouchMove={[Function]} + onTouchStart={[Function]} + tabIndex={0} + type="button" > - <ForwardRef(TouchRipple) + <span + className="MuiButton-label text-16-bold" + > + ecogesture.initModal.btn2 + </span> + <WithStyles(memo) center={false} - classes={ - Object { - "child": "MuiTouchRipple-child", - "childLeaving": "MuiTouchRipple-childLeaving", - "childPulsate": "MuiTouchRipple-childPulsate", - "ripple": "MuiTouchRipple-ripple", - "ripplePulsate": "MuiTouchRipple-ripplePulsate", - "rippleVisible": "MuiTouchRipple-rippleVisible", - "root": "MuiTouchRipple-root", - } - } > - <span - className="MuiTouchRipple-root" + <ForwardRef(TouchRipple) + center={false} + classes={ + Object { + "child": "MuiTouchRipple-child", + "childLeaving": "MuiTouchRipple-childLeaving", + "childPulsate": "MuiTouchRipple-childPulsate", + "ripple": "MuiTouchRipple-ripple", + "ripplePulsate": "MuiTouchRipple-ripplePulsate", + "rippleVisible": "MuiTouchRipple-rippleVisible", + "root": "MuiTouchRipple-root", + } + } > - <TransitionGroup - childFactory={[Function]} - component={null} - exit={true} - /> - </span> - </ForwardRef(TouchRipple)> - </WithStyles(memo)> - </button> - </ForwardRef(ButtonBase)> - </WithStyles(ForwardRef(ButtonBase))> - </ForwardRef(Button)> - </WithStyles(ForwardRef(Button))> + <span + className="MuiTouchRipple-root" + > + <TransitionGroup + childFactory={[Function]} + component={null} + exit={true} + /> + </span> + </ForwardRef(TouchRipple)> + </WithStyles(memo)> + </button> + </ForwardRef(ButtonBase)> + </WithStyles(ForwardRef(ButtonBase))> + </ForwardRef(Button)> + </WithStyles(ForwardRef(Button))> + </div> </div> </div> - </div> - </ForwardRef(Paper)> - </WithStyles(ForwardRef(Paper))> - </div> - </Transition> - </ForwardRef(Fade)> - <div - data-test="sentinelEnd" - tabIndex={0} - /> - </Unstable_TrapFocus> - </div> - </Portal> - </ForwardRef(Portal)> - </ForwardRef(Modal)> - </ForwardRef(Dialog)> - </WithStyles(ForwardRef(Dialog))> - </EcogestureInitModal> - </EcogestureView> + </ForwardRef(Paper)> + </WithStyles(ForwardRef(Paper))> + </div> + </Transition> + </ForwardRef(Fade)> + <div + data-test="sentinelEnd" + tabIndex={0} + /> + </Unstable_TrapFocus> + </div> + </Portal> + </ForwardRef(Portal)> + </ForwardRef(Modal)> + </ForwardRef(Dialog)> + </WithStyles(ForwardRef(Dialog))> + </EcogestureInitModal> + </mock-content> + </EcogestureTabsView> </Provider> `; diff --git a/src/components/Ecogesture/__snapshots__/EfficiencyRating.spec.tsx.snap b/src/components/Ecogesture/__snapshots__/EfficiencyRating.spec.tsx.snap deleted file mode 100644 index 005c98b343ca3a95b56c1e53021a4a3b077dd3de..0000000000000000000000000000000000000000 --- a/src/components/Ecogesture/__snapshots__/EfficiencyRating.spec.tsx.snap +++ /dev/null @@ -1,195 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`EfficiencyRating component should be rendered correctly 1`] = ` -<Provider - store={ - Object { - "clearActions": [Function], - "dispatch": [Function], - "getActions": [Function], - "getState": [Function], - "replaceReducer": [Function], - "subscribe": [Function], - } - } -> - <EfficiencyRating - result={3} - > - <div - className="thunder" - > - <StyledIcon - className="star" - icon="test-file-stub" - key="1" - size={15} - > - <Icon - aria-hidden={true} - className="star" - icon="test-file-stub" - size={15} - spin={false} - > - <Component - aria-hidden={true} - className="star styles__icon___23x3R" - height={15} - style={Object {}} - width={15} - > - <svg - aria-hidden={true} - className="star styles__icon___23x3R" - height={15} - style={Object {}} - width={15} - > - <use - xlinkHref="#test-file-stub" - /> - </svg> - </Component> - </Icon> - </StyledIcon> - <StyledIcon - className="star" - icon="test-file-stub" - key="2" - size={15} - > - <Icon - aria-hidden={true} - className="star" - icon="test-file-stub" - size={15} - spin={false} - > - <Component - aria-hidden={true} - className="star styles__icon___23x3R" - height={15} - style={Object {}} - width={15} - > - <svg - aria-hidden={true} - className="star styles__icon___23x3R" - height={15} - style={Object {}} - width={15} - > - <use - xlinkHref="#test-file-stub" - /> - </svg> - </Component> - </Icon> - </StyledIcon> - <StyledIcon - className="star" - icon="test-file-stub" - key="3" - size={15} - > - <Icon - aria-hidden={true} - className="star" - icon="test-file-stub" - size={15} - spin={false} - > - <Component - aria-hidden={true} - className="star styles__icon___23x3R" - height={15} - style={Object {}} - width={15} - > - <svg - aria-hidden={true} - className="star styles__icon___23x3R" - height={15} - style={Object {}} - width={15} - > - <use - xlinkHref="#test-file-stub" - /> - </svg> - </Component> - </Icon> - </StyledIcon> - <StyledIcon - className="star" - icon="test-file-stub" - key="4" - size={15} - > - <Icon - aria-hidden={true} - className="star" - icon="test-file-stub" - size={15} - spin={false} - > - <Component - aria-hidden={true} - className="star styles__icon___23x3R" - height={15} - style={Object {}} - width={15} - > - <svg - aria-hidden={true} - className="star styles__icon___23x3R" - height={15} - style={Object {}} - width={15} - > - <use - xlinkHref="#test-file-stub" - /> - </svg> - </Component> - </Icon> - </StyledIcon> - <StyledIcon - className="star" - icon="test-file-stub" - key="5" - size={15} - > - <Icon - aria-hidden={true} - className="star" - icon="test-file-stub" - size={15} - spin={false} - > - <Component - aria-hidden={true} - className="star styles__icon___23x3R" - height={15} - style={Object {}} - width={15} - > - <svg - aria-hidden={true} - className="star styles__icon___23x3R" - height={15} - style={Object {}} - width={15} - > - <use - xlinkHref="#test-file-stub" - /> - </svg> - </Component> - </Icon> - </StyledIcon> - </div> - </EfficiencyRating> -</Provider> -`; diff --git a/src/components/Ecogesture/__snapshots__/SingleEcogesture.spec.tsx.snap b/src/components/Ecogesture/__snapshots__/SingleEcogesture.spec.tsx.snap deleted file mode 100644 index 2eb812c6fea8317a280b716740e2bb8956c4dd16..0000000000000000000000000000000000000000 --- a/src/components/Ecogesture/__snapshots__/SingleEcogesture.spec.tsx.snap +++ /dev/null @@ -1,368 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`SingleEcogesture component should be rendered correctly 1`] = ` -<Provider - store={ - Object { - "clearActions": [Function], - "dispatch": [Function], - "getActions": [Function], - "getState": [Function], - "replaceReducer": [Function], - "subscribe": [Function], - } - } -> - <SingleEcogesture> - <Component - backFunction={[Function]} - displayBackArrow={true} - titleKey="common.title_ecogesture" - > - <div - id="CozyBar" - /> - </Component> - <Component - desktopTitleKey="common.title_ecogesture" - displayBackArrow={true} - setHeaderHeight={[Function]} - > - <div - id="Header" - /> - </Component> - <Component - height={0} - > - <div - id="content" - > - <div - className="single-ecogesture" - > - <div - className="icon-container" - /> - <div - className="details" - > - <div - className="text-22 title" - > - Bonhomme de neige - </div> - <div - className="efficiency" - > - <span - className="text text-14-normal" - > - ecogesture_modal.efficiency - </span> - <Component - result={4} - > - <div - id="EfficiencyRating" - /> - </Component> - </div> - </div> - <div - className="styled-container" - > - <div - className="long-name text-18-bold" - > - Je baisse le chauffage en mode hors gel lorsque je m'absente plus de 2 jours. - </div> - <div - className="toggle-text text-15-normal" - onClick={[Function]} - role="button" - > - ecogesture_modal.show_more - </div> - <div - className="description text-16-normal-150" - > - On se demande parfois si cela vaut le coup de "couper le chauffage" quand on s’absente… dès qu’il s’agit d’un week-end la réponse est « oui sûrement » ! Attention cependant au retour à ne pas faire de la surchauffe ! L’idéal est bien évidemment de régler sa programmation pour que le chauffage se relance quelques heures avant votre retour… - </div> - </div> - <div - className="buttons-selection" - > - <WithStyles(ForwardRef(IconButton)) - aria-label="ecogesture.objective" - classes={ - Object { - "label": "text-15-normal", - "root": "btn-secondary-negative objective-btn false", - } - } - onClick={[Function]} - > - <ForwardRef(IconButton) - aria-label="ecogesture.objective" - classes={ - Object { - "colorInherit": "MuiIconButton-colorInherit", - "colorPrimary": "MuiIconButton-colorPrimary", - "colorSecondary": "MuiIconButton-colorSecondary", - "disabled": "Mui-disabled", - "edgeEnd": "MuiIconButton-edgeEnd", - "edgeStart": "MuiIconButton-edgeStart", - "label": "MuiIconButton-label text-15-normal", - "root": "MuiIconButton-root btn-secondary-negative objective-btn false", - "sizeSmall": "MuiIconButton-sizeSmall", - } - } - onClick={[Function]} - > - <WithStyles(ForwardRef(ButtonBase)) - aria-label="ecogesture.objective" - centerRipple={true} - className="MuiIconButton-root btn-secondary-negative objective-btn false" - disabled={false} - focusRipple={true} - onClick={[Function]} - > - <ForwardRef(ButtonBase) - aria-label="ecogesture.objective" - centerRipple={true} - className="MuiIconButton-root btn-secondary-negative objective-btn false" - classes={ - Object { - "disabled": "Mui-disabled", - "focusVisible": "Mui-focusVisible", - "root": "MuiButtonBase-root", - } - } - disabled={false} - focusRipple={true} - onClick={[Function]} - > - <button - aria-label="ecogesture.objective" - className="MuiButtonBase-root MuiIconButton-root btn-secondary-negative objective-btn false" - disabled={false} - onBlur={[Function]} - onClick={[Function]} - onDragLeave={[Function]} - onFocus={[Function]} - onKeyDown={[Function]} - onKeyUp={[Function]} - onMouseDown={[Function]} - onMouseLeave={[Function]} - onMouseUp={[Function]} - onTouchEnd={[Function]} - onTouchMove={[Function]} - onTouchStart={[Function]} - tabIndex={0} - type="button" - > - <span - className="MuiIconButton-label text-15-normal" - > - <Icon - className="status-icon" - icon="test-file-stub" - size={40} - spin={false} - > - <Component - className="status-icon styles__icon___23x3R" - height={40} - style={Object {}} - width={40} - > - <svg - className="status-icon styles__icon___23x3R" - height={40} - style={Object {}} - width={40} - > - <use - xlinkHref="#test-file-stub" - /> - </svg> - </Component> - </Icon> - <span> - ecogesture.objective - </span> - </span> - <WithStyles(memo) - center={true} - > - <ForwardRef(TouchRipple) - center={true} - classes={ - Object { - "child": "MuiTouchRipple-child", - "childLeaving": "MuiTouchRipple-childLeaving", - "childPulsate": "MuiTouchRipple-childPulsate", - "ripple": "MuiTouchRipple-ripple", - "ripplePulsate": "MuiTouchRipple-ripplePulsate", - "rippleVisible": "MuiTouchRipple-rippleVisible", - "root": "MuiTouchRipple-root", - } - } - > - <span - className="MuiTouchRipple-root" - > - <TransitionGroup - childFactory={[Function]} - component={null} - exit={true} - /> - </span> - </ForwardRef(TouchRipple)> - </WithStyles(memo)> - </button> - </ForwardRef(ButtonBase)> - </WithStyles(ForwardRef(ButtonBase))> - </ForwardRef(IconButton)> - </WithStyles(ForwardRef(IconButton))> - <WithStyles(ForwardRef(IconButton)) - aria-label="ecogesture.doing" - classes={ - Object { - "label": "text-15-normal", - "root": "btn-secondary-negative doing-btn false", - } - } - onClick={[Function]} - > - <ForwardRef(IconButton) - aria-label="ecogesture.doing" - classes={ - Object { - "colorInherit": "MuiIconButton-colorInherit", - "colorPrimary": "MuiIconButton-colorPrimary", - "colorSecondary": "MuiIconButton-colorSecondary", - "disabled": "Mui-disabled", - "edgeEnd": "MuiIconButton-edgeEnd", - "edgeStart": "MuiIconButton-edgeStart", - "label": "MuiIconButton-label text-15-normal", - "root": "MuiIconButton-root btn-secondary-negative doing-btn false", - "sizeSmall": "MuiIconButton-sizeSmall", - } - } - onClick={[Function]} - > - <WithStyles(ForwardRef(ButtonBase)) - aria-label="ecogesture.doing" - centerRipple={true} - className="MuiIconButton-root btn-secondary-negative doing-btn false" - disabled={false} - focusRipple={true} - onClick={[Function]} - > - <ForwardRef(ButtonBase) - aria-label="ecogesture.doing" - centerRipple={true} - className="MuiIconButton-root btn-secondary-negative doing-btn false" - classes={ - Object { - "disabled": "Mui-disabled", - "focusVisible": "Mui-focusVisible", - "root": "MuiButtonBase-root", - } - } - disabled={false} - focusRipple={true} - onClick={[Function]} - > - <button - aria-label="ecogesture.doing" - className="MuiButtonBase-root MuiIconButton-root btn-secondary-negative doing-btn false" - disabled={false} - onBlur={[Function]} - onClick={[Function]} - onDragLeave={[Function]} - onFocus={[Function]} - onKeyDown={[Function]} - onKeyUp={[Function]} - onMouseDown={[Function]} - onMouseLeave={[Function]} - onMouseUp={[Function]} - onTouchEnd={[Function]} - onTouchMove={[Function]} - onTouchStart={[Function]} - tabIndex={0} - type="button" - > - <span - className="MuiIconButton-label text-15-normal" - > - <Icon - className="status-icon" - icon="test-file-stub" - size={40} - spin={false} - > - <Component - className="status-icon styles__icon___23x3R" - height={40} - style={Object {}} - width={40} - > - <svg - className="status-icon styles__icon___23x3R" - height={40} - style={Object {}} - width={40} - > - <use - xlinkHref="#test-file-stub" - /> - </svg> - </Component> - </Icon> - <span> - ecogesture.doing - </span> - </span> - <WithStyles(memo) - center={true} - > - <ForwardRef(TouchRipple) - center={true} - classes={ - Object { - "child": "MuiTouchRipple-child", - "childLeaving": "MuiTouchRipple-childLeaving", - "childPulsate": "MuiTouchRipple-childPulsate", - "ripple": "MuiTouchRipple-ripple", - "ripplePulsate": "MuiTouchRipple-ripplePulsate", - "rippleVisible": "MuiTouchRipple-rippleVisible", - "root": "MuiTouchRipple-root", - } - } - > - <span - className="MuiTouchRipple-root" - > - <TransitionGroup - childFactory={[Function]} - component={null} - exit={true} - /> - </span> - </ForwardRef(TouchRipple)> - </WithStyles(memo)> - </button> - </ForwardRef(ButtonBase)> - </WithStyles(ForwardRef(ButtonBase))> - </ForwardRef(IconButton)> - </WithStyles(ForwardRef(IconButton))> - </div> - </div> - </div> - </Component> - </SingleEcogesture> -</Provider> -`; diff --git a/src/components/Ecogesture/__snapshots__/SingleEcogestureView.spec.tsx.snap b/src/components/Ecogesture/__snapshots__/SingleEcogestureView.spec.tsx.snap new file mode 100644 index 0000000000000000000000000000000000000000..49280df12fef51b78697af6bdcd84ea7ba2bb082 --- /dev/null +++ b/src/components/Ecogesture/__snapshots__/SingleEcogestureView.spec.tsx.snap @@ -0,0 +1,436 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`SingleEcogesture component should be rendered correctly 1`] = ` +<Provider + store={ + Object { + "clearActions": [Function], + "dispatch": [Function], + "getActions": [Function], + "getState": [Function], + "replaceReducer": [Function], + "subscribe": [Function], + } + } +> + <SingleEcogestureView> + <mock-cozybar + displayBackArrow={true} + titleKey="common.title_ecogesture" + /> + <mock-header + desktopTitleKey="common.title_ecogesture" + displayBackArrow={true} + setHeaderHeight={[Function]} + /> + <mock-content + heightOffset={0} + > + <div + className="single-ecogesture" + > + <div + className="icon-container" + > + <StyledIcon + className="icon-big" + icon="test-file-stub" + size={220} + > + <Icon + aria-hidden={true} + className="icon-big" + icon="test-file-stub" + size={220} + spin={false} + > + <Component + aria-hidden={true} + className="icon-big styles__icon___23x3R" + height={220} + style={Object {}} + width={220} + > + <svg + aria-hidden={true} + className="icon-big styles__icon___23x3R" + height={220} + style={Object {}} + width={220} + > + <use + xlinkHref="#test-file-stub" + /> + </svg> + </Component> + </Icon> + </StyledIcon> + </div> + <div + className="details" + > + <div + className="text-22 title" + > + Bonhomme de neige + </div> + <div + className="efficiency" + > + <span + className="text text-14-normal" + > + ecogesture_modal.efficiency + </span> + <mock-EfficiencyRating + result={4} + /> + </div> + </div> + <div + className="styled-container" + > + <div + className="long-name text-18-bold" + > + Je baisse le chauffage en mode hors gel lorsque je m'absente plus de 2 jours. + </div> + <div + className="showMore text-15-normal" + onClick={[Function]} + role="button" + > + ecogesture_modal.show_more + </div> + <WithStyles(ForwardRef(Collapse)) + in={false} + > + <ForwardRef(Collapse) + classes={ + Object { + "entered": "MuiCollapse-entered", + "hidden": "MuiCollapse-hidden", + "root": "MuiCollapse-root", + "wrapper": "MuiCollapse-wrapper", + "wrapperInner": "MuiCollapse-wrapperInner", + } + } + in={false} + > + <Transition + addEndListener={[Function]} + appear={false} + enter={true} + exit={true} + in={false} + mountOnEnter={false} + onEnter={[Function]} + onEntered={[Function]} + onEntering={[Function]} + onExit={[Function]} + onExited={[Function]} + onExiting={[Function]} + timeout={300} + unmountOnExit={false} + > + <div + className="MuiCollapse-root MuiCollapse-hidden" + style={ + Object { + "minHeight": "0px", + } + } + > + <div + className="MuiCollapse-wrapper" + > + <div + className="MuiCollapse-wrapperInner" + > + <div + className="longDescription text-16-normal-150" + > + On se demande parfois si cela vaut le coup de "couper le chauffage" quand on s’absente… dès qu’il s’agit d’un week-end la réponse est « oui sûrement » ! Attention cependant au retour à ne pas faire de la surchauffe ! L’idéal est bien évidemment de régler sa programmation pour que le chauffage se relance quelques heures avant votre retour… + </div> + </div> + </div> + </div> + </Transition> + </ForwardRef(Collapse)> + </WithStyles(ForwardRef(Collapse))> + </div> + <div + className="buttons-selection" + > + <WithStyles(ForwardRef(IconButton)) + aria-label="ecogesture.objective" + classes={ + Object { + "label": "text-15-normal", + "root": "btn-secondary-negative objective-btn false", + } + } + onClick={[Function]} + > + <ForwardRef(IconButton) + aria-label="ecogesture.objective" + classes={ + Object { + "colorInherit": "MuiIconButton-colorInherit", + "colorPrimary": "MuiIconButton-colorPrimary", + "colorSecondary": "MuiIconButton-colorSecondary", + "disabled": "Mui-disabled", + "edgeEnd": "MuiIconButton-edgeEnd", + "edgeStart": "MuiIconButton-edgeStart", + "label": "MuiIconButton-label text-15-normal", + "root": "MuiIconButton-root btn-secondary-negative objective-btn false", + "sizeSmall": "MuiIconButton-sizeSmall", + } + } + onClick={[Function]} + > + <WithStyles(ForwardRef(ButtonBase)) + aria-label="ecogesture.objective" + centerRipple={true} + className="MuiIconButton-root btn-secondary-negative objective-btn false" + disabled={false} + focusRipple={true} + onClick={[Function]} + > + <ForwardRef(ButtonBase) + aria-label="ecogesture.objective" + centerRipple={true} + className="MuiIconButton-root btn-secondary-negative objective-btn false" + classes={ + Object { + "disabled": "Mui-disabled", + "focusVisible": "Mui-focusVisible", + "root": "MuiButtonBase-root", + } + } + disabled={false} + focusRipple={true} + onClick={[Function]} + > + <button + aria-label="ecogesture.objective" + className="MuiButtonBase-root MuiIconButton-root btn-secondary-negative objective-btn false" + disabled={false} + onBlur={[Function]} + onClick={[Function]} + onDragLeave={[Function]} + onFocus={[Function]} + onKeyDown={[Function]} + onKeyUp={[Function]} + onMouseDown={[Function]} + onMouseLeave={[Function]} + onMouseUp={[Function]} + onTouchEnd={[Function]} + onTouchMove={[Function]} + onTouchStart={[Function]} + tabIndex={0} + type="button" + > + <span + className="MuiIconButton-label text-15-normal" + > + <Icon + className="status-icon" + icon="test-file-stub" + size={40} + spin={false} + > + <Component + className="status-icon styles__icon___23x3R" + height={40} + style={Object {}} + width={40} + > + <svg + className="status-icon styles__icon___23x3R" + height={40} + style={Object {}} + width={40} + > + <use + xlinkHref="#test-file-stub" + /> + </svg> + </Component> + </Icon> + <span> + ecogesture.objective + </span> + </span> + <WithStyles(memo) + center={true} + > + <ForwardRef(TouchRipple) + center={true} + classes={ + Object { + "child": "MuiTouchRipple-child", + "childLeaving": "MuiTouchRipple-childLeaving", + "childPulsate": "MuiTouchRipple-childPulsate", + "ripple": "MuiTouchRipple-ripple", + "ripplePulsate": "MuiTouchRipple-ripplePulsate", + "rippleVisible": "MuiTouchRipple-rippleVisible", + "root": "MuiTouchRipple-root", + } + } + > + <span + className="MuiTouchRipple-root" + > + <TransitionGroup + childFactory={[Function]} + component={null} + exit={true} + /> + </span> + </ForwardRef(TouchRipple)> + </WithStyles(memo)> + </button> + </ForwardRef(ButtonBase)> + </WithStyles(ForwardRef(ButtonBase))> + </ForwardRef(IconButton)> + </WithStyles(ForwardRef(IconButton))> + <WithStyles(ForwardRef(IconButton)) + aria-label="ecogesture.doing" + classes={ + Object { + "label": "text-15-normal", + "root": "btn-secondary-negative doing-btn false", + } + } + onClick={[Function]} + > + <ForwardRef(IconButton) + aria-label="ecogesture.doing" + classes={ + Object { + "colorInherit": "MuiIconButton-colorInherit", + "colorPrimary": "MuiIconButton-colorPrimary", + "colorSecondary": "MuiIconButton-colorSecondary", + "disabled": "Mui-disabled", + "edgeEnd": "MuiIconButton-edgeEnd", + "edgeStart": "MuiIconButton-edgeStart", + "label": "MuiIconButton-label text-15-normal", + "root": "MuiIconButton-root btn-secondary-negative doing-btn false", + "sizeSmall": "MuiIconButton-sizeSmall", + } + } + onClick={[Function]} + > + <WithStyles(ForwardRef(ButtonBase)) + aria-label="ecogesture.doing" + centerRipple={true} + className="MuiIconButton-root btn-secondary-negative doing-btn false" + disabled={false} + focusRipple={true} + onClick={[Function]} + > + <ForwardRef(ButtonBase) + aria-label="ecogesture.doing" + centerRipple={true} + className="MuiIconButton-root btn-secondary-negative doing-btn false" + classes={ + Object { + "disabled": "Mui-disabled", + "focusVisible": "Mui-focusVisible", + "root": "MuiButtonBase-root", + } + } + disabled={false} + focusRipple={true} + onClick={[Function]} + > + <button + aria-label="ecogesture.doing" + className="MuiButtonBase-root MuiIconButton-root btn-secondary-negative doing-btn false" + disabled={false} + onBlur={[Function]} + onClick={[Function]} + onDragLeave={[Function]} + onFocus={[Function]} + onKeyDown={[Function]} + onKeyUp={[Function]} + onMouseDown={[Function]} + onMouseLeave={[Function]} + onMouseUp={[Function]} + onTouchEnd={[Function]} + onTouchMove={[Function]} + onTouchStart={[Function]} + tabIndex={0} + type="button" + > + <span + className="MuiIconButton-label text-15-normal" + > + <Icon + className="status-icon" + icon="test-file-stub" + size={40} + spin={false} + > + <Component + className="status-icon styles__icon___23x3R" + height={40} + style={Object {}} + width={40} + > + <svg + className="status-icon styles__icon___23x3R" + height={40} + style={Object {}} + width={40} + > + <use + xlinkHref="#test-file-stub" + /> + </svg> + </Component> + </Icon> + <span> + ecogesture.doing + </span> + </span> + <WithStyles(memo) + center={true} + > + <ForwardRef(TouchRipple) + center={true} + classes={ + Object { + "child": "MuiTouchRipple-child", + "childLeaving": "MuiTouchRipple-childLeaving", + "childPulsate": "MuiTouchRipple-childPulsate", + "ripple": "MuiTouchRipple-ripple", + "ripplePulsate": "MuiTouchRipple-ripplePulsate", + "rippleVisible": "MuiTouchRipple-rippleVisible", + "root": "MuiTouchRipple-root", + } + } + > + <span + className="MuiTouchRipple-root" + > + <TransitionGroup + childFactory={[Function]} + component={null} + exit={true} + /> + </span> + </ForwardRef(TouchRipple)> + </WithStyles(memo)> + </button> + </ForwardRef(ButtonBase)> + </WithStyles(ForwardRef(ButtonBase))> + </ForwardRef(IconButton)> + </WithStyles(ForwardRef(IconButton))> + </div> + </div> + </mock-content> + </SingleEcogestureView> +</Provider> +`; diff --git a/src/components/Ecogesture/ecogestureView.scss b/src/components/Ecogesture/ecogestureTabsView.scss similarity index 100% rename from src/components/Ecogesture/ecogestureView.scss rename to src/components/Ecogesture/ecogestureTabsView.scss diff --git a/src/components/Ecogesture/singleEcogesture.scss b/src/components/Ecogesture/singleEcogestureView.scss similarity index 91% rename from src/components/Ecogesture/singleEcogesture.scss rename to src/components/Ecogesture/singleEcogestureView.scss index b786284ef7596ec96dd706da128f14e44cc863dc..c8c6d61f9064491e32ab600bb173bc7e476d5999 100644 --- a/src/components/Ecogesture/singleEcogesture.scss +++ b/src/components/Ecogesture/singleEcogestureView.scss @@ -1,5 +1,4 @@ @import 'src/styles/base/color'; -@import 'src/styles/base/breakpoint'; .single-ecogesture { color: $grey-bright; @@ -42,20 +41,17 @@ text-align: center; color: white; } - .description { - display: none; - margin: 1.5rem 0.5rem 0.5rem 0.5rem; - text-align: left; - } - .block { - display: block !important; - } - .toggle-text { + + .showMore { text-align: center; text-decoration: underline; margin-top: 1.5rem; cursor: pointer; } + .longDescription { + margin: 1em 0.5rem; + text-align: left; + } } .buttons-selection { width: 100%; diff --git a/src/components/EcogestureForm/EcogestureFormEquipment.spec.tsx b/src/components/EcogestureForm/EcogestureFormEquipment/EcogestureFormEquipment.spec.tsx similarity index 59% rename from src/components/EcogestureForm/EcogestureFormEquipment.spec.tsx rename to src/components/EcogestureForm/EcogestureFormEquipment/EcogestureFormEquipment.spec.tsx index d1e633a61649020325f81e7f25198d55309ddf44..91a4fd40e0e99c7103a647eb7abb129dbfc3ec4a 100644 --- a/src/components/EcogestureForm/EcogestureFormEquipment.spec.tsx +++ b/src/components/EcogestureForm/EcogestureFormEquipment/EcogestureFormEquipment.spec.tsx @@ -2,51 +2,20 @@ import { Button } from '@material-ui/core' import { mount } from 'enzyme' import toJson from 'enzyme-to-json' import React from 'react' -import * as reactRedux from 'react-redux' import { Provider } from 'react-redux' -import configureStore from 'redux-mock-store' -import { challengeStateData } from '../../../tests/__mocks__/challengeStateData.mock' -import { globalStateData } from '../../../tests/__mocks__/globalStateData.mock' -import { mockProfileEcogesture } from '../../../tests/__mocks__/profileEcogesture.mock' -import { mockInitialEcolyoState } from '../../../tests/__mocks__/store' -import { waitForComponentToPaint } from '../../../tests/__mocks__/testUtils' +import { mockProfileEcogesture } from 'tests/__mocks__/profileEcogesture.mock' +import { createMockEcolyoStore } from 'tests/__mocks__/store' +import { waitForComponentToPaint } from 'tests/__mocks__/testUtils' import EcogestureFormEquipment from './EcogestureFormEquipment' -jest.mock('cozy-ui/transpiled/react/I18n', () => { - return { - useI18n: jest.fn(() => { - return { - t: (str: string) => str, - } - }), - } -}) -const mockStore = configureStore([]) const mockSetPreviousStep = jest.fn() const mockSetNextStep = jest.fn() -const useSelectorSpy = jest.spyOn(reactRedux, 'useSelector') -const mockHistoryPush = jest.fn() -jest.mock('react-router-dom', () => ({ - ...jest.requireActual('react-router-dom'), - useNavigate: () => ({ - push: mockHistoryPush, - }), -})) -jest.mock('./EquipmentIcon', () => 'mock-equipment-icon') +jest.mock('../EquipmentIcon/EquipmentIcon', () => 'mock-equipment-icon') describe('EcogestureFormEquipment component', () => { - useSelectorSpy.mockReturnValue({ - ...mockInitialEcolyoState.profile, - }) - + const store = createMockEcolyoStore() it('should be rendered correctly', async () => { - const store = mockStore({ - ecolyo: { - global: globalStateData, - challenge: challengeStateData, - }, - }) const wrapper = mount( <Provider store={store}> <EcogestureFormEquipment @@ -62,13 +31,6 @@ describe('EcogestureFormEquipment component', () => { }) it('should select equipment and unselect it', async () => { - const store = mockStore({ - ecolyo: { - global: globalStateData, - challenge: challengeStateData, - }, - }) - const wrapper = mount( <Provider store={store}> <EcogestureFormEquipment @@ -83,19 +45,13 @@ describe('EcogestureFormEquipment component', () => { wrapper.find('.item-eq').first().simulate('change') await waitForComponentToPaint(wrapper) - expect(wrapper.find('.item-eq').first().hasClass('checked')).toBeTruthy + expect(wrapper.find('.item-eq').first().hasClass('checked')).toBeTruthy() wrapper.find('.checked').first().simulate('change') await waitForComponentToPaint(wrapper) expect(wrapper.find('.item-eq').first().hasClass('checked')).toBeFalsy() }) it('should click on disabled back button', async () => { - const store = mockStore({ - ecolyo: { - global: globalStateData, - challenge: challengeStateData, - }, - }) const wrapper = mount( <Provider store={store}> <EcogestureFormEquipment diff --git a/src/components/EcogestureForm/EcogestureFormEquipment.tsx b/src/components/EcogestureForm/EcogestureFormEquipment/EcogestureFormEquipment.tsx similarity index 82% rename from src/components/EcogestureForm/EcogestureFormEquipment.tsx rename to src/components/EcogestureForm/EcogestureFormEquipment/EcogestureFormEquipment.tsx index b26bd8eec3c018ed818ea19796b30f15ff2f0d6b..85caa4b5381b778e4fb8c2b91da0d2a287ef0579 100644 --- a/src/components/EcogestureForm/EcogestureFormEquipment.tsx +++ b/src/components/EcogestureForm/EcogestureFormEquipment/EcogestureFormEquipment.tsx @@ -1,14 +1,11 @@ -import FormNavigation from 'components/FormGlobal/FormNavigation' +import FormNavigation from 'components/CommonKit/FormNavigation/FormNavigation' import 'components/ProfileType/profileTypeForm.scss' import { useI18n } from 'cozy-ui/transpiled/react/I18n' -import { EquipmentType } from 'enum/ecogesture.enum' -import { EcogestureStepForm } from 'enum/ecogestureForm.enum' -import { ProfileTypeStepForm } from 'enum/profileType.enum' +import { EcogestureStepForm, EquipmentType, ProfileTypeStepForm } from 'enums' import { ProfileEcogesture, ProfileType } from 'models' import React, { useCallback, useState } from 'react' -import { useSelector } from 'react-redux' -import { AppStore } from 'store' -import EquipmentIcon from './EquipmentIcon' +import { useAppSelector } from 'store/hooks' +import EquipmentIcon from '../EquipmentIcon/EquipmentIcon' import './ecogestureFormEquipment.scss' interface EcogestureFormEquipmentProps { @@ -29,8 +26,8 @@ const EcogestureFormEquipment = ({ step, }: EcogestureFormEquipmentProps) => { const { t } = useI18n() - const { isProfileEcogestureCompleted } = useSelector( - (state: AppStore) => state.ecolyo.profile + const { isProfileEcogestureCompleted } = useAppSelector( + state => state.ecolyo.profile ) const previousEquipments = currentProfileType?.equipments || currentProfileEcogesture?.equipments || [] @@ -83,15 +80,15 @@ const EcogestureFormEquipment = ({ return ( <> <div className="ecogesture-profile-container"> - <div className={'equipment-form-container'}> - <div className={'equipment-label text-22-normal'}> + <div className="equipment-form-container"> + <div className="equipment-label text-22-normal"> {t( `ecogesture_profile.${EcogestureStepForm[ EcogestureStepForm.EQUIPMENTS ].toLowerCase()}.question` )} </div> - <div className={'equipment-hint text-16-normal'}> + <div className="equipment-hint text-16-normal"> {t( `ecogesture_profile.${EcogestureStepForm[ EcogestureStepForm.EQUIPMENTS @@ -100,9 +97,9 @@ const EcogestureFormEquipment = ({ </div> <div className="icons-container"> {Object.values(EquipmentType).map(equipment => ( - <label key={equipment} className={'checkbox-equipment'}> + <label key={equipment} className="checkbox-equipment"> <input - type={'checkbox'} + type="checkbox" value={equipment} name={equipment.toString()} onChange={() => handleChange(equipment)} diff --git a/src/components/EcogestureForm/__snapshots__/EcogestureFormEquipment.spec.tsx.snap b/src/components/EcogestureForm/EcogestureFormEquipment/__snapshots__/EcogestureFormEquipment.spec.tsx.snap similarity index 100% rename from src/components/EcogestureForm/__snapshots__/EcogestureFormEquipment.spec.tsx.snap rename to src/components/EcogestureForm/EcogestureFormEquipment/__snapshots__/EcogestureFormEquipment.spec.tsx.snap diff --git a/src/components/EcogestureForm/ecogestureFormEquipment.scss b/src/components/EcogestureForm/EcogestureFormEquipment/ecogestureFormEquipment.scss similarity index 96% rename from src/components/EcogestureForm/ecogestureFormEquipment.scss rename to src/components/EcogestureForm/EcogestureFormEquipment/ecogestureFormEquipment.scss index 43fb2428905e3fbb448b1a4ff157159086d16fdb..be3e7257d2ffe9ba87153d315305cb90aba38294 100644 --- a/src/components/EcogestureForm/ecogestureFormEquipment.scss +++ b/src/components/EcogestureForm/EcogestureFormEquipment/ecogestureFormEquipment.scss @@ -1,5 +1,5 @@ @import 'src/styles/base/color'; -@import '../../styles/base/breakpoint'; +@import 'src/styles/base/breakpoint'; .equipment-form-container { padding: 1.5rem; diff --git a/src/components/EcogestureForm/EcogestureFormSingleChoice.spec.tsx b/src/components/EcogestureForm/EcogestureFormSingleChoice/EcogestureFormSingleChoice.spec.tsx similarity index 79% rename from src/components/EcogestureForm/EcogestureFormSingleChoice.spec.tsx rename to src/components/EcogestureForm/EcogestureFormSingleChoice/EcogestureFormSingleChoice.spec.tsx index 1b6515c429eb7c8dbf22cd7520635df02720b308..3d97bafc6e7d1818a5eb16eaa519467f1ae1e7b6 100644 --- a/src/components/EcogestureForm/EcogestureFormSingleChoice.spec.tsx +++ b/src/components/EcogestureForm/EcogestureFormSingleChoice/EcogestureFormSingleChoice.spec.tsx @@ -1,37 +1,18 @@ -/* eslint-disable react/display-name */ import { Button } from '@material-ui/core' import { mount } from 'enzyme' import toJson from 'enzyme-to-json' import React from 'react' -import * as reactRedux from 'react-redux' import { Provider } from 'react-redux' import { mockEcogestureAnswer, mockProfileEcogesture, -} from '../../../tests/__mocks__/profileEcogesture.mock' -import { createMockEcolyoStore } from '../../../tests/__mocks__/store' -import { waitForComponentToPaint } from '../../../tests/__mocks__/testUtils' +} from 'tests/__mocks__/profileEcogesture.mock' +import { createMockEcolyoStore } from 'tests/__mocks__/store' +import { waitForComponentToPaint } from 'tests/__mocks__/testUtils' import EcogestureFormSingleChoice from './EcogestureFormSingleChoice' -const useSelectorSpy = jest.spyOn(reactRedux, 'useSelector') - -jest.mock('cozy-ui/transpiled/react/I18n', () => { - return { - useI18n: jest.fn(() => { - return { - t: (str: string) => str, - } - }), - } -}) -const mockedNavigate = jest.fn() -jest.mock('react-router-dom', () => ({ - ...jest.requireActual('react-router-dom'), - useNavigate: () => mockedNavigate, -})) - jest.mock( - 'components/EcogestureForm/EcogestureLaunchFormModal', + 'components/EcogestureForm/EcogestureLaunchFormModal/EcogestureLaunchFormModal', () => 'mock-ecogesturelaunchmodal' ) @@ -39,9 +20,6 @@ const mockHandleNextStep = jest.fn() const mockHandlePreviousStep = jest.fn() describe('EcogestureFormSingleChoice component', () => { const store = createMockEcolyoStore() - beforeEach(() => { - store.clearActions() - }) it('should be rendered correctly', async () => { const wrapper = mount( @@ -115,11 +93,6 @@ describe('EcogestureFormSingleChoice component', () => { expect(mockHandlePreviousStep).toHaveBeenCalledTimes(1) }) it('should keep previous answer', async () => { - useSelectorSpy.mockReturnValue({ - profile: { - isProfileEcogestureCompleted: true, - }, - }) const wrapper = mount( <Provider store={store}> <EcogestureFormSingleChoice diff --git a/src/components/EcogestureForm/EcogestureFormSingleChoice.tsx b/src/components/EcogestureForm/EcogestureFormSingleChoice/EcogestureFormSingleChoice.tsx similarity index 82% rename from src/components/EcogestureForm/EcogestureFormSingleChoice.tsx rename to src/components/EcogestureForm/EcogestureFormSingleChoice/EcogestureFormSingleChoice.tsx index 5f1299666e89f4e2b82397ed0952840ec4922d03..e7efcf827da8c60189afcc7377ab04eccc9af595 100644 --- a/src/components/EcogestureForm/EcogestureFormSingleChoice.tsx +++ b/src/components/EcogestureForm/EcogestureFormSingleChoice/EcogestureFormSingleChoice.tsx @@ -1,16 +1,15 @@ import classNames from 'classnames' -import FormNavigation from 'components/FormGlobal/FormNavigation' +import FormNavigation from 'components/CommonKit/FormNavigation/FormNavigation' import 'components/ProfileType/profileTypeForm.scss' import { useI18n } from 'cozy-ui/transpiled/react/I18n' -import { EcogestureStepForm } from 'enum/ecogestureForm.enum' +import { EcogestureStepForm } from 'enums' import { ProfileEcogesture, ProfileEcogestureAnswer, ProfileEcogestureValues, -} from 'models/profileEcogesture.model' +} from 'models' import React, { useCallback, useState } from 'react' -import { useSelector } from 'react-redux' -import { AppStore } from 'store' +import { useAppSelector } from 'store/hooks' import './ecogestureFormSingleChoice.scss' interface EcogestureFormSingleChoiceProps { step: EcogestureStepForm @@ -30,8 +29,8 @@ const EcogestureFormSingleChoice = ({ setPreviousStep, }: EcogestureFormSingleChoiceProps) => { const { t } = useI18n() - const { isProfileEcogestureCompleted } = useSelector( - (state: AppStore) => state.ecolyo.profile + const { isProfileEcogestureCompleted } = useAppSelector( + state => state.ecolyo.profile ) const [answer, setAnswer] = useState<ProfileEcogestureValues>( isProfileEcogestureCompleted || step < viewedStep @@ -49,14 +48,14 @@ const EcogestureFormSingleChoice = ({ return ( <div className="ecogesture-profile-container"> - <div className={'profile-form-container ecogesture-form-single'}> - <div className={'profile-question-label'}> + <div className="profile-form-container ecogesture-form-single"> + <div className="profile-question-label"> {t( `ecogesture_form.${EcogestureStepForm[step].toLowerCase()}.question` )} </div> {answerType.choices.map(value => { - if (!value) return null + if (value === null) return null return ( <label key={value.toString()} @@ -67,7 +66,7 @@ const EcogestureFormSingleChoice = ({ })} > <input - type={'radio'} + type="radio" value={value} name={value.toString()} onChange={() => setAnswer(value)} diff --git a/src/components/EcogestureForm/__snapshots__/EcogestureFormSingleChoice.spec.tsx.snap b/src/components/EcogestureForm/EcogestureFormSingleChoice/__snapshots__/EcogestureFormSingleChoice.spec.tsx.snap similarity index 100% rename from src/components/EcogestureForm/__snapshots__/EcogestureFormSingleChoice.spec.tsx.snap rename to src/components/EcogestureForm/EcogestureFormSingleChoice/__snapshots__/EcogestureFormSingleChoice.spec.tsx.snap diff --git a/src/components/EcogestureForm/ecogestureFormSingleChoice.scss b/src/components/EcogestureForm/EcogestureFormSingleChoice/ecogestureFormSingleChoice.scss similarity index 88% rename from src/components/EcogestureForm/ecogestureFormSingleChoice.scss rename to src/components/EcogestureForm/EcogestureFormSingleChoice/ecogestureFormSingleChoice.scss index 93360c88ec8200a01d7e2fda89432abb2d3510f4..a8181829fad052cd50e12727aaac40431323ba3f 100644 --- a/src/components/EcogestureForm/ecogestureFormSingleChoice.scss +++ b/src/components/EcogestureForm/EcogestureFormSingleChoice/ecogestureFormSingleChoice.scss @@ -1,5 +1,5 @@ -@import '../../styles/base/color'; -@import '../../styles/base/breakpoint'; +@import 'src/styles/base/color'; +@import 'src/styles/base/breakpoint'; .ecogesture-profile-container { display: flex; diff --git a/src/components/EcogestureForm/EcogestureFormView.spec.tsx b/src/components/EcogestureForm/EcogestureFormView.spec.tsx index 78474a832ea8baadda173e0f28f88adbf309b580..77256f6dc3a6203aa1fd52e46c032f4db2f70854 100644 --- a/src/components/EcogestureForm/EcogestureFormView.spec.tsx +++ b/src/components/EcogestureForm/EcogestureFormView.spec.tsx @@ -2,51 +2,35 @@ import { Button } from '@material-ui/core' import { mount } from 'enzyme' import toJson from 'enzyme-to-json' -import { Profile } from 'models' import React from 'react' -import * as reactRedux from 'react-redux' import { Provider } from 'react-redux' -import { - createMockEcolyoStore, - mockInitialEcolyoState, -} from '../../../tests/__mocks__/store' -import { waitForComponentToPaint } from '../../../tests/__mocks__/testUtils' +import * as storeHooks from 'store/hooks' +import { mockProfileEcogesture } from 'tests/__mocks__/profileEcogesture.mock' +import { createMockEcolyoStore } from 'tests/__mocks__/store' +import { waitForComponentToPaint } from 'tests/__mocks__/testUtils' import EcogestureFormView from './EcogestureFormView' -jest.mock('cozy-ui/transpiled/react/I18n', () => { - return { - useI18n: jest.fn(() => { - return { - t: (str: string) => str, - } - }), - } -}) - jest.mock('components/Header/CozyBar', () => 'mock-cozybar') jest.mock('components/Header/Header', () => 'mock-header') jest.mock( - 'components/EcogestureForm/EcogestureLaunchFormModal', + 'components/EcogestureForm/EcogestureLaunchFormModal/EcogestureLaunchFormModal', () => 'mock-ecogesturelaunchmodal' ) -const mockUseDispatch = jest.spyOn(reactRedux, 'useDispatch') +const mockAppDispatch = jest.spyOn(storeHooks, 'useAppDispatch') jest.mock('components/Content/Content', () => 'mock-content') const mockedNavigate = jest.fn() jest.mock('react-router-dom', () => ({ ...jest.requireActual('react-router-dom'), useNavigate: () => mockedNavigate, - useLocation: () => { - return { - search: '', - } - }, + useLocation: () => ({ + search: '', + }), })) describe('EcogestureFormView component', () => { const store = createMockEcolyoStore() beforeEach(() => { - store.clearActions() - mockUseDispatch.mockClear() + jest.clearAllMocks() }) it('should be rendered correctly', async () => { @@ -58,7 +42,7 @@ describe('EcogestureFormView component', () => { await waitForComponentToPaint(wrapper) expect(toJson(wrapper)).toMatchSnapshot() }) - it('should render singlechoice', async () => { + it('should render singleChoice', async () => { const wrapper = mount( <Provider store={store}> <EcogestureFormView /> @@ -68,13 +52,12 @@ describe('EcogestureFormView component', () => { expect(wrapper.find('.ecogesture-form-single').exists()).toBeTruthy() }) it('should render profiletype form step because profiletype is completed', async () => { - const updatedProfile: Profile = { - ...mockInitialEcolyoState.profile, - isProfileTypeCompleted: true, - } - const updatedStore = { ...mockInitialEcolyoState, profile: updatedProfile } + const store = createMockEcolyoStore({ + profile: { isProfileTypeCompleted: true }, + profileEcogesture: mockProfileEcogesture, + }) const wrapper = mount( - <Provider store={createMockEcolyoStore(updatedStore)}> + <Provider store={store}> <EcogestureFormView /> </Provider> ) @@ -112,7 +95,7 @@ describe('EcogestureFormView component', () => { }) it('should handle form end', async () => { - mockUseDispatch.mockReturnValue(jest.fn()) + mockAppDispatch.mockReturnValue(jest.fn()) jest .spyOn(React, 'useState') .mockImplementationOnce(() => [0, () => null]) @@ -123,6 +106,6 @@ describe('EcogestureFormView component', () => { </Provider> ) await waitForComponentToPaint(wrapper) - expect(mockUseDispatch).toHaveBeenCalledTimes(2) + expect(mockAppDispatch).toHaveBeenCalledTimes(2) }) }) diff --git a/src/components/EcogestureForm/EcogestureFormView.tsx b/src/components/EcogestureForm/EcogestureFormView.tsx index b3faea70e482efb173af8a7949874f4c563d5f09..b7aabd755eb5aba0310c41969783c5bc97b6f730 100644 --- a/src/components/EcogestureForm/EcogestureFormView.tsx +++ b/src/components/EcogestureForm/EcogestureFormView.tsx @@ -1,38 +1,28 @@ import Content from 'components/Content/Content' -import EcogestureFormEquipment from 'components/EcogestureForm/EcogestureFormEquipment' -import EcogestureFormSingleChoice from 'components/EcogestureForm/EcogestureFormSingleChoice' -import EcogestureLaunchFormModal from 'components/EcogestureForm/EcogestureLaunchFormModal' import CozyBar from 'components/Header/CozyBar' import Header from 'components/Header/Header' import Loader from 'components/Loader/Loader' import ProfileTypeView from 'components/ProfileType/ProfileTypeView' -import { - EcogestureStepForm, - ProfileEcogestureAnswerType, -} from 'enum/ecogestureForm.enum' -import { - ProfileEcogesture, - ProfileEcogestureAnswer, -} from 'models/profileEcogesture.model' -import React, { Dispatch, useCallback, useEffect, useState } from 'react' -import { useDispatch, useSelector } from 'react-redux' +import { EcogestureStepForm, ProfileEcogestureAnswerType } from 'enums' +import { ProfileEcogesture, ProfileEcogestureAnswer } from 'models' +import React, { useCallback, useEffect, useState } from 'react' import { useLocation, useNavigate } from 'react-router-dom' import ProfileEcogestureFormService from 'services/profileEcogestureForm.service' -import { AppActionsTypes, AppStore } from 'store' -import { updateProfile } from 'store/profile/profile.actions' -import { newProfileEcogestureEntry } from 'store/profileEcogesture/profileEcogesture.actions' +import { useAppDispatch, useAppSelector } from 'store/hooks' +import { updateProfile } from 'store/profile/profile.slice' +import { newProfileEcogestureEntry } from 'store/profileEcogesture/profileEcogesture.slice' +import EcogestureFormEquipment from './EcogestureFormEquipment/EcogestureFormEquipment' +import EcogestureFormSingleChoice from './EcogestureFormSingleChoice/EcogestureFormSingleChoice' +import EcogestureLaunchFormModal from './EcogestureLaunchFormModal/EcogestureLaunchFormModal' const EcogestureFormView = () => { - const dispatch: Dispatch<AppActionsTypes> = useDispatch() + const navigate = useNavigate() + const dispatch = useAppDispatch() const { profile: { isProfileTypeCompleted }, profileEcogesture, - } = useSelector((state: AppStore) => state.ecolyo) - const navigate = useNavigate() + } = useAppSelector(state => state.ecolyo) const [headerHeight, setHeaderHeight] = useState<number>(0) - const defineHeaderHeight = (height: number) => { - setHeaderHeight(height) - } const shouldOpenModal = new URLSearchParams(useLocation().search).get('modal') const [step, setStep] = useState<EcogestureStepForm>( @@ -94,24 +84,24 @@ const EcogestureFormView = () => { } }, [handleEndForm, step]) - if (isLoading) { - return ( - <Content height={headerHeight}> - <Loader /> - </Content> - ) + if (isProfileTypeCompleted) { + return <ProfileTypeView /> } + return ( <> - <CozyBar titleKey={'common.title_ecogestures'} /> + <CozyBar titleKey="common.title_ecogestures" /> <Header - setHeaderHeight={defineHeaderHeight} - desktopTitleKey={'common.title_ecogestures'} + setHeaderHeight={setHeaderHeight} + desktopTitleKey="common.title_ecogestures" /> - <Content height={headerHeight}> - {isProfileTypeCompleted ? ( - <ProfileTypeView /> - ) : ( + <Content heightOffset={headerHeight}> + {isLoading && ( + <div className="loaderContainer"> + <Loader /> + </div> + )} + {!isLoading && ( <> {step === EcogestureStepForm.EQUIPMENTS && ( <EcogestureFormEquipment diff --git a/src/components/EcogestureForm/EcogestureLaunchFormModal.spec.tsx b/src/components/EcogestureForm/EcogestureLaunchFormModal/EcogestureLaunchFormModal.spec.tsx similarity index 83% rename from src/components/EcogestureForm/EcogestureLaunchFormModal.spec.tsx rename to src/components/EcogestureForm/EcogestureLaunchFormModal/EcogestureLaunchFormModal.spec.tsx index 6bd433f4919213f871dfca5a987f1b9f9b1a03a5..1efe25a5ee1b77c66b2e72a4ea8a45bdbfa06bcc 100644 --- a/src/components/EcogestureForm/EcogestureLaunchFormModal.spec.tsx +++ b/src/components/EcogestureForm/EcogestureLaunchFormModal/EcogestureLaunchFormModal.spec.tsx @@ -4,16 +4,6 @@ import toJson from 'enzyme-to-json' import React from 'react' import EcogestureLaunchFormModal from './EcogestureLaunchFormModal' -jest.mock('cozy-ui/transpiled/react/I18n', () => { - return { - useI18n: jest.fn(() => { - return { - t: (str: string) => str, - } - }), - } -}) - const mockHandleClose = jest.fn() describe('EcogestureLaunchFormModal component', () => { it('should be rendered correctly', () => { diff --git a/src/components/EcogestureForm/EcogestureLaunchFormModal.tsx b/src/components/EcogestureForm/EcogestureLaunchFormModal/EcogestureLaunchFormModal.tsx similarity index 95% rename from src/components/EcogestureForm/EcogestureLaunchFormModal.tsx rename to src/components/EcogestureForm/EcogestureLaunchFormModal/EcogestureLaunchFormModal.tsx index 43d41314757b94143c5bd35bef7739e62dcf90c4..328ec33efd44004193119a6044bf2fc3a21a0bf2 100644 --- a/src/components/EcogestureForm/EcogestureLaunchFormModal.tsx +++ b/src/components/EcogestureForm/EcogestureLaunchFormModal/EcogestureLaunchFormModal.tsx @@ -19,13 +19,13 @@ const EcogestureLaunchFormModal = ({ <Dialog open={open} onClose={handleCloseClick} - aria-labelledby={'accessibility-title'} + aria-labelledby="accessibility-title" classes={{ root: 'modal-root', paper: 'modal-paper', }} > - <div id={'accessibility-title'}> + <div id="accessibility-title"> {t('feedback.accessibility.window_title')} </div> <IconButton diff --git a/src/components/EcogestureForm/__snapshots__/EcogestureLaunchFormModal.spec.tsx.snap b/src/components/EcogestureForm/EcogestureLaunchFormModal/__snapshots__/EcogestureLaunchFormModal.spec.tsx.snap similarity index 100% rename from src/components/EcogestureForm/__snapshots__/EcogestureLaunchFormModal.spec.tsx.snap rename to src/components/EcogestureForm/EcogestureLaunchFormModal/__snapshots__/EcogestureLaunchFormModal.spec.tsx.snap diff --git a/src/components/EcogestureForm/ecogestureLaunchFormModal.scss b/src/components/EcogestureForm/EcogestureLaunchFormModal/ecogestureLaunchFormModal.scss similarity index 84% rename from src/components/EcogestureForm/ecogestureLaunchFormModal.scss rename to src/components/EcogestureForm/EcogestureLaunchFormModal/ecogestureLaunchFormModal.scss index c3e52eacfedfa0f7bf5c243b2e164dfaaadb8c9e..283ead71a2a4533f761d1001fbc010309fba75d3 100644 --- a/src/components/EcogestureForm/ecogestureLaunchFormModal.scss +++ b/src/components/EcogestureForm/EcogestureLaunchFormModal/ecogestureLaunchFormModal.scss @@ -1,4 +1,4 @@ -@import '../../styles/base/color'; +@import 'src/styles/base/color'; .eg-init-modal { color: $grey-bright; diff --git a/src/components/EcogestureForm/EquipmentIcon.spec.tsx b/src/components/EcogestureForm/EquipmentIcon/EquipmentIcon.spec.tsx similarity index 58% rename from src/components/EcogestureForm/EquipmentIcon.spec.tsx rename to src/components/EcogestureForm/EquipmentIcon/EquipmentIcon.spec.tsx index ffb0703be6559ae3837db6815ebaf6e9afdb933b..6d248173c0e505d11a7d2ed6f6b4e94de80229ac 100644 --- a/src/components/EcogestureForm/EquipmentIcon.spec.tsx +++ b/src/components/EcogestureForm/EquipmentIcon/EquipmentIcon.spec.tsx @@ -1,31 +1,13 @@ /* eslint-disable react/display-name */ -import { EquipmentType } from 'enum/ecogesture.enum' +import { EquipmentType } from 'enums' import { mount } from 'enzyme' import toJson from 'enzyme-to-json' import React from 'react' -import { waitForComponentToPaint } from '../../../tests/__mocks__/testUtils' +import { waitForComponentToPaint } from 'tests/__mocks__/testUtils' import EquipmentIcon from './EquipmentIcon' -jest.mock('cozy-ui/transpiled/react/I18n', () => { - return { - useI18n: jest.fn(() => { - return { - t: (str: string) => str, - } - }), - } -}) -const mockImportIconById = jest.fn() -jest.mock('utils/utils', () => { - return { - importIconById: jest.fn(() => { - return mockImportIconById - }), - } -}) describe('EcogestureFormSingleChoice component', () => { it('should be rendered correctly', async () => { - mockImportIconById.mockReturnValue('') const wrapper = mount( <EquipmentIcon equipment={EquipmentType.BOILER} isChecked={false} /> ) @@ -33,7 +15,6 @@ describe('EcogestureFormSingleChoice component', () => { expect(toJson(wrapper)).toMatchSnapshot() }) it('should render checked icon', async () => { - mockImportIconById.mockReturnValue('') const wrapper = mount( <EquipmentIcon equipment={EquipmentType.BOILER} isChecked={true} /> ) diff --git a/src/components/EcogestureForm/EquipmentIcon.tsx b/src/components/EcogestureForm/EquipmentIcon/EquipmentIcon.tsx similarity index 94% rename from src/components/EcogestureForm/EquipmentIcon.tsx rename to src/components/EcogestureForm/EquipmentIcon/EquipmentIcon.tsx index 46b1b09c79752261cc6e1bbb91c4c757878a9664..e01d242adb824194b6249d775d88fe1d39039c40 100644 --- a/src/components/EcogestureForm/EquipmentIcon.tsx +++ b/src/components/EcogestureForm/EquipmentIcon/EquipmentIcon.tsx @@ -34,7 +34,7 @@ const EquipmentIcon = ({ equipment, isChecked }: EquipmentIconProps) => { : ' equipment-icon-container' } > - <Icon icon={icon} size={40} className={'equipmentIcon '} /> + <Icon icon={icon} size={40} className="equipmentIcon " /> </div> <div className="text text-14-normal"> {t(`ecogesture_profile.equipments.${equipment.toLocaleLowerCase()}`)} diff --git a/src/components/EcogestureForm/__snapshots__/EquipmentIcon.spec.tsx.snap b/src/components/EcogestureForm/EquipmentIcon/__snapshots__/EquipmentIcon.spec.tsx.snap similarity index 92% rename from src/components/EcogestureForm/__snapshots__/EquipmentIcon.spec.tsx.snap rename to src/components/EcogestureForm/EquipmentIcon/__snapshots__/EquipmentIcon.spec.tsx.snap index bded38e56adb198ea87f56117e6db48cec16285f..8909ac3fb08ea93c2135fee9ae4789885bf69701 100644 --- a/src/components/EcogestureForm/__snapshots__/EquipmentIcon.spec.tsx.snap +++ b/src/components/EcogestureForm/EquipmentIcon/__snapshots__/EquipmentIcon.spec.tsx.snap @@ -10,7 +10,7 @@ exports[`EcogestureFormSingleChoice component should be rendered correctly 1`] = > <Icon className="equipmentIcon " - icon="" + icon="test-file-stub" size={40} spin={false} > @@ -27,7 +27,7 @@ exports[`EcogestureFormSingleChoice component should be rendered correctly 1`] = width={40} > <use - xlinkHref="#" + xlinkHref="#test-file-stub" /> </svg> </Component> diff --git a/src/components/EcogestureForm/__snapshots__/EcogestureFormView.spec.tsx.snap b/src/components/EcogestureForm/__snapshots__/EcogestureFormView.spec.tsx.snap index 304c1fdddbaa8721f125a341cc1ab6837f54a958..b343a1c9654cf7eae93c8fa31497c0ca862cc0a1 100644 --- a/src/components/EcogestureForm/__snapshots__/EcogestureFormView.spec.tsx.snap +++ b/src/components/EcogestureForm/__snapshots__/EcogestureFormView.spec.tsx.snap @@ -22,7 +22,7 @@ exports[`EcogestureFormView component should be rendered correctly 1`] = ` setHeaderHeight={[Function]} /> <mock-content - height={0} + heightOffset={0} > <EcogestureFormSingleChoice answerType={ diff --git a/src/components/EcogestureSelection/EcogestureSelectionDetail.spec.tsx b/src/components/EcogestureSelection/EcogestureSelectionDetail/EcogestureSelectionDetail.spec.tsx similarity index 70% rename from src/components/EcogestureSelection/EcogestureSelectionDetail.spec.tsx rename to src/components/EcogestureSelection/EcogestureSelectionDetail/EcogestureSelectionDetail.spec.tsx index 2aa3ec4a6a0fed87ca33f9d7fa48f1059a194e9d..33640fbccb586f68b29928f91c088f2bc9509660 100644 --- a/src/components/EcogestureSelection/EcogestureSelectionDetail.spec.tsx +++ b/src/components/EcogestureSelection/EcogestureSelectionDetail/EcogestureSelectionDetail.spec.tsx @@ -2,37 +2,14 @@ import { Button } from '@material-ui/core' import { mount } from 'enzyme' import toJson from 'enzyme-to-json' import React from 'react' -import { mockedEcogesturesData } from '../../../tests/__mocks__/ecogesturesData.mock' -import { waitForComponentToPaint } from '../../../tests/__mocks__/testUtils' +import { mockedEcogesturesData } from 'tests/__mocks__/ecogesturesData.mock' +import { waitForComponentToPaint } from 'tests/__mocks__/testUtils' import EcogestureSelectionDetail from './EcogestureSelectionDetail' -jest.mock('cozy-ui/transpiled/react/I18n', () => { - return { - useI18n: jest.fn(() => { - return { - t: (str: string) => str, - } - }), - } -}) -const mockImportIconById = jest.fn() -jest.mock('utils/utils', () => { - return { - importIconById: jest.fn(() => { - return mockImportIconById - }), - } -}) const mockValidate = jest.fn() describe('EcogestureSelectionDetail component', () => { - beforeEach(() => { - mockImportIconById.mockClear() - mockValidate.mockClear() - }) - it('should be rendered correctly', async () => { - mockImportIconById.mockReturnValueOnce('testIcon') const wrapper = mount( <EcogestureSelectionDetail ecogesture={mockedEcogesturesData[0]} @@ -44,8 +21,22 @@ describe('EcogestureSelectionDetail component', () => { expect(toJson(wrapper)).toMatchSnapshot() }) + it('should toggle more details', async () => { + const wrapper = mount( + <EcogestureSelectionDetail + ecogesture={mockedEcogesturesData[0]} + validate={mockValidate} + title={mockedEcogesturesData[0].shortName} + /> + ) + await waitForComponentToPaint(wrapper) + + wrapper.find('.showMore').first().simulate('click') + await waitForComponentToPaint(wrapper) + + expect(wrapper.find('.showMore').text()).toBe('ecogesture_modal.show_less') + }) it('should call validate with objective to true', async () => { - mockImportIconById.mockReturnValueOnce('testIcon') const wrapper = mount( <EcogestureSelectionDetail ecogesture={mockedEcogesturesData[0]} @@ -59,7 +50,6 @@ describe('EcogestureSelectionDetail component', () => { }) it('should call validate with doing to true', async () => { - mockImportIconById.mockReturnValueOnce('testIcon') const wrapper = mount( <EcogestureSelectionDetail ecogesture={mockedEcogesturesData[0]} @@ -73,7 +63,6 @@ describe('EcogestureSelectionDetail component', () => { }) it('should call validate with objective and doing to false', async () => { - mockImportIconById.mockReturnValueOnce('testIcon') const wrapper = mount( <EcogestureSelectionDetail ecogesture={mockedEcogesturesData[0]} diff --git a/src/components/EcogestureSelection/EcogestureSelectionDetail.tsx b/src/components/EcogestureSelection/EcogestureSelectionDetail/EcogestureSelectionDetail.tsx similarity index 76% rename from src/components/EcogestureSelection/EcogestureSelectionDetail.tsx rename to src/components/EcogestureSelection/EcogestureSelectionDetail/EcogestureSelectionDetail.tsx index 1c58e184a47635ddf11c142bf709f44bef95810c..cf50f528ddd004fde180ea4784756ade2190af07 100644 --- a/src/components/EcogestureSelection/EcogestureSelectionDetail.tsx +++ b/src/components/EcogestureSelection/EcogestureSelectionDetail/EcogestureSelectionDetail.tsx @@ -1,4 +1,4 @@ -import { Button } from '@material-ui/core' +import { Button, Collapse } from '@material-ui/core' import doingIcon from 'assets/icons/ico/doing-enabled.svg' import objectiveIcon from 'assets/icons/ico/objective-enabled.svg' import skipIcon from 'assets/icons/ico/skip-enabled.svg' @@ -23,20 +23,18 @@ const EcogestureSelectionDetail = ({ }: EcogestureSelectionDetailProps) => { const { t } = useI18n() const [ecogestureIcon, setEcogestureIcon] = useState<string>('') + const [showDetails, setShowDetails] = useState(false) useEffect(() => { let subscribed = true async function getIcon() { - const _icon = await importIconById(ecogesture.id, 'ecogesture') + const icon = await importIconById(ecogesture.id, 'ecogesture') if (subscribed) { - if (_icon) { - setEcogestureIcon(_icon) - } else { - setEcogestureIcon(defaultIcon) - } + setEcogestureIcon(icon || defaultIcon) } } getIcon() + setShowDetails(false) return () => { subscribed = false } @@ -45,9 +43,25 @@ const EcogestureSelectionDetail = ({ return ( <div className="eg-selection-detail-container"> <div className="content"> - <StyledIcon className="icon" icon={ecogestureIcon} size={240} /> + <div className="iconContainer"> + <StyledIcon className="icon" icon={ecogestureIcon} size={240} /> + </div> <div className="text-22 title">{title}</div> <div className="text text-18-bold">{ecogesture.longName}</div> + + <div + className="showMore text-15-normal" + onClick={() => setShowDetails(prev => !prev)} + role="button" + > + {t(`ecogesture_modal.show_${showDetails ? 'less' : 'more'}`)} + </div> + + <Collapse in={showDetails} exit={false}> + <div className="longDescription text-16-normal-150"> + {ecogesture.longDescription} + </div> + </Collapse> </div> <div className="buttons"> <Button diff --git a/src/components/EcogestureSelection/__snapshots__/EcogestureSelectionDetail.spec.tsx.snap b/src/components/EcogestureSelection/EcogestureSelectionDetail/__snapshots__/EcogestureSelectionDetail.spec.tsx.snap similarity index 88% rename from src/components/EcogestureSelection/__snapshots__/EcogestureSelectionDetail.spec.tsx.snap rename to src/components/EcogestureSelection/EcogestureSelectionDetail/__snapshots__/EcogestureSelectionDetail.spec.tsx.snap index 13d309ddfbb17765cde97b784c6f2f7bc7e221d6..0b56a7a8e59162761f2850469f30d2328467c5db 100644 --- a/src/components/EcogestureSelection/__snapshots__/EcogestureSelectionDetail.spec.tsx.snap +++ b/src/components/EcogestureSelection/EcogestureSelectionDetail/__snapshots__/EcogestureSelectionDetail.spec.tsx.snap @@ -44,39 +44,43 @@ exports[`EcogestureSelectionDetail component should be rendered correctly 1`] = <div className="content" > - <StyledIcon - className="icon" - icon="testIcon" - size={240} + <div + className="iconContainer" > - <Icon - aria-hidden={true} + <StyledIcon className="icon" - icon="testIcon" + icon="test-file-stub" size={240} - spin={false} > - <Component + <Icon aria-hidden={true} - className="icon styles__icon___23x3R" - height={240} - style={Object {}} - width={240} + className="icon" + icon="test-file-stub" + size={240} + spin={false} > - <svg + <Component aria-hidden={true} className="icon styles__icon___23x3R" height={240} style={Object {}} width={240} > - <use - xlinkHref="#testIcon" - /> - </svg> - </Component> - </Icon> - </StyledIcon> + <svg + aria-hidden={true} + className="icon styles__icon___23x3R" + height={240} + style={Object {}} + width={240} + > + <use + xlinkHref="#test-file-stub" + /> + </svg> + </Component> + </Icon> + </StyledIcon> + </div> <div className="text-22 title" > @@ -87,6 +91,71 @@ exports[`EcogestureSelectionDetail component should be rendered correctly 1`] = > Je baisse le chauffage en mode hors gel lorsque je m'absente plus de 2 jours. </div> + <div + className="showMore text-15-normal" + onClick={[Function]} + role="button" + > + ecogesture_modal.show_more + </div> + <WithStyles(ForwardRef(Collapse)) + exit={false} + in={false} + > + <ForwardRef(Collapse) + classes={ + Object { + "entered": "MuiCollapse-entered", + "hidden": "MuiCollapse-hidden", + "root": "MuiCollapse-root", + "wrapper": "MuiCollapse-wrapper", + "wrapperInner": "MuiCollapse-wrapperInner", + } + } + exit={false} + in={false} + > + <Transition + addEndListener={[Function]} + appear={false} + enter={true} + exit={false} + in={false} + mountOnEnter={false} + onEnter={[Function]} + onEntered={[Function]} + onEntering={[Function]} + onExit={[Function]} + onExited={[Function]} + onExiting={[Function]} + timeout={300} + unmountOnExit={false} + > + <div + className="MuiCollapse-root MuiCollapse-hidden" + style={ + Object { + "minHeight": "0px", + } + } + > + <div + className="MuiCollapse-wrapper" + > + <div + className="MuiCollapse-wrapperInner" + > + <div + className="longDescription text-16-normal-150" + > + On se demande parfois si cela vaut le coup de "couper le chauffage" quand on s’absente… dès qu’il s’agit d’un week-end la réponse est « oui sûrement » ! Attention cependant au retour à ne pas faire de la surchauffe ! L’idéal est bien évidemment de régler sa programmation pour que le chauffage se relance quelques heures avant votre retour… + </div> + </div> + </div> + </div> + </Transition> + </ForwardRef(Collapse)> + </WithStyles(ForwardRef(Collapse))> </div> <div className="buttons" diff --git a/src/components/EcogestureSelection/ecogestureSelectionDetail.scss b/src/components/EcogestureSelection/EcogestureSelectionDetail/ecogestureSelectionDetail.scss similarity index 68% rename from src/components/EcogestureSelection/ecogestureSelectionDetail.scss rename to src/components/EcogestureSelection/EcogestureSelectionDetail/ecogestureSelectionDetail.scss index 7f860e0385f0fe9b0b55f00a37b17c486349ae82..2bdb65ed0f31fdccb95994385e7831ad0ac782be 100644 --- a/src/components/EcogestureSelection/ecogestureSelectionDetail.scss +++ b/src/components/EcogestureSelection/EcogestureSelectionDetail/ecogestureSelectionDetail.scss @@ -1,42 +1,43 @@ -@import '../../styles/base/color'; -@import '../../styles/base/breakpoint'; +@import 'src/styles/base/color'; +@import 'src/styles/base/breakpoint'; .eg-selection-detail-container { - min-height: inherit; display: flex; flex-direction: column; text-align: center; color: $grey-bright; padding: 0 1.5rem; + flex: 1; + max-height: calc(100vh - 60px - 72px - 0px); + .content { display: flex; gap: 0.5rem; flex-direction: column; flex: 1; - justify-content: center; + justify-content: flex-start; align-items: center; + overflow-y: auto; .title { color: $soft-grey; font-weight: 700; } - .icon { - @media #{$phone} { - width: 50%; - height: 50%; - } - @media #{$small-phone} { - width: 30%; - height: 30%; - } + .iconContainer { + height: 240px; + } + + .showMore { + text-align: center; + text-decoration: underline; + margin-top: 1rem; + cursor: pointer; } - .text { - min-height: 4.875rem; - display: flex; - align-items: center; - margin: 0 1rem; + .longDescription { + margin: 1rem 0.5rem; + text-align: left; } } .buttons { diff --git a/src/components/EcogestureSelection/EcogestureSelectionEnd.spec.tsx b/src/components/EcogestureSelection/EcogestureSelectionEnd/EcogestureSelectionEnd.spec.tsx similarity index 80% rename from src/components/EcogestureSelection/EcogestureSelectionEnd.spec.tsx rename to src/components/EcogestureSelection/EcogestureSelectionEnd/EcogestureSelectionEnd.spec.tsx index ee657cb0b79f616573ee3c668d69bc0e518c9f30..b6359dd88ff4b2d0f1e63d9615ab7c7b94247a6f 100644 --- a/src/components/EcogestureSelection/EcogestureSelectionEnd.spec.tsx +++ b/src/components/EcogestureSelection/EcogestureSelectionEnd/EcogestureSelectionEnd.spec.tsx @@ -4,15 +4,6 @@ import toJson from 'enzyme-to-json' import React from 'react' import EcogestureSelectionEnd from './EcogestureSelectionEnd' -jest.mock('cozy-ui/transpiled/react/I18n', () => { - return { - useI18n: jest.fn(() => { - return { - t: (str: string) => str, - } - }), - } -}) const mockedNavigate = jest.fn() jest.mock('react-router-dom', () => ({ ...jest.requireActual('react-router-dom'), @@ -21,7 +12,7 @@ jest.mock('react-router-dom', () => ({ describe('EcogestureSelectionEnd component', () => { beforeEach(() => { - mockedNavigate.mockClear() + jest.clearAllMocks() }) it('should be rendered correctly', () => { diff --git a/src/components/EcogestureSelection/EcogestureSelectionEnd.tsx b/src/components/EcogestureSelection/EcogestureSelectionEnd/EcogestureSelectionEnd.tsx similarity index 87% rename from src/components/EcogestureSelection/EcogestureSelectionEnd.tsx rename to src/components/EcogestureSelection/EcogestureSelectionEnd/EcogestureSelectionEnd.tsx index 5742708e628210bb7da4a06b1722d91068c76b96..27c356afb667820e493cf7d7857d2169d057857e 100644 --- a/src/components/EcogestureSelection/EcogestureSelectionEnd.tsx +++ b/src/components/EcogestureSelection/EcogestureSelectionEnd/EcogestureSelectionEnd.tsx @@ -2,7 +2,7 @@ import { Button } from '@material-ui/core' import icon from 'assets/icons/visu/profileType/finish.svg' import StyledIcon from 'components/CommonKit/Icon/StyledIcon' import { useI18n } from 'cozy-ui/transpiled/react/I18n' -import React, { useCallback } from 'react' +import React from 'react' import { useNavigate } from 'react-router-dom' import './ecogestureSelectionEnd.scss' @@ -10,9 +10,6 @@ const EcogestureSelectionEnd = () => { const { t } = useI18n() const navigate = useNavigate() - const goToObjectives = useCallback(() => { - navigate('/ecogestures?tab=0') - }, [navigate]) return ( <div className="eg-selection-end-container"> <div className="content"> @@ -34,7 +31,7 @@ const EcogestureSelectionEnd = () => { root: 'btn-highlight', label: 'text-16-bold', }} - onClick={goToObjectives} + onClick={() => navigate('/ecogestures?tab=0')} > {t('ecogesture_selection.button_ok')} </Button> diff --git a/src/components/EcogestureSelection/__snapshots__/EcogestureSelectionEnd.spec.tsx.snap b/src/components/EcogestureSelection/EcogestureSelectionEnd/__snapshots__/EcogestureSelectionEnd.spec.tsx.snap similarity index 100% rename from src/components/EcogestureSelection/__snapshots__/EcogestureSelectionEnd.spec.tsx.snap rename to src/components/EcogestureSelection/EcogestureSelectionEnd/__snapshots__/EcogestureSelectionEnd.spec.tsx.snap diff --git a/src/components/EcogestureSelection/ecogestureSelectionEnd.scss b/src/components/EcogestureSelection/EcogestureSelectionEnd/ecogestureSelectionEnd.scss similarity index 91% rename from src/components/EcogestureSelection/ecogestureSelectionEnd.scss rename to src/components/EcogestureSelection/EcogestureSelectionEnd/ecogestureSelectionEnd.scss index 803a4b3aded9e9120c63c703f13e11cefde0c142..8a3cd1a42d0c3c4c44e66ca6ebc894e191e994dc 100644 --- a/src/components/EcogestureSelection/ecogestureSelectionEnd.scss +++ b/src/components/EcogestureSelection/EcogestureSelectionEnd/ecogestureSelectionEnd.scss @@ -1,5 +1,5 @@ -@import '../../styles/base/color'; -@import '../../styles/base/breakpoint'; +@import 'src/styles/base/color'; +@import 'src/styles/base/breakpoint'; .eg-selection-end-container { position: relative; diff --git a/src/components/EcogestureSelection/EcogestureSelectionModal.spec.tsx b/src/components/EcogestureSelection/EcogestureSelectionModal/EcogestureSelectionModal.spec.tsx similarity index 83% rename from src/components/EcogestureSelection/EcogestureSelectionModal.spec.tsx rename to src/components/EcogestureSelection/EcogestureSelectionModal/EcogestureSelectionModal.spec.tsx index 26ab115f3d3ee24d956d2d92d483972555f6295f..b2f3141ca6eaacce91aa0cd11a60e755297fc0ea 100644 --- a/src/components/EcogestureSelection/EcogestureSelectionModal.spec.tsx +++ b/src/components/EcogestureSelection/EcogestureSelectionModal/EcogestureSelectionModal.spec.tsx @@ -4,16 +4,6 @@ import toJson from 'enzyme-to-json' import React from 'react' import EcogestureSelectionModal from './EcogestureSelectionModal' -jest.mock('cozy-ui/transpiled/react/I18n', () => { - return { - useI18n: jest.fn(() => { - return { - t: (str: string) => str, - } - }), - } -}) - const mockHandleClose = jest.fn() describe('EcogestureInitModal component', () => { it('should be rendered correctly', () => { diff --git a/src/components/EcogestureSelection/EcogestureSelectionModal.tsx b/src/components/EcogestureSelection/EcogestureSelectionModal/EcogestureSelectionModal.tsx similarity index 95% rename from src/components/EcogestureSelection/EcogestureSelectionModal.tsx rename to src/components/EcogestureSelection/EcogestureSelectionModal/EcogestureSelectionModal.tsx index 48d2db7aad55c4aad19af5538365e8e5d472be12..f79f26a0263e91874ed4dd1f22d46a357ecd607c 100644 --- a/src/components/EcogestureSelection/EcogestureSelectionModal.tsx +++ b/src/components/EcogestureSelection/EcogestureSelectionModal/EcogestureSelectionModal.tsx @@ -21,13 +21,13 @@ const EcogestureSelectionModal = ({ <Dialog open={open} onClose={handleCloseClick} - aria-labelledby={'accessibility-title'} + aria-labelledby="accessibility-title" classes={{ root: 'modal-root', paper: 'modal-paper', }} > - <div id={'accessibility-title'}> + <div id="accessibility-title"> {t('ecogesture_selection.accessibility.window_title')} </div> <IconButton diff --git a/src/components/EcogestureSelection/__snapshots__/EcogestureSelectionModal.spec.tsx.snap b/src/components/EcogestureSelection/EcogestureSelectionModal/__snapshots__/EcogestureSelectionModal.spec.tsx.snap similarity index 100% rename from src/components/EcogestureSelection/__snapshots__/EcogestureSelectionModal.spec.tsx.snap rename to src/components/EcogestureSelection/EcogestureSelectionModal/__snapshots__/EcogestureSelectionModal.spec.tsx.snap diff --git a/src/components/EcogestureSelection/ecogestureSelectionModal.scss b/src/components/EcogestureSelection/EcogestureSelectionModal/ecogestureSelectionModal.scss similarity index 88% rename from src/components/EcogestureSelection/ecogestureSelectionModal.scss rename to src/components/EcogestureSelection/EcogestureSelectionModal/ecogestureSelectionModal.scss index 99a08d67a118b774f5573f524763b6b34c06f7a2..9093e9a2497a2e1420a808428b21956843c4d44a 100644 --- a/src/components/EcogestureSelection/ecogestureSelectionModal.scss +++ b/src/components/EcogestureSelection/EcogestureSelectionModal/ecogestureSelectionModal.scss @@ -1,4 +1,4 @@ -@import '../../styles/base/color'; +@import 'src/styles/base/color'; .eg-selection-modal { color: $grey-bright; diff --git a/src/components/EcogestureSelection/EcogestureSelectionRestart.spec.tsx b/src/components/EcogestureSelection/EcogestureSelectionRestart/EcogestureSelectionRestart.spec.tsx similarity index 83% rename from src/components/EcogestureSelection/EcogestureSelectionRestart.spec.tsx rename to src/components/EcogestureSelection/EcogestureSelectionRestart/EcogestureSelectionRestart.spec.tsx index d13a55a6d16e68606c69c4c04f212953572651f6..08bc2048c80cd920cf7ec6c4291944c56f159bd5 100644 --- a/src/components/EcogestureSelection/EcogestureSelectionRestart.spec.tsx +++ b/src/components/EcogestureSelection/EcogestureSelectionRestart/EcogestureSelectionRestart.spec.tsx @@ -4,15 +4,6 @@ import toJson from 'enzyme-to-json' import React from 'react' import EcogestureSelectionRestart from './EcogestureSelectionRestart' -jest.mock('cozy-ui/transpiled/react/I18n', () => { - return { - useI18n: jest.fn(() => { - return { - t: (str: string) => str, - } - }), - } -}) const mockedNavigate = jest.fn() jest.mock('react-router-dom', () => ({ ...jest.requireActual('react-router-dom'), @@ -21,11 +12,6 @@ jest.mock('react-router-dom', () => ({ const mockRestart = jest.fn() describe('EcogestureSelectionRestart component', () => { - beforeEach(() => { - mockedNavigate.mockClear() - mockRestart.mockClear() - }) - it('should be rendered correctly', () => { const wrapper = mount( <EcogestureSelectionRestart listLength={10} restart={mockRestart} /> diff --git a/src/components/EcogestureSelection/EcogestureSelectionRestart.tsx b/src/components/EcogestureSelection/EcogestureSelectionRestart/EcogestureSelectionRestart.tsx similarity index 86% rename from src/components/EcogestureSelection/EcogestureSelectionRestart.tsx rename to src/components/EcogestureSelection/EcogestureSelectionRestart/EcogestureSelectionRestart.tsx index 33a68a477c8096ced33c5fd8c2f1eb5ca96e1d11..8482b95431ccfe35c6f2b587264b975c1e542c29 100644 --- a/src/components/EcogestureSelection/EcogestureSelectionRestart.tsx +++ b/src/components/EcogestureSelection/EcogestureSelectionRestart/EcogestureSelectionRestart.tsx @@ -2,7 +2,7 @@ import { Button } from '@material-ui/core' import icon from 'assets/icons/visu/ecogesture/ECOGESTURE0001.svg' import StyledIcon from 'components/CommonKit/Icon/StyledIcon' import { useI18n } from 'cozy-ui/transpiled/react/I18n' -import React, { useCallback } from 'react' +import React from 'react' import { useNavigate } from 'react-router-dom' import './ecogestureSelectionRestart.scss' @@ -18,17 +18,12 @@ const EcogestureSelectionRestart = ({ const { t } = useI18n() const navigate = useNavigate() - const goToObjectives = useCallback(() => { - navigate('/ecogestures?tab=0') - }, [navigate]) - return ( <div className="eg-selection-restart-container"> <div className="content"> <div className="title text-21-bold"> {t('ecogesture_selection.title', { - // eslint-disable-next-line camelcase - smart_count: listLength, + smartCount: listLength, })} </div> <StyledIcon icon={icon} size={120} /> @@ -45,7 +40,7 @@ const EcogestureSelectionRestart = ({ root: 'btn-secondary-negative', label: 'text-16-normal', }} - onClick={goToObjectives} + onClick={() => navigate('/ecogestures?tab=0')} > {t('ecogesture_selection.button_go_to_ecogesture')} </Button> diff --git a/src/components/EcogestureSelection/__snapshots__/EcogestureSelectionRestart.spec.tsx.snap b/src/components/EcogestureSelection/EcogestureSelectionRestart/__snapshots__/EcogestureSelectionRestart.spec.tsx.snap similarity index 100% rename from src/components/EcogestureSelection/__snapshots__/EcogestureSelectionRestart.spec.tsx.snap rename to src/components/EcogestureSelection/EcogestureSelectionRestart/__snapshots__/EcogestureSelectionRestart.spec.tsx.snap diff --git a/src/components/EcogestureSelection/ecogestureSelectionRestart.scss b/src/components/EcogestureSelection/EcogestureSelectionRestart/ecogestureSelectionRestart.scss similarity index 92% rename from src/components/EcogestureSelection/ecogestureSelectionRestart.scss rename to src/components/EcogestureSelection/EcogestureSelectionRestart/ecogestureSelectionRestart.scss index 08c2885b01e7b35bcdb1d02bd7da499631e44a65..a68688b03d27a6335741cc82cddc71c6cb65c4ad 100644 --- a/src/components/EcogestureSelection/ecogestureSelectionRestart.scss +++ b/src/components/EcogestureSelection/EcogestureSelectionRestart/ecogestureSelectionRestart.scss @@ -1,5 +1,5 @@ -@import '../../styles/base/color'; -@import '../../styles/base/breakpoint'; +@import 'src/styles/base/color'; +@import 'src/styles/base/breakpoint'; .eg-selection-restart-container { position: relative; diff --git a/src/components/EcogestureSelection/EcogestureSelection.spec.tsx b/src/components/EcogestureSelection/EcogestureSelectionView.spec.tsx similarity index 50% rename from src/components/EcogestureSelection/EcogestureSelection.spec.tsx rename to src/components/EcogestureSelection/EcogestureSelectionView.spec.tsx index 0ea212bcf337cf233ba62f50953545058b52694a..234ba798c846879c520b2fdc1091dcbb1e3ea964 100644 --- a/src/components/EcogestureSelection/EcogestureSelection.spec.tsx +++ b/src/components/EcogestureSelection/EcogestureSelectionView.spec.tsx @@ -3,81 +3,49 @@ import { mount } from 'enzyme' import toJson from 'enzyme-to-json' import React from 'react' import { Provider } from 'react-redux' -import mockClient from '../../../tests/__mocks__/client' -import { mockedEcogesturesData } from '../../../tests/__mocks__/ecogesturesData.mock' -import { createMockEcolyoStore } from '../../../tests/__mocks__/store' -import { waitForComponentToPaint } from '../../../tests/__mocks__/testUtils' -import EcogestureSelection from './EcogestureSelection' +import { mockedEcogesturesData } from 'tests/__mocks__/ecogesturesData.mock' +import { createMockEcolyoStore } from 'tests/__mocks__/store' +import { waitForComponentToPaint } from 'tests/__mocks__/testUtils' +import EcogestureSelectionView from './EcogestureSelectionView' -jest.mock('cozy-ui/transpiled/react/I18n', () => { - return { - useI18n: jest.fn(() => { - return { - t: (str: string) => str, - } - }), - } -}) -jest.mock('cozy-client', () => { - return { - useClient: jest.fn(() => { - return mockClient - }), - } -}) -const mockHistoryGoBack = jest.fn() -jest.mock('react-router-dom', () => ({ - ...jest.requireActual('react-router-dom'), - useLocation: () => { - return { - search: '', - } - }, - useNavigate: () => ({ - push: mockHistoryGoBack, - }), -})) const mockGetEcogestureListByProfile = jest.fn() jest.mock('services/ecogesture.service', () => { - return jest.fn(() => { - return { - getEcogestureListByProfile: mockGetEcogestureListByProfile, - } - }) + return jest.fn(() => ({ + getEcogestureListByProfile: mockGetEcogestureListByProfile, + })) }) jest.mock('components/Header/CozyBar', () => 'mock-cozybar') jest.mock('components/Header/Header', () => 'mock-header') jest.mock('components/Content/Content', () => 'mock-content') jest.mock( - 'components/EcogestureSelection/EcogestureSelectionModal', - () => 'mock-ecogestureselectionmodal' + 'components/EcogestureSelection/EcogestureSelectionModal/EcogestureSelectionModal', + () => 'mock-ecogestureSelectionModal' ) jest.mock( - 'components/EcogestureSelection/EcogestureSelectionDetail', - () => 'mock-ecogestureselectiondetail' + 'components/EcogestureSelection/EcogestureSelectionDetail/EcogestureSelectionDetail', + () => 'mock-ecogestureSelectionDetail' ) jest.mock( - 'components/EcogestureSelection/EcogestureSelectionRestart', - () => 'mock-ecogestureselectionrestart' + 'components/EcogestureSelection/EcogestureSelectionRestart/EcogestureSelectionRestart', + () => 'mock-ecogestureSelectionRestart' ) jest.mock( - 'components/EcogestureSelection/EcogestureSelectionEnd', - () => 'mock-ecogestureselectionend' + 'components/EcogestureSelection/EcogestureSelectionEnd/EcogestureSelectionEnd', + () => 'mock-ecogestureSelectionEnd' ) describe('EcogestureSelection component', () => { const store = createMockEcolyoStore() beforeEach(() => { - store.clearActions() - mockGetEcogestureListByProfile.mockClear() + jest.clearAllMocks() }) it('should be rendered correctly', async () => { mockGetEcogestureListByProfile.mockResolvedValue([mockedEcogesturesData[0]]) const wrapper = mount( <Provider store={store}> - <EcogestureSelection /> + <EcogestureSelectionView /> </Provider> ) await waitForComponentToPaint(wrapper) @@ -87,30 +55,30 @@ describe('EcogestureSelection component', () => { mockGetEcogestureListByProfile.mockResolvedValue([mockedEcogesturesData[0]]) const wrapper = mount( <Provider store={store}> - <EcogestureSelection /> + <EcogestureSelectionView /> </Provider> ) await waitForComponentToPaint(wrapper) - expect(wrapper.find('mock-ecogestureselectionmodal').exists()).toBeTruthy() + expect(wrapper.find('mock-ecogestureSelectionModal').exists()).toBeTruthy() }) it('should render with the EcogestureSelectionDetail', async () => { mockGetEcogestureListByProfile.mockResolvedValue([mockedEcogesturesData[0]]) const wrapper = mount( <Provider store={store}> - <EcogestureSelection /> + <EcogestureSelectionView /> </Provider> ) await waitForComponentToPaint(wrapper) - expect(wrapper.find('mock-ecogestureselectiondetail').exists()).toBeTruthy() + expect(wrapper.find('mock-ecogestureSelectionDetail').exists()).toBeTruthy() }) it('should render with the EcogestureSelectionEnd', async () => { mockGetEcogestureListByProfile.mockResolvedValue([]) const wrapper = mount( <Provider store={store}> - <EcogestureSelection /> + <EcogestureSelectionView /> </Provider> ) await waitForComponentToPaint(wrapper) - expect(wrapper.find('mock-ecogestureselectionend').exists()).toBeTruthy() + expect(wrapper.find('mock-ecogestureSelectionEnd').exists()).toBeTruthy() }) }) diff --git a/src/components/EcogestureSelection/EcogestureSelection.tsx b/src/components/EcogestureSelection/EcogestureSelectionView.tsx similarity index 77% rename from src/components/EcogestureSelection/EcogestureSelection.tsx rename to src/components/EcogestureSelection/EcogestureSelectionView.tsx index a04d394156641b336a7a52541a33bb22663e438a..749060770df62a29fd23f39092b29e6331b86dd1 100644 --- a/src/components/EcogestureSelection/EcogestureSelection.tsx +++ b/src/components/EcogestureSelection/EcogestureSelectionView.tsx @@ -1,8 +1,4 @@ import Content from 'components/Content/Content' -import EcogestureSelectionDetail from 'components/EcogestureSelection/EcogestureSelectionDetail' -import EcogestureSelectionEnd from 'components/EcogestureSelection/EcogestureSelectionEnd' -import EcogestureSelectionModal from 'components/EcogestureSelection/EcogestureSelectionModal' -import EcogestureSelectionRestart from 'components/EcogestureSelection/EcogestureSelectionRestart' import CozyBar from 'components/Header/CozyBar' import Header from 'components/Header/Header' import Loader from 'components/Loader/Loader' @@ -10,16 +6,20 @@ import { useClient } from 'cozy-client' import { useI18n } from 'cozy-ui/transpiled/react/I18n' import { Ecogesture } from 'models' import React, { useCallback, useEffect, useMemo, useState } from 'react' -import { useSelector } from 'react-redux' import { useNavigate } from 'react-router-dom' import EcogestureService from 'services/ecogesture.service' -import { AppStore } from 'store' -import './ecogestureSelection.scss' +import { useAppSelector } from 'store/hooks' +import EcogestureSelectionDetail from './EcogestureSelectionDetail/EcogestureSelectionDetail' +import EcogestureSelectionEnd from './EcogestureSelectionEnd/EcogestureSelectionEnd' +import EcogestureSelectionModal from './EcogestureSelectionModal/EcogestureSelectionModal' +import EcogestureSelectionRestart from './EcogestureSelectionRestart/EcogestureSelectionRestart' +import './ecogestureSelectionView.scss' -const EcogestureSelection = () => { +const EcogestureSelectionView = () => { const { t } = useI18n() const client = useClient() const navigate = useNavigate() + const { profileEcogesture } = useAppSelector(state => state.ecolyo) const [isLoading, setIsLoading] = useState(true) const [headerHeight, setHeaderHeight] = useState<number>(0) const [indexEcogesture, setIndexEcogesture] = useState<number>(0) @@ -29,17 +29,10 @@ const EcogestureSelection = () => { const [openEcogestureSelectionModal, setOpenEcogestureSelectionModal] = useState(false) - const defineHeaderHeight = useCallback((height: number) => { - setHeaderHeight(height) - }, []) - const ecogestureService = useMemo( () => new EcogestureService(client), [client] ) - const profileEcogesture = useSelector( - (state: AppStore) => state.ecolyo.profileEcogesture - ) const getTitle = useCallback((): string => { if ( @@ -111,16 +104,6 @@ const EcogestureSelection = () => { } }, [ecogestureService, profileEcogesture]) - if (isLoading) { - return ( - <Content height={headerHeight}> - <div className="eg-selection-loader"> - <Loader /> - </div> - </Content> - ) - } - const renderEcogestureSelection = () => { if (indexEcogesture <= ecogestureList.length - 1) { return ( @@ -145,13 +128,13 @@ const EcogestureSelection = () => { return ( <> <CozyBar - titleKey={'common.title_ecogestures_choice'} + titleKey="common.title_ecogestures_choice" displayBackArrow={true} backFunction={() => navigate('/ecogestures')} /> <Header - setHeaderHeight={defineHeaderHeight} - desktopTitleKey={'common.title_ecogestures_choice'} + setHeaderHeight={setHeaderHeight} + desktopTitleKey="common.title_ecogestures_choice" displayBackArrow={true} > <div className="eg-selection-header"> @@ -160,15 +143,26 @@ const EcogestureSelection = () => { : ''} </div> </Header> - <Content height={headerHeight}>{renderEcogestureSelection()}</Content> - {openEcogestureSelectionModal && ( - <EcogestureSelectionModal - open={openEcogestureSelectionModal} - handleCloseClick={() => setOpenEcogestureSelectionModal(false)} - /> - )} + <Content heightOffset={headerHeight}> + {isLoading && ( + <div className="loaderContainer"> + <Loader /> + </div> + )} + {!isLoading && ( + <> + {renderEcogestureSelection()} + {openEcogestureSelectionModal && ( + <EcogestureSelectionModal + open={openEcogestureSelectionModal} + handleCloseClick={() => setOpenEcogestureSelectionModal(false)} + /> + )} + </> + )} + </Content> </> ) } -export default EcogestureSelection +export default EcogestureSelectionView diff --git a/src/components/EcogestureSelection/__snapshots__/EcogestureSelection.spec.tsx.snap b/src/components/EcogestureSelection/__snapshots__/EcogestureSelectionView.spec.tsx.snap similarity index 91% rename from src/components/EcogestureSelection/__snapshots__/EcogestureSelection.spec.tsx.snap rename to src/components/EcogestureSelection/__snapshots__/EcogestureSelectionView.spec.tsx.snap index 32838b95b199f5c6354c5fb61b4dd2e60415240c..ed9d0311c8a6b5491e0c668cb785fb5a4c43aafb 100644 --- a/src/components/EcogestureSelection/__snapshots__/EcogestureSelection.spec.tsx.snap +++ b/src/components/EcogestureSelection/__snapshots__/EcogestureSelectionView.spec.tsx.snap @@ -13,7 +13,7 @@ exports[`EcogestureSelection component should be rendered correctly 1`] = ` } } > - <EcogestureSelection> + <EcogestureSelectionView> <mock-cozybar backFunction={[Function]} displayBackArrow={true} @@ -31,9 +31,9 @@ exports[`EcogestureSelection component should be rendered correctly 1`] = ` </div> </mock-header> <mock-content - height={0} + heightOffset={0} > - <mock-ecogestureselectiondetail + <mock-ecogestureSelectionDetail ecogesture={ Object { "_id": "ECOGESTURE001", @@ -70,11 +70,11 @@ exports[`EcogestureSelection component should be rendered correctly 1`] = ` title="Bonhomme de neige" validate={[Function]} /> + <mock-ecogestureSelectionModal + handleCloseClick={[Function]} + open={true} + /> </mock-content> - <mock-ecogestureselectionmodal - handleCloseClick={[Function]} - open={true} - /> - </EcogestureSelection> + </EcogestureSelectionView> </Provider> `; diff --git a/src/components/EcogestureSelection/ecogestureSelection.scss b/src/components/EcogestureSelection/ecogestureSelection.scss deleted file mode 100644 index 128410d01da72b40f7d06c50bffbcf9e58ee2dde..0000000000000000000000000000000000000000 --- a/src/components/EcogestureSelection/ecogestureSelection.scss +++ /dev/null @@ -1,19 +0,0 @@ -@import '../../styles/base/color'; -@import '../../styles/base/breakpoint'; - -.eg-selection-loader { - min-height: inherit; - display: flex; - justify-content: center; - align-items: center; - @media all and(min-width: $width-tablet) { - min-height: 80vh; - } -} - -.eg-selection-header { - color: $grey-bright; - text-align: center; - margin-top: -1rem; - margin-bottom: 1rem; -} diff --git a/src/components/EcogestureSelection/ecogestureSelectionView.scss b/src/components/EcogestureSelection/ecogestureSelectionView.scss new file mode 100644 index 0000000000000000000000000000000000000000..08a03001ffa0d5e46b21df7012b8f3bb23d8a3ba --- /dev/null +++ b/src/components/EcogestureSelection/ecogestureSelectionView.scss @@ -0,0 +1,9 @@ +@import 'src/styles/base/color'; +@import 'src/styles/base/breakpoint'; + +.eg-selection-header { + color: $grey-bright; + text-align: center; + margin-top: -1rem; + margin-bottom: 1rem; +} diff --git a/src/components/Exploration/ExplorationError.spec.tsx b/src/components/Exploration/ExplorationError.spec.tsx index b3f676a96e81885b53b7797f1263507fa5416441..4ea8699db42cada633e20108310d45a64d088909 100644 --- a/src/components/Exploration/ExplorationError.spec.tsx +++ b/src/components/Exploration/ExplorationError.spec.tsx @@ -2,25 +2,10 @@ import ExplorationError from 'components/Exploration/ExplorationError' import { shallow } from 'enzyme' import React from 'react' -jest.mock('cozy-ui/transpiled/react/I18n', () => { - return { - useI18n: jest.fn(() => { - return { - t: (str: string) => str, - } - }), - } -}) - -const mockedNavigate = jest.fn() -jest.mock('react-router-dom', () => ({ - ...jest.requireActual('react-router-dom'), - useNavigate: () => mockedNavigate, -})) - describe('ExplorationError component', () => { it('should be rendered correctly', () => { const component = shallow(<ExplorationError />).getElement + // TODO fix empty snapshot expect(component).toMatchSnapshot() }) }) diff --git a/src/components/Exploration/ExplorationError.tsx b/src/components/Exploration/ExplorationError.tsx index efd22f0f0d8e0d33f211531c73bada580a55ac1c..64702698d0f084c5ca80cc343423d7c7bf800726 100644 --- a/src/components/Exploration/ExplorationError.tsx +++ b/src/components/Exploration/ExplorationError.tsx @@ -1,6 +1,6 @@ import Button from '@material-ui/core/Button' import { useI18n } from 'cozy-ui/transpiled/react/I18n' -import React, { useCallback } from 'react' +import React from 'react' import { useNavigate } from 'react-router-dom' import './explorationError.scss' @@ -8,10 +8,6 @@ const ExplorationError = () => { const { t } = useI18n() const navigate = useNavigate() - const goBack = useCallback(() => { - navigate(-1) - }, [navigate]) - return ( <div className="exploration-error-container"> <div className="exploration-error-message"> @@ -20,7 +16,7 @@ const ExplorationError = () => { <div className="exploration-error-button"> <Button aria-label={t('exploration.accessibility.button_go_back')} - onClick={goBack} + onClick={() => navigate(-1)} classes={{ root: 'btn-secondary-negative', label: 'text-16-normal', diff --git a/src/components/Exploration/ExplorationFinished.spec.tsx b/src/components/Exploration/ExplorationFinished.spec.tsx index 177d4adfe14c926a9883245eebae458c9bad73fb..50c40cda1ad626c09baf5c2cabc6a8a1ace2c87a 100644 --- a/src/components/Exploration/ExplorationFinished.spec.tsx +++ b/src/components/Exploration/ExplorationFinished.spec.tsx @@ -3,35 +3,13 @@ import StyledIcon from 'components/CommonKit/Icon/StyledIcon' import { mount } from 'enzyme' import React from 'react' import { Provider } from 'react-redux' -import configureStore from 'redux-mock-store' -import { globalStateData } from '../../../tests/__mocks__/globalStateData.mock' -import { userChallengeData } from '../../../tests/__mocks__/userChallengeData.mock' +import { createMockEcolyoStore } from 'tests/__mocks__/store' +import { userChallengeData } from 'tests/__mocks__/userChallengeData.mock' import ExplorationFinished from './ExplorationFinished' -jest.mock('cozy-ui/transpiled/react/I18n', () => { - return { - useI18n: jest.fn(() => { - return { - t: (str: string) => str, - } - }), - } -}) -const mockedNavigate = jest.fn() -jest.mock('react-router-dom', () => ({ - ...jest.requireActual('react-router-dom'), - useNavigate: () => mockedNavigate, -})) - -const mockStore = configureStore([]) - describe('ExplorationFinished', () => { + const store = createMockEcolyoStore() it('should be rendered correctly', () => { - const store = mockStore({ - ecolyo: { - global: globalStateData, - }, - }) const wrapper = mount( <Provider store={store}> <ExplorationFinished userChallenge={userChallengeData[0]} /> @@ -40,16 +18,11 @@ describe('ExplorationFinished', () => { expect(wrapper.find(StyledIcon).exists()).toBeTruthy() expect(wrapper.find('.congratulation').exists()).toBeTruthy() expect(wrapper.find('.exploration-earn').exists()).toBeTruthy() - expect(wrapper.find('.msg-sucess').text()).toEqual( + expect(wrapper.find('.msg-success').text()).toEqual( userChallengeData[0].exploration.message_success ) }) it('should redirect to challenge on click on styledButton', () => { - const store = mockStore({ - ecolyo: { - global: globalStateData, - }, - }) const wrapper = mount( <Provider store={store}> <ExplorationFinished userChallenge={userChallengeData[0]} /> diff --git a/src/components/Exploration/ExplorationFinished.tsx b/src/components/Exploration/ExplorationFinished.tsx index bbc2d5365db2528cd646f224d497c56ba32c63b8..e1251181a9918a1896d979231eacf183339d3594 100644 --- a/src/components/Exploration/ExplorationFinished.tsx +++ b/src/components/Exploration/ExplorationFinished.tsx @@ -1,20 +1,21 @@ import Button from '@material-ui/core/Button' import starResult from 'assets/icons/visu/quiz/starResult.svg' import StyledIcon from 'components/CommonKit/Icon/StyledIcon' -import { Client, useClient } from 'cozy-client' +import { useClient } from 'cozy-client' import { useI18n } from 'cozy-ui/transpiled/react/I18n' -import { UsageEventType } from 'enum/usageEvent.enum' -import { UserChallengeUpdateFlag } from 'enum/userChallenge.enum' -import { UserExplorationState } from 'enum/userExploration.enum' +import { + UsageEventType, + UserChallengeUpdateFlag, + UserExplorationState, +} from 'enums' import { UserChallenge } from 'models' -import React, { Dispatch, useCallback } from 'react' -import { useDispatch } from 'react-redux' +import React, { useCallback } from 'react' import { useNavigate } from 'react-router-dom' import ChallengeService from 'services/challenge.service' import UsageEventService from 'services/usageEvent.service' -import { AppActionsTypes } from 'store' import { updateUserChallengeList } from 'store/challenge/challenge.slice' -import { toggleChallengeExplorationNotification } from 'store/global/global.actions' +import { toggleChallengeExplorationNotification } from 'store/global/global.slice' +import { useAppDispatch } from 'store/hooks' import './explorationFinished.scss' interface ExplorationFinishedProps { @@ -22,9 +23,9 @@ interface ExplorationFinishedProps { } const ExplorationFinished = ({ userChallenge }: ExplorationFinishedProps) => { - const client: Client = useClient() const { t } = useI18n() - const dispatch = useDispatch<Dispatch<AppActionsTypes>>() + const client = useClient() + const dispatch = useAppDispatch() const navigate = useNavigate() const checkNotificationToEnd = useCallback(async () => { @@ -54,7 +55,7 @@ const ExplorationFinished = ({ userChallenge }: ExplorationFinishedProps) => { <div className="exploration-card"> <div className="exploration-finish"> <div className="congratulation">{t('exploration.congratulation')}</div> - <div className="msg-sucess"> + <div className="msg-success"> {userChallenge.exploration.message_success} </div> <div className="exploration-earn">{t('exploration.earn')}</div> diff --git a/src/components/Exploration/ExplorationOngoing.spec.tsx b/src/components/Exploration/ExplorationOngoing.spec.tsx index 55852f19d0fcec63bea51f5d29f69286a1f33089..fd468838a054e0940ab340371fa5e0856548697f 100644 --- a/src/components/Exploration/ExplorationOngoing.spec.tsx +++ b/src/components/Exploration/ExplorationOngoing.spec.tsx @@ -2,50 +2,21 @@ import ExplorationOngoing from 'components/Exploration/ExplorationOngoing' import { mount } from 'enzyme' import React from 'react' import { Provider } from 'react-redux' -import configureStore from 'redux-mock-store' -import { challengeStateData } from '../../../tests/__mocks__/challengeStateData.mock' -import { globalStateData } from '../../../tests/__mocks__/globalStateData.mock' -import { userChallengeData } from '../../../tests/__mocks__/userChallengeData.mock' - -jest.mock('cozy-ui/transpiled/react/I18n', () => { - return { - useI18n: jest.fn(() => { - return { - t: (str: string) => str, - } - }), - } -}) +import { createMockEcolyoStore } from 'tests/__mocks__/store' +import { userChallengeData } from 'tests/__mocks__/userChallengeData.mock' const mockUserChallengeUpdateFlag = jest.fn() const mockIsChallengeDone = jest.fn() jest.mock('services/challenge.service', () => { - return jest.fn(() => { - return { - updateUserChallenge: mockUserChallengeUpdateFlag, - isChallengeDone: mockIsChallengeDone, - } - }) + return jest.fn(() => ({ + updateUserChallenge: mockUserChallengeUpdateFlag, + isChallengeDone: mockIsChallengeDone, + })) }) -const mockHistoryPush = jest.fn() -jest.mock('react-router-dom', () => ({ - ...jest.requireActual('react-router-dom'), - useNavigate: () => ({ - push: mockHistoryPush, - }), -})) - -const mockStore = configureStore([]) - describe('ExplorationOngoing component', () => { it('should be rendered correctly', () => { - const store = mockStore({ - ecolyo: { - global: globalStateData, - challenge: challengeStateData, - }, - }) + const store = createMockEcolyoStore() const wrapper = mount( <Provider store={store}> <ExplorationOngoing userChallenge={userChallengeData[0]} /> diff --git a/src/components/Exploration/ExplorationOngoing.tsx b/src/components/Exploration/ExplorationOngoing.tsx index 68bec1b732511e1a9d143647131db987522b0771..9e817ec55e630e706c6aa3d69092b2dddc5061d5 100644 --- a/src/components/Exploration/ExplorationOngoing.tsx +++ b/src/components/Exploration/ExplorationOngoing.tsx @@ -1,23 +1,22 @@ import Button from '@material-ui/core/Button' import explorationIcon from 'assets/icons/visu/exploration/shield.svg' -import StarsContainer from 'components/Challenge/StarsContainer' import StyledIcon from 'components/CommonKit/Icon/StyledIcon' -import { Client, useClient } from 'cozy-client' +import StarsContainer from 'components/CommonKit/StarsContainer/StarsContainer' +import { useClient } from 'cozy-client' import { useI18n } from 'cozy-ui/transpiled/react/I18n' -import { UsageEventType } from 'enum/usageEvent.enum' -import { UserChallengeUpdateFlag } from 'enum/userChallenge.enum' import { + UsageEventType, + UserChallengeUpdateFlag, UserExplorationState, UserExplorationType, -} from 'enum/userExploration.enum' +} from 'enums' import { UserChallenge } from 'models' -import React, { Dispatch, useCallback } from 'react' -import { useDispatch } from 'react-redux' +import React from 'react' import { useNavigate } from 'react-router-dom' import ChallengeService from 'services/challenge.service' import UsageEventService from 'services/usageEvent.service' -import { AppActionsTypes } from 'store' import { updateUserChallengeList } from 'store/challenge/challenge.slice' +import { useAppDispatch } from 'store/hooks' import './explorationOngoing.scss' interface ExplorationOngoingProps { @@ -25,13 +24,10 @@ interface ExplorationOngoingProps { } const ExplorationOngoing = ({ userChallenge }: ExplorationOngoingProps) => { - const client: Client = useClient() const { t } = useI18n() - const dispatch = useDispatch<Dispatch<AppActionsTypes>>() + const client = useClient() + const dispatch = useAppDispatch() const navigate = useNavigate() - const goBack = useCallback(() => { - navigate(-1) - }, [navigate]) const startExploration = async () => { if (userChallenge.exploration.state !== UserExplorationState.ONGOING) { const challengeService = new ChallengeService(client) @@ -76,7 +72,7 @@ const ExplorationOngoing = ({ userChallenge }: ExplorationOngoingProps) => { </Button> <Button aria-label={t('exploration.accessibility.button_already_done')} - onClick={goBack} + onClick={() => navigate(-1)} classes={{ root: 'btn-secondary-negative', label: 'text-16-normal', diff --git a/src/components/Exploration/ExplorationView.spec.tsx b/src/components/Exploration/ExplorationView.spec.tsx index 90cfc6c0a0e695e1e84f70b5c97955fef2669b7d..ee403e980aae1b5d781265dc8e19e539e68ac1f6 100644 --- a/src/components/Exploration/ExplorationView.spec.tsx +++ b/src/components/Exploration/ExplorationView.spec.tsx @@ -1,9 +1,10 @@ -import { UserExplorationState } from 'enum/userExploration.enum' -import { shallow } from 'enzyme' +import { UserExplorationState } from 'enums' +import { mount } from 'enzyme' import React from 'react' -import * as reactRedux from 'react-redux' -import { challengeStateData } from '../../../tests/__mocks__/challengeStateData.mock' -import { userChallengeData } from '../../../tests/__mocks__/userChallengeData.mock' +import { Provider } from 'react-redux' +import { challengeStateData } from 'tests/__mocks__/challengeStateData.mock' +import { createMockEcolyoStore } from 'tests/__mocks__/store' +import { userChallengeData } from 'tests/__mocks__/userChallengeData.mock' import ExplorationError from './ExplorationError' import ExplorationFinished from './ExplorationFinished' import ExplorationOngoing from './ExplorationOngoing' @@ -13,8 +14,6 @@ jest.mock('components/Header/CozyBar', () => 'mock-cozybar') jest.mock('components/Header/Header', () => 'mock-header') jest.mock('components/Content/Content', () => 'mock-content') -const mockUseSelector = jest.spyOn(reactRedux, 'useSelector') - describe('ExplorationView', () => { it('should be rendered with ExplorationError component when unknown exploration state', () => { const updatedUserChallenge = { @@ -28,8 +27,12 @@ describe('ExplorationView', () => { ...challengeStateData, currentChallenge: updatedUserChallenge, } - mockUseSelector.mockReturnValue(updatedChallengeState) - const wrapper = shallow(<ExplorationView />) + const store = createMockEcolyoStore({ challenge: updatedChallengeState }) + const wrapper = mount( + <Provider store={store}> + <ExplorationView /> + </Provider> + ) expect(wrapper.find(ExplorationError).exists()).toBeTruthy() }) @@ -45,8 +48,12 @@ describe('ExplorationView', () => { ...challengeStateData, currentChallenge: updatedUserChallenge, } - mockUseSelector.mockReturnValue(updatedChallengeState) - const wrapper = shallow(<ExplorationView />) + const store = createMockEcolyoStore({ challenge: updatedChallengeState }) + const wrapper = mount( + <Provider store={store}> + <ExplorationView /> + </Provider> + ) expect(wrapper.find(ExplorationOngoing).exists()).toBeTruthy() }) @@ -62,8 +69,12 @@ describe('ExplorationView', () => { ...challengeStateData, currentChallenge: updatedUserChallenge, } - mockUseSelector.mockReturnValue(updatedChallengeState) - const wrapper = shallow(<ExplorationView />) + const store = createMockEcolyoStore({ challenge: updatedChallengeState }) + const wrapper = mount( + <Provider store={store}> + <ExplorationView /> + </Provider> + ) expect(wrapper.find(ExplorationOngoing).exists()).toBeTruthy() }) @@ -79,8 +90,12 @@ describe('ExplorationView', () => { ...challengeStateData, currentChallenge: updatedUserChallenge, } - mockUseSelector.mockReturnValue(updatedChallengeState) - const wrapper = shallow(<ExplorationView />) + const store = createMockEcolyoStore({ challenge: updatedChallengeState }) + const wrapper = mount( + <Provider store={store}> + <ExplorationView /> + </Provider> + ) expect(wrapper.find(ExplorationFinished).exists()).toBeTruthy() }) }) diff --git a/src/components/Exploration/ExplorationView.tsx b/src/components/Exploration/ExplorationView.tsx index b08315fbbd9eb35b9b71449ea4342fb515bb102d..54106238c9db76a3568939e1d8555de613288457 100644 --- a/src/components/Exploration/ExplorationView.tsx +++ b/src/components/Exploration/ExplorationView.tsx @@ -1,24 +1,17 @@ import Content from 'components/Content/Content' import CozyBar from 'components/Header/CozyBar' import Header from 'components/Header/Header' -import { UserExplorationState } from 'enum/userExploration.enum' +import { UserExplorationState } from 'enums' import { UserChallenge } from 'models' -import React, { useCallback, useState } from 'react' -import { useSelector } from 'react-redux' -import { AppStore } from 'store' +import React, { useState } from 'react' +import { useAppSelector } from 'store/hooks' import ExplorationError from './ExplorationError' import ExplorationFinished from './ExplorationFinished' import ExplorationOngoing from './ExplorationOngoing' const ExplorationView = () => { + const { currentChallenge } = useAppSelector(state => state.ecolyo.challenge) const [headerHeight, setHeaderHeight] = useState<number>(0) - const { currentChallenge } = useSelector( - (state: AppStore) => state.ecolyo.challenge - ) - - const defineHeaderHeight = useCallback((height: number) => { - setHeaderHeight(height) - }, []) const renderExploration = (challenge: UserChallenge) => { switch (challenge.exploration.state) { @@ -35,13 +28,13 @@ const ExplorationView = () => { return ( <> - <CozyBar titleKey={'common.title_exploration'} displayBackArrow={true} /> + <CozyBar titleKey="common.title_exploration" displayBackArrow={true} /> <Header - setHeaderHeight={defineHeaderHeight} - desktopTitleKey={'common.title_exploration'} + setHeaderHeight={setHeaderHeight} + desktopTitleKey="common.title_exploration" displayBackArrow={true} /> - <Content height={headerHeight}> + <Content heightOffset={headerHeight}> {currentChallenge && renderExploration(currentChallenge)} </Content> </> diff --git a/src/components/Exploration/explorationError.scss b/src/components/Exploration/explorationError.scss index 9c747d83a044c9cb1c9fe7975d78348b059ba188..119d190c47f3abb5eedbd5d52d6aec464719bfb7 100644 --- a/src/components/Exploration/explorationError.scss +++ b/src/components/Exploration/explorationError.scss @@ -1,4 +1,4 @@ -@import '../../styles/base/color'; +@import 'src/styles/base/color'; .exploration-error-container { display: flex; diff --git a/src/components/Exploration/explorationFinished.scss b/src/components/Exploration/explorationFinished.scss index b9110a27750cbd096ec0b1a42ace2718736c33a0..17fed8e73a2f30b6179471b75a27311b12783e9a 100644 --- a/src/components/Exploration/explorationFinished.scss +++ b/src/components/Exploration/explorationFinished.scss @@ -1,5 +1,5 @@ -@import '../../styles/base/color'; -@import '../../styles/base/breakpoint'; +@import 'src/styles/base/color'; +@import 'src/styles/base/breakpoint'; .exploration-card { display: flex; diff --git a/src/components/Exploration/explorationOngoing.scss b/src/components/Exploration/explorationOngoing.scss index 81ebd1521a1d8db3531a78809ec51586a8e08fb9..69589be0633223c28c43bf9ba002f7af234e1c0c 100644 --- a/src/components/Exploration/explorationOngoing.scss +++ b/src/components/Exploration/explorationOngoing.scss @@ -1,5 +1,5 @@ -@import '../../styles/base/color'; -@import '../../styles/base/breakpoint'; +@import 'src/styles/base/color'; +@import 'src/styles/base/breakpoint'; .exploration-container { display: flex; diff --git a/src/components/Feedback/FeedbackModal.spec.tsx b/src/components/Feedback/FeedbackModal.spec.tsx index 5f3afdd466a9dd5add00245557cbd75e9e07b5bf..8c7520ace692c3c63def7c746685546311306ebd 100644 --- a/src/components/Feedback/FeedbackModal.spec.tsx +++ b/src/components/Feedback/FeedbackModal.spec.tsx @@ -1,101 +1,70 @@ import FeedbackModal from 'components/Feedback/FeedbackModal' import { mount } from 'enzyme' +import toJson from 'enzyme-to-json' import React from 'react' -import * as reactRedux from 'react-redux' import { Provider } from 'react-redux' -import { BrowserRouter } from 'react-router-dom' -import { createMockEcolyoStore } from '../../../tests/__mocks__/store' -import { waitForComponentToPaint } from '../../../tests/__mocks__/testUtils' -import { userChallengeExplo1OnGoing } from '../../../tests/__mocks__/userChallengeData.mock' +import * as storeHooks from 'store/hooks' +import { createMockEcolyoStore } from 'tests/__mocks__/store' // Value coming from jest.config declare let __SAU_LINK__: string -jest.mock('cozy-ui/transpiled/react/I18n', () => { - return { - useI18n: jest.fn(() => { - return { - t: (str: string) => str, - } - }), - } -}) - jest.mock('services/environment.service', () => { - return jest.fn(() => { - return { - isProduction: () => true, - } - }) + return jest.fn(() => ({ + isProduction: () => true, + })) }) -const handleFeedbackModalClose = jest.fn() +jest.mock('components/Hooks/useExploration', () => () => ['', jest.fn()]) -const mockUseSelector = jest.spyOn(reactRedux, 'useSelector') -const mockUseDispatch = jest.spyOn(reactRedux, 'useDispatch') +const mockAppDispatch = jest.spyOn(storeHooks, 'useAppDispatch') describe('FeedbackModal component', () => { - const store = createMockEcolyoStore() + const store = createMockEcolyoStore({ modal: { isFeedbacksOpen: true } }) beforeEach(() => { - store.clearActions() + jest.clearAllMocks() }) it('should render the component', () => { - mockUseDispatch.mockReturnValue(jest.fn()) const component = mount( <Provider store={store}> - <BrowserRouter> - <FeedbackModal - open={true} - handleCloseClick={handleFeedbackModalClose} - /> - </BrowserRouter> + <FeedbackModal /> </Provider> - ).getElement() - expect(component).toMatchSnapshot() - }) -}) -describe('FeedbackModal functionalities', () => { - const store = createMockEcolyoStore() - beforeEach(() => { - store.clearActions() + ) + expect(toJson(component)).toMatchSnapshot() }) - it('should close the modal', async () => { - mockUseDispatch.mockReturnValue(jest.fn()) - mockUseSelector.mockReturnValue(userChallengeExplo1OnGoing) - const wrapper = mount( - <Provider store={store}> - <BrowserRouter> - <FeedbackModal - open={true} - handleCloseClick={handleFeedbackModalClose} - /> - </BrowserRouter> - </Provider> - ) - await waitForComponentToPaint(wrapper) + describe('FeedbackModal functionalities', () => { + it('should close modal with the "x" button', async () => { + const wrapper = mount( + <Provider store={store}> + <FeedbackModal /> + </Provider> + ) - wrapper.find('.modal-paper-close-button').first().simulate('click') - expect(handleFeedbackModalClose).toHaveBeenCalledTimes(1) - wrapper.find('.btn-secondary-positive').first().simulate('click') - expect(handleFeedbackModalClose).toHaveBeenCalledTimes(2) - }) + wrapper.find('.modal-paper-close-button').first().simulate('click') + expect(mockAppDispatch).toHaveBeenCalledTimes(1) + }) - it('should open the SAU link', () => { - global.open = jest.fn() + it('should close modal with the "later" button', async () => { + const wrapper = mount( + <Provider store={store}> + <FeedbackModal /> + </Provider> + ) + wrapper.find('.btn-secondary-positive').first().simulate('click') + expect(mockAppDispatch).toHaveBeenCalledTimes(1) + }) - const wrapper = mount( - <Provider store={store}> - <BrowserRouter> - <FeedbackModal - open={true} - handleCloseClick={handleFeedbackModalClose} - /> - </BrowserRouter> - </Provider> - ) - wrapper.find('.btn-highlight').first().simulate('click') - expect(window.open).toBeCalledTimes(1) - expect(global.open).toHaveBeenCalledWith(`${__SAU_LINK__}?version=0.0.0`) + it('should open the SAU link', () => { + global.open = jest.fn() + const wrapper = mount( + <Provider store={store}> + <FeedbackModal /> + </Provider> + ) + wrapper.find('.btn-highlight').first().simulate('click') + expect(window.open).toHaveBeenCalledTimes(1) + expect(global.open).toHaveBeenCalledWith(`${__SAU_LINK__}?version=0.0.0`) + }) }) }) diff --git a/src/components/Feedback/FeedbackModal.tsx b/src/components/Feedback/FeedbackModal.tsx index e3858f129f868e2fd709e2dc1204071768ebd897..41ce4648465da72e184fa3f3836d57f24a925fb0 100644 --- a/src/components/Feedback/FeedbackModal.tsx +++ b/src/components/Feedback/FeedbackModal.tsx @@ -5,27 +5,26 @@ import CloseIcon from 'assets/icons/ico/close.svg' import ecolyoIcon from 'assets/icons/ico/ecolyo.svg' import StyledIcon from 'components/CommonKit/Icon/StyledIcon' import useExploration from 'components/Hooks/useExploration' -import { Client, useClient } from 'cozy-client' -import { IuseI18n, useI18n } from 'cozy-ui/transpiled/react/I18n' +import { useClient } from 'cozy-client' +import { useI18n } from 'cozy-ui/transpiled/react/I18n' import Icon from 'cozy-ui/transpiled/react/Icon' -import { UserExplorationID } from 'enum/userExploration.enum' +import { UserExplorationID } from 'enums' import React from 'react' +import { useAppDispatch, useAppSelector } from 'store/hooks' +import { openFeedbackModal } from 'store/modal/modal.slice' import './feedbackModal.scss' declare let __SAU_LINK__: string -interface FeedbackModalProps { - open: boolean - handleCloseClick: () => void -} - -const FeedbackModal = ({ open, handleCloseClick }: FeedbackModalProps) => { - const { t }: IuseI18n = useI18n() - const client: Client = useClient() +const FeedbackModal = () => { + const { t } = useI18n() + const client = useClient() + const dispatch = useAppDispatch() + const { isFeedbacksOpen } = useAppSelector(state => state.ecolyo.modal) const [, setValidExploration] = useExploration() const closeModal = () => { - handleCloseClick() + dispatch(openFeedbackModal(false)) } const goToSAU = () => { @@ -35,18 +34,15 @@ const FeedbackModal = ({ open, handleCloseClick }: FeedbackModalProps) => { return ( <Dialog - open={open} - onClose={(event, reason): void => { - event && reason !== 'backdropClick' && closeModal() - }} - disableEscapeKeyDown - aria-labelledby={'accessibility-title'} + open={isFeedbacksOpen} + onClose={() => closeModal()} + aria-labelledby="accessibility-title" classes={{ root: 'modal-root', paper: 'modal-paper yellow-border', }} > - <div id={'accessibility-title'}> + <div id="accessibility-title"> {t('feedback.accessibility.window_title')} </div> <IconButton diff --git a/src/components/Feedback/__snapshots__/FeedbackModal.spec.tsx.snap b/src/components/Feedback/__snapshots__/FeedbackModal.spec.tsx.snap index bbf516e897809c47d29676f2b8e2c70d1526908c..d9288b66bd3795c0b1e3f168684e968353440b6c 100644 --- a/src/components/Feedback/__snapshots__/FeedbackModal.spec.tsx.snap +++ b/src/components/Feedback/__snapshots__/FeedbackModal.spec.tsx.snap @@ -13,11 +13,1166 @@ exports[`FeedbackModal component should render the component 1`] = ` } } > - <BrowserRouter> - <FeedbackModal - handleCloseClick={[MockFunction]} + <FeedbackModal> + <WithStyles(ForwardRef(Dialog)) + aria-labelledby="accessibility-title" + classes={ + Object { + "paper": "modal-paper yellow-border", + "root": "modal-root", + } + } + onClose={[Function]} open={true} - /> - </BrowserRouter> + > + <ForwardRef(Dialog) + aria-labelledby="accessibility-title" + classes={ + Object { + "container": "MuiDialog-container", + "paper": "MuiDialog-paper modal-paper yellow-border", + "paperFullScreen": "MuiDialog-paperFullScreen", + "paperFullWidth": "MuiDialog-paperFullWidth", + "paperScrollBody": "MuiDialog-paperScrollBody", + "paperScrollPaper": "MuiDialog-paperScrollPaper", + "paperWidthFalse": "MuiDialog-paperWidthFalse", + "paperWidthLg": "MuiDialog-paperWidthLg", + "paperWidthMd": "MuiDialog-paperWidthMd", + "paperWidthSm": "MuiDialog-paperWidthSm", + "paperWidthXl": "MuiDialog-paperWidthXl", + "paperWidthXs": "MuiDialog-paperWidthXs", + "root": "MuiDialog-root modal-root", + "scrollBody": "MuiDialog-scrollBody", + "scrollPaper": "MuiDialog-scrollPaper", + } + } + onClose={[Function]} + open={true} + > + <ForwardRef(Modal) + BackdropComponent={ + Object { + "$$typeof": Symbol(react.forward_ref), + "Naked": Object { + "$$typeof": Symbol(react.forward_ref), + "propTypes": Object { + "children": [Function], + "className": [Function], + "classes": [Function], + "invisible": [Function], + "open": [Function], + "transitionDuration": [Function], + }, + "render": [Function], + }, + "displayName": "WithStyles(ForwardRef(Backdrop))", + "options": Object { + "defaultTheme": Object { + "breakpoints": Object { + "between": [Function], + "down": [Function], + "keys": Array [ + "xs", + "sm", + "md", + "lg", + "xl", + ], + "only": [Function], + "up": [Function], + "values": Object { + "lg": 1280, + "md": 960, + "sm": 600, + "xl": 1920, + "xs": 0, + }, + "width": [Function], + }, + "direction": "ltr", + "mixins": Object { + "gutters": [Function], + "toolbar": Object { + "@media (min-width:0px) and (orientation: landscape)": Object { + "minHeight": 48, + }, + "@media (min-width:600px)": Object { + "minHeight": 64, + }, + "minHeight": 56, + }, + }, + "overrides": Object {}, + "palette": Object { + "action": Object { + "activatedOpacity": 0.12, + "active": "rgba(0, 0, 0, 0.54)", + "disabled": "rgba(0, 0, 0, 0.26)", + "disabledBackground": "rgba(0, 0, 0, 0.12)", + "disabledOpacity": 0.38, + "focus": "rgba(0, 0, 0, 0.12)", + "focusOpacity": 0.12, + "hover": "rgba(0, 0, 0, 0.04)", + "hoverOpacity": 0.04, + "selected": "rgba(0, 0, 0, 0.08)", + "selectedOpacity": 0.08, + }, + "augmentColor": [Function], + "background": Object { + "default": "#fafafa", + "paper": "#fff", + }, + "common": Object { + "black": "#000", + "white": "#fff", + }, + "contrastThreshold": 3, + "divider": "rgba(0, 0, 0, 0.12)", + "error": Object { + "contrastText": "#fff", + "dark": "#d32f2f", + "light": "#e57373", + "main": "#f44336", + }, + "getContrastText": [Function], + "grey": Object { + "100": "#f5f5f5", + "200": "#eeeeee", + "300": "#e0e0e0", + "400": "#bdbdbd", + "50": "#fafafa", + "500": "#9e9e9e", + "600": "#757575", + "700": "#616161", + "800": "#424242", + "900": "#212121", + "A100": "#d5d5d5", + "A200": "#aaaaaa", + "A400": "#303030", + "A700": "#616161", + }, + "info": Object { + "contrastText": "#fff", + "dark": "#1976d2", + "light": "#64b5f6", + "main": "#2196f3", + }, + "primary": Object { + "contrastText": "#fff", + "dark": "#303f9f", + "light": "#7986cb", + "main": "#3f51b5", + }, + "secondary": Object { + "contrastText": "#fff", + "dark": "#c51162", + "light": "#ff4081", + "main": "#f50057", + }, + "success": Object { + "contrastText": "rgba(0, 0, 0, 0.87)", + "dark": "#388e3c", + "light": "#81c784", + "main": "#4caf50", + }, + "text": Object { + "disabled": "rgba(0, 0, 0, 0.38)", + "hint": "rgba(0, 0, 0, 0.38)", + "primary": "rgba(0, 0, 0, 0.87)", + "secondary": "rgba(0, 0, 0, 0.54)", + }, + "tonalOffset": 0.2, + "type": "light", + "warning": Object { + "contrastText": "rgba(0, 0, 0, 0.87)", + "dark": "#f57c00", + "light": "#ffb74d", + "main": "#ff9800", + }, + }, + "props": Object {}, + "shadows": Array [ + "none", + "0px 2px 1px -1px rgba(0,0,0,0.2),0px 1px 1px 0px rgba(0,0,0,0.14),0px 1px 3px 0px rgba(0,0,0,0.12)", + "0px 3px 1px -2px rgba(0,0,0,0.2),0px 2px 2px 0px rgba(0,0,0,0.14),0px 1px 5px 0px rgba(0,0,0,0.12)", + "0px 3px 3px -2px rgba(0,0,0,0.2),0px 3px 4px 0px rgba(0,0,0,0.14),0px 1px 8px 0px rgba(0,0,0,0.12)", + "0px 2px 4px -1px rgba(0,0,0,0.2),0px 4px 5px 0px rgba(0,0,0,0.14),0px 1px 10px 0px rgba(0,0,0,0.12)", + "0px 3px 5px -1px rgba(0,0,0,0.2),0px 5px 8px 0px rgba(0,0,0,0.14),0px 1px 14px 0px rgba(0,0,0,0.12)", + "0px 3px 5px -1px rgba(0,0,0,0.2),0px 6px 10px 0px rgba(0,0,0,0.14),0px 1px 18px 0px rgba(0,0,0,0.12)", + "0px 4px 5px -2px rgba(0,0,0,0.2),0px 7px 10px 1px rgba(0,0,0,0.14),0px 2px 16px 1px rgba(0,0,0,0.12)", + "0px 5px 5px -3px rgba(0,0,0,0.2),0px 8px 10px 1px rgba(0,0,0,0.14),0px 3px 14px 2px rgba(0,0,0,0.12)", + "0px 5px 6px -3px rgba(0,0,0,0.2),0px 9px 12px 1px rgba(0,0,0,0.14),0px 3px 16px 2px rgba(0,0,0,0.12)", + "0px 6px 6px -3px rgba(0,0,0,0.2),0px 10px 14px 1px rgba(0,0,0,0.14),0px 4px 18px 3px rgba(0,0,0,0.12)", + "0px 6px 7px -4px rgba(0,0,0,0.2),0px 11px 15px 1px rgba(0,0,0,0.14),0px 4px 20px 3px rgba(0,0,0,0.12)", + "0px 7px 8px -4px rgba(0,0,0,0.2),0px 12px 17px 2px rgba(0,0,0,0.14),0px 5px 22px 4px rgba(0,0,0,0.12)", + "0px 7px 8px -4px rgba(0,0,0,0.2),0px 13px 19px 2px rgba(0,0,0,0.14),0px 5px 24px 4px rgba(0,0,0,0.12)", + "0px 7px 9px -4px rgba(0,0,0,0.2),0px 14px 21px 2px rgba(0,0,0,0.14),0px 5px 26px 4px rgba(0,0,0,0.12)", + "0px 8px 9px -5px rgba(0,0,0,0.2),0px 15px 22px 2px rgba(0,0,0,0.14),0px 6px 28px 5px rgba(0,0,0,0.12)", + "0px 8px 10px -5px rgba(0,0,0,0.2),0px 16px 24px 2px rgba(0,0,0,0.14),0px 6px 30px 5px rgba(0,0,0,0.12)", + "0px 8px 11px -5px rgba(0,0,0,0.2),0px 17px 26px 2px rgba(0,0,0,0.14),0px 6px 32px 5px rgba(0,0,0,0.12)", + "0px 9px 11px -5px rgba(0,0,0,0.2),0px 18px 28px 2px rgba(0,0,0,0.14),0px 7px 34px 6px rgba(0,0,0,0.12)", + "0px 9px 12px -6px rgba(0,0,0,0.2),0px 19px 29px 2px rgba(0,0,0,0.14),0px 7px 36px 6px rgba(0,0,0,0.12)", + "0px 10px 13px -6px rgba(0,0,0,0.2),0px 20px 31px 3px rgba(0,0,0,0.14),0px 8px 38px 7px rgba(0,0,0,0.12)", + "0px 10px 13px -6px rgba(0,0,0,0.2),0px 21px 33px 3px rgba(0,0,0,0.14),0px 8px 40px 7px rgba(0,0,0,0.12)", + "0px 10px 14px -6px rgba(0,0,0,0.2),0px 22px 35px 3px rgba(0,0,0,0.14),0px 8px 42px 7px rgba(0,0,0,0.12)", + "0px 11px 14px -7px rgba(0,0,0,0.2),0px 23px 36px 3px rgba(0,0,0,0.14),0px 9px 44px 8px rgba(0,0,0,0.12)", + "0px 11px 15px -7px rgba(0,0,0,0.2),0px 24px 38px 3px rgba(0,0,0,0.14),0px 9px 46px 8px rgba(0,0,0,0.12)", + ], + "shape": Object { + "borderRadius": 4, + }, + "spacing": [Function], + "transitions": Object { + "create": [Function], + "duration": Object { + "complex": 375, + "enteringScreen": 225, + "leavingScreen": 195, + "short": 250, + "shorter": 200, + "shortest": 150, + "standard": 300, + }, + "easing": Object { + "easeIn": "cubic-bezier(0.4, 0, 1, 1)", + "easeInOut": "cubic-bezier(0.4, 0, 0.2, 1)", + "easeOut": "cubic-bezier(0.0, 0, 0.2, 1)", + "sharp": "cubic-bezier(0.4, 0, 0.6, 1)", + }, + "getAutoHeightDuration": [Function], + }, + "typography": Object { + "body1": Object { + "fontFamily": "\\"Roboto\\", \\"Helvetica\\", \\"Arial\\", sans-serif", + "fontSize": "1rem", + "fontWeight": 400, + "letterSpacing": "0.00938em", + "lineHeight": 1.5, + }, + "body2": Object { + "fontFamily": "\\"Roboto\\", \\"Helvetica\\", \\"Arial\\", sans-serif", + "fontSize": "0.875rem", + "fontWeight": 400, + "letterSpacing": "0.01071em", + "lineHeight": 1.43, + }, + "button": Object { + "fontFamily": "\\"Roboto\\", \\"Helvetica\\", \\"Arial\\", sans-serif", + "fontSize": "0.875rem", + "fontWeight": 500, + "letterSpacing": "0.02857em", + "lineHeight": 1.75, + "textTransform": "uppercase", + }, + "caption": Object { + "fontFamily": "\\"Roboto\\", \\"Helvetica\\", \\"Arial\\", sans-serif", + "fontSize": "0.75rem", + "fontWeight": 400, + "letterSpacing": "0.03333em", + "lineHeight": 1.66, + }, + "fontFamily": "\\"Roboto\\", \\"Helvetica\\", \\"Arial\\", sans-serif", + "fontSize": 14, + "fontWeightBold": 700, + "fontWeightLight": 300, + "fontWeightMedium": 500, + "fontWeightRegular": 400, + "h1": Object { + "fontFamily": "\\"Roboto\\", \\"Helvetica\\", \\"Arial\\", sans-serif", + "fontSize": "6rem", + "fontWeight": 300, + "letterSpacing": "-0.01562em", + "lineHeight": 1.167, + }, + "h2": Object { + "fontFamily": "\\"Roboto\\", \\"Helvetica\\", \\"Arial\\", sans-serif", + "fontSize": "3.75rem", + "fontWeight": 300, + "letterSpacing": "-0.00833em", + "lineHeight": 1.2, + }, + "h3": Object { + "fontFamily": "\\"Roboto\\", \\"Helvetica\\", \\"Arial\\", sans-serif", + "fontSize": "3rem", + "fontWeight": 400, + "letterSpacing": "0em", + "lineHeight": 1.167, + }, + "h4": Object { + "fontFamily": "\\"Roboto\\", \\"Helvetica\\", \\"Arial\\", sans-serif", + "fontSize": "2.125rem", + "fontWeight": 400, + "letterSpacing": "0.00735em", + "lineHeight": 1.235, + }, + "h5": Object { + "fontFamily": "\\"Roboto\\", \\"Helvetica\\", \\"Arial\\", sans-serif", + "fontSize": "1.5rem", + "fontWeight": 400, + "letterSpacing": "0em", + "lineHeight": 1.334, + }, + "h6": Object { + "fontFamily": "\\"Roboto\\", \\"Helvetica\\", \\"Arial\\", sans-serif", + "fontSize": "1.25rem", + "fontWeight": 500, + "letterSpacing": "0.0075em", + "lineHeight": 1.6, + }, + "htmlFontSize": 16, + "overline": Object { + "fontFamily": "\\"Roboto\\", \\"Helvetica\\", \\"Arial\\", sans-serif", + "fontSize": "0.75rem", + "fontWeight": 400, + "letterSpacing": "0.08333em", + "lineHeight": 2.66, + "textTransform": "uppercase", + }, + "pxToRem": [Function], + "round": [Function], + "subtitle1": Object { + "fontFamily": "\\"Roboto\\", \\"Helvetica\\", \\"Arial\\", sans-serif", + "fontSize": "1rem", + "fontWeight": 400, + "letterSpacing": "0.00938em", + "lineHeight": 1.75, + }, + "subtitle2": Object { + "fontFamily": "\\"Roboto\\", \\"Helvetica\\", \\"Arial\\", sans-serif", + "fontSize": "0.875rem", + "fontWeight": 500, + "letterSpacing": "0.00714em", + "lineHeight": 1.57, + }, + }, + "zIndex": Object { + "appBar": 1100, + "drawer": 1200, + "mobileStepper": 1000, + "modal": 1300, + "snackbar": 1400, + "speedDial": 1050, + "tooltip": 1500, + }, + }, + "name": "MuiBackdrop", + }, + "propTypes": Object { + "classes": [Function], + "innerRef": [Function], + }, + "render": [Function], + "useStyles": [Function], + } + } + BackdropProps={ + Object { + "transitionDuration": Object { + "enter": 225, + "exit": 195, + }, + } + } + className="MuiDialog-root modal-root" + closeAfterTransition={true} + disableEscapeKeyDown={false} + onClose={[Function]} + open={true} + > + <ForwardRef(Portal) + disablePortal={false} + > + <Portal + containerInfo={ + <body + style="padding-right: 0px; overflow: hidden;" + > + <div + class="MuiDialog-root modal-root" + role="presentation" + style="position: fixed; z-index: 1300; right: 0px; bottom: 0px; top: 0px; left: 0px;" + > + <div + aria-hidden="true" + class="MuiBackdrop-root" + style="opacity: 1; webkit-transition: opacity 225ms cubic-bezier(0.4, 0, 0.2, 1) 0ms; transition: opacity 225ms cubic-bezier(0.4, 0, 0.2, 1) 0ms;" + /> + <div + data-test="sentinelStart" + tabindex="0" + /> + <div + class="MuiDialog-container MuiDialog-scrollPaper" + role="none presentation" + style="opacity: 1; webkit-transition: opacity 225ms cubic-bezier(0.4, 0, 0.2, 1) 0ms; transition: opacity 225ms cubic-bezier(0.4, 0, 0.2, 1) 0ms;" + tabindex="-1" + > + <div + aria-labelledby="accessibility-title" + class="MuiPaper-root MuiDialog-paper modal-paper yellow-border MuiDialog-paperScrollPaper MuiDialog-paperWidthSm MuiPaper-elevation24 MuiPaper-rounded" + role="dialog" + > + <div + id="accessibility-title" + > + feedback.accessibility.window_title + </div> + <button + aria-label="feedback.accessibility.button_close" + class="MuiButtonBase-root MuiIconButton-root modal-paper-close-button" + tabindex="0" + type="button" + > + <span + class="MuiIconButton-label" + > + <svg + class="styles__icon___23x3R" + height="16" + width="16" + > + <use + xlink:href="#test-file-stub" + /> + </svg> + </span> + <span + class="MuiTouchRipple-root" + /> + </button> + <div + class="fb-root" + > + <svg + aria-hidden="true" + class="styles__icon___23x3R" + height="80" + width="80" + > + <use + xlink:href="#test-file-stub" + /> + </svg> + <p + class="title" + > + feedback.title + </p> + <p + class="text" + > + feedback.text1 + </p> + <p + class="text" + > + feedback.text2 + </p> + <div + class="actions" + > + <button + aria-label="feedback.later" + class="MuiButtonBase-root MuiButton-root btn-secondary-positive MuiButton-text" + tabindex="0" + type="button" + > + <span + class="MuiButton-label text-16-bold" + > + feedback.later + </span> + <span + class="MuiTouchRipple-root" + /> + </button> + <button + aria-label="feedback.lets_go" + class="MuiButtonBase-root MuiButton-root btn-highlight MuiButton-text" + tabindex="0" + type="button" + > + <span + class="MuiButton-label text-16-bold" + > + feedback.lets_go + </span> + <span + class="MuiTouchRipple-root" + /> + </button> + </div> + </div> + </div> + </div> + <div + data-test="sentinelEnd" + tabindex="0" + /> + </div> + </body> + } + > + <div + className="MuiDialog-root modal-root" + onKeyDown={[Function]} + role="presentation" + style={ + Object { + "bottom": 0, + "left": 0, + "position": "fixed", + "right": 0, + "top": 0, + "zIndex": 1300, + } + } + > + <WithStyles(ForwardRef(Backdrop)) + onClick={[Function]} + open={true} + transitionDuration={ + Object { + "enter": 225, + "exit": 195, + } + } + > + <ForwardRef(Backdrop) + classes={ + Object { + "invisible": "MuiBackdrop-invisible", + "root": "MuiBackdrop-root", + } + } + onClick={[Function]} + open={true} + transitionDuration={ + Object { + "enter": 225, + "exit": 195, + } + } + > + <ForwardRef(Fade) + in={true} + onClick={[Function]} + timeout={ + Object { + "enter": 225, + "exit": 195, + } + } + > + <Transition + appear={true} + enter={true} + exit={true} + in={true} + mountOnEnter={false} + onClick={[Function]} + onEnter={[Function]} + onEntered={[Function]} + onEntering={[Function]} + onExit={[Function]} + onExited={[Function]} + onExiting={[Function]} + timeout={ + Object { + "enter": 225, + "exit": 195, + } + } + unmountOnExit={false} + > + <div + aria-hidden={true} + className="MuiBackdrop-root" + onClick={[Function]} + style={ + Object { + "opacity": 1, + "visibility": undefined, + } + } + /> + </Transition> + </ForwardRef(Fade)> + </ForwardRef(Backdrop)> + </WithStyles(ForwardRef(Backdrop))> + <Unstable_TrapFocus + disableAutoFocus={false} + disableEnforceFocus={false} + disableRestoreFocus={false} + getDoc={[Function]} + isEnabled={[Function]} + open={true} + > + <div + data-test="sentinelStart" + tabIndex={0} + /> + <ForwardRef(Fade) + appear={true} + in={true} + onEnter={[Function]} + onExited={[Function]} + role="none presentation" + tabIndex="-1" + timeout={ + Object { + "enter": 225, + "exit": 195, + } + } + > + <Transition + appear={true} + enter={true} + exit={true} + in={true} + mountOnEnter={false} + onEnter={[Function]} + onEntered={[Function]} + onEntering={[Function]} + onExit={[Function]} + onExited={[Function]} + onExiting={[Function]} + role="none presentation" + tabIndex="-1" + timeout={ + Object { + "enter": 225, + "exit": 195, + } + } + unmountOnExit={false} + > + <div + className="MuiDialog-container MuiDialog-scrollPaper" + onMouseDown={[Function]} + onMouseUp={[Function]} + role="none presentation" + style={ + Object { + "opacity": 1, + "visibility": undefined, + } + } + tabIndex="-1" + > + <WithStyles(ForwardRef(Paper)) + aria-labelledby="accessibility-title" + className="MuiDialog-paper modal-paper yellow-border MuiDialog-paperScrollPaper MuiDialog-paperWidthSm" + elevation={24} + role="dialog" + > + <ForwardRef(Paper) + aria-labelledby="accessibility-title" + className="MuiDialog-paper modal-paper yellow-border MuiDialog-paperScrollPaper MuiDialog-paperWidthSm" + classes={ + Object { + "elevation0": "MuiPaper-elevation0", + "elevation1": "MuiPaper-elevation1", + "elevation10": "MuiPaper-elevation10", + "elevation11": "MuiPaper-elevation11", + "elevation12": "MuiPaper-elevation12", + "elevation13": "MuiPaper-elevation13", + "elevation14": "MuiPaper-elevation14", + "elevation15": "MuiPaper-elevation15", + "elevation16": "MuiPaper-elevation16", + "elevation17": "MuiPaper-elevation17", + "elevation18": "MuiPaper-elevation18", + "elevation19": "MuiPaper-elevation19", + "elevation2": "MuiPaper-elevation2", + "elevation20": "MuiPaper-elevation20", + "elevation21": "MuiPaper-elevation21", + "elevation22": "MuiPaper-elevation22", + "elevation23": "MuiPaper-elevation23", + "elevation24": "MuiPaper-elevation24", + "elevation3": "MuiPaper-elevation3", + "elevation4": "MuiPaper-elevation4", + "elevation5": "MuiPaper-elevation5", + "elevation6": "MuiPaper-elevation6", + "elevation7": "MuiPaper-elevation7", + "elevation8": "MuiPaper-elevation8", + "elevation9": "MuiPaper-elevation9", + "outlined": "MuiPaper-outlined", + "root": "MuiPaper-root", + "rounded": "MuiPaper-rounded", + } + } + elevation={24} + role="dialog" + > + <div + aria-labelledby="accessibility-title" + className="MuiPaper-root MuiDialog-paper modal-paper yellow-border MuiDialog-paperScrollPaper MuiDialog-paperWidthSm MuiPaper-elevation24 MuiPaper-rounded" + role="dialog" + > + <div + id="accessibility-title" + > + feedback.accessibility.window_title + </div> + <WithStyles(ForwardRef(IconButton)) + aria-label="feedback.accessibility.button_close" + className="modal-paper-close-button" + onClick={[Function]} + > + <ForwardRef(IconButton) + aria-label="feedback.accessibility.button_close" + className="modal-paper-close-button" + classes={ + Object { + "colorInherit": "MuiIconButton-colorInherit", + "colorPrimary": "MuiIconButton-colorPrimary", + "colorSecondary": "MuiIconButton-colorSecondary", + "disabled": "Mui-disabled", + "edgeEnd": "MuiIconButton-edgeEnd", + "edgeStart": "MuiIconButton-edgeStart", + "label": "MuiIconButton-label", + "root": "MuiIconButton-root", + "sizeSmall": "MuiIconButton-sizeSmall", + } + } + onClick={[Function]} + > + <WithStyles(ForwardRef(ButtonBase)) + aria-label="feedback.accessibility.button_close" + centerRipple={true} + className="MuiIconButton-root modal-paper-close-button" + disabled={false} + focusRipple={true} + onClick={[Function]} + > + <ForwardRef(ButtonBase) + aria-label="feedback.accessibility.button_close" + centerRipple={true} + className="MuiIconButton-root modal-paper-close-button" + classes={ + Object { + "disabled": "Mui-disabled", + "focusVisible": "Mui-focusVisible", + "root": "MuiButtonBase-root", + } + } + disabled={false} + focusRipple={true} + onClick={[Function]} + > + <button + aria-label="feedback.accessibility.button_close" + className="MuiButtonBase-root MuiIconButton-root modal-paper-close-button" + disabled={false} + onBlur={[Function]} + onClick={[Function]} + onDragLeave={[Function]} + onFocus={[Function]} + onKeyDown={[Function]} + onKeyUp={[Function]} + onMouseDown={[Function]} + onMouseLeave={[Function]} + onMouseUp={[Function]} + onTouchEnd={[Function]} + onTouchMove={[Function]} + onTouchStart={[Function]} + tabIndex={0} + type="button" + > + <span + className="MuiIconButton-label" + > + <Icon + icon="test-file-stub" + size={16} + spin={false} + > + <Component + className="styles__icon___23x3R" + height={16} + style={Object {}} + width={16} + > + <svg + className="styles__icon___23x3R" + height={16} + style={Object {}} + width={16} + > + <use + xlinkHref="#test-file-stub" + /> + </svg> + </Component> + </Icon> + </span> + <WithStyles(memo) + center={true} + > + <ForwardRef(TouchRipple) + center={true} + classes={ + Object { + "child": "MuiTouchRipple-child", + "childLeaving": "MuiTouchRipple-childLeaving", + "childPulsate": "MuiTouchRipple-childPulsate", + "ripple": "MuiTouchRipple-ripple", + "ripplePulsate": "MuiTouchRipple-ripplePulsate", + "rippleVisible": "MuiTouchRipple-rippleVisible", + "root": "MuiTouchRipple-root", + } + } + > + <span + className="MuiTouchRipple-root" + > + <TransitionGroup + childFactory={[Function]} + component={null} + exit={true} + /> + </span> + </ForwardRef(TouchRipple)> + </WithStyles(memo)> + </button> + </ForwardRef(ButtonBase)> + </WithStyles(ForwardRef(ButtonBase))> + </ForwardRef(IconButton)> + </WithStyles(ForwardRef(IconButton))> + <div + className="fb-root" + > + <StyledIcon + icon="test-file-stub" + size={80} + > + <Icon + aria-hidden={true} + icon="test-file-stub" + size={80} + spin={false} + > + <Component + aria-hidden={true} + className="styles__icon___23x3R" + height={80} + style={Object {}} + width={80} + > + <svg + aria-hidden={true} + className="styles__icon___23x3R" + height={80} + style={Object {}} + width={80} + > + <use + xlinkHref="#test-file-stub" + /> + </svg> + </Component> + </Icon> + </StyledIcon> + <p + className="title" + > + feedback.title + </p> + <p + className="text" + > + feedback.text1 + </p> + <p + className="text" + > + feedback.text2 + </p> + <div + className="actions" + > + <WithStyles(ForwardRef(Button)) + aria-label="feedback.later" + classes={ + Object { + "label": "text-16-bold", + "root": "btn-secondary-positive", + } + } + onClick={[Function]} + > + <ForwardRef(Button) + aria-label="feedback.later" + classes={ + Object { + "colorInherit": "MuiButton-colorInherit", + "contained": "MuiButton-contained", + "containedPrimary": "MuiButton-containedPrimary", + "containedSecondary": "MuiButton-containedSecondary", + "containedSizeLarge": "MuiButton-containedSizeLarge", + "containedSizeSmall": "MuiButton-containedSizeSmall", + "disableElevation": "MuiButton-disableElevation", + "disabled": "Mui-disabled", + "endIcon": "MuiButton-endIcon", + "focusVisible": "Mui-focusVisible", + "fullWidth": "MuiButton-fullWidth", + "iconSizeLarge": "MuiButton-iconSizeLarge", + "iconSizeMedium": "MuiButton-iconSizeMedium", + "iconSizeSmall": "MuiButton-iconSizeSmall", + "label": "MuiButton-label text-16-bold", + "outlined": "MuiButton-outlined", + "outlinedPrimary": "MuiButton-outlinedPrimary", + "outlinedSecondary": "MuiButton-outlinedSecondary", + "outlinedSizeLarge": "MuiButton-outlinedSizeLarge", + "outlinedSizeSmall": "MuiButton-outlinedSizeSmall", + "root": "MuiButton-root btn-secondary-positive", + "sizeLarge": "MuiButton-sizeLarge", + "sizeSmall": "MuiButton-sizeSmall", + "startIcon": "MuiButton-startIcon", + "text": "MuiButton-text", + "textPrimary": "MuiButton-textPrimary", + "textSecondary": "MuiButton-textSecondary", + "textSizeLarge": "MuiButton-textSizeLarge", + "textSizeSmall": "MuiButton-textSizeSmall", + } + } + onClick={[Function]} + > + <WithStyles(ForwardRef(ButtonBase)) + aria-label="feedback.later" + className="MuiButton-root btn-secondary-positive MuiButton-text" + component="button" + disabled={false} + focusRipple={true} + focusVisibleClassName="Mui-focusVisible" + onClick={[Function]} + type="button" + > + <ForwardRef(ButtonBase) + aria-label="feedback.later" + className="MuiButton-root btn-secondary-positive MuiButton-text" + classes={ + Object { + "disabled": "Mui-disabled", + "focusVisible": "Mui-focusVisible", + "root": "MuiButtonBase-root", + } + } + component="button" + disabled={false} + focusRipple={true} + focusVisibleClassName="Mui-focusVisible" + onClick={[Function]} + type="button" + > + <button + aria-label="feedback.later" + className="MuiButtonBase-root MuiButton-root btn-secondary-positive MuiButton-text" + disabled={false} + onBlur={[Function]} + onClick={[Function]} + onDragLeave={[Function]} + onFocus={[Function]} + onKeyDown={[Function]} + onKeyUp={[Function]} + onMouseDown={[Function]} + onMouseLeave={[Function]} + onMouseUp={[Function]} + onTouchEnd={[Function]} + onTouchMove={[Function]} + onTouchStart={[Function]} + tabIndex={0} + type="button" + > + <span + className="MuiButton-label text-16-bold" + > + feedback.later + </span> + <WithStyles(memo) + center={false} + > + <ForwardRef(TouchRipple) + center={false} + classes={ + Object { + "child": "MuiTouchRipple-child", + "childLeaving": "MuiTouchRipple-childLeaving", + "childPulsate": "MuiTouchRipple-childPulsate", + "ripple": "MuiTouchRipple-ripple", + "ripplePulsate": "MuiTouchRipple-ripplePulsate", + "rippleVisible": "MuiTouchRipple-rippleVisible", + "root": "MuiTouchRipple-root", + } + } + > + <span + className="MuiTouchRipple-root" + > + <TransitionGroup + childFactory={[Function]} + component={null} + exit={true} + /> + </span> + </ForwardRef(TouchRipple)> + </WithStyles(memo)> + </button> + </ForwardRef(ButtonBase)> + </WithStyles(ForwardRef(ButtonBase))> + </ForwardRef(Button)> + </WithStyles(ForwardRef(Button))> + <WithStyles(ForwardRef(Button)) + aria-label="feedback.lets_go" + classes={ + Object { + "label": "text-16-bold", + "root": "btn-highlight", + } + } + onClick={[Function]} + > + <ForwardRef(Button) + aria-label="feedback.lets_go" + classes={ + Object { + "colorInherit": "MuiButton-colorInherit", + "contained": "MuiButton-contained", + "containedPrimary": "MuiButton-containedPrimary", + "containedSecondary": "MuiButton-containedSecondary", + "containedSizeLarge": "MuiButton-containedSizeLarge", + "containedSizeSmall": "MuiButton-containedSizeSmall", + "disableElevation": "MuiButton-disableElevation", + "disabled": "Mui-disabled", + "endIcon": "MuiButton-endIcon", + "focusVisible": "Mui-focusVisible", + "fullWidth": "MuiButton-fullWidth", + "iconSizeLarge": "MuiButton-iconSizeLarge", + "iconSizeMedium": "MuiButton-iconSizeMedium", + "iconSizeSmall": "MuiButton-iconSizeSmall", + "label": "MuiButton-label text-16-bold", + "outlined": "MuiButton-outlined", + "outlinedPrimary": "MuiButton-outlinedPrimary", + "outlinedSecondary": "MuiButton-outlinedSecondary", + "outlinedSizeLarge": "MuiButton-outlinedSizeLarge", + "outlinedSizeSmall": "MuiButton-outlinedSizeSmall", + "root": "MuiButton-root btn-highlight", + "sizeLarge": "MuiButton-sizeLarge", + "sizeSmall": "MuiButton-sizeSmall", + "startIcon": "MuiButton-startIcon", + "text": "MuiButton-text", + "textPrimary": "MuiButton-textPrimary", + "textSecondary": "MuiButton-textSecondary", + "textSizeLarge": "MuiButton-textSizeLarge", + "textSizeSmall": "MuiButton-textSizeSmall", + } + } + onClick={[Function]} + > + <WithStyles(ForwardRef(ButtonBase)) + aria-label="feedback.lets_go" + className="MuiButton-root btn-highlight MuiButton-text" + component="button" + disabled={false} + focusRipple={true} + focusVisibleClassName="Mui-focusVisible" + onClick={[Function]} + type="button" + > + <ForwardRef(ButtonBase) + aria-label="feedback.lets_go" + className="MuiButton-root btn-highlight MuiButton-text" + classes={ + Object { + "disabled": "Mui-disabled", + "focusVisible": "Mui-focusVisible", + "root": "MuiButtonBase-root", + } + } + component="button" + disabled={false} + focusRipple={true} + focusVisibleClassName="Mui-focusVisible" + onClick={[Function]} + type="button" + > + <button + aria-label="feedback.lets_go" + className="MuiButtonBase-root MuiButton-root btn-highlight MuiButton-text" + disabled={false} + onBlur={[Function]} + onClick={[Function]} + onDragLeave={[Function]} + onFocus={[Function]} + onKeyDown={[Function]} + onKeyUp={[Function]} + onMouseDown={[Function]} + onMouseLeave={[Function]} + onMouseUp={[Function]} + onTouchEnd={[Function]} + onTouchMove={[Function]} + onTouchStart={[Function]} + tabIndex={0} + type="button" + > + <span + className="MuiButton-label text-16-bold" + > + feedback.lets_go + </span> + <WithStyles(memo) + center={false} + > + <ForwardRef(TouchRipple) + center={false} + classes={ + Object { + "child": "MuiTouchRipple-child", + "childLeaving": "MuiTouchRipple-childLeaving", + "childPulsate": "MuiTouchRipple-childPulsate", + "ripple": "MuiTouchRipple-ripple", + "ripplePulsate": "MuiTouchRipple-ripplePulsate", + "rippleVisible": "MuiTouchRipple-rippleVisible", + "root": "MuiTouchRipple-root", + } + } + > + <span + className="MuiTouchRipple-root" + > + <TransitionGroup + childFactory={[Function]} + component={null} + exit={true} + /> + </span> + </ForwardRef(TouchRipple)> + </WithStyles(memo)> + </button> + </ForwardRef(ButtonBase)> + </WithStyles(ForwardRef(ButtonBase))> + </ForwardRef(Button)> + </WithStyles(ForwardRef(Button))> + </div> + </div> + </div> + </ForwardRef(Paper)> + </WithStyles(ForwardRef(Paper))> + </div> + </Transition> + </ForwardRef(Fade)> + <div + data-test="sentinelEnd" + tabIndex={0} + /> + </Unstable_TrapFocus> + </div> + </Portal> + </ForwardRef(Portal)> + </ForwardRef(Modal)> + </ForwardRef(Dialog)> + </WithStyles(ForwardRef(Dialog))> + </FeedbackModal> </Provider> `; diff --git a/src/components/FluidChart/FluidChart.tsx b/src/components/FluidChart/FluidChart.tsx index 158f05147fa75b80d0ee524d3fa1d24be833e13a..537ee6ee30ab6482e148e41fda8c36023f474fca 100644 --- a/src/components/FluidChart/FluidChart.tsx +++ b/src/components/FluidChart/FluidChart.tsx @@ -1,32 +1,28 @@ -import { Button } from '@material-ui/core' +import { Button, Slide } from '@material-ui/core' import LegendComparisonIcon from 'assets/icons/ico/legendComparison.svg' import StyledIcon from 'components/CommonKit/Icon/StyledIcon' import StyledSwitch from 'components/CommonKit/Switch/StyledSwitch' -import HalfHourNoData from 'components/HalfHourNoData/HalfHourNoData' import useExploration from 'components/Hooks/useExploration' -import TimeStepSelector from 'components/TimeStepSelector/TimeStepSelector' import { useClient } from 'cozy-client' import { useI18n } from 'cozy-ui/transpiled/react/I18n' -import { FluidType } from 'enum/fluid.enum' -import { TimeStep } from 'enum/timeStep.enum' -import { UsageEventType } from 'enum/usageEvent.enum' -import { UserExplorationID } from 'enum/userExploration.enum' -import React, { Dispatch, useCallback, useEffect, useState } from 'react' -import { useDispatch, useSelector } from 'react-redux' +import { FluidType, TimeStep, UsageEventType, UserExplorationID } from 'enums' +import React, { useCallback, useEffect, useState } from 'react' import { useNavigate } from 'react-router-dom' import ConsumptionService from 'services/consumption.service' import DateChartService from 'services/dateChart.service' import UsageEventService from 'services/usageEvent.service' -import { AppActionsTypes, AppStore } from 'store' import { setCurrentIndex, setSelectedDate, setShowCompare, setShowOfflineData, } from 'store/chart/chart.slice' +import { useAppDispatch, useAppSelector } from 'store/hooks' import { openConnectionModal } from 'store/modal/modal.slice' import { getFluidName, getKonnectorSlug, isKonnectorActive } from 'utils/utils' import FluidChartSwipe from './FluidChartSwipe' +import HalfHourNoData from './HalfHourNoData/HalfHourNoData' +import TimeStepSelector from './TimeStepSelector/TimeStepSelector' import './fluidChart.scss' interface FluidChartProps { @@ -40,8 +36,8 @@ const FluidChart = ({ fluidType, setActive }: FluidChartProps) => { const { chart: { currentTimeStep, selectedDate, showCompare }, global: { fluidStatus }, - } = useSelector((state: AppStore) => state.ecolyo) - const dispatch = useDispatch<Dispatch<AppActionsTypes>>() + } = useAppSelector(state => state.ecolyo) + const dispatch = useAppDispatch() const navigate = useNavigate() const currentFluidStatus = fluidStatus[fluidType] @@ -147,10 +143,10 @@ const FluidChart = ({ fluidType, setActive }: FluidChartProps) => { const LastDataValid = () => ( <div className="lastValidData"> - <span className={`text-16-normal date`} onClick={moveToDate}> - {t('consumption_visualizer.last_valid_data')} - {' : '} - {currentFluidStatus?.lastDataDate?.toFormat('dd/MM/yy') || '-'} + <span className="text-16-bold date" onClick={moveToDate}> + {t('consumption_visualizer.last_valid_data', { + date: currentFluidStatus?.lastDataDate?.toFormat('dd/MM/yy') || '-', + })} </span> <p>{t('auth.warningOfflineData')}</p> <Button @@ -176,7 +172,9 @@ const FluidChart = ({ fluidType, setActive }: FluidChartProps) => { <FluidChartSwipe fluidType={fluidType} setActive={setActive} /> </div> {showCompare && currentTimeStep !== TimeStep.YEAR && ( - <DisplayLegend /> + <Slide direction="right" in={showCompare}> + {DisplayLegend()} + </Slide> )} </> )} diff --git a/src/components/FluidChart/FluidChartSlide.tsx b/src/components/FluidChart/FluidChartSlide.tsx index 3218478982d6992111d99ad95b292aa6ccfb8634..5be0634977f3cfdcd80bd50e2d7f6c64ed82559a 100644 --- a/src/components/FluidChart/FluidChartSlide.tsx +++ b/src/components/FluidChart/FluidChartSlide.tsx @@ -2,16 +2,14 @@ import BarChart from 'components/Charts/BarChart' import ConsumptionVisualizer from 'components/ConsumptionVisualizer/ConsumptionVisualizer' import Loader from 'components/Loader/Loader' import { useClient } from 'cozy-client' -import { FluidType } from 'enum/fluid.enum' -import { TimeStep } from 'enum/timeStep.enum' +import { FluidType, TimeStep } from 'enums' import { DateTime } from 'luxon' import { Datachart } from 'models' -import React, { Dispatch, useEffect, useState } from 'react' -import { useDispatch, useSelector } from 'react-redux' +import React, { useEffect, useState } from 'react' import ConsumptionService from 'services/consumption.service' import DateChartService from 'services/dateChart.service' -import { AppActionsTypes, AppStore } from 'store' import { setCurrentDataChart, setLoading } from 'store/chart/chart.slice' +import { useAppDispatch, useAppSelector } from 'store/hooks' import './fluidChartSlide.scss' interface FluidChartSlideProps { @@ -32,11 +30,11 @@ const FluidChartSlide = ({ setActive, }: FluidChartSlideProps) => { const client = useClient() - const dispatch = useDispatch<Dispatch<AppActionsTypes>>() + const dispatch = useAppDispatch() const { - chart: { currentTimeStep, currentIndex }, + chart: { currentTimeStep, currentIndex, showCompare }, global: { fluidStatus, fluidTypes }, - } = useSelector((state: AppStore) => state.ecolyo) + } = useAppSelector(state => state.ecolyo) const [chartData, setChartData] = useState<Datachart>({ actualData: [], @@ -115,7 +113,7 @@ const FluidChartSlide = ({ }, [dispatch, index, currentIndex, chartData]) return ( - <div className={'fluidchartslide-root'} aria-busy={!isDataLoaded}> + <div className="fluidchartslide-root" aria-busy={!isDataLoaded}> {!isDataLoaded ? ( <div className="data-spinner"> <Loader fluidType={fluidType} /> @@ -127,6 +125,7 @@ const FluidChartSlide = ({ chartData={chartData} fluidType={fluidType} timeStep={timeStep} + showCompare={showCompare} height={height} width={width} isSwitching={isSwitching} diff --git a/src/components/FluidChart/FluidChartSwipe.tsx b/src/components/FluidChart/FluidChartSwipe.tsx index 403d914b9de79fbe1cd75fbc1e6f86951a41d147..68c3ee7b2105658129224995389a0310f3f88fd9 100644 --- a/src/components/FluidChart/FluidChartSwipe.tsx +++ b/src/components/FluidChart/FluidChartSwipe.tsx @@ -1,14 +1,13 @@ import FluidChartSlide from 'components/FluidChart/FluidChartSlide' import { useChartResize } from 'components/Hooks/useChartResize' -import { FluidType } from 'enum/fluid.enum' +import { FluidType } from 'enums' import { DateTime } from 'luxon' -import React, { Dispatch, useEffect, useRef, useState } from 'react' -import { useDispatch, useSelector } from 'react-redux' +import React, { useEffect, useRef, useState } from 'react' import SwipeableViews from 'react-swipeable-views' import { virtualize } from 'react-swipeable-views-utils' import DateChartService from 'services/dateChart.service' -import { AppActionsTypes, AppStore } from 'store' import { setCurrentIndex, setSelectedDate } from 'store/chart/chart.slice' +import { useAppDispatch, useAppSelector } from 'store/hooks' import './fluidChartSwipe.scss' const VirtualizeSwipeableViews = virtualize(SwipeableViews) @@ -19,10 +18,9 @@ interface FluidChartSwipeProps { } const FluidChartSwipe = ({ fluidType, setActive }: FluidChartSwipeProps) => { - const dispatch = useDispatch<Dispatch<AppActionsTypes>>() - const { currentIndex, currentTimeStep, selectedDate, loading } = useSelector( - (state: AppStore) => state.ecolyo.chart - ) + const dispatch = useAppDispatch() + const { currentIndex, currentTimeStep, selectedDate, loading } = + useAppSelector(state => state.ecolyo.chart) const swipe = useRef<HTMLDivElement>(null) const [isSwitching, setIsSwitching] = useState(false) @@ -82,7 +80,7 @@ const FluidChartSwipe = ({ fluidType, setActive }: FluidChartSwipeProps) => { ) return ( - <div className={'fluidchartswipe-root'} ref={swipe}> + <div className="fluidchartswipe-root" ref={swipe}> <VirtualizeSwipeableViews index={currentIndex} overscanSlideAfter={1} diff --git a/src/components/HalfHourNoData/HalfHourNoData.spec.tsx b/src/components/FluidChart/HalfHourNoData/HalfHourNoData.spec.tsx similarity index 64% rename from src/components/HalfHourNoData/HalfHourNoData.spec.tsx rename to src/components/FluidChart/HalfHourNoData/HalfHourNoData.spec.tsx index ff7c1481a9cc6f01dea9d0e5c5a9daf5a186a462..5b817591bf6040deab0540b88f806542e5078fb4 100644 --- a/src/components/HalfHourNoData/HalfHourNoData.spec.tsx +++ b/src/components/FluidChart/HalfHourNoData/HalfHourNoData.spec.tsx @@ -2,16 +2,6 @@ import { mount } from 'enzyme' import React from 'react' import HalfHourNoData from './HalfHourNoData' -jest.mock('cozy-ui/transpiled/react/I18n', () => { - return { - useI18n: jest.fn(() => { - return { - t: (str: string) => str, - } - }), - } -}) - describe('HalfHourNoData component', () => { it('should render correctly HalfHourNoData', () => { const component = mount(<HalfHourNoData />) diff --git a/src/components/HalfHourNoData/HalfHourNoData.tsx b/src/components/FluidChart/HalfHourNoData/HalfHourNoData.tsx similarity index 74% rename from src/components/HalfHourNoData/HalfHourNoData.tsx rename to src/components/FluidChart/HalfHourNoData/HalfHourNoData.tsx index c092103109d91c98ce47d26168de90998a4dd37e..9b88e93c8be5701cc0f803d608d9f5d0fe006258 100644 --- a/src/components/HalfHourNoData/HalfHourNoData.tsx +++ b/src/components/FluidChart/HalfHourNoData/HalfHourNoData.tsx @@ -1,9 +1,9 @@ -import { IuseI18n, useI18n } from 'cozy-ui/transpiled/react/I18n' +import { useI18n } from 'cozy-ui/transpiled/react/I18n' import React from 'react' import './halfHourNoData.scss' const HalfHourNoData = () => { - const { t }: IuseI18n = useI18n() + const { t } = useI18n() return ( <div className="halfHour"> <h2>{t('timestep.half_an_hour.gather_data_title')}</h2> diff --git a/src/components/HalfHourNoData/__snapshots__/HalfHourNoData.spec.tsx.snap b/src/components/FluidChart/HalfHourNoData/__snapshots__/HalfHourNoData.spec.tsx.snap similarity index 100% rename from src/components/HalfHourNoData/__snapshots__/HalfHourNoData.spec.tsx.snap rename to src/components/FluidChart/HalfHourNoData/__snapshots__/HalfHourNoData.spec.tsx.snap diff --git a/src/components/HalfHourNoData/halfHourNoData.scss b/src/components/FluidChart/HalfHourNoData/halfHourNoData.scss similarity index 100% rename from src/components/HalfHourNoData/halfHourNoData.scss rename to src/components/FluidChart/HalfHourNoData/halfHourNoData.scss diff --git a/src/components/TimeStepSelector/TimeStepSelector.spec.tsx b/src/components/FluidChart/TimeStepSelector/TimeStepSelector.spec.tsx similarity index 55% rename from src/components/TimeStepSelector/TimeStepSelector.spec.tsx rename to src/components/FluidChart/TimeStepSelector/TimeStepSelector.spec.tsx index 005f1fd3baf9bec0b51fdf50730ea8102c23d33d..25c2672cc2540a55bcbb7044a777cb6cf651487e 100644 --- a/src/components/TimeStepSelector/TimeStepSelector.spec.tsx +++ b/src/components/FluidChart/TimeStepSelector/TimeStepSelector.spec.tsx @@ -1,52 +1,37 @@ import { Button } from '@material-ui/core' -import TimeStepSelector from 'components/TimeStepSelector/TimeStepSelector' -import { FluidType } from 'enum/fluid.enum' -import { TimeStep } from 'enum/timeStep.enum' +import TimeStepSelector from 'components/FluidChart/TimeStepSelector/TimeStepSelector' +import { FluidType, TimeStep } from 'enums' import { mount } from 'enzyme' import toJson from 'enzyme-to-json' import { DateTime } from 'luxon' import React from 'react' -import * as reactRedux from 'react-redux' import { Provider } from 'react-redux' import UsageEventService from 'services/usageEvent.service' import * as chartActions from 'store/chart/chart.slice' -import { createMockEcolyoStore } from '../../../tests/__mocks__/store' -import { waitForComponentToPaint } from '../../../tests/__mocks__/testUtils' +import { createMockEcolyoStore } from 'tests/__mocks__/store' +import { waitForComponentToPaint } from 'tests/__mocks__/testUtils' -jest.mock('cozy-ui/transpiled/react/I18n', () => { - return { - useI18n: jest.fn(() => { - return { - t: (str: string) => str, - } - }), - } -}) jest.mock('services/usageEvent.service') const mockAddEvent = jest.fn() UsageEventService.addEvent = mockAddEvent -const useSelectorSpy = jest.spyOn(reactRedux, 'useSelector') -const useDispatchSpy = jest.spyOn(reactRedux, 'useDispatch') const setCurrentTimeStepSpy = jest.spyOn(chartActions, 'setCurrentTimeStep') const setCurrentIndexSpy = jest.spyOn(chartActions, 'setCurrentIndex') const setSelectedDateSpy = jest.spyOn(chartActions, 'setSelectedDate') describe('TimeStepSelector component', () => { - const store = createMockEcolyoStore() beforeEach(() => { - store.clearActions() - useSelectorSpy.mockClear() - useDispatchSpy.mockClear() setCurrentTimeStepSpy.mockClear() }) it('should render component properly with 4 timesteps', async () => { - useSelectorSpy.mockReturnValue({ - currentTimeStep: TimeStep.DAY, - selectedDate: DateTime.local().setZone('utc', { - keepLocalTime: true, - }), + const store = createMockEcolyoStore({ + chart: { + currentTimeStep: TimeStep.DAY, + selectedDate: DateTime.local().setZone('utc', { + keepLocalTime: true, + }), + }, }) const wrapper = mount( <Provider store={store}> @@ -60,11 +45,13 @@ describe('TimeStepSelector component', () => { }) it('should render component properly with 5 timesteps', () => { - useSelectorSpy.mockReturnValue({ - currentTimeStep: TimeStep.DAY, - selectedDate: DateTime.local().setZone('utc', { - keepLocalTime: true, - }), + const store = createMockEcolyoStore({ + chart: { + currentTimeStep: TimeStep.DAY, + selectedDate: DateTime.local().setZone('utc', { + keepLocalTime: true, + }), + }, }) const wrapper = mount( <Provider store={store}> @@ -76,11 +63,13 @@ describe('TimeStepSelector component', () => { }) it('should define next TimeStep and dispatch it', () => { - useSelectorSpy.mockReturnValue({ - currentTimeStep: TimeStep.YEAR, - selectedDate: DateTime.local().setZone('utc', { - keepLocalTime: true, - }), + const store = createMockEcolyoStore({ + chart: { + currentTimeStep: TimeStep.YEAR, + selectedDate: DateTime.local().setZone('utc', { + keepLocalTime: true, + }), + }, }) const wrapper = mount( <Provider store={store}> @@ -88,16 +77,18 @@ describe('TimeStepSelector component', () => { </Provider> ) wrapper.find('#day').first().simulate('click') - expect(setCurrentTimeStepSpy).toBeCalledTimes(1) + expect(setCurrentTimeStepSpy).toHaveBeenCalledTimes(1) expect(setCurrentTimeStepSpy).toHaveBeenCalledWith(TimeStep.DAY) - expect(setCurrentIndexSpy).toBeCalledTimes(1) + expect(setCurrentIndexSpy).toHaveBeenCalledTimes(1) }) it('should go to todays day with timestep week', () => { - useSelectorSpy.mockReturnValue({ - currentTimeStep: TimeStep.YEAR, - selectedDate: DateTime.local().setZone('utc', { - keepLocalTime: true, - }), + const store = createMockEcolyoStore({ + chart: { + currentTimeStep: TimeStep.YEAR, + selectedDate: DateTime.local().setZone('utc', { + keepLocalTime: true, + }), + }, }) const wrapper = mount( <Provider store={store}> @@ -105,9 +96,9 @@ describe('TimeStepSelector component', () => { </Provider> ) wrapper.find(Button).first().simulate('click') - expect(setCurrentTimeStepSpy).toBeCalledTimes(1) + expect(setCurrentTimeStepSpy).toHaveBeenCalledTimes(1) expect(setCurrentTimeStepSpy).toHaveBeenCalledWith(TimeStep.WEEK) - expect(setCurrentIndexSpy).toBeCalledTimes(2) - expect(setSelectedDateSpy).toBeCalledTimes(1) + expect(setCurrentIndexSpy).toHaveBeenCalledTimes(2) + expect(setSelectedDateSpy).toHaveBeenCalledTimes(1) }) }) diff --git a/src/components/TimeStepSelector/TimeStepSelector.tsx b/src/components/FluidChart/TimeStepSelector/TimeStepSelector.tsx similarity index 80% rename from src/components/TimeStepSelector/TimeStepSelector.tsx rename to src/components/FluidChart/TimeStepSelector/TimeStepSelector.tsx index 6a72bc1eb2f2c1ff068bec5e62eff491c1d50151..d57884a7020e4f3c0be391462ab45de4bf924659 100644 --- a/src/components/TimeStepSelector/TimeStepSelector.tsx +++ b/src/components/FluidChart/TimeStepSelector/TimeStepSelector.tsx @@ -1,29 +1,26 @@ import { Button } from '@material-ui/core' import { useClient } from 'cozy-client' import { useI18n } from 'cozy-ui/transpiled/react/I18n' -import { FluidType } from 'enum/fluid.enum' -import { TimeStep } from 'enum/timeStep.enum' -import { UsageEventType } from 'enum/usageEvent.enum' +import { FluidType, TimeStep, UsageEventType } from 'enums' import { DateTime } from 'luxon' -import React, { Dispatch } from 'react' -import { useDispatch, useSelector } from 'react-redux' +import React from 'react' import DateChartService from 'services/dateChart.service' import UsageEventService from 'services/usageEvent.service' -import { AppActionsTypes, AppStore } from 'store' import { setCurrentIndex, setCurrentTimeStep, setSelectedDate, } from 'store/chart/chart.slice' +import { useAppDispatch, useAppSelector } from 'store/hooks' import { getFluidName } from 'utils/utils' import './timeStepSelector.scss' const TimeStepSelector = ({ fluidType }: { fluidType: FluidType }) => { - const { currentTimeStep, selectedDate } = useSelector( - (state: AppStore) => state.ecolyo.chart - ) const { t } = useI18n() - const dispatch = useDispatch<Dispatch<AppActionsTypes>>() + const dispatch = useAppDispatch() + const { currentTimeStep, selectedDate } = useAppSelector( + state => state.ecolyo.chart + ) const dateChartService = new DateChartService() const client = useClient() const timeStepElecArray: TimeStep[] = [ @@ -73,7 +70,7 @@ const TimeStepSelector = ({ fluidType }: { fluidType: FluidType }) => { dispatch(setCurrentIndex(index)) } return ( - <div className={'timestep-selector'}> + <div className="timestep-selector"> <Button onClick={handleToday} classes={{ @@ -83,7 +80,7 @@ const TimeStepSelector = ({ fluidType }: { fluidType: FluidType }) => { > {t('timestep.today')} </Button> - <div className={'timestep-container'}> + <div className="timestep-container"> <ul className={`timestep-bar ${ fluidType === FluidType.ELECTRICITY && 'elec-bar' @@ -99,7 +96,7 @@ const TimeStepSelector = ({ fluidType }: { fluidType: FluidType }) => { id={TimeStep[step].toLowerCase()} > <span className="clickable-area" /> - <span className={'text text-14-normal'}> + <span className="text text-14-normal"> {t(`timestep.${TimeStep[step].toLowerCase()}.period`)} </span> </li> diff --git a/src/components/TimeStepSelector/__snapshots__/TimeStepSelector.spec.tsx.snap b/src/components/FluidChart/TimeStepSelector/__snapshots__/TimeStepSelector.spec.tsx.snap similarity index 100% rename from src/components/TimeStepSelector/__snapshots__/TimeStepSelector.spec.tsx.snap rename to src/components/FluidChart/TimeStepSelector/__snapshots__/TimeStepSelector.spec.tsx.snap diff --git a/src/components/TimeStepSelector/timeStepSelector.scss b/src/components/FluidChart/TimeStepSelector/timeStepSelector.scss similarity index 94% rename from src/components/TimeStepSelector/timeStepSelector.scss rename to src/components/FluidChart/TimeStepSelector/timeStepSelector.scss index f5bba5f0717ea98fcde74da3a81a0410e90d3c46..b041802de637920000fea84f9275c41134e18341 100644 --- a/src/components/TimeStepSelector/timeStepSelector.scss +++ b/src/components/FluidChart/TimeStepSelector/timeStepSelector.scss @@ -1,6 +1,6 @@ -@import '../../styles/base/color'; -@import '../../styles/base/breakpoint'; -@import '../../styles/base/mixins'; +@import 'src/styles/base/color'; +@import 'src/styles/base/breakpoint'; +@import 'src/styles/base/mixins'; .timestep-selector { display: flex; diff --git a/src/components/FluidChart/fluidChart.scss b/src/components/FluidChart/fluidChart.scss index bc1536b6cace470356a4edaae9cee782947a1c62..138f86bbf547ef2b0a749e7904e67bda31de4694 100644 --- a/src/components/FluidChart/fluidChart.scss +++ b/src/components/FluidChart/fluidChart.scss @@ -26,7 +26,7 @@ } } .compareLegend { - padding: 0.5rem 0 1rem 0; + padding: 0 0 1rem 0; display: flex; gap: 1rem; font-weight: 700; diff --git a/src/components/FormGlobal/FormNavigation.spec.tsx b/src/components/FormGlobal/FormNavigation.spec.tsx deleted file mode 100644 index d620db074e9130ad3e8b184669fd3ec36560e011..0000000000000000000000000000000000000000 --- a/src/components/FormGlobal/FormNavigation.spec.tsx +++ /dev/null @@ -1,51 +0,0 @@ -import Button from '@material-ui/core/Button' -import { ProfileTypeStepForm } from 'enum/profileType.enum' -import { mount } from 'enzyme' -import React from 'react' -import { Provider } from 'react-redux' -import { createMockEcolyoStore } from '../../../tests/__mocks__/store' -import FormNavigation from './FormNavigation' - -jest.mock('cozy-ui/transpiled/react/I18n', () => { - return { - useI18n: jest.fn(() => { - return { - t: (str: string) => str, - } - }), - } -}) - -const mockedNavigate = jest.fn() -jest.mock('react-router-dom', () => ({ - ...jest.requireActual('react-router-dom'), - useNavigate: () => mockedNavigate, -})) - -describe('FormNavigation component', () => { - const store = createMockEcolyoStore() - beforeEach(() => { - store.clearActions() - }) - - it('should be rendered correctly', () => { - const mockhandlePrevious = jest.fn() - const mockhandleNext = jest.fn() - const wrapper = mount( - <Provider store={store}> - <FormNavigation - step={ProfileTypeStepForm.COOKING_FLUID} - handlePrevious={mockhandlePrevious} - handleNext={mockhandleNext} - disableNextButton={false} - /> - </Provider> - ) - wrapper.find(Button).at(0).simulate('click') - wrapper.find(Button).at(1).simulate('click') - expect(wrapper.find('profile-navigation')).toBeTruthy() - expect(wrapper.find(Button)).toBeTruthy() - expect(mockhandlePrevious.mock.calls.length).toEqual(1) - expect(mockhandleNext.mock.calls.length).toEqual(1) - }) -}) diff --git a/src/components/Header/CozyBar.spec.tsx b/src/components/Header/CozyBar.spec.tsx index ab4141b207c6db69ee6bb5faa4d3d95e7ea2ff99..274a14b02a7b75dd088148174d95780760d286bd 100644 --- a/src/components/Header/CozyBar.spec.tsx +++ b/src/components/Header/CozyBar.spec.tsx @@ -1,12 +1,11 @@ import CozyBar from 'components/Header/CozyBar' -import { ScreenType } from 'enum/screen.enum' +import { ScreenType } from 'enums' import { mount } from 'enzyme' import toJson from 'enzyme-to-json' import React from 'react' import { Provider } from 'react-redux' -import configureStore from 'redux-mock-store' import * as ModalAction from 'store/modal/modal.slice' -import { globalStateData } from '../../../tests/__mocks__/globalStateData.mock' +import { createMockEcolyoStore } from 'tests/__mocks__/store' interface BarProps { children: React.ReactNode @@ -20,30 +19,14 @@ jest.mock('utils/cozyBar', () => { } }) -jest.mock('cozy-ui/transpiled/react/I18n', () => { - return { - useI18n: jest.fn(() => { - return { - t: (str: string) => str, - } - }), - } -}) - const mockedNavigate = jest.fn() jest.mock('react-router-dom', () => ({ ...jest.requireActual('react-router-dom'), useNavigate: () => mockedNavigate, })) -const mockStore = configureStore([]) - describe('CozyBar component', () => { - const store = mockStore({ - ecolyo: { - global: globalStateData, - }, - }) + const store = createMockEcolyoStore() it('should be rendered correctly without without left arrow', () => { const wrapper = mount( <Provider store={store}> @@ -92,10 +75,8 @@ describe('CozyBar component', () => { }) it('should not be rendered with screen type different from mobile', () => { - const store = mockStore({ - ecolyo: { - global: { ...globalStateData, screenType: ScreenType.DESKTOP }, - }, + const store = createMockEcolyoStore({ + global: { screenType: ScreenType.DESKTOP }, }) const wrapper = mount( <Provider store={store}> diff --git a/src/components/Header/CozyBar.tsx b/src/components/Header/CozyBar.tsx index 0c0ca007800e0706f7ab72ee5cfa920daa857694..d0cccb6005d43438fc1fc1541e68236440318cb5 100644 --- a/src/components/Header/CozyBar.tsx +++ b/src/components/Header/CozyBar.tsx @@ -2,11 +2,10 @@ import BackArrowIcon from 'assets/icons/ico/back-arrow.svg' import FeedbackIcon from 'assets/icons/ico/feedback.svg' import StyledIconButton from 'components/CommonKit/IconButton/StyledIconButton' import { useI18n } from 'cozy-ui/transpiled/react/I18n' -import { ScreenType } from 'enum/screen.enum' -import React, { Dispatch, useCallback } from 'react' -import { useDispatch, useSelector } from 'react-redux' +import { ScreenType } from 'enums' +import React, { useCallback } from 'react' import { useNavigate } from 'react-router-dom' -import { AppActionsTypes, AppStore } from 'store' +import { useAppDispatch, useAppSelector } from 'store/hooks' import { openFeedbackModal } from 'store/modal/modal.slice' import cozyBar from 'utils/cozyBar' @@ -24,9 +23,9 @@ const CozyBar = ({ }: CozyBarProps) => { const { t } = useI18n() const navigate = useNavigate() - const dispatch = useDispatch<Dispatch<AppActionsTypes>>() const { BarLeft, BarCenter, BarRight } = cozyBar - const { screenType } = useSelector((state: AppStore) => state.ecolyo.global) + const dispatch = useAppDispatch() + const { screenType } = useAppSelector(state => state.ecolyo.global) const handleClickBack = useCallback(() => { if (backFunction) { diff --git a/src/components/Header/Header.spec.tsx b/src/components/Header/Header.spec.tsx index d7f0f27c3d10b2c58c263a479ec0dd7f963ac682..939b20f152bcd3ed27a467a879807c668428796e 100644 --- a/src/components/Header/Header.spec.tsx +++ b/src/components/Header/Header.spec.tsx @@ -1,22 +1,10 @@ import IconButton from '@material-ui/core/IconButton' import Header from 'components/Header/Header' -import { ScreenType } from 'enum/screen.enum' import { mount } from 'enzyme' import React from 'react' import { Provider } from 'react-redux' -import configureStore from 'redux-mock-store' import * as ModalAction from 'store/modal/modal.slice' -import { globalStateData } from '../../../tests/__mocks__/globalStateData.mock' - -jest.mock('cozy-ui/transpiled/react/I18n', () => { - return { - useI18n: jest.fn(() => { - return { - t: (str: string) => str, - } - }), - } -}) +import { createMockEcolyoStore } from 'tests/__mocks__/store' const mockedNavigate = jest.fn() jest.mock('react-router-dom', () => ({ @@ -25,15 +13,10 @@ jest.mock('react-router-dom', () => ({ })) const mockSetHeaderHeight = jest.fn() -const mockStore = configureStore([]) describe('Header component', () => { + const store = createMockEcolyoStore() it('should be rendered correctly', () => { - const store = mockStore({ - ecolyo: { - global: globalStateData, - }, - }) const wrapper = mount( <Provider store={store}> <Header @@ -46,15 +29,10 @@ describe('Header component', () => { }) it('should display title and back button when desktopTitle key provided and displayBackArrow is true', () => { - const store = mockStore({ - ecolyo: { - global: globalStateData, - }, - }) const wrapper = mount( <Provider store={store}> <Header - desktopTitleKey={'KEY'} + desktopTitleKey="KEY" displayBackArrow={true} setHeaderHeight={mockSetHeaderHeight} /> @@ -67,15 +45,10 @@ describe('Header component', () => { }) it('should call handleClickBack when back button is clicked', () => { - const store = mockStore({ - ecolyo: { - global: { ...globalStateData, screenType: ScreenType.DESKTOP }, - }, - }) const wrapper = mount( <Provider store={store}> <Header - desktopTitleKey={'KEY'} + desktopTitleKey="KEY" displayBackArrow={true} setHeaderHeight={mockSetHeaderHeight} /> @@ -90,14 +63,6 @@ describe('Header component', () => { }) it('should call handleClickFeedbacks when feedback button is clicked', () => { - const store = mockStore({ - ecolyo: { - global: globalStateData, - modal: { - isFeedbacksOpen: false, - }, - }, - }) const wrapper = mount( <Provider store={store}> <Header diff --git a/src/components/Header/Header.tsx b/src/components/Header/Header.tsx index 428868001f84e7c0efb8d60e5c46008e4e4c73b8..db54fd2971edb157b4fc87cfa9f831477a09ef20 100644 --- a/src/components/Header/Header.tsx +++ b/src/components/Header/Header.tsx @@ -3,11 +3,10 @@ import BackArrowIcon from 'assets/icons/ico/back-arrow.svg' import FeedbackIcon from 'assets/icons/ico/feedback.svg' import { useI18n } from 'cozy-ui/transpiled/react/I18n' import Icon from 'cozy-ui/transpiled/react/Icon' -import { ScreenType } from 'enum/screen.enum' -import React, { Dispatch, useCallback, useEffect, useRef } from 'react' -import { useDispatch, useSelector } from 'react-redux' +import { ScreenType } from 'enums' +import React, { useCallback, useEffect, useRef } from 'react' import { useNavigate } from 'react-router-dom' -import { AppActionsTypes, AppStore } from 'store' +import { useAppDispatch, useAppSelector } from 'store/hooks' import { openFeedbackModal } from 'store/modal/modal.slice' import './header.scss' @@ -32,9 +31,8 @@ const Header = ({ const { t } = useI18n() const navigate = useNavigate() const header = useRef<HTMLDivElement>(null) - const dispatch = useDispatch<Dispatch<AppActionsTypes>>() - const { screenType } = useSelector((state: AppStore) => state.ecolyo.global) - + const dispatch = useAppDispatch() + const { screenType } = useAppSelector(state => state.ecolyo.global) const cozyBarHeight = 48 const handleClickBack = useCallback(() => { diff --git a/src/components/Home/ConsumptionDetails.spec.tsx b/src/components/Home/ConsumptionDetails.spec.tsx deleted file mode 100644 index 6bb3fe42dff707eda976b5354c4f257c947f673a..0000000000000000000000000000000000000000 --- a/src/components/Home/ConsumptionDetails.spec.tsx +++ /dev/null @@ -1,109 +0,0 @@ -import { FluidType } from 'enum/fluid.enum' -import { TimeStep } from 'enum/timeStep.enum' -import { mount } from 'enzyme' -import toJson from 'enzyme-to-json' -import React from 'react' -import * as reactRedux from 'react-redux' -import { Provider } from 'react-redux' -import { BrowserRouter } from 'react-router-dom' -import { - createMockEcolyoStore, - mockInitialChartState, - mockInitialGlobalState, -} from '../../../tests/__mocks__/store' -import { waitForComponentToPaint } from '../../../tests/__mocks__/testUtils' -import ConsumptionDetails from './ConsumptionDetails' - -jest.mock('cozy-ui/transpiled/react/I18n', () => { - return { - useI18n: jest.fn(() => { - return { - t: (str: string) => str, - } - }), - } -}) - -const mockUseSelector = jest.spyOn(reactRedux, 'useSelector') - -describe('ConsumptionDetails component', () => { - const store = createMockEcolyoStore() - beforeEach(() => { - store.clearActions() - mockUseSelector.mockClear() - }) - it('should be rendered correctly', async () => { - mockUseSelector.mockReturnValue({ - fluidStatus: mockInitialGlobalState.fluidStatus, - fluidTypes: [FluidType.ELECTRICITY], - selectedDate: mockInitialChartState.selectedDate, - currentTimeStep: TimeStep.WEEK, - currentIndex: mockInitialChartState.currentIndex, - currentDatachart: mockInitialChartState.currentDatachart, - }) - const wrapper = mount( - <Provider store={store}> - <BrowserRouter> - <ConsumptionDetails fluidType={FluidType.ELECTRICITY} /> - </BrowserRouter> - </Provider> - ) - await waitForComponentToPaint(wrapper) - expect(toJson(wrapper)).toMatchSnapshot() - }) - - it('should not render connection card ', () => { - mockUseSelector.mockReturnValue({ - fluidStatus: mockInitialGlobalState.fluidStatus, - fluidTypes: [FluidType.ELECTRICITY, FluidType.GAS, FluidType.WATER], - selectedDate: mockInitialChartState.selectedDate, - currentTimeStep: TimeStep.WEEK, - currentIndex: mockInitialChartState.currentIndex, - currentDatachart: mockInitialChartState.currentDatachart, - }) - const wrapper = mount( - <Provider store={store}> - <BrowserRouter> - <ConsumptionDetails fluidType={FluidType.MULTIFLUID} /> - </BrowserRouter> - </Provider> - ) - expect(wrapper.contains('.fluidcard-link')).toBeFalsy() - }) - it('should render one connection card ', () => { - mockUseSelector.mockReturnValue({ - fluidStatus: mockInitialGlobalState.fluidStatus, - fluidTypes: [FluidType.ELECTRICITY, FluidType.GAS], - selectedDate: mockInitialChartState.selectedDate, - currentTimeStep: TimeStep.WEEK, - currentIndex: mockInitialChartState.currentIndex, - currentDatachart: mockInitialChartState.currentDatachart, - }) - const wrapper = mount( - <Provider store={store}> - <BrowserRouter> - <ConsumptionDetails fluidType={FluidType.MULTIFLUID} /> - </BrowserRouter> - </Provider> - ) - expect(wrapper.find('.fluidcard-link')).toBeTruthy() - }) - it('should not render connection card and show multifluid link', () => { - mockUseSelector.mockReturnValue({ - fluidStatus: mockInitialGlobalState.fluidStatus, - fluidTypes: [FluidType.ELECTRICITY, FluidType.GAS], - selectedDate: mockInitialChartState.selectedDate, - currentTimeStep: TimeStep.WEEK, - currentIndex: mockInitialChartState.currentIndex, - currentDatachart: mockInitialChartState.currentDatachart, - }) - const wrapper = mount( - <Provider store={store}> - <BrowserRouter> - <ConsumptionDetails fluidType={FluidType.ELECTRICITY} /> - </BrowserRouter> - </Provider> - ) - expect(wrapper.find('.multi-link')).toBeTruthy() - }) -}) diff --git a/src/components/Home/FluidButtons.spec.tsx b/src/components/Home/FluidButtons.spec.tsx deleted file mode 100644 index 08e569ac59e4178e5fac2974993d89990544a194..0000000000000000000000000000000000000000 --- a/src/components/Home/FluidButtons.spec.tsx +++ /dev/null @@ -1,40 +0,0 @@ -import { FluidType } from 'enum/fluid.enum' -import { mount } from 'enzyme' -import toJson from 'enzyme-to-json' -import React from 'react' -import { Provider } from 'react-redux' -import { createMockEcolyoStore } from '../../../tests/__mocks__/store' -import { waitForComponentToPaint } from '../../../tests/__mocks__/testUtils' -import FluidButtons from './FluidButtons' - -jest.mock('cozy-ui/transpiled/react/I18n', () => { - return { - useI18n: jest.fn(() => { - return { - t: (str: string) => str, - } - }), - } -}) -const mockedNavigate = jest.fn() -jest.mock('react-router-dom', () => ({ - ...jest.requireActual('react-router-dom'), - useNavigate: () => mockedNavigate, -})) - -describe('FluidButtons component', () => { - const store = createMockEcolyoStore() - beforeEach(() => { - store.clearActions() - }) - - it('should be rendered correctly', async () => { - const wrapper = mount( - <Provider store={store}> - <FluidButtons activeFluid={FluidType.ELECTRICITY} /> - </Provider> - ) - await waitForComponentToPaint(wrapper) - expect(toJson(wrapper)).toMatchSnapshot() - }) -}) diff --git a/src/components/Home/__snapshots__/ConsumptionDetails.spec.tsx.snap b/src/components/Home/__snapshots__/ConsumptionDetails.spec.tsx.snap deleted file mode 100644 index 6dd5c4b177614d50aab12ba4c37a821a090073f1..0000000000000000000000000000000000000000 --- a/src/components/Home/__snapshots__/ConsumptionDetails.spec.tsx.snap +++ /dev/null @@ -1,118 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`ConsumptionDetails component should be rendered correctly 1`] = ` -<Provider - store={ - Object { - "clearActions": [Function], - "dispatch": [Function], - "getActions": [Function], - "getState": [Function], - "replaceReducer": [Function], - "subscribe": [Function], - } - } -> - <BrowserRouter> - <Router - location={ - Object { - "hash": "", - "key": "default", - "pathname": "/", - "search": "", - "state": null, - } - } - navigationType="POP" - navigator={ - Object { - "action": "POP", - "createHref": [Function], - "encodeLocation": [Function], - "go": [Function], - "listen": [Function], - "location": Object { - "hash": "", - "key": "default", - "pathname": "/", - "search": "", - "state": null, - }, - "push": [Function], - "replace": [Function], - } - } - > - <ConsumptionDetails - fluidType={0} - > - <div - className="consumption-details-root" - > - <div - className="consumption-details-content" - > - <div - className="consumption-details-header text-16-normal-uppercase details-title" - /> - <TotalConsumption - fluidType={0} - > - <div - className="icon-line " - > - <StyledIcon - className="pile-icon" - icon="test-file-stub" - size={36} - > - <Icon - aria-hidden={true} - className="pile-icon" - icon="test-file-stub" - size={36} - spin={false} - > - <Component - aria-hidden={true} - className="pile-icon styles__icon___23x3R" - height={36} - style={Object {}} - width={36} - > - <svg - aria-hidden={true} - className="pile-icon styles__icon___23x3R" - height={36} - style={Object {}} - width={36} - > - <use - xlinkHref="#test-file-stub" - /> - </svg> - </Component> - </Icon> - </StyledIcon> - <div> - <span - className="euro-value" - > - ----- - </span> - <span - className="euro-symbol" - > - € - </span> - </div> - </div> - </TotalConsumption> - </div> - </div> - </ConsumptionDetails> - </Router> - </BrowserRouter> -</Provider> -`; diff --git a/src/components/Hooks/useExploration.spec.tsx b/src/components/Hooks/useExploration.spec.tsx index 8124169d7a6da85771fc34babf4d922a769866bd..4e70b76a814779aaebcdfdcffc5739226cf4d91d 100644 --- a/src/components/Hooks/useExploration.spec.tsx +++ b/src/components/Hooks/useExploration.spec.tsx @@ -1,19 +1,21 @@ import { act, renderHook } from '@testing-library/react-hooks' import useExploration from 'components/Hooks/useExploration' -import { UserExplorationID } from 'enum/userExploration.enum' -import * as reactRedux from 'react-redux' -import { userChallengeExplo1OnGoing } from '../../../tests/__mocks__/userChallengeData.mock' - -const dispatchMock = jest.fn() -const mockUseSelector = jest.spyOn(reactRedux, 'useSelector') -const mockUseDispatch = jest.spyOn(reactRedux, 'useDispatch') +import { UserExplorationID } from 'enums' +import React from 'react' +import { Provider } from 'react-redux' +import { createMockEcolyoStore } from 'tests/__mocks__/store' +import { userChallengeExplo1OnGoing } from 'tests/__mocks__/userChallengeData.mock' describe('useExploration Hooks', () => { it('should return "EXPLORATION001"', () => { - mockUseDispatch.mockReturnValue(dispatchMock) - mockUseSelector.mockReturnValue(userChallengeExplo1OnGoing) + const store = createMockEcolyoStore({ + challenge: { currentChallenge: userChallengeExplo1OnGoing }, + }) - const { result } = renderHook(() => useExploration()) + const wrapper = ({ children }: { children: JSX.Element }) => ( + <Provider store={store}>{children}</Provider> + ) + const { result } = renderHook(() => useExploration(), { wrapper }) act(() => { result.current[1](UserExplorationID.EXPLORATION001) diff --git a/src/components/Hooks/useExploration.tsx b/src/components/Hooks/useExploration.tsx index a42e644f23f0b7807f8badc83361f100124988d2..36e9be442f8063e69ed96c2197606b11e3d87ad4 100644 --- a/src/components/Hooks/useExploration.tsx +++ b/src/components/Hooks/useExploration.tsx @@ -1,19 +1,16 @@ -import { Client, useClient } from 'cozy-client' -import { UserExplorationState } from 'enum/userExploration.enum' -import { ChallengeState, UserExploration } from 'models' +import { useClient } from 'cozy-client' +import { UserExplorationState } from 'enums' +import { UserExploration } from 'models' import { Dispatch, SetStateAction, useEffect, useState } from 'react' -import { useDispatch, useSelector } from 'react-redux' import ExplorationService from 'services/exploration.service' -import { AppActionsTypes, AppStore } from 'store' import { updateUserChallengeList } from 'store/challenge/challenge.slice' -import { toggleChallengeExplorationNotification } from 'store/global/global.actions' +import { toggleChallengeExplorationNotification } from 'store/global/global.slice' +import { useAppDispatch, useAppSelector } from 'store/hooks' const useExploration = (): [string, Dispatch<SetStateAction<string>>] => { - const client: Client = useClient() - const dispatch = useDispatch<Dispatch<AppActionsTypes>>() - const { currentChallenge }: ChallengeState = useSelector( - (state: AppStore) => state.ecolyo.challenge - ) + const client = useClient() + const dispatch = useAppDispatch() + const { currentChallenge } = useAppSelector(state => state.ecolyo.challenge) const exploration: UserExploration | null = currentChallenge ? currentChallenge.exploration : null diff --git a/src/components/Hooks/useKonnectorAuth.tsx b/src/components/Hooks/useKonnectorAuth.tsx index d1d1c0bf9bea1937fdb12a4a0feae1f674b127a3..1750eff2df85a7848c8bfad5ac0dca5bf0be7bd8 100644 --- a/src/components/Hooks/useKonnectorAuth.tsx +++ b/src/components/Hooks/useKonnectorAuth.tsx @@ -1,47 +1,38 @@ import * as Sentry from '@sentry/react' -import { Client, useClient } from 'cozy-client' +import { useClient } from 'cozy-client' import { useI18n } from 'cozy-ui/transpiled/react/I18n' -import { FluidSlugType } from 'enum/fluidSlug.enum' -import { UsageEventType } from 'enum/usageEvent.enum' +import { FluidSlugType, FluidType, UsageEventType } from 'enums' import { AccountAuthData, AccountSgeData, FluidConnection, - FluidStatus, UsageEvent, } from 'models' -import { Dispatch, useCallback, useState } from 'react' -import { useDispatch, useSelector } from 'react-redux' +import { useState } from 'react' import AccountService from 'services/account.service' import ConnectionService from 'services/connection.service' import UsageEventService from 'services/usageEvent.service' -import { AppActionsTypes, AppStore } from 'store' import { setLoading } from 'store/chart/chart.slice' -import { updatedFluidConnection } from 'store/global/global.actions' +import { updateFluidConnection } from 'store/global/global.slice' +import { useAppDispatch, useAppSelector } from 'store/hooks' import logApp from 'utils/logger' const useKonnectorAuth = ( - fluidStatus: FluidStatus, + fluidType: FluidType, login?: string, password?: string ): [() => Promise<null | undefined>, () => Promise<void>, string] => { - const client: Client = useClient() + const client = useClient() const { t } = useI18n() - const dispatch = useDispatch<Dispatch<AppActionsTypes>>() + const dispatch = useAppDispatch() + const { sgeConnect, fluidStatus } = useAppSelector( + state => state.ecolyo.global + ) + const currentFluidStatus = fluidStatus[fluidType] const konnectorSlug: FluidSlugType = - fluidStatus.connection.konnectorConfig.slug - const { sgeConnect } = useSelector((state: AppStore) => state.ecolyo.global) - + currentFluidStatus.connection.konnectorConfig.slug const [connectError, setError] = useState<string>('') - const onSuccess = useCallback(async () => { - const updatedConnection: FluidConnection = { - ...fluidStatus.connection, - shouldLaunchKonnector: true, - } - dispatch(updatedFluidConnection(fluidStatus.fluidType, updatedConnection)) - }, [dispatch, fluidStatus.fluidType, fluidStatus.connection]) - const sendUsageEventError = async (slug: string): Promise<UsageEvent> => { return UsageEventService.addEvent(client, { type: UsageEventType.KONNECTOR_CONNECT_EVENT, @@ -76,24 +67,29 @@ const useKonnectorAuth = ( return null } const updatedConnection: FluidConnection = { - ...fluidStatus.connection, + ...currentFluidStatus.connection, account: _account, trigger: _trigger, + shouldLaunchKonnector: true, } setLoading(false) - dispatch(updatedFluidConnection(fluidStatus.fluidType, updatedConnection)) - onSuccess() + dispatch( + updateFluidConnection({ + fluidType: currentFluidStatus.fluidType, + fluidConnection: updatedConnection, + }) + ) } catch (error) { setLoading(false) sendUsageEventError(konnectorSlug) logApp.error(error) - Sentry.captureException(JSON.stringify({ error })) + Sentry.captureException(error) } } const update = async () => { - if (fluidStatus.connection.account) { - const _account = fluidStatus.connection.account + if (currentFluidStatus.connection.account) { + const _account = currentFluidStatus.connection.account let auth: AccountAuthData | AccountSgeData if (konnectorSlug === FluidSlugType.WATER) { auth = { @@ -114,11 +110,16 @@ const useKonnectorAuth = ( const accountService = new AccountService(client) const updatedAccount = await accountService.updateAccount(_account) const updatedConnection: FluidConnection = { - ...fluidStatus.connection, + ...currentFluidStatus.connection, account: updatedAccount, + shouldLaunchKonnector: true, } - dispatch(updatedFluidConnection(fluidStatus.fluidType, updatedConnection)) - onSuccess() + dispatch( + updateFluidConnection({ + fluidType: currentFluidStatus.fluidType, + fluidConnection: updatedConnection, + }) + ) } } return [connect, update, connectError] diff --git a/src/components/Connection/ConnectionNotFound.spec.tsx b/src/components/Konnector/ConnectionNotFound/ConnectionNotFound.spec.tsx similarity index 74% rename from src/components/Connection/ConnectionNotFound.spec.tsx rename to src/components/Konnector/ConnectionNotFound/ConnectionNotFound.spec.tsx index 1772e89ff42cad50f04e69a7d50bc2b2f3eebe38..b156f88bdaa38b1f97e2ebba58900d9ccf3f8d21 100644 --- a/src/components/Connection/ConnectionNotFound.spec.tsx +++ b/src/components/Konnector/ConnectionNotFound/ConnectionNotFound.spec.tsx @@ -1,17 +1,7 @@ import Button from '@material-ui/core/Button' -import ConnectionNotFound from 'components/Connection/ConnectionNotFound' import { mount, shallow } from 'enzyme' import React from 'react' - -jest.mock('cozy-ui/transpiled/react/I18n', () => { - return { - useI18n: jest.fn(() => { - return { - t: (str: string) => str, - } - }), - } -}) +import ConnectionNotFound from './ConnectionNotFound' describe('ConnectionNotFound component test', () => { const konnectorSlug = 'enedissgegrandlyon' diff --git a/src/components/Connection/ConnectionNotFound.tsx b/src/components/Konnector/ConnectionNotFound/ConnectionNotFound.tsx similarity index 100% rename from src/components/Connection/ConnectionNotFound.tsx rename to src/components/Konnector/ConnectionNotFound/ConnectionNotFound.tsx diff --git a/src/components/Connection/__snapshots__/ConnectionNotFound.spec.tsx.snap b/src/components/Konnector/ConnectionNotFound/__snapshots__/ConnectionNotFound.spec.tsx.snap similarity index 100% rename from src/components/Connection/__snapshots__/ConnectionNotFound.spec.tsx.snap rename to src/components/Konnector/ConnectionNotFound/__snapshots__/ConnectionNotFound.spec.tsx.snap diff --git a/src/components/Connection/connectionNotFound.scss b/src/components/Konnector/ConnectionNotFound/connectionNotFound.scss similarity index 100% rename from src/components/Connection/connectionNotFound.scss rename to src/components/Konnector/ConnectionNotFound/connectionNotFound.scss diff --git a/src/components/Connection/ConnectionResult.tsx b/src/components/Konnector/ConnectionResult/ConnectionResult.tsx similarity index 85% rename from src/components/Connection/ConnectionResult.tsx rename to src/components/Konnector/ConnectionResult/ConnectionResult.tsx index 27263a062697e937d31d5184a94fea4e0d43825d..d94ae43114627d6ea6231cbd247b0ec658594289 100644 --- a/src/components/Connection/ConnectionResult.tsx +++ b/src/components/Konnector/ConnectionResult/ConnectionResult.tsx @@ -1,11 +1,11 @@ import Button from '@material-ui/core/Button' +import warningDark from 'assets/icons/ico/warning-dark.svg' import warningWhite from 'assets/icons/ico/warning-white.svg' import StyledIcon from 'components/CommonKit/Icon/StyledIcon' 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 { FluidType, KonnectorUpdate } from 'enums' import { DateTime } from 'luxon' import { Account, @@ -14,36 +14,35 @@ import { FluidStatus, Trigger, } from 'models' -import React, { Dispatch, useCallback, useEffect, useState } from 'react' -import { useDispatch } from 'react-redux' +import React, { useCallback, useEffect, useState } from 'react' import AccountService from 'services/account.service' import DateChartService from 'services/dateChart.service' import TriggerService from 'services/triggers.service' -import { AppActionsTypes } from 'store' import { setShouldRefreshConsent, + updateFluidConnection, updateSgeStore, - updatedFluidConnection, -} from 'store/global/global.actions' +} from 'store/global/global.slice' +import { useAppDispatch, useAppSelector } from 'store/hooks' import { getKonnectorUpdateError } from 'utils/utils' -import DeleteGRDFAccountModal from './DeleteGRDFAccountModal' +import DeleteGRDFAccountModal from '../../Connection/GRDFDeleteAccountModal/DeleteGRDFAccountModal' import './connectionResult.scss' interface ConnectionResultProps { - fluidStatus: FluidStatus handleAccountDeletion: () => Promise<void> fluidType: FluidType } const ConnectionResult = ({ - fluidStatus, handleAccountDeletion, fluidType, }: ConnectionResultProps) => { const { t } = useI18n() const client = useClient() - const dispatch = useDispatch<Dispatch<AppActionsTypes>>() - const account: Account | null = fluidStatus.connection.account + const dispatch = useAppDispatch() + const { fluidStatus } = useAppSelector(state => state.ecolyo.global) + const currentFluidStatus = fluidStatus[fluidType] + const account: Account | null = currentFluidStatus.connection.account const [deleting, setDeleting] = useState<boolean>(false) const [updating, setUpdating] = useState<boolean>(false) @@ -65,11 +64,16 @@ const ConnectionResult = ({ setLastExecutionDate('-') setKonnectorError('') const updatedConnection: FluidConnection = { - ...fluidStatus.connection, + ...currentFluidStatus.connection, shouldLaunchKonnector: true, isUpdating: true, } - dispatch(updatedFluidConnection(fluidStatus.fluidType, updatedConnection)) + dispatch( + updateFluidConnection({ + fluidType: currentFluidStatus.fluidType, + fluidConnection: updatedConnection, + }) + ) setUpdating(false) } @@ -97,8 +101,11 @@ const ConnectionResult = ({ const isOutdated = useCallback(() => { const dateChartService = new DateChartService() - return dateChartService.isDataOutdated(fluidStatus.lastDataDate, fluidType) - }, [fluidStatus, fluidType]) + return dateChartService.isDataOutdated( + currentFluidStatus.lastDataDate, + currentFluidStatus.fluidType + ) + }, [currentFluidStatus]) const hasUpdatedToday = useCallback(() => { const todayDate = DateTime.local() @@ -119,7 +126,7 @@ const ConnectionResult = ({ const handleRefreshConsent = useCallback( (fluidType: FluidType) => { if (fluidType == FluidType.ELECTRICITY) { - const accountData = fluidStatus.connection.account + const accountData = currentFluidStatus.connection.account ?.auth as AccountSgeData // store the previous account data since the onDelete will remove account from DB dispatch( @@ -141,31 +148,37 @@ const ConnectionResult = ({ deleteAccountsAndTriggers() } }, - [deleteAccountsAndTriggers, dispatch, fluidStatus.connection.account?.auth] + [ + deleteAccountsAndTriggers, + dispatch, + currentFluidStatus.connection.account?.auth, + ] ) useEffect(() => { - if (fluidStatus.connection.triggerState?.last_success) { + if (currentFluidStatus.connection.triggerState?.last_success) { const result = DateTime.fromISO( - fluidStatus.connection.triggerState.last_success + currentFluidStatus.connection.triggerState.last_success ) setLastExecutionDate(result) } else { setLastExecutionDate('-') } if ( - fluidStatus.connection.triggerState?.status === 'errored' && - fluidStatus.connection.triggerState?.last_error + currentFluidStatus.connection.triggerState?.status === 'errored' && + currentFluidStatus.connection.triggerState?.last_error ) { setStatus('errored') setKonnectorError( - getKonnectorUpdateError(fluidStatus.connection.triggerState.last_error) + getKonnectorUpdateError( + currentFluidStatus.connection.triggerState.last_error + ) ) } if (isOutdated()) { setOutDatedDataDays(isOutdated()) } - }, [fluidStatus.connection.triggerState, isOutdated]) + }, [currentFluidStatus.connection.triggerState, isOutdated]) const getFluidTypeTranslation = (fluidType: FluidType) => { switch (fluidType) { @@ -184,14 +197,14 @@ const ConnectionResult = ({ /** * Get Konnector state, possible values: - * * partner maintenance - * * error state - * * outdated - * * last update date + * - partner maintenance + * - error state + * - outdated + * - last update date */ const getConnectionStatus = () => { // First check if there is partner error from backoffice - if (fluidStatus.maintenance) { + if (currentFluidStatus.maintenance) { return ( <div className="connection-caption text-16-normal"> <div className="text-16-normal"> @@ -217,7 +230,7 @@ const ConnectionResult = ({ if (outDatedDataDays) { return ( <DisplayDataOutdated - fluidStatus={fluidStatus} + fluidStatus={currentFluidStatus} fluidType={fluidType} lastExecutionDate={lastExecutionDate} hasUpdatedToday={hasUpdatedToday()} @@ -237,7 +250,9 @@ const ConnectionResult = ({ <div className="connection-update-result"> <div className={ - status === 'errored' && !hasUpdatedToday() && !fluidStatus.maintenance + status === 'errored' && + !hasUpdatedToday() && + !currentFluidStatus.maintenance ? 'connection-update-errored' : '' } @@ -417,9 +432,9 @@ const DisplayAlreadyUpdatedToday = ({ const DisplayManualUpdate = () => { const { t } = useI18n() return ( - <div className="connection-caption-errored connection-update-errored warning-white text-16-normal"> + <div className="connection-caption-warning connection-update-errored warning-white text-16-normal"> <StyledIcon - icon={warningWhite} + icon={warningDark} size={36} className="warning-icon" role="img" diff --git a/src/components/Connection/connectionResult.scss b/src/components/Konnector/ConnectionResult/connectionResult.scss similarity index 62% rename from src/components/Connection/connectionResult.scss rename to src/components/Konnector/ConnectionResult/connectionResult.scss index f508a239956b1128166a2ea10e6913f22186fcef..05a0a13650e640b6295f2b26d81cca837f743ada 100644 --- a/src/components/Connection/connectionResult.scss +++ b/src/components/Konnector/ConnectionResult/connectionResult.scss @@ -27,6 +27,26 @@ margin-right: 1rem; } } + .connection-caption-warning { + background-color: $gold-shadow; + margin: 0 -2.5rem; + padding: 0.4rem 2.5rem; + display: flex; + align-items: center; + color: $dark-2; + @media #{$tablet} { + margin: 0 -1.2rem; + padding: 0.4rem 1.2rem; + } + + .warning-icon { + min-width: 20px; + margin-right: 1rem; + } + .warning-white { + margin-right: 1rem; + } + } .connection-caption { color: $grey-bright; } @@ -42,7 +62,7 @@ gap: 1rem; button.btn-secondary-positive { span:first-child { - color: $red-primary !important; + color: $white !important; } } } diff --git a/src/components/Konnector/KonnectorModal.spec.tsx b/src/components/Konnector/KonnectorModal.spec.tsx index 818ac1a95d4e84d1f6337c22066cc457875e785a..a2ce56da75df6eb2bca2f18a74ef98dc44d5a355 100644 --- a/src/components/Konnector/KonnectorModal.spec.tsx +++ b/src/components/Konnector/KonnectorModal.spec.tsx @@ -1,36 +1,20 @@ import { Button } from '@material-ui/core' -import { FluidType } from 'enum/fluid.enum' -import { KonnectorError } from 'enum/konnectorError.enum' +import { FluidType, KonnectorError } from 'enums' import { mount } from 'enzyme' import toJson from 'enzyme-to-json' import React from 'react' import { Provider } from 'react-redux' -import { createMockEcolyoStore } from '../../../tests/__mocks__/store' -import { waitForComponentToPaint } from '../../../tests/__mocks__/testUtils' +import { createMockEcolyoStore } from 'tests/__mocks__/store' +import { waitForComponentToPaint } from 'tests/__mocks__/testUtils' import KonnectorModal from './KonnectorModal' -jest.mock('cozy-ui/transpiled/react/I18n', () => { - return { - useI18n: jest.fn(() => { - return { - t: (str: string) => str, - } - }), - } -}) -const mockedNavigate = jest.fn() -jest.mock('react-router-dom', () => ({ - ...jest.requireActual('react-router-dom'), - useNavigate: () => mockedNavigate, -})) +const mockHandleCloseClick = jest.fn() describe('KonnectorModal component', () => { const store = createMockEcolyoStore() beforeEach(() => { - store.clearActions() jest.clearAllMocks() }) - const mockHandleCloseClick = jest.fn() it('should be rendered correctly', () => { const wrapper = mount( <Provider store={store}> @@ -73,7 +57,7 @@ describe('KonnectorModal component', () => { <KonnectorModal open={true} isUpdating={false} - state={'errored'} + state="errored" error={null} fluidType={FluidType.ELECTRICITY} handleCloseClick={mockHandleCloseClick} @@ -92,7 +76,7 @@ describe('KonnectorModal component', () => { <KonnectorModal open={true} isUpdating={false} - state={'error'} + state="error" error={KonnectorError.LOGIN_FAILED} fluidType={FluidType.ELECTRICITY} handleCloseClick={mockHandleCloseClick} @@ -110,7 +94,7 @@ describe('KonnectorModal component', () => { <KonnectorModal open={true} isUpdating={false} - state={'error'} + state="error" error={null} fluidType={FluidType.ELECTRICITY} handleCloseClick={mockHandleCloseClick} diff --git a/src/components/Konnector/KonnectorModal.tsx b/src/components/Konnector/KonnectorModal.tsx index f02c94ea6c13400fb9eb708714694d287d0b280f..6039a2c8cc6ef3328c902055e67180d70262192c 100644 --- a/src/components/Konnector/KonnectorModal.tsx +++ b/src/components/Konnector/KonnectorModal.tsx @@ -12,8 +12,7 @@ import { } from 'cozy-harvest-lib/dist/models/flowEvents' import { useI18n } from 'cozy-ui/transpiled/react/I18n' import Icon from 'cozy-ui/transpiled/react/Icon' -import { FluidType } from 'enum/fluid.enum' -import { KonnectorError } from 'enum/konnectorError.enum' +import { FluidType, KonnectorError } from 'enums' import { shuffle } from 'lodash' import { Account } from 'models' import React, { useCallback, useEffect, useMemo, useState } from 'react' @@ -145,13 +144,13 @@ const KonnectorModal = ({ reason !== 'backdropClick' && handleCloseClick(state === SUCCESS_EVENT) }} - aria-labelledby={'accessibility-title'} + aria-labelledby="accessibility-title" classes={{ root: 'modal-root', paper: 'modal-paper', }} > - <div id={'accessibility-title'}> + <div id="accessibility-title"> {t('konnector_modal.accessibility.window_title')} </div> <div className="kmodal-content"> @@ -209,6 +208,7 @@ const KonnectorModal = ({ )} {showCommonErrors && ( <div + className="commonErrorsList" dangerouslySetInnerHTML={{ __html: t( 'konnector_modal.show_common_error_list' diff --git a/src/components/Konnector/KonnectorModalFooter.spec.tsx b/src/components/Konnector/KonnectorModalFooter.spec.tsx index 2502794d98d3dc758f077d25ad401f679f2921bd..9cae908979dd046567044598190bbda60fa0cb97 100644 --- a/src/components/Konnector/KonnectorModalFooter.spec.tsx +++ b/src/components/Konnector/KonnectorModalFooter.spec.tsx @@ -1,25 +1,15 @@ 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 { KonnectorError } from 'enums' import { mount } from 'enzyme' import toJson from 'enzyme-to-json' import React from 'react' import { Provider } from 'react-redux' -import { accountsData } from '../../../tests/__mocks__/accountsData.mock' -import { createMockEcolyoStore } from '../../../tests/__mocks__/store' -import { waitForComponentToPaint } from '../../../tests/__mocks__/testUtils' +import { accountsData } from 'tests/__mocks__/accountsData.mock' +import { createMockEcolyoStore } from 'tests/__mocks__/store' +import { waitForComponentToPaint } from 'tests/__mocks__/testUtils' import KonnectorModalFooter from './KonnectorModalFooter' -jest.mock('cozy-ui/transpiled/react/I18n', () => { - return { - useI18n: jest.fn(() => { - return { - t: (str: string) => str, - } - }), - } -}) const mockedNavigate = jest.fn() jest.mock('react-router-dom', () => ({ ...jest.requireActual('react-router-dom'), @@ -30,10 +20,7 @@ const mockDelete = jest.fn() describe('KonnectorModalFooter component', () => { const store = createMockEcolyoStore() beforeEach(() => { - store.clearActions() - mockDelete.mockClear() - mockClose.mockClear() - mockedNavigate.mockClear() + jest.clearAllMocks() }) it('should be rendered correctly', () => { @@ -42,7 +29,6 @@ describe('KonnectorModalFooter component', () => { <KonnectorModalFooter state={null} error={null} - fluidType={FluidType.ELECTRICITY} handleCloseClick={mockClose} handleAccountDeletion={mockDelete} account={null} @@ -59,7 +45,6 @@ describe('KonnectorModalFooter component', () => { <KonnectorModalFooter state={ERROR_EVENT} error={KonnectorError.USER_ACTION_NEEDED} - fluidType={FluidType.ELECTRICITY} handleCloseClick={mockClose} handleAccountDeletion={mockDelete} account={null} @@ -78,7 +63,6 @@ describe('KonnectorModalFooter component', () => { <KonnectorModalFooter state={ERROR_EVENT} error={KonnectorError.LOGIN_FAILED} - fluidType={FluidType.ELECTRICITY} handleCloseClick={mockClose} handleAccountDeletion={mockDelete} account={null} @@ -95,7 +79,6 @@ describe('KonnectorModalFooter component', () => { <KonnectorModalFooter state={ERROR_EVENT} error={KonnectorError.TERMS_VERSION_MISMATCH} - fluidType={FluidType.ELECTRICITY} handleCloseClick={mockClose} handleAccountDeletion={mockDelete} account={null} @@ -113,7 +96,6 @@ describe('KonnectorModalFooter component', () => { <KonnectorModalFooter state={ERROR_EVENT} error={KonnectorError.LOGIN_FAILED} - fluidType={FluidType.ELECTRICITY} handleCloseClick={mockClose} handleAccountDeletion={mockDelete} account={null} @@ -130,7 +112,6 @@ describe('KonnectorModalFooter component', () => { <KonnectorModalFooter state={ERROR_EVENT} error={KonnectorError.TERMS_VERSION_MISMATCH} - fluidType={FluidType.ELECTRICITY} handleCloseClick={mockClose} handleAccountDeletion={mockDelete} account={accountsData[0]} @@ -149,7 +130,6 @@ describe('KonnectorModalFooter component', () => { <KonnectorModalFooter state={ERROR_EVENT} error={KonnectorError.TERMS_VERSION_MISMATCH} - fluidType={FluidType.ELECTRICITY} handleCloseClick={mockClose} handleAccountDeletion={mockDelete} account={accountsData[0]} @@ -168,7 +148,6 @@ describe('KonnectorModalFooter component', () => { <KonnectorModalFooter state={ERROR_EVENT} error={KonnectorError.TERMS_VERSION_MISMATCH} - fluidType={FluidType.ELECTRICITY} handleCloseClick={mockClose} handleAccountDeletion={mockDelete} account={null} diff --git a/src/components/Konnector/KonnectorModalFooter.tsx b/src/components/Konnector/KonnectorModalFooter.tsx index 7ce01b20503760e4d795c5dd0c7d0cb6de35c594..9405b038e22fbac3605931574f127403719a90b5 100644 --- a/src/components/Konnector/KonnectorModalFooter.tsx +++ b/src/components/Konnector/KonnectorModalFooter.tsx @@ -5,7 +5,7 @@ import { SUCCESS_EVENT, } from 'cozy-harvest-lib/dist/models/flowEvents' import { useI18n } from 'cozy-ui/transpiled/react/I18n' -import { KonnectorError } from 'enum/konnectorError.enum' +import { KonnectorError } from 'enums' import { Account } from 'models' import React, { useCallback } from 'react' import { useNavigate } from 'react-router-dom' @@ -105,7 +105,7 @@ const KonnectorModalFooter = ({ }} style={{ height: '40px' }} > - <div>{'Plus tard'}</div> + <div>Plus tard</div> </Button> <Button aria-label={t('konnector_modal.accessibility.button_close')} diff --git a/src/components/Konnector/KonnectorViewerCard.tsx b/src/components/Konnector/KonnectorViewerCard.tsx index e5249c3d07572d46e7a8cb09ca4ab93b427bc76f..e0e44542b1259656304f6124cbffa61466ccc539 100644 --- a/src/components/Konnector/KonnectorViewerCard.tsx +++ b/src/components/Konnector/KonnectorViewerCard.tsx @@ -7,12 +7,13 @@ import { 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 WarningNotif from 'assets/icons/ico/notif_warning.svg' import OfflinePicto from 'assets/icons/visu/offline-param.svg' 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 ConnectionNotFound from 'components/Konnector/ConnectionNotFound/ConnectionNotFound' +import ConnectionResult from 'components/Konnector/ConnectionResult/ConnectionResult' import KonnectorModal from 'components/Konnector/KonnectorModal' import { useClient } from 'cozy-client' import { isKonnectorRunning } from 'cozy-harvest-lib/dist/helpers/triggers' @@ -24,12 +25,15 @@ import { } 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 { + FluidSlugType, + FluidState, + FluidType, + KonnectorError, + UsageEventType, + UserChallengeState, + UserDuelState, +} from 'enums' import { DateTime } from 'luxon' import { Account, @@ -37,18 +41,11 @@ import { FluidConnection, FluidStatus, Konnector, + PartnersInfo, Trigger, UsageEvent, } from 'models' -import { PartnersInfo } from 'models/partnersInfo.model' -import React, { - Dispatch, - useCallback, - useEffect, - useMemo, - useState, -} from 'react' -import { useDispatch, useSelector } from 'react-redux' +import React, { useCallback, useEffect, useMemo, useState } from 'react' import { useNavigate } from 'react-router-dom' import AccountService from 'services/account.service' import ChallengeService from 'services/challenge.service' @@ -56,22 +53,21 @@ import DateChartService from 'services/dateChart.service' import FluidService from 'services/fluid.service' import PartnersInfoService from 'services/partnersInfo.service' import UsageEventService from 'services/usageEvent.service' -import { AppActionsTypes, AppStore } from 'store' import { setChallengeConsumption } from 'store/challenge/challenge.slice' import { setSelectedDate, setShowOfflineData } from 'store/chart/chart.slice' import { setFluidStatus, + setLastEpglLogin, toggleChallengeDuelNotification, - updatedFluidConnection, -} from 'store/global/global.actions' + updateFluidConnection, +} from 'store/global/global.slice' +import { useAppDispatch, useAppSelector } from 'store/hooks' import { openConnectionModal } from 'store/modal/modal.slice' -import { getAddPicto, getParamPicto } from 'utils/picto' +import { getParamPicto } from 'utils/picto' import { getKonnectorSlug } from 'utils/utils' import './konnectorViewerCard.scss' interface KonnectorViewerCardProps { - fluidStatus: FluidStatus - isParam: boolean isDisconnected: boolean showOfflineData: boolean active: boolean @@ -80,8 +76,6 @@ interface KonnectorViewerCardProps { } const KonnectorViewerCard = ({ - fluidStatus, - isParam, isDisconnected, showOfflineData, active, @@ -90,30 +84,25 @@ const KonnectorViewerCard = ({ }: KonnectorViewerCardProps) => { const { t } = useI18n() const client = useClient() - const dispatch = useDispatch<Dispatch<AppActionsTypes>>() + const dispatch = useAppDispatch() const navigate = useNavigate() - - const fluidSlug = fluidStatus.connection.konnectorConfig.slug - const fluidState = fluidStatus.status - const konnector: Konnector | null = fluidStatus.connection.konnector - const account: Account | null = fluidStatus.connection.account - const trigger: Trigger | null = fluidStatus.connection.trigger const { challenge: { currentChallenge }, - global: { fluidStatus: statusArray, shouldRefreshConsent, partnersInfo }, - } = useSelector((state: AppStore) => state.ecolyo) + global: { fluidStatus, shouldRefreshConsent, partnersInfo }, + } = useAppSelector(state => state.ecolyo) + const currentFluidStatus = fluidStatus[fluidType] + const fluidSlug = currentFluidStatus.connection.konnectorConfig.slug + const fluidState = currentFluidStatus.status + const konnector: Konnector | null = currentFluidStatus.connection.konnector + const account: Account | null = currentFluidStatus.connection.account + const trigger: Trigger | null = currentFluidStatus.connection.trigger const [openModal, setOpenModal] = useState(false) const [isUpdating, setIsUpdating] = useState(false) - const [isLogging, setIsLogging] = useState( - fluidSlug !== FluidSlugType.GAS ? true : false - ) + const [isLogging, setIsLogging] = useState(fluidSlug !== FluidSlugType.GAS) const [konnectorErrorDescription, setKonnectorErrorDescription] = useState<KonnectorError | null>(null) const [konnectorState, setKonnectorState] = useState<string | null>(null) - const [updatedFluidStatus, setUpdatedFluidStatus] = useState<FluidStatus[]>( - [] - ) const [isOutdatedData, setIsOutdatedData] = useState<number | null>(null) const fluidService = useMemo(() => new FluidService(client), [client]) const partnersInfoService = useMemo( @@ -122,14 +111,11 @@ const KonnectorViewerCard = ({ ) const lastDataDate = - fluidType !== FluidType.MULTIFLUID && statusArray[fluidType].lastDataDate - ? statusArray[fluidType].lastDataDate!.toLocaleString() + fluidType + fluidType !== FluidType.MULTIFLUID && currentFluidStatus.lastDataDate + ? currentFluidStatus.lastDataDate.toLocaleString() + fluidType : fluidType - const iconType = getParamPicto(fluidStatus.fluidType) - const iconAddType = isParam - ? getParamPicto(fluidStatus.fluidType) - : getAddPicto(fluidStatus.fluidType) + const iconType = getParamPicto(currentFluidStatus.fluidType) const toggleAccordion = () => { setActive(prev => !prev) @@ -140,7 +126,6 @@ const KonnectorViewerCard = ({ > => { const _updatedFluidStatus: FluidStatus[] = await fluidService.getFluidStatus() - setUpdatedFluidStatus(_updatedFluidStatus) const refDate = DateTime.fromISO('0001-01-01') let _lastDataDate: DateTime | null = DateTime.fromISO('0001-01-01') for (const fluid of _updatedFluidStatus) { @@ -205,7 +190,8 @@ const KonnectorViewerCard = ({ konnectorErrorDescription === KonnectorError.LOGIN_FAILED || konnectorErrorDescription === KonnectorError.UNKNOWN_ERROR || konnectorErrorDescription === KonnectorError.CHALLENGE_ASKED || - konnectorErrorDescription === KonnectorError.CRITICAL + konnectorErrorDescription === KonnectorError.CRITICAL || + konnectorErrorDescription === KonnectorError.MISSING_SECRET // CASE FOR ENEDIS CODE INSEE ERROR const isEnedisCodeInseeError = @@ -214,39 +200,43 @@ const KonnectorViewerCard = ({ const shouldDeleteAccount = account && !isSuccess && - fluidStatus && - fluidStatus.connection.account && + currentFluidStatus && + currentFluidStatus.connection.account && (isGlobalLoginFailed || isEnedisCodeInseeError) if (shouldDeleteAccount) { - // KEEP CREDENTIALS FOR EGL + // KEEP LAST LOGIN FOR EPGL + let lastEpglLogin = '' if ( fluidSlug === FluidSlugType.WATER && - fluidStatus.connection.account?.auth + currentFluidStatus.connection.account?.auth ) { - const auth = fluidStatus.connection.account.auth as AccountAuthData - fluidStatus.connection.konnectorConfig.lastKnownCredentials = - auth.login + const auth = currentFluidStatus.connection.account + .auth as AccountAuthData + lastEpglLogin = auth.login } // DELETE ACCOUNT const accountService = new AccountService(client) await accountService.deleteAccount(account) await handleAccountDeletion() + + // RESTORE LAST KNOWN CREDENTIALS + if (lastEpglLogin) { + dispatch(setLastEpglLogin(lastEpglLogin)) + } } else { - if (isSuccess && fluidStatus.lastDataDate === null) { + if (isSuccess && currentFluidStatus.lastDataDate === null) { // UPDATE THE DACC EVENT STATUS TO SUCCESS - await UsageEventService.udpateConnectionAttemptEvent( + await UsageEventService.updateConnectionAttemptEvent( client, fluidSlug ) } - if (updatedFluidStatus.length > 0) { - // const partnersInfo = await partnersInfoService.getPartnersInfo() - const updatedFluidStatus = await fluidService.getFluidStatus( - partnersInfo - ) - dispatch(setFluidStatus(updatedFluidStatus)) - } + // const partnersInfo = await partnersInfoService.getPartnersInfo() + const updatedFluidStatus = await fluidService.getFluidStatus( + partnersInfo + ) + dispatch(setFluidStatus(updatedFluidStatus)) } setActive(false) @@ -258,14 +248,13 @@ const KonnectorViewerCard = ({ [ account, konnectorErrorDescription, - fluidStatus, + currentFluidStatus, isUpdating, fluidType, setActive, fluidSlug, client, handleAccountDeletion, - updatedFluidStatus.length, fluidService, partnersInfo, dispatch, @@ -304,7 +293,7 @@ const KonnectorViewerCard = ({ [client] ) - const toggleModalConnection = () => { + const toggleModalConnection = useCallback(() => { switch (fluidType) { case FluidType.ELECTRICITY: navigate('/sge-connect') @@ -315,7 +304,7 @@ const KonnectorViewerCard = ({ dispatch(openConnectionModal(true)) break } - } + }, [dispatch, fluidType, navigate]) const getConnectionCard = useCallback(() => { if (showOfflineData && !account) { @@ -338,39 +327,45 @@ const KonnectorViewerCard = ({ else if ( (fluidState === FluidState.ERROR_LOGIN_FAILED && fluidType === FluidType.WATER) || - (account && fluidStatus.status !== FluidState.NOT_CONNECTED) + (account && currentFluidStatus.status !== FluidState.NOT_CONNECTED) ) { return ( <ConnectionResult - fluidStatus={fluidStatus} handleAccountDeletion={handleAccountDeletion} fluidType={fluidType} key={lastDataDate} /> ) } else { - return <Connection fluidStatus={fluidStatus} /> + return <Connection fluidType={currentFluidStatus.fluidType} /> } }, [ - fluidState, - isUpdating, account, - fluidStatus, + currentFluidStatus.fluidType, + currentFluidStatus.status, fluidSlug, - handleAccountDeletion, + fluidState, fluidType, + handleAccountDeletion, + isUpdating, lastDataDate, + showOfflineData, + t, + toggleModalConnection, ]) const callbackResponse = useCallback( async (_state: string) => { if (_state !== LOGIN_SUCCESS_EVENT) { const updatedConnection: FluidConnection = { - ...fluidStatus.connection, + ...currentFluidStatus.connection, shouldLaunchKonnector: false, } dispatch( - updatedFluidConnection(fluidStatus.fluidType, updatedConnection) + updateFluidConnection({ + fluidType: currentFluidStatus.fluidType, + fluidConnection: updatedConnection, + }) ) Promise.all([ await refreshChallengeState(), @@ -381,56 +376,79 @@ const KonnectorViewerCard = ({ }, [ dispatch, - fluidStatus.connection, - fluidStatus.fluidType, + currentFluidStatus.connection, + currentFluidStatus.fluidType, refreshChallengeState, updateGlobalFluidStatus, ] ) + + const getIconForStatus = ( + status: FluidState, + maintenance: boolean, + connection: FluidConnection, + outdatedData: number | null + ) => { + if (maintenance) { + return ( + <StyledIcon + icon={PartnersIssueNotif} + size={24} + className="konnector-state-picto" + /> + ) + } + + if ( + (status === FluidState.ERROR || + status === FluidState.ERROR_LOGIN_FAILED) && + connection.account + ) { + return ( + <StyledIcon + icon={ErrorNotif} + size={24} + className="konnector-state-picto" + /> + ) + } + + if (outdatedData && outdatedData > 0) { + return ( + <StyledIcon + icon={WarningNotif} + size={24} + className="konnector-state-picto" + /> + ) + } + } + const displayKonnectorIcon = useCallback(() => { return ( <div className="konnector-icon"> <Icon - icon={fluidStatus.connection.account ? iconType : OfflinePicto} + icon={currentFluidStatus.connection.account ? iconType : OfflinePicto} size={49} /> - {fluidStatus.maintenance ? ( - <StyledIcon - icon={PartnersIssueNotif} - size={24} - className="konnector-state-picto" - /> - ) : ( - (fluidStatus.status === FluidState.ERROR || - isOutdatedData || - fluidStatus.status === FluidState.ERROR_LOGIN_FAILED) && - fluidStatus.connection.account && ( - <StyledIcon - icon={ErrorNotif} - size={24} - className="konnector-state-picto" - /> - ) + {getIconForStatus( + currentFluidStatus.status, + currentFluidStatus.maintenance, + currentFluidStatus.connection, + isOutdatedData )} </div> ) - }, [ - fluidStatus.connection.account, - fluidStatus.maintenance, - fluidStatus.status, - iconAddType, - iconType, - isOutdatedData, - ]) + }, [currentFluidStatus, iconType, isOutdatedData]) const displayKonnectorHeader = useCallback(() => { - if (fluidStatus.maintenance) { + if (currentFluidStatus.maintenance) { return ( <span className="text-16-bold"> {t(`konnector_options.partner_issue`)} </span> ) - } else if (isOutdatedData && fluidStatus.connection.account) { + } else if (isOutdatedData && currentFluidStatus.connection.account) { return ( <span className="text-16-bold outdated"> {t('konnector_options.outdated', { @@ -438,19 +456,19 @@ const KonnectorViewerCard = ({ })} </span> ) - } else if (fluidStatus.connection.account && !isOutdatedData) { - return t(`FLUID.${FluidType[fluidStatus.fluidType]}.LABEL`) + } else if (currentFluidStatus.connection.account && !isOutdatedData) { + return t(`FLUID.${FluidType[currentFluidStatus.fluidType]}.LABEL`) } else { return t( `konnector_options.label_offline_${FluidType[ - fluidStatus.fluidType + currentFluidStatus.fluidType ].toLowerCase()}` ) } }, [ - fluidStatus.connection.account, - fluidStatus.fluidType, - fluidStatus.maintenance, + currentFluidStatus.connection.account, + currentFluidStatus.fluidType, + currentFluidStatus.maintenance, isOutdatedData, t, ]) @@ -471,28 +489,45 @@ const KonnectorViewerCard = ({ let subscribed = true async function getData() { if ( - fluidStatus.connection.shouldLaunchKonnector && + currentFluidStatus.connection.shouldLaunchKonnector && !isKonnectorRunning(trigger) ) { if (subscribed) { - if (fluidStatus.connection.isUpdating) setIsUpdating(true) + if (currentFluidStatus.connection.isUpdating) setIsUpdating(true) setOpenModal(true) - fluidStatus.connection.shouldLaunchKonnector = false + const updatedConnection: FluidConnection = { + ...currentFluidStatus.connection, + shouldLaunchKonnector: false, + } + dispatch( + updateFluidConnection({ + fluidType: currentFluidStatus.fluidType, + fluidConnection: updatedConnection, + }) + ) } - const connectionFlow = new ConnectionFlow(client, trigger, konnector) await connectionFlow.launch() connectionFlow.jobWatcher.on(ERROR_EVENT, () => { - sendUsageEventError(fluidSlug, fluidStatus.lastDataDate === null) + sendUsageEventError( + fluidSlug, + currentFluidStatus.lastDataDate === null + ) setKonnectorErrorDescription(connectionFlow.jobWatcher.on()._error) callbackResponse(ERROR_EVENT) }) connectionFlow.jobWatcher.on(LOGIN_SUCCESS_EVENT, () => { setIsLogging(false) - sendUsageEventSuccess(fluidSlug, fluidStatus.lastDataDate === null) + sendUsageEventSuccess( + fluidSlug, + currentFluidStatus.lastDataDate === null + ) }) connectionFlow.jobWatcher.on(SUCCESS_EVENT, () => { - sendUsageEventSuccess(fluidSlug, fluidStatus.lastDataDate === null) + sendUsageEventSuccess( + fluidSlug, + currentFluidStatus.lastDataDate === null + ) callbackResponse(SUCCESS_EVENT) }) } @@ -500,27 +535,28 @@ const KonnectorViewerCard = ({ !shouldRefreshConsent && getData() const dateChartService = new DateChartService() setIsOutdatedData( - dateChartService.isDataOutdated(fluidStatus.lastDataDate, fluidType) + dateChartService.isDataOutdated( + currentFluidStatus.lastDataDate, + fluidType + ) ) return () => { subscribed = false } }, [ - client, - konnector, - trigger, - fluidStatus.connection, - fluidStatus.connection.shouldLaunchKonnector, - fluidStatus.connection.isUpdating, - fluidStatus.fluidType, callbackResponse, - setActive, - fluidStatus.lastDataDate, + client, + currentFluidStatus.connection, + currentFluidStatus.fluidType, + currentFluidStatus.lastDataDate, + dispatch, + fluidSlug, fluidType, + konnector, sendUsageEventError, - fluidSlug, sendUsageEventSuccess, shouldRefreshConsent, + trigger, ]) return ( @@ -531,9 +567,9 @@ const KonnectorViewerCard = ({ onChange={toggleAccordion} classes={{ root: `expansion-panel-root ${ - !fluidStatus.maintenance && - (fluidStatus.status === FluidState.ERROR || - fluidStatus.status === FluidState.ERROR_LOGIN_FAILED) + !currentFluidStatus.maintenance && + (currentFluidStatus.status === FluidState.ERROR || + currentFluidStatus.status === FluidState.ERROR_LOGIN_FAILED) ? 'red-border' : '' }`, @@ -542,7 +578,7 @@ const KonnectorViewerCard = ({ <AccordionSummary aria-label={t( `konnector_options.accessibility.button_toggle_detail_${FluidType[ - fluidStatus.fluidType + currentFluidStatus.fluidType ].toLowerCase()}` )} expandIcon={ @@ -556,9 +592,11 @@ const KonnectorViewerCard = ({ {displayKonnectorIcon()} <div className={classNames('text-16-bold konnector-title', { - [`${FluidType[fluidStatus.fluidType].toLowerCase()}-connected`]: - fluidStatus.status !== FluidState.NOT_CONNECTED && - !fluidStatus.maintenance, + [`${FluidType[ + currentFluidStatus.fluidType + ].toLowerCase()}-connected`]: + currentFluidStatus.status !== FluidState.NOT_CONNECTED && + !currentFluidStatus.maintenance, })} > {displayKonnectorHeader()} @@ -583,7 +621,7 @@ const KonnectorViewerCard = ({ isLogging={isLogging} state={konnectorState} error={konnectorErrorDescription} - fluidType={fluidStatus.fluidType} + fluidType={currentFluidStatus.fluidType} handleCloseClick={handleConnectionEnd} handleAccountDeletion={handleAccountDeletion} account={account} diff --git a/src/components/Konnector/KonnectorViewerList.spec.tsx b/src/components/Konnector/KonnectorViewerList.spec.tsx index 9394ed2ca3a75f7a2c50e10c451befe0fc1574bc..505bc5610081f730a5c63d4d6869eedcd2285cdb 100644 --- a/src/components/Konnector/KonnectorViewerList.spec.tsx +++ b/src/components/Konnector/KonnectorViewerList.spec.tsx @@ -1,24 +1,11 @@ import { mount } from 'enzyme' import toJson from 'enzyme-to-json' import React from 'react' -import * as reactRedux from 'react-redux' import { Provider } from 'react-redux' -import { - createMockEcolyoStore, - mockInitialGlobalState, -} from '../../../tests/__mocks__/store' -import { waitForComponentToPaint } from '../../../tests/__mocks__/testUtils' +import { createMockEcolyoStore } from 'tests/__mocks__/store' +import { waitForComponentToPaint } from 'tests/__mocks__/testUtils' import KonnectorViewerList from './KonnectorViewerList' -jest.mock('cozy-ui/transpiled/react/I18n', () => { - return { - useI18n: jest.fn(() => { - return { - t: (str: string) => str, - } - }), - } -}) const mockedNavigate = jest.fn() jest.mock('react-router-dom', () => ({ ...jest.requireActual('react-router-dom'), @@ -27,9 +14,6 @@ jest.mock('react-router-dom', () => ({ describe('KonnectorViewerList component', () => { const store = createMockEcolyoStore() - beforeEach(() => { - store.clearActions() - }) it('should be rendered correctly', async () => { const wrapper = mount( @@ -41,11 +25,6 @@ describe('KonnectorViewerList component', () => { expect(toJson(wrapper)).toMatchSnapshot() }) it('should click on card and nav to fluid', async () => { - const mockUseSelector = jest.spyOn(reactRedux, 'useSelector') - - mockUseSelector.mockReturnValue({ - fluidStatus: mockInitialGlobalState.fluidStatus, - }) const wrapper = mount( <Provider store={store}> <KonnectorViewerList /> diff --git a/src/components/Konnector/KonnectorViewerList.tsx b/src/components/Konnector/KonnectorViewerList.tsx index e4c0c6190ead10314feb40b986357b73821e3537..58fc207425d78446bcb6801b2abe404adc0423bb 100644 --- a/src/components/Konnector/KonnectorViewerList.tsx +++ b/src/components/Konnector/KonnectorViewerList.tsx @@ -1,28 +1,25 @@ import StyledCard from 'components/CommonKit/Card/StyledCard' import { useI18n } from 'cozy-ui/transpiled/react/I18n' import Icon from 'cozy-ui/transpiled/react/Icon' -import { FluidType } from 'enum/fluid.enum' +import { FluidType } from 'enums' import { FluidStatus } from 'models' -import React, { useCallback } from 'react' -import { useSelector } from 'react-redux' +import React from 'react' import { useNavigate } from 'react-router-dom' -import { AppStore } from 'store' +import { useAppSelector } from 'store/hooks' import { getAddPicto } from 'utils/picto' import { getFluidName } from 'utils/utils' import './konnectorViewerList.scss' const KonnectorViewerList = () => { const { t } = useI18n() - const { fluidStatus } = useSelector((state: AppStore) => state.ecolyo.global) + const { fluidStatus } = useAppSelector(state => state.ecolyo.global) const navigate = useNavigate() - const goToFluid = useCallback( - fluidType => { - navigate(`/consumption/${getFluidName(fluidType)}`) - }, - [navigate] - ) + const goToFluid = (fluidType: FluidType) => { + navigate(`/consumption/${getFluidName(fluidType)}`) + } + return ( - <> + <div className="konnectorsList"> {fluidStatus.map((fluidStatusItem: FluidStatus, key: number) => ( <StyledCard key={key} @@ -44,7 +41,7 @@ const KonnectorViewerList = () => { </div> </StyledCard> ))} - </> + </div> ) } diff --git a/src/components/Konnector/__snapshots__/KonnectorModalFooter.spec.tsx.snap b/src/components/Konnector/__snapshots__/KonnectorModalFooter.spec.tsx.snap index 729e3c5d13d8721ad2e9fe24dbc4223c7940dad3..c54c118d73c5d35603892d5c7fd1eb25e25bbd49 100644 --- a/src/components/Konnector/__snapshots__/KonnectorModalFooter.spec.tsx.snap +++ b/src/components/Konnector/__snapshots__/KonnectorModalFooter.spec.tsx.snap @@ -16,7 +16,6 @@ exports[`KonnectorModalFooter component should be rendered correctly 1`] = ` <KonnectorModalFooter account={null} error={null} - fluidType={0} handleAccountDeletion={[MockFunction]} handleCloseClick={[MockFunction]} isUpdating={false} diff --git a/src/components/Konnector/__snapshots__/KonnectorViewerList.spec.tsx.snap b/src/components/Konnector/__snapshots__/KonnectorViewerList.spec.tsx.snap index 6a487b21e1ed33a10a1e4786cac1c50a0fb4eadd..6295440273087145768e2ea94b73c7b30703bec5 100644 --- a/src/components/Konnector/__snapshots__/KonnectorViewerList.spec.tsx.snap +++ b/src/components/Konnector/__snapshots__/KonnectorViewerList.spec.tsx.snap @@ -14,465 +14,469 @@ exports[`KonnectorViewerList component should be rendered correctly 1`] = ` } > <KonnectorViewerList> - <StyledCard - className="connection-card" - fluidType={0} - key="0" - onClick={[Function]} + <div + className="konnectorsList" > - <WithStyles(WithStyles(ForwardRef(CardActionArea))) - className="connection-card electricity" + <StyledCard + className="connection-card" + fluidType={0} + key="0" onClick={[Function]} > - <WithStyles(ForwardRef(CardActionArea)) + <WithStyles(WithStyles(ForwardRef(CardActionArea))) className="connection-card electricity" - classes={ - Object { - "root": "WithStyles(ForwardRef(CardActionArea))-root-1", - } - } onClick={[Function]} > - <ForwardRef(CardActionArea) + <WithStyles(ForwardRef(CardActionArea)) className="connection-card electricity" classes={ Object { - "focusHighlight": "MuiCardActionArea-focusHighlight", - "focusVisible": "Mui-focusVisible", - "root": "MuiCardActionArea-root WithStyles(ForwardRef(CardActionArea))-root-1", + "root": "WithStyles(ForwardRef(CardActionArea))-root-1", } } onClick={[Function]} > - <WithStyles(ForwardRef(ButtonBase)) - className="MuiCardActionArea-root WithStyles(ForwardRef(CardActionArea))-root-1 connection-card electricity" - focusVisibleClassName="Mui-focusVisible" + <ForwardRef(CardActionArea) + className="connection-card electricity" + classes={ + Object { + "focusHighlight": "MuiCardActionArea-focusHighlight", + "focusVisible": "Mui-focusVisible", + "root": "MuiCardActionArea-root WithStyles(ForwardRef(CardActionArea))-root-1", + } + } onClick={[Function]} > - <ForwardRef(ButtonBase) + <WithStyles(ForwardRef(ButtonBase)) className="MuiCardActionArea-root WithStyles(ForwardRef(CardActionArea))-root-1 connection-card electricity" - classes={ - Object { - "disabled": "Mui-disabled", - "focusVisible": "Mui-focusVisible", - "root": "MuiButtonBase-root", - } - } focusVisibleClassName="Mui-focusVisible" onClick={[Function]} > - <button - className="MuiButtonBase-root MuiCardActionArea-root WithStyles(ForwardRef(CardActionArea))-root-1 connection-card electricity" - disabled={false} - onBlur={[Function]} + <ForwardRef(ButtonBase) + className="MuiCardActionArea-root WithStyles(ForwardRef(CardActionArea))-root-1 connection-card electricity" + classes={ + Object { + "disabled": "Mui-disabled", + "focusVisible": "Mui-focusVisible", + "root": "MuiButtonBase-root", + } + } + focusVisibleClassName="Mui-focusVisible" onClick={[Function]} - onDragLeave={[Function]} - onFocus={[Function]} - onKeyDown={[Function]} - onKeyUp={[Function]} - onMouseDown={[Function]} - onMouseLeave={[Function]} - onMouseUp={[Function]} - onTouchEnd={[Function]} - onTouchMove={[Function]} - onTouchStart={[Function]} - tabIndex={0} - type="button" > - <WithStyles(WithStyles(ForwardRef(CardContent)))> - <WithStyles(ForwardRef(CardContent)) - classes={ - Object { - "root": "WithStyles(ForwardRef(CardContent))-root-2", - } - } - > - <ForwardRef(CardContent) + <button + className="MuiButtonBase-root MuiCardActionArea-root WithStyles(ForwardRef(CardActionArea))-root-1 connection-card electricity" + disabled={false} + onBlur={[Function]} + onClick={[Function]} + onDragLeave={[Function]} + onFocus={[Function]} + onKeyDown={[Function]} + onKeyUp={[Function]} + onMouseDown={[Function]} + onMouseLeave={[Function]} + onMouseUp={[Function]} + onTouchEnd={[Function]} + onTouchMove={[Function]} + onTouchStart={[Function]} + tabIndex={0} + type="button" + > + <WithStyles(WithStyles(ForwardRef(CardContent)))> + <WithStyles(ForwardRef(CardContent)) classes={ Object { - "root": "MuiCardContent-root WithStyles(ForwardRef(CardContent))-root-2", + "root": "WithStyles(ForwardRef(CardContent))-root-2", } } > - <div - className="MuiCardContent-root WithStyles(ForwardRef(CardContent))-root-2" + <ForwardRef(CardContent) + classes={ + Object { + "root": "MuiCardContent-root WithStyles(ForwardRef(CardContent))-root-2", + } + } > - <Icon - icon="test-file-stub" - size={36} - spin={false} + <div + className="MuiCardContent-root WithStyles(ForwardRef(CardContent))-root-2" > - <Component - className="styles__icon___23x3R" - height={36} - style={Object {}} - width={36} + <Icon + icon="test-file-stub" + size={36} + spin={false} > - <svg + <Component className="styles__icon___23x3R" height={36} style={Object {}} width={36} > - <use - xlinkHref="#test-file-stub" - /> - </svg> - </Component> - </Icon> - <div - className="konnector-title text-18-bold electricity" - > - konnector_options.label_connect_to_electricity + <svg + className="styles__icon___23x3R" + height={36} + style={Object {}} + width={36} + > + <use + xlinkHref="#test-file-stub" + /> + </svg> + </Component> + </Icon> + <div + className="konnector-title text-18-bold electricity" + > + konnector_options.label_connect_to_electricity + </div> </div> - </div> - </ForwardRef(CardContent)> - </WithStyles(ForwardRef(CardContent))> - </WithStyles(WithStyles(ForwardRef(CardContent)))> - <span - className="MuiCardActionArea-focusHighlight" - /> - <WithStyles(memo) - center={false} - > - <ForwardRef(TouchRipple) + </ForwardRef(CardContent)> + </WithStyles(ForwardRef(CardContent))> + </WithStyles(WithStyles(ForwardRef(CardContent)))> + <span + className="MuiCardActionArea-focusHighlight" + /> + <WithStyles(memo) center={false} - classes={ - Object { - "child": "MuiTouchRipple-child", - "childLeaving": "MuiTouchRipple-childLeaving", - "childPulsate": "MuiTouchRipple-childPulsate", - "ripple": "MuiTouchRipple-ripple", - "ripplePulsate": "MuiTouchRipple-ripplePulsate", - "rippleVisible": "MuiTouchRipple-rippleVisible", - "root": "MuiTouchRipple-root", - } - } > - <span - className="MuiTouchRipple-root" + <ForwardRef(TouchRipple) + center={false} + classes={ + Object { + "child": "MuiTouchRipple-child", + "childLeaving": "MuiTouchRipple-childLeaving", + "childPulsate": "MuiTouchRipple-childPulsate", + "ripple": "MuiTouchRipple-ripple", + "ripplePulsate": "MuiTouchRipple-ripplePulsate", + "rippleVisible": "MuiTouchRipple-rippleVisible", + "root": "MuiTouchRipple-root", + } + } > - <TransitionGroup - childFactory={[Function]} - component={null} - exit={true} - /> - </span> - </ForwardRef(TouchRipple)> - </WithStyles(memo)> - </button> - </ForwardRef(ButtonBase)> - </WithStyles(ForwardRef(ButtonBase))> - </ForwardRef(CardActionArea)> - </WithStyles(ForwardRef(CardActionArea))> - </WithStyles(WithStyles(ForwardRef(CardActionArea)))> - </StyledCard> - <StyledCard - className="connection-card" - fluidType={1} - key="1" - onClick={[Function]} - > - <WithStyles(WithStyles(ForwardRef(CardActionArea))) - className="connection-card water" + <span + className="MuiTouchRipple-root" + > + <TransitionGroup + childFactory={[Function]} + component={null} + exit={true} + /> + </span> + </ForwardRef(TouchRipple)> + </WithStyles(memo)> + </button> + </ForwardRef(ButtonBase)> + </WithStyles(ForwardRef(ButtonBase))> + </ForwardRef(CardActionArea)> + </WithStyles(ForwardRef(CardActionArea))> + </WithStyles(WithStyles(ForwardRef(CardActionArea)))> + </StyledCard> + <StyledCard + className="connection-card" + fluidType={1} + key="1" onClick={[Function]} > - <WithStyles(ForwardRef(CardActionArea)) + <WithStyles(WithStyles(ForwardRef(CardActionArea))) className="connection-card water" - classes={ - Object { - "root": "WithStyles(ForwardRef(CardActionArea))-root-1", - } - } onClick={[Function]} > - <ForwardRef(CardActionArea) + <WithStyles(ForwardRef(CardActionArea)) className="connection-card water" classes={ Object { - "focusHighlight": "MuiCardActionArea-focusHighlight", - "focusVisible": "Mui-focusVisible", - "root": "MuiCardActionArea-root WithStyles(ForwardRef(CardActionArea))-root-1", + "root": "WithStyles(ForwardRef(CardActionArea))-root-1", } } onClick={[Function]} > - <WithStyles(ForwardRef(ButtonBase)) - className="MuiCardActionArea-root WithStyles(ForwardRef(CardActionArea))-root-1 connection-card water" - focusVisibleClassName="Mui-focusVisible" + <ForwardRef(CardActionArea) + className="connection-card water" + classes={ + Object { + "focusHighlight": "MuiCardActionArea-focusHighlight", + "focusVisible": "Mui-focusVisible", + "root": "MuiCardActionArea-root WithStyles(ForwardRef(CardActionArea))-root-1", + } + } onClick={[Function]} > - <ForwardRef(ButtonBase) + <WithStyles(ForwardRef(ButtonBase)) className="MuiCardActionArea-root WithStyles(ForwardRef(CardActionArea))-root-1 connection-card water" - classes={ - Object { - "disabled": "Mui-disabled", - "focusVisible": "Mui-focusVisible", - "root": "MuiButtonBase-root", - } - } focusVisibleClassName="Mui-focusVisible" onClick={[Function]} > - <button - className="MuiButtonBase-root MuiCardActionArea-root WithStyles(ForwardRef(CardActionArea))-root-1 connection-card water" - disabled={false} - onBlur={[Function]} + <ForwardRef(ButtonBase) + className="MuiCardActionArea-root WithStyles(ForwardRef(CardActionArea))-root-1 connection-card water" + classes={ + Object { + "disabled": "Mui-disabled", + "focusVisible": "Mui-focusVisible", + "root": "MuiButtonBase-root", + } + } + focusVisibleClassName="Mui-focusVisible" onClick={[Function]} - onDragLeave={[Function]} - onFocus={[Function]} - onKeyDown={[Function]} - onKeyUp={[Function]} - onMouseDown={[Function]} - onMouseLeave={[Function]} - onMouseUp={[Function]} - onTouchEnd={[Function]} - onTouchMove={[Function]} - onTouchStart={[Function]} - tabIndex={0} - type="button" > - <WithStyles(WithStyles(ForwardRef(CardContent)))> - <WithStyles(ForwardRef(CardContent)) - classes={ - Object { - "root": "WithStyles(ForwardRef(CardContent))-root-2", - } - } - > - <ForwardRef(CardContent) + <button + className="MuiButtonBase-root MuiCardActionArea-root WithStyles(ForwardRef(CardActionArea))-root-1 connection-card water" + disabled={false} + onBlur={[Function]} + onClick={[Function]} + onDragLeave={[Function]} + onFocus={[Function]} + onKeyDown={[Function]} + onKeyUp={[Function]} + onMouseDown={[Function]} + onMouseLeave={[Function]} + onMouseUp={[Function]} + onTouchEnd={[Function]} + onTouchMove={[Function]} + onTouchStart={[Function]} + tabIndex={0} + type="button" + > + <WithStyles(WithStyles(ForwardRef(CardContent)))> + <WithStyles(ForwardRef(CardContent)) classes={ Object { - "root": "MuiCardContent-root WithStyles(ForwardRef(CardContent))-root-2", + "root": "WithStyles(ForwardRef(CardContent))-root-2", } } > - <div - className="MuiCardContent-root WithStyles(ForwardRef(CardContent))-root-2" + <ForwardRef(CardContent) + classes={ + Object { + "root": "MuiCardContent-root WithStyles(ForwardRef(CardContent))-root-2", + } + } > - <Icon - icon="test-file-stub" - size={36} - spin={false} + <div + className="MuiCardContent-root WithStyles(ForwardRef(CardContent))-root-2" > - <Component - className="styles__icon___23x3R" - height={36} - style={Object {}} - width={36} + <Icon + icon="test-file-stub" + size={36} + spin={false} > - <svg + <Component className="styles__icon___23x3R" height={36} style={Object {}} width={36} > - <use - xlinkHref="#test-file-stub" - /> - </svg> - </Component> - </Icon> - <div - className="konnector-title text-18-bold water" - > - konnector_options.label_connect_to_water + <svg + className="styles__icon___23x3R" + height={36} + style={Object {}} + width={36} + > + <use + xlinkHref="#test-file-stub" + /> + </svg> + </Component> + </Icon> + <div + className="konnector-title text-18-bold water" + > + konnector_options.label_connect_to_water + </div> </div> - </div> - </ForwardRef(CardContent)> - </WithStyles(ForwardRef(CardContent))> - </WithStyles(WithStyles(ForwardRef(CardContent)))> - <span - className="MuiCardActionArea-focusHighlight" - /> - <WithStyles(memo) - center={false} - > - <ForwardRef(TouchRipple) + </ForwardRef(CardContent)> + </WithStyles(ForwardRef(CardContent))> + </WithStyles(WithStyles(ForwardRef(CardContent)))> + <span + className="MuiCardActionArea-focusHighlight" + /> + <WithStyles(memo) center={false} - classes={ - Object { - "child": "MuiTouchRipple-child", - "childLeaving": "MuiTouchRipple-childLeaving", - "childPulsate": "MuiTouchRipple-childPulsate", - "ripple": "MuiTouchRipple-ripple", - "ripplePulsate": "MuiTouchRipple-ripplePulsate", - "rippleVisible": "MuiTouchRipple-rippleVisible", - "root": "MuiTouchRipple-root", - } - } > - <span - className="MuiTouchRipple-root" + <ForwardRef(TouchRipple) + center={false} + classes={ + Object { + "child": "MuiTouchRipple-child", + "childLeaving": "MuiTouchRipple-childLeaving", + "childPulsate": "MuiTouchRipple-childPulsate", + "ripple": "MuiTouchRipple-ripple", + "ripplePulsate": "MuiTouchRipple-ripplePulsate", + "rippleVisible": "MuiTouchRipple-rippleVisible", + "root": "MuiTouchRipple-root", + } + } > - <TransitionGroup - childFactory={[Function]} - component={null} - exit={true} - /> - </span> - </ForwardRef(TouchRipple)> - </WithStyles(memo)> - </button> - </ForwardRef(ButtonBase)> - </WithStyles(ForwardRef(ButtonBase))> - </ForwardRef(CardActionArea)> - </WithStyles(ForwardRef(CardActionArea))> - </WithStyles(WithStyles(ForwardRef(CardActionArea)))> - </StyledCard> - <StyledCard - className="connection-card" - fluidType={2} - key="2" - onClick={[Function]} - > - <WithStyles(WithStyles(ForwardRef(CardActionArea))) - className="connection-card gas" + <span + className="MuiTouchRipple-root" + > + <TransitionGroup + childFactory={[Function]} + component={null} + exit={true} + /> + </span> + </ForwardRef(TouchRipple)> + </WithStyles(memo)> + </button> + </ForwardRef(ButtonBase)> + </WithStyles(ForwardRef(ButtonBase))> + </ForwardRef(CardActionArea)> + </WithStyles(ForwardRef(CardActionArea))> + </WithStyles(WithStyles(ForwardRef(CardActionArea)))> + </StyledCard> + <StyledCard + className="connection-card" + fluidType={2} + key="2" onClick={[Function]} > - <WithStyles(ForwardRef(CardActionArea)) + <WithStyles(WithStyles(ForwardRef(CardActionArea))) className="connection-card gas" - classes={ - Object { - "root": "WithStyles(ForwardRef(CardActionArea))-root-1", - } - } onClick={[Function]} > - <ForwardRef(CardActionArea) + <WithStyles(ForwardRef(CardActionArea)) className="connection-card gas" classes={ Object { - "focusHighlight": "MuiCardActionArea-focusHighlight", - "focusVisible": "Mui-focusVisible", - "root": "MuiCardActionArea-root WithStyles(ForwardRef(CardActionArea))-root-1", + "root": "WithStyles(ForwardRef(CardActionArea))-root-1", } } onClick={[Function]} > - <WithStyles(ForwardRef(ButtonBase)) - className="MuiCardActionArea-root WithStyles(ForwardRef(CardActionArea))-root-1 connection-card gas" - focusVisibleClassName="Mui-focusVisible" + <ForwardRef(CardActionArea) + className="connection-card gas" + classes={ + Object { + "focusHighlight": "MuiCardActionArea-focusHighlight", + "focusVisible": "Mui-focusVisible", + "root": "MuiCardActionArea-root WithStyles(ForwardRef(CardActionArea))-root-1", + } + } onClick={[Function]} > - <ForwardRef(ButtonBase) + <WithStyles(ForwardRef(ButtonBase)) className="MuiCardActionArea-root WithStyles(ForwardRef(CardActionArea))-root-1 connection-card gas" - classes={ - Object { - "disabled": "Mui-disabled", - "focusVisible": "Mui-focusVisible", - "root": "MuiButtonBase-root", - } - } focusVisibleClassName="Mui-focusVisible" onClick={[Function]} > - <button - className="MuiButtonBase-root MuiCardActionArea-root WithStyles(ForwardRef(CardActionArea))-root-1 connection-card gas" - disabled={false} - onBlur={[Function]} + <ForwardRef(ButtonBase) + className="MuiCardActionArea-root WithStyles(ForwardRef(CardActionArea))-root-1 connection-card gas" + classes={ + Object { + "disabled": "Mui-disabled", + "focusVisible": "Mui-focusVisible", + "root": "MuiButtonBase-root", + } + } + focusVisibleClassName="Mui-focusVisible" onClick={[Function]} - onDragLeave={[Function]} - onFocus={[Function]} - onKeyDown={[Function]} - onKeyUp={[Function]} - onMouseDown={[Function]} - onMouseLeave={[Function]} - onMouseUp={[Function]} - onTouchEnd={[Function]} - onTouchMove={[Function]} - onTouchStart={[Function]} - tabIndex={0} - type="button" > - <WithStyles(WithStyles(ForwardRef(CardContent)))> - <WithStyles(ForwardRef(CardContent)) - classes={ - Object { - "root": "WithStyles(ForwardRef(CardContent))-root-2", - } - } - > - <ForwardRef(CardContent) + <button + className="MuiButtonBase-root MuiCardActionArea-root WithStyles(ForwardRef(CardActionArea))-root-1 connection-card gas" + disabled={false} + onBlur={[Function]} + onClick={[Function]} + onDragLeave={[Function]} + onFocus={[Function]} + onKeyDown={[Function]} + onKeyUp={[Function]} + onMouseDown={[Function]} + onMouseLeave={[Function]} + onMouseUp={[Function]} + onTouchEnd={[Function]} + onTouchMove={[Function]} + onTouchStart={[Function]} + tabIndex={0} + type="button" + > + <WithStyles(WithStyles(ForwardRef(CardContent)))> + <WithStyles(ForwardRef(CardContent)) classes={ Object { - "root": "MuiCardContent-root WithStyles(ForwardRef(CardContent))-root-2", + "root": "WithStyles(ForwardRef(CardContent))-root-2", } } > - <div - className="MuiCardContent-root WithStyles(ForwardRef(CardContent))-root-2" + <ForwardRef(CardContent) + classes={ + Object { + "root": "MuiCardContent-root WithStyles(ForwardRef(CardContent))-root-2", + } + } > - <Icon - icon="test-file-stub" - size={36} - spin={false} + <div + className="MuiCardContent-root WithStyles(ForwardRef(CardContent))-root-2" > - <Component - className="styles__icon___23x3R" - height={36} - style={Object {}} - width={36} + <Icon + icon="test-file-stub" + size={36} + spin={false} > - <svg + <Component className="styles__icon___23x3R" height={36} style={Object {}} width={36} > - <use - xlinkHref="#test-file-stub" - /> - </svg> - </Component> - </Icon> - <div - className="konnector-title text-18-bold gas" - > - konnector_options.label_connect_to_gas + <svg + className="styles__icon___23x3R" + height={36} + style={Object {}} + width={36} + > + <use + xlinkHref="#test-file-stub" + /> + </svg> + </Component> + </Icon> + <div + className="konnector-title text-18-bold gas" + > + konnector_options.label_connect_to_gas + </div> </div> - </div> - </ForwardRef(CardContent)> - </WithStyles(ForwardRef(CardContent))> - </WithStyles(WithStyles(ForwardRef(CardContent)))> - <span - className="MuiCardActionArea-focusHighlight" - /> - <WithStyles(memo) - center={false} - > - <ForwardRef(TouchRipple) + </ForwardRef(CardContent)> + </WithStyles(ForwardRef(CardContent))> + </WithStyles(WithStyles(ForwardRef(CardContent)))> + <span + className="MuiCardActionArea-focusHighlight" + /> + <WithStyles(memo) center={false} - classes={ - Object { - "child": "MuiTouchRipple-child", - "childLeaving": "MuiTouchRipple-childLeaving", - "childPulsate": "MuiTouchRipple-childPulsate", - "ripple": "MuiTouchRipple-ripple", - "ripplePulsate": "MuiTouchRipple-ripplePulsate", - "rippleVisible": "MuiTouchRipple-rippleVisible", - "root": "MuiTouchRipple-root", - } - } > - <span - className="MuiTouchRipple-root" + <ForwardRef(TouchRipple) + center={false} + classes={ + Object { + "child": "MuiTouchRipple-child", + "childLeaving": "MuiTouchRipple-childLeaving", + "childPulsate": "MuiTouchRipple-childPulsate", + "ripple": "MuiTouchRipple-ripple", + "ripplePulsate": "MuiTouchRipple-ripplePulsate", + "rippleVisible": "MuiTouchRipple-rippleVisible", + "root": "MuiTouchRipple-root", + } + } > - <TransitionGroup - childFactory={[Function]} - component={null} - exit={true} - /> - </span> - </ForwardRef(TouchRipple)> - </WithStyles(memo)> - </button> - </ForwardRef(ButtonBase)> - </WithStyles(ForwardRef(ButtonBase))> - </ForwardRef(CardActionArea)> - </WithStyles(ForwardRef(CardActionArea))> - </WithStyles(WithStyles(ForwardRef(CardActionArea)))> - </StyledCard> + <span + className="MuiTouchRipple-root" + > + <TransitionGroup + childFactory={[Function]} + component={null} + exit={true} + /> + </span> + </ForwardRef(TouchRipple)> + </WithStyles(memo)> + </button> + </ForwardRef(ButtonBase)> + </WithStyles(ForwardRef(ButtonBase))> + </ForwardRef(CardActionArea)> + </WithStyles(ForwardRef(CardActionArea))> + </WithStyles(WithStyles(ForwardRef(CardActionArea)))> + </StyledCard> + </div> </KonnectorViewerList> </Provider> `; diff --git a/src/components/Konnector/konnectorModal.scss b/src/components/Konnector/konnectorModal.scss index f6fd4967003b641af2010af18788b5308d4f5726..e650b7c1eb45b084e5830f4cb7ec640617110f83 100644 --- a/src/components/Konnector/konnectorModal.scss +++ b/src/components/Konnector/konnectorModal.scss @@ -84,6 +84,25 @@ cursor: pointer; margin: 1rem auto 0.5rem; } + .commonErrorsList { + text-align: left; + span { + font-weight: 700; + &.gold { + color: $gold-shadow; + } + } + .center { + text-align: center; + font-weight: 700; + } + p { + text-align: center; + font-style: italic; + font-weight: 400; + font-size: 0.9rem; + } + } } } } diff --git a/src/components/Konnector/konnectorViewerList.scss b/src/components/Konnector/konnectorViewerList.scss index 4005432f3ca26f473d1689fdc87837cbcd3cb251..bb94bfef8f16e23af9058dbccff1244f001fa293 100644 --- a/src/components/Konnector/konnectorViewerList.scss +++ b/src/components/Konnector/konnectorViewerList.scss @@ -1,16 +1,21 @@ @import 'src/styles/base/color'; @import 'src/styles/base/breakpoint'; -button.connection-card { - height: 80px; - margin-bottom: 1rem; - &.electricity { - border: 1px solid var(--elecColor40); - } - &.gas { - border: 1px solid var(--gasColor40); - } - &.water { - border: 1px solid var(--waterColor40); +.konnectorsList { + display: flex; + flex-direction: column; + gap: 1rem; + padding-top: 1rem; + button.connection-card { + height: 80px; + &.electricity { + border: 1px solid var(--elecColor40); + } + &.gas { + border: 1px solid var(--gasColor40); + } + &.water { + border: 1px solid var(--waterColor40); + } } } diff --git a/src/components/Loader/Loader.spec.tsx b/src/components/Loader/Loader.spec.tsx index 231c5b013606758b577ee2be1abef4973f99fa88..91618983d037be9155a6d8a2d79f67b139c1741a 100644 --- a/src/components/Loader/Loader.spec.tsx +++ b/src/components/Loader/Loader.spec.tsx @@ -1,18 +1,8 @@ -import { FluidType } from 'enum/fluid.enum' +import { FluidType } from 'enums' import { mount } from 'enzyme' import React from 'react' import Loader from './Loader' -jest.mock('cozy-ui/transpiled/react/I18n', () => { - return { - useI18n: jest.fn(() => { - return { - t: (str: string) => str, - } - }), - } -}) - describe('Loader component', () => { it('should render base Loader', () => { const wrapper = mount(<Loader />) diff --git a/src/components/Loader/Loader.tsx b/src/components/Loader/Loader.tsx index aafdf086d332ed62c967778617929236e909714f..838a7c341ecd768a77f7c10c9f4225a77cdb327c 100644 --- a/src/components/Loader/Loader.tsx +++ b/src/components/Loader/Loader.tsx @@ -1,5 +1,5 @@ import { useI18n } from 'cozy-ui/transpiled/react/I18n' -import { FluidType } from 'enum/fluid.enum' +import { FluidType } from 'enums' import React from 'react' import './Loader.scss' diff --git a/src/components/Navbar/Navbar.spec.tsx b/src/components/Navbar/Navbar.spec.tsx index e9a446415d50e8c680620dd4f5983a41f2437f33..b457828e3ad1b908fe88acef7ac8fafdaa7a9e69 100644 --- a/src/components/Navbar/Navbar.spec.tsx +++ b/src/components/Navbar/Navbar.spec.tsx @@ -3,28 +3,11 @@ import { mount } from 'enzyme' import React from 'react' import { Provider } from 'react-redux' import { BrowserRouter } from 'react-router-dom' -import configureStore from 'redux-mock-store' -import { globalStateData } from '../../../tests/__mocks__/globalStateData.mock' - -jest.mock('cozy-ui/transpiled/react/I18n', () => { - return { - useI18n: jest.fn(() => { - return { - t: (str: string) => str, - } - }), - } -}) - -const mockStore = configureStore([]) +import { createMockEcolyoStore } from 'tests/__mocks__/store' describe('Navbar component', () => { it('should be rendered correctly with 5 navlink', () => { - const store = mockStore({ - ecolyo: { - global: globalStateData, - }, - }) + const store = createMockEcolyoStore() const wrapper = mount( <Provider store={store}> <BrowserRouter> @@ -36,15 +19,12 @@ describe('Navbar component', () => { }) it('should be rendered correctly with notifications', () => { - const store = mockStore({ - ecolyo: { - global: { - ...globalStateData, - challengeExplorationNotification: true, - challengeActionNotification: false, - challengeDuelNotification: false, - analysisNotification: true, - }, + const store = createMockEcolyoStore({ + global: { + challengeExplorationNotification: true, + challengeActionNotification: false, + challengeDuelNotification: false, + analysisNotification: true, }, }) const wrapper = mount( @@ -59,15 +39,12 @@ describe('Navbar component', () => { }) it('should be rendered correctly without notifications', () => { - const store = mockStore({ - ecolyo: { - global: { - ...globalStateData, - challengeExplorationNotification: false, - challengeActionNotification: false, - challengeDuelNotification: false, - analysisNotification: false, - }, + const store = createMockEcolyoStore({ + global: { + challengeExplorationNotification: false, + challengeActionNotification: false, + challengeDuelNotification: false, + analysisNotification: false, }, }) const wrapper = mount( diff --git a/src/components/Navbar/Navbar.tsx b/src/components/Navbar/Navbar.tsx index 8a67ad38cee09c38990f77aee618d032d6e77919..36095b762ece775ced72e22cd8ce94c45b7ea965 100644 --- a/src/components/Navbar/Navbar.tsx +++ b/src/components/Navbar/Navbar.tsx @@ -13,22 +13,21 @@ import logos from 'assets/png/logos_partenaires.svg' import StyledIcon from 'components/CommonKit/Icon/StyledIcon' import { useClient } from 'cozy-client' import { useI18n } from 'cozy-ui/transpiled/react/I18n' -import { UsageEventType } from 'enum/usageEvent.enum' +import { UsageEventType } from 'enums' import React, { useCallback } from 'react' -import { useSelector } from 'react-redux' import { NavLink, useLocation } from 'react-router-dom' import UsageEventService from 'services/usageEvent.service' -import { AppStore } from 'store' +import { useAppSelector } from 'store/hooks' import './navBar.scss' -export const Navbar = () => { +const Navbar = () => { const { t } = useI18n() const { challengeExplorationNotification, challengeActionNotification, challengeDuelNotification, analysisNotification, - } = useSelector((state: AppStore) => state.ecolyo.global) + } = useAppSelector(state => state.ecolyo.global) const { pathname } = useLocation() const client = useClient() @@ -41,6 +40,12 @@ export const Navbar = () => { }, [client] ) + + /** Return class "is-active" if pathname includes matcher */ + const isActive = (matcher: string) => { + return pathname.includes(matcher) ? 'is-active' : '' + } + return ( <aside className="o-sidebar"> <nav role="navigation" aria-label="navigation"> @@ -52,9 +57,7 @@ export const Navbar = () => { <Link component={NavLink} to="/consumption" - className={`c-nav-link ${ - pathname.includes('/consumption') ? 'is-active' : '' - }`} + className={`c-nav-link ${isActive('/consumption')}`} > <StyledIcon className="c-nav-icon off" icon={ConsoIconOff} /> <StyledIcon className="c-nav-icon on" icon={ConsoIconOn} /> @@ -65,9 +68,7 @@ export const Navbar = () => { <Link component={NavLink} to="/challenges" - className={`c-nav-link ${ - pathname.includes('/challenges') ? 'is-active' : '' - }`} + className={`c-nav-link ${isActive('/challenges')}`} > {(challengeExplorationNotification || challengeActionNotification || @@ -84,9 +85,7 @@ export const Navbar = () => { <Link component={NavLink} to="/ecogestures" - className={`c-nav-link ${ - pathname.includes('/ecogestures') ? 'is-active' : '' - }`} + className={`c-nav-link ${isActive('/ecogesture')}`} > <StyledIcon className="c-nav-icon off" icon={BulbIconOff} /> <StyledIcon className="c-nav-icon on" icon={BulbIconOn} /> @@ -111,9 +110,7 @@ export const Navbar = () => { <Link component={NavLink} to="/options" - className={`c-nav-link ${ - pathname.includes('/options') ? 'is-active' : '' - }`} + className={`c-nav-link ${isActive('/options')}`} > <StyledIcon className="c-nav-icon off" icon={ParameterIconOff} /> <StyledIcon className="c-nav-icon on" icon={ParameterIconOn} /> diff --git a/src/components/Options/ExportData/ExportData.spec.tsx b/src/components/Options/ExportData/ExportData.spec.tsx index ef4cf3cf380dee33473741923879b06f45d33c6b..3afe225cedebd2d113d6995bc6c510bd1b8c30c6 100644 --- a/src/components/Options/ExportData/ExportData.spec.tsx +++ b/src/components/Options/ExportData/ExportData.spec.tsx @@ -1,37 +1,15 @@ import { mount } from 'enzyme' import toJson from 'enzyme-to-json' import React from 'react' -import mockClient from '../../../../tests/__mocks__/client' - import ExportData from './ExportData' -jest.mock('cozy-ui/transpiled/react/I18n', () => { - return { - useI18n: jest.fn(() => { - return { - t: (str: string) => str, - } - }), - } -}) -const mockGetExportableFluids = jest.fn(() => { - return [] -}) jest.mock('services/consumption.service', () => { - return jest.fn(() => { - return { - fetchAllFirstDateData: jest.fn(() => { - return [null, null, null] - }), - getExportableFluids: mockGetExportableFluids, - } - }) + return jest.fn(() => ({ + fetchAllFirstDateData: jest.fn(() => [null, null, null]), + getFluidsWithData: jest.fn(() => []), + })) }) -jest.mock('cozy-client', () => ({ - useClient: () => mockClient, -})) - describe('exportOptions component', () => { it('should be rendered correctly', async () => { const wrapper = mount(<ExportData />) diff --git a/src/components/Options/ExportData/ExportData.tsx b/src/components/Options/ExportData/ExportData.tsx index 253a24355d001e2aa329fcd96bb618c83037a714..b0d620cf7c894674cd20ed3006bc1073d9f534f3 100644 --- a/src/components/Options/ExportData/ExportData.tsx +++ b/src/components/Options/ExportData/ExportData.tsx @@ -7,17 +7,16 @@ import { import chevronDown from 'assets/icons/ico/chevron-down.svg' import exportIcon from 'assets/icons/ico/export.svg' import classNames from 'classnames' -import ExportDoneModal from 'components/Export/exportDoneModal' -import ExportLoadingModal from 'components/Export/exportLoadingModal' -import ExportStartModal from 'components/Export/exportStartModal' import { useClient } from 'cozy-client' import { useI18n } from 'cozy-ui/transpiled/react/I18n' import Icon from 'cozy-ui/transpiled/react/Icon' -import { FluidType } from 'enum/fluid.enum' -import { TimeStep } from 'enum/timeStep.enum' +import { FluidType, TimeStep } from 'enums' import { remove } from 'lodash' import React, { useEffect, useMemo, useState } from 'react' import ConsumptionDataManager from 'services/consumption.service' +import ExportDoneModal from './Modals/exportDoneModal' +import ExportLoadingModal from './Modals/exportLoadingModal' +import ExportStartModal from './Modals/exportStartModal' import './exportData.scss' const ExportData = () => { @@ -55,11 +54,10 @@ const ExportData = () => { useEffect(() => { let subscribed = true const getExportableFluids = async () => { - const exportableFluidsData: FluidType[] = - await consumptionService.getExportableFluids( - [FluidType.ELECTRICITY, FluidType.WATER, FluidType.GAS], - TimeStep.MONTH - ) + const exportableFluidsData = await consumptionService.getFluidsWithData( + [FluidType.ELECTRICITY, FluidType.WATER, FluidType.GAS], + TimeStep.MONTH + ) setExportableFluids(exportableFluidsData) setAnswer(exportableFluidsData) subscribed = false @@ -82,13 +80,13 @@ const ExportData = () => { })} > <input - type={'checkbox'} + type="checkbox" value={fluidType} - name={t('FLUID.' + FluidType[fluidType] + '.LABEL')} + name={t(`FLUID.${FluidType[fluidType]}.LABEL`)} onChange={() => handleChange(fluidType)} checked={answer.includes(fluidType)} /> - {t('FLUID.' + FluidType[fluidType] + '.LABEL')} + {t(`FLUID.${FluidType[fluidType]}.LABEL`)} </label> )) diff --git a/src/components/Export/__snapshots__/exportDoneModal.spec.tsx.snap b/src/components/Options/ExportData/Modals/__snapshots__/exportDoneModal.spec.tsx.snap similarity index 100% rename from src/components/Export/__snapshots__/exportDoneModal.spec.tsx.snap rename to src/components/Options/ExportData/Modals/__snapshots__/exportDoneModal.spec.tsx.snap diff --git a/src/components/Export/__snapshots__/exportLoadingModal.spec.tsx.snap b/src/components/Options/ExportData/Modals/__snapshots__/exportLoadingModal.spec.tsx.snap similarity index 100% rename from src/components/Export/__snapshots__/exportLoadingModal.spec.tsx.snap rename to src/components/Options/ExportData/Modals/__snapshots__/exportLoadingModal.spec.tsx.snap diff --git a/src/components/Export/__snapshots__/exportStartModal.spec.tsx.snap b/src/components/Options/ExportData/Modals/__snapshots__/exportStartModal.spec.tsx.snap similarity index 100% rename from src/components/Export/__snapshots__/exportStartModal.spec.tsx.snap rename to src/components/Options/ExportData/Modals/__snapshots__/exportStartModal.spec.tsx.snap diff --git a/src/components/Export/exportDoneModal.scss b/src/components/Options/ExportData/Modals/exportDoneModal.scss similarity index 100% rename from src/components/Export/exportDoneModal.scss rename to src/components/Options/ExportData/Modals/exportDoneModal.scss diff --git a/src/components/Export/exportDoneModal.spec.tsx b/src/components/Options/ExportData/Modals/exportDoneModal.spec.tsx similarity index 71% rename from src/components/Export/exportDoneModal.spec.tsx rename to src/components/Options/ExportData/Modals/exportDoneModal.spec.tsx index b8d12e0a2c8561aea26f48e50859272502084683..a9e1c7f46cf09434129c0aebb7678baf80925d45 100644 --- a/src/components/Export/exportDoneModal.spec.tsx +++ b/src/components/Options/ExportData/Modals/exportDoneModal.spec.tsx @@ -1,28 +1,15 @@ import { Button } from '@material-ui/core' -import ExportDoneModal from 'components/Export/exportDoneModal' import { mount } from 'enzyme' import toJson from 'enzyme-to-json' import React from 'react' import { Provider } from 'react-redux' -import { createMockEcolyoStore } from '../../../tests/__mocks__/store' - -jest.mock('cozy-ui/transpiled/react/I18n', () => { - return { - useI18n: jest.fn(() => { - return { - t: (str: string) => str, - } - }), - } -}) +import { createMockEcolyoStore } from 'tests/__mocks__/store' +import ExportDoneModal from './exportDoneModal' const mockHandleClose = jest.fn() describe('exportDoneModal component', () => { const store = createMockEcolyoStore() - beforeEach(() => { - store.clearActions() - }) it('should be rendered correctly', () => { const wrapper = mount( @@ -39,7 +26,7 @@ describe('exportDoneModal component', () => { it('should display error message', () => undefined) - it('should close modal ', () => { + it('should close modal', () => { const wrapper = mount( <Provider store={store}> <ExportDoneModal diff --git a/src/components/Export/exportDoneModal.tsx b/src/components/Options/ExportData/Modals/exportDoneModal.tsx similarity index 96% rename from src/components/Export/exportDoneModal.tsx rename to src/components/Options/ExportData/Modals/exportDoneModal.tsx index 4ad5cc4015c3bf8283da9f482da4aec2457220f4..4bdfd90163d55d8834243bb206da7c095d803ed8 100644 --- a/src/components/Export/exportDoneModal.tsx +++ b/src/components/Options/ExportData/Modals/exportDoneModal.tsx @@ -25,13 +25,13 @@ const ExportDoneModal = ({ <Dialog open={open} onClose={handleCloseClick} - aria-labelledby={'accessibility-title'} + aria-labelledby="accessibility-title" classes={{ root: 'modal-root', paper: 'modal-paper', }} > - <div id={'accessibility-title'}> + <div id="accessibility-title"> {t('export.modal_done.accessibility_title')} </div> diff --git a/src/components/Export/exportLoadingModal.scss b/src/components/Options/ExportData/Modals/exportLoadingModal.scss similarity index 100% rename from src/components/Export/exportLoadingModal.scss rename to src/components/Options/ExportData/Modals/exportLoadingModal.scss diff --git a/src/components/Export/exportLoadingModal.spec.tsx b/src/components/Options/ExportData/Modals/exportLoadingModal.spec.tsx similarity index 70% rename from src/components/Export/exportLoadingModal.spec.tsx rename to src/components/Options/ExportData/Modals/exportLoadingModal.spec.tsx index 57534eb6592db6f7070dcdaac677b07ad8b3ba54..aeb7d672b21ee18090c1b972ac88de02543533b2 100644 --- a/src/components/Export/exportLoadingModal.spec.tsx +++ b/src/components/Options/ExportData/Modals/exportLoadingModal.spec.tsx @@ -1,30 +1,18 @@ import { Button } from '@material-ui/core' -import ExportLoadingModal from 'components/Export/exportLoadingModal' +import { FluidType } from 'enums' import { mount } from 'enzyme' import toJson from 'enzyme-to-json' import React from 'react' import { Provider } from 'react-redux' -import { createMockEcolyoStore } from '../../../tests/__mocks__/store' - -jest.mock('cozy-ui/transpiled/react/I18n', () => { - return { - useI18n: jest.fn(() => { - return { - t: (str: string) => str, - } - }), - } -}) +import { createMockEcolyoStore } from 'tests/__mocks__/store' +import ExportLoadingModal from './exportLoadingModal' const mockHandleClose = jest.fn() const mockHandleDone = jest.fn() -const mockSelectedFluids: Array<any> = [0, 1, 2] +const mockSelectedFluids: FluidType[] = [0, 1, 2] describe('ExportLoadingModal component', () => { const store = createMockEcolyoStore() - beforeEach(() => { - store.clearActions() - }) it('should be rendered correctly', () => { const wrapper = mount( @@ -40,7 +28,7 @@ describe('ExportLoadingModal component', () => { expect(toJson(wrapper)).toMatchSnapshot() }) - it('should cancel download ', () => { + it('should cancel download', () => { const wrapper = mount( <Provider store={store}> <ExportLoadingModal diff --git a/src/components/Export/exportLoadingModal.tsx b/src/components/Options/ExportData/Modals/exportLoadingModal.tsx similarity index 93% rename from src/components/Export/exportLoadingModal.tsx rename to src/components/Options/ExportData/Modals/exportLoadingModal.tsx index dfce4d8676e4c0a3abee26784e20da6033ba2b2b..edf47eb38f806d115074d1dac52c5dbbbee382cf 100644 --- a/src/components/Export/exportLoadingModal.tsx +++ b/src/components/Options/ExportData/Modals/exportLoadingModal.tsx @@ -9,8 +9,7 @@ import * as XLSX from 'xlsx' import CloseIcon from 'assets/icons/ico/close.svg' import Loader from 'components/Loader/Loader' -import { FluidType } from 'enum/fluid.enum' -import { TimeStep } from 'enum/timeStep.enum' +import { FluidType, TimeStep } from 'enums' import { Datachart, Dataload, TimePeriod } from 'models' import ConsumptionDataManager from 'services/consumption.service' import EnedisMonthlyAnalysisDataService from 'services/enedisMonthlyAnalysisData.service' @@ -71,7 +70,7 @@ const ExportLoadingModal = ({ dataRow[t('export.year')] = dataload.date.year dataRow[ `${t('export.consumption')} (${t( - 'FLUID.' + FluidType[fluidType] + '.UNIT' + `FLUID.${FluidType[fluidType]}.UNIT` )})` ] = dataload.value if (fluidType === FluidType.ELECTRICITY) { @@ -126,7 +125,7 @@ const ExportLoadingModal = ({ if (!dataLoad?.actualData) return null const exportDataSheet: ExportDataSheet = { - fluidName: t('FLUID.' + FluidType[fluidType] + '.LABEL'), + fluidName: t(`FLUID.${FluidType[fluidType]}.LABEL`), data: [], } diff --git a/src/components/Export/exportStartModal.scss b/src/components/Options/ExportData/Modals/exportStartModal.scss similarity index 88% rename from src/components/Export/exportStartModal.scss rename to src/components/Options/ExportData/Modals/exportStartModal.scss index 9f481c116266658ae05958a024366871e2632eaa..738f1c53cf9ad27db5f221870ae6825f6ef38850 100644 --- a/src/components/Export/exportStartModal.scss +++ b/src/components/Options/ExportData/Modals/exportStartModal.scss @@ -12,9 +12,11 @@ color: $gold-shadow; } .buttons { + margin-top: 2rem; display: flex; gap: 1rem; button { + margin: 0; height: 40px; } } diff --git a/src/components/Export/exportStartModal.spec.tsx b/src/components/Options/ExportData/Modals/exportStartModal.spec.tsx similarity index 72% rename from src/components/Export/exportStartModal.spec.tsx rename to src/components/Options/ExportData/Modals/exportStartModal.spec.tsx index d23c4598b958c6ab24b3576c5b82d47e5faaa872..f72defa44b9241920678f0a7e3b8be51a8f561ac 100644 --- a/src/components/Export/exportStartModal.spec.tsx +++ b/src/components/Options/ExportData/Modals/exportStartModal.spec.tsx @@ -1,29 +1,16 @@ import { Button } from '@material-ui/core' -import ExportStartModal from 'components/Export/exportStartModal' import { mount } from 'enzyme' import toJson from 'enzyme-to-json' import React from 'react' import { Provider } from 'react-redux' -import { createMockEcolyoStore } from '../../../tests/__mocks__/store' - -jest.mock('cozy-ui/transpiled/react/I18n', () => { - return { - useI18n: jest.fn(() => { - return { - t: (str: string) => str, - } - }), - } -}) +import { createMockEcolyoStore } from 'tests/__mocks__/store' +import ExportStartModal from './exportStartModal' const mockHandleClose = jest.fn() const mockHandleDownloadClick = jest.fn() describe('exportStartModal component', () => { const store = createMockEcolyoStore() - beforeEach(() => { - store.clearActions() - }) it('should be rendered correctly', () => { const wrapper = mount( @@ -38,7 +25,7 @@ describe('exportStartModal component', () => { expect(toJson(wrapper)).toMatchSnapshot() }) - it('should close modal ', () => { + it('should close modal', () => { const wrapper = mount( <Provider store={store}> <ExportStartModal diff --git a/src/components/Export/exportStartModal.tsx b/src/components/Options/ExportData/Modals/exportStartModal.tsx similarity index 96% rename from src/components/Export/exportStartModal.tsx rename to src/components/Options/ExportData/Modals/exportStartModal.tsx index f6c87e0beb6acf01a423d540ed0310d26182639b..1fbebcd06f7aa76eb1f9d1a82ab12415aa8b31f7 100644 --- a/src/components/Export/exportStartModal.tsx +++ b/src/components/Options/ExportData/Modals/exportStartModal.tsx @@ -24,13 +24,13 @@ const ExportStartModal = ({ <Dialog open={open} onClose={handleCloseClick} - aria-labelledby={'accessibility_title'} + aria-labelledby="accessibility_title" classes={{ root: 'modal-root', paper: 'modal-paper', }} > - <div id={'accessibility-title'}> + <div id="accessibility-title"> {t('export.modal_start.accessibility_title')} </div> <div className="modal-start-root"> diff --git a/src/components/Options/GCU/GCUContent.spec.tsx b/src/components/Options/GCU/GCUContent.spec.tsx index f7480cd76e1780e54a5cd5e26834b39939143397..2bc41f57b908daa0b20931d8a48be0fef4720aa2 100644 --- a/src/components/Options/GCU/GCUContent.spec.tsx +++ b/src/components/Options/GCU/GCUContent.spec.tsx @@ -2,29 +2,9 @@ import GCUContent from 'components/Options/GCU/GCUContent' import { shallow } from 'enzyme' import React from 'react' -jest.mock('cozy-ui/transpiled/react/I18n', () => { - return { - useI18n: jest.fn(() => { - return { - t: (str: string) => { - if (str === 'gcu.content.part9_4_content') { - return 'test <a href="link.com">link</a>fin test' - } else { - return str - } - }, - } - }), - } -}) - describe('GCUContent component', () => { it('should be rendered correctly', () => { const component = shallow(<GCUContent />).getElement() expect(component).toMatchSnapshot() }) - it('should display a link when translation contains <a href=""></a>', () => { - const component = shallow(<GCUContent />).getElement() - expect(component).toMatchSnapshot() - }) }) diff --git a/src/components/Options/GCU/GCUContent.tsx b/src/components/Options/GCU/GCUContent.tsx index 1ecb3fcc6d3cc0eb9387d219dc1daa27add51278..e15457d091369bf4469a944c6b44d819f04422e1 100644 --- a/src/components/Options/GCU/GCUContent.tsx +++ b/src/components/Options/GCU/GCUContent.tsx @@ -1,6 +1,5 @@ import { useI18n } from 'cozy-ui/transpiled/react/I18n' import React from 'react' -import { decoreText } from 'utils/decoreText' import './gcuContent.scss' const GCUContent = (): JSX.Element => { @@ -39,7 +38,10 @@ const GCUContent = (): JSX.Element => { {t('gcu.content.title4')} </div> <p className="text-14-normal">{t('gcu.content.part4_1')}</p> - <p className="text-14-normal">{decoreText(t('gcu.content.part4_2'))}</p> + <p + className="text-14-normal" + dangerouslySetInnerHTML={{ __html: t('gcu.content.part4_2') }} + /> <div className="gcu-content-part-title text-15-normal"> {t('gcu.content.title5')} </div> @@ -69,7 +71,10 @@ const GCUContent = (): JSX.Element => { {t('gcu.content.title8')} </div> <p className="text-14-normal">{t('gcu.content.part8_1')}</p> - <p className="text-14-normal">{decoreText(t('gcu.content.part8_2'))}</p> + <p + className="text-14-normal" + dangerouslySetInnerHTML={{ __html: t('gcu.content.part8_2') }} + /> <div className="gcu-content-part-title text-15-normal"> {t('gcu.content.title9')} </div> @@ -87,7 +92,11 @@ const GCUContent = (): JSX.Element => { </p> <p className="text-14-normal"> <span className="text-14-bold">{t('gcu.content.part9_4_title')}</span> - <span>{decoreText(t('gcu.content.part9_4_content'))}</span> + <span + dangerouslySetInnerHTML={{ + __html: t('gcu.content.part9_4_content'), + }} + /> </p> <p className="text-14-normal"> <span className="text-14-bold">{t('gcu.content.part9_5_title')}</span> diff --git a/src/components/Options/GCU/GCULink.spec.tsx b/src/components/Options/GCU/GCULink.spec.tsx index cf64c957da4db31d4223ace43ded22753cb9d094..f3cb6b4f33f294ff4767901ceafbf2aa58280998 100644 --- a/src/components/Options/GCU/GCULink.spec.tsx +++ b/src/components/Options/GCU/GCULink.spec.tsx @@ -2,16 +2,6 @@ import LegalNoticeLink from 'components/Options/LegalNotice/LegalNoticeLink' import { shallow } from 'enzyme' import React from 'react' -jest.mock('cozy-ui/transpiled/react/I18n', () => { - return { - useI18n: jest.fn(() => { - return { - t: (str: string) => str, - } - }), - } -}) - describe('LegalNoticeLink component', () => { it('should be rendered correctly', () => { const component = shallow(<LegalNoticeLink />).getElement() diff --git a/src/components/Options/GCU/GCUView.tsx b/src/components/Options/GCU/GCUView.tsx index 999dd89a81f7d9e778f1b4d088eb1839b2e6a73f..d5d525e538062eb138d3f08c670643efef9337c3 100644 --- a/src/components/Options/GCU/GCUView.tsx +++ b/src/components/Options/GCU/GCUView.tsx @@ -2,24 +2,20 @@ import Content from 'components/Content/Content' import CozyBar from 'components/Header/CozyBar' import Header from 'components/Header/Header' import GCUContent from 'components/Options/GCU/GCUContent' -import React, { useCallback, useState } from 'react' +import React, { useState } from 'react' const GCUView = () => { const [headerHeight, setHeaderHeight] = useState<number>(0) - const defineHeaderHeight = useCallback((height: number) => { - setHeaderHeight(height) - }, []) - return ( <> - <CozyBar titleKey={'common.title_gcu'} displayBackArrow={true} /> + <CozyBar titleKey="common.title_gcu" displayBackArrow={true} /> <Header - setHeaderHeight={defineHeaderHeight} - desktopTitleKey={'common.title_gcu'} + setHeaderHeight={setHeaderHeight} + desktopTitleKey="common.title_gcu" displayBackArrow={true} /> - <Content height={headerHeight}> + <Content heightOffset={headerHeight}> <GCUContent /> </Content> </> diff --git a/src/components/Options/GCU/__snapshots__/GCUContent.spec.tsx.snap b/src/components/Options/GCU/__snapshots__/GCUContent.spec.tsx.snap index 007cca08c725d8850df473c4f4c49142a34f2de1..93d8846db6808891dfce8569b1bb4924ef66289c 100644 --- a/src/components/Options/GCU/__snapshots__/GCUContent.spec.tsx.snap +++ b/src/components/Options/GCU/__snapshots__/GCUContent.spec.tsx.snap @@ -107,9 +107,12 @@ exports[`GCUContent component should be rendered correctly 1`] = ` </p> <p className="text-14-normal" - > - gcu.content.part4_2 - </p> + dangerouslySetInnerHTML={ + Object { + "__html": "gcu.content.part4_2", + } + } + /> <div className="gcu-content-part-title text-15-normal" > @@ -205,9 +208,12 @@ exports[`GCUContent component should be rendered correctly 1`] = ` </p> <p className="text-14-normal" - > - gcu.content.part8_2 - </p> + dangerouslySetInnerHTML={ + Object { + "__html": "gcu.content.part8_2", + } + } + /> <div className="gcu-content-part-title text-15-normal" > @@ -257,306 +263,13 @@ exports[`GCUContent component should be rendered correctly 1`] = ` > gcu.content.part9_4_title </span> - <span> - <React.Fragment> - test - <a - href="link.com" - rel="noopener noreferrer" - target="_blank" - > - link - </a> - fin test - </React.Fragment> - </span> - </p> - <p - className="text-14-normal" - > - <span - className="text-14-bold" - > - gcu.content.part9_5_title - </span> - <span> - gcu.content.part9_5_content - </span> - </p> - </div> -</div> -`; - -exports[`GCUContent component should display a link when translation contains <a href=""></a> 1`] = ` -<div - className="gcu-content-root" -> - <div - className="gcu-content-wrapper" - > - <p - className="text-14-normal version" - > - gcu.version - </p> - <div - className="gcu-content-part-title text-15-normal" - > - gcu.content.title1 - </div> - <p - className="text-14-normal" - > - gcu.content.part1_1 - </p> - <p - className="text-14-normal" - > - gcu.content.part1_2 - </p> - <p - className="text-14-normal" - > - gcu.content.part1_3 - </p> - <div - className="gcu-content-part-title text-15-normal" - > - gcu.content.title2 - </div> - <p - className="text-14-normal" - > - gcu.content.part2_1 - </p> - <p - className="text-14-normal" - > - gcu.content.part2_2 - </p> - <ul - className="text-14-normal" - > - <li> - gcu.content.part2_2_list1 - </li> - <li> - gcu.content.part2_2_list2 - </li> - <li> - gcu.content.part2_2_list3 - </li> - </ul> - <p - className="text-14-normal" - > - gcu.content.part2_3 - </p> - <p - className="text-14-normal" - > - gcu.content.part2_4 - </p> - <div - className="gcu-content-part-title text-15-normal" - > - gcu.content.title3 - </div> - <p - className="text-14-normal" - > - gcu.content.part3_1 - </p> - <p - className="text-14-normal" - > - gcu.content.part3_2 - </p> - <p - className="text-14-normal" - > - gcu.content.part3_3 - </p> - <p - className="text-14-normal" - > - gcu.content.part3_4 - </p> - <div - className="gcu-content-part-title text-15-normal" - > - gcu.content.title4 - </div> - <p - className="text-14-normal" - > - gcu.content.part4_1 - </p> - <p - className="text-14-normal" - > - gcu.content.part4_2 - </p> - <div - className="gcu-content-part-title text-15-normal" - > - gcu.content.title5 - </div> - <p - className="text-14-normal" - > - gcu.content.part5_1 - </p> - <p - className="text-14-normal" - > - gcu.content.part5_2 - </p> - <p - className="text-14-normal" - > - gcu.content.part5_3 - </p> - <ul - className="text-14-normal" - > - <li> - gcu.content.part5_3_list1 - </li> - <li> - gcu.content.part5_3_list2 - </li> - </ul> - <p - className="text-14-normal" - > - gcu.content.part5_4 - </p> - <p - className="text-14-normal" - > - gcu.content.part5_5 - </p> - <div - className="gcu-content-part-title text-15-normal" - > - gcu.content.title6 - </div> - <p - className="text-14-normal" - > - gcu.content.part6_1 - </p> - <p - className="text-14-normal" - > - gcu.content.part6_2 - </p> - <p - className="text-14-normal" - > - gcu.content.part6_3 - </p> - <ul - className="text-14-normal" - > - <li> - gcu.content.part6_3_list1 - </li> - <li> - gcu.content.part6_3_list2 - </li> - <li> - gcu.content.part6_3_list3 - </li> - </ul> - <p - className="text-14-normal" - > - gcu.content.part6_4 - </p> - <p - className="text-14-normal" - > - gcu.content.part6_5 - </p> - <div - className="gcu-content-part-title text-15-normal" - > - gcu.content.title8 - </div> - <p - className="text-14-normal" - > - gcu.content.part8_1 - </p> - <p - className="text-14-normal" - > - gcu.content.part8_2 - </p> - <div - className="gcu-content-part-title text-15-normal" - > - gcu.content.title9 - </div> - <p - className="text-14-normal" - > - <span - className="text-14-bold" - > - gcu.content.part9_1_title - </span> - <span> - gcu.content.part9_1_content - </span> - </p> - <p - className="text-14-normal" - > - <span - className="text-14-bold" - > - gcu.content.part9_2_title - </span> - <span> - gcu.content.part9_2_content - </span> - </p> - <p - className="text-14-normal" - > - <span - className="text-14-bold" - > - gcu.content.part9_3_title - </span> - <span> - gcu.content.part9_3_content - </span> - </p> - <p - className="text-14-normal" - > <span - className="text-14-bold" - > - gcu.content.part9_4_title - </span> - <span> - <React.Fragment> - test - <a - href="link.com" - rel="noopener noreferrer" - target="_blank" - > - link - </a> - fin test - </React.Fragment> - </span> + dangerouslySetInnerHTML={ + Object { + "__html": "gcu.content.part9_4_content", + } + } + /> </p> <p className="text-14-normal" diff --git a/src/components/Options/GCU/__snapshots__/GCUView.spec.tsx.snap b/src/components/Options/GCU/__snapshots__/GCUView.spec.tsx.snap index bcc93b8a7020797f0037ffa7d0db41ef8be7f3e6..da0d5940a8758e3b30a5de6b21f6bcc5fcede716 100644 --- a/src/components/Options/GCU/__snapshots__/GCUView.spec.tsx.snap +++ b/src/components/Options/GCU/__snapshots__/GCUView.spec.tsx.snap @@ -12,7 +12,7 @@ exports[`GCUView component should be rendered correctly 1`] = ` setHeaderHeight={[Function]} /> <mock-content - height={0} + heightOffset={0} > <GCUContent /> </mock-content> diff --git a/src/components/Options/HelpLink/HelpLink.tsx b/src/components/Options/HelpLink/HelpLink.tsx index d463ce5213c874808dce1bed554589738d594d68..3a1c82dd69eadb534edc582e629c39d1548b6ce0 100644 --- a/src/components/Options/HelpLink/HelpLink.tsx +++ b/src/components/Options/HelpLink/HelpLink.tsx @@ -2,15 +2,14 @@ import Link from '@material-ui/core/Link' import QuestionMarkIcon from 'assets/icons/ico/questionMark.svg' import StyledIcon from 'components/CommonKit/Icon/StyledIcon' import { useI18n } from 'cozy-ui/transpiled/react/I18n' -import React, { Dispatch } from 'react' -import { useDispatch } from 'react-redux' -import { AppActionsTypes } from 'store' +import React from 'react' +import { useAppDispatch } from 'store/hooks' import { openFeedbackModal } from 'store/modal/modal.slice' import './HelpLink.scss' const HelpLink = () => { const { t } = useI18n() - const dispatch = useDispatch<Dispatch<AppActionsTypes>>() + const dispatch = useAppDispatch() return ( <div diff --git a/src/components/Options/LegalNotice/LegalNoticeContent.spec.tsx b/src/components/Options/LegalNotice/LegalNoticeContent.spec.tsx index ed6459952bfe193088413580e22590772e697415..55cbffee7411bb30bd48c38f9dce6e0d059c8cc7 100644 --- a/src/components/Options/LegalNotice/LegalNoticeContent.spec.tsx +++ b/src/components/Options/LegalNotice/LegalNoticeContent.spec.tsx @@ -2,16 +2,6 @@ import LegalNoticeContent from 'components/Options/LegalNotice/LegalNoticeConten import { shallow } from 'enzyme' import React from 'react' -jest.mock('cozy-ui/transpiled/react/I18n', () => { - return { - useI18n: jest.fn(() => { - return { - t: (str: string) => str, - } - }), - } -}) - describe('LegalNoticeContent component', () => { it('should be rendered correctly', () => { const component = shallow(<LegalNoticeContent />).getElement() diff --git a/src/components/Options/LegalNotice/LegalNoticeContent.tsx b/src/components/Options/LegalNotice/LegalNoticeContent.tsx index eba23d5b0b9e5b79016ca01453e24d9aa6298068..86b3c385fd6a79d691ba9f302801f2fcb8237514 100644 --- a/src/components/Options/LegalNotice/LegalNoticeContent.tsx +++ b/src/components/Options/LegalNotice/LegalNoticeContent.tsx @@ -1,6 +1,5 @@ import { useI18n } from 'cozy-ui/transpiled/react/I18n' import React from 'react' -import { decoreText } from 'utils/decoreText' import './legalNoticeView.scss' const LegalNoticeContent = () => { @@ -10,10 +9,13 @@ const LegalNoticeContent = () => { <div className="legal-notice-root"> <div className="legal-notice-content"> <p className="version">{t('legal.version')}</p> - <p>{decoreText(t('legal.site'))}</p> + <p dangerouslySetInnerHTML={{ __html: t('legal.site') }} /> <p>{t('legal.adress')}</p> <p>{t('legal.phone')}</p> - <p className="ln-contact">{decoreText(t('legal.mail'))}</p> + <p + className="ln-contact" + dangerouslySetInnerHTML={{ __html: t('legal.mail') }} + /> <div className="text-16-normal"> <div className="legal-notice-oneline"> <span className="text-14-normal">{t('legal.p1b')}</span> @@ -56,7 +58,9 @@ const LegalNoticeContent = () => { <li>{t('legal.part2-3-2')}</li> <li>{t('legal.part2-3-3')}</li> <li>{t('legal.part2-3-4')}</li> - <li>{decoreText(t('legal.part2-3-5'))}</li> + <li + dangerouslySetInnerHTML={{ __html: t('legal.part2-3-5') }} + /> </ul> </li> <li>{t('legal.part2-4')}</li> @@ -68,10 +72,10 @@ const LegalNoticeContent = () => { <li>{t('legal.part2-6-2')}</li> <li>{t('legal.part2-6-3')}</li> </ul> - <p>{decoreText(t('legal.part2-7'))}</p> + <p dangerouslySetInnerHTML={{ __html: t('legal.part2-7') }} /> <p>{t('legal.part2-8')}</p> <p>{t('legal.part2-9')}</p> - <p>{decoreText(t('legal.part2-10'))}</p> + <p dangerouslySetInnerHTML={{ __html: t('legal.part2-10') }} /> <p>{t('legal.part2-11')}</p> </div> <div className="legal-notice-part"> @@ -95,7 +99,7 @@ const LegalNoticeContent = () => { <div className="legal-notice-part"> <h3>{t('legal.title7')}</h3> <p>{t('legal.part7-1')}</p> - <p>{decoreText(t('legal.part7-2'))}</p> + <p dangerouslySetInnerHTML={{ __html: t('legal.part7-2') }} /> <p>{t('legal.part7-3')}</p> </div> <div className="legal-notice-part"> diff --git a/src/components/Options/LegalNotice/LegalNoticeLink.spec.tsx b/src/components/Options/LegalNotice/LegalNoticeLink.spec.tsx index dcea071586f5b63f1e8e1dcdcfd9ee0e1956bcd6..190508b0a3b43e85ffa0c7ce0d07a6d65012fdc1 100644 --- a/src/components/Options/LegalNotice/LegalNoticeLink.spec.tsx +++ b/src/components/Options/LegalNotice/LegalNoticeLink.spec.tsx @@ -2,16 +2,6 @@ import GCULink from 'components/Options/GCU/GCULink' import { shallow } from 'enzyme' import React from 'react' -jest.mock('cozy-ui/transpiled/react/I18n', () => { - return { - useI18n: jest.fn(() => { - return { - t: (str: string) => str, - } - }), - } -}) - describe('GCULink component', () => { it('should be rendered correctly', () => { const component = shallow(<GCULink />).getElement() diff --git a/src/components/Options/LegalNotice/LegalNoticeLink.tsx b/src/components/Options/LegalNotice/LegalNoticeLink.tsx index 5475686d5866eff333af781dbb4262a6f68c646e..cdd71ce7026fb051fc40b6660fa0b8d1b10e934d 100644 --- a/src/components/Options/LegalNotice/LegalNoticeLink.tsx +++ b/src/components/Options/LegalNotice/LegalNoticeLink.tsx @@ -3,7 +3,7 @@ import LegalNoticeIcon from 'assets/icons/ico/legal-notice.svg' import StyledIcon from 'components/CommonKit/Icon/StyledIcon' import { useClient } from 'cozy-client' import { useI18n } from 'cozy-ui/transpiled/react/I18n' -import { UsageEventType } from 'enum/usageEvent.enum' +import { UsageEventType } from 'enums' import React, { useCallback } from 'react' import { Link as RouterLink } from 'react-router-dom' import UsageEventService from 'services/usageEvent.service' diff --git a/src/components/Options/LegalNotice/LegalNoticeView.tsx b/src/components/Options/LegalNotice/LegalNoticeView.tsx index cd7b6723a5498a27ed20706681863cee96b2e2b9..4c68ee2a1b48cca408a1cae207e24ca4464cd182 100644 --- a/src/components/Options/LegalNotice/LegalNoticeView.tsx +++ b/src/components/Options/LegalNotice/LegalNoticeView.tsx @@ -1,25 +1,22 @@ import Content from 'components/Content/Content' import CozyBar from 'components/Header/CozyBar' import Header from 'components/Header/Header' -import React, { useCallback, useState } from 'react' +import React, { useState } from 'react' import LegalNoticeContent from './LegalNoticeContent' import './legalNoticeView.scss' const LegalNoticeView = () => { const [headerHeight, setHeaderHeight] = useState<number>(0) - const defineHeaderHeight = useCallback((height: number) => { - setHeaderHeight(height) - }, []) return ( <> - <CozyBar titleKey={'common.title_legal_notice'} displayBackArrow={true} /> + <CozyBar titleKey="common.title_legal_notice" displayBackArrow={true} /> <Header - setHeaderHeight={defineHeaderHeight} - desktopTitleKey={'common.title_legal_notice'} + setHeaderHeight={setHeaderHeight} + desktopTitleKey="common.title_legal_notice" displayBackArrow={true} /> - <Content height={headerHeight}> + <Content heightOffset={headerHeight}> <LegalNoticeContent /> </Content> </> diff --git a/src/components/Options/LegalNotice/__snapshots__/LegalNoticeContent.spec.tsx.snap b/src/components/Options/LegalNotice/__snapshots__/LegalNoticeContent.spec.tsx.snap index 69a5b05402c63a1db03028dd805a630148bf4493..322cf9fb612ba9ab88be218725372d23a485eaba 100644 --- a/src/components/Options/LegalNotice/__snapshots__/LegalNoticeContent.spec.tsx.snap +++ b/src/components/Options/LegalNotice/__snapshots__/LegalNoticeContent.spec.tsx.snap @@ -13,9 +13,13 @@ exports[`LegalNoticeContent component should be rendered correctly 1`] = ` > legal.version </p> - <p> - legal.site - </p> + <p + dangerouslySetInnerHTML={ + Object { + "__html": "legal.site", + } + } + /> <p> legal.adress </p> @@ -24,9 +28,12 @@ exports[`LegalNoticeContent component should be rendered correctly 1`] = ` </p> <p className="ln-contact" - > - legal.mail - </p> + dangerouslySetInnerHTML={ + Object { + "__html": "legal.mail", + } + } + /> <div className="text-16-normal" > @@ -132,9 +139,13 @@ exports[`LegalNoticeContent component should be rendered correctly 1`] = ` <li> legal.part2-3-4 </li> - <li> - legal.part2-3-5 - </li> + <li + dangerouslySetInnerHTML={ + Object { + "__html": "legal.part2-3-5", + } + } + /> </ul> </li> <li> @@ -158,18 +169,26 @@ exports[`LegalNoticeContent component should be rendered correctly 1`] = ` legal.part2-6-3 </li> </ul> - <p> - legal.part2-7 - </p> + <p + dangerouslySetInnerHTML={ + Object { + "__html": "legal.part2-7", + } + } + /> <p> legal.part2-8 </p> <p> legal.part2-9 </p> - <p> - legal.part2-10 - </p> + <p + dangerouslySetInnerHTML={ + Object { + "__html": "legal.part2-10", + } + } + /> <p> legal.part2-11 </p> @@ -229,9 +248,13 @@ exports[`LegalNoticeContent component should be rendered correctly 1`] = ` <p> legal.part7-1 </p> - <p> - legal.part7-2 - </p> + <p + dangerouslySetInnerHTML={ + Object { + "__html": "legal.part7-2", + } + } + /> <p> legal.part7-3 </p> diff --git a/src/components/Options/LegalNotice/__snapshots__/LegalNoticeView.spec.tsx.snap b/src/components/Options/LegalNotice/__snapshots__/LegalNoticeView.spec.tsx.snap index 52b42634ccd99ef5cc0458c03738dcb536858289..e3e3b81e15207a38e46063d71dbfbf700c247024 100644 --- a/src/components/Options/LegalNotice/__snapshots__/LegalNoticeView.spec.tsx.snap +++ b/src/components/Options/LegalNotice/__snapshots__/LegalNoticeView.spec.tsx.snap @@ -12,7 +12,7 @@ exports[`LegalNoticeView component should be rendered correctly 1`] = ` setHeaderHeight={[Function]} /> <mock-content - height={0} + heightOffset={0} > <LegalNoticeContent /> </mock-content> diff --git a/src/components/Options/MatomoOptOut/MatomoOptOut.spec.tsx b/src/components/Options/MatomoOptOut/MatomoOptOut.spec.tsx index c74c68c3b5a31ece0daaf62befb2bc232697559a..ad9864f10b2466b2e313d4f6228a5033dd9d8294 100644 --- a/src/components/Options/MatomoOptOut/MatomoOptOut.spec.tsx +++ b/src/components/Options/MatomoOptOut/MatomoOptOut.spec.tsx @@ -2,16 +2,6 @@ import { shallow } from 'enzyme' import React from 'react' import MatomoOptOut from './MatomoOptOut' -jest.mock('cozy-ui/transpiled/react/I18n', () => { - return { - useI18n: jest.fn(() => { - return { - t: (str: string) => str, - } - }), - } -}) - describe('MatomoOptOut component', () => { it('should be rendered correctly', () => { const component = shallow(<MatomoOptOut />).getElement() diff --git a/src/components/Options/OptionsView.tsx b/src/components/Options/OptionsView.tsx index baf6819f2a0d51d74d764ef10397e1041f650cc2..8da4b6a0fb4b806e59c4fd3fd206f89c00333724 100644 --- a/src/components/Options/OptionsView.tsx +++ b/src/components/Options/OptionsView.tsx @@ -15,18 +15,15 @@ import Version from './Version/Version' const OptionsView = () => { const [headerHeight, setHeaderHeight] = useState<number>(0) - const defineHeaderHeight = (height: number) => { - setHeaderHeight(height) - } return ( <> - <CozyBar titleKey={'common.title_options'} /> + <CozyBar titleKey="common.title_options" /> <Header - setHeaderHeight={defineHeaderHeight} - desktopTitleKey={'common.title_options'} + setHeaderHeight={setHeaderHeight} + desktopTitleKey="common.title_options" /> - <Content height={headerHeight}> + <Content heightOffset={headerHeight}> <ProfileTypeOptions /> <ExportData /> <ReportOptions /> diff --git a/src/components/Options/ProfileTypeOptions/ProfileTypeOptions.spec.tsx b/src/components/Options/ProfileTypeOptions/ProfileTypeOptions.spec.tsx index 5189e961c095c86d7a12caa2dfd504ab2f2fa399..6bbdb5dc30564e920ce41dad76e9924daaf21e1c 100644 --- a/src/components/Options/ProfileTypeOptions/ProfileTypeOptions.spec.tsx +++ b/src/components/Options/ProfileTypeOptions/ProfileTypeOptions.spec.tsx @@ -7,41 +7,20 @@ import { IndividualInsulationWork, IndividualOrCollective, ThreeChoicesAnswer, -} from 'enum/profileType.enum' +} from 'enums' import { mount } from 'enzyme' import React from 'react' import { Provider } from 'react-redux' -import configureStore from 'redux-mock-store' -import { profileData } from '../../../../tests/__mocks__/profileData.mock' -import { mockProfileType } from '../../../../tests/__mocks__/profileType.mock' -import { mockInitialChallengeState } from '../../../../tests/__mocks__/store' - -jest.mock('cozy-ui/transpiled/react/I18n', () => { - return { - useI18n: jest.fn(() => { - return { - t: (str: string) => str, - } - }), - } -}) -const mockedNavigate = jest.fn() -jest.mock('react-router-dom', () => ({ - ...jest.requireActual('react-router-dom'), - useNavigate: () => mockedNavigate, -})) - -const mockStore = configureStore([]) +import { mockProfileType } from 'tests/__mocks__/profileType.mock' +import { + createMockEcolyoStore, + mockChallengeState, + mockProfileState, +} from 'tests/__mocks__/store' describe('ProfileTypeOptions component', () => { + const store = createMockEcolyoStore() it('should be rendered correctly', () => { - const store = mockStore({ - ecolyo: { - profile: profileData, - profileType: mockProfileType, - challenge: mockInitialChallengeState, - }, - }) const wrapper = mount( <Provider store={store}> <ProfileTypeOptions /> @@ -53,15 +32,10 @@ describe('ProfileTypeOptions component', () => { wrapper.find('.profile-link').first().simulate('click') }) it('should be rendered when user complete profile type form', () => { - const profileTypeCompleted = { ...profileData } - const profileTypeData = { ...mockProfileType } - profileTypeCompleted.isProfileTypeCompleted = true - const store = mockStore({ - ecolyo: { - profile: profileTypeCompleted, - profileType: profileTypeData, - challenge: mockInitialChallengeState, - }, + const store = createMockEcolyoStore({ + profile: { ...mockProfileState, isProfileTypeCompleted: true }, + profileType: mockProfileType, + challenge: mockChallengeState, }) const wrapper = mount( <Provider store={store}> @@ -71,16 +45,10 @@ describe('ProfileTypeOptions component', () => { expect(wrapper.find('.profile-container').exists()).toBeTruthy() }) it('should be rendered when housing_type = apartment', () => { - const profileTypeCompleted = { ...profileData } - const profileTypeData = { ...mockProfileType } - profileTypeCompleted.isProfileTypeCompleted = true - profileTypeData.housingType = HousingType.APARTMENT - const store = mockStore({ - ecolyo: { - profile: profileTypeCompleted, - profileType: profileTypeData, - challenge: mockInitialChallengeState, - }, + const store = createMockEcolyoStore({ + profile: { ...mockProfileState, isProfileTypeCompleted: true }, + profileType: { ...mockProfileType, housingType: HousingType.APARTMENT }, + challenge: mockChallengeState, }) const wrapper = mount( <Provider store={store}> @@ -90,22 +58,16 @@ describe('ProfileTypeOptions component', () => { expect(wrapper.find('.floor').exists()).toBeTruthy() }) it('should display heating with equipments', () => { - const profileTypeCompleted = { - ...profileData, - } - const profileTypeData = { ...mockProfileType } - - profileTypeData.heating = IndividualOrCollective.INDIVIDUAL - profileTypeCompleted.isProfileTypeCompleted = true - profileTypeData.housingType = HousingType.APARTMENT - profileTypeData.hasInstalledVentilation = ThreeChoicesAnswer.YES - profileTypeData.hasReplacedHeater = ThreeChoicesAnswer.YES - const store = mockStore({ - ecolyo: { - profile: profileTypeCompleted, - profileType: profileTypeData, - challenge: mockInitialChallengeState, + const store = createMockEcolyoStore({ + profile: { ...mockProfileState, isProfileTypeCompleted: true }, + profileType: { + ...mockProfileType, + heating: IndividualOrCollective.INDIVIDUAL, + housingType: HousingType.APARTMENT, + hasInstalledVentilation: ThreeChoicesAnswer.YES, + hasReplacedHeater: ThreeChoicesAnswer.YES, }, + challenge: mockChallengeState, }) const wrapper = mount( <Provider store={store}> @@ -115,23 +77,20 @@ describe('ProfileTypeOptions component', () => { expect(wrapper.find('.equipments').exists()).toBeTruthy() }) it('should display insulation work', () => { - const profileTypeCompleted = { - ...profileData, - } - const profileTypeData = { ...mockProfileType } - - profileTypeCompleted.isProfileTypeCompleted = true - profileTypeData.housingType = HousingType.APARTMENT - profileTypeData.individualInsulationWork = [ - IndividualInsulationWork.ROOF_INSULATION, - IndividualInsulationWork.WINDOW_REPLACEMENT, - ] - const store = mockStore({ - ecolyo: { - profile: profileTypeCompleted, - profileType: profileTypeData, - challenge: mockInitialChallengeState, + const store = createMockEcolyoStore({ + profile: { + ...mockProfileState, + isProfileTypeCompleted: true, + }, + profileType: { + ...mockProfileType, + housingType: HousingType.APARTMENT, + individualInsulationWork: [ + IndividualInsulationWork.ROOF_INSULATION, + IndividualInsulationWork.WINDOW_REPLACEMENT, + ], }, + challenge: mockChallengeState, }) const wrapper = mount( <Provider store={store}> diff --git a/src/components/Options/ProfileTypeOptions/ProfileTypeOptions.tsx b/src/components/Options/ProfileTypeOptions/ProfileTypeOptions.tsx index 79fab17416acdb05de78815e3c60dd48b7cd7a29..1648f83c82ee3642a9cb3b8687d5fa15d9b35538 100644 --- a/src/components/Options/ProfileTypeOptions/ProfileTypeOptions.tsx +++ b/src/components/Options/ProfileTypeOptions/ProfileTypeOptions.tsx @@ -11,24 +11,21 @@ import StyledIcon from 'components/CommonKit/Icon/StyledIcon' import useExploration from 'components/Hooks/useExploration' import { useI18n } from 'cozy-ui/transpiled/react/I18n' import Icon from 'cozy-ui/transpiled/react/Icon' -import { FluidType } from 'enum/fluid.enum' import { + FluidType, HousingType, IndividualOrCollective, OutsideFacingWalls, ThreeChoicesAnswer, -} from 'enum/profileType.enum' -import { UserExplorationID } from 'enum/userExploration.enum' -import React, { useCallback, useState } from 'react' -import { useSelector } from 'react-redux' + UserExplorationID, +} from 'enums' +import React, { useState } from 'react' import { useNavigate } from 'react-router-dom' -import { AppStore } from 'store' +import { useAppSelector } from 'store/hooks' import './profileTypeOptions.scss' const ProfileTypeOptions = () => { - const { profile, profileType } = useSelector( - (state: AppStore) => state.ecolyo - ) + const { profile, profileType } = useAppSelector(state => state.ecolyo) const { t } = useI18n() const navigate = useNavigate() const [, setValidExploration] = useExploration() @@ -41,9 +38,9 @@ const ProfileTypeOptions = () => { setActive(prev => !prev) } - const goToForm = useCallback(() => { + const goToForm = () => { navigate('/profileType') - }, [navigate]) + } return ( <div className="profile-type-root"> diff --git a/src/components/Options/ReportOptions/ReportOptions.spec.tsx b/src/components/Options/ReportOptions/ReportOptions.spec.tsx index baaeff3f3d1591037497778c6148ee9c0119c277..8794bd7e8cf8a8e05393ca4e916b8b6f9f6bba09 100644 --- a/src/components/Options/ReportOptions/ReportOptions.spec.tsx +++ b/src/components/Options/ReportOptions/ReportOptions.spec.tsx @@ -1,33 +1,21 @@ import { Button } from '@material-ui/core' import StyledSwitch from 'components/CommonKit/Switch/StyledSwitch' import ReportOptions from 'components/Options/ReportOptions/ReportOptions' -import { FluidState, FluidType } from 'enum/fluid.enum' +import { FluidState, FluidType } from 'enums' import { mount } from 'enzyme' import React from 'react' import { Provider } from 'react-redux' -import * as profileActions from 'store/profile/profile.actions' +import * as profileActions from 'store/profile/profile.slice' import { createMockEcolyoStore, mockInitialEcolyoState, -} from '../../../../tests/__mocks__/store' - -jest.mock('cozy-ui/transpiled/react/I18n', () => { - return { - useI18n: jest.fn(() => { - return { - t: (str: string) => str, - } - }), - } -}) +} from 'tests/__mocks__/store' const mockUpdateProfile = jest.fn() jest.mock('services/profile.service', () => { - return jest.fn(() => { - return { - updateProfile: mockUpdateProfile, - } - }) + return jest.fn(() => ({ + updateProfile: mockUpdateProfile, + })) }) const updateProfileSpy = jest.spyOn(profileActions, 'updateProfile') @@ -35,8 +23,7 @@ const updateProfileSpy = jest.spyOn(profileActions, 'updateProfile') describe('ReportOptions component', () => { const store = createMockEcolyoStore() beforeEach(() => { - store.clearActions() - updateProfileSpy.mockClear() + jest.clearAllMocks() }) it('should be rendered with sendAnalysisNotification to true', () => { @@ -55,7 +42,7 @@ describe('ReportOptions component', () => { </Provider> ) wrapper.find(Button).first().simulate('click') - expect(updateProfileSpy).toBeCalledTimes(1) + expect(updateProfileSpy).toHaveBeenCalledTimes(1) expect(updateProfileSpy).toHaveBeenCalledWith({ sendAnalysisNotification: false, }) @@ -69,7 +56,7 @@ describe('ReportOptions component', () => { </Provider> ) wrapper.find(Button).first().simulate('click') - expect(updateProfileSpy).toBeCalledTimes(1) + expect(updateProfileSpy).toHaveBeenCalledTimes(1) expect(updateProfileSpy).toHaveBeenCalledWith({ sendAnalysisNotification: true, }) @@ -98,7 +85,7 @@ describe('ReportOptions component', () => { .find('input') .first() .simulate('change', { target: { checked: 'true' } }) - expect(updateProfileSpy).toBeCalledTimes(1) + expect(updateProfileSpy).toHaveBeenCalledTimes(1) expect(updateProfileSpy).toHaveBeenCalledWith({ sendConsumptionAlert: true, }) diff --git a/src/components/Options/ReportOptions/ReportOptions.tsx b/src/components/Options/ReportOptions/ReportOptions.tsx index f24ed8ad617ba3e00d17a6e691037208b78ba6ea..463651514731915010ae22cc9d728f73cbabc5b9 100644 --- a/src/components/Options/ReportOptions/ReportOptions.tsx +++ b/src/components/Options/ReportOptions/ReportOptions.tsx @@ -2,33 +2,31 @@ import { Button } from '@material-ui/core' import StyledSwitch from 'components/CommonKit/Switch/StyledSwitch' import { useClient } from 'cozy-client' import { useI18n } from 'cozy-ui/transpiled/react/I18n' -import { FluidState, FluidType } from 'enum/fluid.enum' -import { TimeStep } from 'enum/timeStep.enum' +import { FluidState, FluidType, TimeStep } from 'enums' import { DateTime } from 'luxon' import { Dataload, TimePeriod } from 'models' -import React, { Dispatch, useCallback, useEffect, useState } from 'react' -import { useDispatch, useSelector } from 'react-redux' +import React, { useCallback, useEffect, useState } from 'react' import ConsumptionDataManager from 'services/consumption.service' -import { AppActionsTypes, AppStore } from 'store' -import { updateProfile } from 'store/profile/profile.actions' +import { useAppDispatch, useAppSelector } from 'store/hooks' +import { updateProfile } from 'store/profile/profile.slice' import './reportOptions.scss' const ReportOptions = () => { const { t } = useI18n() const client = useClient() - const dispatch = useDispatch<Dispatch<AppActionsTypes>>() + const dispatch = useAppDispatch() const { global: { fluidStatus }, profile, - } = useSelector((state: AppStore) => state.ecolyo) + } = useAppSelector(state => state.ecolyo) const [maxDayData, setLastSemesterMaxDay] = useState<Dataload | null>(null) - const updateProfileReport = async (value: boolean) => { + const updateProfileReport = (value: boolean) => { dispatch(updateProfile({ sendAnalysisNotification: value })) } const updateProfileAlert = useCallback( - async (value: boolean) => { + (value: boolean) => { dispatch(updateProfile({ sendConsumptionAlert: value })) }, [dispatch] @@ -37,7 +35,9 @@ const ReportOptions = () => { const setWaterLimit = (e: React.ChangeEvent<HTMLInputElement>) => { if (e.target.value !== null && parseInt(e.target.value) > 0) { dispatch( - updateProfile({ waterDailyConsumptionLimit: parseInt(e.target.value) }) + updateProfile({ + waterDailyConsumptionLimit: parseInt(e.target.value), + }) ) } else { updateProfileAlert(false) @@ -101,7 +101,7 @@ const ReportOptions = () => { <Button aria-label={t('unsubscribe.button_accessibility')} onClick={() => toggleAnalysisNotification()} - variant={'contained'} + variant="contained" classes={{ root: 'btn-highlight', label: 'text-18-bold', @@ -149,7 +149,7 @@ const ReportOptions = () => { <div className="switch-container-alert"> <input className="input-style" - type={'number'} + type="number" defaultValue={ profile.waterDailyConsumptionLimit === 0 ? '' diff --git a/src/components/Options/Unsubscribe/UnSubscribe.spec.tsx b/src/components/Options/Unsubscribe/UnSubscribeView.spec.tsx similarity index 70% rename from src/components/Options/Unsubscribe/UnSubscribe.spec.tsx rename to src/components/Options/Unsubscribe/UnSubscribeView.spec.tsx index f1b1dc38279ff51b86f04b94e0bf360815ab831a..55ada4892d7ed895434fbd064e9bec9021e7b524 100644 --- a/src/components/Options/Unsubscribe/UnSubscribe.spec.tsx +++ b/src/components/Options/Unsubscribe/UnSubscribeView.spec.tsx @@ -3,30 +3,19 @@ import { mount } from 'enzyme' import toJson from 'enzyme-to-json' import React from 'react' import { Provider } from 'react-redux' -import * as profileActions from 'store/profile/profile.actions' -import { createMockEcolyoStore } from '../../../../tests/__mocks__/store' -import UnSubscribe from './UnSubscribe' +import * as profileActions from 'store/profile/profile.slice' +import { createMockEcolyoStore } from 'tests/__mocks__/store' +import UnSubscribeView from './UnSubscribeView' -jest.mock('cozy-ui/transpiled/react/I18n', () => { - return { - useI18n: jest.fn(() => { - return { - t: (str: string) => str, - } - }), - } -}) jest.mock('components/Header/CozyBar', () => 'mock-cozybar') jest.mock('components/Header/Header', () => 'mock-header') jest.mock('components/Content/Content', () => 'mock-content') const mockUpdateProfile = jest.fn() jest.mock('services/profile.service', () => { - return jest.fn(() => { - return { - updateProfile: mockUpdateProfile, - } - }) + return jest.fn(() => ({ + updateProfile: mockUpdateProfile, + })) }) const updateProfileSpy = jest.spyOn(profileActions, 'updateProfile') const mockedNavigate = jest.fn() @@ -38,14 +27,13 @@ jest.mock('react-router-dom', () => ({ describe('UnSubscribe component', () => { const store = createMockEcolyoStore() beforeEach(() => { - store.clearActions() - updateProfileSpy.mockClear() + jest.clearAllMocks() }) it('should be rendered correctly', () => { const wrapper = mount( <Provider store={store}> - <UnSubscribe /> + <UnSubscribeView /> </Provider> ) expect(toJson(wrapper)).toMatchSnapshot() @@ -54,7 +42,7 @@ describe('UnSubscribe component', () => { it('should click on button and deactivate report', () => { const wrapper = mount( <Provider store={store}> - <UnSubscribe /> + <UnSubscribeView /> </Provider> ) wrapper.find(Button).simulate('click') diff --git a/src/components/Options/Unsubscribe/UnSubscribe.tsx b/src/components/Options/Unsubscribe/UnSubscribeView.tsx similarity index 68% rename from src/components/Options/Unsubscribe/UnSubscribe.tsx rename to src/components/Options/Unsubscribe/UnSubscribeView.tsx index 1ce8beeaae6f58656ba78f755aec99863aeb804f..8b5dd2240df556a125a4656c252635b5ea8349e3 100644 --- a/src/components/Options/Unsubscribe/UnSubscribe.tsx +++ b/src/components/Options/Unsubscribe/UnSubscribeView.tsx @@ -5,21 +5,17 @@ import Content from 'components/Content/Content' import CozyBar from 'components/Header/CozyBar' import Header from 'components/Header/Header' import { useI18n } from 'cozy-ui/transpiled/react/I18n' -import React, { Dispatch, useState } from 'react' -import { useDispatch } from 'react-redux' +import React, { useState } from 'react' import { useNavigate } from 'react-router-dom' -import { AppActionsTypes } from 'store' -import { updateProfile } from 'store/profile/profile.actions' -import './unSubscribe.scss' +import { useAppDispatch } from 'store/hooks' +import { updateProfile } from 'store/profile/profile.slice' +import './unSubscribeView.scss' -const UnSubscribe = () => { - const [headerHeight, setHeaderHeight] = useState<number>(0) - const defineHeaderHeight = (height: number) => { - setHeaderHeight(height) - } +const UnSubscribeView = () => { const { t } = useI18n() - const dispatch = useDispatch<Dispatch<AppActionsTypes>>() const navigate = useNavigate() + const dispatch = useAppDispatch() + const [headerHeight, setHeaderHeight] = useState<number>(0) const unSubscribe = async () => { dispatch(updateProfile({ sendAnalysisNotification: false })) navigate('/consumption') @@ -27,12 +23,12 @@ const UnSubscribe = () => { return ( <> - <CozyBar titleKey={'common.title_analysis'} /> + <CozyBar titleKey="common.title_analysis" /> <Header - setHeaderHeight={defineHeaderHeight} - desktopTitleKey={'common.title_analysis'} + setHeaderHeight={setHeaderHeight} + desktopTitleKey="common.title_analysis" /> - <Content height={headerHeight}> + <Content heightOffset={headerHeight}> <div className="unsubscribe-container"> <StyledIcon className="profile-icon" icon={BearIcon} size={250} /> @@ -43,7 +39,7 @@ const UnSubscribe = () => { <Button aria-label={t('unsubscribe.button_accessibility')} onClick={() => unSubscribe()} - variant={'contained'} + variant="contained" classes={{ root: 'btn-highlight', label: 'text-18-bold', @@ -58,4 +54,4 @@ const UnSubscribe = () => { ) } -export default UnSubscribe +export default UnSubscribeView diff --git a/src/components/Options/Unsubscribe/__snapshots__/UnSubscribe.spec.tsx.snap b/src/components/Options/Unsubscribe/__snapshots__/UnSubscribeView.spec.tsx.snap similarity index 99% rename from src/components/Options/Unsubscribe/__snapshots__/UnSubscribe.spec.tsx.snap rename to src/components/Options/Unsubscribe/__snapshots__/UnSubscribeView.spec.tsx.snap index d06e84f78e27bb05e0db7fe618368590e8998070..8518469701265ae8c94aa8ecf3ad6063eed6f985 100644 --- a/src/components/Options/Unsubscribe/__snapshots__/UnSubscribe.spec.tsx.snap +++ b/src/components/Options/Unsubscribe/__snapshots__/UnSubscribeView.spec.tsx.snap @@ -13,7 +13,7 @@ exports[`UnSubscribe component should be rendered correctly 1`] = ` } } > - <UnSubscribe> + <UnSubscribeView> <mock-cozybar titleKey="common.title_analysis" /> @@ -22,7 +22,7 @@ exports[`UnSubscribe component should be rendered correctly 1`] = ` setHeaderHeight={[Function]} /> <mock-content - height={0} + heightOffset={0} > <div className="unsubscribe-container" @@ -207,6 +207,6 @@ exports[`UnSubscribe component should be rendered correctly 1`] = ` </WithStyles(ForwardRef(Button))> </div> </mock-content> - </UnSubscribe> + </UnSubscribeView> </Provider> `; diff --git a/src/components/Options/Unsubscribe/unSubscribe.scss b/src/components/Options/Unsubscribe/unSubscribeView.scss similarity index 100% rename from src/components/Options/Unsubscribe/unSubscribe.scss rename to src/components/Options/Unsubscribe/unSubscribeView.scss diff --git a/src/components/Options/Version/Version.tsx b/src/components/Options/Version/Version.tsx index 151b8189fb13023d79fa2aff723f78d4e15ae65f..5d74881e09fb6244817a47238d4d02666e9a1425 100644 --- a/src/components/Options/Version/Version.tsx +++ b/src/components/Options/Version/Version.tsx @@ -1,9 +1,9 @@ -import { Client, useClient } from 'cozy-client' +import { useClient } from 'cozy-client' import React from 'react' import './version.scss' const Version = () => { - const client: Client = useClient() + const client = useClient() return ( <div className="version-root text-14-normal"> {`v ${client.appMetadata.version}`} diff --git a/src/components/Options/__snapshots__/OptionsView.spec.tsx.snap b/src/components/Options/__snapshots__/OptionsView.spec.tsx.snap index 7690e522649c43dadd5304904535270c4c2e1086..5417b10551f0928cbf257528d9c345106e34b077 100644 --- a/src/components/Options/__snapshots__/OptionsView.spec.tsx.snap +++ b/src/components/Options/__snapshots__/OptionsView.spec.tsx.snap @@ -10,7 +10,7 @@ exports[`OptionsView component should be rendered correctly 1`] = ` setHeaderHeight={[Function]} /> <mock-content - height={0} + heightOffset={0} > <ProfileTypeOptions /> <ExportData /> diff --git a/src/components/PartnerIssue/PartnerIssueModal.spec.tsx b/src/components/PartnerIssue/PartnerIssueModal.spec.tsx index de6d946e2b07f301babef14a9df3194189e3ff11..c3ac2e4d67277124e28e68950db4d32b468138bc 100644 --- a/src/components/PartnerIssue/PartnerIssueModal.spec.tsx +++ b/src/components/PartnerIssue/PartnerIssueModal.spec.tsx @@ -1,73 +1,49 @@ import { Button } from '@material-ui/core' +import { FluidType } from 'enums' import { mount } from 'enzyme' import toJson from 'enzyme-to-json' import React from 'react' -import { Provider } from 'react-redux' -import configureStore from 'redux-mock-store' -import { mockInitialEcolyoState } from '../../../tests/__mocks__/store' import PartnerIssueModal from './PartnerIssueModal' -jest.mock('cozy-ui/transpiled/react/I18n', () => { - return { - useI18n: jest.fn(() => { - return { - t: (str: string) => str, - } - }), - } -}) - -const mockStore = configureStore([]) const mockHandleClose = jest.fn() describe('PartnerIssueModal component', () => { - const store = mockStore({ - ecolyo: mockInitialEcolyoState, - }) it('should render correctly', () => { const wrapper = mount( - <Provider store={store}> - <PartnerIssueModal - open={true} - handleCloseClick={mockHandleClose} - issuedFluid={mockInitialEcolyoState.global.fluidStatus[0]} - /> - </Provider> + <PartnerIssueModal + open={true} + handleCloseClick={mockHandleClose} + issuedFluid={FluidType.ELECTRICITY} + /> ) expect(toJson(wrapper)).toMatchSnapshot() }) it('should render elec modal', () => { const wrapper = mount( - <Provider store={store}> - <PartnerIssueModal - open={true} - handleCloseClick={mockHandleClose} - issuedFluid={mockInitialEcolyoState.global.fluidStatus[0]} - /> - </Provider> + <PartnerIssueModal + open={true} + handleCloseClick={mockHandleClose} + issuedFluid={FluidType.ELECTRICITY} + /> ) expect(wrapper.text().includes('error_connect_elec')).toBeTruthy() }) it('should render water modal', () => { const wrapper = mount( - <Provider store={store}> - <PartnerIssueModal - open={true} - handleCloseClick={mockHandleClose} - issuedFluid={mockInitialEcolyoState.global.fluidStatus[1]} - /> - </Provider> + <PartnerIssueModal + open={true} + handleCloseClick={mockHandleClose} + issuedFluid={FluidType.WATER} + /> ) expect(wrapper.text().includes('error_connect_water')).toBeTruthy() }) it('should close modal', () => { const wrapper = mount( - <Provider store={store}> - <PartnerIssueModal - open={true} - handleCloseClick={mockHandleClose} - issuedFluid={mockInitialEcolyoState.global.fluidStatus[0]} - /> - </Provider> + <PartnerIssueModal + open={true} + handleCloseClick={mockHandleClose} + issuedFluid={FluidType.ELECTRICITY} + /> ) wrapper.find(Button).simulate('click') expect(mockHandleClose).toHaveBeenCalled() @@ -75,13 +51,11 @@ describe('PartnerIssueModal component', () => { it('should not be rendered', () => { const wrapper = mount( - <Provider store={store}> - <PartnerIssueModal - open={false} - handleCloseClick={mockHandleClose} - issuedFluid={mockInitialEcolyoState.global.fluidStatus[0]} - /> - </Provider> + <PartnerIssueModal + open={false} + handleCloseClick={mockHandleClose} + issuedFluid={FluidType.ELECTRICITY} + /> ) expect(wrapper.find('div.partnerIssueModal').exists()).toBeFalsy() }) diff --git a/src/components/PartnerIssue/PartnerIssueModal.tsx b/src/components/PartnerIssue/PartnerIssueModal.tsx index 59d4c7842b84cbee2a94db15aaed0791087312ae..8876a8083913d85df2d45e8e7eeb0b1ad087f32b 100644 --- a/src/components/PartnerIssue/PartnerIssueModal.tsx +++ b/src/components/PartnerIssue/PartnerIssueModal.tsx @@ -6,14 +6,13 @@ import OrangeWarn from 'assets/icons/ico/warn-orange.svg' import StyledIcon from 'components/CommonKit/Icon/StyledIcon' import { useI18n } from 'cozy-ui/transpiled/react/I18n' import Icon from 'cozy-ui/transpiled/react/Icon' -import { FluidType } from 'enum/fluid.enum' -import { FluidStatus } from 'models' +import { FluidType } from 'enums' import React from 'react' import './partnerIssueModal.scss' interface PartnerIssueModalProps { open: boolean - issuedFluid: FluidStatus + issuedFluid: FluidType handleCloseClick: (fluidType: FluidType) => void } @@ -25,7 +24,7 @@ const PartnerIssueModal = ({ const { t } = useI18n() const getFluidTypeLabel = () => { - switch (issuedFluid.fluidType) { + switch (issuedFluid) { case FluidType.ELECTRICITY: return 'elec' case FluidType.WATER: @@ -40,30 +39,28 @@ const PartnerIssueModal = ({ open={open} disableEscapeKeyDown onClose={(event, reason): void => { - event && - reason !== 'backdropClick' && - handleCloseClick(issuedFluid.fluidType) + event && reason !== 'backdropClick' && handleCloseClick(issuedFluid) }} - aria-labelledby={'accessibility-title'} + aria-labelledby="accessibility-title" classes={{ root: 'modal-root', paper: 'modal-paper', }} style={{ zIndex: 1500 }} > - <div id={'accessibility-title'}> + <div id="accessibility-title"> {t('feedback.accessibility.window_title')} </div> <IconButton aria-label={t('feedback.accessibility.button_close')} className="modal-paper-close-button" - onClick={() => handleCloseClick(issuedFluid.fluidType)} + onClick={() => handleCloseClick(issuedFluid)} > <Icon icon={CloseIcon} size={16} /> </IconButton> <div className="partnerIssueModal"> - <StyledIcon icon={OrangeWarn} size={40} className={'warn-icon'} /> + <StyledIcon icon={OrangeWarn} size={40} className="warn-icon" /> <div className="partner-issue-title text-20-bold"> {t('consumption.partner_issue_modal.title')} </div> @@ -82,7 +79,7 @@ const PartnerIssueModal = ({ }} /> <Button - onClick={() => handleCloseClick(issuedFluid.fluidType)} + onClick={() => handleCloseClick(issuedFluid)} classes={{ root: 'btn-highlight', label: 'text-16-bold', diff --git a/src/components/PartnerIssue/__snapshots__/PartnerIssueModal.spec.tsx.snap b/src/components/PartnerIssue/__snapshots__/PartnerIssueModal.spec.tsx.snap index 1b915b824f4f32b3047300b8500f8607388f185a..afd0cdd3465ce6bc9272539e4f51558166690e5e 100644 --- a/src/components/PartnerIssue/__snapshots__/PartnerIssueModal.spec.tsx.snap +++ b/src/components/PartnerIssue/__snapshots__/PartnerIssueModal.spec.tsx.snap @@ -1,52 +1,47 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP exports[`PartnerIssueModal component should render correctly 1`] = ` -<Provider - store={ - Object { - "clearActions": [Function], - "dispatch": [Function], - "getActions": [Function], - "getState": [Function], - "replaceReducer": [Function], - "subscribe": [Function], - } - } +<PartnerIssueModal + handleCloseClick={[MockFunction]} + issuedFluid={0} + open={true} > - <PartnerIssueModal - handleCloseClick={[MockFunction]} - issuedFluid={ + <WithStyles(ForwardRef(Dialog)) + aria-labelledby="accessibility-title" + classes={ Object { - "connection": Object { - "account": null, - "isUpdating": false, - "konnector": null, - "konnectorConfig": Object { - "activation": "", - "name": "", - "oauth": false, - "siteLink": "", - "slug": "enedissgegrandlyon", - }, - "shouldLaunchKonnector": false, - "trigger": null, - "triggerState": null, - }, - "firstDataDate": null, - "fluidType": 0, - "lastDataDate": null, - "maintenance": false, - "status": 0, + "paper": "modal-paper", + "root": "modal-root", } } + disableEscapeKeyDown={true} + onClose={[Function]} open={true} + style={ + Object { + "zIndex": 1500, + } + } > - <WithStyles(ForwardRef(Dialog)) + <ForwardRef(Dialog) aria-labelledby="accessibility-title" classes={ Object { - "paper": "modal-paper", - "root": "modal-root", + "container": "MuiDialog-container", + "paper": "MuiDialog-paper modal-paper", + "paperFullScreen": "MuiDialog-paperFullScreen", + "paperFullWidth": "MuiDialog-paperFullWidth", + "paperScrollBody": "MuiDialog-paperScrollBody", + "paperScrollPaper": "MuiDialog-paperScrollPaper", + "paperWidthFalse": "MuiDialog-paperWidthFalse", + "paperWidthLg": "MuiDialog-paperWidthLg", + "paperWidthMd": "MuiDialog-paperWidthMd", + "paperWidthSm": "MuiDialog-paperWidthSm", + "paperWidthXl": "MuiDialog-paperWidthXl", + "paperWidthXs": "MuiDialog-paperWidthXs", + "root": "MuiDialog-root modal-root", + "scrollBody": "MuiDialog-scrollBody", + "scrollPaper": "MuiDialog-scrollPaper", } } disableEscapeKeyDown={true} @@ -58,500 +53,486 @@ exports[`PartnerIssueModal component should render correctly 1`] = ` } } > - <ForwardRef(Dialog) - aria-labelledby="accessibility-title" - classes={ + <ForwardRef(Modal) + BackdropComponent={ Object { - "container": "MuiDialog-container", - "paper": "MuiDialog-paper modal-paper", - "paperFullScreen": "MuiDialog-paperFullScreen", - "paperFullWidth": "MuiDialog-paperFullWidth", - "paperScrollBody": "MuiDialog-paperScrollBody", - "paperScrollPaper": "MuiDialog-paperScrollPaper", - "paperWidthFalse": "MuiDialog-paperWidthFalse", - "paperWidthLg": "MuiDialog-paperWidthLg", - "paperWidthMd": "MuiDialog-paperWidthMd", - "paperWidthSm": "MuiDialog-paperWidthSm", - "paperWidthXl": "MuiDialog-paperWidthXl", - "paperWidthXs": "MuiDialog-paperWidthXs", - "root": "MuiDialog-root modal-root", - "scrollBody": "MuiDialog-scrollBody", - "scrollPaper": "MuiDialog-scrollPaper", - } - } - disableEscapeKeyDown={true} - onClose={[Function]} - open={true} - style={ - Object { - "zIndex": 1500, - } - } - > - <ForwardRef(Modal) - BackdropComponent={ - Object { + "$$typeof": Symbol(react.forward_ref), + "Naked": Object { "$$typeof": Symbol(react.forward_ref), - "Naked": Object { - "$$typeof": Symbol(react.forward_ref), - "propTypes": Object { - "children": [Function], - "className": [Function], - "classes": [Function], - "invisible": [Function], - "open": [Function], - "transitionDuration": [Function], - }, - "render": [Function], + "propTypes": Object { + "children": [Function], + "className": [Function], + "classes": [Function], + "invisible": [Function], + "open": [Function], + "transitionDuration": [Function], }, - "displayName": "WithStyles(ForwardRef(Backdrop))", - "options": Object { - "defaultTheme": Object { - "breakpoints": Object { - "between": [Function], - "down": [Function], - "keys": Array [ - "xs", - "sm", - "md", - "lg", - "xl", - ], - "only": [Function], - "up": [Function], - "values": Object { - "lg": 1280, - "md": 960, - "sm": 600, - "xl": 1920, - "xs": 0, - }, - "width": [Function], - }, - "direction": "ltr", - "mixins": Object { - "gutters": [Function], - "toolbar": Object { - "@media (min-width:0px) and (orientation: landscape)": Object { - "minHeight": 48, - }, - "@media (min-width:600px)": Object { - "minHeight": 64, - }, - "minHeight": 56, - }, + "render": [Function], + }, + "displayName": "WithStyles(ForwardRef(Backdrop))", + "options": Object { + "defaultTheme": Object { + "breakpoints": Object { + "between": [Function], + "down": [Function], + "keys": Array [ + "xs", + "sm", + "md", + "lg", + "xl", + ], + "only": [Function], + "up": [Function], + "values": Object { + "lg": 1280, + "md": 960, + "sm": 600, + "xl": 1920, + "xs": 0, }, - "overrides": Object {}, - "palette": Object { - "action": Object { - "activatedOpacity": 0.12, - "active": "rgba(0, 0, 0, 0.54)", - "disabled": "rgba(0, 0, 0, 0.26)", - "disabledBackground": "rgba(0, 0, 0, 0.12)", - "disabledOpacity": 0.38, - "focus": "rgba(0, 0, 0, 0.12)", - "focusOpacity": 0.12, - "hover": "rgba(0, 0, 0, 0.04)", - "hoverOpacity": 0.04, - "selected": "rgba(0, 0, 0, 0.08)", - "selectedOpacity": 0.08, - }, - "augmentColor": [Function], - "background": Object { - "default": "#fafafa", - "paper": "#fff", - }, - "common": Object { - "black": "#000", - "white": "#fff", - }, - "contrastThreshold": 3, - "divider": "rgba(0, 0, 0, 0.12)", - "error": Object { - "contrastText": "#fff", - "dark": "#d32f2f", - "light": "#e57373", - "main": "#f44336", - }, - "getContrastText": [Function], - "grey": Object { - "100": "#f5f5f5", - "200": "#eeeeee", - "300": "#e0e0e0", - "400": "#bdbdbd", - "50": "#fafafa", - "500": "#9e9e9e", - "600": "#757575", - "700": "#616161", - "800": "#424242", - "900": "#212121", - "A100": "#d5d5d5", - "A200": "#aaaaaa", - "A400": "#303030", - "A700": "#616161", - }, - "info": Object { - "contrastText": "#fff", - "dark": "#1976d2", - "light": "#64b5f6", - "main": "#2196f3", - }, - "primary": Object { - "contrastText": "#fff", - "dark": "#303f9f", - "light": "#7986cb", - "main": "#3f51b5", - }, - "secondary": Object { - "contrastText": "#fff", - "dark": "#c51162", - "light": "#ff4081", - "main": "#f50057", - }, - "success": Object { - "contrastText": "rgba(0, 0, 0, 0.87)", - "dark": "#388e3c", - "light": "#81c784", - "main": "#4caf50", - }, - "text": Object { - "disabled": "rgba(0, 0, 0, 0.38)", - "hint": "rgba(0, 0, 0, 0.38)", - "primary": "rgba(0, 0, 0, 0.87)", - "secondary": "rgba(0, 0, 0, 0.54)", + "width": [Function], + }, + "direction": "ltr", + "mixins": Object { + "gutters": [Function], + "toolbar": Object { + "@media (min-width:0px) and (orientation: landscape)": Object { + "minHeight": 48, }, - "tonalOffset": 0.2, - "type": "light", - "warning": Object { - "contrastText": "rgba(0, 0, 0, 0.87)", - "dark": "#f57c00", - "light": "#ffb74d", - "main": "#ff9800", + "@media (min-width:600px)": Object { + "minHeight": 64, }, + "minHeight": 56, }, - "props": Object {}, - "shadows": Array [ - "none", - "0px 2px 1px -1px rgba(0,0,0,0.2),0px 1px 1px 0px rgba(0,0,0,0.14),0px 1px 3px 0px rgba(0,0,0,0.12)", - "0px 3px 1px -2px rgba(0,0,0,0.2),0px 2px 2px 0px rgba(0,0,0,0.14),0px 1px 5px 0px rgba(0,0,0,0.12)", - "0px 3px 3px -2px rgba(0,0,0,0.2),0px 3px 4px 0px rgba(0,0,0,0.14),0px 1px 8px 0px rgba(0,0,0,0.12)", - "0px 2px 4px -1px rgba(0,0,0,0.2),0px 4px 5px 0px rgba(0,0,0,0.14),0px 1px 10px 0px rgba(0,0,0,0.12)", - "0px 3px 5px -1px rgba(0,0,0,0.2),0px 5px 8px 0px rgba(0,0,0,0.14),0px 1px 14px 0px rgba(0,0,0,0.12)", - "0px 3px 5px -1px rgba(0,0,0,0.2),0px 6px 10px 0px rgba(0,0,0,0.14),0px 1px 18px 0px rgba(0,0,0,0.12)", - "0px 4px 5px -2px rgba(0,0,0,0.2),0px 7px 10px 1px rgba(0,0,0,0.14),0px 2px 16px 1px rgba(0,0,0,0.12)", - "0px 5px 5px -3px rgba(0,0,0,0.2),0px 8px 10px 1px rgba(0,0,0,0.14),0px 3px 14px 2px rgba(0,0,0,0.12)", - "0px 5px 6px -3px rgba(0,0,0,0.2),0px 9px 12px 1px rgba(0,0,0,0.14),0px 3px 16px 2px rgba(0,0,0,0.12)", - "0px 6px 6px -3px rgba(0,0,0,0.2),0px 10px 14px 1px rgba(0,0,0,0.14),0px 4px 18px 3px rgba(0,0,0,0.12)", - "0px 6px 7px -4px rgba(0,0,0,0.2),0px 11px 15px 1px rgba(0,0,0,0.14),0px 4px 20px 3px rgba(0,0,0,0.12)", - "0px 7px 8px -4px rgba(0,0,0,0.2),0px 12px 17px 2px rgba(0,0,0,0.14),0px 5px 22px 4px rgba(0,0,0,0.12)", - "0px 7px 8px -4px rgba(0,0,0,0.2),0px 13px 19px 2px rgba(0,0,0,0.14),0px 5px 24px 4px rgba(0,0,0,0.12)", - "0px 7px 9px -4px rgba(0,0,0,0.2),0px 14px 21px 2px rgba(0,0,0,0.14),0px 5px 26px 4px rgba(0,0,0,0.12)", - "0px 8px 9px -5px rgba(0,0,0,0.2),0px 15px 22px 2px rgba(0,0,0,0.14),0px 6px 28px 5px rgba(0,0,0,0.12)", - "0px 8px 10px -5px rgba(0,0,0,0.2),0px 16px 24px 2px rgba(0,0,0,0.14),0px 6px 30px 5px rgba(0,0,0,0.12)", - "0px 8px 11px -5px rgba(0,0,0,0.2),0px 17px 26px 2px rgba(0,0,0,0.14),0px 6px 32px 5px rgba(0,0,0,0.12)", - "0px 9px 11px -5px rgba(0,0,0,0.2),0px 18px 28px 2px rgba(0,0,0,0.14),0px 7px 34px 6px rgba(0,0,0,0.12)", - "0px 9px 12px -6px rgba(0,0,0,0.2),0px 19px 29px 2px rgba(0,0,0,0.14),0px 7px 36px 6px rgba(0,0,0,0.12)", - "0px 10px 13px -6px rgba(0,0,0,0.2),0px 20px 31px 3px rgba(0,0,0,0.14),0px 8px 38px 7px rgba(0,0,0,0.12)", - "0px 10px 13px -6px rgba(0,0,0,0.2),0px 21px 33px 3px rgba(0,0,0,0.14),0px 8px 40px 7px rgba(0,0,0,0.12)", - "0px 10px 14px -6px rgba(0,0,0,0.2),0px 22px 35px 3px rgba(0,0,0,0.14),0px 8px 42px 7px rgba(0,0,0,0.12)", - "0px 11px 14px -7px rgba(0,0,0,0.2),0px 23px 36px 3px rgba(0,0,0,0.14),0px 9px 44px 8px rgba(0,0,0,0.12)", - "0px 11px 15px -7px rgba(0,0,0,0.2),0px 24px 38px 3px rgba(0,0,0,0.14),0px 9px 46px 8px rgba(0,0,0,0.12)", - ], - "shape": Object { - "borderRadius": 4, + }, + "overrides": Object {}, + "palette": Object { + "action": Object { + "activatedOpacity": 0.12, + "active": "rgba(0, 0, 0, 0.54)", + "disabled": "rgba(0, 0, 0, 0.26)", + "disabledBackground": "rgba(0, 0, 0, 0.12)", + "disabledOpacity": 0.38, + "focus": "rgba(0, 0, 0, 0.12)", + "focusOpacity": 0.12, + "hover": "rgba(0, 0, 0, 0.04)", + "hoverOpacity": 0.04, + "selected": "rgba(0, 0, 0, 0.08)", + "selectedOpacity": 0.08, }, - "spacing": [Function], - "transitions": Object { - "create": [Function], - "duration": Object { - "complex": 375, - "enteringScreen": 225, - "leavingScreen": 195, - "short": 250, - "shorter": 200, - "shortest": 150, - "standard": 300, - }, - "easing": Object { - "easeIn": "cubic-bezier(0.4, 0, 1, 1)", - "easeInOut": "cubic-bezier(0.4, 0, 0.2, 1)", - "easeOut": "cubic-bezier(0.0, 0, 0.2, 1)", - "sharp": "cubic-bezier(0.4, 0, 0.6, 1)", - }, - "getAutoHeightDuration": [Function], + "augmentColor": [Function], + "background": Object { + "default": "#fafafa", + "paper": "#fff", }, - "typography": Object { - "body1": Object { - "fontFamily": "\\"Roboto\\", \\"Helvetica\\", \\"Arial\\", sans-serif", - "fontSize": "1rem", - "fontWeight": 400, - "letterSpacing": "0.00938em", - "lineHeight": 1.5, - }, - "body2": Object { - "fontFamily": "\\"Roboto\\", \\"Helvetica\\", \\"Arial\\", sans-serif", - "fontSize": "0.875rem", - "fontWeight": 400, - "letterSpacing": "0.01071em", - "lineHeight": 1.43, - }, - "button": Object { - "fontFamily": "\\"Roboto\\", \\"Helvetica\\", \\"Arial\\", sans-serif", - "fontSize": "0.875rem", - "fontWeight": 500, - "letterSpacing": "0.02857em", - "lineHeight": 1.75, - "textTransform": "uppercase", - }, - "caption": Object { - "fontFamily": "\\"Roboto\\", \\"Helvetica\\", \\"Arial\\", sans-serif", - "fontSize": "0.75rem", - "fontWeight": 400, - "letterSpacing": "0.03333em", - "lineHeight": 1.66, - }, + "common": Object { + "black": "#000", + "white": "#fff", + }, + "contrastThreshold": 3, + "divider": "rgba(0, 0, 0, 0.12)", + "error": Object { + "contrastText": "#fff", + "dark": "#d32f2f", + "light": "#e57373", + "main": "#f44336", + }, + "getContrastText": [Function], + "grey": Object { + "100": "#f5f5f5", + "200": "#eeeeee", + "300": "#e0e0e0", + "400": "#bdbdbd", + "50": "#fafafa", + "500": "#9e9e9e", + "600": "#757575", + "700": "#616161", + "800": "#424242", + "900": "#212121", + "A100": "#d5d5d5", + "A200": "#aaaaaa", + "A400": "#303030", + "A700": "#616161", + }, + "info": Object { + "contrastText": "#fff", + "dark": "#1976d2", + "light": "#64b5f6", + "main": "#2196f3", + }, + "primary": Object { + "contrastText": "#fff", + "dark": "#303f9f", + "light": "#7986cb", + "main": "#3f51b5", + }, + "secondary": Object { + "contrastText": "#fff", + "dark": "#c51162", + "light": "#ff4081", + "main": "#f50057", + }, + "success": Object { + "contrastText": "rgba(0, 0, 0, 0.87)", + "dark": "#388e3c", + "light": "#81c784", + "main": "#4caf50", + }, + "text": Object { + "disabled": "rgba(0, 0, 0, 0.38)", + "hint": "rgba(0, 0, 0, 0.38)", + "primary": "rgba(0, 0, 0, 0.87)", + "secondary": "rgba(0, 0, 0, 0.54)", + }, + "tonalOffset": 0.2, + "type": "light", + "warning": Object { + "contrastText": "rgba(0, 0, 0, 0.87)", + "dark": "#f57c00", + "light": "#ffb74d", + "main": "#ff9800", + }, + }, + "props": Object {}, + "shadows": Array [ + "none", + "0px 2px 1px -1px rgba(0,0,0,0.2),0px 1px 1px 0px rgba(0,0,0,0.14),0px 1px 3px 0px rgba(0,0,0,0.12)", + "0px 3px 1px -2px rgba(0,0,0,0.2),0px 2px 2px 0px rgba(0,0,0,0.14),0px 1px 5px 0px rgba(0,0,0,0.12)", + "0px 3px 3px -2px rgba(0,0,0,0.2),0px 3px 4px 0px rgba(0,0,0,0.14),0px 1px 8px 0px rgba(0,0,0,0.12)", + "0px 2px 4px -1px rgba(0,0,0,0.2),0px 4px 5px 0px rgba(0,0,0,0.14),0px 1px 10px 0px rgba(0,0,0,0.12)", + "0px 3px 5px -1px rgba(0,0,0,0.2),0px 5px 8px 0px rgba(0,0,0,0.14),0px 1px 14px 0px rgba(0,0,0,0.12)", + "0px 3px 5px -1px rgba(0,0,0,0.2),0px 6px 10px 0px rgba(0,0,0,0.14),0px 1px 18px 0px rgba(0,0,0,0.12)", + "0px 4px 5px -2px rgba(0,0,0,0.2),0px 7px 10px 1px rgba(0,0,0,0.14),0px 2px 16px 1px rgba(0,0,0,0.12)", + "0px 5px 5px -3px rgba(0,0,0,0.2),0px 8px 10px 1px rgba(0,0,0,0.14),0px 3px 14px 2px rgba(0,0,0,0.12)", + "0px 5px 6px -3px rgba(0,0,0,0.2),0px 9px 12px 1px rgba(0,0,0,0.14),0px 3px 16px 2px rgba(0,0,0,0.12)", + "0px 6px 6px -3px rgba(0,0,0,0.2),0px 10px 14px 1px rgba(0,0,0,0.14),0px 4px 18px 3px rgba(0,0,0,0.12)", + "0px 6px 7px -4px rgba(0,0,0,0.2),0px 11px 15px 1px rgba(0,0,0,0.14),0px 4px 20px 3px rgba(0,0,0,0.12)", + "0px 7px 8px -4px rgba(0,0,0,0.2),0px 12px 17px 2px rgba(0,0,0,0.14),0px 5px 22px 4px rgba(0,0,0,0.12)", + "0px 7px 8px -4px rgba(0,0,0,0.2),0px 13px 19px 2px rgba(0,0,0,0.14),0px 5px 24px 4px rgba(0,0,0,0.12)", + "0px 7px 9px -4px rgba(0,0,0,0.2),0px 14px 21px 2px rgba(0,0,0,0.14),0px 5px 26px 4px rgba(0,0,0,0.12)", + "0px 8px 9px -5px rgba(0,0,0,0.2),0px 15px 22px 2px rgba(0,0,0,0.14),0px 6px 28px 5px rgba(0,0,0,0.12)", + "0px 8px 10px -5px rgba(0,0,0,0.2),0px 16px 24px 2px rgba(0,0,0,0.14),0px 6px 30px 5px rgba(0,0,0,0.12)", + "0px 8px 11px -5px rgba(0,0,0,0.2),0px 17px 26px 2px rgba(0,0,0,0.14),0px 6px 32px 5px rgba(0,0,0,0.12)", + "0px 9px 11px -5px rgba(0,0,0,0.2),0px 18px 28px 2px rgba(0,0,0,0.14),0px 7px 34px 6px rgba(0,0,0,0.12)", + "0px 9px 12px -6px rgba(0,0,0,0.2),0px 19px 29px 2px rgba(0,0,0,0.14),0px 7px 36px 6px rgba(0,0,0,0.12)", + "0px 10px 13px -6px rgba(0,0,0,0.2),0px 20px 31px 3px rgba(0,0,0,0.14),0px 8px 38px 7px rgba(0,0,0,0.12)", + "0px 10px 13px -6px rgba(0,0,0,0.2),0px 21px 33px 3px rgba(0,0,0,0.14),0px 8px 40px 7px rgba(0,0,0,0.12)", + "0px 10px 14px -6px rgba(0,0,0,0.2),0px 22px 35px 3px rgba(0,0,0,0.14),0px 8px 42px 7px rgba(0,0,0,0.12)", + "0px 11px 14px -7px rgba(0,0,0,0.2),0px 23px 36px 3px rgba(0,0,0,0.14),0px 9px 44px 8px rgba(0,0,0,0.12)", + "0px 11px 15px -7px rgba(0,0,0,0.2),0px 24px 38px 3px rgba(0,0,0,0.14),0px 9px 46px 8px rgba(0,0,0,0.12)", + ], + "shape": Object { + "borderRadius": 4, + }, + "spacing": [Function], + "transitions": Object { + "create": [Function], + "duration": Object { + "complex": 375, + "enteringScreen": 225, + "leavingScreen": 195, + "short": 250, + "shorter": 200, + "shortest": 150, + "standard": 300, + }, + "easing": Object { + "easeIn": "cubic-bezier(0.4, 0, 1, 1)", + "easeInOut": "cubic-bezier(0.4, 0, 0.2, 1)", + "easeOut": "cubic-bezier(0.0, 0, 0.2, 1)", + "sharp": "cubic-bezier(0.4, 0, 0.6, 1)", + }, + "getAutoHeightDuration": [Function], + }, + "typography": Object { + "body1": Object { "fontFamily": "\\"Roboto\\", \\"Helvetica\\", \\"Arial\\", sans-serif", - "fontSize": 14, - "fontWeightBold": 700, - "fontWeightLight": 300, - "fontWeightMedium": 500, - "fontWeightRegular": 400, - "h1": Object { - "fontFamily": "\\"Roboto\\", \\"Helvetica\\", \\"Arial\\", sans-serif", - "fontSize": "6rem", - "fontWeight": 300, - "letterSpacing": "-0.01562em", - "lineHeight": 1.167, - }, - "h2": Object { - "fontFamily": "\\"Roboto\\", \\"Helvetica\\", \\"Arial\\", sans-serif", - "fontSize": "3.75rem", - "fontWeight": 300, - "letterSpacing": "-0.00833em", - "lineHeight": 1.2, - }, - "h3": Object { - "fontFamily": "\\"Roboto\\", \\"Helvetica\\", \\"Arial\\", sans-serif", - "fontSize": "3rem", - "fontWeight": 400, - "letterSpacing": "0em", - "lineHeight": 1.167, - }, - "h4": Object { - "fontFamily": "\\"Roboto\\", \\"Helvetica\\", \\"Arial\\", sans-serif", - "fontSize": "2.125rem", - "fontWeight": 400, - "letterSpacing": "0.00735em", - "lineHeight": 1.235, - }, - "h5": Object { - "fontFamily": "\\"Roboto\\", \\"Helvetica\\", \\"Arial\\", sans-serif", - "fontSize": "1.5rem", - "fontWeight": 400, - "letterSpacing": "0em", - "lineHeight": 1.334, - }, - "h6": Object { - "fontFamily": "\\"Roboto\\", \\"Helvetica\\", \\"Arial\\", sans-serif", - "fontSize": "1.25rem", - "fontWeight": 500, - "letterSpacing": "0.0075em", - "lineHeight": 1.6, - }, - "htmlFontSize": 16, - "overline": Object { - "fontFamily": "\\"Roboto\\", \\"Helvetica\\", \\"Arial\\", sans-serif", - "fontSize": "0.75rem", - "fontWeight": 400, - "letterSpacing": "0.08333em", - "lineHeight": 2.66, - "textTransform": "uppercase", - }, - "pxToRem": [Function], - "round": [Function], - "subtitle1": Object { - "fontFamily": "\\"Roboto\\", \\"Helvetica\\", \\"Arial\\", sans-serif", - "fontSize": "1rem", - "fontWeight": 400, - "letterSpacing": "0.00938em", - "lineHeight": 1.75, - }, - "subtitle2": Object { - "fontFamily": "\\"Roboto\\", \\"Helvetica\\", \\"Arial\\", sans-serif", - "fontSize": "0.875rem", - "fontWeight": 500, - "letterSpacing": "0.00714em", - "lineHeight": 1.57, - }, + "fontSize": "1rem", + "fontWeight": 400, + "letterSpacing": "0.00938em", + "lineHeight": 1.5, + }, + "body2": Object { + "fontFamily": "\\"Roboto\\", \\"Helvetica\\", \\"Arial\\", sans-serif", + "fontSize": "0.875rem", + "fontWeight": 400, + "letterSpacing": "0.01071em", + "lineHeight": 1.43, + }, + "button": Object { + "fontFamily": "\\"Roboto\\", \\"Helvetica\\", \\"Arial\\", sans-serif", + "fontSize": "0.875rem", + "fontWeight": 500, + "letterSpacing": "0.02857em", + "lineHeight": 1.75, + "textTransform": "uppercase", + }, + "caption": Object { + "fontFamily": "\\"Roboto\\", \\"Helvetica\\", \\"Arial\\", sans-serif", + "fontSize": "0.75rem", + "fontWeight": 400, + "letterSpacing": "0.03333em", + "lineHeight": 1.66, + }, + "fontFamily": "\\"Roboto\\", \\"Helvetica\\", \\"Arial\\", sans-serif", + "fontSize": 14, + "fontWeightBold": 700, + "fontWeightLight": 300, + "fontWeightMedium": 500, + "fontWeightRegular": 400, + "h1": Object { + "fontFamily": "\\"Roboto\\", \\"Helvetica\\", \\"Arial\\", sans-serif", + "fontSize": "6rem", + "fontWeight": 300, + "letterSpacing": "-0.01562em", + "lineHeight": 1.167, }, - "zIndex": Object { - "appBar": 1100, - "drawer": 1200, - "mobileStepper": 1000, - "modal": 1300, - "snackbar": 1400, - "speedDial": 1050, - "tooltip": 1500, + "h2": Object { + "fontFamily": "\\"Roboto\\", \\"Helvetica\\", \\"Arial\\", sans-serif", + "fontSize": "3.75rem", + "fontWeight": 300, + "letterSpacing": "-0.00833em", + "lineHeight": 1.2, + }, + "h3": Object { + "fontFamily": "\\"Roboto\\", \\"Helvetica\\", \\"Arial\\", sans-serif", + "fontSize": "3rem", + "fontWeight": 400, + "letterSpacing": "0em", + "lineHeight": 1.167, + }, + "h4": Object { + "fontFamily": "\\"Roboto\\", \\"Helvetica\\", \\"Arial\\", sans-serif", + "fontSize": "2.125rem", + "fontWeight": 400, + "letterSpacing": "0.00735em", + "lineHeight": 1.235, + }, + "h5": Object { + "fontFamily": "\\"Roboto\\", \\"Helvetica\\", \\"Arial\\", sans-serif", + "fontSize": "1.5rem", + "fontWeight": 400, + "letterSpacing": "0em", + "lineHeight": 1.334, + }, + "h6": Object { + "fontFamily": "\\"Roboto\\", \\"Helvetica\\", \\"Arial\\", sans-serif", + "fontSize": "1.25rem", + "fontWeight": 500, + "letterSpacing": "0.0075em", + "lineHeight": 1.6, + }, + "htmlFontSize": 16, + "overline": Object { + "fontFamily": "\\"Roboto\\", \\"Helvetica\\", \\"Arial\\", sans-serif", + "fontSize": "0.75rem", + "fontWeight": 400, + "letterSpacing": "0.08333em", + "lineHeight": 2.66, + "textTransform": "uppercase", + }, + "pxToRem": [Function], + "round": [Function], + "subtitle1": Object { + "fontFamily": "\\"Roboto\\", \\"Helvetica\\", \\"Arial\\", sans-serif", + "fontSize": "1rem", + "fontWeight": 400, + "letterSpacing": "0.00938em", + "lineHeight": 1.75, + }, + "subtitle2": Object { + "fontFamily": "\\"Roboto\\", \\"Helvetica\\", \\"Arial\\", sans-serif", + "fontSize": "0.875rem", + "fontWeight": 500, + "letterSpacing": "0.00714em", + "lineHeight": 1.57, }, }, - "name": "MuiBackdrop", - }, - "propTypes": Object { - "classes": [Function], - "innerRef": [Function], + "zIndex": Object { + "appBar": 1100, + "drawer": 1200, + "mobileStepper": 1000, + "modal": 1300, + "snackbar": 1400, + "speedDial": 1050, + "tooltip": 1500, + }, }, - "render": [Function], - "useStyles": [Function], - } + "name": "MuiBackdrop", + }, + "propTypes": Object { + "classes": [Function], + "innerRef": [Function], + }, + "render": [Function], + "useStyles": [Function], } - BackdropProps={ - Object { - "transitionDuration": Object { - "enter": 225, - "exit": 195, - }, - } + } + BackdropProps={ + Object { + "transitionDuration": Object { + "enter": 225, + "exit": 195, + }, } - className="MuiDialog-root modal-root" - closeAfterTransition={true} - disableEscapeKeyDown={true} - onClose={[Function]} - open={true} - style={ - Object { - "zIndex": 1500, - } + } + className="MuiDialog-root modal-root" + closeAfterTransition={true} + disableEscapeKeyDown={true} + onClose={[Function]} + open={true} + style={ + Object { + "zIndex": 1500, } + } + > + <ForwardRef(Portal) + disablePortal={false} > - <ForwardRef(Portal) - disablePortal={false} - > - <Portal - containerInfo={ - <body - style="padding-right: 0px; overflow: hidden;" + <Portal + containerInfo={ + <body + style="padding-right: 0px; overflow: hidden;" + > + <div + class="MuiDialog-root modal-root" + role="presentation" + style="position: fixed; z-index: 1500; right: 0px; bottom: 0px; top: 0px; left: 0px;" > <div - class="MuiDialog-root modal-root" - role="presentation" - style="position: fixed; z-index: 1500; right: 0px; bottom: 0px; top: 0px; left: 0px;" + aria-hidden="true" + class="MuiBackdrop-root" + style="opacity: 1; webkit-transition: opacity 225ms cubic-bezier(0.4, 0, 0.2, 1) 0ms; transition: opacity 225ms cubic-bezier(0.4, 0, 0.2, 1) 0ms;" + /> + <div + data-test="sentinelStart" + tabindex="0" + /> + <div + class="MuiDialog-container MuiDialog-scrollPaper" + role="none presentation" + style="opacity: 1; webkit-transition: opacity 225ms cubic-bezier(0.4, 0, 0.2, 1) 0ms; transition: opacity 225ms cubic-bezier(0.4, 0, 0.2, 1) 0ms;" + tabindex="-1" > <div - aria-hidden="true" - class="MuiBackdrop-root" - style="opacity: 1; webkit-transition: opacity 225ms cubic-bezier(0.4, 0, 0.2, 1) 0ms; transition: opacity 225ms cubic-bezier(0.4, 0, 0.2, 1) 0ms;" - /> - <div - data-test="sentinelStart" - tabindex="0" - /> - <div - class="MuiDialog-container MuiDialog-scrollPaper" - role="none presentation" - style="opacity: 1; webkit-transition: opacity 225ms cubic-bezier(0.4, 0, 0.2, 1) 0ms; transition: opacity 225ms cubic-bezier(0.4, 0, 0.2, 1) 0ms;" - tabindex="-1" + aria-labelledby="accessibility-title" + class="MuiPaper-root MuiDialog-paper modal-paper MuiDialog-paperScrollPaper MuiDialog-paperWidthSm MuiPaper-elevation24 MuiPaper-rounded" + role="dialog" > <div - aria-labelledby="accessibility-title" - class="MuiPaper-root MuiDialog-paper modal-paper MuiDialog-paperScrollPaper MuiDialog-paperWidthSm MuiPaper-elevation24 MuiPaper-rounded" - role="dialog" + id="accessibility-title" + > + feedback.accessibility.window_title + </div> + <button + aria-label="feedback.accessibility.button_close" + class="MuiButtonBase-root MuiIconButton-root modal-paper-close-button" + tabindex="0" + type="button" + > + <span + class="MuiIconButton-label" + > + <svg + class="styles__icon___23x3R" + height="16" + width="16" + > + <use + xlink:href="#test-file-stub" + /> + </svg> + </span> + <span + class="MuiTouchRipple-root" + /> + </button> + <div + class="partnerIssueModal" > + <svg + aria-hidden="true" + class="warn-icon styles__icon___23x3R" + height="40" + width="40" + > + <use + xlink:href="#test-file-stub" + /> + </svg> + <div + class="partner-issue-title text-20-bold" + > + consumption.partner_issue_modal.title + </div> <div - id="accessibility-title" + class="partner-issue-content text-16-normal" > - feedback.accessibility.window_title + consumption.partner_issue_modal.error_connect_elec + </div> + <br /> + <div> + consumption.partner_issue_modal.additional_text </div> <button - aria-label="feedback.accessibility.button_close" - class="MuiButtonBase-root MuiIconButton-root modal-paper-close-button" + class="MuiButtonBase-root MuiButton-root btn-highlight MuiButton-text" tabindex="0" type="button" > <span - class="MuiIconButton-label" + class="MuiButton-label text-16-bold" > - <svg - class="styles__icon___23x3R" - height="16" - width="16" - > - <use - xlink:href="#test-file-stub" - /> - </svg> + consumption.partner_issue_modal.ok </span> <span class="MuiTouchRipple-root" /> </button> - <div - class="partnerIssueModal" - > - <svg - aria-hidden="true" - class="warn-icon styles__icon___23x3R" - height="40" - width="40" - > - <use - xlink:href="#test-file-stub" - /> - </svg> - <div - class="partner-issue-title text-20-bold" - > - consumption.partner_issue_modal.title - </div> - <div - class="partner-issue-content text-16-normal" - > - consumption.partner_issue_modal.error_connect_elec - </div> - <br /> - <div> - consumption.partner_issue_modal.additional_text - </div> - <button - class="MuiButtonBase-root MuiButton-root btn-highlight MuiButton-text" - tabindex="0" - type="button" - > - <span - class="MuiButton-label text-16-bold" - > - consumption.partner_issue_modal.ok - </span> - <span - class="MuiTouchRipple-root" - /> - </button> - </div> </div> </div> - <div - data-test="sentinelEnd" - tabindex="0" - /> </div> - </body> + <div + data-test="sentinelEnd" + tabindex="0" + /> + </div> + </body> + } + > + <div + className="MuiDialog-root modal-root" + onKeyDown={[Function]} + role="presentation" + style={ + Object { + "bottom": 0, + "left": 0, + "position": "fixed", + "right": 0, + "top": 0, + "zIndex": 1500, + } } > - <div - className="MuiDialog-root modal-root" - onKeyDown={[Function]} - role="presentation" - style={ + <WithStyles(ForwardRef(Backdrop)) + onClick={[Function]} + open={true} + transitionDuration={ Object { - "bottom": 0, - "left": 0, - "position": "fixed", - "right": 0, - "top": 0, - "zIndex": 1500, + "enter": 225, + "exit": 195, } } > - <WithStyles(ForwardRef(Backdrop)) + <ForwardRef(Backdrop) + classes={ + Object { + "invisible": "MuiBackdrop-invisible", + "root": "MuiBackdrop-root", + } + } onClick={[Function]} open={true} transitionDuration={ @@ -561,85 +542,90 @@ exports[`PartnerIssueModal component should render correctly 1`] = ` } } > - <ForwardRef(Backdrop) - classes={ - Object { - "invisible": "MuiBackdrop-invisible", - "root": "MuiBackdrop-root", - } - } + <ForwardRef(Fade) + in={true} onClick={[Function]} - open={true} - transitionDuration={ + timeout={ Object { "enter": 225, "exit": 195, } } > - <ForwardRef(Fade) + <Transition + appear={true} + enter={true} + exit={true} in={true} + mountOnEnter={false} onClick={[Function]} + onEnter={[Function]} + onEntered={[Function]} + onEntering={[Function]} + onExit={[Function]} + onExited={[Function]} + onExiting={[Function]} timeout={ Object { "enter": 225, "exit": 195, } } + unmountOnExit={false} > - <Transition - appear={true} - enter={true} - exit={true} - in={true} - mountOnEnter={false} + <div + aria-hidden={true} + className="MuiBackdrop-root" onClick={[Function]} - onEnter={[Function]} - onEntered={[Function]} - onEntering={[Function]} - onExit={[Function]} - onExited={[Function]} - onExiting={[Function]} - timeout={ + style={ Object { - "enter": 225, - "exit": 195, + "opacity": 1, + "visibility": undefined, } } - unmountOnExit={false} - > - <div - aria-hidden={true} - className="MuiBackdrop-root" - onClick={[Function]} - style={ - Object { - "opacity": 1, - "visibility": undefined, - } - } - /> - </Transition> - </ForwardRef(Fade)> - </ForwardRef(Backdrop)> - </WithStyles(ForwardRef(Backdrop))> - <Unstable_TrapFocus - disableAutoFocus={false} - disableEnforceFocus={false} - disableRestoreFocus={false} - getDoc={[Function]} - isEnabled={[Function]} - open={true} + /> + </Transition> + </ForwardRef(Fade)> + </ForwardRef(Backdrop)> + </WithStyles(ForwardRef(Backdrop))> + <Unstable_TrapFocus + disableAutoFocus={false} + disableEnforceFocus={false} + disableRestoreFocus={false} + getDoc={[Function]} + isEnabled={[Function]} + open={true} + > + <div + data-test="sentinelStart" + tabIndex={0} + /> + <ForwardRef(Fade) + appear={true} + in={true} + onEnter={[Function]} + onExited={[Function]} + role="none presentation" + tabIndex="-1" + timeout={ + Object { + "enter": 225, + "exit": 195, + } + } > - <div - data-test="sentinelStart" - tabIndex={0} - /> - <ForwardRef(Fade) + <Transition appear={true} + enter={true} + exit={true} in={true} + mountOnEnter={false} onEnter={[Function]} + onEntered={[Function]} + onEntering={[Function]} + onExit={[Function]} onExited={[Function]} + onExiting={[Function]} role="none presentation" tabIndex="-1" timeout={ @@ -648,131 +634,313 @@ exports[`PartnerIssueModal component should render correctly 1`] = ` "exit": 195, } } + unmountOnExit={false} > - <Transition - appear={true} - enter={true} - exit={true} - in={true} - mountOnEnter={false} - onEnter={[Function]} - onEntered={[Function]} - onEntering={[Function]} - onExit={[Function]} - onExited={[Function]} - onExiting={[Function]} + <div + className="MuiDialog-container MuiDialog-scrollPaper" + onMouseDown={[Function]} + onMouseUp={[Function]} role="none presentation" - tabIndex="-1" - timeout={ + style={ Object { - "enter": 225, - "exit": 195, + "opacity": 1, + "visibility": undefined, } } - unmountOnExit={false} + tabIndex="-1" > - <div - className="MuiDialog-container MuiDialog-scrollPaper" - onMouseDown={[Function]} - onMouseUp={[Function]} - role="none presentation" - style={ - Object { - "opacity": 1, - "visibility": undefined, - } - } - tabIndex="-1" + <WithStyles(ForwardRef(Paper)) + aria-labelledby="accessibility-title" + className="MuiDialog-paper modal-paper MuiDialog-paperScrollPaper MuiDialog-paperWidthSm" + elevation={24} + role="dialog" > - <WithStyles(ForwardRef(Paper)) + <ForwardRef(Paper) aria-labelledby="accessibility-title" className="MuiDialog-paper modal-paper MuiDialog-paperScrollPaper MuiDialog-paperWidthSm" + classes={ + Object { + "elevation0": "MuiPaper-elevation0", + "elevation1": "MuiPaper-elevation1", + "elevation10": "MuiPaper-elevation10", + "elevation11": "MuiPaper-elevation11", + "elevation12": "MuiPaper-elevation12", + "elevation13": "MuiPaper-elevation13", + "elevation14": "MuiPaper-elevation14", + "elevation15": "MuiPaper-elevation15", + "elevation16": "MuiPaper-elevation16", + "elevation17": "MuiPaper-elevation17", + "elevation18": "MuiPaper-elevation18", + "elevation19": "MuiPaper-elevation19", + "elevation2": "MuiPaper-elevation2", + "elevation20": "MuiPaper-elevation20", + "elevation21": "MuiPaper-elevation21", + "elevation22": "MuiPaper-elevation22", + "elevation23": "MuiPaper-elevation23", + "elevation24": "MuiPaper-elevation24", + "elevation3": "MuiPaper-elevation3", + "elevation4": "MuiPaper-elevation4", + "elevation5": "MuiPaper-elevation5", + "elevation6": "MuiPaper-elevation6", + "elevation7": "MuiPaper-elevation7", + "elevation8": "MuiPaper-elevation8", + "elevation9": "MuiPaper-elevation9", + "outlined": "MuiPaper-outlined", + "root": "MuiPaper-root", + "rounded": "MuiPaper-rounded", + } + } elevation={24} role="dialog" > - <ForwardRef(Paper) + <div aria-labelledby="accessibility-title" - className="MuiDialog-paper modal-paper MuiDialog-paperScrollPaper MuiDialog-paperWidthSm" - classes={ - Object { - "elevation0": "MuiPaper-elevation0", - "elevation1": "MuiPaper-elevation1", - "elevation10": "MuiPaper-elevation10", - "elevation11": "MuiPaper-elevation11", - "elevation12": "MuiPaper-elevation12", - "elevation13": "MuiPaper-elevation13", - "elevation14": "MuiPaper-elevation14", - "elevation15": "MuiPaper-elevation15", - "elevation16": "MuiPaper-elevation16", - "elevation17": "MuiPaper-elevation17", - "elevation18": "MuiPaper-elevation18", - "elevation19": "MuiPaper-elevation19", - "elevation2": "MuiPaper-elevation2", - "elevation20": "MuiPaper-elevation20", - "elevation21": "MuiPaper-elevation21", - "elevation22": "MuiPaper-elevation22", - "elevation23": "MuiPaper-elevation23", - "elevation24": "MuiPaper-elevation24", - "elevation3": "MuiPaper-elevation3", - "elevation4": "MuiPaper-elevation4", - "elevation5": "MuiPaper-elevation5", - "elevation6": "MuiPaper-elevation6", - "elevation7": "MuiPaper-elevation7", - "elevation8": "MuiPaper-elevation8", - "elevation9": "MuiPaper-elevation9", - "outlined": "MuiPaper-outlined", - "root": "MuiPaper-root", - "rounded": "MuiPaper-rounded", - } - } - elevation={24} + className="MuiPaper-root MuiDialog-paper modal-paper MuiDialog-paperScrollPaper MuiDialog-paperWidthSm MuiPaper-elevation24 MuiPaper-rounded" role="dialog" > <div - aria-labelledby="accessibility-title" - className="MuiPaper-root MuiDialog-paper modal-paper MuiDialog-paperScrollPaper MuiDialog-paperWidthSm MuiPaper-elevation24 MuiPaper-rounded" - role="dialog" + id="accessibility-title" > - <div - id="accessibility-title" - > - feedback.accessibility.window_title - </div> - <WithStyles(ForwardRef(IconButton)) + feedback.accessibility.window_title + </div> + <WithStyles(ForwardRef(IconButton)) + aria-label="feedback.accessibility.button_close" + className="modal-paper-close-button" + onClick={[Function]} + > + <ForwardRef(IconButton) aria-label="feedback.accessibility.button_close" className="modal-paper-close-button" + classes={ + Object { + "colorInherit": "MuiIconButton-colorInherit", + "colorPrimary": "MuiIconButton-colorPrimary", + "colorSecondary": "MuiIconButton-colorSecondary", + "disabled": "Mui-disabled", + "edgeEnd": "MuiIconButton-edgeEnd", + "edgeStart": "MuiIconButton-edgeStart", + "label": "MuiIconButton-label", + "root": "MuiIconButton-root", + "sizeSmall": "MuiIconButton-sizeSmall", + } + } onClick={[Function]} > - <ForwardRef(IconButton) + <WithStyles(ForwardRef(ButtonBase)) aria-label="feedback.accessibility.button_close" - className="modal-paper-close-button" + centerRipple={true} + className="MuiIconButton-root modal-paper-close-button" + disabled={false} + focusRipple={true} + onClick={[Function]} + > + <ForwardRef(ButtonBase) + aria-label="feedback.accessibility.button_close" + centerRipple={true} + className="MuiIconButton-root modal-paper-close-button" + classes={ + Object { + "disabled": "Mui-disabled", + "focusVisible": "Mui-focusVisible", + "root": "MuiButtonBase-root", + } + } + disabled={false} + focusRipple={true} + onClick={[Function]} + > + <button + aria-label="feedback.accessibility.button_close" + className="MuiButtonBase-root MuiIconButton-root modal-paper-close-button" + disabled={false} + onBlur={[Function]} + onClick={[Function]} + onDragLeave={[Function]} + onFocus={[Function]} + onKeyDown={[Function]} + onKeyUp={[Function]} + onMouseDown={[Function]} + onMouseLeave={[Function]} + onMouseUp={[Function]} + onTouchEnd={[Function]} + onTouchMove={[Function]} + onTouchStart={[Function]} + tabIndex={0} + type="button" + > + <span + className="MuiIconButton-label" + > + <Icon + icon="test-file-stub" + size={16} + spin={false} + > + <Component + className="styles__icon___23x3R" + height={16} + style={Object {}} + width={16} + > + <svg + className="styles__icon___23x3R" + height={16} + style={Object {}} + width={16} + > + <use + xlinkHref="#test-file-stub" + /> + </svg> + </Component> + </Icon> + </span> + <WithStyles(memo) + center={true} + > + <ForwardRef(TouchRipple) + center={true} + classes={ + Object { + "child": "MuiTouchRipple-child", + "childLeaving": "MuiTouchRipple-childLeaving", + "childPulsate": "MuiTouchRipple-childPulsate", + "ripple": "MuiTouchRipple-ripple", + "ripplePulsate": "MuiTouchRipple-ripplePulsate", + "rippleVisible": "MuiTouchRipple-rippleVisible", + "root": "MuiTouchRipple-root", + } + } + > + <span + className="MuiTouchRipple-root" + > + <TransitionGroup + childFactory={[Function]} + component={null} + exit={true} + /> + </span> + </ForwardRef(TouchRipple)> + </WithStyles(memo)> + </button> + </ForwardRef(ButtonBase)> + </WithStyles(ForwardRef(ButtonBase))> + </ForwardRef(IconButton)> + </WithStyles(ForwardRef(IconButton))> + <div + className="partnerIssueModal" + > + <StyledIcon + className="warn-icon" + icon="test-file-stub" + size={40} + > + <Icon + aria-hidden={true} + className="warn-icon" + icon="test-file-stub" + size={40} + spin={false} + > + <Component + aria-hidden={true} + className="warn-icon styles__icon___23x3R" + height={40} + style={Object {}} + width={40} + > + <svg + aria-hidden={true} + className="warn-icon styles__icon___23x3R" + height={40} + style={Object {}} + width={40} + > + <use + xlinkHref="#test-file-stub" + /> + </svg> + </Component> + </Icon> + </StyledIcon> + <div + className="partner-issue-title text-20-bold" + > + consumption.partner_issue_modal.title + </div> + <div + className="partner-issue-content text-16-normal" + dangerouslySetInnerHTML={ + Object { + "__html": "consumption.partner_issue_modal.error_connect_elec", + } + } + /> + <br /> + <div + dangerouslySetInnerHTML={ + Object { + "__html": "consumption.partner_issue_modal.additional_text", + } + } + /> + <WithStyles(ForwardRef(Button)) + classes={ + Object { + "label": "text-16-bold", + "root": "btn-highlight", + } + } + onClick={[Function]} + > + <ForwardRef(Button) classes={ Object { - "colorInherit": "MuiIconButton-colorInherit", - "colorPrimary": "MuiIconButton-colorPrimary", - "colorSecondary": "MuiIconButton-colorSecondary", + "colorInherit": "MuiButton-colorInherit", + "contained": "MuiButton-contained", + "containedPrimary": "MuiButton-containedPrimary", + "containedSecondary": "MuiButton-containedSecondary", + "containedSizeLarge": "MuiButton-containedSizeLarge", + "containedSizeSmall": "MuiButton-containedSizeSmall", + "disableElevation": "MuiButton-disableElevation", "disabled": "Mui-disabled", - "edgeEnd": "MuiIconButton-edgeEnd", - "edgeStart": "MuiIconButton-edgeStart", - "label": "MuiIconButton-label", - "root": "MuiIconButton-root", - "sizeSmall": "MuiIconButton-sizeSmall", + "endIcon": "MuiButton-endIcon", + "focusVisible": "Mui-focusVisible", + "fullWidth": "MuiButton-fullWidth", + "iconSizeLarge": "MuiButton-iconSizeLarge", + "iconSizeMedium": "MuiButton-iconSizeMedium", + "iconSizeSmall": "MuiButton-iconSizeSmall", + "label": "MuiButton-label text-16-bold", + "outlined": "MuiButton-outlined", + "outlinedPrimary": "MuiButton-outlinedPrimary", + "outlinedSecondary": "MuiButton-outlinedSecondary", + "outlinedSizeLarge": "MuiButton-outlinedSizeLarge", + "outlinedSizeSmall": "MuiButton-outlinedSizeSmall", + "root": "MuiButton-root btn-highlight", + "sizeLarge": "MuiButton-sizeLarge", + "sizeSmall": "MuiButton-sizeSmall", + "startIcon": "MuiButton-startIcon", + "text": "MuiButton-text", + "textPrimary": "MuiButton-textPrimary", + "textSecondary": "MuiButton-textSecondary", + "textSizeLarge": "MuiButton-textSizeLarge", + "textSizeSmall": "MuiButton-textSizeSmall", } } onClick={[Function]} > <WithStyles(ForwardRef(ButtonBase)) - aria-label="feedback.accessibility.button_close" - centerRipple={true} - className="MuiIconButton-root modal-paper-close-button" + className="MuiButton-root btn-highlight MuiButton-text" + component="button" disabled={false} focusRipple={true} + focusVisibleClassName="Mui-focusVisible" onClick={[Function]} + type="button" > <ForwardRef(ButtonBase) - aria-label="feedback.accessibility.button_close" - centerRipple={true} - className="MuiIconButton-root modal-paper-close-button" + className="MuiButton-root btn-highlight MuiButton-text" classes={ Object { "disabled": "Mui-disabled", @@ -780,13 +948,15 @@ exports[`PartnerIssueModal component should render correctly 1`] = ` "root": "MuiButtonBase-root", } } + component="button" disabled={false} focusRipple={true} + focusVisibleClassName="Mui-focusVisible" onClick={[Function]} + type="button" > <button - aria-label="feedback.accessibility.button_close" - className="MuiButtonBase-root MuiIconButton-root modal-paper-close-button" + className="MuiButtonBase-root MuiButton-root btn-highlight MuiButton-text" disabled={false} onBlur={[Function]} onClick={[Function]} @@ -804,37 +974,15 @@ exports[`PartnerIssueModal component should render correctly 1`] = ` type="button" > <span - className="MuiIconButton-label" + className="MuiButton-label text-16-bold" > - <Icon - icon="test-file-stub" - size={16} - spin={false} - > - <Component - className="styles__icon___23x3R" - height={16} - style={Object {}} - width={16} - > - <svg - className="styles__icon___23x3R" - height={16} - style={Object {}} - width={16} - > - <use - xlinkHref="#test-file-stub" - /> - </svg> - </Component> - </Icon> + consumption.partner_issue_modal.ok </span> <WithStyles(memo) - center={true} + center={false} > <ForwardRef(TouchRipple) - center={true} + center={false} classes={ Object { "child": "MuiTouchRipple-child", @@ -861,209 +1009,25 @@ exports[`PartnerIssueModal component should render correctly 1`] = ` </button> </ForwardRef(ButtonBase)> </WithStyles(ForwardRef(ButtonBase))> - </ForwardRef(IconButton)> - </WithStyles(ForwardRef(IconButton))> - <div - className="partnerIssueModal" - > - <StyledIcon - className="warn-icon" - icon="test-file-stub" - size={40} - > - <Icon - aria-hidden={true} - className="warn-icon" - icon="test-file-stub" - size={40} - spin={false} - > - <Component - aria-hidden={true} - className="warn-icon styles__icon___23x3R" - height={40} - style={Object {}} - width={40} - > - <svg - aria-hidden={true} - className="warn-icon styles__icon___23x3R" - height={40} - style={Object {}} - width={40} - > - <use - xlinkHref="#test-file-stub" - /> - </svg> - </Component> - </Icon> - </StyledIcon> - <div - className="partner-issue-title text-20-bold" - > - consumption.partner_issue_modal.title - </div> - <div - className="partner-issue-content text-16-normal" - dangerouslySetInnerHTML={ - Object { - "__html": "consumption.partner_issue_modal.error_connect_elec", - } - } - /> - <br /> - <div - dangerouslySetInnerHTML={ - Object { - "__html": "consumption.partner_issue_modal.additional_text", - } - } - /> - <WithStyles(ForwardRef(Button)) - classes={ - Object { - "label": "text-16-bold", - "root": "btn-highlight", - } - } - onClick={[Function]} - > - <ForwardRef(Button) - classes={ - Object { - "colorInherit": "MuiButton-colorInherit", - "contained": "MuiButton-contained", - "containedPrimary": "MuiButton-containedPrimary", - "containedSecondary": "MuiButton-containedSecondary", - "containedSizeLarge": "MuiButton-containedSizeLarge", - "containedSizeSmall": "MuiButton-containedSizeSmall", - "disableElevation": "MuiButton-disableElevation", - "disabled": "Mui-disabled", - "endIcon": "MuiButton-endIcon", - "focusVisible": "Mui-focusVisible", - "fullWidth": "MuiButton-fullWidth", - "iconSizeLarge": "MuiButton-iconSizeLarge", - "iconSizeMedium": "MuiButton-iconSizeMedium", - "iconSizeSmall": "MuiButton-iconSizeSmall", - "label": "MuiButton-label text-16-bold", - "outlined": "MuiButton-outlined", - "outlinedPrimary": "MuiButton-outlinedPrimary", - "outlinedSecondary": "MuiButton-outlinedSecondary", - "outlinedSizeLarge": "MuiButton-outlinedSizeLarge", - "outlinedSizeSmall": "MuiButton-outlinedSizeSmall", - "root": "MuiButton-root btn-highlight", - "sizeLarge": "MuiButton-sizeLarge", - "sizeSmall": "MuiButton-sizeSmall", - "startIcon": "MuiButton-startIcon", - "text": "MuiButton-text", - "textPrimary": "MuiButton-textPrimary", - "textSecondary": "MuiButton-textSecondary", - "textSizeLarge": "MuiButton-textSizeLarge", - "textSizeSmall": "MuiButton-textSizeSmall", - } - } - onClick={[Function]} - > - <WithStyles(ForwardRef(ButtonBase)) - className="MuiButton-root btn-highlight MuiButton-text" - component="button" - disabled={false} - focusRipple={true} - focusVisibleClassName="Mui-focusVisible" - onClick={[Function]} - type="button" - > - <ForwardRef(ButtonBase) - className="MuiButton-root btn-highlight MuiButton-text" - classes={ - Object { - "disabled": "Mui-disabled", - "focusVisible": "Mui-focusVisible", - "root": "MuiButtonBase-root", - } - } - component="button" - disabled={false} - focusRipple={true} - focusVisibleClassName="Mui-focusVisible" - onClick={[Function]} - type="button" - > - <button - className="MuiButtonBase-root MuiButton-root btn-highlight MuiButton-text" - disabled={false} - onBlur={[Function]} - onClick={[Function]} - onDragLeave={[Function]} - onFocus={[Function]} - onKeyDown={[Function]} - onKeyUp={[Function]} - onMouseDown={[Function]} - onMouseLeave={[Function]} - onMouseUp={[Function]} - onTouchEnd={[Function]} - onTouchMove={[Function]} - onTouchStart={[Function]} - tabIndex={0} - type="button" - > - <span - className="MuiButton-label text-16-bold" - > - consumption.partner_issue_modal.ok - </span> - <WithStyles(memo) - center={false} - > - <ForwardRef(TouchRipple) - center={false} - classes={ - Object { - "child": "MuiTouchRipple-child", - "childLeaving": "MuiTouchRipple-childLeaving", - "childPulsate": "MuiTouchRipple-childPulsate", - "ripple": "MuiTouchRipple-ripple", - "ripplePulsate": "MuiTouchRipple-ripplePulsate", - "rippleVisible": "MuiTouchRipple-rippleVisible", - "root": "MuiTouchRipple-root", - } - } - > - <span - className="MuiTouchRipple-root" - > - <TransitionGroup - childFactory={[Function]} - component={null} - exit={true} - /> - </span> - </ForwardRef(TouchRipple)> - </WithStyles(memo)> - </button> - </ForwardRef(ButtonBase)> - </WithStyles(ForwardRef(ButtonBase))> - </ForwardRef(Button)> - </WithStyles(ForwardRef(Button))> - </div> + </ForwardRef(Button)> + </WithStyles(ForwardRef(Button))> </div> - </ForwardRef(Paper)> - </WithStyles(ForwardRef(Paper))> - </div> - </Transition> - </ForwardRef(Fade)> - <div - data-test="sentinelEnd" - tabIndex={0} - /> - </Unstable_TrapFocus> - </div> - </Portal> - </ForwardRef(Portal)> - </ForwardRef(Modal)> - </ForwardRef(Dialog)> - </WithStyles(ForwardRef(Dialog))> - </PartnerIssueModal> -</Provider> + </div> + </ForwardRef(Paper)> + </WithStyles(ForwardRef(Paper))> + </div> + </Transition> + </ForwardRef(Fade)> + <div + data-test="sentinelEnd" + tabIndex={0} + /> + </Unstable_TrapFocus> + </div> + </Portal> + </ForwardRef(Portal)> + </ForwardRef(Modal)> + </ForwardRef(Dialog)> + </WithStyles(ForwardRef(Dialog))> +</PartnerIssueModal> `; diff --git a/src/components/PartnerIssue/partnerIssueModal.scss b/src/components/PartnerIssue/partnerIssueModal.scss index 5ffa04a87f5eaae4394bdc6494905d9474423426..7ddf1e1b2ed045a8d36a1997fcb6f55dd16fe7c1 100644 --- a/src/components/PartnerIssue/partnerIssueModal.scss +++ b/src/components/PartnerIssue/partnerIssueModal.scss @@ -1,5 +1,5 @@ -@import '../../styles/base/typo-variables'; -@import '../../styles/base/color'; +@import 'src/styles/base/typo-variables'; +@import 'src/styles/base/color'; .partnerIssueModal { padding: 1rem; diff --git a/src/components/ProfileType/ProfileTypeFinished.spec.tsx b/src/components/ProfileType/ProfileTypeFinished/ProfileTypeFinished.spec.tsx similarity index 72% rename from src/components/ProfileType/ProfileTypeFinished.spec.tsx rename to src/components/ProfileType/ProfileTypeFinished/ProfileTypeFinished.spec.tsx index 0b4dda62045cb71531415c19515d58f3d05a7d67..efaf28189242e8be1aaa2611bf7560d58c607686 100644 --- a/src/components/ProfileType/ProfileTypeFinished.spec.tsx +++ b/src/components/ProfileType/ProfileTypeFinished/ProfileTypeFinished.spec.tsx @@ -3,12 +3,11 @@ import { mount } from 'enzyme' import React from 'react' import { Provider } from 'react-redux' import UsageEventService from 'services/usageEvent.service' -import { mockProfileType } from '../../../tests/__mocks__/profileType.mock' -import { createMockEcolyoStore } from '../../../tests/__mocks__/store' +import { mockProfileType } from 'tests/__mocks__/profileType.mock' +import { createMockEcolyoStore } from 'tests/__mocks__/store' import ProfileTypeFinished from './ProfileTypeFinished' const mockedNavigate = jest.fn() - jest.mock('react-router-dom', () => ({ ...jest.requireActual('react-router-dom'), useLocation: () => ({ @@ -16,15 +15,7 @@ jest.mock('react-router-dom', () => ({ }), useNavigate: () => mockedNavigate, })) -jest.mock('cozy-ui/transpiled/react/I18n', () => { - return { - useI18n: jest.fn(() => { - return { - t: (str: string) => str, - } - }), - } -}) + const mockAddEvent = jest.fn() jest.mock('services/usageEvent.service') UsageEventService.addEvent = mockAddEvent @@ -32,18 +23,15 @@ UsageEventService.addEvent = mockAddEvent const mockGetAllProfileTypes = jest.fn() const mockDeleteProfileTypes = jest.fn() jest.mock('services/profileTypeEntity.service', () => { - return jest.fn(() => { - return { - getAllProfileTypes: mockGetAllProfileTypes, - deleteProfileTypes: mockDeleteProfileTypes, - } - }) + return jest.fn(() => ({ + getAllProfileTypes: mockGetAllProfileTypes, + deleteProfileTypes: mockDeleteProfileTypes, + })) }) describe('ProfileTypeFinished component', () => { const store = createMockEcolyoStore() beforeEach(() => { - store.clearActions() jest.clearAllMocks() }) diff --git a/src/components/ProfileType/ProfileTypeFinished.tsx b/src/components/ProfileType/ProfileTypeFinished/ProfileTypeFinished.tsx similarity index 81% rename from src/components/ProfileType/ProfileTypeFinished.tsx rename to src/components/ProfileType/ProfileTypeFinished/ProfileTypeFinished.tsx index c47d58667093a21e73439766aeaff0f0fb7f25f3..f4b2f0ef36f99fe06ef170bae22613f63cbf55d0 100644 --- a/src/components/ProfileType/ProfileTypeFinished.tsx +++ b/src/components/ProfileType/ProfileTypeFinished/ProfileTypeFinished.tsx @@ -3,35 +3,32 @@ import * as Sentry from '@sentry/react' import finishIcon from 'assets/icons/visu/profileType/finish.svg' import StyledIcon from 'components/CommonKit/Icon/StyledIcon' import useExploration from 'components/Hooks/useExploration' -import 'components/ProfileType/profileTypeFinished.scss' import { Client, useClient } from 'cozy-client' import { useI18n } from 'cozy-ui/transpiled/react/I18n' import { PROFILETYPE_DOCTYPE } from 'doctypes' -import { UsageEventType } from 'enum/usageEvent.enum' -import { UserExplorationID } from 'enum/userExploration.enum' +import { UsageEventType, UserExplorationID } from 'enums' import { DateTime } from 'luxon' -import { TimePeriod } from 'models' -import { ProfileType } from 'models/profileType.model' -import React, { Dispatch, useEffect, useState } from 'react' -import { useDispatch, useSelector } from 'react-redux' +import { ProfileType, TimePeriod } from 'models' +import React, { useEffect, useState } from 'react' import { useLocation, useNavigate } from 'react-router-dom' import ProfileTypeService from 'services/profileType.service' import ProfileTypeEntityService from 'services/profileTypeEntity.service' import UsageEventService from 'services/usageEvent.service' -import { AppActionsTypes, AppStore } from 'store' -import { updateProfile } from 'store/profile/profile.actions' +import { useAppDispatch, useAppSelector } from 'store/hooks' +import { updateProfile } from 'store/profile/profile.slice' import { setProfileType } from 'store/profileType/profileType.slice' +import './profileTypeFinished.scss' const ProfileTypeFinished = ({ profileType }: { profileType: ProfileType }) => { const { t } = useI18n() + const client = useClient() const location = useLocation() - const dispatch = useDispatch<Dispatch<AppActionsTypes>>() const navigate = useNavigate() - const client = useClient() + const dispatch = useAppDispatch() const { challenge: { currentChallenge }, profile, - } = useSelector((state: AppStore) => state.ecolyo) + } = useAppSelector(state => state.ecolyo) const handleClick = () => { if (location?.pathname === '/ecogesture-form') { navigate('/ecogesture-selection') @@ -124,23 +121,19 @@ const ProfileTypeFinished = ({ profileType }: { profileType: ProfileType }) => { ]) return ( - <div className={'profile-type-finished-card'}> - <StyledIcon - className={'profile-type-icon'} - icon={finishIcon} - size={120} - /> - <div className={'profile-type-finished-label text-28-normal-uppercase'}> + <div className="profile-type-finished-card"> + <StyledIcon className="profile-type-icon" icon={finishIcon} size={120} /> + <div className="profile-type-finished-label text-28-normal-uppercase"> {t('profile_type.finished.title')} </div> - <div className={'profile-type-finished-description text-18-normal'}> + <div className="profile-type-finished-description text-18-normal"> <div>{t('profile_type.finished.label1')}</div> <div>{t('profile_type.finished.label2')}</div> </div> <Button aria-label={t('profile_type.accessibility.button_validate')} onClick={handleClick} - className={'profile-type-finished-button'} + className="profile-type-finished-button" classes={{ root: 'btn-primary-positive', label: 'text-16-normal', diff --git a/src/components/ProfileType/profileTypeFinished.scss b/src/components/ProfileType/ProfileTypeFinished/profileTypeFinished.scss similarity index 88% rename from src/components/ProfileType/profileTypeFinished.scss rename to src/components/ProfileType/ProfileTypeFinished/profileTypeFinished.scss index 9aa4e25053e8ac82478b106f00d38bacff39eece..7e0d427a6bb9836df23a6d854719557266099055 100644 --- a/src/components/ProfileType/profileTypeFinished.scss +++ b/src/components/ProfileType/ProfileTypeFinished/profileTypeFinished.scss @@ -1,5 +1,5 @@ -@import '../../styles/base/color'; -@import '../../styles/base/breakpoint'; +@import 'src/styles/base/color'; +@import 'src/styles/base/breakpoint'; .profile-type-finished-card { margin: auto; diff --git a/src/components/ProfileType/ProfileTypeFormDateSelection.tsx b/src/components/ProfileType/ProfileTypeFormDateSelection/ProfileTypeFormDateSelection.tsx similarity index 91% rename from src/components/ProfileType/ProfileTypeFormDateSelection.tsx rename to src/components/ProfileType/ProfileTypeFormDateSelection/ProfileTypeFormDateSelection.tsx index d9b203f0cc59a06ce30e2893d5158875694bfb66..cad6e9cd5bf3bbbc8667035c66386b49a4ecf5b4 100644 --- a/src/components/ProfileType/ProfileTypeFormDateSelection.tsx +++ b/src/components/ProfileType/ProfileTypeFormDateSelection/ProfileTypeFormDateSelection.tsx @@ -1,15 +1,11 @@ import { MenuItem, Select } from '@material-ui/core' -import FormNavigation from 'components/FormGlobal/FormNavigation' -import FormProgress from 'components/FormGlobal/FormProgress' +import FormNavigation from 'components/CommonKit/FormNavigation/FormNavigation' +import FormProgress from 'components/CommonKit/FormProgress/FormProgress' import 'components/ProfileType/profileTypeForm.scss' import { useI18n } from 'cozy-ui/transpiled/react/I18n' -import { ProfileTypeStepForm } from 'enum/profileType.enum' +import { ProfileTypeStepForm } from 'enums' import { DateTime } from 'luxon' -import { - ProfileType, - ProfileTypeAnswer, - ProfileTypeValues, -} from 'models/profileType.model' +import { ProfileType, ProfileTypeAnswer, ProfileTypeValues } from 'models' import React, { useCallback, useState } from 'react' import { getMonthFullName } from 'utils/utils' @@ -134,9 +130,9 @@ const ProfileTypeFormDateSelection = ({ return ( <> - <div className={'profile-form-container'}> - <FormProgress step={step} formType={'profile'} /> - <div className={'profile-question-label'}> + <div className="profile-form-container"> + <FormProgress step={step} formType="profile" /> + <div className="profile-question-label"> {t( `profile_type.${ProfileTypeStepForm[step].toLowerCase()}.question` )} diff --git a/src/components/ProfileType/ProfileTypeFormMultiChoice.spec.tsx b/src/components/ProfileType/ProfileTypeFormMultiChoice.spec.tsx deleted file mode 100644 index 5d4160e1f38963231dc63c36589da244c8c7713d..0000000000000000000000000000000000000000 --- a/src/components/ProfileType/ProfileTypeFormMultiChoice.spec.tsx +++ /dev/null @@ -1,51 +0,0 @@ -import { ProfileTypeStepForm } from 'enum/profileType.enum' -import { mount } from 'enzyme' -import React from 'react' -import { Provider } from 'react-redux' -import { - mockProfileType, - mockProfileTypeAnswers, -} from '../../../tests/__mocks__/profileType.mock' -import { createMockEcolyoStore } from '../../../tests/__mocks__/store' -import ProfileTypeFormMultiChoice from './ProfileTypeFormMultiChoice' - -jest.mock('cozy-ui/transpiled/react/I18n', () => { - return { - useI18n: jest.fn(() => { - return { - t: (str: string) => str, - } - }), - } -}) - -const mockedNavigate = jest.fn() -jest.mock('react-router-dom', () => ({ - ...jest.requireActual('react-router-dom'), - useNavigate: () => mockedNavigate, -})) - -describe('ProfileTypeFormMultiChoice component', () => { - const store = createMockEcolyoStore() - beforeEach(() => { - store.clearActions() - }) - - it('should be rendered correctly', () => { - const mockhandlePrevious = jest.fn() - const mockhandleNext = jest.fn() - const wrapper = mount( - <Provider store={store}> - <ProfileTypeFormMultiChoice - step={ProfileTypeStepForm.COOKING_FLUID} - viewedStep={ProfileTypeStepForm.AREA} - currentProfileType={mockProfileType} - answerType={mockProfileTypeAnswers[1]} - setNextStep={mockhandlePrevious} - setPreviousStep={mockhandleNext} - /> - </Provider> - ) - expect(wrapper.find('input')).toBeTruthy() - }) -}) diff --git a/src/components/ProfileType/ProfileTypeFormMultiChoice/ProfileTypeFormMultiChoice.spec.tsx b/src/components/ProfileType/ProfileTypeFormMultiChoice/ProfileTypeFormMultiChoice.spec.tsx new file mode 100644 index 0000000000000000000000000000000000000000..4abad2652cce93fb255da34448fda9a142e631cc --- /dev/null +++ b/src/components/ProfileType/ProfileTypeFormMultiChoice/ProfileTypeFormMultiChoice.spec.tsx @@ -0,0 +1,33 @@ +import { ProfileTypeStepForm } from 'enums' +import { mount } from 'enzyme' +import React from 'react' +import { Provider } from 'react-redux' +import { + mockProfileType, + mockProfileTypeAnswers, +} from 'tests/__mocks__/profileType.mock' +import { createMockEcolyoStore } from 'tests/__mocks__/store' +import ProfileTypeFormMultiChoice from './ProfileTypeFormMultiChoice' + +const mockHandlePrevious = jest.fn() +const mockHandleNext = jest.fn() + +describe('ProfileTypeFormMultiChoice component', () => { + const store = createMockEcolyoStore() + + it('should be rendered correctly', () => { + const wrapper = mount( + <Provider store={store}> + <ProfileTypeFormMultiChoice + step={ProfileTypeStepForm.COOKING_FLUID} + viewedStep={ProfileTypeStepForm.AREA} + currentProfileType={mockProfileType} + answerType={mockProfileTypeAnswers[1]} + setNextStep={mockHandlePrevious} + setPreviousStep={mockHandleNext} + /> + </Provider> + ) + expect(wrapper.find('input')).toBeTruthy() + }) +}) diff --git a/src/components/ProfileType/ProfileTypeFormMultiChoice.tsx b/src/components/ProfileType/ProfileTypeFormMultiChoice/ProfileTypeFormMultiChoice.tsx similarity index 83% rename from src/components/ProfileType/ProfileTypeFormMultiChoice.tsx rename to src/components/ProfileType/ProfileTypeFormMultiChoice/ProfileTypeFormMultiChoice.tsx index 95c275ca6ed38d8739724fe4e400e87fb8f930c0..6a58102c477facedfdd91c2b89d8c7469af56e59 100644 --- a/src/components/ProfileType/ProfileTypeFormMultiChoice.tsx +++ b/src/components/ProfileType/ProfileTypeFormMultiChoice/ProfileTypeFormMultiChoice.tsx @@ -1,14 +1,13 @@ import classNames from 'classnames' -import FormNavigation from 'components/FormGlobal/FormNavigation' -import FormProgress from 'components/FormGlobal/FormProgress' +import FormNavigation from 'components/CommonKit/FormNavigation/FormNavigation' +import FormProgress from 'components/CommonKit/FormProgress/FormProgress' import 'components/ProfileType/profileTypeForm.scss' import { useI18n } from 'cozy-ui/transpiled/react/I18n' -import { ProfileTypeStepForm } from 'enum/profileType.enum' +import { ProfileTypeStepForm } from 'enums' import { remove } from 'lodash' -import { ProfileType, ProfileTypeAnswer } from 'models/profileType.model' +import { ProfileType, ProfileTypeAnswer } from 'models' import React, { useCallback, useEffect, useState } from 'react' -import { useSelector } from 'react-redux' -import { AppStore } from 'store' +import { useAppSelector } from 'store/hooks' interface ProfileTypeFormMultiChoiceProps { step: ProfileTypeStepForm @@ -28,8 +27,8 @@ const ProfileTypeFormMultiChoice = ({ setPreviousStep, }: ProfileTypeFormMultiChoiceProps) => { const { t } = useI18n() - const { isProfileTypeCompleted } = useSelector( - (state: AppStore) => state.ecolyo.profile + const { isProfileTypeCompleted } = useAppSelector( + state => state.ecolyo.profile ) const [answer, setAnswer] = useState<string[]>([]) @@ -74,9 +73,9 @@ const ProfileTypeFormMultiChoice = ({ return ( <> - <div className={'profile-form-container'}> - <FormProgress step={step} formType={'profile'} /> - <div className={'profile-question-label'}> + <div className="profile-form-container"> + <FormProgress step={step} formType="profile" /> + <div className="profile-question-label"> {t( `profile_type.${ProfileTypeStepForm[step].toLowerCase()}.question` )} @@ -95,7 +94,7 @@ const ProfileTypeFormMultiChoice = ({ })} > <input - type={'checkbox'} + type="checkbox" value={stringValue} name={stringValue} onChange={() => handleChange(stringValue)} diff --git a/src/components/ProfileType/ProfileTypeFormNumber.spec.tsx b/src/components/ProfileType/ProfileTypeFormNumber.spec.tsx deleted file mode 100644 index c9b0f6aea21672cb10525809e8994263ce43e914..0000000000000000000000000000000000000000 --- a/src/components/ProfileType/ProfileTypeFormNumber.spec.tsx +++ /dev/null @@ -1,50 +0,0 @@ -import { ProfileTypeStepForm } from 'enum/profileType.enum' -import { mount } from 'enzyme' -import React from 'react' -import { Provider } from 'react-redux' -import { - mockProfileType, - mockProfileTypeAnswers, -} from '../../../tests/__mocks__/profileType.mock' -import { createMockEcolyoStore } from '../../../tests/__mocks__/store' -import ProfileTypeFormNumber from './ProfileTypeFormNumber' - -jest.mock('cozy-ui/transpiled/react/I18n', () => { - return { - useI18n: jest.fn(() => { - return { - t: (str: string) => str, - } - }), - } -}) -const mockedNavigate = jest.fn() -jest.mock('react-router-dom', () => ({ - ...jest.requireActual('react-router-dom'), - useNavigate: () => mockedNavigate, -})) - -describe('ProfileTypeFormNumber component', () => { - const store = createMockEcolyoStore() - beforeEach(() => { - store.clearActions() - }) - - it('should be rendered correctly', () => { - const mockhandlePrevious = jest.fn() - const mockhandleNext = jest.fn() - const wrapper = mount( - <Provider store={store}> - <ProfileTypeFormNumber - step={ProfileTypeStepForm.COOKING_FLUID} - viewedStep={ProfileTypeStepForm.AREA} - currentProfileType={mockProfileType} - answerType={mockProfileTypeAnswers[1]} - setNextStep={mockhandlePrevious} - setPreviousStep={mockhandleNext} - /> - </Provider> - ) - expect(wrapper.find('input')).toBeTruthy() - }) -}) diff --git a/src/components/ProfileType/ProfileTypeFormNumber/ProfileTypeFormNumber.spec.tsx b/src/components/ProfileType/ProfileTypeFormNumber/ProfileTypeFormNumber.spec.tsx new file mode 100644 index 0000000000000000000000000000000000000000..f272691bbd6efd2744606f5d494b34c4a50c4b7f --- /dev/null +++ b/src/components/ProfileType/ProfileTypeFormNumber/ProfileTypeFormNumber.spec.tsx @@ -0,0 +1,33 @@ +import { ProfileTypeStepForm } from 'enums' +import { mount } from 'enzyme' +import React from 'react' +import { Provider } from 'react-redux' +import { + mockProfileType, + mockProfileTypeAnswers, +} from 'tests/__mocks__/profileType.mock' +import { createMockEcolyoStore } from 'tests/__mocks__/store' +import ProfileTypeFormNumber from './ProfileTypeFormNumber' + +const mockHandlePrevious = jest.fn() +const mockHandleNext = jest.fn() + +describe('ProfileTypeFormNumber component', () => { + const store = createMockEcolyoStore() + + it('should be rendered correctly', () => { + const wrapper = mount( + <Provider store={store}> + <ProfileTypeFormNumber + step={ProfileTypeStepForm.COOKING_FLUID} + viewedStep={ProfileTypeStepForm.AREA} + currentProfileType={mockProfileType} + answerType={mockProfileTypeAnswers[1]} + setNextStep={mockHandlePrevious} + setPreviousStep={mockHandleNext} + /> + </Provider> + ) + expect(wrapper.find('input')).toBeTruthy() + }) +}) diff --git a/src/components/ProfileType/ProfileTypeFormNumber.tsx b/src/components/ProfileType/ProfileTypeFormNumber/ProfileTypeFormNumber.tsx similarity index 72% rename from src/components/ProfileType/ProfileTypeFormNumber.tsx rename to src/components/ProfileType/ProfileTypeFormNumber/ProfileTypeFormNumber.tsx index 2b700fedc1d03328846830491e6e6db9e0dbf3c6..7636440590b0c7d8872e1e74160b6a6db6447bca 100644 --- a/src/components/ProfileType/ProfileTypeFormNumber.tsx +++ b/src/components/ProfileType/ProfileTypeFormNumber/ProfileTypeFormNumber.tsx @@ -1,16 +1,11 @@ -import FormNavigation from 'components/FormGlobal/FormNavigation' -import FormProgress from 'components/FormGlobal/FormProgress' +import FormNavigation from 'components/CommonKit/FormNavigation/FormNavigation' +import FormProgress from 'components/CommonKit/FormProgress/FormProgress' import 'components/ProfileType/profileTypeForm.scss' import { useI18n } from 'cozy-ui/transpiled/react/I18n' -import { ProfileTypeStepForm } from 'enum/profileType.enum' -import { - ProfileType, - ProfileTypeAnswer, - ProfileTypeValues, -} from 'models/profileType.model' +import { ProfileTypeStepForm } from 'enums' +import { ProfileType, ProfileTypeAnswer, ProfileTypeValues } from 'models' import React, { useCallback, useEffect, useState } from 'react' -import { useSelector } from 'react-redux' -import { AppStore } from 'store' +import { useAppSelector } from 'store/hooks' interface ProfileTypeFormNumberProps { step: ProfileTypeStepForm @@ -30,8 +25,8 @@ const ProfileTypeFormNumber = ({ setPreviousStep, }: ProfileTypeFormNumberProps) => { const { t } = useI18n() - const { isProfileTypeCompleted } = useSelector( - (state: AppStore) => state.ecolyo.profile + const { isProfileTypeCompleted } = useAppSelector( + state => state.ecolyo.profile ) const [answer, setAnswer] = useState<ProfileTypeValues>('') @@ -51,17 +46,17 @@ const ProfileTypeFormNumber = ({ return ( <> - <div className={'profile-form-container'}> - <FormProgress step={step} formType={'profile'} /> - <div className={'profile-question-label'}> + <div className="profile-form-container"> + <FormProgress step={step} formType="profile" /> + <div className="profile-question-label"> {t( `profile_type.${ProfileTypeStepForm[step].toLowerCase()}.question` )} </div> {answer != null && ( - <label className={'text'}> + <label className="text"> <input - type={'number'} + type="number" value={answer.toString()} name={answerType.attribute} onChange={e => setAnswer(e.target.value)} diff --git a/src/components/ProfileType/ProfileTypeFormNumberSelection.spec.tsx b/src/components/ProfileType/ProfileTypeFormNumberSelection.spec.tsx deleted file mode 100644 index ce1e6210ab9d44ea75f54a0981d53c83622ee59e..0000000000000000000000000000000000000000 --- a/src/components/ProfileType/ProfileTypeFormNumberSelection.spec.tsx +++ /dev/null @@ -1,50 +0,0 @@ -import { ProfileTypeStepForm } from 'enum/profileType.enum' -import { mount } from 'enzyme' -import React from 'react' -import { Provider } from 'react-redux' -import { - mockProfileType, - mockProfileTypeAnswers, -} from '../../../tests/__mocks__/profileType.mock' -import { createMockEcolyoStore } from '../../../tests/__mocks__/store' -import ProfileTypeFormNumberSelection from './ProfileTypeFormNumberSelection' - -jest.mock('cozy-ui/transpiled/react/I18n', () => { - return { - useI18n: jest.fn(() => { - return { - t: (str: string) => str, - } - }), - } -}) -const mockedNavigate = jest.fn() -jest.mock('react-router-dom', () => ({ - ...jest.requireActual('react-router-dom'), - useNavigate: () => mockedNavigate, -})) - -describe('ProfileTypeFormNumberSelection component', () => { - const store = createMockEcolyoStore() - beforeEach(() => { - store.clearActions() - }) - - it('should be rendered correctly', () => { - const mockhandlePrevious = jest.fn() - const mockhandleNext = jest.fn() - const wrapper = mount( - <Provider store={store}> - <ProfileTypeFormNumberSelection - step={ProfileTypeStepForm.COOKING_FLUID} - viewedStep={ProfileTypeStepForm.AREA} - currentProfileType={mockProfileType} - answerType={mockProfileTypeAnswers[3]} - setNextStep={mockhandlePrevious} - setPreviousStep={mockhandleNext} - /> - </Provider> - ) - expect(wrapper.find('input')).toBeTruthy() - }) -}) diff --git a/src/components/ProfileType/ProfileTypeFormNumberSelection/ProfileTypeFormNumberSelection.spec.tsx b/src/components/ProfileType/ProfileTypeFormNumberSelection/ProfileTypeFormNumberSelection.spec.tsx new file mode 100644 index 0000000000000000000000000000000000000000..c575f170dfc097af77f0f2df3bf6ade0f059bc4e --- /dev/null +++ b/src/components/ProfileType/ProfileTypeFormNumberSelection/ProfileTypeFormNumberSelection.spec.tsx @@ -0,0 +1,33 @@ +import { ProfileTypeStepForm } from 'enums' +import { mount } from 'enzyme' +import React from 'react' +import { Provider } from 'react-redux' +import { + mockProfileType, + mockProfileTypeAnswers, +} from 'tests/__mocks__/profileType.mock' +import { createMockEcolyoStore } from 'tests/__mocks__/store' +import ProfileTypeFormNumberSelection from './ProfileTypeFormNumberSelection' + +const mockHandlePrevious = jest.fn() +const mockHandleNext = jest.fn() + +describe('ProfileTypeFormNumberSelection component', () => { + const store = createMockEcolyoStore() + + it('should be rendered correctly', () => { + const wrapper = mount( + <Provider store={store}> + <ProfileTypeFormNumberSelection + step={ProfileTypeStepForm.COOKING_FLUID} + viewedStep={ProfileTypeStepForm.AREA} + currentProfileType={mockProfileType} + answerType={mockProfileTypeAnswers[3]} + setNextStep={mockHandleNext} + setPreviousStep={mockHandlePrevious} + /> + </Provider> + ) + expect(wrapper.find('input')).toBeTruthy() + }) +}) diff --git a/src/components/ProfileType/ProfileTypeFormNumberSelection.tsx b/src/components/ProfileType/ProfileTypeFormNumberSelection/ProfileTypeFormNumberSelection.tsx similarity index 76% rename from src/components/ProfileType/ProfileTypeFormNumberSelection.tsx rename to src/components/ProfileType/ProfileTypeFormNumberSelection/ProfileTypeFormNumberSelection.tsx index 034e8bde4ea6aeb0e360891e97308b93bb5b6a94..32b9486bf2cdf3526ee87bccad5a9fe90681dc15 100644 --- a/src/components/ProfileType/ProfileTypeFormNumberSelection.tsx +++ b/src/components/ProfileType/ProfileTypeFormNumberSelection/ProfileTypeFormNumberSelection.tsx @@ -1,17 +1,12 @@ import { Button } from '@material-ui/core' -import FormNavigation from 'components/FormGlobal/FormNavigation' -import FormProgress from 'components/FormGlobal/FormProgress' +import FormNavigation from 'components/CommonKit/FormNavigation/FormNavigation' +import FormProgress from 'components/CommonKit/FormProgress/FormProgress' import 'components/ProfileType/profileTypeForm.scss' import { useI18n } from 'cozy-ui/transpiled/react/I18n' -import { ProfileTypeStepForm } from 'enum/profileType.enum' -import { - ProfileType, - ProfileTypeAnswer, - ProfileTypeValues, -} from 'models/profileType.model' +import { ProfileTypeStepForm } from 'enums' +import { ProfileType, ProfileTypeAnswer, ProfileTypeValues } from 'models' import React, { useCallback, useEffect, useState } from 'react' -import { useSelector } from 'react-redux' -import { AppStore } from 'store' +import { useAppSelector } from 'store/hooks' interface ProfileTypeFormNumberSelectionProps { step: ProfileTypeStepForm @@ -31,8 +26,8 @@ const ProfileTypeFormNumberSelection = ({ setPreviousStep, }: ProfileTypeFormNumberSelectionProps) => { const { t } = useI18n() - const { isProfileTypeCompleted } = useSelector( - (state: AppStore) => state.ecolyo.profile + const { isProfileTypeCompleted } = useAppSelector( + state => state.ecolyo.profile ) const [answer, setAnswer] = useState<ProfileTypeValues>('') const [index, setIndex] = useState<number>(0) @@ -70,32 +65,32 @@ const ProfileTypeFormNumberSelection = ({ return ( <> - <div className={'profile-form-container'}> - <FormProgress step={step} formType={'profile'} /> - <div className={'profile-question-label'}> + <div className="profile-form-container"> + <FormProgress step={step} formType="profile" /> + <div className="profile-question-label"> {t( `profile_type.${ProfileTypeStepForm[step].toLowerCase()}.question` )} </div> {answer !== null ? ( - <div className={'number-container'}> + <div className="number-container"> <Button - className={'btn-profile-number'} + className="btn-profile-number" onClick={() => decrement()} disabled={index < 1} > - </Button> - <label className={'number'}> + <label className="number"> <input - type={'text'} + type="text" value={answer.toString()} name={answerType.attribute} disabled={true} /> </label> <Button - className={'btn-profile-number'} + className="btn-profile-number" onClick={() => increment()} disabled={index >= answerType.choices.length - 1} > diff --git a/src/components/ProfileType/ProfileTypeFormSingleChoice.spec.tsx b/src/components/ProfileType/ProfileTypeFormSingleChoice.spec.tsx deleted file mode 100644 index f4c4e4e8ae30882f352bca71897d48d8a4547d29..0000000000000000000000000000000000000000 --- a/src/components/ProfileType/ProfileTypeFormSingleChoice.spec.tsx +++ /dev/null @@ -1,50 +0,0 @@ -import { ProfileTypeStepForm } from 'enum/profileType.enum' -import { mount } from 'enzyme' -import React from 'react' -import { Provider } from 'react-redux' -import { - mockProfileType, - mockProfileTypeAnswers, -} from '../../../tests/__mocks__/profileType.mock' -import { createMockEcolyoStore } from '../../../tests/__mocks__/store' -import ProfileTypeFormSingleChoice from './ProfileTypeFormSingleChoice' - -jest.mock('cozy-ui/transpiled/react/I18n', () => { - return { - useI18n: jest.fn(() => { - return { - t: (str: string) => str, - } - }), - } -}) -const mockedNavigate = jest.fn() -jest.mock('react-router-dom', () => ({ - ...jest.requireActual('react-router-dom'), - useNavigate: () => mockedNavigate, -})) - -describe('ProfileTypeFormSingleChoice component', () => { - const store = createMockEcolyoStore() - beforeEach(() => { - store.clearActions() - }) - - it('should be rendered correctly', () => { - const mockhandlePrevious = jest.fn() - const mockhandleNext = jest.fn() - const wrapper = mount( - <Provider store={store}> - <ProfileTypeFormSingleChoice - step={ProfileTypeStepForm.COOKING_FLUID} - viewedStep={ProfileTypeStepForm.AREA} - currentProfileType={mockProfileType} - answerType={mockProfileTypeAnswers[1]} - setNextStep={mockhandlePrevious} - setPreviousStep={mockhandleNext} - /> - </Provider> - ) - expect(wrapper.find('input')).toBeTruthy() - }) -}) diff --git a/src/components/ProfileType/ProfileTypeFormSingleChoice/ProfileTypeFormSingleChoice.spec.tsx b/src/components/ProfileType/ProfileTypeFormSingleChoice/ProfileTypeFormSingleChoice.spec.tsx new file mode 100644 index 0000000000000000000000000000000000000000..5ee630d394f4889819d8870ea47a778ba2e02c28 --- /dev/null +++ b/src/components/ProfileType/ProfileTypeFormSingleChoice/ProfileTypeFormSingleChoice.spec.tsx @@ -0,0 +1,33 @@ +import { ProfileTypeStepForm } from 'enums' +import { mount } from 'enzyme' +import React from 'react' +import { Provider } from 'react-redux' +import { + mockProfileType, + mockProfileTypeAnswers, +} from 'tests/__mocks__/profileType.mock' +import { createMockEcolyoStore } from 'tests/__mocks__/store' +import ProfileTypeFormSingleChoice from './ProfileTypeFormSingleChoice' + +const mockHandlePrevious = jest.fn() +const mockHandleNext = jest.fn() + +describe('ProfileTypeFormSingleChoice component', () => { + const store = createMockEcolyoStore() + + it('should be rendered correctly', () => { + const wrapper = mount( + <Provider store={store}> + <ProfileTypeFormSingleChoice + step={ProfileTypeStepForm.COOKING_FLUID} + viewedStep={ProfileTypeStepForm.AREA} + currentProfileType={mockProfileType} + answerType={mockProfileTypeAnswers[1]} + setNextStep={mockHandleNext} + setPreviousStep={mockHandlePrevious} + /> + </Provider> + ) + expect(wrapper.find('input')).toBeTruthy() + }) +}) diff --git a/src/components/ProfileType/ProfileTypeFormSingleChoice.tsx b/src/components/ProfileType/ProfileTypeFormSingleChoice/ProfileTypeFormSingleChoice.tsx similarity index 82% rename from src/components/ProfileType/ProfileTypeFormSingleChoice.tsx rename to src/components/ProfileType/ProfileTypeFormSingleChoice/ProfileTypeFormSingleChoice.tsx index 85f3a0e17801a9d517d538f95cbc7c5ae9a8b105..52f88be87c5fa774acbf08f7e881bc76a9b88ec6 100644 --- a/src/components/ProfileType/ProfileTypeFormSingleChoice.tsx +++ b/src/components/ProfileType/ProfileTypeFormSingleChoice/ProfileTypeFormSingleChoice.tsx @@ -1,18 +1,17 @@ import classNames from 'classnames' -import FormNavigation from 'components/FormGlobal/FormNavigation' -import FormProgress from 'components/FormGlobal/FormProgress' +import FormNavigation from 'components/CommonKit/FormNavigation/FormNavigation' +import FormProgress from 'components/CommonKit/FormProgress/FormProgress' import 'components/ProfileType/profileTypeForm.scss' import { useI18n } from 'cozy-ui/transpiled/react/I18n' -import { ProfileTypeStepForm } from 'enum/profileType.enum' -import { ProfileEcogesture } from 'models' +import { ProfileTypeStepForm } from 'enums' import { + ProfileEcogesture, ProfileType, ProfileTypeAnswer, ProfileTypeValues, -} from 'models/profileType.model' +} from 'models' import React, { useCallback, useEffect, useState } from 'react' -import { useSelector } from 'react-redux' -import { AppStore } from 'store' +import { useAppSelector } from 'store/hooks' interface ProfileTypeFormSingleChoiceProps { step: ProfileTypeStepForm @@ -35,7 +34,7 @@ const ProfileTypeFormSingleChoice = ({ const { profile: { isProfileTypeCompleted, isProfileEcogestureCompleted }, profileEcogesture, - } = useSelector((state: AppStore) => state.ecolyo) + } = useAppSelector(state => state.ecolyo) const [answer, setAnswer] = useState<ProfileTypeValues>('') const handlePrevious = useCallback(() => { @@ -70,15 +69,15 @@ const ProfileTypeFormSingleChoice = ({ return ( <> - <div className={'profile-form-container'}> - <FormProgress step={step} formType={'profile'} /> - <div className={'profile-question-label'}> + <div className="profile-form-container"> + <FormProgress step={step} formType="profile" /> + <div className="profile-question-label"> {t( `profile_type.${ProfileTypeStepForm[step].toLowerCase()}.question` )} </div> {answerType.choices.map((value, index) => { - if (!value && value !== 0) return null + if (value === null) return null return ( <label @@ -90,7 +89,7 @@ const ProfileTypeFormSingleChoice = ({ })} > <input - type={'radio'} + type="radio" value={value.toString()} name={value.toString()} onChange={() => setAnswer(value)} diff --git a/src/components/ProfileType/ProfileTypeView.spec.tsx b/src/components/ProfileType/ProfileTypeView.spec.tsx index 466f3939ccff7a70a3b9523e7067a2fe0a6358a1..a2192fa8995f0b01af52e76805d20169ff381f28 100644 --- a/src/components/ProfileType/ProfileTypeView.spec.tsx +++ b/src/components/ProfileType/ProfileTypeView.spec.tsx @@ -2,22 +2,7 @@ import ProfileTypeView from 'components/ProfileType/ProfileTypeView' import { mount } from 'enzyme' import React from 'react' import { Provider } from 'react-redux' -import { createMockEcolyoStore } from '../../../tests/__mocks__/store' - -jest.mock('cozy-ui/transpiled/react/I18n', () => { - return { - useI18n: jest.fn(() => { - return { - t: (str: string) => str, - } - }), - } -}) -const mockedNavigate = jest.fn() -jest.mock('react-router-dom', () => ({ - ...jest.requireActual('react-router-dom'), - useNavigate: () => mockedNavigate, -})) +import { createMockEcolyoStore } from 'tests/__mocks__/store' jest.mock('components/Header/CozyBar', () => 'mock-cozybar') jest.mock('components/Header/Header', () => 'mock-header') @@ -25,9 +10,6 @@ jest.mock('components/Content/Content', () => 'mock-content') describe('ProfileTypeView component', () => { const store = createMockEcolyoStore() - beforeEach(() => { - store.clearActions() - }) it('should be rendered correctly', () => { const wrapper = mount( diff --git a/src/components/ProfileType/ProfileTypeView.tsx b/src/components/ProfileType/ProfileTypeView.tsx index f5c18d2bc5a4d3812e6d8e4e499e1a20a887baf5..6f619beb1e9c8c1372a0ad4602cb87174dffce58 100644 --- a/src/components/ProfileType/ProfileTypeView.tsx +++ b/src/components/ProfileType/ProfileTypeView.tsx @@ -1,18 +1,13 @@ import Content from 'components/Content/Content' -import EcogestureFormEquipment from 'components/EcogestureForm/EcogestureFormEquipment' +import EcogestureFormEquipment from 'components/EcogestureForm/EcogestureFormEquipment/EcogestureFormEquipment' import CozyBar from 'components/Header/CozyBar' import Header from 'components/Header/Header' import Loader from 'components/Loader/Loader' -import ProfileTypeFinished from 'components/ProfileType/ProfileTypeFinished' -import ProfileTypeFormMultiChoice from 'components/ProfileType/ProfileTypeFormMultiChoice' -import ProfileTypeFormNumber from 'components/ProfileType/ProfileTypeFormNumber' -import ProfileTypeFormNumberSelection from 'components/ProfileType/ProfileTypeFormNumberSelection' -import ProfileTypeFormSingleChoice from 'components/ProfileType/ProfileTypeFormSingleChoice' import 'components/ProfileType/profileTypeView.scss' -import { FluidType } from 'enum/fluid.enum' import { ConstructionYear, Floor, + FluidType, HotWaterEquipment, HotWaterFluid, HousingType, @@ -23,18 +18,22 @@ import { ProfileTypeStepForm, ThreeChoicesAnswer, WarmingType, -} from 'enum/profileType.enum' +} from 'enums' import { DateTime } from 'luxon' import { ProfileType, ProfileTypeAnswer } from 'models' import React, { useCallback, useEffect, useState } from 'react' -import { useSelector } from 'react-redux' import ProfileTypeFormService from 'services/profileTypeForm.service' -import { AppStore } from 'store' -import ProfileTypeFormDateSelection from './ProfileTypeFormDateSelection' +import { useAppSelector } from 'store/hooks' +import ProfileTypeFinished from './ProfileTypeFinished/ProfileTypeFinished' +import ProfileTypeFormDateSelection from './ProfileTypeFormDateSelection/ProfileTypeFormDateSelection' +import ProfileTypeFormMultiChoice from './ProfileTypeFormMultiChoice/ProfileTypeFormMultiChoice' +import ProfileTypeFormNumber from './ProfileTypeFormNumber/ProfileTypeFormNumber' +import ProfileTypeFormNumberSelection from './ProfileTypeFormNumberSelection/ProfileTypeFormNumberSelection' +import ProfileTypeFormSingleChoice from './ProfileTypeFormSingleChoice/ProfileTypeFormSingleChoice' const ProfileTypeView = () => { - const { profile, profileType, profileEcogesture } = useSelector( - (state: AppStore) => state.ecolyo + const { profile, profileType, profileEcogesture } = useAppSelector( + state => state.ecolyo ) const [headerHeight, setHeaderHeight] = useState<number>(0) @@ -74,10 +73,6 @@ const ProfileTypeView = () => { const [isLoading, setIsLoading] = useState<boolean>(true) const [viewedStep, setViewedStep] = useState<number>(-1) - const defineHeaderHeight = useCallback((height: number) => { - setHeaderHeight(height) - }, []) - // if ecogesture profile is completed, update default profileType useEffect(() => { if (profile.isProfileEcogestureCompleted) { @@ -228,14 +223,14 @@ const ProfileTypeView = () => { return ( <> - <CozyBar titleKey={'common.title_profiletype'} displayBackArrow={true} /> + <CozyBar titleKey="common.title_profiletype" displayBackArrow={true} /> <Header - setHeaderHeight={defineHeaderHeight} - desktopTitleKey={'common.title_profiletype'} + setHeaderHeight={setHeaderHeight} + desktopTitleKey="common.title_profiletype" displayBackArrow={true} /> - <Content height={headerHeight}> - <div className={'profile-type-container'}> + <Content heightOffset={headerHeight}> + <div className="profile-type-container"> {isLoading && <Loader />} {!isLoading && ( <> diff --git a/src/components/ProfileType/profileTypeForm.scss b/src/components/ProfileType/profileTypeForm.scss index 221115bfee9549b15a6c18108b33551f41b9bcdf..8812beebb8a54ccfd5a1f6103e8208641769cf4e 100644 --- a/src/components/ProfileType/profileTypeForm.scss +++ b/src/components/ProfileType/profileTypeForm.scss @@ -1,6 +1,6 @@ -@import '../../styles/base/color'; -@import '../../styles/base/breakpoint'; -@import '../../styles/base/typo-variables'; +@import 'src/styles/base/color'; +@import 'src/styles/base/breakpoint'; +@import 'src/styles/base/typo-variables'; .profile-form-container { color: $white; diff --git a/src/components/Quiz/QuizBegin.spec.tsx b/src/components/Quiz/QuizBegin/QuizBegin.spec.tsx similarity index 53% rename from src/components/Quiz/QuizBegin.spec.tsx rename to src/components/Quiz/QuizBegin/QuizBegin.spec.tsx index 1532074626de3152e5c952d4bea05cd5e9e159e8..8ad0f7374488588c3031ec8da08b872056d2044c 100644 --- a/src/components/Quiz/QuizBegin.spec.tsx +++ b/src/components/Quiz/QuizBegin/QuizBegin.spec.tsx @@ -1,42 +1,23 @@ import Button from '@material-ui/core/Button' import StyledIcon from 'components/CommonKit/Icon/StyledIcon' -import { UserChallengeUpdateFlag } from 'enum/userChallenge.enum' +import { UserChallengeUpdateFlag } from 'enums' import { mount } from 'enzyme' import React from 'react' import { Provider } from 'react-redux' -import configureStore from 'redux-mock-store' -import { globalStateData } from '../../../tests/__mocks__/globalStateData.mock' -import { userChallengeData } from '../../../tests/__mocks__/userChallengeData.mock' +import { createMockEcolyoStore } from 'tests/__mocks__/store' +import { userChallengeData } from 'tests/__mocks__/userChallengeData.mock' import QuizBegin from './QuizBegin' -jest.mock('cozy-ui/transpiled/react/I18n', () => { - return { - useI18n: jest.fn(() => { - return { - t: (str: string) => str, - } - }), - } -}) - const mockUserChallengeUpdateFlag = jest.fn() jest.mock('services/challenge.service', () => { - return jest.fn(() => { - return { - updateUserChallenge: mockUserChallengeUpdateFlag, - } - }) + return jest.fn(() => ({ + updateUserChallenge: mockUserChallengeUpdateFlag, + })) }) -const mockStore = configureStore([]) - describe('QuizBegin component', () => { it('should be rendered correctly', () => { - const store = mockStore({ - ecolyo: { - global: globalStateData, - }, - }) + const store = createMockEcolyoStore() const wrapper = mount( <Provider store={store}> <QuizBegin userChallenge={userChallengeData[0]} /> diff --git a/src/components/Quiz/QuizBegin.tsx b/src/components/Quiz/QuizBegin/QuizBegin.tsx similarity index 84% rename from src/components/Quiz/QuizBegin.tsx rename to src/components/Quiz/QuizBegin/QuizBegin.tsx index 5ba3ea40ab895c1b1c6999bb9b4e2fe586a78b76..ee0a1bf83a4454f60ea1cee55f830dac1cd50341 100644 --- a/src/components/Quiz/QuizBegin.tsx +++ b/src/components/Quiz/QuizBegin/QuizBegin.tsx @@ -1,22 +1,21 @@ import Button from '@material-ui/core/Button' import quizIcon from 'assets/icons/visu/quiz/questionMark.svg' -import StarsContainer from 'components/Challenge/StarsContainer' import StyledIcon from 'components/CommonKit/Icon/StyledIcon' +import StarsContainer from 'components/CommonKit/StarsContainer/StarsContainer' import { Client, useClient } from 'cozy-client' import { useI18n } from 'cozy-ui/transpiled/react/I18n' -import { UserChallengeUpdateFlag } from 'enum/userChallenge.enum' +import { UserChallengeUpdateFlag } from 'enums' import { UserChallenge } from 'models' -import React, { Dispatch } from 'react' -import { useDispatch } from 'react-redux' +import React from 'react' import ChallengeService from 'services/challenge.service' -import { AppActionsTypes } from 'store' import { updateUserChallengeList } from 'store/challenge/challenge.slice' +import { useAppDispatch } from 'store/hooks' import './quizBegin.scss' const QuizBegin = ({ userChallenge }: { userChallenge: UserChallenge }) => { const client: Client = useClient() const { t } = useI18n() - const dispatch = useDispatch<Dispatch<AppActionsTypes>>() + const dispatch = useAppDispatch() const launchQuiz = async () => { const challengeService: ChallengeService = new ChallengeService(client) const userChallengeUpdated: UserChallenge = diff --git a/src/components/Quiz/quizBegin.scss b/src/components/Quiz/QuizBegin/quizBegin.scss similarity index 92% rename from src/components/Quiz/quizBegin.scss rename to src/components/Quiz/QuizBegin/quizBegin.scss index c1b59893cf0acceefa0ad75f1234e1c279f36fed..b0a54d51e535066ebacbb35f419a869865e46a7f 100644 --- a/src/components/Quiz/quizBegin.scss +++ b/src/components/Quiz/QuizBegin/quizBegin.scss @@ -1,5 +1,5 @@ -@import '../../styles/base/color'; -@import '../../styles/base/breakpoint'; +@import 'src/styles/base/color'; +@import 'src/styles/base/breakpoint'; .quiz-container { display: flex; @@ -8,6 +8,7 @@ align-items: center; margin: auto; padding: 1.5rem; + gap: 1rem; } .quiz-begin-container { display: flex; diff --git a/src/components/Quiz/QuizExplanationModal.tsx b/src/components/Quiz/QuizExplanationModal/QuizExplanationModal.tsx similarity index 94% rename from src/components/Quiz/QuizExplanationModal.tsx rename to src/components/Quiz/QuizExplanationModal/QuizExplanationModal.tsx index f1f1d432d14670f0fe56b6bbe5ecd2b1830c936c..d1dc630d7c3d2a28ac67b3c0a4f1cf77d7b50b59 100644 --- a/src/components/Quiz/QuizExplanationModal.tsx +++ b/src/components/Quiz/QuizExplanationModal/QuizExplanationModal.tsx @@ -37,15 +37,13 @@ const QuizExplanationModal = ({ <Dialog open={open} onClose={handleCloseClick} - aria-labelledby={'accessibility-title'} + aria-labelledby="accessibility-title" classes={{ root: 'modal-root', paper: 'modal-paper', }} > - <div id={'accessibility-title'}> - {t('quiz.accessibility.window_title')} - </div> + <div id="accessibility-title">{t('quiz.accessibility.window_title')}</div> <div className="quiz-modal-root"> {question && ( <> diff --git a/src/components/Quiz/quizExplanationModal.scss b/src/components/Quiz/QuizExplanationModal/quizExplanationModal.scss similarity index 83% rename from src/components/Quiz/quizExplanationModal.scss rename to src/components/Quiz/QuizExplanationModal/quizExplanationModal.scss index a5ad24d164c2b604e5379b75dfe47f81d8c9d5b6..d38aa4e603716fd18fc4c824f133d875828af86e 100644 --- a/src/components/Quiz/quizExplanationModal.scss +++ b/src/components/Quiz/QuizExplanationModal/quizExplanationModal.scss @@ -1,4 +1,4 @@ -@import '../../styles/base/color'; +@import 'src/styles/base/color'; .quiz-modal-root { display: flex; @@ -6,6 +6,7 @@ justify-content: center; align-items: center; text-align: center; + gap: 1rem; .quiz-modal-answer { font-weight: bold; font-size: 1.7rem; @@ -20,7 +21,7 @@ } } .answer-label { - margin-bottom: 1.5rem; + margin-bottom: 0.5rem; } button.btn-secondary-negative { diff --git a/src/components/Quiz/QuizFinish.spec.tsx b/src/components/Quiz/QuizFinish/QuizFinish.spec.tsx similarity index 57% rename from src/components/Quiz/QuizFinish.spec.tsx rename to src/components/Quiz/QuizFinish/QuizFinish.spec.tsx index 10b2b5ba9c2fd06a0ee0f5b0e55f31c4ba06ce64..1329a7fd31bb63acf52a33fa598d40c021b4c2d8 100644 --- a/src/components/Quiz/QuizFinish.spec.tsx +++ b/src/components/Quiz/QuizFinish/QuizFinish.spec.tsx @@ -1,32 +1,19 @@ import Button from '@material-ui/core/Button' import StyledIcon from 'components/CommonKit/Icon/StyledIcon' -import { UserChallengeUpdateFlag } from 'enum/userChallenge.enum' +import { UserChallengeUpdateFlag } from 'enums' import { mount } from 'enzyme' import React from 'react' import { Provider } from 'react-redux' -import configureStore from 'redux-mock-store' -import { globalStateData } from '../../../tests/__mocks__/globalStateData.mock' -import { waitForComponentToPaint } from '../../../tests/__mocks__/testUtils' -import { userChallengeData } from '../../../tests/__mocks__/userChallengeData.mock' +import { createMockEcolyoStore } from 'tests/__mocks__/store' +import { waitForComponentToPaint } from 'tests/__mocks__/testUtils' +import { userChallengeData } from 'tests/__mocks__/userChallengeData.mock' import QuizFinish from './QuizFinish' -jest.mock('cozy-ui/transpiled/react/I18n', () => { - return { - useI18n: jest.fn(() => { - return { - t: (str: string) => str, - } - }), - } -}) - const mockUserChallengeUpdateFlag = jest.fn() jest.mock('services/challenge.service', () => { - return jest.fn(() => { - return { - updateUserChallenge: mockUserChallengeUpdateFlag, - } - }) + return jest.fn(() => ({ + updateUserChallenge: mockUserChallengeUpdateFlag, + })) }) const mockedNavigate = jest.fn() @@ -35,15 +22,9 @@ jest.mock('react-router-dom', () => ({ useNavigate: () => mockedNavigate, })) -const mockStore = configureStore([]) - describe('QuizFinish', () => { it('should be rendered correctly', async () => { - const store = mockStore({ - ecolyo: { - global: globalStateData, - }, - }) + const store = createMockEcolyoStore() const wrapper = mount( <Provider store={store}> <QuizFinish userChallenge={userChallengeData[0]} /> diff --git a/src/components/Quiz/QuizFinish.tsx b/src/components/Quiz/QuizFinish/QuizFinish.tsx similarity index 89% rename from src/components/Quiz/QuizFinish.tsx rename to src/components/Quiz/QuizFinish/QuizFinish.tsx index e3abbcf0ae72a04aca396c055a72e576237c731d..7ffc1162e96772ce6c8703f7a46dc47256a8d2ef 100644 --- a/src/components/Quiz/QuizFinish.tsx +++ b/src/components/Quiz/QuizFinish/QuizFinish.tsx @@ -1,23 +1,22 @@ import Button from '@material-ui/core/Button' import starResult from 'assets/icons/visu/quiz/starResult.svg' import StyledIcon from 'components/CommonKit/Icon/StyledIcon' -import { Client, useClient } from 'cozy-client' +import { useClient } from 'cozy-client' import { useI18n } from 'cozy-ui/transpiled/react/I18n' -import { UserChallengeUpdateFlag } from 'enum/userChallenge.enum' +import { UserChallengeUpdateFlag } from 'enums' import { UserChallenge } from 'models' -import React, { Dispatch, useCallback, useMemo } from 'react' -import { useDispatch } from 'react-redux' +import React, { useCallback, useMemo } from 'react' import { useNavigate } from 'react-router-dom' import ChallengeService from 'services/challenge.service' -import { AppActionsTypes } from 'store' import { updateUserChallengeList } from 'store/challenge/challenge.slice' +import { useAppDispatch } from 'store/hooks' import './quizFinish.scss' const QuizFinish = ({ userChallenge }: { userChallenge: UserChallenge }) => { - const client: Client = useClient() const { t } = useI18n() + const client = useClient() const navigate = useNavigate() - const dispatch = useDispatch<Dispatch<AppActionsTypes>>() + const dispatch = useAppDispatch() const challengeService: ChallengeService = useMemo( () => new ChallengeService(client), [client] diff --git a/src/components/Quiz/quizFinish.scss b/src/components/Quiz/QuizFinish/quizFinish.scss similarity index 80% rename from src/components/Quiz/quizFinish.scss rename to src/components/Quiz/QuizFinish/quizFinish.scss index 79da8a18aaa1ac8f67814f4f6f6e346799c8b76b..e438ae230ba447a8f7a9c428f5f08af869ba5884 100644 --- a/src/components/Quiz/quizFinish.scss +++ b/src/components/Quiz/QuizFinish/quizFinish.scss @@ -1,5 +1,5 @@ -@import '../../styles/base/color'; -@import '../../styles/base/breakpoint'; +@import 'src/styles/base/color'; +@import 'src/styles/base/breakpoint'; .quiz-finish-container { padding: 1.5rem; @@ -9,13 +9,18 @@ color: $white; background: $grey-linear-gradient-background; text-align: center; + display: flex; + flex-direction: column; + align-items: center; button.btn-secondary-negative { border-color: $grey-bright; - min-width: 15rem; } .button-start { margin-top: 3rem; + display: flex; + flex-direction: column; + gap: 1rem; } } .score-final-title { diff --git a/src/components/Quiz/QuizQuestion.spec.tsx b/src/components/Quiz/QuizQuestion/QuizQuestion.spec.tsx similarity index 57% rename from src/components/Quiz/QuizQuestion.spec.tsx rename to src/components/Quiz/QuizQuestion/QuizQuestion.spec.tsx index 16a951db361c715065fcd94da472738a2d8af141..1421e6ce31b630dbe81e2859b64ccc84908c5ffa 100644 --- a/src/components/Quiz/QuizQuestion.spec.tsx +++ b/src/components/Quiz/QuizQuestion/QuizQuestion.spec.tsx @@ -1,31 +1,12 @@ /* eslint-disable react/display-name */ -import { UserQuestionState } from 'enum/userQuiz.enum' +import { UserQuestionState } from 'enums' import { mount } from 'enzyme' import React from 'react' -import * as reactRedux from 'react-redux' import { Provider } from 'react-redux' -import { createMockEcolyoStore } from '../../../tests/__mocks__/store' -import { userChallengeData } from '../../../tests/__mocks__/userChallengeData.mock' +import { createMockEcolyoStore } from 'tests/__mocks__/store' +import { userChallengeData } from 'tests/__mocks__/userChallengeData.mock' import QuizQuestion from './QuizQuestion' -jest.mock('cozy-ui/transpiled/react/I18n', () => { - return { - useI18n: jest.fn(() => { - return { - t: (str: string) => str, - } - }), - } -}) - -const mockHistoryPush = jest.fn() -jest.mock('react-router-dom', () => ({ - ...jest.requireActual('react-router-dom'), - useNavigate: () => ({ - push: mockHistoryPush, - }), -})) - const mockgetCustomQuestion = jest.fn() jest.mock('services/quiz.service', () => { return jest.fn(() => { @@ -35,19 +16,18 @@ jest.mock('services/quiz.service', () => { }) }) -jest.mock('components/Quiz/QuizCustomQuestionContent', () => () => ( - <div id="quizcustomquestioncontent" /> -)) -jest.mock('components/Quiz/QuizQuestionContent', () => () => ( +jest.mock( + 'components/Quiz/QuizQuestion/QuizQuestionContentCustom', + () => () => <div id="QuizQuestionContentCustom" /> +) +jest.mock('components/Quiz/QuizQuestion/QuizQuestionContent', () => () => ( <div id="quizquestioncontent" /> )) -const useSelectorSpy = jest.spyOn(reactRedux, 'useSelector') describe('QuizQuestion component', () => { const store = createMockEcolyoStore() beforeEach(() => { store.clearActions() - useSelectorSpy.mockClear() }) it('should be rendered correctly with question', () => { @@ -57,7 +37,7 @@ describe('QuizQuestion component', () => { </Provider> ) expect(wrapper.find('#quizquestioncontent').exists()).toBeTruthy() - expect(wrapper.find('#quizcustomquestioncontent').exists()).toBeFalsy() + expect(wrapper.find('#QuizQuestionContentCustom').exists()).toBeFalsy() }) it('should be rendered correctly with customQuestion', () => { @@ -73,6 +53,6 @@ describe('QuizQuestion component', () => { </Provider> ) expect(wrapper.find('#quizquestioncontent').exists()).toBeFalsy() - expect(wrapper.find('#quizcustomquestioncontent').exists()).toBeTruthy() + expect(wrapper.find('#QuizQuestionContentCustom').exists()).toBeTruthy() }) }) diff --git a/src/components/Quiz/QuizQuestion.tsx b/src/components/Quiz/QuizQuestion/QuizQuestion.tsx similarity index 84% rename from src/components/Quiz/QuizQuestion.tsx rename to src/components/Quiz/QuizQuestion/QuizQuestion.tsx index b433733c0755e9337c4e57f985f9e26d6ece2ba3..f8f13cc7245f9619ecc00e1330021d8edc22e6ae 100644 --- a/src/components/Quiz/QuizQuestion.tsx +++ b/src/components/Quiz/QuizQuestion/QuizQuestion.tsx @@ -1,12 +1,11 @@ -import QuizCustomQuestionContent from 'components/Quiz/QuizCustomQuestionContent' -import QuizQuestionContent from 'components/Quiz/QuizQuestionContent' import { Client, useClient } from 'cozy-client' import { QuestionEntity, UserChallenge } from 'models' import React, { useEffect, useState } from 'react' -import { useSelector } from 'react-redux' import { useNavigate } from 'react-router-dom' import QuizService from 'services/quiz.service' -import { AppStore } from 'store' +import { useAppSelector } from 'store/hooks' +import QuizQuestionContent from './QuizQuestionContent' +import QuizQuestionContentCustom from './QuizQuestionContentCustom' import './quizQuestion.scss' const QuizQuestion = ({ userChallenge }: { userChallenge: UserChallenge }) => { @@ -20,7 +19,7 @@ const QuizQuestion = ({ userChallenge }: { userChallenge: UserChallenge }) => { const [customQuestionLoading, setCustomQuestionLoading] = useState<boolean>(false) const client: Client = useClient() - const { fluidTypes } = useSelector((state: AppStore) => state.ecolyo.global) + const { fluidTypes } = useAppSelector(state => state.ecolyo.global) const navigate = useNavigate() const goBack = () => { @@ -53,7 +52,7 @@ const QuizQuestion = ({ userChallenge }: { userChallenge: UserChallenge }) => { return ( <> {isCustomQuest ? ( - <QuizCustomQuestionContent + <QuizQuestionContentCustom userChallenge={userChallenge} goBack={goBack} question={question} diff --git a/src/components/Quiz/QuizQuestionContent.spec.tsx b/src/components/Quiz/QuizQuestion/QuizQuestionContent.spec.tsx similarity index 55% rename from src/components/Quiz/QuizQuestionContent.spec.tsx rename to src/components/Quiz/QuizQuestion/QuizQuestionContent.spec.tsx index 326945c96e293db970a4a16e1dc1cc1780986656..e30abb302c4f9edb801e003c5dcabcebc7335f42 100644 --- a/src/components/Quiz/QuizQuestionContent.spec.tsx +++ b/src/components/Quiz/QuizQuestion/QuizQuestionContent.spec.tsx @@ -1,21 +1,9 @@ -import QuizQuestionContent from 'components/Quiz/QuizQuestionContent' import { mount } from 'enzyme' import React from 'react' import { Provider } from 'react-redux' -import configureStore from 'redux-mock-store' -import { challengeStateData } from '../../../tests/__mocks__/challengeStateData.mock' -import { globalStateData } from '../../../tests/__mocks__/globalStateData.mock' -import { userChallengeData } from '../../../tests/__mocks__/userChallengeData.mock' - -jest.mock('cozy-ui/transpiled/react/I18n', () => { - return { - useI18n: jest.fn(() => { - return { - t: (str: string) => str, - } - }), - } -}) +import { createMockEcolyoStore } from 'tests/__mocks__/store' +import { userChallengeData } from 'tests/__mocks__/userChallengeData.mock' +import QuizQuestionContent from './QuizQuestionContent' const mockedNavigate = jest.fn() jest.mock('react-router-dom', () => ({ @@ -25,32 +13,21 @@ jest.mock('react-router-dom', () => ({ const mockUpdateUserQuiz = jest.fn() jest.mock('services/quiz.service', () => { - return jest.fn(() => { - return { - updateUserQuiz: mockUpdateUserQuiz, - } - }) + return jest.fn(() => ({ + updateUserQuiz: mockUpdateUserQuiz, + })) }) const mockUserChallengeUpdateFlag = jest.fn() jest.mock('services/challenge.service', () => { - return jest.fn(() => { - return { - updateUserChallenge: mockUserChallengeUpdateFlag, - } - }) + return jest.fn(() => ({ + updateUserChallenge: mockUserChallengeUpdateFlag, + })) }) -const mockStore = configureStore([]) - describe('QuizQuestionContent component', () => { + const store = createMockEcolyoStore() it('should be rendered correctly', () => { - const store = mockStore({ - ecolyo: { - global: globalStateData, - challenge: challengeStateData, - }, - }) const wrapper = mount( <Provider store={store}> <QuizQuestionContent @@ -66,12 +43,6 @@ describe('QuizQuestionContent component', () => { expect(wrapper.find('input')).toHaveLength(3) }) it('should redirect to challenge on click on btn-back', () => { - const store = mockStore({ - ecolyo: { - global: globalStateData, - challenge: challengeStateData, - }, - }) const wrapper = mount( <Provider store={store}> <QuizQuestionContent diff --git a/src/components/Quiz/QuizQuestionContent.tsx b/src/components/Quiz/QuizQuestion/QuizQuestionContent.tsx similarity index 95% rename from src/components/Quiz/QuizQuestionContent.tsx rename to src/components/Quiz/QuizQuestion/QuizQuestionContent.tsx index 3007c8cc292541e4bbbbec3f353aaf3f906fbc63..d26f33bdf25806fbd65d662ea7880aefede3d37e 100644 --- a/src/components/Quiz/QuizQuestionContent.tsx +++ b/src/components/Quiz/QuizQuestion/QuizQuestionContent.tsx @@ -1,17 +1,16 @@ import Button from '@material-ui/core/Button' import CloseIcon from 'assets/icons/ico/close.svg' import StyledIconButton from 'components/CommonKit/IconButton/StyledIconButton' -import QuizExplanationModal from 'components/Quiz/QuizExplanationModal' +import QuizExplanationModal from 'components/Quiz/QuizExplanationModal/QuizExplanationModal' import { Client, useClient } from 'cozy-client' import { useI18n } from 'cozy-ui/transpiled/react/I18n' -import { UserChallengeUpdateFlag } from 'enum/userChallenge.enum' +import { UserChallengeUpdateFlag } from 'enums' import { Answer, UserChallenge, UserQuiz } from 'models' import React, { Dispatch, SetStateAction, useCallback, useState } from 'react' -import { useDispatch } from 'react-redux' import ChallengeService from 'services/challenge.service' import QuizService from 'services/quiz.service' -import { AppActionsTypes } from 'store' import { updateUserChallengeList } from 'store/challenge/challenge.slice' +import { useAppDispatch } from 'store/hooks' import './quizQuestion.scss' interface QuizQuestionContent { @@ -26,6 +25,8 @@ const QuizQuestionContent = ({ goBack, }: QuizQuestionContent) => { const { t } = useI18n() + const client: Client = useClient() + const dispatch = useAppDispatch() const questionIndexLocked = userChallenge.quiz.questions.findIndex( answer => answer.result == 0 ) @@ -35,9 +36,6 @@ const QuizQuestionContent = ({ const [questionIndex, setQuestionIndex] = useState<number>(questionIndexLocked) - const client: Client = useClient() - const dispatch = useDispatch<Dispatch<AppActionsTypes>>() - const quizService: QuizService = new QuizService(client) const challengeService: ChallengeService = new ChallengeService(client) diff --git a/src/components/Quiz/QuizCustomQuestionContent.spec.tsx b/src/components/Quiz/QuizQuestion/QuizQuestionContentCustom.spec.tsx similarity index 60% rename from src/components/Quiz/QuizCustomQuestionContent.spec.tsx rename to src/components/Quiz/QuizQuestion/QuizQuestionContentCustom.spec.tsx index 92053cea0548bc900cec68e17df1d58195d906c1..7c5b860e950deeebbb365a6d46a5c41964ac2064 100644 --- a/src/components/Quiz/QuizCustomQuestionContent.spec.tsx +++ b/src/components/Quiz/QuizQuestion/QuizQuestionContentCustom.spec.tsx @@ -3,23 +3,11 @@ import Loader from 'components/Loader/Loader' import { mount } from 'enzyme' import React from 'react' import { Provider } from 'react-redux' -import configureStore from 'redux-mock-store' -import { challengeStateData } from '../../../tests/__mocks__/challengeStateData.mock' -import { globalStateData } from '../../../tests/__mocks__/globalStateData.mock' -import { questionEntity } from '../../../tests/__mocks__/quizData.mock' -import { userChallengeData } from '../../../tests/__mocks__/userChallengeData.mock' -import QuizCustomQuestionContent from './QuizCustomQuestionContent' -import QuizExplanationModal from './QuizExplanationModal' - -jest.mock('cozy-ui/transpiled/react/I18n', () => { - return { - useI18n: jest.fn(() => { - return { - t: (str: string) => str, - } - }), - } -}) +import { questionEntity } from 'tests/__mocks__/quizData.mock' +import { createMockEcolyoStore } from 'tests/__mocks__/store' +import { userChallengeData } from 'tests/__mocks__/userChallengeData.mock' +import QuizExplanationModal from '../QuizExplanationModal/QuizExplanationModal' +import QuizQuestionContentCustom from './QuizQuestionContentCustom' const mockHistoryPush = jest.fn() jest.mock('react-router-dom', () => ({ @@ -32,36 +20,25 @@ jest.mock('react-router-dom', () => ({ const mockUpdateUserQuiz = jest.fn() const mockGetCustomQuestion = jest.fn() jest.mock('services/quiz.service', () => { - return jest.fn(() => { - return { - updateUserQuiz: mockUpdateUserQuiz, - getCustomQuestion: mockGetCustomQuestion, - } - }) + return jest.fn(() => ({ + updateUserQuiz: mockUpdateUserQuiz, + getCustomQuestion: mockGetCustomQuestion, + })) }) const mockUserChallengeUpdateFlag = jest.fn() jest.mock('services/challenge.service', () => { - return jest.fn(() => { - return { - updateUserChallenge: mockUserChallengeUpdateFlag, - } - }) + return jest.fn(() => ({ + updateUserChallenge: mockUserChallengeUpdateFlag, + })) }) -const mockStore = configureStore([]) - describe('QuizCustomQuestionContent component', () => { + const store = createMockEcolyoStore() it('should be rendered correctly', () => { - const store = mockStore({ - ecolyo: { - global: globalStateData, - challenge: challengeStateData, - }, - }) const wrapper = mount( <Provider store={store}> - <QuizCustomQuestionContent + <QuizQuestionContentCustom userChallenge={userChallengeData[0]} question={questionEntity} goBack={mockHistoryPush('/challenges')} @@ -79,15 +56,9 @@ describe('QuizCustomQuestionContent component', () => { expect(wrapper.find('input')).toHaveLength(3) }) it('should be rendered correctly with loader', () => { - const store = mockStore({ - ecolyo: { - global: globalStateData, - challenge: challengeStateData, - }, - }) const wrapper = mount( <Provider store={store}> - <QuizCustomQuestionContent + <QuizQuestionContentCustom userChallenge={userChallengeData[0]} question={questionEntity} goBack={mockHistoryPush('/challenges')} @@ -98,15 +69,9 @@ describe('QuizCustomQuestionContent component', () => { expect(wrapper.find(Loader).exists()).toBeTruthy() }) it('should display QuizExplanationModal when click on Button', () => { - const store = mockStore({ - ecolyo: { - global: globalStateData, - challenge: challengeStateData, - }, - }) const wrapper = mount( <Provider store={store}> - <QuizCustomQuestionContent + <QuizQuestionContentCustom userChallenge={userChallengeData[0]} question={questionEntity} goBack={mockHistoryPush('/challenges')} @@ -115,12 +80,11 @@ describe('QuizCustomQuestionContent component', () => { </Provider> ) const answer = questionEntity.answers[0].answerLabel - expect( - wrapper - .find({ type: 'radio' }) - .at(0) - .simulate('change', { target: { value: answer } }) - ) + wrapper + .find({ type: 'radio' }) + .at(0) + .simulate('change', { target: { value: answer } }) + expect(wrapper.find(Button).exists()).toBeTruthy() wrapper.find('.btn-secondary-negative').forEach(node => { node.simulate('click') diff --git a/src/components/Quiz/QuizCustomQuestionContent.tsx b/src/components/Quiz/QuizQuestion/QuizQuestionContentCustom.tsx similarity index 89% rename from src/components/Quiz/QuizCustomQuestionContent.tsx rename to src/components/Quiz/QuizQuestion/QuizQuestionContentCustom.tsx index 1c4efae265ba27fc645e474a42e8bc20353c9ac6..dc55ae0a7c5bbf1d27d927f5419f4b26e739b256 100644 --- a/src/components/Quiz/QuizCustomQuestionContent.tsx +++ b/src/components/Quiz/QuizQuestion/QuizQuestionContentCustom.tsx @@ -2,41 +2,39 @@ import Button from '@material-ui/core/Button' import CloseIcon from 'assets/icons/ico/close.svg' import StyledIconButton from 'components/CommonKit/IconButton/StyledIconButton' import Loader from 'components/Loader/Loader' -import QuizExplanationModal from 'components/Quiz/QuizExplanationModal' +import QuizExplanationModal from 'components/Quiz/QuizExplanationModal/QuizExplanationModal' import { Client, useClient } from 'cozy-client' import { useI18n } from 'cozy-ui/transpiled/react/I18n' -import { UsageEventType } from 'enum/usageEvent.enum' -import { UserChallengeUpdateFlag } from 'enum/userChallenge.enum' +import { UsageEventType, UserChallengeUpdateFlag } from 'enums' import { Answer, QuestionEntity, UserChallenge, UserQuiz } from 'models' -import React, { Dispatch, useState } from 'react' -import { useDispatch } from 'react-redux' +import React, { useState } from 'react' import ChallengeService from 'services/challenge.service' import QuizService from 'services/quiz.service' import UsageEventService from 'services/usageEvent.service' -import { AppActionsTypes } from 'store' import { updateUserChallengeList } from 'store/challenge/challenge.slice' +import { useAppDispatch } from 'store/hooks' import './quizQuestion.scss' -interface QuizCustomQuestionContent { +interface QuizQuestionContentCustomProps { userChallenge: UserChallenge goBack: () => void question: QuestionEntity | undefined isLoading: boolean } -const QuizCustomQuestionContent = ({ +const QuizQuestionContentCustom = ({ userChallenge, goBack, question, isLoading, -}: QuizCustomQuestionContent) => { +}: QuizQuestionContentCustomProps) => { const { t } = useI18n() + const client: Client = useClient() + const dispatch = useAppDispatch() + const [userChoice, setUserChoice] = useState<string>('') const [openModal, setOpenModal] = useState<boolean>(false) const [answerIndex, setAnswerIndex] = useState<number>(0) - const client: Client = useClient() - const dispatch = useDispatch<Dispatch<AppActionsTypes>>() - const quizService: QuizService = new QuizService(client) const challengeService: ChallengeService = new ChallengeService(client) @@ -100,7 +98,7 @@ const QuizCustomQuestionContent = ({ </p> {isLoading ? ( - <div className={'question-loading'} aria-busy="true"> + <div className="question-loading"> <Loader /> </div> ) : ( @@ -150,4 +148,4 @@ const QuizCustomQuestionContent = ({ ) } -export default QuizCustomQuestionContent +export default QuizQuestionContentCustom diff --git a/src/components/Quiz/quizQuestion.scss b/src/components/Quiz/QuizQuestion/quizQuestion.scss similarity index 96% rename from src/components/Quiz/quizQuestion.scss rename to src/components/Quiz/QuizQuestion/quizQuestion.scss index d0a3baa006a6430ba9946f10c5fec7b60b2de1c0..72faed6cb7909fdd1762eb6d53f0cccdf68806ae 100644 --- a/src/components/Quiz/quizQuestion.scss +++ b/src/components/Quiz/QuizQuestion/quizQuestion.scss @@ -1,5 +1,5 @@ -@import '../../styles/base/color'; -@import '../../styles/base/breakpoint'; +@import 'src/styles/base/color'; +@import 'src/styles/base/breakpoint'; .quiz-container { .question-container { diff --git a/src/components/Quiz/QuizView.spec.tsx b/src/components/Quiz/QuizView.spec.tsx index 241cd54a9987fee3309ba022d03363a0a8ce0938..40f0962f05fc29a234711ced6b822ae0f5f04d95 100644 --- a/src/components/Quiz/QuizView.spec.tsx +++ b/src/components/Quiz/QuizView.spec.tsx @@ -1,18 +1,19 @@ import QuizView from 'components/Quiz/QuizView' -import { UserQuizState } from 'enum/userQuiz.enum' -import { shallow } from 'enzyme' +import { UserQuizState } from 'enums' +import { mount } from 'enzyme' +import { ChallengeState } from 'models' import React from 'react' -import * as reactRedux from 'react-redux' -import { challengeStateData } from '../../../tests/__mocks__/challengeStateData.mock' -import { userChallengeData } from '../../../tests/__mocks__/userChallengeData.mock' -import QuizBegin from './QuizBegin' -import QuizFinish from './QuizFinish' -import QuizQuestion from './QuizQuestion' +import { Provider } from 'react-redux' +import { challengeStateData } from 'tests/__mocks__/challengeStateData.mock' +import { createMockEcolyoStore, mockGlobalState } from 'tests/__mocks__/store' +import { userChallengeData } from 'tests/__mocks__/userChallengeData.mock' +import QuizBegin from './QuizBegin/QuizBegin' +import QuizFinish from './QuizFinish/QuizFinish' +import QuizQuestion from './QuizQuestion/QuizQuestion' jest.mock('components/Header/CozyBar', () => 'mock-cozybar') jest.mock('components/Header/Header', () => 'mock-header') jest.mock('components/Content/Content', () => 'mock-content') -const mockUseSelector = jest.spyOn(reactRedux, 'useSelector') describe('QuizView component', () => { it('should be rendered with QuizBegin component when quiz state = unlocked', () => { @@ -24,8 +25,15 @@ describe('QuizView component', () => { ...challengeStateData, currentChallenge: updatedUserChallenge, } - mockUseSelector.mockReturnValue(updatedChallengeState) - const wrapper = shallow(<QuizView />) + const store = createMockEcolyoStore({ + challenge: updatedChallengeState, + global: mockGlobalState, + }) + const wrapper = mount( + <Provider store={store}> + <QuizView /> + </Provider> + ) expect(wrapper.find(QuizBegin).exists()).toBeTruthy() }) @@ -38,8 +46,15 @@ describe('QuizView component', () => { ...challengeStateData, currentChallenge: updatedUserChallenge, } - mockUseSelector.mockReturnValue(updatedChallengeState) - const wrapper = shallow(<QuizView />) + const store = createMockEcolyoStore({ + challenge: updatedChallengeState, + global: mockGlobalState, + }) + const wrapper = mount( + <Provider store={store}> + <QuizView /> + </Provider> + ) expect(wrapper.find(QuizQuestion).exists()).toBeTruthy() }) @@ -52,22 +67,35 @@ describe('QuizView component', () => { ...challengeStateData, currentChallenge: updatedUserChallenge, } - mockUseSelector.mockReturnValue(updatedChallengeState) - const wrapper = shallow(<QuizView />) + const store = createMockEcolyoStore({ + challenge: updatedChallengeState, + global: mockGlobalState, + }) + const wrapper = mount( + <Provider store={store}> + <QuizView /> + </Provider> + ) expect(wrapper.find(QuizFinish).exists()).toBeTruthy() }) it('should be rendered with QuizBegin component when quiz state = null', () => { - const updatedUserChallenge = { - ...userChallengeData[0], - quiz: { ...userChallengeData[0].quiz, state: null }, - } - const updatedChallengeState = { + const updatedChallengeState: ChallengeState = { ...challengeStateData, - currentChallenge: updatedUserChallenge, + currentChallenge: { + ...userChallengeData[0], + quiz: { ...userChallengeData[0].quiz, state: UserQuizState.UNLOCKED }, + }, } - mockUseSelector.mockReturnValue(updatedChallengeState) - const wrapper = shallow(<QuizView />) + const store = createMockEcolyoStore({ + challenge: updatedChallengeState, + global: mockGlobalState, + }) + const wrapper = mount( + <Provider store={store}> + <QuizView /> + </Provider> + ) expect(wrapper.find(QuizBegin).exists()).toBeTruthy() }) }) diff --git a/src/components/Quiz/QuizView.tsx b/src/components/Quiz/QuizView.tsx index 4888e43e1e9d84b8fdd285290cbc3453a39dee07..380346fbe0fba125cf5b63b232dccee3b2f28b45 100644 --- a/src/components/Quiz/QuizView.tsx +++ b/src/components/Quiz/QuizView.tsx @@ -1,24 +1,17 @@ import Content from 'components/Content/Content' import CozyBar from 'components/Header/CozyBar' import Header from 'components/Header/Header' -import { UserQuizState } from 'enum/userQuiz.enum' +import { UserQuizState } from 'enums' import { UserChallenge } from 'models' -import React, { useCallback, useState } from 'react' -import { useSelector } from 'react-redux' -import { AppStore } from 'store' -import QuizBegin from './QuizBegin' -import QuizFinish from './QuizFinish' -import QuizQuestion from './QuizQuestion' +import React, { useState } from 'react' +import { useAppSelector } from 'store/hooks' +import QuizBegin from './QuizBegin/QuizBegin' +import QuizFinish from './QuizFinish/QuizFinish' +import QuizQuestion from './QuizQuestion/QuizQuestion' const QuizView = () => { + const { currentChallenge } = useAppSelector(state => state.ecolyo.challenge) const [headerHeight, setHeaderHeight] = useState<number>(0) - const { currentChallenge } = useSelector( - (state: AppStore) => state.ecolyo.challenge - ) - - const defineHeaderHeight = useCallback((height: number) => { - setHeaderHeight(height) - }, []) const renderQuiz = (challenge: UserChallenge) => { switch (challenge.quiz.state) { @@ -35,13 +28,13 @@ const QuizView = () => { return ( <> - <CozyBar titleKey={'common.title_quiz'} displayBackArrow={true} /> + <CozyBar titleKey="common.title_quiz" displayBackArrow={true} /> <Header - setHeaderHeight={defineHeaderHeight} - desktopTitleKey={'common.title_quiz'} + setHeaderHeight={setHeaderHeight} + desktopTitleKey="common.title_quiz" displayBackArrow={true} /> - <Content height={headerHeight}> + <Content heightOffset={headerHeight}> {currentChallenge && renderQuiz(currentChallenge)} </Content> </> diff --git a/src/components/Home/ReleaseNotesModal.scss b/src/components/ReleaseNotesModal/ReleaseNotesModal.scss similarity index 93% rename from src/components/Home/ReleaseNotesModal.scss rename to src/components/ReleaseNotesModal/ReleaseNotesModal.scss index 83ac0850d4ca6d9abdfe26064eaa0510a6959282..f17f44f76eeb3adfffd53071990a0b848bae921c 100644 --- a/src/components/Home/ReleaseNotesModal.scss +++ b/src/components/ReleaseNotesModal/ReleaseNotesModal.scss @@ -1,5 +1,5 @@ -@import '../../styles/base/color'; -@import '../../styles/base/breakpoint'; +@import 'src/styles/base/color'; +@import 'src/styles/base/breakpoint'; .release-root.black { .modal-overlay { diff --git a/src/components/Home/ReleaseNotesModal.tsx b/src/components/ReleaseNotesModal/ReleaseNotesModal.tsx similarity index 83% rename from src/components/Home/ReleaseNotesModal.tsx rename to src/components/ReleaseNotesModal/ReleaseNotesModal.tsx index 13dac570ae33003d448fcaaaf5e2376182bfd6af..4d6c6988e43844ac20c6209990efd459afce63bd 100644 --- a/src/components/Home/ReleaseNotesModal.tsx +++ b/src/components/ReleaseNotesModal/ReleaseNotesModal.tsx @@ -2,9 +2,7 @@ import Button from '@material-ui/core/Button' import Dialog from '@material-ui/core/Dialog' import { useI18n } from 'cozy-ui/transpiled/react/I18n' import React from 'react' -import { useSelector } from 'react-redux' -import { AppStore } from 'store' -import { decoreText } from 'utils/decoreText' +import { useAppSelector } from 'store/hooks' import './ReleaseNotesModal.scss' interface ReleaseNotesModalProps { @@ -17,7 +15,7 @@ const ReleaseNotesModal = ({ handleCloseClick, }: ReleaseNotesModalProps) => { const { t } = useI18n() - const { releaseNotes } = useSelector((state: AppStore) => state.ecolyo.global) + const { releaseNotes } = useAppSelector(state => state.ecolyo.global) return ( <Dialog @@ -26,13 +24,13 @@ const ReleaseNotesModal = ({ onClose={(event, reason): void => { event && reason !== 'backdropClick' && handleCloseClick() }} - aria-labelledby={'accessibility-title'} + aria-labelledby="accessibility-title" classes={{ root: 'modal-root', paper: 'modal-paper', }} > - <div id={'accessibility-title'}> + <div id="accessibility-title"> {t( 'consumption_visualizer.release_notes_modal.accessibility.window_title' )} @@ -52,9 +50,10 @@ const ReleaseNotesModal = ({ <div className="release-note-message text-16-bold"> {note.title} </div> - <div className="release-note-description text-16-normal"> - {decoreText(note.description)} - </div> + <div + className="release-note-description text-16-normal" + dangerouslySetInnerHTML={{ __html: note.description }} + /> </div> ))} </div> diff --git a/src/components/Routes/Routes.tsx b/src/components/Routes/Routes.tsx index f795d67a8ad84ed5ba1844b6b413476eeea30dcf..259830e52e4c14771f18f5d2f047accdab59ebad 100644 --- a/src/components/Routes/Routes.tsx +++ b/src/components/Routes/Routes.tsx @@ -3,23 +3,25 @@ import ChallengeView from 'components/Challenge/ChallengeView' import SgeConnectView from 'components/Connection/SGEConnect/SgeConnectView' import DuelView from 'components/Duel/DuelView' import EcogestureFormView from 'components/EcogestureForm/EcogestureFormView' -import EcogestureSelection from 'components/EcogestureSelection/EcogestureSelection' +import EcogestureSelectionView from 'components/EcogestureSelection/EcogestureSelectionView' import ExplorationView from 'components/Exploration/ExplorationView' import Loader from 'components/Loader/Loader' -import UnSubscribe from 'components/Options/Unsubscribe/UnSubscribe' +import UnSubscribeView from 'components/Options/Unsubscribe/UnSubscribeView' import QuizView from 'components/Quiz/QuizView' import TermsView from 'components/Terms/TermsView' -import { FluidType } from 'enum/fluid.enum' +import { FluidType } from 'enums' import { TermsStatus } from 'models' import React, { lazy, Suspense } from 'react' import { Navigate, Route, Routes } from 'react-router-dom' -const ConsumptionView = lazy(() => import('components/Home/ConsumptionView')) -const EcogestureView = lazy( - () => import('components/Ecogesture/EcogestureView') +const ConsumptionView = lazy( + () => import('components/Consumption/ConsumptionView') ) -const SingleEcogesture = lazy( - () => import('components/Ecogesture/SingleEcogesture') +const EcogestureTabsView = lazy( + () => import('components/Ecogesture/EcogestureTabsView') +) +const SingleEcogestureView = lazy( + () => import('components/Ecogesture/SingleEcogestureView') ) const OptionsView = lazy(() => import('components/Options/OptionsView')) const LegalNoticeView = lazy( @@ -77,24 +79,20 @@ const AppRoutes = ({ termsStatus }: { termsStatus: TermsStatus }) => { <Route path="/ecogesture-form" element={<EcogestureFormView />} /> <Route path="/ecogesture-selection" - element={<EcogestureSelection />} - /> - <Route - path="/ecogesture/:ecogestureID/:tab" - element={<SingleEcogesture />} + element={<EcogestureSelectionView />} /> <Route path="/ecogesture/:ecogestureID" - element={<SingleEcogesture />} + element={<SingleEcogestureView />} /> - <Route path="/ecogestures" element={<EcogestureView />} /> + <Route path="/ecogestures" element={<EcogestureTabsView />} /> <Route path="/options/legalnotice" element={<LegalNoticeView />} /> <Route path="/options/gcu" element={<GCUView />} /> <Route path="/options/:connectParam" element={<OptionsView />} /> <Route path="/options" element={<OptionsView />} /> <Route path="/analysis" element={<AnalysisView />} /> <Route path="/profiletype" element={<ProfileTypeView />} /> - <Route path="/unsubscribe" element={<UnSubscribe />} /> + <Route path="/unsubscribe" element={<UnSubscribeView />} /> <Route path="*" element={<Navigate replace to="/consumption" />} /> </> )} diff --git a/src/components/Splash/SplashRoot.spec.tsx b/src/components/Splash/SplashRoot.spec.tsx index e54bcec9139affbde9ea8a3319b6c89631f3b0d0..55bce081c191a794a3c82d34dafa55c0c344c466 100644 --- a/src/components/Splash/SplashRoot.spec.tsx +++ b/src/components/Splash/SplashRoot.spec.tsx @@ -1,8 +1,8 @@ import { mount } from 'enzyme' import toJson from 'enzyme-to-json' import React from 'react' -import * as reactRedux from 'react-redux' -import { userChallengeExplo1OnGoing } from '../../../tests/__mocks__/userChallengeData.mock' +import { Provider } from 'react-redux' +import { createMockEcolyoStore } from 'tests/__mocks__/store' import SplashRoot from './SplashRoot' jest.mock('@sentry/react', () => ({ @@ -11,23 +11,16 @@ jest.mock('@sentry/react', () => ({ startTransaction: () => ({ finish: jest.fn() }), })) -jest.mock('cozy-ui/transpiled/react/I18n', () => { - return { - useI18n: jest.fn(() => { - return { - t: (str: string) => str, - } - }), - } -}) -const mockUseSelector = jest.spyOn(reactRedux, 'useSelector') -const mockUseDispatch = jest.spyOn(reactRedux, 'useDispatch') - describe('SplashRoot component', () => { - it('should be rendered correctly', () => { - mockUseSelector.mockReturnValue(userChallengeExplo1OnGoing) - mockUseDispatch.mockReturnValue(jest.fn()) - const component = mount(<SplashRoot>children</SplashRoot>) + it('should be rendered correctly', async () => { + const store = createMockEcolyoStore() + const component = mount( + <Provider store={store}> + <SplashRoot>children</SplashRoot> + </Provider> + ) + // TODO we should waitForComponent + // await waitForComponentToPaint(component) expect(toJson(component)).toMatchSnapshot() }) }) diff --git a/src/components/Splash/SplashRoot.tsx b/src/components/Splash/SplashRoot.tsx index 6559550039424c1254a815af1257d65b8e675e4e..49d280d3116c663c49bf5d8c2fe2e2c70041ed9c 100644 --- a/src/components/Splash/SplashRoot.tsx +++ b/src/components/Splash/SplashRoot.tsx @@ -2,14 +2,14 @@ import * as Sentry from '@sentry/react' import classNames from 'classnames' import useExploration from 'components/Hooks/useExploration' import { useClient } from 'cozy-client' -import { UsageEventType } from 'enum/usageEvent.enum' -import { UserActionState } from 'enum/userAction.enum' -import { UserChallengeState } from 'enum/userChallenge.enum' -import { UserDuelState } from 'enum/userDuel.enum' import { + UsageEventType, + UserActionState, + UserChallengeState, + UserDuelState, UserExplorationID, UserExplorationState, -} from 'enum/userExploration.enum' +} from 'enums' import { DateTime } from 'luxon' import { migrations } from 'migrations/migration.data' import { MigrationService } from 'migrations/migration.service' @@ -22,14 +22,7 @@ import { ProfileType, UserChallenge, } from 'models' -import React, { - Dispatch, - ReactNode, - useCallback, - useEffect, - useState, -} from 'react' -import { useDispatch } from 'react-redux' +import React, { ReactNode, useCallback, useEffect, useState } from 'react' import ActionService from 'services/action.service' import ChallengeService from 'services/challenge.service' import CustomPopupService from 'services/customPopup.service' @@ -38,7 +31,6 @@ import InitializationService from 'services/initialization.service' import PartnersInfoService from 'services/partnersInfo.service' import ProfileTypeEntityService from 'services/profileTypeEntity.service' import UsageEventService from 'services/usageEvent.service' -import { AppActionsTypes } from 'store' import { setAnalysisMonth } from 'store/analysis/analysis.slice' import { setChallengeConsumption, @@ -53,11 +45,12 @@ import { toggleChallengeActionNotification, toggleChallengeDuelNotification, toggleChallengeExplorationNotification, - updateTermValidation, -} from 'store/global/global.actions' + updateTermsStatus, +} from 'store/global/global.slice' +import { useAppDispatch } from 'store/hooks' import { openPartnersModal, setCustomPopup } from 'store/modal/modal.slice' -import { updateProfile } from 'store/profile/profile.actions' -import { updateProfileEcogestureSuccess } from 'store/profileEcogesture/profileEcogesture.actions' +import { updateProfile } from 'store/profile/profile.slice' +import { setProfileEcogesture } from 'store/profileEcogesture/profileEcogesture.slice' import { setProfileType } from 'store/profileType/profileType.slice' import { logDuration } from 'utils/duration' import logApp from 'utils/logger' @@ -78,6 +71,7 @@ interface SplashRootProps { const SplashRoot = ({ fadeTimer = 1000, children }: SplashRootProps) => { const client = useClient() const today = getTodayDate().toISO() + const dispatch = useAppDispatch() const [{ splashEnd, splashStart }, setState] = useState({ splashEnd: false, splashStart: false, @@ -87,7 +81,6 @@ const SplashRoot = ({ fadeTimer = 1000, children }: SplashRootProps) => { const [initStepErrors, setInitStepErrors] = useState<InitStepsErrors | null>( null ) - const dispatch: Dispatch<AppActionsTypes> = useDispatch() /** Return current status of partner if modal has not been seen today */ const getPartnerStatus = useCallback( @@ -208,7 +201,7 @@ const SplashRoot = ({ fadeTimer = 1000, children }: SplashRootProps) => { try { // init Terms const termsStatus = await initializationService.initConsent() - if (subscribed) dispatch(updateTermValidation(termsStatus)) + if (subscribed) dispatch(updateTermsStatus(termsStatus)) // Init fluidPrices await initializationService.initFluidPrices() @@ -222,11 +215,11 @@ const SplashRoot = ({ fadeTimer = 1000, children }: SplashRootProps) => { const migrationsResult = await ms.runMigrations(migrations) // Init last release notes when they exist dispatch( - showReleaseNotes( - migrationsResult.show, - migrationsResult.notes, - migrationsResult.redirectLink - ) + showReleaseNotes({ + notes: migrationsResult.notes, + redirectLink: migrationsResult.redirectLink, + show: migrationsResult.show, + }) ) if (subscribed && profile) { setValidExploration(UserExplorationID.EXPLORATION007) @@ -257,7 +250,7 @@ const SplashRoot = ({ fadeTimer = 1000, children }: SplashRootProps) => { await loadProfileType(profileType) } if (profileEcogesture) { - dispatch(updateProfileEcogestureSuccess(profileEcogesture)) + dispatch(setProfileEcogesture(profileEcogesture)) } dispatch(toggleAnalysisNotification(!profile.haveSeenLastAnalysis)) } @@ -380,7 +373,7 @@ const SplashRoot = ({ fadeTimer = 1000, children }: SplashRootProps) => { setInitStepErrors(InitStepsErrors.UNKNOWN_ERROR) } logApp.error(`[Initialization] Error : ${error}`) - Sentry.captureException(JSON.stringify({ error })) + Sentry.captureException(error) } finally { transaction.finish() } diff --git a/src/components/Splash/SplashScreen.spec.tsx b/src/components/Splash/SplashScreen.spec.tsx index f84d639835334a30a8e19bcf51e627f78a823b4d..2277171e630a2a725a43747ee81bd56cadb6384b 100644 --- a/src/components/Splash/SplashScreen.spec.tsx +++ b/src/components/Splash/SplashScreen.spec.tsx @@ -4,16 +4,6 @@ import { InitSteps } from 'models/initialisationSteps.model' import React from 'react' import SplashScreen from './SplashScreen' -jest.mock('cozy-ui/transpiled/react/I18n', () => { - return { - useI18n: jest.fn(() => { - return { - t: (str: string) => str, - } - }), - } -}) - describe('SplashScreen component', () => { it('should be rendered correctly', () => { const component = mount(<SplashScreen initStep={InitSteps.CONSENT} />) diff --git a/src/components/Splash/SplashScreen.tsx b/src/components/Splash/SplashScreen.tsx index 468b85b5f9eb5b2a450bf4101e500839f8a857b8..6b71828829fa2a0fc85950a92fe5cb4ee53eed22 100644 --- a/src/components/Splash/SplashScreen.tsx +++ b/src/components/Splash/SplashScreen.tsx @@ -1,17 +1,16 @@ import logoLoading from 'assets/anims/logoLoading.gif' import logos from 'assets/png/logos_partenaires.svg' import { useI18n } from 'cozy-ui/transpiled/react/I18n' -import { InitSteps } from 'models/initialisationSteps.model' +import { InitSteps } from 'models' import React from 'react' import './splashScreen.scss' const SplashScreen = ({ initStep }: { initStep: InitSteps }) => { const { t } = useI18n() const getProgress = () => { - const total: number = Object.values(InitSteps).length / 2 - const progress: number = - initStep === 0 ? 10 : Math.round((initStep / total) * 100) - return progress + const total = Object.values(InitSteps).length / 2 + const progress = initStep === 0 ? 10 : Math.round((initStep / total) * 100) + return progress - 90 /* hack to make the progress bar start way left */ } return ( <> @@ -23,7 +22,7 @@ const SplashScreen = ({ initStep }: { initStep: InitSteps }) => { <div className="splash-progress-bar-container"> <div className="splash-progress-bar-content" - style={{ width: `${getProgress()}%` }} + style={{ left: `${getProgress()}%` }} /> </div> </div> diff --git a/src/components/Splash/SplashScreenError.spec.tsx b/src/components/Splash/SplashScreenError.spec.tsx index 2c5fceffbd11b61fbb1c5c1f3d6e486086bdabef..2f3837093ea572132a209200d5be30813769565e 100644 --- a/src/components/Splash/SplashScreenError.spec.tsx +++ b/src/components/Splash/SplashScreenError.spec.tsx @@ -5,16 +5,6 @@ import { InitStepsErrors } from 'models/initialisationSteps.model' import React from 'react' import SplashScreenError from './SplashScreenError' -jest.mock('cozy-ui/transpiled/react/I18n', () => { - return { - useI18n: jest.fn(() => { - return { - t: (str: string) => str, - } - }), - } -}) - describe('SplashScreenError component', () => { const reload = window.location.reload diff --git a/src/components/Splash/SplashScreenError.tsx b/src/components/Splash/SplashScreenError.tsx index 91eaf7dbac5a299a8bfbf089bdaef94dd8408584..1ebaaac2abd87d83b4931eb31503ee1bdd802010 100644 --- a/src/components/Splash/SplashScreenError.tsx +++ b/src/components/Splash/SplashScreenError.tsx @@ -2,7 +2,7 @@ import Button from '@material-ui/core/Button' import ecolyoIcon from 'assets/icons/ico/ecolyo.svg' import StyledIcon from 'components/CommonKit/Icon/StyledIcon' import { useI18n } from 'cozy-ui/transpiled/react/I18n' -import { InitStepsErrors } from 'models/initialisationSteps.model' +import { InitStepsErrors } from 'models' import React from 'react' import './splashScreen.scss' diff --git a/src/components/Splash/__snapshots__/SplashRoot.spec.tsx.snap b/src/components/Splash/__snapshots__/SplashRoot.spec.tsx.snap index 143c5d080b97c0fc008a880d869440f3d7117d5f..e08db15efcfc96775a4cb572766f96015ae5e8b5 100644 --- a/src/components/Splash/__snapshots__/SplashRoot.spec.tsx.snap +++ b/src/components/Splash/__snapshots__/SplashRoot.spec.tsx.snap @@ -1,63 +1,76 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP exports[`SplashRoot component should be rendered correctly 1`] = ` -<SplashRoot> - <div - className="splash-root" - style={ - Object { - "transitionDuration": "1s", - } +<Provider + store={ + Object { + "clearActions": [Function], + "dispatch": [Function], + "getActions": [Function], + "getState": [Function], + "replaceReducer": [Function], + "subscribe": [Function], } - > - <SplashScreen - initStep={1} + } +> + <SplashRoot> + <div + className="splash-root" + style={ + Object { + "transitionDuration": "1s", + } + } > - <div - className="splash-content" + <SplashScreen + initStep={1} > <div - className="splash-loader" + className="splash-content" > - <img - alt="Chargement" - src="test-file-stub" - /> - <span> - Ecolyo - </span> <div - className="splash-progress" + className="splash-loader" > + <img + alt="Chargement" + src="test-file-stub" + /> + <span> + Ecolyo + </span> <div - className="splash-progress-bar-container" + className="splash-progress" > <div - className="splash-progress-bar-content" - style={ - Object { - "width": "17%", + className="splash-progress-bar-container" + > + <div + className="splash-progress-bar-content" + style={ + Object { + "left": "-73%", + } } - } - /> + /> + </div> </div> </div> + <div + className="step-label text-18-normal" + > + splashscreen.step.1 + </div> + <div + className="splash-logos-container" + > + <img + alt="ensemble de logos" + src="test-file-stub" + /> + </div> </div> - <div - className="step-label text-18-normal" - > - splashscreen.step.1 - </div> - <div - className="splash-logos-container" - > - <img - alt="ensemble de logos" - src="test-file-stub" - /> - </div> - </div> - </SplashScreen> - </div> -</SplashRoot> + </SplashScreen> + </div> + </SplashRoot> +</Provider> `; diff --git a/src/components/Splash/__snapshots__/SplashScreen.spec.tsx.snap b/src/components/Splash/__snapshots__/SplashScreen.spec.tsx.snap index 03f304221a00fb3d066ee05a3f92b919d04add4d..089fbbee784a09ee4bde93983143a772877d50d4 100644 --- a/src/components/Splash/__snapshots__/SplashScreen.spec.tsx.snap +++ b/src/components/Splash/__snapshots__/SplashScreen.spec.tsx.snap @@ -27,7 +27,7 @@ exports[`SplashScreen component should be rendered correctly 1`] = ` className="splash-progress-bar-content" style={ Object { - "width": "17%", + "left": "-73%", } } /> diff --git a/src/components/Splash/splashScreen.scss b/src/components/Splash/splashScreen.scss index af366e848959e8ef7596c9ccae85c4545a97f575..a9456aaec07796c2dec991e2684ce719d7c0fafa 100644 --- a/src/components/Splash/splashScreen.scss +++ b/src/components/Splash/splashScreen.scss @@ -72,7 +72,6 @@ border-radius: 12px; box-sizing: border-box; max-width: 350px; - .splash-progress-bar-container { flex: 1; height: 12px; @@ -90,29 +89,16 @@ background-size: 9px 9px; border: solid 1px $gold-shadow; border-radius: 12px; + overflow: hidden; + position: relative; .splash-progress-bar-content { - height: 12px; - box-sizing: border-box; background-color: $gold-shadow; - border: solid 1px $gold-shadow; - border-radius: 12px 4px 0 12px; - border-right: none; - transition: all 300ms ease; - position: relative; - overflow: hidden; - top: -1px; - left: -1px; - &:after { - content: ''; - position: absolute; - display: block; - transform: rotate(45deg); - background-color: $dark-2; - width: 15px; - height: 15px; - right: -9px; - top: -8px; - } + position: absolute; + bottom: -150px; + left: -100%; + height: 300px; + width: 100%; + transform: rotate(45deg); } } } diff --git a/src/components/Terms/CGUModal.spec.tsx b/src/components/Terms/CGUModal.spec.tsx index 154bfef851e2d3d55570037b7dce35841a508f56..8e54916bc82c6fc57c15e19143b5445b98707f21 100644 --- a/src/components/Terms/CGUModal.spec.tsx +++ b/src/components/Terms/CGUModal.spec.tsx @@ -3,16 +3,6 @@ import toJson from 'enzyme-to-json' import React from 'react' import CGUModal from './CGUModal' -jest.mock('cozy-ui/transpiled/react/I18n', () => { - return { - useI18n: jest.fn(() => { - return { - t: (str: string) => str, - } - }), - } -}) - describe('CGUModal component', () => { it('should be rendered correctly', () => { const component = mount( diff --git a/src/components/Terms/CGUModal.tsx b/src/components/Terms/CGUModal.tsx index 2102a0a3d890b04fbd8d66bc8618ea8abb778ea4..ea7517d8025bcc0f93dbee0a6b76bea8845f498c 100644 --- a/src/components/Terms/CGUModal.tsx +++ b/src/components/Terms/CGUModal.tsx @@ -17,13 +17,13 @@ const CGUModal = ({ open, handleCloseClick }: CGUModalProps) => { <Dialog open={open} onClose={handleCloseClick} - aria-labelledby={'accessibility-title'} + aria-labelledby="accessibility-title" classes={{ root: 'modal-root', paper: 'modal-paper', }} > - <div id={'accessibility-title'}> + <div id="accessibility-title"> {t('feedback.accessibility.window_title')} </div> <IconButton diff --git a/src/components/Terms/DataShareConsentContent.spec.tsx b/src/components/Terms/DataShareConsentContent.spec.tsx index 43865afb140d5fd455a5f096708cccd6df9965ba..e2653b92ad8d0b25428984fbb73461a13912c05b 100644 --- a/src/components/Terms/DataShareConsentContent.spec.tsx +++ b/src/components/Terms/DataShareConsentContent.spec.tsx @@ -2,27 +2,13 @@ import { mount } from 'enzyme' import toJson from 'enzyme-to-json' import React from 'react' import { Provider } from 'react-redux' -import configureStore from 'redux-mock-store' -import { profileData } from '../../../tests/__mocks__/profileData.mock' +import { createMockEcolyoStore } from 'tests/__mocks__/store' import DataShareConsentContent from './DataShareConsentContent' -jest.mock('cozy-ui/transpiled/react/I18n', () => { - return { - useI18n: jest.fn(() => { - return { - t: (str: string) => str, - } - }), - } -}) -const mockStore = configureStore([]) - describe('DataShareConsentContent component', () => { it('should be rendered correctly with first connexion text', () => { - const store = mockStore({ - ecolyo: { - profile: profileData, - }, + const store = createMockEcolyoStore({ + profile: { isFirstConnection: true }, }) const component = mount( <Provider store={store}> @@ -32,11 +18,8 @@ describe('DataShareConsentContent component', () => { expect(toJson(component)).toMatchSnapshot() }) it('should be rendered correctly without first connexion text', () => { - profileData.isFirstConnection = false - const store = mockStore({ - ecolyo: { - profile: profileData, - }, + const store = createMockEcolyoStore({ + profile: { isFirstConnection: false }, }) const component = mount( <Provider store={store}> diff --git a/src/components/Terms/DataShareConsentContent.tsx b/src/components/Terms/DataShareConsentContent.tsx index 8a561a2652fc27aea34e396bbcfc360315b31157..97e17a7abb99a7e0e5fc8b9bef177412afe13654 100644 --- a/src/components/Terms/DataShareConsentContent.tsx +++ b/src/components/Terms/DataShareConsentContent.tsx @@ -1,15 +1,11 @@ import { useI18n } from 'cozy-ui/transpiled/react/I18n' import React from 'react' -import { useSelector } from 'react-redux' -import { AppStore } from 'store' -import { decoreText } from 'utils/decoreText' +import { useAppSelector } from 'store/hooks' import './termsView.scss' const DataShareConsentContent = () => { const { t } = useI18n() - const { isFirstConnection } = useSelector( - (state: AppStore) => state.ecolyo.profile - ) + const { isFirstConnection } = useAppSelector(state => state.ecolyo.profile) return ( <div className="dataShare-content-root"> @@ -32,14 +28,15 @@ const DataShareConsentContent = () => { </ul> <p className="text-14-normal">{t('dataShare.part4')}</p> <p className="text-14-normal">{t('dataShare.part5')}</p> - <p className="text-14-normal">{decoreText(t('dataShare.part6'))}</p> + <p className="text-14-normal">{t('dataShare.part6')}</p> <p className="text-14-normal">{t('dataShare.part7')}</p> <p className="text-14-normal">{t('dataShare.part8')}</p> <span className="text-14-normal">{t('dataShare.part9')}</span> <span className="text-14-normal">{t('dataShare.part10')}</span> - <span className="text-14-normal"> - {decoreText(t('dataShare.link1'))} - </span> + <span + className="text-14-normal" + dangerouslySetInnerHTML={{ __html: t('dataShare.link1') }} + /> </div> </div> ) diff --git a/src/components/Terms/LegalNoticeModal.spec.tsx b/src/components/Terms/LegalNoticeModal.spec.tsx index daf57584765892879423ec486a95e32b98213a8b..1c8144711c383bebe7ab3f60a0cea09f67986d5f 100644 --- a/src/components/Terms/LegalNoticeModal.spec.tsx +++ b/src/components/Terms/LegalNoticeModal.spec.tsx @@ -3,16 +3,6 @@ import toJson from 'enzyme-to-json' import React from 'react' import LegalNoticeModal from './LegalNoticeModal' -jest.mock('cozy-ui/transpiled/react/I18n', () => { - return { - useI18n: jest.fn(() => { - return { - t: (str: string) => str, - } - }), - } -}) - describe('LegalNoticeModal component', () => { it('should be rendered correctly', () => { const component = mount( diff --git a/src/components/Terms/LegalNoticeModal.tsx b/src/components/Terms/LegalNoticeModal.tsx index 7e7e15f3b616a112441680adcbdd996d30394fd6..79247af0ec8d3289202f78cb47d741d03d8c29f1 100644 --- a/src/components/Terms/LegalNoticeModal.tsx +++ b/src/components/Terms/LegalNoticeModal.tsx @@ -21,13 +21,13 @@ const LegalNoticeModal = ({ <Dialog open={open} onClose={handleCloseClick} - aria-labelledby={'accessibility-title'} + aria-labelledby="accessibility-title" classes={{ root: 'modal-root', paper: 'modal-paper', }} > - <div id={'accessibility-title'}>{t('legal.title_legal')}</div> + <div id="accessibility-title">{t('legal.title_legal')}</div> <IconButton aria-label={t('feedback.accessibility.button_close')} className="modal-paper-close-button" diff --git a/src/components/Terms/MinorUpdateContent.spec.tsx b/src/components/Terms/MinorUpdateContent.spec.tsx index 642be1f800c8459981c19180688b660fe7712d4f..01cc232537a5da4339ab3337eeb4541942cfac08 100644 --- a/src/components/Terms/MinorUpdateContent.spec.tsx +++ b/src/components/Terms/MinorUpdateContent.spec.tsx @@ -3,16 +3,6 @@ import toJson from 'enzyme-to-json' import React from 'react' import MinorUpdateContent from './MinorUpdateContent' -jest.mock('cozy-ui/transpiled/react/I18n', () => { - return { - useI18n: jest.fn(() => { - return { - t: (str: string) => str, - } - }), - } -}) - describe('Minor update content component', () => { it('should be rendered correctly', () => { const component = mount(<MinorUpdateContent />) diff --git a/src/components/Terms/TermsView.spec.tsx b/src/components/Terms/TermsView.spec.tsx index 377c3e49cfb52fea474d0d98cfe63946bbf8c340..f615514e3d753f11560337e1c47e5bffe8d63fd6 100644 --- a/src/components/Terms/TermsView.spec.tsx +++ b/src/components/Terms/TermsView.spec.tsx @@ -2,49 +2,28 @@ import { Button } from '@material-ui/core' import { mount } from 'enzyme' import toJson from 'enzyme-to-json' import React from 'react' -import * as reactRedux from 'react-redux' import { Provider } from 'react-redux' -import { default as configureStore } from 'redux-mock-store' -import { createMockEcolyoStore } from '../../../tests/__mocks__/store' -import { mockUpToDateTerm } from '../../../tests/__mocks__/termsData.mock' +import * as storeHooks from 'store/hooks' +import { createMockEcolyoStore } from 'tests/__mocks__/store' +import { mockUpToDateTerm } from 'tests/__mocks__/termsData.mock' import TermsView from './TermsView' -jest.mock('cozy-ui/transpiled/react/I18n', () => { - return { - useI18n: jest.fn(() => { - return { - t: (str: string) => str, - } - }), - } -}) - const mockCreateTerm = jest.fn() const mockGetTermsVersionType = jest.fn() jest.mock('services/terms.service', () => { - return jest.fn(() => { - return { - createTerm: mockCreateTerm, - getTermsVersionType: mockGetTermsVersionType, - } - }) + return jest.fn(() => ({ + createTerm: mockCreateTerm, + getTermsVersionType: mockGetTermsVersionType, + })) }) -const mockedNavigate = jest.fn() -jest.mock('react-router-dom', () => ({ - ...jest.requireActual('react-router-dom'), - useNavigate: () => mockedNavigate, -})) -const mockStore = configureStore([]) -const mockUseDispatch = jest.spyOn(reactRedux, 'useDispatch') +const mockAppDispatch = jest.spyOn(storeHooks, 'useAppDispatch') const mockUpdateProfile = jest.fn() jest.mock('services/profile.service', () => { - return jest.fn(() => { - return { - updateProfile: mockUpdateProfile, - } - }) + return jest.fn(() => ({ + updateProfile: mockUpdateProfile, + })) }) describe('TermsView component', () => { @@ -69,7 +48,7 @@ describe('TermsView component', () => { expect(wrapper.find('input').at(1).props().checked).toEqual(true) expect(wrapper.find(Button).first().hasClass('disabled')).toBeFalsy() wrapper.find(Button).first().simulate('click') - expect(mockUseDispatch).toHaveBeenCalledTimes(3) + expect(mockAppDispatch).toHaveBeenCalledTimes(3) }) it('should be rendered correctly', () => { const component = mount( diff --git a/src/components/Terms/TermsView.tsx b/src/components/Terms/TermsView.tsx index 5ce7b5a0c550ee620b257ffbeeb3ba17e5f46783..728aa5ec018aa2a8e42c940f60c911f65b6681f3 100644 --- a/src/components/Terms/TermsView.tsx +++ b/src/components/Terms/TermsView.tsx @@ -2,13 +2,11 @@ import { Button } from '@material-ui/core' import classNames from 'classnames' import { useClient } from 'cozy-client' import { useI18n } from 'cozy-ui/transpiled/react/I18n' -import React, { Dispatch, useCallback, useState } from 'react' -import { useDispatch, useSelector } from 'react-redux' +import React, { useCallback, useState } from 'react' import { useNavigate } from 'react-router-dom' import TermsService from 'services/terms.service' -import { AppActionsTypes, AppStore } from 'store' -import { updateTermValidation } from 'store/global/global.actions' -import { decoreText } from 'utils/decoreText' +import { updateTermsStatus } from 'store/global/global.slice' +import { useAppDispatch, useAppSelector } from 'store/hooks' import CGUModal from './CGUModal' import DataShareConsentContent from './DataShareConsentContent' import LegalNoticeModal from './LegalNoticeModal' @@ -18,15 +16,15 @@ import './termsView.scss' const TermsView = () => { const { t } = useI18n() const client = useClient() - const dispatch = useDispatch<Dispatch<AppActionsTypes>>() const navigate = useNavigate() + const dispatch = useAppDispatch() + const { termsStatus } = useAppSelector(state => state.ecolyo.global) const [GCUValidation, setGCUValidation] = useState<boolean>(false) const [dataConsentValidation, setDataConsentValidation] = useState<boolean>(false) const [openCGUModal, setOpenCGUModal] = useState<boolean>(false) const [openLegalNoticeModal, setOpenLegalNoticeModal] = useState<boolean>(false) - const { termsStatus } = useSelector((state: AppStore) => state.ecolyo.global) const toggleCGUModal = () => { setOpenCGUModal(prev => !prev) @@ -48,7 +46,7 @@ const TermsView = () => { const createdTerm = await termsService.createTerm() if (createdTerm) { dispatch( - updateTermValidation({ + updateTermsStatus({ accepted: true, versionType: await termsService.getTermsVersionType(), }) @@ -70,7 +68,7 @@ const TermsView = () => { })} > <input - type={'checkbox'} + type="checkbox" name="Data-consent-validation" onChange={handleDataConsentValidation} checked={dataConsentValidation} @@ -83,17 +81,29 @@ const TermsView = () => { })} > <input - type={'checkbox'} + type="checkbox" name="GCU-validation" onChange={handleGCUValidate} checked={GCUValidation} /> - <span> - {decoreText(t('dataShare.validCGU'), () => toggleCGUModal())} - {decoreText(t('dataShare.validLegal'), () => - toggleLegalNoticeModal() - )} - </span> + <div> + <span + onClick={e => { + e.preventDefault() + toggleCGUModal() + }} + dangerouslySetInnerHTML={{ __html: t('dataShare.validCGU') }} + /> + <span + onClick={e => { + e.preventDefault() + toggleLegalNoticeModal() + }} + dangerouslySetInnerHTML={{ + __html: t('dataShare.validLegal'), + }} + /> + </div> </label> </div> <div className="terms-footer"> @@ -122,7 +132,7 @@ const TermsView = () => { <Button aria-label={t('minorUpdate.button')} onClick={handleTermValidate} - className={'gcu-modal-button'} + className="gcu-modal-button" classes={{ root: 'btn-profile-next rounded', label: 'text-16-bold', diff --git a/src/components/Terms/__snapshots__/CGUModal.spec.tsx.snap b/src/components/Terms/__snapshots__/CGUModal.spec.tsx.snap index f4c8c69d3d9466806c769c35f927478916bc178e..640e034ecfb9141db9aa27c259b0e319b3ea84e9 100644 --- a/src/components/Terms/__snapshots__/CGUModal.spec.tsx.snap +++ b/src/components/Terms/__snapshots__/CGUModal.spec.tsx.snap @@ -1164,9 +1164,12 @@ exports[`CGUModal component should be rendered correctly 1`] = ` </p> <p className="text-14-normal" - > - gcu.content.part4_2 - </p> + dangerouslySetInnerHTML={ + Object { + "__html": "gcu.content.part4_2", + } + } + /> <div className="gcu-content-part-title text-15-normal" > @@ -1262,9 +1265,12 @@ exports[`CGUModal component should be rendered correctly 1`] = ` </p> <p className="text-14-normal" - > - gcu.content.part8_2 - </p> + dangerouslySetInnerHTML={ + Object { + "__html": "gcu.content.part8_2", + } + } + /> <div className="gcu-content-part-title text-15-normal" > @@ -1314,9 +1320,13 @@ exports[`CGUModal component should be rendered correctly 1`] = ` > gcu.content.part9_4_title </span> - <span> - gcu.content.part9_4_content - </span> + <span + dangerouslySetInnerHTML={ + Object { + "__html": "gcu.content.part9_4_content", + } + } + /> </p> <p className="text-14-normal" diff --git a/src/components/Terms/__snapshots__/DataShareConsentContent.spec.tsx.snap b/src/components/Terms/__snapshots__/DataShareConsentContent.spec.tsx.snap index 6355e73b82194c4e4bc3ac49991f1a4c4b01487e..e73f9fe284542df8c5d93672bea9a157f7f20820 100644 --- a/src/components/Terms/__snapshots__/DataShareConsentContent.spec.tsx.snap +++ b/src/components/Terms/__snapshots__/DataShareConsentContent.spec.tsx.snap @@ -96,9 +96,12 @@ exports[`DataShareConsentContent component should be rendered correctly with fir </span> <span className="text-14-normal" - > - dataShare.link1 - </span> + dangerouslySetInnerHTML={ + Object { + "__html": "dataShare.link1", + } + } + /> </div> </div> </DataShareConsentContent> @@ -206,9 +209,12 @@ exports[`DataShareConsentContent component should be rendered correctly without </span> <span className="text-14-normal" - > - dataShare.link1 - </span> + dangerouslySetInnerHTML={ + Object { + "__html": "dataShare.link1", + } + } + /> </div> </div> </DataShareConsentContent> diff --git a/src/components/Terms/__snapshots__/LegalNoticeModal.spec.tsx.snap b/src/components/Terms/__snapshots__/LegalNoticeModal.spec.tsx.snap index 5f03163208a50ffa6f4672024a25a81e4b3c98f2..81580a001b627d3cc9f40fa6bd9941ffe8155734 100644 --- a/src/components/Terms/__snapshots__/LegalNoticeModal.spec.tsx.snap +++ b/src/components/Terms/__snapshots__/LegalNoticeModal.spec.tsx.snap @@ -1055,9 +1055,13 @@ exports[`LegalNoticeModal component should be rendered correctly 1`] = ` > legal.version </p> - <p> - legal.site - </p> + <p + dangerouslySetInnerHTML={ + Object { + "__html": "legal.site", + } + } + /> <p> legal.adress </p> @@ -1066,9 +1070,12 @@ exports[`LegalNoticeModal component should be rendered correctly 1`] = ` </p> <p className="ln-contact" - > - legal.mail - </p> + dangerouslySetInnerHTML={ + Object { + "__html": "legal.mail", + } + } + /> <div className="text-16-normal" > @@ -1174,9 +1181,13 @@ exports[`LegalNoticeModal component should be rendered correctly 1`] = ` <li> legal.part2-3-4 </li> - <li> - legal.part2-3-5 - </li> + <li + dangerouslySetInnerHTML={ + Object { + "__html": "legal.part2-3-5", + } + } + /> </ul> </li> <li> @@ -1200,18 +1211,26 @@ exports[`LegalNoticeModal component should be rendered correctly 1`] = ` legal.part2-6-3 </li> </ul> - <p> - legal.part2-7 - </p> + <p + dangerouslySetInnerHTML={ + Object { + "__html": "legal.part2-7", + } + } + /> <p> legal.part2-8 </p> <p> legal.part2-9 </p> - <p> - legal.part2-10 - </p> + <p + dangerouslySetInnerHTML={ + Object { + "__html": "legal.part2-10", + } + } + /> <p> legal.part2-11 </p> @@ -1271,9 +1290,13 @@ exports[`LegalNoticeModal component should be rendered correctly 1`] = ` <p> legal.part7-1 </p> - <p> - legal.part7-2 - </p> + <p + dangerouslySetInnerHTML={ + Object { + "__html": "legal.part7-2", + } + } + /> <p> legal.part7-3 </p> diff --git a/src/components/Terms/__snapshots__/TermsView.spec.tsx.snap b/src/components/Terms/__snapshots__/TermsView.spec.tsx.snap index 5c505a9990fa805c946808d4fc2a52a395e6a6f4..3ea6482684fea0d932e35e3b127f8b71ea167c47 100644 --- a/src/components/Terms/__snapshots__/TermsView.spec.tsx.snap +++ b/src/components/Terms/__snapshots__/TermsView.spec.tsx.snap @@ -108,9 +108,12 @@ exports[`TermsView component should be rendered correctly 1`] = ` </span> <span className="text-14-normal" - > - dataShare.link1 - </span> + dangerouslySetInnerHTML={ + Object { + "__html": "dataShare.link1", + } + } + /> </div> </div> </DataShareConsentContent> @@ -134,10 +137,24 @@ exports[`TermsView component should be rendered correctly 1`] = ` onChange={[Function]} type="checkbox" /> - <span> - dataShare.validCGU - dataShare.validLegal - </span> + <div> + <span + dangerouslySetInnerHTML={ + Object { + "__html": "dataShare.validCGU", + } + } + onClick={[Function]} + /> + <span + dangerouslySetInnerHTML={ + Object { + "__html": "dataShare.validLegal", + } + } + onClick={[Function]} + /> + </div> </label> </div> <div diff --git a/src/components/Terms/termsView.scss b/src/components/Terms/termsView.scss index e7ccf1b1656d98024398c8d07b2d8ac48e969a5e..6e058dad69caa5f63058d3be2c3b384864bde654 100644 --- a/src/components/Terms/termsView.scss +++ b/src/components/Terms/termsView.scss @@ -1,6 +1,8 @@ @import 'src/styles/base/color'; @import 'src/styles/base/mixins'; +@include checkBox(); + .terms-wrapper { padding: 0rem 1.5rem 0 1.5rem; box-sizing: border-box; @@ -21,12 +23,15 @@ .terms-content { max-width: 45rem; margin: auto; + .action { + cursor: pointer; + color: $gold-shadow; + } } .dataShare-content-wrapper, .dataShare-content-root { width: inherit; } -@include checkBox(); .terms-footer { max-width: 45rem; @@ -43,12 +48,3 @@ } } } -button.action { - appearance: none; - cursor: pointer; - display: contents; - background: transparent; - border: none; - padding: 0; - color: $gold-shadow; -} diff --git a/src/components/TotalConsumption/TotalConsumption.spec.tsx b/src/components/TotalConsumption/TotalConsumption.spec.tsx index 6bc327a26d131b0951ba3f510cf1a0c9a10f267d..a427bd1cac2d56d05c8c9eaee6663c9c0fe5597d 100644 --- a/src/components/TotalConsumption/TotalConsumption.spec.tsx +++ b/src/components/TotalConsumption/TotalConsumption.spec.tsx @@ -1,31 +1,16 @@ -import { FluidType } from 'enum/fluid.enum' -import { TimeStep } from 'enum/timeStep.enum' +import { FluidType, TimeStep } from 'enums' import { mount } from 'enzyme' import React from 'react' import { Provider } from 'react-redux' -import configureStore from 'redux-mock-store' -import { graphData } from '../../../tests/__mocks__/chartData.mock' -import { mockInitialChartState } from '../../../tests/__mocks__/store' -import { waitForComponentToPaint } from '../../../tests/__mocks__/testUtils' +import { graphData } from 'tests/__mocks__/chartData.mock' +import { createMockEcolyoStore, mockChartState } from 'tests/__mocks__/store' +import { waitForComponentToPaint } from 'tests/__mocks__/testUtils' import TotalConsumption from './TotalConsumption' -jest.mock('cozy-ui/transpiled/react/I18n', () => { - return { - useI18n: jest.fn(() => { - return { - t: (str: string) => str, - } - }), - } -}) - -const mockStore = configureStore([]) -const mockChartStore = mockStore({ - ecolyo: { - chart: { - ...mockInitialChartState, - currentDatachart: graphData, - }, +const mockChartStore = createMockEcolyoStore({ + chart: { + ...mockChartState, + currentDatachart: graphData, }, }) @@ -60,14 +45,12 @@ describe('TotalConsumption component', () => { expect(component.find('.euro-value').first().text()).toEqual('130,84') }) it('should format multifluid value AND compared value', async () => { - const store = mockStore({ - ecolyo: { - chart: { - ...mockInitialChartState, - currentDatachart: graphData, - showCompare: true, - currentTimeStep: TimeStep.DAY, - }, + const store = createMockEcolyoStore({ + chart: { + ...mockChartState, + currentDatachart: graphData, + showCompare: true, + currentTimeStep: TimeStep.DAY, }, }) const component = mount( @@ -81,12 +64,7 @@ describe('TotalConsumption component', () => { expect(component.find('.euro-value').at(1).text()).toEqual('110,66') }) it('should display ----- when half an hour electricity data is not activated', async () => { - const store = mockStore({ - ecolyo: { - chart: mockInitialChartState, - currentDatachart: graphData, - }, - }) + const store = createMockEcolyoStore() const component = mount( <Provider store={store}> <TotalConsumption fluidType={FluidType.ELECTRICITY} /> diff --git a/src/components/TotalConsumption/TotalConsumption.tsx b/src/components/TotalConsumption/TotalConsumption.tsx index 032b6a78c8abf542b0480657790b67bfe6bf510a..eec9e9ab7730e222d0f969a3339c9e75f4d3548a 100644 --- a/src/components/TotalConsumption/TotalConsumption.tsx +++ b/src/components/TotalConsumption/TotalConsumption.tsx @@ -2,20 +2,18 @@ import Coin from 'assets/icons/ico/coin.svg' import Coins from 'assets/icons/ico/coins.svg' import StyledIcon from 'components/CommonKit/Icon/StyledIcon' import { useClient } from 'cozy-client' -import { FluidType } from 'enum/fluid.enum' -import { TimeStep } from 'enum/timeStep.enum' +import { FluidType, TimeStep } from 'enums' import { Dataload } from 'models' import React, { useCallback, useEffect, useState } from 'react' -import { useSelector } from 'react-redux' import ConsumptionService from 'services/consumption.service' import ConverterService from 'services/converter.service' -import { AppStore } from 'store' +import { useAppSelector } from 'store/hooks' import { formatNumberValues } from 'utils/utils' import './totalConsumption.scss' const TotalConsumption = ({ fluidType }: { fluidType: FluidType }) => { - const { currentTimeStep, showCompare, currentDatachart } = useSelector( - (state: AppStore) => state.ecolyo.chart + const { currentTimeStep, showCompare, currentDatachart } = useAppSelector( + state => state.ecolyo.chart ) const client = useClient() const [totalValue, setTotalValue] = useState<string>('-----') diff --git a/src/components/WelcomeModal/WelcomeModal.spec.tsx b/src/components/WelcomeModal/WelcomeModal.spec.tsx index c6ed7950f96f56e6a5ac137545cc20a7a1001dae..a4fa5b4211cebcce60fbb4f3fcb04c11a6fb4231 100644 --- a/src/components/WelcomeModal/WelcomeModal.spec.tsx +++ b/src/components/WelcomeModal/WelcomeModal.spec.tsx @@ -3,27 +3,10 @@ import { mount } from 'enzyme' import toJson from 'enzyme-to-json' import React from 'react' import { Provider } from 'react-redux' -import configureStore from 'redux-mock-store' -import thunk from 'redux-thunk' -import * as profileActions from 'store/profile/profile.actions' -import mockClient from '../../../tests/__mocks__/client' -import { profileData } from '../../../tests/__mocks__/profileData.mock' +import * as profileActions from 'store/profile/profile.slice' +import { createMockEcolyoStore } from 'tests/__mocks__/store' import WelcomeModal from './WelcomeModal' -jest.mock('cozy-ui/transpiled/react/I18n', () => { - return { - useI18n: jest.fn(() => { - return { - t: (str: string) => str, - } - }), - } -}) -jest.mock('cozy-client', () => { - return { - useClient: jest.fn(() => mockClient), - } -}) jest.mock('components/Hooks/useUserInstanceSettings', () => { return jest.fn(() => ({ data: { @@ -33,50 +16,37 @@ jest.mock('components/Hooks/useUserInstanceSettings', () => { })) }) jest.mock('services/environment.service', () => { - return jest.fn(() => { - return { - getPublicURL: () => 'https://ecolyo-agent-rec.grandlyon.com', - } - }) + return jest.fn(() => ({ + getPublicURL: () => 'https://ecolyo-agent-rec.grandlyon.com', + })) }) const mockSendMail = jest.fn() jest.mock('services/mail.service', () => { - return jest.fn(() => { - return { - SendMail: mockSendMail, - } - }) + return jest.fn(() => ({ + SendMail: mockSendMail, + })) }) jest.mock('notifications/welcome.hbs', () => { - return jest.fn(() => { - return { - welcomeTemplate: jest.fn(), - } - }) + return jest.fn(() => ({ + welcomeTemplate: jest.fn(), + })) }) jest.mock('mjml-browser', () => { - return jest.fn(() => { - return { - mjml2html: jest.fn(), - } - }) + return jest.fn(() => ({ + mjml2html: jest.fn(), + })) }) jest.mock('services/profile.service') -const mockStore = configureStore([thunk.withExtraArgument({ mockClient })]) const updateProfileSpy = jest.spyOn(profileActions, 'updateProfile') describe('WelcomeModal component', () => { beforeEach(() => { - updateProfileSpy.mockClear() + jest.clearAllMocks() }) + const store = createMockEcolyoStore() it('should be rendered correctly', () => { - const store = mockStore({ - ecolyo: { - profile: profileData, - }, - }) const component = mount( <Provider store={store}> <WelcomeModal open={true} /> @@ -86,11 +56,6 @@ describe('WelcomeModal component', () => { }) it('should not be rendered', () => { - const store = mockStore({ - ecolyo: { - profile: profileData, - }, - }) const component = mount( <Provider store={store}> <WelcomeModal open={false} /> @@ -100,18 +65,13 @@ describe('WelcomeModal component', () => { }) it('should send mail and update profile when user click on the ok button', async () => { - const store = mockStore({ - ecolyo: { - profile: profileData, - }, - }) const component = mount( <Provider store={store}> <WelcomeModal open={true} /> </Provider> ) component.find(Button).first().simulate('click') - expect(mockSendMail).toBeCalled() + expect(mockSendMail).toHaveBeenCalled() expect(updateProfileSpy).toHaveBeenCalledWith({ isFirstConnection: false, onboarding: { @@ -121,18 +81,13 @@ describe('WelcomeModal component', () => { }) it('should send mail and update profile when modal is closed by user', async () => { - const store = mockStore({ - ecolyo: { - profile: profileData, - }, - }) const component = mount( <Provider store={store}> <WelcomeModal open={true} /> </Provider> ) component.find(IconButton).first().simulate('click') - expect(mockSendMail).toBeCalled() + expect(mockSendMail).toHaveBeenCalled() expect(updateProfileSpy).toHaveBeenCalledWith({ isFirstConnection: false, onboarding: { diff --git a/src/components/WelcomeModal/WelcomeModal.tsx b/src/components/WelcomeModal/WelcomeModal.tsx index a4fcf032d60a1827fe036c8022ad29388de970d3..0fc095b5ffa698e75180400981320c099537be36 100644 --- a/src/components/WelcomeModal/WelcomeModal.tsx +++ b/src/components/WelcomeModal/WelcomeModal.tsx @@ -5,12 +5,11 @@ import useUserInstanceSettings from 'components/Hooks/useUserInstanceSettings' import { useClient } from 'cozy-client' import { useI18n } from 'cozy-ui/transpiled/react/I18n' import Icon from 'cozy-ui/transpiled/react/Icon' -import React, { Dispatch, useCallback } from 'react' -import { useDispatch } from 'react-redux' +import React, { useCallback } from 'react' import EnvironmentService from 'services/environment.service' import MailService from 'services/mail.service' -import { AppActionsTypes } from 'store' -import { updateProfile } from 'store/profile/profile.actions' +import { useAppDispatch } from 'store/hooks' +import { updateProfile } from 'store/profile/profile.slice' import './welcomeModal.scss' const welcomeTemplate = require('notifications/welcome.hbs') @@ -23,7 +22,7 @@ interface WelcomeModalProps { const WelcomeModal = ({ open }: WelcomeModalProps) => { const { t } = useI18n() const client = useClient() - const dispatch = useDispatch<Dispatch<AppActionsTypes>>() + const dispatch = useAppDispatch() const { data: instanceSettings } = useUserInstanceSettings() const setWelcomeModalViewed = useCallback(async () => { @@ -63,13 +62,10 @@ const WelcomeModal = ({ open }: WelcomeModalProps) => { } mailService.SendMail(client, mailData) - dispatch( updateProfile({ isFirstConnection: false, - onboarding: { - isWelcomeSeen: true, - }, + onboarding: { isWelcomeSeen: true }, }) ) }, [client, dispatch, instanceSettings]) @@ -78,13 +74,13 @@ const WelcomeModal = ({ open }: WelcomeModalProps) => { <Dialog open={open} onClose={setWelcomeModalViewed} - aria-labelledby={'accessibility-title'} + aria-labelledby="accessibility-title" classes={{ root: 'modal-root', paper: 'modal-paper', }} > - <div id={'accessibility-title'}> + <div id="accessibility-title"> {t('onboarding.welcomeModal.accessibility.window_title')} </div> <IconButton diff --git a/src/doctypes/index.ts b/src/doctypes/index.ts index 535698232c1e37d419cbf2445be5dacab0fba96a..3eded16b7eb5ed8c96f57ab34952b702f8c94a03 100644 --- a/src/doctypes/index.ts +++ b/src/doctypes/index.ts @@ -216,3 +216,8 @@ export * from './io-cozy-jobs' export * from './io-cozy-konnectors' export * from './io-cozy-terms' export * from './io-cozy-triggers' +export * from './remote/org.ecolyo.agent' +export * from './remote/org.ecolyo.agent.custom.popup' +export * from './remote/org.ecolyo.agent.partners.info' +export * from './remote/org.ecolyo.agent.prices' +export * from './remote/org.ecolyo.dju' diff --git a/src/doctypes/io-cozy-jobs.ts b/src/doctypes/io-cozy-jobs.ts index bf16df50381f551c53bc9467196fa434e92d5c6b..8454d9aeeab37ef4f940eb8076a857b2de437162 100644 --- a/src/doctypes/io-cozy-jobs.ts +++ b/src/doctypes/io-cozy-jobs.ts @@ -1,5 +1 @@ export const JOBS_DOCTYPE = 'io.cozy.jobs' - -export type Job = { - _id: string -} diff --git a/src/enum/konnectorUpdate.enum.ts b/src/enum/konnectorUpdate.enum.ts deleted file mode 100644 index d9b5dd8d71ce6bd1a2220069394358f976f7374e..0000000000000000000000000000000000000000 --- a/src/enum/konnectorUpdate.enum.ts +++ /dev/null @@ -1,6 +0,0 @@ -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/enum/dacc.enum.ts b/src/enums/dacc.enum.ts similarity index 92% rename from src/enum/dacc.enum.ts rename to src/enums/dacc.enum.ts index e07106c4813c77fec8ac2282d9c71737c3104325..707054fda7dc96682b4dd4cf4f1dd07e02dfde20 100644 --- a/src/enum/dacc.enum.ts +++ b/src/enums/dacc.enum.ts @@ -11,7 +11,7 @@ export enum DaccEvent { QUIZ_STARS = 'quiz-stars', SUMMARY_SUBSCRIPTION_MONTHLY = 'summary-subscription-monthly', FLUID_DATA_GRANULARITY = 'fluid-data-granularity-monthly', - PARTNER_SUCESS_MONTHLY = 'konnector-attempts-before-success', + PARTNER_SUCCESS_MONTHLY = 'konnector-attempts-before-success', UNINITIALIZED_KONNECTOR_ATTEMPTS_MONTHLY = 'uninitialized-konnector-attempts-monthly', CONNECTION_COUNT_MONTHLY = 'connection-count-monthly', PROFILE_COUNT_MONTHLY = 'profile-count', diff --git a/src/enum/dataload.enum.ts b/src/enums/dataload.enum.ts similarity index 100% rename from src/enum/dataload.enum.ts rename to src/enums/dataload.enum.ts diff --git a/src/enum/ecogesture.enum.ts b/src/enums/ecogesture.enum.ts similarity index 100% rename from src/enum/ecogesture.enum.ts rename to src/enums/ecogesture.enum.ts diff --git a/src/enum/ecogestureForm.enum.ts b/src/enums/ecogestureForm.enum.ts similarity index 89% rename from src/enum/ecogestureForm.enum.ts rename to src/enums/ecogestureForm.enum.ts index 3e847a32533a511af712846712647aa6a2af3bf5..4caa98b55d110aad5e71c4c47a853eb45f413f5f 100644 --- a/src/enum/ecogestureForm.enum.ts +++ b/src/enums/ecogestureForm.enum.ts @@ -1,7 +1,7 @@ export enum EcogestureStepForm { HEATING_TYPE = 0, WARMING_FLUID = 1, - HOT_WATER_TYPE = 2, + HOT_WATER = 2, EQUIPMENTS = 3, END, } diff --git a/src/enum/fluid.enum.ts b/src/enums/fluid.enum.ts similarity index 100% rename from src/enum/fluid.enum.ts rename to src/enums/fluid.enum.ts diff --git a/src/enum/fluidSlug.enum.ts b/src/enums/fluidSlug.enum.ts similarity index 100% rename from src/enum/fluidSlug.enum.ts rename to src/enums/fluidSlug.enum.ts diff --git a/src/enums/index.ts b/src/enums/index.ts new file mode 100644 index 0000000000000000000000000000000000000000..921ed6776e0b3113c1163fc3dd8437b8032bf144 --- /dev/null +++ b/src/enums/index.ts @@ -0,0 +1,19 @@ +export * from './dacc.enum' +export * from './dataload.enum' +export * from './ecogesture.enum' +export * from './ecogestureForm.enum' +export * from './fluid.enum' +export * from './fluidSlug.enum' +export * from './jobState.enum' +export * from './konnectorStatus.enum' +export * from './profileType.enum' +export * from './screen.enum' +export * from './sgeStep.enum' +export * from './timeStep.enum' +export * from './usageEvent.enum' +export * from './usageEventProperties.enum' +export * from './userAction.enum' +export * from './userChallenge.enum' +export * from './userDuel.enum' +export * from './userExploration.enum' +export * from './userQuiz.enum' diff --git a/src/enum/jobState.enum.ts b/src/enums/jobState.enum.ts similarity index 100% rename from src/enum/jobState.enum.ts rename to src/enums/jobState.enum.ts diff --git a/src/enum/konnectorError.enum.ts b/src/enums/konnectorStatus.enum.ts similarity index 50% rename from src/enum/konnectorError.enum.ts rename to src/enums/konnectorStatus.enum.ts index 090a513caafdfc5b964c22c0ec86ab1e0cc98867..4e8543316bd8de24d6cf05a1843e1e2a88371467 100644 --- a/src/enum/konnectorError.enum.ts +++ b/src/enums/konnectorStatus.enum.ts @@ -5,4 +5,12 @@ export enum KonnectorError { CHALLENGE_ASKED = 'CHALLENGE_ASKED', UNKNOWN_ERROR = 'UNKNOWN_ERROR', CRITICAL = 'exit status 1', + MISSING_SECRET = "Cannot read property 'secret' of null", +} + +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/enum/profileType.enum.ts b/src/enums/profileType.enum.ts similarity index 100% rename from src/enum/profileType.enum.ts rename to src/enums/profileType.enum.ts diff --git a/src/enum/screen.enum.ts b/src/enums/screen.enum.ts similarity index 100% rename from src/enum/screen.enum.ts rename to src/enums/screen.enum.ts diff --git a/src/enum/sgeStep.enum.ts b/src/enums/sgeStep.enum.ts similarity index 100% rename from src/enum/sgeStep.enum.ts rename to src/enums/sgeStep.enum.ts diff --git a/src/enum/timeStep.enum.ts b/src/enums/timeStep.enum.ts similarity index 100% rename from src/enum/timeStep.enum.ts rename to src/enums/timeStep.enum.ts diff --git a/src/enum/usageEvent.enum.ts b/src/enums/usageEvent.enum.ts similarity index 100% rename from src/enum/usageEvent.enum.ts rename to src/enums/usageEvent.enum.ts diff --git a/src/enum/usageEventProperties.enum.ts b/src/enums/usageEventProperties.enum.ts similarity index 100% rename from src/enum/usageEventProperties.enum.ts rename to src/enums/usageEventProperties.enum.ts diff --git a/src/enum/userAction.enum.ts b/src/enums/userAction.enum.ts similarity index 100% rename from src/enum/userAction.enum.ts rename to src/enums/userAction.enum.ts diff --git a/src/enum/userChallenge.enum.ts b/src/enums/userChallenge.enum.ts similarity index 97% rename from src/enum/userChallenge.enum.ts rename to src/enums/userChallenge.enum.ts index 70ac303228dcbaa4e2e7016d58504b0f9b3963fd..193179877e6bb5df6e8a34fb17222215b8446fd8 100644 --- a/src/enum/userChallenge.enum.ts +++ b/src/enums/userChallenge.enum.ts @@ -6,6 +6,7 @@ export enum UserChallengeUpdateFlag { DUEL_CONSUMPTION = 13, DUEL_WIN = 14, DUEL_LOSS = 15, + DUEL_RESET = 16, QUIZ = 20, QUIZ_START = 21, QUIZ_DONE = 22, diff --git a/src/enum/userDuel.enum.ts b/src/enums/userDuel.enum.ts similarity index 100% rename from src/enum/userDuel.enum.ts rename to src/enums/userDuel.enum.ts diff --git a/src/enum/userExploration.enum.ts b/src/enums/userExploration.enum.ts similarity index 100% rename from src/enum/userExploration.enum.ts rename to src/enums/userExploration.enum.ts diff --git a/src/enum/userQuiz.enum.ts b/src/enums/userQuiz.enum.ts similarity index 100% rename from src/enum/userQuiz.enum.ts rename to src/enums/userQuiz.enum.ts diff --git a/src/locales/fr.json b/src/locales/fr.json index 823bb73b4d6e3d4008b14ccf4055e3086061ae97..409eb54ad34be172d8f161de7ac2163033b3f404 100644 --- a/src/locales/fr.json +++ b/src/locales/fr.json @@ -32,6 +32,7 @@ "ELECTRICITY": { "NAME": "Électricité", "LABEL": "Électricité", + "LABEL_PREPOSITION": "d'électricité", "UNIT": "kWh", "ADD": "Ajouter l'électricité", "MEGAUNIT": "MWh", @@ -40,6 +41,7 @@ "WATER": { "NAME": "Eau", "LABEL": "Eau", + "LABEL_PREPOSITION": "d'eau", "ADD": "Ajouter l'eau", "UNIT": "L", "MEGAUNIT": "m³", @@ -48,6 +50,7 @@ "GAS": { "NAME": "Gaz", "LABEL": "Gaz", + "LABEL_PREPOSITION": "de gaz", "ADD": "Ajouter le gaz", "UNIT": "kWh", "MEGAUNIT": "MWh", @@ -60,7 +63,7 @@ } }, "action": { - "duration": "Durée : %{smart_count} jours", + "duration": "Durée : %{smartCount} jours", "result": "Résultat", "finished": "Défi terminé !", "details": "Détail de l'astuce", @@ -83,6 +86,8 @@ }, "analysis": { "viewTitle": "Analyse", + "warning_title": "Analyse incomplète", + "warning_text": "Ecolyo n'a pas encore reçu toutes les données %{fluidList} pour ce mois", "comparison": "Comparatif", "analysis_date": "Conso totale", "challenge": "Défis terminés en", @@ -90,8 +95,7 @@ "average_home": "Conso moyenne d'un profil similaire", "average_home_description": "Le comparatif ici présenté est calculé sur la base d'un profil similaire au vôtre. Il s'agit d'un calcul et non d'une comparaison avec les autres utilisateurs de l'application. Sont pris en compte l'ensemble des informations entrées dans votre profil\u00a0: mode de chauffage, âge du logement et éventuels travaux de rénovation, etc. Ce modèle a été créé avec l'Agence Locale de l'Energie sur la base de chiffres issues du Schéma Directeur des Energies de la Métropole de Lyon et de Chiffres-clé publiés par l'ADEME (l'Agence de l'Environnement et de la Maîtrise de l'Energie).", "approximative_description": "Pour comparer votre consommation avec un foyer similaire ou avec une conso idéale, veuillez détailler votre profil", - "not_connected": "Non connecté", - "no_data_2": "Données non disponibles", + "no_data": "Pas de données", "accessibility": { "button_go_to_profil": "Détailler mon profil" }, @@ -100,25 +104,23 @@ "title": "Comparateur", "month_tab": "Comparer au mois dernier", "year_tab": "Comparer à l'année dernière" - }, - "no_data": "Pas de données" + } }, "analysis_error_modal": { "title": "Aucune analyse", "message": "Pour profiter d’une analyse de vos consommations, connectez au moins un de vos compteurs.", - "go_to_options": "Je connecte mes compteurs", - "go_back": "Retour", + "go_to_conso": "Je connecte mes compteurs", + "understood": "J'ai compris", "accessibility": { "window_title": "Fenêtre d'erreur", - "button_go_back": "Retour", + "button_understood": "J'ai compris", "button_goto_konnector": "Aller aux connecteurs" } }, "analysis_pie": { "total": "Conso totale", "month": "Au mois\u00a0", - "estimation": "Comment sont estimés", - "estimation2": "les prix\u00a0?" + "estimation": "Comment sont estimés<br>les prix\u00a0?" }, "special_elec": { "title": "Spécial Électricité", @@ -201,10 +203,9 @@ "subtitle1": "Plus qu’à donner votre accord pour connecter votre compteur de gaz et Ecolyo\u00a0!" }, "step1": { - "info1": "Un <span>compte chez GRDF</span> est nécessaire pour vous connecter au gaz", - "info2": " <span>quelque soit votre fournisseur de gaz</span>.", - "info3": "<p>GRDF est le gestionnaire de réseau. C'est lui qui est responsable de votre compteur Gazpar et de la collecte des données de consommation.</p>", - "info4": "Possédez-vous un <span>compte GRDF</span>\u00a0?" + "info1": "Un <span>compte chez GRDF</span> est nécessaire pour vous connecter au gaz <span>quelque soit votre fournisseur de gaz</span>.", + "info2": "<p>GRDF est le gestionnaire de réseau. C'est lui qui est responsable de votre compteur Gazpar et de la collecte des données de consommation.</p>", + "info3": "Possédez-vous un <span>compte GRDF</span>\u00a0?" }, "step2": { "info1": "Une fois votre compte créé, <span>n'oubliez pas de revenir sur Ecolyo</span> pour finaliser la connexion." @@ -281,7 +282,8 @@ "win": "Gagné", "lost": "Perdu", "final_defi": "sur le duel final", - "final_defi_view": "Revoir le duel final" + "final_defi_view": "Revoir le duel final", + "reset_defi": "Relancer le défi" }, "card_last": { "title": "Tous les défis sont terminés", @@ -335,17 +337,16 @@ "missing_data": "Données manquantes", "no_data": "Pas de données", "why_no_data": "Pourquoi n'ai-je pas de données\u00a0?", - "last_data": "Dernières données", - "last_valid_data": "Dernières données valides", - "last_available_data": "Dernières données disponibles", - "last_valid_data_multi": "Dernières données complètes", + "last_valid_data": "Dernières données valides : %{date}", + "last_available_data": "Dernières données disponibles : %{date}", + "last_valid_data_multi": "Dernières données complètes : %{date}", "data_to_come": "à venir", "aie": "Aïe !", "data_empty": "Vide", "estimated": "estimés", "dataModal": { "list_title": "3 raisons possibles :", - "item1": "le lien entre Ecolyo et le fournisseur de données est rompu : une mise à jour de ce lien (en bas de la page) peut résoudre ce problème.", + "item1": "le lien entre Ecolyo et le fournisseur de données est rompu\u00a0: une mise à jour de ce lien (en bas de la page) peut résoudre ce problème.", "item2": "un problème technique chez votre gestionnaire\u00a0: se connecter directement chez ce gestionnaire pour vérifier que cette donnée apparaît.", "item3": "pour le gaz : vous n'avez pas autorisé Ecolyo à accéder aux données de consommation de cette période.", "item4": "vous n'aviez tout simplement pas de compteur communicant à l'époque\u00a0!" @@ -393,17 +394,17 @@ } }, "duel_result_modal": { - "sucess": { - "title": "Félicitations !", - "message1": "Vous avez économisé ", - "message2": "et gagné le badge ", - "button_validate": "Youpi !" + "success": { + "title": "Félicitations", + "message1": "Vous avez économisé %{value} €", + "message2": "et gagné le badge %{title} !", + "button_validate": "Youpi" }, "lost": { - "title": "Presque !", - "message1": "Vous avez dépassé de ", - "message2": "et manqué le badge ", - "button_validate": "Zut alors !" + "title": "Presque", + "message1": "Vous avez dépassé de %{value} €", + "message2": "et manqué le badge %{title}", + "button_validate": "Zut alors" }, "accessibility": { "window_title": "Fenêtre de résultat", @@ -494,8 +495,8 @@ "title_ecogesture": "Astuce", "title_action": "Action", "efficiency": "Efficacité", - "show_less": "Voir moins d’infos", - "show_more": "Voir plus d’infos", + "show_less": "Voir moins", + "show_more": "Voir plus", "select_action": "Je choisis cette action", "accessibility": { "window_title_ecogesture": "Fenêtre astuce", @@ -523,13 +524,20 @@ }, "warming_fluid": { "title": "Source chauffage", - "question": "Quelle source d’énergie principale utilisez-vous pour votre chauffage\u00a0?", + "question": "Quelle source d’énergie principale utilisez-vous pour vous chauffer\u00a0?", "0": "Électricité", "2": "Gaz", "3": "Bois", - "4": "Fioul" + "4": "Fioul", + "5": "Autre", + "no_fluid_text": "Produit ni par de l'électricité, ni par du gaz, ni par du bois ou du fuel", + "0_text": "Produit grâce à de l'électricité", + "2_text": "Produit grâce au gaz", + "3_text": "Produit grâce au bois", + "4_text": "Produit grâce au fioul", + "5_text": "Produit grâce à un autre moyen" }, - "hot_water_type": { + "hot_water": { "title": "Eau chaude", "question": "Quel est votre type de production d’eau chaude\u00a0?", "individual": "Individuelle", @@ -562,7 +570,7 @@ }, "ecogesture_selection": { "header": "Sélection des astuces", - "title": "Vous avez parcouru un groupe de %{smart_count} astuces", + "title": "Vous avez parcouru un groupe de %{smartCount} astuces", "text": "Voulez-vous continuer sur votre lancée ou remettre cette sélection à plus tard\u00a0?", "title_final": "Félicitations !", "text_final_1": "Vous avez terminé la sélection des astuces adaptées à votre consommation.", @@ -648,7 +656,7 @@ "link1": "<a href=\"https://demarches.toodego.com/sve/proteger-mes-donnees-personnelles/\">https://demarches.toodego.com/sve/proteger-mes-donnees-personnelles/</a>", "validDataConsent": "Je consens au traitement de mes données tel que décrit ci-dessus.", "validCGU": "Je valide les <span class=\"action\">Conditions Générales d’Utilisation</span> ", - "validLegal": " du service et ai pris connaissance des <span class=\"action\"> Mentions Légales </span> de celui-ci.", + "validLegal": " du service et ai pris connaissance des <span class=\"action\">Mentions Légales</span> de celui-ci.", "button_accept": "C'est parti !", "accessibility": { "button_accept": "Accepter les conditions générales d'utilisation" @@ -822,7 +830,7 @@ "button_understood": "J'ai compris", "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>", + "show_common_error_list": "<span>Le problème peut provenir des cas suivants :</span><ul><li>Vous avez un co-titulaire sur votre contrat. Veillez à bien entrer le nom du <span class=\"gold\">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 class=\"gold\">numéro de votre compteur</span> (PDL)\u00a0? Tout autre numéro (de contrat, de client) ne fonctionne pas.</li></ul><p>Si vous rencontrez toujours des difficultés, contactez notre service d'aide </p><div class=\"center\">Avez-vous pensez à vérifier ces informations\u00a0?</div>", "accessibility": { "window_title": "Fenêtre d'attente de connexion", "button_close": "Fermer la fenêtre" @@ -936,25 +944,6 @@ } } }, - "old_fluid_data_modal": { - "errorTxt": "Aïe !", - "oldData": "Vos données semblent anciennes", - "verify": "Veuillez vérifier l’état de vos connecteurs : ", - "problem": "Vos connecteurs semblent bien connectés, il se peut qu’il y ait un problème au niveau du ou des fournisseurs de données :", - "problem_electricity": "pour l'électricité.", - "problem_water": "pour l'eau.", - "problem_gas": "pour le gaz.", - "contact": "Veuillez prendre contact directement avec eux.", - "accessButton": "Accéder aux connecteurs", - "later": "Plus tard", - "ok": "Ok", - "accessibility": { - "window_title": "Fenêtre d'information", - "button_ok": "Fermer la fenêtre", - "button_later": "Fermer la fenêtre", - "button_goto_konnector": "Aller aux connecteurs" - } - }, "performance_indicator": { "bilan": { "text1": "Par rapport à ", diff --git a/src/migrations/migration.data.ts b/src/migrations/migration.data.ts index ada83c237aafcf36dbcbb8aaca076b2e5e37312d..abaf259e49dc579d75feda279dceb962c988d873 100644 --- a/src/migrations/migration.data.ts +++ b/src/migrations/migration.data.ts @@ -15,7 +15,7 @@ import { PROFILE_DOCTYPE, USERCHALLENGE_DOCTYPE, } from 'doctypes' -import { UserQuizState } from 'enum/userQuiz.enum' +import { UserQuizState } from 'enums' import { DateTime } from 'luxon' import { DataloadEntity, Profile, ProfileType, UserChallenge } from 'models' import { Migration } from './migration.type' diff --git a/src/migrations/migration.service.spec.ts b/src/migrations/migration.service.spec.ts index 5e717326c8935395fdbb16f34c5b600f75dd7e55..c865c5d7adff26fcd6ee1131e4f6f751a3ac0a6c 100644 --- a/src/migrations/migration.service.spec.ts +++ b/src/migrations/migration.service.spec.ts @@ -3,7 +3,8 @@ import { PROFILE_DOCTYPE } from 'doctypes' import { Profile } from 'models' import { Notes } from 'models/releaseNotes.model' import { Schema } from 'models/schema.models' -import mockClient from '../../tests/__mocks__/client' +import mockClient from 'tests/__mocks__/client.mock' +import { getError } from 'tests/__mocks__/testUtils' import * as Migrate from './migration' import { MIGRATION_RESULT_FAILED } from './migration.data' import { MigrationService } from './migration.service' @@ -17,7 +18,7 @@ describe('Migration service', () => { description: '', } beforeEach(() => { - migrateSpy.mockClear() + jest.clearAllMocks() }) it('should run migrations', async () => { const schema: Schema = { _id: '1', version: 0 } @@ -47,7 +48,7 @@ describe('Migration service', () => { ] mockClient.query.mockResolvedValue(mockQueryResult) await ms.runMigrations(migrations) - expect(migrateSpy).toBeCalledTimes(1) + expect(migrateSpy).toHaveBeenCalledTimes(1) }) it('should run migrations with one fail', async () => { @@ -79,7 +80,7 @@ describe('Migration service', () => { mockClient.query.mockResolvedValue(mockQueryResult) await ms.runMigrations(migrations) - expect(migrateSpyOneFail).toBeCalledTimes(2) + expect(migrateSpyOneFail).toHaveBeenCalledTimes(2) }) it('should not run migrations with two fail', async () => { @@ -112,13 +113,10 @@ describe('Migration service', () => { .spyOn(Migrate, 'migrate') .mockResolvedValueOnce(result) .mockResolvedValueOnce(result) - try { - await ms.runMigrations(migrations) - expect(migrateSpyTwoFailsKo).toBeCalledTimes(1) - expect(migrateSpy).toBeCalledTimes(1) - } catch (error) { - expect(error).toEqual(new Error()) - } + const error = await getError(async () => ms.runMigrations(migrations)) + expect(migrateSpyTwoFailsKo).toHaveBeenCalledTimes(2) + expect(migrateSpy).toHaveBeenCalledTimes(2) + expect(error).toEqual(new Error()) }) it('should skip migrations if schema number is up to date', async () => { @@ -145,7 +143,7 @@ describe('Migration service', () => { mockClient.query.mockResolvedValue(mockQueryResult) await ms.runMigrations(migrations) - expect(migrateSpy).toBeCalledTimes(0) + expect(migrateSpy).toHaveBeenCalledTimes(0) }) it('should run 2 migrations properly from a fresh instance and dont show releasenotes', async () => { const schema: Schema = { _id: '1', version: 0 } @@ -182,7 +180,7 @@ describe('Migration service', () => { mockClient.query.mockResolvedValue(mockQueryResult) const res = await ms.runMigrations(migrations) - expect(migrateSpy).toBeCalledTimes(2) + expect(migrateSpy).toHaveBeenCalledTimes(2) expect(res.show).toBeFalsy() }) }) diff --git a/src/migrations/migration.service.ts b/src/migrations/migration.service.ts index 2746f148312d76f019c5910ea088ada15bbb0802..757f9644727b3f045dcfa578f784c4c61432445b 100644 --- a/src/migrations/migration.service.ts +++ b/src/migrations/migration.service.ts @@ -1,9 +1,7 @@ import * as Sentry from '@sentry/react' import { Client, Q, QueryDefinition, QueryResult } from 'cozy-client' -import { SCHEMAS_DOCTYPE } from 'doctypes/com-grandlyon-ecolyo-schemas' -import { InitStepsErrors } from 'models/initialisationSteps.model' -import { ReleaseNotes } from 'models/releaseNotes.model' -import { Schema } from 'models/schema.models' +import { SCHEMAS_DOCTYPE } from 'doctypes' +import { InitStepsErrors, ReleaseNotes, Schema } from 'models' import { logDuration } from 'utils/duration' import logApp from 'utils/logger' import { migrate, migrationLog } from './migration' diff --git a/src/migrations/migration.spec.ts b/src/migrations/migration.spec.ts index 1aa4f518578d95d682ee35f1f79631d7d5833e35..03ae98d6611370f73800a205c7c26fea9b5aae44 100644 --- a/src/migrations/migration.spec.ts +++ b/src/migrations/migration.spec.ts @@ -2,8 +2,8 @@ import { QueryResult } from 'cozy-client' import { FLUIDSPRICES_DOCTYPE, PROFILE_DOCTYPE } from 'doctypes' import { FluidPrice, Profile } from 'models' import { Schema } from 'models/schema.models' -import mockClient from '../../tests/__mocks__/client' -import { profileData } from '../../tests/__mocks__/profileData.mock' +import mockClient from 'tests/__mocks__/client.mock' +import { mockProfileState } from 'tests/__mocks__/store' import { migrate, migrationLog } from './migration' import { MIGRATION_RESULT_COMPLETE, @@ -30,13 +30,13 @@ describe('migration logger', () => { }, } - it('it should return noop', () => { + it('should return noop', () => { const result: MigrationResult = { type: MIGRATION_RESULT_NOOP, errors: [] } const reply = migrationLog(migration, result) expect(reply).toEqual('--- Removing mailToken from profil => NOOP') }) - it('it should return noop', () => { + it('should return Complete', () => { const result: MigrationResult = { type: MIGRATION_RESULT_COMPLETE, errors: [], @@ -45,7 +45,7 @@ describe('migration logger', () => { expect(reply).toEqual('--- Removing mailToken from profil => Complete') }) - it('it should return noop', () => { + it('should return Failed', () => { const result: MigrationResult = { type: MIGRATION_RESULT_FAILED, errors: [], @@ -73,7 +73,7 @@ describe('migration', () => { }, } - it('it should return schema does not exist', async () => { + it('should return schema does not exist', async () => { const mockQueryResult: QueryResult<Schema[]> = { data: [], bookmark: '', @@ -94,7 +94,7 @@ describe('migration', () => { expect(result).toEqual({ type: MIGRATION_RESULT_NOOP, errors: [] }) }) - it('it should return migration failed', async () => { + it('should return migration failed', async () => { const mockQueryResult: QueryResult<Schema[]> = { data: [], bookmark: '', @@ -120,7 +120,7 @@ describe('migration', () => { }) }) - it('it should return migration complete', async () => { + it('should return migration complete', async () => { const mockQueryResultWithoutAnySchema: QueryResult<Schema[]> = { data: [], bookmark: '', @@ -134,7 +134,7 @@ describe('migration', () => { skip: 0, } const mockQueryResultProfile: QueryResult<Profile[]> = { - data: [profileData], + data: [mockProfileState], bookmark: '', next: false, skip: 0, @@ -152,7 +152,7 @@ describe('migration', () => { }) }) - it('it should return migration noop', async () => { + it('should return migration noop', async () => { const migrationTest: Migration = { baseSchemaVersion: 0, targetSchemaVersion: 1, @@ -177,7 +177,7 @@ describe('migration', () => { skip: 0, } const mockQueryResultProfile: QueryResult<Profile[]> = { - data: [profileData], + data: [mockProfileState], bookmark: '', next: false, skip: 0, @@ -197,7 +197,7 @@ describe('migration', () => { }) describe('migration create', () => { - it('it should return migration complete for creation', async () => { + it('should return migration complete for creation', async () => { const migrationTestCreate: Migration = { baseSchemaVersion: 0, targetSchemaVersion: 1, diff --git a/src/migrations/migration.ts b/src/migrations/migration.ts index 746e0c0adc59cda5e98c0703da1c9b01299da17e..2129af07325c78f34319913811a8a5ea7afd928c 100644 --- a/src/migrations/migration.ts +++ b/src/migrations/migration.ts @@ -1,7 +1,7 @@ import * as Sentry from '@sentry/react' import { Client, Q, QueryDefinition, QueryResult } from 'cozy-client' -import { SCHEMAS_DOCTYPE } from 'doctypes/com-grandlyon-ecolyo-schemas' -import { Schema } from 'models/schema.models' +import { SCHEMAS_DOCTYPE } from 'doctypes' +import { Schema } from 'models' import logApp from 'utils/logger' import { MIGRATION_RESULT_COMPLETE, @@ -33,7 +33,6 @@ async function currentSchemaVersion(_client: Client): Promise<number> { /** * Retrieve all documents of a given doctype * @param _client cozyClient - * @param doctype * @returns all documents of given doctype */ async function getDocs( @@ -58,8 +57,6 @@ async function getDocs( /** * Update schema version - * @param _client - * @param targetSchemaVersion */ async function updateSchemaVersion( _client: Client, @@ -75,8 +72,6 @@ async function updateSchemaVersion( /** * Save updated docs - * @param _client - * @param docs * @returns Promise<MigrationResult> */ async function save(_client: Client, docs: any[]): Promise<MigrationResult> { @@ -126,9 +121,6 @@ export const initSchemaDoctype = async ( /** * Run migration - * @param migration - * @param _client - * @returnsPromise<MigrationResult> */ export async function migrate( migration: Migration, @@ -181,7 +173,7 @@ export async function migrate( } } catch (error: any) { console.error(error) - Sentry.captureException(JSON.stringify({ error })) + Sentry.captureException(error) result = { type: MIGRATION_RESULT_FAILED, errors: [error.toString()], diff --git a/src/migrations/migration.type.ts b/src/migrations/migration.type.ts index 1ee3c97765b38cd236e8dee76213289f1fbf03f8..e4b7a93c41f4cc840d720efd63179e1c8abace36 100644 --- a/src/migrations/migration.type.ts +++ b/src/migrations/migration.type.ts @@ -1,5 +1,5 @@ import { Client } from 'cozy-client' -import { Notes } from 'models/releaseNotes.model' +import { Notes } from 'models' type SchemaVersion = number diff --git a/src/models/action.model.ts b/src/models/action.model.ts index d9c011f5deacd8c1bb04d8dcdbc9910df656f73a..dec0f416b2ec36b25df277712174b745216b17b3 100644 --- a/src/models/action.model.ts +++ b/src/models/action.model.ts @@ -1,4 +1,4 @@ -import { UserActionState } from 'enum/userAction.enum' +import { UserActionState } from 'enums' import { DateTime } from 'luxon' import { Ecogesture } from 'models' diff --git a/src/models/challenge.model.ts b/src/models/challenge.model.ts index 1e9bee4e14a790b0f90a275222314cf638a7610e..919efe2c7f0a17c25f67785d923b3c6e0283b1be 100644 --- a/src/models/challenge.model.ts +++ b/src/models/challenge.model.ts @@ -1,7 +1,4 @@ -import { - UserChallengeState, - UserChallengeSuccess, -} from 'enum/userChallenge.enum' +import { UserChallengeState, UserChallengeSuccess } from 'enums' import { DateTime } from 'luxon' import { Dataload, @@ -35,12 +32,6 @@ export interface ChallengeEntity { } } -export interface ChallengeProgress { - quizProgress: number - explorationProgress: number - actionProgress: number -} - export interface UserChallengeEntity { id: string title: string @@ -48,7 +39,11 @@ export interface UserChallengeEntity { description: string state: UserChallengeState target: number - progress: ChallengeProgress + progress: { + quizProgress: number + explorationProgress: number + actionProgress: number + } duel: UserDuelEntity success: UserChallengeSuccess startDate: string | null diff --git a/src/models/chart.model.ts b/src/models/chart.model.ts index 787ad686194256b15a72ba011142f1adc5893683..96fa843eb8d5fb4f190d2e46a740ea4315f866d1 100644 --- a/src/models/chart.model.ts +++ b/src/models/chart.model.ts @@ -1,4 +1,4 @@ -import { TimeStep } from 'enum/timeStep.enum' +import { TimeStep } from 'enums' import { DateTime } from 'luxon' import { Datachart } from 'models' diff --git a/src/models/config.model.ts b/src/models/config.model.ts index 121b79ed624ddec8625dde974c258685585d19d0..66171535b8b17f68ef290c36022b065d7d4c39ca 100644 --- a/src/models/config.model.ts +++ b/src/models/config.model.ts @@ -1,11 +1,10 @@ -import { FluidSlugType } from 'enum/fluidSlug.enum' +import { FluidSlugType } from 'enums' export interface KonnectorConfig { name: string oauth: boolean slug: FluidSlugType cron?: string - lastKnownCredentials?: string siteLink: string activation: string } diff --git a/src/models/dataload.model.ts b/src/models/dataload.model.ts index 3f7f73b015d7674971456e33d8026d27ed8c1c4d..e40d69dfea223a50afb617fd95af328dfe2181ee 100644 --- a/src/models/dataload.model.ts +++ b/src/models/dataload.model.ts @@ -1,4 +1,4 @@ -import { DataloadState } from 'enum/dataload.enum' +import { DataloadState } from 'enums' import { DateTime } from 'luxon' export interface DataloadValueDetail { diff --git a/src/models/dju.model.ts b/src/models/dju.model.ts index a74baa1625edf2d6fb82661d45a1e63c330469bc..b1cb16e082fa339458cd799a061f9f5e0ef40e1f 100644 --- a/src/models/dju.model.ts +++ b/src/models/dju.model.ts @@ -6,7 +6,7 @@ export interface DjuResult { values: DjuMeasure[] } -export interface DjuMeasure { +interface DjuMeasure { horodate: string measurement: number observation: string diff --git a/src/models/duel.model.ts b/src/models/duel.model.ts index 83687f7191a3e0a35fbfca2ecae29302c09c0eb0..43628dbca34928f89018a84fd9627cc453f5e24c 100644 --- a/src/models/duel.model.ts +++ b/src/models/duel.model.ts @@ -1,5 +1,4 @@ -import { FluidType } from 'enum/fluid.enum' -import { UserDuelState } from 'enum/userDuel.enum' +import { FluidType, UserDuelState } from 'enums' import { DateTime, Duration } from 'luxon' export interface DuelEntity { diff --git a/src/models/ecogesture.model.ts b/src/models/ecogesture.model.ts index 79f82d677d19d3dc5bb59a9af046f8c988b2aab2..d885795ce1c40b929c147f61ec196a1bdac7fc40 100644 --- a/src/models/ecogesture.model.ts +++ b/src/models/ecogesture.model.ts @@ -1,5 +1,4 @@ -import { EquipmentType, Room, Season, Usage } from 'enum/ecogesture.enum' -import { FluidType } from 'enum/fluid.enum' +import { EquipmentType, FluidType, Room, Season, Usage } from 'enums' export interface Ecogesture { id: string diff --git a/src/models/exploration.model.ts b/src/models/exploration.model.ts index eccf99be8768779fca4eaff4b4f26a723323d0bc..792225668c73ad536d1729253a353ccb33b7a8c8 100644 --- a/src/models/exploration.model.ts +++ b/src/models/exploration.model.ts @@ -1,9 +1,5 @@ /* eslint-disable camelcase */ -import { FluidType } from 'enum/fluid.enum' -import { - UserExplorationState, - UserExplorationType, -} from 'enum/userExploration.enum' +import { FluidType, UserExplorationState, UserExplorationType } from 'enums' import { DateTime } from 'luxon' export interface ExplorationEntity { diff --git a/src/models/fluid.model.ts b/src/models/fluid.model.ts index 2994de62dc4b3ada6fcc0f347872a937964bba18..a99af34eb156a60a32ba5ba763421c78c326b0c9 100644 --- a/src/models/fluid.model.ts +++ b/src/models/fluid.model.ts @@ -1,4 +1,4 @@ -import { FluidState, FluidType } from 'enum/fluid.enum' +import { FluidState, FluidType } from 'enums' import { DateTime } from 'luxon' import { Account, Konnector, KonnectorConfig, Trigger } from 'models' import { TriggerState } from './trigger.model' diff --git a/src/models/fluidPrice.model.ts b/src/models/fluidPrice.model.ts index 97bd6227989362beaa68bace880b53aef498d3af..c38feff398246475c8653a8d69bdbb69d41cd4b7 100644 --- a/src/models/fluidPrice.model.ts +++ b/src/models/fluidPrice.model.ts @@ -1,4 +1,4 @@ -import { FluidType } from 'enum/fluid.enum' +import { FluidType } from 'enums' export interface FluidPrice { fluidType: FluidType diff --git a/src/models/global.model.ts b/src/models/global.model.ts index 30118eeb38bb9f93663a277824778e5b2c92f39d..8885c78cd72d5debe8c04da2c799feef04e131c2 100644 --- a/src/models/global.model.ts +++ b/src/models/global.model.ts @@ -1,5 +1,4 @@ -import { FluidType } from 'enum/fluid.enum' -import { ScreenType } from 'enum/screen.enum' +import { FluidType, ScreenType, Usage } from 'enums' import { TermsStatus } from 'models' import { FluidStatus } from './fluid.model' import { PartnersInfo } from './partnersInfo.model' @@ -19,4 +18,6 @@ export interface GlobalState { shouldRefreshConsent: boolean sgeConnect: SgeStore partnersInfo: PartnersInfo + ecogestureFilter: Usage + lastEpglLogin: string } diff --git a/src/models/index.ts b/src/models/index.ts index 09b065bde0cefccc575de8795af3273f8519c7d9..99412717d6e8d8ea01c96ebeea6beb395ffc6cf5 100644 --- a/src/models/index.ts +++ b/src/models/index.ts @@ -7,8 +7,10 @@ export * from './config.model' export * from './customPopup.model' export * from './datachart.model' export * from './dataload.model' +export * from './dju.model' export * from './duel.model' export * from './ecogesture.model' +export * from './enedisMonthlyAnalysis' export * from './exploration.model' export * from './fluid.model' export * from './fluidPrice.model' @@ -16,13 +18,18 @@ export * from './global.model' export * from './indicator.model' export * from './initialisationSteps.model' export * from './konnector.model' +export * from './maxPower.model' export * from './modal.model' +export * from './monthlyReport.model' export * from './partnersInfo.model' export * from './profile.model' export * from './profileEcogesture.model' export * from './profileType.model' export * from './quiz.model' export * from './relation.model' +export * from './releaseNotes.model' +export * from './schema.models' +export * from './sgeStore.model' export * from './term.model' export * from './timePeriod.model' export * from './trigger.model' diff --git a/src/models/modal.model.ts b/src/models/modal.model.ts index 0dbb67b01b0ebc564477a51773902c2434199297..019051d00c75129a4462867115947247dea66030 100644 --- a/src/models/modal.model.ts +++ b/src/models/modal.model.ts @@ -1,4 +1,4 @@ -import { CustomPopup } from 'models/customPopup.model' +import { CustomPopup } from 'models' export interface ModalState { customPopupModal: CustomPopup diff --git a/src/models/profileEcogesture.model.ts b/src/models/profileEcogesture.model.ts index 217f67a7030951283c9c80238898c1bcf8c6532e..9c1fdd8d788449aaaca55e9ccd13c33529c1b666 100644 --- a/src/models/profileEcogesture.model.ts +++ b/src/models/profileEcogesture.model.ts @@ -1,4 +1,4 @@ -import { ProfileEcogestureAnswerType } from 'enum/ecogestureForm.enum' +import { ProfileEcogestureAnswerType } from 'enums' import { ProfileType } from './profileType.model' export type ProfileEcogesture = Pick< diff --git a/src/models/profileType.model.ts b/src/models/profileType.model.ts index e3184314d77fd3f5f2c1e9737c3e8a846458a1fa..0c62b3844b0dd64a4b4d3e7df4e273cf08590dff 100644 --- a/src/models/profileType.model.ts +++ b/src/models/profileType.model.ts @@ -1,8 +1,8 @@ -import { EquipmentType } from 'enum/ecogesture.enum' -import { FluidType } from 'enum/fluid.enum' import { ConstructionYear, + EquipmentType, Floor, + FluidType, HotWaterEquipment, HotWaterFluid, HousingType, @@ -12,7 +12,7 @@ import { ProfileTypeFormType, ThreeChoicesAnswer, WarmingType, -} from 'enum/profileType.enum' +} from 'enums' import { DateTime } from 'luxon' export interface ProfileType { diff --git a/src/models/quiz.model.ts b/src/models/quiz.model.ts index a03221eb7381f73f201cd384710bac2ce7533eea..1aaeb1733986d3d87cc8c011979507f1ccc2e8f6 100644 --- a/src/models/quiz.model.ts +++ b/src/models/quiz.model.ts @@ -1,9 +1,9 @@ -import { TimeStep } from 'enum/timeStep.enum' import { CustomQuestionType, + TimeStep, UserQuestionState, UserQuizState, -} from 'enum/userQuiz.enum' +} from 'enums' import { DateTime } from 'luxon' export interface Answer { @@ -60,6 +60,3 @@ export interface IntervalAnswer { date: DateTime value: number } -export interface OtherAnswer { - value: number -} diff --git a/src/models/usageEvent.model.ts b/src/models/usageEvent.model.ts index 210a849f116a5f8d4909dd2d4beed90f4571bbee..d0f04944e7c946023ecd5a823a7f7f676d17f371 100644 --- a/src/models/usageEvent.model.ts +++ b/src/models/usageEvent.model.ts @@ -1,4 +1,4 @@ -import { UsageEventType } from 'enum/usageEvent.enum' +import { UsageEventType } from 'enums' import { DateTime } from 'luxon' export interface AddEventParams { diff --git a/src/services/account.service.spec.ts b/src/services/account.service.spec.ts index c1d2d227ce6d8c200344f1c4e25438f8341f23c3..cb6e07b6b3524bd75fef20a8fccec046a716de1f 100644 --- a/src/services/account.service.spec.ts +++ b/src/services/account.service.spec.ts @@ -2,10 +2,11 @@ import { QueryResult } from 'cozy-client' import * as harvestLibAccounts from 'cozy-harvest-lib/dist/connections/accounts' import { Account, AccountAuthData } from 'models' -import { accountsData } from '../../tests/__mocks__/accountsData.mock' -import mockClient from '../../tests/__mocks__/client' -import { konnectorsData } from '../../tests/__mocks__/konnectorsData.mock' -import { triggersEnedisData } from '../../tests/__mocks__/triggersData.mock' +import { accountsData } from 'tests/__mocks__/accountsData.mock' +import mockClient from 'tests/__mocks__/client.mock' +import { konnectorsData } from 'tests/__mocks__/konnectorsData.mock' +import { getError } from 'tests/__mocks__/testUtils' +import { triggersEnedisData } from 'tests/__mocks__/triggersData.mock' import AccountService from './account.service' jest.mock('cozy-harvest-lib/dist/connections/accounts') @@ -15,11 +16,9 @@ const mockHavestLibAccounts = harvestLibAccounts as jest.Mocked< const mockGetTriggerForAccount = jest.fn() jest.mock('./triggers.service', () => { - return jest.fn(() => { - return { - getTriggerForAccount: mockGetTriggerForAccount, - } - }) + return jest.fn(() => ({ + getTriggerForAccount: mockGetTriggerForAccount, + })) }) describe('Account service', () => { @@ -51,11 +50,10 @@ describe('Account service', () => { it('should throw error when fetchAccount unsuccessfully', async () => { mockHavestLibAccounts.fetchAccount.mockRejectedValueOnce(new Error()) const mockId = 'io.cozy.konnectors/eglgrandlyon' - try { - await accountService.getAccount(mockId) - } catch (error) { - expect(error).toEqual(new Error('Get account failed')) - } + const error = await getError(async () => + accountService.getAccount(mockId) + ) + expect(error).toEqual(new Error('Get account failed')) }) }) @@ -132,11 +130,10 @@ describe('Account service', () => { it('should throw error when updateAccount unsuccessfully', async () => { mockHavestLibAccounts.updateAccount.mockRejectedValueOnce(new Error()) - try { - await accountService.updateAccount(accountsData[2]) - } catch (error) { - expect(error).toEqual(new Error('Update account failed')) - } + const error = await getError(async () => + accountService.updateAccount(accountsData[2]) + ) + expect(error).toEqual(new Error('Update account failed')) }) }) @@ -149,11 +146,10 @@ describe('Account service', () => { it('should throw error when destroy unsuccessfully', async () => { mockHavestLibAccounts.deleteAccount.mockRejectedValueOnce(new Error()) - try { - await accountService.deleteAccount(accountsData[2]) - } catch (error) { - expect(error).toEqual(new Error('Delete account failed')) - } + const error = await getError(async () => + accountService.deleteAccount(accountsData[2]) + ) + expect(error).toEqual(new Error('Delete account failed')) }) }) diff --git a/src/services/account.service.ts b/src/services/account.service.ts index 13ffc78f86d14ef764bfb509ab02f7b9d7d653cd..3ed4c8bfc6e40c851b566fdc8ff51041e4828fa5 100644 --- a/src/services/account.service.ts +++ b/src/services/account.service.ts @@ -57,7 +57,7 @@ export default class AccountService { const errorMessage = `Get account failed :${JSON.stringify(error)}` logStack('error', errorMessage) logApp.error(errorMessage) - Sentry.captureException(errorMessage) + Sentry.captureException(error) throw new Error('Get account failed') } } @@ -106,7 +106,7 @@ export default class AccountService { const errorMessage = `Error GetAccountByType: ${JSON.stringify(error)}` logStack('error', errorMessage) logApp.error(errorMessage) - Sentry.captureException(errorMessage) + Sentry.captureException(error) return null } } @@ -124,7 +124,7 @@ export default class AccountService { const errorMessage = `Error: GetAccountsByType: ${JSON.stringify(error)}` logStack('error', errorMessage) logApp.error(errorMessage) - Sentry.captureException(errorMessage) + Sentry.captureException(error) return [] } } @@ -137,7 +137,7 @@ export default class AccountService { const errorMessage = `Update account failed: ${JSON.stringify(error)}` logStack('error', errorMessage) logApp.error(errorMessage) - Sentry.captureException(errorMessage) + Sentry.captureException(error) throw new Error('Update account failed') } } @@ -150,7 +150,7 @@ export default class AccountService { const errorMessage = `Delete account failed` logStack('error', errorMessage) logApp.error(errorMessage) - Sentry.captureException(errorMessage) + Sentry.captureException(error) throw new Error(errorMessage) } } diff --git a/src/services/action.service.spec.ts b/src/services/action.service.spec.ts index 6eea6bfa56f7c29146325fa8e0746f3aaba3358a..ea0ca3a00376b4300f96a109dc36a506b73fe6e7 100644 --- a/src/services/action.service.spec.ts +++ b/src/services/action.service.spec.ts @@ -1,51 +1,50 @@ -import { Season } from 'enum/ecogesture.enum' -import { UserActionState } from 'enum/userAction.enum' +import { Season, UserActionState } from 'enums' import { DateTime } from 'luxon' import { Ecogesture, UserAction } from 'models' -import * as utils from 'utils/utils' import { AllEcogestureData, defaultEcogestureData, ecogestureDefault, -} from '../../tests/__mocks__/actionData.mock' -import mockClient from '../../tests/__mocks__/client' -import { userChallengeData } from '../../tests/__mocks__/userChallengeData.mock' +} from 'tests/__mocks__/actionData.mock' +import mockClient from 'tests/__mocks__/client.mock' +import { userChallengeData } from 'tests/__mocks__/userChallengeData.mock' import ActionService from './action.service' -const mockgetAllUserChallengeEntities = jest.fn() +const mockGetAllUserChallengeEntities = jest.fn() jest.mock('./challenge.service', () => { - return jest.fn(() => { - return { - getAllUserChallengeEntities: mockgetAllUserChallengeEntities, - } - }) + return jest.fn(() => ({ + getAllUserChallengeEntities: mockGetAllUserChallengeEntities, + })) }) -const mockgetAllEcogestures = jest.fn() -const mockgetEcogesturesByIds = jest.fn() +const mockGetAllEcogestures = jest.fn() +const mockGetEcogesturesByIds = jest.fn() jest.mock('./ecogesture.service', () => { - return jest.fn(() => { - return { - getAllEcogestures: mockgetAllEcogestures, - getEcogesturesByIds: mockgetEcogesturesByIds, - } - }) + return jest.fn(() => ({ + getAllEcogestures: mockGetAllEcogestures, + getEcogesturesByIds: mockGetEcogesturesByIds, + })) }) +const mockGetSeason = jest.fn() +jest.mock('utils/utils', () => ({ + getSeason: () => mockGetSeason(), +})) + describe('Action Service', () => { const actionService = new ActionService(mockClient) it('should return the default actions', async () => { - mockgetAllEcogestures.mockResolvedValueOnce(AllEcogestureData) - mockgetEcogesturesByIds.mockResolvedValueOnce(defaultEcogestureData) + mockGetAllEcogestures.mockResolvedValueOnce(AllEcogestureData) + mockGetEcogesturesByIds.mockResolvedValueOnce(defaultEcogestureData) const result: Ecogesture[] = await actionService.getDefaultActions() expect(result).toEqual(defaultEcogestureData) }) it('should return the Available Action List', async () => { - mockgetAllUserChallengeEntities.mockResolvedValueOnce(userChallengeData) - mockgetAllEcogestures.mockResolvedValueOnce(AllEcogestureData) - mockgetEcogesturesByIds.mockResolvedValueOnce([ + mockGetAllUserChallengeEntities.mockResolvedValueOnce(userChallengeData) + mockGetAllEcogestures.mockResolvedValueOnce(AllEcogestureData) + mockGetEcogesturesByIds.mockResolvedValueOnce([ AllEcogestureData[2], AllEcogestureData[3], AllEcogestureData[4], @@ -59,7 +58,7 @@ describe('Action Service', () => { ]) }) it('should return winter ecogestures', () => { - jest.spyOn(utils, 'getSeason').mockReturnValueOnce(Season.WINTER) + mockGetSeason.mockReturnValueOnce(Season.WINTER) const result: Ecogesture[] = actionService.filterBySeason(AllEcogestureData) expect(result).toEqual([ AllEcogestureData[0], @@ -68,13 +67,13 @@ describe('Action Service', () => { ]) }) it('should return no season ecogestures', () => { - jest.spyOn(utils, 'getSeason').mockReturnValueOnce(Season.NONE) + mockGetSeason.mockReturnValueOnce(Season.NONE) const result: Ecogesture[] = actionService.filterBySeason(AllEcogestureData) expect(result).toEqual([AllEcogestureData[3], AllEcogestureData[4]]) }) it('should return summer ecogestures', () => { - jest.spyOn(utils, 'getSeason').mockReturnValueOnce(Season.SUMMER) + mockGetSeason.mockReturnValueOnce(Season.SUMMER) const result: Ecogesture[] = actionService.filterBySeason(AllEcogestureData) expect(result).toEqual([ @@ -101,7 +100,7 @@ describe('Action Service', () => { expect(result).toEqual(UserActionDefault) }) it('complete list if < 3', async () => { - mockgetEcogesturesByIds.mockResolvedValueOnce([ + mockGetEcogesturesByIds.mockResolvedValueOnce([ AllEcogestureData[2], AllEcogestureData[3], AllEcogestureData[4], @@ -120,10 +119,10 @@ describe('Action Service', () => { describe('getCustomActions function', () => { it('should return filtered and sorted ecogestures and not complete the list', async () => { - jest.spyOn(utils, 'getSeason').mockReturnValueOnce(Season.WINTER) - mockgetAllUserChallengeEntities.mockResolvedValueOnce(userChallengeData) - mockgetAllEcogestures.mockResolvedValueOnce(AllEcogestureData) - mockgetEcogesturesByIds.mockResolvedValueOnce([ + mockGetSeason.mockReturnValueOnce(Season.WINTER) + mockGetAllUserChallengeEntities.mockResolvedValueOnce(userChallengeData) + mockGetAllEcogestures.mockResolvedValueOnce(AllEcogestureData) + mockGetEcogesturesByIds.mockResolvedValueOnce([ AllEcogestureData[0], AllEcogestureData[1], AllEcogestureData[2], @@ -140,17 +139,17 @@ describe('Action Service', () => { ]) }) it('should return filtered and sorted ecogestures and complete the list with default ecogesture', async () => { - jest.spyOn(utils, 'getSeason').mockReturnValueOnce(Season.WINTER) - mockgetAllUserChallengeEntities.mockResolvedValueOnce(userChallengeData) - mockgetAllEcogestures.mockResolvedValueOnce(AllEcogestureData) - mockgetEcogesturesByIds.mockResolvedValueOnce([ + mockGetSeason.mockReturnValueOnce(Season.WINTER) + mockGetAllUserChallengeEntities.mockResolvedValueOnce(userChallengeData) + mockGetAllEcogestures.mockResolvedValueOnce(AllEcogestureData) + mockGetEcogesturesByIds.mockResolvedValueOnce([ AllEcogestureData[0], AllEcogestureData[1], AllEcogestureData[2], AllEcogestureData[3], ]) - mockgetEcogesturesByIds.mockClear() - mockgetEcogesturesByIds.mockResolvedValueOnce([ + mockGetEcogesturesByIds.mockClear() + mockGetEcogesturesByIds.mockResolvedValueOnce([ defaultEcogestureData[0], defaultEcogestureData[1], defaultEcogestureData[2], diff --git a/src/services/action.service.ts b/src/services/action.service.ts index 9441daf6380dc0fd4e4ef766f472a0df476e8f9e..cede08d02afbcb07b1c6254268389ffdc3e2e298 100644 --- a/src/services/action.service.ts +++ b/src/services/action.service.ts @@ -1,8 +1,10 @@ import { Client } from 'cozy-client' -import { Season } from 'enum/ecogesture.enum' -import { FluidType } from 'enum/fluid.enum' -import { UserActionState } from 'enum/userAction.enum' -import { UserChallengeUpdateFlag } from 'enum/userChallenge.enum' +import { + FluidType, + Season, + UserActionState, + UserChallengeUpdateFlag, +} from 'enums' import { orderBy } from 'lodash' import { DateTime } from 'luxon' import { Ecogesture, UserAction, UserChallenge } from 'models' @@ -23,7 +25,6 @@ export default class ActionService { /** * Get the list of available actions - * @returns {Promise<Ecogesture[]>} */ public async getAvailableActionList(): Promise<Ecogesture[]> { const userChallenges: UserChallenge[] = @@ -53,8 +54,7 @@ export default class ActionService { } /** - * Get default eocgestures - * @returns {Promise<Ecogesture[]>} + * Get default ecogestures */ public async getDefaultActions(): Promise<Ecogesture[]> { const actionIds = ['ECOGESTURE0030', 'ECOGESTURE0014', 'ECOGESTURE0010'] @@ -64,9 +64,7 @@ export default class ActionService { return defaultActions } - /** Complete the list with unfinished default ecogestures - * @returns {Promise<Ecogesture[]>} - */ + /** Complete the list with unfinished default ecogestures */ public async keepListComplete( actionList: Ecogesture[] ): Promise<Ecogesture[]> { @@ -79,12 +77,6 @@ export default class ActionService { return actionList } - /** - * - * @param {Ecogesture[]} filteredList - * @param {Ecogesture[]} actionList - * @returns {Ecogesture[]} - */ private completeWithNoSeason( filteredList: Ecogesture[], actionList: Ecogesture[] @@ -105,8 +97,6 @@ export default class ActionService { } /** * filterBySeason - Filter action list depending on current season - * @param {Ecogesture[]} actionList - * @returns {Ecogesture[]} */ public filterBySeason(actionList: Ecogesture[]): Ecogesture[] { let filteredList: Ecogesture[] = [] @@ -132,8 +122,6 @@ export default class ActionService { /** * getCustomActions - Filter action by fluid and season and sort them by difficulty first and efficiency second - * @param {FluidType[]} connectedFluids - * @returns {Promise<Ecogesture[]>} */ public async getCustomActions( connectedFluids: FluidType[] @@ -167,8 +155,6 @@ export default class ActionService { /** * launchAction - parse ecogesture to UserAction and launch it - * @param {Ecogesture} Ecogesture - * @returns {UserAction} */ public launchAction(ecogesture: Ecogesture): UserAction { const userAction: UserAction = { @@ -182,8 +168,7 @@ export default class ActionService { } /** * awaitNotificationAction - * @param {UserAction} UserAction - * @returns {UserAction} - updated user action + * @returns {UserAction} updated user action */ public awaitNotificationAction(userAction: UserAction): UserAction { const updatedUserAction: UserAction = { @@ -194,8 +179,7 @@ export default class ActionService { } /** * endAction - * @param {UserAction} UserAction - * @returns {UserAction} - updated user action + * @returns {UserAction} updated user action */ public endAction(userAction: UserAction): UserAction { const updatedUserAction: UserAction = { @@ -206,8 +190,6 @@ export default class ActionService { } /** * isActionDone - Set Action state to notification if progress > actionDuration - * @param {UserChallenge} currentChallenge - * @returns {Promise<UserChallenge | null>} */ public async isActionDone( currentChallenge: UserChallenge diff --git a/src/services/challenge.service.spec.ts b/src/services/challenge.service.spec.ts index b05f55465cffc743227c81ea9e673f3e68cd5a0f..2f0c2bb070680dba3d22da91e25c02480094f487 100644 --- a/src/services/challenge.service.spec.ts +++ b/src/services/challenge.service.spec.ts @@ -1,13 +1,13 @@ /* eslint-disable camelcase */ import { QueryResult } from 'cozy-client' -import { DataloadState } from 'enum/dataload.enum' -import { UserActionState } from 'enum/userAction.enum' import { + DataloadState, + UserActionState, UserChallengeState, UserChallengeSuccess, UserChallengeUpdateFlag, -} from 'enum/userChallenge.enum' -import { UserDuelState } from 'enum/userDuel.enum' + UserDuelState, +} from 'enums' import { cloneDeep } from 'lodash' import { DateTime, Duration } from 'luxon' import { @@ -21,14 +21,14 @@ import { import { allChallengeEntityData, challengeEntityData, -} from '../../tests/__mocks__/challengeEntity.mock' -import { graphData } from '../../tests/__mocks__/chartData.mock' -import mockClient from '../../tests/__mocks__/client' +} from 'tests/__mocks__/challengeEntity.mock' +import { graphData } from 'tests/__mocks__/chartData.mock' +import mockClient from 'tests/__mocks__/client.mock' import { allDuelEntity, duelData, duelEntity, -} from '../../tests/__mocks__/duelData.mock' +} from 'tests/__mocks__/duelData.mock' import { explorationDefault, explorationEntity, @@ -39,53 +39,45 @@ import { userExploration4, userExploration4_0, userExplorationUnlocked, -} from '../../tests/__mocks__/explorationData.mock' -import { fluidStatusData } from '../../tests/__mocks__/fluidStatusData.mock' -import { quizEntity, userQuiz } from '../../tests/__mocks__/quizData.mock' +} from 'tests/__mocks__/explorationData.mock' +import { fluidStatusData } from 'tests/__mocks__/fluidStatusData.mock' +import { quizEntity, userQuiz } from 'tests/__mocks__/quizData.mock' +import { getError } from 'tests/__mocks__/testUtils' import { userChallengeData, userChallengeDefault, userChallengeExplo1OnGoing, userChallengeExplo4, userChallengeExplo4_0, -} from '../../tests/__mocks__/userChallengeData.mock' +} from 'tests/__mocks__/userChallengeData.mock' import ChallengeService from './challenge.service' const mockGetExplorationEntityById = jest.fn() const mockParseExplorationEntityToUserExploration = jest.fn() const mockGetUserExplorationFromExplorationEntities = jest.fn() jest.mock('./exploration.service', () => { - return jest.fn(() => { - return { - getExplorationEntityById: mockGetExplorationEntityById, - parseExplorationEntityToUserExploration: - mockParseExplorationEntityToUserExploration, - getUserExplorationfromExplorationEntities: - mockGetUserExplorationFromExplorationEntities, - } - }) + return jest.fn(() => ({ + getExplorationEntityById: mockGetExplorationEntityById, + parseExplorationEntityToUserExploration: + mockParseExplorationEntityToUserExploration, + getUserExplorationfromExplorationEntities: + mockGetUserExplorationFromExplorationEntities, + })) }) const mockGetGraphData = jest.fn() const mockCalculatePerformanceIndicatorValue = jest.fn() jest.mock('./consumption.service', () => { - return jest.fn(() => { - return { - getGraphData: mockGetGraphData, - calculatePerformanceIndicatorValue: - mockCalculatePerformanceIndicatorValue, - } - }) + return jest.fn(() => ({ + getGraphData: mockGetGraphData, + calculatePerformanceIndicatorValue: mockCalculatePerformanceIndicatorValue, + })) }) describe('Challenge service', () => { const challengeService = new ChallengeService(mockClient) beforeEach(() => { - mockGetExplorationEntityById.mockClear() - mockParseExplorationEntityToUserExploration.mockClear() - mockGetUserExplorationFromExplorationEntities.mockClear() - mockGetGraphData.mockClear() - mockCalculatePerformanceIndicatorValue.mockClear() + jest.clearAllMocks() }) describe('unLockCurrentUserChallenge method', () => { @@ -264,11 +256,10 @@ describe('Challenge service', () => { } mockClient.query.mockResolvedValueOnce(mockQueryResult) mockClient.destroy.mockRejectedValue(new Error()) - try { - await challengeService.deleteAllChallengeEntities() - } catch (error) { - expect(error).toEqual(new Error()) - } + const error = await getError(async () => + challengeService.deleteAllChallengeEntities() + ) + expect(error).toEqual(new Error()) }) }) @@ -316,12 +307,11 @@ describe('Challenge service', () => { expect(result).toEqual(expectedResult) }) it('should throw an error because create failed', async () => { - mockClient.create.mockRejectedValue(new Error()) - try { - await challengeService.initChallengeDuelProgress(userChallengeData[0]) - } catch (error) { - expect(error).toEqual(new Error()) - } + mockClient.save.mockRejectedValue(new Error()) + const error = await getError(async () => + challengeService.initChallengeDuelProgress(userChallengeData[0]) + ) + expect(error).toEqual(new Error()) }) }) @@ -341,11 +331,10 @@ describe('Challenge service', () => { }) it('should throw an error because create failed', async () => { mockClient.create.mockRejectedValue(new Error()) - try { - await challengeService.startUserChallenge(userChallengeData[0]) - } catch (error) { - expect(error).toEqual(new Error()) - } + const error = await getError(async () => + challengeService.startUserChallenge(userChallengeData[0]) + ) + expect(error).toEqual(new Error()) }) }) @@ -383,14 +372,15 @@ describe('Challenge service', () => { ) expect(result).toEqual(userChallengeData[0]) }) - it('should throw error when failed to save the updateUserChallenge', () => { + it('should throw error when failed to save the updateUserChallenge', async () => { mockClient.save.mockRejectedValueOnce(new Error()) - expect( + const error = await getError(async () => challengeService.updateUserChallenge( userChallengeData[0], UserChallengeUpdateFlag.DUEL_START ) - ).rejects.toEqual(new Error()) + ) + expect(error).toEqual(new Error()) }) }) @@ -495,7 +485,7 @@ describe('Challenge service', () => { ) expect(result).toEqual({ isDone: true, isWin: true }) }) - it('should return isDone = true, isWin = false when userConsumption >= threshold ', async () => { + it('should return isDone = true, isWin = false when userConsumption >= threshold', async () => { const updatedUserChallenge = { ...userChallenge, duel: { @@ -581,7 +571,7 @@ describe('Challenge service', () => { expect(result).toEqual({ isDone: true, isWin: true }) }) - it('should return isDone = true and isWin = false when all data are available and userConsumption >= threshold ', async () => { + it('should return isDone = true and isWin = false when all data are available and userConsumption >= threshold', async () => { const updatedUserChallenge = { ...userChallenge, duel: { diff --git a/src/services/challenge.service.ts b/src/services/challenge.service.ts index b9de549d948d7fc7019cc42bc7b339dcc2268459..8cfaeffcdce83867d563b3ad94a7645eb6c75597 100644 --- a/src/services/challenge.service.ts +++ b/src/services/challenge.service.ts @@ -2,16 +2,17 @@ import * as Sentry from '@sentry/react' import { Client, Q, QueryDefinition, QueryResult } from 'cozy-client' import logger from 'cozy-logger' import { CHALLENGE_DOCTYPE, USERCHALLENGE_DOCTYPE } from 'doctypes' -import { FluidState, FluidType } from 'enum/fluid.enum' -import { TimeStep } from 'enum/timeStep.enum' -import { UserActionState } from 'enum/userAction.enum' import { + FluidState, + FluidType, + TimeStep, + UserActionState, UserChallengeState, UserChallengeSuccess, UserChallengeUpdateFlag, -} from 'enum/userChallenge.enum' -import { UserDuelState } from 'enum/userDuel.enum' -import { UserExplorationState } from 'enum/userExploration.enum' + UserDuelState, + UserExplorationState, +} from 'enums' import { DateTime } from 'luxon' import { ChallengeEntity, @@ -55,7 +56,6 @@ export default class ChallengeService { * Retrieve list of Userchallenge and unlock the current challenge if the last one is done * If all challenges are locked, then unlock the first one * @param {UserChallenge[]} userChallenges - status of fluids - * @returns {UserChallenge[]} */ public unLockCurrentUserChallenge( userChallenges: UserChallenge[] @@ -76,7 +76,6 @@ export default class ChallengeService { /** * Retrieve UserChallenge from the UserChallengeEntity * @param {UserChallengeEntity} userChallenges - status of fluids - * @returns {UserChallenge} */ public parseUserChallengeEntityToUserChallenge( userChallengeEntity: UserChallengeEntity @@ -116,7 +115,6 @@ export default class ChallengeService { /** * Retrieve UserChallenge from the UserChallengeEntity * @param {UserChallengeEntity} userChallenges - status of fluids - * @returns {UserChallenge} */ public parseChallengeEntityToUserChallenge( challenge: ChallengeEntity, @@ -153,7 +151,6 @@ export default class ChallengeService { /** * * @param {UserExploration | ExplorationEntity} exploration - Exploration to be tested - * @param {FluidStatus[]} fluidStatus * @returns {boolean} isValid */ public async isExplorationConditionVerified( @@ -176,7 +173,6 @@ export default class ChallengeService { /** * * @param {ChallengeEntity} challenge - get all relations entities of a challenge - * @returns {RelationEntitiesObject} */ public async getRelationEntities( challenge: ChallengeEntity @@ -197,12 +193,6 @@ export default class ChallengeService { /** * Get a UserChallenge from its Entity and verify the exploration if there is a condition and if it's verified - * @param {UserExploration} exploration - * @param {ChallengeEntity} challenge - * @param {UserDuel} duel - * @param {UserQuiz} quiz - * @param {FluidStatus[]} fluidStatus - * @returns {UserChallenge} */ public async getUpdatedUserChallengeIfExplorationConditionIsValid( exploration: UserExploration, @@ -242,13 +232,6 @@ export default class ChallengeService { /** * The whole exploration process, checks if the exploration fluid condition exists and is valid for each existing * Exploration related to given challenge - * @param {ExplorationEntity[] | undefined} explorationEntities - * @param {Relation[]} explorationEntityRelation - * @param {ChallengeEntity} challenge - * @param {UserDuel} duel - * @param {UserQuiz} quiz - * @param {UserChallenge[]} buildList - * @param {FluidStatus[]} fluidStatus * @returns {UserChallenge[]} - buildList */ public async processExploration( @@ -284,10 +267,6 @@ export default class ChallengeService { } /** * Checks if the exploration condition exists and is valid when updating the buildList - * @param {UserChallenge} userChallenge - * @param {ChallengeEntity[]} challengeEntityList - * @param {FluidStatus[]} fluidStatus - * @returns {UserChallenge} */ public async loopVerificationExplorationCondition( userChallenge: UserChallenge, @@ -335,8 +314,6 @@ export default class ChallengeService { /** * Retrieve UserChallenge list with all challenges - * @param {FluidStatus[]} fluidStatus - * @returns {UserChallenge[]} */ public async buildUserChallengeList( fluidStatus: FluidStatus[] @@ -456,7 +433,6 @@ export default class ChallengeService { /** * Retrieve all ChallengeEntities - * @returns {ChallengeEntity[]} */ public async getAllChallengeEntities(): Promise<ChallengeEntity[]> { const query: QueryDefinition = Q(CHALLENGE_DOCTYPE) @@ -467,7 +443,6 @@ export default class ChallengeService { /** * Delete all ChallengeEntities - * @returns {boolean} * @throws {Error} */ public async deleteAllChallengeEntities(): Promise<boolean> { @@ -484,14 +459,13 @@ export default class ChallengeService { )}` logStack('error', errorMessage) logApp.error(errorMessage) - Sentry.captureException(errorMessage) + Sentry.captureException(error) throw error } } /** * Retrieve all UserChallengeEntities - * @returns {UserChallenge[]} */ public async getAllUserChallengeEntities(): Promise<UserChallenge[]> { const query: QueryDefinition = Q(USERCHALLENGE_DOCTYPE) @@ -517,10 +491,8 @@ export default class ChallengeService { }> { const consumptionService = new ConsumptionDataManager(this._client) try { - const dataloads: Dataload[] = await this.getUserChallengeDataload( - userChallenge - ) - const userConsumption: number = getRoundFloat( + const dataloads = await this.getUserChallengeDataload(userChallenge) + const userConsumption = getRoundFloat( consumptionService.calculatePerformanceIndicatorValue(dataloads) ) const _userChallenge: UserChallenge = { @@ -530,11 +502,10 @@ export default class ChallengeService { userConsumption: userConsumption, }, } - const updatedUserChallenge: UserChallenge = - await this.updateUserChallenge( - _userChallenge, - UserChallengeUpdateFlag.DUEL_CONSUMPTION - ) + const updatedUserChallenge = await this.updateUserChallenge( + _userChallenge, + UserChallengeUpdateFlag.DUEL_CONSUMPTION + ) return { updatedUserChallenge, dataloads } } catch (error) { const errorMessage = `Challenge service error on initChallengeDuelProgress: ${JSON.stringify( @@ -542,14 +513,13 @@ export default class ChallengeService { )}` logStack('error', errorMessage) logApp.error(errorMessage) - Sentry.captureException(errorMessage) + Sentry.captureException(error) throw error } } /** * Start UserChallenge and retrieve updated UserChallenge - * @returns {UserChallenge} * @throws {Error} */ public async startUserChallenge( @@ -585,7 +555,7 @@ export default class ChallengeService { )}` logStack('error', errorMessage) logApp.error(errorMessage) - Sentry.captureException(errorMessage) + Sentry.captureException(error) throw error } } @@ -673,6 +643,15 @@ export default class ChallengeService { success: UserChallengeSuccess.LOST, } break + case UserChallengeUpdateFlag.DUEL_RESET: + updatedDuel = await duelService.resetUserDuel(userChallenge.duel) + updatedUserChallenge = { + ...userChallenge, + state: UserChallengeState.DUEL, + duel: updatedDuel, + success: UserChallengeSuccess.ONGOING, + } + break case UserChallengeUpdateFlag.QUIZ_START: updatedQuiz = await quizService.startUserQuiz(userChallenge.quiz) updatedUserChallenge = { @@ -796,7 +775,7 @@ export default class ChallengeService { )}` logStack('error', errorMessage) logApp.error(errorMessage) - Sentry.captureException(errorMessage) + Sentry.captureException(error) throw error } } @@ -805,7 +784,6 @@ export default class ChallengeService { * Retrieve the dataload for a UserChallenge with duel ongoing * @param {UserChallenge} userChallenge - userChallenge to update * @param {UserChallengeUpdateFlag} flag - update flag - * @returns {Dataload[]} */ public async getUserChallengeDataload( userChallenge: UserChallenge @@ -837,7 +815,6 @@ export default class ChallengeService { * Define if challenge is done and if is win or lost * @param {UserChallenge} userChallenge - current userChallenge * @param {Dataload[]} dataloads - dataloads of current challenge - * @returns {boolean, boolean} */ public async isChallengeDone( userChallenge: UserChallenge, diff --git a/src/services/connection.service.spec.ts b/src/services/connection.service.spec.ts index 9b8e6910b4b8ca5791a3f6b404e1e3f6d5af462d..445efa37ffd5330e4e4f23b02ca88105b548f1fb 100644 --- a/src/services/connection.service.spec.ts +++ b/src/services/connection.service.spec.ts @@ -1,35 +1,29 @@ import { AccountAuthData } from 'models' -import { accountsData } from '../../tests/__mocks__/accountsData.mock' -import mockClient from '../../tests/__mocks__/client' -import { konnectorsData } from '../../tests/__mocks__/konnectorsData.mock' -import { triggersData } from '../../tests/__mocks__/triggersData.mock' +import { accountsData } from 'tests/__mocks__/accountsData.mock' +import mockClient from 'tests/__mocks__/client.mock' +import { konnectorsData } from 'tests/__mocks__/konnectorsData.mock' +import { triggersData } from 'tests/__mocks__/triggersData.mock' import ConnectionService from './connection.service' const mockGetKonnector = jest.fn() jest.mock('./konnector.service', () => { - return jest.fn(() => { - return { - getKonnector: mockGetKonnector, - } - }) + return jest.fn(() => ({ + getKonnector: mockGetKonnector, + })) }) const mockCreateAccount = jest.fn() jest.mock('./account.service', () => { - return jest.fn(() => { - return { - createAccount: mockCreateAccount, - } - }) + return jest.fn(() => ({ + createAccount: mockCreateAccount, + })) }) const mockCreateTrigger = jest.fn() jest.mock('./triggers.service', () => { - return jest.fn(() => { - return { - createTrigger: mockCreateTrigger, - } - }) + return jest.fn(() => ({ + createTrigger: mockCreateTrigger, + })) }) const mockEGLAuthData: AccountAuthData = { diff --git a/src/services/connection.service.ts b/src/services/connection.service.ts index af9ccea3b23784d69a74183927209a31a17d8596..500955376ca4980422bbbf4248071349f5ddefbe 100644 --- a/src/services/connection.service.ts +++ b/src/services/connection.service.ts @@ -6,9 +6,9 @@ import { AccountAuthData, AccountSgeData, Konnector, + SgeStore, Trigger, } from 'models' -import { SgeStore } from 'models/sgeStore.model' import AccountService from 'services/account.service' import KonnectorService from 'services/konnector.service' import TriggerService from 'services/triggers.service' diff --git a/src/services/consumption.service.spec.ts b/src/services/consumption.service.spec.ts index 9c14ac5fa72003fd59bde4673c000cfe14cd97ed..ba675a859c898aac29c919567cb254f70d7509d1 100644 --- a/src/services/consumption.service.spec.ts +++ b/src/services/consumption.service.spec.ts @@ -1,8 +1,6 @@ import { QueryResult } from 'cozy-client' import { ENEDIS_MINUTE_DOCTYPE } from 'doctypes' -import { DataloadState } from 'enum/dataload.enum' -import { FluidType } from 'enum/fluid.enum' -import { TimeStep } from 'enum/timeStep.enum' +import { DataloadState, FluidType, TimeStep } from 'enums' import { DateTime } from 'luxon' import { Datachart, @@ -12,10 +10,14 @@ import { FluidStatus, TimePeriod, } from 'models' -import mockClient from '../../tests/__mocks__/client' -import { fluidPrices } from '../../tests/__mocks__/fluidPrice.mock' -import { fluidStatusConnectedData } from '../../tests/__mocks__/fluidStatusData.mock' -import { loadDayData } from '../../tests/__mocks__/loadDayData.mock' +import mockClient from 'tests/__mocks__/client.mock' +import { + fetchDayDataComplete, + fetchDayDataIncomplete, +} from 'tests/__mocks__/fetchDayData.mock' +import { fluidPrices } from 'tests/__mocks__/fluidPrice.mock' +import { fluidStatusConnectedData } from 'tests/__mocks__/fluidStatusData.mock' +import { loadDayData } from 'tests/__mocks__/loadDayData.mock' import ConsumptionDataManager from './consumption.service' const mockFetchFluidData = jest.fn() @@ -24,15 +26,13 @@ const mockGetFirstDateData = jest.fn() const mockGetLastDateData = jest.fn() const mockGetEntries = jest.fn() jest.mock('./queryRunner.service', () => { - return jest.fn(() => { - return { - fetchFluidData: mockFetchFluidData, - fetchFluidMaxData: mockFetchFluidMaxData, - getFirstDateData: mockGetFirstDateData, - getLastDateData: mockGetLastDateData, - getEntries: mockGetEntries, - } - }) + return jest.fn(() => ({ + fetchFluidData: mockFetchFluidData, + fetchFluidMaxData: mockFetchFluidMaxData, + getFirstDateData: mockGetFirstDateData, + getLastDateData: mockGetLastDateData, + getEntries: mockGetEntries, + })) }) describe('Consumption service', () => { @@ -76,9 +76,6 @@ describe('Consumption service', () => { ] describe('getGraphData method', () => { - beforeEach(() => { - mockFetchFluidData.mockClear() - }) it('should return null', async () => { const result = await consumptionDataManager.getGraphData( mockTimePeriod, @@ -403,7 +400,7 @@ describe('Consumption service', () => { }) }) - describe('getExportableFluids method', () => { + describe('getFluidsWithData method', () => { it('should return the array of fluidTypes that have entries', async () => { const fluidTypes: FluidType[] = [ FluidType.ELECTRICITY, @@ -413,7 +410,7 @@ describe('Consumption service', () => { mockGetEntries.mockResolvedValueOnce({ data: [1] }) mockGetEntries.mockResolvedValueOnce({ data: [] }) mockGetEntries.mockResolvedValueOnce({ data: [1] }) - const result = await consumptionDataManager.getExportableFluids( + const result = await consumptionDataManager.getFluidsWithData( fluidTypes, TimeStep.MONTH ) @@ -581,4 +578,58 @@ describe('Consumption service', () => { expect(result.length).toEqual(4) }) }) + + describe('getFluidsWithDataForTimePeriod', () => { + const allFluids = [FluidType.ELECTRICITY, FluidType.WATER, FluidType.GAS] + const timePeriods: TimePeriod = { + startDate: DateTime.local(2023, 5, 1), + endDate: DateTime.local(2023, 6, 1), + } + it('should return 2 fluids', async () => { + mockFetchFluidData.mockResolvedValueOnce(null) + mockFetchFluidData.mockResolvedValueOnce(mockFetchDataActual) + mockFetchFluidData.mockResolvedValueOnce(mockFetchDataActual) + const fluidsWithData = + await consumptionDataManager.getFluidsWithDataForTimePeriod( + allFluids, + timePeriods + ) + expect(fluidsWithData).toEqual([FluidType.WATER, FluidType.GAS]) + }) + it('should return no fluids', async () => { + mockFetchFluidData.mockResolvedValue(null) + const fluidsWithData = + await consumptionDataManager.getFluidsWithDataForTimePeriod( + allFluids, + timePeriods + ) + expect(fluidsWithData).toEqual([]) + }) + }) + + describe('getFluidsWithIncompleteDataForTimePeriod', () => { + const allFluids = [FluidType.ELECTRICITY, FluidType.WATER, FluidType.GAS] + const month = DateTime.local(2023, 7, 1) + + it('should return 2 fluids', async () => { + mockFetchFluidData.mockResolvedValueOnce(fetchDayDataComplete) + mockFetchFluidData.mockResolvedValueOnce(fetchDayDataIncomplete) + mockFetchFluidData.mockResolvedValueOnce(fetchDayDataIncomplete) + const fluidsWithIncompleteData = + await consumptionDataManager.getFluidsWithIncompleteData( + allFluids, + month + ) + expect(fluidsWithIncompleteData).toEqual([FluidType.WATER, FluidType.GAS]) + }) + it('should return no fluids', async () => { + mockFetchFluidData.mockResolvedValue(fetchDayDataComplete) + const fluidsWithData = + await consumptionDataManager.getFluidsWithIncompleteData( + allFluids, + month + ) + expect(fluidsWithData).toEqual([]) + }) + }) }) diff --git a/src/services/consumption.service.ts b/src/services/consumption.service.ts index 48fb3f060614ce28957d46b43270676d3fbbdcdc..b6565ff740072fd5396b760f8c84122651a26223 100644 --- a/src/services/consumption.service.ts +++ b/src/services/consumption.service.ts @@ -1,26 +1,24 @@ import { Client, Q, QueryDefinition, QueryResult } from 'cozy-client' import { Doctype } from 'cozy-client/types/types' import { ENEDIS_MINUTE_DOCTYPE } from 'doctypes' -import { DataloadState } from 'enum/dataload.enum' -import { FluidType } from 'enum/fluid.enum' -import { TimeStep } from 'enum/timeStep.enum' +import { DataloadState, FluidType, TimeStep } from 'enums' import { DateTime } from 'luxon' import { Datachart, Dataload, DataloadEntity, DataloadValueDetail, + EnedisMonthlyAnalysisData, FluidStatus, PerformanceIndicator, TimePeriod, } from 'models' -import { EnedisMonthlyAnalysisData } from 'models/enedisMonthlyAnalysis' import ConsumptionFormatterService from 'services/consumptionFormatter.service' import ConsumptionValidatorService from 'services/consumptionValidator.service' import ConverterService from 'services/converter.service' import QueryRunnerService from 'services/queryRunner.service' -export interface ISingleFluidChartData { +interface ISingleFluidChartData { chartData: Datachart | null chartFluid: FluidType } @@ -331,17 +329,68 @@ export default class ConsumptionDataManager { return result } - public async getExportableFluids( + /** + * Check that fluidTypes contains data over a timestep. + * @returns an array of FluidType that contains data + */ + public async getFluidsWithData( fluidTypes: FluidType[], timeStep: TimeStep ): Promise<FluidType[]> { - const exportableFluids: FluidType[] = [] + const fluidsWithData: FluidType[] = [] for (const fluidType of fluidTypes) { if (await this.checkDoctypeEntries(fluidType, timeStep)) { - exportableFluids.push(fluidType) + fluidsWithData.push(fluidType) + } + } + return fluidsWithData + } + + public async getFluidsWithDataForTimePeriod( + fluidTypes: FluidType[], + timePeriod: TimePeriod, + timeStep = TimeStep.MONTH + ): Promise<FluidType[]> { + const fluidsWithData: FluidType[] = [] + for (const fluidType of fluidTypes) { + const data = await this._queryRunnerService.fetchFluidData( + timePeriod, + timeStep, + fluidType + ) + if (data?.length) { + fluidsWithData.push(fluidType) + } + } + return fluidsWithData + } + + /** + * Retrieves an array of fluid types that have incomplete data for a given month. + * + * Data is incomplete if at least one daily data is missing for the month. + * @param {DateTime} month - The month for which to check the data completeness. + */ + public async getFluidsWithIncompleteData( + fluidTypes: FluidType[], + month: DateTime + ): Promise<FluidType[]> { + const fluidsWithIncompleteData: FluidType[] = [] + const timePeriod: TimePeriod = { + startDate: month.startOf('month'), + endDate: month.endOf('month'), + } + for (const fluidType of fluidTypes) { + const data = await this._queryRunnerService.fetchFluidData( + timePeriod, + TimeStep.DAY, + fluidType + ) + if (data?.length && data?.length < month.daysInMonth) { + fluidsWithIncompleteData.push(fluidType) } } - return exportableFluids + return fluidsWithIncompleteData } public async fetchAllFirstDateData( @@ -533,7 +582,6 @@ export default class ConsumptionDataManager { /** * getLastHourData - * @param {Client} client * @param {number} month number * @returns {Promise<DataloadEntity[]>} usageEvent added */ @@ -556,8 +604,6 @@ export default class ConsumptionDataManager { /** * Get the first entry of a given data doctype (enedis, grdf, egl) - * @param doctype - * @returns */ public async getFirsDataDateFromDoctype( doctype: Doctype diff --git a/src/services/consumptionFormatter.service.spec.ts b/src/services/consumptionFormatter.service.spec.ts index 1b6e2c2b9d7d31d288524351448127e476847e41..2c07788f299d6ea224d3b7d0bb93a5f43c52a2c5 100644 --- a/src/services/consumptionFormatter.service.spec.ts +++ b/src/services/consumptionFormatter.service.spec.ts @@ -1,9 +1,8 @@ -import { DataloadState } from 'enum/dataload.enum' -import { FluidType } from 'enum/fluid.enum' -import { TimeStep } from 'enum/timeStep.enum' +import { DataloadState, FluidType, TimeStep } from 'enums' import { DateTime } from 'luxon' import { Dataload, FluidStatus, TimePeriod } from 'models' -import { fluidStatusConnectedData } from '../../tests/__mocks__/fluidStatusData.mock' +import { fluidStatusConnectedData } from 'tests/__mocks__/fluidStatusData.mock' +import { getError } from 'tests/__mocks__/testUtils' import ConsumptionFormatterService from './consumptionFormatter.service' const localSpy = jest.spyOn(DateTime, 'local') @@ -251,8 +250,8 @@ describe('ConsumptionFormatter service', () => { ) expect(result).toEqual(mockResult) }) - it('should return an error because of unknown TimeStep', () => { - try { + it('should return an error because of unknown TimeStep', async () => { + const error = await getError(async () => consumptionFormatterService.formatGraphData( mockDataLoad, mockTimePeriod, @@ -260,9 +259,8 @@ describe('ConsumptionFormatter service', () => { FluidType.ELECTRICITY, fluidStatus[FluidType.ELECTRICITY] ) - } catch (error) { - expect(error).toEqual(new Error('TimeStep unknown')) - } + ) + expect(error).toEqual(new Error('TimeStep unknown')) }) }) diff --git a/src/services/consumptionFormatter.service.ts b/src/services/consumptionFormatter.service.ts index 36c32a784e0f51da74ccb45ed2279132b19a8b54..cc05206889191b517bd1936f52ad0cffb046420e 100644 --- a/src/services/consumptionFormatter.service.ts +++ b/src/services/consumptionFormatter.service.ts @@ -1,6 +1,4 @@ -import { DataloadState } from 'enum/dataload.enum' -import { FluidType } from 'enum/fluid.enum' -import { TimeStep } from 'enum/timeStep.enum' +import { DataloadState, FluidType, TimeStep } from 'enums' import { DateTime, Interval } from 'luxon' import { Dataload, FluidStatus, TimePeriod } from 'models' import DateChartService from 'services/dateChart.service' diff --git a/src/services/consumptionValidator.service.spec.ts b/src/services/consumptionValidator.service.spec.ts index dbb3be7527d383363280d27190c6d43381024adb..819a9724a39ae7e4890842d11e10a988f28eb9c0 100644 --- a/src/services/consumptionValidator.service.spec.ts +++ b/src/services/consumptionValidator.service.spec.ts @@ -1,5 +1,4 @@ -import { FluidType } from 'enum/fluid.enum' -import { TimeStep } from 'enum/timeStep.enum' +import { FluidType, TimeStep } from 'enums' import { DateTime } from 'luxon' import { TimePeriod } from 'models' import ConsumptionValidatorService from './consumptionValidator.service' @@ -12,15 +11,15 @@ const mockTimePeriodComparison: TimePeriod = { startDate: DateTime.fromISO('2020-09-01T00:00:00.000Z', { zone: 'utc' }), endDate: DateTime.fromISO('2020-09-03T23:59:59.999Z', { zone: 'utc' }), } -let fluidTypes: FluidType[] = [0, 1, 2] +let allFluids: FluidType[] = [0, 1, 2] describe('ConsumptionFormatter service', () => { const consumptionValidatorService = new ConsumptionValidatorService() - describe('formatGraphData method', () => { + describe('ValidateGetGraphData method', () => { it('should return true for DAY', () => { const result = consumptionValidatorService.ValidateGetGraphData( mockTimePeriod, TimeStep.DAY, - fluidTypes + allFluids ) expect(result).toBeTruthy() }) @@ -28,7 +27,7 @@ describe('ConsumptionFormatter service', () => { const result = consumptionValidatorService.ValidateGetGraphData( mockTimePeriod, TimeStep.DAY, - fluidTypes, + allFluids, mockTimePeriodComparison ) expect(result).toBeTruthy() @@ -43,12 +42,12 @@ describe('ConsumptionFormatter service', () => { const result = consumptionValidatorService.ValidateGetGraphData( mockTimePeriod, TimeStep.DAY, - fluidTypes, + allFluids, wrongTimePeriodComparison ) expect(result).toBeFalsy() }) - it('should return false with comparison Date', () => { + it('should return false with comparison Date for elec', () => { const wrongTimePeriodComparison: TimePeriod = { startDate: DateTime.fromISO('2020-09-05T00:00:00.000Z', { zone: 'utc', @@ -82,7 +81,7 @@ describe('ConsumptionFormatter service', () => { const result = consumptionValidatorService.ValidateGetGraphData( wrongTimePeriod, TimeStep.DAY, - fluidTypes + allFluids ) expect(result).toBeFalsy() }) @@ -90,12 +89,12 @@ describe('ConsumptionFormatter service', () => { const result = consumptionValidatorService.ValidateGetGraphData( mockTimePeriod, TimeStep.HALF_AN_HOUR, - fluidTypes + allFluids ) expect(result).toBeFalsy() }) it('should return false because of HALF_AN_HOUR and ValidateTimePeriodLength', () => { - fluidTypes = [0] // Only fluid without TimeStep incompatibilty + allFluids = [0] // Only fluid without TimeStep incompatibilty const mockTimePeriodTooLong: TimePeriod = { startDate: DateTime.fromISO('2020-10-01T00:00:00.000Z', { zone: 'utc', @@ -105,7 +104,7 @@ describe('ConsumptionFormatter service', () => { const result = consumptionValidatorService.ValidateGetGraphData( mockTimePeriodTooLong, TimeStep.HALF_AN_HOUR, - fluidTypes + allFluids ) expect(result).toBeFalsy() }) @@ -119,7 +118,7 @@ describe('ConsumptionFormatter service', () => { const result = consumptionValidatorService.ValidateGetGraphData( mockTimePeriodTooLong, TimeStep.WEEK, - fluidTypes + allFluids ) expect(result).toBeFalsy() }) @@ -133,7 +132,7 @@ describe('ConsumptionFormatter service', () => { const result = consumptionValidatorService.ValidateGetGraphData( mockTimePeriodTooLong, TimeStep.DAY, - fluidTypes + allFluids ) expect(result).toBeFalsy() }) @@ -147,7 +146,7 @@ describe('ConsumptionFormatter service', () => { const result = consumptionValidatorService.ValidateGetGraphData( mockTimePeriodTooLong, TimeStep.MONTH, - fluidTypes + allFluids ) expect(result).toBeFalsy() }) @@ -161,7 +160,7 @@ describe('ConsumptionFormatter service', () => { const result = consumptionValidatorService.ValidateGetGraphData( mockTimePeriodTooLong, TimeStep.YEAR, - fluidTypes + allFluids ) expect(result).toBeFalsy() }) diff --git a/src/services/consumptionValidator.service.ts b/src/services/consumptionValidator.service.ts index 7f3901487ce2cf808b519cfbc7e1ee27f4abbfcd..c120459d8a7a477720bfb8083595a43b29aa32ce 100644 --- a/src/services/consumptionValidator.service.ts +++ b/src/services/consumptionValidator.service.ts @@ -1,5 +1,4 @@ -import { FluidType } from 'enum/fluid.enum' -import { TimeStep } from 'enum/timeStep.enum' +import { FluidType, TimeStep } from 'enums' import { Interval } from 'luxon' import { TimePeriod } from 'models' diff --git a/src/services/converter.service.spec.ts b/src/services/converter.service.spec.ts index da324b069e93fa3e6f9f8f808ef20f8d2a9accca..85868150ad91496b08e9f260e0e915abd2e52b6b 100644 --- a/src/services/converter.service.spec.ts +++ b/src/services/converter.service.spec.ts @@ -1,4 +1,4 @@ -import { FluidType } from 'enum/fluid.enum' +import { FluidType } from 'enums' import ConverterService from './converter.service' import ConfigService from './fluidConfig.service' diff --git a/src/services/converter.service.ts b/src/services/converter.service.ts index c7e45fa5614413d11490d5c422f217d4fb143f92..d283508b42a1d209dc5e51885365c43f10975d97 100644 --- a/src/services/converter.service.ts +++ b/src/services/converter.service.ts @@ -1,4 +1,4 @@ -import { FluidType } from 'enum/fluid.enum' +import { FluidType } from 'enums' import { FluidConfig } from 'models' import ConfigService from './fluidConfig.service' @@ -34,7 +34,6 @@ export default class ConverterService { * @param {FluidConfig} fluidConfig - Fluid configuration * @param {number} load - Load value * @param {number} [price] - Price if exist - * @returns {number} */ private applyPrice( fluidConfig: FluidConfig, diff --git a/src/services/customPopup.service.test.ts b/src/services/customPopup.service.spec.ts similarity index 74% rename from src/services/customPopup.service.test.ts rename to src/services/customPopup.service.spec.ts index 95201974937b73cc975c2b9f46afe90b983a8595..11d1d9cc798e0e93b399a36b6a5e7d5a811d7a80 100644 --- a/src/services/customPopup.service.test.ts +++ b/src/services/customPopup.service.spec.ts @@ -1,13 +1,11 @@ -import mockClient from '../../tests/__mocks__/client' -import { mockCustomPopup } from '../../tests/__mocks__/customPopup.mock' +import mockClient from 'tests/__mocks__/client.mock' +import { mockCustomPopup } from 'tests/__mocks__/customPopup.mock' import CustomPopupService from './customPopup.service' jest.mock('services/environment.service', () => { - return jest.fn(() => { - return { - isProduction: () => true, - } - }) + return jest.fn(() => ({ + isProduction: () => true, + })) }) describe('PartnersInfo service', () => { @@ -26,7 +24,8 @@ describe('PartnersInfo service', () => { res = await customPopupService.getCustomPopup() expect(true).toBe(false) } catch (error) { - expect(res).toBe(undefined) + // } + expect(res).toBe(undefined) }) }) diff --git a/src/services/customPopup.service.ts b/src/services/customPopup.service.ts index 32f87726eee3350a2bf1f302737ccfa50fe0f62f..f09472520760a6cca1f6cb286c051605016c0d05 100644 --- a/src/services/customPopup.service.ts +++ b/src/services/customPopup.service.ts @@ -4,8 +4,8 @@ import logger from 'cozy-logger' import { REMOTE_ORG_ECOLYO_AGENT_CUSTOM_POPUP, REMOTE_ORG_ECOLYO_AGENT_CUSTOM_POPUP_REC, -} from 'doctypes/remote/org.ecolyo.agent.custom.popup' -import { CustomPopup } from 'models/customPopup.model' +} from 'doctypes' +import { CustomPopup } from 'models' import logApp from 'utils/logger' import EnvironmentService from './environment.service' @@ -20,7 +20,7 @@ export default class CustomPopupService { /** * Get information from backoffice about the status of custom popup * On success, respond the customPopup - * Else, throw an error + * Else, return undefined */ public async getCustomPopup(): Promise<CustomPopup | undefined> { const env = new EnvironmentService() @@ -39,7 +39,7 @@ export default class CustomPopupService { )}` logStack('error', errorMessage) logApp.error(errorMessage) - Sentry.captureException(errorMessage) + Sentry.captureException(error) } } } diff --git a/src/services/dateChart.service.spec.ts b/src/services/dateChart.service.spec.ts index 393f02a1241719c32c1bedcd63935072d894a95c..59c9d2d5b8cad3a3e4f8b7e347809c057cc24a2c 100644 --- a/src/services/dateChart.service.spec.ts +++ b/src/services/dateChart.service.spec.ts @@ -1,6 +1,7 @@ -import { TimeStep } from 'enum/timeStep.enum' +import { TimeStep } from 'enums' import { DateTime } from 'luxon' import { TimePeriod } from 'models' +import { getError } from 'tests/__mocks__/testUtils' import DateChartService from './dateChart.service' const localSpy = jest.spyOn(DateTime, 'local') @@ -294,12 +295,11 @@ describe('dateChart service', () => { expect(result).toEqual(expectedTimePeriod) }) - it('should throw error for unknown TimeStep', () => { - try { + it('should throw error for unknown TimeStep', async () => { + const error = await getError(async () => dateChartService.defineTimePeriod(refDate, unknownTimeStep, -1) - } catch (error) { - expect(error).toEqual(new Error('TimeStep unknown')) - } + ) + expect(error).toEqual(new Error('TimeStep unknown')) }) }) @@ -686,18 +686,17 @@ describe('dateChart service', () => { expect(result).toBe(false) }) - it('should throw error for unknown TimeStep', () => { + it('should throw error for unknown TimeStep', async () => { const firstDate = DateTime.fromISO('2020-10-31T00:00:00.000Z', { zone: 'utc', }) const secondDate = DateTime.fromISO('2020-10-31T00:30:00.000Z', { zone: 'utc', }) - try { + const error = await getError(async () => dateChartService.compareStepDate(unknownTimeStep, firstDate, secondDate) - } catch (error) { - expect(error).toEqual(new Error('TimeStep unknown')) - } + ) + expect(error).toEqual(new Error('TimeStep unknown')) }) }) @@ -1111,20 +1110,6 @@ describe('dateChart service', () => { ) expect(result).toEqual(1) }) - it('should return index -1 for year, 2024', () => { - const selectedDate: DateTime = DateTime.fromISO( - '2024-01-01T00:00:00.000Z', - { - zone: 'utc', - } - ) - const result = dateChartService.defineDateIndex( - TimeStep.YEAR, - selectedDate - ) - expect(result).toEqual(-1) - }) - it('should return index 0 for month, 05-2020', () => { const selectedDate: DateTime = DateTime.fromISO( '2020-05-01T00:00:00.000Z', diff --git a/src/services/dateChart.service.ts b/src/services/dateChart.service.ts index 199666c05ec86bd1b857ea55c932ef98c5c0bb29..1a5ac296b4322b29a324126e36d9f6a043a68256 100644 --- a/src/services/dateChart.service.ts +++ b/src/services/dateChart.service.ts @@ -1,5 +1,4 @@ -import { FluidType } from 'enum/fluid.enum' -import { TimeStep } from 'enum/timeStep.enum' +import { FluidType, TimeStep } from 'enums' import { DateTime, Interval } from 'luxon' import { FluidConfig, TimePeriod } from 'models' import ConfigService from './fluidConfig.service' @@ -7,9 +6,6 @@ import ConfigService from './fluidConfig.service' export default class DateChartService { /** * Define a time period for a given slide defined by its index - * @param referenceDate - * @param timeStep - * @param index */ public defineTimePeriod( referenceDate: DateTime, @@ -94,7 +90,6 @@ export default class DateChartService { * @param {DateTime} referenceDate - reference date * @param {TimeStep} timeStep - time step * @param {number} index - index - * @returns {DateTime} */ public defineFirstStepDate( referenceDate: DateTime, @@ -110,7 +105,6 @@ export default class DateChartService { * @param {DateTime} referenceDate - reference date * @param {TimeStep} timeStep - time step * @param {number} index - index - * @returns {DateTime} */ public defineLastStepDate( referenceDate: DateTime, @@ -257,10 +251,10 @@ export default class DateChartService { } /** - * Return the date incremented in function of the timestep + * Return the chart index in function of the timestep and a given date * @param {TimeStep} timeStep - current time step * @param {DateTime} selectedDate - current selected date - * @returns {number} - incremented date + * @returns {number} - index */ public defineDateIndex(timeStep: TimeStep, selectedDate: DateTime): number { const today = DateTime.local().setZone('utc', { @@ -268,11 +262,7 @@ export default class DateChartService { }) switch (timeStep) { case TimeStep.YEAR: - if (today.year >= selectedDate.year) { - return Math.trunc((today.year - selectedDate.year) / 5) - } else { - return Math.trunc((today.year - selectedDate.year) / 5) - 1 - } + return Math.trunc((today.year - selectedDate.year) / 5) case TimeStep.MONTH: return today.year - selectedDate.year case TimeStep.DAY: @@ -297,8 +287,6 @@ export default class DateChartService { /** * Checks if the last data date is outdated and returns the number of missing days - * @param {DateTime | null} lastDataDate - * @param {FluidType} fluidType * @returns {number| null} - The number of missing days */ public isDataOutdated( diff --git a/src/services/duel.service.spec.ts b/src/services/duel.service.spec.ts index dd4ea30f57b7c68da20d494d080a6fe153558c65..93cd9552abc03d91449dc2814d1bbb00aade13ac 100644 --- a/src/services/duel.service.spec.ts +++ b/src/services/duel.service.spec.ts @@ -1,40 +1,36 @@ import { QueryResult } from 'cozy-client' -import { FluidType } from 'enum/fluid.enum' -import { UserDuelState } from 'enum/userDuel.enum' +import { FluidType, UserDuelState } from 'enums' import { DateTime, Duration } from 'luxon' import { DuelEntity, UserDuel } from 'models' import DuelService from 'services/duel.service' -import { fullGraphData, graphData } from '../../tests/__mocks__/chartData.mock' -import mockClient from '../../tests/__mocks__/client' +import { fullGraphData, graphData } from 'tests/__mocks__/chartData.mock' +import mockClient from 'tests/__mocks__/client.mock' import { allDuelData, duelData, duelEntity, -} from '../../tests/__mocks__/duelData.mock' +} from 'tests/__mocks__/duelData.mock' import { fluidStatusConnectedData, fluidStatusData, -} from '../../tests/__mocks__/fluidStatusData.mock' +} from 'tests/__mocks__/fluidStatusData.mock' +import { getError } from 'tests/__mocks__/testUtils' const mockGetPerformanceIndicators = jest.fn() const mockGetGraphData = jest.fn() jest.mock('./consumption.service', () => { - return jest.fn(() => { - return { - getPerformanceIndicators: mockGetPerformanceIndicators, - getGraphData: mockGetGraphData, - } - }) + return jest.fn(() => ({ + getPerformanceIndicators: mockGetPerformanceIndicators, + getGraphData: mockGetGraphData, + })) }) const mockAggregatePerformanceIndicators = jest.fn() jest.mock('./performanceIndicator.service', () => { - return jest.fn(() => { - return { - aggregatePerformanceIndicators: mockAggregatePerformanceIndicators, - } - }) + return jest.fn(() => ({ + aggregatePerformanceIndicators: mockAggregatePerformanceIndicators, + })) }) describe('Duel service', () => { @@ -92,11 +88,10 @@ describe('Duel service', () => { } mockClient.query.mockResolvedValueOnce(mockQueryResult) mockClient.destroy.mockRejectedValue(new Error()) - try { - await duelService.deleteAllDuelEntities() - } catch (error) { - expect(error).toEqual(new Error()) - } + const error = await getError(async () => + duelService.deleteAllDuelEntities() + ) + expect(error).toEqual(new Error()) }) }) @@ -120,6 +115,20 @@ describe('Duel service', () => { }) }) + describe('resetUserDuel method', () => { + it('should return the userDuel with unlocked state', async () => { + const result = await duelService.resetUserDuel(duelData) + const mockUpdatedDuel: UserDuel = { + ...duelData, + startDate: null, + state: UserDuelState.UNLOCKED, + threshold: 0, + userConsumption: 0, + } + expect(result).toEqual(mockUpdatedDuel) + }) + }) + describe('parseDuelEntityToDuel method', () => { it('should return the userDuel from a duelEntity', () => { const mockUpdatedDuel: UserDuel = { diff --git a/src/services/duel.service.ts b/src/services/duel.service.ts index 63e308e4ca42d94e4a769603e14ee699d86eef1e..f721543a6fe7ca02e60cf59567fc99eca63c69a9 100644 --- a/src/services/duel.service.ts +++ b/src/services/duel.service.ts @@ -1,10 +1,8 @@ import * as Sentry from '@sentry/react' import { Client, Q, QueryDefinition, QueryResult } from 'cozy-client' import logger from 'cozy-logger' -import { DUEL_DOCTYPE } from 'doctypes/com-grandlyon-ecolyo-duel' -import { FluidState, FluidType } from 'enum/fluid.enum' -import { TimeStep } from 'enum/timeStep.enum' -import { UserDuelState } from 'enum/userDuel.enum' +import { DUEL_DOCTYPE } from 'doctypes' +import { FluidState, FluidType, TimeStep, UserDuelState } from 'enums' import { DateTime, Duration } from 'luxon' import { Datachart, @@ -32,7 +30,6 @@ export default class DuelService { /** * Retrieve period with data based on lastDataDate of the fluids * @param {FluidStatus[]} fluidStatus - status of fluids - * @param {Duel} userDuel * @returns {TimePeriod} - true when deleted with success */ private async getValidPeriod( @@ -69,10 +66,6 @@ export default class DuelService { } /** * Check all period until find one with no empty value or return false - * @param period - * @param fluidType - * @param duration - * @returns {Promise<false | TimePeriod>} */ private async isPeriodComplete( period: TimePeriod, @@ -118,7 +111,6 @@ export default class DuelService { } /** * Retrieve all duel entities from db - * @returns {DuelEntity[]} */ public async getAllDuelEntities(): Promise<DuelEntity[]> { const query: QueryDefinition = Q(DUEL_DOCTYPE) @@ -129,9 +121,7 @@ export default class DuelService { /** * Retrieve duel entities from db given the id - * * @param {string} duelId - ID of the searched duel - * @returns {DuelEntity} */ public async getDuelEntityById(duelId: string): Promise<DuelEntity> { const query: QueryDefinition = Q(DUEL_DOCTYPE) @@ -158,7 +148,7 @@ export default class DuelService { const errorMessage = `deleteAllDuelEntities:${JSON.stringify(error)}` logStack('error', errorMessage) logApp.error(errorMessage) - Sentry.captureException(errorMessage) + Sentry.captureException(error) throw error } } @@ -166,7 +156,6 @@ export default class DuelService { /** * Return duel with updated state to UserDuelState.UNLOCKED * @param {UserDuel} userDuel - userDuel to unlock - * @returns {UserDuel} */ public async unlockUserDuel(userDuel: UserDuel): Promise<UserDuel> { const updatedUserDuel: UserDuel = { @@ -189,9 +178,8 @@ export default class DuelService { } /** - * Return duel with updated thrshold and fluidTypes + * Return duel with updated threshold and fluidTypes * @param {UserDuel} userDuel - userDuel to update - * @returns {UserDuel} */ public async updateUserDuelThreshold( userDuel: UserDuel, @@ -243,7 +231,6 @@ export default class DuelService { /** * Return duel with updated state to UserDuelState.ONGOING and startDate * @param {UserDuel} userDuel - userDuel to update - * @returns {UserDuel} */ public async startUserDuel(userDuel: UserDuel): Promise<UserDuel> { const updatedUserDuel: UserDuel = { @@ -259,7 +246,6 @@ export default class DuelService { /** * Return duel with updated state to UserDuelState.DONE * @param {UserDuel} userDuel - userDuel to update - * @returns {UserDuel} */ public async endUserDuel(userDuel: UserDuel): Promise<UserDuel> { const updatedUserDuel: UserDuel = { @@ -269,10 +255,23 @@ export default class DuelService { return updatedUserDuel } + /** + * Return duel with updated state to UserDuelState.UNLOCKED + * @param {UserDuel} userDuel - userDuel to reset + */ + public async resetUserDuel(userDuel: UserDuel): Promise<UserDuel> { + return { + ...userDuel, + startDate: null, + state: UserDuelState.UNLOCKED, + threshold: 0, + userConsumption: 0, + } + } + /** * Return duel created from duel entity * @param {DuelEntity} duel - userDuel to update - * @returns {Duel} */ public parseDuelEntityToDuel(duel: DuelEntity): UserDuel { const userDuel: UserDuel = { @@ -293,7 +292,6 @@ export default class DuelService { * Return duel created from duel entity * @param {DuelEntity[]} duelEntityList - userDuel to update * @param {string} searchId - userDuel to update - * @returns {UserDuel} */ public getDuelfromDuelEntities( duelEntityList: DuelEntity[], diff --git a/src/services/ecogesture.service.spec.ts b/src/services/ecogesture.service.spec.ts index 6e9ebd93f17f1d72c99f4819b3739a9bb68a17d5..a249083d9be48b35dcfc48ea6bae4b039a80249a 100644 --- a/src/services/ecogesture.service.spec.ts +++ b/src/services/ecogesture.service.spec.ts @@ -1,19 +1,19 @@ import { QueryResult } from 'cozy-client' import ecogestureData from 'db/ecogestureData.json' -import { EquipmentType } from 'enum/ecogesture.enum' -import { IndividualOrCollective, WarmingType } from 'enum/profileType.enum' +import { EquipmentType, IndividualOrCollective, WarmingType } from 'enums' import { Ecogesture } from 'models' import { ProfileEcogesture } from 'models/profileEcogesture.model' -import { hashFile } from 'utils/hash' -import mockClient from '../../tests/__mocks__/client' +import mockClient from 'tests/__mocks__/client.mock' import { BoilerEcogesture, BoilerEcogestureFalse, ecogesturesECSData, ecogesturesHeatingData, mockedEcogesturesData, -} from '../../tests/__mocks__/ecogesturesData.mock' -import { mockProfileEcogesture } from '../../tests/__mocks__/profileEcogesture.mock' +} from 'tests/__mocks__/ecogesturesData.mock' +import { mockProfileEcogesture } from 'tests/__mocks__/profileEcogesture.mock' +import { getError } from 'tests/__mocks__/testUtils' +import { hashFile } from 'utils/hash' import EcogestureService from './ecogesture.service' // Add types definition to json data @@ -59,7 +59,7 @@ describe('Ecogesture service', () => { it('should return true when 3 ecogestures stored', async () => { mockClient.query.mockResolvedValueOnce(mockQueryResultMockedEcogestures) const result = await ecogestureService.deleteAllEcogestures() - expect(mockClient.destroy).toBeCalledTimes(3) + expect(mockClient.destroy).toHaveBeenCalledTimes(3) expect(result).toBe(true) }) it('should return true when no ecogestures stored', async () => { @@ -79,7 +79,7 @@ describe('Ecogesture service', () => { it('should return true when 3 ecogestures stored', async () => { mockClient.query.mockResolvedValueOnce(mockQueryResultMockedEcogestures) const result = await ecogestureService.reinitAllEcogestures() - expect(mockClient.save).toBeCalledTimes(3) + expect(mockClient.save).toHaveBeenCalledTimes(3) expect(result).toBe(true) }) it('should return true when no ecogestures stored', async () => { @@ -304,7 +304,10 @@ describe('Ecogesture service', () => { .spyOn(ecogestureService, 'deleteAllEcogestures') .mockResolvedValue(true) mockClient.create.mockRejectedValueOnce(new Error()) - expect(ecogestureService.initEcogesture('')).rejects.toThrow(new Error()) + const error = await getError(async () => + ecogestureService.initEcogesture('') + ) + expect(error).toEqual(new Error()) }) }) }) diff --git a/src/services/ecogesture.service.ts b/src/services/ecogesture.service.ts index 0420aa5094fe95e39671618f3433766c7a17b709..4f56d58fdfa0a4052b71d124bb97f3c75621cb9a 100644 --- a/src/services/ecogesture.service.ts +++ b/src/services/ecogesture.service.ts @@ -3,12 +3,15 @@ import { Client, Q, QueryDefinition, QueryResult } from 'cozy-client' import logger from 'cozy-logger' import ecogestureData from 'db/ecogestureData.json' import { ECOGESTURE_DOCTYPE } from 'doctypes' -import { Season, Usage } from 'enum/ecogesture.enum' -import { FluidType } from 'enum/fluid.enum' -import { IndividualOrCollective, WarmingType } from 'enum/profileType.enum' +import { + FluidType, + IndividualOrCollective, + Season, + Usage, + WarmingType, +} from 'enums' import { orderBy } from 'lodash' -import { Ecogesture } from 'models' -import { ProfileEcogesture } from 'models/profileEcogesture.model' +import { Ecogesture, ProfileEcogesture } from 'models' import { logDuration } from 'utils/duration' import { hashFile } from 'utils/hash' import logApp from 'utils/logger' @@ -59,7 +62,7 @@ export default class EcogestureService { )}` logStack('error', errorMessage) logApp.error(errorMessage) - Sentry.captureException(errorMessage) + Sentry.captureException(error) throw error } } @@ -99,7 +102,7 @@ export default class EcogestureService { )}` logStack('error', errorMessage) logApp.error(errorMessage) - Sentry.captureException(errorMessage) + Sentry.captureException(error) throw error } } else { @@ -153,7 +156,6 @@ export default class EcogestureService { /** * @param {string} ids - ecogestures ids - * @returns {Promise<Ecogesture[]>} */ public async getEcogesturesByIds(ids: string[]): Promise<Ecogesture[]> { const query: QueryDefinition = Q(ECOGESTURE_DOCTYPE).getByIds(ids) @@ -175,7 +177,7 @@ export default class EcogestureService { )}` logStack('error', errorMessage) logApp.error(errorMessage) - Sentry.captureException(errorMessage) + Sentry.captureException(error) throw error } } @@ -198,16 +200,13 @@ export default class EcogestureService { )}` logStack('error', errorMessage) logApp.error(errorMessage) - Sentry.captureException(errorMessage) + Sentry.captureException(error) throw error } } /** * Removes ecogestures from the list that doesn't fit with user's usages - * @param {Ecogesture[]} ecogestureList - * @param {ProfileEcogesture} profileEcogesture - * @returns {Ecogesture[]} */ public filterByUsage( ecogestureList: Ecogesture[], @@ -248,9 +247,6 @@ export default class EcogestureService { /** * Removes ecogesture from the list that depends on equipment the user hasn't - * @param {Ecogesture[]} ecogestureList - * @param {ProfileEcogesture} profileEcogesture - * @returns {Ecogesture[]} */ public filterByEquipment( ecogestureList: Ecogesture[], @@ -271,8 +267,6 @@ export default class EcogestureService { /** * Return a filtered list according to ecogesture profile, the list is sorted by low difficulty and high efficiency - * @param {ProfileEcogesture} profileEcogesture - * @returns {Ecogesture[]} */ public async getEcogestureListByProfile( profileEcogesture: ProfileEcogesture diff --git a/src/services/enedisMonthlyAnalysisData.service.spec.ts b/src/services/enedisMonthlyAnalysisData.service.spec.ts index 3a5f15f44a8073bea2069c245bc55eae6f91d0a1..fd72985c39bc3781c9645494dfe27fb7d44840d8 100644 --- a/src/services/enedisMonthlyAnalysisData.service.spec.ts +++ b/src/services/enedisMonthlyAnalysisData.service.spec.ts @@ -1,13 +1,13 @@ import { QueryResult } from 'cozy-client' import { EnedisMonthlyAnalysisData } from 'models/enedisMonthlyAnalysis' import { MaxPowerEntity } from 'models/maxPower.model' -import mockClient from '../../tests/__mocks__/client' +import mockClient from 'tests/__mocks__/client.mock' import { maxPowerData, mockDataLoadEnedisAnalysis, mockEnedisMonthlyAnalysis, mockEnedisMonthlyAnalysisArray, -} from '../../tests/__mocks__/enedisMonthlyAnalysisData.mock' +} from 'tests/__mocks__/enedisMonthlyAnalysisData.mock' import EnedisMonthlyAnalysisDataService from './enedisMonthlyAnalysisData.service' describe('Enedis Monthly Analysis service', () => { diff --git a/src/services/enedisMonthlyAnalysisData.service.ts b/src/services/enedisMonthlyAnalysisData.service.ts index 0eff9590f3fb55bb6819be5b1e2624a3aa36e0e6..a46ff453c9abb88f3f1b82dfac789e3d258ee991 100644 --- a/src/services/enedisMonthlyAnalysisData.service.ts +++ b/src/services/enedisMonthlyAnalysisData.service.ts @@ -5,14 +5,13 @@ import { ENEDIS_MAXPOWER_DOCTYPE, ENEDIS_MONTHLY_ANALYSIS_DATA_DOCTYPE, } from 'doctypes' -import { DataloadState } from 'enum/dataload.enum' +import { DataloadState } from 'enums' import { DateTime } from 'luxon' -import { Dataload } from 'models' +import { Dataload, MaxPowerEntity } from 'models' import { AggregatedEnedisMonthlyDataloads, EnedisMonthlyAnalysisData, } from 'models/enedisMonthlyAnalysis' -import { MaxPowerEntity } from 'models/maxPower.model' import logApp from 'utils/logger' const logStack = logger.namespace('enedisMonthlyAnalysisDataService') @@ -25,7 +24,6 @@ export default class EnedisMonthlyAnalysisDataService { /** * Retrieve all exploration entities from db - * @returns {EnedisMonthlyAnalysisData[]} */ public async getAllEnedisMonthlyAnalysisData(): Promise< EnedisMonthlyAnalysisData[] @@ -41,8 +39,6 @@ export default class EnedisMonthlyAnalysisDataService { /** * getLastEnedisMonthlyAnalysis - * @param {Client} client - * @returns {Promise<EnedisMonthlyAnalysisData[]>} */ public async getLastEnedisMonthlyAnalysis(): Promise< EnedisMonthlyAnalysisData[] @@ -58,8 +54,6 @@ export default class EnedisMonthlyAnalysisDataService { /** * Aggregates Enedis Analysis data in order to create Dataload injectable in graph component - * @param {EnedisMonthlyAnalysisData} data - * @returns {AggregatedEnedisMonthlyDataloads} */ public aggregateValuesToDataLoad = ( data: EnedisMonthlyAnalysisData @@ -106,9 +100,6 @@ export default class EnedisMonthlyAnalysisDataService { /** * Get an enedis monthly analysis for given month and year - * @param {number} year - * @param {number} month - * @returns {Promise<EnedisMonthlyAnalysisData[]>} */ public async getEnedisMonthlyAnalysisByDate( year: number, @@ -126,8 +117,6 @@ export default class EnedisMonthlyAnalysisDataService { /** * Creates a new EnedisMonthlyAnalysis - * @param {EnedisMonthlyAnalysisData} newEnedisMonthlyAnalysisData - * @returns {Promise<EnedisMonthlyAnalysisData | null>} */ public async createEnedisMonthlyAnalysisData( newEnedisMonthlyAnalysisData: EnedisMonthlyAnalysisData @@ -146,16 +135,13 @@ export default class EnedisMonthlyAnalysisDataService { )}` logStack('error', errorMessage) logApp.error(errorMessage) - Sentry.captureException(errorMessage) + Sentry.captureException(error) throw error } } /** * Get Max power for a given month and year - * @param {number} year - * @param {number} month - * @returns {Promise<MaxPowerEntity[]>} */ public async getMaxPowerByDate( year: number, diff --git a/src/services/exploration.service.spec.ts b/src/services/exploration.service.spec.ts index d6d1b092aa5e52e98f304c7a279a84eac882b547..ebd9e8870624f574f962052d5f04bc10eda6aeea 100644 --- a/src/services/exploration.service.spec.ts +++ b/src/services/exploration.service.spec.ts @@ -1,18 +1,19 @@ import { QueryResult } from 'cozy-client' -import { UserExplorationState } from 'enum/userExploration.enum' +import { UserExplorationState } from 'enums' import { ExplorationEntity, UserChallenge, UserExploration } from 'models' -import mockClient from '../../tests/__mocks__/client' +import mockClient from 'tests/__mocks__/client.mock' import { allExplorationEntities, explorationEntity, userExplorationDone, userExplorationStarted, userExplorationUnlocked, -} from '../../tests/__mocks__/explorationData.mock' +} from 'tests/__mocks__/explorationData.mock' +import { getError } from 'tests/__mocks__/testUtils' import { userChallengeExplo1OnGoing, userChallengeExplo2OnGoing, -} from '../../tests/__mocks__/userChallengeData.mock' +} from 'tests/__mocks__/userChallengeData.mock' import ExplorationService from './exploration.service' describe('Exploration service', () => { @@ -72,11 +73,10 @@ describe('Exploration service', () => { } mockClient.query.mockResolvedValueOnce(mockQueryResult) mockClient.destroy.mockRejectedValue(new Error()) - try { - await explorationService.deleteAllExplorationEntities() - } catch (error) { - expect(error).toEqual(new Error()) - } + const error = await getError(async () => + explorationService.deleteAllExplorationEntities() + ) + expect(error).toEqual(new Error()) }) }) diff --git a/src/services/exploration.service.ts b/src/services/exploration.service.ts index 8a4db83a644ba04a881fe6fe91a7d6bc66e5dddb..605b9f54cb09d1db617559d8650d09b55321274d 100644 --- a/src/services/exploration.service.ts +++ b/src/services/exploration.service.ts @@ -1,11 +1,11 @@ import { Client, Q, QueryDefinition, QueryResult } from 'cozy-client' import { EXPLORATION_DOCTYPE } from 'doctypes' -import { UserChallengeUpdateFlag } from 'enum/userChallenge.enum' import { + UserChallengeUpdateFlag, UserExplorationID, UserExplorationState, UserExplorationType, -} from 'enum/userExploration.enum' +} from 'enums' import { DateTime } from 'luxon' import { ExplorationEntity, UserChallenge, UserExploration } from 'models' import ChallengeService from './challenge.service' @@ -19,7 +19,6 @@ export default class ExplorationService { /** * Retrieve all exploration entities from db - * @returns {ExplorationEntity[]} */ public async getAllExplorationEntities(): Promise<ExplorationEntity[]> { const query: QueryDefinition = Q(EXPLORATION_DOCTYPE) @@ -30,9 +29,7 @@ export default class ExplorationService { /** * Retrieve exploration entities from db given the id - * * @param {string} explorationId - ID of the searched exploration - * @returns {ExplorationEntity} */ public async getExplorationEntityById( explorationId: string @@ -65,7 +62,6 @@ export default class ExplorationService { * Return exploration created from exploration entity * @param {ExplorationEntity[]} explorationEntityList - userExploration to update * @param {string} searchId - userExploration to update - * @returns {UserExploration} */ public getUserExplorationfromExplorationEntities( explorationEntityList: ExplorationEntity[], @@ -102,8 +98,6 @@ export default class ExplorationService { /** * Return UserExploration created from ExplorationEntity - * @param {ExplorationEntity} - * @returns {UserExploration} */ public parseExplorationEntityToUserExploration( exploration: ExplorationEntity @@ -121,7 +115,6 @@ export default class ExplorationService { /** * Return exploration with updated state to UserExplorationState.ONGOING * @param {UserExploration} userExploration - userExploration to update - * @returns {UserExploration} */ public async startUserExploration( userExploration: UserExploration @@ -136,7 +129,6 @@ export default class ExplorationService { /** * Return exploration with updated state to UserExplorationState.NOTIFICATION * @param {UserExploration} userExploration - userExploration to update - * @returns {UserExploration} */ public async awaitNotificationUserExploration( userExploration: UserExploration @@ -151,7 +143,6 @@ export default class ExplorationService { /** * Return exploration with updated state to UserExplorationState.DONE * @param {UserExploration} userExploration - userExploration to update - * @returns {UserExploration} */ public endUserExploration(userExploration: UserExploration): UserExploration { const updatedUserExploration: UserExploration = { @@ -165,9 +156,6 @@ export default class ExplorationService { /** * Return updated exploration * @param {UserExploration} userExploration - userExploration to update - * @returns {UserExploration} - * @returns {questionIndex} - * @returns {questionResult} */ public async updateUserExploration( userExploration: UserExploration @@ -185,7 +173,6 @@ export default class ExplorationService { * Return updated UserChallenge with updated UserExploration * @param {UserChallenge} currentChallenge - currentUserChallenge ongoing * @param {string} explorationID - Id of the exploration - * @returns {UserChallenge} */ public async checkExploration( currentChallenge: UserChallenge, diff --git a/src/services/fluid.service.spec.ts b/src/services/fluid.service.spec.ts index 53fe0add5056faf5b87e9eb36e8afbce5d40bf2b..fd3878c55a1cc99c81652e2c3bead30182c10de4 100644 --- a/src/services/fluid.service.spec.ts +++ b/src/services/fluid.service.spec.ts @@ -1,53 +1,44 @@ /* eslint-disable camelcase */ -import { FluidState, FluidType } from 'enum/fluid.enum' -import { FluidSlugType } from 'enum/fluidSlug.enum' +import { FluidSlugType, FluidState, FluidType } from 'enums' import { DateTime } from 'luxon' import { FluidStatus } from 'models' -import { accountsData } from '../../tests/__mocks__/accountsData.mock' -import mockClient from '../../tests/__mocks__/client' -import { konnectorsData } from '../../tests/__mocks__/konnectorsData.mock' -import { triggersData } from '../../tests/__mocks__/triggersData.mock' -import { triggerStateData } from '../../tests/__mocks__/triggerStateData.mock' +import { accountsData } from 'tests/__mocks__/accountsData.mock' +import mockClient from 'tests/__mocks__/client.mock' +import { konnectorsData } from 'tests/__mocks__/konnectorsData.mock' +import { triggerStateData } from 'tests/__mocks__/triggerStateData.mock' +import { triggersData } from 'tests/__mocks__/triggersData.mock' import FluidService from './fluid.service' const mockGetAccountByType = jest.fn() jest.mock('./account.service', () => { - return jest.fn(() => { - return { - getAccountByType: mockGetAccountByType, - } - }) + return jest.fn(() => ({ + getAccountByType: mockGetAccountByType, + })) }) const mockGetKonnector = jest.fn() jest.mock('./konnector.service', () => { - return jest.fn(() => { - return { - getKonnector: mockGetKonnector, - } - }) + return jest.fn(() => ({ + getKonnector: mockGetKonnector, + })) }) const mockGetTrigger = jest.fn() const mockFetchTriggerState = jest.fn() jest.mock('./triggers.service', () => { - return jest.fn(() => { - return { - getTrigger: mockGetTrigger, - fetchTriggerState: mockFetchTriggerState, - } - }) + return jest.fn(() => ({ + getTrigger: mockGetTrigger, + fetchTriggerState: mockFetchTriggerState, + })) }) const mockFetchAllFirstDateData = jest.fn() const mockFetchAllLastDateData = jest.fn() jest.mock('./consumption.service', () => { - return jest.fn(() => { - return { - fetchAllFirstDateData: mockFetchAllFirstDateData, - fetchAllLastDateData: mockFetchAllLastDateData, - } - }) + return jest.fn(() => ({ + fetchAllFirstDateData: mockFetchAllFirstDateData, + fetchAllLastDateData: mockFetchAllLastDateData, + })) }) const mockDataDates: (DateTime | null)[] = [ diff --git a/src/services/fluid.service.ts b/src/services/fluid.service.ts index 3de8f5c45b2851602969df86e00dca3571419be4..a25af857cd7ba141a30710ad61771d68587551f3 100644 --- a/src/services/fluid.service.ts +++ b/src/services/fluid.service.ts @@ -1,8 +1,14 @@ import { Client } from 'cozy-client' -import { FluidState, FluidType } from 'enum/fluid.enum' +import { FluidState, FluidType } from 'enums' import { DateTime } from 'luxon' -import { Account, FluidStatus, Konnector, Trigger, TriggerState } from 'models' -import { PartnersInfo } from 'models/partnersInfo.model' +import { + Account, + FluidStatus, + Konnector, + PartnersInfo, + Trigger, + TriggerState, +} from 'models' import AccountService from 'services/account.service' import ConsumptionService from 'services/consumption.service' import ConfigService from 'services/fluidConfig.service' @@ -171,8 +177,6 @@ export default class FluidService { /** * Return fluids with data older than 5 days - * @param {FluidStatus[]} fluidStatus - * @returns {FluidType[]} */ static getOldFluidData = async ( fluidStatus: FluidStatus[] diff --git a/src/services/fluidsPrices.service.spec.ts b/src/services/fluidsPrices.service.spec.ts index f83929e3bd6e2636351cb916845d7734d5ba316d..a25157e4ca9c2d55fa9a3eefc442c15418e9dc30 100644 --- a/src/services/fluidsPrices.service.spec.ts +++ b/src/services/fluidsPrices.service.spec.ts @@ -1,12 +1,13 @@ import { QueryResult } from 'cozy-client' -import { FluidType } from 'enum/fluid.enum' +import { FluidType } from 'enums' import { DateTime } from 'luxon' import { FluidPrice } from 'models' -import mockClient from '../../tests/__mocks__/client' +import mockClient from 'tests/__mocks__/client.mock' import { allLastFluidPrices, fluidPrices, -} from '../../tests/__mocks__/fluidPrice.mock' +} from 'tests/__mocks__/fluidPrice.mock' +import { getError } from 'tests/__mocks__/testUtils' import FluidPricesService from './fluidsPrices.service' describe('FluidPrices service', () => { @@ -23,7 +24,7 @@ describe('FluidPrices service', () => { mockClient.query.mockResolvedValueOnce(mockQueryResult) const prices = await fluidPricesService.getAllPrices() expect(prices).toBe(fluidPrices) - expect(mockClient.query).toBeCalled() + expect(mockClient.query).toHaveBeenCalled() }) }) @@ -43,7 +44,7 @@ describe('FluidPrices service', () => { }) ) expect(prices).toBe(fluidPrices[0]) - expect(mockClient.query).toBeCalled() + expect(mockClient.query).toHaveBeenCalled() }) it('should getPrices for gas', async () => { const mockQueryResult: QueryResult<FluidPrice[]> = { @@ -60,7 +61,7 @@ describe('FluidPrices service', () => { }) ) expect(prices).toBe(fluidPrices[3]) - expect(mockClient.query).toBeCalled() + expect(mockClient.query).toHaveBeenCalled() }) }) @@ -77,7 +78,7 @@ describe('FluidPrices service', () => { console.log('Prix reçus :', prices) console.log('Prix attendus :', allLastFluidPrices) expect(prices).toStrictEqual(allLastFluidPrices) - expect(mockClient.query).toBeCalled() + expect(mockClient.query).toHaveBeenCalled() }) }) @@ -91,7 +92,7 @@ describe('FluidPrices service', () => { } mockClient.query.mockResolvedValueOnce(mockQueryResult) const result = await fluidPricesService.deleteAllFluidsPrices() - expect(mockClient.destroy).toBeCalledTimes(6) + expect(mockClient.destroy).toHaveBeenCalledTimes(6) expect(result).toBe(true) }) it('should return true when no fluidsPrices stored', async () => { @@ -128,7 +129,7 @@ describe('FluidPrices service', () => { mockClient.query.mockResolvedValueOnce(mockQueryResult) const price = await fluidPricesService.checkIfPriceExists(fluidPrices[0]) expect(price).toStrictEqual(fluidPrices[0]) - expect(mockClient.query).toBeCalled() + expect(mockClient.query).toHaveBeenCalled() }) it('should create a price and return it', async () => { const mockQueryResult: QueryResult<FluidPrice> = { @@ -143,11 +144,10 @@ describe('FluidPrices service', () => { }) it('should fail to create a price', async () => { mockClient.create.mockRejectedValue(new Error()) - try { - await fluidPricesService.createPrice(fluidPrices[0]) - } catch (error) { - expect(error).toEqual(new Error()) - } + const error = await getError( + async () => await fluidPricesService.createPrice(fluidPrices[0]) + ) + expect(error).toEqual(new Error()) }) it('should update a price', async () => { const updatedPrice = { ...fluidPrices[0], price: 0.1 } @@ -162,16 +162,15 @@ describe('FluidPrices service', () => { price: 0.1, }) expect(price).toStrictEqual(updatedPrice) - expect(mockClient.query).toBeCalled() + expect(mockClient.query).toHaveBeenCalled() }) it('should fail to update a price', async () => { mockClient.save.mockRejectedValue(new Error()) - try { - await fluidPricesService.updatePrice(fluidPrices[0], { + const error = await getError(async () => + fluidPricesService.updatePrice(fluidPrices[0], { price: 0.1, }) - } catch (error) { - expect(error).toEqual(new Error()) - } + ) + expect(error).toEqual(new Error()) }) }) diff --git a/src/services/fluidsPrices.service.ts b/src/services/fluidsPrices.service.ts index 7ea8c8fb3e3e072a5d7e5ae21de0a2c5ca4f47c9..6eb9945c490cec11c5684dab446a28d13c43d6ee 100644 --- a/src/services/fluidsPrices.service.ts +++ b/src/services/fluidsPrices.service.ts @@ -2,7 +2,7 @@ import * as Sentry from '@sentry/react' import { Client, Q, QueryDefinition, QueryResult } from 'cozy-client' import logger from 'cozy-logger' import { FLUIDSPRICES_DOCTYPE } from 'doctypes' -import { FluidType } from 'enum/fluid.enum' +import { FluidType } from 'enums' import { DateTime } from 'luxon' import { FluidPrice } from 'models' import logApp from 'utils/logger' @@ -19,7 +19,6 @@ export default class FluidPricesService { /** * Get all prices available in database - * @returns {FluidPrice[]} */ public async getAllPrices(): Promise<FluidPrice[]> { const query: QueryDefinition = Q(FLUIDSPRICES_DOCTYPE).limitBy(900) @@ -31,9 +30,6 @@ export default class FluidPricesService { /** * Get a price according to a fluidType and a data. This method return the nearest and valid price for the given date. - * @param {FluidType} fluidType - * @param {DateTime} date - * @returns {FluidPrice} */ public async getPrices( fluidType: FluidType, @@ -57,7 +53,6 @@ export default class FluidPricesService { /** * Get current prices for all fluidTypes. - * @returns {FluidPrice[]} */ public async getAllLastPrices(): Promise<FluidPrice[]> { const query: QueryDefinition = Q(FLUIDSPRICES_DOCTYPE) @@ -113,15 +108,14 @@ export default class FluidPricesService { const errorMessage = `deleteAllFluidsPrices: ${JSON.stringify(error)}` logStack('error', errorMessage) logApp.error(errorMessage) - Sentry.captureException(errorMessage) + Sentry.captureException(error) return false } } /** * Check if a fluidprice exists in db - * @param {FluidPrice} fluidPrice - * @returns {FluidPrice | null} price or null + * @returns {Promise<FluidPrice | null>} price or null */ public async checkIfPriceExists( fluidPrice: FluidPrice @@ -139,8 +133,7 @@ export default class FluidPricesService { /** * Creates a new fluidPrice - * @param {FluidPrice} fluidPrice - * @returns {FluidPrice | null} price or null + * @returns {Promise<FluidPrice | null>} price or null */ public async createPrice(newPrice: FluidPrice): Promise<FluidPrice | null> { try { @@ -153,16 +146,13 @@ export default class FluidPricesService { )}` logStack('error', errorMessage) logApp.error(errorMessage) - Sentry.captureException(errorMessage) + Sentry.captureException(error) throw error } } /** * Updates a price in db - * @param {FluidPrice} doc - * @param {Partial<FluidPrice>} attributes - * @returns {FluidPrice | null} */ public async updatePrice( doc: FluidPrice, diff --git a/src/services/initialization.service.spec.ts b/src/services/initialization.service.spec.ts index e6fdcf3387d36d36428ee2880e188d9911f75113..ca938be0ebeec56c08baff1e0f74c6f9516b4f7d 100644 --- a/src/services/initialization.service.spec.ts +++ b/src/services/initialization.service.spec.ts @@ -3,54 +3,47 @@ import challengeEntityData from 'db/challengeEntity.json' import duelEntityData from 'db/duelEntity.json' import explorationEntityData from 'db/explorationEntity.json' import quizEntityData from 'db/quizEntity.json' -import { FluidType } from 'enum/fluid.enum' +import { FluidType } from 'enums' import { DateTime } from 'luxon' -import { UserChallenge } from 'models' -import { getActualAnalysisDate } from 'utils/date' -import { hashFile } from 'utils/hash' -import { allChallengeEntityData } from '../../tests/__mocks__/challengeEntity.mock' -import { graphData } from '../../tests/__mocks__/chartData.mock' -import mockClient from '../../tests/__mocks__/client' -import { allDuelEntity } from '../../tests/__mocks__/duelData.mock' -import { allExplorationEntities } from '../../tests/__mocks__/explorationData.mock' -import { fluidPrices } from '../../tests/__mocks__/fluidPrice.mock' -import { fluidStatusData } from '../../tests/__mocks__/fluidStatusData.mock' -import { profileData } from '../../tests/__mocks__/profileData.mock' -import { allQuizEntities } from '../../tests/__mocks__/quizData.mock' +import { Profile, Trigger, UserChallenge } from 'models' +import { allChallengeEntityData } from 'tests/__mocks__/challengeEntity.mock' +import { graphData } from 'tests/__mocks__/chartData.mock' +import mockClient from 'tests/__mocks__/client.mock' +import { allDuelEntity } from 'tests/__mocks__/duelData.mock' +import { allExplorationEntities } from 'tests/__mocks__/explorationData.mock' +import { fluidStatusData } from 'tests/__mocks__/fluidStatusData.mock' +import { allQuizEntities } from 'tests/__mocks__/quizData.mock' +import { mockProfileState } from 'tests/__mocks__/store' import { mockOutdatedTerm, mockUpToDateTerm, -} from '../../tests/__mocks__/termsData.mock' -import { userChallengeData } from '../../tests/__mocks__/userChallengeData.mock' +} from 'tests/__mocks__/termsData.mock' +import { userChallengeData } from 'tests/__mocks__/userChallengeData.mock' +import { getActualAnalysisDate } from 'utils/date' +import { hashFile } from 'utils/hash' import InitializationService from './initialization.service' const mockCreateIndexKonnector = jest.fn() jest.mock('./konnector.service', () => { - return jest.fn(() => { - return { - createIndexKonnector: mockCreateIndexKonnector, - } - }) + return jest.fn(() => ({ + createIndexKonnector: mockCreateIndexKonnector, + })) }) const mockCreateIndexAccount = jest.fn() jest.mock('./account.service', () => { - return jest.fn(() => { - return { - createIndexAccount: mockCreateIndexAccount, - } - }) + return jest.fn(() => ({ + createIndexAccount: mockCreateIndexAccount, + })) }) const mockGetProfile = jest.fn() const mockUpdateProfile = jest.fn() jest.mock('./profile.service', () => { - return jest.fn(() => { - return { - getProfile: mockGetProfile, - updateProfile: mockUpdateProfile, - } - }) + return jest.fn(() => ({ + getProfile: mockGetProfile, + updateProfile: mockUpdateProfile, + })) }) const mockGetAllChallengeEntities = jest.fn() @@ -60,78 +53,64 @@ const mockGetUserChallengeDataload = jest.fn() const mockUserChallengeUpdateFlag = jest.fn() const mockInitChallengeDuelProgress = jest.fn() jest.mock('./challenge.service', () => { - return jest.fn(() => { - return { - getAllChallengeEntities: mockGetAllChallengeEntities, - deleteAllChallengeEntities: mockDeleteAllChallengeEntities, - buildUserChallengeList: mockBuildUserChallengeList, - getUserChallengeDataload: mockGetUserChallengeDataload, - updateUserChallenge: mockUserChallengeUpdateFlag, - initChallengeDuelProgress: mockInitChallengeDuelProgress, - } - }) + return jest.fn(() => ({ + getAllChallengeEntities: mockGetAllChallengeEntities, + deleteAllChallengeEntities: mockDeleteAllChallengeEntities, + buildUserChallengeList: mockBuildUserChallengeList, + getUserChallengeDataload: mockGetUserChallengeDataload, + updateUserChallenge: mockUserChallengeUpdateFlag, + initChallengeDuelProgress: mockInitChallengeDuelProgress, + })) }) const mockGetAllPrices = jest.fn() const mockDeleteAllFluidsPrices = jest.fn() jest.mock('./fluidsPrices.service', () => { - return jest.fn(() => { - return { - getAllPrices: mockGetAllPrices, - deleteAllFluidsPrices: mockDeleteAllFluidsPrices, - } - }) + return jest.fn(() => ({ + getAllPrices: mockGetAllPrices, + deleteAllFluidsPrices: mockDeleteAllFluidsPrices, + })) }) const mockGetAllDuelEntities = jest.fn() const mockDeleteAllDuelEntities = jest.fn() jest.mock('./duel.service', () => { - return jest.fn(() => { - return { - getAllDuelEntities: mockGetAllDuelEntities, - deleteAllDuelEntities: mockDeleteAllDuelEntities, - } - }) + return jest.fn(() => ({ + getAllDuelEntities: mockGetAllDuelEntities, + deleteAllDuelEntities: mockDeleteAllDuelEntities, + })) }) const mockGetAllQuizEntities = jest.fn() const mockDeleteAllQuizEntities = jest.fn() jest.mock('./quiz.service', () => { - return jest.fn(() => { - return { - getAllQuizEntities: mockGetAllQuizEntities, - deleteAllQuizEntities: mockDeleteAllQuizEntities, - } - }) + return jest.fn(() => ({ + getAllQuizEntities: mockGetAllQuizEntities, + deleteAllQuizEntities: mockDeleteAllQuizEntities, + })) }) const mockGetAllExplorationEntities = jest.fn() const mockDeleteAllExplorationEntities = jest.fn() jest.mock('./exploration.service', () => { - return jest.fn(() => { - return { - getAllExplorationEntities: mockGetAllExplorationEntities, - deleteAllExplorationEntities: mockDeleteAllExplorationEntities, - } - }) + return jest.fn(() => ({ + getAllExplorationEntities: mockGetAllExplorationEntities, + deleteAllExplorationEntities: mockDeleteAllExplorationEntities, + })) }) const mockGetKonnectorAccountStatus = jest.fn() jest.mock('./konnectorStatus.service', () => { - return jest.fn(() => { - return { - getKonnectorAccountStatus: mockGetKonnectorAccountStatus, - } - }) + return jest.fn(() => ({ + getKonnectorAccountStatus: mockGetKonnectorAccountStatus, + })) }) const mockGetFluidStatus = jest.fn() jest.mock('./fluid.service', () => { - return jest.fn(() => { - return { - getFluidStatus: mockGetFluidStatus, - } - }) + return jest.fn(() => ({ + getFluidStatus: mockGetFluidStatus, + })) }) const mockIsConsentVersionUpToDate = jest.fn() @@ -139,14 +118,12 @@ const mockIsLastTermValidated = jest.fn() const mockGetTermsVersionType = jest.fn() const mockGetLastTerm = jest.fn() jest.mock('./terms.service', () => { - return jest.fn(() => { - return { - isConsentVersionUpToDate: mockIsConsentVersionUpToDate, - isLastTermValidated: mockIsLastTermValidated, - getTermsVersionType: mockGetTermsVersionType, - getLastTerm: mockGetLastTerm, - } - }) + return jest.fn(() => ({ + isConsentVersionUpToDate: mockIsConsentVersionUpToDate, + isLastTermValidated: mockIsLastTermValidated, + getTermsVersionType: mockGetTermsVersionType, + getLastTerm: mockGetLastTerm, + })) }) describe('Initialization service', () => { @@ -156,20 +133,15 @@ describe('Initialization service', () => { jest.fn() ) beforeEach(() => { - mockClient.query.mockClear() - mockClient.create.mockClear() + jest.clearAllMocks() }) describe('initProfile method', () => { - beforeEach(() => { - mockGetProfile.mockClear() - mockUpdateProfile.mockClear() - }) it('should return the profil when existing', async () => { - mockGetProfile.mockResolvedValueOnce(profileData) - mockUpdateProfile.mockResolvedValueOnce(profileData) + mockGetProfile.mockResolvedValueOnce(mockProfileState) + mockUpdateProfile.mockResolvedValueOnce(mockProfileState) await expect(initializationService.initProfile()).resolves.toEqual( - profileData + mockProfileState ) }) it('should create and return the profil when no existing', async () => { @@ -181,9 +153,9 @@ describe('Initialization service', () => { } mockGetProfile.mockResolvedValueOnce(null) mockClient.create.mockResolvedValueOnce(mockQueryResult) - mockUpdateProfile.mockResolvedValueOnce(profileData) + mockUpdateProfile.mockResolvedValueOnce(mockProfileState) await expect(initializationService.initProfile()).resolves.toEqual( - profileData + mockProfileState ) }) it('should throw error when the profile is not created', async () => { @@ -199,38 +171,54 @@ describe('Initialization service', () => { new Error('initProfile: Profile not created') ) }) - it('should throw error when the profile could not be fetched', () => { + it('should throw error when the profile could not be fetched', async () => { mockGetProfile.mockRejectedValueOnce(new Error()) - expect(initializationService.initProfile()).rejects.toEqual(new Error()) + await expect(initializationService.initProfile()).rejects.toEqual( + new Error() + ) }) - it('should throw error when the profile failed to be created', () => { + it('should throw error when the profile failed to be created', async () => { mockGetProfile.mockResolvedValueOnce(null) mockClient.create.mockRejectedValueOnce(new Error()) - expect(initializationService.initProfile()).rejects.toEqual(new Error()) + await expect(initializationService.initProfile()).rejects.toEqual( + new Error() + ) }) }) describe('initFluidPrices method', () => { - beforeEach(() => { - mockGetAllPrices.mockClear() - mockDeleteAllFluidsPrices.mockClear() - }) - it('should do nothing because prices are already created', async () => { - mockGetAllPrices.mockResolvedValueOnce(fluidPrices) - const isDone = await initializationService.initFluidPrices() - expect(isDone).toBeTruthy() + it('should launch fluidsPrices service', async () => { + const mockQueryResult: QueryResult<Trigger[]> = { + data: [ + { + _id: 'triggerId', + type: '', + arguments: '', + message: { account: '', konnector: '' }, + worker: '', + }, + ], + bookmark: '', + next: false, + skip: 0, + } + mockClient.query.mockResolvedValueOnce(mockQueryResult) + await initializationService.initFluidPrices() + expect(mockClient.getStackClient).toHaveBeenCalledTimes(1) }) - it('should try to fetch prices from remote doctype', async () => { - mockGetAllPrices.mockResolvedValueOnce('') - const isDone = await initializationService.initFluidPrices() - expect(isDone).toBeFalsy() + it('should not launch fluidsPrices service because trigger is not found', async () => { + const mockQueryResult: QueryResult<Trigger[]> = { + data: [], + bookmark: '', + next: false, + skip: 0, + } + mockClient.query.mockResolvedValueOnce(mockQueryResult) + await initializationService.initFluidPrices() + expect(mockClient.getStackClient).toHaveBeenCalledTimes(0) }) }) describe('initChallengeEntity method', () => { - beforeEach(() => { - mockGetAllChallengeEntities.mockClear() - mockDeleteAllChallengeEntities.mockClear() - }) it('should return hash when challenges hash is already up to date', async () => { mockGetAllChallengeEntities.mockResolvedValueOnce(challengeEntityData) const hash = hashFile(challengeEntityData) @@ -322,17 +310,13 @@ describe('Initialization service', () => { .mockResolvedValueOnce(challengeEntityData) mockDeleteAllChallengeEntities.mockResolvedValue(true) mockClient.create.mockRejectedValueOnce(new Error()) - expect(initializationService.initChallengeEntity('')).rejects.toThrow( - new Error() - ) + await expect( + initializationService.initChallengeEntity('') + ).rejects.toThrow(new Error()) }) }) describe('initDuelEntity method', () => { - beforeEach(() => { - mockGetAllDuelEntities.mockClear() - mockDeleteAllDuelEntities.mockClear() - }) it('should return hash when duel hash is already up to date', async () => { mockGetAllDuelEntities.mockResolvedValueOnce(duelEntityData) const hash = hashFile(duelEntityData) @@ -418,17 +402,13 @@ describe('Initialization service', () => { .mockResolvedValueOnce(duelEntityData) mockDeleteAllDuelEntities.mockResolvedValue(true) mockClient.create.mockRejectedValueOnce(new Error()) - expect(initializationService.initDuelEntity('')).rejects.toThrow( + await expect(initializationService.initDuelEntity('')).rejects.toThrow( new Error() ) }) }) describe('initQuizEntity method', () => { - beforeEach(() => { - mockGetAllQuizEntities.mockClear() - mockDeleteAllQuizEntities.mockClear() - }) it('should return hash when quiz hash is already up to date', async () => { mockGetAllQuizEntities.mockResolvedValueOnce(quizEntityData) const hash = hashFile(quizEntityData) @@ -514,17 +494,13 @@ describe('Initialization service', () => { .mockResolvedValueOnce(quizEntityData) mockDeleteAllQuizEntities.mockResolvedValue(true) mockClient.create.mockRejectedValueOnce(new Error()) - expect(initializationService.initQuizEntity('')).rejects.toThrow( + await expect(initializationService.initQuizEntity('')).rejects.toThrow( new Error() ) }) }) describe('initExplorationEntity method', () => { - beforeEach(() => { - mockGetAllExplorationEntities.mockClear() - mockDeleteAllExplorationEntities.mockClear() - }) it('should return hash when explorations hash is already up to date', async () => { mockGetAllExplorationEntities.mockResolvedValueOnce(explorationEntityData) const hash = hashFile(explorationEntityData) @@ -620,43 +596,44 @@ describe('Initialization service', () => { .mockResolvedValueOnce(explorationEntityData) mockDeleteAllExplorationEntities.mockResolvedValue(true) mockClient.create.mockRejectedValueOnce(new Error()) - expect(initializationService.initExplorationEntity('')).rejects.toThrow( - new Error() - ) + await expect( + initializationService.initExplorationEntity('') + ).rejects.toThrow(new Error()) }) }) describe('initAnalysis method', () => { it('should return monthlyAnalysisDate and haveSeenLastAnalysis when analysis is up to date', async () => { - const mockProfile = { - ...profileData, + const profile: Profile = { + ...mockProfileState, monthlyAnalysisDate: getActualAnalysisDate(), } await expect( - initializationService.initAnalysis(mockProfile) + initializationService.initAnalysis(profile) ).resolves.toEqual({ monthlyAnalysisDate: getActualAnalysisDate(), - haveSeenLastAnalysis: mockProfile.haveSeenLastAnalysis, + haveSeenLastAnalysis: profile.haveSeenLastAnalysis, }) }) it('should return updated monthlyAnalysisDate and haveSeenLastAnalysis=true when analysis is not up to date and isFirstConnection', async () => { - const mockProfile = { - ...profileData, + const profile: Profile = { + ...mockProfileState, monthlyAnalysisDate: DateTime.fromISO('2000-10-02T00:00:00.000Z', { zone: 'utc', }), haveSeenLastAnalysis: true, + isFirstConnection: true, } await expect( - initializationService.initAnalysis(mockProfile) + initializationService.initAnalysis(profile) ).resolves.toEqual({ monthlyAnalysisDate: getActualAnalysisDate(), haveSeenLastAnalysis: true, }) }) it('should return updated monthlyAnalysisDate and haveSeenLastAnalysis=false when analysis is not up to date and isFirstConnection is false', async () => { - const mockProfile = { - ...profileData, + const profile: Profile = { + ...mockProfileState, isFirstConnection: false, monthlyAnalysisDate: DateTime.fromISO('2000-10-02T00:00:00.000Z', { zone: 'utc', @@ -664,7 +641,7 @@ describe('Initialization service', () => { haveSeenLastAnalysis: true, } await expect( - initializationService.initAnalysis(mockProfile) + initializationService.initAnalysis(profile) ).resolves.toEqual({ monthlyAnalysisDate: getActualAnalysisDate(), haveSeenLastAnalysis: false, @@ -673,9 +650,6 @@ describe('Initialization service', () => { }) describe('initFluidType method', () => { - beforeEach(() => { - mockGetKonnectorAccountStatus.mockClear() - }) it('should return all fluid types', async () => { mockGetKonnectorAccountStatus.mockResolvedValueOnce([ FluidType.ELECTRICITY, @@ -703,9 +677,6 @@ describe('Initialization service', () => { }) describe('initFluidStatus method', () => { - beforeEach(() => { - mockGetFluidStatus.mockClear() - }) it('should return all fluids type', async () => { mockGetFluidStatus.mockResolvedValueOnce(fluidStatusData) await expect(initializationService.initFluidStatus()).resolves.toEqual( @@ -727,9 +698,6 @@ describe('Initialization service', () => { }) describe('initUserChallenges method', () => { - beforeEach(() => { - mockBuildUserChallengeList.mockClear() - }) it('should return all userChallenges', async () => { mockBuildUserChallengeList.mockResolvedValueOnce(userChallengeData) await expect( @@ -753,9 +721,6 @@ describe('Initialization service', () => { }) describe('initDuelProgress method', () => { - beforeEach(() => { - mockInitChallengeDuelProgress.mockClear() - }) it('should return updatedUserChallenge and dataload', async () => { const expectedUpdatedUserChallenge: UserChallenge = { ...userChallengeData[0], diff --git a/src/services/initialization.service.ts b/src/services/initialization.service.ts index 56b3b9fc63ed91580768ce9ee827b6220868301c..1383331b40a76f3cbf4e5750e51add7d7468c60a 100644 --- a/src/services/initialization.service.ts +++ b/src/services/initialization.service.ts @@ -1,5 +1,5 @@ import * as Sentry from '@sentry/react' -import { Client } from 'cozy-client' +import { Client, Q, QueryDefinition, QueryResult } from 'cozy-client' import logger from 'cozy-logger' import challengeEntityData from 'db/challengeEntity.json' import duelEntityData from 'db/duelEntity.json' @@ -12,26 +12,24 @@ import { EXPLORATION_DOCTYPE, PROFILE_DOCTYPE, QUIZ_DOCTYPE, + TRIGGERS_DOCTYPE, } from 'doctypes' -import { - REMOTE_ORG_ECOLYO_AGENT_PRICES, - REMOTE_ORG_ECOLYO_AGENT_PRICES_REC, -} from 'doctypes/remote/org.ecolyo.agent.prices' -import { FluidType } from 'enum/fluid.enum' +import { FluidType } from 'enums' import { DateTime } from 'luxon' import { initSchemaDoctype } from 'migrations/migration' import { migrations } from 'migrations/migration.data' import { Dataload, - FluidPrice, FluidStatus, + InitSteps, + InitStepsErrors, Profile, + ProfileEcogesture, ProfileType, TermsStatus, + Trigger, UserChallenge, } from 'models' -import { InitSteps, InitStepsErrors } from 'models/initialisationSteps.model' -import { ProfileEcogesture } from 'models/profileEcogesture.model' import React from 'react' import ChallengeService from 'services/challenge.service' import DuelService from 'services/duel.service' @@ -44,8 +42,6 @@ import { getActualAnalysisDate } from 'utils/date' import { logDuration } from 'utils/duration' import { hashFile } from 'utils/hash' import logApp from 'utils/logger' -import EnvironmentService from './environment.service' -import FluidPricesService from './fluidsPrices.service' import ProfileEcogestureService from './profileEcogesture.service' import ProfileTypeEntityService from './profileTypeEntity.service' import TermsService from './terms.service' @@ -113,7 +109,7 @@ export default class InitializationService { )}` logStack('error', errorMessage) logApp.error(errorMessage) - Sentry.captureException(errorMessage) + Sentry.captureException(error) throw error } } @@ -138,7 +134,7 @@ export default class InitializationService { )}` logStack('error', errorMessage) logApp.error(errorMessage) - Sentry.captureException(errorMessage) + Sentry.captureException(error) throw error } } @@ -157,52 +153,33 @@ export default class InitializationService { )}` logStack('error', errorMessage) logApp.error(errorMessage) - Sentry.captureException(errorMessage) + Sentry.captureException(error) throw error } } - public async initFluidPrices(): Promise<boolean> { + public async initFluidPrices(): Promise<void> { const startTime = performance.now() - const fpService = new FluidPricesService(this._client) - // Populate data if none ecogesture exists - const loadedPrices = await fpService.getAllPrices() - if (loadedPrices?.length) { - logDuration('[Initialization] FluidPrices db already created', startTime) - return true + logDuration('[Initialization] Launching fluidPrices service', startTime) + const triggerQuery: QueryDefinition = Q(TRIGGERS_DOCTYPE).where({ + 'message.name': 'fluidsPrices', + }) + const { + data: [trigger], + }: QueryResult<Array<Trigger>> = await this._client.query(triggerQuery) + if (trigger?._id) { + this._client + .getStackClient() + .fetchJSON('POST', `/jobs/triggers/${trigger._id}/launch`) + logDuration( + '[Initialization] fluidPrices service launched successfully', + startTime + ) } else { - try { - const fluidTypes: FluidType[] = [ - FluidType.ELECTRICITY, - FluidType.WATER, - FluidType.GAS, - ] - const allPrices: FluidPrice[] = [] - const env = new EnvironmentService() - const remoteUrl = env.isProduction() - ? REMOTE_ORG_ECOLYO_AGENT_PRICES - : REMOTE_ORG_ECOLYO_AGENT_PRICES_REC - - for (const fluid of fluidTypes) { - const prices = await this._client - .getStackClient() - .fetchJSON('GET', `${remoteUrl}?fluidtype=${fluid}`) - allPrices.push(...prices) - } - for (const price of allPrices) { - await fpService.createPrice(price) - } - logDuration('[Initialization] FluidPrices db created', startTime) - return true - } catch (error) { - const errorMessage = `Initialization error - initFluidPrices: ${JSON.stringify( - error - )}` - logStack('error', errorMessage) - logApp.error(errorMessage) - Sentry.captureException(errorMessage) - return false - } + logDuration( + '[Initialization] FluidPrices service trigger not found', + startTime + ) } } @@ -237,7 +214,7 @@ export default class InitializationService { )}` logStack('error', errorMessage) logApp.error(errorMessage) - Sentry.captureException(errorMessage) + Sentry.captureException(error) throw error } } @@ -268,7 +245,7 @@ export default class InitializationService { )}` logStack('error', errorMessage) logApp.error(errorMessage) - Sentry.captureException(errorMessage) + Sentry.captureException(error) throw error } } else { @@ -307,7 +284,7 @@ export default class InitializationService { )}` logStack('error', errorMessage) logApp.error(errorMessage) - Sentry.captureException(errorMessage) + Sentry.captureException(error) throw error } } @@ -338,7 +315,7 @@ export default class InitializationService { )}` logStack('error', errorMessage) logApp.error(errorMessage) - Sentry.captureException(errorMessage) + Sentry.captureException(error) throw error } } else { @@ -378,7 +355,7 @@ export default class InitializationService { )}` logStack('error', errorMessage) logApp.error(errorMessage) - Sentry.captureException(errorMessage) + Sentry.captureException(error) throw error } } @@ -409,7 +386,7 @@ export default class InitializationService { )}` logStack('error', errorMessage) logApp.error(errorMessage) - Sentry.captureException(errorMessage) + Sentry.captureException(error) throw error } } else { @@ -452,7 +429,7 @@ export default class InitializationService { )}` logStack('error', errorMessage) logApp.error(errorMessage) - Sentry.captureException(errorMessage) + Sentry.captureException(error) throw error } } @@ -486,7 +463,7 @@ export default class InitializationService { )}` logStack('error', errorMessage) logApp.error(errorMessage) - Sentry.captureException(errorMessage) + Sentry.captureException(error) throw error } } else { @@ -532,7 +509,7 @@ export default class InitializationService { )}` logStack('error', errorMessage) logApp.error(errorMessage) - Sentry.captureException(errorMessage) + Sentry.captureException(error) throw error } } @@ -562,7 +539,7 @@ export default class InitializationService { )}` logStack('error', errorMessage) logApp.error(errorMessage) - Sentry.captureException(errorMessage) + Sentry.captureException(error) throw error } } @@ -592,7 +569,7 @@ export default class InitializationService { )}` logStack('error', errorMessage) logApp.error(errorMessage) - Sentry.captureException(errorMessage) + Sentry.captureException(error) throw error } } @@ -625,7 +602,7 @@ export default class InitializationService { )}` logStack('error', errorMessage) logApp.error(errorMessage) - Sentry.captureException(errorMessage) + Sentry.captureException(error) throw error } } @@ -651,7 +628,7 @@ export default class InitializationService { const errorMessage = `Initialization error - : ${JSON.stringify(error)}` logStack('error', errorMessage) logApp.error(errorMessage) - Sentry.captureException(errorMessage) + Sentry.captureException(error) throw error } } @@ -696,7 +673,7 @@ export default class InitializationService { )}` logStack('error', errorMessage) logApp.error(errorMessage) - Sentry.captureException(errorMessage) + Sentry.captureException(error) throw error } finally { logDuration('[Initialization] initConsent finished', startTime) diff --git a/src/services/konnector.service.spec.ts b/src/services/konnector.service.spec.ts index 844fa0748a3415d23276f0b56e0fb98d804414e3..85791bc51a8d69d579e48baa7d2c966f1017364b 100644 --- a/src/services/konnector.service.spec.ts +++ b/src/services/konnector.service.spec.ts @@ -1,21 +1,19 @@ import { QueryResult } from 'cozy-client' import { Konnector } from 'models' -import { accountsData } from '../../tests/__mocks__/accountsData.mock' -import mockClient from '../../tests/__mocks__/client' -import { konnectorsData } from '../../tests/__mocks__/konnectorsData.mock' -import { triggersData } from '../../tests/__mocks__/triggersData.mock' -import { triggerStateData } from '../../tests/__mocks__/triggerStateData.mock' +import { accountsData } from 'tests/__mocks__/accountsData.mock' +import mockClient from 'tests/__mocks__/client.mock' +import { konnectorsData } from 'tests/__mocks__/konnectorsData.mock' +import { triggerStateData } from 'tests/__mocks__/triggerStateData.mock' +import { triggersData } from 'tests/__mocks__/triggersData.mock' import KonnectorService from './konnector.service' const mockGetTrigger = jest.fn() const mockFetchTriggerState = jest.fn() jest.mock('./triggers.service', () => { - return jest.fn(() => { - return { - getTrigger: mockGetTrigger, - fetchTriggerState: mockFetchTriggerState, - } - }) + return jest.fn(() => ({ + getTrigger: mockGetTrigger, + fetchTriggerState: mockFetchTriggerState, + })) }) describe('KonnectorService service', () => { diff --git a/src/services/konnectorStatus.service.spec.ts b/src/services/konnectorStatus.service.spec.ts index 2f4a8a7864398235aa82c6f92c4c67ed0c7fa4ba..204f5f149fb5da63c5ed12b865f50e1946fc093f 100644 --- a/src/services/konnectorStatus.service.spec.ts +++ b/src/services/konnectorStatus.service.spec.ts @@ -1,14 +1,12 @@ -import { accountsData } from '../../tests/__mocks__/accountsData.mock' -import mockClient from '../../tests/__mocks__/client' +import { accountsData } from 'tests/__mocks__/accountsData.mock' +import mockClient from 'tests/__mocks__/client.mock' import KonnectorStatusService from './konnectorStatus.service' const mockGetAccountByType = jest.fn() jest.mock('./account.service', () => { - return jest.fn(() => { - return { - getAccountByType: mockGetAccountByType, - } - }) + return jest.fn(() => ({ + getAccountByType: mockGetAccountByType, + })) }) describe('KonnectorService service', () => { diff --git a/src/services/konnectorStatus.service.ts b/src/services/konnectorStatus.service.ts index 10addfe4a80f4664f740cfe8e5aa282f63fbe3d6..2ccb17bdb1eec46e2c356267921b213ec39bba45 100644 --- a/src/services/konnectorStatus.service.ts +++ b/src/services/konnectorStatus.service.ts @@ -1,5 +1,5 @@ import { Client } from 'cozy-client' -import { FluidType } from 'enum/fluid.enum' +import { FluidType } from 'enums' import AccountService from 'services/account.service' import ConfigService from 'services/fluidConfig.service' @@ -12,8 +12,7 @@ export default class KonnectorStatusService { /** * Return a FluidType array containing each konnector fluid with a account - * @param void - * @return {Promise<FluidType[]>} configured FluidTypes array + * @returns {Promise<FluidType[]>} configured FluidTypes array */ async getKonnectorAccountStatus(): Promise<FluidType[]> { const fluidConfig = new ConfigService().getFluidConfig() diff --git a/src/services/mail.service.spec.ts b/src/services/mail.service.spec.ts index b67f09c8fb724dec1a27fe63beea7360c2d33c2b..6d209422168492dff206183dc6f460861f6e0a3c 100644 --- a/src/services/mail.service.spec.ts +++ b/src/services/mail.service.spec.ts @@ -1,4 +1,4 @@ -import mockClient from '../../tests/__mocks__/client' +import mockClient from 'tests/__mocks__/client.mock' import MailService from './mail.service' describe('Mail service', () => { diff --git a/src/services/mail.service.ts b/src/services/mail.service.ts index 9528efdfd535ffc35a8cdb970e43be48b9ea0346..1e425524b7d7e39e1eb68e9ba873d4f726bbe7dc 100644 --- a/src/services/mail.service.ts +++ b/src/services/mail.service.ts @@ -16,7 +16,7 @@ export default class MailService { const errorMessage = `Failed to send mail` logStack('error', errorMessage) logApp.error(errorMessage) - Sentry.captureException(errorMessage) + Sentry.captureException(error) throw new Error(errorMessage) } } diff --git a/src/services/partnersInfo.service.spec.ts b/src/services/partnersInfo.service.spec.ts index ffb46973ef0254e7772d44917dfe3565a880f38f..43e2240179a570722e85c8003edbb7ad2ecee090 100644 --- a/src/services/partnersInfo.service.spec.ts +++ b/src/services/partnersInfo.service.spec.ts @@ -1,13 +1,11 @@ import { PartnersInfo } from 'models/partnersInfo.model' -import mockClient from '../../tests/__mocks__/client' +import mockClient from 'tests/__mocks__/client.mock' import PartnersInfoService from './partnersInfo.service' jest.mock('services/environment.service', () => { - return jest.fn(() => { - return { - isProduction: () => true, - } - }) + return jest.fn(() => ({ + isProduction: () => true, + })) }) /* eslint-disable camelcase */ @@ -30,14 +28,15 @@ describe('PartnersInfo service', () => { expect(result).toEqual(mockPartnersInfo) }) - it('should return an error', async () => { + it('should return undefined', async () => { mockClient.getStackClient().fetchJSON.mockRejectedValue(new Error()) let res try { res = await partnersInfoService.getPartnersInfo() expect(true).toBe(false) - } catch (error) { - expect(res).toBe(undefined) + } catch (e) { + // } + expect(res).toBe(undefined) }) }) diff --git a/src/services/partnersInfo.service.ts b/src/services/partnersInfo.service.ts index 26d814d8f82a0ecab9df128624bb846c6a5e5b3d..624137ddcd973ba50c0f00abe22650812cd1aa85 100644 --- a/src/services/partnersInfo.service.ts +++ b/src/services/partnersInfo.service.ts @@ -4,8 +4,8 @@ import logger from 'cozy-logger' import { REMOTE_ORG_ECOLYO_AGENT_PARTNERS_INFO, REMOTE_ORG_ECOLYO_AGENT_PARTNERS_INFO_REC, -} from 'doctypes/remote/org.ecolyo.agent.partners.info' -import { PartnersInfo } from 'models/partnersInfo.model' +} from 'doctypes' +import { PartnersInfo } from 'models' import logApp from 'utils/logger' import EnvironmentService from './environment.service' @@ -20,7 +20,7 @@ export default class PartnersInfoService { /** * Get information from backoffice about the status of partners' service * On success, respond the partnersInfo - * Else, throw an error + * Else, return undefined */ public async getPartnersInfo(): Promise<PartnersInfo | undefined> { const env = new EnvironmentService() @@ -39,7 +39,7 @@ export default class PartnersInfoService { )}` logStack('error', errorMessage) logApp.error(errorMessage) - Sentry.captureException(errorMessage) + Sentry.captureException(error) } } } diff --git a/src/services/profile.service.spec.ts b/src/services/profile.service.spec.ts index af34c70da7d378c2f439846695980e7eb0fdcff3..c30366ec2bd7246006f3c4bb77adcfd64de34b3d 100644 --- a/src/services/profile.service.spec.ts +++ b/src/services/profile.service.spec.ts @@ -1,8 +1,8 @@ import { QueryResult } from 'cozy-client' import { DateTime } from 'luxon' import { Profile } from 'models' -import mockClient from '../../tests/__mocks__/client' -import { profileData } from '../../tests/__mocks__/profileData.mock' +import mockClient from 'tests/__mocks__/client.mock' +import { mockProfileState } from 'tests/__mocks__/store' import ProfileService from './profile.service' describe('UserProfile service', () => { @@ -11,19 +11,19 @@ describe('UserProfile service', () => { describe('getUserProfile', () => { it('should return the user profile', async () => { const mockQueryResult: QueryResult<Profile[]> = { - data: [profileData], + data: [mockProfileState], bookmark: '', next: false, skip: 0, } mockClient.query.mockResolvedValueOnce(mockQueryResult) const result = await profileService.getProfile() - expect(result).toEqual(profileData) + expect(result).toEqual(mockProfileState) }) it('should return the user profile from string monthlyAnalysisDate', async () => { const userProfile = { - ...profileData, + ...mockProfileState, monthlyAnalysisDate: '2020-11-09T11:27:30.073Z', } // eslint-disable-next-line @typescript-eslint/no-explicit-any @@ -35,7 +35,7 @@ describe('UserProfile service', () => { } mockClient.query.mockResolvedValueOnce(mockQueryResult) const resultUserProfile = { - ...profileData, + ...mockProfileState, monthlyAnalysisDate: DateTime.fromISO('2020-11-09T11:27:30.073Z', { zone: 'utc', }), @@ -60,7 +60,7 @@ describe('UserProfile service', () => { describe('updateUserProfile', () => { it('should return an updated user profile', async () => { const userProfile = { - ...profileData, + ...mockProfileState, monthlyAnalysisDate: '2020-11-03T00:00:00.000Z', customPopupDate: '2020-11-03T00:00:00.000Z', } @@ -85,7 +85,7 @@ describe('UserProfile service', () => { } mockClient.save.mockResolvedValueOnce(mockUpdatedQueryResult) const resultUserProfile = { - ...profileData, + ...mockProfileState, monthlyAnalysisDate: DateTime.fromISO('2020-11-03T00:00:00.000Z', { zone: 'utc', }), @@ -103,7 +103,7 @@ describe('UserProfile service', () => { it('should return null if no user profile found', async () => { const mockQueryResult: QueryResult<Profile[]> = { - data: [profileData], + data: [mockProfileState], bookmark: '', next: false, skip: 0, diff --git a/src/services/profile.service.ts b/src/services/profile.service.ts index 64bf5dc792d3d18564472b50773c10ee527240d3..48a31b7224ff4bfef964f420d4623323dfb17eb5 100644 --- a/src/services/profile.service.ts +++ b/src/services/profile.service.ts @@ -21,8 +21,6 @@ export default class ProfileService { /** * Retrieve Profile from the ProfileEntity - * @param {ProfileEntity} profileEntity - * @returns {Profile} */ private parseProfileEntityToProfile(profileEntity: ProfileEntity): Profile { const profile: Profile = { diff --git a/src/services/profileEcogesture.service.spec.ts b/src/services/profileEcogesture.service.spec.ts index 5a6e2ee6037697cc373d593ed1f30549ddfff174..a68faa2b36da81aa02a99675d63f32bc42fa8992 100644 --- a/src/services/profileEcogesture.service.spec.ts +++ b/src/services/profileEcogesture.service.spec.ts @@ -1,8 +1,8 @@ import { QueryResult } from 'cozy-client' -import { EquipmentType } from 'enum/ecogesture.enum' +import { EquipmentType } from 'enums' import { ProfileEcogesture } from 'models/profileEcogesture.model' -import mockClient from '../../tests/__mocks__/client' -import { mockProfileEcogestureUpdated } from '../../tests/__mocks__/profileEcogesture.mock' +import mockClient from 'tests/__mocks__/client.mock' +import { mockProfileEcogestureUpdated } from 'tests/__mocks__/profileEcogesture.mock' import ProfileEcogestureService from './profileEcogesture.service' const profileEcogestureService = new ProfileEcogestureService(mockClient) diff --git a/src/services/profileEcogesture.service.ts b/src/services/profileEcogesture.service.ts index d38c43f890206a452748f08727539dcef79de78d..e9cfce1e125ebd6e3162c3a626adccd7054dfb00 100644 --- a/src/services/profileEcogesture.service.ts +++ b/src/services/profileEcogesture.service.ts @@ -1,6 +1,6 @@ import { Client, Q, QueryDefinition, QueryResult } from 'cozy-client' import { PROFILEECOGESTURE_DOCTYPE } from 'doctypes' -import { ProfileEcogesture } from 'models/profileEcogesture.model' +import { ProfileEcogesture } from 'models' export default class ProfileEcogestureService { private readonly _client: Client @@ -10,7 +10,6 @@ export default class ProfileEcogestureService { } /** * Retrieve the ProfileEcogesture from db - * @returns {ProfileEcogesture} */ public async getProfileEcogesture(): Promise<ProfileEcogesture | null> { const query: QueryDefinition = Q(PROFILEECOGESTURE_DOCTYPE) @@ -25,7 +24,6 @@ export default class ProfileEcogestureService { /** * Saves ProfileEcogesture in database - * @returns {ProfileEcogesture} */ public async updateProfileEcogesture( attributes: Partial<ProfileEcogesture> diff --git a/src/services/profileEcogestureForm.service.ts b/src/services/profileEcogestureForm.service.ts index 0da0d9ead5ad4974b4fb06fa4a4809cabe62a547..e3d994fb3c7246af560e0ccfd6c951ec69ad3ebb 100644 --- a/src/services/profileEcogestureForm.service.ts +++ b/src/services/profileEcogestureForm.service.ts @@ -1,14 +1,15 @@ -import { EquipmentType } from 'enum/ecogesture.enum' import { EcogestureStepForm, + EquipmentType, + IndividualOrCollective, ProfileEcogestureAnswerType, -} from 'enum/ecogestureForm.enum' -import { IndividualOrCollective, WarmingType } from 'enum/profileType.enum' + WarmingType, +} from 'enums' import { ProfileEcogesture, ProfileEcogestureAnswer, ProfileEcogestureValues, -} from 'models/profileEcogesture.model' +} from 'models' export default class ProfileEcogestureFormService { private readonly profileEcogesture: ProfileEcogesture @@ -19,7 +20,6 @@ export default class ProfileEcogestureFormService { /** * getNextFormStep - * @param {EcogestureStepForm} step * @returns {EcogestureStepForm} next step */ public getNextFormStep(step: EcogestureStepForm): EcogestureStepForm { @@ -28,10 +28,10 @@ export default class ProfileEcogestureFormService { return this.profileEcogesture.heating === IndividualOrCollective.INDIVIDUAL ? EcogestureStepForm.WARMING_FLUID - : EcogestureStepForm.HOT_WATER_TYPE + : EcogestureStepForm.HOT_WATER case EcogestureStepForm.WARMING_FLUID: - return EcogestureStepForm.HOT_WATER_TYPE - case EcogestureStepForm.HOT_WATER_TYPE: + return EcogestureStepForm.HOT_WATER + case EcogestureStepForm.HOT_WATER: return EcogestureStepForm.EQUIPMENTS case EcogestureStepForm.EQUIPMENTS: return EcogestureStepForm.END @@ -42,14 +42,13 @@ export default class ProfileEcogestureFormService { /** * getPreviousFormStep - * @param {EcogestureStepForm} step * @returns {EcogestureStepForm} previous step */ public getPreviousFormStep(step: EcogestureStepForm): EcogestureStepForm { switch (step) { case EcogestureStepForm.EQUIPMENTS: - return EcogestureStepForm.HOT_WATER_TYPE - case EcogestureStepForm.HOT_WATER_TYPE: + return EcogestureStepForm.HOT_WATER + case EcogestureStepForm.HOT_WATER: return this.profileEcogesture.heating === IndividualOrCollective.INDIVIDUAL ? EcogestureStepForm.WARMING_FLUID @@ -63,8 +62,6 @@ export default class ProfileEcogestureFormService { /** * getAnswerForStep - * @param {EcogestureStepForm} step - * @returns {EcogestureFormAnswer} */ static getAnswerForStep(step: EcogestureStepForm): ProfileEcogestureAnswer { switch (step) { @@ -77,9 +74,10 @@ export default class ProfileEcogestureFormService { WarmingType.GAS, WarmingType.WOOD, WarmingType.FUEL, + WarmingType.OTHER, ], } - case EcogestureStepForm.HOT_WATER_TYPE: + case EcogestureStepForm.HOT_WATER: return { type: ProfileEcogestureAnswerType.SINGLE_CHOICE, attribute: 'hotWater', diff --git a/src/services/profileType.service.spec.ts b/src/services/profileType.service.spec.ts index 0d58b4f0a1a177ee0bbbd6ef1ff48aba844cdef2..73909c5b355fc60f7ae44c7503bf1aae16345228 100644 --- a/src/services/profileType.service.spec.ts +++ b/src/services/profileType.service.spec.ts @@ -7,10 +7,10 @@ import { ProfileTypeStepForm, ThreeChoicesAnswer, WarmingType, -} from 'enum/profileType.enum' +} from 'enums' import { DateTime } from 'luxon' import { ProfileType } from 'models/profileType.model' -import mockClient from '../../tests/__mocks__/client' +import mockClient from 'tests/__mocks__/client.mock' import { mockCorrectedConsumption, mockEstimatedConsumption, @@ -36,7 +36,7 @@ import { mockTestProfile3, mockWaterRawNeeds, mockWaterSpreadNeeds, -} from '../../tests/__mocks__/profileType.mock' +} from 'tests/__mocks__/profileType.mock' import ProfileTypeService from './profileType.service' import ProfileTypeFormService from './profileTypeForm.service' diff --git a/src/services/profileType.service.ts b/src/services/profileType.service.ts index 2255192a8c05659608928105a284886e8dd118a7..ee742cec125aa3e34247b92da4666f3d752fcd5c 100644 --- a/src/services/profileType.service.ts +++ b/src/services/profileType.service.ts @@ -6,26 +6,26 @@ import elecSpeData from 'constants/consumptionConstants/electricSpecific.json' import heatingData from 'constants/consumptionConstants/heating.json' import { Client } from 'cozy-client' import logger from 'cozy-logger' -import { REMOTE_ORG_ECOLYO_DJU } from 'doctypes/remote/org.ecolyo.dju' -import { FluidType } from 'enum/fluid.enum' +import { REMOTE_ORG_ECOLYO_DJU } from 'doctypes' import { ConstructionYear, Floor, + FluidType, HotWaterEquipment, HousingType, IndividualInsulationWork, IndividualOrCollective, OutsideFacingWalls, ThreeChoicesAnswer, -} from 'enum/profileType.enum' +} from 'enums' import { DateTime } from 'luxon' -import { DjuResult } from 'models/dju.model' import { DetailsMonthlyForecast, + DjuResult, FluidForecast, MonthlyForecast, ProfileType, -} from 'models/profileType.model' +} from 'models' import logApp from 'utils/logger' import ConverterService from './converter.service' @@ -66,7 +66,6 @@ export default class ProfileTypeService { /** * calculateWarmingCorrectedConsumption - * @param {number} estimatedConsumption * @returns {number} - Corrected consumption */ public calculateWarmingCorrectedConsumption( @@ -183,10 +182,8 @@ export default class ProfileTypeService { /** * calculateWarmingMonthConsumption - @param {number} correctedConsumption - @param {number} number @returns {number} monthConsumption - */ + */ public async calculateWarmingMonthConsumption( correctedConsumption: number, month: number @@ -199,8 +196,6 @@ export default class ProfileTypeService { } /** * getMonthHeating - * @param {ProfileType} profileType - * @param {number} month * @returns {number} Month heating consumption in kw/h */ public async getMonthHeating(month: number): Promise<number> { @@ -216,9 +211,6 @@ export default class ProfileTypeService { /** * Calculate water raw needs by month - * - * @param {ProfileType} profileType - * @param {number} month * @returns {number} rawConsumption */ public calculateMonthWaterRawNeeds( @@ -240,9 +232,6 @@ export default class ProfileTypeService { } /** * Calculate spread water needs by month - * - * @param {ProfileType} profileType - * @param {number} month * @returns {number} spreadConsumption */ public calculateSpreadNeeds(profileType: ProfileType, month: number): number { @@ -261,9 +250,6 @@ export default class ProfileTypeService { } /** * Calculate total ecs consumption by month - * - * @param {number} spreadConsumption - * @param {ProfileType} profileType * @returns {number} monthEcsConsumption */ public calculateTotalConsumption( @@ -294,9 +280,6 @@ export default class ProfileTypeService { } /** * Get ECS consumption by month - * - * @param {ProfileType} profileType - * @param {number} month * @returns {number} monthEcsConsumption */ public getMonthEcs(month: number) { @@ -313,8 +296,6 @@ export default class ProfileTypeService { } /** * Get cooking consumption by month - * @param {ProfileType} profileType - * @param {number} month * @returns {number} monthCookingConsumption */ public getMonthCookingConsumption(month: number): number { @@ -332,8 +313,6 @@ export default class ProfileTypeService { } /** * Get specific electricity consumption by month - * @param {ProfileType} profileType - * @param {number} month * @returns {number} monthElectricSpecificConsumption */ public getMonthElectricSpecificConsumption(month: number): number { @@ -352,8 +331,6 @@ export default class ProfileTypeService { } /** * Get cold water consumption by month - * @param {ProfileType} profileType - * @param {number} month * @returns {number} monthColdWaterConsumption */ public getMonthColdWaterConsumption(month: number): number { @@ -373,9 +350,7 @@ export default class ProfileTypeService { } /** * getDetailsMonthlyForecast - * @param {FluidType} fluidType - * @param {number} month - * @returns {number} DetailsMonthlyForecast + * @returns DetailsMonthlyForecast */ public async getDetailsMonthlyForecast( fluidType: FluidType, @@ -425,12 +400,6 @@ export default class ProfileTypeService { return detailsMonthlyForecast } - /** - * getFluidForecast - * @param {FluidType} fluidType - * @param {number} month - @returns {FluidForecast} fluidForecast - */ public async getFluidForecast( fluidType: FluidType, month: number @@ -459,8 +428,7 @@ export default class ProfileTypeService { /** * getMonthlyForecast - * @param {number} month - * @returns {MonthlyForecast} MonthlyForecast + * @returns {Promise<MonthlyForecast>} MonthlyForecast */ public async getMonthlyForecast(month: number): Promise<MonthlyForecast> { const elecForecast: FluidForecast = await this.getFluidForecast( @@ -486,9 +454,7 @@ export default class ProfileTypeService { /** * Try to fetch dju from remote doctype, if no data or error, return default data - * @param {Client} client - * @param {number} month - * @returns {number} monthDju + * @returns {Promise<number>} monthDju */ public fetchDJU = async (month: number): Promise<number> => { const startDate: string = DateTime.local() @@ -533,14 +499,13 @@ export default class ProfileTypeService { const errorMessage = `fetchDju error : ${JSON.stringify(error)}` logStack('error', errorMessage) logApp.error(errorMessage) - Sentry.captureException(errorMessage) + Sentry.captureException(error) return heatingData.dju_average_by_month[month - 1] } } /** * checkConsistency - * @param {ProfileType} profileType * @returns {ProfileType} consistent profile type */ static checkConsistency(profileType: ProfileType): ProfileType { diff --git a/src/services/profileTypeEntity.service.spec.ts b/src/services/profileTypeEntity.service.spec.ts index 1fc0e9b6615d78e35e6ae087f6c0cd743dece966..b47674c0a5f6af43d71d2ed062632255d9c1b412 100644 --- a/src/services/profileTypeEntity.service.spec.ts +++ b/src/services/profileTypeEntity.service.spec.ts @@ -1,7 +1,7 @@ import { QueryResult } from 'cozy-client' import { ProfileType } from 'models' -import mockClient from '../../tests/__mocks__/client' -import { profileTypeData } from '../../tests/__mocks__/profileType.mock' +import mockClient from 'tests/__mocks__/client.mock' +import { profileTypeData } from 'tests/__mocks__/profileType.mock' import ProfileTypeEntityService from './profileTypeEntity.service' describe('UserProfileTypeEntity service', () => { diff --git a/src/services/profileTypeEntity.service.ts b/src/services/profileTypeEntity.service.ts index bb68839a13cdca9313f5d79a101531ce07037132..59d6b80dada9c3b9ec30dbb5f525933fd9368496 100644 --- a/src/services/profileTypeEntity.service.ts +++ b/src/services/profileTypeEntity.service.ts @@ -19,8 +19,6 @@ export default class ProfileTypeEntityService { * Retrieves ProfileType from the PROFILETYPE_DOCTYPE * When called with date parameter, fetches closest profileType to the date * When called without parameters, fetches last profileType in doctype - * @param {DateTime} date - * @returns {ProfileType} */ public async getProfileType(date?: DateTime): Promise<ProfileType | null> { const query: QueryDefinition = Q(PROFILETYPE_DOCTYPE) @@ -83,8 +81,6 @@ export default class ProfileTypeEntityService { * Retrieves all ProfileTypes from the PROFILETYPE_DOCTYPE * When called with period parameter, returns all profileTypes found for this period or null * When called without parameters, returns all profileTypes or null if none exist - * @param {TimePeriod} timePeriod - * @returns {ProfileType} */ public async getAllProfileTypes( timePeriod?: TimePeriod @@ -132,7 +128,6 @@ export default class ProfileTypeEntityService { /** * Saves profileType in database - * @returns {ProfileType} */ public async saveProfileType( attributes: Partial<ProfileType> @@ -154,7 +149,6 @@ export default class ProfileTypeEntityService { /** * Deletes Array of ProfileTypes - * @returns {boolean} */ public async deleteProfileTypes( profileTypes: ProfileType[] @@ -168,15 +162,13 @@ export default class ProfileTypeEntityService { const errorMessage = `deleteProfileTypes: ${JSON.stringify(error)}` logStack('error', errorMessage) logApp.error(errorMessage) - Sentry.captureException(errorMessage) + Sentry.captureException(error) return false } } /** * Retrieves ProfileType from the ProfileTypeEntity - * @param {ProfileType} profileTypeEntity - * @returns {ProfileType} */ private parseProfileTypeEntityToProfileType( profileTypeEntity: ProfileType diff --git a/src/services/profileTypeForm.service.ts b/src/services/profileTypeForm.service.ts index 14e2bcd30ffeac698edfb303a551b2023e181f0b..afa3020e9377e65f78759beaa58993c089bb139b 100644 --- a/src/services/profileTypeForm.service.ts +++ b/src/services/profileTypeForm.service.ts @@ -1,8 +1,8 @@ -import { EquipmentType } from 'enum/ecogesture.enum' -import { FluidType } from 'enum/fluid.enum' import { ConstructionYear, + EquipmentType, Floor, + FluidType, HotWaterEquipment, HotWaterFluid, HousingType, @@ -13,7 +13,7 @@ import { ProfileTypeStepForm, ThreeChoicesAnswer, WarmingType, -} from 'enum/profileType.enum' +} from 'enums' import { ProfileType, ProfileTypeAnswer } from 'models' export default class ProfileTypeFormService { @@ -25,7 +25,6 @@ export default class ProfileTypeFormService { /** * getNextFormStep - * @param {ProfileTypeStepForm} step * @returns {ProfileTypeStepForm} next step */ public getNextFormStep( @@ -88,7 +87,6 @@ export default class ProfileTypeFormService { /** * getPreviousFormStep - * @param {ProfileTypeStepForm} step * @returns {ProfileTypeStepForm} previous step */ public getPreviousFormStep(step: ProfileTypeStepForm): ProfileTypeStepForm { @@ -144,8 +142,7 @@ export default class ProfileTypeFormService { /** * getAnswerForStep - * @param {ProfileTypeStepForm} step - * @returns {ProfileTypeAnswer} + * @returns {ProfileTypeAnswer} - answer type */ static getAnswerForStep(step: ProfileTypeStepForm): ProfileTypeAnswer { switch (step) { diff --git a/src/services/queryRunner.service.spec.ts b/src/services/queryRunner.service.spec.ts index e820301be69aaf41cd3fadc60cf44df47dc2a2f9..656180de012107559449b5f0b7a78ed61419aa5a 100644 --- a/src/services/queryRunner.service.spec.ts +++ b/src/services/queryRunner.service.spec.ts @@ -1,14 +1,12 @@ import { QueryResult } from 'cozy-client' -import { DataloadState } from 'enum/dataload.enum' -import { FluidType } from 'enum/fluid.enum' -import { TimeStep } from 'enum/timeStep.enum' +import { DataloadState, FluidType, TimeStep } from 'enums' import { DateTime } from 'luxon' import { Dataload, DataloadEntity } from 'models' -import mockClient from '../../tests/__mocks__/client' -import { loadDayData } from '../../tests/__mocks__/loadDayData.mock' -import { loadMinuteData } from '../../tests/__mocks__/loadMinuteData.mock' -import { loadMonthData } from '../../tests/__mocks__/loadMonthData.mock' -import { loadYearData } from '../../tests/__mocks__/loadYearData.mock' +import mockClient from 'tests/__mocks__/client.mock' +import { loadDayData } from 'tests/__mocks__/loadDayData.mock' +import { loadMinuteData } from 'tests/__mocks__/loadMinuteData.mock' +import { loadMonthData } from 'tests/__mocks__/loadMonthData.mock' +import { loadYearData } from 'tests/__mocks__/loadYearData.mock' import QueryRunner from './queryRunner.service' const unknownTimeStep = 99 as TimeStep @@ -1369,7 +1367,7 @@ describe('queryRunner service', () => { }) }) - describe('fetchFluidData method', () => { + describe('fetchFluidRawDoctype method', () => { it('should return the data of the elec fluid and year time step', async () => { const mockTimePeriod = { startDate: DateTime.fromISO('2018-01-01T00:00:00.000Z', { diff --git a/src/services/queryRunner.service.ts b/src/services/queryRunner.service.ts index dffb788de165216d9d5890ef1e6a3f7c239e5c93..3fffee26dfc4292c518396f10702e59f9fa63443 100644 --- a/src/services/queryRunner.service.ts +++ b/src/services/queryRunner.service.ts @@ -11,9 +11,7 @@ import { GRDF_MONTH_DOCTYPE, GRDF_YEAR_DOCTYPE, } from 'doctypes' -import { DataloadState } from 'enum/dataload.enum' -import { FluidType } from 'enum/fluid.enum' -import { TimeStep } from 'enum/timeStep.enum' +import { DataloadState, FluidType, TimeStep } from 'enums' import { DateTime, Interval } from 'luxon' import { Dataload, TimePeriod } from 'models' import logApp from 'utils/logger' diff --git a/src/services/quiz.service.spec.ts b/src/services/quiz.service.spec.ts index 12462ae479373d9899a760e6ee3781f3ecdaea48..7b891b8419ff4ca068327a52d776f8a3ed7000d0 100644 --- a/src/services/quiz.service.spec.ts +++ b/src/services/quiz.service.spec.ts @@ -1,11 +1,11 @@ import { QueryResult } from 'cozy-client' -import { FluidType } from 'enum/fluid.enum' -import { TimeStep } from 'enum/timeStep.enum' import { CustomQuestionType, + FluidType, + TimeStep, UserQuestionState, UserQuizState, -} from 'enum/userQuiz.enum' +} from 'enums' import { DateTime } from 'luxon' import { CustomQuestionEntity, @@ -19,18 +19,19 @@ import { fullMonthGraphData, graphData, graphMonthData, -} from '../../tests/__mocks__/chartData.mock' -import mockClient from '../../tests/__mocks__/client' +} from 'tests/__mocks__/chartData.mock' +import mockClient from 'tests/__mocks__/client.mock' import { + UserQuizDone, + UserQuizReseted, + UserQuizStarted, allQuizEntities, customQuestionEntity, quizDefault, quizEntity, userQuiz, - UserQuizDone, - UserQuizReseted, - UserQuizStarted, -} from '../../tests/__mocks__/quizData.mock' +} from 'tests/__mocks__/quizData.mock' +import { getError } from 'tests/__mocks__/testUtils' import QuizService from './quiz.service' const localSpy = jest.spyOn(DateTime, 'local') @@ -40,12 +41,10 @@ const randomSpy = jest.spyOn(Math, 'random') const mockGetGraphData = jest.fn() const mockGetMaxLoad = jest.fn() jest.mock('./consumption.service', () => { - return jest.fn(() => { - return { - getGraphData: mockGetGraphData, - getMaxLoad: mockGetMaxLoad, - } - }) + return jest.fn(() => ({ + getGraphData: mockGetGraphData, + getMaxLoad: mockGetMaxLoad, + })) }) describe('Quiz service', () => { @@ -103,11 +102,10 @@ describe('Quiz service', () => { } mockClient.query.mockResolvedValueOnce(mockQueryResult) mockClient.destroy.mockRejectedValue(new Error()) - try { - await quizService.deleteAllQuizEntities() - } catch (error) { - expect(error).toEqual(new Error()) - } + const error = await getError(async () => + quizService.deleteAllQuizEntities() + ) + expect(error).toEqual(new Error()) }) }) diff --git a/src/services/quiz.service.ts b/src/services/quiz.service.ts index c553c7f7d53869a308a38bd0af9af923eb7b266c..bb0a4f72cfaff373803692dda8b16590095984e1 100644 --- a/src/services/quiz.service.ts +++ b/src/services/quiz.service.ts @@ -1,12 +1,12 @@ import { Client, Q, QueryDefinition, QueryResult } from 'cozy-client' import { QUIZ_DOCTYPE } from 'doctypes' -import { FluidType } from 'enum/fluid.enum' -import { TimeStep } from 'enum/timeStep.enum' import { CustomQuestionType, + FluidType, + TimeStep, UserQuestionState, UserQuizState, -} from 'enum/userQuiz.enum' +} from 'enums' import { shuffle } from 'lodash' import { DateTime } from 'luxon' import { @@ -34,7 +34,6 @@ export default class QuizService { /** * Retrieve all quiz entities from db - * @returns {QuizEntity[]} */ public async getAllQuizEntities(): Promise<QuizEntity[]> { const query: QueryDefinition = Q(QUIZ_DOCTYPE) @@ -46,9 +45,7 @@ export default class QuizService { /** * Retrieve quiz entities from db given the id - * * @param {string} quizId - ID of the searched quiz - * @returns {QuizEntity} */ public async getQuizEntityById(quizId: string): Promise<QuizEntity> { const query: QueryDefinition = Q(QUIZ_DOCTYPE) @@ -77,7 +74,6 @@ export default class QuizService { * Return quiz created from quiz entity * @param {QuizEntity[]} quizEntityList - userQuiz to update * @param {string} searchId - userQuiz to update - * @returns {UserQuiz} */ public getUserQuizfromQuizEntities( quizEntityList: QuizEntity[], @@ -113,8 +109,6 @@ export default class QuizService { /** * Return UserQuestion created from QuestionEntity - * @param {QuestionEntity} - * @returns {UserQuestion} */ public parseQuestionEntityToQuestion(question: QuestionEntity): UserQuestion { const userQuestion: UserQuestion = { @@ -126,8 +120,6 @@ export default class QuizService { /** * Return UserCustomQuestion created from CustomQuestionEntity - * @param {CustomQuestionEntity} - * @returns {UserCustomQuestion} */ public parseCustomQuestionEntityToCustomQuestion( customQuestion: CustomQuestionEntity @@ -141,8 +133,6 @@ export default class QuizService { /** * Return UserQuiz created from QuizEntity - * @param {QuizEntity} - * @returns {UserQuiz} */ public parseQuizEntityToUserQuiz(quiz: QuizEntity): UserQuiz { const userQuestions: UserQuestion[] = [] @@ -173,7 +163,6 @@ export default class QuizService { /** * Return quiz with updated state to UserQuizState.ONGOING and randomize question and answers * @param {UserQuiz} userQuiz - userQuiz to update - * @returns {UserQuiz} */ public async startUserQuiz(userQuiz: UserQuiz): Promise<UserQuiz> { const questions = userQuiz.questions.map(question => ({ @@ -193,7 +182,6 @@ export default class QuizService { /** * Return quiz with updated state to UserQuizState.UNLOCKED and updated questions with false result * @param {UserQuiz} userQuiz - userQuiz to update - * @returns {UserQuiz} */ public async resetUserQuiz(userQuiz: UserQuiz): Promise<UserQuiz> { const updatedQuestions: UserQuestion[] = userQuiz.questions.map( @@ -218,7 +206,6 @@ export default class QuizService { /** * Return quiz with updated state to UserQuizState.DONE * @param {UserQuiz} userQuiz - userQuiz to update - * @returns {UserQuiz} */ public async endUserQuiz(userQuiz: UserQuiz): Promise<UserQuiz> { const updatedUserQuiz: UserQuiz = { @@ -231,9 +218,6 @@ export default class QuizService { /** * Return quiz with result and updated question or customQuestion if no index is passed * @param {UserQuiz} userQuiz - userQuiz to update - * @returns {UserQuiz} - * @returns {questionIndex} - * @returns {questionResult} */ public async updateUserQuiz( userQuiz: UserQuiz, @@ -274,9 +258,6 @@ export default class QuizService { /** * Build a custom question with the customQuestionEntity - * @param customQuestionEntity - * @param fluidType - * @returns {QuestionEntity} */ public async getCustomQuestion( customQuestionEntity: CustomQuestionEntity, @@ -362,9 +343,6 @@ export default class QuizService { /** * Get the interval needed for the further calculs - * @param interval - * @param period - * @returns {TimePeriod} */ private getTimePeriodFromInterval( interval: TimeStep, @@ -413,10 +391,6 @@ export default class QuizService { * Finds max load on given past time period * when no max load is found looks x month/year back for a max value * if nothing is found fall back on most recent data - * @param timeStep - * @param interval - * @param fluidType - * @returns {Promise<IntervalAnswer>} */ private async getMaxLoadOnLastInterval( timeStep: TimeStep, @@ -501,11 +475,6 @@ export default class QuizService { /** * Calcul the average value on a given period - * @param timeStep - * @param interval - * @param fluidType - * @param weekday - * @returns {Promise<number>} */ private async getAverageOnGivenPeriod( timeStep: TimeStep, @@ -550,9 +519,6 @@ export default class QuizService { /** * Generate wrong date answer following the right one - * @param rightDate - * @param interval - * @returns {Answer[]} */ private getAnswersForInterval( rightDate: DateTime, @@ -641,9 +607,6 @@ export default class QuizService { /** * Generate wrong value answer following the right one - * @param maxLoad - * @param unit - * @returns {Answer[]} */ private getAnswersForNumberValue(maxLoad: number, unit: string): Answer[] { const coefList: number[] = [0.6, 0.7, 0.8, 0.12, 0.13] diff --git a/src/services/terms.service.spec.ts b/src/services/terms.service.spec.ts index 2d6e2768acae8a6e6ef1bb94b507b07b8ddade2f..eb6c6769b20fffcd96774a1e5448de474ad97da9 100644 --- a/src/services/terms.service.spec.ts +++ b/src/services/terms.service.spec.ts @@ -1,13 +1,13 @@ import { QueryResult } from 'cozy-client' import { DateTime } from 'luxon' import { Term } from 'models' -import mockClient from '../../tests/__mocks__/client' -import mockConfig from '../../tests/__mocks__/mockConfig.mock' +import mockClient from 'tests/__mocks__/client.mock' +import mockConfig from 'tests/__mocks__/mockConfig.mock' import { mockOutdatedTerm, mockTermsData, mockUpToDateTerm, -} from '../../tests/__mocks__/termsData.mock' +} from 'tests/__mocks__/termsData.mock' import TermsService from './terms.service' const localSpy = jest.spyOn(DateTime, 'local') diff --git a/src/services/terms.service.ts b/src/services/terms.service.ts index c9c3061a95372e312e8dffa58493fd61164a002c..778405b3f809f071e167f7106df99d6f35649c8d 100644 --- a/src/services/terms.service.ts +++ b/src/services/terms.service.ts @@ -16,7 +16,6 @@ export default class TermsService { } /** * Gets the last term doctype - * @returns {Term} */ public async getLastTerm(): Promise<Term> { const query: QueryDefinition = Q(TERMS_DOCTYPE) @@ -30,10 +29,7 @@ export default class TermsService { return terms } - /** - * Checks if the last term has been accepted by user - * @returns {boolean} - */ + /** Checks if the last term has been accepted by user */ public async isLastTermValidated(): Promise<boolean> { const query: QueryDefinition = Q(TERMS_DOCTYPE) .where({}) @@ -46,10 +42,7 @@ export default class TermsService { if (terms?.accepted) return true else return false } - /** - * Compares the version number in the last term with the current app CGU version in the manifest - * @returns {boolean} - */ + /** Compares the version number in the last term with the current app CGU version in the manifest */ public async isConsentVersionUpToDate(): Promise<boolean> { const lastTerm = await this.getLastTerm() if (lastTerm && lastTerm.version === config.termsVersion) return true @@ -73,8 +66,6 @@ export default class TermsService { /** * Creates a new term - * @param newTerm - * @returns */ public async createTerm(): Promise<Term | null> { try { @@ -92,7 +83,7 @@ export default class TermsService { const errorMessage = `Error creating new term: ${JSON.stringify(error)}` logStack('error', errorMessage) logApp.error(errorMessage) - Sentry.captureException(errorMessage) + Sentry.captureException(error) throw error } } diff --git a/src/services/timePeriod.service.spec.ts b/src/services/timePeriod.service.spec.ts index 58830ee8c6192b513333f8ab1bb1b4be91b6821b..abc6455fb1c27f99e61c5091ffd234a929f2193e 100644 --- a/src/services/timePeriod.service.spec.ts +++ b/src/services/timePeriod.service.spec.ts @@ -1,7 +1,7 @@ -import { FluidType } from 'enum/fluid.enum' -import { TimeStep } from 'enum/timeStep.enum' +import { FluidType, TimeStep } from 'enums' import { DateTime } from 'luxon' import { TimePeriod } from 'models' +import { getError } from 'tests/__mocks__/testUtils' import TimePeriodService from './timePeriod.service' const randomDate = DateTime.fromISO('2020-10-10T08:00:00.000Z', { @@ -254,7 +254,7 @@ describe('timePeriod service', () => { ) expect(result).toEqual(expectedComparisonDateTime) }) - it('should return an error because of unknown TimeStep', () => { + it('should return an error because of unknown TimeStep', async () => { const timePeriod: TimePeriod = { startDate: DateTime.fromISO('2020-10-07T08:00:00.000Z', { zone: 'utc', @@ -263,11 +263,10 @@ describe('timePeriod service', () => { zone: 'utc', }), } - try { + const error = await getError(async () => timePeriodService.getComparisonTimePeriod(timePeriod, unknownTimeStep) - } catch (error) { - expect(error).toEqual(new Error('TimeStep unknown')) - } + ) + expect(error).toEqual(new Error('TimeStep unknown')) }) }) @@ -322,15 +321,14 @@ describe('timePeriod service', () => { ) expect(result).toEqual(expectedDate) }) - it('should return an error because of unknown TimeStep', () => { - try { + it('should return an error because of unknown TimeStep', async () => { + const error = await getError(async () => timePeriodService.getLastDayOfCompletePeriod( randomDate, unknownTimeStep ) - } catch (error) { - expect(error).toEqual(new Error('TimeStep unknown')) - } + ) + expect(error).toEqual(new Error('TimeStep unknown')) }) }) @@ -375,7 +373,7 @@ describe('timePeriod service', () => { ) expect(result).toEqual(expectedDate) }) - it('should return the date of the last day of current period', () => { + it('should return the date of the last day of current period for year', () => { const expectedDate = DateTime.fromISO('2020-12-31T00:00:00.000Z', { zone: 'utc', }) @@ -385,12 +383,11 @@ describe('timePeriod service', () => { ) expect(result).toEqual(expectedDate) }) - it('should return the date of the last day of current period', () => { - try { + it('should return unknown timestep', async () => { + const error = await getError(async () => timePeriodService.getLastDayOfTimePeriod(randomDate, unknownTimeStep) - } catch (error) { - expect(error).toEqual(new Error('TimeStep unknown')) - } + ) + expect(error).toEqual(new Error('TimeStep unknown')) }) }) @@ -445,15 +442,14 @@ describe('timePeriod service', () => { ) expect(result).toEqual(expectedDate) }) - it('should return the date of the last day of current period', () => { - try { + it('should return the date of the last day of current period', async () => { + const error = await getError(async () => timePeriodService.getStartDateFromEndDateByTimeStep( randomDate, unknownTimeStep ) - } catch (error) { - expect(error).toEqual(new Error('TimeStep unknown')) - } + ) + expect(error).toEqual(new Error('TimeStep unknown')) }) }) }) diff --git a/src/services/timePeriod.service.ts b/src/services/timePeriod.service.ts index 655f8b7538644022c0b213c692545ebe65583cd4..46804b2e55b687df5c0352d75c20e87dc7655979 100644 --- a/src/services/timePeriod.service.ts +++ b/src/services/timePeriod.service.ts @@ -1,5 +1,4 @@ -import { FluidType } from 'enum/fluid.enum' -import { TimeStep } from 'enum/timeStep.enum' +import { FluidType, TimeStep } from 'enums' import { DateTime } from 'luxon' import { TimePeriod } from 'models' import ConfigService from 'services/fluidConfig.service' diff --git a/src/services/triggers.service.spec.ts b/src/services/triggers.service.spec.ts index f4aabb01a55ccf0a6202d7b4b3a1bdb7b092d032..88691fb425594dd7be6c13074c98252cff2dacd3 100644 --- a/src/services/triggers.service.spec.ts +++ b/src/services/triggers.service.spec.ts @@ -1,19 +1,18 @@ import { QueryResult } from 'cozy-client' import { Trigger, TriggerState } from 'models' -import { accountsData } from '../../tests/__mocks__/accountsData.mock' -import mockClient from '../../tests/__mocks__/client' -import { konnectorsData } from '../../tests/__mocks__/konnectorsData.mock' -import { triggersData } from '../../tests/__mocks__/triggersData.mock' -import { triggerStateData } from '../../tests/__mocks__/triggerStateData.mock' +import { accountsData } from 'tests/__mocks__/accountsData.mock' +import mockClient from 'tests/__mocks__/client.mock' +import { konnectorsData } from 'tests/__mocks__/konnectorsData.mock' +import { getError } from 'tests/__mocks__/testUtils' +import { triggerStateData } from 'tests/__mocks__/triggerStateData.mock' +import { triggersData } from 'tests/__mocks__/triggersData.mock' import TriggerService from './triggers.service' const mockCreateTrigger = jest.fn() jest.mock('cozy-harvest-lib/dist/connections/triggers', () => { - return jest.fn(() => { - return { - createTrigger: mockCreateTrigger, - } - }) + return jest.fn(() => ({ + createTrigger: mockCreateTrigger, + })) }) describe('TriggerService service', () => { @@ -121,34 +120,32 @@ describe('TriggerService service', () => { it('should throw an error', async () => { mockClient.getStackClient().fetchJSON.mockRejectedValueOnce(new Error()) - try { - await triggerService.fetchTriggerState(triggersData[0]) - } catch (error) { - expect(error).toEqual(new Error('Fetch trigger state failed')) - } + const error = await getError(async () => + triggerService.fetchTriggerState(triggersData[0]) + ) + expect(error).toEqual(new Error('Fetch trigger state failed')) }) }) describe('deleteTrigger method', () => { it('should return true when destroy successfully', async () => { - const mockDetroyResult: QueryResult<Trigger[]> = { + const mockDestroyResult: QueryResult<Trigger[]> = { data: [], bookmark: '', next: false, skip: 0, } - mockClient.destroy.mockResolvedValueOnce(mockDetroyResult) + mockClient.destroy.mockResolvedValueOnce(mockDestroyResult) const result = await triggerService.deleteTrigger(triggersData[0]) expect(result).toBe(true) }) it('should throw error when destroy unsuccessfully', async () => { mockClient.destroy.mockRejectedValueOnce(new Error()) - try { - await triggerService.deleteTrigger(triggersData[0]) - } catch (error) { - expect(error).toEqual(new Error('Delete trigger failed')) - } + const error = await getError(async () => + triggerService.deleteTrigger(triggersData[0]) + ) + expect(error).toEqual(new Error('Delete trigger failed')) }) }) }) diff --git a/src/services/triggers.service.ts b/src/services/triggers.service.ts index 830b22746f0c4f0994b349dea8d529fb2a2d4035..d3478fcfc809d106fbe1b5841b773f51585deef6 100644 --- a/src/services/triggers.service.ts +++ b/src/services/triggers.service.ts @@ -103,7 +103,7 @@ export default class TriggerService { const errorMessage = `Delete trigger failed: ${JSON.stringify(error)}` logStack('error', errorMessage) logApp.error(errorMessage) - Sentry.captureException(errorMessage) + Sentry.captureException(error) throw new Error('Delete trigger failed') } } diff --git a/src/services/usageEvent.service.spec.ts b/src/services/usageEvent.service.spec.ts index 5fcc3a4cca66ce4650372b9475779ec0a8373b4c..237f7c74dff74ee0799075260c8df7008e61ee81 100644 --- a/src/services/usageEvent.service.spec.ts +++ b/src/services/usageEvent.service.spec.ts @@ -1,8 +1,9 @@ import { QueryResult } from 'cozy-client' -import { UsageEventType } from 'enum/usageEvent.enum' +import { UsageEventType } from 'enums' import { DateTime } from 'luxon' import { AddEventParams, UsageEventEntity } from 'models' -import mockClient from '../../tests/__mocks__/client' +import mockClient from 'tests/__mocks__/client.mock' +import { getError } from 'tests/__mocks__/testUtils' import { allUsageEventsData, connectionAttemptEGLError, @@ -11,7 +12,7 @@ import { connectionUsageEventsData, usageEventData, usageEventEntityData, -} from '../../tests/__mocks__/usageEventsData.mock' +} from 'tests/__mocks__/usageEventsData.mock' import UsageEventService from './usageEvent.service' const localSpy = jest.spyOn(DateTime, 'local') @@ -63,14 +64,13 @@ describe('UsageEvent service', () => { }) it('should throw an error', async () => { mockClient.save.mockRejectedValue(new Error()) - try { - await UsageEventService.updateUsageEventsAggregated( + const error = await getError(async () => + UsageEventService.updateUsageEventsAggregated( mockClient, allUsageEventsData ) - } catch (error) { - expect(error).toEqual(new Error()) - } + ) + expect(error).toEqual(new Error('Could not update all events')) }) }) describe('getEvents method', () => { @@ -127,7 +127,7 @@ describe('UsageEvent service', () => { expect(result).toEqual(usageEventData) }) }) - describe('udpateConnectionAttemptEvent method', () => { + describe('updateConnectionAttemptEvent method', () => { it('should update the last attempt to true', async () => { const mockQueryResult: QueryResult<UsageEventEntity[]> = { data: [connectionAttemptEGLError], @@ -143,7 +143,7 @@ describe('UsageEvent service', () => { } mockClient.query.mockResolvedValueOnce(mockQueryResult) mockClient.save.mockResolvedValueOnce(mockQueryResult2) - const result = await UsageEventService.udpateConnectionAttemptEvent( + const result = await UsageEventService.updateConnectionAttemptEvent( mockClient, 'eglgrandlyon' ) @@ -157,7 +157,7 @@ describe('UsageEvent service', () => { skip: 0, } mockClient.query.mockResolvedValueOnce(mockQueryResult) - const result = await UsageEventService.udpateConnectionAttemptEvent( + const result = await UsageEventService.updateConnectionAttemptEvent( mockClient, 'eglgrandlyon' ) @@ -171,7 +171,7 @@ describe('UsageEvent service', () => { skip: 0, } mockClient.query.mockResolvedValueOnce(mockQueryResult) - const result = await UsageEventService.udpateConnectionAttemptEvent( + const result = await UsageEventService.updateConnectionAttemptEvent( mockClient, 'eglgrandlyon' ) diff --git a/src/services/usageEvent.service.ts b/src/services/usageEvent.service.ts index 33fb71ea2b15ace740910d1d21852b30ad64f971..cc362ee26dbc8fdde3df3ed4e5abd36dffae94dc 100644 --- a/src/services/usageEvent.service.ts +++ b/src/services/usageEvent.service.ts @@ -8,7 +8,7 @@ import { } from 'cozy-client' import logger from 'cozy-logger' import { USAGEEVENT_DOCTYPE } from 'doctypes' -import { UsageEventType } from 'enum/usageEvent.enum' +import { UsageEventType } from 'enums' import { DateTime } from 'luxon' import { AddEventParams, @@ -22,9 +22,6 @@ const logStack = logger.namespace('usageEventService') export default class UsageEventService { /** - * addEvent - * @param {Client} client - * @param {AddEventParams} params * @returns {Promise<UsageEvent>} usageEvent added */ static async addEvent( @@ -49,9 +46,6 @@ export default class UsageEventService { } /** - * addEvent - * @param {Client} client - * @param {AddEventParams} params * @returns {Promise<UsageEvent>} usageEvent added */ static async addEventIfDoesntExist( @@ -66,13 +60,7 @@ export default class UsageEventService { return null } - /** - * - * @param {Client} client - * @param {string} konnectorSlug - * @returns - */ - static async udpateConnectionAttemptEvent( + static async updateConnectionAttemptEvent( client: Client, konnectorSlug: string ): Promise<UsageEventEntity | undefined> { @@ -101,47 +89,42 @@ export default class UsageEventService { return savedEvent } } catch (error) { - const errorMessage = `UsageEvent service error on udpateConnectionAttemptEvent: ${JSON.stringify( + const errorMessage = `UsageEvent service error on updateConnectionAttemptEvent: ${JSON.stringify( error )}` logStack('error', errorMessage) logApp.error(errorMessage) - Sentry.captureException(errorMessage) + Sentry.captureException(error) } } /** - * updateUsageEventsAggregated - * @param {Client} client - * @param {string[]} ids * @returns {Promise<boolean>} return true if all events are updated */ static async updateUsageEventsAggregated( client: Client, events: UsageEvent[] ): Promise<boolean> { - for (const event of events) { - try { + try { + for (const event of events) { await client.save({ ...event, aggregated: true, }) - } catch (error) { - const errorMessage = `UsageEvent service error on updateUsageEventsAggregated: ${JSON.stringify( - error - )}` - logStack('error', errorMessage) - logApp.error(errorMessage) - Sentry.captureException(errorMessage) } + return true + } catch (error) { + const errorMessage = `UsageEvent service error on updateUsageEventsAggregated: ${JSON.stringify( + error + )}` + logStack('error', errorMessage) + logApp.error(errorMessage) + Sentry.captureException(error) + throw new Error('Could not update all events') } - return true } /** - * getEvents - * @param {Client} client - * @param {MongoSelector} filterParams * @returns {Promise<UsageEvent[]>} usageEvent added */ static async getEvents( @@ -164,8 +147,6 @@ export default class UsageEventService { /** * Retrieve UsageEvent from the UsageEventEntity - * @param {UsageEventEntity} usageEventEntity - * @returns {UsageEvent} */ static parseUsageEventEntityToUsageEvent( usageEventEntity: UsageEventEntity diff --git a/src/store/analysis/analysis.slice.spec.ts b/src/store/analysis/analysis.slice.spec.ts index cfe3161895ece34893cce6e4250d1ccd9d1d247e..8e8ac488ee08b829a2b2493d8b5ccc9fb20bb851 100644 --- a/src/store/analysis/analysis.slice.spec.ts +++ b/src/store/analysis/analysis.slice.spec.ts @@ -1,5 +1,5 @@ import { DateTime } from 'luxon' -import { mockAnalysisState } from '../../../tests/__mocks__/store' +import { mockAnalysisState } from 'tests/__mocks__/store' import { analysisSlice, setAnalysisMonth, setPeriod } from './analysis.slice' describe('analysis reducer', () => { diff --git a/src/store/analysis/analysis.slice.ts b/src/store/analysis/analysis.slice.ts index b3fdf4b33b5fd55d09d912a8ebe22b3fcd40d3c4..11eabac17c89f295762c5bf02b5ecdc10c45a866 100644 --- a/src/store/analysis/analysis.slice.ts +++ b/src/store/analysis/analysis.slice.ts @@ -7,19 +7,14 @@ const initialState: AnalysisState = { analysisMonth: DateTime.local().minus({ months: 1 }).startOf('day'), } -type SetPeriodAction = PayloadAction<'month' | 'year'> -type SetSelectedMonthAction = PayloadAction<DateTime> - -export type AnalysisActionTypes = SetPeriodAction | SetSelectedMonthAction - export const analysisSlice = createSlice({ name: 'analysis', initialState, reducers: { - setPeriod: (state, action: SetPeriodAction) => { + setPeriod: (state, action: PayloadAction<'month' | 'year'>) => { state.period = action.payload }, - setAnalysisMonth: (state, action: SetSelectedMonthAction) => { + setAnalysisMonth: (state, action: PayloadAction<DateTime>) => { state.analysisMonth = action.payload }, }, diff --git a/src/store/challenge/challenge.slice.spec.ts b/src/store/challenge/challenge.slice.spec.ts index 8adbc4cc7271313784926b77b6d50388fd62c6b2..f4a265cdf615264845e93d98099247311b8e174f 100644 --- a/src/store/challenge/challenge.slice.spec.ts +++ b/src/store/challenge/challenge.slice.spec.ts @@ -1,12 +1,11 @@ -import { DataloadState } from 'enum/dataload.enum' -import { UserChallengeState } from 'enum/userChallenge.enum' +import { DataloadState, UserChallengeState } from 'enums' import { DateTime } from 'luxon' import { ChallengeState, Dataload, UserChallenge } from 'models' -import { mockInitialChallengeState } from '../../../tests/__mocks__/store' +import { mockChallengeState } from 'tests/__mocks__/store' import { userChallengeData, userChallengeDefault, -} from '../../../tests/__mocks__/userChallengeData.mock' +} from 'tests/__mocks__/userChallengeData.mock' import { challengeSlice, setChallengeConsumption, @@ -18,12 +17,12 @@ import { describe('challenge reducer', () => { it('should return the initial state', () => { const state = challengeSlice.reducer(undefined, { type: undefined }) - expect(state).toEqual(mockInitialChallengeState) + expect(state).toEqual(mockChallengeState) }) it('should handle setUserChallengeList', () => { const state = challengeSlice.reducer( - mockInitialChallengeState, + mockChallengeState, setUserChallengeList(userChallengeData) ) const expectedResult: ChallengeState = { @@ -34,9 +33,9 @@ describe('challenge reducer', () => { expect(state).toEqual(expectedResult) }) - it('should handle updateUserChallengeList ', () => { + it('should handle updateUserChallengeList', () => { const updatedMockInitialChallengeState = { - ...mockInitialChallengeState, + ...mockChallengeState, userChallengeList: userChallengeDefault, } const updatedUserChallenge: UserChallenge = { @@ -58,9 +57,9 @@ describe('challenge reducer', () => { expect(state).toEqual(expectedResult) }) - it('should handle unlockNextUserChallenge ', () => { + it('should handle unlockNextUserChallenge', () => { const updatedMockInitialChallengeState = { - ...mockInitialChallengeState, + ...mockChallengeState, userChallengeList: userChallengeDefault, } const updatedUserChallenge: UserChallenge = { @@ -88,9 +87,9 @@ describe('challenge reducer', () => { expect(state).toEqual(expectedResult) }) - it('should handle SET_CHALLENGE_CONSUMPTION ', () => { + it('should handle SET_CHALLENGE_CONSUMPTION', () => { const updatedMockInitialChallengeState = { - ...mockInitialChallengeState, + ...mockChallengeState, userChallengeList: userChallengeDefault, } const dataload: Dataload[] = [ diff --git a/src/store/challenge/challenge.slice.ts b/src/store/challenge/challenge.slice.ts index eae360e05ee1019d0aa87b11f70174bfae4b7792..8b5d33573f11aaeff89859ca72bba5552b9ed2f2 100644 --- a/src/store/challenge/challenge.slice.ts +++ b/src/store/challenge/challenge.slice.ts @@ -1,5 +1,5 @@ import { PayloadAction, createSlice } from '@reduxjs/toolkit' -import { UserChallengeState } from 'enum/userChallenge.enum' +import { UserChallengeState } from 'enums' import { ChallengeState, Dataload, UserChallenge } from 'models' const initialState: ChallengeState = { @@ -8,25 +8,16 @@ const initialState: ChallengeState = { currentDataload: [], } -type SetUserChallengeList = PayloadAction<UserChallenge[]> -type UpdateUserChallengeList = PayloadAction<UserChallenge> -type UnlockNextUserChallenge = PayloadAction<UserChallenge> type SetChallengeConsumption = PayloadAction<{ userChallenge: UserChallenge currentDataload: Dataload[] }> -export type ChallengeActionTypes = - | SetUserChallengeList - | UpdateUserChallengeList - | UnlockNextUserChallenge - | SetChallengeConsumption - export const challengeSlice = createSlice({ name: 'challenge', initialState, reducers: { - setUserChallengeList: (state, action: SetUserChallengeList) => { + setUserChallengeList: (state, action: PayloadAction<UserChallenge[]>) => { const filteredCurrentChallenge = action.payload.filter( challenge => challenge.state === UserChallengeState.ONGOING || @@ -37,7 +28,7 @@ export const challengeSlice = createSlice({ state.userChallengeList = action.payload state.currentChallenge = currentChallenge }, - updateUserChallengeList: (state, action: UpdateUserChallengeList) => { + updateUserChallengeList: (state, action: PayloadAction<UserChallenge>) => { const id = action.payload.id const currentChallenge = action.payload.state === UserChallengeState.ONGOING || @@ -51,12 +42,15 @@ export const challengeSlice = createSlice({ state.userChallengeList = updatedList state.currentChallenge = currentChallenge || state.currentChallenge }, - unlockNextUserChallenge: (state, action: UnlockNextUserChallenge) => { + unlockNextUserChallenge: (state, action: PayloadAction<UserChallenge>) => { const id = action.payload.id const updatedList = [...state.userChallengeList] const findIndex = updatedList.findIndex(challenge => challenge.id === id) updatedList[findIndex] = action.payload - if (typeof updatedList[findIndex + 1] !== 'undefined') { + if ( + typeof updatedList[findIndex + 1] !== 'undefined' && + updatedList[findIndex + 1].state === UserChallengeState.LOCKED + ) { updatedList[findIndex + 1] = { ...updatedList[findIndex + 1], state: UserChallengeState.UNLOCKED, diff --git a/src/store/chart/chart.slice.spec.ts b/src/store/chart/chart.slice.spec.ts index 717c26db45e99c62987b9fd3ea23e8580899e221..9015e59e329b09ed494600f00def39203bac9ad5 100644 --- a/src/store/chart/chart.slice.spec.ts +++ b/src/store/chart/chart.slice.spec.ts @@ -1,7 +1,7 @@ -import { TimeStep } from 'enum/timeStep.enum' +import { TimeStep } from 'enums' import { DateTime } from 'luxon' -import { graphData } from '../../../tests/__mocks__/chartData.mock' -import { mockInitialChartState } from '../../../tests/__mocks__/store' +import { graphData } from 'tests/__mocks__/chartData.mock' +import { mockChartState } from 'tests/__mocks__/store' import { chartSlice, setCurrentDataChart, @@ -16,12 +16,12 @@ import { describe('chart reducer', () => { it('should return the initial state', () => { const initialState = chartSlice.reducer(undefined, { type: undefined }) - expect(initialState).toEqual(mockInitialChartState) + expect(initialState).toEqual(mockChartState) }) it('should return same state if no action', () => { - const state = chartSlice.reducer(mockInitialChartState, { type: undefined }) - expect(state).toEqual(mockInitialChartState) + const state = chartSlice.reducer(mockChartState, { type: undefined }) + expect(state).toEqual(mockChartState) }) describe('setSelectedDate', () => { @@ -30,11 +30,11 @@ describe('chart reducer', () => { zone: 'utc', }) const state = chartSlice.reducer( - mockInitialChartState, + mockChartState, setSelectedDate(mockDate) ) expect(state).toEqual({ - ...mockInitialChartState, + ...mockChartState, selectedDate: mockDate, }) }) @@ -43,21 +43,21 @@ describe('chart reducer', () => { describe('setCurrentTimeStep', () => { it('should handle setCurrentTimeStep with payload', () => { const state = chartSlice.reducer( - mockInitialChartState, + mockChartState, setCurrentTimeStep(TimeStep.MONTH) ) expect(state).toEqual({ - ...mockInitialChartState, + ...mockChartState, currentTimeStep: TimeStep.MONTH, }) }) it('should disable showCompare if timestep is year', () => { const state = chartSlice.reducer( - { ...mockInitialChartState, showCompare: true }, + { ...mockChartState, showCompare: true }, setCurrentTimeStep(TimeStep.YEAR) ) expect(state).toEqual({ - ...mockInitialChartState, + ...mockChartState, showCompare: false, currentTimeStep: TimeStep.YEAR, }) @@ -66,12 +66,9 @@ describe('chart reducer', () => { describe('setCurrentIndex', () => { it('should handle setCurrentIndex with payload', () => { - const state = chartSlice.reducer( - mockInitialChartState, - setCurrentIndex(1) - ) + const state = chartSlice.reducer(mockChartState, setCurrentIndex(1)) expect(state).toEqual({ - ...mockInitialChartState, + ...mockChartState, currentIndex: 1, }) }) @@ -80,11 +77,11 @@ describe('chart reducer', () => { describe('setCurrentDataChart', () => { it('should handle setCurrentDataChart with payload', () => { const state = chartSlice.reducer( - mockInitialChartState, + mockChartState, setCurrentDataChart(graphData) ) expect(state).toEqual({ - ...mockInitialChartState, + ...mockChartState, currentDatachart: graphData, }) }) @@ -93,11 +90,11 @@ describe('chart reducer', () => { describe('setCurrentDataChartIndex', () => { it('should handle setCurrentDataChartIndex with payload', () => { const state = chartSlice.reducer( - mockInitialChartState, + mockChartState, setCurrentDataChartIndex(1) ) expect(state).toEqual({ - ...mockInitialChartState, + ...mockChartState, currentDatachartIndex: 1, }) }) @@ -105,9 +102,9 @@ describe('chart reducer', () => { describe('setLoading', () => { it('should handle setLoading with payload', () => { - const state = chartSlice.reducer(mockInitialChartState, setLoading(false)) + const state = chartSlice.reducer(mockChartState, setLoading(false)) expect(state).toEqual({ - ...mockInitialChartState, + ...mockChartState, loading: false, }) }) @@ -115,104 +112,11 @@ describe('chart reducer', () => { describe('setShowCompare', () => { it('should handle setShowCompare', () => { - const state = chartSlice.reducer( - mockInitialChartState, - setShowCompare(true) - ) + const state = chartSlice.reducer(mockChartState, setShowCompare(true)) expect(state).toEqual({ - ...mockInitialChartState, + ...mockChartState, showCompare: true, }) }) }) }) - -describe('chart reducer', () => { - it('should return the initial state', () => { - const initialState = chartSlice.reducer(undefined, { type: undefined }) - expect(initialState).toEqual(mockInitialChartState) - }) - - it('should return same state if no action', () => { - const state = chartSlice.reducer(mockInitialChartState, { type: undefined }) - expect(state).toEqual(mockInitialChartState) - }) - - describe('setSelectedDate', () => { - it('should handle SET_SELECTED_DATE with payload', () => { - const mockDate = DateTime.fromISO('2021-01-01T00:00:00.000Z', { - zone: 'utc', - }) - const state = chartSlice.reducer( - mockInitialChartState, - setSelectedDate(mockDate) - ) - expect(state).toEqual({ - ...mockInitialChartState, - selectedDate: mockDate, - }) - }) - }) - - describe('setCurrentTimeStep', () => { - it('should handle SET_CURRENT_TIMESTEP with payload', () => { - const state = chartSlice.reducer( - mockInitialChartState, - setCurrentTimeStep(TimeStep.MONTH) - ) - expect(state).toEqual({ - ...mockInitialChartState, - currentTimeStep: TimeStep.MONTH, - }) - }) - }) - - describe('setCurrentIndex', () => { - it('should handle SET_CURRENT_INDEX with payload', () => { - const state = chartSlice.reducer( - mockInitialChartState, - setCurrentIndex(1) - ) - expect(state).toEqual({ - ...mockInitialChartState, - currentIndex: 1, - }) - }) - }) - - describe('setCurrentDataChart', () => { - it('should handle SET_CURRENT_DATACHART with payload', () => { - const state = chartSlice.reducer( - mockInitialChartState, - setCurrentDataChart(graphData) - ) - expect(state).toEqual({ - ...mockInitialChartState, - currentDatachart: graphData, - }) - }) - }) - - describe('setCurrentDataChartIndex', () => { - it('should handle SET_CURRENT_DATACHART_INDEX with payload', () => { - const state = chartSlice.reducer( - mockInitialChartState, - setCurrentDataChartIndex(1) - ) - expect(state).toEqual({ - ...mockInitialChartState, - currentDatachartIndex: 1, - }) - }) - }) - - describe('setLoading', () => { - it('should handle SET_LOADING with payload', () => { - const state = chartSlice.reducer(mockInitialChartState, setLoading(false)) - expect(state).toEqual({ - ...mockInitialChartState, - loading: false, - }) - }) - }) -}) diff --git a/src/store/chart/chart.slice.ts b/src/store/chart/chart.slice.ts index d724d93d06df31708ca5538be3cfb07b22d7d770..60f4790d601c1edbfcf6bf9b35e61af23320d940 100644 --- a/src/store/chart/chart.slice.ts +++ b/src/store/chart/chart.slice.ts @@ -1,27 +1,8 @@ import { PayloadAction, createSlice } from '@reduxjs/toolkit' -import { TimeStep } from 'enum/timeStep.enum' +import { TimeStep } from 'enums' import { DateTime } from 'luxon' import { ChartState, Datachart } from 'models' -type SetCurrentDataChart = PayloadAction<Datachart> -type SetCurrentDataChartIndex = PayloadAction<number> -type SetCurrentIndex = PayloadAction<number> -type SetCurrentTimeStep = PayloadAction<TimeStep> -type SetLoading = PayloadAction<boolean> -type SetSelectedDate = PayloadAction<DateTime> -type SetShowCompare = PayloadAction<boolean> -type SetShowOfflineData = PayloadAction<boolean> - -export type ChartActionTypes = - | SetCurrentDataChart - | SetCurrentDataChartIndex - | SetCurrentIndex - | SetCurrentTimeStep - | SetLoading - | SetSelectedDate - | SetShowCompare - | SetShowOfflineData - const initialState: ChartState = { selectedDate: DateTime.local().endOf('minute').setZone('utc', { keepLocalTime: true, @@ -39,31 +20,31 @@ export const chartSlice = createSlice({ name: 'chart', initialState, reducers: { - setCurrentDataChart: (state, action: SetCurrentDataChart) => { + setCurrentDataChart: (state, action: PayloadAction<Datachart>) => { state.currentDatachart = action.payload }, - setCurrentDataChartIndex: (state, action: SetCurrentDataChartIndex) => { + setCurrentDataChartIndex: (state, action: PayloadAction<number>) => { state.currentDatachartIndex = action.payload }, - setCurrentIndex: (state, action: SetCurrentIndex) => { + setCurrentIndex: (state, action: PayloadAction<number>) => { state.currentIndex = action.payload }, - setCurrentTimeStep: (state, action: SetCurrentTimeStep) => { + setCurrentTimeStep: (state, action: PayloadAction<TimeStep>) => { state.currentTimeStep = action.payload if (state.currentTimeStep === TimeStep.YEAR) { state.showCompare = false } }, - setLoading: (state, action: SetLoading) => { + setLoading: (state, action: PayloadAction<boolean>) => { state.loading = action.payload }, - setSelectedDate: (state, action: SetSelectedDate) => { + setSelectedDate: (state, action: PayloadAction<DateTime>) => { state.selectedDate = action.payload }, - setShowCompare: (state, action: SetShowCompare) => { + setShowCompare: (state, action: PayloadAction<boolean>) => { state.showCompare = action.payload }, - setShowOfflineData: (state, action: SetShowOfflineData) => { + setShowOfflineData: (state, action: PayloadAction<boolean>) => { state.showOfflineData = action.payload }, }, diff --git a/src/store/global/global.action.spec.ts b/src/store/global/global.action.spec.ts deleted file mode 100644 index 255bdc56ca394e2e97bf2970aded58109bd10a7f..0000000000000000000000000000000000000000 --- a/src/store/global/global.action.spec.ts +++ /dev/null @@ -1,79 +0,0 @@ -import { ScreenType } from 'enum/screen.enum' -import { mockInitialGlobalState } from '../../../tests/__mocks__/store' -import { - CHANGE_SCREEN_TYPE, - GlobalActionTypes, - SET_FLUID_STATUS, - TOGGLE_ANALYSIS_NOTIFICATION, - TOGGLE_CHALLENGE_ACTION_NOTIFICATION, - TOGGLE_CHALLENGE_DUEL_NOTIFICATION, - TOGGLE_CHALLENGE_EXPLORATION_NOTIFICATION, - changeScreenType, - setFluidStatus, - toggleAnalysisNotification, - toggleChallengeActionNotification, - toggleChallengeDuelNotification, - toggleChallengeExplorationNotification, -} from './global.actions' - -describe('global actions', () => { - it('should create an action to change screenType', () => { - const screenType = ScreenType.DESKTOP - const expectedAction: GlobalActionTypes = { - type: CHANGE_SCREEN_TYPE, - payload: screenType, - } - expect(changeScreenType(screenType)).toEqual(expectedAction) - }) - - it('should create an action to toggle challenge exploration notification', () => { - const notification = true - const expectedAction: GlobalActionTypes = { - type: TOGGLE_CHALLENGE_EXPLORATION_NOTIFICATION, - payload: notification, - } - expect(toggleChallengeExplorationNotification(notification)).toEqual( - expectedAction - ) - }) - - it('should create an action to toggle challenge action notification', () => { - const notification = true - const expectedAction: GlobalActionTypes = { - type: TOGGLE_CHALLENGE_ACTION_NOTIFICATION, - payload: notification, - } - expect(toggleChallengeActionNotification(notification)).toEqual( - expectedAction - ) - }) - - it('should create an action to toggle challenge duel notification', () => { - const notification = true - const expectedAction: GlobalActionTypes = { - type: TOGGLE_CHALLENGE_DUEL_NOTIFICATION, - payload: notification, - } - expect(toggleChallengeDuelNotification(notification)).toEqual( - expectedAction - ) - }) - - it('should create an action to toggle analysis notification', () => { - const notification = true - const expectedAction: GlobalActionTypes = { - type: TOGGLE_ANALYSIS_NOTIFICATION, - payload: notification, - } - expect(toggleAnalysisNotification(notification)).toEqual(expectedAction) - }) - - it('should create an action to set fluid status', () => { - const fluidStatus = mockInitialGlobalState.fluidStatus - const expectedAction: GlobalActionTypes = { - type: SET_FLUID_STATUS, - payload: fluidStatus, - } - expect(setFluidStatus(fluidStatus)).toEqual(expectedAction) - }) -}) diff --git a/src/store/global/global.actions.ts b/src/store/global/global.actions.ts deleted file mode 100644 index 77a9fda4ef0157c3e7e4d90de942a82214d31260..0000000000000000000000000000000000000000 --- a/src/store/global/global.actions.ts +++ /dev/null @@ -1,204 +0,0 @@ -import { FluidType } from 'enum/fluid.enum' -import { ScreenType } from 'enum/screen.enum' -import { FluidConnection, FluidStatus, TermsStatus } from 'models' -import { PartnersInfo } from 'models/partnersInfo.model' -import { Notes } from 'models/releaseNotes.model' -import { SgeStore } from 'models/sgeStore.model' -import { defaultAction } from 'store' - -export const CHANGE_SCREEN_TYPE = 'CHANGE_SCREEN_TYPE' -export const SET_FLUID_STATUS = 'SET_FLUID_STATUS' -export const SET_PARTNERS_INFO = 'SET_PARTNERS_INFO' -export const SET_SHOULD_REFRESH_CONSENT = 'SET_SHOULD_REFRESH_CONSENT' -export const SHOW_RELEASE_NOTES = 'SHOW_RELEASE_NOTES' -export const TOGGLE_ANALYSIS_NOTIFICATION = 'TOGGLE_ANALYSIS_NOTIFICATION' -export const TOGGLE_CHALLENGE_ACTION_NOTIFICATION = - 'TOGGLE_CHALLENGE_ACTION_NOTIFICATION' -export const TOGGLE_CHALLENGE_DUEL_NOTIFICATION = - 'TOGGLE_CHALLENGE_DUEL_NOTIFICATION' -export const TOGGLE_CHALLENGE_EXPLORATION_NOTIFICATION = - 'TOGGLE_CHALLENGE_EXPLORATION_NOTIFICATION' -export const UPDATE_FLUID_CONNECTION = 'UPDATE_FLUID_CONNECTION' -export const UPDATE_SGE_CONNECT = 'UPDATE_SGE_CONNECT' -export const UPDATE_TERMS_VALIDATION = 'UPDATE_TERMS_VALIDATION' - -interface ChangeScreenType { - type: typeof CHANGE_SCREEN_TYPE - payload?: ScreenType -} - -interface SetPartnersInfo { - type: typeof SET_PARTNERS_INFO - payload?: PartnersInfo -} - -interface SetPartnersInfo { - type: typeof SET_PARTNERS_INFO - payload?: PartnersInfo -} - -interface ToggleChallengeExplorationNotification { - type: typeof TOGGLE_CHALLENGE_EXPLORATION_NOTIFICATION - payload?: boolean -} - -interface ToggleChallengeActionNotification { - type: typeof TOGGLE_CHALLENGE_ACTION_NOTIFICATION - payload?: boolean -} - -interface ToggleChallengeDuelNotification { - type: typeof TOGGLE_CHALLENGE_DUEL_NOTIFICATION - payload?: boolean -} - -interface ToggleAnalysisNotification { - type: typeof TOGGLE_ANALYSIS_NOTIFICATION - payload?: boolean -} - -interface SetFluidStatus { - type: typeof SET_FLUID_STATUS - payload?: FluidStatus[] -} - -interface UpdatedFluidConnection { - type: typeof UPDATE_FLUID_CONNECTION - payload?: { fluidType: FluidType; fluidConnection: FluidConnection } -} - -interface UpdateTermValidation { - type: typeof UPDATE_TERMS_VALIDATION - payload?: TermsStatus -} - -interface ShowReleaseNotes { - type: typeof SHOW_RELEASE_NOTES - payload?: { show: boolean; notes: Notes[]; redirectLink?: string } -} - -interface SetShouldRefreshConsent { - type: typeof SET_SHOULD_REFRESH_CONSENT - payload?: boolean -} -interface UpdateSGEConnect { - type: typeof UPDATE_SGE_CONNECT - payload?: SgeStore -} - -export function changeScreenType(screenType: ScreenType): ChangeScreenType { - return { - type: CHANGE_SCREEN_TYPE, - payload: screenType, - } -} - -export function showReleaseNotes( - show: boolean, - notes: Notes[], - redirectLink?: string -): ShowReleaseNotes { - return { - type: SHOW_RELEASE_NOTES, - payload: { show, notes, redirectLink }, - } -} - -export function toggleChallengeExplorationNotification( - notification: boolean -): ToggleChallengeExplorationNotification { - return { - type: TOGGLE_CHALLENGE_EXPLORATION_NOTIFICATION, - payload: notification, - } -} - -export function toggleChallengeActionNotification( - notification: boolean -): ToggleChallengeActionNotification { - return { - type: TOGGLE_CHALLENGE_ACTION_NOTIFICATION, - payload: notification, - } -} - -export function toggleChallengeDuelNotification( - notification: boolean -): ToggleChallengeDuelNotification { - return { - type: TOGGLE_CHALLENGE_DUEL_NOTIFICATION, - payload: notification, - } -} - -export function toggleAnalysisNotification( - notification: boolean -): ToggleAnalysisNotification { - return { - type: TOGGLE_ANALYSIS_NOTIFICATION, - payload: notification, - } -} - -export function setFluidStatus(fluidStatus: FluidStatus[]): SetFluidStatus { - return { - type: SET_FLUID_STATUS, - payload: fluidStatus, - } -} -export function updatedFluidConnection( - fluidType: FluidType, - fluidConnection: FluidConnection -): UpdatedFluidConnection { - return { - type: UPDATE_FLUID_CONNECTION, - payload: { fluidType, fluidConnection }, - } -} - -export function updateTermValidation( - termsStatus: TermsStatus -): UpdateTermValidation { - return { - type: UPDATE_TERMS_VALIDATION, - payload: termsStatus, - } -} - -export function setPartnersInfo(partnersInfo: PartnersInfo): SetPartnersInfo { - return { - type: SET_PARTNERS_INFO, - payload: partnersInfo, - } -} - -export function setShouldRefreshConsent( - shouldRefreshConsent: boolean -): SetShouldRefreshConsent { - return { - type: SET_SHOULD_REFRESH_CONSENT, - payload: shouldRefreshConsent, - } -} - -export function updateSgeStore(sgeStore: SgeStore): UpdateSGEConnect { - return { - type: UPDATE_SGE_CONNECT, - payload: sgeStore, - } -} - -export type GlobalActionTypes = - | ChangeScreenType - | ToggleChallengeExplorationNotification - | ToggleChallengeActionNotification - | ToggleChallengeDuelNotification - | ToggleAnalysisNotification - | SetFluidStatus - | UpdatedFluidConnection - | UpdateTermValidation - | ShowReleaseNotes - | SetShouldRefreshConsent - | UpdateSGEConnect - | SetPartnersInfo - | typeof defaultAction diff --git a/src/store/global/global.reducer.spec.ts b/src/store/global/global.reducer.spec.ts deleted file mode 100644 index b97675431307e3b08589a453d901050d830b00f8..0000000000000000000000000000000000000000 --- a/src/store/global/global.reducer.spec.ts +++ /dev/null @@ -1,213 +0,0 @@ -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 { defaultAction } from 'store' -import { accountsData } from '../../../tests/__mocks__/accountsData.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, - SET_FLUID_STATUS, - TOGGLE_ANALYSIS_NOTIFICATION, - TOGGLE_CHALLENGE_ACTION_NOTIFICATION, - TOGGLE_CHALLENGE_DUEL_NOTIFICATION, - TOGGLE_CHALLENGE_EXPLORATION_NOTIFICATION, -} from './global.actions' -import { globalReducer } from './global.reducer' - -const nowUtc = DateTime.local().setZone('utc', { keepLocalTime: true }) -const mockDataDates = Array(3).fill(nowUtc) - -describe('global reducer', () => { - it('should return the initial state', () => { - const state = globalReducer(undefined, { ...defaultAction }) - expect(state).toEqual(mockInitialGlobalState) - }) - - describe('CHANGE_SCREEN_TYPE', () => { - it('should handle CHANGE_SCREEN_TYPE with payload', () => { - const state = globalReducer(mockInitialGlobalState, { - type: CHANGE_SCREEN_TYPE, - payload: ScreenType.DESKTOP, - }) - expect(state).toEqual({ - ...mockInitialGlobalState, - screenType: ScreenType.DESKTOP, - }) - }) - it('should handle CHANGE_SCREEN_TYPE without payload', () => { - const state = globalReducer(mockInitialGlobalState, { - type: CHANGE_SCREEN_TYPE, - }) - expect(state).toEqual(mockInitialGlobalState) - }) - }) - - describe('TOGGLE_CHALLENGE_EXPLORATION_NOTIFICATION', () => { - it('should handle TOGGLE_CHALLENGE_EXPLORATION_NOTIFICATION with payload', () => { - const state = globalReducer(mockInitialGlobalState, { - type: TOGGLE_CHALLENGE_EXPLORATION_NOTIFICATION, - payload: true, - }) - expect(state).toEqual({ - ...mockInitialGlobalState, - challengeExplorationNotification: true, - }) - }) - - it('should handle TOGGLE_CHALLENGE_EXPLORATION_NOTIFICATION without payload', () => { - const state = globalReducer(mockInitialGlobalState, { - type: TOGGLE_CHALLENGE_EXPLORATION_NOTIFICATION, - }) - expect(state).toEqual(mockInitialGlobalState) - }) - }) - - describe('TOGGLE_CHALLENGE_ACTION_NOTIFICATION', () => { - it('should handle TOGGLE_CHALLENGE_ACTION_NOTIFICATION with payload', () => { - const state = globalReducer(mockInitialGlobalState, { - type: TOGGLE_CHALLENGE_ACTION_NOTIFICATION, - payload: true, - }) - expect(state).toEqual({ - ...mockInitialGlobalState, - challengeActionNotification: true, - }) - }) - it('should handle TOGGLE_CHALLENGE_ACTION_NOTIFICATION without payload', () => { - const state = globalReducer(mockInitialGlobalState, { - type: TOGGLE_CHALLENGE_ACTION_NOTIFICATION, - }) - expect(state).toEqual(mockInitialGlobalState) - }) - }) - - describe('TOGGLE_CHALLENGE_DUEL_NOTIFICATION', () => { - it('should handle TOGGLE_CHALLENGE_DUEL_NOTIFICATION with payload', () => { - const state = globalReducer(mockInitialGlobalState, { - type: TOGGLE_CHALLENGE_DUEL_NOTIFICATION, - payload: true, - }) - expect(state).toEqual({ - ...mockInitialGlobalState, - challengeDuelNotification: true, - }) - }) - it('should handle TOGGLE_CHALLENGE_DUEL_NOTIFICATION without payload', () => { - const state = globalReducer(mockInitialGlobalState, { - type: TOGGLE_CHALLENGE_DUEL_NOTIFICATION, - }) - expect(state).toEqual(mockInitialGlobalState) - }) - }) - - describe('TOGGLE_ANALYSIS_NOTIFICATION', () => { - it('should handle TOGGLE_ANALYSIS_NOTIFICATION with payload', () => { - const state = globalReducer(mockInitialGlobalState, { - type: TOGGLE_ANALYSIS_NOTIFICATION, - payload: true, - }) - expect(state).toEqual({ - ...mockInitialGlobalState, - analysisNotification: true, - }) - }) - it('should handle TOGGLE_ANALYSIS_NOTIFICATION without payload', () => { - const state = globalReducer(mockInitialGlobalState, { - type: TOGGLE_ANALYSIS_NOTIFICATION, - }) - expect(state).toEqual(mockInitialGlobalState) - }) - }) - - it('should handle SET_FLUID_STATUS with payload', () => { - const fluidStatus: FluidStatus[] = [ - { - fluidType: FluidType.ELECTRICITY, - status: FluidState.ERROR, - maintenance: false, - firstDataDate: mockDataDates[FluidType.ELECTRICITY], - lastDataDate: mockDataDates[FluidType.ELECTRICITY], - connection: { - konnector: konnectorsData[0], - account: accountsData[0], - trigger: triggersData[0], - triggerState: null, - shouldLaunchKonnector: false, - isUpdating: false, - konnectorConfig: { - name: 'Enedis', - oauth: true, - slug: FluidSlugType.ELECTRICITY, - siteLink: 'https://mon-compte-particulier.enedis.fr/donnees/', - activation: 'https://mon-compte-particulier.enedis.fr/donnees/', - }, - }, - }, - { - fluidType: FluidType.WATER, - status: FluidState.ERROR, - maintenance: false, - firstDataDate: mockDataDates[FluidType.WATER], - lastDataDate: mockDataDates[FluidType.WATER], - connection: { - konnector: konnectorsData[1], - account: accountsData[1], - trigger: triggersData[1], - triggerState: null, - shouldLaunchKonnector: false, - isUpdating: false, - konnectorConfig: { - name: 'Eau Publique du Grand Lyon', - oauth: false, - slug: FluidSlugType.WATER, - siteLink: - 'https://agence.eaudugrandlyon.com/inscription.aspx#subc-now', - activation: '', - }, - }, - }, - { - fluidType: FluidType.GAS, - status: FluidState.KONNECTOR_NOT_FOUND, - maintenance: false, - firstDataDate: mockDataDates[FluidType.GAS], - lastDataDate: mockDataDates[FluidType.GAS], - connection: { - konnector: null, - account: accountsData[2], - trigger: null, - triggerState: null, - shouldLaunchKonnector: false, - isUpdating: false, - konnectorConfig: { - name: 'GRDF', - oauth: true, - slug: FluidSlugType.GAS, - siteLink: 'https://monespace.grdf.fr/creation-particulier', - activation: '', - }, - }, - }, - ] - const state = globalReducer(mockInitialGlobalState, { - type: SET_FLUID_STATUS, - payload: fluidStatus, - }) - expect(state).toEqual({ - ...mockInitialGlobalState, - fluidStatus: fluidStatus, - fluidTypes: [FluidType.ELECTRICITY, FluidType.WATER], - }) - }) - - it('should handle SET_FLUID_STATUS without payload', () => { - const state = globalReducer(mockInitialGlobalState, { - type: SET_FLUID_STATUS, - }) - expect(state).toEqual(mockInitialGlobalState) - }) -}) diff --git a/src/store/global/global.slice.spec.ts b/src/store/global/global.slice.spec.ts new file mode 100644 index 0000000000000000000000000000000000000000..b4fc3d507a4612d127f3e2196de7e5012c5bdd2d --- /dev/null +++ b/src/store/global/global.slice.spec.ts @@ -0,0 +1,322 @@ +/* eslint-disable camelcase */ +import { FluidSlugType, FluidState, FluidType, ScreenType, Usage } from 'enums' +import { DateTime } from 'luxon' +import { FluidStatus, PartnersInfo, TermsStatus } from 'models' +import { SgeStore } from 'models/sgeStore.model' +import { accountsData } from 'tests/__mocks__/accountsData.mock' +import { konnectorsData } from 'tests/__mocks__/konnectorsData.mock' +import { mockGlobalState } from 'tests/__mocks__/store' +import { triggersData } from 'tests/__mocks__/triggersData.mock' +import { + changeScreenType, + globalSlice, + setFluidStatus, + setLastEpglLogin, + setPartnersInfo, + setShouldRefreshConsent, + showReleaseNotes, + toggleAnalysisNotification, + toggleChallengeActionNotification, + toggleChallengeDuelNotification, + toggleChallengeExplorationNotification, + updateEcogestureFilter, + updateFluidConnection, + updateSgeStore, + updateTermsStatus, +} from './global.slice' + +const nowUtc = DateTime.local().setZone('utc', { keepLocalTime: true }) +const mockDataDates = Array(3).fill(nowUtc) + +const fluidStatus: FluidStatus[] = [ + { + fluidType: FluidType.ELECTRICITY, + status: FluidState.ERROR, + maintenance: false, + firstDataDate: mockDataDates[FluidType.ELECTRICITY], + lastDataDate: mockDataDates[FluidType.ELECTRICITY], + connection: { + konnector: konnectorsData[0], + account: accountsData[0], + trigger: triggersData[0], + triggerState: null, + shouldLaunchKonnector: false, + isUpdating: false, + konnectorConfig: { + name: 'Enedis', + oauth: true, + slug: FluidSlugType.ELECTRICITY, + siteLink: 'https://mon-compte-particulier.enedis.fr/donnees/', + activation: 'https://mon-compte-particulier.enedis.fr/donnees/', + }, + }, + }, + { + fluidType: FluidType.WATER, + status: FluidState.ERROR, + maintenance: false, + firstDataDate: mockDataDates[FluidType.WATER], + lastDataDate: mockDataDates[FluidType.WATER], + connection: { + konnector: konnectorsData[1], + account: accountsData[1], + trigger: triggersData[1], + triggerState: null, + shouldLaunchKonnector: false, + isUpdating: false, + konnectorConfig: { + name: 'Eau Publique du Grand Lyon', + oauth: false, + slug: FluidSlugType.WATER, + siteLink: 'https://agence.eaudugrandlyon.com/inscription.aspx#subc-now', + activation: '', + }, + }, + }, + { + fluidType: FluidType.GAS, + status: FluidState.KONNECTOR_NOT_FOUND, + maintenance: false, + firstDataDate: mockDataDates[FluidType.GAS], + lastDataDate: mockDataDates[FluidType.GAS], + connection: { + konnector: null, + account: accountsData[2], + trigger: null, + triggerState: null, + shouldLaunchKonnector: false, + isUpdating: false, + konnectorConfig: { + name: 'GRDF', + oauth: true, + slug: FluidSlugType.GAS, + siteLink: 'https://monespace.grdf.fr/creation-particulier', + activation: '', + }, + }, + }, +] + +describe('globalSlice', () => { + it('should return the initial state', () => { + const initialState = globalSlice.reducer(undefined, { type: undefined }) + expect(initialState).toEqual(mockGlobalState) + }) + + it('should handle changeScreenType', () => { + const state = globalSlice.reducer( + mockGlobalState, + changeScreenType(ScreenType.DESKTOP) + ) + expect(state).toEqual({ + ...mockGlobalState, + screenType: ScreenType.DESKTOP, + }) + }) + it('should handle toggleChallengeExplorationNotification', () => { + const state = globalSlice.reducer( + mockGlobalState, + toggleChallengeExplorationNotification(true) + ) + expect(state).toEqual({ + ...mockGlobalState, + challengeExplorationNotification: true, + }) + }) + it('should handle toggleChallengeActionNotification', () => { + const state = globalSlice.reducer( + mockGlobalState, + toggleChallengeActionNotification(true) + ) + expect(state).toEqual({ + ...mockGlobalState, + challengeActionNotification: true, + }) + }) + it('should handle toggleChallengeDuelNotification', () => { + const state = globalSlice.reducer( + mockGlobalState, + toggleChallengeDuelNotification(true) + ) + expect(state).toEqual({ + ...mockGlobalState, + challengeDuelNotification: true, + }) + }) + it('should handle toggleAnalysisNotification', () => { + const state = globalSlice.reducer( + mockGlobalState, + toggleAnalysisNotification(true) + ) + expect(state).toEqual({ + ...mockGlobalState, + analysisNotification: true, + }) + }) + it('should handle setFluidStatus', () => { + const state = globalSlice.reducer( + mockGlobalState, + setFluidStatus(fluidStatus) + ) + expect(state).toEqual({ + ...mockGlobalState, + fluidStatus: fluidStatus, + fluidTypes: [FluidType.ELECTRICITY, FluidType.WATER], + }) + }) + + it('should handle updateTermsStatus', () => { + const expectedTermsStatus: TermsStatus = { + accepted: false, + versionType: 'major', + } + const state = globalSlice.reducer( + mockGlobalState, + updateTermsStatus(expectedTermsStatus) + ) + expect(state).toEqual({ + ...mockGlobalState, + termsStatus: expectedTermsStatus, + }) + }) + + it('should handle showReleaseNotes', () => { + const state = globalSlice.reducer( + mockGlobalState, + showReleaseNotes({ + show: true, + notes: [{ description: 'desc', title: 'Title' }], + }) + ) + expect(state).toEqual({ + ...mockGlobalState, + releaseNotes: { + show: true, + notes: [{ description: 'desc', title: 'Title' }], + }, + }) + }) + + it('should handle setPartnersInfo', () => { + const expectedPartnersInfo: PartnersInfo = { + egl_failure: true, + enedis_failure: true, + grdf_failure: true, + notification_activated: true, + } + const state = globalSlice.reducer( + mockGlobalState, + setPartnersInfo(expectedPartnersInfo) + ) + expect(state).toEqual({ + ...mockGlobalState, + partnersInfo: expectedPartnersInfo, + }) + }) + + it('should handle setShouldRefreshConsent', () => { + const state = globalSlice.reducer( + mockGlobalState, + setShouldRefreshConsent(true) + ) + expect(state).toEqual({ + ...mockGlobalState, + shouldRefreshConsent: true, + }) + }) + it('should handle setSgeConnect', () => { + const expectedSgeConnect: SgeStore = { + address: 'address', + city: 'city', + currentStep: 1, + dataConsent: true, + firstName: 'firstName', + lastName: 'lastName', + pdl: 12345678901234, + pdlConfirm: true, + shouldLaunchAccount: true, + zipCode: 99999, + } + const state = globalSlice.reducer( + mockGlobalState, + updateSgeStore(expectedSgeConnect) + ) + expect(state).toEqual({ + ...mockGlobalState, + sgeConnect: expectedSgeConnect, + }) + }) + it('should handle updateFluidConnection', () => { + const state = globalSlice.reducer( + mockGlobalState, + updateFluidConnection({ + fluidType: FluidType.ELECTRICITY, + fluidConnection: { + shouldLaunchKonnector: true, + isUpdating: true, + konnector: null, + account: null, + trigger: null, + triggerState: null, + konnectorConfig: { + name: 'config', + oauth: false, + slug: FluidSlugType.ELECTRICITY, + siteLink: 'link', + activation: 'activation', + }, + }, + }) + ) + expect(state).toEqual({ + ...mockGlobalState, + fluidStatus: [ + { + fluidType: FluidType.ELECTRICITY, + firstDataDate: null, + lastDataDate: null, + maintenance: false, + status: 0, + connection: { + shouldLaunchKonnector: true, + isUpdating: true, + konnector: null, + account: null, + trigger: null, + triggerState: null, + konnectorConfig: { + name: 'config', + oauth: false, + slug: FluidSlugType.ELECTRICITY, + siteLink: 'link', + activation: 'activation', + }, + }, + }, + ...mockGlobalState.fluidStatus.slice(1), + ], + }) + }) + + it('should handle setLastEpglLogin', () => { + const state = globalSlice.reducer( + mockGlobalState, + setLastEpglLogin('1234567') + ) + expect(state).toEqual({ + ...mockGlobalState, + lastEpglLogin: '1234567', + }) + }) + + it('should change the ecogestureFilter', () => { + const state = globalSlice.reducer( + mockGlobalState, + updateEcogestureFilter(Usage.AIR_CONDITIONING) + ) + expect(state).toEqual({ + ...mockGlobalState, + ecogestureFilter: Usage.AIR_CONDITIONING, + }) + }) +}) diff --git a/src/store/global/global.reducer.ts b/src/store/global/global.slice.ts similarity index 50% rename from src/store/global/global.reducer.ts rename to src/store/global/global.slice.ts index 7736b81b29f6bba534254812fbc998440020df79..f251ba453ab9d70ae6008aa7156ba6695c49aa98 100644 --- a/src/store/global/global.reducer.ts +++ b/src/store/global/global.slice.ts @@ -1,24 +1,15 @@ /* eslint-disable camelcase */ -import { FluidState, FluidType } from 'enum/fluid.enum' -import { FluidSlugType } from 'enum/fluidSlug.enum' -import { ScreenType } from 'enum/screen.enum' -import { FluidStatus, GlobalState } from 'models' -import { Reducer } from 'redux' +import { PayloadAction, createSlice } from '@reduxjs/toolkit' +import { FluidSlugType, FluidState, FluidType, ScreenType, Usage } from 'enums' import { - CHANGE_SCREEN_TYPE, - GlobalActionTypes, - SET_FLUID_STATUS, - SET_PARTNERS_INFO, - SET_SHOULD_REFRESH_CONSENT, - SHOW_RELEASE_NOTES, - TOGGLE_ANALYSIS_NOTIFICATION, - TOGGLE_CHALLENGE_ACTION_NOTIFICATION, - TOGGLE_CHALLENGE_DUEL_NOTIFICATION, - TOGGLE_CHALLENGE_EXPLORATION_NOTIFICATION, - UPDATE_FLUID_CONNECTION, - UPDATE_SGE_CONNECT, - UPDATE_TERMS_VALIDATION, -} from 'store/global/global.actions' + FluidConnection, + FluidStatus, + GlobalState, + Notes, + PartnersInfo, + SgeStore, + TermsStatus, +} from 'models' const initialState: GlobalState = { screenType: ScreenType.MOBILE, @@ -127,8 +118,20 @@ const initialState: GlobalState = { pdlConfirm: false, shouldLaunchAccount: false, }, + ecogestureFilter: Usage.ALL, + lastEpglLogin: '', } +type UpdatedFluidConnection = PayloadAction<{ + fluidType: FluidType + fluidConnection: FluidConnection +}> +type ShowReleaseNote = PayloadAction<{ + show: boolean + notes: Notes[] + redirectLink?: string +}> + const getFluidTypesFromStatus = (fluidStatus: FluidStatus[]): FluidType[] => { const fluidTypes: FluidType[] = [] fluidStatus.forEach(fluid => { @@ -146,66 +149,82 @@ const getFluidTypesFromStatus = (fluidStatus: FluidStatus[]): FluidType[] => { return fluidTypes.sort() } -export const globalReducer: Reducer<GlobalState, GlobalActionTypes> = ( - state = initialState, - action -) => { - if (action.payload == undefined) return state - - const updateState = (updates: Partial<GlobalState>): GlobalState => ({ - ...state, - ...updates, - }) - - switch (action.type) { - case CHANGE_SCREEN_TYPE: - return updateState({ screenType: action.payload }) - - case TOGGLE_CHALLENGE_EXPLORATION_NOTIFICATION: - return updateState({ challengeExplorationNotification: action.payload }) - - case TOGGLE_CHALLENGE_ACTION_NOTIFICATION: - return updateState({ challengeActionNotification: action.payload }) - - case TOGGLE_CHALLENGE_DUEL_NOTIFICATION: - return updateState({ challengeDuelNotification: action.payload }) - - case TOGGLE_ANALYSIS_NOTIFICATION: - return updateState({ analysisNotification: action.payload }) - - case SET_FLUID_STATUS: - return updateState({ - fluidStatus: action.payload, - fluidTypes: getFluidTypesFromStatus(action.payload), - }) - - case UPDATE_TERMS_VALIDATION: - return updateState({ termsStatus: action.payload }) - - case SHOW_RELEASE_NOTES: - return updateState({ releaseNotes: action.payload }) - - case SET_PARTNERS_INFO: - return updateState({ partnersInfo: action.payload }) - - case SET_SHOULD_REFRESH_CONSENT: - return updateState({ shouldRefreshConsent: action.payload }) - - case UPDATE_FLUID_CONNECTION: - const updatedFluidStatus = [...state.fluidStatus] - const fluidType: FluidType = action.payload.fluidType - const findIndex = state.fluidStatus.findIndex( - fluid => fluid.fluidType === fluidType - ) - updatedFluidStatus[findIndex].connection = action.payload.fluidConnection - return { - ...state, - fluidStatus: updatedFluidStatus, - } - case UPDATE_SGE_CONNECT: - return updateState({ sgeConnect: action.payload }) +export const globalSlice = createSlice({ + name: 'global', + initialState, + reducers: { + changeScreenType: (state, action: PayloadAction<ScreenType>) => { + state.screenType = action.payload + }, + toggleChallengeExplorationNotification: ( + state, + action: PayloadAction<boolean> + ) => { + state.challengeExplorationNotification = action.payload + }, - default: - return state - } -} + toggleChallengeActionNotification: ( + state, + action: PayloadAction<boolean> + ) => { + state.challengeActionNotification = action.payload + }, + toggleChallengeDuelNotification: ( + state, + action: PayloadAction<boolean> + ) => { + state.challengeDuelNotification = action.payload + }, + toggleAnalysisNotification: (state, action: PayloadAction<boolean>) => { + state.analysisNotification = action.payload + }, + setFluidStatus: (state, action: PayloadAction<FluidStatus[]>) => { + state.fluidStatus = action.payload + state.fluidTypes = getFluidTypesFromStatus(action.payload) + }, + updateTermsStatus: (state, action: PayloadAction<TermsStatus>) => { + state.termsStatus = action.payload + }, + showReleaseNotes: (state, action: ShowReleaseNote) => { + state.releaseNotes = action.payload + }, + setPartnersInfo: (state, action: PayloadAction<PartnersInfo>) => { + state.partnersInfo = action.payload + }, + setShouldRefreshConsent: (state, action: PayloadAction<boolean>) => { + state.shouldRefreshConsent = action.payload + }, + updateFluidConnection: ( + state, + { payload: { fluidType, fluidConnection } }: UpdatedFluidConnection + ) => { + state.fluidStatus[fluidType].connection = fluidConnection + }, + setLastEpglLogin: (state, action: PayloadAction<string>) => { + state.lastEpglLogin = action.payload + }, + updateSgeStore: (state, action: PayloadAction<SgeStore>) => { + state.sgeConnect = action.payload + }, + updateEcogestureFilter: (state, action: PayloadAction<Usage>) => { + state.ecogestureFilter = action.payload + }, + }, +}) + +export const { + changeScreenType, + setFluidStatus, + setLastEpglLogin, + setPartnersInfo, + setShouldRefreshConsent, + showReleaseNotes, + toggleAnalysisNotification, + toggleChallengeActionNotification, + toggleChallengeDuelNotification, + toggleChallengeExplorationNotification, + updateEcogestureFilter, + updateFluidConnection, + updateSgeStore, + updateTermsStatus, +} = globalSlice.actions diff --git a/src/store/hooks.ts b/src/store/hooks.ts new file mode 100644 index 0000000000000000000000000000000000000000..21a319209c0bc26aa1d502d3593373536345c336 --- /dev/null +++ b/src/store/hooks.ts @@ -0,0 +1,9 @@ +// eslint-disable-next-line @typescript-eslint/no-restricted-imports +import { TypedUseSelectorHook, useDispatch, useSelector } from 'react-redux' +import { AppDispatch, AppState } from './store' + +// Typed hooks +// https://redux.js.org/tutorials/typescript-quick-start#define-typed-hooks + +export const useAppDispatch: () => AppDispatch = useDispatch +export const useAppSelector: TypedUseSelectorHook<AppState> = useSelector diff --git a/src/store/index.ts b/src/store/index.ts deleted file mode 100644 index b703e919b028617eb7997a7dfe0a307c17ea0b75..0000000000000000000000000000000000000000 --- a/src/store/index.ts +++ /dev/null @@ -1,109 +0,0 @@ -import * as Sentry from '@sentry/react' -import { Client } from 'cozy-client' -import { - AnalysisState, - ChallengeState, - GlobalState, - ModalState, - Profile, - ProfileType, -} from 'models' -import { ChartState } from 'models/chart.model' -import { ProfileEcogesture } from 'models/profileEcogesture.model' -import { - Store, - applyMiddleware, - combineReducers, - compose, - createStore, -} from 'redux' -import { composeWithDevTools } from 'redux-devtools-extension' -import thunkMiddleware from 'redux-thunk' -import { globalReducer } from 'store/global/global.reducer' -import { AnalysisActionTypes, analysisSlice } from './analysis/analysis.slice' -import { - ChallengeActionTypes, - challengeSlice, -} from './challenge/challenge.slice' -import { ChartActionTypes, chartSlice } from './chart/chart.slice' -import { GlobalActionTypes } from './global/global.actions' -import { ModalActionTypes, modalSlice } from './modal/modal.slice' -import { ProfileActionTypes } from './profile/profile.actions' -import { profileReducer } from './profile/profile.reducer' -import { ProfileEcogestureActionTypes } from './profileEcogesture/profileEcogesture.actions' -import { profileEcogestureReducer } from './profileEcogesture/profileEcogesture.reducer' -import { - ProfileTypeActionTypes, - profileTypeSlice, -} from './profileType/profileType.slice' - -export interface EcolyoState { - analysis: AnalysisState - challenge: ChallengeState - chart: ChartState - global: GlobalState - modal: ModalState - profile: Profile - profileEcogesture: ProfileEcogesture - profileType: ProfileType -} - -export const defaultAction = { type: null, payload: undefined } - -const ecolyoReducer = combineReducers({ - analysis: analysisSlice.reducer, - challenge: challengeSlice.reducer, - chart: chartSlice.reducer, - global: globalReducer, - modal: modalSlice.reducer, - profile: profileReducer, - profileEcogesture: profileEcogestureReducer, - profileType: profileTypeSlice.reducer, -}) - -export interface AppStore { - ecolyo: EcolyoState - cozy: unknown -} - -const appActions = { - ...analysisSlice.actions, - ...challengeSlice.actions, - ...chartSlice.actions, - ...modalSlice.actions, - ...profileTypeSlice.actions, -} - -// TODO refactor types with AppActionsTypes = typeof appActions -export type AppActionsTypes = - | AnalysisActionTypes - | ChallengeActionTypes - | ChartActionTypes - | GlobalActionTypes - | ModalActionTypes - | ProfileActionTypes - | ProfileEcogestureActionTypes - | ProfileTypeActionTypes - -const sentryReduxEnhancer = Sentry.createReduxEnhancer({}) - -const configureStore = (client: Client, persistedState: any) => { - const middlewares = [thunkMiddleware.withExtraArgument({ client })] - const composeEnhancers = - composeWithDevTools({ trace: true, actionCreators: appActions }) || compose - - const store: Store<AppStore, AppActionsTypes> = createStore( - combineReducers({ - ecolyo: ecolyoReducer, - cozy: client.reducer(), - persistedState, - }), - composeEnhancers( - // eslint-disable-next-line prefer-spread - applyMiddleware.apply(null, middlewares), - sentryReduxEnhancer - ) - ) - return store -} -export default configureStore diff --git a/src/store/modal/modal.slice.spec.ts b/src/store/modal/modal.slice.spec.ts index 644eaffa2934c85ba2290160954034015ba22daa..f9f98b9a361882b03d822a27eb47db29a16dab92 100644 --- a/src/store/modal/modal.slice.spec.ts +++ b/src/store/modal/modal.slice.spec.ts @@ -1,6 +1,6 @@ import { ModalState } from 'models' -import { mockCustomPopup } from '../../../tests/__mocks__/customPopup.mock' -import { mockInitialModalState } from '../../../tests/__mocks__/store' +import { mockCustomPopup } from 'tests/__mocks__/customPopup.mock' +import { mockModalState } from 'tests/__mocks__/store' import { modalSlice, openConnectionModal, @@ -12,17 +12,14 @@ import { describe('modal reducer', () => { it('should return the initial state', () => { const initialState = modalSlice.reducer(undefined, { type: undefined }) - expect(initialState).toEqual(mockInitialModalState) + expect(initialState).toEqual(mockModalState) }) describe('openFeedbackModal', () => { it('should handle openFeedbackModal', () => { - const state = modalSlice.reducer( - mockInitialModalState, - openFeedbackModal(true) - ) + const state = modalSlice.reducer(mockModalState, openFeedbackModal(true)) expect(state).toEqual({ - ...mockInitialModalState, + ...mockModalState, isFeedbacksOpen: true, }) }) @@ -35,11 +32,11 @@ describe('modal reducer', () => { grdf: true, } it('should have all partners to false by default', () => { - const state = modalSlice.reducer(mockInitialModalState, { + const state = modalSlice.reducer(mockModalState, { type: undefined, }) const expectedResult: ModalState = { - ...mockInitialModalState, + ...mockModalState, partnersIssueModal: { egl: false, enedis: false, @@ -50,11 +47,11 @@ describe('modal reducer', () => { }) it('should handle openPartnersModal to set all partners to true', () => { const state = modalSlice.reducer( - mockInitialModalState, + mockModalState, openPartnersModal({ egl: true, enedis: true, grdf: true }) ) const expectedResult: ModalState = { - ...mockInitialModalState, + ...mockModalState, partnersIssueModal: { ...partnersModalAllTrue, }, @@ -64,7 +61,7 @@ describe('modal reducer', () => { it('should handle openPartnersModal to set some partners to false', () => { const state = modalSlice.reducer( { - ...mockInitialModalState, + ...mockModalState, partnersIssueModal: { ...partnersModalAllTrue, }, @@ -72,7 +69,7 @@ describe('modal reducer', () => { openPartnersModal({ egl: true, enedis: false, grdf: false }) ) const expectedResult: ModalState = { - ...mockInitialModalState, + ...mockModalState, partnersIssueModal: { egl: true, enedis: false, @@ -83,11 +80,11 @@ describe('modal reducer', () => { }) it('should handle openConnectionModal', () => { const state = modalSlice.reducer( - mockInitialModalState, + mockModalState, openConnectionModal(true) ) expect(state).toEqual({ - ...mockInitialModalState, + ...mockModalState, isConnectionModalOpen: true, }) }) @@ -96,11 +93,11 @@ describe('modal reducer', () => { describe('customPopup', () => { it('should handle setCustomPopup', () => { const state = modalSlice.reducer( - mockInitialModalState, + mockModalState, setCustomPopup(mockCustomPopup) ) expect(state).toEqual({ - ...mockInitialModalState, + ...mockModalState, customPopupModal: mockCustomPopup, }) }) diff --git a/src/store/modal/modal.slice.ts b/src/store/modal/modal.slice.ts index 8f4afd48cf616ef370e1bfc7f235bef4a666aca2..c65edeeca335afd67272d43e1cc2fa14b99caa76 100644 --- a/src/store/modal/modal.slice.ts +++ b/src/store/modal/modal.slice.ts @@ -17,34 +17,26 @@ const initialState: ModalState = { }, } -type OpenFeedbackModalAction = PayloadAction<boolean> -type OpenConnectionModalAction = PayloadAction<boolean> type OpenPartnersModalAction = PayloadAction<{ egl: boolean enedis: boolean grdf: boolean }> -type SetCustomPopup = PayloadAction<CustomPopup> - -export type ModalActionTypes = - | OpenFeedbackModalAction - | OpenPartnersModalAction - | SetCustomPopup export const modalSlice = createSlice({ name: 'modal', initialState, reducers: { - openFeedbackModal: (state, action: OpenFeedbackModalAction) => { + openFeedbackModal: (state, action: PayloadAction<boolean>) => { state.isFeedbacksOpen = action.payload }, openPartnersModal: (state, action: OpenPartnersModalAction) => { state.partnersIssueModal = action.payload }, - openConnectionModal: (state, action: OpenConnectionModalAction) => { + openConnectionModal: (state, action: PayloadAction<boolean>) => { state.isConnectionModalOpen = action.payload }, - setCustomPopup: (state, action: SetCustomPopup) => { + setCustomPopup: (state, action: PayloadAction<CustomPopup>) => { state.customPopupModal = action.payload }, }, diff --git a/src/store/profile/profile.action.spec.ts b/src/store/profile/profile.action.spec.ts deleted file mode 100644 index bd942e0879fd04363c8bc7c29039108e41ff3589..0000000000000000000000000000000000000000 --- a/src/store/profile/profile.action.spec.ts +++ /dev/null @@ -1,36 +0,0 @@ -import { profileData } from '../../../tests/__mocks__/profileData.mock' -import { createMockEcolyoStore } from '../../../tests/__mocks__/store' -import { updateProfile, UPDATE_PROFILE } from './profile.actions' - -const mockUpdateProfile = jest.fn() -jest.mock('services/profile.service', () => { - return jest.fn(() => { - return { - updateProfile: mockUpdateProfile, - } - }) -}) - -describe('profile actions', () => { - const store = createMockEcolyoStore() - beforeEach(() => { - store.clearActions() - }) - it('should create an UPDATE_PROFILE action when profile is updated', async () => { - mockUpdateProfile.mockResolvedValueOnce(profileData) - const expectedActions = [ - { - type: UPDATE_PROFILE, - payload: profileData, - }, - ] - await store.dispatch(updateProfile(profileData)) - expect(store.getActions()).toEqual(expectedActions) - }) - - it('should not create action when profile is not updated', async () => { - mockUpdateProfile.mockResolvedValueOnce(null) - await store.dispatch(updateProfile(profileData)) - expect(store.getActions()).toEqual([]) - }) -}) diff --git a/src/store/profile/profile.actions.ts b/src/store/profile/profile.actions.ts deleted file mode 100644 index 4d3808f88bd9ad846956f91f837cfc8b9b34e595..0000000000000000000000000000000000000000 --- a/src/store/profile/profile.actions.ts +++ /dev/null @@ -1,35 +0,0 @@ -import { Client } from 'cozy-client' -import { Profile } from 'models' -import { Dispatch } from 'react' -import ProfileService from 'services/profile.service' -import { AppStore, defaultAction } from 'store' - -export const UPDATE_PROFILE = 'UPDATE_PROFILE' - -export interface UpdateProfile { - type: typeof UPDATE_PROFILE - payload?: Profile -} - -export type ProfileActionTypes = UpdateProfile | typeof defaultAction - -function updateProfileSuccess(updatedProfile: Profile): UpdateProfile { - return { - type: UPDATE_PROFILE, - payload: updatedProfile, - } -} - -export function updateProfile(updates: Partial<Profile>): any { - return async ( - dispatch: Dispatch<UpdateProfile>, - getState: () => AppStore, - { client }: { client: Client } - ) => { - const profileService = new ProfileService(client) - const updatedProfile = await profileService.updateProfile(updates) - if (updatedProfile) { - dispatch(updateProfileSuccess(updatedProfile)) - } - } -} diff --git a/src/store/profile/profile.reducer.spec.ts b/src/store/profile/profile.reducer.spec.ts deleted file mode 100644 index 95c22aaef918c56d97060f0a2d8191982e6314d0..0000000000000000000000000000000000000000 --- a/src/store/profile/profile.reducer.spec.ts +++ /dev/null @@ -1,27 +0,0 @@ -import { defaultAction } from 'store' -import { profileData } from '../../../tests/__mocks__/profileData.mock' -import { mockInitialProfileState } from '../../../tests/__mocks__/store' -import { UPDATE_PROFILE } from './profile.actions' -import { profileReducer } from './profile.reducer' - -describe('profile reducer', () => { - it('should return the initial state', () => { - const state = profileReducer(undefined, { ...defaultAction }) - expect(state).toEqual(mockInitialProfileState) - }) - - it('should handle UPDATE_PROFILE with payload', () => { - const state = profileReducer(mockInitialProfileState, { - type: UPDATE_PROFILE, - payload: profileData, - }) - expect(state).toEqual(profileData) - }) - - it('should handle UPDATE_PROFILE without payload', () => { - const state = profileReducer(mockInitialProfileState, { - type: UPDATE_PROFILE, - }) - expect(state).toEqual(mockInitialProfileState) - }) -}) diff --git a/src/store/profile/profile.slice.spec.ts b/src/store/profile/profile.slice.spec.ts new file mode 100644 index 0000000000000000000000000000000000000000..aca5f4bbd7aec52404cfa22fcbd3c0cf01e80732 --- /dev/null +++ b/src/store/profile/profile.slice.spec.ts @@ -0,0 +1,11 @@ +import { mockProfileState } from '../../../tests/__mocks__/store' +import { profileSlice } from './profile.slice' + +describe('profile slice', () => { + it('should return the initial state', () => { + const initialState = profileSlice.reducer(undefined, { + type: undefined, + }) + expect(initialState).toEqual(mockProfileState) + }) +}) diff --git a/src/store/profile/profile.slice.ts b/src/store/profile/profile.slice.ts new file mode 100644 index 0000000000000000000000000000000000000000..c2d5c3a5c3539b51bef2219bbfeda08974125b1c --- /dev/null +++ b/src/store/profile/profile.slice.ts @@ -0,0 +1,78 @@ +import { createAsyncThunk, createSlice } from '@reduxjs/toolkit' +import { Client } from 'cozy-client' +import { DateTime } from 'luxon' +import { Profile } from 'models' +import ProfileService from 'services/profile.service' +import { AppDispatch, AppState } from 'store/store' + +const initialState: Profile = { + id: '', + ecogestureHash: '', + challengeHash: '', + duelHash: '', + quizHash: '', + explorationHash: '', + isFirstConnection: false, + partnersIssueSeenDate: { + enedis: DateTime.fromISO('0000-01-01T00:00:00.000Z', { + zone: 'utc', + }), + egl: DateTime.fromISO('0000-01-01T00:00:00.000Z', { + zone: 'utc', + }), + grdf: DateTime.fromISO('0000-01-01T00:00:00.000Z', { + zone: 'utc', + }), + }, + lastConnectionDate: DateTime.fromISO('0000-01-01T00:00:00.000Z', { + zone: 'utc', + }), + customPopupDate: DateTime.fromISO('0000-01-01T00:00:00.000Z', { + zone: 'utc', + }), + haveSeenLastAnalysis: true, + sendAnalysisNotification: true, + sendConsumptionAlert: false, + waterDailyConsumptionLimit: 0, + mailToken: '', + monthlyAnalysisDate: DateTime.fromISO('0000-01-01T00:00:00.000Z', { + zone: 'utc', + }), + isProfileTypeCompleted: false, + isProfileEcogestureCompleted: false, + onboarding: { + isWelcomeSeen: true, + }, + haveSeenEcogestureModal: false, + activateHalfHourDate: DateTime.fromISO('0000-01-01T00:00:00.000Z', { + zone: 'utc', + }), +} + +export const profileSlice = createSlice({ + name: 'profile', + initialState, + reducers: {}, + extraReducers: builder => { + builder.addCase(updateProfile.fulfilled, (state, action) => { + Object.assign(state, action.payload) + }) + }, +}) + +/** + * Thunk updating profile in couch DB. + * If the profile has an update, dispatch it to the app + */ +export const updateProfile = createAsyncThunk< + Profile | void, + Partial<Profile>, + { dispatch: AppDispatch; state: AppState; extra: { client: Client } } +>('profile/updateProfile', async (profileUpdates, thunkAPI) => { + const client = thunkAPI.extra.client + const profileService = new ProfileService(client) + const updatedProfile = await profileService.updateProfile(profileUpdates) + if (updatedProfile) { + return updatedProfile + } +}) diff --git a/src/store/profileEcogesture/profileEcogesture.action.spec.ts b/src/store/profileEcogesture/profileEcogesture.action.spec.ts deleted file mode 100644 index ad0f42b7948f74982e2040eb6e39b49b863760bd..0000000000000000000000000000000000000000 --- a/src/store/profileEcogesture/profileEcogesture.action.spec.ts +++ /dev/null @@ -1,41 +0,0 @@ -import { mockProfileEcogesture } from '../../../tests/__mocks__/profileEcogesture.mock' -import { createMockEcolyoStore } from '../../../tests/__mocks__/store' -import { - updateProfileEcogesture, - UPDATE_PROFILE_ECOGESTURE, -} from './profileEcogesture.actions' - -const mockUpdateProfileEcogesture = jest.fn() -const mockNewProfileEcogestureEntry = jest.fn() -jest.mock('services/profileEcogesture.service', () => { - return jest.fn(() => { - return { - updateProfileEcogesture: mockUpdateProfileEcogesture, - newProfileEcogestureEntry: mockNewProfileEcogestureEntry, - } - }) -}) - -describe('profileEcogesture actions', () => { - const store = createMockEcolyoStore() - beforeEach(() => { - store.clearActions() - }) - it('should create an UPDATE_PROFILE_ECOGESTURE action when ecogestureProfile is updated', async () => { - mockUpdateProfileEcogesture.mockResolvedValueOnce(mockProfileEcogesture) - const expectedActions = [ - { - type: UPDATE_PROFILE_ECOGESTURE, - payload: mockProfileEcogesture, - }, - ] - await store.dispatch(updateProfileEcogesture(mockProfileEcogesture)) - expect(store.getActions()).toEqual(expectedActions) - }) - - it('should not create action when ProfileEcogesture is not updated', async () => { - mockUpdateProfileEcogesture.mockResolvedValueOnce(null) - await store.dispatch(updateProfileEcogesture(mockProfileEcogesture)) - expect(store.getActions()).toEqual([]) - }) -}) diff --git a/src/store/profileEcogesture/profileEcogesture.actions.ts b/src/store/profileEcogesture/profileEcogesture.actions.ts deleted file mode 100644 index 77140546584eca81839145ed7e8571534cf4c82c..0000000000000000000000000000000000000000 --- a/src/store/profileEcogesture/profileEcogesture.actions.ts +++ /dev/null @@ -1,70 +0,0 @@ -import { Client } from 'cozy-client' -import { PROFILEECOGESTURE_DOCTYPE } from 'doctypes/com-grandlyon-ecolyo-profileecogesture' -import { ProfileEcogesture } from 'models/profileEcogesture.model' -import { Dispatch } from 'react' -import ProfileEcogestureService from 'services/profileEcogesture.service' -import { AppStore, defaultAction } from 'store' - -// TODO never used ? -export const CREATE_NEW_PROFILE_ECOGESTURE = 'CREATE_NEW_PROFILE_ECOGESTURE' -export const UPDATE_PROFILE_ECOGESTURE = 'UPDATE_PROFILE_ECOGESTURE' - -export interface UpdateProfileEcogesture { - type: typeof UPDATE_PROFILE_ECOGESTURE - payload?: ProfileEcogesture -} - -// TODO never used ? -export interface CreateNewProfileEcogesture { - type: typeof CREATE_NEW_PROFILE_ECOGESTURE - payload?: ProfileEcogesture -} - -export type ProfileEcogestureActionTypes = - | UpdateProfileEcogesture - | CreateNewProfileEcogesture - | typeof defaultAction - -export function updateProfileEcogestureSuccess( - updatedProfileEcogesture: ProfileEcogesture -): UpdateProfileEcogesture { - return { - type: UPDATE_PROFILE_ECOGESTURE, - payload: updatedProfileEcogesture, - } -} - -export function updateProfileEcogesture( - updates: Partial<ProfileEcogesture> -): any { - return async ( - dispatch: Dispatch<UpdateProfileEcogesture>, - getState: () => AppStore, - { client }: { client: Client } - ) => { - const profileEcogestureService = new ProfileEcogestureService(client) - const updatedProfileEcogesture = - await profileEcogestureService.updateProfileEcogesture(updates) - if (updatedProfileEcogesture) { - dispatch(updateProfileEcogestureSuccess(updatedProfileEcogesture)) - } - } -} - -export function newProfileEcogestureEntry( - updates: Partial<ProfileEcogesture> -): any { - return async ( - dispatch: Dispatch<UpdateProfileEcogesture>, - getState: () => AppStore, - { client }: { client: Client } - ) => { - const { data: newProfileEcogesture } = await client.create( - PROFILEECOGESTURE_DOCTYPE, - updates - ) - if (newProfileEcogesture) { - dispatch(updateProfileEcogestureSuccess(newProfileEcogesture)) - } - } -} diff --git a/src/store/profileEcogesture/profileEcogesture.reducer.spec.ts b/src/store/profileEcogesture/profileEcogesture.reducer.spec.ts deleted file mode 100644 index 1158a9881f3f659e21808483c764c1a324095e8a..0000000000000000000000000000000000000000 --- a/src/store/profileEcogesture/profileEcogesture.reducer.spec.ts +++ /dev/null @@ -1,29 +0,0 @@ -import { defaultAction } from 'store' -import { - mockProfileEcogesture, - mockProfileEcogestureUpdated, -} from '../../../tests/__mocks__/profileEcogesture.mock' -import { UPDATE_PROFILE_ECOGESTURE } from './profileEcogesture.actions' -import { profileEcogestureReducer } from './profileEcogesture.reducer' - -describe('profileEcogesture reducer', () => { - it('should return the initial state', () => { - const state = profileEcogestureReducer(undefined, { ...defaultAction }) - expect(state).toEqual(mockProfileEcogesture) - }) - - it('should handle UPDATE_PROFILE_ECOGESTURE with payload', () => { - const state = profileEcogestureReducer(mockProfileEcogesture, { - type: UPDATE_PROFILE_ECOGESTURE, - payload: mockProfileEcogestureUpdated, - }) - expect(state).toEqual(mockProfileEcogestureUpdated) - }) - - it('should handle UPDATE_PROFILE_ECOGESTURE without payload', () => { - const state = profileEcogestureReducer(mockProfileEcogesture, { - type: UPDATE_PROFILE_ECOGESTURE, - }) - expect(state).toEqual(mockProfileEcogesture) - }) -}) diff --git a/src/store/profileEcogesture/profileEcogesture.reducer.ts b/src/store/profileEcogesture/profileEcogesture.reducer.ts deleted file mode 100644 index 511c813a06fd8b23eb1a58185a1343762274da53..0000000000000000000000000000000000000000 --- a/src/store/profileEcogesture/profileEcogesture.reducer.ts +++ /dev/null @@ -1,33 +0,0 @@ -import { IndividualOrCollective, WarmingType } from 'enum/profileType.enum' -import { ProfileEcogesture } from 'models/profileEcogesture.model' -import { Reducer } from 'redux' -import { - CREATE_NEW_PROFILE_ECOGESTURE, - ProfileEcogestureActionTypes, - UPDATE_PROFILE_ECOGESTURE, -} from './profileEcogesture.actions' - -const initialState: ProfileEcogesture = { - heating: IndividualOrCollective.INDIVIDUAL, - warmingFluid: WarmingType.ELECTRICITY, - hotWater: IndividualOrCollective.INDIVIDUAL, - equipments: [], -} - -export const profileEcogestureReducer: Reducer< - ProfileEcogesture, - ProfileEcogestureActionTypes -> = (state = initialState, action) => { - if (action.payload == undefined) return state - - switch (action.type) { - case UPDATE_PROFILE_ECOGESTURE: - case CREATE_NEW_PROFILE_ECOGESTURE: - return { - ...state, - ...action.payload, - } - default: - return state - } -} diff --git a/src/store/profileEcogesture/profileEcogesture.slice.spec.ts b/src/store/profileEcogesture/profileEcogesture.slice.spec.ts new file mode 100644 index 0000000000000000000000000000000000000000..290c69278fd2419c3f13b74c406c84e742c92115 --- /dev/null +++ b/src/store/profileEcogesture/profileEcogesture.slice.spec.ts @@ -0,0 +1,24 @@ +import { + mockProfileEcogesture, + mockProfileEcogestureUpdated, +} from 'tests/__mocks__/profileEcogesture.mock' +import { profileEcogestureSlice } from './profileEcogesture.slice' + +describe('profileEcogesture slice', () => { + it('should return the initial state', () => { + const initialState = profileEcogestureSlice.reducer(undefined, { + type: undefined, + }) + expect(initialState).toEqual(mockProfileEcogesture) + }) + + it('should handle setProfileEcogesture', () => { + const state = profileEcogestureSlice.reducer( + mockProfileEcogesture, + profileEcogestureSlice.actions.setProfileEcogesture( + mockProfileEcogestureUpdated + ) + ) + expect(state).toEqual(mockProfileEcogestureUpdated) + }) +}) diff --git a/src/store/profileEcogesture/profileEcogesture.slice.ts b/src/store/profileEcogesture/profileEcogesture.slice.ts new file mode 100644 index 0000000000000000000000000000000000000000..73b40b443406955ae193c134b02c9a29e1be4a03 --- /dev/null +++ b/src/store/profileEcogesture/profileEcogesture.slice.ts @@ -0,0 +1,49 @@ +import { PayloadAction, createAsyncThunk, createSlice } from '@reduxjs/toolkit' +import { Client } from 'cozy-client' +import { PROFILEECOGESTURE_DOCTYPE } from 'doctypes' +import { IndividualOrCollective, WarmingType } from 'enums' +import { ProfileEcogesture } from 'models' +import { AppDispatch, AppState } from 'store/store' + +const initialState: ProfileEcogesture = { + heating: IndividualOrCollective.INDIVIDUAL, + warmingFluid: WarmingType.ELECTRICITY, + hotWater: IndividualOrCollective.INDIVIDUAL, + equipments: [], +} + +export const profileEcogestureSlice = createSlice({ + name: 'profileEcogesture', + initialState, + reducers: { + setProfileEcogesture: (state, action: PayloadAction<ProfileEcogesture>) => { + Object.assign(state, action.payload) + }, + }, + extraReducers: builder => { + builder.addCase(newProfileEcogestureEntry.fulfilled, (state, action) => { + Object.assign(state, action.payload) + }) + }, +}) + +export const { setProfileEcogesture } = profileEcogestureSlice.actions + +/** + * Thunk creating a new profile ecogesture in couch DB. + * Then dispatch it to the app + */ +export const newProfileEcogestureEntry = createAsyncThunk< + ProfileEcogesture | void, + Partial<ProfileEcogesture>, + { dispatch: AppDispatch; state: AppState; extra: { client: Client } } +>('profileEcogesture/newProfileEcogesture', async (updates, thunkAPI) => { + const client = thunkAPI.extra.client + const { data: newProfileEcogesture } = await client.create( + PROFILEECOGESTURE_DOCTYPE, + updates + ) + if (newProfileEcogesture) { + return newProfileEcogesture + } +}) diff --git a/src/store/profileType/profileType.slice.spec.ts b/src/store/profileType/profileType.slice.spec.ts index f4fb708b43e73f4cf39bffc4496c6cc09f015718..d359df254235ff64b45bfb2e7ea14daf509740ea 100644 --- a/src/store/profileType/profileType.slice.spec.ts +++ b/src/store/profileType/profileType.slice.spec.ts @@ -1,8 +1,8 @@ -import { EquipmentType } from 'enum/ecogesture.enum' -import { FluidType } from 'enum/fluid.enum' import { ConstructionYear, + EquipmentType, Floor, + FluidType, HotWaterEquipment, HotWaterFluid, HousingType, @@ -10,10 +10,10 @@ import { OutsideFacingWalls, ThreeChoicesAnswer, WarmingType, -} from 'enum/profileType.enum' +} from 'enums' import { DateTime } from 'luxon' import { ProfileType } from 'models' -import { mockInitialProfileTypeState } from '../../../tests/__mocks__/store' +import { mockProfileTypeState } from 'tests/__mocks__/store' import { profileTypeSlice, setProfileType } from './profileType.slice' describe('profileType reducer', () => { @@ -21,17 +21,17 @@ describe('profileType reducer', () => { const initialState = profileTypeSlice.reducer(undefined, { type: undefined, }) - expect(initialState).toEqual(mockInitialProfileTypeState) + expect(initialState).toEqual(mockProfileTypeState) }) describe('setProfileType', () => { it('should handle update with partial payload', () => { const state = profileTypeSlice.reducer( - mockInitialProfileTypeState, + mockProfileTypeState, setProfileType({ housingType: HousingType.APARTMENT }) ) expect(state).toEqual({ - ...mockInitialProfileTypeState, + ...mockProfileTypeState, housingType: HousingType.APARTMENT, }) }) @@ -58,7 +58,7 @@ describe('profileType reducer', () => { equipments: [EquipmentType.BOILER], } const state = profileTypeSlice.reducer( - mockInitialProfileTypeState, + mockProfileTypeState, setProfileType(newProfileType) ) expect(state).toEqual(newProfileType) diff --git a/src/store/profileType/profileType.slice.ts b/src/store/profileType/profileType.slice.ts index e267f6fce5791f0abd351be67f24a1b1554e71ff..1a6cdd51610ee997aea857f2558264575e5cd71d 100644 --- a/src/store/profileType/profileType.slice.ts +++ b/src/store/profileType/profileType.slice.ts @@ -1,8 +1,8 @@ import { PayloadAction, createSlice } from '@reduxjs/toolkit' -import { FluidType } from 'enum/fluid.enum' import { ConstructionYear, Floor, + FluidType, HotWaterEquipment, HotWaterFluid, HousingType, @@ -11,7 +11,7 @@ import { OutsideFacingWalls, ThreeChoicesAnswer, WarmingType, -} from 'enum/profileType.enum' +} from 'enums' import { DateTime } from 'luxon' import { ProfileType } from 'models' @@ -39,15 +39,11 @@ const initialState: ProfileType = { equipments: [], } -type SetProfileType = PayloadAction<Partial<ProfileType>> - -export type ProfileTypeActionTypes = SetProfileType - export const profileTypeSlice = createSlice({ name: 'profileType', initialState, reducers: { - setProfileType: (state, action: SetProfileType) => { + setProfileType: (state, action: PayloadAction<Partial<ProfileType>>) => { Object.assign(state, action.payload) }, }, diff --git a/src/store/store.ts b/src/store/store.ts new file mode 100644 index 0000000000000000000000000000000000000000..3348dcf8f15bd1514dbc12ae164d0c4355077756 --- /dev/null +++ b/src/store/store.ts @@ -0,0 +1,83 @@ +import { Dispatch, configureStore } from '@reduxjs/toolkit' +import * as Sentry from '@sentry/react' +import { Client } from 'cozy-client' +import { + AnalysisState, + ChallengeState, + ChartState, + GlobalState, + ModalState, + Profile, + ProfileEcogesture, + ProfileType, +} from 'models' +import { combineReducers } from 'redux' +import { analysisSlice } from './analysis/analysis.slice' +import { challengeSlice } from './challenge/challenge.slice' +import { chartSlice } from './chart/chart.slice' +import { globalSlice } from './global/global.slice' +import { modalSlice } from './modal/modal.slice' +import { profileSlice } from './profile/profile.slice' +import { profileEcogestureSlice } from './profileEcogesture/profileEcogesture.slice' +import { profileTypeSlice } from './profileType/profileType.slice' + +export interface AppState { + cozy: unknown + ecolyo: { + analysis: AnalysisState + challenge: ChallengeState + chart: ChartState + global: GlobalState + modal: ModalState + profile: Profile + profileEcogesture: ProfileEcogesture + profileType: ProfileType + } +} + +/** Partial interfaces used for testing purposes */ +export interface MockEcolyoState { + analysis: Partial<AnalysisState> + challenge: Partial<ChallengeState> + chart: Partial<ChartState> + global: Partial<GlobalState> + modal: Partial<ModalState> + profile: Partial<Profile> + profileEcogesture: Partial<ProfileEcogesture> + profileType: Partial<ProfileType> +} + +const sentryReduxEnhancer = Sentry.createReduxEnhancer({}) + +const ecolyo = combineReducers({ + analysis: analysisSlice.reducer, + challenge: challengeSlice.reducer, + chart: chartSlice.reducer, + global: globalSlice.reducer, + modal: modalSlice.reducer, + profile: profileSlice.reducer, + profileEcogesture: profileEcogestureSlice.reducer, + profileType: profileTypeSlice.reducer, +}) + +/** setupStore function to configure redux store taking an extra argument 'client' */ +export const setupStore = (client: Client) => { + const store = configureStore({ + reducer: { + cozy: client.reducer(), + ecolyo, + }, + middleware: getDefaultMiddleware => + getDefaultMiddleware({ + serializableCheck: false, + thunk: { extraArgument: { client } }, + }), + devTools: true, + enhancers: [sentryReduxEnhancer], + }) + + return store +} + +// export type AppDispatch = ReturnType<typeof setupStore>['dispatch'] +export type AppDispatch = Dispatch<any> diff --git a/src/styles/base/_color.scss b/src/styles/base/_color.scss index ed06067df8c0d8dd47eb15042d6a4eda5546a9ea..bc7fa395af58468ba90d67a3ed1cd9e1bf304b4e 100644 --- a/src/styles/base/_color.scss +++ b/src/styles/base/_color.scss @@ -11,6 +11,7 @@ $dark-background: radial-gradient( #1b1c22 100% ); $bottom-bar-grey: #32343d; +$black-shadow: #0000008c; /** RED **/ $red-primary: #d25959; diff --git a/src/styles/base/_layout.scss b/src/styles/base/_layout.scss index 63369debd4a3f418c3b063be15c330ce58711b52..688abe38d86d2d8e3e76df9400246a5ca30cd1bb 100644 --- a/src/styles/base/_layout.scss +++ b/src/styles/base/_layout.scss @@ -1,6 +1,6 @@ @import 'color'; -@import '../base/breakpoint'; -@import '../base/z-index'; +@import 'breakpoint'; +@import 'z-index'; html { background: $dark-light-2; diff --git a/src/styles/components/_barchart.scss b/src/styles/components/_barchart.scss index 7097e1166b54d81abdba7f456d5223939d5aace9..209e00d3bfa361fa0a0decfb44d9acf7a072bcb3 100644 --- a/src/styles/components/_barchart.scss +++ b/src/styles/components/_barchart.scss @@ -128,11 +128,10 @@ } } .bar-UNCOMING { - fill: $dark; + fill: $grey-dark; opacity: 0.6; &.selected { - fill: $multi-color; - filter: drop-shadow(0 -0.1rem 0.2rem $multi-color); + fill: $grey-dark; } &.disabled { &:hover { @@ -244,46 +243,15 @@ } } -/** Animatio ndelay **/ +/** Animation delay **/ .delay { animation-duration: 0.4s; } -.delay--0 { - animation-duration: 0.6s; -} -.delay--1 { - animation-duration: 0.7s; -} -.delay--2 { - animation-duration: 0.8s; -} -.delay--3 { - animation-duration: 0.9s; -} -.delay--4 { - animation-duration: 1s; -} -.delay--5 { - animation-duration: 1.1s; -} -.delay--6 { - animation-duration: 1.2s; -} -.delay--7 { - animation-duration: 1.3s; -} -.delay--8 { - animation-duration: 1.4s; -} -.delay--9 { - animation-duration: 1.5s; -} -.delay--10 { - animation-duration: 1.6s; -} -.delay--11 { - animation-duration: 1.8s; -} -.delay--12 { - animation-duration: 1.9s; + +$animation-duration-base: 0.4s; // Base animation duration + +@for $i from 0 through 48 { + .delay--#{$i} { + animation-duration: $animation-duration-base + $i * 0.08s; + } } diff --git a/src/styles/components/_buttons.scss b/src/styles/components/_buttons.scss index 8735392e47590a5fb133a2fea430b4571b7e6974..210658472e6690949f6ddc17f0e0459d179b11ec 100644 --- a/src/styles/components/_buttons.scss +++ b/src/styles/components/_buttons.scss @@ -20,16 +20,11 @@ button { } } } - &.btn-primary-negative { - @include button( - transparent, - $gold-shadow, - 1px solid $grey-dark, - transparent - ) { - background-color: rgba($grey-dark, 0.2); + &.btn-primary-challenge { + @include button($blue-light, black, 1px solid $blue-light, transparent) { + background-color: rgba($blue-light, 0.2); span:first-child { - color: rgba($gold-shadow, 0.7); + color: black; } } } @@ -37,12 +32,7 @@ button { @include button(transparent, $gold-euro, 1px solid $grey-dark); } &.btn-secondary-positive { - @include button( - transparent, - $grey-bright, - 1px solid $dark-light-2, - transparent - ) { + @include button(transparent, $grey-bright, 1px solid $white, transparent) { background-color: rgba($dark-light-2, 0.2); span:first-child { color: rgba($grey-bright, 0.7); diff --git a/src/styles/components/_card.scss b/src/styles/components/_card.scss index 4d079cef9976410cea493ff017194d90fce3a086..94634375044e4bf66b712020034a796805a442ca 100644 --- a/src/styles/components/_card.scss +++ b/src/styles/components/_card.scss @@ -10,6 +10,6 @@ background: $grey-linear-gradient-background-hover; } &.rich-card { - padding: 24px 16px; + padding: 16px; } } diff --git a/src/styles/index.css b/src/styles/index.css deleted file mode 100644 index 8ab6ce1cff1ddfb8986f684c802ca0717039d5fe..0000000000000000000000000000000000000000 --- a/src/styles/index.css +++ /dev/null @@ -1,1708 +0,0 @@ -/* Cozy UI utilities classes */ -@import '~cozy-ui/dist/cozy-ui.min.css'; -/* Cozy UI React components styles */ -@import '~cozy-ui/transpiled/react/stylesheet.css'; -/* App styles */ -/** BLACK **/ -/** RED **/ -/** YELLOW **/ -/** ORANGE **/ -/** BLUE **/ -/** GREEN **/ -/** WHITE **/ -/** GREY **/ -/** App colors **/ -/** TABS GRADIENT **/ -/** SCROLLBAR **/ -@import url('https://fonts.googleapis.com/css2?family=Lato:wght@400;700&display=swap'); -html { - background: #121212; -} - -body { - background: #121212; - overflow: unset !important; -} - -.column { - display: flex; - flex-direction: column; -} - -.row { - display: flex; - flex-direction: row; -} - -.cozy-bar { - width: 100%; - display: flex; - align-items: center; - justify-content: center; - margin-left: 0; -} -@media only screen and (max-width: 768px) { - .cozy-bar { - margin-left: 1.25rem; - } -} - -[role='banner'] .coz-bar-container { - background-color: #ffffff; -} -@media only screen and (max-width: 768px) { - [role='banner'] .coz-bar-container { - padding: 0.6rem 0 0 0; - background-color: unset; - } -} - -.coz-bar-wrapper { - box-shadow: unset !important; - background: unset !important; -} - -.cv-button { - width: 4.25rem; -} - -.coz-label { - color: #32363f; -} - -.header { - display: flex; - align-items: center; - flex-direction: column; - overflow: hidden; - width: 100%; - z-index: 18; - position: fixed; - top: 48px; - left: 0; -} -@media only screen and (max-width: 768px) { - .header { - top: 0; - } -} -.header .header-top { - background: radial-gradient(circle, rgb(52, 54, 65) 0%, rgb(27, 28, 34) 100%); - width: 100%; -} -.header .header-top .header-text { - padding: 0 1rem 1rem 1rem; - color: #e0e0e0; -} -.header .header-content { - margin: 0 0 0 220px; - display: flex; - flex-direction: column; -} -@media only screen and (max-width: 1023px) { - .header .header-content { - margin: 0; - } -} -@media only screen and (max-width: 768px) { - .header .header-content { - margin: 60px 0 0 0; - } -} -.header .header-content .header-content-top { - display: flex; - flex-direction: row; -} -.header .header-content .header-content-top.header-content-top-right { - justify-content: flex-end; -} -.header .header-content .header-content-top .header-text { - padding: 2rem 1rem; - flex: 1; -} -.header .header-content .header-content-top .header-text-desktop { - display: flex; - flex: 1; - padding: 2rem 1.25rem; - color: #e0e0e0; -} -.header .header-content .header-content-top .header-back-button { - padding: 0 0.75rem; -} -@media only screen and (max-width: 768px) { - .header .header-content .header-content-top .header-text { - padding: 0 1rem 1rem 1rem; - color: #e0e0e0; - } - .header .header-content .header-content-top .header-text-desktop { - display: none; - } - .header .header-content .header-content-top .header-feedbacks-button { - display: none; - } -} - -.content-view-loading { - height: 80vh; - width: 100%; - display: flex; - flex-direction: column; - justify-content: center; - align-items: center; - color: #e0e0e0; -} -.content-view-loading .content-view-loading-text { - padding-top: 1rem; - margin: 0 2rem; - text-align: center; -} -.content-view-loading .content-view-loading-button { - max-width: 50vw; - margin-top: 1rem; -} - -[role='main'] { - /* width */ - /* Track */ - /* Handle */ -} -[role='main']::-webkit-scrollbar { - width: 10px; -} -[role='main']::-webkit-scrollbar-track { - background: #3e4045; -} -[role='main']::-webkit-scrollbar-thumb { - background: #6f7074; -} - -/** BLACK **/ -/** RED **/ -/** YELLOW **/ -/** ORANGE **/ -/** BLUE **/ -/** GREEN **/ -/** WHITE **/ -/** GREY **/ -/** App colors **/ -/** TABS GRADIENT **/ -/** SCROLLBAR **/ -/** BLACK **/ -/** RED **/ -/** YELLOW **/ -/** ORANGE **/ -/** BLUE **/ -/** GREEN **/ -/** WHITE **/ -/** GREY **/ -/** App colors **/ -/** TABS GRADIENT **/ -/** SCROLLBAR **/ -* { - font-family: Lato, sans-serif; -} - -h1, -h2, -h3, -h4, -h5, -h6, -p { - color: #a0a0a0; - font-family: Lato, sans-serif; -} - -.home-title { - font-size: 1rem; - font-family: Lato, sans-serif; - font-style: normal; - font-weight: normal; - line-height: 120%; - text-transform: uppercase; -} - -.app-title { - font-family: Lato, sans-serif; - font-style: normal; - font-weight: bold; - font-size: 21px; - line-height: 24px; - text-align: center; - letter-spacing: 0.15px; - color: #e0e0e0; - text-shadow: 0px -1px 0px #060609, 0px 1px 0px rgba(255, 255, 255, 0.07); -} - -.isBuilding { - color: #e3b82a; - margin-left: 0.8rem; - margin-right: 0.8rem; -} - -.text-10, -.text-10-italic, -.text-10-bold, -.text-10-bold-capitalize, -.text-10-bold-uppercase, -.text-10-normal, -.text-10-normal-150, -.text-10-normal-uppercase { - font-style: normal; - font-size: 0.625rem; - line-height: 120%; -} -.text-10-normal, -.text-10-normal-150, -.text-10-normal-uppercase { - font-weight: normal; -} -.text-10-normal-uppercase { - text-transform: uppercase; -} -.text-10-normal-150 { - line-height: 150%; -} -.text-10-bold, -.text-10-bold-capitalize, -.text-10-bold-uppercase { - font-weight: 700; -} -.text-10-bold-uppercase { - text-transform: uppercase; -} -.text-10-bold-capitalize { - text-transform: capitalize; -} -.text-10-italic { - font-style: italic; - font-weight: normal; -} - -.text-14, -.text-14-italic, -.text-14-bold, -.text-14-bold-capitalize, -.text-14-bold-uppercase, -.text-14-normal, -.text-14-normal-150, -.text-14-normal-uppercase { - font-style: normal; - font-size: 0.875rem; - line-height: 120%; -} -.text-14-normal, -.text-14-normal-150, -.text-14-normal-uppercase { - font-weight: normal; -} -.text-14-normal-uppercase { - text-transform: uppercase; -} -.text-14-normal-150 { - line-height: 150%; -} -.text-14-bold, -.text-14-bold-capitalize, -.text-14-bold-uppercase { - font-weight: 700; -} -.text-14-bold-uppercase { - text-transform: uppercase; -} -.text-14-bold-capitalize { - text-transform: capitalize; -} -.text-14-italic { - font-style: italic; - font-weight: normal; -} - -.text-15, -.text-15-italic, -.text-15-bold, -.text-15-bold-capitalize, -.text-15-bold-uppercase, -.text-15-normal, -.text-15-normal-150, -.text-15-normal-uppercase { - font-style: normal; - font-size: 0.938rem; - line-height: 120%; -} -.text-15-normal, -.text-15-normal-150, -.text-15-normal-uppercase { - font-weight: normal; -} -.text-15-normal-uppercase { - text-transform: uppercase; -} -.text-15-normal-150 { - line-height: 150%; -} -.text-15-bold, -.text-15-bold-capitalize, -.text-15-bold-uppercase { - font-weight: 700; -} -.text-15-bold-uppercase { - text-transform: uppercase; -} -.text-15-bold-capitalize { - text-transform: capitalize; -} -.text-15-italic { - font-style: italic; - font-weight: normal; -} - -.text-16, -.text-16-italic, -.text-16-bold, -.text-16-bold-capitalize, -.text-16-bold-uppercase, -.text-16-normal, -.text-16-normal-150, -.text-16-normal-uppercase { - font-style: normal; - font-size: 1rem; - line-height: 120%; -} -.text-16-normal, -.text-16-normal-150, -.text-16-normal-uppercase { - font-weight: normal; -} -.text-16-normal-uppercase { - text-transform: uppercase; -} -.text-16-normal-150 { - line-height: 150%; -} -.text-16-bold, -.text-16-bold-capitalize, -.text-16-bold-uppercase { - font-weight: 700; -} -.text-16-bold-uppercase { - text-transform: uppercase; -} -.text-16-bold-capitalize { - text-transform: capitalize; -} -.text-16-italic { - font-style: italic; - font-weight: normal; -} - -.text-18, -.text-18-italic, -.text-18-bold, -.text-18-bold-capitalize, -.text-18-bold-uppercase, -.text-18-normal, -.text-18-normal-150, -.text-18-normal-uppercase { - font-style: normal; - font-size: 1.125rem; - line-height: 120%; -} -.text-18-normal, -.text-18-normal-150, -.text-18-normal-uppercase { - font-weight: normal; -} -.text-18-normal-uppercase { - text-transform: uppercase; -} -.text-18-normal-150 { - line-height: 150%; -} -.text-18-bold, -.text-18-bold-capitalize, -.text-18-bold-uppercase { - font-weight: 700; -} -.text-18-bold-uppercase { - text-transform: uppercase; -} -.text-18-bold-capitalize { - text-transform: capitalize; -} -.text-18-italic { - font-style: italic; - font-weight: normal; -} - -.text-19, -.text-19-italic, -.text-19-bold, -.text-19-bold-capitalize, -.text-19-bold-uppercase, -.text-19-normal, -.text-19-normal-150, -.text-19-normal-uppercase { - font-style: normal; - font-size: 1.188rem; - line-height: 120%; -} -.text-19-normal, -.text-19-normal-150, -.text-19-normal-uppercase { - font-weight: normal; -} -.text-19-normal-uppercase { - text-transform: uppercase; -} -.text-19-normal-150 { - line-height: 150%; -} -.text-19-bold, -.text-19-bold-capitalize, -.text-19-bold-uppercase { - font-weight: 700; -} -.text-19-bold-uppercase { - text-transform: uppercase; -} -.text-19-bold-capitalize { - text-transform: capitalize; -} -.text-19-italic { - font-style: italic; - font-weight: normal; -} - -.text-20, -.text-20-italic, -.text-20-bold, -.text-20-bold-capitalize, -.text-20-bold-uppercase, -.text-20-normal, -.text-20-normal-150, -.text-20-normal-uppercase { - font-style: normal; - font-size: 1.25rem; - line-height: 120%; -} -.text-20-normal, -.text-20-normal-150, -.text-20-normal-uppercase { - font-weight: normal; -} -.text-20-normal-uppercase { - text-transform: uppercase; -} -.text-20-normal-150 { - line-height: 150%; -} -.text-20-bold, -.text-20-bold-capitalize, -.text-20-bold-uppercase { - font-weight: 700; -} -.text-20-bold-uppercase { - text-transform: uppercase; -} -.text-20-bold-capitalize { - text-transform: capitalize; -} -.text-20-italic { - font-style: italic; - font-weight: normal; -} - -.text-21, -.text-21-italic, -.text-21-bold, -.text-21-bold-capitalize, -.text-21-bold-uppercase, -.text-21-normal, -.text-21-normal-150, -.text-21-normal-uppercase { - font-style: normal; - font-size: 1.313rem; - line-height: 120%; -} -.text-21-normal, -.text-21-normal-150, -.text-21-normal-uppercase { - font-weight: normal; -} -.text-21-normal-uppercase { - text-transform: uppercase; -} -.text-21-normal-150 { - line-height: 150%; -} -.text-21-bold, -.text-21-bold-capitalize, -.text-21-bold-uppercase { - font-weight: 700; -} -.text-21-bold-uppercase { - text-transform: uppercase; -} -.text-21-bold-capitalize { - text-transform: capitalize; -} -.text-21-italic { - font-style: italic; - font-weight: normal; -} - -.text-22, -.text-22-italic, -.text-22-bold, -.text-22-bold-capitalize, -.text-22-bold-uppercase, -.text-22-normal, -.text-22-normal-150, -.text-22-normal-uppercase { - font-style: normal; - font-size: 1.375rem; - line-height: 120%; -} -.text-22-normal, -.text-22-normal-150, -.text-22-normal-uppercase { - font-weight: normal; -} -.text-22-normal-uppercase { - text-transform: uppercase; -} -.text-22-normal-150 { - line-height: 150%; -} -.text-22-bold, -.text-22-bold-capitalize, -.text-22-bold-uppercase { - font-weight: 700; -} -.text-22-bold-uppercase { - text-transform: uppercase; -} -.text-22-bold-capitalize { - text-transform: capitalize; -} -.text-22-italic { - font-style: italic; - font-weight: normal; -} - -.text-24, -.text-24-italic, -.text-24-bold, -.text-24-bold-capitalize, -.text-24-bold-uppercase, -.text-24-normal, -.text-24-normal-150, -.text-24-normal-uppercase { - font-style: normal; - font-size: 1.5rem; - line-height: 120%; -} -.text-24-normal, -.text-24-normal-150, -.text-24-normal-uppercase { - font-weight: normal; -} -.text-24-normal-uppercase { - text-transform: uppercase; -} -.text-24-normal-150 { - line-height: 150%; -} -.text-24-bold, -.text-24-bold-capitalize, -.text-24-bold-uppercase { - font-weight: 700; -} -.text-24-bold-uppercase { - text-transform: uppercase; -} -.text-24-bold-capitalize { - text-transform: capitalize; -} -.text-24-italic { - font-style: italic; - font-weight: normal; -} - -.text-26, -.text-26-italic, -.text-26-bold, -.text-26-bold-capitalize, -.text-26-bold-uppercase, -.text-26-normal, -.text-26-normal-150, -.text-26-normal-uppercase { - font-style: normal; - font-size: 1.625rem; - line-height: 120%; -} -.text-26-normal, -.text-26-normal-150, -.text-26-normal-uppercase { - font-weight: normal; -} -.text-26-normal-uppercase { - text-transform: uppercase; -} -.text-26-normal-150 { - line-height: 150%; -} -.text-26-bold, -.text-26-bold-capitalize, -.text-26-bold-uppercase { - font-weight: 700; -} -.text-26-bold-uppercase { - text-transform: uppercase; -} -.text-26-bold-capitalize { - text-transform: capitalize; -} -.text-26-italic { - font-style: italic; - font-weight: normal; -} - -.text-28, -.text-28-italic, -.text-28-bold, -.text-28-bold-capitalize, -.text-28-bold-uppercase, -.text-28-normal, -.text-28-normal-150, -.text-28-normal-uppercase { - font-style: normal; - font-size: 1.75rem; - line-height: 120%; -} -.text-28-normal, -.text-28-normal-150, -.text-28-normal-uppercase { - font-weight: normal; -} -.text-28-normal-uppercase { - text-transform: uppercase; -} -.text-28-normal-150 { - line-height: 150%; -} -.text-28-bold, -.text-28-bold-capitalize, -.text-28-bold-uppercase { - font-weight: 700; -} -.text-28-bold-uppercase { - text-transform: uppercase; -} -.text-28-bold-capitalize { - text-transform: capitalize; -} -.text-28-italic { - font-style: italic; - font-weight: normal; -} - -.text-36, -.text-36-italic, -.text-36-bold, -.text-36-bold-capitalize, -.text-36-bold-uppercase, -.text-36-normal, -.text-36-normal-150, -.text-36-normal-uppercase { - font-style: normal; - font-size: 2.25rem; - line-height: 120%; -} -.text-36-normal, -.text-36-normal-150, -.text-36-normal-uppercase { - font-weight: normal; -} -.text-36-normal-uppercase { - text-transform: uppercase; -} -.text-36-normal-150 { - line-height: 150%; -} -.text-36-bold, -.text-36-bold-capitalize, -.text-36-bold-uppercase { - font-weight: 700; -} -.text-36-bold-uppercase { - text-transform: uppercase; -} -.text-36-bold-capitalize { - text-transform: capitalize; -} -.text-36-italic { - font-style: italic; - font-weight: normal; -} - -/* Card */ -.card-title-on { - font-family: Lato, sans-serif; - font-style: normal; - font-weight: normal; - font-size: 1.125rem; - line-height: 120%; - color: #e0e0e0; -} - -.card-text-bold { - font-family: Lato, sans-serif; - font-style: normal; - font-weight: bold; - font-size: 1rem; - line-height: 120%; - color: #e0e0e0; -} - -.card-result { - font-family: Lato, sans-serif; - font-style: normal; - font-weight: 900; - font-size: 1.75rem; - line-height: 120%; - color: #e0e0e0; -} - -.card-indicator { - font-family: Lato, sans-serif; - font-style: normal; - font-weight: normal; - font-size: 1rem; - line-height: 120%; - color: #e0e0e0; -} - -.card-text { - font-family: Lato, sans-serif; - font-style: normal; - font-weight: normal; - font-size: 1rem; - line-height: 120%; - color: #e0e0e0; -} - -/* Chart */ -.chart-ticks-x-text { - font-family: Lato, sans-serif; - font-style: normal; - font-weight: normal; - font-size: 1rem; - line-height: 120%; -} -@media only screen and (max-width: 768px) { - .chart-ticks-x-text { - font-size: 0.685rem; - } -} - -.chart-ticks-y-text { - font-family: Lato, sans-serif; - font-style: normal; - font-weight: normal; - font-size: 0.9rem; - line-height: 120%; -} -@media only screen and (max-width: 768px) { - .chart-ticks-y-text { - font-size: 0.75rem; - } -} - -/* Cozy bar */ -.cozybar { - font-family: Lato, sans-serif; - font-style: normal; - font-weight: bold; - font-size: 1.3125rem; - line-height: 120%; - color: #e0e0e0; -} - -/** BLACK **/ -/** RED **/ -/** YELLOW **/ -/** ORANGE **/ -/** BLUE **/ -/** GREEN **/ -/** WHITE **/ -/** GREY **/ -/** App colors **/ -/** TABS GRADIENT **/ -/** SCROLLBAR **/ -.axis { - color: #7b7b7b; -} -.axis .tick-text { - fill: #7b7b7b; -} -.axis .tick-text.tick-text-selected { - fill: #e0e0e0; -} -.axis .separator { - text-align: center; - margin: 0 2px; - font-size: 1rem !important; -} - -.value-text { - fill: #7b7b7b; -} -.value-text.selected { - fill: #e0e0e0; -} - -.barContainer:hover, -.barFill:hover { - cursor: pointer; -} - -.background-true { - opacity: 0.1; -} -.background-true:hover { - cursor: pointer; -} - -.background-false { - opacity: 0; -} - -.bar-compare-ELECTRICITY:hover, -.bar-compare-GAS:hover, -.bar-compare-WATER:hover, -.bar-compare-MULTIFLUID:hover, -.bar-MULTIFLUID:hover, -.bar-WATER:hover, -.bar-GAS:hover, -.bar-ELECTRICITY:hover { - cursor: pointer; -} - -.bar-ELECTRICITY { - fill: #5d3d2a; -} -.bar-ELECTRICITY.selected { - fill: #d87b39; - filter: drop-shadow(0 -0.1rem 0.2rem #d87b39); -} - -.bar-compare-ELECTRICITY { - fill: #795c47; -} -.bar-compare-ELECTRICITY.selected { - fill: #e2bca1; - filter: drop-shadow(0 -0.1rem 0.2rem #e2bca1); -} - -.bar-WATER { - fill: #20415e; -} -.bar-WATER.selected { - fill: #3a98ec; - filter: drop-shadow(0 -0.1rem 0.2rem #3a98ec); -} - -.bar-compare-WATER { - fill: #4d5c6e; -} -.bar-compare-WATER.selected { - fill: #abd4fa; - filter: drop-shadow(0 -0.1rem 0.2rem #abd4fa); -} - -.bar-GAS { - fill: #184940; -} -.bar-GAS.selected { - fill: #45d1b8; - filter: drop-shadow(0 -0.1rem 0.2rem #45d1b8); -} - -.bar-compare-GAS { - fill: #597773; -} -.bar-compare-GAS.selected { - fill: #a8f7e9; - filter: drop-shadow(0 -0.1rem 0.2rem #a8f7e9); -} - -.bar-MULTIFLUID { - fill: #705d1d; -} -.bar-MULTIFLUID.selected { - fill: #e3b82a; - filter: drop-shadow(0 -0.1rem 0.2rem #e3b82a); -} -.bar-MULTIFLUID.disabled:hover { - cursor: default; -} - -.bar-duel { - fill: #61f0f2; -} -.bar-duel.selected { - fill: #61f0f2; - filter: drop-shadow(0 -0.1rem 0.2rem #61f0f2); -} -.bar-duel.disabled:hover { - cursor: default; -} - -.bar-UNCOMING { - fill: #242633; - opacity: 0.6; -} -.bar-UNCOMING.selected { - fill: #e3b82a; - filter: drop-shadow(0 -0.1rem 0.2rem #e3b82a); -} -.bar-UNCOMING.disabled:hover { - cursor: default; -} - -.bar-compare-MULTIFLUID { - fill: #7d6a4e; -} -.bar-compare-MULTIFLUID.selected { - fill: #ffd597; - filter: drop-shadow(0 -0.1rem 0.2rem #e3b82a); -} - -.bar-average { - stroke-width: 2; - stroke: #e3b82a; -} - -.week { - fill: #e2bca1; -} -.week.selected { - fill: #e2bca1; - filter: drop-shadow(0 -0.1rem 0.2rem #e2bca1); -} - -.weekend { - fill: #ffd597; -} -.weekend.selected { - fill: #ffd597; - filter: drop-shadow(0 -0.1rem 0.2rem #e3b82a); -} - -/** Animation **/ -.bounce-1 { - animation-name: bounce-1; - animation-timing-function: cubic-bezier(1, 1, 0.42, 1); - animation-iteration-count: 1; - transform-origin: bottom center; - transform-box: fill-box; -} - -@keyframes bounce-1 { - 0% { - transform: scale(0.1, 0.1); - } - 28% { - transform: scale(0.1, 1.1); - } - 45% { - transform: scale(0.8, 0.95); - } - 55% { - transform: scale(1, 1); - } - 65% { - transform: scale(1, 0.98); - } - 75% { - transform: scale(1, 1); - } -} -.bounce-2 { - animation-name: bounce-2; - animation-timing-function: cubic-bezier(1, 1, 0.42, 1); - animation-iteration-count: 1; - transform-origin: bottom center; - transform-box: fill-box; -} - -@keyframes bounce-2 { - 0% { - transform: scale(1, 1); - } - 28% { - transform: scale(1, 1.1); - } - 45% { - transform: scale(0.8, 0.95); - } - 55% { - transform: scale(1, 1); - } - 65% { - transform: scale(1, 0.98); - } - 75% { - transform: scale(1, 1); - } -} -.bounce-3 { - animation-name: bounce-3; - animation-timing-function: cubic-bezier(1, 1, 0.42, 1); - animation-iteration-count: 1; - transform-origin: bottom center; -} - -@keyframes bounce-3 { - 0% { - opacity: 0.6; - transform: scaleY(1); - } - 50% { - transform: scaleY(1.1); - opacity: 0.8; - } - 100% { - transform: scaleY(1); - opacity: 1; - } -} -/** Animatio ndelay **/ -.delay { - animation-duration: 0.4s; -} - -.delay--0 { - animation-duration: 0.6s; -} - -.delay--1 { - animation-duration: 0.7s; -} - -.delay--2 { - animation-duration: 0.8s; -} - -.delay--3 { - animation-duration: 0.9s; -} - -.delay--4 { - animation-duration: 1s; -} - -.delay--5 { - animation-duration: 1.1s; -} - -.delay--6 { - animation-duration: 1.2s; -} - -.delay--7 { - animation-duration: 1.3s; -} - -.delay--8 { - animation-duration: 1.4s; -} - -.delay--9 { - animation-duration: 1.5s; -} - -.delay--10 { - animation-duration: 1.6s; -} - -.delay--11 { - animation-duration: 1.8s; -} - -.delay--12 { - animation-duration: 1.9s; -} - -/** BLACK **/ -/** RED **/ -/** YELLOW **/ -/** ORANGE **/ -/** BLUE **/ -/** GREEN **/ -/** WHITE **/ -/** GREY **/ -/** App colors **/ -/** TABS GRADIENT **/ -/** SCROLLBAR **/ -button.btn-highlight { - background: radial-gradient( - 105.25% 64.58% at 49.68% 70.83%, - rgba(226, 137, 4, 0.5) 0%, - rgba(255, 255, 255, 0) 100% - ), - #f1c017; - background-color: #e3b82a; - border: none; - border-radius: 2px; - margin: 1.5rem 0 0; - width: 100%; - text-transform: initial; - cursor: pointer; -} -button.btn-highlight span:first-child { - color: #000000; -} -button.btn-highlight:hover, -button.btn-highlight:focus, -button.btn-highlight.active, -button.btn-highlight:disabled { - background-color: #b89318; -} -button.btn-highlight:disabled { - cursor: not-allowed; -} -button.btn-primary-positive { - background: transparent; - background-color: transparent; - border: 1px solid #121212; - border-radius: 2px; - margin: 1.5rem 0 0; - width: 100%; - text-transform: initial; - cursor: pointer; -} -button.btn-primary-positive span:first-child { - color: #e3b82a; -} -button.btn-primary-positive:hover, -button.btn-primary-positive:focus, -button.btn-primary-positive.active, -button.btn-primary-positive:disabled { - background-color: rgba(18, 18, 18, 0.2); -} -button.btn-primary-positive:hover span:first-child, -button.btn-primary-positive:focus span:first-child, -button.btn-primary-positive.active span:first-child, -button.btn-primary-positive:disabled span:first-child { - color: rgba(227, 184, 42, 0.7); -} -button.btn-primary-positive:disabled { - cursor: not-allowed; -} -button.btn-primary-negative { - background: transparent; - background-color: transparent; - border: 1px solid #7b7b7b; - border-radius: 2px; - margin: 1.5rem 0 0; - width: 100%; - text-transform: initial; - cursor: pointer; -} -button.btn-primary-negative span:first-child { - color: #e3b82a; -} -button.btn-primary-negative:hover, -button.btn-primary-negative:focus, -button.btn-primary-negative.active, -button.btn-primary-negative:disabled { - background-color: rgba(123, 123, 123, 0.2); -} -button.btn-primary-negative:hover span:first-child, -button.btn-primary-negative:focus span:first-child, -button.btn-primary-negative.active span:first-child, -button.btn-primary-negative:disabled span:first-child { - color: rgba(227, 184, 42, 0.7); -} -button.btn-primary-negative:disabled { - cursor: not-allowed; -} -button.btn-secondary-positive { - background: transparent; - background-color: transparent; - border: 1px solid #121212; - border-radius: 2px; - margin: 1.5rem 0 0; - width: 100%; - text-transform: initial; - cursor: pointer; -} -button.btn-secondary-positive span:first-child { - color: #e0e0e0; -} -button.btn-secondary-positive:hover, -button.btn-secondary-positive:focus, -button.btn-secondary-positive.active, -button.btn-secondary-positive:disabled { - background-color: rgba(18, 18, 18, 0.2); -} -button.btn-secondary-positive:hover span:first-child, -button.btn-secondary-positive:focus span:first-child, -button.btn-secondary-positive.active span:first-child, -button.btn-secondary-positive:disabled span:first-child { - color: rgba(224, 224, 224, 0.7); -} -button.btn-secondary-positive:disabled { - cursor: not-allowed; -} -button.btn-secondary-negative { - background: transparent; - background-color: transparent; - border: 1px solid #7b7b7b; - border-radius: 2px; - margin: 1.5rem 0 0; - width: 100%; - text-transform: initial; - cursor: pointer; -} -button.btn-secondary-negative span:first-child { - color: #e0e0e0; -} -button.btn-secondary-negative:hover, -button.btn-secondary-negative:focus, -button.btn-secondary-negative.active, -button.btn-secondary-negative:disabled { - background-color: rgba(123, 123, 123, 0.2); -} -button.btn-secondary-negative:hover span:first-child, -button.btn-secondary-negative:focus span:first-child, -button.btn-secondary-negative.active span:first-child, -button.btn-secondary-negative:disabled span:first-child { - color: rgba(224, 224, 224, 0.7); -} -button.btn-secondary-negative:disabled { - cursor: not-allowed; -} -button.btn-duel-off { - background: #121212; - background-color: #121212; - border: 1px solid rgba(97, 240, 242, 0.5); - border-radius: 2px; - margin: 1.5rem 0 0; - width: 100%; - text-transform: initial; - cursor: pointer; -} -button.btn-duel-off span:first-child { - color: #ffffff; -} -button.btn-duel-off:hover, -button.btn-duel-off:focus, -button.btn-duel-off.active, -button.btn-duel-off:disabled { - background-color: black; -} -button.btn-duel-off:disabled { - cursor: not-allowed; -} -button.btn-duel-active { - background: #58ffff; - background-color: #58ffff; - border: none; - border-radius: 2px; - margin: 1.5rem 0 0; - width: 100%; - text-transform: initial; - cursor: pointer; -} -button.btn-duel-active span:first-child { - color: #121212; -} -button.btn-duel-active:hover, -button.btn-duel-active:focus, -button.btn-duel-active.active, -button.btn-duel-active:disabled { - background-color: #00bebe; -} -button.btn-duel-active:disabled { - cursor: not-allowed; -} -button.btn-duel-on { - background: radial-gradient( - 60.65% 30.62% at 50% 3.13%, - #2a2b30 0%, - #1b1c22 100% - ); - background-color: #121212; - border: 1px solid #58ffff; - border-radius: 2px; - margin: 1.5rem 0 0; - width: 100%; - text-transform: initial; - cursor: pointer; -} -button.btn-duel-on span:first-child { - color: #ffffff; -} -button.btn-duel-on:hover, -button.btn-duel-on:focus, -button.btn-duel-on.active, -button.btn-duel-on:disabled { - background-color: black; -} -button.btn-duel-on:disabled { - cursor: not-allowed; -} -button.btn-profile-next { - background: radial-gradient( - 105.25% 64.58% at 49.68% 70.83%, - rgba(226, 137, 4, 0.5) 0%, - rgba(255, 255, 255, 0) 100% - ), - #f1c017; - background-color: #e3b82a; - border: none; - border-radius: 2px; - margin: 1.5rem 0 0; - width: 100%; - text-transform: initial; - cursor: pointer; -} -button.btn-profile-next span:first-child { - color: #000000; -} -button.btn-profile-next:hover, -button.btn-profile-next:focus, -button.btn-profile-next.active, -button.btn-profile-next:disabled { - background-color: #b89318; -} -button.btn-profile-next:disabled { - cursor: not-allowed; -} -button.btn-profile-back { - background: none; - background-color: none; - border: none; - border-radius: 2px; - margin: 1.5rem 0 0; - width: 100%; - text-transform: initial; - cursor: pointer; -} -button.btn-profile-back span:first-child { - color: #a0a0a0; -} -button.btn-profile-back:disabled { - cursor: not-allowed; -} - -/** BLACK **/ -/** RED **/ -/** YELLOW **/ -/** ORANGE **/ -/** BLUE **/ -/** GREEN **/ -/** WHITE **/ -/** GREY **/ -/** App colors **/ -/** TABS GRADIENT **/ -/** SCROLLBAR **/ -.card { - background: linear-gradient(180deg, rgb(50, 51, 57) 0%, rgb(37, 38, 43) 100%); - box-sizing: border-box; - box-shadow: 0px 4px 8px rgba(0, 0, 0, 0.75); - border-radius: 4px; - margin: 10px 0px 20px 0px; - padding: 16px; -} -.card:hover { - background: linear-gradient( - 180deg, - rgba(70, 71, 77, 0.7) 0%, - rgba(57, 58, 63, 0.7) 100% - ); -} -.card.rich-card { - padding: 24px 16px; -} - -/** BLACK **/ -/** RED **/ -/** YELLOW **/ -/** ORANGE **/ -/** BLUE **/ -/** GREEN **/ -/** WHITE **/ -/** GREY **/ -/** App colors **/ -/** TABS GRADIENT **/ -/** SCROLLBAR **/ -div.modal-root .MuiBackdrop-root { - background-color: hsla(231deg, 11%, 12%, 0.85); -} - -div.modal-paper { - background: linear-gradient(180deg, rgb(50, 51, 57) 0%, rgb(37, 38, 43) 100%); - width: 36rem; - max-width: 100%; - max-height: 90vh; - padding: 2rem; - box-sizing: border-box; - box-shadow: 0px 4px 16px rgba(0, 0, 0, 0.55); - border-radius: 4px; - margin: 0 0 0 13.75rem; - align-items: center; - color: #ffffff; -} -@media only screen and (max-width: 1023px) { - div.modal-paper { - width: 35rem; - margin: 0; - } -} -@media only screen and (max-width: 768px) { - div.modal-paper { - padding: 1rem; - width: 85%; - max-width: 35rem; - margin: 0; - } -} -div.modal-paper.no-padding { - padding: 0; -} -div.modal-paper.blue-border { - border: 1px solid rgba(88, 255, 255, 0.2509803922); -} -div.modal-paper.blue-light-border { - border: 1px solid #61f0f2; -} -div.modal-paper.yellow-border { - border: 1px solid rgba(227, 184, 42, 0.4); -} -div.modal-paper .modal-paper-close-button { - position: absolute; - top: 0.5rem; - right: 0.5rem; - padding: 5px 5px; - z-index: 10; -} - -div.modal-paper-full-screen { - background: linear-gradient(180deg, rgb(50, 51, 57) 0%, rgb(37, 38, 43) 100%); - width: 100%; - max-width: 100%; - height: 100%; - max-height: 100%; - padding: 0; - margin: 0; - box-sizing: border-box; - box-shadow: 0px 4px 16px rgba(0, 0, 0, 0.55); - border-radius: 4px; - color: #ffffff; - display: flex; - align-items: center; -} -div.modal-paper-full-screen.dark-background { - background: #121212; -} - -/** BLACK **/ -/** RED **/ -/** YELLOW **/ -/** ORANGE **/ -/** BLUE **/ -/** GREEN **/ -/** WHITE **/ -/** GREY **/ -/** App colors **/ -/** TABS GRADIENT **/ -/** SCROLLBAR **/ -div.expansion-panel-root { - margin: 1.2rem 0; - color: #e0e0e0; - background: linear-gradient(180deg, rgb(50, 51, 57) 0%, rgb(37, 38, 43) 100%); - border-radius: 4px; - box-shadow: 0px 4px 8px rgba(0, 0, 0, 0.75); - transition: background-color 0.6s ease; - box-sizing: border-box; -} -div.expansion-panel-root.Mui-expanded:first-child { - margin: 1.2rem 0; -} -div.expansion-panel-root.Mui-expanded:last-child { - margin: 1.2rem 0; -} -div.expansion-panel-root.red-border { - border: 1px solid #d25959; -} - -div.expansion-panel-summary { - padding: 0.25rem 1.2rem; - min-height: 4rem; -} -div.expansion-panel-summary.Mui-focused { - border-radius: 4px; - background-color: unset; - box-shadow: 0 0 0 1px #e0e0e0; -} -div.expansion-panel-summary.Mui-expanded { - min-height: 4rem; -} -div.expansion-panel-summary.Mui-expanded.small { - min-height: 3rem; -} -div.expansion-panel-summary.small { - padding: 0 1.2rem; - min-height: 3rem; -} -div.expansion-panel-summary.bold-text { - font-weight: bold; -} - -div.expansion-panel-content { - display: flex; - align-items: center; -} -div.expansion-panel-content.Mui-expanded { - margin: 0.75rem 0; -} - -div.expansion-panel-details { - padding: 0 1.2rem 1.2rem; -} - -/** BLACK **/ -/** RED **/ -/** YELLOW **/ -/** ORANGE **/ -/** BLUE **/ -/** GREEN **/ -/** WHITE **/ -/** GREY **/ -/** App colors **/ -/** TABS GRADIENT **/ -/** SCROLLBAR **/ -a { - color: #deaf0e; -} -a:visited { - color: #deaf0e; -} - -a:focus { - outline: none; - box-shadow: inset 0 0 0 1px #e0e0e0; -} -a:focus > div:first-child { - box-shadow: 0 0 0 1px #e0e0e0; -} - -a.MuiLink-underlineHover:hover { - text-decoration: none; -} - -a.MuiTypography-colorPrimary { - color: #e0e0e0; -} - -:root { - --blue: #58ffff; - --blue40: rgba(88, 255, 255, 0.2509803922); - --blueBackground: radial-gradient( - 105.25% 64.58% at 49.68% 70.83%, - rgba(1, 153, 163, 0.5) 0%, - rgba(255, 255, 255, 0) 100% - ), - #58ffff; - --blueRadialGradient: radial-gradient( - 105.25% 64.58% at 49.68% 70.83%, - rgba(1, 153, 163, 0.5) 0%, - rgba(255, 255, 255, 0) 100% - ), - #58ffff; - --blueRadialGradientTrans: radial-gradient( - circle, - #58ffff 0%, - rgba(255, 255, 255, 0) 100% - ); - --elecColor: #d87b39; - --elecColor40: rgba(216, 123, 57, 0.4); - --elecCompareColor: #e2bca1; - --gasColor: #45d1b8; - --gasColor40: rgba(69, 209, 184, 0.4); - --gasCompareColor: #a8f7e9; - --waterColor: #3a98ec; - --waterColor40: rgba(58, 152, 236, 0.4); - --waterCompareColor: #abd4fa; - --multiColor: #e3b82a; - --multiCompareColor: #ffd597; - --redPrimary: #d25959; - --greyBright: #e0e0e0; - --greyDark: #7b7b7b; - --textWhite: #ffffff; - --softGrey: #a0a0a0; - --darkLight: #25262b; - --darkLight2: #121212; - --textFont: Lato, sans-serif; - --greyLinearGradientBackground: linear-gradient( - 180deg, - rgb(50, 51, 57) 0%, - rgb(37, 38, 43) 100% - ); - --multiColorRadialGradientTrans: radial-gradient( - circle, - #e3b82a 0%, - rgba(255, 255, 255, 0) 100% - ); - --elecColorRadialGradientTrans: radial-gradient( - circle, - #d87b39 0%, - rgba(255, 255, 255, 0) 100% - ); - --waterColorRadialGradientTrans: radial-gradient( - circle, - #3a98ec 0%, - rgba(255, 255, 255, 0) 100% - ); - --gasColorRadialGradientTrans: radial-gradient( - circle, - #e3b82a 0%, - rgba(255, 255, 255, 0) 100% - ); - --multiColorRadialGradient: radial-gradient( - 105.25% 64.58% at 49.68% 70.83%, - rgba(226, 137, 4, 0.5) 0%, - rgba(255, 255, 255, 0) 100% - ), - #f1c017; - --elecColorRadialGradient: radial-gradient( - 105.25% 64.58% at 49.68% 70.83%, - rgba(158, 67, 2, 0.5) 0%, - rgba(255, 255, 255, 0) 100% - ), - #d87b39; - --gasColorRadialGradient: radial-gradient( - 105.25% 64.58% at 49.68% 70.83%, - rgba(4, 106, 88, 0.5) 0%, - rgba(255, 255, 255, 0) 100% - ), - #45d1b8; - --waterColorRadialGradient: radial-gradient( - 105.25% 64.58% at 49.68% 70.83%, - rgba(2, 93, 174, 0.5) 0%, - rgba(255, 255, 255, 0) 100% - ), - #3a98ec; -} - -.application { - overflow-x: hidden; - background-color: #121212; -} - -/*# sourceMappingURL=index.css.map */ diff --git a/src/styles/index.css.map b/src/styles/index.css.map deleted file mode 100644 index 6b13903acfebfb59681513a4e856accd459301b8..0000000000000000000000000000000000000000 --- a/src/styles/index.css.map +++ /dev/null @@ -1,22 +0,0 @@ -{ - "version": 3, - "sourceRoot": "", - "sources": [ - "index.scss", - "base/_color.scss", - "base/_layout.scss", - "base/_z-index.scss", - "base/_typography.scss", - "base/_typo-variables.scss", - "components/_barchart.scss", - "components/_buttons.scss", - "base/_mixins.scss", - "components/_card.scss", - "components/_dialog.scss", - "components/_expansion-panel.scss", - "components/_link.scss" - ], - "names": [], - "mappings": "AAAA;AACQ;AACR;AACQ;AACR;ACJA;AAYA;AAGA;AAMA;AAGA;AAmBA;AAIA;AAIA;AAoBA;AA0BA;AA+CA;ADhIQ;AEZR;EACE,YDDa;;;ACIf;EACE,YDLa;ECMb;;;AAGF;EACE;EACA;;;AAGF;EACE;EACA;;;AAGF;EACE;EACA;EACA;EACA;EACA;;AACA;EANF;IAOI;;;;AAIJ;EACE,kBDaM;;ACZN;EAFF;IAGI;IACA;;;;AAIJ;EACE;EACA;;;AAEF;EACE;;;AAEF;EACE;;;AAGF;EACE;EACA;EACA;EACA;EACA;EACA,SCxDS;EDyDT;EACA;EACA;;AACA;EAVF;IAWI;;;AAEF;EACE;EAKA;;AACA;EACE;EACA,ODvBQ;;AC0BZ;EACE;EACA;EACA;;AACA;EAJF;IAKI;;;AAEF;EAPF;IAQI;;;AAEF;EACE;EACA;;AACA;EACE;;AAEF;EACE;EACA;;AAEF;EACE;EACA;EACA;EACA,ODlDM;;ACoDR;EACE;;AAEF;EACE;IACE;IACA,OD1DI;;EC4DN;IACE;;EAEF;IACE;;;;AAOV;EACE;EACA;EACA;EACA;EACA;EACA;EACA,OD9EY;;AC+EZ;EACE;EACA;EACA;;AAEF;EACE;EACA;;;AAIJ;AACE;AAIA;AAIA;;AAPA;EACE;;AAGF;EACE,YDHc;;ACMhB;EACE,YDNc;;;AAnJlB;AAYA;AAGA;AAMA;AAGA;AAmBA;AAIA;AAIA;AAoBA;AA0BA;AA+CA;AAhJA;AAYA;AAGA;AAMA;AAGA;AAmBA;AAIA;AAIA;AAoBA;AA0BA;AA+CA;AG5IA;EACE,aCLU;;;ADQZ;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;EAOE,OHsCU;EGrCV,aChBU;;;ADmBZ;EACE;EACA,aCrBU;EDsBV;EACA;EACA;EACA;;;AAGF;EACE,aC7BU;ED8BV;EACA;EACA;EACA;EAEA;EACA;EACA,OHeY;EGdZ;;;AAEF;EACE,OHtBY;EGuBZ;EACA;;;AAIA;EACE;EACA,WC/CQ;EDgDR;;AACA;EAEE;;AACA;EAEE;;AAEF;EAEE;;AAGJ;EAEE;;AACA;EAEE;;AAEF;EAEE;;AAGJ;EAEE;EACA;;;AA/BJ;EACE;EACA,WC/CQ;EDgDR;;AACA;EAEE;;AACA;EAEE;;AAEF;EAEE;;AAGJ;EAEE;;AACA;EAEE;;AAEF;EAEE;;AAGJ;EAEE;EACA;;;AA/BJ;EACE;EACA,WC/CQ;EDgDR;;AACA;EAEE;;AACA;EAEE;;AAEF;EAEE;;AAGJ;EAEE;;AACA;EAEE;;AAEF;EAEE;;AAGJ;EAEE;EACA;;;AA/BJ;EACE;EACA,WC/CQ;EDgDR;;AACA;EAEE;;AACA;EAEE;;AAEF;EAEE;;AAGJ;EAEE;;AACA;EAEE;;AAEF;EAEE;;AAGJ;EAEE;EACA;;;AA/BJ;EACE;EACA,WC/CQ;EDgDR;;AACA;EAEE;;AACA;EAEE;;AAEF;EAEE;;AAGJ;EAEE;;AACA;EAEE;;AAEF;EAEE;;AAGJ;EAEE;EACA;;;AA/BJ;EACE;EACA,WC/CQ;EDgDR;;AACA;EAEE;;AACA;EAEE;;AAEF;EAEE;;AAGJ;EAEE;;AACA;EAEE;;AAEF;EAEE;;AAGJ;EAEE;EACA;;;AA/BJ;EACE;EACA,WC/CQ;EDgDR;;AACA;EAEE;;AACA;EAEE;;AAEF;EAEE;;AAGJ;EAEE;;AACA;EAEE;;AAEF;EAEE;;AAGJ;EAEE;EACA;;;AA/BJ;EACE;EACA,WC/CQ;EDgDR;;AACA;EAEE;;AACA;EAEE;;AAEF;EAEE;;AAGJ;EAEE;;AACA;EAEE;;AAEF;EAEE;;AAGJ;EAEE;EACA;;;AA/BJ;EACE;EACA,WC/CQ;EDgDR;;AACA;EAEE;;AACA;EAEE;;AAEF;EAEE;;AAGJ;EAEE;;AACA;EAEE;;AAEF;EAEE;;AAGJ;EAEE;EACA;;;AA/BJ;EACE;EACA,WC/CQ;EDgDR;;AACA;EAEE;;AACA;EAEE;;AAEF;EAEE;;AAGJ;EAEE;;AACA;EAEE;;AAEF;EAEE;;AAGJ;EAEE;EACA;;;AA/BJ;EACE;EACA,WC/CQ;EDgDR;;AACA;EAEE;;AACA;EAEE;;AAEF;EAEE;;AAGJ;EAEE;;AACA;EAEE;;AAEF;EAEE;;AAGJ;EAEE;EACA;;;AA/BJ;EACE;EACA,WC/CQ;EDgDR;;AACA;EAEE;;AACA;EAEE;;AAEF;EAEE;;AAGJ;EAEE;;AACA;EAEE;;AAEF;EAEE;;AAGJ;EAEE;EACA;;;AA/BJ;EACE;EACA,WC/CQ;EDgDR;;AACA;EAEE;;AACA;EAEE;;AAEF;EAEE;;AAGJ;EAEE;;AACA;EAEE;;AAEF;EAEE;;AAGJ;EAEE;EACA;;;AAKN;AACA;EACE,aCrFU;EDsFV;EACA;EACA;EACA;EACA,OHtCY;;;AGwCd;EACE,aC7FU;ED8FV;EACA;EACA;EACA;EACA,OH9CY;;;AGgDd;EACE,aCrGU;EDsGV;EACA;EACA;EACA;EACA,OHtDY;;;AGwDd;EACE,aC7GU;ED8GV;EACA;EACA;EACA;EACA,OH9DY;;;AGgEd;EACE,aCrHU;EDsHV;EACA;EACA;EACA;EACA,OHtEY;;;AGyEd;AACA;EACE,aC/HU;EDgIV;EACA;EACA;EACA;;AACA;EANF;IAOI;;;;AAGJ;EACE,aCzIU;ED0IV;EACA;EACA;EACA;;AACA;EANF;IAOI;;;;AAIJ;AACA;EACE,aCrJU;EDsJV;EACA;EACA;EACA;EACA,OHtGY;;;AApDd;AAYA;AAGA;AAMA;AAGA;AAmBA;AAIA;AAIA;AAoBA;AA0BA;AA+CA;AK7IA;EACE,OLkDU;;AKjDV;EACE,MLgDQ;;AK/CR;EACE,ML4CQ;;AKzCZ;EACE;EACA;EACA;;;AAGJ;EACE,MLoCU;;AKnCV;EACE,MLgCU;;;AK3BZ;AAAA;EACE;;;AAGJ;EACE;;AACA;EACE;;;AAGJ;EACE;;;AAUA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;EACE;;;AAGJ;EACE,MLuBe;;AKtBf;EACE,MLmBS;EKlBT;;;AAIJ;EACE,MLiBuB;;AKhBvB;EACE,MLciB;EKbjB;;;AAIJ;EACE,MLmBgB;;AKlBhB;EACE,MLeU;EKdV;;;AAIJ;EACE,MLawB;;AKZxB;EACE,MLUkB;EKTlB;;;AAIJ;EACE,MLHc;;AKId;EACE,MLPQ;EKQR;;;AAIJ;EACE,MLTsB;;AKUtB;EACE,MLZgB;EKahB;;;AAIJ;EACE,MLRgB;;AKShB;EACE,MLXU;EKYV;;AAGA;EACE;;;AAIN;EACE,MLpFW;;AKqFX;EACE,MLtFS;EKuFT;;AAGA;EACE;;;AAIN;EACE,ML1HK;EK2HL;;AACA;EACE,MLpCU;EKqCV;;AAGA;EACE;;;AAKN;EACE,ML5CwB;;AK6CxB;EACE,ML/CkB;EKgDlB;;;AAGJ;EACE;EACA,QLvDY;;;AKyDd;EACE,MLzEmB;;AK0EnB;EACE,ML3EiB;EK4EjB;;;AAGJ;EACE,ML/DoB;;AKgEpB;EACE,MLjEkB;EKkElB;;;AAGJ;AACA;EACE;EACA;EACA;EACA;EACA;;;AAEF;EACE;IACE;;EAEF;IACE;;EAEF;IACE;;EAEF;IACE;;EAEF;IACE;;EAEF;IACE;;;AAIJ;EACE;EACA;EACA;EACA;EACA;;;AAEF;EACE;IACE;;EAEF;IACE;;EAEF;IACE;;EAEF;IACE;;EAEF;IACE;;EAEF;IACE;;;AAIJ;EACE;EACA;EACA;EACA;;;AAEF;EACE;IACE;IACA;;EAEF;IACE;IACA;;EAEF;IACE;IACA;;;AAIJ;AACA;EACE;;;AAEF;EACE;;;AAEF;EACE;;;AAEF;EACE;;;AAEF;EACE;;;AAEF;EACE;;;AAEF;EACE;;;AAEF;EACE;;;AAEF;EACE;;;AAEF;EACE;;;AAEF;EACE;;;AAEF;EACE;;;AAEF;EACE;;;AAEF;EACE;;;ALxRF;AAYA;AAGA;AAMA;AAGA;AAmBA;AAIA;AAIA;AAoBA;AA0BA;AA+CA;AM5IE;ECEA,YPiH4B;EOhH5B,kBPYY;EOXZ,QDHyC;ECIzC;EACA;EACA;EACA;EACA;;AACA;EACE,ODV8B;;ACYhC;EDXI;;ACiBJ;EACE;;ADfF;ECHA,YDQI;ECPJ,kBDII;ECHJ,QDKI;ECJJ;EACA;EACA;EACA;EACA;;AACA;EACE,OPIU;;AOFZ;EDDI;;AACA;EACE;;ACKN;EACE;;ADFF;EChBA,YDqBI;ECpBJ,kBDiBI;EChBJ,QDkBI;ECjBJ;EACA;EACA;EACA;EACA;;AACA;EACE,OPIU;;AOFZ;EDYI;;AACA;EACE;;ACRN;EACE;;ADWF;EC7BA,YDkCI;ECjCJ,kBD8BI;EC7BJ,QD+BI;EC9BJ;EACA;EACA;EACA;EACA;;AACA;EACE,OPqCU;;AOnCZ;EDyBI;;AACA;EACE;;ACrBN;EACE;;ADwBF;EC1CA,YD+CI;EC9CJ,kBD2CI;EC1CJ,QD4CI;EC3CJ;EACA;EACA;EACA;EACA;;AACA;EACE,OPqCU;;AOnCZ;EDsCI;;AACA;EACE;;AClCN;EACE;;ADqCF;ECvDA,YPFa;EOGb,kBPHa;EOIb,QDyDI;ECxDJ;EACA;EACA;EACA;EACA;;AACA;EACE,OPiCI;;AO/BN;EDmDI;;AC7CJ;EACE;;AD+CF;ECjEA,YPmBK;EOlBL,kBPkBK;EOjBL,QDgEwC;EC/DxC;EACA;EACA;EACA;EACA;;AACA;EACE,OPXW;;AOab;EDwDI;;AClDJ;EACE;;ADoDF;ECtEA;EACA,kBPHa;EOIb,QDqEyC;ECpEzC;EACA;EACA;EACA;EACA;;AACA;EACE,OPiCI;;AO/BN;ED6DI;;ACvDJ;EACE;;ADyDF;EC3EA,YPiH4B;EOhH5B,kBPYY;EOXZ,QD0EyC;ECzEzC;EACA;EACA;EACA;EACA;;AACA;EACE,ODmE8B;;ACjEhC;EDkEI;;AC5DJ;EACE;;AD8DF;EChFA,YDiF0C;EChF1C,kBDgFkB;EC/ElB,QD+EoC;EC9EpC;EACA;EACA;EACA;EACA;;AACA;EACE,OPsCQ;;AO9BV;EACE;;;APxBJ;AAYA;AAGA;AAMA;AAGA;AAmBA;AAIA;AAIA;AAoBA;AA0BA;AA+CA;AQ9IA;EACE,YRoDgC;EQnDhC;EACA;EACA;EACA;EACA;;AACA;EACE,YRkDoC;;AQhDtC;EACE;;;ARbJ;AAYA;AAGA;AAMA;AAGA;AAmBA;AAIA;AAIA;AAoBA;AA0BA;AA+CA;AS5IE;EACE;;;AAIJ;EACE,YT6CgC;ES5ChC;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA,OT4BM;;AS3BN;EAZF;IAaI;IACA;;;AAEF;EAhBF;IAiBI;IACA;IACA;IACA;;;AAEF;EACE;;AAEF;EACE;;AAEF;EACE;;AAEF;EACE;;AAEF;EACE;EACA;EACA;EACA;EACA,SP9CO;;;AOkDX;EACE,YTEgC;ESDhC;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA,OTfM;ESgBN;EACA;;AACA;EACE,YT/DW;;;AAJf;AAYA;AAGA;AAMA;AAGA;AAmBA;AAIA;AAIA;AAoBA;AA0BA;AA+CA;AU9IA;EACE;EACA,OVgDY;EU/CZ,YVkDgC;EUjDhC;EACA;EACA;EACA;;AACA;EACE;;AAEF;EACE;;AAEF;EACE;;;AAGJ;EACE;EACA;;AACA;EACE;EACA;EACA;;AAEF;EACE;;AACA;EACE;;AAGJ;EACE;EACA;;AAEF;EACE;;;AAGJ;EACE;EACA;;AACA;EACE;;;AAGJ;EACE;;;AVlDF;AAYA;AAGA;AAMA;AAGA;AAmBA;AAIA;AAIA;AAoBA;AA0BA;AA+CA;AW/IA;EACE,OXgBW;;AWfX;EACE,OXcS;;;AWVb;EACE;EACA;;AACA;EACE;;;AAGJ;EACE;;;AAEF;EACE,OXiCY;;;ADlCd;EACE;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;;AAGF;EAME;EACA,kBCzDa", - "file": "index.css" -} diff --git a/src/styles/index.scss b/src/styles/index.scss index 628ccfc6414f433765d7e26b114207dbc002c97c..2ee8873d98d20621914f25a5c6950af7985a981a 100644 --- a/src/styles/index.scss +++ b/src/styles/index.scss @@ -69,6 +69,9 @@ .loaderContainer { height: 80vh; - justify-content: center; display: flex; + flex: 1; + justify-content: center; + // useful when text is rendered with loader + align-items: center; } diff --git a/src/targets/browser/index.tsx b/src/targets/browser/index.tsx index d8800d9b42c840aacf87c62f71dbf5cc28899e77..353a7bffaa17059c25cf619ee6edfb78747d4ad6 100644 --- a/src/targets/browser/index.tsx +++ b/src/targets/browser/index.tsx @@ -20,7 +20,7 @@ import { render } from 'react-dom' import { Provider } from 'react-redux' import { HashRouter } from 'react-router-dom' import EnvironmentService from 'services/environment.service' -import configureStore from 'store' +import { setupStore } from 'store/store' import cozyBar from 'utils/cozyBar' import logApp from 'utils/logger' import MatomoTracker from 'utils/matomoTracker' @@ -50,8 +50,7 @@ const setupApp = memoize(() => { schema, }) - const persistedState: any = {} - const store = configureStore(client, persistedState) + const store = setupStore(client) const envService = new EnvironmentService() const isLocal = envService.isLocal() const development = envService.isDev() diff --git a/src/targets/services/aggregatorUsageEvents.ts b/src/targets/services/aggregatorUsageEvents.ts index 782add87babdf44a4ad6c79de72932c686176aae..09ef985fc44fd8dd98d997f2656cc30783bbb1cb 100644 --- a/src/targets/services/aggregatorUsageEvents.ts +++ b/src/targets/services/aggregatorUsageEvents.ts @@ -1,14 +1,18 @@ import * as Sentry from '@sentry/react' import { Client } from 'cozy-client' import logger from 'cozy-logger' -import { DaccEvent } from 'enum/dacc.enum' -import { FluidState, FluidType } from 'enum/fluid.enum' -import { FluidSlugType } from 'enum/fluidSlug.enum' -import { HotWaterFluid, WarmingType } from 'enum/profileType.enum' -import { TimeStep } from 'enum/timeStep.enum' -import { UsageEventType } from 'enum/usageEvent.enum' -import { UsageEventProperties } from 'enum/usageEventProperties.enum' -import { UserChallengeState } from 'enum/userChallenge.enum' +import { + DaccEvent, + FluidSlugType, + FluidState, + FluidType, + HotWaterFluid, + TimeStep, + UsageEventProperties, + UsageEventType, + UserChallengeState, + WarmingType, +} from 'enums' import { toNumber, uniq } from 'lodash' import { DateTime } from 'luxon' import { FluidStatus, PerformanceIndicator, UsageEvent } from 'models' @@ -81,7 +85,7 @@ const sendIndicator = async ( 'error', `Error while sending indicator ${indicator.measureName} to remote doctype: ${errorMessage}` ) - Sentry.captureException(JSON.stringify({ error })) + Sentry.captureException(error) throw error } } @@ -371,7 +375,6 @@ const calculateConnectedKonnectorPerDay = async (client: Client) => { /** * Build indicator group string with handling of : ECS, heating for gas and electricity. - * * @param client Client * @param fluidType FluidType * @returns Promise<string> @@ -479,8 +482,7 @@ const getConsumptionValue = async ( /** * Send an indicator on the consumption variation in % for each fluid type. - * @param client - * @group [{ slug }, { seniority (in month) }, { profile (ECS, chauffage, etc...) }], + * @description [{ slug }, { seniority (in month) }, { profile (ECS, chauffage, etc...) }], */ const calculateConsumptionVariation = async (client: Client) => { logStack('info', `calculateConsumptionVariation`) @@ -536,7 +538,7 @@ const calculateConsumptionVariation = async (client: Client) => { }, } - // if user wasnt connected during current month, dont send indicator + // if user wasn't connected during current month, dont send indicator const events: UsageEvent[] = await UsageEventService.getEvents(client, { eventDate: { $lt: DateTime.local() @@ -767,7 +769,7 @@ const sendKonnectorEvents = async (client: Client) => { const konnectorSuccess: Indicator = { createdBy: 'ecolyo', - measureName: DaccEvent.PARTNER_SUCESS_MONTHLY, + measureName: DaccEvent.PARTNER_SUCCESS_MONTHLY, // eslint-disable-next-line camelcase group1: { fluid_type: slug }, startDate: DateTime.local() @@ -1227,7 +1229,7 @@ const AggregatorUsageEvents = async ({ error += `${el.doctype}, ` }) logStack('error', error) - Sentry.captureException(JSON.stringify({ error })) + Sentry.captureException(error) throw error } diff --git a/src/targets/services/consumptionAlert.ts b/src/targets/services/consumptionAlert.ts index 49d49ae03ebc767b89bbdaf36f3ebfd65adaf425..496b83c3596b712b97f7d5449464086b69401478 100644 --- a/src/targets/services/consumptionAlert.ts +++ b/src/targets/services/consumptionAlert.ts @@ -1,6 +1,6 @@ import { Client } from 'cozy-client' import logger from 'cozy-logger' -import { FluidType } from 'enum/fluid.enum' +import { FluidType } from 'enums' import get from 'lodash/get' import { DateTime } from 'luxon' import mjml2html from 'mjml' diff --git a/src/targets/services/enedisHalfHourMonthlyAnalysis.ts b/src/targets/services/enedisHalfHourMonthlyAnalysis.ts index 980b2cb71745fd88172b8279b185fa3398817319..28c355598e3583ffda5b4d9a4952763d6be3365f 100644 --- a/src/targets/services/enedisHalfHourMonthlyAnalysis.ts +++ b/src/targets/services/enedisHalfHourMonthlyAnalysis.ts @@ -5,8 +5,7 @@ import { ENEDIS_MINUTE_DOCTYPE, ENEDIS_MONTHLY_ANALYSIS_DATA_DOCTYPE, } from 'doctypes' -import { FluidType } from 'enum/fluid.enum' -import { TimeStep } from 'enum/timeStep.enum' +import { FluidType, TimeStep } from 'enums' import { union } from 'lodash' import { DateTime } from 'luxon' import { Datachart, DataloadEntity, TimePeriod } from 'models' @@ -23,30 +22,20 @@ interface EnedisMonthlyProps { /** * Gets the minimum consumption value in a month - * @param weekEndValuesArray - * @param weekValuesArray - * @returns number */ const getMinMonthlyLoad = ( weekEndValuesArray: number[][], weekValuesArray: number[][], - numberofDaysInMonth: number + numberOfDaysInMonth: number ): number => { const totalArray = union(...weekEndValuesArray, ...weekValuesArray) const filteredTotal = totalArray.filter(val => val !== -1 && val !== 0) const talonCons = Math.min(...filteredTotal) - const minCons = talonCons * 48 * numberofDaysInMonth + const minCons = talonCons * 48 * numberOfDaysInMonth logStack('info', `Minimum value is ${minCons} `) return minCons } -/** - * - * @param monthlyArray - * @param dataChart - * @param isWeekend - * @returns - */ const populateArrayWithTotalData = ( monthlyArray: number[][], dataChart: Datachart, @@ -76,13 +65,7 @@ const populateArrayWithTotalData = ( }) } } -/** - * Gets max Power value for a given month - * @param month - * @param year - * @param client - * @returns - */ +/** Gets max Power value for a given month */ const getMonthMaxPower = async ( month: number, year: number, @@ -101,10 +84,6 @@ const getMonthMaxPower = async ( } /** * Get the average arrays of half-hour value on a given month - * @param client - * @param month - * @param year - * @returns {Promise<MonthlyAveragesLoads>} */ const getEnedisMonthAnalysisData = async ( client: Client, @@ -186,8 +165,6 @@ const getEnedisMonthAnalysisData = async ( /** * Synchronize enedis monthly analysis with database depending on if the service has already ran * and if the enedis minute tracking has been activated - * @param {Client} client - * @returns */ const syncEnedisMonthlyAnalysisDataDoctype = async ({ client, diff --git a/src/targets/services/fluidsPrices.ts b/src/targets/services/fluidsPrices.ts index d6a5f0a6a0b82265da7529eb455d10343d05c185..8e2706850f6d7aa6f841abfd28c3250cf4591cb2 100644 --- a/src/targets/services/fluidsPrices.ts +++ b/src/targets/services/fluidsPrices.ts @@ -1,13 +1,14 @@ import * as Sentry from '@sentry/react' import { Client } from 'cozy-client' import logger from 'cozy-logger' -import { EGL_DAY_DOCTYPE, ENEDIS_DAY_DOCTYPE, GRDF_DAY_DOCTYPE } from 'doctypes' import { + EGL_DAY_DOCTYPE, + ENEDIS_DAY_DOCTYPE, + GRDF_DAY_DOCTYPE, REMOTE_ORG_ECOLYO_AGENT_PRICES, REMOTE_ORG_ECOLYO_AGENT_PRICES_REC, -} from 'doctypes/remote/org.ecolyo.agent.prices' -import { FluidType } from 'enum/fluid.enum' -import { TimeStep } from 'enum/timeStep.enum' +} from 'doctypes' +import { FluidType, TimeStep } from 'enums' import { DateTime } from 'luxon' import { DataloadEntity, FluidPrice, TimePeriod } from 'models' import ConsumptionDataManager from 'services/consumption.service' @@ -38,8 +39,6 @@ const getRemotePricesByFluid = async ( /** * Synchro the remote prices with database and returns a date where we have to relaunch aggregation if a price has been edited in backoffice - * @param {Client} client - * @param {FluidType} fluidType * @returns {string | null} the oldest startDate */ const synchroPricesToUpdate = async ( @@ -50,65 +49,56 @@ const synchroPricesToUpdate = async ( const remotePrices = await getRemotePricesByFluid(client, fluidType) let firstEditedPrice: string | null = null await Promise.all( - remotePrices.map(remotePrice => { - // eslint-disable-next-line no-async-promise-executor - return new Promise<void>(async resolve => { - try { - // Check if price exist in database - const existingPrice = await fps.checkIfPriceExists(remotePrice) - if (existingPrice) { - // Check if the remote price is more recent - if ( - existingPrice.UpdatedAt && - remotePrice.UpdatedAt && - existingPrice.UpdatedAt < remotePrice.UpdatedAt - ) { - logStack( - 'debug', - `Price exist in db but not up to date, updating it` - ) - // If a price has been updated, set the oldest startDate of the edited price so we can redo aggregation - if (firstEditedPrice === null) { - firstEditedPrice = remotePrice.startDate - } - if (firstEditedPrice >= remotePrice.startDate) { - firstEditedPrice = remotePrice.startDate - } - - // update this price in db - await fps.updatePrice(existingPrice, { - price: remotePrice.price, - UpdatedAt: remotePrice.UpdatedAt, - startDate: remotePrice.startDate, - endDate: remotePrice.endDate, - }) - } else if (!existingPrice.UpdatedAt && remotePrice.UpdatedAt) { - // updatedAt key doesn't exist in db - await fps.updatePrice(existingPrice, { - UpdatedAt: remotePrice.UpdatedAt, - }) - } else { - logStack('debug', `Price up to date`) - } - } else { - logStack('debug', `Price doesn't exist in db, creating new price`) - // If a price has been updated, set the oldest startDate of the edited price so we can redo aggregation - if (firstEditedPrice === null) { - firstEditedPrice = remotePrice.startDate - } - if (firstEditedPrice >= remotePrice.startDate) { - firstEditedPrice = remotePrice.startDate - } - // create price in db - await fps.createPrice(remotePrice) + remotePrices.map(async remotePrice => { + try { + const existingPrice = await fps.checkIfPriceExists(remotePrice) + if (!existingPrice) { + logStack('debug', `Price doesn't exist in db, creating a new price`) + // If a price has been updated, set the oldest startDate of the edited price so we can redo aggregation + if ( + firstEditedPrice === null || + firstEditedPrice >= remotePrice.startDate + ) { + firstEditedPrice = remotePrice.startDate } - } catch (error) { - logStack('error', `Error: ${error}`) - Sentry.captureException(JSON.stringify({ error })) - } finally { - resolve() + await fps.createPrice(remotePrice) + return } - }) + + if (!existingPrice.UpdatedAt && remotePrice.UpdatedAt) { + // updatedAt key doesn't exist in db + await fps.updatePrice(existingPrice, { + UpdatedAt: remotePrice.UpdatedAt, + }) + return + } else if ( + !existingPrice.UpdatedAt || + !remotePrice.UpdatedAt || + existingPrice.UpdatedAt >= remotePrice.UpdatedAt + ) { + logStack('debug', `Price up to date`) + return + } + logStack('debug', `Price exists in db but not up to date, updating it`) + // If a price has been updated, set the oldest startDate of the edited price so we can redo aggregation + if ( + firstEditedPrice === null || + firstEditedPrice >= remotePrice.startDate + ) { + firstEditedPrice = remotePrice.startDate + } + + // update this price in db + await fps.updatePrice(existingPrice, { + price: remotePrice.price, + UpdatedAt: remotePrice.UpdatedAt, + startDate: remotePrice.startDate, + endDate: remotePrice.endDate, + }) + } catch (error) { + logStack('error', `Error: ${error}`) + Sentry.captureException(error) + } }) ) return firstEditedPrice @@ -166,41 +156,36 @@ const aggregatePrices = async ( ) await Promise.all( tsa.map(async ts => { - // eslint-disable-next-line no-async-promise-executor - return new Promise<void>(async resolve => { - let date: DateTime = DateTime.local() - Object.assign(date, firstDate) - try { - do { - const tp = await getTimePeriod(ts, date) - // Get doc for aggregation - const data = await qr.fetchFluidRawDoctype( - tp, - TimeStep.DAY, - fluidType - ) - // Get doc to update - const docToUpdate = await qr.fetchFluidRawDoctype(tp, ts, fluidType) + let date: DateTime = DateTime.local() + Object.assign(date, firstDate) + try { + do { + const tp = await getTimePeriod(ts, date) + // Get doc for aggregation + const data = await qr.fetchFluidRawDoctype( + tp, + TimeStep.DAY, + fluidType + ) + // Get doc to update + const docToUpdate = await qr.fetchFluidRawDoctype(tp, ts, fluidType) - if (docToUpdate?.data && data?.data) { - docToUpdate.data[0].price = data.data.map(price).reduce(sum) - } - // Save updated docs - await cdm.saveDocs(docToUpdate.data) - // Update date according to timestep - if (ts === TimeStep.YEAR) { - date = date.plus({ year: 1 }).startOf('month') - } else { - date = date.plus({ month: 1 }).startOf('month') - } - } while (date < today) - } catch (error) { - logStack('info', `Error : ${error}`) - Sentry.captureException(JSON.stringify({ error })) - } finally { - resolve() - } - }) + if (docToUpdate?.data && data?.data) { + docToUpdate.data[0].price = data.data.map(price).reduce(sum) + } + // Save updated docs + await cdm.saveDocs(docToUpdate?.data) + // Update date according to timestep + if (ts === TimeStep.YEAR) { + date = date.plus({ year: 1 }).startOf('month') + } else { + date = date.plus({ month: 1 }).startOf('month') + } + } while (date < today) + } catch (error) { + logStack('info', `Error : ${error}`) + Sentry.captureException(error) + } }) ) logStack('debug', `Aggregation done`) @@ -301,51 +286,46 @@ const applyPrices = async (client: Client, fluidType: FluidType) => { // Hourly and daily prices await Promise.all( tsa.map(async timeStep => { - // eslint-disable-next-line no-async-promise-executor - return new Promise<void>(async resolve => { - let date: DateTime = DateTime.local().setZone('utc', { - keepLocalTime: true, - }) - Object.assign(date, firstDate) - try { - do { - // Get price - const priceData = await fluidsPricesService.getPrices( - fluidType, - date - ) - const tp = await getTimePeriod(timeStep, date) - // Get doc to update - const data = await qr.fetchFluidRawDoctype( - tp, - timeStep, - fluidType - ) - - // If lastItem has a price, skip this day (in order to save perf) - const lastItem = data?.data && data.data[data.data.length - 1] - if (lastItem && priceData) { - // if a price has been updated in backoffice re-calculates all price from the firstEditedPriceDate - data?.data.forEach((element: DataloadEntity) => { - element.price = element.load * priceData.price - }) - // Save updated docs - await cdm.saveDocs(data.data) - } - // Update date - if (timeStep === TimeStep.HALF_AN_HOUR) { - date = date.plus({ days: 1 }) - } else { - date = date.plus({ month: 1 }).startOf('month') - } - } while (date < today) - } catch (error) { - logStack('error', `ERROR : ${error} `) - Sentry.captureException(JSON.stringify({ error })) - } finally { - resolve() - } + let date: DateTime = DateTime.local().setZone('utc', { + keepLocalTime: true, }) + Object.assign(date, firstDate) + try { + do { + // Get price + const priceData = await fluidsPricesService.getPrices( + fluidType, + date + ) + const tp = await getTimePeriod(timeStep, date) + // Get doc to update + const data = await qr.fetchFluidRawDoctype( + tp, + timeStep, + fluidType + ) + + // If lastItem has a price, skip this day (in order to save perf) + const lastItem = data?.data && data.data[data.data.length - 1] + if (lastItem && priceData) { + // if a price has been updated in backoffice re-calculates all price from the firstEditedPriceDate + data?.data.forEach((element: DataloadEntity) => { + element.price = element.load * priceData.price + }) + // Save updated docs + await cdm.saveDocs(data.data) + } + // Update date + if (timeStep === TimeStep.HALF_AN_HOUR) { + date = date.plus({ days: 1 }) + } else { + date = date.plus({ month: 1 }).startOf('month') + } + } while (date < today) + } catch (error) { + logStack('error', `ERROR : ${error} `) + Sentry.captureException(error) + } }) ) diff --git a/src/targets/services/monthlyReportNotification.ts b/src/targets/services/monthlyReportNotification.ts index 65e4a7c6659eca59c8ab3616e98446d645f949be..9d4dc2fd2360e451764cffcb5dca51d7e8a6fb95 100644 --- a/src/targets/services/monthlyReportNotification.ts +++ b/src/targets/services/monthlyReportNotification.ts @@ -1,17 +1,12 @@ import * as Sentry from '@sentry/react' import { Client } from 'cozy-client' import logger from 'cozy-logger' -import { - REMOTE_ORG_ECOLYO_AGENT, - REMOTE_ORG_ECOLYO_AGENT_REC, -} from 'doctypes/remote/org.ecolyo.agent' -import { FluidType } from 'enum/fluid.enum' -import { TimeStep } from 'enum/timeStep.enum' +import { REMOTE_ORG_ECOLYO_AGENT, REMOTE_ORG_ECOLYO_AGENT_REC } from 'doctypes' +import { FluidType, TimeStep } from 'enums' import get from 'lodash/get' import { DateTime, DurationLike } from 'luxon' import mjml2html from 'mjml' -import { PerformanceIndicator } from 'models' -import { MonthlyReport } from 'models/monthlyReport.model' +import { MonthlyReport, PerformanceIndicator } from 'models' import ConsumptionService from 'services/consumption.service' import EnvironmentService from 'services/environment.service' import MailService from 'services/mail.service' @@ -28,7 +23,6 @@ interface MonthlyReportNotificationProps { /** * Get consumption value for all fluid if exist - * @param client * @param fluidType - FluidType */ const getConsumptionValue = async ( @@ -60,8 +54,6 @@ const getConsumptionValue = async ( /** * Build consumption text to attach in email. According to client consumption, display electricity and/or gaz and/or water - * @param client - * @returns string */ const buildComparisonText = async ( client: Client, @@ -144,7 +136,7 @@ const getMonthlyReport = async ( return result } catch (error) { logStack('error', JSON.stringify(error)) - Sentry.captureException(JSON.stringify({ error })) + Sentry.captureException(error) return { year: parseInt(year), month: parseInt(month), @@ -183,7 +175,7 @@ const monthlyReportNotification = async ({ }) } catch (error) { logStack('error', 'Update mailToken user profile error : ' + error) - Sentry.captureException(JSON.stringify({ error })) + Sentry.captureException(error) throw error } } diff --git a/src/types/cozy-client.d.ts b/src/types/cozy-client.d.ts index c6784da3d6c2f5140852b3acb7907fd0e4f44926..8a7d20f28601fcd335b7b332c50fbed2fe9c0795 100644 --- a/src/types/cozy-client.d.ts +++ b/src/types/cozy-client.d.ts @@ -1,3 +1,4 @@ +/* eslint-disable jsdoc/no-undefined-types */ import { RealtimePlugin, TRealtimePlugin } from 'cozy-realtime' import * as CozyStackClient from 'cozy-stack-client' import { TDoctype } from 'doctypes' @@ -6,6 +7,7 @@ import { Relation } from 'models' declare module 'cozy-client' { /** * @typedef {object} HydratedDocument + * @property {unknown} client client */ export const CozyProvider: React.FC<{ client: Client; store?: any }> @@ -109,7 +111,6 @@ declare module 'cozy-client' { * `pluginName` that will be use as the key in the `plugins` object. * * Two plugins with the same `pluginName` cannot co-exist. - * * @example * ``` * class AlertPlugin { @@ -154,12 +155,10 @@ declare module 'cozy-client' { * * - "beforeLogin" at the beginning, before links have been set up * - "login" when the client is fully logged in and links have been set up - * * @param {object} options - Options * @param {string} options.token - If passed, the token is set on the client * @param {string} options.uri - If passed, the uri is set on the client * @returns {Promise} - Resolves when all links have been setup and client is fully logged in - * */ login(options: ClientLogin): Promise<unknown> @@ -170,7 +169,6 @@ declare module 'cozy-client' { * * - "beforeLogout" at the beginning, before links have been reset * - "login" when the client is fully logged out and links have been reset - * * @returns {Promise} - Resolves when all links have been reset and client is fully logged out */ logout(): Promise<unknown> @@ -178,7 +176,6 @@ declare module 'cozy-client' { /** * Forwards to a stack client instance and returns * a [DocumentCollection]{@link https://docs.cozy.io/en/cozy-client/api/cozy-stack-client/#DocumentCollection} instance. - * * @param {string} doctype - The collection doctype. * @returns {CozyStackClient.DocumentCollection} - Collection corresponding to the doctype */ @@ -186,7 +183,6 @@ declare module 'cozy-client' { /** * Fetches an endpoint in an authorized way. - * * @param {string} method The HTTP method. * @param {string} path The URI. * @param {object} body The payload. @@ -213,9 +209,8 @@ declare module 'cozy-client' { * Saves multiple documents in one batch * - Can only be called with documents from the same doctype * - Does not support automatic creation of references - * * @param {CozyClientDocument[]} docs - * @param {Object} mutationOptions + * @param {object} mutationOptions * @returns {Promise<void>} */ saveAll(docs: D[], mutationOptions?: any): Promise<QueryResult<T, I>> @@ -227,12 +222,11 @@ declare module 'cozy-client' { * const baseDoc = { _type: 'io.cozy.todo', label: 'Go hiking' } * // relations can be arrays or single objects * const relationships = { - * attachments: [{ _id: 12345, _type: 'io.cozy.files' }, { _id: 6789, _type: 'io.cozy.files' }], - * bills: { _id: 9999, _type: 'io.cozy.bills' } + * attachments: [{ _id: 12345, _type: 'io.cozy.files' }, { _id: 6789, _type: 'io.cozy.files' }], + * bills: { _id: 9999, _type: 'io.cozy.bills' } * } * client.getDocumentSavePlan(baseDoc, relationships) * ``` - * * @param {object} document The base document to create * @param {object} relationships The list of relationships to add, as a dictionnary. Keys should be relationship names and values the documents to link. * @returns {Mutation[]} One or more mutation to execute @@ -242,7 +236,6 @@ declare module 'cozy-client' { /** * Destroys a document. {before,after}:destroy hooks will be fired. - * * @param {Document} document - Document to be deleted * @returns {Document} The document that has been deleted */ @@ -259,7 +252,6 @@ declare module 'cozy-client' { * Results from the query will be saved internally and can be retrieved via * `getQueryFromState` or directly using `<Query />`. `<Query />` automatically * executes its query when mounted if no fetch policy has been indicated. - * * @param {QueryDefinition} queryDefinition - Definition that will be executed * @param {string} options - Options * @param {string} options.as - Names the query so it can be reused (by multiple components for example) @@ -275,8 +267,7 @@ declare module 'cozy-client' { * Will fetch all documents for a `queryDefinition`, automatically fetching more * documents if the total of documents is superior to the pagination limit. Can * result in a lot of network requests. - * - * @param {QueryDefinition} queryDefinition - Definition to be executed + * @param queryDefinition - Definition to be executed * @param {object} options - Options to the query * @returns {Array} All documents matching the query */ @@ -302,7 +293,6 @@ declare module 'cozy-client' { * Returns documents with their relationships resolved according to their schema. * If related documents are not in the store, they will not be fetched automatically. * Instead, the relationships will have null documents. - * * @param {string} doctype - Doctype of the documents being hydrated * @param {Array<Document>} documents - Documents to be hydrated * @returns {Array<HydratedDocument>} @@ -317,9 +307,8 @@ declare module 'cozy-client' { * * The original document is kept in the target attribute of * the relationship - * * @param {Document} document for which relationships must be resolved - * @param {Schema} schemaArg for the document doctype + * @param {TDoctype} schemaArg for the document doctype * @returns {HydratedDocument} */ hydrateDocument<D>(document: D, schemaArg?: TDoctype): HydratedDocument @@ -339,7 +328,6 @@ declare module 'cozy-client' { export class HasMany { /** * Sets a relationship item with the relationship name and id - * * @param {object} doc - Document to be updated * @param {string} relName - Name of the relationship * @param {string} relItemId - Id of the relationship item @@ -354,7 +342,6 @@ declare module 'cozy-client' { /** * Gets a relationship item with the relationship name and id - * * @param {object} doc - Document to be updated * @param {string} relName - Name of the relationship * @param {string} relItemId - Id of the relationship item @@ -363,7 +350,6 @@ declare module 'cozy-client' { /** * Updates a relationship item with the relationship name and id - * * @param {object} doc - Document to be updated * @param {string} relName - Name of the relationship * @param {string} relItemId - Id of the relationship item diff --git a/src/utils/date.spec.ts b/src/utils/date.spec.ts index a3ab46f2f056e0f9755b91d9b4fcd72335a1b935..a1028add5844625ad644a9bd30cdacc365924758 100644 --- a/src/utils/date.spec.ts +++ b/src/utils/date.spec.ts @@ -1,8 +1,7 @@ -import { FluidType } from 'enum/fluid.enum' -import { TimeStep } from 'enum/timeStep.enum' +import { FluidType, TimeStep } from 'enums' import { DateTime } from 'luxon' import { Dataload } from 'models' -import { graphData } from '../../tests/__mocks__/chartData.mock' +import { graphData } from 'tests/__mocks__/chartData.mock' import { compareDates, convertDateToMonthYearString, @@ -347,7 +346,7 @@ describe('date utils', () => { expect(result).toBe(3) }) - it('it should return 3 when there are many fluid type including WATER', () => { + it('should return 3 when there are many fluid type including WATER', () => { const result = getLagDays([FluidType.ELECTRICITY, FluidType.WATER]) expect(result).toBe(3) }) @@ -357,12 +356,12 @@ describe('date utils', () => { expect(result).toBe(2) }) - it('it should return 2 when there are many fluid type including GAS and excluding WATER', () => { + it('should return 2 when there are many fluid type including GAS and excluding WATER', () => { const result = getLagDays([FluidType.ELECTRICITY, FluidType.GAS]) expect(result).toBe(2) }) - it('it should return when there is only ELECTRICITY Fluid Type', () => { + it('should return when there is only ELECTRICITY Fluid Type', () => { const result = getLagDays([FluidType.ELECTRICITY]) expect(result).toBe(1) }) diff --git a/src/utils/date.ts b/src/utils/date.ts index 805c50a8da1924327e80fca1840b6d22b226f809..e474fdd4923b6b7b8393ae80baac318783b7c447 100644 --- a/src/utils/date.ts +++ b/src/utils/date.ts @@ -1,5 +1,4 @@ -import { FluidType } from 'enum/fluid.enum' -import { TimeStep } from 'enum/timeStep.enum' +import { FluidType, TimeStep } from 'enums' import { DateTime } from 'luxon' import { Dataload } from 'models' import { getMonthNameWithPrep } from './utils' diff --git a/src/utils/decoreText.spec.tsx b/src/utils/decoreText.spec.tsx deleted file mode 100644 index b9c0f21500cfaf9647df2d292756fda4fb89497b..0000000000000000000000000000000000000000 --- a/src/utils/decoreText.spec.tsx +++ /dev/null @@ -1,16 +0,0 @@ -import React from 'react' -import { decoreText } from './decoreText' - -describe('decoreText utilis test', () => { - it('should return text with span', () => { - const text = 'text <span>with span</span> end of text' - const result = decoreText(text) - - const expected: JSX.Element = ( - <> - text <span>with span</span> end of text - </> - ) - expect(result).toStrictEqual(expected) - }) -}) diff --git a/src/utils/decoreText.tsx b/src/utils/decoreText.tsx deleted file mode 100644 index ebf8d62132f65a943e503a3f2538259c12219fa2..0000000000000000000000000000000000000000 --- a/src/utils/decoreText.tsx +++ /dev/null @@ -1,56 +0,0 @@ -import React from 'react' - -export const decoreText = (line: string, action?: () => void) => { - if (line.includes('<a href="')) { - const indexRefStart = line.indexOf('<a href="') - const indexRefEnd = line.indexOf('">') - const indexEnd = line.indexOf('</a>') - return ( - <> - {line.substring(0, indexRefStart)} - <a - href={line.substring(indexRefStart + 9, indexRefEnd)} - target="_blank" - rel="noopener noreferrer" - > - {line.substring(indexRefEnd + 2, indexEnd)} - </a> - {line.substring(indexEnd + 4, line.length)} - </> - ) - } else if (line.includes('<p>')) { - const indexStart = line.indexOf('<p>') - const indexEnd = line.indexOf('</p>') - return ( - <> - {line.substring(0, indexStart)} - <p>{line.substring(indexStart + 3, indexEnd)}</p> - {line.substring(indexEnd + 4, line.length)} - </> - ) - } else if (line.includes('<span>')) { - const indexStart = line.indexOf('<span>') - const indexEnd = line.indexOf('</span>') - return ( - <> - {line.substring(0, indexStart)} - <span>{line.substring(indexStart + 6, indexEnd)}</span> - {line.substring(indexEnd + 7, line.length)} - </> - ) - } else if (line.includes('<span class="action">')) { - const indexStart = line.indexOf('<span class="action">') - const indexEnd = line.indexOf('</span>') - return ( - <> - {line.substring(0, indexStart)} - <button className="action" onClick={action}> - {line.substring(indexStart + 21, indexEnd)} - </button> - {line.substring(indexEnd + 7, line.length)} - </> - ) - } else { - return line - } -} diff --git a/src/utils/duration.ts b/src/utils/duration.ts index adaadaf1428e2cc609331a2178704054a2ea76c2..00b5555a55e7cec20d863c94810f89ac1abca1a8 100644 --- a/src/utils/duration.ts +++ b/src/utils/duration.ts @@ -4,7 +4,7 @@ import logApp from './logger' * Logs the time spend and add "in xx ms" * @param {string} scope string Migration | Initialization | ... * @param startTime number raw duration in ms - * @output [Scope] Finished in XXX ms + * @description [Scope] Finished in XXX ms * @example * logDuration("[Migration] Finished", 764745674); // [Migration] Finished in 685 ms */ diff --git a/src/utils/hash.spec.ts b/src/utils/hash.spec.ts index bc97808dec2ca2510587fd8e96605b1c16aff61b..0edc793c186e28d821bc301fadb7ddb7a2f5dd34 100644 --- a/src/utils/hash.spec.ts +++ b/src/utils/hash.spec.ts @@ -1,4 +1,4 @@ -import { mockedEcogesturesData } from '../../tests/__mocks__/ecogesturesData.mock' +import { mockedEcogesturesData } from 'tests/__mocks__/ecogesturesData.mock' import { hashFile } from './hash' describe('hash utils test', () => { diff --git a/src/utils/picto.spec.ts b/src/utils/picto.spec.ts index 422ec60c8630a678d1d7eeaec81be58fbd237bc3..c7ba738b0fd74e0715b3e6f97ca47decbff83c09 100644 --- a/src/utils/picto.spec.ts +++ b/src/utils/picto.spec.ts @@ -11,7 +11,7 @@ import iconGrdfWhiteLogo from 'assets/icons/visu/grdf-logo-white.svg' import iconGrdfLogo from 'assets/icons/visu/grdf-logo.svg' import MultiIcon from 'assets/icons/visu/multi-icon.svg' import WaterParamIcon from 'assets/icons/visu/water-param.svg' -import { FluidType } from 'enum/fluid.enum' +import { FluidType } from 'enums' import ElecSmallIcon from '../assets/icons/visu/elec-small.svg' import ElecIcon from '../assets/icons/visu/elec.svg' import GasSmallIcon from '../assets/icons/visu/gas-small.svg' diff --git a/src/utils/picto.ts b/src/utils/picto.ts index 54058b3d5dd0e91ec0cc317d5a44a21845ac08a7..0c8ae28308923a3373a21fcf45e2f56e672a4fcc 100644 --- a/src/utils/picto.ts +++ b/src/utils/picto.ts @@ -5,26 +5,26 @@ import Disconnected from 'assets/icons/visu/disconnected-grey.svg' import DisconnectedActive from 'assets/icons/visu/disconnected.svg' import iconEglWhiteLogo from 'assets/icons/visu/egl-logo-white.svg' import iconEglLogo from 'assets/icons/visu/egl-logo.svg' +import ElecUnactive from 'assets/icons/visu/elec-grey.svg' import ElecParamIcon from 'assets/icons/visu/elec-param.svg' +import ElecSmallIcon from 'assets/icons/visu/elec-small.svg' +import ElecIcon from 'assets/icons/visu/elec.svg' import iconEnedisWhiteLogo from 'assets/icons/visu/enedis-logo-white.svg' import iconEnedisLogo from 'assets/icons/visu/enedis-logo.svg' +import GasUnactive from 'assets/icons/visu/gas-grey.svg' import GasParamIcon from 'assets/icons/visu/gas-param.svg' +import GasSmallIcon from 'assets/icons/visu/gas-small.svg' +import GasIcon from 'assets/icons/visu/gas.svg' import iconGrdfWhiteLogo from 'assets/icons/visu/grdf-logo-white.svg' import iconGrdfLogo from 'assets/icons/visu/grdf-logo.svg' import MultiUnactive from 'assets/icons/visu/multi-grey.svg' import Multi from 'assets/icons/visu/multi.svg' +import WaterUnactive from 'assets/icons/visu/water-grey.svg' import WaterParamIcon from 'assets/icons/visu/water-param.svg' +import WaterSmallIcon from 'assets/icons/visu/water-small.svg' +import WaterIcon from 'assets/icons/visu/water.svg' +import { FluidType } from 'enums' import ConfigService from 'services/fluidConfig.service' -import ElecUnactive from '../assets/icons/visu/elec-grey.svg' -import ElecSmallIcon from '../assets/icons/visu/elec-small.svg' -import ElecIcon from '../assets/icons/visu/elec.svg' -import GasUnactive from '../assets/icons/visu/gas-grey.svg' -import GasSmallIcon from '../assets/icons/visu/gas-small.svg' -import GasIcon from '../assets/icons/visu/gas.svg' -import WaterUnactive from '../assets/icons/visu/water-grey.svg' -import WaterSmallIcon from '../assets/icons/visu/water-small.svg' -import WaterIcon from '../assets/icons/visu/water.svg' -import { FluidType } from '../enum/fluid.enum' /** * Return an icon corresponding to FluidType enum diff --git a/src/utils/utils.spec.ts b/src/utils/utils.spec.ts index 70bdbb0e64fa6c188fab3aa74620e854b63cffe7..1fe7e5944fb3ec95055b854411e2044d96d97af3 100644 --- a/src/utils/utils.spec.ts +++ b/src/utils/utils.spec.ts @@ -1,10 +1,14 @@ -import { Season } from 'enum/ecogesture.enum' -import { FluidState, FluidType } from 'enum/fluid.enum' -import { FluidSlugType } from 'enum/fluidSlug.enum' -import { KonnectorUpdate } from 'enum/konnectorUpdate.enum' +import { + FluidSlugType, + FluidState, + FluidType, + KonnectorUpdate, + Season, +} from 'enums' import { DateTime } from 'luxon' import { FluidStatus } from 'models' import { + formatListWithAnd, formatNumberValues, getChallengeTitleWithLineReturn, getFluidName, @@ -193,18 +197,18 @@ describe('utils test', () => { }) }) - describe('getMonthFullName', () => { + describe('getMonthName', () => { it('should return the name of the month', () => { expect(getMonthName(DateTime.local(2023, 6, 1))).toBe('juin') }) }) describe('getMonthNameWithPrep', () => { - it('should return the name of the month with " de " ', () => { + it('should return the name of the month with " de "', () => { const date = DateTime.fromISO('2020-11-29T23:59:59.999Z') expect(getMonthNameWithPrep(date)).toBe('de novembre') }) - it('should return the name of the month with " d\'" ', () => { + it('should return the name of the month with " d\'"', () => { const date = DateTime.fromISO('2020-10-29T23:59:59.999Z') expect(getMonthNameWithPrep(date)).toBe('d’octobre') }) @@ -224,4 +228,21 @@ describe('utils test', () => { expect(getFluidName(FluidType.MULTIFLUID)).toBe('multifluid') }) }) + + describe('formatListWithAnd', () => { + it('should return empty string', () => { + expect(formatListWithAnd([])).toBe('') + }) + it('should return single element', () => { + expect(formatListWithAnd(['pomme'])).toBe('pomme') + }) + it('should return two elements joined by "et"', () => { + expect(formatListWithAnd(['pomme', 'banane'])).toBe('pomme et banane') + }) + it('should return elements joined by commas except the last one with "et"', () => { + expect(formatListWithAnd(['pomme', 'banane', 'cerise'])).toBe( + 'pomme, banane et cerise' + ) + }) + }) }) diff --git a/src/utils/utils.ts b/src/utils/utils.ts index cae5a543900c147b1bf784d9e5b12705af4d3430..748166f31c588baca762f5c70ff252ac1900555e 100644 --- a/src/utils/utils.ts +++ b/src/utils/utils.ts @@ -1,11 +1,15 @@ -import { Season } from 'enum/ecogesture.enum' -import { FluidSlugType } from 'enum/fluidSlug.enum' +import { captureException } from '@sentry/react' +import { + FluidSlugType, + FluidState, + FluidType, + KonnectorUpdate, + Season, +} from 'enums' import get from 'lodash/get' import { DateTime, Interval } from 'luxon' import { FluidStatus, GetRelationshipsReturn, Relation } from 'models' import challengeData from '../db/challengeEntity.json' -import { FluidState, FluidType } from '../enum/fluid.enum' -import { KonnectorUpdate } from '../enum/konnectorUpdate.enum' export function getFluidType(type: string) { switch (type.toUpperCase()) { @@ -31,7 +35,8 @@ export function getKonnectorSlug(fluidType: FluidType) { throw new Error('unknown fluidtype') } } -/** Return lowercase fluidtype +/** + * Return lowercase fluidtype * @example FluidType.ELECTRICITY => 'electricity' */ export function getFluidName(fluidType: FluidType) { @@ -116,7 +121,7 @@ export function getRelationshipHasMany<D>(doc: D, relName: string): Relation[] { /** * Get many relations in doc * @param {object} doc - DocumentEntity - * @param {Array<[relName: string]: Array<Relation>>} relNameList - Array of name of the relations + * @param relNameList - Array of name of the relations */ export function getRelationships<D>( doc: D, @@ -128,20 +133,23 @@ export function getRelationships<D>( } /** - * @param id - * @param pathType + * Import a svg file with format : id.svg */ -export const importIconById = async (id: string, pathType: string) => { - // Les svg doivent être au format id.svg +export const importIconById = async ( + id: string, + pathType: string +): Promise<string | undefined> => { let importedChallengeIcon try { importedChallengeIcon = await import( /* webpackMode: "eager" */ `assets/icons/visu/${pathType}/${id}.svg` ) - // eslint-disable-next-line no-empty - } catch (e) {} - if (importedChallengeIcon) { - return importedChallengeIcon.default + if (importedChallengeIcon) { + return importedChallengeIcon.default + } + } catch (e) { + console.error(`Could not import icon ${pathType}/${id}`) + captureException(e) } } @@ -166,7 +174,7 @@ export const getMonthFullName = (month: number) => { /** * Return month string according to month index - * @Note Equivalent to date.monthLong + * @variation Equivalent to date.monthLong * @param date - DateTime * @returns month in french */ @@ -285,3 +293,30 @@ export const getTodayDate = () => keepLocalTime: true, }) .startOf('day') + +/** + * Formats an array of strings into a list with commas and an "et" (and) before the last element. + * @param {string[]} array - The array of strings to be formatted. + * @returns {string} The formatted list string. + * + * If the array is empty, an empty string is returned. + * If the array has only one element, that element is returned as is. + * If the array has two elements, they are joined with " et " (and). + * If the array has more than two elements, all but the last element are joined with commas, + * and " et " (and) is placed before the last element. + * @example + * // Returns "pomme, banane et cerise" + * formatListWithAnd(['pomme', 'banane', 'cerise']); + */ +export const formatListWithAnd = (array: string[]) => { + if (array.length === 0) { + return '' + } else if (array.length === 1) { + return array[0] + } else if (array.length === 2) { + return array.join(' et ') + } else { + const lastElement = array.pop() + return array.join(', ') + ' et ' + lastElement + } +} diff --git a/tests/__mocks__/actionData.mock.ts b/tests/__mocks__/actionData.mock.ts index 5cd2ef51f5264989d86f2f3604577f0795b516ef..c2a5d716ce300507c3dab2b34a7d7e8deafe53f3 100644 --- a/tests/__mocks__/actionData.mock.ts +++ b/tests/__mocks__/actionData.mock.ts @@ -1,4 +1,4 @@ -import { EquipmentType, Season } from 'enum/ecogesture.enum' +import { EquipmentType, Season } from 'enums' import { Ecogesture } from 'models' export const defaultEcogestureData: Ecogesture[] = [ diff --git a/tests/__mocks__/chartData.mock.ts b/tests/__mocks__/chartData.mock.ts index 4fd3ddd29cfa1692333444f391143f65949d0aaf..904a31f3e66e6f54ed8426584bf31f2bfd108b60 100644 --- a/tests/__mocks__/chartData.mock.ts +++ b/tests/__mocks__/chartData.mock.ts @@ -1,6 +1,6 @@ -import { Datachart, Dataload } from 'models' +import { DataloadState } from 'enums' import { DateTime } from 'luxon' -import { DataloadState } from 'enum/dataload.enum' +import { Datachart, Dataload } from 'models' export const graphData: Datachart = { actualData: [ diff --git a/tests/__mocks__/client.ts b/tests/__mocks__/client.mock.ts similarity index 100% rename from tests/__mocks__/client.ts rename to tests/__mocks__/client.mock.ts diff --git a/tests/__mocks__/customPopup.mock.ts b/tests/__mocks__/customPopup.mock.ts index 6576af638fc9d3cdf80094416d55b37722bc3c63..65c9b9d93101881fb1b78e2fc1bea274fca164f6 100644 --- a/tests/__mocks__/customPopup.mock.ts +++ b/tests/__mocks__/customPopup.mock.ts @@ -1,4 +1,4 @@ -import { CustomPopup } from 'models/customPopup.model' +import { CustomPopup } from 'models' export const mockCustomPopup: CustomPopup = { popupEnabled: true, diff --git a/tests/__mocks__/duelData.mock.ts b/tests/__mocks__/duelData.mock.ts index ec44157b84358a4ba9444ebd7d4f1aef6bbc9f87..f429b67a5eb2f8f1f2137870d1a985777e1e6e53 100644 --- a/tests/__mocks__/duelData.mock.ts +++ b/tests/__mocks__/duelData.mock.ts @@ -1,6 +1,6 @@ +import { UserDuelState } from 'enums' import { Duration } from 'luxon' -import { UserDuel, DuelEntity } from 'models' -import { UserDuelState } from 'enum/userDuel.enum' +import { DuelEntity, UserDuel } from 'models' export const duelEntity: DuelEntity = { id: 'DUEL001', diff --git a/tests/__mocks__/ecogesturesData.mock.ts b/tests/__mocks__/ecogesturesData.mock.ts index 827eb511a04bed69c722dd5a28d482be20ff15ed..c7a61cc907cfa7af7a4a2301c09c276d97aff0fe 100644 --- a/tests/__mocks__/ecogesturesData.mock.ts +++ b/tests/__mocks__/ecogesturesData.mock.ts @@ -1,5 +1,4 @@ -import { EquipmentType, Room, Season, Usage } from 'enum/ecogesture.enum' -import { FluidType } from 'enum/fluid.enum' +import { EquipmentType, FluidType, Room, Season, Usage } from 'enums' import { Ecogesture } from 'models' export const mockedEcogesturesData: Ecogesture[] = [ @@ -265,354 +264,6 @@ export const ecogesturesECSData: Ecogesture[] = [ }, ] -export const ecogesturesCookingData: Ecogesture[] = [ - { - fluidTypes: [FluidType.ELECTRICITY], - id: '001', - longDescription: - 'On se demande parfois si cela vaut le coup de "couper le chauffage" quand on s’absente… dès qu’il s’agit d’un week-end la réponse est « oui sûrement » ! Attention cependant au retour à ne pas faire de la surchauffe ! L’idéal est bien évidemment de régler sa programmation pour que le chauffage se relance quelques heures avant votre retour…', - longName: - "Je baisse le chauffage en mode hors gel lorsque je m'absente plus de 2 jours.", - shortName: 'Bonhomme de neige', - usage: Usage.COOKING, - impactLevel: 8, - efficiency: 4, - difficulty: 1, - room: [Room.ALL], - season: Season.WINTER, - equipment: false, - equipmentType: [], - equipmentInstallation: true, - investment: null, - action: false, - actionName: null, - actionDuration: 3, - doing: false, - objective: false, - viewedInSelection: false, - _id: '001', - _rev: '1-67f1ea36efdd892c96bf64a8943154cd', - _type: 'com.grandlyon.ecolyo.ecogesture', - }, - { - fluidTypes: [FluidType.GAS], - id: '002', - longDescription: - "Cela permet de garder la fraîcheur à l'intérieur. Le climatiseur n'est pas là pour refroidir la rue mais bien la pièce.", - longName: 'Je ferme mes fenêtres quand la climatisation est en marche', - shortName: 'Coup de vent', - usage: Usage.COOKING, - impactLevel: 8, - efficiency: 4, - difficulty: 1, - room: [Room.ALL], - season: Season.SUMMER, - equipment: true, - equipmentType: [EquipmentType.AIR_CONDITIONING], - equipmentInstallation: true, - investment: null, - action: false, - actionName: null, - actionDuration: 3, - doing: false, - objective: false, - viewedInSelection: false, - _id: '002', - _rev: '1-ef7ddd778254e3b7d331a88fd17f606d', - _type: 'com.grandlyon.ecolyo.ecogesture', - }, - { - fluidTypes: [FluidType.ELECTRICITY, FluidType.GAS], - id: '0013', - longDescription: - "Utilisez la température la plus basse possible : de nombreux produits nettoyants sont efficaces à froid et un cycle à 90 °C consomme 3 fois plus d'énergie qu'un lavage à 40 °C. En effet, 80 % de l'énergie consommée par un lave-linge ou un lave-vaisselle sert au chauffage de l'eau ! Que ce soit pour la vaisselle ou le linge, les programmes de lavage intensif consomment jusqu'à 40 % de plus. Si possible, rincez à l'eau froide : la température de rinçage n'a pas d'effet sur le nettoyage du linge ou de la vaisselle. Attention cependant avec les tissus qui peuvent rétrécir : ce qui fait rétrécir, c'est le passage d'une température à une autre. Mieux vaut alors faire le cycle complet à l'eau froide pour les premiers lavages de tissus sensibles. Pour du linge ou de la vaisselle peu sales, utilisez la touche \"Eco\". Elle réduit la température de lavage et allonge sa durée (c’est le chauffage de l’eau qui consomme le plus). Vous économiserez jusqu’à 45 % par rapport aux cycles longs. Néanmoins, pour vous prémunir contre les bouchons de graisse dans les canalisations, faites quand même un cycle à chaud une fois par mois environ.", - longName: - 'J’utilise le plus souvent les cycles courts à basse température pour laver le linge et la vaisselle.', - shortName: 'Accelerateur de particules', - usage: Usage.COOKING, - impactLevel: 2, - efficiency: 1, - difficulty: 1, - room: [Room.BATHROOM, Room.LAUNDRY, Room.KITCHEN], - season: Season.NONE, - equipment: true, - equipmentType: [EquipmentType.WASHING_MACHINE, EquipmentType.DISHWASHER], - equipmentInstallation: true, - investment: null, - action: true, - actionName: - 'J’utilise le cycle court à basse température pour laver le linge et la vaisselle.', - actionDuration: 3, - doing: false, - objective: false, - viewedInSelection: false, - _id: '0013', - _rev: '1-0b2761dd4aef79556c7aef144060fde6', - _type: 'com.grandlyon.ecolyo.ecogesture', - }, - { - fluidTypes: [FluidType.WATER], - id: '0014', - longDescription: - "Utilisez la température la plus basse possible : de nombreux produits nettoyants sont efficaces à froid et un cycle à 90 °C consomme 3 fois plus d'énergie qu'un lavage à 40 °C. En effet, 80 % de l'énergie consommée par un lave-linge ou un lave-vaisselle sert au chauffage de l'eau ! Que ce soit pour la vaisselle ou le linge, les programmes de lavage intensif consomment jusqu'à 40 % de plus. Si possible, rincez à l'eau froide : la température de rinçage n'a pas d'effet sur le nettoyage du linge ou de la vaisselle. Attention cependant avec les tissus qui peuvent rétrécir : ce qui fait rétrécir, c'est le passage d'une température à une autre. Mieux vaut alors faire le cycle complet à l'eau froide pour les premiers lavages de tissus sensibles. Pour du linge ou de la vaisselle peu sales, utilisez la touche \"Eco\". Elle réduit la température de lavage et allonge sa durée (c’est le chauffage de l’eau qui consomme le plus). Vous économiserez jusqu’à 45 % par rapport aux cycles longs. Néanmoins, pour vous prémunir contre les bouchons de graisse dans les canalisations, faites quand même un cycle à chaud une fois par mois environ.", - longName: - 'J’utilise le plus souvent les cycles courts à basse température pour laver le linge et la vaisselle.', - shortName: 'Accelerateur de particules', - usage: Usage.COOKING, - impactLevel: 2, - efficiency: 1, - difficulty: 1, - room: [Room.BATHROOM, Room.LAUNDRY, Room.KITCHEN], - season: Season.NONE, - equipment: true, - equipmentType: [EquipmentType.WASHING_MACHINE, EquipmentType.DISHWASHER], - equipmentInstallation: true, - investment: null, - action: true, - actionName: - 'J’attends que les plats chauds aient refroidi avant de les mettre au réfrigérateur et je les couvre.', - actionDuration: 3, - doing: false, - objective: false, - viewedInSelection: false, - _id: '0014', - _rev: '1-0b2761dd4aef79556c7aef144060fde6', - _type: 'com.grandlyon.ecolyo.ecogesture', - }, -] - -export const ecogesturesElecSpecificData: Ecogesture[] = [ - { - fluidTypes: [FluidType.ELECTRICITY], - id: '001', - longDescription: - 'On se demande parfois si cela vaut le coup de "couper le chauffage" quand on s’absente… dès qu’il s’agit d’un week-end la réponse est « oui sûrement » ! Attention cependant au retour à ne pas faire de la surchauffe ! L’idéal est bien évidemment de régler sa programmation pour que le chauffage se relance quelques heures avant votre retour…', - longName: - "Je baisse le chauffage en mode hors gel lorsque je m'absente plus de 2 jours.", - shortName: 'Bonhomme de neige', - usage: Usage.ELECTRICITY_SPECIFIC, - impactLevel: 8, - efficiency: 4, - difficulty: 1, - room: [Room.ALL], - season: Season.WINTER, - equipment: false, - equipmentType: [], - equipmentInstallation: true, - investment: null, - action: false, - actionName: null, - actionDuration: 3, - doing: false, - objective: false, - viewedInSelection: false, - _id: '001', - _rev: '1-67f1ea36efdd892c96bf64a8943154cd', - _type: 'com.grandlyon.ecolyo.ecogesture', - }, - { - fluidTypes: [FluidType.GAS], - id: '002', - longDescription: - "Cela permet de garder la fraîcheur à l'intérieur. Le climatiseur n'est pas là pour refroidir la rue mais bien la pièce.", - longName: 'Je ferme mes fenêtres quand la climatisation est en marche', - shortName: 'Coup de vent', - usage: Usage.ELECTRICITY_SPECIFIC, - impactLevel: 8, - efficiency: 4, - difficulty: 1, - room: [Room.ALL], - season: Season.SUMMER, - equipment: true, - equipmentType: [EquipmentType.AIR_CONDITIONING], - equipmentInstallation: true, - investment: null, - action: false, - actionName: null, - actionDuration: 3, - doing: false, - objective: false, - viewedInSelection: false, - _id: '002', - _rev: '1-ef7ddd778254e3b7d331a88fd17f606d', - _type: 'com.grandlyon.ecolyo.ecogesture', - }, - { - fluidTypes: [FluidType.WATER], - id: '0013', - longDescription: - "Utilisez la température la plus basse possible : de nombreux produits nettoyants sont efficaces à froid et un cycle à 90 °C consomme 3 fois plus d'énergie qu'un lavage à 40 °C. En effet, 80 % de l'énergie consommée par un lave-linge ou un lave-vaisselle sert au chauffage de l'eau ! Que ce soit pour la vaisselle ou le linge, les programmes de lavage intensif consomment jusqu'à 40 % de plus. Si possible, rincez à l'eau froide : la température de rinçage n'a pas d'effet sur le nettoyage du linge ou de la vaisselle. Attention cependant avec les tissus qui peuvent rétrécir : ce qui fait rétrécir, c'est le passage d'une température à une autre. Mieux vaut alors faire le cycle complet à l'eau froide pour les premiers lavages de tissus sensibles. Pour du linge ou de la vaisselle peu sales, utilisez la touche \"Eco\". Elle réduit la température de lavage et allonge sa durée (c’est le chauffage de l’eau qui consomme le plus). Vous économiserez jusqu’à 45 % par rapport aux cycles longs. Néanmoins, pour vous prémunir contre les bouchons de graisse dans les canalisations, faites quand même un cycle à chaud une fois par mois environ.", - longName: - 'J’utilise le plus souvent les cycles courts à basse température pour laver le linge et la vaisselle.', - shortName: 'Accelerateur de particules', - usage: Usage.ELECTRICITY_SPECIFIC, - impactLevel: 2, - efficiency: 1, - difficulty: 1, - room: [Room.BATHROOM, Room.LAUNDRY, Room.KITCHEN], - season: Season.NONE, - equipment: false, - equipmentType: [EquipmentType.WASHING_MACHINE, EquipmentType.DISHWASHER], - equipmentInstallation: true, - investment: null, - action: true, - actionName: - 'J’utilise le cycle court à basse température pour laver le linge et la vaisselle.', - actionDuration: 3, - doing: false, - objective: false, - viewedInSelection: false, - _id: '0013', - _rev: '1-0b2761dd4aef79556c7aef144060fde6', - _type: 'com.grandlyon.ecolyo.ecogesture', - }, -] - -export const ecogesturesAirConditioningData: Ecogesture[] = [ - { - fluidTypes: [FluidType.ELECTRICITY], - id: '001', - longDescription: - 'On se demande parfois si cela vaut le coup de "couper le chauffage" quand on s’absente… dès qu’il s’agit d’un week-end la réponse est « oui sûrement » ! Attention cependant au retour à ne pas faire de la surchauffe ! L’idéal est bien évidemment de régler sa programmation pour que le chauffage se relance quelques heures avant votre retour…', - longName: - "Je baisse le chauffage en mode hors gel lorsque je m'absente plus de 2 jours.", - shortName: 'Bonhomme de neige', - usage: Usage.AIR_CONDITIONING, - impactLevel: 8, - efficiency: 4, - difficulty: 1, - room: [Room.ALL], - season: Season.WINTER, - equipment: false, - equipmentType: [], - equipmentInstallation: true, - investment: null, - action: false, - actionName: null, - actionDuration: 3, - doing: false, - objective: false, - viewedInSelection: false, - _id: '001', - _rev: '1-67f1ea36efdd892c96bf64a8943154cd', - _type: 'com.grandlyon.ecolyo.ecogesture', - }, - { - fluidTypes: [FluidType.GAS], - id: '002', - longDescription: - "Cela permet de garder la fraîcheur à l'intérieur. Le climatiseur n'est pas là pour refroidir la rue mais bien la pièce.", - longName: 'Je ferme mes fenêtres quand la climatisation est en marche', - shortName: 'Coup de vent', - usage: Usage.AIR_CONDITIONING, - impactLevel: 8, - efficiency: 4, - difficulty: 1, - room: [Room.ALL], - season: Season.SUMMER, - equipment: true, - equipmentType: [EquipmentType.AIR_CONDITIONING], - equipmentInstallation: true, - investment: null, - action: false, - actionName: null, - actionDuration: 3, - doing: false, - objective: false, - viewedInSelection: false, - _id: '002', - _rev: '1-ef7ddd778254e3b7d331a88fd17f606d', - _type: 'com.grandlyon.ecolyo.ecogesture', - }, - { - fluidTypes: [FluidType.WATER], - id: '0013', - longDescription: - "Utilisez la température la plus basse possible : de nombreux produits nettoyants sont efficaces à froid et un cycle à 90 °C consomme 3 fois plus d'énergie qu'un lavage à 40 °C. En effet, 80 % de l'énergie consommée par un lave-linge ou un lave-vaisselle sert au chauffage de l'eau ! Que ce soit pour la vaisselle ou le linge, les programmes de lavage intensif consomment jusqu'à 40 % de plus. Si possible, rincez à l'eau froide : la température de rinçage n'a pas d'effet sur le nettoyage du linge ou de la vaisselle. Attention cependant avec les tissus qui peuvent rétrécir : ce qui fait rétrécir, c'est le passage d'une température à une autre. Mieux vaut alors faire le cycle complet à l'eau froide pour les premiers lavages de tissus sensibles. Pour du linge ou de la vaisselle peu sales, utilisez la touche \"Eco\". Elle réduit la température de lavage et allonge sa durée (c’est le chauffage de l’eau qui consomme le plus). Vous économiserez jusqu’à 45 % par rapport aux cycles longs. Néanmoins, pour vous prémunir contre les bouchons de graisse dans les canalisations, faites quand même un cycle à chaud une fois par mois environ.", - longName: - 'J’utilise le plus souvent les cycles courts à basse température pour laver le linge et la vaisselle.', - shortName: 'Accelerateur de particules', - usage: Usage.AIR_CONDITIONING, - impactLevel: 2, - efficiency: 1, - difficulty: 1, - room: [Room.BATHROOM, Room.LAUNDRY, Room.KITCHEN], - season: Season.NONE, - equipment: false, - equipmentType: [EquipmentType.WASHING_MACHINE, EquipmentType.DISHWASHER], - equipmentInstallation: true, - investment: null, - action: true, - actionName: - 'J’utilise le cycle court à basse température pour laver le linge et la vaisselle.', - actionDuration: 3, - doing: false, - objective: false, - viewedInSelection: false, - _id: '0013', - _rev: '1-0b2761dd4aef79556c7aef144060fde6', - _type: 'com.grandlyon.ecolyo.ecogesture', - }, -] - -export const ecogesturesColdWaterData: Ecogesture[] = [ - { - fluidTypes: [FluidType.WATER], - id: '001', - longDescription: - 'On se demande parfois si cela vaut le coup de "couper le chauffage" quand on s’absente… dès qu’il s’agit d’un week-end la réponse est « oui sûrement » ! Attention cependant au retour à ne pas faire de la surchauffe ! L’idéal est bien évidemment de régler sa programmation pour que le chauffage se relance quelques heures avant votre retour…', - longName: - "Je baisse le chauffage en mode hors gel lorsque je m'absente plus de 2 jours.", - shortName: 'Bonhomme de neige', - usage: Usage.COLD_WATER, - impactLevel: 8, - efficiency: 4, - difficulty: 1, - room: [Room.ALL], - season: Season.WINTER, - equipment: false, - equipmentType: [], - equipmentInstallation: true, - investment: null, - action: false, - actionName: null, - actionDuration: 3, - doing: false, - objective: false, - viewedInSelection: false, - _id: '001', - _rev: '1-67f1ea36efdd892c96bf64a8943154cd', - _type: 'com.grandlyon.ecolyo.ecogesture', - }, - { - fluidTypes: [FluidType.WATER], - id: '002', - longDescription: - "Cela permet de garder la fraîcheur à l'intérieur. Le climatiseur n'est pas là pour refroidir la rue mais bien la pièce.", - longName: 'Je ferme mes fenêtres quand la climatisation est en marche', - shortName: 'Coup de vent', - usage: Usage.COLD_WATER, - impactLevel: 8, - efficiency: 4, - difficulty: 1, - room: [Room.ALL], - season: Season.SUMMER, - equipment: true, - equipmentType: [EquipmentType.AIR_CONDITIONING], - equipmentInstallation: true, - investment: null, - action: false, - actionName: null, - actionDuration: 3, - doing: false, - objective: false, - viewedInSelection: false, - _id: '002', - _rev: '1-ef7ddd778254e3b7d331a88fd17f606d', - _type: 'com.grandlyon.ecolyo.ecogesture', - }, -] - export const BoilerEcogesture: Ecogesture[] = [ { fluidTypes: [FluidType.ELECTRICITY, FluidType.WATER], diff --git a/tests/__mocks__/enedisMonthlyAnalysisData.mock.ts b/tests/__mocks__/enedisMonthlyAnalysisData.mock.ts index 76c474dfb3341bf1f0dda0a31dfcba588dbe0822..bba9d3cc07c5222e83525b1e029b4752ec3acf3c 100644 --- a/tests/__mocks__/enedisMonthlyAnalysisData.mock.ts +++ b/tests/__mocks__/enedisMonthlyAnalysisData.mock.ts @@ -1,10 +1,10 @@ -import { DataloadState } from 'enum/dataload.enum' +import { DataloadState } from 'enums' import { DateTime } from 'luxon' +import { MaxPowerEntity } from 'models' import { AggregatedEnedisMonthlyDataloads, EnedisMonthlyAnalysisData, } from 'models/enedisMonthlyAnalysis' -import { MaxPowerEntity } from 'models/maxPower.model' export const mockEnedisMonthlyAnalysis: EnedisMonthlyAnalysisData = { weekDaysHalfHourAverageValues: [0.35, 0.34, 0.33, 0.32, 0.31, 0.3], diff --git a/tests/__mocks__/explorationData.mock.ts b/tests/__mocks__/explorationData.mock.ts index a5ea25b2a4725c8c036c236944127b4d28732776..baed6c85d8e3398975596c4865cd8d4d7a7f18f4 100644 --- a/tests/__mocks__/explorationData.mock.ts +++ b/tests/__mocks__/explorationData.mock.ts @@ -1,8 +1,5 @@ /* eslint-disable camelcase */ -import { - UserExplorationState, - UserExplorationType, -} from 'enum/userExploration.enum' +import { UserExplorationState, UserExplorationType } from 'enums' import { ExplorationEntity, UserExploration } from 'models' export const explorationEntity: ExplorationEntity = { diff --git a/tests/__mocks__/fetchDayData.mock.ts b/tests/__mocks__/fetchDayData.mock.ts new file mode 100644 index 0000000000000000000000000000000000000000..800fdcf75058aecc9c709fc9001e0082c781ff17 --- /dev/null +++ b/tests/__mocks__/fetchDayData.mock.ts @@ -0,0 +1,375 @@ +import { DataloadState } from 'enums' +import { DateTime } from 'luxon' +import { Dataload } from 'models' + +export const fetchDayDataIncomplete: Dataload[] = [ + { + date: DateTime.fromISO('2023-07-02T00:00:00.000Z'), + value: 56.8, + state: DataloadState.VALID, + valueDetail: null, + }, + { + date: DateTime.fromISO('2023-07-03T00:00:00.000Z'), + value: 37.66, + state: DataloadState.VALID, + valueDetail: null, + }, + { + date: DateTime.fromISO('2023-07-04T00:00:00.000Z'), + value: 39.58, + state: DataloadState.VALID, + valueDetail: null, + }, + { + date: DateTime.fromISO('2023-07-05T00:00:00.000Z'), + value: 46.81, + state: DataloadState.VALID, + valueDetail: null, + }, + { + date: DateTime.fromISO('2023-07-06T00:00:00.000Z'), + value: 45.83, + state: DataloadState.VALID, + valueDetail: null, + }, + { + date: DateTime.fromISO('2023-07-07T00:00:00.000Z'), + value: 22.95, + state: DataloadState.VALID, + valueDetail: null, + }, + { + date: DateTime.fromISO('2023-07-08T00:00:00.000Z'), + value: 38.95, + state: DataloadState.VALID, + valueDetail: null, + }, + { + date: DateTime.fromISO('2023-07-09T00:00:00.000Z'), + value: 22.23, + state: DataloadState.VALID, + valueDetail: null, + }, + { + date: DateTime.fromISO('2023-07-10T00:00:00.000Z'), + value: 49.86, + state: DataloadState.VALID, + valueDetail: null, + }, + { + date: DateTime.fromISO('2023-07-11T00:00:00.000Z'), + value: 62.78, + state: DataloadState.VALID, + valueDetail: null, + }, + { + date: DateTime.fromISO('2023-07-12T00:00:00.000Z'), + value: 45.44, + state: DataloadState.VALID, + valueDetail: null, + }, + { + date: DateTime.fromISO('2023-07-13T00:00:00.000Z'), + value: 66.06, + state: DataloadState.VALID, + valueDetail: null, + }, + { + date: DateTime.fromISO('2023-07-14T00:00:00.000Z'), + value: 22.29, + state: DataloadState.VALID, + valueDetail: null, + }, + { + date: DateTime.fromISO('2023-07-15T00:00:00.000Z'), + value: 43.06, + state: DataloadState.VALID, + valueDetail: null, + }, + { + date: DateTime.fromISO('2023-07-16T00:00:00.000Z'), + value: 25.35, + state: DataloadState.VALID, + valueDetail: null, + }, + { + date: DateTime.fromISO('2023-07-17T00:00:00.000Z'), + value: 16.24, + state: DataloadState.VALID, + valueDetail: null, + }, + { + date: DateTime.fromISO('2023-07-18T00:00:00.000Z'), + value: 36.4, + state: DataloadState.VALID, + valueDetail: null, + }, + { + date: DateTime.fromISO('2023-07-19T00:00:00.000Z'), + value: 54.38, + state: DataloadState.VALID, + valueDetail: null, + }, + { + date: DateTime.fromISO('2023-07-20T00:00:00.000Z'), + value: 55.99, + state: DataloadState.VALID, + valueDetail: null, + }, + { + date: DateTime.fromISO('2023-07-21T00:00:00.000Z'), + value: 55.96, + state: DataloadState.VALID, + valueDetail: null, + }, + { + date: DateTime.fromISO('2023-07-22T00:00:00.000Z'), + value: 30.11, + state: DataloadState.VALID, + valueDetail: null, + }, + { + date: DateTime.fromISO('2023-07-23T00:00:00.000Z'), + value: 17.08, + state: DataloadState.VALID, + valueDetail: null, + }, + { + date: DateTime.fromISO('2023-07-24T00:00:00.000Z'), + value: 63.52, + state: DataloadState.VALID, + valueDetail: null, + }, + { + date: DateTime.fromISO('2023-07-25T00:00:00.000Z'), + value: 23.64, + state: DataloadState.VALID, + valueDetail: null, + }, + { + date: DateTime.fromISO('2023-07-26T00:00:00.000Z'), + value: 61.71, + state: DataloadState.VALID, + valueDetail: null, + }, + { + date: DateTime.fromISO('2023-07-27T00:00:00.000Z'), + value: 25.13, + state: DataloadState.VALID, + valueDetail: null, + }, + { + date: DateTime.fromISO('2023-07-28T00:00:00.000Z'), + value: 50.61, + state: DataloadState.VALID, + valueDetail: null, + }, + { + date: DateTime.fromISO('2023-07-29T00:00:00.000Z'), + value: 25.86, + state: DataloadState.VALID, + valueDetail: null, + }, + { + date: DateTime.fromISO('2023-07-30T00:00:00.000Z'), + value: 44.85, + state: DataloadState.VALID, + valueDetail: null, + }, + { + date: DateTime.fromISO('2023-07-31T00:00:00.000Z'), + value: 34.09, + state: DataloadState.VALID, + valueDetail: null, + }, +] + +export const fetchDayDataComplete: Dataload[] = [ + { + date: DateTime.fromISO('2023-07-01T00:00:00.000Z'), + value: 35.53, + state: DataloadState.VALID, + valueDetail: null, + }, + { + date: DateTime.fromISO('2023-07-02T00:00:00.000Z'), + value: 56.8, + state: DataloadState.VALID, + valueDetail: null, + }, + { + date: DateTime.fromISO('2023-07-03T00:00:00.000Z'), + value: 37.66, + state: DataloadState.VALID, + valueDetail: null, + }, + { + date: DateTime.fromISO('2023-07-04T00:00:00.000Z'), + value: 39.58, + state: DataloadState.VALID, + valueDetail: null, + }, + { + date: DateTime.fromISO('2023-07-05T00:00:00.000Z'), + value: 46.81, + state: DataloadState.VALID, + valueDetail: null, + }, + { + date: DateTime.fromISO('2023-07-06T00:00:00.000Z'), + value: 45.83, + state: DataloadState.VALID, + valueDetail: null, + }, + { + date: DateTime.fromISO('2023-07-07T00:00:00.000Z'), + value: 22.95, + state: DataloadState.VALID, + valueDetail: null, + }, + { + date: DateTime.fromISO('2023-07-08T00:00:00.000Z'), + value: 38.95, + state: DataloadState.VALID, + valueDetail: null, + }, + { + date: DateTime.fromISO('2023-07-09T00:00:00.000Z'), + value: 22.23, + state: DataloadState.VALID, + valueDetail: null, + }, + { + date: DateTime.fromISO('2023-07-10T00:00:00.000Z'), + value: 49.86, + state: DataloadState.VALID, + valueDetail: null, + }, + { + date: DateTime.fromISO('2023-07-11T00:00:00.000Z'), + value: 62.78, + state: DataloadState.VALID, + valueDetail: null, + }, + { + date: DateTime.fromISO('2023-07-12T00:00:00.000Z'), + value: 45.44, + state: DataloadState.VALID, + valueDetail: null, + }, + { + date: DateTime.fromISO('2023-07-13T00:00:00.000Z'), + value: 66.06, + state: DataloadState.VALID, + valueDetail: null, + }, + { + date: DateTime.fromISO('2023-07-14T00:00:00.000Z'), + value: 22.29, + state: DataloadState.VALID, + valueDetail: null, + }, + { + date: DateTime.fromISO('2023-07-15T00:00:00.000Z'), + value: 43.06, + state: DataloadState.VALID, + valueDetail: null, + }, + { + date: DateTime.fromISO('2023-07-16T00:00:00.000Z'), + value: 25.35, + state: DataloadState.VALID, + valueDetail: null, + }, + { + date: DateTime.fromISO('2023-07-17T00:00:00.000Z'), + value: 16.24, + state: DataloadState.VALID, + valueDetail: null, + }, + { + date: DateTime.fromISO('2023-07-18T00:00:00.000Z'), + value: 36.4, + state: DataloadState.VALID, + valueDetail: null, + }, + { + date: DateTime.fromISO('2023-07-19T00:00:00.000Z'), + value: 54.38, + state: DataloadState.VALID, + valueDetail: null, + }, + { + date: DateTime.fromISO('2023-07-20T00:00:00.000Z'), + value: 55.99, + state: DataloadState.VALID, + valueDetail: null, + }, + { + date: DateTime.fromISO('2023-07-21T00:00:00.000Z'), + value: 55.96, + state: DataloadState.VALID, + valueDetail: null, + }, + { + date: DateTime.fromISO('2023-07-22T00:00:00.000Z'), + value: 30.11, + state: DataloadState.VALID, + valueDetail: null, + }, + { + date: DateTime.fromISO('2023-07-23T00:00:00.000Z'), + value: 17.08, + state: DataloadState.VALID, + valueDetail: null, + }, + { + date: DateTime.fromISO('2023-07-24T00:00:00.000Z'), + value: 63.52, + state: DataloadState.VALID, + valueDetail: null, + }, + { + date: DateTime.fromISO('2023-07-25T00:00:00.000Z'), + value: 23.64, + state: DataloadState.VALID, + valueDetail: null, + }, + { + date: DateTime.fromISO('2023-07-26T00:00:00.000Z'), + value: 61.71, + state: DataloadState.VALID, + valueDetail: null, + }, + { + date: DateTime.fromISO('2023-07-27T00:00:00.000Z'), + value: 25.13, + state: DataloadState.VALID, + valueDetail: null, + }, + { + date: DateTime.fromISO('2023-07-28T00:00:00.000Z'), + value: 50.61, + state: DataloadState.VALID, + valueDetail: null, + }, + { + date: DateTime.fromISO('2023-07-29T00:00:00.000Z'), + value: 25.86, + state: DataloadState.VALID, + valueDetail: null, + }, + { + date: DateTime.fromISO('2023-07-30T00:00:00.000Z'), + value: 44.85, + state: DataloadState.VALID, + valueDetail: null, + }, + { + date: DateTime.fromISO('2023-07-31T00:00:00.000Z'), + value: 34.09, + state: DataloadState.VALID, + valueDetail: null, + }, +] diff --git a/tests/__mocks__/fluidStatusData.mock.ts b/tests/__mocks__/fluidStatusData.mock.ts index 684bd3346c7dae958172d46530bf775624788b57..b9e9880732e2e22c19f93b99906c0326ab0a6394 100644 --- a/tests/__mocks__/fluidStatusData.mock.ts +++ b/tests/__mocks__/fluidStatusData.mock.ts @@ -1,9 +1,7 @@ /* eslint-disable camelcase */ -import { FluidState } from 'enum/fluid.enum' -import { FluidSlugType } from 'enum/fluidSlug.enum' +import { FluidSlugType, FluidState, FluidType } from 'enums' import { DateTime } from 'luxon' import { FluidStatus } from 'models' -import { PartnersInfo } from 'models/partnersInfo.model' export const fluidStatusData: FluidStatus[] = [ { @@ -85,18 +83,6 @@ export const fluidStatusData: FluidStatus[] = [ }, }, ] -export const mockPartnersInfoActivated: PartnersInfo = { - grdf_failure: true, - enedis_failure: true, - egl_failure: true, - notification_activated: true, -} -export const mockPartnersInfoDisabled: PartnersInfo = { - grdf_failure: false, - enedis_failure: false, - egl_failure: false, - notification_activated: false, -} export const fluidStatusConnectedData: FluidStatus[] = [ { @@ -237,3 +223,72 @@ export const SgeStatusWithAccount: FluidStatus = { }, }, } + +export const mockExpiredElec: FluidStatus = { + fluidType: FluidType.ELECTRICITY, + status: FluidState.KONNECTOR_NOT_FOUND, + maintenance: true, + firstDataDate: null, + lastDataDate: null, + connection: { + shouldLaunchKonnector: false, + isUpdating: false, + konnector: null, + account: { + _id: '1', + account_type: 'test', + data: { + consentId: 1, + expirationDate: '1999-08-08', + }, + }, + trigger: null, + triggerState: { + trigger_id: '0', + status: '', + last_executed_job_id: '', + last_execution: '', + last_manual_execution: '', + last_manual_job_id: '', + last_error: 'USER_ACTION_NEEDED.OAUTH_OUTDATED', + }, + konnectorConfig: { + name: '', + oauth: false, + slug: FluidSlugType.ELECTRICITY, + siteLink: '', + activation: '', + }, + }, +} + +export const mockExpiredGas: FluidStatus = { + fluidType: FluidType.GAS, + status: FluidState.ERROR_LOGIN_FAILED, + maintenance: false, + firstDataDate: null, + lastDataDate: null, + connection: { + shouldLaunchKonnector: false, + isUpdating: false, + konnector: null, + account: null, + trigger: null, + triggerState: { + trigger_id: '0', + status: '', + last_executed_job_id: '', + last_execution: '', + last_manual_execution: '', + last_manual_job_id: '', + last_error: 'USER_ACTION_NEEDED.OAUTH_OUTDATED', + }, + konnectorConfig: { + name: '', + oauth: false, + slug: FluidSlugType.GAS, + siteLink: '', + activation: '', + }, + }, +} diff --git a/tests/__mocks__/profileData.mock.ts b/tests/__mocks__/profileData.mock.ts index 5aa144b8624de319827fed50f712142574a2423c..82a92073ab89b9f5aed02680d149d039b8d5bdb3 100644 --- a/tests/__mocks__/profileData.mock.ts +++ b/tests/__mocks__/profileData.mock.ts @@ -1,6 +1,7 @@ import { DateTime } from 'luxon' import { Profile } from 'models' +// TODO to remove ? export const profileData: Profile = { _id: '4d9403218ef13e65b2e3a8ad1700bc41', _rev: '16-57473da4fc26315247c217083175dfa0', diff --git a/tests/__mocks__/profileEcogesture.mock.ts b/tests/__mocks__/profileEcogesture.mock.ts index 5489fead6c303f7c780c3fb55c13c3aad1969510..d73e1e654c1dae93d7c8cfc3e6024e8b6fdb681d 100644 --- a/tests/__mocks__/profileEcogesture.mock.ts +++ b/tests/__mocks__/profileEcogesture.mock.ts @@ -1,10 +1,10 @@ -import { EquipmentType } from 'enum/ecogesture.enum' -import { ProfileEcogestureAnswerType } from 'enum/ecogestureForm.enum' -import { IndividualOrCollective, WarmingType } from 'enum/profileType.enum' import { - ProfileEcogesture, - ProfileEcogestureAnswer, -} from 'models/profileEcogesture.model' + EquipmentType, + IndividualOrCollective, + ProfileEcogestureAnswerType, + WarmingType, +} from 'enums' +import { ProfileEcogesture, ProfileEcogestureAnswer } from 'models' export const mockProfileEcogesture: ProfileEcogesture = { heating: IndividualOrCollective.INDIVIDUAL, diff --git a/tests/__mocks__/profileType.mock.ts b/tests/__mocks__/profileType.mock.ts index 7dcd4672215673997ab49455e9c3b743ba8ae30d..37580a53f4211e99059ea7d33a52d4103e5fa2b8 100644 --- a/tests/__mocks__/profileType.mock.ts +++ b/tests/__mocks__/profileType.mock.ts @@ -1,7 +1,7 @@ -import { FluidType } from 'enum/fluid.enum' import { ConstructionYear, Floor, + FluidType, HotWaterEquipment, HotWaterFluid, HousingType, @@ -11,13 +11,9 @@ import { ProfileTypeFormType, ThreeChoicesAnswer, WarmingType, -} from 'enum/profileType.enum' +} from 'enums' import { DateTime } from 'luxon' -import { - MonthlyForecast, - ProfileType, - ProfileTypeAnswer, -} from 'models/profileType.model' +import { MonthlyForecast, ProfileType, ProfileTypeAnswer } from 'models' export const profileTypeData: ProfileType = { _id: 'ed8a160e06431be15c8fdbb428000f6a', @@ -105,8 +101,6 @@ export const mockProfileType1: ProfileType = { }), equipments: [], } -export const mockEstimatedConsumption1 = 6450 -export const mockCorrectedConsumption1 = 6450 // For the month of February export const mockMonthConsumption1 = 1174 @@ -134,7 +128,6 @@ export const mockProfileType2: ProfileType = { }), equipments: [], } -export const mockEstimatedConsumption2 = 16560 export const mockCorrectedConsumption2 = 15411 // For the month of January export const mockMonthConsumption2 = 3000 diff --git a/tests/__mocks__/quizData.mock.ts b/tests/__mocks__/quizData.mock.ts index 0a21247893b0e923de30e12997d0256595323fe1..87d068aded235c6a45f1821b93f9a587dfe1dd21 100644 --- a/tests/__mocks__/quizData.mock.ts +++ b/tests/__mocks__/quizData.mock.ts @@ -1,14 +1,9 @@ -import { TimeStep } from 'enum/timeStep.enum' -import { - CustomQuestionType, - UserQuestionState, - UserQuizState, -} from 'enum/userQuiz.enum' +import { CustomQuestionType, TimeStep, UserQuizState } from 'enums' import { DateTime } from 'luxon' import { - QuizEntity, - QuestionEntity, CustomQuestionEntity, + QuestionEntity, + QuizEntity, UserQuiz, } from 'models' @@ -40,7 +35,7 @@ export const customQuestionEntity: CustomQuestionEntity = { singleFluid: false, } -export const questionEntities: QuestionEntity[] = [ +const questionEntities: QuestionEntity[] = [ { questionLabel: 'Quelle longueur faisait l’aqueduc du Gier pour acheminer l’eau sur Lyon à l’époque romaine ?', @@ -279,79 +274,3 @@ export const userQuiz: UserQuiz = { result: 0, state: UserQuizState.UNLOCKED, } - -export const userQuizDone: UserQuiz = { - customQuestion: { - period: {}, - interval: TimeStep.DAY, - questionLabel: 'Custom1', - timeStep: TimeStep.DAY, - type: CustomQuestionType.DATE, - result: 0, - singleFluid: false, - }, - id: 'QUIZ001', - questions: [ - { - answers: [ - { answerLabel: '86 km', isTrue: true }, - { answerLabel: '78 km', isTrue: false }, - { answerLabel: '56 km', isTrue: false }, - ], - explanation: - "L’aqueduc du Gier est un des aqueducs antiques de Lyon desservant la ville antique de Lugdunum. Avec ses 86 km il est le plus long des quatre aqueducs ayant alimenté la ville en eau, et celui dont les structures sont le mieux conservées. Il doit son nom au fait qu'il puise aux sources du Gier, affluent du Rhône", - questionLabel: - 'Quelle longueur faisait l’aqueduc du Gier pour acheminer l’eau sur Lyon à l’époque romaine ?', - result: UserQuestionState.CORRECT, - source: 'string', - }, - { - answers: [ - { - answerLabel: '1 point d’eau public pour 800 habitants.', - isTrue: true, - }, - { - answerLabel: '1 point d’eau public pour 400 habitants.', - isTrue: false, - }, - { - answerLabel: '1 point d’eau public pour 200 habitants.', - isTrue: false, - }, - ], - explanation: 'string', - questionLabel: - "En 1800 à Lyon, combien de points d'eau y avait-il par habitants ?", - result: UserQuestionState.CORRECT, - source: 'string', - }, - { - answers: [ - { answerLabel: 'François Mitterrand', isTrue: false }, - { answerLabel: 'Napoléon Ier', isTrue: true }, - { answerLabel: 'Napoléon III', isTrue: false }, - ], - explanation: 'string', - questionLabel: - 'Qui officialise la création de la Compagnie Générale des eaux ?', - result: UserQuestionState.CORRECT, - source: 'string', - }, - { - answers: [ - { answerLabel: 'string', isTrue: false }, - { answerLabel: 'string', isTrue: false }, - { answerLabel: 'Aristide Dumont', isTrue: true }, - ], - explanation: 'string', - questionLabel: - 'Quel ingénieur est à l’origine du projet d’alimentation en eau en 1856 ?', - result: UserQuestionState.UNCORRECT, - source: 'string', - }, - ], - startDate: null, - result: 3, - state: UserQuizState.DONE, -} diff --git a/tests/__mocks__/store.ts b/tests/__mocks__/store.ts deleted file mode 100644 index d3540b60bbc3d2eecdb72a8a97d28905891c600d..0000000000000000000000000000000000000000 --- a/tests/__mocks__/store.ts +++ /dev/null @@ -1,351 +0,0 @@ -/* eslint-disable camelcase */ -import { FluidState, FluidType } from 'enum/fluid.enum' -import { FluidSlugType } from 'enum/fluidSlug.enum' -import { - ConstructionYear, - Floor, - HotWaterEquipment, - HotWaterFluid, - HousingType, - IndividualInsulationWork, - IndividualOrCollective, - OutsideFacingWalls, - ThreeChoicesAnswer, - WarmingType, -} from 'enum/profileType.enum' -import { ScreenType } from 'enum/screen.enum' -import { TimeStep } from 'enum/timeStep.enum' -import { DateTime } from 'luxon' -import { - AnalysisState, - ChallengeState, - ChartState, - FluidStatus, - GlobalState, - ModalState, - Profile, - ProfileType, -} from 'models' -import { ProfileEcogesture } from 'models/profileEcogesture.model' -import configureStore from 'redux-mock-store' -import thunkMiddleware from 'redux-thunk' -import { AppActionsTypes, EcolyoState } from 'store' -import mockClient from './client' -import { mockProfileEcogesture } from './profileEcogesture.mock' - -export const mockInitialGlobalState: GlobalState = { - screenType: ScreenType.MOBILE, - challengeExplorationNotification: false, - challengeActionNotification: false, - challengeDuelNotification: false, - analysisNotification: false, - termsStatus: { - accepted: true, - versionType: 'init', - }, - partnersInfo: { - egl_failure: false, - enedis_failure: false, - grdf_failure: false, - notification_activated: false, - }, - releaseNotes: { - show: false, - notes: [{ description: '', title: '' }], - }, - fluidStatus: [ - { - fluidType: FluidType.ELECTRICITY, - status: FluidState.KONNECTOR_NOT_FOUND, - maintenance: false, - firstDataDate: null, - lastDataDate: null, - connection: { - shouldLaunchKonnector: false, - isUpdating: false, - konnector: null, - account: null, - trigger: null, - triggerState: null, - konnectorConfig: { - name: '', - oauth: false, - slug: FluidSlugType.ELECTRICITY, - siteLink: '', - activation: '', - }, - }, - }, - { - fluidType: FluidType.WATER, - status: FluidState.KONNECTOR_NOT_FOUND, - maintenance: false, - firstDataDate: null, - lastDataDate: null, - connection: { - shouldLaunchKonnector: false, - isUpdating: false, - konnector: null, - account: null, - trigger: null, - triggerState: null, - konnectorConfig: { - name: '', - oauth: false, - slug: FluidSlugType.WATER, - siteLink: '', - activation: '', - }, - }, - }, - { - fluidType: FluidType.GAS, - status: FluidState.KONNECTOR_NOT_FOUND, - maintenance: false, - firstDataDate: null, - lastDataDate: null, - connection: { - shouldLaunchKonnector: false, - isUpdating: false, - konnector: null, - account: null, - trigger: null, - triggerState: null, - konnectorConfig: { - name: '', - oauth: false, - slug: FluidSlugType.GAS, - siteLink: '', - activation: '', - }, - }, - }, - ], - fluidTypes: [], - shouldRefreshConsent: false, - sgeConnect: { - address: '', - city: '', - currentStep: 0, - dataConsent: false, - firstName: '', - lastName: '', - pdl: null, - pdlConfirm: false, - zipCode: null, - shouldLaunchAccount: false, - }, -} -export const mockExpiredElec: FluidStatus = { - fluidType: FluidType.ELECTRICITY, - status: FluidState.KONNECTOR_NOT_FOUND, - maintenance: true, - firstDataDate: null, - lastDataDate: null, - connection: { - shouldLaunchKonnector: false, - isUpdating: false, - konnector: null, - account: { - _id: '1', - account_type: 'test', - data: { - consentId: 1, - expirationDate: '1999-08-08', - }, - }, - trigger: null, - triggerState: { - trigger_id: '0', - status: '', - last_executed_job_id: '', - last_execution: '', - last_manual_execution: '', - last_manual_job_id: '', - last_error: 'USER_ACTION_NEEDED.OAUTH_OUTDATED', - }, - konnectorConfig: { - name: '', - oauth: false, - slug: FluidSlugType.ELECTRICITY, - siteLink: '', - activation: '', - }, - }, -} - -export const mockExpiredGas: FluidStatus = { - fluidType: FluidType.GAS, - status: FluidState.ERROR_LOGIN_FAILED, - maintenance: false, - firstDataDate: null, - lastDataDate: null, - connection: { - shouldLaunchKonnector: false, - isUpdating: false, - konnector: null, - account: null, - trigger: null, - triggerState: { - trigger_id: '0', - status: '', - last_executed_job_id: '', - last_execution: '', - last_manual_execution: '', - last_manual_job_id: '', - last_error: 'USER_ACTION_NEEDED.OAUTH_OUTDATED', - }, - konnectorConfig: { - name: '', - oauth: false, - slug: FluidSlugType.GAS, - siteLink: '', - activation: '', - }, - }, -} -export const mockMaintenanceGas: FluidStatus = { - ...mockExpiredGas, - maintenance: true, -} - -export const mockInitialProfileState: Profile = { - id: '', - ecogestureHash: '', - challengeHash: '', - duelHash: '', - quizHash: '', - explorationHash: '', - isFirstConnection: false, - partnersIssueSeenDate: { - enedis: DateTime.fromISO('0000-01-01T00:00:00.000Z'), - egl: DateTime.fromISO('0000-01-01T00:00:00.000Z'), - grdf: DateTime.fromISO('0000-01-01T00:00:00.000Z'), - }, - lastConnectionDate: DateTime.fromISO('0000-01-01T00:00:00.000Z'), - haveSeenLastAnalysis: true, - sendConsumptionAlert: false, - waterDailyConsumptionLimit: 0, - sendAnalysisNotification: true, - isProfileEcogestureCompleted: false, - mailToken: '', - monthlyAnalysisDate: DateTime.fromISO('0000-01-01T00:00:00.000Z'), - isProfileTypeCompleted: false, - onboarding: { - isWelcomeSeen: true, - }, - haveSeenEcogestureModal: false, - activateHalfHourDate: DateTime.fromISO('0000-01-01T00:00:00.000Z'), - customPopupDate: DateTime.fromISO('0000-01-01T00:00:00.000Z'), -} - -export const mockInitialProfileTypeState: ProfileType = { - housingType: HousingType.INDIVIDUAL_HOUSE, - constructionYear: ConstructionYear.BETWEEN_1975_AND_1989, - area: '100', - occupantsNumber: 4, - outsideFacingWalls: OutsideFacingWalls.TWO, - floor: Floor.NOT_APPLICABLE, - heating: IndividualOrCollective.INDIVIDUAL, - coldWater: IndividualOrCollective.INDIVIDUAL, - hotWater: IndividualOrCollective.INDIVIDUAL, - individualInsulationWork: [ - IndividualInsulationWork.WINDOW_REPLACEMENT, - IndividualInsulationWork.WALL_INSULATION, - ], - hasInstalledVentilation: ThreeChoicesAnswer.UNKNOWN, - hasReplacedHeater: ThreeChoicesAnswer.UNKNOWN, - hotWaterEquipment: HotWaterEquipment.SOLAR, - warmingFluid: WarmingType.ELECTRICITY, - hotWaterFluid: HotWaterFluid.ELECTRICITY, - cookingFluid: FluidType.ELECTRICITY, - updateDate: DateTime.fromISO('0000-01-01T00:00:00.000Z'), - equipments: [], -} - -export const mockInitialChartState: ChartState = { - selectedDate: DateTime.local().endOf('minute').setZone('utc', { - keepLocalTime: true, - }), - currentTimeStep: TimeStep.WEEK, - currentIndex: 0, - currentDatachart: { actualData: [], comparisonData: null }, - currentDatachartIndex: 0, - loading: true, - showCompare: false, - showOfflineData: false, -} - -export const mockInitialModalState: ModalState = { - customPopupModal: { - popupEnabled: false, - title: '', - description: '', - endDate: '', - }, - isConnectionModalOpen: false, - isFeedbacksOpen: false, - partnersIssueModal: { - enedis: false, - egl: false, - grdf: false, - }, -} - -export const mockInitialChallengeState: ChallengeState = { - userChallengeList: [], - currentChallenge: null, - currentDataload: [], -} - -export const mockAnalysisState: AnalysisState = { - period: 'month', - analysisMonth: DateTime.local(2023, 1, 1).startOf('day'), -} - -export const mockInitialEcolyoState: EcolyoState = { - analysis: mockAnalysisState, - challenge: mockInitialChallengeState, - chart: mockInitialChartState, - global: mockInitialGlobalState, - modal: mockInitialModalState, - profile: mockInitialProfileState, - profileType: mockInitialProfileTypeState, - profileEcogesture: mockProfileEcogesture, -} - -const middlewares = [thunkMiddleware.withExtraArgument({ mockClient })] -const mockStore = configureStore< - { - ecolyo: { - analysis: AnalysisState - challenge: ChallengeState - chart: ChartState - global: GlobalState - modal: ModalState - profile: Profile - profileEcogesture: ProfileEcogesture - profileType: ProfileType - } - cozy: unknown - }, - AppActionsTypes ->(middlewares) -const mockedStore = mockStore({ - ecolyo: mockInitialEcolyoState, - cozy: {}, -}) - -/** - * Create a mocked Ecolyo store with the default mockInitialEcolyoState - */ -export const createMockEcolyoStore = ( - initialState: EcolyoState = mockInitialEcolyoState -) => { - return mockStore({ - ecolyo: initialState, - cozy: {}, - }) -} - -export default mockedStore diff --git a/tests/__mocks__/store/analysis.state.mock.ts b/tests/__mocks__/store/analysis.state.mock.ts new file mode 100644 index 0000000000000000000000000000000000000000..9c19d8e1d63b54d0f29d04a84ce2e3004a88ea47 --- /dev/null +++ b/tests/__mocks__/store/analysis.state.mock.ts @@ -0,0 +1,7 @@ +import { DateTime } from 'luxon' +import { AnalysisState } from 'models' + +export const mockAnalysisState: AnalysisState = { + period: 'month', + analysisMonth: DateTime.local(2023, 1, 1).startOf('day'), +} diff --git a/tests/__mocks__/store/challenge.state.mock.ts b/tests/__mocks__/store/challenge.state.mock.ts new file mode 100644 index 0000000000000000000000000000000000000000..653def14adee6803effc53798034329b45b92a50 --- /dev/null +++ b/tests/__mocks__/store/challenge.state.mock.ts @@ -0,0 +1,7 @@ +import { ChallengeState } from 'models' + +export const mockChallengeState: ChallengeState = { + userChallengeList: [], + currentChallenge: null, + currentDataload: [], +} diff --git a/tests/__mocks__/store/chart.state.mock.ts b/tests/__mocks__/store/chart.state.mock.ts new file mode 100644 index 0000000000000000000000000000000000000000..df355ad572383eb3e1d9e627a43808852e5fe909 --- /dev/null +++ b/tests/__mocks__/store/chart.state.mock.ts @@ -0,0 +1,16 @@ +import { TimeStep } from 'enums' +import { DateTime } from 'luxon' +import { ChartState } from 'models' + +export const mockChartState: ChartState = { + selectedDate: DateTime.local().endOf('minute').setZone('utc', { + keepLocalTime: true, + }), + currentTimeStep: TimeStep.WEEK, + currentIndex: 0, + currentDatachart: { actualData: [], comparisonData: null }, + currentDatachartIndex: 0, + loading: true, + showCompare: false, + showOfflineData: false, +} diff --git a/tests/__mocks__/globalStateData.mock.ts b/tests/__mocks__/store/global.state.mock.ts similarity index 82% rename from tests/__mocks__/globalStateData.mock.ts rename to tests/__mocks__/store/global.state.mock.ts index a657805557f7463252c28dbe1f125f54bba01992..ddc0d309f58fab3acdb351c8541b654f6df8e8a6 100644 --- a/tests/__mocks__/globalStateData.mock.ts +++ b/tests/__mocks__/store/global.state.mock.ts @@ -1,115 +1,109 @@ -/* eslint-disable camelcase */ -import { FluidState, FluidType } from 'enum/fluid.enum' -import { FluidSlugType } from 'enum/fluidSlug.enum' -import { ScreenType } from 'enum/screen.enum' -import { GlobalState } from 'models' - -export const globalStateData: GlobalState = { - screenType: ScreenType.MOBILE, - releaseNotes: { - show: false, - notes: [], - }, - challengeExplorationNotification: false, - challengeActionNotification: false, - challengeDuelNotification: false, - analysisNotification: false, - termsStatus: { - accepted: false, - versionType: 'major', - }, - partnersInfo: { - egl_failure: false, - enedis_failure: false, - grdf_failure: false, - notification_activated: false, - }, - fluidStatus: [ - { - fluidType: FluidType.ELECTRICITY, - status: FluidState.KONNECTOR_NOT_FOUND, - maintenance: false, - firstDataDate: null, - lastDataDate: null, - connection: { - shouldLaunchKonnector: false, - isUpdating: false, - konnector: null, - account: null, - trigger: null, - triggerState: null, - konnectorConfig: { - name: '', - oauth: false, - slug: FluidSlugType.ELECTRICITY, - siteLink: '', - activation: '', - }, - }, - }, - { - fluidType: FluidType.WATER, - status: FluidState.KONNECTOR_NOT_FOUND, - maintenance: false, - firstDataDate: null, - lastDataDate: null, - connection: { - shouldLaunchKonnector: false, - isUpdating: false, - konnector: null, - account: null, - trigger: null, - triggerState: null, - konnectorConfig: { - name: '', - oauth: false, - slug: FluidSlugType.WATER, - siteLink: '', - activation: '', - }, - }, - }, - { - fluidType: FluidType.GAS, - status: FluidState.KONNECTOR_NOT_FOUND, - maintenance: false, - firstDataDate: null, - lastDataDate: null, - connection: { - shouldLaunchKonnector: false, - isUpdating: false, - konnector: null, - account: null, - trigger: null, - triggerState: null, - konnectorConfig: { - name: '', - oauth: false, - slug: FluidSlugType.GAS, - siteLink: '', - activation: '', - }, - }, - }, - ], - fluidTypes: [], - shouldRefreshConsent: false, - sgeConnect: { - currentStep: 0, - firstName: '', - lastName: '', - pdl: null, - address: '', - zipCode: null, - city: '', - dataConsent: false, - pdlConfirm: false, - shouldLaunchAccount: false, - }, - customPopupModal: { - title: '', - description: '', - popupEnabled: false, - endDate: '', - }, -} +/* eslint-disable camelcase */ +import { FluidSlugType, FluidState, FluidType, ScreenType, Usage } from 'enums' +import { GlobalState } from 'models' + +export const mockGlobalState: GlobalState = { + screenType: ScreenType.MOBILE, + challengeExplorationNotification: false, + challengeActionNotification: false, + challengeDuelNotification: false, + analysisNotification: false, + lastEpglLogin: '', + termsStatus: { + accepted: true, + versionType: 'init', + }, + partnersInfo: { + egl_failure: false, + enedis_failure: false, + grdf_failure: false, + notification_activated: false, + }, + releaseNotes: { + show: false, + notes: [{ description: '', title: '' }], + }, + fluidStatus: [ + { + fluidType: FluidType.ELECTRICITY, + status: FluidState.KONNECTOR_NOT_FOUND, + maintenance: false, + firstDataDate: null, + lastDataDate: null, + connection: { + shouldLaunchKonnector: false, + isUpdating: false, + konnector: null, + account: null, + trigger: null, + triggerState: null, + konnectorConfig: { + name: '', + oauth: false, + slug: FluidSlugType.ELECTRICITY, + siteLink: '', + activation: '', + }, + }, + }, + { + fluidType: FluidType.WATER, + status: FluidState.KONNECTOR_NOT_FOUND, + maintenance: false, + firstDataDate: null, + lastDataDate: null, + connection: { + shouldLaunchKonnector: false, + isUpdating: false, + konnector: null, + account: null, + trigger: null, + triggerState: null, + konnectorConfig: { + name: '', + oauth: false, + slug: FluidSlugType.WATER, + siteLink: '', + activation: '', + }, + }, + }, + { + fluidType: FluidType.GAS, + status: FluidState.KONNECTOR_NOT_FOUND, + maintenance: false, + firstDataDate: null, + lastDataDate: null, + connection: { + shouldLaunchKonnector: false, + isUpdating: false, + konnector: null, + account: null, + trigger: null, + triggerState: null, + konnectorConfig: { + name: '', + oauth: false, + slug: FluidSlugType.GAS, + siteLink: '', + activation: '', + }, + }, + }, + ], + fluidTypes: [], + shouldRefreshConsent: false, + sgeConnect: { + address: '', + city: '', + currentStep: 0, + dataConsent: false, + firstName: '', + lastName: '', + pdl: null, + pdlConfirm: false, + zipCode: null, + shouldLaunchAccount: false, + }, + ecogestureFilter: Usage.ALL, +} diff --git a/tests/__mocks__/store/index.ts b/tests/__mocks__/store/index.ts new file mode 100644 index 0000000000000000000000000000000000000000..1a4f61367a19175eb437a64c63a5ec6907442f45 --- /dev/null +++ b/tests/__mocks__/store/index.ts @@ -0,0 +1,8 @@ +export * from './analysis.state.mock' +export * from './challenge.state.mock' +export * from './chart.state.mock' +export * from './global.state.mock' +export * from './modal.state.mock' +export * from './profile.state.mock' +export * from './profileType.state.mock' +export * from './store.mock' diff --git a/tests/__mocks__/store/modal.state.mock.ts b/tests/__mocks__/store/modal.state.mock.ts new file mode 100644 index 0000000000000000000000000000000000000000..1407ce08c87d174bd15e3b7d1d6d10f98e47c82a --- /dev/null +++ b/tests/__mocks__/store/modal.state.mock.ts @@ -0,0 +1,17 @@ +import { ModalState } from 'models' + +export const mockModalState: ModalState = { + customPopupModal: { + popupEnabled: false, + title: '', + description: '', + endDate: '', + }, + isConnectionModalOpen: false, + isFeedbacksOpen: false, + partnersIssueModal: { + enedis: false, + egl: false, + grdf: false, + }, +} diff --git a/src/store/profile/profile.reducer.ts b/tests/__mocks__/store/profile.state.mock.ts similarity index 50% rename from src/store/profile/profile.reducer.ts rename to tests/__mocks__/store/profile.state.mock.ts index 182a0c0bffe4486dd2ad397dcb4412e1e7f28d87..cb896d683d30eddebab0b43fabca149d4a03d035 100644 --- a/src/store/profile/profile.reducer.ts +++ b/tests/__mocks__/store/profile.state.mock.ts @@ -1,52 +1,46 @@ -import { DateTime } from 'luxon' -import { Profile } from 'models' -import { Reducer } from 'redux' -import { - ProfileActionTypes, - UPDATE_PROFILE, -} from 'store/profile/profile.actions' - -const initialState: Profile = { - id: '', - ecogestureHash: '', - challengeHash: '', - duelHash: '', - quizHash: '', - explorationHash: '', - isFirstConnection: false, - partnersIssueSeenDate: { - enedis: DateTime.fromISO('0000-01-01T00:00:00.000Z'), - egl: DateTime.fromISO('0000-01-01T00:00:00.000Z'), - grdf: DateTime.fromISO('0000-01-01T00:00:00.000Z'), - }, - lastConnectionDate: DateTime.fromISO('0000-01-01T00:00:00.000Z'), - customPopupDate: DateTime.fromISO('0000-01-01T00:00:00.000Z'), - haveSeenLastAnalysis: true, - sendAnalysisNotification: true, - sendConsumptionAlert: false, - waterDailyConsumptionLimit: 0, - mailToken: '', - monthlyAnalysisDate: DateTime.fromISO('0000-01-01T00:00:00.000Z'), - isProfileTypeCompleted: false, - isProfileEcogestureCompleted: false, - onboarding: { - isWelcomeSeen: true, - }, - haveSeenEcogestureModal: false, - activateHalfHourDate: DateTime.fromISO('0000-01-01T00:00:00.000Z'), -} - -export const profileReducer: Reducer<Profile, ProfileActionTypes> = ( - state = initialState, - action -) => { - switch (action.type) { - case UPDATE_PROFILE: - return { - ...state, - ...action.payload, - } - default: - return state - } -} +import { DateTime } from 'luxon' +import { Profile } from 'models' + +export const mockProfileState: Profile = { + id: '', + ecogestureHash: '', + challengeHash: '', + duelHash: '', + quizHash: '', + explorationHash: '', + isFirstConnection: false, + partnersIssueSeenDate: { + enedis: DateTime.fromISO('0000-01-01T00:00:00.000Z', { + zone: 'utc', + }), + egl: DateTime.fromISO('0000-01-01T00:00:00.000Z', { + zone: 'utc', + }), + grdf: DateTime.fromISO('0000-01-01T00:00:00.000Z', { + zone: 'utc', + }), + }, + lastConnectionDate: DateTime.fromISO('0000-01-01T00:00:00.000Z', { + zone: 'utc', + }), + haveSeenLastAnalysis: true, + sendConsumptionAlert: false, + waterDailyConsumptionLimit: 0, + sendAnalysisNotification: true, + isProfileEcogestureCompleted: false, + mailToken: '', + monthlyAnalysisDate: DateTime.fromISO('0000-01-01T00:00:00.000Z', { + zone: 'utc', + }), + isProfileTypeCompleted: false, + onboarding: { + isWelcomeSeen: true, + }, + haveSeenEcogestureModal: false, + activateHalfHourDate: DateTime.fromISO('0000-01-01T00:00:00.000Z', { + zone: 'utc', + }), + customPopupDate: DateTime.fromISO('0000-01-01T00:00:00.000Z', { + zone: 'utc', + }), +} diff --git a/tests/__mocks__/store/profileType.state.mock.ts b/tests/__mocks__/store/profileType.state.mock.ts new file mode 100644 index 0000000000000000000000000000000000000000..e3a947570cdb873bdabea7926812cba4bbe211d8 --- /dev/null +++ b/tests/__mocks__/store/profileType.state.mock.ts @@ -0,0 +1,39 @@ +import { + ConstructionYear, + Floor, + FluidType, + HotWaterEquipment, + HotWaterFluid, + HousingType, + IndividualInsulationWork, + IndividualOrCollective, + OutsideFacingWalls, + ThreeChoicesAnswer, + WarmingType, +} from 'enums' +import { DateTime } from 'luxon' +import { ProfileType } from 'models' + +export const mockProfileTypeState: ProfileType = { + housingType: HousingType.INDIVIDUAL_HOUSE, + constructionYear: ConstructionYear.BETWEEN_1975_AND_1989, + area: '100', + occupantsNumber: 4, + outsideFacingWalls: OutsideFacingWalls.TWO, + floor: Floor.NOT_APPLICABLE, + heating: IndividualOrCollective.INDIVIDUAL, + coldWater: IndividualOrCollective.INDIVIDUAL, + hotWater: IndividualOrCollective.INDIVIDUAL, + individualInsulationWork: [ + IndividualInsulationWork.WINDOW_REPLACEMENT, + IndividualInsulationWork.WALL_INSULATION, + ], + hasInstalledVentilation: ThreeChoicesAnswer.UNKNOWN, + hasReplacedHeater: ThreeChoicesAnswer.UNKNOWN, + hotWaterEquipment: HotWaterEquipment.SOLAR, + warmingFluid: WarmingType.ELECTRICITY, + hotWaterFluid: HotWaterFluid.ELECTRICITY, + cookingFluid: FluidType.ELECTRICITY, + updateDate: DateTime.fromISO('0000-01-01T00:00:00.000Z'), + equipments: [], +} diff --git a/tests/__mocks__/store/store.mock.ts b/tests/__mocks__/store/store.mock.ts new file mode 100644 index 0000000000000000000000000000000000000000..cc4be7aa4f975f89994702509d0c7fa4095769d7 --- /dev/null +++ b/tests/__mocks__/store/store.mock.ts @@ -0,0 +1,43 @@ +import { AnyAction } from '@reduxjs/toolkit' +import configureStore from 'redux-mock-store' +import thunkMiddleware from 'redux-thunk' +import { AppState, MockEcolyoState } from 'store/store' +import mockClient from '../client.mock' +import { mockProfileEcogesture } from '../profileEcogesture.mock' +import { mockAnalysisState } from './analysis.state.mock' +import { mockChallengeState } from './challenge.state.mock' +import { mockChartState } from './chart.state.mock' +import { mockGlobalState } from './global.state.mock' +import { mockModalState } from './modal.state.mock' +import { mockProfileState } from './profile.state.mock' +import { mockProfileTypeState } from './profileType.state.mock' + +export const mockInitialEcolyoState: AppState['ecolyo'] = { + analysis: mockAnalysisState, + challenge: mockChallengeState, + chart: mockChartState, + global: mockGlobalState, + modal: mockModalState, + profile: mockProfileState, + profileType: mockProfileTypeState, + profileEcogesture: mockProfileEcogesture, +} + +const middlewares = [thunkMiddleware.withExtraArgument({ mockClient })] +const mockStore = configureStore< + { ecolyo: Partial<MockEcolyoState>; cozy: unknown }, + AnyAction +>(middlewares) + +/** + * Create a mocked Ecolyo store with the default mockInitialEcolyoState + * @argument state - optional, a partial desired state + */ +export const createMockEcolyoStore = ( + initialState: Partial<MockEcolyoState> = mockInitialEcolyoState +) => { + return mockStore({ + ecolyo: initialState, + cozy: {}, + }) +} diff --git a/tests/__mocks__/testUtils.ts b/tests/__mocks__/testUtils.ts index 6b779ccf6faab7c684fa756df3415156264a349d..dd25be4229602ef6a971d988aa8940b1a561750e 100644 --- a/tests/__mocks__/testUtils.ts +++ b/tests/__mocks__/testUtils.ts @@ -9,3 +9,22 @@ export const waitForComponentToPaint = async <TP extends any = {}>( wrapper.update() }) } + +class NoErrorThrownError extends Error {} + +/** + * @issue Jest only considers a test to have failed if it throws an error, meaning if calls to assertion functions like expect occur in conditional code such as a catch statement, tests can end up passing but not actually test anything. + * @solution A better way to handle this situation is to introduce a wrapper to handle the catching, and otherwise return a specific "no error thrown" error if nothing is thrown by the wrapped function + * @docs https://github.com/jest-community/eslint-plugin-jest/blob/main/docs/rules/no-conditional-expect.md#disallow-calling-expect-conditionally-no-conditional-expect + */ +export const getError = async <TError>( + call: () => unknown +): Promise<TError> => { + try { + await call() + + throw new NoErrorThrownError('No error thrown') + } catch (error: unknown) { + return error as TError + } +} diff --git a/tests/__mocks__/usageEventsData.mock.ts b/tests/__mocks__/usageEventsData.mock.ts index dde061dd292225d143dd101c769ad23558cbe888..d96ad448d38f992e294302ea5f114caf3ab4d897 100644 --- a/tests/__mocks__/usageEventsData.mock.ts +++ b/tests/__mocks__/usageEventsData.mock.ts @@ -1,4 +1,4 @@ -import { UsageEventType } from 'enum/usageEvent.enum' +import { UsageEventType } from 'enums' import { DateTime } from 'luxon' import { UsageEvent, UsageEventEntity } from 'models' @@ -20,37 +20,6 @@ export const usageEventData: UsageEvent = { aggregated: false, } -export const allUsageEventEntitiesData: UsageEventEntity[] = [ - { - _id: '0001', - type: UsageEventType.CONNECTION_EVENT, - context: 'desktop', - eventDate: '2020-10-10T08:08:08.008Z', - aggregated: false, - }, - { - _id: '0002', - type: UsageEventType.NAVIGATION_EVENT, - target: 'consumption', - eventDate: '2020-10-10T08:09:08.008Z', - aggregated: false, - }, - { - _id: '0003', - type: UsageEventType.CONNECTION_EVENT, - context: 'desktop', - eventDate: '2020-10-11T08:08:08.008Z', - aggregated: false, - }, - { - _id: '0004', - type: UsageEventType.NAVIGATION_EVENT, - context: 'challenge', - eventDate: '2020-10-11T08:09:08.008Z', - aggregated: false, - }, -] - export const allUsageEventsData: UsageEvent[] = [ { _id: '0001', diff --git a/tests/__mocks__/userChallengeData.mock.ts b/tests/__mocks__/userChallengeData.mock.ts index 205338b0380ddbccaa9ab6cf3a2df8d79c26ca51..3966c3f0b4a98577899f9bcd8f46a4f85dc7f5af 100644 --- a/tests/__mocks__/userChallengeData.mock.ts +++ b/tests/__mocks__/userChallengeData.mock.ts @@ -1,10 +1,10 @@ /* eslint-disable camelcase */ -import { UserActionState } from 'enum/userAction.enum' import { + UserActionState, UserChallengeState, UserChallengeSuccess, -} from 'enum/userChallenge.enum' -import { UserExplorationType } from 'enum/userExploration.enum' + UserExplorationType, +} from 'enums' import { UserChallenge } from 'models' import { duelData, duelDefault } from './duelData.mock' import { diff --git a/tests/jestLib/setup.js b/tests/jestLib/setup.js deleted file mode 100644 index 46f8d0d2523f3d6a709e375759f70074a9fd8d85..0000000000000000000000000000000000000000 --- a/tests/jestLib/setup.js +++ /dev/null @@ -1,37 +0,0 @@ -require('babel-polyfill') -require('jest-canvas-mock') - -import { configure } from 'enzyme' -import Adapter from 'enzyme-adapter-react-16' - -configure({ adapter: new Adapter() }) - -// polyfill for requestAnimationFrame -/* istanbul ignore next */ -global.requestAnimationFrame = cb => { - setTimeout(cb, 0) -} - -global.cozy = { - bar: { - BarLeft: ({ children }) => children, - BarRight: ({ children }) => children, - BarCenter: ({ children }) => children, - setTheme: () => null, - }, -} - -Object.defineProperty(window, 'getComputedStyle', { - value: () => ({ - getPropertyValue: prop => { - switch (prop) { - case '--blue': - return '#58ffff' - case '--greyDark': - return '#7b7b7b' - default: - return '#FFFFFF' - } - }, - }), -}) diff --git a/tests/jestLib/setupTests.ts b/tests/jestLib/setupTests.ts new file mode 100644 index 0000000000000000000000000000000000000000..a71f0dfd2226a5d58074a29a9f37c71fc0e1e1d6 --- /dev/null +++ b/tests/jestLib/setupTests.ts @@ -0,0 +1,24 @@ +require('babel-polyfill') +require('jest-canvas-mock') + +import { configure } from 'enzyme' +import Adapter from 'enzyme-adapter-react-16' +import mockClient from 'tests/__mocks__/client.mock' + +configure({ adapter: new Adapter() }) + +jest.mock('cozy-ui/transpiled/react/I18n', () => ({ + useI18n: jest.fn(() => ({ + t: (key: string) => key, + })), +})) + +jest.mock('cozy-client', () => ({ + ...jest.requireActual('cozy-client'), + useClient: () => mockClient, +})) + +jest.mock('react-router-dom', () => ({ + ...jest.requireActual('react-router-dom'), + useNavigate: () => jest.fn(), +})) diff --git a/tsconfig.json b/tsconfig.json index 02ef5015853296073d1fee881418debfea51057d..918223a92ae41951a898f2a5c62cdab1262f56d2 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,7 +1,7 @@ { "compilerOptions": { "target": "esnext", - "baseUrl": "src", + "baseUrl": ".", "allowJs": true, "skipLibCheck": true, "esModuleInterop": true, @@ -16,7 +16,8 @@ "jsx": "react", "lib": ["esnext", "dom"], "paths": { - "*": ["*", "../node_modules/*", "types/*"] + "tests/*": ["tests/*"], + "*": ["src/*", "../node_modules/*", "types/*"] } }, "include": ["src/**/*", "tests/**/*"] diff --git a/yarn.lock b/yarn.lock index b0430e79d6dbbbffe6f455426eb17d2a79f1c9f5..2616ea33eb3c11f95fa1c0d1bab60128a005969b 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2,6 +2,11 @@ # yarn lockfile v1 +"@aashutoshrathi/word-wrap@^1.2.3": + version "1.2.6" + resolved "https://registry.yarnpkg.com/@aashutoshrathi/word-wrap/-/word-wrap-1.2.6.tgz#bd9154aec9983f77b3a034ecaa015c2e4201f6cf" + integrity sha512-1Yjs2SvM8TflER/OD3cOjhWWOZb58A2t7wpE2S9XfBYTiIl+XFhQG2bjy4Pu1I+EAlCNUzRDYDdFwFYUKvXcIA== + "@alloc/types@^1.2.1": version "1.3.0" resolved "https://registry.yarnpkg.com/@alloc/types/-/types-1.3.0.tgz#904245b8d3260a4b7d8a801c12501968f64fac08" @@ -1473,6 +1478,13 @@ dependencies: regenerator-runtime "^0.13.4" +"@babel/runtime@^7.12.1": + version "7.22.6" + resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.22.6.tgz#57d64b9ae3cff1d67eb067ae117dac087f5bd438" + integrity sha512-wDb5pWm4WDdF6LFUde3Jl8WzPA+3ZbxYqkC6xAXuD3irdEHN1k0NfTRrJD8ZD378SJ61miMLCqIOXYhd8x+AJQ== + dependencies: + regenerator-runtime "^0.13.11" + "@babel/runtime@^7.16.3": version "7.18.9" resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.18.9.tgz#b4fcfce55db3d2e5e080d2490f608a3b9f407f4a" @@ -1662,6 +1674,15 @@ resolved "https://registry.yarnpkg.com/@emotion/weak-memoize/-/weak-memoize-0.2.5.tgz#8eed982e2ee6f7f4e44c253e12962980791efd46" integrity sha512-6U71C2Wp7r5XtFtQzYrW5iKFT67OixrSxjI4MptCHzdSVlgabczzqLe0ZSgnub/5Kp4hSbpDB1tMytZY9pwxxA== +"@es-joy/jsdoccomment@~0.40.1": + version "0.40.1" + resolved "https://registry.yarnpkg.com/@es-joy/jsdoccomment/-/jsdoccomment-0.40.1.tgz#13acd77fb372ed1c83b7355edd865a3b370c9ec4" + integrity sha512-YORCdZSusAlBrFpZ77pJjc5r1bQs5caPWtAu+WWmiSo+8XaUzseapVrfAtiRFbQWnrBxxLLEwF6f6ZG/UgCQCg== + dependencies: + comment-parser "1.4.0" + esquery "^1.5.0" + jsdoc-type-pratt-parser "~4.0.0" + "@eslint-community/eslint-utils@^4.2.0": version "4.3.0" resolved "https://registry.yarnpkg.com/@eslint-community/eslint-utils/-/eslint-utils-4.3.0.tgz#a556790523a351b4e47e9d385f47265eaaf9780a" @@ -1674,6 +1695,11 @@ resolved "https://registry.yarnpkg.com/@eslint-community/regexpp/-/regexpp-4.4.0.tgz#3e61c564fcd6b921cb789838631c5ee44df09403" integrity sha512-A9983Q0LnDGdLPjxyXQ00sbV+K+O+ko2Dr+CZigbHWtX9pNfxlaBkMR8X1CztI73zuEyEBXTVjx7CE+/VSwDiQ== +"@eslint-community/regexpp@^4.6.1": + version "4.8.0" + resolved "https://registry.yarnpkg.com/@eslint-community/regexpp/-/regexpp-4.8.0.tgz#11195513186f68d42fbf449f9a7136b2c0c92005" + integrity sha512-JylOEEzDiOryeUnFbQz+oViCXS0KsvR1mvHkoMiu5+UiBvy+RYX7tzlIIIEstF/gVa2tj9AQXk3dgnxv6KxhFg== + "@eslint/eslintrc@^0.4.3": version "0.4.3" resolved "https://registry.yarnpkg.com/@eslint/eslintrc/-/eslintrc-0.4.3.tgz#9e42981ef035beb3dd49add17acb96e8ff6f394c" @@ -1704,14 +1730,14 @@ minimatch "^3.1.2" strip-json-comments "^3.1.1" -"@eslint/eslintrc@^2.0.1": - version "2.0.1" - resolved "https://registry.yarnpkg.com/@eslint/eslintrc/-/eslintrc-2.0.1.tgz#7888fe7ec8f21bc26d646dbd2c11cd776e21192d" - integrity sha512-eFRmABvW2E5Ho6f5fHLqgena46rOj7r7OKHYfLElqcBfGFHHpjBhivyi5+jOEQuSpdc/1phIZJlbC2te+tZNIw== +"@eslint/eslintrc@^2.1.2": + version "2.1.2" + resolved "https://registry.yarnpkg.com/@eslint/eslintrc/-/eslintrc-2.1.2.tgz#c6936b4b328c64496692f76944e755738be62396" + integrity sha512-+wvgpDsrB1YqAMdEUCcnTlpfVBH7Vqn6A/NT3D8WVXFIaKMlErPIZT3oCIAVCOtarRpMtelZLqJeU3t7WY6X6g== dependencies: ajv "^6.12.4" debug "^4.3.2" - espree "^9.5.0" + espree "^9.6.0" globals "^13.19.0" ignore "^5.2.0" import-fresh "^3.2.1" @@ -1719,20 +1745,20 @@ minimatch "^3.1.2" strip-json-comments "^3.1.1" -"@eslint/js@8.36.0": - version "8.36.0" - resolved "https://registry.yarnpkg.com/@eslint/js/-/js-8.36.0.tgz#9837f768c03a1e4a30bd304a64fb8844f0e72efe" - integrity sha512-lxJ9R5ygVm8ZWgYdUweoq5ownDlJ4upvoWmO4eLxBYHdMo+vZ/Rx0EN6MbKWDJOSUGrqJy2Gt+Dyv/VKml0fjg== +"@eslint/js@8.49.0": + version "8.49.0" + resolved "https://registry.yarnpkg.com/@eslint/js/-/js-8.49.0.tgz#86f79756004a97fa4df866835093f1df3d03c333" + integrity sha512-1S8uAY/MTJqVx0SC4epBq+N2yhuwtNwLbJYNZyhL2pO1ZVKn5HFXav5T41Ryzy9K9V7ZId2JB2oy/W4aCd9/2w== "@gar/promisify@^1.0.1": version "1.1.3" resolved "https://registry.yarnpkg.com/@gar/promisify/-/promisify-1.1.3.tgz#555193ab2e3bb3b6adc3d551c9c030d9e860daf6" integrity sha512-k2Ty1JcVojjJFwrg/ThKi2ujJ7XNLYaFGNB/bWT9wGR+oSMJHMa5w+CUq6p/pVrKeNNgA7pCqEcjSnHVoqJQFw== -"@humanwhocodes/config-array@^0.11.8": - version "0.11.8" - resolved "https://registry.yarnpkg.com/@humanwhocodes/config-array/-/config-array-0.11.8.tgz#03595ac2075a4dc0f191cc2131de14fbd7d410b9" - integrity sha512-UybHIJzJnR5Qc/MsD9Kr+RpO2h+/P1GhOwdiLPXK5TWk5sgTdu88bTD9UP+CKbPPh5Rni1u0GjAdYQLemG8g+g== +"@humanwhocodes/config-array@^0.11.11": + version "0.11.11" + resolved "https://registry.yarnpkg.com/@humanwhocodes/config-array/-/config-array-0.11.11.tgz#88a04c570dbbc7dd943e4712429c3df09bc32844" + integrity sha512-N2brEuAadi0CcdeMXUkhbZB84eskAc8MEX1By6qEchoVywSgXPIjou4rYsl0V3Hj0ZnuGycGCjdNgockbzeWNA== dependencies: "@humanwhocodes/object-schema" "^1.2.1" debug "^4.1.1" @@ -2338,15 +2364,15 @@ "@react-spring/core" "9.0.0-rc.3" "@react-spring/shared" "9.0.0-rc.3" -"@reduxjs/toolkit@^1.9.3": - version "1.9.3" - resolved "https://registry.yarnpkg.com/@reduxjs/toolkit/-/toolkit-1.9.3.tgz#27e1a33072b5a312e4f7fa19247fec160bbb2df9" - integrity sha512-GU2TNBQVofL09VGmuSioNPQIu6Ml0YLf4EJhgj0AvBadRlCGzUWet8372LjvO4fqKZF2vH1xU0htAa7BrK9pZg== +"@reduxjs/toolkit@^1.9.5": + version "1.9.5" + resolved "https://registry.yarnpkg.com/@reduxjs/toolkit/-/toolkit-1.9.5.tgz#d3987849c24189ca483baa7aa59386c8e52077c4" + integrity sha512-Rt97jHmfTeaxL4swLRNPD/zV4OxTes4la07Xc4hetpUW/vc75t5m1ANyxG6ymnEQ2FsLQsoMlYB2vV1sO3m8tQ== dependencies: - immer "^9.0.16" - redux "^4.2.0" + immer "^9.0.21" + redux "^4.2.1" redux-thunk "^2.4.2" - reselect "^4.1.7" + reselect "^4.1.8" "@remix-run/router@1.2.1": version "1.2.1" @@ -2545,13 +2571,6 @@ dependencies: "@types/node" "*" -"@types/classnames@^2.2.10": - version "2.3.1" - resolved "https://registry.yarnpkg.com/@types/classnames/-/classnames-2.3.1.tgz#3c2467aa0f1a93f1f021e3b9bcf938bd5dfdc0dd" - integrity sha512-zeOWb0JGBoVmlQoznvqXbE0tEC/HONsnoUNH19Hc96NFsTAwTXbTqb8FMYkru1F/iqp7a18Ws3nWJvtA1sHD1A== - dependencies: - classnames "*" - "@types/d3-array@^2": version "2.12.3" resolved "https://registry.yarnpkg.com/@types/d3-array/-/d3-array-2.12.3.tgz#8d16d51fb04ad5a5a8ebe14eb8263a579f1efdd1" @@ -2762,6 +2781,21 @@ "@types/d3-transition" "^2" "@types/d3-zoom" "^2" +"@types/enzyme-adapter-react-16@^1.0.6": + version "1.0.6" + resolved "https://registry.yarnpkg.com/@types/enzyme-adapter-react-16/-/enzyme-adapter-react-16-1.0.6.tgz#8aca7ae2fd6c7137d869b6616e696d21bb8b0cec" + integrity sha512-VonDkZ15jzqDWL8mPFIQnnLtjwebuL9YnDkqeCDYnB4IVgwUm0mwKkqhrxLL6mb05xm7qqa3IE95m8CZE9imCg== + dependencies: + "@types/enzyme" "*" + +"@types/enzyme@*": + version "3.10.13" + resolved "https://registry.yarnpkg.com/@types/enzyme/-/enzyme-3.10.13.tgz#332c0ed59b01f7b1c398c532a1c21a5feefabeb1" + integrity sha512-FCtoUhmFsud0Yx9fmZk179GkdZ4U9B0GFte64/Md+W/agx0L5SxsIIbhLBOxIb9y2UfBA4WQnaG1Od/UsUQs9Q== + dependencies: + "@types/cheerio" "*" + "@types/react" "^16" + "@types/enzyme@^3.10.8": version "3.10.12" resolved "https://registry.yarnpkg.com/@types/enzyme/-/enzyme-3.10.12.tgz#ac4494801b38188935580642f772ad18f72c132f" @@ -2820,7 +2854,7 @@ dependencies: history "*" -"@types/hoist-non-react-statics@^3.3.0": +"@types/hoist-non-react-statics@^3.3.0", "@types/hoist-non-react-statics@^3.3.1": version "3.3.1" resolved "https://registry.yarnpkg.com/@types/hoist-non-react-statics/-/hoist-non-react-statics-3.3.1.tgz#1124aafe5118cb591977aeb1ceaaed1070eb039f" integrity sha512-iMIqiko6ooLrTh1joXodJK5X9xeEALT1kM5G3ZLhD3hszxBdIEd5C75U834D9mLcINgD4OyZf5uQXjkuYydWvA== @@ -2953,7 +2987,7 @@ dependencies: "@types/react" "*" -"@types/react-redux@^7.1.11", "@types/react-redux@^7.1.20": +"@types/react-redux@^7.1.20": version "7.1.24" resolved "https://registry.yarnpkg.com/@types/react-redux/-/react-redux-7.1.24.tgz#6caaff1603aba17b27d20f8ad073e4c077e975c0" integrity sha512-7FkurKcS1k0FHZEtdbbgN8Oc6b+stGSfZYjQGicofJ0j4U0qIn/jaSvnP2pLwZKiai3/17xqqxkkrxTgN8UNbQ== @@ -3032,6 +3066,11 @@ resolved "https://registry.yarnpkg.com/@types/stack-utils/-/stack-utils-2.0.1.tgz#20f18294f797f2209b5f65c8e3b5c8e8261d127c" integrity sha512-Hl219/BT5fLAaz6NDkSuhzasy49dwQS/DSdu4MdggFB8zcXv7vflBI3xp7FEmkmdDkBUI2bPUNeMttp2knYdxw== +"@types/use-sync-external-store@^0.0.3": + version "0.0.3" + resolved "https://registry.yarnpkg.com/@types/use-sync-external-store/-/use-sync-external-store-0.0.3.tgz#b6725d5f4af24ace33b36fafd295136e75509f43" + integrity sha512-EwmlvuaxPNej9+T4v5AuBPJa2x2UOJVdjCtDHgcDqitUeOtjnJKJ+apYjVcAoBEMjKW1VVFGZLUb5+qqa09XFA== + "@types/yargs-parser@*": version "21.0.0" resolved "https://registry.yarnpkg.com/@types/yargs-parser/-/yargs-parser-21.0.0.tgz#0c60e537fa790f5f9472ed2776c2b71ec117351b" @@ -3103,6 +3142,14 @@ "@typescript-eslint/types" "5.56.0" "@typescript-eslint/visitor-keys" "5.56.0" +"@typescript-eslint/scope-manager@5.62.0": + version "5.62.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-5.62.0.tgz#d9457ccc6a0b8d6b37d0eb252a23022478c5460c" + integrity sha512-VXuvVvZeQCQb5Zgf4HAxc04q5j+WrNAtNh9OwCsCgpKqESMTu3tF/jhZ3xG6T4NZwWl65Bg8KuS2uEvhSfLl0w== + dependencies: + "@typescript-eslint/types" "5.62.0" + "@typescript-eslint/visitor-keys" "5.62.0" + "@typescript-eslint/type-utils@5.56.0": version "5.56.0" resolved "https://registry.yarnpkg.com/@typescript-eslint/type-utils/-/type-utils-5.56.0.tgz#e6f004a072f09c42e263dc50e98c70b41a509685" @@ -3123,6 +3170,11 @@ resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-5.56.0.tgz#b03f0bfd6fa2afff4e67c5795930aff398cbd834" integrity sha512-JyAzbTJcIyhuUhogmiu+t79AkdnqgPUEsxMTMc/dCZczGMJQh1MK2wgrju++yMN6AWroVAy2jxyPcPr3SWCq5w== +"@typescript-eslint/types@5.62.0": + version "5.62.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-5.62.0.tgz#258607e60effa309f067608931c3df6fed41fd2f" + integrity sha512-87NVngcbVXUahrRTqIK27gD2t5Cu1yuCXxbLcFtCzZGlfyVWWh8mLHkoxzjsB6DDNnvdL+fW8MiwPEJyGJQDgQ== + "@typescript-eslint/typescript-estree@5.30.5": version "5.30.5" resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-5.30.5.tgz#c520e4eba20551c4ec76af8d344a42eb6c9767bb" @@ -3149,6 +3201,19 @@ semver "^7.3.7" tsutils "^3.21.0" +"@typescript-eslint/typescript-estree@5.62.0": + version "5.62.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-5.62.0.tgz#7d17794b77fabcac615d6a48fb143330d962eb9b" + integrity sha512-CmcQ6uY7b9y694lKdRB8FEel7JbU/40iSAPomu++SjLMntB+2Leay2LO6i8VnJk58MtE9/nQSFIH6jpyRWyYzA== + dependencies: + "@typescript-eslint/types" "5.62.0" + "@typescript-eslint/visitor-keys" "5.62.0" + debug "^4.3.4" + globby "^11.1.0" + is-glob "^4.0.3" + semver "^7.3.7" + tsutils "^3.21.0" + "@typescript-eslint/utils@5.56.0": version "5.56.0" resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-5.56.0.tgz#db64705409b9a15546053fb4deb2888b37df1f41" @@ -3163,6 +3228,20 @@ eslint-scope "^5.1.1" semver "^7.3.7" +"@typescript-eslint/utils@^5.10.0": + version "5.62.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-5.62.0.tgz#141e809c71636e4a75daa39faed2fb5f4b10df86" + integrity sha512-n8oxjeb5aIbPFEtmQxQYOLI0i9n5ySBEY/ZEHHZqKQSFnxio1rv6dthascc9dLuwrL0RC5mPCxB7vnAVGAYWAQ== + dependencies: + "@eslint-community/eslint-utils" "^4.2.0" + "@types/json-schema" "^7.0.9" + "@types/semver" "^7.3.12" + "@typescript-eslint/scope-manager" "5.62.0" + "@typescript-eslint/types" "5.62.0" + "@typescript-eslint/typescript-estree" "5.62.0" + eslint-scope "^5.1.1" + semver "^7.3.7" + "@typescript-eslint/visitor-keys@5.30.5": version "5.30.5" resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-5.30.5.tgz#d4bb969202019d5d5d849a0aaedc7370cc044b14" @@ -3179,6 +3258,14 @@ "@typescript-eslint/types" "5.56.0" eslint-visitor-keys "^3.3.0" +"@typescript-eslint/visitor-keys@5.62.0": + version "5.62.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-5.62.0.tgz#2174011917ce582875954ffe2f6912d5931e353e" + integrity sha512-07ny+LHRzQXepkGg6w0mFY41fVUNBrL2Roj/++7V1txKugfjm/Ci/qSND03r2RhlJhJYMcTn9AhhSSqQp0Ysyw== + dependencies: + "@typescript-eslint/types" "5.62.0" + eslint-visitor-keys "^3.3.0" + "@webassemblyjs/ast@1.9.0": version "1.9.0" resolved "https://registry.yarnpkg.com/@webassemblyjs/ast/-/ast-1.9.0.tgz#bd850604b4042459a5a41cd7d338cbed695ed964" @@ -3393,10 +3480,10 @@ acorn@^8.2.4, acorn@^8.7.1: resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.7.1.tgz#0197122c843d1bf6d0a5e83220a788f278f63c30" integrity sha512-Xx54uLJQZ19lKygFXOWsscKUbsBZW0CPykPhVQdhIeIwrbPmJzqeASDInc8nKBnp/JT6igTs82qPXz069H8I/A== -acorn@^8.8.0: - version "8.8.2" - resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.8.2.tgz#1b2f25db02af965399b9776b0c2c391276d37c4a" - integrity sha512-xjIYgE8HBrkpd/sJqOGNspf8uHG+NOHGOw6a/Urj8taM2EXfdNAH2oFcPeIFfsv3+kz/mJrS5VuMqbNLjCa2vw== +acorn@^8.9.0: + version "8.10.0" + resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.10.0.tgz#8be5b3907a67221a81ab23c7889c4c5526b62ec5" + integrity sha512-F0SAmZ8iUtS//m8DmCTA0jlh6TDKkHQyK6xc6V4KDTyZKA9dnvX9/3sRTVQrWm79glUAZbnmmNcdYwUIHWVybw== add-stream@^1.0.0: version "1.0.0" @@ -3587,6 +3674,11 @@ aproba@^1.1.1: resolved "https://registry.yarnpkg.com/aproba/-/aproba-1.2.0.tgz#6802e6264efd18c790a1b0d517f0f2627bf2c94a" integrity sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw== +are-docs-informative@^0.0.2: + version "0.0.2" + resolved "https://registry.yarnpkg.com/are-docs-informative/-/are-docs-informative-0.0.2.tgz#387f0e93f5d45280373d387a59d34c96db321963" + integrity sha512-ixiS0nLNNG5jNQzgZJNoUpBKdo9yTYZMGJ+QgT2jmjR7G7+QHRCc4v6LQ3NgE7EBJq+o0ams3waJwkrlBom8Ig== + argparse@^1.0.10, argparse@^1.0.7: version "1.0.10" resolved "https://registry.yarnpkg.com/argparse/-/argparse-1.0.10.tgz#bcd6791ea5ae09725e17e5ad988134cd40b3d911" @@ -4474,6 +4566,11 @@ buffer@^5.5.0: base64-js "^1.3.1" ieee754 "^1.1.13" +builtin-modules@^3.3.0: + version "3.3.0" + resolved "https://registry.yarnpkg.com/builtin-modules/-/builtin-modules-3.3.0.tgz#cae62812b89801e9656336e46223e030386be7b6" + integrity sha512-zhaCDicdLuWN5UbN5IMnFqNMhNfo919sH85y2/ea+5Yg9TsTkeZxpL+JLbp6cgYFS4sRLp3YV4S6yDuqVWHYOw== + builtin-status-codes@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/builtin-status-codes/-/builtin-status-codes-3.0.0.tgz#85982878e21b98e1c66425e03d0174788f569ee8" @@ -4661,9 +4758,9 @@ camelcase@^6.0.0: integrity sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA== caniuse-lite@^1.0.30001039, caniuse-lite@^1.0.30001359: - version "1.0.30001361" - resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001361.tgz#ba2adb2527566fb96f3ac7c67698ae7fc495a28d" - integrity sha512-ybhCrjNtkFji1/Wto6SSJKkWk6kZgVQsDq5QI83SafsF6FXv2JB4df9eEdH6g8sdGgqTXrFLjAxqBGgYoU3azQ== + version "1.0.30001538" + resolved "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001538.tgz" + integrity sha512-HWJnhnID+0YMtGlzcp3T9drmBJUVDchPJ08tpUGFLs9CYlwWPH2uLgpHn8fND5pCgXVtnGS3H4QR9XLMHVNkHw== capture-exit@^2.0.0: version "2.0.0" @@ -4914,11 +5011,16 @@ classificator@^0.3.3: dependencies: decimal.js "^10.0.0" -classnames@*, classnames@^2.2.5, classnames@^2.2.6: +classnames@^2.2.5, classnames@^2.2.6: version "2.3.1" resolved "https://registry.yarnpkg.com/classnames/-/classnames-2.3.1.tgz#dfcfa3891e306ec1dad105d0e88f4417b8535e8e" integrity sha512-OlQdbZ7gLfGarSqxesMesDa5uz7KFbID8Kpq/SxIoNGDqY8lSYs0D+hhtBXhcdB3rcbXArFr7vlHheLk1voeNA== +classnames@^2.3.2: + version "2.3.2" + resolved "https://registry.yarnpkg.com/classnames/-/classnames-2.3.2.tgz#351d813bf0137fcc6a76a16b88208d2560a0d924" + integrity sha512-CSbhY4cFEJRe6/GQzIk5qXZ4Jeg5pcsP7b5peFSDpffpe1cqjASH/n9UTjBwOp6XpMSTwQ8Za2K5V02ueA7Tmw== + clean-css@4.2.x, clean-css@^4.2.1: version "4.2.4" resolved "https://registry.yarnpkg.com/clean-css/-/clean-css-4.2.4.tgz#733bf46eba4e607c6891ea57c24a989356831178" @@ -5179,6 +5281,11 @@ commander@^9.3.0: resolved "https://registry.yarnpkg.com/commander/-/commander-9.3.0.tgz#f619114a5a2d2054e0d9ff1b31d5ccf89255e26b" integrity sha512-hv95iU5uXPbK83mjrJKuZyFM/LBAoCV/XhVGkS5Je6tl7sxr6A0ITMw5WoRV46/UaJ46Nllm3Xt7IaJhXTIkzw== +comment-parser@1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/comment-parser/-/comment-parser-1.4.0.tgz#0f8c560f59698193854f12884c20c0e39a26d32c" + integrity sha512-QLyTNiZ2KDOibvFPlZ6ZngVsZ/0gYnE6uTXi5aoDg8ed3AkJAz4sEje3Y8a29hQ1s6A99MZXe47fLAXQ1rTqaw== + common-tags@^1.4.0: version "1.8.2" resolved "https://registry.yarnpkg.com/common-tags/-/common-tags-1.8.2.tgz#94ebb3c076d26032745fd54face7f688ef5ac9c6" @@ -7468,6 +7575,28 @@ eslint-loader@^4.0.2: object-hash "^2.0.3" schema-utils "^2.6.5" +eslint-plugin-jest@^27.2.3: + version "27.2.3" + resolved "https://registry.yarnpkg.com/eslint-plugin-jest/-/eslint-plugin-jest-27.2.3.tgz#6f8a4bb2ca82c0c5d481d1b3be256ab001f5a3ec" + integrity sha512-sRLlSCpICzWuje66Gl9zvdF6mwD5X86I4u55hJyFBsxYOsBCmT5+kSUjf+fkFWVMMgpzNEupjW8WzUqi83hJAQ== + dependencies: + "@typescript-eslint/utils" "^5.10.0" + +eslint-plugin-jsdoc@^46.8.2: + version "46.8.2" + resolved "https://registry.yarnpkg.com/eslint-plugin-jsdoc/-/eslint-plugin-jsdoc-46.8.2.tgz#3e6b1c93e91e38fe01874d45da121b56393c54a5" + integrity sha512-5TSnD018f3tUJNne4s4gDWQflbsgOycIKEUBoCLn6XtBMgNHxQFmV8vVxUtiPxAQq8lrX85OaSG/2gnctxw9uQ== + dependencies: + "@es-joy/jsdoccomment" "~0.40.1" + are-docs-informative "^0.0.2" + comment-parser "1.4.0" + debug "^4.3.4" + escape-string-regexp "^4.0.0" + esquery "^1.5.0" + is-builtin-module "^3.2.1" + semver "^7.5.4" + spdx-expression-parse "^3.0.1" + eslint-plugin-prettier@3.1.2: version "3.1.2" resolved "https://registry.yarnpkg.com/eslint-plugin-prettier/-/eslint-plugin-prettier-3.1.2.tgz#432e5a667666ab84ce72f945c72f77d996a5c9ba" @@ -7590,6 +7719,14 @@ eslint-scope@^7.0.0, eslint-scope@^7.1.1: esrecurse "^4.3.0" estraverse "^5.2.0" +eslint-scope@^7.2.2: + version "7.2.2" + resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-7.2.2.tgz#deb4f92563390f32006894af62a22dba1c46423f" + integrity sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg== + dependencies: + esrecurse "^4.3.0" + estraverse "^5.2.0" + eslint-utils@^1.3.1: version "1.4.3" resolved "https://registry.yarnpkg.com/eslint-utils/-/eslint-utils-1.4.3.tgz#74fec7c54d0776b6f67e0251040b5806564e981f" @@ -7626,6 +7763,11 @@ eslint-visitor-keys@^3.1.0, eslint-visitor-keys@^3.3.0: resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-3.3.0.tgz#f6480fa6b1f30efe2d1968aa8ac745b862469826" integrity sha512-mQ+suqKJVyeuwGYHAdjMFqjCyfl8+Ldnxuyp3ldiMBFKkvytrXUZWaiPCEav8qDHKty44bD+qV1IP4T+w+xXRA== +eslint-visitor-keys@^3.4.1, eslint-visitor-keys@^3.4.3: + version "3.4.3" + resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz#0cd72fe8550e3c2eae156a96a4dddcd1c8ac5800" + integrity sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag== + eslint@5.16.0: version "5.16.0" resolved "https://registry.yarnpkg.com/eslint/-/eslint-5.16.0.tgz#a1e3ac1aae4a3fbd8296fcf8f7ab7314cbb6abea" @@ -7714,27 +7856,27 @@ eslint@^7.32.0: text-table "^0.2.0" v8-compile-cache "^2.0.3" -eslint@^8.36.0: - version "8.36.0" - resolved "https://registry.yarnpkg.com/eslint/-/eslint-8.36.0.tgz#1bd72202200a5492f91803b113fb8a83b11285cf" - integrity sha512-Y956lmS7vDqomxlaaQAHVmeb4tNMp2FWIvU/RnU5BD3IKMD/MJPr76xdyr68P8tV1iNMvN2mRK0yy3c+UjL+bw== +eslint@^8.49.0: + version "8.49.0" + resolved "https://registry.yarnpkg.com/eslint/-/eslint-8.49.0.tgz#09d80a89bdb4edee2efcf6964623af1054bf6d42" + integrity sha512-jw03ENfm6VJI0jA9U+8H5zfl5b+FvuU3YYvZRdZHOlU2ggJkxrlkJH4HcDrZpj6YwD8kuYqvQM8LyesoazrSOQ== dependencies: "@eslint-community/eslint-utils" "^4.2.0" - "@eslint-community/regexpp" "^4.4.0" - "@eslint/eslintrc" "^2.0.1" - "@eslint/js" "8.36.0" - "@humanwhocodes/config-array" "^0.11.8" + "@eslint-community/regexpp" "^4.6.1" + "@eslint/eslintrc" "^2.1.2" + "@eslint/js" "8.49.0" + "@humanwhocodes/config-array" "^0.11.11" "@humanwhocodes/module-importer" "^1.0.1" "@nodelib/fs.walk" "^1.2.8" - ajv "^6.10.0" + ajv "^6.12.4" chalk "^4.0.0" cross-spawn "^7.0.2" debug "^4.3.2" doctrine "^3.0.0" escape-string-regexp "^4.0.0" - eslint-scope "^7.1.1" - eslint-visitor-keys "^3.3.0" - espree "^9.5.0" + eslint-scope "^7.2.2" + eslint-visitor-keys "^3.4.3" + espree "^9.6.1" esquery "^1.4.2" esutils "^2.0.2" fast-deep-equal "^3.1.3" @@ -7742,22 +7884,19 @@ eslint@^8.36.0: find-up "^5.0.0" glob-parent "^6.0.2" globals "^13.19.0" - grapheme-splitter "^1.0.4" + graphemer "^1.4.0" ignore "^5.2.0" - import-fresh "^3.0.0" imurmurhash "^0.1.4" is-glob "^4.0.0" is-path-inside "^3.0.3" - js-sdsl "^4.1.4" js-yaml "^4.1.0" json-stable-stringify-without-jsonify "^1.0.1" levn "^0.4.1" lodash.merge "^4.6.2" minimatch "^3.1.2" natural-compare "^1.4.0" - optionator "^0.9.1" + optionator "^0.9.3" strip-ansi "^6.0.1" - strip-json-comments "^3.1.0" text-table "^0.2.0" eslint@^8.7.0: @@ -7837,14 +7976,14 @@ espree@^9.0.0, espree@^9.3.2: acorn-jsx "^5.3.2" eslint-visitor-keys "^3.3.0" -espree@^9.5.0: - version "9.5.0" - resolved "https://registry.yarnpkg.com/espree/-/espree-9.5.0.tgz#3646d4e3f58907464edba852fa047e6a27bdf113" - integrity sha512-JPbJGhKc47++oo4JkEoTe2wjy4fmMwvFpgJT9cQzmfXKp22Dr6Hf1tdCteLz1h0P3t+mGvWZ+4Uankvh8+c6zw== +espree@^9.6.0, espree@^9.6.1: + version "9.6.1" + resolved "https://registry.yarnpkg.com/espree/-/espree-9.6.1.tgz#a2a17b8e434690a5432f2f8018ce71d331a48c6f" + integrity sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ== dependencies: - acorn "^8.8.0" + acorn "^8.9.0" acorn-jsx "^5.3.2" - eslint-visitor-keys "^3.3.0" + eslint-visitor-keys "^3.4.1" esprima@^4.0.0, esprima@^4.0.1: version "4.0.1" @@ -7858,7 +7997,7 @@ esquery@^1.0.1, esquery@^1.4.0: dependencies: estraverse "^5.1.0" -esquery@^1.4.2: +esquery@^1.4.2, esquery@^1.5.0: version "1.5.0" resolved "https://registry.yarnpkg.com/esquery/-/esquery-1.5.0.tgz#6ce17738de8577694edd7361c57182ac8cb0db0b" integrity sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg== @@ -8872,6 +9011,11 @@ grapheme-splitter@^1.0.4: resolved "https://registry.yarnpkg.com/grapheme-splitter/-/grapheme-splitter-1.0.4.tgz#9cf3a665c6247479896834af35cf1dbb4400767e" integrity sha512-bzh50DW9kTPM00T8y4o8vQg89Di9oLJVLW/KaOGIXJWP/iqCN6WKYkbNOF04vFLJhwcpYUh9ydh/+5vpOqV4YQ== +graphemer@^1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/graphemer/-/graphemer-1.4.0.tgz#fb2f1d55e0e3a1849aeffc90c4fa0dd53a0e66c6" + integrity sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag== + growly@^1.3.0: version "1.3.0" resolved "https://registry.yarnpkg.com/growly/-/growly-1.3.0.tgz#f10748cbe76af964b7c96c93c6bcc28af120c081" @@ -9427,7 +9571,7 @@ immediate@3.0.6: resolved "https://registry.yarnpkg.com/immediate/-/immediate-3.0.6.tgz#9db1dbd0faf8de6fbe0f5dd5e56bb606280de69b" integrity sha512-XXOFtyqDjNDAQxVfYxuF7g9Il/IbWmmlQg2MYKOH8ExIT1qg6xc4zyS3HaEEATgs1btfzxq15ciUiY7gjSXRGQ== -immer@^9.0.16: +immer@^9.0.21: version "9.0.21" resolved "https://registry.yarnpkg.com/immer/-/immer-9.0.21.tgz#1e025ea31a40f24fb064f1fef23e931496330176" integrity sha512-bc4NBHqOqSfRW7POMkHd51LvClaeMXpm8dx0e8oE2GORbq5aRK7Bxl4FyzVLdGtLmvLKL7BTDBG5ACQm4HWjTA== @@ -9709,6 +9853,13 @@ is-buffer@^1.1.4, is-buffer@^1.1.5, is-buffer@~1.1.6: resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-1.1.6.tgz#efaa2ea9daa0d7ab2ea13a97b2b8ad51fefbe8be" integrity sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w== +is-builtin-module@^3.2.1: + version "3.2.1" + resolved "https://registry.yarnpkg.com/is-builtin-module/-/is-builtin-module-3.2.1.tgz#f03271717d8654cfcaf07ab0463faa3571581169" + integrity sha512-BSLE3HnV2syZ0FK0iMA/yUGplUeMmNz4AW5fnTunbCIqZi4vG3WjJT9FHMy5D69xmAYBHXQhJdALdpwVxV501A== + dependencies: + builtin-modules "^3.3.0" + is-callable@^1.1.3, is-callable@^1.2.7: version "1.2.7" resolved "https://registry.yarnpkg.com/is-callable/-/is-callable-1.2.7.tgz#3bc2a85ea742d9e36205dcacdd72ca1fdc51b055" @@ -10630,11 +10781,6 @@ js-levenshtein@^1.1.3: resolved "https://registry.yarnpkg.com/js-levenshtein/-/js-levenshtein-1.1.6.tgz#c6cee58eb3550372df8deb85fad5ce66ce01d59d" integrity sha512-X2BB11YZtrRqY4EnQcLX5Rh373zbK4alC1FW7D7MBhL2gtcC17cTnr6DmfHZeS0s2rTHjUTMMHfG7gO8SSdw+g== -js-sdsl@^4.1.4: - version "4.4.0" - resolved "https://registry.yarnpkg.com/js-sdsl/-/js-sdsl-4.4.0.tgz#8b437dbe642daa95760400b602378ed8ffea8430" - integrity sha512-FfVSdx6pJ41Oa+CF7RDaFmTnCaFhua+SNYQX74riGOpl96x+2jQCqEfQ2bnXu/5DPCqlRuiqyvTJM0Qjz26IVg== - "js-tokens@^3.0.0 || ^4.0.0", js-tokens@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499" @@ -10660,6 +10806,11 @@ jsbn@~0.1.0: resolved "https://registry.yarnpkg.com/jsbn/-/jsbn-0.1.1.tgz#a5e654c2e5a2deb5f201d96cefbca80c0ef2f513" integrity sha512-UVU9dibq2JcFWxQPA6KCqj5O42VOmAY3zQUfEKxU0KpTGXwNoCjkX1e13eHNvw/xPynt6pU0rZ1htjWTNTSXsg== +jsdoc-type-pratt-parser@~4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/jsdoc-type-pratt-parser/-/jsdoc-type-pratt-parser-4.0.0.tgz#136f0571a99c184d84ec84662c45c29ceff71114" + integrity sha512-YtOli5Cmzy3q4dP26GraSOeAhqecewG04hoO8DY56CH4KJ9Fvv5qKWUCCo3HZob7esJQHCv6/+bnTy72xZZaVQ== + jsdom@^16.2.1, jsdom@^16.4.0: version "16.7.0" resolved "https://registry.yarnpkg.com/jsdom/-/jsdom-16.7.0.tgz#918ae71965424b197c819f8183a754e18977b710" @@ -12782,6 +12933,18 @@ optionator@^0.9.1: type-check "^0.4.0" word-wrap "^1.2.3" +optionator@^0.9.3: + version "0.9.3" + resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.9.3.tgz#007397d44ed1872fdc6ed31360190f81814e2c64" + integrity sha512-JjCoypp+jKn1ttEFExxhetCKeJt9zhAgAve5FXHixTvFDW/5aEktX9bufBKLRRMdU7bNtpLfcGu94B3cdEJgjg== + dependencies: + "@aashutoshrathi/word-wrap" "^1.2.3" + deep-is "^0.1.3" + fast-levenshtein "^2.0.6" + levn "^0.4.1" + prelude-ls "^1.2.1" + type-check "^0.4.0" + os-browserify@^0.3.0: version "0.3.0" resolved "https://registry.yarnpkg.com/os-browserify/-/os-browserify-0.3.0.tgz#854373c7f5c2315914fc9bfc6bd8238fdda1ec27" @@ -14081,7 +14244,7 @@ react-redux@5.1.1: react-is "^16.6.0" react-lifecycles-compat "^3.0.0" -react-redux@^7.2.0, react-redux@^7.2.2: +react-redux@^7.2.0: version "7.2.8" resolved "https://registry.yarnpkg.com/react-redux/-/react-redux-7.2.8.tgz#a894068315e65de5b1b68899f9c6ee0923dd28de" integrity sha512-6+uDjhs3PSIclqoCk0kd6iX74gzrGc3W5zcAjbrFgEdIjRSQObdIwfx80unTkVUYvbQ95Y8Av3OvFHq1w5EOUw== @@ -14093,6 +14256,18 @@ react-redux@^7.2.0, react-redux@^7.2.2: prop-types "^15.7.2" react-is "^17.0.2" +react-redux@^8.1.2: + version "8.1.2" + resolved "https://registry.yarnpkg.com/react-redux/-/react-redux-8.1.2.tgz#9076bbc6b60f746659ad6d51cb05de9c5e1e9188" + integrity sha512-xJKYI189VwfsFc4CJvHqHlDrzyFTY/3vZACbE+rr/zQ34Xx1wQfB4OTOSeOSNrF6BDVe8OOdxIrAnMGXA3ggfw== + dependencies: + "@babel/runtime" "^7.12.1" + "@types/hoist-non-react-statics" "^3.3.1" + "@types/use-sync-external-store" "^0.0.3" + hoist-non-react-statics "^3.3.2" + react-is "^18.0.0" + use-sync-external-store "^1.0.0" + react-remove-scroll-bar@^2.3.3: version "2.3.3" resolved "https://registry.yarnpkg.com/react-remove-scroll-bar/-/react-remove-scroll-bar-2.3.3.tgz#e291f71b1bb30f5f67f023765b7435f4b2b2cd94" @@ -14436,7 +14611,7 @@ redux@4.1.2: dependencies: "@babel/runtime" "^7.9.2" -redux@^4.2.0: +redux@^4.2.1: version "4.2.1" resolved "https://registry.yarnpkg.com/redux/-/redux-4.2.1.tgz#c08f4306826c49b5e9dc901dee0452ea8fce6197" integrity sha512-LAUYz4lc+Do8/g7aeRa8JkyDErK6ekstQaqWQrNRW//MY1TvCEpMtpTWvlQ+FPbWCx+Xixu/6SHt5N0HR+SB4w== @@ -14680,10 +14855,10 @@ requires-port@^1.0.0: resolved "https://registry.yarnpkg.com/requires-port/-/requires-port-1.0.0.tgz#925d2601d39ac485e091cf0da5c6e694dc3dcaff" integrity sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ== -reselect@^4.1.7: - version "4.1.7" - resolved "https://registry.yarnpkg.com/reselect/-/reselect-4.1.7.tgz#56480d9ff3d3188970ee2b76527bd94a95567a42" - integrity sha512-Zu1xbUt3/OPwsXL46hvOOoQrap2azE7ZQbokq61BQfiXvhewsKDwhMeZjTX9sX0nvw1t/U5Audyn1I9P/m9z0A== +reselect@^4.1.8: + version "4.1.8" + resolved "https://registry.yarnpkg.com/reselect/-/reselect-4.1.8.tgz#3f5dc671ea168dccdeb3e141236f69f02eaec524" + integrity sha512-ab9EmR80F/zQTMNeneUr4cv+jSwPJgIlvEmVwLerwrWVbpLlBuls9XHzIeTFy4cegU2NHBp3va0LKOzU5qFEYQ== resolve-cwd@^2.0.0: version "2.0.0" @@ -15038,6 +15213,13 @@ semver@^7.1.1, semver@^7.2.1, semver@^7.3.2, semver@^7.3.4, semver@^7.3.5, semve dependencies: lru-cache "^6.0.0" +semver@^7.5.4: + version "7.5.4" + resolved "https://registry.yarnpkg.com/semver/-/semver-7.5.4.tgz#483986ec4ed38e1c6c48c34894a9182dbff68a6e" + integrity sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA== + dependencies: + lru-cache "^6.0.0" + send@0.18.0: version "0.18.0" resolved "https://registry.yarnpkg.com/send/-/send-0.18.0.tgz#670167cc654b05f5aa4a767f9113bb371bc706be" @@ -15404,7 +15586,7 @@ spdx-exceptions@^2.1.0: resolved "https://registry.yarnpkg.com/spdx-exceptions/-/spdx-exceptions-2.3.0.tgz#3f28ce1a77a00372683eade4a433183527a2163d" integrity sha512-/tTrYOC7PPI1nUAgx34hUpqXuyJG+DTHJTnIULG4rDygi4xu/tfgmq1e1cIRwRzwZgo4NLySi+ricLkZkw4i5A== -spdx-expression-parse@^3.0.0: +spdx-expression-parse@^3.0.0, spdx-expression-parse@^3.0.1: version "3.0.1" resolved "https://registry.yarnpkg.com/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz#cf70f50482eefdc98e3ce0a6833e4a53ceeba679" integrity sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q== @@ -16765,6 +16947,11 @@ use-sidecar@^1.1.2: detect-node-es "^1.1.0" tslib "^2.0.0" +use-sync-external-store@^1.0.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/use-sync-external-store/-/use-sync-external-store-1.2.0.tgz#7dbefd6ef3fe4e767a0cf5d7287aacfb5846928a" + integrity sha512-eEgnFxGQ1Ife9bzYs6VLi8/4X6CObHMw9Qr9tPY43iKwsPw8xE8+EFsf/2cFZ5S3esXgpWgtSCtLNS41F+sKPA== + use@^3.1.0: version "3.1.1" resolved "https://registry.yarnpkg.com/use/-/use-3.1.1.tgz#d50c8cac79a19fbc20f2911f56eb973f4e10070f"