diff --git a/apps/backend/src/donationItems/donationItems.controller.spec.ts b/apps/backend/src/donationItems/donationItems.controller.spec.ts new file mode 100644 index 00000000..ed10f8a0 --- /dev/null +++ b/apps/backend/src/donationItems/donationItems.controller.spec.ts @@ -0,0 +1,115 @@ +import { Test, TestingModule } from '@nestjs/testing'; +import { DonationItemsController } from './donationItems.controller'; +import { DonationItemsService } from './donationItems.service'; +import { DonationItem } from './donationItems.entity'; +import { mock } from 'jest-mock-extended'; +import { FoodType } from './types'; +import { CreateMultipleDonationItemsDto } from './dtos/create-donation-items.dto'; + +const mockDonationItemsService = mock(); + +describe('DonationItemsController', () => { + let controller: DonationItemsController; + + const mockDonationItemsCreateData: Partial[] = [ + { + itemId: 1, + donationId: 1, + itemName: 'Canned Beans', + quantity: 100, + reservedQuantity: 0, + ozPerItem: 15, + estimatedValue: 200, + foodType: FoodType.DAIRY_FREE_ALTERNATIVES, + }, + { + itemId: 2, + donationId: 1, + itemName: 'Rice', + quantity: 50, + reservedQuantity: 0, + ozPerItem: 20, + estimatedValue: 150, + foodType: FoodType.GLUTEN_FREE_BAKING_PANCAKE_MIXES, + }, + ]; + + beforeEach(async () => { + const module: TestingModule = await Test.createTestingModule({ + controllers: [DonationItemsController], + providers: [ + { provide: DonationItemsService, useValue: mockDonationItemsService }, + ], + }).compile(); + + controller = module.get(DonationItemsController); + }); + + it('should be defined', () => { + expect(controller).toBeDefined(); + }); + + describe('create', () => { + it('should call donationItemsService.create and return a donationItem', async () => { + const donationItemData = mockDonationItemsCreateData[0]; + mockDonationItemsService.create.mockResolvedValue( + donationItemData as DonationItem, + ); + const result = await controller.createDonationItem( + donationItemData as DonationItem, + ); + expect(result).toEqual(donationItemData as DonationItem); + expect(mockDonationItemsService.create).toHaveBeenCalledWith( + donationItemData.donationId, + donationItemData.itemName, + donationItemData.quantity, + donationItemData.reservedQuantity, + donationItemData.ozPerItem, + donationItemData.estimatedValue, + donationItemData.foodType, + ); + }); + }); + + describe('createMultipleDonationItems', () => { + it('should call donationItemsService.createMultipleDonationItems with donationId and items, and return the created donation items', async () => { + const mockBody: CreateMultipleDonationItemsDto = { + donationId: 1, + items: [ + { + itemName: 'Rice Noodles', + quantity: 100, + reservedQuantity: 0, + ozPerItem: 5, + estimatedValue: 100, + foodType: FoodType.DAIRY_FREE_ALTERNATIVES, + }, + { + itemName: 'Beans', + quantity: 50, + reservedQuantity: 0, + ozPerItem: 10, + estimatedValue: 80, + foodType: FoodType.GLUTEN_FREE_BAKING_PANCAKE_MIXES, + }, + ], + }; + + const mockCreatedItems: Partial[] = [ + { itemId: 1, donationId: 1, ...mockBody.items[0] }, + { itemId: 2, donationId: 1, ...mockBody.items[1] }, + ]; + + mockDonationItemsService.createMultipleDonationItems.mockResolvedValue( + mockCreatedItems as DonationItem[], + ); + + const result = await controller.createMultipleDonationItems(mockBody); + + expect( + mockDonationItemsService.createMultipleDonationItems, + ).toHaveBeenCalledWith(mockBody.donationId, mockBody.items); + expect(result).toEqual(mockCreatedItems); + }); + }); +}); diff --git a/apps/backend/src/donationItems/donationItems.controller.ts b/apps/backend/src/donationItems/donationItems.controller.ts index 191b53fb..8279c3c8 100644 --- a/apps/backend/src/donationItems/donationItems.controller.ts +++ b/apps/backend/src/donationItems/donationItems.controller.ts @@ -12,6 +12,7 @@ import { ApiBody } from '@nestjs/swagger'; import { DonationItemsService } from './donationItems.service'; import { DonationItem } from './donationItems.entity'; import { FoodType } from './types'; +import { CreateMultipleDonationItemsDto } from './dtos/create-donation-items.dto'; @Controller('donation-items') //@UseInterceptors() @@ -74,6 +75,46 @@ export class DonationItemsController { ); } + @Post('/create-multiple') + @ApiBody({ + description: 'Bulk create donation items for a single donation', + schema: { + type: 'object', + properties: { + donationId: { + type: 'integer', + example: 1, + }, + items: { + type: 'array', + items: { + type: 'object', + properties: { + itemName: { type: 'string', example: 'Rice Noodles' }, + quantity: { type: 'integer', example: 100 }, + reservedQuantity: { type: 'integer', example: 0 }, + ozPerItem: { type: 'integer', example: 5 }, + estimatedValue: { type: 'integer', example: 100 }, + foodType: { + type: 'string', + enum: Object.values(FoodType), + example: FoodType.DAIRY_FREE_ALTERNATIVES, + }, + }, + }, + }, + }, + }, + }) + async createMultipleDonationItems( + @Body() body: CreateMultipleDonationItemsDto, + ): Promise { + return this.donationItemsService.createMultipleDonationItems( + body.donationId, + body.items, + ); + } + @Patch('/update-quantity/:itemId') async updateDonationItemQuantity( @Param('itemId', ParseIntPipe) itemId: number, diff --git a/apps/backend/src/donationItems/donationItems.entity.ts b/apps/backend/src/donationItems/donationItems.entity.ts index afd2c0c2..bd9a5098 100644 --- a/apps/backend/src/donationItems/donationItems.entity.ts +++ b/apps/backend/src/donationItems/donationItems.entity.ts @@ -16,7 +16,7 @@ export class DonationItem { itemId: number; @Column({ name: 'donation_id', type: 'int' }) - donation_id: number; + donationId: number; @ManyToOne(() => Donation, { nullable: false }) @JoinColumn({ name: 'donation_id', referencedColumnName: 'donationId' }) diff --git a/apps/backend/src/donationItems/donationItems.service.ts b/apps/backend/src/donationItems/donationItems.service.ts index 116742c6..740a2650 100644 --- a/apps/backend/src/donationItems/donationItems.service.ts +++ b/apps/backend/src/donationItems/donationItems.service.ts @@ -44,6 +44,37 @@ export class DonationItemsService { return this.repo.save(donationItem); } + async createMultipleDonationItems( + donationId: number, + items: { + itemName: string; + quantity: number; + reservedQuantity: number; + ozPerItem: number; + estimatedValue: number; + foodType: FoodType; + }[], + ): Promise { + validateId(donationId, 'Donation'); + + const donation = await this.donationRepo.findOneBy({ donationId }); + if (!donation) throw new NotFoundException('Donation not found'); + + const donationItems = items.map((item) => + this.repo.create({ + donation, + itemName: item.itemName, + quantity: item.quantity, + reservedQuantity: item.reservedQuantity, + ozPerItem: item.ozPerItem, + estimatedValue: item.estimatedValue, + foodType: item.foodType, + }), + ); + + return this.repo.save(donationItems); + } + async updateDonationItemQuantity(itemId: number): Promise { validateId(itemId, 'Donation Item'); diff --git a/apps/backend/src/donationItems/dtos/create-donation-items.dto.ts b/apps/backend/src/donationItems/dtos/create-donation-items.dto.ts new file mode 100644 index 00000000..11a63d77 --- /dev/null +++ b/apps/backend/src/donationItems/dtos/create-donation-items.dto.ts @@ -0,0 +1,48 @@ +import { + IsNumber, + IsString, + IsArray, + ValidateNested, + Min, + IsEnum, + IsNotEmpty, + Length, +} from 'class-validator'; +import { Type } from 'class-transformer'; +import { FoodType } from '../types'; + +export class CreateDonationItemDto { + @IsString() + @IsNotEmpty() + @Length(1, 255) + itemName: string; + + @IsNumber() + @Min(1) + quantity: number; + + @IsNumber() + @Min(0) + reservedQuantity: number; + + @IsNumber() + @Min(1) + ozPerItem: number; + + @IsNumber() + @Min(1) + estimatedValue: number; + + @IsEnum(FoodType) + foodType: FoodType; +} + +export class CreateMultipleDonationItemsDto { + @IsNumber() + donationId: number; + + @IsArray() + @ValidateNested({ each: true }) + @Type(() => CreateDonationItemDto) + items: CreateDonationItemDto[]; +} diff --git a/apps/backend/src/migrations/1764816885341-RemoveUnusedStatuses.ts b/apps/backend/src/migrations/1764816885341-RemoveUnusedStatuses.ts index 6419e233..4c35fd0f 100644 --- a/apps/backend/src/migrations/1764816885341-RemoveUnusedStatuses.ts +++ b/apps/backend/src/migrations/1764816885341-RemoveUnusedStatuses.ts @@ -1,25 +1,24 @@ -import { MigrationInterface, QueryRunner } from "typeorm"; +import { MigrationInterface, QueryRunner } from 'typeorm'; export class RemoveUnusedStatuses1764816885341 implements MigrationInterface { + public async up(queryRunner: QueryRunner): Promise { + await queryRunner.query( + `ALTER TABLE allocations DROP COLUMN IF EXISTS status;`, + ); + await queryRunner.query( + `ALTER TABLE donation_items DROP COLUMN IF EXISTS status;`, + ); + } - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query( - `ALTER TABLE allocations DROP COLUMN IF EXISTS status;` - ); - await queryRunner.query( - `ALTER TABLE donation_items DROP COLUMN IF EXISTS status;` - ); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query(` + public async down(queryRunner: QueryRunner): Promise { + await queryRunner.query(` ALTER TABLE allocations ADD COLUMN status VARCHAR(25) NOT NULL DEFAULT 'pending'; `); - await queryRunner.query(` + await queryRunner.query(` ALTER TABLE donation_items ADD COLUMN status VARCHAR(25) NOT NULL DEFAULT 'available'; `); - } + } } diff --git a/apps/backend/src/pantries/dtos/pantry-application.dto.ts b/apps/backend/src/pantries/dtos/pantry-application.dto.ts index 42510915..c7473b0f 100644 --- a/apps/backend/src/pantries/dtos/pantry-application.dto.ts +++ b/apps/backend/src/pantries/dtos/pantry-application.dto.ts @@ -52,7 +52,7 @@ export class PantryApplicationDto { @IsNotEmpty() @MaxLength(255) emailContactOther?: string; - + @IsOptional() @IsString() @IsNotEmpty() diff --git a/apps/frontend/src/api/apiClient.ts b/apps/frontend/src/api/apiClient.ts index a548bfa5..770dfdec 100644 --- a/apps/frontend/src/api/apiClient.ts +++ b/apps/frontend/src/api/apiClient.ts @@ -10,6 +10,7 @@ import { CreateFoodRequestBody, Pantry, PantryApplicationDto, + CreateMultipleDonationItemsBody, } from 'types/types'; const defaultBaseUrl = @@ -53,6 +54,14 @@ export class ApiClient { return this.post('/api/requests/create', body) as Promise; } + public async postMultipleDonationItems( + body: CreateMultipleDonationItemsBody, + ): Promise { + return this.post('/api/donation-items/create-multiple', body) as Promise< + DonationItem[] + >; + } + private async patch(path: string, body: unknown): Promise { return this.axiosInstance .patch(path, body) diff --git a/apps/frontend/src/components/forms/donationDetailsModal.tsx b/apps/frontend/src/components/forms/donationDetailsModal.tsx index 093b06df..37fd1389 100644 --- a/apps/frontend/src/components/forms/donationDetailsModal.tsx +++ b/apps/frontend/src/components/forms/donationDetailsModal.tsx @@ -8,12 +8,11 @@ import { CloseButton, } from '@chakra-ui/react'; import ApiClient from '@api/apiClient'; -import { Donation } from 'types/types'; -import { DonationItem } from 'types/types'; +import { Donation, DonationItem } from 'types/types'; import { formatDate } from '@utils/utils'; interface DonationDetailsModalProps { - donation: Donation; + donation?: Donation; isOpen: boolean; onClose: () => void; } @@ -23,30 +22,34 @@ const DonationDetailsModal: React.FC = ({ isOpen, onClose, }) => { + const [loadedDonation, setLoadedDonation] = useState(); const [items, setItems] = useState([]); + const donationId = donation?.donationId; // adjust if your ID field is different + useEffect(() => { - if (isOpen) { - const fetchData = async () => { - try { - const itemsData = await ApiClient.getDonationItemsByDonationId( - donation.donationId, - ); - - setItems(itemsData); - } catch (error) { - alert('Error fetching donation details:' + error); - } - }; - - fetchData(); - } - }, [isOpen, donation]); + if (!isOpen || !donationId) return; + + const fetchData = async () => { + try { + const donationData = await ApiClient.getOrderDonation(donationId); + const itemsData = await ApiClient.getDonationItemsByDonationId( + donationId, + ); + + setLoadedDonation(donationData); + setItems(itemsData); + } catch (err) { + alert('Error fetching donation details: ' + err); + } + }; + + fetchData(); + }, [isOpen, donationId]); + // Group items by food type const groupedItems = items.reduce((acc, item) => { - if (!acc[item.foodType]) { - acc[item.foodType] = []; - } + if (!acc[item.foodType]) acc[item.foodType] = []; acc[item.foodType].push(item); return acc; }, {} as Record); @@ -61,7 +64,8 @@ const DonationDetailsModal: React.FC = ({ scrollBehavior="inside" > - + + @@ -70,21 +74,17 @@ const DonationDetailsModal: React.FC = ({ - - Donation #{donation.donationId} Details + + Donation #{donationId} Details - {donation && ( + + {loadedDonation && ( <> - - {donation.foodManufacturer?.foodManufacturerName} + + {loadedDonation.foodManufacturer?.foodManufacturerName} - - {formatDate(donation.dateDonated)} + + {formatDate(loadedDonation.dateDonated)} )} @@ -92,18 +92,14 @@ const DonationDetailsModal: React.FC = ({ - {donation && ( + {loadedDonation && ( {Object.entries(groupedItems).map(([foodType, typeItems]) => ( - + {foodType} + {typeItems.map((item, index) => ( = ({ overflow="hidden" > - - {item.itemName} - + {item.itemName} + = ({ justifyContent="center" bg="white" > - - {item.quantity} - + {item.quantity} ))} diff --git a/apps/frontend/src/components/forms/newDonationFormModal.tsx b/apps/frontend/src/components/forms/newDonationFormModal.tsx index d6697d08..e89145bc 100644 --- a/apps/frontend/src/components/forms/newDonationFormModal.tsx +++ b/apps/frontend/src/components/forms/newDonationFormModal.tsx @@ -10,6 +10,7 @@ import { Dialog, NativeSelect, NativeSelectIndicator, + Portal, } from '@chakra-ui/react'; import { useState } from 'react'; import ApiClient from '@api/apiClient'; @@ -57,18 +58,16 @@ const NewDonationFormModal: React.FC = ({ updatedRows.forEach((row) => { if (row.numItems && row.ozPerItem && row.valuePerItem) { - totalItems += parseInt(row.numItems); - totalOz += parseFloat(row.ozPerItem) * parseInt(row.numItems); - totalValue += parseFloat(row.valuePerItem) * parseInt(row.numItems); + const qty = parseInt(row.numItems); + totalItems += qty; + totalOz += parseFloat(row.ozPerItem) * qty; + totalValue += parseFloat(row.valuePerItem) * qty; } }); - totalOz = parseFloat(totalOz.toFixed(2)); - totalValue = parseFloat(totalValue.toFixed(2)); - setTotalItems(totalItems); - setTotalOz(totalOz); - setTotalValue(totalValue); + setTotalOz(parseFloat(totalOz.toFixed(2))); + setTotalValue(parseFloat(totalValue.toFixed(2))); }; const addRow = () => { @@ -86,36 +85,32 @@ const NewDonationFormModal: React.FC = ({ }; const deleteRow = () => { - if (rows.length === 1) { - return; - } const newRows = rows.slice(0, -1); setRows(newRows); calculateTotals(newRows); }; const handleSubmit = async () => { - const hasEmptyFields = rows.some( + const hasEmpty = rows.some( (row) => - row.foodItem === '' || - row.foodType === '' || - row.numItems === '' || - row.ozPerItem === '' || - row.valuePerItem === '', + !row.foodItem || + !row.foodType || + !row.numItems || + !row.ozPerItem || + !row.valuePerItem, ); - if (hasEmptyFields) { + if (hasEmpty) { alert('Please fill in all fields before submitting.'); return; } onClose(); - const foodManufacturerId = 1; const donation_body = { - foodManufacturerId: foodManufacturerId, - totalItems: totalItems, - totalOz: totalOz, + foodManufacturerId: 1, + totalItems, + totalOz, totalEstimatedValue: totalValue, }; @@ -123,30 +118,20 @@ const NewDonationFormModal: React.FC = ({ const donationResponse = await ApiClient.postDonation(donation_body); const donationId = donationResponse?.donationId; - // Automatically update the page after creating new donation onDonationSuccess(); if (donationId) { - rows.forEach(async (row) => { - const donationItem_body = { - donationId: donationId, - itemName: row.foodItem, - quantity: parseInt(row.numItems), - ozPerItem: parseFloat(row.ozPerItem), - estimatedValue: parseFloat(row.valuePerItem), - foodType: row.foodType, - }; + const items = rows.map((row) => ({ + itemName: row.foodItem, + quantity: parseInt(row.numItems), + reservedQuantity: 0, + ozPerItem: parseFloat(row.ozPerItem), + estimatedValue: parseFloat(row.valuePerItem), + foodType: row.foodType, + })); + + await ApiClient.postMultipleDonationItems({ donationId, items }); - const donationItemResponse = await ApiClient.postDonationItem( - donationItem_body, - ); - if (donationItemResponse) { - console.log('Donation item submitted successfully'); - } else { - console.error('Failed to submit donation item'); - alert('Failed to submit donation item'); - } - }); setRows([ { id: 1, @@ -161,139 +146,143 @@ const NewDonationFormModal: React.FC = ({ setTotalOz(0); setTotalValue(0); } else { - console.error('Failed to submit donation'); alert('Failed to submit donation'); } } catch (error) { - console.error('Error submitting new donation', error); - alert('Error submitting new donation'); + alert('Error submitting new donation: ' + error); } }; return ( { if (!e.open) onClose(); }} closeOnInteractOutside > - - - - - - SSF Log New Donation Form SSF Donation Log Form - - - - - Log a new donation by filling out the form below. Use the add or - delete row buttons to add or remove food items from the donation. - Please make sure to fill out all fields before submitting. - - Log a new donation - - - - - - Total # of items: {totalItems}    Total oz of - items: {totalOz}    Total value of items:{' '} - {totalValue} - - - - - - - - Food Item - Food Type - # of Items - Oz per Item - Value per Item - - - - {rows.map((row) => ( - - - - handleChange(row.id, 'foodItem', e.target.value) - } - /> - - - - + + + + + + + + SSF Log New Donation Form + + + + + + Log a new donation by filling out the form below. + + + + + + + + Total Items: {totalItems}   Total oz: {totalOz}{' '} +   Total Value: {totalValue} + + + + + + + + + Food Item + Food Type + # of Items + Oz per Item + Value per Item + + + + + {rows.map((row) => ( + + + - handleChange(row.id, 'foodType', e.target.value) + handleChange(row.id, 'foodItem', e.target.value) } - > - {FoodTypes.map((type) => ( - - ))} - - - - - - - handleChange(row.id, 'numItems', e.target.value) - } - /> - - - - handleChange(row.id, 'ozPerItem', e.target.value) - } - /> - - - - handleChange(row.id, 'valuePerItem', e.target.value) - } - /> - - - ))} - - - - - - - - - - - + /> + + + + + + handleChange(row.id, 'foodType', e.target.value) + } + > + + {FoodTypes.map((type) => ( + + ))} + + + + + + + + handleChange(row.id, 'numItems', e.target.value) + } + /> + + + + + handleChange(row.id, 'ozPerItem', e.target.value) + } + /> + + + + + handleChange( + row.id, + 'valuePerItem', + e.target.value, + ) + } + /> + + + ))} + + + + + + + + + + + + ); }; diff --git a/apps/frontend/src/components/forms/pantryApplicationForm.tsx b/apps/frontend/src/components/forms/pantryApplicationForm.tsx index 94abfe3a..df185caa 100644 --- a/apps/frontend/src/components/forms/pantryApplicationForm.tsx +++ b/apps/frontend/src/components/forms/pantryApplicationForm.tsx @@ -67,18 +67,22 @@ const activityOptions = [ const PantryApplicationForm: React.FC = () => { const [contactPhone, setContactPhone] = useState(''); - const [secondaryContactPhone, setSecondaryContactPhone] = useState(''); + const [secondaryContactPhone, setSecondaryContactPhone] = + useState(''); const [activities, setActivities] = useState([]); const allergenClientsExactOption: string = 'I have an exact number'; const [allergenClients, setAllergenClients] = useState(); const [restrictions, setRestrictions] = useState([]); - const [reserveFoodForAllergic, setReserveFoodForAllergic] = useState(); - const [differentMailingAddress, setDifferentMailingAddress] = useState(); + const [reserveFoodForAllergic, setReserveFoodForAllergic] = + useState(); + const [differentMailingAddress, setDifferentMailingAddress] = useState< + boolean | null + >(); const [otherEmailContact, setOtherEmailContact] = useState(false); const sectionTitleStyles = { - fontFamily: "inter", + fontFamily: 'inter', fontWeight: '600', fontSize: 'md', color: 'gray.dark', @@ -86,16 +90,16 @@ const PantryApplicationForm: React.FC = () => { }; const sectionSubtitleStyles = { - fontFamily: "inter", + fontFamily: 'inter', fontWeight: '400', color: 'gray.light', mb: '2.25em', fontSize: 'sm', - } + }; const fieldHeaderStyles = { color: 'neutral.800', - fontFamily: "inter", + fontFamily: 'inter', fontSize: 'sm', fontWeight: '600', }; @@ -103,96 +107,121 @@ const PantryApplicationForm: React.FC = () => { return ( - + Partner Pantry Application - Thank you for your interest in partnering with Securing Safe Food (SSF) to help - serve clients with food allergies and other adverse reactions to foods. + Thank you for your interest in partnering with Securing Safe Food + (SSF) to help serve clients with food allergies and other adverse + reactions to foods. -
- + Pantry Application Form - + - This application helps us understand your pantry’s capacity and interest in - distributing allergen-friendly food. We’ll ask about your pantry’s current - practices, storage capabilities, and communication preferences. + This application helps us understand your pantry’s capacity and + interest in distributing allergen-friendly food. We’ll ask about + your pantry’s current practices, storage capabilities, and + communication preferences. - Please answer as accurately as possible. If you have any questions or need help, - don’t hesitate to contact the SSF team. + Please answer as accurately as possible. If you have any questions + or need help, don’t hesitate to contact the SSF team. - - - Primary Contact Information - + + Primary Contact Information First Name - + - + Last Name - + - + Phone Number - + Email Address - + - + - Is there someone at your pantry who can regularly check and respond to emails from SSF as needed?{' '} - + Is there someone at your pantry who can regularly check and + respond to emails from SSF as needed?{' '} + - setOtherEmailContact(e.value === 'Other')} + onValueChange={(e: { value: string }) => + setOtherEmailContact(e.value === 'Other') + } > {['Yes', 'No', 'Other'].map((value) => ( - - - + + - + {value} @@ -201,127 +230,151 @@ const PantryApplicationForm: React.FC = () => { - - + - - Secondary Contact Information - + Secondary Contact Information - - First Name - - + First Name + - - Last Name - - + Last Name + - - Phone Number - + Phone Number - - Email Address - - + Email Address + - - + + Food Shipment Address Please list your address for food shipments. - + Address Line 1 - + - + - - Address Line 2 - - + Address Line 2 + City/Town - + - + State/Region/Province - + - + Zip/Post Code - + - + - - Country - - + Country + - Does this address differ from your pantry's mailing address for documents?{' '} - + Does this address differ from your pantry's mailing address for + documents? - setDifferentMailingAddress(e.value === 'Yes')} + onValueChange={(e: { value: string }) => + setDifferentMailingAddress(e.value === 'Yes') + } name="differentMailingAddress" > {['Yes', 'No'].map((value) => ( - - - + + - + {value} @@ -331,28 +384,22 @@ const PantryApplicationForm: React.FC = () => { - Would your pantry be able to accept food deliveries - during standard business hours Mon-Fri?{' '} - + Would your pantry be able to accept food deliveries during + standard business hours Mon-Fri?{' '} + - + {['Yes', 'No'].map((value) => ( - - + - + {value} @@ -364,10 +411,13 @@ const PantryApplicationForm: React.FC = () => { Please note any delivery window restrictions. -