updates on the google change

This commit is contained in:
2026-07-04 16:57:39 +05:30
parent cc901b4875
commit 89cf46ffb4
6 changed files with 102 additions and 204 deletions

View File

@@ -5,7 +5,7 @@ import { useTheme } from '@mui/material/styles';
import { useMediaQuery, Box, Button, Grid, Stack, TextField, Typography } from '@mui/material'; import { useMediaQuery, Box, Button, Grid, Stack, TextField, Typography } from '@mui/material';
// third party // third party
import { useTimer } from 'react-timer-hook'; const { useTimer } = require('react-timer-hook');
// assets // assets
import coming from 'assets/images/maintenance/coming-soon.png'; import coming from 'assets/images/maintenance/coming-soon.png';

View File

@@ -34,6 +34,7 @@ import {
FormControlLabel FormControlLabel
} from '@mui/material'; } from '@mui/material';
import CloseIcon from '@mui/icons-material/Close'; import CloseIcon from '@mui/icons-material/Close';
import { calculateDrivingDistance, calculateTotalCharge } from '../../../utils/distance';
import { Empty } from 'antd'; import { Empty } from 'antd';
import { FaPhoneAlt } from 'react-icons/fa'; import { FaPhoneAlt } from 'react-icons/fa';
import { GiDoorHandle } from 'react-icons/gi'; import { GiDoorHandle } from 'react-icons/gi';
@@ -619,66 +620,25 @@ const Createorder1 = () => {
}; };
const calculateDistance = async (pickup, drop) => { const calculateDistance = async (pickup, drop) => {
const service = new google.maps.DistanceMatrixService();
const getDistanceMatrix = (origins, destinations, travelMode, unitSystem) => {
return new Promise((resolve, reject) => {
service.getDistanceMatrix(
{
origins: [new google.maps.LatLng(origins.latitude, origins.longitude)],
destinations: [new google.maps.LatLng(destinations.latitude, destinations.longitude)],
travelMode: travelMode,
unitSystem: unitSystem
},
(response, status) => {
if (status === 'OK') {
resolve(response);
} else {
reject(new Error(`Error calculating distance: ${status}`));
}
}
);
});
};
try { try {
// Use await to wait for the promise to resolve const roundedDistance = await calculateDrivingDistance(pickup, drop);
const response = await getDistanceMatrix(pickup, drop, 'DRIVING', google.maps.UnitSystem.METRIC); console.log('calculated distance in km:', roundedDistance);
// Handle the response
const results = response.rows[0].elements;
for (let i = 0; i < results.length; i++) {
const element = results[i];
const distance = element.distance.value;
console.log('distance in m ', distance);
const distanceInKm = (distance / 1000).toFixed(2);
console.log('distance in km ', distanceInKm);
const roundedDistance = Math.round(distanceInKm);
console.log('roundedDistance', roundedDistance);
setDistance(roundedDistance); setDistance(roundedDistance);
if (roundedDistance < minKm) {
setTotalCharge(basePrice); const total = calculateTotalCharge(roundedDistance, basePrice, pricePerKm, minKm);
} else { console.log('total charge:', total);
console.log('minKm', minKm);
console.log('pricePerKm', pricePerKm);
console.log('basePrice', basePrice);
const total = (roundedDistance - minKm) * pricePerKm + basePrice;
console.log('total', total);
setTotalCharge(total); setTotalCharge(total);
}
setShowDistance(true); setShowDistance(true);
if (roundedDistance > appLocaRadius) { if (roundedDistance > appLocaRadius) {
setShowDistance(true); setShowDistance(true);
setOpen4(true); setOpen4(true);
} }
// Extract the numerical value of the duration // ⏱️ Approximate duration
const durationMatch = element.duration.text.match(/([\d.]+)/); const avgSpeed = 40; // km/h (adjust if needed)
const duration = durationMatch ? parseInt(durationMatch[0]) : null; const duration = Math.round((roundedDistance / avgSpeed) * 60); // minutes
// Display only the numerical values
console.log(`Distance: ${roundedDistance}, Duration: ${duration}`); console.log(`Distance: ${roundedDistance}, Duration: ${duration}`);
}
} catch (error) { } catch (error) {
console.error('Error calculating distance:', error); console.error('Error calculating distance:', error);
} }

View File

@@ -17,6 +17,7 @@ dayjs.extend(utc);
import { enqueueSnackbar } from 'notistack'; import { enqueueSnackbar } from 'notistack';
import { useNavigate } from 'react-router'; import { useNavigate } from 'react-router';
import Papa from 'papaparse'; import Papa from 'papaparse';
import { calculateDrivingDistance, calculateTotalCharge } from '../../../utils/distance';
import * as XLSX from 'xlsx'; import * as XLSX from 'xlsx';
import { import {
@@ -375,37 +376,6 @@ const MultipleOrders = () => {
// 🔹 Main distance calculation function // 🔹 Main distance calculation function
const calculateDistance = async (customer) => { const calculateDistance = async (customer) => {
const service = new google.maps.DistanceMatrixService();
// Helper: safely get distance matrix
const getDistanceMatrix = (origins, destinations) => {
return new Promise((resolve, reject) => {
// 2;
try {
if (!origins || !destinations) {
return reject(new Error('Origin or destination data missing.'));
}
service.getDistanceMatrix(
{
origins: [new google.maps.LatLng(origins.latitude, origins.longitude)],
destinations: [new google.maps.LatLng(destinations.latitude, destinations.longitude)],
travelMode: 'DRIVING',
unitSystem: google.maps.UnitSystem.METRIC
},
(response, status) => {
if (status === 'OK') {
resolve(response);
} else {
reject(new Error(`Google API error: ${status}`));
}
}
);
} catch (err) {
reject(new Error(`Unexpected error inside DistanceMatrixService: ${err.message}`));
}
});
};
try { try {
// --- Input validation --- // --- Input validation ---
if (!customer || typeof customer !== 'object') { if (!customer || typeof customer !== 'object') {
@@ -416,38 +386,18 @@ const MultipleOrders = () => {
throw new Error('Origin (pickCust) data missing or invalid.'); throw new Error('Origin (pickCust) data missing or invalid.');
} }
// --- Call Google Maps API ---
const response = await getDistanceMatrix(pickCust, customer);
// --- Validate response structure ---
if (!response.rows?.[0]?.elements?.[0] || !response.rows[0].elements[0].distance?.value) {
throw new Error('Malformed Distance Matrix response: missing distance value.');
}
// --- Compute distance --- // --- Compute distance ---
const distanceInMeters = response.rows[0].elements[0].distance.value; const roundedDistance = await calculateDrivingDistance(pickCust, customer);
const distanceInKilometers = distanceInMeters / 1000;
const roundedDistance = Math.round(distanceInKilometers);
// --- Calculate total charge --- // --- Calculate total charge ---
let totalcharge; const totalcharge = calculateTotalCharge(roundedDistance, basePrice, pricePerKm, minKm);
if (roundedDistance < minKm) {
totalcharge = basePrice;
} else {
totalcharge = (roundedDistance - minKm) * pricePerKm + basePrice;
}
return { roundedDistance, totalcharge }; return { roundedDistance, totalcharge };
} catch (error) { } catch (error) {
// --- Categorized smart error handling --- // --- Categorized smart error handling ---
console.log('on calculateDistance', error.message); console.log('on calculateDistance', error.message);
if (error.message.includes('Google API')) { if (error.message.includes('Invalid coordinates') || error.message.includes('Invalid coordinate')) {
console.log('🚨 Google Maps API Error:', error.message); console.log('📍 Invalid coordinate format:', error.message);
OpenToast('Invalid file format, upload valid file', 'error', 5000); OpenToast('Invalid coordinate format. Check location data.', 'warning', 3000);
} else if (error.message.includes('Invalid coordinates')) {
console.log('📍 Invalid coordinate format:', error.message, 3000);
OpenToast('Invalid coordinate format. Check location data.', 'warning'), 3000;
} else if (error.message.includes('Malformed Distance Matrix')) {
console.log('⚠️ Unexpected Google response structure:', error.message);
OpenToast('Google Distance Matrix returned invalid data.', 'error', 3000);
} else if (error.message.includes('Origin') || error.message.includes('customer')) { } else if (error.message.includes('Origin') || error.message.includes('customer')) {
console.log('❌ Missing or invalid input data:', error.message); console.log('❌ Missing or invalid input data:', error.message);
OpenToast('Missing or invalid input data for distance calculation.', 'warning', 3000); OpenToast('Missing or invalid input data for distance calculation.', 'warning', 3000);

View File

@@ -16,6 +16,7 @@ var utc = require('dayjs/plugin/utc');
dayjs.extend(utc); dayjs.extend(utc);
import { enqueueSnackbar } from 'notistack'; import { enqueueSnackbar } from 'notistack';
import { useNavigate } from 'react-router'; import { useNavigate } from 'react-router';
import { calculateDrivingDistance, calculateTotalCharge } from '../../../utils/distance';
import { GoogleMap, LoadScript, Marker } from '@react-google-maps/api'; import { GoogleMap, LoadScript, Marker } from '@react-google-maps/api';
import { import {
@@ -236,67 +237,13 @@ const MultipleOrders = () => {
// ========================================================= || calculateDistance || ========================================================= // ========================================================= || calculateDistance || =========================================================
const calculateDistance = async (customer) => { const calculateDistance = async (customer) => {
console.log('Distance calculation starts'); console.log('Distance calculation starts');
const service = new google.maps.DistanceMatrixService();
// Helper function to get the distance matrix
const getDistanceMatrix = async (origins, destinations) => {
console.log('origins', origins);
console.log('destinations', destinations);
return new Promise((resolve, reject) => {
console.log('calculation starts');
service.getDistanceMatrix(
{
origins: [new google.maps.LatLng(origins.latitude, origins.longitude)],
destinations: [new google.maps.LatLng(destinations.latitude, destinations.longitude)],
travelMode: 'DRIVING',
unitSystem: google.maps.UnitSystem.METRIC // Distances in metric units (km)
},
(response, status) => {
console.log('cal response', response);
console.log('cal status', status);
if (status === 'OK') {
console.log('calcualtion resolved');
resolve(response);
} else {
console.log('calcualtion rejected');
reject(new Error(`Error calculating distance: ${status}`));
}
}
);
});
};
try { try {
// Call getDistanceMatrix and wait for the response const roundedDistance = await calculateDrivingDistance(pickCust, customer);
const response = await getDistanceMatrix(pickCust, customer); const totalcharge = calculateTotalCharge(roundedDistance, basePrice, pricePerKm, minKm);
// Extract distance from the first result
const distanceInMeters = response.rows[0].elements[0].distance.value;
// Convert distance from meters to kilometers
const distanceInKilometers = distanceInMeters / 1000;
// Round the distance to the nearest integer
const roundedDistance = Math.round(distanceInKilometers);
let totalcharge;
if (roundedDistance < minKm) {
console.log('minKm', minKm);
console.log('pricePerKm', pricePerKm);
console.log('basePrice', basePrice);
totalcharge = basePrice;
} else {
console.log('minKm', minKm);
console.log('pricePerKm', pricePerKm);
console.log('basePrice', basePrice);
totalcharge = (roundedDistance - minKm) * pricePerKm + basePrice;
console.log('totalcharge', totalcharge);
}
// Return the rounded distance
return { roundedDistance, totalcharge }; return { roundedDistance, totalcharge };
} catch (error) { } catch (error) {
console.error('Error calculating distance:', error); console.error('Error calculating distance:', error);
throw error; // Rethrow the error to be handled by the caller throw error;
} }
}; };

View File

@@ -7,6 +7,7 @@ import { useNavigate } from 'react-router';
import { useTheme } from '@mui/material/styles'; import { useTheme } from '@mui/material/styles';
import useMediaQuery from '@mui/material/useMediaQuery'; import useMediaQuery from '@mui/material/useMediaQuery';
import { enqueueSnackbar } from 'notistack'; import { enqueueSnackbar } from 'notistack';
import { calculateDrivingDistance, calculateTotalCharge } from '../../../utils/distance';
import { import {
FormControl, FormControl,
@@ -238,46 +239,21 @@ const MultipleOrders = () => {
}, [dropCust]); }, [dropCust]);
// ============================== distance (Google) ============================== // ============================== distance (Google) ==============================
// ============================== distance (OSRM/Haversine) ==============================
const calculateDistance = async (customer) => { const calculateDistance = async (customer) => {
if (typeof window === 'undefined' || !window.google?.maps?.DistanceMatrixService) {
throw new Error('Google Maps not loaded');
}
const service = new window.google.maps.DistanceMatrixService();
const getDistanceMatrix = (origins, destinations) =>
new Promise((resolve, reject) => {
try {
if (!origins || !destinations) return reject(new Error('Origin or destination data missing.'));
service.getDistanceMatrix(
{
origins: [new window.google.maps.LatLng(origins.latitude, origins.longitude)],
destinations: [new window.google.maps.LatLng(destinations.latitude, destinations.longitude)],
travelMode: 'DRIVING',
unitSystem: window.google.maps.UnitSystem.METRIC
},
(response, status) => {
if (status === 'OK') resolve(response);
else reject(new Error(`Google API error: ${status}`));
}
);
} catch (err) {
reject(new Error(`Unexpected error inside DistanceMatrixService: ${err.message}`));
}
});
try { try {
if (!customer || typeof customer !== 'object') throw new Error('Invalid customer data.'); if (!customer || typeof customer !== 'object') throw new Error('Invalid customer data.');
if (!pickCust || typeof pickCust !== 'object') throw new Error('Origin (pickCust) data missing or invalid.'); if (!pickCust || typeof pickCust !== 'object') throw new Error('Origin (pickCust) data missing or invalid.');
const response = await getDistanceMatrix(pickCust, customer);
const distVal = response?.rows?.[0]?.elements?.[0]?.distance?.value; const roundedDistance = await calculateDrivingDistance(pickCust, customer);
if (distVal == null) throw new Error('Malformed Distance Matrix response: missing distance value.'); const totalcharge = calculateTotalCharge(roundedDistance, basePrice, pricePerKm, minKm);
const km = distVal / 1000;
const roundedDistance = Math.round(km);
const totalcharge = roundedDistance < minKm ? basePrice : (roundedDistance - minKm) * pricePerKm + basePrice;
return { roundedDistance, totalcharge }; return { roundedDistance, totalcharge };
} catch (error) { } catch (error) {
if (error.message.includes('Google API')) OpenToast('Invalid coordinates or Google API error.', 'error', 3000); if (error.message.includes('Origin') || error.message.includes('customer') || error.message.includes('coordinates')) {
else if (error.message.includes('Malformed')) OpenToast('Google Distance Matrix returned invalid data.', 'error', 3000); OpenToast('Missing or invalid input data for distance calculation.', 'warning', 3000);
else OpenToast('Unexpected error during distance calculation.', 'error', 3000); } else {
OpenToast('Unexpected error during distance calculation.', 'error', 3000);
}
throw error; throw error;
} }
}; };

65
src/utils/distance.js Normal file
View File

@@ -0,0 +1,65 @@
/**
* Calculates distance (in km) between origin and destination.
* Uses OSRM as primary driving distance source, and falls back to Haversine with a 1.3 multiplier.
*
* @param {Object} origin - { latitude, longitude }
* @param {Object} destination - { latitude, longitude }
* @returns {Promise<number>} - Round distance in KM
*/
export const calculateDrivingDistance = async (origin, destination) => {
const lat1 = origin?.latitude;
const lon1 = origin?.longitude;
const lat2 = destination?.latitude;
const lon2 = destination?.longitude;
if (lat1 == null || lon1 == null || lat2 == null || lon2 == null) {
throw new Error("Invalid coordinates");
}
// 1. Try OSRM API (either self-hosted or public demo server for fallback)
const osrmBaseUrl = process.env.REACT_APP_OSRM_URL || "https://router.project-osrm.org";
try {
const url = `${osrmBaseUrl}/route/v1/driving/${lon1},${lat1};${lon2},${lat2}?overview=false`;
const response = await fetch(url);
if (response.ok) {
const data = await response.json();
if (data.routes && data.routes.length > 0) {
const distanceInMeters = data.routes[0].distance;
const distanceInKm = distanceInMeters / 1000;
return Math.round(distanceInKm);
}
}
} catch (error) {
console.warn("OSRM API failed, falling back to Haversine math:", error);
}
// 2. Fallback: Haversine Formula with 1.3x multiplier
const toRad = (val) => (val * Math.PI) / 180;
const R = 6371; // Earth radius in km
const dLat = toRad(lat2 - lat1);
const dLon = toRad(lon2 - lon1);
const a =
Math.sin(dLat / 2) * Math.sin(dLat / 2) +
Math.cos(toRad(lat1)) * Math.cos(toRad(lat2)) *
Math.sin(dLon / 2) * Math.sin(dLon / 2);
const c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
const aerialDistance = R * c;
return Math.round(aerialDistance * 1.3);
};
/**
* Calculates total charge based on distance and pricing tier
*
* @param {number} distanceKm
* @param {number} basePrice
* @param {number} pricePerKm
* @param {number} minKm
* @returns {number}
*/
export const calculateTotalCharge = (distanceKm, basePrice, pricePerKm, minKm) => {
if (distanceKm < minKm) {
return basePrice;
}
return (distanceKm - minKm) * pricePerKm + basePrice;
};