diff --git a/src/pages/nearle/dispatch/Preview.js b/src/pages/nearle/dispatch/Preview.js
index ce01673..6681a90 100644
--- a/src/pages/nearle/dispatch/Preview.js
+++ b/src/pages/nearle/dispatch/Preview.js
@@ -297,7 +297,7 @@ const Preview = () => {
// so a later reload / back-forward also bounces instead of re-using it.
useEffect(() => {
if (!stateData.dispatchPreviewData) {
- navigate('/nearle/orders', { replace: true });
+ navigate('/doormile/orders', { replace: true });
return;
}
if (typeof window !== 'undefined' && window.history?.state) {
@@ -414,7 +414,7 @@ const Preview = () => {
OpenToast('Delivery Created Successfully', 'success', 2000);
setIsLoading(false);
if (rider?.userfcmtoken) notifyRiderMutation.mutate(rider.userfcmtoken);
- navigate('/nearle/deliveries');
+ navigate('/doormile/deliveries');
},
onError: (error) => {
OpenToast(error.message, 'error', 4000);
@@ -566,7 +566,7 @@ const Preview = () => {
navigate('/nearle/orders')}
+ onClick={() => navigate('/doormile/orders')}
sx={{ bgcolor: 'action.hover', '&:hover': { bgcolor: 'action.selected' } }}
>
diff --git a/src/pages/nearle/invoice/invoice.js b/src/pages/nearle/invoice/invoice.js
deleted file mode 100644
index fce8cd0..0000000
--- a/src/pages/nearle/invoice/invoice.js
+++ /dev/null
@@ -1,859 +0,0 @@
-import React, { useState, useMemo } from 'react';
-import { Outlet, useNavigate } from 'react-router-dom';
-import { useQuery } from '@tanstack/react-query';
-import dayjs from 'dayjs';
-var utc = require('dayjs/plugin/utc');
-dayjs.extend(utc);
-
-import {
- Avatar,
- Box,
- Divider,
- Grid,
- IconButton,
- Paper,
- Stack,
- Table,
- TableBody,
- TableCell,
- TableContainer,
- TableHead,
- TablePagination,
- TableRow,
- Tooltip,
- Typography,
- useMediaQuery
-} from '@mui/material';
-import { useTheme } from '@mui/material/styles';
-import {
- MdReceiptLong,
- MdDashboard,
- MdHourglassEmpty,
- MdReportProblem,
- MdCheckCircle,
- MdGroups,
- MdEventNote,
- MdCurrencyRupee,
- MdVisibility,
- MdInventory2,
- MdOutlinePendingActions,
- MdOutlineCheckCircle
-} from 'react-icons/md';
-
-import { fetchinvoiceinsight, fetchdeliverylist } from 'pages/api/api';
-import Loader from 'components/Loader';
-import DebounceSearchBar from 'components/nearle_components/DebounceSearchBar';
-import PageHeader from 'components/nearle_components/PageHeader';
-import StatCard from 'components/nearle_components/StatCard';
-import { OrdersTableSkeleton } from '../orders/OrdersTableSkeleton';
-import { MobileCard, MobileCardList, MobileField, MobileFieldGrid } from 'components/nearle_components/MobileCard';
-
-// ============================================================================
-// Design tokens — shared with deliveries / tenants / customers / pricing /
-// orders-details / riders-summary pages.
-// ============================================================================
-const DT = {
- radiusPill: 999,
- radiusCard: 14,
- shadowSoft: '0 1px 2px rgba(15, 23, 42, 0.04), 0 8px 24px rgba(15, 23, 42, 0.05)',
- shadowMd: '0 1px 3px rgba(15, 23, 42, 0.06)',
- shadowPop: '0 12px 32px rgba(15, 23, 42, 0.12)',
- textPrimary: '#0f172a',
- textSecondary: '#64748b',
- textMuted: '#94a3b8',
- borderSubtle: '#e2e8f0',
- divider: '#f1f5f9',
- surface: '#ffffff',
- surfaceAlt: '#f8fafc'
-};
-const a = (c, suffix) => `${c}${suffix}`;
-const tint = (c) => a(c, '08');
-const soft = (c) => a(c, '18');
-const ring = (c) => a(c, '26');
-const edge = (c) => a(c, '55');
-
-const BRAND = '#662582';
-
-const AccentAvatar = ({ color, selected, size = 24, children }) => (
-
- {children}
-
-);
-
-// Bill status → tab visual meta (semantic colours; brand purple reserved for "All").
-const STATUS_META = {
- 0: { key: 'all', label: 'All', color: BRAND, icon: MdDashboard, countKey: 'totalcount' },
- 1: { key: 'open', label: 'Open', color: '#ef4444', icon: MdHourglassEmpty, countKey: 'pendingcount' },
- 2: { key: 'overdue', label: 'Overdue', color: '#f59e0b', icon: MdReportProblem, countKey: 'overduecount' },
- 3: { key: 'paid', label: 'Paid', color: '#10b981', icon: MdCheckCircle, countKey: 'paidcount' }
-};
-const STATUS_TABS = [0, 1, 2, 3];
-
-function formatNumberToRupees(value) {
- return new Intl.NumberFormat('en-IN', {
- style: 'currency',
- currency: 'INR',
- minimumFractionDigits: 2
- }).format(Number(value) || 0);
-}
-
-const Invoice = () => {
- const navigate = useNavigate();
- const theme = useTheme();
- const isMobile = useMediaQuery(theme.breakpoints.down('md'));
- const [page, setPage] = useState(0);
- const [rowsPerPage, setRowsPerPage] = useState(10);
- const [billStatus, setBillStatus] = useState(0);
- const [isloader, setIsLoader] = useState(false);
- const [searchword, setSearchword] = useState('');
- const [debouncedSearch, setDebouncedSearch] = useState('');
-
- const handleDebouncedSearch = React.useCallback((val) => {
- setDebouncedSearch(val);
- setPage(0);
- }, []);
-
- // ============================================= || fetchinvoiceinsight ||
- const {
- data: insightdata,
- isLoading: isInsightLoading,
- isError: isInsightError,
- error: insightError
- } = useQuery({
- queryKey: ['invoiceInsight'],
- queryFn: fetchinvoiceinsight,
- refetchInterval: 300000
- });
-
- // ============================================= || fetchdeliverylist ||
- // NOTE: queryKey shape MUST stay `[billStatus]` — `fetchdeliverylist`
- // destructures `const [billStatus] = queryKey`.
- const {
- data: deliveryList,
- isLoading: isDeliveryLoading,
- isError: isDeliveryError,
- error: deliveryError
- } = useQuery({
- queryKey: [billStatus],
- queryFn: fetchdeliverylist,
- refetchInterval: 300000
- });
-
- const isLoading = isInsightLoading || isDeliveryLoading;
- const isError = isInsightError || isDeliveryError;
- const errorMessage = insightError?.message || deliveryError?.message;
-
- // Client-side filter across tenant name, contact person, invoice number.
- const filteredList = useMemo(() => {
- if (!deliveryList) return [];
- if (!debouncedSearch) return deliveryList;
- const q = debouncedSearch.toLowerCase().trim();
- return deliveryList.filter((row) =>
- [row.tenantname, row.contactperson, String(row.invoiceno)]
- .filter(Boolean)
- .some((field) => String(field).toLowerCase().includes(q))
- );
- }, [deliveryList, debouncedSearch]);
-
- const activePage = useMemo(() => {
- const maxPage = Math.max(0, Math.ceil(filteredList.length / rowsPerPage) - 1);
- return Math.min(page, maxPage);
- }, [filteredList.length, page, rowsPerPage]);
-
- // Keep page state in sync when filters or data updates shrink the list below current page
- React.useEffect(() => {
- if (page !== activePage) {
- setPage(activePage);
- }
- }, [page, activePage]);
-
- const pagedList = useMemo(
- () => filteredList.slice(activePage * rowsPerPage, activePage * rowsPerPage + rowsPerPage),
- [filteredList, activePage, rowsPerPage]
- );
-
- const grandTotal = useMemo(
- () => filteredList.reduce((sum, r) => sum + (Number(r.totalamount) || 0), 0),
- [filteredList]
- );
-
- const pageTotal = useMemo(
- () => pagedList.reduce((sum, r) => sum + (Number(r.totalamount) || 0), 0),
- [pagedList]
- );
-
- const handleChangePage = (event, newPage) => setPage(newPage);
- const handleChangeRowsPerPage = (event) => {
- setRowsPerPage(+event?.target?.value);
- setPage(0);
- };
-
- if (isError) {
- return errorMessage;
- }
-
- const KPI_META = [
- { idx: 0, label: 'All Invoices', color: BRAND, icon: MdDashboard, value: insightdata?.totalcount ?? 0 },
- { idx: 1, label: 'Open', color: '#ef4444', icon: MdOutlinePendingActions, value: insightdata?.pendingcount ?? 0 },
- { idx: 2, label: 'Overdue', color: '#f59e0b', icon: MdReportProblem, value: insightdata?.overduecount ?? 0 },
- { idx: 3, label: 'Paid', color: '#10b981', icon: MdOutlineCheckCircle, value: insightdata?.paidcount ?? 0 }
- ];
-
- const activeMeta = STATUS_META[billStatus];
-
- return (
- <>
- {(isloader || isLoading) && }
-
- {/* ============================================= || Header || ============================================= */}
-
-
-
- Grand Total
-
-
- {formatNumberToRupees(grandTotal)}
-
-
- }
- />
-
- {/* ============================================= || KPI Cards (clickable filter) || ============================================= */}
-
- {KPI_META.map((item) => {
- const Icon = item.icon;
- return (
-
- {
- setBillStatus(item.idx);
- setPage(0);
- }}
- sx={{ cursor: 'pointer', height: '100%' }}
- >
- }
- color={item.color}
- loading={isInsightLoading}
- />
-
-
- );
- })}
-
-
- {/* ============================================= || Status Tabs + Search || ============================================= */}
-
-
-
- {STATUS_TABS.map((idx) => {
- const meta = STATUS_META[idx];
- const Icon = meta.icon;
- const active = billStatus === idx;
- const count = insightdata?.[meta.countKey] ?? 0;
- return (
- {
- setBillStatus(idx);
- setPage(0);
- }}
- sx={{
- display: 'inline-flex',
- alignItems: 'center',
- gap: { xs: 0.625, md: 0.875 },
- pl: 0.5,
- pr: { xs: 1, md: 1.25 },
- py: 0.5,
- flexShrink: 0,
- cursor: 'pointer',
- borderRadius: 999,
- border: `1px solid ${active ? meta.color : DT.borderSubtle}`,
- bgcolor: active ? meta.color : DT.surface,
- color: active ? '#fff' : DT.textSecondary,
- fontWeight: 600,
- boxShadow: 'none',
- transition: 'background-color 0.15s, border-color 0.15s, color 0.15s',
- '&:hover': {
- borderColor: active ? meta.color : '#cbd5e1',
- bgcolor: active ? meta.color : DT.surfaceAlt
- }
- }}
- >
-
-
-
-
- {meta.label}
-
-
- {count}
-
-
- );
- })}
-
-
-
-
-
-
-
-
- {/* ============================================= || Table || ============================================= */}
-
- {isMobile ? (
- <>
- {isDeliveryLoading ? (
-
-
-
- ) : pagedList.length === 0 ? (
-
-
-
-
-
- No invoices to show
-
-
- {searchword
- ? 'Try a different keyword.'
- : `No ${activeMeta.label.toLowerCase()} invoices for this filter.`}
-
-
- ) : (
-
- {pagedList.map((item, index) => {
- const overdue =
- billStatus === 2 ||
- (item.duedate && dayjs(item.duedate).isBefore(dayjs(), 'day') && billStatus !== 3);
- return (
-
-
-
-
-
-
-
- {item.tenantname || '—'}
-
- {item.contactperson && (
-
- {item.contactperson}
-
- )}
-
-
-
- {
- setIsLoader(true);
- setTimeout(() => {
- setIsLoader(false);
- navigate('/nearle/invoice/preview', { state: item });
- }, 500);
- }}
- sx={{
- flexShrink: 0,
- bgcolor: soft(BRAND),
- color: BRAND,
- border: `1px solid ${edge(BRAND)}`,
- '&:hover': { bgcolor: BRAND, color: '#fff' }
- }}
- >
-
-
-
-
- }
- >
-
-
-
- {item.invoiceno || '—'}
-
-
-
-
-
- {formatNumberToRupees(item.totalamount).replace('₹', '').trim()}
-
-
-
-
-
-
- {item.transactiondate ? dayjs(item.transactiondate).format('DD/MM/YYYY') : '—'}
-
-
-
-
-
-
-
- {item.duedate ? dayjs(item.duedate).format('DD/MM/YYYY') : '—'}
-
-
-
-
-
- {item.itemcount ?? 0}
-
-
-
-
- );
- })}
-
- )}
- >
- ) : (
-
-
-
-
- #
- Client
- Invoice ID
- Invoice Date
- Due Date
- Items
- Amount
- Action
-
-
-
-
- {isDeliveryLoading && }
- {!isDeliveryLoading && pagedList.length === 0 ? (
-
-
-
-
-
-
-
- No invoices to show
-
-
- {searchword
- ? 'Try a different keyword.'
- : `No ${activeMeta.label.toLowerCase()} invoices for this filter.`}
-
-
-
-
- ) : (
- pagedList.map((item, index) => {
- const overdue = billStatus === 2 || (item.duedate && dayjs(item.duedate).isBefore(dayjs(), 'day') && billStatus !== 3);
- return (
-
-
-
- {String(activePage * rowsPerPage + index + 1).padStart(2, '0')}
-
-
-
-
-
-
-
-
-
-
- {item.tenantname || '—'}
-
- {item.contactperson && (
-
- {item.contactperson}
-
- )}
-
-
-
-
-
-
- {item.invoiceno || '—'}
-
-
-
-
-
-
-
-
- {item.transactiondate ? dayjs(item.transactiondate).format('DD/MM/YYYY') : '—'}
-
-
-
- {item.transactiondate ? dayjs(item.transactiondate).utc().format('hh:mm A') : ''}
-
-
-
-
-
-
-
-
-
- {item.duedate ? dayjs(item.duedate).format('DD/MM/YYYY') : '—'}
-
-
-
- {item.duedate ? dayjs(item.duedate).utc().format('hh:mm A') : ''}
-
-
-
-
-
-
- {item.itemcount ?? 0}
-
-
-
-
-
-
- {formatNumberToRupees(item.totalamount).replace('₹', '').trim()}
-
-
-
-
-
- {
- setIsLoader(true);
- setTimeout(() => {
- setIsLoader(false);
- navigate('/nearle/invoice/preview', { state: item });
- }, 500);
- }}
- sx={{
- bgcolor: soft(BRAND),
- color: BRAND,
- border: `1px solid ${edge(BRAND)}`,
- '&:hover': { bgcolor: BRAND, color: '#fff' }
- }}
- >
-
-
-
-
-
- );
- })
- )}
-
-
-
- )}
-
-
-
-
- Page total · {formatNumberToRupees(pageTotal)}
-
-
-
-
-
-
- >
- );
-};
-
-export default Invoice;
diff --git a/src/pages/nearle/invoice/invoicePreview.js b/src/pages/nearle/invoice/invoicePreview.js
deleted file mode 100644
index 84de501..0000000
--- a/src/pages/nearle/invoice/invoicePreview.js
+++ /dev/null
@@ -1,486 +0,0 @@
-import React, { useRef, useState, useEffect } from 'react';
-import { useLocation } from 'react-router-dom';
-import { useTheme } from '@mui/material/styles';
-import useMediaQuery from '@mui/material/useMediaQuery';
-// import nearleLogo from '../../../assets/images/nearleLogo.png';
-import logo_nearle1 from '../../../assets/images/logo-nearle1.png';
-import axios from 'axios';
-import dayjs from 'dayjs';
-import Loader from 'components/Loader';
-import { enqueueSnackbar } from 'notistack';
-import { DownloadOutlined, PrinterFilled } from '@ant-design/icons';
-import ReactToPrint, { useReactToPrint } from 'react-to-print';
-import { SearchOutlined, LeftOutlined, RightOutlined } from '@ant-design/icons';
-import ArrowBackIcon from '@mui/icons-material/ArrowBack';
-// import jsPDF from 'jspdf';
-import { useNavigate } from 'react-router-dom';
-import { FaArrowLeft } from 'react-icons/fa6';
-import { FaIndianRupeeSign } from 'react-icons/fa6';
-
-// import autoTable from 'jspdf-autotable';
-import {
- Grid,
- Button,
- Divider,
- Table,
- TableBody,
- TableCell,
- TableContainer,
- TableHead,
- TablePagination,
- TableRow,
- Tabs,
- Tab,
- Typography,
- Box,
- OutlinedInput,
- InputAdornment,
- IconButton,
- TextField,
- Tooltip,
- Dialog,
- DialogTitle,
- DialogContent,
- DialogActions,
- Stack,
- Chip
-} from '@mui/material';
-
-const InvoicePreview = () => {
- const [selected, setselected] = useState({});
- const location = useLocation();
- const navigate = useNavigate();
- console.log('previewSelect', location.state);
- const componentRef = useRef(null);
- const [tabletype, settabletype] = useState(true);
- const [paydialog, setpaydialog] = useState(false);
- const [refnumber, setRefnumber] = useState('');
- const [remarks, setRemarks] = useState('');
- const theme = useTheme();
- const isMobile = useMediaQuery(theme.breakpoints.down('md'));
- useEffect(() => {
- setselected(location.state);
- }, []);
-
- // ================================================= || formatNumberToRupees || =================================================
-
- function formatNumberToRupees(value) {
- return new Intl.NumberFormat('en-IN', {
- style: 'currency',
- currency: 'INR',
- minimumFractionDigits: 2
- }).format(value);
- }
-
- // ================================================= || updatePayment || =================================================
-
- const updatePayment = async () => {
- try {
- const updateResponse = await axios.put(`${process.env.REACT_APP_URL}/invoice/updatestatus`, {
- salesid: selected.salesid,
- referenceno: refnumber,
- referencedate: dayjs().format('YYYY-MM-DD HH:mm:ss'),
- billstatus: 2,
- paymentremarks: remarks
- });
- if (updateResponse.status) {
- enqueueSnackbar(' Updated Successfully ', {
- variant: 'success',
- anchorOrigin: { vertical: 'top', horizontal: 'right' },
- autoHideDuration: 1000
- });
- }
- console.log('updateResponse', updateResponse);
- } catch (error) {
- console.log('updateResponse', error);
- }
- };
-
- return (
- <>
-
-
-
- {
- navigate('/nearle/invoice');
- }}
- >
-
-
-
-
-
-
- Invoice Details
-
-
-
-
-
-
- {
- setpaydialog(true);
- }}
- >
- {' '}
-
- Update Payment
-
- (
- }
- variant="outlined"
- color="primary"
- fullWidth={isMobile}
- sx={{
- '&:hover': {
- backgroundColor: 'primary.main',
- color: 'primary.contrastText'
- }
- }}
- >
- Print
-
- )}
- content={() => componentRef.current}
- />
-
-
-
- {/* minWidth keeps the invoice at a legible fixed layout on phones —
- the parent's overflowX:auto then lets it scroll horizontally
- instead of squishing the header into vertical slivers. 720px sits
- within the print page width, so printing is unaffected. */}
-
-
-
-
-
-
- {' '}
-
- {/*
- {`Invoice No: ${"\u00a0\u00a0\u00a0"}${selected.invoiceno}`}
- */}
-
-
- Invoice No :
-
- {`${'\u00a0\u00a0'}${selected.invoiceno}`}
-
-
-
-
-
- Date :{' '}
-
-
- {dayjs(selected.transactiondate).format('DD-MM-YYYY')}
-
-
-
-
- Due Date :
-
- {dayjs(selected.dueDate).format('DD-MM-YYYY')}
-
- {/*
-
- Invoice No :
-
-
- {`${"\u00a0\u00a0\u00a0"}${selected.invoiceno}`}
-
- */}
-
-
-
-
-
-
-
-
-
- From:
-
- Nearle Technology Privite Limited.
-
- 424, 4th floor,
-
- Red rose towers,
- DB Road, RS Puram,
- 641002.
- care@nearle.in
- 9047968666
-
-
-
-
-
-
-
-
-
-
-
- To:
-
- {selected.tenantname}
- {selected.address}
- {selected.suburb}
- {selected.city}
- {selected.state} {' '}
-
-
-
-
-
-
-
-
-
-
-
-
-
- S.No
- Particulars
- Unit
- Quantity
- Rate
- {/* {selected && selected.pricingtypeid === 73 && ( */}
- Other Charges
- {/* )} */}
- Amount
-
-
- {selected.tenantsalesdetails && (
-
-
- 1
-
-
- {`Invoice from ${dayjs(selected.tenantsalesdetails[0].fromdate).format('DD-MM-YYYY')} to ${dayjs(
- selected.tenantsalesdetails[0].todate
- ).format('DD-MM-YYYY')}`}
-
-
-
- {selected.tenantsalesdetails[0].pricingtype}
-
-
-
- {`${selected.tenantsalesdetails[0].quantity.toFixed(2)} km`}
-
-
- {`₹ ${selected.tenantsalesdetails[0].baserate.toFixed(2)}`}
-
- {/* {selected.tenantsalesdetails[0].pricingtypeid == 73 && ( */}
-
- {`₹ ${selected.tenantsalesdetails[0].othercharges}.00`}
-
- {/* )} */}
-
- {`₹ ${selected.tenantsalesdetails[0].amount}.00`}
-
-
-
- )}
-
-
-
-
-
-
-
-
- Sub Total:
- {formatNumberToRupees(selected.salesamount)}
-
-
- Discount:
-
- - {formatNumberToRupees(selected.discountamt)}
-
-
-
- Tax:
-
- + {formatNumberToRupees(selected.taxamount)}
-
-
-
-
- Grand Total:
-
- {formatNumberToRupees(Math.round(selected.totalamount))}
-
-
-
-
-
-
-
-
- Notes: {selected.remarks}
-
-
-
-
- {/* ================================================= || updatePayment Dialog || ================================================= */}
-
{
- setpaydialog(false);
- }}
- maxWidth={'sm'}
- fullWidth
- >
-
-
-
- ₹
-
-
- Update Payment
-
-
-
-
-
- Reference No
- {
- setRefnumber(e.target.value);
- }}
- />
-
-
- Remarks
- {
- setRemarks(e.target.value);
- }}
- />
-
-
-
- {
- setpaydialog(false);
- }}
- >
- Cancel
-
- {
- setpaydialog(false);
- updatePayment();
- navigate('/nearle/invoice');
- }}
- >
- Update
-
-
-
- >
- );
-};
-
-export default InvoicePreview;
diff --git a/src/pages/nearle/login.js b/src/pages/nearle/login.js
index 03fb252..fe27c32 100644
--- a/src/pages/nearle/login.js
+++ b/src/pages/nearle/login.js
@@ -1,45 +1,90 @@
import { useState, useEffect } from 'react';
-import { enqueueSnackbar, closeSnackbar } from 'notistack';
-import AnimateButton from 'components/@extended/AnimateButton';
-import OtpInput from 'react18-input-otp';
-
-import { Box, Card, CardContent, Stack, TextField, Button, Typography, Link, FormLabel, IconButton, InputAdornment } from '@mui/material';
-import { useTheme } from '@mui/material/styles';
+import { enqueueSnackbar } from 'notistack';
import axios from 'axios';
import { useNavigate } from 'react-router-dom';
import Loader from 'components/Loader';
-import logo from 'assets/images/logo-nearle1.png';
-import expressImage from 'assets/images/express.png';
+import logo from 'assets/images/doormile-logo.png';
+
import { useSelector, useDispatch } from 'react-redux';
import { OpenToast } from 'components/third-party/OpenToast';
import { closeGlobalToast, GlobalToast } from 'components/nearle_components/GlobalToast';
-import Visibility from '@mui/icons-material/Visibility';
-import VisibilityOff from '@mui/icons-material/VisibilityOff';
import { setLoginUser } from 'store/reducers/loginUserSlice';
import { markSessionStart } from 'utils/session';
+import { DT } from 'themes/dt/tokens';
+
+// Astryx design system — see themes/astryx.js for the Doormile brand theme
+// and CLAUDE.md's block for the CLI workflow.
+// NOTE: custom CSS (xstyle/stylex.create()) isn't wired up yet — see the
+// comment in config-overrides.js. Everything below uses Astryx component
+// props only; the brand gradient panel and the two logo images are plain
+// native elements with inline `style` for that reason.
+import { AppShell } from '@astryxdesign/core/AppShell';
+import { Theme } from '@astryxdesign/core/theme';
+import { HStack } from '@astryxdesign/core/HStack';
+import { VStack } from '@astryxdesign/core/VStack';
+import { Center } from '@astryxdesign/core/Center';
+import { Card } from '@astryxdesign/core/Card';
+import { Heading } from '@astryxdesign/core/Heading';
+import { Text } from '@astryxdesign/core/Text';
+import { TextInput } from '@astryxdesign/core/TextInput';
+import { Button } from '@astryxdesign/core/Button';
+import { Link } from '@astryxdesign/core/Link';
+import { doormileTheme } from 'themes/astryx';
+
+const brandPanelStyle = {
+ display: 'flex',
+ flexDirection: 'column',
+ justifyContent: 'center',
+ position: 'relative',
+ overflow: 'hidden',
+ width: '46%',
+ height: '100vh',
+ color: '#fff',
+ padding: 48,
+ background: `linear-gradient(150deg, ${DT.brand} 0%, #D25463 100%)`
+};
+
+const logoLockupStyle = { position: 'absolute', top: 48, left: 48, maxHeight: 60 };
+
+const bulletDotStyle = {
+ width: 22,
+ height: 22,
+ borderRadius: '50%',
+ backgroundColor: 'rgba(255, 255, 255, 0.18)',
+ display: 'inline-flex',
+ alignItems: 'center',
+ justifyContent: 'center',
+ fontSize: 13,
+ fontWeight: 700,
+ flexShrink: 0
+};
+
+// doormile-logo.png is a white asset; recolour to brand red for this
+// white-background card (the brand-panel logo stays white as-is).
+const formLogoStyle = {
+ maxHeight: 48,
+ filter: 'brightness(0) saturate(100%) invert(15%) sepia(93%) saturate(5437%) hue-rotate(346deg) brightness(81%) contrast(92%)'
+};
+
+const BULLETS = ['Real-time fleet visibility', 'AI-optimised dispatch routes', 'Tenant, pricing & invoice control'];
const Login = () => {
const dispatch = useDispatch();
const fcmtoken = useSelector((state) => state.fcm);
- const permission = useSelector((state) => state.fcm.permission);
- const theme = useTheme();
const [loading, setLoading] = useState(false);
let navigate = useNavigate();
const [otp, setOtp] = useState('');
- const [currentotp, setCurrentotp] = useState('');
const [userinfo, setUserinfo] = useState({});
const [username, setUsername] = useState('');
const [passwordStatus, setPasswordStatus] = useState(0);
const [password, setPassword] = useState('');
const [confirmPassword, setConfirmPassword] = useState('');
const [isPassword, setIspassword] = useState(false);
- const [showPassword, setShowPassword] = useState(false);
- const [showConfirmPassword, setShowConfirmPassword] = useState(false);
const [userid, setUserid] = useState(0);
useEffect(() => {
if (localStorage.getItem('firstname')) {
- navigate('/nearle/dispatch');
+ navigate('/doormile/dispatch');
}
}, []);
@@ -100,7 +145,7 @@ const Login = () => {
localStorage.setItem('userfcmtoken', userinfo.userfcmtoken);
markSessionStart();
fetchAppLocations(userinfo.userid);
- navigate('/nearle/dispatch');
+ navigate('/doormile/dispatch');
} else {
OpenToast(res.data.message, 'error', 3000);
}
@@ -123,7 +168,7 @@ const Login = () => {
markSessionStart();
closeGlobalToast(); // to close the pin snackbar
- navigate('/nearle/dispatch');
+ navigate('/doormile/dispatch');
};
const opentoast = (message) => {
@@ -152,320 +197,157 @@ const Login = () => {
}
};
+ const handleSubmit = (e) => {
+ e.preventDefault();
+ if (passwordStatus == 0) {
+ loginsend();
+ } else if (passwordStatus == 1) {
+ if (!password || !confirmPassword || password != confirmPassword) {
+ OpenToast('Check Password', 'warning', 3000);
+ } else {
+ updateUser();
+ }
+ } else if (passwordStatus == 2) {
+ if (!password) {
+ OpenToast('Invalid Password', 'warning', 3000);
+ }
+ loginsend();
+ }
+ };
+
return (
-
- {loading && }
+
+
+ {loading && }
+
+ {/* ---- Left brand panel (plain element: see the note at the top of
+ this file about custom styling not going through Astryx yet) ---- */}
+
+
- {/* ---- Left brand panel (hidden on small screens) ---- */}
-
- {/* Logo at the top-left corner */}
-
+
+
+ Operate your dispatch, end to end.
+
+
+ Orders, AI route optimisation, live rider tracking and billing — all in the Doormile Express operator console.
+
- {/* decorative light glows */}
-
-
+
+ {BULLETS.map((t) => (
+
+ ✓
+ {t}
+
+ ))}
+
+
+
-
-
- Operate your dispatch,
-
- end to end.
-
-
- Orders, AI route optimisation, live rider tracking and billing — all in the NearlExpress operator console.
-
+ {/* ---- Right form panel ---- */}
+
+
+
+
+
+ Welcome back
+ Sign in to the Doormile Express console
+
-
- {['Real-time fleet visibility', 'AI-optimised dispatch routes', 'Tenant, pricing & invoice control'].map((t) => (
-
-
- ✓
-
- {t}
-
- ))}
-
-
-
-
- {/* ---- Right form panel ---- */}
-
-
-
- {/* Logo */}
-
-
-
-
- {/* Title */}
-
- Welcome back
-
-
- Sign in to the NearlExpress console
-
-
-
-
-
-
+ {/* OTP / retry */}
+ {isPassword && (
+
+
+ Enter Password
+ {
+ setOtp('');
+ loginsend();
+ }}
+ >
+ Retry
+
+
+ setPassword(value)} isLabelHidden />
+
+ )}
- {/* footer */}
-
-
- © All rights reserved
-
-
- Terms and Conditions
-
-
- Privacy Policy
-
-
-
-
-
+
+
+
+
+
+ {/* footer */}
+
+
+ © All rights reserved
+
+
+ Terms and Conditions
+
+
+ Privacy Policy
+
+
+
+
+
+
+
);
};
diff --git a/src/pages/nearle/login1.js b/src/pages/nearle/login1.js
index ab23a9f..1d1715b 100644
--- a/src/pages/nearle/login1.js
+++ b/src/pages/nearle/login1.js
@@ -22,7 +22,11 @@ import { useTheme } from '@mui/material/styles';
import useMediaQuery from '@mui/material/useMediaQuery';
import AnimateButton from 'components/@extended/AnimateButton';
-import logo from 'assets/images/logo-nearle1.png';
+import logo from 'assets/images/doormile-logo.png';
+
+// doormile-logo.png is a white asset; recolour it to brand red for this page's light background.
+const DOORMILE_RED_FILTER =
+ 'brightness(0) saturate(100%) invert(15%) sepia(93%) saturate(5437%) hue-rotate(346deg) brightness(81%) contrast(92%)';
import axios from 'axios';
import { useNavigate } from 'react-router-dom';
@@ -228,7 +232,7 @@ const Login = () => {
// sx={{ ml: 3, mt: 3 }}
sx={{ ml: { xs: 0, md: 3 }, mt: { xs: 3, md: 1 }, textAlign: { xs: 'center', md: 'left' } }}
>
-
+
{
const {
data: paymentModes = [],
- isLoading: paymentModesLoading,
- isError: paymentModesError,
- error: paymentModesErrorMessage
+ isLoading: paymentModesLoading
} = useQuery({
queryKey: ['paymentmodes'],
queryFn: fetchPaymentType
@@ -246,10 +245,7 @@ const OrdersPreview = () => {
const {
data: ridersList = [],
- isLoading: ridersListLoading,
- isError: ridersListError,
- error: ridersListErrorMessage,
- refetch: ridersListRefetch
+ isLoading: ridersListLoading
} = useQuery({
queryKey: ['ridersList', appId], // Unique key for caching & re-fetching
queryFn: fetchRidersList,
@@ -282,13 +278,13 @@ const OrdersPreview = () => {
onSuccess: (data, variables) => {
console.log('data', data);
console.log('varialbles', variables);
- notifyRiderMutation.mutate(rider.userfcmtoken || riderToken); // Call notifyRider after success
+ notifyRiderMutation.mutate(rider?.userfcmtoken || riderToken); // Call notifyRider after success
if (data.status == 'accepted') {
OpenToast('Delivery Created Successfully', 'success', 2000);
}
setTimeout(() => {
setIsLoading(false);
- navigate('/nearle/deliveries');
+ navigate('/nearle/orders');
}, 2000);
},
onError: (error) => {
@@ -581,11 +577,6 @@ const OrdersPreview = () => {
{index + 1}
- {/* {aiMode == 1 && (
-
-
-
- )} */}
@@ -656,12 +647,6 @@ const OrdersPreview = () => {
{val.ordernotes}
- {/* {aiMode == 1 && (
-
- {val.username}
- ID : {val.userid}
-
- )} */}
{
disabled={aiMode === 0 && (!rider || !payment)}
onClick={handleManualCreateDelivery}
>
- Assign Orders
+ Finalise
diff --git a/src/pages/nearle/orders/OrdersRedesign.css b/src/pages/nearle/orders/OrdersRedesign.css
index 950f7af..cc2c39c 100644
--- a/src/pages/nearle/orders/OrdersRedesign.css
+++ b/src/pages/nearle/orders/OrdersRedesign.css
@@ -1,554 +1,50 @@
-/* OrdersRedesign.css - Premium Aesthetics & Micro-Animations */
+/* OrdersRedesign.css — premium aesthetics + micro-animations
+ Ported from xpressconsole; trimmed to only the classes the
+ redesigned multipleOrders.js (and its peers) consume here. */
-/* ============================================== */
-/* Pickup / Drop Location Panel (Redesign) */
-/* ============================================== */
-.location-panel {
- position: relative;
- padding: 12px 14px;
- border-radius: 12px;
- border: 1px solid #eef2f6;
- background: linear-gradient(180deg, #ffffff 0%, #fbfcff 100%);
- transition: box-shadow 0.3s ease, transform 0.3s ease;
- height: 100%;
-}
-
-.location-panel:hover {
- box-shadow: 0 10px 30px -10px rgba(62, 73, 84, 0.10);
-}
-
-.location-panel::before {
- content: '';
- position: absolute;
- left: 0;
- top: 22px;
- bottom: 22px;
- width: 4px;
- border-radius: 0 4px 4px 0;
-}
-
-.pickup-panel::before {
- background: linear-gradient(180deg, #1890ff, #096dd9);
-}
-
-.drop-panel::before {
- background: linear-gradient(180deg, #a855f7, #65387a);
-}
-
-.lp-header {
- display: flex;
- justify-content: space-between;
- align-items: center;
- gap: 10px;
- flex-wrap: wrap;
- margin-bottom: 12px;
- padding-bottom: 10px;
- border-bottom: 1px dashed #e2e8f0;
-}
-
-.lp-header-actions {
- display: inline-flex;
- align-items: center;
- gap: 8px;
- flex-wrap: wrap;
-}
-
-/* Completion pill in panel header */
-.lp-completion-pill {
- display: inline-flex;
- align-items: center;
- font-size: 11.5px;
- font-weight: 700;
- letter-spacing: 0.5px;
- text-transform: uppercase;
- padding: 4px 11px;
- border-radius: 999px;
- background: rgba(148, 163, 184, 0.14);
- color: #64748b;
- border: 1px solid rgba(148, 163, 184, 0.25);
- line-height: 1;
-}
-
-.lp-completion-pill--ok {
- background: rgba(34, 197, 94, 0.12);
- color: #15803d;
- border-color: rgba(34, 197, 94, 0.30);
-}
-
-.lp-completion-pill--ok::before {
- content: '✓';
- margin-right: 4px;
- font-weight: 900;
-}
-
-/* Distance pill — sits alongside the completion pill in each panel header.
- Same shape language as the completion pill so the header reads as a coherent row of chips. */
-.lp-distance-pill {
- display: inline-flex;
- align-items: center;
- gap: 4px;
- font-size: 11.5px;
- font-weight: 700;
- letter-spacing: 0.3px;
- padding: 4px 10px;
- border-radius: 999px;
- background: linear-gradient(135deg, rgba(24, 144, 255, 0.10), rgba(168, 85, 247, 0.10));
- color: #1e293b;
- border: 1px solid rgba(101, 56, 122, 0.20);
- line-height: 1;
- white-space: nowrap;
-}
-
-.lp-distance-pill .lp-distance-arrow {
- color: #94a3b8;
- font-weight: 600;
-}
-
-.pickup-panel .lp-distance-pill {
- border-color: rgba(24, 144, 255, 0.25);
-}
-
-.drop-panel .lp-distance-pill {
- border-color: rgba(101, 56, 122, 0.25);
-}
-
-/* Compact icon-only swap button placed inside each panel header's action row.
- Color follows the panel's accent so it doesn't look like a generic floating button. */
-.lp-swap-btn {
- width: 32px !important;
- height: 32px !important;
- border-radius: 10px !important;
- border: 1px solid #e2e8f0 !important;
- background: #ffffff !important;
- color: #475569 !important;
- transition: all 0.2s ease;
-}
-
-.lp-swap-btn:hover {
- background: #f8fafc !important;
- border-color: #cbd5e1 !important;
- color: #1e293b !important;
- transform: rotate(180deg);
-}
-
-.pickup-panel .lp-swap-btn:hover {
- color: #1890ff !important;
- border-color: rgba(24, 144, 255, 0.35) !important;
-}
-
-.drop-panel .lp-swap-btn:hover {
- color: #65387a !important;
- border-color: rgba(101, 56, 122, 0.35) !important;
-}
-
-.lp-swap-btn.Mui-disabled {
- background: #f8fafc !important;
- border-color: #eef2f6 !important;
- color: #cbd5e1 !important;
-}
-
-.lp-header-title {
- display: flex;
- align-items: center;
- gap: 12px;
-}
-
-.lp-badge {
- width: 34px;
- height: 34px;
- border-radius: 10px;
- display: flex;
- align-items: center;
- justify-content: center;
- font-size: 15px;
- color: #fff;
- flex-shrink: 0;
- box-shadow: 0 4px 10px rgba(0, 0, 0, 0.10);
-}
-
-.pickup-panel .lp-badge {
- background: linear-gradient(135deg, #1890ff, #096dd9);
- box-shadow: 0 6px 14px rgba(24, 144, 255, 0.30);
-}
-
-.drop-panel .lp-badge {
- background: linear-gradient(135deg, #a855f7, #65387a);
- box-shadow: 0 6px 14px rgba(101, 56, 122, 0.30);
-}
-
-.lp-title {
- font-size: 15px;
- font-weight: 700;
- color: #1e293b;
- line-height: 1.2;
-}
-
-.lp-subtitle {
- font-size: 11.5px;
- color: #94a3b8;
- margin-top: 1px;
-}
-
-.lp-action-btn {
- text-transform: none !important;
- font-weight: 600 !important;
- font-size: 12px !important;
- border-radius: 8px !important;
- padding: 5px 11px !important;
- letter-spacing: 0.2px !important;
- min-height: 30px !important;
-}
-
-.pickup-panel .lp-action-btn {
- color: #1890ff !important;
- background: rgba(24, 144, 255, 0.08) !important;
-}
-
-.pickup-panel .lp-action-btn:hover {
- background: rgba(24, 144, 255, 0.16) !important;
-}
-
-.drop-panel .lp-action-btn {
- color: #65387a !important;
- background: rgba(168, 85, 247, 0.10) !important;
-}
-
-.drop-panel .lp-action-btn:hover {
- background: rgba(168, 85, 247, 0.18) !important;
-}
-
-.lp-action-btn.Mui-disabled {
- color: #cbd5e1 !important;
- background: #f8fafc !important;
-}
-
-/* Ghost variant used for secondary actions (e.g. "Same as Pickup") */
-.lp-action-btn--ghost {
- color: #475569 !important;
- background: transparent !important;
- border: 1px dashed #cbd5e1 !important;
-}
-
-.lp-action-btn--ghost:hover {
- color: #1e293b !important;
- background: #f8fafc !important;
- border-color: #94a3b8 !important;
-}
-
-.lp-action-btn--ghost.Mui-disabled {
- color: #cbd5e1 !important;
- background: transparent !important;
- border-color: #e2e8f0 !important;
-}
-
-/* Inline helper under the address search input — replaces the boxed wrapper */
-.address-search-helper {
- display: flex !important;
- align-items: center !important;
- gap: 6px !important;
- font-size: 13px !important;
- font-weight: 500 !important;
- margin-top: 6px !important;
- margin-left: 2px !important;
-}
-
-.address-search-helper.pickup-helper {
- color: #1890ff !important;
-}
-
-.address-search-helper.drop-helper {
- color: #65387a !important;
-}
-
-/* Field group caption */
-.field-group-caption {
- display: flex;
- align-items: center;
- gap: 8px;
- font-size: 10.5px;
- font-weight: 700;
- letter-spacing: 0.7px;
- text-transform: uppercase;
- color: #64748b;
- margin-bottom: 8px;
-}
-
-.field-group-caption::after {
- content: '';
- flex: 1;
- height: 1px;
- background: linear-gradient(90deg, #e2e8f0 0%, transparent 100%);
-}
-
-.field-group-dot {
- width: 7px;
- height: 7px;
- border-radius: 50%;
- display: inline-block;
-}
-
-.pickup-panel .field-group-dot {
- background: #1890ff;
-}
-
-.drop-panel .field-group-dot {
- background: #65387a;
-}
-
-/* Address search highlight */
-.address-search-block {
- background: rgba(24, 144, 255, 0.04);
- border-radius: 12px;
- padding: 16px;
- border: 1px solid rgba(24, 144, 255, 0.12);
- transition: border-color 0.2s ease;
-}
-
-.drop-panel .address-search-block {
- background: rgba(168, 85, 247, 0.04);
- border: 1px solid rgba(101, 56, 122, 0.12);
-}
-
-.address-search-block:focus-within {
- border-color: rgba(24, 144, 255, 0.4);
-}
-
-.drop-panel .address-search-block:focus-within {
- border-color: rgba(101, 56, 122, 0.4);
-}
-
-.address-search-hint {
- display: flex;
- align-items: center;
- gap: 6px;
- font-size: 11.5px;
- color: #64748b;
- margin-bottom: 12px;
- font-weight: 500;
-}
-
-/* Save-for-later pill */
-.save-later-pill {
- display: inline-flex;
- align-items: center;
- gap: 6px;
- background: linear-gradient(135deg, rgba(34, 197, 94, 0.10), rgba(34, 197, 94, 0.04));
- border: 1px dashed #86efac;
- border-radius: 999px;
- padding: 4px 12px 4px 8px;
- margin-top: 4px;
-}
-
-.save-later-pill .MuiFormControlLabel-root {
- margin: 0;
-}
-
-.save-later-pill .MuiCheckbox-root {
- padding: 4px;
- color: #22c55e;
-}
-
-.save-later-pill .MuiTypography-root {
- font-size: 13.5px;
- font-weight: 600;
- color: #15803d;
-}
-
-/* ============================================== */
-/* Vertical Route Flow (Pickup -> Drop) */
-/* ============================================== */
-.route-flow {
- display: flex;
- flex-direction: column;
- gap: 18px;
-}
-
-.route-flow-link {
- display: flex;
- align-items: center;
- justify-content: flex-start;
- position: relative;
- padding: 22px 0 22px 31px;
- gap: 18px;
- min-height: 80px;
-}
-
-.route-flow-link::before {
- content: '';
- position: absolute;
- left: 46px;
- top: 0;
- bottom: 0;
- width: 2px;
- background: repeating-linear-gradient(to bottom, #cbd5e1, #cbd5e1 4px, transparent 4px, transparent 8px);
- z-index: 1;
-}
-
-.route-flow-arrow {
- position: relative;
- z-index: 2;
- display: inline-flex;
- align-items: center;
- justify-content: center;
- width: 32px;
- height: 32px;
- border-radius: 50%;
- background: #ffffff;
- border: 2px solid #cbd5e1;
- color: #64748b;
- box-shadow: 0 2px 6px rgba(0, 0, 0, 0.04);
- transition: all 0.25s ease;
-}
-
-.route-flow-arrow:hover {
- background: linear-gradient(135deg, #1890ff, #65387a);
- color: #fff;
- border-color: transparent;
- transform: scale(1.05);
-}
-
-.route-flow-distance {
- display: inline-flex;
- align-items: center;
- gap: 8px;
- background: linear-gradient(135deg, rgba(24, 144, 255, 0.08), rgba(168, 85, 247, 0.08));
- border: 1px dashed rgba(101, 56, 122, 0.25);
- border-radius: 999px;
- padding: 6px 16px;
- font-size: 14px;
- font-weight: 600;
- color: #475569;
-}
-
-.route-flow-distance .dist-value {
- color: #1890ff;
- font-weight: 700;
- font-size: 14.5px;
-}
-
-.route-flow-distance .dist-label {
- color: #64748b;
- font-weight: 500;
- font-size: 13.5px;
-}
-
-.route-flow-distance .dist-route {
- display: inline-flex;
- align-items: center;
- gap: 5px;
- margin-right: 2px;
-}
-
-.route-flow-distance .dist-dot {
- width: 7px;
- height: 7px;
- border-radius: 50%;
- display: inline-block;
-}
-
-.route-flow-distance .dist-dot--pick {
- background: #1890ff;
- box-shadow: 0 0 0 2px rgba(24, 144, 255, 0.18);
-}
-
-.route-flow-distance .dist-dot--drop {
- background: #65387a;
- box-shadow: 0 0 0 2px rgba(101, 56, 122, 0.18);
-}
-
-.route-flow-distance .dist-arrow {
- color: #94a3b8;
- font-size: 11px;
- line-height: 1;
-}
-
-.route-flow-distance .dist-placeholder {
- color: #94a3b8;
- font-weight: 500;
- font-style: italic;
- font-size: 13.5px;
-}
-
-/* Swap pickup ↔ drop button in the route connector */
-.route-flow-swap {
- margin-left: auto !important;
- display: inline-flex !important;
- align-items: center !important;
- gap: 6px !important;
- text-transform: none !important;
- font-weight: 600 !important;
- font-size: 13.5px !important;
- letter-spacing: 0.2px !important;
- color: #475569 !important;
- background: #ffffff !important;
- border: 1px solid #e2e8f0 !important;
- border-radius: 999px !important;
- padding: 6px 14px !important;
- min-width: 0 !important;
- box-shadow: 0 1px 2px rgba(0, 0, 0, 0.04);
- transition: all 0.2s ease;
-}
-
-.route-flow-swap:hover {
- color: #1e293b !important;
- background: #f8fafc !important;
- border-color: #cbd5e1 !important;
- transform: translateY(-1px);
- box-shadow: 0 4px 10px -2px rgba(0, 0, 0, 0.08);
-}
-
-.route-flow-swap.Mui-disabled {
- color: #cbd5e1 !important;
- border-color: #eef2f6 !important;
- background: #ffffff !important;
- box-shadow: none;
-}
-
-
-/* Workspace background — dashboard shell.
- Outer page is locked to 100vh on md+, no body scroll. Columns scroll internally.
- sx-level rules on the JSX wrapper drive height/overflow per breakpoint — keep this
- class background-only so it doesn't fight inline styles. */
+/* ---------- Page background ---------- */
.orders-workspace-bg {
background: linear-gradient(135deg, #f8fafc 0%, #edf2f7 100%) !important;
}
-/* Internal-scroll columns: thin, on-hover scrollbar that doesn't intrude on the design */
-.dashboard-scroll-col {
- scrollbar-width: thin;
- scrollbar-color: rgba(148, 163, 184, 0.4) transparent;
+/* ---------- Cards ---------- */
+.orders-card {
+ background: #ffffff !important;
+ border: 1px solid #eef2f6 !important;
+ border-radius: 12px !important;
+ box-shadow: 0 10px 25px -5px rgba(62, 73, 84, 0.04),
+ 0 4px 12px -2px rgba(62, 73, 84, 0.02) !important;
+ transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1) !important;
+ overflow: hidden;
+}
+.orders-card:hover {
+ box-shadow: 0 16px 35px -8px rgba(62, 73, 84, 0.08),
+ 0 6px 16px -3px rgba(62, 73, 84, 0.03) !important;
}
-.dashboard-scroll-col::-webkit-scrollbar {
- width: 8px;
+.orders-card .MuiOutlinedInput-root {
+ font-size: 13px !important;
+ border-radius: 10px !important;
+}
+.orders-card .MuiOutlinedInput-input {
+ font-size: 13px !important;
+ padding-top: 9px !important;
+ padding-bottom: 9px !important;
+}
+.orders-card .MuiInputLabel-root {
+ font-size: 13px !important;
+}
+.orders-card .MuiInputLabel-root.MuiInputLabel-shrink {
+ font-size: 11.5px !important;
}
-.dashboard-scroll-col::-webkit-scrollbar-track {
- background: transparent;
-}
-
-.dashboard-scroll-col::-webkit-scrollbar-thumb {
- background-color: rgba(148, 163, 184, 0.35);
- border-radius: 999px;
- border: 2px solid transparent;
- background-clip: padding-box;
-}
-
-.dashboard-scroll-col:hover::-webkit-scrollbar-thumb {
- background-color: rgba(100, 116, 139, 0.55);
- background-clip: padding-box;
-}
-
-/* Card section title with a leading gradient accent strip.
- Used by "Other Details" and "Schedule" cards (and any other card section
- that wants a premium-feeling left-edge accent before its h5 title). */
+/* ---------- Section title bar (gradient strip + h-title) ---------- */
.section-title-bar {
display: flex;
align-items: center;
gap: 12px;
margin-bottom: 20px;
}
-
.section-title-bar::before {
content: '';
width: 4px;
@@ -557,969 +53,20 @@
background: linear-gradient(180deg, #1890ff, #096dd9);
flex-shrink: 0;
}
-
-/* Accent variant for the Schedule card — uses the purple/violet gradient
- from the drop-panel so users get a subtle visual cue distinguishing
- sections without needing labels. */
.section-title-bar--accent::before {
background: linear-gradient(180deg, #a855f7, #65387a);
}
-
.section-title-bar .MuiTypography-root {
margin-bottom: 0 !important;
line-height: 1.2;
}
-/* Service Configuration Horizontal Header Row */
-.service-config-bar {
- background: rgba(255, 255, 255, 0.75) !important;
- backdrop-filter: blur(16px) !important;
- -webkit-backdrop-filter: blur(16px) !important;
- border: 1px solid rgba(255, 255, 255, 0.6) !important;
- border-radius: 12px !important;
- box-shadow: 0 4px 20px -5px rgba(148, 163, 184, 0.1) !important;
- padding: 12px 20px !important;
- margin-bottom: 12px !important;
- flex-shrink: 0;
-}
-
-/* Main Dashboard 3-Column Console Wrapper */
-.console-dashboard-layout {
- display: flex;
- gap: 16px;
- flex: 1;
- overflow: hidden;
-}
-
-/* Balanced Left & Right Panes */
-.console-left-pane {
- flex: 1.7;
- /* ~63% width */
- display: flex;
- flex-direction: column;
- gap: 12px;
- overflow-y: auto;
- padding-right: 4px;
-}
-
-.console-right-pane {
- flex: 1;
- /* ~37% width */
- display: flex;
- flex-direction: column;
- gap: 12px;
- overflow-y: auto;
- padding-right: 4px;
-}
-
-/* Custom Scrollbar for Individual Columns to keep console extremely clean */
-.console-left-pane::-webkit-scrollbar,
-.console-right-pane::-webkit-scrollbar {
- width: 4px;
-}
-
-.console-left-pane::-webkit-scrollbar-track,
-.console-right-pane::-webkit-scrollbar-track {
- background: transparent;
-}
-
-.console-left-pane::-webkit-scrollbar-thumb,
-.console-right-pane::-webkit-scrollbar-thumb {
- background: rgba(148, 163, 184, 0.3);
- border-radius: 99px;
-}
-
-.console-left-pane::-webkit-scrollbar-thumb:hover,
-.console-right-pane::-webkit-scrollbar-thumb:hover {
- background: rgba(148, 163, 184, 0.5);
-}
-
-/* Glassmorphism Card Style */
-.glass-card {
- background: rgba(255, 255, 255, 0.8) !important;
- backdrop-filter: blur(12px) !important;
- -webkit-backdrop-filter: blur(12px) !important;
- border: 1px solid rgba(255, 255, 255, 0.5) !important;
- border-radius: 12px !important;
- box-shadow: 0 10px 25px -5px rgba(62, 73, 84, 0.04), 0 4px 12px -2px rgba(62, 73, 84, 0.02) !important;
- transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1) !important;
-}
-
-.glass-card:hover {
- box-shadow: 0 16px 35px -8px rgba(62, 73, 84, 0.07), 0 6px 16px -3px rgba(62, 73, 84, 0.03) !important;
- border-color: rgba(255, 255, 255, 0.8) !important;
-}
-
-/* Premium Focus Glows inside Location Panel inputs */
-.pickup-panel .MuiOutlinedInput-root.Mui-focused .MuiOutlinedInput-notchedOutline {
- border-color: #0ea5e9 !important;
- box-shadow: 0 0 0 3px rgba(14, 165, 233, 0.12);
-}
-
-.drop-panel .MuiOutlinedInput-root.Mui-focused .MuiOutlinedInput-notchedOutline {
- border-color: #a855f7 !important;
- box-shadow: 0 0 0 3px rgba(168, 85, 247, 0.12);
-}
-
-/* Glowing active weight selector card variants */
-.weight-card-btn.active.weight-light {
- background: rgba(14, 165, 233, 0.04) !important;
- border-color: #0ea5e9 !important;
- box-shadow: 0 6px 16px rgba(14, 165, 233, 0.15) !important;
-}
-
-.weight-card-btn.active.weight-light::before {
- content: '';
- position: absolute;
- top: 0;
- left: 0;
- right: 0;
- height: 3px;
- background: #0ea5e9;
-}
-
-.weight-card-btn.active.weight-medium {
- background: rgba(168, 85, 247, 0.04) !important;
- border-color: #a855f7 !important;
- box-shadow: 0 6px 16px rgba(168, 85, 247, 0.15) !important;
-}
-
-.weight-card-btn.active.weight-medium::before {
- content: '';
- position: absolute;
- top: 0;
- left: 0;
- right: 0;
- height: 3px;
- background: #a855f7;
-}
-
-.weight-card-btn.active.weight-heavy {
- background: rgba(99, 102, 241, 0.04) !important;
- border-color: #662582 !important;
- box-shadow: 0 6px 16px rgba(99, 102, 241, 0.15) !important;
-}
-
-.weight-card-btn.active.weight-heavy::before {
- content: '';
- position: absolute;
- top: 0;
- left: 0;
- right: 0;
- height: 3px;
- background: #662582;
-}
-
-/* Premium Card Overrides */
-.orders-card {
- background: #ffffff !important;
- border: 1px solid #eef2f6 !important;
- border-radius: 12px !important;
- box-shadow: 0 10px 25px -5px rgba(62, 73, 84, 0.04), 0 4px 12px -2px rgba(62, 73, 84, 0.02) !important;
- transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1) !important;
- overflow: hidden;
-}
-
-/* ============================================== */
-/* MUI Field Sizing — Readable on large screens */
-/* ============================================== */
-
-/* Compact TextField input + label sizes inside Pickup/Drop panels and order cards */
-.location-panel .MuiOutlinedInput-root,
-.orders-card .MuiOutlinedInput-root {
- font-size: 13px !important;
- border-radius: 10px !important;
-}
-
-.location-panel .MuiOutlinedInput-input,
-.orders-card .MuiOutlinedInput-input {
- font-size: 13px !important;
- padding-top: 9px !important;
- padding-bottom: 9px !important;
-}
-
-.location-panel .MuiInputLabel-root,
-.orders-card .MuiInputLabel-root {
- font-size: 13px !important;
-}
-
-/* When label is shrunk (floating up), keep it slightly smaller for the float effect */
-.location-panel .MuiInputLabel-root.MuiInputLabel-shrink,
-.orders-card .MuiInputLabel-root.MuiInputLabel-shrink {
- font-size: 11.5px !important;
-}
-
-/* MUI helper text (validation / hints under fields) */
-.location-panel .MuiFormHelperText-root,
-.orders-card .MuiFormHelperText-root {
- font-size: 11px !important;
- margin-top: 3px !important;
-}
-
-/* Autocomplete options dropdown */
-.MuiAutocomplete-popper .MuiAutocomplete-option {
- font-size: 13px !important;
- padding-top: 6px !important;
- padding-bottom: 6px !important;
- min-height: 34px !important;
-}
-
-/* Card section titles (h5 / h6) inside order cards — tighter hierarchy */
-.orders-card .MuiTypography-h5 {
- font-size: 15px !important;
-}
-
-.orders-card .MuiTypography-h6 {
- font-size: 13.5px !important;
-}
-
-.orders-card:hover {
- box-shadow: 0 16px 35px -8px rgba(62, 73, 84, 0.08), 0 6px 16px -3px rgba(62, 73, 84, 0.03) !important;
-}
-
-/* Glassmorphic elements */
-.glass-panel {
- background: rgba(255, 255, 255, 0.8) !important;
- backdrop-filter: blur(12px) !important;
- -webkit-backdrop-filter: blur(12px) !important;
- border: 1px solid rgba(255, 255, 255, 0.5) !important;
-}
-
-/* Trip Route Visual Connector */
-.connector-line-wrapper {
- position: relative;
- display: flex;
- align-items: center;
- justify-content: center;
- height: 100%;
-}
-
-.connector-line {
- position: absolute;
- top: 15%;
- bottom: 15%;
- width: 2px;
- background: repeating-linear-gradient(to bottom,
- #1890ff,
- #1890ff 6px,
- transparent 6px,
- transparent 12px);
- z-index: 1;
-}
-
-.connector-icon-wrapper {
- background: #ffffff;
- border: 2px solid #1890ff;
- border-radius: 50%;
- width: 32px;
- height: 32px;
- display: flex;
- align-items: center;
- justify-content: center;
- box-shadow: 0 4px 10px rgba(24, 144, 255, 0.15);
- z-index: 2;
- transition: all 0.3s ease;
-}
-
-.connector-line-wrapper:hover .connector-icon-wrapper {
- transform: scale(1.15) rotate(15deg);
- box-shadow: 0 6px 14px rgba(24, 144, 255, 0.25);
-}
-
-/* Custom Interactive Cargo Weight Selector */
-.weight-selector-grid {
- display: grid;
- grid-template-columns: repeat(3, 1fr);
- gap: 10px;
- width: 100%;
- margin: 8px 0;
-}
-
-.weight-card-btn {
- background: #ffffff;
- border: 1.5px solid #eef2f6;
- border-radius: 10px;
- padding: 10px 8px;
- display: flex;
- flex-direction: column;
- align-items: center;
- justify-content: center;
- cursor: pointer;
- transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
- text-align: center;
- user-select: none;
- position: relative;
- overflow: hidden;
-}
-
-.weight-card-btn:hover {
- transform: translateY(-1.5px);
- border-color: #cbd5e1;
- background-color: #f8fafc;
-}
-
-.weight-card-btn.active {
- background: rgba(24, 144, 255, 0.04);
- border-color: #1890ff;
- box-shadow: 0 4px 12px -2px rgba(24, 144, 255, 0.12);
-}
-
-.weight-card-btn.active::before {
- content: '';
- position: absolute;
- top: 0;
- left: 0;
- right: 0;
- height: 3px;
- background: #1890ff;
-}
-
-.weight-card-icon {
- font-size: 18px;
- margin-bottom: 4px;
- color: #64748b;
- transition: all 0.3s ease;
-}
-
-.weight-card-btn.active .weight-card-icon {
- color: #1890ff;
- transform: scale(1.08);
-}
-
-.weight-card-label {
- font-size: 12.5px;
- font-weight: 600;
- color: #334155;
- margin-bottom: 2px;
-}
-
-.weight-card-desc {
- font-size: 9.5px;
- color: #64748b;
- line-height: 1.2;
-}
-
-/* Live Map Preview Container */
-.map-preview-wrapper {
- position: relative;
- border-radius: 12px;
- overflow: hidden;
- box-shadow: 0 4px 15px rgba(0, 0, 0, 0.05);
- border: 1px solid #eef2f6;
- height: 260px;
- min-height: 260px;
-}
-
-.map-preview-wrapper .leaflet-container {
- height: 100% !important;
- min-height: 0 !important;
-}
-
-.map-preview-wrapper > div {
- min-height: 0 !important;
-}
-
-/* Premium Cost & Metrics Dashboard — compact professional layout */
-.pricing-summary-card {
- background: linear-gradient(135deg, #ffffff 0%, #fafbfc 100%) !important;
- border: 1px solid #eef2f6 !important;
- border-radius: 14px !important;
- padding: 14px 16px !important;
-}
-
-.pricing-header {
- display: flex;
- align-items: baseline;
- justify-content: space-between;
- gap: 12px;
- margin-bottom: 10px;
- padding-bottom: 10px;
- border-bottom: 1px solid #f1f5f9;
-}
-
-.pricing-title {
- font-size: 14px !important;
- font-weight: 700 !important;
- color: #1e293b !important;
- letter-spacing: -0.01em;
-}
-
-.pricing-subtitle {
- font-size: 11px !important;
- font-weight: 500 !important;
- color: #94a3b8 !important;
- text-transform: uppercase;
- letter-spacing: 0.6px;
-}
-
-.price-metric-item {
- display: flex;
- align-items: center;
- justify-content: space-between;
- padding: 7px 0;
- border-bottom: 1px solid #f5f7fa;
-}
-
-.price-metric-item:last-of-type {
- border-bottom: none;
- padding-bottom: 4px;
-}
-
-.price-metric-label {
- font-size: 12.5px;
- color: #475569;
- font-weight: 500;
- display: flex;
- align-items: center;
- gap: 10px;
- min-width: 0;
-}
-
-.price-metric-icon {
- width: 26px;
- height: 26px;
- flex-shrink: 0;
- border-radius: 8px;
- display: inline-flex;
- align-items: center;
- justify-content: center;
- font-size: 12px;
-}
-
-.price-metric-icon.icon-distance {
- background: rgba(24, 144, 255, 0.10);
- color: #1890ff;
-}
-
-.price-metric-icon.icon-base {
- background: rgba(34, 197, 94, 0.10);
- color: #16a34a;
-}
-
-.price-metric-icon.icon-rate {
- background: rgba(245, 158, 11, 0.12);
- color: #d97706;
-}
-
-.price-metric-sub {
- color: #94a3b8;
- font-weight: 500;
- font-size: 11.5px;
-}
-
-.price-metric-value {
- font-size: 13.5px;
- font-weight: 700;
- color: #1e293b;
- display: inline-flex;
- align-items: baseline;
- gap: 2px;
- white-space: nowrap;
-}
-
-.price-metric-value.highlight {
- color: #1890ff;
-}
-
-.price-metric-unit {
- font-size: 11px;
- font-weight: 500;
- color: #94a3b8;
- margin-left: 2px;
-}
-
-.total-charge-badge {
- background: linear-gradient(135deg, rgba(24, 144, 255, 0.08) 0%, rgba(101, 56, 122, 0.10) 100%);
- border: 1px solid rgba(101, 56, 122, 0.18);
- border-radius: 10px;
- padding: 10px 14px;
- display: flex;
- align-items: center;
- justify-content: space-between;
- gap: 12px;
- margin-top: 12px;
-}
-
-.total-charge-left {
- display: inline-flex;
- align-items: center;
- gap: 8px;
- min-width: 0;
-}
-
-.total-charge-icon {
- font-size: 13px;
- color: #65387A;
- flex-shrink: 0;
-}
-
-.total-charge-label {
- font-size: 11.5px;
- font-weight: 700;
- text-transform: uppercase;
- letter-spacing: 0.6px;
- color: #65387A;
-}
-
-.total-charge-val {
- font-size: 20px;
- font-weight: 800;
- color: #65387A;
- line-height: 1.1;
- letter-spacing: -0.01em;
- white-space: nowrap;
-}
-
-/* Gradient Action Button — compact professional */
-.gradient-btn-create {
- background: linear-gradient(135deg, #1890ff 0%, #65387a 100%) !important;
- color: #ffffff !important;
- font-weight: 600 !important;
- font-size: 13px !important;
- letter-spacing: 0.01em !important;
- text-transform: none !important;
- border-radius: 10px !important;
- padding: 8px 18px !important;
- min-height: 38px !important;
- box-shadow: 0 4px 12px -3px rgba(24, 144, 255, 0.30), 0 2px 4px rgba(101, 56, 122, 0.10) !important;
- transition: all 0.22s cubic-bezier(0.4, 0, 0.2, 1) !important;
- border: none !important;
- display: inline-flex !important;
- align-items: center !important;
- justify-content: center !important;
- gap: 8px !important;
-}
-
-.gradient-btn-create .MuiButton-startIcon,
-.gradient-btn-create .MuiButton-endIcon {
- margin: 0 !important;
-}
-
-.gradient-btn-create:hover {
- filter: brightness(1.04);
- box-shadow: 0 8px 18px -4px rgba(24, 144, 255, 0.40), 0 3px 8px rgba(101, 56, 122, 0.18) !important;
-}
-
-.gradient-btn-create:active {
- filter: brightness(0.98);
-}
-
-.gradient-btn-create.Mui-disabled,
-.gradient-btn-create:disabled {
- background: #e2e8f0 !important;
- color: #94a3b8 !important;
- box-shadow: none !important;
- cursor: not-allowed !important;
-}
-
-/* Completion checklist */
-.completion-checklist {
- margin: 16px 0;
- padding: 0;
- list-style: none;
-}
-
-.completion-item {
- display: flex;
- align-items: center;
- gap: 12px;
- font-size: 14.5px;
- color: #64748b;
- margin-bottom: 10px;
- transition: all 0.3s ease;
- line-height: 1.4;
-}
-
-.completion-item.completed {
- color: #0f172a;
- font-weight: 600;
-}
-
-.completion-bullet {
- width: 10px;
- height: 10px;
- border-radius: 50%;
- background-color: #cbd5e1;
- flex-shrink: 0;
- transition: all 0.3s ease;
-}
-
-.completion-item.completed .completion-bullet {
- background-color: #10b981;
- box-shadow: 0 0 8px #10b981;
-}
-
-/* Saved Address Modal Cards */
-.address-card-btn {
- width: 100%;
- border: 1.5px solid #eef2f6 !important;
- border-radius: 12px !important;
- padding: 16px !important;
- background: #ffffff !important;
- text-transform: none !important;
- transition: all 0.2s ease !important;
- margin-bottom: 12px;
-}
-
-.address-card-btn:hover {
- border-color: #1890ff !important;
- background-color: rgba(24, 144, 255, 0.02) !important;
- transform: translateY(-2px);
- box-shadow: 0 4px 12px rgba(0, 0, 0, 0.03);
-}
-
-.address-card-btn:disabled {
- background-color: #f8fafc !important;
- border-color: #e2e8f0 !important;
- opacity: 0.7;
-}
-
-/* Status pulses */
-.pulse-indicator {
- width: 8px;
- height: 8px;
- border-radius: 50%;
- background: #10b981;
- box-shadow: 0 0 0 0 rgba(16, 185, 129, 0.7);
- animation: pulse-green 2s infinite;
-}
-
-@keyframes pulse-green {
- 0% {
- transform: scale(0.95);
- box-shadow: 0 0 0 0 rgba(16, 185, 129, 0.7);
- }
-
- 70% {
- transform: scale(1);
- box-shadow: 0 0 0 6px rgba(16, 185, 129, 0);
- }
-
- 100% {
- transform: scale(0.95);
- box-shadow: 0 0 0 0 rgba(16, 185, 129, 0);
- }
-}
-
-.pulse-yellow {
- background: #f59e0b;
- box-shadow: 0 0 0 0 rgba(245, 158, 11, 0.7);
- animation: pulse-yellow-anim 2s infinite;
-}
-
-@keyframes pulse-yellow-anim {
- 0% {
- transform: scale(0.95);
- box-shadow: 0 0 0 0 rgba(245, 158, 11, 0.7);
- }
-
- 70% {
- transform: scale(1);
- box-shadow: 0 0 0 6px rgba(245, 158, 11, 0);
- }
-
- 100% {
- transform: scale(0.95);
- box-shadow: 0 0 0 0 rgba(245, 158, 11, 0);
- }
-}
-
-/* Form layout responsiveness adjustments */
-@media (max-width: 959px) {
- .connector-line-wrapper {
- display: none;
- }
-}
-
-/* ============================================== */
-/* Side-by-Side Pickup / Drop (md+ breakpoint) */
-/* At md+ the route flow rotates to horizontal: */
-/* [ PICKUP ] [ vertical connector ] [ DROP ] */
-/* ============================================== */
-@media (min-width: 900px) {
- .route-flow {
- flex-direction: row;
- align-items: stretch;
- gap: 16px;
- }
-
- /* Each panel takes equal share of the row; min-width: 0 prevents flex blow-out */
- .route-flow > .location-panel {
- flex: 1 1 0;
- min-width: 0;
- }
-
- /* Stack the inner field grids vertically — at ~340px panel width, side-by-side fields
- don't have room for label + icon adornment + input. Force one column per panel. */
- .route-flow > .location-panel .MuiGrid-container > .MuiGrid-item {
- flex-basis: 100% !important;
- max-width: 100% !important;
- }
-
- /* Connector becomes a narrow vertical strip between the two panels */
- .route-flow-link {
- flex-direction: column;
- align-items: center;
- justify-content: center;
- padding: 8px 4px;
- min-height: 0;
- min-width: 92px;
- flex-shrink: 0;
- gap: 14px;
- }
-
- /* The vertical dashed line was a guide for the vertical layout — hide it in row mode.
- The arrow circle + colored panel borders carry enough visual cue on their own. */
- .route-flow-link::before {
- display: none;
- }
-
- /* Rotate the down-arrow to point right (pickup → drop direction) */
- .route-flow-arrow svg {
- transform: rotate(-90deg);
- transition: transform 0.25s ease;
- }
-
- /* Swap button no longer floats right — it stacks beneath the distance pill */
- .route-flow-swap {
- margin-left: 0 !important;
- margin-top: 0 !important;
- }
-
- /* Distance pill: stack vertically inside the narrow connector column —
- route dots on top, value below — and drop the "Distance" label since the
- pill's existence is self-explanatory in this position. */
- .route-flow-distance {
- flex-direction: column;
- gap: 4px;
- padding: 8px 10px;
- text-align: center;
- line-height: 1.2;
- }
-
- .route-flow-distance .dist-label {
- display: none;
- }
-
- /* Compact the placeholder text so it fits when no addresses are set yet */
- .route-flow-distance .dist-placeholder {
- font-size: 11px;
- line-height: 1.3;
- }
-}
-
-/* On very wide screens (xl+), restore the 2-col inner grid inside each panel —
- panels are now wide enough (~440px+) for label + icon + input pairs. */
-@media (min-width: 1536px) {
- .route-flow > .location-panel .MuiGrid-container > .MuiGrid-item.MuiGrid-grid-sm-6 {
- flex-basis: 50% !important;
- max-width: 50% !important;
- }
-}
-
-/* Act as senior frontend engineer and UI/UX specialist:
- Scale down visual elements, paddings, and font sizes on laptop screens
- to reclaim precious screen space and maintain a high-density, premium look. */
-@media (max-width: 1400px) {
- .orders-card .MuiTypography-h5 {
- font-size: 17px !important;
- }
-
- .orders-card .MuiTypography-h6 {
- font-size: 14.5px !important;
- }
-
- .lp-title {
- font-size: 15.5px;
- }
-
- .lp-subtitle {
- font-size: 12px;
- margin-top: 1px;
- }
-
- .lp-badge {
- width: 36px;
- height: 36px;
- border-radius: 10px;
- font-size: 15px;
- }
-
- .lp-action-btn {
- font-size: 12.5px !important;
- padding: 5px 10px !important;
- }
-
- .route-flow-link {
- padding: 16px 0 16px 26px;
- min-height: 60px;
- }
-
- .route-flow-link::before {
- left: 41px;
- }
-
- .route-flow-arrow {
- width: 28px;
- height: 28px;
- }
-
- .route-flow-distance {
- padding: 4px 12px;
- font-size: 12.5px;
- }
-
- .route-flow-swap {
- font-size: 12px !important;
- padding: 4px 10px !important;
- }
-
- .map-preview-wrapper {
- height: 220px;
- min-height: 220px;
- }
-
- .weight-card-btn {
- padding: 8px 6px;
- }
-
- .weight-card-label {
- font-size: 11.5px;
- }
-
- .weight-card-desc {
- font-size: 9px;
- }
-
- .orders-card {
- padding: 16px !important; /* Tighten general card padding from 24px */
- }
-
- .orders-card.page-header-row {
- padding: 10px 16px !important; /* Tighten the header row padding */
- }
-}
-
-/* Reclaim unused screen space around the workspace card on desktop and laptop viewports */
-@media (min-width: 900px) {
- /* Expand the maximum width of the layout container so it spans the screen and removes empty margins */
- .MuiContainer-root:has(.orders-workspace-bg) {
- max-width: 1600px !important;
- padding-left: 16px !important;
- padding-right: 16px !important;
- }
-
- /* Reduce the spacing outside the page container */
- main:has(.orders-workspace-bg) {
- padding: 16px !important;
- }
-}
-
-/* ============================================== */
-/* Compact header dropdowns (Location / Client / Business Location) */
-/* ============================================== */
-.header-compact-tf .MuiOutlinedInput-root {
- border-radius: 10px !important;
- height: 40px !important;
- padding-left: 10px !important;
- font-size: 12.5px !important;
- background: #ffffff;
-}
-
-.header-compact-tf .MuiOutlinedInput-input {
- padding-top: 6px !important;
- padding-bottom: 6px !important;
- font-size: 12.5px !important;
-}
-
-.header-compact-tf .MuiInputLabel-root {
- font-size: 11.5px !important;
- letter-spacing: 0.02em;
- font-weight: 600;
- color: #64748b !important;
-}
-
-.header-compact-tf .MuiInputLabel-shrink {
- transform: translate(12px, -7px) scale(0.82) !important;
- background: #ffffff;
- padding: 0 4px;
-}
-
-.header-compact-tf .MuiOutlinedInput-notchedOutline {
- border-color: #e2e8f0;
-}
-
-.header-compact-tf:hover .MuiOutlinedInput-notchedOutline {
- border-color: #cbd5e1;
-}
-
-.header-compact-tf .Mui-focused .MuiOutlinedInput-notchedOutline {
- border-width: 1.5px !important;
-}
-
-/* Autocomplete-specific tweaks: vertically center the clear / popup icons */
-.header-compact-input .MuiAutocomplete-endAdornment {
- top: 50%;
- transform: translateY(-50%);
- right: 8px;
- display: inline-flex;
- align-items: center;
- height: auto;
- gap: 2px;
-}
-
-.header-compact-input .MuiAutocomplete-endAdornment .MuiSvgIcon-root {
- font-size: 16px;
- display: block;
-}
-
-.header-compact-input .MuiAutocomplete-clearIndicator,
-.header-compact-input .MuiAutocomplete-popupIndicator {
- padding: 3px !important;
- width: 22px;
- height: 22px;
- display: inline-flex;
- align-items: center;
- justify-content: center;
- color: #94a3b8 !important;
-}
-
-.header-compact-input .MuiAutocomplete-clearIndicator:hover,
-.header-compact-input .MuiAutocomplete-popupIndicator:hover {
- background: rgba(148, 163, 184, 0.12) !important;
- color: #475569 !important;
-}
-
-.header-compact-input .MuiAutocomplete-popupIndicator {
- margin-right: 0;
-}
-
-.header-compact-input .MuiOutlinedInput-root {
- padding-top: 0 !important;
- padding-bottom: 0 !important;
- padding-right: 60px !important;
-}
-
-.header-compact-input .MuiAutocomplete-input {
- padding: 4px 4px 4px 0 !important;
- height: auto !important;
-}
-
-/* Title row alignment tweak for tighter header */
-.page-header-row {
- min-height: 0 !important;
-}
-
-/* ============================================== */
-/* Delivery Preferences Card */
-/* (Special Dispatch Notes + SMS Updates) */
-/* ============================================== */
+/* ---------- Delivery preferences card ---------- */
.delivery-prefs-card {
background: linear-gradient(135deg, #ffffff 0%, #fbfcff 100%) !important;
border: 1px solid #eef2f6 !important;
border-radius: 14px !important;
}
-
.delivery-prefs-header {
display: flex;
align-items: baseline;
@@ -1529,7 +76,6 @@
padding-bottom: 10px;
border-bottom: 1px solid #f1f5f9;
}
-
.delivery-prefs-title {
font-size: 14px !important;
font-weight: 700 !important;
@@ -1537,7 +83,6 @@
letter-spacing: -0.01em;
line-height: 1.2;
}
-
.delivery-prefs-sub {
font-size: 10.5px !important;
font-weight: 500 !important;
@@ -1547,19 +92,16 @@
text-align: right;
line-height: 1.2;
}
-
.delivery-prefs-row {
display: flex;
flex-direction: column;
gap: 10px;
}
-
.delivery-prefs-field {
display: flex;
flex-direction: column;
gap: 5px;
}
-
.delivery-prefs-label {
display: inline-flex;
align-items: center;
@@ -1571,306 +113,176 @@
color: #64748b;
}
-/* SMS toggle tile — a card-like clickable strip */
-.sms-toggle-tile {
+/* ---------- Pricing summary card ---------- */
+.pricing-summary-card {
+ background: linear-gradient(135deg, #ffffff 0%, #fafbfc 100%) !important;
+ border: 1px solid #eef2f6 !important;
+ border-radius: 14px !important;
+ padding: 14px 16px !important;
+}
+.pricing-header {
display: flex;
- align-items: center;
+ align-items: baseline;
justify-content: space-between;
- gap: 10px;
- padding: 8px 12px;
- border-radius: 10px;
- border: 1px solid #eef2f6;
- background: #fafbfc;
- cursor: pointer;
- user-select: none;
- transition: border-color 0.2s ease, background 0.2s ease, box-shadow 0.2s ease;
+ gap: 12px;
+ margin-bottom: 10px;
+ padding-bottom: 10px;
+ border-bottom: 1px solid #f1f5f9;
}
-
-.sms-toggle-tile:hover {
- border-color: #cbd5e1;
- background: #ffffff;
-}
-
-.sms-toggle-tile.is-active {
- background: linear-gradient(135deg, rgba(24, 144, 255, 0.06) 0%, rgba(101, 56, 122, 0.05) 100%);
- border-color: rgba(24, 144, 255, 0.28);
- box-shadow: 0 3px 10px -3px rgba(24, 144, 255, 0.18);
-}
-
-.sms-toggle-left {
- display: inline-flex;
- align-items: center;
- gap: 9px;
- min-width: 0;
-}
-
-.sms-toggle-icon {
- width: 28px;
- height: 28px;
- flex-shrink: 0;
- border-radius: 8px;
- display: inline-flex;
- align-items: center;
- justify-content: center;
- background: #eef2f6;
- color: #94a3b8;
- transition: all 0.2s ease;
-}
-
-.sms-toggle-tile.is-active .sms-toggle-icon {
- background: linear-gradient(135deg, #1890ff, #65387a);
- color: #ffffff;
- box-shadow: 0 3px 10px rgba(101, 56, 122, 0.22);
-}
-
-.sms-toggle-title {
- font-size: 12.5px !important;
- font-weight: 700 !important;
- color: #1e293b !important;
- line-height: 1.2 !important;
- letter-spacing: -0.005em;
-}
-
-.sms-toggle-sub {
- font-size: 10.5px !important;
- color: #94a3b8 !important;
- font-weight: 500 !important;
- margin-top: 1px !important;
- line-height: 1.2 !important;
- overflow: hidden;
- text-overflow: ellipsis;
- white-space: nowrap;
-}
-
-.sms-toggle-tile .MuiSwitch-root {
- flex-shrink: 0;
-}
-
-/* ============================================== */
-/* Pickup → Drop Two-Step Stepper */
-/* ============================================== */
-.route-stepper {
- display: flex;
- align-items: stretch;
- gap: 0;
- padding: 4px;
- margin-bottom: 12px;
- background: linear-gradient(135deg, #f8fafc 0%, #f1f5f9 100%);
- border: 1px solid #e2e8f0;
- border-radius: 12px;
-}
-
-.route-step {
- flex: 1;
- display: flex;
- align-items: center;
- gap: 10px;
- padding: 6px 10px;
- border-radius: 9px;
- cursor: pointer;
- transition: background-color 0.22s ease, box-shadow 0.22s ease, transform 0.22s ease;
- user-select: none;
- background: transparent;
- outline: none;
-}
-
-.route-step:hover {
- background: rgba(255, 255, 255, 0.6);
-}
-
-.route-step.is-active {
- background: #ffffff;
- box-shadow: 0 6px 18px -8px rgba(15, 23, 42, 0.12), 0 2px 6px -2px rgba(15, 23, 42, 0.06);
- transform: translateY(-1px);
-}
-
-.route-step.is-locked {
- cursor: not-allowed;
- opacity: 0.6;
-}
-
-.route-step.is-locked:hover {
- background: transparent;
-}
-
-.route-step-index {
- width: 26px;
- height: 26px;
- flex-shrink: 0;
- border-radius: 50%;
- display: inline-flex;
- align-items: center;
- justify-content: center;
- font-weight: 700;
- font-size: 12px;
- color: #94a3b8;
- background: #ffffff;
- border: 1.5px solid #e2e8f0;
- transition: all 0.22s ease;
-}
-
-.step-pickup.is-active .route-step-index {
- background: linear-gradient(135deg, #1890ff, #096dd9);
- border-color: transparent;
- color: #ffffff;
- box-shadow: 0 4px 12px rgba(24, 144, 255, 0.32);
-}
-
-.step-drop.is-active .route-step-index {
- background: linear-gradient(135deg, #a855f7, #65387a);
- border-color: transparent;
- color: #ffffff;
- box-shadow: 0 4px 12px rgba(101, 56, 122, 0.32);
-}
-
-.step-pickup.is-done:not(.is-active) .route-step-index {
- background: rgba(34, 197, 94, 0.12);
- border-color: rgba(34, 197, 94, 0.35);
- color: #16a34a;
-}
-
-.route-step-text {
- display: flex;
- flex-direction: column;
- line-height: 1.2;
-}
-
-.route-step-title {
- font-size: 13px !important;
+.pricing-title {
+ font-size: 14px !important;
font-weight: 700 !important;
color: #1e293b !important;
letter-spacing: -0.01em;
}
-
-.route-step.is-locked .route-step-title {
- color: #94a3b8 !important;
-}
-
-.route-step-sub {
- font-size: 10.5px !important;
+.pricing-subtitle {
+ font-size: 11px !important;
font-weight: 500 !important;
color: #94a3b8 !important;
- margin-top: 1px !important;
+ text-transform: uppercase;
+ letter-spacing: 0.6px;
}
-.route-step-connector {
- flex-shrink: 0;
- display: flex;
- align-items: center;
- justify-content: center;
- padding: 0 6px;
- position: relative;
- min-width: 28px;
-}
-
-.route-step-line {
- width: 100%;
- height: 2px;
- background: #e2e8f0;
- border-radius: 2px;
- transition: background 0.3s ease;
-}
-
-.route-step-connector.is-done .route-step-line {
- background: linear-gradient(90deg, #1890ff, #a855f7);
-}
-
-.route-step-line-arrow {
- position: absolute;
- display: inline-flex;
- align-items: center;
- justify-content: center;
- width: 22px;
- height: 22px;
- border-radius: 50%;
- background: #ffffff;
- border: 1.5px solid #e2e8f0;
- color: #cbd5e1;
- font-size: 10px;
- transition: all 0.3s ease;
-}
-
-.route-step-connector.is-done .route-step-line-arrow {
- border-color: rgba(168, 85, 247, 0.4);
- color: #a855f7;
-}
-
-/* Step navigation footer inside each panel */
-.step-nav {
- margin-top: 12px;
- padding-top: 10px;
- border-top: 1px dashed #e2e8f0;
+/* ---------- Total charge badge ---------- */
+.total-charge-badge {
+ background: linear-gradient(135deg, rgba(24, 144, 255, 0.08) 0%, rgba(101, 56, 122, 0.10) 100%);
+ border: 1px solid rgba(101, 56, 122, 0.18);
+ border-radius: 10px;
+ padding: 10px 14px;
display: flex;
align-items: center;
justify-content: space-between;
- gap: 10px;
- flex-wrap: wrap;
+ gap: 12px;
+ margin-top: 12px;
+}
+.total-charge-left {
+ display: inline-flex;
+ align-items: center;
+ gap: 8px;
+ min-width: 0;
+}
+.total-charge-icon {
+ font-size: 13px;
+ color: #65387A;
+ flex-shrink: 0;
+}
+.total-charge-label {
+ font-size: 11.5px;
+ font-weight: 700;
+ text-transform: uppercase;
+ letter-spacing: 0.6px;
+ color: #65387A;
+}
+.total-charge-val {
+ font-size: 20px;
+ font-weight: 800;
+ color: #65387A;
+ line-height: 1.1;
+ letter-spacing: -0.01em;
+ white-space: nowrap;
}
-.step-nav-hint {
- font-size: 11.5px !important;
- color: #64748b !important;
- font-weight: 500 !important;
-}
-
-.step-nav-btn {
- text-transform: none !important;
- font-weight: 600 !important;
- border-radius: 8px !important;
- padding: 6px 14px !important;
- font-size: 12px !important;
- letter-spacing: 0.01em !important;
- transition: all 0.22s ease !important;
- min-height: 32px !important;
-}
-
-.step-nav-next {
- background: linear-gradient(135deg, #1890ff, #65387a) !important;
+/* ---------- Gradient action button ---------- */
+.gradient-btn-create {
+ background: linear-gradient(135deg, #1890ff 0%, #65387a 100%) !important;
color: #ffffff !important;
- box-shadow: 0 6px 18px -6px rgba(101, 56, 122, 0.35) !important;
+ font-weight: 600 !important;
+ font-size: 13px !important;
+ letter-spacing: 0.01em !important;
+ text-transform: none !important;
+ border-radius: 10px !important;
+ padding: 8px 18px !important;
+ min-height: 38px !important;
+ box-shadow: 0 4px 12px -3px rgba(24, 144, 255, 0.30),
+ 0 2px 4px rgba(101, 56, 122, 0.10) !important;
+ transition: all 0.22s cubic-bezier(0.4, 0, 0.2, 1) !important;
+ border: none !important;
+ display: inline-flex !important;
+ align-items: center !important;
+ justify-content: center !important;
+ gap: 8px !important;
}
-
-.step-nav-next:hover {
- filter: brightness(1.05);
- transform: translateY(-1px);
- box-shadow: 0 10px 22px -8px rgba(101, 56, 122, 0.45) !important;
+.gradient-btn-create .MuiButton-startIcon,
+.gradient-btn-create .MuiButton-endIcon {
+ margin: 0 !important;
}
-
-.step-nav-next.Mui-disabled {
+.gradient-btn-create:hover {
+ filter: brightness(1.04);
+ box-shadow: 0 8px 18px -4px rgba(24, 144, 255, 0.40),
+ 0 3px 8px rgba(101, 56, 122, 0.18) !important;
+}
+.gradient-btn-create:active { filter: brightness(0.98); }
+.gradient-btn-create.Mui-disabled,
+.gradient-btn-create:disabled {
background: #e2e8f0 !important;
color: #94a3b8 !important;
box-shadow: none !important;
+ cursor: not-allowed !important;
}
-.step-nav-back {
+/* ---------- Compact header inputs (Location/Client/Business) ---------- */
+.header-compact-tf .MuiOutlinedInput-root {
+ border-radius: 10px !important;
+ height: 40px !important;
+ padding-left: 10px !important;
+ font-size: 12.5px !important;
+ background: #ffffff;
+}
+.header-compact-tf .MuiOutlinedInput-input {
+ padding-top: 6px !important;
+ padding-bottom: 6px !important;
+ font-size: 12.5px !important;
+}
+.header-compact-tf .MuiInputLabel-root {
+ font-size: 11.5px !important;
+ letter-spacing: 0.02em;
+ font-weight: 600;
+ color: #64748b !important;
+}
+.header-compact-tf .MuiInputLabel-shrink {
+ transform: translate(12px, -7px) scale(0.82) !important;
+ background: #ffffff;
+ padding: 0 4px;
+}
+.header-compact-tf .MuiOutlinedInput-notchedOutline { border-color: #e2e8f0; }
+.header-compact-tf:hover .MuiOutlinedInput-notchedOutline { border-color: #cbd5e1; }
+.header-compact-tf .Mui-focused .MuiOutlinedInput-notchedOutline { border-width: 1.5px !important; }
+
+.header-compact-input .MuiAutocomplete-endAdornment {
+ top: 50%;
+ transform: translateY(-50%);
+ right: 8px;
+ display: inline-flex;
+ align-items: center;
+ height: auto;
+ gap: 2px;
+}
+.header-compact-input .MuiAutocomplete-endAdornment .MuiSvgIcon-root {
+ font-size: 16px;
+ display: block;
+}
+.header-compact-input .MuiAutocomplete-clearIndicator,
+.header-compact-input .MuiAutocomplete-popupIndicator {
+ padding: 3px !important;
+ width: 22px;
+ height: 22px;
+ display: inline-flex;
+ align-items: center;
+ justify-content: center;
+ color: #94a3b8 !important;
+}
+.header-compact-input .MuiAutocomplete-clearIndicator:hover,
+.header-compact-input .MuiAutocomplete-popupIndicator:hover {
+ background: rgba(148, 163, 184, 0.12) !important;
color: #475569 !important;
- background: #f1f5f9 !important;
- border: 1px solid #e2e8f0 !important;
}
-
-.step-nav-back:hover {
- background: #e2e8f0 !important;
- color: #1e293b !important;
+.header-compact-input .MuiAutocomplete-popupIndicator { margin-right: 0; }
+.header-compact-input .MuiOutlinedInput-root {
+ padding-top: 0 !important;
+ padding-bottom: 0 !important;
+ padding-right: 60px !important;
+}
+.header-compact-input .MuiAutocomplete-input {
+ padding: 4px 4px 4px 0 !important;
+ height: auto !important;
}
-
-@media (max-width: 599px) {
- .route-step-sub {
- display: none !important;
- }
- .route-step {
- padding: 8px 10px;
- gap: 8px;
- }
- .route-step-index {
- width: 28px;
- height: 28px;
- font-size: 13px;
- }
- .step-nav {
- flex-direction: column-reverse;
- align-items: stretch;
- }
- .step-nav-btn {
- width: 100%;
- }
-}
\ No newline at end of file
diff --git a/src/pages/nearle/orders/OrdersTableSkeleton.js b/src/pages/nearle/orders/OrdersTableSkeleton.js
index 80bb899..a146695 100644
--- a/src/pages/nearle/orders/OrdersTableSkeleton.js
+++ b/src/pages/nearle/orders/OrdersTableSkeleton.js
@@ -1,3 +1,4 @@
+/* eslint-disable no-unused-vars */
import { TableRow, TableCell, Skeleton, Stack } from '@mui/material';
export const OrdersTableSkeleton = ({ rowsPerPage = 5, col = 1 }) => {
diff --git a/src/pages/nearle/orders/RidersPinPointOSM.js b/src/pages/nearle/orders/RidersPinPointOSM.js
new file mode 100644
index 0000000..3eec0b2
--- /dev/null
+++ b/src/pages/nearle/orders/RidersPinPointOSM.js
@@ -0,0 +1,79 @@
+/* eslint-disable no-unused-vars */
+import { MapContainer, TileLayer, Marker, Popup } from 'react-leaflet';
+import L from 'leaflet';
+import 'leaflet/dist/leaflet.css';
+
+// distance function (same)
+function distance(lat1, lng1, lat2, lng2) {
+ const R = 6371;
+ const dLat = (lat2 - lat1) * (Math.PI / 180);
+ const dLng = (lng2 - lng1) * (Math.PI / 180);
+
+ const a = Math.sin(dLat / 2) ** 2 + Math.cos(lat1 * (Math.PI / 180)) * Math.cos(lat2 * (Math.PI / 180)) * Math.sin(dLng / 2) ** 2;
+
+ return R * 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
+}
+
+const center = [11.015181, 76.953682];
+
+const riders = [
+ { id: 1, lat: 11.04362, lng: 76.924667 },
+ { id: 2, lat: 11.00988, lng: 76.949966 },
+ { id: 3, lat: 11.020983, lng: 76.966331 }
+];
+
+export default function RidersPinPointOSM() {
+ const sortedRiders = riders
+ .map((r) => ({
+ ...r,
+ distance: distance(center[0], center[1], r.lat, r.lng)
+ }))
+ .sort((a, b) => a.distance - b.distance);
+
+ // purple center marker
+ const centerIcon = L.icon({
+ iconUrl: 'https://maps.google.com/mapfiles/ms/icons/purple-dot.png',
+ iconSize: [32, 32]
+ });
+
+ // basic numbered marker icon
+ const createMarkerIcon = (number) =>
+ L.divIcon({
+ className: 'custom-marker',
+ html: `
+
+ ${number}
+
+ `,
+ iconSize: [30, 30],
+ iconAnchor: [15, 15]
+ });
+
+ return (
+
+ {/* OSM tiles */}
+
+
+ {/* Purple center marker */}
+
+
+ {/* Sorted rider markers */}
+ {sortedRiders.map((r, index) => (
+
+ Rider {index + 1}
+
+ ))}
+
+ );
+}
diff --git a/src/pages/nearle/orders/createorder1.js b/src/pages/nearle/orders/createorder1.js
index 0e0e7eb..1407dc5 100644
--- a/src/pages/nearle/orders/createorder1.js
+++ b/src/pages/nearle/orders/createorder1.js
@@ -1,3 +1,4 @@
+/* eslint-disable no-unused-vars */
import * as React from 'react';
import { useEffect, useState, useRef, Fragment } from 'react';
import {
@@ -6,33 +7,42 @@ import {
Grid,
Typography,
Stack,
+ Box,
Button,
TextField,
Autocomplete,
+ CardActions,
Chip,
+ Avatar,
Divider,
DialogTitle,
DialogContent,
Checkbox,
DialogActions,
CircularProgress,
+ ButtonGroup,
+ FormLabel,
IconButton,
+ Drawer,
+ InputLabel,
+ Select,
+ MenuItem,
Switch,
+ CardHeader,
+ Card,
OutlinedInput,
FormGroup,
- FormControlLabel,
- Box,
- Card,
- useMediaQuery
+ FormControlLabel
} 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 { FaPhoneAlt } 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 { MdLocationCity } from 'react-icons/md';
import { TbMapPinCode } from 'react-icons/tb';
import { FaLocationDot } from 'react-icons/fa6';
import axios from 'axios';
@@ -50,124 +60,122 @@ 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 LocationOnIcon from '@mui/icons-material/LocationOn';
+import parse from 'autosuggest-highlight/parse';
+import { debounce } from '@mui/material/utils';
+import CardContent from 'themes/overrides/CardContent';
+import { PhoneAndroid } from '@mui/icons-material';
+import { SearchOutlined, CloseOutlined } 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';
+import { Paper } from '@mui/material';
+import {
+ MdAddShoppingCart,
+ MdMyLocation,
+ MdLocationOn,
+ MdSchedule,
+ MdLocalShipping,
+ MdAttachMoney,
+ MdNotes,
+ MdCheckCircle,
+ MdReceiptLong,
+ MdInventory2,
+ MdStraighten,
+ MdPersonPin,
+ MdPerson,
+ MdHistoryToggleOff
+} from 'react-icons/md';
-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;
+// ============================================================================
+// Design tokens — shared with the rest of the redesigned operator pages.
+// ============================================================================
+const DT = {
+ radiusPill: 999,
+ radiusCard: 16,
+ shadowSoft: '0 14px 40px rgba(15, 23, 42, 0.10)',
+ shadowMd: '0 8px 24px rgba(15, 23, 42, 0.08)',
+ shadowPop: '0 18px 50px rgba(15, 23, 42, 0.18)',
+ textPrimary: '#0f172a',
+ textSecondary: '#64748b',
+ textMuted: '#94a3b8',
+ borderSubtle: '#e2e8f0',
+ divider: '#f1f5f9',
+ surface: '#ffffff',
+ surfaceAlt: '#f8fafc'
};
+const dtA = (c, suffix) => `${c}${suffix}`;
+const tint = (c) => dtA(c, '08');
+const soft = (c) => dtA(c, '18');
+const ring = (c) => dtA(c, '26');
+const edge = (c) => dtA(c, '55');
-const OrderMap = ({ startPoint, endPoint, appLocaLat, appLocaLng }) => {
- const defaultCenter = [
- parseFloat(appLocaLat) || 11.0168,
- parseFloat(appLocaLng) || 76.9558
- ];
+const BRAND = '#C01227';
+const BRAND_LIGHT = '#D25463';
- 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 (
-
-
-
- {hasPick && }
- {hasDrop && }
- {routePoints.length > 0 ? (
-
- ) : (
- hasPick && hasDrop &&
+// Soft card section header — coloured banner above each form section.
+const SectionHeader = ({ color, icon, title, subtitle, action }) => (
+
+
+
+ {icon}
+
+
+ {title}
+ {subtitle && (
+
+ {subtitle}
+
)}
-
-
-
- );
-};
+
+
+ {action}
+
+);
+
+// Section wrapper Paper used as the outer card for each form block.
+const SectionCard = ({ children, sx = {} }) => (
+
+ {children}
+
+);
+
+// Popup paper for Autocomplete dropdowns — matches the rest of the design.
+const SoftPaper = (props) => (
+
+);
function loadScript(src, position, id) {
if (!position) {
@@ -184,96 +192,190 @@ function loadScript(src, position, id) {
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 [value, setValue] = React.useState(null);
+ const [value1, setValue1] = React.useState(null);
+ const [inputValue, setInputValue] = React.useState('');
const [inputValue1, setInputValue1] = React.useState('');
const [inputValue2, setInputValue2] = React.useState('');
+ const [inputValue3, setInputValue3] = React.useState('');
+ const [options, setOptions] = React.useState([]);
+ const [options1, setOptions1] = React.useState([]);
+ const loaded = React.useRef(false);
+ const loaded1 = React.useRef(false);
+ const [mobilenumber, setMobilenumber] = useState('');
+ const [emailaddress, setEmailaddress] = useState('');
+ const [city, setCity] = useState('');
+ const [city1, setCity1] = useState('');
+ const [zipcode, setZipcode] = useState('');
+ const [zipcode1, setZipcode1] = useState('');
+ const [state, setState] = useState('');
+ const [state1, setState1] = useState('');
+ const [suburb, setSuburb] = useState('');
+ const [suburb1, setSuburb1] = useState('');
+ const [pickContactName, setPickContactName] = useState('');
+ const [dropContactName, setDropContactName] = useState('');
+ const [pickdoorno, setPickDoorno] = useState('');
+ const [dropDoorno, setDropDoorno] = useState('');
+ const [pickLandmark, setPickLandmark] = useState('');
+ const [dropLandmark, setDropLandmark] = useState('');
+ const [address, setAddress] = useState('');
+ const [address1, setAddress1] = useState('');
+ const [latlong, setLatlong] = useState({});
+ const [latlong1, setLatlong1] = useState({});
+ const autocompleteService = useRef(null);
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]);
+ const handleOkClick1 = () => {
+ // Set focus back to the text field after clicking the "OK" chip
+ if (textFieldRef1.current) {
+ textFieldRef1.current.focus();
+ }
+ };
+
+ const handleOkClick2 = () => {
+ // Set focus back to the text field after clicking the "OK" chip
+ if (textFieldRef2.current) {
+ textFieldRef2.current.focus();
+ }
+ };
+
+ const top100Films = [
+ { label: 'The Shawshank Redemption', year: 1994 },
+ { label: 'The Godfather', year: 1972 },
+ { label: 'The Godfather: Part II', year: 1974 },
+ { label: 'The Dark Knight', year: 2008 },
+ { label: '12 Angry Men', year: 1957 }
+ ];
+
+ // // // ====================================================== || address (pick)|| ======================================================
+ // useEffect(() => {
+ // if (address) {
+ // try {
+ // Geocode.fromAddress(address).then(
+ // (response) => {
+ // if (response.status == 'OK') {
+ // const { lat, lng } = response.results[0].geometry.location;
+ // console.log({ lat, lng });
+ // setLatlong({
+ // lat,
+ // lng
+ // });
+ // console.log(response);
+ // if (response.results[0].address_components) {
+ // let place = response.results[0];
+ // let cityA, zipcodeA, stateA, suburbA;
+ // for (let i = 0; i < place.address_components.length; i++) {
+ // for (let j = 0; j < place.address_components[i].types.length; j++) {
+ // switch (place.address_components[i].types[j]) {
+ // case 'locality':
+ // cityA = place.address_components[i].long_name;
+ // break;
+ // case 'administrative_area_level_1':
+ // stateA = place.address_components[i].long_name;
+ // break;
+ // case 'postal_code':
+ // zipcodeA = place.address_components[i].long_name;
+ // break;
+ // case 'sublocality':
+ // suburbA = place.address_components[i].long_name;
+ // break;
+ // }
+ // }
+ // }
+ // setCity(cityA || '');
+ // setState(stateA || '');
+ // setZipcode(zipcodeA || '');
+ // setSuburb(suburbA || '');
+ // console.log({ lat, lng, cityA, stateA, zipcodeA, suburbA });
+ // setPickCust({
+ // ...pickCust
+ // // city: cityA,
+ // // state: stateA,
+ // // postcode: zipcodeA,
+ // // suburb: suburbA
+ // // latitude: lat,
+ // // longitude: lng
+ // });
+ // // setStartPoint({ latitude: lat, longitude: lng });
+ // }
+ // }
+ // },
+ // (error) => {
+ // console.log(error);
+ // }
+ // );
+ // } catch (err) {
+ // console.log(err);
+ // }
+ // }
+ // }, [address]);
+ // // // ====================================================== || address 1 (drop)|| ======================================================
+ // useEffect(() => {
+ // if (address) {
+ // try {
+ // Geocode.fromAddress(address1).then(
+ // (response) => {
+ // if (response.status == 'OK') {
+ // const { lat, lng } = response.results[0].geometry.location;
+
+ // setLatlong1({
+ // lat,
+ // lng
+ // });
+ // console.log(response);
+ // if (response.results[0].address_components) {
+ // let place = response.results[0];
+ // let cityB, zipcodeB, stateB, suburbB;
+ // for (let i = 0; i < place.address_components.length; i++) {
+ // for (let j = 0; j < place.address_components[i].types.length; j++) {
+ // switch (place.address_components[i].types[j]) {
+ // case 'locality':
+ // cityB = place.address_components[i].long_name;
+ // break;
+ // case 'administrative_area_level_1':
+ // stateB = place.address_components[i].long_name;
+ // break;
+ // case 'postal_code':
+ // zipcodeB = place.address_components[i].long_name;
+ // break;
+ // case 'sublocality':
+ // suburbB = place.address_components[i].long_name;
+ // break;
+ // }
+ // }
+ // }
+ // setCity(cityB || '');
+ // setState(stateB || '');
+ // setZipcode(zipcodeB || '');
+ // setSuburb(suburbB || '');
+ // console.log({ lat, lng, cityB, stateB, zipcodeB, suburbB });
+ // setDropCust({
+ // ...dropCust
+ // // city: cityB,
+ // // state: stateB,
+ // // postcode: zipcodeB,
+ // // suburb: suburbB
+ // // latitude: lat,
+ // // longitude: lng
+ // });
+ // // setEndPoint({ latitude: lat, longitude: lng });
+ // }
+ // }
+ // },
+ // (error) => {
+ // console.log(error);
+ // }
+ // );
+ // } catch (err) {
+ // console.log(err);
+ // }
+ // }
+ // }, [address1]);
if (typeof window !== 'undefined' && !loaded.current) {
if (!document.querySelector('#google-maps')) {
@@ -286,49 +388,178 @@ const Createorder1 = () => {
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);
- }
- };
+ // const fetch = React.useMemo(
+ // () =>
+ // debounce((request, callback) => {
+ // autocompleteService.current.getPlacePredictions(request, callback);
+ // }, 400),
+ // []
+ // );
+ // const fetch1 = React.useMemo(
+ // () =>
+ // debounce((request, callback) => {
+ // autocompleteService.current.getPlacePredictions(request, callback);
+ // }, 400),
+ // []
+ // );
+
+ // ====================================================== || options (pick)|| ======================================================
+
+ // React.useEffect(() => {
+ // let active = true;
+ // if (!autocompleteService.current && window.google) {
+ // autocompleteService.current = new window.google.maps.places.AutocompleteService();
+ // }
+ // if (!autocompleteService.current) {
+ // return undefined;
+ // }
+ // if (inputValue === '') {
+ // setOptions(value ? [value] : []);
+ // return undefined;
+ // }
+ // fetch({ input: inputValue }, (results) => {
+ // if (active) {
+ // let newOptions = [];
+
+ // if (value) {
+ // newOptions = [value];
+ // }
+
+ // if (results) {
+ // newOptions = [...newOptions, ...results];
+ // }
+
+ // setOptions(newOptions);
+ // }
+ // });
+
+ // return () => {
+ // active = false;
+ // };
+ // }, [value, inputValue, fetch]);
+
+ // // ====================================================== || options1 (drop)|| ======================================================
+ // React.useEffect(() => {
+ // let active = true;
+ // if (!autocompleteService.current && window.google) {
+ // autocompleteService.current = new window.google.maps.places.AutocompleteService();
+ // }
+ // if (!autocompleteService.current) {
+ // return undefined;
+ // }
+ // if (inputValue1 === '') {
+ // setOptions1(value1 ? [value1] : []);
+ // return undefined;
+ // }
+ // fetch1({ input: inputValue1 }, (results) => {
+ // if (active) {
+ // let newOptions = [];
+
+ // if (value1) {
+ // newOptions = [value1];
+ // }
+
+ // if (results) {
+ // newOptions = [...newOptions, ...results];
+ // }
+
+ // setOptions1(newOptions);
+ // }
+ // });
+
+ // return () => {
+ // active = false;
+ // };
+ // }, [value1, inputValue1, fetch1]);
+
+ const appId = localStorage.getItem('applocationid');
+ const navigate = useNavigate();
+ const [open, setOpen] = useState({});
+ const [open1, setOpen1] = useState('');
+ const [open2, setOpen2] = useState(false);
+ const [open3, setOpen3] = useState(false);
+ const [open4, setOpen4] = useState(false);
+ const [shift, setShift] = useState(1);
+ const [clientlist, setClientlist] = useState([]);
+ const [clientdetail, setClientdetail] = useState([]);
+ const [eventname, setEventname] = useState('');
+ const [startdate, setStartdate] = useState(dayjs().format('MM-DD-YYYY'));
+ const [enddate, setEnddate] = useState(dayjs().add(1, 'day').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 [currentsno, setCurrentsno] = useState('');
+ const [roleoptions, setRoleoptions] = useState([]);
+ const theme = useTheme();
+ const [otherinstructions, setOtherinstructions] = useState('');
+ const [attireslist, setAttireslist] = useState([]);
+ const [serviceaddonslist, setServiceaddonslist] = useState([]);
+ const [orderaddonobj, setOrderaddonobj] = useState([]);
+ const [stafflist, setStafflist] = useState([]);
+ const [loading2, setLoading2] = useState(false);
+ const [loading, setLoading] = useState(false);
+ const [btnLoading, setBtnLoading] = useState(false);
+ const [shiftarr, setShiftarr] = useState([]);
+ const [shiftarr1, setShiftarr1] = useState([]);
+ const [orderarr, setOrderarr] = useState([]);
+ const [alertmessage, setAlertmessage] = useState('');
+ const [tabstatus, setTabstatus] = useState('');
+ const [tenantinfo, setTenantinfo] = useState({});
+ const [searchword, setSearchword] = useState('');
+ const [clientdetailarr, setClientdetailarr] = useState([]);
+ const [clientdetailbusinessarr, setClientdetailbusinessarr] = useState([]);
+ const [admintoken, setAdmintoken] = useState();
+ const [tenantlocationlist, setTenantlocationlist] = useState([]);
+ const [tenant, setTenant] = useState({});
+ const [clientinfo, setClientinfo] = useState({});
+ const [selectedtime, setSelectedtime] = useState('');
+ const [tenantlist, setTenantlist] = useState([]);
+ const [tenantid, setTenantid] = useState();
+ const [tenantlocation, setTenantlocation] = useState('');
+ const [pickupswitch, setPickupswitch] = useState(true);
+ const [deliverytype, setDeliverytype] = useState('B');
+ const [dropswitch, setDropswitch] = useState(false);
+ 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();
+ const [weight, setWeight] = useState('');
+ const tid = localStorage.getItem('tenantid');
+ const [selectedCatChip, setSelectedCatChip] = useState(null);
+ const [isCustomerOpen, setIsCustomerOpen] = useState(false);
+ const [searchCustList, setSearchCustList] = useState('');
+ const [customerlist, setCustomerlist] = useState([]);
+ const [pickCust, setPickCust] = useState({});
+ const [dropCust, setDropCust] = useState({});
+ 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 [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);
+
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]);
+ console.log(isSms);
+ }, [isSms]);
const handleChipClick = (chipLabel) => {
setSelectedCatChip(chipLabel);
@@ -344,9 +575,9 @@ const Createorder1 = () => {
}
});
- const fetchTenantPricing = async (id) => {
+ const fetchTenantPricing = async () => {
try {
- const pricingResponse = await axios.get(`${process.env.REACT_APP_URL}/tenants/gettenantpricing/?tenantid=${id}`);
+ const pricingResponse = await axios.get(`${process.env.REACT_APP_URL}/tenants/gettenantpricing/?tenantid=${tid}`);
console.log('pricingResponse', pricingResponse.data.details);
setBasePrice(pricingResponse.data.details.baseprice);
setPricePerKm(pricingResponse.data.details.priceperkm);
@@ -355,6 +586,9 @@ const Createorder1 = () => {
console.log('fetchTenantPricing error', error);
}
};
+ useEffect(() => {
+ fetchTenantPricing();
+ }, []);
useEffect(() => {
console.log('startPoint', startPoint);
@@ -365,7 +599,26 @@ const Createorder1 = () => {
}
}, [startPoint, endPoint]);
- // google distance matrix logic
+ const getDistance = () => {
+ const dist = geolib.getPreciseDistance(startPoint, endPoint, 1);
+ console.log(`Distance: ${dist} meters`);
+ const distanceInKm = (dist / 1000).toFixed(2);
+ const roundedDistance = Math.round(distanceInKm);
+ console.log('roundedDistance', roundedDistance);
+ setDistance(roundedDistance.toFixed(2));
+ if (roundedDistance < minKm) {
+ setTotalCharge(basePrice);
+ } else {
+ const total = (roundedDistance - minKm) * pricePerKm + basePrice;
+ setTotalCharge(total);
+ }
+ setShowDistance(true);
+ if (roundedDistance > appLocaRadius) {
+ setShowDistance(true);
+ setOpen4(true);
+ }
+ };
+
const calculateDistance = async (pickup, drop) => {
try {
const roundedDistance = await calculateDrivingDistance(pickup, drop);
@@ -379,7 +632,7 @@ const Createorder1 = () => {
setShowDistance(true);
if (roundedDistance > appLocaRadius) {
setShowDistance(true);
- setOpen(true);
+ setOpen4(true);
}
// ⏱️ Approximate duration
@@ -391,12 +644,6 @@ const Createorder1 = () => {
}
};
- useEffect(() => {
- if (tenantid) {
- clientdetails();
- }
- }, [searchCustList?.length > 3, searchCustList == '', tenantid]);
-
useEffect(() => {
if (timeslotarr[0]) {
let arr = [];
@@ -405,23 +652,90 @@ const Createorder1 = () => {
arr.push(val);
}
});
+
+ if (arr[0]) {
+ setOrderarr([
+ {
+ sno: 1,
+ address: '',
+ customerid: '',
+ deliverytime: dayjs(arr[0]) || '',
+ deliverylocationid: '',
+ clientname: '',
+ contactno: '',
+ latitude: '',
+ longitude: ''
+ }
+ ]);
+ }
}
}, [timeslotarr]);
+ useEffect(() => {
+ if (searchword) {
+ let arr = clientdetail.filter((val) => {
+ return (
+ val.address.toLowerCase().includes(searchword.toLowerCase()) ||
+ val.firstname.toLowerCase().includes(searchword.toLowerCase()) ||
+ val.contactno.toLowerCase().includes(searchword.toLowerCase())
+ );
+ });
+ console.log(arr);
+ setClientdetailarr([...arr]);
+ } else {
+ setClientdetailarr([...clientdetail]);
+ }
+ }, [searchword]);
+
+ // const { ref: materialRef } = usePlacesWidget({
+ // apiKey: process.env.REACT_APP_GOOGLE_MAPS_API_KEY,
+ // onPlaceSelected: (place) => {
+ // console.log(place);
+
+ // // setAddress(place.formatted_address)
+ // let city1, zipcode1, state1, suburb1;
+ // for (let i = 0; i < place.address_components.length; i++) {
+ // for (let j = 0; j < place.address_components[i].types.length; j++) {
+ // switch (place.address_components[i].types[j]) {
+ // case 'locality':
+ // city1 = place.address_components[i].long_name;
+ // break;
+ // case 'administrative_area_level_1':
+ // state1 = place.address_components[i].long_name;
+ // break;
+ // case 'postal_code':
+ // zipcode1 = place.address_components[i].long_name;
+ // break;
+ // case 'sublocality':
+ // suburb1 = place.address_components[i].long_name;
+ // break;
+ // }
+ // }
+ // }
+ // // setCity(city1 || '')
+ // // setState(state1 || '');
+ // // setZipcode(zipcode1 || '');
+ // // setSuburb(suburb1 || '')
+ // },
+
+ // options: {
+ // types: ['address' || 'geocode']
+ // }
+ // });
+
// ==================================================== || fetchtenantinfo || ====================================================
const fetchtenantinfo = async () => {
setLoading(true);
- console.log('tenantid', tenantid);
+ console.log('tid', tid);
await axios
- .get(`${process.env.REACT_APP_URL}/tenants/gettenantinfo/?tenantid=${tenantid}`)
+ .get(`${process.env.REACT_APP_URL}/tenants/gettenantinfo/?tenantid=${tid}`)
.then((res) => {
console.log('fetchtenantinfo', res);
if (res.data.status) {
setTenant(res.data.details);
-
+ setTenantid(res.data.details.tenantid);
fetchAppAdminTokens();
- setSubCatName(res.data.details.subcategoryname);
setSubCatId(res.data.details.subcategoryid);
}
setLoading(false);
@@ -432,22 +746,22 @@ const Createorder1 = () => {
});
};
useEffect(() => {
- if (tenantid) {
- fetchtenantinfo();
- }
- }, [tenantid]);
- // ==================================================== || getsubcategories || ====================================================
+ fetchtenantinfo();
+ }, []);
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) {
+ if (res.data.status && res.data.details) {
setSubCat(res.data.details);
+ } else {
+ setSubCat([]);
}
})
.catch((err) => {
console.log(err);
+ setSubCat([]);
});
};
useEffect(() => {
@@ -466,7 +780,6 @@ const Createorder1 = () => {
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}`);
@@ -490,10 +803,8 @@ const Createorder1 = () => {
});
};
useEffect(() => {
- if (appId) {
- fetchTiming();
- }
- }, [appId]);
+ fetchTiming();
+ }, []);
// =============================================== || fetchAppAdminTokens (via appId) || ===============================================
const fetchAppAdminTokens = async () => {
@@ -501,7 +812,9 @@ const Createorder1 = () => {
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
+ const userfcmtokemArray = res.data.details.applocationadmins.map((admin) => admin.userfcmtokem);
+ console.log('fetchAppAdminTokens', res);
+ console.log('userfcmtokemArray', userfcmtokemArray);
if (res.data.status) {
setAdmintoken(userfcmtokemArray);
}
@@ -525,11 +838,21 @@ const Createorder1 = () => {
enqueueSnackbar(message, {
variant: variant,
anchorOrigin: { vertical: 'top', horizontal: 'right' },
- autoHideDuration: time ? time : 1500
+ autoHideDuration: time ? time : 2000
});
console.log(alertmessage);
};
+ function closeAddressModal() {
+ setOpen2(false);
+ }
+ function closetimemodal() {
+ setOpen3(false);
+ setCurrentsno('');
+ }
+
+ // =============================================== || createsubmitobj1 (create orders) || ===============================================
+
const createsubmitobj2 = async () => {
let arr = {};
arr = {
@@ -537,7 +860,7 @@ const Createorder1 = () => {
applocationid: tenant.applolcationid,
cancellled: '',
categoryid: +tenant.categoryid,
- configid: 9,
+ configid: 7,
customerid: isNumChange1 == 0 ? +pickCust.customerid || 0 : 0,
deliveryaddress: dropCust.address || '',
deliverycharge: +totalCharge.toFixed(2) || 0,
@@ -551,44 +874,50 @@ const Createorder1 = () => {
deliverylocationid: dropCust.deliverylocationid || 0,
deliverylong: dropCust.longitude.toString(),
deliverytime: `${dayjs(startdate).format('YYYY-MM-DD')} ${dayjs(selectedtime.$d).format('HH:mm:ss')}`,
- deliverytype: 'B',
+ deliverytype: pickCust.customerid !== 0 || dropCust.customerid !== 0 ? 'B' : 'C',
delivered: '',
itemcount: 1,
kms: distance.toString() || 0,
- locationid: +locationid,
+ locationid: +tenanatLocoId, //main or branch
moduleid: +tenant.moduleid,
orderamount: +totalCharge.toFixed(2) || 0,
ordercharges: 0.0,
orderdate: dayjs().format('YYYY-MM-DD HH:mm:ss'),
+ orderheaderid: 0,
+ orderid: '', //
ordernotes: otherinstructions,
orderstatus: 'created',
ordervalue: +totalCharge.toFixed(2) || 0,
partnerid: tenant.partnerid,
- partneruserid: +userid,
paymentstatus: 1,
paymenttype: 42,
+ pending: '',
pickupaddress: pickCust.address || '',
pickupcity: pickCust.city || '',
pickupcontactno: pickCust.contactno || '',
pickupcustomer: pickCust.firstname || '',
pickuplandmark: pickCust.landmark || '',
- pickuplat: pickCust.latitude.toString() || '',
+ pickuplat: pickCust.latitude.toString(),
pickuplocation: pickCust.suburb || '',
pickuplocationid: pickCust.deliverylocationid || 0,
- pickuplong: pickCust.longitude.toString() || '',
+ pickuplong: pickCust.longitude.toString(),
+ processing: '',
+ ready: '',
+ remarks: '',
smsdelivery: isSms,
subcategoryid: +subCatId,
+ taxamount: 0.0,
tenantid: tenant.tenantid,
- collectionamt: +collectionamt,
- quantity: +quantity,
- weight,
- pickupSlot
+ tenantuserid: parseInt(localStorage.getItem('userid')),
+ collectionamt: +collectionamt || 0,
+ quantity: +quantity || 1
},
+
pickup: {
address: pickCust.address || '',
applocationid: tenant.applolcationid,
city: pickCust.city || '',
- configid: 1,
+ configid: 7,
contactno: pickCust.contactno || '',
customertoken: '',
customerid: isNumChange1 == 0 ? pickCust.customerid || 0 : 0,
@@ -601,25 +930,25 @@ const Createorder1 = () => {
landmark: pickCust.landmark || '',
latitude: pickCust.latitude.toString() || '',
longitude: pickCust.longitude.toString() || '',
+ locationid: pickCust.deliverylocationid || 0,
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,
+ configid: 7,
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 || '',
@@ -627,6 +956,7 @@ const Createorder1 = () => {
landmark: dropCust.landmark || '',
latitude: dropCust.latitude.toString(),
longitude: dropCust.longitude.toString(),
+ locationid: dropCust.deliverylocationid || 0,
postcode: dropCust.postcode || '',
primaryaddress: 1,
profileimage: '',
@@ -671,6 +1001,7 @@ const Createorder1 = () => {
} else {
try {
const createRes = await axios.post(`${process.env.REACT_APP_URL2}/orders/createorder`, arr);
+ // const createRes = await axios.post(`${process.env.REACT_APP_URL}/orders/createorder`, arr);
if (createRes.data.status) {
console.log('createRes', createRes);
enqueueSnackbar('Order Created Successfully', {
@@ -679,36 +1010,106 @@ const Createorder1 = () => {
autoHideDuration: 1000
});
if (admintoken) {
- // notifyadmin(admintoken);
- sendnotifications();
+ notifyadmin(admintoken);
+ // sendnotifications();
}
+
navigate('/nearle/orders');
} else {
- opentoast('Error in creating orders', 'warning');
+ opentoast('Something went wrong, Cannot create order', 'warning');
}
setLoading(false);
+ console.log(createRes);
} catch (error) {
- opentoast(error.message, 'warning');
console.log('createResErr', error);
}
}
};
+ useEffect(() => {
+ console.log('shiftarr');
+ console.log(shiftarr);
+ }, [shiftarr]);
+
+ const clicked1 = (e) => {
+ setShift(e);
+ };
+
+ const dialogopen = (i, result) => {
+ console.log(i, result);
+ setOpen({ shiftsno: result.sno, sno: i.sno });
+ };
+ const dialogclose = () => {
+ setOpen('');
+ };
// ========================================================= || 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}`;
+ ? // ? `${process.env.REACT_APP_URL}/customers/getbytid/?tenantid=${tid}&pageno=1&pagesize=1`
+ `${process.env.REACT_APP_URL}/customers/gettenantcustomers/?tenantid=${tid}&pageno=1&pagesize=20`
+ : `${process.env.REACT_APP_URL}/customers/search/?tenantid=${tid}&keyword=${searchCustList}`;
+
await axios
.get(url)
.then((res) => {
+ console.log('clientdetails', res.data.details);
+ if (res.data.status && res.data.details) {
+ setClientdetail(res.data.details || []);
+ setCustomerlist(res.data.details || []);
+ let arr = [];
+ res.data.details.map((val) => {
+ arr.push({
+ label: `${val.firstname} | ${val.contactno}`,
+ ...val
+ });
+ });
+ setClientdetailarr(arr);
+ } else {
+ setClientdetail([]);
+ setCustomerlist([]);
+ setClientdetailarr([]);
+ }
+ setLoading2(false);
+ })
+ .catch((err) => {
+ console.log(err);
+ setLoading2(false);
+ opentoast('server error', 'warning');
+ });
+ } catch (err) {
+ console.log(err);
+ setLoading2(false);
+ }
+ };
+ useEffect(() => {
+ console.log('clientdetails, by search');
+ clientdetails();
+ // clientdetailsbusiness();
+ }, [searchCustList.length > 3, searchCustList == '']);
+ // ========================================================= || clientdetailsbusiness || =========================================================
+ const clientdetailsbusiness = async () => {
+ setLoading2(true);
+ try {
+ await axios
+ .get(`${process.env.REACT_APP_URL}/customers/getbytid/?tenantid=${tid}&locationid=1`)
+ .then((res) => {
+ console.log('clientdetailsbusiness', res.data.details);
if (res.data.status) {
- console.log('clientdetails', res.data.details);
setClientdetail(res.data.details);
- setCustomerlist(res.data.details);
+ // if (!searchword) {
+ // setClientdetailarr(res.data.details)
+ // }
+ let arr = [];
+ res.data.details.map((val) => {
+ arr.push({
+ label: `${val.firstname} | ${val.contactno}`,
+ ...val
+ });
+ });
+ setClientdetailbusinessarr(arr);
}
setLoading2(false);
})
@@ -763,7 +1164,7 @@ const Createorder1 = () => {
// ============================================= || Google Maps Autocomplete(pick) || =============================================
useEffect(() => {
// Initialize Google Maps Autocomplete
- if (inputValue1) {
+ if (inputValue2) {
const autocompleteInput = document.getElementById('addressAuto1');
const autocomplete = new window.google.maps.places.Autocomplete(autocompleteInput, {
// types: ['(cities)'], // You can adjust the types parameter based on your requirements
@@ -775,15 +1176,17 @@ const Createorder1 = () => {
radius: appLocaRadius * 1000
}).getBounds()
});
-
+ let arr = [];
// Event listener for autocomplete place changed
autocomplete.addListener('place_changed', () => {
const place = autocomplete.getPlace();
- setInputValue1(`${place.name}, ${place.formatted_address}`);
+ setInputValue2(`${place.name}, ${place.formatted_address}`);
console.log('new place', place); // Do something with the selected place
console.log(' pick (new place) lat lng', { lat: place.geometry.location.lat(), lng: place.geometry.location.lng() }); // Do something with the selected place
// to trigger getDistance
setStartPoint({ latitude: place.geometry.location.lat(), longitude: place.geometry.location.lng() });
+ setValue(place);
+ setAddress(`${place.name} ${place.formatted_address}`);
setPickCust({ ...pickCust, address: `${place.name} ${place.formatted_address}` });
const address = {
address: `${place.name} ${place.formatted_address}`,
@@ -842,11 +1245,11 @@ const Createorder1 = () => {
console.log('Pick Address:', address);
});
}
- }, [inputValue1]);
+ }, [inputValue2]);
// ============================================= || Google Maps Autocomplete(Drop) || =============================================
useEffect(() => {
- if (inputValue2) {
+ if (inputValue3) {
// Initialize Google Maps Autocomplete
const autocompleteInput = document.getElementById('addressAuto2');
const autocomplete = new window.google.maps.places.Autocomplete(autocompleteInput, {
@@ -863,11 +1266,12 @@ const Createorder1 = () => {
// Event listener for autocomplete place changed
autocomplete.addListener('place_changed', () => {
const place = autocomplete.getPlace();
- setInputValue2(`${place.name}, ${place.formatted_address}`);
+ setInputValue3(`${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() });
-
+ setValue1(place);
+ setAddress1(`${place.name} ${place.formatted_address}`);
setDropCust({ ...dropCust, address: `${place.name} ${place.formatted_address}` });
const address = {
address: `${place.name} ${place.formatted_address}`,
@@ -926,1596 +1330,1529 @@ const Createorder1 = () => {
console.log('Drop Address:', address);
});
}
- }, [inputValue2]);
+ }, [inputValue3]);
// ============================================= || gettenantlocations (branches) || =============================================
- const gettenantlocations = async (id) => {
+ const gettenantlocations = async () => {
try {
- const res = await axios.get(`${process.env.REACT_APP_URL}/tenants/gettenantlocations/?tenantid=${id}`);
+ const res = await axios.get(`${process.env.REACT_APP_URL}/tenants/gettenantlocations/?tenantid=${tid}`);
console.log('gettenantlocations', res.data.details);
- if (res.data.details.length == 1) {
+ if (res.data && res.data.details) {
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);
+ if (res.data.details.length == 1) {
+ setIsLocation(true);
+ setTenanatLocoId(res.data.details[0].locationid);
+ }
} else {
- setTenantlocations(res.data.details);
+ setTenantlocations([]);
}
} catch (err) {
console.log('gettenantlocations', err);
+ setTenantlocations([]);
}
};
+ useEffect(() => {
+ gettenantlocations();
+ }, []);
return (
<>
{loading && }
- {loading2 && }
-
- {/* Header Section — single white card spanning the full row:
- title on the left, service configurators inline on the right. */}
-
-
+
+
-
-
- Create New Order
-
-
-
-
-
- {/* Choose App location */}
-
- `${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) => (
-
-
- {params.InputProps.startAdornment}
- >
- )
- }}
- />
- )}
- />
-
-
- {/* Choose Client */}
-
- {
- 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) => (
-
-
- {params.InputProps.startAdornment}
- >
- )
- }}
- />
- )}
- />
-
-
- {/* Business Location */}
-
- {tenantLocations.length == 1 ? (
-
- )
+
+
+
+ >
+
+
+
+
+ Create Order
+
+
+
+
+ Fill pickup, drop, schedule & pricing details
+
+
+
+
+
+ {tenantLocations.length === 1 ? (
+
+ {tenantLocations[0].locationname}
+
) : (
`${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);
- }
- }}
+ getOptionLabel={(option) =>
+ option && option.locationname ? `${option.locationname} (${option.suburb || ''})` : ''
+ }
+ isOptionEqualToValue={(option, value) => option?.locationid === value?.locationid}
+ PaperComponent={SoftPaper}
+ sx={{ width: { xs: '100%', sm: 300 } }}
+ size="small"
renderInput={(params) => (
-
- {params.InputProps.startAdornment}
- >
+
+
+
+
+
)
}}
- />
- )}
- />
- )}
-
-
-
-
- {/* Workspace 2-Column responsive layout */}
-
-
- {/* Left Column: Form & Configurator (7.5 columns on lg+) */}
-
-
- {/* Card 2: Route Planner (Pickup & Drop) — tighter padding on md+ since
- the two panels now sit side-by-side and need the horizontal room. */}
-
- {/* Two-step stepper: Pickup → Drop */}
-
- setRouteStep(1)}
- role="button"
- tabIndex={0}
- >
-
- {pickupStepComplete && routeStep !== 1 ? : '1'}
-
-
- Pickup
- Where to collect
-
-
-
-
-
-
-
-
-
-
- {
- if (pickupStepComplete) {
- setRouteStep(2);
- } else {
- opentoast('Please complete Pickup details first', 'warning', 2000);
- }
- }}
- role="button"
- tabIndex={0}
- >
- 2
-
- Drop
- Where to deliver
-
-
-
-
-
-
- {/* Pickup Details Block */}
-
-
-
-
-
-
-
- Pickup
- Where to collect the parcel
-
-
-
- }
- 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
-
-
-
-
- {/* Contact group */}
-
- Contact
-
-
-
-
-
-
- ),
- style: { borderRadius: '10px' }
- }}
- variant="outlined"
- label="Contact Name"
- value={pickCust?.firstname || ''}
- onChange={(e) => {
- setPickCust({ ...pickCust, firstname: e.target.value });
- }}
- />
-
-
-
-
-
- ),
- 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);
- }
- }}
- />
-
-
-
- {/* Address Autocomplete */}
-
- Address Lookup
-
- {addId1 == 0 ? (
- setInputValue1(e.target.value)}
- helperText="Start typing to auto-fill the address details below"
- FormHelperTextProps={{ className: 'address-search-helper pickup-helper' }}
- InputProps={{
- startAdornment: (
-
-
-
- ),
- endAdornment: (
- {
- setInputValue1('');
- setPickCust({
- ...pickCust,
- doorno: '',
- suburb: '',
- city: '',
- postcode: '',
- landmark: ''
- });
- setShowDistance(false);
- setStartPoint({ latitude: 0, longitude: 0 });
- }}
- size="small"
- >
-
-
- ),
- style: { borderRadius: '10px', background: '#fff' }
- }}
- />
- ) : (
-
-
-
- ),
- endAdornment: (
- {
- setAddId1(0);
- setPickCust({
- ...pickCust,
- doorno: '',
- suburb: '',
- city: '',
- postcode: '',
- landmark: ''
- });
- setShowDistance(false);
- setStartPoint({ latitude: 0, longitude: 0 });
- }}
- size="small"
- >
-
-
- ),
- 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 */}
-
- Address Details
-
-
-
-
-
-
- ),
- style: { borderRadius: '10px' }
- }}
- variant="outlined"
- label="Door No / Street"
- value={pickCust?.doorno || ''}
- onChange={(e) => {
- setPickCust({ ...pickCust, doorno: e.target.value });
- }}
- />
-
-
-
-
-
- ),
- style: { borderRadius: '10px' }
- }}
- variant="outlined"
- label="Location"
- value={pickCust?.suburb || ''}
- onChange={(e) => {
- setPickCust({ ...pickCust, suburb: e.target.value });
- }}
- />
-
-
-
-
-
- ),
- style: { borderRadius: '10px' }
- }}
- variant="outlined"
- label="Postcode"
- value={pickCust?.postcode || ''}
- onChange={(e) => {
- setPickCust({ ...pickCust, postcode: e.target.value });
- }}
- />
-
-
-
-
-
- ),
- style: { borderRadius: '10px' }
- }}
- variant="outlined"
- label="Landmark"
- value={pickCust?.landmark || ''}
- onChange={(e) => {
- setPickCust({ ...pickCust, landmark: e.target.value });
- }}
- />
-
-
-
- {/* Save for later */}
- {showCheck1 == 1 && (
-
-
- {
- setIsNumChange1(e.target.checked ? 1 : 0);
- }}
- />
- }
- label="Save contact for later"
- />
-
-
- )}
-
- {/* Step navigation */}
-
-
- {pickupStepComplete
- ? 'Pickup looks good. Proceed to Drop details.'
- : 'Fill the required Pickup fields to continue.'}
-
- }
- onClick={() => setRouteStep(2)}
- >
- Continue to Drop
-
-
-
-
- {/* Drop Details Block */}
-
-
-
-
-
-
-
- Drop
- Where to deliver the parcel
-
-
-
- }
- 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
-
-
-
-
- {/* Contact group */}
-
- Contact
-
-
-
-
-
-
- ),
- style: { borderRadius: '10px' }
- }}
- value={dropCust?.firstname || ''}
- onChange={(e) => {
- setDropCust({ ...dropCust, firstname: e.target.value });
- }}
- />
-
-
-
-
-
- ),
- 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);
- }
- }}
- />
-
-
-
- {/* Address Autocomplete */}
-
- Address Lookup
-
- {addId2 == 0 ? (
- setInputValue2(e.target.value)}
- helperText="Start typing to auto-fill the address details below"
- FormHelperTextProps={{ className: 'address-search-helper drop-helper' }}
- InputProps={{
- startAdornment: (
-
-
-
- ),
- endAdornment: (
- {
- setInputValue2('');
- setDropCust({
- ...dropCust,
- doorno: '',
- suburb: '',
- city: '',
- postcode: '',
- landmark: ''
- });
- setShowDistance(false);
- setEndPoint({ latitude: 0, longitude: 0 });
- }}
- size="small"
- >
-
-
- ),
- style: { borderRadius: '10px', background: '#fff' }
- }}
- />
- ) : (
-
-
-
- ),
- endAdornment: (
- {
- setAddId2(0);
- setDropCust({
- ...dropCust,
- doorno: '',
- suburb: '',
- city: '',
- postcode: '',
- landmark: ''
- });
- setShowDistance(false);
- setEndPoint({ latitude: 0, longitude: 0 });
- }}
- size="small"
- >
-
-
- ),
- 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 */}
-
- Address Details
-
-
-
-
-
-
- ),
- style: { borderRadius: '10px' }
- }}
- value={dropCust?.doorno || ''}
- onChange={(e) => {
- setDropCust({ ...dropCust, doorno: e.target.value });
- }}
- />
-
-
-
-
-
- ),
- style: { borderRadius: '10px' }
- }}
- value={dropCust?.suburb || ''}
- onChange={(e) => {
- setDropCust({ ...dropCust, suburb: e.target.value });
- }}
- />
-
-
-
-
-
- ),
- style: { borderRadius: '10px' }
- }}
- value={dropCust?.postcode || ''}
- onChange={(e) => {
- setDropCust({ ...dropCust, postcode: e.target.value });
- }}
- />
-
-
-
-
-
- ),
- style: { borderRadius: '10px' }
- }}
- value={dropCust?.landmark || ''}
- onChange={(e) => {
- setDropCust({ ...dropCust, landmark: e.target.value });
- }}
- />
-
-
-
- {/* Save for later */}
- {showCheck2 == 1 && (
-
-
- {
- setIsNumChange2(e.target.checked ? 1 : 0);
- }}
- />
- }
- label="Save contact for later"
- />
-
-
- )}
-
- {/* Step navigation */}
-
- }
- onClick={() => setRouteStep(1)}
- >
- Back to Pickup
-
-
- Review the route below once Drop is filled.
-
-
-
-
-
-
- {/* Card 3: Cargo & Dispatch Logistics */}
-
-
-
- Cargo & Dispatch Logistics
-
-
-
-
- {/* Section Header: Cargo Details */}
-
-
-
- Cargo Details
-
-
-
-
-
- {/* Row 1: Category, Cash Collect, Quantity */}
-
-
- option?.subcategoryname || ''}
- fullWidth
sx={{
'& .MuiOutlinedInput-root': {
- borderRadius: '12px',
- height: '38px',
- paddingTop: '0px !important',
- paddingBottom: '0px !important'
- }
- }}
- renderInput={(params) => (
-
-
- {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);
+ borderRadius: DT.radiusPill + 'px',
+ bgcolor: '#fff',
+ fontWeight: 600,
+ '& fieldset': { borderColor: edge(BRAND), borderWidth: 1.5 },
+ '&:hover fieldset': { borderColor: BRAND },
+ '&.Mui-focused': { boxShadow: `0 0 0 3px ${ring(BRAND)}` },
+ '&.Mui-focused fieldset': { borderColor: BRAND, borderWidth: 2 }
}
}}
/>
-
-
+ )}
+ onChange={(event, value, reason) => {
+ if (value) {
+ setTenanatLocoId(value.locationid);
+ setIsLocation(true);
+ }
+ if (reason === 'clear') {
+ setIsLocation(false);
+ }
+ }}
+ />
+ )}
+
+
+
-
-
- {
- setCollectionamt(e.target.value);
- }}
- inputProps={{ min: 0 }}
- sx={{ '& .MuiOutlinedInput-root': { borderRadius: '12px', height: '38px' } }}
- InputProps={{
- startAdornment: (
-
- ₹
-
- )
- }}
- />
-
-
+
+
+
+
+
+ {/* ================================================= || Pickup || ================================================= */}
+
+
+ }
+ title="Pickup Details"
+ subtitle="Where the order is picked up"
+ action={
+ }
+ onClick={() => {
+ if (!isLocation) {
+ opentoast('Select Business Location', 'warning');
+ } else {
+ setIsCustomerOpen(true);
+ setpickordrop(1);
+ setPickCust({});
+ setInputValue2('');
+ setSearchCustList('');
+ }
+ }}
+ sx={{
+ borderRadius: 999,
+ px: 1.5,
+ py: 0.375,
+ fontSize: 11.5,
+ fontWeight: 700,
+ textTransform: 'none',
+ borderColor: edge('#0ea5e9'),
+ color: '#0ea5e9',
+ '&:hover': {
+ borderColor: '#0ea5e9',
+ bgcolor: tint('#0ea5e9'),
+ boxShadow: `0 0 0 3px ${ring('#0ea5e9')}`
+ }
+ }}
+ >
+ Saved Locations
+
+ }
+ />
+
+
+
+
+ {/* ====================================== ||Contact Name (pick) || ====================================== */}
+
+
+
+
+ )
+ }}
+ variant="outlined"
+ label="Contact Name"
+ value={pickCust.firstname}
+ onChange={(e) => {
+ setPickCust({ ...pickCust, firstname: e.target.value });
+ }}
+ />
+
+ {/* ====================================== ||Contact Number(pick) || ====================================== */}
+
+
+
+
+ )
+ }}
+ 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);
+ }
+ }}
+ />
+
+ {/* ====================================== || Address (pick) || ====================================== */}
+
+
+ {addId1 == 0 ? (
+
+ setInputValue2(e.target.value)}
+ InputProps={{
+ endAdornment: (
+ {
+ setInputValue2('');
+ setPickCust({
+ ...pickCust,
+ doorno: '',
+ suburb: '',
+ city: '',
+ postcode: '',
+ landmark: ''
+ });
+ setShowDistance(false);
+ setStartPoint({ latitude: 0, longitude: 0 });
+ }}
+ size="small"
+ >
+
+
+ )
+ }}
+ />
+
+ ) : (
+ {
+ setAddId1(0);
+ setPickCust({
+ ...pickCust,
+ // firstname: '',
+ // contactno: '',
+ doorno: '',
+ suburb: '',
+ city: '',
+ postcode: '',
+ landmark: ''
+ });
+ setShowDistance(false);
+ setStartPoint({ latitude: 0, longitude: 0 });
+ }}
+ >
+
+
+ )
+ }}
+ variant="outlined"
+ placeholder="Select"
+ value={pickCust.address}
+ onChange={(e) => {
+ setPickCust({ ...pickCust, address: e.target.value });
+ if (e.target.value == '') {
+ setAddId1(0);
+ setShowDistance(false);
+ setStartPoint({ latitude: 0, longitude: 0 });
+ }
+ }}
+ />
+ )}
+
+
-
-
- {
- setQuantity(e.target.value);
- }}
- inputProps={{ min: 1 }}
- sx={{ '& .MuiOutlinedInput-root': { borderRadius: '12px', height: '38px' } }}
- InputProps={{
- startAdornment: (
-
-
-
- )
- }}
- />
-
-
+ {/* ====================================== ||Door No (pick) || ====================================== */}
+
+
+
+
+ )
+ }}
+ variant="outlined"
+ label="Door No / Street"
+ value={pickCust.doorno}
+ onChange={(e) => {
+ setPickCust({ ...pickCust, doorno: e.target.value });
+ }}
+ />
+
+ {/* ====================================== || Suburb (pick) || ====================================== */}
+
+
+
+
+ )
+ }}
+ variant="outlined"
+ label="Location"
+ value={pickCust.suburb}
+ onChange={(e) => {
+ setPickCust({ ...pickCust, suburb: e.target.value });
+ }}
+ />
+
+ {/* ====================================== || City (pick) || ====================================== */}
+
+
+
+
+ )
+ }}
+ variant="outlined"
+ label="City"
+ value={pickCust.city}
+ onChange={(e) => {
+ setPickCust({ ...pickCust, city: e.target.value });
+ }}
+ />
+
+ {/* ====================================== || postcode (pick) || ====================================== */}
+
+
+
+
+ )
+ }}
+ variant="outlined"
+ label="Postcode"
+ value={pickCust.postcode}
+ onChange={(e) => {
+ setPickCust({ ...pickCust, postcode: e.target.value });
+ }}
+ />
+
+ {/* ====================================== || Landmark (pick) || ====================================== */}
+
+
+
+
+ )
+ }}
+ variant="outlined"
+ label="Landmark"
+ value={pickCust.landmark}
+ onChange={(e) => {
+ setPickCust({ ...pickCust, landmark: e.target.value });
+ }}
+ />
+
+ {/* ====================================== ||Checkbox save for later (pick) || ====================================== */}
+ {showCheck1 == 1 && (
+
+
+ {
+ setIsNumChange1(e.target.checked ? 1 : 0);
+ }}
+ />
+ }
+ label="Save For Later"
+ />
+
+
+ )}
+
+
+
+
+
+
+ {/* ================================================= || Drop || ================================================= */}
+
+
+ }
+ title="Drop Details"
+ subtitle="Where the order is delivered"
+ action={
+ }
+ onClick={() => {
+ if (!isLocation) {
+ opentoast('Select Business Location', 'warning');
+ } else {
+ setIsCustomerOpen(true);
+ setpickordrop(2);
+ setInputValue3('');
+ setSearchCustList('');
+ }
+ }}
+ sx={{
+ borderRadius: 999,
+ px: 1.5,
+ py: 0.375,
+ fontSize: 11.5,
+ fontWeight: 700,
+ textTransform: 'none',
+ borderColor: edge(BRAND),
+ color: BRAND,
+ '&:hover': {
+ borderColor: BRAND,
+ bgcolor: tint(BRAND),
+ boxShadow: `0 0 0 3px ${ring(BRAND)}`
+ }
+ }}
+ >
+ Saved Locations
+
+ }
+ />
+
+
+
+
+
+ Drop Details
+
+
+ {/* Customer */}
+ {/* {
+ if (val) {
+ setDropswitch(true);
+ setClientinfo({});
+ } else {
+ setDropswitch(false);
+ setClientinfo({});
+ }
+ }}
+ size="small"
+ />
+ Business */}
+ {
+ if (!isLocation) {
+ opentoast('Select Business Location', 'warning');
+ } else {
+ setIsCustomerOpen(true);
+ setpickordrop(2);
- {/* Section Header: Handover & Schedule */}
-
-
-
-
- Schedule Details
-
-
-
-
-
- {/* Nested Grid Container with tight spacing to eliminate excessive gaps */}
-
-
- {/* Row 3: Pickup Date & Time Slot (Side-by-Side) */}
-
-
- {
- 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: (
-
-
-
- )
- },
- sx: {
- '& .MuiOutlinedInput-root': {
- borderRadius: '12px',
- height: '38px',
- paddingLeft: '10px'
+ setInputValue3('');
+ setSearchCustList('');
+ }
+ }}
+ >
+ Saved Locations
+
+
+
+ {/* new2 */}
+ {/* `${option.firstname} (${option.contactno})`}
+ sx={{ mt: 0, mb: 1 }}
+ renderInput={(params) => (
+ {
+ setSearchCustList(e.target.value);
+ }}
+ InputProps={{
+ ...params.InputProps,
+ inputProps: {
+ ...params.inputProps,
+ maxLength: 10
+ }
+ }}
+ />
+ )}
+ onChange={(e, val, reason) => {
+ if (val) {
+ if (pickCust.customerid === val.customerid) {
+ opentoast('Select Another Customer', 'error');
+ setSearchCustList('');
+ } else {
+ console.log('DropClient', val);
+ setDropCust(val);
+ setEndPoint({ latitude: val.latitude, longitude: val.longitude });
+ setAddId2(1);
}
}
+ if (reason == 'clear') {
+ setSearchCustList('');
+ }
+ }}
+ noOptionsText={
+ /^[0-9]{10}$/.test(searchCustList) ? (
+
+ {
+ setDropCust({ ...dropCust, contactno: searchCustList });
+ handleOkClick2();
+ setSearchCustList('');
+ }}
+ />
+
+ ) : null
}
- }}
- disablePast
- />
-
-
+ /> */}
+
-
- {
- 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) => (
-
+
+ {/* ====================================== ||Contact Name (drop) || ====================================== */}
+
+
+
+
+ )
+ }}
+ value={dropCust.firstname}
+ onChange={(e) => {
+ setDropCust({ ...dropCust, firstname: e.target.value });
+ }}
+ />
+
+ {/* ====================================== ||Contact Number (drop) || ====================================== */}
+
+
+
+
+ )
+ }}
+ 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);
+ }
+ }}
+ />
+
+
+
+ {addId2 == 0 ? (
+
+ setInputValue3(e.target.value)}
+ InputProps={{
+ endAdornment: (
+ {
+ setInputValue3('');
+ setDropCust({
+ ...dropCust,
+ doorno: '',
+ suburb: '',
+ city: '',
+ postcode: '',
+ landmark: ''
+ });
+ setShowDistance(false);
+ setEndPoint({ latitude: 0, longitude: 0 });
+ }}
+ size="small"
+ >
+
+
+ )
+ }}
+ />
+
+ ) : (
+ {
+ setAddId2(0);
+ setDropCust({
+ ...dropCust,
+ firstname: '',
+ contactno: '',
+ doorno: '',
+ suburb: '',
+ city: '',
+ postcode: '',
+ landmark: ''
+ });
+ setShowDistance(false);
+ setEndPoint({ latitude: 0, longitude: 0 });
+ }}
+ >
+
+
+ )
+ }}
+ variant="outlined"
+ placeholder="Select"
+ value={dropCust.address}
+ onChange={(e) => {
+ setPickCust({ ...dropCust, address: e.target.value });
+ if (e.target.value == '') {
+ setAddId2(0);
+ setShowDistance(false);
+ setEndPoint({ latitude: 0, longitude: 0 });
+ }
+ }}
+ />
+ )}
+
+
+
+ {/* ====================================== ||Door No (drop) || ====================================== */}
+
+
+
+
+ )
+ }}
+ value={dropCust.doorno}
+ onChange={(e) => {
+ setDropCust({ ...dropCust, doorno: e.target.value });
+ }}
+ />
+
+ {/* ====================================== ||Suburb (drop) || ====================================== */}
+
+
+
+
+ )
+ }}
+ value={dropCust.suburb}
+ onChange={(e) => {
+ setDropCust({ ...dropCust, suburb: e.target.value });
+ }}
+ />
+
+ {/* ====================================== ||City (drop) || ====================================== */}
+
+
+
+
+ )
+ }}
+ value={dropCust.city}
+ onChange={(e) => {
+ setDropCust({ ...dropCust, city: e.target.value });
+ }}
+ />
+
+
+ {/* ====================================== ||Postcode (drop) || ====================================== */}
+
+
+
+
+ )
+ }}
+ value={dropCust.postcode}
+ onChange={(e) => {
+ setDropCust({ ...dropCust, postcode: e.target.value });
+ }}
+ />
+
+ {/* ====================================== ||Landmark (drop) || ====================================== */}
+
+
+
+
+ )
+ }}
+ value={dropCust.landmark}
+ onChange={(e) => {
+ setDropCust({ ...dropCust, landmark: e.target.value });
+ }}
+ />
+
+ {/* ====================================== ||Checkbox save for later (drop) || ====================================== */}
+ {showCheck2 == 1 && (
+
+
+ {
+ setIsNumChange2(e.target.checked ? 1 : 0);
+ }}
+ />
+ }
+ label="Save For Later"
+ />
+
+
+ )}
+
+
+ {/*
+
+ Save for Later
+
+ */}
+
+
+
+
+ {/* ================================================= || Time || ================================================= */}
+
+
+ }
+ title="Schedule"
+ subtitle="Pickup date & time slot"
+ />
+
+
+
+ Date
+
+ {
+ let dateres11 = dayjs().diff(dayjs(`${dayjs(e).format('YYYY-MM-DD')}`), 'd');
+ console.log('dateres11');
+ console.log(dateres11);
+ setSelectedtime('');
+ if (dateres11 <= 0) {
+ console.log('startdate', e);
+ setStartdate(e);
+ setEnddate(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);
+ }
+ });
+ if (arr[0]) {
+ setOrderarr([
+ {
+ sno: 1,
+ address: '',
+ customerid: '',
+ deliverytime: dayjs(arr[0]) || '',
+ deliverylocationid: '',
+ clientname: '',
+ contactno: '',
+ latitude: '',
+ longitude: ''
+ }
+ ]);
+ } else {
+ setOrderarr([]);
+ }
+ } else {
+ setAlertmessage('choose Upcoming Date');
+ opentoast('choose Upcoming Date', 'warning');
+ setStartdate(NaN);
+ }
+ }}
+ value={dayjs(startdate)}
+ sx={{ width: '100%', mt: 2 }}
+ disablePast
+ />
+
+
+ Time
+
+
+
+ {timeslotarr.map((val, index) => {
+ if (
+ dayjs().diff(dayjs(`${dayjs(startdate).format('MM-DD-YYYY')} ${dayjs(val).format('HH:mm:ss')}`), 'm') <= 0
+ ) {
+ const active = dayjs(selectedtime).format('HH:mm') == dayjs(val).format('HH:mm');
+ return (
+ {
+ if (distance > appLocaRadius) {
+ setOpen4(true);
+ } else if (showDistance) {
+ setSelectedtime(val);
+ } else {
+ opentoast('Select Pickup and Drop', 'error');
+ }
+ }}
+ sx={{
+ display: 'inline-flex',
+ alignItems: 'center',
+ gap: 0.5,
+ px: 1.25,
+ py: 0.5,
+ cursor: 'pointer',
+ borderRadius: 999,
+ border: `1.5px solid ${active ? '#f59e0b' : edge('#f59e0b')}`,
+ bgcolor: active ? '#f59e0b' : tint('#f59e0b'),
+ color: active ? '#fff' : '#f59e0b',
+ fontSize: 12,
+ fontWeight: 800,
+ transition: 'all 0.15s',
+ boxShadow: active ? `0 6px 18px ${ring('#f59e0b')}` : 'none',
+ '&:hover': {
+ borderColor: '#f59e0b',
+ boxShadow: active ? `0 6px 18px ${ring('#f59e0b')}` : `0 0 0 3px ${ring('#f59e0b')}`
+ }
+ }}
+ >
+ {dayjs(val).format('hh:mm A')}
+
+ );
+ }
+ })}
+
+
+
+
+
+
+
+
+
+ }
+ title="Distance & Pricing"
+ subtitle="Auto-calculated from pickup → drop"
+ />
+
+ {showDistance && (
+
+
+
+
+
+
+
+
+ )}
+
+ Category
+ `${option.subcategoryname}` || ''}
+ sx={{ my: 2, zIndex: '100' }}
fullWidth
- InputLabelProps={{ shrink: true }}
- sx={{ '& .MuiOutlinedInput-root': { borderRadius: '12px', height: '38px' } }}
- InputProps={{
- ...params.InputProps,
- startAdornment: (
- <>
-
- {params.InputProps.startAdornment}
- >
- )
+ renderInput={(params) => }
+ onChange={(event, value, reason) => {
+ if (value) {
+ console.log(value);
+ setSubCatName(value.subcategoryname);
+ setSubCatId(value.subcategoryid);
+ }
}}
/>
- )}
- />
-
-
+
+ Weight
+
+ {
+ handleChipClick('1-10kgs');
+ setWeight('1-10kgs');
+ }}
+ />
+ {
+ handleChipClick('11-20kgs');
+ setWeight('11-20kgs');
+ }}
+ />
+ {
+ handleChipClick('21-30kgs');
+ setWeight('21-30kgs');
+ }}
+ />
+
+
+ SMS Delivery
+ {
+ setIsSms(e.target.checked ? 1 : 0);
+ }}
+ />
+
+
+
-
-
+
- {/* Right Column: Live Map & Cost Summary Panel (4.5 columns on lg+, sticky) */}
-
+ }
+ title="Collection & Quantity"
+ subtitle="Cash to collect on delivery, total items"
+ />
+
+
+
+ setCollectionamt(e.target.value)}
+ inputProps={{ min: 0 }}
+ />
+
+
+ setQuantity(e.target.value)}
+ inputProps={{ min: 1 }}
+ />
+
+
+
+
+
+ {/* ================================================= || Notes || ================================================= */}
+
+ }
+ title="Notes"
+ subtitle="Add anything the rider should know"
+ />
+
+ setOtherinstructions(e.target.value)}
+ />
+
+
+ {!showDistance && (
+
+ Set pickup & drop to enable
+
+ )}
+ }
+ onClick={() => {
+ setLoading(true);
+ setBtnLoading(true);
+ createsubmitobj2();
+ setTimeout(() => {
+ setLoading(false);
+ setBtnLoading(false);
+ }, 1000);
+ }}
+ sx={{
+ borderRadius: 999,
+ px: 3,
+ py: 1,
+ fontWeight: 800,
+ textTransform: 'none',
+ fontSize: 13,
+ background: `linear-gradient(135deg, ${BRAND} 0%, ${BRAND_LIGHT} 100%)`,
+ color: '#fff',
+ boxShadow: `0 8px 22px ${ring(BRAND)}`,
+ transition: 'all 0.18s',
+ '&:hover': {
+ background: `linear-gradient(135deg, #4D1C61 0%, ${BRAND} 100%)`,
+ transform: 'translateY(-1px)',
+ boxShadow: `0 10px 26px ${ring(BRAND)}`
+ },
+ '&.Mui-disabled': {
+ background: DT.divider,
+ color: DT.textMuted,
+ boxShadow: 'none'
+ }
+ }}
+ >
+ {btnLoading ? : 'Create Order'}
+
+
+
+
+
+
+
+ {/*
+
+
+ Select Time
+
+
+
+
+
+ {timeslotarr.map((val) => {
+ if (
+ dayjs().diff(dayjs(`${dayjs(startdate).format('MM-DD-YYYY')} ${dayjs(val).format('HH:mm:ss')}`), 'm') <= 0
+ // && currentsno
+ ) {
+ return (
+ <>
+
+ {
+ setSelectedtime(dayjs(val).format('hh:mm A'));
+ }}
+ />
+
+ >
+ );
+ }
+ })}
+
+
+
+
+ {
+ closetimemodal();
+ }}
+ >
+ Cancel
+
+
+ OK
+
+
+ */}
+
+ {/* ============================================= || saved address Dialog || ============================================= */}
+
setIsCustomerOpen(false)}
+ fullWidth
+ maxWidth="sm"
+ PaperProps={{ sx: { borderRadius: 3 } }}
+ >
+
-
-
- {/* Map Card */}
-
-
-
- Live Route Preview
+
+
+
+
+
+
+ Saved Locations
-
-
-
-
-
- {/* Delivery Preferences — Dispatch Notes & SMS Updates */}
-
-
- Delivery Preferences
- Customer notifications & dispatch instructions
-
-
-
-
-
-
- Special Dispatch Notes
-
- 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'
- }
- }}
- />
-
-
- setIsSms(isSms === 1 ? 0 : 1)}
- role="button"
- tabIndex={0}
- >
-
-
-
-
-
- SMS Updates
- Auto-notify customer on dispatch & delivery
-
-
- {
- e.stopPropagation();
- setIsSms(e.target.checked ? 1 : 0);
- }}
- />
-
-
-
-
- {/* Pricing breakdown card */}
-
-
- Pricing & Dispatch
- Live cost estimate
-
-
-
-
-
-
-
- Delivery Distance
-
-
- {showDistance ? `${distance} km` : '—'}
-
-
-
-
-
-
-
-
-
- Base Fare
- · {minKm} km
-
-
-
- {basePrice ? `₹${basePrice.toFixed(2)}` : '₹0.00'}
-
-
-
-
-
-
-
-
- Rate per km
-
-
- {pricePerKm ? `₹${pricePerKm.toFixed(2)}` : '₹0.00'}
- /km
-
-
-
- {/* Total Cost Display */}
- {showDistance && (
-
-
-
-
Total Delivery Charge
-
-
₹{totalCharge.toFixed(2)}
-
- )}
-
- {/* Submit button */}
-
-
- }
- onClick={() => {
- setLoading(true);
- setBtnLoading(true);
- createsubmitobj2();
- setTimeout(() => {
- setLoading(false);
- setBtnLoading(false);
- }, 2000);
- }}
- >
- {btnLoading ? (
-
- ) : (
- 'Dispatch Delivery Order'
- )}
-
-
-
-
+
+ Pick a saved customer for {pickordrop === 1 ? 'Pickup' : 'Drop'}
+
+
-
-
-
-
- {/* Saved address Dialog (Modal) */}
- {
- setIsCustomerOpen(false);
- setSearchCustList('');
- }}
- fullWidth
- fullScreen={isMobile}
- sx={{
- '& .MuiDialog-paper': {
- borderRadius: { xs: 0, sm: '16px' },
- overflow: 'hidden'
- }
- }}
- >
-
-
-
- {`Select Saved Address (${pickordrop === 1 ? 'Pickup' : 'Drop'})`}
-
-
-
+
+
-
-
-
-
-
-
- {customerlist?.length == 0 ? (
-
-
-
- ) : (
-
- {customerlist &&
- customerlist.map((address, index) => (
- {
- 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}
- >
-
-
- {`${address.firstname} (${address.contactno})`}
-
-
- {address.address}
-
-
-
- ))}
- )}
-
+
+
+ {customerlist.length === 0 ? (
+
+
+
+
+
+ No saved locations
+
+
+ {searchCustList ? 'Try a different keyword.' : 'Save a customer from the order form to reuse it later.'}
+
+
+ ) : (
+
+ {customerlist.map((address, index) => {
+ const isUsed = pickCust.customerid === address.customerid;
+ return (
+ {
+ if (isUsed) return;
+ setIsCustomerOpen(false);
+ if (pickordrop === 1) {
+ setAddId1(1);
+ setStartPoint({ latitude: address.latitude, longitude: address.longitude });
+ setPickCust(address);
+ setPickNum(address.contactno);
+ } else {
+ setAddId2(1);
+ setEndPoint({ latitude: address.latitude, longitude: address.longitude });
+ setDropCust(address);
+ setdropNum(address.contactno);
+ }
+ }}
+ sx={{
+ display: 'flex',
+ alignItems: 'flex-start',
+ gap: 1.25,
+ p: 1.5,
+ borderRadius: 2,
+ border: '1px solid',
+ borderColor: isUsed ? edge('#94a3b8') : DT.borderSubtle,
+ bgcolor: isUsed ? DT.surfaceAlt : '#fff',
+ cursor: isUsed ? 'not-allowed' : 'pointer',
+ opacity: isUsed ? 0.6 : 1,
+ transition: 'all 0.15s',
+ '&:hover': isUsed
+ ? {}
+ : {
+ borderColor: edge(BRAND),
+ bgcolor: tint(BRAND),
+ boxShadow: DT.shadowSoft
+ }
+ }}
+ >
+
+ {String(address.firstname || '?').charAt(0).toUpperCase()}
+
+
+
+
+ {address.firstname}
+
+
+ {address.contactno}
+
+ {isUsed && (
+
+ Already used
+
+ )}
+
+
+ {address.address}
+
+
+
+ );
+ })}
+
+ )}
+
+
+ setIsCustomerOpen(false)}
+ sx={{
+ borderRadius: 999,
+ px: 2.5,
+ borderColor: DT.borderSubtle,
+ color: DT.textSecondary,
+ fontWeight: 700,
+ textTransform: 'none',
+ '&:hover': { borderColor: DT.textSecondary, bgcolor: DT.surfaceAlt }
+ }}
+ >
+ Cancel
+
+
+
-
-
-
- setOpen4(false)} PaperProps={{ sx: { borderRadius: 3 } }}>
+ {
- setIsCustomerOpen(false);
- setSearchCustList('');
+ p: 2.5,
+ background: `linear-gradient(135deg, ${tint('#ef4444')} 0%, ${tint('#f59e0b')} 100%)`,
+ borderBottom: `1px solid ${DT.borderSubtle}`
}}
>
- Cancel
-
-
-
-
- {/* Location error Dialog */}
-
{
- 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'
- }
- }}
- >
-
-
-
- Dispatch Blocked
-
-
-
-
-
- Our delivery partners cannot service this coordinate combination. The route distance exceeds the active operating radius for this app location.
-
-
-
- {
- setOpen(false);
- }}
- >
- Acknowledge & Close
-
-
+
+
+
+
+
+
+ Out of Service Area
+
+
+ This drop point is outside the supported radius
+
+
+
+
+
+
+ Service is not available at this location. Try a different drop point within the coverage zone.
+
+
+
+ setOpen4(false)}
+ sx={{
+ borderRadius: 999,
+ px: 3,
+ bgcolor: '#ef4444',
+ fontWeight: 700,
+ textTransform: 'none',
+ boxShadow: `0 6px 18px ${ring('#ef4444')}`,
+ '&:hover': { bgcolor: '#dc2626' }
+ }}
+ >
+ Close
+
+
+
+
>
);
};
diff --git a/src/pages/nearle/orders/details.js b/src/pages/nearle/orders/details.js
index f52c6ed..97a4732 100644
--- a/src/pages/nearle/orders/details.js
+++ b/src/pages/nearle/orders/details.js
@@ -1,8 +1,7 @@
+/* eslint-disable no-unused-vars */
import {
- useEffect,
- useState,
- Fragment
- // useReducer
+ useEffect, useState, Fragment
+ // useReducer
} from 'react';
import BorderColorIcon from '@mui/icons-material/BorderColor';
import {
@@ -17,20 +16,21 @@ import {
// UserOutlined,
EnvironmentOutlined,
EditTwoTone
- // DeleteTwoTone
+ // DeleteTwoTone
} from '@ant-design/icons';
// import WomanIcon from '@mui/icons-material/Woman';
// import { Link } from 'react-router-dom';
// import SoupKitchenIcon from '@mui/icons-material/SoupKitchen';
import DirectionsCarIcon from '@mui/icons-material/DirectionsCar';
-import { KeyboardArrowUp, KeyboardArrowDown } from '@mui/icons-material';
+import SendIcon from '@mui/icons-material/Send';
+import { KeyboardArrowUp, KeyboardArrowDown } from '@mui/icons-material'
// import { PopupTransition } from 'components/@extended/Transitions';
// import { useDispatch } from 'react-redux';
// import { openSnackbar } from 'store/reducers/snackbar';
// assets
import { DeleteFilled, NotificationOutlined } from '@ant-design/icons';
-var utc = require('dayjs/plugin/utc');
+var utc = require('dayjs/plugin/utc')
// import { groupBy } from "core-js/actual/array/group-by";
// import "lodash.chunk";
// var chunk = require('lodash.chunk');
@@ -81,15 +81,13 @@ import MainCard from 'components/MainCard';
import Loader from 'components/Loader';
// import AlertCustomerDelete from 'sections/apps/customer/AlertCustomerDelete';
import dayjs from 'dayjs';
-dayjs.extend(utc);
+dayjs.extend(utc)
// import { Link as RouterLink } from 'react-router-dom';
// import PlayCircleFilled from '@mui/icons-material/PlayCircleFilled';
// import SmileFilled from '@mui/icons-material/Mood';
// import HeartFilled from '@mui/icons-material/Favorite';
import { useTheme } from '@mui/material/styles';
-import useMediaQuery from '@mui/material/useMediaQuery';
-import { MobileCard, MobileCardList, MobileField, MobileFieldGrid } from 'components/nearle_components/MobileCard';
import {
CloseOutlined,
WarningOutlined,
@@ -100,6 +98,91 @@ import {
// DeleteTwoTone
} from '@ant-design/icons';
import { enqueueSnackbar } from 'notistack';
+import {
+ MdLocalShipping,
+ MdHourglassEmpty,
+ MdCheckCircle,
+ MdCancel,
+ MdAccessTime,
+ MdHistoryToggleOff,
+ MdAssignmentTurnedIn,
+ MdEdit,
+ MdArrowBack,
+ MdReceiptLong
+} from 'react-icons/md';
+import { Paper, Box } from '@mui/material';
+
+// ============================================================================
+// Design tokens — shared with the rest of the redesigned operator pages.
+// ============================================================================
+const DT = {
+ radiusPill: 999,
+ radiusCard: 16,
+ shadowSoft: '0 14px 40px rgba(15, 23, 42, 0.10)',
+ shadowMd: '0 8px 24px rgba(15, 23, 42, 0.08)',
+ shadowPop: '0 18px 50px rgba(15, 23, 42, 0.18)',
+ textPrimary: '#0f172a',
+ textSecondary: '#64748b',
+ textMuted: '#94a3b8',
+ borderSubtle: '#e2e8f0',
+ divider: '#f1f5f9',
+ surface: '#ffffff',
+ surfaceAlt: '#f8fafc'
+};
+const dtA = (c, suffix) => `${c}${suffix}`;
+const tint = (c) => dtA(c, '08');
+const soft = (c) => dtA(c, '18');
+const ring = (c) => dtA(c, '26');
+const edge = (c) => dtA(c, '55');
+
+const BRAND = '#C01227';
+const BRAND_LIGHT = '#D25463';
+
+// Semantic per-status palette — also drives StatusBadge.
+const STATUS_META = {
+ pending: { label: 'Pending', color: '#f59e0b', icon: MdHourglassEmpty },
+ assigned: { label: 'Assigned', color: '#0ea5e9', icon: MdAssignmentTurnedIn },
+ confirmed: { label: 'Confirmed', color: '#10b981', icon: MdCheckCircle },
+ modified: { label: 'Modified', color: '#06b6d4', icon: MdHistoryToggleOff },
+ processing: { label: 'Processing', color: BRAND, icon: MdAccessTime },
+ active: { label: 'Active', color: '#8b5cf6', icon: MdLocalShipping },
+ closed: { label: 'Closed', color: '#06b6d4', icon: MdCheckCircle },
+ completed: { label: 'Completed', color: '#10b981', icon: MdCheckCircle },
+ cancelled: { label: 'Cancelled', color: '#ef4444', icon: MdCancel }
+};
+
+const StatusBadge = ({ status, size = 'md' }) => {
+ if (!status) return null;
+ const meta = STATUS_META[String(status).toLowerCase()] || {
+ label: status,
+ color: DT.textMuted,
+ icon: MdHistoryToggleOff
+ };
+ const Icon = meta.icon;
+ const px = size === 'lg' ? 1.25 : 1;
+ const py = size === 'lg' ? 0.5 : 0.375;
+ const fs = size === 'lg' ? 12 : 11;
+ return (
+
+ {meta.label}
+
+ );
+};
const Details = () => {
// const [searchParams] = useSearchParams();
@@ -116,7 +199,7 @@ const Details = () => {
const [tenantaddress, setTenantaddress] = useState('');
const [dialogopen, setDialogopen] = useState(false);
const [orderstatus, setOrderstatus] = useState('');
- const [currentrole] = useState('');
+ const [currentrole, setCurrentrole] = useState('');
const [taxamount, setTaxamount] = useState('');
const [subtotal, setSubtotal] = useState('');
const [grandtotal, setGrandtotal] = useState('');
@@ -128,12 +211,14 @@ const Details = () => {
const [staffarr, setStaffarr] = useState([]);
const [orderheaderid, setOrderheaderid] = useState('');
const [tenantid, setTenantid] = useState('');
- const [starttime] = useState('');
- const [endtime] = useState('');
+ const [starttime, setStarttime] = useState('');
+ const [endtime, setEndtime] = useState('');
// const [orderstatus,setOrderstatus]=useStatus('');
const [pendingtime, setPendingtime] = useState('');
// const [processdate,setProcessdate]=useState('');
- const [categoryarr, setcategoryarr] = useState([]);
+ const [orderdetailid, setOrderdetailid] = useState('');
+ const [productid, setProductid] = useState('');
+ const [categoryarr, setcategoryarr] = useState([])
const [currentshiftobj, setCurrentshiftobj] = useState({
shifts: 0,
assigned: 0,
@@ -141,22 +226,22 @@ const Details = () => {
shiftid: 0,
price: 0
});
- const [tabstatus, setTabstatus] = useState(0);
+ const [tabstatus, setTabstatus] = useState(0)
const { state } = useLocation();
const [assignedpendingcount, setAssignedpendingcount] = useState('');
// const [, forceUpdate] = useReducer(x => x + 1, 0);
// const dispatch = useDispatch();
const navigate = useNavigate();
const [expandopen, setExpandopen] = useState(['', '']);
- const [startdate, setStartdate] = useState('');
- const [invoiceeligible, setInvoiceeligible] = useState(false);
+ const [startdate, setStartdate] = useState('')
+ const [invoiceeligible, setInvoiceeligible] = useState(false)
useEffect(() => {
- console.log('categoryarr');
+ console.log("categoryarr")
console.log(orderarr, eventlocation, venuetype, starttime, endtime);
// forceUpdate();
- }, [categoryarr]);
+ }, [categoryarr])
// const navigate = useNavigate();
useEffect(() => {
@@ -164,22 +249,23 @@ const Details = () => {
setOrderheaderid(state.orderheaderid);
setTenantid(state.tenantid);
}
- console.log(state);
+ console.log(state)
// fetchroleslist(1)
- console.log(Date.now());
- }, []);
+ console.log(Date.now())
+ }, [])
useEffect(() => {
if (state) {
- setOrderheaderid(state.orderheaderid);
- setTenantid(state.tenantid);
+ setOrderheaderid(state.orderheaderid );
+ setTenantid(state.tenantid );
}
- console.log(state);
+ console.log(state)
// fetchroleslist(1)
- console.log(Date.now());
- }, [state.orderheaderid, state.tenantid]);
+ console.log(Date.now())
+ }, [
+ state.orderheaderid, state.tenantid
+ ])
const theme = useTheme();
- const isMobile = useMediaQuery(theme.breakpoints.down('md'));
// const fetchorderdetails = async () => {
// setLoading(true);
@@ -205,40 +291,47 @@ const Details = () => {
.then((res) => {
console.log(res);
- let result = res.data.Details.find((res1) => res1.orderheaderid == orderheaderid);
+ let result = res.data.Details.find((res1) => res1.orderheaderid == orderheaderid)
// orderheaderid
- console.log('result');
+ console.log("result")
- console.log(result);
+ console.log(result)
setOrderaddons(result.orderaddons);
- setVenuetype(result.venuetype);
- setOtherinstructions(result.remarks);
- setStartdate(result.startdate);
+ setVenuetype(result.venuetype)
+ setOtherinstructions(result.remarks)
+ setStartdate(result.startdate)
+
+
setClientname(result.tenantname);
setEventlocation('');
setTenantaddress(result.tenantaddress);
setEventname(result.eventname);
+
+
setOrderdate(dayjs(result.orderdate).format('MM/DD/YYYY') || '');
setOrderid(result.orderid);
setOrderstatus(result.orderstatus);
setTaxamount(result.taxamount);
- setSubtotal(result.orderamount);
+ setSubtotal(result.orderamount)
setGrandtotal(result.ordervalue);
setCancelleddate(dayjs(result.cancelled).format('MM/DD/YYYY') || '');
// if (result.orderstatus === 'pending') {
- setPendingtime(result.pending);
+ setPendingtime(result.pending)
// }
+
setLoading(false);
})
.catch((err) => {
console.log(err);
setLoading(false);
});
- };
+ }
+
+
const fetchorderattires = async () => {
setLoading(true);
@@ -265,7 +358,7 @@ const Details = () => {
// setcategoryarr(result);
console.log('categoryarr');
- setcategoryarr(res.data.Details);
+ setcategoryarr(res.data.Details)
console.log(res.data.Details);
setLoading(false);
@@ -274,52 +367,94 @@ const Details = () => {
console.log(err);
setLoading(false);
});
- };
+ }
+ const fetchroleslist = async (cid, starttime1, endtime1, hid, sid) => {
+ let fromdate = dayjs(starttime1).subtract(59, 'minutes')
+ .format('YYYY-MM-DD HH:mm:ss');
+ // let todate = dayjs(endtime1).utc().format('YYYY-MM-DD HH:mm:ss');
+ // let fromdate = dayjs(starttime1).utc().format('YYYY-MM-DD HH:mm:ss');
+ let todate = dayjs(endtime1)
+ .format('YYYY-MM-DD HH:mm:ss');
+ let url1;
+ if (starttime1) {
+ url1 = `${process.env.REACT_APP_URL2}/staffs/pools/getstaffs/?categoryid=${cid}&headerid=${hid}&shiftid=${sid}&starttime=${fromdate}&endtime=${todate}`;
+ } else {
+ url1 = `${process.env.REACT_APP_URL2}/staffs/pools/getstaffs/?categoryid=${cid}&headerid=${hid}&shiftid=${sid}`
+ }
+ setLoading(true);
+ setStafflist([])
+ await axios
+ // .get(`${process.env.REACT_APP_URL2}/staffs/pools/getstaffs/?categoryid=${cid}&headerid=${hid}&starttime=${fromdate}&endtime=${todate}`)
+ .get(url1)
+ .then((res) => {
+ console.log('rolelist');
+ console.log(res);
+ // console.log(fromdate, todate)
+ // console.log(dayjs(starttime1).format('YYYY-MM-DD HH:mm:ss'))
+ // console.log(dayjs(endtime1).format('HH:mm:ss'))
+
+
+ setStafflist(res.data.Details || [])
+ // let result = res.data.Details.find((res1) => res1.orderheaderid == searchParams.get('id'))
+ // orderheaderid
+ // console.log(result)
+ // setOrderaddons(result.orderaddons);
+ // setVenuetype(result.venuetype)
+ // setOtherinstructions(result.remarks)
+ setLoading(false);
+ })
+ .catch((err) => {
+ console.log(err);
+ setLoading(false);
+ });
+ }
const fetchstafflist = async (odid) => {
- setLoading(true);
+ setLoading(true)
try {
// await axios.get(`${process.env.REACT_APP_URL}/orders/orderanalytics?orderdate=${chosendate}`)
- await axios
- .get(`${process.env.REACT_APP_URL2}/orders/getassignedinfo?orderdetailid=${odid}`)
+ await axios.get(`${process.env.REACT_APP_URL2}/orders/getassignedinfo?orderdetailid=${odid}`)
.then((res) => {
- console.log(res);
+ console.log(res)
if (res.data.status) {
- setStafflist(res.data.Details);
+ setStafflist(res.data.Details)
}
- setLoading(false);
+ setLoading(false)
+ }).catch((err) => {
+ console.log(err)
+ setLoading(false)
})
- .catch((err) => {
- console.log(err);
- setLoading(false);
- });
+
} catch (err) {
console.log(err);
- setLoading(false);
+ setLoading(false)
}
- };
+
+ }
const cancelorder = async () => {
- await axios
- .put(`${process.env.REACT_APP_URL2}/orders/cancel`, {
- // "Orderheaderid": parseInt(orderheaderid),
- // "Tenantid": parseInt(tenantid),
- // "Orderstatus": "cancelled",
- // "Currentdatetime": dayjs().format('YYYY-MM-DD HH:mm:ss'),
- // "Cod": false,
- // "Remarks": "",
- orderheaderid: parseInt(orderheaderid),
- // "orderdetailid":78,
- // "shiftid":788,
- orderstatus: 'cancelled',
- cancelled: dayjs().format('YYYY-MM-DD HH:mm:ss'),
- unserviceable: invoiceeligible ? 0 : 1
- })
+
+ await axios.put(`${process.env.REACT_APP_URL2}/orders/cancel`, {
+
+ // "Orderheaderid": parseInt(orderheaderid),
+ // "Tenantid": parseInt(tenantid),
+ // "Orderstatus": "cancelled",
+ // "Currentdatetime": dayjs().format('YYYY-MM-DD HH:mm:ss'),
+ // "Cod": false,
+ // "Remarks": "",
+ "orderheaderid": parseInt(orderheaderid),
+ // "orderdetailid":78,
+ // "shiftid":788,
+ "orderstatus": "cancelled",
+ "cancelled": dayjs().format('YYYY-MM-DD HH:mm:ss'),
+ "unserviceable": (invoiceeligible) ? 0 : 1,
+
+ })
.then((res) => {
- console.log(res);
+ console.log(res)
if (res.data.status) {
if (orderheaderid && tenantid) {
// fetchorderdetails();
@@ -327,114 +462,121 @@ const Details = () => {
fetchorderattires();
}
}
+
+ }).catch((err) => {
+ console.log(err)
})
- .catch((err) => {
- console.log(err);
- });
- };
+
+ }
const unassign = async (val) => {
+
let obj = {
orderheaderid: orderheaderid,
orderprocessid: val.orderprocessid,
orderdetailid: val.orderdetailid,
- orderstatus: 'pending',
+ orderstatus: "pending",
pending: dayjs().format('YYYY-MM-DD HH:mm:ss'),
// processing:0,
// cancelled:0,
// completed:0,
// accepted:0,
status: 1
- };
- console.log(obj);
+ }
+ console.log(obj)
- await axios
- .put(`${process.env.REACT_APP_URL2}/orders/updateprocessstatus`, obj)
+ await axios.put(`${process.env.REACT_APP_URL2}/orders/updateprocessstatus`, obj)
.then((res) => {
- console.log(res);
- if (res.data.message === 'Successful') {
+ console.log(res)
+ if (res.data.message === "Successful") {
// if (orderheaderid && tenantid) {
enqueueSnackbar('Role unassigned successfully', {
- variant: 'success',
- anchorOrigin: { vertical: 'top', horizontal: 'right' },
+ variant: 'success', anchorOrigin: { vertical: 'top', horizontal: 'right' },
autoHideDuration: 2000
- });
+ })
if (currentshiftobj.assigned > currentshiftobj.shifts) {
- sendunassignnotification(val);
+ sendunassignnotification(val)
}
+
+
fetchorderaddons();
fetchorderattires();
setOpen(false);
fetchassignedcount();
- dialogclose();
+ dialogclose()
setTimeout(() => {
fetchassignedcount();
- }, 2000);
+
+ }, 2000)
}
+
+ }).catch((err) => {
+ console.log(err)
})
- .catch((err) => {
- console.log(err);
- });
- };
+
+ }
+
const sendunassignnotification = (val) => {
- console.log(val);
+ console.log(val)
let data2;
- let tokenarr = [val.userfcmtoken];
- let arr1 = [
- {
- notificationid: 0,
- notificationdate: dayjs().format('YYYY-MM-DD HH:mm:ss'),
- Title: 'Staff Un-Asigned',
- message: `${val.firstname} has been Un-assigned to the order ${orderid}`,
- configid: 2,
- tenantid: tenantid,
- orderheaderid: orderheaderid,
- orderprocessid: val.orderprocessid,
- shiftid: val.shiftid,
- userid: val.userid,
- orderid: orderid,
- success: 0,
- orderstatus: 'assigned',
- processing: dayjs().format('YYYY-MM-DD HH:mm:ss'),
- notifytype: 2,
- notifyreason: 'Staff Un-Assigned'
- // "sound": "ring",
- // "click_action": "FLUTTER_NOTIFICATION_CLICK",
- // "firstname": val.firstname
- }
- ];
+ let tokenarr = [val.userfcmtoken]
+ let arr1 = [{
+ "notificationid": 0,
+ "notificationdate": dayjs().format('YYYY-MM-DD HH:mm:ss'),
+ "Title": "Staff Un-Asigned",
+ "message": `${val.firstname} has been Un-assigned to the order ${orderid}`,
+ "configid": 2,
+ "tenantid": tenantid,
+ "orderheaderid": orderheaderid,
+ "orderprocessid": val.orderprocessid,
+ "shiftid": val.shiftid,
+ "userid": val.userid,
+ "orderid": orderid,
+ "success": 0,
+ "orderstatus": 'assigned',
+ "processing": dayjs().format('YYYY-MM-DD HH:mm:ss'),
+ "notifytype": 2,
+ "notifyreason": 'Staff Un-Assigned'
+ // "sound": "ring",
+ // "click_action": "FLUTTER_NOTIFICATION_CLICK",
+ // "firstname": val.firstname
+
+ }];
+
+
+
data2 = {
- Title: 'Staff Un-Asigned',
- message: `A Staff has been Un-assigned to the order ${orderid}`,
- tenantid: tenantid,
- orderheaderid: orderheaderid,
- orderid: orderid,
- configid: 2
+ "Title": "Staff Un-Asigned",
+ "message": `A Staff has been Un-assigned to the order ${orderid}`,
+ "tenantid": tenantid,
+ "orderheaderid": orderheaderid,
+ "orderid": orderid,
+ "configid": 2,
// "click_action": "FLUTTER_NOTIFICATION_CLICK"
- };
+ }
let fcmmodel = {
- priority: 'high',
- registration_ids: tokenarr,
- data: data2,
- notification: {
- body: `An order has been Un-assigned ${orderid}`,
- title: 'Legendary',
- sound: 'ring',
- content_available: true,
- click_action: 'FLUTTER_NOTIFICATION_CLICK'
+ "priority": "high",
+ "registration_ids": tokenarr,
+ "data": data2,
+ "notification": {
+ "body": `An order has been Un-assigned ${orderid}`,
+ "title": "Legendary",
+ "sound": "ring",
+ "content_available": true,
+ "click_action": "FLUTTER_NOTIFICATION_CLICK"
}
- };
+ }
let grpnotifyobj = {
- notifications: arr1,
- fcmmodel: fcmmodel
- };
- console.log('grpnotifyobj unassign');
- console.log(grpnotifyobj);
- sendgroupnotification(grpnotifyobj);
- };
+ "notifications": arr1,
+ "fcmmodel": fcmmodel
+ }
+ console.log("grpnotifyobj unassign")
+ console.log(grpnotifyobj)
+ sendgroupnotification(grpnotifyobj)
+ }
useEffect(() => {
console.log(orderheaderid);
@@ -442,7 +584,7 @@ const Details = () => {
// fetchorderdetails();
fetchorderaddons();
fetchorderattires();
- fetchassignedcount();
+ fetchassignedcount()
// fetchuserdetails();
console.log(location.state || '');
// setOrderid(location.state.orderid || '');
@@ -457,7 +599,7 @@ const Details = () => {
setLoading(false);
}
// fetchorderdetails();
- console.log(orderheaderid, tenantid);
+ console.log(orderheaderid, tenantid)
}, [orderheaderid, tenantid, assignedpendingcount]);
const handleClose = () => {
@@ -466,75 +608,80 @@ const Details = () => {
const dialogclose = () => {
setDialogopen(false);
setStaffarr([]);
- setExpandopen(['', '']);
+ setExpandopen(['', ''])
};
useEffect(() => {
- console.log(currentshiftobj);
- });
+ console.log(currentshiftobj)
+ })
+
const assignok = async () => {
- let arr = [];
+ let arr = []
let arr1 = [];
staffarr.map((val) => {
arr.push({
- orderprocessid: 0,
+ "orderprocessid": 0,
// "processdate": `${dayjs(new Date()).format('YYYY-MM-DD')} ${dayjs(new Date()).format('HH:mm:ss')}`, //current date
- processdate: dayjs().format('YYYY-MM-DD HH:mm:ss'), //current date
- tenantid: tenantid,
- orderheaderid: orderheaderid,
- orderdetailid: val.orderdetailid, ////
- productid: val.productid, /////
- userid: val.userid,
- orderstatus: 'pending',
- pending: `${dayjs(pendingtime).format('YYYY-MM-DD')} ${dayjs(pendingtime).format('HH:mm:ss')}`, // if pending
- starttime: `${dayjs(starttime).format('YYYY-MM-DD')} ${dayjs(starttime).format('HH:mm:ss')}`,
- endtime: `${dayjs(endtime).format('YYYY-MM-DD')} ${dayjs(endtime).format('HH:mm:ss')}`,
- appuserid: parseInt(localStorage.getItem('appuserid')), //loginuserid
- shiftid: val.shiftid,
- userrate: val.userrate,
- productrate: val.productrate
- });
+ "processdate": dayjs().format('YYYY-MM-DD HH:mm:ss'), //current date
+ "tenantid": tenantid,
+ "orderheaderid": orderheaderid,
+ "orderdetailid": val.orderdetailid,////
+ "productid": val.productid,/////
+ "userid": val.userid,
+ "orderstatus": "pending",
+ "pending": `${dayjs(pendingtime).format('YYYY-MM-DD')} ${dayjs(pendingtime).format('HH:mm:ss')}`, // if pending
+ "starttime": `${dayjs(starttime).format('YYYY-MM-DD')} ${dayjs(starttime).format('HH:mm:ss')}`,
+ "endtime": `${dayjs(endtime).format('YYYY-MM-DD')} ${dayjs(endtime).format('HH:mm:ss')}`,
+ "appuserid": parseInt(localStorage.getItem("appuserid")), //loginuserid
+ "shiftid": val.shiftid,
+ "userrate": val.userrate,
+ "productrate": val.productrate
+ })
staffarr.map((val) => {
arr1.push({
- notificationid: 0,
- notificationdate: dayjs().format('YYYY-MM-DD HH:mm:ss'),
- Title: 'Staff Asigned',
- message: `A Staff has been assigned to the order ${orderid}`,
- configid: 2,
- tenantid: tenantid,
- orderheaderid: orderheaderid,
- orderprocessid: 0,
- shiftid: val.shiftid,
- userid: val.userid,
- orderid: orderid,
- sound: 'ring',
- click_action: 'FLUTTER_NOTIFICATION_CLICK',
- firstname: val.firstname
- });
- });
- });
- console.log('arr');
- console.log(arr);
+ "notificationid": 0,
+ "notificationdate": dayjs().format('YYYY-MM-DD HH:mm:ss'),
+ "Title": "Staff Asigned",
+ "message": `A Staff has been assigned to the order ${orderid}`,
+ "configid": 2,
+ "tenantid": tenantid,
+ "orderheaderid": orderheaderid,
+ "orderprocessid": 0,
+ "shiftid": val.shiftid,
+ "userid": val.userid,
+ "orderid": orderid,
+ "sound": "ring",
+ "click_action": "FLUTTER_NOTIFICATION_CLICK",
+ "firstname": val.firstname
+ })
- await axios
- .post(`${process.env.REACT_APP_URL2}/orders/createorderprocess`, arr)
+ })
+
+ })
+ console.log('arr')
+ console.log(arr)
+
+ await axios.post(`${process.env.REACT_APP_URL2}/orders/createorderprocess`, arr)
.then((res) => {
- console.log(res);
- if (res.data.message === 'Successfully created') {
+ console.log(res)
+ if (res.data.message === "Successfully created") {
// if (orderheaderid && tenantid) {
// fetchorderdetails();
// fetchorderaddons();
// fetchorderattires();
// }
+
enqueueSnackbar('Roles assigned successfully', {
- variant: 'success',
- anchorOrigin: { vertical: 'top', horizontal: 'right' },
+ variant: 'success', anchorOrigin: { vertical: 'top', horizontal: 'right' },
autoHideDuration: 2000
- });
+ })
// fetchroleslist(productid, '', '', orderheaderid, arr1[0].shiftid);
- // console.log(productid, '', '', orderheaderid, arr1[0].shiftid);
+ console.log(productid, '', '', orderheaderid, arr1[0].shiftid)
+
+
+
// arr1.map((val2) => {
// notificationpush(val2,val2.Title);
@@ -543,93 +690,173 @@ const Details = () => {
fetchorderattires();
fetchassignedcount();
}
+
+ }).catch((err) => {
+ console.log(err)
})
- .catch((err) => {
- console.log(err);
- });
- console.log(arr);
- };
+ console.log(arr)
+ }
const notificationpush = async (val) => {
- let fcmtoken = val.userfcmtoken;
+ let fcmtoken = val.userfcmtoken
let obj1 = {
- notificationid: 0,
- notificationdate: dayjs().format('YYYY-MM-DD HH:mm:ss'),
- Title: 'Staff Asigned',
- message: `A Staff has been assigned to the order ${orderid}`,
- configid: 2,
- tenantid: tenantid,
- orderheaderid: orderheaderid,
- orderprocessid: val.orderprocessid,
- shiftid: val.shiftid,
- userid: val.userid,
- orderid: orderid,
- sound: 'ring',
- click_action: 'FLUTTER_NOTIFICATION_CLICK'
+ "notificationid": 0,
+ "notificationdate": dayjs().format('YYYY-MM-DD HH:mm:ss'),
+ "Title": "Staff Asigned",
+ "message": `A Staff has been assigned to the order ${orderid}`,
+ "configid": 2,
+ "tenantid": tenantid,
+ "orderheaderid": orderheaderid,
+ "orderprocessid": val.orderprocessid,
+ "shiftid": val.shiftid,
+ "userid": val.userid,
+ "orderid": orderid,
+ "sound": "ring",
+ "click_action": "FLUTTER_NOTIFICATION_CLICK",
// "firstname": val.firstname
+
};
- console.log(obj1, fcmtoken);
- await axios
- .post(
- `${process.env.REACT_APP_URL2}/utils/notification/send`,
- {
- priority: 'high',
- registration_ids: [fcmtoken],
- data: obj1,
- notification: {
- body: `A Staff has been assigned to ${orderid}`,
- title: 'Legendary',
- sound: 'ring',
- content_available: true
- }
- },
- {
- headers: {
- Authorization: `Bearer ${process.env.REACT_APP_STAFF_TOKEN}`
- }
+ console.log(obj1, fcmtoken)
+ await axios.post(`${process.env.REACT_APP_URL2}/utils/notification/send`,
+ {
+ "priority": "high",
+ "registration_ids": [fcmtoken],
+ "data": obj1,
+ "notification": {
+ "body": `A Staff has been assigned to ${orderid}`,
+ "title": "Legendary",
+ "sound": "ring",
+ "content_available": true
}
- )
+ }
+ , {
+ headers: {
+ 'Authorization': `Bearer ${process.env.REACT_APP_STAFF_TOKEN}`
+ }
+ }
+ )
.then((res) => {
- console.log(res);
+ console.log(res)
// if(res.data.status){
enqueueSnackbar('Notification sent successfully', {
- variant: 'success',
- anchorOrigin: { vertical: 'top', horizontal: 'right' },
+ variant: 'success', anchorOrigin: { vertical: 'top', horizontal: 'right' },
autoHideDuration: 2000
- });
+ })
// }
})
.catch((err) => {
- console.log(err);
- });
- };
+ console.log(err)
+ })
+
+ }
+
+ const fetchassignedstaffs = async () => {
+
+ // console.log(obj1)
+ await axios.get(`${process.env.REACT_APP_URL2}/orders/getnotificationusers?orderheaderid=${orderheaderid}`)
+ .then((res) => {
+ if (res.data.status) {
+ let arr1 = [];
+ let data2;
+ let tokenarr = []
+ console.log(res)
+
+ res.data.details.map((val) => {
+ arr1.push({
+ "notificationid": 0,
+ "notificationdate": dayjs().format('YYYY-MM-DD HH:mm:ss'),
+ "Title": "Staff Asigned",
+ "message": `${val.staffname} has been assigned to the order ${orderid}`,
+ "configid": 2,
+ "tenantid": tenantid,
+ "orderheaderid": orderheaderid,
+ "orderprocessid": val.orderprocessid,
+ "shiftid": val.shiftid,
+ "userid": val.userid,
+ "orderid": orderid,
+ "success": 0,
+ "orderstatus": 'assigned',
+ "processing": dayjs().format('YYYY-MM-DD HH:mm:ss'),
+ "notifytype": 1,
+ "notifyreason": 'Staff Assigned'
+ // "sound": "ring",
+ // "click_action": "FLUTTER_NOTIFICATION_CLICK",
+ // "firstname": val.firstname
+
+ });
+ tokenarr.push(val.userfcmtoken);
+
+ })
- const sendgroupnotification = async (obj1) => {
- console.log(obj1);
- await axios
- .post(`${process.env.REACT_APP_URL2}/utils/notification/sendall`, obj1, {
- headers: {
- Authorization: `Bearer ${process.env.REACT_APP_STAFF_TOKEN}`
+ data2 = {
+ "Title": "Staff Asigned",
+ "message": `A Staff has been assigned to the order ${orderid}`,
+ "tenantid": tenantid,
+ "orderheaderid": orderheaderid,
+ "orderid": orderid,
+ "configid": 2,
+ // "click_action": "FLUTTER_NOTIFICATION_CLICK"
+ }
+ let fcmmodel = {
+ "priority": "high",
+ "registration_ids": tokenarr,
+ "data": data2,
+ "notification": {
+ "body": `An order has been assigned ${orderid}`,
+ "title": "Legendary",
+ "sound": "ring",
+ "content_available": true,
+ "click_action": "FLUTTER_NOTIFICATION_CLICK"
+ }
+ }
+ let grpnotifyobj = {
+ "notifications": arr1,
+ "fcmmodel": fcmmodel
+ }
+ console.log("grpnotifyobj")
+ console.log(grpnotifyobj)
+ sendgroupnotification(grpnotifyobj)
+ // notificationpush(obj2, val.userfcmtoken);
+ // notificationpush(arr1,tokenarr);
+ // enqueueSnackbar('Notifications sent successfully', {
+ // variant: 'success', anchorOrigin: { vertical: 'top', horizontal: 'right' },
+ // autoHideDuration: 2000
+ // })
}
})
+ .catch((err) => {
+ console.log(err)
+ })
+
+ }
+
+ const sendgroupnotification = async (obj1) => {
+
+ console.log(obj1)
+ await axios.post(`${process.env.REACT_APP_URL2}/utils/notification/sendall`, obj1, {
+ headers: {
+ 'Authorization': `Bearer ${process.env.REACT_APP_STAFF_TOKEN}`
+ }
+ }
+ )
.then((res) => {
- console.log(res);
+ console.log(res)
if (res.data.status) {
// updateorderstatus();
enqueueSnackbar('Notification sent successfully', {
- variant: 'success',
- anchorOrigin: { vertical: 'top', horizontal: 'right' },
+ variant: 'success', anchorOrigin: { vertical: 'top', horizontal: 'right' },
autoHideDuration: 2000
- });
+ })
fetchorderaddons();
}
})
.catch((err) => {
- console.log(err);
- });
- };
+ console.log(err)
+ })
+
+ }
// const updateorderstatus = async () => {
@@ -658,15 +885,15 @@ const Details = () => {
// }
const fetchassignedcount = async () => {
+
// console.log(obj1)
- await axios
- .get(`${process.env.REACT_APP_URL2}/orders/getorderstatuscount?orderheaderid=${orderheaderid}`)
+ await axios.get(`${process.env.REACT_APP_URL2}/orders/getorderstatuscount?orderheaderid=${orderheaderid}`)
.then((res) => {
if (res.data.status) {
// let arr1=[];
- console.log(res);
- setAssignedpendingcount(res.data.pendingcount);
- fetchorderaddons();
+ console.log(res)
+ setAssignedpendingcount(res.data.pendingcount)
+ fetchorderaddons()
// res.data.details.map((val) => {
// let val2={
// "notificationid": 0,
@@ -686,24 +913,25 @@ const Details = () => {
// };
+
// notificationpush(val2,val.userfcmtoken);
+
// })
} else {
- setAssignedpendingcount(res.data.pendingcount);
- fetchorderaddons();
+ setAssignedpendingcount(res.data.pendingcount)
+ fetchorderaddons()
}
})
.catch((err) => {
- console.log(err);
- });
- };
+ console.log(err)
+ })
+
+ }
function AlertCustomerDelete({
// title,
- open,
- handleClose
- }) {
+ open, handleClose }) {
const [deletepassword, setDeletepassword] = useState('');
return (
@@ -711,63 +939,105 @@ const Details = () => {
open={open}
onClose={() => handleClose(false)}
maxWidth="xs"
- fullScreen={isMobile}
- PaperProps={{ sx: { borderRadius: { xs: 0, sm: 3 } } }}
+ PaperProps={{ sx: { borderRadius: 3 } }}
>
-
-
-
+
+
+
-
-
-
-
- {/*
- Are you sure you want to cancel this order?
- */}
- {invoiceeligible && (
- }>
- Order is within 24Hrs time frame. The order will be invoiced with standard pricing as agreed.
- {/* This is an warning alert. */}
-
- Terms & Condition link
-
-
- )}
-
- Please type in the order number to confirm.
+
+
+ Cancel Order
+
+
+ Confirm to permanently cancel this order
- {
- console.log(e.target.value);
- setDeletepassword(e.target.value);
- }}
- error={deletepassword !== orderid.slice(4)}
- // error={true}
- value={deletepassword}
- />
+
+
+
+
+
+ {orderid.slice(4)}
+
-
+ {(invoiceeligible) &&
+ }>
+ Order is within 24Hrs time frame. The order will be invoiced with standard pricing as agreed.
+ Terms & Condition link
+
+ }
+
+
+ Please type in the order number to confirm.
+
+ setDeletepassword(e.target.value)}
+ error={deletepassword !== orderid.slice(4)}
+ value={deletepassword}
+ placeholder={orderid.slice(4)}
+ />
+
+
+ handleClose(false)}
+ variant="outlined"
+ sx={{
+ borderRadius: 999,
+ py: 1,
+ borderColor: DT.borderSubtle,
+ color: DT.textSecondary,
+ fontWeight: 700,
+ '&:hover': { borderColor: DT.textSecondary, bgcolor: DT.surfaceAlt }
+ }}
+ >
+ No
+
{
if (deletepassword === orderid.slice(4)) {
cancelorder();
handleClose(true);
}
}}
- autoFocus
+ sx={{
+ borderRadius: 999,
+ py: 1,
+ bgcolor: '#ef4444',
+ fontWeight: 700,
+ boxShadow: `0 6px 18px ${ring('#ef4444')}`,
+ '&:hover': { bgcolor: '#dc2626' }
+ }}
>
Yes, Cancel
- handleClose(false)} color="secondary" variant="outlined">
- No
-
@@ -781,68 +1051,120 @@ const Details = () => {
-
-
-
-
- Assign Roles
+ // fullScreen
+ TransitionComponent={PopupTransition}>
-
+
+
+
+
+
+
+
+
+ Assign Roles
+
+
+ {clientname} · {currentrole}
+
+
-
+
+ {orderid}
+
-
+
+
- {/* */}
- setTabstatus((e) => (e === 0 ? 1 : 0))}
- variant="scrollable"
- scrollButtons="auto"
+ setTabstatus((e) => (e === 0 ? 1 : 0))}
+ sx={{
+ display: 'inline-flex',
+ alignItems: 'center',
+ gap: 0.75,
+ px: 1.25,
+ py: 0.625,
+ borderRadius: 999,
+ cursor: 'pointer',
+ bgcolor: BRAND,
+ color: '#fff',
+ fontWeight: 800,
+ fontSize: 12,
+ boxShadow: `0 6px 18px ${ring(BRAND)}`
+ }}
>
- {/* */}
-
-
+
+
+
+ {currentrole || 'Role'}
+
-
-
-
-
+
+ {[
+ { label: 'Required', value: currentshiftobj.shifts, color: BRAND },
+ { label: 'Assigned', value: currentshiftobj.assigned, color: '#10b981' },
+ { label: 'Remaining', value: currentshiftobj.remaining, color: '#ef4444' }
+ ].map((c) => (
+
+ {c.label}
+
+ {c.value ?? 0}
+
+
+ ))}
@@ -853,10 +1175,10 @@ const Details = () => {
-
+
setTabstatus((e) => (e === 0) ? 1 : 0)}
variant="scrollable" scrollButtons="auto" >
@@ -876,130 +1198,27 @@ const Details = () => {
*/}
+
{/* */}
{/* */}
- {stafflist.length === 0 ? (
+ {(stafflist.length === 0) ?
<>
- {loading ? (
+ {(loading) ?
<>
+
+
+
>
- ) : (
+ :
No Staffs Available
- )}
+
+ }
>
- ) : isMobile ? (
-
- {stafflist.map((val, i) => {
- const isSelected = staffarr.find((res) => res.userid == val.userid) ? true : false;
- return (
-
-
-
-
-
- {val.firstname}
-
- {val.contactno}
-
-
-
- {val.orderdetailid !== orderdetailid ? (
- {
- console.log(currentshiftobj);
- if (currentshiftobj.remaining >= 0) {
- if (e.target.checked && currentshiftobj.remaining != 0) {
- let arr = staffarr;
- arr.push({
- userid: val.userid,
- orderdetailid,
- productid,
- shiftid: currentshiftobj.shiftid,
- userrate: currentshiftobj.price,
- productrate: val.rolecost,
- firstname: val.firstname
- });
- setStaffarr([...arr]);
- let obj = currentshiftobj;
- obj.assigned++;
- obj.remaining = obj.shifts - obj.assigned;
- setCurrentshiftobj({ ...obj });
- } else if (
- currentshiftobj.assigned != currentshiftobj.shifts ||
- (currentshiftobj.remaining === 0 && !e.target.checked)
- ) {
- let arr = staffarr;
- let index = arr.findIndex((val1) => val1.userid === val.userid);
- arr.splice(index, 1);
- setStaffarr([...arr]);
- let obj = currentshiftobj;
- obj.assigned--;
- obj.remaining = obj.shifts - obj.assigned;
- setCurrentshiftobj({ ...obj });
- }
- console.log(staffarr);
- }
- }}
- />
- ) : (
-
-
-
- {
- console.log(val);
- unassign(val);
- }}
- >
-
-
-
-
- {
- console.log(val);
- notificationpush(val);
- }}
- >
-
-
-
-
- )}
-
-
-
-
-
- {val.cateoryname}
-
-
-
-
-
-
-
-
-
-
- {val.orderid && (
-
-
-
- )}
-
-
- );
- })}
-
- ) : (
+ :
+
@@ -1019,238 +1238,223 @@ const Details = () => {
City
Action
+
{stafflist.map((val, i) => {
- return (
-
- res.userid == val.userid) ? '#f5f5f5' : '',
- ':hover': {
- backgroundColor: staffarr.find((res) => res.userid == val.userid) ? '#f5f5f5 !important' : ''
- }
- }}
- >
-
- {i + 1}
-
-
-
-
- {/* {row.tenantname.charAt(0)} */}
-
-
- {val.firstname}
-
- {val.contactno}
-
-
+
+ return
+
+
+ res.userid == val.userid)) ? '#f5f5f5' : '', ':hover': {
+ backgroundColor: (staffarr.find((res) => res.userid == val.userid)) ? '#f5f5f5 !important' : ''
+ }
+ }}>
+
+ {i + 1}
+
+
+
+
+ {/* {row.tenantname.charAt(0)} */}
+
+
+ {val.firstname}
+
+ {val.contactno}
+
-
-
- {/*
+
+
+
+ {/*
{val.contactno}
some demo address
*/}
-
-
- {val.cateoryname}
-
-
- {/* {row.category} */}
-
-
- {val.rolecost}
- {/* */}
- {/* {(row.gender === 1) && } */}
- {/* {row.gender === 0 && } */}
- {/* */}
- {/* */}
- {/* B+ */}
- {/* {row.devicetype} */}
- {val.experience} Years
-
-
-
- {val.city}
-
- {val.orderdetailid !== orderdetailid ? (
- <>
- res.userid == val.userid) ? true : false}
- onClick={(e) => {
- console.log(currentshiftobj);
- if (currentshiftobj.remaining >= 0) {
- if (e.target.checked && currentshiftobj.remaining != 0) {
- let arr = staffarr;
- arr.push({
- userid: val.userid,
- orderdetailid,
- productid,
- shiftid: currentshiftobj.shiftid,
- userrate: currentshiftobj.price,
- productrate: val.rolecost,
- firstname: val.firstname
- });
- setStaffarr([...arr]);
- let obj = currentshiftobj;
- // obj.shifts--;
- // obj.assigned = arr.length;
- obj.assigned++;
- obj.remaining = obj.shifts - obj.assigned;
- setCurrentshiftobj({ ...obj });
- } else if (
- currentshiftobj.assigned != currentshiftobj.shifts ||
- (currentshiftobj.remaining === 0 && !e.target.checked)
- ) {
- let arr = staffarr;
- // let index = arr.indexOf(val.userid)
- let index = arr.findIndex((val1) => val1.userid === val.userid);
- arr.splice(index, 1);
- setStaffarr([...arr]);
- let obj = currentshiftobj;
- // obj.shifts++;
- // obj.assigned = arr.length;
- obj.assigned--;
- obj.remaining = obj.shifts - obj.assigned;
- setCurrentshiftobj({ ...obj });
- }
- // forceUpdate();
- console.log(staffarr);
+
+ {val.cateoryname}
+
+ {/* {row.category} */}
+
+
+
+ {val.rolecost}
+ {/* */}
+ {/* {(row.gender === 1) && } */}
+ {/* {row.gender === 0 && } */}
+ {/* */}
+ {/* */}
+ {/* B+ */}
+ {/* {row.devicetype} */}
+ {val.experience} Years
+
+ {val.city}
+
+ {(val.orderdetailid !== orderdetailid) ?
+ <>
+ res.userid == val.userid)) ? true : false}
+ onClick={(e) => {
+ console.log(currentshiftobj)
+ if (currentshiftobj.remaining >= 0) {
+
+
+ if (e.target.checked && currentshiftobj.remaining != 0) {
+ let arr = staffarr;
+ arr.push({
+ userid: val.userid,
+ orderdetailid,
+ productid,
+ shiftid: currentshiftobj.shiftid,
+ userrate: currentshiftobj.price,
+ productrate: val.rolecost,
+ firstname: val.firstname
+ });
+ setStaffarr([...arr])
+ let obj = currentshiftobj;
+ // obj.shifts--;
+ // obj.assigned = arr.length;
+ obj.assigned++;
+ obj.remaining = obj.shifts - obj.assigned;
+ setCurrentshiftobj({ ...obj })
+ } else if (currentshiftobj.assigned != currentshiftobj.shifts || (currentshiftobj.remaining === 0 && (!e.target.checked))) {
+ let arr = staffarr;
+ // let index = arr.indexOf(val.userid)
+ let index = arr.findIndex((val1) => val1.userid === val.userid)
+ arr.splice(index, 1);
+ setStaffarr([...arr]);
+ let obj = currentshiftobj;
+ // obj.shifts++;
+ // obj.assigned = arr.length;
+ obj.assigned--;
+ obj.remaining = obj.shifts - obj.assigned;
+ setCurrentshiftobj({ ...obj })
}
- }}
- />
- >
- ) : (
- <>
-
+ // forceUpdate();
+ console.log(staffarr);
+ }
+ }} />
- {/*
+ :
+
+ <>
+
+
+ {/* */}
-
- {
- console.log(val);
- unassign(val);
- // sendunassignnotification(val)
- }}
- >
- {/* */}
-
-
-
-
- {
- console.log(val);
- // unassign(val)
- notificationpush(val);
- }}
- >
- {/* */}
-
-
-
- >
- )}
-
-
- {val.orderid && (
- <>
-
- >
- )}
-
-
-
- );
- })}
+
+ {
+ console.log(val)
+ unassign(val)
+ // sendunassignnotification(val)
+ }}>
+ {/* */}
+
+
+
+
+ {
+ console.log(val)
+ // unassign(val)
+ notificationpush(val)
+ }}>
+ {/* */}
+
+
+
+ >
+ }
+
+
+
+
+ {(val.orderid) &&
+
+ <>
+
+ >
+
+ }
+
+
+
+
+ })
+ }
- )}
+ }
-
- {stafflist.length > 0 && (
+
+ {(stafflist.length > 0) &&
<>
-
- OK
-
- {
- // dialogclose();
- setStaffarr([]);
- let obj = currentshiftobj;
- // obj.shifts = row.orderqty;
- obj.remaining = obj.shifts;
- obj.assigned = 0;
+ OK
+ {
- setCurrentshiftobj(obj);
- }}
- >
- clear
-
+ // dialogclose();
+ setStaffarr([]);
+ let obj = currentshiftobj;
+ // obj.shifts = row.orderqty;
+ obj.remaining = obj.shifts;
+ obj.assigned = 0;
+
+ setCurrentshiftobj(obj);
+ }}>clear
>
- )}
- {
- dialogclose();
- }}
- >
- Close
-
+ }
+ { dialogclose() }}>Close
{/* */}
{/* */}
-
+
-
+
+
+
{/*
-
+
*/}
@@ -1259,184 +1463,201 @@ const Details = () => {
Details
*/}
-
-
-
-
- history.back()}
- // onClick={()=>}
+
+
+ history.back()}
+ sx={{
+ bgcolor: '#fff',
+ border: `1px solid ${DT.borderSubtle}`,
+ borderRadius: 999,
+ color: DT.textPrimary,
+ '&:hover': { bgcolor: tint(BRAND), borderColor: edge(BRAND), color: BRAND }
+ }}
+ >
+
+
+
+
+
+
+
-
-
- {/* Test me */}
-
- Details
-
- {/* */}
- : orderid}
- variant="combined"
- color="warning"
- size="small"
- />
- {/* Date */}
- {/* {orderdate} */}
- : orderdate}
- variant="combined"
- color="primary"
- size="small"
- />
-
- {orderstatus === 'pending' && }
- {orderstatus === 'cancelled' && }
- {orderstatus === 'completed' && }
- {orderstatus === 'processing' && }
- {orderstatus === 'assigned' && }
- {orderstatus === 'confirmed' && }
-
- {orderstatus === 'active' && }
- {orderstatus === 'closed' && }
-
- {orderstatus === 'modified' && }
-
+ Order Details
+
+
+
+
+ {orderid === '' ? : orderid}
+
+
+
+ {orderdate === '' ? : orderdate}
+
+
-
-
- {/* {dayjs(startdate).$d.toString()} */}
- {/* {startdate} */}
- {/* {dayjs().$d.toString()} */}
-
- {(orderstatus === 'pending' || orderstatus === 'assigned' || orderstatus === 'confirmed' || orderstatus === 'modified') && (
- // && (dayjs(startdate).$d > dayjs().$d)
-
- }
- onClick={(e) => {
- e.stopPropagation();
- // if (dayjs(startdate).$d > dayjs().$d) {
- if (dayjs(dayjs().format('MM-DD-YYYY')).isBefore(dayjs(dayjs(startdate).format('MM-DD-YYYY')))) {
- navigate(`/editorder`, {
- state: {
- orderheaderid: orderheaderid,
- tenantid: tenantid
- }
- });
- } else {
- enqueueSnackbar(
- 'Order cannot be edited.\n Order date is not valid at this time',
-
- {
- variant: 'error',
- anchorOrigin: { vertical: 'top', horizontal: 'right' },
- autoHideDuration: 4000,
- style: { whiteSpace: 'pre-line' }
- }
- );
- }
- }}
- >
- Edit Order
-
-
- )}
-
- {/* {(((orderstatus === 'pending')
- || (orderstatus === 'modified'))
- && assignedpendingcount === 0) &&
- <>
- }
- onClick={() => {
- fetchassignedstaffs();
- }}
- >
- Notify Staff
-
- >
- } */}
- {orderstatus !== 'cancelled' && orderstatus !== '' && orderstatus !== 'completed' && orderstatus !== 'closed' && (
- <>
- {
- console.log(dayjs(startdate).diff(dayjs(), 'm') / 60);
- if (dayjs(startdate).diff(dayjs(), 'm') / 60 > 24) {
- setInvoiceeligible(false);
- setOpen(true);
- } else {
- setInvoiceeligible(true);
- setOpen(true);
- }
- }}
- sx={{ borderRadius: '40px', mt: { xs: 2, sm: 0 }, width: { xs: '100%', sm: 'auto' } }}
- startIcon={ }
- >
- Cancel Order
-
- >
- )}
- {orderstatus === 'cancelled' && (
- <>
-
- >
- )}
- {/* {(orderstatus === 'completed') &&
- {
- navigate(`/invoice/create`, {
- state: {
- orderheaderid: orderheaderid,
- tenantid: tenantid
- }
- })
-
- }
- }
- sx={{ borderRadius: '40px', mt: { xs: 2, sm: 0 } }}
- >
- Raise Invoice
-
- } */}
-
-
-
+
+
+ {((orderstatus === 'pending') ||
+ (orderstatus === 'assigned') ||
+ (orderstatus === 'confirmed') ||
+ (orderstatus === 'modified')) && (
+
+ }
+ onClick={(e) => {
+ e.stopPropagation();
+ if (dayjs(dayjs().format('MM-DD-YYYY')).isBefore(dayjs(dayjs(startdate).format('MM-DD-YYYY')))) {
+ navigate(`/editorder`, {
+ state: {
+ orderheaderid: orderheaderid,
+ tenantid: tenantid
+ }
+ });
+ } else {
+ enqueueSnackbar('Order cannot be edited.\n Order date is not valid at this time', {
+ variant: 'error',
+ anchorOrigin: { vertical: 'top', horizontal: 'right' },
+ autoHideDuration: 4000,
+ style: { whiteSpace: 'pre-line' }
+ });
+ }
+ }}
+ >
+ Edit Order
+
+
+ )}
+
+ {orderstatus !== 'cancelled' && orderstatus !== '' && orderstatus !== 'completed' && orderstatus !== 'closed' && (
+ {
+ if ((dayjs(startdate).diff(dayjs(), 'm') / 60) > 24) {
+ setInvoiceeligible(false);
+ setOpen(true);
+ } else {
+ setInvoiceeligible(true);
+ setOpen(true);
+ }
+ }}
+ startIcon={ }
+ >
+ Cancel Order
+
+ )}
+
+ {orderstatus === 'cancelled' && (
+
+ Cancelled on {cancelleddate}
+
+ )}
+
+
+
+
{/* Dialog window */}
+
-
+
{/* {(dayjs().isBefore(dayjs(startdate)))?'true':'false'} */}
{/* */}
@@ -1468,9 +1689,7 @@ const Details = () => {
Client
-
- {clientname === '' ? : clientname}
-
+ {(clientname === '') ? : clientname}
{/* {eventlocation.map((val, i) => {
return {val}
@@ -1481,9 +1700,7 @@ const Details = () => {
fafdf
dafaf
afdafafd */}
-
- {tenantaddress === '' ? : tenantaddress}
-
+ {(tenantaddress === '') ? : tenantaddress}
@@ -1494,12 +1711,10 @@ const Details = () => {
Event
-
- {eventname === '' ? : eventname}
-
+ {(eventname === '') ? : eventname}
{/*
{(eventlocation === '') ? : eventlocation}
-
+
: venuetype} color="primary" variant="light" size="small" sx={{ width: 'max-content' }} />
*/}
@@ -1507,331 +1722,160 @@ const Details = () => {
- {categoryarr.map((val5, j) => {
- return (
-
-
-
-
-
- Shift {j + 1}
-
- {''}
- {val5.locationaddress}
-
- {val5.shiftstatus === 1 && }
-
-
- {val5.ordercontacts.map((val11) => {
- return (
- <>
-
-
- {val11.contactname.charAt(0).toUpperCase()}
-
-
- >
- );
- })}
-
+ {categoryarr.map((val5, j) => {
+
+
+
+
+
+ return < Fragment key={val5.locationaddress}>
+
+
+
+
+
+ Shift {j + 1}
+
+
+ {''}{val5.locationaddress}
+
+ {(val5.shiftstatus === 1) &&
+
+ }
- {isMobile ? (
-
- {val5.orderdetails.length === 0 && (
-
-
-
-
-
- )}
- {val5.orderdetails.map((row, i) => (
-
-
-
- #{i + 1}
- {row.productname}
-
-
-
- {
- setStafflist([]);
- setExpandopen(expandopen[0] === j && expandopen[1] === i ? ['', ''] : [j, i]);
- fetchstafflist(row.orderdetailid);
- }}
- >
- {expandopen[0] === j && expandopen[1] === i ? : }
-
-
- {orderstatus === 'cancelled' && (
-
-
-
- )}
- {row.status === 1 && (
-
-
-
-
-
- )}
- {row.supplyqty > row.orderqty && (
-
-
-
-
-
- )}
-
-
-
-
-
- {dayjs(row.starttime).format('MM/DD/YYYY')}
- {dayjs(row.starttime).format('hh:mm A')}
-
-
-
-
- {dayjs(row.endtime).format('MM/DD/YYYY')}
- {dayjs(row.endtime).format('hh:mm A')}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- {stafflist.length === 0 ? (
- loading ? (
-
-
-
- ) : (
-
- No Staffs has been Assigned
-
- )
- ) : (
-
- {stafflist.map((val, si) => (
-
-
-
- {val.staffname}
-
-
-
-
-
- {val.orderstatus === 'pending' && }
- {val.orderstatus === 'cancelled' && (
-
- )}
- {val.orderstatus === 'completed' && (
-
- )}
- {val.orderstatus === 'processing' && (
-
- )}
- {val.orderstatus === 'assigned' && }
- {val.orderstatus === 'confirmed' && (
-
- )}
- {val.orderstatus === 'active' && }
- {val.orderstatus === 'closed' && }
-
-
-
-
-
- {dayjs(val.Starttime).format('MM/DD/YYYY')}
- {dayjs(val.Starttime).format('hh:mm A')}
-
-
-
-
- {dayjs(val.Endtime).format('MM/DD/YYYY')}
- {dayjs(val.Endtime).format('hh:mm A')}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- ))}
-
- )}
-
-
- ))}
-
- ) : (
-
-
-
-
- #
- Role
- Start Date
- End Date
- Unpaid break
- Count
- Assigned
- Attire
- Price
- {/* Tax */}
- Amount
- Action
-
-
-
- {val5.orderdetails.length === 0 && (
- <>
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- {/* */}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- {/*
+
+ {val5.ordercontacts.map((val11) => {
+
+ return <>
+
+ {val11.contactname.charAt(0).toUpperCase()}
+
+ >
+ })
+
+ }
+
+
+
+
+
+
+
+
+ #
+ Role
+ Start Date
+ End Date
+ Unpaid break
+ Count
+ Assigned
+ Attire
+ Price
+ {/* Tax */}
+ Amount
+ Action
+
+
+
+ {(val5.orderdetails.length === 0) &&
+ <>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {/* */}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {/*
*/}
-
- {/* */}
- >
- )}
- {/* */}
- {val5.orderdetails.map((row, i) => (
- <>
-
- {i + 1}
- {row.productname}
- {/* {row.productname}
+
+ {/* */}
+ >
+ }
+
+ {/* */}
+ {val5.orderdetails.map((row, i) => (
+ <>
+
+ {i + 1}
+ {row.productname}
+ {/* {row.productname}
*/}
-
-
- {dayjs(row.starttime).format('MM/DD/YYYY')}
- {dayjs(row.starttime).format('hh:mm A')}
-
-
-
- {' '}
-
- {dayjs(row.endtime).format('MM/DD/YYYY')}
- {dayjs(row.endtime).format('hh:mm A')}
-
-
- {row.unpaidbreak || 0}
-
-
-
-
-
-
-
- {/* < Grid container spacing={1}>
+
+
+ {dayjs(row.starttime).format('MM/DD/YYYY')}
+ {dayjs(row.starttime).format('hh:mm A')}
+
+
+
+ {' '}
+
+ {dayjs(row.endtime).format('MM/DD/YYYY')}
+ {dayjs(row.endtime).format('hh:mm A')}
+
+
+ {row.unpaidbreak || 0}
+
+
+
+
+
+
+
+
+
+ {/* < Grid container spacing={1}>
{(row.orderattires || []).map((val) => {
return
@@ -1843,30 +1887,42 @@ const Details = () => {
}
*/}
-
- ${row.price}
- {/* {row.taxamount} */}
- ${row.landingamount}
-
-
-
- {
- setStafflist([]);
- setExpandopen(expandopen[0] === j && expandopen[1] === i ? ['', ''] : [j, i]);
- // expanddatafetch(row.orderheaderid);
+
+ ${row.price}
+ {/* {row.taxamount} */}
+ ${row.landingamount}
+
+
+
- // fetchroleslist(row.productid, '', '', val5.orderheaderid, row.shiftid);
- fetchstafflist(row.orderdetailid);
- }}
- >
- {expandopen[0] === j && expandopen[1] === i ? : }
-
-
+
- {/* {(orderstatus !== 'cancelled') &&
+ {
+ setStafflist([]);
+ setExpandopen(((expandopen[0] === j) && (expandopen[1] === i)) ? ['', ''] : [j, i])
+ // expanddatafetch(row.orderheaderid);
+
+ // fetchroleslist(row.productid, '', '', val5.orderheaderid, row.shiftid);
+ fetchstafflist(row.orderdetailid)
+
+
+ }
+ }
+ >
+ {((expandopen[0] === j) && (expandopen[1] === i)) ?
+
+ :
+ }
+
+
+
+
+
+ {/* {(orderstatus !== 'cancelled') &&
<>
{
@@ -1907,102 +1963,111 @@ const Details = () => {
setDialogopen(true);
}} >
-
+
>
} */}
- {orderstatus === 'cancelled' && (
+ {(orderstatus === 'cancelled') &&
+ <>
+
+ >
+ }
+
+ {(row.status === 1) &&
+
+
+
+
+
+ }
+ {(row.supplyqty > row.orderqty) &&
+
+
+
+
+
+ }
+
+
+
+
+
+
+
+
+
+
+
+ {/* */}
+
+
+ {(stafflist.length === 0) ?
<>
-
-
-
+ {(loading) ?
+ <>
+
+
+
+
+
+
+ >
+ :
+ <>
+
+ No Staffs has been Assigned
+
+ >
+ }
>
- )}
+ :
- {row.status === 1 && (
-
-
-
-
-
- )}
- {row.supplyqty > row.orderqty && (
-
-
-
-
-
- )}
-
-
-
-
-
-
- {/* */}
+
+
+
+
+ #
+ Staff
+ Start Time
+ End Time
+ Pay Rate
-
- {stafflist.length === 0 ? (
- <>
- {loading ? (
- <>
-
-
-
- >
- ) : (
- <>
-
- No Staffs has been Assigned
-
- >
- )}
- >
- ) : (
-
-
-
-
- #
- Staff
- Start Time
- End Time
- Pay Rate
+ {/* Category */}
+ Clockin
+ Clockout
- {/* Category */}
- Clockin
- Clockout
+ Hours Worked
- Hours Worked
- {/* Experience */}
- {/* Level */}
- {/* City */}
- Status
-
-
-
- {stafflist.map((val, i) => {
- return (
-
- res.userid == val.userid)) ? '#f5f5f5' : '', ':hover': {
- // backgroundColor: (staffarr.find((res) => res.userid == val.userid)) ? '#f5f5f5 !important' : ''
- // }
- }
- }
- >
-
- {i + 1}
-
- {/*
+
+ {/* Experience */}
+
+ {/* Level */}
+ {/* City */}
+ Status
+
+
+
+
+ {stafflist.map((val, i) => {
+
+ return
+
+
+ res.userid == val.userid)) ? '#f5f5f5' : '', ':hover': {
+ // backgroundColor: (staffarr.find((res) => res.userid == val.userid)) ? '#f5f5f5 !important' : ''
+ // }
+
+ }}>
+
+ {i + 1}
+
+ {/*
{
*/}
-
-
- {val.staffname}
-
-
-
-
-
-
-
-
- {dayjs(val.Starttime).format('MM/DD/YYYY')}
-
-
- {dayjs(val.Starttime).format('hh:mm A')}
-
-
-
-
-
-
- {dayjs(val.Endtime).format('MM/DD/YYYY')}
-
-
- {dayjs(val.Endtime).format('hh:mm A')}
-
-
-
- {val.rolecost}
+
+
+
+ {val.staffname}
+
+
+
+
+
+
+
+
+ {dayjs(val.Starttime).format('MM/DD/YYYY')}
+ {dayjs(val.Starttime).format('hh:mm A')}
+
+
+
+
+ {dayjs(val.Endtime).format('MM/DD/YYYY')}
+ {dayjs(val.Endtime).format('hh:mm A')}
+
+
+ {val.rolecost}
- {/*
+ {/*
{val.cateoryname}
@@ -2060,50 +2119,38 @@ const Details = () => {
*/}
-
-
- {/* Clock In: */}
- {/* Age */}
-
-
-
-
-
-
- {/* Clock In: */}
- {/* Age */}
-
-
-
-
- {val.hoursworked}
+
+
+ {/* Clock In: */}
+ {/* Age */}
+
+
- {/*
+
+
+
+
+ {/* Clock In: */}
+ {/* Age */}
+
+
+
+
+
+ {val.hoursworked}
+
+
+ {/*
+
-
+
@@ -2130,82 +2177,98 @@ const Details = () => {
*/}
-
-
- {val.orderstatus === 'pending' && (
-
- )}
- {val.orderstatus === 'cancelled' && (
-
- )}
- {val.orderstatus === 'completed' && (
-
- )}
- {val.orderstatus === 'processing' && (
-
- )}
- {val.orderstatus === 'assigned' && (
-
- )}
- {val.orderstatus === 'confirmed' && (
-
- )}
- {val.orderstatus === 'active' && (
-
- )}
- {val.orderstatus === 'closed' && (
-
- )}
-
-
-
-
- );
- })}
-
-
-
- )}
-
-
-
-
- >
- ))}
-
-
-
- )}
-
-
-
- );
- })}
+
+
+
+
+ {(val.orderstatus === 'pending') &&
+
+
+ }
+ {(val.orderstatus === 'cancelled') &&
+
+
+
+ }
+ {(val.orderstatus === 'completed') &&
+
+
+ }
+ {(val.orderstatus === 'processing') &&
+
+ }
+ {(val.orderstatus === 'assigned') &&
+
+ }
+ {(val.orderstatus === 'confirmed') &&
+
+ }
+
+ {(val.orderstatus === 'active') &&
+
+ }
+ {(val.orderstatus === 'closed') &&
+
+ }
+
+
+
+
+
+
+ })
+ }
+
+
+
+ }
+
+
+
+
+
+
+
+
+
+
+ >
+ ))}
+
+
+
+
+
+
+
+
+
+ })
+ }
-
-
+
{/* */}
{/* Order Addons
*/}
- {(orderaddons || []).map((val) => {
- return (
-
+ {
+
+
+ (orderaddons || []).map((val) => {
+ return
- } variant="outlined" color="error" label={val.addon} />
+ } variant='outlined' color="error" label={val.addon} />
- );
- })}
+ })
+ }
{/*
} variant='outlined' color="error" label="Parking Provided" />
@@ -2228,11 +2291,11 @@ const Details = () => {
{/* */}
{/* */}
-
-
+
+
Sub Total:
- ${subtotal === '' ? : subtotal}
+ ${(subtotal === '') ? : subtotal}
{/*
Discount:
@@ -2242,26 +2305,25 @@ const Details = () => {
*/}
Tax:
- {taxamount === '' ? : taxamount}
+ {(taxamount === '') ? : taxamount}
Grand Total:
-
- {grandtotal === '' ? : `$${grandtotal}`}
-
+ {(grandtotal === '') ? : `$${grandtotal}`}
{/* */}
-
-
+
- Other Instructions:
- {otherinstructions}
+ Other Instructions:
+
+
+ {otherinstructions}
+
{/*
@@ -2269,11 +2331,12 @@ const Details = () => {
*/}
-
+
{/* */}
{/*
{ notificationpush() }}>notify */}
-
+
+
>
);
};
diff --git a/src/pages/nearle/orders/map.js b/src/pages/nearle/orders/map.js
new file mode 100644
index 0000000..4a62f0a
--- /dev/null
+++ b/src/pages/nearle/orders/map.js
@@ -0,0 +1,157 @@
+/* eslint-disable no-unused-vars */
+import * as React from 'react';
+import Box from '@mui/material/Box';
+import TextField from '@mui/material/TextField';
+import Autocomplete from '@mui/material/Autocomplete';
+import LocationOnIcon from '@mui/icons-material/LocationOn';
+import Grid from '@mui/material/Grid';
+import Typography from '@mui/material/Typography';
+import parse from 'autosuggest-highlight/parse';
+import { debounce } from '@mui/material/utils';
+
+// This key was created specifically for the demo in mui.com.
+// You need to create a new one for your application.
+const GOOGLE_MAPS_API_KEY ='AIzaSyCF4KatYCI3vqz1_H3kiHeyS3yCMfYToh8';
+
+function loadScript(src, position, id) {
+ if (!position) {
+ return;
+ }
+
+ const script = document.createElement('script');
+ script.setAttribute('async', '');
+ script.setAttribute('id', id);
+ script.src = src;
+ position.appendChild(script);
+}
+
+const autocompleteService = { current: null };
+
+export default function GoogleMaps() {
+ const [value, setValue] = React.useState(null);
+ const [inputValue, setInputValue] = React.useState('');
+ const [options, setOptions] = React.useState([]);
+ const loaded = React.useRef(false);
+
+ if (typeof window !== 'undefined' && !loaded.current) {
+ if (!document.querySelector('#google-maps')) {
+ loadScript(
+ `https://maps.googleapis.com/maps/api/js?key=${GOOGLE_MAPS_API_KEY}&libraries=places`,
+ document.querySelector('head'),
+ 'google-maps',
+ );
+ }
+
+ loaded.current = true;
+ }
+
+ const fetch = React.useMemo(
+ () =>
+ debounce((request, callback) => {
+ autocompleteService.current.getPlacePredictions(request, callback);
+ }, 400),
+ [],
+ );
+
+ React.useEffect(() => {
+ let active = true;
+
+ if (!autocompleteService.current && window.google) {
+ autocompleteService.current =
+ new window.google.maps.places.AutocompleteService();
+ }
+ if (!autocompleteService.current) {
+ return undefined;
+ }
+
+ if (inputValue === '') {
+ setOptions(value ? [value] : []);
+ return undefined;
+ }
+
+ fetch({ input: inputValue }, (results) => {
+ if (active) {
+ let newOptions = [];
+
+ if (value) {
+ newOptions = [value];
+ }
+
+ if (results) {
+ newOptions = [...newOptions, ...results];
+ }
+
+ setOptions(newOptions);
+ }
+ });
+
+ return () => {
+ active = false;
+ };
+ }, [value, inputValue, fetch]);
+
+ return (
+
+ typeof option === 'string' ? option : option.description
+ }
+ filterOptions={(x) => x}
+ options={options}
+ autoComplete
+ includeInputInList
+ filterSelectedOptions
+ value={value}
+ noOptionsText="No locations"
+ onChange={(event, newValue) => {
+ setOptions(newValue ? [newValue, ...options] : options);
+ setValue(newValue);
+ }}
+ onInputChange={(event, newInputValue) => {
+ setInputValue(newInputValue);
+ }}
+ renderInput={(params) => (
+
+ )}
+ renderOption={(props, option) => {
+ const matches =
+ option.structured_formatting.main_text_matched_substrings || [];
+
+ const parts = parse(
+ option.structured_formatting.main_text,
+ matches.map((match) => [match.offset, match.offset + match.length]),
+ );
+
+ return (
+
+
+
+
+
+
+ {parts.map((part, index) => (
+
+ {part.text}
+
+ ))}
+
+ {option.structured_formatting.secondary_text}
+
+
+
+
+ );
+ }}
+ />
+ );
+}
diff --git a/src/pages/nearle/orders/miltiUploadBackup.js b/src/pages/nearle/orders/miltiUploadBackup.js
new file mode 100644
index 0000000..490794f
--- /dev/null
+++ b/src/pages/nearle/orders/miltiUploadBackup.js
@@ -0,0 +1,1610 @@
+/* eslint-disable no-unused-vars */
+import React from 'react';
+import Loader from 'components/Loader';
+import { useEffect, useState, Fragment, useRef } from 'react';
+import { useTheme } from '@mui/material/styles';
+import MainCard from 'components/MainCard';
+import axios from 'axios';
+import ClearIcon from '@mui/icons-material/Clear';
+import { SearchOutlined, CloseOutlined, ExclamationCircleOutlined, FileAddOutlined } from '@ant-design/icons';
+import { Empty } from 'antd';
+import MyLocationIcon from '@mui/icons-material/MyLocation';
+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 dayjs from 'dayjs';
+var utc = require('dayjs/plugin/utc');
+dayjs.extend(utc);
+import { enqueueSnackbar } from 'notistack';
+import { useNavigate } from 'react-router';
+import Papa from 'papaparse';
+import { calculateDrivingDistance, calculateTotalCharge } from '../../../utils/distance';
+import * as XLSX from 'xlsx';
+
+import {
+ FormControl,
+ InputAdornment,
+ Grid,
+ Typography,
+ Stack,
+ Box,
+ Button,
+ TextField,
+ Autocomplete,
+ Chip,
+ Divider,
+ Dialog,
+ DialogTitle,
+ DialogContent,
+ Checkbox,
+ DialogActions,
+ CircularProgress,
+ IconButton,
+ OutlinedInput,
+ FormGroup,
+ FormControlLabel,
+ Table,
+ TableContainer,
+ TableCell,
+ TableBody,
+ TableRow,
+ Paper,
+ TableHead,
+ FormLabel,
+ RadioGroup,
+ Radio,
+ Backdrop,
+ List,
+ ListItem,
+ ListItemText
+} from '@mui/material';
+import CircularLoader from 'components/nearle_components/CircularLoader';
+
+const MultipleOrders = () => {
+ const navigate = useNavigate();
+ const theme = useTheme();
+ const locationRef = useRef(null);
+ const tenantRef = useRef(null);
+ const userid = localStorage.getItem('userid');
+ const [locations, setLocations] = useState([]);
+ const [tenantlist, setTenantlist] = useState([]);
+ const [loading, setLoading] = useState(false);
+ const [btnLoading, setBtnLoading] = useState(false);
+ const [appId, setAppId] = useState(0);
+ const [tenantLocations, setTenantlocations] = useState([]);
+ // const [tenantid, setTenantid] = useState(0);
+ const tenantid = localStorage.getItem('tenantid') || 0;
+ const [locationid, setLocationid] = useState(0);
+ const [basePrice, setBasePrice] = useState(0);
+ const [pricePerKm, setPricePerKm] = useState(0);
+ const [minKm, setMinKm] = useState(0);
+ const [pickCust, setPickCust] = useState(null);
+ const [dropCust, setDropCust] = useState([]);
+ const [isCustomerOpen, setIsCustomerOpen] = useState(false);
+ const [searchCustList, setSearchCustList] = useState('');
+ const [customerlist, setCustomerlist] = useState([]);
+ const [startdate, setStartdate] = useState(dayjs().format('MM-DD-YYYY'));
+ const [timeslotarr, setTimeslotarr] = useState([]);
+ const [starttime, setStatrttime] = useState();
+ const [endtime, setEndtime] = useState();
+ const [selectedtime, setSelectedtime] = useState('');
+ const [alertmessage, setAlertmessage] = useState('');
+ const [otherinstructions, setOtherinstructions] = useState('');
+ const [admintoken, setAdmintoken] = useState();
+ const [totaldist, settotaldist] = useState(0);
+ const [totalAmt, settotalAmt] = useState(0);
+ const [totalQty, settotalQty] = useState(0);
+ const [totalCash, settotalCash] = useState(0);
+ const [users, setUsers] = useState([]);
+ const [uploadType, setUploadType] = useState(null);
+ const [tenantValue, setTenantValue] = useState(null);
+ const [locationValue, setLocationValue] = useState(null);
+ const [pickupSlotsList, setPickupSlotsList] = useState(null);
+ const [pickupSlot, setPickupSlot] = useState(null);
+
+ 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]);
+
+ // =============================================== || opentoast || ===============================================
+ const opentoast = (message, variant, time) => {
+ enqueueSnackbar(message, {
+ variant: variant,
+ anchorOrigin: { vertical: 'top', horizontal: 'right' },
+ autoHideDuration: time ? time : 1500
+ });
+ console.log(alertmessage);
+ };
+
+ // 🔹 Smart toast wrapper — prevents duplicate toasts for same message within 3 seconds
+ let toastCache = {};
+ const OpenToast = (message, type = 'info', timeout = 10000) => {
+ const key = `${type}-${message}`;
+ if (toastCache[key]) return; // skip duplicates
+ opentoast(message, type, timeout); // your existing toast/snackbar
+ toastCache[key] = true;
+ setTimeout(() => delete toastCache[key], 3000); // reset after delay
+ };
+
+ // ==============================|| fetchAppLocations ||============================== //
+
+ const fetchAppLocations = async () => {
+ setLoading(true);
+
+ 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);
+ OpenToast(err.message, 'error', 5000);
+ } finally {
+ setLoading(false);
+ }
+ };
+ 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]);
+ // ============================================= || fetchTenantPricing || =============================================
+
+ 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);
+ }
+ };
+ // ============================================= || 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);
+ setPickCust(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);
+ }
+ };
+ useEffect(() => {
+ gettenantlocations(tenantid);
+ }, [tenantid]);
+ // ========================================================= || clientdetails || =========================================================
+ const clientdetails = async () => {
+ 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);
+
+ setCustomerlist(res.data.details);
+ let arr = [];
+ res.data.details.map((val) => {
+ arr.push({
+ label: `${val.firstname} | ${val.contactno}`,
+ ...val
+ });
+ });
+ }
+ })
+ .catch((err) => {
+ console.log(err);
+ opentoast('server error', 'warning');
+ });
+ } catch (err) {
+ console.log(err);
+ }
+ };
+ useEffect(() => {
+ if (tenantid) {
+ clientdetails();
+ }
+ }, [searchCustList.length > 3, searchCustList == '', tenantid]);
+
+ // ========================================================= || calculateTotal(dist , charge) || =========================================================
+ const calculateTotal = () => {
+ let a1 = 0;
+ let a2 = 0;
+ let a3 = 0;
+ let a4 = 0;
+ dropCust.map((customer) => {
+ a1 += customer.distance;
+ a2 += customer.totalcharge;
+ a3 += customer.quantity;
+ a4 += customer.collectionamt;
+ });
+ settotaldist(a1);
+ settotalAmt(a2);
+ settotalQty(a3);
+ settotalCash(a4);
+ };
+ useEffect(() => {
+ calculateTotal();
+ }, [dropCust]);
+
+ // ========================================================= || handleCheckboxChange || =========================================================
+ const handleCheckboxChange = async (event, customer) => {
+ setLoading(true);
+ if (event.target.checked) {
+ // If the checkbox is checked, calculate the distance and add the customer
+ try {
+ const obj = await calculateDistance(customer);
+ const { roundedDistance, totalcharge } = obj;
+ // Create a new customer object with the distance property
+ const updatedCustomer = {
+ ...customer,
+ distance: roundedDistance,
+ totalcharge: totalcharge
+ };
+
+ // Add the updated customer object to dropCust
+ setDropCust((prevDropCust) => [...prevDropCust, updatedCustomer]);
+
+ // Log the rounded distance
+ // console.log(`Rounded Distance: ${roundedDistance} km`);
+ } catch (error) {
+ console.error('Failed to calculate distance:', error);
+ } finally {
+ setLoading(false);
+ }
+ } else {
+ // If the checkbox is unchecked, remove the customer from dropCust
+ setDropCust((prevDropCust) => {
+ return prevDropCust.filter((cust) => cust.customerid !== customer.customerid);
+ });
+ setLoading(false);
+ }
+ };
+ // ========================================================= || handleCheckboxChange1 || =========================================================
+ // const handleCheckboxChange1 = async (customer) => {
+ // console.log('customer', customer);
+ // setLoading(true);
+ // try {
+ // const obj = await calculateDistance(customer);
+ // const { roundedDistance, totalcharge } = obj;
+ // // Create a new customer object with the distance property
+ // const updatedCustomer = {
+ // ...customer,
+ // distance: roundedDistance,
+ // totalcharge: totalcharge
+ // };
+
+ // // Add the updated customer object to dropCust
+ // setDropCust((prevDropCust) => [...prevDropCust, updatedCustomer]);
+
+ // // Log the rounded distance
+ // console.log(`Rounded Distance: ${roundedDistance} km`);
+ // setLoading(false);
+ // } catch (error) {
+ // console.error('Failed to calculate distance:', error);
+ // }
+ // };
+ const handleCheckboxChange1 = async (customer) => {
+ console.log('customer', customer);
+
+ setLoading(true);
+
+ try {
+ setDropCust((prevDropCust) => {
+ const isAlreadySelected = prevDropCust.some((c) => c.firstname === customer.firstname);
+
+ // 🔴 REMOVE if already exists
+ if (isAlreadySelected) {
+ return prevDropCust.filter((c) => c.firstname !== customer.firstname);
+ }
+
+ // 🟢 ADD if not exists (calculate distance)
+ return prevDropCust;
+ });
+
+ // Only calculate distance if customer is not already added
+ const alreadyExists = dropCust.some((c) => c.firstname === customer.firstname);
+
+ if (!alreadyExists) {
+ const obj = await calculateDistance(customer);
+ const { roundedDistance, totalcharge } = obj;
+
+ const updatedCustomer = {
+ ...customer,
+ distance: roundedDistance,
+ totalcharge
+ };
+
+ setDropCust((prevDropCust) => [...prevDropCust, updatedCustomer]);
+
+ console.log(`Rounded Distance: ${roundedDistance} km`);
+ }
+ } catch (error) {
+ console.error('Failed to calculate distance:', error);
+ } finally {
+ setLoading(false);
+ }
+ };
+
+ // ========================================================= || calculateDistance || =========================================================
+
+ // 🔹 Main distance calculation function
+ const calculateDistance = async (customer) => {
+ try {
+ // --- Input validation ---
+ if (!customer || typeof customer !== 'object') {
+ throw new Error('Invalid customer data: expected an object.');
+ }
+
+ if (!pickCust || typeof pickCust !== 'object') {
+ throw new Error('Origin (pickCust) data missing or invalid.');
+ }
+
+ // --- Compute distance ---
+ const roundedDistance = await calculateDrivingDistance(pickCust, customer);
+
+ // --- Calculate total charge ---
+ const totalcharge = calculateTotalCharge(roundedDistance, basePrice, pricePerKm, minKm);
+ return { roundedDistance, totalcharge };
+ } catch (error) {
+ // --- Categorized smart error handling ---
+ console.log('on calculateDistance', error.message);
+ if (error.message.includes('Invalid coordinates') || error.message.includes('Invalid coordinate')) {
+ console.log('📍 Invalid coordinate format:', error.message);
+ OpenToast('Invalid coordinate format. Check location data.', 'warning', 3000);
+ } else if (error.message.includes('Origin') || error.message.includes('customer')) {
+ console.log('❌ Missing or invalid input data:', error.message);
+ OpenToast('Missing or invalid input data for distance calculation.', 'warning', 3000);
+ } else {
+ console.log('💥 Unexpected error calculating distance:', error);
+ OpenToast('Unexpected error during distance calculation.', 'error', 3000);
+ }
+
+ throw error; // keeps your current flow intact
+ }
+ };
+
+ // ==================================================== || 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 } = res.data.details[0];
+ if (res.data.status) {
+ 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]);
+
+ 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
+ console.log('fetchAppAdminTokens', res);
+ console.log('userfcmtokemArray', userfcmtokemArray);
+ if (res.data.status) {
+ setAdmintoken(userfcmtokemArray);
+ }
+ setLoading(false);
+ })
+ .catch((err) => {
+ console.log(err);
+ setLoading(false);
+ });
+ };
+
+ useEffect(() => {
+ if (appId) {
+ fetchAppAdminTokens();
+ }
+ }, [appId]);
+
+ useEffect(() => {
+ console.log('pickCust', pickCust);
+ }, [pickCust]);
+ useEffect(() => {
+ console.log('dropCust', dropCust);
+ }, [dropCust]);
+ // // ==================================================== || 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) {
+ // setTenantid(res.data.details.tenantid);
+ // }
+ // setLoading(false);
+ // })
+ // .catch((err) => {
+ // console.log(err);
+ // setLoading(false);
+ // });
+ // };
+ // useEffect(() => {
+ // if (tenantid) {
+ // fetchtenantinfo();
+ // }
+ // }, [tenantid]);
+ // ================================================== || 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);
+ });
+ };
+
+ const cleanReceiverName = (name) => {
+ if (typeof name !== 'string') return name;
+ return name.replace(/^[\d.\s]+/, '').trim();
+ };
+
+ const handleFileUpload = (event) => {
+ console.log('Normal upload started...');
+ try {
+ const file = event.target.files?.[0];
+ if (!file) {
+ opentoast('No file selected.', 'warning');
+ return;
+ }
+
+ const fileName = file.name.toLowerCase();
+ const isCSV = fileName.endsWith('.csv');
+ const isExcel = fileName.endsWith('.xls') || fileName.endsWith('.xlsx');
+
+ // Invalid file
+ if (!isCSV && !isExcel) {
+ opentoast('Invalid file type. Please upload a CSV or Excel file.', 'warning');
+ return;
+ }
+
+ // ---------------------- CSV ----------------------
+ if (isCSV) {
+ Papa.parse(file, {
+ header: true,
+ dynamicTyping: true,
+ skipEmptyLines: true,
+ complete: (results) => {
+ const data = results.data || [];
+ if (data.length === 0) {
+ opentoast('CSV file is empty or invalid.', 'warning');
+ setUsers([]);
+ return;
+ }
+ const cleanedData = data.map((row) => ({
+ ...row,
+ firstname: cleanReceiverName(row.firstname)
+ }));
+ console.log('✅ Parsed CSV Data:', cleanedData);
+ setUsers(cleanedData);
+ opentoast('CSV file uploaded successfully, ✅', 'success', 3000);
+ opentoast(' Press Continue to add delivery customers', 'warning', 5000);
+ },
+ error: (error) => {
+ console.error('❌ CSV Parse Error:', error.message);
+ opentoast(`CSV parsing failed: ${error.message}`, 'warning');
+ }
+ });
+ }
+
+ // ---------------------- EXCEL (.xls / .xlsx) ----------------------
+ if (isExcel) {
+ const reader = new FileReader();
+
+ reader.onload = (e) => {
+ try {
+ const data = e.target.result;
+
+ // Use correct mode for binary Excel formats
+ const workbook = XLSX.read(data, {
+ type: 'binary',
+ cellDates: true,
+ cellNF: false,
+ cellText: false
+ });
+ const firstSheet = workbook.SheetNames[0];
+ const worksheet = workbook.Sheets[firstSheet];
+ const jsonData = XLSX.utils.sheet_to_json(worksheet, { defval: '' });
+
+ if (!jsonData || jsonData.length === 0) {
+ opentoast('Excel file is empty or invalid.', 'warning');
+ setUsers([]);
+ return;
+ }
+
+ const cleanedData = jsonData.map((row) => ({
+ ...row,
+ firstname: cleanReceiverName(row.firstname)
+ }));
+
+ console.log('✅ Parsed Excel Data:', cleanedData);
+ setUsers(cleanedData);
+ opentoast('Excel file uploaded successfully ✅, press continue', 'success', 3000);
+ } catch (err) {
+ console.error('❌ Excel Parse Error:', err);
+ opentoast(`Error reading Excel: ${err.message}`, 'warning');
+ }
+ };
+
+ // ✅ Key fix: use readAsBinaryString for both .xls & .xlsx
+ reader.readAsBinaryString(file);
+ }
+ } catch (err) {
+ console.error('Unexpected error during file upload:', err.message);
+ opentoast(`Unexpected error: ${err.message}`, 'warning');
+ }
+ };
+
+ // your header mapping
+ const headerMap = {
+ 'pickupdate(yyyy-mmm-dd)': 'date',
+ 'sendername*': 'locationname',
+ 'senderphone*': 'locationcontact',
+ 'senderaddress*': 'locationaddress',
+ 'receivername*': 'firstname',
+ 'receiverphone': 'contactno',
+ 'receiveralternatephone*': 'altcontactno',
+ receiverfulladdress: 'address',
+ receiverlatitude: 'latitude',
+ receiverlongitude: 'longitude',
+ 'itemdescription*': 'description',
+ Quantity: 'quantity',
+ ' Collect Cash': 'collectionamt'
+ };
+
+ // helper to normalize headers
+ const normalizeHeader = (header) => header?.toString().trim().toLowerCase().replace(/\s+/g, '');
+
+ const handleFileDirectUpload = (event) => {
+ try {
+ const file = event.target.files?.[0];
+ if (!file) {
+ opentoast('No file selected.', 'warning');
+ return;
+ }
+
+ const fileName = file.name.toLowerCase();
+ const isCSV = fileName.endsWith('.csv');
+ const isExcel = fileName.endsWith('.xls') || fileName.endsWith('.xlsx');
+
+ if (!isCSV && !isExcel) {
+ opentoast('Invalid file type. Please upload a CSV or Excel file.', 'warning');
+ return;
+ }
+
+ const processData = (data, headers) => {
+ console.log('data', data);
+ const normalizedMap = {};
+ for (const key in headerMap) {
+ normalizedMap[normalizeHeader(key)] = headerMap[key];
+ }
+ console.log('normalizedMap', normalizedMap);
+
+ const mappedData = data.map((row) => {
+ const newRow = {};
+ for (const key in row) {
+ const cleanKey = normalizeHeader(key);
+ const newKey = normalizedMap[cleanKey] || cleanKey;
+ let value = row[key];
+ if (newKey === 'firstname') value = cleanReceiverName(value);
+
+ newRow[newKey] = value;
+ }
+
+ return newRow;
+ });
+
+ const missingCols = Object.keys(headerMap)
+ .filter((clientCol) => clientCol.endsWith('*'))
+ .filter((clientCol) => !headers.includes(normalizeHeader(clientCol)));
+
+ if (missingCols.length > 0) {
+ isExcel && opentoast(`Missing columns: ${missingCols.join(', ')}`, 'warning');
+ }
+
+ console.log('✅ Final Processed Data:', mappedData);
+ setUsers(mappedData);
+ opentoast('File uploaded and successfully ', 'success', 3000);
+ opentoast('Press Continue', 'warning', 3000);
+ };
+
+ // ============ CSV handler ============
+ if (isCSV) {
+ Papa.parse(file, {
+ header: true,
+ dynamicTyping: true,
+ skipEmptyLines: true,
+ complete: (results) => {
+ if (!results.data?.length) {
+ opentoast('CSV file is empty or has no valid rows.', 'warning');
+ setUsers([]);
+ return;
+ }
+ const headers = results.meta.fields.map(normalizeHeader);
+ processData(results.data, headers);
+ },
+ error: (error) => {
+ console.error('❌ CSV Parsing Error:', error);
+ opentoast(`CSV parsing failed: ${error.message}`, 'warning');
+ }
+ });
+ }
+
+ // ============ Excel handler ============
+ if (isExcel) {
+ const reader = new FileReader();
+ reader.onload = (e) => {
+ try {
+ const data = e.target.result;
+ // Try reading as binary first
+ let workbook;
+ try {
+ workbook = XLSX.read(data, { type: 'binary' });
+ } catch {
+ // fallback for modern XLSX files
+ const arrayBuffer = new Uint8Array(data);
+ workbook = XLSX.read(arrayBuffer, { type: 'array' });
+ }
+
+ const firstSheet = workbook.SheetNames[0];
+ const worksheet = workbook.Sheets[firstSheet];
+ const jsonData = XLSX.utils.sheet_to_json(worksheet, { defval: '' });
+
+ if (!jsonData?.length) {
+ opentoast('Excel file is empty or invalid.', 'warning');
+ setUsers([]);
+ return;
+ }
+
+ const headers = Object.keys(jsonData[0]).map(normalizeHeader);
+ processData(jsonData, headers);
+ } catch (err) {
+ console.error('❌ Error processing Excel:', err);
+ opentoast(`Error reading Excel: ${err.message}`, 'warning');
+ }
+ };
+
+ // Important: use readAsBinaryString for Excel
+ reader.readAsBinaryString(file);
+ }
+ } catch (err) {
+ console.error('Unexpected error during file upload:', err);
+ opentoast(`Unexpected error: ${err.message}`, 'warning');
+ }
+ };
+
+ // =============================================== || createorders || ===============================================
+ const createorders = async () => {
+ // ===================== Build Payload =====================
+ const arr = dropCust.map((customer) => ({
+ applocationid: pickCust.applocationid,
+ configid: 9,
+ partnerid: pickCust.partnerid,
+ partneruserid: +userid,
+ paymentstatus: 1,
+ paymenttype: 42,
+ pickupaddress: pickCust.address || '',
+ pickupcity: pickCust.city || '',
+ pickupcontactno: pickCust.contactno || '',
+ pickupcustomer: pickCust.locationname || '',
+ pickuplandmark: pickCust.landmark || '',
+ pickuplat: pickCust.latitude,
+ pickuplocation: pickCust.suburb || '',
+ pickuplocationid: pickCust.locationid || 0,
+ pickuplong: pickCust.longitude,
+ tenantid: pickCust.tenantid,
+
+ customerid: +customer?.customerid,
+ deliveryaddress: customer.address || '',
+ deliverycharge: +customer.totalcharge || 0,
+ deliverycity: customer.city || '',
+ deliverycontactno: customer.contactno?.toString() || '',
+ deliverycustomer: customer.firstname || '',
+ deliveryid: +customer.customerid,
+ deliverylandmark: customer.landmark || '',
+ deliverylat: customer.latitude?.toString() || '',
+ deliverylocation: customer.suburb || '',
+ deliverylocationid: customer.deliverylocationid || 0,
+ deliverylong: customer.longitude?.toString() || '',
+ deliverytime: `${dayjs(startdate).format('YYYY-MM-DD')} ${dayjs(selectedtime.$d).format('HH:mm:ss')}`,
+ deliverytype: 'B',
+
+ itemcount: 1,
+ quantity: customer.quantity,
+ collectionamt: customer.collectionamt,
+ kms: customer.distance?.toString() || '0',
+ locationid: +pickCust.locationid,
+ moduleid: +pickCust.moduleid,
+
+ orderamount: +customer.totalcharge || 0,
+ ordercharges: 0.0,
+ orderdate: dayjs().format('YYYY-MM-DD HH:mm:ss'),
+ ordernotes: otherinstructions,
+ orderstatus: 'created',
+ ordervalue: +customer.totalcharge || 0,
+ pickupSlot
+ }));
+
+ console.log('arr', arr);
+
+ // ===================== Validation =====================
+ if (!tenantid) {
+ opentoast('Choose Client', 'warning');
+ return;
+ }
+ setLoading(true);
+ try {
+ const res = await axios.post(`${process.env.REACT_APP_URL}/orders/createorders`, arr);
+ if (res.data.status) {
+ opentoast('Order Created Successfully', 'success', 2000);
+ if (admintoken) {
+ sendnotifications();
+ }
+ navigate('/nearle/orders');
+ setLoading(false);
+ } else {
+ console.log(res.data);
+ console.error('Create order failed (API response):', res.data);
+ opentoast(res?.data?.message || 'Order creation failed. Please try again.', 'warning', 3000);
+ }
+ } catch (err) {
+ opentoast(err.message, 'error', 2000);
+ console.log('create orders', err.message);
+ console.error('Create order error:', {
+ message: err.message,
+ response: err.response,
+ request: err.request,
+ stack: err.stack
+ });
+
+ // Exact but short error for user
+ let toastMessage = 'Something went wrong. Please try again.';
+
+ if (err.response) {
+ // Server responded with error
+ toastMessage = err.response.data?.message || `Server error (${err.response.status})`;
+ } else if (err.request) {
+ // No response received
+ toastMessage = 'Network error. Check your internet connection.';
+ }
+ opentoast(toastMessage, 'error');
+ setLoading(false);
+ } finally {
+ setLoading(false);
+ setBtnLoading(false);
+ }
+ };
+
+ const [fileName, setFileName] = useState('');
+ const removeFileExtension = (fileName) => {
+ return fileName.replace(/\.[^/.]+$/, '');
+ };
+
+ const onFileChange = (event) => {
+ const file = event.target.files[0];
+ if (!file) return;
+ const cleanedName = removeFileExtension(file.name);
+ setFileName((prev) => (prev ? `${prev}, ${cleanedName}` : cleanedName));
+ if (tenantid === 916) {
+ handleFileDirectUpload(event);
+ } else {
+ handleFileDirectUpload(event);
+ // handleFileUpload(event);
+ }
+ };
+
+ const handleQuantityChange = (customerid, value) => {
+ setDropCust((prev) => prev.map((cust) => (cust.customerid === customerid ? { ...cust, quantity: Number(value) || 0 } : cust)));
+ };
+ const handleCollectionAmtChange = (customerid, value) => {
+ setDropCust((prev) => prev.map((cust) => (cust.customerid === customerid ? { ...cust, collectionamt: Number(value) || 0 } : cust)));
+ };
+
+ return (
+ <>
+ {loading && (
+ <>
+
+ {/* */}
+ >
+ )}
+ {
+ theme.zIndex.drawer + 1
+ }}
+ open={btnLoading} // when loader = true, backdrop covers the page
+ >
+
+
+ }
+
+
+ {/* ===================================================== ||Business Location || ===================================================== */}
+
+
+ Create Multiple Order
+
+
+ {tenantLocations?.length === 1 ? (
+
+
+
+ )
+ }}
+ />
+ ) : (
+ `${option.locationname} (${option.suburb})`}
+ value={locationValue}
+ 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 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);
+ setPickCust(value);
+ setPickupSlotsList(value?.slots);
+ }
+ }}
+ renderInput={(params) => }
+ />
+ )}
+
+
+
+
+ {/* ===================================================== || Pickup || ===================================================== */}
+
+
+ {locationid !== 0 && (
+
+
+
+
+
+ )}
+ {/* ================================================= || Time || ================================================= */}
+
+
+
+
+
+ {
+ setStartdate(e);
+ let dateres11 = dayjs().diff(dayjs(`${dayjs(e).format('YYYY-MM-DD')}`), 'd');
+ console.log('dateres11');
+ console.log(dateres11);
+ setSelectedtime('');
+ if (dateres11 <= 0) {
+ console.log('startdate', e);
+ 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: 'auto', mt: 0 }}
+ disablePast
+ />
+
+
+ {/* {timeslotarr.length > 0 && (
+
+
+
+
+
+
+ Time
+
+
+
+
+
+ {
+ setStartdate(e);
+ let dateres11 = dayjs().diff(dayjs(`${dayjs(e).format('YYYY-MM-DD')}`), 'd');
+ console.log('dateres11');
+ console.log(dateres11);
+ setSelectedtime('');
+ if (dateres11 <= 0) {
+ console.log('startdate', e);
+ 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: 'auto', mt: 0 }}
+ disablePast
+ />
+
+
+
+
+
+
+ {timeslotarr.map((val, index) => {
+ if (
+ dayjs().diff(dayjs(`${dayjs(startdate).format('MM-DD-YYYY')} ${dayjs(val).format('HH:mm:ss')}`), 'm') <= 0
+ ) {
+ return (
+
+
+ {
+ console.log('selectedtime', val);
+ setSelectedtime(val);
+ }}
+ // onClick={() => {
+ // if (distance > appLocaRadius) {
+ // setOpen(true);
+ // } else if (showDistance) {
+ // console.log('selectedtime', val);
+ // setSelectedtime(val);
+ // } else {
+ // opentoast('Out of city limit', 'error');
+ // }
+ // }}
+ />
+
+
+ );
+ }
+ })}
+
+
+
+
+
+ )} */}
+
+
+ {
+ if (reason === 'clear') {
+ setSelectedtime(null);
+ setPickupSlot(null);
+ } else {
+ // Convert to AM/PM and merge with date
+ 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.name} (${dayjs(option.time, 'HH:mm').format('hh:mm A')})`}
+ renderInput={(params) => }
+ />
+
+
+
+
+
+ {/* ===================================================== || Drop || ===================================================== */}
+
+
+
+
+ Drop ({dropCust?.length || 0})
+
+
+ {/* ================= Upload CSV ================= */}
+ {uploadType === 0 && (
+ <>
+ {fileName && (
+
+
+
+ {fileName}
+
+
+ )}
+
+
+
+
+
+ {dropCust?.length > 0 ? 'Add More Files' : ' Upload CSV'}
+
+
+ >
+ )}
+
+ {/* ================= Continue ================= */}
+ {users.length >= 1 && uploadType === 0 && (
+ {
+ users.forEach((customer) => handleCheckboxChange1(customer));
+ }}
+ >
+ Continue
+
+ )}
+
+ {/* ================= Select Customers ================= */}
+ {uploadType === 1 && (
+ {
+ setIsCustomerOpen(true);
+ setSearchCustList('');
+ }}
+ >
+ Select Customers
+
+ )}
+
+ {/* ================= Upload Type ================= */}
+
+
+ Upload Type
+ {
+ if (!locationid) {
+ OpenToast('Please select Business Location!', 'warning', 3000);
+ return;
+ }
+ setUploadType(Number(e.target.value));
+ setDropCust([]);
+ setUsers([]);
+ setFileName('');
+ }}
+ >
+ } label="Excel / CSV" />
+ } label="Selection" />
+
+
+
+
+
+ }
+ >
+
+
+ {dropCust?.length > 0 ? (
+ <>
+
+
+ S.No
+ Customer
+ Address
+ Quantity
+
+
+ Cash Collect
+
+ Kms
+
+ Charge
+ Action
+
+
+
+
+ {dropCust?.map((customer, index) => (
+
+ {index + 1}
+ {customer.firstname}
+ {customer.address}
+
+ {uploadType == 0 ? (
+ {customer.quantity}
+ ) : (
+ handleQuantityChange(customer.customerid, e.target.value)}
+ inputProps={{ min: 0 }}
+ />
+ )}
+
+
+ {uploadType == 0 ? (
+ ₹{Number(customer.collectionamt || 0).toFixed(2)}
+ ) : (
+ {
+ if (e.target.value <= 0) {
+ handleCollectionAmtChange(customer.customerid, 0);
+ } else {
+ handleCollectionAmtChange(customer.customerid, e.target.value);
+ }
+ }}
+ inputProps={{ min: 0 }}
+ InputProps={{
+ startAdornment: ₹
+ }}
+ />
+ )}
+
+
+ {customer.distance}
+ {`₹${customer?.totalcharge?.toFixed(2)}`}
+
+ {
+ <>
+ handleCheckboxChange(event, customer)}
+ onClick={() => handleCheckboxChange1(customer)}
+ />
+ >
+ }
+
+
+ ))}
+ {dropCust?.length != 0 && (
+
+ Total
+
+
+
+ {`${totalQty} `}
+
+
+
+ {`${totalCash?.toFixed(2)} `}
+
+
+ {`${totaldist} `}
+
+
+ {`₹${totalAmt?.toFixed(2)}`}
+
+
+
+
+ )}
+
+ >
+ ) : (
+
+ {/* Header */}
+
+ {' '}
+
+ Important Instructions
+
+
+
+ {/* Ordered List */}
+
+
+ Choose either Upload Type to upload CSV/Excel files, or
+ Selection Type to select from saved customers.
+
+
+
+ Uploaded CSV or Excel files must follow the required format and contain the correct column names.
+
+
+
+ Multiple files can be uploaded, but only one file at a time .
+
+
+
+ Invalid or incorrectly formatted files will not be processed.
+
+
+
+ )}
+
+
+
+
+
+
+ {/* ================================================= || Notes || ================================================= */}
+
+
+
+ setOtherinstructions(e.target.value)}
+ />
+
+
+ {
+ setLoading(true);
+ setBtnLoading(true);
+ createorders();
+ }}
+ sx={{
+ '&:hover': {
+ transform: 'scale(1.05)',
+ transition: 'transform 0.3s ease'
+ }
+ }}
+ >
+ {btnLoading ? : 'Create'}
+
+
+
+
+
+
+ {/* ============================================= || saved address Dialog || ============================================= */}
+ {
+ setIsCustomerOpen(false);
+ }}
+ fullWidth
+ sx={{ minWidth: 'lg' }}
+ >
+
+
+ {`Select Drop Customers (${dropCust.length || 0})`}
+
+
+
+
+
+
+
+
+ {customerlist?.length == 0 ? (
+
+
+
+ ) : (
+
+ {customerlist &&
+ customerlist?.map((customer, index) => (
+
+ cust.customerid === customer.customerid)} // Set the checked state of the checkbox based on whether the customer is in `dropCust`
+ onChange={(event) => handleCheckboxChange(event, customer)}
+ />
+ }
+ label={
+
+
+ {`${customer.firstname} (${customer.contactno})`}
+
+
+
+ {customer.address}
+
+
+ }
+ />
+
+ ))}
+
+ )}
+
+
+
+ {
+ setIsCustomerOpen(false);
+ }}
+ >
+ {dropCust.length == 0 ? 'Close' : 'Continue'}
+
+
+
+ >
+ );
+};
+
+export default MultipleOrders;
diff --git a/src/pages/nearle/orders/multiOrderBackup.js b/src/pages/nearle/orders/multiOrderBackup.js
new file mode 100644
index 0000000..2ba9b65
--- /dev/null
+++ b/src/pages/nearle/orders/multiOrderBackup.js
@@ -0,0 +1,846 @@
+/* eslint-disable no-unused-vars */
+import React from 'react';
+import Loader from 'components/Loader';
+import { useEffect, useState, Fragment } from 'react';
+import { useTheme } from '@mui/material/styles';
+import MainCard from 'components/MainCard';
+import axios from 'axios';
+import ClearIcon from '@mui/icons-material/Clear';
+import { SearchOutlined, CloseOutlined } from '@ant-design/icons';
+import { Empty } from 'antd';
+import MyLocationIcon from '@mui/icons-material/MyLocation';
+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 dayjs from 'dayjs';
+var utc = require('dayjs/plugin/utc');
+dayjs.extend(utc);
+import { enqueueSnackbar } from 'notistack';
+import { useNavigate } from 'react-router';
+import { calculateDrivingDistance, calculateTotalCharge } from '../../../utils/distance';
+import { GoogleMap, LoadScript, Marker } from '@react-google-maps/api';
+
+import {
+ FormControl,
+ InputAdornment,
+ Grid,
+ Typography,
+ Stack,
+ Button,
+ TextField,
+ Autocomplete,
+ Divider,
+ Dialog,
+ DialogTitle,
+ DialogContent,
+ Checkbox,
+ DialogActions,
+ CircularProgress,
+ IconButton,
+ OutlinedInput,
+ FormGroup,
+ FormControlLabel,
+ Table,
+ TableContainer,
+ TableCell,
+ TableBody,
+ TableRow,
+ Paper,
+ TableHead,
+ Box
+} from '@mui/material';
+import CircularLoader from 'components/nearle_components/CircularLoader';
+// import RidersPinPointOSM from './RidersPinPointOSM';
+import RidersPinPoint from './ridersPinPoint';
+
+const MultipleOrders = () => {
+ const navigate = useNavigate();
+ const theme = useTheme();
+ const [loading, setLoading] = useState(false);
+ const [btnLoading, setBtnLoading] = useState(false);
+ const [appId, setAppId] = useState(0);
+
+ const [tenantLocations, setTenantlocations] = useState([]);
+ const userid = localStorage.getItem('userid');
+ const tenId = localStorage.getItem('tenantid');
+ const [tid, setTid] = useState(0);
+ const [isLocation, setIsLocation] = useState(false);
+ const [basePrice, setBasePrice] = useState(0);
+ const [pricePerKm, setPricePerKm] = useState(0);
+ const [minKm, setMinKm] = useState(0);
+ const [pickCust, setPickCust] = useState(null);
+ const [dropCust, setDropCust] = useState([]);
+ const [isCustomerOpen, setIsCustomerOpen] = useState(false);
+ const [searchCustList, setSearchCustList] = useState('');
+ const [customerlist, setCustomerlist] = useState([]);
+ const [startdate, setStartdate] = useState(dayjs().format('MM-DD-YYYY'));
+ const [timeslotarr, setTimeslotarr] = useState([]);
+ const [starttime, setStatrttime] = useState();
+ const [endtime, setEndtime] = useState();
+ const [alertmessage, setAlertmessage] = useState('');
+ const [otherinstructions, setOtherinstructions] = useState('');
+ const [admintoken, setAdmintoken] = useState();
+ const [totaldist, settotaldist] = useState(0);
+ const [totalAmt, settotalAmt] = useState(0);
+ const [isLoading, setIsLoading] = useState(false);
+ const [showMap, setShowMap] = useState(false);
+
+ useEffect(() => {
+ dropCust && console.log('dropCust', dropCust);
+ }, [dropCust]);
+
+ // =============================================== || opentoast || ===============================================
+ const opentoast = (message, variant, time) => {
+ enqueueSnackbar(message, {
+ variant: variant,
+ anchorOrigin: { vertical: 'top', horizontal: 'right' },
+ autoHideDuration: time ? time : 1500
+ });
+ console.log(alertmessage);
+ };
+ // ==============================|| 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);
+ } catch (err) {
+ console.log('locationRes', err);
+ }
+ };
+ useEffect(() => {
+ fetchAppLocations();
+ }, []);
+
+ // ============================================= || fetchTenantPricing || =============================================
+
+ const fetchTenantPricing = async (id) => {
+ try {
+ const pricingResponse = await axios.get(`${process.env.REACT_APP_URL}/tenants/gettenantpricing/?tenantid=${tenId}`);
+ 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(() => {
+ fetchTenantPricing();
+ }, []);
+ // ============================================= || 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) {
+ setIsLocation(true);
+ setTenantlocations(res.data.details);
+ setPickCust(res.data.details[0]);
+ } else {
+ setTenantlocations(res.data.details);
+ }
+ } catch (err) {
+ console.log('gettenantlocations', err);
+ }
+ };
+ useEffect(() => {
+ gettenantlocations(tenId);
+ }, []);
+ // ========================================================= || clientdetails || =========================================================
+ const clientdetails = async () => {
+ try {
+ let url =
+ searchCustList == ''
+ ? `${process.env.REACT_APP_URL}/customers/gettenantcustomers/?tenantid=${tenId}&pageno=1&pagesize=10`
+ : `${process.env.REACT_APP_URL}/customers/search/?tenantid=${tenId}&keyword=${searchCustList}`;
+ await axios
+ .get(url)
+ .then((res) => {
+ if (res.data.status) {
+ console.log('clientdetails', res.data.details);
+
+ setCustomerlist(res.data.details);
+ let arr = [];
+ res.data.details.map((val) => {
+ arr.push({
+ label: `${val.firstname} | ${val.contactno}`,
+ ...val
+ });
+ });
+ }
+ })
+ .catch((err) => {
+ console.log(err);
+ opentoast('server error', 'warning');
+ });
+ } catch (err) {
+ console.log(err);
+ }
+ };
+ useEffect(() => {
+ if (tenId) {
+ clientdetails();
+ }
+ }, [searchCustList.length > 3, searchCustList == '', tenId]);
+
+ // ========================================================= || calculateTotal(dist , charge) || =========================================================
+ const calculateTotal = () => {
+ let a1 = 0;
+ let a2 = 0;
+ dropCust?.map((customer) => {
+ a1 += customer.distance;
+ a2 += customer.totalcharge;
+ });
+ settotaldist(a1);
+ settotalAmt(a2);
+ };
+ useEffect(() => {
+ dropCust && calculateTotal();
+ }, [dropCust]);
+
+ // ========================================================= || handleCheckboxChange || =========================================================
+ const handleCheckboxChange = async (event, customer) => {
+ setIsLoading(true);
+ console.log('event', event.target.checked);
+ console.log('customer', customer);
+ if (event.target.checked) {
+ // If the checkbox is checked, calculate the distance and add the customer
+ try {
+ const obj = await calculateDistance(customer);
+ console.log('return of calculateDistance', obj);
+
+ const { roundedDistance, totalcharge } = obj;
+ // Create a new customer object with the distance property
+ const updatedCustomer = {
+ ...customer,
+ distance: roundedDistance,
+ totalcharge: totalcharge
+ };
+
+ // Add the updated customer object to dropCust
+ setDropCust((prevDropCust) => [...prevDropCust, updatedCustomer]);
+
+ // Log the rounded distance
+ console.log(`Rounded Distance: ${roundedDistance} km`);
+ } catch (error) {
+ console.error('Failed to calculate distance:', error);
+ }
+ setIsLoading(false);
+ } else {
+ // If the checkbox is unchecked, remove the customer from dropCust
+ setDropCust((prevDropCust) => {
+ return prevDropCust.filter((cust) => cust.customerid !== customer.customerid);
+ });
+ setIsLoading(false);
+ }
+ };
+
+ // ========================================================= || calculateDistance || =========================================================
+ const calculateDistance = async (customer) => {
+ console.log('Distance calculation starts');
+ try {
+ const roundedDistance = await calculateDrivingDistance(pickCust, customer);
+ const totalcharge = calculateTotalCharge(roundedDistance, basePrice, pricePerKm, minKm);
+ return { roundedDistance, totalcharge };
+ } catch (error) {
+ console.error('Error calculating distance:', error);
+ throw error;
+ }
+ };
+
+ // ==================================================== || 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) {
+ 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();
+ }
+ }, [starttime, endtime, 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
+ console.log('fetchAppAdminTokens', res);
+ console.log('userfcmtokemArray', userfcmtokemArray);
+ if (res.data.status) {
+ setAdmintoken(userfcmtokemArray);
+ }
+ setLoading(false);
+ })
+ .catch((err) => {
+ console.log(err);
+ setLoading(false);
+ });
+ };
+
+ useEffect(() => {
+ if (starttime && endtime) {
+ fetchAppAdminTokens();
+ }
+ }, [starttime, endtime]);
+
+ useEffect(() => {
+ console.log('pickCust', pickCust);
+ }, [pickCust]);
+
+ // ==================================================== || fetchtenantinfo || ====================================================
+ const fetchtenantinfo = async () => {
+ setLoading(true);
+ console.log('tid', tid);
+
+ await axios
+ .get(`${process.env.REACT_APP_URL}/tenants/gettenantinfo/?tenantid=${tid}`)
+ .then((res) => {
+ console.log('fetchtenantinfo', res);
+ if (res.data.status) {
+ fetchAppAdminTokens();
+ }
+ setLoading(false);
+ })
+ .catch((err) => {
+ console.log(err);
+ setLoading(false);
+ });
+ };
+ useEffect(() => {
+ if (tid) {
+ fetchtenantinfo();
+ }
+ }, [tid]);
+ // ================================================== || 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);
+ });
+ };
+ // =============================================== || creategrouporders || ===============================================
+ const creategrouporders = async () => {
+ const arr = dropCust?.map((customer) => ({
+ applocationid: pickCust.applocationid,
+ cancellled: '',
+ // categoryid: +tenant.categoryid,
+ configid: 9,
+ customerid: customer.customerid,
+ deliveryaddress: customer.address || '',
+ deliverycharge: +customer.totalcharge || 0,
+ deliverycity: customer.city || '',
+ deliverycontactno: customer.contactno || '',
+ deliverycustomer: customer.firstname || '',
+ deliveryid: +customer.customerid,
+ deliverylandmark: customer.landmark || '',
+ deliverylat: customer.latitude,
+ deliverylocation: customer.suburb || '',
+ deliverylocationid: customer.deliverylocationid || 0,
+ deliverylong: customer.longitude,
+ // deliverytime: `${dayjs(startdate).format('YYYY-MM-DD HH:mm:ss')} `,
+ deliverytime: dayjs().format('YYYY-MM-DD HH:mm:ss'),
+ deliverytype: 'B',
+ delivered: '',
+ itemcount: 1,
+ kms: customer.distance.toString() || 0,
+ locationid: +pickCust.locationid,
+ moduleid: +pickCust.moduleid,
+ orderamount: +customer.totalcharge || 0,
+ ordercharges: 0.0,
+ orderdate: dayjs().format('YYYY-MM-DD HH:mm:ss'),
+ orderheaderid: 0,
+ orderid: '', //
+ ordernotes: otherinstructions,
+ orderstatus: 'created',
+ ordervalue: +customer.totalcharge || 0,
+ partnerid: pickCust.partnerid,
+ partneruserid: +userid,
+ paymentstatus: 1,
+ paymenttype: 42,
+ pending: '',
+ pickupaddress: pickCust.address || '',
+ pickupcity: pickCust.locationcity || '',
+ pickupcontactno: pickCust.contactno || '',
+ pickupcustomer: pickCust.locationname || '',
+ pickuplandmark: pickCust.landmark || '',
+ pickuplat: pickCust.latitude,
+ pickuplocation: pickCust.suburb || '',
+ pickuplocationid: pickCust.locationid || 0,
+ pickuplong: pickCust.longitude,
+ processing: '',
+ ready: '',
+ remarks: '',
+ taxamount: 0.0,
+ tenantid: pickCust.tenantid,
+ tenantuserid: 0
+ }));
+ console.log('arr', arr);
+
+ if (!tenId) {
+ opentoast('Choose Client ', 'warning');
+ } else {
+ setLoading(true);
+
+ await axios
+ .post(`${process.env.REACT_APP_URL}/orders/createorders`, arr)
+ .then((res) => {
+ if (res.data.status) {
+ enqueueSnackbar('Order Created Successfully', {
+ variant: 'success',
+ anchorOrigin: { vertical: 'top', horizontal: 'right' },
+ autoHideDuration: 1000
+ });
+ if (admintoken) {
+ // notifyadmin(admintoken);
+ sendnotifications();
+ }
+ navigate('/nearle/orders');
+ } else {
+ opentoast(res.data.message, 'warning');
+ }
+ setLoading(false);
+ console.log(res);
+ })
+ .catch((err) => {
+ console.log(err);
+ // opentoast(err.data.message, 'warning');
+ setLoading(false);
+ });
+ }
+ console.log(arr);
+ };
+
+ return (
+ <>
+ {loading && }
+ {/* */}
+
+
+
+
+ Multiple Orders
+
+
+
+
+
+ {/* Business Location */}
+
+ {tenantLocations?.length === 1 ? (
+
+
+
+ )
+ }}
+ />
+ ) : (
+ `${option.locationname} (${option.suburb})`}
+ onChange={(event, value, reason) => {
+ if (value) {
+ setTid(value.tenantid);
+ setIsLocation(true);
+ setPickCust(value);
+ }
+ if (reason === 'clear') setIsLocation(false);
+ }}
+ renderInput={(params) => }
+ />
+ )}
+
+
+ {/* Date Picker */}
+
+
+ {
+ let diff = dayjs().diff(dayjs(dayjs(e).format('YYYY-MM-DD')), 'd');
+
+ if (diff <= 0) {
+ setStartdate(e);
+
+ let arr = [];
+ timeslotarr.forEach((val) => {
+ if (dayjs().diff(dayjs(`${dayjs(e).format('MM-DD-YYYY')} ${dayjs(val).format('HH:mm:ss')}`), 'm') <= 0) {
+ arr.push(val);
+ }
+ });
+
+ if (arr[0]) {
+ setOrderarr([
+ {
+ sno: 1,
+ address: '',
+ customerid: '',
+ deliverytime: dayjs(arr[0]),
+ deliverylocationid: '',
+ clientname: '',
+ contactno: '',
+ latitude: '',
+ longitude: ''
+ }
+ ]);
+ } else {
+ setOrderarr([]);
+ }
+ } else {
+ opentoast('choose Upcoming Date', 'warning');
+ setStartdate(NaN);
+ }
+ }}
+ />
+
+
+
+
+
+
+ {/* ===================================================== || Pickup || ===================================================== */}
+ {pickCust && (
+
+
+
+
+ Pickup Location
+ Address
+
+
+
+
+ {pickCust?.locationname}
+ {pickCust?.address}
+
+
+
+
+ )}
+
+ {/* ===================================================== || Drop || ===================================================== */}
+
+ {
+ if (!isLocation) {
+ opentoast('Select Business Location', 'warning');
+ } else {
+ setIsCustomerOpen(true);
+ setSearchCustList('');
+ }
+ }}
+ >
+ Select Customers
+
+ }
+ >
+
+
+
+
+ S.No
+ Customer
+ Address
+ Kms
+ Charge
+ Action
+
+
+
+ {!dropCust && (
+
+
+
+
+
+ )}
+ {dropCust?.map((customer, index) => (
+
+ {index + 1}
+ {customer.firstname}
+ {customer.address}
+ {customer.distance}
+ {`₹${customer.totalcharge}.00`}
+
+ {
+ handleCheckboxChange(event, customer)}
+ />
+ }
+
+
+ ))}
+ {dropCust?.length != 0 && (
+
+
+ Total
+
+
+
+
+ {`${totaldist} `}
+
+
+ {`₹${totalAmt}.00`}
+
+
+
+ )}
+
+
+
+
+
+ {/* ================================================= || Riders Map || ================================================= */}
+
+ {/* {showMap && dropCust.length >= 1 && } */}
+
+ {/* ================================================= || Notes || ================================================= */}
+ {dropCust && (
+
+
+
+ setOtherinstructions(e.target.value)}
+ />
+
+
+ {
+ setLoading(true);
+ setBtnLoading(true);
+ creategrouporders();
+ setTimeout(() => {
+ setLoading(false);
+ setBtnLoading(false);
+ }, 2000);
+ }}
+ sx={{
+ '&:hover': {
+ transform: 'scale(1.05)',
+ transition: 'transform 0.3s ease'
+ }
+ }}
+ >
+ {btnLoading ? : 'Create'}
+
+
+
+
+ )}
+
+ {/* ============================================= || saved address Dialog || ============================================= */}
+ {
+ setIsCustomerOpen(false);
+ }}
+ fullWidth
+ sx={{ minWidth: 'lg' }}
+ >
+ {isLoading && }
+
+
+ {`Select Drop Customers (${dropCust?.length || 0})`}
+
+
+
+
+
+
+
+
+ {customerlist.length == 0 ? (
+
+
+
+ ) : (
+
+ {customerlist &&
+ customerlist.map((customer, index) => (
+
+ cust.customerid === customer.customerid)} // Set the checked state of the checkbox based on whether the customer is in `dropCust`
+ onChange={(event) => handleCheckboxChange(event, customer)}
+ />
+ }
+ label={
+
+
+ {`${customer.firstname} (${customer.contactno})`}
+
+
+
+ {customer.address}
+
+
+ }
+ />
+
+ ))}
+
+ )}
+
+
+
+ {
+ setIsCustomerOpen(false);
+ {
+ dropCust?.length !== 0 && setShowMap(true);
+ }
+ }}
+ >
+ {dropCust?.length !== 0 ? 'Continue' : 'Close'}
+
+
+
+ >
+ );
+};
+
+export default MultipleOrders;
diff --git a/src/pages/nearle/orders/multipleOrders.js b/src/pages/nearle/orders/multipleOrders.js
index 834226f..a1f99f3 100644
--- a/src/pages/nearle/orders/multipleOrders.js
+++ b/src/pages/nearle/orders/multipleOrders.js
@@ -1,4 +1,5 @@
-import React, { useEffect, useState, useRef, Fragment } from 'react';
+/* eslint-disable no-unused-vars */
+import React, { useEffect, useState, useRef } from 'react';
import axios from 'axios';
import Papa from 'papaparse';
import * as XLSX from 'xlsx';
@@ -55,9 +56,7 @@ import {
CalendarOutlined,
ClockCircleOutlined,
FileTextOutlined,
- InboxOutlined,
- LockOutlined,
- CheckCircleFilled
+ InboxOutlined
} from '@ant-design/icons';
import { Empty } from 'antd';
import { FaUser, FaTruck, FaUsers, FaPaperPlane, FaRoute, FaMoneyBillWave, FaBoxes, FaReceipt } from 'react-icons/fa';
@@ -66,47 +65,31 @@ import { MdOutlineCloudUpload } from 'react-icons/md';
import Loader from 'components/Loader';
import CircularLoader from 'components/CircularLoader';
-import AnimateButton from 'components/@extended/AnimateButton';
-import { MobileCard, MobileCardList, MobileField, MobileFieldGrid } from 'components/nearle_components/MobileCard';
import './OrdersRedesign.css';
var utc = require('dayjs/plugin/utc');
dayjs.extend(utc);
-// ============================== small style tokens ==============================
-const cellHeaderSx = {
- fontSize: 11.5,
- fontWeight: 700,
- color: '#475569',
- py: 0.75,
- px: 1
-};
-
-const cellBodySx = {
- fontSize: 12,
- py: 0.6,
- px: 1
-};
+const cellHeaderSx = { fontSize: 11.5, fontWeight: 700, color: '#475569', py: 0.75, px: 1 };
+const cellBodySx = { fontSize: 12, py: 0.6, px: 1 };
const MultipleOrders = () => {
const navigate = useNavigate();
const theme = useTheme();
const isMobile = useMediaQuery(theme.breakpoints.down('md'));
const locationRef = useRef(null);
- const tenantRef = useRef(null);
const userid = localStorage.getItem('userid');
+ // tenantid is fixed for this app — comes from the logged-in session
+ const tenantid = localStorage.getItem('tenantid');
// ============================== state ==============================
const [locations, setLocations] = useState([]);
- const [tenantlist, setTenantlist] = useState([]);
const [tenantLocations, setTenantlocations] = useState([]);
const [loading, setLoading] = useState(false);
const [btnLoading, setBtnLoading] = useState(false);
const [appId, setAppId] = useState(0);
- const [tenantid, setTenantid] = useState(0);
const [locationid, setLocationid] = useState(0);
- const [tenantValue, setTenantValue] = useState(null);
const [locationValue, setLocationValue] = useState(null);
const [basePrice, setBasePrice] = useState(0);
@@ -135,18 +118,16 @@ const MultipleOrders = () => {
const [uploadType, setUploadType] = useState(null);
const [users, setUsers] = useState([]);
const [fileName, setFileName] = useState('');
+ const [slotDropdownOpen, setSlotDropdownOpen] = useState(false);
- // Stable dedup cache for OpenToast. Was a `let` inside the component body,
- // which got recreated on every render and broke the dedup. A ref persists
- // across renders without triggering re-renders itself.
const toastCacheRef = useRef({});
// ============================== toast ==============================
const opentoast = (message, variant, time) => {
enqueueSnackbar(message, {
- variant: variant,
+ variant,
anchorOrigin: { vertical: 'top', horizontal: 'right' },
- autoHideDuration: time ? time : 1500
+ autoHideDuration: time || 1500
});
};
@@ -158,15 +139,10 @@ const MultipleOrders = () => {
setTimeout(() => delete toastCacheRef.current[key], 3000);
};
- // ============================== effects: reset chains ==============================
+ // ============================== reset chains ==============================
useEffect(() => {
- // appId change → clear downstream selections (tenant, location, customers)
- setTenantid(0);
- setTenantValue(null);
setLocationid(0);
setLocationValue(null);
- setTenantlocations([]);
- setPickCust(null);
setDropCust([]);
setUsers([]);
setUploadType(null);
@@ -176,22 +152,12 @@ const MultipleOrders = () => {
setSelectedtime('');
}, [appId]);
- useEffect(() => {
- // tenantid change → clear location/customers (keep appId)
- setLocationid(0);
- setLocationValue(null);
- setDropCust([]);
- setUsers([]);
- setUploadType(null);
- setFileName('');
- }, [tenantid]);
-
// ============================== fetchAppLocations ==============================
const fetchAppLocations = async () => {
setLoading(true);
try {
- const locationRes = await axios.get(`${process.env.REACT_APP_URL}/partners/getlocations/?userid=${userid}`);
- setLocations(locationRes.data.details || []);
+ const res = await axios.get(`${process.env.REACT_APP_URL}/partners/getlocations/?userid=${userid}`);
+ setLocations(res.data.details || []);
} catch (err) {
OpenToast(err.message, 'error', 5000);
} finally {
@@ -199,29 +165,7 @@ const MultipleOrders = () => {
}
};
- useEffect(() => {
- fetchAppLocations();
- }, []);
-
- // ============================== fetchtenantinfolist ==============================
- const fetchtenantinfolist = async () => {
- setLoading(true);
- try {
- const res = await axios.get(`${process.env.REACT_APP_URL}/tenants/gettenants/?applocationid=${appId}&status=active`);
- if (res.data.status) {
- const arr = (res.data.details || []).map((val) => ({ ...val, label: `${val.tenantname}` }));
- setTenantlist(arr);
- }
- } catch (err) {
- OpenToast('Failed to load clients', 'warning', 3000);
- } finally {
- setLoading(false);
- }
- };
-
- useEffect(() => {
- if (appId) fetchtenantinfolist();
- }, [appId]);
+ useEffect(() => { fetchAppLocations(); }, []);
// ============================== fetchTenantPricing ==============================
const fetchTenantPricing = async (id) => {
@@ -231,11 +175,13 @@ const MultipleOrders = () => {
setBasePrice(d.baseprice || 0);
setPricePerKm(d.priceperkm || 0);
setMinKm(d.minkm || 0);
- } catch (error) {
- console.log('fetchTenantPricing error', error);
+ } catch (err) {
+ console.log('fetchTenantPricing', err);
}
};
+ useEffect(() => { if (tenantid) fetchTenantPricing(tenantid); }, []);
+
// ============================== gettenantlocations ==============================
const gettenantlocations = async (id) => {
try {
@@ -255,24 +201,23 @@ const MultipleOrders = () => {
}
};
+ useEffect(() => { if (tenantid) gettenantlocations(tenantid); }, []);
+
// ============================== clientdetails ==============================
const clientdetails = async () => {
try {
- const 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}`;
+ const 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}`;
const res = await axios.get(url);
if (res.data.status) setCustomerlist(res.data.details || []);
} catch (err) {
- console.log(err);
opentoast('server error', 'warning');
}
};
useEffect(() => {
if (!tenantid) return;
- // Light debounce so we don't fire on every keystroke.
const t = setTimeout(() => {
if (searchCustList === '' || searchCustList.length > 2) clientdetails();
}, 250);
@@ -281,10 +226,7 @@ const MultipleOrders = () => {
// ============================== totals ==============================
useEffect(() => {
- let a1 = 0;
- let a2 = 0;
- let a3 = 0;
- let a4 = 0;
+ let a1 = 0, a2 = 0, a3 = 0, a4 = 0;
dropCust.forEach((c) => {
a1 += Number(c.distance) || 0;
a2 += Number(c.totalcharge) || 0;
@@ -297,6 +239,7 @@ const MultipleOrders = () => {
settotalCash(a4);
}, [dropCust]);
+ // ============================== distance (Google) ==============================
// ============================== distance (OSRM/Haversine) ==============================
const calculateDistance = async (customer) => {
try {
@@ -316,7 +259,7 @@ const MultipleOrders = () => {
}
};
- // ============================== handleCheckboxChange (dialog: add/remove on tick) ==============================
+ // ============================== checkbox handlers ==============================
const handleCheckboxChange = async (event, customer) => {
setLoading(true);
try {
@@ -333,31 +276,18 @@ const MultipleOrders = () => {
}
};
- // Toggle handler used by:
- // 1. CSV "Continue" bulk add (matches by firstname since uploaded rows
- // don't carry a stable customerid).
- // 2. Per-row remove (CloseOutlined) in the drop table.
- // Uses a single functional updater + locally-captured already-selected flag
- // so we don't read stale `dropCust` after the state change.
const handleCheckboxChange1 = async (customer) => {
- // Compute "already selected" from the latest state synchronously.
let wasSelected = false;
setDropCust((prev) => {
wasSelected = prev.some((c) => c.firstname === customer.firstname);
- if (wasSelected) {
- return prev.filter((c) => c.firstname !== customer.firstname);
- }
+ if (wasSelected) return prev.filter((c) => c.firstname !== customer.firstname);
return prev;
});
-
- if (wasSelected) return; // remove path is done
-
- // Add path — compute distance, then append.
+ if (wasSelected) return;
setLoading(true);
try {
const { roundedDistance, totalcharge } = await calculateDistance(customer);
setDropCust((prev) => {
- // Guard against parallel adds for the same row.
if (prev.some((c) => c.firstname === customer.firstname)) return prev;
return [...prev, { ...customer, distance: roundedDistance, totalcharge }];
});
@@ -381,9 +311,7 @@ const MultipleOrders = () => {
}
};
- useEffect(() => {
- if (appId) fetchAppAdminTokens();
- }, [appId]);
+ useEffect(() => { if (appId) fetchAppAdminTokens(); }, [appId]);
// ============================== sendnotifications ==============================
const sendnotifications = async () => {
@@ -392,15 +320,9 @@ const MultipleOrders = () => {
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'
- }
+ notification: { title: 'Nearle Merchant', body: 'An Order has been placed successfully, kindly process the same', sound: 'ring' }
});
- if (res.data.message === 'Success') {
- opentoast('Notification sent Successfully', 'success', 1000);
- }
+ if (res.data.message === 'Success') opentoast('Notification sent Successfully', 'success', 1000);
} catch (err) {
opentoast(err.message, 'error', 1000);
}
@@ -423,31 +345,21 @@ const MultipleOrders = () => {
receiverlongitude: 'longitude',
'itemdescription*': 'description',
Quantity: 'quantity',
- ' Collect Cash': 'collectionamt',
- customerDeliveryTime: 'customerdeliverytime',
- kitchenPickupTime: 'kitchenpickuptime'
+ ' Collect Cash': 'collectionamt'
};
const handleFileDirectUpload = (event) => {
try {
const file = event.target.files?.[0];
- if (!file) {
- opentoast('No file selected.', 'warning');
- return;
- }
+ if (!file) { opentoast('No file selected.', 'warning'); return; }
const fileNameLower = file.name.toLowerCase();
const isCSV = fileNameLower.endsWith('.csv');
const isExcel = fileNameLower.endsWith('.xls') || fileNameLower.endsWith('.xlsx');
-
- if (!isCSV && !isExcel) {
- opentoast('Invalid file type. Please upload a CSV or Excel file.', 'warning');
- return;
- }
+ if (!isCSV && !isExcel) { opentoast('Invalid file type. Please upload a CSV or Excel file.', 'warning'); return; }
const processData = (data, headers) => {
const normalizedMap = {};
for (const key in headerMap) normalizedMap[normalizeHeader(key)] = headerMap[key];
-
const mappedData = data.map((row) => {
const newRow = {};
for (const key in row) {
@@ -459,17 +371,11 @@ const MultipleOrders = () => {
}
return newRow;
});
-
const requiredCols = Object.keys(headerMap).filter((k) => k.trim().endsWith('*'));
- const missingRequired = requiredCols.filter(
- (clientCol) => !headers.includes(normalizeHeader(clientCol))
- );
+ const missingRequired = requiredCols.filter((clientCol) => !headers.includes(normalizeHeader(clientCol)));
if (missingRequired.length > 0) {
- opentoast(`Missing required columns: ${missingRequired.join(', ')}`, 'warning', 3000);
- setUsers([]);
- return;
+ opentoast(`Missing columns: ${missingRequired.join(', ')}`, 'warning', 3000);
}
-
setUsers(mappedData);
opentoast('File uploaded successfully', 'success', 2000);
opentoast('Press Continue to add as drop customers', 'info', 2500);
@@ -477,38 +383,22 @@ const MultipleOrders = () => {
if (isCSV) {
Papa.parse(file, {
- header: true,
- dynamicTyping: true,
- skipEmptyLines: true,
+ header: true, dynamicTyping: true, skipEmptyLines: true,
complete: (results) => {
- if (!results.data?.length) {
- opentoast('CSV file is empty or has no valid rows.', 'warning');
- setUsers([]);
- return;
- }
- const headers = results.meta.fields.map(normalizeHeader);
- processData(results.data, headers);
+ if (!results.data?.length) { opentoast('CSV file is empty or has no valid rows.', 'warning'); setUsers([]); return; }
+ processData(results.data, results.meta.fields.map(normalizeHeader));
},
error: (error) => opentoast(`CSV parsing failed: ${error.message}`, 'warning')
});
}
-
if (isExcel) {
const reader = new FileReader();
reader.onload = (e) => {
try {
- const data = e.target.result;
- const workbook = XLSX.read(data, { type: 'binary' });
- const firstSheet = workbook.SheetNames[0];
- const worksheet = workbook.Sheets[firstSheet];
- const jsonData = XLSX.utils.sheet_to_json(worksheet, { defval: '' });
- if (!jsonData?.length) {
- opentoast('Excel file is empty or invalid.', 'warning');
- setUsers([]);
- return;
- }
- const headers = Object.keys(jsonData[0]).map(normalizeHeader);
- processData(jsonData, headers);
+ const workbook = XLSX.read(e.target.result, { type: 'binary' });
+ const jsonData = XLSX.utils.sheet_to_json(workbook.Sheets[workbook.SheetNames[0]], { defval: '' });
+ if (!jsonData?.length) { opentoast('Excel file is empty or invalid.', 'warning'); setUsers([]); return; }
+ processData(jsonData, Object.keys(jsonData[0]).map(normalizeHeader));
} catch (err) {
opentoast(`Error reading Excel: ${err.message}`, 'warning');
}
@@ -537,44 +427,27 @@ const MultipleOrders = () => {
setDropCust((prev) => prev.map((c) => (c.customerid === customerid ? { ...c, collectionamt: Number(value) || 0 } : c)));
};
- // ============================== createorders ==============================
+ // ============================== buildDeliveryTime ==============================
const buildDeliveryTime = () => {
- // Prefer the parsed pickupSlot (already merged date + slot's time).
- // Fall back to startdate + selectedtime when present.
if (pickupSlot) {
const parsed = dayjs(pickupSlot, ['YYYY-MM-DD hh:mm A', 'YYYY-MM-DD HH:mm:ss']);
if (parsed.isValid()) return parsed.format('YYYY-MM-DD HH:mm:ss');
}
if (startdate && selectedtime) {
- const parsed = dayjs(`${dayjs(startdate).format('YYYY-MM-DD')} ${selectedtime}`, [
- 'YYYY-MM-DD hh:mm A',
- 'YYYY-MM-DD HH:mm:ss'
- ]);
+ const parsed = dayjs(`${dayjs(startdate).format('YYYY-MM-DD')} ${selectedtime}`, ['YYYY-MM-DD hh:mm A', 'YYYY-MM-DD HH:mm:ss']);
if (parsed.isValid()) return parsed.format('YYYY-MM-DD HH:mm:ss');
}
return dayjs().format('YYYY-MM-DD HH:mm:ss');
};
+ // ============================== createorders ==============================
const createorders = async () => {
- if (!tenantid) {
- opentoast('Choose Client', 'warning');
- return;
- }
- if (!pickCust) {
- opentoast('Pickup location required', 'warning');
- return;
- }
- if (!pickupSlot) {
- opentoast('Select a pickup slot', 'warning');
- return;
- }
- if (!dropCust.length) {
- opentoast('Add at least one drop customer', 'warning');
- return;
- }
+ if (!tenantid) { opentoast('Client not found. Please re-login.', 'warning'); return; }
+ if (!pickCust) { opentoast('Pickup location required', 'warning'); return; }
+ if (!pickupSlot) { opentoast('Select a pickup slot', 'warning'); return; }
+ if (!dropCust.length) { opentoast('Add at least one drop customer', 'warning'); return; }
const deliverytime = buildDeliveryTime();
-
const arr = dropCust.map((customer) => ({
applocationid: pickCust.applocationid,
configid: 9,
@@ -592,7 +465,6 @@ const MultipleOrders = () => {
pickuplocationid: pickCust.locationid || 0,
pickuplong: pickCust.longitude,
tenantid: pickCust.tenantid,
-
customerid: +customer?.customerid,
deliveryaddress: customer.address || '',
deliverycharge: +customer.totalcharge || 0,
@@ -607,14 +479,12 @@ const MultipleOrders = () => {
deliverylong: customer.longitude?.toString() || '',
deliverytime,
deliverytype: 'B',
-
itemcount: 1,
quantity: customer.quantity,
collectionamt: customer.collectionamt,
kms: customer.distance?.toString() || '0',
locationid: +pickCust.locationid,
moduleid: +pickCust.moduleid,
-
orderamount: +customer.totalcharge || 0,
ordercharges: 0.0,
orderdate: dayjs().format('YYYY-MM-DD HH:mm:ss'),
@@ -636,13 +506,8 @@ const MultipleOrders = () => {
opentoast(res?.data?.message || 'Order creation failed. Please try again.', 'warning', 3000);
}
} catch (err) {
- let toastMessage = 'Something went wrong. Please try again.';
- if (err.response) {
- toastMessage = err.response.data?.message || `Server error (${err.response.status})`;
- } else if (err.request) {
- toastMessage = 'Network error. Check your internet connection.';
- }
- opentoast(toastMessage, 'error', 3000);
+ const msg = err.response ? err.response.data?.message || `Server error (${err.response.status})` : err.request ? 'Network error. Check your internet connection.' : 'Something went wrong.';
+ opentoast(msg, 'error', 3000);
} finally {
setLoading(false);
setBtnLoading(false);
@@ -650,21 +515,8 @@ const MultipleOrders = () => {
};
// ============================== derived ==============================
- const stepsComplete = {
- location: !!appId,
- client: !!tenantid,
- business: !!locationid,
- schedule: !!pickupSlot,
- drops: dropCust.length > 0
- };
- const canSubmit =
- stepsComplete.location && stepsComplete.client && stepsComplete.business && stepsComplete.schedule && stepsComplete.drops;
-
- // ============================== preview helpers ==============================
- // The right pane shows three exclusive views:
- // 1. dropCust.length > 0 → "Drop List" with calculated charges + remove
- // 2. users.length > 0 → raw "File Preview" of parsed rows, awaiting Continue
- // 3. else → empty state
+ const canSubmit = !!locationid && !!pickupSlot && dropCust.length > 0;
+ const prereqOk = !!locationid;
const previewMode = dropCust.length > 0 ? 'drops' : users.length > 0 ? 'preview' : 'empty';
// ============================== render ==============================
@@ -675,7 +527,6 @@ const MultipleOrders = () => {
- {/* Outer viewport-locked shell — page never scrolls; panes scroll internally. */}
{
gap: 1
}}
>
- {/* Thin title bar */}
-
+ {/* Title bar */}
+
Create Multiple Orders
@@ -703,9 +548,7 @@ const MultipleOrders = () => {
size="small"
label={`${dropCust.length} drop${dropCust.length === 1 ? '' : 's'}`}
sx={{
- height: 20,
- fontSize: 10.5,
- fontWeight: 700,
+ height: 20, fontSize: 10.5, fontWeight: 700,
bgcolor: dropCust.length ? 'rgba(24,144,255,0.10)' : '#f1f5f9',
color: dropCust.length ? '#1890ff' : '#94a3b8',
border: `1px solid ${dropCust.length ? 'rgba(24,144,255,0.25)' : '#e2e8f0'}`
@@ -717,155 +560,57 @@ const MultipleOrders = () => {
- {/* ============================== 50 / 50 workspace ============================== */}
-
- {/* ============================== LEFT 50% : Input fields ============================== */}
+ {/* 50 / 50 workspace */}
+
+
+ {/* LEFT — input fields */}
- {/* Card: Setup (Location / Client / Business) */}
+ {/* Card: Schedule & Pickup */}
-
+
- Setup
+ Schedule & Pickup
-
- `${option.locationname}`}
- onChange={(event, value, reason) => {
- if (reason === 'clear') setAppId(0);
- else if (value) setAppId(value.applocationid);
- }}
- renderInput={(params) => (
-
-
- {params.InputProps.startAdornment}
- >
- )
- }}
- />
- )}
- />
-
-
- option?.tenantname || ''}
- isOptionEqualToValue={(option, value) => option.tenantid === value.tenantid}
- onOpen={(event) => {
- if (!appId) {
- event.preventDefault();
- OpenToast('Please select Location first!', 'warning', 3000);
- setTimeout(() => locationRef.current?.focus(), 0);
- }
- }}
- onChange={(e, val, reason) => {
- if (reason === 'clear') {
- setTenantid(0);
- setTenantValue(null);
- } else if (val) {
- setTenantid(val.tenantid);
- setTenantValue(val);
- fetchTenantPricing(val.tenantid);
- gettenantlocations(val.tenantid);
- }
- }}
- renderInput={(params) => (
-
-
- {params.InputProps.startAdornment}
- >
- )
- }}
- />
- )}
- />
-
-
- {tenantLocations.length === 1 ? (
+
+ {tenantLocations?.length === 1 ? (
+
+
+
)
}}
+ sx={{
+ '& .MuiOutlinedInput-root': { borderRadius: '10px', height: '36px', alignItems: 'center' },
+ '& .MuiOutlinedInput-input': { padding: '0 14px !important' }
+ }}
/>
) : (
- option?.locationname ? `${option.locationname} (${option.suburb || ''})` : ''
- }
- onOpen={(event) => {
- if (!appId && !tenantid) {
- event.preventDefault();
- OpenToast('Please select Location and Client first!', 'warning', 3000);
- setTimeout(() => locationRef.current?.focus(), 0);
- } else if (!tenantid) {
- event.preventDefault();
- OpenToast('Please select Client first!', 'warning', 3000);
- setTimeout(() => tenantRef.current?.focus(), 0);
- }
- }}
+ getOptionLabel={(option) => option ? `${option.locationname} (${option.suburb || option.locationsuburb || ''})` : ''}
+ value={locationValue}
onChange={(event, value, reason) => {
if (reason === 'clear' || !value) {
setLocationid(0);
@@ -876,200 +621,126 @@ const MultipleOrders = () => {
setLocationid(value.locationid || 0);
setLocationValue(value);
setPickCust(value);
- setPickupSlotsList(value?.slots);
+ setPickupSlotsList(value?.slots || null);
}
}}
renderInput={(params) => (
-
- {params.InputProps.startAdornment}
- >
- )
- }}
/>
)}
+ sx={{
+ '& .MuiOutlinedInput-root': { borderRadius: '10px', height: '36px', alignItems: 'center', padding: '0 9px !important' },
+ '& .MuiAutocomplete-input': { padding: '0 !important' }
+ }}
/>
)}
+
+
+ {
+ if (!e || !dayjs(e).isValid()) { setStartdate(dayjs().format('MM-DD-YYYY')); return; }
+ const diffDays = dayjs().diff(dayjs(dayjs(e).format('YYYY-MM-DD')), 'd');
+ if (diffDays <= 0) {
+ setStartdate(dayjs(e).format('MM-DD-YYYY'));
+ setSelectedtime('');
+ setPickupSlot(null);
+ } else {
+ opentoast('Choose an upcoming date', 'warning');
+ setStartdate(dayjs().format('MM-DD-YYYY'));
+ }
+ }}
+ disablePast
+ slotProps={{
+ textField: {
+ size: 'small', fullWidth: true, InputLabelProps: { shrink: true },
+ InputProps: {
+ startAdornment: (
+
+
+
+ )
+ },
+ sx: { '& .MuiOutlinedInput-root': { borderRadius: '10px', height: '36px' } }
+ }
+ }}
+ />
+
+
+
+ {
+ if (!locationid) {
+ OpenToast('Please select a Business Location first.', 'warning', 3000);
+ return;
+ }
+ setSlotDropdownOpen(true);
+ }}
+ onClose={() => setSlotDropdownOpen(false)}
+ sx={{
+ '& .MuiOutlinedInput-root': { borderRadius: '10px', height: '36px', alignItems: 'center', padding: '0 9px !important' },
+ '& .MuiAutocomplete-input': { padding: '0 !important' }
+ }}
+ onChange={(e, newValue, reason) => {
+ if (reason === 'clear' || !newValue) { setSelectedtime(null); setPickupSlot(null); return; }
+ if (!newValue.time) { OpenToast('This slot has no time configured.', 'warning', 3000); return; }
+ 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) => (
+
+
+
+ )
+ }}
+ />
+ )}
+ />
+
+
+ {pickCust ? (
+
+
+
+
+
+
+ {pickCust.locationname || '—'}
+
+
+ {pickCust.address || '—'}
+
+
+
+ ) : (
+
+ Pickup auto-fills once a Business Location is selected.
+
+ )}
+
- {/* Card: Schedule + Pickup display */}
-
-
-
- Schedule & Pickup
-
-
-
-
-
- {
- if (!e || !dayjs(e).isValid()) {
- setStartdate(dayjs().format('MM-DD-YYYY'));
- return;
- }
- const diffDays = dayjs().diff(dayjs(`${dayjs(e).format('YYYY-MM-DD')}`), 'd');
- if (diffDays <= 0) {
- setStartdate(dayjs(e).format('MM-DD-YYYY'));
- setSelectedtime('');
- setPickupSlot(null);
- } else {
- opentoast('Choose an upcoming date', 'warning');
- setStartdate(dayjs().format('MM-DD-YYYY'));
- }
- }}
- disablePast
- slotProps={{
- textField: {
- size: 'small',
- fullWidth: true,
- InputLabelProps: { shrink: true },
- InputProps: {
- startAdornment: (
-
-
-
- )
- },
- sx: {
- '& .MuiOutlinedInput-root': {
- borderRadius: '10px',
- height: '36px',
- paddingLeft: '10px'
- }
- }
- }
- }}
- />
-
-
-
- {
- if (reason === 'clear' || !newValue) {
- setSelectedtime(null);
- setPickupSlot(null);
- return;
- }
- if (!newValue.time) {
- OpenToast('This slot has no time configured.', 'warning', 3000);
- return;
- }
- 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) => (
-
-
- {params.InputProps.startAdornment}
- >
- )
- }}
- />
- )}
- />
-
-
- {/* Pickup display (compact, single row) */}
-
- {pickCust ? (
-
-
-
-
-
-
- {pickCust.locationname || '—'}
-
-
- {pickCust.address || '—'}
-
-
-
- ) : (
-
- Pickup auto-fills once a Business Location is selected.
-
- )}
-
-
-
-
-
-
{/* Card: Notes */}
@@ -1083,26 +754,13 @@ const MultipleOrders = () => {
Special Dispatch Notes
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'
- }
+ '& .MuiOutlinedInput-root': { borderRadius: '10px', height: '36px', alignItems: 'center', fontSize: '12px', background: '#ffffff' },
+ '& .MuiOutlinedInput-input': { padding: '0 14px !important', fontSize: '12px' }
}}
/>
@@ -1112,106 +770,27 @@ const MultipleOrders = () => {
{/* Card: Summary + Submit */}
-
- Bulk Summary
-
-
- Live totals
-
+ Bulk Summary
+ Live totals
{(() => {
const metric = ({ icon: Icon, label, value, accent, active }) => (
-
-
+
+
-
- {label}
-
-
- {value}
-
+ {label}
+ {value}
);
return (
-
- {metric({
- icon: FaRoute,
- label: 'Distance',
- value: totaldist ? `${totaldist} km` : '—',
- accent: '#1890ff',
- active: !!totaldist
- })}
-
-
- {metric({
- icon: FaBoxes,
- label: 'Quantity',
- value: totalQty || 0,
- accent: '#16a34a',
- active: !!totalQty
- })}
-
-
- {metric({
- icon: FaMoneyBillWave,
- label: 'Cash Collect',
- value: `₹${Number(totalCash).toFixed(2)}`,
- accent: '#d97706',
- active: !!totalCash
- })}
-
-
- {metric({
- icon: FaTruck,
- label: 'Deliveries',
- value: dropCust.length,
- accent: '#65387a',
- active: dropCust.length > 0
- })}
-
+ {metric({ icon: FaRoute, label: 'Distance', value: totaldist ? `${totaldist} km` : '—', accent: '#1890ff', active: !!totaldist })}
+ {metric({ icon: FaBoxes, label: 'Quantity', value: totalQty || 0, accent: '#16a34a', active: !!totalQty })}
+ {metric({ icon: FaMoneyBillWave, label: 'Cash Collect', value: `₹${Number(totalCash).toFixed(2)}`, accent: '#d97706', active: !!totalCash })}
+ {metric({ icon: FaTruck, label: 'Deliveries', value: dropCust.length, accent: '#65387a', active: dropCust.length > 0 })}
);
})()}
@@ -1222,162 +801,65 @@ const MultipleOrders = () => {
Total Charge