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-18017] Ability to unlink event from edit/view event page #3846

Merged
merged 27 commits into from
Dec 17, 2024
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
519196d
feat: add menu items for unlik and delete event
henrikmv Oct 14, 2024
31f0b4a
feat: temp
henrikmv Oct 18, 2024
919a15d
Merge branch 'master' of https://github.com/dhis2/capture-app into hv…
henrikmv Oct 18, 2024
2509447
feat: delete and unlink function
henrikmv Oct 18, 2024
8c02716
Merge branch 'master' of https://github.com/dhis2/capture-app into hv…
henrikmv Oct 21, 2024
dba31d1
fix: review changes
henrikmv Oct 28, 2024
9d443b1
fix: remove update data
henrikmv Oct 28, 2024
74a1fe9
fix: use invalidatequeries
henrikmv Oct 30, 2024
f993afd
Merge branch 'master' of https://github.com/dhis2/capture-app into hv…
henrikmv Oct 30, 2024
e39d360
fix: remove noticebox and add alerterror
henrikmv Oct 30, 2024
4cd3f98
feat: add validation
henrikmv Nov 4, 2024
4c596fc
fix: indexeddb write access
henrikmv Nov 5, 2024
7a7678b
Merge branch 'master' of https://github.com/dhis2/capture-app into hv…
henrikmv Nov 6, 2024
f6c9610
fix: review comments
henrikmv Nov 6, 2024
73eb06b
fix: user message improvements
henrikmv Nov 27, 2024
e3284e9
Merge remote-tracking branch 'origin/master' into hv/feat/DHIS2-18017…
henrikmv Dec 5, 2024
1ce3a78
Revert "Merge remote-tracking branch 'origin/master' into hv/feat/DHI…
henrikmv Dec 5, 2024
1a3db3f
fix: merge conflict
henrikmv Dec 5, 2024
87f249a
Merge branch 'master' into hv/feat/DHIS2-18017_AbilityToUnlinkEvent
henrikmv Dec 5, 2024
9143053
fix: dublicate code
henrikmv Dec 5, 2024
a0c848f
feat: update dhis ui
henrikmv Dec 6, 2024
1890238
Merge remote-tracking branch 'origin/master' into hv/feat/DHIS2-18017…
henrikmv Dec 9, 2024
93579fa
fix: merge error in package json
henrikmv Dec 10, 2024
c502b84
Merge remote-tracking branch 'origin/master' into hv/feat/DHIS2-18017…
henrikmv Dec 14, 2024
aec168d
Merge remote-tracking branch 'origin/master' into hv/feat/DHIS2-18017…
henrikmv Dec 16, 2024
6b7dd5f
Revert "feat: update dhis ui"
henrikmv Dec 17, 2024
df83ca1
fix: revert changes in version after dhis2 ui update
henrikmv Dec 17, 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
48 changes: 41 additions & 7 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-10-14T14:53:34.553Z\n"
"PO-Revision-Date: 2024-10-14T14:53:34.553Z\n"
"POT-Creation-Date: 2024-10-18T08:53:26.831Z\n"
"PO-Revision-Date: 2024-10-18T08:53:26.831Z\n"

msgid "Choose one or more dates..."
msgstr "Choose one or more dates..."
Expand Down Expand Up @@ -1483,12 +1483,49 @@ msgstr "{{ scheduledEvents }} scheduled"
msgid "Stages and Events"
msgstr "Stages and Events"

msgid "An error occurred while loading the widget."
msgstr "An error occurred while loading the widget."
msgid ""
"Are you sure you want to unlink and delete the event? This will permanently "
"remove the event and all related data."
msgstr ""
"Are you sure you want to unlink and delete the event? This will permanently "
"remove the event and all related data."

msgid "There was a problem unlinking and deleting the event"
msgstr "There was a problem unlinking and deleting the event"

msgid "Yes, unlink and delete event"
msgstr "Yes, unlink and delete event"

msgid "An error occurred while unlinking the relationship."
msgstr "An error occurred while unlinking the relationship."

msgid "Unlink relationship"
msgstr "Unlink relationship"

msgid "Are you sure you want to unlink this relationship?"
msgstr "Are you sure you want to unlink this relationship?"

msgid "There was a problem unlinking the relationship"
msgstr "There was a problem unlinking the relationship"

msgid "Yes, unlink relationship"
msgstr "Yes, unlink relationship"

msgid "An error occurred while deleting the relationship."
msgstr "An error occurred while deleting the relationship."

msgid "View linked event"
msgstr "View linked event"

msgid "Unlink event"
msgstr "Unlink event"

msgid "Unlink and delete event"
msgstr "Unlink and delete event"

msgid "An error occurred while loading the widget."
msgstr "An error occurred while loading the widget."

msgid "Scheduled"
msgstr "Scheduled"

Expand Down Expand Up @@ -1559,9 +1596,6 @@ msgstr ""
msgid "Yes, delete relationship"
msgstr "Yes, delete relationship"

msgid "An error occurred while deleting the relationship."
msgstr "An error occurred while deleting the relationship."

msgid "To open this relationship, please wait until saving is complete"
msgstr "To open this relationship, please wait until saving is complete"

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ type Props = {
...CssClasses,
}

export const ScheduleInOrgUnitPlain = ({
const ScheduleInOrgUnitPlain = ({
relatedStagesDataValues,
setRelatedStagesDataValues,
saveAttempted,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
// @flow
import React, { useState } from 'react';
import i18n from '@dhis2/d2-i18n';
import {
Button,
ButtonStrip,
Modal,
ModalActions,
ModalContent,
ModalTitle,
NoticeBox,
} from '@dhis2/ui';
import { useDataEngine } from '@dhis2/app-runtime';
import type { Props } from './UnlinkAndDeleteModal.types';

export const UnlinkAndDeleteModal = ({
setOpenModal,
eventId,
setUpdateData,
}: Props) => {
const [errorReports, setErrorReports] = useState([]);
const [loading, setLoading] = useState(false);
const dataEngine = useDataEngine();

const handleDelete = async () => {
setLoading(true);
setErrorReports([]);
setUpdateData(true);

try {
const mutation = {
resource: '/tracker?async=false&importStrategy=DELETE',
type: 'create',
data: { events: [{ event: eventId }] },
};

await dataEngine.mutate(mutation);
setOpenModal(false);
} catch (error) {
const messages = error.details?.response?.errorReports?.map(report => report.message) || [
error.message,
];
setErrorReports(messages);
} finally {
setLoading(false);
setUpdateData(false);
}
};
henrikmv marked this conversation as resolved.
Show resolved Hide resolved

return (
<Modal dataTest="event-unlink-and-delete-modal" position="middle">
henrikmv marked this conversation as resolved.
Show resolved Hide resolved
<ModalTitle>{i18n.t('Delete event')}</ModalTitle>
<ModalContent>
<p>
{i18n.t(
'Are you sure you want to unlink and delete the event? This will permanently remove the event and all related data.',
)}
</p>
{errorReports.length > 0 && (
<NoticeBox
title={i18n.t('There was a problem unlinking and deleting the event')}
error
>
<ul>
{errorReports.map((message, index) => (
// eslint-disable-next-line react/no-array-index-key
<li key={index}>{message}</li>
))}
</ul>
</NoticeBox>
)}
</ModalContent>
<ModalActions>
<ButtonStrip end>
<Button onClick={() => setOpenModal(false)} secondary disabled={loading}>
{i18n.t('No, cancel')}
</Button>
<Button destructive onClick={handleDelete} disabled={loading}>
{i18n.t('Yes, unlink and delete event')}
</Button>
</ButtonStrip>
</ModalActions>
</Modal>
);
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
// @flow
export type Props = {|
setOpenModal: (open: boolean) => void,
eventId: string,
setUpdateData: Function,
|};
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
// @flow
import React, { useState } from 'react';
import i18n from '@dhis2/d2-i18n';
import {
Modal,
ModalContent,
ModalTitle,
ModalActions,
ButtonStrip,
Button,
NoticeBox,
} from '@dhis2/ui';
import { useDeleteRelationship } from './useDeleteRelationship';
import type { Props } from './UnlinkModal.types';

export const UnlinkModal = ({
setOpenModal,
relationshipId,
setUpdateData,
}: Props) => {
const [loading, setLoading] = useState(false);
const [errorMessage, setErrorMessage] = useState(null);

const { onDeleteRelationship } = useDeleteRelationship({ sourceId: relationshipId });

const handleUnlink = async () => {
setLoading(true);
setErrorMessage(null);
setUpdateData(true);

try {
await onDeleteRelationship({ relationshipId });
setOpenModal(false);
} catch (error) {
setErrorMessage(i18n.t('An error occurred while unlinking the relationship.'));
setLoading(false);
} finally {
setLoading(false);
setUpdateData(false);
}
};

return (
<Modal dataTest="event-unlink-modal">
<ModalTitle>
{i18n.t('Unlink relationship')}
</ModalTitle>
<ModalContent>
<p>{i18n.t('Are you sure you want to unlink this relationship?')}</p>
henrikmv marked this conversation as resolved.
Show resolved Hide resolved
{errorMessage && (
<NoticeBox
title={i18n.t('There was a problem unlinking the relationship')}
error
>
{errorMessage}
</NoticeBox>
)}
</ModalContent>
<ModalActions>
<ButtonStrip end>
<Button onClick={() => setOpenModal(false)} secondary>
{i18n.t('No, cancel')}
</Button>
<Button destructive onClick={handleUnlink} disabled={loading}>
{i18n.t('Yes, unlink relationship')}
</Button>
</ButtonStrip>
</ModalActions>
</Modal>
);
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
// @flow
export type Props = {|
setOpenModal: (open: boolean) => void,
relationshipId: string,
setUpdateData: Function,
|};
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
// @flow
export { UnlinkModal } from './UnlinkModal';
export { UnlinkAndDeleteModal } from './UnlinkAndDeleteModal';
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
// @flow
import i18n from '@dhis2/d2-i18n';
import log from 'loglevel';
import { errorCreator, FEATURES, useFeature } from 'capture-core-utils';
import { handleAPIResponse, REQUESTED_ENTITIES } from 'capture-core/utils/api';
import { useMutation, useQueryClient } from 'react-query';
import { useAlert, useDataEngine } from '@dhis2/app-runtime';
import { ReactQueryAppNamespace } from '../../../../utils/reactQueryHelpers';

type Props = {
sourceId: string,
};

export type OnDeleteRelationship = ({ relationshipId: string }) => void;

const deleteRelationshipMutation = {
resource: 'tracker?importStrategy=DELETE&async=false',
type: 'create',
data: ({ relationshipId }) => ({
relationships: [
{
relationship: relationshipId,
},
],
}),
};

export const useDeleteRelationship = ({ sourceId }: Props): { onDeleteRelationship: OnDeleteRelationship } => {
const dataEngine = useDataEngine();
const queryKey: string = useFeature(FEATURES.exportablePayload) ? 'relationships' : 'instances';
const queryClient = useQueryClient();
const { show: showError } = useAlert(
i18n.t('An error occurred while deleting the relationship.'),
{
critical: true,
},
);
const { mutate: onDeleteRelationship } = useMutation(
({ relationshipId }) => dataEngine.mutate(deleteRelationshipMutation, { variables: { relationshipId } }),
{
onMutate: ({ relationshipId }) => {
const prevRelationships = queryClient
.getQueryData([ReactQueryAppNamespace, 'relationships', sourceId]);

const apiRelationships = handleAPIResponse(REQUESTED_ENTITIES.relationships, prevRelationships);

const newRelationships = apiRelationships
?.filter(({ relationship }) => relationship !== relationshipId);

queryClient.setQueryData(
[ReactQueryAppNamespace, 'relationships', sourceId],
{ [queryKey]: newRelationships });

return { prevRelationships };
},
onError: (error, { relationshipId }, context) => {
log.error(errorCreator('An error occurred while deleting the relationship')({ error, relationshipId }));
showError();

if (!context?.prevRelationships) return;
queryClient.setQueryData(
[ReactQueryAppNamespace, 'relationships', sourceId],
context.prevRelationships,
);
},
},
henrikmv marked this conversation as resolved.
Show resolved Hide resolved
);

return { onDeleteRelationship };
};
Loading
Loading