fixing bugs with item notification radius
This commit is contained in:
@@ -6,6 +6,10 @@ import {
|
||||
} from "../services/geocodingService";
|
||||
import AddressAutocomplete from "./AddressAutocomplete";
|
||||
import { PlaceDetails } from "../services/placesService";
|
||||
import {
|
||||
useAddressAutocomplete,
|
||||
usStates,
|
||||
} from "../hooks/useAddressAutocomplete";
|
||||
|
||||
interface LocationFormData {
|
||||
address1: string;
|
||||
@@ -29,123 +33,14 @@ interface LocationFormProps {
|
||||
onAddressSelect: (addressId: string) => void;
|
||||
formatAddressDisplay: (address: Address) => string;
|
||||
onCoordinatesChange?: (latitude: number, longitude: number) => void;
|
||||
onGeocodeRef?: (geocodeFunction: () => Promise<boolean>) => void;
|
||||
onGeocodeRef?: (
|
||||
geocodeFunction: () => Promise<{
|
||||
latitude: number;
|
||||
longitude: number;
|
||||
} | null>
|
||||
) => void;
|
||||
}
|
||||
|
||||
// State constants - moved to top to avoid hoisting issues
|
||||
const usStates = [
|
||||
"Alabama",
|
||||
"Alaska",
|
||||
"Arizona",
|
||||
"Arkansas",
|
||||
"California",
|
||||
"Colorado",
|
||||
"Connecticut",
|
||||
"Delaware",
|
||||
"Florida",
|
||||
"Georgia",
|
||||
"Hawaii",
|
||||
"Idaho",
|
||||
"Illinois",
|
||||
"Indiana",
|
||||
"Iowa",
|
||||
"Kansas",
|
||||
"Kentucky",
|
||||
"Louisiana",
|
||||
"Maine",
|
||||
"Maryland",
|
||||
"Massachusetts",
|
||||
"Michigan",
|
||||
"Minnesota",
|
||||
"Mississippi",
|
||||
"Missouri",
|
||||
"Montana",
|
||||
"Nebraska",
|
||||
"Nevada",
|
||||
"New Hampshire",
|
||||
"New Jersey",
|
||||
"New Mexico",
|
||||
"New York",
|
||||
"North Carolina",
|
||||
"North Dakota",
|
||||
"Ohio",
|
||||
"Oklahoma",
|
||||
"Oregon",
|
||||
"Pennsylvania",
|
||||
"Rhode Island",
|
||||
"South Carolina",
|
||||
"South Dakota",
|
||||
"Tennessee",
|
||||
"Texas",
|
||||
"Utah",
|
||||
"Vermont",
|
||||
"Virginia",
|
||||
"Washington",
|
||||
"West Virginia",
|
||||
"Wisconsin",
|
||||
"Wyoming",
|
||||
];
|
||||
|
||||
// State code to full name mapping for Google Places API integration
|
||||
const stateCodeToName: { [key: string]: string } = {
|
||||
AL: "Alabama",
|
||||
AK: "Alaska",
|
||||
AZ: "Arizona",
|
||||
AR: "Arkansas",
|
||||
CA: "California",
|
||||
CO: "Colorado",
|
||||
CT: "Connecticut",
|
||||
DE: "Delaware",
|
||||
FL: "Florida",
|
||||
GA: "Georgia",
|
||||
HI: "Hawaii",
|
||||
ID: "Idaho",
|
||||
IL: "Illinois",
|
||||
IN: "Indiana",
|
||||
IA: "Iowa",
|
||||
KS: "Kansas",
|
||||
KY: "Kentucky",
|
||||
LA: "Louisiana",
|
||||
ME: "Maine",
|
||||
MD: "Maryland",
|
||||
MA: "Massachusetts",
|
||||
MI: "Michigan",
|
||||
MN: "Minnesota",
|
||||
MS: "Mississippi",
|
||||
MO: "Missouri",
|
||||
MT: "Montana",
|
||||
NE: "Nebraska",
|
||||
NV: "Nevada",
|
||||
NH: "New Hampshire",
|
||||
NJ: "New Jersey",
|
||||
NM: "New Mexico",
|
||||
NY: "New York",
|
||||
NC: "North Carolina",
|
||||
ND: "North Dakota",
|
||||
OH: "Ohio",
|
||||
OK: "Oklahoma",
|
||||
OR: "Oregon",
|
||||
PA: "Pennsylvania",
|
||||
RI: "Rhode Island",
|
||||
SC: "South Carolina",
|
||||
SD: "South Dakota",
|
||||
TN: "Tennessee",
|
||||
TX: "Texas",
|
||||
UT: "Utah",
|
||||
VT: "Vermont",
|
||||
VA: "Virginia",
|
||||
WA: "Washington",
|
||||
WV: "West Virginia",
|
||||
WI: "Wisconsin",
|
||||
WY: "Wyoming",
|
||||
DC: "District of Columbia",
|
||||
PR: "Puerto Rico",
|
||||
VI: "Virgin Islands",
|
||||
AS: "American Samoa",
|
||||
GU: "Guam",
|
||||
MP: "Northern Mariana Islands",
|
||||
};
|
||||
|
||||
const LocationForm: React.FC<LocationFormProps> = ({
|
||||
data,
|
||||
userAddresses,
|
||||
@@ -164,11 +59,13 @@ const LocationForm: React.FC<LocationFormProps> = ({
|
||||
|
||||
// Debounced geocoding function
|
||||
const geocodeAddress = useCallback(
|
||||
async (addressData: LocationFormData) => {
|
||||
async (
|
||||
addressData: LocationFormData
|
||||
): Promise<{ latitude: number; longitude: number } | null> => {
|
||||
if (
|
||||
!geocodingService.isAddressComplete(addressData as AddressComponents)
|
||||
) {
|
||||
return;
|
||||
return null;
|
||||
}
|
||||
|
||||
setGeocoding(true);
|
||||
@@ -182,6 +79,7 @@ const LocationForm: React.FC<LocationFormProps> = ({
|
||||
|
||||
if ("error" in result) {
|
||||
setGeocodeError(result.details || result.error);
|
||||
return null;
|
||||
} else {
|
||||
setGeocodeSuccess(true);
|
||||
if (onCoordinatesChange) {
|
||||
@@ -189,9 +87,13 @@ const LocationForm: React.FC<LocationFormProps> = ({
|
||||
}
|
||||
// Clear success message after 3 seconds
|
||||
setTimeout(() => setGeocodeSuccess(false), 3000);
|
||||
|
||||
// Return the coordinates
|
||||
return { latitude: result.latitude, longitude: result.longitude };
|
||||
}
|
||||
} catch (error) {
|
||||
setGeocodeError("Failed to geocode address");
|
||||
return null;
|
||||
} finally {
|
||||
setGeocoding(false);
|
||||
}
|
||||
@@ -202,10 +104,10 @@ const LocationForm: React.FC<LocationFormProps> = ({
|
||||
// Expose geocoding function to parent components
|
||||
const triggerGeocoding = useCallback(async () => {
|
||||
if (data.address1 && data.city && data.state && data.zipCode) {
|
||||
await geocodeAddress(data);
|
||||
return true; // Successfully triggered
|
||||
const coordinates = await geocodeAddress(data);
|
||||
return coordinates; // Return coordinates directly from geocoding
|
||||
}
|
||||
return false; // Incomplete address
|
||||
return null; // Incomplete address
|
||||
}, [data, geocodeAddress]);
|
||||
|
||||
// Pass geocoding function to parent component
|
||||
@@ -215,16 +117,19 @@ const LocationForm: React.FC<LocationFormProps> = ({
|
||||
}
|
||||
}, [onGeocodeRef, triggerGeocoding]);
|
||||
|
||||
// Use address autocomplete hook
|
||||
const { parsePlace } = useAddressAutocomplete();
|
||||
|
||||
// Handle place selection from autocomplete
|
||||
const handlePlaceSelect = useCallback(
|
||||
(place: PlaceDetails) => {
|
||||
try {
|
||||
const addressComponents = place.addressComponents;
|
||||
const parsedAddress = parsePlace(place);
|
||||
|
||||
// Build address1 from street number and route
|
||||
const streetNumber = addressComponents.streetNumber || "";
|
||||
const route = addressComponents.route || "";
|
||||
const address1 = `${streetNumber} ${route}`.trim();
|
||||
if (!parsedAddress) {
|
||||
setPlacesApiError(true);
|
||||
return;
|
||||
}
|
||||
|
||||
// Create synthetic events to update form data
|
||||
const createSyntheticEvent = (name: string, value: string) =>
|
||||
@@ -237,52 +142,15 @@ const LocationForm: React.FC<LocationFormProps> = ({
|
||||
} as React.ChangeEvent<HTMLInputElement>);
|
||||
|
||||
// Update all address fields
|
||||
onChange(
|
||||
createSyntheticEvent("address1", address1 || place.formattedAddress)
|
||||
);
|
||||
|
||||
if (addressComponents.locality) {
|
||||
onChange(createSyntheticEvent("city", addressComponents.locality));
|
||||
}
|
||||
|
||||
if (addressComponents.administrativeAreaLevel1) {
|
||||
// Convert state code to full name using mapping, with fallback to long name or original code
|
||||
const stateCode = addressComponents.administrativeAreaLevel1;
|
||||
const stateName =
|
||||
stateCodeToName[stateCode] ||
|
||||
addressComponents.administrativeAreaLevel1Long ||
|
||||
stateCode;
|
||||
|
||||
// Only set the state if it exists in our dropdown options
|
||||
if (usStates.includes(stateName)) {
|
||||
onChange(createSyntheticEvent("state", stateName));
|
||||
} else {
|
||||
console.warn(
|
||||
`State not found in dropdown options: ${stateName} (code: ${stateCode})`
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
if (addressComponents.postalCode) {
|
||||
onChange(
|
||||
createSyntheticEvent("zipCode", addressComponents.postalCode)
|
||||
);
|
||||
}
|
||||
|
||||
if (addressComponents.country) {
|
||||
onChange(createSyntheticEvent("country", addressComponents.country));
|
||||
}
|
||||
onChange(createSyntheticEvent("address1", parsedAddress.address1));
|
||||
onChange(createSyntheticEvent("city", parsedAddress.city));
|
||||
onChange(createSyntheticEvent("state", parsedAddress.state));
|
||||
onChange(createSyntheticEvent("zipCode", parsedAddress.zipCode));
|
||||
onChange(createSyntheticEvent("country", parsedAddress.country));
|
||||
|
||||
// Set coordinates immediately
|
||||
if (
|
||||
onCoordinatesChange &&
|
||||
place.geometry.latitude &&
|
||||
place.geometry.longitude
|
||||
) {
|
||||
onCoordinatesChange(
|
||||
place.geometry.latitude,
|
||||
place.geometry.longitude
|
||||
);
|
||||
if (onCoordinatesChange) {
|
||||
onCoordinatesChange(parsedAddress.latitude, parsedAddress.longitude);
|
||||
}
|
||||
|
||||
// Clear any previous geocoding messages
|
||||
@@ -295,7 +163,7 @@ const LocationForm: React.FC<LocationFormProps> = ({
|
||||
setPlacesApiError(true);
|
||||
}
|
||||
},
|
||||
[onChange, onCoordinatesChange]
|
||||
[onChange, onCoordinatesChange, parsePlace]
|
||||
);
|
||||
|
||||
// Handle Places API errors
|
||||
|
||||
@@ -89,8 +89,8 @@ const Navbar: React.FC = () => {
|
||||
navigate("/");
|
||||
};
|
||||
|
||||
const handleSearch = (e: React.FormEvent) => {
|
||||
e.preventDefault();
|
||||
const handleSearch = (e?: React.FormEvent | React.MouseEvent) => {
|
||||
e?.preventDefault();
|
||||
const params = new URLSearchParams();
|
||||
|
||||
if (searchFilters.search.trim()) {
|
||||
@@ -142,7 +142,7 @@ const Navbar: React.FC = () => {
|
||||
<div className="collapse navbar-collapse" id="navbarNav">
|
||||
<div className="d-flex align-items-center w-100">
|
||||
<div className="position-absolute start-50 translate-middle-x">
|
||||
<form onSubmit={handleSearch}>
|
||||
<div>
|
||||
<div className="input-group" style={{ width: "520px" }}>
|
||||
<input
|
||||
type="text"
|
||||
@@ -152,6 +152,11 @@ const Navbar: React.FC = () => {
|
||||
onChange={(e) =>
|
||||
handleSearchInputChange("search", e.target.value)
|
||||
}
|
||||
onKeyDown={(e) => {
|
||||
if (e.key === "Enter") {
|
||||
handleSearch(e);
|
||||
}
|
||||
}}
|
||||
/>
|
||||
<span
|
||||
className="input-group-text text-muted"
|
||||
@@ -171,12 +176,21 @@ const Navbar: React.FC = () => {
|
||||
onChange={(e) =>
|
||||
handleSearchInputChange("location", e.target.value)
|
||||
}
|
||||
onKeyDown={(e) => {
|
||||
if (e.key === "Enter") {
|
||||
handleSearch(e);
|
||||
}
|
||||
}}
|
||||
/>
|
||||
<button className="btn btn-outline-secondary" type="submit">
|
||||
<button
|
||||
className="btn btn-outline-secondary"
|
||||
type="button"
|
||||
onClick={handleSearch}
|
||||
>
|
||||
<i className="bi bi-search"></i>
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
<div className="ms-auto d-flex align-items-center">
|
||||
<Link
|
||||
|
||||
Reference in New Issue
Block a user