diff --git a/ui/public/id-card-solid.svg b/ui/public/id-card-solid.svg new file mode 100644 index 00000000..8abeb2c8 --- /dev/null +++ b/ui/public/id-card-solid.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/ui/public/key-solid.svg b/ui/public/key-solid.svg new file mode 100644 index 00000000..7555f7ed --- /dev/null +++ b/ui/public/key-solid.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/ui/public/user-solid.svg b/ui/public/user-solid.svg new file mode 100644 index 00000000..30cbd7d3 --- /dev/null +++ b/ui/public/user-solid.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/ui/public/wrench-solid.svg b/ui/public/wrench-solid.svg new file mode 100644 index 00000000..280b3bd0 --- /dev/null +++ b/ui/public/wrench-solid.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/ui/src/components/layout/navbar/dept-account-icon.tsx b/ui/src/components/layout/navbar/dept-account-icon.tsx new file mode 100644 index 00000000..738d86eb --- /dev/null +++ b/ui/src/components/layout/navbar/dept-account-icon.tsx @@ -0,0 +1,61 @@ +'use client'; + +import { useState } from 'react'; + +import { School } from 'lucide-react'; +import DynamicModal from '@/components/modal/dynamic-modal'; +import { faUser } from '@fortawesome/free-solid-svg-icons'; +import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; +import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from '@/components/ui/tooltip'; +import User from '@/lib/access/user'; + +const DeptAccountIcon = ({ currentUser }: { currentUser: User }) => { + const [isModalOpen, setIsModalOpen] = useState(false); + const openDepartmentalModal = () => { + setIsModalOpen(true); + }; + + const closeDepartmentalModal = () => { + setIsModalOpen(false); + }; + + return ( + <> + {currentUser.uid == currentUser.uhUuid && ( +
+ + + + +
+ +
+
+ +

You are not in your personal account

+
+
+
+
+ )} + {isModalOpen && ( + + )} + + ); +}; + +export default DeptAccountIcon; diff --git a/ui/src/components/layout/navbar/navbar-menu.tsx b/ui/src/components/layout/navbar/navbar-menu.tsx index 483e605b..28260133 100644 --- a/ui/src/components/layout/navbar/navbar-menu.tsx +++ b/ui/src/components/layout/navbar/navbar-menu.tsx @@ -1,7 +1,7 @@ 'use client'; import { Sheet, SheetContent, SheetDescription, SheetHeader, SheetTitle, SheetTrigger } from '@/components/ui/sheet'; -import { User } from 'next-cas-client'; +import User from '@/lib/access/user.ts'; import Link from 'next/link'; import { NavbarLinks } from './navbar-links'; import { useState } from 'react'; diff --git a/ui/src/components/layout/navbar/navbar.tsx b/ui/src/components/layout/navbar/navbar.tsx index 8382e4bc..eb818dba 100644 --- a/ui/src/components/layout/navbar/navbar.tsx +++ b/ui/src/components/layout/navbar/navbar.tsx @@ -4,11 +4,13 @@ import { NavbarLinks } from './navbar-links'; import LoginButton from './login-button'; import NavbarMenu from './navbar-menu'; import TimeoutModal from '@/components/modal/timeout-modal'; -import { getUser } from '@/lib/access/user'; +import { getUser } from '@/lib/access/user.ts'; import Role from '@/lib/access/role'; +import DeptAccountIcon from '@/components/layout/navbar/dept-account-icon'; const Navbar = async () => { const currentUser = await getUser(); + return ( <> @@ -34,6 +36,7 @@ const Navbar = async () => { /> +
{NavbarLinks.filter( (navbarLink) => diff --git a/ui/src/components/modal/dynamic-modal.tsx b/ui/src/components/modal/dynamic-modal.tsx index d8933183..9db92515 100644 --- a/ui/src/components/modal/dynamic-modal.tsx +++ b/ui/src/components/modal/dynamic-modal.tsx @@ -9,41 +9,34 @@ import { AlertDialogFooter, AlertDialogCancel } from '@/components/ui/alert-dialog'; -import { ReactNode, useState } from 'react'; +import { ReactNode } from 'react'; import { Button } from '@/components/ui/button'; const DynamicModal = ({ open, title, body, - buttons + buttons, + onClose }: { open: boolean; title: string; body: string; buttons?: ReactNode[]; + onClose: () => void; }) => { - const [openDynamicModal, setOpenDynamicModal] = useState(open); - - /** - * Closes the modal. - */ - const close = () => { - setOpenDynamicModal(false); - }; - return ( - + {title} {body} - close()}>OK + OK {/*Any buttons that should lead the user to a different page.*/} {buttons?.map((button, index) => ( - ))} diff --git a/ui/tests/components/modal/dynamic-modal.test.tsx b/ui/tests/components/modal/dynamic-modal.test.tsx index f52cef0b..2df95ced 100644 --- a/ui/tests/components/modal/dynamic-modal.test.tsx +++ b/ui/tests/components/modal/dynamic-modal.test.tsx @@ -1,10 +1,14 @@ import { fireEvent, render, screen } from '@testing-library/react'; import DynamicModal from '@/components/modal/dynamic-modal'; import Link from 'next/link'; +import { useState } from 'react'; describe('DynamicModal', () => { it('should open an informational modal with test contents and no extra buttons', () => { - render(); + const onClose = jest.fn(); + render( + + ); fireEvent.focus(document); expect(screen.getByRole('alertdialog', { name: 'A Dynamic Title' })).toBeInTheDocument(); @@ -14,11 +18,13 @@ describe('DynamicModal', () => { }); it('should open an informational modal with test contents and extra buttons', () => { + const onClose = jest.fn(); render( Button1, <>Button2]} /> ); @@ -33,7 +39,16 @@ describe('DynamicModal', () => { }); it('should close the modal upon clicking the OK button', () => { - render(); + const onClose = jest.fn(); + render( + + ); fireEvent.focus(document); expect(screen.getByRole('alertdialog', { name: 'A Dynamic Title' })).toBeInTheDocument(); @@ -43,15 +58,18 @@ describe('DynamicModal', () => { expect(screen.getByRole('button', { name: 'OK' })).toBeInTheDocument(); fireEvent.click(screen.getByRole('button', { name: 'OK' })); - expect(screen.queryByRole('alertdialog', { name: 'A Dynamic Title' })).not.toBeInTheDocument(); + // Cannot use useState in the test environment so expect the onClose function to be called once. + expect(onClose).toHaveBeenCalledTimes(1); // Assumes the onClose function toggles a useState variable. }); it('should close the modal and route to the provided link (Feedback)', () => { + const onClose = jest.fn(); render( Feedback @@ -69,6 +87,7 @@ describe('DynamicModal', () => { 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(); + // Cannot use useState in the test environment so expect the onClose function to be called once. + expect(onClose).toHaveBeenCalledTimes(1); // Assumes the onClose function toggles a useState variable. }); });