diff --git a/ui/src/components/modal/dynamic-modal.tsx b/ui/src/components/modal/dynamic-modal.tsx new file mode 100644 index 00000000..d8933183 --- /dev/null +++ b/ui/src/components/modal/dynamic-modal.tsx @@ -0,0 +1,56 @@ +'use client'; + +import { + AlertDialog, + AlertDialogHeader, + AlertDialogContent, + AlertDialogDescription, + AlertDialogTitle, + AlertDialogFooter, + AlertDialogCancel +} from '@/components/ui/alert-dialog'; +import { ReactNode, useState } from 'react'; +import { Button } from '@/components/ui/button'; + +const DynamicModal = ({ + open, + title, + body, + buttons +}: { + open: boolean; + title: string; + body: string; + buttons?: ReactNode[]; +}) => { + const [openDynamicModal, setOpenDynamicModal] = useState(open); + + /** + * Closes the modal. + */ + const close = () => { + setOpenDynamicModal(false); + }; + + return ( + + + + {title} + {body} + + + close()}>OK + {/*Any buttons that should lead the user to a different page.*/} + {buttons?.map((button, index) => ( + + ))} + + + + ); +}; + +export default DynamicModal; diff --git a/ui/tests/components/modal/dynamic-modal.test.tsx b/ui/tests/components/modal/dynamic-modal.test.tsx new file mode 100644 index 00000000..f52cef0b --- /dev/null +++ b/ui/tests/components/modal/dynamic-modal.test.tsx @@ -0,0 +1,74 @@ +import { fireEvent, render, screen } from '@testing-library/react'; +import DynamicModal from '@/components/modal/dynamic-modal'; +import Link from 'next/link'; + +describe('DynamicModal', () => { + it('should open an informational modal with test contents and no extra buttons', () => { + render(); + fireEvent.focus(document); + + expect(screen.getByRole('alertdialog', { name: 'A Dynamic Title' })).toBeInTheDocument(); + expect(screen.getByRole('alertdialog')).toHaveTextContent('Some dynamic message here.'); + + expect(screen.getByRole('button', { name: 'OK' })).toBeInTheDocument(); + }); + + it('should open an informational modal with test contents and extra buttons', () => { + render( + Button1, <>Button2]} + /> + ); + fireEvent.focus(document); + + expect(screen.getByRole('alertdialog', { name: 'A Dynamic Title' })).toBeInTheDocument(); + expect(screen.getByRole('alertdialog')).toHaveTextContent('Some dynamic message here.'); + + expect(screen.getByRole('button', { name: 'OK' })).toBeInTheDocument(); + expect(screen.getByRole('button', { name: 'Button1' })).toBeInTheDocument(); + expect(screen.getByRole('button', { name: 'Button2' })).toBeInTheDocument(); + }); + + it('should close the modal upon clicking the OK button', () => { + render(); + fireEvent.focus(document); + + expect(screen.getByRole('alertdialog', { name: 'A Dynamic Title' })).toBeInTheDocument(); + expect(screen.getByRole('heading', { name: 'A Dynamic Title' })).toBeInTheDocument(); + expect(screen.getByRole('alertdialog')).toHaveTextContent('Some dynamic message here.'); + + expect(screen.getByRole('button', { name: 'OK' })).toBeInTheDocument(); + + fireEvent.click(screen.getByRole('button', { name: 'OK' })); + expect(screen.queryByRole('alertdialog', { name: 'A Dynamic Title' })).not.toBeInTheDocument(); + }); + + it('should close the modal and route to the provided link (Feedback)', () => { + render( + + Feedback + + ]} + /> + ); + fireEvent.focus(document); + + expect(screen.getByRole('alertdialog', { name: 'A Modal to the Feedback Page' })).toBeInTheDocument(); + expect(screen.getByRole('alertdialog')).toHaveTextContent('Click Feedback to go to the Feedback Page.'); + + expect(screen.getByRole('button', { name: 'OK' })).toBeInTheDocument(); + expect(screen.getByRole('button', { name: 'Feedback' })).toBeInTheDocument(); + expect(screen.getByRole('link', { name: 'Feedback' })).toHaveAttribute('href', '/feedback'); + + fireEvent.click(screen.getByRole('button', { name: 'Feedback' })); + expect(screen.queryByRole('alertdialog', { name: 'A Modal to the Feedback Page' })).not.toBeInTheDocument(); + }); +});