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-9652 with save buttons #1260

Merged
merged 53 commits into from
Jan 5, 2021
Merged
Show file tree
Hide file tree
Changes from 38 commits
Commits
Show all changes
53 commits
Select commit Hold shift + click to select a range
684098e
feat: adds tetselector on the new page
paschalidi Nov 26, 2020
d57dda9
feat: trackedEntityTypeId on url for new and search page
paschalidi Nov 26, 2020
7445483
refactor: cleans up the older func
paschalidi Nov 26, 2020
1816123
chore: removes debugger
paschalidi Nov 26, 2020
4d8001c
chore: order
paschalidi Nov 26, 2020
5286ddc
fix: one trackedEntityTypeId
paschalidi Nov 26, 2020
1b119d4
chore: one line
paschalidi Nov 26, 2020
73293c0
feat: adds the enrollment and profile sections
paschalidi Nov 26, 2020
2cda0b2
chore: tetype once
paschalidi Nov 26, 2020
7e1a12c
chore: better id
paschalidi Nov 26, 2020
8e1f067
chore: reverts
paschalidi Nov 26, 2020
cdea6ec
chore: reverts
paschalidi Nov 26, 2020
6d55a6f
chore: reverts
paschalidi Nov 26, 2020
d2f3937
chore: linting
paschalidi Nov 26, 2020
8c1caf9
chore: styles the forms
paschalidi Nov 26, 2020
e60d3b6
chore: rebasing
paschalidi Nov 26, 2020
d3f343c
chore: reverts
paschalidi Nov 26, 2020
5b59256
chore: reverts ;)
paschalidi Nov 26, 2020
776622a
chore: styles the max width
paschalidi Nov 26, 2020
8c91c49
refactor: exports consts and moves the files around
paschalidi Nov 26, 2020
584c058
chore: remove line
paschalidi Nov 26, 2020
f12add8
refactor: the registration entries are self initialised and ready to use
paschalidi Nov 26, 2020
f428586
chore: rebasing
paschalidi Nov 26, 2020
6048d42
fix: infinite loading state
paschalidi Nov 30, 2020
9d89f52
Merge remote-tracking branch 'origin/master' into cp/registration/10-…
paschalidi Dec 3, 2020
39558c4
chore: rebasing
paschalidi Dec 3, 2020
e9faaaa
chore: styles
paschalidi Dec 3, 2020
56517a1
Merge branch 'cp/registration/09-styles' into cp/registration/10-enro…
paschalidi Dec 3, 2020
83dcbcd
chore: removes dispatch
paschalidi Dec 3, 2020
9022a68
Merge branch 'cp/registration/10-enrollment-data-entry' into cp/regis…
paschalidi Dec 3, 2020
774a28a
chore: lints
paschalidi Dec 3, 2020
e9b0b3f
chore: reverts
paschalidi Dec 3, 2020
a9bb19c
chore: no {}
paschalidi Dec 3, 2020
33d15b1
chore: creates containers
paschalidi Dec 3, 2020
3d81661
chore: fixes the paths
paschalidi Dec 3, 2020
05dbd79
chore: loading indicator
paschalidi Dec 3, 2020
a7ac966
chore: no need for startDataEntryInitialisationEpic
paschalidi Dec 3, 2020
89c15b9
feat: with buttons
paschalidi Dec 3, 2020
89b776b
chore: rebase
paschalidi Dec 3, 2020
33c730d
chore: org unit
paschalidi Dec 3, 2020
ac340f4
chore: "better" text
paschalidi Dec 3, 2020
34e96a2
chore: flow fixes me
paschalidi Dec 3, 2020
5f9e41f
Merge remote-tracking branch 'origin/master' into cp/registration/10-…
paschalidi Dec 3, 2020
0dcb1f2
Merge branch 'cp/registration/10-enrollment-data-entry' into cp/regis…
paschalidi Dec 3, 2020
331529b
Merge branch 'cp/registration/11-shows-enrollment-section' into cp/re…
paschalidi Dec 3, 2020
42f41c8
Merge remote-tracking branch 'origin/master' into cp/registration/12-…
paschalidi Dec 7, 2020
a01b33a
Merge remote-tracking branch 'origin/master' into cp/registration/12-…
paschalidi Dec 10, 2020
3d6107f
chore: InfoIconText refactoe
paschalidi Jan 5, 2021
f471b34
Merge remote-tracking branch 'origin/master' into cp/registration/12-…
paschalidi Jan 5, 2021
1301c33
chore: space
paschalidi Jan 5, 2021
a43961a
chore: no space
paschalidi Jan 5, 2021
3575dbf
Merge remote-tracking branch 'origin/master' into cp/registration/12-…
paschalidi Jan 5, 2021
a3dd10a
[part 02] feat: DHIS2-9653 submitting a new TEI (#1266)
paschalidi Jan 5, 2021
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
34 changes: 23 additions & 11 deletions i18n/en.pot
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,9 @@ msgstr ""
msgid "A future date is not allowed"
msgstr ""

msgid "Metadata error. see log for details"
msgstr ""

msgid "An error has occurred. See log for details"
msgstr ""

Expand Down Expand Up @@ -523,6 +526,24 @@ msgstr ""
msgid "Choose a registering unit to start reporting"
msgstr ""

msgid "Saving a {{trackedEntityName}} in"
msgstr ""

msgid "in"
msgstr ""

msgid "Saving a {{trackedEntityName}}"
msgstr ""

msgid "without"
msgstr ""

msgid "enrollment in"
msgstr ""

msgid "Enroll in a program by selecting a program from the top bar."
msgstr ""

msgid "Creating a new {{TET}} in {{program}} in {{orgUnit}}"
msgstr ""

Expand Down Expand Up @@ -564,9 +585,6 @@ msgstr ""
msgid "Saving to"
msgstr ""

msgid "in"
msgstr ""

msgid ""
"This is not an event program or the metadata is corrupt. See log for "
"details."
Expand Down Expand Up @@ -640,13 +658,10 @@ msgstr ""
msgid "Link"
msgstr ""

msgid "Metadata error. see log for details"
msgstr ""

msgid "Review duplicates"
msgid "Review Duplicates"
msgstr ""

msgid "Create {{trackedEntityTypeName}} and link"
msgid "Save new {{trackedEntityTypeName}} and link"
msgstr ""

msgid "Possible duplicates found"
Expand All @@ -670,9 +685,6 @@ msgstr ""
msgid "Registration"
msgstr ""

msgid "Review Duplicates"
msgstr ""

msgid "Search results"
msgstr ""

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,6 @@ import D2SectionFields from './D2SectionFields.container';
import { Section as MetaDataSection } from '../../metaData';

const getStyles = theme => ({
sectionFieldsInSection: {
margin: theme.spacing.unit,
},
section: {
backgroundColor: 'white',
maxWidth: theme.typography.pxToRem(892),
Expand All @@ -20,7 +17,6 @@ type Props = {
sectionMetaData: MetaDataSection,
isHidden?: ?boolean,
classes: {
sectionFieldsInSection: string,
section: string,
},
formHorizontal: ?boolean,
Expand Down Expand Up @@ -70,19 +66,15 @@ class D2Section extends React.PureComponent<Props> {
elevation={2}
className={classes.section}
>
<div
className={classes.sectionFieldsInSection}
>
{/* $FlowFixMe[cannot-spread-inexact] automated comment
*/}
<D2SectionFields
ref={(instance) => {
this.sectionFieldsInstance = instance;
}}
fieldsMetaData={sectionMetaData.elements}
{...passOnProps}
/>
</div>
{/* $FlowFixMe[cannot-spread-inexact] automated comment */}
<D2SectionFields
ref={(instance) => {
this.sectionFieldsInstance = instance;
}}
fieldsMetaData={sectionMetaData.elements}
{...passOnProps}
/>

</Section>
</div>
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -277,8 +277,8 @@ class FinalEnrollmentDataEntry extends React.Component<FinalTeiDataEntryProps> {
return (
// $FlowFixMe[cannot-spread-inexact] automated comment
<DataEntry
dataEntrySections={FinalEnrollmentDataEntry.dataEntrySectionDefinitions}
{...passOnProps}
dataEntrySections={FinalEnrollmentDataEntry.dataEntrySectionDefinitions}
formFoundation={enrollmentMetadata.enrollmentForm}
/>
);
Expand Down Expand Up @@ -310,7 +310,7 @@ class PreEnrollmentDataEntryPure extends React.PureComponent<Object> {
}
}

class PreEnrollmentDataEntry extends React.Component<PreEnrollmentDataEntryProps> {
export class EnrollmentDataEntryComponent extends React.Component<PreEnrollmentDataEntryProps> {
getValidationContext = () => {
const { orgUnit, onGetUnsavedAttributeValues } = this.props;
return {
Expand Down Expand Up @@ -341,7 +341,8 @@ class PreEnrollmentDataEntry extends React.Component<PreEnrollmentDataEntryProps
onUpdateDataEntryField,
onStartAsyncUpdateField,
onGetUnsavedAttributeValues,
...passOnProps } = this.props;
...passOnProps
} = this.props;
return (
// $FlowFixMe[cannot-spread-inexact] automated comment
<PreEnrollmentDataEntryPure
Expand All @@ -354,5 +355,3 @@ class PreEnrollmentDataEntry extends React.Component<PreEnrollmentDataEntryProps
);
}
}

export default PreEnrollmentDataEntry;
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
import { connect } from 'react-redux';
import { updateFieldBatch, asyncUpdateSuccessBatch, updateDataEntryFieldBatch } from './actions/enrollment.actionBatchs';
import { startAsyncUpdateFieldForNewEnrollment } from './actions/enrollment.actions';
import Enrollment from './Enrollment.component';
import { EnrollmentDataEntryComponent } from './EnrollmentDataEntry.component';

const mapStateToProps = () => ({});

Expand Down Expand Up @@ -46,5 +46,5 @@ const mapDispatchToProps = (dispatch: ReduxDispatch) => ({
});

// $FlowFixMe
export default connect(mapStateToProps, mapDispatchToProps)(Enrollment);
export const EnrollmentDataEntry = connect(mapStateToProps, mapDispatchToProps)(EnrollmentDataEntryComponent);

Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// @flow
export { default as Enrollment } from './Enrollment.container';
export { EnrollmentDataEntry } from './EnrollmentDataEntry.container';
export { default as sectionKeys } from './constants/sectionKeys.const';
export { actionTypes as openActionTypes } from './actions/open.actions';
export {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
// @flow
import { actionCreator } from '../../../actions/actions.utils';

export const enrollmentRegistrationEntryActionTypes = {
TRACKER_PROGRAM_REGISTRATION_ENTRY_INITIALISATION_START: 'StartInitForEnrollmentRegistrationForm',
};

export const startNewEnrollmentDataEntryInitialisation = ({ selectedOrgUnitId, selectedScopeId, dataEntryId, formFoundation }: Object) =>
actionCreator(enrollmentRegistrationEntryActionTypes.TRACKER_PROGRAM_REGISTRATION_ENTRY_INITIALISATION_START)({ selectedOrgUnitId, selectedScopeId, dataEntryId, formFoundation });

Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
// @flow
import React from 'react';
import { useScopeInfo } from '../../../hooks/useScopeInfo';
import { scopeTypes } from '../../../metaData';
import { EnrollmentDataEntry } from '../Enrollment';
import { useCurrentOrgUnitInfo } from '../../../hooks/useCurrentOrgUnitInfo';
import { useRegistrationFormInfoForSelectedScope } from '../common/useRegistrationFormInfoForSelectedScope';
import type { OwnProps } from './EnrollmentRegistrationEntry.types';
import { withSaveHandler } from '../../DataEntry';

const styles = ({ typography }) => ({
marginTop: {
marginTop: typography.pxToRem(2),
},
});
export const EnrollmentRegistrationEntryComponent = ({ selectedScopeId, id, ...rest }: OwnProps) => {
const { scopeType } = useScopeInfo(selectedScopeId);
const { formId, registrationMetaData, formFoundation } = useRegistrationFormInfoForSelectedScope(selectedScopeId);
const orgUnit = useCurrentOrgUnitInfo();

const EnrollmentRegistrationEntryPlain =
({
id,
selectedScopeId,
enrollmentMetadata,
saveButtonText,
classes,
onSave,
...rest
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

suggestion: passOnProps

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Right. I will make a PR in the end renaming all the rest to onProps.

}: {...OwnProps, ...CssClasses}) => {
const { scopeType } = useScopeInfo(selectedScopeId);
useDataEntryLifecycle(selectedScopeId, id, scopeType);
const { formId, formFoundation } = useRegistrationFormInfoForSelectedScope(selectedScopeId);
const orgUnit = useCurrentOrgUnitInfo();

return (
<>
{
scopeType === scopeTypes.TRACKER_PROGRAM && formId &&
<>
<EnrollmentDataEntry
orgUnit={orgUnit}
programId={selectedScopeId}
formFoundation={formFoundation}
enrollmentMetadata={enrollmentMetadata}
id={id}
{...rest}
/>
{
onSave &&
<Button
dataTest="dhis2-capture-create-and-link-button"
primary
onClick={onSave}
className={classes.marginTop}
>
{saveButtonText}
</Button>
Comment on lines +49 to +57
Copy link
Contributor Author

@paschalidi paschalidi Dec 3, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Displaying the buttons only when there is an onSave function.

I dont know what is your preference on this one. To my eyes using HOC component to display the buttons in this case seems kind of an overkill. Dont get me wrong HOC are great but I would use them in cases we want to share something between multiple components like you do on the withLoadingIndicator

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yep, this is fine 👍

}

</>
}
</>
);
};

export const EnrollmentRegistrationEntry: ComponentType<OwnProps> =
compose(
withSaveHandler({ onGetFormFoundation: ({ enrollmentMetadata }) => enrollmentMetadata && enrollmentMetadata.enrollmentForm }),
withStyles(styles),
)(EnrollmentRegistrationEntryPlain);
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
// @flow
import { useDispatch } from 'react-redux';
import React, { useEffect } from 'react';
import type { ComponentType } from 'react';
import { EnrollmentRegistrationEntryComponent } from './EnrollmentRegistrationEntry.component';
import { startNewEnrollmentDataEntryInitialisation } from './EnrollmentRegistrationEntry.actions';
import type { OwnProps } from './EnrollmentRegistrationEntry.types';
import { useScopeInfo } from '../../../hooks/useScopeInfo';
import { useRegistrationFormInfoForSelectedScope } from '../common/useRegistrationFormInfoForSelectedScope';
import { useCurrentOrgUnitInfo } from '../../../hooks/useCurrentOrgUnitInfo';
import { scopeTypes } from '../../../metaData';

const useInitialiseEnrollmentRegistration = (selectedScopeId, dataEntryId) => {
const dispatch = useDispatch();
const { scopeType } = useScopeInfo(selectedScopeId);
const { id: selectedOrgUnitId } = useCurrentOrgUnitInfo();
const { formId, formFoundation } = useRegistrationFormInfoForSelectedScope(selectedScopeId);
const registrationFormReady = !!formId;
useEffect(() => {
if (registrationFormReady && scopeType === scopeTypes.TRACKER_PROGRAM) {
dispatch(
startNewEnrollmentDataEntryInitialisation(
{ selectedOrgUnitId, selectedScopeId, dataEntryId, formFoundation },
),
);
}
}, [
scopeType,
dataEntryId,
selectedScopeId,
selectedOrgUnitId,
registrationFormReady,
formFoundation,
dispatch,
]);
};


export const EnrollmentRegistrationEntry: ComponentType<OwnProps> = ({ selectedScopeId, id, ...rest }) => {
useInitialiseEnrollmentRegistration(selectedScopeId, id);

return (
<EnrollmentRegistrationEntryComponent
selectedScopeId={selectedScopeId}
id={id}
{...rest}
/>);
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
// @flow
import { ofType } from 'redux-observable';
import { pluck, switchMap } from 'rxjs/operators';
import { empty, from } from 'rxjs';
import { errorCreator } from 'capture-core-utils';
import log from 'loglevel';
import i18n from '@dhis2/d2-i18n';
import { enrollmentRegistrationEntryActionTypes } from './EnrollmentRegistrationEntry.actions';
import { openDataEntryForNewEnrollmentBatchAsync } from '../Enrollment';
import { getTrackerProgramThrowIfNotFound } from '../../../metaData/helpers';
import { openDataEntryFailed } from '../../Pages/NewRelationship/RegisterTei/DataEntry/RegisterTeiDataEntry.actions';
import { type TrackerProgram } from '../../../metaData/Program';

export const startNewEnrollmentDataEntrySelfInitialisationEpic = (action$: InputObservable) =>
action$.pipe(
ofType(enrollmentRegistrationEntryActionTypes.TRACKER_PROGRAM_REGISTRATION_ENTRY_INITIALISATION_START),
pluck('payload'),
switchMap(({ selectedOrgUnitId, selectedScopeId: programId, dataEntryId, formFoundation }) => {
if (selectedOrgUnitId) {
let trackerProgram: ?TrackerProgram;
try {
trackerProgram = getTrackerProgramThrowIfNotFound(programId);
} catch (error) {
log.error(
errorCreator('tracker program for id not found')({ programId, error }),
);
return Promise.resolve(openDataEntryFailed(i18n.t('Metadata error. see log for details')));
}

const openEnrollmentPromise = openDataEntryForNewEnrollmentBatchAsync(
trackerProgram,
formFoundation,
{ id: selectedOrgUnitId },
dataEntryId,
);

return from(openEnrollmentPromise);
}

return empty();
}),
);
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
// @flow
import type { RenderFoundation } from '../../../metaData/RenderFoundation';
import type { RegistrationFormMetadata } from '../common/types';

export type OwnProps = $ReadOnly<{|
id: string,
enrollmentMetadata: RegistrationFormMetadata,
selectedScopeId: string,
saveButtonText: string,
fieldOptions?: Object,
onSave: (dataEntryId: string, itemId: string, formFoundation: RenderFoundation) => void,
onPostProcessErrorMessage: Function,
onGetUnsavedAttributeValues: Function,
onUpdateField: Function,
onStartAsyncUpdateField: Function,
|}>
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
// @flow
import { actionCreator } from '../../../actions/actions.utils';

export const teiRegistrationEntryActionTypes = {
TEI_REGISTRATION_ENTRY_INITIALISATION_START: 'StartInitForTrackedEntityTypeRegistrationForm',
};

export const startNewTeiDataEntryInitialisation = ({ selectedOrgUnitId, selectedScopeId, dataEntryId, formFoundation }: Object) =>
actionCreator(teiRegistrationEntryActionTypes.TEI_REGISTRATION_ENTRY_INITIALISATION_START)({ selectedOrgUnitId, selectedScopeId, dataEntryId, formFoundation });
Loading