diff --git a/apps/frontend/src/app.tsx b/apps/frontend/src/app.tsx
index e31dc284..89872b41 100644
--- a/apps/frontend/src/app.tsx
+++ b/apps/frontend/src/app.tsx
@@ -17,6 +17,7 @@ import PantryApplication from '@containers/pantryApplication';
import PantryApplicationSubmitted from '@containers/pantryApplicationSubmitted';
import { submitPantryApplicationForm } from '@components/forms/pantryApplicationForm';
import ApprovePantries from '@containers/approvePantries';
+import ApplicationDetails from '@containers/applicationDetails';
import VolunteerManagement from '@containers/volunteerManagement';
import FoodManufacturerOrderDashboard from '@containers/foodManufacturerOrderDashboard';
import DonationManagement from '@containers/donationManagement';
@@ -161,6 +162,14 @@ const router = createBrowserRouter([
),
},
+ {
+ path: '/application-details/:applicationId',
+ element: (
+
+
+
+ ),
+ },
{
path: '/admin-donation',
element: (
diff --git a/apps/frontend/src/containers/applicationDetails.tsx b/apps/frontend/src/containers/applicationDetails.tsx
new file mode 100644
index 00000000..c7541ab2
--- /dev/null
+++ b/apps/frontend/src/containers/applicationDetails.tsx
@@ -0,0 +1,388 @@
+import React, { useCallback, useEffect, useState } from 'react';
+import { useParams, useNavigate } from 'react-router-dom';
+import {
+ Center,
+ Box,
+ Grid,
+ GridItem,
+ Text,
+ Button,
+ Heading,
+ VStack,
+ HStack,
+ Spinner,
+ Badge,
+ Flex,
+} from '@chakra-ui/react';
+import ApiClient from '@api/apiClient';
+import { Pantry } from 'types/types';
+
+type PantryWithShipment = Pantry & {
+ shipmentAddressLine1?: string | null;
+ shipmentAddressLine2?: string | null;
+ shipmentAddressCity?: string | null;
+ shipmentAddressState?: string | null;
+ shipmentAddressZip?: string | null;
+ shipmentAddressCountry?: string | null;
+};
+
+const ApplicationDetails: React.FC = () => {
+ const { applicationId } = useParams<{ applicationId: string }>();
+ const navigate = useNavigate();
+ const [application, setApplication] = useState(
+ null,
+ );
+ const [loading, setLoading] = useState(true);
+ const [error, setError] = useState(null);
+
+ const formatPhone = (phone?: string | null) => {
+ if (!phone) return null;
+ const digits = phone.replace(/\D/g, '');
+ if (digits.length === 10) {
+ return `${digits.slice(0, 3)}-${digits.slice(3, 6)}-${digits.slice(6)}`;
+ }
+ return phone;
+ };
+
+ const fetchApplicationDetails = useCallback(async () => {
+ try {
+ setLoading(true);
+ setError(null);
+ if (!applicationId) {
+ setError('Application ID not provided');
+ return;
+ }
+ const data = await ApiClient.getPantry(parseInt(applicationId, 10));
+ setApplication(data as PantryWithShipment);
+ } catch (err) {
+ setError(
+ 'Error loading application details: ' +
+ (err instanceof Error ? err.message : String(err)),
+ );
+ } finally {
+ setLoading(false);
+ }
+ }, [applicationId]);
+
+ useEffect(() => {
+ fetchApplicationDetails();
+ }, [fetchApplicationDetails]);
+
+ const handleApprove = async () => {
+ if (application) {
+ try {
+ await ApiClient.updatePantry(application.pantryId, 'approve');
+ navigate('/approve-pantries');
+ } catch (err) {
+ alert('Error approving application: ' + err);
+ }
+ }
+ };
+
+ const handleDeny = async () => {
+ if (application) {
+ try {
+ await ApiClient.updatePantry(application.pantryId, 'deny');
+ navigate('/approve-pantries');
+ } catch (err) {
+ alert('Error denying application: ' + err);
+ }
+ }
+ };
+
+ if (loading) {
+ return (
+
+
+ Loading application details...
+
+ );
+ }
+
+ if (error) {
+ return (
+
+
+ {error}
+
+
+
+ );
+ }
+
+ if (!application) {
+ return (
+
+
+ Application not found
+
+
+
+ );
+ }
+
+ const pantryUser = application.pantryUser;
+
+ return (
+
+
+ {/* Page Title */}
+
+ Application Details
+
+
+ {/* Main Content Card */}
+
+
+ {/* Application Header */}
+
+
+ Application #{application.pantryId}
+
+
+ {application.pantryName}
+
+
+ Applied {new Date(application.dateApplied).toLocaleDateString('en-US', { month: '2-digit', day: '2-digit', year: 'numeric' })}
+
+
+
+ {/* Point of Contact and Shipping Address */}
+
+
+
+ Point of Contact Information
+
+
+
+ {pantryUser
+ ? `${pantryUser.firstName} ${pantryUser.lastName}`
+ : application.secondaryContactFirstName &&
+ application.secondaryContactLastName
+ ? `${application.secondaryContactFirstName} ${application.secondaryContactLastName}`
+ : 'N/A'}
+
+
+ {formatPhone(
+ pantryUser?.phone ?? application.secondaryContactPhone,
+ ) ?? 'N/A'}
+
+
+ {pantryUser?.email ??
+ application.secondaryContactEmail ??
+ 'N/A'}
+
+
+
+
+
+ Shipping Address
+
+
+
+ {application.shipmentAddressLine1 ?? 'N/A'},
+
+
+ {application.shipmentAddressCity ?? 'N/A'},{' '}
+ {application.shipmentAddressState ?? 'N/A'}{' '}
+ {application.shipmentAddressZip ?? ''}
+
+
+ {application.shipmentAddressCountry === 'US'
+ ? 'United States of America'
+ : application.shipmentAddressCountry ?? 'N/A'}
+
+
+
+
+
+ {/* Pantry Details */}
+
+
+ Pantry Details
+
+
+
+
+ Name
+
+ {application.pantryName}
+
+
+
+ Approximate # of Clients
+
+ {application.allergenClients}
+
+
+
+
+ {/* Food Allergies and Restrictions */}
+
+
+ Food Allergies and Restrictions
+
+
+ {application.restrictions && application.restrictions.length > 0 ? (
+ application.restrictions.map((restriction, index) => (
+
+ {restriction}
+
+ ))
+ ) : (
+ None
+ )}
+
+
+
+
+
+ Accepts Refrigerated Donations?
+
+ {application.refrigeratedDonation}
+
+
+
+ Willing to Reserve Donations for Allergen-Avoidant Individuals
+
+ {application.reserveFoodForAllergic}
+
+
+
+ {application.reservationExplanation && (
+
+
+ Justification
+
+ {application.reservationExplanation}
+
+ )}
+
+
+
+
+ Dedicated section for allergy-friendly items?
+
+ {application.dedicatedAllergyFriendly ? 'Yes, we have a dedicated shelf or box' : 'No'}
+
+
+
+ How Often Allergen-Avoidant Clients Visit
+
+ {application.clientVisitFrequency ?? 'Not specified'}
+
+
+
+
+
+
+ Confident in Identifying the Top 9 Allergens
+
+ {application.identifyAllergensConfidence ?? 'Not specified'}
+
+
+
+ Serves Allergen-Avoidant Children
+
+ {application.serveAllergicChildren ?? 'Not specified'}
+
+
+
+
+ {/* Open to SSF Activities */}
+
+
+ Open to SSF Activities
+
+
+ {application.activities && application.activities.length > 0 ? (
+ application.activities.map((activity, index) => (
+
+ {activity}
+
+ ))
+ ) : (
+ None
+ )}
+
+
+
+ {/* Comments/Concerns */}
+
+
+ Comments/Concerns
+
+ {application.activitiesComments || '-'}
+
+
+ {/* Allergen-free Items in Stock */}
+
+
+ Allergen-free Items in Stock
+
+ {application.itemsInStock}
+
+
+ {/* Client Requests */}
+
+
+ Client Requests
+
+ {application.needMoreOptions}
+
+
+ {/* Subscribed to Newsletter */}
+
+
+ Subscribed to Newsletter
+
+ {application.newsletterSubscription ? 'Yes' : 'No'}
+
+
+ {/* Action Buttons */}
+
+
+
+
+
+
+
+
+ );
+};
+
+export default ApplicationDetails;
diff --git a/apps/frontend/src/containers/approvePantries.tsx b/apps/frontend/src/containers/approvePantries.tsx
index bbe3882a..61f94b51 100644
--- a/apps/frontend/src/containers/approvePantries.tsx
+++ b/apps/frontend/src/containers/approvePantries.tsx
@@ -1,4 +1,5 @@
import React, { useEffect, useState } from 'react';
+import { useNavigate } from 'react-router-dom';
import {
Center,
Table,
@@ -7,16 +8,15 @@ import {
NativeSelect,
NativeSelectIndicator,
} from '@chakra-ui/react';
-import PantryApplicationModal from '@components/forms/pantryApplicationModal';
import ApiClient from '@api/apiClient';
import { Pantry } from 'types/types';
import { formatDate } from '@utils/utils';
const ApprovePantries: React.FC = () => {
+ const navigate = useNavigate();
const [pendingPantries, setPendingPantries] = useState([]);
const [sortedPantries, setSortedPantries] = useState([]);
const [sort, setSort] = useState('');
- const [openPantry, setOpenPantry] = useState(null);
const fetchPantries = async () => {
try {
@@ -91,7 +91,7 @@ const ApprovePantries: React.FC = () => {
bg="transparent"
color="cyan"
fontWeight="600"
- onClick={() => setOpenPantry(pantry)}
+ onClick={() => navigate(`/application-details/${pantry.pantryId}`)}
>
{pantry.pantryName}
@@ -117,13 +117,6 @@ const ApprovePantries: React.FC = () => {
))}
- {openPantry && (
- setOpenPantry(null)}
- />
- )}