diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 000000000..ed94f44b1 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,3 @@ +{ + "git.ignoreLimitWarning": true +} \ No newline at end of file diff --git a/apps/frontend/src/app.tsx b/apps/frontend/src/app.tsx index 230bd3a22..5a7efaa9d 100644 --- a/apps/frontend/src/app.tsx +++ b/apps/frontend/src/app.tsx @@ -1,10 +1,6 @@ import { createBrowserRouter, RouterProvider } from 'react-router-dom'; import Root from '@containers/root'; import NotFound from '@containers/404'; -import PantryPastOrders from '@containers/pantryPastOrders'; -import Pantries from '@containers/pantries'; -import Orders from '@containers/orders'; -import PantryDashboard from '@containers/pantryDashboard'; import FormRequests from '@containers/formRequests'; import PantryApplication from '@containers/pantryApplication'; import ApplicationSubmitted from '@containers/applicationSubmitted'; @@ -12,12 +8,12 @@ import { submitPantryApplicationForm } from '@components/forms/pantryApplication import ApprovePantries from '@containers/approvePantries'; import PantryApplicationDetails from '@containers/pantryApplicationDetails'; import VolunteerManagement from '@containers/volunteerManagement'; -import FoodManufacturerOrderDashboard from '@containers/foodManufacturerOrderDashboard'; import AdminDonation from '@containers/adminDonation'; import Homepage from '@containers/homepage'; import AdminOrderManagement from '@containers/adminOrderManagement'; import { Amplify } from 'aws-amplify'; import CognitoAuthConfig from './aws-exports'; +import { ROUTES } from './routes'; import FoodManufacturerDonationManagement from '@containers/foodManufacturerDonationManagement'; import LoginPage from '@containers/loginPage'; import SignupPage from '@containers/signupPage'; @@ -42,7 +38,7 @@ Amplify.configure(CognitoAuthConfig); const router = createBrowserRouter([ { - path: '/', + path: ROUTES.HOME, element: , errorElement: , children: [ @@ -52,94 +48,37 @@ const router = createBrowserRouter([ element: , }, { - path: '/login', + path: ROUTES.LOGIN, element: , }, { - path: '/signup', + path: ROUTES.SIGNUP, element: , }, { - path: '/forgot-password', + path: ROUTES.FORGOT_PASSWORD, element: , }, { - path: '/pantry-application', + path: ROUTES.PANTRY_APPLICATION, element: , action: submitPantryApplicationForm, }, { - path: '/food-manufacturer-application', + path: ROUTES.FOOD_MANUFACTURER_APPLICATION, element: , action: submitManufacturerApplicationForm, }, { - path: '/application-submitted', + path: ROUTES.APPLICATION_SUBMITTED, element: , }, { - path: '/unauthorized', + path: ROUTES.UNAUTHORIZED, element: , }, - // Private routes (protected by auth) { - path: '/pantry-past-orders', - element: ( - - - - ), - }, - { - path: '/pantries', - element: ( - - - - ), - }, - { - path: '/pantry-dashboard', - element: ( - - - - ), - }, - { - path: '/pantry-past-orders', - element: ( - - - - ), - }, - { - path: '/pantries', - element: ( - - - - ), - }, - { - path: '/food-manufacturer-order-dashboard', - element: ( - - - - ), - }, - { - path: '/orders', - element: ( - - - - ), - }, - { - path: '/request-form', + path: ROUTES.REQUEST_FORM, element: ( @@ -147,7 +86,7 @@ const router = createBrowserRouter([ ), }, { - path: '/fm-donation-management', + path: ROUTES.FM_DONATION_MANAGEMENT, element: ( @@ -155,7 +94,7 @@ const router = createBrowserRouter([ ), }, { - path: '/approve-pantries', + path: ROUTES.APPROVE_PANTRIES, element: ( @@ -163,7 +102,7 @@ const router = createBrowserRouter([ ), }, { - path: '/approve-food-manufacturers', + path: ROUTES.APPROVE_FOOD_MANUFACTURERS, element: ( @@ -171,7 +110,7 @@ const router = createBrowserRouter([ ), }, { - path: '/pantry-application-details/:applicationId', + path: ROUTES.PANTRY_APPLICATION_DETAILS, element: ( @@ -179,7 +118,7 @@ const router = createBrowserRouter([ ), }, { - path: '/food-manufacturer-application-details/:applicationId', + path: ROUTES.FOOD_MANUFACTURER_APPLICATION_DETAILS, element: ( @@ -187,7 +126,7 @@ const router = createBrowserRouter([ ), }, { - path: '/admin-donation', + path: ROUTES.ADMIN_DONATION, element: ( @@ -195,7 +134,7 @@ const router = createBrowserRouter([ ), }, { - path: '/admin-donation-stats', + path: ROUTES.ADMIN_DONATION_STATS, element: ( @@ -203,31 +142,31 @@ const router = createBrowserRouter([ ), }, { - path: '/test-admin-dashboard', + path: ROUTES.VOLUNTEER_MANAGEMENT, element: ( - + ), }, { - path: '/admin-request-management', + path: ROUTES.TEST_ADMIN_DASHBOARD, element: ( - + ), }, { - path: '/volunteer-management', + path: ROUTES.ADMIN_REQUEST_MANAGEMENT, element: ( - + ), }, { - path: '/admin-order-management', + path: ROUTES.ADMIN_ORDER_MANAGEMENT, element: ( @@ -235,7 +174,7 @@ const router = createBrowserRouter([ ), }, { - path: '/pantry-order-management', + path: ROUTES.PANTRY_ORDER_MANAGEMENT, element: ( @@ -243,7 +182,7 @@ const router = createBrowserRouter([ ), }, { - path: '/profile', + path: ROUTES.PROFILE, element: ( @@ -251,7 +190,7 @@ const router = createBrowserRouter([ ), }, { - path: '/volunteer-assigned-pantries', + path: ROUTES.VOLUNTEER_ASSIGNED_PANTRIES, element: ( @@ -259,7 +198,7 @@ const router = createBrowserRouter([ ), }, { - path: '/volunteer-request-management', + path: ROUTES.VOLUNTEER_REQUEST_MANAGEMENT, element: ( @@ -267,7 +206,7 @@ const router = createBrowserRouter([ ), }, { - path: '/volunteer-order-management', + path: ROUTES.VOLUNTEER_ORDER_MANAGEMENT, element: ( diff --git a/apps/frontend/src/components/AuthHeader.tsx b/apps/frontend/src/components/AuthHeader.tsx new file mode 100644 index 000000000..bb76e46c1 --- /dev/null +++ b/apps/frontend/src/components/AuthHeader.tsx @@ -0,0 +1,23 @@ +import { Box } from '@chakra-ui/react'; + +const AuthHeader: React.FC = () => ( + + + SSF + + +); + +export default AuthHeader; diff --git a/apps/frontend/src/components/Navbar.tsx b/apps/frontend/src/components/Navbar.tsx new file mode 100644 index 000000000..8875fa34a --- /dev/null +++ b/apps/frontend/src/components/Navbar.tsx @@ -0,0 +1,395 @@ +import React, { useEffect, useState } from 'react'; +import { Link as RouterLink, useLocation, useNavigate } from 'react-router-dom'; +import { Box, Flex, Text, VStack } from '@chakra-ui/react'; +import { useAuthenticator } from '@aws-amplify/ui-react'; +import { signOut } from 'aws-amplify/auth'; +import { ChevronDown, ChevronRight, LogOut } from 'lucide-react'; +import ApiClient from '@api/apiClient'; +import { Role, User } from '../types/types'; +import { ROUTES } from '../routes'; + +const ROLE_MAP: Record = { + [Role.ADMIN]: { label: 'Admin' }, + [Role.VOLUNTEER]: { label: 'Volunteer' }, + [Role.PANTRY]: { label: 'Pantry' }, + [Role.FOODMANUFACTURER]: { label: 'Manufacturer' }, +}; + +// Nav Structure Types +type FlatNav = { type: 'flat'; label: string; to: string }; +type GroupNav = { + type: 'group'; + label: string; + children: Array<{ label: string; to: string }>; +}; +type NavSection = FlatNav | GroupNav; + +// Role Nav Definitions +const ROLE_NAV_SECTIONS: Record = { + [Role.ADMIN]: [ + { + type: 'group', + label: 'Volunteers', + children: [ + { label: 'Volunteer Management', to: ROUTES.VOLUNTEER_MANAGEMENT }, + ], + }, + { + type: 'group', + label: 'Pantries', + children: [ + { label: 'Pantry Management', to: ROUTES.PANTRY_MANAGEMENT }, + { label: 'Application Review', to: ROUTES.APPROVE_PANTRIES }, + ], + }, + { + type: 'group', + label: 'Orders', + children: [ + { label: 'Order Management', to: ROUTES.ADMIN_ORDER_MANAGEMENT }, + { label: 'Food Requests', to: ROUTES.FOOD_REQUESTS }, + ], + }, + { + type: 'group', + label: 'Manufacturers', + children: [ + { label: 'Donation Management', to: ROUTES.ADMIN_DONATION }, + { label: 'Application Review', to: ROUTES.APPROVE_FOOD_MANUFACTURERS }, + { label: 'Donation Statistics', to: ROUTES.ADMIN_DONATION_STATS }, + ], + }, + ], + [Role.VOLUNTEER]: [ + { + type: 'flat', + label: 'Assigned Pantries', + to: ROUTES.VOLUNTEER_ASSIGNED_PANTRIES, + }, + { + type: 'group', + label: 'Orders', + children: [ + { + label: 'Order Management', + to: ROUTES.VOLUNTEER_ORDER_MANAGEMENT, + }, + { + label: 'Food Requests', + to: ROUTES.VOLUNTEER_REQUEST_MANAGEMENT, + }, + ], + }, + ], + [Role.FOODMANUFACTURER]: [ + { + type: 'group', + label: 'Donations', + children: [ + { label: 'Donation Management', to: ROUTES.FM_DONATION_MANAGEMENT }, + ], + }, + ], + [Role.PANTRY]: [ + { + type: 'group', + label: 'Orders', + children: [ + { label: 'Order Management', to: ROUTES.PANTRY_ORDER_MANAGEMENT }, + { label: 'Food Requests', to: ROUTES.REQUEST_FORM }, + ], + }, + ], +}; + +// Subcomponents +const NavLink: React.FC<{ + to: string; + label: string; + isActive: boolean; +}> = ({ to, label, isActive }) => ( + + + + {label} + + + +); + +interface NavGroupProps { + label: string; + children: Array<{ label: string; to: string }>; + isOpen: boolean; + onToggle: () => void; + activePath: string; +} + +const NavGroup: React.FC = ({ + label, + children, + isOpen, + onToggle, + activePath, +}) => ( + + + + {label} + + {isOpen ? ( + + ) : ( + + )} + + + {isOpen && + children.map((child) => { + const isActive = activePath === child.to; + return ( + + + + + + + + + {child.label} + + + + + ); + })} + +); + +const Navbar: React.FC = () => { + const { authStatus } = useAuthenticator((context) => [context.authStatus]); + const [currentUser, setCurrentUser] = useState(null); + const [openGroups, setOpenGroups] = useState>(new Set()); + const location = useLocation(); + const navigate = useNavigate(); + + useEffect(() => { + if (authStatus === 'authenticated') { + ApiClient.getMe() + .then(setCurrentUser) + .catch(() => setCurrentUser(null)); + } else { + setCurrentUser(null); + } + }, [authStatus]); + + // On reload or navigation, make sure the currently opened groups stays open + useEffect(() => { + if (!currentUser) return; + const sections = ROLE_NAV_SECTIONS[currentUser.role]; + setOpenGroups((prev) => { + const next = new Set(prev); + sections.forEach((s) => { + if ( + s.type === 'group' && + s.children.some((c) => c.to === location.pathname) + ) { + next.add(s.label); + } + }); + return next; + }); + }, [location.pathname, currentUser]); + + if (authStatus !== 'authenticated' || !currentUser) return null; + + const roleLabel = ROLE_MAP[currentUser.role].label; + const sections: NavSection[] = ROLE_NAV_SECTIONS[currentUser.role]; + const email = currentUser.email; + + const toggleGroup = (label: string) => { + setOpenGroups((prev) => { + const next = new Set(prev); + if (next.has(label)) next.delete(label); + else next.add(label); + return next; + }); + }; + + const handleSignOut = async () => { + await signOut(); + navigate(ROUTES.LOGIN, { replace: true }); + }; + + return ( + + + + + SSF logo + + + + {roleLabel ? `${roleLabel} Dashboard` : 'Dashboard'} + + + {email} + + + + + + + + + {sections.map((section) => + section.type === 'flat' ? ( + + ) : ( + toggleGroup(section.label)} + activePath={location.pathname} + /> + ), + )} + + + + + + Sign Out + + + + ); +}; + +export default Navbar; diff --git a/apps/frontend/src/components/forms/manufacturerApplicationForm.tsx b/apps/frontend/src/components/forms/manufacturerApplicationForm.tsx index ab70c93fe..e104581cf 100644 --- a/apps/frontend/src/components/forms/manufacturerApplicationForm.tsx +++ b/apps/frontend/src/components/forms/manufacturerApplicationForm.tsx @@ -36,6 +36,7 @@ import { } from '../../types/manufacturerEnums'; import { FloatingAlert } from '@components/floatingAlert'; import { useAlert } from '../../hooks/alert'; +import { ROUTES } from '../../routes'; const ManufacturerApplicationForm: React.FC = () => { const [contactPhone, setContactPhone] = useState(''); @@ -107,7 +108,7 @@ const ManufacturerApplicationForm: React.FC = () => { borderColor="neutral.200" rounded="sm" > -
+ Food Manufacturer Application Form @@ -721,7 +722,7 @@ export const submitManufacturerApplicationForm: ActionFunction = async ({ try { await ApiClient.postManufacturer(data as ManufacturerApplicationDto); - return redirect('/application-submitted'); + return redirect(ROUTES.APPLICATION_SUBMITTED); } catch (error) { if (axios.isAxiosError(error) && error.response?.status === 400) { return { diff --git a/apps/frontend/src/components/forms/pantryApplicationForm.tsx b/apps/frontend/src/components/forms/pantryApplicationForm.tsx index f580de481..526de1d1d 100644 --- a/apps/frontend/src/components/forms/pantryApplicationForm.tsx +++ b/apps/frontend/src/components/forms/pantryApplicationForm.tsx @@ -32,6 +32,7 @@ import { ChevronDownIcon } from 'lucide-react'; import { TagGroup } from './tagGroup'; import { FloatingAlert } from '@components/floatingAlert'; import { useAlert } from '../../hooks/alert'; +import { ROUTES } from '../../routes'; export const otherRestrictionsOptions: string[] = [ 'Other allergy (e.g., yeast, sunflower, etc.)', @@ -142,7 +143,7 @@ const PantryApplicationForm: React.FC = () => { borderColor="neutral.200" rounded="sm" > - + Pantry Application Form @@ -1210,7 +1211,7 @@ export const submitPantryApplicationForm: ActionFunction = async ({ try { await ApiClient.postPantry(data as PantryApplicationDto); - return redirect('/application-submitted'); + return redirect(ROUTES.APPLICATION_SUBMITTED); } catch (error) { if (axios.isAxiosError(error) && error.response?.status === 400) { return { diff --git a/apps/frontend/src/components/signOutButton.tsx b/apps/frontend/src/components/signOutButton.tsx index 5b7abec01..2de170fe2 100644 --- a/apps/frontend/src/components/signOutButton.tsx +++ b/apps/frontend/src/components/signOutButton.tsx @@ -2,6 +2,7 @@ import apiClient from '@api/apiClient'; import { Button, ButtonProps } from '@chakra-ui/react'; import { signOut } from 'aws-amplify/auth'; import { useNavigate } from 'react-router-dom'; +import { ROUTES } from '../routes'; type SignOutButtonProps = ButtonProps; @@ -10,7 +11,7 @@ const SignOutButton: React.FC = (props) => { const handleSignOut = async () => { await signOut(); - navigate('/'); + navigate(ROUTES.LOGIN, { replace: true }); }; return ( diff --git a/apps/frontend/src/containers/foodManufacturerApplicationDetails.tsx b/apps/frontend/src/containers/foodManufacturerApplicationDetails.tsx index 5147e3e35..f60646c8b 100644 --- a/apps/frontend/src/containers/foodManufacturerApplicationDetails.tsx +++ b/apps/frontend/src/containers/foodManufacturerApplicationDetails.tsx @@ -12,7 +12,7 @@ import { Spinner, } from '@chakra-ui/react'; import ApiClient from '@api/apiClient'; -import { FoodManufacturer } from 'types/types'; +import { ApplicationStatus, FoodManufacturer } from '../types/types'; import { formatDate, formatPhone } from '@utils/utils'; import { TagGroup } from '@components/forms/tagGroup'; import { FileX, TriangleAlert, WifiOff } from 'lucide-react'; @@ -20,6 +20,7 @@ import { AxiosError } from 'axios'; import { FloatingAlert } from '@components/floatingAlert'; import { useAlert } from '../hooks/alert'; import ConfirmFoodManufacturerDecisionModal from '@components/forms/confirmFoodManufacturerDecisionModal'; +import { ROUTES } from '../routes'; interface EmptyStateProps { icon: React.ReactNode; @@ -73,7 +74,7 @@ const EmptyState: React.FC = ({ textStyle="p2" fontWeight={600} > - + Return to applications @@ -170,7 +171,10 @@ const FoodManufacturerApplicationDetails: React.FC = () => { 'approve', ); navigate( - '/approve-food-manufacturers?action=approved&name=' + + ROUTES.APPROVE_FOOD_MANUFACTURERS + + '?action=' + + ApplicationStatus.APPROVED + + '&name=' + application.foodManufacturerName, ); } catch { @@ -187,7 +191,10 @@ const FoodManufacturerApplicationDetails: React.FC = () => { 'deny', ); navigate( - '/approve-food-manufacturers?action=denied&name=' + + ROUTES.APPROVE_FOOD_MANUFACTURERS + + '?action=' + + ApplicationStatus.DENIED + + '&name=' + application.foodManufacturerName, ); } catch { diff --git a/apps/frontend/src/containers/foodManufacturerOrderDashboard.tsx b/apps/frontend/src/containers/foodManufacturerOrderDashboard.tsx deleted file mode 100644 index b118f0a78..000000000 --- a/apps/frontend/src/containers/foodManufacturerOrderDashboard.tsx +++ /dev/null @@ -1,113 +0,0 @@ -import React, { useEffect, useState } from 'react'; -import { Center, Table, Button, ButtonGroup, VStack } from '@chakra-ui/react'; -import ApiClient from '@api/apiClient'; -import { Order } from 'types/types'; -import OrderInformationModal from '@components/forms/orderInformationModal'; -import { formatDate } from '@utils/utils'; - -const FoodManufacturerOrderDashboard: React.FC = () => { - const [orders, setOrders] = useState([]); - const [orderType, setOrderType] = useState<'current' | 'past'>('current'); - const [openOrderId, setOpenOrderId] = useState(null); - - useEffect(() => { - fetchOrders(); - }, [orderType]); - - const fetchOrders = async () => { - try { - const data = - orderType === 'current' - ? await ApiClient.getCurrentOrders() - : await ApiClient.getPastOrders(); - setOrders(data); - } catch (error) { - alert('Error fetching orders: ' + error); - } - }; - - const updateOrderStatus = async ( - orderId: number, - newStatus: 'shipped' | 'delivered', - ) => { - try { - await ApiClient.updateOrderStatus(orderId, newStatus); - fetchOrders(); - } catch (error) { - alert(`Error updating order status: ` + error); - } - }; - - return ( -
- - - - - - - - - - Order ID - Date Placed - Status - Actions - - - - {orders.map((order) => ( - - - - - {formatDate(order.createdAt)} - {order.status} - - - {order.status === 'pending' && ( - - )} - - - - ))} - {openOrderId && ( - setOpenOrderId(null)} - /> - )} - - - -
- ); -}; - -export default FoodManufacturerOrderDashboard; diff --git a/apps/frontend/src/containers/forgotPasswordPage.tsx b/apps/frontend/src/containers/forgotPasswordPage.tsx index e2d4405fb..7e9c0d5f6 100644 --- a/apps/frontend/src/containers/forgotPasswordPage.tsx +++ b/apps/frontend/src/containers/forgotPasswordPage.tsx @@ -1,20 +1,23 @@ import { Box } from '@chakra-ui/react'; import loginBackground from '../assets/login_background.png'; import ResetPasswordModal from '@components/forms/resetPasswordModal'; +import AuthHeader from '@components/AuthHeader'; const ForgotPasswordPage: React.FC = () => { return ( - - + + + + + ); }; diff --git a/apps/frontend/src/containers/homepage.tsx b/apps/frontend/src/containers/homepage.tsx index 75c7c3656..26750cb02 100644 --- a/apps/frontend/src/containers/homepage.tsx +++ b/apps/frontend/src/containers/homepage.tsx @@ -24,7 +24,7 @@ const Homepage: React.FC = () => { - + Profile View @@ -33,16 +33,6 @@ const Homepage: React.FC = () => { Pantry View - - - Pantry Dashboard - - - - - Past Orders - - Request Form @@ -70,18 +60,6 @@ const Homepage: React.FC = () => { Food Manufacturer View - - - - Order Dashboard - - - - - - Orders - - diff --git a/apps/frontend/src/containers/loginPage.tsx b/apps/frontend/src/containers/loginPage.tsx index e3fc46909..1cc951dfd 100644 --- a/apps/frontend/src/containers/loginPage.tsx +++ b/apps/frontend/src/containers/loginPage.tsx @@ -16,6 +16,8 @@ import loginBackground from '../assets/login_background.png'; import { Eye, EyeOff } from 'lucide-react'; import { FloatingAlert } from '@components/floatingAlert'; import { useAlert } from '../hooks/alert'; +import AuthHeader from '@components/AuthHeader'; +import { ROUTES } from '../routes'; type Step = 'login' | 'new-password'; @@ -87,192 +89,204 @@ const LoginPage: React.FC = () => { }; return ( - - {alertState && ( - - )} + + - {step === 'login' ? ( - - - Log In - - Welcome to the Securing Safe Food (SSF) Portal. Please log in - with your account credentials. - - - - - Email - setEmail(e.target.value)} - /> - + {alertState && ( + + )} + + {step === 'login' ? ( + + + Log In + + Welcome to the Securing Safe Food (SSF) Portal. Please log in + with your account credentials. + + - - Password - + + Email setPassword(e.target.value)} + onChange={(e) => setEmail(e.target.value)} /> - setShowPassword((prev) => !prev)} - > - - {showPassword && } - {!showPassword && } - - - - + - - - ) : ( - - - Set New Password - - Your account requires a new password before continuing. Your - password should be at least 8 characters. - - + + Password + + setPassword(e.target.value)} + /> + setShowPassword((prev) => !prev)} + > + + {showPassword && } + {!showPassword && } + + + + - - New Password - - setNewPassword(e.target.value)} - /> - setShowNewPassword((prev) => !prev)} - > - - {showNewPassword && } - {!showNewPassword && } - - - - + + + ) : ( + + + Set New Password + + Your account requires a new password before continuing. Your + password should be at least 8 characters. + + - - Confirm Password - - setConfirmNewPassword(e.target.value)} - /> - setShowConfirmNewPassword((prev) => !prev)} - > - - {showConfirmNewPassword && } - {!showConfirmNewPassword && } - - - - + + New Password + + setNewPassword(e.target.value)} + /> + setShowNewPassword((prev) => !prev)} + > + + {showNewPassword && } + {!showNewPassword && } + + + + - - - )} + + + Confirm Password + + + setConfirmNewPassword(e.target.value)} + /> + setShowConfirmNewPassword((prev) => !prev)} + > + + {showConfirmNewPassword && } + {!showConfirmNewPassword && } + + + + + + + + )} - {step === 'login' && ( - <> - - Don't have an account?{' '} - + navigate('/signup')} - variant="underline" - textDecorationColor="neutral.300" + textAlign="center" + mt={6} > - Sign up - - + Don't have an account?{' '} + navigate(ROUTES.SIGNUP)} + variant="underline" + textDecorationColor="neutral.300" + > + Sign up + + - - navigate('/forgot-password')}> - Reset Password - - - - )} + + navigate(ROUTES.FORGOT_PASSWORD)} + > + Forgot Password? + + + + )} + ); diff --git a/apps/frontend/src/containers/orders.tsx b/apps/frontend/src/containers/orders.tsx deleted file mode 100644 index b4aa4db9b..000000000 --- a/apps/frontend/src/containers/orders.tsx +++ /dev/null @@ -1,5 +0,0 @@ -const Orders: React.FC = () => { - return <>Orders; -}; - -export default Orders; diff --git a/apps/frontend/src/containers/pantries.tsx b/apps/frontend/src/containers/pantries.tsx deleted file mode 100644 index 91e9e22df..000000000 --- a/apps/frontend/src/containers/pantries.tsx +++ /dev/null @@ -1,5 +0,0 @@ -const Pantries: React.FC = () => { - return <>Pantries; -}; - -export default Pantries; diff --git a/apps/frontend/src/containers/pantryApplicationDetails.tsx b/apps/frontend/src/containers/pantryApplicationDetails.tsx index 978140065..e9766eeba 100644 --- a/apps/frontend/src/containers/pantryApplicationDetails.tsx +++ b/apps/frontend/src/containers/pantryApplicationDetails.tsx @@ -12,7 +12,7 @@ import { Spinner, } from '@chakra-ui/react'; import ApiClient from '@api/apiClient'; -import { PantryWithUser } from 'types/types'; +import { ApplicationStatus, PantryWithUser } from '../types/types'; import { formatDate, formatPhone } from '@utils/utils'; import { TagGroup } from '@components/forms/tagGroup'; import { FileX, TriangleAlert, WifiOff } from 'lucide-react'; @@ -20,6 +20,7 @@ import { AxiosError } from 'axios'; import { FloatingAlert } from '@components/floatingAlert'; import ConfirmPantryDecisionModal from '@components/forms/confirmPantryDecisionModal'; import { useAlert } from '../hooks/alert'; +import { ROUTES } from '../routes'; interface EmptyStateProps { icon: React.ReactNode; @@ -73,7 +74,7 @@ const EmptyState: React.FC = ({ textStyle="p2" fontWeight={600} > - Return to applications + Return to applications )} @@ -163,7 +164,11 @@ const PantryApplicationDetails: React.FC = () => { try { await ApiClient.updatePantry(application.pantryId, 'approve'); navigate( - '/approve-pantries?action=approved&name=' + application.pantryName, + ROUTES.APPROVE_PANTRIES + + '?action=' + + ApplicationStatus.APPROVED + + '&name=' + + application.pantryName, ); } catch { setAlertMessage('Error approving application'); @@ -176,7 +181,11 @@ const PantryApplicationDetails: React.FC = () => { try { await ApiClient.updatePantry(application.pantryId, 'deny'); navigate( - '/approve-pantries?action=denied&name=' + application.pantryName, + ROUTES.APPROVE_PANTRIES + + '?action=' + + ApplicationStatus.DENIED + + '&name=' + + application.pantryName, ); } catch { setAlertMessage('Error denying application'); diff --git a/apps/frontend/src/containers/pantryPastOrders.tsx b/apps/frontend/src/containers/pantryPastOrders.tsx deleted file mode 100644 index 260a492f9..000000000 --- a/apps/frontend/src/containers/pantryPastOrders.tsx +++ /dev/null @@ -1,5 +0,0 @@ -const PantryPastOrders: React.FC = () => { - return <>Pantry past orders; -}; - -export default PantryPastOrders; diff --git a/apps/frontend/src/containers/root.tsx b/apps/frontend/src/containers/root.tsx index 214d09b74..9e216caaf 100644 --- a/apps/frontend/src/containers/root.tsx +++ b/apps/frontend/src/containers/root.tsx @@ -1,7 +1,8 @@ import { Outlet, useNavigate } from 'react-router-dom'; -import Header from '../components/Header'; +import { Box, Flex } from '@chakra-ui/react'; import { useEffect } from 'react'; import apiClient from '@api/apiClient'; +import Navbar from '../components/Navbar'; const Root: React.FC = () => { const navigate = useNavigate(); @@ -11,10 +12,12 @@ const Root: React.FC = () => { }, [navigate]); return ( -
-
- -
+ + + + + + ); }; diff --git a/apps/frontend/src/containers/signupPage.tsx b/apps/frontend/src/containers/signupPage.tsx index 756c4bc71..7793ba528 100644 --- a/apps/frontend/src/containers/signupPage.tsx +++ b/apps/frontend/src/containers/signupPage.tsx @@ -1,74 +1,78 @@ import { useNavigate } from 'react-router-dom'; import { Box, Text, VStack, Button, Link } from '@chakra-ui/react'; import loginBackground from '../assets/login_background.png'; +import AuthHeader from '@components/AuthHeader'; +import { ROUTES } from '../routes'; const SignupPage: React.FC = () => { const navigate = useNavigate(); return ( - + + - - - Sign Up - - Please select your specified user type to begin your account - creation. - - + + + + Sign Up + + Please select your specified user type to begin your account + creation. + + - + - - - - Already have an account?{' '} - navigate('/login')} - variant="underline" - textDecorationColor="neutral.300" - > - Log in - - + + + + Already have an account?{' '} + navigate(ROUTES.LOGIN)} + variant="underline" + textDecorationColor="neutral.300" + > + Log in + + + ); diff --git a/apps/frontend/src/containers/volunteerAssignedPantries.tsx b/apps/frontend/src/containers/volunteerAssignedPantries.tsx index 33bdec9f8..53e37450a 100644 --- a/apps/frontend/src/containers/volunteerAssignedPantries.tsx +++ b/apps/frontend/src/containers/volunteerAssignedPantries.tsx @@ -17,6 +17,7 @@ import { RefrigeratedDonation } from '../types/pantryEnums'; import { FloatingAlert } from '@components/floatingAlert'; import { useNavigate } from 'react-router-dom'; import { useAlert } from '../hooks/alert'; +import { ROUTES } from '../routes'; const AssignedPantries: React.FC = () => { const navigate = useNavigate(); @@ -382,7 +383,9 @@ const AssignedPantries: React.FC = () => { textDecoration="underline" color="neutral.700" textStyle="p2" - onClick={() => navigate('/landing-page')} + onClick={() => + navigate(ROUTES.VOLUNTEER_REQUEST_MANAGEMENT) + } p={0} height="auto" minW="auto" diff --git a/apps/frontend/src/routes.ts b/apps/frontend/src/routes.ts new file mode 100644 index 000000000..976befab1 --- /dev/null +++ b/apps/frontend/src/routes.ts @@ -0,0 +1,38 @@ +export const ROUTES = { + HOME: '/', + + LOGIN: '/login', + SIGNUP: '/signup', + FORGOT_PASSWORD: '/forgot-password', + UNAUTHORIZED: '/unauthorized', + + PROFILE: '/profile', + + PANTRY_APPLICATION: '/pantry-application', + FOOD_MANUFACTURER_APPLICATION: '/food-manufacturer-application', + APPLICATION_SUBMITTED: '/application-submitted', + + PANTRY_APPLICATION_DETAILS: '/pantry-application-details/:applicationId', + FOOD_MANUFACTURER_APPLICATION_DETAILS: + '/food-manufacturer-application-details/:applicationId', + + APPROVE_PANTRIES: '/approve-pantries', + APPROVE_FOOD_MANUFACTURERS: '/approve-food-manufacturers', + VOLUNTEER_MANAGEMENT: '/volunteer-management', + PANTRY_MANAGEMENT: '/pantry-management', + FOOD_REQUESTS: '/food-reqeusts', + ADMIN_ORDER_MANAGEMENT: '/admin-order-management', + ADMIN_DONATION: '/admin-donation', + ADMIN_DONATION_STATS: '/admin-donation-stats', + ADMIN_REQUEST_MANAGEMENT: '/admin-request-management', + TEST_ADMIN_DASHBOARD: '/test-admin-dashboard', + + VOLUNTEER_ASSIGNED_PANTRIES: '/volunteer-assigned-pantries', + VOLUNTEER_REQUEST_MANAGEMENT: '/volunteer-request-management', + VOLUNTEER_ORDER_MANAGEMENT: '/volunteer-order-management', + + PANTRY_ORDER_MANAGEMENT: '/pantry-order-management', + REQUEST_FORM: '/request-form', + + FM_DONATION_MANAGEMENT: '/fm-donation-management', +};