diff --git a/.env b/.env index f97a712..a04f0dc 100644 --- a/.env +++ b/.env @@ -4,13 +4,10 @@ GENERATE_SOURCEMAP = false ## Backend API URL REACT_APP_API_URL=https://mock-data-api-nextjs.vercel.app/ -## Google Map Key - REACT_APP_URL=https://jupiter.nearle.app/live/api/v1 REACT_APP_URL2=https://jupiter.nearle.app/live/api/v2 REACT_APP_URL3=https://jupiter.nearle.app/live/api/v3 REACT_APP_STAFF_TOKEN= -REACT_APP_GOOGLE_MAPS_API_KEY=AIzaSyCF4KatYCI3vqz1_H3kiHeyS3yCMfYToh8 REACT_APP_RIDER_ACCESS_ID=AAAAILMpCEU:APA91bEavuOllBI6sFgYtxXAgNmAVwNA-MnCMHLGlR4_t7UqpLajAkdn3T0CZr_zaLBknLyim9ytFLMZgbeXmKqTad_PKCbqlYjHpaizVrLXtecxqyEy4UktIacK2UvHVUATHL-7VQQk diff --git a/.env.development b/.env.development index 972e18a..dd90009 100644 --- a/.env.development +++ b/.env.development @@ -2,7 +2,6 @@ REACT_APP_URL=https://jupiter.nearle.app/live/api/v1 REACT_APP_URL2=https://jupiter.nearle.app/live/api/v2 REACT_APP_URL3=https://jupiter.nearle.app/live/api/v3 REACT_APP_STAFF_TOKEN= -REACT_APP_GOOGLE_MAPS_API_KEY=AIzaSyCF4KatYCI3vqz1_H3kiHeyS3yCMfYToh8 REACT_APP_RIDER_ACCESS_ID=AAAAILMpCEU:APA91bEavuOllBI6sFgYtxXAgNmAVwNA-MnCMHLGlR4_t7UqpLajAkdn3T0CZr_zaLBknLyim9ytFLMZgbeXmKqTad_PKCbqlYjHpaizVrLXtecxqyEy4UktIacK2UvHVUATHL-7VQQk diff --git a/package.json b/package.json index f438d0e..22e1282 100644 --- a/package.json +++ b/package.json @@ -13,12 +13,10 @@ "@mui/lab": "^5.0.0-alpha.127", "@mui/material": "^5.12.1", "@mui/x-date-pickers": "^6.18.2", - "@react-google-maps/api": "^2.20.7", "@reduxjs/toolkit": "^1.9.5", "@svgr/webpack": "^7.0.0", "@tanstack/react-query": "^5.17.9", "antd": "^5.11.5", - "autosuggest-highlight": "^3.3.4", "axios": "^1.3.5", "buffer": "^6.0.3", "chance": "^1.1.11", @@ -45,8 +43,6 @@ "react-dnd": "^16.0.1", "react-dnd-html5-backend": "^16.0.1", "react-dom": "^18.2.0", - "react-geocode": "^0.2.3", - "react-google-autocomplete": "^2.7.3", "react-icons": "^4.12.0", "react-intl": "^6.4.1", "react-leaflet": "^4.2.1", diff --git a/src/components/nearle_components/AddressAutocomplete.js b/src/components/nearle_components/AddressAutocomplete.js new file mode 100644 index 0000000..3212de9 --- /dev/null +++ b/src/components/nearle_components/AddressAutocomplete.js @@ -0,0 +1,193 @@ +import React, { useEffect, useMemo, useState } from 'react'; + +import { Autocomplete, TextField, CircularProgress } from '@mui/material'; +import { debounce } from '@mui/material/utils'; + +// Free OSM Nominatim geocoder — replaces Google Places Autocomplete / +// react-geocode across the console. No API key required. Nominatim's usage +// policy caps the public endpoint at ~1 req/sec, so every caller here is +// debounced (500ms) and cancels stale in-flight predictions. +const NOMINATIM_SEARCH_URL = 'https://nominatim.openstreetmap.org/search'; + +// Builds a Google-Places-shaped `address_components` array (each entry +// `{ long_name, short_name, types: [] }`) from Nominatim's flat `address` +// object, so existing call sites' `place.address_components.forEach(...)` +// type-switch parsing keeps working unchanged. +const buildAddressComponents = (addr = {}) => { + const components = []; + const push = (longName, types) => { + if (longName) components.push({ long_name: longName, short_name: longName, types }); + }; + push(addr.house_number, ['street_number']); + push(addr.road || addr.pedestrian, ['route']); + push(addr.suburb || addr.neighbourhood || addr.quarter, ['sublocality_level_1', 'sublocality']); + push(addr.city_district || addr.county, ['administrative_area_level_3']); + push(addr.city || addr.town || addr.village, ['locality']); + push(addr.state, ['administrative_area_level_1']); + push(addr.country, ['country']); + push(addr.postcode, ['postal_code']); + return components; +}; + +// Shapes a Nominatim result close enough to a Google Places `place` object +// (formatted_address, geometry.location.lat()/lng(), address_components) +// that call sites need only mechanical edits, not rewrites. +export const toPlace = (result) => ({ + formatted_address: result.display_name, + name: result.display_name?.split(',')[0] || '', + geometry: { + location: { + lat: () => parseFloat(result.lat), + lng: () => parseFloat(result.lon) + } + }, + address_components: buildAddressComponents(result.address) +}); + +const buildParams = (query, bias) => { + const params = new URLSearchParams({ q: query, format: 'json', addressdetails: '1', limit: '5' }); + if (bias?.lat && bias?.lng) { + const d = 0.5; // ~55km box around the operator's zone — soft bias, not a hard filter + params.set('viewbox', `${bias.lng - d},${bias.lat + d},${bias.lng + d},${bias.lat - d}`); + } + return params; +}; + +// 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. +export async function geocodeAddress(address, { bias } = {}) { + if (!address) return null; + try { + const params = buildParams(address, bias); + params.set('limit', '1'); + const res = await fetch(`${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]); + } catch (err) { + console.error('geocodeAddress error:', err); + return null; + } +} + +// Address search-as-you-type — replaces Google Places Autocomplete +// (usePlacesWidget / window.google.maps.places.Autocomplete / +// AutocompleteService) across the console. Renders as an MUI Autocomplete +// with freeSolo so the operator can still submit free text. +// +// Props: +// value / onChange(text) — controlled free-text input value +// onPlaceSelected(place) — fired when a suggestion is chosen; `place` +// is shaped like a Google Places `place` +// bias { lat, lng } — optional soft bias toward the operator's zone +const AddressAutocomplete = ({ + id, + label, + placeholder = 'Search address', + value, + onChange, + onPlaceSelected, + bias, + sx, + textFieldSx, + fullWidth = true, + disabled, + inputRef, + TextFieldProps = {} +}) => { + const [inputValue, setInputValue] = useState(value || ''); + const [options, setOptions] = useState([]); + const [loading, setLoading] = useState(false); + + useEffect(() => { + if (value !== undefined && value !== inputValue) setInputValue(value || ''); + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [value]); + + const fetchPredictions = useMemo( + () => + debounce((query, bias1, callback) => { + if (!query) { + callback([]); + return; + } + const params = buildParams(query, bias1); + fetch(`${NOMINATIM_SEARCH_URL}?${params.toString()}`, { headers: { Accept: 'application/json' } }) + .then((res) => (res.ok ? res.json() : [])) + .then((results) => callback(results || [])) + .catch(() => callback([])); + }, 500), + [] + ); + + useEffect(() => { + let active = true; + if (!inputValue) { + setOptions([]); + setLoading(false); + return undefined; + } + setLoading(true); + fetchPredictions(inputValue, bias, (results) => { + if (!active) return; + setLoading(false); + setOptions(results); + }); + return () => { + active = false; + }; + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [inputValue, bias?.lat, bias?.lng, fetchPredictions]); + + return ( + x} + getOptionLabel={(option) => (typeof option === 'string' ? option : option.display_name || '')} + isOptionEqualToValue={(option, val) => option.place_id === val?.place_id} + inputValue={inputValue} + onInputChange={(event, newInputValue) => { + setInputValue(newInputValue); + onChange?.(newInputValue); + }} + onChange={(event, selected) => { + if (selected && typeof selected !== 'string') { + setInputValue(selected.display_name || ''); + onPlaceSelected?.(toPlace(selected)); + } + }} + renderInput={(params) => ( + + {loading ? : null} + {TextFieldProps.InputProps?.endAdornment ?? params.InputProps.endAdornment} + + ) + }} + /> + )} + /> + ); +}; + +export default AddressAutocomplete; diff --git a/src/pages/nearle/clients/Tenants.js b/src/pages/nearle/clients/Tenants.js index b9bd26d..e953eac 100644 --- a/src/pages/nearle/clients/Tenants.js +++ b/src/pages/nearle/clients/Tenants.js @@ -1,4 +1,4 @@ -import React, { useEffect, useState, useRef, useMemo, Fragment } from 'react'; +import React, { useEffect, useState, useRef, Fragment } from 'react'; import MainCard from 'components/MainCard'; import axios from 'axios'; import { useTheme } from '@mui/material/styles'; @@ -6,10 +6,7 @@ import Loader from 'components/Loader'; import { Empty } from 'antd'; import dayjs from 'dayjs'; import { enqueueSnackbar } from 'notistack'; -import Geocode from 'react-geocode'; -import LocationOnIcon from '@mui/icons-material/LocationOn'; -import parse from 'autosuggest-highlight/parse'; -import { debounce } from '@mui/material/utils'; +import AddressAutocomplete from 'components/nearle_components/AddressAutocomplete'; import { Stack, Table, @@ -184,7 +181,6 @@ const Clients1 = () => { const [appId, setAppId] = useState(0); const [locaName, setLocoName] = useState(''); const [locations] = useState('All'); - const [value, setValue] = React.useState(null); const [value0, setValue0] = useState(0); const [value1, setValue1] = useState(0); const [value2, setValue2] = useState(0); @@ -196,7 +192,6 @@ const Clients1 = () => { const [appPricing, setAppPricing] = useState([]); const [selectedPricing, setSelectedPricing] = useState({}); const [isPrice, setIsprice] = useState(true); - const [address, setAddress] = useState(''); const [city, setCity] = useState(''); const [zipcode, setZipcode] = useState(''); const [latlong, setLatlong] = useState({}); @@ -258,144 +253,50 @@ const Clients1 = () => { autoHideDuration: duration }); }; - // ==============================|| google address ||============================== // - const GOOGLE_MAPS_API_KEY = process.env.REACT_APP_GOOGLE_MAPS_API_KEY; + // ==============================|| address autocomplete ||============================== // + const handleAddressPlaceSelected = (place) => { + const lat = place.geometry.location.lat(); + const lng = place.geometry.location.lng(); + setLatlong({ lat, lng }); + setEditClient((prev) => ({ + ...prev, + address: place.formatted_address, + latitude: lat.toString(), + longitude: lng.toString() + })); - function loadScript(src, position, id) { - if (!position) { - return; - } - - const script = document.createElement('script'); - script.setAttribute('async', ''); - script.setAttribute('id', id); - script.src = src; - position.appendChild(script); - } - - const autocompleteService = { current: null }; - // ==============================|| for google address ||============================== // - const [inputValue, setInputValue] = useState(''); - const [options, setOptions] = useState([]); - const loaded = useRef(false); - if (typeof window !== 'undefined' && !loaded.current) { - if (!document.querySelector('#google-maps')) { - loadScript( - `https://maps.googleapis.com/maps/api/js?key=${GOOGLE_MAPS_API_KEY}&libraries=places`, - document.querySelector('head'), - 'google-maps' - ); - } - - loaded.current = true; - } - - const fetch = useMemo( - () => - debounce((request, callback) => { - autocompleteService.current.getPlacePredictions(request, callback); - }, 400), - [] - ); - useEffect(() => { - let active = true; - if (!autocompleteService.current && window.google) { - autocompleteService.current = new window.google.maps.places.AutocompleteService(); - } - if (!autocompleteService.current) { - return undefined; - } - - if (inputValue === '') { - setOptions(value ? [value] : []); - return undefined; - } - fetch({ input: inputValue }, (results) => { - if (active) { - let newOptions = []; - - if (value) { - newOptions = [value]; + let city1, zipcode1, state1, suburb1; + place.address_components.forEach((component) => { + component.types.forEach((type) => { + switch (type) { + case 'locality': + city1 = component.long_name; + break; + case 'administrative_area_level_1': + state1 = component.long_name; + break; + case 'postal_code': + zipcode1 = component.long_name; + break; + case 'sublocality': + case 'sublocality_level_1': + suburb1 = component.long_name; + break; } - - if (results) { - newOptions = [...newOptions, ...results]; - } - setOptions(newOptions); - } + }); }); - - return () => { - active = false; - }; - }, [value, inputValue, fetch]); - - Geocode.setApiKey(process.env.REACT_APP_GOOGLE_MAPS_API_KEY); - useEffect(() => { - try { - console.log('selected address =>', address); - Geocode.fromAddress(address).then( - (response) => { - console.log('lat long response =>', response.results[0]); - if (response.status == 'OK') { - const { lat, lng } = response.results[0].geometry.location; - setLatlong({ - lat, - lng - }); - setEditClient({ - ...editClient, - latitude: lat.toString(), - longitude: lng.toString() - }); - // setSelectedCustomer({ - // ...selectedCustomer, - // latitude: lat, - // longitude: lng, - // }); - if (response.results[0].address_components) { - let place = response.results[0]; - let city1, zipcode1, state1, suburb1; - for (let i = 0; i < place.address_components.length; i++) { - for (let j = 0; j < place.address_components[i].types.length; j++) { - switch (place.address_components[i].types[j]) { - case 'locality': - city1 = place.address_components[i].long_name; - break; - case 'administrative_area_level_1': - state1 = place.address_components[i].long_name; - break; - case 'postal_code': - zipcode1 = place.address_components[i].long_name; - break; - case 'sublocality': - suburb1 = place.address_components[i].long_name; - break; - } - } - } - setCity(city1 || ''); - setState(state1 || ''); - setZipcode(zipcode1 || ''); - setSuburb(suburb1 || ''); - setEditClient({ - ...editClient, - city: city1 || '', - state: state1 || '', - postcode: zipcode || '', - suburb: suburb1 || '' - }); - } - } - }, - (error) => { - console.log(error); - } - ); - } catch (err) { - console.log(err); - } - }, [address]); + setCity(city1 || ''); + setState(state1 || ''); + setZipcode(zipcode1 || ''); + setSuburb(suburb1 || ''); + setEditClient((prev) => ({ + ...prev, + city: city1 || '', + state: state1 || '', + postcode: zipcode1 || '', + suburb: suburb1 || '' + })); + }; useEffect(() => { selectedCustomer && @@ -1562,85 +1463,19 @@ const Clients1 = () => { /> - (typeof option === 'string' ? option : option.description)} - filterOptions={(x) => x} - options={options} - autoComplete - includeInputInList - filterSelectedOptions - defaultValue={selectedCustomer.address} - noOptionsText="No locations" - onChange={(event, newValue) => { - setOptions(newValue ? [newValue, ...options] : options); - setValue(newValue || ''); - console.log('newValue', newValue); - setAddress(newValue?.description || ''); - setEditClient({ - ...editClient, - address: newValue?.description || '' - }); - }} - onInputChange={(event, newInputValue) => { - setInputValue(newInputValue); - }} - renderInput={(params) => ( - - )} - renderOption={(props, option) => { - const matches = option.structured_formatting.main_text_matched_substrings || []; - - const parts = parse( - option.structured_formatting.main_text, - matches.map((match) => [match.offset, match.offset + match.length]) - ); - - return ( -
  • - - - - - - {parts.map((part, index) => ( - - {part.text} - - ))} - - {option.structured_formatting.secondary_text} - - - -
  • - ); - }} + label="Address" + value={editClient?.address ?? selectedCustomer.address ?? ''} + onChange={(text) => + setEditClient((prev) => ({ + ...prev, + address: text + })) + } + onPlaceSelected={handleAddressPlaceSelected} + TextFieldProps={{ variant: 'outlined' }} />
    diff --git a/src/pages/nearle/clients/createCustomer.js b/src/pages/nearle/clients/createCustomer.js index a997b54..0fa8cdc 100644 --- a/src/pages/nearle/clients/createCustomer.js +++ b/src/pages/nearle/clients/createCustomer.js @@ -4,7 +4,7 @@ import { Button, Grid, InputLabel, MenuItem, Select, Stack, TextField, Typograph import MainCard from 'components/MainCard'; import axios from 'axios'; import Loader from 'components/Loader'; -import Geocode from 'react-geocode'; +import AddressAutocomplete from 'components/nearle_components/AddressAutocomplete'; import { enqueueSnackbar } from 'notistack'; import { useNavigate } from 'react-router'; import CloseIcon from '@mui/icons-material/Close'; @@ -25,7 +25,6 @@ const CreateCustomer = () => { const [inputValue2, setInputValue2] = useState(''); const [appLocaLat, setAppLocaLat] = useState(); const [appLocaLng, setAppLocaLng] = useState(); - const [appLocaRadius, setAppLocaRadius] = useState(); const [locaName, setLocoName] = useState('Select Location'); const [tenantlist, setTenantlist] = useState([]); const [tid, setTid] = useState(0); @@ -34,92 +33,68 @@ const CreateCustomer = () => { const [loading, setLoading] = useState(false); const navigate = useNavigate(); - Geocode.setApiKey(process.env.REACT_APP_GOOGLE_MAPS_API_KEY); - - useEffect(() => { - // Initialize Google Maps Autocomplete - if (inputValue2) { - const autocompleteInput = document.getElementById('addressAuto1'); - const autocomplete = new window.google.maps.places.Autocomplete(autocompleteInput, { - // types: ['(cities)'], // You can adjust the types parameter based on your requirements - strictBounds: true, - bounds: new window.google.maps.Circle({ - // center: new window.google.maps.LatLng(11.0050707, 76.9509083), - // radius: 100000 - center: new window.google.maps.LatLng(appLocaLat, appLocaLng), - - radius: appLocaRadius * 1000 - }).getBounds() + const handlePlaceSelected = (place) => { + setInputValue2(`${place.name}, ${place.formatted_address}`); + // to trigger getDistance + setStartPoint({ latitude: place.geometry.location.lat(), longitude: place.geometry.location.lng() }); + setAddress(`${place.name} ${place.formatted_address}`); + setPickCust({ ...pickCust, address: `${place.name} ${place.formatted_address}` }); + const address = { + address: `${place.name} ${place.formatted_address}`, + street_number: '', + route: '', + locality: '', + sublocality_level_1: '', + administrative_area_level_3: '', + administrative_area_level_1: '', + country: '', + postal_code: '' + }; + place.address_components.forEach((component) => { + component.types.forEach((type) => { + switch (type) { + case 'street_number': + address.street_number = component.long_name; + break; + case 'route': + address.route = component.long_name; + break; + case 'locality': + address.locality = component.long_name; + break; + case 'sublocality_level_1': + address.sublocality_level_1 = component.long_name; + break; + case 'administrative_area_level_3': + address.administrative_area_level_3 = component.long_name; + break; + case 'administrative_area_level_1': + address.administrative_area_level_1 = component.long_name; + break; + case 'country': + address.country = component.long_name; + break; + case 'postal_code': + address.postal_code = component.long_name; + break; + // Add more cases as needed for other types + } }); - // Event listener for autocomplete place changed - autocomplete.addListener('place_changed', () => { - const place = autocomplete.getPlace(); - setInputValue2(`${place.name}, ${place.formatted_address}`); - console.log('new place', place); // Do something with the selected place - console.log(' pick (new place) lat lng', { lat: place.geometry.location.lat(), lng: place.geometry.location.lng() }); // Do something with the selected place - // to trigger getDistance - setStartPoint({ latitude: place.geometry.location.lat(), longitude: place.geometry.location.lng() }); - setAddress(`${place.name} ${place.formatted_address}`); - setPickCust({ ...pickCust, address: `${place.name} ${place.formatted_address}` }); - const address = { - address: `${place.name} ${place.formatted_address}`, - street_number: '', - route: '', - locality: '', - sublocality_level_1: '', - administrative_area_level_3: '', - administrative_area_level_1: '', - country: '', - postal_code: '' - }; - place.address_components.forEach((component) => { - component.types.forEach((type) => { - switch (type) { - case 'street_number': - address.street_number = component.long_name; - break; - case 'route': - address.route = component.long_name; - break; - case 'locality': - address.locality = component.long_name; - break; - case 'sublocality_level_1': - address.sublocality_level_1 = component.long_name; - break; - case 'administrative_area_level_3': - address.administrative_area_level_3 = component.long_name; - break; - case 'administrative_area_level_1': - address.administrative_area_level_1 = component.long_name; - break; - case 'country': - address.country = component.long_name; - break; - case 'postal_code': - address.postal_code = component.long_name; - break; - // Add more cases as needed for other types - } - }); - }); + }); - // Use address object as per your requirements - setPickCust({ - ...pickCust, - address: address.address, - doorno: `${address.street_number} ${address.route}`, - suburb: address.administrative_area_level_3, - city: address.locality, - state: address.administrative_area_level_1, - postcode: address.postal_code, - latitude: place.geometry.location.lat(), - longitude: place.geometry.location.lng() - }); - console.log('Pick Address:', address); - }); - } - }, [inputValue2]); + // Use address object as per your requirements + setPickCust({ + ...pickCust, + address: address.address, + doorno: `${address.street_number} ${address.route}`, + suburb: address.administrative_area_level_3, + city: address.locality, + state: address.administrative_area_level_1, + postcode: address.postal_code, + latitude: place.geometry.location.lat(), + longitude: place.geometry.location.lng() + }); + }; // ==================================================== || getapplocations || ==================================================== const getapplocations = async () => { setLoading(true); @@ -127,12 +102,10 @@ const CreateCustomer = () => { .get(`${process.env.REACT_APP_URL}/utils/getapplocations/?applocationid=${appId}`) .then((res) => { console.log('getapplocations', res); - const { latitude, longitude, radius } = res.data.details[0]; + const { latitude, longitude } = res.data.details[0]; if (res.data.status) { setAppLocaLat(latitude); setAppLocaLng(longitude); - setAppLocaRadius(radius); - console.log('radius', radius); } setLoading(false); }) @@ -380,38 +353,42 @@ const CreateCustomer = () => { Address - { + onChange={(text) => { if (appId) { - appId && setInputValue2(e.target.value); + setInputValue2(text); } else { OpenToast('Select Location First', 'warning', 3000); } }} - InputProps={{ - endAdornment: ( - { - setInputValue2(''); - setPickCust({ - ...pickCust, - doorno: '', - suburb: '', - city: '', - postcode: '', - landmark: '' - }); - setStartPoint({ latitude: 0, longitude: 0 }); - }} - size="small" - > - - - ) + onPlaceSelected={handlePlaceSelected} + bias={{ lat: appLocaLat, lng: appLocaLng }} + TextFieldProps={{ + variant: 'outlined', + InputProps: { + endAdornment: ( + { + setInputValue2(''); + setPickCust({ + ...pickCust, + doorno: '', + suburb: '', + city: '', + postcode: '', + landmark: '' + }); + setStartPoint({ latitude: 0, longitude: 0 }); + }} + size="small" + > + + + ) + } }} /> diff --git a/src/pages/nearle/clients/createclient.js b/src/pages/nearle/clients/createclient.js index e44eb07..8d1922c 100644 --- a/src/pages/nearle/clients/createclient.js +++ b/src/pages/nearle/clients/createclient.js @@ -10,12 +10,10 @@ import { Box, Button, FormLabel, Grid, InputLabel, MenuItem, Select, Stack, Text // project import import MainCard from 'components/MainCard'; import axios from 'axios'; -import { usePlacesWidget } from 'react-google-autocomplete'; +import AddressAutocomplete, { geocodeAddress } from 'components/nearle_components/AddressAutocomplete'; import Loader from 'components/Loader'; -import Geocode from 'react-geocode'; import { enqueueSnackbar } from 'notistack'; import { useNavigate } from 'react-router'; -// import { setLocationType } from 'react-geocode'; // const avatarImage = require.context('assets/images/users', true); @@ -49,9 +47,6 @@ const Createclient = () => { const navigate = useNavigate(); - Geocode.setApiKey(process.env.REACT_APP_GOOGLE_MAPS_API_KEY); - // Geocode.setApiKey('AIzaSyCF4KatYCI3vqz1_H3kiHeyS3yCMfYToh8'); - const [loading, setLoading] = useState(false); useEffect(() => { @@ -63,25 +58,15 @@ const Createclient = () => { }, []); useEffect(() => { - try { - Geocode.fromAddress(address).then( - (response) => { - if (response.status == 'OK') { - const { lat, lng } = response.results[0].geometry.location; - setLatlong({ - lat, - lng - }); - console.log(response); - } - }, - (error) => { - console.log(error); - } - ); - } catch (err) { - console.log(err); - } + let active = true; + geocodeAddress(address).then((place) => { + if (active && place) { + setLatlong({ lat: place.geometry.location.lat(), lng: place.geometry.location.lng() }); + } + }); + return () => { + active = false; + }; }, [address]); const opentoast = (message) => { @@ -151,45 +136,33 @@ const Createclient = () => { } }, [selectedImage]); - const { ref: materialRef } = usePlacesWidget({ - apiKey: process.env.REACT_APP_GOOGLE_MAPS_API_KEY, - onPlaceSelected: (place) => { - console.log(place); - - setAddress(place.formatted_address); - let city1, zipcode1, state1, suburb1; - for (let i = 0; i < place.address_components.length; i++) { - for (let j = 0; j < place.address_components[i].types.length; j++) { - switch (place.address_components[i].types[j]) { - case 'locality': - city1 = place.address_components[i].long_name; - break; - case 'administrative_area_level_1': - state1 = place.address_components[i].long_name; - break; - case 'postal_code': - zipcode1 = place.address_components[i].long_name; - break; - case 'sublocality': - suburb1 = place.address_components[i].long_name; - break; - } + const handleAddressPlaceSelected = (place) => { + setAddress(place.formatted_address); + let city1, zipcode1, state1, suburb1; + for (let i = 0; i < place.address_components.length; i++) { + for (let j = 0; j < place.address_components[i].types.length; j++) { + switch (place.address_components[i].types[j]) { + case 'locality': + city1 = place.address_components[i].long_name; + break; + case 'administrative_area_level_1': + state1 = place.address_components[i].long_name; + break; + case 'postal_code': + zipcode1 = place.address_components[i].long_name; + break; + case 'sublocality': + case 'sublocality_level_1': + suburb1 = place.address_components[i].long_name; + break; } } - setCity(city1 || ''); - setState(state1 || ''); - setZipcode(zipcode1 || ''); - setSuburb(suburb1 || ''); - - // setAddress(place.formatted_address) - }, - // inputAutocompleteValue: "country", - options: { - // componentRestrictions: 'us', - // types: ["establishment"] - types: ['address' || 'geocode'] } - }); + setCity(city1 || ''); + setState(state1 || ''); + setZipcode(zipcode1 || ''); + setSuburb(suburb1 || ''); + }; const createprofile = async () => { console.log('res', businessname, businessno, mobilenumber, emailaddress, address, city, zipcode); @@ -486,14 +459,13 @@ const Createclient = () => { Address - setAddress(e.target.value)} - inputRef={materialRef} + onChange={setAddress} + onPlaceSelected={handleAddressPlaceSelected} /> diff --git a/src/pages/nearle/customers/customers.js b/src/pages/nearle/customers/customers.js index fa57360..df215cb 100644 --- a/src/pages/nearle/customers/customers.js +++ b/src/pages/nearle/customers/customers.js @@ -1,4 +1,4 @@ -import { React, useState, useEffect, useRef, useMemo } from 'react'; +import { React, useState, useEffect, useRef } from 'react'; import axios from 'axios'; import { FaRegEdit } from 'react-icons/fa'; import LoaderWithImage from 'components/nearle_components/LoaderWithImage'; @@ -23,7 +23,6 @@ import { DialogContent, Button, TextField, - Autocomplete, Avatar, Paper, useMediaQuery, @@ -42,12 +41,9 @@ import { MdOutlineHowToReg, MdOutlinePlace } from 'react-icons/md'; -import Geocode from 'react-geocode'; -import LocationOnIcon from '@mui/icons-material/LocationOn'; -import parse from 'autosuggest-highlight/parse'; -import { debounce } from '@mui/material/utils'; // project imports import Loader from 'components/Loader'; +import AddressAutocomplete from 'components/nearle_components/AddressAutocomplete'; import DebounceSearchBar from 'components/nearle_components/DebounceSearchBar'; import LocationAutocomplete from 'components/nearle_components/LocationAutocomplete'; import PageHeader from 'components/nearle_components/PageHeader'; @@ -111,23 +107,6 @@ const AccentAvatar = ({ color, selected, size = 24, children }) => ( ); -// ==============================|| google address ||============================== // -const GOOGLE_MAPS_API_KEY = process.env.REACT_APP_GOOGLE_MAPS_API_KEY; - -function loadScript(src, position, id) { - if (!position) { - return; - } - - const script = document.createElement('script'); - script.setAttribute('async', ''); - script.setAttribute('id', id); - script.src = src; - position.appendChild(script); -} - -const autocompleteService = { current: null }; - // ==============================|| MUI TABLE - ENHANCED ||============================== // export default function Customers() { @@ -141,7 +120,6 @@ export default function Customers() { const [locaName, setLocoName] = useState('All'); const [selectedCustomer, setSelectedCustomer] = useState({}); // to edit const [open, setOpen] = useState(false); - const [address, setAddress] = useState(''); const [latlong, setLatlong] = useState({}); const [city, setCity] = useState(''); const [postcode, setPostcode] = useState(''); @@ -150,136 +128,47 @@ export default function Customers() { const [searchword, setSearchword] = useState(''); const [debouncedSearch, setDebouncedSearch] = useState(''); - // ==============================|| for google address ||============================== // - const [value, setValue] = useState(null); - const [inputValue, setInputValue] = useState(''); - const [options, setOptions] = useState([]); - const loaded = useRef(false); - if (typeof window !== 'undefined' && !loaded.current) { - if (!document.querySelector('#google-maps')) { - loadScript( - `https://maps.googleapis.com/maps/api/js?key=${GOOGLE_MAPS_API_KEY}&libraries=places`, - document.querySelector('head'), - 'google-maps' - ); - } + // ==============================|| address autocomplete ||============================== // + const handleAddressPlaceSelected = (place) => { + const lat = place.geometry.location.lat(); + const lng = place.geometry.location.lng(); + setLatlong({ lat, lng }); - loaded.current = true; - } - const fetch = useMemo( - () => - debounce((request, callback) => { - autocompleteService.current.getPlacePredictions(request, callback); - }, 400), - [] - ); - useEffect(() => { - let active = true; - - if (!autocompleteService.current && window.google) { - autocompleteService.current = new window.google.maps.places.AutocompleteService(); - } - if (!autocompleteService.current) { - return undefined; - } - - if (inputValue === '') { - setOptions(value ? [value] : []); - return undefined; - } - - fetch({ input: inputValue }, (results) => { - if (active) { - let newOptions = []; - - if (value) { - newOptions = [value]; + let city1, zipcode1, state1, suburb1; + place.address_components.forEach((component) => { + component.types.forEach((type) => { + switch (type) { + case 'locality': + city1 = component.long_name; + break; + case 'administrative_area_level_1': + state1 = component.long_name; + break; + case 'postal_code': + zipcode1 = component.long_name; + break; + case 'sublocality': + case 'sublocality_level_1': + suburb1 = component.long_name; + break; } - - if (results) { - newOptions = [...newOptions, ...results]; - } - - setOptions(newOptions); - } + }); }); - - return () => { - active = false; - }; - }, [value, inputValue, fetch]); - - Geocode.setApiKey(process.env.REACT_APP_GOOGLE_MAPS_API_KEY); - useEffect(() => { - try { - console.log('selected address =>', address); - Geocode.fromAddress(address).then( - (response) => { - console.log('lat long response =>', response.results[0]); - if (response.status == 'OK') { - const { lat, lng } = response.results[0].geometry.location; - setLatlong({ - lat, - lng - }); - // setSelectedCustomer({ - // ...selectedCustomer, - // latitude: lat, - // longitude: lng - // }); - if (response.results[0].address_components) { - let place = response.results[0]; - let city1, zipcode1, state1, suburb1; - for (let i = 0; i < place.address_components.length; i++) { - for (let j = 0; j < place.address_components[i].types.length; j++) { - switch (place.address_components[i].types[j]) { - case 'locality': - city1 = place.address_components[i].long_name; - break; - case 'administrative_area_level_1': - state1 = place.address_components[i].long_name; - break; - case 'postal_code': - zipcode1 = place.address_components[i].long_name; - break; - case 'sublocality': - suburb1 = place.address_components[i].long_name; - break; - } - } - } - setCity(city1 || ''); - setState(state1 || ''); - setPostcode(zipcode1 || ''); - setSuburb(suburb1 || ''); - setSelectedCustomer((prev) => ({ - ...prev, - city: city1 || '', - state: state1 || '', - postcode: zipcode1 || '', - suburb: suburb1 || '', - latitude: lat || '', - longitude: lng || '' - })); - } - } - }, - (error) => { - console.log(error); - } - ); - } catch (err) { - console.log(err); - } - }, [address]); - - // useEffect(() => { - // selectedCustomer && - // setLatlong({ - // lat: selectedCustomer.latitude, - // lng: selectedCustomer.longitude - // }); - // }, [selectedCustomer]); + setCity(city1 || ''); + setState(state1 || ''); + setPostcode(zipcode1 || ''); + setSuburb(suburb1 || ''); + setSelectedCustomer((prev) => ({ + ...prev, + address: place.formatted_address, + city: city1 || '', + state: state1 || '', + postcode: zipcode1 || '', + suburb: suburb1 || '', + latitude: lat || '', + longitude: lng || '' + })); + }; // ==============================|| getallcustomers (customers) ||============================== // @@ -891,72 +780,17 @@ export default function Customers() { Address - (typeof option === 'string' ? option : option?.description || '')} - filterOptions={(x) => x} - options={options} - autoComplete - includeInputInList - filterSelectedOptions - value={selectedCustomer?.address} - noOptionsText="No locations" - onChange={(event, newValue) => { - setOptions(newValue ? [newValue, ...options] : options); - setValue(newValue); - console.log('newValue', newValue || ''); - setAddress(newValue?.description); - setSelectedCustomer({ - ...selectedCustomer, - address: newValue?.description - }); - }} - onInputChange={(event, newInputValue) => { - setInputValue(newInputValue); - }} - renderInput={(params) => } - renderOption={(props, option) => { - const matches = option.structured_formatting.main_text_matched_substrings || []; - - const parts = parse( - option.structured_formatting.main_text, - matches.map((match) => [match.offset, match.offset + match.length]) - ); - - return ( -
  • - - - - - - {parts?.map((part, index) => ( - - {part.text} - - ))} - - {option?.structured_formatting.secondary_text} - - - -
  • - ); - }} + value={selectedCustomer?.address || ''} + onChange={(text) => + setSelectedCustomer((prev) => ({ + ...prev, + address: text + })) + } + onPlaceSelected={handleAddressPlaceSelected} />
    diff --git a/src/pages/nearle/orders/createorder1.js b/src/pages/nearle/orders/createorder1.js index 0e0e7eb..fd52db6 100644 --- a/src/pages/nearle/orders/createorder1.js +++ b/src/pages/nearle/orders/createorder1.js @@ -37,7 +37,7 @@ import { TbMapPinCode } from 'react-icons/tb'; import { FaLocationDot } from 'react-icons/fa6'; import axios from 'axios'; import { useTheme } from '@mui/material/styles'; -import Geocode from 'react-geocode'; +import AddressAutocomplete from 'components/nearle_components/AddressAutocomplete'; import Loader from 'components/Loader'; import * as geolib from 'geolib'; import MainCard from 'components/MainCard'; @@ -169,22 +169,7 @@ const OrderMap = ({ startPoint, endPoint, appLocaLat, appLocaLng }) => { ); }; -function loadScript(src, position, id) { - if (!position) { - return; - } - - const script = document.createElement('script'); - script.setAttribute('async', ''); - script.setAttribute('id', id); - script.src = src; - position.appendChild(script); -} - const Createorder1 = () => { - Geocode.setApiKey(process.env.REACT_APP_GOOGLE_MAPS_API_KEY); - // ================================================= || GoogleMaps (Drawer) || ================================================= - const loaded = React.useRef(false); const navigate = useNavigate(); const theme = useTheme(); const isMobile = useMediaQuery(theme.breakpoints.down('md')); @@ -275,17 +260,6 @@ const Createorder1 = () => { console.log('pickupSlot', pickupSlot); }, [pickupSlotsList, pickupSlot]); - if (typeof window !== 'undefined' && !loaded.current) { - if (!document.querySelector('#google-maps')) { - loadScript( - `https://maps.googleapis.com/maps/api/js?key=${process.env.REACT_APP_GOOGLE_MAPS_API_KEY}&libraries=places&location=10.3656,77.9690&radius=50000&components=country:IN&strictbounds=true`, - document.querySelector('head'), - 'google-maps' - ); - } - loaded.current = true; - } - // ==============================|| fetchAppLocations ||============================== // const fetchAppLocations = async () => { try { @@ -760,173 +734,129 @@ const Createorder1 = () => { setLoading(false); }); }; - // ============================================= || Google Maps Autocomplete(pick) || ============================================= - useEffect(() => { - // Initialize Google Maps Autocomplete - if (inputValue1) { - const autocompleteInput = document.getElementById('addressAuto1'); - const autocomplete = new window.google.maps.places.Autocomplete(autocompleteInput, { - // types: ['(cities)'], // You can adjust the types parameter based on your requirements - strictBounds: true, - bounds: new window.google.maps.Circle({ - // center: new window.google.maps.LatLng(11.0050707, 76.9509083), - // radius: 100000 - center: new window.google.maps.LatLng(appLocaLat, appLocaLng), - radius: appLocaRadius * 1000 - }).getBounds() + // ============================================= || Address Autocomplete (pick) || ============================================= + const handlePickPlaceSelected = (place) => { + setInputValue1(`${place.name}, ${place.formatted_address}`); + // to trigger getDistance + setStartPoint({ latitude: place.geometry.location.lat(), longitude: place.geometry.location.lng() }); + setPickCust({ ...pickCust, address: `${place.name} ${place.formatted_address}` }); + const address = { + address: `${place.name} ${place.formatted_address}`, + street_number: '', + route: '', + locality: '', + sublocality_level_1: '', + administrative_area_level_3: '', + administrative_area_level_1: '', + country: '', + postal_code: '' + }; + place.address_components.forEach((component) => { + component.types.forEach((type) => { + switch (type) { + case 'street_number': + address.street_number = component.long_name; + break; + case 'route': + address.route = component.long_name; + break; + case 'locality': + address.locality = component.long_name; + break; + case 'sublocality_level_1': + address.sublocality_level_1 = component.long_name; + break; + case 'administrative_area_level_3': + address.administrative_area_level_3 = component.long_name; + break; + case 'administrative_area_level_1': + address.administrative_area_level_1 = component.long_name; + break; + case 'country': + address.country = component.long_name; + break; + case 'postal_code': + address.postal_code = component.long_name; + break; + // Add more cases as needed for other types + } }); + }); - // Event listener for autocomplete place changed - autocomplete.addListener('place_changed', () => { - const place = autocomplete.getPlace(); - setInputValue1(`${place.name}, ${place.formatted_address}`); - console.log('new place', place); // Do something with the selected place - console.log(' pick (new place) lat lng', { lat: place.geometry.location.lat(), lng: place.geometry.location.lng() }); // Do something with the selected place - // to trigger getDistance - setStartPoint({ latitude: place.geometry.location.lat(), longitude: place.geometry.location.lng() }); - setPickCust({ ...pickCust, address: `${place.name} ${place.formatted_address}` }); - const address = { - address: `${place.name} ${place.formatted_address}`, - street_number: '', - route: '', - locality: '', - sublocality_level_1: '', - administrative_area_level_3: '', - administrative_area_level_1: '', - country: '', - postal_code: '' - }; - place.address_components.forEach((component) => { - component.types.forEach((type) => { - switch (type) { - case 'street_number': - address.street_number = component.long_name; - break; - case 'route': - address.route = component.long_name; - break; - case 'locality': - address.locality = component.long_name; - break; - case 'sublocality_level_1': - address.sublocality_level_1 = component.long_name; - break; - case 'administrative_area_level_3': - address.administrative_area_level_3 = component.long_name; - break; - case 'administrative_area_level_1': - address.administrative_area_level_1 = component.long_name; - break; - case 'country': - address.country = component.long_name; - break; - case 'postal_code': - address.postal_code = component.long_name; - break; - // Add more cases as needed for other types - } - }); - }); + // Use address object as per your requirements + setPickCust({ + ...pickCust, + address: address.address, + doorno: `${address.street_number} ${address.route}`, + suburb: address.sublocality_level_1, + city: address.locality, + postcode: address.postal_code, + latitude: place.geometry.location.lat(), + longitude: place.geometry.location.lng() + }); + }; + // ============================================= || Address Autocomplete (Drop) || ============================================= - // Use address object as per your requirements - setPickCust({ - ...pickCust, - address: address.address, - doorno: `${address.street_number} ${address.route}`, - suburb: address.sublocality_level_1, - city: address.locality, - postcode: address.postal_code, - latitude: place.geometry.location.lat(), - longitude: place.geometry.location.lng() - }); - console.log('Pick Address:', address); + const handleDropPlaceSelected = (place) => { + setInputValue2(`${place.name}, ${place.formatted_address}`); + setEndPoint({ latitude: place.geometry.location.lat(), longitude: place.geometry.location.lng() }); + + setDropCust({ ...dropCust, address: `${place.name} ${place.formatted_address}` }); + const address = { + address: `${place.name} ${place.formatted_address}`, + street_number: '', + route: '', + locality: '', + sublocality_level_1: '', + administrative_area_level_3: '', + administrative_area_level_1: '', + country: '', + postal_code: '' + }; + place.address_components.forEach((component) => { + component.types.forEach((type) => { + switch (type) { + case 'street_number': + address.street_number = component.long_name; + break; + case 'route': + address.route = component.long_name; + break; + case 'locality': + address.locality = component.long_name; + break; + case 'sublocality_level_1': + address.sublocality_level_1 = component.long_name; + break; + case 'administrative_area_level_3': + address.administrative_area_level_3 = component.long_name; + break; + case 'administrative_area_level_1': + address.administrative_area_level_1 = component.long_name; + break; + case 'country': + address.country = component.long_name; + break; + case 'postal_code': + address.postal_code = component.long_name; + break; + // Add more cases as needed for other types + } }); - } - }, [inputValue1]); - // ============================================= || Google Maps Autocomplete(Drop) || ============================================= + }); - useEffect(() => { - if (inputValue2) { - // Initialize Google Maps Autocomplete - const autocompleteInput = document.getElementById('addressAuto2'); - const autocomplete = new window.google.maps.places.Autocomplete(autocompleteInput, { - // types: ['(cities)'], // You can adjust the types parameter based on your requirements - strictBounds: true, - bounds: new window.google.maps.Circle({ - // center: new window.google.maps.LatLng(11.0050707, 76.9509083), - center: new window.google.maps.LatLng(appLocaLat, appLocaLng), - radius: appLocaRadius * 1000 //km to m - // radius: 100000 //km to m - }).getBounds() - }); - let arr = []; - // Event listener for autocomplete place changed - autocomplete.addListener('place_changed', () => { - const place = autocomplete.getPlace(); - setInputValue2(`${place.name}, ${place.formatted_address}`); - console.log('new place', place); // Do something with the selected place - console.log('drop (new place) lat lng', { lat: place.geometry.location.lat(), lng: place.geometry.location.lng() }); // Do something with the selected place - setEndPoint({ latitude: place.geometry.location.lat(), longitude: place.geometry.location.lng() }); - - setDropCust({ ...dropCust, address: `${place.name} ${place.formatted_address}` }); - const address = { - address: `${place.name} ${place.formatted_address}`, - street_number: '', - route: '', - locality: '', - sublocality_level_1: '', - administrative_area_level_3: '', - administrative_area_level_1: '', - country: '', - postal_code: '' - }; - place.address_components.forEach((component) => { - component.types.forEach((type) => { - switch (type) { - case 'street_number': - address.street_number = component.long_name; - break; - case 'route': - address.route = component.long_name; - break; - case 'locality': - address.locality = component.long_name; - break; - case 'sublocality_level_1': - address.sublocality_level_1 = component.long_name; - break; - case 'administrative_area_level_3': - address.administrative_area_level_3 = component.long_name; - break; - case 'administrative_area_level_1': - address.administrative_area_level_1 = component.long_name; - break; - case 'country': - address.country = component.long_name; - break; - case 'postal_code': - address.postal_code = component.long_name; - break; - // Add more cases as needed for other types - } - }); - }); - - // Use address object as per your requirements - setDropCust({ - ...dropCust, - address: address.address, - doorno: `${address.street_number} ${address.route}`, - suburb: address.sublocality_level_1, - city: address.locality, - postcode: address.postal_code, - latitude: place.geometry.location.lat(), - longitude: place.geometry.location.lng() - }); - console.log('Drop Address:', address); - }); - } - }, [inputValue2]); + // Use address object as per your requirements + setDropCust({ + ...dropCust, + address: address.address, + doorno: `${address.street_number} ${address.route}`, + suburb: address.sublocality_level_1, + city: address.locality, + postcode: address.postal_code, + latitude: place.geometry.location.lat(), + longitude: place.geometry.location.lng() + }); + }; // ============================================= || gettenantlocations (branches) || ============================================= const gettenantlocations = async (id) => { @@ -1375,43 +1305,47 @@ const Createorder1 = () => { Address Lookup {addId1 == 0 ? ( - setInputValue1(e.target.value)} - helperText="Start typing to auto-fill the address details below" - FormHelperTextProps={{ className: 'address-search-helper pickup-helper' }} - InputProps={{ - startAdornment: ( - - - - ), - endAdornment: ( - { - setInputValue1(''); - setPickCust({ - ...pickCust, - doorno: '', - suburb: '', - city: '', - postcode: '', - landmark: '' - }); - setShowDistance(false); - setStartPoint({ latitude: 0, longitude: 0 }); - }} - size="small" - > - - - ), - style: { borderRadius: '10px', background: '#fff' } + onChange={setInputValue1} + onPlaceSelected={handlePickPlaceSelected} + bias={{ lat: appLocaLat, lng: appLocaLng }} + TextFieldProps={{ + size: 'small', + variant: 'outlined', + helperText: 'Start typing to auto-fill the address details below', + FormHelperTextProps: { className: 'address-search-helper pickup-helper' }, + InputProps: { + startAdornment: ( + + + + ), + endAdornment: ( + { + setInputValue1(''); + setPickCust({ + ...pickCust, + doorno: '', + suburb: '', + city: '', + postcode: '', + landmark: '' + }); + setShowDistance(false); + setStartPoint({ latitude: 0, longitude: 0 }); + }} + size="small" + > + + + ), + style: { borderRadius: '10px', background: '#fff' } + } }} /> ) : ( @@ -1693,43 +1627,47 @@ const Createorder1 = () => { Address Lookup {addId2 == 0 ? ( - setInputValue2(e.target.value)} - helperText="Start typing to auto-fill the address details below" - FormHelperTextProps={{ className: 'address-search-helper drop-helper' }} - InputProps={{ - startAdornment: ( - - - - ), - endAdornment: ( - { - setInputValue2(''); - setDropCust({ - ...dropCust, - doorno: '', - suburb: '', - city: '', - postcode: '', - landmark: '' - }); - setShowDistance(false); - setEndPoint({ latitude: 0, longitude: 0 }); - }} - size="small" - > - - - ), - style: { borderRadius: '10px', background: '#fff' } + onChange={setInputValue2} + onPlaceSelected={handleDropPlaceSelected} + bias={{ lat: appLocaLat, lng: appLocaLng }} + TextFieldProps={{ + size: 'small', + variant: 'outlined', + helperText: 'Start typing to auto-fill the address details below', + FormHelperTextProps: { className: 'address-search-helper drop-helper' }, + InputProps: { + startAdornment: ( + + + + ), + endAdornment: ( + { + setInputValue2(''); + setDropCust({ + ...dropCust, + doorno: '', + suburb: '', + city: '', + postcode: '', + landmark: '' + }); + setShowDistance(false); + setEndPoint({ latitude: 0, longitude: 0 }); + }} + size="small" + > + + + ), + style: { borderRadius: '10px', background: '#fff' } + } }} /> ) : ( diff --git a/src/pages/nearle/orders/newcreateOrder.js b/src/pages/nearle/orders/newcreateOrder.js index e137ad3..ecb5fc0 100644 --- a/src/pages/nearle/orders/newcreateOrder.js +++ b/src/pages/nearle/orders/newcreateOrder.js @@ -37,7 +37,7 @@ import { TbMapPinCode } from 'react-icons/tb'; import { FaLocationDot } from 'react-icons/fa6'; import axios from 'axios'; import { useTheme } from '@mui/material/styles'; -import Geocode from 'react-geocode'; +import AddressAutocomplete from 'components/nearle_components/AddressAutocomplete'; import Loader from 'components/Loader'; import MainCard from 'components/MainCard'; import { FaUser } from 'react-icons/fa6'; @@ -280,22 +280,7 @@ const OrderMap = ({ startPoint, endPoint, appLocaLat, appLocaLng }) => { }; -function loadScript(src, position, id) { - if (!position) { - return; - } - - const script = document.createElement('script'); - script.setAttribute('async', ''); - script.setAttribute('id', id); - script.src = src; - position.appendChild(script); -} - const Createorder1 = () => { - Geocode.setApiKey(process.env.REACT_APP_GOOGLE_MAPS_API_KEY); - // ================================================= || GoogleMaps (Drawer) || ================================================= - const loaded = React.useRef(false); const navigate = useNavigate(); const theme = useTheme(); const locationRef = useRef(null); @@ -380,17 +365,6 @@ const Createorder1 = () => { } }; - if (typeof window !== 'undefined' && !loaded.current) { - if (!document.querySelector('#google-maps')) { - loadScript( - `https://maps.googleapis.com/maps/api/js?key=${process.env.REACT_APP_GOOGLE_MAPS_API_KEY}&libraries=places&location=10.3656,77.9690&radius=50000&components=country:IN&strictbounds=true`, - document.querySelector('head'), - 'google-maps' - ); - } - loaded.current = true; - } - // ==============================|| fetchAppLocations ||============================== // const fetchAppLocations = async () => { try { @@ -863,173 +837,129 @@ const Createorder1 = () => { setLoading(false); }); }; - // ============================================= || Google Maps Autocomplete(pick) || ============================================= - useEffect(() => { - // Initialize Google Maps Autocomplete - if (inputValue1) { - const autocompleteInput = document.getElementById('addressAuto1'); - const autocomplete = new window.google.maps.places.Autocomplete(autocompleteInput, { - // types: ['(cities)'], // You can adjust the types parameter based on your requirements - strictBounds: true, - bounds: new window.google.maps.Circle({ - // center: new window.google.maps.LatLng(11.0050707, 76.9509083), - // radius: 100000 - center: new window.google.maps.LatLng(appLocaLat, appLocaLng), - radius: appLocaRadius * 1000 - }).getBounds() + // ============================================= || Address Autocomplete (pick) || ============================================= + const handlePickPlaceSelected = (place) => { + setInputValue1(`${place.name}, ${place.formatted_address}`); + // to trigger getDistance + setStartPoint({ latitude: place.geometry.location.lat(), longitude: place.geometry.location.lng() }); + setPickCust({ ...pickCust, address: `${place.name} ${place.formatted_address}` }); + const address = { + address: `${place.name} ${place.formatted_address}`, + street_number: '', + route: '', + locality: '', + sublocality_level_1: '', + administrative_area_level_3: '', + administrative_area_level_1: '', + country: '', + postal_code: '' + }; + place.address_components.forEach((component) => { + component.types.forEach((type) => { + switch (type) { + case 'street_number': + address.street_number = component.long_name; + break; + case 'route': + address.route = component.long_name; + break; + case 'locality': + address.locality = component.long_name; + break; + case 'sublocality_level_1': + address.sublocality_level_1 = component.long_name; + break; + case 'administrative_area_level_3': + address.administrative_area_level_3 = component.long_name; + break; + case 'administrative_area_level_1': + address.administrative_area_level_1 = component.long_name; + break; + case 'country': + address.country = component.long_name; + break; + case 'postal_code': + address.postal_code = component.long_name; + break; + // Add more cases as needed for other types + } }); + }); - // Event listener for autocomplete place changed - autocomplete.addListener('place_changed', () => { - const place = autocomplete.getPlace(); - setInputValue1(`${place.name}, ${place.formatted_address}`); - console.log('new place', place); // Do something with the selected place - console.log(' pick (new place) lat lng', { lat: place.geometry.location.lat(), lng: place.geometry.location.lng() }); // Do something with the selected place - // to trigger getDistance - setStartPoint({ latitude: place.geometry.location.lat(), longitude: place.geometry.location.lng() }); - setPickCust({ ...pickCust, address: `${place.name} ${place.formatted_address}` }); - const address = { - address: `${place.name} ${place.formatted_address}`, - street_number: '', - route: '', - locality: '', - sublocality_level_1: '', - administrative_area_level_3: '', - administrative_area_level_1: '', - country: '', - postal_code: '' - }; - place.address_components.forEach((component) => { - component.types.forEach((type) => { - switch (type) { - case 'street_number': - address.street_number = component.long_name; - break; - case 'route': - address.route = component.long_name; - break; - case 'locality': - address.locality = component.long_name; - break; - case 'sublocality_level_1': - address.sublocality_level_1 = component.long_name; - break; - case 'administrative_area_level_3': - address.administrative_area_level_3 = component.long_name; - break; - case 'administrative_area_level_1': - address.administrative_area_level_1 = component.long_name; - break; - case 'country': - address.country = component.long_name; - break; - case 'postal_code': - address.postal_code = component.long_name; - break; - // Add more cases as needed for other types - } - }); - }); + // Use address object as per your requirements + setPickCust({ + ...pickCust, + address: address.address, + doorno: `${address.street_number} ${address.route}`, + suburb: address.sublocality_level_1, + city: address.locality, + postcode: address.postal_code, + latitude: place.geometry.location.lat(), + longitude: place.geometry.location.lng() + }); + }; + // ============================================= || Address Autocomplete (Drop) || ============================================= - // Use address object as per your requirements - setPickCust({ - ...pickCust, - address: address.address, - doorno: `${address.street_number} ${address.route}`, - suburb: address.sublocality_level_1, - city: address.locality, - postcode: address.postal_code, - latitude: place.geometry.location.lat(), - longitude: place.geometry.location.lng() - }); - console.log('Pick Address:', address); + const handleDropPlaceSelected = (place) => { + setInputValue2(`${place.name}, ${place.formatted_address}`); + setEndPoint({ latitude: place.geometry.location.lat(), longitude: place.geometry.location.lng() }); + + setDropCust({ ...dropCust, address: `${place.name} ${place.formatted_address}` }); + const address = { + address: `${place.name} ${place.formatted_address}`, + street_number: '', + route: '', + locality: '', + sublocality_level_1: '', + administrative_area_level_3: '', + administrative_area_level_1: '', + country: '', + postal_code: '' + }; + place.address_components.forEach((component) => { + component.types.forEach((type) => { + switch (type) { + case 'street_number': + address.street_number = component.long_name; + break; + case 'route': + address.route = component.long_name; + break; + case 'locality': + address.locality = component.long_name; + break; + case 'sublocality_level_1': + address.sublocality_level_1 = component.long_name; + break; + case 'administrative_area_level_3': + address.administrative_area_level_3 = component.long_name; + break; + case 'administrative_area_level_1': + address.administrative_area_level_1 = component.long_name; + break; + case 'country': + address.country = component.long_name; + break; + case 'postal_code': + address.postal_code = component.long_name; + break; + // Add more cases as needed for other types + } }); - } - }, [inputValue1]); - // ============================================= || Google Maps Autocomplete(Drop) || ============================================= + }); - useEffect(() => { - if (inputValue2) { - // Initialize Google Maps Autocomplete - const autocompleteInput = document.getElementById('addressAuto2'); - const autocomplete = new window.google.maps.places.Autocomplete(autocompleteInput, { - // types: ['(cities)'], // You can adjust the types parameter based on your requirements - strictBounds: true, - bounds: new window.google.maps.Circle({ - // center: new window.google.maps.LatLng(11.0050707, 76.9509083), - center: new window.google.maps.LatLng(appLocaLat, appLocaLng), - radius: appLocaRadius * 1000 //km to m - // radius: 100000 //km to m - }).getBounds() - }); - let arr = []; - // Event listener for autocomplete place changed - autocomplete.addListener('place_changed', () => { - const place = autocomplete.getPlace(); - setInputValue2(`${place.name}, ${place.formatted_address}`); - console.log('new place', place); // Do something with the selected place - console.log('drop (new place) lat lng', { lat: place.geometry.location.lat(), lng: place.geometry.location.lng() }); // Do something with the selected place - setEndPoint({ latitude: place.geometry.location.lat(), longitude: place.geometry.location.lng() }); - - setDropCust({ ...dropCust, address: `${place.name} ${place.formatted_address}` }); - const address = { - address: `${place.name} ${place.formatted_address}`, - street_number: '', - route: '', - locality: '', - sublocality_level_1: '', - administrative_area_level_3: '', - administrative_area_level_1: '', - country: '', - postal_code: '' - }; - place.address_components.forEach((component) => { - component.types.forEach((type) => { - switch (type) { - case 'street_number': - address.street_number = component.long_name; - break; - case 'route': - address.route = component.long_name; - break; - case 'locality': - address.locality = component.long_name; - break; - case 'sublocality_level_1': - address.sublocality_level_1 = component.long_name; - break; - case 'administrative_area_level_3': - address.administrative_area_level_3 = component.long_name; - break; - case 'administrative_area_level_1': - address.administrative_area_level_1 = component.long_name; - break; - case 'country': - address.country = component.long_name; - break; - case 'postal_code': - address.postal_code = component.long_name; - break; - // Add more cases as needed for other types - } - }); - }); - - // Use address object as per your requirements - setDropCust({ - ...dropCust, - address: address.address, - doorno: `${address.street_number} ${address.route}`, - suburb: address.sublocality_level_1, - city: address.locality, - postcode: address.postal_code, - latitude: place.geometry.location.lat(), - longitude: place.geometry.location.lng() - }); - console.log('Drop Address:', address); - }); - } - }, [inputValue2]); + // Use address object as per your requirements + setDropCust({ + ...dropCust, + address: address.address, + doorno: `${address.street_number} ${address.route}`, + suburb: address.sublocality_level_1, + city: address.locality, + postcode: address.postal_code, + latitude: place.geometry.location.lat(), + longitude: place.geometry.location.lng() + }); + }; // ============================================= || gettenantlocations (branches) || ============================================= const gettenantlocations = async (id) => { @@ -1422,35 +1352,38 @@ const Createorder1 = () => { {addId1 == 0 ? (
    - setInputValue1(e.target.value)} - InputProps={{ - endAdornment: ( - { - setInputValue1(''); - setPickCust({ - ...pickCust, - doorno: '', - suburb: '', - city: '', - postcode: '', - landmark: '' - }); - setShowDistance(false); - setStartPoint({ latitude: 0, longitude: 0 }); - }} - size="small" - > - - - ) + onChange={setInputValue1} + onPlaceSelected={handlePickPlaceSelected} + bias={{ lat: appLocaLat, lng: appLocaLng }} + TextFieldProps={{ + variant: 'outlined', + InputProps: { + endAdornment: ( + { + setInputValue1(''); + setPickCust({ + ...pickCust, + doorno: '', + suburb: '', + city: '', + postcode: '', + landmark: '' + }); + setShowDistance(false); + setStartPoint({ latitude: 0, longitude: 0 }); + }} + size="small" + > + + + ) + } }} />
    @@ -1799,35 +1732,38 @@ const Createorder1 = () => { {addId2 == 0 ? (
    - setInputValue2(e.target.value)} - InputProps={{ - endAdornment: ( - { - setInputValue2(''); - setDropCust({ - ...dropCust, - doorno: '', - suburb: '', - city: '', - postcode: '', - landmark: '' - }); - setShowDistance(false); - setEndPoint({ latitude: 0, longitude: 0 }); - }} - size="small" - > - - - ) + onChange={setInputValue2} + onPlaceSelected={handleDropPlaceSelected} + bias={{ lat: appLocaLat, lng: appLocaLng }} + TextFieldProps={{ + variant: 'outlined', + InputProps: { + endAdornment: ( + { + setInputValue2(''); + setDropCust({ + ...dropCust, + doorno: '', + suburb: '', + city: '', + postcode: '', + landmark: '' + }); + setShowDistance(false); + setEndPoint({ latitude: 0, longitude: 0 }); + }} + size="small" + > + + + ) + } }} />
    diff --git a/src/pages/nearle/reports/MapWithRouteGoogle.js b/src/pages/nearle/reports/MapWithRouteGoogle.js deleted file mode 100644 index e7e1e5e..0000000 --- a/src/pages/nearle/reports/MapWithRouteGoogle.js +++ /dev/null @@ -1,91 +0,0 @@ -import React, { useEffect, useRef } from 'react'; -import { LoadScriptNext, GoogleMap } from '@react-google-maps/api'; - -const containerStyle = { - width: '100%', - height: '90vh' -}; - -const MapWithRouteGoogle = ({ coordinates, additionalProps, setMapOpen }) => { - const mapRef = useRef(null); - - /** Convert coordinates to numbers */ - const numericCoordinates = coordinates - .map((c) => { - const lat = Number(c.lat); - const lng = Number(c.lng); - return isNaN(lat) || isNaN(lng) ? null : { lat, lng }; - }) - .filter(Boolean); - - if (numericCoordinates.length < 2) { - return
    No route data available
    ; - } - - const start = numericCoordinates[0]; - const end = numericCoordinates[numericCoordinates.length - 1]; - - /** Map loaded callback */ - const onMapLoad = (map) => { - // draw markers - new window.google.maps.Marker({ - position: start, - map, - label: 'S', - title: `Start: ${additionalProps?.riderStart}` - }); - - new window.google.maps.Marker({ - position: end, - map, - label: 'E', - title: `End: ${additionalProps?.riderEnd}` - }); - - // draw rider route (point-to-point) - const route = new window.google.maps.Polyline({ - path: numericCoordinates, - geodesic: false, - strokeColor: '#1A73E8', - strokeOpacity: 1.0, - strokeWeight: 4 - }); - - route.setMap(map); - - // auto fit - const bounds = new window.google.maps.LatLngBounds(); - numericCoordinates.forEach((p) => bounds.extend(p)); - map.fitBounds(bounds); - }; - - return ( - <> - - - - - {/* Polyline and markers added via onLoad */} - - - - ); -}; - -export default MapWithRouteGoogle; diff --git a/src/pages/nearle/reports/RiderLocationMap.js b/src/pages/nearle/reports/RiderLocationMap.js index 5dfabf2..1d484eb 100644 --- a/src/pages/nearle/reports/RiderLocationMap.js +++ b/src/pages/nearle/reports/RiderLocationMap.js @@ -1,76 +1,55 @@ import { Button } from '@mui/material'; -import { LoadScriptNext, GoogleMap, Marker, OverlayView } from '@react-google-maps/api'; +import { MapContainer, TileLayer, Marker, Tooltip } from 'react-leaflet'; +import L from 'leaflet'; +import 'leaflet/dist/leaflet.css'; const containerStyle = { width: '100%', height: 'calc(100vh - 150px)' }; +// Green marker +const GreenIcon = new L.Icon({ + iconUrl: 'https://cdn.rawgit.com/pointhi/leaflet-color-markers/master/img/marker-icon-2x-green.png', + shadowUrl: 'https://cdnjs.cloudflare.com/ajax/libs/leaflet/0.7.7/images/marker-shadow.png', + iconSize: [25, 41], + iconAnchor: [12, 41], + shadowSize: [41, 41] +}); + +// Red marker +const RedIcon = new L.Icon({ + iconUrl: 'https://cdn.rawgit.com/pointhi/leaflet-color-markers/master/img/marker-icon-2x-red.png', + shadowUrl: 'https://cdnjs.cloudflare.com/ajax/libs/leaflet/0.7.7/images/marker-shadow.png', + iconSize: [25, 41], + iconAnchor: [12, 41], + shadowSize: [41, 41] +}); + export default function RiderLocationMap({ riderLocations }) { console.log('riderLocations', riderLocations); - const center = { - lat: Number(riderLocations?.[0]?.latitude || 11.0056), - lng: Number(riderLocations?.[0]?.longitude || 76.9661) - }; - const GreenIcon = { - url: 'https://cdn.rawgit.com/pointhi/leaflet-color-markers/master/img/marker-icon-2x-green.png', - scaledSize: new window.google.maps.Size(25, 41), - anchor: new window.google.maps.Point(12, 41) - }; - - const RedIcon = { - url: 'https://cdn.rawgit.com/pointhi/leaflet-color-markers/master/img/marker-icon-2x-red.png', - scaledSize: new window.google.maps.Size(25, 41), - anchor: new window.google.maps.Point(12, 41) - }; + const center = [Number(riderLocations?.[0]?.latitude || 11.0056), Number(riderLocations?.[0]?.longitude || 76.9661)]; return ( - - - {riderLocations && - riderLocations?.map((r, index) => { - const lat = Number(r.latitude); - const lng = Number(r.longitude); - return ( -
    - {/* Marker */} - - -
    - -
    -
    -
    - ); - })} -
    -
    + + + {riderLocations && + riderLocations.map((r, index) => { + const lat = Number(r.latitude); + const lng = Number(r.longitude); + return ( + + + + + + ); + })} + ); } diff --git a/src/pages/nearle/reports/RidersRoutes.js b/src/pages/nearle/reports/RidersRoutes.js index 24fc765..fc00b3f 100644 --- a/src/pages/nearle/reports/RidersRoutes.js +++ b/src/pages/nearle/reports/RidersRoutes.js @@ -1,10 +1,46 @@ -import React, { useEffect, useMemo, useRef, useState } from 'react'; -import { GoogleMap, Polyline, Marker, InfoWindow, useJsApiLoader } from '@react-google-maps/api'; +import React, { useEffect, useMemo, useState } from 'react'; +import { MapContainer, TileLayer, Polyline, Marker, Popup, useMap } from 'react-leaflet'; +import L from 'leaflet'; +import 'leaflet/dist/leaflet.css'; import { Box, IconButton, Stack, Typography, CircularProgress } from '@mui/material'; import { MdClose, MdRoute } from 'react-icons/md'; const containerStyle = { width: '100%', height: '100%' }; +// Numbered step icon — brand purple to match the planned-route polyline below. +// Drawn fresh per render as a data URL so the step number can be baked into +// the SVG without juggling external marker assets. +const stepIcon = (n, isFocused) => { + const size = isFocused ? 38 : 32; + const color = isFocused ? '#4D1C61' : '#662582'; + const svg = encodeURIComponent( + `` + + `` + + `${n}` + + `` + ); + return new L.Icon({ + iconUrl: `data:image/svg+xml;charset=UTF-8,${svg}`, + iconSize: [size, size], + iconAnchor: [size / 2, size / 2] + }); +}; + +// Fits the map to the planned path once both the map and data are ready. +// Re-runs whenever the route changes (different rider / date). +const FitBoundsController = ({ dropPath }) => { + const map = useMap(); + useEffect(() => { + if (!dropPath.length) return; + if (dropPath.length === 1) { + map.setView(dropPath[0], 14); + } else { + map.fitBounds(dropPath, { padding: [48, 48] }); + } + }, [dropPath, map]); + return null; +}; + // Renders a single rider's PLANNED route for the date range chosen on the // Riders Summary page. `details` is an ordered array of waypoints (sorted by // the planning step number) shaped as: @@ -13,84 +49,38 @@ const containerStyle = { width: '100%', height: '100%' }; // `dropLat/dropLng` are required; pickup coords are optional and rendered as // faded pre-stops if present. export default function RidersRoutes({ details, loading, riderName, dateRange, onClose }) { - const mapRef = useRef(null); const [focusedStep, setFocusedStep] = useState(null); const [routePath, setRoutePath] = useState([]); const [routeLoading, setRouteLoading] = useState(false); - const { isLoaded } = useJsApiLoader({ - googleMapsApiKey: process.env.REACT_APP_GOOGLE_MAPS_KEY - }); - // Step-pin coordinates in planning order — what the polyline connects. - const dropPath = useMemo( - () => (details || []).map((d) => ({ lat: d.dropLat, lng: d.dropLng })), - [details] - ); - - // Auto-fit map bounds to the full planned path once the map and data are - // both ready. Re-runs whenever the route changes (different rider / date). - useEffect(() => { - if (!isLoaded || !mapRef.current || dropPath.length === 0) return; - const bounds = new window.google.maps.LatLngBounds(); - dropPath.forEach((p) => bounds.extend(p)); - mapRef.current.fitBounds(bounds, 48); - }, [isLoaded, dropPath]); + const dropPath = useMemo(() => (details || []).map((d) => [d.dropLat, d.dropLng]), [details]); // Resolve the rider's planned waypoints into an actual road-following path - // via the Directions API. Without this, the polyline would cut across - // buildings / aerial lines — operators have no way to read the real route. - // Directions has a 25-waypoint limit per request, so we chunk and stitch. + // via OSRM. Without this, the polyline would cut across buildings / aerial + // lines — operators have no way to read the real route. useEffect(() => { - if (!isLoaded || dropPath.length < 2) { + if (dropPath.length < 2) { setRoutePath([]); return; } let cancelled = false; - const ds = new window.google.maps.DirectionsService(); - const MAX_WPS = 23; // origin + 23 waypoints + destination = 25 stops/chunk - - const fetchSegment = (origin, destination, waypoints) => - new Promise((resolve, reject) => { - ds.route( - { - origin, - destination, - waypoints: waypoints.map((p) => ({ location: p, stopover: true })), - travelMode: window.google.maps.TravelMode.DRIVING - }, - (result, status) => { - if (status === 'OK') resolve(result); - else reject(new Error(status)); - } - ); - }); (async () => { setRouteLoading(true); try { - const points = dropPath; - const all = []; - let i = 0; - while (i < points.length - 1) { - const remaining = points.length - 1 - i; - const take = Math.min(remaining, MAX_WPS + 1); - const origin = points[i]; - const destination = points[i + take]; - const waypoints = points.slice(i + 1, i + take); - const res = await fetchSegment(origin, destination, waypoints); - const seg = res.routes[0].overview_path.map((ll) => ({ - lat: ll.lat(), - lng: ll.lng() - })); - // Avoid duplicating the join point between adjacent chunks. - if (all.length > 0 && seg.length > 0) seg.shift(); - all.push(...seg); - i += take; + const coords = dropPath.map(([lat, lng]) => `${lng},${lat}`).join(';'); + const url = `https://router.project-osrm.org/route/v1/driving/${coords}?overview=full&geometries=geojson`; + const res = await fetch(url); + const data = await res.json(); + if (!cancelled && data.routes?.length) { + const points = data.routes[0].geometry.coordinates.map(([lng, lat]) => [lat, lng]); + setRoutePath(points); + } else if (!cancelled) { + setRoutePath([]); } - if (!cancelled) setRoutePath(all); - } catch { - // Fall back to the straight-line skeleton on failure (quota, no route, etc.). + } catch (e) { + console.warn('OSRM route error:', e); if (!cancelled) setRoutePath([]); } finally { if (!cancelled) setRouteLoading(false); @@ -100,22 +90,7 @@ export default function RidersRoutes({ details, loading, riderName, dateRange, o return () => { cancelled = true; }; - }, [isLoaded, dropPath]); - - // Numbered step icon as a data URL — drawn fresh per render so we can pass - // the step number into the SVG without juggling external assets. Color is - // brand purple to match the planned-route polyline below. - const stepIcon = (n, isFocused) => { - const size = isFocused ? 38 : 32; - const color = isFocused ? '#4D1C61' : '#662582'; - const svg = encodeURIComponent( - `` + - `` + - `${n}` + - `` - ); - return `data:image/svg+xml;charset=UTF-8,${svg}`; - }; + }, [dropPath]); const headerBar = ( - - Planned route{riderName ? ` — ${riderName}` : ''} - - {dateRange && ( - {dateRange} - )} + Planned route{riderName ? ` — ${riderName}` : ''} + {dateRange && {dateRange}} {details && details.length > 0 && ( @@ -154,16 +125,14 @@ export default function RidersRoutes({ details, loading, riderName, dateRange, o ); - // Loading state — route fetch in flight OR Google Maps script not ready yet. - if (loading || !isLoaded) { + // Loading state — parent is still fetching the planned route data. + if (loading) { return ( {headerBar} - - {loading ? 'Loading planned route…' : 'Loading map…'} - + Loading planned route… ); @@ -176,9 +145,7 @@ export default function RidersRoutes({ details, loading, riderName, dateRange, o {headerBar} - - No planned route for this rider - + No planned route for this rider There are no deliveries with drop coordinates assigned to this rider for the selected date range. @@ -191,53 +158,21 @@ export default function RidersRoutes({ details, loading, riderName, dateRange, o {headerBar} - (mapRef.current = map)} - center={dropPath[0]} - zoom={14} - options={{ - streetViewControl: false, - mapTypeControl: false, - fullscreenControl: false - }} - > + + + + {routePath.length > 0 ? ( <> {/* Translucent backdrop so the route stays legible on busy tiles. */} - - {/* Road-following planned route from the Directions API. */} - + + {/* Road-following planned route from OSRM. */} + ) : ( - // Fallback while Directions is in flight (or if it fails) — dashed + // Fallback while OSRM is in flight (or if it fails) — dashed // straight-line skeleton between drop pins in step order. - + )} {details.map((d, i) => { @@ -246,39 +181,29 @@ export default function RidersRoutes({ details, loading, riderName, dateRange, o return ( setFocusedStep(isFocused ? null : d.deliveryid)} - zIndex={isFocused ? 1000 : stepNum} + position={[d.dropLat, d.dropLng]} + icon={stepIcon(stepNum, isFocused)} + eventHandlers={{ + click: () => setFocusedStep(isFocused ? null : d.deliveryid) + }} + zIndexOffset={isFocused ? 1000 : stepNum} > - {isFocused && ( - setFocusedStep(null)}> - - - Step {stepNum} · {d.customer} - - {d.address && ( - - {d.address} - - )} - {d.expectedTime && ( - - ETA {String(d.expectedTime).slice(11, 16) || d.expectedTime} - - )} - {d.orderid && ( - - Order #{d.orderid} - - )} - - - )} + setFocusedStep(null)}> + + + Step {stepNum} · {d.customer} + + {d.address && {d.address}} + {d.expectedTime && ( + ETA {String(d.expectedTime).slice(11, 16) || d.expectedTime} + )} + {d.orderid && Order #{d.orderid}} + + ); })} - + ); diff --git a/src/pages/nearle/requests/requests.js b/src/pages/nearle/requests/requests.js index 7d13a77..3856090 100644 --- a/src/pages/nearle/requests/requests.js +++ b/src/pages/nearle/requests/requests.js @@ -50,7 +50,7 @@ import { useState, useEffect } from 'react'; import axios from 'axios'; import Loader from 'components/Loader'; import Transitions from 'components/@extended/Transitions'; -import Autocomplete from 'react-google-autocomplete'; +import AddressAutocomplete from 'components/nearle_components/AddressAutocomplete'; import * as React from 'react'; @@ -60,8 +60,6 @@ import TablePagination from '@mui/material/TablePagination'; import TableSortLabel from '@mui/material/TableSortLabel'; import { visuallyHidden } from '@mui/utils'; -import Geocode from 'react-geocode'; - const Requests = () => { // let dispatch = useDispatch(); @@ -201,7 +199,6 @@ const Requests = () => { const [suburb, setSuburb] = useState(''); const [currenttenantid] = useState(''); const [latlong, setLatlong] = useState({}); - Geocode.setApiKey(process.env.REACT_APP_GOOGLE_MAPS_API_KEY); // const [alertmessage, setAlertmessage] = useState(''); // const [toast, setToast] = useState(false); const [rolesarr, setRolesarr] = useState([]); @@ -277,27 +274,34 @@ const Requests = () => { // } - useEffect(() => { - try { - Geocode.fromAddress(address).then( - (response) => { - if (response.status == 'OK') { - const { lat, lng } = response.results[0].geometry.location; - setLatlong({ - lat, - lng - }); - console.log(response); - } - }, - (error) => { - console.log(error); + const handleAddressPlaceSelected = (place) => { + setAddress(place.formatted_address); + setLatlong({ lat: place.geometry.location.lat(), lng: place.geometry.location.lng() }); + let city1, state, zipcode1, suburb1; + place.address_components.forEach((component) => { + component.types.forEach((type) => { + switch (type) { + case 'locality': + city1 = component.long_name; + break; + case 'administrative_area_level_1': + state = component.long_name; + break; + case 'postal_code': + zipcode1 = component.long_name; + break; + case 'sublocality': + case 'sublocality_level_1': + suburb1 = component.long_name; + break; } - ); - } catch (err) { - console.log(err); - } - }, [address]); + }); + }); + setCity(city1 || ''); + setState1(state || ''); + setZipcode(zipcode1 || ''); + setSuburb(suburb1 || ''); + }; useEffect(() => { console.log('rolesarr'); @@ -1458,53 +1462,22 @@ const Requests = () => { {/* } */} - { - setAddress(place.formatted_address); - let city1, state, zipcode1, suburb1; - for (let i = 0; i < place.address_components.length; i++) { - for (let j = 0; j < place.address_components[i].types.length; j++) { - switch (place.address_components[i].types[j]) { - case 'locality': - city1 = place.address_components[i].long_name; - break; - case 'administrative_area_level_1': - state = place.address_components[i].long_name; - break; - case 'postal_code': - zipcode1 = place.address_components[i].long_name; - break; - case 'sublocality': - suburb1 = place.address_components[i].long_name; - break; - } - } - } - setCity(city1 || ''); - setState1(state || ''); - setZipcode(zipcode1 || ''); - setSuburb(suburb1 || ''); - }} - options={{ - types: ['address' || 'geocode'] - }} + setAddress(e.target.value)} + onChange={setAddress} + onPlaceSelected={handleAddressPlaceSelected} + TextFieldProps={{ + className: 'automap', + InputProps: { + style: { + borderRadius: '5px', + border: '1px solid #e0e0e0' + } + } + }} />
    diff --git a/src/pages/nearle/riders/createrider.js b/src/pages/nearle/riders/createrider.js index 45ac77b..d25eec1 100644 --- a/src/pages/nearle/riders/createrider.js +++ b/src/pages/nearle/riders/createrider.js @@ -11,12 +11,10 @@ import { Box, Button, Grid, InputLabel, MenuItem, Select, Stack, TextField, Typo import MainCard from 'components/MainCard'; import axios from 'axios'; // assets -import { usePlacesWidget } from 'react-google-autocomplete'; +import AddressAutocomplete, { geocodeAddress } from 'components/nearle_components/AddressAutocomplete'; import Loader from 'components/Loader'; -import Geocode from 'react-geocode'; import { enqueueSnackbar } from 'notistack'; import { useNavigate } from 'react-router'; -// import { setLocationType } from 'react-geocode'; // const avatarImage = require.context('assets/images/users', true); @@ -50,9 +48,6 @@ const Createrider = () => { const theme = useTheme(); const isMobile = useMediaQuery(theme.breakpoints.down('md')); - Geocode.setApiKey(process.env.REACT_APP_GOOGLE_MAPS_API_KEY); - // Geocode.setApiKey('AIzaSyCF4KatYCI3vqz1_H3kiHeyS3yCMfYToh8'); - const [loading, setLoading] = useState(false); useEffect(() => { @@ -64,25 +59,15 @@ const Createrider = () => { }, []); useEffect(() => { - try { - Geocode.fromAddress(address).then( - (response) => { - if (response.status == 'OK') { - const { lat, lng } = response.results[0].geometry.location; - setLatlong({ - lat, - lng - }); - console.log(response); - } - }, - (error) => { - console.log(error); - } - ); - } catch (err) { - console.log(err); - } + let active = true; + geocodeAddress(address).then((place) => { + if (active && place) { + setLatlong({ lat: place.geometry.location.lat(), lng: place.geometry.location.lng() }); + } + }); + return () => { + active = false; + }; }, [address]); const opentoast = (message) => { @@ -119,45 +104,33 @@ const Createrider = () => { } }, [selectedImage]); - const { ref: materialRef } = usePlacesWidget({ - apiKey: process.env.REACT_APP_GOOGLE_MAPS_API_KEY, - onPlaceSelected: (place) => { - console.log(place); - - setAddress(place.formatted_address); - let city1, zipcode1, state1, suburb1; - for (let i = 0; i < place.address_components.length; i++) { - for (let j = 0; j < place.address_components[i].types.length; j++) { - switch (place.address_components[i].types[j]) { - case 'locality': - city1 = place.address_components[i].long_name; - break; - case 'administrative_area_level_1': - state1 = place.address_components[i].long_name; - break; - case 'postal_code': - zipcode1 = place.address_components[i].long_name; - break; - case 'sublocality': - suburb1 = place.address_components[i].long_name; - break; - } + const handleAddressPlaceSelected = (place) => { + setAddress(place.formatted_address); + let city1, zipcode1, state1, suburb1; + for (let i = 0; i < place.address_components.length; i++) { + for (let j = 0; j < place.address_components[i].types.length; j++) { + switch (place.address_components[i].types[j]) { + case 'locality': + city1 = place.address_components[i].long_name; + break; + case 'administrative_area_level_1': + state1 = place.address_components[i].long_name; + break; + case 'postal_code': + zipcode1 = place.address_components[i].long_name; + break; + case 'sublocality': + case 'sublocality_level_1': + suburb1 = place.address_components[i].long_name; + break; } } - setCity(city1 || ''); - setState(state1 || ''); - setZipcode(zipcode1 || ''); - setSuburb(suburb1 || ''); - - // setAddress(place.formatted_address) - }, - // inputAutocompleteValue: "country", - options: { - // componentRestrictions: 'us', - // types: ["establishment"] - types: ['address' || 'geocode'] } - }); + setCity(city1 || ''); + setState(state1 || ''); + setZipcode(zipcode1 || ''); + setSuburb(suburb1 || ''); + }; const createprofile = async () => { console.log('res', businessname, businessno, mobilenumber, emailaddress, address, city, zipcode); @@ -340,14 +313,13 @@ const Createrider = () => { Address - setAddress(e.target.value)} - inputRef={materialRef} + onChange={setAddress} + onPlaceSelected={handleAddressPlaceSelected} /> diff --git a/src/pages/nearle/riders/editRider.js b/src/pages/nearle/riders/editRider.js index f965bd8..a0f0c14 100644 --- a/src/pages/nearle/riders/editRider.js +++ b/src/pages/nearle/riders/editRider.js @@ -28,9 +28,8 @@ import { DatePicker } from '@mui/x-date-pickers/DatePicker'; // project import import MainCard from 'components/MainCard'; import axios from 'axios'; -import { usePlacesWidget } from 'react-google-autocomplete'; +import AddressAutocomplete from 'components/nearle_components/AddressAutocomplete'; import Loader from 'components/Loader'; -import Geocode from 'react-geocode'; import { enqueueSnackbar } from 'notistack'; import dayjs from 'dayjs'; import CircularLoader from 'components/CircularLoader'; @@ -55,8 +54,6 @@ const EditRider = () => { const [locaName, setLocoName] = useState(); const userid = localStorage.getItem('userid'); - Geocode.setApiKey(process.env.REACT_APP_GOOGLE_MAPS_API_KEY); - const [loading, setLoading] = useState(false); const fetchRiderData = async (id) => { @@ -237,46 +234,30 @@ const EditRider = () => { } }, [selectedImage]); - const { ref: materialRef } = usePlacesWidget({ - apiKey: process.env.REACT_APP_GOOGLE_MAPS_API_KEY, - onPlaceSelected: (place) => { - console.log(place); - setAddress(place.formatted_address); + const handleAddressPlaceSelected = (place) => { + setAddress(place.formatted_address); - let city1, zipcode1, state1, suburb1; - for (let i = 0; i < place.address_components.length; i++) { - for (let j = 0; j < place.address_components[i].types.length; j++) { - switch (place.address_components[i].types[j]) { - case 'locality': - city1 = place.address_components[i].long_name; - break; - case 'administrative_area_level_1': - state1 = place.address_components[i].long_name; - break; - case 'postal_code': - zipcode1 = place.address_components[i].long_name; - break; - case 'sublocality': - suburb1 = place.address_components[i].long_name; - break; - } + let city1, state1, suburb1; + for (let i = 0; i < place.address_components.length; i++) { + for (let j = 0; j < place.address_components[i].types.length; j++) { + switch (place.address_components[i].types[j]) { + case 'locality': + city1 = place.address_components[i].long_name; + break; + case 'administrative_area_level_1': + state1 = place.address_components[i].long_name; + break; + case 'sublocality': + case 'sublocality_level_1': + suburb1 = place.address_components[i].long_name; + break; } } - setCity(city1 || ''); - - setState(state1 || ''); - setZipcode(zipcode1 || ''); - setSuburb(suburb1 || ''); - - // setAddress(place.formatted_address) - }, - // inputAutocompleteValue: "country", - options: { - // componentRestrictions: 'us', - // types: ["establishment"] - types: ['address' || 'geocode'] } - }); + setCity(city1 || ''); + setState(state1 || ''); + setSuburb(suburb1 || ''); + }; const updateRider = async () => { setLoading(true); @@ -483,16 +464,13 @@ const EditRider = () => { Address - { - setAddress(e.target.value); - }} - inputRef={materialRef} + onChange={setAddress} + onPlaceSelected={handleAddressPlaceSelected} /> diff --git a/src/pages/nearle/riders/riders.js b/src/pages/nearle/riders/riders.js index ed99329..edf45a9 100644 --- a/src/pages/nearle/riders/riders.js +++ b/src/pages/nearle/riders/riders.js @@ -1,6 +1,5 @@ import * as React from 'react'; import { useState, useEffect, useRef, Fragment } from 'react'; -import Geocode from 'react-geocode'; import { useNavigate } from 'react-router-dom'; import axios from 'axios'; import { @@ -491,8 +490,6 @@ const Riders = () => { } }); - Geocode.setApiKey(process.env.REACT_APP_GOOGLE_MAPS_API_KEY); - const handleChangetab = (i) => { setTabvalue(i); setLogsRow(null);