diff --git a/package-lock.json b/package-lock.json index d3a18cd3c..65644c140 100644 --- a/package-lock.json +++ b/package-lock.json @@ -48,8 +48,8 @@ "redux-logger": "^3.0.6", "redux-persist": "^6.0.0", "redux-state-sync": "^3.1.4", - "sanitize-html": "^2.12.1", - "tss-react": "^4.8.4" + "tss-react": "^4.8.4", + "uuid": "^9.0.1" }, "devDependencies": { "@testing-library/dom": "^8.20.0", @@ -71,7 +71,6 @@ "@types/react-router": "^5.1.20", "@types/react-router-dom": "^5.3.3", "@types/redux-logger": "^3.0.9", - "@types/sanitize-html": "^2.11.0", "@types/uuid": "^8.3.4", "@typescript-eslint/eslint-plugin": "^5.57.0", "@typescript-eslint/parser": "^5.57.0", @@ -5958,61 +5957,6 @@ "integrity": "sha512-wWKOClTTiizcZhXnPY4wikVAwmdYHp8q6DmC+EJUzAMsycb7HB32Kh9RN4+0gExjmPmZSAQjgURXIGATPegAvA==", "peer": true }, - "node_modules/@types/sanitize-html": { - "version": "2.11.0", - "resolved": "https://registry.npmjs.org/@types/sanitize-html/-/sanitize-html-2.11.0.tgz", - "integrity": "sha512-7oxPGNQHXLHE48r/r/qjn7q0hlrs3kL7oZnGj0Wf/h9tj/6ibFyRkNbsDxaBBZ4XUZ0Dx5LGCyDJ04ytSofacQ==", - "dev": true, - "dependencies": { - "htmlparser2": "^8.0.0" - } - }, - "node_modules/@types/sanitize-html/node_modules/domelementtype": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz", - "integrity": "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/fb55" - } - ] - }, - "node_modules/@types/sanitize-html/node_modules/domhandler": { - "version": "5.0.3", - "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-5.0.3.tgz", - "integrity": "sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==", - "dev": true, - "dependencies": { - "domelementtype": "^2.3.0" - }, - "engines": { - "node": ">= 4" - }, - "funding": { - "url": "https://github.com/fb55/domhandler?sponsor=1" - } - }, - "node_modules/@types/sanitize-html/node_modules/htmlparser2": { - "version": "8.0.2", - "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-8.0.2.tgz", - "integrity": "sha512-GYdjWKDkbRLkZ5geuHs5NY1puJ+PXwP7+fHPRz06Eirsb9ugf6d8kkXav6ADhcODhFFPMIXyxkxSuMf3D6NCFA==", - "dev": true, - "funding": [ - "https://github.com/fb55/htmlparser2?sponsor=1", - { - "type": "github", - "url": "https://github.com/sponsors/fb55" - } - ], - "dependencies": { - "domelementtype": "^2.3.0", - "domhandler": "^5.0.3", - "domutils": "^3.0.1", - "entities": "^4.4.0" - } - }, "node_modules/@types/scheduler": { "version": "0.16.8", "resolved": "https://registry.npmjs.org/@types/scheduler/-/scheduler-0.16.8.tgz", @@ -9705,6 +9649,7 @@ "version": "4.3.1", "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz", "integrity": "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==", + "peer": true, "engines": { "node": ">=0.10.0" } @@ -13000,14 +12945,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/is-plain-object": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-5.0.0.tgz", - "integrity": "sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q==", - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/is-potential-custom-element-name": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.1.tgz", @@ -16479,11 +16416,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/parse-srcset": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/parse-srcset/-/parse-srcset-1.0.2.tgz", - "integrity": "sha512-/2qh0lav6CmI15FzA3i/2Bzk2zCgQhGMkvhOhKNcBVQ1ldgpbfiNTVslmooUmWJcADi1f1kIeynbDRVzNlfR6Q==" - }, "node_modules/parse5": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/parse5/-/parse5-6.0.1.tgz", @@ -19422,62 +19354,6 @@ "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" }, - "node_modules/sanitize-html": { - "version": "2.12.1", - "resolved": "https://registry.npmjs.org/sanitize-html/-/sanitize-html-2.12.1.tgz", - "integrity": "sha512-Plh+JAn0UVDpBRP/xEjsk+xDCoOvMBwQUf/K+/cBAVuTbtX8bj2VB7S1sL1dssVpykqp0/KPSesHrqXtokVBpA==", - "dependencies": { - "deepmerge": "^4.2.2", - "escape-string-regexp": "^4.0.0", - "htmlparser2": "^8.0.0", - "is-plain-object": "^5.0.0", - "parse-srcset": "^1.0.2", - "postcss": "^8.3.11" - } - }, - "node_modules/sanitize-html/node_modules/domelementtype": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz", - "integrity": "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/fb55" - } - ] - }, - "node_modules/sanitize-html/node_modules/domhandler": { - "version": "5.0.3", - "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-5.0.3.tgz", - "integrity": "sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==", - "dependencies": { - "domelementtype": "^2.3.0" - }, - "engines": { - "node": ">= 4" - }, - "funding": { - "url": "https://github.com/fb55/domhandler?sponsor=1" - } - }, - "node_modules/sanitize-html/node_modules/htmlparser2": { - "version": "8.0.2", - "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-8.0.2.tgz", - "integrity": "sha512-GYdjWKDkbRLkZ5geuHs5NY1puJ+PXwP7+fHPRz06Eirsb9ugf6d8kkXav6ADhcODhFFPMIXyxkxSuMf3D6NCFA==", - "funding": [ - "https://github.com/fb55/htmlparser2?sponsor=1", - { - "type": "github", - "url": "https://github.com/sponsors/fb55" - } - ], - "dependencies": { - "domelementtype": "^2.3.0", - "domhandler": "^5.0.3", - "domutils": "^3.0.1", - "entities": "^4.4.0" - } - }, "node_modules/sanitize.css": { "version": "13.0.0", "resolved": "https://registry.npmjs.org/sanitize.css/-/sanitize.css-13.0.0.tgz", @@ -19892,6 +19768,15 @@ "websocket-driver": "^0.7.4" } }, + "node_modules/sockjs/node_modules/uuid": { + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", + "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", + "peer": true, + "bin": { + "uuid": "dist/bin/uuid" + } + }, "node_modules/source-list-map": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/source-list-map/-/source-list-map-2.0.1.tgz", @@ -21498,10 +21383,13 @@ } }, "node_modules/uuid": { - "version": "8.3.2", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", - "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", - "peer": true, + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.1.tgz", + "integrity": "sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==", + "funding": [ + "https://github.com/sponsors/broofa", + "https://github.com/sponsors/ctavan" + ], "bin": { "uuid": "dist/bin/uuid" } @@ -27282,44 +27170,6 @@ "integrity": "sha512-wWKOClTTiizcZhXnPY4wikVAwmdYHp8q6DmC+EJUzAMsycb7HB32Kh9RN4+0gExjmPmZSAQjgURXIGATPegAvA==", "peer": true }, - "@types/sanitize-html": { - "version": "2.11.0", - "resolved": "https://registry.npmjs.org/@types/sanitize-html/-/sanitize-html-2.11.0.tgz", - "integrity": "sha512-7oxPGNQHXLHE48r/r/qjn7q0hlrs3kL7oZnGj0Wf/h9tj/6ibFyRkNbsDxaBBZ4XUZ0Dx5LGCyDJ04ytSofacQ==", - "dev": true, - "requires": { - "htmlparser2": "^8.0.0" - }, - "dependencies": { - "domelementtype": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz", - "integrity": "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==", - "dev": true - }, - "domhandler": { - "version": "5.0.3", - "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-5.0.3.tgz", - "integrity": "sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==", - "dev": true, - "requires": { - "domelementtype": "^2.3.0" - } - }, - "htmlparser2": { - "version": "8.0.2", - "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-8.0.2.tgz", - "integrity": "sha512-GYdjWKDkbRLkZ5geuHs5NY1puJ+PXwP7+fHPRz06Eirsb9ugf6d8kkXav6ADhcODhFFPMIXyxkxSuMf3D6NCFA==", - "dev": true, - "requires": { - "domelementtype": "^2.3.0", - "domhandler": "^5.0.3", - "domutils": "^3.0.1", - "entities": "^4.4.0" - } - } - } - }, "@types/scheduler": { "version": "0.16.8", "resolved": "https://registry.npmjs.org/@types/scheduler/-/scheduler-0.16.8.tgz", @@ -30120,7 +29970,8 @@ "deepmerge": { "version": "4.3.1", "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz", - "integrity": "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==" + "integrity": "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==", + "peer": true }, "default-gateway": { "version": "6.0.3", @@ -32516,11 +32367,6 @@ "integrity": "sha512-gwsOE28k+23GP1B6vFl1oVh/WOzmawBrKwo5Ev6wMKzPkaXaCDIQKzLnvsA42DRlbVTWorkgTKIviAKCWkfUwA==", "peer": true }, - "is-plain-object": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-5.0.0.tgz", - "integrity": "sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q==" - }, "is-potential-custom-element-name": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.1.tgz", @@ -35259,11 +35105,6 @@ "lines-and-columns": "^1.1.6" } }, - "parse-srcset": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/parse-srcset/-/parse-srcset-1.0.2.tgz", - "integrity": "sha512-/2qh0lav6CmI15FzA3i/2Bzk2zCgQhGMkvhOhKNcBVQ1ldgpbfiNTVslmooUmWJcADi1f1kIeynbDRVzNlfR6Q==" - }, "parse5": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/parse5/-/parse5-6.0.1.tgz", @@ -37228,45 +37069,6 @@ "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" }, - "sanitize-html": { - "version": "2.12.1", - "resolved": "https://registry.npmjs.org/sanitize-html/-/sanitize-html-2.12.1.tgz", - "integrity": "sha512-Plh+JAn0UVDpBRP/xEjsk+xDCoOvMBwQUf/K+/cBAVuTbtX8bj2VB7S1sL1dssVpykqp0/KPSesHrqXtokVBpA==", - "requires": { - "deepmerge": "^4.2.2", - "escape-string-regexp": "^4.0.0", - "htmlparser2": "^8.0.0", - "is-plain-object": "^5.0.0", - "parse-srcset": "^1.0.2", - "postcss": "8.4.31" - }, - "dependencies": { - "domelementtype": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz", - "integrity": "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==" - }, - "domhandler": { - "version": "5.0.3", - "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-5.0.3.tgz", - "integrity": "sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==", - "requires": { - "domelementtype": "^2.3.0" - } - }, - "htmlparser2": { - "version": "8.0.2", - "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-8.0.2.tgz", - "integrity": "sha512-GYdjWKDkbRLkZ5geuHs5NY1puJ+PXwP7+fHPRz06Eirsb9ugf6d8kkXav6ADhcODhFFPMIXyxkxSuMf3D6NCFA==", - "requires": { - "domelementtype": "^2.3.0", - "domhandler": "^5.0.3", - "domutils": "^3.0.1", - "entities": "^4.4.0" - } - } - } - }, "sanitize.css": { "version": "13.0.0", "resolved": "https://registry.npmjs.org/sanitize.css/-/sanitize.css-13.0.0.tgz", @@ -37598,6 +37400,14 @@ "faye-websocket": "^0.11.3", "uuid": "^8.3.2", "websocket-driver": "^0.7.4" + }, + "dependencies": { + "uuid": { + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", + "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", + "peer": true + } } }, "source-list-map": { @@ -38804,10 +38614,9 @@ "peer": true }, "uuid": { - "version": "8.3.2", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", - "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", - "peer": true + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.1.tgz", + "integrity": "sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==" }, "v8-to-istanbul": { "version": "8.1.1", diff --git a/src/components/CreationCohort/DiagramView/components/CriteriaCard/styles.ts b/src/components/CreationCohort/DiagramView/components/CriteriaCard/styles.ts index 67ff6ac38..975bf1ea6 100644 --- a/src/components/CreationCohort/DiagramView/components/CriteriaCard/styles.ts +++ b/src/components/CreationCohort/DiagramView/components/CriteriaCard/styles.ts @@ -19,7 +19,6 @@ const useStyles = makeStyles()((theme: Theme) => ({ } }, title: { - whiteSpace: 'nowrap', marginLeft: 4 }, secondItem: { diff --git a/src/components/CreationCohort/DiagramView/components/LogicalOperator/components/CriteriaRightPanel/AdvancedInputs/OccurrencesInputs/OccurrenceNumberInputs.tsx b/src/components/CreationCohort/DiagramView/components/LogicalOperator/components/CriteriaRightPanel/AdvancedInputs/OccurrencesInputs/OccurrenceNumberInputs.tsx deleted file mode 100644 index 6d853f2b6..000000000 --- a/src/components/CreationCohort/DiagramView/components/LogicalOperator/components/CriteriaRightPanel/AdvancedInputs/OccurrencesInputs/OccurrenceNumberInputs.tsx +++ /dev/null @@ -1,126 +0,0 @@ -import React, { useEffect, useMemo, useState } from 'react' - -import { FormLabel, Grid, MenuItem, Select, TextField, Tooltip } from '@mui/material' -import InfoIcon from '@mui/icons-material/Info' - -import { CriteriaName, CriteriaNameType } from 'types' - -const defaultOccurrencesNumberInputs = { - code: [], - isLeaf: false, - valueMin: 1, - valueMax: 99999, - valueComparator: '>=', - occurrence: 1, - occurrenceComparator: '>=', - startOccurrence: '', - endOccurrence: '', - isInclusive: true -} - -const getMinForComparatorType = (comparator: string) => { - if (comparator === '<') return 1 - return 0 -} - -type OccurrencesNumberInputsProps = { - form: CriteriaNameType - selectedCriteria: any - onChangeValue: (key: string, value: any) => void -} - -const OccurrencesNumberInputs: React.FC = (props) => { - const { form, onChangeValue } = props - const [invalidOccurrenceNumber, setInvalidOccurenceNumber] = useState(false) - const selectedCriteria = { ...defaultOccurrencesNumberInputs, ...props.selectedCriteria } - const minValue = useMemo( - () => getMinForComparatorType(selectedCriteria.occurrenceComparator), - [selectedCriteria.occurrenceComparator] - ) - - const _onChangeOccurenceNumber = (value: string) => { - // this method prevent entering a number like "12" if the comparator is "<" since the first digit "1" is not valid - // but this use case won't happen often i guess - // also this can be got around by multiples ways (copy/paste, using the arrows, selecting comparator <= first, etc.) - try { - const occNumber = parseInt(value) - if (occNumber < minValue) { - setInvalidOccurenceNumber(true) - return - } - setInvalidOccurenceNumber(false) - onChangeValue('occurrence', occNumber) - } catch (error) { - // should never happen because of the input type and the keypress filter - } - } - - useEffect(() => { - if (selectedCriteria.occurrence < minValue) { - onChangeValue('occurrence', minValue) - return - } - }, [selectedCriteria.occurrenceComparator]) - - return ( - <> - - Nombre d'occurrences - {(form == CriteriaName.Ccam || - form === CriteriaName.Cim10 || - form === CriteriaName.Ghm || - form == CriteriaName.Biology || - CriteriaName.VisitSupport) && ( - - { - "Si vous choisissez un chapitre, le nombre d'occurrences ne s'applique pas sur un unique élément de ce chapitre, mais sur l'ensemble des éléments de ce chapitre." - } -
-
- { - "Exemple: Nombre d'occurrences >= 3 sur un chapitre signifie que l'on inclus les patients qui ont eu au moins 3 éléments de ce chapitre, distincts ou non" - } - - } - > - -
- )} -
- - - - - _onChangeOccurenceNumber(e.target.value)} - /> - - - ) -} - -export default OccurrencesNumberInputs diff --git a/src/components/CreationCohort/DiagramView/components/LogicalOperator/components/CriteriaRightPanel/BiologyForm/components/Form/BiologyForm.tsx b/src/components/CreationCohort/DiagramView/components/LogicalOperator/components/CriteriaRightPanel/BiologyForm/components/Form/BiologyForm.tsx index a6fcc5e1e..018f2cbe6 100644 --- a/src/components/CreationCohort/DiagramView/components/LogicalOperator/components/CriteriaRightPanel/BiologyForm/components/Form/BiologyForm.tsx +++ b/src/components/CreationCohort/DiagramView/components/LogicalOperator/components/CriteriaRightPanel/BiologyForm/components/Form/BiologyForm.tsx @@ -24,10 +24,11 @@ import useStyles from './styles' import { useAppDispatch, useAppSelector } from 'state' import { fetchBiology } from 'state/biology' import { CriteriaItemDataCache, CriteriaName, HierarchyTree } from 'types' -import OccurrencesNumberInputs from '../../../AdvancedInputs/OccurrencesInputs/OccurrenceNumberInputs' import AdvancedInputs from '../../../AdvancedInputs/AdvancedInputs' import { ObservationDataType, Comparators } from 'types/requestCriterias' import services from 'services/aphp' +import { BlockWrapper } from 'components/ui/Layout' +import OccurenceInput from 'components/ui/Inputs/Occurences' type BiologyFormProps = { isOpen: boolean @@ -50,9 +51,13 @@ const BiologyForm: React.FC = (props) => { const [allowSearchByValue, setAllowSearchByValue] = useState( typeof currentState.searchByValue[0] === 'number' || typeof currentState.searchByValue[1] === 'number' ) + const [occurrence, setOccurrence] = useState(currentState.occurrence || 1) + const [occurrenceComparator, setOccurrenceComparator] = useState( + currentState.occurrenceComparator || Comparators.GREATER_OR_EQUAL + ) const _onSubmit = () => { - onChangeSelectedCriteria(currentState) + onChangeSelectedCriteria({ ...currentState, occurrence: occurrence, occurrenceComparator: occurrenceComparator }) dispatch(fetchBiology()) } @@ -73,28 +78,22 @@ const BiologyForm: React.FC = (props) => { try { const getChildrenResp = await services.cohortCreation.fetchBiologyHierarchy(currentState.code?.[0].id) - if (getChildrenResp.length > 0) { - if (currentState.isLeaf !== false) { - onChangeValue('isLeaf', false) - } - } else { - if (currentState.isLeaf !== true) { - onChangeValue('isLeaf', true) - } - } + getChildrenResp?.length > 0 ? onChangeValue('isLeaf', false) : onChangeValue('isLeaf', true) } catch (error) { console.error('Erreur lors du check des enfants du code de biologie sélectionné', error) } } - if (currentState?.code?.length === 1 && currentState?.code[0].id !== '*') { - checkChildren() - } else { - if (currentState.isLeaf !== false) { - onChangeValue('isLeaf', false) - } + currentState?.code?.length === 1 && currentState?.code[0].id !== '*' + ? checkChildren() + : onChangeValue('isLeaf', false) + }, [currentState?.code]) + + useEffect(() => { + if (!currentState.isLeaf) { + setAllowSearchByValue(false) } - }, [currentState.isLeaf, currentState?.code]) + }, [currentState.isLeaf]) useEffect(() => { if (!allowSearchByValue) { @@ -166,11 +165,33 @@ const BiologyForm: React.FC = (props) => { /> - + + + + Nombre d'occurrences + + Si vous choisissez un chapitre, le nombre d'occurrences ne s'applique pas sur un unique élément de + ce chapitre, mais sur l'ensemble des éléments de ce chapitre.
Exemple: Nombre d'occurrences + ≥ 3 sur un chapitre signifie que l'on inclus les patients qui ont eu au moins 3 éléments de ce + chapitre, distincts ou non` + + } + > + +
+
+
+ { + setOccurrence(newOccurence) + setOccurrenceComparator(newComparator) + }} + /> +
Codes de biologie diff --git a/src/components/CreationCohort/DiagramView/components/LogicalOperator/components/CriteriaRightPanel/BiologyForm/components/Form/styles.ts b/src/components/CreationCohort/DiagramView/components/LogicalOperator/components/CriteriaRightPanel/BiologyForm/components/Form/styles.ts index 8765a8bcb..dfb355e06 100644 --- a/src/components/CreationCohort/DiagramView/components/LogicalOperator/components/CriteriaRightPanel/BiologyForm/components/Form/styles.ts +++ b/src/components/CreationCohort/DiagramView/components/LogicalOperator/components/CriteriaRightPanel/BiologyForm/components/Form/styles.ts @@ -47,6 +47,12 @@ const useStyles = makeStyles()(() => ({ '& > button': { margin: '12px 8px' } + }, + durationLegend: { + color: '#153D8A', + fontWeight: 600, + fontSize: 12, + paddingBottom: 10 } })) diff --git a/src/components/CreationCohort/DiagramView/components/LogicalOperator/components/CriteriaRightPanel/CCAM/components/Form/CCAMForm.tsx b/src/components/CreationCohort/DiagramView/components/LogicalOperator/components/CriteriaRightPanel/CCAM/components/Form/CCAMForm.tsx index f06122529..4784712ac 100644 --- a/src/components/CreationCohort/DiagramView/components/LogicalOperator/components/CriteriaRightPanel/CCAM/components/Form/CCAMForm.tsx +++ b/src/components/CreationCohort/DiagramView/components/LogicalOperator/components/CriteriaRightPanel/CCAM/components/Form/CCAMForm.tsx @@ -12,9 +12,11 @@ import { Typography, Radio, RadioGroup, - FormControlLabel + FormControlLabel, + Tooltip } from '@mui/material' +import InfoIcon from '@mui/icons-material/Info' import KeyboardBackspaceIcon from '@mui/icons-material/KeyboardBackspace' import AdvancedInputs from 'components/CreationCohort/DiagramView/components/LogicalOperator/components/CriteriaRightPanel/AdvancedInputs/AdvancedInputs' @@ -23,10 +25,11 @@ import useStyles from './styles' import { useAppDispatch, useAppSelector } from 'state' import { fetchProcedure } from 'state/pmsi' import { CriteriaItemDataCache, CriteriaName, HierarchyTree } from 'types' -import OccurrencesNumberInputs from '../../../AdvancedInputs/OccurrencesInputs/OccurrenceNumberInputs' import AsyncAutocomplete from 'components/ui/Inputs/AsyncAutocomplete' import services from 'services/aphp' -import { CcamDataType } from 'types/requestCriterias' +import { CcamDataType, Comparators } from 'types/requestCriterias' +import { BlockWrapper } from 'components/ui/Layout' +import OccurenceInput from 'components/ui/Inputs/Occurences' type CcamFormProps = { isOpen: boolean @@ -46,9 +49,13 @@ const CcamForm: React.FC = (props) => { const initialState: HierarchyTree | null = useAppSelector((state) => state.syncHierarchyTable) const currentState = { ...selectedCriteria, ...initialState } const [multiFields, setMultiFields] = useState(localStorage.getItem('multiple_fields')) + const [occurrence, setOccurrence] = useState(currentState.occurrence || 1) + const [occurrenceComparator, setOccurrenceComparator] = useState( + currentState.occurrenceComparator || Comparators.GREATER_OR_EQUAL + ) const _onSubmit = () => { - onChangeSelectedCriteria(currentState) + onChangeSelectedCriteria({ ...currentState, occurrence: occurrence, occurrenceComparator: occurrenceComparator }) dispatch(fetchProcedure()) } @@ -128,11 +135,33 @@ const CcamForm: React.FC = (props) => { /> - + + + + Nombre d'occurrences + + Si vous choisissez un chapitre, le nombre d'occurrences ne s'applique pas sur un unique élément de + ce chapitre, mais sur l'ensemble des éléments de ce chapitre.
Exemple: Nombre d'occurrences + ≥ 3 sur un chapitre signifie que l'on inclus les patients qui ont eu au moins 3 éléments de ce + chapitre, distincts ou non` + + } + > + +
+
+
+ { + setOccurrence(newOccurence) + setOccurrenceComparator(newComparator) + }} + /> +
({ '& > button': { margin: '12px 8px' } + }, + durationLegend: { + color: '#153D8A', + fontWeight: 600, + fontSize: 12, + paddingBottom: 10 } })) diff --git a/src/components/CreationCohort/DiagramView/components/LogicalOperator/components/CriteriaRightPanel/Cim10Form/components/Form/Cim10Form.tsx b/src/components/CreationCohort/DiagramView/components/LogicalOperator/components/CriteriaRightPanel/Cim10Form/components/Form/Cim10Form.tsx index 47a31eb09..42839fe4f 100644 --- a/src/components/CreationCohort/DiagramView/components/LogicalOperator/components/CriteriaRightPanel/Cim10Form/components/Form/Cim10Form.tsx +++ b/src/components/CreationCohort/DiagramView/components/LogicalOperator/components/CriteriaRightPanel/Cim10Form/components/Form/Cim10Form.tsx @@ -11,9 +11,11 @@ import { Link, Switch, TextField, + Tooltip, Typography } from '@mui/material' +import InfoIcon from '@mui/icons-material/Info' import KeyboardBackspaceIcon from '@mui/icons-material/KeyboardBackspace' import AdvancedInputs from '../../../AdvancedInputs/AdvancedInputs' @@ -22,10 +24,11 @@ import useStyles from './styles' import { useAppDispatch, useAppSelector } from 'state' import { fetchCondition } from 'state/pmsi' import { CriteriaItemDataCache, CriteriaName, HierarchyTree } from 'types' -import OccurrencesNumberInputs from '../../../AdvancedInputs/OccurrencesInputs/OccurrenceNumberInputs' import AsyncAutocomplete from 'components/ui/Inputs/AsyncAutocomplete' import services from 'services/aphp' -import { Cim10DataType } from 'types/requestCriterias' +import { Cim10DataType, Comparators } from 'types/requestCriterias' +import { BlockWrapper } from 'components/ui/Layout' +import OccurenceInput from 'components/ui/Inputs/Occurences' type Cim10FormProps = { isOpen: boolean @@ -46,9 +49,14 @@ const Cim10Form: React.FC = (props) => { const currentState = { ...selectedCriteria, ...initialState } const [multiFields, setMultiFields] = useState(localStorage.getItem('multiple_fields')) const _onSubmit = () => { - onChangeSelectedCriteria(currentState) + onChangeSelectedCriteria({ ...currentState, occurrence: occurrence, occurrenceComparator: occurrenceComparator }) dispatch(fetchCondition()) } + const [occurrence, setOccurrence] = useState(currentState.occurrence || 1) + const [occurrenceComparator, setOccurrenceComparator] = useState( + currentState.occurrenceComparator || Comparators.GREATER_OR_EQUAL + ) + const getDiagOptions = async (searchValue: string, signal: AbortSignal) => await services.cohortCreation.fetchCim10Diagnostic(searchValue, false, signal) @@ -142,11 +150,34 @@ const Cim10Form: React.FC = (props) => { color="secondary" /> - + + + + + Nombre d'occurrences + + Si vous choisissez un chapitre, le nombre d'occurrences ne s'applique pas sur un unique élément de + ce chapitre, mais sur l'ensemble des éléments de ce chapitre.
Exemple: Nombre d'occurrences + ≥ 3 sur un chapitre signifie que l'on inclus les patients qui ont eu au moins 3 éléments de ce + chapitre, distincts ou non` + + } + > + +
+
+
+ { + setOccurrence(newOccurence) + setOccurrenceComparator(newComparator) + }} + /> +
({ '& > button': { margin: '12px 8px' } + }, + durationLegend: { + color: '#153D8A', + fontWeight: 600, + fontSize: 12, + paddingBottom: 10 } })) diff --git a/src/components/CreationCohort/DiagramView/components/LogicalOperator/components/CriteriaRightPanel/DocumentsForm/DocumentsForm.tsx b/src/components/CreationCohort/DiagramView/components/LogicalOperator/components/CriteriaRightPanel/DocumentsForm/DocumentsForm.tsx index f29e589bc..6aa7ac3ea 100644 --- a/src/components/CreationCohort/DiagramView/components/LogicalOperator/components/CriteriaRightPanel/DocumentsForm/DocumentsForm.tsx +++ b/src/components/CreationCohort/DiagramView/components/LogicalOperator/components/CriteriaRightPanel/DocumentsForm/DocumentsForm.tsx @@ -29,13 +29,14 @@ import useStyles from './styles' import { CriteriaDrawerComponentProps, CriteriaName } from 'types' import services from 'services/aphp' import { useDebounce } from 'utils/debounce' -import OccurrencesNumberInputs from '../AdvancedInputs/OccurrencesInputs/OccurrenceNumberInputs' import { SearchByTypes } from 'types/searchCriterias' import { IndeterminateCheckBoxOutlined } from '@mui/icons-material' import { SearchInputError } from 'types/error' import { Comparators, DocType, DocumentDataType, RessourceType } from 'types/requestCriterias' import Searchbar from 'components/ui/Searchbar' import SearchInput from 'components/ui/Searchbar/SearchInput' +import { BlockWrapper } from 'components/ui/Layout' +import OccurenceInput from 'components/ui/Inputs/Occurences' const defaultComposition: Omit = { type: RessourceType.DOCUMENTS, @@ -62,12 +63,16 @@ const CompositionForm: React.FC = (props) => { const [multiFields, setMultiFields] = useState(localStorage.getItem('multiple_fields')) const [searchCheckingLoading, setSearchCheckingLoading] = useState(false) const [searchInputError, setSearchInputError] = useState(undefined) + const [occurrence, setOccurrence] = useState(defaultValues.occurrence || 1) + const [occurrenceComparator, setOccurrenceComparator] = useState( + defaultValues.occurrenceComparator || Comparators.GREATER_OR_EQUAL + ) const debouncedSearchItem = useDebounce(500, defaultValues.search) const isEdition = selectedCriteria !== null ? true : false const _onSubmit = () => { - onChangeSelectedCriteria(defaultValues) + onChangeSelectedCriteria({ ...defaultValues, occurrence: occurrence, occurrenceComparator: occurrenceComparator }) } const _onChangeValue = (key: string, value: any) => { @@ -151,11 +156,19 @@ const CompositionForm: React.FC = (props) => { /> - + + + Nombre d'occurrences + + { + setOccurrence(newOccurence) + setOccurrenceComparator(newComparator) + }} + /> + Rechercher dans : diff --git a/src/components/CreationCohort/DiagramView/components/LogicalOperator/components/CriteriaRightPanel/DocumentsForm/styles.ts b/src/components/CreationCohort/DiagramView/components/LogicalOperator/components/CriteriaRightPanel/DocumentsForm/styles.ts index 0438c36ca..954de4de5 100644 --- a/src/components/CreationCohort/DiagramView/components/LogicalOperator/components/CriteriaRightPanel/DocumentsForm/styles.ts +++ b/src/components/CreationCohort/DiagramView/components/LogicalOperator/components/CriteriaRightPanel/DocumentsForm/styles.ts @@ -53,6 +53,12 @@ const useStyles = makeStyles()(() => ({ height: 50, padding: '10px 0px' } + }, + durationLegend: { + color: '#153D8A', + fontWeight: 600, + fontSize: 12, + paddingBottom: 10 } })) diff --git a/src/components/CreationCohort/DiagramView/components/LogicalOperator/components/CriteriaRightPanel/GHM/components/Form/GhmForm.tsx b/src/components/CreationCohort/DiagramView/components/LogicalOperator/components/CriteriaRightPanel/GHM/components/Form/GhmForm.tsx index ba1742663..5e51a8a38 100644 --- a/src/components/CreationCohort/DiagramView/components/LogicalOperator/components/CriteriaRightPanel/GHM/components/Form/GhmForm.tsx +++ b/src/components/CreationCohort/DiagramView/components/LogicalOperator/components/CriteriaRightPanel/GHM/components/Form/GhmForm.tsx @@ -1,18 +1,32 @@ import React, { useState } from 'react' -import { Alert, Button, Divider, FormLabel, Grid, IconButton, Link, Switch, TextField, Typography } from '@mui/material' - +import { + Alert, + Button, + Divider, + FormLabel, + Grid, + IconButton, + Link, + Switch, + TextField, + Tooltip, + Typography +} from '@mui/material' + +import InfoIcon from '@mui/icons-material/Info' import KeyboardBackspaceIcon from '@mui/icons-material/KeyboardBackspace' import useStyles from './styles' import { useAppDispatch, useAppSelector } from 'state' import { fetchClaim } from 'state/pmsi' import { CriteriaItemDataCache, CriteriaName, HierarchyTree } from 'types' -import OccurrencesNumberInputs from '../../../AdvancedInputs/OccurrencesInputs/OccurrenceNumberInputs' import AdvancedInputs from '../../../AdvancedInputs/AdvancedInputs' import AsyncAutocomplete from 'components/ui/Inputs/AsyncAutocomplete' import services from 'services/aphp' -import { GhmDataType } from 'types/requestCriterias' +import { Comparators, GhmDataType } from 'types/requestCriterias' +import { BlockWrapper } from 'components/ui/Layout' +import OccurenceInput from 'components/ui/Inputs/Occurences' type GHMFormProps = { isOpen: boolean @@ -32,11 +46,15 @@ const GhmForm: React.FC = (props) => { const initialState: HierarchyTree | null = useAppSelector((state) => state.syncHierarchyTable) const currentState = { ...selectedCriteria, ...initialState } const [multiFields, setMultiFields] = useState(localStorage.getItem('multiple_fields')) + const [occurrence, setOccurrence] = useState(currentState.occurrence || 1) + const [occurrenceComparator, setOccurrenceComparator] = useState( + currentState.occurrenceComparator || Comparators.GREATER_OR_EQUAL + ) const getGhmOptions = async (searchValue: string, signal: AbortSignal) => await services.cohortCreation.fetchGhmData(searchValue, false, signal) const _onSubmit = () => { - onChangeSelectedCriteria(currentState) + onChangeSelectedCriteria({ ...currentState, occurrence: occurrence, occurrenceComparator: occurrenceComparator }) dispatch(fetchClaim()) } const defaultValuesCode = currentState.code @@ -121,11 +139,33 @@ const GhmForm: React.FC = (props) => { /> - + + + + Nombre d'occurrences + + Si vous choisissez un chapitre, le nombre d'occurrences ne s'applique pas sur un unique élément de + ce chapitre, mais sur l'ensemble des éléments de ce chapitre.
Exemple: Nombre d'occurrences + ≥ 3 sur un chapitre signifie que l'on inclus les patients qui ont eu au moins 3 éléments de ce + chapitre, distincts ou non` + + } + > + +
+
+
+ { + setOccurrence(newOccurence) + setOccurrenceComparator(newComparator) + }} + /> +
({ '& > button': { margin: '12px 8px' } + }, + durationLegend: { + color: '#153D8A', + fontWeight: 600, + fontSize: 12, + paddingBottom: 10 } })) diff --git a/src/components/CreationCohort/DiagramView/components/LogicalOperator/components/CriteriaRightPanel/IPPForm/IPPForm.tsx b/src/components/CreationCohort/DiagramView/components/LogicalOperator/components/CriteriaRightPanel/IPPForm/IPPForm.tsx index a79a4b008..193fee363 100644 --- a/src/components/CreationCohort/DiagramView/components/LogicalOperator/components/CriteriaRightPanel/IPPForm/IPPForm.tsx +++ b/src/components/CreationCohort/DiagramView/components/LogicalOperator/components/CriteriaRightPanel/IPPForm/IPPForm.tsx @@ -110,7 +110,7 @@ const IPPForm: React.FC = (props) => { - {ippList.length} IPP détectés. + {ippList.length} IPP détecté{ippList.length > 1 ? 's' : ''}. diff --git a/src/components/CreationCohort/DiagramView/components/LogicalOperator/components/CriteriaRightPanel/ImagingForm/index.tsx b/src/components/CreationCohort/DiagramView/components/LogicalOperator/components/CriteriaRightPanel/ImagingForm/index.tsx index 2baac5b4d..067b81992 100644 --- a/src/components/CreationCohort/DiagramView/components/LogicalOperator/components/CriteriaRightPanel/ImagingForm/index.tsx +++ b/src/components/CreationCohort/DiagramView/components/LogicalOperator/components/CriteriaRightPanel/ImagingForm/index.tsx @@ -171,12 +171,11 @@ const ImagingForm: React.FC = (props) => { disabled={error === Error.INCOHERENT_AGE_ERROR || error === Error.SEARCHINPUT_ERROR || error === Error.UID_ERROR} isInclusive={isInclusive} onChangeIsInclusive={setIsInclusive} - infoAlert="Tous les éléments des champs multiples sont liés par une contrainte OU" - warningAlert="Seuls les examens présents dans le PACS Philips et rattachés à un Dossier Administratif (NDA) sont - actuellement disponibles. Le flux alimentant les métadonnées associées aux séries et aux examens est suspendu - depuis le 01/02/2023 suite à la migration du PACS AP-HP. Aucun examen produit après cette date n'est - disponible via cohort360. Pour tout besoin d'examen post 01/02/2023, merci de contacter le support Cohort360 : - dsn-id-recherche-support-cohort360@aphp.fr.." + infoAlert={['Tous les éléments des champs multiples sont liés par une contrainte OU']} + warningAlert={[ + 'Seuls les examens présents dans le PACS Philips et rattachés à un Dossier Administratif (NDA) sont actuellement disponibles.', + "Le flux alimentant les métadonnées associées aux séries et aux examens est suspendu depuis le 01/02/2023 suite à la migration du PACS AP-HP. Aucun examen produit après cette date n'est disponible via cohort360. Pour tout besoin d'examen post 01/02/2023, merci de contacter le support Cohort360 : dsn-id-recherche-support-cohort360@aphp.fr." + ]} > diff --git a/src/components/CreationCohort/DiagramView/components/LogicalOperator/components/CriteriaRightPanel/MedicationForm/components/Form/MedicationForm.tsx b/src/components/CreationCohort/DiagramView/components/LogicalOperator/components/CriteriaRightPanel/MedicationForm/components/Form/MedicationForm.tsx index 691a58e84..9f5398421 100644 --- a/src/components/CreationCohort/DiagramView/components/LogicalOperator/components/CriteriaRightPanel/MedicationForm/components/Form/MedicationForm.tsx +++ b/src/components/CreationCohort/DiagramView/components/LogicalOperator/components/CriteriaRightPanel/MedicationForm/components/Form/MedicationForm.tsx @@ -13,9 +13,11 @@ import { RadioGroup, Switch, TextField, + Tooltip, Typography } from '@mui/material' +import InfoIcon from '@mui/icons-material/Info' import KeyboardBackspaceIcon from '@mui/icons-material/KeyboardBackspace' import AdvancedInputs from '../../../AdvancedInputs/AdvancedInputs' @@ -24,11 +26,12 @@ import useStyles from './styles' import { useAppDispatch, useAppSelector } from 'state' import { fetchMedication } from 'state/medication' import { CriteriaItemDataCache, CriteriaName, HierarchyTree } from 'types' -import OccurrencesNumberInputs from '../../../AdvancedInputs/OccurrencesInputs/OccurrenceNumberInputs' import AsyncAutocomplete from 'components/ui/Inputs/AsyncAutocomplete' import services from 'services/aphp' -import { MedicationDataType } from 'types/requestCriterias' +import { Comparators, MedicationDataType, RessourceType } from 'types/requestCriterias' import { displaySystem } from 'utils/displayValueSetSystem' +import { BlockWrapper } from 'components/ui/Layout' +import OccurenceInput from 'components/ui/Inputs/Occurences' type MedicationFormProps = { isOpen: boolean @@ -49,6 +52,10 @@ const MedicationForm: React.FC = (props) => { const initialState: HierarchyTree | null = useAppSelector((state) => state.syncHierarchyTable) const currentState = { ...selectedCriteria, ...initialState } const [multiFields, setMultiFields] = useState(localStorage.getItem('multiple_fields')) + const [occurrence, setOccurrence] = useState(currentState.occurrence || 1) + const [occurrenceComparator, setOccurrenceComparator] = useState( + currentState.occurrenceComparator || Comparators.GREATER_OR_EQUAL + ) const getMedicationOptions = async (searchValue: string, signal: AbortSignal) => { const response = await services.cohortCreation.fetchMedicationData(searchValue, false, signal) @@ -58,7 +65,7 @@ const MedicationForm: React.FC = (props) => { } const _onSubmit = () => { - onChangeSelectedCriteria(currentState) + onChangeSelectedCriteria({ ...currentState, occurrence: occurrence, occurrenceComparator: occurrenceComparator }) dispatch(fetchMedication()) } @@ -66,17 +73,18 @@ const MedicationForm: React.FC = (props) => { return <> } - const selectedCriteriaPrescriptionType = currentState.prescriptionType - ? currentState.prescriptionType.map((prescriptionType) => { - const criteriaPrescriptionType = criteriaData.data.prescriptionTypes - ? criteriaData.data.prescriptionTypes.find((p: any) => p.id === prescriptionType.id) - : null - return { - id: prescriptionType.id, - label: prescriptionType.label ? prescriptionType.label : criteriaPrescriptionType?.label ?? '?' - } - }) - : [] + const selectedCriteriaPrescriptionType = + currentState.type === RessourceType.MEDICATION_REQUEST && currentState.prescriptionType + ? currentState.prescriptionType.map((prescriptionType) => { + const criteriaPrescriptionType = criteriaData.data.prescriptionTypes + ? criteriaData.data.prescriptionTypes.find((p: any) => p.id === prescriptionType.id) + : null + return { + id: prescriptionType.id, + label: prescriptionType.label ? prescriptionType.label : criteriaPrescriptionType?.label ?? '?' + } + }) + : [] const selectedCriteriaAdministration = currentState.administration ? currentState.administration.map((administration) => { @@ -158,11 +166,33 @@ const MedicationForm: React.FC = (props) => { color="secondary" /> - + + + + Nombre d'occurrences + + Si vous choisissez un chapitre, le nombre d'occurrences ne s'applique pas sur un unique élément de + ce chapitre, mais sur l'ensemble des éléments de ce chapitre.
Exemple: Nombre d'occurrences + ≥ 3 sur un chapitre signifie que l'on inclus les patients qui ont eu au moins 3 éléments de ce + chapitre, distincts ou non` + + } + > + +
+
+
+ { + setOccurrence(newOccurence) + setOccurrenceComparator(newComparator) + }} + /> +
= (props) => { onChangeValue('code', value) }} /> - {currentState.type === 'MedicationRequest' && ( + {currentState.type === RessourceType.MEDICATION_REQUEST && ( ({ '& > button': { margin: '12px 8px' } + }, + durationLegend: { + color: '#153D8A', + fontWeight: 600, + fontSize: 12, + paddingBottom: 10 } })) diff --git a/src/components/CreationCohort/DiagramView/components/LogicalOperator/components/CriteriaRightPanel/MedicationForm/index.tsx b/src/components/CreationCohort/DiagramView/components/LogicalOperator/components/CriteriaRightPanel/MedicationForm/index.tsx index 30dd438d4..fdd445b0d 100644 --- a/src/components/CreationCohort/DiagramView/components/LogicalOperator/components/CriteriaRightPanel/MedicationForm/index.tsx +++ b/src/components/CreationCohort/DiagramView/components/LogicalOperator/components/CriteriaRightPanel/MedicationForm/index.tsx @@ -18,7 +18,6 @@ export const defaultMedication: Omit = { type: RessourceType.MEDICATION_REQUEST, title: 'Critère de médicament', code: [], - prescriptionType: [], administration: [], occurrence: 1, occurrenceComparator: Comparators.GREATER_OR_EQUAL, @@ -29,6 +28,13 @@ export const defaultMedication: Omit = { isInclusive: true } +const removeNonCommonFields = (medication: MedicationDataType) => { + if (medication.type === RessourceType.MEDICATION_ADMINISTRATION) { + return { ...medication, prescriptionType: null } + } + return medication +} + const Index = (props: CriteriaDrawerComponentProps) => { const { criteriaData, selectedCriteria, onChangeSelectedCriteria, goBack } = props const [selectedTab, setSelectedTab] = useState<'form' | 'exploration'>(selectedCriteria ? 'form' : 'exploration') @@ -51,7 +57,7 @@ const Index = (props: CriteriaDrawerComponentProps) => { value, defaultCriteria, hierarchy, - (updatedCriteria) => setDefaultCriteria(updatedCriteria as MedicationDataType), + (updatedCriteria) => setDefaultCriteria(removeNonCommonFields(updatedCriteria as MedicationDataType)), selectedTab, defaultMedication.type, dispatch diff --git a/src/components/CreationCohort/DiagramView/components/LogicalOperator/components/LogicalOperatorItem/LogicalOperatorItem.tsx b/src/components/CreationCohort/DiagramView/components/LogicalOperator/components/LogicalOperatorItem/LogicalOperatorItem.tsx index 64d0ee5fa..fc8eb36c9 100644 --- a/src/components/CreationCohort/DiagramView/components/LogicalOperator/components/LogicalOperatorItem/LogicalOperatorItem.tsx +++ b/src/components/CreationCohort/DiagramView/components/LogicalOperator/components/LogicalOperatorItem/LogicalOperatorItem.tsx @@ -175,12 +175,15 @@ const LogicalOperatorItem: React.FC = ({ itemId }) => const deleteInvalidConstraints = () => { const currentLogicalOperatorCriteriaIds: number[] = criteriaGroup.find(({ id }) => id === itemId)?.criteriaIds ?? [] - const correctConstraints = temporalConstraints.filter( - (constraint) => - !(constraint.idList as number[]).every((criteriaId: number) => - currentLogicalOperatorCriteriaIds.includes(criteriaId) - ) - ) + const correctConstraints = temporalConstraints.filter((constraint) => { + const constraintsInAndGroup = !(constraint.idList as number[]).some((criteriaId: number) => + currentLogicalOperatorCriteriaIds.includes(criteriaId) + ) + + const noGlobalConstraints = itemId !== 0 || !constraint.idList.includes('All' as never) + + return constraintsInAndGroup && noGlobalConstraints + }) dispatch(updateTemporalConstraints(correctConstraints)) } @@ -230,13 +233,10 @@ const LogicalOperatorItem: React.FC = ({ itemId }) => className={classes.inputSelect} onChange={(event) => { if (event.target.value !== 'andGroup') { - if (isMainOperator) { - setOpenConfirmationDialog(true) - } else { - deleteInvalidConstraints() - } + setOpenConfirmationDialog(true) + } else { + _handleChangeLogicalOperatorProps('groupType', event.target.value) } - _handleChangeLogicalOperatorProps('groupType', event.target.value) }} style={{ color: 'currentColor' }} variant="standard" @@ -289,11 +289,11 @@ const LogicalOperatorItem: React.FC = ({ itemId }) => onCancel={() => setOpenConfirmationDialog(false)} onClose={() => setOpenConfirmationDialog(false)} onConfirm={() => { - dispatch(updateTemporalConstraints([])) + deleteInvalidConstraints() _handleChangeLogicalOperatorProps('groupType', 'orGroup') }} message={ - "L'ajout de contraintes temporelles n'étant possible que sur un groupe de critères ET, passer sur un groupe de critères OU vous fera perdre toutes vos précédentes contraintes temporelles." + "L'ajout de contraintes temporelles n'étant possible que sur un groupe de critères ET, passer sur un groupe de critères OU vous fera perdre toutes les contraintes temporelles de ce groupe." } /> diff --git a/src/components/CreationCohort/DiagramView/components/TemporalConstraintCard/components/TemporalConstraintModal/TemporalConstraintModal.tsx b/src/components/CreationCohort/DiagramView/components/TemporalConstraintCard/components/TemporalConstraintModal/TemporalConstraintModal.tsx index 7ac74b70d..ab2c89d53 100644 --- a/src/components/CreationCohort/DiagramView/components/TemporalConstraintCard/components/TemporalConstraintModal/TemporalConstraintModal.tsx +++ b/src/components/CreationCohort/DiagramView/components/TemporalConstraintCard/components/TemporalConstraintModal/TemporalConstraintModal.tsx @@ -190,6 +190,7 @@ const TemporalConstraint: React.FC<{ value={TemporalConstraintsKind.SAME_ENCOUNTER} control={} label="Tous les critères ont lieu au cours du même séjour" + disabled={criteriaGroup[0].type === 'orGroup'} /> )} - - - Séquence d'évènements entre deux critères - - - + {criteriaGroup[0].type !== 'orGroup' && ( + + + Séquence d'évènements entre deux critères + + + + + + - - - + )} diff --git a/src/components/Patient/PatientBiology/PatientBiology.tsx b/src/components/Patient/PatientBiology/PatientBiology.tsx index cbd469436..7ba5769ba 100644 --- a/src/components/Patient/PatientBiology/PatientBiology.tsx +++ b/src/components/Patient/PatientBiology/PatientBiology.tsx @@ -324,6 +324,13 @@ const PatientBiology = ({ groupId }: PatientBiologyProps) => { value={selectedSavedFilter?.filterParams.searchInput} /> + + + = ({ groupId }) => { maxLimit={50} /> - {!searchResults.deidentified && ( - - - + + {!searchResults.deidentified && ( = ({ const age = getAge(patient as CohortPatient) const firstName = deidentifiedBoolean ? 'Prénom' : patient.name?.[0].given?.[0] - const lastName = deidentifiedBoolean ? 'Nom' : patient.name?.map((e) => e.family).join(' ') + const lastName = deidentifiedBoolean + ? 'Nom' + : patient.name + ?.map((e) => { + if (e.use === 'official') { + return e.family ?? 'Non renseigné' + } + if (e.use === 'maiden') { + return `(${patient.gender === 'female' ? 'née' : 'né'} : ${e.family})` ?? 'Non renseigné' + } + }) + .join(' ') ?? 'Non renseigné' const ipp = deidentifiedBoolean ? `IPP chiffré: ${patient.id ?? '-'}` diff --git a/src/components/Patient/PatientHeader/PatientTitle/PatientTitle.tsx b/src/components/Patient/PatientHeader/PatientTitle/PatientTitle.tsx index 51878dc87..df51c5d06 100644 --- a/src/components/Patient/PatientHeader/PatientTitle/PatientTitle.tsx +++ b/src/components/Patient/PatientHeader/PatientTitle/PatientTitle.tsx @@ -12,7 +12,7 @@ import useStyles from './styles' type PatientTitleProps = { firstName: string | undefined - lastName: string | undefined + lastName: string | (string | undefined)[] | undefined } const PatientTitle: React.FC = ({ firstName, lastName }) => { const { classes } = useStyles() diff --git a/src/components/Patient/PatientMedication/PatientMedication.tsx b/src/components/Patient/PatientMedication/PatientMedication.tsx index d2a82878b..8abd620eb 100644 --- a/src/components/Patient/PatientMedication/PatientMedication.tsx +++ b/src/components/Patient/PatientMedication/PatientMedication.tsx @@ -60,6 +60,7 @@ const PatientMedication = ({ groupId }: PatientMedicationProps) => { const [toggleSavedFiltersModal, setToggleSavedFiltersModal] = useState(false) const [toggleFilterInfoModal, setToggleFilterInfoModal] = useState(false) const [isReadonlyFilterInfoModal, setIsReadonlyFilterInfoModal] = useState(true) + const [triggerClean, setTriggerClean] = useState(false) const dispatch = useAppDispatch() const patient = useAppSelector((state) => state.patient) @@ -189,6 +190,7 @@ const PatientMedication = ({ groupId }: PatientMedicationProps) => { useEffect(() => { setPage(1) removeSearchCriterias() + setTriggerClean(!triggerClean) setLoadingStatus(LoadingStatus.IDDLE) }, [selectedTab]) @@ -296,6 +298,7 @@ const PatientMedication = ({ groupId }: PatientMedicationProps) => { color="secondary" onClose={() => setToggleFilterByModal(false)} onSubmit={(newFilters) => addFilters({ ...filters, ...newFilters })} + onClean={triggerClean} > {!searchResults.deidentified && } {selectedTab.id === RessourceType.MEDICATION_REQUEST && prescriptionTypes && ( diff --git a/src/components/Patient/PatientPMSI/PatientPMSI.tsx b/src/components/Patient/PatientPMSI/PatientPMSI.tsx index 3777e7dba..cae7aef48 100644 --- a/src/components/Patient/PatientPMSI/PatientPMSI.tsx +++ b/src/components/Patient/PatientPMSI/PatientPMSI.tsx @@ -64,6 +64,7 @@ const PatientPMSI = ({ groupId }: PatientPMSIProps) => { const [toggleSavedFiltersModal, setToggleSavedFiltersModal] = useState(false) const [toggleFilterInfoModal, setToggleFilterInfoModal] = useState(false) const [isReadonlyFilterInfoModal, setIsReadonlyFilterInfoModal] = useState(true) + const [triggerClean, setTriggerClean] = useState(false) const dispatch = useAppDispatch() const [selectedTab, setSelectedTab] = useState({ @@ -100,6 +101,7 @@ const PatientPMSI = ({ groupId }: PatientPMSIProps) => { }, { changeOrderBy, changeSearchInput, addFilters, removeFilter, removeSearchCriterias, addSearchCriterias } ] = useSearchCriterias(initPmsiSearchCriterias) + const filtersAsArray = useMemo( () => selectFiltersAsArray({ code, nda, diagnosticTypes, source, startDate, endDate, executiveUnits }), [code, nda, diagnosticTypes, source, startDate, endDate, executiveUnits] @@ -182,6 +184,7 @@ const PatientPMSI = ({ groupId }: PatientPMSIProps) => { useEffect(() => { setPage(1) removeSearchCriterias() + setTriggerClean(!triggerClean) setLoadingStatus(LoadingStatus.IDDLE) }, [selectedTab]) @@ -304,6 +307,7 @@ const PatientPMSI = ({ groupId }: PatientPMSIProps) => { color="secondary" onClose={() => setToggleFilterByModal(false)} onSubmit={(newFilters) => addFilters({ ...filters, ...newFilters })} + onClean={triggerClean} > {!searchResults.deidentified && } diff --git a/src/components/Patient/PatientSidebar/PatientSidebar.tsx b/src/components/Patient/PatientSidebar/PatientSidebar.tsx index 4b0f62925..6423a17de 100644 --- a/src/components/Patient/PatientSidebar/PatientSidebar.tsx +++ b/src/components/Patient/PatientSidebar/PatientSidebar.tsx @@ -1,12 +1,10 @@ import React, { useEffect, useMemo, useRef, useState } from 'react' import { useLocation } from 'react-router-dom' -import moment from 'moment/moment' import { Divider, Drawer, Grid, IconButton, Typography } from '@mui/material' import { ChevronRight, Sort } from '@mui/icons-material' import { ReactComponent as FilterList } from 'assets/icones/filter.svg' -import { substructAgeString } from 'utils/age' import { selectFiltersAsArray } from 'utils/filters' import { cancelPendingRequest } from 'utils/abortController' import services from 'services/aphp' @@ -85,10 +83,6 @@ const PatientSidebar = ({ total, patients, openDrawer, onClose, deidentifiedBool const fetchPatients = async () => { try { const includeFacets = false - const birthdates: [string, string] = [ - moment(substructAgeString(filters.birthdatesRanges[0] || '')).format('MM/DD/YYYY'), - moment(substructAgeString(filters.birthdatesRanges[1] || '')).format('MM/DD/YYYY') - ] setLoadingStatus(LoadingStatus.FETCHING) const result = await services.cohorts.fetchPatientList( @@ -98,7 +92,7 @@ const PatientSidebar = ({ total, patients, openDrawer, onClose, deidentifiedBool orderBy, searchInput, searchBy, - filters: { genders, vitalStatuses, birthdatesRanges: birthdates } + filters: { genders, vitalStatuses, birthdatesRanges } } }, deidentifiedBoolean ?? true, @@ -185,7 +179,11 @@ const PatientSidebar = ({ total, patients, openDrawer, onClose, deidentifiedBool > - +