diff --git a/src/components/nearle_components/AddressAutocomplete.js b/src/components/nearle_components/AddressAutocomplete.js index fa9d9f3..f68cee1 100644 --- a/src/components/nearle_components/AddressAutocomplete.js +++ b/src/components/nearle_components/AddressAutocomplete.js @@ -143,22 +143,45 @@ const buildParams = (query, bias) => { return params; }; +const searchOnce = async (query, bias) => { + const params = buildParams(query, bias); + params.set('limit', '1'); + const res = await fetchWithTimeout(`${NOMINATIM_SEARCH_URL}?${params.toString()}`, { headers: { Accept: 'application/json' } }); + if (!res.ok) return null; + const results = await res.json(); + return results?.length ? results[0] : null; +}; + // Standalone forward-geocode helper — replaces `Geocode.fromAddress(address)` // for call sites that resolve a plain text address without a predictions // dropdown (e.g. re-geocoding on submit). Returns a `toPlace`-shaped object, // or null if nothing matched. +// +// Unlike Google's geocoder, Nominatim only matches when every term in the +// query belongs to the same indexed record — it has no "closest approximate +// match" behaviour. A door number + unlisted micro-locality/street name (very +// common for Indian addresses, e.g. "60, Keezha Raman Puthoor, ...") makes +// the whole query match nothing, even though the city/postcode later in the +// string resolves fine on its own. So on a miss, retry with the leading +// (most specific, least likely to be indexed) comma-separated segments +// dropped one at a time until something matches — worst case this lands on +// just " ", an approximate pin instead of no pin at all. export async function geocodeAddress(address, { bias } = {}) { if (!address) return null; const plusCodeResult = await plusCodeToResult(address, bias); if (plusCodeResult) return toPlace(plusCodeResult); + const segments = address + .split(',') + .map((s) => s.trim()) + .filter(Boolean); + const queries = segments.length > 1 ? segments.map((_, i) => segments.slice(i).join(', ')) : [address]; try { - const params = buildParams(address, bias); - params.set('limit', '1'); - const res = await fetchWithTimeout(`${NOMINATIM_SEARCH_URL}?${params.toString()}`, { headers: { Accept: 'application/json' } }); - if (!res.ok) return null; - const results = await res.json(); - if (!results?.length) return null; - return toPlace(results[0]); + for (const query of queries) { + // eslint-disable-next-line no-await-in-loop + const result = await searchOnce(query, bias); + if (result) return toPlace(result); + } + return null; } catch (err) { console.error('geocodeAddress error:', err); return null; diff --git a/src/pages/nearle/clients/createCustomer.js b/src/pages/nearle/clients/createCustomer.js index bab9c94..1e6b370 100644 --- a/src/pages/nearle/clients/createCustomer.js +++ b/src/pages/nearle/clients/createCustomer.js @@ -53,6 +53,12 @@ const CreateCustomer = () => { const [inputValue2, setInputValue2] = useState(''); const [appLocaLat, setAppLocaLat] = useState(); const [appLocaLng, setAppLocaLng] = useState(); + // appLocaLat/appLocaLng load from a separate, independent API call that isn't + // guaranteed to finish before the address field becomes typable. Without them, + // the free-text geocoder's suggestions carry no geographic bias and return + // globally scattered, irrelevant matches for partial/as-you-type queries — so + // the address field stays disabled until a real bias point is available. + const isBiasReady = Number.isFinite(Number(appLocaLat)) && Number.isFinite(Number(appLocaLng)) && !(Number(appLocaLat) === 0 && Number(appLocaLng) === 0); const [locaName, setLocoName] = useState('Select Location'); const [locations, setLocations] = useState('Select Location'); const [tenantlist, setTenantlist] = useState([]); @@ -457,6 +463,8 @@ const CreateCustomer = () => { { const [appLocaLat, setAppLocaLat] = useState(); const [appLocaLng, setAppLocaLng] = useState(); const [appLocaRadius, setAppLocaRadius] = useState(); + // appLocaLat/appLocaLng load from a separate, independent API call (fetchTiming) + // that isn't guaranteed to finish before the address field becomes typable + // (isLocation, gated on tenant-location selection, resolves on its own timeline). + // Without them, the free-text geocoder's suggestions carry no geographic bias and + // return globally scattered, irrelevant matches for partial/as-you-type queries — + // so the address field stays disabled until a real bias point is available. + const isBiasReady = Number.isFinite(Number(appLocaLat)) && Number.isFinite(Number(appLocaLng)) && !(Number(appLocaLat) === 0 && Number(appLocaLng) === 0); const [isNumChange1, setIsNumChange1] = useState(0); const [isNumChange2, setIsNumChange2] = useState(0); const [showCheck1, setShowCheck1] = useState(0); @@ -484,8 +491,9 @@ const Createorder1 = () => { .get(`${process.env.REACT_APP_URL}/utils/getapplocations/?applocationid=${appId}`) .then((res) => { console.log('fetchTiming', res); - const { opentime, closetime, latitude, longitude, radius } = res.data.details[0]; - if (res.data.status) { + const details = res.data?.details?.[0]; + if (res.data.status && details) { + const { opentime, closetime, latitude, longitude, radius } = details; setAppLocaLat(latitude); setAppLocaLng(longitude); setAppLocaRadius(radius); @@ -1331,7 +1339,8 @@ const Createorder1 = () => {
{