diff --git a/apps/frontend/src/app.tsx b/apps/frontend/src/app.tsx
index c844de29..a49dde7b 100644
--- a/apps/frontend/src/app.tsx
+++ b/apps/frontend/src/app.tsx
@@ -13,6 +13,7 @@ import PantryApplication from '@containers/pantryApplication';
import ApplicationSubmitted from '@containers/applicationSubmitted';
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 AdminDonation from '@containers/adminDonation';
@@ -174,6 +175,14 @@ const router = createBrowserRouter([
),
},
+ {
+ path: '/application-details/:applicationId',
+ element: (
+
+
+
+ ),
+ },
{
path: '/admin-donation',
element: (
diff --git a/apps/frontend/src/components/forms/pantryApplicationModal.tsx b/apps/frontend/src/components/forms/pantryApplicationModal.tsx
index 4c973fd6..ede50a2e 100644
--- a/apps/frontend/src/components/forms/pantryApplicationModal.tsx
+++ b/apps/frontend/src/components/forms/pantryApplicationModal.tsx
@@ -66,32 +66,32 @@ const PantryApplicationModal: React.FC = ({
Shipping Address Line 1
- {pantry.shippingAddressLine1}
+ {pantry.shipmentAddressLine1}
Shipping Address Line 2
- {pantry.shippingAddressLine2 ?? ''}
+ {pantry.shipmentAddressLine2 ?? ''}
Shipping Address City
- {pantry.shippingAddressCity}
+ {pantry.shipmentAddressCity}
Shipping Address State
- {pantry.shippingAddressState}
+ {pantry.shipmentAddressState}
Shipping Address Zip
- {pantry.shippingAddressZip}
+ {pantry.shipmentAddressZip}
Shipping Address Country
- {pantry.shippingAddressCountry ?? ''}
+ {pantry.shipmentAddressCountry ?? ''}
Allergen Clients
diff --git a/apps/frontend/src/containers/applicationDetails.tsx b/apps/frontend/src/containers/applicationDetails.tsx
new file mode 100644
index 00000000..ebc61c6d
--- /dev/null
+++ b/apps/frontend/src/containers/applicationDetails.tsx
@@ -0,0 +1,373 @@
+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,
+} from '@chakra-ui/react';
+import ApiClient from '@api/apiClient';
+import { Pantry } from 'types/types';
+import { formatDate, formatPhone } from '@utils/utils';
+import { TagGroup } from '@components/forms/tagGroup';
+
+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 fieldContentStyles = {
+ textStyle: 'p2',
+ color: 'gray.light',
+ lineHeight: '1.2',
+ };
+
+ const headerStyles = {
+ textStyle: 'p2',
+ color: 'neutral.800',
+ };
+
+ const sectionHeaderStyles = {
+ ...headerStyles,
+ fontWeight: 600,
+ };
+
+ const fieldHeaderStyles = {
+ ...headerStyles,
+ fontWeight: 500,
+ mb: 1,
+ };
+
+ 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);
+ } 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 (
+
+
+
+ Application Details
+
+
+
+
+
+
+ Application #{application.pantryId}
+
+
+ {application.pantryName}
+
+
+ Applied {formatDate(application.dateApplied)}
+
+
+
+
+
+
+ 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'}
+
+
+
+
+ Shipment 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
+
+
+
+ Name
+ {application.pantryName}
+
+
+ Approximate # of Clients
+
+ {application.allergenClients}
+
+
+
+
+
+
+
+ Food Allergies and Restrictions
+
+ {application.restrictions &&
+ application.restrictions.length > 0 ? (
+
+ ) : (
+ 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'}
+
+
+
+
+
+
+
+ Confidence in Identifying the Top 9 Allergens
+
+
+ {application.identifyAllergensConfidence ?? 'Not specified'}
+
+
+
+
+ Serves Allergen-Avoidant Children
+
+
+ {application.serveAllergicChildren ?? 'Not specified'}
+
+
+
+
+
+ Open to SSF Activities
+ {application.activities && application.activities.length > 0 ? (
+
+ ) : (
+ None
+ )}
+
+
+
+ Comments/Concerns
+
+ {application.activitiesComments || '-'}
+
+
+
+
+
+ Allergen-free Items in Stock
+
+ {application.itemsInStock}
+
+
+
+ Client Requests
+ {application.needMoreOptions}
+
+
+
+ Subscribed to Newsletter
+
+ {application.newsletterSubscription ? 'Yes' : 'No'}
+
+
+
+
+
+
+
+
+
+
+
+ );
+};
+
+export default ApplicationDetails;
diff --git a/apps/frontend/src/containers/approvePantries.tsx b/apps/frontend/src/containers/approvePantries.tsx
index d2bd59c8..b47fac2d 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,9 @@ const ApprovePantries: React.FC = () => {
bg="transparent"
color="cyan"
fontWeight="600"
- onClick={() => setOpenPantry(pantry)}
+ onClick={() =>
+ navigate(`/application-details/${pantry.pantryId}`)
+ }
>
{pantry.pantryName}
@@ -117,13 +119,6 @@ const ApprovePantries: React.FC = () => {
))}
- {openPantry && (
- setOpenPantry(null)}
- />
- )}
diff --git a/apps/frontend/src/theme.ts b/apps/frontend/src/theme.ts
index abf16ad8..0b320004 100644
--- a/apps/frontend/src/theme.ts
+++ b/apps/frontend/src/theme.ts
@@ -53,6 +53,13 @@ const textStyles = defineTextStyles({
fontWeight: '400',
},
},
+ p3: {
+ value: {
+ fontFamily: 'inter',
+ fontSize: '12px',
+ fontWeight: '400',
+ },
+ },
});
const customConfig = defineConfig({
diff --git a/apps/frontend/src/types/types.ts b/apps/frontend/src/types/types.ts
index ce85f3b4..eed45507 100644
--- a/apps/frontend/src/types/types.ts
+++ b/apps/frontend/src/types/types.ts
@@ -19,12 +19,12 @@ import {
export interface Pantry {
pantryId: number;
pantryName: string;
- shippingAddressLine1: string;
- shippingAddressLine2?: string;
- shippingAddressCity: string;
- shippingAddressState: string;
- shippingAddressZip: string;
- shippingAddressCountry?: string;
+ shipmentAddressLine1: string;
+ shipmentAddressLine2?: string;
+ shipmentAddressCity: string;
+ shipmentAddressState: string;
+ shipmentAddressZip: string;
+ shipmentAddressCountry?: string;
mailingAddressLine1: string;
mailingAddressLine2?: string;
mailingAddressCity: string;
@@ -71,12 +71,12 @@ export interface PantryApplicationDto {
secondaryContactEmail?: string;
secondaryContactPhone?: string;
pantryName: string;
- shippingAddressLine1: string;
- shippingAddressLine2?: string;
- shippingAddressCity: string;
- shippingAddressState: string;
- shippingAddressZip: string;
- shippingAddressCountry?: string;
+ shipmentAddressLine1: string;
+ shipmentAddressLine2?: string;
+ shipmentAddressCity: string;
+ shipmentAddressState: string;
+ shipmentAddressZip: string;
+ shipmentAddressCountry?: string;
mailingAddressLine1: string;
mailingAddressLine2?: string;
mailingAddressCity: string;
@@ -218,7 +218,7 @@ export interface Order {
deliveredAt?: Date;
allocations: Allocation[];
trackingLink?: string;
- shippingCost?: number;
+ shipmentCost?: number;
}
export interface OrderItemDetails {
diff --git a/apps/frontend/src/utils/utils.ts b/apps/frontend/src/utils/utils.ts
index 2b7faa21..4e704f80 100644
--- a/apps/frontend/src/utils/utils.ts
+++ b/apps/frontend/src/utils/utils.ts
@@ -1,5 +1,14 @@
import { DayOfWeek, RecurrenceEnum, RepeatOnState } from '../types/types';
+export 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;
+};
+
export const formatDate = (dateString: string) => {
const date = new Date(dateString);
return date.toLocaleDateString('en-US');