diff --git a/apps/frontend/src/app.tsx b/apps/frontend/src/app.tsx index 89e0fccf..625bd25d 100644 --- a/apps/frontend/src/app.tsx +++ b/apps/frontend/src/app.tsx @@ -22,6 +22,7 @@ import DonationManagement from '@containers/donationManagement'; import AdminDonation from '@containers/adminDonation'; import { pantryIdLoader } from '@loaders/pantryIdLoader'; import Homepage from '@containers/homepage'; +import AssignedPantries from '@containers/volunteerAssignedPantries' const router = createBrowserRouter([ { @@ -96,6 +97,10 @@ const router = createBrowserRouter([ path: '/volunteer-management', element: , }, + { + path: '/volunteer-assigned-pantries', + element: , + }, ], }, ]); diff --git a/apps/frontend/src/containers/homepage.tsx b/apps/frontend/src/containers/homepage.tsx index a753762b..c39cca69 100644 --- a/apps/frontend/src/containers/homepage.tsx +++ b/apps/frontend/src/containers/homepage.tsx @@ -133,6 +133,11 @@ const Homepage: React.FC = () => { Pantry Overview + + + Volunteer Assigned Pantries + + diff --git a/apps/frontend/src/containers/volunteerAssignedPantries.tsx b/apps/frontend/src/containers/volunteerAssignedPantries.tsx new file mode 100644 index 00000000..28a6f1f5 --- /dev/null +++ b/apps/frontend/src/containers/volunteerAssignedPantries.tsx @@ -0,0 +1,289 @@ +import React, { useState, useEffect } from 'react'; +import { Funnel } from 'lucide-react'; +import { + Box, + Button, + Table, + Heading, + VStack, + Checkbox, + Text, +} from '@chakra-ui/react'; +import ApiClient from '@api/apiClient'; +import { Pantry } from 'types/types'; +import { RefrigeratedDonation } from '../types/pantryEnums'; +import { Assignments } from 'types/volunteerAssignments'; + +const AssignedPantries: React.FC = () => { + const [assignments, setAssignments] = useState([]); + const [filteredAssignments, setFilteredAssignments] = useState([]); + const [pantryDetails, setPantryDetails] = useState>(new Map()); + const [isFilterOpen, setIsFilterOpen] = useState(false); + const [filterRefrigeratorFriendly, setFilterRefrigeratorFriendly] = useState(null); + + useEffect(() => { + const fetchAssignments = async () => { + try { + + const data = await ApiClient.getAllAssignments() as Assignments[]; + setAssignments(data); + setFilteredAssignments(data); + + const detailsMap = new Map(); + await Promise.all( + data + .filter(assignment => assignment.pantry) + .map(async (assignment) => { + try { + const pantry = await ApiClient.getPantry(assignment.pantry!.pantryId); + detailsMap.set(assignment.pantry!.pantryId, pantry); + } catch (error) { + console.error(`Error fetching pantry ${assignment.pantry!.pantryId}:`, error); + } + }) + ); + setPantryDetails(detailsMap); + } catch (error) { + console.error('Error fetching assignments:', error); + alert('Error fetching assigned pantries: ' + error); + } + }; + + fetchAssignments(); + }, []); + + useEffect(() => { + + let filtered = [...assignments]; + + if (filterRefrigeratorFriendly !== null) { + filtered = filtered.filter(assignment => { + if (!assignment.pantry) return false; + const pantry = pantryDetails.get(assignment.pantry.pantryId); + if (!pantry) return true; + const isRefrigeratorFriendlyValue = + pantry.refrigeratedDonation === RefrigeratedDonation.YES || + pantry.refrigeratedDonation === RefrigeratedDonation.SOMETIMES; + return isRefrigeratorFriendlyValue === filterRefrigeratorFriendly; + }); + } + + setFilteredAssignments(filtered); + }, [filterRefrigeratorFriendly, assignments, pantryDetails]); + + + const handleViewOrders = (pantryId: number) => { + // TODO: Redirect to Order Management page when it's created + console.log('View orders for pantry:', pantryId); + }; + + const isRefrigeratorFriendly = (pantryId: number): boolean => { + const pantry = pantryDetails.get(pantryId); + if (!pantry) return false; + return pantry.refrigeratedDonation === RefrigeratedDonation.YES || + pantry.refrigeratedDonation === RefrigeratedDonation.SOMETIMES; + }; + + const getRefrigeratorFriendlyText = (pantryId: number): string => { + const pantry = pantryDetails.get(pantryId); + if (!pantry) return 'Loading...'; + if (pantry.refrigeratedDonation === RefrigeratedDonation.YES || + pantry.refrigeratedDonation === RefrigeratedDonation.SOMETIMES) { + return 'Refrigerator-Friendly'; + } + return 'Not Refrigerator-Friendly'; + }; + + const tableHeaderStyles = { + borderBottom: '1px solid', + borderColor: 'neutral.100', + color: 'neutral.800', + fontFamily: 'inter', + fontWeight: '600', + fontSize: 'sm', + }; + + return ( + + + Assigned Pantries + + + {/* Filter Button */} + + + + + {isFilterOpen && ( + <> + setIsFilterOpen(false)} + zIndex={10} + /> + + + + + setFilterRefrigeratorFriendly(e.checked ? true : null) + } + color="black" + size="sm" + > + + + + setFilterRefrigeratorFriendly(filterRefrigeratorFriendly === true ? null : true)}> + Refrigerator-Friendly Only + + + + + + setFilterRefrigeratorFriendly(e.checked ? false : null) + } + color="black" + size="sm" + > + + + + setFilterRefrigeratorFriendly(filterRefrigeratorFriendly === false ? null : false)}> + Not Refrigerator-Friendly Only + + + + + + )} + + + + {/* Pantries Table */} + + + + + Pantry + + + Refrigerator-Friendly + + + Action + + + + + {filteredAssignments.map((assignment) => { + + if (!assignment.pantry) return null; + + return ( + + + + + + + {assignment.pantry ? getRefrigeratorFriendlyText(assignment.pantry.pantryId) : 'N/A'} + + + + + + + ); + })} + + + + ); +}; + +export default AssignedPantries; \ No newline at end of file diff --git a/apps/frontend/src/types/volunteerAssignments.ts b/apps/frontend/src/types/volunteerAssignments.ts new file mode 100644 index 00000000..73d43f4f --- /dev/null +++ b/apps/frontend/src/types/volunteerAssignments.ts @@ -0,0 +1,18 @@ +export interface LimitedPantryInfo { + pantryId: number; + pantryName: string; +} + +export interface Assignments { + assignmentId: number; + volunteer: { + id: number; + firstName: string; + lastName: string; + email: string; + phone: string; + role: string; + }; + pantry: LimitedPantryInfo | null; +} +