Repository: Altinn/altinn-access-management-frontend
Pull request #1298: Error handling in modal on package delegation or revoking
Author: login: allinox
Labels: name: kind/feature-request
description: Used when issue is a new feature or request
Created: 2025-03-02T22:11:49Z | Merged: 2025-03-03T15:22:24Z

<!--- Provide a general summary of your changes in the Title above -->

## Description
<!--- Describe your changes in detail -->

PRen bygger på tidligere introdusert hook for pakke-actions og endrer visning av feil under sletting eller delegering fra snackbar, til visning av feilinformasjon i alert på infomodal. Jeg snakket med Jon Kjetil og pr nå er det usikkerheter rundt hvordan vi kan vite om en delegering/sletting feiler fordi brukeren ikke har lov til å gjennomføre handlingen eller om det er en teknisk feil (sannsynligvis vil denne informasjonen bli gitt som en del av en details modell, men hva slags feilkode som vil komme og hvordan det vil se ut var usikkert). Derfor foreslår jeg at vi holder oss til å vise feil som teknisk feil for nå, og kombinerer det med en delegation check på forhånd, noe som vil luke ut så og si alle slike feil uansett.
Vi kan evt. legge til dekning av caset for ikke lov til å gjennomføre handling senere når vi vet mer om returnert data.

Pr nå er følgene caser dekket:
- Feil på delegering/sletting fra visningsliste på bruker
- Feil på delegering/sletting fra visningsliste på reportee (tilganger hos andre)
- Feil på delegering/sletting fra infomodal direkte
- Feil på delegering/sletting fra søk i modal

Dersom søk i modal fjernes på sikt, så kan statehåndtering av feil forenkles, men intil videre må dette caset også dekkes.

I tillegg er følgende lagt til:
- Endret bakgrunnsfarge til blå
- Endret farger på rolle-tags i brukers header for å distansere fra ellers bruk av fargekombinasjoner ellers assosiert med aktive/deaktive elementer
- La til visning av infomodal på reportee-sider

For å teste feilmelding, kan enhver pakke en bruker har forsøkes fjernes, eller pakken Renovasjon kan gis. Begge disse casene skal feile.

## Related Issue(s)
- https://github.com/Altinn/altinn-authorization-tmp/issues/78
- https://github.com/Altinn/altinn-authorization-tmp/issues/72

## Verification
- [ ] **Your** code builds clean without any errors or warnings
- [ ] Manual testing done (required)
- [ ] Relevant automated test added (if you find this hard, leave it and we'll help out)
- [ ] All tests run green

## Documentation
- [ ] User documentation is updated with a separate linked PR in [altinn-studio-docs.](https://github.com/Altinn/altinn-studio-docs) (if applicable)



Diff:
diff --git a/.mock/mockServiceWorker.js b/.mock/mockServiceWorker.js
index ec47a9a50..2c85f7512 100644
--- a/.mock/mockServiceWorker.js
+++ b/.mock/mockServiceWorker.js
@@ -8,42 +8,42 @@
  * - Please do NOT serve this file on production.
  */
 
-const PACKAGE_VERSION = '2.7.0'
-const INTEGRITY_CHECKSUM = '00729d72e3b82faf54ca8b9621dbb96f'
-const IS_MOCKED_RESPONSE = Symbol('isMockedResponse')
-const activeClientIds = new Set()
+const PACKAGE_VERSION = '2.4.11';
+const INTEGRITY_CHECKSUM = '26357c79639bfa20d64c0efca2a87423';
+const IS_MOCKED_RESPONSE = Symbol('isMockedResponse');
+const activeClientIds = new Set();
 
 self.addEventListener('install', function () {
-  self.skipWaiting()
-})
+  self.skipWaiting();
+});
 
 self.addEventListener('activate', function (event) {
-  event.waitUntil(self.clients.claim())
-})
+  event.waitUntil(self.clients.claim());
+});
 
 self.addEventListener('message', async function (event) {
-  const clientId = event.source.id
+  const clientId = event.source.id;
 
   if (!clientId || !self.clients) {
-    return
+    return;
   }
 
-  const client = await self.clients.get(clientId)
+  const client = await self.clients.get(clientId);
 
   if (!client) {
-    return
+    return;
   }
 
   const allClients = await self.clients.matchAll({
     type: 'window',
-  })
+  });
 
   switch (event.data) {
     case 'KEEPALIVE_REQUEST': {
       sendToClient(client, {
         type: 'KEEPALIVE_RESPONSE',
-      })
-      break
+      });
+      break;
     }
 
     case 'INTEGRITY_CHECK_REQUEST': {
@@ -53,83 +53,78 @@ self.addEventListener('message', async function (event) {
           packageVersion: PACKAGE_VERSION,
           checksum: INTEGRITY_CHECKSUM,
         },
-      })
-      break
+      });
+      break;
     }
 
     case 'MOCK_ACTIVATE': {
-      activeClientIds.add(clientId)
+      activeClientIds.add(clientId);
 
       sendToClient(client, {
         type: 'MOCKING_ENABLED',
-        payload: {
-          client: {
-            id: client.id,
-            frameType: client.frameType,
-          },
-        },
-      })
-      break
+        payload: true,
+      });
+      break;
     }
 
     case 'MOCK_DEACTIVATE': {
-      activeClientIds.delete(clientId)
-      break
+      activeClientIds.delete(clientId);
+      break;
     }
 
     case 'CLIENT_CLOSED': {
-      activeClientIds.delete(clientId)
+      activeClientIds.delete(clientId);
 
       const remainingClients = allClients.filter((client) => {
-        return client.id !== clientId
-      })
+        return client.id !== clientId;
+      });
 
       // Unregister itself when there are no more clients
       if (remainingClients.length === 0) {
-        self.registration.unregister()
+        self.registration.unregister();
       }
 
-      break
+      break;
     }
   }
-})
+});
 
 self.addEventListener('fetch', function (event) {
-  const { request } = event
+  const { request } = event;
 
   // Bypass navigation requests.
   if (request.mode === 'navigate') {
-    return
+    return;
   }
 
   // Opening the DevTools triggers the "only-if-cached" request
   // that cannot be handled by the worker. Bypass such requests.
   if (request.cache === 'only-if-cached' && request.mode !== 'same-origin') {
-    return
+    return;
   }
 
   // Bypass all requests when there are no active clients.
   // Prevents the self-unregistered worked from handling requests
   // after it's been deleted (still remains active until the next reload).
   if (activeClientIds.size === 0) {
-    return
+    return;
   }
 
   // Generate unique request ID.
-  const requestId = crypto.randomUUID()
-  event.respondWith(handleRequest(event, requestId))
-})
+  const requestId = crypto.randomUUID();
+  event.respondWith(handleRequest(event, requestId));
+});
 
 async function handleRequest(event, requestId) {
-  const client = await resolveMainClient(event)
-  const response = await getResponse(event, client, requestId)
+  const client = await resolveMainClient(event);
+  const response = await getResponse(event, client, requestId);
 
   // Send back the response clone for the "response:*" life-cycle events.
   // Ensure MSW is active and ready to handle the message, otherwise
   // this message will pend indefinitely.
   if (client && activeClientIds.has(client.id)) {
-    ;(async function () {
-      const responseClone = response.clone()
+    (async function () {
+      const responseClone = response.clone();
 
       sendToClient(
         client,
@@ -146,11 +141,11 @@ async function handleRequest(event, requestId) {
           },
         },
         [responseClone.body],
-      )
-    })()
+      );
+    })();
   }
 
-  return response
+  return response;
 }
 
 // Resolve the main client for the given event.
@@ -158,67 +153,49 @@ async function handleRequest(event, requestId) {
 // that registered the worker. It's with the latter the worker should
 // communicate with during the response resolving phase.
 async function resolveMainClient(event) {
-  const client = await self.clients.get(event.clientId)
-
-  if (activeClientIds.has(event.clientId)) {
-    return client
-  }
+  const client = await self.clients.get(event.clientId);
 
   if (client?.frameType === 'top-level') {
-    return client
+    return client;
   }
 
   const allClients = await self.clients.matchAll({
     type: 'window',
-  })
+  });
 
   return allClients
     .filter((client) => {
       // Get only those clients that are currently visible.
-      return client.visibilityState === 'visible'
+      return client.visibilityState === 'visible';
     })
     .find((client) => {
       // Find the client ID that's recorded in the
       // set of clients that have registered the worker.
-      return activeClientIds.has(client.id)
-    })
+      return activeClientIds.has(client.id);
+    });
 }
 
 async function getResponse(event, client, requestId) {
-  const { request } = event
+  const { request } = event;
 
   // Clone the request because it might've been already used
   // (i.e. its body has been read and sent to the client).
-  const requestClone = request.clone()
+  const requestClone = request.clone();
 
   function passthrough() {
-    // Cast the request headers to a new Headers instance
-    // so the headers can be manipulated with.
-    const headers = new Headers(requestClone.headers)
-
-    // Remove the "accept" header value that marked this request as passthrough.
-    // This prevents request alteration and also keeps it compliant with the
-    // user-defined CORS policies.
-    const acceptHeader = headers.get('accept')
-    if (acceptHeader) {
-      const values = acceptHeader.split(',').map((value) => value.trim())
-      const filteredValues = values.filter(
-        (value) => value !== 'msw/passthrough',
-      )
-
-      if (filteredValues.length > 0) {
-        headers.set('accept', filteredValues.join(', '))
-      } else {
-        headers.delete('accept')
-      }
-    }
+    const headers = Object.fromEntries(requestClone.headers.entries());
 
-    return fetch(requestClone, { headers })
+    // Remove internal MSW request header so the passthrough request
+    // complies with any potential CORS preflight checks on the server.
+    // Some servers forbid unknown request headers.
+    delete headers['x-msw-intention'];
+
+    return fetch(requestClone, { headers });
   }
 
   // Bypass mocking when the client is not active.
   if (!client) {
-    return passthrough()
+    return passthrough();
   }
 
   // Bypass initial page load requests (i.e. static assets).
@@ -226,11 +203,11 @@ async function getResponse(event, client, requestId) {
   // means that MSW hasn't dispatched the "MOCK_ACTIVATE" event yet
   // and is not ready to handle requests.
   if (!activeClientIds.has(client.id)) {
-    return passthrough()
+    return passthrough();
   }
 
   // Notify the client that a request has been intercepted.
-  const requestBuffer = await request.arrayBuffer()
+  const requestBuffer = await request.arrayBuffer();
   const clientMessage = await sendToClient(
     client,
     {
@@ -253,38 +230,35 @@ async function getResponse(event, client, requestId) {
       },
     },
     [requestBuffer],
-  )
+  );
 
   switch (clientMessage.type) {
     case 'MOCK_RESPONSE': {
-      return respondWithMock(clientMessage.data)
+      return respondWithMock(clientMessage.data);
     }
 
     case 'PASSTHROUGH': {
-      return passthrough()
+      return passthrough();
     }
   }
 
-  return passthrough()
+  return passthrough();
 }
 
 function sendToClient(client, message, transferrables = []) {
   return new Promise((resolve, reject) => {
-    const channel = new MessageChannel()
+    const channel = new MessageChannel();
 
     channel.port1.onmessage = (event) => {
       if (event.data && event.data.error) {
-        return reject(event.data.error)
+        return reject(event.data.error);
       }
 
-      resolve(event.data)
-    }
+      resolve(event.data);
+    };
 
-    client.postMessage(
-      message,
-      [channel.port2].concat(transferrables.filter(Boolean)),
-    )
-  })
+    client.postMessage(message, [channel.port2].concat(transferrables.filter(Boolean)));
+  });
 }
 
 async function respondWithMock(response) {
@@ -293,15 +267,15 @@ async function respondWithMock(response) {
   // instance will have status code set to 0. Since it's not possible to create
   // a Response instance with status code 0, handle that use-case separately.
   if (response.status === 0) {
-    return Response.error()
+    return Response.error();
   }
 
-  const mockedResponse = new Response(response.body, response)
+  const mockedResponse = new Response(response.body, response);
 
   Reflect.defineProperty(mockedResponse, IS_MOCKED_RESPONSE, {
     value: true,
     enumerable: true,
-  })
+  });
 
-  return mockedResponse
+  return mockedResponse;
 }
diff --git a/backend/src/Altinn.AccessManagement.UI/Altinn.AccessManagement.UI.Mocks/Mocks/AccessManagementClientMock.cs b/backend/src/Altinn.AccessManagement.UI/Altinn.AccessManagement.UI.Mocks/Mocks/AccessManagementClientMock.cs
index 3a9448f4d..6786109ab 100644
--- a/backend/src/Altinn.AccessManagement.UI/Altinn.AccessManagement.UI.Mocks/Mocks/AccessManagementClientMock.cs
+++ b/backend/src/Altinn.AccessManagement.UI/Altinn.AccessManagement.UI.Mocks/Mocks/AccessManagementClientMock.cs
@@ -90,7 +90,7 @@ public Task<List<AuthorizedParty>> GetReporteeRightHolders(int partyId)
         /// <inheritdoc />
         public Task<List<AuthorizedParty>> GetReporteeList(Guid partyId)
         {
-              try
+            try
             {
                 return Task.FromResult(Util.GetMockData<List<AuthorizedParty>>(Path.Combine(dataFolder, "ReporteeList", "reporteeList.json")));
             }
@@ -242,6 +242,10 @@ public Task<HttpResponseMessage> CreateAccessPackageDelegation(string party, Gui
             {
                 return Task.FromResult(new HttpResponseMessage(HttpStatusCode.BadRequest));
             }
+            else if (packageId == "5eb07bdc-5c3c-4c85-add3-5405b214b8a3") // Package is Renovasjon
+            {
+                return Task.FromResult(new HttpResponseMessage(HttpStatusCode.BadRequest));
+            }
             else
             {
                 return Task.FromResult(new HttpResponseMessage(HttpStatusCode.Created));
diff --git a/src/features/amUI/common/AccessPackageList/AccessPackageList.tsx b/src/features/amUI/common/AccessPackageList/AccessPackageList.tsx
index 0791a8c43..71b88c73d 100644
--- a/src/features/amUI/common/AccessPackageList/AccessPackageList.tsx
+++ b/src/features/amUI/common/AccessPackageList/AccessPackageList.tsx
@@ -15,6 +15,7 @@ import { PackageItem } from './PackageItem';
 import { useAccessPackageActions } from './useAccessPackageActions';
 import { SkeletonAccessPackageList } from './SkeletonAccessPackageList';
 import { ButtonWithConfirmPopup } from '../ButtonWithConfirmPopup/ButtonWithConfirmPopup';
+import { ActionError } from '@/resources/hooks/useActionError';
 
 export enum packageActions {
   DELEGATE = 'DELEGATE',
@@ -33,9 +34,9 @@ interface AccessPackageListProps {
   useDeleteConfirm?: boolean;
   onSelect?: (accessPackage: AccessPackage) => void;
   onDelegateSuccess?: (accessPackage: AccessPackage, toParty: Party) => void;
-  onDelegateError?: (accessPackage: AccessPackage, toParty: Party) => void;
+  onDelegateError?: (accessPackage: AccessPackage, error: ActionError) => void;
   onRevokeSuccess?: (accessPackage: AccessPackage, toParty: Party) => void;
-  onRevokeError?: (accessPackage: AccessPackage, toParty: Party) => void;
+  onRevokeError?: (accessPackage: AccessPackage, error: ActionError) => void;
 }
 
 export const AccessPackageList = ({
diff --git a/src/features/amUI/common/AccessPackageList/useAccessPackageActions.ts b/src/features/amUI/common/AccessPackageList/useAccessPackageActions.ts
index 0e6b351e5..bee0595c4 100644
--- a/src/features/amUI/common/AccessPackageList/useAccessPackageActions.ts
+++ b/src/features/amUI/common/AccessPackageList/useAccessPackageActions.ts
@@ -7,13 +7,14 @@ import type { Party } from '@/rtk/features/lookupApi';
 import { useGetPartyByUUIDQuery } from '@/rtk/features/lookupApi';
 
 import { useSnackbar } from '../Snackbar';
+import { ActionError } from '@/resources/hooks/useActionError';
 
 interface useAccessPackageActionsProps {
   toUuid: string;
   onDelegateSuccess?: (accessPackage: AccessPackage, toParty: Party) => void;
-  onDelegateError?: (accessPackage: AccessPackage, toParty: Party) => void;
+  onDelegateError?: (accessPackage: AccessPackage, errorInfo: ActionError) => void;
   onRevokeSuccess?: (accessPackage: AccessPackage, toParty: Party) => void;
-  onRevokeError?: (accessPackage: AccessPackage, toParty: Party) => void;
+  onRevokeError?: (accessPackage: AccessPackage, errorInfo: ActionError) => void;
 }
 
 export const useAccessPackageActions = ({
@@ -42,8 +43,13 @@ export const useAccessPackageActions = ({
     }
   };
 
-  const handleDelegateError = (accessPackage: AccessPackage, toParty: Party) => {
-    if (onDelegateError) onDelegateError(accessPackage, toParty);
+  const handleDelegateError = (
+    accessPackage: AccessPackage,
+    toParty: Party,
+    httpStatus: string,
+    timestamp: string,
+  ) => {
+    if (onDelegateError) onDelegateError(accessPackage, { httpStatus, timestamp });
     else {
       openSnackbar({
         message: t('access_packages.package_delegation_error', {
@@ -66,8 +72,13 @@ export const useAccessPackageActions = ({
     }
   };
 
-  const handleRevokeError = (accessPackage: AccessPackage, toParty: Party) => {
-    if (onRevokeError) onRevokeError(accessPackage, toParty);
+  const handleRevokeError = (
+    accessPackage: AccessPackage,
+    toParty: Party,
+    httpStatus: string,
+    timestamp: string,
+  ) => {
+    if (onRevokeError) onRevokeError(accessPackage, { httpStatus, timestamp });
     else {
       openSnackbar({
         message: t('access_packages.package_deletion_error', {
@@ -88,8 +99,13 @@ export const useAccessPackageActions = ({
       () => {
         handleDelegateSuccess(accessPackage, toParty);
       },
-      () => {
-        handleDelegateError(accessPackage, toParty);
+      (httpStatus) => {
+        handleDelegateError(
+          accessPackage,
+          toParty,
+          httpStatus.toString(),
+          new Date().toISOString(),
+        );
       },
     );
   };
@@ -104,8 +120,8 @@ export const useAccessPackageActions = ({
       () => {
         handleRevokeSuccess(accessPackage, toParty);
       },
-      () => {
-        handleRevokeError(accessPackage, toParty);
+      (httpStatus) => {
+        handleRevokeError(accessPackage, toParty, httpStatus.toString(), new Date().toISOString());
       },
     );
   };
diff --git a/src/features/amUI/common/PageLayoutWrapper/PageLayoutWrapper.tsx b/src/features/amUI/common/PageLayoutWrapper/PageLayoutWrapper.tsx
index ddcc59e0e..ebb45aa7e 100644
--- a/src/features/amUI/common/PageLayoutWrapper/PageLayoutWrapper.tsx
+++ b/src/features/amUI/common/PageLayoutWrapper/PageLayoutWrapper.tsx
@@ -18,7 +18,7 @@ export const PageLayoutWrapper = ({ children }: PageLayoutWrapperProps): React.R
   return (
     <RootProvider>
       <Layout
-        color={'neutral'}
+        color={'company'}
         theme='subtle'
         header={{
           logo: { href: getAltinnStartPageUrl(), title: 'Altinn' },
diff --git a/src/features/amUI/common/TechnicalErrorParagraphs/TechnicalErrorParagraphs.tsx b/src/features/amUI/common/TechnicalErrorParagraphs/TechnicalErrorParagraphs.tsx
index 2d74d5e4e..75703c1f7 100644
--- a/src/features/amUI/common/TechnicalErrorParagraphs/TechnicalErrorParagraphs.tsx
+++ b/src/features/amUI/common/TechnicalErrorParagraphs/TechnicalErrorParagraphs.tsx
@@ -33,12 +33,8 @@ export const TechnicalErrorParagraphs = ({
             minute: '2-digit',
             second: '2-digit',
           }),
-        })}
-      </Paragraph>
-      <Paragraph size={size}>
-        {t('common.error_status', {
-          status: status,
-        })}
+        })}{' '}
+        - {t('common.error_status', { status: status })}
       </Paragraph>
     </>
   );
diff --git a/src/features/amUI/common/UserRoles/UserRoles.tsx b/src/features/amUI/common/UserRoles/UserRoles.tsx
index 2c011b1bc..c44efbb75 100644
--- a/src/features/amUI/common/UserRoles/UserRoles.tsx
+++ b/src/features/amUI/common/UserRoles/UserRoles.tsx
@@ -26,12 +26,13 @@ export const UserRoles = ({
       {...props}
     >
       {data?.map((assignment) => {
-        const color = assignment?.role?.urn?.includes('brreg:') ? 'company' : 'accent';
+        const isER = assignment?.role?.urn?.includes('brreg:');
         return (
           <Badge
-            color={color}
+            color={isER ? 'info' : 'company'}
             label={assignment.role.name}
             key={assignment.id}
+            theme={isER ? 'base' : 'subtle'}
           />
         );
       })}
diff --git a/src/features/amUI/reporteeRightsPage/ReporteeAccessPackageSection.tsx b/src/features/amUI/reporteeRightsPage/ReporteeAccessPackageSection.tsx
index 0ae72efb5..82378f85c 100644
--- a/src/features/amUI/reporteeRightsPage/ReporteeAccessPackageSection.tsx
+++ b/src/features/amUI/reporteeRightsPage/ReporteeAccessPackageSection.tsx
@@ -4,6 +4,12 @@ import { useTranslation } from 'react-i18next';
 import { AccessPackageList, packageActions } from '../common/AccessPackageList/AccessPackageList';
 
 import { getCookie } from '@/resources/Cookie/CookieMethods';
+import { useRef, useState } from 'react';
+import { AccessPackage } from '@/rtk/features/accessPackageApi';
+import { AccessPackageInfoModal } from '../userRightsPage/AccessPackageSection/AccessPackageInfoModal';
+import { useGetReporteePartyQuery } from '@/rtk/features/lookupApi';
+import { useParams } from 'react-router';
+import { useActionError } from '@/resources/hooks/useActionError';
 
 interface ReporteeAccessPackageSectionProps {
   reporteeUuid?: string;
@@ -15,22 +21,54 @@ export const ReporteeAccessPackageSection = ({
   reporteeUuid,
 }: ReporteeAccessPackageSectionProps) => {
   const { t } = useTranslation();
+  const modalRef = useRef<HTMLDialogElement>(null);
+  const [modalItem, setModalItem] = useState<AccessPackage | undefined>(undefined);
+  const { error, setError } = useActionError();
+
+  const { data: party } = useGetReporteePartyQuery();
+
   return (
-    <>
-      <Heading
-        level={2}
-        size='xs'
-        id='access_packages_title'
-      >
-        {t('access_packages.current_access_packages_title', { count: numberOfAccesses })}
-      </Heading>
-      <AccessPackageList
-        fromPartyUuid={reporteeUuid ?? ''}
-        toPartyUuid={getCookie('AltinnPartyUuid')}
-        availableActions={[packageActions.REVOKE, packageActions.REQUEST]}
-        useDeleteConfirm
-        showAllPackages
-      />
-    </>
+    party && (
+      <>
+        <Heading
+          level={2}
+          size='xs'
+          id='access_packages_title'
+        >
+          {t('access_packages.current_access_packages_title', { count: numberOfAccesses })}
+        </Heading>
+        <AccessPackageList
+          fromPartyUuid={reporteeUuid ?? ''}
+          toPartyUuid={getCookie('AltinnPartyUuid')}
+          availableActions={[packageActions.REVOKE, packageActions.REQUEST]}
+          useDeleteConfirm
+          showAllPackages
+          onSelect={(accessPackage) => {
+            setModalItem(accessPackage);
+            modalRef.current?.showModal();
+          }}
+          onDelegateError={(accessPackage, errorInfo) => {
+            setError(errorInfo);
+            setModalItem(accessPackage);
+            modalRef.current?.showModal();
+          }}
+          onRevokeError={(accessPackage, errorInfo) => {
+            setError(errorInfo);
+            setModalItem(accessPackage);
+            modalRef.current?.showModal();
+          }}
+        />
+        <AccessPackageInfoModal
+          modalRef={modalRef}
+          toParty={party}
+          modalItem={modalItem}
+          onClose={() => {
+            setModalItem(undefined);
+            setError(null);
+          }}
+          openWithError={error ?? undefined}
+        />
+      </>
+    )
   );
 };
diff --git a/src/features/amUI/userRightsPage/AccessPackageSection/AccessPackageInfoModal.tsx b/src/features/amUI/userRightsPage/AccessPackageSection/AccessPackageInfoModal.tsx
index a763f430d..376255afa 100644
--- a/src/features/amUI/userRightsPage/AccessPackageSection/AccessPackageInfoModal.tsx
+++ b/src/features/amUI/userRightsPage/AccessPackageSection/AccessPackageInfoModal.tsx
@@ -4,12 +4,15 @@ import type { AccessPackage } from '@/rtk/features/accessPackageApi';
 import type { Party } from '@/rtk/features/lookupApi';
 
 import { EditModal } from '../DelegationModal/EditModal';
+import { ActionError } from '@/resources/hooks/useActionError';
+import { DelegationModalProvider } from '../DelegationModal/DelegationModalContext';
 
 interface AccessPackageInfoModalProps {
   modalRef: React.RefObject<HTMLDialogElement>;
   toParty: Party;
   modalItem: AccessPackage | undefined;
   onClose?: () => void;
+  openWithError?: ActionError | null;
 }
 
 export const AccessPackageInfoModal = ({
@@ -17,19 +20,17 @@ export const AccessPackageInfoModal = ({
   toParty,
   modalItem,
   onClose,
+  openWithError,
 }: AccessPackageInfoModalProps) => {
-  useEffect(() => {
-    const handleClose = () => onClose?.();
-
-    modalRef.current?.addEventListener('close', handleClose);
-    return () => modalRef.current?.removeEventListener('close', handleClose);
-  }, [onClose, modalRef]);
-
   return (
-    <EditModal
-      ref={modalRef}
-      toParty={toParty}
-      accessPackage={modalItem}
-    />
+    <DelegationModalProvider>
+      <EditModal
+        ref={modalRef}
+        toParty={toParty}
+        accessPackage={modalItem}
+        openWithError={openWithError}
+        onClose={onClose}
+      />
+    </DelegationModalProvider>
   );
 };
diff --git a/src/features/amUI/userRightsPage/AccessPackageSection/ActiveDelegations.tsx b/src/features/amUI/userRightsPage/AccessPackageSection/ActiveDelegations.tsx
index 761403c2b..60c681bbf 100644
--- a/src/features/amUI/userRightsPage/AccessPackageSection/ActiveDelegations.tsx
+++ b/src/features/amUI/userRightsPage/AccessPackageSection/ActiveDelegations.tsx
@@ -11,10 +11,12 @@ import {
 
 import { AccessPackageInfoModal } from './AccessPackageInfoModal';
 import { useGetUserInfoQuery } from '@/rtk/features/userInfoApi';
+import { useActionError } from '@/resources/hooks/useActionError';
 
 export const ActiveDelegations = ({ toParty }: { toParty: Party }) => {
   const modalRef = useRef<HTMLDialogElement>(null);
   const [modalItem, setModalItem] = useState<AccessPackage | undefined>(undefined);
+  const { error: actionError, setError: setActionError } = useActionError();
   const { data: currentUser, isLoading: currentUserLoading } = useGetUserInfoQuery();
 
   const isCurrentUser = currentUser?.uuid === toParty.partyUuid;
@@ -35,6 +37,16 @@ export const ActiveDelegations = ({ toParty }: { toParty: Party }) => {
           packageActions.REVOKE,
           isCurrentUser ? packageActions.REQUEST : packageActions.DELEGATE,
         ]}
+        onDelegateError={(accessPackage, error) => {
+          setActionError(error);
+          setModalItem(accessPackage);
+          modalRef.current?.showModal();
+        }}
+        onRevokeError={(accessPackage, error) => {
+          setActionError(error);
+          setModalItem(accessPackage);
+          modalRef.current?.showModal();
+        }}
       />
 
       <AccessPackageInfoModal
@@ -43,7 +55,9 @@ export const ActiveDelegations = ({ toParty }: { toParty: Party }) => {
         modalItem={modalItem}
         onClose={() => {
           setModalItem(undefined);
+          setActionError(null);
         }}
+        openWithError={actionError}
       />
     </>
   );
diff --git a/src/features/amUI/userRightsPage/AccessPackageSection/DeletePackageButton.tsx b/src/features/amUI/userRightsPage/AccessPackageSection/DeletePackageButton.tsx
index 9d6df4409..1aee52f82 100644
--- a/src/features/amUI/userRightsPage/AccessPackageSection/DeletePackageButton.tsx
+++ b/src/features/amUI/userRightsPage/AccessPackageSection/DeletePackageButton.tsx
@@ -13,21 +13,18 @@ interface DeletePackageButtonProps {
   toParty: Party;
   fullText?: boolean;
   disabled?: boolean;
+  onClick?: () => void;
 }
 
 export const DeletePackageButton = ({
   accessPackage,
   toParty,
   fullText = false,
+  onClick,
   ...props
 }: DeletePackageButtonProps) => {
   const { t } = useTranslation();
   const { data: representingParty } = useGetReporteePartyQuery();
-  const { onRevoke } = useAccessPackageActions({ toUuid: toParty.partyUuid });
-
-  const onClick = () => {
-    onRevoke(accessPackage);
-  };
 
   return (
     representingParty && (
diff --git a/src/features/amUI/userRightsPage/DelegationModal/AccessPackages/AccessPackageInfo.tsx b/src/features/amUI/userRightsPage/DelegationModal/AccessPackages/AccessPackageInfo.tsx
index f67913069..473bdc237 100644
--- a/src/features/amUI/userRightsPage/DelegationModal/AccessPackages/AccessPackageInfo.tsx
+++ b/src/features/amUI/userRightsPage/DelegationModal/AccessPackages/AccessPackageInfo.tsx
@@ -1,5 +1,5 @@
 import * as React from 'react';
-import { Heading, Paragraph } from '@digdir/designsystemet-react';
+import { Alert, Heading, Paragraph } from '@digdir/designsystemet-react';
 import type { ListItemProps } from '@altinn/altinn-components';
 import { List, Button, Icon } from '@altinn/altinn-components';
 import { Trans, useTranslation } from 'react-i18next';
@@ -18,6 +18,9 @@ import { useAccessPackageActions } from '@/features/amUI/common/AccessPackageLis
 import { DeletePackageButton } from '../../AccessPackageSection/DeletePackageButton';
 
 import classes from './AccessPackageInfo.module.css';
+import { TechnicalErrorParagraphs } from '@/features/amUI/common/TechnicalErrorParagraphs';
+import { ActionError, useActionError } from '@/resources/hooks/useActionError';
+import { useDelegationModalContext } from '../DelegationModalContext';
 
 export interface PackageInfoProps {
   accessPackage: AccessPackage;
@@ -26,12 +29,17 @@ export interface PackageInfoProps {
 
 export const AccessPackageInfo = ({ accessPackage, toParty }: PackageInfoProps) => {
   const { t } = useTranslation();
+  const { actionError, setActionError } = useDelegationModalContext();
 
-  const { onDelegate } = useAccessPackageActions({ toUuid: toParty.partyUuid });
+  const { onDelegate, onRevoke } = useAccessPackageActions({
+    toUuid: toParty.partyUuid,
+    onDelegateError: (_, error: ActionError) => setActionError(error),
+    onRevokeError: (_, error: ActionError) => setActionError(error),
+  });
 
   const { data: activeDelegations, isFetching } = useGetUserDelegationsQuery({
     to: toParty.partyUuid,
-    from: getCookie('partyUuid'),
+    from: getCookie('AltinnPartyUuid'),
   });
   const userHasPackage = React.useMemo(() => {
     if (activeDelegations && !isFetching) {
@@ -58,6 +66,25 @@ export const AccessPackageInfo = ({ accessPackage, toParty }: PackageInfoProps)
           {accessPackage?.name}
         </Heading>
       </div>
+      {!!actionError && (
+        <>
+          <Alert
+            color='danger'
+            size='sm'
+          >
+            {userHasPackage ? (
+              <Heading size='2xs'>{t('delegation_modal.general_error.revoke_heading')}</Heading>
+            ) : (
+              <Heading size='2xs'>{t('delegation_modal.general_error.delegate_heading')}</Heading>
+            )}
+            <TechnicalErrorParagraphs
+              size='xs'
+              status={actionError.httpStatus}
+              time={actionError.timestamp}
+            />
+          </Alert>
+        </>
+      )}
       <Paragraph variant='long'>{accessPackage?.description}</Paragraph>
       {accessPackage?.inherited && (
         <div className={classes.inherited}>
@@ -88,6 +115,7 @@ export const AccessPackageInfo = ({ accessPackage, toParty }: PackageInfoProps)
           <List
             items={listItems}
             spacing='xs'
+            defaultItemSize='xs'
           />
         </div>
       </div>
@@ -98,6 +126,7 @@ export const AccessPackageInfo = ({ accessPackage, toParty }: PackageInfoProps)
             toParty={toParty}
             fullText
             disabled={isFetching || accessPackage.inherited}
+            onClick={() => onRevoke(accessPackage)}
           />
         ) : (
           <Button onClick={() => onDelegate(accessPackage)}>{t('common.give_poa')}</Button>
@@ -133,7 +162,5 @@ const useMinimizableResourceList = (list: IdNamePair[]) => {
   const minimizedList = list
     .slice(0, showAll ? list.length : MINIMIZED_LIST_SIZE)
     .map(mapResourceToListItem);
-  return {
-    listItems: showAll ? minimizedList : [...minimizedList, showMoreListItem],
-  };
+  return { listItems: showAll ? minimizedList : [...minimizedList, showMoreListItem] };
 };
diff --git a/src/features/amUI/userRightsPage/DelegationModal/AccessPackages/PackageSearch.tsx b/src/features/amUI/userRightsPage/DelegationModal/AccessPackages/PackageSearch.tsx
index 81b623ab5..a74f41066 100644
--- a/src/features/amUI/userRightsPage/DelegationModal/AccessPackages/PackageSearch.tsx
+++ b/src/features/amUI/userRightsPage/DelegationModal/AccessPackages/PackageSearch.tsx
@@ -11,17 +11,20 @@ import { getCookie } from '@/resources/Cookie/CookieMethods';
 import { useDelegationModalContext } from '../DelegationModalContext';
 
 import classes from './PackageSearch.module.css';
+import { ActionError } from '@/resources/hooks/useActionError';
 
 export interface PackageSearchProps {
   onSelection: (pack: AccessPackage) => void;
+  onActionError: (accessPackage: AccessPackage) => void;
   toParty: Party;
 }
 
-export const PackageSearch = ({ toParty, onSelection }: PackageSearchProps) => {
+export const PackageSearch = ({ toParty, onSelection, onActionError }: PackageSearchProps) => {
   const { t } = useTranslation();
   const [debouncedSearchString, setDebouncedSearchString] = useState('');
 
-  const { searchString, setSearchString, setCurrentPage } = useDelegationModalContext();
+  const { searchString, setSearchString, setCurrentPage, setActionError } =
+    useDelegationModalContext();
 
   const debouncedSearch = debounce((searchString: string) => {
     setDebouncedSearchString(searchString);
@@ -68,6 +71,14 @@ export const PackageSearch = ({ toParty, onSelection }: PackageSearchProps) => {
             showAllPackages={true}
             onSelect={onSelection}
             searchString={debouncedSearchString}
+            onDelegateError={(accessPackage, errorInfo) => {
+              onActionError(accessPackage);
+              setActionError(errorInfo);
+            }}
+            onRevokeError={(accessPackage, errorInfo) => {
+              onActionError(accessPackage);
+              setActionError(errorInfo);
+            }}
           />
         </div>
       </search>
diff --git a/src/features/amUI/userRightsPage/DelegationModal/DelegationModalContent.tsx b/src/features/amUI/userRightsPage/DelegationModal/DelegationModalContent.tsx
index 427fcd4ad..592e895fd 100644
--- a/src/features/amUI/userRightsPage/DelegationModal/DelegationModalContent.tsx
+++ b/src/features/amUI/userRightsPage/DelegationModal/DelegationModalContent.tsx
@@ -33,6 +33,7 @@ export const DelegationModalContent = ({ toParty, delegationType }: DelegationMo
     packageToView,
     infoView,
     reset,
+    setActionError,
   } = useDelegationModalContext();
 
   const onResourceSelection = (resource?: ServiceResource) => {
@@ -40,7 +41,10 @@ export const DelegationModalContent = ({ toParty, delegationType }: DelegationMo
     setResourceToView(resource);
   };
 
-  const onPackageSelection = (accessPackage?: AccessPackage) => {
+  const onPackageSelection = (accessPackage?: AccessPackage, error: boolean = false) => {
+    if (!error) {
+      setActionError(null);
+    }
     setInfoView(true);
     setPackageToView(accessPackage);
   };
@@ -68,6 +72,9 @@ export const DelegationModalContent = ({ toParty, delegationType }: DelegationMo
         <PackageSearch
           onSelection={onPackageSelection}
           toParty={toParty}
+          onActionError={(accessPackage: AccessPackage) => {
+            onPackageSelection(accessPackage, true);
+          }}
         />
       );
       infoViewContent = packageToView && (
diff --git a/src/features/amUI/userRightsPage/DelegationModal/DelegationModalContext.tsx b/src/features/amUI/userRightsPage/DelegationModal/DelegationModalContext.tsx
index ad9a1743e..d269a4418 100644
--- a/src/features/amUI/userRightsPage/DelegationModal/DelegationModalContext.tsx
+++ b/src/features/amUI/userRightsPage/DelegationModal/DelegationModalContext.tsx
@@ -2,6 +2,7 @@ import React, { createContext, useContext, useState } from 'react';
 
 import type { ServiceResource } from '@/rtk/features/singleRights/singleRightsApi';
 import type { AccessPackage } from '@/rtk/features/accessPackageApi';
+import { ActionError, useActionError } from '@/resources/hooks/useActionError';
 export interface DelegationModalProps {
   children: React.ReactNode;
 }
@@ -22,6 +23,8 @@ interface DelegationModalContextProps {
   onSelection: (resource?: ServiceResource, accessPackage?: AccessPackage) => void;
   expandedAreas: string[];
   toggleExpanded: (value: boolean, id: string) => void;
+  actionError: ActionError | null;
+  setActionError: (error: ActionError | null) => void;
   reset: () => void;
 }
 
@@ -35,6 +38,7 @@ export const DelegationModalProvider: React.FC<DelegationModalProps> = ({ childr
   const [packageToView, setPackageToView] = useState<AccessPackage | undefined>(undefined);
   const [infoView, setInfoView] = useState(false);
   const [expandedAreas, setExpandedAreas] = useState<string[]>([]);
+  const { error: actionError, setError: setActionError } = useActionError();
 
   const toggleExpanded = (value: boolean, id: string) => {
     if (value) {
@@ -55,6 +59,7 @@ export const DelegationModalProvider: React.FC<DelegationModalProps> = ({ childr
   };
 
   const reset = () => {
+    setActionError(null);
     setCurrentPage(1);
     setResourceToView(undefined);
     setPackageToView(undefined);
@@ -82,6 +87,8 @@ export const DelegationModalProvider: React.FC<DelegationModalProps> = ({ childr
         setPackageToView,
         expandedAreas,
         toggleExpanded,
+        actionError,
+        setActionError,
         reset,
       }}
     >
diff --git a/src/features/amUI/userRightsPage/DelegationModal/EditModal.tsx b/src/features/amUI/userRightsPage/DelegationModal/EditModal.tsx
index acf85271b..f6ff50657 100644
--- a/src/features/amUI/userRightsPage/DelegationModal/EditModal.tsx
+++ b/src/features/amUI/userRightsPage/DelegationModal/EditModal.tsx
@@ -1,6 +1,6 @@
 import * as React from 'react';
 import { Modal } from '@digdir/designsystemet-react';
-import { forwardRef } from 'react';
+import { forwardRef, useEffect } from 'react';
 
 import type { ServiceResource } from '@/rtk/features/singleRights/singleRightsApi';
 import type { Party } from '@/rtk/features/lookupApi';
@@ -13,22 +13,58 @@ import { SnackbarProvider } from '../../common/Snackbar';
 import classes from './DelegationModal.module.css';
 import { AccessPackageInfo } from './AccessPackages/AccessPackageInfo';
 import { RoleInfo } from './Role/RoleInfo';
+import { ActionError } from '@/resources/hooks/useActionError';
+import { useDelegationModalContext } from './DelegationModalContext';
 
 export interface EditModalProps {
   resource?: ServiceResource;
   accessPackage?: AccessPackage;
   role?: Role;
   toParty: Party;
+  openWithError?: ActionError | null;
+  onClose?: () => void;
 }
 
 export const EditModal = forwardRef<HTMLDialogElement, EditModalProps>(
-  ({ toParty, resource, accessPackage, role }, ref) => {
+  ({ toParty, resource, accessPackage, role, openWithError, onClose }, ref) => {
+    const { setActionError, actionError, reset } = useDelegationModalContext();
+
+    useEffect(() => {
+      if (!!openWithError) {
+        setActionError(openWithError);
+      } else {
+        setActionError(null);
+      }
+    }, [openWithError]);
+
+    const onClosing = () => {
+      onClose?.();
+      reset();
+    };
+
+    /* handle closing */
+    useEffect(() => {
+      const handleClose = () => onClosing?.();
+
+      if (ref && 'current' in ref && ref.current) {
+        ref.current.addEventListener('close', handleClose);
+      }
+      return () => {
+        if (ref && 'current' in ref && ref.current) {
+          ref.current.removeEventListener('close', handleClose);
+        }
+      };
+    }, [onClosing, ref]);
+
     return (
       <Modal.Context>
         <Modal
           ref={ref}
           className={classes.modalDialog}
           backdropClose
+          onClose={() => {
+            onClosing();
+          }}
         >
           <SnackbarProvider>
             <div className={classes.content}>
diff --git a/src/features/amUI/userRightsPage/RoleSection/RoleInfoModal.tsx b/src/features/amUI/userRightsPage/RoleSection/RoleInfoModal.tsx
index 491366650..3310307d8 100644
--- a/src/features/amUI/userRightsPage/RoleSection/RoleInfoModal.tsx
+++ b/src/features/amUI/userRightsPage/RoleSection/RoleInfoModal.tsx
@@ -4,6 +4,7 @@ import type { Party } from '@/rtk/features/lookupApi';
 import type { Role } from '@/rtk/features/roleApi';
 
 import { EditModal } from '../DelegationModal/EditModal';
+import { DelegationModalProvider } from '../DelegationModal/DelegationModalContext';
 
 interface RoleInfoModalProps {
   modalRef: React.RefObject<HTMLDialogElement>;
@@ -21,10 +22,12 @@ export const RoleInfoModal = ({ modalRef, toParty, role, onClose }: RoleInfoModa
   }, [onClose, modalRef]);
 
   return (
-    <EditModal
-      ref={modalRef}
-      toParty={toParty}
-      role={role}
-    />
+    <DelegationModalProvider>
+      <EditModal
+        ref={modalRef}
+        toParty={toParty}
+        role={role}
+      />
+    </DelegationModalProvider>
   );
 };
diff --git a/src/features/amUI/userRightsPage/SingleRightsSection/SingleRightItem.tsx b/src/features/amUI/userRightsPage/SingleRightsSection/SingleRightItem.tsx
index f9d616509..5634e8056 100644
--- a/src/features/amUI/userRightsPage/SingleRightsSection/SingleRightItem.tsx
+++ b/src/features/amUI/userRightsPage/SingleRightsSection/SingleRightItem.tsx
@@ -12,6 +12,7 @@ import { EditModal } from '../DelegationModal/EditModal';
 
 import { DeleteResourceButton } from './DeleteResourceButton';
 import classes from './SingleRightsSection.module.css';
+import { DelegationModalProvider } from '../DelegationModal/DelegationModalContext';
 
 interface SingleRightItemProps {
   resource: ServiceResource;
@@ -49,11 +50,13 @@ const SingleRightItem: FC<SingleRightItemProps> = ({ resource, toParty }) => {
           }}
         ></div>
       </li>
-      <EditModal
-        ref={modalRef}
-        toParty={toParty}
-        resource={resource}
-      ></EditModal>
+      <DelegationModalProvider>
+        <EditModal
+          ref={modalRef}
+          toParty={toParty}
+          resource={resource}
+        ></EditModal>
+      </DelegationModalProvider>
     </>
   );
 };
diff --git a/src/localizations/en.json b/src/localizations/en.json
index e8cee9b42..70fb8cb60 100644
--- a/src/localizations/en.json
+++ b/src/localizations/en.json
@@ -69,7 +69,7 @@
     "show_less": "Show less",
     "technical_error": "Sorry, a technical error has occurred. Please contact Altinn user service if the problem persists.",
     "time_of_error": "Error occurred at time: {{time}}",
-    "error_status": "Status: {{status}}",
+    "error_status": "HttpStatus: {{status}}",
     "ssn": "National identity number",
     "last_name": "Last name",
     "subunit": "Subunit",
@@ -303,6 +303,10 @@
       "all_failed": "No rights were granted to {{name}}",
       "some_failed": "We couldn't grant these rights: {{actions}}"
     },
+    "general_error": {
+      "revoke_heading": "Could not delete power of attorney",
+      "delegate_heading": "Could not give power of attorney"
+    },
     "service_error": {
       "general_heading": "You cannot give access to this service",
       "technical_error_heading": "Something went wrong",
diff --git a/src/localizations/no_nb.json b/src/localizations/no_nb.json
index f08599f27..02487b7ef 100644
--- a/src/localizations/no_nb.json
+++ b/src/localizations/no_nb.json
@@ -68,7 +68,7 @@
     "show_less": "Se mindre",
     "technical_error": "Beklager, det har skjedd en teknisk feil. Vennligst ta kontakt med Altinn brukerservice hvis problemet fortsetter.",
     "time_of_error": "Tidspunkt feilen inntraff: {{time}}",
-    "error_status": "Status: {{status}}",
+    "error_status": "HttpStatus: {{status}}",
     "ssn": "Fødselsnummer",
     "last_name": "Etternavn",
     "org_number": "Organisasjonsnummer",
@@ -302,7 +302,10 @@
       "missing_role_message": "Du får ikke delegert hele tjenesten, fordi du mangler noen av rettighetene selv. Daglig leder eller hovedadministrator kan gi deg tilgang.",
       "missing_srr_right_message": "{{reportee}} er ikke gitt tillatelse fra {{resourceOwner}} til å delegere hele tjenesten. Ta kontakt med dem dersom du ønsker å endre dette."
     },
-
+    "general_error": {
+      "revoke_heading": "Kunne ikke slette fullmakt",
+      "delegate_heading": "Kunne ikke gi fullmakt"
+    },
     "service_error": {
       "general_heading": "Du kan ikke gi fullmakt til denne tjenesten",
       "technical_error_heading": "Noe gikk galt",
diff --git a/src/localizations/no_nn.json b/src/localizations/no_nn.json
index bd3bf4f95..d64cf0331 100644
--- a/src/localizations/no_nn.json
+++ b/src/localizations/no_nn.json
@@ -68,7 +68,7 @@
     "show_less": "Se mindre",
     "technical_error": "Beklagar, det har skjedd ein teknisk feil. Ver venleg å ta kontakt med Altinn brukerservice om problemet held fram.",
     "time_of_error": "Tidspunkt feilen oppstod: {{time}}",
-    "error_status": "Status: {{status}}",
+    "error_status": "HttpStatus: {{status}}",
     "ssn": "Fødselsnummer",
     "last_name": "Etternavn",
     "subunit": "Underenhet"
@@ -299,6 +299,10 @@
       "all_failed": "Ingen ny fullmakt er gjeven til {{name}}",
       "some_failed": "Fylgjande tilgangar vart ikkje gjevne: {{actions}}"
     },
+    "general_error": {
+      "revoke_heading": "Kunne ikkje slette fullmakt",
+      "delegate_heading": "Kunne ikkje gi fullmakt"
+    },
     "service_error": {
       "general_heading": "Du kan ikkje gi fullmakt til denne tenesta",
       "technical_error_heading": "Noko gjekk gale",
diff --git a/src/resources/hooks/useActionError.tsx b/src/resources/hooks/useActionError.tsx
new file mode 100644
index 000000000..a85675fca
--- /dev/null
+++ b/src/resources/hooks/useActionError.tsx
@@ -0,0 +1,17 @@
+import { useState } from 'react';
+
+/** A standardized error for any type of delegation, request, or revoking action */
+export type ActionError = {
+  /** The http status received with the error */
+  httpStatus: string;
+  /** When the error happened */
+  timestamp: string;
+};
+
+/** Use state for the ActionError type */
+export const useActionError = (initValue?: ActionError) => {
+  const [error, setError] = useState<ActionError | null>(initValue ?? null);
+  const isError = error !== null;
+
+  return { isError, error, setError };
+};
diff --git a/src/resources/hooks/useDelegateAccessPackage.tsx b/src/resources/hooks/useDelegateAccessPackage.tsx
index 7064b61a9..b21a3a33a 100644
--- a/src/resources/hooks/useDelegateAccessPackage.tsx
+++ b/src/resources/hooks/useDelegateAccessPackage.tsx
@@ -16,8 +16,8 @@ export const useDelegateAccessPackage = () => {
       .then(() => {
         onSuccess?.();
       })
-      .catch((status) => {
-        onError?.(status);
+      .catch((response) => {
+        onError?.(response.status);
       });
   };
 
diff --git a/src/resources/hooks/useRevokeAccessPackage.tsx b/src/resources/hooks/useRevokeAccessPackage.tsx
index 3a0aede2a..52f073ce9 100644
--- a/src/resources/hooks/useRevokeAccessPackage.tsx
+++ b/src/resources/hooks/useRevokeAccessPackage.tsx
@@ -16,8 +16,8 @@ export const useRevokeAccessPackage = () => {
       .then(() => {
         onSuccess?.();
       })
-      .catch((status) => {
-        onError?.(status);
+      .catch((response) => {
+        onError?.(response.status);
       });
   };
 


Reviews:
user: login: sonwit
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-03T08:28:08Z
user: login: allinox
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-03T08:44:57Z
user: login: sonwit
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-03T08:58:34Z
user: login: sonwit
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-03T09:09:03Z
user: login: sonwit
body: Great work on implementing this! Errors are handled much better now.
Also, great job fixing the background color and the Role-badge colors.

I'm not able to test that it works at the moment (due to issues with the test environment), but I don't see any changes that would likely cause issues. So, I'll approve this PR (with a few comments, but nothing major or important).
state: APPROVED
author_association: CONTRIBUTOR
submitted_at: 2025-03-03T09:25:21Z
user: login: allinox
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-03T15:03:01Z
user: login: allinox
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-03T15:03:38Z

Review comments:
diff_hunk: @@ -58,6 +66,25 @@ export const AccessPackageInfo = ({ accessPackage, toParty }: PackageInfoProps)
           {accessPackage?.name}
         </Heading>
       </div>
+      {!!actionError && (
+        <>
+          <Alert
+            color='danger'
+            size='sm'
+          >
+            {userHasPackage ? (
+              <Heading size='2xs'>Kunne ikke slette fullmakt</Heading>
path: src/features/amUI/userRightsPage/DelegationModal/AccessPackages/AccessPackageInfo.tsx
user: login: sonwit
body: Should this be translated?  
created_at: 2025-03-03T08:28:08Z
author_association: CONTRIBUTOR
diff_hunk: @@ -58,6 +66,25 @@ export const AccessPackageInfo = ({ accessPackage, toParty }: PackageInfoProps)
           {accessPackage?.name}
         </Heading>
       </div>
+      {!!actionError && (
+        <>
+          <Alert
+            color='danger'
+            size='sm'
+          >
+            {userHasPackage ? (
+              <Heading size='2xs'>Kunne ikke slette fullmakt</Heading>
path: src/features/amUI/userRightsPage/DelegationModal/AccessPackages/AccessPackageInfo.tsx
user: login: allinox
body: Whoops! It should! I forgot to add it to the text-files 🙈
created_at: 2025-03-03T08:44:57Z
author_association: CONTRIBUTOR
diff_hunk: @@ -15,22 +21,55 @@ export const ReporteeAccessPackageSection = ({
   reporteeUuid,
 }: ReporteeAccessPackageSectionProps) => {
   const { t } = useTranslation();
+  const { id } = useParams<{ id: string }>();
path: src/features/amUI/reporteeRightsPage/ReporteeAccessPackageSection.tsx
user: login: sonwit
body: Can this be removed? 
created_at: 2025-03-03T08:58:34Z
author_association: CONTRIBUTOR
diff_hunk: @@ -33,13 +33,13 @@ export const TechnicalErrorParagraphs = ({
             minute: '2-digit',
             second: '2-digit',
           }),
-        })}
-      </Paragraph>
-      <Paragraph size={size}>
+        })}{' '}
+        -{' '}
         {t('common.error_status', {
           status: status,
         })}
       </Paragraph>
+      <Paragraph size={size}></Paragraph>
path: src/features/amUI/common/TechnicalErrorParagraphs/TechnicalErrorParagraphs.tsx
user: login: sonwit
body: Do we need this empty p tag?
created_at: 2025-03-03T09:09:03Z
author_association: CONTRIBUTOR
diff_hunk: @@ -15,22 +21,55 @@ export const ReporteeAccessPackageSection = ({
   reporteeUuid,
 }: ReporteeAccessPackageSectionProps) => {
   const { t } = useTranslation();
+  const { id } = useParams<{ id: string }>();
path: src/features/amUI/reporteeRightsPage/ReporteeAccessPackageSection.tsx
user: login: allinox
body: It absolutely can!
created_at: 2025-03-03T15:03:00Z
author_association: CONTRIBUTOR
diff_hunk: @@ -33,13 +33,13 @@ export const TechnicalErrorParagraphs = ({
             minute: '2-digit',
             second: '2-digit',
           }),
-        })}
-      </Paragraph>
-      <Paragraph size={size}>
+        })}{' '}
+        -{' '}
         {t('common.error_status', {
           status: status,
         })}
       </Paragraph>
+      <Paragraph size={size}></Paragraph>
path: src/features/amUI/common/TechnicalErrorParagraphs/TechnicalErrorParagraphs.tsx
user: login: allinox
body: Nope, I just forgot to delete it 😅
created_at: 2025-03-03T15:03:36Z
author_association: CONTRIBUTOR

PR comments:
user: login: sonarqubecloud[bot]
created_at: 2025-03-03T15:17:34Z
body: ## [![Quality Gate Failed](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/QualityGateBadge/qg-failed-20px.png 'Quality Gate Failed')](https://sonarcloud.io/dashboard?id=Altinn_altinn-access-management-frontend&pullRequest=1298) **Quality Gate failed**  
Failed conditions  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/failed-16px.png '') [C Reliability Rating on New Code](https://sonarcloud.io/dashboard?id=Altinn_altinn-access-management-frontend&pullRequest=1298) (required ≥ A)  
  
[See analysis details on SonarQube Cloud](https://sonarcloud.io/dashboard?id=Altinn_altinn-access-management-frontend&pullRequest=1298)

##   
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/light_bulb-16px.png '') Catch issues before they fail your Quality Gate with our IDE extension ![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/sonarlint-16px.png '') [SonarQube for IDE](https://www.sonarsource.com/products/sonarlint/features/connected-mode/?referrer=pull-request)


author_association: NONE