Skip to content

Commit

Permalink
feat: implement transfers
Browse files Browse the repository at this point in the history
  • Loading branch information
eirikhaugstulen committed Jan 30, 2024
1 parent 95be4b0 commit a36ba4b
Show file tree
Hide file tree
Showing 30 changed files with 680 additions and 364 deletions.
21 changes: 16 additions & 5 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-01-28T18:28:58.743Z\n"
"PO-Revision-Date: 2024-01-28T18:28:58.743Z\n"
"POT-Creation-Date: 2024-01-29T10:42:09.557Z\n"
"PO-Revision-Date: 2024-01-29T10:42:09.557Z\n"

msgid "Choose one or more dates..."
msgstr "Choose one or more dates..."
Expand Down Expand Up @@ -1206,6 +1206,20 @@ msgstr "Finish drawing before saving"
msgid "Set area"
msgstr "Set area"

msgid ""
"Transferring enrollment ownership from {{ownerOrgUnit}} to "
"{{newOrgUnit}}{{escape}}"
msgstr ""
"Transferring enrollment ownership from {{ownerOrgUnit}} to "
"{{newOrgUnit}}{{escape}}"

msgid ""
"You will lose access to the enrollment when transferring ownership to "
"{{organisationUnit}}."
msgstr ""
"You will lose access to the enrollment when transferring ownership to "
"{{organisationUnit}}."

msgid "Transfer Ownership"
msgstr "Transfer Ownership"

Expand Down Expand Up @@ -1393,9 +1407,6 @@ msgstr "This stage can only have one event"
msgid "Events could not be retrieved. Please try again later."
msgstr "Events could not be retrieved. Please try again later."

msgid "Assigned to"
msgstr "Assigned to"

msgid "{{ totalEvents }} events"
msgstr "{{ totalEvents }} events"

Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,14 +10,14 @@
"packages/rules-engine"
],
"dependencies": {
"@dhis2/rules-engine-javascript": "100.53.0",
"@dhis2/app-runtime": "^3.9.3",
"@dhis2/d2-i18n": "^1.1.0",
"@dhis2/d2-icons": "^1.0.1",
"@dhis2/d2-ui-app": "^2.0.0",
"@dhis2/d2-ui-org-unit-tree": "^7.3.3",
"@dhis2/d2-ui-rich-text": "^7.4.0",
"@dhis2/d2-ui-sharing-dialog": "^7.3.3",
"@dhis2/rules-engine-javascript": "100.50.3",
"@dhis2/ui": "^9.1.1",
"@joakim_sm/react-infinite-calendar": "^2.4.2",
"@material-ui/core": "3.9.4",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,7 @@ const OrgUnitFieldPlain = (props: Props) => {
onBlur && onBlur(null);
};


const styles = maxTreeHeight ? { maxHeight: maxTreeHeight, overflowY: 'auto' } : null;
return (
<div
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ export const EnrollmentPageDefaultPlain = ({
onUpdateIncidentDate,
onEnrollmentError,
ruleEffects,
onTransferOutsideCaptureScope,
}: PlainProps) => {
const [mainContentVisible, setMainContentVisibility] = useState(true);
const [addRelationShipContainerElement, setAddRelationshipContainerElement] =
Expand Down Expand Up @@ -149,6 +150,7 @@ export const EnrollmentPageDefaultPlain = ({
onUpdateEnrollmentDate={onUpdateEnrollmentDate}
onUpdateIncidentDate={onUpdateIncidentDate}
onError={onEnrollmentError}
onTransferOutsideCaptureScope={onTransferOutsideCaptureScope}
/>}
</div>
</div>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,10 @@ export const EnrollmentPageDefault = () => {
history.push(`/new?${buildUrlQueryString({ orgUnitId, programId, teiId })}`);
};

const onTransferOutsideCaptureScope = () => {
history.push(`/?${buildUrlQueryString({ orgUnitId, programId })}`);
};

const onEnrollmentError = message => dispatch(showEnrollmentError({ message }));

if (error) {
Expand Down Expand Up @@ -131,6 +135,7 @@ export const EnrollmentPageDefault = () => {
onUpdateIncidentDate={onUpdateIncidentDate}
onEnrollmentError={onEnrollmentError}
ruleEffects={ruleEffects}
onTransferOutsideCaptureScope={onTransferOutsideCaptureScope}
/>
);
};
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ export type Props = {|
onLinkedRecordClick: LinkedRecordClick,
onUpdateEnrollmentDate: (enrollmentDate: string) => void,
onUpdateIncidentDate: (incidentDate: string) => void,
onTransferOutsideCaptureScope: () => void,
onEnrollmentError: (message: string) => void,
ruleEffects?: Array<{id: string, type: $Values<effectActions>}>;
|};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ const EnrollmentAddEventPagePain = ({
onEnrollmentSuccess,
pageFailure,
ready,
onTransferOutsideCaptureScope,
classes,
...passOnProps
}: Props) => (
Expand Down Expand Up @@ -132,6 +133,7 @@ const EnrollmentAddEventPagePain = ({
onAddNew={onAddNew}
onError={onEnrollmentError}
onSuccess={onEnrollmentSuccess}
onTransferOutsideCaptureScope={onTransferOutsideCaptureScope}
/>
</div>
</div>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,10 @@ export const EnrollmentAddEventPageDefault = ({
const onEnrollmentError = message => dispatch(showEnrollmentError({ message }));
const onEnrollmentSuccess = () => dispatch(fetchEnrollments());

const onTransferOutsideCaptureScope = () => {
history.push(`/?${buildUrlQueryString({ orgUnitId, programId })}`);
};

const widgetReducerName = 'enrollmentEvent-newEvent';

const dataEntryHasChanges = useSelector(state => getDataEntryHasChanges(state, widgetReducerName));
Expand Down Expand Up @@ -151,6 +155,7 @@ export const EnrollmentAddEventPageDefault = ({
dataEntryHasChanges={dataEntryHasChanges}
onEnrollmentError={onEnrollmentError}
onEnrollmentSuccess={onEnrollmentSuccess}
onTransferOutsideCaptureScope={onTransferOutsideCaptureScope}
/>
</>
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ export type Props = {|
onDelete: () => void,
onAddNew: () => void,
onEnrollmentError: (message: string) => void,
onTransferOutsideCaptureScope?: () => void,
onEnrollmentSuccess: () => void,
widgetEffects: ?WidgetEffects,
hideWidgets: HideWidgets,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,7 @@ const EnrollmentEditEventPageRight = ({
getAssignedUserSaveContext,
onSaveAssignee,
onSaveAssigneeError,
onTransferOutsideCaptureScope,
addRelationShipContainerElement,
toggleVisibility,
}) => (
Expand Down Expand Up @@ -152,7 +153,8 @@ const EnrollmentEditEventPageRight = ({
addRelationshipRenderElement={addRelationShipContainerElement}
onOpenAddRelationship={toggleVisibility}
onCloseAddRelationship={toggleVisibility}
onAddRelationship={() => {}}
onAddRelationship={() => {
}}
onLinkedRecordClick={onLinkedRecordClick}
/>
)}
Expand All @@ -166,6 +168,7 @@ const EnrollmentEditEventPageRight = ({
onAddNew={onAddNew}
onError={onEnrollmentError}
onSuccess={onEnrollmentSuccess}
onTransferOutsideCaptureScope={onTransferOutsideCaptureScope}
/>
</>
);
Expand Down Expand Up @@ -201,6 +204,7 @@ const EnrollmentEditEventPagePain = ({
getAssignedUserSaveContext,
onSaveAssignee,
onSaveAssigneeError,
onTransferOutsideCaptureScope,
}: PlainProps) => {
const [mainContentVisible, setMainContentVisible] = useState(true);
const [addRelationShipContainerElement, setAddRelationShipContainerElement] = useState<?HTMLDivElement>(undefined);
Expand Down Expand Up @@ -272,6 +276,7 @@ const EnrollmentEditEventPagePain = ({
onSaveAssigneeError={onSaveAssigneeError}
addRelationShipContainerElement={addRelationShipContainerElement}
toggleVisibility={toggleVisibility}
onTransferOutsideCaptureScope={onTransferOutsideCaptureScope}
/>
</div>
</div>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -161,6 +161,9 @@ const EnrollmentEditEventPageWithContextPlain = ({
const assignedUser: ApiAssignedUser = convertClientToServer(newAssignee, dataElementTypes.ASSIGNEE);
dispatch(setAssignee(assignedUser, newAssignee, eventId));
};
const onTransferOutsideCaptureScope = () => {
history.push(`/?${buildUrlQueryString({ orgUnitId, programId })}`);
};
const onSaveAssigneeError = (prevAssignee) => {
const assignedUser: ApiAssignedUser | typeof undefined = prevAssignee
// $FlowFixMe dataElementTypes flow error
Expand Down Expand Up @@ -200,6 +203,7 @@ const EnrollmentEditEventPageWithContextPlain = ({
getAssignedUserSaveContext={getAssignedUserSaveContext}
onSaveAssignee={onSaveAssignee}
onSaveAssigneeError={onSaveAssigneeError}
onTransferOutsideCaptureScope={onTransferOutsideCaptureScope}
/>
);
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ export type PlainProps = {|
onEnrollmentSuccess: () => void,
onCancelEditEvent: (isScheduled: boolean) => void,
onHandleScheduleSave: (eventData: Object) => void,
onTransferOutsideCaptureScope?: () => void,
pageStatus: string,
eventStatus?: string,
eventAccess: {|
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ const styles = {

export const ActionsPlain = ({
enrollment = {},
ownerOrgUnitId,
tetName,
canAddNew,
onUpdate,
Expand Down Expand Up @@ -124,6 +125,7 @@ export const ActionsPlain = ({
{isOpenTransfer && (
<TransferModal
enrollment={enrollment}
ownerOrgUnitId={ownerOrgUnitId}
setOpenTransfer={setOpenTransfer}
onUpdateOwnership={onUpdateOwnership}
/>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,15 @@ export const Actions = ({
onDelete,
onError,
onSuccess,
onTransferOutsideCaptureScope,
...passOnProps
}: Props) => {
const { updateMutation, updateLoading } = useUpdateEnrollment(refetchEnrollment, refetchTEI, onError);
const { deleteMutation, deleteLoading } = useDeleteEnrollment(onDelete, onError);
const { updateEnrollmentOwnership } = useUpdateOwnership({
teiId: enrollment.trackedEntity,
programId: enrollment.program,
onTransferOutsideCaptureScope,
refetchTEI,
});

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,25 @@ import type { QueryRefetchFunction } from '@dhis2/app-runtime';
import i18n from '@dhis2/d2-i18n';
import { useAlert, useDataEngine, useConfig } from '@dhis2/app-runtime';
import { useMutation } from 'react-query';
import { ProgramAccessLevels } from '../../../TransferModal/hooks/useProgramAccessLevel';
import { OrgUnitScopes } from '../../../TransferModal/hooks/useTransferValidation';

type Props = {
teiId: ?string,
programId: ?string,
onTransferOutsideCaptureScope?: () => void,
refetchTEI: QueryRefetchFunction,
}

export type UpdateEnrollmentOwnership = {|
orgUnitId: string,
programAccessLevel: ?$Values<typeof ProgramAccessLevels>,
orgUnitScopes: {
ORIGIN: ?$Values<typeof OrgUnitScopes>,
DESTINATION: ?$Values<typeof OrgUnitScopes>,
},
|} => void;


const UpdateEnrollmentOwnershipMutation = {
resource: 'tracker/ownership/transfer',
Expand All @@ -32,51 +44,22 @@ const UpdateEnrollmentOwnershipMutation = {
},
};

export const useUpdateOwnership = ({ refetchTEI, programId, teiId }: Props) => {
export const useUpdateOwnership = ({
refetchTEI,
programId,
teiId,
onTransferOutsideCaptureScope,
}: Props): { updateEnrollmentOwnership: UpdateEnrollmentOwnership } => {
const dataEngine = useDataEngine();
const { apiVersion } = useConfig();
const { show: showErrorAlert } = useAlert(
i18n.t('An error occurred while transferring ownership'),
{ critical: true },
);
const orgUnitIsInScope = async (orgUnitId: string) => {
const captureScopeQuery = dataEngine.query({
orgUnits: {
resource: 'organisationUnits',
params: {
paging: false,
userOnly: true,
fields: 'id,displayName',
},
},
});

const ancestorsQuery = dataEngine.query({
ancestors: {
resource: 'organisationUnits',
id: orgUnitId,
params: {
fields: 'ancestors[id,displayName]',
},
},
});

const result = await Promise.all([
captureScopeQuery,
ancestorsQuery,
]);

const [{ orgUnits: { organisationUnits } }, { ancestors: { ancestors } }] = result;
ancestors.push({ id: orgUnitId });
debugger;
return ancestors.some(({ id: ancestorId }) => organisationUnits.some(({ id }) => {
return ancestorId === id;
}));
};

// $FlowFixMe
const { mutate: updateEnrollmentOwnership } = useMutation(
(orgUnitId: string) => dataEngine.mutate(UpdateEnrollmentOwnershipMutation, {
({ orgUnitId }) => dataEngine.mutate(UpdateEnrollmentOwnershipMutation, {
variables: {
programId,
teiId,
Expand All @@ -85,12 +68,33 @@ export const useUpdateOwnership = ({ refetchTEI, programId, teiId }: Props) => {
},
}),
{
onMutate: (orgUnitId) => {
orgUnitIsInScope(orgUnitId).then((isInScope) => {
if (isInScope) {
onMutate: ({ programAccessLevel, orgUnitScopes }) => {
// If the user is transferring ownership to a capture scope, we stay on the same page
if (orgUnitScopes.DESTINATION === OrgUnitScopes.CAPTURE) {
refetchTEI();
return;
}

if ([ProgramAccessLevels.OPEN, ProgramAccessLevels.AUDITED].includes(programAccessLevel)) {
refetchTEI();
return;
}

// Assuming that all cases are outside the capture scope and program is protected or closed

if (programAccessLevel === ProgramAccessLevels.PROTECTED) {
if (orgUnitScopes.ORIGIN === OrgUnitScopes.CAPTURE) {
onTransferOutsideCaptureScope && onTransferOutsideCaptureScope();
return;
} else if (orgUnitScopes.ORIGIN === OrgUnitScopes.SEARCH) {
refetchTEI();
return;
}
});
}

if (programAccessLevel === ProgramAccessLevels.CLOSED) {
onTransferOutsideCaptureScope && onTransferOutsideCaptureScope();
}
},
onError: () => showErrorAlert(),
},
Expand Down
Loading

0 comments on commit a36ba4b

Please sign in to comment.