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(); + }); +});