From 28a0ab50fdd96c59b7eb733db04e1c4a7c581b20 Mon Sep 17 00:00:00 2001 From: Dalton Burkhart Date: Mon, 8 Jun 2026 00:23:08 -0700 Subject: [PATCH 1/7] Initial pantry application changes --- .../pantries/dtos/pantry-application.dto.ts | 10 +- apps/backend/src/pantries/types.ts | 1 - .../forms/editableFMApplication.tsx | 28 - .../forms/editablePantryApplication.tsx | 56 +- .../forms/manufacturerApplicationForm.tsx | 71 ++- .../forms/pantryApplicationForm.tsx | 538 ++++++++++-------- .../forms/pantryApplicationModal.tsx | 12 - .../foodManufacturerApplicationDetails.tsx | 7 - .../containers/pantryApplicationDetails.tsx | 19 +- apps/frontend/src/types/pantryEnums.ts | 13 +- apps/frontend/src/types/types.ts | 22 +- 11 files changed, 381 insertions(+), 396 deletions(-) diff --git a/apps/backend/src/pantries/dtos/pantry-application.dto.ts b/apps/backend/src/pantries/dtos/pantry-application.dto.ts index 3a71c1762..406671670 100644 --- a/apps/backend/src/pantries/dtos/pantry-application.dto.ts +++ b/apps/backend/src/pantries/dtos/pantry-application.dto.ts @@ -111,11 +111,10 @@ export class PantryApplicationDto { @Length(1, 255) shipmentAddressZip!: string; - @IsOptional() @IsString() - @MaxLength(255) @IsNotEmpty() - shipmentAddressCountry?: string; + @Length(1, 255) + shipmentAddressCountry!: string; @IsString() @IsNotEmpty() @@ -143,11 +142,10 @@ export class PantryApplicationDto { @Length(1, 255) mailingAddressZip!: string; - @IsOptional() @IsString() - @MaxLength(255) @IsNotEmpty() - mailingAddressCountry?: string; + @Length(1, 255) + mailingAddressCountry!: string; @IsString() @IsNotEmpty() diff --git a/apps/backend/src/pantries/types.ts b/apps/backend/src/pantries/types.ts index 8b904d331..6eab9ecff 100644 --- a/apps/backend/src/pantries/types.ts +++ b/apps/backend/src/pantries/types.ts @@ -70,7 +70,6 @@ export enum ServeAllergicChildren { export enum Activity { CREATE_LABELED_SHELF = 'Create labeled shelf', PROVIDE_EDUCATIONAL_PAMPHLETS = 'Provide educational pamphlets', - TRACK_DIETARY_NEEDS = 'Spreadsheet to track dietary needs', POST_RESOURCE_FLYERS = 'Post allergen-free resource flyers', SURVEY_CLIENTS = 'Survey clients to determine medical dietary needs', COLLECT_FEEDBACK = 'Collect feedback from allergen-avoidant clients', diff --git a/apps/frontend/src/components/forms/editableFMApplication.tsx b/apps/frontend/src/components/forms/editableFMApplication.tsx index a82f61a4c..109c9f42f 100644 --- a/apps/frontend/src/components/forms/editableFMApplication.tsx +++ b/apps/frontend/src/components/forms/editableFMApplication.tsx @@ -55,7 +55,6 @@ type FormState = { donateWastedFood: string; manufacturerAttribute: string; additionalComments: string; - newsletterSubscription: string; }; function buildFormState(app: FoodManufacturer): FormState { @@ -75,12 +74,6 @@ function buildFormState(app: FoodManufacturer): FormState { donateWastedFood: app.donateWastedFood ?? '', manufacturerAttribute: app.manufacturerAttribute ?? '', additionalComments: app.additionalComments ?? '', - newsletterSubscription: - app.newsletterSubscription != null - ? app.newsletterSubscription - ? 'Yes' - : 'No' - : '', }; } @@ -170,9 +163,6 @@ const EditableFMApplication: React.FC = ({ manufacturerAttribute: (form.manufacturerAttribute as ManufacturerAttribute) || undefined, additionalComments: form.additionalComments || undefined, - newsletterSubscription: form.newsletterSubscription - ? form.newsletterSubscription === 'Yes' - : undefined, }; const updated = await ApiClient.updateFoodManufacturerApplicationData( application.foodManufacturerId, @@ -316,16 +306,6 @@ const EditableFMApplication: React.FC = ({ label="Additional Information" value={application.additionalComments} /> - ); @@ -482,14 +462,6 @@ const EditableFMApplication: React.FC = ({ textarea /> - setField('newsletterSubscription', v)} - /> - {error && ( {error} diff --git a/apps/frontend/src/components/forms/editablePantryApplication.tsx b/apps/frontend/src/components/forms/editablePantryApplication.tsx index 8fb74e023..f12ea8c9d 100644 --- a/apps/frontend/src/components/forms/editablePantryApplication.tsx +++ b/apps/frontend/src/components/forms/editablePantryApplication.tsx @@ -17,8 +17,8 @@ import { RefrigeratedDonation, ReserveFoodForAllergic, ClientVisitFrequency, - AllergensConfidence, ServeAllergicChildren, + DedicatedAllergyFriendly, } from '../../types/pantryEnums'; import { formatPhone } from '@utils/utils'; import { TagGroup } from '@components/forms/tagGroup'; @@ -110,13 +110,11 @@ type FormState = { reservationExplanation: string; dedicatedAllergyFriendly: string; clientVisitFrequency: string; - identifyAllergensConfidence: string; serveAllergicChildren: string; activities: string[]; activitiesComments: string; itemsInStock: string; needMoreOptions: string; - newsletterSubscription: string; }; function buildFormState(app: PantryWithUser): FormState { @@ -152,20 +150,13 @@ function buildFormState(app: PantryWithUser): FormState { refrigeratedDonation: app.refrigeratedDonation ?? '', reserveFoodForAllergic: app.reserveFoodForAllergic ?? '', reservationExplanation: app.reservationExplanation ?? '', - dedicatedAllergyFriendly: app.dedicatedAllergyFriendly ? 'Yes' : 'No', + dedicatedAllergyFriendly: app.dedicatedAllergyFriendly ?? '', clientVisitFrequency: app.clientVisitFrequency ?? '', - identifyAllergensConfidence: app.identifyAllergensConfidence ?? '', serveAllergicChildren: app.serveAllergicChildren ?? '', activities: app.activities ?? [], activitiesComments: app.activitiesComments ?? '', itemsInStock: app.itemsInStock ?? '', needMoreOptions: app.needMoreOptions ?? '', - newsletterSubscription: - app.newsletterSubscription != null - ? app.newsletterSubscription - ? 'Yes' - : 'No' - : '', }; } @@ -285,7 +276,9 @@ const EditablePantryApplication: React.FC = ({ restrictions: form.restrictions, refrigeratedDonation: (form.refrigeratedDonation as RefrigeratedDonation) || undefined, - dedicatedAllergyFriendly: form.dedicatedAllergyFriendly === 'Yes', + dedicatedAllergyFriendly: + (form.dedicatedAllergyFriendly as DedicatedAllergyFriendly) || + undefined, reserveFoodForAllergic: (form.reserveFoodForAllergic as ReserveFoodForAllergic) || undefined, reservationExplanation: @@ -295,16 +288,12 @@ const EditablePantryApplication: React.FC = ({ : null, clientVisitFrequency: (form.clientVisitFrequency as ClientVisitFrequency) || undefined, - identifyAllergensConfidence: - (form.identifyAllergensConfidence as AllergensConfidence) || - undefined, serveAllergicChildren: (form.serveAllergicChildren as ServeAllergicChildren) || undefined, activities: form.activities as Activity[], activitiesComments: form.activitiesComments || undefined, itemsInStock: form.itemsInStock || undefined, needMoreOptions: form.needMoreOptions || undefined, - newsletterSubscription: form.newsletterSubscription === 'Yes', }; const updated = await ApiClient.updatePantryApplicationData( application.pantryId, @@ -455,7 +444,7 @@ const EditablePantryApplication: React.FC = ({ /> = ({ label="How Often Do Allergen-Avoidant Clients Visit?" value={application.clientVisitFrequency} /> - = ({ value={application.itemsInStock} /> - ); @@ -630,7 +605,7 @@ const EditablePantryApplication: React.FC = ({ label="Do you have a dedicated shelf or section of your pantry for allergy-friendly items?" name="dedicatedAllergyFriendly" value={form.dedicatedAllergyFriendly} - options={['Yes', 'No']} + options={Object.values(DedicatedAllergyFriendly)} onChange={(v) => setField('dedicatedAllergyFriendly', v)} required /> @@ -669,15 +644,6 @@ const EditablePantryApplication: React.FC = ({ onChange={(v) => setField('clientVisitFrequency', v)} /> - setField('identifyAllergensConfidence', v)} - /> - = ({ required /> - setField('newsletterSubscription', v)} - /> - {error && ( {error} diff --git a/apps/frontend/src/components/forms/manufacturerApplicationForm.tsx b/apps/frontend/src/components/forms/manufacturerApplicationForm.tsx index e104581cf..6fcc5d5ce 100644 --- a/apps/frontend/src/components/forms/manufacturerApplicationForm.tsx +++ b/apps/frontend/src/components/forms/manufacturerApplicationForm.tsx @@ -14,6 +14,7 @@ import { Separator, Checkbox, Menu, + Link, } from '@chakra-ui/react'; import { ActionFunction, @@ -81,7 +82,7 @@ const ManufacturerApplicationForm: React.FC = () => { }, [actionData, setAlertMessage]); return ( - + {alertState && ( { - - - Would you like to subscribe to our quarterly newsletter? - - - - {['Yes', 'No'].map((value) => ( - - - - - - - {value} - - - ))} - - + + + + + + By submitting this form, you agree to our{' '} + e.stopPropagation()} + > + Privacy Policy + {' '} + and{' '} + e.stopPropagation()} + > + Terms of Use + + . + + - + - By submitting this form, you agree to our Privacy Policy.{' '} - + By submitting this form, you agree to receive automated emails + from Securing Safe Food (SSF) Corp. should your pantry be + enrolled in our program. @@ -698,14 +712,9 @@ export const submitManufacturerApplicationForm: ActionFunction = async ({ 'inKindDonations', form.get('inKindDonations') === 'Yes', ); - manufacturerApplicationData.set( - 'newsletterSubscription', - form.get('newsletterSubscription') === 'Yes', - ); form.delete('productsGlutenFree'); form.delete('productsContainSulfites'); form.delete('inKindDonations'); - form.delete('newsletterSubscription'); form.delete('unlistedProductAllergens'); form.delete('facilityFreeAllergens'); diff --git a/apps/frontend/src/components/forms/pantryApplicationForm.tsx b/apps/frontend/src/components/forms/pantryApplicationForm.tsx index 526de1d1d..91d18308d 100644 --- a/apps/frontend/src/components/forms/pantryApplicationForm.tsx +++ b/apps/frontend/src/components/forms/pantryApplicationForm.tsx @@ -14,6 +14,7 @@ import { Separator, Checkbox, Menu, + Link, } from '@chakra-ui/react'; import { ActionFunction, @@ -26,7 +27,7 @@ import React, { useEffect, useState } from 'react'; import { USPhoneInput } from '@components/forms/usPhoneInput'; import { PantryApplicationDto } from '../../types/types'; import ApiClient from '@api/apiClient'; -import { Activity } from '../../types/pantryEnums'; +import { Activity, DedicatedAllergyFriendly } from '../../types/pantryEnums'; import axios from 'axios'; import { ChevronDownIcon } from 'lucide-react'; import { TagGroup } from './tagGroup'; @@ -34,28 +35,24 @@ 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.)', - 'Other allergic illness (e.g., eosinophilic esophagitis, FPIES, oral allergy syndrome)', - 'Other dietary restriction', -]; +export const restrictionsOtherOption = + "Other (e.g., irritable bowel syndrome, Crohn's disease, fruit/vegetable sensitivities)"; export const dietaryRestrictionOptions = [ - 'Egg allergy', - 'Fish allergy', 'Milk allergy', - 'Lactose intolerance/dairy sensitivity', + 'Lactose intolerance', + 'Egg allergy', 'Peanut allergy', + 'Tree nut allergy', + 'Fish allergy', 'Shellfish allergy', + 'Celiac disease', + 'Gluten intolerance or sensitivity', + 'Wheat allergy', 'Soy allergy', 'Sesame allergy', - 'Tree nut allergy', - 'Wheat allergy', - 'Celiac disease', - 'Gluten sensitivity (not celiac disease)', - "Gastrointestinal illness (IBS, Crohn's, gastroparesis, etc.)", - ...otherRestrictionsOptions, - 'Unsure', + "I'm not sure", + restrictionsOtherOption, ]; export const activityOptions = [ @@ -65,7 +62,16 @@ export const activityOptions = [ 'Post allergen-free resource flyers throughout pantry', 'Survey your clients to determine their medical dietary needs', 'Collect feedback from allergen-avoidant clients on SSF foods', - 'Something else', +]; + +export const languageOtherOption = 'Other (please specify)'; + +export const languageOptions = [ + 'English', + 'Spanish', + 'Mandarin', + 'Russian', + languageOtherOption, ]; const PantryApplicationForm: React.FC = () => { @@ -77,6 +83,7 @@ const PantryApplicationForm: React.FC = () => { const [allergenClients, setAllergenClients] = useState(); const [restrictions, setRestrictions] = useState([]); + const [languages, setLanguages] = useState([]); const [reserveFoodForAllergic, setReserveFoodForAllergic] = useState(); const [differentMailingAddress, setDifferentMailingAddress] = useState< @@ -116,7 +123,7 @@ const PantryApplicationForm: React.FC = () => { }, [actionData, setAlertMessage]); return ( - + {alertState && ( { - Primary Contact Information + + + + Food Pantry Name + + + + + + + Primary Contact + @@ -207,7 +225,7 @@ const PantryApplicationForm: React.FC = () => { - Email Address + Email { /> + Secondary Contact - - Secondary Contact Information First Name @@ -292,7 +309,7 @@ const PantryApplicationForm: React.FC = () => { /> - Email Address + Email { - Food Shipment Address - - - Please list your address for food shipments. + What is your pantry's address for food shipments? + @@ -331,7 +346,7 @@ const PantryApplicationForm: React.FC = () => { - City/Town + City { - State/Region/Province + Zip Code - Zip/Post Code + Country - - Country + + + State + + + Does this address differ from your pantry's mailing address for - documents? + documents (e.g., 11" by 17" poster resources)?{' '} + { - - - Would your pantry be able to accept food deliveries during - standard business hours Mon-Fri?{' '} - - - - - {['Yes', 'No'].map((value) => ( - - - - - - - {value} - - - ))} - - - - - - Please note any delivery window restrictions. - -