diff --git a/src/components/CreationCohort/DiagramView/components/PopulationCard/PopulationCard.tsx b/src/components/CreationCohort/DiagramView/components/PopulationCard/PopulationCard.tsx index 9b5910be7..adc73ae58 100644 --- a/src/components/CreationCohort/DiagramView/components/PopulationCard/PopulationCard.tsx +++ b/src/components/CreationCohort/DiagramView/components/PopulationCard/PopulationCard.tsx @@ -66,7 +66,7 @@ const PopulationCard: React.FC = (props) => { const selectionAndPopulationWithRightError = [...selectedItems, ...populationWithRightError] const _onChangePopulation = async (selectedPopulations: ScopeTreeRow[]) => { - dispatch(buildCohortCreation({ selectedPopulation: selectedPopulations })) + dispatch(buildCohortCreation({ selectedPopulation: selectedPopulations })) } const setUpdatedItems = (updatedSelection: ScopeTreeRow[]) => { diff --git a/src/components/Dashboard/ExportModal/ExportModal.tsx b/src/components/Dashboard/ExportModal/ExportModal.tsx index ce9c0c31d..44960d9e0 100644 --- a/src/components/Dashboard/ExportModal/ExportModal.tsx +++ b/src/components/Dashboard/ExportModal/ExportModal.tsx @@ -1,4 +1,5 @@ import React, { useState, useEffect, useRef } from 'react' +import { isAxiosError } from 'axios' import { Accordion, @@ -139,8 +140,8 @@ const ExportModal: React.FC = ({ cohortId, open, handleClose } tables: settings?.tables }) - if (response && response.error) { - setExportResponse({ status: 'error', detail: response.error.detail }) + if (isAxiosError(response)) { + setExportResponse({ status: 'error', detail: response.message }) } else { setExportResponse({ status: 'finish', detail: '' }) } diff --git a/src/components/Filters/MedicationFilters/index.tsx b/src/components/Filters/MedicationFilters/index.tsx index 04492ada4..573162ca0 100644 --- a/src/components/Filters/MedicationFilters/index.tsx +++ b/src/components/Filters/MedicationFilters/index.tsx @@ -55,8 +55,8 @@ const MedicationFilters: React.FC = ({ const { classes } = useStyles() const [_nda, setNda] = useState(filters.nda) - const [_startDate, setStartDate] = useState(filters.startDate) - const [_endDate, setEndDate] = useState(filters.endDate) + const [_startDate, setStartDate] = useState(filters.startDate) + const [_endDate, setEndDate] = useState(filters.endDate) const [_selectedPrescriptionTypes, setSelectedPrescriptionTypes] = useState(filters.selectedPrescriptionTypes) const [_selectedAdministrationRoutes, setSelectedAdministrationRoutes] = useState( filters.selectedAdministrationRoutes diff --git a/src/components/Inputs/InputAutocompleteAsync/InputAutocompleteAsync.tsx b/src/components/Inputs/InputAutocompleteAsync/InputAutocompleteAsync.tsx index 3d3da712c..01d9a670d 100644 --- a/src/components/Inputs/InputAutocompleteAsync/InputAutocompleteAsync.tsx +++ b/src/components/Inputs/InputAutocompleteAsync/InputAutocompleteAsync.tsx @@ -4,13 +4,12 @@ import { Autocomplete, CircularProgress, TextField } from '@mui/material' import { displaySystem } from 'utils/displayValueSetSystem' -import { ValueSetSystem } from 'types' import { cancelPendingRequest } from 'utils/abortController' interface ElementType { id: string label: string - system: ValueSetSystem + system?: string } type InputAutocompleteAsyncProps = { @@ -23,7 +22,7 @@ type InputAutocompleteAsyncProps = { onChange?: (e: any, value: any) => void renderInput?: any autocompleteOptions?: ElementType[] - getAutocompleteOptions?: (searchValue: string, signal: AbortSignal) => Promise + getAutocompleteOptions?: (searchValue: string, signal: AbortSignal) => Promise noOptionsText?: string helperText?: string } @@ -93,7 +92,7 @@ const InputAutocompleteAsync: FC = (props) => { onChange={onChange} options={options ?? []} isOptionEqualToValue={(option, value) => option.id === value.id} - getOptionLabel={(option) => `${displaySystem(option.system)}${option.label} `} + getOptionLabel={(option) => `${displaySystem(option?.system)}${option.label} `} renderInput={(params) => ( Promise + }) => Promise } ``` diff --git a/src/services/aphp/callApi.ts b/src/services/aphp/callApi.ts index dbb7e189b..3ef198432 100644 --- a/src/services/aphp/callApi.ts +++ b/src/services/aphp/callApi.ts @@ -11,7 +11,8 @@ import { IScope, Back_API_Response, Cohort, - DataRights + DataRights, + CohortRights } from 'types' import { FHIR_Bundle_Response } from 'types' @@ -27,6 +28,7 @@ import { ImagingStudy, MedicationAdministration, MedicationRequest, + Observation, OperationOutcome, Parameters, ParametersParameter, @@ -34,7 +36,6 @@ import { Procedure, ValueSet } from 'fhir/r4' -import { Observation } from 'fhir/r4' import { getApiResponseResourceOrThrow, getApiResponseResourcesOrThrow } from 'utils/apiHelpers' import { idSort, labelSort } from 'utils/alphabeticalSort' import { capitalizeFirstLetter } from 'utils/capitalize' @@ -46,7 +47,7 @@ const paramValuesReducerWithPrefix = (prefix: string): ((accumulator: string, currentValue: string) => string) => (accumulator: string, currentValue: string) => accumulator ? `${accumulator},${prefix + currentValue}` : currentValue ? prefix + currentValue : accumulator -const paramValuesReducer = (accumulator: any, currentValue: any): any => +const paramValuesReducer = (accumulator: string, currentValue: string): string => accumulator ? `${accumulator},${currentValue}` : currentValue ? currentValue : accumulator const paramsReducer = (accumulator: string, currentValue: string): string => accumulator ? `${accumulator}&${currentValue}` : currentValue ? currentValue : accumulator @@ -101,27 +102,27 @@ export const fetchPatient = async (args: fetchPatientProps): FHIR_Bundle_Promise // By default, all the calls to `/Patient` will have 'active=true' in parameter let options: string[] = ['active=true'] - if (_id) options = [...options, `_id=${_id}`] // eslint-disable-line - if (size !== undefined) options = [...options, `_count=${size}`] // eslint-disable-line - if (offset) options = [...options, `_offset=${offset}`] // eslint-disable-line - if (_sort) options = [...options, `_sort=${_sortDirection}${_sort}`] // eslint-disable-line - if (gender) options = [...options, `gender=${gender}`] // eslint-disable-line + if (_id) options = [...options, `_id=${_id}`] + if (size !== undefined) options = [...options, `_count=${size}`] + if (offset) options = [...options, `_offset=${offset}`] + if (_sort) options = [...options, `_sort=${_sortDirection}${_sort}`] + if (gender) options = [...options, `gender=${gender}`] if (_text && _text.length > 0) { if (Array.isArray(_text)) { const searchInput = _text.map((text) => `${searchBy}=${encodeURIComponent(`"${text}"`)}`).join('&') options = [...options, searchInput] } else { - options = [...options, `${searchBy}=${_text}`] // eslint-disable-line + options = [...options, `${searchBy}=${_text}`] } } - if (deceased !== undefined) options = [...options, `deceased=${deceased}`] // eslint-disable-line - if (minBirthdate) options = [...options, `${deidentified ? 'age-month' : 'age-day'}=ge${minBirthdate}`] // eslint-disable-line - if (maxBirthdate) options = [...options, `${deidentified ? 'age-month' : 'age-day'}=le${maxBirthdate}`] // eslint-disable-line + if (deceased !== undefined) options = [...options, `deceased=${deceased}`] + if (minBirthdate) options = [...options, `${deidentified ? 'age-month' : 'age-day'}=ge${minBirthdate}`] + if (maxBirthdate) options = [...options, `${deidentified ? 'age-month' : 'age-day'}=le${maxBirthdate}`] - if (_list && _list.length > 0) options = [...options, `_list=${_list.reduce(paramValuesReducer)}`] // eslint-disable-line + if (_list && _list.length > 0) options = [...options, `_list=${_list.reduce(paramValuesReducer)}`] if (pivotFacet && pivotFacet.length > 0) - options = [...options, `pivot-facet=${pivotFacet.reduce(paramValuesReducer)}`] // eslint-disable-line - if (_elements && _elements.length > 0) options = [...options, `_elements=${_elements.reduce(paramValuesReducer)}`] // eslint-disable-line + options = [...options, `pivot-facet=${pivotFacet.reduce(paramValuesReducer, '')}`] + if (_elements && _elements.length > 0) options = [...options, `_elements=${_elements.reduce(paramValuesReducer, '')}`] const response = await apiFhir.get>(`/Patient?${options.reduce(paramsReducer)}`, { signal: signal @@ -163,18 +164,18 @@ export const fetchEncounter = async (args: fetchEncounterProps): FHIR_Bundle_Pro // By default, all the calls to `/Encounter` will have 'subject.active=true' in parameter let options: string[] = ['subject.active=true'] - if (_id) options = [...options, `_id=${_id}`] // eslint-disable-line - if (size !== undefined) options = [...options, `_count=${size}`] // eslint-disable-line - if (offset) options = [...options, `offset=${offset}`] // eslint-disable-line - if (_sort) options = [...options, `_sort=${_sortDirection}${_sort},id`] // eslint-disable-line - if (patient) options = [...options, `subject=${patient}`] // eslint-disable-line - if (type) options = [...options, `type=${type}`] // eslint-disable-line - if (typeNot) options = [...options, `type:not=${typeNot}`] // eslint-disable-line - - if (_list && _list.length > 0) options = [...options, `_list=${_list.reduce(paramValuesReducer)}`] // eslint-disable-line - if (status && status.length > 0) options = [...options, `status=${status.reduce(paramValuesReducer)}`] // eslint-disable-line - if (_elements && _elements.length > 0) options = [...options, `_elements=${_elements.reduce(paramValuesReducer)}`] // eslint-disable-line - if (facet && facet.length > 0) options = [...options, `facet=${facet.reduce(paramValuesReducer)}`] // eslint-disable-line + if (_id) options = [...options, `_id=${_id}`] + if (size !== undefined) options = [...options, `_count=${size}`] + if (offset) options = [...options, `offset=${offset}`] + if (_sort) options = [...options, `_sort=${_sortDirection}${_sort},id`] + if (patient) options = [...options, `subject=${patient}`] + if (type) options = [...options, `type=${type}`] + if (typeNot) options = [...options, `type:not=${typeNot}`] + + if (_list && _list.length > 0) options = [...options, `_list=${_list.reduce(paramValuesReducer)}`] + if (status && status.length > 0) options = [...options, `status=${status.reduce(paramValuesReducer)}`] + if (_elements && _elements.length > 0) options = [...options, `_elements=${_elements.reduce(paramValuesReducer, '')}`] + if (facet && facet.length > 0) options = [...options, `facet=${facet.reduce(paramValuesReducer, '')}`] const response = await apiFhir.get>(`/Encounter?${options.reduce(paramsReducer)}`, { signal: signal @@ -267,13 +268,13 @@ export const fetchDocumentReference = async ( `contenttype=${encodeURIComponent('http://terminology.hl7.org/CodeSystem/v3-mediatypes|text/plain')}`, 'subject.active=true' ] - if (_id) options = [...options, `_id=${_id}`] // eslint-disable-line - if (size !== undefined) options = [...options, `_count=${size}`] // eslint-disable-line + if (_id) options = [...options, `_id=${_id}`] + if (size !== undefined) options = [...options, `_count=${size}`] if (offset) options = [...options, `offset=${offset}`] - if (_sort) options = [...options, `_sort=${_sortDirection}${_sort},id`] // eslint-disable-line - if (type) options = [...options, `type=${type}`] // eslint-disable-line + if (_sort) options = [...options, `_sort=${_sortDirection}${_sort},id`] + if (type) options = [...options, `type=${type}`] if (_text) - options = [...options, `${searchBy === SearchByTypes.TEXT ? `_text` : 'description'}=${encodeURIComponent(_text)}`] // eslint-disable-line + options = [...options, `${searchBy === SearchByTypes.TEXT ? `_text` : 'description'}=${encodeURIComponent(_text)}`] if (highlight_search_results) options = [ ...options, @@ -282,31 +283,31 @@ export const fetchDocumentReference = async ( ? `_tag=${encodeURIComponent('https://terminology.eds.aphp.fr/misc|HIGHLIGHT_RESULTS')}` : '' }` - ] // eslint-disable-line + ] if (status) options = [ ...options, `docstatus=${encodeURIComponent('http://hl7.org/fhir/CodeSystem/composition-status|') + status}` - ] // eslint-disable-line - if (patient) options = [...options, `subject=${patient}`] // eslint-disable-line - if (patientIdentifier) options = [...options, `subject.identifier=${patientIdentifier}`] // eslint-disable-line - if (encounter) options = [...options, `encounter=${encounter}`] // eslint-disable-line - if (encounterIdentifier) options = [...options, `encounter.identifier=${encounterIdentifier}`] // eslint-disable-line + ] + if (patient) options = [...options, `subject=${patient}`] + if (patientIdentifier) options = [...options, `subject.identifier=${patientIdentifier}`] + if (encounter) options = [...options, `encounter=${encounter}`] + if (encounterIdentifier) options = [...options, `encounter.identifier=${encounterIdentifier}`] if (onlyPdfAvailable) options = [ ...options, `contenttype=${encodeURIComponent('http://terminology.hl7.org/CodeSystem/v3-mediatypes|application/pdf')}` - ] // eslint-disable-line - if (minDate) options = [...options, `date=ge${minDate}`] // eslint-disable-line - if (maxDate) options = [...options, `date=le${maxDate}`] // eslint-disable-line + ] + if (minDate) options = [...options, `date=ge${minDate}`] + if (maxDate) options = [...options, `date=le${maxDate}`] if (executiveUnits && executiveUnits.length > 0) - options = [...options, `encounter.encounter-care-site=${executiveUnits}`] // eslint-disable-line + options = [...options, `encounter.encounter-care-site=${executiveUnits}`] - if (_list && _list.length > 0) options = [...options, `_list=${_list.reduce(paramValuesReducer)}`] // eslint-disable-line - if (facet && facet.length > 0) options = [...options, `facet=${facet.reduce(paramValuesReducer)}`] // eslint-disable-line + if (_list && _list.length > 0) options = [...options, `_list=${_list.reduce(paramValuesReducer)}`] + if (facet && facet.length > 0) options = [...options, `facet=${facet.reduce(paramValuesReducer, '')}`] if (uniqueFacet && uniqueFacet.length > 0) - options = [...options, `unique-facet=${uniqueFacet.reduce(paramValuesReducer)}`] // eslint-disable-line - if (_elements && _elements.length > 0) options = [...options, `_elements=${_elements.reduce(paramValuesReducer)}`] // eslint-disable-line + options = [...options, `unique-facet=${uniqueFacet.reduce(paramValuesReducer, '')}`] + if (_elements && _elements.length > 0) options = [...options, `_elements=${_elements.reduce(paramValuesReducer, '')}`] const response = await apiFhir.get>( `/DocumentReference?${options.reduce(paramsReducer)}`, @@ -407,7 +408,7 @@ export const fetchBinary = async (args: fetchBinaryProps): FHIR_Bundle_Promise_R const { _id } = args let options: string[] = [] - if (_id) options = [...options, `_id=${_id}`] // eslint-disable-line + if (_id) options = [...options, `_id=${_id}`] const documentResp = await apiFhir.get>(`/Binary?${options.reduce(paramsReducer)}`) @@ -447,21 +448,21 @@ export const fetchProcedure = async (args: fetchProcedureProps): FHIR_Bundle_Pro // By default, all the calls to `/Procedure` will have 'patient.active=true' in parameter let options: string[] = ['subject.active=true'] - if (size !== undefined) options = [...options, `_count=${size}`] // eslint-disable-line - if (offset) options = [...options, `offset=${offset}`] // eslint-disable-line - if (_sort) options = [...options, `_sort=${_sortDirection}${_sort},id`] // eslint-disable-line - if (subject) options = [...options, `subject=${subject}`] // eslint-disable-line - if (code) options = [...options, `code=${encodeURIComponent(`${PROCEDURE_HIERARCHY}|`) + code}`] // eslint-disable-line + if (size !== undefined) options = [...options, `_count=${size}`] + if (offset) options = [...options, `offset=${offset}`] + if (_sort) options = [...options, `_sort=${_sortDirection}${_sort},id`] + if (subject) options = [...options, `subject=${subject}`] + if (code) options = [...options, `code=${encodeURIComponent(`${PROCEDURE_HIERARCHY}|`) + code}`] if (source) options = [...options, `source=${source}`] - if (_text) options = [...options, `_text=${encodeURIComponent(_text)}`] // eslint-disable-line + if (_text) options = [...options, `_text=${encodeURIComponent(_text)}`] if (status) - options = [...options, `status=${encodeURIComponent('http://hl7.org/fhir/CodeSystem/event-status|') + status}`] // eslint-disable-line - if (encounterIdentifier) options = [...options, `encounter.identifier=${encounterIdentifier}`] // eslint-disable-line - if (minDate) options = [...options, `date=ge${minDate}`] // eslint-disable-line - if (maxDate) options = [...options, `date=le${maxDate}`] // eslint-disable-line - if (_list && _list.length > 0) options = [...options, `_list=${_list.reduce(paramValuesReducer)}`] // eslint-disable-line + options = [...options, `status=${encodeURIComponent('http://hl7.org/fhir/CodeSystem/event-status|') + status}`] + if (encounterIdentifier) options = [...options, `encounter.identifier=${encounterIdentifier}`] + if (minDate) options = [...options, `date=ge${minDate}`] + if (maxDate) options = [...options, `date=le${maxDate}`] + if (_list && _list.length > 0) options = [...options, `_list=${_list.reduce(paramValuesReducer)}`] if (executiveUnits && executiveUnits.length > 0) - options = [...options, `encounter.encounter-care-site=${executiveUnits}`] // eslint-disable-line + options = [...options, `encounter.encounter-care-site=${executiveUnits}`] const response = await apiFhir.get>(`/Procedure?${options.reduce(paramsReducer)}`, { signal: args.signal @@ -512,28 +513,28 @@ export const fetchClaim = async (args: fetchClaimProps): FHIR_Bundle_Promise_Res // By default, all the calls to `/Claim` will have 'patient.active=true' in parameter let options: string[] = ['patient.active=true'] - if (size !== undefined) options = [...options, `_count=${size}`] // eslint-disable-line - if (offset) options = [...options, `offset=${offset}`] // eslint-disable-line - if (_sort) options = [...options, `_sort=${_sortDirection}${_sort},id`] // eslint-disable-line - if (patient) options = [...options, `patient=${patient}`] // eslint-disable-line + if (size !== undefined) options = [...options, `_count=${size}`] + if (offset) options = [...options, `offset=${offset}`] + if (_sort) options = [...options, `_sort=${_sortDirection}${_sort},id`] + if (patient) options = [...options, `patient=${patient}`] if (diagnosis) options = [ ...options, `diagnosis=${encodeURIComponent('https://terminology.eds.aphp.fr/aphp-orbis-ghm|') + diagnosis}` - ] // eslint-disable-line - if (_text) options = [...options, `_text=${encodeURIComponent(_text)}`] // eslint-disable-line + ] + if (_text) options = [...options, `_text=${encodeURIComponent(_text)}`] if (status) options = [ ...options, `status=${encodeURIComponent('https://terminology.eds.aphp.fr/aphp-orbis-ghm-cost-status|') + status}` - ] // eslint-disable-line - if (encounterIdentifier) options = [...options, `encounter.identifier=${encounterIdentifier}`] // eslint-disable-line - if (minCreated) options = [...options, `created=ge${minCreated}`] // eslint-disable-line - if (maxCreated) options = [...options, `created=le${maxCreated}`] // eslint-disable-line + ] + if (encounterIdentifier) options = [...options, `encounter.identifier=${encounterIdentifier}`] + if (minCreated) options = [...options, `created=ge${minCreated}`] + if (maxCreated) options = [...options, `created=le${maxCreated}`] if (executiveUnits && executiveUnits.length > 0) - options = [...options, `encounter.encounter-care-site=${executiveUnits}`] // eslint-disable-line + options = [...options, `encounter.encounter-care-site=${executiveUnits}`] - if (_list && _list.length > 0) options = [...options, `_list=${_list.reduce(paramValuesReducer)}`] // eslint-disable-line + if (_list && _list.length > 0) options = [...options, `_list=${_list.reduce(paramValuesReducer)}`] const response = await apiFhir.get>(`/Claim?${options.reduce(paramsReducer)}`, { signal: args.signal @@ -576,20 +577,20 @@ export const fetchCondition = async (args: fetchConditionProps): FHIR_Bundle_Pro // By default, all the calls to `/Condition` will have 'patient.active=true' in parameter let options: string[] = ['subject.active=true'] - if (size !== undefined) options = [...options, `_count=${size}`] // eslint-disable-line - if (offset !== undefined) options = [...options, `offset=${offset}`] // eslint-disable-line - if (_sort) options = [...options, `_sort=${_sortDirection}${_sort},id`] // eslint-disable-line - if (subject) options = [...options, `subject=${subject}`] // eslint-disable-line + if (size !== undefined) options = [...options, `_count=${size}`] + if (offset !== undefined) options = [...options, `offset=${offset}`] + if (_sort) options = [...options, `_sort=${_sortDirection}${_sort},id`] + if (subject) options = [...options, `subject=${subject}`] if (code) - options = [...options, `code=${encodeURIComponent('https://terminology.eds.aphp.fr/aphp-orbis-cim10|') + code}`] // eslint-disable-line - if (_text) options = [...options, `_text=${encodeURIComponent(_text)}`] // eslint-disable-line - if (encounterIdentifier) options = [...options, `encounter.identifier=${encounterIdentifier}`] // eslint-disable-line - if (minRecordedDate) options = [...options, `recorded-date=ge${minRecordedDate}`] // eslint-disable-line - if (maxRecordedDate) options = [...options, `recorded-date=le${maxRecordedDate}`] // eslint-disable-line + options = [...options, `code=${encodeURIComponent('https://terminology.eds.aphp.fr/aphp-orbis-cim10|') + code}`] + if (_text) options = [...options, `_text=${encodeURIComponent(_text)}`] + if (encounterIdentifier) options = [...options, `encounter.identifier=${encounterIdentifier}`] + if (minRecordedDate) options = [...options, `recorded-date=ge${minRecordedDate}`] + if (maxRecordedDate) options = [...options, `recorded-date=le${maxRecordedDate}`] if (executiveUnits && executiveUnits.length > 0) - options = [...options, `encounter.encounter-care-site=${executiveUnits}`] // eslint-disable-line + options = [...options, `encounter.encounter-care-site=${executiveUnits}`] - if (_list && _list.length > 0) options = [...options, `_list=${_list.reduce(paramValuesReducer)}`] // eslint-disable-line + if (_list && _list.length > 0) options = [...options, `_list=${_list.reduce(paramValuesReducer)}`] if (type && type.length > 0) options = [ ...options, @@ -648,27 +649,27 @@ export const fetchObservation = async (args: fetchObservationProps): FHIR_Bundle // By default, all the calls to `/Observation` will have 'value-quantity-value=ge0,le0' and 'patient.active=true' in the parameters let options: string[] = ['value-quantity=ge0,le0', 'subject.active=true'] - if (id) options = [...options, `_id=${id}`] // eslint-disable-line - if (size !== undefined) options = [...options, `_count=${size}`] // eslint-disable-line - if (offset) options = [...options, `offset=${offset}`] // eslint-disable-line - if (_sort) options = [...options, `_sort=${_sortDirection}${_sort.includes('code') ? _sort : `${_sort},id`}`] // eslint-disable-line - if (_text) options = [...options, `_text=${encodeURIComponent(_text)}`] // eslint-disable-line - if (encounter) options = [...options, `encounter.identifier=${encounter}`] // eslint-disable-line + if (id) options = [...options, `_id=${id}`] + if (size !== undefined) options = [...options, `_count=${size}`] + if (offset) options = [...options, `offset=${offset}`] + if (_sort) options = [...options, `_sort=${_sortDirection}${_sort.includes('code') ? _sort : `${_sort},id`}`] + if (_text) options = [...options, `_text=${encodeURIComponent(_text)}`] + if (encounter) options = [...options, `encounter.identifier=${encounter}`] if (anabio || loinc) options = [ ...options, `code=${anabio ? encodeURIComponent('https://terminology.eds.aphp.fr/aphp-itm-anabio|') + anabio : ''}${ anabio && loinc ? ',' : '' }${loinc ? encodeURIComponent('https://terminology.eds.aphp.fr/aphp-itm-loinc|') + loinc : ''}` - ] // eslint-disable-line - if (subject) options = [...options, `subject=${subject}`] // eslint-disable-line - if (minDate) options = [...options, `date=ge${minDate}`] // eslint-disable-line - if (maxDate) options = [...options, `date=le${maxDate}`] // eslint-disable-line - if (rowStatus) options = [...options, `status=${BiologyStatus.VALIDATED}`] // eslint-disable-line + ] + if (subject) options = [...options, `subject=${subject}`] + if (minDate) options = [...options, `date=ge${minDate}`] + if (maxDate) options = [...options, `date=le${maxDate}`] + if (rowStatus) options = [...options, `status=${BiologyStatus.VALIDATED}`] if (executiveUnits && executiveUnits.length > 0) - options = [...options, `encounter.encounter-care-site=${executiveUnits}`] // eslint-disable-line + options = [...options, `encounter.encounter-care-site=${executiveUnits}`] - if (_list && _list.length > 0) options = [...options, `_list=${_list.reduce(paramValuesReducer)}`] // eslint-disable-line + if (_list && _list.length > 0) options = [...options, `_list=${_list.reduce(paramValuesReducer)}`] const response = await apiFhir.get>( `/Observation?${options.reduce(paramsReducer)}`, @@ -721,20 +722,20 @@ export const fetchMedicationRequest = async ( // By default, all the calls to `/MedicationRequest` will have 'patient.active=true' in parameter let options: string[] = ['subject.active=true'] - if (id) options = [...options, `_id=${id}`] // eslint-disable-line - if (size !== undefined) options = [...options, `_count=${size}`] // eslint-disable-line - if (offset !== undefined) options = [...options, `offset=${offset}`] // eslint-disable-line - if (_sort) options = [...options, `_sort=${_sortDirection}${_sort},id`] // eslint-disable-line - if (subject) options = [...options, `subject=${subject}`] // eslint-disable-line - if (encounter) options = [...options, `encounter.identifier=${encounter}`] // eslint-disable-line - if (_text) options = [...options, `_text=${encodeURIComponent(_text)}`] // eslint-disable-line - if (type) options = [...options, `category=*${encodeURIComponent('|')}${type}`] // eslint-disable-line - if (minDate) options = [...options, `validity-period-start=ge${minDate}`] // eslint-disable-line - if (maxDate) options = [...options, `validity-period-start=le${maxDate}`] // eslint-disable-line + if (id) options = [...options, `_id=${id}`] + if (size !== undefined) options = [...options, `_count=${size}`] + if (offset !== undefined) options = [...options, `offset=${offset}`] + if (_sort) options = [...options, `_sort=${_sortDirection}${_sort},id`] + if (subject) options = [...options, `subject=${subject}`] + if (encounter) options = [...options, `encounter.identifier=${encounter}`] + if (_text) options = [...options, `_text=${encodeURIComponent(_text)}`] + if (type) options = [...options, `category=*${encodeURIComponent('|')}${type}`] + if (minDate) options = [...options, `validity-period-start=ge${minDate}`] + if (maxDate) options = [...options, `validity-period-start=le${maxDate}`] if (executiveUnits && executiveUnits.length > 0) - options = [...options, `encounter.encounter-care-site=${executiveUnits}`] // eslint-disable-line + options = [...options, `encounter.encounter-care-site=${executiveUnits}`] - if (_list && _list.length > 0) options = [...options, `_list=${_list.reduce(paramValuesReducer)}`] // eslint-disable-line + if (_list && _list.length > 0) options = [...options, `_list=${_list.reduce(paramValuesReducer)}`] const response = await apiFhir.get>( `/MedicationRequest?${options.reduce(paramsReducer)}`, @@ -787,25 +788,25 @@ export const fetchMedicationAdministration = async ( // By default, all the calls to `/MedicationAdministration` will have 'patient.active=true' in parameter let options: string[] = ['subject.active=true'] - if (id) options = [...options, `_id=${id}`] // eslint-disable-line - if (size !== undefined) options = [...options, `_count=${size}`] // eslint-disable-line - if (offset) options = [...options, `offset=${offset}`] // eslint-disable-line - if (_sort) options = [...options, `_sort=${_sortDirection}${_sort},id`] // eslint-disable-line - if (subject) options = [...options, `subject=${subject}`] // eslint-disable-line - if (encounter) options = [...options, `context.identifier=${encounter}`] // eslint-disable-line - if (_text) options = [...options, `_text=${encodeURIComponent(_text)}`] // eslint-disable-line + if (id) options = [...options, `_id=${id}`] + if (size !== undefined) options = [...options, `_count=${size}`] + if (offset) options = [...options, `offset=${offset}`] + if (_sort) options = [...options, `_sort=${_sortDirection}${_sort},id`] + if (subject) options = [...options, `subject=${subject}`] + if (encounter) options = [...options, `context.identifier=${encounter}`] + if (_text) options = [...options, `_text=${encodeURIComponent(_text)}`] if (route) options = [ ...options, `dosage-route=${ encodeURIComponent('https://terminology.eds.aphp.fr/aphp-orbis-medicament-voie-administration|') + route }` - ] // eslint-disable-line - if (minDate) options = [...options, `effective-time=ge${minDate}`] // eslint-disable-line - if (maxDate) options = [...options, `effective-time=le${maxDate}`] // eslint-disable-line + ] + if (minDate) options = [...options, `effective-time=ge${minDate}`] + if (maxDate) options = [...options, `effective-time=le${maxDate}`] if (executiveUnits && executiveUnits.length > 0) options = [...options, `context.encounter-care-site=${executiveUnits}`] // eslint-disable-line - if (_list && _list.length > 0) options = [...options, `_list=${_list.reduce(paramValuesReducer)}`] // eslint-disable-line + if (_list && _list.length > 0) options = [...options, `_list=${_list.reduce(paramValuesReducer)}`] const response = await apiFhir.get>( `/MedicationAdministration?${options.reduce(paramsReducer)}`, @@ -867,7 +868,7 @@ export const fetchImaging = async (args: fetchImagingProps): FHIR_Bundle_Promise if (modalities) options = [...options, `modality=*${encodeURIComponent('|')}${modalities}`] if (executiveUnits && executiveUnits.length > 0) options = [...options, `encounter.encounter-care-site=${executiveUnits}`] - if (_list && _list.length > 0) options = [...options, `_list=${_list.reduce(paramValuesReducer)}`] // eslint-disable-line + if (_list && _list.length > 0) options = [...options, `_list=${_list.reduce(paramValuesReducer)}`] const response = await apiFhir.get>( `/ImagingStudy?${options.reduce(paramsReducer)}`, @@ -1018,13 +1019,13 @@ export const fetchScope: ( const { perimetersIds, cohortIds, search, type, isExecutiveUnit, offset, limit } = args let options: string[] = [] - if (search) options = [...options, `search=${search}`] // eslint-disable-line - if (offset) options = [...options, `offset=${offset}`] // eslint-disable-line - if (limit) options = [...options, `limit=${limit}`] // eslint-disable-line - if (!search) options = [...options, `limit=-1`] // eslint-disable-line - if (perimetersIds && perimetersIds.length > 0) options = [...options, `local_id=${perimetersIds.join(',')}`] // eslint-disable-line - if (cohortIds && cohortIds.length > 0) options = [...options, `cohort_id=${cohortIds.join(',')}`] // eslint-disable-line - if (type && type.length > 0) options = [...options, `type_source_value=${type.join(',')}`] // eslint-disable-line + if (search) options = [...options, `search=${search}`] + if (offset) options = [...options, `offset=${offset}`] + if (limit) options = [...options, `limit=${limit}`] + if (!search) options = [...options, `limit=-1`] + if (perimetersIds && perimetersIds.length > 0) options = [...options, `local_id=${perimetersIds.join(',')}`] + if (cohortIds && cohortIds.length > 0) options = [...options, `cohort_id=${cohortIds.join(',')}`] + if (type && type.length > 0) options = [...options, `type_source_value=${type.join(',')}`] const url: string = isExecutiveUnit ? 'accesses/perimeters/?' : 'accesses/perimeters/patient-data/rights/?' const response: AxiosResponse = await apiBackend.get(`${url}${options.reduce(paramsReducer)}`, { @@ -1039,7 +1040,7 @@ export const fetchAccessExpirations: ( const { expiring } = args let options: string[] = [] - if (expiring === true || expiring === false) options = [...options, `expiring=${expiring}`] // eslint-disable-line + if (expiring === true || expiring === false) options = [...options, `expiring=${expiring}`] const response: AxiosResponse = await apiBackend.get( `accesses/accesses/my-accesses/?${options.reduce(paramsReducer)}` @@ -1053,7 +1054,7 @@ export const fetchPerimeterAccesses = async (perimeter: string): Promise { - const response = await apiBackend.get(`cohort/cohorts/cohort-rights/?fhir_group_id=${cohortIds}`) + const response = await apiBackend.get(`cohort/cohorts/cohort-rights/?fhir_group_id=${cohortIds}`) return response } diff --git a/src/services/aphp/serviceCohortCreation.ts b/src/services/aphp/serviceCohortCreation.ts index 1bf1091d3..95ed29c79 100644 --- a/src/services/aphp/serviceCohortCreation.ts +++ b/src/services/aphp/serviceCohortCreation.ts @@ -2,7 +2,10 @@ import { AxiosResponse } from 'axios' import apiBack from '../apiBackend' import { + Cohort, + CountCohort, DatedMeasure, + FetchRequest, HierarchyElement, HierarchyElementWithSystem, QuerySnapshotInfo, @@ -52,12 +55,17 @@ export interface IServiceCohortCreation { cohortName?: string, cohortDescription?: string, globalCount?: boolean - ) => Promise + ) => Promise | null> /** * Cette fonction permet de récupérer le count d'une requête */ - countCohort: (requeteurJson?: string, snapshotId?: string, requestId?: string, uuid?: string) => Promise + countCohort: ( + requeteurJson?: string, + snapshotId?: string, + requestId?: string, + uuid?: string + ) => Promise /** * Cette fonction permet de créer un état de `snapshot` pour l'historique d'une requête @@ -72,7 +80,7 @@ export interface IServiceCohortCreation { /** * Permet de récupérer toutes les informations utiles pour l'utilisation du requeteur */ - fetchRequest: (requestId: string, snapshotId?: string) => Promise + fetchRequest: (requestId: string, snapshotId?: string) => Promise fetchSnapshot: (snapshotId: string) => Promise @@ -132,7 +140,7 @@ const servicesCohortCreation: IServiceCohortCreation = { if (!requeteurJson || !datedMeasureId || !snapshotId || !requestId) return null if (globalCount === undefined) globalCount = false - const cohortResult = await apiBack.post('/cohort/cohorts/', { + const cohortResult = await apiBack.post('/cohort/cohorts/', { dated_measure_id: datedMeasureId, request_query_snapshot_id: snapshotId, request_id: requestId, @@ -157,7 +165,7 @@ const servicesCohortCreation: IServiceCohortCreation = { byrequest: 0, count_outdated: measureResult?.data?.count_outdated, shortCohortLimit: measureResult?.data?.cohort_limit - } + } as CountCohort } else { if (!requeteurJson || !snapshotId || !requestId) return null @@ -172,7 +180,7 @@ const servicesCohortCreation: IServiceCohortCreation = { uuid: measureResult?.data?.uuid, count_outdated: measureResult?.data?.count_outdated, shortCohortLimit: measureResult?.data?.cohort_limit - } + } as CountCohort } }, @@ -224,7 +232,9 @@ const servicesCohortCreation: IServiceCohortCreation = { // clean Global count currentSnapshot = { ...currentSnapshot, - dated_measures: currentSnapshot.dated_measures.filter((dated_measure: any) => dated_measure.mode !== 'Global') + dated_measures: currentSnapshot.dated_measures.filter( + (dated_measure: DatedMeasure) => dated_measure.mode !== 'Global' + ) } shortCohortLimit = @@ -242,7 +252,7 @@ const servicesCohortCreation: IServiceCohortCreation = { count: currentSnapshot ? currentSnapshot.dated_measures[0] : {}, shortCohortLimit, count_outdated - } + } as FetchRequest return result }, diff --git a/src/services/aphp/serviceCohorts.ts b/src/services/aphp/serviceCohorts.ts index b40e95dce..38c974dc8 100644 --- a/src/services/aphp/serviceCohorts.ts +++ b/src/services/aphp/serviceCohorts.ts @@ -9,7 +9,8 @@ import { DocumentsData, ImagingData, CohortImaging, - CohortComposition + CohortComposition, + Export } from 'types' import { getGenderRepartitionMapAphp, @@ -32,8 +33,8 @@ import { } from './callApi' import apiBackend from '../apiBackend' -import { Binary, DocumentReference, Extension, ParametersParameter, Patient } from 'fhir/r4' -import { CanceledError } from 'axios' +import { Binary, DocumentReference, Extension, ImagingStudy, ParametersParameter, Patient } from 'fhir/r4' +import { AxiosError, AxiosResponse, CanceledError, isAxiosError } from 'axios' import { VitalStatus, SearchCriterias, @@ -139,7 +140,7 @@ export interface IServiceCohorts { }, groupId?: string, signal?: AbortSignal - ) => Promise | Promise | Promise> + ) => Promise | Promise /** * Retourne la liste d'objets d'Imagerie liés à une cohorte @@ -153,7 +154,7 @@ export interface IServiceCohorts { }, groupId?: string, signal?: AbortSignal - ) => Promise | Promise> + ) => Promise /** * Permet de vérifier si le champ de recherche textuelle est correct @@ -207,7 +208,11 @@ export interface IServiceCohorts { * - motivation: Raison de l'export * - tables: Liste de tables demandées dans l'export */ - createExport: (args: { cohortId: number; motivation: string; tables: string[] }) => Promise + createExport: (args: { + cohortId: number + motivation: string + tables: string[] + }) => Promise | AxiosError> } const servicesCohorts: IServiceCohorts = { @@ -259,32 +264,29 @@ const servicesCohorts: IServiceCohorts = { const agePyramidData = patientsResp.data.resourceType === 'Bundle' ? getAgeRepartitionMapAphp( - patientsResp.data.meta?.extension?.find((facet: any) => facet.url === ChartCode.agePyramid)?.extension + patientsResp.data.meta?.extension?.find((facet) => facet.url === ChartCode.agePyramid)?.extension ) : undefined const genderRepartitionMap = patientsResp.data.resourceType === 'Bundle' ? getGenderRepartitionMapAphp( - patientsResp.data.meta?.extension?.find((facet: any) => facet.url === ChartCode.genderRepartition) - ?.extension + patientsResp.data.meta?.extension?.find((facet) => facet.url === ChartCode.genderRepartition)?.extension ) : undefined const monthlyVisitData = encountersResp.data.resourceType === 'Bundle' ? getVisitRepartitionMapAphp( - encountersResp.data.meta?.extension?.find((facet: any) => facet.url === ChartCode.monthlyVisits) - ?.extension + encountersResp.data.meta?.extension?.find((facet) => facet.url === ChartCode.monthlyVisits)?.extension ) : undefined const visitTypeRepartitionData = encountersResp.data.resourceType === 'Bundle' ? getEncounterRepartitionMapAphp( - encountersResp.data.meta?.extension?.find( - (facet: Extension) => facet.url === ChartCode.visitTypeRepartition - )?.extension + encountersResp.data.meta?.extension?.find((facet) => facet.url === ChartCode.visitTypeRepartition) + ?.extension ) : undefined @@ -440,7 +442,12 @@ const servicesCohorts: IServiceCohorts = { ]) const imagingList = getApiResponseResources(imagingResponse) ?? [] - const completeImagingList = (await getResourceInfos(imagingList, deidentified, groupId, signal)) as CohortImaging[] + const completeImagingList = await getResourceInfos( + imagingList, + deidentified, + groupId, + signal + ) const totalImaging = imagingResponse.data?.resourceType === 'Bundle' ? imagingResponse.data?.total : 0 const totalAllImaging = @@ -529,12 +536,12 @@ const servicesCohorts: IServiceCohorts = { : totalPatientDocs const documentsList = getApiResponseResources(docsList) ?? [] - const filledDocumentsList = (await getResourceInfos( + const filledDocumentsList = await getResourceInfos( documentsList, deidentified, groupId, signal - )) as CohortComposition[] + ) return { totalDocs: totalDocs ?? 0, @@ -619,18 +626,18 @@ const servicesCohorts: IServiceCohorts = { return documentBinaries && documentBinaries.length > 0 ? documentBinaries[0] : undefined }, - fetchCohortsRights: async (cohorts) => { + fetchCohortsRights: async (cohorts): Promise => { try { const ids = cohorts .map((cohort) => cohort.fhir_group_id) .filter((id) => id !== undefined || id !== '') - .filter((i) => i !== '') as string[] + .filter((i): i is string => i !== '') if (ids.length === 0) return [] const rightsResponse = await fetchCohortAccesses(ids) return cohorts.map((cohort) => { return { ...cohort, - rights: rightsResponse.data.find((right: any) => right.cohort_id == cohort.fhir_group_id)?.rights + rights: rightsResponse.data.find((right) => right.cohort_id == cohort.fhir_group_id)?.rights } }) } catch (error) { @@ -639,40 +646,22 @@ const servicesCohorts: IServiceCohorts = { } }, - createExport: async (args) => { + createExport: async (args): Promise | AxiosError> => { try { const { cohortId, motivation, tables } = args - const exportResponse = await new Promise((resolve) => { - resolve( - apiBackend.post('/exports/', { - cohort_id: cohortId, - motivation, - tables: tables.map((table: string) => ({ - omop_table_name: table - })), - nominative: true, // Nominative should always be true when exporting a CSV (see issue #1113) - output_format: 'csv' - }) - ) + return await apiBackend.post('/exports/', { + cohort_id: cohortId, + motivation, + tables: tables.map((table) => ({ + omop_table_name: table + })), + nominative: true, // Nominative should always be true when exporting a CSV (see issue #1113) + output_format: 'csv' }) - .then((values) => { - return values - }) - .catch((error) => { - return error - }) - - // @ts-ignore - if (exportResponse && exportResponse && exportResponse.status !== 201) { - // @ts-ignore - return { error: exportResponse && exportResponse.response.data } - } else { - // @ts-ignore - return exportResponse && exportResponse.data - } } catch (error) { - return { error } + if (isAxiosError(error)) return error + else throw error } } } diff --git a/src/services/aphp/servicePractitioner.ts b/src/services/aphp/servicePractitioner.ts index 781d65e72..30403ad35 100644 --- a/src/services/aphp/servicePractitioner.ts +++ b/src/services/aphp/servicePractitioner.ts @@ -1,5 +1,7 @@ import apiBackend from 'services/apiBackend' import { REFRESH_TOKEN } from '../../constants' +import { Authentication, MaintenanceInfo } from 'types' +import { AxiosError, AxiosResponse } from 'axios' export interface IServicePractitioner { /** @@ -11,8 +13,11 @@ export interface IServicePractitioner { * * Retourne la reponse de Axios */ - authenticateWithCredentials: (username: string, password: string) => Promise - authenticateWithCode: (code: string) => Promise + authenticateWithCredentials: ( + username: string, + password: string + ) => Promise | AxiosError> + authenticateWithCode: (code: string) => Promise | AxiosError> /** * Cette fonction permet d'appeler la route de logout @@ -23,43 +28,43 @@ export interface IServicePractitioner { /** * Maintenance */ - maintenance: () => Promise + maintenance: () => Promise | AxiosError> } const servicePractitioner: IServicePractitioner = { - authenticateWithCredentials: async (username, password) => { + authenticateWithCredentials: async (username, password): Promise | AxiosError> => { try { const formData = new FormData() formData.append('username', username.toString()) formData.append('password', password) - return await apiBackend.post(`/auth/login/`, formData) + return await apiBackend.post(`/auth/login/`, formData) } catch (error) { console.error('Error authenticating with credentials', error) - return error + return error as AxiosError } }, - authenticateWithCode: async (authCode: string) => { + authenticateWithCode: async (authCode: string): Promise | AxiosError> => { try { - return await apiBackend.post(`/auth/oidc/login`, { auth_code: authCode }) + return await apiBackend.post(`/auth/oidc/login`, { auth_code: authCode }) } catch (error) { console.error('Error authenticating with an authorization code', error) - return error + return error as AxiosError } }, - logout: async () => { + logout: async (): Promise => { await apiBackend.post(`/auth/logout/`, { refresh_token: localStorage.getItem(REFRESH_TOKEN) }) localStorage.clear() }, - maintenance: async () => { + maintenance: async (): Promise | AxiosError> => { try { - return await apiBackend.get(`/maintenances/next/`) + return await apiBackend.get(`/maintenances/next/`) } catch (error) { - console.error("erreur lors de l'éxécution de la fonction maintenance", error) - return error + console.error("Erreur lors de l'exécution de la fonction maintenance", error) + return error as AxiosError } } } diff --git a/src/services/aphp/serviceProjects.ts b/src/services/aphp/serviceProjects.ts index f8b3ba200..2634ecae9 100644 --- a/src/services/aphp/serviceProjects.ts +++ b/src/services/aphp/serviceProjects.ts @@ -1,3 +1,4 @@ +import { AxiosResponse } from 'axios' import apiBack from '../apiBackend' import { ProjectType, RequestType, Cohort, User } from 'types' @@ -117,7 +118,7 @@ export interface IServiceProjects { * Retourne: * - Requete partagée */ - shareRequest: (sharedRequest: RequestType, notify_by_email: boolean) => Promise + shareRequest: (sharedRequest: RequestType, notify_by_email: boolean) => Promise> /** * Cette fonction supprime un requete existant @@ -331,13 +332,13 @@ const servicesProjects: IServiceProjects = { throw new Error('Impossible de modifier la requête') } }, - shareRequest: async (sharedRequest, notify_by_email) => { + shareRequest: async (sharedRequest, notify_by_email): Promise> => { const usersToShareId = sharedRequest.usersToShare?.map((userToshareId: User) => userToshareId.username) const shared_query_snapshot_id = sharedRequest.shared_query_snapshot ? sharedRequest.shared_query_snapshot : sharedRequest.currentSnapshot?.uuid const shared_query_snapshot_name = sharedRequest.name ? sharedRequest.name : sharedRequest.requestName - const shareRequestResponse = (await apiBack.post( + const shareRequestResponse = (await apiBack.post( `/cohort/request-query-snapshots/${shared_query_snapshot_id}/share/`, { name: shared_query_snapshot_name, @@ -346,7 +347,7 @@ const servicesProjects: IServiceProjects = { } )) ?? { status: 400 } if (shareRequestResponse.status === 201) { - return shareRequestResponse.data as ProjectType, shareRequestResponse + return shareRequestResponse.data, shareRequestResponse } else { console.error('Impossible de partager la requête') return shareRequestResponse @@ -357,7 +358,7 @@ const servicesProjects: IServiceProjects = { status: 400 } if (deleteProjectResponse.status === 204) { - return deleteProjectResponse.data as ProjectType + return deleteProjectResponse.data } else { throw new Error('Impossible de supprimer la requête') } @@ -406,7 +407,7 @@ const servicesProjects: IServiceProjects = { fetchCohortsList: async (filters, searchInput, orderBy, limit, offset, signal) => { const _sortDirection = orderBy.orderDirection === Direction.DESC ? '-' : '' - const optionsReducer = (accumulator: any, currentValue: any) => + const optionsReducer = (accumulator: string, currentValue: string) => accumulator ? `${accumulator}&${currentValue}` : currentValue ? currentValue : accumulator let options: string[] = [] diff --git a/src/services/aphp/serviceUsers.ts b/src/services/aphp/serviceUsers.ts index 35278d28c..5172f6f29 100644 --- a/src/services/aphp/serviceUsers.ts +++ b/src/services/aphp/serviceUsers.ts @@ -1,10 +1,11 @@ import { Direction, OrderBy } from 'types/searchCriterias' import apiBack from '../apiBackend' +import { Back_API_Response, User } from 'types' export const getUsers = async (orderBy: OrderBy, page?: number, searchInput?: string) => { const searchFilter = searchInput ? `&search=${searchInput}` : '' - const usersResp = await apiBack.get( + const usersResp = await apiBack.get>( `/users/?manual_only=true&page=${page}&ordering=${orderBy.orderDirection === Direction.DESC ? '-' : ''}${ orderBy.orderBy }${searchFilter}` @@ -12,12 +13,12 @@ export const getUsers = async (orderBy: OrderBy, page?: number, searchInput?: st if (usersResp.status === 200) { return { - users: usersResp.data.results ?? undefined, + users: usersResp.data.results ?? [], total: usersResp.data.count ?? 0 } } else { return { - users: undefined, + users: [], total: 0 } } diff --git a/src/state/exploredCohort.ts b/src/state/exploredCohort.ts index 5f9df1f13..18b9f49e9 100644 --- a/src/state/exploredCohort.ts +++ b/src/state/exploredCohort.ts @@ -7,12 +7,12 @@ import { ODD_EXPORT } from '../constants' import services from 'services/aphp' import servicesPerimeters from '../services/aphp/servicePerimeters' -import { GroupMember } from 'fhir/r4' +import { GroupMember, Patient } from 'fhir/r4' export type ExploredCohortState = { - importedPatients: any[] - includedPatients: any[] - excludedPatients: any[] + importedPatients: Patient[] + includedPatients: Patient[] + excludedPatients: Patient[] loading: boolean rightToExplore: boolean | undefined requestId?: string @@ -94,7 +94,7 @@ const fetchExploredCohort = createAsyncThunk< shouldRefreshData = !statePerimeterIds || statePerimeterIds.length !== perimeterIds.length || - statePerimeterIds.some((id) => !perimeterIds.includes(id)) + statePerimeterIds.some((id: string) => !perimeterIds.includes(id)) break } case 'patients': { @@ -198,7 +198,7 @@ const exploredCohortSlice = createSlice({ name: 'exploredCohort', initialState: defaultInitialState as ExploredCohortState, reducers: { - addImportedPatients: (state: ExploredCohortState, action: PayloadAction) => { + addImportedPatients: (state: ExploredCohortState, action: PayloadAction) => { const importedPatients = [...state.importedPatients, ...action.payload] state.importedPatients = importedPatients.filter( (patient, index, self) => @@ -207,18 +207,18 @@ const exploredCohortSlice = createSlice({ !state.excludedPatients.map((p) => p.id).includes(patient.id) ) }, - removeImportedPatients: (state: ExploredCohortState, action: PayloadAction) => { + removeImportedPatients: (state: ExploredCohortState, action: PayloadAction) => { const listId = action.payload.map((patient) => patient.id) state.importedPatients = state.importedPatients.filter((patient) => !listId.includes(patient.id)) }, - includePatients: (state: ExploredCohortState, action: PayloadAction) => { + includePatients: (state: ExploredCohortState, action: PayloadAction) => { const includedPatients = [...state.includedPatients, ...action.payload] state.importedPatients = state.importedPatients.filter( (patient) => !action.payload.map((p) => p.id).includes(patient.id) ) state.includedPatients = includedPatients }, - excludePatients: (state: ExploredCohortState, action: PayloadAction) => { + excludePatients: (state: ExploredCohortState, action: PayloadAction) => { const toExcluded = state.originalPatients?.filter((patient) => action.payload.map((p) => p.id).includes(patient.id) ) @@ -241,7 +241,7 @@ const exploredCohortSlice = createSlice({ importedPatients: allImportedPatients } }, - removeExcludedPatients: (state: ExploredCohortState, action: PayloadAction) => { + removeExcludedPatients: (state: ExploredCohortState, action: PayloadAction) => { if (!action || !action.payload) return const statePatient = state.originalPatients || [] const originalPatients = [...statePatient, ...action.payload] diff --git a/src/types.ts b/src/types.ts index 2884ee72c..0239a9d12 100644 --- a/src/types.ts +++ b/src/types.ts @@ -5,6 +5,7 @@ import { Condition, DocumentReference, Encounter, + Extension, FhirResource, Group, ImagingStudy, @@ -12,6 +13,7 @@ import { MedicationRequest, Observation, OperationOutcome, + Parameters, Patient, Procedure, Resource @@ -19,7 +21,7 @@ import { import { AxiosResponse } from 'axios' import { SearchByTypes } from 'types/searchCriterias' import { SearchInputError } from 'types/error' -import { Comparators, CriteriaDataKey, SelectedCriteriaType } from 'types/requestCriterias' +import { Comparators, CriteriaDataKey, DocType, SelectedCriteriaType } from 'types/requestCriterias' export enum CohortJobStatus { _long_pending = 'long_pending', @@ -73,6 +75,29 @@ export enum CohortCreationError { ERROR_REGEX = 'error_regex' } +export type Authentication = Token & { + user: User + last_login: string +} + +export type Token = { + access_token: string + refresh_token: string +} + +export type MaintenanceInfo = { + id: string + insert_datetime: string + update_datetime: string + delete_datetime: string + start_datetime: string + end_datetime: string + maintenance_start: string + maintenance_end: string + active: boolean + subject: string +} + export type FHIR_API_Response = T | OperationOutcome export type FHIR_Bundle_Response = FHIR_API_Response> export type FHIR_API_Promise_Response = Promise>> @@ -99,7 +124,7 @@ export type CohortComposition = DocumentReference & { serviceProvider?: string NDA?: string event?: {} - parameter?: any[] + parameter?: Parameters[] title?: string encounter?: { id?: string @@ -107,7 +132,7 @@ export type CohortComposition = DocumentReference & { serviceProvider?: string NDA?: string event?: {} - parameter?: any[] + parameter?: Parameters[] title?: string }[] } @@ -221,7 +246,7 @@ export type ScopeTreeRow = AbstractTree<{ full_path?: string quantity: number parentId?: string | null - managingEntity?: any | undefined + managingEntity?: never above_levels_ids?: string inferior_levels_ids?: string cohort_id?: string @@ -285,7 +310,7 @@ export type CohortData = { originalPatients?: CohortPatient[] totalDocs?: number documentsList?: CohortComposition[] - wordcloudData?: any + wordcloudData?: never[] encounters?: Encounter[] genderRepartitionMap?: GenderRepartitionType visitTypeRepartitionData?: SimpleChartDataType[] @@ -386,10 +411,16 @@ export type CriteriaItemType = { fontWeight?: string components: React.FC | null disabled?: boolean - fetch?: { [key in CriteriaDataKey]?: (...args: any[]) => Promise } + fetch?: { [key in CriteriaDataKey]?: FetchFunctionVariant } subItems?: CriteriaItemType[] } +type FetchFunctionVariant = + | (() => Promise) + | ((searchValue?: string, noStar?: boolean, signal?: AbortSignal) => Promise) + +export type ResearchType = string | boolean | AbortSignal | undefined + export type ValueSet = { code: string display: string @@ -454,6 +485,13 @@ export type Snapshot = QuerySnapshotInfo & { perimeters_ids?: string[] } +export type RequestQuerySnapshot = Snapshot & { + name: string + insert_datetime: string + update_datetime: string + delete_datetime: string +} + export type CurrentSnapshot = Snapshot & { navHistoryIndex: number } @@ -480,6 +518,17 @@ export type DatedMeasure = { mode: 'Snapshot' | 'Global' } +export type CountCohort = { + date: string + status?: string + uuid: string + shortCohortLimit: number + count_outdated: boolean + jobFailMsg?: string + includePatient?: number + byrequest?: number +} + export type Cohort = { uuid?: string owner?: string @@ -504,7 +553,12 @@ export type Cohort = { favorite?: boolean create_task_id?: string type?: 'IMPORT_I2B2' | 'MY_ORGANIZATIONS' | 'MY_PATIENTS' | 'MY_COHORTS' - extension?: any[] + extension?: Extension[] + rights?: GroupRights +} + +export type CohortRights = { + cohort_id: string rights?: GroupRights } @@ -520,6 +574,30 @@ export type CohortCreationCounterType = { count_outdated?: boolean } +export type FetchRequest = { + requestName: string + snapshotsHistory: QuerySnapshotInfo[] + json: string + currentSnapshot: Snapshot + count: DatedMeasure + shortCohortLimit: number + count_outdated: boolean +} + +export type Export = { + motivation: string + output_format: string + cohort_id: string + provider_source_value: string + target_unix_account: number + tables: { omop_table_name: string } + nominative: boolean + shift_dates: boolean + cohort_fk: string + provider_id: string + owner: string +} + export type ContactSubmitForm = FormData /** diff --git a/src/utils/cohortCreation.ts b/src/utils/cohortCreation.ts index 174ad659c..0ba459854 100644 --- a/src/utils/cohortCreation.ts +++ b/src/utils/cohortCreation.ts @@ -184,15 +184,15 @@ type RequeteurSearchType = { version: string _type: string sourcePopulation: { - caresiteCohortList?: number[] - providerCohorttList?: number[] + caresiteCohortList?: string[] + providerCohortList?: string[] } request: RequeteurGroupType | undefined } const constructFilterFhir = (criterion: SelectedCriteriaType, deidentified: boolean): string => { let filterFhir = '' - const filterReducer = (accumulator: any, currentValue: any): string => + const filterReducer = (accumulator: string, currentValue: string): string => accumulator ? `${accumulator}&${currentValue}` : currentValue ? currentValue : accumulator switch (criterion.type) { @@ -499,8 +499,8 @@ export function buildRequest( _type: 'request', sourcePopulation: { caresiteCohortList: selectedPopulation - ?.map((_selectedPopulation: any) => _selectedPopulation.cohort_id) - .filter((item) => !!item && item !== 'loading') + ?.map((_selectedPopulation) => _selectedPopulation?.cohort_id) + .filter((item): item is string => !!item && item !== 'loading') }, request: !mainCriteriaGroups ? undefined @@ -1190,17 +1190,20 @@ export async function unbuildRequest(_json: string): Promise { ) => _criteriaGroup && _criteriaGroup.length > 0 ? _criteriaGroup - .map((groupItem: any) => ({ - id: groupItem._id, - title: 'Groupe de critères', - criteriaIds: - groupItem.criteria && groupItem.criteria.length > 0 - ? groupItem.criteria.map((criteria: RequeteurCriteriaType | RequeteurGroupType) => criteria._id) - : [], - isSubGroup: groupItem.isSubItem, - isInclusive: groupItem.isInclusive, - type: groupItem._type - })) + .map( + (groupItem: RequeteurGroupType) => + ({ + id: groupItem._id, + title: 'Groupe de critères', + criteriaIds: + groupItem.criteria && groupItem.criteria.length > 0 + ? groupItem.criteria.map((criteria) => criteria._id) + : [], + isSubGroup: !!groupItem.criteria.length, + isInclusive: groupItem.isInclusive, + type: groupItem._type + } as CriteriaGroupType) + ) .sort((prev, next) => next.id - prev.id) : [] @@ -1365,16 +1368,22 @@ export const joinRequest = async (oldJson: string, newJson: string, parentId: nu const oldRequest = JSON.parse(oldJson) as RequeteurSearchType const newRequest = JSON.parse(newJson) as RequeteurSearchType - const changeIdOfRequest = (request: any): any => { - const { criteria } = request + const isRequeteurGroupType = ( + criterion: RequeteurGroupType | RequeteurCriteriaType + ): criterion is RequeteurGroupType => { + return criterion && !!(criterion as RequeteurGroupType).criteria.length + } + const changeIdOfRequest = ( + criteria: (RequeteurGroupType | RequeteurCriteriaType)[] + ): (RequeteurGroupType | RequeteurCriteriaType)[] => { for (const criterion of criteria) { if (criterion._type === 'basicResource') { criterion._id += 128 } else { criterion._id -= 128 - if (criterion && criterion.criteria && criterion.criteria.length > 0) { - criterion.criteria = changeIdOfRequest(criterion) + if (isRequeteurGroupType(criterion) && criterion.criteria && criterion.criteria.length > 0) { + criterion.criteria = changeIdOfRequest(criterion.criteria) } } } @@ -1385,7 +1394,7 @@ export const joinRequest = async (oldJson: string, newJson: string, parentId: nu _id: (newRequest?.request?._id ?? 0) - 128, _type: newRequest.request?._type === 'andGroup' ? 'andGroup' : 'orGroup', isInclusive: true, - criteria: changeIdOfRequest(newRequest.request) + criteria: changeIdOfRequest(newRequest.request?.criteria || []) } const fillRequestWithNewRequest = (criterionGroup?: RequeteurGroupType): RequeteurGroupType | undefined => { diff --git a/src/utils/displayValueSetSystem.ts b/src/utils/displayValueSetSystem.ts index d4eee49f2..fac490b07 100644 --- a/src/utils/displayValueSetSystem.ts +++ b/src/utils/displayValueSetSystem.ts @@ -1,7 +1,6 @@ import { MEDICATION_ATC, MEDICATION_UCD } from '../constants' -import { ValueSetSystem } from '../types' -export const displaySystem = (system?: ValueSetSystem) => { +export const displaySystem = (system?: string) => { switch (system) { case MEDICATION_ATC: return 'ATC: '