diff --git a/CHANGELOG.md b/CHANGELOG.md index c029841c2f..4315d38cf1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,17 @@ +# [101.23.0](https://github.com/dhis2/capture-app/compare/v101.22.0...v101.23.0) (2025-01-24) + + +### Features + +* [DHIS2-18325] Show orgunit selector in the new event form ([#3879](https://github.com/dhis2/capture-app/issues/3879)) ([f07b4d4](https://github.com/dhis2/capture-app/commit/f07b4d47c219a21db2769cdc525135aa007ffe96)) + +# [101.22.0](https://github.com/dhis2/capture-app/compare/v101.21.6...v101.22.0) (2025-01-24) + + +### Features + +* [DHIS2-17192] show related stages widget on registration page ([#3880](https://github.com/dhis2/capture-app/issues/3880)) ([03c156a](https://github.com/dhis2/capture-app/commit/03c156a8aa19708c5fc40140aa390ef547e18d25)) + ## [101.21.6](https://github.com/dhis2/capture-app/compare/v101.21.5...v101.21.6) (2025-01-16) diff --git a/cypress/e2e/ScopeSelector/ScopeSelector.feature b/cypress/e2e/ScopeSelector/ScopeSelector.feature index 5a06714422..5a6d4f0b83 100644 --- a/cypress/e2e/ScopeSelector/ScopeSelector.feature +++ b/cypress/e2e/ScopeSelector/ScopeSelector.feature @@ -221,11 +221,6 @@ Feature: User uses the ScopeSelector to navigate When you reset the program selection Then you see message explaining you need to select a program - Scenario: Enrollment event new page > resetting the org unit - Given you land on a enrollment page domain by having typed /#/enrollmentEventNew?programId=IpHINAT79UW&orgUnitId=UgYg0YW7ZIh&teiId=fhFQhO0xILJ&enrollmentId=gPDueU02tn8&stageId=A03MvHHogjR - When you reset the org unit selection - Then you see the enrollment event New page but there is no org unit id in the url - Scenario: Enrollment event new page > resetting the enrollment Given you land on a enrollment page domain by having typed /#/enrollmentEventNew?programId=IpHINAT79UW&orgUnitId=UgYg0YW7ZIh&teiId=fhFQhO0xILJ&enrollmentId=gPDueU02tn8&stageId=A03MvHHogjR When you reset the enrollment selection diff --git a/cypress/e2e/ScopeSelector/ScopeSelector.js b/cypress/e2e/ScopeSelector/ScopeSelector.js index 65bd9930f3..79b9e21065 100644 --- a/cypress/e2e/ScopeSelector/ScopeSelector.js +++ b/cypress/e2e/ScopeSelector/ScopeSelector.js @@ -290,11 +290,6 @@ And('you see the enrollment event Edit page but there is no org unit id in the u cy.get('[data-test="widget-enrollment-event-view"]').should('exist'); }); -And('you see the enrollment event New page but there is no org unit id in the url', () => { - cy.url().should('eq', `${Cypress.config().baseUrl}/#/enrollmentEventNew?enrollmentId=gPDueU02tn8&programId=IpHINAT79UW&stageId=A03MvHHogjR&teiId=fhFQhO0xILJ`); - cy.contains('Choose an organisation unit to start reporting'); -}); - And('you see the enrollment event New page but there is no stage id in the url', () => { cy.url().should('eq', `${Cypress.config().baseUrl}/#/enrollmentEventNew?enrollmentId=gPDueU02tn8&orgUnitId=UgYg0YW7ZIh&programId=IpHINAT79UW&teiId=fhFQhO0xILJ`); cy.contains('Choose a stage for a new event'); diff --git a/i18n/en.pot b/i18n/en.pot index 93d8853fb3..c88bba3923 100644 --- a/i18n/en.pot +++ b/i18n/en.pot @@ -5,8 +5,8 @@ msgstr "" "Content-Type: text/plain; charset=utf-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1)\n" -"POT-Creation-Date: 2024-12-15T15:25:38.375Z\n" -"PO-Revision-Date: 2024-12-15T15:25:38.375Z\n" +"POT-Creation-Date: 2025-01-02T13:08:32.303Z\n" +"PO-Revision-Date: 2025-01-02T13:08:32.303Z\n" msgid "Choose one or more dates..." msgstr "Choose one or more dates..." @@ -709,9 +709,6 @@ msgstr "There was an error opening the Page" msgid "There was an error loading the page" msgstr "There was an error loading the page" -msgid "Choose an organisation unit to start reporting" -msgstr "Choose an organisation unit to start reporting" - msgid "Program stage is invalid" msgstr "Program stage is invalid" @@ -768,6 +765,9 @@ msgstr "" "You don't have access to create a {{trackedEntityName}} in the current " "selections" +msgid "Choose an organisation unit to start reporting" +msgstr "Choose an organisation unit to start reporting" + msgid "Choose the {{missingCategories}} to start reporting" msgstr "Choose the {{missingCategories}} to start reporting" @@ -1231,12 +1231,21 @@ msgstr "Add coordinates" msgid "Add area" msgstr "Add area" +msgid "Please add or cancel the note before saving the event" +msgstr "Please add or cancel the note before saving the event" + +msgid "Please provide an valid organisation unit" +msgstr "Please provide an valid organisation unit" + msgid "organisation unit could not be retrieved. Please try again later." msgstr "organisation unit could not be retrieved. Please try again later." msgid "Saving to {{stageName}} for {{programName}} in {{orgUnitName}}" msgstr "Saving to {{stageName}} for {{programName}} in {{orgUnitName}}" +msgid "Saving to {{stageName}} for {{programName}}" +msgstr "Saving to {{stageName}} for {{programName}}" + msgid "program or stage is invalid" msgstr "program or stage is invalid" @@ -1258,9 +1267,6 @@ msgstr "Warning" msgid "stage not found in rules execution" msgstr "stage not found in rules execution" -msgid "Please provide an valid organisation unit" -msgstr "Please provide an valid organisation unit" - msgid "Delete event" msgstr "Delete event" @@ -1313,9 +1319,6 @@ msgid_plural "There are {{count}} scheduled event in {{orgUnitName}} on this day msgstr[0] "There are {{count}} scheduled event in {{orgUnitName}} on this day." msgstr[1] "There are {{count}} scheduled events in {{orgUnitName}} on this day." -msgid "Scheduling an event in {{stageName}} for {{programName}} in {{orgUnitName}}" -msgstr "Scheduling an event in {{stageName}} for {{programName}} in {{orgUnitName}}" - msgid "Schedule info" msgstr "Schedule info" diff --git a/package.json b/package.json index a9757dddca..ac11f9289d 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "capture-app", "homepage": ".", - "version": "101.21.6", + "version": "101.23.0", "cacheVersion": "7", "serverVersion": "38", "license": "BSD-3-Clause", @@ -10,7 +10,7 @@ "packages/rules-engine" ], "dependencies": { - "@dhis2/rules-engine-javascript": "101.21.6", + "@dhis2/rules-engine-javascript": "101.23.0", "@dhis2/app-runtime": "^3.9.3", "@dhis2/d2-i18n": "^1.1.0", "@dhis2/d2-icons": "^1.0.1", @@ -115,7 +115,7 @@ "eslint-config-react-app": "^6.0.0", "eslint-friendly-formatter": "^3.0.0", "eslint-import-resolver-exports": "^1.0.0-beta.5", - "eslint-import-resolver-webpack": "^0.13.2", + "eslint-import-resolver-webpack": "^0.13.10", "eslint-plugin-flowtype": "^5.10.0", "eslint-plugin-import": "2.29.1", "eslint-plugin-jsx-a11y": "^5.1.1", diff --git a/packages/rules-engine/package.json b/packages/rules-engine/package.json index 658743899a..01683af635 100644 --- a/packages/rules-engine/package.json +++ b/packages/rules-engine/package.json @@ -1,6 +1,6 @@ { "name": "@dhis2/rules-engine-javascript", - "version": "101.21.6", + "version": "101.23.0", "license": "BSD-3-Clause", "main": "./build/cjs/index.js", "scripts": { diff --git a/packages/rules-engine/src/d2Functions/getD2Functions.types.js b/packages/rules-engine/src/d2Functions/getD2Functions.types.js index cb2fbcd0f5..4bba6395a1 100644 --- a/packages/rules-engine/src/d2Functions/getD2Functions.types.js +++ b/packages/rules-engine/src/d2Functions/getD2Functions.types.js @@ -8,7 +8,7 @@ import type { export type D2FunctionsInput = $ReadOnly<{| dateUtils: IDateUtils, variablesHash: RuleVariables, - selectedOrgUnit: OrgUnit, + selectedOrgUnit: ?OrgUnit, selectedUserRoles: Array, |}>; diff --git a/packages/rules-engine/src/rulesEngine.types.js b/packages/rules-engine/src/rulesEngine.types.js index 5d3d5bbf47..fd25b9e251 100644 --- a/packages/rules-engine/src/rulesEngine.types.js +++ b/packages/rules-engine/src/rulesEngine.types.js @@ -156,7 +156,7 @@ export type RulesEngineInput = {| selectedEntity?: ?TEIValues, trackedEntityAttributes?: ?TrackedEntityAttributes, selectedEnrollment?: ?Enrollment, - selectedOrgUnit: OrgUnit, + selectedOrgUnit: ?OrgUnit, selectedUserRoles?: ?Array, optionSets: OptionSets, |} diff --git a/packages/rules-engine/src/services/VariableService/VariableService.js b/packages/rules-engine/src/services/VariableService/VariableService.js index 9b596a8190..4e2ef49c8c 100644 --- a/packages/rules-engine/src/services/VariableService/VariableService.js +++ b/packages/rules-engine/src/services/VariableService/VariableService.js @@ -37,7 +37,7 @@ type SourceData = { selectedEntity: ?TEIValues, selectedEnrollment: ?Enrollment, optionSets: OptionSets, - selectedOrgUnit: OrgUnit, + selectedOrgUnit: ?OrgUnit, }; const variableSourceTypesDataElementSpecific = { @@ -516,7 +516,7 @@ export class VariableService { return variables; } - getOrganisationContextVariables(orgUnit: OrgUnit) { + getOrganisationContextVariables(orgUnit: ?OrgUnit) { const variables = {}; variables.orgunit_code = this.buildContextVariable(orgUnit?.code, typeKeys.TEXT); return variables; diff --git a/packages/rules-engine/src/services/VariableService/variableService.types.js b/packages/rules-engine/src/services/VariableService/variableService.types.js index 2977933c29..01e1810ff0 100644 --- a/packages/rules-engine/src/services/VariableService/variableService.types.js +++ b/packages/rules-engine/src/services/VariableService/variableService.types.js @@ -85,7 +85,7 @@ export type VariableServiceInput = {| selectedEntity: ?TEIValues, trackedEntityAttributes: ?TrackedEntityAttributes, selectedEnrollment: ?Enrollment, - selectedOrgUnit: OrgUnit, + selectedOrgUnit: ?OrgUnit, optionSets: OptionSets, constants: ?Constants, |}; diff --git a/src/core_modules/capture-core/components/DataEntries/Enrollment/EnrollmentDataEntry.component.js b/src/core_modules/capture-core/components/DataEntries/Enrollment/EnrollmentDataEntry.component.js index 18a20c37c4..7f136ed6fb 100644 --- a/src/core_modules/capture-core/components/DataEntries/Enrollment/EnrollmentDataEntry.component.js +++ b/src/core_modules/capture-core/components/DataEntries/Enrollment/EnrollmentDataEntry.component.js @@ -238,7 +238,7 @@ const getGeometrySettings = () => ({ dialogLabel: i18n.t('Area'), required: false, orientation: getOrientation(props.formHorizontal), - orgUnit: props.orgUnit, + orgUnitId: props.orgUnit?.id, }); } @@ -249,7 +249,7 @@ const getGeometrySettings = () => ({ required: false, orientation: getOrientation(props.formHorizontal), shrinkDisabled: props.formHorizontal, - orgUnit: props.orgUnit, + orgUnitId: props.orgUnit?.id, }); }, getPropName: () => 'geometry', @@ -330,6 +330,7 @@ type FinalTeiDataEntryProps = { programId: string, id: string, orgUnitId: string, + orgUnit: OrgUnit, onUpdateDataEntryField: Function, onUpdateFormFieldAsync: Function, onUpdateFormField: Function, @@ -459,6 +460,7 @@ export class EnrollmentDataEntryComponent extends React.Component ); diff --git a/src/core_modules/capture-core/components/DataEntries/Enrollment/EnrollmentWithFirstStageDataEntry/EnrollmentWithFirstStageDataEntry.component.js b/src/core_modules/capture-core/components/DataEntries/Enrollment/EnrollmentWithFirstStageDataEntry/EnrollmentWithFirstStageDataEntry.component.js index cff88329d0..c085023578 100644 --- a/src/core_modules/capture-core/components/DataEntries/Enrollment/EnrollmentWithFirstStageDataEntry/EnrollmentWithFirstStageDataEntry.component.js +++ b/src/core_modules/capture-core/components/DataEntries/Enrollment/EnrollmentWithFirstStageDataEntry/EnrollmentWithFirstStageDataEntry.component.js @@ -128,7 +128,7 @@ const getStageGeometrySettings = () => ({ dialogLabel: i18n.t('Area'), required: false, orientation: getOrientation(props.formHorizontal), - orgUnit: props.orgUnit, + orgUnitId: props.orgUnit?.id, }); } @@ -139,7 +139,7 @@ const getStageGeometrySettings = () => ({ required: false, orientation: getOrientation(props.formHorizontal), shrinkDisabled: props.formHorizontal, - orgUnit: props.orgUnit, + orgUnitId: props.orgUnit?.id, }); }, getPropName: () => stageMainDataIds.GEOMETRY, diff --git a/src/core_modules/capture-core/components/DataEntries/Enrollment/EnrollmentWithFirstStageDataEntry/EnrollmentWithFirstStageDataEntry.container.js b/src/core_modules/capture-core/components/DataEntries/Enrollment/EnrollmentWithFirstStageDataEntry/EnrollmentWithFirstStageDataEntry.container.js index dcce7692a4..21a3346d82 100644 --- a/src/core_modules/capture-core/components/DataEntries/Enrollment/EnrollmentWithFirstStageDataEntry/EnrollmentWithFirstStageDataEntry.container.js +++ b/src/core_modules/capture-core/components/DataEntries/Enrollment/EnrollmentWithFirstStageDataEntry/EnrollmentWithFirstStageDataEntry.container.js @@ -10,7 +10,7 @@ const getSectionId = sectionId => (sectionId === Section.MAIN_SECTION_ID ? `${Section.MAIN_SECTION_ID}-stage` : sectionId); export const EnrollmentWithFirstStageDataEntry = (props: Props) => { - const { firstStageMetaData, relatedStageRef, relatedStageActionsOptions, ...passOnProps } = props; + const { firstStageMetaData, orgUnit, relatedStageRef, relatedStageActionsOptions, ...passOnProps } = props; const { stage: { stageForm: firstStageFormFoundation, name: stageName }, } = firstStageMetaData; @@ -23,6 +23,8 @@ export const EnrollmentWithFirstStageDataEntry = (props: Props) => { <> diff --git a/src/core_modules/capture-core/components/DataEntries/Enrollment/EnrollmentWithFirstStageDataEntry/EnrollmentWithFirstStageDataEntry.types.js b/src/core_modules/capture-core/components/DataEntries/Enrollment/EnrollmentWithFirstStageDataEntry/EnrollmentWithFirstStageDataEntry.types.js index 135a01646b..b888f267a6 100644 --- a/src/core_modules/capture-core/components/DataEntries/Enrollment/EnrollmentWithFirstStageDataEntry/EnrollmentWithFirstStageDataEntry.types.js +++ b/src/core_modules/capture-core/components/DataEntries/Enrollment/EnrollmentWithFirstStageDataEntry/EnrollmentWithFirstStageDataEntry.types.js @@ -1,4 +1,5 @@ // @flow +import type { OrgUnit } from '@dhis2/rules-engine-javascript'; import type { ProgramStage, RenderFoundation } from '../../../../metaData'; import type { RelatedStageRefPayload } from '../../../WidgetRelatedStages'; import { relatedStageActions } from '../../../WidgetRelatedStages'; @@ -8,6 +9,7 @@ export type Props = { stage: ProgramStage, }, formFoundation: RenderFoundation, + orgUnit: ?OrgUnit, programId: string, relatedStageRef?: { current: ?RelatedStageRefPayload }, relatedStageActionsOptions?: { diff --git a/src/core_modules/capture-core/components/DataEntries/SingleEventRegistrationEntry/DataEntryWrapper/DataEntry/DataEntry.component.js b/src/core_modules/capture-core/components/DataEntries/SingleEventRegistrationEntry/DataEntryWrapper/DataEntry/DataEntry.component.js index 3743fa5dc4..546aca4224 100644 --- a/src/core_modules/capture-core/components/DataEntries/SingleEventRegistrationEntry/DataEntryWrapper/DataEntry/DataEntry.component.js +++ b/src/core_modules/capture-core/components/DataEntries/SingleEventRegistrationEntry/DataEntryWrapper/DataEntry/DataEntry.component.js @@ -236,7 +236,7 @@ const buildGeometrySettingsFn = () => ({ dialogLabel: i18n.t('Area'), required: false, orientation: getOrientation(props.formHorizontal), - orgUnit: props.orgUnit, + orgUnitId: props.orgUnit?.id, }); } @@ -247,7 +247,7 @@ const buildGeometrySettingsFn = () => ({ required: false, orientation: getOrientation(props.formHorizontal), shrinkDisabled: props.formHorizontal, - orgUnit: props.orgUnit, + orgUnitId: props.orgUnit?.id, }); }, getPropName: () => 'geometry', @@ -637,6 +637,7 @@ class NewEventDataEntry extends Component { dataEntrySections={this.dataEntrySections} relationshipsRef={this.setRelationshipsInstance} orgUnit={orgUnit} + orgUnitId={orgUnit?.id} {...passOnProps} /> diff --git a/src/core_modules/capture-core/components/DataEntry/index.js b/src/core_modules/capture-core/components/DataEntry/index.js index 97ce464d1a..b27e7eb6c8 100644 --- a/src/core_modules/capture-core/components/DataEntry/index.js +++ b/src/core_modules/capture-core/components/DataEntry/index.js @@ -30,4 +30,5 @@ export { } from './actions/dataEntry.actions'; export { actionTypes as loadNewActionTypes } from './actions/dataEntryLoadNew.actions'; export { actionTypes as loadEditActionTypes, cleanUpDataEntry } from './actions/dataEntry.actions'; +export { getDataEntryKey } from './common/getDataEntryKey'; diff --git a/src/core_modules/capture-core/components/FormFields/New/HOC/withCenterPoint.js b/src/core_modules/capture-core/components/FormFields/New/HOC/withCenterPoint.js index 0ac9861d47..a702ea22b5 100644 --- a/src/core_modules/capture-core/components/FormFields/New/HOC/withCenterPoint.js +++ b/src/core_modules/capture-core/components/FormFields/New/HOC/withCenterPoint.js @@ -1,56 +1,115 @@ // @flow -import React, { type ComponentType, useMemo, useState } from 'react'; +import React, { type ComponentType, useMemo, useState, useEffect } from 'react'; +import { ceil } from 'lodash'; import { useApiMetadataQuery } from 'capture-core/utils/reactQueryHelpers'; +type Props = { + orgUnitId: ?string, +}; + const DEFAULT_CENTER = [51.505, -0.09]; const convertToClientCoordinates = ({ coordinates, type }: { coordinates: any[], type: string }) => { switch (type) { case 'Point': return [coordinates[1], coordinates[0]]; - case 'Polygon': - return coordinates[0][0]; + case 'Polygon': { + // Calculate a center point by finding the min and max values for longitude and latitude + // and getting the mean of those values + const { minLatitude, maxLatitude, minLongitude, maxLongitude } = coordinates[0] + .reduce((accExtremes, [iLongitude, iLatitude]) => { + if (iLatitude > accExtremes.maxLatitude) { + accExtremes.maxLatitude = iLatitude; + } else if (iLatitude < accExtremes.minLatitude) { + accExtremes.minLatitude = iLatitude; + } + + if (iLongitude > accExtremes.maxLongitude) { + accExtremes.maxLongitude = iLongitude; + } else if (iLongitude < accExtremes.minLongitude) { + accExtremes.minLongitude = iLongitude; + } + + return accExtremes; + }, { + minLatitude: coordinates[0][0][1], + maxLatitude: coordinates[0][0][1], + minLongitude: coordinates[0][0][0], + maxLongitude: coordinates[0][0][0], + }); + + const latitude = ceil((maxLatitude + minLatitude) / 2, 6); + const longitude = ceil((maxLongitude + minLongitude) / 2, 6); + + return [latitude, longitude]; + } default: return DEFAULT_CENTER; } }; -const getCenterPoint = (InnerComponent: ComponentType) => (props: Object) => { - const { orgUnit, ...passOnProps } = props; - const [orgUnitKey, setOrgUnitKey] = useState(orgUnit.id); - const [shouldFetch, setShouldFetch] = useState(false); - const queryKey = ['organisationUnit', 'geometry', orgUnitKey]; +const getCenterPoint = (InnerComponent: ComponentType) => ({ orgUnitId, ...passOnProps }: Props) => { + const [orgUnitFetchId, setOrgUnitFetchId] = useState(orgUnitId); + const [fetchEnabled, setFetchEnabled] = useState(false); + + useEffect(() => { + setOrgUnitFetchId(orgUnitId); + }, [orgUnitId]); + + const queryKey = ['organisationUnit', 'geometry', orgUnitFetchId]; const queryFn = { resource: 'organisationUnits', - id: () => orgUnitKey, + id: () => orgUnitFetchId, params: { fields: 'geometry,parent', }, }; const queryOptions = useMemo( - () => ({ enabled: Boolean(orgUnit.id) && shouldFetch }), - [shouldFetch, orgUnit.id], + () => ({ enabled: Boolean(orgUnitFetchId) && fetchEnabled }), + [fetchEnabled, orgUnitFetchId], ); + + // $FlowFixMe When the query is disabled, the prerequisites for the queryKey and the queryFn are not met. const { data } = useApiMetadataQuery(queryKey, queryFn, queryOptions); + useEffect(() => { + if (data?.parent && !data?.geometry) { + setOrgUnitFetchId(data.parent.id); + } + }, [data]); + const center = useMemo(() => { + if (!orgUnitFetchId) { + return DEFAULT_CENTER; + } if (data) { - const { geometry, parent } = data; - if (geometry) { - return convertToClientCoordinates(geometry); - } else if (parent?.id) { - setOrgUnitKey(parent.id); + if (data.geometry) { + return convertToClientCoordinates(data.geometry); + } + if (data.parent) { + return null; } return DEFAULT_CENTER; } - return undefined; - }, [data]); + return null; + }, [data, orgUnitFetchId]); const onOpenMap = (hasValue) => { - setShouldFetch(!hasValue); + setFetchEnabled(!hasValue); }; - return ; + const onCloseMap = () => { + setFetchEnabled(false); + }; + + return ( + + ); }; export const withCenterPoint = () => (InnerComponent: ComponentType) => getCenterPoint(InnerComponent); diff --git a/src/core_modules/capture-core/components/Pages/EnrollmentAddEvent/EnrollmentAddEventPageDefault/EnrollmentAddEventPageDefault.component.js b/src/core_modules/capture-core/components/Pages/EnrollmentAddEvent/EnrollmentAddEventPageDefault/EnrollmentAddEventPageDefault.component.js index 01fc09eae1..1e3b7b907a 100644 --- a/src/core_modules/capture-core/components/Pages/EnrollmentAddEvent/EnrollmentAddEventPageDefault/EnrollmentAddEventPageDefault.component.js +++ b/src/core_modules/capture-core/components/Pages/EnrollmentAddEvent/EnrollmentAddEventPageDefault/EnrollmentAddEventPageDefault.component.js @@ -4,7 +4,6 @@ import i18n from '@dhis2/d2-i18n'; import { spacersNum } from '@dhis2/ui'; import withStyles from '@material-ui/core/styles/withStyles'; import type { Props } from './EnrollmentAddEventPageDefault.types'; -import { IncompleteSelectionsMessage } from '../../../IncompleteSelectionsMessage'; import { EnrollmentPageLayout } from '../../common/EnrollmentOverviewDomain/EnrollmentPageLayout'; import { EnrollmentPageKeys, @@ -65,14 +64,6 @@ const EnrollmentAddEventPagePain = ({ ); } - if (!orgUnitId) { - return ( - - {i18n.t('Choose an organisation unit to start reporting')} - - ); - } - if (!ready) { return null; } diff --git a/src/core_modules/capture-core/components/Pages/EnrollmentAddEvent/TopBar/TopBar.component.js b/src/core_modules/capture-core/components/Pages/EnrollmentAddEvent/TopBar/TopBar.component.js index a6dc11d89b..059ccf7b66 100644 --- a/src/core_modules/capture-core/components/Pages/EnrollmentAddEvent/TopBar/TopBar.component.js +++ b/src/core_modules/capture-core/components/Pages/EnrollmentAddEvent/TopBar/TopBar.component.js @@ -34,6 +34,7 @@ export const EnrollmentAddEventTopBar = ({ onResetOrgUnitId={() => onResetOrgUnitId()} isUserInteractionInProgress={userInteractionInProgress} onStartAgain={() => reset()} + isReadOnly > { } render() { - const { selectedOrgUnitId, selectedOrgUnit, previousOrgUnitId, onReset, classes } = this.props; + const { selectedOrgUnitId, selectedOrgUnit, previousOrgUnitId, onReset, isReadOnly, classes } = this.props; return ( this.setState({ open })} - onClearSelectionClick={() => onReset()} + onClearSelectionClick={!isReadOnly ? () => onReset() : undefined} + displayOnly={isReadOnly} dataTest="org-unit-selector-container" >
diff --git a/src/core_modules/capture-core/components/ScopeSelector/QuickSelector/QuickSelector.component.js b/src/core_modules/capture-core/components/ScopeSelector/QuickSelector/QuickSelector.component.js index bb713b6d3b..fb50a1a350 100644 --- a/src/core_modules/capture-core/components/ScopeSelector/QuickSelector/QuickSelector.component.js +++ b/src/core_modules/capture-core/components/ScopeSelector/QuickSelector/QuickSelector.component.js @@ -22,6 +22,7 @@ export const QuickSelector = ({ formIsOpen, children, onStartAgain, + isReadOnly, }: Props) => ( {children} diff --git a/src/core_modules/capture-core/components/ScopeSelector/QuickSelector/QuickSelector.types.js b/src/core_modules/capture-core/components/ScopeSelector/QuickSelector/QuickSelector.types.js index 148a0b7bfd..828969cfb0 100644 --- a/src/core_modules/capture-core/components/ScopeSelector/QuickSelector/QuickSelector.types.js +++ b/src/core_modules/capture-core/components/ScopeSelector/QuickSelector/QuickSelector.types.js @@ -17,4 +17,5 @@ export type Props = { onStartAgain: () => void, formIsOpen: boolean, children: Node, + isReadOnly?: boolean, }; diff --git a/src/core_modules/capture-core/components/ScopeSelector/ScopeSelector.component.js b/src/core_modules/capture-core/components/ScopeSelector/ScopeSelector.component.js index 6cce3cefa5..d47daf6c48 100644 --- a/src/core_modules/capture-core/components/ScopeSelector/ScopeSelector.component.js +++ b/src/core_modules/capture-core/components/ScopeSelector/ScopeSelector.component.js @@ -119,6 +119,7 @@ class ScopeSelectorClass extends Component { selectedCategories={this.props.selectedCategories} isUserInteractionInProgress={this.props.isUserInteractionInProgress} formIsOpen={this.props.formIsOpen} + isReadOnly={this.props.isReadOnly} > {this.props.children} diff --git a/src/core_modules/capture-core/components/ScopeSelector/ScopeSelector.container.js b/src/core_modules/capture-core/components/ScopeSelector/ScopeSelector.container.js index 6199295503..1d85ef9825 100644 --- a/src/core_modules/capture-core/components/ScopeSelector/ScopeSelector.container.js +++ b/src/core_modules/capture-core/components/ScopeSelector/ScopeSelector.container.js @@ -31,6 +31,7 @@ export const ScopeSelector: ComponentType = ({ onStartAgain, formIsOpen = false, children, + isReadOnly, }) => { const dispatch = useDispatch(); const [selectedOrgUnit, setSelectedOrgUnit] = useState({ name: undefined, id: selectedOrgUnitId }); @@ -81,6 +82,7 @@ export const ScopeSelector: ComponentType = ({ isUserInteractionInProgress={isUserInteractionInProgress} formIsOpen={formIsOpen} onStartAgain={onStartAgain} + isReadOnly={isReadOnly} ready={ready} > {children} diff --git a/src/core_modules/capture-core/components/ScopeSelector/ScopeSelector.types.js b/src/core_modules/capture-core/components/ScopeSelector/ScopeSelector.types.js index 09faa0ece8..40879e8091 100644 --- a/src/core_modules/capture-core/components/ScopeSelector/ScopeSelector.types.js +++ b/src/core_modules/capture-core/components/ScopeSelector/ScopeSelector.types.js @@ -18,6 +18,7 @@ export type OwnProps = $ReadOnly<{| onStartAgain: () => void, formIsOpen?: boolean, children: Node, + isReadOnly?: boolean, |}> export type PropsFromRedux = $ReadOnly<{| diff --git a/src/core_modules/capture-core/components/WidgetEnrollmentEventNew/DataEntry/DataEntry.component.js b/src/core_modules/capture-core/components/WidgetEnrollmentEventNew/DataEntry/DataEntry.component.js index aa4520ca1c..d8ca9d25cd 100644 --- a/src/core_modules/capture-core/components/WidgetEnrollmentEventNew/DataEntry/DataEntry.component.js +++ b/src/core_modules/capture-core/components/WidgetEnrollmentEventNew/DataEntry/DataEntry.component.js @@ -7,9 +7,12 @@ import { DataEntry as DataEntryContainer } from '../../DataEntry/DataEntry.conta import { withDataEntryField } from '../../DataEntry/dataEntryField/withDataEntryField'; import { withDataEntryNotesHandler } from '../../DataEntry/dataEntryNotes/withDataEntryNotesHandler'; import { Notes } from '../../Notes/Notes.component'; -import { getEventDateValidatorContainers } from './fieldValidators/eventDate.validatorContainersGetter'; +import { + getEventDateValidatorContainers, + getOrgUnitValidatorContainers, + getNoteValidatorContainers, +} from './fieldValidators'; import { type RenderFoundation, type ProgramStage } from '../../../metaData'; -import { getNoteValidatorContainers } from './fieldValidators/note.validatorContainersGetter'; import { placements, withCleanUp, @@ -28,9 +31,11 @@ import { withDefaultShouldUpdateInterface, orientations, VirtualizedSelectField, + SingleOrgUnitSelectField, } from '../../FormFields/New'; import { Assignee } from './Assignee'; import { inMemoryFileStore } from '../../DataEntry/file/inMemoryFileStore'; +import { SavingText } from '../SavingText'; import { addEventSaveTypes } from './addEventSaveTypes'; import labelTypeClasses from './dataEntryFieldLabels.module.css'; import { withDataEntryFieldIfApplicable } from '../../DataEntry/dataEntryField/withDataEntryFieldIfApplicable'; @@ -102,7 +107,6 @@ const baseComponentStylesVertical = { }, }; - function defaultFilterProps(props: Object) { const { formHorizontal, fieldOptions, validationError, modified, ...passOnProps } = props; return passOnProps; @@ -161,6 +165,46 @@ const buildReportDateSettingsFn = () => { return reportDateSettings; }; +const buildOrgUnitSettingsFn = () => { + const orgUnitComponent = + withCalculateMessages(overrideMessagePropNames)( + withFocusSaver()( + withDefaultFieldContainer()( + withDefaultShouldUpdateInterface()( + withLabel({ + onGetUseVerticalOrientation: (props: Object) => props.formHorizontal, + onGetCustomFieldLabeClass: (props: Object) => `${props.fieldOptions.fieldLabelMediaBasedClass} ${labelTypeClasses.orgUnitLabel}`, + })( + withDisplayMessages()( + withInternalChangeHandler()( + withFilterProps(defaultFilterProps)(SingleOrgUnitSelectField), + ), + ), + ), + ), + ), + ), + ); + + const orgUnitSettings = { + getComponent: () => orgUnitComponent, + getComponentProps: (props: Object) => createComponentProps(props, { + width: props && props.formHorizontal ? 150 : 350, + label: i18n.t('Organisation unit'), + required: true, + }), + getPropName: () => 'orgUnit', + getValidatorContainers: () => getOrgUnitValidatorContainers(), + getMeta: () => ({ + placement: placements.TOP, + section: dataEntrySectionNames.BASICINFO, + }), + }; + + return orgUnitSettings; +}; + + const pointComponent = withCalculateMessages(overrideMessagePropNames)( withFocusSaver()( withDefaultFieldContainer()( @@ -223,7 +267,7 @@ const buildGeometrySettingsFn = () => ({ dialogLabel: i18n.t('Area'), required: false, orientation: getOrientation(props.formHorizontal), - orgUnit: props.orgUnit, + orgUnitId: props.orgUnitIdFieldValue, }); } @@ -234,7 +278,7 @@ const buildGeometrySettingsFn = () => ({ required: false, orientation: getOrientation(props.formHorizontal), shrinkDisabled: props.formHorizontal, - orgUnit: props.orgUnit, + orgUnitId: props.orgUnitIdFieldValue, }); }, getPropName: () => 'geometry', @@ -284,8 +328,8 @@ const buildAssigneeSettingsFn = () => { withTransformPropName(['onBlur', 'onSet'])( withFocusSaver()( withFilterProps((props: Object) => { - const defaultFiltred = defaultFilterProps(props); - const { validationAttempted, touched, ...passOnProps } = defaultFiltred; + const defaultfiltered = defaultFilterProps(props); + const { validationAttempted, touched, ...passOnProps } = defaultfiltered; return passOnProps; })(Assignee), ), @@ -350,7 +394,14 @@ const getCategoryOptionsSettingsFn = () => { const dataEntryFilterProps = (props: Object) => { - const { stage, onScrollToRelationships, recentlyAddedRelationshipId, relationshipsRef, ...passOnProps } = props; + const { + stage, + onScrollToRelationships, + recentlyAddedRelationshipId, + relationshipsRef, + orgUnitIdFieldValue, + ...passOnProps + } = props; return passOnProps; }; @@ -358,6 +409,7 @@ const WrappedDataEntry = compose( withAOCFieldBuilder({}), withDataEntryFields(getCategoryOptionsSettingsFn()), withDataEntryField(buildReportDateSettingsFn()), + withDataEntryField(buildOrgUnitSettingsFn()), withDataEntryFieldIfApplicable(buildGeometrySettingsFn()), withDataEntryField(buildNotesSettingsFn()), withDataEntryFieldIfApplicable(buildAssigneeSettingsFn()), @@ -365,6 +417,12 @@ const WrappedDataEntry = compose( withFilterProps(dataEntryFilterProps), )(DataEntryContainer); +type OrgUnit = {| + id: string, + name: string, + path: string, +|}; + type Props = { id: string, orgUnitId: string, @@ -388,6 +446,9 @@ type Props = { theme: Theme, formHorizontal: ?boolean, recentlyAddedRelationshipId?: ?string, + placementDomNodeForSavingText?: HTMLElement, + programName: string, + orgUnitFieldValue: ?OrgUnit, }; type DataEntrySection = { placement: $Values, @@ -463,10 +524,16 @@ class DataEntryPlain extends Component { onSetSaveTypes, theme, id, + placementDomNodeForSavingText, + programName, + stage, + orgUnitFieldValue, ...passOnProps } = this.props; + return (
+ {/* the props orgUnit, orgUnitId and selectedOrgUnitId should all be removed from here. See DHIS2-18869 */} {/* $FlowFixMe[cannot-spread-inexact] automated comment */} { fieldOptions={this.fieldOptions} dataEntrySections={this.dataEntrySections} relationshipsRef={this.setRelationshipsInstance} + stage={stage} + orgUnitIdFieldValue={orgUnitFieldValue?.id} + orgUnit={orgUnitFieldValue} + orgUnitId={orgUnitFieldValue?.id} + selectedOrgUnitId={orgUnitFieldValue?.id} {...passOnProps} /> +
); } diff --git a/src/core_modules/capture-core/components/WidgetEnrollmentEventNew/DataEntry/DataEntry.container.js b/src/core_modules/capture-core/components/WidgetEnrollmentEventNew/DataEntry/DataEntry.container.js index aa16f0c93b..1e9811e132 100644 --- a/src/core_modules/capture-core/components/WidgetEnrollmentEventNew/DataEntry/DataEntry.container.js +++ b/src/core_modules/capture-core/components/WidgetEnrollmentEventNew/DataEntry/DataEntry.container.js @@ -4,7 +4,7 @@ import { v4 as uuid } from 'uuid'; import { useDispatch, useSelector } from 'react-redux'; import { batchActions } from 'redux-batched-actions'; import { DataEntryComponent } from './DataEntry.component'; -import { startRunRulesPostUpdateField } from '../../DataEntry'; +import { startRunRulesPostUpdateField, getDataEntryKey } from '../../DataEntry'; import { startAsyncUpdateFieldForNewEvent, executeRulesOnUpdateForNewEvent, @@ -15,9 +15,13 @@ import { import typeof { addEventSaveTypes } from './addEventSaveTypes'; import type { ContainerProps } from './dataEntry.types'; -export const DataEntry = ({ orgUnit, rulesExecutionDependenciesClientFormatted, ...passOnProps }: ContainerProps) => { +export const DataEntry = ({ rulesExecutionDependenciesClientFormatted, id, ...passOnProps }: ContainerProps) => { const dispatch = useDispatch(); - const { orgUnitId, programId } = useSelector(({ currentSelections }) => currentSelections); + const { programId } = useSelector(({ currentSelections }) => currentSelections); + const dataEntryItemId = useSelector(({ dataEntries }) => dataEntries[id] && dataEntries[id].itemId); + const dataEntryKey = getDataEntryKey(id, dataEntryItemId); + const orgUnitFieldValue = useSelector(({ dataEntriesFieldsValue }) => dataEntriesFieldsValue[dataEntryKey].orgUnit); + const onUpdateDataEntryField = useCallback((innerAction: ReduxAction) => { const { dataEntryId, itemId } = innerAction.payload; const uid = uuid(); @@ -25,9 +29,9 @@ export const DataEntry = ({ orgUnit, rulesExecutionDependenciesClientFormatted, dispatch(batchActions([ innerAction, startRunRulesPostUpdateField(dataEntryId, itemId, uid), - executeRulesOnUpdateForNewEvent({ ...innerAction.payload, uid, orgUnit, rulesExecutionDependenciesClientFormatted }), + executeRulesOnUpdateForNewEvent({ ...innerAction.payload, uid, rulesExecutionDependenciesClientFormatted }), ], newEventWidgetDataEntryBatchActionTypes.UPDATE_DATA_ENTRY_FIELD_ADD_EVENT_ACTION_BATCH)); - }, [dispatch, orgUnit, rulesExecutionDependenciesClientFormatted]); + }, [dispatch, rulesExecutionDependenciesClientFormatted]); const onUpdateField = useCallback((innerAction: ReduxAction) => { const { dataEntryId, itemId } = innerAction.payload; @@ -36,9 +40,9 @@ export const DataEntry = ({ orgUnit, rulesExecutionDependenciesClientFormatted, dispatch(batchActions([ innerAction, startRunRulesPostUpdateField(dataEntryId, itemId, uid), - executeRulesOnUpdateForNewEvent({ ...innerAction.payload, uid, orgUnit, rulesExecutionDependenciesClientFormatted }), + executeRulesOnUpdateForNewEvent({ ...innerAction.payload, uid, rulesExecutionDependenciesClientFormatted }), ], newEventWidgetDataEntryBatchActionTypes.FIELD_UPDATE_BATCH)); - }, [dispatch, orgUnit, rulesExecutionDependenciesClientFormatted]); + }, [dispatch, rulesExecutionDependenciesClientFormatted]); const onStartAsyncUpdateField = useCallback(( innerAction: ReduxAction, @@ -50,13 +54,13 @@ export const DataEntry = ({ orgUnit, rulesExecutionDependenciesClientFormatted, return batchActions([ successInnerAction, startRunRulesPostUpdateField(dataEntryId, itemId, uid), - executeRulesOnUpdateForNewEvent({ ...successInnerAction.payload, dataEntryId, itemId, uid, orgUnit, rulesExecutionDependenciesClientFormatted }), + executeRulesOnUpdateForNewEvent({ ...successInnerAction.payload, dataEntryId, itemId, uid, rulesExecutionDependenciesClientFormatted }), ], newEventWidgetDataEntryBatchActionTypes.FIELD_UPDATE_BATCH); }; const onAsyncUpdateError = (errorInnerAction: ReduxAction) => errorInnerAction; dispatch(startAsyncUpdateFieldForNewEvent(innerAction, onAsyncUpdateSuccess, onAsyncUpdateError)); - }, [dispatch, orgUnit, rulesExecutionDependenciesClientFormatted]); + }, [dispatch, rulesExecutionDependenciesClientFormatted]); const onAddNote = useCallback((itemId: string, dataEntryId: string, note: string) => { dispatch(addNewEventNote(itemId, dataEntryId, note)); @@ -65,12 +69,11 @@ export const DataEntry = ({ orgUnit, rulesExecutionDependenciesClientFormatted, const onSetSaveTypes = useCallback((newSaveTypes: ?Array<$Values>) => { dispatch(setNewEventSaveTypes(newSaveTypes)); }, [dispatch]); - return ( void, dataEntryFieldRef: (instance: any, id: string) => void, rulesExecutionDependenciesClientFormatted: RulesExecutionDependenciesClientFormatted, onSaveAndCompleteEnrollment: (enrollment: Object) => void, + placementDomNodeForSavingText?: HTMLElement, + programName: string, |}; export type Props = $Diff; diff --git a/src/core_modules/capture-core/components/WidgetEnrollmentEventNew/DataEntry/epics/dataEntryRules.epics.js b/src/core_modules/capture-core/components/WidgetEnrollmentEventNew/DataEntry/epics/dataEntryRules.epics.js index f582f16368..50b1b20275 100644 --- a/src/core_modules/capture-core/components/WidgetEnrollmentEventNew/DataEntry/epics/dataEntryRules.epics.js +++ b/src/core_modules/capture-core/components/WidgetEnrollmentEventNew/DataEntry/epics/dataEntryRules.epics.js @@ -3,7 +3,6 @@ import { ofType } from 'redux-observable'; import { map, switchMap } from 'rxjs/operators'; import { from } from 'rxjs'; import { batchActions } from 'redux-batched-actions'; -import type { OrgUnit } from '@dhis2/rules-engine-javascript'; import i18n from '@dhis2/d2-i18n'; import { getTrackerProgramThrowIfNotFound } from '../../../../metaData/helpers'; import { rulesExecutedPostUpdateField } from '../../../DataEntry/actions/dataEntry.actions'; @@ -22,6 +21,7 @@ import { import { getDataEntryKey } from '../../../DataEntry/common/getDataEntryKey'; import type { RulesExecutionDependenciesClientFormatted } from '../../common.types'; import { getLocationQuery } from '../../../../utils/routing'; +import { getCoreOrgUnitFn, orgUnitFetched } from '../../../../metadataRetrieval/coreOrgUnit'; import type { QuerySingleResource } from '../../../../utils/api'; const runRulesForNewEvent = async ({ @@ -29,7 +29,6 @@ const runRulesForNewEvent = async ({ dataEntryId, itemId, uid, - orgUnit, rulesExecutionDependenciesClientFormatted, fieldData, querySingleResource, @@ -38,7 +37,6 @@ const runRulesForNewEvent = async ({ dataEntryId: string, itemId: string, uid: string, - orgUnit: OrgUnit, rulesExecutionDependenciesClientFormatted: RulesExecutionDependenciesClientFormatted, fieldData?: ?FieldData, querySingleResource: QuerySingleResource, @@ -59,11 +57,14 @@ const runRulesForNewEvent = async ({ const currentEventValues = getCurrentClientValues(state, foundation, formId, fieldData); const currentEventMainData = getCurrentClientMainData(state, itemId, dataEntryId, foundation); const currentEvent = { ...currentEventValues, ...currentEventMainData, programStageId }; + const { coreOrgUnit, cached } = + // $FlowFixMe + await getCoreOrgUnitFn(querySingleResource)(currentEvent.orgUnit?.id, store.value.organisationUnits); const effects = getApplicableRuleEffectsForTrackerProgram({ program, stage, - orgUnit, + orgUnit: coreOrgUnit, currentEvent, otherEvents: events, attributeValues, @@ -79,6 +80,7 @@ const runRulesForNewEvent = async ({ return batchActions([ updateRulesEffects(effectsWithValidations, formId), rulesExecutedPostUpdateField(dataEntryId, itemId, uid), + ...(coreOrgUnit && !cached ? [orgUnitFetched(coreOrgUnit)] : []), ], newEventWidgetDataEntryBatchActionTypes.RULES_EFFECTS_ACTIONS_BATCH, ); @@ -95,13 +97,12 @@ export const runRulesOnUpdateDataEntryFieldForNewEnrollmentEventEpic = ( actionBatch.payload .find(action => action.type === newEventWidgetDataEntryActionTypes.RULES_ON_UPDATE_EXECUTE)), switchMap((action) => { - const { dataEntryId, itemId, uid, orgUnit, rulesExecutionDependenciesClientFormatted } = action.payload; + const { dataEntryId, itemId, uid, rulesExecutionDependenciesClientFormatted } = action.payload; const runRulesForNewEventPromise = runRulesForNewEvent({ store, dataEntryId, itemId, uid, - orgUnit, rulesExecutionDependenciesClientFormatted, querySingleResource, }); @@ -126,7 +127,6 @@ export const runRulesOnUpdateFieldForNewEnrollmentEventEpic = ( elementId, value, uiState, - orgUnit, rulesExecutionDependenciesClientFormatted, } = action.payload; @@ -141,7 +141,6 @@ export const runRulesOnUpdateFieldForNewEnrollmentEventEpic = ( dataEntryId, itemId, uid, - orgUnit, rulesExecutionDependenciesClientFormatted, fieldData, querySingleResource, diff --git a/src/core_modules/capture-core/components/WidgetEnrollmentEventNew/DataEntry/fieldValidators/index.js b/src/core_modules/capture-core/components/WidgetEnrollmentEventNew/DataEntry/fieldValidators/index.js new file mode 100644 index 0000000000..1d1e26c9a9 --- /dev/null +++ b/src/core_modules/capture-core/components/WidgetEnrollmentEventNew/DataEntry/fieldValidators/index.js @@ -0,0 +1,5 @@ +// @flow +export { getCategoryOptionsValidatorContainers } from './categoryOptions.validatorContainersGetter'; +export { getEventDateValidatorContainers } from './eventDate.validatorContainersGetter'; +export { getNoteValidatorContainers } from './note.validatorContainersGetter'; +export { getOrgUnitValidatorContainers } from './orgUnit.validatorContainersGetter'; diff --git a/src/core_modules/capture-core/components/WidgetEnrollmentEventNew/DataEntry/fieldValidators/orgUnit.validatorContainersGetter.js b/src/core_modules/capture-core/components/WidgetEnrollmentEventNew/DataEntry/fieldValidators/orgUnit.validatorContainersGetter.js new file mode 100644 index 0000000000..acdc3c076e --- /dev/null +++ b/src/core_modules/capture-core/components/WidgetEnrollmentEventNew/DataEntry/fieldValidators/orgUnit.validatorContainersGetter.js @@ -0,0 +1,15 @@ +// @flow +import { isValidOrgUnit } from 'capture-core-utils/validators/form'; +import i18n from '@dhis2/d2-i18n'; + +const validateOrgUnit = (value?: ?Object) => isValidOrgUnit(value); + +export const getOrgUnitValidatorContainers = () => { + const validatorContainers = [ + { + validator: validateOrgUnit, + errorMessage: i18n.t('Please provide an valid organisation unit'), + }, + ]; + return validatorContainers; +}; diff --git a/src/core_modules/capture-core/components/WidgetEnrollmentEventNew/DataEntry/helpers/getOpenDataEntryActions.js b/src/core_modules/capture-core/components/WidgetEnrollmentEventNew/DataEntry/helpers/getOpenDataEntryActions.js index 4552b41cae..067bec0172 100644 --- a/src/core_modules/capture-core/components/WidgetEnrollmentEventNew/DataEntry/helpers/getOpenDataEntryActions.js +++ b/src/core_modules/capture-core/components/WidgetEnrollmentEventNew/DataEntry/helpers/getOpenDataEntryActions.js @@ -1,8 +1,7 @@ // @flow - import { convertGeometryOut } from 'capture-core/components/DataEntries/converters'; import { loadNewDataEntry } from '../../../DataEntry/actions/dataEntryLoadNew.actions'; -import { getEventDateValidatorContainers } from '../fieldValidators/eventDate.validatorContainersGetter'; +import { getEventDateValidatorContainers, getOrgUnitValidatorContainers } from '../fieldValidators'; import { getNoteValidatorContainers } from '../fieldValidators/note.validatorContainersGetter'; import type { ProgramCategory } from '../../../WidgetEventSchedule/CategoryOptions/CategoryOptions.types'; import { getCategoryOptionsValidatorContainers } from '../fieldValidators/categoryOptions.validatorContainersGetter'; @@ -15,6 +14,11 @@ const dataEntryPropsToInclude: DataEntryPropsToInclude = [ type: 'DATE', validatorContainers: getEventDateValidatorContainers(), }, + { + id: 'orgUnit', + type: 'ORGANISATION_UNIT', + validatorContainers: getOrgUnitValidatorContainers(), + }, { id: 'scheduledAt', type: 'DATE', @@ -37,7 +41,12 @@ const dataEntryPropsToInclude: DataEntryPropsToInclude = [ ]; export const getOpenDataEntryActions = - (dataEntryId: string, itemId: string, programCategory?: ProgramCategory) => { + (dataEntryId: string, itemId: string, programCategory?: ProgramCategory, orgUnit: Object) => { + const defaultDataEntryValues = { + orgUnit: orgUnit + ? { id: orgUnit.id, name: orgUnit.name, path: orgUnit.path } + : undefined, + }; if (programCategory && programCategory.categories) { dataEntryPropsToInclude.push(...programCategory.categories.map(category => ({ id: `attributeCategoryOptions-${category.id}`, @@ -45,6 +54,6 @@ export const getOpenDataEntryActions = validatorContainers: getCategoryOptionsValidatorContainers({ categories: programCategory.categories }, category.id), }))); } - return loadNewDataEntry(dataEntryId, itemId, dataEntryPropsToInclude); + return loadNewDataEntry(dataEntryId, itemId, dataEntryPropsToInclude, defaultDataEntryValues); }; diff --git a/src/core_modules/capture-core/components/WidgetEnrollmentEventNew/DataEntry/helpers/getRulesActions.js b/src/core_modules/capture-core/components/WidgetEnrollmentEventNew/DataEntry/helpers/getRulesActions.js index d8aaa50247..ea6eb4c7c6 100644 --- a/src/core_modules/capture-core/components/WidgetEnrollmentEventNew/DataEntry/helpers/getRulesActions.js +++ b/src/core_modules/capture-core/components/WidgetEnrollmentEventNew/DataEntry/helpers/getRulesActions.js @@ -28,7 +28,7 @@ export const getRulesActions = ({ formFoundation: RenderFoundation, dataEntryId: string, itemId: string, - orgUnit: OrgUnit, + orgUnit: ?OrgUnit, eventsRulesDependency: EnrollmentEvents, attributesValuesRulesDependency: AttributeValuesClientFormatted, enrollmentDataRulesDependency: EnrollmentData, diff --git a/src/core_modules/capture-core/components/WidgetEnrollmentEventNew/OrgUnitFetcher/OrgUnitFetcher.component.js b/src/core_modules/capture-core/components/WidgetEnrollmentEventNew/OrgUnitFetcher/OrgUnitFetcher.component.js index f92ecbfa41..5a89482dbc 100644 --- a/src/core_modules/capture-core/components/WidgetEnrollmentEventNew/OrgUnitFetcher/OrgUnitFetcher.component.js +++ b/src/core_modules/capture-core/components/WidgetEnrollmentEventNew/OrgUnitFetcher/OrgUnitFetcher.component.js @@ -19,14 +19,10 @@ export const OrgUnitFetcher = ({ ); } - if (orgUnit) { - return ( - - ); - } - - return null; + return ( + + ); }; diff --git a/src/core_modules/capture-core/components/WidgetEnrollmentEventNew/SavingText/SavingText.component.js b/src/core_modules/capture-core/components/WidgetEnrollmentEventNew/SavingText/SavingText.component.js index 14df486439..90ca327618 100644 --- a/src/core_modules/capture-core/components/WidgetEnrollmentEventNew/SavingText/SavingText.component.js +++ b/src/core_modules/capture-core/components/WidgetEnrollmentEventNew/SavingText/SavingText.component.js @@ -1,14 +1,20 @@ // @flow import React from 'react'; +import ReactDOM from 'react-dom'; import i18n from '@dhis2/d2-i18n'; import { InfoIconText } from '../../InfoIconText'; import type { Props } from './savingText.types'; -export const SavingText = ({ orgUnitName, stageName, programName }: Props) => ( - - - {i18n.t('Saving to {{stageName}} for {{programName}} in {{orgUnitName}}', - { orgUnitName, stageName, programName, interpolation: { escapeValue: false } })} - - -); +export const SavingText = ({ orgUnitName, stageName, programName, placementDomNode }: Props) => + (placementDomNode ? + ReactDOM.createPortal(( + + + {orgUnitName + ? i18n.t('Saving to {{stageName}} for {{programName}} in {{orgUnitName}}', + { orgUnitName, stageName, programName, interpolation: { escapeValue: false } }) + : i18n.t('Saving to {{stageName}} for {{programName}}', + { stageName, programName, interpolation: { escapeValue: false } })} + + + ), placementDomNode) : null); diff --git a/src/core_modules/capture-core/components/WidgetEnrollmentEventNew/SavingText/savingText.types.js b/src/core_modules/capture-core/components/WidgetEnrollmentEventNew/SavingText/savingText.types.js index 90b4edcc85..45cd2d74eb 100644 --- a/src/core_modules/capture-core/components/WidgetEnrollmentEventNew/SavingText/savingText.types.js +++ b/src/core_modules/capture-core/components/WidgetEnrollmentEventNew/SavingText/savingText.types.js @@ -1,7 +1,8 @@ // @flow export type Props = {| - orgUnitName: string, + orgUnitName?: string, stageName: string, programName: string, + placementDomNode?: HTMLElement, |}; diff --git a/src/core_modules/capture-core/components/WidgetEnrollmentEventNew/Validated/Validated.component.js b/src/core_modules/capture-core/components/WidgetEnrollmentEventNew/Validated/Validated.component.js index 7f34363548..adb86949ae 100644 --- a/src/core_modules/capture-core/components/WidgetEnrollmentEventNew/Validated/Validated.component.js +++ b/src/core_modules/capture-core/components/WidgetEnrollmentEventNew/Validated/Validated.component.js @@ -5,8 +5,8 @@ import withStyles from '@material-ui/core/styles/withStyles'; import { Widget } from '../../Widget'; import { DataEntry } from '../DataEntry'; import { FinishButtons } from '../FinishButtons'; -import { SavingText } from '../SavingText'; import { RelatedStagesActions } from '../../WidgetRelatedStages'; +import { usePlacementDomNode } from '../../../utils/portal/usePlacementDomNode'; import type { Props } from './validated.types'; const styles = () => ({ @@ -27,44 +27,50 @@ const ValidatedPlain = ({ relatedStageRef, onSave, onCancel, - orgUnit, id, ...passOnProps -}: Props) => ( - - } - > - {ready && ( +}: Props) => { + const { domRef: savingTextRef, domNode: savingTextDomNode } = usePlacementDomNode(); + + return ( + + } + >
- - - - + {ready && ( + <> + + + + + )} +
- )} - -); + + ); +}; export const ValidatedComponent: ComponentType< $Diff, diff --git a/src/core_modules/capture-core/components/WidgetEnrollmentEventNew/Validated/Validated.container.js b/src/core_modules/capture-core/components/WidgetEnrollmentEventNew/Validated/Validated.container.js index 6425cea75d..ef24042f8f 100644 --- a/src/core_modules/capture-core/components/WidgetEnrollmentEventNew/Validated/Validated.container.js +++ b/src/core_modules/capture-core/components/WidgetEnrollmentEventNew/Validated/Validated.container.js @@ -23,7 +23,7 @@ import type { RelatedStageRefPayload } from '../../WidgetRelatedStages'; const SaveHandlerHOC = withSaveHandler()(ValidatedComponent); const AskToCreateNewHandlerHOC = withAskToCreateNew()(SaveHandlerHOC); -const DataEntry = withAskToCompleteEnrollment()(AskToCreateNewHandlerHOC); +const ValidatedComponentWrapper = withAskToCompleteEnrollment()(AskToCreateNewHandlerHOC); export const Validated = ({ program, @@ -32,7 +32,7 @@ export const Validated = ({ onSaveExternal, onSaveSuccessActionType, onSaveErrorActionType, - orgUnit, + orgUnitContext, teiId, enrollmentId, rulesExecutionDependencies, @@ -50,8 +50,6 @@ export const Validated = ({ dataEntryId, itemId, programId: program.id, - orgUnitId: orgUnit.id, - orgUnitName: orgUnit.name, teiId, enrollmentId, formFoundation, @@ -64,7 +62,7 @@ export const Validated = ({ program, stage, formFoundation, - orgUnit, + orgUnitContext, dataEntryId, itemId, // $FlowFixMe Investigate @@ -137,13 +135,13 @@ export const Validated = ({ dispatch(startCreateNewAfterCompleting({ enrollmentId, isCreateNew, - orgUnitId: orgUnit.id, + orgUnitId: orgUnitContext?.id, programId: program.id, teiId, availableProgramStages, })); } - }, [handleSave, formFoundation, dispatch, enrollmentId, orgUnit.id, program.id, teiId, availableProgramStages]); + }, [handleSave, formFoundation, dispatch, enrollmentId, orgUnitContext?.id, program.id, teiId, availableProgramStages]); const handleSaveAndCompleteEnrollment = useCallback( @@ -170,12 +168,11 @@ export const Validated = ({ }, [dispatch]); return ( - ); diff --git a/src/core_modules/capture-core/components/WidgetEnrollmentEventNew/Validated/getConvertedAddEvent.js b/src/core_modules/capture-core/components/WidgetEnrollmentEventNew/Validated/getConvertedAddEvent.js index bbfb66046c..8cc308c31e 100644 --- a/src/core_modules/capture-core/components/WidgetEnrollmentEventNew/Validated/getConvertedAddEvent.js +++ b/src/core_modules/capture-core/components/WidgetEnrollmentEventNew/Validated/getConvertedAddEvent.js @@ -11,8 +11,6 @@ export const getAddEventEnrollmentServerData = ({ mainDataClientValues, eventId, programId, - orgUnitId, - orgUnitName, teiId, enrollmentId, completed, @@ -25,8 +23,6 @@ export const getAddEventEnrollmentServerData = ({ mainDataClientValues: Object, eventId: string, programId: string, - orgUnitId: string, - orgUnitName: string, teiId: string, enrollmentId: string, completed?: boolean, @@ -49,11 +45,11 @@ export const getAddEventEnrollmentServerData = ({ event: eventId, program: programId, programStage: formFoundation.id, - orgUnit: orgUnitId, + orgUnit: mainDataServerValues.orgUnit.id, + orgUnitName: mainDataServerValues.orgUnit.name, trackedEntity: teiId, enrollment: enrollmentId, scheduledAt: mainDataServerValues.occurredAt, - orgUnitName, updatedAt, uid, dataValues: Object diff --git a/src/core_modules/capture-core/components/WidgetEnrollmentEventNew/Validated/useBuildNewEventPayload.js b/src/core_modules/capture-core/components/WidgetEnrollmentEventNew/Validated/useBuildNewEventPayload.js index ab8c0f3683..21f2518d01 100644 --- a/src/core_modules/capture-core/components/WidgetEnrollmentEventNew/Validated/useBuildNewEventPayload.js +++ b/src/core_modules/capture-core/components/WidgetEnrollmentEventNew/Validated/useBuildNewEventPayload.js @@ -13,11 +13,9 @@ import type { RelatedStageRefPayload } from '../../WidgetRelatedStages'; type Props = { dataEntryId: string, itemId: string, - orgUnitId: string, programId: string, formFoundation: RenderFoundation, enrollmentId: string, - orgUnitName: string, teiId: string, }; @@ -52,11 +50,9 @@ export const createServerData = ({ export const useBuildNewEventPayload = ({ dataEntryId, itemId, - orgUnitId, programId, teiId, enrollmentId, - orgUnitName, formFoundation, }: Props) => { const { serverVersion: { minor } } = useConfig(); @@ -140,10 +136,8 @@ export const useBuildNewEventPayload = ({ eventId: requestEventId, mainDataClientValues: { ...dataEntryClientValues, notes: notesValues }, programId, - orgUnitId, enrollmentId, teiId, - orgUnitName, completed: saveType === addEventSaveTypes.COMPLETE, fromClientDate, serverMinorVersion: minor, diff --git a/src/core_modules/capture-core/components/WidgetEnrollmentEventNew/Validated/useLifecycle.js b/src/core_modules/capture-core/components/WidgetEnrollmentEventNew/Validated/useLifecycle.js index bf41bf3e53..92a68bf095 100644 --- a/src/core_modules/capture-core/components/WidgetEnrollmentEventNew/Validated/useLifecycle.js +++ b/src/core_modules/capture-core/components/WidgetEnrollmentEventNew/Validated/useLifecycle.js @@ -12,7 +12,7 @@ export const useLifecycle = ({ program, stage, formFoundation, - orgUnit, + orgUnitContext, dataEntryId, itemId, rulesExecutionDependenciesClientFormatted: { @@ -24,7 +24,7 @@ export const useLifecycle = ({ program: TrackerProgram, stage: ProgramStage, formFoundation: RenderFoundation, - orgUnit: OrgUnit, + orgUnitContext?: OrgUnit, dataEntryId: string, itemId: string, rulesExecutionDependenciesClientFormatted: RulesExecutionDependenciesClientFormatted, @@ -39,12 +39,12 @@ export const useLifecycle = ({ useEffect(() => { if (!isLoading) { dispatch(batchActions([ - ...getOpenDataEntryActions(dataEntryId, itemId, programCategory), + ...getOpenDataEntryActions(dataEntryId, itemId, programCategory, orgUnitContext), ])); dataEntryReadyRef.current = true; delayRulesExecutionRef.current = true; } - }, [dispatch, dataEntryId, itemId, program, formFoundation, isLoading, programCategory]); + }, [dispatch, dataEntryId, itemId, program, formFoundation, isLoading, programCategory, orgUnitContext]); const eventsRef = useRef(); const attributesRef = useRef(); @@ -70,7 +70,7 @@ export const useLifecycle = ({ formFoundation, dataEntryId, itemId, - orgUnit, + orgUnit: orgUnitContext, eventsRulesDependency, attributesValuesRulesDependency, enrollmentDataRulesDependency, @@ -84,7 +84,7 @@ export const useLifecycle = ({ // eslint-disable-next-line react-hooks/exhaustive-deps }, [ dispatch, - orgUnit, + orgUnitContext, eventsRulesDependency, attributesValuesRulesDependency, program, diff --git a/src/core_modules/capture-core/components/WidgetEnrollmentEventNew/Validated/validated.types.js b/src/core_modules/capture-core/components/WidgetEnrollmentEventNew/Validated/validated.types.js index 8d8e58fa74..e11d2dc759 100644 --- a/src/core_modules/capture-core/components/WidgetEnrollmentEventNew/Validated/validated.types.js +++ b/src/core_modules/capture-core/components/WidgetEnrollmentEventNew/Validated/validated.types.js @@ -9,7 +9,7 @@ import type { export type ContainerProps = {| ...CommonValidatedProps, - orgUnit: OrgUnit, + orgUnitContext?: OrgUnit, |}; export type Props = {| @@ -19,7 +19,7 @@ export type Props = {| eventSaveInProgress: boolean, stage: ProgramStage, formFoundation: RenderFoundation, - orgUnit: OrgUnit, + orgUnit?: OrgUnit, ready: boolean, id: string, itemId: string, diff --git a/src/core_modules/capture-core/components/WidgetEventEdit/EditEventDataEntry/EditEventDataEntry.component.js b/src/core_modules/capture-core/components/WidgetEventEdit/EditEventDataEntry/EditEventDataEntry.component.js index e958a69644..7c2103b71e 100644 --- a/src/core_modules/capture-core/components/WidgetEventEdit/EditEventDataEntry/EditEventDataEntry.component.js +++ b/src/core_modules/capture-core/components/WidgetEventEdit/EditEventDataEntry/EditEventDataEntry.component.js @@ -252,7 +252,7 @@ const buildGeometrySettingsFn = () => ({ label: i18n.t('Area'), dialogLabel: i18n.t('Area'), required: false, - orgUnit: props.orgUnit, + orgUnitId: props.orgUnit?.id, }); } return createComponentProps(props, { @@ -260,7 +260,7 @@ const buildGeometrySettingsFn = () => ({ label: i18n.t('Coordinate'), dialogLabel: i18n.t('Coordinate'), required: false, - orgUnit: props.orgUnit, + orgUnitId: props.orgUnit?.id, }); }, getPropName: () => 'geometry', @@ -513,6 +513,7 @@ class EditEventDataEntryPlain extends Component { fieldOptions={this.fieldOptions} dataEntrySections={this.dataEntrySections} orgUnit={orgUnit} + orgUnitId={orgUnit?.id} programId={programId} selectedOrgUnitId={orgUnit?.id} {...passOnProps} diff --git a/src/core_modules/capture-core/components/WidgetEventSchedule/ScheduleText/ScheduleText.component.js b/src/core_modules/capture-core/components/WidgetEventSchedule/ScheduleText/ScheduleText.component.js index b16eb0a896..aaf311e0fb 100644 --- a/src/core_modules/capture-core/components/WidgetEventSchedule/ScheduleText/ScheduleText.component.js +++ b/src/core_modules/capture-core/components/WidgetEventSchedule/ScheduleText/ScheduleText.component.js @@ -7,9 +7,12 @@ import type { Props } from './scheduleText.types'; export const ScheduleText = ({ orgUnitName, stageName, programName }: Props) => ( - { i18n.t('Scheduling an event in {{stageName}} for {{programName}} in {{orgUnitName}}', - { orgUnitName, stageName, programName, interpolation: { escapeValue: false } })} + {i18n.t( + orgUnitName + ? 'Scheduling an event in {{stageName}} for {{programName}} in {{orgUnitName}}' + : 'Scheduling an event in {{stageName}} for {{programName}}', + { orgUnitName, stageName, programName, interpolation: { escapeValue: false } }, + )} ); - diff --git a/src/core_modules/capture-core/components/WidgetEventSchedule/WidgetEventSchedule.container.js b/src/core_modules/capture-core/components/WidgetEventSchedule/WidgetEventSchedule.container.js index 4132d024e9..1ea77bc470 100644 --- a/src/core_modules/capture-core/components/WidgetEventSchedule/WidgetEventSchedule.container.js +++ b/src/core_modules/capture-core/components/WidgetEventSchedule/WidgetEventSchedule.container.js @@ -201,7 +201,6 @@ export const WidgetEventSchedule = ({ onSetAssignee={onSetAssignee} {...passOnProps} /> - ); }; diff --git a/src/core_modules/capture-core/metadataRetrieval/coreOrgUnit/getCoreOrgUnitFn.js b/src/core_modules/capture-core/metadataRetrieval/coreOrgUnit/getCoreOrgUnitFn.js new file mode 100644 index 0000000000..317d2f2220 --- /dev/null +++ b/src/core_modules/capture-core/metadataRetrieval/coreOrgUnit/getCoreOrgUnitFn.js @@ -0,0 +1,17 @@ +// @flow +import { fetchCoreOrgUnit } from './fetchCoreOrgUnit'; +import type { CoreOrgUnit } from './coreOrgUnit.types'; +import type { QuerySingleResource } from '../../utils/api'; + +export const getCoreOrgUnitFn = (querySingleResource: QuerySingleResource) => + async (orgUnitId?: string, cachedOrgUnitsCore: { [orgUnitId: string]: CoreOrgUnit }) => { + if (!orgUnitId) { + return { coreOrgUnit: null, cached: false }; + } + const cachedOrgUnit = cachedOrgUnitsCore[orgUnitId]; + if (cachedOrgUnit) { + return { coreOrgUnit: cachedOrgUnit, cached: true }; + } + const fetchedOrgUnit = await fetchCoreOrgUnit(orgUnitId, querySingleResource); + return { coreOrgUnit: fetchedOrgUnit, cached: false }; + }; diff --git a/src/core_modules/capture-core/metadataRetrieval/coreOrgUnit/index.js b/src/core_modules/capture-core/metadataRetrieval/coreOrgUnit/index.js index ee09984e67..7aa2fd6104 100644 --- a/src/core_modules/capture-core/metadataRetrieval/coreOrgUnit/index.js +++ b/src/core_modules/capture-core/metadataRetrieval/coreOrgUnit/index.js @@ -1,5 +1,6 @@ // @flow export { useCoreOrgUnit } from './useCoreOrgUnit'; -export { getCoreOrgUnit } from './coreOrgUnit.actions'; +export { getCoreOrgUnit, orgUnitFetched } from './coreOrgUnit.actions'; export { getCoreOrgUnitEpic } from './getCoreOrgUnit.epics'; +export { getCoreOrgUnitFn } from './getCoreOrgUnitFn'; export type { CoreOrgUnit } from './coreOrgUnit.types'; diff --git a/src/core_modules/capture-core/rules/rules.types.js b/src/core_modules/capture-core/rules/rules.types.js index 0249ee664c..07f870ae4b 100644 --- a/src/core_modules/capture-core/rules/rules.types.js +++ b/src/core_modules/capture-core/rules/rules.types.js @@ -14,7 +14,7 @@ import type { ProgramStage, TrackerProgram, EventProgram, RenderFoundation } fro export type GetApplicableRuleEffectsForTrackerProgramInput = {| program: TrackerProgram, stage?: ProgramStage, - orgUnit: OrgUnit, + orgUnit: ?OrgUnit, currentEvent?: EventData, otherEvents?: EventsData, attributeValues?: TEIValues, @@ -29,7 +29,7 @@ export type GetApplicableRuleEffectsForEventProgramInput = {| |}; export type GetApplicableRuleEffectsInput = {| - orgUnit: OrgUnit, + orgUnit: ?OrgUnit, currentEvent?: EventData, otherEvents?: EventsData, attributeValues?: TEIValues, diff --git a/src/core_modules/capture-core/utils/portal/index.js b/src/core_modules/capture-core/utils/portal/index.js new file mode 100644 index 0000000000..14fd5ee2e9 --- /dev/null +++ b/src/core_modules/capture-core/utils/portal/index.js @@ -0,0 +1,2 @@ +// @flow +export { usePlacementDomNode } from './usePlacementDomNode'; diff --git a/src/core_modules/capture-core/utils/portal/usePlacementDomNode.js b/src/core_modules/capture-core/utils/portal/usePlacementDomNode.js new file mode 100644 index 0000000000..0ed2b70b16 --- /dev/null +++ b/src/core_modules/capture-core/utils/portal/usePlacementDomNode.js @@ -0,0 +1,19 @@ +// @flow +import { useState, useEffect, useRef } from 'react'; + +// Main use case is to get the placement DOM Node when using portals. +// The hook ensures a rerender after a reference to the DOMNode has been acquired. +export const usePlacementDomNode = () => { + const domRef = useRef(); + const [domNode, setDomNode] = useState(); + useEffect(() => { + if (domRef.current) { + setDomNode(domRef.current); + } + }, [setDomNode]); + + return { + domRef, + domNode, + }; +}; diff --git a/src/core_modules/capture-ui/CoordinateField/CoordinateField.component.js b/src/core_modules/capture-ui/CoordinateField/CoordinateField.component.js index 782b38b821..064b03c35d 100644 --- a/src/core_modules/capture-ui/CoordinateField/CoordinateField.component.js +++ b/src/core_modules/capture-ui/CoordinateField/CoordinateField.component.js @@ -20,7 +20,8 @@ type Coordinate = { type Props = { onBlur: (value: any) => void, - onOpenMap: (hasValue: boolean) => void, + onOpenMap?: (hasValue: boolean) => void, + onCloseMap?: () => void, orientation: $Values, center?: ?Array, onChange?: ?(value: any) => void, @@ -89,11 +90,12 @@ export class CoordinateField extends React.Component { } closeMap = () => { + this.props.onCloseMap?.(); this.setState({ showMap: false }); } openMap = () => { - this.props.onOpenMap(Boolean(this.props.value)); + this.props.onOpenMap?.(Boolean(this.props.value)); this.setState({ showMap: true, position: this.getPosition() }); } @@ -169,7 +171,10 @@ export class CoordinateField extends React.Component { } renderMap = () => { - const { position, zoom } = this.state; + const { position, zoom, showMap } = this.state; + if (!showMap || (!position && !this.props.center)) { + return null; + } const center = position || this.props.center; return (
diff --git a/yarn.lock b/yarn.lock index 3c9064bb08..3c6e47ae66 100644 --- a/yarn.lock +++ b/yarn.lock @@ -5210,7 +5210,7 @@ array.prototype.filter@^1.0.0: es-object-atoms "^1.0.0" is-string "^1.0.7" -array.prototype.find@^2.1.1, array.prototype.find@^2.2.2: +array.prototype.find@^2.1.1: version "2.2.3" resolved "https://registry.yarnpkg.com/array.prototype.find/-/array.prototype.find-2.2.3.tgz#675a233dbcd9b65ecf1fb3f915741aebc45461e6" integrity sha512-fO/ORdOELvjbbeIfZfzrXFMhYHGofRGqd+am9zm3tZ4GlJINj/pA2eITyfd65Vg6+ZbHd/Cys7stpoRSWtQFdA== @@ -6086,6 +6086,14 @@ cachedir@^2.3.0: resolved "https://registry.yarnpkg.com/cachedir/-/cachedir-2.4.0.tgz#7fef9cf7367233d7c88068fe6e34ed0d355a610d" integrity sha512-9EtFOZR8g22CL7BWjJ9BUx1+A/djkofnyW3aOXZORNW2kxoUpx2h+uN2cOqwPmFhnpVmxg+KW2OjOSgChTEvsQ== +call-bind-apply-helpers@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.1.tgz#32e5892e6361b29b0b545ba6f7763378daca2840" + integrity sha512-BhYE+WDaywFg2TBWYNXAE+8B1ATnThNBqXHP5nQu0jWJdVvY2hvkpyB3qOmtmDePiS5/BDQ8wASEWGMWRG148g== + dependencies: + es-errors "^1.3.0" + function-bind "^1.1.2" + call-bind@^1.0.2, call-bind@^1.0.5, call-bind@^1.0.6, call-bind@^1.0.7: version "1.0.7" resolved "https://registry.yarnpkg.com/call-bind/-/call-bind-1.0.7.tgz#06016599c40c56498c18769d2730be242b6fa3b9" @@ -6097,6 +6105,14 @@ call-bind@^1.0.2, call-bind@^1.0.5, call-bind@^1.0.6, call-bind@^1.0.7: get-intrinsic "^1.2.4" set-function-length "^1.2.1" +call-bound@^1.0.2: + version "1.0.3" + resolved "https://registry.yarnpkg.com/call-bound/-/call-bound-1.0.3.tgz#41cfd032b593e39176a71533ab4f384aa04fd681" + integrity sha512-YTd+6wGlNlPxSuri7Y6X8tY2dmm12UMH66RpKMhiX6rsk5wXXnYgbUcOt8kiS31/AjfoTOvCsE+w8nZQLQnzHA== + dependencies: + call-bind-apply-helpers "^1.0.1" + get-intrinsic "^1.2.6" + callsites@^3.0.0: version "3.1.0" resolved "https://registry.yarnpkg.com/callsites/-/callsites-3.1.0.tgz#b3630abd8943432f54b3f0519238e33cd7df2f73" @@ -7878,6 +7894,15 @@ draft-js@>=0.10.0: immutable "~3.7.4" object-assign "^4.1.1" +dunder-proto@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/dunder-proto/-/dunder-proto-1.0.1.tgz#d7ae667e1dc83482f8b70fd0f6eefc50da30f58a" + integrity sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A== + dependencies: + call-bind-apply-helpers "^1.0.1" + es-errors "^1.3.0" + gopd "^1.2.0" + duplexer3@^0.1.4: version "0.1.5" resolved "https://registry.yarnpkg.com/duplexer3/-/duplexer3-0.1.5.tgz#0b5e4d7bad5de8901ea4440624c8e1d20099217e" @@ -8212,6 +8237,11 @@ es-define-property@^1.0.0: dependencies: get-intrinsic "^1.2.4" +es-define-property@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/es-define-property/-/es-define-property-1.0.1.tgz#983eb2f9a6724e9303f61addf011c72e09e0b0fa" + integrity sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g== + es-errors@^1.2.1, es-errors@^1.3.0: version "1.3.0" resolved "https://registry.yarnpkg.com/es-errors/-/es-errors-1.3.0.tgz#05f75a25dab98e4fb1dcd5e1472c0546d5057c8f" @@ -8472,19 +8502,18 @@ eslint-import-resolver-node@^0.3.9: is-core-module "^2.13.0" resolve "^1.22.4" -eslint-import-resolver-webpack@^0.13.2: - version "0.13.8" - resolved "https://registry.yarnpkg.com/eslint-import-resolver-webpack/-/eslint-import-resolver-webpack-0.13.8.tgz#5f64d1d653eefa19cdfd0f0165c996b6be7012f9" - integrity sha512-Y7WIaXWV+Q21Rz/PJgUxiW/FTBOWmU8NTLdz+nz9mMoiz5vAev/fOaQxwD7qRzTfE3HSm1qsxZ5uRd7eX+VEtA== +eslint-import-resolver-webpack@^0.13.10: + version "0.13.10" + resolved "https://registry.yarnpkg.com/eslint-import-resolver-webpack/-/eslint-import-resolver-webpack-0.13.10.tgz#d5b69ca548190bd6fd517e5732d2b16cf884227a" + integrity sha512-ciVTEg7sA56wRMR772PyjcBRmyBMLS46xgzQZqt6cWBEKc7cK65ZSSLCTLVRu2gGtKyXUb5stwf4xxLBfERLFA== dependencies: - array.prototype.find "^2.2.2" debug "^3.2.7" enhanced-resolve "^0.9.1" find-root "^1.1.0" - hasown "^2.0.0" + hasown "^2.0.2" interpret "^1.4.0" - is-core-module "^2.13.1" - is-regex "^1.1.4" + is-core-module "^2.15.1" + is-regex "^1.2.0" lodash "^4.17.21" resolve "^2.0.0-next.5" semver "^5.7.2" @@ -9594,6 +9623,22 @@ get-intrinsic@^1.1.3, get-intrinsic@^1.2.1, get-intrinsic@^1.2.2, get-intrinsic@ has-symbols "^1.0.3" hasown "^2.0.0" +get-intrinsic@^1.2.6: + version "1.2.7" + resolved "https://registry.yarnpkg.com/get-intrinsic/-/get-intrinsic-1.2.7.tgz#dcfcb33d3272e15f445d15124bc0a216189b9044" + integrity sha512-VW6Pxhsrk0KAOqs3WEd0klDiF/+V7gQOpAvY1jVU/LHmaD/kQO4523aiJuikX/QAKYiW6x8Jh+RJej1almdtCA== + dependencies: + call-bind-apply-helpers "^1.0.1" + es-define-property "^1.0.1" + es-errors "^1.3.0" + es-object-atoms "^1.0.0" + function-bind "^1.1.2" + get-proto "^1.0.0" + gopd "^1.2.0" + has-symbols "^1.1.0" + hasown "^2.0.2" + math-intrinsics "^1.1.0" + get-own-enumerable-property-symbols@^3.0.0: version "3.0.2" resolved "https://registry.yarnpkg.com/get-own-enumerable-property-symbols/-/get-own-enumerable-property-symbols-3.0.2.tgz#b5fde77f22cbe35f390b4e089922c50bce6ef664" @@ -9604,6 +9649,14 @@ get-package-type@^0.1.0: resolved "https://registry.yarnpkg.com/get-package-type/-/get-package-type-0.1.0.tgz#8de2d803cff44df3bc6c456e6668b36c3926e11a" integrity sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q== +get-proto@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/get-proto/-/get-proto-1.0.1.tgz#150b3f2743869ef3e851ec0c49d15b1d14d00ee1" + integrity sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g== + dependencies: + dunder-proto "^1.0.1" + es-object-atoms "^1.0.0" + get-stream@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-3.0.0.tgz#8e943d1358dc37555054ecbe2edb05aa174ede14" @@ -9868,6 +9921,11 @@ gopd@^1.0.1: dependencies: get-intrinsic "^1.1.3" +gopd@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/gopd/-/gopd-1.2.0.tgz#89f56b8217bdbc8802bd299df6d7f1081d7e51a1" + integrity sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg== + got@^9.6.0: version "9.6.0" resolved "https://registry.yarnpkg.com/got/-/got-9.6.0.tgz#edf45e7d67f99545705de1f7bbeeeb121765ed85" @@ -9995,6 +10053,11 @@ has-symbols@^1.0.1, has-symbols@^1.0.2, has-symbols@^1.0.3: resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.0.3.tgz#bb7b2c4349251dce87b125f7bdf874aa7c8b39f8" integrity sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A== +has-symbols@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.1.0.tgz#fc9c6a783a084951d0b971fe1018de813707a338" + integrity sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ== + has-tostringtag@^1.0.0, has-tostringtag@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/has-tostringtag/-/has-tostringtag-1.0.2.tgz#2cdc42d40bef2e5b4eeab7c01a73c54ce7ab5abc" @@ -10649,10 +10712,10 @@ is-ci@^3.0.0: dependencies: ci-info "^3.2.0" -is-core-module@^2.13.0, is-core-module@^2.13.1, is-core-module@^2.5.0: - version "2.15.0" - resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.15.0.tgz#71c72ec5442ace7e76b306e9d48db361f22699ea" - integrity sha512-Dd+Lb2/zvk9SKy1TGCt1wFJFo/MWBPMX5x7KcvLajWTGuomczdQX61PvY5yK6SVACwpoexWo81IfFyoKY2QnTA== +is-core-module@^2.13.0, is-core-module@^2.13.1, is-core-module@^2.15.1, is-core-module@^2.5.0: + version "2.16.1" + resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.16.1.tgz#2a98801a849f43e2add644fbb6bc6229b19a4ef4" + integrity sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w== dependencies: hasown "^2.0.2" @@ -10923,13 +10986,15 @@ is-primitive@^2.0.0: resolved "https://registry.yarnpkg.com/is-primitive/-/is-primitive-2.0.0.tgz#207bab91638499c07b2adf240a41a87210034575" integrity sha512-N3w1tFaRfk3UrPfqeRyD+GYDASU3W5VinKhlORy8EWVf/sIdDL9GAcew85XmktCfH+ngG7SRXEVDoO18WMdB/Q== -is-regex@^1.0.5, is-regex@^1.1.0, is-regex@^1.1.4: - version "1.1.4" - resolved "https://registry.yarnpkg.com/is-regex/-/is-regex-1.1.4.tgz#eef5663cd59fa4c0ae339505323df6854bb15958" - integrity sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg== +is-regex@^1.0.5, is-regex@^1.1.0, is-regex@^1.1.4, is-regex@^1.2.0: + version "1.2.1" + resolved "https://registry.yarnpkg.com/is-regex/-/is-regex-1.2.1.tgz#76d70a3ed10ef9be48eb577887d74205bf0cad22" + integrity sha512-MjYsKHO5O7mCsmRGxWcLWheFqN9DJ/2TmngvjKXihe6efViPqc274+Fx/4fYj/r03+ESvBdTXK0V6tA3rgez1g== dependencies: - call-bind "^1.0.2" - has-tostringtag "^1.0.0" + call-bound "^1.0.2" + gopd "^1.2.0" + has-tostringtag "^1.0.2" + hasown "^2.0.2" is-regexp@^1.0.0: version "1.0.0" @@ -12765,6 +12830,11 @@ material-ui@^0.20.0: simple-assign "^0.1.0" warning "^3.0.0" +math-intrinsics@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/math-intrinsics/-/math-intrinsics-1.1.0.tgz#a0dd74be81e2aa5c2f27e65ce283605ee4e2b7f9" + integrity sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g== + math-random@^1.0.1: version "1.0.4" resolved "https://registry.yarnpkg.com/math-random/-/math-random-1.0.4.tgz#5dd6943c938548267016d4e34f057583080c514c"