diff --git a/.gitignore b/.gitignore index 3c2eb0de..57f5508d 100644 --- a/.gitignore +++ b/.gitignore @@ -2,5 +2,6 @@ .idea/ log .DS_Store +backend/tmp/ .vscode/ diff --git a/backend/src/modules/location-address/service.ts b/backend/src/modules/location-address/service.ts index 42e5cd7a..847e759f 100644 --- a/backend/src/modules/location-address/service.ts +++ b/backend/src/modules/location-address/service.ts @@ -80,9 +80,15 @@ export class LocationAddressService implements ILocationAddressService { createLocationAddress = withServiceErrorHandling( async (payload: CreateLocationAddressDTO, companyId: string): Promise => { const fipsLocation = await this.locationMatcher.getLocationFips(payload); - - if (fipsLocation === null) { - throw Boom.badRequest("Fips state and county code cannot be null"); + if ( + fipsLocation === null || + !fipsLocation || + fipsLocation.fipsStateCode === null || + fipsLocation.fipsCountyCode === null + ) { + throw Boom.badRequest( + `Please enter a valid address. Unable to validate address: ${payload.streetAddress}, ${payload.city}, ${payload.stateProvince}.` + ); } // Add FIPS codes into payload to send to transaction layer @@ -137,6 +143,11 @@ export class LocationAddressService implements ILocationAddressService { const transformedPayload = await Promise.all( payload.map(async (element) => { const currFips = await this.locationMatcher.getLocationFips(element); + if (!currFips || currFips.fipsStateCode === null || currFips.fipsCountyCode === null) { + throw Boom.badRequest( + `Please enter a valid address. Unable to validate address: ${element.streetAddress}, ${element.city}, ${element.stateProvince}.` + ); + } return { ...element, ...currFips }; }) ); @@ -177,8 +188,15 @@ export class LocationAddressService implements ILocationAddressService { // get the new fips codes if any of the address fields have changed const fipsLocation = await this.locationMatcher.getLocationFips(locationForMatching); - if (fipsLocation === null) { - throw Boom.badRequest("Fips state and county code cannot be null"); + if ( + fipsLocation === null || + !fipsLocation || + fipsLocation.fipsStateCode === null || + fipsLocation.fipsCountyCode === null + ) { + throw Boom.badRequest( + `Please enter a valid address. Unable to validate address: ${payload.streetAddress}, ${payload.city}, ${payload.stateProvince}.` + ); } const updatedLocationWithFips = { diff --git a/backend/src/types/Location.ts b/backend/src/types/Location.ts index 9e2560db..bbd2a3e4 100644 --- a/backend/src/types/Location.ts +++ b/backend/src/types/Location.ts @@ -11,7 +11,7 @@ export const LocationAddressSchema = z.object({ city: z.string(), streetAddress: z.string(), postalCode: z.string().nonempty().regex(/^\d+$/, { - message: "Must be a non-negative number string", + message: "Please enter a valid Postal Code. Must be a non-negative number.", }), county: z.string().optional(), companyId: z.uuid(), @@ -29,7 +29,7 @@ export const LocationAddressSchemaType = z.object({ city: z.string(), streetAddress: z.string(), postalCode: z.string().nonempty().regex(/^\d+$/, { - message: "Must be a non-negative number string", + message: "Please enter a valid Postal Code. Must be a non-negative number.", }), county: z.string().optional(), companyId: z.uuid(), @@ -45,7 +45,7 @@ export const CreateLocationAddressSchema = z.object({ city: z.string().nonempty(), streetAddress: z.string().nonempty(), postalCode: z.string().nonempty().regex(/^\d+$/, { - message: "Must be a non-negative number string", + message: "Please enter a valid Postal Code. Must be a non-negative number.", }), county: z.string().nonempty().optional(), }); @@ -72,7 +72,7 @@ export const GetAllLocationAddressesSchema = z.array( city: z.string().nonempty(), streetAddress: z.string().nonempty(), postalCode: z.string().nonempty().regex(/^\d+$/, { - message: "Must be a non-negative number string", + message: "Please enter a valid Postal Code. Must be a non-negative number.", }), county: z.string().nonempty().optional(), companyId: z.uuid(), @@ -93,7 +93,7 @@ export const UpdateLocationAddressDTOSchema = z.object({ postalCode: z .string() .regex(/^\d+$/, { - message: "Must be a non-negative number string", + message: "Please enter a valid Postal Code. Must be a non-negative number.", }) .optional(), county: z.string().optional().nullable(), diff --git a/backend/src/utilities/error.ts b/backend/src/utilities/error.ts index d74a2bac..2519d3ac 100644 --- a/backend/src/utilities/error.ts +++ b/backend/src/utilities/error.ts @@ -24,7 +24,7 @@ export const withServiceErrorHandling = (handler: (...args: case "23502": throw Boom.badRequest("Missing required field"); default: - throw Boom.internal(error, { message: "An expected error occured" }); + throw Boom.internal(error, { message: "An unexpected error occured" }); } } else { throw Boom.boomify(error); diff --git a/frontend/api/location.ts b/frontend/api/location.ts index f541f871..cb7e5801 100644 --- a/frontend/api/location.ts +++ b/frontend/api/location.ts @@ -20,7 +20,13 @@ export const createLocation = async (payload: CreateLocationRequest): Promise()(req); @@ -36,7 +42,13 @@ export const createLocationBulk = async (payload: CreateLocationBulkRequest): Pr if (response.ok) { return data!; } else { - throw Error(error?.error); + const apiError = new Error(error?.error || "Failed to create locations - Unkown Error") as Error & { + status: number; + statusText: string; + }; + apiError.status = response.status; + apiError.statusText = response.statusText; + throw apiError; } }; return authWrapper()(req); diff --git a/frontend/app/business-profile/overview/InsuranceCard.tsx b/frontend/app/business-profile/overview/InsuranceCard.tsx index 56b21048..31225c92 100644 --- a/frontend/app/business-profile/overview/InsuranceCard.tsx +++ b/frontend/app/business-profile/overview/InsuranceCard.tsx @@ -34,7 +34,8 @@ export default function InsuranceCard() { setEditingInsuranceIndex(null); }, onError: (error: Error) => { - setSaveError("An error occurred while saving the location: " + error.message); + const errorMessage = error.message || "Error updating policy. Check required fields and try again"; + setSaveError(errorMessage); }, }); @@ -45,7 +46,8 @@ export default function InsuranceCard() { setEditingInsuranceIndex(null); }, onError: (error: Error) => { - setSaveError("An error occurred while saving the location: " + error.message); + const errorMessage = error.message || "Error creating policy. Check required fields and try again"; + setSaveError(errorMessage); }, }); diff --git a/frontend/app/business-profile/overview/LocationsCard.tsx b/frontend/app/business-profile/overview/LocationsCard.tsx index fbbd465c..44b02cdd 100644 --- a/frontend/app/business-profile/overview/LocationsCard.tsx +++ b/frontend/app/business-profile/overview/LocationsCard.tsx @@ -31,7 +31,8 @@ export default function LocationsCard() { if (error.message.includes("postalCode")) { setSaveError("Error updating location. Please check postal code details and try again."); } else { - setSaveError("An error occurred while saving the location."); + const errorMessage = error.message || "Error updating location. Check required fields and try again"; + setSaveError(errorMessage); } }, }); @@ -46,7 +47,8 @@ export default function LocationsCard() { if (error.message.includes("postalCode")) { setSaveError("Error creating location. Please check postal code details and try again."); } else { - setSaveError("An error occurred while creating the location."); + const errorMessage = error.message || "Error creating location. Check required fields and try again"; + setSaveError(errorMessage); } }, }); @@ -58,7 +60,8 @@ export default function LocationsCard() { setEditingLocationIndex(null); }, onError: (_error: Error) => { - setSaveError("An error occurred while deleting the location."); + const errorMessage = _error.message || "Error removing location. Check required fields and try again"; + setSaveError(errorMessage); }, }); diff --git a/frontend/app/signup/company.tsx b/frontend/app/signup/company.tsx index 3aca90f0..0a5d21a3 100644 --- a/frontend/app/signup/company.tsx +++ b/frontend/app/signup/company.tsx @@ -73,7 +73,8 @@ export default function Company({ handleNext: incrementNext }: CompanyInfoProps) incrementNext(); }, onError: (_error: Error) => { - setLocError("Error creating locations. Check required fields and try again"); + const errorMessage = _error.message || "Error creating locations. Check required fields and try again"; + setLocError(errorMessage); }, }); diff --git a/frontend/components/table/CategorySelector.tsx b/frontend/components/table/CategorySelector.tsx index 763e7c18..6aefb92f 100644 --- a/frontend/components/table/CategorySelector.tsx +++ b/frontend/components/table/CategorySelector.tsx @@ -24,7 +24,6 @@ export default function CategorySelector({ categories = defaultCategories, }: CategorySelectorProps) { const [isOpen, setIsOpen] = useState(false); - const [searchQuery, setSearchQuery] = useState(""); const dropdownRef = useRef(null); const [portalRoot, setPortalRoot] = useState(null); const portalDropdownRef = useRef(null); @@ -62,12 +61,9 @@ export default function CategorySelector({ }; }, [isOpen]); - const filteredCategories = categories.filter((cat) => cat.toLowerCase().includes(searchQuery.toLowerCase())); - const handleCategorySelect = (category: string) => { onCategoryChange(category); setIsOpen(false); - setSearchQuery(""); }; const handleRemoveCategory = (e: React.MouseEvent) => { @@ -107,7 +103,7 @@ export default function CategorySelector({ createPortal(
- {/* Search Input */} -
- setSearchQuery(e.target.value)} - className="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-purple-500 text-sm" - autoFocus - /> -
- {/* Category List */}
- {filteredCategories.length > 0 ? ( - filteredCategories.map((category) => ( -
handleCategorySelect(category)} - className="flex items-center gap-3 px-4 py-3 hover:bg-gray-50 cursor-pointer transition-colors" - > - {/* Drag Handle */} -
-
-
-
-
-
-
-
-
-
-
-
-
+ {categories.map((category) => ( +
handleCategorySelect(category)} + className="flex items-center gap-3 px-4 py-3 hover:bg-gray-50 cursor-pointer transition-colors" + > + {/* Drag Handle */} +
+
+
+
- - {/* Category */} - - {category} - -
- )) - ) : ( -
- {searchQuery ? ( -
-

No matching categories

- +
+
+
+
+
+
+
- ) : ( - "No categories available" - )} +
+ + {/* Category */} + + {category} +
- )} + ))}
, portalRoot