diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index f5dfb2a8b8d9b60e65e24db659cab25700af728b..3c12ea75791485aad6dfeb95d44c25b577a73372 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -1,5 +1,5 @@ default: - image: ${CI_DEPENDENCY_PROXY_DIRECT_GROUP_IMAGE_PREFIX}/node:14.19.3-alpine + image: ${CI_DEPENDENCY_PROXY_DIRECT_GROUP_IMAGE_PREFIX}/node:16.19.1-alpine services: - name: ${CI_DEPENDENCY_PROXY_DIRECT_GROUP_IMAGE_PREFIX}/docker:20.10.9-dind alias: docker @@ -11,8 +11,8 @@ stages: - quality - test - build - - push-build - - deploy + - push-deploy + - update-instances - publish variables: @@ -112,64 +112,80 @@ test: - master - merge_requests -build: +build-dev: stage: build before_script: - apk add git - apk add bash script: - yarn - - yarn build + - yarn build-dev only: - dev - master - merge_requests artifacts: + expire_in: 1 day paths: - build/ -br_build_test: - stage: push-build +build-prod: + stage: build + before_script: + - apk add git + - apk add bash + script: + - yarn + - yarn build + rules: + - if: $CI_MERGE_REQUEST_TARGET_BRANCH_NAME == "master" + artifacts: + expire_in: 1 day + paths: + - build/ + +deploy-dev: + stage: push-deploy before_script: - apk add git - apk add bash script: - yarn - - ls build - git config --global user.name build-pipeline - git config --global user.email "$GIT_USER" - git config --global user.password "$GIT_PWD" - git config user.email "$GIT_USER" - git remote set-url origin https://"$GIT_USER":"$GIT_PWD"@forge.grandlyon.com/web-et-numerique/factory/llle_project/ecolyo.git - git config --global credential.helper store - - yarn deploy-test + - yarn deploy-dev only: - merge_requests - needs: - - build when: manual + needs: + - build-dev -br_build_dev: - stage: push-build +deploy-test: + stage: push-deploy before_script: - apk add git - apk add bash script: - yarn + - ls build - git config --global user.name build-pipeline - git config --global user.email "$GIT_USER" - git config --global user.password "$GIT_PWD" - git config user.email "$GIT_USER" - git remote set-url origin https://"$GIT_USER":"$GIT_PWD"@forge.grandlyon.com/web-et-numerique/factory/llle_project/ecolyo.git - git config --global credential.helper store - - yarn deploy-dev + - yarn deploy-test only: - dev needs: - - build + - build-dev -br_build: - stage: push-build +deploy: + stage: push-deploy before_script: - apk add git - apk add bash @@ -185,41 +201,40 @@ br_build: only: - master needs: - - build + - build-dev -deploy_test: - stage: deploy +update-dev: + stage: update-instances tags: - deploy-alpha script: - cd /root/ecolyo-infra-scripts/cicid_scripts - - './update_ecolyo_dev.sh' + - './update_ecolyo_dev_dev.sh' only: - merge_requests environment: name: dev url: https://ecolyo.dev.cozy.self-data.alpha.grandlyon.com/ - when: manual needs: - - br_build_test + - deploy-dev -deploy_demo: - stage: deploy +update-demo: + stage: update-instances tags: - deploy-alpha script: - cd /root/ecolyo-infra-scripts/cicid_scripts - - './update_ecolyodemo_dev.sh' + - './update_ecolyodemo_test.sh' only: - dev environment: name: ecolyodemo url: https://ecolyo.ecolyodemo.cozy.self-data.alpha.grandlyon.com/ needs: - - br_build_dev + - deploy-test -deploy_all: - stage: deploy +update-all: + stage: update-instances tags: - deploy-alpha script: @@ -228,7 +243,7 @@ deploy_all: only: - master needs: - - br_build + - deploy publish: stage: publish diff --git a/.gitlab/issue_templates/[Bug] Ecolyo.md b/.gitlab/issue_templates/[Bug] Ecolyo.md index eff6a9f7c4f51fe3150244ba2b636478fbb18ab7..9ef3f4e9379cdf5e952335625cfa5a882f6304ba 100644 --- a/.gitlab/issue_templates/[Bug] Ecolyo.md +++ b/.gitlab/issue_templates/[Bug] Ecolyo.md @@ -1,10 +1,10 @@ /title [Scope] Description -### Résumé du problème +## Résumé du problème _Donnez une description briève du problème._ -### L'environnement +## L'environnement 1. Utilisez vous l'application sur: @@ -22,16 +22,16 @@ _Donnez une description briève du problème._ - [ ] Safari - [ ] Autre -### Les étapes pour reproduire le bug +## Les étapes pour reproduire le bug _Listez les étapes qui vous permettent de reproduire ce bug, cette étape est très importante._ -### Décrivez le comportement du _bug_ ? +## Décrivez le comportement du _bug_ ? -### Quel serez le comportement _attendu_ ? +## Quel serez le comportement _attendu_ ? -### Logs et/ou screenshots +## Logs et/ou screenshots -### Possible fixes +## Possible fixes /label ~"bug" diff --git a/.gitlab/issue_templates/[QA] Ecolyo.md b/.gitlab/issue_templates/[QA] Ecolyo.md new file mode 100644 index 0000000000000000000000000000000000000000..1141136441627ab8e392ea6fa3d4b7b9eb0e22ce --- /dev/null +++ b/.gitlab/issue_templates/[QA] Ecolyo.md @@ -0,0 +1,77 @@ +/assign @hnouts +/confidential true + +[TOC] + +# Cahier de recette pour la version _x.x.x_ + +🚀 _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_ + +--- + +1. **Onboarding** + - [ ] Le chargement de l'application fonctionne correctement + - [ ] La page tutoriel est présentée + - [ ] Les CGU sont demandées + *** +2. **Comportement sans connecteur connecté** + - [ ] La page conso pousse à la connexion + - [ ] La page analyse pousse à la connexion + *** +3. **Lancement des connecteurs** + - [ ] SGE + - [ ] GRDF + - [ ] EPGL + *** +4. **Page Défis** + - [ ] L'utilisateur peut lancer le 1er défi + *** +5. **Analyse et conso** + - [ ] La profondeur de données va jusqu'à 1 an dans la conso + - [ ] 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) + *** +6. **Page Options** + - [ ] L'utilisateur est inscrit par défaut à la newsletter + - [ ] L'utilisateur n'est pas exclu des statistiques d'usage MATOMO + - [ ] La nouvelle version de l'app est indiquée dans le pied de page + - [ ] L'accès au SAU est fonctionnel + - [ ] Les mentions légales sont accessibles + - [ ] L'export de données fonctionne quand un connecteur est rattaché + *** +7. **Page Astuces** + - [ ] Chargement de la base des écogestes dans "Toutes" + - [ ] Lancement du module du choix des écogestes Ok + - [ ] Chargement du "petit profil" si le profil n'est pas renseigné + *** +8. **Icône raccourci** + - [ ] L'utilisateur peut facilement ajouter l'application en raccourci (pwa) + *** +9. **Autres** + - [ ] Les informations de navigation remonte dans le matomo recette + +--- + +### Instance historique + +💬 _ici ecolyodemo.cozy.self-data.alpha.grandlyon.com_ + +--- + +1. **Migration** + - [ ] Si une migration était nécessaire, vérifier quand c'est possible qu'elle a bien eu lieu + +--- + +## Tests des nouvelles fonctionalités + +📠_À mettre à jour selon les derniers développements_ diff --git a/.gitlab/merge_request_templates/default.md b/.gitlab/merge_request_templates/default.md index 577c107226e397f9a1d00fc48611ec246eb8fc1e..bcaceee3e9b9ab566fd20635f698fabfbbfe5318 100644 --- a/.gitlab/merge_request_templates/default.md +++ b/.gitlab/merge_request_templates/default.md @@ -1,5 +1,9 @@ -| :triangular_flag_on_post: Give your MR the same name that the desired squash commit. In doubt, check the conventional commit [doc](https://www.conventionalcommits.org/en/v1.0.0/).| +# Related to + +| :triangular_flag_on_post: Give your MR title the same name that the desired squash commit. In doubt, check the conventional commit [doc][conventional-commits]. examples | | --- | +| **feat(profile)**: add... | +| **fix(annuaire)**: remove... | ## What does this MR do and why? @@ -9,12 +13,12 @@ _Describe in detail what your merge request does and why._ _These are strongly recommended to assist reviewers and reduce the time to merge your change._ - ## How to set up and validate locally (or on alpha) _List all steps to set up and validate the changes on local environment._ ## MR acceptance checklist + _To be completed by the chosen reviewer._ <!--- @@ -24,10 +28,9 @@ More reading on checklists can be found in the "Checklist Manifesto": http://atu "It is common to misconceive how checklists function in complex lines of work. They are not comprehensive how-to guides, whether for building a skyscraper or getting a plane out of trouble. They are quick and simple tools aimed to buttress the skills of expert professionals." - Gawande, Atul. The Checklist Manifesto ---> - ### Quality [](https://sonarqube.forge.grandlyon.com/dashboard?id=ecolyo-mr) - [](https://sonarqube.forge.grandlyon.com/dashboard?id=ecolyo-mr) -- For the code that this change impacts, I believe that the **automated tests validate functionality** that is **highly important to users**. If the existing automated tests do not cover this functionality, I have **added the necessary additional tests** or I have added an issue to describe the automation testing gap and linked it to this MR. +- For the code that this change impacts, I believe that the **automated tests validate functionality** that is **highly important to users**. If the existing automated tests do not cover this functionality, I have **added the necessary additional tests** or I have added an issue to describe the automation testing gap and linked it to this MR. - I have made sure that the **sonar quality coverage is up to standards**. - I have **considered the impact** of this change on the **front-end**, **back-end**, and **database** portions of the system where appropriate and applied. - I have tested this MR in **all supported browsers** or determined that this testing is not needed. @@ -50,3 +53,6 @@ More reading on checklists can be found in the "Checklist Manifesto": http://atu ### Deployment - When featured on a self-data project release, I have made sure my **app version** in the manifest and package.json is **incremented** and any relative **changes to the permissions are clearly written and transmitted to Cozy**. + +[conventional-commits]: https://www.conventionalcommits.org/en/v1.0.0/ + diff --git a/.vscode/settings.json b/.vscode/settings.json index 1f1e7b0bf6bb476eaa432a6a0377fc9abc92a62c..7f5cf2b2b27149237b6d777af535f4a000cb4f62 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -41,8 +41,10 @@ "backoffice", "barchart", "camelcase", + "cicid", "CONSO", "cozycloud", + "d’éco", "dacc", "Datachart", "dataload", @@ -51,49 +53,84 @@ "Dataloads", "defi", "depense", + "désembouant", + "désembouer", "doctypes", "ecogesture", "Ecogesture", "ecogestures", "ecolyo", "Ecolyo", + "ecolyodemo", + "Ecoreno'v", "eglgrandlyon", "elec", + "élec", "enedis", "Enedis", "ENEDIS", "enedissgegrandlyon", "Epgl", + "esnext", "firstname", "fluidchart", "fluidchartslide", + "fluidsprices", "fluidtype", + "Folinge", "Gazpar", "Gier", "grandlyon", "grdf", "GRDF", "grdfgrandlyon", + "Hypervitesse", + "késako", "Konnected", "konnector", "konnectors", + "l'ADEME", + "L’embouage", "lastname", - "Lugdunum", "legalnotice", + "llle", + "Lugdunum", "luxon", "matomo", "Matomo", + "maxpower", "MEGAUNIT", + "Métroooooo", "monthlyanalysis", + "mousseur", + "mousseurs", "multifluid", "MULTIFLUID", "mutlifluid", + "numerique", + "oeufs", + "picto", "Picto", + "PIV'EAU", + "profileecogesture", + "PROFILEECOGESTURE", "profiletype", "PROFILETYPE", + "pseudonymisées", "Reinit", + "SHARAPOWATT", "splashscreen", + "swipeable", + "Swipeable", + "Téléo", "testid", - "UNSTARTED" - ] + "Tétris", + "TIMESTEP", + "timestep", + "UNSTARTED", + "usageevent", + "Usain", + "userchallenge" + ], + "typescript.tsdk": "node_modules/typescript/lib" } diff --git a/CHANGELOG.md b/CHANGELOG.md index fb7b6acd06e5b2c2d6e07290a748facf7ef6cbdc..09e335af263c34c226cd45f61c5f02d8fe20c670 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,38 @@ 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.3.0](https://forge.grandlyon.com/web-et-numerique/factory/llle_project/ecolyo/compare/v2.2.2...v2.3.0) (2023-04-06) + + +### Features + +* add node engine 16 ([cd674d8](https://forge.grandlyon.com/web-et-numerique/factory/llle_project/ecolyo/commit/cd674d89ff90128f9de794996ac189b256e6e3db)) +* better description for SHARAPOWATT challenge ([ca4e539](https://forge.grandlyon.com/web-et-numerique/factory/llle_project/ecolyo/commit/ca4e53992838e835c1083659fa26d633a9b97c45)) +* **grdf:** improve handling of grdf consent form issues ([487c1e0](https://forge.grandlyon.com/web-et-numerique/factory/llle_project/ecolyo/commit/487c1e07c34e391fc61c44a789397c21b719a87e)) +* **newsletter:** add SAU link ([4aa7134](https://forge.grandlyon.com/web-et-numerique/factory/llle_project/ecolyo/commit/4aa71340843c6c1e1f97e16d47ae51c0199f74c3)) +* **options:** add accessibility link ([84e7509](https://forge.grandlyon.com/web-et-numerique/factory/llle_project/ecolyo/commit/84e75099f0b246a4b5af2ded619f785b87809dfe)) +* **profile:** select fioul or other in profile selection ([df67f0e](https://forge.grandlyon.com/web-et-numerique/factory/llle_project/ecolyo/commit/df67f0e6f5339d1d94df47c03ded443d63c8e301)) +* update konnector success modal ([cc407fe](https://forge.grandlyon.com/web-et-numerique/factory/llle_project/ecolyo/commit/cc407feaac86e1562fc7c5cb784e6ec23bd8be50)) +* update legal notice ([0e4fe22](https://forge.grandlyon.com/web-et-numerique/factory/llle_project/ecolyo/commit/0e4fe2273224decfa4270bce04caec3131200fe4)) + + +### Bug Fixes + +* **accessibility:** open in a new tab ([07bfec1](https://forge.grandlyon.com/web-et-numerique/factory/llle_project/ecolyo/commit/07bfec1ab287c69906771be4d7d666c5f9166d0b)) +* **accessibility:** remove duplicate tag ([085988f](https://forge.grandlyon.com/web-et-numerique/factory/llle_project/ecolyo/commit/085988f964b8221f0a144f3fe2edba16ac35b99a)) +* **analysis:** crash page with gaz only ([62a43d4](https://forge.grandlyon.com/web-et-numerique/factory/llle_project/ecolyo/commit/62a43d4d5e69f30f9a0e3ba11f9938572f798b11)) +* **analysis:** duplicate section ([a4ae740](https://forge.grandlyon.com/web-et-numerique/factory/llle_project/ecolyo/commit/a4ae740a3c7e460531b3e566016af97e313d759d)) +* defaults welcome modal to seen ([1f5d3bf](https://forge.grandlyon.com/web-et-numerique/factory/llle_project/ecolyo/commit/1f5d3bfa944756ac0de358879636ed95ec5c32f6)) +* **deps:** update dependency cozy-client to v35 ([3d3dc69](https://forge.grandlyon.com/web-et-numerique/factory/llle_project/ecolyo/commit/3d3dc6924498efb9312db0213227512f006acbe4)) +* **deps:** update dependency cozy-ui to v81 ([7573ade](https://forge.grandlyon.com/web-et-numerique/factory/llle_project/ecolyo/commit/7573ade54a844c7ac7860b706ff3cc7f287cd8c3)) +* **ecogesture:** typo ([2c7aa11](https://forge.grandlyon.com/web-et-numerique/factory/llle_project/ecolyo/commit/2c7aa111f728e82c223fa61c9425bf524a1d9d69)) +* **emails:** darkmode on gmail ios ([32b0126](https://forge.grandlyon.com/web-et-numerique/factory/llle_project/ecolyo/commit/32b01260ee48b345f9a48990755611bc4393c685)) +* **fluidButton:** change showError icon triggers ([04d1dcd](https://forge.grandlyon.com/web-et-numerique/factory/llle_project/ecolyo/commit/04d1dcd5991cf09524bfdfea7305d6a8cbe9d686)) +* latest prices in estimation modal ([5c2d42b](https://forge.grandlyon.com/web-et-numerique/factory/llle_project/ecolyo/commit/5c2d42bb867d2f880749260deaea65d2a0d8db26)) +* **partnersInfo:** agent call optimization ([d719b70](https://forge.grandlyon.com/web-et-numerique/factory/llle_project/ecolyo/commit/d719b70dc7de184e624fb69be68ea78592c0c2c8)) +* remove duplicate titles in options ([f2a60be](https://forge.grandlyon.com/web-et-numerique/factory/llle_project/ecolyo/commit/f2a60befdf90a8c6aa33f31bfe1e1aeec6c602ae)) +* **router:** redirect to termsView when terms are not accepted ([7c7a09c](https://forge.grandlyon.com/web-et-numerique/factory/llle_project/ecolyo/commit/7c7a09cc89ebdd0648f268135010b039c2c62e0d)) + ### [2.2.2](https://forge.grandlyon.com/web-et-numerique/factory/llle_project/ecolyo/compare/v2.2.1...v2.2.2) (2023-02-09) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index a3ac1dc63445e76c34c4ceeef16e91f65bb77154..a774a0e2fd4122c4695e8be3bcc5a3befb52866c 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,6 +1,6 @@ -# How to contribute to LyonLivingLabEnergy? +# How to contribute to Ecolyo ? -Thank you for your interest in contributing to this Cozy application! There are many ways to contribute, and we appreciate all of them. +Thank you for your interest in contributing to this application! There are many ways to contribute, and we appreciate all of them. ## Security Issues @@ -18,7 +18,7 @@ Opening an issue is as easy as following [this link][issues] and filling out the - What did you try, step by step? - What did you expect? - What did happen instead? -- What is the version of the LyonLivingLabEnergy app? +- What is the version of the app? ## Pull Requests @@ -40,9 +40,9 @@ Pull requests are the primary mechanism we use to change Cozy. GitHub itself has Fork the project on GitHub and [check out your copy locally][forking]. ``` -$ git clone https://forge.grandlyon.com/web-et-numerique/factory/llle_project/ecolyo.git -$ cd ecolyo -$ git remote add fork git://github.com/yourusername/ecolyo.git +git clone https://forge.grandlyon.com/web-et-numerique/factory/llle_project/ecolyo.git +cd ecolyo +git remote add fork git://github.com/yourusername/ecolyo.git ``` #### Step 2: Branch @@ -50,7 +50,7 @@ $ git remote add fork git://github.com/yourusername/ecolyo.git Create a branch and start hacking: ``` -$ git checkout -b my-branch origin/master +git checkout -b my-branch origin/master ``` #### Step 3: Code @@ -62,8 +62,7 @@ Well, we think you know how to do that. Just be sure to follow the coding guidel Don't forget to add tests and be sure they are green: ``` -$ cd ecolyo -$ npm run test +yarn test ``` #### Step 5: Commit @@ -77,40 +76,36 @@ Please follow the [Conventional Commits Specification][conventional-commits] to Use `git rebase` (_not_ `git merge`) to sync your work from time to time. ``` -$ git fetch origin -$ git rebase origin/master my-branch +git fetch origin +git rebase origin/master my-branch ``` #### Step 7: Push ``` -$ git push -u fork my-branch +git push -u fork my-branch ``` -Go to https://github.com/yourusername/ecolyo and select your branch. Click the 'Pull Request' button and fill out the form. +Go to <https://github.com/yourusername/ecolyo> and select your branch. Click the 'Pull Request' button and fill out the form. Alternatively, you can use [hub] to open the pull request from your terminal: ``` -$ git pull-request -b master -m "My PR message" -o +git pull-request -b master -m "My PR message" -o ``` Pull requests are usually reviewed within a few days. If there are comments to address, apply your changes in a separate commit and push that to your branch. Post a comment in the pull request afterwards; GitHub doesn't send out notifications when you add commits. -## Writing documentation - -Documentation improvements are very welcome. We try to keep a good documentation in the `/docs` folder. But, you know, we are developers, we can forget to document important stuff that look obvious to us. And documentation can always be improved. - ## Translations -The LyonLivingLabEnergy is translated on a platform called [Transifex][tx]. [This tutorial][tx-start] can help you to learn how to make your first steps here. If you have any question, don't hesitate to ask us! +The Ecolyo is translated on a platform called [Transifex][tx]. [This tutorial][tx-start] can help you to learn how to make your first steps here. If you have any question, don't hesitate to ask us! ## Community You can help us by making our community even more vibrant. For example, you can write a blog post, take some videos, answer the questions on [the forum][forum], organize new meetups, and speak about what you like in Cozy! [conventional-commits]: https://conventionalcommits.org -[issues]: https://forge.grandlyon.com/web-et-numerique/factory/llle_project/ecolyo/issues/new +[issues]: https://support.grandlyon.com/ecolyo/ [pr]: https://help.github.com/categories/collaborating-with-issues-and-pull-requests/ [forking]: http://blog.campoy.cat/2014/03/github-and-go-forking-pull-requests-and.html [stdjs]: http://standardjs.com/ diff --git a/README.md b/README.md index 801cb647fb94e972a4af07903b6fbf010ae78946..d7c001cc9d082083d57eb945fe5471638618d406 100644 --- a/README.md +++ b/README.md @@ -2,27 +2,32 @@ ## What's Ecolyo? -Ecolyo is a mobile-first app allowing citizen to visualise easily their energy consumption (electricity, gas, water ...). The app allow simple and more advanced data visualisation -but give also some tips on how to reduce energy consumption. +Ecolyo is a mobile-first app allowing citizens to visualise easily their energy consumption (electricity, gas, water ...). The app allows data visualisation but give also some tips on how to reduce energy consumption. -## Hack +## How does it works ? -_:pushpin: Note:_ we recommend to use [Yarn] instead of NPM for package management. Don't hesitate to [install][yarn-install] and use it for your Cozy projects, it's now our main node packages tool for Cozy official apps. +Ecolyo uses "konnectors" for fetching data. More on : -### Install +- [enedis konnector](https://forge.grandlyon.com/web-et-numerique/factory/llle_project/enedis-sge-konnector) +- [grdf konnector](https://forge.grandlyon.com/web-et-numerique/factory/llle_project/grdf-konnector) +- [egl konnector](https://forge.grandlyon.com/web-et-numerique/factory/llle_project/egl-konnector) -Hacking the Cozy Ecolyo app requires you to [setup a dev environment][setup]. +## Development + +For a more complete look at our project, check our [Self Data Docs](https://doc.self-data.alpha.grandlyon.com/) + +_:pushpin: Note:_ we recommend to use [Yarn] instead of NPM for package management. + +Developing the Cozy Ecolyo app requires you to be familiar with [cozy's documentation](https://docs.cozy.io/en/). You can then clone the app repository and install dependencies: ```sh -$ git clone https://forge.grandlyon.com/web-et-numerique/factory/llle_project/ecolyo.git -$ cd ecolyo -$ yarn install +git clone https://forge.grandlyon.com/web-et-numerique/factory/llle_project/ecolyo.git +cd ecolyo +yarn ``` -:pushpin: If you use a node environment wrapper like [nvm] or [ndenv], don't forget to set your local node version before doing a `yarn install`. - Cozy's apps use a standard set of _npm scripts_ to run common tasks, like watch, lint, test, build… ### Run it inside a default Cozy using Docker @@ -30,18 +35,17 @@ Cozy's apps use a standard set of _npm scripts_ to run common tasks, like watch, First of all get cozy dev image : ```sh -$ docker pull cozy/cozy-app-dev +docker pull cozy/cozy-app-dev ``` Then you can run your application inside a Cozy thanks to the [cozy-stack docker image][cozy-stack-docker]: ```sh # in a terminal, run your app in watch mode with a docker running Cozy -$ cd ecolyo $ yarn start ``` -After the build and the stack launched, your app is now available at http://ecolyo.cozy.tools:8080. +After the build and the stack launched, your app is now available at <http://ecolyo.cozy.tools:8080>. ### Run it inside custom Docker @@ -52,13 +56,20 @@ For the project we have created our own docker container. For more information o Tests are run by [jest] under the hood. You can easily run the tests suite with: ```sh -$ cd ecolyo -$ yarn test +yarn test ``` :pushpin: Don't forget to update / create new tests when you contribute to code to keep the app the consistent. -## Models +### Open a Pull-Request + +If you want to work on Ecolyo and submit code modifications, feel free to open pull-requests! See the [contributing guide][contribute] for more information about how to properly open pull-requests. + +### Commits + +You must follow these rules to write your commit messages : [Conventional Commits Specification][conventional-commits] + +### Data storage The Cozy datastore stores documents, which can be seen as JSON objects. A `doctype` is simply a declaration of the fields in a given JSON object, to store similar objects in an homogeneous fashion. @@ -69,27 +80,19 @@ Whenever your app needs to use a given `doctype`, you should: - Check if this is a standard `doctype` defined in Cozy itself. If this is the case, you should add a model declaration in your app containing at least the fields listed in the [main fields list for this `doctype`][doctypes]. Note that you can extend the Cozy-provided `doctype` with your own customs fields. This is typically what is done in [Konnectors] for the [Bill `doctype`][bill-doctype]. - If no standards `doctypes` fit your needs, you should define your own `doctype` in your app. In this case, you do not have to put any field you want in your model, but you should crosscheck other cozy apps to try to homogeneize the names of your fields, so that your `doctype` data could be reused by other apps. This is typically the case for the [Konnector `doctype`][konnector-doctype] in [Konnectors]. -### Open a Pull-Request - -If you want to work on Ecolyo and submit code modifications, feel free to open pull-requests! See the [contributing guide][contribute] for more information about how to properly open pull-requests. - -### Commits - -You must follow these rules to write your commit messages : [Conventional Commits Specification][conventional-commits] - ## Community -### What's Cozy? - -<div align="center"> - <a href="https://cozy.io"> - <img src="https://cdn.rawgit.com/cozy/cozy-site/master/src/images/cozy-logo-name-horizontal-blue.svg" alt="cozy" height="48" /> - </a> - </div> - </br> +### What's Cozy?  [Cozy] is a platform that brings all your web services in the same private space. With it, your webapps and your devices can share data easily, providing you with a new experience. You can install Cozy on your own hardware where no one's tracking you. +You can reach the Cozy Community by: + +- Chatting with us on IRC [#cozycloud on Freenode][freenode] +- Posting on our [Forum][forum] +- Posting issues on the [Github repos][github] +- Say Hi! on [Twitter][twitter] + ### Localization Localization and translations are handled by [Transifex][tx], which is used by all Cozy's apps. @@ -100,29 +103,15 @@ As a _developer_, you must [configure the transifex client][tx-client], and clai ### Maintainer -The lead maintainer for Ecolyo is [hsubtil](https://forge.grandlyon.com/ext.sopra.husubtil), send him/her a :beers: to say hello! - -### Get in touch - -You can reach the Cozy Community by: - -- Chatting with us on IRC [#cozycloud on Freenode][freenode] -- Posting on our [Forum][forum] -- Posting issues on the [Github repos][github] -- Say Hi! on [Twitter][twitter] +Ecolyo is maintained by the [factory team](https://forge.grandlyon.com/groups/web-et-numerique/factory/-/group_members) feel free to get in touch ! ## License Ecolyo is developed by "La métropole de Lyon" and distributed under the [AGPL v3 license][agpl-3.0]. [conventional-commits]: https://conventionalcommits.org -[standard-version]: https://github.com/conventional-changelog/standard-version [cozy]: https://cozy.io 'Cozy Cloud' -[setup]: https://dev.cozy.io/#set-up-the-development-environment 'Cozy dev docs: Set up the Development Environment' [yarn]: https://yarnpkg.com/ -[yarn-install]: https://yarnpkg.com/en/docs/install -[cozy-ui]: https://github.com/cozy/cozy-ui -[cozy-client-js]: https://github.com/cozy/cozy-client-js/ [cozy-stack-docker]: https://github.com/cozy/cozy-stack/blob/master/docs/client-app-dev.md#with-docker [doctypes]: https://cozy.github.io/cozy-doctypes/ [bill-doctype]: https://github.com/cozy/cozy-konnector-libs/blob/master/models/bill.js @@ -138,6 +127,4 @@ Ecolyo is developed by "La métropole de Lyon" and distributed under the [AGPL v [forum]: https://forum.cozy.io/ [github]: https://github.com/cozy/ [twitter]: https://twitter.com/cozycloud -[nvm]: https://github.com/creationix/nvm -[ndenv]: https://github.com/riywo/ndenv [jest]: https://facebook.github.io/jest/ diff --git a/app.config.alpha.js b/app.config.alpha.js index 23d023ab4c1ce3a1af1050e2868035172c3b4b22..596d9d432bb053d5e567ac249ca156f9806b0dc2 100644 --- a/app.config.alpha.js +++ b/app.config.alpha.js @@ -13,7 +13,7 @@ const { target, addAnalyzer } = require('cozy-scripts/config/webpack.vars') const configs = [ require('cozy-scripts/config/webpack.config.base'), require('cozy-scripts/config/webpack.config.chunks'), - //require('cozy-scripts/config/webpack.config.react'), + // require('cozy-scripts/config/webpack.config.react'), require('./app.config.react'), // Override the react config require('cozy-scripts/config/webpack.config.cozy-ui'), require('cozy-scripts/config/webpack.config.cozy-ui.react'), @@ -31,6 +31,6 @@ const configs = [ configs.push(require('./app.config.environment.alpha')) -//module.exports = merge.apply(null, configs) +// module.exports = merge.apply(null, configs) // eslint-disable-next-line prefer-spread module.exports = [merge.apply(null, configs)] // cozy builder expects an array diff --git a/app.config.js b/app.config.js index 5bd0f5e6b525699766a85fbd403169d3b0dcc9f7..358e507e32ffad4257461581dc8d52d130121f36 100644 --- a/app.config.js +++ b/app.config.js @@ -37,6 +37,6 @@ if (environment === 'production') { configs.push(require('./app.config.environment.dev')) } -//module.exports = merge.apply(null, configs) +// module.exports = merge.apply(null, configs) // eslint-disable-next-line prefer-spread module.exports = [merge.apply(null, configs)] // cozy builder expects an array diff --git a/docker/local.ini b/docker/local.ini index c9b3888799b787df0a38db8c8316adfde3070076..8509de64e958a0cdf53f8b5ff6fcc985a6dc080d 100644 --- a/docker/local.ini +++ b/docker/local.ini @@ -44,6 +44,8 @@ ;config_whitelist = [{httpd,config_whitelist}, {log,level}, {etc,etc}] [chttpd_auth] +; Increased timeout session (28800 = 8 hours in seconds) +timeout = 28800 ; If you set this to true, you should also uncomment the WWW-Authenticate line ; above. If you don't configure a WWW-Authenticate header, CouchDB will send ; Basic realm="server" in order to prevent you getting logged out. @@ -93,3 +95,5 @@ ; changing this. [admins] admin = password + + diff --git a/docs/code_review.md b/docs/code_review.md deleted file mode 100644 index 458b858ac4750b1dd07179042eec454e11c5de3e..0000000000000000000000000000000000000000 --- a/docs/code_review.md +++ /dev/null @@ -1,244 +0,0 @@ -Code Review -=========== - -Note : les points redondants entre différents fichiers ne sont pas forcément ré-expliqués. - -## App.jsx - -Redirection redondante dans la configuration du routeur : - -```jsx -<Redirect from="/" to="/home" /> -<Redirect from="*" to="/home" /> -``` - -## CardsContainer.tsx - -### Usage non recommandé de `any` : - -```tsx - const [elecCardProps, setElecCardProps] = useState<any>({ - consumptionValue: null, - weeklyCompareValue: null, - }) -``` - -Il vaut mieux définir un type commun dans `fluidService.ts` par exemple : - -```tsx -// fluidService.ts -export type ProcessedData = { - consumptionValue: number; - weeklyCompareValue: number; - euclideanComparator: string; -} - -// Card.tsx -export interface CardProps extends ProcessedData { - type: FluidType - t: any -} - -// CardsContainer.tsx -const [elecCardProps, setElecCardProps] = useState<ProcessedData|null>(null) - -// Dans le render : -{elecCardProps && <Card - type={FluidType.ELECTRICITY} - {...elecCardProps} -/>} -``` - -### Instanciation des services - -Il vaut mieux instancier les services dans les effets où on les utilise, pour éviter d'en instancier un de nouveau à chaque render, alors que l'effet l'utilisant n'est exécuté qu'une seule fois, au premier render, via le tableau de dépendances vide `[]` : - -```tsx -useEffect(() => { - const fluidService = new FluidService(client) - // ... -}, []) -``` - -### `async/await` dans un effet - -Un effet `async` n'est pas évident, car pendant qu'on attend un retour, il se peut que le composant soit re-render entre-temps, voire détruit. - -Du coup on aurait une `Promise` résolue, et les `set...CardProps` appelés alors que l'élément n'existe plus, généreront une erreur. - -Pour éviter cela il faut rajouter un flag mis à jour lors du unsubscribe de l'effet : - -```tsx -useEffect(() => { - const fluidService = new FluidService(client) - let subscribed = true - - async function getData() { - const elecData = await fluidService.getElectricityLastTwoWeeks() - const gasData = await fluidService.getGasLastTwoWeeks() - const waterData = await fluidService.getWaterLastTwoWeeks() - - if (subscribed) { - setElecCardProps(fluidService.processElectricityData(elecData.data)) - setGasCardProps(fluidService.processGasData(gasData.data)) - setWaterCardProps(fluidService.processWaterData(waterData.data)) - setIsLoading(false) - } - } - - getData() - - // Fonction unsubscribe, appelée avant le prochain render ou avant la destruction. - return () => { - subscribed = false - } -}, []) -``` - -### Multiples `await` - -Dernière chose pour optimiser les appels : quand on chaine des await, ils sont exécutés en séquence. - -Pour les appeler en parallèle, on peut utiliser `Promise.all()` couplé à de la deconstruction. - -Avant : - -```tsx -const elecData = await fluidService.getElectricityLastTwoWeeks() -const gasData = await fluidService.getGasLastTwoWeeks() -const waterData = await fluidService.getWaterLastTwoWeeks() -``` - -Après : - -```tsx -const [elecData, gasData, waterData] = await Promise.all([ - fluidService.getElectricityLastTwoWeeks(), - fluidService.getGasLastTwoWeeks(), - fluidService.getWaterLastTwoWeeks(), -]) -``` - -## KonnectorViewerList.tsx - -### Déclaration des fonctions utilisées par un effect - -De la même façon que les services doivent être instanciés dans l'effect, il vaut mieux déclarer les fonctions utilisées par un effect dans celui-ci, pour éviter de définir une nouvelle référence à chaque render. C'est le cas ici des fonctions `setAllKonnectors` et `setAllTriggers` : - -*Noter l'utilisation d'un flag subscribed comme expliqué précédemment.* - -```tsx - useEffect(() => { - let subscribed = true - - const setAllKonnectors = async () => { - const kss = new KonnectorStatusService(client) - const allKonnectors = await kss.getAllKonnectors() - - if (subscribed) { - setKonnectors(allKonnectors) - } - } - - const setAllTriggers = async () => { - const kss = new KonnectorStatusService(client) - const allTriggers = await kss.getAllTriggers() - - if (subscribed) { - setTriggers(allTriggers) - } - } - - setAllKonnectors() - setAllTriggers() - - return () => { - subscribed = false - } - }, []) -``` - -De même, la fonction `fetchKonnectorFromTrigger` pourrait être déplacée en dehors composant pour éviter de créer une nouvelle référence à chaque render. - -### Valeur utilisée pour la `key` lors d'un `.map()`` - -Idéalement, la prop `key` doit avoir une valeur associée à l'item courant, plutôt que son index dans le tableau. En effet le tableau pourrait changer, et un index pourrait pointer vers un autre item que celui du render précédent. - -La conséquence serait que le même élément serait utilisé pour render le nouvel item, sans qu'il soit détruit, générant potentiellement des effets de bords non souhaités (certains effect pourraient ne pas être exécutés par exemple). - -Pour éviter ça, on peut utiliser en `key` une propriété unique de l'item s'il y en a une : - -```tsx -<KonnectorViewer - key={item.id} - konnectorConfig={item} - trigger={getLastTrigger(item)} -/> -``` - -## KonnectorConfigForm.tsx - -### Ref - -Le hook `useRef` peut être utilisé pour stocker n'importe quelle valeur, pour s'en servir pour un node HTML, on peut le déclarer comme suit : - -Avant : - -```tsx -const content: React.MutableRefObject<null> = useRef<null>(null) -``` - -Après : - -```tsx -const content = useRef<HTMLDivElement>(null) -``` - -### Callbacks - -Dans le formulaire, on peut directement passer au `onSubmit` la callback comme la signature est identique : - -Avant : - -```tsx -onSubmit={(e: React.FormEvent<HTMLFormElement>) => handleSubmit(e)} -``` - -Après : - -```tsx -onSubmit={handleSubmit} -``` - -De plus, il est préférable quand on fourni des fonctions à des composants React (mais pas nécessaire lors des simples balises HTML) de mémoizer cette fonction pour fournir toujours la même fonction entre les renders. - -On peut faire ceci via le hook `useCallback`, et en refactorisant le stockage du couple login/password, on peut faire ceci : - -*Noter le tableau de dépendances, comme pour useEffect et useMemo, qui permet de préciser quand la référence de la fonction peut changer* - -```tsx -const [{login, password}, setCredentials] = useState({ - login: '', - password: '', -}) - -const handleChange = useCallback((e: React.ChangeEvent<HTMLInputElement>) => { - // Il nous faut utiliser cette syntaxe, avec une fonction, pour récupérer la valeur précédente. - // On ne peut utiliser les valeurs déconstruites plus haut car elles pourraient ne pas être à jour, React entassant une pile de callbacks avant de toutes les exécuter) - // Il faut aussi extraire les valeurs avant car la fonction est asynchrone, et l'event peut avoir été détruit entretemps - const {name, value} = e.target - - setCredentials(credentials => { - return { - ...credentials, - [name]: value, - } - }) -}, []) - -<Field - onChange={handleChange} - name="login" - value={login} -/> -``` diff --git a/konnector-dev-config.json b/konnector-dev-config.json index 10ca55a3767664acf807dd1c9ef2ddd966238fb6..3e0c112641f98fe2ed5ade04b3d31a797f3a9da7 100644 --- a/konnector-dev-config.json +++ b/konnector-dev-config.json @@ -1,4 +1,4 @@ { "COZY_URL": "http://cozy.tools:8080", "fields": {} -} \ No newline at end of file +} diff --git a/manifest.webapp b/manifest.webapp index 322fc31aa73bfa798d7250b8b069ad8697d0425b..65196c7818b4ece32d710c75f4ef79b52a331fe7 100644 --- a/manifest.webapp +++ b/manifest.webapp @@ -3,7 +3,7 @@ "slug": "ecolyo", "icon": "icon.svg", "categories": ["energy"], - "version": "2.2.2", + "version": "2.3.0", "licence": "AGPL-3.0", "editor": "Métropole de Lyon", "default_locale": "fr", diff --git a/package.json b/package.json index cd63cb5c7d137fdf0c7020dea2a4e5781abad39b..13e40b936910b712f1a7426b95819aaf6db2f2c9 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,9 @@ { "name": "ecolyo", - "version": "2.2.2", + "version": "2.3.0", + "engines": { + "node": ">=16.0.0" + }, "scripts": { "build": "yarn run build:css && yarn run build:browser", "build:browser": "cs build --browser ", @@ -50,7 +53,7 @@ "@sentry/tracing": "^7.21.1", "@simbathesailor/use-what-changed": "^2.0.0", "cozy-bar": "8.9.2", - "cozy-client": "34.7.1", + "cozy-client": "35.6.0", "cozy-device-helper": ">=2.1.0", "cozy-flags": ">2.8.6", "cozy-harvest-lib": "9.26.14", @@ -59,7 +62,7 @@ "cozy-logger": ">1.7.0", "cozy-realtime": "4.2.8", "cozy-scripts": "6.3.10", - "cozy-ui": "79.3.0", + "cozy-ui": "81.5.0", "d3": "^6.0.0", "detect-browser": "^5.1.1", "file-saver": "^2.0.5", @@ -87,7 +90,7 @@ "@types/enzyme": "^3.10.8", "@types/file-saver": "^2.0.5", "@types/history": "^5.0.0", - "@types/jest": "^29.0.0", + "@types/jest": "^29.4.0", "@types/lodash": "^4.14.149", "@types/luxon": "^3.0.0", "@types/node-fetch": "^2.5.7", @@ -98,33 +101,33 @@ "@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.37.0", - "@typescript-eslint/parser": "^5.37.0", + "@typescript-eslint/eslint-plugin": "^5.56.0", + "@typescript-eslint/parser": "^5.56.0", "axios": "^1.3.0", "babel-polyfill": "^6.26.0", "babel-preset-cozy-app": "2.0.3", "copy-webpack-plugin": "6.4.1", "cozy-app-publish": "^0.31.0", - "cozy-jobs-cli": "^1.13.6", + "cozy-jobs-cli": "^2.0.0", "enzyme": "3.11.0", "enzyme-adapter-react-16": "1.15.6", "enzyme-to-json": "^3.6.2", - "eslint": "^8.18.0", - "eslint-config-prettier": "^8.5.0", + "eslint": "^8.36.0", + "eslint-config-prettier": "^8.8.0", "eslint-plugin-prettier": "^4.2.1", - "eslint-plugin-react": "7.31.8", - "eslint-plugin-react-hooks": "^4.2.0", + "eslint-plugin-react": "7.32.2", + "eslint-plugin-react-hooks": "^4.6.0", "git-directory-deploy": "1.5.1", "husky": "^8.0.1", - "jest-canvas-mock": "^2.3.0", - "jest-junit": "^14.0.0", + "jest-canvas-mock": "^2.4.0", + "jest-junit": "^15.0.0", "lint-staged": ">=8", "loglevel": "^1.6.6", "luxon": "^3.0.0", "mjml": "^4.10.2", "mjml-web": "^4.10.0", "npm-run-all": "^4.1.5", - "prettier": "^2.7.1", + "prettier": "^2.8.5", "prettier-eslint": "^15.0.1", "raw-loader": "^4.0.2", "react-test-renderer": "16.14.0", @@ -132,7 +135,7 @@ "sass": "^1.49.11", "sass-loader": "^8.0.0", "standard-version": "^9.3.1", - "typescript": "^4.0.0", + "typescript": "^5.0.0", "uglifyjs-webpack-plugin": "^2.2.0", "webextension-polyfill": "^0.10.0" }, diff --git a/renovate.json b/renovate.json index b112c41fe0a6199b90b6ed222afb403f00c0964c..039e82fc1d73b8c1217e0e3ba66429b3cd276461 100644 --- a/renovate.json +++ b/renovate.json @@ -1,7 +1,5 @@ { "$schema": "https://docs.renovatebot.com/renovate-schema.json", - "extends": [ - "local>systemes-dinformation/renovate/renovate-config" - ], + "extends": ["local>systemes-dinformation/renovate/renovate-config"], "labels": ["dependencies"] } diff --git a/scripts/createDayDataFiles.js b/scripts/createDayDataFiles.js index d5abc98edde52c87860876cb53a4f3298855bf3b..2159ee996e6ff1e157ee57e3972b8ca8d8817391 100644 --- a/scripts/createDayDataFiles.js +++ b/scripts/createDayDataFiles.js @@ -11,7 +11,7 @@ function getRandomInt(min, max) { const maxValue = Math.floor(max * 100) // NOSONAR const result = - (Math.floor(Math.random() * (maxValue - minValue)) + minValue) / 100 //NOSONAR + (Math.floor(Math.random() * (maxValue - minValue)) + minValue) / 100 // NOSONAR return result } diff --git a/scripts/server.js b/scripts/server.js index 376b0652329d4d8b1fe3245b18e043981b96b269..77447511e0b33bc184d7737ebed60ff9a70242cb 100644 --- a/scripts/server.js +++ b/scripts/server.js @@ -8,7 +8,7 @@ const process = (request, response) => { console.log('Listening on port 8081...') http - .createServer(function(request, response) { + .createServer(function (request, response) { const requestStart = Date.now() let errorMessage = null diff --git a/src/assets/icons/ico/accessibility.svg b/src/assets/icons/ico/accessibility.svg new file mode 100644 index 0000000000000000000000000000000000000000..fcfad1c0f34298927a69ce53b37a76e5294cf9d9 --- /dev/null +++ b/src/assets/icons/ico/accessibility.svg @@ -0,0 +1,4 @@ +<svg width="38" height="38" viewBox="0 0 38 38" fill="none" xmlns="http://www.w3.org/2000/svg"> +<path fill-rule="evenodd" clip-rule="evenodd" d="M19.0002 10.5883C20.2672 10.5883 21.2943 9.56118 21.2943 8.29418C21.2943 7.02717 20.2672 6.00006 19.0002 6.00006C17.7332 6.00006 16.7061 7.02717 16.7061 8.29418C16.7061 9.56118 17.7332 10.5883 19.0002 10.5883ZM10.0465 10.8921L17.0043 13.0329C18.3047 13.433 19.6953 13.433 20.9957 13.0329L27.9535 10.8921C28.4443 10.741 28.9412 11.108 28.9412 11.6215C28.9412 11.9232 28.7636 12.1965 28.4879 12.319L22.7143 14.8851C22.3157 15.0622 22.0588 15.4575 22.0588 15.8937V19.4508C22.0588 20.6781 22.1459 21.9038 22.3195 23.1187L23.4575 31.0846C23.5265 31.5677 23.1517 31.9999 22.6637 31.9999C22.3057 31.9999 21.991 31.7626 21.8927 31.4183L19.4956 23.0285C19.3532 22.5301 18.6468 22.5301 18.5044 23.0285L16.1074 31.4183C16.009 31.7626 15.6944 31.9999 15.3363 31.9999C14.8484 31.9999 14.4735 31.5677 14.5425 31.0846L15.6805 23.1187C15.8541 21.9038 15.9412 20.6781 15.9412 19.4508V15.8937C15.9412 15.4575 15.6843 15.0622 15.2857 14.8851L9.5121 12.319C9.23647 12.1965 9.05884 11.9232 9.05884 11.6215C9.05884 11.108 9.55573 10.741 10.0465 10.8921Z" fill="white"/> +<rect x="0.5" y="0.811462" width="37" height="36.377" rx="18.1885" stroke="white"/> +</svg> diff --git a/src/assets/icons/ico/gcu.svg b/src/assets/icons/ico/gcu.svg new file mode 100644 index 0000000000000000000000000000000000000000..677a646549e170eed799df0b52bdd52ca1410a7d --- /dev/null +++ b/src/assets/icons/ico/gcu.svg @@ -0,0 +1,12 @@ +<svg width="38" height="38" viewBox="0 0 38 38" fill="none" xmlns="http://www.w3.org/2000/svg"> +<path d="M11.431 31.5V6.5H26.569V25.9276L21.2079 31.5H11.431Z" stroke="white"/> +<path d="M25.9227 26.5L21.9998 30.7264V26.5H25.9227Z" stroke="white"/> +<line x1="13.6207" y1="9.08621" x2="24.3793" y2="9.08621" stroke="white"/> +<line x1="13.6207" y1="11.7759" x2="24.3793" y2="11.7759" stroke="white"/> +<line x1="13.6207" y1="14.4655" x2="24.3793" y2="14.4655" stroke="white"/> +<line x1="13.6207" y1="17.1552" x2="24.3793" y2="17.1552" stroke="white"/> +<line x1="13.6207" y1="19.8448" x2="24.3793" y2="19.8448" stroke="white"/> +<line x1="13.6207" y1="22.5345" x2="19.8966" y2="22.5345" stroke="white"/> +<path d="M13.6207 26.6207L15.4138 28.4138L19 24.8276" stroke="white"/> +<rect x="0.5" y="0.811478" width="37" height="36.377" rx="18.1885" stroke="white"/> +</svg> diff --git a/src/assets/icons/ico/white-arrow.svg b/src/assets/icons/ico/white-arrow.svg index 315176006821c1b9e9220dacdc7839e156e475d7..3eb09711f2519a6029d046fa5e471ce83f032f4a 100644 --- a/src/assets/icons/ico/white-arrow.svg +++ b/src/assets/icons/ico/white-arrow.svg @@ -1,4 +1,3 @@ <svg width="9" height="19" viewBox="0 0 9 19" fill="#FFFFFF" xmlns="http://www.w3.org/2000/svg"> <path d="M0.727051 18L8.72705 9L0.727049 6.99382e-07" fill="#FFFFFF"/> -</g> </svg> diff --git a/src/components/Action/ActionBegin.tsx b/src/components/Action/ActionBegin.tsx index c1c45183ba142f9e4552d53a5763289372bbbee7..546036e699ff8e1b973822b95b31a1655ffac714 100644 --- a/src/components/Action/ActionBegin.tsx +++ b/src/components/Action/ActionBegin.tsx @@ -26,10 +26,10 @@ const ActionBegin: React.FC<ActionBeginProps> = ({ }: ActionBeginProps) => { const client: Client = useClient() const { t } = useI18n() - const { isProfileTypeCompleted } = useSelector( - (state: AppStore) => state.ecolyo.profile - ) - const { fluidTypes } = useSelector((state: AppStore) => state.ecolyo.global) + const { + global: { fluidTypes }, + profile: { isProfileTypeCompleted }, + } = useSelector((state: AppStore) => state.ecolyo) const [currentAction, setCurrentAction] = useState<Ecogesture>() const [actionIcon, setActionIcon] = useState<string>('') const [openLaunchModal, setOpenLaunchModal] = useState<boolean>(false) diff --git a/src/components/Action/ActionCard.spec.tsx b/src/components/Action/ActionCard.spec.tsx index b91d9de04786fb04148019726bc3c6a397ab8368..db4315c17d86bb499e36897017baa0fe738c1105 100644 --- a/src/components/Action/ActionCard.spec.tsx +++ b/src/components/Action/ActionCard.spec.tsx @@ -1,4 +1,5 @@ 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 React from 'react' @@ -21,7 +22,8 @@ jest.mock('cozy-ui/transpiled/react/I18n', () => { }), } }) -const mockImportIconById = jest.fn() + +const mockImportIconById = jest.fn(() => defaultIcon) jest.mock('utils/utils', () => { return { importIconById: jest.fn(() => { diff --git a/src/components/Action/ActionChoose.spec.tsx b/src/components/Action/ActionChoose.spec.tsx index d1c67697be9abf67bf3f5fc4fad3c55749b509d8..41a5db7fddb76e0eed26fa8cb77650eafe14b6b7 100644 --- a/src/components/Action/ActionChoose.spec.tsx +++ b/src/components/Action/ActionChoose.spec.tsx @@ -17,6 +17,15 @@ jest.mock('cozy-ui/transpiled/react/I18n', () => { }), } }) + +const mockGetEcogesturesByIds = jest.fn(() => []) +jest.mock('services/ecogesture.service', () => { + return jest.fn(() => { + return { + getEcogesturesByIds: mockGetEcogesturesByIds, + } + }) +}) const mockStore = configureStore([]) describe('ActionChoose component', () => { diff --git a/src/components/Action/ActionChoose.tsx b/src/components/Action/ActionChoose.tsx index afdf64117986538b49a5040f2f8ffcb84261bbee..98337ce197aa12cd3587f325904bbca779faa914 100644 --- a/src/components/Action/ActionChoose.tsx +++ b/src/components/Action/ActionChoose.tsx @@ -1,7 +1,7 @@ -import React, { useState } from 'react' -import { Ecogesture, UserChallenge } from 'models' import ActionBegin from 'components/Action/ActionBegin' import ActionList from 'components/Action/ActionList' +import { Ecogesture, UserChallenge } from 'models' +import React, { useState } from 'react' import './actionChoose.scss' interface ActionChooseProps { diff --git a/src/components/Action/ActionDone.tsx b/src/components/Action/ActionDone.tsx index c483853482883d01cfecc473b6a0474a3107eb6f..1d94980dc928cb805053a714e54311329c086e66 100644 --- a/src/components/Action/ActionDone.tsx +++ b/src/components/Action/ActionDone.tsx @@ -6,11 +6,12 @@ import { useI18n } from 'cozy-ui/transpiled/react/I18n' import { UsageEventType } from 'enum/usageEvent.enum' import { UserChallengeUpdateFlag } from 'enum/userChallenge.enum' import { UserChallenge } from 'models' -import React, { useCallback } from 'react' +import React, { Dispatch, useCallback } from 'react' import { useDispatch } from 'react-redux' 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.actions' import { toggleChallengeActionNotification } from 'store/global/global.actions' import './actionDone.scss' @@ -23,7 +24,7 @@ const ActionDone: React.FC<ActionDoneProps> = ({ }: ActionDoneProps) => { const { t } = useI18n() const client = useClient() - const dispatch = useDispatch() + const dispatch = useDispatch<Dispatch<AppActionsTypes>>() const navigate = useNavigate() const handleEndAction = useCallback(async () => { const challengeService = new ChallengeService(client) diff --git a/src/components/Action/ActionList.spec.tsx b/src/components/Action/ActionList.spec.tsx index 038cc7e91c6719a71b88aa12fa2488bdbe714f83..85516527b9cc7b8cbba8b9bf854dc0f5be14063a 100644 --- a/src/components/Action/ActionList.spec.tsx +++ b/src/components/Action/ActionList.spec.tsx @@ -23,6 +23,16 @@ jest.mock('services/action.service', () => { }) }) +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) diff --git a/src/components/Action/ActionList.tsx b/src/components/Action/ActionList.tsx index 8e1dd62322162d56377207995842acffa2895eaa..447ca9aee3975db6449a2c6cf59115a50531830e 100644 --- a/src/components/Action/ActionList.tsx +++ b/src/components/Action/ActionList.tsx @@ -1,11 +1,11 @@ -import React, { useState, useEffect } from 'react' +import ActionCard from 'components/Action/ActionCard' import { Client, useClient } from 'cozy-client' -import { useSelector } from 'react-redux' import { Ecogesture } from 'models' -import './actionBegin.scss' -import { AppStore } from 'store' +import React, { useEffect, useState } from 'react' +import { useSelector } from 'react-redux' import ActionService from 'services/action.service' -import ActionCard from 'components/Action/ActionCard' +import { AppStore } from 'store' +import './actionBegin.scss' interface ActionListProps { setSelectedAction: React.Dispatch<React.SetStateAction<Ecogesture | null>> @@ -17,10 +17,10 @@ const ActionList: React.FC<ActionListProps> = ({ setShowList, }: ActionListProps) => { const client: Client = useClient() - const { isProfileTypeCompleted } = useSelector( - (state: AppStore) => state.ecolyo.profile - ) - const { fluidTypes } = useSelector((state: AppStore) => state.ecolyo.global) + const { + global: { fluidTypes }, + profile: { isProfileTypeCompleted }, + } = useSelector((state: AppStore) => state.ecolyo) const [actions, setActions] = useState<Ecogesture[]>() useEffect(() => { diff --git a/src/components/Action/ActionModal.tsx b/src/components/Action/ActionModal.tsx index 98cee53cdff3296cd4912cdf9eaf6527f2396c9a..cb209b25e13a42f4eaa1091e940078fb5c0f02c5 100644 --- a/src/components/Action/ActionModal.tsx +++ b/src/components/Action/ActionModal.tsx @@ -1,17 +1,17 @@ -import React, { useCallback } from 'react' -import './actionModal.scss' +import Button from '@material-ui/core/Button' +import Dialog from '@material-ui/core/Dialog' +import chronoMini from 'assets/icons/visu/action/chrono-mini.svg' import { useClient } from 'cozy-client' -import { useDispatch } from 'react-redux' import { useI18n } from 'cozy-ui/transpiled/react/I18n' -import { Ecogesture, UserChallenge } from 'models' +import Icon from 'cozy-ui/transpiled/react/Icon' import { UserChallengeUpdateFlag } from 'enum/userChallenge.enum' +import { Ecogesture, UserChallenge } from 'models' +import React, { Dispatch, useCallback } from 'react' +import { useDispatch } from 'react-redux' import ChallengeService from 'services/challenge.service' - -import Icon from 'cozy-ui/transpiled/react/Icon' -import Button from '@material-ui/core/Button' -import Dialog from '@material-ui/core/Dialog' +import { AppActionsTypes } from 'store' import { updateUserChallengeList } from 'store/challenge/challenge.actions' -import chronoMini from 'assets/icons/visu/action/chrono-mini.svg' +import './actionModal.scss' interface ActionModalProps { open: boolean @@ -26,7 +26,7 @@ const ActionModal: React.FC<ActionModalProps> = ({ handleCloseClick, userChallenge, }: ActionModalProps) => { - const dispatch = useDispatch() + const dispatch = useDispatch<Dispatch<AppActionsTypes>>() const client = useClient() const { t } = useI18n() const launchAction = useCallback(async () => { diff --git a/src/components/Action/ActionOnGoing.tsx b/src/components/Action/ActionOnGoing.tsx index 8627d2e829103a606d1aad326bc89189d555cfc4..44b7181c45e1c3b1e8d299d3bfc23094b80ddc22 100644 --- a/src/components/Action/ActionOnGoing.tsx +++ b/src/components/Action/ActionOnGoing.tsx @@ -1,12 +1,12 @@ -import React, { useCallback, useState } from 'react' -import { UserAction } from 'models' -import StyledIcon from 'components/CommonKit/Icon/StyledIcon' import { Button } from '@material-ui/core' -import { DateTime } from 'luxon' -import './actionOnGoing.scss' import ClockIcon from 'assets/icons/visu/action/duration-clock.svg' -import { useI18n } from 'cozy-ui/transpiled/react/I18n' +import StyledIcon from 'components/CommonKit/Icon/StyledIcon' import EcogestureModal from 'components/Ecogesture/EcogestureModal' +import { useI18n } from 'cozy-ui/transpiled/react/I18n' +import { DateTime } from 'luxon' +import { UserAction } from 'models' +import React, { useCallback, useState } from 'react' +import './actionOnGoing.scss' interface ActionOnGoingProps { userAction: UserAction diff --git a/src/components/Action/ActionView.spec.tsx b/src/components/Action/ActionView.spec.tsx index d6bd172a6fc807182814ba36a57c93cbf684779b..e10f9778f36aa4950e842de684702d7332c9cbe5 100644 --- a/src/components/Action/ActionView.spec.tsx +++ b/src/components/Action/ActionView.spec.tsx @@ -29,6 +29,7 @@ jest.mock('react-router-dom', () => ({ 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') const mockStore = configureStore([]) describe('ActionView component', () => { diff --git a/src/components/Action/actionModal.scss b/src/components/Action/actionModal.scss index 8daa3a4fbc0085fac1207bb915fbfecffbd05fb7..5b35affa4321f50e90f2e3970945b3bc1e88df62 100644 --- a/src/components/Action/actionModal.scss +++ b/src/components/Action/actionModal.scss @@ -22,4 +22,4 @@ #accessibility-title { display: none; -} \ No newline at end of file +} diff --git a/src/components/Analysis/AnalysisConsumption.tsx b/src/components/Analysis/AnalysisConsumption.tsx index daa4d07f30ddcd7095d21789e725a20da1f13fa6..bdf63113e9116a0ffbf8ccbc8c243e107995b8ee 100644 --- a/src/components/Analysis/AnalysisConsumption.tsx +++ b/src/components/Analysis/AnalysisConsumption.tsx @@ -8,7 +8,6 @@ import chevronDown from 'assets/icons/ico/chevron-down.svg' import ProfileEditIcon from 'assets/icons/ico/profile-edit.svg' import AnalysisIcon from 'assets/icons/visu/analysis/analysis.svg' import PlaceHolderIcon from 'assets/icons/visu/analysis/no-profile-placeholder.svg' -import AnalysisConsumptionRow from 'components/Analysis/AnalysisConsumptionRow' import StyledIcon from 'components/CommonKit/Icon/StyledIcon' import Loader from 'components/Loader/Loader' import { Client, useClient } from 'cozy-client' @@ -16,7 +15,7 @@ import { useI18n } from 'cozy-ui/transpiled/react/I18n' import Icon from 'cozy-ui/transpiled/react/Icon' import { FluidType } from 'enum/fluid.enum' import { DateTime } from 'luxon' -import { PerformanceIndicator, Profile } from 'models' +import { PerformanceIndicator } from 'models' import { MonthlyForecast, ProfileType } from 'models/profileType.model' import React, { useCallback, useEffect, useState } from 'react' import { useSelector } from 'react-redux' @@ -24,6 +23,7 @@ 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' interface AnalysisConsumptionProps { @@ -41,13 +41,13 @@ const AnalysisConsumption: React.FC<AnalysisConsumptionProps> = ({ const navigate = useNavigate() const client: Client = useClient() const userPriceConsumption: number = aggregatedPerformanceIndicator.value || 0 - const profile: Profile = useSelector( - (state: AppStore) => state.ecolyo.profile - ) - const { fluidTypes } = useSelector((state: AppStore) => state.ecolyo.global) + const { + global: { fluidTypes }, + profile, + } = useSelector((state: AppStore) => state.ecolyo) const [homePriceConsumption, setHomePriceConsumption] = useState<number>(0) const [forecast, setForecast] = useState<MonthlyForecast | null>(null) - const [isLoading, setisLoading] = useState<boolean>(true) + const [isLoading, setIsLoading] = useState<boolean>(true) const [activeAverageHome, setActiveAverageHome] = useState<boolean>(false) const toggleAccordion = () => { @@ -75,7 +75,7 @@ const AnalysisConsumption: React.FC<AnalysisConsumptionProps> = ({ const emptyFluidTypes: FluidType[] = [] for (let i = 0; i < performanceIndicators.length; i++) { - if (!performanceIndicators[i]?.value) { + if (!performanceIndicators[i]?.value && fluidTypes[i]) { emptyFluidTypes.push(fluidTypes[i]) } } @@ -102,7 +102,7 @@ const AnalysisConsumption: React.FC<AnalysisConsumptionProps> = ({ useEffect(() => { let subscribed = true - async function loadAverageComsumption() { + async function loadAverageConsumption() { const profileTypeEntityService = new ProfileTypeEntityService(client) const profileType: ProfileType | null = await profileTypeEntityService.getProfileType( @@ -123,11 +123,11 @@ const AnalysisConsumption: React.FC<AnalysisConsumptionProps> = ({ if (monthlyForecast) { getTotalValueWithConnectedFluids(monthlyForecast) } - setisLoading(false) + setIsLoading(false) } } } - loadAverageComsumption() + loadAverageConsumption() return () => { subscribed = false } @@ -139,7 +139,7 @@ const AnalysisConsumption: React.FC<AnalysisConsumptionProps> = ({ analysisDate, ]) - const profileNotCompleted = () => ( + const profileNotCompleted = ( <div className="no-profile"> <div className="text-16-normal"> {t('analysis.approximative_description')} @@ -163,6 +163,108 @@ const AnalysisConsumption: React.FC<AnalysisConsumptionProps> = ({ </div> ) + const Consumption = ( + <div className="analysis-graph"> + {isLoading ? ( + <div className="loader-container"> + <Loader color="elec" /> + </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> + {fluidTypes.map( + fluid => + Boolean(performanceIndicators[fluid]?.value) && ( + <AnalysisConsumptionRow + key={fluid} + fluid={fluid} + userPriceConsumption={userPriceConsumption} + homePriceConsumption={homePriceConsumption} + performanceValue={performanceIndicators[fluid].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.map(fluid => ( + <AnalysisConsumptionRow + key={fluid} + fluid={fluid} + userPriceConsumption={userPriceConsumption} + homePriceConsumption={homePriceConsumption} + performanceValue={null} + forecast={forecast} + connected={false} + noData={true} + /> + ))} + + <Accordion + expanded={activeAverageHome} + onChange={toggleAccordion} + classes={{ + root: 'expansion-panel-root', + }} + > + <AccordionSummary + aria-label={t( + 'profile_type.accessibility.button_toggle_average_home' + )} + expandIcon={ + <Icon icon={chevronDown} size={16} className="accordion-icon" /> + } + classes={{ + root: 'expansion-panel-summary', + content: 'expansion-panel-content', + }} + > + <div className="accordion-title accordion-title"> + {t('analysis.average_home')} + </div> + </AccordionSummary> + <AccordionDetails + classes={{ + root: 'expansion-panel-details', + }} + > + <span className="accordion-desc text-16-normal"> + {t('analysis.average_home_description')} + </span> + </AccordionDetails> + </Accordion> + </> + )} + </div> + ) + return ( <> <div className="status-header"> @@ -185,109 +287,8 @@ const AnalysisConsumption: React.FC<AnalysisConsumptionProps> = ({ </div> <div className="analysis-graph"> - {!profile.isProfileTypeCompleted ? ( - profileNotCompleted() - ) : isLoading ? ( - <div className="loader-container"> - <Loader color="elec" /> - </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> - {fluidTypes.map( - (fluid, index) => - performanceIndicators[fluid]?.value && ( - <AnalysisConsumptionRow - key={index} - fluid={fluid} - userPriceConsumption={userPriceConsumption} - homePriceConsumption={homePriceConsumption} - performanceValue={performanceIndicators[fluid].value} - forecast={forecast} - connected={true} - noData={false} - /> - ) - )} - {fluidTypes.length < 3 && <hr className="consumption-sep" />} - {disconnectedFluidTypes.map((fluid, index) => ( - <AnalysisConsumptionRow - key={index} - fluid={fluid} - userPriceConsumption={userPriceConsumption} - homePriceConsumption={homePriceConsumption} - performanceValue={null} - forecast={forecast} - connected={false} - noData={false} - /> - ))} - {emptyFluidTypes.map((fluid, index) => ( - <AnalysisConsumptionRow - key={index} - fluid={fluid} - userPriceConsumption={userPriceConsumption} - homePriceConsumption={homePriceConsumption} - performanceValue={null} - forecast={forecast} - connected={false} - noData={true} - /> - ))} - - <Accordion - expanded={activeAverageHome} - onChange={toggleAccordion} - classes={{ - root: 'expansion-panel-root', - }} - > - <AccordionSummary - aria-label={t( - 'profile_type.accessibility.button_toggle_average_home' - )} - expandIcon={ - <Icon - icon={chevronDown} - size={16} - className="accordion-icon" - /> - } - classes={{ - root: 'expansion-panel-summary', - content: 'expansion-panel-content', - }} - > - <div className="accordion-title accordion-title"> - {t('analysis.average_home')} - </div> - </AccordionSummary> - <AccordionDetails - classes={{ - root: 'expansion-panel-details', - }} - > - <span className="accordion-desc text-16-normal"> - {t('analysis.average_home_description')} - </span> - </AccordionDetails> - </Accordion> - </> - )} + {!profile.isProfileTypeCompleted && profileNotCompleted} + {profile.isProfileTypeCompleted && Consumption} </div> </> ) diff --git a/src/components/Analysis/AnalysisConsumptionRow.spec.tsx b/src/components/Analysis/AnalysisConsumptionRow.spec.tsx index 2deb45ac4ad4b3d3cee5ee7c0c71f6ebc5e3767d..b147d31cf440dafc9f9cd73c09e4a28cd448649f 100644 --- a/src/components/Analysis/AnalysisConsumptionRow.spec.tsx +++ b/src/components/Analysis/AnalysisConsumptionRow.spec.tsx @@ -1,8 +1,8 @@ -import React from 'react' -import { mount } from 'enzyme' -import { mockMonthlyForecastJanuaryTestProfile1 } from '../../../tests/__mocks__/profileType.mock' import { FluidType } from 'enum/fluid.enum' +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', () => { diff --git a/src/components/Analysis/AnalysisConsumptionRow.tsx b/src/components/Analysis/AnalysisConsumptionRow.tsx index c4a3fbeb8ed1f7b4984448c3d98638767ecc13b0..b92298babf4a7283514acf661d82cd55f886e46a 100644 --- a/src/components/Analysis/AnalysisConsumptionRow.tsx +++ b/src/components/Analysis/AnalysisConsumptionRow.tsx @@ -1,14 +1,14 @@ -import React from 'react' +import EuroIcon from 'assets/icons/ico/euro-icon.svg' import classNames from 'classnames' -import './analysisConsumptionRow.scss' -import { useI18n } from 'cozy-ui/transpiled/react/I18n' -import { getPicto } from 'utils/picto' -import { formatNumberValues } from 'utils/utils' import StyledIcon from 'components/CommonKit/Icon/StyledIcon' -import EuroIcon from 'assets/icons/ico/euro-icon.svg' +import { useI18n } from 'cozy-ui/transpiled/react/I18n' import { FluidType } from 'enum/fluid.enum' 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' interface AnalysisConsumptionRowProps { fluid: FluidType @@ -104,6 +104,16 @@ const AnalysisConsumptionRow: React.FC<AnalysisConsumptionRowProps> = ({ return `${(fluidValue / maxPriceConsumption) * 100}%` } } + + let comparaisonText: string + if (connected) { + comparaisonText = formatFluidConsumptionForConso(fluid) + } else if (noData) { + comparaisonText = t(`analysis.no_data_2`) + } else { + comparaisonText = t(`analysis.not_connected`) + } + return ( <div className={`consumption-${FluidType[fluid].toLowerCase()} analysisRow`} @@ -114,11 +124,7 @@ const AnalysisConsumptionRow: React.FC<AnalysisConsumptionRowProps> = ({ ['not-connected']: !connected || noData, })} > - {connected - ? formatFluidConsumptionForConso(fluid) - : noData - ? t(`analysis.no_data_2`) - : t(`analysis.not_connected`)} + {comparaisonText} </div> <div className="container-graph"> {connected && ( diff --git a/src/components/Analysis/AnalysisView.spec.tsx b/src/components/Analysis/AnalysisView.spec.tsx index 32c67dbd856468e65bcfcfb7f1c996362c5a846d..87e6fb72a27e4b34cffba80e29d52832dd259c78 100644 --- a/src/components/Analysis/AnalysisView.spec.tsx +++ b/src/components/Analysis/AnalysisView.spec.tsx @@ -8,8 +8,8 @@ import * as profileActions from 'store/profile/profile.actions' import { globalStateData } from '../../../tests/__mocks__/globalStateData.mock' import { profileData } from '../../../tests/__mocks__/profileData.mock' import { - createMockStore, - mockInitialEcolyoState, + createMockEcolyoStore, + mockInitialChartState, } from '../../../tests/__mocks__/store' jest.mock('cozy-ui/transpiled/react/I18n', () => { @@ -43,10 +43,9 @@ const toggleAnalysisNotificationSpy = jest.spyOn( const updateProfileSpy = jest.spyOn(profileActions, 'updateProfile') describe('AnalysisView component', () => { - // eslint-disable-next-line @typescript-eslint/no-explicit-any - let store: any + const store = createMockEcolyoStore() beforeEach(() => { - store = createMockStore(mockInitialEcolyoState) + store.clearActions() useSelectorSpy.mockClear() useDispatchSpy.mockClear() toggleAnalysisNotificationSpy.mockClear() @@ -57,6 +56,7 @@ describe('AnalysisView component', () => { useSelectorSpy.mockReturnValue({ global: globalStateData, profile: profileData, + chart: mockInitialChartState, }) useDispatchSpy.mockReturnValue(jest.fn()) const wrapper = mount( @@ -80,6 +80,7 @@ describe('AnalysisView component', () => { ...profileData, haveSeenLastAnalysis: false, }, + chart: mockInitialChartState, }) useDispatchSpy.mockReturnValue(jest.fn()) const wrapper = mount( diff --git a/src/components/Analysis/AnalysisView.tsx b/src/components/Analysis/AnalysisView.tsx index 49f1099e26f860bd8afe3951f52768755bc5dabe..55dd0fcc29038ebaa1fb8b5549cfb6a6f107d9a1 100644 --- a/src/components/Analysis/AnalysisView.tsx +++ b/src/components/Analysis/AnalysisView.tsx @@ -1,9 +1,3 @@ -import React, { useCallback, useEffect, useState } from 'react' -import { useDispatch, useSelector } from 'react-redux' -import { AppStore } from 'store' -import { toggleAnalysisNotification } from 'store/global/global.actions' -import { updateProfile } from 'store/profile/profile.actions' - import MonthlyAnalysis from 'components/Analysis/MonthlyAnalysis' import Content from 'components/Content/Content' import DateNavigator from 'components/DateNavigator/DateNavigator' @@ -12,24 +6,27 @@ import Header from 'components/Header/Header' import { useClient } from 'cozy-client' import { UsageEventType } from 'enum/usageEvent.enum' import { DateTime } from 'luxon' +import React, { Dispatch, useCallback, useEffect, useState } from 'react' +import { useDispatch, useSelector } from 'react-redux' import { useLocation } from 'react-router-dom' 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 './analysisView.scss' const AnalysisView: React.FC = () => { const client = useClient() const [headerHeight, setHeaderHeight] = useState<number>(0) const { + chart: { selectedDate }, global: { analysisNotification }, - profile: { monthlyAnalysisDate }, + profile: { monthlyAnalysisDate, mailToken }, } = useSelector((state: AppStore) => state.ecolyo) - const { selectedDate } = useSelector((state: AppStore) => state.ecolyo.chart) const [currentAnalysisDate, setCurrentAnalysisDate] = useState<DateTime>(monthlyAnalysisDate) - const { mailToken } = useSelector((state: AppStore) => state.ecolyo.profile) - const dispatch = useDispatch() - + const dispatch = useDispatch<Dispatch<AppActionsTypes>>() const defineHeaderHeight = useCallback((height: number) => { setHeaderHeight(height) }, []) diff --git a/src/components/Analysis/ElecHalfHourChart.spec.tsx b/src/components/Analysis/ElecHalfHourChart.spec.tsx index 702caef22cd3a763508c52e9ed90179538e8ea95..8cb417f255794dc21dab3493610e4d74f2d9a685 100644 --- a/src/components/Analysis/ElecHalfHourChart.spec.tsx +++ b/src/components/Analysis/ElecHalfHourChart.spec.tsx @@ -1,12 +1,12 @@ -import React from 'react' import { mount } from 'enzyme' -import { globalStateData } from '../../../tests/__mocks__/globalStateData.mock' +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' -import * as reactRedux from 'react-redux' -import { DateTime } from 'luxon' -import { dataLoadArray } from '../../../tests/__mocks__/datachartData.mock' jest.mock('cozy-ui/transpiled/react/I18n', () => { return { diff --git a/src/components/Analysis/ElecHalfHourChart.tsx b/src/components/Analysis/ElecHalfHourChart.tsx index e04845561012176f17a145ff8ff19956e448781c..f24bc9e81a17d8a907a1a98305094e6fd79c81d0 100644 --- a/src/components/Analysis/ElecHalfHourChart.tsx +++ b/src/components/Analysis/ElecHalfHourChart.tsx @@ -1,12 +1,12 @@ -import React, { useEffect, useRef, useState } from 'react' -import Bar from 'components/Charts/Bar' import AxisBottom from 'components/Charts/AxisBottom' import AxisRight from 'components/Charts/AxisRight' -import { FluidType } from 'enum/fluid.enum' +import Bar from 'components/Charts/Bar' import { scaleBand, ScaleBand, scaleLinear, ScaleLinear } from 'd3-scale' -import { DateTime } from 'luxon' +import { FluidType } from 'enum/fluid.enum' import { TimeStep } from 'enum/timeStep.enum' +import { DateTime } from 'luxon' import { Dataload } from 'models' +import React, { useEffect, useRef, useState } from 'react' import './elecHalfHourMonthlyAnalysis.scss' interface ElecHalfHourChartProps { diff --git a/src/components/Analysis/ElecHalfHourMonthlyAnalysis.spec.tsx b/src/components/Analysis/ElecHalfHourMonthlyAnalysis.spec.tsx index 9ce4cd90f3c0e38d3fceae44c5f4aaf3f57acd7e..2326f69a18a33bd840366f0409255be7b6bd3582 100644 --- a/src/components/Analysis/ElecHalfHourMonthlyAnalysis.spec.tsx +++ b/src/components/Analysis/ElecHalfHourMonthlyAnalysis.spec.tsx @@ -1,16 +1,16 @@ -import React from 'react' +import { IconButton } from '@material-ui/core' import { mount } from 'enzyme' import toJson from 'enzyme-to-json' -import { waitForComponentToPaint } from '../../../tests/__mocks__/testUtils' import { DateTime } from 'luxon' -import ElecHalfHourMonthlyAnalysis from './ElecHalfHourMonthlyAnalysis' -import { IconButton } from '@material-ui/core' +import { PerformanceIndicator } from 'models' +import React from 'react' import { mockDataLoadEnedisAnalysis, mockEnedisMonthlyAnalysisArray, } from '../../../tests/__mocks__/enedisMonthlyAnalysisData.mock' -import { PerformanceIndicator } from 'models' import { allLastFluidPrices } from '../../../tests/__mocks__/fluidPrice.mock' +import { waitForComponentToPaint } from '../../../tests/__mocks__/testUtils' +import ElecHalfHourMonthlyAnalysis from './ElecHalfHourMonthlyAnalysis' jest.mock('cozy-ui/transpiled/react/I18n', () => { return { diff --git a/src/components/Analysis/ElecHalfHourMonthlyAnalysis.tsx b/src/components/Analysis/ElecHalfHourMonthlyAnalysis.tsx index 58165f30c0720574e4f615614457c07dcbd53d47..625f7a4f106fd009eea99914a91d020448ea81e8 100644 --- a/src/components/Analysis/ElecHalfHourMonthlyAnalysis.tsx +++ b/src/components/Analysis/ElecHalfHourMonthlyAnalysis.tsx @@ -54,8 +54,7 @@ const ElecHalfHourMonthlyAnalysis: React.FC< }, []) const isDataFullyComplete = useCallback(monthDataloads => { if ( - monthDataloads && - monthDataloads.weekend && + monthDataloads?.weekend && monthDataloads.week && monthDataloads.weekend[0]?.value !== null && monthDataloads.week[0]?.value !== null diff --git a/src/components/Analysis/ElecInfoModal.spec.tsx b/src/components/Analysis/ElecInfoModal.spec.tsx index cbd20d0dcb97f58925e18cc1a4e35c7ca092ee9d..a3207082fa69a5d0ee49f4bcf92aa7bf47a84057 100644 --- a/src/components/Analysis/ElecInfoModal.spec.tsx +++ b/src/components/Analysis/ElecInfoModal.spec.tsx @@ -1,6 +1,6 @@ -import React from 'react' import { mount } from 'enzyme' import toJson from 'enzyme-to-json' +import React from 'react' import ElecInfoModal from './ElecInfoModal' jest.mock('cozy-ui/transpiled/react/I18n', () => { diff --git a/src/components/Analysis/ElecInfoModal.tsx b/src/components/Analysis/ElecInfoModal.tsx index 1b2b0ba284ca5327dba7a542c1b9f12073215f67..5224c3346aa4564669fa58add021c5c9b5dcc125 100644 --- a/src/components/Analysis/ElecInfoModal.tsx +++ b/src/components/Analysis/ElecInfoModal.tsx @@ -1,9 +1,9 @@ -import React from 'react' -import { useI18n } from 'cozy-ui/transpiled/react/I18n' -import Dialog from '@material-ui/core/Dialog' import { IconButton } from '@material-ui/core' -import Icon from 'cozy-ui/transpiled/react/Icon' +import Dialog from '@material-ui/core/Dialog' 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 React from 'react' import './elecInfoModal.scss' interface ElecInfoModalProps { diff --git a/src/components/Analysis/MaxConsumptionCard.spec.tsx b/src/components/Analysis/MaxConsumptionCard.spec.tsx index ec38f627242e4390c7442297dd30f9ecd8ff48b0..5a3ac902d1c0823b6692c2953888b9a9626cd28e 100644 --- a/src/components/Analysis/MaxConsumptionCard.spec.tsx +++ b/src/components/Analysis/MaxConsumptionCard.spec.tsx @@ -1,12 +1,13 @@ -import React from 'react' +import { FluidType } from 'enum/fluid.enum' import { mount } from 'enzyme' import { DateTime } from 'luxon' +import React from 'react' import * as reactRedux from 'react-redux' -import { globalStateData } from '../../../tests/__mocks__/globalStateData.mock' import { Provider } from 'react-redux' import configureStore from 'redux-mock-store' +import mockClient from '../../../tests/__mocks__/client' +import { globalStateData } from '../../../tests/__mocks__/globalStateData.mock' import MaxConsumptionCard from './MaxConsumptionCard' -import { FluidType } from 'enum/fluid.enum' jest.mock('cozy-ui/transpiled/react/I18n', () => { return { @@ -17,6 +18,23 @@ jest.mock('cozy-ui/transpiled/react/I18n', () => { }), } }) + +const mockGetMaxLoad = jest.fn(() => 0) +jest.mock('services/consumption.service', () => { + return jest.fn(() => { + return { + getMaxLoad: mockGetMaxLoad, + } + }) +}) +jest.mock('cozy-client', () => { + return { + useClient: jest.fn(() => { + return mockClient + }), + } +}) + const mockStore = configureStore([]) const mockUseSelector = jest.spyOn(reactRedux, 'useSelector') diff --git a/src/components/Analysis/MonthlyAnalysis.spec.tsx b/src/components/Analysis/MonthlyAnalysis.spec.tsx index ab9d33e918e9369c2a78ed777cc6df0d861137ee..ea7ede3c010c4eb3cd9a501bceb4b6c03706195f 100644 --- a/src/components/Analysis/MonthlyAnalysis.spec.tsx +++ b/src/components/Analysis/MonthlyAnalysis.spec.tsx @@ -1,15 +1,12 @@ -import React from 'react' -import { mount } from 'enzyme' - import MonthlyAnalysis from 'components/Analysis/MonthlyAnalysis' +import { FluidType } from 'enum/fluid.enum' +import { mount } from 'enzyme' import { DateTime } from 'luxon' - +import React from 'react' import * as reactRedux from 'react-redux' -import { userChallengeExplo1OnGoing } from '../../../tests/__mocks__/userChallengeData.mock' - -import { globalStateData } from '../../../tests/__mocks__/globalStateData.mock' import { Provider } from 'react-redux' import configureStore from 'redux-mock-store' +import { globalStateData } from '../../../tests/__mocks__/globalStateData.mock' jest.mock('cozy-ui/transpiled/react/I18n', () => { return { @@ -20,12 +17,20 @@ jest.mock('cozy-ui/transpiled/react/I18n', () => { }), } }) +jest.mock('services/consumption.service') +jest.mock( + 'components/PerformanceIndicator/FluidPerformanceIndicator', + () => 'mock-fluid-performance-indicator' +) + const mockStore = configureStore([]) const mockUseSelector = jest.spyOn(reactRedux, 'useSelector') describe('MonthlyAnalysis component', () => { - mockUseSelector.mockReturnValue(userChallengeExplo1OnGoing) + mockUseSelector.mockReturnValue({ + fluidTypes: [FluidType.ELECTRICITY, FluidType.GAS], + }) it('should be rendered correctly', () => { const store = mockStore({ diff --git a/src/components/Analysis/MonthlyAnalysis.tsx b/src/components/Analysis/MonthlyAnalysis.tsx index ee59f2a5d1b96b51cc4346d3e94fcb33c43d3e13..da0110f451c03eb8298f492e630dc230b74b7d12 100644 --- a/src/components/Analysis/MonthlyAnalysis.tsx +++ b/src/components/Analysis/MonthlyAnalysis.tsx @@ -102,7 +102,7 @@ const MonthlyAnalysis: React.FC<MonthlyAnalysisProps> = ({ if (isLoaded) { const app = document.querySelector('.app-content') window.scrollTo(0, scrollPosition) - app && app.scrollTo(0, scrollPosition) + app?.scrollTo(0, scrollPosition) } }, [isLoaded, scrollPosition]) @@ -119,18 +119,21 @@ const MonthlyAnalysis: React.FC<MonthlyAnalysisProps> = ({ <> <div className="analysis-content"> <div> - {fluidConfig.map((fluid, index) => { - return fluidTypes.includes(fluid.fluidTypeId) ? ( - <FluidPerformanceIndicator - key={index} - fluidType={fluid.fluidTypeId} - performanceIndicator={ - performanceIndicators[fluid.fluidTypeId] - } - date={analysisDate.minus({ month: 1 }).startOf('month')} - /> - ) : null - })} + {fluidConfig.map( + fluid => + fluidTypes.includes(fluid.fluidTypeId) && ( + <FluidPerformanceIndicator + key={fluid.konnectorConfig.slug} + fluidType={fluid.fluidTypeId} + performanceIndicator={ + performanceIndicators[fluid.fluidTypeId] + } + date={analysisDate + .minus({ month: 1 }) + .startOf('month')} + /> + ) + )} </div> </div> diff --git a/src/components/Analysis/PieChart.spec.tsx b/src/components/Analysis/PieChart.spec.tsx index 11b0a66908c3bf5338bcb071e7adcfc800ca0d47..84bba0ee8718f6d486f76884a1b214e248b027ab 100644 --- a/src/components/Analysis/PieChart.spec.tsx +++ b/src/components/Analysis/PieChart.spec.tsx @@ -1,12 +1,12 @@ -import React from 'react' +import { DataloadState } from 'enum/dataload.enum' import { mount } from 'enzyme' import { DateTime } from 'luxon' -import { globalStateData } from '../../../tests/__mocks__/globalStateData.mock' +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' -import { DataloadValueDetail } from 'models' -import { DataloadState } from 'enum/dataload.enum' jest.mock('cozy-ui/transpiled/react/I18n', () => { return { @@ -17,6 +17,16 @@ jest.mock('cozy-ui/transpiled/react/I18n', () => { }), } }) + +const mockGetAllLastPrices = jest.fn() +jest.mock('services/fluidsPrices.service', () => { + return jest.fn(() => { + return { + getAllLastPrices: mockGetAllLastPrices, + } + }) +}) + const mockStore = configureStore([]) describe('PieChart component', () => { diff --git a/src/components/Analysis/PieChart.tsx b/src/components/Analysis/PieChart.tsx index 65929a7cb42a84d8f2b46a5014cd93893f342c94..a33312c7354909625a4f2c14918bfbce26bd2295 100644 --- a/src/components/Analysis/PieChart.tsx +++ b/src/components/Analysis/PieChart.tsx @@ -1,12 +1,12 @@ -import React, { useCallback, useEffect, useRef, useState } from 'react' -import './totalAnalysisChart.scss' -import * as d3 from 'd3' +import EstimatedConsumptionModal from 'components/ConsumptionVisualizer/EstimatedConsumptionModal' import { useI18n } from 'cozy-ui/transpiled/react/I18n' -import { formatNumberValues } from 'utils/utils' +import * as d3 from 'd3' import { DateTime } from 'luxon' -import { convertDateToMonthString } from 'utils/date' -import EstimatedConsumptionModal from 'components/ConsumptionVisualizer/EstimatedConsumptionModal' import { DataloadValueDetail } from 'models' +import React, { useCallback, useEffect, useRef, useState } from 'react' +import { convertDateToMonthString } from 'utils/date' +import { formatNumberValues } from 'utils/utils' +import './totalAnalysisChart.scss' interface PieProps { innerRadius: number diff --git a/src/components/Analysis/TotalAnalysisChart.spec.tsx b/src/components/Analysis/TotalAnalysisChart.spec.tsx index 2ec549add6f76f5e1ece5bf527f729fb31829249..352503150f34a937bd30dd5c614dbc6a2b477542 100644 --- a/src/components/Analysis/TotalAnalysisChart.spec.tsx +++ b/src/components/Analysis/TotalAnalysisChart.spec.tsx @@ -1,18 +1,14 @@ -import React from 'react' +import { DataloadState } from 'enum/dataload.enum' +import { FluidType } from 'enum/fluid.enum' import { mount } from 'enzyme' import { DateTime } from 'luxon' - +import { Datachart } from 'models' +import React from 'react' +import { act } from 'react-dom/test-utils' import { Provider } from 'react-redux' +import { graphMonthData } from '../../../tests/__mocks__/chartData.mock' +import { createMockEcolyoStore } from '../../../tests/__mocks__/store' import TotalAnalysisChart from './TotalAnalysisChart' -import { FluidType } from 'enum/fluid.enum' -import { graphMonthData } from '../../../tests/__mocks__/datachartData.mock' -import { act } from 'react-dom/test-utils' -import { - createMockStore, - mockInitialEcolyoState, -} from '../../../tests/__mocks__/store' -import { Datachart } from 'models' -import { DataloadState } from 'enum/dataload.enum' jest.mock('cozy-ui/transpiled/react/I18n', () => { return { @@ -34,10 +30,9 @@ jest.mock('services/consumption.service', () => { jest.mock('components/Analysis/PieChart', () => 'mock-piechart') describe('TotalAnalysisChart component', () => { - // eslint-disable-next-line @typescript-eslint/no-explicit-any - let store: any + const store = createMockEcolyoStore() beforeEach(() => { - store = createMockStore(mockInitialEcolyoState) + store.clearActions() }) it('should be rendered correctly', () => { diff --git a/src/components/Analysis/TotalAnalysisChart.tsx b/src/components/Analysis/TotalAnalysisChart.tsx index 6d14c65d6f6b08b65c7e38ebce8ba2aa183ae21a..238f2d338d1aab160603704dfa7121bc14a3dea9 100644 --- a/src/components/Analysis/TotalAnalysisChart.tsx +++ b/src/components/Analysis/TotalAnalysisChart.tsx @@ -1,18 +1,17 @@ -import React, { useState, useEffect } from 'react' -import './analysisView.scss' -import { DateTime } from 'luxon' import { useClient } from 'cozy-client' -import ConsumptionDataManager from 'services/consumption.service' +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 { DateTime } from 'luxon' import { DataloadValueDetail, TimePeriod } from 'models' -import PieChart from './PieChart' -import './totalAnalysisChart.scss' +import React, { useEffect, useState } from 'react' +import ConsumptionDataManager from 'services/consumption.service' import { getNavPicto } from 'utils/picto' -import Icon from 'cozy-ui/transpiled/react/Icon' - import { formatNumberValues } from 'utils/utils' -import { useI18n } from 'cozy-ui/transpiled/react/I18n' +import './analysisView.scss' +import PieChart from './PieChart' +import './totalAnalysisChart.scss' interface TotalAnalysisChartProps { analysisDate: DateTime diff --git a/src/components/App.tsx b/src/components/App.tsx index fd0b11c37075af7f4debe63a30733d460af47bd7..9bca9f4edaaa2de3315c4db7a73e47648f6275cb 100644 --- a/src/components/App.tsx +++ b/src/components/App.tsx @@ -1,10 +1,8 @@ import Navbar from 'components/Navbar/Navbar' -import WelcomeModal from 'components/Onboarding/WelcomeModal' import AppRoutes from 'components/Routes/Routes' import SplashRoot from 'components/Splash/SplashRoot' -import SplashScreen from 'components/Splash/SplashScreen' -import SplashScreenError from 'components/Splash/SplashScreenError' -import { Content, Layout, Main } from 'cozy-ui/transpiled/react/Layout' +import WelcomeModal from 'components/WelcomeModal/WelcomeModal' +import { Layout } from 'cozy-ui/transpiled/react/Layout' import React, { useEffect } from 'react' import { useSelector } from 'react-redux' import { useLocation } from 'react-router-dom' @@ -17,8 +15,10 @@ interface AppProps { export const App = ({ tracker }: AppProps) => { const location = useLocation() - const { onboarding } = useSelector((state: AppStore) => state.ecolyo.profile) - const { termsStatus } = useSelector((state: AppStore) => state.ecolyo.global) + const { + global: { termsStatus }, + profile: { onboarding }, + } = useSelector((state: AppStore) => state.ecolyo) useEffect(() => { tracker?.track(location) @@ -26,21 +26,16 @@ export const App = ({ tracker }: AppProps) => { return ( <Layout> - <SplashRoot - splashComponent={SplashScreen} - splashErrorComponent={SplashScreenError} - > + <SplashRoot> {termsStatus.accepted && ( <> <WelcomeModal open={!onboarding.isWelcomeSeen} /> <Navbar /> </> )} - <Main> - <Content className="app-content"> - <AppRoutes termsStatus={termsStatus} /> - </Content> - </Main> + <main className="app-content"> + <AppRoutes termsStatus={termsStatus} /> + </main> </SplashRoot> </Layout> ) diff --git a/src/components/Challenge/ChallengeCard.spec.tsx b/src/components/Challenge/ChallengeCard.spec.tsx index d481a4d2a81665e1c4dcf4e5a948fd6abb9fa2bf..9519e7e99752c02f3c2ee0f63afecbfd833e1c90 100644 --- a/src/components/Challenge/ChallengeCard.spec.tsx +++ b/src/components/Challenge/ChallengeCard.spec.tsx @@ -1,10 +1,10 @@ -import React from 'react' import { shallow } from 'enzyme' +import React from 'react' +import { userChallengeData } from '../../../tests/__mocks__/userChallengeData.mock' import ChallengeCard from './ChallengeCard' import ChallengeCardLocked from './ChallengeCardLocked' -import ChallengeCardUnlocked from './ChallengeCardUnlocked' import ChallengeCardOnGoing from './ChallengeCardOnGoing' -import { userChallengeData } from '../../../tests/__mocks__/userChallengeData.mock' +import ChallengeCardUnlocked from './ChallengeCardUnlocked' jest.mock('cozy-ui/transpiled/react/I18n', () => { return { diff --git a/src/components/Challenge/ChallengeCard.tsx b/src/components/Challenge/ChallengeCard.tsx index 6336cc75b7e92c9d2cf094248d5b6b63f893628e..5088f4347401fda2ebc7713f4d5ea43cf60ea5c3 100644 --- a/src/components/Challenge/ChallengeCard.tsx +++ b/src/components/Challenge/ChallengeCard.tsx @@ -1,12 +1,12 @@ import { UserChallengeState } from 'enum/userChallenge.enum' import { UserChallenge } from 'models' import React from 'react' +import './challengeCard.scss' import ChallengeCardDone from './ChallengeCardDone' +import ChallengeCardLast from './ChallengeCardLast' import ChallengeCardLocked from './ChallengeCardLocked' import ChallengeCardOnGoing from './ChallengeCardOnGoing' import ChallengeCardUnlocked from './ChallengeCardUnlocked' -import './challengeCard.scss' -import ChallengeCardLast from './ChallengeCardLast' interface ChallengeCardProps { userChallenge?: UserChallenge @@ -14,7 +14,7 @@ interface ChallengeCardProps { index: number cardWidth: number cardHeight: number - isChallengeCardLast: boolean + isChallengeCardLast?: boolean moveToSlide: (slideIndex: number) => void } @@ -24,7 +24,7 @@ const ChallengeCard: React.FC<ChallengeCardProps> = ({ index, cardWidth, cardHeight, - isChallengeCardLast, + isChallengeCardLast = false, moveToSlide, }: ChallengeCardProps) => { const renderCard = (userChallenge: UserChallenge | undefined) => { diff --git a/src/components/Challenge/ChallengeCardLast.spec.tsx b/src/components/Challenge/ChallengeCardLast.spec.tsx index 0a304978c8e1a5527c6aef4cea4956e1ccba3043..b9b4cee801ba40f5a8014e7f04d391e71d86cf5d 100644 --- a/src/components/Challenge/ChallengeCardLast.spec.tsx +++ b/src/components/Challenge/ChallengeCardLast.spec.tsx @@ -1,9 +1,9 @@ -import React from 'react' import { mount } from 'enzyme' -import ChallengeCardLast from './ChallengeCardLast' +import React from 'react' import { Provider } from 'react-redux' import configureStore from 'redux-mock-store' import { globalStateData } from '../../../tests/__mocks__/globalStateData.mock' +import ChallengeCardLast from './ChallengeCardLast' // Value coming from jest.config declare let __SAU_IDEA_DIRECT_LINK__: string diff --git a/src/components/Challenge/ChallengeCardLocked.spec.tsx b/src/components/Challenge/ChallengeCardLocked.spec.tsx index 80236b17128106e6182305ff54c56fc882de0776..a3d3f4d67acf4f9a1c9f117be6444c18ceb95e43 100644 --- a/src/components/Challenge/ChallengeCardLocked.spec.tsx +++ b/src/components/Challenge/ChallengeCardLocked.spec.tsx @@ -1,7 +1,7 @@ -import React from 'react' import { shallow } from 'enzyme' -import ChallengeCardLocked from './ChallengeCardLocked' +import React from 'react' import { userChallengeData } from '../../../tests/__mocks__/userChallengeData.mock' +import ChallengeCardLocked from './ChallengeCardLocked' jest.mock('cozy-ui/transpiled/react/I18n', () => { return { diff --git a/src/components/Challenge/ChallengeCardLocked.tsx b/src/components/Challenge/ChallengeCardLocked.tsx index 980beac580f7ef4b6425b2c9dd910293c63685ff..6624aae9e1b3ff4bdb2380b052ab94320ec88208 100644 --- a/src/components/Challenge/ChallengeCardLocked.tsx +++ b/src/components/Challenge/ChallengeCardLocked.tsx @@ -1,10 +1,10 @@ -import React from 'react' -import './challengeCardLocked.scss' -import { UserChallenge } from 'models' -import StyledIcon from 'components/CommonKit/Icon/StyledIcon' import challengeLockedIcon from 'assets/icons/visu/challenge/challengeLocked.svg' +import StyledIcon from 'components/CommonKit/Icon/StyledIcon' import { useI18n } from 'cozy-ui/transpiled/react/I18n' +import { UserChallenge } from 'models' +import React from 'react' import { getChallengeTitleWithLineReturn } from 'utils/utils' +import './challengeCardLocked.scss' interface ChallengeCardLockedProps { userChallenge: UserChallenge diff --git a/src/components/Challenge/ChallengeCardOnGoing.tsx b/src/components/Challenge/ChallengeCardOnGoing.tsx index be9eb1452d2e10d288d0d6c459a9b5725c31510f..6fd07442333c2af42f1dfdbea61e479f6ee55560 100644 --- a/src/components/Challenge/ChallengeCardOnGoing.tsx +++ b/src/components/Challenge/ChallengeCardOnGoing.tsx @@ -15,11 +15,11 @@ import { UserDuelState } from 'enum/userDuel.enum' import { UserExplorationState } from 'enum/userExploration.enum' import { UserQuizState } from 'enum/userQuiz.enum' import { UserChallenge } from 'models' -import React, { useCallback, useEffect, useState } from 'react' +import React, { Dispatch, useCallback, useEffect, useState } from 'react' import { useDispatch, useSelector } from 'react-redux' import { useNavigate } from 'react-router-dom' import ChallengeService from 'services/challenge.service' -import { AppStore } from 'store' +import { AppActionsTypes, AppStore } from 'store' import { updateUserChallengeList } from 'store/challenge/challenge.actions' import { getChallengeTitleWithLineReturn, importIconById } from 'utils/utils' import './challengeCardOnGoing.scss' @@ -34,11 +34,11 @@ const ChallengeCardOnGoing: React.FC<ChallengeCardOnGoingProps> = ({ }: ChallengeCardOnGoingProps) => { const client: Client = useClient() const { t } = useI18n() - const dispatch = useDispatch() + const dispatch = useDispatch<Dispatch<AppActionsTypes>>() const navigate = useNavigate() const [isOneFluidUp, setIsOneFluidUp] = useState<boolean>(true) const [challengeIcon, setChallengeIcon] = useState<string>(defaultIcon) - const [isDone, setisDone] = useState<boolean>(false) + const [isDone, setIsDone] = useState<boolean>(false) const [isLoading, setIsLoading] = useState<boolean>(false) const { challenge: { currentDataload }, @@ -113,7 +113,7 @@ const ChallengeCardOnGoing: React.FC<ChallengeCardOnGoingProps> = ({ currentDataload ) if (subscribed) { - setisDone(isChallengeDone.isDone) + setIsDone(isChallengeDone.isDone) } } const unlockDuel = async () => { diff --git a/src/components/Challenge/ChallengeCardUnlocked.spec.tsx b/src/components/Challenge/ChallengeCardUnlocked.spec.tsx index 3a8dcbb186ec5b0930ac94e722e45bae3d847810..d705c58d051219aff5aecefd1eb41bc1e62b1409 100644 --- a/src/components/Challenge/ChallengeCardUnlocked.spec.tsx +++ b/src/components/Challenge/ChallengeCardUnlocked.spec.tsx @@ -1,8 +1,10 @@ +import defaultIcon from 'assets/icons/visu/challenge/challengeLocked.svg' import { FluidType } from 'enum/fluid.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 { globalStateData } from '../../../tests/__mocks__/globalStateData.mock' import { userChallengeData } from '../../../tests/__mocks__/userChallengeData.mock' import ChallengeCardUnlocked from './ChallengeCardUnlocked' @@ -26,13 +28,16 @@ jest.mock('services/challenge.service', () => { } }) }) -const mockImportIconById = jest.fn() +const mockImportIconById = jest.fn(() => defaultIcon) jest.mock('utils/utils', () => { return { importIconById: jest.fn(() => mockImportIconById), getChallengeTitleWithLineReturn: jest.fn(() => 'Challenge 1'), } }) +jest.mock('services/usageEvent.service') +const mockAddEvent = jest.fn() +UsageEventService.addEvent = mockAddEvent const mockStore = configureStore([]) diff --git a/src/components/Challenge/ChallengeCardUnlocked.tsx b/src/components/Challenge/ChallengeCardUnlocked.tsx index 60603710c92b10e56596abbe4ef31e78dcf017fe..68cfcd89f0dfbedb7bf825ba236900cf0531ecf2 100644 --- a/src/components/Challenge/ChallengeCardUnlocked.tsx +++ b/src/components/Challenge/ChallengeCardUnlocked.tsx @@ -6,11 +6,11 @@ import { useI18n } from 'cozy-ui/transpiled/react/I18n' import { FluidState } from 'enum/fluid.enum' import { UsageEventType } from 'enum/usageEvent.enum' import { UserChallenge } from 'models' -import React, { useCallback, useEffect, useState } from 'react' +import React, { Dispatch, useCallback, useEffect, useState } from 'react' import { useDispatch, useSelector } from 'react-redux' import ChallengeService from 'services/challenge.service' import UsageEventService from 'services/usageEvent.service' -import { AppStore } from 'store' +import { AppActionsTypes, AppStore } from 'store' import { updateUserChallengeList } from 'store/challenge/challenge.actions' import { getChallengeTitleWithLineReturn, importIconById } from 'utils/utils' import './challengeCardUnlocked.scss' @@ -23,12 +23,13 @@ const ChallengeCardUnlocked: React.FC<ChallengeCardUnlockedProps> = ({ userChallenge, }: ChallengeCardUnlockedProps) => { const client: Client = useClient() - const dispatch = useDispatch() + const dispatch = useDispatch<Dispatch<AppActionsTypes>>() const { t } = useI18n() const [openNoFluidModal, setopenNoFluidModal] = useState(false) - const { fluidTypes } = useSelector((state: AppStore) => state.ecolyo.global) - const { fluidStatus } = useSelector((state: AppStore) => state.ecolyo.global) + const { fluidTypes, fluidStatus } = useSelector( + (state: AppStore) => state.ecolyo.global + ) const [challengeIcon, setChallengeIcon] = useState(defaultIcon) let statusRequirementOk = false diff --git a/src/components/Challenge/ChallengeNoFluidModal.spec.tsx b/src/components/Challenge/ChallengeNoFluidModal.spec.tsx index ca1ba37a471045121bec1f1a9d1be1c60d5a0986..8e92291ead926ea84d3e21d875936e2f310ce18a 100644 --- a/src/components/Challenge/ChallengeNoFluidModal.spec.tsx +++ b/src/components/Challenge/ChallengeNoFluidModal.spec.tsx @@ -1,5 +1,5 @@ -import React from 'react' import { shallow } from 'enzyme' +import React from 'react' import ChallengeNoFluidModal from './ChallengeNoFluidModal' jest.mock('cozy-ui/transpiled/react/I18n', () => { diff --git a/src/components/Challenge/ChallengeNoFluidModal.tsx b/src/components/Challenge/ChallengeNoFluidModal.tsx index b9d5ff8cc8b6c48189cb9a1f2f6cbb305bc9cbed..9d9c0e9fc72aab0f6b80e2bb9a055fe3e1aa98ad 100644 --- a/src/components/Challenge/ChallengeNoFluidModal.tsx +++ b/src/components/Challenge/ChallengeNoFluidModal.tsx @@ -1,8 +1,8 @@ -import React from 'react' -import './challengeNoFluidModal.scss' -import { useI18n } from 'cozy-ui/transpiled/react/I18n' 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 './challengeNoFluidModal.scss' interface ChallengeNoFluidModalProps { open: boolean diff --git a/src/components/Challenge/ChallengeView.spec.tsx b/src/components/Challenge/ChallengeView.spec.tsx index 1e33a61329085affa7c19b006327cbb235a5dc19..69768b00c7885b39864b855b745c867689018fe5 100644 --- a/src/components/Challenge/ChallengeView.spec.tsx +++ b/src/components/Challenge/ChallengeView.spec.tsx @@ -1,13 +1,10 @@ -import React from 'react' +import ChallengeView from 'components/Challenge/ChallengeView' import { mount } from 'enzyme' import toJson from 'enzyme-to-json' -import ChallengeView from 'components/Challenge/ChallengeView' +import React from 'react' import * as reactRedux from 'react-redux' import { challengeStateDataFull } from '../../../tests/__mocks__/challengeStateData.mock' -import { - createMockStore, - mockInitialEcolyoState, -} from '../../../tests/__mocks__/store' +import { createMockEcolyoStore } from '../../../tests/__mocks__/store' const mockUseSelector = jest.spyOn(reactRedux, 'useSelector') @@ -26,13 +23,13 @@ jest.mock('components/Header/Header', () => 'mock-header') jest.mock('components/Content/Content', () => 'mock-content') jest.mock('components/Challenge/ChallengeCard', () => 'mock-challengecard') +// TODO unused ? const useSelectorSpy = jest.spyOn(reactRedux, 'useSelector') describe('ChallengeView component', () => { - // eslint-disable-next-line @typescript-eslint/no-explicit-any - let store: any + const store = createMockEcolyoStore() beforeEach(() => { - store = createMockStore(mockInitialEcolyoState) + store.clearActions() useSelectorSpy.mockClear() }) diff --git a/src/components/Challenge/ChallengeView.tsx b/src/components/Challenge/ChallengeView.tsx index 49a0ee304f46ef334935fa6504d92e0bc7b47314..5f00edbfd69ad12c5f183e2fa3cf82434253a0c3 100644 --- a/src/components/Challenge/ChallengeView.tsx +++ b/src/components/Challenge/ChallengeView.tsx @@ -1,6 +1,6 @@ import LeftArrowIcon from 'assets/icons/ico/left-arrow.svg' import RightArrowIcon from 'assets/icons/ico/right-arrow.svg' -import StyledIconbutton from 'components/CommonKit/IconButton/StyledIconButton' +import StyledIconButton from 'components/CommonKit/IconButton/StyledIconButton' import Content from 'components/Content/Content' import CozyBar from 'components/Header/CozyBar' import Header from 'components/Header/Header' @@ -20,16 +20,16 @@ const ChallengeView: React.FC = () => { ) const marginPx = 16 - const cardWitdh = + const cardWidth = window.outerWidth < 500 ? window.outerWidth - marginPx * 6 : 285 const cardHeight = window.outerHeight * 0.6 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 [index, setIndex] = useState<number>(0) + const [lastChallengeIndex, setLastChallengeIndex] = useState<number>(0) const [isLastDuelDone, setIsLastDuelDone] = useState<boolean>(false) - const [containerTranslation, setcontainerTranslation] = + const [containerTranslation, setContainerTranslation] = useState<number>(marginPx) const defineHeaderHeight = (height: number) => { setHeaderHeight(height) @@ -47,34 +47,34 @@ const ChallengeView: React.FC = () => { (isLastDuelDone && index < userChallengeList.length) ) { if (index === 0) - setcontainerTranslation( - (prev: number) => prev - cardWitdh - marginPx * 1.2 + setContainerTranslation( + (prev: number) => prev - cardWidth - marginPx * 1.2 ) else if (index >= 1) - setcontainerTranslation((prev: number) => prev - cardWitdh - marginPx) - else setcontainerTranslation((prev: number) => prev - cardWitdh) - setindex(prev => prev + 1) + setContainerTranslation((prev: number) => prev - cardWidth - marginPx) + else setContainerTranslation((prev: number) => prev - cardWidth) + setIndex(prev => prev + 1) } - }, [cardWitdh, index, userChallengeList.length]) + }, [cardWidth, index, userChallengeList.length]) const moveSliderLeft = useCallback(() => { if (index > 0) { if (index >= 1) - setcontainerTranslation((prev: number) => prev + cardWitdh + marginPx) - else setcontainerTranslation((prev: number) => prev + cardWitdh) - setindex(prev => prev - 1) + setContainerTranslation((prev: number) => prev + cardWidth + marginPx) + else setContainerTranslation((prev: number) => prev + cardWidth) + setIndex(prev => prev - 1) } if (index <= 1) { - setcontainerTranslation(marginPx) + setContainerTranslation(marginPx) } - }, [cardWitdh, index]) + }, [cardWidth, index]) const moveToSlide = useCallback( (slideIndex: number) => { - setcontainerTranslation(-slideIndex * (cardWitdh + marginPx) + marginPx) - setindex(slideIndex) + setContainerTranslation(-slideIndex * (cardWidth + marginPx) + marginPx) + setIndex(slideIndex) }, - [cardWitdh] + [cardWidth] ) // eslint-disable-next-line @typescript-eslint/no-explicit-any @@ -88,7 +88,7 @@ const ChallengeView: React.FC = () => { // if the swipe is too small and can be taken for a touch if (touchStart && touchEnd) { if (touchStart - touchEnd < 5 && -5 < touchStart - touchEnd) return - // Change the following value in order to change the swipe sensibilyy + // Change the following value in order to change the swipe sensibility if (touchStart - touchEnd > 75) { // If swipe left move slider right and add positive translation moveSliderRight() @@ -115,22 +115,22 @@ const ChallengeView: React.FC = () => { challenge.state === UserChallengeState.ONGOING || challenge.state === UserChallengeState.DUEL ) { - setlastChallengeIndex(i) + setLastChallengeIndex(i) if (lastChallengeIndex === 0) return else if (lastChallengeIndex === 1) { - setcontainerTranslation(0 - cardWitdh * lastChallengeIndex) + setContainerTranslation(0 - cardWidth * lastChallengeIndex) } else { - setcontainerTranslation( - 0 - cardWitdh * lastChallengeIndex - marginPx * 1.2 + setContainerTranslation( + 0 - cardWidth * lastChallengeIndex - marginPx * 1.2 ) } if (isLastDuelDone) { - setlastChallengeIndex(i + 1) + setLastChallengeIndex(i + 1) } - setindex(i) + setIndex(i) } }) - }, [userChallengeList, lastChallengeIndex, cardWitdh, isLastDuelDone]) + }, [userChallengeList, lastChallengeIndex, cardWidth, isLastDuelDone]) useEffect(() => { if ( @@ -167,13 +167,12 @@ const ChallengeView: React.FC = () => { > {userChallengeList.map((userChallenge, i) => ( <ChallengeCard - key={i} + key={userChallenge.id} userChallenge={userChallenge} indexSlider={index} index={i} - cardWidth={cardWitdh} + cardWidth={cardWidth} cardHeight={cardHeight} - isChallengeCardLast={false} moveToSlide={moveToSlide} /> ))} @@ -182,7 +181,7 @@ const ChallengeView: React.FC = () => { <ChallengeCard indexSlider={index} index={5} - cardWidth={cardWitdh} + cardWidth={cardWidth} cardHeight={cardHeight} isChallengeCardLast={true} moveToSlide={moveToSlide} @@ -191,13 +190,13 @@ const ChallengeView: React.FC = () => { </div> </div> <div className="sliderButtons"> - <StyledIconbutton + <StyledIconButton onClick={moveSliderLeft} icon={LeftArrowIcon} sized={16} aria-label={t('challenge.accessibility.button_slider_previous')} /> - <StyledIconbutton + <StyledIconButton onClick={moveSliderRight} icon={RightArrowIcon} sized={16} diff --git a/src/components/Challenge/StarsContainer.tsx b/src/components/Challenge/StarsContainer.tsx index 47ce2ce2b5535aaef9a2251b151d6232058d011e..ab6c67731bbecc39571a18fb5951ae42235487f9 100644 --- a/src/components/Challenge/StarsContainer.tsx +++ b/src/components/Challenge/StarsContainer.tsx @@ -1,7 +1,7 @@ -import React, { useEffect, useState } from 'react' -import StyledIcon from 'components/CommonKit/Icon/StyledIcon' import starIcon from 'assets/icons/visu/challenge/star.svg' import starFilled from 'assets/icons/visu/challenge/starFilled.svg' +import StyledIcon from 'components/CommonKit/Icon/StyledIcon' +import React from 'react' interface StarsContainerProps { result: number @@ -12,30 +12,16 @@ const StarsContainer: React.FC<StarsContainerProps> = ({ result, isQuizBegin, }: StarsContainerProps) => { - const [elements] = useState<string[]>([]) - - useEffect(() => { - const renderStars = () => { - // To be removed when action and explorations will be done - if (result === 5) { - elements.splice(0, elements.length) - } - for (let i = 0; i < 5; i++) { - if (i < result) elements.push(starFilled) - else if (i >= result) elements.push(starIcon) - } - } - renderStars() - }, [result, elements]) + const maxStars = [1, 2, 3, 4, 5] return ( <div className="stars"> - {elements.map((star, i) => { + {maxStars.map(star => { return ( <StyledIcon - key={i} + key={star} className="star" - icon={star} + icon={result >= star ? starFilled : starIcon} size={isQuizBegin ? 25 : 15} /> ) diff --git a/src/components/Challenge/__snapshots__/ChallengeView.spec.tsx.snap b/src/components/Challenge/__snapshots__/ChallengeView.spec.tsx.snap index 487d01b855f6718e93bb1a75d57085cf2033d785..3ddca6ea025581559a79db5eacfab2fa73695af8 100644 --- a/src/components/Challenge/__snapshots__/ChallengeView.spec.tsx.snap +++ b/src/components/Challenge/__snapshots__/ChallengeView.spec.tsx.snap @@ -47,8 +47,7 @@ exports[`ChallengeView component should be rendered correctly 1`] = ` cardWidth={285} index={0} indexSlider={3} - isChallengeCardLast={false} - key="0" + key="CHALLENGE0001" moveToSlide={[Function]} userChallenge={ Object { @@ -199,8 +198,7 @@ exports[`ChallengeView component should be rendered correctly 1`] = ` cardWidth={285} index={1} indexSlider={3} - isChallengeCardLast={false} - key="1" + key="CHALLENGE0002" moveToSlide={[Function]} userChallenge={ Object { @@ -351,8 +349,7 @@ exports[`ChallengeView component should be rendered correctly 1`] = ` cardWidth={285} index={2} indexSlider={3} - isChallengeCardLast={false} - key="2" + key="CHALLENGE0003" moveToSlide={[Function]} userChallenge={ Object { @@ -503,8 +500,7 @@ exports[`ChallengeView component should be rendered correctly 1`] = ` cardWidth={285} index={3} indexSlider={3} - isChallengeCardLast={false} - key="3" + key="CHALLENGE0004" moveToSlide={[Function]} userChallenge={ Object { @@ -655,8 +651,7 @@ exports[`ChallengeView component should be rendered correctly 1`] = ` cardWidth={285} index={4} indexSlider={3} - isChallengeCardLast={false} - key="4" + key="CHALLENGE0005" moveToSlide={[Function]} userChallenge={ Object { @@ -807,8 +802,7 @@ exports[`ChallengeView component should be rendered correctly 1`] = ` cardWidth={285} index={5} indexSlider={3} - isChallengeCardLast={false} - key="5" + key="CHALLENGE0006" moveToSlide={[Function]} userChallenge={ Object { diff --git a/src/components/Challenge/challengeNoFluidModal.scss b/src/components/Challenge/challengeNoFluidModal.scss index 6afe50b68b61a88da53b51ce27d2328a17f438c1..e956f006f55cc12f10ff93987397e9ec987738fd 100644 --- a/src/components/Challenge/challengeNoFluidModal.scss +++ b/src/components/Challenge/challengeNoFluidModal.scss @@ -36,4 +36,4 @@ #accessibility-title { display: none; -} \ No newline at end of file +} diff --git a/src/components/Charts/AxisBottom.spec.tsx b/src/components/Charts/AxisBottom.spec.tsx index 871824baa987cc934fd9f2a6cbb0f883822ee7f0..e6e5a7f13c77b92e4eaa707dc522ccf9b2b0dbd4 100644 --- a/src/components/Charts/AxisBottom.spec.tsx +++ b/src/components/Charts/AxisBottom.spec.tsx @@ -1,16 +1,13 @@ -import React from 'react' -import AxisBottom from './AxisBottom' -import { mount } from 'enzyme' -import { Provider } from 'react-redux' -import * as reactRedux from 'react-redux' -import { - createMockStore, - mockInitialEcolyoState, -} from '../../../tests/__mocks__/store' -import { graphData } from '../../../tests/__mocks__/datachartData.mock' +import { scaleBand, ScaleBand } from 'd3-scale' import { TimeStep } from 'enum/timeStep.enum' +import { mount } from 'enzyme' import { DateTime } from 'luxon' -import { scaleBand, ScaleBand } from 'd3-scale' +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 AxisBottom from './AxisBottom' const mockXScale: ScaleBand<string> = scaleBand() .domain(['0', '10']) @@ -29,10 +26,9 @@ const useSelectorSpy = jest.spyOn(reactRedux, 'useSelector') const useDispatchSpy = jest.spyOn(reactRedux, 'useDispatch') describe('AxisBottom component test', () => { - // eslint-disable-next-line @typescript-eslint/no-explicit-any - let store: any + const store = createMockEcolyoStore() beforeEach(() => { - store = createMockStore(mockInitialEcolyoState) + store.clearActions() useDispatchSpy.mockClear() }) diff --git a/src/components/Charts/AxisBottom.tsx b/src/components/Charts/AxisBottom.tsx index 9302b9cd943a9abe3184bc380c06914348b28b7e..4ad15f3dc452e010bc3c62f4926141ef49146797 100644 --- a/src/components/Charts/AxisBottom.tsx +++ b/src/components/Charts/AxisBottom.tsx @@ -1,13 +1,12 @@ -import React from 'react' -import { useSelector } from 'react-redux' -import { AppStore } from 'store' -import { DateTime } from 'luxon' import { ScaleBand } from 'd3-scale' - import { TimeStep } from 'enum/timeStep.enum' +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 { capitalize } from 'lodash' +import { AppStore } from 'store' interface TextTypeProps { index: number diff --git a/src/components/Charts/AxisRight.spec.tsx b/src/components/Charts/AxisRight.spec.tsx index bfa9f22178273b13902c0c0cf78fe51310d8644f..668eb4e85347ac357817fadbc1188848c7f8ed74 100644 --- a/src/components/Charts/AxisRight.spec.tsx +++ b/src/components/Charts/AxisRight.spec.tsx @@ -1,7 +1,7 @@ -import React from 'react' import { scaleLinear } from 'd3' import { FluidType } from 'enum/fluid.enum' import { mount } from 'enzyme' +import React from 'react' import AxisRight from './AxisRight' jest.mock('cozy-ui/transpiled/react/I18n', () => { diff --git a/src/components/Charts/AxisRight.tsx b/src/components/Charts/AxisRight.tsx index 18fc9e45fcdd2c985060cd31f7a6515e78beed38..7ba81a2e94c7a921985dd33332974c52b3d8fcfd 100644 --- a/src/components/Charts/AxisRight.tsx +++ b/src/components/Charts/AxisRight.tsx @@ -1,9 +1,9 @@ -import React, { useEffect, useRef } from 'react' import { useI18n } from 'cozy-ui/transpiled/react/I18n' -import { select, selectAll } from 'd3-selection' import { axisRight } from 'd3-axis' import { ScaleLinear } from 'd3-scale' +import { select, selectAll } from 'd3-selection' import { FluidType } from 'enum/fluid.enum' +import React, { useEffect, useRef } from 'react' interface AxisRightProps { yScale: ScaleLinear<number, number> @@ -37,7 +37,7 @@ const AxisRight = ({ .tickSize(-width) .tickSizeOuter(0) .tickFormat(d => - d >= 1000 && fluidStyle !== 'MULTIFLUID' + Number(d) >= 1000 && fluidStyle !== 'MULTIFLUID' ? typeof d === 'number' ? `${d / 1000} ${t('FLUID.' + fluidStyle + '.MEGAUNIT')}` : `${d.valueOf() / 1000} ${t( diff --git a/src/components/Charts/Bar.spec.tsx b/src/components/Charts/Bar.spec.tsx index 84c59fb729c26951e627bb8e16e6abb5d99494f6..6880d2f3940f15a12b246c4095b613acc581b038 100644 --- a/src/components/Charts/Bar.spec.tsx +++ b/src/components/Charts/Bar.spec.tsx @@ -1,18 +1,15 @@ -import React from 'react' +import { scaleBand, ScaleBand, scaleLinear } from 'd3' +import { FluidType } from 'enum/fluid.enum' +import { TimeStep } from 'enum/timeStep.enum' import { mount } from 'enzyme' -import { Provider } from 'react-redux' +import { DateTime } from 'luxon' +import React from 'react' import * as reactRedux from 'react-redux' -import { - createMockStore, - mockInitialEcolyoState, -} from '../../../tests/__mocks__/store' +import { Provider } from 'react-redux' import * as chartActions from 'store/chart/chart.actions' +import { graphData } from '../../../tests/__mocks__/chartData.mock' +import { createMockEcolyoStore } from '../../../tests/__mocks__/store' import Bar from './Bar' -import { FluidType } from 'enum/fluid.enum' -import { TimeStep } from 'enum/timeStep.enum' -import { graphData } from '../../../tests/__mocks__/datachartData.mock' -import { DateTime } from 'luxon' -import { scaleBand, ScaleBand, scaleLinear } from 'd3' const mockXScale: ScaleBand<string> = scaleBand() .domain( @@ -46,10 +43,9 @@ const setCurrentDatachartIndexSpy = jest.spyOn( ) describe('Bar component test', () => { - // eslint-disable-next-line @typescript-eslint/no-explicit-any - let store: any + const store = createMockEcolyoStore() beforeEach(() => { - store = createMockStore(mockInitialEcolyoState) + store.clearActions() useDispatchSpy.mockClear() setSelectedDateSpy.mockClear() setCurrentDatachartIndexSpy.mockClear() diff --git a/src/components/Charts/Bar.tsx b/src/components/Charts/Bar.tsx index 6cb7877b4a96217d05f9e48d0e1d456f81d5809a..06ff85fdb1968737121662015cb7bb0cbd3e6e4f 100644 --- a/src/components/Charts/Bar.tsx +++ b/src/components/Charts/Bar.tsx @@ -4,10 +4,10 @@ import { FluidType } from 'enum/fluid.enum' import { TimeStep } from 'enum/timeStep.enum' import { DateTime } from 'luxon' import { Dataload } from 'models' -import React, { useEffect, useState } from 'react' +import React, { Dispatch, useEffect, useState } from 'react' import { useDispatch, useSelector } from 'react-redux' import DateChartService from 'services/dateChart.service' -import { AppStore } from 'store' +import { AppActionsTypes, AppStore } from 'store' import { setCurrentDatachartIndex, setSelectedDate, @@ -44,7 +44,7 @@ const Bar = ({ isMultiMissingFluid, weekdays, }: BarProps) => { - const dispatch = useDispatch() + const dispatch = useDispatch<Dispatch<AppActionsTypes>>() const { selectedDate } = useSelector((state: AppStore) => state.ecolyo.chart) const [clicked, setClicked] = useState(false) const [animationEnded, setAnimationEnded] = useState(false) diff --git a/src/components/Charts/BarChart.tsx b/src/components/Charts/BarChart.tsx index e47408ad23520e872360a122ddf180e1e251e1d2..da37a2d71654b8fc4250b80e378688fd6d1c6f3c 100644 --- a/src/components/Charts/BarChart.tsx +++ b/src/components/Charts/BarChart.tsx @@ -1,15 +1,13 @@ -import React from 'react' +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 { DateTime } from 'luxon' - +import { DataloadState } from 'enum/dataload.enum' import { FluidType } from 'enum/fluid.enum' import { TimeStep } from 'enum/timeStep.enum' +import { DateTime } from 'luxon' import { Datachart } from 'models' - -import Bar from 'components/Charts/Bar' -import AxisBottom from 'components/Charts/AxisBottom' -import AxisRight from 'components/Charts/AxisRight' -import { DataloadState } from 'enum/dataload.enum' +import React from 'react' export interface BarChartProps { chartData: Datachart @@ -95,7 +93,7 @@ const BarChart: React.FC<BarChartProps> = ({ index={index} dataload={d} compareDataload={ - chartData.comparisonData && chartData.comparisonData[index] + chartData.comparisonData?.[index] ? chartData.comparisonData[index] : null } diff --git a/src/components/Charts/UncomingBar.tsx b/src/components/Charts/UncomingBar.tsx index e669a5d07332862e775fade1c031464585c7361b..9e11a1b3af7dfba3954ebae2ce6267db42c0d186 100644 --- a/src/components/Charts/UncomingBar.tsx +++ b/src/components/Charts/UncomingBar.tsx @@ -1,8 +1,8 @@ -import React, { useState } from 'react' import { ScaleBand, ScaleLinear } from 'd3-scale' -import { DateTime } from 'luxon' import { detect } from 'detect-browser' +import { DateTime } from 'luxon' import { Dataload } from 'models' +import React, { useState } from 'react' interface BarProps { index: number diff --git a/src/components/CommonKit/Card/StyledBorderCard.spec.tsx b/src/components/CommonKit/Card/StyledBorderCard.spec.tsx index c3dfb9703695d784cb91dbe93d4a03abff289095..38d535360f8a7667234e7fe9980bec0073e1c0a2 100644 --- a/src/components/CommonKit/Card/StyledBorderCard.spec.tsx +++ b/src/components/CommonKit/Card/StyledBorderCard.spec.tsx @@ -1,5 +1,5 @@ -import React from 'react' import { mount } from 'enzyme' +import React from 'react' import StyledBorderCard from './StyledBorderCard' describe('StyledBorderCard component test', () => { diff --git a/src/components/CommonKit/Card/StyledBorderCard.tsx b/src/components/CommonKit/Card/StyledBorderCard.tsx index a3f76a0ceed0d1f76cb95adcf6df7c01383b3426..7f9a6a34dff44c65ac484dc88cc347521341c886 100644 --- a/src/components/CommonKit/Card/StyledBorderCard.tsx +++ b/src/components/CommonKit/Card/StyledBorderCard.tsx @@ -1,9 +1,9 @@ -import React from 'react' import CardActionArea, { CardActionAreaProps, } from '@material-ui/core/CardActionArea' import CardContent from '@material-ui/core/CardContent' import { withStyles } from '@material-ui/core/styles' +import React from 'react' const CardBase = withStyles({ root: { @@ -14,13 +14,11 @@ const CardBase = withStyles({ margin: '1.25rem 0', cursor: 'default', }, -})(CardActionArea) +})(CardActionArea) as React.FC<StyledBorderCardProps> type StyledBorderCardProps = CardActionAreaProps -const StyledBorderCard: React.ComponentType<StyledBorderCardProps> = ({ - ...props -}: StyledBorderCardProps) => { +const StyledBorderCard = ({ ...props }: StyledBorderCardProps) => { return ( <CardBase {...props}> <CardContent>{props.children}</CardContent> diff --git a/src/components/CommonKit/Card/StyledCard.spec.tsx b/src/components/CommonKit/Card/StyledCard.spec.tsx index 5aebe397eed648346dea2183d75d1eb42a1130b1..e302e4f5c08be287a9fce2982230e7e25cd841cc 100644 --- a/src/components/CommonKit/Card/StyledCard.spec.tsx +++ b/src/components/CommonKit/Card/StyledCard.spec.tsx @@ -1,10 +1,10 @@ -import React from 'react' +import { FluidType } from 'enum/fluid.enum' import { mount } from 'enzyme' +import React from 'react' import StyledCard from './StyledCard' -import { FluidType } from 'enum/fluid.enum' describe('StyledCard component test', () => { - it('should render correctly Electricty StyledCard', () => { + it('should render correctly Electricity StyledCard', () => { const wrapper = mount(<StyledCard fluidType={FluidType.ELECTRICITY} />) expect(wrapper.getElement()).toMatchSnapshot() }) diff --git a/src/components/CommonKit/Card/StyledCard.tsx b/src/components/CommonKit/Card/StyledCard.tsx index d6890efa4474943a5a98fa95ce977035dbc6e5cc..c6a10c174f8a963203718d9ca263be35aefab5d5 100644 --- a/src/components/CommonKit/Card/StyledCard.tsx +++ b/src/components/CommonKit/Card/StyledCard.tsx @@ -1,10 +1,10 @@ -import React, { ReactNode } from 'react' import CardActionArea, { CardActionAreaProps, } 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 React, { ReactNode } from 'react' const CardBase = withStyles({ root: { @@ -14,36 +14,37 @@ const CardBase = withStyles({ borderRadius: '4px', margin: '10px 0px 20px 0px', }, -})(CardActionArea) +})(CardActionArea) as React.FC<StyledCardProps> const CardElec = withStyles({ root: { border: '1px solid var(--elecColor40)', }, -})(CardBase) +})(CardBase) as React.FC<StyledCardProps> const CardWater = withStyles({ root: { border: '1px solid var(--waterColor40)', }, -})(CardBase) +})(CardBase) as React.FC<StyledCardProps> const CardGas = withStyles({ root: { border: '1px solid var(--gasColor40)', }, -})(CardBase) +})(CardBase) as React.FC<StyledCardProps> + const CardMulti = withStyles({ root: { border: '1px solid var( --greyDark)', }, -})(CardBase) +})(CardBase) as React.FC<StyledCardProps> const CardContentBase = withStyles({ root: { color: 'white', }, -})(CardContent) +})(CardContent) as React.FC<StyledCardProps> interface StyledCardProps extends CardActionAreaProps { fluidType?: FluidType @@ -56,10 +57,7 @@ const GenerateContentCard = ( return <CardContentBase>{children}</CardContentBase> } -const StyledCard: React.ComponentType<StyledCardProps> = ({ - fluidType, - ...props -}: StyledCardProps) => { +const StyledCard = ({ fluidType, ...props }: StyledCardProps) => { switch (fluidType) { case FluidType.ELECTRICITY: return ( diff --git a/src/components/CommonKit/Card/StyledEcogestureCard.spec.tsx b/src/components/CommonKit/Card/StyledEcogestureCard.spec.tsx index 4bf07d365abfe830b7aba95841389a73b1fb2d81..6b6aac0e0bf49307d28d643ecc56cae8bd037e98 100644 --- a/src/components/CommonKit/Card/StyledEcogestureCard.spec.tsx +++ b/src/components/CommonKit/Card/StyledEcogestureCard.spec.tsx @@ -1,5 +1,5 @@ -import React from 'react' import { mount } from 'enzyme' +import React from 'react' import StyledEcogestureCard from './StyledEcogestureCard' describe('StyledEcogestureCard component test', () => { @@ -8,7 +8,7 @@ describe('StyledEcogestureCard component test', () => { expect(wrapper.getElement()).toMatchSnapshot() }) - it('should render correclty new ecogesture StyledEcogestureCard with newEcogesture', () => { + it('should render correctly new ecogesture StyledEcogestureCard with newEcogesture', () => { const wrapper = mount(<StyledEcogestureCard newEcogesture={true} />) expect(wrapper.getElement()).toMatchSnapshot() }) diff --git a/src/components/CommonKit/Card/StyledEcogestureCard.tsx b/src/components/CommonKit/Card/StyledEcogestureCard.tsx index 9f2e6e5dbd8bf786d829691cdca6dc01e7d869bb..08fd623762bc340a6e9056a7cd8754570f03967f 100644 --- a/src/components/CommonKit/Card/StyledEcogestureCard.tsx +++ b/src/components/CommonKit/Card/StyledEcogestureCard.tsx @@ -1,9 +1,9 @@ -import React, { ReactNode } from 'react' import CardActionArea, { CardActionAreaProps, } from '@material-ui/core/CardActionArea' import CardContent from '@material-ui/core/CardContent' import { withStyles } from '@material-ui/core/styles' +import React, { ReactNode } from 'react' const CardBase = withStyles({ root: { @@ -16,7 +16,7 @@ const CardBase = withStyles({ padding: '0.5rem 1rem', minHeight: '72px', }, -})(CardActionArea) +})(CardActionArea) as React.FC<StyledEcogestureCardProps> const CardNew = withStyles({ '@keyframes glowAnimation': { @@ -31,7 +31,7 @@ const CardNew = withStyles({ height: '100%', padding: 0, }, -})(CardBase) +})(CardBase) as React.FC<StyledEcogestureCardProps> const CardBlueBorderContentBase = withStyles({ root: { @@ -39,7 +39,8 @@ const CardBlueBorderContentBase = withStyles({ height: '100%', padding: 0, }, -})(CardBase) +})(CardBase) as React.FC<StyledEcogestureCardProps> + const CardChallengeBase = withStyles({ root: { height: '100%', @@ -48,7 +49,7 @@ const CardChallengeBase = withStyles({ alignItems: 'center', justifyContent: 'center', }, -})(CardContent) +})(CardContent) as React.FC<StyledEcogestureCardProps> const CardContentBase = withStyles({ root: { @@ -56,7 +57,7 @@ const CardContentBase = withStyles({ height: '100%', padding: 0, }, -})(CardContent) +})(CardContent) as React.FC<StyledEcogestureCardProps> interface StyledEcogestureCardProps extends CardActionAreaProps { border?: boolean @@ -67,7 +68,7 @@ const GenerateContentCard = (children: ReactNode): React.ReactFragment => { return <CardChallengeBase>{children}</CardChallengeBase> } -const StyledEcogestureCard: React.ComponentType<StyledEcogestureCardProps> = ({ +const StyledEcogestureCard = ({ border, newEcogesture, ...props diff --git a/src/components/CommonKit/Card/StyledIconCard.spec.tsx b/src/components/CommonKit/Card/StyledIconCard.spec.tsx index e8d742296b8e6ad23d77b006e59dae91c437089e..77b94a6844c58f58a39ce4f33d09a3cb42521a04 100644 --- a/src/components/CommonKit/Card/StyledIconCard.spec.tsx +++ b/src/components/CommonKit/Card/StyledIconCard.spec.tsx @@ -1,7 +1,7 @@ -import React from 'react' +import { FluidType } from 'enum/fluid.enum' import { mount } from 'enzyme' +import React from 'react' import StyledIconCard from './StyledIconCard' -import { FluidType } from 'enum/fluid.enum' describe('StyledIconCard component test', () => { it('it should render correctly StyledIconCard', () => { diff --git a/src/components/CommonKit/Card/StyledIconCard.tsx b/src/components/CommonKit/Card/StyledIconCard.tsx index b5b087ad3f39ba87e7758706c6581cb02e6216a4..58e6b8d4f09fdad56642fb04e1059b0a5ad569af 100644 --- a/src/components/CommonKit/Card/StyledIconCard.tsx +++ b/src/components/CommonKit/Card/StyledIconCard.tsx @@ -1,12 +1,12 @@ -import React, { ReactNode } from 'react' import CardActionArea, { CardActionAreaProps, } from '@material-ui/core/CardActionArea' import CardContent from '@material-ui/core/CardContent' +import Grid from '@material-ui/core/Grid' import { withStyles } from '@material-ui/core/styles' import { FluidType } from 'enum/fluid.enum' +import React, { ReactNode } from 'react' import { getPicto } from 'utils/picto' -import Grid from '@material-ui/core/Grid' import StyledIcon from '../Icon/StyledIcon' const CardBase = withStyles({ @@ -19,34 +19,34 @@ const CardBase = withStyles({ display: 'inline', margin: '0', }, -})(CardActionArea) +})(CardActionArea) as React.FC<StyledIconCardProps> const CardElec = withStyles({ root: { border: '1px solid var(--elecColor40)', }, -})(CardBase) +})(CardBase) as React.FC<StyledIconCardProps> const CardWater = withStyles({ root: { border: '1px solid var(--waterColor40)', }, -})(CardBase) +})(CardBase) as React.FC<StyledIconCardProps> const CardGas = withStyles({ root: { border: '1px solid var(--gasColor40)', }, -})(CardBase) +})(CardBase) as React.FC<StyledIconCardProps> const CardContentBase = withStyles({ root: { color: 'white', }, -})(CardContent) +})(CardContent) as React.FC<StyledIconCardProps> interface StyledIconCardProps extends CardActionAreaProps { - fluidType: FluidType + fluidType?: FluidType } const GenerateContentCard = ( @@ -73,10 +73,7 @@ const GenerateContentCard = ( ) } -const StyledIconCard: React.ComponentType<StyledIconCardProps> = ({ - fluidType, - ...props -}: StyledIconCardProps) => { +const StyledIconCard = ({ fluidType, ...props }: StyledIconCardProps) => { switch (fluidType) { case FluidType.ELECTRICITY: return ( diff --git a/src/components/CommonKit/Card/__snapshots__/StyledCard.spec.tsx.snap b/src/components/CommonKit/Card/__snapshots__/StyledCard.spec.tsx.snap index 5d0d39416eca9070294430421b7e184ce602b89c..52bb45d8bd676b5fb217f3ea9195340af328efaf 100644 --- a/src/components/CommonKit/Card/__snapshots__/StyledCard.spec.tsx.snap +++ b/src/components/CommonKit/Card/__snapshots__/StyledCard.spec.tsx.snap @@ -1,6 +1,6 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[`StyledCard component test should render correctly Electricty StyledCard 1`] = ` +exports[`StyledCard component test should render correctly Electricity StyledCard 1`] = ` <StyledCard fluidType={0} /> diff --git a/src/components/CommonKit/Card/__snapshots__/StyledEcogestureCard.spec.tsx.snap b/src/components/CommonKit/Card/__snapshots__/StyledEcogestureCard.spec.tsx.snap index cde7efd3f5d6eae37c40d7dd902ff1d7878a051d..a370edbdadc7988390d0c53c7a4c0defcd6ecde1 100644 --- a/src/components/CommonKit/Card/__snapshots__/StyledEcogestureCard.spec.tsx.snap +++ b/src/components/CommonKit/Card/__snapshots__/StyledEcogestureCard.spec.tsx.snap @@ -1,11 +1,5 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[`StyledEcogestureCard component test should render correclty new ecogesture StyledEcogestureCard with newEcogesture 1`] = ` -<StyledEcogestureCard - newEcogesture={true} -/> -`; - exports[`StyledEcogestureCard component test should render correctly border StyledEcogestureCard 1`] = `<StyledEcogestureCard />`; exports[`StyledEcogestureCard component test should render correctly border StyledEcogestureCard with border 1`] = ` @@ -13,3 +7,9 @@ exports[`StyledEcogestureCard component test should render correctly border Styl border={true} /> `; + +exports[`StyledEcogestureCard component test should render correctly new ecogesture StyledEcogestureCard with newEcogesture 1`] = ` +<StyledEcogestureCard + newEcogesture={true} +/> +`; diff --git a/src/components/CommonKit/IconButton/StyledIconBorderedButton.spec.tsx b/src/components/CommonKit/IconButton/StyledIconBorderedButton.spec.tsx index e6dd16f77facd44685da0743503f8994661458a7..1890bead1d5f57d01f15714b25869d263e9076d6 100644 --- a/src/components/CommonKit/IconButton/StyledIconBorderedButton.spec.tsx +++ b/src/components/CommonKit/IconButton/StyledIconBorderedButton.spec.tsx @@ -1,5 +1,5 @@ -import React from 'react' import { shallow } from 'enzyme' +import React from 'react' import StyledIconBorderedButton from './StyledIconBorderedButton' describe('StyledIconBorderedButton component test', () => { @@ -10,7 +10,7 @@ describe('StyledIconBorderedButton component test', () => { it('should render correctly UnselectedIconButtonBase ', () => { const wrapper = shallow( - <StyledIconBorderedButton icon={mockProps.icon} size={mockProps.size} /> + <StyledIconBorderedButton icon={mockProps.icon} sized={mockProps.size} /> ) expect(wrapper.getElement()).toMatchSnapshot() @@ -20,7 +20,7 @@ describe('StyledIconBorderedButton component test', () => { const wrapper = shallow( <StyledIconBorderedButton icon={mockProps.icon} - size={mockProps.size} + sized={mockProps.size} selected={true} /> ) diff --git a/src/components/CommonKit/IconButton/StyledIconBorderedButton.tsx b/src/components/CommonKit/IconButton/StyledIconBorderedButton.tsx index 6ec0e550b0fb042da39dd822eadf0feb0cf5385c..761d01d449469faa7f29240f6d60359af9235dc2 100644 --- a/src/components/CommonKit/IconButton/StyledIconBorderedButton.tsx +++ b/src/components/CommonKit/IconButton/StyledIconBorderedButton.tsx @@ -1,7 +1,7 @@ -import React from 'react' -import { withStyles } from '@material-ui/core/styles' import IconButton, { IconButtonProps } from '@material-ui/core/IconButton' +import { withStyles } from '@material-ui/core/styles' import StyledIconProps from 'components/CommonKit/Icon/StyledIcon' +import React from 'react' const IconButtonBase = withStyles({ root: { diff --git a/src/components/CommonKit/IconButton/StyledIconButton.spec.tsx b/src/components/CommonKit/IconButton/StyledIconButton.spec.tsx index 11546e02eea4a27a97e478845edf43c1d7ad0562..d621190f29c518c206db6daeae52808e1c6ffbcd 100644 --- a/src/components/CommonKit/IconButton/StyledIconButton.spec.tsx +++ b/src/components/CommonKit/IconButton/StyledIconButton.spec.tsx @@ -1,5 +1,5 @@ -import React from 'react' import { shallow } from 'enzyme' +import React from 'react' import StyledIconButton from './StyledIconButton' describe('StyledIconButton component test', () => { @@ -10,7 +10,7 @@ describe('StyledIconButton component test', () => { } const wrapper = shallow( - <StyledIconButton icon={mockProps.icon} size={mockProps.size} /> + <StyledIconButton icon={mockProps.icon} sized={mockProps.size} /> ) expect(wrapper.getElement()).toMatchSnapshot() diff --git a/src/components/CommonKit/IconButton/StyledIconButton.tsx b/src/components/CommonKit/IconButton/StyledIconButton.tsx index 4aaea811af86664831811cbc3e4d19219a5fa694..03e1b990581d3dfb13417329d5ee72d2e62c1020 100644 --- a/src/components/CommonKit/IconButton/StyledIconButton.tsx +++ b/src/components/CommonKit/IconButton/StyledIconButton.tsx @@ -1,7 +1,7 @@ -import React from 'react' -import { withStyles } from '@material-ui/core/styles' import IconButton, { IconButtonProps } from '@material-ui/core/IconButton' +import { withStyles } from '@material-ui/core/styles' import StyledIconProps from 'components/CommonKit/Icon/StyledIcon' +import React from 'react' const IconButtonBase = withStyles({ root: { diff --git a/src/components/CommonKit/IconButton/__snapshots__/StyledIconBorderedButton.spec.tsx.snap b/src/components/CommonKit/IconButton/__snapshots__/StyledIconBorderedButton.spec.tsx.snap index e8691596e93d58279f285ae20f03e7f280a092ec..55ffe0707050115b083c4664fa1c380f7755ceeb 100644 --- a/src/components/CommonKit/IconButton/__snapshots__/StyledIconBorderedButton.spec.tsx.snap +++ b/src/components/CommonKit/IconButton/__snapshots__/StyledIconBorderedButton.spec.tsx.snap @@ -2,12 +2,10 @@ exports[`StyledIconBorderedButton component test should render correctly SelectedIconButtonBase 1`] = ` <React.Fragment> - <WithStyles(WithStyles(WithStyles(ForwardRef(IconButton)))) - size={20} - > + <WithStyles(WithStyles(WithStyles(ForwardRef(IconButton))))> <StyledIcon icon="icon" - size={16} + size={20} /> </WithStyles(WithStyles(WithStyles(ForwardRef(IconButton))))> </React.Fragment> @@ -15,12 +13,10 @@ exports[`StyledIconBorderedButton component test should render correctly Selecte exports[`StyledIconBorderedButton component test should render correctly UnselectedIconButtonBase 1`] = ` <React.Fragment> - <WithStyles(WithStyles(WithStyles(ForwardRef(IconButton)))) - size={20} - > + <WithStyles(WithStyles(WithStyles(ForwardRef(IconButton))))> <StyledIcon icon="icon" - size={16} + size={20} /> </WithStyles(WithStyles(WithStyles(ForwardRef(IconButton))))> </React.Fragment> diff --git a/src/components/CommonKit/IconButton/__snapshots__/StyledIconButton.spec.tsx.snap b/src/components/CommonKit/IconButton/__snapshots__/StyledIconButton.spec.tsx.snap index 5f194e789590b447fa73af9ec20db6d5428904ac..f91cdd49811fe980afd9c27de7cd25b30dd99de0 100644 --- a/src/components/CommonKit/IconButton/__snapshots__/StyledIconButton.spec.tsx.snap +++ b/src/components/CommonKit/IconButton/__snapshots__/StyledIconButton.spec.tsx.snap @@ -1,12 +1,10 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP exports[`StyledIconButton component test should render correctly StyledIconButton 1`] = ` -<WithStyles(WithStyles(ForwardRef(IconButton))) - size={15} -> +<WithStyles(WithStyles(ForwardRef(IconButton)))> <StyledIcon icon="icon" - size={16} + size={15} /> </WithStyles(WithStyles(ForwardRef(IconButton)))> `; diff --git a/src/components/CommonKit/Switch/StyledSwitch.spec.tsx b/src/components/CommonKit/Switch/StyledSwitch.spec.tsx index 00a82423b46d719e2c854355c4d4be3ffed23baf..b3605a86cb94e5fc6e909b6f83b65692c7006bb6 100644 --- a/src/components/CommonKit/Switch/StyledSwitch.spec.tsx +++ b/src/components/CommonKit/Switch/StyledSwitch.spec.tsx @@ -1,10 +1,10 @@ -import React from 'react' +import { FluidType } from 'enum/fluid.enum' import { mount } from 'enzyme' +import React from 'react' import StyledSwitch from './StyledSwitch' -import { FluidType } from 'enum/fluid.enum' describe('StyledSwitch component test', () => { - it('should render correctly electricty StyledSwitch', () => { + it('should render correctly electricity StyledSwitch', () => { const wrapper = mount(<StyledSwitch fluidType={FluidType.ELECTRICITY} />) expect(wrapper.getElement()).toMatchSnapshot() diff --git a/src/components/CommonKit/Switch/StyledSwitch.tsx b/src/components/CommonKit/Switch/StyledSwitch.tsx index a82bd25f23d0c4ce508a7f8e1a8f31a321c411a9..87535cd0b1c9a312f4aa54685896f354386e7e62 100644 --- a/src/components/CommonKit/Switch/StyledSwitch.tsx +++ b/src/components/CommonKit/Switch/StyledSwitch.tsx @@ -1,7 +1,7 @@ -import React from 'react' -import { FluidType } from 'enum/fluid.enum' -import Switch, { SwitchProps } from '@material-ui/core/Switch' import { withStyles } from '@material-ui/core/styles' +import Switch, { SwitchProps } from '@material-ui/core/Switch' +import { FluidType } from 'enum/fluid.enum' +import React from 'react' const SwitchBase = withStyles({ root: { @@ -29,7 +29,7 @@ const SwitchBase = withStyles({ marginLeft: 'initial', left: 0, }, -})(Switch) +})(Switch) as React.FC<StyledSwitchProps> const SwitchElec = withStyles({ switchBase: { @@ -41,7 +41,7 @@ const SwitchElec = withStyles({ }, checked: {}, track: {}, -})(SwitchBase) +})(SwitchBase) as React.FC<StyledSwitchProps> const SwitchWater = withStyles({ switchBase: { @@ -53,7 +53,7 @@ const SwitchWater = withStyles({ }, checked: {}, track: {}, -})(SwitchBase) +})(SwitchBase) as React.FC<StyledSwitchProps> const SwitchGas = withStyles({ switchBase: { @@ -65,16 +65,13 @@ const SwitchGas = withStyles({ }, checked: {}, track: {}, -})(SwitchBase) +})(SwitchBase) as React.FC<StyledSwitchProps> interface StyledSwitchProps extends SwitchProps { fluidType?: FluidType } -const StyledSwitch: React.ComponentType<StyledSwitchProps> = ({ - fluidType, - ...props -}: StyledSwitchProps) => { +const StyledSwitch = ({ fluidType, ...props }: StyledSwitchProps) => { if (fluidType !== undefined) { switch (fluidType) { case FluidType.ELECTRICITY: diff --git a/src/components/CommonKit/Switch/__snapshots__/StyledSwitch.spec.tsx.snap b/src/components/CommonKit/Switch/__snapshots__/StyledSwitch.spec.tsx.snap index 14ab2c5e208a9f9476926663179baeba853df57d..a69f06614469b151eed0b9a94b44c6d9ebfd0247 100644 --- a/src/components/CommonKit/Switch/__snapshots__/StyledSwitch.spec.tsx.snap +++ b/src/components/CommonKit/Switch/__snapshots__/StyledSwitch.spec.tsx.snap @@ -1,6 +1,6 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[`StyledSwitch component test should render correctly electricty StyledSwitch 1`] = ` +exports[`StyledSwitch component test should render correctly electricity StyledSwitch 1`] = ` <StyledSwitch fluidType={0} /> diff --git a/src/components/Connection/Connection.tsx b/src/components/Connection/Connection.tsx index 3da86c44de6389db1eefe6aabe3fbf4e89a9a053..184c158670a6ad6e76b1b7a5e9e6f41fee4670ce 100644 --- a/src/components/Connection/Connection.tsx +++ b/src/components/Connection/Connection.tsx @@ -1,7 +1,8 @@ import { FluidType } from 'enum/fluid.enum' import { FluidConnection, FluidStatus } from 'models' -import React, { useCallback } from 'react' +import React, { Dispatch, useCallback } from 'react' import { useDispatch } from 'react-redux' +import { AppActionsTypes } from 'store' import { updatedFluidConnection } from 'store/global/global.actions' import './connection.scss' import EpglInit from './EPGLConnect/EpglInit' @@ -14,7 +15,7 @@ interface ConnectionProps { const Connection: React.FC<ConnectionProps> = ({ fluidStatus, }: ConnectionProps) => { - const dispatch = useDispatch() + const dispatch = useDispatch<Dispatch<AppActionsTypes>>() const handleSuccess = useCallback(async () => { const updatedConnection: FluidConnection = { diff --git a/src/components/Connection/ConnectionNotFound.spec.tsx b/src/components/Connection/ConnectionNotFound.spec.tsx index a2b02027cfe45ae4a19a47dc8ebc6d2dca8ab8c1..1772e89ff42cad50f04e69a7d50bc2b2f3eebe38 100644 --- a/src/components/Connection/ConnectionNotFound.spec.tsx +++ b/src/components/Connection/ConnectionNotFound.spec.tsx @@ -1,7 +1,7 @@ -import React from 'react' -import { shallow, mount } from 'enzyme' -import ConnectionNotFound from 'components/Connection/ConnectionNotFound' 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 { diff --git a/src/components/Connection/ConnectionNotFound.tsx b/src/components/Connection/ConnectionNotFound.tsx index 9eee50aa1a1310968066eaf09dcbc51884ff169d..e80bda11abbfde9f76b0601add74a3fa713cb757 100644 --- a/src/components/Connection/ConnectionNotFound.tsx +++ b/src/components/Connection/ConnectionNotFound.tsx @@ -1,6 +1,6 @@ -import React from 'react' -import { useI18n } from 'cozy-ui/transpiled/react/I18n' import Button from '@material-ui/core/Button' +import { useI18n } from 'cozy-ui/transpiled/react/I18n' +import React from 'react' import './connectionNotFound.scss' interface ConnectionNotFoundProps { konnectorSlug: string diff --git a/src/components/Connection/ConnectionResult.tsx b/src/components/Connection/ConnectionResult.tsx index 9fc8b66bd622340ccb59b4c03dde027d912b9ece..f41fa87fe37227f2d43b89aff24cbc34e51f1185 100644 --- a/src/components/Connection/ConnectionResult.tsx +++ b/src/components/Connection/ConnectionResult.tsx @@ -5,23 +5,25 @@ import Loader from 'components/Loader/Loader' import { useClient } from 'cozy-client' import { useI18n } from 'cozy-ui/transpiled/react/I18n' import { FluidType } from 'enum/fluid.enum' +import { KonnectorUpdate } from 'enum/konnectorUpdate.enum' import { DateTime } from 'luxon' import { Account, AccountSgeData, FluidConnection, FluidStatus, - Trigger + Trigger, } from 'models' -import React, { useCallback, useEffect, useState } from 'react' +import React, { Dispatch, useCallback, useEffect, useState } from 'react' import { useDispatch } from 'react-redux' import AccountService from 'services/account.service' import DateChartService from 'services/dateChart.service' import TriggerService from 'services/triggers.service' +import { AppActionsTypes } from 'store' import { setShouldRefreshConsent, updatedFluidConnection, - updateSgeStore + updateSgeStore, } from 'store/global/global.actions' import { getKonnectorUpdateError } from 'utils/utils' import './connectionResult.scss' @@ -40,7 +42,7 @@ const ConnectionResult: React.FC<ConnectionResultProps> = ({ }: ConnectionResultProps) => { const { t } = useI18n() const client = useClient() - const dispatch = useDispatch() + const dispatch = useDispatch<Dispatch<AppActionsTypes>>() const account: Account | null = fluidStatus.connection.account const [deleting, setDeleting] = useState<boolean>(false) @@ -176,6 +178,10 @@ const ConnectionResult: React.FC<ConnectionResultProps> = ({ } } + const consentError = + konnectorError === KonnectorUpdate.ERROR_CONSENT_FORM_GAS || + konnectorError === KonnectorUpdate.ERROR_UPDATE_OAUTH + return ( <div className="connection-update-result"> <div @@ -198,6 +204,7 @@ const ConnectionResult: React.FC<ConnectionResultProps> = ({ // Else check if konnector is in error state <DisplayKonnectorErrorState konnectorError={konnectorError} + consentRelatedError={consentError} lastExecutionDate={lastExecutionDate} fluidConcerned={getFluidTypeTranslation(fluidType)} /> @@ -217,27 +224,29 @@ const ConnectionResult: React.FC<ConnectionResultProps> = ({ )} </div> <div className="inline-buttons"> - <Button - aria-label={t('konnector_form.accessibility.button_delete')} - onClick={ - fluidType === FluidType.GAS - ? toggleGRDFDeletionModal - : deleteAccountsAndTriggers - } - disabled={updating || deleting} - classes={{ - root: 'btn-secondary-positive', - label: 'text-16-normal', - }} - > - {deleting - ? t('konnector_form.loading') - : t('konnector_form.button_delete')} - </Button> + {!consentError && ( + <Button + aria-label={t('konnector_form.accessibility.button_delete')} + onClick={ + fluidType === FluidType.GAS + ? toggleGRDFDeletionModal + : deleteAccountsAndTriggers + } + disabled={updating || deleting} + classes={{ + root: 'btn-secondary-positive', + label: 'text-16-normal', + }} + > + {deleting + ? t('konnector_form.loading') + : t('konnector_form.button_delete')} + </Button> + )} <Button aria-label={t('konnector_form.accessibility.button_update')} onClick={ - konnectorError === 'error_update_oauth' + consentError ? () => handleRefreshConsent(fluidType) : updateKonnector } @@ -250,7 +259,7 @@ const ConnectionResult: React.FC<ConnectionResultProps> = ({ {updating && <Loader color="black" />} {!updating && ( <div> - {konnectorError === 'error_update_oauth' + {consentError ? t('konnector_form.button_oauth_reload') : t('konnector_form.button_update')} </div> @@ -270,10 +279,12 @@ const ConnectionResult: React.FC<ConnectionResultProps> = ({ const DisplayKonnectorErrorState = ({ konnectorError, + consentRelatedError, lastExecutionDate, fluidConcerned, }: { konnectorError: string + consentRelatedError: boolean lastExecutionDate: string | DateTime fluidConcerned: string }) => { @@ -295,7 +306,7 @@ const DisplayKonnectorErrorState = ({ {t(`konnector_form.${konnectorError}`, { fluid: fluidConcerned, })} - {konnectorError !== 'error_update_oauth' && ( + {!consentRelatedError && ( <> <div className="connection-caption"> {t('konnector_form.label_updated_at')} diff --git a/src/components/Connection/DeleteGRDFAccountModal.spec.tsx b/src/components/Connection/DeleteGRDFAccountModal.spec.tsx index a517038943eb0573b83e3a2c183a8c20874a8007..9450e052f8a28c8daeebbbeb3f00adabe959275d 100644 --- a/src/components/Connection/DeleteGRDFAccountModal.spec.tsx +++ b/src/components/Connection/DeleteGRDFAccountModal.spec.tsx @@ -1,7 +1,7 @@ -import React from 'react' +import { Button } from '@material-ui/core' import { mount } from 'enzyme' import toJson from 'enzyme-to-json' -import { Button } from '@material-ui/core' +import React from 'react' import DeleteGRDFAccountModal from './DeleteGRDFAccountModal' jest.mock('cozy-ui/transpiled/react/I18n', () => { diff --git a/src/components/Connection/DeleteGRDFAccountModal.tsx b/src/components/Connection/DeleteGRDFAccountModal.tsx index 69eaa4b64dd06bdbb1aad05a3893d3a0ed30bce4..6ec568182479006ce2b0692051151abcf923e5d2 100644 --- a/src/components/Connection/DeleteGRDFAccountModal.tsx +++ b/src/components/Connection/DeleteGRDFAccountModal.tsx @@ -1,10 +1,10 @@ -import React, { useCallback } from 'react' -import { useI18n } from 'cozy-ui/transpiled/react/I18n' +import { Button, IconButton } from '@material-ui/core' import Dialog from '@material-ui/core/Dialog' import CloseIcon from 'assets/icons/ico/close.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 { Button, IconButton } from '@material-ui/core' +import React, { useCallback } from 'react' import './deleteGRDFAccountModal.scss' interface DeleteGRDFAccountModalProps { diff --git a/src/components/Connection/ExpiredConsentModal.tsx b/src/components/Connection/ExpiredConsentModal.tsx index ef0c9c5ee1e79676fdf55d944776d9c241b6cb56..6a6dcc5c5d784090b3e7a4a92f2830fdd6c7798e 100644 --- a/src/components/Connection/ExpiredConsentModal.tsx +++ b/src/components/Connection/ExpiredConsentModal.tsx @@ -7,10 +7,10 @@ import { useI18n } from 'cozy-ui/transpiled/react/I18n' import Icon from 'cozy-ui/transpiled/react/Icon' import { FluidType } from 'enum/fluid.enum' import { AccountSgeData } from 'models' -import React, { useCallback } from 'react' +import React, { Dispatch, useCallback } from 'react' import { useDispatch, useSelector } from 'react-redux' import { useNavigate } from 'react-router-dom' -import { AppStore } from 'store' +import { AppActionsTypes, AppStore } from 'store' import { setShouldRefreshConsent, updateSgeStore, @@ -32,7 +32,7 @@ const ExpiredConsentModal: React.FC<ExpiredConsentModalProps> = ({ }: ExpiredConsentModalProps) => { const { t } = useI18n() const navigate = useNavigate() - const dispatch = useDispatch() + const dispatch = useDispatch<Dispatch<AppActionsTypes>>() const { fluidStatus } = useSelector((state: AppStore) => state.ecolyo.global) const launchUpdateConsent = useCallback(() => { diff --git a/src/components/Connection/FormOAuth.tsx b/src/components/Connection/FormOAuth.tsx index 93eb4226d71030e257ce674a95612e72073ae415..a732fd9602217b91a113405a21be2da274c86e63 100644 --- a/src/components/Connection/FormOAuth.tsx +++ b/src/components/Connection/FormOAuth.tsx @@ -4,10 +4,10 @@ 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, { useCallback, useEffect, useState } from 'react' +import React, { Dispatch, useCallback, useEffect, useState } from 'react' import { useDispatch, useSelector } from 'react-redux' import UsageEventService from 'services/usageEvent.service' -import { AppStore } from 'store' +import { AppActionsTypes, AppStore } from 'store' import { setShouldRefreshConsent } from 'store/global/global.actions' interface FormOAuthProps { @@ -30,7 +30,7 @@ const FormOAuth: React.FC<FormOAuthProps> = ({ const { shouldRefreshConsent } = useSelector( (state: AppStore) => state.ecolyo.global ) - const dispatch = useDispatch() + const dispatch = useDispatch<Dispatch<AppActionsTypes>>() const endOAuth = useCallback(() => { setStatus(IDLE) // Set back to false the variable that allows to automatically refresh the consent (deletes and recreates the account) diff --git a/src/components/Connection/GRDFConnect/GrdfInit.tsx b/src/components/Connection/GRDFConnect/GrdfInit.tsx index 4414d9b035d381ced015ec9e8e43395a5c5d4e1e..3e580a9f40ee3796252fc15d69e75ddc39ca17bd 100644 --- a/src/components/Connection/GRDFConnect/GrdfInit.tsx +++ b/src/components/Connection/GRDFConnect/GrdfInit.tsx @@ -2,11 +2,12 @@ import GrdfConnectModal from 'components/Connection/PartnerConnectModal/GrdfConn import { useClient } from 'cozy-client' import { UsageEventType } from 'enum/usageEvent.enum' import { FluidConnection, FluidStatus, Konnector, Trigger } from 'models' -import React, { useCallback, useState } from 'react' +import React, { Dispatch, useCallback, useState } from 'react' import { useDispatch } from 'react-redux' import AccountService from 'services/account.service' import TriggerService from 'services/triggers.service' import UsageEventService from 'services/usageEvent.service' +import { AppActionsTypes } from 'store' import { updatedFluidConnection } from 'store/global/global.actions' import '../connection.scss' import GrdfBill from './GrdfBill' @@ -22,7 +23,7 @@ const GrdfInit: React.FC<GrdfInitProps> = ({ onSuccess, }: GrdfInitProps) => { const client = useClient() - const dispatch = useDispatch() + const dispatch = useDispatch<Dispatch<AppActionsTypes>>() const [openModal, setOpenModal] = useState(false) const [showForm, setShowForm] = useState(false) diff --git a/src/components/Connection/SGEConnect/SgeConnectView.tsx b/src/components/Connection/SGEConnect/SgeConnectView.tsx index d1e6d89d20e3af078f36ee46cadee431e20613e0..8a78148b0ff6eec6a04f93c754b8104d4935d016 100644 --- a/src/components/Connection/SGEConnect/SgeConnectView.tsx +++ b/src/components/Connection/SGEConnect/SgeConnectView.tsx @@ -5,9 +5,9 @@ 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, { useCallback, useState } from 'react' +import React, { Dispatch, useCallback, useState } from 'react' import { useDispatch, useSelector } from 'react-redux' -import { AppStore } from 'store' +import { AppActionsTypes, AppStore } from 'store' import { updateSgeStore } from 'store/global/global.actions' import './SgeConnect.scss' import StepAddress from './StepAddress' @@ -27,7 +27,7 @@ export type SGEKeysForm = const SgeConnectView: React.FC = () => { const [headerHeight, setHeaderHeight] = useState<number>(0) const { sgeConnect } = useSelector((state: AppStore) => state.ecolyo.global) - const dispatch = useDispatch() + const dispatch = useDispatch<Dispatch<AppActionsTypes>>() const [currentStep, setCurrentStep] = useState<SgeStep>( sgeConnect.currentStep ) diff --git a/src/components/Connection/SGEConnect/SgeInit.tsx b/src/components/Connection/SGEConnect/SgeInit.tsx index 259324ac27e7d96c2973435dd07edeff4e3eda7f..c882678e44e8138c06aaff4ebd237fa53779c7cd 100644 --- a/src/components/Connection/SGEConnect/SgeInit.tsx +++ b/src/components/Connection/SGEConnect/SgeInit.tsx @@ -4,10 +4,10 @@ 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, { useEffect } from 'react' +import React, { Dispatch, useEffect } from 'react' import { useDispatch, useSelector } from 'react-redux' import { useNavigate } from 'react-router-dom' -import { AppStore } from 'store' +import { AppActionsTypes, AppStore } from 'store' import { setShouldRefreshConsent, updateSgeStore, @@ -24,7 +24,7 @@ const SgeInit: React.FC<SgeInitProps> = ({ fluidStatus }: SgeInitProps) => { const account: Account | null = fluidStatus.connection.account const { sgeConnect } = useSelector((state: AppStore) => state.ecolyo.global) - const dispatch = useDispatch() + const dispatch = useDispatch<Dispatch<AppActionsTypes>>() const [connect, update] = useKonnectorAuth(fluidStatus) useEffect(() => { diff --git a/src/components/Connection/SGEConnect/SgeModalHint.spec.tsx b/src/components/Connection/SGEConnect/SgeModalHint.spec.tsx index c5513c1ef3fa9516d79d96f6f6338f8c0674d2c6..86efcf12d591964811923a9b982b963b0c45abb0 100644 --- a/src/components/Connection/SGEConnect/SgeModalHint.spec.tsx +++ b/src/components/Connection/SGEConnect/SgeModalHint.spec.tsx @@ -1,9 +1,9 @@ -import React from 'react' import { mount } from 'enzyme' -import configureStore from 'redux-mock-store' +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 toJson from 'enzyme-to-json' import SgeModalHint from './SgeModalHint' jest.mock('cozy-ui/transpiled/react/I18n', () => { diff --git a/src/components/Connection/SGEConnect/StepAddress.spec.tsx b/src/components/Connection/SGEConnect/StepAddress.spec.tsx index dd8b7fbdfc20ed56cddb82dfe43a08f3a4cb2e98..4874eaee45fa946607e3a3d1cd7efcb6ef1e6a38 100644 --- a/src/components/Connection/SGEConnect/StepAddress.spec.tsx +++ b/src/components/Connection/SGEConnect/StepAddress.spec.tsx @@ -1,9 +1,9 @@ -import React from 'react' import { mount } from 'enzyme' -import configureStore from 'redux-mock-store' +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 toJson from 'enzyme-to-json' import StepAddress from './StepAddress' jest.mock('cozy-ui/transpiled/react/I18n', () => { diff --git a/src/components/Connection/SGEConnect/StepIdentityAndPdl.spec.tsx b/src/components/Connection/SGEConnect/StepIdentityAndPdl.spec.tsx index 4a6ffacf3c40c7e37edefbd4a17850a317ad8ee4..dba57dc00833286368cf785304f4713498147679 100644 --- a/src/components/Connection/SGEConnect/StepIdentityAndPdl.spec.tsx +++ b/src/components/Connection/SGEConnect/StepIdentityAndPdl.spec.tsx @@ -1,9 +1,9 @@ -import React from 'react' import { mount } from 'enzyme' -import configureStore from 'redux-mock-store' +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 toJson from 'enzyme-to-json' import StepIdentityAndPdl from './StepIdentityAndPdl' jest.mock('cozy-ui/transpiled/react/I18n', () => { diff --git a/src/components/Connection/SGEConnect/__snapshots__/SgeConnectView.spec.tsx.snap b/src/components/Connection/SGEConnect/__snapshots__/SgeConnectView.spec.tsx.snap index f942fe39679b7581059f24af1d030026f0da57ff..cea387fbd3146cf38bcc892739c721792fd622cf 100644 --- a/src/components/Connection/SGEConnect/__snapshots__/SgeConnectView.spec.tsx.snap +++ b/src/components/Connection/SGEConnect/__snapshots__/SgeConnectView.spec.tsx.snap @@ -642,7 +642,6 @@ exports[`SgeConnectView component should be rendered correctly 1`] = ` "dataConsent": false, "firstName": "", "lastName": "", - "openSGEForm": false, "pdl": null, "pdlConfirm": false, "shouldLaunchAccount": false, diff --git a/src/components/Connection/SGEConnect/__snapshots__/SgeInit.spec.tsx.snap b/src/components/Connection/SGEConnect/__snapshots__/SgeInit.spec.tsx.snap index 8e4012899c81137d2fdf79f9c8708f117bdbfdb5..9664ddc16aee3b8da6918d4f4d801b4156ea068a 100644 --- a/src/components/Connection/SGEConnect/__snapshots__/SgeInit.spec.tsx.snap +++ b/src/components/Connection/SGEConnect/__snapshots__/SgeInit.spec.tsx.snap @@ -34,6 +34,7 @@ exports[`SgeInit component should be rendered correctly 1`] = ` "firstDataDate": "2019-09-01T00:00:00.000Z", "fluidType": 0, "lastDataDate": "2020-09-01T00:00:00.000Z", + "maintenance": false, "status": 0, } } diff --git a/src/components/Connection/SGEConnect/__snapshots__/StepAddress.spec.tsx.snap b/src/components/Connection/SGEConnect/__snapshots__/StepAddress.spec.tsx.snap index 26812fdf7014e4a971b43a489b87dcd3202f7ece..bffbbf9d0daf4c604fe6515786a9fa9d54a83c71 100644 --- a/src/components/Connection/SGEConnect/__snapshots__/StepAddress.spec.tsx.snap +++ b/src/components/Connection/SGEConnect/__snapshots__/StepAddress.spec.tsx.snap @@ -23,7 +23,6 @@ exports[`StepAddress component should be rendered correctly 1`] = ` "dataConsent": false, "firstName": "", "lastName": "", - "openSGEForm": false, "pdl": null, "pdlConfirm": false, "shouldLaunchAccount": false, diff --git a/src/components/Connection/SGEConnect/__snapshots__/StepConsent.spec.tsx.snap b/src/components/Connection/SGEConnect/__snapshots__/StepConsent.spec.tsx.snap index b377c4e67e55737300f2a633b16de3503e32ade0..f5fd68d492c79666b431eae5ce7719273b7005d1 100644 --- a/src/components/Connection/SGEConnect/__snapshots__/StepConsent.spec.tsx.snap +++ b/src/components/Connection/SGEConnect/__snapshots__/StepConsent.spec.tsx.snap @@ -23,7 +23,6 @@ exports[`StepConsent component should be rendered correctly 1`] = ` "dataConsent": false, "firstName": "", "lastName": "", - "openSGEForm": false, "pdl": null, "pdlConfirm": false, "shouldLaunchAccount": false, diff --git a/src/components/Connection/SGEConnect/__snapshots__/StepIdentityAndPdl.spec.tsx.snap b/src/components/Connection/SGEConnect/__snapshots__/StepIdentityAndPdl.spec.tsx.snap index d02da53ca004a9588d0971dfa7199fd70a289efc..171bb6590ba3ba466e4d50f40aac68569570a4d6 100644 --- a/src/components/Connection/SGEConnect/__snapshots__/StepIdentityAndPdl.spec.tsx.snap +++ b/src/components/Connection/SGEConnect/__snapshots__/StepIdentityAndPdl.spec.tsx.snap @@ -23,7 +23,6 @@ exports[`StepIdentityAndPdl component should be rendered correctly 1`] = ` "dataConsent": false, "firstName": "", "lastName": "", - "openSGEForm": false, "pdl": null, "pdlConfirm": false, "shouldLaunchAccount": false, diff --git a/src/components/Connection/__snapshots__/Connection.spec.tsx.snap b/src/components/Connection/__snapshots__/Connection.spec.tsx.snap index 0dc42e448cc7515a2de41988d7707201e12cb206..3996b0f97426c3aae5e1e2d8b0ffc6ed38636ea0 100644 --- a/src/components/Connection/__snapshots__/Connection.spec.tsx.snap +++ b/src/components/Connection/__snapshots__/Connection.spec.tsx.snap @@ -45,6 +45,7 @@ exports[`Connection component test should call EpglInit 1`] = ` "firstDataDate": "2019-09-01T00:00:00.000Z", "fluidType": 0, "lastDataDate": "2020-09-01T00:00:00.000Z", + "maintenance": false, "status": 200, } } @@ -84,6 +85,7 @@ exports[`Connection component test should call EpglInit 1`] = ` "firstDataDate": "2019-09-01T00:00:00.000Z", "fluidType": 0, "lastDataDate": "2020-09-01T00:00:00.000Z", + "maintenance": false, "status": 200, } } @@ -308,6 +310,7 @@ exports[`Connection component test should call GrdfInit 1`] = ` "firstDataDate": "2019-09-01T00:00:00.000Z", "fluidType": 2, "lastDataDate": "2020-09-01T00:00:00.000Z", + "maintenance": false, "status": 200, } } @@ -336,6 +339,7 @@ exports[`Connection component test should call GrdfInit 1`] = ` "firstDataDate": "2019-09-01T00:00:00.000Z", "fluidType": 2, "lastDataDate": "2020-09-01T00:00:00.000Z", + "maintenance": false, "status": 200, } } diff --git a/src/components/Connection/connectionResult.scss b/src/components/Connection/connectionResult.scss index 6d46ca06831d704e396c84b8be352823cfe9cb19..f508a239956b1128166a2ea10e6913f22186fcef 100644 --- a/src/components/Connection/connectionResult.scss +++ b/src/components/Connection/connectionResult.scss @@ -20,6 +20,7 @@ } .warning-icon { + min-width: 20px; margin-right: 1rem; } .warning-white { diff --git a/src/components/ConsumptionVisualizer/ConsumptionVisualizer.tsx b/src/components/ConsumptionVisualizer/ConsumptionVisualizer.tsx index 11007d24c1da41a0801b87ef401646ba4c4a66a6..a2d879851348987052f1f257fdc47a96ef31d273 100644 --- a/src/components/ConsumptionVisualizer/ConsumptionVisualizer.tsx +++ b/src/components/ConsumptionVisualizer/ConsumptionVisualizer.tsx @@ -1,12 +1,11 @@ -import React from 'react' -import './consumptionVisualizer.scss' -import { useSelector } from 'react-redux' -import { AppStore } from 'store' +import DataloadConsumptionVisualizer from 'components/ConsumptionVisualizer/DataloadConsumptionVisualizer' import { FluidType } from 'enum/fluid.enum' import { DateTime } from 'luxon' import { Dataload } from 'models' - -import DataloadConsumptionVisualizer from 'components/ConsumptionVisualizer/DataloadConsumptionVisualizer' +import React from 'react' +import { useSelector } from 'react-redux' +import { AppStore } from 'store' +import './consumptionVisualizer.scss' import InfoDataConsumptionVisualizer from './InfoDataConsumptionVisualizer' interface ConsumptionVisualizerProps { @@ -19,12 +18,11 @@ const ConsumptionVisualizer: React.FC<ConsumptionVisualizerProps> = ({ showCompare, setActive, }: ConsumptionVisualizerProps) => { - const { fluidStatus, fluidTypes } = useSelector( - (state: AppStore) => state.ecolyo.global - ) - const { currentDatachart, currentDatachartIndex } = useSelector( - (state: AppStore) => state.ecolyo.chart - ) + const { + chart: { currentDatachart, currentDatachartIndex }, + global: { fluidStatus, fluidTypes }, + } = useSelector((state: AppStore) => state.ecolyo) + const dataload: Dataload = currentDatachart.actualData[currentDatachartIndex] const compareDataload: Dataload | null = currentDatachart.comparisonData ? currentDatachart.comparisonData[currentDatachartIndex] diff --git a/src/components/ConsumptionVisualizer/DataloadConsumptionVisualizer.spec.tsx b/src/components/ConsumptionVisualizer/DataloadConsumptionVisualizer.spec.tsx index 9377278e20666b2d250966bfdae2446230b00954..50dde72a4dac679eee16dd9de80d2c7d6ce737a1 100644 --- a/src/components/ConsumptionVisualizer/DataloadConsumptionVisualizer.spec.tsx +++ b/src/components/ConsumptionVisualizer/DataloadConsumptionVisualizer.spec.tsx @@ -1,18 +1,19 @@ -import React from 'react' import { mount } from 'enzyme' +import React from 'react' import { Provider } from 'react-redux' +import { DataloadState } from 'enum/dataload.enum' +import { FluidType } from 'enum/fluid.enum' +import { Dataload } from 'models' +import { BrowserRouter as Router } 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 DataloadConsumptionVisualizer from './DataloadConsumptionVisualizer' -import { FluidType } from 'enum/fluid.enum' -import { baseDataLoad } from '../../../tests/__mocks__/datachartData.mock' -import { Dataload } from 'models' -import { BrowserRouter as Router } from 'react-router-dom' -import UsageEventService from 'services/usageEvent.service' jest.mock('cozy-ui/transpiled/react/I18n', () => { return { @@ -24,6 +25,15 @@ jest.mock('cozy-ui/transpiled/react/I18n', () => { } }) +const mockGetAllLastPrices = jest.fn() +jest.mock('services/fluidsPrices.service', () => { + return jest.fn(() => { + return { + getAllLastPrices: mockGetAllLastPrices, + } + }) +}) + const mockStore = configureStore([]) const mockChartStateLoaded = { ...mockInitialChartState, loading: false } const emptyDataLoad = { ...baseDataLoad, value: -1 } @@ -33,7 +43,11 @@ const dataLoadWithValueDetailEmpty: Dataload = { } const dataLoadWithValueDetail: Dataload = { ...baseDataLoad, - valueDetail: [0.612216, 0.675242, 0.6779610000000003], + valueDetail: [ + { state: DataloadState.VALID, value: 0.612216 }, + { state: DataloadState.VALID, value: 0.675242 }, + { state: DataloadState.VALID, value: 0.6779610000000003 }, + ], } describe('Dataload consumption visualizer component', () => { diff --git a/src/components/ConsumptionVisualizer/DataloadConsumptionVisualizer.tsx b/src/components/ConsumptionVisualizer/DataloadConsumptionVisualizer.tsx index fe02f644682aaaafa24fad8625051406f3c13871..fb64ac41b617dce10612d6692cebbef1de28c82f 100644 --- a/src/components/ConsumptionVisualizer/DataloadConsumptionVisualizer.tsx +++ b/src/components/ConsumptionVisualizer/DataloadConsumptionVisualizer.tsx @@ -1,13 +1,13 @@ +import { DataloadSectionType, DataloadState } from 'enum/dataload.enum' +import { FluidType } from 'enum/fluid.enum' +import { Dataload } from 'models' import React, { useCallback, useState } from 'react' -import './dataloadConsumptionVisualizer.scss' import { useSelector } from 'react-redux' import { AppStore } from 'store' -import { Dataload } from 'models' -import { FluidType } from 'enum/fluid.enum' -import EstimatedConsumptionModal from './EstimatedConsumptionModal' +import './dataloadConsumptionVisualizer.scss' import DataloadNoValue from './DataloadNoValue' -import { DataloadSectionType, DataloadState } from 'enum/dataload.enum' import DataloadSection from './DataloadSection' +import EstimatedConsumptionModal from './EstimatedConsumptionModal' interface DataloadConsumptionVisualizerProps { fluidType: FluidType diff --git a/src/components/ConsumptionVisualizer/DataloadNoValue.spec.tsx b/src/components/ConsumptionVisualizer/DataloadNoValue.spec.tsx index f1e680ae2c54ba432b88a476a368a561f1a877f1..8dff84828bf4e4d4803c9035969db86858c99a8e 100644 --- a/src/components/ConsumptionVisualizer/DataloadNoValue.spec.tsx +++ b/src/components/ConsumptionVisualizer/DataloadNoValue.spec.tsx @@ -1,11 +1,11 @@ -import React from 'react' +import { DataloadState } from 'enum/dataload.enum' +import { FluidType } from 'enum/fluid.enum' import { mount } from 'enzyme' import toJson from 'enzyme-to-json' -import { FluidType } from 'enum/fluid.enum' -import DataloadNoValue from './DataloadNoValue' -import { baseDataLoad } from '../../../tests/__mocks__/datachartData.mock' -import { DataloadState } from 'enum/dataload.enum' import { Dataload } from 'models' +import React from 'react' +import { baseDataLoad } from '../../../tests/__mocks__/chartData.mock' +import DataloadNoValue from './DataloadNoValue' jest.mock('cozy-ui/transpiled/react/I18n', () => { return { diff --git a/src/components/ConsumptionVisualizer/DataloadNoValue.tsx b/src/components/ConsumptionVisualizer/DataloadNoValue.tsx index cef6acd8c784debd24d4757265284e0b0b00ca8b..04b194750ea7bf4b55ff0e79a04837c4f166ba35 100644 --- a/src/components/ConsumptionVisualizer/DataloadNoValue.tsx +++ b/src/components/ConsumptionVisualizer/DataloadNoValue.tsx @@ -1,10 +1,10 @@ -import React, { useCallback } from 'react' -import './consumptionVisualizer.scss' -import { FluidType } from 'enum/fluid.enum' -import { Dataload } from 'models' +import classNames from 'classnames' import { useI18n } from 'cozy-ui/transpiled/react/I18n' import { DataloadState } from 'enum/dataload.enum' -import classNames from 'classnames' +import { FluidType } from 'enum/fluid.enum' +import { Dataload } from 'models' +import React, { useCallback } from 'react' +import './consumptionVisualizer.scss' interface DataloadNoValueProps { dataload: Dataload diff --git a/src/components/ConsumptionVisualizer/DataloadSection.spec.tsx b/src/components/ConsumptionVisualizer/DataloadSection.spec.tsx index 348a7d9d6077effa0a4190e39b31f06bf02799cf..32f5bea2191f47acaaf765256569cfb3aeb34cb8 100644 --- a/src/components/ConsumptionVisualizer/DataloadSection.spec.tsx +++ b/src/components/ConsumptionVisualizer/DataloadSection.spec.tsx @@ -1,10 +1,10 @@ -import React from 'react' +import { DataloadSectionType } from 'enum/dataload.enum' +import { FluidType } from 'enum/fluid.enum' import { mount } from 'enzyme' import toJson from 'enzyme-to-json' -import { FluidType } from 'enum/fluid.enum' -import { baseDataLoad } from '../../../tests/__mocks__/datachartData.mock' -import { DataloadSectionType } from 'enum/dataload.enum' import { Dataload } from 'models' +import React from 'react' +import { baseDataLoad } from '../../../tests/__mocks__/chartData.mock' import DataloadSection from './DataloadSection' jest.mock('cozy-ui/transpiled/react/I18n', () => { diff --git a/src/components/ConsumptionVisualizer/DataloadSection.tsx b/src/components/ConsumptionVisualizer/DataloadSection.tsx index 14482e3c5bc62bc4738652ca9e5f385ea25f60dd..3132d25dad4af730f36e8a1f946cd529eec3d43d 100644 --- a/src/components/ConsumptionVisualizer/DataloadSection.tsx +++ b/src/components/ConsumptionVisualizer/DataloadSection.tsx @@ -1,13 +1,12 @@ -import React from 'react' -import './consumptionVisualizer.scss' -import { FluidType } from 'enum/fluid.enum' -import { Dataload } from 'models' +import classNames from 'classnames' import { useI18n } from 'cozy-ui/transpiled/react/I18n' import { DataloadSectionType } from 'enum/dataload.enum' -import classNames from 'classnames' - -import DataloadSectionValue from './DataloadSectionValue' +import { FluidType } from 'enum/fluid.enum' +import { Dataload } from 'models' +import React from 'react' +import './consumptionVisualizer.scss' import DataloadSectionDetail from './DataloadSectionDetail' +import DataloadSectionValue from './DataloadSectionValue' interface DataloadSectionProps { dataload: Dataload diff --git a/src/components/ConsumptionVisualizer/DataloadSectionDetail.spec.tsx b/src/components/ConsumptionVisualizer/DataloadSectionDetail.spec.tsx index 6a515cd71baeab0f7dc8f0182a21e42013d8010f..677ebe1a5dc112445d9509ef8287f27630155f2f 100644 --- a/src/components/ConsumptionVisualizer/DataloadSectionDetail.spec.tsx +++ b/src/components/ConsumptionVisualizer/DataloadSectionDetail.spec.tsx @@ -1,10 +1,10 @@ -import React from 'react' +import { DataloadSectionType, DataloadState } from 'enum/dataload.enum' +import { FluidType } from 'enum/fluid.enum' import { mount } from 'enzyme' import toJson from 'enzyme-to-json' -import { FluidType } from 'enum/fluid.enum' -import { baseDataLoad } from '../../../tests/__mocks__/datachartData.mock' -import { DataloadSectionType, DataloadState } from 'enum/dataload.enum' import { Dataload } from 'models' +import React from 'react' +import { baseDataLoad } from '../../../tests/__mocks__/chartData.mock' import DataloadSectionDetail from './DataloadSectionDetail' jest.mock('cozy-ui/transpiled/react/I18n', () => { diff --git a/src/components/ConsumptionVisualizer/DataloadSectionDetail.tsx b/src/components/ConsumptionVisualizer/DataloadSectionDetail.tsx index b765c74730a02148aed03875c782c6299cde807c..7ce1a123f3dd2b3a0022acb1c83599b16b8e419e 100644 --- a/src/components/ConsumptionVisualizer/DataloadSectionDetail.tsx +++ b/src/components/ConsumptionVisualizer/DataloadSectionDetail.tsx @@ -1,17 +1,17 @@ -import React, { useCallback } from 'react' import classNames from 'classnames' -import { NavLink } from 'react-router-dom' import { useClient } from 'cozy-client' import { useI18n } from 'cozy-ui/transpiled/react/I18n' import Icon from 'cozy-ui/transpiled/react/Icon' -import { getNavPicto } from 'utils/picto' -import { Dataload } from 'models' -import { FluidType } from 'enum/fluid.enum' import { DataloadSectionType, DataloadState } from 'enum/dataload.enum' +import { FluidType } from 'enum/fluid.enum' import { UsageEventType } from 'enum/usageEvent.enum' +import { Dataload } from 'models' +import React, { useCallback } from 'react' +import { NavLink } from 'react-router-dom' import ConverterService from 'services/converter.service' -import { formatNumberValues } from 'utils/utils' import UsageEventService from 'services/usageEvent.service' +import { getNavPicto } from 'utils/picto' +import { formatNumberValues } from 'utils/utils' interface DataloadSectionDetailProps { dataload: Dataload diff --git a/src/components/ConsumptionVisualizer/DataloadSectionValue.spec.tsx b/src/components/ConsumptionVisualizer/DataloadSectionValue.spec.tsx index 4181b6a2ebccde40cdd799e5df89b08349f84fcf..1604ac509cbe4eb41c061242906a9f84c8ac6a78 100644 --- a/src/components/ConsumptionVisualizer/DataloadSectionValue.spec.tsx +++ b/src/components/ConsumptionVisualizer/DataloadSectionValue.spec.tsx @@ -1,13 +1,13 @@ -import React from 'react' +import { DataloadSectionType } from 'enum/dataload.enum' +import { FluidType } from 'enum/fluid.enum' import { mount } from 'enzyme' import toJson from 'enzyme-to-json' -import { FluidType } from 'enum/fluid.enum' +import { Dataload } from 'models' +import React from 'react' import { baseDataLoad, baseMultiFluidDataLoad, -} from '../../../tests/__mocks__/datachartData.mock' -import { DataloadSectionType } from 'enum/dataload.enum' -import { Dataload } from 'models' +} from '../../../tests/__mocks__/chartData.mock' import DataloadSectionValue from './DataloadSectionValue' jest.mock('cozy-ui/transpiled/react/I18n', () => { diff --git a/src/components/ConsumptionVisualizer/DataloadSectionValue.tsx b/src/components/ConsumptionVisualizer/DataloadSectionValue.tsx index 14f2db2dfc45fee0017b739e9b100517b3c5e9ef..72ed67a78d4c991c0b00965ff0010ae6014464d8 100644 --- a/src/components/ConsumptionVisualizer/DataloadSectionValue.tsx +++ b/src/components/ConsumptionVisualizer/DataloadSectionValue.tsx @@ -1,8 +1,8 @@ -import React from 'react' import { useI18n } from 'cozy-ui/transpiled/react/I18n' -import { Dataload } from 'models' -import { FluidType } from 'enum/fluid.enum' import { DataloadSectionType } from 'enum/dataload.enum' +import { FluidType } from 'enum/fluid.enum' +import { Dataload } from 'models' +import React from 'react' import { formatNumberValues } from 'utils/utils' interface DataloadSectionValueProps { @@ -39,10 +39,15 @@ const DataloadSectionValue = ({ ) } + const formattedValue = formatNumberValues( + dataload.value, + FluidType[fluidType], + true + ) + return ( <> - {formatNumberValues(dataload.value, FluidType[fluidType], true) >= - 1000 ? ( + {Number(formattedValue) >= 1000 ? ( <> {formatNumberValues(dataload.value, FluidType[fluidType])} <span className="text-18-normal"> diff --git a/src/components/ConsumptionVisualizer/EstimatedConsumptionModal.spec.tsx b/src/components/ConsumptionVisualizer/EstimatedConsumptionModal.spec.tsx index 12f759dc55119d8b30ae673e2f712832d2745a5f..6c6816dff5e797fce51b7a35c762fe908a279628 100644 --- a/src/components/ConsumptionVisualizer/EstimatedConsumptionModal.spec.tsx +++ b/src/components/ConsumptionVisualizer/EstimatedConsumptionModal.spec.tsx @@ -1,7 +1,6 @@ -import React from 'react' import { mount } from 'enzyme' +import React from 'react' import { Provider } from 'react-redux' - import configureStore from 'redux-mock-store' import { mockInitialEcolyoState } from '../../../tests/__mocks__/store' import EstimatedConsumptionModal from './EstimatedConsumptionModal' @@ -16,6 +15,15 @@ jest.mock('cozy-ui/transpiled/react/I18n', () => { } }) +const mockGetAllLastPrices = jest.fn() +jest.mock('services/fluidsPrices.service', () => { + return jest.fn(() => { + return { + getAllLastPrices: mockGetAllLastPrices, + } + }) +}) + const mockStore = configureStore([]) const mockHandleClose = jest.fn() describe('EstimatedConsumptionModal component', () => { diff --git a/src/components/ConsumptionVisualizer/EstimatedConsumptionModal.tsx b/src/components/ConsumptionVisualizer/EstimatedConsumptionModal.tsx index 7d3c7fa407bfe08039e7d81f900d8403374fe5c9..267b981cdb1122fc7cce0a735602bd43da9de3e8 100644 --- a/src/components/ConsumptionVisualizer/EstimatedConsumptionModal.tsx +++ b/src/components/ConsumptionVisualizer/EstimatedConsumptionModal.tsx @@ -1,15 +1,15 @@ -import React, { useEffect, useState } from 'react' -import { useI18n } from 'cozy-ui/transpiled/react/I18n' +import { IconButton } from '@material-ui/core' import Dialog from '@material-ui/core/Dialog' -import { FluidType } from 'enum/fluid.enum' import CloseIcon from 'assets/icons/ico/close.svg' -import Icon from 'cozy-ui/transpiled/react/Icon' -import { IconButton } from '@material-ui/core' -import './estimatedConsumptionModal.scss' -import FluidPricesService from 'services/fluidsPrices.service' 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 { DateTime } from 'luxon' import { FluidPrice } from 'models' +import React, { useEffect, useState } from 'react' +import FluidPricesService from 'services/fluidsPrices.service' +import './estimatedConsumptionModal.scss' interface EstimatedConsumptionModalProps { open: boolean diff --git a/src/components/ConsumptionVisualizer/InfoDataConsumptionVisualizer.spec.tsx b/src/components/ConsumptionVisualizer/InfoDataConsumptionVisualizer.spec.tsx index 679d8ca0a069558a5214e2413d7e717f02f42ca0..b56ed2c52da501873dbe9514d7614c24938f119f 100644 --- a/src/components/ConsumptionVisualizer/InfoDataConsumptionVisualizer.spec.tsx +++ b/src/components/ConsumptionVisualizer/InfoDataConsumptionVisualizer.spec.tsx @@ -1,19 +1,16 @@ -import React from 'react' +import { DataloadState } from 'enum/dataload.enum' +import { FluidType } from 'enum/fluid.enum' import { mount } from 'enzyme' import toJson from 'enzyme-to-json' -import { Provider } from 'react-redux' -import * as reactRedux from 'react-redux' -import { - createMockStore, - mockInitialEcolyoState, -} from '../../../tests/__mocks__/store' -import { FluidType } from 'enum/fluid.enum' -import { Dataload } from 'models' 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 InfoDataConsumptionVisualizer from './InfoDataConsumptionVisualizer' -import { DataloadState } from 'enum/dataload.enum' import NoDataModal from './NoDataModal' -import { baseDataLoad } from '../../../tests/__mocks__/datachartData.mock' jest.mock('cozy-ui/transpiled/react/I18n', () => { return { @@ -33,10 +30,9 @@ describe('InfoDataConsumptionVisualizer component', () => { }) const mockDataload: Dataload = baseDataLoad - // eslint-disable-next-line @typescript-eslint/no-explicit-any - let store: any + const store = createMockEcolyoStore() beforeEach(() => { - store = createMockStore(mockInitialEcolyoState) + store.clearActions() }) it('should render correctly when data valid', () => { diff --git a/src/components/ConsumptionVisualizer/InfoDataConsumptionVisualizer.tsx b/src/components/ConsumptionVisualizer/InfoDataConsumptionVisualizer.tsx index 030ed6ae736ae4fc95a9830cb25904989d127383..b4524da551ebc4fafe33f835a41b6b3b131ed7ae 100644 --- a/src/components/ConsumptionVisualizer/InfoDataConsumptionVisualizer.tsx +++ b/src/components/ConsumptionVisualizer/InfoDataConsumptionVisualizer.tsx @@ -1,14 +1,14 @@ -import React, { useCallback, useState } from 'react' -import './infoDataConsumptionVisualizer.scss' import { useI18n } from 'cozy-ui/transpiled/react/I18n' -import { useDispatch, useSelector } from 'react-redux' +import { DataloadState } from 'enum/dataload.enum' +import { FluidType } from 'enum/fluid.enum' import { DateTime } from 'luxon' import { Dataload } from 'models' -import { FluidType } from 'enum/fluid.enum' -import { AppStore } from 'store' -import { setCurrentIndex, setSelectedDate } from 'store/chart/chart.actions' +import React, { Dispatch, useCallback, useState } from 'react' +import { useDispatch, useSelector } from 'react-redux' import DateChartService from 'services/dateChart.service' -import { DataloadState } from 'enum/dataload.enum' +import { AppActionsTypes, AppStore } from 'store' +import { setCurrentIndex, setSelectedDate } from 'store/chart/chart.actions' +import './infoDataConsumptionVisualizer.scss' import NoDataModal from './NoDataModal' interface InfoDataConsumptionVisualizerProps { @@ -23,7 +23,7 @@ const InfoDataConsumptionVisualizer = ({ lastDataDate, }: InfoDataConsumptionVisualizerProps) => { const { t } = useI18n() - const dispatch = useDispatch() + const dispatch = useDispatch<Dispatch<AppActionsTypes>>() const { currentTimeStep } = useSelector( (state: AppStore) => state.ecolyo.chart ) diff --git a/src/components/ConsumptionVisualizer/NoDataModal.spec.tsx b/src/components/ConsumptionVisualizer/NoDataModal.spec.tsx index d233665e12ecacb0436078ecd81839f41acd4d83..ca13f103c9b9e49161596d48110eab020b14facc 100644 --- a/src/components/ConsumptionVisualizer/NoDataModal.spec.tsx +++ b/src/components/ConsumptionVisualizer/NoDataModal.spec.tsx @@ -1,7 +1,6 @@ -import React from 'react' import { mount } from 'enzyme' +import React from 'react' import { Provider } from 'react-redux' - import configureStore from 'redux-mock-store' import { mockInitialEcolyoState } from '../../../tests/__mocks__/store' import NoDataModal from './NoDataModal' diff --git a/src/components/ConsumptionVisualizer/NoDataModal.tsx b/src/components/ConsumptionVisualizer/NoDataModal.tsx index b61a39f2560b65b25bc4416b78d92da8b0b77e41..11c362381192ab392d009f238999a7dd2609e3c6 100644 --- a/src/components/ConsumptionVisualizer/NoDataModal.tsx +++ b/src/components/ConsumptionVisualizer/NoDataModal.tsx @@ -1,10 +1,10 @@ -import React from 'react' -import { useI18n } from 'cozy-ui/transpiled/react/I18n' +import { Button, IconButton } from '@material-ui/core' import Dialog from '@material-ui/core/Dialog' import CloseIcon from 'assets/icons/ico/close.svg' import QuestionIcon from 'assets/icons/ico/questionMark.svg' +import { useI18n } from 'cozy-ui/transpiled/react/I18n' import Icon from 'cozy-ui/transpiled/react/Icon' -import { Button, IconButton } from '@material-ui/core' +import React from 'react' import './noDataModal.scss' interface NoDataModalProps { @@ -61,6 +61,10 @@ const NoDataModal: React.FC<NoDataModalProps> = ({ <span>• </span> {t('consumption_visualizer.dataModal.item3')} </div> + <div className="text-16-normal justified-text"> + <span>• </span> + {t('consumption_visualizer.dataModal.item4')} + </div> <Button aria-label={t('ecogesture_info_modal.button_close')} onClick={handleCloseClick} diff --git a/src/components/Content/Content.tsx b/src/components/Content/Content.tsx index 3f7e11a9aa3a6058a2cd7f223edf86427a51306f..cfef2245f554a0da3adbb4faffc3a5a6314c4244 100644 --- a/src/components/Content/Content.tsx +++ b/src/components/Content/Content.tsx @@ -1,10 +1,10 @@ import FeedbackModal from 'components/Feedback/FeedbackModal' import { ScreenType } from 'enum/screen.enum' -import React, { useCallback, useEffect } from 'react' +import React, { Dispatch, useCallback, useEffect } from 'react' import { useDispatch, useSelector } from 'react-redux' -import { AppStore } from 'store' +import { AppActionsTypes, AppStore } from 'store' import { changeScreenType } from 'store/global/global.actions' -import { updateModalIsFeedbacksOpen } from 'store/modal/modal.actions' +import { openFeedbackModal } from 'store/modal/modal.actions' import './content.scss' interface ContentProps { children?: React.ReactNode @@ -17,17 +17,17 @@ const Content: React.FC<ContentProps> = ({ height = 0, background = 'inherit', }: ContentProps) => { - const dispatch = useDispatch() - const { screenType } = useSelector((state: AppStore) => state.ecolyo.global) - const { isFeedbacksOpen } = useSelector( - (state: AppStore) => state.ecolyo.modal - ) + const dispatch = useDispatch<Dispatch<AppActionsTypes>>() + const { + global: { screenType }, + modal: { isFeedbacksOpen }, + } = useSelector((state: AppStore) => state.ecolyo) const cozyBarHeight = 48 const cozyNavHeight = 56 const handleFeedbackModalClose = useCallback(() => { - dispatch(updateModalIsFeedbacksOpen(false)) + dispatch(openFeedbackModal(false)) }, [dispatch]) // Set listeners for scroll diff --git a/src/components/DateNavigator/DateNavigator.spec.tsx b/src/components/DateNavigator/DateNavigator.spec.tsx index bfa2adf669b49e918aaea35a329ded17f0b74871..7c1f57700326aa79c96f0ce1163b3b9d3933c277 100644 --- a/src/components/DateNavigator/DateNavigator.spec.tsx +++ b/src/components/DateNavigator/DateNavigator.spec.tsx @@ -1,14 +1,14 @@ -import React from 'react' +import { IconButton } from '@material-ui/core' import { mount } from 'enzyme' import { DateTime } from 'luxon' -import * as reactRedux from 'react-redux' +import React from 'react' import { act } from 'react-dom/test-utils' -import { globalStateData } from '../../../tests/__mocks__/globalStateData.mock' +import * as reactRedux from 'react-redux' import { Provider } from 'react-redux' import configureStore from 'redux-mock-store' -import DateNavigator from './DateNavigator' +import { globalStateData } from '../../../tests/__mocks__/globalStateData.mock' import { mockInitialChartState } from '../../../tests/__mocks__/store' -import { IconButton } from '@material-ui/core' +import DateNavigator from './DateNavigator' jest.mock('cozy-ui/transpiled/react/I18n', () => { return { diff --git a/src/components/DateNavigator/DateNavigator.tsx b/src/components/DateNavigator/DateNavigator.tsx index 5a1936bad94e991a3dda66ffd4092045a3cab59e..9bdb35a7e6d6f32912b0a016cd17974d8ee138f1 100644 --- a/src/components/DateNavigator/DateNavigator.tsx +++ b/src/components/DateNavigator/DateNavigator.tsx @@ -8,10 +8,10 @@ import Icon from 'cozy-ui/transpiled/react/Icon' import { FluidType } from 'enum/fluid.enum' import { TimeStep } from 'enum/timeStep.enum' import { DateTime } from 'luxon' -import React from 'react' +import React, { Dispatch } from 'react' import { useDispatch, useSelector } from 'react-redux' import DateChartService from 'services/dateChart.service' -import { AppStore } from 'store' +import { AppActionsTypes, AppStore } from 'store' import { setCurrentIndex, setSelectedDate } from 'store/chart/chart.actions' import { isLastDateReached } from 'utils/date' import { isKonnectorActive } from 'utils/utils' @@ -29,11 +29,11 @@ const DateNavigator: React.FC<DateNavigatorProps> = ({ inlineDateDisplay = false, }: DateNavigatorProps) => { const { t } = useI18n() - const dispatch = useDispatch() - const { currentTimeStep, selectedDate, currentIndex } = useSelector( - (state: AppStore) => state.ecolyo.chart - ) - const { fluidStatus } = useSelector((state: AppStore) => state.ecolyo.global) + const dispatch = useDispatch<Dispatch<AppActionsTypes>>() + const { + chart: { currentTimeStep, selectedDate, currentIndex }, + global: { fluidStatus }, + } = useSelector((state: AppStore) => state.ecolyo) const disablePrev = selectedDate < @@ -65,7 +65,7 @@ const DateNavigator: React.FC<DateNavigatorProps> = ({ currentAnalysisDate, increment ) - setCurrentAnalysisDate && setCurrentAnalysisDate(updatedDate) + setCurrentAnalysisDate?.(updatedDate) } } diff --git a/src/components/Duel/DuelBar.tsx b/src/components/Duel/DuelBar.tsx index 976ab117515cd35e39e6c9c5681e1cd80173388e..9dfbb3d0df52e337a71b41478a4350b1889ef412 100644 --- a/src/components/Duel/DuelBar.tsx +++ b/src/components/Duel/DuelBar.tsx @@ -1,18 +1,15 @@ -import React from 'react' -import { useSelector } from 'react-redux' -import { AppStore } from 'store' - -import { scaleBand, ScaleBand, scaleLinear, ScaleLinear } from 'd3-scale' -import { DateTime } from 'luxon' - -import { TimeStep } from 'enum/timeStep.enum' -import { Dataload, UserChallenge } from 'models' - -import Bar from 'components/Charts/Bar' import AxisBottom from 'components/Charts/AxisBottom' 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 { DateTime } from 'luxon' +import { Dataload, UserChallenge } from 'models' +import React from 'react' +import { useSelector } from 'react-redux' +import { AppStore } from 'store' export interface BarChartProps { userChallenge: UserChallenge diff --git a/src/components/Duel/DuelChart.tsx b/src/components/Duel/DuelChart.tsx index 54538e998c97100782a69f08e9adec67e798a21c..eaa8d67195fbdaaea588bac2d525d34ba9d721a0 100644 --- a/src/components/Duel/DuelChart.tsx +++ b/src/components/Duel/DuelChart.tsx @@ -1,8 +1,8 @@ -import React, { useState, useEffect } from 'react' -import './duelChart.scss' +import DuelBar from 'components/Duel/DuelBar' import { TimeStep } from 'enum/timeStep.enum' import { Dataload, UserChallenge } from 'models' -import DuelBar from 'components/Duel/DuelBar' +import React, { useEffect, useState } from 'react' +import './duelChart.scss' interface DuelChartProps { userChallenge: UserChallenge diff --git a/src/components/Duel/DuelEmptyValueModal.tsx b/src/components/Duel/DuelEmptyValueModal.tsx index 373de8b10fe165385f668fa85950654358b1bf44..2fbdf024ad98f3a766d0ec8f37213d22f0259b96 100644 --- a/src/components/Duel/DuelEmptyValueModal.tsx +++ b/src/components/Duel/DuelEmptyValueModal.tsx @@ -1,13 +1,11 @@ -import { useI18n } from 'cozy-ui/transpiled/react/I18n' -import React, { useEffect, useState } from 'react' -import './duelEmptyValueModal.scss' - import Button from '@material-ui/core/Button' import Dialog from '@material-ui/core/Dialog' -import Icon from 'cozy-ui/transpiled/react/Icon' - 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 React, { useEffect, useState } from 'react' import { importIconById } from 'utils/utils' +import './duelEmptyValueModal.scss' interface DuelEmptyValueModalProps { open: boolean diff --git a/src/components/Duel/DuelOngoing.tsx b/src/components/Duel/DuelOngoing.tsx index 9e6646353bb28780b793e278761ecaf60a6de765..80ad04c31c9cd32b24b0c834dc588f85e1a15389 100644 --- a/src/components/Duel/DuelOngoing.tsx +++ b/src/components/Duel/DuelOngoing.tsx @@ -14,12 +14,19 @@ import { } from 'enum/userChallenge.enum' import { UserDuelState } from 'enum/userDuel.enum' import { Dataload, UserChallenge, UserDuel } from 'models' -import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react' +import React, { + Dispatch, + useCallback, + useEffect, + useMemo, + useRef, + useState, +} from 'react' import { useDispatch, useSelector } from 'react-redux' import { useNavigate } from 'react-router-dom' import ChallengeService from 'services/challenge.service' import UsageEventService from 'services/usageEvent.service' -import { AppStore } from 'store' +import { AppActionsTypes, AppStore } from 'store' import { unlockNextUserChallenge, updateUserChallengeList, @@ -39,22 +46,19 @@ const DuelOngoing: React.FC<DuelOngoingProps> = ({ }: DuelOngoingProps) => { const client: Client = useClient() const { t } = useI18n() - const { currentDataload } = useSelector( + const { currentDataload, userChallengeList } = useSelector( (state: AppStore) => state.ecolyo.challenge ) - const dispatch = useDispatch() + const dispatch = useDispatch<Dispatch<AppActionsTypes>>() const navigate = useNavigate() const [resultModal, setResultModal] = useState<boolean>(false) const [winChallenge, setWinChallenge] = useState<boolean>(false) const [isLastDuel, setIsLastDuel] = useState<boolean>(false) const [width, setWidth] = useState<number>(0) const [height, setHeight] = useState<number>(0) - const [finishedDataLoad, setfinishedDataLoad] = useState<Dataload[]>() + const [finishedDataLoad, setFinishedDataLoad] = useState<Dataload[]>() const chartContainer = useRef<HTMLDivElement>(null) const challengeService = useMemo(() => new ChallengeService(client), [client]) - const { userChallengeList } = useSelector( - (state: AppStore) => state.ecolyo.challenge - ) const duel: UserDuel = userChallenge.duel const title: string = duel.title @@ -157,7 +161,7 @@ const DuelOngoing: React.FC<DuelOngoingProps> = ({ const dataloads: Dataload[] = await challengeService.getUserChallengeDataload(userChallenge) if (subscribed) { - setfinishedDataLoad(dataloads) + setFinishedDataLoad(dataloads) } } } diff --git a/src/components/Duel/DuelResultModal.tsx b/src/components/Duel/DuelResultModal.tsx index b1b1d28086b8651616c59080b59f48e073d4d705..0c99d1a3a71b9b90ec7e288a64ce212e139ac7e0 100644 --- a/src/components/Duel/DuelResultModal.tsx +++ b/src/components/Duel/DuelResultModal.tsx @@ -1,14 +1,13 @@ +import Button from '@material-ui/core/Button' +import Dialog from '@material-ui/core/Dialog' +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 React, { useEffect, useState } from 'react' import { formatNumberValues, importIconById } from 'utils/utils' import './duelResultModal.scss' -import Button from '@material-ui/core/Button' -import Dialog from '@material-ui/core/Dialog' -import defaultIcon from 'assets/icons/visu/duelResult/default.svg' -import Icon from 'cozy-ui/transpiled/react/Icon' - interface DuelResultModalProps { open: boolean userChallenge: UserChallenge diff --git a/src/components/Duel/DuelUnlocked.spec.tsx b/src/components/Duel/DuelUnlocked.spec.tsx index cbc81c630edb99cb32fdb76bff01414b870abd21..cf155a120faac08c69d2141685bf8e48968b2b42 100644 --- a/src/components/Duel/DuelUnlocked.spec.tsx +++ b/src/components/Duel/DuelUnlocked.spec.tsx @@ -1,4 +1,5 @@ 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' @@ -7,6 +8,7 @@ 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' @@ -20,7 +22,7 @@ jest.mock('cozy-ui/transpiled/react/I18n', () => { }), } }) -const mockImportIconById = jest.fn() +const mockImportIconById = jest.fn(() => defaultIcon) const mockFormatNumberValues = jest.fn() jest.mock('utils/utils', () => { return { @@ -43,9 +45,21 @@ jest.mock('services/challenge.service', () => { }) }) +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: { diff --git a/src/components/Duel/DuelUnlocked.tsx b/src/components/Duel/DuelUnlocked.tsx index 328d791c8489c74edc5a58433c139e16047d2f93..8128a5539b3a88afaad6e58948667c2d0c0639f2 100644 --- a/src/components/Duel/DuelUnlocked.tsx +++ b/src/components/Duel/DuelUnlocked.tsx @@ -1,21 +1,21 @@ +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 { useI18n } from 'cozy-ui/transpiled/react/I18n' +import { UsageEventType } from 'enum/usageEvent.enum' +import { UserChallengeUpdateFlag } from 'enum/userChallenge.enum' import { UserChallenge } from 'models' -import React, { useCallback, useEffect, useState } from 'react' +import React, { Dispatch, useCallback, useEffect, useState } from 'react' import { useDispatch } from 'react-redux' import ChallengeService from 'services/challenge.service' +import UsageEventService from 'services/usageEvent.service' +import { AppActionsTypes } from 'store' import { setChallengeConsumption } from 'store/challenge/challenge.actions' import { formatNumberValues, importIconById } from 'utils/utils' import './duelUnlocked.scss' -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 { UsageEventType } from 'enum/usageEvent.enum' -import { UserChallengeUpdateFlag } from 'enum/userChallenge.enum' -import UsageEventService from 'services/usageEvent.service' - interface DuelUnlockedProps { userChallenge: UserChallenge } @@ -24,7 +24,7 @@ const DuelUnlocked: React.FC<DuelUnlockedProps> = ({ userChallenge, }: DuelUnlockedProps) => { const client: Client = useClient() - const dispatch = useDispatch() + const dispatch = useDispatch<Dispatch<AppActionsTypes>>() const { t } = useI18n() const [duelIcon, setDuelIcon] = useState(defaultIcon) diff --git a/src/components/Duel/duelChart.scss b/src/components/Duel/duelChart.scss index e44d6484fb1368c6682a3b4666832c1367fc1c10..459de5914467eb9afd79a0154100b896ceefd453 100644 --- a/src/components/Duel/duelChart.scss +++ b/src/components/Duel/duelChart.scss @@ -1,8 +1,7 @@ @import '../../styles/base/color'; @import '../../styles/base/breakpoint'; - .chart-root { margin-bottom: 1rem; max-width: 400px; -} \ No newline at end of file +} diff --git a/src/components/Duel/duelEmptyValueModal.scss b/src/components/Duel/duelEmptyValueModal.scss index aedd0ae584572d3fe31404503a00e86b336c3075..e0b34f0ec3f3592799701877b2745ce04043594f 100644 --- a/src/components/Duel/duelEmptyValueModal.scss +++ b/src/components/Duel/duelEmptyValueModal.scss @@ -7,7 +7,7 @@ align-items: center; padding: 1.5rem 0.5rem; text-align: center; - .modal-empty-value-title{ + .modal-empty-value-title { margin: 2rem 0 1rem; } @@ -18,4 +18,4 @@ #accessibility-title { display: none; -} \ No newline at end of file +} diff --git a/src/components/Duel/lastDuelModal.spec.tsx b/src/components/Duel/lastDuelModal.spec.tsx index 10c3783167dfadf026429c797d88b2d8fadc3e0f..4001dd478a7dceb1714d6eefdebf93e65fc42d94 100644 --- a/src/components/Duel/lastDuelModal.spec.tsx +++ b/src/components/Duel/lastDuelModal.spec.tsx @@ -1,5 +1,5 @@ -import React from 'react' import { mount } from 'enzyme' +import React from 'react' import { act } from 'react-dom/test-utils' import LastDuelModal from './lastDuelModal' diff --git a/src/components/Duel/lastDuelModal.tsx b/src/components/Duel/lastDuelModal.tsx index 97ac7a1a5f389b4b409bc55a46fb8d4052a801c6..00d2985a6f20387d509ce152555f2685e4e207cf 100644 --- a/src/components/Duel/lastDuelModal.tsx +++ b/src/components/Duel/lastDuelModal.tsx @@ -1,10 +1,10 @@ -import React from 'react' -import './lastDuelModal.scss' -import { useI18n } from 'cozy-ui/transpiled/react/I18n' import Dialog from '@material-ui/core/Dialog' -import star from 'assets/icons/visu/duel/star.svg' import CloseIcon from 'assets/icons/ico/close.svg' +import star from 'assets/icons/visu/duel/star.svg' import StyledIcon from 'components/CommonKit/Icon/StyledIcon' +import { useI18n } from 'cozy-ui/transpiled/react/I18n' +import React from 'react' +import './lastDuelModal.scss' interface LastDuelModalProps { open: boolean diff --git a/src/components/Ecogesture/EcogestureCard.tsx b/src/components/Ecogesture/EcogestureCard.tsx index d0c502e2cf344c2e43163bfd2ccb2085da0257ea..650846699ab4e18a6da6eafedfc7b5a8ad945dca 100644 --- a/src/components/Ecogesture/EcogestureCard.tsx +++ b/src/components/Ecogesture/EcogestureCard.tsx @@ -7,16 +7,16 @@ import React, { useEffect, useState } from 'react' import { Link as RouterLink } from 'react-router-dom' import { importIconById } from 'utils/utils' import './ecogestureCard.scss' -import EfficientyRating from './EfficientyRating' +import EfficiencyRating from './EfficiencyRating' interface EcogestureCardProps { ecogesture: Ecogesture - selectionCompleted: boolean + selectionCompleted?: boolean } const EcogestureCard: React.FC<EcogestureCardProps> = ({ ecogesture, - selectionCompleted, + selectionCompleted = false, }: EcogestureCardProps) => { const [ecogestureIcon, setEcogestureIcon] = useState<string>('') useEffect(() => { @@ -52,7 +52,7 @@ const EcogestureCard: React.FC<EcogestureCardProps> = ({ {ecogesture.shortName} </div> <div className="ec-content-efficiency"> - <EfficientyRating result={Math.round(ecogesture.efficiency)} /> + <EfficiencyRating result={Math.round(ecogesture.efficiency)} /> </div> </div> </div> diff --git a/src/components/Ecogesture/EcogestureEmptyList.spec.tsx b/src/components/Ecogesture/EcogestureEmptyList.spec.tsx index 09bfb0cc9e377400b21294eb8572f26b46da3830..09570fb09f8d25b80396bb03951eddc7384433c1 100644 --- a/src/components/Ecogesture/EcogestureEmptyList.spec.tsx +++ b/src/components/Ecogesture/EcogestureEmptyList.spec.tsx @@ -17,13 +17,15 @@ jest.mock('cozy-ui/transpiled/react/I18n', () => { }), } }) -const mockedNavigate = jest.fn() 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({ @@ -38,6 +40,7 @@ describe('EcogestureEmptyList component', () => { setTab={mockChangeTab} isObjective={true} isSelectionDone={false} + handleReinitClick={mockHandleClick} /> </Provider> ) @@ -56,6 +59,7 @@ describe('EcogestureEmptyList component', () => { setTab={mockChangeTab} isObjective={false} isSelectionDone={true} + handleReinitClick={mockHandleClick} /> </Provider> ) @@ -75,6 +79,7 @@ describe('EcogestureEmptyList component', () => { setTab={mockChangeTab} isObjective={false} isSelectionDone={false} + handleReinitClick={mockHandleClick} /> </Provider> ) @@ -94,6 +99,7 @@ describe('EcogestureEmptyList component', () => { setTab={mockChangeTab} isObjective={false} isSelectionDone={true} + handleReinitClick={mockHandleClick} /> </Provider> ) @@ -115,6 +121,7 @@ describe('EcogestureEmptyList component', () => { setTab={mockChangeTab} isObjective={true} isSelectionDone={true} + handleReinitClick={mockHandleClick} /> </Provider> ) diff --git a/src/components/Ecogesture/EcogestureEmptyList.tsx b/src/components/Ecogesture/EcogestureEmptyList.tsx index dfeb15139aa0387088e93412481be8f1bb93991b..521cf35fd068c437da07b0ed2be69cd6ea6ba983 100644 --- a/src/components/Ecogesture/EcogestureEmptyList.tsx +++ b/src/components/Ecogesture/EcogestureEmptyList.tsx @@ -53,7 +53,7 @@ const EcogestureEmptyList: React.FC<EcogestureEmptyListProps> = ({ {isSelectionDone && ( <Button - aria-label={t('ecogesture.emptyList.reinit')} + aria-label={t('ecogesture.reinit')} onClick={handleReinitClick} classes={{ root: 'reinit-button btn-profile-next rounded', diff --git a/src/components/Ecogesture/EcogestureInitModal.tsx b/src/components/Ecogesture/EcogestureInitModal.tsx index 3993af59ede7ee0f1331df44dd66af18e193434b..38c4ab1cf0f93e5e1070d742421559f626ed8851 100644 --- a/src/components/Ecogesture/EcogestureInitModal.tsx +++ b/src/components/Ecogesture/EcogestureInitModal.tsx @@ -1,9 +1,9 @@ -import React from 'react' -import Dialog from '@material-ui/core/Dialog' import { Button, IconButton } from '@material-ui/core' -import Icon from 'cozy-ui/transpiled/react/Icon' -import { useI18n } from 'cozy-ui/transpiled/react/I18n' +import Dialog from '@material-ui/core/Dialog' 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 React from 'react' import './ecogestureInitModal.scss' interface EcogestureInitModalProps { open: boolean diff --git a/src/components/Ecogesture/EcogestureList.spec.tsx b/src/components/Ecogesture/EcogestureList.spec.tsx index e0ab6d225753f18c4b336200e5e58ed41beece17..0ea4f27a95bd46eb95c01c9bf30a27b98982954c 100644 --- a/src/components/Ecogesture/EcogestureList.spec.tsx +++ b/src/components/Ecogesture/EcogestureList.spec.tsx @@ -1,14 +1,14 @@ -import React from 'react' -import { mount } from 'enzyme' +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 { globalStateData } from '../../../tests/__mocks__/globalStateData.mock' import { ecogesturesData } from '../../../tests/__mocks__/ecogesturesData.mock' -import { BrowserRouter } from 'react-router-dom' -import { Button, MenuItem } from '@material-ui/core' +import { globalStateData } from '../../../tests/__mocks__/globalStateData.mock' import { waitForComponentToPaint } from '../../../tests/__mocks__/testUtils' jest.mock('cozy-ui/transpiled/react/I18n', () => { @@ -23,6 +23,7 @@ jest.mock('cozy-ui/transpiled/react/I18n', () => { jest.mock('components/Ecogesture/EcogestureCard', () => 'mock-ecogesturecard') const mockStore = configureStore([]) +const mockHandleReinit = jest.fn() describe('EcogesturesList component', () => { it('should be rendered correctly', async () => { @@ -40,6 +41,7 @@ describe('EcogesturesList component', () => { displaySelection={false} selectionTotal={0} selectionViewed={0} + handleReinitClick={mockHandleReinit} /> </BrowserRouter> </Provider> diff --git a/src/components/Ecogesture/EcogestureList.tsx b/src/components/Ecogesture/EcogestureList.tsx index 49e07606e07cdb627df50dee685696129b3ee260..5b652f69e4d0430a4d3d9cf5bd5c71bb676e369f 100644 --- a/src/components/Ecogesture/EcogestureList.tsx +++ b/src/components/Ecogesture/EcogestureList.tsx @@ -5,7 +5,7 @@ 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 { EcogestureStatus, Usage } from 'enum/ecogesture.enum' +import { Usage } from 'enum/ecogesture.enum' import { Ecogesture } from 'models' import React, { useState } from 'react' import { useNavigate } from 'react-router-dom' @@ -16,8 +16,7 @@ interface EcogestureListProps { displaySelection: boolean selectionTotal: number selectionViewed: number - index: number - handleReinitClick: () => void + handleReinitClick?: () => void } const EcogestureList: React.FC<EcogestureListProps> = ({ @@ -25,7 +24,6 @@ const EcogestureList: React.FC<EcogestureListProps> = ({ displaySelection, selectionTotal, selectionViewed, - index, handleReinitClick, }: EcogestureListProps) => { const { t } = useI18n() @@ -50,8 +48,8 @@ const EcogestureList: React.FC<EcogestureListProps> = ({ const filterEcogesture = (_ecogestures: Ecogesture[]) => { const filtered = _ecogestures .filter(ecogesture => Usage[ecogesture.usage] === activeFilter) - .map((ecogesture, index) => ( - <div key={index} className="ecogesture-list-item"> + .map(ecogesture => ( + <div key={ecogesture.id} className="ecogesture-list-item"> <EcogestureCard ecogesture={ecogesture} selectionCompleted={selectionViewed === selectionTotal} @@ -169,10 +167,10 @@ const EcogestureList: React.FC<EcogestureListProps> = ({ </div> <div className="ecogesture-content"> {list.length > 0 && activeFilter === Usage[Usage.ALL] - ? list.map((ecogesture, index) => ( + ? list.map(ecogesture => ( <EcogestureCard + key={ecogesture.id} ecogesture={ecogesture} - key={index} selectionCompleted={selectionViewed === selectionTotal} /> )) @@ -188,7 +186,7 @@ const EcogestureList: React.FC<EcogestureListProps> = ({ </div> </div> )} - {!displaySelection && index !== EcogestureStatus.ALL && ( + {!displaySelection && handleReinitClick && ( <button className="reinit-button" onClick={handleReinitClick}> <span>{t('ecogesture.reinit')}</span> </button> diff --git a/src/components/Ecogesture/EcogestureModal.tsx b/src/components/Ecogesture/EcogestureModal.tsx index e6abd217f67a318cb398c4a15dc6f7e230afbc2f..b5e5a3216623db05f9f39ebe044a988e7fba1919 100644 --- a/src/components/Ecogesture/EcogestureModal.tsx +++ b/src/components/Ecogesture/EcogestureModal.tsx @@ -1,23 +1,21 @@ +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 { getPicto } from 'utils/picto' import { importIconById } from 'utils/utils' import './ecogestureModal.scss' - -import { Ecogesture } from 'models' - -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 StyledIcon from 'components/CommonKit/Icon/StyledIcon' -import Icon from 'cozy-ui/transpiled/react/Icon' -import EfficientyRating from './EfficientyRating' +import EfficiencyRating from './EfficiencyRating' interface EcogestureModalProps { open: boolean @@ -103,7 +101,7 @@ const EcogestureModal: React.FC<EcogestureModalProps> = ({ <span className="em-efficiency"> {t('ecogesture_modal.efficiency')} </span> - <EfficientyRating result={Math.round(ecogesture.efficiency)} /> + <EfficiencyRating result={Math.round(ecogesture.efficiency)} /> </div> <div className="em-picto-flow"> {ecogesture.fluidTypes.map((fluid, index) => ( diff --git a/src/components/Ecogesture/EcogestureReinitModal.tsx b/src/components/Ecogesture/EcogestureReinitModal.tsx index cb6325857acdc3db7bfc7e071ff3c0f75f155939..15d9da6e9de373e4106bd2a16985373407851ab9 100644 --- a/src/components/Ecogesture/EcogestureReinitModal.tsx +++ b/src/components/Ecogesture/EcogestureReinitModal.tsx @@ -1,11 +1,11 @@ -import React from 'react' -import Dialog from '@material-ui/core/Dialog' import { Button, IconButton } from '@material-ui/core' -import Icon from 'cozy-ui/transpiled/react/Icon' -import { useI18n } from 'cozy-ui/transpiled/react/I18n' +import Dialog from '@material-ui/core/Dialog' import CloseIcon from 'assets/icons/ico/close.svg' -import './ecogestureReinitModal.scss' import warningIcon from 'assets/icons/ico/warn-orange.svg' +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 diff --git a/src/components/Ecogesture/EcogestureView.spec.tsx b/src/components/Ecogesture/EcogestureView.spec.tsx index 8a25aa6a6495e4623f2b1293f67afa5961956ab9..04f4eb18e8e38fe7704a9bfe585a2866e2fef7d5 100644 --- a/src/components/Ecogesture/EcogestureView.spec.tsx +++ b/src/components/Ecogesture/EcogestureView.spec.tsx @@ -9,8 +9,8 @@ import { Provider } from 'react-redux' import * as profileActions from 'store/profile/profile.actions' import { ecogesturesData } from '../../../tests/__mocks__/ecogesturesData.mock' import { - createMockStore, - mockInitialEcolyoState, + createMockEcolyoStore, + mockInitialProfileState, } from '../../../tests/__mocks__/store' import { waitForComponentToPaint } from '../../../tests/__mocks__/testUtils' import EcogestureEmptyList from './EcogestureEmptyList' @@ -25,22 +25,22 @@ jest.mock('cozy-ui/transpiled/react/I18n', () => { }), } }) -const mockgetAllEcogestures = jest.fn() +const mockGetAllEcogestures = jest.fn() const mockGetEcogestureListByProfile = jest.fn() jest.mock('services/ecogesture.service', () => { return jest.fn(() => { return { - getAllEcogestures: mockgetAllEcogestures, + getAllEcogestures: mockGetAllEcogestures, getEcogestureListByProfile: mockGetEcogestureListByProfile, } }) }) -const mockgetProfile = jest.fn() +const mockGetProfile = jest.fn() const mockUpdateProfile = jest.fn() jest.mock('services/profile.service', () => { return jest.fn(() => { return { - getProfile: mockgetProfile, + getProfile: mockGetProfile, updateProfile: mockUpdateProfile, } }) @@ -50,11 +50,11 @@ 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() +const mockGetSeason = jest.fn() jest.mock('utils/utils', () => { return { getSeason: jest.fn(() => { - return mockgetSeason + return mockGetSeason }), } }) @@ -71,23 +71,22 @@ jest.mock('react-router-dom', () => ({ })) describe('EcogestureView component', () => { - // eslint-disable-next-line @typescript-eslint/no-explicit-any - let store: any + const store = createMockEcolyoStore() beforeEach(() => { - store = createMockStore(mockInitialEcolyoState) - mockgetSeason.mockClear() - mockgetAllEcogestures.mockClear() + store.clearActions() + mockGetSeason.mockClear() + mockGetAllEcogestures.mockClear() mockGetEcogestureListByProfile.mockClear() }) it('should be rendered correctly', async () => { useSelectorSpy.mockReturnValue({ - ...mockInitialEcolyoState.profile, + profile: mockInitialProfileState, isProfileTypeCompleted: true, haveSeenEcogestureModal: true, }) - mockgetSeason.mockReturnValue(Season.WINTER) - mockgetAllEcogestures.mockResolvedValueOnce(ecogesturesData) + mockGetSeason.mockReturnValue(Season.WINTER) + mockGetAllEcogestures.mockResolvedValueOnce(ecogesturesData) mockGetEcogestureListByProfile.mockResolvedValue([]) const wrapper = mount( <Provider store={store}> @@ -103,12 +102,12 @@ describe('EcogestureView component', () => { const updateProfileSpy = jest.spyOn(profileActions, 'updateProfile') useSelectorSpy.mockReturnValue({ - ...mockInitialEcolyoState.profile, + profile: mockInitialProfileState, isProfileTypeCompleted: true, haveSeenEcogestureModal: false, }) - mockgetSeason.mockReturnValue(Season.WINTER) - mockgetAllEcogestures.mockResolvedValueOnce(ecogesturesData) + mockGetSeason.mockReturnValue(Season.WINTER) + mockGetAllEcogestures.mockResolvedValueOnce(ecogesturesData) mockGetEcogestureListByProfile.mockResolvedValueOnce([]) const wrapper = mount( <Provider store={store}> @@ -128,12 +127,12 @@ describe('EcogestureView component', () => { it('should render empty list', async () => { useSelectorSpy.mockReturnValue({ - ...mockInitialEcolyoState.profile, + profile: mockInitialProfileState, isProfileTypeCompleted: true, haveSeenEcogestureModal: false, }) - mockgetSeason.mockReturnValue(Season.WINTER) - mockgetAllEcogestures.mockResolvedValueOnce([]) + mockGetSeason.mockReturnValue(Season.WINTER) + mockGetAllEcogestures.mockResolvedValueOnce([]) mockGetEcogestureListByProfile.mockResolvedValueOnce([]) const wrapper = mount( <Provider store={store}> @@ -146,12 +145,12 @@ describe('EcogestureView component', () => { }) it('should change tab', async () => { useSelectorSpy.mockReturnValue({ - ...mockInitialEcolyoState.profile, + profile: mockInitialProfileState, isProfileTypeCompleted: true, haveSeenEcogestureModal: true, }) - mockgetSeason.mockReturnValue(Season.WINTER) - mockgetAllEcogestures.mockResolvedValueOnce(ecogesturesData) + mockGetSeason.mockReturnValue(Season.WINTER) + mockGetAllEcogestures.mockResolvedValueOnce(ecogesturesData) mockGetEcogestureListByProfile.mockResolvedValueOnce([]) const wrapper = mount( <Provider store={store}> @@ -161,7 +160,7 @@ describe('EcogestureView component', () => { await waitForComponentToPaint(wrapper) wrapper.find(Tab).first().simulate('click') - mockgetAllEcogestures.mockResolvedValueOnce([]) + mockGetAllEcogestures.mockResolvedValueOnce([]) await waitForComponentToPaint(wrapper) diff --git a/src/components/Ecogesture/EcogestureView.tsx b/src/components/Ecogesture/EcogestureView.tsx index 412756216520f5113f5a1f71c9181360cebb7198..626ddc4635e43da3dd48983843c89421a9a1c5cb 100644 --- a/src/components/Ecogesture/EcogestureView.tsx +++ b/src/components/Ecogesture/EcogestureView.tsx @@ -7,14 +7,13 @@ 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 { EcogestureStatus } from 'enum/ecogesture.enum' +import { EcogestureTab } from 'enum/ecogesture.enum' import { Ecogesture } from 'models' -import { ProfileEcogesture } from 'models/profileEcogesture.model' -import React, { useCallback, useEffect, useState } from 'react' +import React, { Dispatch, useCallback, useEffect, useState } from 'react' import { useDispatch, useSelector } from 'react-redux' import { useLocation, useNavigate } from 'react-router-dom' import EcogestureService from 'services/ecogesture.service' -import { AppStore } from 'store' +import { AppActionsTypes, AppStore } from 'store' import { updateProfile } from 'store/profile/profile.actions' import { getSeason } from 'utils/utils' import EcogestureEmptyList from './EcogestureEmptyList' @@ -24,20 +23,20 @@ import './ecogestureView.scss' interface TabPanelProps { children?: React.ReactNode - index: number + tab: EcogestureTab value: number } const TabPanel: React.FC<TabPanelProps> = ({ children, - index, + tab, value, }: TabPanelProps) => { return ( <div role="tabpanel" - hidden={value !== index} - id={`simple-tabpanel-${index}`} - aria-labelledby={`simple-tab-${index}`} + hidden={value !== tab} + id={`simple-tabpanel-${tab}`} + aria-labelledby={`simple-tab-${tab}`} > {children} </div> @@ -51,19 +50,17 @@ const EcogestureView: React.FC = () => { } const { t } = useI18n() const client = useClient() - const dispatch = useDispatch() + const dispatch = useDispatch<Dispatch<AppActionsTypes>>() const tab = new URLSearchParams(useLocation().search).get('tab') - const profileType = useSelector((state: AppStore) => state.ecolyo.profileType) - const profileEcogesture: ProfileEcogesture = useSelector( - (state: AppStore) => state.ecolyo.profileEcogesture - ) + const { + profile: { haveSeenEcogestureModal, isProfileEcogestureCompleted }, + profileEcogesture, + profileType, + } = useSelector((state: AppStore) => state.ecolyo) - const { haveSeenEcogestureModal, isProfileEcogestureCompleted } = useSelector( - (state: AppStore) => state.ecolyo.profile - ) - const [tabValue, setTabValue] = useState<EcogestureStatus>( - tab ? parseInt(tab) : EcogestureStatus.OBJECTIVE + const [tabValue, setTabValue] = useState<EcogestureTab>( + tab ? parseInt(tab) : EcogestureTab.OBJECTIVE ) const navigate = useNavigate() const [isLoaded, setIsLoaded] = useState<boolean>(false) @@ -130,16 +127,19 @@ const EcogestureView: React.FC = () => { } }, []) - const getLabel = useCallback( - (_tab: number) => { + const getTabLabel = useCallback( + (tab: EcogestureTab) => { + const tabCounts = { + [EcogestureTab.OBJECTIVE]: objectiveEcogestureList.length, + [EcogestureTab.DOING]: doingEcogestureList.length, + [EcogestureTab.ALL]: allEcogestureList.length, + } + return ( <> - {t(`ecogesture.title_tab_${_tab}`)} - <br></br> - {_tab === EcogestureStatus.OBJECTIVE && - `(${objectiveEcogestureList.length})`} - {_tab === EcogestureStatus.DOING && `(${doingEcogestureList.length})`} - {_tab === EcogestureStatus.ALL && `(${allEcogestureList.length})`} + {t(`ecogesture.title_tab_${tab}`)} + <br /> + {`(${tabCounts[tab]})`} </> ) }, @@ -205,31 +205,31 @@ const EcogestureView: React.FC = () => { centered={true} > <Tab - label={getLabel(EcogestureStatus.OBJECTIVE)} + label={getTabLabel(EcogestureTab.OBJECTIVE)} className={classNames('single-tab', { - ['active']: tabValue === EcogestureStatus.OBJECTIVE, + ['active']: tabValue === EcogestureTab.OBJECTIVE, })} - {...tabProps(EcogestureStatus.OBJECTIVE)} + {...tabProps(EcogestureTab.OBJECTIVE)} /> <Tab - label={getLabel(EcogestureStatus.DOING)} + label={getTabLabel(EcogestureTab.DOING)} className={classNames('single-tab', { - ['active']: tabValue === EcogestureStatus.DOING, + ['active']: tabValue === EcogestureTab.DOING, })} - {...tabProps(EcogestureStatus.DOING)} + {...tabProps(EcogestureTab.DOING)} /> <Tab - label={getLabel(EcogestureStatus.ALL)} + label={getTabLabel(EcogestureTab.ALL)} className={classNames('single-tab', { - ['active']: tabValue === EcogestureStatus.ALL, + ['active']: tabValue === EcogestureTab.ALL, })} - {...tabProps(EcogestureStatus.ALL)} + {...tabProps(EcogestureTab.ALL)} /> </Tabs> </Header> <Content height={headerHeight}> - <TabPanel value={tabValue} index={EcogestureStatus.OBJECTIVE}> + <TabPanel value={tabValue} tab={EcogestureTab.OBJECTIVE}> {isProfileEcogestureCompleted && (totalAvailable === totalViewed && objectiveEcogestureList.length === 0 ? ( @@ -245,7 +245,6 @@ const EcogestureView: React.FC = () => { displaySelection={totalAvailable !== totalViewed} selectionTotal={totalAvailable} selectionViewed={totalViewed} - index={EcogestureStatus.OBJECTIVE} handleReinitClick={handleReinitClick} /> ))} @@ -259,7 +258,7 @@ const EcogestureView: React.FC = () => { )} </TabPanel> - <TabPanel value={tabValue} index={EcogestureStatus.DOING}> + <TabPanel value={tabValue} tab={EcogestureTab.DOING}> {isProfileEcogestureCompleted && (totalAvailable === totalViewed && doingEcogestureList.length === 0 ? ( @@ -275,7 +274,6 @@ const EcogestureView: React.FC = () => { displaySelection={totalAvailable !== totalViewed} selectionTotal={totalAvailable} selectionViewed={totalViewed} - index={EcogestureStatus.DOING} handleReinitClick={handleReinitClick} /> ))} @@ -289,15 +287,13 @@ const EcogestureView: React.FC = () => { )} </TabPanel> - <TabPanel value={tabValue} index={EcogestureStatus.ALL}> - {allEcogestureList.length && ( + <TabPanel value={tabValue} tab={EcogestureTab.ALL}> + {Boolean(allEcogestureList.length) && ( <EcogestureList list={allEcogestureList} displaySelection={false} selectionTotal={totalAvailable} selectionViewed={totalViewed} - index={EcogestureStatus.ALL} - handleReinitClick={handleReinitClick} /> )} </TabPanel> diff --git a/src/components/Ecogesture/EfficientyRating.spec.tsx b/src/components/Ecogesture/EfficiencyRating.spec.tsx similarity index 85% rename from src/components/Ecogesture/EfficientyRating.spec.tsx rename to src/components/Ecogesture/EfficiencyRating.spec.tsx index 6b28de3796cfd74894268ca53e83d975ae5531fa..4cf025b1fafee98dc16614d1a033a5267263a39c 100644 --- a/src/components/Ecogesture/EfficientyRating.spec.tsx +++ b/src/components/Ecogesture/EfficiencyRating.spec.tsx @@ -1,7 +1,7 @@ -import React from 'react' +import EfficiencyRating from 'components/Ecogesture/EfficiencyRating' import { mount } from 'enzyme' -import EfficientyRating from 'components/Ecogesture/EfficientyRating' 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' @@ -19,7 +19,7 @@ jest.mock('cozy-ui/transpiled/react/I18n', () => { const mockStore = configureStore([]) -describe('EfficientyRating component', () => { +describe('EfficiencyRating component', () => { it('should be rendered correctly', () => { const store = mockStore({ ecolyo: { @@ -29,7 +29,7 @@ describe('EfficientyRating component', () => { }) const wrapper = mount( <Provider store={store}> - <EfficientyRating result={3} /> + <EfficiencyRating result={3} /> </Provider> ) expect(toJson(wrapper)).toMatchSnapshot() diff --git a/src/components/Ecogesture/EfficiencyRating.tsx b/src/components/Ecogesture/EfficiencyRating.tsx new file mode 100644 index 0000000000000000000000000000000000000000..1bb2adc7a60b93a024834d58d1a788b9bea322f4 --- /dev/null +++ b/src/components/Ecogesture/EfficiencyRating.tsx @@ -0,0 +1,23 @@ +import thunderEmpty from 'assets/icons/visu/thunderEmpty.svg' +import thunderFilled from 'assets/icons/visu/thunderFilled.svg' +import StyledIcon from 'components/CommonKit/Icon/StyledIcon' +import React from 'react' + +const EfficiencyRating = ({ result }: { result: number }) => { + const maxStars = [1, 2, 3, 4, 5] + + return ( + <div className="thunder"> + {maxStars.map(star => ( + <StyledIcon + key={star} + className="star" + icon={result >= star ? thunderFilled : thunderEmpty} + size={15} + /> + ))} + </div> + ) +} + +export default EfficiencyRating diff --git a/src/components/Ecogesture/EfficientyRating.tsx b/src/components/Ecogesture/EfficientyRating.tsx deleted file mode 100644 index e9fa30bf390b31f92145544d8874e2de635817c0..0000000000000000000000000000000000000000 --- a/src/components/Ecogesture/EfficientyRating.tsx +++ /dev/null @@ -1,41 +0,0 @@ -import React from 'react' -import StyledIcon from 'components/CommonKit/Icon/StyledIcon' -import thunderFilled from 'assets/icons/visu/thunderFilled.svg' -import thunderEmpty from 'assets/icons/visu/thunderEmpty.svg' - -interface EfficientyRatingProps { - result: number -} - -const EfficientyRating: React.FC<EfficientyRatingProps> = ({ - result, -}: EfficientyRatingProps) => { - const maxStars = [1, 2, 3, 4, 5] - - return ( - <div className="thunder"> - {maxStars.map((number, i) => { - if (number <= result) - return ( - <StyledIcon - key={i} - className="star" - icon={thunderFilled} - size={15} - /> - ) - else - return ( - <StyledIcon - key={i} - className="star" - icon={thunderEmpty} - size={15} - /> - ) - })} - </div> - ) -} - -export default EfficientyRating diff --git a/src/components/Ecogesture/SingleEcogesture.spec.tsx b/src/components/Ecogesture/SingleEcogesture.spec.tsx index ce940c2a238190f33ccc1c409909dc27188586f1..140a42012eba7cd9fbfd0acf43d1cc5b82a4767d 100644 --- a/src/components/Ecogesture/SingleEcogesture.spec.tsx +++ b/src/components/Ecogesture/SingleEcogesture.spec.tsx @@ -37,8 +37,8 @@ jest.mock('utils/utils', () => { } }) -jest.mock('components/Ecogesture/EfficientyRating', () => () => ( - <div id="EfficientyRating" /> +jest.mock('components/Ecogesture/EfficiencyRating', () => () => ( + <div id="EfficiencyRating" /> )) jest.mock('components/Header/Header', () => () => <div id="Header" />) jest.mock('components/Header/CozyBar', () => () => <div id="CozyBar" />) diff --git a/src/components/Ecogesture/SingleEcogesture.tsx b/src/components/Ecogesture/SingleEcogesture.tsx index 58b9237fa77d9516f247ad05f6aa865fbb839415..ec5c06c56355dd76471d70663579cf2bfa864e80 100644 --- a/src/components/Ecogesture/SingleEcogesture.tsx +++ b/src/components/Ecogesture/SingleEcogesture.tsx @@ -22,7 +22,7 @@ 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 EfficientyRating from './EfficientyRating' +import EfficiencyRating from './EfficiencyRating' import './singleEcogesture.scss' interface EcogestureLocation extends Location { @@ -134,13 +134,13 @@ const SingleEcogesture: React.FC = () => { return ( <> <CozyBar - titleKey={t('common.title_ecogesture')} + titleKey={'common.title_ecogesture'} displayBackArrow={true} backFunction={() => navigate('/ecogestures')} /> <Header setHeaderHeight={defineHeaderHeight} - desktopTitleKey={t('common.title_ecogesture')} + desktopTitleKey={'common.title_ecogesture'} displayBackArrow={true} /> <Content height={headerHeight}> @@ -160,7 +160,7 @@ const SingleEcogesture: React.FC = () => { <span className="text text-14-normal"> {t('ecogesture_modal.efficiency')} </span> - <EfficientyRating result={Math.round(ecogesture.efficiency)} /> + <EfficiencyRating result={Math.round(ecogesture.efficiency)} /> </div> </div> <div className="styled-container"> diff --git a/src/components/Ecogesture/__snapshots__/EcogestureCard.spec.tsx.snap b/src/components/Ecogesture/__snapshots__/EcogestureCard.spec.tsx.snap index 255097ff63691bdc6d98b5f3f83d3cd3ddeba081..ff294fcfbbb6576ea20f845c19234af57012df4b 100644 --- a/src/components/Ecogesture/__snapshots__/EcogestureCard.spec.tsx.snap +++ b/src/components/Ecogesture/__snapshots__/EcogestureCard.spec.tsx.snap @@ -90,7 +90,7 @@ exports[`EcogestureCard component should be rendered correctly 1`] = ` } state={ Object { - "selectionCompleted": undefined, + "selectionCompleted": false, } } to={ @@ -120,7 +120,7 @@ exports[`EcogestureCard component should be rendered correctly 1`] = ` } state={ Object { - "selectionCompleted": undefined, + "selectionCompleted": false, } } to={ @@ -143,7 +143,7 @@ exports[`EcogestureCard component should be rendered correctly 1`] = ` onFocus={[Function]} state={ Object { - "selectionCompleted": undefined, + "selectionCompleted": false, } } to={ @@ -201,7 +201,7 @@ exports[`EcogestureCard component should be rendered correctly 1`] = ` onFocus={[Function]} state={ Object { - "selectionCompleted": undefined, + "selectionCompleted": false, } } to={ @@ -217,7 +217,7 @@ exports[`EcogestureCard component should be rendered correctly 1`] = ` onFocus={[Function]} state={ Object { - "selectionCompleted": undefined, + "selectionCompleted": false, } } to={ @@ -328,7 +328,7 @@ exports[`EcogestureCard component should be rendered correctly 1`] = ` <div className="ec-content-efficiency" > - <EfficientyRating + <EfficiencyRating result={4} > <div @@ -337,7 +337,7 @@ exports[`EcogestureCard component should be rendered correctly 1`] = ` <Component className="star" icon="test-file-stub" - key="0" + key="1" size={15} > <div @@ -347,7 +347,7 @@ exports[`EcogestureCard component should be rendered correctly 1`] = ` <Component className="star" icon="test-file-stub" - key="1" + key="2" size={15} > <div @@ -357,7 +357,7 @@ exports[`EcogestureCard component should be rendered correctly 1`] = ` <Component className="star" icon="test-file-stub" - key="2" + key="3" size={15} > <div @@ -367,7 +367,7 @@ exports[`EcogestureCard component should be rendered correctly 1`] = ` <Component className="star" icon="test-file-stub" - key="3" + key="4" size={15} > <div @@ -377,7 +377,7 @@ exports[`EcogestureCard component should be rendered correctly 1`] = ` <Component className="star" icon="test-file-stub" - key="4" + key="5" size={15} > <div @@ -385,7 +385,7 @@ exports[`EcogestureCard component should be rendered correctly 1`] = ` /> </Component> </div> - </EfficientyRating> + </EfficiencyRating> </div> </div> </div> diff --git a/src/components/Ecogesture/__snapshots__/EcogestureEmptyList.spec.tsx.snap b/src/components/Ecogesture/__snapshots__/EcogestureEmptyList.spec.tsx.snap index 328305ab2f0a815cf71602e0cc0079e6e057a5c9..80b817f03803af8c47a20a7687266d4f6432ecd9 100644 --- a/src/components/Ecogesture/__snapshots__/EcogestureEmptyList.spec.tsx.snap +++ b/src/components/Ecogesture/__snapshots__/EcogestureEmptyList.spec.tsx.snap @@ -14,6 +14,7 @@ exports[`EcogestureEmptyList component should be rendered correctly 1`] = ` } > <EcogestureEmptyList + handleReinitClick={[MockFunction]} isObjective={true} isSelectionDone={false} setTab={[MockFunction]} diff --git a/src/components/Ecogesture/__snapshots__/EcogestureList.spec.tsx.snap b/src/components/Ecogesture/__snapshots__/EcogestureList.spec.tsx.snap index 2e84f2bcb60fc29353a64a0c4180b180468c2935..426846c3562143ea6d12b4ecfd43f1c3bbabb057 100644 --- a/src/components/Ecogesture/__snapshots__/EcogestureList.spec.tsx.snap +++ b/src/components/Ecogesture/__snapshots__/EcogestureList.spec.tsx.snap @@ -46,6 +46,7 @@ exports[`EcogesturesList component should be rendered correctly 1`] = ` > <EcogestureList displaySelection={false} + handleReinitClick={[MockFunction]} list={ Array [ Object { @@ -100,7 +101,7 @@ exports[`EcogesturesList component should be rendered correctly 1`] = ` "id": "ECOGESTURE002", "impactLevel": 8, "investment": null, - "longDescription": "Cela permet de garder la fraicheur à l'intérieur. Le climatiseur n'est pas là pour refroidir la rue mais bien la pièce.", + "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", "objective": false, "room": Array [ @@ -1870,7 +1871,7 @@ exports[`EcogesturesList component should be rendered correctly 1`] = ` "viewedInSelection": false, } } - key="0" + key="ECOGESTURE001" selectionCompleted={true} /> <mock-ecogesturecard @@ -1896,7 +1897,7 @@ exports[`EcogesturesList component should be rendered correctly 1`] = ` "id": "ECOGESTURE002", "impactLevel": 8, "investment": null, - "longDescription": "Cela permet de garder la fraicheur à l'intérieur. Le climatiseur n'est pas là pour refroidir la rue mais bien la pièce.", + "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", "objective": false, "room": Array [ @@ -1908,7 +1909,7 @@ exports[`EcogesturesList component should be rendered correctly 1`] = ` "viewedInSelection": false, } } - key="1" + key="ECOGESTURE002" selectionCompleted={true} /> <mock-ecogesturecard @@ -1949,11 +1950,12 @@ exports[`EcogesturesList component should be rendered correctly 1`] = ` "viewedInSelection": false, } } - key="2" + key="ECOGESTURE0013" selectionCompleted={true} /> <button className="reinit-button" + onClick={[MockFunction]} > <span> ecogesture.reinit diff --git a/src/components/Ecogesture/__snapshots__/EcogestureView.spec.tsx.snap b/src/components/Ecogesture/__snapshots__/EcogestureView.spec.tsx.snap index 6c9d81778a4947c8740c528210754d92536a5c28..d47df12610c87982a5271683ae4bad81ad318af7 100644 --- a/src/components/Ecogesture/__snapshots__/EcogestureView.spec.tsx.snap +++ b/src/components/Ecogesture/__snapshots__/EcogestureView.spec.tsx.snap @@ -562,7 +562,7 @@ exports[`EcogestureView component should be rendered correctly 1`] = ` height={0} > <TabPanel - index={0} + tab={0} value={0} > <div @@ -898,7 +898,7 @@ exports[`EcogestureView component should be rendered correctly 1`] = ` </div> </TabPanel> <TabPanel - index={1} + tab={1} value={0} > <div @@ -1234,7 +1234,7 @@ exports[`EcogestureView component should be rendered correctly 1`] = ` </div> </TabPanel> <TabPanel - index={2} + tab={2} value={0} > <div @@ -1245,8 +1245,6 @@ exports[`EcogestureView component should be rendered correctly 1`] = ` > <mock-ecogesturelist displaySelection={false} - handleReinitClick={[Function]} - index={2} list={ Array [ Object { @@ -1301,7 +1299,7 @@ exports[`EcogestureView component should be rendered correctly 1`] = ` "id": "ECOGESTURE002", "impactLevel": 8, "investment": null, - "longDescription": "Cela permet de garder la fraicheur à l'intérieur. Le climatiseur n'est pas là pour refroidir la rue mais bien la pièce.", + "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", "objective": false, "room": Array [ @@ -1355,6 +1353,1132 @@ exports[`EcogestureView component should be rendered correctly 1`] = ` </div> </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]} + 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={[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 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={[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="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={[Function]} + > + <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={[Function]} + > + <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={[Function]} + 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={[Function]} + type="button" + > + <button + aria-label="ecogesture.initModal.btn1" + className="MuiButtonBase-root MuiButton-root btn-secondary-negative 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-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={[Function]} + > + <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={[Function]} + > + <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={[Function]} + 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={[Function]} + type="button" + > + <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" + > + <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> </EcogestureView> </Provider> `; diff --git a/src/components/Ecogesture/__snapshots__/EfficientyRating.spec.tsx.snap b/src/components/Ecogesture/__snapshots__/EfficiencyRating.spec.tsx.snap similarity index 97% rename from src/components/Ecogesture/__snapshots__/EfficientyRating.spec.tsx.snap rename to src/components/Ecogesture/__snapshots__/EfficiencyRating.spec.tsx.snap index 596e41d6d8ac9ea60413be73af4a3418efe19208..005c98b343ca3a95b56c1e53021a4a3b077dd3de 100644 --- a/src/components/Ecogesture/__snapshots__/EfficientyRating.spec.tsx.snap +++ b/src/components/Ecogesture/__snapshots__/EfficiencyRating.spec.tsx.snap @@ -1,6 +1,6 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[`EfficientyRating component should be rendered correctly 1`] = ` +exports[`EfficiencyRating component should be rendered correctly 1`] = ` <Provider store={ Object { @@ -13,7 +13,7 @@ exports[`EfficientyRating component should be rendered correctly 1`] = ` } } > - <EfficientyRating + <EfficiencyRating result={3} > <div @@ -22,7 +22,7 @@ exports[`EfficientyRating component should be rendered correctly 1`] = ` <StyledIcon className="star" icon="test-file-stub" - key="0" + key="1" size={15} > <Icon @@ -56,7 +56,7 @@ exports[`EfficientyRating component should be rendered correctly 1`] = ` <StyledIcon className="star" icon="test-file-stub" - key="1" + key="2" size={15} > <Icon @@ -90,7 +90,7 @@ exports[`EfficientyRating component should be rendered correctly 1`] = ` <StyledIcon className="star" icon="test-file-stub" - key="2" + key="3" size={15} > <Icon @@ -124,7 +124,7 @@ exports[`EfficientyRating component should be rendered correctly 1`] = ` <StyledIcon className="star" icon="test-file-stub" - key="3" + key="4" size={15} > <Icon @@ -158,7 +158,7 @@ exports[`EfficientyRating component should be rendered correctly 1`] = ` <StyledIcon className="star" icon="test-file-stub" - key="4" + key="5" size={15} > <Icon @@ -190,6 +190,6 @@ exports[`EfficientyRating component should be rendered correctly 1`] = ` </Icon> </StyledIcon> </div> - </EfficientyRating> + </EfficiencyRating> </Provider> `; diff --git a/src/components/Ecogesture/__snapshots__/SingleEcogesture.spec.tsx.snap b/src/components/Ecogesture/__snapshots__/SingleEcogesture.spec.tsx.snap index 075ec115c2b7adc4044e2bf05343e7ddc876cbdd..2eb812c6fea8317a280b716740e2bb8956c4dd16 100644 --- a/src/components/Ecogesture/__snapshots__/SingleEcogesture.spec.tsx.snap +++ b/src/components/Ecogesture/__snapshots__/SingleEcogesture.spec.tsx.snap @@ -64,7 +64,7 @@ exports[`SingleEcogesture component should be rendered correctly 1`] = ` result={4} > <div - id="EfficientyRating" + id="EfficiencyRating" /> </Component> </div> diff --git a/src/components/EcogestureForm/EcogestureFormEquipment.tsx b/src/components/EcogestureForm/EcogestureFormEquipment.tsx index 654b26d1526c919dd139949d35b552c2eaba34d6..83a2009cadea5160deca61d7eda4fd5f862adb9c 100644 --- a/src/components/EcogestureForm/EcogestureFormEquipment.tsx +++ b/src/components/EcogestureForm/EcogestureFormEquipment.tsx @@ -5,10 +5,10 @@ import { EquipmentType } from 'enum/ecogesture.enum' import { EcogestureStepForm } from 'enum/ecogestureForm.enum' import { ProfileTypeStepForm } from 'enum/profileType.enum' import { ProfileEcogesture } from 'models/profileEcogesture.model' -import React, { useCallback, useState } from 'react' +import React, { Dispatch, useCallback, useState } from 'react' import { useDispatch, useSelector } from 'react-redux' import { useNavigate } from 'react-router-dom' -import { AppStore } from 'store' +import { AppActionsTypes, AppStore } from 'store' import { updateProfile } from 'store/profile/profile.actions' import { newProfileEcogestureEntry, @@ -31,7 +31,7 @@ const EcogestureFormEquipment: React.FC<EcogestureFormEquipmentProps> = ({ step, }: EcogestureFormEquipmentProps) => { const { t } = useI18n() - const dispatch = useDispatch() + const dispatch: Dispatch<AppActionsTypes> = useDispatch() const navigate = useNavigate() const { isProfileEcogestureCompleted } = useSelector( (state: AppStore) => state.ecolyo.profile @@ -101,26 +101,24 @@ const EcogestureFormEquipment: React.FC<EcogestureFormEquipmentProps> = ({ )} </div> <div className="icons-container"> - {Object.values(EquipmentType).map((equipment, index) => { - return ( - <label key={index} className={'checkbox-equipment'}> - <input - type={'checkbox'} - value={equipment} - name={equipment.toString()} - onChange={() => handleChange(equipment)} - checked={isChecked(equipment)} - className={ - isChecked(equipment) ? 'item-eq checked' : 'item-eq' - } - /> - <EquipmentIcon - equipment={equipment} - isChecked={answer.includes(equipment)} - /> - </label> - ) - })} + {Object.values(EquipmentType).map(equipment => ( + <label key={equipment} className={'checkbox-equipment'}> + <input + type={'checkbox'} + value={equipment} + name={equipment.toString()} + onChange={() => handleChange(equipment)} + checked={isChecked(equipment)} + className={ + isChecked(equipment) ? 'item-eq checked' : 'item-eq' + } + /> + <EquipmentIcon + equipment={equipment} + isChecked={answer.includes(equipment)} + /> + </label> + ))} </div> </div> </div> @@ -128,7 +126,7 @@ const EcogestureFormEquipment: React.FC<EcogestureFormEquipmentProps> = ({ step={step} handlePrevious={handlePrevious} handleNext={handleNext} - disableNextButton={answer === []} + disableNextButton={answer.length == 0} isEcogesture={true} /> </> diff --git a/src/components/EcogestureForm/EcogestureFormSingleChoice.spec.tsx b/src/components/EcogestureForm/EcogestureFormSingleChoice.spec.tsx index daddf3c16433cf763b89ff273ca058b7feaab98b..1f961c4a03fcb1dbd74113a1d55ba8b9c1c8f734 100644 --- a/src/components/EcogestureForm/EcogestureFormSingleChoice.spec.tsx +++ b/src/components/EcogestureForm/EcogestureFormSingleChoice.spec.tsx @@ -1,18 +1,14 @@ /* 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 { - createMockStore, - mockInitialEcolyoState, -} from '../../../tests/__mocks__/store' - -import { Button } from '@material-ui/core' import { mockEcogestureAnswer, mockProfileEcogesture, } from '../../../tests/__mocks__/profileEcogesture.mock' +import { createMockEcolyoStore } from '../../../tests/__mocks__/store' import { waitForComponentToPaint } from '../../../tests/__mocks__/testUtils' import EcogestureFormSingleChoice from './EcogestureFormSingleChoice' @@ -39,10 +35,9 @@ jest.mock( const mockHandleNextStep = jest.fn() const mockHandlePreviousStep = jest.fn() describe('EcogestureFormSingleChoice component', () => { - // eslint-disable-next-line @typescript-eslint/no-explicit-any - let store: any + const store = createMockEcolyoStore() beforeEach(() => { - store = createMockStore(mockInitialEcolyoState) + store.clearActions() }) it('should be rendered correctly', async () => { @@ -50,9 +45,9 @@ describe('EcogestureFormSingleChoice component', () => { <Provider store={store}> <EcogestureFormSingleChoice step={0} - viewedStep={-1} + viewedStep={1} setNextStep={mockHandleNextStep} - setPrevioustStep={mockHandlePreviousStep} + setPreviousStep={mockHandlePreviousStep} profileEcogesture={mockProfileEcogesture} answerType={mockEcogestureAnswer} /> @@ -66,9 +61,9 @@ describe('EcogestureFormSingleChoice component', () => { <Provider store={store}> <EcogestureFormSingleChoice step={0} - viewedStep={-1} + viewedStep={1} setNextStep={mockHandleNextStep} - setPrevioustStep={mockHandlePreviousStep} + setPreviousStep={mockHandlePreviousStep} profileEcogesture={mockProfileEcogesture} answerType={mockEcogestureAnswer} /> @@ -84,9 +79,9 @@ describe('EcogestureFormSingleChoice component', () => { <Provider store={store}> <EcogestureFormSingleChoice step={0} - viewedStep={-1} + viewedStep={1} setNextStep={mockHandleNextStep} - setPrevioustStep={mockHandlePreviousStep} + setPreviousStep={mockHandlePreviousStep} profileEcogesture={mockProfileEcogesture} answerType={mockEcogestureAnswer} /> @@ -106,7 +101,7 @@ describe('EcogestureFormSingleChoice component', () => { step={1} viewedStep={0} setNextStep={mockHandleNextStep} - setPrevioustStep={mockHandlePreviousStep} + setPreviousStep={mockHandlePreviousStep} profileEcogesture={mockProfileEcogesture} answerType={mockEcogestureAnswer} /> @@ -123,7 +118,7 @@ describe('EcogestureFormSingleChoice component', () => { step={0} viewedStep={1} setNextStep={mockHandleNextStep} - setPrevioustStep={mockHandlePreviousStep} + setPreviousStep={mockHandlePreviousStep} profileEcogesture={mockProfileEcogesture} answerType={mockEcogestureAnswer} /> diff --git a/src/components/EcogestureForm/EcogestureFormSingleChoice.tsx b/src/components/EcogestureForm/EcogestureFormSingleChoice.tsx index eab64499cd3bfdfcd56ac1e0e131613a806478bb..dbf9b2fe1956dcfe5ed5cc9c71312f57e7e0abb0 100644 --- a/src/components/EcogestureForm/EcogestureFormSingleChoice.tsx +++ b/src/components/EcogestureForm/EcogestureFormSingleChoice.tsx @@ -1,24 +1,24 @@ -import React, { useCallback, useEffect, useState } from 'react' -import 'components/ProfileType/profileTypeForm.scss' -import { useI18n } from 'cozy-ui/transpiled/react/I18n' import classNames from 'classnames' import FormNavigation from 'components/FormGlobal/FormNavigation' +import 'components/ProfileType/profileTypeForm.scss' +import { useI18n } from 'cozy-ui/transpiled/react/I18n' import { EcogestureStepForm } from 'enum/ecogestureForm.enum' import { ProfileEcogesture, ProfileEcogestureAnswer, ProfileEcogestureAnswerChoices, } from 'models/profileEcogesture.model' -import './ecogestureFormSingleChoice.scss' +import React, { useCallback, useEffect, useState } from 'react' import { useSelector } from 'react-redux' import { AppStore } from 'store' +import './ecogestureFormSingleChoice.scss' interface EcogestureFormSingleChoiceProps { step: EcogestureStepForm viewedStep: EcogestureStepForm profileEcogesture: ProfileEcogesture answerType: ProfileEcogestureAnswer setNextStep: Function - setPrevioustStep: Function + setPreviousStep: Function } const EcogestureFormSingleChoice: React.FC<EcogestureFormSingleChoiceProps> = ({ @@ -27,7 +27,7 @@ const EcogestureFormSingleChoice: React.FC<EcogestureFormSingleChoiceProps> = ({ profileEcogesture, answerType, setNextStep, - setPrevioustStep, + setPreviousStep, }: EcogestureFormSingleChoiceProps) => { const { t } = useI18n() const { isProfileEcogestureCompleted } = useSelector( @@ -38,8 +38,8 @@ const EcogestureFormSingleChoice: React.FC<EcogestureFormSingleChoiceProps> = ({ ) const handlePrevious = useCallback(() => { - setPrevioustStep(profileEcogesture) - }, [profileEcogesture, setPrevioustStep]) + setPreviousStep(profileEcogesture) + }, [profileEcogesture, setPreviousStep]) const handleAnswer = useCallback((value: ProfileEcogestureAnswerChoices) => { setAnswer(value) diff --git a/src/components/EcogestureForm/EcogestureFormView.spec.tsx b/src/components/EcogestureForm/EcogestureFormView.spec.tsx index ced14d322584a1e305bf25e77408304d441950b2..d8588e3e67171fccb5620bbee49c33052cacb65d 100644 --- a/src/components/EcogestureForm/EcogestureFormView.spec.tsx +++ b/src/components/EcogestureForm/EcogestureFormView.spec.tsx @@ -6,7 +6,7 @@ import { Profile } from 'models' import React from 'react' import { Provider } from 'react-redux' import { - createMockStore, + createMockEcolyoStore, mockInitialEcolyoState, } from '../../../tests/__mocks__/store' import { waitForComponentToPaint } from '../../../tests/__mocks__/testUtils' @@ -41,10 +41,9 @@ jest.mock('react-router-dom', () => ({ })) describe('EcogestureFormView component', () => { - // eslint-disable-next-line @typescript-eslint/no-explicit-any - let store: any + const store = createMockEcolyoStore() beforeEach(() => { - store = createMockStore(mockInitialEcolyoState) + store.clearActions() }) it('should be rendered correctly', async () => { @@ -72,7 +71,7 @@ describe('EcogestureFormView component', () => { } const updatedStore = { ...mockInitialEcolyoState, profile: updatedProfile } const wrapper = mount( - <Provider store={createMockStore(updatedStore)}> + <Provider store={createMockEcolyoStore(updatedStore)}> <EcogestureFormView /> </Provider> ) diff --git a/src/components/EcogestureForm/EcogestureFormView.tsx b/src/components/EcogestureForm/EcogestureFormView.tsx index c052ddf9a020ed73d597c606b5967454d1040716..b2fbe1779d04ecc9f6135e2fa64572d20df9dc0a 100644 --- a/src/components/EcogestureForm/EcogestureFormView.tsx +++ b/src/components/EcogestureForm/EcogestureFormView.tsx @@ -10,7 +10,6 @@ import { EcogestureStepForm, ProfileEcogestureAnswerType, } from 'enum/ecogestureForm.enum' -import { Profile } from 'models' import { ProfileEcogesture, ProfileEcogestureAnswer, @@ -26,12 +25,11 @@ const EcogestureFormView: React.FC = () => { const defineHeaderHeight = (height: number) => { setHeaderHeight(height) } - const { isProfileTypeCompleted }: Profile = useSelector( - (state: AppStore) => state.ecolyo.profile - ) - const curProfileEcogesture: ProfileEcogesture = useSelector( - (state: AppStore) => state.ecolyo.profileEcogesture - ) + const { + profile: { isProfileTypeCompleted }, + profileEcogesture: curProfileEcogesture, + } = useSelector((state: AppStore) => state.ecolyo) + const shouldOpenModal = new URLSearchParams(useLocation().search).get('modal') const [step, setStep] = useState<EcogestureStepForm>( EcogestureStepForm.HEATING_TYPE @@ -119,7 +117,7 @@ const EcogestureFormView: React.FC = () => { profileEcogesture={profileEcogesture} answerType={answerType} setNextStep={setNextStep} - setPrevioustStep={setPreviousStep} + setPreviousStep={setPreviousStep} /> )} </> diff --git a/src/components/EcogestureForm/EcogestureLaunchFormModal.spec.tsx b/src/components/EcogestureForm/EcogestureLaunchFormModal.spec.tsx index c41160d25732bac5a45416d1128c9ff9a16fecaf..6bd433f4919213f871dfca5a987f1b9f9b1a03a5 100644 --- a/src/components/EcogestureForm/EcogestureLaunchFormModal.spec.tsx +++ b/src/components/EcogestureForm/EcogestureLaunchFormModal.spec.tsx @@ -1,8 +1,8 @@ -import React from 'react' +import { Button } from '@material-ui/core' import { mount } from 'enzyme' import toJson from 'enzyme-to-json' +import React from 'react' import EcogestureLaunchFormModal from './EcogestureLaunchFormModal' -import { Button } from '@material-ui/core' jest.mock('cozy-ui/transpiled/react/I18n', () => { return { diff --git a/src/components/EcogestureForm/EcogestureLaunchFormModal.tsx b/src/components/EcogestureForm/EcogestureLaunchFormModal.tsx index 1a0ff36d5b6a42d5ed8ddc2b36007f5635b5c563..8e93c619c5f4f2e1ed050702aa534340bb9aaba0 100644 --- a/src/components/EcogestureForm/EcogestureLaunchFormModal.tsx +++ b/src/components/EcogestureForm/EcogestureLaunchFormModal.tsx @@ -1,9 +1,9 @@ -import React from 'react' -import Dialog from '@material-ui/core/Dialog' import { Button, IconButton } from '@material-ui/core' -import Icon from 'cozy-ui/transpiled/react/Icon' -import { useI18n } from 'cozy-ui/transpiled/react/I18n' +import Dialog from '@material-ui/core/Dialog' 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 React from 'react' import './ecogestureLaunchFormModal.scss' interface EcogestureLaunchFormModalProps { diff --git a/src/components/EcogestureForm/__snapshots__/EcogestureFormEquipment.spec.tsx.snap b/src/components/EcogestureForm/__snapshots__/EcogestureFormEquipment.spec.tsx.snap index ddc81916dc8bfdab84df561049c7ef8387b9ccf8..3d438e9efa10df387fc2ea4872131b93bc90c85a 100644 --- a/src/components/EcogestureForm/__snapshots__/EcogestureFormEquipment.spec.tsx.snap +++ b/src/components/EcogestureForm/__snapshots__/EcogestureFormEquipment.spec.tsx.snap @@ -47,7 +47,7 @@ exports[`EcogestureFormEquipment component should be rendered correctly 1`] = ` > <label className="checkbox-equipment" - key="0" + key="AIR_CONDITIONING" > <input checked={false} @@ -64,7 +64,7 @@ exports[`EcogestureFormEquipment component should be rendered correctly 1`] = ` </label> <label className="checkbox-equipment" - key="1" + key="COMPUTER" > <input checked={false} @@ -81,7 +81,7 @@ exports[`EcogestureFormEquipment component should be rendered correctly 1`] = ` </label> <label className="checkbox-equipment" - key="2" + key="MICROWAVE" > <input checked={false} @@ -98,7 +98,7 @@ exports[`EcogestureFormEquipment component should be rendered correctly 1`] = ` </label> <label className="checkbox-equipment" - key="3" + key="WASHING_MACHINE" > <input checked={false} @@ -115,7 +115,7 @@ exports[`EcogestureFormEquipment component should be rendered correctly 1`] = ` </label> <label className="checkbox-equipment" - key="4" + key="DISHWASHER" > <input checked={false} @@ -132,7 +132,7 @@ exports[`EcogestureFormEquipment component should be rendered correctly 1`] = ` </label> <label className="checkbox-equipment" - key="5" + key="COOKING_PLATES" > <input checked={false} @@ -149,7 +149,7 @@ exports[`EcogestureFormEquipment component should be rendered correctly 1`] = ` </label> <label className="checkbox-equipment" - key="6" + key="DRYER" > <input checked={false} @@ -166,7 +166,7 @@ exports[`EcogestureFormEquipment component should be rendered correctly 1`] = ` </label> <label className="checkbox-equipment" - key="7" + key="REFREGIRATOR" > <input checked={false} @@ -183,7 +183,7 @@ exports[`EcogestureFormEquipment component should be rendered correctly 1`] = ` </label> <label className="checkbox-equipment" - key="8" + key="FAN" > <input checked={false} @@ -200,7 +200,7 @@ exports[`EcogestureFormEquipment component should be rendered correctly 1`] = ` </label> <label className="checkbox-equipment" - key="9" + key="CURTAIN" > <input checked={false} @@ -217,7 +217,7 @@ exports[`EcogestureFormEquipment component should be rendered correctly 1`] = ` </label> <label className="checkbox-equipment" - key="10" + key="INTERNET_BOX" > <input checked={false} @@ -234,7 +234,7 @@ exports[`EcogestureFormEquipment component should be rendered correctly 1`] = ` </label> <label className="checkbox-equipment" - key="11" + key="VENTILATION" > <input checked={false} @@ -251,7 +251,7 @@ exports[`EcogestureFormEquipment component should be rendered correctly 1`] = ` </label> <label className="checkbox-equipment" - key="12" + key="FREEZER" > <input checked={false} @@ -268,7 +268,7 @@ exports[`EcogestureFormEquipment component should be rendered correctly 1`] = ` </label> <label className="checkbox-equipment" - key="13" + key="BOILER" > <input checked={false} @@ -285,7 +285,7 @@ exports[`EcogestureFormEquipment component should be rendered correctly 1`] = ` </label> <label className="checkbox-equipment" - key="14" + key="HYDRAULIC_HEATING" > <input checked={false} @@ -304,7 +304,7 @@ exports[`EcogestureFormEquipment component should be rendered correctly 1`] = ` </div> </div> <FormNavigation - disableNextButton={false} + disableNextButton={true} handleNext={[Function]} handlePrevious={[Function]} isEcogesture={true} @@ -422,19 +422,19 @@ exports[`EcogestureFormEquipment component should be rendered correctly 1`] = ` </WithStyles(ForwardRef(Button))> <WithStyles(ForwardRef(Button)) aria-label="profile_type.accessibility.button_next" - className="profile-navigation-button" + className="profile-navigation-button disabled" classes={ Object { "label": "text-16-bold", "root": "btn-profile-next", } } - disabled={false} + disabled={true} onClick={[Function]} > <ForwardRef(Button) aria-label="profile_type.accessibility.button_next" - className="profile-navigation-button" + className="profile-navigation-button disabled" classes={ Object { "colorInherit": "MuiButton-colorInherit", @@ -468,14 +468,14 @@ exports[`EcogestureFormEquipment component should be rendered correctly 1`] = ` "textSizeSmall": "MuiButton-textSizeSmall", } } - disabled={false} + disabled={true} onClick={[Function]} > <WithStyles(ForwardRef(ButtonBase)) aria-label="profile_type.accessibility.button_next" - className="MuiButton-root btn-profile-next MuiButton-text profile-navigation-button" + className="MuiButton-root btn-profile-next MuiButton-text profile-navigation-button disabled Mui-disabled" component="button" - disabled={false} + disabled={true} focusRipple={true} focusVisibleClassName="Mui-focusVisible" onClick={[Function]} @@ -483,7 +483,7 @@ exports[`EcogestureFormEquipment component should be rendered correctly 1`] = ` > <ForwardRef(ButtonBase) aria-label="profile_type.accessibility.button_next" - className="MuiButton-root btn-profile-next MuiButton-text profile-navigation-button" + className="MuiButton-root btn-profile-next MuiButton-text profile-navigation-button disabled Mui-disabled" classes={ Object { "disabled": "Mui-disabled", @@ -492,7 +492,7 @@ exports[`EcogestureFormEquipment component should be rendered correctly 1`] = ` } } component="button" - disabled={false} + disabled={true} focusRipple={true} focusVisibleClassName="Mui-focusVisible" onClick={[Function]} @@ -500,8 +500,8 @@ exports[`EcogestureFormEquipment component should be rendered correctly 1`] = ` > <button aria-label="profile_type.accessibility.button_next" - className="MuiButtonBase-root MuiButton-root btn-profile-next MuiButton-text profile-navigation-button" - disabled={false} + className="MuiButtonBase-root MuiButton-root btn-profile-next MuiButton-text profile-navigation-button disabled Mui-disabled Mui-disabled" + disabled={true} onBlur={[Function]} onClick={[Function]} onDragLeave={[Function]} @@ -514,7 +514,7 @@ exports[`EcogestureFormEquipment component should be rendered correctly 1`] = ` onTouchEnd={[Function]} onTouchMove={[Function]} onTouchStart={[Function]} - tabIndex={0} + tabIndex={-1} type="button" > <span @@ -522,34 +522,6 @@ exports[`EcogestureFormEquipment component should be rendered correctly 1`] = ` > profile_type.form.button_next > </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))> diff --git a/src/components/EcogestureForm/__snapshots__/EcogestureFormSingleChoice.spec.tsx.snap b/src/components/EcogestureForm/__snapshots__/EcogestureFormSingleChoice.spec.tsx.snap index 93eafddb3cce92ff89963b43662aca1aa14e3555..8dfe3731ddfe10627e288544994e65b4ae2fdd5a 100644 --- a/src/components/EcogestureForm/__snapshots__/EcogestureFormSingleChoice.spec.tsx.snap +++ b/src/components/EcogestureForm/__snapshots__/EcogestureFormSingleChoice.spec.tsx.snap @@ -33,9 +33,9 @@ exports[`EcogestureFormSingleChoice component should be rendered correctly 1`] = } } setNextStep={[MockFunction]} - setPrevioustStep={[MockFunction]} + setPreviousStep={[MockFunction]} step={0} - viewedStep={-1} + viewedStep={1} > <div className="ecogesture-profile-container" @@ -49,12 +49,12 @@ exports[`EcogestureFormSingleChoice component should be rendered correctly 1`] = ecogesture_form.heating_type.question </div> <label - className="radio_short" + className="radio_short answer-checked" key="0" > <input - checked={false} - className="" + checked={true} + className="checked-input" name="individual" onChange={[Function]} type="radio" @@ -78,7 +78,7 @@ exports[`EcogestureFormSingleChoice component should be rendered correctly 1`] = </label> </div> <FormNavigation - disableNextButton={true} + disableNextButton={false} handleNext={[Function]} handlePrevious={[Function]} isEcogesture={true} @@ -196,19 +196,19 @@ exports[`EcogestureFormSingleChoice component should be rendered correctly 1`] = </WithStyles(ForwardRef(Button))> <WithStyles(ForwardRef(Button)) aria-label="profile_type.accessibility.button_next" - className="profile-navigation-button disabled" + className="profile-navigation-button" classes={ Object { "label": "text-16-bold", "root": "btn-profile-next", } } - disabled={true} + disabled={false} onClick={[Function]} > <ForwardRef(Button) aria-label="profile_type.accessibility.button_next" - className="profile-navigation-button disabled" + className="profile-navigation-button" classes={ Object { "colorInherit": "MuiButton-colorInherit", @@ -242,14 +242,14 @@ exports[`EcogestureFormSingleChoice component should be rendered correctly 1`] = "textSizeSmall": "MuiButton-textSizeSmall", } } - disabled={true} + disabled={false} onClick={[Function]} > <WithStyles(ForwardRef(ButtonBase)) aria-label="profile_type.accessibility.button_next" - className="MuiButton-root btn-profile-next MuiButton-text profile-navigation-button disabled Mui-disabled" + className="MuiButton-root btn-profile-next MuiButton-text profile-navigation-button" component="button" - disabled={true} + disabled={false} focusRipple={true} focusVisibleClassName="Mui-focusVisible" onClick={[Function]} @@ -257,7 +257,7 @@ exports[`EcogestureFormSingleChoice component should be rendered correctly 1`] = > <ForwardRef(ButtonBase) aria-label="profile_type.accessibility.button_next" - className="MuiButton-root btn-profile-next MuiButton-text profile-navigation-button disabled Mui-disabled" + className="MuiButton-root btn-profile-next MuiButton-text profile-navigation-button" classes={ Object { "disabled": "Mui-disabled", @@ -266,7 +266,7 @@ exports[`EcogestureFormSingleChoice component should be rendered correctly 1`] = } } component="button" - disabled={true} + disabled={false} focusRipple={true} focusVisibleClassName="Mui-focusVisible" onClick={[Function]} @@ -274,8 +274,8 @@ exports[`EcogestureFormSingleChoice component should be rendered correctly 1`] = > <button aria-label="profile_type.accessibility.button_next" - className="MuiButtonBase-root MuiButton-root btn-profile-next MuiButton-text profile-navigation-button disabled Mui-disabled Mui-disabled" - disabled={true} + className="MuiButtonBase-root MuiButton-root btn-profile-next MuiButton-text profile-navigation-button" + disabled={false} onBlur={[Function]} onClick={[Function]} onDragLeave={[Function]} @@ -288,7 +288,7 @@ exports[`EcogestureFormSingleChoice component should be rendered correctly 1`] = onTouchEnd={[Function]} onTouchMove={[Function]} onTouchStart={[Function]} - tabIndex={-1} + tabIndex={0} type="button" > <span @@ -296,6 +296,34 @@ exports[`EcogestureFormSingleChoice component should be rendered correctly 1`] = > profile_type.form.button_next > </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))> diff --git a/src/components/EcogestureForm/__snapshots__/EcogestureFormView.spec.tsx.snap b/src/components/EcogestureForm/__snapshots__/EcogestureFormView.spec.tsx.snap index 70dd31dc953e82bf248058ae95601460c421e3ee..05718102ded39cce7cef10b601ffc5083d50b91f 100644 --- a/src/components/EcogestureForm/__snapshots__/EcogestureFormView.spec.tsx.snap +++ b/src/components/EcogestureForm/__snapshots__/EcogestureFormView.spec.tsx.snap @@ -44,7 +44,7 @@ exports[`EcogestureFormView component should be rendered correctly 1`] = ` } } setNextStep={[Function]} - setPrevioustStep={[Function]} + setPreviousStep={[Function]} step={0} viewedStep={-1} > diff --git a/src/components/EcogestureForm/ecogestureFormSingleChoice.scss b/src/components/EcogestureForm/ecogestureFormSingleChoice.scss index 1afea74c1b4db91656df55458e5cc0d5a3f43880..93360c88ec8200a01d7e2fda89432abb2d3510f4 100644 --- a/src/components/EcogestureForm/ecogestureFormSingleChoice.scss +++ b/src/components/EcogestureForm/ecogestureFormSingleChoice.scss @@ -2,7 +2,6 @@ @import '../../styles/base/breakpoint'; .ecogesture-profile-container { - overflow-y: scroll; display: flex; flex-direction: column; flex: 1; diff --git a/src/components/EcogestureSelection/EcogestureSelection.spec.tsx b/src/components/EcogestureSelection/EcogestureSelection.spec.tsx index e11981ae1848632a70c52bbff62a4918520803d7..ea641c50adec0a2b9d5d8714214185ac1023e532 100644 --- a/src/components/EcogestureSelection/EcogestureSelection.spec.tsx +++ b/src/components/EcogestureSelection/EcogestureSelection.spec.tsx @@ -5,10 +5,7 @@ import React from 'react' import { Provider } from 'react-redux' import mockClient from '../../../tests/__mocks__/client' import { ecogesturesData } from '../../../tests/__mocks__/ecogesturesData.mock' -import { - createMockStore, - mockInitialEcolyoState, -} from '../../../tests/__mocks__/store' +import { createMockEcolyoStore } from '../../../tests/__mocks__/store' import { waitForComponentToPaint } from '../../../tests/__mocks__/testUtils' import EcogestureSelection from './EcogestureSelection' @@ -70,10 +67,9 @@ jest.mock( ) describe('EcogestureSelection component', () => { - // eslint-disable-next-line @typescript-eslint/no-explicit-any - let store: any + const store = createMockEcolyoStore() beforeEach(() => { - store = createMockStore(mockInitialEcolyoState) + store.clearActions() mockGetEcogestureListByProfile.mockClear() }) diff --git a/src/components/EcogestureSelection/EcogestureSelection.tsx b/src/components/EcogestureSelection/EcogestureSelection.tsx index c9e3e71143f87fbb915ff6f3f874c42c266a233c..3250748c75c143b4b54a1fd2aae658c9f1614499 100644 --- a/src/components/EcogestureSelection/EcogestureSelection.tsx +++ b/src/components/EcogestureSelection/EcogestureSelection.tsx @@ -9,7 +9,6 @@ import Loader from 'components/Loader/Loader' import { useClient } from 'cozy-client' import { useI18n } from 'cozy-ui/transpiled/react/I18n' import { Ecogesture } from 'models' -import { ProfileEcogesture } from 'models/profileEcogesture.model' import React, { useCallback, useEffect, useMemo, useState } from 'react' import { useSelector } from 'react-redux' import { useNavigate } from 'react-router-dom' @@ -38,7 +37,7 @@ const EcogestureSelection: React.FC = () => { () => new EcogestureService(client), [client] ) - const profileEcogesture: ProfileEcogesture = useSelector( + const profileEcogesture = useSelector( (state: AppStore) => state.ecolyo.profileEcogesture ) diff --git a/src/components/EcogestureSelection/EcogestureSelectionModal.spec.tsx b/src/components/EcogestureSelection/EcogestureSelectionModal.spec.tsx index 27b1073dd4d645fca3bc29754fe5eaefdb03fda9..26ab115f3d3ee24d956d2d92d483972555f6295f 100644 --- a/src/components/EcogestureSelection/EcogestureSelectionModal.spec.tsx +++ b/src/components/EcogestureSelection/EcogestureSelectionModal.spec.tsx @@ -1,8 +1,8 @@ -import React from 'react' +import { Button } from '@material-ui/core' import { mount } from 'enzyme' import toJson from 'enzyme-to-json' +import React from 'react' import EcogestureSelectionModal from './EcogestureSelectionModal' -import { Button } from '@material-ui/core' jest.mock('cozy-ui/transpiled/react/I18n', () => { return { diff --git a/src/components/EcogestureSelection/EcogestureSelectionModal.tsx b/src/components/EcogestureSelection/EcogestureSelectionModal.tsx index 81990d9a416ef9422c4988835147792688ae8829..644d448fd590e1bea521abc5b0f196c226e663ba 100644 --- a/src/components/EcogestureSelection/EcogestureSelectionModal.tsx +++ b/src/components/EcogestureSelection/EcogestureSelectionModal.tsx @@ -1,9 +1,9 @@ -import React from 'react' -import Dialog from '@material-ui/core/Dialog' import { Button, IconButton } from '@material-ui/core' -import Icon from 'cozy-ui/transpiled/react/Icon' -import { useI18n } from 'cozy-ui/transpiled/react/I18n' +import Dialog from '@material-ui/core/Dialog' 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 React from 'react' import './ecogestureSelectionModal.scss' interface EcogestureSelectionModalProps { diff --git a/src/components/Exploration/ExplorationFinished.tsx b/src/components/Exploration/ExplorationFinished.tsx index 78256d909f14f1696770746f729bf3fec00be10b..09b753bf24cef157536e9c76d17214255ca62a4e 100644 --- a/src/components/Exploration/ExplorationFinished.tsx +++ b/src/components/Exploration/ExplorationFinished.tsx @@ -7,11 +7,12 @@ import { UsageEventType } from 'enum/usageEvent.enum' import { UserChallengeUpdateFlag } from 'enum/userChallenge.enum' import { UserExplorationState } from 'enum/userExploration.enum' import { UserChallenge } from 'models' -import React, { useCallback } from 'react' +import React, { Dispatch, useCallback } from 'react' import { useDispatch } from 'react-redux' 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.actions' import { toggleChallengeExplorationNotification } from 'store/global/global.actions' import './explorationFinished.scss' @@ -25,7 +26,7 @@ const ExplorationFinished: React.FC<ExplorationFinishedProps> = ({ }: ExplorationFinishedProps) => { const client: Client = useClient() const { t } = useI18n() - const dispatch = useDispatch() + const dispatch = useDispatch<Dispatch<AppActionsTypes>>() const navigate = useNavigate() const checkNotificationToEnd = useCallback(async () => { diff --git a/src/components/Exploration/ExplorationOngoing.tsx b/src/components/Exploration/ExplorationOngoing.tsx index 9bb2aaf233436c894484424a6f618f0b259e1f25..29eadebfcb8d76af3356bd02dc736665d02c8412 100644 --- a/src/components/Exploration/ExplorationOngoing.tsx +++ b/src/components/Exploration/ExplorationOngoing.tsx @@ -1,13 +1,9 @@ -import { Client, useClient } from 'cozy-client' -import { useI18n } from 'cozy-ui/transpiled/react/I18n' -import React, { useCallback } from 'react' -import { useDispatch } from 'react-redux' -import './explorationOngoing.scss' - 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 { useI18n } from 'cozy-ui/transpiled/react/I18n' import { UsageEventType } from 'enum/usageEvent.enum' import { UserChallengeUpdateFlag } from 'enum/userChallenge.enum' import { @@ -15,10 +11,14 @@ import { UserExplorationType, } from 'enum/userExploration.enum' import { UserChallenge } from 'models' +import React, { Dispatch, useCallback } from 'react' +import { useDispatch } from 'react-redux' 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.actions' +import './explorationOngoing.scss' interface ExplorationOngoingProps { userChallenge: UserChallenge @@ -29,7 +29,7 @@ const ExplorationOngoing: React.FC<ExplorationOngoingProps> = ({ }: ExplorationOngoingProps) => { const client: Client = useClient() const { t } = useI18n() - const dispatch = useDispatch() + const dispatch = useDispatch<Dispatch<AppActionsTypes>>() const navigate = useNavigate() const goBack = useCallback(() => { navigate(-1) diff --git a/src/components/Exploration/ExplorationView.spec.tsx b/src/components/Exploration/ExplorationView.spec.tsx index 8852f059e2fff1c9677acb69e7d37c964573d039..90cfc6c0a0e695e1e84f70b5c97955fef2669b7d 100644 --- a/src/components/Exploration/ExplorationView.spec.tsx +++ b/src/components/Exploration/ExplorationView.spec.tsx @@ -1,13 +1,13 @@ -import React from 'react' +import { UserExplorationState } from 'enum/userExploration.enum' import { shallow } from 'enzyme' +import React from 'react' import * as reactRedux from 'react-redux' -import ExplorationView from './ExplorationView' -import { userChallengeData } from '../../../tests/__mocks__/userChallengeData.mock' import { challengeStateData } from '../../../tests/__mocks__/challengeStateData.mock' -import ExplorationFinished from './ExplorationFinished' +import { userChallengeData } from '../../../tests/__mocks__/userChallengeData.mock' import ExplorationError from './ExplorationError' +import ExplorationFinished from './ExplorationFinished' import ExplorationOngoing from './ExplorationOngoing' -import { UserExplorationState } from 'enum/userExploration.enum' +import ExplorationView from './ExplorationView' jest.mock('components/Header/CozyBar', () => 'mock-cozybar') jest.mock('components/Header/Header', () => 'mock-header') diff --git a/src/components/Export/exportDoneModal.spec.tsx b/src/components/Export/exportDoneModal.spec.tsx index 3cedb4649cc8a0e35800b3d50fad817fab7b45a6..ea6d5625d2f9570ca37c5b5486d1f71ff9cf3ed4 100644 --- a/src/components/Export/exportDoneModal.spec.tsx +++ b/src/components/Export/exportDoneModal.spec.tsx @@ -1,13 +1,10 @@ -import React from 'react' -import { Provider } from 'react-redux' -import { mount } from 'enzyme' -import toJson from 'enzyme-to-json' -import { - createMockStore, - mockInitialEcolyoState, -} from '../../../tests/__mocks__/store' 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 { @@ -22,9 +19,9 @@ jest.mock('cozy-ui/transpiled/react/I18n', () => { const mockHandleClose = jest.fn() describe('exportDoneModal component', () => { - let store: any + const store = createMockEcolyoStore() beforeEach(() => { - store = createMockStore(mockInitialEcolyoState) + store.clearActions() }) it('should be rendered correctly', () => { @@ -40,17 +37,7 @@ describe('exportDoneModal component', () => { expect(toJson(wrapper)).toMatchSnapshot() }) - it('should display error message', () => { - const wrapper = mount( - <Provider store={store}> - <ExportDoneModal - open={true} - error={true} - handleCloseClick={mockHandleClose} - /> - </Provider> - ) - }) + it('should display error message', () => {}) it('should close modal ', () => { const wrapper = mount( diff --git a/src/components/Export/exportDoneModal.tsx b/src/components/Export/exportDoneModal.tsx index 6de9ff9ce3c7632d6cc0f7e94b9581408027ae82..ea3bd2bf25c5fd32e270987bae2b015704c89421 100644 --- a/src/components/Export/exportDoneModal.tsx +++ b/src/components/Export/exportDoneModal.tsx @@ -1,12 +1,12 @@ -import React from 'react' -import './exportDoneModal.scss' -import { useI18n } from 'cozy-ui/transpiled/react/I18n' +import { Button, IconButton } from '@material-ui/core' import Dialog from '@material-ui/core/Dialog' import CloseIcon from 'assets/icons/ico/close.svg' -import { Button, IconButton } from '@material-ui/core' -import Icon from 'cozy-ui/transpiled/react/Icon' import exportDone from 'assets/icons/ico/exportDone.svg' import warnCross from 'assets/icons/ico/warn-cross.svg' +import { useI18n } from 'cozy-ui/transpiled/react/I18n' +import Icon from 'cozy-ui/transpiled/react/Icon' +import React from 'react' +import './exportDoneModal.scss' interface ExportDoneModalProps { open: boolean diff --git a/src/components/Export/exportLoadingModal.spec.tsx b/src/components/Export/exportLoadingModal.spec.tsx index 904424ba61d16904d6c788a2fe0770ead1462b56..57534eb6592db6f7070dcdaac677b07ad8b3ba54 100644 --- a/src/components/Export/exportLoadingModal.spec.tsx +++ b/src/components/Export/exportLoadingModal.spec.tsx @@ -1,13 +1,10 @@ -import React from 'react' -import { Provider } from 'react-redux' -import { mount } from 'enzyme' -import toJson from 'enzyme-to-json' -import { - createMockStore, - mockInitialEcolyoState, -} from '../../../tests/__mocks__/store' import { Button } from '@material-ui/core' import ExportLoadingModal from 'components/Export/exportLoadingModal' +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 { @@ -24,9 +21,9 @@ const mockHandleDone = jest.fn() const mockSelectedFluids: Array<any> = [0, 1, 2] describe('ExportLoadingModal component', () => { - let store: any + const store = createMockEcolyoStore() beforeEach(() => { - store = createMockStore(mockInitialEcolyoState) + store.clearActions() }) it('should be rendered correctly', () => { diff --git a/src/components/Export/exportStartModal.spec.tsx b/src/components/Export/exportStartModal.spec.tsx index c6cd58838d44a1c580f721e0db276f69e8e520d1..d23c4598b958c6ab24b3576c5b82d47e5faaa872 100644 --- a/src/components/Export/exportStartModal.spec.tsx +++ b/src/components/Export/exportStartModal.spec.tsx @@ -1,13 +1,10 @@ -import React from 'react' -import { Provider } from 'react-redux' -import { mount } from 'enzyme' -import toJson from 'enzyme-to-json' -import { - createMockStore, - mockInitialEcolyoState, -} from '../../../tests/__mocks__/store' 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 { @@ -23,9 +20,9 @@ const mockHandleClose = jest.fn() const mockHandleDownloadClick = jest.fn() describe('exportStartModal component', () => { - let store: any + const store = createMockEcolyoStore() beforeEach(() => { - store = createMockStore(mockInitialEcolyoState) + store.clearActions() }) it('should be rendered correctly', () => { diff --git a/src/components/Export/exportStartModal.tsx b/src/components/Export/exportStartModal.tsx index 58fd7a5954fe66606239bd09f0df3a4f70390948..ef7784cf8855bb95b5d48cc980c474f30ed77abe 100644 --- a/src/components/Export/exportStartModal.tsx +++ b/src/components/Export/exportStartModal.tsx @@ -1,11 +1,11 @@ -import React from 'react' -import './exportStartModal.scss' -import { useI18n } from 'cozy-ui/transpiled/react/I18n' +import { Button, IconButton } from '@material-ui/core' import Dialog from '@material-ui/core/Dialog' import CloseIcon from 'assets/icons/ico/close.svg' -import { Button, IconButton } from '@material-ui/core' -import Icon from 'cozy-ui/transpiled/react/Icon' import download from 'assets/icons/ico/download.svg' +import { useI18n } from 'cozy-ui/transpiled/react/I18n' +import Icon from 'cozy-ui/transpiled/react/Icon' +import React from 'react' +import './exportStartModal.scss' interface ExportStartModalProps { open: boolean diff --git a/src/components/Feedback/FeedbackModal.spec.tsx b/src/components/Feedback/FeedbackModal.spec.tsx index 93bbd7f6118c569254491cb1e22bd949b9bc34f7..9b51acb66e2c99983e009d128924f86d8d4b6041 100644 --- a/src/components/Feedback/FeedbackModal.spec.tsx +++ b/src/components/Feedback/FeedbackModal.spec.tsx @@ -1,15 +1,12 @@ +import FeedbackModal from 'components/Feedback/FeedbackModal' +import { mount } from 'enzyme' import React from 'react' -import { BrowserRouter } from 'react-router-dom' +import { act } from 'react-dom/test-utils' import * as reactRedux from 'react-redux' import { Provider } from 'react-redux' -import { mount } from 'enzyme' -import FeedbackModal from 'components/Feedback/FeedbackModal' +import { BrowserRouter } from 'react-router-dom' +import { createMockEcolyoStore } from '../../../tests/__mocks__/store' import { userChallengeExplo1OnGoing } from '../../../tests/__mocks__/userChallengeData.mock' -import { - createMockStore, - mockInitialEcolyoState, -} from '../../../tests/__mocks__/store' -import { act } from 'react-dom/test-utils' // Value coming from jest.config declare let __SAU_LINK__: string @@ -38,9 +35,9 @@ const mockUseSelector = jest.spyOn(reactRedux, 'useSelector') const mockUseDispatch = jest.spyOn(reactRedux, 'useDispatch') describe('FeedbackModal component', () => { - let store: any + const store = createMockEcolyoStore() beforeEach(() => { - store = createMockStore(mockInitialEcolyoState) + store.clearActions() }) it('should render the component', () => { mockUseDispatch.mockReturnValue(jest.fn()) @@ -57,10 +54,10 @@ describe('FeedbackModal component', () => { expect(component).toMatchSnapshot() }) }) -describe('FeedbackModal functionnalities', () => { - let store: any +describe('FeedbackModal functionalities', () => { + const store = createMockEcolyoStore() beforeEach(() => { - store = createMockStore(mockInitialEcolyoState) + store.clearActions() }) it('should close the modal', async () => { diff --git a/src/components/Feedback/FeedbackModal.tsx b/src/components/Feedback/FeedbackModal.tsx index 53a9130ee7b45ed28ccd2e2c3ff49e626946f6c4..fef7c2595fb456e5b048826084672ba0e5d366ba 100644 --- a/src/components/Feedback/FeedbackModal.tsx +++ b/src/components/Feedback/FeedbackModal.tsx @@ -62,7 +62,8 @@ const FeedbackModal: React.FC<FeedbackModalProps> = ({ <div className="fb-root"> <StyledIcon icon={ecolyoIcon} size={80} /> <p className="title">{t('feedback.title')}</p> - <p className="subtitle">{t('feedback.subtitle')}</p> + <p className="text">{t('feedback.text1')}</p> + <p className="text">{t('feedback.text2')}</p> <div className="actions"> <Button aria-label={t('feedback.later')} diff --git a/src/components/Feedback/feedbackModal.scss b/src/components/Feedback/feedbackModal.scss index dae85d4cae5c98e9f93cafc959ca539c7ff76ba2..379ceff5f9448aa00c1b24d713b442c550ff181e 100644 --- a/src/components/Feedback/feedbackModal.scss +++ b/src/components/Feedback/feedbackModal.scss @@ -17,15 +17,15 @@ padding: 0.5rem; } - .subtitle { + .text { color: $grey-bright; - margin: 1rem 0 2rem; } .actions { width: 100%; display: flex; justify-content: center; + margin-top: 1rem; gap: 16px; button { margin-top: 0; diff --git a/src/components/FluidChart/FluidChart.tsx b/src/components/FluidChart/FluidChart.tsx index c3257a3245a907111dae927a396301085d141e53..ad566e29d622bda5513781c48fd8a1ef655b8dd0 100644 --- a/src/components/FluidChart/FluidChart.tsx +++ b/src/components/FluidChart/FluidChart.tsx @@ -27,10 +27,11 @@ const FluidChart: React.FC<FluidChartProps> = ({ }: FluidChartProps) => { const { t } = useI18n() const client = useClient() - const { fluidStatus } = useSelector((state: AppStore) => state.ecolyo.global) - const { currentTimeStep, selectedDate } = useSelector( - (state: AppStore) => state.ecolyo.chart - ) + const { + chart: { currentTimeStep, selectedDate }, + global: { fluidStatus }, + } = useSelector((state: AppStore) => state.ecolyo) + const [, setValidExploration] = useExploration() const [isLoaded, setIsLoaded] = useState<boolean>(false) const [showCompare, setShowCompare] = useState<boolean>(false) diff --git a/src/components/FluidChart/FluidChartSlide.tsx b/src/components/FluidChart/FluidChartSlide.tsx index 1a60fb84ad09dbba3a7183343d8b690536dddacb..b272ab25a177fc30f98ca24ebe55542e199ce9a1 100644 --- a/src/components/FluidChart/FluidChartSlide.tsx +++ b/src/components/FluidChart/FluidChartSlide.tsx @@ -6,11 +6,11 @@ import { FluidType } from 'enum/fluid.enum' import { TimeStep } from 'enum/timeStep.enum' import { DateTime } from 'luxon' import { Datachart } from 'models' -import React, { useEffect, useState } from 'react' +import React, { Dispatch, useEffect, useState } from 'react' import { useDispatch, useSelector } from 'react-redux' import ConsumptionService from 'services/consumption.service' import DateChartService from 'services/dateChart.service' -import { AppStore } from 'store' +import { AppActionsTypes, AppStore } from 'store' import { setCurrentDatachart, setLoading } from 'store/chart/chart.actions' import './fluidChartSlide.scss' @@ -34,19 +34,18 @@ const FluidChartSlide: React.FC<FluidChartSlideProps> = ({ setActive, }: FluidChartSlideProps) => { const client = useClient() - const dispatch = useDispatch() - const { currentTimeStep, currentIndex } = useSelector( - (state: AppStore) => state.ecolyo.chart - ) - const { fluidTypes, fluidStatus } = useSelector( - (state: AppStore) => state.ecolyo.global - ) + const dispatch = useDispatch<Dispatch<AppActionsTypes>>() + const { + chart: { currentTimeStep, currentIndex }, + global: { fluidStatus, fluidTypes }, + } = useSelector((state: AppStore) => state.ecolyo) + const [chartData, setChartData] = useState<Datachart>({ actualData: [], comparisonData: null, }) const [isDataLoaded, setIsDataLoaded] = useState<boolean>(false) - const [timeStep, setTimeStep] = useState<TimeStep>(99) + const [timeStep, setTimeStep] = useState<TimeStep>(TimeStep.WEEK) useEffect(() => { let subscribed = true diff --git a/src/components/FluidChart/FluidChartSwipe.tsx b/src/components/FluidChart/FluidChartSwipe.tsx index 246291866f230f0d6675eb1dfe3a4ed91aa2c397..269979d0c6b36a2dd797f63bfcb8cf2d75d262a2 100644 --- a/src/components/FluidChart/FluidChartSwipe.tsx +++ b/src/components/FluidChart/FluidChartSwipe.tsx @@ -1,15 +1,14 @@ -import React, { useState, useEffect, useRef } from 'react' -import './fluidChartSwipe.scss' +import FluidChartSlide from 'components/FluidChart/FluidChartSlide' +import { FluidType } from 'enum/fluid.enum' +import { DateTime } from 'luxon' +import React, { Dispatch, useEffect, useRef, useState } from 'react' import { useDispatch, useSelector } from 'react-redux' -import { AppStore } from 'store' -import { setCurrentIndex, setSelectedDate } from 'store/chart/chart.actions' import SwipeableViews from 'react-swipeable-views' import { virtualize } from 'react-swipeable-views-utils' -import { DateTime } from 'luxon' - -import { FluidType } from 'enum/fluid.enum' -import FluidChartSlide from 'components/FluidChart/FluidChartSlide' import DateChartService from 'services/dateChart.service' +import { AppActionsTypes, AppStore } from 'store' +import { setCurrentIndex, setSelectedDate } from 'store/chart/chart.actions' +import './fluidChartSwipe.scss' const VirtualizeSwipeableViews = virtualize(SwipeableViews) @@ -24,7 +23,7 @@ const FluidChartSwipe: React.FC<FluidChartSwipeProps> = ({ showCompare, setActive, }: FluidChartSwipeProps) => { - const dispatch = useDispatch() + const dispatch = useDispatch<Dispatch<AppActionsTypes>>() const { currentIndex, currentTimeStep, selectedDate, loading } = useSelector( (state: AppStore) => state.ecolyo.chart ) diff --git a/src/components/FormGlobal/FormNavigation.spec.tsx b/src/components/FormGlobal/FormNavigation.spec.tsx index 0da82c679f399ff48f30a27fad09d5e3f2782199..d620db074e9130ad3e8b184669fd3ec36560e011 100644 --- a/src/components/FormGlobal/FormNavigation.spec.tsx +++ b/src/components/FormGlobal/FormNavigation.spec.tsx @@ -3,10 +3,7 @@ import { ProfileTypeStepForm } from 'enum/profileType.enum' import { mount } from 'enzyme' import React from 'react' import { Provider } from 'react-redux' -import { - createMockStore, - mockInitialEcolyoState, -} from '../../../tests/__mocks__/store' +import { createMockEcolyoStore } from '../../../tests/__mocks__/store' import FormNavigation from './FormNavigation' jest.mock('cozy-ui/transpiled/react/I18n', () => { @@ -26,9 +23,9 @@ jest.mock('react-router-dom', () => ({ })) describe('FormNavigation component', () => { - let store: any + const store = createMockEcolyoStore() beforeEach(() => { - store = createMockStore(mockInitialEcolyoState) + store.clearActions() }) it('should be rendered correctly', () => { diff --git a/src/components/FormGlobal/FormProgress.tsx b/src/components/FormGlobal/FormProgress.tsx index b371ef2ae9562de3cda95a956ee90b9bc1fcfcae..0d3944d01c49f36ae917199b33d702c3a7524655 100644 --- a/src/components/FormGlobal/FormProgress.tsx +++ b/src/components/FormGlobal/FormProgress.tsx @@ -1,7 +1,7 @@ -import React from 'react' import 'components/FormGlobal/formProgress.scss' import { ProfileTypeStepForm } from 'enum/profileType.enum' import { SgeStep } from 'enum/sgeStep.enum' +import React from 'react' interface FormProgressProps { step: ProfileTypeStepForm | SgeStep diff --git a/src/components/HalfHourNoData/HalfHourNoData.spec.tsx b/src/components/HalfHourNoData/HalfHourNoData.spec.tsx index 84275d83bc6056bb85a120c6f190ee2847e001f4..ff7c1481a9cc6f01dea9d0e5c5a9daf5a186a462 100644 --- a/src/components/HalfHourNoData/HalfHourNoData.spec.tsx +++ b/src/components/HalfHourNoData/HalfHourNoData.spec.tsx @@ -1,5 +1,5 @@ -import React from 'react' import { mount } from 'enzyme' +import React from 'react' import HalfHourNoData from './HalfHourNoData' jest.mock('cozy-ui/transpiled/react/I18n', () => { diff --git a/src/components/HalfHourNoData/HalfHourNoData.tsx b/src/components/HalfHourNoData/HalfHourNoData.tsx index 1834608414a7e84f390927e8363ac624da88503d..c092103109d91c98ce47d26168de90998a4dd37e 100644 --- a/src/components/HalfHourNoData/HalfHourNoData.tsx +++ b/src/components/HalfHourNoData/HalfHourNoData.tsx @@ -1,5 +1,5 @@ -import React from 'react' import { IuseI18n, useI18n } from 'cozy-ui/transpiled/react/I18n' +import React from 'react' import './halfHourNoData.scss' const HalfHourNoData = () => { diff --git a/src/components/Header/CozyBar.spec.tsx b/src/components/Header/CozyBar.spec.tsx index 23cddd5774882eed6e2d9e2e784771efa578bd61..da3522ebfbeaa608af401197e4d4144179ed7e0d 100644 --- a/src/components/Header/CozyBar.spec.tsx +++ b/src/components/Header/CozyBar.spec.tsx @@ -70,7 +70,7 @@ describe('CozyBar component', () => { <CozyBar /> </Provider> ) - const updateModalSpy = jest.spyOn(ModalAction, 'updateModalIsFeedbacksOpen') + const updateModalSpy = jest.spyOn(ModalAction, 'openFeedbackModal') wrapper.find('BarRight').find('.cv-button').first().simulate('click') expect(updateModalSpy).toHaveBeenCalledWith(true) }) diff --git a/src/components/Header/CozyBar.tsx b/src/components/Header/CozyBar.tsx index eae7de645c172de07e75c811f23863fec8164906..891266275d9d3111ed92d26c3c938e9f353e5783 100644 --- a/src/components/Header/CozyBar.tsx +++ b/src/components/Header/CozyBar.tsx @@ -3,11 +3,19 @@ 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, { useCallback } from 'react' +import React, { Dispatch, useCallback } from 'react' import { useDispatch, useSelector } from 'react-redux' import { useNavigate } from 'react-router-dom' -import { AppStore } from 'store' -import { updateModalIsFeedbacksOpen } from 'store/modal/modal.actions' +import { AppActionsTypes, AppStore } from 'store' +import { openFeedbackModal } from 'store/modal/modal.actions' + +declare const cozy: { + bar: { + BarLeft: Function + BarCenter: Function + BarRight: Function + } +} interface CozyBarProps { titleKey?: string @@ -23,7 +31,7 @@ const CozyBar = ({ }: CozyBarProps) => { const { t } = useI18n() const navigate = useNavigate() - const dispatch = useDispatch() + const dispatch = useDispatch<Dispatch<AppActionsTypes>>() const { BarLeft, BarCenter, BarRight } = cozy.bar const { screenType } = useSelector((state: AppStore) => state.ecolyo.global) @@ -36,7 +44,7 @@ const CozyBar = ({ }, [backFunction, navigate]) const handleClickFeedbacks = () => { - dispatch(updateModalIsFeedbacksOpen(true)) + dispatch(openFeedbackModal(true)) } const cozyBarCustom = (screen?: ScreenType) => { diff --git a/src/components/Header/Header.spec.tsx b/src/components/Header/Header.spec.tsx index 7405f33ceda4add6941fc1d299ce317e66ce3470..68c619a57a15e2f928c36a9d6ef08296172c96b7 100644 --- a/src/components/Header/Header.spec.tsx +++ b/src/components/Header/Header.spec.tsx @@ -24,7 +24,7 @@ jest.mock('react-router-dom', () => ({ useNavigate: () => mockedNavigate, })) -const mocksetHeaderHeight = jest.fn() +const mockSetHeaderHeight = jest.fn() const mockStore = configureStore([]) describe('Header component', () => { @@ -37,7 +37,7 @@ describe('Header component', () => { const wrapper = mount( <Provider store={store}> <Header - setHeaderHeight={mocksetHeaderHeight} + setHeaderHeight={mockSetHeaderHeight} desktopTitleKey="mockKey" /> </Provider> @@ -56,7 +56,7 @@ describe('Header component', () => { <Header desktopTitleKey={'KEY'} displayBackArrow={true} - setHeaderHeight={mocksetHeaderHeight} + setHeaderHeight={mockSetHeaderHeight} /> </Provider> ) @@ -77,7 +77,7 @@ describe('Header component', () => { <Header desktopTitleKey={'KEY'} displayBackArrow={true} - setHeaderHeight={mocksetHeaderHeight} + setHeaderHeight={mockSetHeaderHeight} /> </Provider> ) @@ -101,12 +101,12 @@ describe('Header component', () => { const wrapper = mount( <Provider store={store}> <Header - setHeaderHeight={mocksetHeaderHeight} + setHeaderHeight={mockSetHeaderHeight} desktopTitleKey="mockKey" /> </Provider> ) - const updateModalSpy = jest.spyOn(ModalAction, 'updateModalIsFeedbacksOpen') + const updateModalSpy = jest.spyOn(ModalAction, 'openFeedbackModal') wrapper .find(IconButton) .find('.header-feedbacks-button') diff --git a/src/components/Header/Header.tsx b/src/components/Header/Header.tsx index b412c34a44895a829600d56bd286f9f0eb60fefb..81cab9dfae017377a5e07033bd492474a4cd557f 100644 --- a/src/components/Header/Header.tsx +++ b/src/components/Header/Header.tsx @@ -1,16 +1,15 @@ -import { useI18n } from 'cozy-ui/transpiled/react/I18n' -import React, { useCallback, useEffect, useRef } from 'react' -import { useDispatch, useSelector } from 'react-redux' -import { AppStore } from 'store' -import { updateModalIsFeedbacksOpen } from 'store/modal/modal.actions' -import './header.scss' - import IconButton from '@material-ui/core/IconButton' 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 { useNavigate } from 'react-router-dom' +import { AppActionsTypes, AppStore } from 'store' +import { openFeedbackModal } from 'store/modal/modal.actions' +import './header.scss' interface HeaderProps { /** translation key used as t('key.value') */ @@ -31,8 +30,8 @@ const Header: React.FC<HeaderProps> = ({ }) => { const { t } = useI18n() const navigate = useNavigate() - const header = useRef(null) - const dispatch = useDispatch() + const header = useRef<HTMLDivElement>(null) + const dispatch = useDispatch<Dispatch<AppActionsTypes>>() const { screenType } = useSelector((state: AppStore) => state.ecolyo.global) const cozyBarHeight = 48 @@ -46,17 +45,13 @@ const Header: React.FC<HeaderProps> = ({ }, [backFunction, navigate]) const handleClickFeedbacks = () => { - dispatch(updateModalIsFeedbacksOpen(true)) + dispatch(openFeedbackModal(true)) } useEffect(() => { - if (screenType === ScreenType.MOBILE) { - setHeaderHeight( - header.current ? header.current.clientHeight - cozyBarHeight : 0 - ) - } else { - setHeaderHeight(header.current ? header.current.clientHeight : 0) - } + const headerHeight = header.current?.clientHeight || 0 + const adjustment = screenType === ScreenType.MOBILE ? cozyBarHeight : 0 + setHeaderHeight(headerHeight - adjustment) }, [screenType, children, setHeaderHeight]) return ( diff --git a/src/components/Home/ConsumptionDetails.spec.tsx b/src/components/Home/ConsumptionDetails.spec.tsx index 9bf79a13482ddea17b480df0b2c8cea801f09e0f..93fcb20809868df503fbf9ebe155ff98829c95d3 100644 --- a/src/components/Home/ConsumptionDetails.spec.tsx +++ b/src/components/Home/ConsumptionDetails.spec.tsx @@ -1,17 +1,16 @@ -import React from 'react' +import { FluidType } from 'enum/fluid.enum' +import { TimeStep } from 'enum/timeStep.enum' import { mount } from 'enzyme' -import ConsumptionDetails from './ConsumptionDetails' +import React from 'react' import * as reactRedux from 'react-redux' -import { TimeStep } from 'enum/timeStep.enum' -import { FluidType } from 'enum/fluid.enum' +import { Provider } from 'react-redux' +import { BrowserRouter } from 'react-router-dom' import { - createMockStore, + createMockEcolyoStore, mockInitialChartState, - mockInitialEcolyoState, mockInitialGlobalState, } from '../../../tests/__mocks__/store' -import { Provider } from 'react-redux' -import { BrowserRouter } from 'react-router-dom' +import ConsumptionDetails from './ConsumptionDetails' jest.mock('cozy-ui/transpiled/react/I18n', () => { return { @@ -26,11 +25,9 @@ jest.mock('cozy-ui/transpiled/react/I18n', () => { const mockUseSelector = jest.spyOn(reactRedux, 'useSelector') describe('ConsumptionDetails component', () => { - // eslint-disable-next-line @typescript-eslint/no-explicit-any - let store: any - + const store = createMockEcolyoStore() beforeEach(() => { - store = createMockStore(mockInitialEcolyoState) + store.clearActions() mockUseSelector.mockClear() }) it('should be rendered correctly', () => { diff --git a/src/components/Home/ConsumptionDetails.tsx b/src/components/Home/ConsumptionDetails.tsx index 5fdd7c022c339f8b01e15afed2a00c83ce8a349b..c61846e7e9e19f7a3eec242c602405746c1c1c52 100644 --- a/src/components/Home/ConsumptionDetails.tsx +++ b/src/components/Home/ConsumptionDetails.tsx @@ -1,10 +1,10 @@ +import TotalConsumption from 'components/TotalConsumption/TotalConsumption' +import { FluidType } from 'enum/fluid.enum' import React from 'react' import { useSelector } from 'react-redux' import { AppStore } from 'store' import { convertDateToShortDateString } from 'utils/date' import './consumptionDetails.scss' -import TotalConsumption from 'components/TotalConsumption/TotalConsumption' -import { FluidType } from 'enum/fluid.enum' interface ConsumptionDetailsProps { fluidType: FluidType } diff --git a/src/components/Home/ConsumptionView.spec.tsx b/src/components/Home/ConsumptionView.spec.tsx index 704f02b8e0dbcf6d44a505ba5d87320ecdf46ae9..63d30b40b750f89f1d3d6d2ee2927d8c15e19160 100644 --- a/src/components/Home/ConsumptionView.spec.tsx +++ b/src/components/Home/ConsumptionView.spec.tsx @@ -2,15 +2,14 @@ import Loader from 'components/Loader/Loader' import { FluidState, FluidType } from 'enum/fluid.enum' import { TimeStep } from 'enum/timeStep.enum' import { mount } from 'enzyme' -import { ChartState, FluidStatus, GlobalState } from 'models' +import { FluidStatus } from 'models' import React from 'react' import * as reactRedux from 'react-redux' import { Provider } from 'react-redux' -import { MockStoreEnhanced } from 'redux-mock-store' import * as chartActions from 'store/chart/chart.actions' import { mockTestProfile1 } from '../../../tests/__mocks__/profileType.mock' import { - createMockStore, + createMockEcolyoStore, mockExpiredElec, mockExpiredGas, mockInitialEcolyoState, @@ -74,17 +73,9 @@ const mockedPartnersIssueModal = { } describe('ConsumptionView component', () => { - let store: MockStoreEnhanced< - { - ecolyo: { - global: GlobalState - chart?: ChartState - } - }, - {} - > + const store = createMockEcolyoStore() beforeEach(() => { - store = createMockStore(mockInitialEcolyoState) + store.clearActions() useDispatchSpy.mockClear() setCurrentTimeStepSpy.mockClear() }) @@ -102,6 +93,7 @@ describe('ConsumptionView component', () => { fluidStatus: mockFluidStatus, releaseNotes: mockInitialEcolyoState.global.releaseNotes, }, + modal: { partnersIssueModal: mockedPartnersIssueModal }, }) const wrapper = mount( <Provider store={store}> @@ -129,6 +121,7 @@ describe('ConsumptionView component', () => { fluidStatus: mockFluidStatus, releaseNotes: mockInitialEcolyoState.global.releaseNotes, }, + modal: { partnersIssueModal: mockedPartnersIssueModal }, }) const wrapper = mount( <Provider store={store}> @@ -151,6 +144,7 @@ describe('ConsumptionView component', () => { fluidStatus: mockInitialEcolyoState.global.fluidStatus, releaseNotes: mockInitialEcolyoState.global.releaseNotes, }, + modal: { partnersIssueModal: mockedPartnersIssueModal }, }) mount( <Provider store={store}> @@ -171,6 +165,7 @@ describe('ConsumptionView component', () => { fluidStatus: [], releaseNotes: mockInitialEcolyoState.global.releaseNotes, }, + modal: { partnersIssueModal: mockedPartnersIssueModal }, fluidStatus: [], }) const wrapper = mount( @@ -194,6 +189,7 @@ describe('ConsumptionView component', () => { fluidStatus: updatedStatus, releaseNotes: mockInitialEcolyoState.global.releaseNotes, }, + modal: { partnersIssueModal: mockedPartnersIssueModal }, fluidStatus: updatedStatus, }) const wrapper = mount( @@ -217,6 +213,7 @@ describe('ConsumptionView component', () => { fluidStatus: updatedStatus, releaseNotes: mockInitialEcolyoState.global.releaseNotes, }, + modal: { partnersIssueModal: mockedPartnersIssueModal }, }) const wrapper = mount( <Provider store={store}> @@ -240,8 +237,8 @@ describe('ConsumptionView component', () => { global: { fluidStatus: updatedStatus, releaseNotes: mockInitialEcolyoState.global.releaseNotes, - openPartnersIssueModal: { ...mockedPartnersIssueModal, egl: true }, }, + modal: { partnersIssueModal: { ...mockedPartnersIssueModal, egl: true } }, }) useDispatchSpy.mockReturnValue(jest.fn()) mockUpdateProfile.mockResolvedValue(mockTestProfile1) @@ -264,8 +261,8 @@ describe('ConsumptionView component', () => { global: { fluidStatus: updatedStatus, releaseNotes: mockInitialEcolyoState.global.releaseNotes, - openPartnersIssueModal: false, }, + modal: { partnersIssueModal: mockedPartnersIssueModal }, }) useDispatchSpy.mockReturnValue(jest.fn()) const wrapper = mount( @@ -287,8 +284,8 @@ describe('ConsumptionView component', () => { global: { fluidStatus: updatedStatus, releaseNotes: mockInitialEcolyoState.global.releaseNotes, - openPartnersIssueModal: mockedPartnersIssueModal, }, + modal: { partnersIssueModal: mockedPartnersIssueModal }, }) useDispatchSpy.mockReturnValue(jest.fn()) const wrapper = mount( @@ -311,8 +308,8 @@ describe('ConsumptionView component', () => { global: { fluidStatus: updatedStatus, releaseNotes: mockInitialEcolyoState.global.releaseNotes, - openPartnersIssueModal: mockedPartnersIssueModal, }, + modal: { partnersIssueModal: mockedPartnersIssueModal }, }) useDispatchSpy.mockReturnValue(jest.fn()) mockUpdateProfile.mockResolvedValue(mockTestProfile1) @@ -334,13 +331,12 @@ describe('ConsumptionView component', () => { }, global: { fluidStatus: updatedStatus, - openPartnersIssueModal: mockedPartnersIssueModal, releaseNotes: { show: true, notes: [{ description: 'description', title: 'title' }], }, }, - openPartnersIssueModal: mockedPartnersIssueModal, + modal: { partnersIssueModal: mockedPartnersIssueModal }, }) useDispatchSpy.mockReturnValue(jest.fn()) mockUpdateProfile.mockResolvedValue(mockTestProfile1) diff --git a/src/components/Home/ConsumptionView.tsx b/src/components/Home/ConsumptionView.tsx index 83a6b6199ecb48bf127eb9b54d0e763fbdc172bf..5d01492efad055387d8ae96f5e7b2bb0bf8d7c04 100644 --- a/src/components/Home/ConsumptionView.tsx +++ b/src/components/Home/ConsumptionView.tsx @@ -15,17 +15,14 @@ import PartnerIssueModal from 'components/PartnerIssue/PartnerIssueModal' import { useClient } from 'cozy-client' import { FluidType } from 'enum/fluid.enum' import { TimeStep } from 'enum/timeStep.enum' -import React, { useCallback, useEffect, useState } from 'react' +import React, { Dispatch, useCallback, useEffect, useState } from 'react' import { useDispatch, useSelector } from 'react-redux' import { useNavigate } from 'react-router-dom' import ProfileService from 'services/profile.service' -import { AppStore } from 'store' +import { AppActionsTypes, AppStore } from 'store' import { setCurrentTimeStep, setLoading } from 'store/chart/chart.actions' -import { - setCustomPopup, - setPartnersIssue, - showReleaseNotes, -} from 'store/global/global.actions' +import { setCustomPopup, showReleaseNotes } from 'store/global/global.actions' +import { openPartnersModal } from 'store/modal/modal.actions' import { getKonnectorUpdateError, getTodayDate, @@ -42,16 +39,12 @@ const ConsumptionView: React.FC<ConsumptionViewProps> = ({ }: ConsumptionViewProps) => { const navigate = useNavigate() const client = useClient() - const dispatch = useDispatch() + const dispatch = useDispatch<Dispatch<AppActionsTypes>>() const isMulti = fluidType !== FluidType.MULTIFLUID const { chart: { currentTimeStep, loading }, - global: { - fluidStatus, - releaseNotes, - customPopupModal, - openPartnersIssueModal, - }, + global: { fluidStatus, releaseNotes, customPopupModal }, + modal: { partnersIssueModal }, } = useSelector((state: AppStore) => state.ecolyo) const [isFluidKonnected, setIsFluidKonnected] = useState<boolean>(false) @@ -118,15 +111,15 @@ const ConsumptionView: React.FC<ConsumptionViewProps> = ({ }) if (updatedProfile) { dispatch( - setPartnersIssue({ - ...openPartnersIssueModal, + openPartnersModal({ + ...partnersIssueModal, [getPartnerKey(fluidType)]: false, }) ) } } }, - [client, dispatch, openPartnersIssueModal] + [client, dispatch, partnersIssueModal] ) const handleCloseCustomPopupModal = async () => { @@ -251,7 +244,7 @@ const ConsumptionView: React.FC<ConsumptionViewProps> = ({ <PartnerIssueModal key={issuedFluid.fluidType} issuedFluid={issuedFluid} - open={openPartnersIssueModal[getPartnerKey(issuedFluid.fluidType)]} + open={partnersIssueModal[getPartnerKey(issuedFluid.fluidType)]} handleCloseClick={handleClosePartnerIssueModal} /> ))} diff --git a/src/components/Home/FluidButton.spec.tsx b/src/components/Home/FluidButton.spec.tsx index e7cdc22c72e345c7a9989966f39c3751f11fbea1..e58745f9c33aa4fbc16d89bc695bc3d621d939cc 100644 --- a/src/components/Home/FluidButton.spec.tsx +++ b/src/components/Home/FluidButton.spec.tsx @@ -1,16 +1,14 @@ +import { FluidState, FluidType } from 'enum/fluid.enum' import { mount } from 'enzyme' +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 { - createMockStore, - mockInitialEcolyoState, + createMockEcolyoStore, mockInitialGlobalState, } from '../../../tests/__mocks__/store' - -import { FluidState, FluidType } from 'enum/fluid.enum' -import { GlobalState } from 'models' -import configureStore from 'redux-mock-store' -import UsageEventService from 'services/usageEvent.service' import FluidButton from './FluidButton' jest.mock('cozy-ui/transpiled/react/I18n', () => { @@ -29,10 +27,9 @@ jest.mock('react-router-dom', () => ({ })) describe('FluidButton component', () => { - // eslint-disable-next-line @typescript-eslint/no-explicit-any - let store: any + const store = createMockEcolyoStore() beforeEach(() => { - store = createMockStore(mockInitialEcolyoState) + store.clearActions() }) it('should be rendered correctly', () => { diff --git a/src/components/Home/FluidButton.tsx b/src/components/Home/FluidButton.tsx index 9d24a0d2bfd91151d24226762d4b6bb63f878fb2..a9ba2c020dda0c745ca857f037fbe9d0b35a44c6 100644 --- a/src/components/Home/FluidButton.tsx +++ b/src/components/Home/FluidButton.tsx @@ -1,12 +1,11 @@ -import { useI18n } from 'cozy-ui/transpiled/react/I18n' -import React, { useCallback, useEffect, useState } from 'react' - import ErrorNotif from 'assets/icons/ico/notif_error.svg' 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 React, { useCallback, useEffect, useState } from 'react' import { useSelector } from 'react-redux' import { useNavigate } from 'react-router-dom' import DateChartService from 'services/dateChart.service' @@ -77,10 +76,7 @@ const FluidButton: React.FC<FluidButtonProps> = ({ // Show errors only on konnected 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()) || - (isConnected() && - fluidStatus[fluidType] && - !fluidStatus[fluidType].lastDataDate) + (fluidType !== FluidType.MULTIFLUID && isConnected() && isOutdated()) ) { setShowError(true) } diff --git a/src/components/Home/FluidButtons.spec.tsx b/src/components/Home/FluidButtons.spec.tsx index 9a1c8df02b2537b8437226367d502066258269d1..34a90e11de944fa87e075a0642394513149b9979 100644 --- a/src/components/Home/FluidButtons.spec.tsx +++ b/src/components/Home/FluidButtons.spec.tsx @@ -1,12 +1,8 @@ +import { FluidType } from 'enum/fluid.enum' import { mount } from 'enzyme' import React from 'react' import { Provider } from 'react-redux' -import { - createMockStore, - mockInitialEcolyoState, -} from '../../../tests/__mocks__/store' - -import { FluidType } from 'enum/fluid.enum' +import { createMockEcolyoStore } from '../../../tests/__mocks__/store' import FluidButtons from './FluidButtons' jest.mock('cozy-ui/transpiled/react/I18n', () => { @@ -25,10 +21,9 @@ jest.mock('react-router-dom', () => ({ })) describe('FluidButtons component', () => { - // eslint-disable-next-line @typescript-eslint/no-explicit-any - let store: any + const store = createMockEcolyoStore() beforeEach(() => { - store = createMockStore(mockInitialEcolyoState) + store.clearActions() }) it('should be rendered correctly', () => { diff --git a/src/components/Home/FluidButtons.tsx b/src/components/Home/FluidButtons.tsx index 2eb74c577ceddea56da2ee5306e0c63f876820e1..6a4d6ce5b7edd1990de94d594a09b21015f54bdc 100644 --- a/src/components/Home/FluidButtons.tsx +++ b/src/components/Home/FluidButtons.tsx @@ -1,6 +1,5 @@ -import React from 'react' - import { FluidType } from 'enum/fluid.enum' +import React from 'react' import FluidButton from './FluidButton' import './fluidButtons.scss' @@ -20,9 +19,9 @@ const FluidButtons: React.FC<FluidButtonsProps> = ({ return ( <div className="fluid-buttons"> <div className="content"> - {orderedFluids.map((fluid, key) => ( + {orderedFluids.map(fluid => ( <FluidButton - key={key} + key={fluid} isActive={activeFluid === fluid} fluidType={fluid} /> diff --git a/src/components/Home/ReleaseNotesModal.tsx b/src/components/Home/ReleaseNotesModal.tsx index 507f38650ccc8c8e63381ce2a987000469ec14ad..cc64fcf1bba2febeb47af4402a72d558e54943f9 100644 --- a/src/components/Home/ReleaseNotesModal.tsx +++ b/src/components/Home/ReleaseNotesModal.tsx @@ -47,8 +47,8 @@ const ReleaseNotesModal: React.FC<ReleaseNotesModalProps> = ({ </div> <div className="release-note-message text-16-normal"> {releaseNotes.notes.length > 0 && - releaseNotes.notes.map((note, index) => ( - <div key={index} className="release-note-part"> + releaseNotes.notes.map(note => ( + <div key={note.title} className="release-note-part"> <div className="release-note-message text-16-bold"> {note.title} </div> diff --git a/src/components/Hooks/useExploration.spec.tsx b/src/components/Hooks/useExploration.spec.tsx index 13d4e02e9651ad48df2054bc9cb3efe584cf761c..8124169d7a6da85771fc34babf4d922a769866bd 100644 --- a/src/components/Hooks/useExploration.spec.tsx +++ b/src/components/Hooks/useExploration.spec.tsx @@ -1,7 +1,7 @@ -import * as reactRedux from 'react-redux' -import { renderHook, act } from '@testing-library/react-hooks' +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() diff --git a/src/components/Hooks/useExploration.tsx b/src/components/Hooks/useExploration.tsx index eac9ba9bcd82b15968ed34a08aeb36b86f50c26b..0858343b897348ec9bd9b2fa2edf505721423634 100644 --- a/src/components/Hooks/useExploration.tsx +++ b/src/components/Hooks/useExploration.tsx @@ -1,16 +1,16 @@ -import { useState, useEffect, Dispatch, SetStateAction } from 'react' -import { useDispatch, useSelector } from 'react-redux' import { Client, useClient } from 'cozy-client' +import { UserExplorationState } from 'enum/userExploration.enum' import { ChallengeState, UserExploration } from 'models' -import { AppStore } from 'store' +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.actions' -import { UserExplorationState } from 'enum/userExploration.enum' import { toggleChallengeExplorationNotification } from 'store/global/global.actions' const useExploration = (): [string, Dispatch<SetStateAction<string>>] => { const client: Client = useClient() - const dispatch = useDispatch() + const dispatch = useDispatch<Dispatch<AppActionsTypes>>() const { currentChallenge }: ChallengeState = useSelector( (state: AppStore) => state.ecolyo.challenge ) diff --git a/src/components/Hooks/useKonnectorAuth.tsx b/src/components/Hooks/useKonnectorAuth.tsx index 2feceda088b7979cff007c8b2f198db54eecf90e..2c5cfbad339da68ac1308a190808b657edadc046 100644 --- a/src/components/Hooks/useKonnectorAuth.tsx +++ b/src/components/Hooks/useKonnectorAuth.tsx @@ -10,12 +10,12 @@ import { FluidStatus, UsageEvent, } from 'models' -import { useCallback, useState } from 'react' +import { Dispatch, useCallback, useState } from 'react' import { useDispatch, useSelector } from 'react-redux' import AccountService from 'services/account.service' import ConnectionService from 'services/connection.service' import UsageEventService from 'services/usageEvent.service' -import { AppStore } from 'store' +import { AppActionsTypes, AppStore } from 'store' import { setLoading } from 'store/chart/chart.actions' import { updatedFluidConnection } from 'store/global/global.actions' import logApp from 'utils/logger' @@ -27,7 +27,7 @@ const useKonnectorAuth = ( ): [() => Promise<null | undefined>, () => Promise<void>, string] => { const client: Client = useClient() const { t } = useI18n() - const dispatch = useDispatch() + const dispatch = useDispatch<Dispatch<AppActionsTypes>>() const konnectorSlug: FluidSlugType = fluidStatus.connection.konnectorConfig.slug const { sgeConnect } = useSelector((state: AppStore) => state.ecolyo.global) diff --git a/src/components/Hooks/useUserInstanceSettings.tsx b/src/components/Hooks/useUserInstanceSettings.tsx index 00390b76c4a118c2f33820c0fd8755e923f9f4d1..8868e24e1312dbf1de8c01807568eb030cdd23fa 100644 --- a/src/components/Hooks/useUserInstanceSettings.tsx +++ b/src/components/Hooks/useUserInstanceSettings.tsx @@ -1,11 +1,12 @@ -import { useState, useEffect } from 'react' -import get from 'lodash/get' import { useClient } from 'cozy-client' +import get from 'lodash/get' import { UserInstanceSettings, UserInstanceSettingsAttributes } from 'models' +import { useEffect, useState } from 'react' const useUserInstanceSettings = (): UserInstanceSettings => { const client = useClient() const [settings, setSettings] = useState<UserInstanceSettingsAttributes>({ + // eslint-disable-next-line camelcase public_name: '', }) const [fetchStatus, setFetchStatus] = useState<string>('idle') diff --git a/src/components/Konnector/KonnectorModal.spec.tsx b/src/components/Konnector/KonnectorModal.spec.tsx index d10e41da64fe2e422ea9b3a767ea30f198d404bc..818ac1a95d4e84d1f6337c22066cc457875e785a 100644 --- a/src/components/Konnector/KonnectorModal.spec.tsx +++ b/src/components/Konnector/KonnectorModal.spec.tsx @@ -1,15 +1,11 @@ -import { mount } from 'enzyme' -import React from 'react' -import { Provider } from 'react-redux' -import { - createMockStore, - mockInitialEcolyoState, -} from '../../../tests/__mocks__/store' - import { Button } from '@material-ui/core' import { FluidType } from 'enum/fluid.enum' import { KonnectorError } from 'enum/konnectorError.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 KonnectorModal from './KonnectorModal' @@ -29,9 +25,9 @@ jest.mock('react-router-dom', () => ({ })) describe('KonnectorModal component', () => { - let store: any + const store = createMockEcolyoStore() beforeEach(() => { - store = createMockStore(mockInitialEcolyoState) + store.clearActions() jest.clearAllMocks() }) const mockHandleCloseClick = jest.fn() diff --git a/src/components/Konnector/KonnectorModal.tsx b/src/components/Konnector/KonnectorModal.tsx index 6796da60af91e44930b4132117a7ba45773a33ae..ec1294a18137b6332cb63b40e5c2c8751a44c17e 100644 --- a/src/components/Konnector/KonnectorModal.tsx +++ b/src/components/Konnector/KonnectorModal.tsx @@ -63,7 +63,7 @@ const KonnectorModal: React.FC<KonnectorModalProps> = ({ <div className="kmodal-waiting-text text-18-italic"> {shuffledWaitingTexts.map((text, idx) => ( <div - key={idx} + key={text.second} className={classNames('waiting-text', { ['show']: idx === index % shuffledWaitingTexts.length, })} @@ -84,7 +84,7 @@ const KonnectorModal: React.FC<KonnectorModalProps> = ({ ) : ( firstConnectionWaitingTexts.map((text, idx) => ( <div - key={idx} + key={text.second} className={classNames('waiting-text', { ['show']: idx === index % firstConnectionWaitingTexts.length, })} @@ -98,6 +98,33 @@ const KonnectorModal: React.FC<KonnectorModalProps> = ({ ) }, [firstConnectionWaitingTexts, index, isLogging, t]) + /** Returns connection success contents, depending on the fluid and update status */ + const connectionSuccessContent = () => ( + <div className="konnector-config"> + <Icon icon={successIcon} size={48} /> + <div className="kcs-picto-txt text-20-bold"> + {t(`konnector_modal.success_${isUpdating ? 'update_' : ''}txt`)} + </div> + <b> + {t( + `konnector_modal.success_data_${ + isUpdating ? 'update_' : '' + }${fluidName.toLowerCase()}` + )} + </b> + <p + style={{ fontWeight: 400 }} + dangerouslySetInnerHTML={{ + __html: t( + `konnector_modal.success_data_additional_${ + isUpdating ? 'update_' : '' + }${fluidName.toLowerCase()}` + ), + }} + /> + </div> + ) + useEffect(() => { const interval = setInterval(() => { if (open && !state) { @@ -213,8 +240,30 @@ const KonnectorModal: React.FC<KonnectorModalProps> = ({ </div> </div> )} + {error === KonnectorError.CHALLENGE_ASKED && + fluidType === FluidType.GAS && ( + // CONSENT FORM ERROR GRDF + <div className="konnector-config"> + <Icon icon={errorIcon} size={48} /> + <div className="kce-picto-txt text-20-bold"> + {t('konnector_modal.error_txt')} + </div> + <div className="title text-20-bold"> + {t('konnector_modal.error_consent_form_gas_title')} + </div> + <div className="err-data-2"> + {t('konnector_modal.error_consent_form_gas_content')} + </div> + <div className="err-data-2"> + {t( + 'konnector_modal.error_consent_form_gas_content_2' + )} + </div> + </div> + )} {error !== KonnectorError.LOGIN_FAILED && - error !== KonnectorError.TERMS_VERSION_MISMATCH && ( + error !== KonnectorError.TERMS_VERSION_MISMATCH && + error !== KonnectorError.CHALLENGE_ASKED && ( // DEFAULT CASE <div className="konnector-config"> {console.log('errortype', error)} @@ -236,24 +285,10 @@ const KonnectorModal: React.FC<KonnectorModalProps> = ({ )} </> )} - {state === SUCCESS_EVENT && ( - // SUCCESS CASE - <div className="konnector-config"> - <Icon icon={successIcon} size={48} /> - <div className="kcs-picto-txt text-20-bold"> - {t('konnector_modal.success_txt')} - </div> - {t( - `konnector_modal.success_data_${ - isUpdating ? 'update_' : '' - }${fluidName.toLowerCase()}` - )} - </div> - )} + {state === SUCCESS_EVENT && connectionSuccessContent()} <KonnectorModalFooter state={state} error={error} - fluidType={fluidType} handleCloseClick={handleCloseClick} handleAccountDeletion={handleAccountDeletion} account={account} diff --git a/src/components/Konnector/KonnectorModalFooter.spec.tsx b/src/components/Konnector/KonnectorModalFooter.spec.tsx index 19c858bc66503590f71b9b92cf77030b432d12f4..2502794d98d3dc758f077d25ad401f679f2921bd 100644 --- a/src/components/Konnector/KonnectorModalFooter.spec.tsx +++ b/src/components/Konnector/KonnectorModalFooter.spec.tsx @@ -7,10 +7,7 @@ import toJson from 'enzyme-to-json' import React from 'react' import { Provider } from 'react-redux' import { accountsData } from '../../../tests/__mocks__/accountsData.mock' -import { - createMockStore, - mockInitialEcolyoState, -} from '../../../tests/__mocks__/store' +import { createMockEcolyoStore } from '../../../tests/__mocks__/store' import { waitForComponentToPaint } from '../../../tests/__mocks__/testUtils' import KonnectorModalFooter from './KonnectorModalFooter' @@ -31,16 +28,9 @@ jest.mock('react-router-dom', () => ({ const mockClose = jest.fn() const mockDelete = jest.fn() describe('KonnectorModalFooter component', () => { - let store: MockStoreEnhanced< - { - ecolyo: { - global: GlobalState - } - }, - {} - > + const store = createMockEcolyoStore() beforeEach(() => { - store = createMockStore(mockInitialEcolyoState) + store.clearActions() mockDelete.mockClear() mockClose.mockClear() mockedNavigate.mockClear() @@ -82,7 +72,7 @@ describe('KonnectorModalFooter component', () => { ) }) - it('should render "come back later" for enedis sge when address / name / pdl are not matching (LOGIN_FAILED)', () => { + it('should render "try again" for enedis sge when address / name / pdl are not matching (LOGIN_FAILED)', () => { const wrapper = mount( <Provider store={store}> <KonnectorModalFooter @@ -96,9 +86,7 @@ describe('KonnectorModalFooter component', () => { /> </Provider> ) - expect(wrapper.find(Button).text()).toBe( - 'konnector_modal.button_come_back_later' - ) + expect(wrapper.find(Button).text()).toBe('konnector_modal.button_try_again') }) it('should render "later" and "Verify infos" for enedis sge encountering an error on contract (TERMS_VERSION_MISMATCH)', () => { diff --git a/src/components/Konnector/KonnectorModalFooter.tsx b/src/components/Konnector/KonnectorModalFooter.tsx index c8e14e357a442a2fbb47278a991d5498a92b48f9..7ebc8434aa6c45f056c3a0649e1a710c0e95f307 100644 --- a/src/components/Konnector/KonnectorModalFooter.tsx +++ b/src/components/Konnector/KonnectorModalFooter.tsx @@ -5,7 +5,6 @@ import { SUCCESS_EVENT, } from 'cozy-harvest-lib/dist/models/flowEvents' import { useI18n } from 'cozy-ui/transpiled/react/I18n' -import { FluidType } from 'enum/fluid.enum' import { KonnectorError } from 'enum/konnectorError.enum' import { Account } from 'models' import React, { useCallback } from 'react' @@ -16,7 +15,6 @@ import './konnectorModal.scss' interface KonnectorModalFooterProps { state: string | null error: KonnectorError | null - fluidType: FluidType handleCloseClick: (isSuccess?: boolean) => void handleAccountDeletion: () => Promise<void> account: Account | null @@ -26,7 +24,6 @@ interface KonnectorModalFooterProps { const KonnectorModalFooter: React.FC<KonnectorModalFooterProps> = ({ state, error, - fluidType, handleCloseClick, handleAccountDeletion, account, @@ -49,6 +46,20 @@ const KonnectorModalFooter: React.FC<KonnectorModalFooterProps> = ({ } }, [account, client, handleAccountDeletion, navigate]) + const defaultButton = ( + <Button + aria-label={t('konnector_modal.accessibility.button_close')} + onClick={() => handleCloseClick(state === SUCCESS_EVENT)} + classes={{ + root: 'btn-highlight', + label: 'text-16-bold', + }} + style={{ height: '40px' }} + > + <div>{t('konnector_modal.button_validate')}</div> + </Button> + ) + const errorButtons = () => { switch (error) { case KonnectorError.USER_ACTION_NEEDED: @@ -67,7 +78,8 @@ const KonnectorModalFooter: React.FC<KonnectorModalFooterProps> = ({ </Button> ) case KonnectorError.LOGIN_FAILED: - // MISMATCH NAME / ADDRESS / PDL + case KonnectorError.CHALLENGE_ASKED: + // INCOMPLETE CONSENT FORM - GRDF return ( <Button aria-label={t('konnector_modal.accessibility.button_close')} @@ -78,7 +90,7 @@ const KonnectorModalFooter: React.FC<KonnectorModalFooterProps> = ({ }} style={{ height: '40px' }} > - <div>{t('konnector_modal.button_come_back_later')}</div> + <div>{t('konnector_modal.button_try_again')}</div> </Button> ) case KonnectorError.TERMS_VERSION_MISMATCH: @@ -112,46 +124,11 @@ const KonnectorModalFooter: React.FC<KonnectorModalFooterProps> = ({ ) default: // DEFAULT FOOTER BUTTONS - // TODO change default button - return ( - <Button - aria-label={t('konnector_modal.accessibility.button_close')} - onClick={() => handleCloseClick(state === SUCCESS_EVENT)} - classes={{ - root: 'btn-highlight', - label: 'text-16-bold', - }} - style={{ height: '40px' }} - > - <div>{t('konnector_modal.button_validate')}</div> - </Button> - ) + return defaultButton } } - const successButton = () => { - // DEFAULT FOOTER BUTTONS - return ( - <Button - aria-label={t('konnector_modal.accessibility.button_close')} - onClick={() => handleCloseClick(state === SUCCESS_EVENT)} - classes={{ - root: 'btn-highlight', - label: 'text-16-bold', - }} - > - <div>{t('konnector_modal.button_validate')}</div> - </Button> - ) - } - - return ( - <> - {state === ERROR_EVENT && fluidType === FluidType.ELECTRICITY - ? errorButtons() - : successButton()} - </> - ) + return <>{state === ERROR_EVENT ? errorButtons() : defaultButton}</> } export default KonnectorModalFooter diff --git a/src/components/Konnector/KonnectorViewerCard.tsx b/src/components/Konnector/KonnectorViewerCard.tsx index e4b391981cf37fef3b8f4813f4eb3dcc578b42bc..9d4d51715dc4e34abebae9f459171a93d8353a96 100644 --- a/src/components/Konnector/KonnectorViewerCard.tsx +++ b/src/components/Konnector/KonnectorViewerCard.tsx @@ -39,7 +39,13 @@ import { UsageEvent, } from 'models' import { PartnersInfo } from 'models/partnersInfo.model' -import React, { useCallback, useEffect, useMemo, useState } from 'react' +import React, { + Dispatch, + useCallback, + useEffect, + useMemo, + useState, +} from 'react' import { useDispatch, useSelector } from 'react-redux' import AccountService from 'services/account.service' import ChallengeService from 'services/challenge.service' @@ -47,7 +53,7 @@ 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 { AppStore } from 'store' +import { AppActionsTypes, AppStore } from 'store' import { setChallengeConsumption } from 'store/challenge/challenge.actions' import { setSelectedDate } from 'store/chart/chart.actions' import { @@ -77,16 +83,17 @@ const KonnectorViewerCard: React.FC<KonnectorViewerCardProps> = ({ }: KonnectorViewerCardProps) => { const { t } = useI18n() const client = useClient() - const dispatch = useDispatch() + const dispatch = useDispatch<Dispatch<AppActionsTypes>>() 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 { fluidStatus: statusArray, shouldRefreshConsent } = useSelector( - (state: AppStore) => state.ecolyo.global - ) + const { + challenge: { currentChallenge }, + global: { fluidStatus: statusArray, shouldRefreshConsent, partnersInfo }, + } = useSelector((state: AppStore) => state.ecolyo) const [openModal, setOpenModal] = useState(false) const [isUpdating, setIsUpdating] = useState(false) @@ -100,9 +107,6 @@ const KonnectorViewerCard: React.FC<KonnectorViewerCardProps> = ({ [] ) const [isOutdatedData, setIsOutdatedData] = useState<number | null>(null) - const { currentChallenge } = useSelector( - (state: AppStore) => state.ecolyo.challenge - ) const fluidService = useMemo(() => new FluidService(client), [client]) const partnersInfoService = useMemo( () => new PartnersInfoService(client), @@ -132,7 +136,7 @@ const KonnectorViewerCard: React.FC<KonnectorViewerCardProps> = ({ const refDate = DateTime.fromISO('0001-01-01') let _lastDataDate: DateTime | null = DateTime.fromISO('0001-01-01') for (const fluid of _updatedFluidStatus) { - if (fluid && fluid?.lastDataDate && fluid?.lastDataDate > _lastDataDate) { + if (fluid?.lastDataDate && fluid?.lastDataDate > _lastDataDate) { _lastDataDate = fluid.lastDataDate } } @@ -183,27 +187,30 @@ const KonnectorViewerCard: React.FC<KonnectorViewerCardProps> = ({ const handleConnectionEnd = useCallback( async (isSuccess?: boolean) => { - if ( - // CASE FOR GLOBAL LOGIN FAILED - (account && - !isSuccess && - (konnectorErrorDescription === KonnectorError.LOGIN_FAILED || - konnectorErrorDescription === KonnectorError.UNKNOWN_ERROR || - konnectorErrorDescription == KonnectorError.CRITICAL) && - fluidStatus !== null && - fluidStatus.connection.account !== null && - fluidStatus.connection.account.auth !== undefined) || - // CASE FOR ENEDIS CODE INSEE ERROR - (account && - !isSuccess && - !isUpdating && - fluidType === FluidType.ELECTRICITY && - fluidStatus !== null && - fluidStatus.connection.account !== null && - fluidStatus.connection.account.auth !== undefined) - ) { + // CASE FOR GLOBAL LOGIN FAILED + const isGlobalLoginFailed = + konnectorErrorDescription === KonnectorError.LOGIN_FAILED || + konnectorErrorDescription === KonnectorError.UNKNOWN_ERROR || + konnectorErrorDescription === KonnectorError.CHALLENGE_ASKED || + konnectorErrorDescription === KonnectorError.CRITICAL + + // CASE FOR ENEDIS CODE INSEE ERROR + const isEnedisCodeInseeError = + !isUpdating && fluidType === FluidType.ELECTRICITY + + const shouldDeleteAccount = + account && + !isSuccess && + fluidStatus && + fluidStatus.connection.account && + (isGlobalLoginFailed || isEnedisCodeInseeError) + + if (shouldDeleteAccount) { // KEEP CREDENTIALS FOR EGL - if (fluidSlug === FluidSlugType.WATER) { + if ( + fluidSlug === FluidSlugType.WATER && + fluidStatus.connection.account?.auth + ) { const auth = fluidStatus.connection.account.auth as AccountAuthData fluidStatus.connection.konnectorConfig.lastKnownCredentials = auth.login @@ -221,11 +228,11 @@ const KonnectorViewerCard: React.FC<KonnectorViewerCardProps> = ({ ) } if (updatedFluidStatus.length > 0) { - const partnersInfo: PartnersInfo | undefined = - await partnersInfoService.getPartnersInfo() - const _updatedFluidStatus: FluidStatus[] = - await fluidService.getFluidStatus(partnersInfo) - dispatch(setFluidStatus(_updatedFluidStatus)) + // const partnersInfo = await partnersInfoService.getPartnersInfo() + const updatedFluidStatus = await fluidService.getFluidStatus( + partnersInfo + ) + dispatch(setFluidStatus(updatedFluidStatus)) } } @@ -246,8 +253,8 @@ const KonnectorViewerCard: React.FC<KonnectorViewerCardProps> = ({ client, handleAccountDeletion, updatedFluidStatus.length, - partnersInfoService, fluidService, + partnersInfo, dispatch, ] ) diff --git a/src/components/Konnector/KonnectorViewerList.spec.tsx b/src/components/Konnector/KonnectorViewerList.spec.tsx index e623dfe4d4867327c2a796f06d72b94bb3d029ad..638e43f17784e764184ca06f05ccdaeb4a69afd4 100644 --- a/src/components/Konnector/KonnectorViewerList.spec.tsx +++ b/src/components/Konnector/KonnectorViewerList.spec.tsx @@ -3,8 +3,7 @@ import React from 'react' import * as reactRedux from 'react-redux' import { Provider } from 'react-redux' import { - createMockStore, - mockInitialEcolyoState, + createMockEcolyoStore, mockInitialGlobalState, } from '../../../tests/__mocks__/store' import KonnectorViewerList from './KonnectorViewerList' @@ -25,9 +24,9 @@ jest.mock('react-router-dom', () => ({ })) describe('KonnectorViewerList component', () => { - let store: any + const store = createMockEcolyoStore() beforeEach(() => { - store = createMockStore(mockInitialEcolyoState) + store.clearActions() }) it('should be rendered correctly', () => { diff --git a/src/components/Konnector/__snapshots__/KonnectorModal.spec.tsx.snap b/src/components/Konnector/__snapshots__/KonnectorModal.spec.tsx.snap index 4e833e5a8723391b59f612379dd4e8fd0887f79f..7e78bb7234cb3219fd6bdf1a662adff251f9a8bb 100644 --- a/src/components/Konnector/__snapshots__/KonnectorModal.spec.tsx.snap +++ b/src/components/Konnector/__snapshots__/KonnectorModal.spec.tsx.snap @@ -491,7 +491,7 @@ exports[`KonnectorModal component should be rendered correctly 1`] = ` Le saviez-vous ? </p> <p> - Pour acheminer l’eau sur Lyon (Lugdunum !) l’acqueduc de Gier faisait 86 km à l’époque Romaine ! + Pour acheminer l’eau sur Lyon (Lugdunum !) l’aqueduc de Gier faisait 86 km à l’époque Romaine ! </p> </div> <div @@ -825,7 +825,7 @@ exports[`KonnectorModal component should be rendered correctly 1`] = ` > <div className="waiting-text show" - key="0" + key="" > <p> La première fois cela peut prendre quelques minutes, par la suite, seulement quelques secondes. @@ -834,7 +834,7 @@ exports[`KonnectorModal component should be rendered correctly 1`] = ` </div> <div className="waiting-text" - key="1" + key="" > <p> Afin de limiter le temps de ce premier chargement, un historique réduit de vos consommations va être chargé. Vous aurez tout de même accès à un an d'historique dès à présent. @@ -843,7 +843,7 @@ exports[`KonnectorModal component should be rendered correctly 1`] = ` </div> <div className="waiting-text" - key="2" + key="" > <p> Demain matin, vous aurez accès à l'ensemble de vos données (jusqu'à trois ans d'historique). @@ -852,18 +852,18 @@ exports[`KonnectorModal component should be rendered correctly 1`] = ` </div> <div className="waiting-text" - key="3" + key="Pour acheminer l’eau sur Lyon (Lugdunum !) l’aqueduc de Gier faisait 86 km à l’époque Romaine !" > <p> Le saviez-vous ? </p> <p> - Pour acheminer l’eau sur Lyon (Lugdunum !) l’acqueduc de Gier faisait 86 km à l’époque Romaine ! + Pour acheminer l’eau sur Lyon (Lugdunum !) l’aqueduc de Gier faisait 86 km à l’époque Romaine ! </p> </div> <div className="waiting-text" - key="4" + key="♪♪" > <p> Rien que de l’eau, de l’eau de pluie, de l’eau de la Métroooooo @@ -874,7 +874,7 @@ exports[`KonnectorModal component should be rendered correctly 1`] = ` </div> <div className="waiting-text" - key="5" + key="Environ 90% de notre électricité provient de centrales de production hors de notre métropole." > <p> Le saviez-vous ? @@ -885,7 +885,7 @@ exports[`KonnectorModal component should be rendered correctly 1`] = ` </div> <div className="waiting-text" - key="6" + key="Avec Ecolyo c’est l’eau AVEC le gaz." > <p> « Il y a de l’eau dans le gaz » … @@ -896,7 +896,7 @@ exports[`KonnectorModal component should be rendered correctly 1`] = ` </div> <div className="waiting-text" - key="7" + key="La consommation énergétique résidentielle représente environ 30% de la consommation énergétique totale de notre territoire." > <p> Le saviez-vous ? @@ -907,7 +907,7 @@ exports[`KonnectorModal component should be rendered correctly 1`] = ` </div> <div className="waiting-text" - key="8" + key="La Métropole de Lyon a été territoire d’expérimentation Linky. Le compteur est présent sur notre territoire depuis plus de 10 ans !" > <p> Le saviez-vous ? @@ -918,7 +918,7 @@ exports[`KonnectorModal component should be rendered correctly 1`] = ` </div> <div className="waiting-text" - key="9" + key="10 minutes d'aération par jour permettent à notre habitat d’être plus sain, avec un air renouvelé, moins de polluants et l’évacuation de l’humidité qui stagne et qui nous oblige à consommer plus de chauffage." > <p> Le saviez-vous ? @@ -929,7 +929,7 @@ exports[`KonnectorModal component should be rendered correctly 1`] = ` </div> <div className="waiting-text" - key="10" + key="2°C ! C’est la différence qu’on peut mesurer dans une rue bien arborée en comparaison d’une rue vide : la végétation est donc cruciale pour le bien être en ville l’été et pour limiter l’installation des climatiseurs." > <p> Le saviez-vous ? @@ -940,7 +940,7 @@ exports[`KonnectorModal component should be rendered correctly 1`] = ` </div> <div className="waiting-text" - key="11" + key="Le saviez-vous ? La loi énergie climat de 2019 impose que d’ici 2025, les bâtiments privés résidentiels les plus énergivores soient tous rénovés !" > <p> Il y a les bonnes pratiques de consommations énergétiques (et Ecolyo est là pour cela !) mais aussi et bien sûr, la rénovation. diff --git a/src/components/Konnector/__snapshots__/KonnectorModalFooter.spec.tsx.snap b/src/components/Konnector/__snapshots__/KonnectorModalFooter.spec.tsx.snap index 527aa6f28cc29dd6db93240fe135b592d52877e6..729e3c5d13d8721ad2e9fe24dbc4223c7940dad3 100644 --- a/src/components/Konnector/__snapshots__/KonnectorModalFooter.spec.tsx.snap +++ b/src/components/Konnector/__snapshots__/KonnectorModalFooter.spec.tsx.snap @@ -31,6 +31,11 @@ exports[`KonnectorModalFooter component should be rendered correctly 1`] = ` } } onClick={[Function]} + style={ + Object { + "height": "40px", + } + } > <ForwardRef(Button) aria-label="konnector_modal.accessibility.button_close" @@ -68,6 +73,11 @@ exports[`KonnectorModalFooter component should be rendered correctly 1`] = ` } } onClick={[Function]} + style={ + Object { + "height": "40px", + } + } > <WithStyles(ForwardRef(ButtonBase)) aria-label="konnector_modal.accessibility.button_close" @@ -77,6 +87,11 @@ exports[`KonnectorModalFooter component should be rendered correctly 1`] = ` focusRipple={true} focusVisibleClassName="Mui-focusVisible" onClick={[Function]} + style={ + Object { + "height": "40px", + } + } type="button" > <ForwardRef(ButtonBase) @@ -94,6 +109,11 @@ exports[`KonnectorModalFooter component should be rendered correctly 1`] = ` focusRipple={true} focusVisibleClassName="Mui-focusVisible" onClick={[Function]} + style={ + Object { + "height": "40px", + } + } type="button" > <button @@ -112,6 +132,11 @@ exports[`KonnectorModalFooter component should be rendered correctly 1`] = ` onTouchEnd={[Function]} onTouchMove={[Function]} onTouchStart={[Function]} + style={ + Object { + "height": "40px", + } + } tabIndex={0} type="button" > diff --git a/src/components/Loader/Loader.tsx b/src/components/Loader/Loader.tsx index 09aef3ec4626b91e1cfd7f0cd8b29d7fa2bf9f77..8f8928b0559b1553d1cf70b3892fd4b123c8992a 100644 --- a/src/components/Loader/Loader.tsx +++ b/src/components/Loader/Loader.tsx @@ -14,25 +14,26 @@ interface color { */ const Loader = ({ color = 'gold', fluidType }: color) => { const { t } = useI18n() + let variant = color switch (fluidType) { case FluidType.MULTIFLUID: - color = 'gold' + variant = 'gold' break case FluidType.ELECTRICITY: - color = 'elec' + variant = 'elec' break case FluidType.GAS: - color = 'gaz' + variant = 'gaz' break case FluidType.WATER: - color = 'water' + variant = 'water' break } return ( <div - className={`loader ${color}`} + className={`loader ${variant}`} aria-busy="true" aria-label={t('common.accessibility.loading')} title={t('common.accessibility.loading')} diff --git a/src/components/Navbar/Navbar.spec.tsx b/src/components/Navbar/Navbar.spec.tsx index 07be998ffe070da06a074117d7a28b891c5e0bd8..e9a446415d50e8c680620dd4f5983a41f2437f33 100644 --- a/src/components/Navbar/Navbar.spec.tsx +++ b/src/components/Navbar/Navbar.spec.tsx @@ -1,9 +1,9 @@ -import React from 'react' +import Navbar from 'components/Navbar/Navbar' import { mount } from 'enzyme' -import { BrowserRouter } from 'react-router-dom' +import React from 'react' import { Provider } from 'react-redux' +import { BrowserRouter } from 'react-router-dom' import configureStore from 'redux-mock-store' -import Navbar from 'components/Navbar/Navbar' import { globalStateData } from '../../../tests/__mocks__/globalStateData.mock' jest.mock('cozy-ui/transpiled/react/I18n', () => { diff --git a/src/components/Options/Accessibility/Accessibility.tsx b/src/components/Options/Accessibility/Accessibility.tsx new file mode 100644 index 0000000000000000000000000000000000000000..6bbb4be6c1cee42bb04b59bc5548190d9b833aef --- /dev/null +++ b/src/components/Options/Accessibility/Accessibility.tsx @@ -0,0 +1,38 @@ +import Link from '@material-ui/core/Link' +import AccessibilityIcon from 'assets/icons/ico/accessibility.svg' +import StyledIcon from 'components/CommonKit/Icon/StyledIcon' +import { useI18n } from 'cozy-ui/transpiled/react/I18n' +import React from 'react' +import '../GCU/gcuLink.scss' + +const Accessibility: React.FC = () => { + const { t } = useI18n() + return ( + <div className="gcu-link-root"> + <div className="gcu-link-content"> + <Link + className="gcu-link-card-link" + href="https://ecolyo.com/accessibilite.html" + target="_blank" + > + <div className="card optionCard"> + <div className="gcu-link-card"> + <div className="gcu-link-card-content"> + <StyledIcon + className="gcu-link-card-content-icon" + icon={AccessibilityIcon} + size={42} + /> + <div className="gcu-link-card-content-title"> + {t('common.title_accessibility')} + </div> + </div> + </div> + </div> + </Link> + </div> + </div> + ) +} + +export default Accessibility diff --git a/src/components/Options/exportOptions.spec.tsx b/src/components/Options/ExportData/ExportData.spec.tsx similarity index 72% rename from src/components/Options/exportOptions.spec.tsx rename to src/components/Options/ExportData/ExportData.spec.tsx index f9248186d09ff934f3b3ca8532afd8beac73aebb..ef4cf3cf380dee33473741923879b06f45d33c6b 100644 --- a/src/components/Options/exportOptions.spec.tsx +++ b/src/components/Options/ExportData/ExportData.spec.tsx @@ -1,8 +1,9 @@ -import ExportOptions from 'components/Options/exportOptions' import { mount } from 'enzyme' import toJson from 'enzyme-to-json' import React from 'react' -import mockClient from '../../../tests/__mocks__/client' +import mockClient from '../../../../tests/__mocks__/client' + +import ExportData from './ExportData' jest.mock('cozy-ui/transpiled/react/I18n', () => { return { @@ -13,12 +14,16 @@ jest.mock('cozy-ui/transpiled/react/I18n', () => { }), } }) +const mockGetExportableFluids = jest.fn(() => { + return [] +}) jest.mock('services/consumption.service', () => { return jest.fn(() => { return { fetchAllFirstDateData: jest.fn(() => { return [null, null, null] }), + getExportableFluids: mockGetExportableFluids, } }) }) @@ -29,7 +34,7 @@ jest.mock('cozy-client', () => ({ describe('exportOptions component', () => { it('should be rendered correctly', async () => { - const wrapper = mount(<ExportOptions />) + const wrapper = mount(<ExportData />) expect(toJson(wrapper)).toMatchSnapshot() }) }) diff --git a/src/components/Options/exportOptions.tsx b/src/components/Options/ExportData/ExportData.tsx similarity index 95% rename from src/components/Options/exportOptions.tsx rename to src/components/Options/ExportData/ExportData.tsx index bce44da306f943c2c4e16d72d8bd655a8827c573..1e9df7f5b87b0d8ecab95efd714cdc04c99a3fae 100644 --- a/src/components/Options/exportOptions.tsx +++ b/src/components/Options/ExportData/ExportData.tsx @@ -18,9 +18,9 @@ import { TimeStep } from 'enum/timeStep.enum' import { remove } from 'lodash' import React, { useEffect, useMemo, useState } from 'react' import ConsumptionDataManager from 'services/consumption.service' -import './exportOptions.scss' +import './exportData.scss' -const ExportOptions: React.FC = () => { +const ExportData: React.FC = () => { const { t } = useI18n() const client = useClient() const consumptionService = useMemo( @@ -190,4 +190,4 @@ const ExportOptions: React.FC = () => { ) } -export default ExportOptions +export default ExportData diff --git a/src/components/Options/__snapshots__/exportOptions.spec.tsx.snap b/src/components/Options/ExportData/__snapshots__/ExportData.spec.tsx.snap similarity index 99% rename from src/components/Options/__snapshots__/exportOptions.spec.tsx.snap rename to src/components/Options/ExportData/__snapshots__/ExportData.spec.tsx.snap index aa4c3579151d165dc4d3cd7204c80e86598c680c..4e44f56f7bad8f699c0c34792f19317cce030178 100644 --- a/src/components/Options/__snapshots__/exportOptions.spec.tsx.snap +++ b/src/components/Options/ExportData/__snapshots__/ExportData.spec.tsx.snap @@ -1,7 +1,7 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP exports[`exportOptions component should be rendered correctly 1`] = ` -<ExportOptions> +<ExportData> <div className="export-option-root" > @@ -1180,5 +1180,5 @@ exports[`exportOptions component should be rendered correctly 1`] = ` </ForwardRef(Dialog)> </WithStyles(ForwardRef(Dialog))> </ExportDoneModal> -</ExportOptions> +</ExportData> `; diff --git a/src/components/Options/exportOptions.scss b/src/components/Options/ExportData/exportData.scss similarity index 100% rename from src/components/Options/exportOptions.scss rename to src/components/Options/ExportData/exportData.scss diff --git a/src/components/GCU/GCUContent.spec.tsx b/src/components/Options/GCU/GCUContent.spec.tsx similarity index 89% rename from src/components/GCU/GCUContent.spec.tsx rename to src/components/Options/GCU/GCUContent.spec.tsx index 7b79865dec3e577616cd4c72a26ad0416f8d6dc4..f7480cd76e1780e54a5cd5e26834b39939143397 100644 --- a/src/components/GCU/GCUContent.spec.tsx +++ b/src/components/Options/GCU/GCUContent.spec.tsx @@ -1,6 +1,6 @@ -import React from 'react' +import GCUContent from 'components/Options/GCU/GCUContent' import { shallow } from 'enzyme' -import GCUContent from 'components/GCU/GCUContent' +import React from 'react' jest.mock('cozy-ui/transpiled/react/I18n', () => { return { diff --git a/src/components/GCU/GCUContent.tsx b/src/components/Options/GCU/GCUContent.tsx similarity index 90% rename from src/components/GCU/GCUContent.tsx rename to src/components/Options/GCU/GCUContent.tsx index ec398cb5dcb7be24f47c81778f87594013c00ed5..1ecb3fcc6d3cc0eb9387d219dc1daa27add51278 100644 --- a/src/components/GCU/GCUContent.tsx +++ b/src/components/Options/GCU/GCUContent.tsx @@ -1,28 +1,15 @@ -import React from 'react' -import './gcuContent.scss' import { useI18n } from 'cozy-ui/transpiled/react/I18n' +import React from 'react' import { decoreText } from 'utils/decoreText' +import './gcuContent.scss' -interface GCUContentProps { - fromOption?: boolean -} - -const GCUContent: React.FC<GCUContentProps> = ({ - fromOption = false, -}: GCUContentProps) => { +const GCUContent = (): JSX.Element => { const { t } = useI18n() return ( <div className="gcu-content-root"> <div className="gcu-content-wrapper"> - <h1 className="gcu-content-title text-22-normal">{t('gcu.title')}</h1> <p className="text-14-normal version">{t('gcu.version')}</p> - {fromOption && ( - <h2 className="gcu-content-subtitle text-16-italic"> - {t('gcu.subtitle')} - </h2> - )} - <div className="gcu-content-part-title text-15-normal"> {t('gcu.content.title1')} </div> diff --git a/src/components/GCU/GCULink.spec.tsx b/src/components/Options/GCU/GCULink.spec.tsx similarity index 81% rename from src/components/GCU/GCULink.spec.tsx rename to src/components/Options/GCU/GCULink.spec.tsx index 58988606516a277e9efb68559a440f7bb2e47677..cf64c957da4db31d4223ace43ded22753cb9d094 100644 --- a/src/components/GCU/GCULink.spec.tsx +++ b/src/components/Options/GCU/GCULink.spec.tsx @@ -1,6 +1,6 @@ -import React from 'react' +import LegalNoticeLink from 'components/Options/LegalNotice/LegalNoticeLink' import { shallow } from 'enzyme' -import LegalNoticeLink from 'components/LegalNotice/LegalNoticeLink' +import React from 'react' jest.mock('cozy-ui/transpiled/react/I18n', () => { return { diff --git a/src/components/GCU/GCULink.tsx b/src/components/Options/GCU/GCULink.tsx similarity index 84% rename from src/components/GCU/GCULink.tsx rename to src/components/Options/GCU/GCULink.tsx index f1ce6a8c5e7bd1c07b79978819cd434ced64dcc5..4e63440137a272037746f71d31212f1f39f529e8 100644 --- a/src/components/GCU/GCULink.tsx +++ b/src/components/Options/GCU/GCULink.tsx @@ -1,5 +1,5 @@ import Link from '@material-ui/core/Link' -import LegalNoticeIcon from 'assets/icons/ico/legal-notice.svg' +import GCUIcon from 'assets/icons/ico/gcu.svg' import StyledIcon from 'components/CommonKit/Icon/StyledIcon' import { useI18n } from 'cozy-ui/transpiled/react/I18n' import React from 'react' @@ -21,11 +21,11 @@ const GCULink: React.FC = () => { <div className="gcu-link-card-content"> <StyledIcon className="gcu-link-card-content-icon" - icon={LegalNoticeIcon} + icon={GCUIcon} size={42} /> <div className="gcu-link-card-content-title"> - {t('gcu_option.title')} + {t('common.title_gcu')} </div> </div> </div> diff --git a/src/components/GCU/GCUView.spec.tsx b/src/components/Options/GCU/GCUView.spec.tsx similarity index 86% rename from src/components/GCU/GCUView.spec.tsx rename to src/components/Options/GCU/GCUView.spec.tsx index 6ede9dbdc54199016cf3717f459440d15105735f..9692ba84bd47f3ade5d9474547d8139142f116fd 100644 --- a/src/components/GCU/GCUView.spec.tsx +++ b/src/components/Options/GCU/GCUView.spec.tsx @@ -1,6 +1,6 @@ -import React from 'react' +import GCUView from 'components/Options/GCU/GCUView' import { shallow } from 'enzyme' -import GCUView from 'components/GCU/GCUView' +import React from 'react' jest.mock('components/Header/CozyBar', () => 'mock-cozybar') jest.mock('components/Header/Header', () => 'mock-header') diff --git a/src/components/GCU/GCUView.tsx b/src/components/Options/GCU/GCUView.tsx similarity index 92% rename from src/components/GCU/GCUView.tsx rename to src/components/Options/GCU/GCUView.tsx index 841c4832243bbc5836ba57800051df27e70a8229..49439dd79c4a4a105c69035967d3ccd8fd8d3730 100644 --- a/src/components/GCU/GCUView.tsx +++ b/src/components/Options/GCU/GCUView.tsx @@ -1,7 +1,7 @@ import Content from 'components/Content/Content' -import GCUContent from 'components/GCU/GCUContent' 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' const GCUView: React.FC = () => { diff --git a/src/components/GCU/__snapshots__/GCUContent.spec.tsx.snap b/src/components/Options/GCU/__snapshots__/GCUContent.spec.tsx.snap similarity index 98% rename from src/components/GCU/__snapshots__/GCUContent.spec.tsx.snap rename to src/components/Options/GCU/__snapshots__/GCUContent.spec.tsx.snap index 67a32efc169d6ad61786a0027d3cca580f41e6e6..007cca08c725d8850df473c4f4c49142a34f2de1 100644 --- a/src/components/GCU/__snapshots__/GCUContent.spec.tsx.snap +++ b/src/components/Options/GCU/__snapshots__/GCUContent.spec.tsx.snap @@ -7,11 +7,6 @@ exports[`GCUContent component should be rendered correctly 1`] = ` <div className="gcu-content-wrapper" > - <h1 - className="gcu-content-title text-22-normal" - > - gcu.title - </h1> <p className="text-14-normal version" > @@ -299,11 +294,6 @@ exports[`GCUContent component should display a link when translation contains <a <div className="gcu-content-wrapper" > - <h1 - className="gcu-content-title text-22-normal" - > - gcu.title - </h1> <p className="text-14-normal version" > diff --git a/src/components/GCU/__snapshots__/GCULink.spec.tsx.snap b/src/components/Options/GCU/__snapshots__/GCULink.spec.tsx.snap similarity index 100% rename from src/components/GCU/__snapshots__/GCULink.spec.tsx.snap rename to src/components/Options/GCU/__snapshots__/GCULink.spec.tsx.snap diff --git a/src/components/GCU/__snapshots__/GCUView.spec.tsx.snap b/src/components/Options/GCU/__snapshots__/GCUView.spec.tsx.snap similarity index 100% rename from src/components/GCU/__snapshots__/GCUView.spec.tsx.snap rename to src/components/Options/GCU/__snapshots__/GCUView.spec.tsx.snap diff --git a/src/components/GCU/gcuContent.scss b/src/components/Options/GCU/gcuContent.scss similarity index 100% rename from src/components/GCU/gcuContent.scss rename to src/components/Options/GCU/gcuContent.scss diff --git a/src/components/GCU/gcuLink.scss b/src/components/Options/GCU/gcuLink.scss similarity index 100% rename from src/components/GCU/gcuLink.scss rename to src/components/Options/GCU/gcuLink.scss diff --git a/src/components/Options/HelpLink/HelpLink.tsx b/src/components/Options/HelpLink/HelpLink.tsx index 7311138ae02517f63607ce95f2d93294bb061765..ee6ac458eec091d2c476caf410cfa221f7bf22e3 100644 --- a/src/components/Options/HelpLink/HelpLink.tsx +++ b/src/components/Options/HelpLink/HelpLink.tsx @@ -2,19 +2,20 @@ 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 from 'react' +import React, { Dispatch } from 'react' import { useDispatch } from 'react-redux' -import { updateModalIsFeedbacksOpen } from 'store/modal/modal.actions' +import { AppActionsTypes } from 'store' +import { openFeedbackModal } from 'store/modal/modal.actions' import './HelpLink.scss' const HelpLink: React.FC = () => { const { t } = useI18n() - const dispatch = useDispatch() + const dispatch = useDispatch<Dispatch<AppActionsTypes>>() return ( <div className="help-root" - onClick={() => dispatch(updateModalIsFeedbacksOpen(true))} + onClick={() => dispatch(openFeedbackModal(true))} > <div className="help-content"> <div className="help-header text-16-normal-uppercase"> diff --git a/src/components/LegalNotice/LegalNoticeContent.spec.tsx b/src/components/Options/LegalNotice/LegalNoticeContent.spec.tsx similarity index 83% rename from src/components/LegalNotice/LegalNoticeContent.spec.tsx rename to src/components/Options/LegalNotice/LegalNoticeContent.spec.tsx index c0aec753959902fa6697d74ec196de167d487857..ed6459952bfe193088413580e22590772e697415 100644 --- a/src/components/LegalNotice/LegalNoticeContent.spec.tsx +++ b/src/components/Options/LegalNotice/LegalNoticeContent.spec.tsx @@ -1,6 +1,6 @@ -import React from 'react' +import LegalNoticeContent from 'components/Options/LegalNotice/LegalNoticeContent' import { shallow } from 'enzyme' -import LegalNoticeContent from 'components/LegalNotice/LegalNoticeContent' +import React from 'react' jest.mock('cozy-ui/transpiled/react/I18n', () => { return { diff --git a/src/components/LegalNotice/LegalNoticeContent.tsx b/src/components/Options/LegalNotice/LegalNoticeContent.tsx similarity index 98% rename from src/components/LegalNotice/LegalNoticeContent.tsx rename to src/components/Options/LegalNotice/LegalNoticeContent.tsx index 4b14ca7f09a524eee7a1d247ef0d5c8ab5df9eef..c19f2bff78e1662cdf148e9c30e40ebdd56a0142 100644 --- a/src/components/LegalNotice/LegalNoticeContent.tsx +++ b/src/components/Options/LegalNotice/LegalNoticeContent.tsx @@ -1,8 +1,7 @@ -import React from 'react' - -import './legalNoticeView.scss' import { useI18n } from 'cozy-ui/transpiled/react/I18n' +import React from 'react' import { decoreText } from 'utils/decoreText' +import './legalNoticeView.scss' const LegalNoticeContent: React.FC = () => { const { t } = useI18n() @@ -10,7 +9,6 @@ const LegalNoticeContent: React.FC = () => { <> <div className="legal-notice-root"> <div className="legal-notice-content"> - <h2>{t('legal.title_legal')}</h2> <p className="version">{t('legal.version')}</p> <p>{decoreText(t('legal.site'))}</p> <p>{t('legal.adress')}</p> diff --git a/src/components/LegalNotice/LegalNoticeLink.spec.tsx b/src/components/Options/LegalNotice/LegalNoticeLink.spec.tsx similarity index 84% rename from src/components/LegalNotice/LegalNoticeLink.spec.tsx rename to src/components/Options/LegalNotice/LegalNoticeLink.spec.tsx index 9302b6be360e376f21cd1eacf9ffeab80de695ab..dcea071586f5b63f1e8e1dcdcfd9ee0e1956bcd6 100644 --- a/src/components/LegalNotice/LegalNoticeLink.spec.tsx +++ b/src/components/Options/LegalNotice/LegalNoticeLink.spec.tsx @@ -1,6 +1,6 @@ -import React from 'react' +import GCULink from 'components/Options/GCU/GCULink' import { shallow } from 'enzyme' -import GCULink from 'components/GCU/GCULink' +import React from 'react' jest.mock('cozy-ui/transpiled/react/I18n', () => { return { diff --git a/src/components/LegalNotice/LegalNoticeLink.tsx b/src/components/Options/LegalNotice/LegalNoticeLink.tsx similarity index 100% rename from src/components/LegalNotice/LegalNoticeLink.tsx rename to src/components/Options/LegalNotice/LegalNoticeLink.tsx diff --git a/src/components/LegalNotice/LegalNoticeView.spec.tsx b/src/components/Options/LegalNotice/LegalNoticeView.spec.tsx similarity index 85% rename from src/components/LegalNotice/LegalNoticeView.spec.tsx rename to src/components/Options/LegalNotice/LegalNoticeView.spec.tsx index 2c3c35247f8254d480c68843e29cc04757bb8d5e..247058c8f1f903f18a043784141abe544abc2c1b 100644 --- a/src/components/LegalNotice/LegalNoticeView.spec.tsx +++ b/src/components/Options/LegalNotice/LegalNoticeView.spec.tsx @@ -1,6 +1,6 @@ -import React from 'react' +import LegalNoticeView from 'components/Options/LegalNotice/LegalNoticeView' import { shallow } from 'enzyme' -import LegalNoticeView from 'components/LegalNotice/LegalNoticeView' +import React from 'react' jest.mock('components/Header/CozyBar', () => 'mock-cozybar') jest.mock('components/Header/Header', () => 'mock-header') diff --git a/src/components/LegalNotice/LegalNoticeView.tsx b/src/components/Options/LegalNotice/LegalNoticeView.tsx similarity index 100% rename from src/components/LegalNotice/LegalNoticeView.tsx rename to src/components/Options/LegalNotice/LegalNoticeView.tsx diff --git a/src/components/LegalNotice/__snapshots__/LegalNoticeContent.spec.tsx.snap b/src/components/Options/LegalNotice/__snapshots__/LegalNoticeContent.spec.tsx.snap similarity index 99% rename from src/components/LegalNotice/__snapshots__/LegalNoticeContent.spec.tsx.snap rename to src/components/Options/LegalNotice/__snapshots__/LegalNoticeContent.spec.tsx.snap index f1a119c2c28210b3e9fdf7be12c91ddcaba56f37..69a5b05402c63a1db03028dd805a630148bf4493 100644 --- a/src/components/LegalNotice/__snapshots__/LegalNoticeContent.spec.tsx.snap +++ b/src/components/Options/LegalNotice/__snapshots__/LegalNoticeContent.spec.tsx.snap @@ -8,9 +8,6 @@ exports[`LegalNoticeContent component should be rendered correctly 1`] = ` <div className="legal-notice-content" > - <h2> - legal.title_legal - </h2> <p className="version" > diff --git a/src/components/LegalNotice/__snapshots__/LegalNoticeLink.spec.tsx.snap b/src/components/Options/LegalNotice/__snapshots__/LegalNoticeLink.spec.tsx.snap similarity index 96% rename from src/components/LegalNotice/__snapshots__/LegalNoticeLink.spec.tsx.snap rename to src/components/Options/LegalNotice/__snapshots__/LegalNoticeLink.spec.tsx.snap index 3192ae8c74d7a39002c78a66261ebc5a0577af7f..39d58611ad43a93d5cdd60390f6fc623a1f9e9c6 100644 --- a/src/components/LegalNotice/__snapshots__/LegalNoticeLink.spec.tsx.snap +++ b/src/components/Options/LegalNotice/__snapshots__/LegalNoticeLink.spec.tsx.snap @@ -35,7 +35,7 @@ exports[`GCULink component should be rendered correctly 1`] = ` <div className="gcu-link-card-content-title" > - gcu_option.title + common.title_gcu </div> </div> </div> diff --git a/src/components/LegalNotice/__snapshots__/LegalNoticeView.spec.tsx.snap b/src/components/Options/LegalNotice/__snapshots__/LegalNoticeView.spec.tsx.snap similarity index 100% rename from src/components/LegalNotice/__snapshots__/LegalNoticeView.spec.tsx.snap rename to src/components/Options/LegalNotice/__snapshots__/LegalNoticeView.spec.tsx.snap diff --git a/src/components/LegalNotice/legalNoticeLink.scss b/src/components/Options/LegalNotice/legalNoticeLink.scss similarity index 100% rename from src/components/LegalNotice/legalNoticeLink.scss rename to src/components/Options/LegalNotice/legalNoticeLink.scss diff --git a/src/components/LegalNotice/legalNoticeView.scss b/src/components/Options/LegalNotice/legalNoticeView.scss similarity index 100% rename from src/components/LegalNotice/legalNoticeView.scss rename to src/components/Options/LegalNotice/legalNoticeView.scss diff --git a/src/components/Options/MatomoOptOut/MatomoOptOut.spec.tsx b/src/components/Options/MatomoOptOut/MatomoOptOut.spec.tsx index 69296c020177a909d8e354410040bccab0cd60d9..c74c68c3b5a31ece0daaf62befb2bc232697559a 100644 --- a/src/components/Options/MatomoOptOut/MatomoOptOut.spec.tsx +++ b/src/components/Options/MatomoOptOut/MatomoOptOut.spec.tsx @@ -1,5 +1,5 @@ -import React from 'react' import { shallow } from 'enzyme' +import React from 'react' import MatomoOptOut from './MatomoOptOut' jest.mock('cozy-ui/transpiled/react/I18n', () => { diff --git a/src/components/Options/MatomoOptOut/MatomoOptOut.tsx b/src/components/Options/MatomoOptOut/MatomoOptOut.tsx index 127642014faec613eb8798cc55e6be0803848fbc..04bf325167112608fd5994532ae21eddad8cbfd5 100644 --- a/src/components/Options/MatomoOptOut/MatomoOptOut.tsx +++ b/src/components/Options/MatomoOptOut/MatomoOptOut.tsx @@ -1,5 +1,5 @@ -import React from 'react' import { useI18n } from 'cozy-ui/transpiled/react/I18n' +import React from 'react' import './matomoOptOut.scss' declare let __PIWIK_TRACKER_URL__: string diff --git a/src/components/Options/OptionsView.spec.tsx b/src/components/Options/OptionsView.spec.tsx index 0f2f73c8d8ff3cec0c7882d4425683ba66266c7e..d0a1f04c6d5ca25e34771add9ad9c5b51eb71a45 100644 --- a/src/components/Options/OptionsView.spec.tsx +++ b/src/components/Options/OptionsView.spec.tsx @@ -1,6 +1,6 @@ -import React from 'react' -import { shallow } from 'enzyme' import OptionsView from 'components/Options/OptionsView' +import { shallow } from 'enzyme' +import React from 'react' jest.mock('components/Header/CozyBar', () => 'mock-cozybar') jest.mock('components/Header/Header', () => 'mock-header') diff --git a/src/components/Options/OptionsView.tsx b/src/components/Options/OptionsView.tsx index ed07406fddecb8a5d824206ac99975b8fa7bdffe..8fd37c74a2cfd4f320954aa00290beb25027ca9e 100644 --- a/src/components/Options/OptionsView.tsx +++ b/src/components/Options/OptionsView.tsx @@ -1,16 +1,17 @@ import logos from 'assets/png/logos_partenaires.svg' import Content from 'components/Content/Content' -import GCULink from 'components/GCU/GCULink' import CozyBar from 'components/Header/CozyBar' import Header from 'components/Header/Header' -import LegalNoticeLink from 'components/LegalNotice/LegalNoticeLink' -import ExportOptions from 'components/Options/exportOptions' -import Version from 'components/Version/Version' import React, { useState } from 'react' +import Accessibility from './Accessibility/Accessibility' +import ExportData from './ExportData/ExportData' +import GCULink from './GCU/GCULink' import HelpLink from './HelpLink/HelpLink' +import LegalNoticeLink from './LegalNotice/LegalNoticeLink' import MatomoOptOut from './MatomoOptOut/MatomoOptOut' import ProfileTypeOptions from './ProfileTypeOptions/ProfileTypeOptions' import ReportOptions from './ReportOptions/ReportOptions' +import Version from './Version/Version' const OptionsView: React.FC = () => { const [headerHeight, setHeaderHeight] = useState<number>(0) @@ -27,11 +28,12 @@ const OptionsView: React.FC = () => { /> <Content height={headerHeight}> <ProfileTypeOptions /> - <ExportOptions /> + <ExportData /> <ReportOptions /> <HelpLink /> <LegalNoticeLink /> <GCULink /> + <Accessibility /> <MatomoOptOut /> <div className="parameters-logos"> <img src={logos} alt="ensemble de logos" /> diff --git a/src/components/Options/ProfileTypeOptions/ProfileTypeOptions.spec.tsx b/src/components/Options/ProfileTypeOptions/ProfileTypeOptions.spec.tsx index 99104e6589dd5a5e3abaa5159bb35f70431e71f7..5189e961c095c86d7a12caa2dfd504ab2f2fa399 100644 --- a/src/components/Options/ProfileTypeOptions/ProfileTypeOptions.spec.tsx +++ b/src/components/Options/ProfileTypeOptions/ProfileTypeOptions.spec.tsx @@ -70,11 +70,11 @@ describe('ProfileTypeOptions component', () => { ) expect(wrapper.find('.profile-container').exists()).toBeTruthy() }) - it('should be rendered when housing_type = appartment', () => { + it('should be rendered when housing_type = apartment', () => { const profileTypeCompleted = { ...profileData } const profileTypeData = { ...mockProfileType } profileTypeCompleted.isProfileTypeCompleted = true - profileTypeData.housingType = HousingType.APPARTMENT + profileTypeData.housingType = HousingType.APARTMENT const store = mockStore({ ecolyo: { profile: profileTypeCompleted, @@ -97,7 +97,7 @@ describe('ProfileTypeOptions component', () => { profileTypeData.heating = IndividualOrCollective.INDIVIDUAL profileTypeCompleted.isProfileTypeCompleted = true - profileTypeData.housingType = HousingType.APPARTMENT + profileTypeData.housingType = HousingType.APARTMENT profileTypeData.hasInstalledVentilation = ThreeChoicesAnswer.YES profileTypeData.hasReplacedHeater = ThreeChoicesAnswer.YES const store = mockStore({ @@ -121,7 +121,7 @@ describe('ProfileTypeOptions component', () => { const profileTypeData = { ...mockProfileType } profileTypeCompleted.isProfileTypeCompleted = true - profileTypeData.housingType = HousingType.APPARTMENT + profileTypeData.housingType = HousingType.APARTMENT profileTypeData.individualInsulationWork = [ IndividualInsulationWork.ROOF_INSULATION, IndividualInsulationWork.WINDOW_REPLACEMENT, diff --git a/src/components/Options/ProfileTypeOptions/ProfileTypeOptions.tsx b/src/components/Options/ProfileTypeOptions/ProfileTypeOptions.tsx index f9584017073f82571905afd387ab6ae102ff97bd..72a98af3e38651d4a5183dcba9d805d6e2d2746d 100644 --- a/src/components/Options/ProfileTypeOptions/ProfileTypeOptions.tsx +++ b/src/components/Options/ProfileTypeOptions/ProfileTypeOptions.tsx @@ -1,34 +1,34 @@ -import Button from '@material-ui/core/Button' -import { useI18n } from 'cozy-ui/transpiled/react/I18n' -import { FluidType } from 'enum/fluid.enum' -import { - HousingType, - IndividualOrCollective, - OutsideFacingWalls, - ThreeChoicesAnswer, -} from 'enum/profileType.enum' -import React, { useCallback, useState } from 'react' -import { useSelector } from 'react-redux' -import { AppStore } from 'store' -import './profileTypeOptions.scss' - import { Accordion, AccordionDetails, AccordionSummary, } from '@material-ui/core' +import Button from '@material-ui/core/Button' import chevronDown from 'assets/icons/ico/chevron-down.svg' import profileIcon from 'assets/icons/ico/profile.svg' import StyledCard from 'components/CommonKit/Card/StyledCard' 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 { + 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' import { useNavigate } from 'react-router-dom' +import { AppStore } from 'store' +import './profileTypeOptions.scss' const ProfileTypeOptions: React.FC = () => { - const profile = useSelector((state: AppStore) => state.ecolyo.profile) - const profileType = useSelector((state: AppStore) => state.ecolyo.profileType) + const { profile, profileType } = useSelector( + (state: AppStore) => state.ecolyo + ) const { t } = useI18n() const navigate = useNavigate() const [, setValidExploration] = useExploration() @@ -108,7 +108,7 @@ const ProfileTypeOptions: React.FC = () => { ? t('profile_type.occupantsNumber.multi') : t('profile_type.occupantsNumber.single')} </div> - {profileType.housingType === HousingType.APPARTMENT && ( + {profileType.housingType === HousingType.APARTMENT && ( <div className="value floor"> {t(`profile_type.floor.${profileType.floor}`)} </div> @@ -173,17 +173,13 @@ const ProfileTypeOptions: React.FC = () => { {t(`profile_type.hot_water.${profileType.hotWater}`)} </div> <div className="value"> - {profileType.warmingFluid !== null && - profileType.heating === IndividualOrCollective.INDIVIDUAL - ? t( - `profile_type.hot_water_fluid.${ - profileType.hotWaterFluid + '_text' - }` - ) - : profileType.heating === - IndividualOrCollective.INDIVIDUAL - ? t('profile_type.hot_water_fluid.no_fluid_text') - : ''} + {profileType.heating === + IndividualOrCollective.INDIVIDUAL && + (profileType.warmingFluid !== null + ? t( + `profile_type.hot_water_fluid.${profileType.hotWaterFluid}_text` + ) + : t('profile_type.hot_water_fluid.no_fluid_text'))} </div> {profileType.hotWater === IndividualOrCollective.INDIVIDUAL && ( @@ -200,13 +196,11 @@ const ProfileTypeOptions: React.FC = () => { {t('profile_type.individual_insulation_work.title')} </div> - {profileType.individualInsulationWork.map((work, index) => { - return ( - <div key={index} className="value"> - {t(`profile_type.individual_insulation_work.${work}`)} - </div> - ) - })} + {profileType.individualInsulationWork.map(work => ( + <div key={work} className="value"> + {t(`profile_type.individual_insulation_work.${work}`)} + </div> + ))} </div> )} <div className="fields"> diff --git a/src/components/Options/ReportOptions/ReportOptions.spec.tsx b/src/components/Options/ReportOptions/ReportOptions.spec.tsx index a31d03958e75df27bf91de38da7acdb762f2f669..baaeff3f3d1591037497778c6148ee9c0119c277 100644 --- a/src/components/Options/ReportOptions/ReportOptions.spec.tsx +++ b/src/components/Options/ReportOptions/ReportOptions.spec.tsx @@ -1,15 +1,15 @@ -import React from 'react' +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 { mount } from 'enzyme' +import React from 'react' import { Provider } from 'react-redux' -import ReportOptions from 'components/Options/ReportOptions/ReportOptions' +import * as profileActions from 'store/profile/profile.actions' import { - createMockStore, + createMockEcolyoStore, mockInitialEcolyoState, } from '../../../../tests/__mocks__/store' -import * as profileActions from 'store/profile/profile.actions' -import { Button } from '@material-ui/core' -import StyledSwitch from 'components/CommonKit/Switch/StyledSwitch' -import { FluidState, FluidType } from 'enum/fluid.enum' jest.mock('cozy-ui/transpiled/react/I18n', () => { return { @@ -33,10 +33,9 @@ jest.mock('services/profile.service', () => { const updateProfileSpy = jest.spyOn(profileActions, 'updateProfile') describe('ReportOptions component', () => { - // eslint-disable-next-line @typescript-eslint/no-explicit-any - let store: any + const store = createMockEcolyoStore() beforeEach(() => { - store = createMockStore(mockInitialEcolyoState) + store.clearActions() updateProfileSpy.mockClear() }) @@ -63,7 +62,6 @@ describe('ReportOptions component', () => { }) it('should be rendered with sendAnalysisNotification false and toggle it to true', () => { mockInitialEcolyoState.profile.sendAnalysisNotification = false - store = createMockStore(mockInitialEcolyoState) const wrapper = mount( <Provider store={store}> @@ -81,7 +79,6 @@ describe('ReportOptions component', () => { mockInitialEcolyoState.profile.sendAnalysisNotification = false mockInitialEcolyoState.global.fluidStatus[FluidType.WATER].status = FluidState.DONE - store = createMockStore(mockInitialEcolyoState) const wrapper = mount( <Provider store={store}> <ReportOptions /> diff --git a/src/components/Options/ReportOptions/ReportOptions.tsx b/src/components/Options/ReportOptions/ReportOptions.tsx index 04a5d172ef22a84b3bdf3855b2fa9874cb736d49..b311b3aa81ba36268a772f545c1e682ad8eff322 100644 --- a/src/components/Options/ReportOptions/ReportOptions.tsx +++ b/src/components/Options/ReportOptions/ReportOptions.tsx @@ -1,24 +1,26 @@ -import React, { useCallback, useEffect, useState } from 'react' -import './reportOptions.scss' -import { useI18n } from 'cozy-ui/transpiled/react/I18n' -import { useSelector, useDispatch } from 'react-redux' -import { AppStore } from 'store' -import { useClient } from 'cozy-client' -import { updateProfile } from 'store/profile/profile.actions' import { Button } from '@material-ui/core' import StyledSwitch from 'components/CommonKit/Switch/StyledSwitch' -import ConsumptionDataManager from 'services/consumption.service' +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 { DateTime } from 'luxon' import { Dataload, TimePeriod } from 'models' -import { TimeStep } from 'enum/timeStep.enum' -import { FluidState, FluidType } from 'enum/fluid.enum' +import React, { Dispatch, useCallback, useEffect, useState } from 'react' +import { useDispatch, useSelector } from 'react-redux' +import ConsumptionDataManager from 'services/consumption.service' +import { AppActionsTypes, AppStore } from 'store' +import { updateProfile } from 'store/profile/profile.actions' +import './reportOptions.scss' const ReportOptions: React.FC = () => { const { t } = useI18n() const client = useClient() - const dispatch = useDispatch() - const profile = useSelector((state: AppStore) => state.ecolyo.profile) - const { fluidStatus } = useSelector((state: AppStore) => state.ecolyo.global) + const dispatch = useDispatch<Dispatch<AppActionsTypes>>() + const { + global: { fluidStatus }, + profile, + } = useSelector((state: AppStore) => state.ecolyo) const [maxDayData, setLastSemesterMaxDay] = useState<Dataload | null>(null) const updateProfileReport = async (value: boolean) => { diff --git a/src/components/Options/Unsubscribe/UnSubscribe.spec.tsx b/src/components/Options/Unsubscribe/UnSubscribe.spec.tsx index 444b03735cc6f716b5248cdb305d1e70356dc744..f1b1dc38279ff51b86f04b94e0bf360815ab831a 100644 --- a/src/components/Options/Unsubscribe/UnSubscribe.spec.tsx +++ b/src/components/Options/Unsubscribe/UnSubscribe.spec.tsx @@ -4,10 +4,7 @@ import toJson from 'enzyme-to-json' import React from 'react' import { Provider } from 'react-redux' import * as profileActions from 'store/profile/profile.actions' -import { - createMockStore, - mockInitialEcolyoState, -} from '../../../../tests/__mocks__/store' +import { createMockEcolyoStore } from '../../../../tests/__mocks__/store' import UnSubscribe from './UnSubscribe' jest.mock('cozy-ui/transpiled/react/I18n', () => { @@ -39,10 +36,9 @@ jest.mock('react-router-dom', () => ({ })) describe('UnSubscribe component', () => { - // eslint-disable-next-line @typescript-eslint/no-explicit-any - let store: any + const store = createMockEcolyoStore() beforeEach(() => { - store = createMockStore(mockInitialEcolyoState) + store.clearActions() updateProfileSpy.mockClear() }) diff --git a/src/components/Options/Unsubscribe/UnSubscribe.tsx b/src/components/Options/Unsubscribe/UnSubscribe.tsx index 19ab95cb71588e0725544d2a18e1db023455987f..8b13800328c9a8b700ea825730da73c886855e2b 100644 --- a/src/components/Options/Unsubscribe/UnSubscribe.tsx +++ b/src/components/Options/Unsubscribe/UnSubscribe.tsx @@ -5,9 +5,10 @@ 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, { useState } from 'react' +import React, { Dispatch, useState } from 'react' import { useDispatch } from 'react-redux' import { useNavigate } from 'react-router-dom' +import { AppActionsTypes } from 'store' import { updateProfile } from 'store/profile/profile.actions' import './unSubscribe.scss' @@ -17,7 +18,7 @@ const UnSubscribe: React.FC = () => { setHeaderHeight(height) } const { t } = useI18n() - const dispatch = useDispatch() + const dispatch = useDispatch<Dispatch<AppActionsTypes>>() const navigate = useNavigate() const unSubscribe = async () => { dispatch(updateProfile({ sendAnalysisNotification: false })) diff --git a/src/components/Version/Version.spec.tsx b/src/components/Options/Version/Version.spec.tsx similarity index 81% rename from src/components/Version/Version.spec.tsx rename to src/components/Options/Version/Version.spec.tsx index 4ee6c5a0ece7327a2389fb34e43671577464ba52..9165d73f9f35a54bc3904d362a722665e2480917 100644 --- a/src/components/Version/Version.spec.tsx +++ b/src/components/Options/Version/Version.spec.tsx @@ -1,6 +1,6 @@ -import React from 'react' +import Version from 'components/Options/Version/Version' import { shallow } from 'enzyme' -import Version from 'components/Version/Version' +import React from 'react' describe('Version component', () => { it('should be rendered correctly', () => { diff --git a/src/components/Version/Version.tsx b/src/components/Options/Version/Version.tsx similarity index 100% rename from src/components/Version/Version.tsx rename to src/components/Options/Version/Version.tsx index c79f7dc6f2652ce9c7d2b23ce5c48bcd7b8a602c..043b118826e19b7f95eafc562edddee5ef9dc803 100644 --- a/src/components/Version/Version.tsx +++ b/src/components/Options/Version/Version.tsx @@ -1,5 +1,5 @@ -import React from 'react' import { Client, useClient } from 'cozy-client' +import React from 'react' import './version.scss' const Version: React.FC = () => { diff --git a/src/components/Version/__snapshots__/Version.spec.tsx.snap b/src/components/Options/Version/__snapshots__/Version.spec.tsx.snap similarity index 100% rename from src/components/Version/__snapshots__/Version.spec.tsx.snap rename to src/components/Options/Version/__snapshots__/Version.spec.tsx.snap diff --git a/src/components/Version/version.scss b/src/components/Options/Version/version.scss similarity index 100% rename from src/components/Version/version.scss rename to src/components/Options/Version/version.scss diff --git a/src/components/Options/__snapshots__/OptionsView.spec.tsx.snap b/src/components/Options/__snapshots__/OptionsView.spec.tsx.snap index 1fcb358c2fd2fdfedf95ab7a6e2f06504c83460f..7690e522649c43dadd5304904535270c4c2e1086 100644 --- a/src/components/Options/__snapshots__/OptionsView.spec.tsx.snap +++ b/src/components/Options/__snapshots__/OptionsView.spec.tsx.snap @@ -13,11 +13,12 @@ exports[`OptionsView component should be rendered correctly 1`] = ` height={0} > <ProfileTypeOptions /> - <ExportOptions /> + <ExportData /> <ReportOptions /> <HelpLink /> <LegalNoticeLink /> <GCULink /> + <Accessibility /> <MatomoOptOut /> <div className="parameters-logos" diff --git a/src/components/PerformanceIndicator/FluidPerformanceIndicator.tsx b/src/components/PerformanceIndicator/FluidPerformanceIndicator.tsx index 9e94a506506817a0345722a7ecdd80f9d532a58c..9d27584ff4298a7bdacc6e230789253eed619658 100644 --- a/src/components/PerformanceIndicator/FluidPerformanceIndicator.tsx +++ b/src/components/PerformanceIndicator/FluidPerformanceIndicator.tsx @@ -1,13 +1,12 @@ -import { useI18n } from 'cozy-ui/transpiled/react/I18n' -import { DateTime } from 'luxon' -import React from 'react' -import './fluidPerformanceIndicator.scss' - import StyledIcon from 'components/CommonKit/Icon/StyledIcon' +import { useI18n } from 'cozy-ui/transpiled/react/I18n' import { FluidType } from 'enum/fluid.enum' +import { DateTime } from 'luxon' import { PerformanceIndicator } from 'models' +import React from 'react' import { getPicto } from 'utils/picto' import { formatNumberValues, getPreviousMonthName } from 'utils/utils' +import './fluidPerformanceIndicator.scss' interface FluidPerformanceIndicatorProps { performanceIndicator: PerformanceIndicator diff --git a/src/components/PerformanceIndicator/PerformanceIndicatorContent.tsx b/src/components/PerformanceIndicator/PerformanceIndicatorContent.tsx index d4bf98789eecedaaa5b215ba2f34fc9cac53b734..afe099db8f59ab06d7cd33c6408b475254949971 100644 --- a/src/components/PerformanceIndicator/PerformanceIndicatorContent.tsx +++ b/src/components/PerformanceIndicator/PerformanceIndicatorContent.tsx @@ -1,21 +1,18 @@ -import React from 'react' -import { useI18n } from 'cozy-ui/transpiled/react/I18n' - -import { TimeStep } from 'enum/timeStep.enum' -import { PerformanceIndicator } from 'models' -import { formatNumberValues } from 'utils/utils' - -import StyledIcon from 'components/CommonKit/Icon/StyledIcon' import PileIcon from 'assets/icons/ico/coins.svg' - +import ErrorIndicatorIcon from 'assets/icons/visu/indicator/error.svg' import GreenIndicatorIcon from 'assets/icons/visu/indicator/green.svg' -import RedIndicatorIcon from 'assets/icons/visu/indicator/red.svg' import GreyIndicatorIcon from 'assets/icons/visu/indicator/grey.svg' -import ErrorIndicatorIcon from 'assets/icons/visu/indicator/error.svg' +import RedIndicatorIcon from 'assets/icons/visu/indicator/red.svg' +import StyledIcon from 'components/CommonKit/Icon/StyledIcon' +import { useI18n } from 'cozy-ui/transpiled/react/I18n' import { FluidType } from 'enum/fluid.enum' -import './fluidPerformanceIndicator.scss' -import { convertDateToMonthString } from 'utils/date' +import { TimeStep } from 'enum/timeStep.enum' import { DateTime } from 'luxon' +import { PerformanceIndicator } from 'models' +import React from 'react' +import { convertDateToMonthString } from 'utils/date' +import { formatNumberValues } from 'utils/utils' +import './fluidPerformanceIndicator.scss' interface PerformanceIndicatorContentProps { performanceIndicator: PerformanceIndicator diff --git a/src/components/ProfileType/ProfileTypeFinished.spec.tsx b/src/components/ProfileType/ProfileTypeFinished.spec.tsx index f151263886e5c0b2ae6cb2c206faafd190932124..0b4dda62045cb71531415c19515d58f3d05a7d67 100644 --- a/src/components/ProfileType/ProfileTypeFinished.spec.tsx +++ b/src/components/ProfileType/ProfileTypeFinished.spec.tsx @@ -2,11 +2,9 @@ import { Button } from '@material-ui/core' 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 { - createMockStore, - mockInitialEcolyoState, -} from '../../../tests/__mocks__/store' +import { createMockEcolyoStore } from '../../../tests/__mocks__/store' import ProfileTypeFinished from './ProfileTypeFinished' const mockedNavigate = jest.fn() @@ -27,15 +25,25 @@ jest.mock('cozy-ui/transpiled/react/I18n', () => { }), } }) +const mockAddEvent = jest.fn() +jest.mock('services/usageEvent.service') +UsageEventService.addEvent = mockAddEvent + +const mockGetAllProfileTypes = jest.fn() +const mockDeleteProfileTypes = jest.fn() +jest.mock('services/profileTypeEntity.service', () => { + return jest.fn(() => { + return { + getAllProfileTypes: mockGetAllProfileTypes, + deleteProfileTypes: mockDeleteProfileTypes, + } + }) +}) describe('ProfileTypeFinished component', () => { - // eslint-disable-next-line @typescript-eslint/no-explicit-any - let store: any + const store = createMockEcolyoStore() beforeEach(() => { - jest.clearAllMocks() - store = createMockStore(mockInitialEcolyoState) - }) - afterEach(() => { + store.clearActions() jest.clearAllMocks() }) diff --git a/src/components/ProfileType/ProfileTypeFinished.tsx b/src/components/ProfileType/ProfileTypeFinished.tsx index 0615a27c44c6690a7b0da3ec729e8bcaeb9c49c7..57d208a83342ae7e2d90b7cffeec905f1a015022 100644 --- a/src/components/ProfileType/ProfileTypeFinished.tsx +++ b/src/components/ProfileType/ProfileTypeFinished.tsx @@ -11,31 +11,28 @@ import { UserExplorationID } from 'enum/userExploration.enum' import { DateTime } from 'luxon' import { TimePeriod } from 'models' import { ProfileType } from 'models/profileType.model' -import React, { useEffect, useState } from 'react' +import React, { Dispatch, useEffect, useState } from 'react' import { useDispatch, useSelector } from 'react-redux' 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 { AppStore } from 'store' +import { AppActionsTypes, AppStore } from 'store' import { updateProfile } from 'store/profile/profile.actions' import { newProfileTypeEntry } from 'store/profileType/profileType.actions' -interface ProfileTypeFinishedProps { - profileType: ProfileType -} - -const ProfileTypeFinished: React.FC<ProfileTypeFinishedProps> = ({ +const ProfileTypeFinished: React.FC<{ profileType: ProfileType }> = ({ profileType, -}: ProfileTypeFinishedProps) => { +}) => { const { t } = useI18n() const location = useLocation() - const dispatch = useDispatch() + const dispatch = useDispatch<Dispatch<AppActionsTypes>>() const navigate = useNavigate() const client = useClient() - const { currentChallenge } = useSelector( - (state: AppStore) => state.ecolyo.challenge - ) + const { + challenge: { currentChallenge }, + profile, + } = useSelector((state: AppStore) => state.ecolyo) const handleClick = () => { if (location?.pathname === '/ecogesture-form') { navigate('/ecogesture-selection') @@ -46,7 +43,6 @@ const ProfileTypeFinished: React.FC<ProfileTypeFinishedProps> = ({ const [isSaved, setIsSaved] = useState<boolean>(false) const [, setValidExploration] = useExploration() - const profile = useSelector((state: AppStore) => state.ecolyo.profile) useEffect(() => { async function checkForExistingProfileType() { diff --git a/src/components/ProfileType/ProfileTypeFormDateSelection.tsx b/src/components/ProfileType/ProfileTypeFormDateSelection.tsx index fcdebab17dacde7581fd5202857905db27993499..fecc5e5d6cbe18d3931285a4e7524da678092889 100644 --- a/src/components/ProfileType/ProfileTypeFormDateSelection.tsx +++ b/src/components/ProfileType/ProfileTypeFormDateSelection.tsx @@ -1,16 +1,16 @@ -import React, { useCallback, useEffect, useState } from 'react' +import { MenuItem, Select } from '@material-ui/core' +import FormNavigation from 'components/FormGlobal/FormNavigation' +import FormProgress from 'components/FormGlobal/FormProgress' import 'components/ProfileType/profileTypeForm.scss' import { useI18n } from 'cozy-ui/transpiled/react/I18n' -import FormProgress from 'components/FormGlobal/FormProgress' -import FormNavigation from 'components/FormGlobal/FormNavigation' import { ProfileTypeStepForm } from 'enum/profileType.enum' +import { DateTime } from 'luxon' import { ProfileType, ProfileTypeAnswer, ProfileTypeAnswerChoices, } from 'models/profileType.model' -import { DateTime } from 'luxon' -import { MenuItem, Select } from '@material-ui/core' +import React, { useCallback, useEffect, useState } from 'react' interface ProfileTypeFormDateSelectionProps { step: ProfileTypeStepForm @@ -18,7 +18,7 @@ interface ProfileTypeFormDateSelectionProps { profileType: ProfileType answerType: ProfileTypeAnswer setNextStep: Function - setPrevioustStep: Function + setPreviousStep: Function isProfileTypeComplete: boolean } @@ -35,7 +35,7 @@ const ProfileTypeFormDateSelection: React.FC< profileType, answerType, setNextStep, - setPrevioustStep, + setPreviousStep, isProfileTypeComplete, }: ProfileTypeFormDateSelectionProps) => { const { t } = useI18n() @@ -137,8 +137,8 @@ const ProfileTypeFormDateSelection: React.FC< } const handlePrevious = useCallback(() => { - setPrevioustStep(profileType) - }, [profileType, setPrevioustStep]) + setPreviousStep(profileType) + }, [profileType, setPreviousStep]) const handleNext = useCallback(() => { profileType[answerType.attribute] = answer @@ -194,8 +194,8 @@ const ProfileTypeFormDateSelection: React.FC< defaultValue={selectedYear} onChange={e => handleSelectYear(e)} > - {selectYears.map((year, key) => ( - <MenuItem value={year} key={key} className="date-option"> + {selectYears.map(year => ( + <MenuItem value={year} key={year} className="date-option"> {year} </MenuItem> ))} @@ -211,21 +211,19 @@ const ProfileTypeFormDateSelection: React.FC< > {/* if current year, only show past and present months else show full months */} {selectedYear === DateTime.now().year - ? selectMonths - .slice(0, DateTime.now().month) - .map((month, key) => ( - <MenuItem - value={month.value} - key={key} - className="date-option" - > - {month.label} - </MenuItem> - )) - : selectMonths.map((month, key) => ( + ? selectMonths.slice(0, DateTime.now().month).map(month => ( + <MenuItem + value={month.value} + key={month.value} + className="date-option" + > + {month.label} + </MenuItem> + )) + : selectMonths.map(month => ( <MenuItem value={month.value} - key={key} + key={month.value} className="date-option" > {month.label} diff --git a/src/components/ProfileType/ProfileTypeFormMultiChoice.spec.tsx b/src/components/ProfileType/ProfileTypeFormMultiChoice.spec.tsx index fee5fae4054652398245d4e02d550dd615c5207b..8b5019a070025c88702e74b651764ab955b94029 100644 --- a/src/components/ProfileType/ProfileTypeFormMultiChoice.spec.tsx +++ b/src/components/ProfileType/ProfileTypeFormMultiChoice.spec.tsx @@ -6,10 +6,7 @@ import { mockProfileType, mockProfileTypeAnswers, } from '../../../tests/__mocks__/profileType.mock' -import { - createMockStore, - mockInitialEcolyoState, -} from '../../../tests/__mocks__/store' +import { createMockEcolyoStore } from '../../../tests/__mocks__/store' import ProfileTypeFormMultiChoice from './ProfileTypeFormMultiChoice' jest.mock('cozy-ui/transpiled/react/I18n', () => { @@ -29,10 +26,9 @@ jest.mock('react-router-dom', () => ({ })) describe('ProfileTypeFormMultiChoice component', () => { - // eslint-disable-next-line @typescript-eslint/no-explicit-any - let store: any + const store = createMockEcolyoStore() beforeEach(() => { - store = createMockStore(mockInitialEcolyoState) + store.clearActions() }) it('should be rendered correctly', () => { @@ -46,7 +42,7 @@ describe('ProfileTypeFormMultiChoice component', () => { profileType={mockProfileType} answerType={mockProfileTypeAnswers[1]} setNextStep={mockhandlePrevious} - setPrevioustStep={mockhandleNext} + setPreviousStep={mockhandleNext} isProfileTypeComplete={false} /> </Provider> diff --git a/src/components/ProfileType/ProfileTypeFormMultiChoice.tsx b/src/components/ProfileType/ProfileTypeFormMultiChoice.tsx index 1df12766cb42d6b4a3b1b95dd6d8711e87df24ca..ecfac832dd8004cf46fa9366cd7661528c48f067 100644 --- a/src/components/ProfileType/ProfileTypeFormMultiChoice.tsx +++ b/src/components/ProfileType/ProfileTypeFormMultiChoice.tsx @@ -1,19 +1,19 @@ -import React, { useCallback, useEffect, useState } from 'react' -import 'components/ProfileType/profileTypeForm.scss' -import { useI18n } from 'cozy-ui/transpiled/react/I18n' import classNames from 'classnames' -import FormProgress from 'components/FormGlobal/FormProgress' import FormNavigation from 'components/FormGlobal/FormNavigation' -import { remove } from 'lodash' +import FormProgress from 'components/FormGlobal/FormProgress' +import 'components/ProfileType/profileTypeForm.scss' +import { useI18n } from 'cozy-ui/transpiled/react/I18n' import { IndividualInsulationWork, ProfileTypeStepForm, } from 'enum/profileType.enum' +import { remove } from 'lodash' import { ProfileType, ProfileTypeAnswer, ProfileTypeAnswerChoices, } from 'models/profileType.model' +import React, { useCallback, useEffect, useState } from 'react' interface ProfileTypeFormMultiChoiceProps { step: ProfileTypeStepForm @@ -21,7 +21,7 @@ interface ProfileTypeFormMultiChoiceProps { profileType: ProfileType answerType: ProfileTypeAnswer setNextStep: Function - setPrevioustStep: Function + setPreviousStep: Function isProfileTypeComplete: boolean } @@ -31,7 +31,7 @@ const ProfileTypeFormMultiChoice: React.FC<ProfileTypeFormMultiChoiceProps> = ({ profileType, answerType, setNextStep, - setPrevioustStep, + setPreviousStep, isProfileTypeComplete, }: ProfileTypeFormMultiChoiceProps) => { const { t } = useI18n() @@ -63,8 +63,8 @@ const ProfileTypeFormMultiChoice: React.FC<ProfileTypeFormMultiChoiceProps> = ({ } const handlePrevious = useCallback(() => { - setPrevioustStep(profileType) - }, [profileType, setPrevioustStep]) + setPreviousStep(profileType) + }, [profileType, setPreviousStep]) const handleNext = useCallback(() => { profileType[answerType.attribute] = answer as IndividualInsulationWork[] diff --git a/src/components/ProfileType/ProfileTypeFormNumber.spec.tsx b/src/components/ProfileType/ProfileTypeFormNumber.spec.tsx index 4dd96a015ffc470b5d7505eedca889a597408594..2631a9fa3567f9464eeabe6c15dec384bd6c7d15 100644 --- a/src/components/ProfileType/ProfileTypeFormNumber.spec.tsx +++ b/src/components/ProfileType/ProfileTypeFormNumber.spec.tsx @@ -6,10 +6,7 @@ import { mockProfileType, mockProfileTypeAnswers, } from '../../../tests/__mocks__/profileType.mock' -import { - createMockStore, - mockInitialEcolyoState, -} from '../../../tests/__mocks__/store' +import { createMockEcolyoStore } from '../../../tests/__mocks__/store' import ProfileTypeFormNumber from './ProfileTypeFormNumber' jest.mock('cozy-ui/transpiled/react/I18n', () => { @@ -28,10 +25,9 @@ jest.mock('react-router-dom', () => ({ })) describe('ProfileTypeFormNumber component', () => { - // eslint-disable-next-line @typescript-eslint/no-explicit-any - let store: any + const store = createMockEcolyoStore() beforeEach(() => { - store = createMockStore(mockInitialEcolyoState) + store.clearActions() }) it('should be rendered correctly', () => { @@ -45,7 +41,7 @@ describe('ProfileTypeFormNumber component', () => { profileType={mockProfileType} answerType={mockProfileTypeAnswers[1]} setNextStep={mockhandlePrevious} - setPrevioustStep={mockhandleNext} + setPreviousStep={mockhandleNext} isProfileTypeComplete={false} /> </Provider> diff --git a/src/components/ProfileType/ProfileTypeFormNumber.tsx b/src/components/ProfileType/ProfileTypeFormNumber.tsx index cdb31f505c0486f66038d2f306191fa189fb69ad..21ee84d9d2716e884a4805971546be7d3f2bdb9c 100644 --- a/src/components/ProfileType/ProfileTypeFormNumber.tsx +++ b/src/components/ProfileType/ProfileTypeFormNumber.tsx @@ -1,14 +1,14 @@ -import React, { useCallback, useEffect, useState } from 'react' +import FormNavigation from 'components/FormGlobal/FormNavigation' +import FormProgress from 'components/FormGlobal/FormProgress' import 'components/ProfileType/profileTypeForm.scss' import { useI18n } from 'cozy-ui/transpiled/react/I18n' -import FormProgress from 'components/FormGlobal/FormProgress' -import FormNavigation from 'components/FormGlobal/FormNavigation' import { ProfileTypeStepForm } from 'enum/profileType.enum' import { ProfileType, ProfileTypeAnswer, ProfileTypeAnswerChoices, } from 'models/profileType.model' +import React, { useCallback, useEffect, useState } from 'react' interface ProfileTypeFormNumberProps { step: ProfileTypeStepForm @@ -16,7 +16,7 @@ interface ProfileTypeFormNumberProps { profileType: ProfileType answerType: ProfileTypeAnswer setNextStep: Function - setPrevioustStep: Function + setPreviousStep: Function isProfileTypeComplete: boolean } @@ -26,15 +26,15 @@ const ProfileTypeFormNumber: React.FC<ProfileTypeFormNumberProps> = ({ profileType, answerType, setNextStep, - setPrevioustStep, + setPreviousStep, isProfileTypeComplete, }: ProfileTypeFormNumberProps) => { const { t } = useI18n() const [answer, setAnswer] = useState<ProfileTypeAnswerChoices>('') const handlePrevious = useCallback(() => { - setPrevioustStep(profileType) - }, [profileType, setPrevioustStep]) + setPreviousStep(profileType) + }, [profileType, setPreviousStep]) const handleNext = useCallback(() => { profileType[answerType.attribute] = answer diff --git a/src/components/ProfileType/ProfileTypeFormNumberSelection.spec.tsx b/src/components/ProfileType/ProfileTypeFormNumberSelection.spec.tsx index ec9c8ed8485569a643ec56ffcf0f1680d5e622d2..e6cf7e1c3a13c3cc2a5ee9df31a53de051ee2dc7 100644 --- a/src/components/ProfileType/ProfileTypeFormNumberSelection.spec.tsx +++ b/src/components/ProfileType/ProfileTypeFormNumberSelection.spec.tsx @@ -6,10 +6,7 @@ import { mockProfileType, mockProfileTypeAnswers, } from '../../../tests/__mocks__/profileType.mock' -import { - createMockStore, - mockInitialEcolyoState, -} from '../../../tests/__mocks__/store' +import { createMockEcolyoStore } from '../../../tests/__mocks__/store' import ProfileTypeFormNumberSelection from './ProfileTypeFormNumberSelection' jest.mock('cozy-ui/transpiled/react/I18n', () => { @@ -28,10 +25,9 @@ jest.mock('react-router-dom', () => ({ })) describe('ProfileTypeFormNumberSelection component', () => { - // eslint-disable-next-line @typescript-eslint/no-explicit-any - let store: any + const store = createMockEcolyoStore() beforeEach(() => { - store = createMockStore(mockInitialEcolyoState) + store.clearActions() }) it('should be rendered correctly', () => { @@ -45,7 +41,7 @@ describe('ProfileTypeFormNumberSelection component', () => { profileType={mockProfileType} answerType={mockProfileTypeAnswers[3]} setNextStep={mockhandlePrevious} - setPrevioustStep={mockhandleNext} + setPreviousStep={mockhandleNext} isProfileTypeComplete={false} /> </Provider> diff --git a/src/components/ProfileType/ProfileTypeFormNumberSelection.tsx b/src/components/ProfileType/ProfileTypeFormNumberSelection.tsx index 8996894ac4a871f2d4d3b3a7653edbe4f4dd07a2..2e3dff0c83fe16508bbca270b0910a702a6e95aa 100644 --- a/src/components/ProfileType/ProfileTypeFormNumberSelection.tsx +++ b/src/components/ProfileType/ProfileTypeFormNumberSelection.tsx @@ -1,14 +1,14 @@ -import React, { useCallback, useEffect, useState } from 'react' +import FormNavigation from 'components/FormGlobal/FormNavigation' +import FormProgress from 'components/FormGlobal/FormProgress' import 'components/ProfileType/profileTypeForm.scss' import { useI18n } from 'cozy-ui/transpiled/react/I18n' -import FormProgress from 'components/FormGlobal/FormProgress' -import FormNavigation from 'components/FormGlobal/FormNavigation' import { ProfileTypeStepForm } from 'enum/profileType.enum' import { ProfileType, ProfileTypeAnswer, ProfileTypeAnswerChoices, } from 'models/profileType.model' +import React, { useCallback, useEffect, useState } from 'react' interface ProfileTypeFormNumberSelectionProps { step: ProfileTypeStepForm @@ -16,7 +16,7 @@ interface ProfileTypeFormNumberSelectionProps { profileType: ProfileType answerType: ProfileTypeAnswer setNextStep: Function - setPrevioustStep: Function + setPreviousStep: Function isProfileTypeComplete: boolean } @@ -28,7 +28,7 @@ const ProfileTypeFormNumberSelection: React.FC< profileType, answerType, setNextStep, - setPrevioustStep, + setPreviousStep, isProfileTypeComplete, }: ProfileTypeFormNumberSelectionProps) => { const { t } = useI18n() @@ -46,8 +46,8 @@ const ProfileTypeFormNumberSelection: React.FC< } const handlePrevious = useCallback(() => { - setPrevioustStep(profileType) - }, [profileType, setPrevioustStep]) + setPreviousStep(profileType) + }, [profileType, setPreviousStep]) const handleNext = useCallback(() => { profileType[answerType.attribute] = answer diff --git a/src/components/ProfileType/ProfileTypeFormSingleChoice.spec.tsx b/src/components/ProfileType/ProfileTypeFormSingleChoice.spec.tsx index 97decd124a48b76dc4f16f5aeec1d663351079f5..f8743a938df9351e4ba42963d8062b2b04a373ae 100644 --- a/src/components/ProfileType/ProfileTypeFormSingleChoice.spec.tsx +++ b/src/components/ProfileType/ProfileTypeFormSingleChoice.spec.tsx @@ -6,10 +6,7 @@ import { mockProfileType, mockProfileTypeAnswers, } from '../../../tests/__mocks__/profileType.mock' -import { - createMockStore, - mockInitialEcolyoState, -} from '../../../tests/__mocks__/store' +import { createMockEcolyoStore } from '../../../tests/__mocks__/store' import ProfileTypeFormSingleChoice from './ProfileTypeFormSingleChoice' jest.mock('cozy-ui/transpiled/react/I18n', () => { @@ -28,10 +25,9 @@ jest.mock('react-router-dom', () => ({ })) describe('ProfileTypeFormSingleChoice component', () => { - // eslint-disable-next-line @typescript-eslint/no-explicit-any - let store: any + const store = createMockEcolyoStore() beforeEach(() => { - store = createMockStore(mockInitialEcolyoState) + store.clearActions() }) it('should be rendered correctly', () => { @@ -45,7 +41,7 @@ describe('ProfileTypeFormSingleChoice component', () => { profileType={mockProfileType} answerType={mockProfileTypeAnswers[1]} setNextStep={mockhandlePrevious} - setPrevioustStep={mockhandleNext} + setPreviousStep={mockhandleNext} isProfileTypeComplete={false} /> </Provider> diff --git a/src/components/ProfileType/ProfileTypeFormSingleChoice.tsx b/src/components/ProfileType/ProfileTypeFormSingleChoice.tsx index f1ddbe33c72c1367d83a46cc5ea65404655176fa..a436afe8191a23b5e7e05a8bcec4d9ba22fffa77 100644 --- a/src/components/ProfileType/ProfileTypeFormSingleChoice.tsx +++ b/src/components/ProfileType/ProfileTypeFormSingleChoice.tsx @@ -1,15 +1,15 @@ -import React, { useCallback, useEffect, useState } from 'react' -import 'components/ProfileType/profileTypeForm.scss' -import { useI18n } from 'cozy-ui/transpiled/react/I18n' import classNames from 'classnames' -import FormProgress from 'components/FormGlobal/FormProgress' import FormNavigation from 'components/FormGlobal/FormNavigation' +import FormProgress from 'components/FormGlobal/FormProgress' +import 'components/ProfileType/profileTypeForm.scss' +import { useI18n } from 'cozy-ui/transpiled/react/I18n' import { ProfileTypeStepForm } from 'enum/profileType.enum' import { ProfileType, ProfileTypeAnswer, ProfileTypeAnswerChoices, } from 'models/profileType.model' +import React, { useCallback, useEffect, useState } from 'react' interface ProfileTypeFormSingleChoiceProps { step: ProfileTypeStepForm @@ -17,7 +17,7 @@ interface ProfileTypeFormSingleChoiceProps { profileType: ProfileType answerType: ProfileTypeAnswer setNextStep: Function - setPrevioustStep: Function + setPreviousStep: Function isProfileTypeComplete: boolean } @@ -29,15 +29,15 @@ const ProfileTypeFormSingleChoice: React.FC< profileType, answerType, setNextStep, - setPrevioustStep, + setPreviousStep, isProfileTypeComplete, }: ProfileTypeFormSingleChoiceProps) => { const { t } = useI18n() const [answer, setAnswer] = useState<ProfileTypeAnswerChoices>('') const handlePrevious = useCallback(() => { - setPrevioustStep(profileType) - }, [profileType, setPrevioustStep]) + setPreviousStep(profileType) + }, [profileType, setPreviousStep]) const handleNext = useCallback(() => { profileType[answerType.attribute] = answer diff --git a/src/components/ProfileType/ProfileTypeView.spec.tsx b/src/components/ProfileType/ProfileTypeView.spec.tsx index 2018cfe89d14160993f64c8ba929b0cfaf42a835..466f3939ccff7a70a3b9523e7067a2fe0a6358a1 100644 --- a/src/components/ProfileType/ProfileTypeView.spec.tsx +++ b/src/components/ProfileType/ProfileTypeView.spec.tsx @@ -2,10 +2,7 @@ import ProfileTypeView from 'components/ProfileType/ProfileTypeView' import { mount } from 'enzyme' import React from 'react' import { Provider } from 'react-redux' -import { - createMockStore, - mockInitialEcolyoState, -} from '../../../tests/__mocks__/store' +import { createMockEcolyoStore } from '../../../tests/__mocks__/store' jest.mock('cozy-ui/transpiled/react/I18n', () => { return { @@ -27,10 +24,9 @@ jest.mock('components/Header/Header', () => 'mock-header') jest.mock('components/Content/Content', () => 'mock-content') describe('ProfileTypeView component', () => { - // eslint-disable-next-line @typescript-eslint/no-explicit-any - let store: any + const store = createMockEcolyoStore() beforeEach(() => { - store = createMockStore(mockInitialEcolyoState) + store.clearActions() }) it('should be rendered correctly', () => { diff --git a/src/components/ProfileType/ProfileTypeView.tsx b/src/components/ProfileType/ProfileTypeView.tsx index 88d58c2300888537e741dcf5dec2d40b8d5d4fee..0b255ca9c7baaa5287f894851ff3b32d5e2823d8 100644 --- a/src/components/ProfileType/ProfileTypeView.tsx +++ b/src/components/ProfileType/ProfileTypeView.tsx @@ -1,20 +1,19 @@ import Content from 'components/Content/Content' +import EcogestureFormEquipment from 'components/EcogestureForm/EcogestureFormEquipment' import CozyBar from 'components/Header/CozyBar' import Header from 'components/Header/Header' import ProfileTypeFinished from 'components/ProfileType/ProfileTypeFinished' -import ProfileTypeFormSingleChoice from 'components/ProfileType/ProfileTypeFormSingleChoice' -import 'components/ProfileType/profileTypeView.scss' -import React, { useCallback, useEffect, useState } from 'react' - -import EcogestureFormEquipment from 'components/EcogestureForm/EcogestureFormEquipment' 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, HotWaterEquipment, + HotWaterFluid, HousingType, IndividualInsulationWork, IndividualOrCollective, @@ -25,21 +24,19 @@ import { WarmingType, } from 'enum/profileType.enum' import { DateTime } from 'luxon' -import { ProfileEcogesture } from 'models/profileEcogesture.model' import { ProfileType, ProfileTypeAnswer } from 'models/profileType.model' +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' const ProfileTypeView: React.FC = () => { - const profile = useSelector((state: AppStore) => state.ecolyo.profile) - const curProfileType = useSelector( - (state: AppStore) => state.ecolyo.profileType - ) - const curProfileEcogesture: ProfileEcogesture = useSelector( - (state: AppStore) => state.ecolyo.profileEcogesture - ) + const { + profile, + profileType: curProfileType, + profileEcogesture: curProfileEcogesture, + } = useSelector((state: AppStore) => state.ecolyo) const [headerHeight, setHeaderHeight] = useState<number>(0) const [profileType, setProfileType] = useState<ProfileType>({ @@ -62,7 +59,7 @@ const ProfileTypeView: React.FC = () => { hotWater: IndividualOrCollective.INDIVIDUAL, hotWaterEquipment: HotWaterEquipment.OTHER, warmingFluid: WarmingType.ELECTRICITY, - hotWaterFluid: FluidType.ELECTRICITY, + hotWaterFluid: HotWaterFluid.ELECTRICITY, cookingFluid: FluidType.ELECTRICITY, equipments: [], }) @@ -139,7 +136,7 @@ const ProfileTypeView: React.FC = () => { answerType={answerType} setNextStep={setNextStep} isProfileTypeComplete={profile.isProfileTypeCompleted} - setPrevioustStep={setPreviousStep} + setPreviousStep={setPreviousStep} /> ) } else if (answerType.type === ProfileTypeFormType.MULTI_CHOICE) { @@ -150,7 +147,7 @@ const ProfileTypeView: React.FC = () => { profileType={profileType} answerType={answerType} setNextStep={setNextStep} - setPrevioustStep={setPreviousStep} + setPreviousStep={setPreviousStep} isProfileTypeComplete={profile.isProfileTypeCompleted} /> ) @@ -163,7 +160,7 @@ const ProfileTypeView: React.FC = () => { answerType={answerType} setNextStep={setNextStep} isProfileTypeComplete={profile.isProfileTypeCompleted} - setPrevioustStep={setPreviousStep} + setPreviousStep={setPreviousStep} /> ) } else if (answerType.type === ProfileTypeFormType.NUMBER_SELECTION) { @@ -175,7 +172,7 @@ const ProfileTypeView: React.FC = () => { answerType={answerType} setNextStep={setNextStep} isProfileTypeComplete={profile.isProfileTypeCompleted} - setPrevioustStep={setPreviousStep} + setPreviousStep={setPreviousStep} /> ) } else if (answerType.type === ProfileTypeFormType.DATE_SELECTION) { @@ -187,7 +184,7 @@ const ProfileTypeView: React.FC = () => { answerType={answerType} setNextStep={setNextStep} isProfileTypeComplete={profile.isProfileTypeCompleted} - setPrevioustStep={setPreviousStep} + setPreviousStep={setPreviousStep} /> ) } else if (answerType.type === ProfileTypeFormType.EQUIPMENT_SELECTION) { diff --git a/src/components/Quiz/QuizBegin.spec.tsx b/src/components/Quiz/QuizBegin.spec.tsx index 87db1ca281596c8f7d95d1c0f6f7c10337c6c8a5..1532074626de3152e5c952d4bea05cd5e9e159e8 100644 --- a/src/components/Quiz/QuizBegin.spec.tsx +++ b/src/components/Quiz/QuizBegin.spec.tsx @@ -1,13 +1,13 @@ -import React from 'react' +import Button from '@material-ui/core/Button' +import StyledIcon from 'components/CommonKit/Icon/StyledIcon' +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 QuizBegin from './QuizBegin' import { globalStateData } from '../../../tests/__mocks__/globalStateData.mock' import { userChallengeData } from '../../../tests/__mocks__/userChallengeData.mock' -import Button from '@material-ui/core/Button' -import StyledIcon from 'components/CommonKit/Icon/StyledIcon' -import { UserChallengeUpdateFlag } from 'enum/userChallenge.enum' +import QuizBegin from './QuizBegin' jest.mock('cozy-ui/transpiled/react/I18n', () => { return { diff --git a/src/components/Quiz/QuizBegin.tsx b/src/components/Quiz/QuizBegin.tsx index c543f5809667a2558d3044b8954173ee74fa3e29..8ab9c1f630d666b358d7e94de51ec8765b9f48a6 100644 --- a/src/components/Quiz/QuizBegin.tsx +++ b/src/components/Quiz/QuizBegin.tsx @@ -1,16 +1,17 @@ -import React from 'react' -import './quizBegin.scss' -import { Client, useClient } from 'cozy-client' -import { useI18n } from 'cozy-ui/transpiled/react/I18n' -import quizIcon from 'assets/icons/visu/quiz/questionMark.svg' 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 { useDispatch } from 'react-redux' +import { Client, useClient } from 'cozy-client' +import { useI18n } from 'cozy-ui/transpiled/react/I18n' import { UserChallengeUpdateFlag } from 'enum/userChallenge.enum' +import { UserChallenge } from 'models' +import React, { Dispatch } from 'react' +import { useDispatch } from 'react-redux' import ChallengeService from 'services/challenge.service' +import { AppActionsTypes } from 'store' import { updateUserChallengeList } from 'store/challenge/challenge.actions' -import { UserChallenge } from 'models' -import StarsContainer from 'components/Challenge/StarsContainer' +import './quizBegin.scss' interface QuizBeginProps { userChallenge: UserChallenge @@ -21,7 +22,7 @@ const QuizBegin: React.FC<QuizBeginProps> = ({ }: QuizBeginProps) => { const client: Client = useClient() const { t } = useI18n() - const dispatch = useDispatch() + const dispatch = useDispatch<Dispatch<AppActionsTypes>>() const launchQuiz = async () => { const challengeService: ChallengeService = new ChallengeService(client) const userChallengeUpdated: UserChallenge = diff --git a/src/components/Quiz/QuizCustomQuestionContent.tsx b/src/components/Quiz/QuizCustomQuestionContent.tsx index a5a38de7729980d4b2ac950bf59d1ba4d0c0cbf6..f5b80fd56b71d2be0448957d72038564242ba907 100644 --- a/src/components/Quiz/QuizCustomQuestionContent.tsx +++ b/src/components/Quiz/QuizCustomQuestionContent.tsx @@ -8,11 +8,12 @@ import { useI18n } from 'cozy-ui/transpiled/react/I18n' import { UsageEventType } from 'enum/usageEvent.enum' import { UserChallengeUpdateFlag } from 'enum/userChallenge.enum' import { Answer, QuestionEntity, UserChallenge, UserQuiz } from 'models' -import React, { useState } from 'react' +import React, { Dispatch, useState } from 'react' import { useDispatch } from 'react-redux' 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.actions' import './quizQuestion.scss' @@ -34,7 +35,7 @@ const QuizCustomQuestionContent: React.FC<QuizCustomQuestionContent> = ({ const [openModal, setOpenModal] = useState<boolean>(false) const [answerIndex, setAnswerIndex] = useState<number>(0) const client: Client = useClient() - const dispatch = useDispatch() + const dispatch = useDispatch<Dispatch<AppActionsTypes>>() const quizService: QuizService = new QuizService(client) const challengeService: ChallengeService = new ChallengeService(client) diff --git a/src/components/Quiz/QuizExplanationModal.tsx b/src/components/Quiz/QuizExplanationModal.tsx index 15ea7551493985e7fafc1612c667e6361810c296..f11e26b73177437144e975e510cf57f81a745652 100644 --- a/src/components/Quiz/QuizExplanationModal.tsx +++ b/src/components/Quiz/QuizExplanationModal.tsx @@ -1,14 +1,12 @@ -import React, { useState, useEffect } from 'react' -import './quizExplanationModal.scss' -import { useI18n } from 'cozy-ui/transpiled/react/I18n' -import { QuestionEntity } from 'models' - +import Button from '@material-ui/core/Button' +import Dialog from '@material-ui/core/Dialog' import correctAnswer from 'assets/icons/ico/correctAnswer.svg' import wrongAnswer from 'assets/icons/ico/wrongAnswer.svg' - +import { useI18n } from 'cozy-ui/transpiled/react/I18n' import Icon from 'cozy-ui/transpiled/react/Icon' -import Button from '@material-ui/core/Button' -import Dialog from '@material-ui/core/Dialog' +import { QuestionEntity } from 'models' +import React, { useEffect, useState } from 'react' +import './quizExplanationModal.scss' interface QuizExplanationModalProps { open: boolean diff --git a/src/components/Quiz/QuizFinish.tsx b/src/components/Quiz/QuizFinish.tsx index b6d49e253f2eef31bf43a8997c3d17dad7961b28..cc0274f473352cabd845a7853d5623a1fbe4f550 100644 --- a/src/components/Quiz/QuizFinish.tsx +++ b/src/components/Quiz/QuizFinish.tsx @@ -5,10 +5,11 @@ import { Client, useClient } from 'cozy-client' import { useI18n } from 'cozy-ui/transpiled/react/I18n' import { UserChallengeUpdateFlag } from 'enum/userChallenge.enum' import { UserChallenge } from 'models' -import React, { useCallback, useMemo } from 'react' +import React, { Dispatch, useCallback, useMemo } from 'react' import { useDispatch } from 'react-redux' import { useNavigate } from 'react-router-dom' import ChallengeService from 'services/challenge.service' +import { AppActionsTypes } from 'store' import { updateUserChallengeList } from 'store/challenge/challenge.actions' import './quizFinish.scss' @@ -22,7 +23,7 @@ const QuizFinish: React.FC<QuizFinishProps> = ({ const client: Client = useClient() const { t } = useI18n() const navigate = useNavigate() - const dispatch = useDispatch() + const dispatch = useDispatch<Dispatch<AppActionsTypes>>() const challengeService: ChallengeService = useMemo( () => new ChallengeService(client), [client] diff --git a/src/components/Quiz/QuizQuestion.spec.tsx b/src/components/Quiz/QuizQuestion.spec.tsx index a83ed32a42ca2516f2e6ede18ae322e574ace844..16a951db361c715065fcd94da472738a2d8af141 100644 --- a/src/components/Quiz/QuizQuestion.spec.tsx +++ b/src/components/Quiz/QuizQuestion.spec.tsx @@ -4,10 +4,7 @@ import { mount } from 'enzyme' import React from 'react' import * as reactRedux from 'react-redux' import { Provider } from 'react-redux' -import { - createMockStore, - mockInitialEcolyoState, -} from '../../../tests/__mocks__/store' +import { createMockEcolyoStore } from '../../../tests/__mocks__/store' import { userChallengeData } from '../../../tests/__mocks__/userChallengeData.mock' import QuizQuestion from './QuizQuestion' @@ -47,10 +44,9 @@ jest.mock('components/Quiz/QuizQuestionContent', () => () => ( const useSelectorSpy = jest.spyOn(reactRedux, 'useSelector') describe('QuizQuestion component', () => { - // eslint-disable-next-line @typescript-eslint/no-explicit-any - let store: any + const store = createMockEcolyoStore() beforeEach(() => { - store = createMockStore(mockInitialEcolyoState) + store.clearActions() useSelectorSpy.mockClear() }) diff --git a/src/components/Quiz/QuizQuestionContent.tsx b/src/components/Quiz/QuizQuestionContent.tsx index a8a79137db1fc037a1e9f478d896a0229a288889..4b12b75b792bbcba8310dd932b0ac577656f8ba2 100644 --- a/src/components/Quiz/QuizQuestionContent.tsx +++ b/src/components/Quiz/QuizQuestionContent.tsx @@ -1,17 +1,18 @@ -import React, { Dispatch, SetStateAction, useCallback, useState } from 'react' -import './quizQuestion.scss' +import Button from '@material-ui/core/Button' import CloseIcon from 'assets/icons/ico/close.svg' import StyledIconButton from 'components/CommonKit/IconButton/StyledIconButton' -import Button from '@material-ui/core/Button' import QuizExplanationModal from 'components/Quiz/QuizExplanationModal' +import { Client, useClient } from 'cozy-client' import { useI18n } from 'cozy-ui/transpiled/react/I18n' +import { UserChallengeUpdateFlag } from 'enum/userChallenge.enum' 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 { Client, useClient } from 'cozy-client' -import { UserChallengeUpdateFlag } from 'enum/userChallenge.enum' +import { AppActionsTypes } from 'store' import { updateUserChallengeList } from 'store/challenge/challenge.actions' -import { useDispatch } from 'react-redux' +import './quizQuestion.scss' interface QuizQuestionContent { userChallenge: UserChallenge @@ -35,7 +36,7 @@ const QuizQuestionContent: React.FC<QuizQuestionContent> = ({ useState<number>(questionIndexLocked) const client: Client = useClient() - const dispatch = useDispatch() + const dispatch = useDispatch<Dispatch<AppActionsTypes>>() const quizService: QuizService = new QuizService(client) const challengeService: ChallengeService = new ChallengeService(client) @@ -97,22 +98,20 @@ const QuizQuestionContent: React.FC<QuizQuestionContent> = ({ {userChallenge.quiz.questions[questionIndex].questionLabel} </p> {userChallenge.quiz.questions[questionIndex].answers.map( - (answer, index) => { - return ( - <div className="answer" key={index}> - <input - type="radio" - id={`answer${index}`} - value={answer.answerLabel} - onChange={handleChange} - checked={userChoice === answer.answerLabel} - /> - <label htmlFor={`answer${index}`} className="text-16-bold"> - {answer.answerLabel} - </label> - </div> - ) - } + (answer, index) => ( + <div className="answer" key={index}> + <input + type="radio" + id={`answer${index}`} + value={answer.answerLabel} + onChange={handleChange} + checked={userChoice === answer.answerLabel} + /> + <label htmlFor={`answer${index}`} className="text-16-bold"> + {answer.answerLabel} + </label> + </div> + ) )} </div> <Button diff --git a/src/components/Quiz/QuizView.spec.tsx b/src/components/Quiz/QuizView.spec.tsx index fec5d9281ee4e4946d4f495562293e9b79611645..241cd54a9987fee3309ba022d03363a0a8ce0938 100644 --- a/src/components/Quiz/QuizView.spec.tsx +++ b/src/components/Quiz/QuizView.spec.tsx @@ -1,13 +1,13 @@ -import React from 'react' -import { shallow } from 'enzyme' import QuizView from 'components/Quiz/QuizView' -import * as reactRedux from 'react-redux' import { UserQuizState } from 'enum/userQuiz.enum' +import { shallow } 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 QuizBegin from './QuizBegin' -import QuizQuestion from './QuizQuestion' import QuizFinish from './QuizFinish' +import QuizQuestion from './QuizQuestion' jest.mock('components/Header/CozyBar', () => 'mock-cozybar') jest.mock('components/Header/Header', () => 'mock-header') diff --git a/src/components/Routes/Routes.tsx b/src/components/Routes/Routes.tsx index fe430787e957e7098283a5c97bddf929df8f1f85..851d878b85b4ebbf5b244d1d4d4d805099538fa0 100644 --- a/src/components/Routes/Routes.tsx +++ b/src/components/Routes/Routes.tsx @@ -23,9 +23,9 @@ const SingleEcogesture = lazy( ) const OptionsView = lazy(() => import('components/Options/OptionsView')) const LegalNoticeView = lazy( - () => import('components/LegalNotice/LegalNoticeView') + () => import('components/Options/LegalNotice/LegalNoticeView') ) -const GCUView = lazy(() => import('components/GCU/GCUView')) +const GCUView = lazy(() => import('components/Options/GCU/GCUView')) const AnalysisView = lazy(() => import('components/Analysis/AnalysisView')) const ProfileTypeView = lazy( () => import('components/ProfileType/ProfileTypeView') @@ -44,61 +44,63 @@ const AppRoutes: React.FC<RouteProps> = ({ termsStatus }: RouteProps) => { } > <Routes> - {termsStatus.accepted && ( - <Route - path="/terms" - element={<Navigate replace to="/consumption" />} - /> - )} - <Route path="/terms" element={<TermsView />} /> {!termsStatus.accepted && ( <> + <Route path="/terms" element={<TermsView />} /> <Route path="*" element={<Navigate replace to="/terms" />} /> - <Route path="/" element={<Navigate replace to="/terms" />} /> </> )} - <Route - path="/consumption/electricity" - element={<ConsumptionView fluidType={FluidType.ELECTRICITY} />} - /> - <Route - path="/consumption/water" - element={<ConsumptionView fluidType={FluidType.WATER} />} - /> - <Route - path="/consumption/gas" - element={<ConsumptionView fluidType={FluidType.GAS} />} - /> - <Route - path="/consumption" - element={<ConsumptionView fluidType={FluidType.MULTIFLUID} />} - /> - <Route path="/sge-connect" element={<SgeConnectView />} /> - <Route path="/challenges/duel" element={<DuelView />} /> - <Route path="/challenges/quiz" element={<QuizView />} /> - <Route path="/challenges/exploration" element={<ExplorationView />} /> - <Route path="/challenges/action" element={<ActionView />} /> - <Route path="/challenges/" element={<ChallengeView />} /> - <Route path="/ecogesture-form" element={<EcogestureFormView />} /> - <Route path="/ecogesture-selection" element={<EcogestureSelection />} /> - <Route - path="/ecogesture/:ecogestureID/:tab" - element={<SingleEcogesture />} - /> - <Route - path="/ecogesture/:ecogestureID" - element={<SingleEcogesture />} - /> - <Route path="/ecogestures" element={<EcogestureView />} /> - <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="/" element={<Navigate replace to="/consumption" />} /> - <Route path="*" element={<Navigate replace to="/consumption" />} /> + {termsStatus.accepted && ( + <> + <Route + path="/consumption/electricity" + element={<ConsumptionView fluidType={FluidType.ELECTRICITY} />} + /> + <Route + path="/consumption/water" + element={<ConsumptionView fluidType={FluidType.WATER} />} + /> + <Route + path="/consumption/gas" + element={<ConsumptionView fluidType={FluidType.GAS} />} + /> + <Route + path="/consumption" + element={<ConsumptionView fluidType={FluidType.MULTIFLUID} />} + /> + <Route path="/sge-connect" element={<SgeConnectView />} /> + <Route path="/challenges/duel" element={<DuelView />} /> + <Route path="/challenges/quiz" element={<QuizView />} /> + <Route + path="/challenges/exploration" + element={<ExplorationView />} + /> + <Route path="/challenges/action" element={<ActionView />} /> + <Route path="/challenges/" element={<ChallengeView />} /> + <Route path="/ecogesture-form" element={<EcogestureFormView />} /> + <Route + path="/ecogesture-selection" + element={<EcogestureSelection />} + /> + <Route + path="/ecogesture/:ecogestureID/:tab" + element={<SingleEcogesture />} + /> + <Route + path="/ecogesture/:ecogestureID" + element={<SingleEcogesture />} + /> + <Route path="/ecogestures" element={<EcogestureView />} /> + <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="*" element={<Navigate replace to="/consumption" />} /> + </> + )} </Routes> </Suspense> ) diff --git a/src/components/Splash/SplashRoot.spec.tsx b/src/components/Splash/SplashRoot.spec.tsx index f6f54888929a9420023f7b050255492211417241..18e45c09edb558e89e47b2d3cc25d57070afb514 100644 --- a/src/components/Splash/SplashRoot.spec.tsx +++ b/src/components/Splash/SplashRoot.spec.tsx @@ -1,10 +1,9 @@ -import React from 'react' import { mount } from 'enzyme' -import SplashRoot from './SplashRoot' -import * as reactRedux from 'react-redux' import toJson from 'enzyme-to-json' - +import React from 'react' +import * as reactRedux from 'react-redux' import { userChallengeExplo1OnGoing } from '../../../tests/__mocks__/userChallengeData.mock' +import SplashRoot from './SplashRoot' jest.mock('cozy-ui/transpiled/react/I18n', () => { return { @@ -22,7 +21,7 @@ describe('SplashRoot component', () => { it('should be rendered correctly', () => { mockUseSelector.mockReturnValue(userChallengeExplo1OnGoing) mockUseDispatch.mockReturnValue(jest.fn()) - const component = mount(<SplashRoot>children</SplashRoot>).getElement() + const component = mount(<SplashRoot>children</SplashRoot>) expect(toJson(component)).toMatchSnapshot() }) }) diff --git a/src/components/Splash/SplashRoot.tsx b/src/components/Splash/SplashRoot.tsx index a7432b5eb92cc99a539a70a5d255f46fd1ee8b26..69e08c6382fcc8cd2e8c7543fd2dfcdbaa29da13 100644 --- a/src/components/Splash/SplashRoot.tsx +++ b/src/components/Splash/SplashRoot.tsx @@ -13,11 +13,14 @@ import { import { DateTime } from 'luxon' import { migrations } from 'migrations/migration.data' import { MigrationService } from 'migrations/migration.service' -import { Profile, TermsStatus, UserChallenge } from 'models' -import { CustomPopup } from 'models/customPopup.model' -import { InitSteps, InitStepsErrors } from 'models/initialisationSteps.model' -import { PartnersInfo } from 'models/partnersInfo.model' -import { ReleaseNotes } from 'models/releaseNotes.model' +import { + CustomPopup, + InitSteps, + InitStepsErrors, + PartnersInfo, + Profile, + UserChallenge, +} from 'models' import React, { Dispatch, ReactNode, @@ -28,23 +31,21 @@ import React, { import { useDispatch } from 'react-redux' import ActionService from 'services/action.service' import ChallengeService from 'services/challenge.service' -import CustomPupopService from 'services/customPopup.service' +import CustomPopupService from 'services/customPopup.service' import FluidService from 'services/fluid.service' import InitializationService from 'services/initialization.service' import PartnersInfoService from 'services/partnersInfo.service' import UsageEventService from 'services/usageEvent.service' +import { AppActionsTypes } from 'store' import { - ChallengeActionTypes, setChallengeConsumption, setUserChallengeList, updateUserChallengeList, } from 'store/challenge/challenge.actions' -import { ChartActionTypes, setSelectedDate } from 'store/chart/chart.actions' +import { setSelectedDate } from 'store/chart/chart.actions' import { - GlobalActionTypes, setCustomPopup, setFluidStatus, - setPartnersIssue, showReleaseNotes, toggleAnalysisNotification, toggleChallengeActionNotification, @@ -52,18 +53,10 @@ import { toggleChallengeExplorationNotification, updateTermValidation, } from 'store/global/global.actions' -import { - ProfileActionTypes, - updateProfile, -} from 'store/profile/profile.actions' -import { - ProfileEcogestureActionTypes, - updateProfileEcogestureSuccess, -} from 'store/profileEcogesture/profileEcogesture.actions' -import { - ProfileTypeActionTypes, - updateProfileType, -} from 'store/profileType/profileType.actions' +import { openPartnersModal } from 'store/modal/modal.actions' +import { updateProfile } from 'store/profile/profile.actions' +import { updateProfileEcogestureSuccess } from 'store/profileEcogesture/profileEcogesture.actions' +import { updateProfileType } from 'store/profileType/profileType.actions' import logApp from 'utils/logger' import { getTodayDate } from 'utils/utils' import './splashRoot.scss' @@ -91,14 +84,7 @@ const SplashRoot = ({ fadeTimer = 1000, children }: SplashRootProps) => { const [initStepErrors, setInitStepErrors] = useState<InitStepsErrors | null>( null ) - const dispatch: Dispatch< - | ChallengeActionTypes - | ChartActionTypes - | GlobalActionTypes - | ProfileActionTypes - | ProfileEcogestureActionTypes - | ProfileTypeActionTypes - > = useDispatch() + const dispatch: Dispatch<AppActionsTypes> = useDispatch() /** Return current status of partner if modal has not been seen today */ const getPartnerStatus = useCallback( @@ -168,7 +154,7 @@ const SplashRoot = ({ fadeTimer = 1000, children }: SplashRootProps) => { } if (Object.values(partnersIssue).some(issue => issue)) { - dispatch(setPartnersIssue(partnersIssue)) + dispatch(openPartnersModal(partnersIssue)) } } } catch (error) { @@ -198,12 +184,11 @@ const SplashRoot = ({ fadeTimer = 1000, children }: SplashRootProps) => { setInitStep, setInitStepErrors ) - const customPopupService = new CustomPupopService(client) + const customPopupService = new CustomPopupService(client) + const partnersInfoService = new PartnersInfoService(client) const ms = new MigrationService(client, setInitStepErrors) try { - const migrationsResult: ReleaseNotes = await ms.runMigrations( - migrations - ) + const migrationsResult = await ms.runMigrations(migrations) // Init last release notes when they exist dispatch( @@ -215,8 +200,7 @@ const SplashRoot = ({ fadeTimer = 1000, children }: SplashRootProps) => { ) // init Terms - const termsStatus: TermsStatus = - await initializationService.initConsent() + const termsStatus = await initializationService.initConsent() if (subscribed) dispatch(updateTermValidation(termsStatus)) // Init fluidPrices @@ -244,14 +228,17 @@ const SplashRoot = ({ fadeTimer = 1000, children }: SplashRootProps) => { initializationService.initChallengeEntity(profile.explorationHash), initializationService.initAnalysis(profile), ]) - profile.ecogestureHash = ecogestureHash - profile.duelHash = duelHash - profile.quizHash = quizHash - profile.challengeHash = challengeHash - profile.explorationHash = explorationHash - profile.monthlyAnalysisDate = analysisResult.monthlyAnalysisDate - profile.haveSeenLastAnalysis = analysisResult.haveSeenLastAnalysis - dispatch(updateProfile(profile)) + const updatedProfile = { + ...profile, + ecogestureHash, + duelHash, + quizHash, + challengeHash, + explorationHash, + monthlyAnalysisDate: analysisResult.monthlyAnalysisDate, + haveSeenLastAnalysis: analysisResult.haveSeenLastAnalysis, + } + dispatch(updateProfile(updatedProfile)) if (profileType) { dispatch(updateProfileType(profileType)) } @@ -264,7 +251,7 @@ const SplashRoot = ({ fadeTimer = 1000, children }: SplashRootProps) => { const fluidStatus = await initializationService.initFluidStatus() if (subscribed) { dispatch(setFluidStatus(fluidStatus)) - const refDate: DateTime = DateTime.fromISO('0001-01-01') + const refDate = DateTime.fromISO('0001-01-01') let lastDataDate: DateTime | null = DateTime.fromISO('0001-01-01') for (const fluid of fluidStatus) { if (fluid.lastDataDate && fluid.lastDataDate > lastDataDate) { @@ -290,7 +277,7 @@ const SplashRoot = ({ fadeTimer = 1000, children }: SplashRootProps) => { ) { dispatch(toggleChallengeExplorationNotification(true)) } - // Set action to notifcation if action is accomplished + // Set action to notification if action is accomplished if ( filteredCurrentOngoingChallenge[0]?.action.state === UserActionState.ONGOING @@ -347,17 +334,20 @@ const SplashRoot = ({ fadeTimer = 1000, children }: SplashRootProps) => { }) } - const customPopup = await customPopupService.getCustomPopup() - if (profile && customPopup) { - await processCustomPopup(profile, customPopup) - } - - const partnersInfoService = new PartnersInfoService(client) - const partnersInfo = await partnersInfoService.getPartnersInfo() - if (profile && partnersInfo) { - await processFluidsStatus(profile, partnersInfo) - await processPartnersStatus(profile, partnersInfo) - } + /** + * Load custom popup and partners info synchronously so these treatments don't block the loading + */ + customPopupService.getCustomPopup().then(async customPopup => { + if (profile && customPopup) { + await processCustomPopup(profile, customPopup) + } + }) + partnersInfoService.getPartnersInfo().then(async partnersInfo => { + if (profile && partnersInfo) { + await processFluidsStatus(profile, partnersInfo) + await processPartnersStatus(profile, partnersInfo) + } + }) if (subscribed) { logApp.info('[Initialization] Finished successfully !') diff --git a/src/components/Splash/SplashScreen.spec.tsx b/src/components/Splash/SplashScreen.spec.tsx index 3b30e82a360e521b437dbe31b56fea011ca1b871..f84d639835334a30a8e19bcf51e627f78a823b4d 100644 --- a/src/components/Splash/SplashScreen.spec.tsx +++ b/src/components/Splash/SplashScreen.spec.tsx @@ -1,8 +1,8 @@ -import React from 'react' import { mount } from 'enzyme' -import SplashScreen from './SplashScreen' import toJson from 'enzyme-to-json' import { InitSteps } from 'models/initialisationSteps.model' +import React from 'react' +import SplashScreen from './SplashScreen' jest.mock('cozy-ui/transpiled/react/I18n', () => { return { diff --git a/src/components/Splash/SplashScreenError.spec.tsx b/src/components/Splash/SplashScreenError.spec.tsx index 2d9af53b853e492e69ccd2bfdd3546e7e8e54965..2c5fceffbd11b61fbb1c5c1f3d6e486086bdabef 100644 --- a/src/components/Splash/SplashScreenError.spec.tsx +++ b/src/components/Splash/SplashScreenError.spec.tsx @@ -1,9 +1,9 @@ -import React from 'react' -import { mount } from 'enzyme' -import SplashScreenError from './SplashScreenError' import Button from '@material-ui/core/Button' -import { InitStepsErrors } from 'models/initialisationSteps.model' +import { mount } from 'enzyme' import toJson from 'enzyme-to-json' +import { InitStepsErrors } from 'models/initialisationSteps.model' +import React from 'react' +import SplashScreenError from './SplashScreenError' jest.mock('cozy-ui/transpiled/react/I18n', () => { return { diff --git a/src/components/Splash/__snapshots__/SplashRoot.spec.tsx.snap b/src/components/Splash/__snapshots__/SplashRoot.spec.tsx.snap index cc8029032259ae786424aab72473e829c45eec6c..0da1b0c6c7c37d42ee372c08ea2cbe6aef628683 100644 --- a/src/components/Splash/__snapshots__/SplashRoot.spec.tsx.snap +++ b/src/components/Splash/__snapshots__/SplashRoot.spec.tsx.snap @@ -1,3 +1,63 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[`SplashRoot component should be rendered correctly 1`] = `undefined`; +exports[`SplashRoot component should be rendered correctly 1`] = ` +<SplashRoot> + <div + className="splash-root" + style={ + Object { + "transitionDuration": "1s", + } + } + > + <SplashScreen + initStep={0} + > + <div + className="splash-content" + > + <div + className="splash-loader" + > + <img + alt="Chargement" + src="test-file-stub" + /> + <span> + Ecolyo + </span> + <div + className="splash-progress" + > + <div + className="splash-progress-bar-container" + > + <div + className="splash-progress-bar-content" + style={ + Object { + "width": "10%", + } + } + /> + </div> + </div> + </div> + <div + className="step-label text-18-normal" + > + splashscreen.step.0 + </div> + <div + className="splash-logos-container" + > + <img + alt="ensemble de logos" + src="test-file-stub" + /> + </div> + </div> + </SplashScreen> + </div> +</SplashRoot> +`; diff --git a/src/components/Terms/CGUModal.spec.tsx b/src/components/Terms/CGUModal.spec.tsx index bcac7e89ca2ba93529cda6ecc61ebb036a995051..154bfef851e2d3d55570037b7dce35841a508f56 100644 --- a/src/components/Terms/CGUModal.spec.tsx +++ b/src/components/Terms/CGUModal.spec.tsx @@ -1,7 +1,7 @@ -import React from 'react' import { mount } from 'enzyme' -import CGUModal from './CGUModal' import toJson from 'enzyme-to-json' +import React from 'react' +import CGUModal from './CGUModal' jest.mock('cozy-ui/transpiled/react/I18n', () => { return { diff --git a/src/components/Terms/CGUModal.tsx b/src/components/Terms/CGUModal.tsx index 4c8fdbd4e5f1d88fb7733f0c9ecace7fdff84c28..b3dfb6a58c68599f7601373cb89bb31cfbbe7c13 100644 --- a/src/components/Terms/CGUModal.tsx +++ b/src/components/Terms/CGUModal.tsx @@ -1,11 +1,11 @@ -import GCUContent from 'components/GCU/GCUContent' -import React from 'react' -import './termsView.scss' -import Dialog from '@material-ui/core/Dialog' import { Button, IconButton } from '@material-ui/core' -import Icon from 'cozy-ui/transpiled/react/Icon' -import { useI18n } from 'cozy-ui/transpiled/react/I18n' +import Dialog from '@material-ui/core/Dialog' import CloseIcon from 'assets/icons/ico/close.svg' +import GCUContent from 'components/Options/GCU/GCUContent' +import { useI18n } from 'cozy-ui/transpiled/react/I18n' +import Icon from 'cozy-ui/transpiled/react/Icon' +import React from 'react' +import './termsView.scss' interface CGUModalProps { open: boolean diff --git a/src/components/Terms/DataShareConsentContent.tsx b/src/components/Terms/DataShareConsentContent.tsx index 95946d4ff711768cadf1dccd770494e42cad2b86..cb2308c8e088a66dc065180c7fa6e8aadfbcf810 100644 --- a/src/components/Terms/DataShareConsentContent.tsx +++ b/src/components/Terms/DataShareConsentContent.tsx @@ -1,9 +1,9 @@ -import React from 'react' import { useI18n } from 'cozy-ui/transpiled/react/I18n' -import './termsView.scss' +import React from 'react' import { useSelector } from 'react-redux' import { AppStore } from 'store' import { decoreText } from 'utils/decoreText' +import './termsView.scss' const DataShareConsentContent: React.FC = () => { const { t } = useI18n() diff --git a/src/components/Terms/LegalNoticeModal.spec.tsx b/src/components/Terms/LegalNoticeModal.spec.tsx index 788b2b8f42561dc40a70632b37708b16563bb210..daf57584765892879423ec486a95e32b98213a8b 100644 --- a/src/components/Terms/LegalNoticeModal.spec.tsx +++ b/src/components/Terms/LegalNoticeModal.spec.tsx @@ -1,7 +1,7 @@ -import React from 'react' import { mount } from 'enzyme' -import LegalNoticeModal from './LegalNoticeModal' import toJson from 'enzyme-to-json' +import React from 'react' +import LegalNoticeModal from './LegalNoticeModal' jest.mock('cozy-ui/transpiled/react/I18n', () => { return { diff --git a/src/components/Terms/LegalNoticeModal.tsx b/src/components/Terms/LegalNoticeModal.tsx index db727e26414c3bc32b9640b17b46e500f9ff451f..9f97244e52c7df19de85299ccb0ca67208116711 100644 --- a/src/components/Terms/LegalNoticeModal.tsx +++ b/src/components/Terms/LegalNoticeModal.tsx @@ -1,11 +1,11 @@ -import React from 'react' -import LegalNoticeContent from 'components/LegalNotice/LegalNoticeContent' -import './termsView.scss' -import Dialog from '@material-ui/core/Dialog' import { Button, IconButton } from '@material-ui/core' -import Icon from 'cozy-ui/transpiled/react/Icon' -import { useI18n } from 'cozy-ui/transpiled/react/I18n' +import Dialog from '@material-ui/core/Dialog' import CloseIcon from 'assets/icons/ico/close.svg' +import LegalNoticeContent from 'components/Options/LegalNotice/LegalNoticeContent' +import { useI18n } from 'cozy-ui/transpiled/react/I18n' +import Icon from 'cozy-ui/transpiled/react/Icon' +import React from 'react' +import './termsView.scss' interface LegalNoticeModalProps { open: boolean diff --git a/src/components/Terms/MinorUpdateContent.spec.tsx b/src/components/Terms/MinorUpdateContent.spec.tsx index 3ce0d5e3868223f7c8a00f4ae713a34ab5a5e8a1..642be1f800c8459981c19180688b660fe7712d4f 100644 --- a/src/components/Terms/MinorUpdateContent.spec.tsx +++ b/src/components/Terms/MinorUpdateContent.spec.tsx @@ -1,6 +1,6 @@ -import React from 'react' import { mount } from 'enzyme' import toJson from 'enzyme-to-json' +import React from 'react' import MinorUpdateContent from './MinorUpdateContent' jest.mock('cozy-ui/transpiled/react/I18n', () => { @@ -15,9 +15,7 @@ jest.mock('cozy-ui/transpiled/react/I18n', () => { describe('Minor update content component', () => { it('should be rendered correctly', () => { - const component = mount( - <MinorUpdateContent toggleLegalNoticeModal={jest.fn()} /> - ) + const component = mount(<MinorUpdateContent />) expect(toJson(component)).toMatchSnapshot() }) }) diff --git a/src/components/Terms/MinorUpdateContent.tsx b/src/components/Terms/MinorUpdateContent.tsx index fcc7ca4c8c3aa325be876b1975aaa462ba9e1adf..1633b98d3c150676afdcd9626411b1e24557c4d4 100644 --- a/src/components/Terms/MinorUpdateContent.tsx +++ b/src/components/Terms/MinorUpdateContent.tsx @@ -1,14 +1,8 @@ -import React from 'react' import { useI18n } from 'cozy-ui/transpiled/react/I18n' +import React from 'react' import './termsView.scss' -interface MinorUpdateContentProps { - toggleLegalNoticeModal: () => void -} - -const MinorUpdateContent = ({ - toggleLegalNoticeModal, -}: MinorUpdateContentProps) => { +const MinorUpdateContent = () => { const { t } = useI18n() return ( <div className="dataShare-content-root"> diff --git a/src/components/Terms/TermsView.spec.tsx b/src/components/Terms/TermsView.spec.tsx index ffcd1aaeb333c1640b0f19fad4b2b8fbfae86497..377c3e49cfb52fea474d0d98cfe63946bbf8c340 100644 --- a/src/components/Terms/TermsView.spec.tsx +++ b/src/components/Terms/TermsView.spec.tsx @@ -4,9 +4,8 @@ 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 { profileData } from '../../../tests/__mocks__/profileData.mock' +import { default as configureStore } from 'redux-mock-store' +import { createMockEcolyoStore } from '../../../tests/__mocks__/store' import { mockUpToDateTerm } from '../../../tests/__mocks__/termsData.mock' import TermsView from './TermsView' @@ -21,10 +20,12 @@ jest.mock('cozy-ui/transpiled/react/I18n', () => { }) const mockCreateTerm = jest.fn() +const mockGetTermsVersionType = jest.fn() jest.mock('services/terms.service', () => { return jest.fn(() => { return { createTerm: mockCreateTerm, + getTermsVersionType: mockGetTermsVersionType, } }) }) @@ -47,13 +48,8 @@ jest.mock('services/profile.service', () => { }) describe('TermsView component', () => { + const store = createMockEcolyoStore() it('should valid checkboxes and valid consent', () => { - const store = mockStore({ - ecolyo: { - profile: profileData, - global: globalStateData, - }, - }) mockCreateTerm.mockResolvedValueOnce(mockUpToDateTerm) const wrapper = mount( <Provider store={store}> @@ -76,12 +72,6 @@ describe('TermsView component', () => { expect(mockUseDispatch).toHaveBeenCalledTimes(3) }) it('should be rendered correctly', () => { - const store = mockStore({ - ecolyo: { - profile: profileData, - global: globalStateData, - }, - }) const component = mount( <Provider store={store}> <TermsView /> @@ -89,13 +79,7 @@ describe('TermsView component', () => { ) expect(toJson(component)).toMatchSnapshot() }) - it('shouldbe unable to valid consent', async () => { - const store = mockStore({ - ecolyo: { - profile: profileData, - global: globalStateData, - }, - }) + it('should be unable to valid consent', async () => { mockCreateTerm.mockResolvedValueOnce(mockUpToDateTerm) const wrapper = mount( <Provider store={store}> diff --git a/src/components/Terms/TermsView.tsx b/src/components/Terms/TermsView.tsx index 00e482ef6e5cd16e3681a5f88f446b2d3e8281aa..51bf642c9d1c5f5b43c66c2331ed5aca5bb262cf 100644 --- a/src/components/Terms/TermsView.tsx +++ b/src/components/Terms/TermsView.tsx @@ -2,11 +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, { useCallback, useState } from 'react' +import React, { Dispatch, useCallback, useState } from 'react' import { useDispatch, useSelector } from 'react-redux' import { useNavigate } from 'react-router-dom' import TermsService from 'services/terms.service' -import { AppStore } from 'store' +import { AppActionsTypes, AppStore } from 'store' import { updateTermValidation } from 'store/global/global.actions' import { decoreText } from 'utils/decoreText' import CGUModal from './CGUModal' @@ -18,7 +18,7 @@ import './termsView.scss' const TermsView: React.FC = () => { const { t } = useI18n() const client = useClient() - const dispatch = useDispatch() + const dispatch = useDispatch<Dispatch<AppActionsTypes>>() const navigate = useNavigate() const [GCUValidation, setGCUValidation] = useState<boolean>(false) const [dataConsentValidation, setDataConsentValidation] = @@ -116,9 +116,7 @@ const TermsView: React.FC = () => { ) : ( <> <div className="terms-content"> - <MinorUpdateContent - toggleLegalNoticeModal={toggleLegalNoticeModal} - /> + <MinorUpdateContent /> </div> <div className="terms-footer"> <Button diff --git a/src/components/Terms/__snapshots__/CGUModal.spec.tsx.snap b/src/components/Terms/__snapshots__/CGUModal.spec.tsx.snap index 121ce5fb7f93af1ee052881204a280f803903324..f4c8c69d3d9466806c769c35f927478916bc178e 100644 --- a/src/components/Terms/__snapshots__/CGUModal.spec.tsx.snap +++ b/src/components/Terms/__snapshots__/CGUModal.spec.tsx.snap @@ -437,11 +437,6 @@ exports[`CGUModal component should be rendered correctly 1`] = ` <div class="gcu-content-wrapper" > - <h1 - class="gcu-content-title text-22-normal" - > - gcu.title - </h1> <p class="text-14-normal version" > @@ -1069,11 +1064,6 @@ exports[`CGUModal component should be rendered correctly 1`] = ` <div className="gcu-content-wrapper" > - <h1 - className="gcu-content-title text-22-normal" - > - gcu.title - </h1> <p className="text-14-normal version" > diff --git a/src/components/Terms/__snapshots__/LegalNoticeModal.spec.tsx.snap b/src/components/Terms/__snapshots__/LegalNoticeModal.spec.tsx.snap index dc4900b2bf7398f986951e870de27fcbb7c2de24..5f03163208a50ffa6f4672024a25a81e4b3c98f2 100644 --- a/src/components/Terms/__snapshots__/LegalNoticeModal.spec.tsx.snap +++ b/src/components/Terms/__snapshots__/LegalNoticeModal.spec.tsx.snap @@ -437,9 +437,6 @@ exports[`LegalNoticeModal component should be rendered correctly 1`] = ` <div class="legal-notice-content" > - <h2> - legal.title_legal - </h2> <p class="version" > @@ -1053,9 +1050,6 @@ exports[`LegalNoticeModal component should be rendered correctly 1`] = ` <div className="legal-notice-content" > - <h2> - legal.title_legal - </h2> <p className="version" > diff --git a/src/components/Terms/__snapshots__/MinorUpdateContent.spec.tsx.snap b/src/components/Terms/__snapshots__/MinorUpdateContent.spec.tsx.snap index 7374bea125c9f4378fa6ab1f2c8dd8ee2018a6e2..46848ba3de01a50d32be8dfeff0f603c9aef5865 100644 --- a/src/components/Terms/__snapshots__/MinorUpdateContent.spec.tsx.snap +++ b/src/components/Terms/__snapshots__/MinorUpdateContent.spec.tsx.snap @@ -1,9 +1,7 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP exports[`Minor update content component should be rendered correctly 1`] = ` -<MinorUpdateContent - toggleLegalNoticeModal={[MockFunction]} -> +<MinorUpdateContent> <div className="dataShare-content-root" > diff --git a/src/components/Terms/__snapshots__/TermsView.spec.tsx.snap b/src/components/Terms/__snapshots__/TermsView.spec.tsx.snap index ac40276bd529b25d499200a7e7e78a4f356aef28..5c505a9990fa805c946808d4fc2a52a395e6a6f4 100644 --- a/src/components/Terms/__snapshots__/TermsView.spec.tsx.snap +++ b/src/components/Terms/__snapshots__/TermsView.spec.tsx.snap @@ -30,8 +30,13 @@ exports[`TermsView component should be rendered correctly 1`] = ` <h1 className="dataShare-content-title text-22-normal" > - dataShare.title1 + dataShare.title1Update </h1> + <p + className="text-14-normal" + > + dataShare.title2Update + </p> <p className="text-14-normal" > diff --git a/src/components/TimeStepSelector/TimeStepSelector.spec.tsx b/src/components/TimeStepSelector/TimeStepSelector.spec.tsx index 472e416abd8ab2ee9a3d55bee9436ee07b7534cc..619d07743f63c4e7236320a5ada1a099bbedbb9b 100644 --- a/src/components/TimeStepSelector/TimeStepSelector.spec.tsx +++ b/src/components/TimeStepSelector/TimeStepSelector.spec.tsx @@ -1,18 +1,15 @@ -import React from 'react' -import { mount } from 'enzyme' -import { Provider } from 'react-redux' -import * as reactRedux from 'react-redux' +import { Button } from '@material-ui/core' import TimeStepSelector from 'components/TimeStepSelector/TimeStepSelector' -import { - createMockStore, - mockInitialEcolyoState, -} from '../../../tests/__mocks__/store' -import * as chartActions from 'store/chart/chart.actions' import { FluidType } from 'enum/fluid.enum' import { TimeStep } from 'enum/timeStep.enum' +import { mount } from 'enzyme' 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 { Button } from '@material-ui/core' +import * as chartActions from 'store/chart/chart.actions' +import { createMockEcolyoStore } from '../../../tests/__mocks__/store' jest.mock('cozy-ui/transpiled/react/I18n', () => { return { @@ -34,10 +31,9 @@ const setCurrentIndexSpy = jest.spyOn(chartActions, 'setCurrentIndex') const setSelectedDateSpy = jest.spyOn(chartActions, 'setSelectedDate') describe('TimeStepSelector component', () => { - // eslint-disable-next-line @typescript-eslint/no-explicit-any - let store: any + const store = createMockEcolyoStore() beforeEach(() => { - store = createMockStore(mockInitialEcolyoState) + store.clearActions() useSelectorSpy.mockClear() useDispatchSpy.mockClear() setCurrentTimeStepSpy.mockClear() diff --git a/src/components/TimeStepSelector/TimeStepSelector.tsx b/src/components/TimeStepSelector/TimeStepSelector.tsx index 62017f27e2c46c75bee2abcc64d42cf38768169d..cf6c3fc9c1e6f74fbf8d4b35faedee2668e57832 100644 --- a/src/components/TimeStepSelector/TimeStepSelector.tsx +++ b/src/components/TimeStepSelector/TimeStepSelector.tsx @@ -1,22 +1,21 @@ -import React from 'react' -import './timeStepSelector.scss' +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 { DateTime } from 'luxon' +import React, { Dispatch } from 'react' import { useDispatch, useSelector } from 'react-redux' -import { AppStore } from 'store' +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.actions' -import { Button } from '@material-ui/core' - -import DateChartService from 'services/dateChart.service' -import { FluidType } from 'enum/fluid.enum' -import { TimeStep } from 'enum/timeStep.enum' -import { useClient } from 'cozy-client' -import { UsageEventType } from 'enum/usageEvent.enum' -import UsageEventService from 'services/usageEvent.service' -import { DateTime } from 'luxon' +import './timeStepSelector.scss' interface TimeStepSelectorProps { fluidType: FluidType @@ -29,7 +28,7 @@ const TimeStepSelector: React.FC<TimeStepSelectorProps> = ({ (state: AppStore) => state.ecolyo.chart ) const { t } = useI18n() - const dispatch = useDispatch() + const dispatch = useDispatch<Dispatch<AppActionsTypes>>() const dateChartService = new DateChartService() const client = useClient() const timeStepElecArray: TimeStep[] = [ @@ -95,25 +94,23 @@ const TimeStepSelector: React.FC<TimeStepSelectorProps> = ({ fluidType === FluidType.ELECTRICITY && 'elec-bar' }`} > - {timeStepArray.map((step, key) => { - return ( - <React.Fragment key={key}> - <li - className={ - step === currentTimeStep ? 'active circle' : 'circle' - } - onClick={() => handleChangeTimeStep(step)} - id={TimeStep[step].toLowerCase()} - > - <span className="clickable-area" /> - <span className={'text text-14-normal'}> - {t(`timestep.${TimeStep[step].toLowerCase()}.period`)} - </span> - </li> - <li className="bar" /> - </React.Fragment> - ) - })} + {timeStepArray.map(step => ( + <React.Fragment key={step}> + <li + className={ + step === currentTimeStep ? 'active circle' : 'circle' + } + onClick={() => handleChangeTimeStep(step)} + id={TimeStep[step].toLowerCase()} + > + <span className="clickable-area" /> + <span className={'text text-14-normal'}> + {t(`timestep.${TimeStep[step].toLowerCase()}.period`)} + </span> + </li> + <li className="bar" /> + </React.Fragment> + ))} </ul> </div> </div> diff --git a/src/components/TotalConsumption/TotalConsumption.spec.tsx b/src/components/TotalConsumption/TotalConsumption.spec.tsx index b8f32bd0a043b1cd9575b62e121e5eee5da51fbb..7f2101b4851464b40c0163fab6b55387051bcaa9 100644 --- a/src/components/TotalConsumption/TotalConsumption.spec.tsx +++ b/src/components/TotalConsumption/TotalConsumption.spec.tsx @@ -1,14 +1,14 @@ -import React from 'react' -import { mount } from 'enzyme' import { FluidType } from 'enum/fluid.enum' -import TotalConsumption from './TotalConsumption' -import { mockInitialChartState } from '../../../tests/__mocks__/store' -import { graphData } from '../../../tests/__mocks__/datachartData.mock' -import { Provider } from 'react-redux' -import configureStore from 'redux-mock-store' import { TimeStep } from 'enum/timeStep.enum' +import { mount } from 'enzyme' import { Dataload } from 'models' +import React from 'react' import { act } from 'react-dom/test-utils' +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 TotalConsumption from './TotalConsumption' jest.mock('cozy-ui/transpiled/react/I18n', () => { return { diff --git a/src/components/TotalConsumption/TotalConsumption.tsx b/src/components/TotalConsumption/TotalConsumption.tsx index 5f9855ca023ae44e37f1197e4ce746eaacbbb1c0..7d033074176a49e9aa8001a1a15153be6feac296 100644 --- a/src/components/TotalConsumption/TotalConsumption.tsx +++ b/src/components/TotalConsumption/TotalConsumption.tsx @@ -1,16 +1,16 @@ -import React, { useEffect, useState } from 'react' -import StyledIcon from 'components/CommonKit/Icon/StyledIcon' import PileIcon from 'assets/icons/ico/coins.svg' -import './totalConsumption.scss' -import { Dataload } from 'models' -import { FluidType } from 'enum/fluid.enum' -import ConverterService from 'services/converter.service' -import { formatNumberValues } from 'utils/utils' -import ConsumptionService from 'services/consumption.service' +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 { Dataload } from 'models' +import React, { 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 { formatNumberValues } from 'utils/utils' +import './totalConsumption.scss' interface TotalConsumptionProps { actualData: Dataload[] diff --git a/src/components/Onboarding/WelcomeModal.spec.tsx b/src/components/WelcomeModal/WelcomeModal.spec.tsx similarity index 95% rename from src/components/Onboarding/WelcomeModal.spec.tsx rename to src/components/WelcomeModal/WelcomeModal.spec.tsx index 32a1543149d0d63b6b375cae68d5d2e210d3675e..c6ed7950f96f56e6a5ac137545cc20a7a1001dae 100644 --- a/src/components/Onboarding/WelcomeModal.spec.tsx +++ b/src/components/WelcomeModal/WelcomeModal.spec.tsx @@ -4,6 +4,7 @@ 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' @@ -60,8 +61,9 @@ jest.mock('mjml-browser', () => { } }) }) +jest.mock('services/profile.service') -const mockStore = configureStore([]) +const mockStore = configureStore([thunk.withExtraArgument({ mockClient })]) const updateProfileSpy = jest.spyOn(profileActions, 'updateProfile') describe('WelcomeModal component', () => { diff --git a/src/components/Onboarding/WelcomeModal.tsx b/src/components/WelcomeModal/WelcomeModal.tsx similarity index 96% rename from src/components/Onboarding/WelcomeModal.tsx rename to src/components/WelcomeModal/WelcomeModal.tsx index b17c2fe7b323525631675c10c3603b23f3fda554..3636741e92360d3c206b92a65c280f9ed6984e9e 100644 --- a/src/components/Onboarding/WelcomeModal.tsx +++ b/src/components/WelcomeModal/WelcomeModal.tsx @@ -5,10 +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, { useCallback } from 'react' +import React, { Dispatch, useCallback } from 'react' import { useDispatch } from 'react-redux' import EnvironmentService from 'services/environment.service' import MailService from 'services/mail.service' +import { AppActionsTypes } from 'store' import { updateProfile } from 'store/profile/profile.actions' import './welcomeModal.scss' @@ -22,7 +23,7 @@ interface WelcomeModalProps { const WelcomeModal = ({ open }: WelcomeModalProps) => { const { t } = useI18n() const client = useClient() - const dispatch = useDispatch() + const dispatch = useDispatch<Dispatch<AppActionsTypes>>() const { data: instanceSettings } = useUserInstanceSettings() const setWelcomeModalViewed = useCallback(async () => { diff --git a/src/components/Onboarding/__snapshots__/WelcomeModal.spec.tsx.snap b/src/components/WelcomeModal/__snapshots__/WelcomeModal.spec.tsx.snap similarity index 100% rename from src/components/Onboarding/__snapshots__/WelcomeModal.spec.tsx.snap rename to src/components/WelcomeModal/__snapshots__/WelcomeModal.spec.tsx.snap diff --git a/src/components/Onboarding/welcomeModal.scss b/src/components/WelcomeModal/welcomeModal.scss similarity index 100% rename from src/components/Onboarding/welcomeModal.scss rename to src/components/WelcomeModal/welcomeModal.scss diff --git a/src/constants/connectionWaitingText.json b/src/constants/connectionWaitingText.json index da97fb792c7886e83012461775ef7ecb235dc7b1..61481a407dd6fba04d255358b5c7fcafcf17a476 100644 --- a/src/constants/connectionWaitingText.json +++ b/src/constants/connectionWaitingText.json @@ -1,7 +1,7 @@ [ { "first": "Le saviez-vous ?", - "second": "Pour acheminer l’eau sur Lyon (Lugdunum !) l’acqueduc de Gier faisait 86 km à l’époque Romaine !" + "second": "Pour acheminer l’eau sur Lyon (Lugdunum !) l’aqueduc de Gier faisait 86 km à l’époque Romaine !" }, { "first": "Rien que de l’eau, de l’eau de pluie, de l’eau de la Métroooooo", diff --git a/src/constants/consumptionConstants/ecs.json b/src/constants/consumptionConstants/ecs.json index b0c773391aff27f51d88031003a34f3fc65a593f..3cc4afec50b7db8ab9d3013c6a0303a119f9bfcd 100644 --- a/src/constants/consumptionConstants/ecs.json +++ b/src/constants/consumptionConstants/ecs.json @@ -38,37 +38,15 @@ } ], "mensual_repartition": [ - 111, - 120, - 111, - 106, - 103, - 93, - 84, - 72, - 92, - 103, - 104, - 101 + 111, 120, 111, 106, 103, 93, 84, 72, 92, 103, 104, 101 ], "cold_water_temperature": [11, 11, 12, 15, 17, 19, 21, 20, 17, 15, 12, 13], "hot_water_temperature": 40, "solar_coverage": [ - 0.19, - 0.33, - 0.36, - 0.6, - 0.61, - 0.73, - 0.92, - 0.81, - 0.67, - 0.46, - 0.24, - 0.25 + 0.19, 0.33, 0.36, 0.6, 0.61, 0.73, 0.92, 0.81, 0.67, 0.46, 0.24, 0.25 ], "efficiency_production_distribution": { - "appartment": 0.55, + "apartment": 0.55, "individual_house": 0.7 }, "coefficient_ecs_consumption": 1.163, diff --git a/src/constants/consumptionConstants/electricSpecific.json b/src/constants/consumptionConstants/electricSpecific.json index dafba211eed8568ce1d68db3b5b0450c9311a378..33217083a86223823cb10b03202518bbffa470b0 100644 --- a/src/constants/consumptionConstants/electricSpecific.json +++ b/src/constants/consumptionConstants/electricSpecific.json @@ -7,7 +7,7 @@ "after_1998": 2900, "unknown": 2900 }, - "appartment": { + "apartment": { "before_1948": 1120, "between_1948_and_1974": 1880, "between_1975_and_1989": 1780, diff --git a/src/constants/consumptionConstants/heating.json b/src/constants/consumptionConstants/heating.json index 4cde7717836d6d7660c229fdf7e303d35d30f043..e3fd84db483a4cd97a9aa4b91f082b1a703f32eb 100644 --- a/src/constants/consumptionConstants/heating.json +++ b/src/constants/consumptionConstants/heating.json @@ -8,7 +8,7 @@ "after_1998": 106, "unknown": 106 }, - "appartment": { + "apartment": { "before_1948": 119, "between_1948_and_1974": 150, "between_1975_and_1989": 105, @@ -17,14 +17,14 @@ "unknown": 74 } }, - "adjustment_outisde_facing_walls": { + "adjustment_outside_facing_walls": { "individual_house": { "1": -0.2, "2": -0.15, "3": -0.1, "4": 0 }, - "appartment": { + "apartment": { "1": -0.1, "2": 0, "3": 0.1, @@ -32,7 +32,7 @@ } }, "adjustment_floor": { - "appartment": { + "apartment": { "ground_floor": 0.1, "intermediate_floor": 0, "last_floor": 0.15, diff --git a/src/db/ecogestureData.json b/src/db/ecogestureData.json index 6b12e829f327334b360d5000b230040f7d081b2f..ac1ae9fcacc3ba0e5320388aac245e35228671d9 100644 --- a/src/db/ecogestureData.json +++ b/src/db/ecogestureData.json @@ -28,7 +28,7 @@ "fluidTypes": [0], "shortName": "Portique thermique", "longName": "Je ferme mes fenêtres quand la climatisation est en marche", - "longDescription": "Cela permet de garder la fraicheur à l'intérieur. Le climatiseur n'est pas là pour refroidir la rue mais bien la pièce.", + "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.", "impactLevel": 8, "efficiency": 4, "difficulty": 1, @@ -279,7 +279,7 @@ "_id": "ECOGESTURE0013", "usage": 5, "fluidTypes": [0], - "shortName": "Accelerateur de particules", + "shortName": "Accélérateur de particules", "longName": "J’utilise le plus souvent les cycles courts à basse température pour laver le linge et la vaisselle.", "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.", "impactLevel": 2, @@ -465,7 +465,7 @@ "fluidTypes": [0], "shortName": "Boules de linge", "longName": "Si j’ai un sèche linge, je sèche mon linge en petits paquets et j’adapte la durée de séchage de mon sèche-linge.", - "longDescription": "Le sèche-linge représente 5% des consommations moyenne d'électrcité spécifique (d'après EDF). Il est important au préalable d’essorer à une vitesse supérieure, jusqu’à 1 000 tours/minutes, si la nature du linge le permet. Le séchage sera alors plus rapide et vous consommerez moins d’énergie pour le sécher", + "longDescription": "Le sèche-linge représente 5% des consommations moyenne d’électricité spécifique (d'après EDF). Il est important au préalable d’essorer à une vitesse supérieure, jusqu’à 1 000 tours/minutes, si la nature du linge le permet. Le séchage sera alors plus rapide et vous consommerez moins d’énergie pour le sécher", "impactLevel": 1, "efficiency": 0.5, "difficulty": 1, @@ -488,7 +488,7 @@ "fluidTypes": [0], "shortName": "Vortex", "longName": "Je nettoie le filtre de ma machine à laver.", - "longDescription": "Repérez la trappe qui existe sur le devant de votre machine (en bas à droite souvent). Ouvrez-la. Dévissez le filtre pour le sortir : attention, un peu d’eau risque de couler (Prenez un bol et une serpillère au cas où).Enlèvez les résidus qui seraient restés dans la trappe : cheveux, pièces etc. Rincez le filtre à l’eau claire. Remettez le filtre en place et hop on referme la trappe ! En étant bien entretenu, votre lave-ligne consomme moins d'énergie, lave mieux votre linge et durera plus longtemps.", + "longDescription": "Repérez la trappe qui existe sur le devant de votre machine (en bas à droite souvent). Ouvrez-la. Dévissez le filtre pour le sortir : attention, un peu d’eau risque de couler (Prenez un bol et une serpillière au cas où).Enlevez les résidus qui seraient restés dans la trappe : cheveux, pièces etc. Rincez le filtre à l’eau claire. Remettez le filtre en place et hop on referme la trappe ! En étant bien entretenu, votre lave-ligne consomme moins d'énergie, lave mieux votre linge et durera plus longtemps.", "impactLevel": 1, "efficiency": 0.5, "difficulty": 1, @@ -601,7 +601,7 @@ "_id": "ECOGESTURE0027", "usage": 5, "fluidTypes": [0], - "shortName": "Marionnetiste", + "shortName": "Marionnettiste", "longName": "Je débranche mes chargeurs quand ils ne sont pas en fonctionnement.", "longDescription": "Certains chargeurs continuent de consommer de l’énergie quand ils restent branchés, même si l’appareil n’est pas connecté. De plus, certaines technologies de batteries supportent mal de rester branchées une fois la charge terminée. Les débrancher dès que l’appareil est chargé permet des économies d’énergie et prolonge la durée de vie de votre appareil.", "impactLevel": 1, @@ -672,7 +672,7 @@ "fluidTypes": [0], "shortName": "Roi du Puzzle", "longName": "J’optimise le rangement dans mon réfrigérateur et/ou congélateur.", - "longDescription": "La partie la plus froide ne se situe pas toujours au même endroit selon l’appareil : dans le haut des réfrigérateurs traditionnels, dans le bas des combinés 2 portes. Dans les réfrigérateurs à froid ventilé, les températures sont plus homogènes. Regardez la notice de votre réfrigérateur pour identifier les différentes zones de température et ainsi ranger chaque aliment à sa place. Enlevez les produits de leur emballage d'origine (film plastique, carton, etc.) qui filtrent le froid. Rangez les denrées de façon rationnelle pour y accéder plus rapidement et aussi pour pouvoir refermer plus rapidement la porte. Surtout, n’obstruez pas le thermostat car s’il est recouvert de givre ou de produits, il ne détectera pas la température correctement et l’abaissera plus que nécessaire. Evitez de mettre trop de poids dans les portes. Une porte qui fonctionne mal provoque des pertes d'énergie. Conseils pour ranger votre réfrigérateur : placez les oeufs sur l'étage le plus haut ; les laitages et le beurre sur l'étage du dessous ; puis les plats cuisinés, les pâtisseries fraîches et charcuteries sur l'étage du milieu ; sur les parties basses, placez les poissons ; et réservez le bac à légumes pour les légumes et les fruits.", + "longDescription": "La partie la plus froide ne se situe pas toujours au même endroit selon l’appareil : dans le haut des réfrigérateurs traditionnels, dans le bas des combinés 2 portes. Dans les réfrigérateurs à froid ventilé, les températures sont plus homogènes. Regardez la notice de votre réfrigérateur pour identifier les différentes zones de température et ainsi ranger chaque aliment à sa place. Enlevez les produits de leur emballage d'origine (film plastique, carton, etc.) qui filtrent le froid. Rangez les denrées de façon rationnelle pour y accéder plus rapidement et aussi pour pouvoir refermer plus rapidement la porte. Surtout, n’obstruez pas le thermostat car s’il est recouvert de givre ou de produits, il ne détectera pas la température correctement et l’abaissera plus que nécessaire. Évitez de mettre trop de poids dans les portes. Une porte qui fonctionne mal provoque des pertes d'énergie. Conseils pour ranger votre réfrigérateur : placez les oeufs sur l'étage le plus haut ; les laitages et le beurre sur l'étage du dessous ; puis les plats cuisinés, les pâtisseries fraîches et charcuteries sur l'étage du milieu ; sur les parties basses, placez les poissons ; et réservez le bac à légumes pour les légumes et les fruits.", "impactLevel": 1, "efficiency": 0.5, "difficulty": 1, @@ -764,7 +764,7 @@ "fluidTypes": [0], "shortName": "Bulles-à -part", "longName": "Je ne fais pas fonctionner mon ventilateur ou la climatisation dans les pièces non occupées", - "longDescription": "Cela permet d'évite des consommations inutiles. Le froid ne restera pas dans la pièce. Donc il est préférable d'allumer le ventilateru ou climatiseur seulement quand des personnes sont présentes dans la pièce.", + "longDescription": "Cela permet d'évite des consommations inutiles. Le froid ne restera pas dans la pièce. Donc il est préférable d'allumer le ventilateur ou climatiseur seulement quand des personnes sont présentes dans la pièce.", "impactLevel": 8, "efficiency": 4, "difficulty": 2, @@ -878,7 +878,7 @@ "usage": 1, "fluidTypes": [0, 2], "shortName": "Calfeutrage", - "longName": "Je bloque les entrées d’air froid des pièces non chauffés (sous-sol, cave, cellier…) à l’aide de boudins de portes.", + "longName": "Je bloque les entrées d’air froid des pièces non chauffées (sous-sol, cave, cellier…) à l’aide de boudins de portes.", "longDescription": "En revanche, ne bouchez jamais les grilles de ventilation, elles sont essentielles pour maintenir une bonne qualité de l’air dans votre logement.", "impactLevel": 7, "efficiency": 3.5, @@ -970,7 +970,7 @@ "usage": 1, "fluidTypes": [0, 2], "shortName": "Thermos-Logis", - "longName": "Je conserve au maximum la fraicheur de mon logement en fermant les volets et fenêtres quand je m’absente pendant la journée.", + "longName": "Je conserve au maximum la fraîcheur de mon logement en fermant les volets et fenêtres quand je m’absente pendant la journée.", "longDescription": "En laissant les fenêtres ouvertes aux heures chaudes, vous faites entrer la chaleur dans le logement. Une chaleur qui sera difficile à évacuer une fois les pièces réchauffées. L’idéal est de fermer les fenêtres dès que la température extérieure dépasse la température du logement. En revanche, laissez-les bien ouvertes la nuit afin que l’air frais rafraîchisse votre intérieur. ", "impactLevel": 7, "efficiency": 3.5, @@ -982,7 +982,7 @@ "equipmentInstallation": true, "investment": null, "action": true, - "actionName": "Je conserve au maximum la fraicheur de mon logement en fermant les volets et fenêtres quand je m’absente pendant la journée.", + "actionName": "Je conserve au maximum la fraîcheur de mon logement en fermant les volets et fenêtres quand je m’absente pendant la journée.", "actionDuration": 3, "doing": false, "objective": false, @@ -1086,7 +1086,7 @@ "fluidTypes": [0], "shortName": "Cape d'invisibilité", "longName": "Je branche ma \"box\" internet sur une multi-prise ou sur une minuterie pour l'éteindre quand je n'en n'ai pas besoin.", - "longDescription": "La consommation des box internet est loin d’être négligeable : autour de 200 kWh par an pour un usage moyen et avec des variations du simple au double selon votre fournisseur et votre équipement. Face à cela, une solution s’impose : la débrancher tout simplement ! Pour faciliter les bonnes habitudes nous vous conseillons de la brancher sur une minuterie qui s’éteindra toute seule pendant la nuit par exemple selon les réglages que vous aurez prévus. Sinon, une simple muli-prise fait l'affaire si vous pensez à l'éteindre !", + "longDescription": "La consommation des box internet est loin d’être négligeable : autour de 200 kWh par an pour un usage moyen et avec des variations du simple au double selon votre fournisseur et votre équipement. Face à cela, une solution s’impose : la débrancher tout simplement ! Pour faciliter les bonnes habitudes nous vous conseillons de la brancher sur une minuterie qui s’éteindra toute seule pendant la nuit par exemple selon les réglages que vous aurez prévus. Sinon, une simple multi-prise fait l'affaire si vous pensez à l'éteindre !", "impactLevel": 3, "efficiency": 1.5, "difficulty": 2, @@ -1187,7 +1187,7 @@ "equipment": false, "equipmentType": ["DRYER"], "equipmentInstallation": false, - "investment": "Etendage", + "investment": "Étendage", "action": false, "actionName": null, "actionDuration": 3, @@ -1270,7 +1270,7 @@ "fluidTypes": [1], "shortName": "Pisciniste", "longName": "Si j'ai un grand évier, j'utilise un bac pour faire la vaisselle.", - "longDescription": "C’est mieux que de laisser le robinet ouvert pendant toute la vaisselle : même si celui-ci est équipé d’un \"écomousseur\" ! En plus, ça mousse mieux et vous économisez aussi du liquide vaisselle, astucieux, non ?", + "longDescription": "C’est mieux que de laisser le robinet ouvert pendant toute la vaisselle : même si celui-ci est équipé d’un \"éco-mousseur\" ! En plus, ça mousse mieux et vous économisez aussi du liquide vaisselle, astucieux, non ?", "impactLevel": 3, "efficiency": 1.5, "difficulty": 2, @@ -1279,7 +1279,7 @@ "equipment": false, "equipmentType": [], "equipmentInstallation": false, - "investment": "un bac à vaiselle", + "investment": "un bac à vaisselle", "action": false, "actionName": null, "actionDuration": 3, @@ -1499,7 +1499,7 @@ "usage": 1, "fluidTypes": [2], "shortName": "Brûleur Expert", - "longName": "Je nettoie et je régle la combustion de ma chaudière tous les ans.", + "longName": "Je nettoie et je règle la combustion de ma chaudière tous les ans.", "longDescription": "Le mauvais entretien ou réglage d’une chaudière peut réduire son efficacité. Pour obtenir un rendement maximal, faites vérifier votre équipement de chauffage tous les ans. L’entretien régulier permet d’éviter les sur-consommations.Indispensable pour votre sécurité, la révision annuelle des chaudières à combustion (gaz, fioul, bois) est obligatoire ", "impactLevel": 7, "efficiency": 3.5, @@ -1592,7 +1592,7 @@ "fluidTypes": [2], "shortName": "Passage au stand", "longName": "Si mon circuit de chauffage a plus de 10 ans, je le fait désembouer.", - "longDescription": "Au fil du temps, la tuyauterie s’oxyde, entraînant la formation de boues et autres sédiments dans le circuit. L’embouage de l’installation nuit à la diffusion de chaleur : cela peut entraîner une perte de la performance allant jusqu’à 40 %. Vous pouvez désembouer votre radiateur vous-même ou faire appel à un pro. Etape 1 : Eteindre sa chaudière puis laissez l’eau redescendre à température ambiante. Fermez tous vos radiateurs. Etape 2 : Le désembouage doit commencer par le premier radiateur, c’est-à -dire le plus proche du chauffage central. Fermez les vannes de ce radiateur. Dévissez son purgeur avec la clé à molette puis versez le produit désembouant directement dans le radiateur à l’aide de votre entonnoir. Revissez le purgeur puis remettez le chauffage central en marche. Laissez agir le produit le temps indiqué sur la notice, soit 2 à 5 jours en moyenne, voire davantage (voir notice produit désembouant). Étape n°3 : La vidange du circuit de chauffage. Patientez le temps nécessaire pour bien laisser le temps au produit d’agir en profondeur. Ce temps lui permet de bien décoller les boues et de les mettre en suspension afin de les évacuer plus facilement. Une fois ce délai passé, vous pouvez procéder à la vidange. Pour cela, coupez le chauffage à nouveau. Vidangez la totalité du circuit de chauffage en permettant un débit suffisamment fort pour évacuer les boues en suspension par le robinet de vidange du radiateur. Lorsque la vidange est effectuée, rincez le radiateur et remplissez-le à nouveau. Vous pouvez aussi faire appel à un plombier, comptez 350 à 450 euros HT pour un circuit comprenant moins de 10 radiateurs.", + "longDescription": "Au fil du temps, la tuyauterie s’oxyde, entraînant la formation de boues et autres sédiments dans le circuit. L’embouage de l’installation nuit à la diffusion de chaleur : cela peut entraîner une perte de la performance allant jusqu’à 40 %. Vous pouvez désembouer votre radiateur vous-même ou faire appel à un pro. Etape 1 : Éteindre sa chaudière puis laissez l’eau redescendre à température ambiante. Fermez tous vos radiateurs. Etape 2 : Le désembouage doit commencer par le premier radiateur, c’est-à -dire le plus proche du chauffage central. Fermez les vannes de ce radiateur. Dévissez son purgeur avec la clé à molette puis versez le produit désembouant directement dans le radiateur à l’aide de votre entonnoir. Revissez le purgeur puis remettez le chauffage central en marche. Laissez agir le produit le temps indiqué sur la notice, soit 2 à 5 jours en moyenne, voire davantage (voir notice produit désembouant). Étape n°3 : La vidange du circuit de chauffage. Patientez le temps nécessaire pour bien laisser le temps au produit d’agir en profondeur. Ce temps lui permet de bien décoller les boues et de les mettre en suspension afin de les évacuer plus facilement. Une fois ce délai passé, vous pouvez procéder à la vidange. Pour cela, coupez le chauffage à nouveau. Vidangez la totalité du circuit de chauffage en permettant un débit suffisamment fort pour évacuer les boues en suspension par le robinet de vidange du radiateur. Lorsque la vidange est effectuée, rincez le radiateur et remplissez-le à nouveau. Vous pouvez aussi faire appel à un plombier, comptez 350 à 450 euros HT pour un circuit comprenant moins de 10 radiateurs.", "impactLevel": 6, "efficiency": 3, "difficulty": 3, @@ -1661,7 +1661,7 @@ "fluidTypes": [0, 2], "shortName": "Le Grand Nettoyage", "longName": "Je purge mes radiateurs hydrauliques tous les ans.", - "longDescription": "Lorsque les radiateurs sont froids en haut mais chauds en bas, c'est qu'ils contiennent de l'air qui diminue nettement leur rendement. Ils ont donc besoin d'être purgés : 1. Coupez l'alimentation d'eau au niveau de votre chaudière pour ne pas avoir de l'eau sous pression, fermez les vannes thermostatiques des radiateurs et prévoyez un récipient pour recueillir l'eau ; 2. Commencez par le radiateur situé au plus bas de la maison : ouvrez le purgeur dans le sens inverse des aiguilles d'une montre jusqu'à entendre un sifflement, signe que l'air s'échappe. En général, le purgeur se trouve en partie haute du radiateur, du côté opposé au robinet d'alimentation. Sur certains modèles anciens, une clé spéciale est nécessaire pour le dévisser (trouvable en quincailleries et magasins de bricolage). Attention, ne dévissez jamais la molette complètement, vous risqueriez de ne jamais réussir à la remettre en place ; 3; Quand l'eau se met à couler, refermez la molette ; 4. Resserez la vis de purge. 5 Vérifiez au manomètre de la chaudière que la pression d'eau dans l'installation est suffisante (entre 1,5 et 2 bars). Dans le cas contraire, ajoutez de l'eau.", + "longDescription": "Lorsque les radiateurs sont froids en haut mais chauds en bas, c'est qu'ils contiennent de l'air qui diminue nettement leur rendement. Ils ont donc besoin d'être purgés : 1. Coupez l'alimentation d'eau au niveau de votre chaudière pour ne pas avoir de l'eau sous pression, fermez les vannes thermostatiques des radiateurs et prévoyez un récipient pour recueillir l'eau ; 2. Commencez par le radiateur situé au plus bas de la maison : ouvrez le purgeur dans le sens inverse des aiguilles d'une montre jusqu'à entendre un sifflement, signe que l'air s'échappe. En général, le purgeur se trouve en partie haute du radiateur, du côté opposé au robinet d'alimentation. Sur certains modèles anciens, une clé spéciale est nécessaire pour le dévisser (trouvable en quincailleries et magasins de bricolage). Attention, ne dévissez jamais la molette complètement, vous risqueriez de ne jamais réussir à la remettre en place ; 3; Quand l'eau se met à couler, refermez la molette ; 4. Resserrez la vis de purge. 5 Vérifiez au manomètre de la chaudière que la pression d'eau dans l'installation est suffisante (entre 1,5 et 2 bars). Dans le cas contraire, ajoutez de l'eau.", "impactLevel": 5, "efficiency": 2.5, "difficulty": 3, diff --git a/src/db/explorationEntity.json b/src/db/explorationEntity.json index 218d3a5e4adb4e9188949387e3b0703c8a08872d..3a596b8da0b693d4b9912c0e17ad4dc4128dfd53 100644 --- a/src/db/explorationEntity.json +++ b/src/db/explorationEntity.json @@ -62,8 +62,8 @@ { "_id": "EXPLORATION005", "state": 0, - "description": "Envoyez-nous un avis sur notre service. Vous remporterez 5 étoiles, quelque soit son contenu (tant qu'il est sincère :))", - "complementary_description": "", + "description": "Envoyez-nous un avis (sincère :)) sur notre service. Vous remporterez 5 étoiles\u00a0!", + "complementary_description": "Pour cela, écrivez-nous via le Service d'Assistance Utilisateurs et sa rubrique \"J'ai une idée à partager\".", "target": 1, "type": 1, "date": null, diff --git a/src/db/quizEntity.json b/src/db/quizEntity.json index ffa6f2a7e4d232be168e9b04a6c36e79a8d3d49d..f49a4a8ccb54a077356ac857af49f6ea6cbe217e 100644 --- a/src/db/quizEntity.json +++ b/src/db/quizEntity.json @@ -133,7 +133,7 @@ "isTrue": false } ], - "explanation": "Ce chiffre peut varier d'un foyer à l'autre et de son activité. Il faut savoir cependant que la quantité de vapeur d’eau produite par les fonctions métaboliques des occupants comme la respiration et la transpiration peut aller jusqu'à 0,2L par personne et par heure. A celà , de l'humidité peut également être créer par les autres activité (lavage, séchage de linge, bain, douche ...) Cette réponse est donc principalement un ordre de grandeur.", + "explanation": "Ce chiffre peut varier d'un foyer à l'autre et de son activité. Il faut savoir cependant que la quantité de vapeur d’eau produite par les fonctions métaboliques des occupants comme la respiration et la transpiration peut aller jusqu'à 0,2L par personne et par heure. A cela, de l'humidité peut également être créer par les autres activité (lavage, séchage de linge, bain, douche ...) Cette réponse est donc principalement un ordre de grandeur.", "source": "string" }, { @@ -205,7 +205,7 @@ "answers": [ { "answerLabel": "Thermique", "isTrue": false }, { - "answerLabel": "Geothermique", + "answerLabel": "Géothermique", "isTrue": true }, { @@ -300,7 +300,7 @@ "source": "string" }, { - "questionLabel": "Quel est l'interêt d'avoir des fenêtre à double vitrage ?", + "questionLabel": "Quel est l’intérêt d'avoir des fenêtre à double vitrage ?", "answers": [ { "answerLabel": "fenêtre plus solide", @@ -406,7 +406,7 @@ } ], "customQuestion": { - "questionLabel": "Quel jour avez-vous le plus consommé parmis les suivants", + "questionLabel": "Quel jour avez-vous le plus consommé parmi les suivants", "type": 0, "timeStep": 20, "interval": 30, diff --git a/src/doctypes/com-grandlyon-ecolyo-fluidsprices.ts b/src/doctypes/com-grandlyon-ecolyo-fluidsprices.ts index 49bd78fb13048633fb75931157c7c6a2204e8782..5d0990df1ff417cad9bb6dac796d0f61fba88ddb 100644 --- a/src/doctypes/com-grandlyon-ecolyo-fluidsprices.ts +++ b/src/doctypes/com-grandlyon-ecolyo-fluidsprices.ts @@ -1 +1 @@ -export const FLUIDPRICES_DOCTYPE = 'com.grandlyon.ecolyo.fluidsprices' +export const FLUIDSPRICES_DOCTYPE = 'com.grandlyon.ecolyo.fluidsprices' diff --git a/src/doctypes/index.ts b/src/doctypes/index.ts index eb711a242a02d5794cca926962def5aa841d3afb..535698232c1e37d419cbf2445be5dacab0fba96a 100644 --- a/src/doctypes/index.ts +++ b/src/doctypes/index.ts @@ -1,34 +1,31 @@ -import { ENEDIS_DAY_DOCTYPE } from './com-grandlyon-enedis-day' -import { GRDF_DAY_DOCTYPE } from './com-grandlyon-grdf-day' -import { EGL_DAY_DOCTYPE } from './com-grandlyon-egl-day' - -import { KONNECTORS_DOCTYPE } from './io-cozy-konnectors' -import { ACCOUNTS_DOCTYPE } from './io-cozy-accounts' -import { JOBS_DOCTYPE } from './io-cozy-jobs' -import { TERMS_DOCTYPE } from './io-cozy-terms' - +import { CHALLENGE_DOCTYPE } from './com-grandlyon-ecolyo-challenge' +import { DUEL_DOCTYPE } from './com-grandlyon-ecolyo-duel' import { ECOGESTURE_DOCTYPE } from './com-grandlyon-ecolyo-ecogesture' +import { EXPLORATION_DOCTYPE } from './com-grandlyon-ecolyo-exploration' +import { FLUIDSPRICES_DOCTYPE } from './com-grandlyon-ecolyo-fluidsprices' import { PROFILE_DOCTYPE } from './com-grandlyon-ecolyo-profile' +import { PROFILEECOGESTURE_DOCTYPE } from './com-grandlyon-ecolyo-profileecogesture' import { PROFILETYPE_DOCTYPE } from './com-grandlyon-ecolyo-profiletype' -import { SCHEMAS_DOCTYPE } from './com-grandlyon-ecolyo-schemas' - -import { CHALLENGE_DOCTYPE } from './com-grandlyon-ecolyo-challenge' -import { USERCHALLENGE_DOCTYPE } from './com-grandlyon-ecolyo-userchallenge' -import { DUEL_DOCTYPE } from './com-grandlyon-ecolyo-duel' import { QUIZ_DOCTYPE } from './com-grandlyon-ecolyo-quiz' -import { FLUIDPRICES_DOCTYPE } from './com-grandlyon-ecolyo-fluidsprices' +import { SCHEMAS_DOCTYPE } from './com-grandlyon-ecolyo-schemas' import { USAGEEVENT_DOCTYPE } from './com-grandlyon-ecolyo-usageevent' -import { EXPLORATION_DOCTYPE } from './com-grandlyon-ecolyo-exploration' -import { ENEDIS_YEAR_DOCTYPE } from './com-grandlyon-enedis-year' -import { ENEDIS_MONTH_DOCTYPE } from './com-grandlyon-enedis-month' -import { ENEDIS_MINUTE_DOCTYPE } from './com-grandlyon-enedis-minute' -import { GRDF_YEAR_DOCTYPE } from './com-grandlyon-grdf-year' -import { GRDF_MONTH_DOCTYPE } from './com-grandlyon-grdf-month' -import { EGL_YEAR_DOCTYPE } from './com-grandlyon-egl-year' +import { USERCHALLENGE_DOCTYPE } from './com-grandlyon-ecolyo-userchallenge' +import { EGL_DAY_DOCTYPE } from './com-grandlyon-egl-day' import { EGL_MONTH_DOCTYPE } from './com-grandlyon-egl-month' -import { ENEDIS_MONTHLY_ANALYSIS_DATA_DOCTYPE } from './com-grandlyon-enedis-monthly-analysis-data' +import { EGL_YEAR_DOCTYPE } from './com-grandlyon-egl-year' +import { ENEDIS_DAY_DOCTYPE } from './com-grandlyon-enedis-day' import { ENEDIS_MAXPOWER_DOCTYPE } from './com-grandlyon-enedis-maxpower' -import { PROFILEECOGESTURE_DOCTYPE } from './com-grandlyon-ecolyo-profileecogesture' +import { ENEDIS_MINUTE_DOCTYPE } from './com-grandlyon-enedis-minute' +import { ENEDIS_MONTH_DOCTYPE } from './com-grandlyon-enedis-month' +import { ENEDIS_MONTHLY_ANALYSIS_DATA_DOCTYPE } from './com-grandlyon-enedis-monthly-analysis-data' +import { ENEDIS_YEAR_DOCTYPE } from './com-grandlyon-enedis-year' +import { GRDF_DAY_DOCTYPE } from './com-grandlyon-grdf-day' +import { GRDF_MONTH_DOCTYPE } from './com-grandlyon-grdf-month' +import { GRDF_YEAR_DOCTYPE } from './com-grandlyon-grdf-year' +import { ACCOUNTS_DOCTYPE } from './io-cozy-accounts' +import { JOBS_DOCTYPE } from './io-cozy-jobs' +import { KONNECTORS_DOCTYPE } from './io-cozy-konnectors' +import { TERMS_DOCTYPE } from './io-cozy-terms' // the documents schema, necessary for CozyClient const doctypes = { @@ -166,7 +163,7 @@ const doctypes = { relationships: {}, }, fluidsPrices: { - doctype: FLUIDPRICES_DOCTYPE, + doctype: FLUIDSPRICES_DOCTYPE, attributes: {}, relationships: {}, }, @@ -190,37 +187,32 @@ const doctypes = { export default doctypes // export all doctypes for the application -export * from './com-grandlyon-enedis-minute' +export * from './com-grandlyon-ecolyo-challenge' +export * from './com-grandlyon-ecolyo-duel' +export * from './com-grandlyon-ecolyo-ecogesture' +export * from './com-grandlyon-ecolyo-exploration' +export * from './com-grandlyon-ecolyo-fluidsprices' +export * from './com-grandlyon-ecolyo-profile' +export * from './com-grandlyon-ecolyo-profileecogesture' +export * from './com-grandlyon-ecolyo-profiletype' +export * from './com-grandlyon-ecolyo-quiz' +export * from './com-grandlyon-ecolyo-schemas' +export * from './com-grandlyon-ecolyo-usageevent' +export * from './com-grandlyon-ecolyo-userchallenge' +export * from './com-grandlyon-egl-day' +export * from './com-grandlyon-egl-month' +export * from './com-grandlyon-egl-year' export * from './com-grandlyon-enedis-day' +export * from './com-grandlyon-enedis-maxpower' +export * from './com-grandlyon-enedis-minute' export * from './com-grandlyon-enedis-month' -export * from './com-grandlyon-enedis-year' export * from './com-grandlyon-enedis-monthly-analysis-data' -export * from './com-grandlyon-enedis-maxpower' - +export * from './com-grandlyon-enedis-year' export * from './com-grandlyon-grdf-day' export * from './com-grandlyon-grdf-month' export * from './com-grandlyon-grdf-year' - -export * from './com-grandlyon-egl-day' -export * from './com-grandlyon-egl-month' -export * from './com-grandlyon-egl-year' - -export * from './io-cozy-konnectors' export * from './io-cozy-accounts' -export * from './io-cozy-triggers' export * from './io-cozy-jobs' +export * from './io-cozy-konnectors' export * from './io-cozy-terms' - -export * from './com-grandlyon-ecolyo-ecogesture' -export * from './com-grandlyon-ecolyo-profile' -export * from './com-grandlyon-ecolyo-profiletype' -export * from './com-grandlyon-ecolyo-schemas' -export * from './com-grandlyon-ecolyo-fluidsprices' - -export * from './com-grandlyon-ecolyo-challenge' -export * from './com-grandlyon-ecolyo-userchallenge' -export * from './com-grandlyon-ecolyo-duel' -export * from './com-grandlyon-ecolyo-quiz' -export * from './com-grandlyon-ecolyo-exploration' -export * from './com-grandlyon-ecolyo-usageevent' -export * from './com-grandlyon-ecolyo-profileecogesture' +export * from './io-cozy-triggers' diff --git a/src/enum/ecogesture.enum.ts b/src/enum/ecogesture.enum.ts index c14162c8e3820dbe84392f5165f52b07941e59aa..c43e069b0065a9f0d1e09ddbcd0ce474c8efdda1 100644 --- a/src/enum/ecogesture.enum.ts +++ b/src/enum/ecogesture.enum.ts @@ -40,7 +40,7 @@ export enum EquipmentType { HYDRAULIC_HEATING = 'HYDRAULIC_HEATING', } -export enum EcogestureStatus { +export enum EcogestureTab { OBJECTIVE = 0, DOING = 1, ALL = 2, diff --git a/src/enum/konnectorError.enum.ts b/src/enum/konnectorError.enum.ts index 17411d2a0e1933974511cc809049cd73329631f8..090a513caafdfc5b964c22c0ec86ab1e0cc98867 100644 --- a/src/enum/konnectorError.enum.ts +++ b/src/enum/konnectorError.enum.ts @@ -2,6 +2,7 @@ export enum KonnectorError { LOGIN_FAILED = 'LOGIN_FAILED', USER_ACTION_NEEDED = 'USER_ACTION_NEEDED', TERMS_VERSION_MISMATCH = 'TERMS_VERSION_MISMATCH', + CHALLENGE_ASKED = 'CHALLENGE_ASKED', UNKNOWN_ERROR = 'UNKNOWN_ERROR', CRITICAL = 'exit status 1', } diff --git a/src/enum/konnectorUpdate.enum.ts b/src/enum/konnectorUpdate.enum.ts index 9d932853d7858d74d900f4af644f0fd4f7c61003..d9b5dd8d71ce6bd1a2220069394358f976f7374e 100644 --- a/src/enum/konnectorUpdate.enum.ts +++ b/src/enum/konnectorUpdate.enum.ts @@ -2,4 +2,5 @@ export enum KonnectorUpdate { ERROR_UPDATE = 'error_update', ERROR_UPDATE_OAUTH = 'error_update_oauth', LOGIN_FAILED = 'login_failed', + ERROR_CONSENT_FORM_GAS = 'error_consent_form_gas', } diff --git a/src/enum/profileType.enum.ts b/src/enum/profileType.enum.ts index 01c2b20a5521cd6ab42731f8f6518ee3469e9ce4..bd2c0a3a2bd7d07cbe64fc062224462b1db69c6e 100644 --- a/src/enum/profileType.enum.ts +++ b/src/enum/profileType.enum.ts @@ -1,6 +1,6 @@ export enum HousingType { INDIVIDUAL_HOUSE = 'individual_house', - APPARTMENT = 'appartment', + APARTMENT = 'apartment', } export enum Floor { @@ -54,6 +54,13 @@ export enum WarmingType { GAS = 2, WOOD = 3, FUEL = 4, + OTHER = 5, +} + +export enum HotWaterFluid { + ELECTRICITY = 0, + GAS = 2, + OTHER = 3, } export enum ProfileTypeStepForm { diff --git a/src/locales/en.json b/src/locales/en.json index 0db3279e44b0dc4fb7e694b6cb10210a96ba6ba5..0967ef424bce6791893e9a57bb952f80fd536e93 100644 --- a/src/locales/en.json +++ b/src/locales/en.json @@ -1,3 +1 @@ -{ - -} +{} diff --git a/src/locales/fr.json b/src/locales/fr.json index fcf5f1b82b34a385ae9bd9bda04b414630494abb..d646b530006f56174fdd860eaaeae67af3fa0bbe 100644 --- a/src/locales/fr.json +++ b/src/locales/fr.json @@ -14,7 +14,8 @@ "title_analysis": "Analyse", "title_profiletype": "Ajuster mon profil", "title_legal_notice": "Mentions légales", - "title_gcu": "CGU", + "title_gcu": "Conditions générales d’utilisation", + "title_accessibility": "Accessibilité : non conforme", "title_sge_connect": "Connexion à l'électricité", "accessibility": { "loading": "Chargement" @@ -208,7 +209,7 @@ }, "step3": { "info1": "La visualisation de vos données sur Ecolyo demande l'activation du <span>partage de toutes les données.</span>", - "info2": "Pour une expérience optimale, <span>une période de consentement de 1 an</span> est recommandée à partir d'aujourd'hui.", + "info2": "Pour une expérience optimale, <span>une période de consentement de 1 an</span> est recommandée à partir d’aujourd’hui.", "info3": "<p>Veillez également à indiquer une date antérieure pour l'historique (1er calendrier) afin de pouvoir récupérer jusqu'à 3 ans d'historique.</p>" }, "button_go_to_partner_site": "Aller sur GRDF" @@ -340,7 +341,8 @@ "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.", "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": "vous n'aviez tout simplement pas de compteur communicant à l'époque\u00a0!" + "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!" }, "modal": { "window_title": "info estimation des prix", @@ -403,7 +405,7 @@ "title": "Félicitations !", "subtitle": "Vous avez terminé tous les défis !", "message1": "Nous travaillons actuellement à vous proposer de nouveaux défis.", - "message2": "Vous pouvez donner votre avis sur ce que vous aimeriez en cliquant sur la bulle jaune." + "message2": "Vous pouvez donner votre avis sur ce que vous aimeriez en cliquant sur la bulle d'aide." }, "duel_empty_value_modal": { "title": "Oups !", @@ -497,7 +499,7 @@ }, "ecogesture_info_modal": { "header": "Comment sont choisis les astuces adaptées à mon profil\u00a0?", - "text": "Les astuces adaptés à votre profil sont aujourd'hui choisies en fonction des compteurs individuels que vous possédez (communicants ou non). Ceux présentés ici vous permettent d'agir sur vos consommations individuelles. Des modes de tri plus personnalisables seront proposés à l'avenir.", + "text": "Les astuces adaptés à votre profil sont aujourd’hui choisies en fonction des compteurs individuels que vous possédez (communicants ou non). Ceux présentés ici vous permettent d'agir sur vos consommations individuelles. Des modes de tri plus personnalisables seront proposés à l'avenir.", "button_close": "J'ai compris", "accessibility": { "window_title": "Fenêtre d'information", @@ -604,12 +606,13 @@ }, "help": { - "title_help": "Besoin d'aide\u00a0?", - "read_help": "Accéder au Service d'Assistance Utilisateur" + "title_help": "une question\u00a0? un problème\u00a0? une suggestion\u00a0?", + "read_help": "Nous écrire via le Service d'Assistance Utilisateur" }, "feedback": { "title": "Vous allez contacter le Service Assistance Utilisateur du Grand Lyon.", - "subtitle": "Pas de panique, c'est bien l'équipe Ecolyo qui traitera votre demande !", + "text1": "Vous pourrez nous remonter un problème, chercher de l'aide pour vous connecter plus facilement, ou encore nous partager une bonne idée d'évolution.", + "text2": "N'hésitez pas à nous écrire ! L'équipe Ecolyo vous répondra avec plaisir :)", "later": "Plus tard", "lets_go": "J'y vais", "accessibility": { @@ -628,7 +631,7 @@ "item2": "En cas de problème majeur avec la gestion de votre compte.", "item3": "De l’évolution de vos consommations, des nouveautés et de la qualité du service via une lettre mensuelle. Vous pouvez à tout moment vous désinscrire de cette lettre via la page Options du service.", "part4": "Vos données privées de consommation d’énergie et d’eau sont récupérées, sauvegardées et stockées dans votre cloud personnel à votre initiative sans visibilité de la Métropole de Lyon sur leur contenu.", - "part5": "Il en est de même pour les données privées de composition du logement et du foyer, fournies par vos soins. Elles restent également sans visibilité de la Métropole de Lyon sur leur contenu.\nLes données d’identification entrées lors de la connexion aux données de consommations d’électricité sont quant à elle conservées dans un espace sécurisé de la Métropole de Lyon et sont utilisées uniquement à des fins de contrôle du consentement par des organismes extérieurs.", + "part5": "Il en est de même pour les données privées de composition du logement et du foyer, fournies par vos soins. Elles restent également sans visibilité de la Métropole de Lyon sur leur contenu.\nLes données d’identification entrées lors de la connexion aux données de consommations d’électricité sont quant à elles conservées dans un espace sécurisé de la Métropole de Lyon et sont utilisées uniquement à des fins de contrôle du consentement par des organismes extérieurs.", "part6": "Dans le cadre de l’évaluation et de l’amélioration du service, des données d’utilisation anonymisées et pseudonymisées seront remontées à des fins d’exploitation statistiques. La récupération de ces statistiques nous permettra de s’assurer du bon fonctionnement technique de la connexion à vos données de consommation, d’évaluer globalement l’usage de l’application via des mesures d’audience ainsi que d’évaluer à terme l’impact global en termes de baisse des consommations énergétiques de notre service.", "part7": "Au sein de votre cloud personnel, vous pouvez à tout moment exercer vos droits d’accès, de rectification, de portabilité, de limitation et d’opposition en consultant notamment la page Options.", "part8": "Vous pouvez également exercer vos droits d’accès, de rectification, de limitation, d’opposition et d’effacement de vos données personnelles en contactant directement le Délégué à la Protection des Données par courrier en écrivant à l’adresse :", @@ -649,7 +652,6 @@ }, "gcu": { "title": "Conditions générales d’utilisation du service", - "subtitle": "Envie de prendre le temps de relire ces CGU ces Conditions Générales d’Utilisation plus tard\u00a0? Vous pourrez les retrouver dans la page Options du service.", "version": "Version du 12.12.2022", "content": { "title1": "Ecolyo, késako\u00a0?", @@ -670,7 +672,7 @@ "part3_3": "Ces acteurs sont responsables de la relève de vos données. Ces données servent notamment à votre fournisseur d’électricité, de gaz ou d’eau pour permettre la facturation de vos consommations d’énergie. Des fournisseurs d’électricité ou de gaz il y en a des dizaines. Les gestionnaires de réseaux (… et de votre compteur) ne sont qu’au nombre de trois. Nous avons donc décidé de travailler avec eux, au plus près de la donnée brute issue de vos compteurs.", "part3_4": "Il vous faudra donc avoir un compte chez GRDF et Eau Publique du Grand Lyon pour accéder à vos données. Si vous n’en avez pas, il suffira de vous en créer un. Ceci ne sera à faire qu’une fois, au début.", "title4": "Ecolyo se trouve dans un cloud personnel Grand Lyon, qu’est-ce que cela signifie\u00a0?", - "part4_1": "Comme vous avez dû le remarquer, lors de votre première connexion à Ecolyo vous avez dû vous créer un compte Cloud Personnel Grand Lyon. Ce cloud personnel est un espace sécurisé porté par l’ambition de vous apporter visibilité, transparence et maitrise sur l’usage de vos données personnelles, et dont les fonctionnalités vous permettant de récupérer, synchroniser, stocker et partager vos données avec les destinataires de votre choix. Le service Ecolyo se déploie à l’intérieur de cet espace protégé. Dans ce cloud personnel, vous pourrez accéder également à d’autres services. Toutes les données traitées par Ecolyo, mais aussi les autres services que vous seriez amenés à utiliser dans ce cloud personnel restent dans ce Cloud Personnel Grand Lyon et n’en sortent pas, sauf si vous décidez vous-même de partager vos données avec des tiers.", + "part4_1": "Comme vous avez dû le remarquer, lors de votre première connexion à Ecolyo vous avez dû vous créer un compte Cloud Personnel Grand Lyon. Ce cloud personnel est un espace sécurisé porté par l’ambition de vous apporter visibilité, transparence et maîtrise sur l’usage de vos données personnelles, et dont les fonctionnalités vous permettant de récupérer, synchroniser, stocker et partager vos données avec les destinataires de votre choix. Le service Ecolyo se déploie à l’intérieur de cet espace protégé. Dans ce cloud personnel, vous pourrez accéder également à d’autres services. Toutes les données traitées par Ecolyo, mais aussi les autres services que vous seriez amenés à utiliser dans ce cloud personnel restent dans ce Cloud Personnel Grand Lyon et n’en sortent pas, sauf si vous décidez vous-même de partager vos données avec des tiers.", "part4_2": "Pour en savoir plus sur ce cloud et son utilisation, ainsi que la durée de conservation de vos données, vous pouvez lire les conditions générales d’utilisation du service <a href=\"https://manager.cozygrandlyon.cloud/tos/266b4226-8417-42fb-b911-41e86dae8581.pdf?locale=fr\">ici</a>.", "title5": "Et donc concrètement pour Ecolyo, quelles données sont collectées et qui y a accès\u00a0?", "part5_1": "Pour qu’Ecolyo ait accès à vos données de consommations, vous devrez activer vos différents connecteurs. À ce moment-là , pour la connexion aux données de gaz et d’eau à travers un parcours qui vous conduira de manière intuitive sur le site de chacun des gestionnaires de réseaux concerné, vous pourrez donner votre consentement à partager ces données avec le Service Ecolyo, et ce pour une durée limitée dans le temps. Pour l’électricité, le don du consentement et la connexion aux données se fait directement dans notre service. Quid de la durée de ce consentement\u00a0? Pour les données électriques, elle est par défaut d'un an. Pour les données gaz, cela sera à vous de la définir (nous vous recommandons 1 an pour une expérience optimale). Les données utilisées pour vérifier la bonne connexion de vos données d’électricité sont stockées du côté de la Métropole de Lyon sur des serveurs sécurisés.", @@ -712,10 +714,6 @@ "button_accept": "Accepter les conditions générales d'utilisation" } }, - "gcu_option": { - "title": "Conditions générales d’utilisation", - "read_gcu": "Lire les CGU" - }, "matomo": { "matomo_title": "Suivi statistiques d'usage Matomo" }, @@ -741,6 +739,7 @@ "error_login_failed": "Identifiants invalides", "error_update": "Un problème est survenu lors du rapatriement de vos données.", "error_update_oauth": "Votre autorisation pour afficher vos données %{fluid} a expiré.", + "error_consent_form_gas": "Vos données ne peuvent être récupérées car vous n'avez pas coché l'autorisation d'accès aux données informatives lors de votre partage de consentement.", "button_oauth_reload": "Redonner mon consentement", "OK": "Ok", "konnector_delta": { @@ -775,9 +774,16 @@ "success_data_electricity": "Vos données de consommation d'électricité sont maintenant connectées à Ecolyo.", "success_data_water": "Vos données de consommation d'eau sont maintenant connectées à Ecolyo.", "success_data_gas": "Vos données de consommation de gaz sont maintenant connectées à Ecolyo.", - "success_data_update_electricity": "Vos données de consommation d'électricité sont maintenant à jour dans Ecolyo.", - "success_data_update_water": "Vos données de consommation d'eau sont maintenant à jour dans Ecolyo.", - "success_data_update_gas": "Vos données de consommation de gaz sont maintenant à jour dans Ecolyo.", + "success_data_additional_electricity": "Les données de consommations mettent entre un et deux jours pour arriver.", + "success_data_additional_water": "Les données de consommations mettent entre trois et cinq jours pour arriver.", + "success_data_additional_gas": "Les données de consommations mettent entre trois et cinq jours pour arriver.", + "success_update_txt": "Connexion réussie !", + "success_data_update_electricity": "Ecolyo est bien connecté à votre compteur d'électricité.", + "success_data_update_water": "Ecolyo est bien connecté à votre compteur d'eau.", + "success_data_update_gas": "Ecolyo est bien connecté à votre compteur de gaz.", + "success_data_additional_update_electricity": "Sachez que la donnée de consommation d'électricité arrive entre J+1 et J+2.<br /><br />S'il vous manque encore des données, c'est qu'elles n'ont pas encore été mises à disposition par le gestionnaire de votre compteur. Merci pour votre patience\u00a0!", + "success_data_additional_update_water": "Sachez que la donnée de consommation d'eau arrive entre J+3 et J+5.<br /><br />S'il vous manque encore des données, c'est qu'elles n'ont pas encore été mises à disposition par le gestionnaire de votre compteur. Merci pour votre patience\u00a0!", + "success_data_additional_update_gas": "Sachez que la donnée de consommation de gaz arrive entre J+3 et J+5.<br /><br />S'il vous manque encore des données, c'est qu'elles n'ont pas encore été mises à disposition par le gestionnaire de votre compteur. Merci pour votre patience\u00a0!", "error_txt": "Aïe !", "mismatch": { "title": "Vos données n'ont pas pu être récupérées.", @@ -794,13 +800,16 @@ "error_credentials_update_electricity": "Un problème a lieu lors de la récupération de vos données. Merci de supprimer votre connecteur et vous reconnecter.", "error_credentials_update_gas": "Un problème a lieu lors de la récupération de vos données. Merci de supprimer votre connecteur et vous reconnecter.", "error_data_gas": "Un problème est survenu. Vos données de consommation de gaz ne seront pas chargées.", + "error_consent_form_gas_title": "Nous n'avons pas pu connecter vos données de consommation de gaz à Ecolyo.", + "error_consent_form_gas_content": "En effet, le partage de vos données de consommation de gaz \"informatives\" doit être accepté.", + "error_consent_form_gas_content_2": "Merci de cocher \"OUI\" au partage de vos données de consommation de gaz, et à \"Autoriser l'accès à mes données informatives\".", "error_data_update_electricity": "Un problème est survenu. Vos données de consommation d’électricité n’ont pas été mises à jour.", "error_data_update_water": "Un problème est survenu. Vos données de consommation d’eau n’ont pas été mises à jour.", "error_data_update_gas": "Un problème est survenu. Vos données de consommation de gaz n’ont pas été mises à jour.", "error_data_2": "Merci de réessayer plus tard.", "button_validate": "Ok", "button_understood": "J'ai compris", - "button_come_back_later": "Revenir plus tard", + "button_try_again": "Réessayer", "show_common_error": "Voir les erreurs récurrentes", "show_common_error_list": "<span style=\"text-align:left; font-weight:700;\">Le problème peut provenir des cas suivants :</span> <ul style=\"text-align:left;\"><li>Vous avez un co-titulaire sur votre contrat. Veillez à bien entrer le nom du <span style=\"color:#E3B82A; font-weight:700;\">titulaire du contrat</span> et non le co-titulaire.</li><li> Votre nom comporte un tiret\u00a0? Tentez sans le tiret.</li><li> Entrez bien le nom de votre commune de résidence en entier (tirets et accents inclus)</li><li> Avez-vous bien entré le <span style=\"color:#E3B82A; font-weight:700;\">numéro de votre compteur</span> (PDL)\u00a0? Tout autre numéro (de contrat, de client) ne fonctionne pas.</li></ul><p style=\"text-align:center; font-style: italic; font-weight:400; font-size: 0.9rem;\">Si vous rencontrez toujours des difficultés, contactez notre service d'aide </p><div style=\"text-align:center; font-weight:700;\">Avez-vous pensez à vérifier ces informations\u00a0?</div>", "accessibility": { @@ -842,7 +851,7 @@ "phone": "Tél : (33) 4 78 63 40 40", "mail": "<a href=\"mailto:ecolyo@grandlyon.com\"> ecolyo(at)grandlyon.com</a>", "p1b": "Directrice de publication : ", - "p1": "Blandine MELAY, Responsable du Service Energie Climat", + "p1": "Blandine MELAY, Responsable du Service Transition Énergétique", "p2b": "Animation éditoriale, gestion et mise à jour : ", "p2": "Marion BERTHOLON, Chargée de services numériques pour la transition énergétique", "p3b": "Photographies : ", @@ -975,7 +984,7 @@ "title": "Logement", "question": "De quel type de logement disposez-vous\u00a0?", "individual_house": "Maison individuelle", - "appartment": "Appartement" + "apartment": "Appartement" }, "construction_year": { "title": "Construction", @@ -1092,20 +1101,24 @@ "2": "Gaz", "3": "Bois", "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" + "4_text": "Produit grâce au fioul", + "5_text": "Produit grâce à un autre moyen" }, "hot_water_fluid": { "title": "Source eau chaude", "question": "Avec quelle source d’énergie votre eau chaude est-elle produite\u00a0?", "0": "Électricité", "2": "Gaz", + "3": "Autre (Fioul, Bois)", "no_fluid_text": "Produite ni par de l'électricité, ni par du gaz", "0_text": "Produite grâce à de l'électricité", - "2_text": "Produite grâce au gaz" + "2_text": "Produite grâce au gaz", + "3_text": "Produite à partir d'un autre moyen que l'électricité ou le gaz" }, "cooking_fluid": { "title": "Source cuisson", diff --git a/src/migrations/migration.data.ts b/src/migrations/migration.data.ts index 06a3a1b5b2bf46746da60bd6f64199b75904b90c..758dfc12f95d6779f7625ec6f9815697ac03fce8 100644 --- a/src/migrations/migration.data.ts +++ b/src/migrations/migration.data.ts @@ -7,7 +7,7 @@ import { ENEDIS_MONTHLY_ANALYSIS_DATA_DOCTYPE, ENEDIS_MONTH_DOCTYPE, ENEDIS_YEAR_DOCTYPE, - FLUIDPRICES_DOCTYPE, + FLUIDSPRICES_DOCTYPE, GRDF_DAY_DOCTYPE, GRDF_MONTH_DOCTYPE, GRDF_YEAR_DOCTYPE, @@ -278,7 +278,7 @@ export const migrations: Migration[] = [ appVersion: '1.6.0', description: 'Init new doctype fluidPrices --deprecated--', releaseNotes: null, - docTypes: FLUIDPRICES_DOCTYPE, + docTypes: FLUIDSPRICES_DOCTYPE, isCreate: true, isDeprecated: true, run: async (): Promise<any> => { @@ -489,7 +489,7 @@ export const migrations: Migration[] = [ appVersion: '1.7.0', description: 'Init new fluidPrices for water -- deprecated --', releaseNotes: null, - docTypes: FLUIDPRICES_DOCTYPE, + docTypes: FLUIDSPRICES_DOCTYPE, isDeprecated: true, run: async (): Promise<any> => { return [] @@ -523,7 +523,7 @@ export const migrations: Migration[] = [ description: 'Empty fluidPrices db so it can be fetched with right format from remote doctype', releaseNotes: null, - docTypes: FLUIDPRICES_DOCTYPE, + docTypes: FLUIDSPRICES_DOCTYPE, run: async (_client: Client, docs: any[]): Promise<any> => { return docs.map(doc => { doc.deleteAction = true diff --git a/src/migrations/migration.service.spec.ts b/src/migrations/migration.service.spec.ts index 7fe06c9f97f3428d9d696a64167737b0d08b6507..5e717326c8935395fdbb16f34c5b600f75dd7e55 100644 --- a/src/migrations/migration.service.spec.ts +++ b/src/migrations/migration.service.spec.ts @@ -1,13 +1,13 @@ +import { Client, QueryResult } from 'cozy-client' 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 { MigrationService } from './migration.service' -import { Migration, MigrationResult } from './migration.type' import * as Migrate from './migration' import { MIGRATION_RESULT_FAILED } from './migration.data' -import { Client, QueryResult } from 'cozy-client' -import { Notes } from 'models/releaseNotes.model' -import { Schema } from 'models/schema.models' +import { MigrationService } from './migration.service' +import { Migration, MigrationResult } from './migration.type' const migrateSpy = jest.spyOn(Migrate, 'migrate') describe('Migration service', () => { diff --git a/src/migrations/migration.spec.ts b/src/migrations/migration.spec.ts index 01adb4cdadbbfa013459a64b4e735f6545b50180..25ef2b9aabddf6ec4267c8d568cc080390e2eeb7 100644 --- a/src/migrations/migration.spec.ts +++ b/src/migrations/migration.spec.ts @@ -1,5 +1,5 @@ import { QueryResult } from 'cozy-client' -import { FLUIDPRICES_DOCTYPE, PROFILE_DOCTYPE } from 'doctypes' +import { FLUIDSPRICES_DOCTYPE, PROFILE_DOCTYPE } from 'doctypes' import { FluidPrice, Profile } from 'models' import { Schema } from 'models/schema.models' import mockClient from '../../tests/__mocks__/client' @@ -114,7 +114,9 @@ describe('migration', () => { const result = await migrate(migration, mockClient) expect(result).toEqual({ type: MIGRATION_RESULT_FAILED, - errors: ["TypeError: Cannot read property 'data' of undefined"], + errors: [ + "TypeError: Cannot read properties of undefined (reading 'data')", + ], }) }) @@ -201,7 +203,7 @@ describe('migration create', () => { targetSchemaVersion: 1, appVersion: '1.2.4', description: 'Add fluid price', - docTypes: FLUIDPRICES_DOCTYPE, + docTypes: FLUIDSPRICES_DOCTYPE, releaseNotes: null, isCreate: true, run: async (): Promise<FluidPrice[]> => { diff --git a/src/models/challenge.model.ts b/src/models/challenge.model.ts index cfda80f6d0607587eba13b20c72c0ba039aa4427..1e9bee4e14a790b0f90a275222314cf638a7610e 100644 --- a/src/models/challenge.model.ts +++ b/src/models/challenge.model.ts @@ -4,15 +4,15 @@ import { } from 'enum/userChallenge.enum' import { DateTime } from 'luxon' import { - UserDuel, - UserDuelEntity, Dataload, - UserQuiz, - UserExploration, Relation, + UserAction, UserActionEntity, + UserDuel, + UserDuelEntity, + UserExploration, + UserQuiz, } from 'models' -import { UserAction } from 'models' export interface ChallengeState { userChallengeList: UserChallenge[] diff --git a/src/models/duel.model.ts b/src/models/duel.model.ts index bd46e2391129350ea9b930c492e091614b6091f7..83687f7191a3e0a35fbfca2ecae29302c09c0eb0 100644 --- a/src/models/duel.model.ts +++ b/src/models/duel.model.ts @@ -1,6 +1,6 @@ -import { DateTime, Duration } from 'luxon' -import { UserDuelState } from 'enum/userDuel.enum' import { FluidType } from 'enum/fluid.enum' +import { UserDuelState } from 'enum/userDuel.enum' +import { DateTime, Duration } from 'luxon' export interface DuelEntity { id: string diff --git a/src/models/exploration.model.ts b/src/models/exploration.model.ts index 6cd6e208121d089067285a3a363e1b3361009771..eccf99be8768779fca4eaff4b4f26a723323d0bc 100644 --- a/src/models/exploration.model.ts +++ b/src/models/exploration.model.ts @@ -1,9 +1,9 @@ /* eslint-disable camelcase */ +import { FluidType } from 'enum/fluid.enum' import { UserExplorationState, UserExplorationType, } from 'enum/userExploration.enum' -import { FluidType } from 'enum/fluid.enum' import { DateTime } from 'luxon' export interface ExplorationEntity { diff --git a/src/models/global.model.ts b/src/models/global.model.ts index 0af069136897307a2aa5830d33d6334e1d2b95d1..1d4edf10f092d53335e3f06ba1804cf1c83e9115 100644 --- a/src/models/global.model.ts +++ b/src/models/global.model.ts @@ -3,6 +3,7 @@ import { ScreenType } from 'enum/screen.enum' import { TermsStatus } from 'models' import { CustomPopup } from './customPopup.model' import { FluidStatus } from './fluid.model' +import { PartnersInfo } from './partnersInfo.model' import { ReleaseNotes } from './releaseNotes.model' import { SgeStore } from './sgeStore.model' @@ -17,11 +18,7 @@ export interface GlobalState { fluidStatus: FluidStatus[] fluidTypes: FluidType[] customPopupModal: CustomPopup - openPartnersIssueModal: { - enedis: boolean - egl: boolean - grdf: boolean - } shouldRefreshConsent: boolean sgeConnect: SgeStore + partnersInfo: PartnersInfo } diff --git a/src/models/index.ts b/src/models/index.ts index ae7e808314d0b5193a975aeee5cc5973fd3659c9..69e5f3bc14850f2b389b87537395b6042eb90aa9 100644 --- a/src/models/index.ts +++ b/src/models/index.ts @@ -1,9 +1,10 @@ export * from './account.model' -export * from './analysis.model' export * from './action.model' +export * from './analysis.model' export * from './challenge.model' export * from './chart.model' export * from './config.model' +export * from './customPopup.model' export * from './datachart.model' export * from './dataload.model' export * from './duel.model' @@ -13,16 +14,16 @@ export * from './fluid.model' export * from './fluidPrice.model' export * from './global.model' export * from './indicator.model' +export * from './initialisationSteps.model' export * from './konnector.model' export * from './modal.model' +export * from './partnersInfo.model' export * from './profile.model' export * from './profileType.model' export * from './quiz.model' export * from './relation.model' -export * from './analysis.model' -export * from './timePeriod.model' export * from './term.model' +export * from './timePeriod.model' export * from './trigger.model' export * from './usageEvent.model' export * from './userInstanceSettings.model' -export * from './fluidPrice.model' diff --git a/src/models/modal.model.ts b/src/models/modal.model.ts index 90dd1a34fd3564201a82261c751fd0ecce4db3dc..d98440cc5f4c7303f906f4bdaaf347156419386a 100644 --- a/src/models/modal.model.ts +++ b/src/models/modal.model.ts @@ -1,3 +1,8 @@ export interface ModalState { isFeedbacksOpen: boolean + partnersIssueModal: { + enedis: boolean + egl: boolean + grdf: boolean + } } diff --git a/src/models/profileEcogesture.model.ts b/src/models/profileEcogesture.model.ts index 08187ec483aa0eb76dc7850571df50832717ba5d..90164e3125e9ea7e4bac68ac6cd7eb730a3f189e 100644 --- a/src/models/profileEcogesture.model.ts +++ b/src/models/profileEcogesture.model.ts @@ -2,8 +2,8 @@ import { EquipmentType } from 'enum/ecogesture.enum' import { ProfileEcogestureAnswerType } from 'enum/ecogestureForm.enum' import { FluidType } from 'enum/fluid.enum' import { - IndividualOrCollective, HotWaterEquipment, + IndividualOrCollective, WarmingType, } from 'enum/profileType.enum' @@ -13,6 +13,7 @@ interface ProfileEcogestureIndexableTypes { | FluidType | WarmingType | EquipmentType[] + | ProfileEcogesture | string | null } diff --git a/src/models/profileType.model.ts b/src/models/profileType.model.ts index a4e6a7fdfacf1b6eda4524a434653242877771c3..f1f0b97959607348f2dd977fe8994fe65ad8ce91 100644 --- a/src/models/profileType.model.ts +++ b/src/models/profileType.model.ts @@ -1,18 +1,19 @@ +import { EquipmentType } from 'enum/ecogesture.enum' +import { FluidType } from 'enum/fluid.enum' import { - HousingType, - Floor, ConstructionYear, - IndividualInsulationWork, + Floor, HotWaterEquipment, - OutsideFacingWalls, + HotWaterFluid, + HousingType, + IndividualInsulationWork, IndividualOrCollective, + OutsideFacingWalls, ProfileTypeFormType, ThreeChoicesAnswer, WarmingType, } from 'enum/profileType.enum' -import { FluidType } from 'enum/fluid.enum' import { DateTime } from 'luxon' -import { EquipmentType } from 'enum/ecogesture.enum' interface ProfileTypeIndexableTypes { [key: string]: @@ -47,7 +48,7 @@ export interface ProfileType extends ProfileTypeIndexableTypes { hasReplacedHeater: ThreeChoicesAnswer hotWaterEquipment: HotWaterEquipment warmingFluid: WarmingType | null - hotWaterFluid: FluidType | null + hotWaterFluid: HotWaterFluid | null cookingFluid: FluidType updateDate: DateTime equipments: EquipmentType[] diff --git a/src/models/quiz.model.ts b/src/models/quiz.model.ts index 1accadc53a48197b600db8e2e01cb0ba9c26443d..a03221eb7381f73f201cd384710bac2ce7533eea 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, UserQuestionState, UserQuizState, } from 'enum/userQuiz.enum' -import { TimeStep } from 'enum/timeStep.enum' import { DateTime } from 'luxon' export interface Answer { diff --git a/src/notifications/base/footer.hbs b/src/notifications/base/footer.hbs index d445afddf0a7a92c1ea73d5d2f999400636fb706..878b0df70ff20a21b47e62b8cb371ddc4d16b8af 100644 --- a/src/notifications/base/footer.hbs +++ b/src/notifications/base/footer.hbs @@ -1,24 +1,30 @@ -<mj-section background-color="black"> +<mj-section background-color='black'> <mj-section> - <mj-column vertical-align="middle"> - <mj-image src="{{baseUrl}}/assets/logo-grandlyon.png" alt="logo-grandlyon"> + <mj-column vertical-align='middle'> + <mj-image + src='{{baseUrl}}/assets/logo-grandlyon.png' + alt='logo-grandlyon' + > </mj-image> </mj-column> - <mj-column vertical-align="middle"> - <mj-image src="{{baseUrl}}/assets/logo-gouv.png" alt="logo-gouvernement"> + <mj-column vertical-align='middle'> + <mj-image src='{{baseUrl}}/assets/logo-gouv.png' alt='logo-gouvernement'> </mj-image> </mj-column> - <mj-column vertical-align="middle" > - <mj-image src="{{baseUrl}}/assets/logo-territoire.png" alt="logo-territoire"> + <mj-column vertical-align='middle'> + <mj-image + src='{{baseUrl}}/assets/logo-territoire.png' + alt='logo-territoire' + > </mj-image> </mj-column> - <mj-column vertical-align="middle"> - <mj-image src="{{baseUrl}}/assets/logo-tiga-white.png" alt="logo-tiga" > + <mj-column vertical-align='middle'> + <mj-image src='{{baseUrl}}/assets/logo-tiga-white.png' alt='logo-tiga'> </mj-image> </mj-column> </mj-section> -</mj-section> +</mj-section> \ No newline at end of file diff --git a/src/notifications/base/header.hbs b/src/notifications/base/header.hbs index 6665c67dce823688f5a7b9ea3e13eeab3e53547c..ebd79f038230a90e393e1d0c6f18199dcba9ce58 100644 --- a/src/notifications/base/header.hbs +++ b/src/notifications/base/header.hbs @@ -1,19 +1,20 @@ -<mj-section css-class="background" padding="17px" align="center"> +<mj-section background-color='#1B1C22' padding='17px' align='center'> <mj-social - css-class="button-with-icon" - icon-size="36px" - mode="horizontal" - font-size="24px" - font-weight="normal" + css-class='button-with-icon' + icon-size='36px' + mode='horizontal' + font-size='24px' + font-weight='normal' > <mj-social-element - color="white" - src="{{baseUrl}}/assets/ecolyo-icon.png" - name="ecolyo" - padding="0 10px 0 0" - align="center" + color='white' + src='{{baseUrl}}/assets/ecolyo-icon.png' + name='ecolyo' + padding='0 10px 0 0' + align='center' + vertical-align='middle' > {{title}} </mj-social-element> </mj-social> -</mj-section> +</mj-section> \ No newline at end of file diff --git a/src/notifications/base/unsubscribe.hbs b/src/notifications/base/unsubscribe.hbs index c504f9869b488a896f9d30e8773a2f7dc5acaa1e..2536352fe46c394382248a611e53b056748d4a1b 100644 --- a/src/notifications/base/unsubscribe.hbs +++ b/src/notifications/base/unsubscribe.hbs @@ -1,8 +1,11 @@ -<mj-section background-color="black"> +<mj-section background-color='black'> <mj-column> - <mj-text color="white" align="center" css-class="small"> + <mj-text color='white' align='center' css-class='small'> Vous ne souhaitez plus recevoir d'email d'Ecolyo ? - <a href="{{unsubscribeUrl}}" style="color: #E3B82A; font-weight: 900 !important;">Se désinscrire</a> + <a + href='{{unsubscribeUrl}}' + style='color: #E3B82A; font-weight: 900 !important;' + >Se désinscrire</a> </mj-text> </mj-column> -</mj-section> +</mj-section> \ No newline at end of file diff --git a/src/notifications/monthlyReport.hbs b/src/notifications/monthlyReport.hbs index 120094858bb0d1ad2e1f31cd4ec42bc1bac68f71..0a1fc0225184b32ac917d97d49ce9628543636a6 100644 --- a/src/notifications/monthlyReport.hbs +++ b/src/notifications/monthlyReport.hbs @@ -21,22 +21,22 @@ {{#> base/header}} {{/base/header}} - <mj-section background-color="#121212"> + <mj-section background-color="#121212"> <mj-column width="55%" vertical-align="middle"> - <mj-text color="white" font-weight="900" font-size="24px"> + <mj-text color="white" font-weight="900" font-size="24px"> Bonjour {{username}}, </mj-text> {{#if consumptionTextExist }} - <mj-text color="white" font-weight="400" font-size="18px">Par rapport au mois {{previousMonth}}, vous avez consommé :{{{consumptionText}}}<br /></mj-text> + <mj-text color="white" font-weight="400" font-size="18px">Par rapport au mois {{previousMonth}}, vous avez consommé :{{{consumptionText}}}<br /></mj-text> {{/if}} </mj-column> <mj-column width="45%" vertical-align="middle"> - <mj-image src={{consoImageUrl}} width="132px" align="center" alt="consomation"></mj-image> + <mj-image src={{consoImageUrl}} width="132px" align="center" alt="consommation"></mj-image> </mj-column> </mj-section> <mj-section background-color="#121212"> <mj-column> - <mj-text color="white" font-weight="400" font-size="18px">Retrouvez le détail de vos consommations et plus d'informations dans votre bilan Ecolyo.<br /><br /></mj-text> + <mj-text color="white" font-weight="400" font-size="18px">Retrouvez le détail de vos consommations et plus d'informations dans votre bilan Ecolyo.<br /><br /></mj-text> <mj-social css-class="button-with-icon" icon-size="36px" mode="horizontal" font-size="20px" font-weight="700"> <mj-social-element src="{{baseUrl}}/assets/ecolyo-icon.png" name="ecolyo" padding="0 10px 0 0" href="{{clientUrl}}"> Voir mon bilan @@ -45,7 +45,7 @@ </mj-column> </mj-section> {{#if isContent}} - <mj-section background-color="radial-gradient(96.2% 96.2% at 50% 3.8%, #343641 0%, #1B1C22 100%)"> + <mj-section background-color="#1B1C22"> <mj-column> {{#if isInfo}} <mj-text css-class="title" color="white" font-weight="900" font-size="24px" align="center" > @@ -85,7 +85,8 @@ Un problème, une question, une suggestion ? </mj-text> <mj-text color="white" align="center" font-size="18px"> - N'hésitez pas à nous écrire via la bulle dans le service. + N'hésitez pas à nous écrire via la bulle dans le service ou en + <a style="color:white;" href="https://support.grandlyon.com/ecolyo/" alt="lien vers le service assistance utilisateur">cliquant ici.</a> </mj-text> </mj-column> </mj-section> diff --git a/src/notifications/style.hbs b/src/notifications/style.hbs index 69b682c0f1878c3f19e1fbfb24cc6d7acb59b755..4e9de2c7d000f731ad21100c9a0c6f1f6a82327e 100644 --- a/src/notifications/style.hbs +++ b/src/notifications/style.hbs @@ -1,7 +1,6 @@ <mj-style> - .main div{ line-height: 23.4px !important; font-family: 'Lato', sans-serif !important; } - .main .background{ background: radial-gradient(96.2% 96.2% at 50% 3.8%, - #343641 0%, #1B1C22 100%) !important; } + .main div{ line-height: 23.4px !important; font-family: 'Lato', sans-serif + !important; } </mj-style> <mj-style> .small div{ font-weight: 400 !important; font-size: 13px !important; @@ -17,10 +16,11 @@ <mj-style> .button table { background-color: #F1C017 !important; margin: 10px !important; } .button-with-icon td { padding-right: 1px !important; } .button-with-icon - table { background-color: #F1C017 !important; margin-left: 10px !important; margin-right: 10px !important; } - .button-with-icon span { vertical-align: middle !important; } - .button-with-icon a { vertical-align: middle !important; padding-right: 10px !important;} - .button-with-icon a img { padding-top: 20px !important;} + table { background-color: #F1C017 !important; margin-left: 10px !important; + margin-right: 10px !important; } .button-with-icon span { vertical-align: + middle !important; } .button-with-icon a { vertical-align: middle !important; + padding-right: 10px !important;} .button-with-icon a img { padding-top: 20px + !important;} </mj-style> <mj-style> .custom-link a { color: #F1C017 !important; text-decoration: none !important; @@ -32,28 +32,23 @@ 12px!important } </mj-style> <mj-attributes> - <mj-all font-family="Lato, sans-serif" font-size="16px" /> + <mj-all font-family='Lato, sans-serif' font-size='16px'></mj-all> </mj-attributes> -<mj-font name="Lato" href="https://fonts.googleapis.com/css?family=Lato" /> -<mj-style> - @font-face { - font-family: 'Lato'; - font-style: normal; - font-weight: 400; - src: local('Lato Regular'), local('Lato-Regular'), url(https://fonts.gstatic.com/s/lato/v13/8qcEw_nrk_5HEcCpYdJu8BTbgVql8nDJpwnrE27mub0.woff2) format('woff2'); - unicode-range: U+0100-024F, U+1E00-1EFF, U+20A0-20AB, U+20AD-20CF, U+2C60-2C7F, U+A720-A7FF; - } - @font-face { - font-family: 'Lato'; - font-style: normal; - font-weight: 400; - src: local('Lato Regular'), local('Lato-Regular'), url(https://fonts.gstatic.com/s/lato/v13/MDadn8DQ_3oT6kvnUq_2r_esZW2xOQ-xsNqO47m55DA.woff2) format('woff2'); - unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2212, U+2215; - } - @font-face { - font-family: 'Lato-Bold'; - font-style: normal; - font-weight: 800; - src: asset-url('Lato-Bold.woff2') format('woff2'); - } +<mj-font + name='Lato' + href='https://fonts.googleapis.com/css?family=Lato' +></mj-font> +<mj-style> + @font-face { font-family: 'Lato'; font-style: normal; font-weight: 400; src: + local('Lato Regular'), local('Lato-Regular'), + url(https://fonts.gstatic.com/s/lato/v13/8qcEw_nrk_5HEcCpYdJu8BTbgVql8nDJpwnrE27mub0.woff2) + format('woff2'); unicode-range: U+0100-024F, U+1E00-1EFF, U+20A0-20AB, + U+20AD-20CF, U+2C60-2C7F, U+A720-A7FF; } @font-face { font-family: 'Lato'; + font-style: normal; font-weight: 400; src: local('Lato Regular'), + local('Lato-Regular'), + url(https://fonts.gstatic.com/s/lato/v13/MDadn8DQ_3oT6kvnUq_2r_esZW2xOQ-xsNqO47m55DA.woff2) + format('woff2'); unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02C6, + U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2212, U+2215; } @font-face { + font-family: 'Lato-Bold'; font-style: normal; font-weight: 800; src: + asset-url('Lato-Bold.woff2') format('woff2'); } </mj-style> \ No newline at end of file diff --git a/src/services/account.service.spec.ts b/src/services/account.service.spec.ts index a3d19f98421c49f3de145633f8b23cdb12e20836..c1d2d227ce6d8c200344f1c4e25438f8341f23c3 100644 --- a/src/services/account.service.spec.ts +++ b/src/services/account.service.spec.ts @@ -1,14 +1,14 @@ /* eslint-disable camelcase */ import { QueryResult } from 'cozy-client' -import { AccountAuthData, Account } from 'models' -import mockClient from '../../tests/__mocks__/client' -import AccountService from './account.service' +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 AccountService from './account.service' jest.mock('cozy-harvest-lib/dist/connections/accounts') -import * as harvestLibAccounts from 'cozy-harvest-lib/dist/connections/accounts' const mockHavestLibAccounts = harvestLibAccounts as jest.Mocked< typeof harvestLibAccounts > diff --git a/src/services/account.service.ts b/src/services/account.service.ts index 4c79724e0d43383c521879e0494fc630ade7d367..13ffc78f86d14ef764bfb509ab02f7b9d7d653cd 100644 --- a/src/services/account.service.ts +++ b/src/services/account.service.ts @@ -1,3 +1,4 @@ +/* eslint-disable camelcase */ import * as Sentry from '@sentry/react' import { Client, Q, QueryDefinition, QueryResult } from 'cozy-client' import { diff --git a/src/services/action.service.spec.ts b/src/services/action.service.spec.ts index 01e769596b9fb367e39f479054f76e55b6ffa758..6eea6bfa56f7c29146325fa8e0746f3aaba3358a 100644 --- a/src/services/action.service.spec.ts +++ b/src/services/action.service.spec.ts @@ -2,6 +2,7 @@ import { Season } from 'enum/ecogesture.enum' import { UserActionState } from 'enum/userAction.enum' import { DateTime } from 'luxon' import { Ecogesture, UserAction } from 'models' +import * as utils from 'utils/utils' import { AllEcogestureData, defaultEcogestureData, @@ -10,7 +11,6 @@ import { import mockClient from '../../tests/__mocks__/client' import { userChallengeData } from '../../tests/__mocks__/userChallengeData.mock' import ActionService from './action.service' -import * as utils from 'utils/utils' const mockgetAllUserChallengeEntities = jest.fn() jest.mock('./challenge.service', () => { diff --git a/src/services/action.service.ts b/src/services/action.service.ts index 7a705f6501a4580806ec52db1786e4916f1788b2..9441daf6380dc0fd4e4ef766f472a0df476e8f9e 100644 --- a/src/services/action.service.ts +++ b/src/services/action.service.ts @@ -34,10 +34,10 @@ export default class ActionService { .filter(ecogesture => ecogesture.action === true) .map(action => action._id) - const actionsDone: (string | null)[] = userChallenges + const actionsDone: (string | undefined)[] = userChallenges .map(challenge => challenge.action) .filter(action => action.state === UserActionState.DONE) - .map(action => action.ecogesture && action.ecogesture.id) + .map(action => action.ecogesture?.id) // Remove actions Done from the list if (actionsDone.length > 0) { actionsListIds.forEach(id => { diff --git a/src/services/challenge.service.spec.ts b/src/services/challenge.service.spec.ts index eaf3ac35baebcafb3bd7b9d87682fb46a824e466..b05f55465cffc743227c81ea9e673f3e68cd5a0f 100644 --- a/src/services/challenge.service.spec.ts +++ b/src/services/challenge.service.spec.ts @@ -1,40 +1,34 @@ /* eslint-disable camelcase */ import { QueryResult } from 'cozy-client' -import { - DuelEntity, - ChallengeEntity, - UserChallenge, - QuizEntity, - ExplorationEntity, - Dataload, -} from 'models' +import { DataloadState } from 'enum/dataload.enum' +import { UserActionState } from 'enum/userAction.enum' import { UserChallengeState, UserChallengeSuccess, + UserChallengeUpdateFlag, } from 'enum/userChallenge.enum' -import { UserChallengeUpdateFlag } from 'enum/userChallenge.enum' -import ChallengeService from './challenge.service' +import { UserDuelState } from 'enum/userDuel.enum' +import { cloneDeep } from 'lodash' +import { DateTime, Duration } from 'luxon' import { - userChallengeData, - userChallengeDefault, - userChallengeExplo1OnGoing, - userChallengeExplo4, - userChallengeExplo4_0, -} from '../../tests/__mocks__/userChallengeData.mock' -import mockClient from '../../tests/__mocks__/client' + ChallengeEntity, + Dataload, + DuelEntity, + ExplorationEntity, + QuizEntity, + UserChallenge, +} from 'models' import { allChallengeEntityData, challengeEntityData, } from '../../tests/__mocks__/challengeEntity.mock' +import { graphData } from '../../tests/__mocks__/chartData.mock' +import mockClient from '../../tests/__mocks__/client' import { allDuelEntity, duelData, duelEntity, } from '../../tests/__mocks__/duelData.mock' -import { DateTime, Duration } from 'luxon' -import { graphData } from '../../tests/__mocks__/datachartData.mock' -import { UserDuelState } from 'enum/userDuel.enum' -import { quizEntity, userQuiz } from '../../tests/__mocks__/quizData.mock' import { explorationDefault, explorationEntity, @@ -44,16 +38,22 @@ import { userExploration1, userExploration4, userExploration4_0, - UserExplorationUnlocked, + userExplorationUnlocked, } from '../../tests/__mocks__/explorationData.mock' import { fluidStatusData } from '../../tests/__mocks__/fluidStatusData.mock' -import { cloneDeep } from 'lodash' -import { UserActionState } from 'enum/userAction.enum' -import { DataloadState } from 'enum/dataload.enum' +import { quizEntity, userQuiz } from '../../tests/__mocks__/quizData.mock' +import { + userChallengeData, + userChallengeDefault, + userChallengeExplo1OnGoing, + userChallengeExplo4, + userChallengeExplo4_0, +} from '../../tests/__mocks__/userChallengeData.mock' +import ChallengeService from './challenge.service' const mockGetExplorationEntityById = jest.fn() const mockParseExplorationEntityToUserExploration = jest.fn() -const mockGetUserExplorationfromExplorationEntities = jest.fn() +const mockGetUserExplorationFromExplorationEntities = jest.fn() jest.mock('./exploration.service', () => { return jest.fn(() => { return { @@ -61,7 +61,7 @@ jest.mock('./exploration.service', () => { parseExplorationEntityToUserExploration: mockParseExplorationEntityToUserExploration, getUserExplorationfromExplorationEntities: - mockGetUserExplorationfromExplorationEntities, + mockGetUserExplorationFromExplorationEntities, } }) }) @@ -83,7 +83,7 @@ describe('Challenge service', () => { beforeEach(() => { mockGetExplorationEntityById.mockClear() mockParseExplorationEntityToUserExploration.mockClear() - mockGetUserExplorationfromExplorationEntities.mockClear() + mockGetUserExplorationFromExplorationEntities.mockClear() mockGetGraphData.mockClear() mockCalculatePerformanceIndicatorValue.mockClear() }) @@ -122,7 +122,7 @@ describe('Challenge service', () => { startDate: null, endingDate: null, quiz: userQuiz, - exploration: UserExplorationUnlocked, + exploration: userExplorationUnlocked, action: { ecogesture: null, startDate: null, @@ -133,7 +133,7 @@ describe('Challenge service', () => { challengeEntityData, duelData, userQuiz, - UserExplorationUnlocked + userExplorationUnlocked ) expect(result).toEqual(expectedResult) }) @@ -179,7 +179,7 @@ describe('Challenge service', () => { mockParseExplorationEntityToUserExploration.mockReturnValue( userExploration ) - mockGetUserExplorationfromExplorationEntities.mockReturnValue( + mockGetUserExplorationFromExplorationEntities.mockReturnValue( userExploration ) const result = await challengeService.buildUserChallengeList( @@ -219,7 +219,7 @@ describe('Challenge service', () => { mockParseExplorationEntityToUserExploration.mockReturnValue( explorationDefault ) - mockGetUserExplorationfromExplorationEntities.mockReturnValue( + mockGetUserExplorationFromExplorationEntities.mockReturnValue( explorationDefault ) const result = await challengeService.buildUserChallengeList( @@ -365,7 +365,7 @@ describe('Challenge service', () => { expect(result).toEqual(userChallengeData[0]) const resultDefault = await challengeService.updateUserChallenge( userChallengeData[0], - 999 + 999 as UserChallengeUpdateFlag ) expect(resultDefault).toEqual(userChallengeData[0]) }) diff --git a/src/services/connection.service.spec.ts b/src/services/connection.service.spec.ts index 8c44725272f38aa4d98c836e9a6a91ae78cdd410..9b8e6910b4b8ca5791a3f6b404e1e3f6d5af462d 100644 --- a/src/services/connection.service.spec.ts +++ b/src/services/connection.service.spec.ts @@ -1,8 +1,9 @@ -import ConnectionService from './connection.service' +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 { accountsData } from '../../tests/__mocks__/accountsData.mock' import { triggersData } from '../../tests/__mocks__/triggersData.mock' +import ConnectionService from './connection.service' const mockGetKonnector = jest.fn() jest.mock('./konnector.service', () => { @@ -31,6 +32,11 @@ jest.mock('./triggers.service', () => { }) }) +const mockEGLAuthData: AccountAuthData = { + login: 'login', + password: 'password', +} + describe('Connection service', () => { const connectionService = new ConnectionService(mockClient) @@ -42,8 +48,7 @@ describe('Connection service', () => { const mockResult = { account: accountsData[0], trigger: triggersData[0] } const result = await connectionService.connectNewUser( konnectorsData[0]._id, - 'login', - 'password' + mockEGLAuthData ) expect(result).toEqual(mockResult) }) @@ -53,8 +58,7 @@ describe('Connection service', () => { try { await connectionService.connectNewUser( konnectorsData[0]._id, - 'login', - 'password' + mockEGLAuthData ) } catch (err) { error = err @@ -70,8 +74,7 @@ describe('Connection service', () => { try { await connectionService.connectNewUser( konnectorsData[0]._id, - 'login', - 'password' + mockEGLAuthData ) } catch (err) { error = err @@ -86,8 +89,7 @@ describe('Connection service', () => { try { await connectionService.connectNewUser( konnectorsData[0]._id, - 'login', - 'password' + mockEGLAuthData ) } catch (err) { error = err diff --git a/src/services/connection.service.ts b/src/services/connection.service.ts index 0a1f855ba4c2f6baa514bf5748bd78d8a4f35d15..af9ccea3b23784d69a74183927209a31a17d8596 100644 --- a/src/services/connection.service.ts +++ b/src/services/connection.service.ts @@ -1,4 +1,6 @@ +import * as Sentry from '@sentry/react' import { Client } from 'cozy-client' +import logger from 'cozy-logger' import { Account, AccountAuthData, @@ -6,12 +8,10 @@ import { Konnector, Trigger, } from 'models' +import { SgeStore } from 'models/sgeStore.model' import AccountService from 'services/account.service' -import TriggerService from 'services/triggers.service' import KonnectorService from 'services/konnector.service' -import { SgeStore } from 'models/sgeStore.model' -import logger from 'cozy-logger' -import * as Sentry from '@sentry/react' +import TriggerService from 'services/triggers.service' import logApp from 'utils/logger' const logStack = logger.namespace('connectionService') @@ -33,7 +33,7 @@ export default class ConnectionService { const konnector: Konnector | null = await konnectorService.getKonnector( konnectorId ) - if (!konnector || !konnector.slug) { + if (!konnector?.slug) { const errorMessage = `Could not find konnector for ${konnectorId}` logStack('error', errorMessage) logApp.error(errorMessage) @@ -63,7 +63,7 @@ export default class ConnectionService { konnector, accountAuthData ) - if (!account || !account._id) { + if (!account?._id) { const errorMessage = `Error during account creation` logStack('error', errorMessage) logApp.error(errorMessage) diff --git a/src/services/consumption.service.spec.ts b/src/services/consumption.service.spec.ts index 226026b0218eb20bf7268620490e7e5289394e61..e57b614a04c5659650811615a96a8a1b56f2425d 100644 --- a/src/services/consumption.service.spec.ts +++ b/src/services/consumption.service.spec.ts @@ -404,7 +404,7 @@ describe('Consumption service', () => { }) describe('getExportableFluids method', () => { - it('should return the array of fluidtypes that have entries', async () => { + it('should return the array of fluidTypes that have entries', async () => { const fluidTypes: FluidType[] = [ FluidType.ELECTRICITY, FluidType.WATER, @@ -501,17 +501,16 @@ describe('Consumption service', () => { describe('checkDoctypeEntries method', () => { it('should return a boolean if doctype are correct', async () => { - let fluidType: FluidType = FluidType.GAS + const fluidType: FluidType = FluidType.GAS mockGetEntries.mockResolvedValueOnce({ data: [1] }) let result = await consumptionDataManager.checkDoctypeEntries( fluidType, TimeStep.DAY ) expect(result).toBeTruthy() - fluidType = 999 mockGetEntries.mockResolvedValueOnce({ data: [] }) result = await consumptionDataManager.checkDoctypeEntries( - fluidType, + 999 as FluidType, TimeStep.DAY ) expect(result).toBeFalsy() diff --git a/src/services/consumption.service.ts b/src/services/consumption.service.ts index 3ad7142253b3466eff3013c0fc8994e957d88c23..e3b2b40701a6cfa63de4579e4aff33c25ae042cb 100644 --- a/src/services/consumption.service.ts +++ b/src/services/consumption.service.ts @@ -89,7 +89,7 @@ export default class ConsumptionDataManager { ) return formattedData } else if (fluidTypes.length > 1 || isHome) { - const toBeAgreggatedData: ISingleFluidChartData[] = [] + const toBeAggregatedData: ISingleFluidChartData[] = [] for (const fluidType of fluidTypes) { const fetchedData = await this.fetchSingleFluidGraphData( timePeriod, @@ -107,13 +107,13 @@ export default class ConsumptionDataManager { fluidStatus ? fluidStatus[fluidType] : undefined ) // validating output data - toBeAgreggatedData.push({ + toBeAggregatedData.push({ chartData: formattedData, chartFluid: fluidType, }) } const aggregatedData: Datachart | null = - this.aggregateGraphData(toBeAgreggatedData) + this.aggregateGraphData(toBeAggregatedData) return aggregatedData } else return null } @@ -150,7 +150,7 @@ export default class ConsumptionDataManager { } } - // fetch last dataload available for a given fluid - return the daily data + // fetch last dataload available for a given fluid - return the daily data public async getLastDataload( fluidTypes: FluidType ): Promise<Dataload[] | null> { @@ -421,8 +421,8 @@ export default class ConsumptionDataManager { } else length = singleFluidCharts[0].chartData.actualData.length for (let i = 0; i < length; i++) { - let agreggatedConvertedValue = 0 - let comparisonAgreggatedConvertedValue = 0 + let aggregatedConvertedValue = 0 + let comparisonAggregatedConvertedValue = 0 const tempAggregatedState: DataloadState[] = [] const tempComparisonAggregatedState: DataloadState[] = [] @@ -449,7 +449,7 @@ export default class ConsumptionDataManager { singleFluidChart.chartFluid, singleFluidChart.chartData.actualData[i].price ) - agreggatedConvertedValue += convertedValue + aggregatedConvertedValue += convertedValue } convertedValueDetail[singleFluidChart.chartFluid] = { @@ -457,10 +457,7 @@ export default class ConsumptionDataManager { state: singleFluidChart.chartData.actualData[i].state, } - if ( - singleFluidChart.chartData.comparisonData && - singleFluidChart.chartData.comparisonData[i] - ) { + if (singleFluidChart.chartData.comparisonData?.[i]) { const comparisonValue = singleFluidChart.chartData.comparisonData[i].value tempComparisonAggregatedState.push( @@ -475,7 +472,7 @@ export default class ConsumptionDataManager { singleFluidChart.chartFluid, singleFluidChart.chartData.comparisonData[i].price ) - comparisonAgreggatedConvertedValue += convertedComparisonValue + comparisonAggregatedConvertedValue += convertedComparisonValue } comparisonConvertedValueDetail[singleFluidChart.chartFluid] = { @@ -486,9 +483,9 @@ export default class ConsumptionDataManager { } if (singleFluidCharts.length === noDataCount) - agreggatedConvertedValue = -1 + aggregatedConvertedValue = -1 if (singleFluidCharts.length === comparisonNoDataCount) - comparisonAgreggatedConvertedValue = -1 + comparisonAggregatedConvertedValue = -1 if (singleFluidCharts[0].chartData.actualData[i]) { // Define the aggregated state @@ -496,14 +493,14 @@ export default class ConsumptionDataManager { this._consumptionFormatterService.defineAggregatedDataloadState( tempAggregatedState ) - const acutaldataLoad: Dataload = { + const actualDataLoad: Dataload = { date: singleFluidCharts[0].chartData.actualData[i].date, - value: agreggatedConvertedValue, + value: aggregatedConvertedValue, state: aggregatedDataloadState, valueDetail: - agreggatedConvertedValue === -1 ? null : convertedValueDetail, + aggregatedConvertedValue === -1 ? null : convertedValueDetail, } - resultChartData.actualData.push(acutaldataLoad) + resultChartData.actualData.push(actualDataLoad) } if ( @@ -516,16 +513,16 @@ export default class ConsumptionDataManager { this._consumptionFormatterService.defineAggregatedDataloadState( tempComparisonAggregatedState ) - const comparisondataLoad: Dataload = { + const comparisonDataLoad: Dataload = { date: singleFluidCharts[0].chartData.comparisonData[i].date, - value: comparisonAgreggatedConvertedValue, + value: comparisonAggregatedConvertedValue, state: aggregatedComparisonDataloadState, valueDetail: - comparisonAgreggatedConvertedValue === -1 + comparisonAggregatedConvertedValue === -1 ? null : comparisonConvertedValueDetail, } - resultChartData.comparisonData.push(comparisondataLoad) + resultChartData.comparisonData.push(comparisonDataLoad) } } return resultChartData diff --git a/src/services/consumptionFormatter.service.spec.ts b/src/services/consumptionFormatter.service.spec.ts index 085dab6fb05aa93daec27a81908119c69e7c82c5..1b6e2c2b9d7d31d288524351448127e476847e41 100644 --- a/src/services/consumptionFormatter.service.spec.ts +++ b/src/services/consumptionFormatter.service.spec.ts @@ -66,7 +66,7 @@ let mockTimePeriod: TimePeriod = { zone: 'utc', }), } -const unknowTimeStep = 999 +const unknownTimeStep = 999 as TimeStep describe('ConsumptionFormatter service', () => { const consumptionFormatterService = new ConsumptionFormatterService() @@ -256,7 +256,7 @@ describe('ConsumptionFormatter service', () => { consumptionFormatterService.formatGraphData( mockDataLoad, mockTimePeriod, - unknowTimeStep, + unknownTimeStep, FluidType.ELECTRICITY, fluidStatus[FluidType.ELECTRICITY] ) @@ -283,7 +283,7 @@ describe('ConsumptionFormatter service', () => { state: DataloadState.EMPTY, valueDetail: null, } - it('sould return not change state because data date < today and no firstFluidDataDate & no lastFluidDataDate', () => { + it('should return not change state because data date < today and no firstFluidDataDate & no lastFluidDataDate', () => { const expectedResult: Dataload = mockData const result: Dataload = consumptionFormatterService.defineDataloadState( mockData, @@ -293,7 +293,7 @@ describe('ConsumptionFormatter service', () => { ) expect(result).toEqual(expectedResult) }) - it('sould return COMING state because data date >= today', () => { + it('should return COMING state because data date >= today', () => { localSpy.mockReturnValueOnce( DateTime.fromISO('2020-10-01T00:00:00.000Z', { zone: 'utc' }) ) @@ -309,7 +309,7 @@ describe('ConsumptionFormatter service', () => { ) expect(result).toEqual(expectedResult) }) - it('sould return VALID state because data.date < firstFluidDataDate for day timestep', () => { + it('should return VALID state because data.date < firstFluidDataDate for day timestep', () => { fluidStatus[FluidType.ELECTRICITY].firstDataDate = DateTime.fromISO( '2020-10-20T00:00:00.000Z', { @@ -328,7 +328,7 @@ describe('ConsumptionFormatter service', () => { ) expect(result).toEqual(expectedResult) }) - it('sould return VALID state because data.date < start of month of firstFluidDataDate for month timestep', () => { + it('should return VALID state because data.date < start of month of firstFluidDataDate for month timestep', () => { fluidStatus[FluidType.ELECTRICITY].firstDataDate = DateTime.fromISO( '2020-11-01T00:00:00.000Z', { @@ -347,7 +347,7 @@ describe('ConsumptionFormatter service', () => { ) expect(result).toEqual(expectedResult) }) - it('sould return VALID state because data.date < start of year firstFluidDataDate for year timestep', () => { + it('should return VALID state because data.date < start of year firstFluidDataDate for year timestep', () => { fluidStatus[FluidType.ELECTRICITY].firstDataDate = DateTime.fromISO( '2021-10-20T00:00:00.000Z', { @@ -366,7 +366,7 @@ describe('ConsumptionFormatter service', () => { ) expect(result).toEqual(expectedResult) }) - it('sould return VALID state because data.date < firstFluidDataDate for month timestep', () => { + it('should return VALID state because data.date < firstFluidDataDate for month timestep', () => { fluidStatus[FluidType.ELECTRICITY].firstDataDate = DateTime.fromISO( '2020-10-20T00:00:00.000Z', { @@ -385,7 +385,7 @@ describe('ConsumptionFormatter service', () => { ) expect(result).toEqual(expectedResult) }) - it('sould return VALID state because data.date < firstFluidDataDate for year timestep', () => { + it('should return VALID state because data.date < firstFluidDataDate for year timestep', () => { fluidStatus[FluidType.ELECTRICITY].firstDataDate = DateTime.fromISO( '2020-12-20T00:00:00.000Z', { @@ -404,7 +404,7 @@ describe('ConsumptionFormatter service', () => { ) expect(result).toEqual(expectedResult) }) - it('sould return HOLE state because data.date between firstFluidDataDate and lastFluidDataDate and value is -1', () => { + it('should return HOLE state because data.date between firstFluidDataDate and lastFluidDataDate and value is -1', () => { fluidStatus[FluidType.ELECTRICITY].firstDataDate = DateTime.fromISO( '2020-08-01T00:00:00.000Z', { @@ -429,7 +429,7 @@ describe('ConsumptionFormatter service', () => { ) expect(result).toEqual(expectedResult) }) - it('sould return VALID state because data.date between firstFluidDataDate and lastFluidDataDate and value is -1', () => { + it('should return VALID state because data.date between firstFluidDataDate and lastFluidDataDate and value is -1', () => { fluidStatus[FluidType.ELECTRICITY].firstDataDate = DateTime.fromISO( '2020-08-01T00:00:00.000Z', { @@ -455,7 +455,7 @@ describe('ConsumptionFormatter service', () => { expect(result).toEqual(expectedResult) }) - describe('sould return COMING state because data.date > lastFluidDataDate and is in dataDelayOffset period', () => { + describe('should return COMING state because data.date > lastFluidDataDate and is in dataDelayOffset period', () => { beforeEach(() => { fluidStatus[FluidType.ELECTRICITY].firstDataDate = DateTime.fromISO( '2020-08-01T00:00:00.000Z', @@ -553,7 +553,7 @@ describe('ConsumptionFormatter service', () => { }) }) - describe('sould return MISSING state because data.date > lastFluidDataDate and is not in dataDelayOffset period', () => { + describe('should return MISSING state because data.date > lastFluidDataDate and is not in dataDelayOffset period', () => { beforeEach(() => { fluidStatus[FluidType.ELECTRICITY].firstDataDate = DateTime.fromISO( '2019-08-01T00:00:00.000Z', diff --git a/src/services/consumptionValidator.service.spec.ts b/src/services/consumptionValidator.service.spec.ts index 2957f46199dafdb72428df2c46ee6521e925bdaa..dbb3be7527d383363280d27190c6d43381024adb 100644 --- a/src/services/consumptionValidator.service.spec.ts +++ b/src/services/consumptionValidator.service.spec.ts @@ -1,8 +1,8 @@ -import ConsumptionValidatorService from './consumptionValidator.service' +import { FluidType } from 'enum/fluid.enum' import { TimeStep } from 'enum/timeStep.enum' import { DateTime } from 'luxon' -import { FluidType } from 'enum/fluid.enum' import { TimePeriod } from 'models' +import ConsumptionValidatorService from './consumptionValidator.service' const mockTimePeriod: TimePeriod = { startDate: DateTime.fromISO('2020-10-01T00:00:00.000Z', { zone: 'utc' }), diff --git a/src/services/consumptionValidator.service.ts b/src/services/consumptionValidator.service.ts index 618e402dfb9298e34a6b677798f01f1a34aca5cc..7f3901487ce2cf808b519cfbc7e1ee27f4abbfcd 100644 --- a/src/services/consumptionValidator.service.ts +++ b/src/services/consumptionValidator.service.ts @@ -1,7 +1,7 @@ import { FluidType } from 'enum/fluid.enum' import { TimeStep } from 'enum/timeStep.enum' -import { TimePeriod } from 'models' import { Interval } from 'luxon' +import { TimePeriod } from 'models' export default class ConsumptionValidatorService { public ValidateGetGraphData( diff --git a/src/services/customPopup.service.test.ts b/src/services/customPopup.service.test.ts index 7b30e3b92329b3185f0fe33978da9d737eca13cd..95201974937b73cc975c2b9f46afe90b983a8595 100644 --- a/src/services/customPopup.service.test.ts +++ b/src/services/customPopup.service.test.ts @@ -1,6 +1,6 @@ import mockClient from '../../tests/__mocks__/client' import { mockCustomPopup } from '../../tests/__mocks__/customPopup.mock' -import CustomPupopService from './customPopup.service' +import CustomPopupService from './customPopup.service' jest.mock('services/environment.service', () => { return jest.fn(() => { @@ -11,11 +11,11 @@ jest.mock('services/environment.service', () => { }) describe('PartnersInfo service', () => { - const customPupopService = new CustomPupopService(mockClient) + const customPopupService = new CustomPopupService(mockClient) it('should return customPopup data', async () => { mockClient.getStackClient().fetchJSON.mockResolvedValueOnce(mockCustomPopup) - const result = await customPupopService.getCustomPopup() + const result = await customPopupService.getCustomPopup() expect(result).toBe(mockCustomPopup) }) @@ -23,7 +23,7 @@ describe('PartnersInfo service', () => { mockClient.getStackClient().fetchJSON.mockRejectedValue(new Error()) let res try { - res = await customPupopService.getCustomPopup() + res = await customPopupService.getCustomPopup() expect(true).toBe(false) } catch (error) { expect(res).toBe(undefined) diff --git a/src/services/customPopup.service.ts b/src/services/customPopup.service.ts index 1eee45690bf3851ca28cd1f33dff3a13f48dfde0..32f87726eee3350a2bf1f302737ccfa50fe0f62f 100644 --- a/src/services/customPopup.service.ts +++ b/src/services/customPopup.service.ts @@ -11,7 +11,7 @@ import EnvironmentService from './environment.service' const logStack = logger.namespace('customPopupService') -export default class CustomPupopService { +export default class CustomPopupService { private readonly _client: Client constructor(_client: Client) { this._client = _client diff --git a/src/services/dateChart.service.spec.ts b/src/services/dateChart.service.spec.ts index e78e403999fb843c453cfec1ac720fd9fd19825e..83449b87a24a2c492f6f41e38e8d1352dbf5867f 100644 --- a/src/services/dateChart.service.spec.ts +++ b/src/services/dateChart.service.spec.ts @@ -1,9 +1,10 @@ -import DateChartService from './dateChart.service' import { TimeStep } from 'enum/timeStep.enum' import { DateTime } from 'luxon' import { TimePeriod } from 'models' +import DateChartService from './dateChart.service' const localSpy = jest.spyOn(DateTime, 'local') +const unknownTimeStep = 0 as TimeStep describe('dateChart service', () => { beforeEach(() => { @@ -295,7 +296,7 @@ describe('dateChart service', () => { it('should throw error for unknown TimeStep', () => { try { - dateChartService.defineTimePeriod(refDate, 4, -1) + dateChartService.defineTimePeriod(refDate, unknownTimeStep, -1) } catch (error) { expect(error).toEqual(new Error('TimeStep unknown')) } @@ -693,7 +694,7 @@ describe('dateChart service', () => { zone: 'utc', }) try { - dateChartService.compareStepDate(4, firstDate, secondDate) + dateChartService.compareStepDate(unknownTimeStep, firstDate, secondDate) } catch (error) { expect(error).toEqual(new Error('TimeStep unknown')) } @@ -834,7 +835,7 @@ describe('dateChart service', () => { } ) const result = dateChartService.defineIncrementForPreviousIndex( - 0, + unknownTimeStep, selectedDate, 0 ) @@ -976,7 +977,7 @@ describe('dateChart service', () => { } ) const result = dateChartService.defineIncrementForNextIndex( - 0, + unknownTimeStep, selectedDate, 0 ) @@ -1069,7 +1070,11 @@ describe('dateChart service', () => { }) it('should return selected date for unknown time step', () => { - const result = dateChartService.incrementeDate(0, selectedDate, 1) + const result = dateChartService.incrementeDate( + unknownTimeStep, + selectedDate, + 1 + ) expect(result).toEqual(selectedDate) }) }) @@ -1287,7 +1292,10 @@ describe('dateChart service', () => { zone: 'utc', } ) - const result = dateChartService.defineDateIndex(0, selectedDate) + const result = dateChartService.defineDateIndex( + unknownTimeStep, + selectedDate + ) expect(result).toEqual(0) }) }) diff --git a/src/services/duel.service.spec.ts b/src/services/duel.service.spec.ts index 09a59b3ad6f2c4400c8e5d3b941cb48303bdd597..dd4ea30f57b7c68da20d494d080a6fe153558c65 100644 --- a/src/services/duel.service.spec.ts +++ b/src/services/duel.service.spec.ts @@ -2,22 +2,19 @@ import { QueryResult } from 'cozy-client' import { FluidType } from 'enum/fluid.enum' import { UserDuelState } from 'enum/userDuel.enum' import { DateTime, Duration } from 'luxon' -import { UserDuel, DuelEntity } from 'models' +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 { - duelData, allDuelData, + duelData, duelEntity, } from '../../tests/__mocks__/duelData.mock' -import mockClient from '../../tests/__mocks__/client' import { fluidStatusConnectedData, fluidStatusData, } from '../../tests/__mocks__/fluidStatusData.mock' -import DuelService from 'services/duel.service' -import { - fullGraphData, - graphData, -} from '../../tests/__mocks__/datachartData.mock' const mockGetPerformanceIndicators = jest.fn() const mockGetGraphData = jest.fn() diff --git a/src/services/duel.service.ts b/src/services/duel.service.ts index be3409ffbd2282f035fc7ce321c8efa7a5a1784a..e4ef323b7b15d0e49a80529a0ead45ff269fdc74 100644 --- a/src/services/duel.service.ts +++ b/src/services/duel.service.ts @@ -138,7 +138,7 @@ export default class DuelService { .where({ _id: duelId }) .limitBy(1) const { data }: QueryResult<DuelEntity[]> = await this._client.query(query) - return data && data[0] + return data?.[0] } /** @@ -219,7 +219,7 @@ export default class DuelService { performanceService.aggregatePerformanceIndicators(fetchLastValidData) // Set the threshold let updatedThreshold: number - if (maxData && maxData.value && maxData.value > 0) { + if (maxData?.value && maxData.value > 0) { updatedThreshold = getRoundFloat(maxData.value) } else { updatedThreshold = -1 diff --git a/src/services/ecogesture.service.spec.ts b/src/services/ecogesture.service.spec.ts index 12bfc03391b1477143d54cfad3f0d4d899c09db0..7448b0fe1b8820f68a7cffbc10047f7a28a715b1 100644 --- a/src/services/ecogesture.service.spec.ts +++ b/src/services/ecogesture.service.spec.ts @@ -1,6 +1,8 @@ import { QueryResult } from 'cozy-client' +import { EquipmentType } from 'enum/ecogesture.enum' +import { IndividualOrCollective, WarmingType } from 'enum/profileType.enum' import { Ecogesture } from 'models' -import EcogestureService from './ecogesture.service' +import { ProfileEcogesture } from 'models/profileEcogesture.model' import mockClient from '../../tests/__mocks__/client' import { BoilerEcogesture, @@ -9,10 +11,8 @@ import { ecogesturesECSData, ecogesturesHeatingData, } from '../../tests/__mocks__/ecogesturesData.mock' -import { IndividualOrCollective, WarmingType } from 'enum/profileType.enum' import { mockProfileEcogesture } from '../../tests/__mocks__/profileEcogesture.mock' -import { ProfileEcogesture } from 'models/profileEcogesture.model' -import { EquipmentType } from 'enum/ecogesture.enum' +import EcogestureService from './ecogesture.service' describe('Ecogesture service', () => { const ecogestureService = new EcogestureService(mockClient) diff --git a/src/services/enedisMonthlyAnalysisData.service.spec.ts b/src/services/enedisMonthlyAnalysisData.service.spec.ts index 4ed0ea21611cb52bb2e89bdb503f12ebae1906e0..3a5f15f44a8073bea2069c245bc55eae6f91d0a1 100644 --- a/src/services/enedisMonthlyAnalysisData.service.spec.ts +++ b/src/services/enedisMonthlyAnalysisData.service.spec.ts @@ -1,14 +1,14 @@ import { QueryResult } from 'cozy-client' -import mockClient from '../../tests/__mocks__/client' -import EnedisMonthlyAnalysisDataService from './enedisMonthlyAnalysisData.service' import { EnedisMonthlyAnalysisData } from 'models/enedisMonthlyAnalysis' +import { MaxPowerEntity } from 'models/maxPower.model' +import mockClient from '../../tests/__mocks__/client' import { maxPowerData, mockDataLoadEnedisAnalysis, mockEnedisMonthlyAnalysis, mockEnedisMonthlyAnalysisArray, } from '../../tests/__mocks__/enedisMonthlyAnalysisData.mock' -import { MaxPowerEntity } from 'models/maxPower.model' +import EnedisMonthlyAnalysisDataService from './enedisMonthlyAnalysisData.service' describe('Enedis Monthly Analysis service', () => { const emas = new EnedisMonthlyAnalysisDataService(mockClient) diff --git a/src/services/exploration.service.spec.ts b/src/services/exploration.service.spec.ts index 8979264f297f885402919ef57978e1fc3a61f431..d6d1b092aa5e52e98f304c7a279a84eac882b547 100644 --- a/src/services/exploration.service.spec.ts +++ b/src/services/exploration.service.spec.ts @@ -1,19 +1,19 @@ import { QueryResult } from 'cozy-client' -import { UserExploration, ExplorationEntity, UserChallenge } from 'models' +import { UserExplorationState } from 'enum/userExploration.enum' +import { ExplorationEntity, UserChallenge, UserExploration } from 'models' +import mockClient from '../../tests/__mocks__/client' import { allExplorationEntities, explorationEntity, - UserExplorationUnlocked, - UserExplorationDone, - UserExplorationStarted, + userExplorationDone, + userExplorationStarted, + userExplorationUnlocked, } from '../../tests/__mocks__/explorationData.mock' -import mockClient from '../../tests/__mocks__/client' -import ExplorationService from './exploration.service' import { userChallengeExplo1OnGoing, userChallengeExplo2OnGoing, } from '../../tests/__mocks__/userChallengeData.mock' -import { UserExplorationState } from 'enum/userExploration.enum' +import ExplorationService from './exploration.service' describe('Exploration service', () => { const explorationService = new ExplorationService(mockClient) @@ -104,7 +104,7 @@ describe('Exploration service', () => { searchId ) const updatedUserExploration = { - ...UserExplorationUnlocked, + ...userExplorationUnlocked, date: result.date, } expect(result).toEqual(updatedUserExploration) @@ -113,17 +113,17 @@ describe('Exploration service', () => { describe('startUserExploration Method', () => { it('should return the started userExploration', async () => { const result = await explorationService.startUserExploration( - UserExplorationUnlocked + userExplorationUnlocked ) - expect(result).toEqual(UserExplorationStarted) + expect(result).toEqual(userExplorationStarted) }) }) describe('endUserExploration Method', () => { it('should return the finished userExploration', async () => { const result = explorationService.endUserExploration( - UserExplorationStarted + userExplorationStarted ) - expect(result).toEqual(UserExplorationDone) + expect(result).toEqual(userExplorationDone) }) }) describe('checkExploration Method', () => { diff --git a/src/services/exploration.service.ts b/src/services/exploration.service.ts index 40ddc77db05644fb4c019b09d13fa4275487a342..466dc382553606eaf85f62436abaf68067041d7d 100644 --- a/src/services/exploration.service.ts +++ b/src/services/exploration.service.ts @@ -1,4 +1,4 @@ -import { Client, QueryDefinition, QueryResult, Q } from 'cozy-client' +import { Client, Q, QueryDefinition, QueryResult } from 'cozy-client' import { EXPLORATION_DOCTYPE } from 'doctypes' import { UserChallengeUpdateFlag } from 'enum/userChallenge.enum' import { diff --git a/src/services/fluid.service.spec.ts b/src/services/fluid.service.spec.ts index f692d9c9a58fbf14104ec52c2ec2f986f4a1d00e..53fe0add5056faf5b87e9eb36e8afbce5d40bf2b 100644 --- a/src/services/fluid.service.spec.ts +++ b/src/services/fluid.service.spec.ts @@ -1,5 +1,6 @@ /* eslint-disable camelcase */ import { FluidState, FluidType } from 'enum/fluid.enum' +import { FluidSlugType } from 'enum/fluidSlug.enum' import { DateTime } from 'luxon' import { FluidStatus } from 'models' import { accountsData } from '../../tests/__mocks__/accountsData.mock' @@ -92,7 +93,7 @@ describe('Fluid service', () => { konnectorConfig: { name: 'Enedis', oauth: false, - slug: 'enedissgegrandlyon', + slug: FluidSlugType.ELECTRICITY, siteLink: 'https://mon-compte-client.enedis.fr/', activation: 'https://mon-compte-particulier.enedis.fr/donnees/', }, @@ -114,7 +115,7 @@ describe('Fluid service', () => { konnectorConfig: { name: 'Eau Publique du Grand Lyon', oauth: false, - slug: 'eglgrandlyon', + slug: FluidSlugType.WATER, siteLink: 'https://www.eaudugrandlyon.com/inscription.aspx#subc-now', activation: '', @@ -137,7 +138,7 @@ describe('Fluid service', () => { konnectorConfig: { name: 'GRDF', oauth: true, - slug: 'grdfgrandlyon', + slug: FluidSlugType.GAS, siteLink: 'https://monespace.grdf.fr/creation-particulier', activation: '', }, @@ -181,7 +182,7 @@ describe('Fluid service', () => { konnectorConfig: { name: 'Enedis', oauth: false, - slug: 'enedissgegrandlyon', + slug: FluidSlugType.ELECTRICITY, siteLink: 'https://mon-compte-client.enedis.fr/', activation: 'https://mon-compte-particulier.enedis.fr/donnees/', }, @@ -203,7 +204,7 @@ describe('Fluid service', () => { konnectorConfig: { name: 'Eau Publique du Grand Lyon', oauth: false, - slug: 'eglgrandlyon', + slug: FluidSlugType.WATER, siteLink: 'https://www.eaudugrandlyon.com/inscription.aspx#subc-now', activation: '', @@ -226,7 +227,7 @@ describe('Fluid service', () => { konnectorConfig: { name: 'GRDF', oauth: true, - slug: 'grdfgrandlyon', + slug: FluidSlugType.GAS, siteLink: 'https://monespace.grdf.fr/creation-particulier', activation: '', }, @@ -270,7 +271,7 @@ describe('Fluid service', () => { konnectorConfig: { name: 'Enedis', oauth: false, - slug: 'enedissgegrandlyon', + slug: FluidSlugType.ELECTRICITY, siteLink: 'https://mon-compte-client.enedis.fr/', activation: 'https://mon-compte-particulier.enedis.fr/donnees/', }, @@ -292,7 +293,7 @@ describe('Fluid service', () => { konnectorConfig: { name: 'Eau Publique du Grand Lyon', oauth: false, - slug: 'eglgrandlyon', + slug: FluidSlugType.WATER, siteLink: 'https://www.eaudugrandlyon.com/inscription.aspx#subc-now', activation: '', @@ -315,7 +316,7 @@ describe('Fluid service', () => { konnectorConfig: { name: 'GRDF', oauth: true, - slug: 'grdfgrandlyon', + slug: FluidSlugType.GAS, siteLink: 'https://monespace.grdf.fr/creation-particulier', activation: '', }, @@ -359,7 +360,7 @@ describe('Fluid service', () => { konnectorConfig: { name: 'Enedis', oauth: false, - slug: 'enedissgegrandlyon', + slug: FluidSlugType.ELECTRICITY, siteLink: 'https://mon-compte-client.enedis.fr/', activation: 'https://mon-compte-particulier.enedis.fr/donnees/', }, @@ -381,7 +382,7 @@ describe('Fluid service', () => { konnectorConfig: { name: 'Eau Publique du Grand Lyon', oauth: false, - slug: 'eglgrandlyon', + slug: FluidSlugType.WATER, siteLink: 'https://www.eaudugrandlyon.com/inscription.aspx#subc-now', activation: '', @@ -404,7 +405,7 @@ describe('Fluid service', () => { konnectorConfig: { name: 'GRDF', oauth: true, - slug: 'grdfgrandlyon', + slug: FluidSlugType.GAS, siteLink: 'https://monespace.grdf.fr/creation-particulier', activation: '', }, @@ -449,7 +450,7 @@ describe('Fluid service', () => { konnectorConfig: { name: 'Enedis', oauth: false, - slug: 'enedissgegrandlyon', + slug: FluidSlugType.ELECTRICITY, siteLink: 'https://mon-compte-client.enedis.fr/', activation: 'https://mon-compte-particulier.enedis.fr/donnees/', }, @@ -471,7 +472,7 @@ describe('Fluid service', () => { konnectorConfig: { name: 'Eau Publique du Grand Lyon', oauth: false, - slug: 'eglgrandlyon', + slug: FluidSlugType.WATER, siteLink: 'https://www.eaudugrandlyon.com/inscription.aspx#subc-now', activation: '', @@ -494,7 +495,7 @@ describe('Fluid service', () => { konnectorConfig: { name: 'GRDF', oauth: true, - slug: 'grdfgrandlyon', + slug: FluidSlugType.GAS, siteLink: 'https://monespace.grdf.fr/creation-particulier', activation: '', }, @@ -544,6 +545,7 @@ describe('Fluid service', () => { { fluidType: FluidType.ELECTRICITY, status: FluidState.DONE, + maintenance: false, firstDataDate: DateTime.fromISO('2019-01-01').setZone('utc', { keepLocalTime: true, }), @@ -560,7 +562,7 @@ describe('Fluid service', () => { konnectorConfig: { name: 'Enedis', oauth: false, - slug: 'enedissgegrandlyon', + slug: FluidSlugType.ELECTRICITY, siteLink: 'https://mon-compte-client.enedis.fr/', activation: 'https://mon-compte-particulier.enedis.fr/donnees/', }, @@ -578,6 +580,7 @@ describe('Fluid service', () => { { fluidType: FluidType.ELECTRICITY, status: FluidState.DONE, + maintenance: false, firstDataDate: DateTime.local().minus({ day: 31 }).setZone('utc', { keepLocalTime: true, }), @@ -594,7 +597,7 @@ describe('Fluid service', () => { konnectorConfig: { name: 'Enedis', oauth: false, - slug: 'enedissgegrandlyon', + slug: FluidSlugType.ELECTRICITY, siteLink: 'https://mon-compte-client.enedis.fr/', activation: 'https://mon-compte-particulier.enedis.fr/donnees/', }, @@ -612,6 +615,7 @@ describe('Fluid service', () => { { fluidType: FluidType.ELECTRICITY, status: FluidState.NOT_CONNECTED, + maintenance: false, firstDataDate: DateTime.fromISO('2019-01-01').setZone('utc', { keepLocalTime: true, }), @@ -628,7 +632,7 @@ describe('Fluid service', () => { konnectorConfig: { name: 'Enedis', oauth: false, - slug: 'enedissgegrandlyon', + slug: FluidSlugType.ELECTRICITY, siteLink: 'https://mon-compte-client.enedis.fr/', activation: 'https://mon-compte-particulier.enedis.fr/donnees/', }, @@ -646,6 +650,7 @@ describe('Fluid service', () => { { fluidType: FluidType.ELECTRICITY, status: FluidState.KONNECTOR_NOT_FOUND, + maintenance: false, firstDataDate: DateTime.fromISO('2019-01-01').setZone('utc', { keepLocalTime: true, }), @@ -662,7 +667,7 @@ describe('Fluid service', () => { konnectorConfig: { name: 'Enedis', oauth: false, - slug: 'enedissgegrandlyon', + slug: FluidSlugType.ELECTRICITY, siteLink: 'https://mon-compte-client.enedis.fr/', activation: 'https://mon-compte-particulier.enedis.fr/donnees/', }, diff --git a/src/services/fluid.service.ts b/src/services/fluid.service.ts index 8376c496b1a48efa960b4f62241560c9c3b0a320..3de8f5c45b2851602969df86e00dca3571419be4 100644 --- a/src/services/fluid.service.ts +++ b/src/services/fluid.service.ts @@ -112,6 +112,7 @@ export default class FluidService { FluidType.WATER, FluidType.GAS, ]) + const result: FluidStatus[] = [ { fluidType: FluidType.ELECTRICITY, @@ -180,7 +181,7 @@ export default class FluidService { if (fluidStatus.length > 0) { for (const fluid of fluidStatus) { let diffInDays = 0 - if (fluid && fluid.lastDataDate) { + if (fluid?.lastDataDate) { const dateToCompare = fluid.lastDataDate diffInDays = dateToCompare.diffNow('days').toObject().days || 0 if ( diff --git a/src/services/fluidConfig.service.ts b/src/services/fluidConfig.service.ts index b6aae3539923e43031c0aed00555ccef4c1a6324..5341c940e9b26c2afb339c9d881708635439283d 100644 --- a/src/services/fluidConfig.service.ts +++ b/src/services/fluidConfig.service.ts @@ -3,7 +3,7 @@ import { FluidConfig } from 'models' export default class ConfigService { public getFluidConfig(): FluidConfig[] { - return Config.fluidConfig + return Config.fluidConfig as FluidConfig[] } /** diff --git a/src/services/fluidsPrices.service.spec.ts b/src/services/fluidsPrices.service.spec.ts index e3c1c5f785fbb153906512a02166584a9a65613b..f83929e3bd6e2636351cb916845d7734d5ba316d 100644 --- a/src/services/fluidsPrices.service.spec.ts +++ b/src/services/fluidsPrices.service.spec.ts @@ -1,13 +1,13 @@ -import FluidPricesService from './fluidsPrices.service' -import mockClient from '../../tests/__mocks__/client' import { QueryResult } from 'cozy-client' +import { FluidType } from 'enum/fluid.enum' +import { DateTime } from 'luxon' import { FluidPrice } from 'models' +import mockClient from '../../tests/__mocks__/client' import { - fluidPrices, allLastFluidPrices, + fluidPrices, } from '../../tests/__mocks__/fluidPrice.mock' -import { FluidType } from 'enum/fluid.enum' -import { DateTime } from 'luxon' +import FluidPricesService from './fluidsPrices.service' describe('FluidPrices service', () => { const fluidPricesService = new FluidPricesService(mockClient) diff --git a/src/services/fluidsPrices.service.ts b/src/services/fluidsPrices.service.ts index 39ac3bf3469841cbef873209ff80e67d88869bc3..acbaf74193adc63ab60866e89986231ab7a5dd81 100644 --- a/src/services/fluidsPrices.service.ts +++ b/src/services/fluidsPrices.service.ts @@ -1,7 +1,7 @@ import * as Sentry from '@sentry/react' import { Client, Q, QueryDefinition, QueryResult } from 'cozy-client' import logger from 'cozy-logger' -import { FLUIDPRICES_DOCTYPE } from 'doctypes' +import { FLUIDSPRICES_DOCTYPE } from 'doctypes' import { FluidType } from 'enum/fluid.enum' import { DateTime } from 'luxon' import { FluidPrice } from 'models' @@ -22,7 +22,7 @@ export default class FluidPricesService { * @returns {FluidPrice[]} */ public async getAllPrices(): Promise<FluidPrice[]> { - const query: QueryDefinition = Q(FLUIDPRICES_DOCTYPE).limitBy(900) + const query: QueryDefinition = Q(FLUIDSPRICES_DOCTYPE).limitBy(900) // TODO : handle case of 1000+ entries in doctype const { data: fluidsPrices }: QueryResult<FluidPrice[]> = await this._client.query(query) @@ -39,7 +39,7 @@ export default class FluidPricesService { fluidType: FluidType, date: DateTime ): Promise<FluidPrice> { - const query: QueryDefinition = Q(FLUIDPRICES_DOCTYPE) + const query: QueryDefinition = Q(FLUIDSPRICES_DOCTYPE) .indexFields(['startDate']) .where({ startDate: { @@ -60,9 +60,9 @@ export default class FluidPricesService { * @returns {FluidPrice[]} */ public async getAllLastPrices(): Promise<FluidPrice[]> { - const query: QueryDefinition = Q(FLUIDPRICES_DOCTYPE) + const query: QueryDefinition = Q(FLUIDSPRICES_DOCTYPE) .indexFields(['fluidType']) - .where({ endDate: { $eq: null } }) + .where({ endDate: { $eq: '' } }) .sortBy([{ fluidType: 'asc' }]) .limitBy(3) @@ -126,7 +126,7 @@ export default class FluidPricesService { public async checkIfPriceExists( fluidPrice: FluidPrice ): Promise<FluidPrice | null> { - const query: QueryDefinition = Q(FLUIDPRICES_DOCTYPE).where({ + const query: QueryDefinition = Q(FLUIDSPRICES_DOCTYPE).where({ startDate: { $eq: fluidPrice.startDate }, fluidType: { $eq: fluidPrice.fluidType }, }) @@ -145,7 +145,7 @@ export default class FluidPricesService { public async createPrice(newPrice: FluidPrice): Promise<FluidPrice | null> { try { const { data: createdPrice }: QueryResult<FluidPrice> = - await this._client.create(FLUIDPRICES_DOCTYPE, newPrice) + await this._client.create(FLUIDSPRICES_DOCTYPE, newPrice) return createdPrice } catch (error) { const errorMessage = `'Error creating new createdPrice: ${JSON.stringify( diff --git a/src/services/initialization.service.spec.ts b/src/services/initialization.service.spec.ts index 74f7a6074e297b50f47d3d79084e1a5bf8ec3b47..3a140471d5d9868f0d2117875e52f6e4c509c54d 100644 --- a/src/services/initialization.service.spec.ts +++ b/src/services/initialization.service.spec.ts @@ -1,20 +1,17 @@ import { QueryResult } from 'cozy-client' -import { DateTime } from 'luxon' -import { UserChallenge } from 'models' -import mockClient from '../../tests/__mocks__/client' -import InitializationService from './initialization.service' - import challengeEntityData from 'db/challengeEntity.json' import duelEntityData from 'db/duelEntity.json' import ecogestureData from 'db/ecogestureData.json' import explorationEntityData from 'db/explorationEntity.json' import quizEntityData from 'db/quizEntity.json' - import { FluidType } from 'enum/fluid.enum' +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__/datachartData.mock' +import { graphData } from '../../tests/__mocks__/chartData.mock' +import mockClient from '../../tests/__mocks__/client' import { allDuelEntity } from '../../tests/__mocks__/duelData.mock' import { ecogesturesData } from '../../tests/__mocks__/ecogesturesData.mock' import { allExplorationEntities } from '../../tests/__mocks__/explorationData.mock' @@ -27,6 +24,7 @@ import { mockUpToDateTerm, } from '../../tests/__mocks__/termsData.mock' import { userChallengeData } from '../../tests/__mocks__/userChallengeData.mock' +import InitializationService from './initialization.service' const mockCreateIndexKonnector = jest.fn() jest.mock('./konnector.service', () => { diff --git a/src/services/initialization.service.ts b/src/services/initialization.service.ts index fa41bf5e1a84297dd4ae7b5492760d6463d14f26..9e4b809185ff9f9843e6a2236dbc67c2062248fa 100644 --- a/src/services/initialization.service.ts +++ b/src/services/initialization.service.ts @@ -589,7 +589,7 @@ export default class InitializationService { ) return { monthlyAnalysisDate: actualAnalysisDate, - haveSeenLastAnalysis: profile.isFirstConnection ? true : false, + haveSeenLastAnalysis: profile.isFirstConnection, } } } catch (error) { diff --git a/src/services/konnector.service.spec.ts b/src/services/konnector.service.spec.ts index 2e72db7c9615093a8c421e29dca55f409462391e..844fa0748a3415d23276f0b56e0fb98d804414e3 100644 --- a/src/services/konnector.service.spec.ts +++ b/src/services/konnector.service.spec.ts @@ -1,11 +1,11 @@ -import KonnectorService from './konnector.service' +import { QueryResult } from 'cozy-client' import { Konnector } from 'models' -import mockClient from '../../tests/__mocks__/client' 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 { QueryResult } from 'cozy-client' +import KonnectorService from './konnector.service' const mockGetTrigger = jest.fn() const mockFetchTriggerState = jest.fn() diff --git a/src/services/konnectorStatus.service.spec.ts b/src/services/konnectorStatus.service.spec.ts index aaf620ab3fb3be1e99f334783fc68e3869d8c233..2f4a8a7864398235aa82c6f92c4c67ed0c7fa4ba 100644 --- a/src/services/konnectorStatus.service.spec.ts +++ b/src/services/konnectorStatus.service.spec.ts @@ -1,6 +1,6 @@ -import KonnectorStatusService from './konnectorStatus.service' -import mockClient from '../../tests/__mocks__/client' import { accountsData } from '../../tests/__mocks__/accountsData.mock' +import mockClient from '../../tests/__mocks__/client' +import KonnectorStatusService from './konnectorStatus.service' const mockGetAccountByType = jest.fn() jest.mock('./account.service', () => { diff --git a/src/services/konnectorStatus.service.ts b/src/services/konnectorStatus.service.ts index 339db0b999eb4d0fe03ae8dba2b9f769e4b6103e..10addfe4a80f4664f740cfe8e5aa282f63fbe3d6 100644 --- a/src/services/konnectorStatus.service.ts +++ b/src/services/konnectorStatus.service.ts @@ -1,7 +1,7 @@ import { Client } from 'cozy-client' -import ConfigService from 'services/fluidConfig.service' -import AccountService from 'services/account.service' import { FluidType } from 'enum/fluid.enum' +import AccountService from 'services/account.service' +import ConfigService from 'services/fluidConfig.service' export default class KonnectorStatusService { private _client: Client diff --git a/src/services/mail.service.spec.ts b/src/services/mail.service.spec.ts index 68d4505667297b693c06819215dd06def1435204..b67f09c8fb724dec1a27fe63beea7360c2d33c2b 100644 --- a/src/services/mail.service.spec.ts +++ b/src/services/mail.service.spec.ts @@ -1,5 +1,5 @@ -import MailService from './mail.service' import mockClient from '../../tests/__mocks__/client' +import MailService from './mail.service' describe('Mail service', () => { const mailService = new MailService() diff --git a/src/services/performanceIndicator.service.ts b/src/services/performanceIndicator.service.ts index 59d7f2555464b772e65e62043c98ba7e7a3b6fec..c459f00c6e93103fc26a43dc64135654aef122e5 100644 --- a/src/services/performanceIndicator.service.ts +++ b/src/services/performanceIndicator.service.ts @@ -77,11 +77,11 @@ export default class PerformanceIndicatorService { } } - const agreggatedPerformanceIndicator: PerformanceIndicator = { + const aggregatedPerformanceIndicator: PerformanceIndicator = { value: currentValue, compareValue: compareValue, percentageVariation: currentValue / compareValue - 1, } - return agreggatedPerformanceIndicator + return aggregatedPerformanceIndicator } } diff --git a/src/services/profileEcogesture.service.spec.ts b/src/services/profileEcogesture.service.spec.ts index 75329f55e2394f0fca8c21f22d26357ab2805e41..5a6e2ee6037697cc373d593ed1f30549ddfff174 100644 --- a/src/services/profileEcogesture.service.spec.ts +++ b/src/services/profileEcogesture.service.spec.ts @@ -9,7 +9,7 @@ const profileEcogestureService = new ProfileEcogestureService(mockClient) describe('ProfileEcogesture service', () => { it('should get the Profile Ecogesture', async () => { - const mockQueryResult: QueryResult<ProfileEcogesture> = { + const mockQueryResult: QueryResult<[ProfileEcogesture]> = { data: [mockProfileEcogestureUpdated], bookmark: '', next: false, @@ -28,7 +28,7 @@ describe('ProfileEcogesture service', () => { EquipmentType.FREEZER, ], } - const mockQueryResult: QueryResult<ProfileEcogesture> = { + const mockQueryResult: QueryResult<[ProfileEcogesture]> = { data: [mockProfileEcogestureUpdated], bookmark: '', next: false, diff --git a/src/services/profileEcogesture.service.ts b/src/services/profileEcogesture.service.ts index 37d5b0e857a6149245455eb7050387d3a7cd73ec..d38c43f890206a452748f08727539dcef79de78d 100644 --- a/src/services/profileEcogesture.service.ts +++ b/src/services/profileEcogesture.service.ts @@ -1,4 +1,4 @@ -import { Client, QueryDefinition, QueryResult, Q } from 'cozy-client' +import { Client, Q, QueryDefinition, QueryResult } from 'cozy-client' import { PROFILEECOGESTURE_DOCTYPE } from 'doctypes' import { ProfileEcogesture } from 'models/profileEcogesture.model' diff --git a/src/services/profileType.service.spec.ts b/src/services/profileType.service.spec.ts index 01fbdce16b87e606f2121a3ca7d500b7b650f8b7..0d58b4f0a1a177ee0bbbd6ef1ff48aba844cdef2 100644 --- a/src/services/profileType.service.spec.ts +++ b/src/services/profileType.service.spec.ts @@ -40,7 +40,7 @@ import { import ProfileTypeService from './profileType.service' import ProfileTypeFormService from './profileTypeForm.service' -const wrongNumber = 99999 +const unknownStep = 99999 as ProfileTypeStepForm describe('ProfileType service', () => { const profileTypeService = new ProfileTypeService( mockProfileType, @@ -183,7 +183,7 @@ describe('ProfileType service', () => { }) }) describe('should get the monthly Forecast', () => { - // For month of january + // For month of January const profileTypeService1 = new ProfileTypeService( mockTestProfile1, mockClient, @@ -342,12 +342,12 @@ describe('ProfileType service', () => { false ) expect(nextStep).toEqual(ProfileTypeStepForm.END) - nextStep = profileTypeFormService.getNextFormStep(wrongNumber, false) + nextStep = profileTypeFormService.getNextFormStep(unknownStep, false) expect(nextStep).toEqual(ProfileTypeStepForm.HOUSING_TYPE) }) }) describe('getPreviousFormStep', () => { - it('should get the previus step in function of the current step', () => { + it('should get the previous step in function of the current step', () => { let previousStep = profileTypeFormService.getPreviousFormStep( ProfileTypeStepForm.AREA ) @@ -405,7 +405,7 @@ describe('ProfileType service', () => { ProfileTypeStepForm.COOKING_FLUID ) expect(previousStep).toEqual(ProfileTypeStepForm.HOT_WATER_EQUIPMENT) - previousStep = profileTypeFormService.getPreviousFormStep(wrongNumber) + previousStep = profileTypeFormService.getPreviousFormStep(unknownStep) expect(previousStep).toEqual(ProfileTypeStepForm.HOUSING_TYPE) }) }) @@ -475,7 +475,7 @@ describe('ProfileType service', () => { ProfileTypeStepForm.COOKING_FLUID ) expect(answers).toEqual(mockProfileTypeAnswers[15]) - answers = ProfileTypeFormService.getAnswerForStep(wrongNumber) + answers = ProfileTypeFormService.getAnswerForStep(unknownStep) expect(answers).toEqual(mockProfileTypeAnswers[16]) }) }) @@ -501,7 +501,7 @@ describe('ProfileType service', () => { const result = ProfileTypeService.checkConsistency(mockProfile) expect(result).toEqual(expectedResult) }) - it('should return consistent profile for appartment', () => { + it('should return consistent profile for apartment', () => { const mockProfile = mockProfileType1 jest .spyOn(DateTime, 'local') diff --git a/src/services/profileType.service.ts b/src/services/profileType.service.ts index 5dafc811a2b4aba27376f9452a1a9179ee3c7148..bcfa6b5cd2a9256eede572a262236d3a8e327978 100644 --- a/src/services/profileType.service.ts +++ b/src/services/profileType.service.ts @@ -85,15 +85,15 @@ export default class ProfileTypeService { // Apply corrections const correctionsNbWalls = - heatingData.adjustment_outisde_facing_walls[housingType] + heatingData.adjustment_outside_facing_walls[housingType] const correctionWalls: number = correctionsNbWalls[outsideFacingWalls] let correctionFloor: number let correctionInsulation: number let correctionFacilities: number - if (this.profileType.housingType === HousingType.APPARTMENT) { - correctionFloor = heatingData.adjustment_floor.appartment[floor] + if (this.profileType.housingType === HousingType.APARTMENT) { + correctionFloor = heatingData.adjustment_floor.apartment[floor] } else correctionFloor = 0 if ( @@ -373,7 +373,7 @@ export default class ProfileTypeService { * getDetailsMonthlyForecast * @param {FluidType} fluidType * @param {number} month - * @returns {numeber} DetailsMnthlyForecast + * @returns {number} DetailsMonthlyForecast */ public async getDetailsMonthlyForecast( fluidType: FluidType, @@ -394,7 +394,8 @@ export default class ProfileTypeService { ecsConsumption: this.profileType.heating === IndividualOrCollective.COLLECTIVE ? null - : fluidType === hotWaterFluid + : hotWaterFluid !== null && + (fluidType as number) === (hotWaterFluid as number) ? this.getMonthEcs(month) : null, cookingConsumption: diff --git a/src/services/profileTypeEntity.service.spec.ts b/src/services/profileTypeEntity.service.spec.ts index 110127eaa48130bed884946382ed498ad7e9c892..1fc0e9b6615d78e35e6ae087f6c0cd743dece966 100644 --- a/src/services/profileTypeEntity.service.spec.ts +++ b/src/services/profileTypeEntity.service.spec.ts @@ -1,8 +1,8 @@ -import ProfileTypeEntityService from './profileTypeEntity.service' import { QueryResult } from 'cozy-client' -import { profileTypeData } from '../../tests/__mocks__/profileType.mock' -import mockClient from '../../tests/__mocks__/client' import { ProfileType } from 'models' +import mockClient from '../../tests/__mocks__/client' +import { profileTypeData } from '../../tests/__mocks__/profileType.mock' +import ProfileTypeEntityService from './profileTypeEntity.service' describe('UserProfileTypeEntity service', () => { const pteService = new ProfileTypeEntityService(mockClient) diff --git a/src/services/profileTypeForm.service.ts b/src/services/profileTypeForm.service.ts index 1a4b3339529baf5a41c347c22a99f962ecc6bdb1..14e2bcd30ffeac698edfb303a551b2023e181f0b 100644 --- a/src/services/profileTypeForm.service.ts +++ b/src/services/profileTypeForm.service.ts @@ -4,6 +4,7 @@ import { ConstructionYear, Floor, HotWaterEquipment, + HotWaterFluid, HousingType, IndividualInsulationWork, IndividualOrCollective, @@ -199,6 +200,7 @@ export default class ProfileTypeFormService { WarmingType.GAS, WarmingType.WOOD, WarmingType.FUEL, + WarmingType.OTHER, ], } case ProfileTypeStepForm.INDIVIDUAL_INSULATION_WORK: @@ -241,7 +243,11 @@ export default class ProfileTypeFormService { return { type: ProfileTypeFormType.SINGLE_CHOICE, attribute: 'hotWaterFluid', - choices: [FluidType.ELECTRICITY, FluidType.GAS], + choices: [ + HotWaterFluid.ELECTRICITY, + HotWaterFluid.GAS, + HotWaterFluid.OTHER, + ], } case ProfileTypeStepForm.COOKING_FLUID: return { diff --git a/src/services/queryRunner.service.spec.ts b/src/services/queryRunner.service.spec.ts index 1df6754513965e79afd155b966282dc5889d0d6d..e820301be69aaf41cd3fadc60cf44df47dc2a2f9 100644 --- a/src/services/queryRunner.service.spec.ts +++ b/src/services/queryRunner.service.spec.ts @@ -11,6 +11,9 @@ import { loadMonthData } from '../../tests/__mocks__/loadMonthData.mock' import { loadYearData } from '../../tests/__mocks__/loadYearData.mock' import QueryRunner from './queryRunner.service' +const unknownTimeStep = 99 as TimeStep +const unknownFluidType = 99 as FluidType + describe('queryRunner service', () => { const queryRunner = new QueryRunner(mockClient) @@ -506,7 +509,7 @@ describe('queryRunner service', () => { expect(result).toEqual(expectedResult) }) - it('should return the day data of the water fluid and unkown time step', async () => { + it('should return the day data of the water fluid and unknown time step', async () => { const mockTimePeriod = { startDate: DateTime.fromISO('2020-11-01T00:00:00.000Z', { zone: 'utc', @@ -562,7 +565,7 @@ describe('queryRunner service', () => { mockClient.query.mockResolvedValue(mockQueryResult) const result: Dataload[] | null = await queryRunner.fetchFluidData( mockTimePeriod, - 99, + unknownTimeStep, FluidType.WATER ) expect(result).toEqual(expectedResult) @@ -783,7 +786,7 @@ describe('queryRunner service', () => { expect(result).toEqual(expectedResult) }) - it('should return the day data of the gas fluid and unkonwn time step', async () => { + it('should return the day data of the gas fluid and unknown time step', async () => { const mockTimePeriod = { startDate: DateTime.fromISO('2020-11-01T00:00:00.000Z', { zone: 'utc', @@ -839,7 +842,7 @@ describe('queryRunner service', () => { mockClient.query.mockResolvedValue(mockQueryResult) const result: Dataload[] | null = await queryRunner.fetchFluidData( mockTimePeriod, - 99, + unknownTimeStep, FluidType.GAS ) expect(result).toEqual(expectedResult) @@ -1091,7 +1094,7 @@ describe('queryRunner service', () => { const result: Dataload[] | null = await queryRunner.fetchFluidData( mockTimePeriod, TimeStep.DAY, - 99 + unknownFluidType ) expect(result).toBeNull() }) @@ -1107,7 +1110,7 @@ describe('queryRunner service', () => { } const result: Dataload[] | null = await queryRunner.fetchFluidData( mockTimePeriod, - 99, + unknownTimeStep, FluidType.ELECTRICITY ) expect(result).toBeNull() @@ -1235,7 +1238,11 @@ describe('queryRunner service', () => { }), } const result: number | Dataload | null = - await queryRunner.fetchFluidMaxData(mockTimePeriod, TimeStep.DAY, 99) + await queryRunner.fetchFluidMaxData( + mockTimePeriod, + TimeStep.DAY, + unknownFluidType + ) expect(result).toBeNull() }) @@ -1251,7 +1258,7 @@ describe('queryRunner service', () => { const result: number | Dataload | null = await queryRunner.fetchFluidMaxData( mockTimePeriod, - 99, + unknownTimeStep, FluidType.ELECTRICITY ) expect(result).toBeNull() @@ -1346,12 +1353,18 @@ describe('queryRunner service', () => { }) it('should return null when unknown fluid type', async () => { - const result = await queryRunner.getEntries(99, TimeStep.DAY) + const result = await queryRunner.getEntries( + unknownFluidType, + TimeStep.DAY + ) expect(result).toBeNull() }) it('should return null when unknown time step', async () => { - const result = await queryRunner.getEntries(FluidType.ELECTRICITY, 99) + const result = await queryRunner.getEntries( + FluidType.ELECTRICITY, + unknownTimeStep + ) expect(result).toBeNull() }) }) @@ -1373,13 +1386,13 @@ describe('queryRunner service', () => { skip: 0, } mockClient.query.mockResolvedValue(mockQueryResult) - const result: QueryResult<any> = await queryRunner.fetchFluidRawDoctype( + const result = await queryRunner.fetchFluidRawDoctype( mockTimePeriod, TimeStep.YEAR, FluidType.ELECTRICITY ) expect(result).toEqual(mockQueryResult) - expect(result.data.length).toEqual(3) + expect(result?.data.length).toEqual(3) }) }) }) diff --git a/src/services/queryRunner.service.ts b/src/services/queryRunner.service.ts index b9fffafffcfac6cdffe77a633b6b1baaa9a87991..6fa8128692d7b81e1c8f31e468c83f3a575140e3 100644 --- a/src/services/queryRunner.service.ts +++ b/src/services/queryRunner.service.ts @@ -354,7 +354,7 @@ export default class QueryRunner { timePeriod: TimePeriod, timeStep: TimeStep, fluidType: FluidType - ): Promise<QueryResult> { + ) { const query: QueryDefinition = this.buildListQuery( timeStep, timePeriod, @@ -392,10 +392,10 @@ export default class QueryRunner { lastDayOfPreviousMonthQuery ) return Math.max( - lastDayOfPreviousMonthResult && lastDayOfPreviousMonthResult.data[0] + lastDayOfPreviousMonthResult?.data[0] ? lastDayOfPreviousMonthResult.data[0].load : 0, - result && result.data[0] ? result.data[0].load : 0 + result?.data[0] ? result.data[0].load : 0 ) } if (result?.data) { @@ -406,9 +406,9 @@ export default class QueryRunner { ) const mappedResult = this.mapDataList(filteredResult, timeStep) if (withDate) { - return mappedResult && mappedResult[0] && mappedResult[0] + return mappedResult?.[0] } - return mappedResult && mappedResult[0] && mappedResult[0].value + return mappedResult?.[0]?.value } return null } diff --git a/src/services/quiz.service.spec.ts b/src/services/quiz.service.spec.ts index bbaa8a1a3fa6372c647b2921cf6c13313cebfc03..12462ae479373d9899a760e6ee3781f3ecdaea48 100644 --- a/src/services/quiz.service.spec.ts +++ b/src/services/quiz.service.spec.ts @@ -1,12 +1,26 @@ import { QueryResult } from 'cozy-client' +import { FluidType } from 'enum/fluid.enum' +import { TimeStep } from 'enum/timeStep.enum' import { - UserQuiz, - QuizEntity, - UserQuestion, + CustomQuestionType, + UserQuestionState, + UserQuizState, +} from 'enum/userQuiz.enum' +import { DateTime } from 'luxon' +import { + CustomQuestionEntity, QuestionEntity, + QuizEntity, UserCustomQuestion, - CustomQuestionEntity, + UserQuestion, + UserQuiz, } from 'models' +import { + fullMonthGraphData, + graphData, + graphMonthData, +} from '../../tests/__mocks__/chartData.mock' +import mockClient from '../../tests/__mocks__/client' import { allQuizEntities, customQuestionEntity, @@ -17,21 +31,7 @@ import { UserQuizReseted, UserQuizStarted, } from '../../tests/__mocks__/quizData.mock' -import mockClient from '../../tests/__mocks__/client' import QuizService from './quiz.service' -import { - CustomQuestionType, - UserQuestionState, - UserQuizState, -} from 'enum/userQuiz.enum' -import { TimeStep } from 'enum/timeStep.enum' -import { FluidType } from 'enum/fluid.enum' -import { DateTime } from 'luxon' -import { - fullMonthGraphData, - graphData, - graphMonthData, -} from '../../tests/__mocks__/datachartData.mock' const localSpy = jest.spyOn(DateTime, 'local') diff --git a/src/services/quiz.service.ts b/src/services/quiz.service.ts index ca0bb4cb5a4b2332a13ea7426ee0fc3ca468f28b..3dfc34ff58d4ab5055188992e0f0d43a683ffbdc 100644 --- a/src/services/quiz.service.ts +++ b/src/services/quiz.service.ts @@ -1,7 +1,13 @@ -import { Client, QueryDefinition, QueryResult, Q } from 'cozy-client' +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, + UserQuestionState, + UserQuizState, +} from 'enum/userQuiz.enum' +import { shuffle } from 'lodash' import { DateTime } from 'luxon' import { Answer, @@ -15,15 +21,9 @@ import { UserQuestion, UserQuiz, } from 'models' -import ConsumptionDataManager from './consumption.service' -import { - CustomQuestionType, - UserQuestionState, - UserQuizState, -} from 'enum/userQuiz.enum' -import { shuffle } from 'lodash' -import { formatNumberValues } from 'utils/utils' import logApp from 'utils/logger' +import { formatNumberValues } from 'utils/utils' +import ConsumptionDataManager from './consumption.service' export default class QuizService { private readonly _client: Client @@ -55,7 +55,7 @@ export default class QuizService { .where({ _id: quizId }) .limitBy(1) const { data }: QueryResult<QuizEntity[]> = await this._client.query(query) - return data && data[0] + return data?.[0] } /** @@ -458,7 +458,7 @@ export default class QuizService { limit.reached = true } - if (graphData && graphData.actualData) { + if (graphData?.actualData) { max = Math.max(...graphData.actualData.map(d => d.value)) } } while (max == -1 && graphData?.actualData && !limit.reached) @@ -519,7 +519,7 @@ export default class QuizService { !singleFluid ) let average = 0 - if (graphData && graphData.actualData) { + if (graphData?.actualData) { let total = 0 let length = 0 graphData.actualData.forEach(d => { @@ -650,12 +650,12 @@ export default class QuizService { const roll2: number[] = coefList.splice(index2, 1) const coef2: number = roll2[0] // Format answers - maxLoad = Math.round(maxLoad * 100) / 100 - const wrongAnswer1 = Math.round(maxLoad * coef1 * 100) / 100 - const wrongAnswer2 = Math.round(maxLoad * coef2 * 100) / 100 + const load = Math.round(maxLoad * 100) / 100 + const wrongAnswer1 = Math.round(load * coef1 * 100) / 100 + const wrongAnswer2 = Math.round(load * coef2 * 100) / 100 return [ { - answerLabel: `${formatNumberValues(maxLoad)} ${unit}`, + answerLabel: `${formatNumberValues(load)} ${unit}`, isTrue: true, }, { diff --git a/src/services/terms.service.spec.ts b/src/services/terms.service.spec.ts index 2e84053ab5f1cae8aae6e07e3aacee54de4f49e1..2d6e2768acae8a6e6ef1bb94b507b07b8ddade2f 100644 --- a/src/services/terms.service.spec.ts +++ b/src/services/terms.service.spec.ts @@ -8,7 +8,6 @@ import { mockTermsData, mockUpToDateTerm, } from '../../tests/__mocks__/termsData.mock' - import TermsService from './terms.service' const localSpy = jest.spyOn(DateTime, 'local') diff --git a/src/services/timePeriod.service.spec.ts b/src/services/timePeriod.service.spec.ts index 7cbc1450173a77ac70b91af551693721665c5f2f..58830ee8c6192b513333f8ab1bb1b4be91b6821b 100644 --- a/src/services/timePeriod.service.spec.ts +++ b/src/services/timePeriod.service.spec.ts @@ -1,13 +1,13 @@ -import TimePeriodService from './timePeriod.service' +import { FluidType } from 'enum/fluid.enum' import { TimeStep } from 'enum/timeStep.enum' import { DateTime } from 'luxon' import { TimePeriod } from 'models' -import { FluidType } from 'enum/fluid.enum' +import TimePeriodService from './timePeriod.service' const randomDate = DateTime.fromISO('2020-10-10T08:00:00.000Z', { zone: 'utc', }) -const unknowTimeStep = 999 +const unknownTimeStep = 999 as TimeStep describe('timePeriod service', () => { const timePeriodService = new TimePeriodService() describe('getTimePeriods method', () => { @@ -264,7 +264,7 @@ describe('timePeriod service', () => { }), } try { - timePeriodService.getComparisonTimePeriod(timePeriod, unknowTimeStep) + timePeriodService.getComparisonTimePeriod(timePeriod, unknownTimeStep) } catch (error) { expect(error).toEqual(new Error('TimeStep unknown')) } @@ -324,7 +324,10 @@ describe('timePeriod service', () => { }) it('should return an error because of unknown TimeStep', () => { try { - timePeriodService.getLastDayOfCompletePeriod(randomDate, unknowTimeStep) + timePeriodService.getLastDayOfCompletePeriod( + randomDate, + unknownTimeStep + ) } catch (error) { expect(error).toEqual(new Error('TimeStep unknown')) } @@ -384,7 +387,7 @@ describe('timePeriod service', () => { }) it('should return the date of the last day of current period', () => { try { - timePeriodService.getLastDayOfTimePeriod(randomDate, unknowTimeStep) + timePeriodService.getLastDayOfTimePeriod(randomDate, unknownTimeStep) } catch (error) { expect(error).toEqual(new Error('TimeStep unknown')) } @@ -446,7 +449,7 @@ describe('timePeriod service', () => { try { timePeriodService.getStartDateFromEndDateByTimeStep( randomDate, - unknowTimeStep + unknownTimeStep ) } catch (error) { expect(error).toEqual(new Error('TimeStep unknown')) diff --git a/src/services/timePeriod.service.ts b/src/services/timePeriod.service.ts index 4765a787c91f353db6d955bbbcbb7e4cf470389f..655f8b7538644022c0b213c692545ebe65583cd4 100644 --- a/src/services/timePeriod.service.ts +++ b/src/services/timePeriod.service.ts @@ -1,6 +1,6 @@ -import { DateTime } from 'luxon' import { FluidType } from 'enum/fluid.enum' import { TimeStep } from 'enum/timeStep.enum' +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 549f87c6f458230066fad718c225b89e13de259a..f4aabb01a55ccf0a6202d7b4b3a1bdb7b092d032 100644 --- a/src/services/triggers.service.spec.ts +++ b/src/services/triggers.service.spec.ts @@ -1,11 +1,11 @@ import { QueryResult } from 'cozy-client' import { Trigger, TriggerState } from 'models' -import mockClient from '../../tests/__mocks__/client' -import TriggerService from './triggers.service' 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 TriggerService from './triggers.service' const mockCreateTrigger = jest.fn() jest.mock('cozy-harvest-lib/dist/connections/triggers', () => { diff --git a/src/services/usageEvent.service.spec.ts b/src/services/usageEvent.service.spec.ts index 050435264382bd11622e9062e7184acd64272a03..5fcc3a4cca66ce4650372b9475779ec0a8373b4c 100644 --- a/src/services/usageEvent.service.spec.ts +++ b/src/services/usageEvent.service.spec.ts @@ -1,8 +1,8 @@ +import { QueryResult } from 'cozy-client' +import { UsageEventType } from 'enum/usageEvent.enum' import { DateTime } from 'luxon' -import mockClient from '../../tests/__mocks__/client' -import UsageEventService from './usageEvent.service' import { AddEventParams, UsageEventEntity } from 'models' -import { QueryResult } from 'cozy-client' +import mockClient from '../../tests/__mocks__/client' import { allUsageEventsData, connectionAttemptEGLError, @@ -12,7 +12,7 @@ import { usageEventData, usageEventEntityData, } from '../../tests/__mocks__/usageEventsData.mock' -import { UsageEventType } from 'enum/usageEvent.enum' +import UsageEventService from './usageEvent.service' const localSpy = jest.spyOn(DateTime, 'local') diff --git a/src/store/challenge/challenge.action.spec.ts b/src/store/challenge/challenge.action.spec.ts index 3a5819e39fdb79383cdb6e58350daa85ff7b085a..66bc6f0e6009b3cb8793e0358543e9432b7f2328 100644 --- a/src/store/challenge/challenge.action.spec.ts +++ b/src/store/challenge/challenge.action.spec.ts @@ -1,14 +1,14 @@ +import { userChallengeData } from '../../../tests/__mocks__/userChallengeData.mock' import { + setChallengeConsumption, + setUserChallengeList, + SET_CHALLENGE_CONSUMPTION, SET_USER_CHALLENGE_LIST, - UPDATE_USER_CHALLENGE_LIST, + unlockNextUserChallenge, UNLOCK_NEXT_USER_CHALLENGE, - SET_CHALLENGE_CONSUMPTION, - setUserChallengeList, updateUserChallengeList, - unlockNextUserChallenge, - setChallengeConsumption, + UPDATE_USER_CHALLENGE_LIST, } from './challenge.actions' -import { userChallengeData } from '../../../tests/__mocks__/userChallengeData.mock' describe('challenge actions', () => { it('should create an action to set userChallengeList', () => { diff --git a/src/store/challenge/challenge.actions.ts b/src/store/challenge/challenge.actions.ts index a685f415500e36444281374b20cffb3ffefaf819..03ab3e29d5de88293b56567af01eefced45b3729 100644 --- a/src/store/challenge/challenge.actions.ts +++ b/src/store/challenge/challenge.actions.ts @@ -1,4 +1,5 @@ import { Dataload, UserChallenge } from 'models' +import { defaultAction } from 'store' export const SET_USER_CHALLENGE_LIST = 'SET_USER_CHALLENGE_LIST' export const UPDATE_USER_CHALLENGE_LIST = 'UPDATE_USER_CHALLENGE_LIST' @@ -30,6 +31,7 @@ export type ChallengeActionTypes = | UpdateUserChallengeList | UnlockNextUserChallenge | SetChallengeConsumption + | typeof defaultAction export function setUserChallengeList( userChallengeList: UserChallenge[] diff --git a/src/store/challenge/challenge.reducer.spec.ts b/src/store/challenge/challenge.reducer.spec.ts index 53959e6004d6ce511875f8f14688678e4859e696..f2ea8117f83c58af7190224ee047e35d8215f1c6 100644 --- a/src/store/challenge/challenge.reducer.spec.ts +++ b/src/store/challenge/challenge.reducer.spec.ts @@ -1,28 +1,29 @@ -import { challengeReducer } from './challenge.reducer' -import { - SET_USER_CHALLENGE_LIST, - UPDATE_USER_CHALLENGE_LIST, - UNLOCK_NEXT_USER_CHALLENGE, - SET_CHALLENGE_CONSUMPTION, -} from './challenge.actions' -import { Dataload, ChallengeState, UserChallenge } from 'models' +import { DataloadState } from 'enum/dataload.enum' import { UserChallengeState } from 'enum/userChallenge.enum' +import { DateTime } from 'luxon' +import { ChallengeState, Dataload, UserChallenge } from 'models' +import { defaultAction } from 'store' +import { mockInitialChallengeState } from '../../../tests/__mocks__/store' import { userChallengeData, userChallengeDefault, } from '../../../tests/__mocks__/userChallengeData.mock' -import { DateTime } from 'luxon' -import { mockInitialChallengeState } from '../../../tests/__mocks__/store' +import { + SET_CHALLENGE_CONSUMPTION, + SET_USER_CHALLENGE_LIST, + UNLOCK_NEXT_USER_CHALLENGE, + UPDATE_USER_CHALLENGE_LIST, +} from './challenge.actions' +import { challengeReducer } from './challenge.reducer' describe('challenge reducer', () => { it('should return the initial state', () => { - // eslint-disable-next-line @typescript-eslint/no-explicit-any - const result = challengeReducer(undefined as any, { type: 'default' }) - expect(result).toEqual(mockInitialChallengeState) + const state = challengeReducer(undefined, { ...defaultAction }) + expect(state).toEqual(mockInitialChallengeState) }) it('should handle SET_USER_CHALLENGE_LIST with payload', () => { - const result = challengeReducer(mockInitialChallengeState, { + const state = challengeReducer(mockInitialChallengeState, { type: SET_USER_CHALLENGE_LIST, payload: userChallengeData, }) @@ -31,14 +32,14 @@ describe('challenge reducer', () => { currentChallenge: userChallengeData[2], currentDataload: [], } - expect(result).toEqual(expectedResult) + expect(state).toEqual(expectedResult) }) it('should handle SET_USER_CHALLENGE_LIST without payload', () => { - const result = challengeReducer(mockInitialChallengeState, { + const state = challengeReducer(mockInitialChallengeState, { type: SET_USER_CHALLENGE_LIST, }) - expect(result).toEqual(mockInitialChallengeState) + expect(state).toEqual(mockInitialChallengeState) }) it('should handle UPDATE_USER_CHALLENGE_LIST with payload', () => { @@ -50,7 +51,7 @@ describe('challenge reducer', () => { ...userChallengeDefault[0], state: UserChallengeState.ONGOING, } - const result = challengeReducer(updatedMockInitialChallengeState, { + const state = challengeReducer(updatedMockInitialChallengeState, { type: UPDATE_USER_CHALLENGE_LIST, payload: updatedUserChallenge, }) @@ -62,14 +63,14 @@ describe('challenge reducer', () => { currentChallenge: updatedUserChallenge, currentDataload: [], } - expect(result).toEqual(expectedResult) + expect(state).toEqual(expectedResult) }) it('should handle UPDATE_USER_CHALLENGE_LIST without payload', () => { - const result = challengeReducer(mockInitialChallengeState, { + const state = challengeReducer(mockInitialChallengeState, { type: UPDATE_USER_CHALLENGE_LIST, }) - expect(result).toEqual(mockInitialChallengeState) + expect(state).toEqual(mockInitialChallengeState) }) it('should handle UNLOCK_NEXT_USER_CHALLENGE with payload', () => { @@ -85,7 +86,7 @@ describe('challenge reducer', () => { ...userChallengeDefault[1], state: UserChallengeState.UNLOCKED, } - const result = challengeReducer(updatedMockInitialChallengeState, { + const state = challengeReducer(updatedMockInitialChallengeState, { type: UNLOCK_NEXT_USER_CHALLENGE, payload: updatedUserChallenge, }) @@ -98,14 +99,14 @@ describe('challenge reducer', () => { currentChallenge: null, currentDataload: [], } - expect(result).toEqual(expectedResult) + expect(state).toEqual(expectedResult) }) it('should handle UNLOCK_NEXT_USER_CHALLENGE without payload', () => { - const result = challengeReducer(mockInitialChallengeState, { + const state = challengeReducer(mockInitialChallengeState, { type: UNLOCK_NEXT_USER_CHALLENGE, }) - expect(result).toEqual(mockInitialChallengeState) + expect(state).toEqual(mockInitialChallengeState) }) it('should handle SET_CHALLENGE_CONSUMPTION with payload', () => { @@ -119,7 +120,12 @@ describe('challenge reducer', () => { zone: 'utc', }), value: 20, - valueDetail: [5.0, 10.0, 5.0], + valueDetail: [ + { state: DataloadState.VALID, value: 5.0 }, + { state: DataloadState.VALID, value: 10.0 }, + { state: DataloadState.VALID, value: 5.0 }, + ], + state: DataloadState.VALID, }, ] const updatedUserChallenge: UserChallenge = { @@ -137,20 +143,20 @@ describe('challenge reducer', () => { currentChallenge: null, currentDataload: dataload, } - const result = challengeReducer(updatedMockInitialChallengeState, { + const state = challengeReducer(updatedMockInitialChallengeState, { type: SET_CHALLENGE_CONSUMPTION, payload: { userChallenge: updatedUserChallenge, currentDataload: dataload, }, }) - expect(result).toEqual(expectedResult) + expect(state).toEqual(expectedResult) }) it('should handle SET_CHALLENGE_CONSUMPTION without payload', () => { - const result = challengeReducer(mockInitialChallengeState, { + const state = challengeReducer(mockInitialChallengeState, { type: SET_CHALLENGE_CONSUMPTION, }) - expect(result).toEqual(mockInitialChallengeState) + expect(state).toEqual(mockInitialChallengeState) }) }) diff --git a/src/store/challenge/challenge.reducer.ts b/src/store/challenge/challenge.reducer.ts index 4a4ce3c02638700a4bde78e5cd29353716cda3cf..4d85c630a4d8a864f9fcd467884f624e1cc48e34 100644 --- a/src/store/challenge/challenge.reducer.ts +++ b/src/store/challenge/challenge.reducer.ts @@ -1,13 +1,13 @@ +import { UserChallengeState } from 'enum/userChallenge.enum' +import { ChallengeState } from 'models' import { Reducer } from 'redux' import { + ChallengeActionTypes, + SET_CHALLENGE_CONSUMPTION, SET_USER_CHALLENGE_LIST, - UPDATE_USER_CHALLENGE_LIST, UNLOCK_NEXT_USER_CHALLENGE, - SET_CHALLENGE_CONSUMPTION, - ChallengeActionTypes, + UPDATE_USER_CHALLENGE_LIST, } from './challenge.actions' -import { ChallengeState } from 'models' -import { UserChallengeState } from 'enum/userChallenge.enum' const initialState: ChallengeState = { userChallengeList: [], @@ -15,95 +15,76 @@ const initialState: ChallengeState = { currentDataload: [], } -export const challengeReducer: Reducer<ChallengeState> = ( +export const challengeReducer: Reducer<ChallengeState, ChallengeActionTypes> = ( state = initialState, - action: ChallengeActionTypes -): ChallengeState => { + action +) => { + if (action.payload == undefined) return state + + const updateState = (updates: Partial<ChallengeState>): ChallengeState => ({ + ...state, + ...updates, + }) switch (action.type) { - case SET_USER_CHALLENGE_LIST: - if (action.payload !== undefined) { - const filteredCurrentChallenge = action.payload.filter( - challenge => - challenge.state === UserChallengeState.ONGOING || - challenge.state === UserChallengeState.DUEL - ) - const currentChallenge = filteredCurrentChallenge[0] - ? filteredCurrentChallenge[0] + case SET_USER_CHALLENGE_LIST: { + const filteredCurrentChallenge = action.payload.filter( + challenge => + challenge.state === UserChallengeState.ONGOING || + challenge.state === UserChallengeState.DUEL + ) + const currentChallenge = filteredCurrentChallenge[0] || null + return updateState({ + userChallengeList: action.payload, + currentChallenge: currentChallenge, + }) + } + + case UPDATE_USER_CHALLENGE_LIST: { + const id = action.payload.id + const currentChallenge = + action.payload.state === UserChallengeState.ONGOING || + action.payload.state === UserChallengeState.DUEL + ? action.payload : null - return { - ...state, - userChallengeList: action.payload, - currentChallenge: currentChallenge, + const updatedList = [...state.userChallengeList] + const findIndex = updatedList.findIndex(challenge => challenge.id === id) + updatedList[findIndex] = action.payload + return updateState({ + userChallengeList: updatedList, + currentChallenge: currentChallenge || state.currentChallenge, + }) + } + case UNLOCK_NEXT_USER_CHALLENGE: { + 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') { + updatedList[findIndex + 1] = { + ...updatedList[findIndex + 1], + state: UserChallengeState.UNLOCKED, } - } else { - return state } - case UPDATE_USER_CHALLENGE_LIST: - if (action.payload !== undefined) { - const id = action.payload.id - const currentChallenge = - action.payload.state === UserChallengeState.ONGOING || - action.payload.state === UserChallengeState.DUEL - ? action.payload - : null - const updatedList = [...state.userChallengeList] - const findIndex = updatedList.findIndex( - challenge => challenge.id === id - ) - updatedList[findIndex] = action.payload - return { - ...state, - userChallengeList: updatedList, - currentChallenge: currentChallenge - ? currentChallenge + return updateState({ + userChallengeList: updatedList, + currentChallenge: null, + }) + } + case SET_CHALLENGE_CONSUMPTION: { + const id = action.payload.userChallenge.id + const updatedList = [...state.userChallengeList] + const findIndex = updatedList.findIndex(challenge => challenge.id === id) + updatedList[findIndex] = action.payload.userChallenge + return updateState({ + userChallengeList: updatedList, + currentChallenge: + state.currentChallenge && + state.currentChallenge.id === action.payload.userChallenge.id + ? action.payload.userChallenge : state.currentChallenge, - } - } else { - return state - } - case UNLOCK_NEXT_USER_CHALLENGE: - if (action.payload !== undefined) { - 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') { - updatedList[findIndex + 1] = { - ...updatedList[findIndex + 1], - state: UserChallengeState.UNLOCKED, - } - } - return { - ...state, - userChallengeList: updatedList, - currentChallenge: null, - } - } else { - return state - } - case SET_CHALLENGE_CONSUMPTION: - if (action.payload !== undefined) { - const id = action.payload.userChallenge.id - const updatedList = [...state.userChallengeList] - const findIndex = updatedList.findIndex( - challenge => challenge.id === id - ) - updatedList[findIndex] = action.payload.userChallenge - return { - ...state, - userChallengeList: updatedList, - currentChallenge: - state.currentChallenge && - state.currentChallenge.id === action.payload.userChallenge.id - ? action.payload.userChallenge - : state.currentChallenge, - currentDataload: action.payload.currentDataload, - } - } else { - return state - } + currentDataload: action.payload.currentDataload, + }) + } default: return state } diff --git a/src/store/chart/chart.action.spec.ts b/src/store/chart/chart.action.spec.ts index 5a3815c37fa93c4374de8ec5a149cbc6bca97fd4..c7b1b47fa86d1b0eb653dc1aee7e519edfe8c18a 100644 --- a/src/store/chart/chart.action.spec.ts +++ b/src/store/chart/chart.action.spec.ts @@ -1,20 +1,20 @@ import { TimeStep } from 'enum/timeStep.enum' import { DateTime } from 'luxon' +import { graphData } from '../../../tests/__mocks__/chartData.mock' import { - SET_CURRENT_TIMESTEP, - SET_SELECTED_DATE, - SET_CURRENT_INDEX, - SET_CURRENT_DATACHART, - SET_LOADING, - setCurrentTimeStep, - setSelectedDate, - setCurrentIndex, setCurrentDatachart, setCurrentDatachartIndex, + setCurrentIndex, + setCurrentTimeStep, setLoading, + setSelectedDate, + SET_CURRENT_DATACHART, SET_CURRENT_DATACHART_INDEX, + SET_CURRENT_INDEX, + SET_CURRENT_TIMESTEP, + SET_LOADING, + SET_SELECTED_DATE, } from './chart.actions' -import { graphData } from '../../../tests/__mocks__/datachartData.mock' describe('chart actions', () => { it('should create an action to set selected date', () => { diff --git a/src/store/chart/chart.actions.ts b/src/store/chart/chart.actions.ts index 67a3932c5ae391210d6615756d0a9b254f70f484..0b65793885c3501cba3f123b5823042a1978eb6c 100644 --- a/src/store/chart/chart.actions.ts +++ b/src/store/chart/chart.actions.ts @@ -1,13 +1,14 @@ import { TimeStep } from 'enum/timeStep.enum' import { DateTime } from 'luxon' import { Datachart } from 'models' +import { defaultAction } from 'store' -export const SET_CURRENT_TIMESTEP = 'SET_CURRENT_TIMESTEP' -export const SET_SELECTED_DATE = 'SET_SELECTED_DATE' -export const SET_CURRENT_INDEX = 'SET_CURRENT_INDEX' export const SET_CURRENT_DATACHART = 'SET_CURRENT_DATACHART' export const SET_CURRENT_DATACHART_INDEX = 'SET_CURRENT_DATACHART_INDEX' +export const SET_CURRENT_INDEX = 'SET_CURRENT_INDEX' +export const SET_CURRENT_TIMESTEP = 'SET_CURRENT_TIMESTEP' export const SET_LOADING = 'SET_LOADING' +export const SET_SELECTED_DATE = 'SET_SELECTED_DATE' interface SetSelectedDate { type: typeof SET_SELECTED_DATE @@ -39,29 +40,21 @@ interface SetLoading { payload?: boolean } -export type ChartActionTypes = - | SetSelectedDate - | SetCurrentTimeStep - | SetCurrentIndex - | SetCurrentDataChart - | SetCurrentDataChartIndex - | SetLoading - -export function setSelectedDate(date: DateTime): ChartActionTypes { +export function setSelectedDate(date: DateTime): SetSelectedDate { return { type: SET_SELECTED_DATE, payload: date, } } -export function setCurrentTimeStep(timeStep: TimeStep): ChartActionTypes { +export function setCurrentTimeStep(timeStep: TimeStep): SetCurrentTimeStep { return { type: SET_CURRENT_TIMESTEP, payload: timeStep, } } -export function setCurrentIndex(currentIndex: number): ChartActionTypes { +export function setCurrentIndex(currentIndex: number): SetCurrentIndex { return { type: SET_CURRENT_INDEX, payload: currentIndex, @@ -70,7 +63,7 @@ export function setCurrentIndex(currentIndex: number): ChartActionTypes { export function setCurrentDatachart( currentDatachart: Datachart -): ChartActionTypes { +): SetCurrentDataChart { return { type: SET_CURRENT_DATACHART, payload: currentDatachart, @@ -79,16 +72,25 @@ export function setCurrentDatachart( export function setCurrentDatachartIndex( currentDatachartIndex: number -): ChartActionTypes { +): SetCurrentDataChartIndex { return { type: SET_CURRENT_DATACHART_INDEX, payload: currentDatachartIndex, } } -export function setLoading(isLoading: boolean): ChartActionTypes { +export function setLoading(isLoading: boolean): SetLoading { return { type: SET_LOADING, payload: isLoading, } } + +export type ChartActionTypes = + | SetSelectedDate + | SetCurrentTimeStep + | SetCurrentIndex + | SetCurrentDataChart + | SetCurrentDataChartIndex + | SetLoading + | typeof defaultAction diff --git a/src/store/chart/chart.reducer.spec.ts b/src/store/chart/chart.reducer.spec.ts index ff94b5340f401ba813c2cb636f177c61e352d9dd..1f167acb432198679abfce62e431d36101c2e147 100644 --- a/src/store/chart/chart.reducer.spec.ts +++ b/src/store/chart/chart.reducer.spec.ts @@ -1,135 +1,138 @@ -import { chartReducer } from './chart.reducer' +import { TimeStep } from 'enum/timeStep.enum' +import { DateTime } from 'luxon' +import { defaultAction } from 'store' +import { graphData } from '../../../tests/__mocks__/chartData.mock' +import { mockInitialChartState } from '../../../tests/__mocks__/store' import { - SET_CURRENT_TIMESTEP, - SET_SELECTED_DATE, - SET_CURRENT_INDEX, SET_CURRENT_DATACHART, SET_CURRENT_DATACHART_INDEX, + SET_CURRENT_INDEX, + SET_CURRENT_TIMESTEP, SET_LOADING, + SET_SELECTED_DATE, } from './chart.actions' -import { DateTime } from 'luxon' -import { TimeStep } from 'enum/timeStep.enum' -import { mockInitialChartState } from '../../../tests/__mocks__/store' -import { graphData } from '../../../tests/__mocks__/datachartData.mock' +import { chartReducer } from './chart.reducer' describe('chart reducer', () => { it('should return the initial state', () => { - // eslint-disable-next-line @typescript-eslint/no-explicit-any - const result = chartReducer(undefined as any, { type: 'default' }) - expect(result).toEqual(mockInitialChartState) - }) - - it('should handle SET_SELECTED_DATE with payload', () => { - const mockDate = DateTime.fromISO('2021-01-01T00:00:00.000Z', { - zone: 'utc', - }) - const result = chartReducer(mockInitialChartState, { - type: SET_SELECTED_DATE, - payload: mockDate, - }) - expect(result).toEqual({ - ...mockInitialChartState, - selectedDate: mockDate, - }) - }) - - it('should handle SET_SELECTED_DATE without payload', () => { - const result = chartReducer(mockInitialChartState, { - type: SET_SELECTED_DATE, - }) - expect(result).toEqual(mockInitialChartState) - }) - - it('should handle SET_CURRENT_TIMESTEP with payload', () => { - const result = chartReducer(mockInitialChartState, { - type: SET_CURRENT_TIMESTEP, - payload: TimeStep.MONTH, - }) - expect(result).toEqual({ - ...mockInitialChartState, - currentTimeStep: TimeStep.MONTH, - }) - }) - - it('should handle SET_CURRENT_TIMESTEP without payload', () => { - const result = chartReducer(mockInitialChartState, { - type: SET_CURRENT_TIMESTEP, - }) - expect(result).toEqual(mockInitialChartState) - }) - - it('should handle SET_CURRENT_INDEX with payload', () => { - const mockDate = DateTime.fromISO('2021-01-01T00:00:00.000Z', { - zone: 'utc', - }) - const result = chartReducer(mockInitialChartState, { - type: SET_CURRENT_INDEX, - payload: mockDate, - }) - expect(result).toEqual({ - ...mockInitialChartState, - currentIndex: mockDate, - }) - }) - - it('should handle SET_CURRENT_INDEX without payload', () => { - const result = chartReducer(mockInitialChartState, { - type: SET_CURRENT_INDEX, - }) - expect(result).toEqual(mockInitialChartState) + const state = chartReducer(undefined, { ...defaultAction }) + expect(state).toEqual(mockInitialChartState) }) - it('should handle SET_CURRENT_DATACHART with payload', () => { - const result = chartReducer(mockInitialChartState, { - type: SET_CURRENT_DATACHART, - payload: graphData, - }) - expect(result).toEqual({ - ...mockInitialChartState, - currentDatachart: graphData, + describe('SET_SELECTED_DATE', () => { + it('should handle SET_SELECTED_DATE with payload', () => { + const mockDate = DateTime.fromISO('2021-01-01T00:00:00.000Z', { + zone: 'utc', + }) + const state = chartReducer(mockInitialChartState, { + type: SET_SELECTED_DATE, + payload: mockDate, + }) + expect(state).toEqual({ + ...mockInitialChartState, + selectedDate: mockDate, + }) + }) + it('should handle SET_SELECTED_DATE without payload', () => { + const state = chartReducer(mockInitialChartState, { + type: SET_SELECTED_DATE, + }) + expect(state).toEqual(mockInitialChartState) }) }) - it('should handle SET_CURRENT_DATACHART without payload', () => { - const result = chartReducer(mockInitialChartState, { - type: SET_CURRENT_DATACHART, + describe('SET_CURRENT_TIMESTEP', () => { + it('should handle SET_CURRENT_TIMESTEP with payload', () => { + const state = chartReducer(mockInitialChartState, { + type: SET_CURRENT_TIMESTEP, + payload: TimeStep.MONTH, + }) + expect(state).toEqual({ + ...mockInitialChartState, + currentTimeStep: TimeStep.MONTH, + }) + }) + it('should handle SET_CURRENT_TIMESTEP without payload', () => { + const state = chartReducer(mockInitialChartState, { + type: SET_CURRENT_TIMESTEP, + }) + expect(state).toEqual(mockInitialChartState) }) - expect(result).toEqual(mockInitialChartState) }) - it('should handle SET_CURRENT_DATACHART_INDEX with payload', () => { - const result = chartReducer(mockInitialChartState, { - type: SET_CURRENT_DATACHART_INDEX, - payload: 1, - }) - expect(result).toEqual({ - ...mockInitialChartState, - currentDatachartIndex: 1, + describe('SET_CURRENT_INDEX', () => { + it('should handle SET_CURRENT_INDEX with payload', () => { + const state = chartReducer(mockInitialChartState, { + type: SET_CURRENT_INDEX, + payload: 1, + }) + expect(state).toEqual({ + ...mockInitialChartState, + currentIndex: 1, + }) + }) + it('should handle SET_CURRENT_INDEX without payload', () => { + const state = chartReducer(mockInitialChartState, { + type: SET_CURRENT_INDEX, + }) + expect(state).toEqual(mockInitialChartState) }) }) - it('should handle SET_CURRENT_DATACHART_INDEX without payload', () => { - const result = chartReducer(mockInitialChartState, { - type: SET_CURRENT_DATACHART_INDEX, + describe('SET_CURRENT_DATACHART', () => { + it('should handle SET_CURRENT_DATACHART with payload', () => { + const state = chartReducer(mockInitialChartState, { + type: SET_CURRENT_DATACHART, + payload: graphData, + }) + expect(state).toEqual({ + ...mockInitialChartState, + currentDatachart: graphData, + }) + }) + it('should handle SET_CURRENT_DATACHART without payload', () => { + const state = chartReducer(mockInitialChartState, { + type: SET_CURRENT_DATACHART, + }) + expect(state).toEqual(mockInitialChartState) }) - expect(result).toEqual(mockInitialChartState) }) - it('should handle SET_LOADING with payload', () => { - const result = chartReducer(mockInitialChartState, { - type: SET_LOADING, - payload: false, - }) - expect(result).toEqual({ - ...mockInitialChartState, - loading: false, + describe('SET_CURRENT_DATACHART_INDEX', () => { + it('should handle SET_CURRENT_DATACHART_INDEX with payload', () => { + const state = chartReducer(mockInitialChartState, { + type: SET_CURRENT_DATACHART_INDEX, + payload: 1, + }) + expect(state).toEqual({ + ...mockInitialChartState, + currentDatachartIndex: 1, + }) + }) + it('should handle SET_CURRENT_DATACHART_INDEX without payload', () => { + const state = chartReducer(mockInitialChartState, { + type: SET_CURRENT_DATACHART_INDEX, + }) + expect(state).toEqual(mockInitialChartState) }) }) - it('should handle SET_LOADING without payload', () => { - const result = chartReducer(mockInitialChartState, { - type: SET_LOADING, + describe('SET_LOADING', () => { + it('should handle SET_LOADING with payload', () => { + const state = chartReducer(mockInitialChartState, { + type: SET_LOADING, + payload: false, + }) + expect(state).toEqual({ + ...mockInitialChartState, + loading: false, + }) + }) + it('should handle SET_LOADING without payload', () => { + const state = chartReducer(mockInitialChartState, { + type: SET_LOADING, + }) + expect(state).toEqual(mockInitialChartState) }) - expect(result).toEqual(mockInitialChartState) }) }) diff --git a/src/store/chart/chart.reducer.ts b/src/store/chart/chart.reducer.ts index 51e15ffb123a7bff4ce1281e19950161ce68d4a5..9d79d2593a8b1830c45a3d16954b74313d4cde31 100644 --- a/src/store/chart/chart.reducer.ts +++ b/src/store/chart/chart.reducer.ts @@ -1,16 +1,16 @@ +import { TimeStep } from 'enum/timeStep.enum' +import { DateTime } from 'luxon' +import { ChartState } from 'models/chart.model' import { Reducer } from 'redux' import { - SET_SELECTED_DATE, - SET_CURRENT_TIMESTEP, - SET_CURRENT_INDEX, + ChartActionTypes, SET_CURRENT_DATACHART, SET_CURRENT_DATACHART_INDEX, + SET_CURRENT_INDEX, + SET_CURRENT_TIMESTEP, SET_LOADING, - ChartActionTypes, + SET_SELECTED_DATE, } from 'store/chart/chart.actions' -import { ChartState } from 'models/chart.model' -import { TimeStep } from 'enum/timeStep.enum' -import { DateTime } from 'luxon' const initialState: ChartState = { selectedDate: DateTime.local().endOf('minute').setZone('utc', { @@ -23,53 +23,36 @@ const initialState: ChartState = { loading: true, } -export const chartReducer: Reducer<ChartState> = ( +export const chartReducer: Reducer<ChartState, ChartActionTypes> = ( state = initialState, - action: ChartActionTypes -): ChartState => { + action +) => { + if (action.payload == undefined) return state + + const updateState = (updates: Partial<ChartState>): ChartState => ({ + ...state, + ...updates, + }) + switch (action.type) { case SET_SELECTED_DATE: - return action.payload != undefined - ? { - ...state, - selectedDate: action.payload, - } - : state + return updateState({ selectedDate: action.payload }) + case SET_CURRENT_TIMESTEP: - return action.payload != undefined - ? { - ...state, - currentTimeStep: action.payload, - } - : state + return updateState({ currentTimeStep: action.payload }) + case SET_CURRENT_INDEX: - return action.payload != undefined - ? { - ...state, - currentIndex: action.payload, - } - : state + return updateState({ currentIndex: action.payload }) + case SET_CURRENT_DATACHART: - return action.payload != undefined - ? { - ...state, - currentDatachart: action.payload, - } - : state + return updateState({ currentDatachart: action.payload }) + case SET_CURRENT_DATACHART_INDEX: - return action.payload != undefined - ? { - ...state, - currentDatachartIndex: action.payload, - } - : state + return updateState({ currentDatachartIndex: action.payload }) + case SET_LOADING: - return action.payload != undefined - ? { - ...state, - loading: action.payload, - } - : state + return updateState({ loading: action.payload }) + default: return state } diff --git a/src/store/global/global.action.spec.ts b/src/store/global/global.action.spec.ts index a06bc8a6698db1b24ef6e3958f8d64e02aaccd9b..2a75a86c38b9fc84f2a84591df9c2d6e738ac9a7 100644 --- a/src/store/global/global.action.spec.ts +++ b/src/store/global/global.action.spec.ts @@ -2,26 +2,27 @@ import { ScreenType } from 'enum/screen.enum' import { mockCustomPopup } from '../../../tests/__mocks__/customPopup.mock' import { mockInitialGlobalState } from '../../../tests/__mocks__/store' import { + changeScreenType, CHANGE_SCREEN_TYPE, - TOGGLE_CHALLENGE_EXPLORATION_NOTIFICATION, - TOGGLE_CHALLENGE_ACTION_NOTIFICATION, - TOGGLE_CHALLENGE_DUEL_NOTIFICATION, - TOGGLE_ANALYSIS_NOTIFICATION, + GlobalActionTypes, + setCustomPopup, + setFluidStatus, + SET_CUSTOM_POPUP, SET_FLUID_STATUS, - changeScreenType, - toggleChallengeExplorationNotification, + toggleAnalysisNotification, toggleChallengeActionNotification, toggleChallengeDuelNotification, - toggleAnalysisNotification, - setFluidStatus, - SET_CUSTOM_POPUP, - setCustomPopup, + toggleChallengeExplorationNotification, + TOGGLE_ANALYSIS_NOTIFICATION, + TOGGLE_CHALLENGE_ACTION_NOTIFICATION, + TOGGLE_CHALLENGE_DUEL_NOTIFICATION, + TOGGLE_CHALLENGE_EXPLORATION_NOTIFICATION, } from './global.actions' describe('global actions', () => { it('should create an action to change screenType', () => { const screenType = ScreenType.DESKTOP - const expectedAction = { + const expectedAction: GlobalActionTypes = { type: CHANGE_SCREEN_TYPE, payload: screenType, } @@ -30,7 +31,7 @@ describe('global actions', () => { it('should create an action to toggle challenge exploration notification', () => { const notification = true - const expectedAction = { + const expectedAction: GlobalActionTypes = { type: TOGGLE_CHALLENGE_EXPLORATION_NOTIFICATION, payload: notification, } @@ -41,7 +42,7 @@ describe('global actions', () => { it('should create an action to toggle challenge action notification', () => { const notification = true - const expectedAction = { + const expectedAction: GlobalActionTypes = { type: TOGGLE_CHALLENGE_ACTION_NOTIFICATION, payload: notification, } @@ -52,7 +53,7 @@ describe('global actions', () => { it('should create an action to toggle challenge duel notification', () => { const notification = true - const expectedAction = { + const expectedAction: GlobalActionTypes = { type: TOGGLE_CHALLENGE_DUEL_NOTIFICATION, payload: notification, } @@ -63,7 +64,7 @@ describe('global actions', () => { it('should create an action to toggle analysis notification', () => { const notification = true - const expectedAction = { + const expectedAction: GlobalActionTypes = { type: TOGGLE_ANALYSIS_NOTIFICATION, payload: notification, } @@ -72,7 +73,7 @@ describe('global actions', () => { it('should create an action to set fluid status', () => { const fluidStatus = mockInitialGlobalState.fluidStatus - const expectedAction = { + const expectedAction: GlobalActionTypes = { type: SET_FLUID_STATUS, payload: fluidStatus, } @@ -81,7 +82,7 @@ describe('global actions', () => { it('should set customPopup', () => { const payload = mockCustomPopup - const expectedAction = { + const expectedAction: GlobalActionTypes = { type: SET_CUSTOM_POPUP, payload, } diff --git a/src/store/global/global.actions.ts b/src/store/global/global.actions.ts index c8e6204f68d7a420afeddcd6a6fe31401163ad00..5abc17651f59e95b3e2fd815c80a18d934e6cdb6 100644 --- a/src/store/global/global.actions.ts +++ b/src/store/global/global.actions.ts @@ -2,46 +2,59 @@ import { FluidType } from 'enum/fluid.enum' import { ScreenType } from 'enum/screen.enum' import { FluidConnection, FluidStatus, TermsStatus } from 'models' import { CustomPopup } from 'models/customPopup.model' +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_CUSTOM_POPUP = 'SET_CUSTOM_POPUP' +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_CHALLENGE_EXPLORATION_NOTIFICATION = - 'TOGGLE_CHALLENGE_EXPLORATION_NOTIFICATION' +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_ANALYSIS_NOTIFICATION = 'TOGGLE_ANALYSIS_NOTIFICATION' -export const SET_FLUID_STATUS = 'SET_FLUID_STATUS' +export const TOGGLE_CHALLENGE_EXPLORATION_NOTIFICATION = + 'TOGGLE_CHALLENGE_EXPLORATION_NOTIFICATION' export const UPDATE_FLUID_CONNECTION = 'UPDATE_FLUID_CONNECTION' -export const UPDATE_TERMS_VALIDATION = 'UPDATE_TERMS_VALIDATION' -export const SET_PARTNERS_ISSUE = 'SET_PARTNERS_ISSUE' -export const SET_CUSTOM_POPUP = 'SET_CUSTOM_POPUP' -export const SET_SHOULD_REFRESH_CONSENT = 'SET_SHOULD_REFRESH_CONSENT' 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 ToogleChallengeExplorationNotification { +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 ToogleChallengeActionNotification { +interface ToggleChallengeActionNotification { type: typeof TOGGLE_CHALLENGE_ACTION_NOTIFICATION payload?: boolean } -interface ToogleChallengeDuelNotification { +interface ToggleChallengeDuelNotification { type: typeof TOGGLE_CHALLENGE_DUEL_NOTIFICATION payload?: boolean } -interface ToogleAnalysisNotification { +interface ToggleAnalysisNotification { type: typeof TOGGLE_ANALYSIS_NOTIFICATION payload?: boolean } @@ -65,16 +78,6 @@ interface ShowReleaseNotes { type: typeof SHOW_RELEASE_NOTES payload?: { show: boolean; notes: Notes[]; redirectLink?: string } } - -interface SetPartnersIssue { - type: typeof SET_PARTNERS_ISSUE - payload?: { - enedis: boolean - egl: boolean - grdf: boolean - } -} - interface SetCustomPopup { type: typeof SET_CUSTOM_POPUP payload: CustomPopup @@ -84,27 +87,12 @@ interface SetShouldRefreshConsent { type: typeof SET_SHOULD_REFRESH_CONSENT payload?: boolean } -export interface UpdateSGEConnect { +interface UpdateSGEConnect { type: typeof UPDATE_SGE_CONNECT payload?: SgeStore } -export type GlobalActionTypes = - | ChangeScreenType - | ToogleChallengeExplorationNotification - | ToogleChallengeActionNotification - | ToogleChallengeDuelNotification - | ToogleAnalysisNotification - | SetFluidStatus - | UpdatedFluidConnection - | UpdateTermValidation - | ShowReleaseNotes - | SetPartnersIssue - | SetCustomPopup - | SetShouldRefreshConsent - | UpdateSGEConnect - -export function changeScreenType(screenType: ScreenType): GlobalActionTypes { +export function changeScreenType(screenType: ScreenType): ChangeScreenType { return { type: CHANGE_SCREEN_TYPE, payload: screenType, @@ -115,7 +103,7 @@ export function showReleaseNotes( show: boolean, notes: Notes[], redirectLink?: string -): GlobalActionTypes { +): ShowReleaseNotes { return { type: SHOW_RELEASE_NOTES, payload: { show, notes, redirectLink }, @@ -123,40 +111,42 @@ export function showReleaseNotes( } export function toggleChallengeExplorationNotification( - notif: boolean -): GlobalActionTypes { + notification: boolean +): ToggleChallengeExplorationNotification { return { type: TOGGLE_CHALLENGE_EXPLORATION_NOTIFICATION, - payload: notif, + payload: notification, } } export function toggleChallengeActionNotification( - notif: boolean -): GlobalActionTypes { + notification: boolean +): ToggleChallengeActionNotification { return { type: TOGGLE_CHALLENGE_ACTION_NOTIFICATION, - payload: notif, + payload: notification, } } export function toggleChallengeDuelNotification( - notif: boolean -): GlobalActionTypes { + notification: boolean +): ToggleChallengeDuelNotification { return { type: TOGGLE_CHALLENGE_DUEL_NOTIFICATION, - payload: notif, + payload: notification, } } -export function toggleAnalysisNotification(notif: boolean): GlobalActionTypes { +export function toggleAnalysisNotification( + notification: boolean +): ToggleAnalysisNotification { return { type: TOGGLE_ANALYSIS_NOTIFICATION, - payload: notif, + payload: notification, } } -export function setFluidStatus(fluidStatus: FluidStatus[]): GlobalActionTypes { +export function setFluidStatus(fluidStatus: FluidStatus[]): SetFluidStatus { return { type: SET_FLUID_STATUS, payload: fluidStatus, @@ -165,7 +155,7 @@ export function setFluidStatus(fluidStatus: FluidStatus[]): GlobalActionTypes { export function updatedFluidConnection( fluidType: FluidType, fluidConnection: FluidConnection -): GlobalActionTypes { +): UpdatedFluidConnection { return { type: UPDATE_FLUID_CONNECTION, payload: { fluidType, fluidConnection }, @@ -174,27 +164,21 @@ export function updatedFluidConnection( export function updateTermValidation( termsStatus: TermsStatus -): GlobalActionTypes { +): UpdateTermValidation { return { type: UPDATE_TERMS_VALIDATION, payload: termsStatus, } } -export function setPartnersIssue(openPartnersIssueModal: { - enedis: boolean - egl: boolean - grdf: boolean -}): GlobalActionTypes { +export function setPartnersInfo(partnersInfo: PartnersInfo): SetPartnersInfo { return { - type: SET_PARTNERS_ISSUE, - payload: openPartnersIssueModal, + type: SET_PARTNERS_INFO, + payload: partnersInfo, } } -export function setCustomPopup( - customPopupModal: CustomPopup -): GlobalActionTypes { +export function setCustomPopup(customPopupModal: CustomPopup): SetCustomPopup { return { type: SET_CUSTOM_POPUP, payload: customPopupModal, @@ -203,16 +187,32 @@ export function setCustomPopup( export function setShouldRefreshConsent( shouldRefreshConsent: boolean -): GlobalActionTypes { +): SetShouldRefreshConsent { return { type: SET_SHOULD_REFRESH_CONSENT, payload: shouldRefreshConsent, } } -export function updateSgeStore(sgeStore: SgeStore): GlobalActionTypes { +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 + | SetCustomPopup + | SetShouldRefreshConsent + | UpdateSGEConnect + | SetPartnersInfo + | typeof defaultAction diff --git a/src/store/global/global.reducer.spec.ts b/src/store/global/global.reducer.spec.ts index b645aae9ec3b6dcd7eeefa54dc9cb3c78ab40bd4..accdd07d15c231ed76387f74970504f0c71447cb 100644 --- a/src/store/global/global.reducer.spec.ts +++ b/src/store/global/global.reducer.spec.ts @@ -3,6 +3,7 @@ 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 { mockCustomPopup } from '../../../tests/__mocks__/customPopup.mock' import { konnectorsData } from '../../../tests/__mocks__/konnectorsData.mock' @@ -19,112 +20,109 @@ import { } from './global.actions' import { globalReducer } from './global.reducer' -const mockDataDates: (DateTime | null)[] = [ - DateTime.local().setZone('utc', { - keepLocalTime: true, - }), - DateTime.local().setZone('utc', { - keepLocalTime: true, - }), - DateTime.local().setZone('utc', { - keepLocalTime: true, - }), -] +const nowUtc = DateTime.local().setZone('utc', { keepLocalTime: true }) +const mockDataDates = Array(3).fill(nowUtc) describe('global reducer', () => { it('should return the initial state', () => { - const result = globalReducer(undefined as any, { type: 'default' }) - expect(result).toEqual(mockInitialGlobalState) + const state = globalReducer(undefined, { ...defaultAction }) + expect(state).toEqual(mockInitialGlobalState) }) - it('should handle CHANGE_SCREEN_TYPE with payload', () => { - const result = globalReducer(mockInitialGlobalState, { - type: CHANGE_SCREEN_TYPE, - payload: ScreenType.DESKTOP, + 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) }) - expect(result).toEqual({ - ...mockInitialGlobalState, - screenType: ScreenType.DESKTOP, - }) - }) - - it('should handle CHANGE_SCREEN_TYPE without payload', () => { - const result = globalReducer(mockInitialGlobalState, { - type: CHANGE_SCREEN_TYPE, - }) - expect(result).toEqual(mockInitialGlobalState) }) - it('should handle TOGGLE_CHALLENGE_EXPLORATION_NOTIFICATION with payload', () => { - const result = globalReducer(mockInitialGlobalState, { - type: TOGGLE_CHALLENGE_EXPLORATION_NOTIFICATION, - payload: true, - }) - expect(result).toEqual({ - ...mockInitialGlobalState, - challengeExplorationNotification: true, + 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 result = globalReducer(mockInitialGlobalState, { - type: TOGGLE_CHALLENGE_EXPLORATION_NOTIFICATION, + it('should handle TOGGLE_CHALLENGE_EXPLORATION_NOTIFICATION without payload', () => { + const state = globalReducer(mockInitialGlobalState, { + type: TOGGLE_CHALLENGE_EXPLORATION_NOTIFICATION, + }) + expect(state).toEqual(mockInitialGlobalState) }) - expect(result).toEqual(mockInitialGlobalState) }) - it('should handle TOGGLE_CHALLENGE_ACTION_NOTIFICATION with payload', () => { - const result = globalReducer(mockInitialGlobalState, { - type: TOGGLE_CHALLENGE_ACTION_NOTIFICATION, - payload: true, - }) - expect(result).toEqual({ - ...mockInitialGlobalState, - challengeActionNotification: true, + 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) }) }) - it('should handle TOGGLE_CHALLENGE_ACTION_NOTIFICATION without payload', () => { - const result = globalReducer(mockInitialGlobalState, { - type: TOGGLE_CHALLENGE_ACTION_NOTIFICATION, - }) - expect(result).toEqual(mockInitialGlobalState) - }) - - it('should handle TOGGLE_CHALLENGE_DUEL_NOTIFICATION with payload', () => { - const result = globalReducer(mockInitialGlobalState, { - type: TOGGLE_CHALLENGE_DUEL_NOTIFICATION, - payload: true, - }) - expect(result).toEqual({ - ...mockInitialGlobalState, - challengeDuelNotification: true, - }) - }) - - it('should handle TOGGLE_CHALLENGE_DUEL_NOTIFICATION without payload', () => { - const result = globalReducer(mockInitialGlobalState, { - type: TOGGLE_CHALLENGE_DUEL_NOTIFICATION, - }) - expect(result).toEqual(mockInitialGlobalState) - }) - - it('should handle TOGGLE_ANALYSIS_NOTIFICATION with payload', () => { - const result = globalReducer(mockInitialGlobalState, { - type: TOGGLE_ANALYSIS_NOTIFICATION, - payload: true, - }) - expect(result).toEqual({ - ...mockInitialGlobalState, - analysisNotification: true, + 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) }) }) - it('should handle TOGGLE_ANALYSIS_NOTIFICATION without payload', () => { - const result = globalReducer(mockInitialGlobalState, { - type: TOGGLE_ANALYSIS_NOTIFICATION, + 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) }) - expect(result).toEqual(mockInitialGlobalState) }) it('should handle SET_FLUID_STATUS with payload', () => { @@ -197,11 +195,11 @@ describe('global reducer', () => { }, }, ] - const result = globalReducer(mockInitialGlobalState, { + const state = globalReducer(mockInitialGlobalState, { type: SET_FLUID_STATUS, payload: fluidStatus, }) - expect(result).toEqual({ + expect(state).toEqual({ ...mockInitialGlobalState, fluidStatus: fluidStatus, fluidTypes: [FluidType.ELECTRICITY, FluidType.WATER], @@ -209,14 +207,14 @@ describe('global reducer', () => { }) it('should handle SET_FLUID_STATUS without payload', () => { - const result = globalReducer(mockInitialGlobalState, { + const state = globalReducer(mockInitialGlobalState, { type: SET_FLUID_STATUS, }) - expect(result).toEqual(mockInitialGlobalState) + expect(state).toEqual(mockInitialGlobalState) }) it('should handle SET_CUSTOM_POPUP with payload', () => { - const result = { + const state = { ...mockInitialGlobalState, customPopupModal: mockCustomPopup, } @@ -225,6 +223,6 @@ describe('global reducer', () => { type: SET_CUSTOM_POPUP, payload: mockCustomPopup, }).customPopupModal - ).toBe(result.customPopupModal) + ).toBe(state.customPopupModal) }) }) diff --git a/src/store/global/global.reducer.ts b/src/store/global/global.reducer.ts index 624e2edbd11368e5476dcb9a06bcd910e081000a..a8281e5b6b8c48217aad109bf5bb7dbc4a4668ab 100644 --- a/src/store/global/global.reducer.ts +++ b/src/store/global/global.reducer.ts @@ -1,3 +1,4 @@ +/* eslint-disable camelcase */ import { FluidState, FluidType } from 'enum/fluid.enum' import { FluidSlugType } from 'enum/fluidSlug.enum' import { ScreenType } from 'enum/screen.enum' @@ -8,7 +9,7 @@ import { GlobalActionTypes, SET_CUSTOM_POPUP, SET_FLUID_STATUS, - SET_PARTNERS_ISSUE, + SET_PARTNERS_INFO, SET_SHOULD_REFRESH_CONSENT, SHOW_RELEASE_NOTES, TOGGLE_ANALYSIS_NOTIFICATION, @@ -36,7 +37,7 @@ const initialState: GlobalState = { challengeDuelNotification: false, analysisNotification: false, termsStatus: { - accepted: false, + accepted: true, versionType: 'init', }, fluidStatus: [ @@ -114,10 +115,11 @@ const initialState: GlobalState = { description: '', endDate: '', }, - openPartnersIssueModal: { - enedis: false, - egl: false, - grdf: false, + partnersInfo: { + egl_failure: false, + enedis_failure: false, + grdf_failure: false, + notification_activated: false, }, shouldRefreshConsent: false, sgeConnect: { @@ -151,110 +153,68 @@ const getFluidTypesFromStatus = (fluidStatus: FluidStatus[]): FluidType[] => { return fluidTypes.sort() } -export const globalReducer: Reducer<GlobalState> = ( +export const globalReducer: Reducer<GlobalState, GlobalActionTypes> = ( state = initialState, - action: GlobalActionTypes -): GlobalState => { + action +) => { + if (action.payload == undefined) return state + + const updateState = (updates: Partial<GlobalState>): GlobalState => ({ + ...state, + ...updates, + }) + switch (action.type) { case CHANGE_SCREEN_TYPE: - return action.payload != undefined - ? { - ...state, - screenType: action.payload, - } - : state + return updateState({ screenType: action.payload }) + case TOGGLE_CHALLENGE_EXPLORATION_NOTIFICATION: - return action.payload != undefined - ? { - ...state, - challengeExplorationNotification: action.payload, - } - : state + return updateState({ challengeExplorationNotification: action.payload }) + case TOGGLE_CHALLENGE_ACTION_NOTIFICATION: - return action.payload != undefined - ? { - ...state, - challengeActionNotification: action.payload, - } - : state + return updateState({ challengeActionNotification: action.payload }) + case TOGGLE_CHALLENGE_DUEL_NOTIFICATION: - return action.payload != undefined - ? { - ...state, - challengeDuelNotification: action.payload, - } - : state + return updateState({ challengeDuelNotification: action.payload }) + case TOGGLE_ANALYSIS_NOTIFICATION: - return action.payload != undefined - ? { - ...state, - analysisNotification: action.payload, - } - : state + return updateState({ analysisNotification: action.payload }) + case SET_FLUID_STATUS: - return action.payload != undefined - ? { - ...state, - fluidStatus: action.payload, - fluidTypes: getFluidTypesFromStatus(action.payload), - } - : state + return updateState({ + fluidStatus: action.payload, + fluidTypes: getFluidTypesFromStatus(action.payload), + }) + case UPDATE_TERMS_VALIDATION: - return action.payload != undefined - ? { - ...state, - termsStatus: action.payload, - } - : state + return updateState({ termsStatus: action.payload }) + case SHOW_RELEASE_NOTES: - return action.payload != undefined - ? { - ...state, - releaseNotes: action.payload, - } - : state - case SET_PARTNERS_ISSUE: - return action.payload != undefined - ? { - ...state, - openPartnersIssueModal: action.payload, - } - : state + return updateState({ releaseNotes: action.payload }) + + case SET_PARTNERS_INFO: + return updateState({ partnersInfo: action.payload }) + case SET_CUSTOM_POPUP: - return { - ...state, - customPopupModal: action.payload, - } + return updateState({ customPopupModal: action.payload }) + case SET_SHOULD_REFRESH_CONSENT: - return action.payload != undefined - ? { - ...state, - shouldRefreshConsent: action.payload, - } - : state + return updateState({ shouldRefreshConsent: action.payload }) + case UPDATE_FLUID_CONNECTION: - if (action.payload !== undefined) { - 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, - } - } else { - return state + 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: - if (action.payload != undefined) - return { - ...state, - sgeConnect: action.payload, - } - return state + return updateState({ sgeConnect: action.payload }) + default: return state } diff --git a/src/store/index.ts b/src/store/index.ts index 103f7e398aa28c36dcc79da2260c3faae486c129..42611fc1fa84555572335a6a4d16893a273c4280 100644 --- a/src/store/index.ts +++ b/src/store/index.ts @@ -20,47 +20,62 @@ import { composeWithDevTools } from 'redux-devtools-extension' import thunkMiddleware from 'redux-thunk' import { globalReducer } from 'store/global/global.reducer' import { modalReducer } from 'store/modal/modal.reducer' +import { ChallengeActionTypes } from './challenge/challenge.actions' import { challengeReducer } from './challenge/challenge.reducer' +import { ChartActionTypes } from './chart/chart.actions' import { chartReducer } from './chart/chart.reducer' +import { GlobalActionTypes } from './global/global.actions' +import { ModalActionTypes } from './modal/modal.actions' +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 } from './profileType/profileType.actions' import { profileTypeReducer } from './profileType/profileType.reducer' export interface EcolyoState { + challenge: ChallengeState + chart: ChartState global: GlobalState + modal: ModalState profile: Profile - profileType: ProfileType profileEcogesture: ProfileEcogesture - chart: ChartState - modal: ModalState - challenge: ChallengeState + profileType: ProfileType } -export const ecolyoReducer = combineReducers({ +export const defaultAction = { type: null, payload: undefined } + +const ecolyoReducer = combineReducers({ + challenge: challengeReducer, + chart: chartReducer, global: globalReducer, + modal: modalReducer, profile: profileReducer, - profileType: profileTypeReducer, profileEcogesture: profileEcogestureReducer, - chart: chartReducer, - modal: modalReducer, - challenge: challengeReducer, + profileType: profileTypeReducer, }) export interface AppStore { ecolyo: EcolyoState - cozy: never + cozy: unknown } +export type AppActionsTypes = + | ChallengeActionTypes + | ChartActionTypes + | GlobalActionTypes + | ModalActionTypes + | ProfileActionTypes + | ProfileEcogestureActionTypes + | ProfileTypeActionTypes + const sentryReduxEnhancer = Sentry.createReduxEnhancer({}) -const configureStore = ( - client: Client, - persistedState: any -): Store<AppStore> => { +const configureStore = (client: Client, persistedState: any) => { const middlewares = [thunkMiddleware.withExtraArgument({ client })] const composeEnhancers = composeWithDevTools({ trace: true }) || compose - const store: Store<AppStore> = createStore( + const store: Store<AppStore, AppActionsTypes> = createStore( combineReducers({ ecolyo: ecolyoReducer, cozy: client.reducer(), diff --git a/src/store/modal/modal.action.spec.ts b/src/store/modal/modal.action.spec.ts index c111d6fd16f630c914bb2362e27e2cc8b1ae66a1..7a4fec68aed008ecb60f8e6eef099d032f6ac48c 100644 --- a/src/store/modal/modal.action.spec.ts +++ b/src/store/modal/modal.action.spec.ts @@ -1,15 +1,12 @@ -import { - UPDATE_MODAL_ISFEEDBACKSOPEN, - updateModalIsFeedbacksOpen, -} from './modal.actions' +import { openFeedbackModal, OPEN_FEEDBACK_MODAL } from './modal.actions' describe('modal actions', () => { it('should create an action to update isFeedbacksOpen', () => { const isOpen = true const expectedAction = { - type: UPDATE_MODAL_ISFEEDBACKSOPEN, + type: OPEN_FEEDBACK_MODAL, payload: isOpen, } - expect(updateModalIsFeedbacksOpen(isOpen)).toEqual(expectedAction) + expect(openFeedbackModal(isOpen)).toEqual(expectedAction) }) }) diff --git a/src/store/modal/modal.actions.ts b/src/store/modal/modal.actions.ts index ea74f5ee5c9390638695f051bb6eaf4e8f157044..fe1ea172b7b15172883d3ff6294aa38d60a69547 100644 --- a/src/store/modal/modal.actions.ts +++ b/src/store/modal/modal.actions.ts @@ -1,15 +1,41 @@ -export const UPDATE_MODAL_ISFEEDBACKSOPEN = 'UPDATE_MODAL_ISFEEDBACKSOPEN' +import { defaultAction } from 'store' -interface UpdateModalFeedbacks { - type: typeof UPDATE_MODAL_ISFEEDBACKSOPEN +export const OPEN_PARTNERS_MODAL = 'OPEN_PARTNERS_ISSUE' +export const OPEN_FEEDBACK_MODAL = 'OPEN_FEEDBACK_MODAL' + +interface OpenFeedbackModal { + type: typeof OPEN_FEEDBACK_MODAL payload?: boolean } -export type ModalActionTypes = UpdateModalFeedbacks +interface OpenPartnersModal { + type: typeof OPEN_PARTNERS_MODAL + payload?: { + egl: boolean + enedis: boolean + grdf: boolean + } +} + +export type ModalActionTypes = + | OpenFeedbackModal + | OpenPartnersModal + | typeof defaultAction -export function updateModalIsFeedbacksOpen(isOpen: boolean): ModalActionTypes { +export function openFeedbackModal(isOpen: boolean): OpenFeedbackModal { return { - type: UPDATE_MODAL_ISFEEDBACKSOPEN, + type: OPEN_FEEDBACK_MODAL, payload: isOpen, } } + +export function openPartnersModal(openPartnersModal: { + egl: boolean + enedis: boolean + grdf: boolean +}): OpenPartnersModal { + return { + type: OPEN_PARTNERS_MODAL, + payload: openPartnersModal, + } +} diff --git a/src/store/modal/modal.reducer.spec.ts b/src/store/modal/modal.reducer.spec.ts index 4735069aff9a4f38dedd1229190140c2016a5ef3..b52662c6fd8e473eafc2b65911080e6408289f0d 100644 --- a/src/store/modal/modal.reducer.spec.ts +++ b/src/store/modal/modal.reducer.spec.ts @@ -1,29 +1,87 @@ -import { modalReducer } from './modal.reducer' -import { UPDATE_MODAL_ISFEEDBACKSOPEN } from './modal.actions' +import { ModalState } from 'models' +import { defaultAction } from 'store' import { mockInitialModalState } from '../../../tests/__mocks__/store' +import { OPEN_FEEDBACK_MODAL, OPEN_PARTNERS_MODAL } from './modal.actions' +import { modalReducer } from './modal.reducer' describe('modal reducer', () => { it('should return the initial state', () => { - // eslint-disable-next-line @typescript-eslint/no-explicit-any - const result = modalReducer(undefined as any, { type: 'default' }) - expect(result).toEqual(mockInitialModalState) + const state = modalReducer(undefined, { ...defaultAction }) + expect(state).toEqual(mockInitialModalState) }) - it('should handle UPDATE_MODAL_ISFEEDBACKSOPEN with payload', () => { - const result = modalReducer(mockInitialModalState, { - type: UPDATE_MODAL_ISFEEDBACKSOPEN, - payload: true, + describe('Feedback Modal', () => { + it('should handle UPDATE_FEEDBACK_MODAL with payload', () => { + const state = modalReducer(mockInitialModalState, { + type: OPEN_FEEDBACK_MODAL, + payload: true, + }) + expect(state).toEqual({ + ...mockInitialModalState, + isFeedbacksOpen: true, + }) }) - expect(result).toEqual({ - ...mockInitialModalState, - isFeedbacksOpen: true, + it('should handle UPDATE_FEEDBACK_MODAL without payload', () => { + const state = modalReducer(mockInitialModalState, { + type: OPEN_FEEDBACK_MODAL, + }) + expect(state).toEqual(mockInitialModalState) }) }) - it('should handle UPDATE_MODAL_ISFEEDBACKSOPEN without payload', () => { - const result = modalReducer(mockInitialModalState, { - type: UPDATE_MODAL_ISFEEDBACKSOPEN, + describe('PartnersInfo', () => { + const partnersModalAllTrue = { + egl: true, + enedis: true, + grdf: true, + } + it('should have all partners to false by default', () => { + const state = modalReducer(mockInitialModalState, { ...defaultAction }) + const expectedResult: ModalState = { + ...mockInitialModalState, + partnersIssueModal: { + egl: false, + enedis: false, + grdf: false, + }, + } + expect(state).toEqual(expectedResult) + }) + it('should handle OPEN_PARTNERS_MODAL to set all partners to true', () => { + const state = modalReducer(mockInitialModalState, { + type: OPEN_PARTNERS_MODAL, + payload: { ...partnersModalAllTrue }, + }) + const expectedResult: ModalState = { + ...mockInitialModalState, + partnersIssueModal: { + ...partnersModalAllTrue, + }, + } + expect(state).toEqual(expectedResult) + }) + it('should handle OPEN_PARTNERS_MODAL to set some partners to false', () => { + const state = modalReducer( + { + ...mockInitialModalState, + partnersIssueModal: { + ...partnersModalAllTrue, + }, + }, + { + type: OPEN_PARTNERS_MODAL, + payload: { egl: true, enedis: false, grdf: false }, + } + ) + const expectedResult: ModalState = { + ...mockInitialModalState, + partnersIssueModal: { + egl: true, + enedis: false, + grdf: false, + }, + } + expect(state).toEqual(expectedResult) }) - expect(result).toEqual(mockInitialModalState) }) }) diff --git a/src/store/modal/modal.reducer.ts b/src/store/modal/modal.reducer.ts index 9833fb12463075a8322aa54aa4efe8ba3ae44130..10b2a2715e0bc90697838ddeaf5c96ffba415521 100644 --- a/src/store/modal/modal.reducer.ts +++ b/src/store/modal/modal.reducer.ts @@ -1,26 +1,38 @@ +import { ModalState } from 'models' import { Reducer } from 'redux' import { - UPDATE_MODAL_ISFEEDBACKSOPEN, ModalActionTypes, + OPEN_FEEDBACK_MODAL, + OPEN_PARTNERS_MODAL, } from 'store/modal/modal.actions' -import { ModalState } from 'models' const initialState: ModalState = { isFeedbacksOpen: false, + partnersIssueModal: { + enedis: false, + egl: false, + grdf: false, + }, } -export const modalReducer: Reducer<ModalState> = ( +export const modalReducer: Reducer<ModalState, ModalActionTypes> = ( state = initialState, - action: ModalActionTypes -): ModalState => { + action +) => { + if (action.payload == undefined) return state + + const updateState = (updates: Partial<ModalState>): ModalState => ({ + ...state, + ...updates, + }) + switch (action.type) { - case UPDATE_MODAL_ISFEEDBACKSOPEN: - const isOpen = - action.payload != undefined ? action.payload : state.isFeedbacksOpen - return { - ...state, - isFeedbacksOpen: isOpen, - } + case OPEN_FEEDBACK_MODAL: + return updateState({ isFeedbacksOpen: action.payload }) + + case OPEN_PARTNERS_MODAL: + return updateState({ partnersIssueModal: action.payload }) + default: return state } diff --git a/src/store/profile/profile.action.spec.ts b/src/store/profile/profile.action.spec.ts index a9d3d73f8fd23a6e0ce8fa0a215e83c937a3df04..bd942e0879fd04363c8bc7c29039108e41ff3589 100644 --- a/src/store/profile/profile.action.spec.ts +++ b/src/store/profile/profile.action.spec.ts @@ -1,8 +1,5 @@ import { profileData } from '../../../tests/__mocks__/profileData.mock' -import { - createMockStore, - mockInitialEcolyoState, -} from '../../../tests/__mocks__/store' +import { createMockEcolyoStore } from '../../../tests/__mocks__/store' import { updateProfile, UPDATE_PROFILE } from './profile.actions' const mockUpdateProfile = jest.fn() @@ -15,10 +12,9 @@ jest.mock('services/profile.service', () => { }) describe('profile actions', () => { - // eslint-disable-next-line @typescript-eslint/no-explicit-any - let store: any + const store = createMockEcolyoStore() beforeEach(() => { - store = createMockStore(mockInitialEcolyoState) + store.clearActions() }) it('should create an UPDATE_PROFILE action when profile is updated', async () => { mockUpdateProfile.mockResolvedValueOnce(profileData) diff --git a/src/store/profile/profile.actions.ts b/src/store/profile/profile.actions.ts index eb8ef46cf11cb28f11cb5c9d90a023f11f6d6e8f..4d3808f88bd9ad846956f91f837cfc8b9b34e595 100644 --- a/src/store/profile/profile.actions.ts +++ b/src/store/profile/profile.actions.ts @@ -1,35 +1,33 @@ import { Client } from 'cozy-client' import { Profile } from 'models' -import ProfileService from 'services/profile.service' import { Dispatch } from 'react' -import { AppStore } from 'store' +import ProfileService from 'services/profile.service' +import { AppStore, defaultAction } from 'store' export const UPDATE_PROFILE = 'UPDATE_PROFILE' -export const SET_FIRST_CONNECTION = 'SET_FIRST_CONNECTION' export interface UpdateProfile { type: typeof UPDATE_PROFILE payload?: Profile } -export type ProfileActionTypes = UpdateProfile +export type ProfileActionTypes = UpdateProfile | typeof defaultAction -export function updateProfileSuccess(updatedProfile: Profile): UpdateProfile { +function updateProfileSuccess(updatedProfile: Profile): UpdateProfile { return { type: UPDATE_PROFILE, payload: updatedProfile, } } -// eslint-disable-next-line @typescript-eslint/no-explicit-any -export function updateProfile(upd: Partial<Profile>): any { +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(upd) + 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 index b1764154b9433d461d6d649641ace3f36e9154d0..95c22aaef918c56d97060f0a2d8191982e6314d0 100644 --- a/src/store/profile/profile.reducer.spec.ts +++ b/src/store/profile/profile.reducer.spec.ts @@ -1,3 +1,4 @@ +import { defaultAction } from 'store' import { profileData } from '../../../tests/__mocks__/profileData.mock' import { mockInitialProfileState } from '../../../tests/__mocks__/store' import { UPDATE_PROFILE } from './profile.actions' @@ -5,23 +6,22 @@ import { profileReducer } from './profile.reducer' describe('profile reducer', () => { it('should return the initial state', () => { - // eslint-disable-next-line @typescript-eslint/no-explicit-any - const result = profileReducer(undefined as any, { type: 'default' }) - expect(result).toEqual(mockInitialProfileState) + const state = profileReducer(undefined, { ...defaultAction }) + expect(state).toEqual(mockInitialProfileState) }) it('should handle UPDATE_PROFILE with payload', () => { - const result = profileReducer(mockInitialProfileState, { + const state = profileReducer(mockInitialProfileState, { type: UPDATE_PROFILE, payload: profileData, }) - expect(result).toEqual(profileData) + expect(state).toEqual(profileData) }) it('should handle UPDATE_PROFILE without payload', () => { - const result = profileReducer(mockInitialProfileState, { + const state = profileReducer(mockInitialProfileState, { type: UPDATE_PROFILE, }) - expect(result).toEqual(mockInitialProfileState) + expect(state).toEqual(mockInitialProfileState) }) }) diff --git a/src/store/profile/profile.reducer.ts b/src/store/profile/profile.reducer.ts index 5c3d9433d75c9b740904fe7f2b972d421b497386..182a0c0bffe4486dd2ad397dcb4412e1e7f28d87 100644 --- a/src/store/profile/profile.reducer.ts +++ b/src/store/profile/profile.reducer.ts @@ -30,16 +30,16 @@ const initialState: Profile = { isProfileTypeCompleted: false, isProfileEcogestureCompleted: false, onboarding: { - isWelcomeSeen: false, + isWelcomeSeen: true, }, haveSeenEcogestureModal: false, activateHalfHourDate: DateTime.fromISO('0000-01-01T00:00:00.000Z'), } -export const profileReducer: Reducer<Profile> = ( +export const profileReducer: Reducer<Profile, ProfileActionTypes> = ( state = initialState, - action: ProfileActionTypes -): Profile => { + action +) => { switch (action.type) { case UPDATE_PROFILE: return { diff --git a/src/store/profileEcogesture/profileEcogesture.action.spec.ts b/src/store/profileEcogesture/profileEcogesture.action.spec.ts index ce271348d47933e93d7c6fa7374afe0faae50bcc..ad0f42b7948f74982e2040eb6e39b49b863760bd 100644 --- a/src/store/profileEcogesture/profileEcogesture.action.spec.ts +++ b/src/store/profileEcogesture/profileEcogesture.action.spec.ts @@ -1,11 +1,8 @@ -import { - createMockStore, - mockInitialEcolyoState, -} from '../../../tests/__mocks__/store' import { mockProfileEcogesture } from '../../../tests/__mocks__/profileEcogesture.mock' +import { createMockEcolyoStore } from '../../../tests/__mocks__/store' import { updateProfileEcogesture, - UPDATE_PROFILEECOGESTURE, + UPDATE_PROFILE_ECOGESTURE, } from './profileEcogesture.actions' const mockUpdateProfileEcogesture = jest.fn() @@ -20,16 +17,15 @@ jest.mock('services/profileEcogesture.service', () => { }) describe('profileEcogesture actions', () => { - // eslint-disable-next-line @typescript-eslint/no-explicit-any - let store: any + const store = createMockEcolyoStore() beforeEach(() => { - store = createMockStore(mockInitialEcolyoState) + store.clearActions() }) - it('should create an UPDATE_PROFILEECOGESTURE action when ecogestureProfile is updated', async () => { + it('should create an UPDATE_PROFILE_ECOGESTURE action when ecogestureProfile is updated', async () => { mockUpdateProfileEcogesture.mockResolvedValueOnce(mockProfileEcogesture) const expectedActions = [ { - type: UPDATE_PROFILEECOGESTURE, + type: UPDATE_PROFILE_ECOGESTURE, payload: mockProfileEcogesture, }, ] diff --git a/src/store/profileEcogesture/profileEcogesture.actions.ts b/src/store/profileEcogesture/profileEcogesture.actions.ts index 67379dd86b762c40fc032b2d5f149b45b33b7aad..77140546584eca81839145ed7e8571534cf4c82c 100644 --- a/src/store/profileEcogesture/profileEcogesture.actions.ts +++ b/src/store/profileEcogesture/profileEcogesture.actions.ts @@ -1,38 +1,42 @@ import { Client } from 'cozy-client' -import { Dispatch } from 'react' -import { AppStore } from 'store' -import { ProfileEcogesture } from 'models/profileEcogesture.model' 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' -export const UPDATE_PROFILEECOGESTURE = 'UPDATE_PROFILEECOGESTURE' -export const CREATE_NEW_PROFILEECOGESTURE = 'CREATE_NEW_PROFILEECOGESTURE' +// 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_PROFILEECOGESTURE + type: typeof UPDATE_PROFILE_ECOGESTURE payload?: ProfileEcogesture } +// TODO never used ? export interface CreateNewProfileEcogesture { - type: typeof CREATE_NEW_PROFILEECOGESTURE + type: typeof CREATE_NEW_PROFILE_ECOGESTURE payload?: ProfileEcogesture } export type ProfileEcogestureActionTypes = | UpdateProfileEcogesture | CreateNewProfileEcogesture + | typeof defaultAction export function updateProfileEcogestureSuccess( updatedProfileEcogesture: ProfileEcogesture ): UpdateProfileEcogesture { return { - type: UPDATE_PROFILEECOGESTURE, + type: UPDATE_PROFILE_ECOGESTURE, payload: updatedProfileEcogesture, } } -// eslint-disable-next-line @typescript-eslint/no-explicit-any -export function updateProfileEcogesture(upd: Partial<ProfileEcogesture>): any { +export function updateProfileEcogesture( + updates: Partial<ProfileEcogesture> +): any { return async ( dispatch: Dispatch<UpdateProfileEcogesture>, getState: () => AppStore, @@ -40,7 +44,7 @@ export function updateProfileEcogesture(upd: Partial<ProfileEcogesture>): any { ) => { const profileEcogestureService = new ProfileEcogestureService(client) const updatedProfileEcogesture = - await profileEcogestureService.updateProfileEcogesture(upd) + await profileEcogestureService.updateProfileEcogesture(updates) if (updatedProfileEcogesture) { dispatch(updateProfileEcogestureSuccess(updatedProfileEcogesture)) } @@ -48,8 +52,7 @@ export function updateProfileEcogesture(upd: Partial<ProfileEcogesture>): any { } export function newProfileEcogestureEntry( - upd: Partial<ProfileEcogesture> - // eslint-disable-next-line @typescript-eslint/no-explicit-any + updates: Partial<ProfileEcogesture> ): any { return async ( dispatch: Dispatch<UpdateProfileEcogesture>, @@ -58,7 +61,7 @@ export function newProfileEcogestureEntry( ) => { const { data: newProfileEcogesture } = await client.create( PROFILEECOGESTURE_DOCTYPE, - upd + updates ) if (newProfileEcogesture) { dispatch(updateProfileEcogestureSuccess(newProfileEcogesture)) diff --git a/src/store/profileEcogesture/profileEcogesture.reducer.spec.ts b/src/store/profileEcogesture/profileEcogesture.reducer.spec.ts index 71662a59115b9f27416a35431f9807b51db7b0f5..1158a9881f3f659e21808483c764c1a324095e8a 100644 --- a/src/store/profileEcogesture/profileEcogesture.reducer.spec.ts +++ b/src/store/profileEcogesture/profileEcogesture.reducer.spec.ts @@ -1,31 +1,29 @@ -import { profileEcogestureReducer } from './profileEcogesture.reducer' -import { UPDATE_PROFILEECOGESTURE } from './profileEcogesture.actions' +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', () => { - // eslint-disable-next-line @typescript-eslint/no-explicit-any - const result = profileEcogestureReducer(undefined as any, { - type: 'default', - }) - expect(result).toEqual(mockProfileEcogesture) + const state = profileEcogestureReducer(undefined, { ...defaultAction }) + expect(state).toEqual(mockProfileEcogesture) }) - it('should handle UPDATE_PROFILEECOGESTURE with payload', () => { - const result = profileEcogestureReducer(mockProfileEcogesture, { - type: UPDATE_PROFILEECOGESTURE, + it('should handle UPDATE_PROFILE_ECOGESTURE with payload', () => { + const state = profileEcogestureReducer(mockProfileEcogesture, { + type: UPDATE_PROFILE_ECOGESTURE, payload: mockProfileEcogestureUpdated, }) - expect(result).toEqual(mockProfileEcogestureUpdated) + expect(state).toEqual(mockProfileEcogestureUpdated) }) - it('should handle UPDATE_PROFILEECOGESTURE without payload', () => { - const result = profileEcogestureReducer(mockProfileEcogesture, { - type: UPDATE_PROFILEECOGESTURE, + it('should handle UPDATE_PROFILE_ECOGESTURE without payload', () => { + const state = profileEcogestureReducer(mockProfileEcogesture, { + type: UPDATE_PROFILE_ECOGESTURE, }) - expect(result).toEqual(mockProfileEcogesture) + expect(state).toEqual(mockProfileEcogesture) }) }) diff --git a/src/store/profileEcogesture/profileEcogesture.reducer.ts b/src/store/profileEcogesture/profileEcogesture.reducer.ts index 40646dc63bdf98987d663bd7ef7820cbf04d7480..511c813a06fd8b23eb1a58185a1343762274da53 100644 --- a/src/store/profileEcogesture/profileEcogesture.reducer.ts +++ b/src/store/profileEcogesture/profileEcogesture.reducer.ts @@ -1,10 +1,10 @@ -import { Reducer } from 'redux' import { IndividualOrCollective, WarmingType } from 'enum/profileType.enum' import { ProfileEcogesture } from 'models/profileEcogesture.model' +import { Reducer } from 'redux' import { - CREATE_NEW_PROFILEECOGESTURE, + CREATE_NEW_PROFILE_ECOGESTURE, ProfileEcogestureActionTypes, - UPDATE_PROFILEECOGESTURE, + UPDATE_PROFILE_ECOGESTURE, } from './profileEcogesture.actions' const initialState: ProfileEcogesture = { @@ -14,13 +14,15 @@ const initialState: ProfileEcogesture = { equipments: [], } -export const profileEcogestureReducer: Reducer<ProfileEcogesture> = ( - state = initialState, - action: ProfileEcogestureActionTypes -): ProfileEcogesture => { +export const profileEcogestureReducer: Reducer< + ProfileEcogesture, + ProfileEcogestureActionTypes +> = (state = initialState, action) => { + if (action.payload == undefined) return state + switch (action.type) { - case UPDATE_PROFILEECOGESTURE: - case CREATE_NEW_PROFILEECOGESTURE: + case UPDATE_PROFILE_ECOGESTURE: + case CREATE_NEW_PROFILE_ECOGESTURE: return { ...state, ...action.payload, diff --git a/src/store/profileType/profileType.actions.spec.ts b/src/store/profileType/profileType.actions.spec.ts index c08db15e0969e1435e0e027aaaa1df7dcc522801..dec9b8345c6ab2e56ecb080238b010d15bb12069 100644 --- a/src/store/profileType/profileType.actions.spec.ts +++ b/src/store/profileType/profileType.actions.spec.ts @@ -1,9 +1,6 @@ -import { UPDATE_PROFILETYPE, updateProfileType } from './profileType.actions' import { profileTypeData } from '../../../tests/__mocks__/profileType.mock' -import { - createMockStore, - mockInitialEcolyoState, -} from '../../../tests/__mocks__/store' +import { createMockEcolyoStore } from '../../../tests/__mocks__/store' +import { updateProfileType, UPDATE_PROFILETYPE } from './profileType.actions' const mockUpdateProfileType = jest.fn() jest.mock('services/profileTypeEntity.service', () => { @@ -15,10 +12,9 @@ jest.mock('services/profileTypeEntity.service', () => { }) describe('profileType actions', () => { - // eslint-disable-next-line @typescript-eslint/no-explicit-any - let store: any + const store = createMockEcolyoStore() beforeEach(() => { - store = createMockStore(mockInitialEcolyoState) + store.clearActions() }) it('should create an UPDATE_PROFILETYPE action when profileType is updated', async () => { mockUpdateProfileType.mockResolvedValueOnce(profileTypeData) diff --git a/src/store/profileType/profileType.actions.ts b/src/store/profileType/profileType.actions.ts index 8df276089282c281a1a94d1fbf6e61b9a8072aaa..25c43810920ec723e4a7adeb3ea7d6b6c053cc7b 100644 --- a/src/store/profileType/profileType.actions.ts +++ b/src/store/profileType/profileType.actions.ts @@ -1,9 +1,9 @@ import { Client } from 'cozy-client' +import { PROFILETYPE_DOCTYPE } from 'doctypes' import { ProfileType } from 'models' import { Dispatch } from 'react' -import { AppStore } from 'store' -import { PROFILETYPE_DOCTYPE } from 'doctypes' import ProfileTypeEntityService from 'services/profileTypeEntity.service' +import { AppStore, defaultAction } from 'store' export const UPDATE_PROFILETYPE = 'UPDATE_PROFILETYPE' export const CREATE_NEW_PROFILETYPE = 'CREATE_NEW_PROFILETYPE' @@ -18,7 +18,10 @@ export interface CreateNewProfileType { payload?: ProfileType } -export type ProfileTypeActionTypes = UpdateProfileType | CreateNewProfileType +export type ProfileTypeActionTypes = + | UpdateProfileType + | CreateNewProfileType + | typeof defaultAction export function updateProfileTypeSuccess( updatedProfileType: ProfileType @@ -29,16 +32,15 @@ export function updateProfileTypeSuccess( } } -// eslint-disable-next-line @typescript-eslint/no-explicit-any -export function updateProfileType(upd: Partial<ProfileType>): any { +export function updateProfileType(updates: Partial<ProfileType>): any { return async ( dispatch: Dispatch<UpdateProfileType>, getState: () => AppStore, { client }: { client: Client } - ) => { + ): Promise<void> => { const profileTypeEntityService = new ProfileTypeEntityService(client) const updatedProfileType = await profileTypeEntityService.updateProfileType( - upd + updates ) if (updatedProfileType) { dispatch(updateProfileTypeSuccess(updatedProfileType)) @@ -46,8 +48,7 @@ export function updateProfileType(upd: Partial<ProfileType>): any { } } -// eslint-disable-next-line @typescript-eslint/no-explicit-any -export function newProfileTypeEntry(upd: Partial<ProfileType>): any { +export function newProfileTypeEntry(updates: Partial<ProfileType>): any { return async ( dispatch: Dispatch<UpdateProfileType>, getState: () => AppStore, @@ -55,7 +56,7 @@ export function newProfileTypeEntry(upd: Partial<ProfileType>): any { ) => { const { data: newProfileType } = await client.create( PROFILETYPE_DOCTYPE, - upd + updates ) if (newProfileType) { dispatch(updateProfileTypeSuccess(newProfileType)) diff --git a/src/store/profileType/profileType.reducer.spec.ts b/src/store/profileType/profileType.reducer.spec.ts index ac723528428d2b3d828d14536b6b01b63b518976..7704a227a54f9cfa5f719fa517a8524234b41600 100644 --- a/src/store/profileType/profileType.reducer.spec.ts +++ b/src/store/profileType/profileType.reducer.spec.ts @@ -1,26 +1,27 @@ -import { profileTypeReducer } from './profileType.reducer' -import { UPDATE_PROFILETYPE } from './profileType.actions' -import { mockInitialProfileTypeState } from '../../../tests/__mocks__/store' +import { defaultAction } from 'store' import { profileTypeData } from '../../../tests/__mocks__/profileType.mock' +import { mockInitialProfileTypeState } from '../../../tests/__mocks__/store' +import { UPDATE_PROFILETYPE } from './profileType.actions' +import { profileTypeReducer } from './profileType.reducer' describe('profile reducer', () => { it('should return the initial state', () => { - const result = profileTypeReducer(undefined as any, { type: 'default' }) - expect(result).toEqual(mockInitialProfileTypeState) + const state = profileTypeReducer(undefined, { ...defaultAction }) + expect(state).toEqual(mockInitialProfileTypeState) }) it('should handle UPDATE_PROFILETYPE with payload', () => { - const result = profileTypeReducer(mockInitialProfileTypeState, { + const state = profileTypeReducer(mockInitialProfileTypeState, { type: UPDATE_PROFILETYPE, payload: profileTypeData, }) - expect(result).toEqual(profileTypeData) + expect(state).toEqual(profileTypeData) }) it('should handle UPDATE_PROFILETYPE without payload', () => { - const result = profileTypeReducer(mockInitialProfileTypeState, { + const state = profileTypeReducer(mockInitialProfileTypeState, { type: UPDATE_PROFILETYPE, }) - expect(result).toEqual(mockInitialProfileTypeState) + expect(state).toEqual(mockInitialProfileTypeState) }) }) diff --git a/src/store/profileType/profileType.reducer.ts b/src/store/profileType/profileType.reducer.ts index a5debb195e059fabf8567d50e406887ea45b5c43..6dbc015b193ab6f42cc01de3370510b193a0a646 100644 --- a/src/store/profileType/profileType.reducer.ts +++ b/src/store/profileType/profileType.reducer.ts @@ -1,14 +1,9 @@ -import { Reducer } from 'redux' -import { - UPDATE_PROFILETYPE, - CREATE_NEW_PROFILETYPE, -} from 'store/profileType/profileType.actions' -import { ProfileType } from 'models' -import { DateTime } from 'luxon' +import { FluidType } from 'enum/fluid.enum' import { ConstructionYear, Floor, HotWaterEquipment, + HotWaterFluid, HousingType, IndividualInsulationWork, IndividualOrCollective, @@ -16,7 +11,13 @@ import { ThreeChoicesAnswer, WarmingType, } from 'enum/profileType.enum' -import { FluidType } from 'enum/fluid.enum' +import { DateTime } from 'luxon' +import { ProfileType } from 'models' +import { Reducer } from 'redux' +import { + CREATE_NEW_PROFILETYPE, + UPDATE_PROFILETYPE, +} from 'store/profileType/profileType.actions' import { ProfileTypeActionTypes } from './profileType.actions' const initialState: ProfileType = { @@ -37,16 +38,16 @@ const initialState: ProfileType = { hasReplacedHeater: ThreeChoicesAnswer.UNKNOWN, hotWaterEquipment: HotWaterEquipment.SOLAR, warmingFluid: WarmingType.ELECTRICITY, - hotWaterFluid: FluidType.ELECTRICITY, + hotWaterFluid: HotWaterFluid.ELECTRICITY, cookingFluid: FluidType.ELECTRICITY, updateDate: DateTime.fromISO('0000-01-01T00:00:00.000Z'), equipments: [], } -export const profileTypeReducer: Reducer<ProfileType> = ( - state = initialState, - action: ProfileTypeActionTypes -): ProfileType => { +export const profileTypeReducer: Reducer< + ProfileType, + ProfileTypeActionTypes +> = (state = initialState, action) => { switch (action.type) { case UPDATE_PROFILETYPE: case CREATE_NEW_PROFILETYPE: diff --git a/src/styles/base/_breakpoint.scss b/src/styles/base/_breakpoint.scss index 26eb95808c9f7de105296286f4865e3424f4e284..8cb5481971e6fc83c49d89160890c19a7a36eefd 100644 --- a/src/styles/base/_breakpoint.scss +++ b/src/styles/base/_breakpoint.scss @@ -5,10 +5,9 @@ $width-tablet: 1023px; $width-desktop: 1200px; $width-large-desktop: 1201px; - -$small-phone: "only screen and (max-width : #{$width-small-phone})"; -$phone: "only screen and (max-width : #{$width-phone})"; -$large-phone: "only screen and (max-width : #{$width-large-phone})"; -$tablet: "only screen and (max-width : #{$width-tablet})"; -$desktop: "only screen and (max-width : #{$width-desktop})"; -$large-desktop: "only screen and (min-width : #{$width-large-desktop})"; +$small-phone: 'only screen and (max-width : #{$width-small-phone})'; +$phone: 'only screen and (max-width : #{$width-phone})'; +$large-phone: 'only screen and (max-width : #{$width-large-phone})'; +$tablet: 'only screen and (max-width : #{$width-tablet})'; +$desktop: 'only screen and (max-width : #{$width-desktop})'; +$large-desktop: 'only screen and (min-width : #{$width-large-desktop})'; diff --git a/src/styles/components/_expansion-panel.scss b/src/styles/components/_expansion-panel.scss index c3a2444f5704888daa0eeb44d4e0ecd42bfcdbb2..b7a3fd566b52189d24f81ab8b24ebe03cdaadb56 100644 --- a/src/styles/components/_expansion-panel.scss +++ b/src/styles/components/_expansion-panel.scss @@ -1,6 +1,6 @@ @import '../base/color'; -div.expansion-panel-root{ +div.expansion-panel-root { margin: 1.2rem 0; color: $grey-bright; background: $grey-linear-gradient-background; @@ -18,7 +18,7 @@ div.expansion-panel-root{ border: 1px solid $red-primary; } } -div.expansion-panel-summary{ +div.expansion-panel-summary { padding: 0.25rem 1.2rem; min-height: 4rem; &.Mui-focused { @@ -49,4 +49,4 @@ div.expansion-panel-content { } div.expansion-panel-details { padding: 0 1.2rem 1.2rem; -} \ No newline at end of file +} diff --git a/src/targets/browser/index.ejs b/src/targets/browser/index.ejs index fe3890f3794dda70253d561ca539d84f4e32388e..ee85e8ba084bdce2227a5426926788879554db44 100644 --- a/src/targets/browser/index.ejs +++ b/src/targets/browser/index.ejs @@ -21,8 +21,6 @@ <!-- PWA Colors --> <meta name="theme-color" content="#343641" /> <meta name="background-color" content="#121212" /> - <!-- PWA iOS title --> - <meta name="apple-mobile-web-app-title" content="Ecolyo"> <% _.forEach(htmlWebpackPlugin.files.css, function(file) { %> <link rel="stylesheet" href="<%- file %>"> diff --git a/src/targets/browser/index.tsx b/src/targets/browser/index.tsx index eb5836f4578cd219bcb3568be388fe65e718b80e..89a2aa750e98e8eb59aba0db902a5f3ee1ebc686 100644 --- a/src/targets/browser/index.tsx +++ b/src/targets/browser/index.tsx @@ -49,7 +49,7 @@ const setupApp = memoize(() => { }) const persistedState: any = {} - const store: any = configureStore(client, persistedState) + const store = configureStore(client, persistedState) const envService = new EnvironmentService() const isLocal = envService.isLocal() const development = envService.isDev() diff --git a/src/targets/mobile/DOCS.md b/src/targets/mobile/DOCS.md index 9ac66d690a4ef290b5a3263676e5b30e4b3e28b6..d5a967aa7354c5721fa147f8ba4502f268070045 100644 --- a/src/targets/mobile/DOCS.md +++ b/src/targets/mobile/DOCS.md @@ -1,2 +1,3 @@ # Mobile development documentation + [Cozy Docs](https://cozy.github.io/cozy-docs-v3/en/dev/cordova/) diff --git a/src/targets/services/aggregatorUsageEvents.ts b/src/targets/services/aggregatorUsageEvents.ts index 9a2c6fd14d664f99a0012268a3438a784aa75834..782add87babdf44a4ad6c79de72932c686176aae 100644 --- a/src/targets/services/aggregatorUsageEvents.ts +++ b/src/targets/services/aggregatorUsageEvents.ts @@ -1,27 +1,27 @@ -import logger from 'cozy-logger' +import * as Sentry from '@sentry/react' import { Client } from 'cozy-client' -import { runService } from './service' -import UsageEventService from 'services/usageEvent.service' -import ProfileService from 'services/profile.service' -import ConsumptionService from 'services/consumption.service' -import { FluidStatus, PerformanceIndicator, UsageEvent } from 'models' -import { UsageEventType } from 'enum/usageEvent.enum' -import { DateTime } from 'luxon' -import { toNumber, uniq } from 'lodash' -import FluidService from 'services/fluid.service' +import logger from 'cozy-logger' +import { DaccEvent } from 'enum/dacc.enum' import { FluidState, FluidType } from 'enum/fluid.enum' -import { getFluidType } from 'utils/utils' +import { FluidSlugType } from 'enum/fluidSlug.enum' +import { HotWaterFluid, WarmingType } from 'enum/profileType.enum' import { TimeStep } from 'enum/timeStep.enum' -import EnvironmentService from 'services/environment.service' -import { DaccEvent } from 'enum/dacc.enum' +import { UsageEventType } from 'enum/usageEvent.enum' import { UsageEventProperties } from 'enum/usageEventProperties.enum' -import ChallengeService from 'services/challenge.service' import { UserChallengeState } from 'enum/userChallenge.enum' +import { toNumber, uniq } from 'lodash' +import { DateTime } from 'luxon' +import { FluidStatus, PerformanceIndicator, UsageEvent } from 'models' +import ChallengeService from 'services/challenge.service' +import ConsumptionService from 'services/consumption.service' +import EnvironmentService from 'services/environment.service' +import FluidService from 'services/fluid.service' +import ProfileService from 'services/profile.service' import ProfileTypeEntityService from 'services/profileTypeEntity.service' import TermsService from 'services/terms.service' -import { WarmingType } from 'enum/profileType.enum' -import { FluidSlugType } from 'enum/fluidSlug.enum' -import * as Sentry from '@sentry/react' +import UsageEventService from 'services/usageEvent.service' +import { getFluidType } from 'utils/utils' +import { runService } from './service' const logStack = logger.namespace('aggregatorUsageEvents') @@ -43,7 +43,7 @@ interface Indicator { const readUsageEvents: UsageEvent[] = [] // Store error events -const errorEvent: { error: any; doctype: string }[] = [] +const errorEvent: { error: unknown; doctype: string }[] = [] const sendIndicator = async ( indicator: Indicator, @@ -73,9 +73,13 @@ const sendIndicator = async ( ) return true } catch (error) { + let errorMessage = 'Failed to do something exceptional' + if (error instanceof Error) { + errorMessage = error.message + } logStack( 'error', - `Error while sending indicator ${indicator.measureName} to remote doctype: ${error.message}` + `Error while sending indicator ${indicator.measureName} to remote doctype: ${errorMessage}` ) Sentry.captureException(JSON.stringify({ error })) throw error @@ -113,47 +117,35 @@ const sendAggregatedEventByDay = async ( ) => { const reducedEvents = reduceEvents(events) for (const item of Object.keys(reducedEvents)) { - const splitedKey = item.split('|') + const splittedKey = item.split('|') let group1 = {} let group2 = {} let group3 = {} - if ( - groupsKeys.group1 && - (groupsIndexes[0] !== 0 || (customValues && customValues[0])) - ) { + if (groupsKeys.group1 && (groupsIndexes[0] !== 0 || customValues?.[0])) { group1 = { - [groupsKeys.group1]: - customValues && customValues[0] - ? customValues[0] - : splitedKey[groupsIndexes[0]], + [groupsKeys.group1]: customValues?.[0] + ? customValues[0] + : splittedKey[groupsIndexes[0]], } } - if ( - groupsKeys.group2 && - (groupsIndexes[1] !== 0 || (customValues && customValues[1])) - ) { + if (groupsKeys.group2 && (groupsIndexes[1] !== 0 || customValues?.[1])) { group2 = { - [groupsKeys.group2]: - customValues && customValues[1] - ? customValues[1] - : splitedKey[groupsIndexes[1]], + [groupsKeys.group2]: customValues?.[1] + ? customValues[1] + : splittedKey[groupsIndexes[1]], } } - if ( - groupsKeys.group3 && - (groupsIndexes[2] !== 0 || (customValues && customValues[2])) - ) { + if (groupsKeys.group3 && (groupsIndexes[2] !== 0 || customValues?.[2])) { group3 = { - [groupsKeys.group3]: - customValues && customValues[2] - ? customValues[2] - : splitedKey[groupsIndexes[2]], + [groupsKeys.group3]: customValues?.[2] + ? customValues[2] + : splittedKey[groupsIndexes[2]], } } const indicator: Indicator = { createdBy: 'ecolyo', measureName: eventType, - startDate: DateTime.fromISO(splitedKey[0]).toISODate(), + startDate: DateTime.fromISO(splittedKey[0]).toISODate(), value: reducedEvents[item].length, group1: group1, ...(Object.keys(group2).length > 0 && { group2: group2 }), @@ -324,23 +316,23 @@ const calculPeriodBetweenChallenge = async ( /** * Format a string with all konnectors in success state - * @param konnectorfluidTypes FluidType[] + * @param konnectorFluidTypes FluidType[] * @returns string */ const getConnectedKonnectorSlug = ( - konnectorfluidTypes: FluidType[] + konnectorFluidTypes: FluidType[] ): string => { let slug = '' - if (konnectorfluidTypes.includes(FluidType.ELECTRICITY)) { + if (konnectorFluidTypes.includes(FluidType.ELECTRICITY)) { slug += 'electricity' } - if (konnectorfluidTypes.includes(FluidType.GAS)) { + if (konnectorFluidTypes.includes(FluidType.GAS)) { if (slug.length > 0) { slug += ':' } slug += 'gas' } - if (konnectorfluidTypes.includes(FluidType.WATER)) { + if (konnectorFluidTypes.includes(FluidType.WATER)) { if (slug.length > 0) { slug += ':' } @@ -357,9 +349,9 @@ const calculateConnectedKonnectorPerDay = async (client: Client) => { ) logStack('info', 'calculateConnectedKonnectorPerDay') if (connectedKonnectors.length > 0) { - const konnectorfluidTypes: FluidType[] = [] + const konnectorFluidTypes: FluidType[] = [] for (const konnector of connectedKonnectors) { - konnectorfluidTypes.push(konnector.fluidType) + konnectorFluidTypes.push(konnector.fluidType) } const KonnectorConnectedPerDayIndicator: Indicator = { createdBy: 'ecolyo', @@ -371,7 +363,7 @@ const calculateConnectedKonnectorPerDay = async (client: Client) => { .startOf('day') .toISODate(), value: connectedKonnectors.length, - group1: { categories: getConnectedKonnectorSlug(konnectorfluidTypes) }, + group1: { categories: getConnectedKonnectorSlug(konnectorFluidTypes) }, } await sendIndicator(KonnectorConnectedPerDayIndicator, client) } @@ -384,15 +376,15 @@ const calculateConnectedKonnectorPerDay = async (client: Client) => { * @param fluidType FluidType * @returns Promise<string> */ -const buildProfileWithFuildType = async ( +const buildProfileWithFluidType = async ( client: Client, fluidType: FluidType ): Promise<string> => { - let formatedProfile = '' + let formattedProfile = '' const profile = await new ProfileService(client).getProfile() // If profile is not filled, return empty string - if (!profile?.isProfileTypeCompleted) return formatedProfile + if (!profile?.isProfileTypeCompleted) return formattedProfile const date = DateTime.local().setZone('utc', { keepLocalTime: true, }) @@ -401,58 +393,62 @@ const buildProfileWithFuildType = async ( ) if (fluidType === FluidType.ELECTRICITY) { if (profile && profileType?.warmingFluid === WarmingType.ELECTRICITY) { - formatedProfile = 'chauffage élec' + formattedProfile = 'chauffage élec' } if (profile && profileType?.warmingFluid === WarmingType.WOOD) { - formatedProfile = 'chauffage bois' + formattedProfile = 'chauffage bois' } if (profile && profileType?.warmingFluid === WarmingType.FUEL) { - formatedProfile = 'chauffage fuel' + formattedProfile = 'chauffage fuel' } - if (profile && profileType?.hotWaterFluid === FluidType.ELECTRICITY) { - if (formatedProfile.length === 0) { - formatedProfile = 'ECS' + if (profile && profileType?.hotWaterFluid === HotWaterFluid.ELECTRICITY) { + if (formattedProfile.length === 0) { + formattedProfile = 'ECS' } else { - formatedProfile += ':ECS' + formattedProfile += ':ECS' } } if (profile && profileType?.cookingFluid === FluidType.ELECTRICITY) { - if (formatedProfile.length === 0) { - formatedProfile = 'cuisine élec' + if (formattedProfile.length === 0) { + formattedProfile = 'cuisine élec' } else { - formatedProfile += ':cuisine élec' + formattedProfile += ':cuisine élec' } } - if (formatedProfile.length === 0) { + if (formattedProfile.length === 0) { return 'électricité spécifique' } else { - return formatedProfile + return formattedProfile } } else if (fluidType === FluidType.GAS) { if (profile && profileType?.warmingFluid === WarmingType.GAS) { - formatedProfile = 'chauffage gaz' + formattedProfile = 'chauffage gaz' } - if (profile && profileType && profileType.hotWaterFluid === FluidType.GAS) { - if (formatedProfile.length === 0) { - formatedProfile = 'ECS' + if ( + profile && + profileType && + profileType.hotWaterFluid === HotWaterFluid.GAS + ) { + if (formattedProfile.length === 0) { + formattedProfile = 'ECS' } else { - formatedProfile += ':ECS' + formattedProfile += ':ECS' } } if (profile && profileType && profileType.cookingFluid === FluidType.GAS) { - if (formatedProfile.length === 0) { - formatedProfile = 'cuisine gaz' + if (formattedProfile.length === 0) { + formattedProfile = 'cuisine gaz' } else { - formatedProfile += ':cuisine gaz' + formattedProfile += ':cuisine gaz' } } - if (formatedProfile.length === 0) { + if (formattedProfile.length === 0) { return 'autre' } else { - return formatedProfile + return formattedProfile } } - return formatedProfile + return formattedProfile } const getConsumptionValue = async ( @@ -524,18 +520,16 @@ const calculateConsumptionVariation = async (client: Client) => { }) .startOf('day') .toISODate(), - value: - consumptionData[fluidType] && - consumptionData[fluidType].percentageVariation - ? consumptionData[fluidType].percentageVariation - : 0, // in percent + value: consumptionData[fluidType]?.percentageVariation + ? consumptionData[fluidType].percentageVariation + : 0, // in percent // eslint-disable-next-line camelcase group1: { fluid_type: FluidType[fluidType].toLowerCase() }, // eslint-disable-next-line camelcase group2: { seniority: Math.round(seniority).toString() }, group3: { // eslint-disable-next-line camelcase - fluid_usage: await buildProfileWithFuildType( + fluid_usage: await buildProfileWithFluidType( client, getFluidType(FluidType[fluidType]) ), @@ -702,7 +696,7 @@ const sendHalfHourConsumption = async (client: Client) => { } /** - * Send indicator to dacc, each month send if user has succed to configure a connector with the number of try. + * Send indicator to dacc, each month send if user has succeeded to configure a connector with the number of try. * @param client CozyClient */ const sendKonnectorEvents = async (client: Client) => { @@ -738,7 +732,7 @@ const sendKonnectorEvents = async (client: Client) => { }, true ) - // Remove success from other month, they should have been already proceced + // Remove success from other month, they should have been already processed // successEvents.length = successEventsOfCurrentMonth for (let index = 0; index < successEvents.length; index++) { diff --git a/src/targets/services/consumptionAlert.ts b/src/targets/services/consumptionAlert.ts index 668306c107dc461601ff8750aeaa0a75f6993611..350fa89eb4dcdf36bc5f8345e7a3d84ba8382657 100644 --- a/src/targets/services/consumptionAlert.ts +++ b/src/targets/services/consumptionAlert.ts @@ -1,16 +1,16 @@ -import logger from 'cozy-logger' import { Client } from 'cozy-client' +import logger from 'cozy-logger' +import { FluidType } from 'enum/fluid.enum' import get from 'lodash/get' -import { runService } from './service' -import ProfileService from 'services/profile.service' -import MailService from 'services/mail.service' import { DateTime } from 'luxon' -const consumptionLimit = require('notifications/consumptionLimit.hbs') import mjml2html from 'mjml' -import { FluidType } from 'enum/fluid.enum' import ConsumptionService from 'services/consumption.service' -import { getPreviousMonthName } from 'utils/utils' import EnvironmentService from 'services/environment.service' +import MailService from 'services/mail.service' +import ProfileService from 'services/profile.service' +import { getPreviousMonthName } from 'utils/utils' +import { runService } from './service' +const consumptionLimit = require('notifications/consumptionLimit.hbs') const logStack = logger.namespace('alert') @@ -18,15 +18,14 @@ interface ConsumptionAlertProps { client: Client } -// Only monitoring WATER fluid for now +// Only monitoring WATER fluid for now const consumptionAlert = async ({ client }: ConsumptionAlertProps) => { logStack('info', 'Fetching user profile...') const upm = new ProfileService(client) const consumptionService = new ConsumptionService(client) const userProfil = await upm.getProfile() if ( - !userProfil || - !userProfil.sendConsumptionAlert || + !userProfil?.sendConsumptionAlert || userProfil.waterDailyConsumptionLimit === 0 ) { logStack( diff --git a/src/targets/services/enedisHalfHourMonthlyAnalysis.ts b/src/targets/services/enedisHalfHourMonthlyAnalysis.ts index ab802266964624187c87a08b331389733577213c..b9bd297ff9be608d0831734d9872ac383275e50c 100644 --- a/src/targets/services/enedisHalfHourMonthlyAnalysis.ts +++ b/src/targets/services/enedisHalfHourMonthlyAnalysis.ts @@ -199,7 +199,7 @@ const syncEnedisMonthlyAnalysisDataDoctype = async ({ )) as DataloadEntity[] const lastEnedisMonthlyAnalysis = await emas.getLastEnedisMonthlyAnalysis() - if (firstMinuteData && firstMinuteData[0]) { + if (firstMinuteData?.[0]) { // First creates the analysis of the month - 1 logStack('info', 'Fetching last Enedis monthly Analysis...') const firstMinuteDate = DateTime.fromObject({ diff --git a/src/targets/services/fluidsPrices.ts b/src/targets/services/fluidsPrices.ts index fd0208f8c30d7cf85b447d2edc473de8659bccba..d6a5f0a6a0b82265da7529eb455d10343d05c185 100644 --- a/src/targets/services/fluidsPrices.ts +++ b/src/targets/services/fluidsPrices.ts @@ -22,7 +22,7 @@ interface PricesProps { client: Client } -const getRemotePricesByfluid = async ( +const getRemotePricesByFluid = async ( client: Client, fluidType: FluidType ): Promise<FluidPrice[]> => { @@ -47,7 +47,7 @@ const synchroPricesToUpdate = async ( fluidType: FluidType ): Promise<string | null> => { const fps = new FluidPricesService(client) - const remotePrices = await getRemotePricesByfluid(client, fluidType) + const remotePrices = await getRemotePricesByFluid(client, fluidType) let firstEditedPrice: string | null = null await Promise.all( remotePrices.map(remotePrice => { @@ -216,8 +216,8 @@ const getDoctypeTypeByFluid = (fluidType: FluidType): string => { if (fluidType === FluidType.WATER) { return EGL_DAY_DOCTYPE } - logStack('error', 'Unkown FluidType') - Sentry.captureException({ error: 'Unkown FluidType Doctype' }) + logStack('error', 'Unknown FluidType') + Sentry.captureException({ error: 'Unknown FluidType Doctype' }) throw new Error() } @@ -228,8 +228,8 @@ const getTimeSetByFluid = (fluidType: FluidType): TimeStep[] => { if (fluidType === FluidType.GAS || fluidType === FluidType.WATER) { return [TimeStep.DAY] } - logStack('error', 'Unkown FluidType') - Sentry.captureException({ error: 'Unkown FluidType' }) + logStack('error', 'Unknown FluidType') + Sentry.captureException({ error: 'Unknown FluidType' }) throw new Error() } @@ -239,11 +239,11 @@ const applyPrices = async (client: Client, fluidType: FluidType) => { const cdm = new ConsumptionDataManager(client) const qr = new QueryRunner(client) - // Synchro dbprices with remote prices + // Synchro db prices with remote prices const firstEditedPriceDate = await synchroPricesToUpdate(client, fluidType) const firstDataDate = await cdm.fetchAllFirstDateData([fluidType]) const prices = await fluidsPricesService.getAllPrices() - // Prices data exsit + // Prices data exist if (prices.length > 0) { logStack('debug', 'fluidPrices data found') const firstMinuteData = await cdm.getFirstDataDateFromDoctypeWithPrice( @@ -253,8 +253,7 @@ const applyPrices = async (client: Client, fluidType: FluidType) => { // If there is data, update hourly data and daily data if ( - firstDataDate && - firstDataDate[0] && + firstDataDate?.[0] && (firstMinuteData || firstEditedPriceDate !== null) ) { const today = DateTime.now() @@ -327,10 +326,9 @@ const applyPrices = async (client: Client, fluidType: FluidType) => { 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.data.forEach((element: DataloadEntity) => { - element.price = element.load * priceData.price - }) + data?.data.forEach((element: DataloadEntity) => { + element.price = element.load * priceData.price + }) // Save updated docs await cdm.saveDocs(data.data) } diff --git a/src/targets/services/monthlyReportNotification.ts b/src/targets/services/monthlyReportNotification.ts index 33bca041bb55e546a208afce0b1a586ef6f51629..82d62f731dc40dfbb374a01b227c858b45f950a8 100644 --- a/src/targets/services/monthlyReportNotification.ts +++ b/src/targets/services/monthlyReportNotification.ts @@ -88,8 +88,7 @@ const buildConsumptionText = async (client: Client) => { } if (consumption[FluidType.GAS]) { const value = - consumption[FluidType.GAS] && - consumption[FluidType.GAS].percentageVariation !== null + consumption[FluidType.GAS]?.percentageVariation !== null ? consumption[FluidType.GAS].percentageVariation : 0 if (value) { @@ -176,7 +175,7 @@ const monthlyReportNotification = async ({ logStack('info', 'Fetching user profile...') const upm = new ProfileService(client) let userProfil = await upm.getProfile() - if (!userProfil || !userProfil.sendAnalysisNotification) { + if (!userProfil?.sendAnalysisNotification) { logStack( 'info', 'End of process - Report Notification disabled in user profile' diff --git a/src/targets/services/service.ts b/src/targets/services/service.ts index c0788e1ffd2154653da9c9bd8e48822ed9900418..b9cad1f0e22ab95c13ebbc8f3885a79bf55ffcd7 100644 --- a/src/targets/services/service.ts +++ b/src/targets/services/service.ts @@ -16,8 +16,7 @@ export const runService = (service: Function) => { const client = CozyClient.fromEnv(process.env, { schema }) - return service({ client }).catch((e: ExceptionInformation) => { - // eslint-disable-next-line no-console + return service({ client }).catch((e: unknown) => { console.error(e) process.exit(1) }) diff --git a/src/types/cozy-client.d.ts b/src/types/cozy-client.d.ts index b6186859507384142c042f203c65f2ad4276aedd..c6784da3d6c2f5140852b3acb7907fd0e4f44926 100644 --- a/src/types/cozy-client.d.ts +++ b/src/types/cozy-client.d.ts @@ -1,5 +1,5 @@ +import { RealtimePlugin, TRealtimePlugin } from 'cozy-realtime' import * as CozyStackClient from 'cozy-stack-client' -import { TRealtimePlugin, RealtimePlugin } from 'cozy-realtime' import { TDoctype } from 'doctypes' import { Relation } from 'models' @@ -85,7 +85,6 @@ declare module 'cozy-client' { export class Client { appMetadata: { version: string; slug: string } options: ClientLogin - idCounter: number isLogged: boolean instanceOptions: ClientInstanceOpts links: unknown diff --git a/src/utils/date.spec.ts b/src/utils/date.spec.ts index ea24f0a3f3eabb5c1e5e7c9c5dcd1ff1c866ebf8..0ce85152d330c353f1319a45a3f1a86b11099d40 100644 --- a/src/utils/date.spec.ts +++ b/src/utils/date.spec.ts @@ -2,16 +2,16 @@ import { FluidType } from 'enum/fluid.enum' import { TimeStep } from 'enum/timeStep.enum' import { DateTime } from 'luxon' import { Dataload } from 'models' -import { graphData } from '../../tests/__mocks__/datachartData.mock' +import { graphData } from '../../tests/__mocks__/chartData.mock' import { compareDates, - isLastDateReached, - isLastPeriodReached, - getLagDays, convertDateToMonthString, + convertDateToMonthYearString, convertDateToShortDateString, getActualAnalysisDate, - convertDateToMonthYearString, + getLagDays, + isLastDateReached, + isLastPeriodReached, } from './date' describe('date utils', () => { @@ -172,14 +172,14 @@ describe('date utils', () => { }) describe('default', () => { - it('should return false', () => { + it('should return false for default case', () => { const result = isLastDateReached( DateTime.local() .setZone('utc', { keepLocalTime: true, }) .minus({ years: 1 }), - 0 + 0 as TimeStep ) expect(result).toBe(false) }) @@ -335,7 +335,7 @@ describe('date utils', () => { keepLocalTime: true, }) .minus({ years: 1 }), - 0 + 0 as TimeStep ) expect(result).toBe(false) }) @@ -363,7 +363,7 @@ describe('date utils', () => { expect(result).toBe(2) }) - it('it should return when there is only ELECTRICTY Fluid Type', () => { + it('it should return when there is only ELECTRICITY Fluid Type', () => { const result = getLagDays([FluidType.ELECTRICITY]) expect(result).toBe(1) }) @@ -373,7 +373,7 @@ describe('date utils', () => { const actualData: Dataload[] = graphData.actualData it('should return an empty string when the TimePeriod is unknown', () => { - const result = convertDateToShortDateString(null, 99) + const result = convertDateToShortDateString(null, 0 as TimeStep) expect(result).toBe('') }) diff --git a/src/utils/date.ts b/src/utils/date.ts index 7ee3c6ad01dc17cb8667f1d8b07039650342d707..06eb684e8cda10b88af807fc40287068ef99cc16 100644 --- a/src/utils/date.ts +++ b/src/utils/date.ts @@ -1,6 +1,6 @@ -import { DateTime } from 'luxon' -import { TimeStep } from 'enum/timeStep.enum' import { FluidType } from 'enum/fluid.enum' +import { TimeStep } from 'enum/timeStep.enum' +import { DateTime } from 'luxon' import { Dataload } from 'models' export function compareDates(dateA: DateTime, dateB: DateTime) { diff --git a/src/utils/hash.spec.ts b/src/utils/hash.spec.ts index 875565bcce2144fa3ba8cbfaae030449e8e6b294..de6088124587eb47497887e60b4ea0af7f278b73 100644 --- a/src/utils/hash.spec.ts +++ b/src/utils/hash.spec.ts @@ -1,11 +1,11 @@ -import { hashFile } from './hash' import { ecogesturesData } from '../../tests/__mocks__/ecogesturesData.mock' +import { hashFile } from './hash' describe('hash utilis test', () => { describe('hashFile test', () => { it('should return the correct hash of the file', () => { const result = hashFile(ecogesturesData) - expect(result).toBe('a4bfebe7779dbf65f92591b2b6226ac7eb78097e') + expect(result).toBe('21c72fc0b67b0393ee457a25956703ef17b5b724') }) }) }) diff --git a/src/utils/matomoTracker.ts b/src/utils/matomoTracker.ts index 1fe084049f77000e7520041bd74f56d530e58765..58c5964b341251e2bf39ebaccc0bfa840faa9b96 100644 --- a/src/utils/matomoTracker.ts +++ b/src/utils/matomoTracker.ts @@ -1,4 +1,3 @@ -import { readCozyDataFromDOM } from 'cozy-ui/transpiled/react/helpers/appDataset' import { History } from 'history' import { Location } from 'react-router' @@ -64,22 +63,6 @@ export default class MatomoTracker { window._paq.push(args) } - configure() { - let cozyDomain - let userId - const root: any = document.querySelector('[role=application]') - if (root?.dataset) { - cozyDomain = readCozyDataFromDOM('cozyDomain') - } - if (cozyDomain) { - userId = cozyDomain - const indexOfPort = cozyDomain.indexOf(':') - if (indexOfPort >= 0) { - userId = userId.substring(0, indexOfPort) - } - } - } - /** If matomo find a cookie "mtm_consent_removed" tracking will not be sent */ track(loc: Location) { if (typeof window === 'undefined') { diff --git a/src/utils/picto.spec.ts b/src/utils/picto.spec.ts index 29258cd1f3fa72e1fa161772f2963c19bd50bac8..422ec60c8630a678d1d7eeaec81be58fbd237bc3 100644 --- a/src/utils/picto.spec.ts +++ b/src/utils/picto.spec.ts @@ -1,29 +1,31 @@ -import { FluidType } from 'enum/fluid.enum' -import ElecIcon from '../assets/icons/visu/elec.svg' -import WaterIcon from '../assets/icons/visu/water.svg' -import GasIcon from '../assets/icons/visu/gas.svg' -import ElecSmallIcon from '../assets/icons/visu/elec-small.svg' -import WaterSmallIcon from '../assets/icons/visu/water-small.svg' -import GasSmallIcon from '../assets/icons/visu/gas-small.svg' import AddElecIcon from 'assets/icons/ico/add-elec.svg' -import AddWaterIcon from 'assets/icons/ico/add-water.svg' import AddGasIcon from 'assets/icons/ico/add-gas.svg' +import AddWaterIcon from 'assets/icons/ico/add-water.svg' +import iconEglWhiteLogo from 'assets/icons/visu/egl-logo-white.svg' +import iconEglLogo from 'assets/icons/visu/egl-logo.svg' import ElecParamIcon from 'assets/icons/visu/elec-param.svg' -import WaterParamIcon from 'assets/icons/visu/water-param.svg' -import GasParamIcon from 'assets/icons/visu/gas-param.svg' -import MultiIcon from 'assets/icons/visu/multi-icon.svg' -import iconEnedisLogo from 'assets/icons/visu/enedis-logo.svg' import iconEnedisWhiteLogo from 'assets/icons/visu/enedis-logo-white.svg' -import iconGrdfLogo from 'assets/icons/visu/grdf-logo.svg' +import iconEnedisLogo from 'assets/icons/visu/enedis-logo.svg' +import GasParamIcon from 'assets/icons/visu/gas-param.svg' import iconGrdfWhiteLogo from 'assets/icons/visu/grdf-logo-white.svg' -import iconEglLogo from 'assets/icons/visu/egl-logo.svg' -import iconEglWhiteLogo from 'assets/icons/visu/egl-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 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' +import GasIcon from '../assets/icons/visu/gas.svg' +import WaterSmallIcon from '../assets/icons/visu/water-small.svg' +import WaterIcon from '../assets/icons/visu/water.svg' import { getAddPicto, getParamPicto, getPartnerPicto, getPicto } from './picto' -describe('picto utilis test', () => { +const unknownFluidType = 99 as FluidType + +describe('picto utils test', () => { describe('getPicto test', () => { - describe('case ELECTRICTY', () => { - it('should return Electricty Icon', () => { + describe('case ELECTRICITY', () => { + it('should return Electricity Icon', () => { const result = getPicto(FluidType.ELECTRICITY) expect(result).toBe(ElecIcon) }) @@ -65,7 +67,7 @@ describe('picto utilis test', () => { }) describe('case default', () => { it('should return default Icon', () => { - const result = getPicto(4) + const result = getPicto(unknownFluidType) expect(result).toBe(ElecIcon) }) }) @@ -87,7 +89,7 @@ describe('picto utilis test', () => { expect(result).toBe(AddGasIcon) }) it('should return default Icon', () => { - const result = getPicto(4) + const result = getPicto(unknownFluidType) expect(result).toBe(ElecIcon) }) }) @@ -108,7 +110,7 @@ describe('picto utilis test', () => { expect(result).toBe(GasParamIcon) }) it('should return default Icon', () => { - const result = getPicto(4) + const result = getPicto(unknownFluidType) expect(result).toBe(ElecParamIcon) }) }) diff --git a/src/utils/picto.ts b/src/utils/picto.ts index 6f5d9e5b5b934c3d2ff2d6a85bf797428c2510c5..a5c2b78cfd9be3e1cae4e3ecdfb51fec480b77c5 100644 --- a/src/utils/picto.ts +++ b/src/utils/picto.ts @@ -1,33 +1,33 @@ -import ElecIcon from '../assets/icons/visu/elec.svg' -import ElecUnactive from '../assets/icons/visu/elec-grey.svg' -import WaterIcon from '../assets/icons/visu/water.svg' -import WaterUnactive from '../assets/icons/visu/water-grey.svg' -import GasIcon from '../assets/icons/visu/gas.svg' -import GasUnactive from '../assets/icons/visu/gas-grey.svg' -import ElecSmallIcon from '../assets/icons/visu/elec-small.svg' -import WaterSmallIcon from '../assets/icons/visu/water-small.svg' -import GasSmallIcon from '../assets/icons/visu/gas-small.svg' import AddElecIcon from 'assets/icons/ico/add-elec.svg' -import AddWaterIcon from 'assets/icons/ico/add-water.svg' import AddGasIcon from 'assets/icons/ico/add-gas.svg' -import ElecParamIcon from 'assets/icons/visu/elec-param.svg' -import Multi from 'assets/icons/visu/multi.svg' -import MultiUnactive from 'assets/icons/visu/multi-grey.svg' -import DisconnectedActive from 'assets/icons/visu/disconnected.svg' +import AddWaterIcon from 'assets/icons/ico/add-water.svg' import Disconnected from 'assets/icons/visu/disconnected-grey.svg' -import WaterParamIcon from 'assets/icons/visu/water-param.svg' -import GasParamIcon from 'assets/icons/visu/gas-param.svg' -import iconEnedisLogo from 'assets/icons/visu/enedis-logo.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 ElecParamIcon from 'assets/icons/visu/elec-param.svg' import iconEnedisWhiteLogo from 'assets/icons/visu/enedis-logo-white.svg' -import iconGrdfLogo from 'assets/icons/visu/grdf-logo.svg' +import iconEnedisLogo from 'assets/icons/visu/enedis-logo.svg' +import GasParamIcon from 'assets/icons/visu/gas-param.svg' import iconGrdfWhiteLogo from 'assets/icons/visu/grdf-logo-white.svg' -import iconEglLogo from 'assets/icons/visu/egl-logo.svg' -import iconEglWhiteLogo from 'assets/icons/visu/egl-logo-white.svg' -import { FluidType } from '../enum/fluid.enum' +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 WaterParamIcon from 'assets/icons/visu/water-param.svg' 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 FuildType enum + * Return an icon corresponding to FluidType enum * @param type FluidType */ export function getPicto(type: FluidType, small = false) { @@ -45,7 +45,7 @@ export function getPicto(type: FluidType, small = false) { } } /** - * Return an icon corresponding to add FuildType enum + * Return an icon corresponding to add FluidType enum * @param type FluidType */ export function getAddPicto(type: FluidType) { @@ -74,55 +74,43 @@ export function getParamPicto(type: FluidType) { } } +const getIcon = ( + active: boolean, + connected: boolean, + activeIcon: string, + inactiveIcon: string +) => { + if (connected) { + return active ? activeIcon : inactiveIcon + } else { + return active ? DisconnectedActive : Disconnected + } +} + /** - * Return an icon corresponding to FuildType enum - * @param type FluidType + * Returns the appropriate icon for a given fluid type and connection status */ export function getNavPicto( - type: FluidType, + fluidType: FluidType, active: boolean, connected: boolean ) { - switch (type) { + switch (fluidType) { case FluidType.ELECTRICITY: - return connected - ? active - ? ElecSmallIcon - : ElecUnactive - : active - ? DisconnectedActive - : Disconnected + return getIcon(active, connected, ElecSmallIcon, ElecUnactive) case FluidType.WATER: - return connected - ? active - ? WaterSmallIcon - : WaterUnactive - : active - ? DisconnectedActive - : Disconnected + return getIcon(active, connected, WaterSmallIcon, WaterUnactive) case FluidType.GAS: - return connected - ? active - ? GasSmallIcon - : GasUnactive - : active - ? DisconnectedActive - : Disconnected + return getIcon(active, connected, GasSmallIcon, GasUnactive) case FluidType.MULTIFLUID: - return connected - ? active - ? Multi - : MultiUnactive - : active - ? DisconnectedActive - : Disconnected + return getIcon(active, connected, Multi, MultiUnactive) default: return ElecIcon } } /** - * Return an partner icon corresponding to FuildType enum + * Return an partner icon corresponding to FluidType enum * @param slug string * @param blackLogo boolean - define the color of the logo (black or white) */ diff --git a/src/utils/utils.spec.ts b/src/utils/utils.spec.ts index 0d32300e771140ca2d521e080d2d43cbce2f8161..ade89ea085183091c9eb27b7192d9a52cc99d8a1 100644 --- a/src/utils/utils.spec.ts +++ b/src/utils/utils.spec.ts @@ -1,6 +1,6 @@ -import { DateTime } from 'luxon' import { Season } from 'enum/ecogesture.enum' import { FluidType } from 'enum/fluid.enum' +import { DateTime } from 'luxon' import { formatNumberValues, getChallengeTitleWithLineReturn, diff --git a/src/utils/utils.ts b/src/utils/utils.ts index 5539950b870e11d89bdc6ebffbf25f1fedf14241..4386dde74532ec779566ec7e83160797b1a96cab 100644 --- a/src/utils/utils.ts +++ b/src/utils/utils.ts @@ -24,11 +24,12 @@ export function getKonnectorUpdateError(type: string) { return KonnectorUpdate.ERROR_UPDATE_OAUTH case 'LOGIN_FAILED': return KonnectorUpdate.LOGIN_FAILED + case 'CHALLENGE_ASKED': + return KonnectorUpdate.ERROR_CONSENT_FORM_GAS default: return KonnectorUpdate.ERROR_UPDATE } } - export function isKonnectorActive( fluidStatus: FluidStatus[], fluidType: FluidType @@ -147,14 +148,14 @@ export const getPreviousMonthName = (date: DateTime) => { 'octobre', 'novembre', 'décembre', - ] + ] as const return monthNames[date.month - 1] } /** * Return month string according to month index * @param date - DateTime - * @returns month in french + * @returns "de" month in french */ export const getMonthNameWithPrep = (date: DateTime) => { const monthNames = [ @@ -170,7 +171,7 @@ export const getMonthNameWithPrep = (date: DateTime) => { `d'octobre`, 'de novembre', 'de décembre', - ] + ] as const return monthNames[date.month - 1] } @@ -231,9 +232,9 @@ export const getSeason = (): Season => { * @returns Simone\nVEILLE */ export const getChallengeTitleWithLineReturn = (userChallengeId: string) => { - for (const chalModel of challengeData) { - if (chalModel._id === userChallengeId) { - return chalModel.title_line_return + for (const challenge of challengeData) { + if (challenge._id === userChallengeId) { + return challenge.title_line_return } } } diff --git a/tests/__mocks__/actionData.mock.ts b/tests/__mocks__/actionData.mock.ts index 538a3fba4841f3708bde6512d6188f904c7ad04b..5cd2ef51f5264989d86f2f3604577f0795b516ef 100644 --- a/tests/__mocks__/actionData.mock.ts +++ b/tests/__mocks__/actionData.mock.ts @@ -1,4 +1,4 @@ -import { Season } from 'enum/ecogesture.enum' +import { EquipmentType, Season } from 'enum/ecogesture.enum' import { Ecogesture } from 'models' export const defaultEcogestureData: Ecogesture[] = [ @@ -145,14 +145,14 @@ export const AllEcogestureData: Ecogesture[] = [ shortName: 'Coup de vent', longName: 'Je ferme mes fenêtres quand la climatisation est en marche', longDescription: - "Cela permet de garder la fraicheur à l'intérieur. Le climatiseur n'est pas là pour refroidir la rue mais bien la pièce.", + "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.", impactLevel: 8, efficiency: 1, difficulty: 1, room: [0], season: Season.SUMMER, equipment: true, - equipmentType: [0], + equipmentType: [EquipmentType.AIR_CONDITIONING], equipmentInstallation: true, investment: null, action: false, diff --git a/tests/__mocks__/datachartData.mock.ts b/tests/__mocks__/chartData.mock.ts similarity index 100% rename from tests/__mocks__/datachartData.mock.ts rename to tests/__mocks__/chartData.mock.ts diff --git a/tests/__mocks__/ecogesturesData.mock.ts b/tests/__mocks__/ecogesturesData.mock.ts index e20933fb6b988babb8d6202932739e5914a4f7fe..3e7b7d7adb9aff80137fe2fb5c7be6381d0256b1 100644 --- a/tests/__mocks__/ecogesturesData.mock.ts +++ b/tests/__mocks__/ecogesturesData.mock.ts @@ -35,7 +35,7 @@ export const ecogesturesData: Ecogesture[] = [ fluidTypes: [FluidType.ELECTRICITY], id: 'ECOGESTURE002', longDescription: - "Cela permet de garder la fraicheur à l'intérieur. Le climatiseur n'est pas là pour refroidir la rue mais bien la pièce.", + "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, @@ -123,7 +123,7 @@ export const ecogesturesHeatingData: Ecogesture[] = [ fluidTypes: [FluidType.GAS], id: 'ECOGESTURE002', longDescription: - "Cela permet de garder la fraicheur à l'intérieur. Le climatiseur n'est pas là pour refroidir la rue mais bien la pièce.", + "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.HEATING, @@ -210,7 +210,7 @@ export const ecogesturesECSData: Ecogesture[] = [ fluidTypes: [FluidType.GAS], id: 'ECOGESTURE002', longDescription: - "Cela permet de garder la fraicheur à l'intérieur. Le climatiseur n'est pas là pour refroidir la rue mais bien la pièce.", + "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.ECS, @@ -298,7 +298,7 @@ export const ecogesturesCookingData: Ecogesture[] = [ fluidTypes: [FluidType.GAS], id: '002', longDescription: - "Cela permet de garder la fraicheur à l'intérieur. Le climatiseur n'est pas là pour refroidir la rue mais bien la pièce.", + "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, @@ -414,7 +414,7 @@ export const ecogesturesElecSpecificData: Ecogesture[] = [ fluidTypes: [FluidType.GAS], id: '002', longDescription: - "Cela permet de garder la fraicheur à l'intérieur. Le climatiseur n'est pas là pour refroidir la rue mais bien la pièce.", + "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, @@ -501,7 +501,7 @@ export const ecogesturesAirConditioningData: Ecogesture[] = [ fluidTypes: [FluidType.GAS], id: '002', longDescription: - "Cela permet de garder la fraicheur à l'intérieur. Le climatiseur n'est pas là pour refroidir la rue mais bien la pièce.", + "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, @@ -588,7 +588,7 @@ export const ecogesturesColdWaterData: Ecogesture[] = [ fluidTypes: [FluidType.WATER], id: '002', longDescription: - "Cela permet de garder la fraicheur à l'intérieur. Le climatiseur n'est pas là pour refroidir la rue mais bien la pièce.", + "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, @@ -636,6 +636,7 @@ export const BoilerEcogesture: Ecogesture[] = [ actionDuration: 3, doing: false, objective: false, + viewedInSelection: false, _id: '001', _rev: '1-67f1ea36efdd892c96bf64a8943154cd', _type: 'com.grandlyon.ecolyo.ecogesture', @@ -664,6 +665,7 @@ export const BoilerEcogestureFalse: Ecogesture[] = [ actionDuration: 3, doing: false, objective: false, + viewedInSelection: false, _id: '001', _rev: '1-67f1ea36efdd892c96bf64a8943154cd', _type: 'com.grandlyon.ecolyo.ecogesture', diff --git a/tests/__mocks__/explorationData.mock.ts b/tests/__mocks__/explorationData.mock.ts index 75e71ac1a5bccf66d8915c80f3003ff2ebfe1867..a5ea25b2a4725c8c036c236944127b4d28732776 100644 --- a/tests/__mocks__/explorationData.mock.ts +++ b/tests/__mocks__/explorationData.mock.ts @@ -178,7 +178,6 @@ export const allExplorationEntities: ExplorationEntity[] = [ fluid_condition: [], message_success: 'Vous nous avez envoyé votre avis sur le service', }, - { id: 'EXPLORATION006', state: 0, @@ -205,7 +204,7 @@ export const allExplorationEntities: ExplorationEntity[] = [ }, ] -export const UserExplorationStarted: UserExploration = { +export const userExplorationStarted: UserExploration = { id: 'EXPLORATION001', state: UserExplorationState.ONGOING, description: 'Avoir complété son profil', @@ -219,7 +218,7 @@ export const UserExplorationStarted: UserExploration = { message_success: 'Vous avez complété votre profil ou refait un tour dans votre profil', } -export const UserExplorationDone: UserExploration = { +export const userExplorationDone: UserExploration = { id: 'EXPLORATION001', state: UserExplorationState.DONE, description: 'Avoir complété son profil', @@ -234,7 +233,7 @@ export const UserExplorationDone: UserExploration = { 'Vous avez complété votre profil ou refait un tour dans votre profil', } -export const UserExplorationUnlocked: UserExploration = { +export const userExplorationUnlocked: UserExploration = { id: 'EXPLORATION001', state: UserExplorationState.UNLOCKED, description: 'Avoir complété son profil', diff --git a/tests/__mocks__/fluidStatusData.mock.ts b/tests/__mocks__/fluidStatusData.mock.ts index b86ae51b88dc694cabb41b74bc34fe2426c17f26..684bd3346c7dae958172d46530bf775624788b57 100644 --- a/tests/__mocks__/fluidStatusData.mock.ts +++ b/tests/__mocks__/fluidStatusData.mock.ts @@ -9,6 +9,7 @@ export const fluidStatusData: FluidStatus[] = [ { fluidType: 0, status: FluidState.KONNECTOR_NOT_FOUND, + maintenance: false, firstDataDate: DateTime.fromISO('2019-09-01T00:00:00.000Z', { zone: 'utc', }), @@ -34,6 +35,7 @@ export const fluidStatusData: FluidStatus[] = [ { fluidType: 1, status: FluidState.KONNECTOR_NOT_FOUND, + maintenance: false, firstDataDate: DateTime.fromISO('2019-09-01T00:00:00.000Z', { zone: 'utc', }), @@ -59,6 +61,7 @@ export const fluidStatusData: FluidStatus[] = [ { fluidType: 2, status: FluidState.KONNECTOR_NOT_FOUND, + maintenance: false, firstDataDate: DateTime.fromISO('2019-09-01T00:00:00.000Z', { zone: 'utc', }), @@ -99,6 +102,7 @@ export const fluidStatusConnectedData: FluidStatus[] = [ { fluidType: 0, status: FluidState.DONE, + maintenance: false, firstDataDate: DateTime.fromISO('2019-09-01T00:00:00.000Z', { zone: 'utc', }), @@ -135,6 +139,7 @@ export const fluidStatusConnectedData: FluidStatus[] = [ { fluidType: 1, status: FluidState.DONE, + maintenance: false, firstDataDate: DateTime.fromISO('2019-09-01T00:00:00.000Z', { zone: 'utc', }), @@ -160,6 +165,7 @@ export const fluidStatusConnectedData: FluidStatus[] = [ { fluidType: 2, status: FluidState.DONE, + maintenance: false, firstDataDate: DateTime.fromISO('2019-09-01T00:00:00.000Z', { zone: 'utc', }), @@ -186,6 +192,7 @@ export const fluidStatusConnectedData: FluidStatus[] = [ export const SgeStatusWithAccount: FluidStatus = { fluidType: 0, status: FluidState.KONNECTOR_NOT_FOUND, + maintenance: false, firstDataDate: DateTime.fromISO('2019-09-01T00:00:00.000Z', { zone: 'utc', }), diff --git a/tests/__mocks__/globalStateData.mock.ts b/tests/__mocks__/globalStateData.mock.ts index 44350809d4a0d10537ffbc30412287c74c2a2270..a657805557f7463252c28dbe1f125f54bba01992 100644 --- a/tests/__mocks__/globalStateData.mock.ts +++ b/tests/__mocks__/globalStateData.mock.ts @@ -1,3 +1,4 @@ +/* eslint-disable camelcase */ import { FluidState, FluidType } from 'enum/fluid.enum' import { FluidSlugType } from 'enum/fluidSlug.enum' import { ScreenType } from 'enum/screen.enum' @@ -17,10 +18,11 @@ export const globalStateData: GlobalState = { accepted: false, versionType: 'major', }, - openPartnersIssueModal: { - enedis: false, - egl: false, - grdf: false, + partnersInfo: { + egl_failure: false, + enedis_failure: false, + grdf_failure: false, + notification_activated: false, }, fluidStatus: [ { @@ -103,7 +105,6 @@ export const globalStateData: GlobalState = { dataConsent: false, pdlConfirm: false, shouldLaunchAccount: false, - openSGEForm: false, }, customPopupModal: { title: '', diff --git a/tests/__mocks__/modalStateData.mock.ts b/tests/__mocks__/modalStateData.mock.ts index b8543efe8952c02cf00c34420c88eb2c684d3a4e..be2d0569a842dda8b09edbef3c6d9e205e202d07 100644 --- a/tests/__mocks__/modalStateData.mock.ts +++ b/tests/__mocks__/modalStateData.mock.ts @@ -2,4 +2,9 @@ import { ModalState } from 'models' export const modalStateData: ModalState = { isFeedbacksOpen: false, + partnersIssueModal: { + egl: false, + enedis: false, + grdf: false, + }, } diff --git a/tests/__mocks__/profileType.mock.ts b/tests/__mocks__/profileType.mock.ts index 053abe45a2c98527349079023bf15af26b70a2a3..7dcd4672215673997ab49455e9c3b743ba8ae30d 100644 --- a/tests/__mocks__/profileType.mock.ts +++ b/tests/__mocks__/profileType.mock.ts @@ -3,6 +3,7 @@ import { ConstructionYear, Floor, HotWaterEquipment, + HotWaterFluid, HousingType, IndividualInsulationWork, IndividualOrCollective, @@ -34,7 +35,7 @@ export const profileTypeData: ProfileType = { hotWater: IndividualOrCollective.INDIVIDUAL, hotWaterEquipment: HotWaterEquipment.OTHER, hotWaterFluid: 0, - housingType: HousingType.APPARTMENT, + housingType: HousingType.APARTMENT, individualInsulationWork: [], occupantsNumber: 2, outsideFacingWalls: OutsideFacingWalls.TWO, @@ -46,7 +47,7 @@ export const profileTypeData: ProfileType = { } export const mockProfileType: ProfileType = { - housingType: HousingType.APPARTMENT, + housingType: HousingType.APARTMENT, constructionYear: ConstructionYear.AFTER_1998, area: '43', occupantsNumber: 1, @@ -60,7 +61,7 @@ export const mockProfileType: ProfileType = { hasReplacedHeater: ThreeChoicesAnswer.NO, hotWaterEquipment: HotWaterEquipment.THERMODYNAMIC, warmingFluid: WarmingType.ELECTRICITY, - hotWaterFluid: FluidType.ELECTRICITY, + hotWaterFluid: HotWaterFluid.ELECTRICITY, cookingFluid: FluidType.ELECTRICITY, updateDate: DateTime.fromISO('2021-01-01T00:00:00.000Z', { zone: 'utc', @@ -69,7 +70,7 @@ export const mockProfileType: ProfileType = { } export const mockEstimatedConsumption = 3182 export const mockCorrectedConsumption = 3500 -//For the month of march +// For the month of march export const mockMonthConsumption = 439 export const mockMonthCookingConsumption = 17 @@ -83,7 +84,7 @@ export const mockMonthEcsConsumptionOther = 166 export const mockMonthEcsConsumptionThermo = 110 export const mockProfileType1: ProfileType = { - housingType: HousingType.APPARTMENT, + housingType: HousingType.APARTMENT, constructionYear: ConstructionYear.BETWEEN_1948_AND_1974, area: '43', occupantsNumber: 2, @@ -97,7 +98,7 @@ export const mockProfileType1: ProfileType = { hasReplacedHeater: ThreeChoicesAnswer.NO, hotWaterEquipment: HotWaterEquipment.SOLAR, warmingFluid: WarmingType.ELECTRICITY, - hotWaterFluid: FluidType.ELECTRICITY, + hotWaterFluid: HotWaterFluid.ELECTRICITY, cookingFluid: FluidType.ELECTRICITY, updateDate: DateTime.fromISO('2021-01-01T00:00:00.000Z', { zone: 'utc', @@ -106,7 +107,7 @@ export const mockProfileType1: ProfileType = { } export const mockEstimatedConsumption1 = 6450 export const mockCorrectedConsumption1 = 6450 -//For the month of February +// For the month of February export const mockMonthConsumption1 = 1174 export const mockMonthEcsConsumption1Solar = 134 @@ -126,7 +127,7 @@ export const mockProfileType2: ProfileType = { hasReplacedHeater: ThreeChoicesAnswer.YES, hotWaterEquipment: HotWaterEquipment.SOLAR, warmingFluid: WarmingType.ELECTRICITY, - hotWaterFluid: FluidType.ELECTRICITY, + hotWaterFluid: HotWaterFluid.ELECTRICITY, cookingFluid: FluidType.ELECTRICITY, updateDate: DateTime.fromISO('2021-01-01T00:00:00.000Z', { zone: 'utc', @@ -135,7 +136,7 @@ export const mockProfileType2: ProfileType = { } export const mockEstimatedConsumption2 = 16560 export const mockCorrectedConsumption2 = 15411 -//For the month of January +// For the month of January export const mockMonthConsumption2 = 3000 export const mockTestProfile1: ProfileType = { @@ -153,7 +154,7 @@ export const mockTestProfile1: ProfileType = { hasReplacedHeater: ThreeChoicesAnswer.NO, hotWaterEquipment: HotWaterEquipment.SOLAR, warmingFluid: WarmingType.ELECTRICITY, - hotWaterFluid: FluidType.GAS, + hotWaterFluid: HotWaterFluid.GAS, cookingFluid: FluidType.GAS, updateDate: DateTime.fromISO('2021-01-01T00:00:00.000Z', { zone: 'utc', @@ -204,7 +205,7 @@ export const mockMonthlyForecastJanuaryTestProfile1: MonthlyForecast = { } export const mockTestProfile2: ProfileType = { - housingType: HousingType.APPARTMENT, + housingType: HousingType.APARTMENT, constructionYear: ConstructionYear.BETWEEN_1975_AND_1989, area: '50', occupantsNumber: 2, @@ -218,7 +219,7 @@ export const mockTestProfile2: ProfileType = { hasReplacedHeater: ThreeChoicesAnswer.NO, hotWaterEquipment: HotWaterEquipment.OTHER, warmingFluid: WarmingType.ELECTRICITY, - hotWaterFluid: FluidType.ELECTRICITY, + hotWaterFluid: HotWaterFluid.ELECTRICITY, cookingFluid: FluidType.ELECTRICITY, updateDate: DateTime.fromISO('2021-01-01T00:00:00.000Z', { zone: 'utc', @@ -270,7 +271,7 @@ export const mockMonthlyForecastJanuaryTestProfile2: MonthlyForecast = { } export const mockTestProfile3: ProfileType = { - housingType: HousingType.APPARTMENT, + housingType: HousingType.APARTMENT, constructionYear: ConstructionYear.BETWEEN_1948_AND_1974, area: '50', occupantsNumber: 2, @@ -379,6 +380,7 @@ export const mockProfileTypeAnswers: ProfileTypeAnswer[] = [ WarmingType.GAS, WarmingType.WOOD, WarmingType.FUEL, + WarmingType.OTHER, ], }, { @@ -409,7 +411,11 @@ export const mockProfileTypeAnswers: ProfileTypeAnswer[] = [ { type: ProfileTypeFormType.SINGLE_CHOICE, attribute: 'hotWaterFluid', - choices: [FluidType.ELECTRICITY, FluidType.GAS], + choices: [ + HotWaterFluid.ELECTRICITY, + HotWaterFluid.GAS, + HotWaterFluid.OTHER, + ], }, { type: ProfileTypeFormType.SINGLE_CHOICE, diff --git a/tests/__mocks__/store.ts b/tests/__mocks__/store.ts index a15e2e8033492356d231641805c5d913a0aa1fe2..7ef4e9327ce072d9432cbd93db6e41646be51ede 100644 --- a/tests/__mocks__/store.ts +++ b/tests/__mocks__/store.ts @@ -5,6 +5,7 @@ import { ConstructionYear, Floor, HotWaterEquipment, + HotWaterFluid, HousingType, IndividualInsulationWork, IndividualOrCollective, @@ -24,11 +25,13 @@ import { Profile, ProfileType, } from 'models' +import { ProfileEcogesture } from 'models/profileEcogesture.model' import configureStore from 'redux-mock-store' import thunkMiddleware from 'redux-thunk' -import { EcolyoState } from 'store' +import { AppActionsTypes, EcolyoState } from 'store' import mockClient from './client' import { mockProfileEcogesture } from './profileEcogesture.mock' + export const mockInitialGlobalState: GlobalState = { screenType: ScreenType.MOBILE, challengeExplorationNotification: false, @@ -36,7 +39,7 @@ export const mockInitialGlobalState: GlobalState = { challengeDuelNotification: false, analysisNotification: false, termsStatus: { - accepted: false, + accepted: true, versionType: 'init', }, customPopupModal: { @@ -45,10 +48,11 @@ export const mockInitialGlobalState: GlobalState = { description: '', endDate: '', }, - openPartnersIssueModal: { - enedis: false, - egl: false, - grdf: false, + partnersInfo: { + egl_failure: false, + enedis_failure: false, + grdf_failure: false, + notification_activated: false, }, releaseNotes: { show: false, @@ -233,7 +237,7 @@ export const mockInitialProfileState: Profile = { monthlyAnalysisDate: DateTime.fromISO('0000-01-01T00:00:00.000Z'), isProfileTypeCompleted: false, onboarding: { - isWelcomeSeen: false, + isWelcomeSeen: true, }, haveSeenEcogestureModal: false, activateHalfHourDate: DateTime.fromISO('0000-01-01T00:00:00.000Z'), @@ -258,7 +262,7 @@ export const mockInitialProfileTypeState: ProfileType = { hasReplacedHeater: ThreeChoicesAnswer.UNKNOWN, hotWaterEquipment: HotWaterEquipment.SOLAR, warmingFluid: WarmingType.ELECTRICITY, - hotWaterFluid: FluidType.ELECTRICITY, + hotWaterFluid: HotWaterFluid.ELECTRICITY, cookingFluid: FluidType.ELECTRICITY, updateDate: DateTime.fromISO('0000-01-01T00:00:00.000Z'), equipments: [], @@ -277,6 +281,11 @@ export const mockInitialChartState: ChartState = { export const mockInitialModalState: ModalState = { isFeedbacksOpen: false, + partnersIssueModal: { + enedis: false, + egl: false, + grdf: false, + }, } export const mockInitialChallengeState: ChallengeState = { @@ -285,7 +294,7 @@ export const mockInitialChallengeState: ChallengeState = { currentDataload: [], } -export const mockInitialEcolyoState = { +export const mockInitialEcolyoState: EcolyoState = { global: mockInitialGlobalState, profile: mockInitialProfileState, profileType: mockInitialProfileTypeState, @@ -296,16 +305,35 @@ export const mockInitialEcolyoState = { } const middlewares = [thunkMiddleware.withExtraArgument({ mockClient })] -const mockStore = configureStore<{ ecolyo: { global: GlobalState } }>( - middlewares -) +const mockStore = configureStore< + { + ecolyo: { + challenge: ChallengeState + chart: ChartState + global: GlobalState + modal: ModalState + profile: Profile + profileEcogesture: ProfileEcogesture + profileType: ProfileType + } + cozy: unknown + }, + AppActionsTypes +>(middlewares) const mockedStore = mockStore({ ecolyo: mockInitialEcolyoState, + cozy: {}, }) -export const createMockStore = (initialState: EcolyoState) => { +/** + * Create a mocked Ecolyo store with the default mockInitialEcolyoState + */ +export const createMockEcolyoStore = ( + initialState: EcolyoState = mockInitialEcolyoState +) => { return mockStore({ ecolyo: initialState, + cozy: {}, }) } diff --git a/tests/__mocks__/userChallengeData.mock.ts b/tests/__mocks__/userChallengeData.mock.ts index ba363b126a758d8362d9fc85a19427da31a3a84a..205338b0380ddbccaa9ab6cf3a2df8d79c26ca51 100644 --- a/tests/__mocks__/userChallengeData.mock.ts +++ b/tests/__mocks__/userChallengeData.mock.ts @@ -9,7 +9,7 @@ import { UserChallenge } from 'models' import { duelData, duelDefault } from './duelData.mock' import { explorationDefault, - UserExplorationUnlocked, + userExplorationUnlocked, } from './explorationData.mock' import { quizDefault, userQuiz } from './quizData.mock' @@ -30,7 +30,7 @@ export const userChallengeData: UserChallenge[] = [ startDate: null, endingDate: null, quiz: userQuiz, - exploration: UserExplorationUnlocked, + exploration: userExplorationUnlocked, action: { ecogesture: null, startDate: null, @@ -53,7 +53,7 @@ export const userChallengeData: UserChallenge[] = [ startDate: null, endingDate: null, quiz: userQuiz, - exploration: UserExplorationUnlocked, + exploration: userExplorationUnlocked, action: { ecogesture: null, startDate: null, @@ -76,7 +76,7 @@ export const userChallengeData: UserChallenge[] = [ startDate: null, endingDate: null, quiz: userQuiz, - exploration: UserExplorationUnlocked, + exploration: userExplorationUnlocked, action: { ecogesture: null, startDate: null, @@ -99,7 +99,7 @@ export const userChallengeData: UserChallenge[] = [ startDate: null, endingDate: null, quiz: userQuiz, - exploration: UserExplorationUnlocked, + exploration: userExplorationUnlocked, action: { ecogesture: null, startDate: null, @@ -122,7 +122,7 @@ export const userChallengeData: UserChallenge[] = [ startDate: null, endingDate: null, quiz: userQuiz, - exploration: UserExplorationUnlocked, + exploration: userExplorationUnlocked, action: { ecogesture: null, startDate: null, @@ -145,7 +145,7 @@ export const userChallengeData: UserChallenge[] = [ startDate: null, endingDate: null, quiz: userQuiz, - exploration: UserExplorationUnlocked, + exploration: userExplorationUnlocked, action: { ecogesture: null, startDate: null, diff --git a/tsconfig.json b/tsconfig.json index 037d4ebe9ccd92b00da869121ad3e3cb1e7bb416..02ef5015853296073d1fee881418debfea51057d 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -14,19 +14,10 @@ "isolatedModules": true, "noEmit": true, "jsx": "react", - "lib": [ - "esnext", - "dom" - ], + "lib": ["esnext", "dom"], "paths": { - "*": [ - "*", - "../node_modules/*", - "types/*" - ] + "*": ["*", "../node_modules/*", "types/*"] } }, - "include": [ - "src/**/*", "tests/**/*" - ] + "include": ["src/**/*", "tests/**/*"] } diff --git a/yarn.lock b/yarn.lock index 64de230e88f3da932dd72cdc2c458e9b92f71ef9..c062f94d85f70039eedc09dfd3f42f8e96734c99 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1662,6 +1662,18 @@ resolved "https://registry.yarnpkg.com/@emotion/weak-memoize/-/weak-memoize-0.2.5.tgz#8eed982e2ee6f7f4e44c253e12962980791efd46" integrity sha512-6U71C2Wp7r5XtFtQzYrW5iKFT67OixrSxjI4MptCHzdSVlgabczzqLe0ZSgnub/5Kp4hSbpDB1tMytZY9pwxxA== +"@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" + integrity sha512-v3oplH6FYCULtFuCeqyuTd9D2WKO937Dxdq+GmHOLL72TTRriLxz2VLlNfkZRsvj6PKnOPAtuT6dwrs/pA5DvA== + dependencies: + eslint-visitor-keys "^3.3.0" + +"@eslint-community/regexpp@^4.4.0": + version "4.4.0" + resolved "https://registry.yarnpkg.com/@eslint-community/regexpp/-/regexpp-4.4.0.tgz#3e61c564fcd6b921cb789838631c5ee44df09403" + integrity sha512-A9983Q0LnDGdLPjxyXQ00sbV+K+O+ko2Dr+CZigbHWtX9pNfxlaBkMR8X1CztI73zuEyEBXTVjx7CE+/VSwDiQ== + "@eslint/eslintrc@^0.4.3": version "0.4.3" resolved "https://registry.yarnpkg.com/@eslint/eslintrc/-/eslintrc-0.4.3.tgz#9e42981ef035beb3dd49add17acb96e8ff6f394c" @@ -1692,11 +1704,40 @@ 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== + dependencies: + ajv "^6.12.4" + debug "^4.3.2" + espree "^9.5.0" + globals "^13.19.0" + ignore "^5.2.0" + import-fresh "^3.2.1" + js-yaml "^4.1.0" + 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== + "@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== + dependencies: + "@humanwhocodes/object-schema" "^1.2.1" + debug "^4.1.1" + minimatch "^3.0.5" + "@humanwhocodes/config-array@^0.5.0": version "0.5.0" resolved "https://registry.yarnpkg.com/@humanwhocodes/config-array/-/config-array-0.5.0.tgz#1407967d4c6eecd7388f83acf1eaf4d0c6e58ef9" @@ -1715,6 +1756,11 @@ debug "^4.1.1" minimatch "^3.0.4" +"@humanwhocodes/module-importer@^1.0.1": + version "1.0.1" + resolved "https://registry.yarnpkg.com/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz#af5b2691a22b44be847b0ca81641c5fb6ad0172c" + integrity sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA== + "@humanwhocodes/object-schema@^1.2.0", "@humanwhocodes/object-schema@^1.2.1": version "1.2.1" resolved "https://registry.yarnpkg.com/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz#b520529ec21d8e5945a1851dfd1c32e94e39ff45" @@ -2110,7 +2156,7 @@ resolved "https://registry.yarnpkg.com/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz#5bd262af94e9d25bd1e71b05deed44876a222e8b" integrity sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A== -"@nodelib/fs.walk@^1.2.3": +"@nodelib/fs.walk@^1.2.3", "@nodelib/fs.walk@^1.2.8": version "1.2.8" resolved "https://registry.yarnpkg.com/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz#e95737e8bb6746ddedf69c556953494f196fe69a" integrity sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg== @@ -2807,10 +2853,10 @@ jest-diff "^26.0.0" pretty-format "^26.0.0" -"@types/jest@^29.0.0": - version "29.0.3" - resolved "https://registry.yarnpkg.com/@types/jest/-/jest-29.0.3.tgz#b61a5ed100850686b8d3c5e28e3a1926b2001b59" - integrity sha512-F6ukyCTwbfsEX5F2YmVYmM5TcTHy1q9P5rWlRbrk56KyMh3v9xRGUO3aa8+SkvMi0SHXtASJv1283enXimC0Og== +"@types/jest@^29.4.0": + version "29.4.0" + resolved "https://registry.yarnpkg.com/@types/jest/-/jest-29.4.0.tgz#a8444ad1704493e84dbf07bb05990b275b3b9206" + integrity sha512-VaywcGQ9tPorCX/Jkkni7RWGFfI11whqzs8dvxF41P17Z+z872thvEvlIbznjPJ02kl1HMX3LmLOonsj2n7HeQ== dependencies: expect "^29.0.0" pretty-format "^29.0.0" @@ -2961,6 +3007,11 @@ resolved "https://registry.yarnpkg.com/@types/scheduler/-/scheduler-0.16.2.tgz#1a62f89525723dde24ba1b01b092bf5df8ad4d39" integrity sha512-hppQEBDmlwhFAXKJX2KnWLYu5yMfi91yazPb2l+lbJiwW+wdo1gNeRA+3RgNSO39WYX2euey41KEwnqesU2Jew== +"@types/semver@^7.3.12": + version "7.3.13" + resolved "https://registry.yarnpkg.com/@types/semver/-/semver-7.3.13.tgz#da4bfd73f49bd541d28920ab0e2bf0ee80f71c91" + integrity sha512-21cFJr9z3g5dW8B0CVI9g2O9beqaThGQ6ZFBqHfwhzLDKUxaqTIy3vnfah/UPkfOiF2pLq+tGz+W8RyCskuslw== + "@types/stack-utils@^1.0.1": version "1.0.1" resolved "https://registry.yarnpkg.com/@types/stack-utils/-/stack-utils-1.0.1.tgz#0a851d3bd96498fa25c33ab7278ed3bd65f06c3e" @@ -2990,18 +3041,19 @@ dependencies: "@types/yargs-parser" "*" -"@typescript-eslint/eslint-plugin@^5.37.0": - version "5.37.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.37.0.tgz#5ccdd5d9004120f28fc6e717fb4b5c9bddcfbc04" - integrity sha512-Fde6W0IafXktz1UlnhGkrrmnnGpAo1kyX7dnyHHVrmwJOn72Oqm3eYtddrpOwwel2W8PAK9F3pIL5S+lfoM0og== +"@typescript-eslint/eslint-plugin@^5.56.0": + version "5.56.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.56.0.tgz#e4fbb4d6dd8dab3e733485c1a44a02189ae75364" + integrity sha512-ZNW37Ccl3oMZkzxrYDUX4o7cnuPgU+YrcaYXzsRtLB16I1FR5SHMqga3zGsaSliZADCWo2v8qHWqAYIj8nWCCg== dependencies: - "@typescript-eslint/scope-manager" "5.37.0" - "@typescript-eslint/type-utils" "5.37.0" - "@typescript-eslint/utils" "5.37.0" + "@eslint-community/regexpp" "^4.4.0" + "@typescript-eslint/scope-manager" "5.56.0" + "@typescript-eslint/type-utils" "5.56.0" + "@typescript-eslint/utils" "5.56.0" debug "^4.3.4" - functional-red-black-tree "^1.0.1" + grapheme-splitter "^1.0.4" ignore "^5.2.0" - regexpp "^3.2.0" + natural-compare-lite "^1.4.0" semver "^7.3.7" tsutils "^3.21.0" @@ -3015,14 +3067,14 @@ "@typescript-eslint/typescript-estree" "5.30.5" debug "^4.3.4" -"@typescript-eslint/parser@^5.37.0": - version "5.37.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-5.37.0.tgz#c382077973f3a4ede7453fb14cadcad3970cbf3b" - integrity sha512-01VzI/ipYKuaG5PkE5+qyJ6m02fVALmMPY3Qq5BHflDx3y4VobbLdHQkSMg9VPRS4KdNt4oYTMaomFoHonBGAw== +"@typescript-eslint/parser@^5.56.0": + version "5.56.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-5.56.0.tgz#42eafb44b639ef1dbd54a3dbe628c446ca753ea6" + integrity sha512-sn1OZmBxUsgxMmR8a8U5QM/Wl+tyqlH//jTqCg8daTAmhAk26L2PFhcqPLlYBhYUJMZJK276qLXlHN3a83o2cg== dependencies: - "@typescript-eslint/scope-manager" "5.37.0" - "@typescript-eslint/types" "5.37.0" - "@typescript-eslint/typescript-estree" "5.37.0" + "@typescript-eslint/scope-manager" "5.56.0" + "@typescript-eslint/types" "5.56.0" + "@typescript-eslint/typescript-estree" "5.56.0" debug "^4.3.4" "@typescript-eslint/scope-manager@5.30.5": @@ -3033,21 +3085,21 @@ "@typescript-eslint/types" "5.30.5" "@typescript-eslint/visitor-keys" "5.30.5" -"@typescript-eslint/scope-manager@5.37.0": - version "5.37.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-5.37.0.tgz#044980e4f1516a774a418dafe701a483a6c9f9ca" - integrity sha512-F67MqrmSXGd/eZnujjtkPgBQzgespu/iCZ+54Ok9X5tALb9L2v3G+QBSoWkXG0p3lcTJsL+iXz5eLUEdSiJU9Q== +"@typescript-eslint/scope-manager@5.56.0": + version "5.56.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-5.56.0.tgz#62b4055088903b5254fa20403010e1c16d6ab725" + integrity sha512-jGYKyt+iBakD0SA5Ww8vFqGpoV2asSjwt60Gl6YcO8ksQ8s2HlUEyHBMSa38bdLopYqGf7EYQMUIGdT/Luw+sw== dependencies: - "@typescript-eslint/types" "5.37.0" - "@typescript-eslint/visitor-keys" "5.37.0" + "@typescript-eslint/types" "5.56.0" + "@typescript-eslint/visitor-keys" "5.56.0" -"@typescript-eslint/type-utils@5.37.0": - version "5.37.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/type-utils/-/type-utils-5.37.0.tgz#43ed2f567ada49d7e33a6e4b6f9babd060445fe5" - integrity sha512-BSx/O0Z0SXOF5tY0bNTBcDEKz2Ec20GVYvq/H/XNKiUorUFilH7NPbFUuiiyzWaSdN3PA8JV0OvYx0gH/5aFAQ== +"@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" + integrity sha512-8WxgOgJjWRy6m4xg9KoSHPzBNZeQbGlQOH7l2QEhQID/+YseaFxg5J/DLwWSsi9Axj4e/cCiKx7PVzOq38tY4A== dependencies: - "@typescript-eslint/typescript-estree" "5.37.0" - "@typescript-eslint/utils" "5.37.0" + "@typescript-eslint/typescript-estree" "5.56.0" + "@typescript-eslint/utils" "5.56.0" debug "^4.3.4" tsutils "^3.21.0" @@ -3056,10 +3108,10 @@ resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-5.30.5.tgz#36a0c05a72af3623cdf9ee8b81ea743b7de75a98" integrity sha512-kZ80w/M2AvsbRvOr3PjaNh6qEW1LFqs2pLdo2s5R38B2HYXG8Z0PP48/4+j1QHJFL3ssHIbJ4odPRS8PlHrFfw== -"@typescript-eslint/types@5.37.0": - version "5.37.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-5.37.0.tgz#09e4870a5f3af7af3f84e08d792644a87d232261" - integrity sha512-3frIJiTa5+tCb2iqR/bf7XwU20lnU05r/sgPJnRpwvfZaqCJBrl8Q/mw9vr3NrNdB/XtVyMA0eppRMMBqdJ1bA== +"@typescript-eslint/types@5.56.0": + version "5.56.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-5.56.0.tgz#b03f0bfd6fa2afff4e67c5795930aff398cbd834" + integrity sha512-JyAzbTJcIyhuUhogmiu+t79AkdnqgPUEsxMTMc/dCZczGMJQh1MK2wgrju++yMN6AWroVAy2jxyPcPr3SWCq5w== "@typescript-eslint/typescript-estree@5.30.5": version "5.30.5" @@ -3074,30 +3126,32 @@ semver "^7.3.7" tsutils "^3.21.0" -"@typescript-eslint/typescript-estree@5.37.0": - version "5.37.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-5.37.0.tgz#956dcf5c98363bcb97bdd5463a0a86072ff79355" - integrity sha512-JkFoFIt/cx59iqEDSgIGnQpCTRv96MQnXCYvJi7QhBC24uyuzbD8wVbajMB1b9x4I0octYFJ3OwjAwNqk1AjDA== +"@typescript-eslint/typescript-estree@5.56.0": + version "5.56.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-5.56.0.tgz#48342aa2344649a03321e74cab9ccecb9af086c3" + integrity sha512-41CH/GncsLXOJi0jb74SnC7jVPWeVJ0pxQj8bOjH1h2O26jXN3YHKDT1ejkVz5YeTEQPeLCCRY0U2r68tfNOcg== dependencies: - "@typescript-eslint/types" "5.37.0" - "@typescript-eslint/visitor-keys" "5.37.0" + "@typescript-eslint/types" "5.56.0" + "@typescript-eslint/visitor-keys" "5.56.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.37.0": - version "5.37.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-5.37.0.tgz#7784cb8e91390c4f90ccaffd24a0cf9874df81b2" - integrity sha512-jUEJoQrWbZhmikbcWSMDuUSxEE7ID2W/QCV/uz10WtQqfOuKZUqFGjqLJ+qhDd17rjgp+QJPqTdPIBWwoob2NQ== +"@typescript-eslint/utils@5.56.0": + version "5.56.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-5.56.0.tgz#db64705409b9a15546053fb4deb2888b37df1f41" + integrity sha512-XhZDVdLnUJNtbzaJeDSCIYaM+Tgr59gZGbFuELgF7m0IY03PlciidS7UQNKLE0+WpUTn1GlycEr6Ivb/afjbhA== dependencies: + "@eslint-community/eslint-utils" "^4.2.0" "@types/json-schema" "^7.0.9" - "@typescript-eslint/scope-manager" "5.37.0" - "@typescript-eslint/types" "5.37.0" - "@typescript-eslint/typescript-estree" "5.37.0" + "@types/semver" "^7.3.12" + "@typescript-eslint/scope-manager" "5.56.0" + "@typescript-eslint/types" "5.56.0" + "@typescript-eslint/typescript-estree" "5.56.0" eslint-scope "^5.1.1" - eslint-utils "^3.0.0" + semver "^7.3.7" "@typescript-eslint/visitor-keys@5.30.5": version "5.30.5" @@ -3107,12 +3161,12 @@ "@typescript-eslint/types" "5.30.5" eslint-visitor-keys "^3.3.0" -"@typescript-eslint/visitor-keys@5.37.0": - version "5.37.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-5.37.0.tgz#7b72dd343295ea11e89b624995abc7103c554eee" - integrity sha512-Hp7rT4cENBPIzMwrlehLW/28EVCOcE9U1Z1BQTc8EA8v5qpr7GRGuG+U58V5tTY48zvUOA3KHvw3rA8tY9fbdA== +"@typescript-eslint/visitor-keys@5.56.0": + version "5.56.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-5.56.0.tgz#f19eb297d972417eb13cb69b35b3213e13cc214f" + integrity sha512-1mFdED7u5bZpX6Xxf5N9U2c18sb+8EvU3tyOIj6LQZ5OOvnmj8BVeNNP603OFPm5KkS1a7IvCIcwrdHXaEMG/Q== dependencies: - "@typescript-eslint/types" "5.37.0" + "@typescript-eslint/types" "5.56.0" eslint-visitor-keys "^3.3.0" "@webassemblyjs/ast@1.9.0": @@ -3329,6 +3383,11 @@ 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== + add-stream@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/add-stream/-/add-stream-1.0.0.tgz#6a7990437ca736d5e1288db92bd3266d5f5cb2aa" @@ -3550,6 +3609,14 @@ arr-union@^3.1.0: resolved "https://registry.yarnpkg.com/arr-union/-/arr-union-3.1.0.tgz#e39b09aea9def866a8f206e288af63919bae39c4" integrity sha512-sKpyeERZ02v1FeCZT8lrfJq5u6goHCtpTAzPwJYe7c8SPFOboNjNg1vz2L4VTn9T4PQxEx13TbXLmYUcS6Ug7Q== +array-buffer-byte-length@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/array-buffer-byte-length/-/array-buffer-byte-length-1.0.0.tgz#fabe8bc193fea865f317fe7807085ee0dee5aead" + integrity sha512-LPuwb2P+NrQw3XhxGc36+XSvuBPopovXYTR9Ew++Du9Yb/bx5AzBfrIsBoj0EZUifjQU+sHL21sseZ3jerWO/A== + dependencies: + call-bind "^1.0.2" + is-array-buffer "^3.0.1" + array-flatten@1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/array-flatten/-/array-flatten-1.1.1.tgz#9a5f699051b1e7073328f2a008968b64ea2955d2" @@ -3576,6 +3643,17 @@ array-includes@^3.0.3, array-includes@^3.1.1, array-includes@^3.1.5: get-intrinsic "^1.1.1" is-string "^1.0.7" +array-includes@^3.1.6: + version "3.1.6" + resolved "https://registry.yarnpkg.com/array-includes/-/array-includes-3.1.6.tgz#9e9e720e194f198266ba9e18c29e6a9b0e4b225f" + integrity sha512-sgTbLvL6cNnw24FnbaDyjmvddQ2ML8arZsgaJhoABMoplz/4QRhtrYS+alr1BUM1Bwp6dhx8vVCBSLG+StwOFw== + dependencies: + call-bind "^1.0.2" + define-properties "^1.1.4" + es-abstract "^1.20.4" + get-intrinsic "^1.1.3" + is-string "^1.0.7" + array-union@^1.0.1: version "1.0.2" resolved "https://registry.yarnpkg.com/array-union/-/array-union-1.0.2.tgz#9a34410e4f4e3da23dea375be5be70f24778ec39" @@ -3629,14 +3707,14 @@ array.prototype.flat@^1.2.3: es-abstract "^1.19.2" es-shim-unscopables "^1.0.0" -array.prototype.flatmap@^1.3.0: - version "1.3.0" - resolved "https://registry.yarnpkg.com/array.prototype.flatmap/-/array.prototype.flatmap-1.3.0.tgz#a7e8ed4225f4788a70cd910abcf0791e76a5534f" - integrity sha512-PZC9/8TKAIxcWKdyeb77EzULHPrIX/tIZebLJUQOMR1OwYosT8yggdfWScfTBCDj5utONvOuPQQumYsU2ULbkg== +array.prototype.flatmap@^1.3.1: + version "1.3.1" + resolved "https://registry.yarnpkg.com/array.prototype.flatmap/-/array.prototype.flatmap-1.3.1.tgz#1aae7903c2100433cb8261cd4ed310aab5c4a183" + integrity sha512-8UGn9O1FDVvMNB0UlLv4voxRMze7+FpHyF5mSMRjWHUMlpoDViniy05870VlxhfgTnLbpuwTzvD76MTtWxB/mQ== dependencies: call-bind "^1.0.2" - define-properties "^1.1.3" - es-abstract "^1.19.2" + define-properties "^1.1.4" + es-abstract "^1.20.4" es-shim-unscopables "^1.0.0" array.prototype.foreach@^1.0.0: @@ -3662,6 +3740,17 @@ array.prototype.reduce@^1.0.4: es-array-method-boxes-properly "^1.0.0" is-string "^1.0.7" +array.prototype.tosorted@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/array.prototype.tosorted/-/array.prototype.tosorted-1.1.1.tgz#ccf44738aa2b5ac56578ffda97c03fd3e23dd532" + integrity sha512-pZYPXPRl2PqWcsUs6LOMn+1f1532nEoPTYowBtqLwAW+W8vSVhkIGnmOX1t/UQjD6YGI0vcD2B1U7ZFGQH9jnQ== + dependencies: + call-bind "^1.0.2" + define-properties "^1.1.4" + es-abstract "^1.20.4" + es-shim-unscopables "^1.0.0" + get-intrinsic "^1.1.3" + arrify@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/arrify/-/arrify-1.0.1.tgz#898508da2226f380df904728456849c1501a4b0d" @@ -3777,6 +3866,11 @@ autoprefixer@9.7.6: postcss "^7.0.27" postcss-value-parser "^4.0.3" +available-typed-arrays@^1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/available-typed-arrays/-/available-typed-arrays-1.0.5.tgz#92f95616501069d07d10edb2fc37d3e1c65123b7" + integrity sha512-DMD0KiN46eipeziST1LPP/STfDU0sufISXmjSgvVsoU2tqxctQeASejWcfNtxYKqETM1UxQ8sp2OrSBWpHY6sw== + aws-sign2@~0.7.0: version "0.7.0" resolved "https://registry.yarnpkg.com/aws-sign2/-/aws-sign2-0.7.0.tgz#b46e890934a9591f2d2f6f86d7e6a9f1b3fe76a8" @@ -4668,6 +4762,18 @@ cheerio-select@^1.5.0: domhandler "^4.3.1" domutils "^2.8.0" +cheerio-select@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/cheerio-select/-/cheerio-select-2.1.0.tgz#4d8673286b8126ca2a8e42740d5e3c4884ae21b4" + integrity sha512-9v9kG0LvzrlcungtnJtpGNxY+fzECQKhK4EGJX2vByejiMX84MFNQw4UxPJl3bFbTMw+Dfs37XaIkCwTZfLh4g== + dependencies: + boolbase "^1.0.0" + css-select "^5.1.0" + css-what "^6.1.0" + domelementtype "^2.3.0" + domhandler "^5.0.3" + domutils "^3.0.1" + cheerio@1.0.0-rc.10, cheerio@^1.0.0-rc.3, cheerio@^1.0.0-rc.9: version "1.0.0-rc.10" resolved "https://registry.yarnpkg.com/cheerio/-/cheerio-1.0.0-rc.10.tgz#2ba3dcdfcc26e7956fc1f440e61d51c643379f3e" @@ -4681,6 +4787,19 @@ cheerio@1.0.0-rc.10, cheerio@^1.0.0-rc.3, cheerio@^1.0.0-rc.9: parse5-htmlparser2-tree-adapter "^6.0.1" tslib "^2.2.0" +cheerio@1.0.0-rc.12: + version "1.0.0-rc.12" + resolved "https://registry.yarnpkg.com/cheerio/-/cheerio-1.0.0-rc.12.tgz#788bf7466506b1c6bf5fae51d24a2c4d62e47683" + integrity sha512-VqR8m68vM46BNnuZ5NtnGBKIE/DfN0cRIzg9n40EIq9NOv90ayxLBXA8fXC5gquFRGJSTRqBq25Jt2ECLR431Q== + dependencies: + cheerio-select "^2.1.0" + dom-serializer "^2.0.0" + domhandler "^5.0.3" + domutils "^3.0.1" + htmlparser2 "^8.0.1" + parse5 "^7.0.0" + parse5-htmlparser2-tree-adapter "^7.0.0" + chokidar@3.0.2: version "3.0.2" resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.0.2.tgz#0d1cd6d04eb2df0327446188cd13736a3367d681" @@ -5535,16 +5654,16 @@ cozy-client-js@^0.20.0: pouchdb-browser "7.0.0" pouchdb-find "7.0.0" -cozy-client@29.1.2: - version "29.1.2" - resolved "https://registry.yarnpkg.com/cozy-client/-/cozy-client-29.1.2.tgz#704122f0fda29663b7084d8395bf8a7503d45831" - integrity sha512-Rtx1DjMvMUrUwhS6TZl2dULmMPz0ogP6we963REeeueUBpNyA4pWNk23maw8DATt7pvF5EIOoJYOY4FVYmf48Q== +cozy-client@29.2.0: + version "29.2.0" + resolved "https://registry.yarnpkg.com/cozy-client/-/cozy-client-29.2.0.tgz#d474fd4268311ae7e23af4966e189a83d348a4ab" + integrity sha512-BtWTB+s+YIqPxvvvyrWELVBxVuVfDeI7RFEU2gn+tU4Ef2AKLuciy3hBX14tuHiAB6U+FHYpqCDK2JW8SdNo8w== dependencies: "@cozy/minilog" "1.0.0" "@types/jest" "^26.0.20" "@types/lodash" "^4.14.170" btoa "^1.2.1" - cozy-stack-client "^29.1.0" + cozy-stack-client "^29.2.0" json-stable-stringify "^1.0.1" lodash "^4.17.13" microee "^0.0.6" @@ -5559,16 +5678,16 @@ cozy-client@29.1.2: sift "^6.0.0" url-search-params-polyfill "^8.0.0" -cozy-client@34.7.1: - version "34.7.1" - resolved "https://registry.yarnpkg.com/cozy-client/-/cozy-client-34.7.1.tgz#d0641b43dbf67ca33a4ccae2a9a62b24784c2e1f" - integrity sha512-3KDrVOCMVnsxLcuCggM/rL13cIh+jY2MKZmHDZVM0cF8HeGMDHOJSH7cGwyL6vEoEzo6K2bxqPafJaIRqgw9Mw== +cozy-client@35.6.0: + version "35.6.0" + resolved "https://registry.yarnpkg.com/cozy-client/-/cozy-client-35.6.0.tgz#f052a020f9f3bf19a85448d72c38d182c08e8da3" + integrity sha512-kDmUXWC9tV+vgqixhKigpnb8AmNUzZLgP6tF8SW5O50/TlORHLVvNlLg63m40ApDSMK1TaCFe+zSkYnF6/ojMQ== dependencies: "@cozy/minilog" "1.0.0" "@types/jest" "^26.0.20" "@types/lodash" "^4.14.170" btoa "^1.2.1" - cozy-stack-client "^34.7.1" + cozy-stack-client "^35.6.0" date-fns "2.29.3" json-stable-stringify "^1.0.1" lodash "^4.17.13" @@ -5584,16 +5703,16 @@ cozy-client@34.7.1: sift "^6.0.0" url-search-params-polyfill "^8.0.0" -cozy-client@^29.1.2: - version "29.2.0" - resolved "https://registry.yarnpkg.com/cozy-client/-/cozy-client-29.2.0.tgz#d474fd4268311ae7e23af4966e189a83d348a4ab" - integrity sha512-BtWTB+s+YIqPxvvvyrWELVBxVuVfDeI7RFEU2gn+tU4Ef2AKLuciy3hBX14tuHiAB6U+FHYpqCDK2JW8SdNo8w== +cozy-client@^33.2.0: + version "33.4.0" + resolved "https://registry.yarnpkg.com/cozy-client/-/cozy-client-33.4.0.tgz#39e713656b3ce847dd453714564b665523001d09" + integrity sha512-2e8hg9pOHnmScpIyeHM4TjZ45hW/uTV+CCO7lS9LN1AsGsEdNdKjD+d4fvLYIX1zUcaqRDhFNUYzCCdz1t5Mag== dependencies: "@cozy/minilog" "1.0.0" "@types/jest" "^26.0.20" "@types/lodash" "^4.14.170" btoa "^1.2.1" - cozy-stack-client "^29.2.0" + cozy-stack-client "^33.4.0" json-stable-stringify "^1.0.1" lodash "^4.17.13" microee "^0.0.6" @@ -5689,10 +5808,10 @@ cozy-interapp@^0.5.4: resolved "https://registry.yarnpkg.com/cozy-interapp/-/cozy-interapp-0.5.7.tgz#75cafe1732ad660e2caf1ccf412f302594705f39" integrity sha512-laIL/ATYV9oZnmqS+LMoO9qzk8XjJ1v2/YrA1Po2rI8ia/MDgjYO07424x2RuvHhNOBPGjD+JmqwQ0rNDlLW+Q== -cozy-jobs-cli@^1.13.6: - version "1.18.1" - resolved "https://registry.yarnpkg.com/cozy-jobs-cli/-/cozy-jobs-cli-1.18.1.tgz#02c9a50d3f1a9947424f345c43f54f3c9dcc5e62" - integrity sha512-SBTWyKrzwj0I+73enhSFf7bJWEBJVAf+wU6740Icj/zkIpPq1jCEiK/ljabyxTskCwHJQ3MymjQFRoEbxC6jCg== +cozy-jobs-cli@^2.0.0: + version "2.0.2" + resolved "https://registry.yarnpkg.com/cozy-jobs-cli/-/cozy-jobs-cli-2.0.2.tgz#5e2c13e9d7a671e916b7f8b776b424ab81a178b0" + integrity sha512-sMQXBQNpiIBBz/gTsU9ssc+/FmjAgD2n2LbP3QhU0v/Xgunr3ooVzJYRkYaJnWnQRlUuav991GOJuLoMRGLvKQ== dependencies: "@pollyjs/adapter-node-http" "5.1.1" "@pollyjs/core" "5.1.1" @@ -5700,14 +5819,14 @@ cozy-jobs-cli@^1.13.6: argparse "^2.0.1" babel-runtime "6.26.0" btoa "^1.2.1" - cheerio "1.0.0-rc.10" + cheerio "1.0.0-rc.12" cli-highlight "2.1.11" commander "7.2.0" - cozy-client "29.1.2" + cozy-client "29.2.0" cozy-device-helper "^2.1.0" cozy-flags "^2.8.7" - cozy-konnector-libs "^4.53.1" - cozy-logger "1.8.0" + cozy-konnector-libs "^5.2.0" + cozy-logger "1.9.0" open "8.4.0" pretty "2.0.0" strip-json-comments "3.1.1" @@ -5733,10 +5852,10 @@ cozy-keys-lib@>=4.1.9: tldjs "^2.3.1" zxcvbn "^4.4.2" -cozy-konnector-libs@^4.53.1: - version "4.53.1" - resolved "https://registry.yarnpkg.com/cozy-konnector-libs/-/cozy-konnector-libs-4.53.1.tgz#eaaec598578cfd8b2813411192eaf54c4f4de4fe" - integrity sha512-NLqonlJI28lxohAeQgnxylNeZN/fGPfbTd4eef4h40qyc+o5PPaujPgBwowSg6jnT0t8LZBpU2k+mM1loUNzcQ== +cozy-konnector-libs@^5.2.0: + version "5.2.0" + resolved "https://registry.yarnpkg.com/cozy-konnector-libs/-/cozy-konnector-libs-5.2.0.tgz#5ec5abe21bf33fea9cd24b48ad3b3a098e1b4f08" + integrity sha512-L9nirvz66TGxaBFJ4siDDkRGLAoYv/8dMfdRbhlCHDxvbf6gMa2mOYhwrI9Tu2NFHt+R6UoqJb5LqHPZFAk9nA== dependencies: babel-runtime "^6.26.0" bluebird "^3.7.2" @@ -5744,7 +5863,7 @@ cozy-konnector-libs@^4.53.1: btoa "1.2.1" cheerio "^1.0.0-rc.9" classificator "^0.3.3" - cozy-client "^29.1.2" + cozy-client "^33.2.0" cozy-client-js "^0.20.0" cozy-device-helper "^2.1.0" cozy-doctypes "^1.83.8" @@ -5764,15 +5883,7 @@ cozy-konnector-libs@^4.53.1: request-promise "^4.2.6" strip-json-comments "^3.1.1" -cozy-logger@1.8.0: - version "1.8.0" - resolved "https://registry.yarnpkg.com/cozy-logger/-/cozy-logger-1.8.0.tgz#8d37f8e52c0de02a65ca0606ad60b0ebf3a60ed6" - integrity sha512-0sBNsfwCwO/r23vrOncvj/EGRjDh/0Emh2WqWL0cYriPbOiidWrsULmh11Q9ykCB1IxBZ3z8PEpaqGTvAas2ug== - dependencies: - chalk "^2.4.2" - json-stringify-safe "5.0.1" - -cozy-logger@>1.7.0, cozy-logger@^1.3.0, cozy-logger@^1.8.0, cozy-logger@^1.9.0: +cozy-logger@1.9.0, cozy-logger@>1.7.0, cozy-logger@^1.3.0, cozy-logger@^1.8.0, cozy-logger@^1.9.0: version "1.9.0" resolved "https://registry.yarnpkg.com/cozy-logger/-/cozy-logger-1.9.0.tgz#e3a2323d9a2945ca10da5c318ff2f63544a54415" integrity sha512-x/iFwFuNTbG4lwgeKPv6HtdixY+CcJm47sRd2za09aS1zZMHnN3HX7fFgoSSgEqFhpnIO/PpP2pVqJ4orSCp0g== @@ -5863,7 +5974,7 @@ cozy-scripts@6.3.10: webpack-dev-server "3.10.3" webpack-merge "4.2.2" -cozy-stack-client@^29.1.0, cozy-stack-client@^29.2.0: +cozy-stack-client@^29.2.0: version "29.2.0" resolved "https://registry.yarnpkg.com/cozy-stack-client/-/cozy-stack-client-29.2.0.tgz#48e9d043cc869c59155979bb1666e4455d5dd0e4" integrity sha512-QD8Bn/t9gLcKdxc0L65zGed6L5KdP/tNt4z63XrAVR2HBuqJcrlt6NucP7TH2FJYOj46mp9fW7iODk9hRD03UA== @@ -5872,19 +5983,28 @@ cozy-stack-client@^29.1.0, cozy-stack-client@^29.2.0: mime "^2.4.0" qs "^6.7.0" -cozy-stack-client@^34.7.1: - version "34.7.1" - resolved "https://registry.yarnpkg.com/cozy-stack-client/-/cozy-stack-client-34.7.1.tgz#f1b81cce2c88ba558a1b5995a91674462f3e629c" - integrity sha512-iarCc6y79HCcQKM7ITQX+y3Tvhi1SjtMGonKAkA98MOtB7qBBolU0CJd9CTLyRfzJAVT/VpXHpwBwTLQ5tyo4g== +cozy-stack-client@^33.4.0: + version "33.4.0" + resolved "https://registry.yarnpkg.com/cozy-stack-client/-/cozy-stack-client-33.4.0.tgz#c0c7ce7f2d65987b10bc8b4a615a3de0eedcf8d4" + integrity sha512-DaCwOdNT+aZJL+BZH04iUe0709O5Pi6qTagRlM+hp7oKwXiJvU3lwYIFE1McGss4rdhlWhIXB107ZFSC1+eagw== + dependencies: + detect-node "^2.0.4" + mime "^2.4.0" + qs "^6.7.0" + +cozy-stack-client@^35.6.0: + version "35.6.0" + resolved "https://registry.yarnpkg.com/cozy-stack-client/-/cozy-stack-client-35.6.0.tgz#9d650adc7f3661e2328780cacab87b7060f8ef4c" + integrity sha512-EVnRHemYHv9NXFeVP003QQ04OpHrcQIp8RQk4zAyS5Qm8dASagF5hZed4K6C+Fs4Z7qSYmP1GRM2zmqiqU3RfQ== dependencies: detect-node "^2.0.4" mime "^2.4.0" qs "^6.7.0" -cozy-ui@79.3.0: - version "79.3.0" - resolved "https://registry.yarnpkg.com/cozy-ui/-/cozy-ui-79.3.0.tgz#9915a3f1aab474b00dc4033d907a31fabb2d1c08" - integrity sha512-OR9KZF9i+alc2sWC7gG2lNuBqiIjJnxkctwt44mK1jWHpQWrQ/4d4HhOcwAcDoAkIWiQyLvmiZivfZVZ3fL/QQ== +cozy-ui@81.5.0: + version "81.5.0" + resolved "https://registry.yarnpkg.com/cozy-ui/-/cozy-ui-81.5.0.tgz#e462a710af3121f30fb2cd908e2154ded23d7dde" + integrity sha512-tHho2iw46CIPsn20aOHExSj3+B/7bNbF6fEFcmaKVj8H2TNbk9Kq6znZ0vO1A7zP2pv7Kj3TGqwbc5zkjwWNYw== dependencies: "@babel/runtime" "^7.3.4" "@material-ui/core" "4.12.3" @@ -6054,6 +6174,17 @@ css-select@^4.1.3, css-select@^4.3.0: domutils "^2.8.0" nth-check "^2.0.1" +css-select@^5.1.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/css-select/-/css-select-5.1.0.tgz#b8ebd6554c3637ccc76688804ad3f6a6fdaea8a6" + integrity sha512-nwoRF1rvRRnnCqqY7updORDsuqKzqYJ28+oSMaJMMgOauh3fvwHqMS7EZpIPqK8GL+g9mKxF1vP/ZjSeNjEVHg== + dependencies: + boolbase "^1.0.0" + css-what "^6.1.0" + domhandler "^5.0.2" + domutils "^3.0.1" + nth-check "^2.0.1" + css-tree@1.0.0-alpha.37: version "1.0.0-alpha.37" resolved "https://registry.yarnpkg.com/css-tree/-/css-tree-1.0.0-alpha.37.tgz#98bebd62c4c1d9f960ec340cf9f7522e30709a22" @@ -6083,7 +6214,7 @@ css-what@^3.2.1: resolved "https://registry.yarnpkg.com/css-what/-/css-what-3.4.2.tgz#ea7026fcb01777edbde52124e21f327e7ae950e4" integrity sha512-ACUm3L0/jiZTqfzRM3Hi9Q8eZqd6IK37mMWPLz9PJxkLWllYeRf+EHUSHYEtFop2Eqytaq1FizFVh7XfBnXCDQ== -css-what@^6.0.1: +css-what@^6.0.1, css-what@^6.1.0: version "6.1.0" resolved "https://registry.yarnpkg.com/css-what/-/css-what-6.1.0.tgz#fb5effcf76f1ddea2c81bdfaa4de44e79bac70f4" integrity sha512-HTUrgRJ7r4dsZKU6GjmpfRK1O76h97Z8MfS1G0FozR+oF2kG6Vfe8JE6zwrkbxigziPHinCJ+gCPjA9EaBDtRw== @@ -6769,6 +6900,15 @@ dom-serializer@^1.0.1, dom-serializer@^1.3.2: domhandler "^4.2.0" entities "^2.0.0" +dom-serializer@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/dom-serializer/-/dom-serializer-2.0.0.tgz#e41b802e1eedf9f6cae183ce5e622d789d7d8e53" + integrity sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg== + dependencies: + domelementtype "^2.3.0" + domhandler "^5.0.2" + entities "^4.2.0" + dom-walk@^0.1.0: version "0.1.2" resolved "https://registry.yarnpkg.com/dom-walk/-/dom-walk-0.1.2.tgz#0c548bef048f4d1f2a97249002236060daa3fd84" @@ -6784,7 +6924,7 @@ domelementtype@1, domelementtype@^1.3.1: resolved "https://registry.yarnpkg.com/domelementtype/-/domelementtype-1.3.1.tgz#d048c44b37b0d10a7f2a3d5fee3f4333d790481f" integrity sha512-BSKB+TSpMpFI/HOxCNr1O8aMOTZ8hT3pM3GQ0w/mWRmkhEDSFJkkyzz4XQsBV44BChwGkrDfMyjVD0eA2aFV3w== -domelementtype@^2.0.1, domelementtype@^2.2.0: +domelementtype@^2.0.1, domelementtype@^2.2.0, domelementtype@^2.3.0: version "2.3.0" resolved "https://registry.yarnpkg.com/domelementtype/-/domelementtype-2.3.0.tgz#5c45e8e869952626331d7aab326d01daf65d589d" integrity sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw== @@ -6817,6 +6957,13 @@ domhandler@^4.0, domhandler@^4.0.0, domhandler@^4.2.0, domhandler@^4.2.2, domhan dependencies: domelementtype "^2.2.0" +domhandler@^5.0.1, domhandler@^5.0.2, domhandler@^5.0.3: + version "5.0.3" + resolved "https://registry.yarnpkg.com/domhandler/-/domhandler-5.0.3.tgz#cc385f7f751f1d1fc650c21374804254538c7d31" + integrity sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w== + dependencies: + domelementtype "^2.3.0" + domready@1.0.8: version "1.0.8" resolved "https://registry.yarnpkg.com/domready/-/domready-1.0.8.tgz#91f252e597b65af77e745ae24dd0185d5e26d58c" @@ -6839,6 +6986,15 @@ domutils@^2.0.0, domutils@^2.5.2, domutils@^2.8.0: domelementtype "^2.2.0" domhandler "^4.2.0" +domutils@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/domutils/-/domutils-3.0.1.tgz#696b3875238338cb186b6c0612bd4901c89a4f1c" + integrity sha512-z08c1l761iKhDFtfXO04C7kTdPBLi41zwOZl00WS8b5eiaebNpY00HKbztwBq+e3vyqWNwWF3mP9YLUeqIrF+Q== + dependencies: + dom-serializer "^2.0.0" + domelementtype "^2.3.0" + domhandler "^5.0.1" + dot-prop@^5.1.0: version "5.3.0" resolved "https://registry.yarnpkg.com/dot-prop/-/dot-prop-5.3.0.tgz#90ccce708cd9cd82cc4dc8c3ddd9abdd55b20e88" @@ -7008,6 +7164,11 @@ entities@^3.0.1: resolved "https://registry.yarnpkg.com/entities/-/entities-3.0.1.tgz#2b887ca62585e96db3903482d336c1006c3001d4" integrity sha512-WiyBqoomrwMdFG1e0kqvASYfnlb0lp8M5o5Fw2OFq1hNZxxcNk8Ik0Xm7LxzBhuidnZB/UtBqVCgUz3kBOP51Q== +entities@^4.2.0, entities@^4.3.0, entities@^4.4.0: + version "4.4.0" + resolved "https://registry.yarnpkg.com/entities/-/entities-4.4.0.tgz#97bdaba170339446495e653cfd2db78962900174" + integrity sha512-oYp7156SP8LkeGD0GF85ad1X9Ai79WtRsZ2gxJqtBuzH+98YUV6jkHEKlZkMbcrjJjIVJNIDP/3WL9wQkoPbWA== + enzyme-adapter-react-16@1.15.6: version "1.15.6" resolved "https://registry.yarnpkg.com/enzyme-adapter-react-16/-/enzyme-adapter-react-16-1.15.6.tgz#fd677a658d62661ac5afd7f7f541f141f8085901" @@ -7124,11 +7285,60 @@ es-abstract@^1.17.2, es-abstract@^1.19.0, es-abstract@^1.19.1, es-abstract@^1.19 string.prototype.trimstart "^1.0.5" unbox-primitive "^1.0.2" +es-abstract@^1.20.4: + version "1.21.2" + resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.21.2.tgz#a56b9695322c8a185dc25975aa3b8ec31d0e7eff" + integrity sha512-y/B5POM2iBnIxCiernH1G7rC9qQoM77lLIMQLuob0zhp8C56Po81+2Nj0WFKnd0pNReDTnkYryc+zhOzpEIROg== + dependencies: + array-buffer-byte-length "^1.0.0" + available-typed-arrays "^1.0.5" + call-bind "^1.0.2" + es-set-tostringtag "^2.0.1" + es-to-primitive "^1.2.1" + function.prototype.name "^1.1.5" + get-intrinsic "^1.2.0" + get-symbol-description "^1.0.0" + globalthis "^1.0.3" + gopd "^1.0.1" + has "^1.0.3" + has-property-descriptors "^1.0.0" + has-proto "^1.0.1" + has-symbols "^1.0.3" + internal-slot "^1.0.5" + is-array-buffer "^3.0.2" + is-callable "^1.2.7" + is-negative-zero "^2.0.2" + is-regex "^1.1.4" + is-shared-array-buffer "^1.0.2" + is-string "^1.0.7" + is-typed-array "^1.1.10" + is-weakref "^1.0.2" + object-inspect "^1.12.3" + object-keys "^1.1.1" + object.assign "^4.1.4" + regexp.prototype.flags "^1.4.3" + safe-regex-test "^1.0.0" + string.prototype.trim "^1.2.7" + string.prototype.trimend "^1.0.6" + string.prototype.trimstart "^1.0.6" + typed-array-length "^1.0.4" + unbox-primitive "^1.0.2" + which-typed-array "^1.1.9" + es-array-method-boxes-properly@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/es-array-method-boxes-properly/-/es-array-method-boxes-properly-1.0.0.tgz#873f3e84418de4ee19c5be752990b2e44718d09e" integrity sha512-wd6JXUmyHmt8T5a2xreUwKcGPq6f1f+WwIJkijUqiGcJz1qqnZgP6XIK+QyIWU5lT7imeNxUll48bziG+TSYcA== +es-set-tostringtag@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/es-set-tostringtag/-/es-set-tostringtag-2.0.1.tgz#338d502f6f674301d710b80c8592de8a15f09cd8" + integrity sha512-g3OMbtlwY3QewlqAiMLI47KywjWZoEytKr8pf6iTC8uJq5bIAH52Z9pnQ8pVL6whrCto53JZDuUIsifGeLorTg== + dependencies: + get-intrinsic "^1.1.3" + has "^1.0.3" + has-tostringtag "^1.0.0" + es-shim-unscopables@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/es-shim-unscopables/-/es-shim-unscopables-1.0.0.tgz#702e632193201e3edf8713635d083d378e510241" @@ -7228,10 +7438,10 @@ eslint-config-prettier@4.3.0: dependencies: get-stdin "^6.0.0" -eslint-config-prettier@^8.5.0: - version "8.5.0" - resolved "https://registry.yarnpkg.com/eslint-config-prettier/-/eslint-config-prettier-8.5.0.tgz#5a81680ec934beca02c7b1a61cf8ca34b66feab1" - integrity sha512-obmWKLUNCnhtQRKc+tmnYuQl0pFU1ibYJQ5BGhTVB08bHe9wC8qUeG7c08dj9XX+AuPj1YSGSQIHl1pnDHZR0Q== +eslint-config-prettier@^8.8.0: + version "8.8.0" + resolved "https://registry.yarnpkg.com/eslint-config-prettier/-/eslint-config-prettier-8.8.0.tgz#bfda738d412adc917fd7b038857110efe98c9348" + integrity sha512-wLbQiFre3tdGgpDv67NQKnJuTlcUVYHas3k+DZCc2U2BadthoEY4B7hLPvAxaqdyOGCzuLfii2fqGph10va7oA== eslint-loader@^4.0.2: version "4.0.2" @@ -7268,10 +7478,10 @@ eslint-plugin-react-hooks@4.0.4: resolved "https://registry.yarnpkg.com/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-4.0.4.tgz#aed33b4254a41b045818cacb047b81e6df27fa58" integrity sha512-equAdEIsUETLFNCmmCkiCGq6rkSK5MoJhXFPFYeUebcjKgBmWWcgVOqZyQC8Bv1BwVCnTq9tBxgJFgAJTWoJtA== -eslint-plugin-react-hooks@^4.2.0: - version "4.3.0" - resolved "https://registry.yarnpkg.com/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-4.3.0.tgz#318dbf312e06fab1c835a4abef00121751ac1172" - integrity sha512-XslZy0LnMn+84NEG9jSGR6eGqaZB3133L8xewQo3fQagbQuGt7a63gf+P1NGKZavEYEC3UXaWEAA/AqDkuN6xA== +eslint-plugin-react-hooks@^4.6.0: + version "4.6.0" + resolved "https://registry.yarnpkg.com/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-4.6.0.tgz#4c3e697ad95b77e93f8646aaa1630c1ba607edd3" + integrity sha512-oFc7Itz9Qxh2x4gNHStv3BqJq54ExXmfC+a1NjAta66IAN87Wu0R/QArgIS9qKzX3dXKPI9H5crl9QchNMY9+g== eslint-plugin-react@7.14.3: version "7.14.3" @@ -7306,25 +7516,26 @@ eslint-plugin-react@7.19.0: string.prototype.matchall "^4.0.2" xregexp "^4.3.0" -eslint-plugin-react@7.31.8: - version "7.31.8" - resolved "https://registry.yarnpkg.com/eslint-plugin-react/-/eslint-plugin-react-7.31.8.tgz#3a4f80c10be1bcbc8197be9e8b641b2a3ef219bf" - integrity sha512-5lBTZmgQmARLLSYiwI71tiGVTLUuqXantZM6vlSY39OaDSV0M7+32K5DnLkmFrwTe+Ksz0ffuLUC91RUviVZfw== +eslint-plugin-react@7.32.2: + version "7.32.2" + resolved "https://registry.yarnpkg.com/eslint-plugin-react/-/eslint-plugin-react-7.32.2.tgz#e71f21c7c265ebce01bcbc9d0955170c55571f10" + integrity sha512-t2fBMa+XzonrrNkyVirzKlvn5RXzzPwRHtMvLAtVZrt8oxgnTQaYbU6SXTOO1mwQgp1y5+toMSKInnzGr0Knqg== dependencies: - array-includes "^3.1.5" - array.prototype.flatmap "^1.3.0" + array-includes "^3.1.6" + array.prototype.flatmap "^1.3.1" + array.prototype.tosorted "^1.1.1" doctrine "^2.1.0" estraverse "^5.3.0" jsx-ast-utils "^2.4.1 || ^3.0.0" minimatch "^3.1.2" - object.entries "^1.1.5" - object.fromentries "^2.0.5" - object.hasown "^1.1.1" - object.values "^1.1.5" + object.entries "^1.1.6" + object.fromentries "^2.0.6" + object.hasown "^1.1.2" + object.values "^1.1.6" prop-types "^15.8.1" - resolve "^2.0.0-next.3" + resolve "^2.0.0-next.4" semver "^6.3.0" - string.prototype.matchall "^4.0.7" + string.prototype.matchall "^4.0.8" eslint-plugin-vue@5.2.3: version "5.2.3" @@ -7489,7 +7700,53 @@ eslint@^7.32.0: text-table "^0.2.0" v8-compile-cache "^2.0.3" -eslint@^8.18.0, eslint@^8.7.0: +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== + 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" + "@humanwhocodes/module-importer" "^1.0.1" + "@nodelib/fs.walk" "^1.2.8" + ajv "^6.10.0" + 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" + esquery "^1.4.2" + esutils "^2.0.2" + fast-deep-equal "^3.1.3" + file-entry-cache "^6.0.1" + find-up "^5.0.0" + glob-parent "^6.0.2" + globals "^13.19.0" + grapheme-splitter "^1.0.4" + 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" + strip-ansi "^6.0.1" + strip-json-comments "^3.1.0" + text-table "^0.2.0" + +eslint@^8.7.0: version "8.19.0" resolved "https://registry.yarnpkg.com/eslint/-/eslint-8.19.0.tgz#7342a3cbc4fbc5c106a1eefe0fd0b50b6b1a7d28" integrity sha512-SXOPj3x9VKvPe81TjjUJCYlV4oJjQw68Uek+AM0X4p+33dj2HY5bpTZOgnQHcG2eAm1mtCU9uNMnJi7exU/kYw== @@ -7566,6 +7823,15 @@ 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== + dependencies: + acorn "^8.8.0" + acorn-jsx "^5.3.2" + eslint-visitor-keys "^3.3.0" + esprima@^4.0.0, esprima@^4.0.1: version "4.0.1" resolved "https://registry.yarnpkg.com/esprima/-/esprima-4.0.1.tgz#13b04cdb3e6c5d19df91ab6987a8695619b0aa71" @@ -7578,6 +7844,13 @@ esquery@^1.0.1, esquery@^1.4.0: dependencies: estraverse "^5.1.0" +esquery@^1.4.2: + version "1.5.0" + resolved "https://registry.yarnpkg.com/esquery/-/esquery-1.5.0.tgz#6ce17738de8577694edd7361c57182ac8cb0db0b" + integrity sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg== + dependencies: + estraverse "^5.1.0" + esrecurse@^4.1.0, esrecurse@^4.3.0: version "4.3.0" resolved "https://registry.yarnpkg.com/esrecurse/-/esrecurse-4.3.0.tgz#7ad7964d679abb28bee72cec63758b1c5d2c9921" @@ -8142,6 +8415,13 @@ follow-redirects@^1.15.0: resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.15.2.tgz#b460864144ba63f2681096f274c4e57026da2c13" integrity sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA== +for-each@^0.3.3: + version "0.3.3" + resolved "https://registry.yarnpkg.com/for-each/-/for-each-0.3.3.tgz#69b447e88a0a5d32c3e7084f3f1710034b21376e" + integrity sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw== + dependencies: + is-callable "^1.1.3" + for-in@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/for-in/-/for-in-1.0.2.tgz#81068d295a8142ec0ac726c6e2200c30fb6d5e80" @@ -8324,6 +8604,15 @@ get-intrinsic@^1.0.2, get-intrinsic@^1.1.0, get-intrinsic@^1.1.1: has "^1.0.3" has-symbols "^1.0.3" +get-intrinsic@^1.1.3, get-intrinsic@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/get-intrinsic/-/get-intrinsic-1.2.0.tgz#7ad1dc0535f3a2904bba075772763e5051f6d05f" + integrity sha512-L049y6nFOuom5wGyRc3/gdTLO94dySVKRACj1RmJZBQXlbTMhtNIgkWkUHq+jYmZvKf14EW1EoJnnjbmoHij0Q== + dependencies: + function-bind "^1.1.1" + has "^1.0.3" + has-symbols "^1.0.3" + get-nonce@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/get-nonce/-/get-nonce-1.0.1.tgz#fdf3f0278073820d2ce9426c18f07481b1e0cdf3" @@ -8445,7 +8734,7 @@ glob-parent@^5.0.0, glob-parent@^5.1.1, glob-parent@^5.1.2, glob-parent@~5.1.2: dependencies: is-glob "^4.0.1" -glob-parent@^6.0.1: +glob-parent@^6.0.1, glob-parent@^6.0.2: version "6.0.2" resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-6.0.2.tgz#6d237d99083950c79290f24c7642a3de9a28f9e3" integrity sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A== @@ -8496,6 +8785,13 @@ globals@^13.15.0: dependencies: type-fest "^0.20.2" +globals@^13.19.0: + version "13.20.0" + resolved "https://registry.yarnpkg.com/globals/-/globals-13.20.0.tgz#ea276a1e508ffd4f1612888f9d1bad1e2717bf82" + integrity sha512-Qg5QtVkCy/kv3FUSlu4ukeZDVf9ee0iXLAUYX13gbR17bnejFTzr4iS9bY7kwCf1NztRNm1t91fjOiyx4CSwPQ== + dependencies: + type-fest "^0.20.2" + globals@^13.6.0, globals@^13.9.0: version "13.17.0" resolved "https://registry.yarnpkg.com/globals/-/globals-13.17.0.tgz#902eb1e680a41da93945adbdcb5a9f361ba69bd4" @@ -8503,6 +8799,13 @@ globals@^13.6.0, globals@^13.9.0: dependencies: type-fest "^0.20.2" +globalthis@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/globalthis/-/globalthis-1.0.3.tgz#5852882a52b80dc301b0660273e1ed082f0b6ccf" + integrity sha512-sFdI5LyBiNTHjRd7cGPWapiHWMOXKyuBNX/cWJ3NfzrZQVa8GI/8cofCl74AOVqq9W5kNmguTIzJ/1s2gyI9wA== + dependencies: + define-properties "^1.1.3" + globby@^11.0.1, globby@^11.1.0: version "11.1.0" resolved "https://registry.yarnpkg.com/globby/-/globby-11.1.0.tgz#bd4be98bb042f83d796f7e3811991fbe82a0d34b" @@ -8538,11 +8841,23 @@ globby@^7.1.1: pify "^3.0.0" slash "^1.0.0" +gopd@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/gopd/-/gopd-1.0.1.tgz#29ff76de69dac7489b7c0918a5788e56477c332c" + integrity sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA== + dependencies: + get-intrinsic "^1.1.3" + graceful-fs@^4.1.11, graceful-fs@^4.1.15, graceful-fs@^4.1.2, graceful-fs@^4.1.3, graceful-fs@^4.1.6, graceful-fs@^4.2.0, graceful-fs@^4.2.4, graceful-fs@^4.2.9: version "4.2.10" resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.10.tgz#147d3a006da4ca3ce14728c7aefc287c367d7a6c" integrity sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA== +grapheme-splitter@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/grapheme-splitter/-/grapheme-splitter-1.0.4.tgz#9cf3a665c6247479896834af35cf1dbb4400767e" + integrity sha512-bzh50DW9kTPM00T8y4o8vQg89Di9oLJVLW/KaOGIXJWP/iqCN6WKYkbNOF04vFLJhwcpYUh9ydh/+5vpOqV4YQ== + growly@^1.3.0: version "1.3.0" resolved "https://registry.yarnpkg.com/growly/-/growly-1.3.0.tgz#f10748cbe76af964b7c96c93c6bcc28af120c081" @@ -8652,6 +8967,11 @@ has-property-descriptors@^1.0.0: dependencies: get-intrinsic "^1.1.1" +has-proto@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/has-proto/-/has-proto-1.0.1.tgz#1885c1305538958aff469fef37937c22795408e0" + integrity sha512-7qE+iP+O+bgF9clE5+UoBFzE65mlBiVj3tKCrlNQ0Ogwm0BjpT/gK4SlLYDMybDh5I3TCTKnPPa0oMG7JDYrhg== + has-symbols@^1.0.1, has-symbols@^1.0.2, has-symbols@^1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.0.3.tgz#bb7b2c4349251dce87b125f7bdf874aa7c8b39f8" @@ -8904,6 +9224,16 @@ htmlparser2@^7.0: domutils "^2.8.0" entities "^3.0.1" +htmlparser2@^8.0.1: + version "8.0.1" + resolved "https://registry.yarnpkg.com/htmlparser2/-/htmlparser2-8.0.1.tgz#abaa985474fcefe269bc761a779b544d7196d010" + integrity sha512-4lVbmc1diZC7GUJQtRQ5yBAeUCL1exyMwmForWkRLnwyzWBFxN633SALPMGYaWZvKe9j1pRZJpauvmxENSp/EA== + dependencies: + domelementtype "^2.3.0" + domhandler "^5.0.2" + domutils "^3.0.1" + entities "^4.3.0" + http-deceiver@^1.2.7: version "1.2.7" resolved "https://registry.yarnpkg.com/http-deceiver/-/http-deceiver-1.2.7.tgz#fa7168944ab9a519d337cb0bec7284dc3e723d87" @@ -9221,6 +9551,15 @@ internal-slot@^1.0.3: has "^1.0.3" side-channel "^1.0.4" +internal-slot@^1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/internal-slot/-/internal-slot-1.0.5.tgz#f2a2ee21f668f8627a4667f309dc0f4fb6674986" + integrity sha512-Y+R5hJrzs52QCG2laLn4udYVnxsfny9CpOhNhUvk/SSSVyF6T27FzRbF0sroPidSu3X8oEAkOn2K804mjpt6UQ== + dependencies: + get-intrinsic "^1.2.0" + has "^1.0.3" + side-channel "^1.0.4" + internmap@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/internmap/-/internmap-1.0.1.tgz#0017cc8a3b99605f0302f2b198d272e015e5df95" @@ -9303,6 +9642,15 @@ is-arguments@^1.0.4: call-bind "^1.0.2" has-tostringtag "^1.0.0" +is-array-buffer@^3.0.1, is-array-buffer@^3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/is-array-buffer/-/is-array-buffer-3.0.2.tgz#f2653ced8412081638ecb0ebbd0c41c6e0aecbbe" + integrity sha512-y+FyyR/w8vfIRq4eQcM1EYgSTnmHXPqaF+IgzgraytCFq5Xh8lllDVmAZolPJiZttZLeFSINPYMaEJ7/vWUa1w== + dependencies: + call-bind "^1.0.2" + get-intrinsic "^1.2.0" + is-typed-array "^1.1.10" + is-arrayish@^0.2.1: version "0.2.1" resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.2.1.tgz#77c99840527aa8ecb1a8ba697b80645a7a926a9d" @@ -9342,6 +9690,11 @@ 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-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" + integrity sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA== + is-callable@^1.1.4, is-callable@^1.1.5, is-callable@^1.2.4: version "1.2.4" resolved "https://registry.yarnpkg.com/is-callable/-/is-callable-1.2.4.tgz#47301d58dd0259407865547853df6d61fe471945" @@ -9531,6 +9884,11 @@ is-path-inside@^2.1.0: dependencies: path-is-inside "^1.0.2" +is-path-inside@^3.0.3: + version "3.0.3" + resolved "https://registry.yarnpkg.com/is-path-inside/-/is-path-inside-3.0.3.tgz#d231362e53a07ff2b0e0ea7fed049161ffd16283" + integrity sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ== + is-plain-obj@^1.1, is-plain-obj@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/is-plain-obj/-/is-plain-obj-1.1.0.tgz#71a50c8429dfca773c92a390a4a03b39fcd51d3e" @@ -9609,6 +9967,17 @@ is-text-path@^1.0.1: dependencies: text-extensions "^1.0.0" +is-typed-array@^1.1.10, is-typed-array@^1.1.9: + version "1.1.10" + resolved "https://registry.yarnpkg.com/is-typed-array/-/is-typed-array-1.1.10.tgz#36a5b5cb4189b575d1a3e4b08536bfb485801e3f" + integrity sha512-PJqgEHiWZvMpaFZ3uTc8kHPM4+4ADTlDniuQL7cU/UDA0Ql7F70yGfHph3cLNe+c9toaigv+DFzTJKhc2CtO6A== + dependencies: + available-typed-arrays "^1.0.5" + call-bind "^1.0.2" + for-each "^0.3.3" + gopd "^1.0.1" + has-tostringtag "^1.0.0" + is-typedarray@^1.0.0, is-typedarray@~1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/is-typedarray/-/is-typedarray-1.0.0.tgz#e479c80858df0c1b11ddda6940f96011fcda4a9a" @@ -9737,7 +10106,7 @@ istanbul-reports@^3.0.2: html-escaper "^2.0.0" istanbul-lib-report "^3.0.0" -jest-canvas-mock@^2.3.0: +jest-canvas-mock@^2.4.0: version "2.4.0" resolved "https://registry.yarnpkg.com/jest-canvas-mock/-/jest-canvas-mock-2.4.0.tgz#947b71442d7719f8e055decaecdb334809465341" integrity sha512-mmMpZzpmLzn5vepIaHk5HoH3Ka4WykbSoLuG/EKoJd0x0ID/t+INo1l8ByfcUJuDM+RIsL4QDg/gDnBbrj2/IQ== @@ -9925,10 +10294,10 @@ jest-jasmine2@^26.6.3: pretty-format "^26.6.2" throat "^5.0.0" -jest-junit@^14.0.0: - version "14.0.0" - resolved "https://registry.yarnpkg.com/jest-junit/-/jest-junit-14.0.0.tgz#f69fc31bab32224848f443480c2c808fccb2a802" - integrity sha512-kALvBDegstTROfDGXH71UGD7k5g7593Y1wuX1wpWT+QTYcBbmtuGOA8UlAt56zo/B2eMIOcaOVEON3j0VXVa4g== +jest-junit@^15.0.0: + version "15.0.0" + resolved "https://registry.yarnpkg.com/jest-junit/-/jest-junit-15.0.0.tgz#a47544ab42e9f8fe7ada56306c218e09e52bd690" + integrity sha512-Z5sVX0Ag3HZdMUnD5DFlG+1gciIFSy7yIVPhOdGUi8YJaI9iLvvBb530gtQL2CHmv0JJeiwRZenr0VrSR7frvg== dependencies: mkdirp "^1.0.4" strip-ansi "^6.0.1" @@ -10242,6 +10611,11 @@ 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" @@ -11222,7 +11596,7 @@ minimalistic-crypto-utils@^1.0.1: resolved "https://registry.yarnpkg.com/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz#f6c00c1c0b082246e5c4d99dfb8c7c083b2b582a" integrity sha512-JIYlbt6g8i5jKfJ3xz7rF0LXmv2TkDxBLUkiBeZ7bAx4GnnNMr8xFpGnOxn6GhTEHx3SjRrZEoU+j04prX1ktg== -"minimatch@2 || 3", minimatch@^3.0.4, minimatch@^3.1.1, minimatch@^3.1.2: +"minimatch@2 || 3", minimatch@^3.0.4, minimatch@^3.0.5, minimatch@^3.1.1, minimatch@^3.1.2: version "3.1.2" resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.1.2.tgz#19cd194bfd3e428f049a70817c038d89ab4be35b" integrity sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw== @@ -11832,6 +12206,11 @@ nanomatch@^1.2.1, nanomatch@^1.2.9: snapdragon "^0.8.1" to-regex "^3.0.1" +natural-compare-lite@^1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/natural-compare-lite/-/natural-compare-lite-1.4.0.tgz#17b09581988979fddafe0201e931ba933c96cbb4" + integrity sha512-Tj+HTDSJJKaZnfiuw+iaF9skdPpTo2GtEly5JHnWV/hfv2Qj/9RKsGISQtLh2ox3l5EAGw487hnBee0sIJ6v2g== + natural-compare@^1.4.0: version "1.4.0" resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7" @@ -12155,6 +12534,11 @@ object-inspect@^1.12.0, object-inspect@^1.12.2, object-inspect@^1.7.0, object-in resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.12.2.tgz#c0641f26394532f28ab8d796ab954e43c009a8ea" integrity sha512-z+cPxW0QGUp0mcqcsgQyLVRDoXFQbXOwBaqyF7VIgI4TWNQsDHrBpUQslRmIfAoYWdYzs6UlKJtB2XJpTaNSpQ== +object-inspect@^1.12.3: + version "1.12.3" + resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.12.3.tgz#ba62dffd67ee256c8c086dfae69e016cd1f198b9" + integrity sha512-geUvdk7c+eizMNUDkRpW1wJwgfOiOeHbxBR/hLXK1aT6zmVSO0jsQcs7fj6MGw89jC/cjGfLcNOrtMYtGqm81g== + object-is@^1.0.1, object-is@^1.0.2, object-is@^1.1.2: version "1.1.5" resolved "https://registry.yarnpkg.com/object-is/-/object-is-1.1.5.tgz#b9deeaa5fc7f1846a0faecdceec138e5778f53ac" @@ -12185,7 +12569,17 @@ object.assign@^4.1.0, object.assign@^4.1.2: has-symbols "^1.0.1" object-keys "^1.1.1" -object.entries@^1.1.0, object.entries@^1.1.1, object.entries@^1.1.2, object.entries@^1.1.4, object.entries@^1.1.5: +object.assign@^4.1.4: + version "4.1.4" + resolved "https://registry.yarnpkg.com/object.assign/-/object.assign-4.1.4.tgz#9673c7c7c351ab8c4d0b516f4343ebf4dfb7799f" + integrity sha512-1mxKf0e58bvyjSCtKYY4sRe9itRk3PJpquJOjeIkz885CczcI4IvJJDLPS72oowuSh+pBxUFROpX+TU++hxhZQ== + dependencies: + call-bind "^1.0.2" + define-properties "^1.1.4" + has-symbols "^1.0.3" + object-keys "^1.1.1" + +object.entries@^1.1.0, object.entries@^1.1.1, object.entries@^1.1.2, object.entries@^1.1.4: version "1.1.5" resolved "https://registry.yarnpkg.com/object.entries/-/object.entries-1.1.5.tgz#e1acdd17c4de2cd96d5a08487cfb9db84d881861" integrity sha512-TyxmjUoZggd4OrrU1W66FMDG6CuqJxsFvymeyXI51+vQLN67zYfZseptRge703kKQdo4uccgAKebXFcRCzk4+g== @@ -12194,7 +12588,16 @@ object.entries@^1.1.0, object.entries@^1.1.1, object.entries@^1.1.2, object.entr define-properties "^1.1.3" es-abstract "^1.19.1" -object.fromentries@^2.0.0, object.fromentries@^2.0.2, object.fromentries@^2.0.3, object.fromentries@^2.0.5: +object.entries@^1.1.6: + version "1.1.6" + resolved "https://registry.yarnpkg.com/object.entries/-/object.entries-1.1.6.tgz#9737d0e5b8291edd340a3e3264bb8a3b00d5fa23" + integrity sha512-leTPzo4Zvg3pmbQ3rDK69Rl8GQvIqMWubrkxONG9/ojtFE2rD9fjMKfSI5BxW3osRH1m6VdzmqK8oAY9aT4x5w== + dependencies: + call-bind "^1.0.2" + define-properties "^1.1.4" + es-abstract "^1.20.4" + +object.fromentries@^2.0.0, object.fromentries@^2.0.2, object.fromentries@^2.0.3: version "2.0.5" resolved "https://registry.yarnpkg.com/object.fromentries/-/object.fromentries-2.0.5.tgz#7b37b205109c21e741e605727fe8b0ad5fa08251" integrity sha512-CAyG5mWQRRiBU57Re4FKoTBjXfDoNwdFVH2Y1tS9PqCsfUTymAohOkEMSG3aRNKmv4lV3O7p1et7c187q6bynw== @@ -12203,6 +12606,15 @@ object.fromentries@^2.0.0, object.fromentries@^2.0.2, object.fromentries@^2.0.3, define-properties "^1.1.3" es-abstract "^1.19.1" +object.fromentries@^2.0.6: + version "2.0.6" + resolved "https://registry.yarnpkg.com/object.fromentries/-/object.fromentries-2.0.6.tgz#cdb04da08c539cffa912dcd368b886e0904bfa73" + integrity sha512-VciD13dswC4j1Xt5394WR4MzmAQmlgN72phd/riNp9vtD7tp4QQWJ0R4wvclXcafgcYK8veHRed2W6XeGBvcfg== + dependencies: + call-bind "^1.0.2" + define-properties "^1.1.4" + es-abstract "^1.20.4" + object.getownpropertydescriptors@^2.0.3, object.getownpropertydescriptors@^2.1.0: version "2.1.4" resolved "https://registry.yarnpkg.com/object.getownpropertydescriptors/-/object.getownpropertydescriptors-2.1.4.tgz#7965e6437a57278b587383831a9b829455a4bc37" @@ -12213,13 +12625,13 @@ object.getownpropertydescriptors@^2.0.3, object.getownpropertydescriptors@^2.1.0 define-properties "^1.1.4" es-abstract "^1.20.1" -object.hasown@^1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/object.hasown/-/object.hasown-1.1.1.tgz#ad1eecc60d03f49460600430d97f23882cf592a3" - integrity sha512-LYLe4tivNQzq4JdaWW6WO3HMZZJWzkkH8fnI6EebWl0VZth2wL2Lovm74ep2/gZzlaTdV62JZHEqHQ2yVn8Q/A== +object.hasown@^1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/object.hasown/-/object.hasown-1.1.2.tgz#f919e21fad4eb38a57bc6345b3afd496515c3f92" + integrity sha512-B5UIT3J1W+WuWIU55h0mjlwaqxiE5vYENJXIXZ4VFe05pNYrkKuK0U/6aFcb0pKywYJh7IhfoqUfKVmrJJHZHw== dependencies: define-properties "^1.1.4" - es-abstract "^1.19.5" + es-abstract "^1.20.4" object.pick@^1.3.0: version "1.3.0" @@ -12228,7 +12640,7 @@ object.pick@^1.3.0: dependencies: isobject "^3.0.1" -object.values@^1.1.0, object.values@^1.1.1, object.values@^1.1.2, object.values@^1.1.5: +object.values@^1.1.0, object.values@^1.1.1, object.values@^1.1.2: version "1.1.5" resolved "https://registry.yarnpkg.com/object.values/-/object.values-1.1.5.tgz#959f63e3ce9ef108720333082131e4a459b716ac" integrity sha512-QUZRW0ilQ3PnPpbNtgdNV1PDbEqLIiSFB3l+EnGtBQ/8SUTLj1PZwtQHABZtLgwpJZTSZhuGLOGk57Drx2IvYg== @@ -12237,6 +12649,15 @@ object.values@^1.1.0, object.values@^1.1.1, object.values@^1.1.2, object.values@ define-properties "^1.1.3" es-abstract "^1.19.1" +object.values@^1.1.6: + version "1.1.6" + resolved "https://registry.yarnpkg.com/object.values/-/object.values-1.1.6.tgz#4abbaa71eba47d63589d402856f908243eea9b1d" + integrity sha512-FVVTkD1vENCsAcwNs9k6jea2uHC/X0+JcjG8YA60FN5CMaJmG95wT9jek/xX9nornqGRrBkKtzuAu2wuHpKqvw== + dependencies: + call-bind "^1.0.2" + define-properties "^1.1.4" + es-abstract "^1.20.4" + obuf@^1.0.0, obuf@^1.1.2: version "1.1.2" resolved "https://registry.yarnpkg.com/obuf/-/obuf-1.1.2.tgz#09bea3343d41859ebd446292d11c9d4db619084e" @@ -12569,6 +12990,14 @@ parse5-htmlparser2-tree-adapter@^6.0.0, parse5-htmlparser2-tree-adapter@^6.0.1: dependencies: parse5 "^6.0.1" +parse5-htmlparser2-tree-adapter@^7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/parse5-htmlparser2-tree-adapter/-/parse5-htmlparser2-tree-adapter-7.0.0.tgz#23c2cc233bcf09bb7beba8b8a69d46b08c62c2f1" + integrity sha512-B77tOZrqqfUfnVcOrUvfdLbz4pu4RopLD/4vmu3HUPswwTA8OH0EMW9BlWR2B0RCoiZRAHEUu7IxeP1Pd1UU+g== + dependencies: + domhandler "^5.0.2" + parse5 "^7.0.0" + parse5@6.0.1, parse5@^6.0.1: version "6.0.1" resolved "https://registry.yarnpkg.com/parse5/-/parse5-6.0.1.tgz#e1a1c085c569b3dc08321184f19a39cc27f7c30b" @@ -12579,6 +13008,13 @@ parse5@^5.1.1: resolved "https://registry.yarnpkg.com/parse5/-/parse5-5.1.1.tgz#f68e4e5ba1852ac2cadc00f4555fff6c2abb6178" integrity sha512-ugq4DFI0Ptb+WWjAdOK16+u/nHfiIrcE+sh8kZMaM0WllQKLI9rOUq6c2b7cwPkXdzfQESqvoqK6ug7U/Yyzug== +parse5@^7.0.0: + version "7.1.2" + resolved "https://registry.yarnpkg.com/parse5/-/parse5-7.1.2.tgz#0736bebbfd77793823240a23b7fc5e010b7f8e32" + integrity sha512-Czj1WaSVpaoj0wbhMzLmWD69anp2WH7FXMB9n1Sy8/ZFF9jolSQVMu1Ij5WIyGmcBmhk7EOndpO4mIpihVqAXw== + dependencies: + entities "^4.4.0" + parseurl@~1.3.2, parseurl@~1.3.3: version "1.3.3" resolved "https://registry.yarnpkg.com/parseurl/-/parseurl-1.3.3.tgz#9da19e7bee8d12dff0513ed5b76957793bc2e8d4" @@ -13146,11 +13582,16 @@ prettier@1.18.2: resolved "https://registry.yarnpkg.com/prettier/-/prettier-1.18.2.tgz#6823e7c5900017b4bd3acf46fe9ac4b4d7bda9ea" integrity sha512-OeHeMc0JhFE9idD4ZdtNibzY0+TPHSpSSb9h8FqtP+YnoZZ1sl8Vc9b1sasjfymH3SonAF4QcA2+mzHPhMvIiw== -prettier@^2.5.1, prettier@^2.7.1: +prettier@^2.5.1: version "2.7.1" resolved "https://registry.yarnpkg.com/prettier/-/prettier-2.7.1.tgz#e235806850d057f97bb08368a4f7d899f7760c64" integrity sha512-ujppO+MkdPqoVINuDFDRLClm7D78qbDt0/NR+wp5FqEZOoTNAjPHWj17QRhu7geIHJfcNhRk1XVQmF8Bp3ye+g== +prettier@^2.8.5: + version "2.8.6" + resolved "https://registry.yarnpkg.com/prettier/-/prettier-2.8.6.tgz#5c174b29befd507f14b83e3c19f83fdc0e974b71" + integrity sha512-mtuzdiBbHwPEgl7NxWlqOkithPyp4VN93V7VeHVWBF+ad3I5avc0RVDT4oImXQy9H/AqxA2NSQH8pSxHW6FYbQ== + pretty-error@^2.0.2: version "2.1.2" resolved "https://registry.yarnpkg.com/pretty-error/-/pretty-error-2.1.2.tgz#be89f82d81b1c86ec8fdfbc385045882727f93b6" @@ -14274,7 +14715,7 @@ resolve@^1.10.0, resolve@^1.10.1, resolve@^1.12.0, resolve@^1.14.2, resolve@^1.1 path-parse "^1.0.7" supports-preserve-symlinks-flag "^1.0.0" -resolve@^2.0.0-next.3: +resolve@^2.0.0-next.4: version "2.0.0-next.4" resolved "https://registry.yarnpkg.com/resolve/-/resolve-2.0.0-next.4.tgz#3d37a113d6429f496ec4752d2a2e58efb1fd4660" integrity sha512-iMDbmAWtfU+MHpxt/I5iWI7cY6YVEZUQ3MBgPQ++XD1PELuJHIl82xBmObyP2KyQmkNB2dsqF7seoQQiAn5yDQ== @@ -14427,6 +14868,15 @@ safe-buffer@5.2.1, safe-buffer@>=5.1.0, safe-buffer@^5.0.1, safe-buffer@^5.1.0, resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6" integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ== +safe-regex-test@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/safe-regex-test/-/safe-regex-test-1.0.0.tgz#793b874d524eb3640d1873aad03596db2d4f2295" + integrity sha512-JBUUzyOgEwXQY1NuPtvcj/qcBDbDmEvWufhlnXZIm75DEHp+afM1r1ujJpJsV/gSM4t59tpDyPi1sd6ZaPFfsA== + dependencies: + call-bind "^1.0.2" + get-intrinsic "^1.1.3" + is-regex "^1.1.4" + safe-regex@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/safe-regex/-/safe-regex-1.1.0.tgz#40a3669f3b077d1e943d44629e157dd48023bf2e" @@ -15231,7 +15681,7 @@ string-width@^5.0.0: emoji-regex "^9.2.2" strip-ansi "^7.0.1" -string.prototype.matchall@^4.0.2, string.prototype.matchall@^4.0.7: +string.prototype.matchall@^4.0.2: version "4.0.7" resolved "https://registry.yarnpkg.com/string.prototype.matchall/-/string.prototype.matchall-4.0.7.tgz#8e6ecb0d8a1fb1fda470d81acecb2dba057a481d" integrity sha512-f48okCX7JiwVi1NXCVWcFnZgADDC/n2vePlQ/KUCNqCikLLilQvwjMO8+BHVKvgzH0JB0J9LEPgxOGT02RoETg== @@ -15245,6 +15695,20 @@ string.prototype.matchall@^4.0.2, string.prototype.matchall@^4.0.7: regexp.prototype.flags "^1.4.1" side-channel "^1.0.4" +string.prototype.matchall@^4.0.8: + version "4.0.8" + resolved "https://registry.yarnpkg.com/string.prototype.matchall/-/string.prototype.matchall-4.0.8.tgz#3bf85722021816dcd1bf38bb714915887ca79fd3" + integrity sha512-6zOCOcJ+RJAQshcTvXPHoxoQGONa3e/Lqx90wUA+wEzX78sg5Bo+1tQo4N0pohS0erG9qtCqJDjNCQBjeWVxyg== + dependencies: + call-bind "^1.0.2" + define-properties "^1.1.4" + es-abstract "^1.20.4" + get-intrinsic "^1.1.3" + has-symbols "^1.0.3" + internal-slot "^1.0.3" + regexp.prototype.flags "^1.4.3" + side-channel "^1.0.4" + string.prototype.padend@^3.0.0: version "3.1.3" resolved "https://registry.yarnpkg.com/string.prototype.padend/-/string.prototype.padend-3.1.3.tgz#997a6de12c92c7cb34dc8a201a6c53d9bd88a5f1" @@ -15263,6 +15727,15 @@ string.prototype.trim@^1.2.1, string.prototype.trim@^1.2.4: define-properties "^1.1.4" es-abstract "^1.19.5" +string.prototype.trim@^1.2.7: + version "1.2.7" + resolved "https://registry.yarnpkg.com/string.prototype.trim/-/string.prototype.trim-1.2.7.tgz#a68352740859f6893f14ce3ef1bb3037f7a90533" + integrity sha512-p6TmeT1T3411M8Cgg9wBTMRtY2q9+PNy9EV1i2lIXUN/btt763oIfxwN3RR8VU6wHX8j/1CFy0L+YuThm6bgOg== + dependencies: + call-bind "^1.0.2" + define-properties "^1.1.4" + es-abstract "^1.20.4" + string.prototype.trimend@^1.0.5: version "1.0.5" resolved "https://registry.yarnpkg.com/string.prototype.trimend/-/string.prototype.trimend-1.0.5.tgz#914a65baaab25fbdd4ee291ca7dde57e869cb8d0" @@ -15272,6 +15745,15 @@ string.prototype.trimend@^1.0.5: define-properties "^1.1.4" es-abstract "^1.19.5" +string.prototype.trimend@^1.0.6: + version "1.0.6" + resolved "https://registry.yarnpkg.com/string.prototype.trimend/-/string.prototype.trimend-1.0.6.tgz#c4a27fa026d979d79c04f17397f250a462944533" + integrity sha512-JySq+4mrPf9EsDBEDYMOb/lM7XQLulwg5R/m1r0PXEFqrV0qHvl58sdTilSXtKOflCsK2E8jxf+GKC0T07RWwQ== + dependencies: + call-bind "^1.0.2" + define-properties "^1.1.4" + es-abstract "^1.20.4" + string.prototype.trimstart@^1.0.5: version "1.0.5" resolved "https://registry.yarnpkg.com/string.prototype.trimstart/-/string.prototype.trimstart-1.0.5.tgz#5466d93ba58cfa2134839f81d7f42437e8c01fef" @@ -15281,6 +15763,15 @@ string.prototype.trimstart@^1.0.5: define-properties "^1.1.4" es-abstract "^1.19.5" +string.prototype.trimstart@^1.0.6: + version "1.0.6" + resolved "https://registry.yarnpkg.com/string.prototype.trimstart/-/string.prototype.trimstart-1.0.6.tgz#e90ab66aa8e4007d92ef591bbf3cd422c56bdcf4" + integrity sha512-omqjMDaY92pbn5HOX7f9IccLA+U1tA9GvtU4JrodiXFfYB7jPzzHpRzpglLAjtUV6bB557zwClJezTqnAiYnQA== + dependencies: + call-bind "^1.0.2" + define-properties "^1.1.4" + es-abstract "^1.20.4" + string_decoder@^1.0.0, string_decoder@^1.1.1: version "1.3.0" resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.3.0.tgz#42f114594a46cf1a8e30b0a84f56c78c3edac21e" @@ -15978,6 +16469,15 @@ type-is@~1.6.18: media-typer "0.3.0" mime-types "~2.1.24" +typed-array-length@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/typed-array-length/-/typed-array-length-1.0.4.tgz#89d83785e5c4098bec72e08b319651f0eac9c1bb" + integrity sha512-KjZypGq+I/H7HI5HlOoGHkWUUGq+Q0TPhQurLbyrVrvnKTBgzLhIJ7j6J/XTQOi0d1RjyZ0wdas8bKs2p0x3Ng== + dependencies: + call-bind "^1.0.2" + for-each "^0.3.3" + is-typed-array "^1.1.9" + typedarray-to-buffer@^3.1.5: version "3.1.5" resolved "https://registry.yarnpkg.com/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz#a97ee7a9ff42691b9f783ff1bc5112fe3fca9080" @@ -15990,16 +16490,21 @@ typedarray@^0.0.6: resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777" integrity sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA== -typescript@^4.0.0, typescript@^4.5.4: - version "4.7.4" - resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.7.4.tgz#1a88596d1cf47d59507a1bcdfb5b9dfe4d488235" - integrity sha512-C0WQT0gezHuw6AdY1M2jxUO83Rjf0HP7Sk1DtXj6j1EwkQNZrHAg2XPWlq62oqEhYvONq5pkC2Y9oPljWToLmQ== - typescript@^4.3.5, typescript@^4.5.2: version "4.8.4" resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.8.4.tgz#c464abca159669597be5f96b8943500b238e60e6" integrity sha512-QCh+85mCy+h0IGff8r5XWzOVSbBO+KfeYrMQh7NJ58QujwcE22u+NUSmUxqF+un70P9GXKxa2HCNiTTMJknyjQ== +typescript@^4.5.4: + version "4.7.4" + resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.7.4.tgz#1a88596d1cf47d59507a1bcdfb5b9dfe4d488235" + integrity sha512-C0WQT0gezHuw6AdY1M2jxUO83Rjf0HP7Sk1DtXj6j1EwkQNZrHAg2XPWlq62oqEhYvONq5pkC2Y9oPljWToLmQ== + +typescript@^5.0.0: + version "5.0.2" + resolved "https://registry.yarnpkg.com/typescript/-/typescript-5.0.2.tgz#891e1a90c5189d8506af64b9ef929fca99ba1ee5" + integrity sha512-wVORMBGO/FAs/++blGNeAVdbNKtIh1rbBL2EyQ1+J9lClJ93KiiKe8PmFIVdXhHcyv44SL9oglmfeSsndo0jRw== + uglify-js@3.4.x: version "3.4.10" resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-3.4.10.tgz#9ad9563d8eb3acdfb8d38597d2af1d815f6a755f" @@ -16746,6 +17251,18 @@ which-module@^2.0.0: resolved "https://registry.yarnpkg.com/which-module/-/which-module-2.0.0.tgz#d9ef07dce77b9902b8a3a8fa4b31c3e3f7e6e87a" integrity sha512-B+enWhmw6cjfVC7kS8Pj9pCrKSc5txArRyaYGe088shv/FGWH+0Rjx/xPgtsWfsUtS27FkP697E4DDhgrgoc0Q== +which-typed-array@^1.1.9: + version "1.1.9" + resolved "https://registry.yarnpkg.com/which-typed-array/-/which-typed-array-1.1.9.tgz#307cf898025848cf995e795e8423c7f337efbde6" + integrity sha512-w9c4xkx6mPidwp7180ckYWfMmvxpjlZuIudNtDf4N/tTAUB8VJbX25qZoAsrtGuYNnGw3pa0AXgbGKRB8/EceA== + dependencies: + available-typed-arrays "^1.0.5" + call-bind "^1.0.2" + for-each "^0.3.3" + gopd "^1.0.1" + has-tostringtag "^1.0.0" + is-typed-array "^1.1.10" + which@^1.2.9: version "1.3.1" resolved "https://registry.yarnpkg.com/which/-/which-1.3.1.tgz#a45043d54f5805316da8d62f9f50918d3da70b0a"