Skip to content

Commit

Permalink
fix: DHIS2-10206 displays dialog when data has entered and user is ex…
Browse files Browse the repository at this point in the history
…iting the page (#1592)

* docs: Update README

* refactor: exports shared steps & fixes all tests (#1483)

* chore: only the fail true is on

* chore: fixes existing tests

* chore: reduces time

* chore: drops time more

* chore: adds 1000 ms

* chore: bring time to 20000

* chore: fixes new page

* chore: bring time down to 7000

* chore: time is 12000

* chore: timer is 14000

* chore: time equals 12000

* feat: extracts the functions

* chore: drops time to 6000

* chore: up to 12000

* chore: 15000

* chore: rebase and splits the shared steps

* chore: addmission date and missing steps

* chore: random and

* chore: fixes the tests

* chore: typo

* fix: program error bug (#1532)

* chore: solves the bug

* chore: covers with tests

* chore: adds missing test cases

* chore: removes the dhis2-capture- prefix (#1410)

* fix: the bug (#1536)

* chore(release): cut 1.15.1 [skip ci]

* the bug ([#1536](#1536)) ([fd2616f](fd2616f))

* chore: forward-ports the last two PRs  (#1588)

* fix: DHIS2-10738 pressing the back button after a fallback crashes app (#1581)

* chore: sets to false

* chore: covers bug case

* fix: the bug (#1580)

* chore: fix the rerun (#1589)

* chore: reverts

* chore: saves

* chore: fixes the bug

* chore: removes unused onCleanup

* chore: improves

* chore: cleans up and lints

* chore: fixes

* chore: imports from correct action

* chore: cleans up also on unmount

* chore: adds curr state

* chore: cleans up

* fix: the crash by removing only the correct entries on cleanUp

* chore: fixes the problem with the window

Co-authored-by: Joakim Storløkken Melseth <joakim@dhis2.org>
Co-authored-by: @dhis2-bot <apps@dhis2.org>
Co-authored-by: Joakim Storløkken Melseth <joakim.melseth@gmail.com>
  • Loading branch information
4 people committed Apr 20, 2021
1 parent ec3fdf8 commit 4027bdd
Show file tree
Hide file tree
Showing 21 changed files with 143 additions and 133 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ import { actionCreator } from '../../../actions/actions.utils';
export const actionTypes = {
FIELDS_VALIDATED: 'FieldsValidated',
FIELD_IS_VALIDATING: 'FieldIsValidating',
CLEAN_UP_FORM_BUILDER: 'CleanUpFormBuilder',
START_UPDATE_FIELD_ASYNC: 'StartUpdateFieldAsync',
UPDATE_FIELD_FROM_ASYNC: 'UpdateFieldFromAsync',
ASYNC_UPDATE_FIELD_FAILED: 'AsyncUpdateFieldFailed',
Expand Down Expand Up @@ -39,10 +38,6 @@ export const fieldsValidated = (
actionCreator(actionTypes.FIELDS_VALIDATED)(
{ fieldsUI, formBuilderId, formId, validatingUids });

export const cleanUpFormBuilder = (remainingUids: Array<string>, formId: string) =>
actionCreator(actionTypes.CLEAN_UP_FORM_BUILDER)(
{ remainingUids, formId });

export const startUpdateFieldAsync = (
elementId: string,
fieldLabel: string,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,12 @@
import * as React from 'react';
import { connect } from 'react-redux';
import uuid from 'uuid/v4';
import { fieldIsValidating, fieldsValidated, cleanUpFormBuilder, startUpdateFieldAsync } from './actions';
import { fieldIsValidating, fieldsValidated, startUpdateFieldAsync } from './actions';

type Props = {
id: string,
onIsValidating: Function,
onFieldsValidated: Function,
onCleanUp: Function,
onUpdateFieldAsyncInner: Function,
onUpdateFieldAsync: ?Function,
};
Expand All @@ -28,12 +27,6 @@ const getAsyncHandler = (InnerComponent: React.ComponentType<any>) =>
this.props.onFieldsValidated(...args, id);
}

// $FlowFixMe[missing-annot] automated comment
handleCleanUp = (...args) => {
const { id } = this.props;
this.props.onCleanUp(...args, id);
}

// $FlowFixMe[missing-annot] automated comment
handleUpdateFieldAsyncInner = (...args) => {
const { onUpdateFieldAsyncInner, onUpdateFieldAsync } = this.props;
Expand All @@ -44,7 +37,6 @@ const getAsyncHandler = (InnerComponent: React.ComponentType<any>) =>
const {
onIsValidating,
onFieldsValidated,
onCleanUp,
onUpdateFieldAsyncInner,
onUpdateFieldAsync,
...passOnProps } = this.props;
Expand All @@ -54,7 +46,6 @@ const getAsyncHandler = (InnerComponent: React.ComponentType<any>) =>
onIsValidating={this.handleIsValidating}
onFieldsValidated={this.handleFieldsValidated}
onUpdateFieldAsync={this.handleUpdateFieldAsyncInner}
onCleanUp={this.handleCleanUp}
{...passOnProps}
/>
);
Expand Down Expand Up @@ -84,12 +75,6 @@ const mapDispatchToProps = (dispatch: ReduxDispatch) => ({
const action = fieldsValidated(fieldsUI, formBuilderId, formId, validatingUids);
dispatch(action);
},
onCleanUp: (
remainingUids: Array<string>,
formId: string,
) => {
dispatch(cleanUpFormBuilder(remainingUids, formId));
},
onUpdateFieldAsyncInner: (
fieldId: string,
fieldLabel: string,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,8 @@ export const batchActionTypes = {
ADD_RELATIONSHIP_BATCH: 'AddNewEventRelationshipBatch',
};

export const newEventCancelNewRelationship = () =>
actionCreator(actionTypes.NEW_EVENT_CANCEL_NEW_RELATIONSHIP)({});
export const newEventCancelNewRelationship = (dataEntryId: string) =>
actionCreator(actionTypes.NEW_EVENT_CANCEL_NEW_RELATIONSHIP)({ dataEntryId });

export const addNewEventRelationship = (relationshipType: { id: string, name: string }, entity: Object, entityType: string) =>
actionCreator(actionTypes.ADD_NEW_EVENT_RELATIONSHIP)({ relationshipType, entity, entityType });
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,8 @@ const getStyles = theme => ({
});

type Props = {
onCancel: () => void,
onCancel: (dataEntryid: string) => void,
dataEntryKey: string,
classes: {
headerContainer: string,
header: string,
Expand Down Expand Up @@ -122,7 +123,7 @@ class NewEventNewRelationshipWrapper extends React.Component<Props, State> {
text={i18n.t('Leaving this page will discard the selections you made for a new relationship')}
confirmText={i18n.t('Yes, discard')}
cancelText={i18n.t('No, stay here')}
onConfirm={this.props.onCancel}
onConfirm={() => this.props.onCancel('relationship')}
open={!!this.state.discardDialogOpen}
onCancel={this.handleCancelDiscard}
/>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,8 @@ const makeMapStateToProps = () => {
};

const mapDispatchToProps = (dispatch: ReduxDispatch) => ({
onCancel: () => {
dispatch(newEventCancelNewRelationship());
onCancel: (dataEntryId: string) => {
dispatch(newEventCancelNewRelationship(dataEntryId));
},
onAddRelationship: (relationshipType: { id: string, name: string}, entity: Object, entityType: string) => {
dispatch(addNewEventRelationship(relationshipType, entity, entityType));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import i18n from '@dhis2/d2-i18n';
import { compose } from 'redux';
import { SingleEventRegistrationEntryComponent } from './SingleEventRegistrationEntry.component';
import withBrowserBackWarning from '../../../HOC/withBrowserBackWarning';
import dataEntryHasChanges from '../../DataEntry/common/dataEntryHasChanges';
import { dataEntryHasChanges } from '../../DataEntry/common/dataEntryHasChanges';
import { makeEventAccessSelector } from './SingleEventRegistrationEntry.selectors';
import { withLoadingIndicator } from '../../../HOC';

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
import { connect } from 'react-redux';
import CancelButton from './CancelButton.component';
import getDataEntryKey from './common/getDataEntryKey';
import dataEntryHasChanges from './common/dataEntryHasChanges';
import { dataEntryHasChanges } from './common/dataEntryHasChanges';

const mapStateToProps = (state: ReduxState, props: {id: string}) => {
const itemId = state.dataEntries && state.dataEntries[props.id] && state.dataEntries[props.id].itemId;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,15 @@
// @flow

export default (state: ReduxState, key: string) => {
export const dataEntryHasChanges = (state: ReduxState, key: string): boolean => {
const reduced = Object.keys(state.formsSectionsFieldsUI)
.filter(formSectionUI => formSectionUI.startsWith(key))
.reduce((accElementsUI, sectionKey) => [...accElementsUI, ...Object.keys(state.formsSectionsFieldsUI[sectionKey]).map(elementKey => state.formsSectionsFieldsUI[sectionKey][elementKey])], []);
.reduce((accElementsUI, sectionKey) =>
[
...accElementsUI,
...Object.keys(state.formsSectionsFieldsUI[sectionKey])
.map(elementKey => state.formsSectionsFieldsUI[sectionKey][elementKey]),
]
, []);

const formIsModified = reduced.some(element => element.modified);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { withRouter } from 'react-router';

import ConfirmDialog from '../Dialogs/ConfirmDialog.component';
import getDataEntryKey from './common/getDataEntryKey';
import getDataEntryHasChanges from './common/dataEntryHasChanges';
import { dataEntryHasChanges as getDataEntryHasChanges } from './common/dataEntryHasChanges';

type Props = {
dataEntryHasChanges: boolean,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
// @flow
import React, { Component } from 'react';
import { withStyles } from '@material-ui/core';
import Dialog from '@material-ui/core/Dialog';
import DialogActions from '@material-ui/core/DialogActions';
import DialogContent from '@material-ui/core/DialogContent';
Expand All @@ -17,6 +18,9 @@ type Props = {
onConfirm: () => void,
};

const StyledDialog = withStyles({ root: { zIndex: 3000 } })(Dialog);
const StyledDialogActions = withStyles({ root: { margin: '8px 8px 12px 0' } })(DialogActions);

class ConfirmDialog extends Component<Props> {
render() {
const {
Expand All @@ -30,7 +34,7 @@ class ConfirmDialog extends Component<Props> {
} = this.props;

return (
<Dialog
<StyledDialog
open={open}
onClose={onCancel}
>
Expand All @@ -40,17 +44,17 @@ class ConfirmDialog extends Component<Props> {
{text}
</DialogContentText>
</DialogContent>
<DialogActions>
<StyledDialogActions>
<Button onClick={onCancel} secondary>
{cancelText}
</Button>
<Button onClick={onConfirm} primary>
{confirmText}
</Button>
</DialogActions>
</Dialog>
</StyledDialogActions>
</StyledDialog>
);
}
}

export default (ConfirmDialog);
export default ConfirmDialog;
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,38 @@ class LockedSelectorClass extends Component<Props, State> {
this.setState({ openStartAgainWarning: true });
}

openNewRegistrationPage = () => {
if (this.props.isUserInteractionInProgress) {
this.setState({ openStartAgainWarning: true });
return;
}
this.props.onOpenNewEventPage();
}

handleOpenNewRegistrationPageWithoutProgramId = () => {
if (this.dontShowWarning()) {
this.props.onOpenNewRegistrationPageWithoutProgramId();
return;
}
this.setState({ openStartAgainWarning: true });
}

handleOpenSearchPage = () => {
if (this.dontShowWarning()) {
this.props.onOpenSearchPage();
return;
}
this.setState({ openStartAgainWarning: true });
}

handleOpenSearchPageWithoutProgramId = () => {
if (this.dontShowWarning()) {
this.props.onOpenSearchPageWithoutProgramId();
return;
}
this.setState({ openStartAgainWarning: true });
}

handleOpenOrgUnitWarning = () => {
if (this.dontShowWarning()) {
this.props.onResetOrgUnitId();
Expand Down Expand Up @@ -95,32 +127,11 @@ class LockedSelectorClass extends Component<Props, State> {
this.handleClose();
}

openNewRegistrationPage = () => {
if (this.props.isUserInteractionInProgress) {
this.setState({ openNewEventWarning: true });
return;
}
this.props.onOpenNewEventPage();
}

handleOpenNewRegistrationPageWithoutProgramId = () => {
this.props.onOpenNewRegistrationPageWithoutProgramId();
}

handleAcceptNew = () => {
this.props.onOpenNewEventPage();
this.handleClose();
}

handleOpenSearchPage = () => {
this.props.onOpenSearchPage();
}

handleOpenSearchPageWithoutProgramId = () => {
this.props.onOpenSearchPageWithoutProgramId();
}


render() {
const { onSetOrgUnit, onSetProgramId, onSetCategoryOption, onResetAllCategoryOptions } = this.props;
return (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ export const LockedSelector: ComponentType<OwnProps> =
customActionsOnProgramIdReset = [],
customActionsOnOrgUnitIdReset = [],
pageToPush = '',
isUserInteractionInProgress = false,
}) => {
const dispatch = useDispatch();

Expand Down Expand Up @@ -187,6 +188,7 @@ export const LockedSelector: ComponentType<OwnProps> =
onSetOrgUnit={dispatchOnSetOrgUnit}
selectedOrgUnitId={selectedOrgUnitId}
selectedProgramId={selectedProgramId}
isUserInteractionInProgress={isUserInteractionInProgress}
ready={ready}
/>
);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
import { actionCreator } from '../../../actions/actions.utils';

export const newPageActionTypes = {
NEW_PAGE_WITHOUT_ORG_UNIT_SELECTED_VIEW: 'NewPageWithoutOrgUnitSelectedView',
NEW_PAGE_WITHOUT_PROGRAM_CATEGORY_SELECTED_VIEW: 'NewPageWithoutProgramComboSelectedView',
NEW_PAGE_DEFAULT_VIEW: 'NewPageDefaultView',
NEW_PAGE_WITHOUT_ORG_UNIT_SELECTED_VIEW: 'NewPage.WithoutOrgUnitSelectedView',
NEW_PAGE_WITHOUT_PROGRAM_CATEGORY_SELECTED_VIEW: 'NewPage.WithoutProgramComboSelectedView',
NEW_PAGE_DEFAULT_VIEW: 'NewPage.DefaultView',
CLEAN_UP_DATA_ENTRY: 'NewPage.DataEntryCleanUp',
};


Expand All @@ -15,3 +16,5 @@ export const showMessageToSelectProgramCategoryOnNewPage = () =>

export const showDefaultViewOnNewPage = () =>
actionCreator(newPageActionTypes.NEW_PAGE_DEFAULT_VIEW)();

export const cleanUpDataEntry = dataEntryId => actionCreator(newPageActionTypes.CLEAN_UP_DATA_ENTRY)({ dataEntryId });
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import { useScopeInfo } from '../../../hooks/useScopeInfo';
import { RegistrationDataEntry } from './RegistrationDataEntry';
import { NoWriteAccessMessage } from '../../NoWriteAccessMessage';
import { IncompleteSelectionsMessage } from '../../IncompleteSelectionsMessage';
import { cleanUpDataEntry } from './NewPage.actions';

const getStyles = () => ({
container: {
Expand All @@ -21,6 +22,8 @@ const getStyles = () => ({
});

export const NEW_TEI_DATA_ENTRY_ID = 'newPageDataEntryId';
export const NEW_SINGLE_EVENT_DATA_ENTRY_ID = 'singleEvent';
export const NEW_RELATIONSHIP_EVENT_DATA_ENTRY_ID = 'relationship';

const NewPagePlain = ({
showMessageToSelectOrgUnitOnNewPage,
Expand All @@ -34,6 +37,7 @@ const NewPagePlain = ({
programCategorySelectionIncomplete,
missingCategoriesInProgramSelection,
orgUnitSelectionIncomplete,
isUserInteractionInProgress,
}: Props) => {
const { scopeType } = useScopeInfo(currentScopeId);
const [selectedScopeId, setScopeId] = useState(currentScopeId);
Expand All @@ -60,7 +64,20 @@ const NewPagePlain = ({
]);

return (<>
<LockedSelector pageToPush="new" />
<LockedSelector
pageToPush="new"
isUserInteractionInProgress={isUserInteractionInProgress}
customActionsOnProgramIdReset={[
cleanUpDataEntry(NEW_TEI_DATA_ENTRY_ID),
cleanUpDataEntry(NEW_SINGLE_EVENT_DATA_ENTRY_ID),
cleanUpDataEntry(NEW_RELATIONSHIP_EVENT_DATA_ENTRY_ID),
]}
customActionsOnOrgUnitIdReset={[
cleanUpDataEntry(NEW_TEI_DATA_ENTRY_ID),
cleanUpDataEntry(NEW_SINGLE_EVENT_DATA_ENTRY_ID),
cleanUpDataEntry(NEW_RELATIONSHIP_EVENT_DATA_ENTRY_ID),
]}
/>
<div data-test="dhis2-capture-registration-page-content" className={classes.container} >
{
!writeAccess ?
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import { useCurrentOrgUnitInfo } from '../../../hooks/useCurrentOrgUnitInfo';
import { useCurrentProgramInfo } from '../../../hooks/useCurrentProgramInfo';
import { getScopeFromScopeId, TrackerProgram, TrackedEntityType } from '../../../metaData';
import { useMissingCategoriesInProgramSelection } from '../../../hooks/useMissingCategoriesInProgramSelection';
import { dataEntryHasChanges } from '../../DataEntry/common/dataEntryHasChanges';

const useUserWriteAccess = (scopeId) => {
const scope = getScopeFromScopeId(scopeId);
Expand Down Expand Up @@ -80,6 +81,16 @@ export const NewPage: ComponentType<{||}> = () => {
};

const writeAccess = useUserWriteAccess(currentScopeId);

const isUserInteractionInProgress: boolean = useSelector(
state =>
dataEntryHasChanges(state, 'singleEvent-newEvent')
|| dataEntryHasChanges(state, 'relationship-newTei')
|| dataEntryHasChanges(state, 'relationship-newEvent')
|| dataEntryHasChanges(state, 'newPageDataEntryId-newEnrollment')
|| dataEntryHasChanges(state, 'newPageDataEntryId-newTei'),
);

return (
<NewPageComponent
showMessageToSelectOrgUnitOnNewPage={dispatchShowMessageToSelectOrgUnitOnNewPage}
Expand All @@ -94,5 +105,6 @@ export const NewPage: ComponentType<{||}> = () => {
newPageStatus={newPageStatus}
error={error}
ready={ready}
isUserInteractionInProgress={isUserInteractionInProgress}
/>);
};
Loading

0 comments on commit 4027bdd

Please sign in to comment.