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
|
## Backend API URL
|
||||||
REACT_APP_API_URL=https://mock-data-api-nextjs.vercel.app/
|
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_URL=https://jupiter.nearle.app/live/api/v1
|
||||||
REACT_APP_URL2=https://jupiter.nearle.app/live/api/v2
|
REACT_APP_URL2=https://jupiter.nearle.app/live/api/v2
|
||||||
REACT_APP_URL3=https://jupiter.nearle.app/live/api/v3
|
REACT_APP_URL3=https://jupiter.nearle.app/live/api/v3
|
||||||
REACT_APP_STAFF_TOKEN=
|
REACT_APP_STAFF_TOKEN=
|
||||||
REACT_APP_GOOGLE_MAPS_API_KEY=AIzaSyCF4KatYCI3vqz1_H3kiHeyS3yCMfYToh8
|
|
||||||
REACT_APP_RIDER_ACCESS_ID=AAAAILMpCEU:APA91bEavuOllBI6sFgYtxXAgNmAVwNA-MnCMHLGlR4_t7UqpLajAkdn3T0CZr_zaLBknLyim9ytFLMZgbeXmKqTad_PKCbqlYjHpaizVrLXtecxqyEy4UktIacK2UvHVUATHL-7VQQk
|
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_URL2=https://jupiter.nearle.app/live/api/v2
|
||||||
REACT_APP_URL3=https://jupiter.nearle.app/live/api/v3
|
REACT_APP_URL3=https://jupiter.nearle.app/live/api/v3
|
||||||
REACT_APP_STAFF_TOKEN=
|
REACT_APP_STAFF_TOKEN=
|
||||||
REACT_APP_GOOGLE_MAPS_API_KEY=AIzaSyCF4KatYCI3vqz1_H3kiHeyS3yCMfYToh8
|
|
||||||
REACT_APP_RIDER_ACCESS_ID=AAAAILMpCEU:APA91bEavuOllBI6sFgYtxXAgNmAVwNA-MnCMHLGlR4_t7UqpLajAkdn3T0CZr_zaLBknLyim9ytFLMZgbeXmKqTad_PKCbqlYjHpaizVrLXtecxqyEy4UktIacK2UvHVUATHL-7VQQk
|
REACT_APP_RIDER_ACCESS_ID=AAAAILMpCEU:APA91bEavuOllBI6sFgYtxXAgNmAVwNA-MnCMHLGlR4_t7UqpLajAkdn3T0CZr_zaLBknLyim9ytFLMZgbeXmKqTad_PKCbqlYjHpaizVrLXtecxqyEy4UktIacK2UvHVUATHL-7VQQk
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -13,12 +13,10 @@
|
|||||||
"@mui/lab": "^5.0.0-alpha.127",
|
"@mui/lab": "^5.0.0-alpha.127",
|
||||||
"@mui/material": "^5.12.1",
|
"@mui/material": "^5.12.1",
|
||||||
"@mui/x-date-pickers": "^6.18.2",
|
"@mui/x-date-pickers": "^6.18.2",
|
||||||
"@react-google-maps/api": "^2.20.7",
|
|
||||||
"@reduxjs/toolkit": "^1.9.5",
|
"@reduxjs/toolkit": "^1.9.5",
|
||||||
"@svgr/webpack": "^7.0.0",
|
"@svgr/webpack": "^7.0.0",
|
||||||
"@tanstack/react-query": "^5.17.9",
|
"@tanstack/react-query": "^5.17.9",
|
||||||
"antd": "^5.11.5",
|
"antd": "^5.11.5",
|
||||||
"autosuggest-highlight": "^3.3.4",
|
|
||||||
"axios": "^1.3.5",
|
"axios": "^1.3.5",
|
||||||
"buffer": "^6.0.3",
|
"buffer": "^6.0.3",
|
||||||
"chance": "^1.1.11",
|
"chance": "^1.1.11",
|
||||||
@@ -45,8 +43,6 @@
|
|||||||
"react-dnd": "^16.0.1",
|
"react-dnd": "^16.0.1",
|
||||||
"react-dnd-html5-backend": "^16.0.1",
|
"react-dnd-html5-backend": "^16.0.1",
|
||||||
"react-dom": "^18.2.0",
|
"react-dom": "^18.2.0",
|
||||||
"react-geocode": "^0.2.3",
|
|
||||||
"react-google-autocomplete": "^2.7.3",
|
|
||||||
"react-icons": "^4.12.0",
|
"react-icons": "^4.12.0",
|
||||||
"react-intl": "^6.4.1",
|
"react-intl": "^6.4.1",
|
||||||
"react-leaflet": "^4.2.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 MainCard from 'components/MainCard';
|
||||||
import axios from 'axios';
|
import axios from 'axios';
|
||||||
import { useTheme } from '@mui/material/styles';
|
import { useTheme } from '@mui/material/styles';
|
||||||
@@ -6,10 +6,7 @@ import Loader from 'components/Loader';
|
|||||||
import { Empty } from 'antd';
|
import { Empty } from 'antd';
|
||||||
import dayjs from 'dayjs';
|
import dayjs from 'dayjs';
|
||||||
import { enqueueSnackbar } from 'notistack';
|
import { enqueueSnackbar } from 'notistack';
|
||||||
import Geocode from 'react-geocode';
|
import AddressAutocomplete from 'components/nearle_components/AddressAutocomplete';
|
||||||
import LocationOnIcon from '@mui/icons-material/LocationOn';
|
|
||||||
import parse from 'autosuggest-highlight/parse';
|
|
||||||
import { debounce } from '@mui/material/utils';
|
|
||||||
import {
|
import {
|
||||||
Stack,
|
Stack,
|
||||||
Table,
|
Table,
|
||||||
@@ -184,7 +181,6 @@ const Clients1 = () => {
|
|||||||
const [appId, setAppId] = useState(0);
|
const [appId, setAppId] = useState(0);
|
||||||
const [locaName, setLocoName] = useState('');
|
const [locaName, setLocoName] = useState('');
|
||||||
const [locations] = useState('All');
|
const [locations] = useState('All');
|
||||||
const [value, setValue] = React.useState(null);
|
|
||||||
const [value0, setValue0] = useState(0);
|
const [value0, setValue0] = useState(0);
|
||||||
const [value1, setValue1] = useState(0);
|
const [value1, setValue1] = useState(0);
|
||||||
const [value2, setValue2] = useState(0);
|
const [value2, setValue2] = useState(0);
|
||||||
@@ -196,7 +192,6 @@ const Clients1 = () => {
|
|||||||
const [appPricing, setAppPricing] = useState([]);
|
const [appPricing, setAppPricing] = useState([]);
|
||||||
const [selectedPricing, setSelectedPricing] = useState({});
|
const [selectedPricing, setSelectedPricing] = useState({});
|
||||||
const [isPrice, setIsprice] = useState(true);
|
const [isPrice, setIsprice] = useState(true);
|
||||||
const [address, setAddress] = useState('');
|
|
||||||
const [city, setCity] = useState('');
|
const [city, setCity] = useState('');
|
||||||
const [zipcode, setZipcode] = useState('');
|
const [zipcode, setZipcode] = useState('');
|
||||||
const [latlong, setLatlong] = useState({});
|
const [latlong, setLatlong] = useState({});
|
||||||
@@ -258,144 +253,50 @@ const Clients1 = () => {
|
|||||||
autoHideDuration: duration
|
autoHideDuration: duration
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
// ==============================|| google address ||============================== //
|
// ==============================|| address autocomplete ||============================== //
|
||||||
const GOOGLE_MAPS_API_KEY = process.env.REACT_APP_GOOGLE_MAPS_API_KEY;
|
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) {
|
let city1, zipcode1, state1, suburb1;
|
||||||
if (!position) {
|
place.address_components.forEach((component) => {
|
||||||
return;
|
component.types.forEach((type) => {
|
||||||
}
|
switch (type) {
|
||||||
|
case 'locality':
|
||||||
const script = document.createElement('script');
|
city1 = component.long_name;
|
||||||
script.setAttribute('async', '');
|
break;
|
||||||
script.setAttribute('id', id);
|
case 'administrative_area_level_1':
|
||||||
script.src = src;
|
state1 = component.long_name;
|
||||||
position.appendChild(script);
|
break;
|
||||||
}
|
case 'postal_code':
|
||||||
|
zipcode1 = component.long_name;
|
||||||
const autocompleteService = { current: null };
|
break;
|
||||||
// ==============================|| for google address ||============================== //
|
case 'sublocality':
|
||||||
const [inputValue, setInputValue] = useState('');
|
case 'sublocality_level_1':
|
||||||
const [options, setOptions] = useState([]);
|
suburb1 = component.long_name;
|
||||||
const loaded = useRef(false);
|
break;
|
||||||
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);
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
setCity(city1 || '');
|
||||||
return () => {
|
setState(state1 || '');
|
||||||
active = false;
|
setZipcode(zipcode1 || '');
|
||||||
};
|
setSuburb(suburb1 || '');
|
||||||
}, [value, inputValue, fetch]);
|
setEditClient((prev) => ({
|
||||||
|
...prev,
|
||||||
Geocode.setApiKey(process.env.REACT_APP_GOOGLE_MAPS_API_KEY);
|
city: city1 || '',
|
||||||
useEffect(() => {
|
state: state1 || '',
|
||||||
try {
|
postcode: zipcode1 || '',
|
||||||
console.log('selected address =>', address);
|
suburb: suburb1 || ''
|
||||||
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]);
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
selectedCustomer &&
|
selectedCustomer &&
|
||||||
@@ -1562,85 +1463,19 @@ const Clients1 = () => {
|
|||||||
/>
|
/>
|
||||||
</Grid>
|
</Grid>
|
||||||
<Grid item xs zeroMinWidth>
|
<Grid item xs zeroMinWidth>
|
||||||
<Autocomplete
|
<AddressAutocomplete
|
||||||
id="google-map-demo"
|
id="address-autocomplete"
|
||||||
sx={{}}
|
|
||||||
fullWidth
|
fullWidth
|
||||||
label={'Address'}
|
label="Address"
|
||||||
getOptionLabel={(option) => (typeof option === 'string' ? option : option.description)}
|
value={editClient?.address ?? selectedCustomer.address ?? ''}
|
||||||
filterOptions={(x) => x}
|
onChange={(text) =>
|
||||||
options={options}
|
setEditClient((prev) => ({
|
||||||
autoComplete
|
...prev,
|
||||||
includeInputInList
|
address: text
|
||||||
filterSelectedOptions
|
}))
|
||||||
defaultValue={selectedCustomer.address}
|
}
|
||||||
noOptionsText="No locations"
|
onPlaceSelected={handleAddressPlaceSelected}
|
||||||
onChange={(event, newValue) => {
|
TextFieldProps={{ variant: 'outlined' }}
|
||||||
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>
|
|
||||||
);
|
|
||||||
}}
|
|
||||||
/>
|
/>
|
||||||
</Grid>
|
</Grid>
|
||||||
</Grid>
|
</Grid>
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import { Button, Grid, InputLabel, MenuItem, Select, Stack, TextField, Typograph
|
|||||||
import MainCard from 'components/MainCard';
|
import MainCard from 'components/MainCard';
|
||||||
import axios from 'axios';
|
import axios from 'axios';
|
||||||
import Loader from 'components/Loader';
|
import Loader from 'components/Loader';
|
||||||
import Geocode from 'react-geocode';
|
import AddressAutocomplete from 'components/nearle_components/AddressAutocomplete';
|
||||||
import { enqueueSnackbar } from 'notistack';
|
import { enqueueSnackbar } from 'notistack';
|
||||||
import { useNavigate } from 'react-router';
|
import { useNavigate } from 'react-router';
|
||||||
import CloseIcon from '@mui/icons-material/Close';
|
import CloseIcon from '@mui/icons-material/Close';
|
||||||
@@ -25,7 +25,6 @@ const CreateCustomer = () => {
|
|||||||
const [inputValue2, setInputValue2] = useState('');
|
const [inputValue2, setInputValue2] = useState('');
|
||||||
const [appLocaLat, setAppLocaLat] = useState();
|
const [appLocaLat, setAppLocaLat] = useState();
|
||||||
const [appLocaLng, setAppLocaLng] = useState();
|
const [appLocaLng, setAppLocaLng] = useState();
|
||||||
const [appLocaRadius, setAppLocaRadius] = useState();
|
|
||||||
const [locaName, setLocoName] = useState('Select Location');
|
const [locaName, setLocoName] = useState('Select Location');
|
||||||
const [tenantlist, setTenantlist] = useState([]);
|
const [tenantlist, setTenantlist] = useState([]);
|
||||||
const [tid, setTid] = useState(0);
|
const [tid, setTid] = useState(0);
|
||||||
@@ -34,92 +33,68 @@ const CreateCustomer = () => {
|
|||||||
const [loading, setLoading] = useState(false);
|
const [loading, setLoading] = useState(false);
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
|
|
||||||
Geocode.setApiKey(process.env.REACT_APP_GOOGLE_MAPS_API_KEY);
|
const handlePlaceSelected = (place) => {
|
||||||
|
setInputValue2(`${place.name}, ${place.formatted_address}`);
|
||||||
useEffect(() => {
|
// to trigger getDistance
|
||||||
// Initialize Google Maps Autocomplete
|
setStartPoint({ latitude: place.geometry.location.lat(), longitude: place.geometry.location.lng() });
|
||||||
if (inputValue2) {
|
setAddress(`${place.name} ${place.formatted_address}`);
|
||||||
const autocompleteInput = document.getElementById('addressAuto1');
|
setPickCust({ ...pickCust, address: `${place.name} ${place.formatted_address}` });
|
||||||
const autocomplete = new window.google.maps.places.Autocomplete(autocompleteInput, {
|
const address = {
|
||||||
// types: ['(cities)'], // You can adjust the types parameter based on your requirements
|
address: `${place.name} ${place.formatted_address}`,
|
||||||
strictBounds: true,
|
street_number: '',
|
||||||
bounds: new window.google.maps.Circle({
|
route: '',
|
||||||
// center: new window.google.maps.LatLng(11.0050707, 76.9509083),
|
locality: '',
|
||||||
// radius: 100000
|
sublocality_level_1: '',
|
||||||
center: new window.google.maps.LatLng(appLocaLat, appLocaLng),
|
administrative_area_level_3: '',
|
||||||
|
administrative_area_level_1: '',
|
||||||
radius: appLocaRadius * 1000
|
country: '',
|
||||||
}).getBounds()
|
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
|
// Use address object as per your requirements
|
||||||
setPickCust({
|
setPickCust({
|
||||||
...pickCust,
|
...pickCust,
|
||||||
address: address.address,
|
address: address.address,
|
||||||
doorno: `${address.street_number} ${address.route}`,
|
doorno: `${address.street_number} ${address.route}`,
|
||||||
suburb: address.administrative_area_level_3,
|
suburb: address.administrative_area_level_3,
|
||||||
city: address.locality,
|
city: address.locality,
|
||||||
state: address.administrative_area_level_1,
|
state: address.administrative_area_level_1,
|
||||||
postcode: address.postal_code,
|
postcode: address.postal_code,
|
||||||
latitude: place.geometry.location.lat(),
|
latitude: place.geometry.location.lat(),
|
||||||
longitude: place.geometry.location.lng()
|
longitude: place.geometry.location.lng()
|
||||||
});
|
});
|
||||||
console.log('Pick Address:', address);
|
};
|
||||||
});
|
|
||||||
}
|
|
||||||
}, [inputValue2]);
|
|
||||||
// ==================================================== || getapplocations || ====================================================
|
// ==================================================== || getapplocations || ====================================================
|
||||||
const getapplocations = async () => {
|
const getapplocations = async () => {
|
||||||
setLoading(true);
|
setLoading(true);
|
||||||
@@ -127,12 +102,10 @@ const CreateCustomer = () => {
|
|||||||
.get(`${process.env.REACT_APP_URL}/utils/getapplocations/?applocationid=${appId}`)
|
.get(`${process.env.REACT_APP_URL}/utils/getapplocations/?applocationid=${appId}`)
|
||||||
.then((res) => {
|
.then((res) => {
|
||||||
console.log('getapplocations', res);
|
console.log('getapplocations', res);
|
||||||
const { latitude, longitude, radius } = res.data.details[0];
|
const { latitude, longitude } = res.data.details[0];
|
||||||
if (res.data.status) {
|
if (res.data.status) {
|
||||||
setAppLocaLat(latitude);
|
setAppLocaLat(latitude);
|
||||||
setAppLocaLng(longitude);
|
setAppLocaLng(longitude);
|
||||||
setAppLocaRadius(radius);
|
|
||||||
console.log('radius', radius);
|
|
||||||
}
|
}
|
||||||
setLoading(false);
|
setLoading(false);
|
||||||
})
|
})
|
||||||
@@ -380,38 +353,42 @@ const CreateCustomer = () => {
|
|||||||
<Grid item xs={12}>
|
<Grid item xs={12}>
|
||||||
<Stack spacing={1.25}>
|
<Stack spacing={1.25}>
|
||||||
<InputLabel htmlFor="personal-email"> Address</InputLabel>
|
<InputLabel htmlFor="personal-email"> Address</InputLabel>
|
||||||
<TextField
|
<AddressAutocomplete
|
||||||
variant="outlined"
|
|
||||||
id="addressAuto1"
|
id="addressAuto1"
|
||||||
fullWidth
|
fullWidth
|
||||||
value={inputValue2}
|
value={inputValue2}
|
||||||
onChange={(e) => {
|
onChange={(text) => {
|
||||||
if (appId) {
|
if (appId) {
|
||||||
appId && setInputValue2(e.target.value);
|
setInputValue2(text);
|
||||||
} else {
|
} else {
|
||||||
OpenToast('Select Location First', 'warning', 3000);
|
OpenToast('Select Location First', 'warning', 3000);
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
InputProps={{
|
onPlaceSelected={handlePlaceSelected}
|
||||||
endAdornment: (
|
bias={{ lat: appLocaLat, lng: appLocaLng }}
|
||||||
<IconButton
|
TextFieldProps={{
|
||||||
onClick={() => {
|
variant: 'outlined',
|
||||||
setInputValue2('');
|
InputProps: {
|
||||||
setPickCust({
|
endAdornment: (
|
||||||
...pickCust,
|
<IconButton
|
||||||
doorno: '',
|
onClick={() => {
|
||||||
suburb: '',
|
setInputValue2('');
|
||||||
city: '',
|
setPickCust({
|
||||||
postcode: '',
|
...pickCust,
|
||||||
landmark: ''
|
doorno: '',
|
||||||
});
|
suburb: '',
|
||||||
setStartPoint({ latitude: 0, longitude: 0 });
|
city: '',
|
||||||
}}
|
postcode: '',
|
||||||
size="small"
|
landmark: ''
|
||||||
>
|
});
|
||||||
<CloseIcon />
|
setStartPoint({ latitude: 0, longitude: 0 });
|
||||||
</IconButton>
|
}}
|
||||||
)
|
size="small"
|
||||||
|
>
|
||||||
|
<CloseIcon />
|
||||||
|
</IconButton>
|
||||||
|
)
|
||||||
|
}
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
</Stack>
|
</Stack>
|
||||||
|
|||||||
@@ -10,12 +10,10 @@ import { Box, Button, FormLabel, Grid, InputLabel, MenuItem, Select, Stack, Text
|
|||||||
// project import
|
// project import
|
||||||
import MainCard from 'components/MainCard';
|
import MainCard from 'components/MainCard';
|
||||||
import axios from 'axios';
|
import axios from 'axios';
|
||||||
import { usePlacesWidget } from 'react-google-autocomplete';
|
import AddressAutocomplete, { geocodeAddress } from 'components/nearle_components/AddressAutocomplete';
|
||||||
import Loader from 'components/Loader';
|
import Loader from 'components/Loader';
|
||||||
import Geocode from 'react-geocode';
|
|
||||||
import { enqueueSnackbar } from 'notistack';
|
import { enqueueSnackbar } from 'notistack';
|
||||||
import { useNavigate } from 'react-router';
|
import { useNavigate } from 'react-router';
|
||||||
// import { setLocationType } from 'react-geocode';
|
|
||||||
|
|
||||||
// const avatarImage = require.context('assets/images/users', true);
|
// const avatarImage = require.context('assets/images/users', true);
|
||||||
|
|
||||||
@@ -49,9 +47,6 @@ const Createclient = () => {
|
|||||||
|
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
|
|
||||||
Geocode.setApiKey(process.env.REACT_APP_GOOGLE_MAPS_API_KEY);
|
|
||||||
// Geocode.setApiKey('AIzaSyCF4KatYCI3vqz1_H3kiHeyS3yCMfYToh8');
|
|
||||||
|
|
||||||
const [loading, setLoading] = useState(false);
|
const [loading, setLoading] = useState(false);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@@ -63,25 +58,15 @@ const Createclient = () => {
|
|||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
try {
|
let active = true;
|
||||||
Geocode.fromAddress(address).then(
|
geocodeAddress(address).then((place) => {
|
||||||
(response) => {
|
if (active && place) {
|
||||||
if (response.status == 'OK') {
|
setLatlong({ lat: place.geometry.location.lat(), lng: place.geometry.location.lng() });
|
||||||
const { lat, lng } = response.results[0].geometry.location;
|
}
|
||||||
setLatlong({
|
});
|
||||||
lat,
|
return () => {
|
||||||
lng
|
active = false;
|
||||||
});
|
};
|
||||||
console.log(response);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
(error) => {
|
|
||||||
console.log(error);
|
|
||||||
}
|
|
||||||
);
|
|
||||||
} catch (err) {
|
|
||||||
console.log(err);
|
|
||||||
}
|
|
||||||
}, [address]);
|
}, [address]);
|
||||||
|
|
||||||
const opentoast = (message) => {
|
const opentoast = (message) => {
|
||||||
@@ -151,45 +136,33 @@ const Createclient = () => {
|
|||||||
}
|
}
|
||||||
}, [selectedImage]);
|
}, [selectedImage]);
|
||||||
|
|
||||||
const { ref: materialRef } = usePlacesWidget({
|
const handleAddressPlaceSelected = (place) => {
|
||||||
apiKey: process.env.REACT_APP_GOOGLE_MAPS_API_KEY,
|
setAddress(place.formatted_address);
|
||||||
onPlaceSelected: (place) => {
|
let city1, zipcode1, state1, suburb1;
|
||||||
console.log(place);
|
for (let i = 0; i < place.address_components.length; i++) {
|
||||||
|
for (let j = 0; j < place.address_components[i].types.length; j++) {
|
||||||
setAddress(place.formatted_address);
|
switch (place.address_components[i].types[j]) {
|
||||||
let city1, zipcode1, state1, suburb1;
|
case 'locality':
|
||||||
for (let i = 0; i < place.address_components.length; i++) {
|
city1 = place.address_components[i].long_name;
|
||||||
for (let j = 0; j < place.address_components[i].types.length; j++) {
|
break;
|
||||||
switch (place.address_components[i].types[j]) {
|
case 'administrative_area_level_1':
|
||||||
case 'locality':
|
state1 = place.address_components[i].long_name;
|
||||||
city1 = place.address_components[i].long_name;
|
break;
|
||||||
break;
|
case 'postal_code':
|
||||||
case 'administrative_area_level_1':
|
zipcode1 = place.address_components[i].long_name;
|
||||||
state1 = place.address_components[i].long_name;
|
break;
|
||||||
break;
|
case 'sublocality':
|
||||||
case 'postal_code':
|
case 'sublocality_level_1':
|
||||||
zipcode1 = place.address_components[i].long_name;
|
suburb1 = place.address_components[i].long_name;
|
||||||
break;
|
break;
|
||||||
case 'sublocality':
|
|
||||||
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 () => {
|
const createprofile = async () => {
|
||||||
console.log('res', businessname, businessno, mobilenumber, emailaddress, address, city, zipcode);
|
console.log('res', businessname, businessno, mobilenumber, emailaddress, address, city, zipcode);
|
||||||
@@ -486,14 +459,13 @@ const Createclient = () => {
|
|||||||
<Grid item xs={12}>
|
<Grid item xs={12}>
|
||||||
<Stack spacing={1.25}>
|
<Stack spacing={1.25}>
|
||||||
<InputLabel htmlFor="personal-address">Address</InputLabel>
|
<InputLabel htmlFor="personal-address">Address</InputLabel>
|
||||||
<TextField
|
<AddressAutocomplete
|
||||||
fullWidth
|
|
||||||
// defaultValue="Street 110-B Kalians Bag, Dewan, M.P. New York"
|
|
||||||
id="personal-address"
|
id="personal-address"
|
||||||
|
fullWidth
|
||||||
placeholder="Address"
|
placeholder="Address"
|
||||||
value={address}
|
value={address}
|
||||||
onChange={(e) => setAddress(e.target.value)}
|
onChange={setAddress}
|
||||||
inputRef={materialRef}
|
onPlaceSelected={handleAddressPlaceSelected}
|
||||||
/>
|
/>
|
||||||
</Stack>
|
</Stack>
|
||||||
</Grid>
|
</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 axios from 'axios';
|
||||||
import { FaRegEdit } from 'react-icons/fa';
|
import { FaRegEdit } from 'react-icons/fa';
|
||||||
import LoaderWithImage from 'components/nearle_components/LoaderWithImage';
|
import LoaderWithImage from 'components/nearle_components/LoaderWithImage';
|
||||||
@@ -23,7 +23,6 @@ import {
|
|||||||
DialogContent,
|
DialogContent,
|
||||||
Button,
|
Button,
|
||||||
TextField,
|
TextField,
|
||||||
Autocomplete,
|
|
||||||
Avatar,
|
Avatar,
|
||||||
Paper,
|
Paper,
|
||||||
useMediaQuery,
|
useMediaQuery,
|
||||||
@@ -42,12 +41,9 @@ import {
|
|||||||
MdOutlineHowToReg,
|
MdOutlineHowToReg,
|
||||||
MdOutlinePlace
|
MdOutlinePlace
|
||||||
} from 'react-icons/md';
|
} 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
|
// project imports
|
||||||
import Loader from 'components/Loader';
|
import Loader from 'components/Loader';
|
||||||
|
import AddressAutocomplete from 'components/nearle_components/AddressAutocomplete';
|
||||||
import DebounceSearchBar from 'components/nearle_components/DebounceSearchBar';
|
import DebounceSearchBar from 'components/nearle_components/DebounceSearchBar';
|
||||||
import LocationAutocomplete from 'components/nearle_components/LocationAutocomplete';
|
import LocationAutocomplete from 'components/nearle_components/LocationAutocomplete';
|
||||||
import PageHeader from 'components/nearle_components/PageHeader';
|
import PageHeader from 'components/nearle_components/PageHeader';
|
||||||
@@ -111,23 +107,6 @@ const AccentAvatar = ({ color, selected, size = 24, children }) => (
|
|||||||
</Avatar>
|
</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 ||============================== //
|
// ==============================|| MUI TABLE - ENHANCED ||============================== //
|
||||||
|
|
||||||
export default function Customers() {
|
export default function Customers() {
|
||||||
@@ -141,7 +120,6 @@ export default function Customers() {
|
|||||||
const [locaName, setLocoName] = useState('All');
|
const [locaName, setLocoName] = useState('All');
|
||||||
const [selectedCustomer, setSelectedCustomer] = useState({}); // to edit
|
const [selectedCustomer, setSelectedCustomer] = useState({}); // to edit
|
||||||
const [open, setOpen] = useState(false);
|
const [open, setOpen] = useState(false);
|
||||||
const [address, setAddress] = useState('');
|
|
||||||
const [latlong, setLatlong] = useState({});
|
const [latlong, setLatlong] = useState({});
|
||||||
const [city, setCity] = useState('');
|
const [city, setCity] = useState('');
|
||||||
const [postcode, setPostcode] = useState('');
|
const [postcode, setPostcode] = useState('');
|
||||||
@@ -150,136 +128,47 @@ export default function Customers() {
|
|||||||
const [searchword, setSearchword] = useState('');
|
const [searchword, setSearchword] = useState('');
|
||||||
const [debouncedSearch, setDebouncedSearch] = useState('');
|
const [debouncedSearch, setDebouncedSearch] = useState('');
|
||||||
|
|
||||||
// ==============================|| for google address ||============================== //
|
// ==============================|| address autocomplete ||============================== //
|
||||||
const [value, setValue] = useState(null);
|
const handleAddressPlaceSelected = (place) => {
|
||||||
const [inputValue, setInputValue] = useState('');
|
const lat = place.geometry.location.lat();
|
||||||
const [options, setOptions] = useState([]);
|
const lng = place.geometry.location.lng();
|
||||||
const loaded = useRef(false);
|
setLatlong({ lat, lng });
|
||||||
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;
|
let city1, zipcode1, state1, suburb1;
|
||||||
}
|
place.address_components.forEach((component) => {
|
||||||
const fetch = useMemo(
|
component.types.forEach((type) => {
|
||||||
() =>
|
switch (type) {
|
||||||
debounce((request, callback) => {
|
case 'locality':
|
||||||
autocompleteService.current.getPlacePredictions(request, callback);
|
city1 = component.long_name;
|
||||||
}, 400),
|
break;
|
||||||
[]
|
case 'administrative_area_level_1':
|
||||||
);
|
state1 = component.long_name;
|
||||||
useEffect(() => {
|
break;
|
||||||
let active = true;
|
case 'postal_code':
|
||||||
|
zipcode1 = component.long_name;
|
||||||
if (!autocompleteService.current && window.google) {
|
break;
|
||||||
autocompleteService.current = new window.google.maps.places.AutocompleteService();
|
case 'sublocality':
|
||||||
}
|
case 'sublocality_level_1':
|
||||||
if (!autocompleteService.current) {
|
suburb1 = component.long_name;
|
||||||
return undefined;
|
break;
|
||||||
}
|
|
||||||
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
setCity(city1 || '');
|
||||||
return () => {
|
setState(state1 || '');
|
||||||
active = false;
|
setPostcode(zipcode1 || '');
|
||||||
};
|
setSuburb(suburb1 || '');
|
||||||
}, [value, inputValue, fetch]);
|
setSelectedCustomer((prev) => ({
|
||||||
|
...prev,
|
||||||
Geocode.setApiKey(process.env.REACT_APP_GOOGLE_MAPS_API_KEY);
|
address: place.formatted_address,
|
||||||
useEffect(() => {
|
city: city1 || '',
|
||||||
try {
|
state: state1 || '',
|
||||||
console.log('selected address =>', address);
|
postcode: zipcode1 || '',
|
||||||
Geocode.fromAddress(address).then(
|
suburb: suburb1 || '',
|
||||||
(response) => {
|
latitude: lat || '',
|
||||||
console.log('lat long response =>', response.results[0]);
|
longitude: lng || ''
|
||||||
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]);
|
|
||||||
|
|
||||||
// ==============================|| getallcustomers (customers) ||============================== //
|
// ==============================|| getallcustomers (customers) ||============================== //
|
||||||
|
|
||||||
@@ -891,72 +780,17 @@ export default function Customers() {
|
|||||||
</Grid>
|
</Grid>
|
||||||
<Grid item xs={12}>
|
<Grid item xs={12}>
|
||||||
<Typography sx={{ mb: 1 }}>Address</Typography>
|
<Typography sx={{ mb: 1 }}>Address</Typography>
|
||||||
<Autocomplete
|
<AddressAutocomplete
|
||||||
id="google-map-demo"
|
id="address-autocomplete"
|
||||||
sx={{}}
|
|
||||||
fullWidth
|
fullWidth
|
||||||
getOptionLabel={(option) => (typeof option === 'string' ? option : option?.description || '')}
|
value={selectedCustomer?.address || ''}
|
||||||
filterOptions={(x) => x}
|
onChange={(text) =>
|
||||||
options={options}
|
setSelectedCustomer((prev) => ({
|
||||||
autoComplete
|
...prev,
|
||||||
includeInputInList
|
address: text
|
||||||
filterSelectedOptions
|
}))
|
||||||
value={selectedCustomer?.address}
|
}
|
||||||
noOptionsText="No locations"
|
onPlaceSelected={handleAddressPlaceSelected}
|
||||||
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>
|
|
||||||
);
|
|
||||||
}}
|
|
||||||
/>
|
/>
|
||||||
</Grid>
|
</Grid>
|
||||||
<Grid item xs={6}>
|
<Grid item xs={6}>
|
||||||
|
|||||||
@@ -37,7 +37,7 @@ import { TbMapPinCode } from 'react-icons/tb';
|
|||||||
import { FaLocationDot } from 'react-icons/fa6';
|
import { FaLocationDot } from 'react-icons/fa6';
|
||||||
import axios from 'axios';
|
import axios from 'axios';
|
||||||
import { useTheme } from '@mui/material/styles';
|
import { useTheme } from '@mui/material/styles';
|
||||||
import Geocode from 'react-geocode';
|
import AddressAutocomplete from 'components/nearle_components/AddressAutocomplete';
|
||||||
import Loader from 'components/Loader';
|
import Loader from 'components/Loader';
|
||||||
import * as geolib from 'geolib';
|
import * as geolib from 'geolib';
|
||||||
import MainCard from 'components/MainCard';
|
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 = () => {
|
const Createorder1 = () => {
|
||||||
Geocode.setApiKey(process.env.REACT_APP_GOOGLE_MAPS_API_KEY);
|
|
||||||
// ================================================= || GoogleMaps (Drawer) || =================================================
|
|
||||||
const loaded = React.useRef(false);
|
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
const theme = useTheme();
|
const theme = useTheme();
|
||||||
const isMobile = useMediaQuery(theme.breakpoints.down('md'));
|
const isMobile = useMediaQuery(theme.breakpoints.down('md'));
|
||||||
@@ -275,17 +260,6 @@ const Createorder1 = () => {
|
|||||||
console.log('pickupSlot', pickupSlot);
|
console.log('pickupSlot', pickupSlot);
|
||||||
}, [pickupSlotsList, 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 ||============================== //
|
// ==============================|| fetchAppLocations ||============================== //
|
||||||
const fetchAppLocations = async () => {
|
const fetchAppLocations = async () => {
|
||||||
try {
|
try {
|
||||||
@@ -760,173 +734,129 @@ const Createorder1 = () => {
|
|||||||
setLoading(false);
|
setLoading(false);
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
// ============================================= || Google Maps Autocomplete(pick) || =============================================
|
// ============================================= || Address Autocomplete (pick) || =============================================
|
||||||
useEffect(() => {
|
const handlePickPlaceSelected = (place) => {
|
||||||
// Initialize Google Maps Autocomplete
|
setInputValue1(`${place.name}, ${place.formatted_address}`);
|
||||||
if (inputValue1) {
|
// to trigger getDistance
|
||||||
const autocompleteInput = document.getElementById('addressAuto1');
|
setStartPoint({ latitude: place.geometry.location.lat(), longitude: place.geometry.location.lng() });
|
||||||
const autocomplete = new window.google.maps.places.Autocomplete(autocompleteInput, {
|
setPickCust({ ...pickCust, address: `${place.name} ${place.formatted_address}` });
|
||||||
// types: ['(cities)'], // You can adjust the types parameter based on your requirements
|
const address = {
|
||||||
strictBounds: true,
|
address: `${place.name} ${place.formatted_address}`,
|
||||||
bounds: new window.google.maps.Circle({
|
street_number: '',
|
||||||
// center: new window.google.maps.LatLng(11.0050707, 76.9509083),
|
route: '',
|
||||||
// radius: 100000
|
locality: '',
|
||||||
center: new window.google.maps.LatLng(appLocaLat, appLocaLng),
|
sublocality_level_1: '',
|
||||||
radius: appLocaRadius * 1000
|
administrative_area_level_3: '',
|
||||||
}).getBounds()
|
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
|
// Use address object as per your requirements
|
||||||
autocomplete.addListener('place_changed', () => {
|
setPickCust({
|
||||||
const place = autocomplete.getPlace();
|
...pickCust,
|
||||||
setInputValue1(`${place.name}, ${place.formatted_address}`);
|
address: address.address,
|
||||||
console.log('new place', place); // Do something with the selected place
|
doorno: `${address.street_number} ${address.route}`,
|
||||||
console.log(' pick (new place) lat lng', { lat: place.geometry.location.lat(), lng: place.geometry.location.lng() }); // Do something with the selected place
|
suburb: address.sublocality_level_1,
|
||||||
// to trigger getDistance
|
city: address.locality,
|
||||||
setStartPoint({ latitude: place.geometry.location.lat(), longitude: place.geometry.location.lng() });
|
postcode: address.postal_code,
|
||||||
setPickCust({ ...pickCust, address: `${place.name} ${place.formatted_address}` });
|
latitude: place.geometry.location.lat(),
|
||||||
const address = {
|
longitude: place.geometry.location.lng()
|
||||||
address: `${place.name} ${place.formatted_address}`,
|
});
|
||||||
street_number: '',
|
};
|
||||||
route: '',
|
// ============================================= || Address Autocomplete (Drop) || =============================================
|
||||||
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
|
const handleDropPlaceSelected = (place) => {
|
||||||
setPickCust({
|
setInputValue2(`${place.name}, ${place.formatted_address}`);
|
||||||
...pickCust,
|
setEndPoint({ latitude: place.geometry.location.lat(), longitude: place.geometry.location.lng() });
|
||||||
address: address.address,
|
|
||||||
doorno: `${address.street_number} ${address.route}`,
|
setDropCust({ ...dropCust, address: `${place.name} ${place.formatted_address}` });
|
||||||
suburb: address.sublocality_level_1,
|
const address = {
|
||||||
city: address.locality,
|
address: `${place.name} ${place.formatted_address}`,
|
||||||
postcode: address.postal_code,
|
street_number: '',
|
||||||
latitude: place.geometry.location.lat(),
|
route: '',
|
||||||
longitude: place.geometry.location.lng()
|
locality: '',
|
||||||
});
|
sublocality_level_1: '',
|
||||||
console.log('Pick Address:', address);
|
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(() => {
|
// Use address object as per your requirements
|
||||||
if (inputValue2) {
|
setDropCust({
|
||||||
// Initialize Google Maps Autocomplete
|
...dropCust,
|
||||||
const autocompleteInput = document.getElementById('addressAuto2');
|
address: address.address,
|
||||||
const autocomplete = new window.google.maps.places.Autocomplete(autocompleteInput, {
|
doorno: `${address.street_number} ${address.route}`,
|
||||||
// types: ['(cities)'], // You can adjust the types parameter based on your requirements
|
suburb: address.sublocality_level_1,
|
||||||
strictBounds: true,
|
city: address.locality,
|
||||||
bounds: new window.google.maps.Circle({
|
postcode: address.postal_code,
|
||||||
// center: new window.google.maps.LatLng(11.0050707, 76.9509083),
|
latitude: place.geometry.location.lat(),
|
||||||
center: new window.google.maps.LatLng(appLocaLat, appLocaLng),
|
longitude: place.geometry.location.lng()
|
||||||
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]);
|
|
||||||
|
|
||||||
// ============================================= || gettenantlocations (branches) || =============================================
|
// ============================================= || gettenantlocations (branches) || =============================================
|
||||||
const gettenantlocations = async (id) => {
|
const gettenantlocations = async (id) => {
|
||||||
@@ -1375,43 +1305,47 @@ const Createorder1 = () => {
|
|||||||
Address Lookup
|
Address Lookup
|
||||||
</Typography>
|
</Typography>
|
||||||
{addId1 == 0 ? (
|
{addId1 == 0 ? (
|
||||||
<TextField
|
<AddressAutocomplete
|
||||||
id="addressAuto1"
|
id="addressAuto1"
|
||||||
fullWidth
|
fullWidth
|
||||||
size="small"
|
placeholder="Search for an address..."
|
||||||
placeholder="Search Google Maps for an address..."
|
|
||||||
variant="outlined"
|
|
||||||
value={inputValue1 || ''}
|
value={inputValue1 || ''}
|
||||||
onChange={(e) => setInputValue1(e.target.value)}
|
onChange={setInputValue1}
|
||||||
helperText="Start typing to auto-fill the address details below"
|
onPlaceSelected={handlePickPlaceSelected}
|
||||||
FormHelperTextProps={{ className: 'address-search-helper pickup-helper' }}
|
bias={{ lat: appLocaLat, lng: appLocaLng }}
|
||||||
InputProps={{
|
TextFieldProps={{
|
||||||
startAdornment: (
|
size: 'small',
|
||||||
<InputAdornment position="start">
|
variant: 'outlined',
|
||||||
<SearchOutlined style={{ fontSize: 15, color: '#662582' }} />
|
helperText: 'Start typing to auto-fill the address details below',
|
||||||
</InputAdornment>
|
FormHelperTextProps: { className: 'address-search-helper pickup-helper' },
|
||||||
),
|
InputProps: {
|
||||||
endAdornment: (
|
startAdornment: (
|
||||||
<IconButton
|
<InputAdornment position="start">
|
||||||
onClick={() => {
|
<SearchOutlined style={{ fontSize: 15, color: '#662582' }} />
|
||||||
setInputValue1('');
|
</InputAdornment>
|
||||||
setPickCust({
|
),
|
||||||
...pickCust,
|
endAdornment: (
|
||||||
doorno: '',
|
<IconButton
|
||||||
suburb: '',
|
onClick={() => {
|
||||||
city: '',
|
setInputValue1('');
|
||||||
postcode: '',
|
setPickCust({
|
||||||
landmark: ''
|
...pickCust,
|
||||||
});
|
doorno: '',
|
||||||
setShowDistance(false);
|
suburb: '',
|
||||||
setStartPoint({ latitude: 0, longitude: 0 });
|
city: '',
|
||||||
}}
|
postcode: '',
|
||||||
size="small"
|
landmark: ''
|
||||||
>
|
});
|
||||||
<CloseIcon fontSize="small" />
|
setShowDistance(false);
|
||||||
</IconButton>
|
setStartPoint({ latitude: 0, longitude: 0 });
|
||||||
),
|
}}
|
||||||
style: { borderRadius: '10px', background: '#fff' }
|
size="small"
|
||||||
|
>
|
||||||
|
<CloseIcon fontSize="small" />
|
||||||
|
</IconButton>
|
||||||
|
),
|
||||||
|
style: { borderRadius: '10px', background: '#fff' }
|
||||||
|
}
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
) : (
|
) : (
|
||||||
@@ -1693,43 +1627,47 @@ const Createorder1 = () => {
|
|||||||
Address Lookup
|
Address Lookup
|
||||||
</Typography>
|
</Typography>
|
||||||
{addId2 == 0 ? (
|
{addId2 == 0 ? (
|
||||||
<TextField
|
<AddressAutocomplete
|
||||||
id="addressAuto2"
|
id="addressAuto2"
|
||||||
placeholder="Search Google Maps for an address..."
|
placeholder="Search for an address..."
|
||||||
variant="outlined"
|
|
||||||
size="small"
|
|
||||||
fullWidth
|
fullWidth
|
||||||
value={inputValue2 || ''}
|
value={inputValue2 || ''}
|
||||||
onChange={(e) => setInputValue2(e.target.value)}
|
onChange={setInputValue2}
|
||||||
helperText="Start typing to auto-fill the address details below"
|
onPlaceSelected={handleDropPlaceSelected}
|
||||||
FormHelperTextProps={{ className: 'address-search-helper drop-helper' }}
|
bias={{ lat: appLocaLat, lng: appLocaLng }}
|
||||||
InputProps={{
|
TextFieldProps={{
|
||||||
startAdornment: (
|
size: 'small',
|
||||||
<InputAdornment position="start">
|
variant: 'outlined',
|
||||||
<SearchOutlined style={{ fontSize: 15, color: '#65387a' }} />
|
helperText: 'Start typing to auto-fill the address details below',
|
||||||
</InputAdornment>
|
FormHelperTextProps: { className: 'address-search-helper drop-helper' },
|
||||||
),
|
InputProps: {
|
||||||
endAdornment: (
|
startAdornment: (
|
||||||
<IconButton
|
<InputAdornment position="start">
|
||||||
onClick={() => {
|
<SearchOutlined style={{ fontSize: 15, color: '#65387a' }} />
|
||||||
setInputValue2('');
|
</InputAdornment>
|
||||||
setDropCust({
|
),
|
||||||
...dropCust,
|
endAdornment: (
|
||||||
doorno: '',
|
<IconButton
|
||||||
suburb: '',
|
onClick={() => {
|
||||||
city: '',
|
setInputValue2('');
|
||||||
postcode: '',
|
setDropCust({
|
||||||
landmark: ''
|
...dropCust,
|
||||||
});
|
doorno: '',
|
||||||
setShowDistance(false);
|
suburb: '',
|
||||||
setEndPoint({ latitude: 0, longitude: 0 });
|
city: '',
|
||||||
}}
|
postcode: '',
|
||||||
size="small"
|
landmark: ''
|
||||||
>
|
});
|
||||||
<CloseIcon fontSize="small" />
|
setShowDistance(false);
|
||||||
</IconButton>
|
setEndPoint({ latitude: 0, longitude: 0 });
|
||||||
),
|
}}
|
||||||
style: { borderRadius: '10px', background: '#fff' }
|
size="small"
|
||||||
|
>
|
||||||
|
<CloseIcon fontSize="small" />
|
||||||
|
</IconButton>
|
||||||
|
),
|
||||||
|
style: { borderRadius: '10px', background: '#fff' }
|
||||||
|
}
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
) : (
|
) : (
|
||||||
|
|||||||
@@ -37,7 +37,7 @@ import { TbMapPinCode } from 'react-icons/tb';
|
|||||||
import { FaLocationDot } from 'react-icons/fa6';
|
import { FaLocationDot } from 'react-icons/fa6';
|
||||||
import axios from 'axios';
|
import axios from 'axios';
|
||||||
import { useTheme } from '@mui/material/styles';
|
import { useTheme } from '@mui/material/styles';
|
||||||
import Geocode from 'react-geocode';
|
import AddressAutocomplete from 'components/nearle_components/AddressAutocomplete';
|
||||||
import Loader from 'components/Loader';
|
import Loader from 'components/Loader';
|
||||||
import MainCard from 'components/MainCard';
|
import MainCard from 'components/MainCard';
|
||||||
import { FaUser } from 'react-icons/fa6';
|
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 = () => {
|
const Createorder1 = () => {
|
||||||
Geocode.setApiKey(process.env.REACT_APP_GOOGLE_MAPS_API_KEY);
|
|
||||||
// ================================================= || GoogleMaps (Drawer) || =================================================
|
|
||||||
const loaded = React.useRef(false);
|
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
const theme = useTheme();
|
const theme = useTheme();
|
||||||
const locationRef = useRef(null);
|
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 ||============================== //
|
// ==============================|| fetchAppLocations ||============================== //
|
||||||
const fetchAppLocations = async () => {
|
const fetchAppLocations = async () => {
|
||||||
try {
|
try {
|
||||||
@@ -863,173 +837,129 @@ const Createorder1 = () => {
|
|||||||
setLoading(false);
|
setLoading(false);
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
// ============================================= || Google Maps Autocomplete(pick) || =============================================
|
// ============================================= || Address Autocomplete (pick) || =============================================
|
||||||
useEffect(() => {
|
const handlePickPlaceSelected = (place) => {
|
||||||
// Initialize Google Maps Autocomplete
|
setInputValue1(`${place.name}, ${place.formatted_address}`);
|
||||||
if (inputValue1) {
|
// to trigger getDistance
|
||||||
const autocompleteInput = document.getElementById('addressAuto1');
|
setStartPoint({ latitude: place.geometry.location.lat(), longitude: place.geometry.location.lng() });
|
||||||
const autocomplete = new window.google.maps.places.Autocomplete(autocompleteInput, {
|
setPickCust({ ...pickCust, address: `${place.name} ${place.formatted_address}` });
|
||||||
// types: ['(cities)'], // You can adjust the types parameter based on your requirements
|
const address = {
|
||||||
strictBounds: true,
|
address: `${place.name} ${place.formatted_address}`,
|
||||||
bounds: new window.google.maps.Circle({
|
street_number: '',
|
||||||
// center: new window.google.maps.LatLng(11.0050707, 76.9509083),
|
route: '',
|
||||||
// radius: 100000
|
locality: '',
|
||||||
center: new window.google.maps.LatLng(appLocaLat, appLocaLng),
|
sublocality_level_1: '',
|
||||||
radius: appLocaRadius * 1000
|
administrative_area_level_3: '',
|
||||||
}).getBounds()
|
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
|
// Use address object as per your requirements
|
||||||
autocomplete.addListener('place_changed', () => {
|
setPickCust({
|
||||||
const place = autocomplete.getPlace();
|
...pickCust,
|
||||||
setInputValue1(`${place.name}, ${place.formatted_address}`);
|
address: address.address,
|
||||||
console.log('new place', place); // Do something with the selected place
|
doorno: `${address.street_number} ${address.route}`,
|
||||||
console.log(' pick (new place) lat lng', { lat: place.geometry.location.lat(), lng: place.geometry.location.lng() }); // Do something with the selected place
|
suburb: address.sublocality_level_1,
|
||||||
// to trigger getDistance
|
city: address.locality,
|
||||||
setStartPoint({ latitude: place.geometry.location.lat(), longitude: place.geometry.location.lng() });
|
postcode: address.postal_code,
|
||||||
setPickCust({ ...pickCust, address: `${place.name} ${place.formatted_address}` });
|
latitude: place.geometry.location.lat(),
|
||||||
const address = {
|
longitude: place.geometry.location.lng()
|
||||||
address: `${place.name} ${place.formatted_address}`,
|
});
|
||||||
street_number: '',
|
};
|
||||||
route: '',
|
// ============================================= || Address Autocomplete (Drop) || =============================================
|
||||||
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
|
const handleDropPlaceSelected = (place) => {
|
||||||
setPickCust({
|
setInputValue2(`${place.name}, ${place.formatted_address}`);
|
||||||
...pickCust,
|
setEndPoint({ latitude: place.geometry.location.lat(), longitude: place.geometry.location.lng() });
|
||||||
address: address.address,
|
|
||||||
doorno: `${address.street_number} ${address.route}`,
|
setDropCust({ ...dropCust, address: `${place.name} ${place.formatted_address}` });
|
||||||
suburb: address.sublocality_level_1,
|
const address = {
|
||||||
city: address.locality,
|
address: `${place.name} ${place.formatted_address}`,
|
||||||
postcode: address.postal_code,
|
street_number: '',
|
||||||
latitude: place.geometry.location.lat(),
|
route: '',
|
||||||
longitude: place.geometry.location.lng()
|
locality: '',
|
||||||
});
|
sublocality_level_1: '',
|
||||||
console.log('Pick Address:', address);
|
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(() => {
|
// Use address object as per your requirements
|
||||||
if (inputValue2) {
|
setDropCust({
|
||||||
// Initialize Google Maps Autocomplete
|
...dropCust,
|
||||||
const autocompleteInput = document.getElementById('addressAuto2');
|
address: address.address,
|
||||||
const autocomplete = new window.google.maps.places.Autocomplete(autocompleteInput, {
|
doorno: `${address.street_number} ${address.route}`,
|
||||||
// types: ['(cities)'], // You can adjust the types parameter based on your requirements
|
suburb: address.sublocality_level_1,
|
||||||
strictBounds: true,
|
city: address.locality,
|
||||||
bounds: new window.google.maps.Circle({
|
postcode: address.postal_code,
|
||||||
// center: new window.google.maps.LatLng(11.0050707, 76.9509083),
|
latitude: place.geometry.location.lat(),
|
||||||
center: new window.google.maps.LatLng(appLocaLat, appLocaLng),
|
longitude: place.geometry.location.lng()
|
||||||
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]);
|
|
||||||
|
|
||||||
// ============================================= || gettenantlocations (branches) || =============================================
|
// ============================================= || gettenantlocations (branches) || =============================================
|
||||||
const gettenantlocations = async (id) => {
|
const gettenantlocations = async (id) => {
|
||||||
@@ -1422,35 +1352,38 @@ const Createorder1 = () => {
|
|||||||
<Stack spacing={1.25} sx={{ mt: 0 }}>
|
<Stack spacing={1.25} sx={{ mt: 0 }}>
|
||||||
{addId1 == 0 ? (
|
{addId1 == 0 ? (
|
||||||
<div>
|
<div>
|
||||||
<TextField
|
<AddressAutocomplete
|
||||||
// disabled={!appId || !tenantid || !locationid}
|
|
||||||
id="addressAuto1"
|
id="addressAuto1"
|
||||||
fullWidth
|
fullWidth
|
||||||
label={'Address'}
|
label={'Address'}
|
||||||
variant="outlined"
|
|
||||||
value={inputValue1 || ''}
|
value={inputValue1 || ''}
|
||||||
onChange={(e) => setInputValue1(e.target.value)}
|
onChange={setInputValue1}
|
||||||
InputProps={{
|
onPlaceSelected={handlePickPlaceSelected}
|
||||||
endAdornment: (
|
bias={{ lat: appLocaLat, lng: appLocaLng }}
|
||||||
<IconButton
|
TextFieldProps={{
|
||||||
onClick={() => {
|
variant: 'outlined',
|
||||||
setInputValue1('');
|
InputProps: {
|
||||||
setPickCust({
|
endAdornment: (
|
||||||
...pickCust,
|
<IconButton
|
||||||
doorno: '',
|
onClick={() => {
|
||||||
suburb: '',
|
setInputValue1('');
|
||||||
city: '',
|
setPickCust({
|
||||||
postcode: '',
|
...pickCust,
|
||||||
landmark: ''
|
doorno: '',
|
||||||
});
|
suburb: '',
|
||||||
setShowDistance(false);
|
city: '',
|
||||||
setStartPoint({ latitude: 0, longitude: 0 });
|
postcode: '',
|
||||||
}}
|
landmark: ''
|
||||||
size="small"
|
});
|
||||||
>
|
setShowDistance(false);
|
||||||
<CloseIcon />
|
setStartPoint({ latitude: 0, longitude: 0 });
|
||||||
</IconButton>
|
}}
|
||||||
)
|
size="small"
|
||||||
|
>
|
||||||
|
<CloseIcon />
|
||||||
|
</IconButton>
|
||||||
|
)
|
||||||
|
}
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
@@ -1799,35 +1732,38 @@ const Createorder1 = () => {
|
|||||||
<Stack spacing={1.25} sx={{ mt: 0 }}>
|
<Stack spacing={1.25} sx={{ mt: 0 }}>
|
||||||
{addId2 == 0 ? (
|
{addId2 == 0 ? (
|
||||||
<div>
|
<div>
|
||||||
<TextField
|
<AddressAutocomplete
|
||||||
// disabled={!appId || !tenantid || !locationid}
|
|
||||||
id="addressAuto2"
|
id="addressAuto2"
|
||||||
label="Address "
|
label="Address "
|
||||||
variant="outlined"
|
|
||||||
fullWidth
|
fullWidth
|
||||||
value={inputValue2 || ''}
|
value={inputValue2 || ''}
|
||||||
onChange={(e) => setInputValue2(e.target.value)}
|
onChange={setInputValue2}
|
||||||
InputProps={{
|
onPlaceSelected={handleDropPlaceSelected}
|
||||||
endAdornment: (
|
bias={{ lat: appLocaLat, lng: appLocaLng }}
|
||||||
<IconButton
|
TextFieldProps={{
|
||||||
onClick={() => {
|
variant: 'outlined',
|
||||||
setInputValue2('');
|
InputProps: {
|
||||||
setDropCust({
|
endAdornment: (
|
||||||
...dropCust,
|
<IconButton
|
||||||
doorno: '',
|
onClick={() => {
|
||||||
suburb: '',
|
setInputValue2('');
|
||||||
city: '',
|
setDropCust({
|
||||||
postcode: '',
|
...dropCust,
|
||||||
landmark: ''
|
doorno: '',
|
||||||
});
|
suburb: '',
|
||||||
setShowDistance(false);
|
city: '',
|
||||||
setEndPoint({ latitude: 0, longitude: 0 });
|
postcode: '',
|
||||||
}}
|
landmark: ''
|
||||||
size="small"
|
});
|
||||||
>
|
setShowDistance(false);
|
||||||
<CloseIcon />
|
setEndPoint({ latitude: 0, longitude: 0 });
|
||||||
</IconButton>
|
}}
|
||||||
)
|
size="small"
|
||||||
|
>
|
||||||
|
<CloseIcon />
|
||||||
|
</IconButton>
|
||||||
|
)
|
||||||
|
}
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
</div>
|
</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 { 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 = {
|
const containerStyle = {
|
||||||
width: '100%',
|
width: '100%',
|
||||||
height: 'calc(100vh - 150px)'
|
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 }) {
|
export default function RiderLocationMap({ riderLocations }) {
|
||||||
console.log('riderLocations', riderLocations);
|
console.log('riderLocations', riderLocations);
|
||||||
|
|
||||||
const center = {
|
const center = [Number(riderLocations?.[0]?.latitude || 11.0056), Number(riderLocations?.[0]?.longitude || 76.9661)];
|
||||||
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)
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<LoadScriptNext googleMapsApiKey={process.env.REACT_APP_GOOGLE_MAPS_API_KEY}>
|
<MapContainer center={center} zoom={12} style={containerStyle}>
|
||||||
<GoogleMap mapContainerStyle={containerStyle} zoom={12} center={center}>
|
<TileLayer url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png" attribution="© OpenStreetMap contributors" />
|
||||||
{riderLocations &&
|
{riderLocations &&
|
||||||
riderLocations?.map((r, index) => {
|
riderLocations.map((r, index) => {
|
||||||
const lat = Number(r.latitude);
|
const lat = Number(r.latitude);
|
||||||
const lng = Number(r.longitude);
|
const lng = Number(r.longitude);
|
||||||
return (
|
return (
|
||||||
<div key={index}>
|
<Marker key={index} position={[lat, lng]} icon={r.status == 'active' ? GreenIcon : RedIcon}>
|
||||||
{/* Marker */}
|
<Tooltip permanent direction="top" offset={[0, -35]} opacity={1} className="rider-location-tooltip">
|
||||||
<Marker
|
<Button variant="contained" color="primary" size="small">
|
||||||
position={{ lat, lng }}
|
{` ${r.username} `}
|
||||||
icon={r.status == 'active' ? GreenIcon : RedIcon}
|
<br />
|
||||||
label={{
|
{`(${r.orderid || ''}) `}
|
||||||
fontSize: '14px',
|
</Button>
|
||||||
fontWeight: 'bold'
|
</Tooltip>
|
||||||
}}
|
</Marker>
|
||||||
/>
|
);
|
||||||
<OverlayView position={{ lat, lng }} mapPaneName={OverlayView.OVERLAY_LAYER}>
|
})}
|
||||||
<div
|
</MapContainer>
|
||||||
style={{
|
|
||||||
background: 'none',
|
|
||||||
color: 'green',
|
|
||||||
padding: '2px 8px',
|
|
||||||
borderRadius: '4px',
|
|
||||||
fontSize: '12px',
|
|
||||||
fontWeight: 600,
|
|
||||||
whiteSpace: 'nowrap',
|
|
||||||
transform: 'translate(-50%, -140%)',
|
|
||||||
pointerEvents: 'none',
|
|
||||||
ml: 20
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<Button variant="contained" color="primary" size="small">
|
|
||||||
{` ${r.username} `}
|
|
||||||
{/* <br /> */}
|
|
||||||
{/* {`${r.contactno || '##### ##### '} `} */}
|
|
||||||
<br />
|
|
||||||
{`(${r.orderid || ''}) `}
|
|
||||||
</Button>
|
|
||||||
</div>
|
|
||||||
</OverlayView>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
})}
|
|
||||||
</GoogleMap>
|
|
||||||
</LoadScriptNext>
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,10 +1,46 @@
|
|||||||
import React, { useEffect, useMemo, useRef, useState } from 'react';
|
import React, { useEffect, useMemo, useState } from 'react';
|
||||||
import { GoogleMap, Polyline, Marker, InfoWindow, useJsApiLoader } from '@react-google-maps/api';
|
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 { Box, IconButton, Stack, Typography, CircularProgress } from '@mui/material';
|
||||||
import { MdClose, MdRoute } from 'react-icons/md';
|
import { MdClose, MdRoute } from 'react-icons/md';
|
||||||
|
|
||||||
const containerStyle = { width: '100%', height: '100%' };
|
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(
|
||||||
|
`<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32" width="${size}" height="${size}">` +
|
||||||
|
`<circle cx="16" cy="16" r="14" fill="${color}" stroke="white" stroke-width="3"/>` +
|
||||||
|
`<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 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
|
// 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
|
// Riders Summary page. `details` is an ordered array of waypoints (sorted by
|
||||||
// the planning step number) shaped as:
|
// 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
|
// `dropLat/dropLng` are required; pickup coords are optional and rendered as
|
||||||
// faded pre-stops if present.
|
// faded pre-stops if present.
|
||||||
export default function RidersRoutes({ details, loading, riderName, dateRange, onClose }) {
|
export default function RidersRoutes({ details, loading, riderName, dateRange, onClose }) {
|
||||||
const mapRef = useRef(null);
|
|
||||||
const [focusedStep, setFocusedStep] = useState(null);
|
const [focusedStep, setFocusedStep] = useState(null);
|
||||||
const [routePath, setRoutePath] = useState([]);
|
const [routePath, setRoutePath] = useState([]);
|
||||||
const [routeLoading, setRouteLoading] = useState(false);
|
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.
|
// Step-pin coordinates in planning order — what the polyline connects.
|
||||||
const dropPath = useMemo(
|
const dropPath = useMemo(() => (details || []).map((d) => [d.dropLat, d.dropLng]), [details]);
|
||||||
() => (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
|
// Resolve the rider's planned waypoints into an actual road-following path
|
||||||
// via the Directions API. Without this, the polyline would cut across
|
// via OSRM. Without this, the polyline would cut across buildings / aerial
|
||||||
// buildings / aerial lines — operators have no way to read the real route.
|
// lines — operators have no way to read the real route.
|
||||||
// Directions has a 25-waypoint limit per request, so we chunk and stitch.
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!isLoaded || dropPath.length < 2) {
|
if (dropPath.length < 2) {
|
||||||
setRoutePath([]);
|
setRoutePath([]);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
let cancelled = false;
|
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 () => {
|
(async () => {
|
||||||
setRouteLoading(true);
|
setRouteLoading(true);
|
||||||
try {
|
try {
|
||||||
const points = dropPath;
|
const coords = dropPath.map(([lat, lng]) => `${lng},${lat}`).join(';');
|
||||||
const all = [];
|
const url = `https://router.project-osrm.org/route/v1/driving/${coords}?overview=full&geometries=geojson`;
|
||||||
let i = 0;
|
const res = await fetch(url);
|
||||||
while (i < points.length - 1) {
|
const data = await res.json();
|
||||||
const remaining = points.length - 1 - i;
|
if (!cancelled && data.routes?.length) {
|
||||||
const take = Math.min(remaining, MAX_WPS + 1);
|
const points = data.routes[0].geometry.coordinates.map(([lng, lat]) => [lat, lng]);
|
||||||
const origin = points[i];
|
setRoutePath(points);
|
||||||
const destination = points[i + take];
|
} else if (!cancelled) {
|
||||||
const waypoints = points.slice(i + 1, i + take);
|
setRoutePath([]);
|
||||||
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 (e) {
|
||||||
} catch {
|
console.warn('OSRM route error:', e);
|
||||||
// Fall back to the straight-line skeleton on failure (quota, no route, etc.).
|
|
||||||
if (!cancelled) setRoutePath([]);
|
if (!cancelled) setRoutePath([]);
|
||||||
} finally {
|
} finally {
|
||||||
if (!cancelled) setRouteLoading(false);
|
if (!cancelled) setRouteLoading(false);
|
||||||
@@ -100,22 +90,7 @@ export default function RidersRoutes({ details, loading, riderName, dateRange, o
|
|||||||
return () => {
|
return () => {
|
||||||
cancelled = true;
|
cancelled = true;
|
||||||
};
|
};
|
||||||
}, [isLoaded, dropPath]);
|
}, [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(
|
|
||||||
`<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32" width="${size}" height="${size}">` +
|
|
||||||
`<circle cx="16" cy="16" r="14" fill="${color}" stroke="white" stroke-width="3"/>` +
|
|
||||||
`<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}`;
|
|
||||||
};
|
|
||||||
|
|
||||||
const headerBar = (
|
const headerBar = (
|
||||||
<Stack
|
<Stack
|
||||||
@@ -133,12 +108,8 @@ export default function RidersRoutes({ details, loading, riderName, dateRange, o
|
|||||||
>
|
>
|
||||||
<MdRoute size={20} />
|
<MdRoute size={20} />
|
||||||
<Stack sx={{ flex: 1, minWidth: 0 }}>
|
<Stack sx={{ flex: 1, minWidth: 0 }}>
|
||||||
<Typography sx={{ fontWeight: 700, fontSize: 15, lineHeight: 1.2 }}>
|
<Typography sx={{ fontWeight: 700, fontSize: 15, lineHeight: 1.2 }}>Planned route{riderName ? ` — ${riderName}` : ''}</Typography>
|
||||||
Planned route{riderName ? ` — ${riderName}` : ''}
|
{dateRange && <Typography sx={{ fontSize: 12, opacity: 0.85 }}>{dateRange}</Typography>}
|
||||||
</Typography>
|
|
||||||
{dateRange && (
|
|
||||||
<Typography sx={{ fontSize: 12, opacity: 0.85 }}>{dateRange}</Typography>
|
|
||||||
)}
|
|
||||||
</Stack>
|
</Stack>
|
||||||
{details && details.length > 0 && (
|
{details && details.length > 0 && (
|
||||||
<Typography sx={{ fontSize: 12, opacity: 0.9, fontWeight: 600 }}>
|
<Typography sx={{ fontSize: 12, opacity: 0.9, fontWeight: 600 }}>
|
||||||
@@ -154,16 +125,14 @@ export default function RidersRoutes({ details, loading, riderName, dateRange, o
|
|||||||
</Stack>
|
</Stack>
|
||||||
);
|
);
|
||||||
|
|
||||||
// Loading state — route fetch in flight OR Google Maps script not ready yet.
|
// Loading state — parent is still fetching the planned route data.
|
||||||
if (loading || !isLoaded) {
|
if (loading) {
|
||||||
return (
|
return (
|
||||||
<Box sx={{ display: 'flex', flexDirection: 'column', height: '100%' }}>
|
<Box sx={{ display: 'flex', flexDirection: 'column', height: '100%' }}>
|
||||||
{headerBar}
|
{headerBar}
|
||||||
<Stack alignItems="center" justifyContent="center" sx={{ flex: 1, gap: 1.5 }}>
|
<Stack alignItems="center" justifyContent="center" sx={{ flex: 1, gap: 1.5 }}>
|
||||||
<CircularProgress size={32} />
|
<CircularProgress size={32} />
|
||||||
<Typography sx={{ color: '#64748b', fontSize: 13 }}>
|
<Typography sx={{ color: '#64748b', fontSize: 13 }}>Loading planned route…</Typography>
|
||||||
{loading ? 'Loading planned route…' : 'Loading map…'}
|
|
||||||
</Typography>
|
|
||||||
</Stack>
|
</Stack>
|
||||||
</Box>
|
</Box>
|
||||||
);
|
);
|
||||||
@@ -176,9 +145,7 @@ export default function RidersRoutes({ details, loading, riderName, dateRange, o
|
|||||||
<Box sx={{ display: 'flex', flexDirection: 'column', height: '100%' }}>
|
<Box sx={{ display: 'flex', flexDirection: 'column', height: '100%' }}>
|
||||||
{headerBar}
|
{headerBar}
|
||||||
<Stack alignItems="center" justifyContent="center" sx={{ flex: 1, gap: 1, p: 3 }}>
|
<Stack alignItems="center" justifyContent="center" sx={{ flex: 1, gap: 1, p: 3 }}>
|
||||||
<Typography sx={{ color: '#1e293b', fontWeight: 700, fontSize: 16 }}>
|
<Typography sx={{ color: '#1e293b', fontWeight: 700, fontSize: 16 }}>No planned route for this rider</Typography>
|
||||||
No planned route for this rider
|
|
||||||
</Typography>
|
|
||||||
<Typography sx={{ color: '#64748b', fontSize: 13, textAlign: 'center', maxWidth: 360 }}>
|
<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.
|
There are no deliveries with drop coordinates assigned to this rider for the selected date range.
|
||||||
</Typography>
|
</Typography>
|
||||||
@@ -191,53 +158,21 @@ export default function RidersRoutes({ details, loading, riderName, dateRange, o
|
|||||||
<Box sx={{ display: 'flex', flexDirection: 'column', height: '100%' }}>
|
<Box sx={{ display: 'flex', flexDirection: 'column', height: '100%' }}>
|
||||||
{headerBar}
|
{headerBar}
|
||||||
<Box sx={{ flex: 1, minHeight: 0 }}>
|
<Box sx={{ flex: 1, minHeight: 0 }}>
|
||||||
<GoogleMap
|
<MapContainer center={dropPath[0]} zoom={14} style={containerStyle} zoomControl={false}>
|
||||||
mapContainerStyle={containerStyle}
|
<TileLayer url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png" attribution="© OpenStreetMap contributors" />
|
||||||
onLoad={(map) => (mapRef.current = map)}
|
<FitBoundsController dropPath={dropPath} />
|
||||||
center={dropPath[0]}
|
|
||||||
zoom={14}
|
|
||||||
options={{
|
|
||||||
streetViewControl: false,
|
|
||||||
mapTypeControl: false,
|
|
||||||
fullscreenControl: false
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{routePath.length > 0 ? (
|
{routePath.length > 0 ? (
|
||||||
<>
|
<>
|
||||||
{/* Translucent backdrop so the route stays legible on busy tiles. */}
|
{/* Translucent backdrop so the route stays legible on busy tiles. */}
|
||||||
<Polyline
|
<Polyline positions={routePath} pathOptions={{ color: '#662582', opacity: 0.25, weight: 8 }} />
|
||||||
path={routePath}
|
{/* Road-following planned route from OSRM. */}
|
||||||
options={{ strokeColor: '#662582', strokeOpacity: 0.25, strokeWeight: 8 }}
|
<Polyline positions={routePath} pathOptions={{ color: '#662582', opacity: 0.95, weight: 4 }} />
|
||||||
/>
|
|
||||||
{/* Road-following planned route from the Directions API. */}
|
|
||||||
<Polyline
|
|
||||||
path={routePath}
|
|
||||||
options={{ strokeColor: '#662582', strokeOpacity: 0.95, strokeWeight: 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.
|
// straight-line skeleton between drop pins in step order.
|
||||||
<Polyline
|
<Polyline positions={dropPath} pathOptions={{ color: '#662582', opacity: 0.6, weight: 3, dashArray: '2 10', lineCap: 'round' }} />
|
||||||
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'
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{details.map((d, i) => {
|
{details.map((d, i) => {
|
||||||
@@ -246,39 +181,29 @@ export default function RidersRoutes({ details, loading, riderName, dateRange, o
|
|||||||
return (
|
return (
|
||||||
<Marker
|
<Marker
|
||||||
key={`step-${d.deliveryid || d.orderid || i}`}
|
key={`step-${d.deliveryid || d.orderid || i}`}
|
||||||
position={{ lat: d.dropLat, lng: d.dropLng }}
|
position={[d.dropLat, d.dropLng]}
|
||||||
icon={{ url: stepIcon(stepNum, isFocused) }}
|
icon={stepIcon(stepNum, isFocused)}
|
||||||
onClick={() => setFocusedStep(isFocused ? null : d.deliveryid)}
|
eventHandlers={{
|
||||||
zIndex={isFocused ? 1000 : stepNum}
|
click: () => setFocusedStep(isFocused ? null : d.deliveryid)
|
||||||
|
}}
|
||||||
|
zIndexOffset={isFocused ? 1000 : stepNum}
|
||||||
>
|
>
|
||||||
{isFocused && (
|
<Popup onClose={() => setFocusedStep(null)}>
|
||||||
<InfoWindow onCloseClick={() => setFocusedStep(null)}>
|
<Box sx={{ minWidth: 180, fontFamily: 'inherit' }}>
|
||||||
<Box sx={{ minWidth: 180, fontFamily: 'inherit' }}>
|
<Typography sx={{ fontWeight: 800, fontSize: 13, color: '#0f172a' }}>
|
||||||
<Typography sx={{ fontWeight: 800, fontSize: 13, color: '#0f172a' }}>
|
Step {stepNum} · {d.customer}
|
||||||
Step {stepNum} · {d.customer}
|
</Typography>
|
||||||
</Typography>
|
{d.address && <Typography sx={{ fontSize: 12, color: '#475569', mt: 0.5 }}>{d.address}</Typography>}
|
||||||
{d.address && (
|
{d.expectedTime && (
|
||||||
<Typography sx={{ fontSize: 12, color: '#475569', mt: 0.5 }}>
|
<Typography sx={{ fontSize: 12, color: '#64748b', mt: 0.5 }}>ETA {String(d.expectedTime).slice(11, 16) || d.expectedTime}</Typography>
|
||||||
{d.address}
|
)}
|
||||||
</Typography>
|
{d.orderid && <Typography sx={{ fontSize: 11, color: '#94a3b8', mt: 0.5 }}>Order #{d.orderid}</Typography>}
|
||||||
)}
|
</Box>
|
||||||
{d.expectedTime && (
|
</Popup>
|
||||||
<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>
|
|
||||||
)}
|
|
||||||
</Marker>
|
</Marker>
|
||||||
);
|
);
|
||||||
})}
|
})}
|
||||||
</GoogleMap>
|
</MapContainer>
|
||||||
</Box>
|
</Box>
|
||||||
</Box>
|
</Box>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -50,7 +50,7 @@ import { useState, useEffect } from 'react';
|
|||||||
import axios from 'axios';
|
import axios from 'axios';
|
||||||
import Loader from 'components/Loader';
|
import Loader from 'components/Loader';
|
||||||
import Transitions from 'components/@extended/Transitions';
|
import Transitions from 'components/@extended/Transitions';
|
||||||
import Autocomplete from 'react-google-autocomplete';
|
import AddressAutocomplete from 'components/nearle_components/AddressAutocomplete';
|
||||||
|
|
||||||
import * as React from 'react';
|
import * as React from 'react';
|
||||||
|
|
||||||
@@ -60,8 +60,6 @@ import TablePagination from '@mui/material/TablePagination';
|
|||||||
import TableSortLabel from '@mui/material/TableSortLabel';
|
import TableSortLabel from '@mui/material/TableSortLabel';
|
||||||
import { visuallyHidden } from '@mui/utils';
|
import { visuallyHidden } from '@mui/utils';
|
||||||
|
|
||||||
import Geocode from 'react-geocode';
|
|
||||||
|
|
||||||
const Requests = () => {
|
const Requests = () => {
|
||||||
// let dispatch = useDispatch();
|
// let dispatch = useDispatch();
|
||||||
|
|
||||||
@@ -201,7 +199,6 @@ const Requests = () => {
|
|||||||
const [suburb, setSuburb] = useState('');
|
const [suburb, setSuburb] = useState('');
|
||||||
const [currenttenantid] = useState('');
|
const [currenttenantid] = useState('');
|
||||||
const [latlong, setLatlong] = useState({});
|
const [latlong, setLatlong] = useState({});
|
||||||
Geocode.setApiKey(process.env.REACT_APP_GOOGLE_MAPS_API_KEY);
|
|
||||||
// const [alertmessage, setAlertmessage] = useState('');
|
// const [alertmessage, setAlertmessage] = useState('');
|
||||||
// const [toast, setToast] = useState(false);
|
// const [toast, setToast] = useState(false);
|
||||||
const [rolesarr, setRolesarr] = useState([]);
|
const [rolesarr, setRolesarr] = useState([]);
|
||||||
@@ -277,27 +274,34 @@ const Requests = () => {
|
|||||||
|
|
||||||
// }
|
// }
|
||||||
|
|
||||||
useEffect(() => {
|
const handleAddressPlaceSelected = (place) => {
|
||||||
try {
|
setAddress(place.formatted_address);
|
||||||
Geocode.fromAddress(address).then(
|
setLatlong({ lat: place.geometry.location.lat(), lng: place.geometry.location.lng() });
|
||||||
(response) => {
|
let city1, state, zipcode1, suburb1;
|
||||||
if (response.status == 'OK') {
|
place.address_components.forEach((component) => {
|
||||||
const { lat, lng } = response.results[0].geometry.location;
|
component.types.forEach((type) => {
|
||||||
setLatlong({
|
switch (type) {
|
||||||
lat,
|
case 'locality':
|
||||||
lng
|
city1 = component.long_name;
|
||||||
});
|
break;
|
||||||
console.log(response);
|
case 'administrative_area_level_1':
|
||||||
}
|
state = component.long_name;
|
||||||
},
|
break;
|
||||||
(error) => {
|
case 'postal_code':
|
||||||
console.log(error);
|
zipcode1 = component.long_name;
|
||||||
|
break;
|
||||||
|
case 'sublocality':
|
||||||
|
case 'sublocality_level_1':
|
||||||
|
suburb1 = component.long_name;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
);
|
});
|
||||||
} catch (err) {
|
});
|
||||||
console.log(err);
|
setCity(city1 || '');
|
||||||
}
|
setState1(state || '');
|
||||||
}, [address]);
|
setZipcode(zipcode1 || '');
|
||||||
|
setSuburb(suburb1 || '');
|
||||||
|
};
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
console.log('rolesarr');
|
console.log('rolesarr');
|
||||||
@@ -1458,53 +1462,22 @@ const Requests = () => {
|
|||||||
|
|
||||||
{/* } */}
|
{/* } */}
|
||||||
|
|
||||||
<Autocomplete
|
<AddressAutocomplete
|
||||||
className="automap"
|
id="request-address-autocomplete"
|
||||||
apiKey={process.env.REACT_APP_GOOGLE_MAPS_API_KEY}
|
fullWidth
|
||||||
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']
|
|
||||||
}}
|
|
||||||
placeholder="Address"
|
placeholder="Address"
|
||||||
value={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>
|
</Stack>
|
||||||
</Grid>
|
</Grid>
|
||||||
|
|||||||
@@ -11,12 +11,10 @@ import { Box, Button, Grid, InputLabel, MenuItem, Select, Stack, TextField, Typo
|
|||||||
import MainCard from 'components/MainCard';
|
import MainCard from 'components/MainCard';
|
||||||
import axios from 'axios';
|
import axios from 'axios';
|
||||||
// assets
|
// assets
|
||||||
import { usePlacesWidget } from 'react-google-autocomplete';
|
import AddressAutocomplete, { geocodeAddress } from 'components/nearle_components/AddressAutocomplete';
|
||||||
import Loader from 'components/Loader';
|
import Loader from 'components/Loader';
|
||||||
import Geocode from 'react-geocode';
|
|
||||||
import { enqueueSnackbar } from 'notistack';
|
import { enqueueSnackbar } from 'notistack';
|
||||||
import { useNavigate } from 'react-router';
|
import { useNavigate } from 'react-router';
|
||||||
// import { setLocationType } from 'react-geocode';
|
|
||||||
|
|
||||||
// const avatarImage = require.context('assets/images/users', true);
|
// const avatarImage = require.context('assets/images/users', true);
|
||||||
|
|
||||||
@@ -50,9 +48,6 @@ const Createrider = () => {
|
|||||||
const theme = useTheme();
|
const theme = useTheme();
|
||||||
const isMobile = useMediaQuery(theme.breakpoints.down('md'));
|
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);
|
const [loading, setLoading] = useState(false);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@@ -64,25 +59,15 @@ const Createrider = () => {
|
|||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
try {
|
let active = true;
|
||||||
Geocode.fromAddress(address).then(
|
geocodeAddress(address).then((place) => {
|
||||||
(response) => {
|
if (active && place) {
|
||||||
if (response.status == 'OK') {
|
setLatlong({ lat: place.geometry.location.lat(), lng: place.geometry.location.lng() });
|
||||||
const { lat, lng } = response.results[0].geometry.location;
|
}
|
||||||
setLatlong({
|
});
|
||||||
lat,
|
return () => {
|
||||||
lng
|
active = false;
|
||||||
});
|
};
|
||||||
console.log(response);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
(error) => {
|
|
||||||
console.log(error);
|
|
||||||
}
|
|
||||||
);
|
|
||||||
} catch (err) {
|
|
||||||
console.log(err);
|
|
||||||
}
|
|
||||||
}, [address]);
|
}, [address]);
|
||||||
|
|
||||||
const opentoast = (message) => {
|
const opentoast = (message) => {
|
||||||
@@ -119,45 +104,33 @@ const Createrider = () => {
|
|||||||
}
|
}
|
||||||
}, [selectedImage]);
|
}, [selectedImage]);
|
||||||
|
|
||||||
const { ref: materialRef } = usePlacesWidget({
|
const handleAddressPlaceSelected = (place) => {
|
||||||
apiKey: process.env.REACT_APP_GOOGLE_MAPS_API_KEY,
|
setAddress(place.formatted_address);
|
||||||
onPlaceSelected: (place) => {
|
let city1, zipcode1, state1, suburb1;
|
||||||
console.log(place);
|
for (let i = 0; i < place.address_components.length; i++) {
|
||||||
|
for (let j = 0; j < place.address_components[i].types.length; j++) {
|
||||||
setAddress(place.formatted_address);
|
switch (place.address_components[i].types[j]) {
|
||||||
let city1, zipcode1, state1, suburb1;
|
case 'locality':
|
||||||
for (let i = 0; i < place.address_components.length; i++) {
|
city1 = place.address_components[i].long_name;
|
||||||
for (let j = 0; j < place.address_components[i].types.length; j++) {
|
break;
|
||||||
switch (place.address_components[i].types[j]) {
|
case 'administrative_area_level_1':
|
||||||
case 'locality':
|
state1 = place.address_components[i].long_name;
|
||||||
city1 = place.address_components[i].long_name;
|
break;
|
||||||
break;
|
case 'postal_code':
|
||||||
case 'administrative_area_level_1':
|
zipcode1 = place.address_components[i].long_name;
|
||||||
state1 = place.address_components[i].long_name;
|
break;
|
||||||
break;
|
case 'sublocality':
|
||||||
case 'postal_code':
|
case 'sublocality_level_1':
|
||||||
zipcode1 = place.address_components[i].long_name;
|
suburb1 = place.address_components[i].long_name;
|
||||||
break;
|
break;
|
||||||
case 'sublocality':
|
|
||||||
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 () => {
|
const createprofile = async () => {
|
||||||
console.log('res', businessname, businessno, mobilenumber, emailaddress, address, city, zipcode);
|
console.log('res', businessname, businessno, mobilenumber, emailaddress, address, city, zipcode);
|
||||||
@@ -340,14 +313,13 @@ const Createrider = () => {
|
|||||||
<Grid item xs={12}>
|
<Grid item xs={12}>
|
||||||
<Stack spacing={1.25}>
|
<Stack spacing={1.25}>
|
||||||
<InputLabel htmlFor="personal-address">Address</InputLabel>
|
<InputLabel htmlFor="personal-address">Address</InputLabel>
|
||||||
<TextField
|
<AddressAutocomplete
|
||||||
fullWidth
|
|
||||||
// defaultValue="Street 110-B Kalians Bag, Dewan, M.P. New York"
|
|
||||||
id="personal-address"
|
id="personal-address"
|
||||||
|
fullWidth
|
||||||
placeholder="Address"
|
placeholder="Address"
|
||||||
value={address}
|
value={address}
|
||||||
onChange={(e) => setAddress(e.target.value)}
|
onChange={setAddress}
|
||||||
inputRef={materialRef}
|
onPlaceSelected={handleAddressPlaceSelected}
|
||||||
/>
|
/>
|
||||||
</Stack>
|
</Stack>
|
||||||
</Grid>
|
</Grid>
|
||||||
|
|||||||
@@ -28,9 +28,8 @@ import { DatePicker } from '@mui/x-date-pickers/DatePicker';
|
|||||||
// project import
|
// project import
|
||||||
import MainCard from 'components/MainCard';
|
import MainCard from 'components/MainCard';
|
||||||
import axios from 'axios';
|
import axios from 'axios';
|
||||||
import { usePlacesWidget } from 'react-google-autocomplete';
|
import AddressAutocomplete from 'components/nearle_components/AddressAutocomplete';
|
||||||
import Loader from 'components/Loader';
|
import Loader from 'components/Loader';
|
||||||
import Geocode from 'react-geocode';
|
|
||||||
import { enqueueSnackbar } from 'notistack';
|
import { enqueueSnackbar } from 'notistack';
|
||||||
import dayjs from 'dayjs';
|
import dayjs from 'dayjs';
|
||||||
import CircularLoader from 'components/CircularLoader';
|
import CircularLoader from 'components/CircularLoader';
|
||||||
@@ -55,8 +54,6 @@ const EditRider = () => {
|
|||||||
const [locaName, setLocoName] = useState();
|
const [locaName, setLocoName] = useState();
|
||||||
const userid = localStorage.getItem('userid');
|
const userid = localStorage.getItem('userid');
|
||||||
|
|
||||||
Geocode.setApiKey(process.env.REACT_APP_GOOGLE_MAPS_API_KEY);
|
|
||||||
|
|
||||||
const [loading, setLoading] = useState(false);
|
const [loading, setLoading] = useState(false);
|
||||||
|
|
||||||
const fetchRiderData = async (id) => {
|
const fetchRiderData = async (id) => {
|
||||||
@@ -237,46 +234,30 @@ const EditRider = () => {
|
|||||||
}
|
}
|
||||||
}, [selectedImage]);
|
}, [selectedImage]);
|
||||||
|
|
||||||
const { ref: materialRef } = usePlacesWidget({
|
const handleAddressPlaceSelected = (place) => {
|
||||||
apiKey: process.env.REACT_APP_GOOGLE_MAPS_API_KEY,
|
setAddress(place.formatted_address);
|
||||||
onPlaceSelected: (place) => {
|
|
||||||
console.log(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 i = 0; i < place.address_components.length; i++) {
|
||||||
for (let j = 0; j < place.address_components[i].types.length; j++) {
|
for (let j = 0; j < place.address_components[i].types.length; j++) {
|
||||||
switch (place.address_components[i].types[j]) {
|
switch (place.address_components[i].types[j]) {
|
||||||
case 'locality':
|
case 'locality':
|
||||||
city1 = place.address_components[i].long_name;
|
city1 = place.address_components[i].long_name;
|
||||||
break;
|
break;
|
||||||
case 'administrative_area_level_1':
|
case 'administrative_area_level_1':
|
||||||
state1 = place.address_components[i].long_name;
|
state1 = place.address_components[i].long_name;
|
||||||
break;
|
break;
|
||||||
case 'postal_code':
|
case 'sublocality':
|
||||||
zipcode1 = place.address_components[i].long_name;
|
case 'sublocality_level_1':
|
||||||
break;
|
suburb1 = place.address_components[i].long_name;
|
||||||
case 'sublocality':
|
break;
|
||||||
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 () => {
|
const updateRider = async () => {
|
||||||
setLoading(true);
|
setLoading(true);
|
||||||
@@ -483,16 +464,13 @@ const EditRider = () => {
|
|||||||
<Grid item xs={12}>
|
<Grid item xs={12}>
|
||||||
<Stack spacing={1.25}>
|
<Stack spacing={1.25}>
|
||||||
<InputLabel htmlFor="personal-address">Address</InputLabel>
|
<InputLabel htmlFor="personal-address">Address</InputLabel>
|
||||||
<TextField
|
<AddressAutocomplete
|
||||||
fullWidth
|
|
||||||
// defaultValue="Street 110-B Kalians Bag, Dewan, M.P. New York"
|
|
||||||
id="personal-address"
|
id="personal-address"
|
||||||
|
fullWidth
|
||||||
placeholder="Address"
|
placeholder="Address"
|
||||||
value={address}
|
value={address}
|
||||||
onChange={(e) => {
|
onChange={setAddress}
|
||||||
setAddress(e.target.value);
|
onPlaceSelected={handleAddressPlaceSelected}
|
||||||
}}
|
|
||||||
inputRef={materialRef}
|
|
||||||
/>
|
/>
|
||||||
</Stack>
|
</Stack>
|
||||||
</Grid>
|
</Grid>
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
import * as React from 'react';
|
import * as React from 'react';
|
||||||
import { useState, useEffect, useRef, Fragment } from 'react';
|
import { useState, useEffect, useRef, Fragment } from 'react';
|
||||||
import Geocode from 'react-geocode';
|
|
||||||
import { useNavigate } from 'react-router-dom';
|
import { useNavigate } from 'react-router-dom';
|
||||||
import axios from 'axios';
|
import axios from 'axios';
|
||||||
import {
|
import {
|
||||||
@@ -491,8 +490,6 @@ const Riders = () => {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
Geocode.setApiKey(process.env.REACT_APP_GOOGLE_MAPS_API_KEY);
|
|
||||||
|
|
||||||
const handleChangetab = (i) => {
|
const handleChangetab = (i) => {
|
||||||
setTabvalue(i);
|
setTabvalue(i);
|
||||||
setLogsRow(null);
|
setLogsRow(null);
|
||||||
|
|||||||
Reference in New Issue
Block a user