diff --git a/ui/src/components/layout/navbar/navbar.tsx b/ui/src/components/layout/navbar/navbar.tsx
index 0c1b4579..b5c67452 100644
--- a/ui/src/components/layout/navbar/navbar.tsx
+++ b/ui/src/components/layout/navbar/navbar.tsx
@@ -35,17 +35,19 @@ const Navbar = async () => {
- {NavbarLinks
- .filter((navbarLink) =>
- currentUser.roles.includes(Role.ADMIN) ||
- currentUser.roles.includes(navbarLink.role))
- .map((navbarLink) =>
-
- {navbarLink.name}
- )}
+ {NavbarLinks.filter(
+ (navbarLink) =>
+ currentUser.roles.includes(Role.ADMIN) ||
+ currentUser.roles.includes(navbarLink.role)
+ ).map((navbarLink) => (
+
+ {navbarLink.name}
+
+ ))}
diff --git a/ui/src/components/modal/api-error-modal.tsx b/ui/src/components/modal/api-error-modal.tsx
new file mode 100644
index 00000000..b37d39e0
--- /dev/null
+++ b/ui/src/components/modal/api-error-modal.tsx
@@ -0,0 +1,53 @@
+'use client';
+
+import {
+ AlertDialog,
+ AlertDialogHeader,
+ AlertDialogContent,
+ AlertDialogDescription,
+ AlertDialogTitle,
+ AlertDialogFooter,
+ AlertDialogAction,
+ AlertDialogCancel
+} from '@/components/ui/alert-dialog';
+import Link from 'next/link';
+import { useState } from 'react';
+
+const ApiErrorModal = ({ open }: { open: boolean }) => {
+ const [openApiErrorModal, setOpenApiErrorModal] = useState(open);
+
+ /**
+ * Closes the modal.
+ */
+ const close = () => {
+ setOpenApiErrorModal(false);
+ };
+ return (
+
+
+
+ Error
+
+ There was an unexpected communications problem. Please use your browser to refresh the page and
+ try again.
+
+
+ If the error persists please refer to our
+ close()}>
+ {' '}
+ feedback page.
+
+
+
+
+ close()}>OK
+
+ close()}>Feedback
+
+
+
+
+ );
+};
+
+export default ApiErrorModal;
diff --git a/ui/tests/app/_components/modal/api-error-modal.test.tsx b/ui/tests/app/_components/modal/api-error-modal.test.tsx
new file mode 100644
index 00000000..77ea79d9
--- /dev/null
+++ b/ui/tests/app/_components/modal/api-error-modal.test.tsx
@@ -0,0 +1,51 @@
+import { fireEvent, render, screen } from '@testing-library/react';
+import ApiErrorModal from '@/components/modal/api-error-modal';
+
+jest.mock('@/access/authentication');
+
+describe('ApiErrorModal', () => {
+ it('should open the API Error modal', () => {
+ render();
+ fireEvent.focus(document);
+
+ expect(screen.getByRole('alertdialog', { name: 'Error' })).toBeInTheDocument();
+ expect(screen.getByRole('link', { name: 'feedback page.' })).toHaveAttribute('href', '/feedback');
+ expect(screen.getByRole('link', { name: 'Feedback' })).toHaveAttribute('href', '/feedback');
+ expect(screen.getByRole('button', { name: 'OK' }));
+ expect(screen.getByRole('button', { name: 'Feedback' }));
+ });
+
+ it('should close the API Error modal if open evaluates to false', () => {
+ render();
+ fireEvent.focus(document);
+
+ expect(screen.queryByRole('alertdialog', { name: 'Error' })).not.toBeInTheDocument();
+ });
+
+ it('should close the modal after clicking the Feedback button', () => {
+ render();
+ fireEvent.focus(document);
+
+ expect(screen.getByRole('alertdialog', { name: 'Error' })).toBeInTheDocument();
+ fireEvent.click(screen.getByRole('button', { name: 'Feedback' }));
+ expect(screen.queryByRole('alertdialog', { name: 'Error' })).not.toBeInTheDocument();
+ });
+
+ it('should close the modal after clicking the provided link', () => {
+ render();
+ fireEvent.focus(document);
+
+ expect(screen.getByRole('alertdialog', { name: 'Error' })).toBeInTheDocument();
+ fireEvent.click(screen.getByRole('link', { name: 'feedback page.' }));
+ expect(screen.queryByRole('alertdialog', { name: 'Error' })).not.toBeInTheDocument();
+ });
+
+ it('should close the modal after clicking the OK button', () => {
+ render();
+ fireEvent.focus(document);
+
+ expect(screen.getByRole('alertdialog', { name: 'Error' })).toBeInTheDocument();
+ fireEvent.click(screen.getByRole('button', { name: 'OK' }));
+ expect(screen.queryByRole('alertdialog', { name: 'Error' })).not.toBeInTheDocument();
+ });
+});