diff --git a/src/core_modules/capture-core/components/DataEntries/EnrollmentRegistrationEntry/hooks/useFormValues.js b/src/core_modules/capture-core/components/DataEntries/EnrollmentRegistrationEntry/hooks/useFormValues.js index 1431a10e23..679d973ecb 100644 --- a/src/core_modules/capture-core/components/DataEntries/EnrollmentRegistrationEntry/hooks/useFormValues.js +++ b/src/core_modules/capture-core/components/DataEntries/EnrollmentRegistrationEntry/hooks/useFormValues.js @@ -8,6 +8,7 @@ import type { RenderFoundation } from '../../../../metaData'; import { convertClientToForm, convertServerToClient } from '../../../../converters'; import { subValueGetterByElementType } from './getSubValueForTei'; import type { QuerySingleResource } from '../../../../utils/api/api.types'; +import { dataElementTypes } from '../../../../metaData'; type InputProgramData = { attributes: Array<{ @@ -32,7 +33,7 @@ export type InputAttribute = { displayName: string, lastUpdated: string, value: string, - valueType: string, + valueType: $Keys, }; type InputForm = { @@ -50,7 +51,7 @@ type StaticPatternValues = { const useClientAttributesWithSubvalues = (program: InputProgramData, attributes: Array) => { const dataEngine = useDataEngine(); - const [listAttributes, setListAttributes] = useState([]); + const [listAttributes, setListAttributes] = useState(null); const getListAttributes = useCallback(async () => { if (program && attributes) { @@ -139,8 +140,6 @@ export const useFormValues = ({ program, trackedEntityInstanceAttributes, orgUni const formValuesReadyRef = useRef(false); const [formValues, setFormValues] = useState({}); const [clientValues, setClientValues] = useState({}); - const areAttributesWithSubvaluesReady = - (teiId && clientAttributesWithSubvalues.length > 0) || (!teiId && clientAttributesWithSubvalues.length === 0); useEffect(() => { formValuesReadyRef.current = false; @@ -152,7 +151,7 @@ export const useFormValues = ({ program, trackedEntityInstanceAttributes, orgUni formFoundation && Object.entries(formFoundation).length > 0 && formValuesReadyRef.current === false && - areAttributesWithSubvaluesReady + !!clientAttributesWithSubvalues ) { const staticPatternValues = { orgUnitCode: orgUnit.code }; const querySingleResource = makeQuerySingleResource(dataEngine.query.bind(dataEngine)); @@ -172,7 +171,6 @@ export const useFormValues = ({ program, trackedEntityInstanceAttributes, orgUni clientAttributesWithSubvalues, formValuesReadyRef, orgUnit, - areAttributesWithSubvaluesReady, searchTerms, dataEngine, ]); diff --git a/src/core_modules/capture-core/components/DataEntries/TeiRegistrationEntry/TeiRegistrationEntry.container.js b/src/core_modules/capture-core/components/DataEntries/TeiRegistrationEntry/TeiRegistrationEntry.container.js index 4c3b8badab..7d017181b9 100644 --- a/src/core_modules/capture-core/components/DataEntries/TeiRegistrationEntry/TeiRegistrationEntry.container.js +++ b/src/core_modules/capture-core/components/DataEntries/TeiRegistrationEntry/TeiRegistrationEntry.container.js @@ -11,19 +11,37 @@ import { useFormValuesFromSearchTerms } from './hooks/useFormValuesFromSearchTer import { dataEntryHasChanges } from '../../DataEntry/common/dataEntryHasChanges'; import { useMetadataForRegistrationForm } from '../common/TEIAndEnrollment/useMetadataForRegistrationForm'; import { useBuildTeiPayload } from './hooks/useBuildTeiPayload'; +import type { InputAttribute } from '../EnrollmentRegistrationEntry/hooks/useFormValues'; -const useInitialiseTeiRegistration = (selectedScopeId, dataEntryId, orgUnitId) => { +type Props = { + selectedScopeId: string, + dataEntryId: string, + orgUnitId: string, + inheritedAttributes: ?Array, +} +const useInitialiseTeiRegistration = ({ + selectedScopeId, + dataEntryId, + orgUnitId, + inheritedAttributes, +}: Props) => { const dispatch = useDispatch(); const { scopeType, trackedEntityName } = useScopeInfo(selectedScopeId); const { formId, formFoundation } = useMetadataForRegistrationForm({ selectedScopeId }); - const formValues = useFormValuesFromSearchTerms(); + const formValues = useFormValuesFromSearchTerms({ inheritedAttributes }); const registrationFormReady = !!formId; useEffect(() => { if (registrationFormReady && scopeType === scopeTypes.TRACKED_ENTITY_TYPE) { dispatch( startNewTeiDataEntryInitialisation( - { selectedOrgUnitId: orgUnitId, selectedScopeId, dataEntryId, formFoundation, formValues }, + { + selectedOrgUnitId: orgUnitId, + selectedScopeId, + dataEntryId, + formFoundation, + formValues, + }, )); } }, [ @@ -43,8 +61,20 @@ const useInitialiseTeiRegistration = (selectedScopeId, dataEntryId, orgUnitId) = }; -export const TeiRegistrationEntry: ComponentType = ({ selectedScopeId, id, orgUnitId, onSave, ...rest }) => { - const { trackedEntityName } = useInitialiseTeiRegistration(selectedScopeId, id, orgUnitId); +export const TeiRegistrationEntry: ComponentType = ({ + selectedScopeId, + id, + orgUnitId, + onSave, + inheritedAttributes, + ...rest +}) => { + const { trackedEntityName } = useInitialiseTeiRegistration({ + selectedScopeId, + dataEntryId: id, + orgUnitId, + inheritedAttributes, + }); const ready = useSelector(({ dataEntries }) => (!!dataEntries[id])); const dataEntry = useSelector(({ dataEntries }) => (dataEntries[id])); const { diff --git a/src/core_modules/capture-core/components/DataEntries/TeiRegistrationEntry/TeiRegistrationEntry.types.js b/src/core_modules/capture-core/components/DataEntries/TeiRegistrationEntry/TeiRegistrationEntry.types.js index 43afd9adc8..33f32eabf8 100644 --- a/src/core_modules/capture-core/components/DataEntries/TeiRegistrationEntry/TeiRegistrationEntry.types.js +++ b/src/core_modules/capture-core/components/DataEntries/TeiRegistrationEntry/TeiRegistrationEntry.types.js @@ -6,6 +6,7 @@ import type { ExistingUniqueValueDialogActionsComponent } from '../withErrorMess import type { TeiPayload, } from '../../Pages/common/TEIRelationshipsWidget/RegisterTei/DataEntry/TrackedEntityInstance/dataEntryTrackedEntityInstance.types'; +import type { InputAttribute } from '../EnrollmentRegistrationEntry/hooks/useFormValues'; export type OwnProps = $ReadOnly<{| id: string, @@ -16,6 +17,7 @@ export type OwnProps = $ReadOnly<{| onSave: (TeiPayload) => void, duplicatesReviewPageSize: number, isSavingInProgress?: boolean, + inheritedAttributes?: Array, renderDuplicatesCardActions?: RenderCustomCardActions, renderDuplicatesDialogActions?: (onCancel: () => void, onSave: (TeiPayload) => void) => Node, ExistingUniqueValueDialogActions: ExistingUniqueValueDialogActionsComponent, diff --git a/src/core_modules/capture-core/components/DataEntries/TeiRegistrationEntry/hooks/useFormValuesFromSearchTerms.js b/src/core_modules/capture-core/components/DataEntries/TeiRegistrationEntry/hooks/useFormValuesFromSearchTerms.js index 87bdf7fa98..42c6fbff54 100644 --- a/src/core_modules/capture-core/components/DataEntries/TeiRegistrationEntry/hooks/useFormValuesFromSearchTerms.js +++ b/src/core_modules/capture-core/components/DataEntries/TeiRegistrationEntry/hooks/useFormValuesFromSearchTerms.js @@ -1,19 +1,32 @@ // @flow -import { useEffect, useState } from 'react'; +import { useMemo } from 'react'; import { useSelector } from 'react-redux'; import { convertClientToForm } from '../../../../converters'; +import type { InputAttribute } from '../../EnrollmentRegistrationEntry/hooks/useFormValues'; +type Props = { + inheritedAttributes: ?Array, +}; -export const useFormValuesFromSearchTerms = () => { +export const useFormValuesFromSearchTerms = ({ inheritedAttributes }: Props) => { const searchTerms = useSelector(({ searchDomain }) => searchDomain.currentSearchInfo.currentSearchTerms); - const [formValues, setFormValues] = useState(); - useEffect(() => { + + return useMemo(() => { + if (inheritedAttributes) { + return inheritedAttributes + ?.reduce((acc, item) => { + acc[item.attribute] = convertClientToForm(item.value, item.valueType); + return acc; + }, {}); + } if (searchTerms) { - const searchFormValues = searchTerms - ?.reduce((acc, item) => ({ ...acc, [item.id]: convertClientToForm(item.value, item.type) }), {}); - setFormValues(searchFormValues); + return searchTerms + ?.reduce((acc, item) => { + acc[item.id] = convertClientToForm(item.value, item.type); + return acc; + }, {}); } - }, [searchTerms]); - return formValues; + return null; + }, [inheritedAttributes, searchTerms]); }; diff --git a/src/core_modules/capture-core/components/FormFields/New/Fields/OrgUnitField/SingleOrgUnitSelectField.component.js b/src/core_modules/capture-core/components/FormFields/New/Fields/OrgUnitField/SingleOrgUnitSelectField.component.js index 6c252f087b..7946993a79 100644 --- a/src/core_modules/capture-core/components/FormFields/New/Fields/OrgUnitField/SingleOrgUnitSelectField.component.js +++ b/src/core_modules/capture-core/components/FormFields/New/Fields/OrgUnitField/SingleOrgUnitSelectField.component.js @@ -13,7 +13,7 @@ const getStyles = () => ({ type OrgUnitValue = { id: string, - name: string, + displayName: string, path: string, } @@ -44,7 +44,7 @@ class SingleOrgUnitSelectFieldPlain extends React.Component { const { classes } = this.props; return (
- {selectedOrgUnit.name} + {selectedOrgUnit.displayName}
); } @@ -52,7 +52,7 @@ class SingleOrgUnitSelectFieldPlain extends React.Component { onSelectOrgUnit = (orgUnit: Object) => { this.props.onBlur({ id: orgUnit.id, - name: orgUnit.displayName, + displayName: orgUnit.displayName, path: orgUnit.path, }); } diff --git a/src/core_modules/capture-core/components/Pages/New/NewPage.types.js b/src/core_modules/capture-core/components/Pages/New/NewPage.types.js index 899367152f..f9357422d7 100644 --- a/src/core_modules/capture-core/components/Pages/New/NewPage.types.js +++ b/src/core_modules/capture-core/components/Pages/New/NewPage.types.js @@ -1,5 +1,6 @@ // @flow import { typeof newPageStatuses } from './NewPage.constants'; +import { dataElementTypes } from '../../../metaData'; type ProgramCategories = Array<{|name: string, id: string|}> @@ -10,7 +11,7 @@ type InputAttribute = { displayName: string, lastUpdated: string, value: string, - valueType: string, + valueType: $Keys, }; export type ContainerProps = $ReadOnly<{| diff --git a/src/core_modules/capture-core/components/Pages/New/RegistrationDataEntry/RegistrationDataEntry.types.js b/src/core_modules/capture-core/components/Pages/New/RegistrationDataEntry/RegistrationDataEntry.types.js index 79a07ea96e..22e908fb66 100644 --- a/src/core_modules/capture-core/components/Pages/New/RegistrationDataEntry/RegistrationDataEntry.types.js +++ b/src/core_modules/capture-core/components/Pages/New/RegistrationDataEntry/RegistrationDataEntry.types.js @@ -1,5 +1,7 @@ // @flow +import { dataElementTypes } from '../../../../metaData'; + type InputAttribute = { attribute: string, code: string, @@ -7,7 +9,7 @@ type InputAttribute = { displayName: string, lastUpdated: string, value: string, - valueType: string, + valueType: $Keys, }; export type OwnProps = $ReadOnly<{| diff --git a/src/core_modules/capture-core/components/Pages/common/TEIRelationshipsWidget/RegisterTei/DataEntry/Enrollment/DataEntryEnrollment.component.js b/src/core_modules/capture-core/components/Pages/common/TEIRelationshipsWidget/RegisterTei/DataEntry/Enrollment/DataEntryEnrollment.component.js index 2dbf0c7a20..25b215eed7 100644 --- a/src/core_modules/capture-core/components/Pages/common/TEIRelationshipsWidget/RegisterTei/DataEntry/Enrollment/DataEntryEnrollment.component.js +++ b/src/core_modules/capture-core/components/Pages/common/TEIRelationshipsWidget/RegisterTei/DataEntry/Enrollment/DataEntryEnrollment.component.js @@ -12,6 +12,7 @@ const NewEnrollmentRelationshipPlain = theme, onSave, programId, + inheritedAttributes, orgUnitId, duplicatesReviewPageSize, renderDuplicatesDialogActions, @@ -35,6 +36,7 @@ const NewEnrollmentRelationshipPlain = renderDuplicatesDialogActions={renderDuplicatesDialogActions} renderDuplicatesCardActions={renderDuplicatesCardActions} ExistingUniqueValueDialogActions={ExistingUniqueValueDialogActions} + trackedEntityInstanceAttributes={inheritedAttributes} /> ); }; diff --git a/src/core_modules/capture-core/components/Pages/common/TEIRelationshipsWidget/RegisterTei/DataEntry/Enrollment/dataEntryEnrollment.types.js b/src/core_modules/capture-core/components/Pages/common/TEIRelationshipsWidget/RegisterTei/DataEntry/Enrollment/dataEntryEnrollment.types.js index de3f6cee6f..3b32b17d35 100644 --- a/src/core_modules/capture-core/components/Pages/common/TEIRelationshipsWidget/RegisterTei/DataEntry/Enrollment/dataEntryEnrollment.types.js +++ b/src/core_modules/capture-core/components/Pages/common/TEIRelationshipsWidget/RegisterTei/DataEntry/Enrollment/dataEntryEnrollment.types.js @@ -6,11 +6,13 @@ import type { SaveForEnrollmentAndTeiRegistration, ExistingUniqueValueDialogActionsComponent, } from '../../../../../../DataEntries'; +import type { InputAttribute } from '../../../../../../DataEntries/EnrollmentRegistrationEntry/hooks/useFormValues'; export type Props = {| theme: Theme, programId: string, orgUnitId: string, + inheritedAttributes: Array, enrollmentMetadata?: Enrollment, onSave: SaveForEnrollmentAndTeiRegistration, duplicatesReviewPageSize: number, diff --git a/src/core_modules/capture-core/components/Pages/common/TEIRelationshipsWidget/RegisterTei/DataEntry/RegisterTeiDataEntry.component.js b/src/core_modules/capture-core/components/Pages/common/TEIRelationshipsWidget/RegisterTei/DataEntry/RegisterTeiDataEntry.component.js index 292a1d1530..940aa904fd 100644 --- a/src/core_modules/capture-core/components/Pages/common/TEIRelationshipsWidget/RegisterTei/DataEntry/RegisterTeiDataEntry.component.js +++ b/src/core_modules/capture-core/components/Pages/common/TEIRelationshipsWidget/RegisterTei/DataEntry/RegisterTeiDataEntry.component.js @@ -12,7 +12,13 @@ type Props = { export class RegisterTeiDataEntryComponent extends React.Component { render() { - const { showDataEntry, programId, onSaveWithoutEnrollment, onSaveWithEnrollment, ...passOnProps } = this.props; + const { + showDataEntry, + programId, + onSaveWithoutEnrollment, + onSaveWithEnrollment, + ...passOnProps + } = this.props; if (!showDataEntry) { return null; diff --git a/src/core_modules/capture-core/components/Pages/common/TEIRelationshipsWidget/RegisterTei/DataEntry/TrackedEntityInstance/DataEntryTrackedEntityInstance.js b/src/core_modules/capture-core/components/Pages/common/TEIRelationshipsWidget/RegisterTei/DataEntry/TrackedEntityInstance/DataEntryTrackedEntityInstance.js index c455e3616d..20579fc2db 100644 --- a/src/core_modules/capture-core/components/Pages/common/TEIRelationshipsWidget/RegisterTei/DataEntry/TrackedEntityInstance/DataEntryTrackedEntityInstance.js +++ b/src/core_modules/capture-core/components/Pages/common/TEIRelationshipsWidget/RegisterTei/DataEntry/TrackedEntityInstance/DataEntryTrackedEntityInstance.js @@ -14,6 +14,7 @@ const RelationshipTrackedEntityInstancePlain = theme, onSave, trackedEntityTypeId, + inheritedAttributes, duplicatesReviewPageSize, renderDuplicatesDialogActions, renderDuplicatesCardActions, @@ -36,6 +37,7 @@ const RelationshipTrackedEntityInstancePlain = orgUnitId={orgUnitId} teiRegistrationMetadata={teiRegistrationMetadata} selectedScopeId={teiRegistrationMetadata.form.id} + inheritedAttributes={inheritedAttributes} saveButtonText={i18n.t('Save new {{trackedEntityTypeName}} and link', { trackedEntityTypeName: trackedEntityTypeNameLC, interpolation: { escapeValue: false }, })} diff --git a/src/core_modules/capture-core/components/Pages/common/TEIRelationshipsWidget/RegisterTei/DataEntry/TrackedEntityInstance/dataEntryTrackedEntityInstance.types.js b/src/core_modules/capture-core/components/Pages/common/TEIRelationshipsWidget/RegisterTei/DataEntry/TrackedEntityInstance/dataEntryTrackedEntityInstance.types.js index b4f9617052..4fcec10567 100644 --- a/src/core_modules/capture-core/components/Pages/common/TEIRelationshipsWidget/RegisterTei/DataEntry/TrackedEntityInstance/dataEntryTrackedEntityInstance.types.js +++ b/src/core_modules/capture-core/components/Pages/common/TEIRelationshipsWidget/RegisterTei/DataEntry/TrackedEntityInstance/dataEntryTrackedEntityInstance.types.js @@ -5,6 +5,7 @@ import type { RenderCustomCardActions } from '../../../../../../CardList'; import type { ExistingUniqueValueDialogActionsComponent, } from '../../../../../../DataEntries'; +import type { InputAttribute } from '../../../../../../DataEntries/EnrollmentRegistrationEntry/hooks/useFormValues'; export type TeiPayload = {| trackedEntity: string, @@ -23,6 +24,7 @@ export type Props = {| trackedEntityTypeId: string, onSave: TeiPayload => void, teiRegistrationMetadata?: TeiRegistration, + inheritedAttributes: Array, duplicatesReviewPageSize: number, renderDuplicatesCardActions?: RenderCustomCardActions, renderDuplicatesDialogActions?: (onCancel: () => void, onSave: (TeiPayload) => void) => Node, diff --git a/src/core_modules/capture-core/components/Pages/common/TEIRelationshipsWidget/RegisterTei/RegisterTei.component.js b/src/core_modules/capture-core/components/Pages/common/TEIRelationshipsWidget/RegisterTei/RegisterTei.component.js index 9a9a7070af..c22abb0c0e 100644 --- a/src/core_modules/capture-core/components/Pages/common/TEIRelationshipsWidget/RegisterTei/RegisterTei.component.js +++ b/src/core_modules/capture-core/components/Pages/common/TEIRelationshipsWidget/RegisterTei/RegisterTei.component.js @@ -64,6 +64,7 @@ const RegisterTeiPlain = ({ trackedEntityName, trackedEntityTypeId, selectedScopeId, + inheritedAttributes, classes, }: ComponentProps) => { const { resultsPageSize } = useContext(ResultsPageSizeContext); @@ -110,6 +111,7 @@ const RegisterTeiPlain = ({ renderDuplicatesDialogActions={renderDuplicatesDialogActions} renderDuplicatesCardActions={renderDuplicatesCardActions} ExistingUniqueValueDialogActions={ExistingUniqueValueDialogActions} + inheritedAttributes={inheritedAttributes} /> { @@ -16,6 +18,15 @@ export const RegisterTei = ({ const error = useSelector(({ newRelationshipRegisterTei }) => (newRelationshipRegisterTei.error)); const selectedScopeId = suggestedProgramId || trackedEntityTypeId; const { trackedEntityName } = useScopeInfo(selectedScopeId); + const { inheritedAttributes, isLoading: isLoadingAttributes } = useInheritedAttributeValues({ + teiId, + trackedEntityTypeId, + programId: suggestedProgramId, + }); + + if (isLoadingAttributes) { + return null; + } return ( ); }; diff --git a/src/core_modules/capture-core/components/Pages/common/TEIRelationshipsWidget/RegisterTei/RegisterTei.types.js b/src/core_modules/capture-core/components/Pages/common/TEIRelationshipsWidget/RegisterTei/RegisterTei.types.js index 0de2b570ba..dea706722b 100644 --- a/src/core_modules/capture-core/components/Pages/common/TEIRelationshipsWidget/RegisterTei/RegisterTei.types.js +++ b/src/core_modules/capture-core/components/Pages/common/TEIRelationshipsWidget/RegisterTei/RegisterTei.types.js @@ -1,4 +1,6 @@ // @flow +import type { InputAttribute } from '../../../../DataEntries/EnrollmentRegistrationEntry/hooks/useFormValues'; + export type SharedProps = {| onLink: (teiId: string, values: Object) => void, onGetUnsavedAttributeValues?: ?Function, @@ -7,6 +9,7 @@ export type SharedProps = {| export type ContainerProps = {| suggestedProgramId: string, + teiId: string, onSave: (teiPayload: Object) => void, ...SharedProps, |}; @@ -16,6 +19,7 @@ export type ComponentProps = {| error: string, dataEntryId: string, trackedEntityName: ?string, + inheritedAttributes: Array, onSaveWithEnrollment: () => void, onSaveWithoutEnrollment: () => void, ...SharedProps, diff --git a/src/core_modules/capture-core/components/Pages/common/TEIRelationshipsWidget/TrackedEntityRelationshipsWrapper/TrackedEntityRelationshipsWrapper.component.js b/src/core_modules/capture-core/components/Pages/common/TEIRelationshipsWidget/TrackedEntityRelationshipsWrapper/TrackedEntityRelationshipsWrapper.component.js index df27fb1125..135dafe53f 100644 --- a/src/core_modules/capture-core/components/Pages/common/TEIRelationshipsWidget/TrackedEntityRelationshipsWrapper/TrackedEntityRelationshipsWrapper.component.js +++ b/src/core_modules/capture-core/components/Pages/common/TEIRelationshipsWidget/TrackedEntityRelationshipsWrapper/TrackedEntityRelationshipsWrapper.component.js @@ -76,6 +76,7 @@ export const TrackedEntityRelationshipsWrapper = ({ suggestedProgramId={suggestedProgramId} onLink={onLinkToTrackedEntityFromSearch} onSave={onLinkToTrackedEntityFromRegistration} + teiId={teiId} onGetUnsavedAttributeValues={() => console.log('get unsaved')} trackedEntityTypeId={selectedTrackedEntityTypeId} /> diff --git a/src/core_modules/capture-core/components/Pages/common/TEIRelationshipsWidget/useInheritedAttributeValues.js b/src/core_modules/capture-core/components/Pages/common/TEIRelationshipsWidget/useInheritedAttributeValues.js new file mode 100644 index 0000000000..8c526525dd --- /dev/null +++ b/src/core_modules/capture-core/components/Pages/common/TEIRelationshipsWidget/useInheritedAttributeValues.js @@ -0,0 +1,70 @@ +// @flow +import { useMemo } from 'react'; +import { useSelector } from 'react-redux'; +import type { InputAttribute } from '../../../DataEntries/EnrollmentRegistrationEntry/hooks/useFormValues'; +import { useApiDataQuery } from '../../../../utils/reactQueryHelpers'; +import { + getProgramFromProgramIdThrowIfNotFound, + getTrackedEntityTypeThrowIfNotFound, + TrackerProgram, +} from '../../../../metaData'; + +type Props = { + teiId: string, + trackedEntityTypeId: string, +}; + +type Return = { + inheritedAttributes: Array, + isLoading: boolean, +}; +export const useInheritedAttributeValues = ({ teiId, trackedEntityTypeId }: Props): Return => { + const programId = useSelector(({ newRelationshipRegisterTei }) => newRelationshipRegisterTei.programId); + const inheritedAttributeIds = useMemo(() => { + const attributeIds = new Set(); + + if (programId) { + const program = getProgramFromProgramIdThrowIfNotFound(programId); + if (program instanceof TrackerProgram) { + program.attributes.forEach((attribute) => { + if (attribute.inherit) { + attributeIds.add(attribute.id); + } + }); + } + return attributeIds; + } + + const trackedEntityType = getTrackedEntityTypeThrowIfNotFound(trackedEntityTypeId); + trackedEntityType.attributes.forEach((attribute) => { + if (attribute.inherit) { + attributeIds.add(attribute.id); + } + }); + return attributeIds; + }, [programId, trackedEntityTypeId]); + + + const { data, isLoading } = useApiDataQuery( + ['inheritedAttributeValues', teiId, programId], + { + resource: 'tracker/trackedEntities', + id: teiId, + params: { + fields: ['attributes'], + program: programId, + }, + }, { + enabled: !!teiId, + select: (response) => { + const attributes = response.attributes || []; + return attributes + .filter(attribute => inheritedAttributeIds.has(attribute.attribute)); + }, + }); + + return { + inheritedAttributes: data ?? [], + isLoading, + }; +}; diff --git a/src/core_modules/capture-core/metaData/DataElement/DataElement.js b/src/core_modules/capture-core/metaData/DataElement/DataElement.js index 5555d4842e..78fe1d959a 100644 --- a/src/core_modules/capture-core/metaData/DataElement/DataElement.js +++ b/src/core_modules/capture-core/metaData/DataElement/DataElement.js @@ -35,6 +35,7 @@ export class DataElement { _displayInReports: boolean; _icon: Icon | void; _unique: ?Unique; + _inherit: boolean; _searchable: ?boolean; _url: ?string; _attributeValues: Array @@ -157,6 +158,14 @@ export class DataElement { return this._unique; } + get inherit(): boolean { + return this._inherit; + } + + set inherit(value: boolean) { + this._inherit = value; + } + set searchable(searchable: boolean) { this._searchable = searchable; } diff --git a/src/core_modules/capture-core/metaDataMemoryStoreBuilders/programs/factory/enrollment/DataElementFactory.js b/src/core_modules/capture-core/metaDataMemoryStoreBuilders/programs/factory/enrollment/DataElementFactory.js index 18e56e1869..27d1222735 100644 --- a/src/core_modules/capture-core/metaDataMemoryStoreBuilders/programs/factory/enrollment/DataElementFactory.js +++ b/src/core_modules/capture-core/metaDataMemoryStoreBuilders/programs/factory/enrollment/DataElementFactory.js @@ -164,6 +164,7 @@ export class DataElementFactory { dataElement.compulsory = cachedProgramTrackedEntityAttribute.mandatory; dataElement.code = cachedTrackedEntityAttribute.code; dataElement.attributeValues = cachedTrackedEntityAttribute.attributeValues; + dataElement.inherit = cachedTrackedEntityAttribute.inherit; dataElement.name = this._getAttributeTranslation( cachedTrackedEntityAttribute.translations, diff --git a/src/core_modules/capture-core/metaDataMemoryStoreBuilders/trackedEntityTypes/factory/TrackedEntityType/DataElementFactory.js b/src/core_modules/capture-core/metaDataMemoryStoreBuilders/trackedEntityTypes/factory/TrackedEntityType/DataElementFactory.js index bc27da80ed..723d148d3c 100644 --- a/src/core_modules/capture-core/metaDataMemoryStoreBuilders/trackedEntityTypes/factory/TrackedEntityType/DataElementFactory.js +++ b/src/core_modules/capture-core/metaDataMemoryStoreBuilders/trackedEntityTypes/factory/TrackedEntityType/DataElementFactory.js @@ -112,6 +112,7 @@ export class DataElementFactory { cachedAttribute.translations, DataElementFactory.translationPropertyNames.DESCRIPTION) || cachedAttribute.description; o.displayInForms = true; + o.inherit = cachedAttribute.inherit; o.displayInReports = cachedTrackedEntityTypeAttribute.displayInList; o.disabled = false; o.type = cachedAttribute.valueType; diff --git a/src/core_modules/capture-core/metaDataStoreLoaders/trackedEntityAttributes/quickStoreOperations/storeTrackedEntityAttributes.js b/src/core_modules/capture-core/metaDataStoreLoaders/trackedEntityAttributes/quickStoreOperations/storeTrackedEntityAttributes.js index 8624bb577e..7658ff4a8b 100644 --- a/src/core_modules/capture-core/metaDataStoreLoaders/trackedEntityAttributes/quickStoreOperations/storeTrackedEntityAttributes.js +++ b/src/core_modules/capture-core/metaDataStoreLoaders/trackedEntityAttributes/quickStoreOperations/storeTrackedEntityAttributes.js @@ -7,7 +7,7 @@ export const storeTrackedEntityAttributes = (ids: Array) => { resource: 'trackedEntityAttributes', params: { fields: 'id,displayName,displayShortName,displayFormName,description,valueType,optionSetValue,unique,orgunitScope,' + - 'pattern,code,attributeValues,translations[property,locale,value],optionSet[id]', + 'pattern,code,attributeValues,inherit,translations[property,locale,value],optionSet[id]', filter: `id:in:[${ids.join(',')}]`, pageSize: ids.length, }, diff --git a/src/core_modules/capture-core/storageControllers/cache.types.js b/src/core_modules/capture-core/storageControllers/cache.types.js index 49ce4a64ca..01ba461309 100644 --- a/src/core_modules/capture-core/storageControllers/cache.types.js +++ b/src/core_modules/capture-core/storageControllers/cache.types.js @@ -26,6 +26,7 @@ export type CachedTrackedEntityAttribute = { translations: Array, valueType: string, optionSetValue: boolean, + inherit: boolean, optionSet: { id: string }, unique: ?boolean, orgunitScope: ?boolean, diff --git a/src/core_modules/capture-core/utils/reactQueryHelpers/query/useApiDataQuery.js b/src/core_modules/capture-core/utils/reactQueryHelpers/query/useApiDataQuery.js index 8505d4aaff..44b0ba996f 100644 --- a/src/core_modules/capture-core/utils/reactQueryHelpers/query/useApiDataQuery.js +++ b/src/core_modules/capture-core/utils/reactQueryHelpers/query/useApiDataQuery.js @@ -6,7 +6,7 @@ import type { Result } from './useMetadataQuery.types'; import { ReactQueryAppNamespace } from '../reactQueryHelpers.const'; export const useApiDataQuery = ( - queryKey: Array, + queryKey: Array, queryObject: ResourceQuery, queryOptions: UseQueryOptions, ): Result => {