-
Notifications
You must be signed in to change notification settings - Fork 10
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
b81f46a
commit dfd5bfc
Showing
19 changed files
with
1,214 additions
and
23 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
100 changes: 100 additions & 0 deletions
100
...omponents/LogicalOperator/components/CriteriaRightPanel/CriteriaForm/components/index.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,100 @@ | ||
import { FormLabel, Tooltip } from '@mui/material' | ||
import React, { PropsWithChildren } from 'react' | ||
import { | ||
CriteriaDataType, | ||
CriteriaFormItemView, | ||
CriteriaFormItemViewProps, | ||
CriteriaItem, | ||
CriteriaItemType, | ||
CriteriaSection, | ||
DataTypeMapping | ||
} from '../types' | ||
import useStyles from '../style' | ||
import { BlockWrapper } from 'components/ui/Layout' | ||
import Collapse from 'components/ui/Collapse' | ||
import { CriteriaLabel } from 'components/ui/CriteriaLabel' | ||
import InfoIcon from '@mui/icons-material/Info' | ||
|
||
type CriteriaItemRuntimeProps<T extends CriteriaDataType> = { | ||
setError: (error?: string) => void | ||
updateData: (data: T) => void | ||
data: T | ||
getValueSetOptions: CriteriaFormItemViewProps<never>['getValueSetOptions'] | ||
searchCode: CriteriaFormItemViewProps<never>['searchCode'] | ||
viewRenderers: { [key in CriteriaItemType]: CriteriaFormItemView<key> } | ||
} | ||
|
||
type CritieraItemProps<T extends CriteriaDataType, U extends CriteriaItem<T>> = CriteriaItemRuntimeProps<T> & U | ||
|
||
export const CFLabel = (props: { label: string; tooltip?: string; altStyle?: boolean }) => { | ||
const { label, tooltip, altStyle } = props | ||
if (altStyle) { | ||
return ( | ||
<FormLabel | ||
style={{ padding: '0 0 1em', fontWeight: 600, fontSize: 12, display: 'flex', alignItems: 'center' }} | ||
component="legend" | ||
> | ||
Fin de prise en charge | ||
{tooltip && ( | ||
<Tooltip title={tooltip}> | ||
<InfoIcon fontSize="small" color="primary" style={{ marginLeft: 4 }} /> | ||
</Tooltip> | ||
)} | ||
</FormLabel> | ||
) | ||
} | ||
return label | ||
} | ||
|
||
export const CFItem = <T extends CriteriaDataType, U extends CriteriaItem<T>>(props: CritieraItemProps<T, U>) => { | ||
const { valueKey, updateData, data, setError, getValueSetOptions, searchCode, viewRenderers } = props | ||
const View = viewRenderers[props.type] as CriteriaFormItemView<U['type']> | ||
const fieldValue = data[valueKey] as DataTypeMapping[U['type']]['dataType'] | ||
return ( | ||
<View | ||
value={fieldValue} | ||
definition={props} | ||
updateData={(value) => updateData({ ...data, [valueKey]: value })} | ||
getValueSetOptions={getValueSetOptions} | ||
searchCode={searchCode} | ||
setError={setError} | ||
/> | ||
) | ||
} | ||
|
||
export const CFSection = <T extends CriteriaDataType>( | ||
props: PropsWithChildren<Omit<CriteriaSection<T>, 'items'> & { collapsed?: boolean }> | ||
) => { | ||
const { classes } = useStyles() | ||
return props.title ? ( | ||
<BlockWrapper className={classes.inputItem}> | ||
<Collapse title={props.title} value={!props.defaulCollapsed || !props.collapsed} margin="0"> | ||
{props.children} | ||
</Collapse> | ||
</BlockWrapper> | ||
) : ( | ||
<>{props.children}</> | ||
) | ||
} | ||
|
||
export const CFItemWrapper = (props: PropsWithChildren<{ label?: string; info?: string }>) => { | ||
const { classes } = useStyles() | ||
return ( | ||
<BlockWrapper className={classes.inputItem}> | ||
{props.label ? ( | ||
<CriteriaLabel label={props.label} style={{ padding: 0, marginTop: '1em' }}> | ||
{props.info && ( | ||
<Tooltip title={props.info}> | ||
<InfoIcon fontSize="small" color="primary" style={{ marginLeft: 4 }} /> | ||
</Tooltip> | ||
)} | ||
</CriteriaLabel> | ||
) : ( | ||
'' | ||
)} | ||
{props.children} | ||
</BlockWrapper> | ||
) | ||
} | ||
|
||
export default { CFItemWrapper, CFSection, CFLabel, CFItem } |
79 changes: 79 additions & 0 deletions
79
...agramView/components/LogicalOperator/components/CriteriaRightPanel/CriteriaForm/index.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,79 @@ | ||
import React, { useEffect, useState } from 'react' | ||
import CriteriaLayout from 'components/ui/CriteriaLayout' | ||
import { | ||
CriteriaData, | ||
CriteriaForm as CriteriaFormDefinition, | ||
CriteriaDataType, | ||
CriteriaFormItemViewProps | ||
} from './types' | ||
import { CFItem, CFItemWrapper, CFSection } from './components' | ||
import FORM_ITEM_RENDERER from './renderers' | ||
|
||
export type CriteriaFormRuntimeProps<T extends CriteriaDataType> = { | ||
goBack: () => void | ||
data?: CriteriaData<T> | ||
updateData: (data: CriteriaData<T>) => void | ||
getValueSetOptions: CriteriaFormItemViewProps<never>['getValueSetOptions'] | ||
searchCode: CriteriaFormItemViewProps<never>['searchCode'] | ||
} | ||
|
||
type CriteriaFormProps<T extends CriteriaDataType> = CriteriaFormDefinition<T> & CriteriaFormRuntimeProps<T> | ||
|
||
export default function CriteriaForm<T extends CriteriaDataType>(props: CriteriaFormProps<T>) { | ||
const [criteriaData, setCriteriaData] = useState<CriteriaData<T>>(props.data || props.initialData) | ||
const { goBack, updateData, label, warningAlert, getValueSetOptions, itemSections, errorMessages, onDataChange } = | ||
props | ||
const isEdition = !!props.data | ||
const [error, setError] = useState<string>() | ||
|
||
useEffect(() => { | ||
onDataChange?.(criteriaData) | ||
}, [criteriaData, onDataChange]) | ||
|
||
return ( | ||
<CriteriaLayout | ||
criteriaLabel={`${label}`} | ||
title={criteriaData.title} | ||
onChangeTitle={(title) => setCriteriaData({ ...criteriaData, title })} | ||
isEdition={isEdition} | ||
goBack={goBack} | ||
onSubmit={() => updateData(criteriaData)} | ||
disabled={error !== undefined} | ||
isInclusive={criteriaData.isInclusive} | ||
onChangeIsInclusive={(isInclusive) => setCriteriaData({ ...criteriaData, isInclusive: isInclusive })} | ||
infoAlert={['Tous les éléments des champs multiples sont liés par une contrainte OU']} | ||
warningAlert={warningAlert} | ||
errorAlert={error ? [errorMessages[error]] : undefined} | ||
> | ||
{itemSections.map((section, index) => ( | ||
<CFSection | ||
key={index} | ||
title={section.title} | ||
defaulCollapsed={section.defaulCollapsed} | ||
collapsed={section.items.every((item) => { | ||
const value = criteriaData[item.valueKey] | ||
return value === null || value === undefined || (Array.isArray(value) && value.length === 0) | ||
})} | ||
> | ||
{section.items.map((item, index) => ( | ||
<CFItemWrapper key={index} label={item.extraLabel} info={item.extraInfo}> | ||
<CFItem | ||
{...{ | ||
viewRenderers: FORM_ITEM_RENDERER, | ||
...item, | ||
data: criteriaData, | ||
getValueSetOptions, | ||
searchCode: props.searchCode, | ||
updateData: (newData: T) => { | ||
setCriteriaData({ ...criteriaData, ...newData }) | ||
}, | ||
setError | ||
}} | ||
/> | ||
</CFItemWrapper> | ||
))} | ||
</CFSection> | ||
))} | ||
</CriteriaLayout> | ||
) | ||
} |
57 changes: 57 additions & 0 deletions
57
...mponents/LogicalOperator/components/CriteriaRightPanel/CriteriaForm/legacyFormAdapter.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,57 @@ | ||
import React from 'react' | ||
import { CriteriaDrawerComponentProps, CriteriaItemDataCache } from 'types' | ||
import { CriteriaData, CriteriaDataType } from './types' | ||
import CriteriaForm from '.' | ||
import { CriteriaForm as CriteriaFormDefinition } from './types' | ||
import { LabelObject } from 'types/searchCriterias' | ||
import { CriteriaDataKey, SelectedCriteriaType } from 'types/requestCriterias' | ||
import { fetchValueSet } from 'services/aphp/callApi' | ||
|
||
export type LegacyAdapterProps<T extends CriteriaDataType, U extends SelectedCriteriaType> = { | ||
form: CriteriaFormDefinition<T> | ||
adapter: { | ||
mapFromLegacyDataType: (legacyData: U, criteriaData: CriteriaItemDataCache) => CriteriaData<T> | ||
mapToLegacyDataType: (data: CriteriaData<T>) => Omit<U, 'id'> | ||
valueSetIdToKey: (valueSetId: string) => CriteriaDataKey | undefined | ||
} | ||
} | ||
|
||
/** | ||
* Enable the use of the new CriteriaForm component with the legacy data format | ||
* @param props contains the form definition and the adapter to convert the legacy data to the new data format | ||
* @returns the legacy Drawer component with the new CriteriaForm component | ||
*/ | ||
export default function withLegacyAdapter<T extends CriteriaDataType, U extends SelectedCriteriaType>( | ||
props: LegacyAdapterProps<T, U> | ||
) { | ||
return (legacyProps: CriteriaDrawerComponentProps) => { | ||
const { criteriaData, goBack, selectedCriteria, onChangeSelectedCriteria } = legacyProps | ||
const runtimeProps = { | ||
data: selectedCriteria | ||
? props.adapter.mapFromLegacyDataType(selectedCriteria as U, criteriaData) | ||
: props.form.initialData, | ||
updateData: (data: CriteriaData<T>) => onChangeSelectedCriteria(props.adapter.mapToLegacyDataType(data) as U), | ||
goBack, | ||
getValueSetOptions: (valueSetId: string) => { | ||
const dataKey = props.adapter.valueSetIdToKey(valueSetId) | ||
if (dataKey === undefined) { | ||
return [] as LabelObject[] | ||
} | ||
return (criteriaData.data[dataKey] as LabelObject[]) || [] | ||
} | ||
} | ||
return ( | ||
<CriteriaForm | ||
{...props.form} | ||
{...runtimeProps} | ||
searchCode={(code: string, codeSystemUrl: string, abortSignal: AbortSignal) => | ||
fetchValueSet( | ||
codeSystemUrl, | ||
{ valueSetTitle: 'Toute la hiérarchie', search: code, noStar: false }, | ||
abortSignal | ||
) | ||
} | ||
/> | ||
) | ||
} | ||
} |
98 changes: 98 additions & 0 deletions
98
...mView/components/LogicalOperator/components/CriteriaRightPanel/CriteriaForm/renderers.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,98 @@ | ||
import React from 'react' | ||
import { CriteriaFormItemView, CriteriaItemType } from './types' | ||
import { CFLabel } from './components' | ||
import CalendarRange from 'components/ui/Inputs/CalendarRange' | ||
import { Autocomplete, TextField } from '@mui/material' | ||
import ExecutiveUnitsInput from 'components/ui/Inputs/ExecutiveUnit' | ||
import OccurenceInput from 'components/ui/Inputs/Occurences' | ||
import SearchbarWithCheck from 'components/ui/Inputs/SearchbarWithCheck' | ||
import AsyncAutocomplete from 'components/ui/Inputs/AsyncAutocomplete' | ||
|
||
const FORM_ITEM_RENDERER: { [key in CriteriaItemType]: CriteriaFormItemView<key> } = { | ||
text: (props) => <TextField label={props.definition.label} />, | ||
duration: (props) => ( | ||
<> | ||
<CalendarRange | ||
inline | ||
label={ | ||
props.definition.label && ( | ||
<CFLabel | ||
label={props.definition.label} | ||
tooltip={props.definition.info} | ||
altStyle={props.definition.labelAltStyle} | ||
/> | ||
) | ||
} | ||
value={!!props.value ? [props.value.start, props.value.end] : [null, null]} | ||
onChange={(range, includeNull) => | ||
props.updateData({ start: range[0] || null, end: range[1] || null, includeNull }) | ||
} | ||
onError={(isError) => props.setError(isError ? props.definition.errorType : undefined)} | ||
includeNullValues={props.value?.includeNull} | ||
onChangeIncludeNullValues={ | ||
props.definition.withOptionIncludeNull | ||
? () => { | ||
/* dummy TODO change CalendarRange to accept a boolean to activate the includeNull checkbox */ | ||
} | ||
: undefined | ||
} | ||
/> | ||
</> | ||
), | ||
autocomplete: (props) => { | ||
return ( | ||
<Autocomplete | ||
multiple | ||
options={props.getValueSetOptions(props.definition.valueSetId)} | ||
noOptionsText={props.definition.noOptionsText} | ||
getOptionLabel={(option) => option.label} | ||
isOptionEqualToValue={(option, value) => option.id === value.id} | ||
value={props.value} | ||
onChange={(e, value) => props.updateData(value)} | ||
renderInput={(params) => <TextField {...params} label={props.definition.label} />} | ||
/> | ||
) | ||
}, | ||
number: (props) => <TextField label={props.definition.label} type="number" />, | ||
executiveUnit: (props) => ( | ||
<ExecutiveUnitsInput | ||
sourceType={props.definition.sourceType} | ||
value={props.value || []} | ||
onChange={(value) => props.updateData(value)} | ||
/> | ||
), | ||
occurrence: (props) => ( | ||
<OccurenceInput | ||
label={props.definition.label} | ||
value={props.value.value} | ||
comparator={props.value.comparator} | ||
onchange={(newCount, newComparator) => { | ||
props.updateData({ value: newCount, comparator: newComparator }) | ||
}} | ||
withHierarchyInfo={props.definition.withHierarchyInfo} | ||
/> | ||
), | ||
boolean: (props) => <TextField label={props.definition.label} type="checkbox" />, | ||
textWithCheck: (props) => ( | ||
<SearchbarWithCheck | ||
searchInput={props.value} | ||
setSearchInput={(value) => props.updateData(value)} | ||
placeholder={props.definition.placeholder} | ||
onError={(isError) => props.setError(isError ? props.definition.errorType : undefined)} | ||
/> | ||
), | ||
codeSearch: (props) => { | ||
return ( | ||
<AsyncAutocomplete | ||
label={props.definition.label || 'Code(s) sélectionné(s)'} | ||
variant="outlined" | ||
noOptionsText={props.definition.noOptionsText} | ||
values={props.value || []} | ||
onFetch={(search, signal) => props.searchCode(search, props.definition.valueSetId, signal)} | ||
onChange={(value) => props.updateData(value)} | ||
/> | ||
) | ||
} | ||
} | ||
|
||
export default FORM_ITEM_RENDERER |
Oops, something went wrong.