2524 lines
101 KiB
JavaScript
2524 lines
101 KiB
JavaScript
import * as React from 'react';
|
|
import { useEffect, useState, useRef, Fragment } from 'react';
|
|
import {
|
|
FormControl,
|
|
InputAdornment,
|
|
Grid,
|
|
Typography,
|
|
Stack,
|
|
Button,
|
|
TextField,
|
|
Autocomplete,
|
|
Chip,
|
|
Divider,
|
|
DialogTitle,
|
|
DialogContent,
|
|
Checkbox,
|
|
DialogActions,
|
|
CircularProgress,
|
|
IconButton,
|
|
Switch,
|
|
OutlinedInput,
|
|
FormGroup,
|
|
FormControlLabel,
|
|
Box,
|
|
Card,
|
|
useMediaQuery
|
|
} from '@mui/material';
|
|
import CloseIcon from '@mui/icons-material/Close';
|
|
import { calculateDrivingDistance, calculateTotalCharge } from '../../../utils/distance';
|
|
import { Empty } from 'antd';
|
|
import { FaPhoneAlt, FaBox, FaBoxes, FaTruck, FaArrowRight, FaArrowLeft, FaCheck, FaRoute, FaMoneyBillWave, FaChartLine, FaReceipt, FaPaperPlane } from 'react-icons/fa';
|
|
import { GiDoorHandle } from 'react-icons/gi';
|
|
import { FaLandmarkDome } from 'react-icons/fa6';
|
|
import ClearIcon from '@mui/icons-material/Clear';
|
|
import { useNavigate } from 'react-router';
|
|
import { TbMapPinCode } from 'react-icons/tb';
|
|
import { FaLocationDot } from 'react-icons/fa6';
|
|
import axios from 'axios';
|
|
import { useTheme } from '@mui/material/styles';
|
|
import Geocode from 'react-geocode';
|
|
import Loader from 'components/Loader';
|
|
import * as geolib from 'geolib';
|
|
import MainCard from 'components/MainCard';
|
|
import { FaUser } from 'react-icons/fa6';
|
|
import { DatePicker } from '@mui/x-date-pickers/DatePicker';
|
|
import { LocalizationProvider } from '@mui/x-date-pickers/LocalizationProvider';
|
|
import { AdapterDayjs } from '@mui/x-date-pickers/AdapterDayjs';
|
|
import Dialog from '@mui/material/Dialog';
|
|
import dayjs from 'dayjs';
|
|
import { enqueueSnackbar } from 'notistack';
|
|
var utc = require('dayjs/plugin/utc');
|
|
dayjs.extend(utc);
|
|
import { SearchOutlined, CloseOutlined, CalendarOutlined, ClockCircleOutlined, FileTextOutlined, MessageOutlined } from '@ant-design/icons';
|
|
import MyLocationIcon from '@mui/icons-material/MyLocation';
|
|
import HighlightOffIcon from '@mui/icons-material/HighlightOff';
|
|
import { OpenToast } from 'components/third-party/OpenToast';
|
|
import { MapContainer, TileLayer, Marker, Polyline, useMap } from 'react-leaflet';
|
|
import L from 'leaflet';
|
|
import 'leaflet/dist/leaflet.css';
|
|
import './OrdersRedesign.css';
|
|
import ArrowDownwardIcon from '@mui/icons-material/ArrowDownward';
|
|
import AnimateButton from 'components/@extended/AnimateButton';
|
|
|
|
const pickupIcon = typeof window !== 'undefined' ? new L.Icon({
|
|
iconUrl: 'https://raw.githubusercontent.com/pointhi/leaflet-color-markers/master/img/marker-icon-2x-blue.png',
|
|
shadowUrl: 'https://cdnjs.cloudflare.com/ajax/libs/leaflet/1.7.1/images/marker-icon.png',
|
|
iconSize: [25, 41],
|
|
iconAnchor: [12, 41],
|
|
popupAnchor: [1, -34],
|
|
shadowSize: [41, 41]
|
|
}) : null;
|
|
|
|
const dropoffIcon = typeof window !== 'undefined' ? new L.Icon({
|
|
iconUrl: 'https://raw.githubusercontent.com/pointhi/leaflet-color-markers/master/img/marker-icon-2x-red.png',
|
|
shadowUrl: 'https://cdnjs.cloudflare.com/ajax/libs/leaflet/1.7.1/images/marker-icon.png',
|
|
iconSize: [25, 41],
|
|
iconAnchor: [12, 41],
|
|
popupAnchor: [1, -34],
|
|
shadowSize: [41, 41]
|
|
}) : null;
|
|
|
|
const MapBoundsController = ({ startPoint, endPoint }) => {
|
|
const map = useMap();
|
|
useEffect(() => {
|
|
const points = [];
|
|
const pLat = parseFloat(startPoint?.latitude);
|
|
const pLng = parseFloat(startPoint?.longitude);
|
|
const dLat = parseFloat(endPoint?.latitude);
|
|
const dLng = parseFloat(endPoint?.longitude);
|
|
|
|
if (!isNaN(pLat) && !isNaN(pLng) && pLat !== 0 && pLng !== 0) {
|
|
points.push([pLat, pLng]);
|
|
}
|
|
if (!isNaN(dLat) && !isNaN(dLng) && dLat !== 0 && dLng !== 0) {
|
|
points.push([dLat, dLng]);
|
|
}
|
|
|
|
if (points.length === 1) {
|
|
map.setView(points[0], 14);
|
|
} else if (points.length === 2) {
|
|
map.fitBounds(points, { padding: [50, 50] });
|
|
}
|
|
}, [startPoint?.latitude, startPoint?.longitude, endPoint?.latitude, endPoint?.longitude, map]);
|
|
return null;
|
|
};
|
|
|
|
const OrderMap = ({ startPoint, endPoint, appLocaLat, appLocaLng }) => {
|
|
const defaultCenter = [
|
|
parseFloat(appLocaLat) || 11.0168,
|
|
parseFloat(appLocaLng) || 76.9558
|
|
];
|
|
|
|
const hasPick = startPoint?.latitude && startPoint?.longitude && parseFloat(startPoint.latitude) !== 0;
|
|
const hasDrop = endPoint?.latitude && endPoint?.longitude && parseFloat(endPoint.latitude) !== 0;
|
|
|
|
const pickCoords = hasPick ? [parseFloat(startPoint.latitude), parseFloat(startPoint.longitude)] : null;
|
|
const dropCoords = hasDrop ? [parseFloat(endPoint.latitude), parseFloat(endPoint.longitude)] : null;
|
|
|
|
const [routePoints, setRoutePoints] = React.useState([]);
|
|
|
|
React.useEffect(() => {
|
|
if (!hasPick || !hasDrop) {
|
|
setRoutePoints([]);
|
|
return;
|
|
}
|
|
|
|
const getOSRMRoute = async () => {
|
|
const url = `https://router.project-osrm.org/route/v1/driving/${startPoint.longitude},${startPoint.latitude};${endPoint.longitude},${endPoint.latitude}?overview=full&geometries=geojson`;
|
|
try {
|
|
const res = await fetch(url);
|
|
const data = await res.json();
|
|
if (data.routes?.length) {
|
|
const points = data.routes[0].geometry.coordinates.map(([lng, lat]) => [lat, lng]);
|
|
setRoutePoints(points);
|
|
} else {
|
|
setRoutePoints([pickCoords, dropCoords]);
|
|
}
|
|
} catch (err) {
|
|
console.error('OSRM Error:', err);
|
|
setRoutePoints([pickCoords, dropCoords]);
|
|
}
|
|
};
|
|
|
|
getOSRMRoute();
|
|
}, [startPoint.latitude, startPoint.longitude, endPoint.latitude, endPoint.longitude, hasPick, hasDrop]);
|
|
|
|
return (
|
|
<div style={{ position: 'relative', width: '100%', height: '100%' }}>
|
|
<MapContainer
|
|
center={defaultCenter}
|
|
zoom={12}
|
|
style={{ width: '100%', height: '100%' }}
|
|
zoomControl={true}
|
|
>
|
|
<TileLayer
|
|
url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png"
|
|
attribution='© OpenStreetMap contributors'
|
|
/>
|
|
{hasPick && <Marker position={pickCoords} icon={pickupIcon} />}
|
|
{hasDrop && <Marker position={dropCoords} icon={dropoffIcon} />}
|
|
{routePoints.length > 0 ? (
|
|
<Polyline positions={routePoints} color="#662582" weight={4} />
|
|
) : (
|
|
hasPick && hasDrop && <Polyline positions={[pickCoords, dropCoords]} color="#662582" weight={4} />
|
|
)}
|
|
<MapBoundsController startPoint={startPoint} endPoint={endPoint} />
|
|
</MapContainer>
|
|
</div>
|
|
);
|
|
};
|
|
|
|
function loadScript(src, position, id) {
|
|
if (!position) {
|
|
return;
|
|
}
|
|
|
|
const script = document.createElement('script');
|
|
script.setAttribute('async', '');
|
|
script.setAttribute('id', id);
|
|
script.src = src;
|
|
position.appendChild(script);
|
|
}
|
|
|
|
const Createorder1 = () => {
|
|
Geocode.setApiKey(process.env.REACT_APP_GOOGLE_MAPS_API_KEY);
|
|
// ================================================= || GoogleMaps (Drawer) || =================================================
|
|
const loaded = React.useRef(false);
|
|
const navigate = useNavigate();
|
|
const theme = useTheme();
|
|
const isMobile = useMediaQuery(theme.breakpoints.down('md'));
|
|
const locationRef = useRef(null);
|
|
const tenantRef = useRef(null);
|
|
const [inputValue1, setInputValue1] = React.useState('');
|
|
const [inputValue2, setInputValue2] = React.useState('');
|
|
const [tenanatLocoId, setTenanatLocoId] = useState(localStorage.getItem('locationid'));
|
|
const [isLocation, setIsLocation] = useState(false);
|
|
const textFieldRef1 = useRef(null);
|
|
const textFieldRef1a = useRef(null);
|
|
const textFieldRef2 = useRef(null);
|
|
const [appId, setAppId] = useState(0);
|
|
const [open, setOpen] = useState(false);
|
|
const [clientdetail, setClientdetail] = useState([]);
|
|
const [startdate, setStartdate] = useState(dayjs().format('MM-DD-YYYY'));
|
|
// const [starttime, setStatrttime] = useState(`${dayjs().format('MM-DD-YYYY')} 08:00:00`);
|
|
const [starttime, setStatrttime] = useState();
|
|
// const [endtime, setEndtime] = useState(`${dayjs().format('MM-DD-YYYY')} 20:00:00`);
|
|
const [endtime, setEndtime] = useState();
|
|
const [timeslotarr, setTimeslotarr] = useState([]);
|
|
const [otherinstructions, setOtherinstructions] = useState('');
|
|
const [loading2, setLoading2] = useState(false);
|
|
const [loading, setLoading] = useState(false);
|
|
const [btnLoading, setBtnLoading] = useState(false);
|
|
const [alertmessage, setAlertmessage] = useState('');
|
|
const [admintoken, setAdmintoken] = useState();
|
|
const [tenant, setTenant] = useState({});
|
|
const [selectedtime, setSelectedtime] = useState('');
|
|
const [tenantlist, setTenantlist] = useState([]);
|
|
const [startPoint, setStartPoint] = useState({ latitude: 0, longitude: 0 });
|
|
const [endPoint, setEndPoint] = useState({ latitude: 0, longitude: 0 });
|
|
const [showDistance, setShowDistance] = useState(false);
|
|
const [distance, setDistance] = useState(0);
|
|
const [basePrice, setBasePrice] = useState(0);
|
|
const [pricePerKm, setPricePerKm] = useState(0);
|
|
const [minKm, setMinKm] = useState(0);
|
|
const [totalCharge, setTotalCharge] = useState(0);
|
|
const [subCat, setSubCat] = useState([]);
|
|
const [subCatName, setSubCatName] = useState('Select ');
|
|
const [subCatId, setSubCatId] = useState(0);
|
|
const [weight, setWeight] = useState('');
|
|
const [tenantid, setTenantid] = useState(0);
|
|
const [locationid, setLocationid] = useState(0);
|
|
const [selectedCatChip, setSelectedCatChip] = useState(null);
|
|
const [isCustomerOpen, setIsCustomerOpen] = useState(false);
|
|
const [searchCustList, setSearchCustList] = useState('');
|
|
const [customerlist, setCustomerlist] = useState([]);
|
|
const [defaultPickup, setDefaultPickup] = useState(null);
|
|
const [pickCust, setPickCust] = useState(null);
|
|
const [dropCust, setDropCust] = useState(null);
|
|
const [pickordrop, setpickordrop] = useState(0); // 1 ->pick 2 -> drop
|
|
const [addId1, setAddId1] = useState(0);
|
|
const [addId2, setAddId2] = useState(0);
|
|
const [tenantLocations, setTenantlocations] = useState([]);
|
|
const [appLocaLat, setAppLocaLat] = useState();
|
|
const [appLocaLng, setAppLocaLng] = useState();
|
|
const [appLocaRadius, setAppLocaRadius] = useState();
|
|
const [locations, setLocations] = useState('Select Location');
|
|
const userid = localStorage.getItem('userid');
|
|
const [isNumChange1, setIsNumChange1] = useState(0);
|
|
const [isNumChange2, setIsNumChange2] = useState(0);
|
|
const [showCheck1, setShowCheck1] = useState(0);
|
|
const [showCheck2, setShowCheck2] = useState(0);
|
|
const [pickNum, setPickNum] = useState();
|
|
const [dropNum, setdropNum] = useState();
|
|
const [numErr1, setNumErr1] = useState(false);
|
|
const [numErr2, setNumErr2] = useState(false);
|
|
const [isSms, setIsSms] = useState(0);
|
|
const [collectionamt, setCollectionamt] = useState(0);
|
|
const [quantity, setQuantity] = useState(1);
|
|
const [tenantValue, setTenantValue] = useState(null);
|
|
const [locationValue, setLocationValue] = useState(null);
|
|
const [pickupSlotsList, setPickupSlotsList] = useState(null);
|
|
const [pickupSlot, setPickupSlot] = useState(null);
|
|
const [routeStep, setRouteStep] = useState(1); // 1 = Pickup, 2 = Drop
|
|
const pickupStepComplete = !!(
|
|
pickCust?.firstname &&
|
|
pickCust?.contactno &&
|
|
String(pickCust.contactno).length === 10 &&
|
|
pickCust?.doorno &&
|
|
pickCust?.suburb &&
|
|
pickCust?.postcode
|
|
);
|
|
|
|
useEffect(() => {
|
|
console.log('pickupSlotsList', pickupSlotsList);
|
|
console.log('pickupSlot', pickupSlot);
|
|
}, [pickupSlotsList, pickupSlot]);
|
|
|
|
if (typeof window !== 'undefined' && !loaded.current) {
|
|
if (!document.querySelector('#google-maps')) {
|
|
loadScript(
|
|
`https://maps.googleapis.com/maps/api/js?key=${process.env.REACT_APP_GOOGLE_MAPS_API_KEY}&libraries=places&location=10.3656,77.9690&radius=50000&components=country:IN&strictbounds=true`,
|
|
document.querySelector('head'),
|
|
'google-maps'
|
|
);
|
|
}
|
|
loaded.current = true;
|
|
}
|
|
|
|
// ==============================|| fetchAppLocations ||============================== //
|
|
const fetchAppLocations = async () => {
|
|
try {
|
|
const locationRes = await axios.get(`${process.env.REACT_APP_URL}/partners/getlocations/?userid=${userid}`);
|
|
console.log('fetchAppLocations', locationRes.data.details);
|
|
setLocations(locationRes.data.details);
|
|
} catch (err) {
|
|
console.log('locationRes', err);
|
|
}
|
|
};
|
|
useEffect(() => {
|
|
fetchAppLocations();
|
|
}, []);
|
|
|
|
// ===================================================== || fetchtenantinfolist || =====================================================
|
|
|
|
const fetchtenantinfolist = async () => {
|
|
setLoading(true);
|
|
await axios
|
|
.get(`${process.env.REACT_APP_URL}/tenants/gettenants/?applocationid=${appId}&status=active`)
|
|
|
|
.then((res) => {
|
|
console.log(res);
|
|
if (res.data.status) {
|
|
let arr = [];
|
|
res.data.details.map((val) => {
|
|
arr.push({
|
|
...val,
|
|
label: `${val.tenantname}`
|
|
});
|
|
});
|
|
setTenantlist(arr);
|
|
}
|
|
setLoading(false);
|
|
})
|
|
.catch((err) => {
|
|
console.log(err);
|
|
setLoading(false);
|
|
});
|
|
};
|
|
useEffect(() => {
|
|
appId && fetchtenantinfolist();
|
|
}, [appId]);
|
|
|
|
const handleChipClick = (chipLabel) => {
|
|
setSelectedCatChip(chipLabel);
|
|
};
|
|
|
|
const chipStyle = (chipLabel) => ({
|
|
cursor: 'pointer',
|
|
backgroundColor: selectedCatChip === chipLabel ? theme.palette.primary.main : 'default',
|
|
color: selectedCatChip === chipLabel ? '#fff' : '',
|
|
'&:hover': {
|
|
backgroundColor: selectedCatChip === chipLabel ? theme.palette.primary.main : theme.palette.primary.light,
|
|
color: '#fff'
|
|
}
|
|
});
|
|
|
|
const fetchTenantPricing = async (id) => {
|
|
try {
|
|
const pricingResponse = await axios.get(`${process.env.REACT_APP_URL}/tenants/gettenantpricing/?tenantid=${id}`);
|
|
console.log('pricingResponse', pricingResponse.data.details);
|
|
setBasePrice(pricingResponse.data.details.baseprice);
|
|
setPricePerKm(pricingResponse.data.details.priceperkm);
|
|
setMinKm(pricingResponse.data.details.minkm);
|
|
} catch (error) {
|
|
console.log('fetchTenantPricing error', error);
|
|
}
|
|
};
|
|
|
|
useEffect(() => {
|
|
console.log('startPoint', startPoint);
|
|
console.log('endPoint', endPoint);
|
|
if (startPoint.latitude != 0 && startPoint.longitude != 0 && endPoint.latitude != 0 && endPoint.longitude != 0) {
|
|
// getDistance();
|
|
calculateDistance(startPoint, endPoint);
|
|
}
|
|
}, [startPoint, endPoint]);
|
|
|
|
// google distance matrix logic
|
|
const calculateDistance = async (pickup, drop) => {
|
|
try {
|
|
const roundedDistance = await calculateDrivingDistance(pickup, drop);
|
|
console.log('calculated distance in km:', roundedDistance);
|
|
setDistance(roundedDistance);
|
|
|
|
const total = calculateTotalCharge(roundedDistance, basePrice, pricePerKm, minKm);
|
|
console.log('total charge:', total);
|
|
setTotalCharge(total);
|
|
|
|
setShowDistance(true);
|
|
if (roundedDistance > appLocaRadius) {
|
|
setShowDistance(true);
|
|
setOpen(true);
|
|
}
|
|
|
|
// ⏱️ Approximate duration
|
|
const avgSpeed = 40; // km/h (adjust if needed)
|
|
const duration = Math.round((roundedDistance / avgSpeed) * 60); // minutes
|
|
console.log(`Distance: ${roundedDistance}, Duration: ${duration}`);
|
|
} catch (error) {
|
|
console.error('Error calculating distance:', error);
|
|
}
|
|
};
|
|
|
|
useEffect(() => {
|
|
if (tenantid) {
|
|
clientdetails();
|
|
}
|
|
}, [searchCustList?.length > 3, searchCustList == '', tenantid]);
|
|
|
|
useEffect(() => {
|
|
if (timeslotarr[0]) {
|
|
let arr = [];
|
|
timeslotarr.map((val) => {
|
|
if (dayjs().diff(dayjs(`${dayjs(startdate).format('MM-DD-YYYY')} ${dayjs(val).format('HH:mm:ss')}`), 'm') <= 0) {
|
|
arr.push(val);
|
|
}
|
|
});
|
|
}
|
|
}, [timeslotarr]);
|
|
|
|
// ==================================================== || fetchtenantinfo || ====================================================
|
|
const fetchtenantinfo = async () => {
|
|
setLoading(true);
|
|
console.log('tenantid', tenantid);
|
|
|
|
await axios
|
|
.get(`${process.env.REACT_APP_URL}/tenants/gettenantinfo/?tenantid=${tenantid}`)
|
|
.then((res) => {
|
|
console.log('fetchtenantinfo', res);
|
|
if (res.data.status) {
|
|
setTenant(res.data.details);
|
|
|
|
fetchAppAdminTokens();
|
|
setSubCatName(res.data.details.subcategoryname);
|
|
setSubCatId(res.data.details.subcategoryid);
|
|
}
|
|
setLoading(false);
|
|
})
|
|
.catch((err) => {
|
|
console.log(err);
|
|
setLoading(false);
|
|
});
|
|
};
|
|
useEffect(() => {
|
|
if (tenantid) {
|
|
fetchtenantinfo();
|
|
}
|
|
}, [tenantid]);
|
|
// ==================================================== || getsubcategories || ====================================================
|
|
const getsubcategories = async () => {
|
|
await axios
|
|
.get(`${process.env.REACT_APP_URL}/utils/getsubcategories/?moduleid=6`)
|
|
.then((res) => {
|
|
console.log('subcateRes', res.data.details);
|
|
if (res.data.status) {
|
|
setSubCat(res.data.details);
|
|
}
|
|
})
|
|
.catch((err) => {
|
|
console.log(err);
|
|
});
|
|
};
|
|
useEffect(() => {
|
|
getsubcategories();
|
|
}, []);
|
|
|
|
// ==================================================== || fetchTiming || ====================================================
|
|
const fetchTiming = async () => {
|
|
setLoading(true);
|
|
await axios
|
|
.get(`${process.env.REACT_APP_URL}/utils/getapplocations/?applocationid=${appId}`)
|
|
.then((res) => {
|
|
console.log('fetchTiming', res);
|
|
const { opentime, closetime, latitude, longitude, radius } = res.data.details[0];
|
|
if (res.data.status) {
|
|
setAppLocaLat(latitude);
|
|
setAppLocaLng(longitude);
|
|
setAppLocaRadius(radius);
|
|
console.log('radius', radius);
|
|
setStatrttime(`${dayjs().format('MM-DD-YYYY')} ${opentime}`);
|
|
setEndtime(`${dayjs().format('MM-DD-YYYY')} ${closetime}`);
|
|
console.log('starttime', `${dayjs().format('MM-DD-YYYY')} ${opentime}`);
|
|
console.log('endtime', `${dayjs().format('MM-DD-YYYY')} ${closetime} `);
|
|
let arr = [];
|
|
for (
|
|
let i = `${dayjs().format('MM-DD-YYYY')} ${opentime}`, j = 0;
|
|
dayjs(`${dayjs().format('MM-DD-YYYY')} ${closetime} `).diff(i, 'm') >= 0;
|
|
j++, i = dayjs(i).add(30, 'm')
|
|
) {
|
|
arr.push(i);
|
|
}
|
|
console.log('setTimeslotarr', arr);
|
|
setTimeslotarr(arr);
|
|
}
|
|
setLoading(false);
|
|
})
|
|
.catch((err) => {
|
|
console.log(err);
|
|
setLoading(false);
|
|
});
|
|
};
|
|
useEffect(() => {
|
|
if (appId) {
|
|
fetchTiming();
|
|
}
|
|
}, [appId]);
|
|
|
|
// =============================================== || fetchAppAdminTokens (via appId) || ===============================================
|
|
const fetchAppAdminTokens = async () => {
|
|
setLoading(true);
|
|
await axios
|
|
.get(`${process.env.REACT_APP_URL}/utils/getapplocationconfig/?applocationid=${appId}`)
|
|
.then((res) => {
|
|
const userfcmtokemArray = res.data.details.applocationadmins.map((admin) => admin.userfcmtokem); // fcm => firebase cloud messaging
|
|
if (res.data.status) {
|
|
setAdmintoken(userfcmtokemArray);
|
|
}
|
|
setLoading(false);
|
|
})
|
|
.catch((err) => {
|
|
console.log(err);
|
|
setLoading(false);
|
|
});
|
|
};
|
|
|
|
useEffect(() => {
|
|
if (starttime && endtime) {
|
|
fetchAppAdminTokens();
|
|
}
|
|
}, [starttime, endtime]);
|
|
|
|
// =============================================== || opentoast || ===============================================
|
|
|
|
const opentoast = (message, variant, time) => {
|
|
enqueueSnackbar(message, {
|
|
variant: variant,
|
|
anchorOrigin: { vertical: 'top', horizontal: 'right' },
|
|
autoHideDuration: time ? time : 1500
|
|
});
|
|
console.log(alertmessage);
|
|
};
|
|
|
|
const createsubmitobj2 = async () => {
|
|
let arr = {};
|
|
arr = {
|
|
orders: {
|
|
applocationid: tenant.applolcationid,
|
|
cancellled: '',
|
|
categoryid: +tenant.categoryid,
|
|
configid: 9,
|
|
customerid: isNumChange1 == 0 ? +pickCust.customerid || 0 : 0,
|
|
deliveryaddress: dropCust.address || '',
|
|
deliverycharge: +totalCharge.toFixed(2) || 0,
|
|
deliverycity: dropCust.city || '',
|
|
deliverycontactno: dropCust.contactno || '',
|
|
deliverycustomer: dropCust.firstname || '',
|
|
deliveryid: isNumChange2 == 0 ? +dropCust.customerid || 0 : 0,
|
|
deliverylandmark: dropCust.landmark || '',
|
|
deliverylat: dropCust.latitude.toString(),
|
|
deliverylocation: dropCust.suburb || '',
|
|
deliverylocationid: dropCust.deliverylocationid || 0,
|
|
deliverylong: dropCust.longitude.toString(),
|
|
deliverytime: `${dayjs(startdate).format('YYYY-MM-DD')} ${dayjs(selectedtime.$d).format('HH:mm:ss')}`,
|
|
deliverytype: 'B',
|
|
delivered: '',
|
|
itemcount: 1,
|
|
kms: distance.toString() || 0,
|
|
locationid: +locationid,
|
|
moduleid: +tenant.moduleid,
|
|
orderamount: +totalCharge.toFixed(2) || 0,
|
|
ordercharges: 0.0,
|
|
orderdate: dayjs().format('YYYY-MM-DD HH:mm:ss'),
|
|
ordernotes: otherinstructions,
|
|
orderstatus: 'created',
|
|
ordervalue: +totalCharge.toFixed(2) || 0,
|
|
partnerid: tenant.partnerid,
|
|
partneruserid: +userid,
|
|
paymentstatus: 1,
|
|
paymenttype: 42,
|
|
pickupaddress: pickCust.address || '',
|
|
pickupcity: pickCust.city || '',
|
|
pickupcontactno: pickCust.contactno || '',
|
|
pickupcustomer: pickCust.firstname || '',
|
|
pickuplandmark: pickCust.landmark || '',
|
|
pickuplat: pickCust.latitude.toString() || '',
|
|
pickuplocation: pickCust.suburb || '',
|
|
pickuplocationid: pickCust.deliverylocationid || 0,
|
|
pickuplong: pickCust.longitude.toString() || '',
|
|
smsdelivery: isSms,
|
|
subcategoryid: +subCatId,
|
|
tenantid: tenant.tenantid,
|
|
collectionamt: +collectionamt,
|
|
quantity: +quantity,
|
|
weight,
|
|
pickupSlot
|
|
},
|
|
pickup: {
|
|
address: pickCust.address || '',
|
|
applocationid: tenant.applolcationid,
|
|
city: pickCust.city || '',
|
|
configid: 1,
|
|
contactno: pickCust.contactno || '',
|
|
customertoken: '',
|
|
customerid: isNumChange1 == 0 ? pickCust.customerid || 0 : 0,
|
|
devicetype: '',
|
|
deviceid: '',
|
|
dialcode: '+91',
|
|
doorno: pickCust.doorno || '',
|
|
email: pickCust.email || '',
|
|
firstname: pickCust.firstname || '',
|
|
landmark: pickCust.landmark || '',
|
|
latitude: pickCust.latitude.toString() || '',
|
|
longitude: pickCust.longitude.toString() || '',
|
|
postcode: pickCust.postcode || '',
|
|
primaryaddress: 1,
|
|
locationid: pickCust.deliverylocationid || 0,
|
|
profileimage: '',
|
|
state: pickCust.state || '',
|
|
suburb: pickCust.suburb || '',
|
|
tenantid: tenant.tenantid
|
|
},
|
|
drop: {
|
|
address: dropCust.address || '',
|
|
applocationid: tenant.applolcationid,
|
|
city: dropCust.city || '',
|
|
configid: 1,
|
|
contactno: dropCust.contactno || '',
|
|
customertoken: '',
|
|
customerid: isNumChange2 == 0 ? dropCust.customerid || 0 : 0,
|
|
devicetype: '',
|
|
deviceid: '',
|
|
locationid: dropCust.deliverylocationid || 0,
|
|
dialcode: '+91',
|
|
doorno: dropCust.doorno || '',
|
|
email: dropCust.email || '',
|
|
firstname: dropCust.firstname || '',
|
|
landmark: dropCust.landmark || '',
|
|
latitude: dropCust.latitude.toString(),
|
|
longitude: dropCust.longitude.toString(),
|
|
postcode: dropCust.postcode || '',
|
|
primaryaddress: 1,
|
|
profileimage: '',
|
|
state: dropCust.state || '',
|
|
suburb: dropCust.suburb || '',
|
|
tenantid: tenant.tenantid
|
|
}
|
|
};
|
|
console.log('createsubmitobj2', arr);
|
|
if (!pickCust.firstname) {
|
|
opentoast('Enter Pickup Contact Name ', 'warning', 2000);
|
|
} else if (!pickCust.contactno) {
|
|
opentoast('Enter Pickup Contact Number ', 'warning', 2000);
|
|
} else if (pickCust.contactno.length != 10) {
|
|
opentoast('Check Pickup Contact Number ', 'error', 2000);
|
|
} else if (!pickCust.suburb) {
|
|
opentoast('Enter Pickup Location ', 'warning', 2000);
|
|
} else if (!pickCust.city) {
|
|
opentoast('Enter Pickup City ', 'warning', 2000);
|
|
} else if (!pickCust.postcode) {
|
|
opentoast('Enter Pickup Postcode ', 'warning', 2000);
|
|
} else if (!pickCust.landmark) {
|
|
opentoast('Enter Pickup Landmark ', 'warning', 2000);
|
|
} else if (!dropCust.firstname) {
|
|
opentoast('Enter Drop Contact Name ', 'warning', 2000);
|
|
} else if (!dropCust.contactno) {
|
|
opentoast('Enter Drop Contact Number', 'warning', 2000);
|
|
} else if (dropCust.contactno.length !== 10) {
|
|
opentoast('Check Drop Contact Number ', 'error', 2000);
|
|
} else if (!dropCust.suburb) {
|
|
opentoast('Enter Drop Suburb ', 'warning', 2000);
|
|
} else if (!dropCust.city) {
|
|
opentoast('Enter Drop City ', 'warning', 2000);
|
|
} else if (!dropCust.postcode) {
|
|
opentoast('Enter Drop postcode ', 'warning', 2000);
|
|
} else if (!dropCust.landmark) {
|
|
opentoast('Enter Drop Landmark ', 'warning', 2000);
|
|
} else if (!selectedtime) {
|
|
opentoast('Choose deliverytime ', 'warning', 2000);
|
|
} else if (!setSubCatId) {
|
|
opentoast('Choose SubCategory ', 'warning', 2000);
|
|
} else {
|
|
try {
|
|
const createRes = await axios.post(`${process.env.REACT_APP_URL2}/orders/createorder`, arr);
|
|
if (createRes.data.status) {
|
|
console.log('createRes', createRes);
|
|
enqueueSnackbar('Order Created Successfully', {
|
|
variant: 'success',
|
|
anchorOrigin: { vertical: 'top', horizontal: 'right' },
|
|
autoHideDuration: 1000
|
|
});
|
|
if (admintoken) {
|
|
// notifyadmin(admintoken);
|
|
sendnotifications();
|
|
}
|
|
navigate('/nearle/orders');
|
|
} else {
|
|
opentoast('Error in creating orders', 'warning');
|
|
}
|
|
setLoading(false);
|
|
} catch (error) {
|
|
opentoast(error.message, 'warning');
|
|
console.log('createResErr', error);
|
|
}
|
|
}
|
|
};
|
|
|
|
// ========================================================= || clientdetails || =========================================================
|
|
const clientdetails = async () => {
|
|
setLoading2(true);
|
|
try {
|
|
let url =
|
|
searchCustList == ''
|
|
? `${process.env.REACT_APP_URL}/customers/gettenantcustomers/?tenantid=${tenantid}&pageno=1&pagesize=30`
|
|
: `${process.env.REACT_APP_URL}/customers/search/?tenantid=${tenantid}&keyword=${searchCustList}`;
|
|
await axios
|
|
.get(url)
|
|
.then((res) => {
|
|
if (res.data.status) {
|
|
console.log('clientdetails', res.data.details);
|
|
setClientdetail(res.data.details);
|
|
setCustomerlist(res.data.details);
|
|
}
|
|
setLoading2(false);
|
|
})
|
|
.catch((err) => {
|
|
console.log(err);
|
|
setLoading2(false);
|
|
opentoast('server error', 'warning');
|
|
});
|
|
} catch (err) {
|
|
console.log(err);
|
|
setLoading2(false);
|
|
}
|
|
};
|
|
|
|
// ================================================== || sendnotifications || ==================================================
|
|
const sendnotifications = async () => {
|
|
setLoading(true);
|
|
await axios
|
|
.post(`${process.env.REACT_APP_URL}/utils/sendnotifications`, {
|
|
priority: 'high',
|
|
registration_ids: admintoken,
|
|
data: {
|
|
accessid: process.env.REACT_APP_RIDER_ACCESS_ID
|
|
},
|
|
notification: {
|
|
title: 'Nearle Merchant',
|
|
body: 'An Order has been placed successfully,kindly process the same',
|
|
sound: 'ring'
|
|
}
|
|
})
|
|
.then((res) => {
|
|
console.log(res);
|
|
if (res.data.message == 'Success') {
|
|
enqueueSnackbar('Notification sent Successfully', {
|
|
variant: 'success',
|
|
anchorOrigin: { vertical: 'top', horizontal: 'right' },
|
|
autoHideDuration: 1000
|
|
});
|
|
}
|
|
setLoading(false);
|
|
})
|
|
.catch((err) => {
|
|
console.log(err);
|
|
enqueueSnackbar(err.message, {
|
|
variant: 'error',
|
|
anchorOrigin: { vertical: 'top', horizontal: 'right' },
|
|
autoHideDuration: 1000
|
|
});
|
|
setLoading(false);
|
|
});
|
|
};
|
|
// ============================================= || Google Maps Autocomplete(pick) || =============================================
|
|
useEffect(() => {
|
|
// Initialize Google Maps Autocomplete
|
|
if (inputValue1) {
|
|
const autocompleteInput = document.getElementById('addressAuto1');
|
|
const autocomplete = new window.google.maps.places.Autocomplete(autocompleteInput, {
|
|
// types: ['(cities)'], // You can adjust the types parameter based on your requirements
|
|
strictBounds: true,
|
|
bounds: new window.google.maps.Circle({
|
|
// center: new window.google.maps.LatLng(11.0050707, 76.9509083),
|
|
// radius: 100000
|
|
center: new window.google.maps.LatLng(appLocaLat, appLocaLng),
|
|
radius: appLocaRadius * 1000
|
|
}).getBounds()
|
|
});
|
|
|
|
// Event listener for autocomplete place changed
|
|
autocomplete.addListener('place_changed', () => {
|
|
const place = autocomplete.getPlace();
|
|
setInputValue1(`${place.name}, ${place.formatted_address}`);
|
|
console.log('new place', place); // Do something with the selected place
|
|
console.log(' pick (new place) lat lng', { lat: place.geometry.location.lat(), lng: place.geometry.location.lng() }); // Do something with the selected place
|
|
// to trigger getDistance
|
|
setStartPoint({ latitude: place.geometry.location.lat(), longitude: place.geometry.location.lng() });
|
|
setPickCust({ ...pickCust, address: `${place.name} ${place.formatted_address}` });
|
|
const address = {
|
|
address: `${place.name} ${place.formatted_address}`,
|
|
street_number: '',
|
|
route: '',
|
|
locality: '',
|
|
sublocality_level_1: '',
|
|
administrative_area_level_3: '',
|
|
administrative_area_level_1: '',
|
|
country: '',
|
|
postal_code: ''
|
|
};
|
|
place.address_components.forEach((component) => {
|
|
component.types.forEach((type) => {
|
|
switch (type) {
|
|
case 'street_number':
|
|
address.street_number = component.long_name;
|
|
break;
|
|
case 'route':
|
|
address.route = component.long_name;
|
|
break;
|
|
case 'locality':
|
|
address.locality = component.long_name;
|
|
break;
|
|
case 'sublocality_level_1':
|
|
address.sublocality_level_1 = component.long_name;
|
|
break;
|
|
case 'administrative_area_level_3':
|
|
address.administrative_area_level_3 = component.long_name;
|
|
break;
|
|
case 'administrative_area_level_1':
|
|
address.administrative_area_level_1 = component.long_name;
|
|
break;
|
|
case 'country':
|
|
address.country = component.long_name;
|
|
break;
|
|
case 'postal_code':
|
|
address.postal_code = component.long_name;
|
|
break;
|
|
// Add more cases as needed for other types
|
|
}
|
|
});
|
|
});
|
|
|
|
// Use address object as per your requirements
|
|
setPickCust({
|
|
...pickCust,
|
|
address: address.address,
|
|
doorno: `${address.street_number} ${address.route}`,
|
|
suburb: address.sublocality_level_1,
|
|
city: address.locality,
|
|
postcode: address.postal_code,
|
|
latitude: place.geometry.location.lat(),
|
|
longitude: place.geometry.location.lng()
|
|
});
|
|
console.log('Pick Address:', address);
|
|
});
|
|
}
|
|
}, [inputValue1]);
|
|
// ============================================= || Google Maps Autocomplete(Drop) || =============================================
|
|
|
|
useEffect(() => {
|
|
if (inputValue2) {
|
|
// Initialize Google Maps Autocomplete
|
|
const autocompleteInput = document.getElementById('addressAuto2');
|
|
const autocomplete = new window.google.maps.places.Autocomplete(autocompleteInput, {
|
|
// types: ['(cities)'], // You can adjust the types parameter based on your requirements
|
|
strictBounds: true,
|
|
bounds: new window.google.maps.Circle({
|
|
// center: new window.google.maps.LatLng(11.0050707, 76.9509083),
|
|
center: new window.google.maps.LatLng(appLocaLat, appLocaLng),
|
|
radius: appLocaRadius * 1000 //km to m
|
|
// radius: 100000 //km to m
|
|
}).getBounds()
|
|
});
|
|
let arr = [];
|
|
// Event listener for autocomplete place changed
|
|
autocomplete.addListener('place_changed', () => {
|
|
const place = autocomplete.getPlace();
|
|
setInputValue2(`${place.name}, ${place.formatted_address}`);
|
|
console.log('new place', place); // Do something with the selected place
|
|
console.log('drop (new place) lat lng', { lat: place.geometry.location.lat(), lng: place.geometry.location.lng() }); // Do something with the selected place
|
|
setEndPoint({ latitude: place.geometry.location.lat(), longitude: place.geometry.location.lng() });
|
|
|
|
setDropCust({ ...dropCust, address: `${place.name} ${place.formatted_address}` });
|
|
const address = {
|
|
address: `${place.name} ${place.formatted_address}`,
|
|
street_number: '',
|
|
route: '',
|
|
locality: '',
|
|
sublocality_level_1: '',
|
|
administrative_area_level_3: '',
|
|
administrative_area_level_1: '',
|
|
country: '',
|
|
postal_code: ''
|
|
};
|
|
place.address_components.forEach((component) => {
|
|
component.types.forEach((type) => {
|
|
switch (type) {
|
|
case 'street_number':
|
|
address.street_number = component.long_name;
|
|
break;
|
|
case 'route':
|
|
address.route = component.long_name;
|
|
break;
|
|
case 'locality':
|
|
address.locality = component.long_name;
|
|
break;
|
|
case 'sublocality_level_1':
|
|
address.sublocality_level_1 = component.long_name;
|
|
break;
|
|
case 'administrative_area_level_3':
|
|
address.administrative_area_level_3 = component.long_name;
|
|
break;
|
|
case 'administrative_area_level_1':
|
|
address.administrative_area_level_1 = component.long_name;
|
|
break;
|
|
case 'country':
|
|
address.country = component.long_name;
|
|
break;
|
|
case 'postal_code':
|
|
address.postal_code = component.long_name;
|
|
break;
|
|
// Add more cases as needed for other types
|
|
}
|
|
});
|
|
});
|
|
|
|
// Use address object as per your requirements
|
|
setDropCust({
|
|
...dropCust,
|
|
address: address.address,
|
|
doorno: `${address.street_number} ${address.route}`,
|
|
suburb: address.sublocality_level_1,
|
|
city: address.locality,
|
|
postcode: address.postal_code,
|
|
latitude: place.geometry.location.lat(),
|
|
longitude: place.geometry.location.lng()
|
|
});
|
|
console.log('Drop Address:', address);
|
|
});
|
|
}
|
|
}, [inputValue2]);
|
|
|
|
// ============================================= || gettenantlocations (branches) || =============================================
|
|
const gettenantlocations = async (id) => {
|
|
try {
|
|
const res = await axios.get(`${process.env.REACT_APP_URL}/tenants/gettenantlocations/?tenantid=${id}`);
|
|
console.log('gettenantlocations', res.data.details);
|
|
if (res.data.details.length == 1) {
|
|
setTenantlocations(res.data.details);
|
|
setDefaultPickup(res.data.details[0]);
|
|
setLocationid(res.data.details[0].locationid);
|
|
setLocationValue(res.data.details[0].locationid);
|
|
setPickupSlotsList(res.data.details[0].slots);
|
|
} else {
|
|
setTenantlocations(res.data.details);
|
|
}
|
|
} catch (err) {
|
|
console.log('gettenantlocations', err);
|
|
}
|
|
};
|
|
|
|
return (
|
|
<>
|
|
{loading && <Loader />}
|
|
{loading2 && <Loader />}
|
|
|
|
<Box
|
|
className="orders-workspace-bg"
|
|
sx={{
|
|
p: 0,
|
|
m: 0,
|
|
minHeight: 'auto',
|
|
display: 'flex',
|
|
flexDirection: 'column'
|
|
}}
|
|
>
|
|
{/* Header Section — single white card spanning the full row:
|
|
title on the left, service configurators inline on the right. */}
|
|
<Card
|
|
className="orders-card page-header-row"
|
|
sx={{
|
|
mb: { xs: 1.5, sm: 2 },
|
|
display: 'flex',
|
|
flexDirection: { xs: 'column', lg: 'row' },
|
|
alignItems: { xs: 'stretch', lg: 'center' },
|
|
justifyContent: 'space-between',
|
|
gap: { xs: 1.25, lg: 2 },
|
|
px: { xs: 1.75, sm: 2 },
|
|
py: { xs: 0.75, sm: 0.9 },
|
|
flexShrink: 0
|
|
}}
|
|
>
|
|
<Box
|
|
className="header-title-block"
|
|
sx={{
|
|
display: 'flex',
|
|
flexDirection: 'column',
|
|
gap: 0,
|
|
minWidth: 0,
|
|
flex: { lg: '1 1 auto' }
|
|
}}
|
|
>
|
|
<Box sx={{ display: 'flex', alignItems: 'center', gap: 1 }}>
|
|
<Typography sx={{ fontWeight: 700, color: '#1e293b', lineHeight: 1.15, fontSize: { xs: '17px', sm: '19px' } }}>
|
|
Create New Order
|
|
</Typography>
|
|
</Box>
|
|
</Box>
|
|
|
|
<Box
|
|
className="header-configurators"
|
|
sx={{
|
|
display: 'flex',
|
|
flexDirection: { xs: 'column', sm: 'row' },
|
|
alignItems: { xs: 'stretch', sm: 'center' },
|
|
justifyContent: { xs: 'stretch', lg: 'flex-end' },
|
|
gap: 1,
|
|
p: 0,
|
|
width: { xs: '100%', lg: 'auto' },
|
|
flexShrink: 0
|
|
}}
|
|
>
|
|
{/* Choose App location */}
|
|
<Box sx={{ width: { xs: '100%', sm: 180, md: 200, xl: 220 } }}>
|
|
<Autocomplete
|
|
fullWidth
|
|
autoFocus
|
|
size="small"
|
|
ref={locationRef}
|
|
options={locations || []}
|
|
getOptionLabel={(option) => `${option.locationname}`}
|
|
className="header-compact-input"
|
|
onChange={(event, value, reason) => {
|
|
if (reason === 'clear') {
|
|
setAppId(0);
|
|
setTenantid(0);
|
|
setTenantValue(null);
|
|
setTenantlist([]);
|
|
setLocationid(0);
|
|
setLocationValue(null);
|
|
setTenantlocations([]);
|
|
setPickCust(null);
|
|
setDropCust(null);
|
|
} else {
|
|
setAppId(value.applocationid);
|
|
setPickCust(null);
|
|
setDropCust(null);
|
|
setTenantid(0);
|
|
setTenantValue(null);
|
|
setLocationid(0);
|
|
setLocationValue(null);
|
|
setTenantlocations([]);
|
|
}
|
|
}}
|
|
renderInput={(params) => (
|
|
<TextField
|
|
{...params}
|
|
size="small"
|
|
placeholder="Choose Location"
|
|
label="Location"
|
|
InputLabelProps={{ shrink: true }}
|
|
className="header-compact-tf"
|
|
InputProps={{
|
|
...params.InputProps,
|
|
startAdornment: (
|
|
<>
|
|
<FaLocationDot style={{ color: '#94a3b8', fontSize: 12, marginRight: 6, flexShrink: 0 }} />
|
|
{params.InputProps.startAdornment}
|
|
</>
|
|
)
|
|
}}
|
|
/>
|
|
)}
|
|
/>
|
|
</Box>
|
|
|
|
{/* Choose Client */}
|
|
<Box sx={{ width: { xs: '100%', sm: 180, md: 200, xl: 220 } }}>
|
|
<Autocomplete
|
|
fullWidth
|
|
size="small"
|
|
className="header-compact-input"
|
|
options={tenantlist || []}
|
|
value={tenantValue}
|
|
onOpen={(event) => {
|
|
if (!appId) {
|
|
event.preventDefault();
|
|
OpenToast('Please select a your location first!', 'warning', 3000);
|
|
setTimeout(() => {
|
|
locationRef.current?.focus();
|
|
}, 0);
|
|
}
|
|
}}
|
|
onChange={(e, val, reason) => {
|
|
if (reason == 'clear') {
|
|
setTenantid(0);
|
|
setTenantValue(null);
|
|
setLocationid(0);
|
|
setLocationValue(null);
|
|
setTenantlocations([]);
|
|
setPickCust(null);
|
|
setDropCust(null);
|
|
} else {
|
|
setTenantid(val?.tenantid || 0);
|
|
setTenantValue(val);
|
|
setLocationid(0);
|
|
setLocationValue(null);
|
|
fetchTenantPricing(val.tenantid);
|
|
gettenantlocations(val.tenantid);
|
|
setDropCust(null);
|
|
}
|
|
}}
|
|
renderInput={(params) => (
|
|
<TextField
|
|
{...params}
|
|
size="small"
|
|
placeholder="Choose Client"
|
|
label="Client"
|
|
inputRef={tenantRef}
|
|
InputLabelProps={{ shrink: true }}
|
|
className="header-compact-tf"
|
|
InputProps={{
|
|
...params.InputProps,
|
|
startAdornment: (
|
|
<>
|
|
<FaUser style={{ color: '#94a3b8', fontSize: 11, marginRight: 6, flexShrink: 0 }} />
|
|
{params.InputProps.startAdornment}
|
|
</>
|
|
)
|
|
}}
|
|
/>
|
|
)}
|
|
/>
|
|
</Box>
|
|
|
|
{/* Business Location */}
|
|
<Box sx={{ width: { xs: '100%', sm: 200, md: 220, xl: 240 } }}>
|
|
{tenantLocations.length == 1 ? (
|
|
<TextField
|
|
variant="outlined"
|
|
fullWidth
|
|
size="small"
|
|
label="Business Location"
|
|
value={tenantLocations[0].locationname}
|
|
InputLabelProps={{ shrink: true }}
|
|
className="header-compact-tf"
|
|
InputProps={{
|
|
style: { color: theme.palette.primary.main },
|
|
startAdornment: (
|
|
<MyLocationIcon style={{ color: '#94a3b8', fontSize: 14, marginRight: 6, flexShrink: 0 }} />
|
|
)
|
|
}}
|
|
/>
|
|
) : (
|
|
<Autocomplete
|
|
fullWidth
|
|
size="small"
|
|
className="header-compact-input"
|
|
value={locationValue}
|
|
options={tenantLocations || []}
|
|
getOptionLabel={(option) => `${option.locationname} (${option.suburb})` || ''}
|
|
onOpen={(event) => {
|
|
if (!appId && !tenantid) {
|
|
event.preventDefault();
|
|
OpenToast('Please select Location and Tenant first!', 'warning', 3000);
|
|
setTimeout(() => {
|
|
locationRef.current?.focus();
|
|
}, 0);
|
|
} else if (!tenantid) {
|
|
event.preventDefault();
|
|
OpenToast('Please select a your Tenant first!', 'warning', 3000);
|
|
setTimeout(() => {
|
|
tenantRef.current?.focus();
|
|
}, 0);
|
|
}
|
|
}}
|
|
onChange={(event, value, reason) => {
|
|
if (reason === 'clear') {
|
|
setLocationid(0);
|
|
setLocationValue(null);
|
|
setPickCust(null);
|
|
} else {
|
|
setLocationid(value.locationid || 0);
|
|
setLocationValue(value);
|
|
setDefaultPickup(value);
|
|
setPickupSlotsList(value?.slots);
|
|
}
|
|
}}
|
|
renderInput={(params) => (
|
|
<TextField
|
|
{...params}
|
|
size="small"
|
|
placeholder="Select Business Locations"
|
|
label="Business Location"
|
|
color="primary"
|
|
InputLabelProps={{ shrink: true }}
|
|
className="header-compact-tf"
|
|
InputProps={{
|
|
...params.InputProps,
|
|
startAdornment: (
|
|
<>
|
|
<MyLocationIcon style={{ color: '#94a3b8', fontSize: 14, marginRight: 6, flexShrink: 0 }} />
|
|
{params.InputProps.startAdornment}
|
|
</>
|
|
)
|
|
}}
|
|
/>
|
|
)}
|
|
/>
|
|
)}
|
|
</Box>
|
|
</Box>
|
|
</Card>
|
|
|
|
{/* Workspace 2-Column responsive layout */}
|
|
<Grid container spacing={{ xs: 2.5, sm: 3, lg: 4 }}>
|
|
|
|
{/* Left Column: Form & Configurator (7.5 columns on lg+) */}
|
|
<Grid
|
|
item
|
|
xs={12}
|
|
lg={7.5}
|
|
sx={{
|
|
display: 'flex',
|
|
flexDirection: 'column',
|
|
gap: { xs: 1.5, sm: 1.75, lg: 2 }
|
|
}}
|
|
>
|
|
|
|
{/* Card 2: Route Planner (Pickup & Drop) — tighter padding on md+ since
|
|
the two panels now sit side-by-side and need the horizontal room. */}
|
|
<Card className="orders-card" sx={{ p: { xs: 1.25, sm: 1.5, lg: 1.5 } }}>
|
|
{/* Two-step stepper: Pickup → Drop */}
|
|
<Box className="route-stepper">
|
|
<Box
|
|
className={`route-step ${routeStep === 1 ? 'is-active' : ''} ${pickupStepComplete ? 'is-done' : ''} step-pickup`}
|
|
onClick={() => setRouteStep(1)}
|
|
role="button"
|
|
tabIndex={0}
|
|
>
|
|
<Box className="route-step-index">
|
|
{pickupStepComplete && routeStep !== 1 ? <FaCheck /> : '1'}
|
|
</Box>
|
|
<Box className="route-step-text">
|
|
<Typography className="route-step-title">Pickup</Typography>
|
|
<Typography className="route-step-sub">Where to collect</Typography>
|
|
</Box>
|
|
</Box>
|
|
|
|
<Box className={`route-step-connector ${pickupStepComplete ? 'is-done' : ''}`}>
|
|
<Box className="route-step-line" />
|
|
<Box className="route-step-line-arrow">
|
|
<FaArrowRight />
|
|
</Box>
|
|
</Box>
|
|
|
|
<Box
|
|
className={`route-step ${routeStep === 2 ? 'is-active' : ''} step-drop ${!pickupStepComplete ? 'is-locked' : ''}`}
|
|
onClick={() => {
|
|
if (pickupStepComplete) {
|
|
setRouteStep(2);
|
|
} else {
|
|
opentoast('Please complete Pickup details first', 'warning', 2000);
|
|
}
|
|
}}
|
|
role="button"
|
|
tabIndex={0}
|
|
>
|
|
<Box className="route-step-index">2</Box>
|
|
<Box className="route-step-text">
|
|
<Typography className="route-step-title">Drop</Typography>
|
|
<Typography className="route-step-sub">Where to deliver</Typography>
|
|
</Box>
|
|
</Box>
|
|
</Box>
|
|
|
|
<Box className="route-flow">
|
|
|
|
{/* Pickup Details Block */}
|
|
<Box
|
|
className="location-panel pickup-panel"
|
|
sx={{ display: routeStep === 1 ? 'block' : 'none' }}
|
|
>
|
|
<Box className="lp-header">
|
|
<Box className="lp-header-title">
|
|
<Box className="lp-badge">
|
|
<FaLocationDot />
|
|
</Box>
|
|
<Box>
|
|
<Typography className="lp-title">Pickup</Typography>
|
|
<Typography className="lp-subtitle">Where to collect the parcel</Typography>
|
|
</Box>
|
|
</Box>
|
|
<Box className="lp-header-actions">
|
|
<Button
|
|
className="lp-action-btn"
|
|
size="small"
|
|
disabled={!locationid}
|
|
startIcon={<SearchOutlined style={{ fontSize: 13 }} />}
|
|
onClick={() => {
|
|
if (!appId && !tenantid && !locationid) {
|
|
OpenToast('Please select Location, Tenant and Business!', 'warning', 3000);
|
|
} else if (!appId && !tenantid) {
|
|
OpenToast('Please select Location and Tenant!', 'warning', 3000);
|
|
} else if (!appId) {
|
|
OpenToast('Please select Location!', 'warning', 3000);
|
|
} else {
|
|
setIsCustomerOpen(true);
|
|
setpickordrop(1);
|
|
setPickCust(null);
|
|
setInputValue1('');
|
|
setSearchCustList('');
|
|
}
|
|
}}
|
|
>
|
|
From Saved
|
|
</Button>
|
|
</Box>
|
|
</Box>
|
|
|
|
{/* Contact group */}
|
|
<Typography className="field-group-caption">
|
|
Contact
|
|
</Typography>
|
|
<Grid container spacing={1.5} sx={{ mt: 0.5 }}>
|
|
<Grid item xs={12} sm={6}>
|
|
<TextField
|
|
inputRef={textFieldRef1}
|
|
fullWidth
|
|
size="small"
|
|
InputProps={{
|
|
startAdornment: (
|
|
<InputAdornment position="start">
|
|
<FaUser style={{ color: '#64748b' }} />
|
|
</InputAdornment>
|
|
),
|
|
style: { borderRadius: '10px' }
|
|
}}
|
|
variant="outlined"
|
|
label="Contact Name"
|
|
value={pickCust?.firstname || ''}
|
|
onChange={(e) => {
|
|
setPickCust({ ...pickCust, firstname: e.target.value });
|
|
}}
|
|
/>
|
|
</Grid>
|
|
<Grid item xs={12} sm={6}>
|
|
<TextField
|
|
error={numErr1}
|
|
inputRef={textFieldRef1a}
|
|
fullWidth
|
|
size="small"
|
|
type="number"
|
|
InputProps={{
|
|
inputProps: { maxLength: 10 },
|
|
startAdornment: (
|
|
<InputAdornment position="start">
|
|
<FaPhoneAlt style={{ color: numErr1 ? '#ef4444' : '#64748b' }} />
|
|
</InputAdornment>
|
|
),
|
|
style: { borderRadius: '10px' }
|
|
}}
|
|
variant="outlined"
|
|
label="Contact Number"
|
|
value={pickCust?.contactno || ''}
|
|
onChange={(e) => {
|
|
if (e.target.value.length <= 10) {
|
|
setPickCust({ ...pickCust, contactno: e.target.value });
|
|
}
|
|
if (pickNum == e.target.value) {
|
|
setShowCheck1(0);
|
|
} else {
|
|
setShowCheck1(1);
|
|
}
|
|
if (e.target.value.length < 10) {
|
|
setNumErr1(true);
|
|
} else {
|
|
setNumErr1(false);
|
|
}
|
|
}}
|
|
/>
|
|
</Grid>
|
|
</Grid>
|
|
|
|
{/* Address Autocomplete */}
|
|
<Typography className="field-group-caption" sx={{ mt: 2 }}>
|
|
Address Lookup
|
|
</Typography>
|
|
{addId1 == 0 ? (
|
|
<TextField
|
|
id="addressAuto1"
|
|
fullWidth
|
|
size="small"
|
|
placeholder="Search Google Maps for an address..."
|
|
variant="outlined"
|
|
value={inputValue1 || ''}
|
|
onChange={(e) => setInputValue1(e.target.value)}
|
|
helperText="Start typing to auto-fill the address details below"
|
|
FormHelperTextProps={{ className: 'address-search-helper pickup-helper' }}
|
|
InputProps={{
|
|
startAdornment: (
|
|
<InputAdornment position="start">
|
|
<SearchOutlined style={{ fontSize: 15, color: '#662582' }} />
|
|
</InputAdornment>
|
|
),
|
|
endAdornment: (
|
|
<IconButton
|
|
onClick={() => {
|
|
setInputValue1('');
|
|
setPickCust({
|
|
...pickCust,
|
|
doorno: '',
|
|
suburb: '',
|
|
city: '',
|
|
postcode: '',
|
|
landmark: ''
|
|
});
|
|
setShowDistance(false);
|
|
setStartPoint({ latitude: 0, longitude: 0 });
|
|
}}
|
|
size="small"
|
|
>
|
|
<CloseIcon fontSize="small" />
|
|
</IconButton>
|
|
),
|
|
style: { borderRadius: '10px', background: '#fff' }
|
|
}}
|
|
/>
|
|
) : (
|
|
<TextField
|
|
variant="outlined"
|
|
fullWidth
|
|
size="small"
|
|
helperText="Saved address selected · clear to search again"
|
|
FormHelperTextProps={{ className: 'address-search-helper pickup-helper' }}
|
|
InputProps={{
|
|
startAdornment: (
|
|
<InputAdornment position="start">
|
|
<FaLocationDot style={{ fontSize: 14, color: '#662582' }} />
|
|
</InputAdornment>
|
|
),
|
|
endAdornment: (
|
|
<IconButton
|
|
onClick={() => {
|
|
setAddId1(0);
|
|
setPickCust({
|
|
...pickCust,
|
|
doorno: '',
|
|
suburb: '',
|
|
city: '',
|
|
postcode: '',
|
|
landmark: ''
|
|
});
|
|
setShowDistance(false);
|
|
setStartPoint({ latitude: 0, longitude: 0 });
|
|
}}
|
|
size="small"
|
|
>
|
|
<ClearIcon fontSize="small" />
|
|
</IconButton>
|
|
),
|
|
style: { borderRadius: '10px', background: '#fff' }
|
|
}}
|
|
value={pickCust?.address || ''}
|
|
onChange={(e) => {
|
|
setPickCust({ ...pickCust, address: e.target.value });
|
|
if (e.target.value == '') {
|
|
setAddId1(0);
|
|
setShowDistance(false);
|
|
setStartPoint({ latitude: 0, longitude: 0 });
|
|
}
|
|
}}
|
|
/>
|
|
)}
|
|
|
|
{/* Address details */}
|
|
<Typography className="field-group-caption" sx={{ mt: 2 }}>
|
|
Address Details
|
|
</Typography>
|
|
<Grid container spacing={1.5} sx={{ mt: 0.5 }}>
|
|
<Grid item xs={12} sm={6}>
|
|
<TextField
|
|
fullWidth
|
|
size="small"
|
|
InputProps={{
|
|
startAdornment: (
|
|
<InputAdornment position="start">
|
|
<GiDoorHandle style={{ color: '#64748b', fontSize: '20px' }} />
|
|
</InputAdornment>
|
|
),
|
|
style: { borderRadius: '10px' }
|
|
}}
|
|
variant="outlined"
|
|
label="Door No / Street"
|
|
value={pickCust?.doorno || ''}
|
|
onChange={(e) => {
|
|
setPickCust({ ...pickCust, doorno: e.target.value });
|
|
}}
|
|
/>
|
|
</Grid>
|
|
<Grid item xs={12} sm={6}>
|
|
<TextField
|
|
fullWidth
|
|
size="small"
|
|
InputProps={{
|
|
startAdornment: (
|
|
<InputAdornment position="start">
|
|
<FaLocationDot style={{ color: '#64748b' }} />
|
|
</InputAdornment>
|
|
),
|
|
style: { borderRadius: '10px' }
|
|
}}
|
|
variant="outlined"
|
|
label="Location"
|
|
value={pickCust?.suburb || ''}
|
|
onChange={(e) => {
|
|
setPickCust({ ...pickCust, suburb: e.target.value });
|
|
}}
|
|
/>
|
|
</Grid>
|
|
<Grid item xs={12} sm={6}>
|
|
<TextField
|
|
fullWidth
|
|
size="small"
|
|
InputProps={{
|
|
startAdornment: (
|
|
<InputAdornment position="start">
|
|
<TbMapPinCode style={{ color: '#64748b', fontSize: '20px' }} />
|
|
</InputAdornment>
|
|
),
|
|
style: { borderRadius: '10px' }
|
|
}}
|
|
variant="outlined"
|
|
label="Postcode"
|
|
value={pickCust?.postcode || ''}
|
|
onChange={(e) => {
|
|
setPickCust({ ...pickCust, postcode: e.target.value });
|
|
}}
|
|
/>
|
|
</Grid>
|
|
<Grid item xs={12} sm={6}>
|
|
<TextField
|
|
fullWidth
|
|
size="small"
|
|
InputProps={{
|
|
startAdornment: (
|
|
<InputAdornment position="start">
|
|
<FaLandmarkDome style={{ color: '#64748b' }} />
|
|
</InputAdornment>
|
|
),
|
|
style: { borderRadius: '10px' }
|
|
}}
|
|
variant="outlined"
|
|
label="Landmark"
|
|
value={pickCust?.landmark || ''}
|
|
onChange={(e) => {
|
|
setPickCust({ ...pickCust, landmark: e.target.value });
|
|
}}
|
|
/>
|
|
</Grid>
|
|
</Grid>
|
|
|
|
{/* Save for later */}
|
|
{showCheck1 == 1 && (
|
|
<Box sx={{ display: 'flex', justifyContent: 'flex-end', mt: 1 }}>
|
|
<Box className="save-later-pill">
|
|
<FormControlLabel
|
|
control={
|
|
<Checkbox
|
|
size="small"
|
|
checked={isNumChange1 === 1}
|
|
onChange={(e) => {
|
|
setIsNumChange1(e.target.checked ? 1 : 0);
|
|
}}
|
|
/>
|
|
}
|
|
label="Save contact for later"
|
|
/>
|
|
</Box>
|
|
</Box>
|
|
)}
|
|
|
|
{/* Step navigation */}
|
|
<Box className="step-nav">
|
|
<Typography className="step-nav-hint">
|
|
{pickupStepComplete
|
|
? 'Pickup looks good. Proceed to Drop details.'
|
|
: 'Fill the required Pickup fields to continue.'}
|
|
</Typography>
|
|
<Button
|
|
className="step-nav-btn step-nav-next"
|
|
disabled={!pickupStepComplete}
|
|
endIcon={<FaArrowRight style={{ fontSize: 12 }} />}
|
|
onClick={() => setRouteStep(2)}
|
|
>
|
|
Continue to Drop
|
|
</Button>
|
|
</Box>
|
|
</Box>
|
|
|
|
{/* Drop Details Block */}
|
|
<Box
|
|
className="location-panel drop-panel"
|
|
sx={{ display: routeStep === 2 ? 'block' : 'none' }}
|
|
>
|
|
<Box className="lp-header">
|
|
<Box className="lp-header-title">
|
|
<Box className="lp-badge">
|
|
<FaLocationDot />
|
|
</Box>
|
|
<Box>
|
|
<Typography className="lp-title">Drop</Typography>
|
|
<Typography className="lp-subtitle">Where to deliver the parcel</Typography>
|
|
</Box>
|
|
</Box>
|
|
<Box className="lp-header-actions">
|
|
<Button
|
|
className="lp-action-btn"
|
|
size="small"
|
|
disabled={!locationid}
|
|
startIcon={<SearchOutlined style={{ fontSize: 13 }} />}
|
|
onClick={() => {
|
|
if (!appId && !tenantid && !locationid) {
|
|
OpenToast('Please select Location, Tenant and Business!', 'warning', 3000);
|
|
} else if (!appId && !tenantid) {
|
|
OpenToast('Please select Location and Tenant!', 'warning', 3000);
|
|
} else if (!appId) {
|
|
OpenToast('Please select Location!', 'warning', 3000);
|
|
} else {
|
|
setIsCustomerOpen(true);
|
|
setpickordrop(2);
|
|
setInputValue2('');
|
|
}
|
|
}}
|
|
>
|
|
From Saved
|
|
</Button>
|
|
</Box>
|
|
</Box>
|
|
|
|
{/* Contact group */}
|
|
<Typography className="field-group-caption">
|
|
Contact
|
|
</Typography>
|
|
<Grid container spacing={1.5} sx={{ mt: 0.5 }}>
|
|
<Grid item xs={12} sm={6}>
|
|
<TextField
|
|
inputRef={textFieldRef2}
|
|
fullWidth
|
|
size="small"
|
|
variant="outlined"
|
|
label="Contact Name"
|
|
InputProps={{
|
|
startAdornment: (
|
|
<InputAdornment position="start">
|
|
<FaUser style={{ color: '#64748b' }} />
|
|
</InputAdornment>
|
|
),
|
|
style: { borderRadius: '10px' }
|
|
}}
|
|
value={dropCust?.firstname || ''}
|
|
onChange={(e) => {
|
|
setDropCust({ ...dropCust, firstname: e.target.value });
|
|
}}
|
|
/>
|
|
</Grid>
|
|
<Grid item xs={12} sm={6}>
|
|
<TextField
|
|
error={numErr2}
|
|
fullWidth
|
|
size="small"
|
|
type="number"
|
|
variant="outlined"
|
|
label="Contact Number"
|
|
InputProps={{
|
|
startAdornment: (
|
|
<InputAdornment position="start">
|
|
<FaPhoneAlt style={{ color: numErr2 ? '#ef4444' : '#64748b' }} />
|
|
</InputAdornment>
|
|
),
|
|
style: { borderRadius: '10px' }
|
|
}}
|
|
value={dropCust?.contactno || ''}
|
|
onChange={(e) => {
|
|
if (e.target.value.length <= 10) {
|
|
setDropCust({ ...dropCust, contactno: e.target.value });
|
|
}
|
|
if (dropNum == e.target.value) {
|
|
setShowCheck2(0);
|
|
} else {
|
|
setShowCheck2(1);
|
|
}
|
|
if (e.target.value.length < 10) {
|
|
setNumErr2(true);
|
|
} else {
|
|
setNumErr2(false);
|
|
}
|
|
}}
|
|
/>
|
|
</Grid>
|
|
</Grid>
|
|
|
|
{/* Address Autocomplete */}
|
|
<Typography className="field-group-caption" sx={{ mt: 2 }}>
|
|
Address Lookup
|
|
</Typography>
|
|
{addId2 == 0 ? (
|
|
<TextField
|
|
id="addressAuto2"
|
|
placeholder="Search Google Maps for an address..."
|
|
variant="outlined"
|
|
size="small"
|
|
fullWidth
|
|
value={inputValue2 || ''}
|
|
onChange={(e) => setInputValue2(e.target.value)}
|
|
helperText="Start typing to auto-fill the address details below"
|
|
FormHelperTextProps={{ className: 'address-search-helper drop-helper' }}
|
|
InputProps={{
|
|
startAdornment: (
|
|
<InputAdornment position="start">
|
|
<SearchOutlined style={{ fontSize: 15, color: '#65387a' }} />
|
|
</InputAdornment>
|
|
),
|
|
endAdornment: (
|
|
<IconButton
|
|
onClick={() => {
|
|
setInputValue2('');
|
|
setDropCust({
|
|
...dropCust,
|
|
doorno: '',
|
|
suburb: '',
|
|
city: '',
|
|
postcode: '',
|
|
landmark: ''
|
|
});
|
|
setShowDistance(false);
|
|
setEndPoint({ latitude: 0, longitude: 0 });
|
|
}}
|
|
size="small"
|
|
>
|
|
<CloseIcon fontSize="small" />
|
|
</IconButton>
|
|
),
|
|
style: { borderRadius: '10px', background: '#fff' }
|
|
}}
|
|
/>
|
|
) : (
|
|
<TextField
|
|
variant="outlined"
|
|
fullWidth
|
|
size="small"
|
|
helperText="Saved address selected · clear to search again"
|
|
FormHelperTextProps={{ className: 'address-search-helper drop-helper' }}
|
|
InputProps={{
|
|
startAdornment: (
|
|
<InputAdornment position="start">
|
|
<FaLocationDot style={{ fontSize: 14, color: '#65387a' }} />
|
|
</InputAdornment>
|
|
),
|
|
endAdornment: (
|
|
<IconButton
|
|
onClick={() => {
|
|
setAddId2(0);
|
|
setDropCust({
|
|
...dropCust,
|
|
doorno: '',
|
|
suburb: '',
|
|
city: '',
|
|
postcode: '',
|
|
landmark: ''
|
|
});
|
|
setShowDistance(false);
|
|
setEndPoint({ latitude: 0, longitude: 0 });
|
|
}}
|
|
size="small"
|
|
>
|
|
<ClearIcon fontSize="small" />
|
|
</IconButton>
|
|
),
|
|
style: { borderRadius: '10px', background: '#fff' }
|
|
}}
|
|
value={dropCust?.address || ''}
|
|
onChange={(e) => {
|
|
setDropCust({ ...dropCust, address: e.target.value });
|
|
if (e.target.value == '') {
|
|
setAddId2(0);
|
|
setShowDistance(false);
|
|
setEndPoint({ latitude: 0, longitude: 0 });
|
|
}
|
|
}}
|
|
/>
|
|
)}
|
|
|
|
{/* Address details */}
|
|
<Typography className="field-group-caption" sx={{ mt: 2 }}>
|
|
Address Details
|
|
</Typography>
|
|
<Grid container spacing={1.5} sx={{ mt: 0.5 }}>
|
|
<Grid item xs={12} sm={6}>
|
|
<TextField
|
|
fullWidth
|
|
size="small"
|
|
variant="outlined"
|
|
label="Door No / Street"
|
|
InputProps={{
|
|
startAdornment: (
|
|
<InputAdornment position="start">
|
|
<GiDoorHandle style={{ color: '#64748b', fontSize: '20px' }} />
|
|
</InputAdornment>
|
|
),
|
|
style: { borderRadius: '10px' }
|
|
}}
|
|
value={dropCust?.doorno || ''}
|
|
onChange={(e) => {
|
|
setDropCust({ ...dropCust, doorno: e.target.value });
|
|
}}
|
|
/>
|
|
</Grid>
|
|
<Grid item xs={12} sm={6}>
|
|
<TextField
|
|
fullWidth
|
|
size="small"
|
|
variant="outlined"
|
|
label="Location"
|
|
InputProps={{
|
|
startAdornment: (
|
|
<InputAdornment position="start">
|
|
<FaLocationDot style={{ color: '#64748b' }} />
|
|
</InputAdornment>
|
|
),
|
|
style: { borderRadius: '10px' }
|
|
}}
|
|
value={dropCust?.suburb || ''}
|
|
onChange={(e) => {
|
|
setDropCust({ ...dropCust, suburb: e.target.value });
|
|
}}
|
|
/>
|
|
</Grid>
|
|
<Grid item xs={12} sm={6}>
|
|
<TextField
|
|
fullWidth
|
|
size="small"
|
|
variant="outlined"
|
|
label="Postcode"
|
|
InputProps={{
|
|
startAdornment: (
|
|
<InputAdornment position="start">
|
|
<TbMapPinCode style={{ color: '#64748b', fontSize: '20px' }} />
|
|
</InputAdornment>
|
|
),
|
|
style: { borderRadius: '10px' }
|
|
}}
|
|
value={dropCust?.postcode || ''}
|
|
onChange={(e) => {
|
|
setDropCust({ ...dropCust, postcode: e.target.value });
|
|
}}
|
|
/>
|
|
</Grid>
|
|
<Grid item xs={12} sm={6}>
|
|
<TextField
|
|
fullWidth
|
|
size="small"
|
|
variant="outlined"
|
|
label="Landmark"
|
|
InputProps={{
|
|
startAdornment: (
|
|
<InputAdornment position="start">
|
|
<FaLandmarkDome style={{ color: '#64748b' }} />
|
|
</InputAdornment>
|
|
),
|
|
style: { borderRadius: '10px' }
|
|
}}
|
|
value={dropCust?.landmark || ''}
|
|
onChange={(e) => {
|
|
setDropCust({ ...dropCust, landmark: e.target.value });
|
|
}}
|
|
/>
|
|
</Grid>
|
|
</Grid>
|
|
|
|
{/* Save for later */}
|
|
{showCheck2 == 1 && (
|
|
<Box sx={{ display: 'flex', justifyContent: 'flex-end', mt: 1 }}>
|
|
<Box className="save-later-pill">
|
|
<FormControlLabel
|
|
control={
|
|
<Checkbox
|
|
size="small"
|
|
checked={isNumChange2 === 1}
|
|
onChange={(e) => {
|
|
setIsNumChange2(e.target.checked ? 1 : 0);
|
|
}}
|
|
/>
|
|
}
|
|
label="Save contact for later"
|
|
/>
|
|
</Box>
|
|
</Box>
|
|
)}
|
|
|
|
{/* Step navigation */}
|
|
<Box className="step-nav">
|
|
<Button
|
|
className="step-nav-btn step-nav-back"
|
|
startIcon={<FaArrowLeft style={{ fontSize: 12 }} />}
|
|
onClick={() => setRouteStep(1)}
|
|
>
|
|
Back to Pickup
|
|
</Button>
|
|
<Typography className="step-nav-hint">
|
|
Review the route below once Drop is filled.
|
|
</Typography>
|
|
</Box>
|
|
</Box>
|
|
</Box>
|
|
</Card>
|
|
|
|
{/* Card 3: Cargo & Dispatch Logistics */}
|
|
<Card className="orders-card" sx={{ p: { xs: 1.5, sm: 1.75, lg: 2 } }}>
|
|
<Box className="section-title-bar" sx={{ mb: 1.25 }}>
|
|
<Typography sx={{ fontWeight: 700, color: '#1e293b', fontSize: '15px', letterSpacing: '-0.01em' }}>
|
|
Cargo & Dispatch Logistics
|
|
</Typography>
|
|
</Box>
|
|
|
|
<Grid container spacing={1.5} alignItems="stretch">
|
|
{/* Section Header: Cargo Details */}
|
|
<Grid item xs={12} sx={{ pt: '0 !important' }}>
|
|
<Box sx={{ display: 'flex', alignItems: 'center', gap: 1, mb: 0.25 }}>
|
|
<Typography sx={{ fontWeight: 700, fontSize: '10.5px', color: '#64748b', letterSpacing: '0.7px', textTransform: 'uppercase' }}>
|
|
Cargo Details
|
|
</Typography>
|
|
<Box sx={{ flex: 1, height: '1px', background: 'linear-gradient(90deg, #eef2f6 0%, transparent 100%)' }} />
|
|
</Box>
|
|
</Grid>
|
|
|
|
{/* Row 1: Category, Cash Collect, Quantity */}
|
|
<Grid item xs={12} sm={4}>
|
|
<Stack>
|
|
<Autocomplete
|
|
id="combo-box-demo"
|
|
size="small"
|
|
options={subCat}
|
|
getOptionLabel={(option) => option?.subcategoryname || ''}
|
|
fullWidth
|
|
sx={{
|
|
'& .MuiOutlinedInput-root': {
|
|
borderRadius: '12px',
|
|
height: '38px',
|
|
paddingTop: '0px !important',
|
|
paddingBottom: '0px !important'
|
|
}
|
|
}}
|
|
renderInput={(params) => (
|
|
<TextField
|
|
{...params}
|
|
label="Category"
|
|
size="small"
|
|
InputLabelProps={{ shrink: true }}
|
|
sx={{ '& .MuiOutlinedInput-root': { borderRadius: '12px', height: '38px' } }}
|
|
InputProps={{
|
|
...params.InputProps,
|
|
startAdornment: (
|
|
<>
|
|
<FaBox style={{ color: '#94a3b8', fontSize: 13, marginRight: 6, marginLeft: 2, flexShrink: 0 }} />
|
|
{params.InputProps.startAdornment}
|
|
</>
|
|
)
|
|
}}
|
|
/>
|
|
)}
|
|
onChange={(event, value, reason) => {
|
|
if (value) {
|
|
console.log(value);
|
|
setSubCatName(value.subcategoryname || '');
|
|
setSubCatId(value.subcategoryid || 0);
|
|
} else if (reason) {
|
|
setSubCatName(null);
|
|
setSubCatId(null);
|
|
}
|
|
}}
|
|
/>
|
|
</Stack>
|
|
</Grid>
|
|
|
|
<Grid item xs={12} sm={4}>
|
|
<Stack>
|
|
<TextField
|
|
type="number"
|
|
size="small"
|
|
value={collectionamt}
|
|
fullWidth
|
|
label="Cash Collect"
|
|
InputLabelProps={{ shrink: true }}
|
|
onChange={(e) => {
|
|
setCollectionamt(e.target.value);
|
|
}}
|
|
inputProps={{ min: 0 }}
|
|
sx={{ '& .MuiOutlinedInput-root': { borderRadius: '12px', height: '38px' } }}
|
|
InputProps={{
|
|
startAdornment: (
|
|
<InputAdornment position="start">
|
|
<Box sx={{ color: '#94a3b8', fontWeight: 700, fontSize: 14, lineHeight: 1 }}>₹</Box>
|
|
</InputAdornment>
|
|
)
|
|
}}
|
|
/>
|
|
</Stack>
|
|
</Grid>
|
|
|
|
<Grid item xs={12} sm={4}>
|
|
<Stack>
|
|
<TextField
|
|
type="number"
|
|
size="small"
|
|
value={quantity}
|
|
fullWidth
|
|
label="Quantity"
|
|
InputLabelProps={{ shrink: true }}
|
|
onChange={(e) => {
|
|
setQuantity(e.target.value);
|
|
}}
|
|
inputProps={{ min: 1 }}
|
|
sx={{ '& .MuiOutlinedInput-root': { borderRadius: '12px', height: '38px' } }}
|
|
InputProps={{
|
|
startAdornment: (
|
|
<InputAdornment position="start">
|
|
<FaBoxes style={{ color: '#94a3b8', fontSize: 14 }} />
|
|
</InputAdornment>
|
|
)
|
|
}}
|
|
/>
|
|
</Stack>
|
|
</Grid>
|
|
|
|
{/* Section Header: Handover & Schedule */}
|
|
<Grid item xs={12} sx={{ mt: 0.5, pb: 0 }}>
|
|
<Box sx={{ display: 'flex', alignItems: 'center', gap: 1, mb: 0.5 }}>
|
|
<Typography sx={{ display: 'flex', alignItems: 'center', gap: 0.75, fontWeight: 700, fontSize: '10.5px', color: '#64748b', letterSpacing: '0.7px', textTransform: 'uppercase' }}>
|
|
<CalendarOutlined style={{ fontSize: '11px', color: '#65387a' }} />
|
|
Schedule Details
|
|
</Typography>
|
|
<Box sx={{ flex: 1, height: '1px', background: 'linear-gradient(90deg, #eef2f6 0%, transparent 100%)' }} />
|
|
</Box>
|
|
</Grid>
|
|
|
|
{/* Nested Grid Container with tight spacing to eliminate excessive gaps */}
|
|
<Grid item xs={12} sx={{ pt: '0px !important' }}>
|
|
<Grid container spacing={1.5} sx={{ mt: 0.5 }}>
|
|
{/* Row 3: Pickup Date & Time Slot (Side-by-Side) */}
|
|
<Grid item xs={12} sm={6}>
|
|
<LocalizationProvider dateAdapter={AdapterDayjs}>
|
|
<DatePicker
|
|
label="Pickup Date"
|
|
format="DD-MM-YYYY"
|
|
onChange={(e) => {
|
|
let dateres11 = dayjs().diff(dayjs(`${dayjs(e).format('YYYY-MM-DD')}`), 'd');
|
|
setSelectedtime('');
|
|
if (dateres11 <= 0) {
|
|
setStartdate(e);
|
|
let arr = [];
|
|
timeslotarr.map((val) => {
|
|
if (
|
|
dayjs().diff(dayjs(`${dayjs(e).format('MM-DD-YYYY')} ${dayjs(val).format('HH:mm:ss')}`), 'm') <= 0
|
|
) {
|
|
arr.push(val);
|
|
}
|
|
});
|
|
} else {
|
|
setAlertmessage('choose Upcoming Date');
|
|
opentoast('choose Upcoming Date', 'warning');
|
|
setStartdate(NaN);
|
|
}
|
|
}}
|
|
value={dayjs(startdate)}
|
|
sx={{
|
|
width: '100%',
|
|
'& .MuiOutlinedInput-root': {
|
|
borderRadius: '12px',
|
|
height: '38px'
|
|
}
|
|
}}
|
|
slotProps={{
|
|
textField: {
|
|
size: 'small',
|
|
fullWidth: true,
|
|
InputLabelProps: { shrink: true },
|
|
InputProps: {
|
|
startAdornment: (
|
|
<InputAdornment position="start">
|
|
<CalendarOutlined style={{ color: '#94a3b8', fontSize: '13px' }} />
|
|
</InputAdornment>
|
|
)
|
|
},
|
|
sx: {
|
|
'& .MuiOutlinedInput-root': {
|
|
borderRadius: '12px',
|
|
height: '38px',
|
|
paddingLeft: '10px'
|
|
}
|
|
}
|
|
}
|
|
}}
|
|
disablePast
|
|
/>
|
|
</LocalizationProvider>
|
|
</Grid>
|
|
|
|
<Grid item xs={12} sm={6}>
|
|
<Autocomplete
|
|
size="small"
|
|
fullWidth
|
|
options={pickupSlotsList || []}
|
|
sx={{
|
|
width: '100%',
|
|
'& .MuiOutlinedInput-root': {
|
|
borderRadius: '12px',
|
|
height: '38px',
|
|
paddingTop: '0px !important',
|
|
paddingBottom: '0px !important'
|
|
}
|
|
}}
|
|
onChange={(e, newValue, reason) => {
|
|
if (reason === 'clear' || !newValue) {
|
|
setSelectedtime(null);
|
|
setPickupSlot(null);
|
|
} else {
|
|
const formattedTime = dayjs(newValue.time, 'HH:mm').format('hh:mm A');
|
|
setSelectedtime(formattedTime);
|
|
const finalDateTime = dayjs(`${startdate} ${formattedTime}`, 'MM-DD-YYYY hh:mm A').format(
|
|
'YYYY-MM-DD hh:mm A'
|
|
);
|
|
setPickupSlot(finalDateTime);
|
|
}
|
|
}}
|
|
getOptionLabel={(option) => option ? `${option.name} (${dayjs(option.time, 'HH:mm').format('hh:mm A')})` : ''}
|
|
renderInput={(params) => (
|
|
<TextField
|
|
{...params}
|
|
label="Pickup Time Slot"
|
|
placeholder="Select Pickup Slot"
|
|
fullWidth
|
|
InputLabelProps={{ shrink: true }}
|
|
sx={{ '& .MuiOutlinedInput-root': { borderRadius: '12px', height: '38px' } }}
|
|
InputProps={{
|
|
...params.InputProps,
|
|
startAdornment: (
|
|
<>
|
|
<ClockCircleOutlined style={{ color: '#94a3b8', fontSize: '13px', marginRight: '6px', marginLeft: '2px', flexShrink: 0 }} />
|
|
{params.InputProps.startAdornment}
|
|
</>
|
|
)
|
|
}}
|
|
/>
|
|
)}
|
|
/>
|
|
</Grid>
|
|
|
|
</Grid>
|
|
</Grid>
|
|
</Grid>
|
|
</Card>
|
|
</Grid>
|
|
|
|
{/* Right Column: Live Map & Cost Summary Panel (4.5 columns on lg+, sticky) */}
|
|
<Grid
|
|
item
|
|
xs={12}
|
|
lg={4.5}
|
|
sx={{
|
|
position: { lg: 'sticky' },
|
|
top: { lg: '24px' },
|
|
height: 'fit-content'
|
|
}}
|
|
>
|
|
<Stack spacing={2}>
|
|
|
|
{/* Map Card */}
|
|
<Card className="orders-card" sx={{ p: 1.5, display: 'flex', flexDirection: 'column' }}>
|
|
<Typography sx={{ fontWeight: 700, mb: 1.25, display: 'flex', alignItems: 'center', gap: 0.75, color: '#1e293b', fontSize: '14px', letterSpacing: '-0.01em' }}>
|
|
<MyLocationIcon sx={{ color: '#662582', fontSize: 16 }} />
|
|
Live Route Preview
|
|
</Typography>
|
|
<div className="map-preview-wrapper">
|
|
<OrderMap startPoint={startPoint} endPoint={endPoint} appLocaLat={appLocaLat} appLocaLng={appLocaLng} />
|
|
</div>
|
|
</Card>
|
|
|
|
{/* Delivery Preferences — Dispatch Notes & SMS Updates */}
|
|
<Card className="orders-card delivery-prefs-card" sx={{ p: 1.5 }}>
|
|
<Box className="delivery-prefs-header">
|
|
<Typography className="delivery-prefs-title">Delivery Preferences</Typography>
|
|
<Typography className="delivery-prefs-sub">Customer notifications & dispatch instructions</Typography>
|
|
</Box>
|
|
|
|
<Box className="delivery-prefs-row">
|
|
<Box className="delivery-prefs-field">
|
|
<label className="delivery-prefs-label" htmlFor="dispatch-notes-input">
|
|
<FileTextOutlined style={{ fontSize: 11, color: '#65387a' }} />
|
|
Special Dispatch Notes
|
|
</label>
|
|
<TextField
|
|
id="dispatch-notes-input"
|
|
size="small"
|
|
fullWidth
|
|
placeholder="Gate codes, call instructions, special cargo care…"
|
|
value={otherinstructions}
|
|
onChange={(e) => setOtherinstructions(e.target.value)}
|
|
sx={{
|
|
'& .MuiOutlinedInput-root': {
|
|
borderRadius: '10px',
|
|
padding: '0 10px',
|
|
alignItems: 'center',
|
|
fontSize: '12px',
|
|
background: '#ffffff',
|
|
height: '32px'
|
|
},
|
|
'& .MuiOutlinedInput-input': {
|
|
padding: '0 !important',
|
|
fontSize: '12px !important',
|
|
lineHeight: '32px'
|
|
}
|
|
}}
|
|
/>
|
|
</Box>
|
|
|
|
<Box
|
|
className={`sms-toggle-tile ${isSms === 1 ? 'is-active' : ''}`}
|
|
onClick={() => setIsSms(isSms === 1 ? 0 : 1)}
|
|
role="button"
|
|
tabIndex={0}
|
|
>
|
|
<Box className="sms-toggle-left">
|
|
<Box className="sms-toggle-icon">
|
|
<MessageOutlined style={{ fontSize: 13 }} />
|
|
</Box>
|
|
<Box sx={{ minWidth: 0 }}>
|
|
<Typography className="sms-toggle-title">SMS Updates</Typography>
|
|
<Typography className="sms-toggle-sub">Auto-notify customer on dispatch & delivery</Typography>
|
|
</Box>
|
|
</Box>
|
|
<Switch
|
|
size="small"
|
|
checked={isSms === 1}
|
|
onChange={(e) => {
|
|
e.stopPropagation();
|
|
setIsSms(e.target.checked ? 1 : 0);
|
|
}}
|
|
/>
|
|
</Box>
|
|
</Box>
|
|
</Card>
|
|
|
|
{/* Pricing breakdown card */}
|
|
<Card className="orders-card pricing-summary-card">
|
|
<Box className="pricing-header">
|
|
<Typography className="pricing-title">Pricing & Dispatch</Typography>
|
|
<Typography className="pricing-subtitle">Live cost estimate</Typography>
|
|
</Box>
|
|
|
|
<div className="price-metric-item">
|
|
<div className="price-metric-label">
|
|
<span className="price-metric-icon icon-distance">
|
|
<FaRoute />
|
|
</span>
|
|
<span>Delivery Distance</span>
|
|
</div>
|
|
<div className={`price-metric-value ${showDistance ? 'highlight' : ''}`}>
|
|
{showDistance ? `${distance} km` : '—'}
|
|
</div>
|
|
</div>
|
|
|
|
<div className="price-metric-item">
|
|
<div className="price-metric-label">
|
|
<span className="price-metric-icon icon-base">
|
|
<FaMoneyBillWave />
|
|
</span>
|
|
<span>
|
|
Base Fare
|
|
<span className="price-metric-sub"> · {minKm} km</span>
|
|
</span>
|
|
</div>
|
|
<div className="price-metric-value">
|
|
{basePrice ? `₹${basePrice.toFixed(2)}` : '₹0.00'}
|
|
</div>
|
|
</div>
|
|
|
|
<div className="price-metric-item">
|
|
<div className="price-metric-label">
|
|
<span className="price-metric-icon icon-rate">
|
|
<FaChartLine />
|
|
</span>
|
|
<span>Rate per km</span>
|
|
</div>
|
|
<div className="price-metric-value">
|
|
{pricePerKm ? `₹${pricePerKm.toFixed(2)}` : '₹0.00'}
|
|
<span className="price-metric-unit">/km</span>
|
|
</div>
|
|
</div>
|
|
|
|
{/* Total Cost Display */}
|
|
{showDistance && (
|
|
<div className="total-charge-badge">
|
|
<div className="total-charge-left">
|
|
<FaReceipt className="total-charge-icon" />
|
|
<div className="total-charge-label">Total Delivery Charge</div>
|
|
</div>
|
|
<div className="total-charge-val">₹{totalCharge.toFixed(2)}</div>
|
|
</div>
|
|
)}
|
|
|
|
{/* Submit button */}
|
|
<Box sx={{ mt: 1.5 }}>
|
|
<AnimateButton>
|
|
<Button
|
|
fullWidth
|
|
className="gradient-btn-create"
|
|
disabled={!showDistance || !selectedtime || !pickupSlot}
|
|
startIcon={!btnLoading && <FaPaperPlane style={{ fontSize: 11 }} />}
|
|
onClick={() => {
|
|
setLoading(true);
|
|
setBtnLoading(true);
|
|
createsubmitobj2();
|
|
setTimeout(() => {
|
|
setLoading(false);
|
|
setBtnLoading(false);
|
|
}, 2000);
|
|
}}
|
|
>
|
|
{btnLoading ? (
|
|
<CircularProgress color="inherit" size={16} thickness={5} />
|
|
) : (
|
|
'Dispatch Delivery Order'
|
|
)}
|
|
</Button>
|
|
</AnimateButton>
|
|
</Box>
|
|
</Card>
|
|
</Stack>
|
|
</Grid>
|
|
</Grid>
|
|
</Box>
|
|
|
|
{/* Saved address Dialog (Modal) */}
|
|
<Dialog
|
|
open={isCustomerOpen}
|
|
onClose={() => {
|
|
setIsCustomerOpen(false);
|
|
setSearchCustList('');
|
|
}}
|
|
fullWidth
|
|
fullScreen={isMobile}
|
|
sx={{
|
|
'& .MuiDialog-paper': {
|
|
borderRadius: { xs: 0, sm: '16px' },
|
|
overflow: 'hidden'
|
|
}
|
|
}}
|
|
>
|
|
<DialogTitle sx={{ background: 'linear-gradient(135deg, #662582 0%, #9255AB 100%)', color: 'white', py: 2.5 }}>
|
|
<Stack spacing={1.5}>
|
|
<Typography variant="h4" sx={{ fontWeight: 600, color: 'white' }}>
|
|
{`Select Saved Address (${pickordrop === 1 ? 'Pickup' : 'Drop'})`}
|
|
</Typography>
|
|
|
|
<FormControl sx={{ width: '100%' }}>
|
|
<OutlinedInput
|
|
autoFocus
|
|
fullWidth
|
|
id="input-search-header"
|
|
placeholder="Search by name, contact, or address..."
|
|
value={searchCustList}
|
|
onChange={(e) => setSearchCustList(e.target.value)}
|
|
sx={{
|
|
bgcolor: 'white',
|
|
borderRadius: '10px',
|
|
'& .MuiOutlinedInput-input': {
|
|
p: '10px 14px'
|
|
}
|
|
}}
|
|
startAdornment={
|
|
<InputAdornment position="start">
|
|
<SearchOutlined style={{ fontSize: 'small', color: '#64748b' }} />
|
|
</InputAdornment>
|
|
}
|
|
endAdornment={
|
|
<IconButton
|
|
sx={{ visibility: searchCustList ? 'visible' : 'hidden', p: 0.5 }}
|
|
onClick={() => {
|
|
setSearchCustList('');
|
|
}}
|
|
>
|
|
<ClearIcon style={{ fontSize: '18px' }} />
|
|
</IconButton>
|
|
}
|
|
autoComplete="off"
|
|
/>
|
|
</FormControl>
|
|
</Stack>
|
|
</DialogTitle>
|
|
|
|
<Divider />
|
|
|
|
<DialogContent sx={{ p: 3, maxHeight: '600px', overflowY: 'auto', bgcolor: '#fafbfc' }}>
|
|
{customerlist?.length == 0 ? (
|
|
<Stack spacing={2} direction={'row'} alignItems={'center'} justifyContent={'center'} sx={{ minHeight: 300 }}>
|
|
<Empty description="No saved addresses found for this client" />
|
|
</Stack>
|
|
) : (
|
|
<Box>
|
|
{customerlist &&
|
|
customerlist.map((address, index) => (
|
|
<Button
|
|
className="address-card-btn"
|
|
onClick={() => {
|
|
setIsCustomerOpen(false);
|
|
setSearchCustList('');
|
|
if (pickordrop === 1) {
|
|
console.log('PickupClient', address);
|
|
setAddId1(1);
|
|
setStartPoint({ latitude: address.latitude, longitude: address.longitude });
|
|
setPickCust(address);
|
|
setPickNum(address.contactno);
|
|
} else {
|
|
console.log('DropClient', address);
|
|
setAddId2(1);
|
|
setEndPoint({ latitude: address.latitude, longitude: address.longitude });
|
|
setDropCust(address);
|
|
setdropNum(address.contactno);
|
|
}
|
|
}}
|
|
disabled={pickCust?.customerid === address.customerid}
|
|
key={index}
|
|
>
|
|
<div style={{ width: '100%', display: 'flex', flexDirection: 'column' }}>
|
|
<Typography variant="subtitle1" sx={{ textAlign: 'left', fontWeight: 600, color: '#1e293b' }}>
|
|
{`${address.firstname} (${address.contactno})`}
|
|
</Typography>
|
|
<Typography variant="body2" sx={{ textAlign: 'left', color: '#64748b', mt: 0.5, lineHeight: 1.4 }}>
|
|
{address.address}
|
|
</Typography>
|
|
</div>
|
|
</Button>
|
|
))}
|
|
</Box>
|
|
)}
|
|
</DialogContent>
|
|
|
|
<Divider />
|
|
|
|
<DialogActions sx={{ p: 2.5, bgcolor: '#fafbfc' }}>
|
|
<Button
|
|
color="error"
|
|
variant="outlined"
|
|
sx={{
|
|
borderRadius: '8px',
|
|
textTransform: 'none',
|
|
px: 3,
|
|
'&:hover': {
|
|
bgcolor: '#ef4444',
|
|
color: 'white',
|
|
borderColor: '#ef4444'
|
|
}
|
|
}}
|
|
onClick={() => {
|
|
setIsCustomerOpen(false);
|
|
setSearchCustList('');
|
|
}}
|
|
>
|
|
Cancel
|
|
</Button>
|
|
</DialogActions>
|
|
</Dialog>
|
|
|
|
{/* Location error Dialog */}
|
|
<Dialog
|
|
open={open}
|
|
onClose={() => {
|
|
setOpen(false);
|
|
}}
|
|
fullWidth
|
|
sx={{
|
|
'& .MuiDialog-paper': {
|
|
borderRadius: { xs: 3, sm: '16px' },
|
|
p: 1.5,
|
|
m: { xs: 1.5, sm: 4 },
|
|
width: { xs: 'calc(100% - 24px)', sm: 'auto' },
|
|
maxWidth: '400px'
|
|
}
|
|
}}
|
|
>
|
|
<DialogTitle sx={{ textAlign: 'center', pb: 1 }}>
|
|
<HighlightOffIcon sx={{ fontSize: 70, color: theme.palette.error.main, mb: 1 }} />
|
|
<Typography variant="h3" sx={{ color: theme.palette.error.main, fontWeight: 700 }}>
|
|
Dispatch Blocked
|
|
</Typography>
|
|
</DialogTitle>
|
|
|
|
<DialogContent sx={{ textAlign: 'center', pb: 2 }}>
|
|
<Typography variant="body1" sx={{ color: '#64748b', lineHeight: 1.5 }}>
|
|
Our delivery partners cannot service this coordinate combination. The route distance exceeds the active operating radius for this app location.
|
|
</Typography>
|
|
</DialogContent>
|
|
|
|
<DialogActions
|
|
sx={{
|
|
bgcolor: theme.palette.error.main,
|
|
borderRadius: '12px',
|
|
display: 'flex',
|
|
alignItems: 'center',
|
|
justifyContent: 'center',
|
|
fontSize: '16px',
|
|
fontWeight: 600,
|
|
color: 'white',
|
|
cursor: 'pointer',
|
|
py: 1.5,
|
|
mx: 2.5,
|
|
mb: 2,
|
|
transition: 'background-color 0.2s ease',
|
|
'&:hover': {
|
|
bgcolor: theme.palette.error.dark
|
|
}
|
|
}}
|
|
onClick={() => {
|
|
setOpen(false);
|
|
}}
|
|
>
|
|
Acknowledge & Close
|
|
</DialogActions>
|
|
</Dialog>
|
|
</>
|
|
);
|
|
};
|
|
|
|
export default Createorder1;
|