updates on the map change and the configurations and removed the google map api key
This commit is contained in:
3
.env
3
.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
|
||||
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
|
||||
@@ -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",
|
||||
|
||||
193
src/components/nearle_components/AddressAutocomplete.js
Normal file
193
src/components/nearle_components/AddressAutocomplete.js
Normal file
@@ -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 (
|
||||
<Autocomplete
|
||||
id={id}
|
||||
freeSolo
|
||||
fullWidth={fullWidth}
|
||||
disabled={disabled}
|
||||
sx={sx}
|
||||
options={options}
|
||||
filterOptions={(x) => 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) => (
|
||||
<TextField
|
||||
{...params}
|
||||
{...TextFieldProps}
|
||||
inputRef={inputRef}
|
||||
label={label}
|
||||
placeholder={placeholder}
|
||||
sx={textFieldSx}
|
||||
autoComplete="off"
|
||||
InputProps={{
|
||||
...params.InputProps,
|
||||
...TextFieldProps.InputProps,
|
||||
startAdornment: TextFieldProps.InputProps?.startAdornment ?? params.InputProps.startAdornment,
|
||||
endAdornment: (
|
||||
<>
|
||||
{loading ? <CircularProgress color="inherit" size={16} /> : null}
|
||||
{TextFieldProps.InputProps?.endAdornment ?? params.InputProps.endAdornment}
|
||||
</>
|
||||
)
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
export default AddressAutocomplete;
|
||||
@@ -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;
|
||||
|
||||
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];
|
||||
}
|
||||
|
||||
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,
|
||||
// ==============================|| 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()
|
||||
});
|
||||
// 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]) {
|
||||
place.address_components.forEach((component) => {
|
||||
component.types.forEach((type) => {
|
||||
switch (type) {
|
||||
case 'locality':
|
||||
city1 = place.address_components[i].long_name;
|
||||
city1 = component.long_name;
|
||||
break;
|
||||
case 'administrative_area_level_1':
|
||||
state1 = place.address_components[i].long_name;
|
||||
state1 = component.long_name;
|
||||
break;
|
||||
case 'postal_code':
|
||||
zipcode1 = place.address_components[i].long_name;
|
||||
zipcode1 = component.long_name;
|
||||
break;
|
||||
case 'sublocality':
|
||||
suburb1 = place.address_components[i].long_name;
|
||||
case 'sublocality_level_1':
|
||||
suburb1 = component.long_name;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
setCity(city1 || '');
|
||||
setState(state1 || '');
|
||||
setZipcode(zipcode1 || '');
|
||||
setSuburb(suburb1 || '');
|
||||
setEditClient({
|
||||
...editClient,
|
||||
setEditClient((prev) => ({
|
||||
...prev,
|
||||
city: city1 || '',
|
||||
state: state1 || '',
|
||||
postcode: zipcode || '',
|
||||
postcode: zipcode1 || '',
|
||||
suburb: suburb1 || ''
|
||||
});
|
||||
}
|
||||
}
|
||||
},
|
||||
(error) => {
|
||||
console.log(error);
|
||||
}
|
||||
);
|
||||
} catch (err) {
|
||||
console.log(err);
|
||||
}
|
||||
}, [address]);
|
||||
}));
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
selectedCustomer &&
|
||||
@@ -1562,85 +1463,19 @@ const Clients1 = () => {
|
||||
/>
|
||||
</Grid>
|
||||
<Grid item xs zeroMinWidth>
|
||||
<Autocomplete
|
||||
id="google-map-demo"
|
||||
sx={{}}
|
||||
<AddressAutocomplete
|
||||
id="address-autocomplete"
|
||||
fullWidth
|
||||
label={'Address'}
|
||||
getOptionLabel={(option) => (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) => (
|
||||
<TextField {...params} fullWidth label="Address" variant="outlined" />
|
||||
)}
|
||||
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 (
|
||||
<li {...props}>
|
||||
<Grid container alignItems="center">
|
||||
<Grid
|
||||
item
|
||||
sx={{
|
||||
display: 'flex',
|
||||
width: 44
|
||||
}}
|
||||
>
|
||||
<LocationOnIcon
|
||||
sx={{
|
||||
color: 'text.secondary'
|
||||
}}
|
||||
/>
|
||||
</Grid>
|
||||
<Grid
|
||||
item
|
||||
sx={{
|
||||
width: 'calc(100% - 44px)',
|
||||
wordWrap: 'break-word'
|
||||
}}
|
||||
>
|
||||
{parts.map((part, index) => (
|
||||
<Box
|
||||
key={index}
|
||||
component="span"
|
||||
sx={{
|
||||
fontWeight: part.highlight ? 'bold' : 'regular'
|
||||
}}
|
||||
>
|
||||
{part.text}
|
||||
</Box>
|
||||
))}
|
||||
<Typography variant="body2" color="text.secondary">
|
||||
{option.structured_formatting.secondary_text}
|
||||
</Typography>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</li>
|
||||
);
|
||||
}}
|
||||
label="Address"
|
||||
value={editClient?.address ?? selectedCustomer.address ?? ''}
|
||||
onChange={(text) =>
|
||||
setEditClient((prev) => ({
|
||||
...prev,
|
||||
address: text
|
||||
}))
|
||||
}
|
||||
onPlaceSelected={handleAddressPlaceSelected}
|
||||
TextFieldProps={{ variant: 'outlined' }}
|
||||
/>
|
||||
</Grid>
|
||||
</Grid>
|
||||
|
||||
@@ -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,29 +33,8 @@ 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()
|
||||
});
|
||||
// Event listener for autocomplete place changed
|
||||
autocomplete.addListener('place_changed', () => {
|
||||
const place = autocomplete.getPlace();
|
||||
const handlePlaceSelected = (place) => {
|
||||
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}`);
|
||||
@@ -116,10 +94,7 @@ const CreateCustomer = () => {
|
||||
latitude: place.geometry.location.lat(),
|
||||
longitude: place.geometry.location.lng()
|
||||
});
|
||||
console.log('Pick Address:', address);
|
||||
});
|
||||
}
|
||||
}, [inputValue2]);
|
||||
};
|
||||
// ==================================================== || 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,19 +353,22 @@ const CreateCustomer = () => {
|
||||
<Grid item xs={12}>
|
||||
<Stack spacing={1.25}>
|
||||
<InputLabel htmlFor="personal-email"> Address</InputLabel>
|
||||
<TextField
|
||||
variant="outlined"
|
||||
<AddressAutocomplete
|
||||
id="addressAuto1"
|
||||
fullWidth
|
||||
value={inputValue2}
|
||||
onChange={(e) => {
|
||||
onChange={(text) => {
|
||||
if (appId) {
|
||||
appId && setInputValue2(e.target.value);
|
||||
setInputValue2(text);
|
||||
} else {
|
||||
OpenToast('Select Location First', 'warning', 3000);
|
||||
}
|
||||
}}
|
||||
InputProps={{
|
||||
onPlaceSelected={handlePlaceSelected}
|
||||
bias={{ lat: appLocaLat, lng: appLocaLng }}
|
||||
TextFieldProps={{
|
||||
variant: 'outlined',
|
||||
InputProps: {
|
||||
endAdornment: (
|
||||
<IconButton
|
||||
onClick={() => {
|
||||
@@ -412,6 +388,7 @@ const CreateCustomer = () => {
|
||||
<CloseIcon />
|
||||
</IconButton>
|
||||
)
|
||||
}
|
||||
}}
|
||||
/>
|
||||
</Stack>
|
||||
|
||||
@@ -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
|
||||
let active = true;
|
||||
geocodeAddress(address).then((place) => {
|
||||
if (active && place) {
|
||||
setLatlong({ lat: place.geometry.location.lat(), lng: place.geometry.location.lng() });
|
||||
}
|
||||
});
|
||||
console.log(response);
|
||||
}
|
||||
},
|
||||
(error) => {
|
||||
console.log(error);
|
||||
}
|
||||
);
|
||||
} catch (err) {
|
||||
console.log(err);
|
||||
}
|
||||
return () => {
|
||||
active = false;
|
||||
};
|
||||
}, [address]);
|
||||
|
||||
const opentoast = (message) => {
|
||||
@@ -151,11 +136,7 @@ const Createclient = () => {
|
||||
}
|
||||
}, [selectedImage]);
|
||||
|
||||
const { ref: materialRef } = usePlacesWidget({
|
||||
apiKey: process.env.REACT_APP_GOOGLE_MAPS_API_KEY,
|
||||
onPlaceSelected: (place) => {
|
||||
console.log(place);
|
||||
|
||||
const handleAddressPlaceSelected = (place) => {
|
||||
setAddress(place.formatted_address);
|
||||
let city1, zipcode1, state1, suburb1;
|
||||
for (let i = 0; i < place.address_components.length; i++) {
|
||||
@@ -171,6 +152,7 @@ const Createclient = () => {
|
||||
zipcode1 = place.address_components[i].long_name;
|
||||
break;
|
||||
case 'sublocality':
|
||||
case 'sublocality_level_1':
|
||||
suburb1 = place.address_components[i].long_name;
|
||||
break;
|
||||
}
|
||||
@@ -180,16 +162,7 @@ const Createclient = () => {
|
||||
setState(state1 || '');
|
||||
setZipcode(zipcode1 || '');
|
||||
setSuburb(suburb1 || '');
|
||||
|
||||
// setAddress(place.formatted_address)
|
||||
},
|
||||
// inputAutocompleteValue: "country",
|
||||
options: {
|
||||
// componentRestrictions: 'us',
|
||||
// types: ["establishment"]
|
||||
types: ['address' || 'geocode']
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
const createprofile = async () => {
|
||||
console.log('res', businessname, businessno, mobilenumber, emailaddress, address, city, zipcode);
|
||||
@@ -486,14 +459,13 @@ const Createclient = () => {
|
||||
<Grid item xs={12}>
|
||||
<Stack spacing={1.25}>
|
||||
<InputLabel htmlFor="personal-address">Address</InputLabel>
|
||||
<TextField
|
||||
fullWidth
|
||||
// defaultValue="Street 110-B Kalians Bag, Dewan, M.P. New York"
|
||||
<AddressAutocomplete
|
||||
id="personal-address"
|
||||
fullWidth
|
||||
placeholder="Address"
|
||||
value={address}
|
||||
onChange={(e) => setAddress(e.target.value)}
|
||||
inputRef={materialRef}
|
||||
onChange={setAddress}
|
||||
onPlaceSelected={handleAddressPlaceSelected}
|
||||
/>
|
||||
</Stack>
|
||||
</Grid>
|
||||
|
||||
@@ -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 }) => (
|
||||
</Avatar>
|
||||
);
|
||||
|
||||
// ==============================|| 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,110 +128,39 @@ 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];
|
||||
}
|
||||
|
||||
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]) {
|
||||
place.address_components.forEach((component) => {
|
||||
component.types.forEach((type) => {
|
||||
switch (type) {
|
||||
case 'locality':
|
||||
city1 = place.address_components[i].long_name;
|
||||
city1 = component.long_name;
|
||||
break;
|
||||
case 'administrative_area_level_1':
|
||||
state1 = place.address_components[i].long_name;
|
||||
state1 = component.long_name;
|
||||
break;
|
||||
case 'postal_code':
|
||||
zipcode1 = place.address_components[i].long_name;
|
||||
zipcode1 = component.long_name;
|
||||
break;
|
||||
case 'sublocality':
|
||||
suburb1 = place.address_components[i].long_name;
|
||||
case 'sublocality_level_1':
|
||||
suburb1 = component.long_name;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
setCity(city1 || '');
|
||||
setState(state1 || '');
|
||||
setPostcode(zipcode1 || '');
|
||||
setSuburb(suburb1 || '');
|
||||
setSelectedCustomer((prev) => ({
|
||||
...prev,
|
||||
address: place.formatted_address,
|
||||
city: city1 || '',
|
||||
state: state1 || '',
|
||||
postcode: zipcode1 || '',
|
||||
@@ -261,25 +168,7 @@ export default function Customers() {
|
||||
latitude: lat || '',
|
||||
longitude: lng || ''
|
||||
}));
|
||||
}
|
||||
}
|
||||
},
|
||||
(error) => {
|
||||
console.log(error);
|
||||
}
|
||||
);
|
||||
} catch (err) {
|
||||
console.log(err);
|
||||
}
|
||||
}, [address]);
|
||||
|
||||
// useEffect(() => {
|
||||
// selectedCustomer &&
|
||||
// setLatlong({
|
||||
// lat: selectedCustomer.latitude,
|
||||
// lng: selectedCustomer.longitude
|
||||
// });
|
||||
// }, [selectedCustomer]);
|
||||
};
|
||||
|
||||
// ==============================|| getallcustomers (customers) ||============================== //
|
||||
|
||||
@@ -891,72 +780,17 @@ export default function Customers() {
|
||||
</Grid>
|
||||
<Grid item xs={12}>
|
||||
<Typography sx={{ mb: 1 }}>Address</Typography>
|
||||
<Autocomplete
|
||||
id="google-map-demo"
|
||||
sx={{}}
|
||||
<AddressAutocomplete
|
||||
id="address-autocomplete"
|
||||
fullWidth
|
||||
getOptionLabel={(option) => (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) => <TextField {...params} fullWidth />}
|
||||
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 (
|
||||
<li {...props}>
|
||||
<Grid container alignItems="center">
|
||||
<Grid item sx={{ display: 'flex', width: 44 }}>
|
||||
<LocationOnIcon sx={{ color: 'text.secondary' }} />
|
||||
</Grid>
|
||||
<Grid
|
||||
item
|
||||
sx={{
|
||||
width: 'calc(100% - 44px)',
|
||||
wordWrap: 'break-word'
|
||||
}}
|
||||
>
|
||||
{parts?.map((part, index) => (
|
||||
<Box
|
||||
key={index}
|
||||
component="span"
|
||||
sx={{
|
||||
fontWeight: part.highlight ? 'bold' : 'regular'
|
||||
}}
|
||||
>
|
||||
{part.text}
|
||||
</Box>
|
||||
))}
|
||||
<Typography variant="body2" color="text.secondary">
|
||||
{option?.structured_formatting.secondary_text}
|
||||
</Typography>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</li>
|
||||
);
|
||||
}}
|
||||
value={selectedCustomer?.address || ''}
|
||||
onChange={(text) =>
|
||||
setSelectedCustomer((prev) => ({
|
||||
...prev,
|
||||
address: text
|
||||
}))
|
||||
}
|
||||
onPlaceSelected={handleAddressPlaceSelected}
|
||||
/>
|
||||
</Grid>
|
||||
<Grid item xs={6}>
|
||||
|
||||
@@ -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,28 +734,9 @@ 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()
|
||||
});
|
||||
|
||||
// Event listener for autocomplete place changed
|
||||
autocomplete.addListener('place_changed', () => {
|
||||
const place = autocomplete.getPlace();
|
||||
// ============================================= || Address Autocomplete (pick) || =============================================
|
||||
const handlePickPlaceSelected = (place) => {
|
||||
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}` });
|
||||
@@ -839,33 +794,11 @@ const Createorder1 = () => {
|
||||
latitude: place.geometry.location.lat(),
|
||||
longitude: place.geometry.location.lng()
|
||||
});
|
||||
console.log('Pick Address:', address);
|
||||
});
|
||||
}
|
||||
}, [inputValue1]);
|
||||
// ============================================= || Google Maps Autocomplete(Drop) || =============================================
|
||||
};
|
||||
// ============================================= || Address 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();
|
||||
const handleDropPlaceSelected = (place) => {
|
||||
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}` });
|
||||
@@ -923,10 +856,7 @@ const Createorder1 = () => {
|
||||
latitude: place.geometry.location.lat(),
|
||||
longitude: place.geometry.location.lng()
|
||||
});
|
||||
console.log('Drop Address:', address);
|
||||
});
|
||||
}
|
||||
}, [inputValue2]);
|
||||
};
|
||||
|
||||
// ============================================= || gettenantlocations (branches) || =============================================
|
||||
const gettenantlocations = async (id) => {
|
||||
@@ -1375,17 +1305,20 @@ const Createorder1 = () => {
|
||||
Address Lookup
|
||||
</Typography>
|
||||
{addId1 == 0 ? (
|
||||
<TextField
|
||||
<AddressAutocomplete
|
||||
id="addressAuto1"
|
||||
fullWidth
|
||||
size="small"
|
||||
placeholder="Search Google Maps for an address..."
|
||||
variant="outlined"
|
||||
placeholder="Search for an address..."
|
||||
value={inputValue1 || ''}
|
||||
onChange={(e) => setInputValue1(e.target.value)}
|
||||
helperText="Start typing to auto-fill the address details below"
|
||||
FormHelperTextProps={{ className: 'address-search-helper pickup-helper' }}
|
||||
InputProps={{
|
||||
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: (
|
||||
<InputAdornment position="start">
|
||||
<SearchOutlined style={{ fontSize: 15, color: '#662582' }} />
|
||||
@@ -1412,6 +1345,7 @@ const Createorder1 = () => {
|
||||
</IconButton>
|
||||
),
|
||||
style: { borderRadius: '10px', background: '#fff' }
|
||||
}
|
||||
}}
|
||||
/>
|
||||
) : (
|
||||
@@ -1693,17 +1627,20 @@ const Createorder1 = () => {
|
||||
Address Lookup
|
||||
</Typography>
|
||||
{addId2 == 0 ? (
|
||||
<TextField
|
||||
<AddressAutocomplete
|
||||
id="addressAuto2"
|
||||
placeholder="Search Google Maps for an address..."
|
||||
variant="outlined"
|
||||
size="small"
|
||||
placeholder="Search for an address..."
|
||||
fullWidth
|
||||
value={inputValue2 || ''}
|
||||
onChange={(e) => setInputValue2(e.target.value)}
|
||||
helperText="Start typing to auto-fill the address details below"
|
||||
FormHelperTextProps={{ className: 'address-search-helper drop-helper' }}
|
||||
InputProps={{
|
||||
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: (
|
||||
<InputAdornment position="start">
|
||||
<SearchOutlined style={{ fontSize: 15, color: '#65387a' }} />
|
||||
@@ -1730,6 +1667,7 @@ const Createorder1 = () => {
|
||||
</IconButton>
|
||||
),
|
||||
style: { borderRadius: '10px', background: '#fff' }
|
||||
}
|
||||
}}
|
||||
/>
|
||||
) : (
|
||||
|
||||
@@ -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,28 +837,9 @@ 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()
|
||||
});
|
||||
|
||||
// Event listener for autocomplete place changed
|
||||
autocomplete.addListener('place_changed', () => {
|
||||
const place = autocomplete.getPlace();
|
||||
// ============================================= || Address Autocomplete (pick) || =============================================
|
||||
const handlePickPlaceSelected = (place) => {
|
||||
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}` });
|
||||
@@ -942,33 +897,11 @@ const Createorder1 = () => {
|
||||
latitude: place.geometry.location.lat(),
|
||||
longitude: place.geometry.location.lng()
|
||||
});
|
||||
console.log('Pick Address:', address);
|
||||
});
|
||||
}
|
||||
}, [inputValue1]);
|
||||
// ============================================= || Google Maps Autocomplete(Drop) || =============================================
|
||||
};
|
||||
// ============================================= || Address 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();
|
||||
const handleDropPlaceSelected = (place) => {
|
||||
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}` });
|
||||
@@ -1026,10 +959,7 @@ const Createorder1 = () => {
|
||||
latitude: place.geometry.location.lat(),
|
||||
longitude: place.geometry.location.lng()
|
||||
});
|
||||
console.log('Drop Address:', address);
|
||||
});
|
||||
}
|
||||
}, [inputValue2]);
|
||||
};
|
||||
|
||||
// ============================================= || gettenantlocations (branches) || =============================================
|
||||
const gettenantlocations = async (id) => {
|
||||
@@ -1422,15 +1352,17 @@ const Createorder1 = () => {
|
||||
<Stack spacing={1.25} sx={{ mt: 0 }}>
|
||||
{addId1 == 0 ? (
|
||||
<div>
|
||||
<TextField
|
||||
// disabled={!appId || !tenantid || !locationid}
|
||||
<AddressAutocomplete
|
||||
id="addressAuto1"
|
||||
fullWidth
|
||||
label={'Address'}
|
||||
variant="outlined"
|
||||
value={inputValue1 || ''}
|
||||
onChange={(e) => setInputValue1(e.target.value)}
|
||||
InputProps={{
|
||||
onChange={setInputValue1}
|
||||
onPlaceSelected={handlePickPlaceSelected}
|
||||
bias={{ lat: appLocaLat, lng: appLocaLng }}
|
||||
TextFieldProps={{
|
||||
variant: 'outlined',
|
||||
InputProps: {
|
||||
endAdornment: (
|
||||
<IconButton
|
||||
onClick={() => {
|
||||
@@ -1451,6 +1383,7 @@ const Createorder1 = () => {
|
||||
<CloseIcon />
|
||||
</IconButton>
|
||||
)
|
||||
}
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
@@ -1799,15 +1732,17 @@ const Createorder1 = () => {
|
||||
<Stack spacing={1.25} sx={{ mt: 0 }}>
|
||||
{addId2 == 0 ? (
|
||||
<div>
|
||||
<TextField
|
||||
// disabled={!appId || !tenantid || !locationid}
|
||||
<AddressAutocomplete
|
||||
id="addressAuto2"
|
||||
label="Address "
|
||||
variant="outlined"
|
||||
fullWidth
|
||||
value={inputValue2 || ''}
|
||||
onChange={(e) => setInputValue2(e.target.value)}
|
||||
InputProps={{
|
||||
onChange={setInputValue2}
|
||||
onPlaceSelected={handleDropPlaceSelected}
|
||||
bias={{ lat: appLocaLat, lng: appLocaLng }}
|
||||
TextFieldProps={{
|
||||
variant: 'outlined',
|
||||
InputProps: {
|
||||
endAdornment: (
|
||||
<IconButton
|
||||
onClick={() => {
|
||||
@@ -1828,6 +1763,7 @@ const Createorder1 = () => {
|
||||
<CloseIcon />
|
||||
</IconButton>
|
||||
)
|
||||
}
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
|
||||
@@ -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 <div>No route data available</div>;
|
||||
}
|
||||
|
||||
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 (
|
||||
<>
|
||||
<button
|
||||
onClick={() => setMapOpen(false)}
|
||||
style={{
|
||||
position: 'absolute',
|
||||
top: 10,
|
||||
right: 10,
|
||||
zIndex: 999,
|
||||
padding: '6px 12px',
|
||||
background: '#1A73E8',
|
||||
color: 'white',
|
||||
borderRadius: 6,
|
||||
cursor: 'pointer',
|
||||
border: 'none'
|
||||
}}
|
||||
>
|
||||
Close
|
||||
</button>
|
||||
|
||||
<LoadScriptNext googleMapsApiKey={process.env.REACT_APP_GOOGLE_MAPS_API_KEY}>
|
||||
<GoogleMap mapContainerStyle={containerStyle} center={start} zoom={14} onLoad={onMapLoad}>
|
||||
{/* Polyline and markers added via onLoad */}
|
||||
</GoogleMap>
|
||||
</LoadScriptNext>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default MapWithRouteGoogle;
|
||||
@@ -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 (
|
||||
<LoadScriptNext googleMapsApiKey={process.env.REACT_APP_GOOGLE_MAPS_API_KEY}>
|
||||
<GoogleMap mapContainerStyle={containerStyle} zoom={12} center={center}>
|
||||
<MapContainer center={center} zoom={12} style={containerStyle}>
|
||||
<TileLayer url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png" attribution="© OpenStreetMap contributors" />
|
||||
{riderLocations &&
|
||||
riderLocations?.map((r, index) => {
|
||||
riderLocations.map((r, index) => {
|
||||
const lat = Number(r.latitude);
|
||||
const lng = Number(r.longitude);
|
||||
return (
|
||||
<div key={index}>
|
||||
{/* Marker */}
|
||||
<Marker
|
||||
position={{ lat, lng }}
|
||||
icon={r.status == 'active' ? GreenIcon : RedIcon}
|
||||
label={{
|
||||
fontSize: '14px',
|
||||
fontWeight: 'bold'
|
||||
}}
|
||||
/>
|
||||
<OverlayView position={{ lat, lng }} mapPaneName={OverlayView.OVERLAY_LAYER}>
|
||||
<div
|
||||
style={{
|
||||
background: 'none',
|
||||
color: 'green',
|
||||
padding: '2px 8px',
|
||||
borderRadius: '4px',
|
||||
fontSize: '12px',
|
||||
fontWeight: 600,
|
||||
whiteSpace: 'nowrap',
|
||||
transform: 'translate(-50%, -140%)',
|
||||
pointerEvents: 'none',
|
||||
ml: 20
|
||||
}}
|
||||
>
|
||||
<Marker key={index} position={[lat, lng]} icon={r.status == 'active' ? GreenIcon : RedIcon}>
|
||||
<Tooltip permanent direction="top" offset={[0, -35]} opacity={1} className="rider-location-tooltip">
|
||||
<Button variant="contained" color="primary" size="small">
|
||||
{` ${r.username} `}
|
||||
{/* <br /> */}
|
||||
{/* {`${r.contactno || '##### ##### '} `} */}
|
||||
<br />
|
||||
{`(${r.orderid || ''}) `}
|
||||
</Button>
|
||||
</div>
|
||||
</OverlayView>
|
||||
</div>
|
||||
</Tooltip>
|
||||
</Marker>
|
||||
);
|
||||
})}
|
||||
</GoogleMap>
|
||||
</LoadScriptNext>
|
||||
</MapContainer>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,110 +1,15 @@
|
||||
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%' };
|
||||
|
||||
// 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:
|
||||
// { step, orderid, deliveryid, customer, address,
|
||||
// dropLat, dropLng, pickLat, pickLng, expectedTime }
|
||||
// `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]);
|
||||
|
||||
// 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.
|
||||
useEffect(() => {
|
||||
if (!isLoaded || 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;
|
||||
}
|
||||
if (!cancelled) setRoutePath(all);
|
||||
} catch {
|
||||
// Fall back to the straight-line skeleton on failure (quota, no route, etc.).
|
||||
if (!cancelled) setRoutePath([]);
|
||||
} finally {
|
||||
if (!cancelled) setRouteLoading(false);
|
||||
}
|
||||
})();
|
||||
|
||||
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.
|
||||
// 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';
|
||||
@@ -114,9 +19,79 @@ export default function RidersRoutes({ details, loading, riderName, dateRange, o
|
||||
`<text x="16" y="21" text-anchor="middle" font-family="Arial,sans-serif" font-size="14" font-weight="700" fill="white">${n}</text>` +
|
||||
`</svg>`
|
||||
);
|
||||
return `data:image/svg+xml;charset=UTF-8,${svg}`;
|
||||
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:
|
||||
// { step, orderid, deliveryid, customer, address,
|
||||
// dropLat, dropLng, pickLat, pickLng, expectedTime }
|
||||
// `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 [focusedStep, setFocusedStep] = useState(null);
|
||||
const [routePath, setRoutePath] = useState([]);
|
||||
const [routeLoading, setRouteLoading] = useState(false);
|
||||
|
||||
// Step-pin coordinates in planning order — what the polyline connects.
|
||||
const dropPath = useMemo(() => (details || []).map((d) => [d.dropLat, d.dropLng]), [details]);
|
||||
|
||||
// Resolve the rider's planned waypoints into an actual road-following path
|
||||
// via OSRM. Without this, the polyline would cut across buildings / aerial
|
||||
// lines — operators have no way to read the real route.
|
||||
useEffect(() => {
|
||||
if (dropPath.length < 2) {
|
||||
setRoutePath([]);
|
||||
return;
|
||||
}
|
||||
let cancelled = false;
|
||||
|
||||
(async () => {
|
||||
setRouteLoading(true);
|
||||
try {
|
||||
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([]);
|
||||
}
|
||||
} catch (e) {
|
||||
console.warn('OSRM route error:', e);
|
||||
if (!cancelled) setRoutePath([]);
|
||||
} finally {
|
||||
if (!cancelled) setRouteLoading(false);
|
||||
}
|
||||
})();
|
||||
|
||||
return () => {
|
||||
cancelled = true;
|
||||
};
|
||||
}, [dropPath]);
|
||||
|
||||
const headerBar = (
|
||||
<Stack
|
||||
direction="row"
|
||||
@@ -133,12 +108,8 @@ export default function RidersRoutes({ details, loading, riderName, dateRange, o
|
||||
>
|
||||
<MdRoute size={20} />
|
||||
<Stack sx={{ flex: 1, minWidth: 0 }}>
|
||||
<Typography sx={{ fontWeight: 700, fontSize: 15, lineHeight: 1.2 }}>
|
||||
Planned route{riderName ? ` — ${riderName}` : ''}
|
||||
</Typography>
|
||||
{dateRange && (
|
||||
<Typography sx={{ fontSize: 12, opacity: 0.85 }}>{dateRange}</Typography>
|
||||
)}
|
||||
<Typography sx={{ fontWeight: 700, fontSize: 15, lineHeight: 1.2 }}>Planned route{riderName ? ` — ${riderName}` : ''}</Typography>
|
||||
{dateRange && <Typography sx={{ fontSize: 12, opacity: 0.85 }}>{dateRange}</Typography>}
|
||||
</Stack>
|
||||
{details && details.length > 0 && (
|
||||
<Typography sx={{ fontSize: 12, opacity: 0.9, fontWeight: 600 }}>
|
||||
@@ -154,16 +125,14 @@ export default function RidersRoutes({ details, loading, riderName, dateRange, o
|
||||
</Stack>
|
||||
);
|
||||
|
||||
// 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 (
|
||||
<Box sx={{ display: 'flex', flexDirection: 'column', height: '100%' }}>
|
||||
{headerBar}
|
||||
<Stack alignItems="center" justifyContent="center" sx={{ flex: 1, gap: 1.5 }}>
|
||||
<CircularProgress size={32} />
|
||||
<Typography sx={{ color: '#64748b', fontSize: 13 }}>
|
||||
{loading ? 'Loading planned route…' : 'Loading map…'}
|
||||
</Typography>
|
||||
<Typography sx={{ color: '#64748b', fontSize: 13 }}>Loading planned route…</Typography>
|
||||
</Stack>
|
||||
</Box>
|
||||
);
|
||||
@@ -176,9 +145,7 @@ export default function RidersRoutes({ details, loading, riderName, dateRange, o
|
||||
<Box sx={{ display: 'flex', flexDirection: 'column', height: '100%' }}>
|
||||
{headerBar}
|
||||
<Stack alignItems="center" justifyContent="center" sx={{ flex: 1, gap: 1, p: 3 }}>
|
||||
<Typography sx={{ color: '#1e293b', fontWeight: 700, fontSize: 16 }}>
|
||||
No planned route for this rider
|
||||
</Typography>
|
||||
<Typography sx={{ color: '#1e293b', fontWeight: 700, fontSize: 16 }}>No planned route for this rider</Typography>
|
||||
<Typography sx={{ color: '#64748b', fontSize: 13, textAlign: 'center', maxWidth: 360 }}>
|
||||
There are no deliveries with drop coordinates assigned to this rider for the selected date range.
|
||||
</Typography>
|
||||
@@ -191,53 +158,21 @@ export default function RidersRoutes({ details, loading, riderName, dateRange, o
|
||||
<Box sx={{ display: 'flex', flexDirection: 'column', height: '100%' }}>
|
||||
{headerBar}
|
||||
<Box sx={{ flex: 1, minHeight: 0 }}>
|
||||
<GoogleMap
|
||||
mapContainerStyle={containerStyle}
|
||||
onLoad={(map) => (mapRef.current = map)}
|
||||
center={dropPath[0]}
|
||||
zoom={14}
|
||||
options={{
|
||||
streetViewControl: false,
|
||||
mapTypeControl: false,
|
||||
fullscreenControl: false
|
||||
}}
|
||||
>
|
||||
<MapContainer center={dropPath[0]} zoom={14} style={containerStyle} zoomControl={false}>
|
||||
<TileLayer url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png" attribution="© OpenStreetMap contributors" />
|
||||
<FitBoundsController dropPath={dropPath} />
|
||||
|
||||
{routePath.length > 0 ? (
|
||||
<>
|
||||
{/* Translucent backdrop so the route stays legible on busy tiles. */}
|
||||
<Polyline
|
||||
path={routePath}
|
||||
options={{ strokeColor: '#662582', strokeOpacity: 0.25, strokeWeight: 8 }}
|
||||
/>
|
||||
{/* Road-following planned route from the Directions API. */}
|
||||
<Polyline
|
||||
path={routePath}
|
||||
options={{ strokeColor: '#662582', strokeOpacity: 0.95, strokeWeight: 4 }}
|
||||
/>
|
||||
<Polyline positions={routePath} pathOptions={{ color: '#662582', opacity: 0.25, weight: 8 }} />
|
||||
{/* Road-following planned route from OSRM. */}
|
||||
<Polyline positions={routePath} pathOptions={{ color: '#662582', opacity: 0.95, weight: 4 }} />
|
||||
</>
|
||||
) : (
|
||||
// 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.
|
||||
<Polyline
|
||||
path={dropPath}
|
||||
options={{
|
||||
strokeColor: '#662582',
|
||||
strokeOpacity: 0,
|
||||
strokeWeight: 0,
|
||||
icons: [
|
||||
{
|
||||
icon: {
|
||||
path: 'M 0,-1 0,1',
|
||||
strokeOpacity: 0.6,
|
||||
strokeColor: '#662582',
|
||||
scale: 3
|
||||
},
|
||||
offset: '0',
|
||||
repeat: '14px'
|
||||
}
|
||||
]
|
||||
}}
|
||||
/>
|
||||
<Polyline positions={dropPath} pathOptions={{ color: '#662582', opacity: 0.6, weight: 3, dashArray: '2 10', lineCap: 'round' }} />
|
||||
)}
|
||||
|
||||
{details.map((d, i) => {
|
||||
@@ -246,39 +181,29 @@ export default function RidersRoutes({ details, loading, riderName, dateRange, o
|
||||
return (
|
||||
<Marker
|
||||
key={`step-${d.deliveryid || d.orderid || i}`}
|
||||
position={{ lat: d.dropLat, lng: d.dropLng }}
|
||||
icon={{ url: stepIcon(stepNum, isFocused) }}
|
||||
onClick={() => 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 && (
|
||||
<InfoWindow onCloseClick={() => setFocusedStep(null)}>
|
||||
<Popup onClose={() => setFocusedStep(null)}>
|
||||
<Box sx={{ minWidth: 180, fontFamily: 'inherit' }}>
|
||||
<Typography sx={{ fontWeight: 800, fontSize: 13, color: '#0f172a' }}>
|
||||
Step {stepNum} · {d.customer}
|
||||
</Typography>
|
||||
{d.address && (
|
||||
<Typography sx={{ fontSize: 12, color: '#475569', mt: 0.5 }}>
|
||||
{d.address}
|
||||
</Typography>
|
||||
)}
|
||||
{d.address && <Typography sx={{ fontSize: 12, color: '#475569', mt: 0.5 }}>{d.address}</Typography>}
|
||||
{d.expectedTime && (
|
||||
<Typography sx={{ fontSize: 12, color: '#64748b', mt: 0.5 }}>
|
||||
ETA {String(d.expectedTime).slice(11, 16) || d.expectedTime}
|
||||
</Typography>
|
||||
)}
|
||||
{d.orderid && (
|
||||
<Typography sx={{ fontSize: 11, color: '#94a3b8', mt: 0.5 }}>
|
||||
Order #{d.orderid}
|
||||
</Typography>
|
||||
<Typography sx={{ fontSize: 12, color: '#64748b', mt: 0.5 }}>ETA {String(d.expectedTime).slice(11, 16) || d.expectedTime}</Typography>
|
||||
)}
|
||||
{d.orderid && <Typography sx={{ fontSize: 11, color: '#94a3b8', mt: 0.5 }}>Order #{d.orderid}</Typography>}
|
||||
</Box>
|
||||
</InfoWindow>
|
||||
)}
|
||||
</Popup>
|
||||
</Marker>
|
||||
);
|
||||
})}
|
||||
</GoogleMap>
|
||||
</MapContainer>
|
||||
</Box>
|
||||
</Box>
|
||||
);
|
||||
|
||||
@@ -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
|
||||
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;
|
||||
}
|
||||
});
|
||||
console.log(response);
|
||||
}
|
||||
},
|
||||
(error) => {
|
||||
console.log(error);
|
||||
}
|
||||
);
|
||||
} catch (err) {
|
||||
console.log(err);
|
||||
}
|
||||
}, [address]);
|
||||
});
|
||||
setCity(city1 || '');
|
||||
setState1(state || '');
|
||||
setZipcode(zipcode1 || '');
|
||||
setSuburb(suburb1 || '');
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
console.log('rolesarr');
|
||||
@@ -1458,53 +1462,22 @@ const Requests = () => {
|
||||
|
||||
{/* } */}
|
||||
|
||||
<Autocomplete
|
||||
className="automap"
|
||||
apiKey={process.env.REACT_APP_GOOGLE_MAPS_API_KEY}
|
||||
style={{
|
||||
width: '100%',
|
||||
height: '40px',
|
||||
borderRadius: '5px',
|
||||
border: '1px solid #e0e0e0',
|
||||
textIndent: '10px',
|
||||
outline: 'none'
|
||||
// ':hover': {
|
||||
// border: '1px solid #00b0ff !important',
|
||||
// backgroundColor:'blue'
|
||||
// }
|
||||
}}
|
||||
onPlaceSelected={(place) => {
|
||||
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']
|
||||
}}
|
||||
<AddressAutocomplete
|
||||
id="request-address-autocomplete"
|
||||
fullWidth
|
||||
placeholder="Address"
|
||||
value={address}
|
||||
onChange={(e) => setAddress(e.target.value)}
|
||||
onChange={setAddress}
|
||||
onPlaceSelected={handleAddressPlaceSelected}
|
||||
TextFieldProps={{
|
||||
className: 'automap',
|
||||
InputProps: {
|
||||
style: {
|
||||
borderRadius: '5px',
|
||||
border: '1px solid #e0e0e0'
|
||||
}
|
||||
}
|
||||
}}
|
||||
/>
|
||||
</Stack>
|
||||
</Grid>
|
||||
|
||||
@@ -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
|
||||
let active = true;
|
||||
geocodeAddress(address).then((place) => {
|
||||
if (active && place) {
|
||||
setLatlong({ lat: place.geometry.location.lat(), lng: place.geometry.location.lng() });
|
||||
}
|
||||
});
|
||||
console.log(response);
|
||||
}
|
||||
},
|
||||
(error) => {
|
||||
console.log(error);
|
||||
}
|
||||
);
|
||||
} catch (err) {
|
||||
console.log(err);
|
||||
}
|
||||
return () => {
|
||||
active = false;
|
||||
};
|
||||
}, [address]);
|
||||
|
||||
const opentoast = (message) => {
|
||||
@@ -119,11 +104,7 @@ const Createrider = () => {
|
||||
}
|
||||
}, [selectedImage]);
|
||||
|
||||
const { ref: materialRef } = usePlacesWidget({
|
||||
apiKey: process.env.REACT_APP_GOOGLE_MAPS_API_KEY,
|
||||
onPlaceSelected: (place) => {
|
||||
console.log(place);
|
||||
|
||||
const handleAddressPlaceSelected = (place) => {
|
||||
setAddress(place.formatted_address);
|
||||
let city1, zipcode1, state1, suburb1;
|
||||
for (let i = 0; i < place.address_components.length; i++) {
|
||||
@@ -139,6 +120,7 @@ const Createrider = () => {
|
||||
zipcode1 = place.address_components[i].long_name;
|
||||
break;
|
||||
case 'sublocality':
|
||||
case 'sublocality_level_1':
|
||||
suburb1 = place.address_components[i].long_name;
|
||||
break;
|
||||
}
|
||||
@@ -148,16 +130,7 @@ const Createrider = () => {
|
||||
setState(state1 || '');
|
||||
setZipcode(zipcode1 || '');
|
||||
setSuburb(suburb1 || '');
|
||||
|
||||
// setAddress(place.formatted_address)
|
||||
},
|
||||
// inputAutocompleteValue: "country",
|
||||
options: {
|
||||
// componentRestrictions: 'us',
|
||||
// types: ["establishment"]
|
||||
types: ['address' || 'geocode']
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
const createprofile = async () => {
|
||||
console.log('res', businessname, businessno, mobilenumber, emailaddress, address, city, zipcode);
|
||||
@@ -340,14 +313,13 @@ const Createrider = () => {
|
||||
<Grid item xs={12}>
|
||||
<Stack spacing={1.25}>
|
||||
<InputLabel htmlFor="personal-address">Address</InputLabel>
|
||||
<TextField
|
||||
fullWidth
|
||||
// defaultValue="Street 110-B Kalians Bag, Dewan, M.P. New York"
|
||||
<AddressAutocomplete
|
||||
id="personal-address"
|
||||
fullWidth
|
||||
placeholder="Address"
|
||||
value={address}
|
||||
onChange={(e) => setAddress(e.target.value)}
|
||||
inputRef={materialRef}
|
||||
onChange={setAddress}
|
||||
onPlaceSelected={handleAddressPlaceSelected}
|
||||
/>
|
||||
</Stack>
|
||||
</Grid>
|
||||
|
||||
@@ -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,13 +234,10 @@ const EditRider = () => {
|
||||
}
|
||||
}, [selectedImage]);
|
||||
|
||||
const { ref: materialRef } = usePlacesWidget({
|
||||
apiKey: process.env.REACT_APP_GOOGLE_MAPS_API_KEY,
|
||||
onPlaceSelected: (place) => {
|
||||
console.log(place);
|
||||
const handleAddressPlaceSelected = (place) => {
|
||||
setAddress(place.formatted_address);
|
||||
|
||||
let city1, zipcode1, state1, suburb1;
|
||||
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]) {
|
||||
@@ -253,30 +247,17 @@ const EditRider = () => {
|
||||
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']
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
const updateRider = async () => {
|
||||
setLoading(true);
|
||||
@@ -483,16 +464,13 @@ const EditRider = () => {
|
||||
<Grid item xs={12}>
|
||||
<Stack spacing={1.25}>
|
||||
<InputLabel htmlFor="personal-address">Address</InputLabel>
|
||||
<TextField
|
||||
fullWidth
|
||||
// defaultValue="Street 110-B Kalians Bag, Dewan, M.P. New York"
|
||||
<AddressAutocomplete
|
||||
id="personal-address"
|
||||
fullWidth
|
||||
placeholder="Address"
|
||||
value={address}
|
||||
onChange={(e) => {
|
||||
setAddress(e.target.value);
|
||||
}}
|
||||
inputRef={materialRef}
|
||||
onChange={setAddress}
|
||||
onPlaceSelected={handleAddressPlaceSelected}
|
||||
/>
|
||||
</Stack>
|
||||
</Grid>
|
||||
|
||||
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user