diff --git a/i18n/en.pot b/i18n/en.pot index 3bee26bc80..5fb403e3d7 100644 --- a/i18n/en.pot +++ b/i18n/en.pot @@ -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-25T18:18:11.518Z\n" +"PO-Revision-Date: 2024-10-25T18:18:11.518Z\n" msgid "Choose one or more dates..." msgstr "Choose one or more dates..." @@ -1133,6 +1133,9 @@ msgstr "Mark as cancelled" msgid "Mark incomplete" msgstr "Mark incomplete" +msgid "You do not have access to delete this enrollment" +msgstr "You do not have access to delete this enrollment" + msgid "Delete enrollment" msgstr "Delete enrollment" diff --git a/src/core_modules/capture-core/components/WidgetEnrollment/Actions/Actions.component.js b/src/core_modules/capture-core/components/WidgetEnrollment/Actions/Actions.component.js index d95f39c8fb..e3e08de57d 100644 --- a/src/core_modules/capture-core/components/WidgetEnrollment/Actions/Actions.component.js +++ b/src/core_modules/capture-core/components/WidgetEnrollment/Actions/Actions.component.js @@ -39,6 +39,7 @@ export const ActionsPlain = ({ onUpdate, onDelete, onUpdateOwnership, + canCascadeDeleteEnrollment, isTransferLoading, onAddNew, loading, @@ -115,6 +116,7 @@ export const ActionsPlain = ({ onUpdate={handleOnUpdateStatus} /> diff --git a/src/core_modules/capture-core/components/WidgetEnrollment/Actions/Actions.container.js b/src/core_modules/capture-core/components/WidgetEnrollment/Actions/Actions.container.js index 79df428da7..b7ad956d52 100644 --- a/src/core_modules/capture-core/components/WidgetEnrollment/Actions/Actions.container.js +++ b/src/core_modules/capture-core/components/WidgetEnrollment/Actions/Actions.container.js @@ -4,6 +4,7 @@ import { ActionsComponent } from './Actions.component'; import type { Props } from './actions.types'; import { useUpdateEnrollment, useDeleteEnrollment } from '../dataMutation/dataMutation'; import { useUpdateOwnership } from './Transfer/hooks'; +import { useAuthorities } from '../../../utils/authority/useAuthorities'; export const Actions = ({ enrollment = {}, @@ -20,6 +21,7 @@ export const Actions = ({ }: Props) => { const { updateMutation, updateLoading } = useUpdateEnrollment(refetchEnrollment, refetchTEI, onError, onSuccess); const { deleteMutation, deleteLoading } = useDeleteEnrollment(onDelete, onError, onSuccess); + const { hasAuthority } = useAuthorities({ authorities: ['F_ENROLLMENT_CASCADE_DELETE'] }); const { updateEnrollmentOwnership, isTransferLoading } = useUpdateOwnership({ teiId: enrollment.trackedEntity, programId: enrollment.program, @@ -52,6 +54,7 @@ export const Actions = ({ onUpdate={updateMutation} onUpdateStatus={handleUpdateStatus} onDelete={deleteMutation} + canCascadeDeleteEnrollment={hasAuthority} loading={updateLoading || deleteLoading || updateStatusLoading} onUpdateOwnership={updateEnrollmentOwnership} isTransferLoading={isTransferLoading} diff --git a/src/core_modules/capture-core/components/WidgetEnrollment/Actions/Delete/Delete.component.js b/src/core_modules/capture-core/components/WidgetEnrollment/Actions/Delete/Delete.component.js index d301326dc7..f870ed9197 100644 --- a/src/core_modules/capture-core/components/WidgetEnrollment/Actions/Delete/Delete.component.js +++ b/src/core_modules/capture-core/components/WidgetEnrollment/Actions/Delete/Delete.component.js @@ -1,4 +1,5 @@ // @flow +import React, { useState } from 'react'; import { IconDelete16, MenuItem, @@ -9,18 +10,21 @@ import { ButtonStrip, Button, } from '@dhis2/ui'; -import React, { useState } from 'react'; import i18n from '@dhis2/d2-i18n'; import type { Props } from './delete.types'; +import { ConditionalTooltip } from '../../../Tooltips/ConditionalTooltip/'; -export const Delete = ({ enrollment, onDelete }: Props) => { +export const Delete = ({ canCascadeDeleteEnrollment, enrollment, onDelete }: Props) => { const [toggle, setToggle] = useState(false); + const disabled = !canCascadeDeleteEnrollment; + const tooltipContent = i18n.t('You do not have access to delete this enrollment'); return ( -
+ } destructive label={i18n.t('Delete')} @@ -54,6 +58,6 @@ export const Delete = ({ enrollment, onDelete }: Props) => { )} -
+ ); }; diff --git a/src/core_modules/capture-core/components/WidgetEnrollment/Actions/Delete/delete.types.js b/src/core_modules/capture-core/components/WidgetEnrollment/Actions/Delete/delete.types.js index 7cd649b391..71b637983f 100644 --- a/src/core_modules/capture-core/components/WidgetEnrollment/Actions/Delete/delete.types.js +++ b/src/core_modules/capture-core/components/WidgetEnrollment/Actions/Delete/delete.types.js @@ -1,6 +1,7 @@ // @flow export type Props = {| + canCascadeDeleteEnrollment: boolean, enrollment: Object, onDelete: (arg: Object) => void, |}; diff --git a/src/core_modules/capture-core/components/WidgetEnrollment/Actions/actions.types.js b/src/core_modules/capture-core/components/WidgetEnrollment/Actions/actions.types.js index e6da45629d..b40adc2282 100644 --- a/src/core_modules/capture-core/components/WidgetEnrollment/Actions/actions.types.js +++ b/src/core_modules/capture-core/components/WidgetEnrollment/Actions/actions.types.js @@ -32,6 +32,7 @@ export type PlainProps = {| onDelete: (arg: Object) => void, onAddNew: (arg: Object) => void, onUpdateOwnership: UpdateEnrollmentOwnership, + canCascadeDeleteEnrollment: boolean, isTransferLoading: boolean, loading: boolean, canAddNew: boolean, diff --git a/src/core_modules/capture-core/components/WidgetEventEdit/WidgetEventEdit.container.js b/src/core_modules/capture-core/components/WidgetEventEdit/WidgetEventEdit.container.js index f953852223..b39bb89c7c 100644 --- a/src/core_modules/capture-core/components/WidgetEventEdit/WidgetEventEdit.container.js +++ b/src/core_modules/capture-core/components/WidgetEventEdit/WidgetEventEdit.container.js @@ -32,7 +32,7 @@ import { EventChangelogWrapper } from './EventChangelogWrapper'; import { FEATURES, useFeature } from '../../../capture-core-utils'; import { inMemoryFileStore } from '../DataEntry/file/inMemoryFileStore'; import { eventStatuses } from './constants/status.const'; -import { useAuthorities } from './hooks'; +import { useAuthorities } from '../../utils/authority/useAuthorities'; const styles = { header: { @@ -101,8 +101,8 @@ export const WidgetEventEditPlain = ({ const loadedValues = useSelector(({ viewEventPage }) => viewEventPage.loadedValues); const eventAccess = getProgramEventAccess(programId, stageId); - const { canEditCompletedEvent } = useAuthorities(); - const blockEntryForm = stage.blockEntryForm && !canEditCompletedEvent && eventStatus === eventStatuses.COMPLETED; + const { hasAuthority } = useAuthorities({ authorities: ['F_UNCOMPLETE_EVENT'] }); + const blockEntryForm = stage.blockEntryForm && !hasAuthority && eventStatus === eventStatuses.COMPLETED; const disableEdit = !eventAccess?.write || blockEntryForm; const tooltipContent = blockEntryForm ? diff --git a/src/core_modules/capture-core/components/WidgetEventEdit/hooks/index.js b/src/core_modules/capture-core/components/WidgetEventEdit/hooks/index.js deleted file mode 100644 index edcfc4f241..0000000000 --- a/src/core_modules/capture-core/components/WidgetEventEdit/hooks/index.js +++ /dev/null @@ -1,2 +0,0 @@ -// @flow -export { useAuthorities } from './useAuthorities'; diff --git a/src/core_modules/capture-core/components/WidgetProfile/OverflowMenu/OverflowMenu.container.js b/src/core_modules/capture-core/components/WidgetProfile/OverflowMenu/OverflowMenu.container.js index f2b4fca631..031f7fd462 100644 --- a/src/core_modules/capture-core/components/WidgetProfile/OverflowMenu/OverflowMenu.container.js +++ b/src/core_modules/capture-core/components/WidgetProfile/OverflowMenu/OverflowMenu.container.js @@ -1,8 +1,8 @@ // @flow import React from 'react'; +import { useAuthorities } from 'capture-core/utils/authority/useAuthorities'; import type { Props } from './OverflowMenu.types'; import { OverflowMenuComponent } from './OverflowMenu.component'; -import { useAuthorities } from './hooks'; export const OverflowMenu = ({ trackedEntityTypeName, @@ -13,13 +13,13 @@ export const OverflowMenu = ({ teiId, programAPI, }: Props) => { - const { canCascadeDeleteTei } = useAuthorities(); + const { hasAuthority } = useAuthorities({ authorities: ['F_TEI_CASCADE_DELETE'] }); return ( { - const queryKey = ['authorities']; - const queryFn = { - resource: 'me.json', - params: { - fields: 'authorities', - }, - }; - const queryOptions = { - select: ({ authorities }) => - authorities && - authorities.some(authority => authority === auth.ALL || authority === auth.F_TEI_CASCADE_DELETE), - }; - const { data } = useApiMetadataQuery(queryKey, queryFn, queryOptions); - - return { - canCascadeDeleteTei: Boolean(data), - }; -}; diff --git a/src/core_modules/capture-core/components/WidgetEventEdit/hooks/useAuthorities.js b/src/core_modules/capture-core/utils/authority/useAuthorities.js similarity index 54% rename from src/core_modules/capture-core/components/WidgetEventEdit/hooks/useAuthorities.js rename to src/core_modules/capture-core/utils/authority/useAuthorities.js index 78de4ab612..0bea301f9e 100644 --- a/src/core_modules/capture-core/components/WidgetEventEdit/hooks/useAuthorities.js +++ b/src/core_modules/capture-core/utils/authority/useAuthorities.js @@ -2,11 +2,10 @@ import { useApiMetadataQuery } from 'capture-core/utils/reactQueryHelpers'; const auth = Object.freeze({ - F_UNCOMPLETE_EVENT: 'F_UNCOMPLETE_EVENT', ALL: 'ALL', }); -export const useAuthorities = () => { +export const useAuthorities = ({ authorities }: { authorities: Array }) => { const queryKey = ['authorities']; const queryFn = { resource: 'me.json', @@ -15,13 +14,15 @@ export const useAuthorities = () => { }, }; const queryOptions = { - select: ({ authorities }) => - authorities && - authorities.some(authority => authority === auth.ALL || authority === auth.F_UNCOMPLETE_EVENT), + select: ({ authorities: userAuthorities }) => + userAuthorities && + authorities.some( + authority => userAuthorities.includes(auth.ALL) || userAuthorities.includes(authority), + ), }; const { data } = useApiMetadataQuery(queryKey, queryFn, queryOptions); return { - canEditCompletedEvent: Boolean(data), + hasAuthority: Boolean(data), }; };