Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: [DHIS2-18325] Show orgunit selector in the new event form #3879

Open
wants to merge 24 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
ed2b1dc
feat: add org unit field to form with validation
henrikmv Nov 11, 2024
e5c91e7
feat: set orgunit for event
henrikmv Nov 13, 2024
87782ae
Merge remote-tracking branch 'origin/master' into hv/feat/DHIS2-18325…
henrikmv Nov 20, 2024
e7614f1
feat: add to redux
henrikmv Nov 25, 2024
1ce0a2c
feat: disable org unit in scope selector
henrikmv Nov 25, 2024
08fa169
feat: add selected org unit to payload
henrikmv Nov 25, 2024
587a441
feat: auto select orgUnit
henrikmv Dec 5, 2024
5056f96
feat: show form without selected org unit
henrikmv Dec 6, 2024
c93d7b6
feat: add orgunit selector to schedule form
henrikmv Dec 7, 2024
8fb93ca
fix: temp
henrikmv Dec 7, 2024
b240a15
fix: style for schedule
henrikmv Dec 8, 2024
0a9847d
fix: code clean up
henrikmv Dec 9, 2024
3274b43
fix: fix map center point when no org unit
henrikmv Dec 9, 2024
3ee7546
Merge remote-tracking branch 'origin/master' into hv/feat/DHIS2-18325…
henrikmv Dec 9, 2024
7f6d2eb
Revert "Merge remote-tracking branch 'origin/master' into hv/feat/DHI…
henrikmv Dec 9, 2024
d9561ed
Merge remote-tracking branch 'origin/master' into hv/feat/DHIS2-18325…
henrikmv Dec 9, 2024
4cae9b6
Revert "Merge remote-tracking branch 'origin/master' into hv/feat/DHI…
henrikmv Dec 10, 2024
831354a
feat: validation org unit in schedule
henrikmv Dec 10, 2024
757df72
Merge remote-tracking branch 'origin/master' into hv/feat/DHIS2-18325…
henrikmv Dec 10, 2024
8c02cc1
fix: nameing of date component
henrikmv Dec 10, 2024
eecfaa0
fix: schedule date automatically info bow
henrikmv Dec 11, 2024
ca17101
fix: remove cy test that clears the org unit
henrikmv Dec 11, 2024
22f2c8d
fix: cy test
henrikmv Dec 12, 2024
621ff6f
fix: add deleted cy test
henrikmv Dec 14, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 0 additions & 5 deletions cypress/e2e/ScopeSelector/ScopeSelector.feature
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
5 changes: 0 additions & 5 deletions cypress/e2e/ScopeSelector/ScopeSelector.js
Original file line number Diff line number Diff line change
Expand Up @@ -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');
Expand Down
47 changes: 25 additions & 22 deletions i18n/en.pot
Original file line number Diff line number Diff line change
Expand Up @@ -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-03T10:58:18.077Z\n"
"PO-Revision-Date: 2024-12-03T10:58:18.077Z\n"
"POT-Creation-Date: 2024-12-10T16:40:25.470Z\n"
"PO-Revision-Date: 2024-12-10T16:40:25.470Z\n"

msgid "Choose one or more dates..."
msgstr "Choose one or more dates..."
Expand Down Expand Up @@ -691,9 +691,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"

Expand Down Expand Up @@ -750,6 +747,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"

Expand Down Expand Up @@ -1213,12 +1213,18 @@ 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"

Expand All @@ -1240,9 +1246,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"

Expand Down Expand Up @@ -1270,6 +1273,12 @@ msgstr "Write a note about this event"
msgid "This event doesn't have any notes"
msgstr "This event doesn't have any notes"

msgid "after"
msgstr "after"

msgid "before"
msgstr "before"

msgid "Schedule date info"
msgstr "Schedule date info"

Expand All @@ -1284,32 +1293,29 @@ msgid_plural "The scheduled date is {{count}} days {{position}} the suggested da
msgstr[0] "The scheduled date is {{count}} day {{position}} the suggested date."
msgstr[1] "The scheduled date is {{count}} days {{position}} the suggested date."

msgid "after"
msgstr "after"

msgid "before"
msgstr "before"

msgid "There are {{count}} scheduled event in {{orgUnitName}} on this day."
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 date / Due date"
msgstr "Schedule date / Due date"

msgid "Please provide a valid organisation unit"
msgstr "Please provide a valid organisation unit"

msgid "Schedule info"
msgstr "Schedule info"

msgid "Schedule date / Due date"
msgstr "Schedule date / Due date"

msgid "Event notes"
msgstr "Event notes"

msgid "Write a note about this scheduled event"
msgstr "Write a note about this scheduled event"

msgid "Program or stage is invalid"
msgstr "Program or stage is invalid"

msgid "Save note"
msgstr "Save note"

Expand Down Expand Up @@ -1406,9 +1412,6 @@ msgstr "Report date"
msgid "Please enter a date"
msgstr "Please enter a date"

msgid "Please provide a valid organisation unit"
msgstr "Please provide a valid organisation unit"

msgid "Please select a valid event"
msgstr "Please select a valid event"

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,9 @@ const convertToClientCoordinates = ({ coordinates, type }: { coordinates: any[],

const getCenterPoint = (InnerComponent: ComponentType<any>) => (props: Object) => {
const { orgUnit, ...passOnProps } = props;
if (!orgUnit || !orgUnit.id) {
return <InnerComponent {...passOnProps} center={DEFAULT_CENTER} onOpenMap={() => {}} />;
}
const [orgUnitKey, setOrgUnitKey] = useState(orgUnit.id);
const [shouldFetch, setShouldFetch] = useState(false);
const queryKey = ['organisationUnit', 'geometry', orgUnitKey];
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -65,14 +64,6 @@ const EnrollmentAddEventPagePain = ({
);
}

if (!orgUnitId) {
return (
<IncompleteSelectionsMessage>
{i18n.t('Choose an organisation unit to start reporting')}
</IncompleteSelectionsMessage>
);
}

if (!ready) {
return null;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ export const EnrollmentAddEventTopBar = ({
onResetOrgUnitId={() => onResetOrgUnitId()}
isUserInteractionInProgress={userInteractionInProgress}
onStartAgain={() => reset()}
isReadOnly
>
<SingleLockedSelect
displayOnly
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ type Props = {
name: string
},
previousOrgUnitId?: string,
isReadOnly?: boolean,
classes: Object,
};

Expand Down Expand Up @@ -48,16 +49,17 @@ class OrgUnitSelectorPlain extends Component<Props, State> {
}

render() {
const { selectedOrgUnitId, selectedOrgUnit, previousOrgUnitId, onReset, classes } = this.props;
const { selectedOrgUnitId, selectedOrgUnit, previousOrgUnitId, onReset, isReadOnly, classes } = this.props;

return (
<SelectorBarItem
label={i18n.t('Organisation unit')}
noValueMessage={i18n.t('Choose an organisation unit')}
value={selectedOrgUnitId ? selectedOrgUnit?.name : ''}
open={this.state.open}
open={!isReadOnly && this.state.open}
setOpen={open => this.setState({ open })}
onClearSelectionClick={() => onReset()}
onClearSelectionClick={!isReadOnly ? () => onReset() : undefined}
displayOnly={isReadOnly}
dataTest="org-unit-selector-container"
>
<div className={classes.selectBarMenu}>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ export const QuickSelector = ({
formIsOpen,
children,
onStartAgain,
isReadOnly,
}: Props) => (
<SelectorBar
disableClearSelections={!selectedProgramId && !selectedOrgUnitId}
Expand All @@ -46,6 +47,7 @@ export const QuickSelector = ({
handleClickOrgUnit={onSetOrgUnit}
selectedOrgUnit={selectedOrgUnit}
onReset={onResetOrgUnitId}
isReadOnly={isReadOnly}
/>
{children}
</SelectorBar>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,4 +17,5 @@ export type Props = {
onStartAgain: () => void,
formIsOpen: boolean,
children: Node,
isReadOnly?: boolean,
};
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,7 @@ class ScopeSelectorClass extends Component<Props, State> {
selectedCategories={this.props.selectedCategories}
isUserInteractionInProgress={this.props.isUserInteractionInProgress}
formIsOpen={this.props.formIsOpen}
isReadOnly={this.props.isReadOnly}
>
{this.props.children}
</QuickSelector>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ export const ScopeSelector: ComponentType<OwnProps> = ({
onStartAgain,
formIsOpen = false,
children,
isReadOnly,
}) => {
const dispatch = useDispatch();
const [selectedOrgUnit, setSelectedOrgUnit] = useState({ name: undefined, id: selectedOrgUnitId });
Expand Down Expand Up @@ -81,6 +82,7 @@ export const ScopeSelector: ComponentType<OwnProps> = ({
isUserInteractionInProgress={isUserInteractionInProgress}
formIsOpen={formIsOpen}
onStartAgain={onStartAgain}
isReadOnly={isReadOnly}
ready={ready}
>
{children}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ export type OwnProps = $ReadOnly<{|
onStartAgain: () => void,
formIsOpen?: boolean,
children: Node,
isReadOnly?: boolean,
|}>

export type PropsFromRedux = $ReadOnly<{|
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -28,6 +31,7 @@ import {
withDefaultShouldUpdateInterface,
orientations,
VirtualizedSelectField,
SingleOrgUnitSelectField,
} from '../../FormFields/New';
import { Assignee } from './Assignee';
import { inMemoryFileStore } from '../../DataEntry/file/inMemoryFileStore';
Expand Down Expand Up @@ -102,7 +106,6 @@ const baseComponentStylesVertical = {
},
};


function defaultFilterProps(props: Object) {
const { formHorizontal, fieldOptions, validationError, modified, ...passOnProps } = props;
return passOnProps;
Expand Down Expand Up @@ -161,6 +164,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()(
Expand Down Expand Up @@ -284,8 +327,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),
),
Expand Down Expand Up @@ -358,6 +401,7 @@ const WrappedDataEntry = compose(
withAOCFieldBuilder({}),
withDataEntryFields(getCategoryOptionsSettingsFn()),
withDataEntryField(buildReportDateSettingsFn()),
withDataEntryField(buildOrgUnitSettingsFn()),
withDataEntryFieldIfApplicable(buildGeometrySettingsFn()),
withDataEntryField(buildNotesSettingsFn()),
withDataEntryFieldIfApplicable(buildAssigneeSettingsFn()),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import type { RulesExecutionDependenciesClientFormatted } from '../common.types'
export type ContainerProps = {|
stage: ProgramStage,
formFoundation: RenderFoundation,
orgUnit: OrgUnit,
orgUnit?: OrgUnit,
id: string,
itemId: string,
formRef: (formInstance: any) => void,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@
}

.orgUnitLabel {
padding-top: 3px;
padding-top: 13px;
}

.selectLabel {
Expand Down
Original file line number Diff line number Diff line change
@@ -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';
Loading
Loading