Files
Doormilexpress_app/src/pages/nearle/orders/details.js

1715 lines
70 KiB
JavaScript

import {
useEffect, useState, Fragment
} from 'react';
import {
useLocation,
useNavigate
} from 'react-router-dom';
import axios from 'axios';
import {
EnvironmentOutlined,
EditTwoTone,
DeleteFilled,
NotificationOutlined,
CloseOutlined,
WarningOutlined
} from '@ant-design/icons';
var utc = require('dayjs/plugin/utc')
import MainCard from 'components/MainCard';
import Loader from 'components/Loader';
import dayjs from 'dayjs';
dayjs.extend(utc)
import { enqueueSnackbar } from 'notistack';
import {
MdLocalShipping,
MdHourglassEmpty,
MdCheckCircle,
MdCancel,
MdAccessTime,
MdHistoryToggleOff,
MdAssignmentTurnedIn,
MdEdit,
MdArrowBack,
MdReceiptLong,
MdDirectionsCar,
MdKeyboardArrowUp,
MdKeyboardArrowDown
} from 'react-icons/md';
import { Button } from '@astryxdesign/core/Button';
import { IconButton } from '@astryxdesign/core/IconButton';
import { Tooltip } from '@astryxdesign/core/Tooltip';
import { Stack } from '@astryxdesign/core/Stack';
import { Layout, LayoutHeader, LayoutContent, LayoutFooter } from '@astryxdesign/core/Layout';
import { Dialog as AstryxDialog } from '@astryxdesign/core/Dialog';
import { TextInput } from '@astryxdesign/core/TextInput';
import { CheckboxInput } from '@astryxdesign/core/CheckboxInput';
import { Skeleton } from '@astryxdesign/core/Skeleton';
import { Spinner } from '@astryxdesign/core/Spinner';
import { Banner } from '@astryxdesign/core/Banner';
import { Link as AstryxLink } from '@astryxdesign/core/Link';
import logger from 'utils/logger';
// ============================================================================
// 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 edge = (c) => dtA(c, '55');
const ring = (c) => dtA(c, '26');
const BRAND = '#C01227';
const BRAND_LIGHT = '#D25463';
// Legacy MUI palette names used throughout this page's chips/badges — mapped
// to real hex so the visual result matches the previous theme.palette.* colors.
const LEGACY_COLOR_MAP = {
primary: BRAND,
secondary: '#8c8c8c',
success: '#52c41a',
error: '#ff4d4f',
warning: '#faad14',
info: '#13c2c2',
default: DT.textMuted
};
const resolveColor = (c) => LEGACY_COLOR_MAP[c] || c || DT.textMuted;
// 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' ? 10 : 8;
const py = size === 'lg' ? 4 : 3;
const fs = size === 'lg' ? 12 : 11;
return (
<span
style={{
display: 'inline-flex',
alignItems: 'center',
gap: 4,
padding: `${py}px ${px}px`,
borderRadius: 999,
backgroundColor: tint(meta.color),
border: `1px solid ${edge(meta.color)}`,
color: meta.color,
fontSize: fs,
fontWeight: 500,
whiteSpace: 'nowrap'
}}
>
<Icon size={12} /> {meta.label}
</span>
);
};
// ----------------------------------------------------------------------------
// Txt — lightweight typography helper replacing MUI Typography variants.
// Keeps the pixel-level sizing this page relies on without adopting the full
// Astryx Text/Heading API for every single label on a very dense page.
// ----------------------------------------------------------------------------
const TYPOGRAPHY_STYLES = {
h3: { fontSize: '1.5rem', fontWeight: 500, lineHeight: 1.2 },
h4: { fontSize: '1.25rem', fontWeight: 500, lineHeight: 1.2 },
h5: { fontSize: '1.0625rem', fontWeight: 400, lineHeight: 1.3 },
subtitle1: { fontSize: '0.95rem', fontWeight: 400, lineHeight: 1.3 },
body1: { fontSize: '0.875rem', fontWeight: 400, lineHeight: 1.4 },
body2: { fontSize: '0.8125rem', fontWeight: 400, lineHeight: 1.4 },
caption: { fontSize: '0.75rem', fontWeight: 400, lineHeight: 1.4 }
};
const Txt = ({ variant = 'body1', color, align, style = {}, children, ...rest }) => {
const base = TYPOGRAPHY_STYLES[variant] || TYPOGRAPHY_STYLES.body1;
const resolvedColor = color === 'secondary' || color === 'textSecondary' ? DT.textSecondary : color || DT.textPrimary;
return (
<div
{...rest}
style={{
margin: 0,
color: resolvedColor,
textAlign: align,
...base,
...style
}}
>
{children}
</div>
);
};
// ----------------------------------------------------------------------------
// Pill — lightweight chip helper replacing MUI Chip (Astryx has no Chip;
// Token's fixed color set doesn't cover the arbitrary legacy palette used
// here, so this mirrors the tint/edge pattern already used by StatusBadge).
// ----------------------------------------------------------------------------
const Pill = ({ label, color = 'default', variant = 'filled', size = 'medium', icon, style = {} }) => {
const c = resolveColor(color);
const isSmall = size === 'small';
const base = {
display: 'inline-flex',
alignItems: 'center',
gap: 4,
borderRadius: 999,
fontWeight: 400,
whiteSpace: 'nowrap',
fontSize: isSmall ? 11 : 12.5,
padding: isSmall ? '2px 8px' : '4px 10px',
lineHeight: 1.6
};
const variantStyle =
variant === 'outlined'
? { backgroundColor: '#fff', border: `1px solid ${edge(c)}`, color: c }
: variant === 'light'
? { backgroundColor: tint(c), border: `1px solid ${edge(c)}`, color: c }
: { backgroundColor: c, color: '#fff' };
return (
<span style={{ ...base, ...variantStyle, ...style }}>
{icon}
{label}
</span>
);
};
// ----------------------------------------------------------------------------
// CircleAvatar — plain circular avatar replacing MUI Avatar (icon avatars &
// initials avatars). Matches the AccentAvatar pattern used elsewhere.
// ----------------------------------------------------------------------------
const CircleAvatar = ({ size = 32, bg = DT.textMuted, color = '#fff', style = {}, children }) => (
<div
style={{
width: size,
height: size,
borderRadius: '50%',
backgroundColor: bg,
color,
display: 'inline-flex',
alignItems: 'center',
justifyContent: 'center',
flexShrink: 0,
fontSize: Math.max(11, Math.round(size * 0.42)),
fontWeight: 400,
...style
}}
>
{children}
</div>
);
const Details = () => {
// const [searchParams] = useSearchParams();
const [orderarr, setOrderarr] = useState([]);
const [loading, setLoading] = useState(true);
const location = useLocation();
const [orderid, setOrderid] = useState('');
const [eventlocation, setEventlocation] = useState('');
const [orderdate, setOrderdate] = useState('');
const [eventname, setEventname] = useState('');
const [open, setOpen] = useState(false);
const [clientname, setClientname] = useState('');
// const [duedate, setDuedate] = useState('');
const [tenantaddress, setTenantaddress] = useState('');
const [dialogopen, setDialogopen] = useState(false);
const [orderstatus, setOrderstatus] = useState('');
const [currentrole, setCurrentrole] = useState('');
const [taxamount, setTaxamount] = useState('');
const [subtotal, setSubtotal] = useState('');
const [grandtotal, setGrandtotal] = useState('');
const [venuetype, setVenuetype] = useState('');
const [orderaddons, setOrderaddons] = useState([]);
const [otherinstructions, setOtherinstructions] = useState('');
const [cancelleddate, setCancelleddate] = useState('');
const [stafflist, setStafflist] = useState([]);
const [staffarr, setStaffarr] = useState([]);
const [orderheaderid, setOrderheaderid] = useState('');
const [tenantid, setTenantid] = useState('');
const [starttime, setStarttime] = useState('');
const [endtime, setEndtime] = useState('');
// const [orderstatus,setOrderstatus]=useStatus('');
const [pendingtime, setPendingtime] = useState('');
// const [processdate,setProcessdate]=useState('');
const [orderdetailid, setOrderdetailid] = useState('');
const [productid, setProductid] = useState('');
const [categoryarr, setcategoryarr] = useState([])
const [currentshiftobj, setCurrentshiftobj] = useState({
shifts: 0,
assigned: 0,
remaining: 0,
shiftid: 0,
price: 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)
useEffect(() => {
logger.info("categoryarr")
logger.info(orderarr, eventlocation, venuetype, starttime, endtime);
// forceUpdate();
}, [categoryarr])
// const navigate = useNavigate();
useEffect(() => {
if (state) {
setOrderheaderid(state.orderheaderid);
setTenantid(state.tenantid);
}
logger.info(state)
// fetchroleslist(1)
logger.info(Date.now())
}, [])
useEffect(() => {
if (state) {
setOrderheaderid(state.orderheaderid );
setTenantid(state.tenantid );
}
logger.info(state)
// fetchroleslist(1)
logger.info(Date.now())
}, [
state.orderheaderid, state.tenantid
])
// const fetchorderdetails = async () => {
// setLoading(true);
// await axios
// .get(`${process.env.REACT_APP_URL}/orders/orderbyid/?orderheaderid=${orderheaderid}`)
// .then((res) => {
// logger.info(res);
// setLoading(false);
// })
// .catch((err) => {
// logger.error(err);
// setLoading(false);
// });
// };
const fetchorderaddons = async () => {
setLoading(true);
await axios
.get(`${process.env.REACT_APP_URL2}/orders/getordersbystatus?tenantid=${tenantid}`)
.then((res) => {
logger.info(res);
let result = res.data.Details.find((res1) => res1.orderheaderid == orderheaderid)
// orderheaderid
logger.info("result")
logger.info(result)
setOrderaddons(result.orderaddons);
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)
setGrandtotal(result.ordervalue);
setCancelleddate(dayjs(result.cancelled).format('MM/DD/YYYY') || '');
// if (result.orderstatus === 'pending') {
setPendingtime(result.pending)
// }
setLoading(false);
})
.catch((err) => {
logger.error(err);
setLoading(false);
});
}
const fetchorderattires = async () => {
setLoading(true);
await axios
.get(`${process.env.REACT_APP_URL}/orders/getorderdetails?orderheaderid=${orderheaderid}`)
.then((res) => {
logger.info('res');
logger.info(res);
setOrderarr(res.data.details || []);
// let result = res.data.Details.find((res1) => res1.orderheaderid == searchParams.get('id'))
// orderheaderid
// logger.info(result)
// setOrderaddons(result.orderaddons);
// setVenuetype(result.venuetype)
// setOtherinstructions(result.remarks)
// logger.info("res");
// let result = _.chain(res.data.Details)
// .groupBy("shiftid")
// .map((value, key) => ({shiftid:key, locationaddress: value[0].locationaddress, roles: value }))
// .value()
// setcategoryarr(result);
logger.info('categoryarr');
setcategoryarr(res.data.details)
logger.info(res.data.details);
setLoading(false);
})
.catch((err) => {
logger.error(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) => {
logger.info('rolelist');
logger.info(res);
// logger.info(fromdate, todate)
// logger.info(dayjs(starttime1).format('YYYY-MM-DD HH:mm:ss'))
// logger.info(dayjs(endtime1).format('HH:mm:ss'))
setStafflist(res.data.Details || [])
// let result = res.data.Details.find((res1) => res1.orderheaderid == searchParams.get('id'))
// orderheaderid
// logger.info(result)
// setOrderaddons(result.orderaddons);
// setVenuetype(result.venuetype)
// setOtherinstructions(result.remarks)
setLoading(false);
})
.catch((err) => {
logger.error(err);
setLoading(false);
});
}
const fetchstafflist = async (odid) => {
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}`)
.then((res) => {
logger.info(res)
if (res.data.status) {
setStafflist(res.data.Details)
}
setLoading(false)
}).catch((err) => {
logger.error(err)
setLoading(false)
})
} catch (err) {
logger.error(err);
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,
})
.then((res) => {
logger.info(res)
if (res.data.status) {
if (orderheaderid && tenantid) {
// fetchorderdetails();
fetchorderaddons();
fetchorderattires();
}
}
}).catch((err) => {
logger.error(err)
})
}
const unassign = async (val) => {
let obj = {
orderheaderid: orderheaderid,
orderprocessid: val.orderprocessid,
orderdetailid: val.orderdetailid,
orderstatus: "pending",
pending: dayjs().format('YYYY-MM-DD HH:mm:ss'),
// processing:0,
// cancelled:0,
// completed:0,
// accepted:0,
status: 1
}
logger.info(obj)
await axios.put(`${process.env.REACT_APP_URL2}/orders/updateprocessstatus`, obj)
.then((res) => {
logger.info(res)
if (res.data.message === "Successful") {
// if (orderheaderid && tenantid) {
enqueueSnackbar('Role unassigned successfully', {
variant: 'success', anchorOrigin: { vertical: 'top', horizontal: 'right' },
autoHideDuration: 2000
})
if (currentshiftobj.assigned > currentshiftobj.shifts) {
sendunassignnotification(val)
}
fetchorderaddons();
fetchorderattires();
setOpen(false);
fetchassignedcount();
dialogclose()
setTimeout(() => {
fetchassignedcount();
}, 2000)
}
}).catch((err) => {
logger.error(err)
})
}
const sendunassignnotification = (val) => {
logger.info(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
}];
data2 = {
"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"
}
}
let grpnotifyobj = {
"notifications": arr1,
"fcmmodel": fcmmodel
}
logger.info("grpnotifyobj unassign")
logger.info(grpnotifyobj)
sendgroupnotification(grpnotifyobj)
}
useEffect(() => {
logger.info(orderheaderid);
if (orderheaderid && tenantid) {
// fetchorderdetails();
fetchorderaddons();
fetchorderattires();
fetchassignedcount()
// fetchuserdetails();
logger.info(location.state || '');
// setOrderid(location.state.orderid || '');
// setEventlocation(location.state.eventlocation || '');
// setEventlocation(address || []);
// setOrderdate(dayjs(location.state.orderdate.substring(0, 10)).format('MM/DD/YYYY') || '');
// setDuedate(dayjs(location.state.orderdate.substring(0, 10)).format('MM/DD/YYYY') || '')
// setEventname(location.state.eventname || '');
// setClientname(location.state.tenantname || '')
} else {
setLoading(false);
}
// fetchorderdetails();
logger.info(orderheaderid, tenantid)
}, [orderheaderid, tenantid, assignedpendingcount]);
const handleClose = () => {
setOpen(false);
};
const dialogclose = () => {
setDialogopen(false);
setStaffarr([]);
setExpandopen(['', ''])
};
useEffect(() => {
logger.info(currentshiftobj)
})
const assignok = async () => {
let arr = []
let arr1 = [];
staffarr.map((val) => {
arr.push({
"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
})
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
})
})
})
logger.info('arr')
logger.info(arr)
await axios.post(`${process.env.REACT_APP_URL2}/orders/createorderprocess`, arr)
.then((res) => {
logger.info(res)
if (res.data.message === "Successfully created") {
// if (orderheaderid && tenantid) {
// fetchorderdetails();
// fetchorderaddons();
// fetchorderattires();
// }
enqueueSnackbar('Roles assigned successfully', {
variant: 'success', anchorOrigin: { vertical: 'top', horizontal: 'right' },
autoHideDuration: 2000
})
// fetchroleslist(productid, '', '', orderheaderid, arr1[0].shiftid);
logger.info(productid, '', '', orderheaderid, arr1[0].shiftid)
// arr1.map((val2) => {
// notificationpush(val2,val2.Title);
// })
setDialogopen(false);
fetchorderattires();
fetchassignedcount();
}
}).catch((err) => {
logger.error(err)
})
logger.info(arr)
}
const notificationpush = async (val) => {
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",
// "firstname": val.firstname
};
logger.info(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) => {
logger.info(res)
// if(res.data.status){
enqueueSnackbar('Notification sent successfully', {
variant: 'success', anchorOrigin: { vertical: 'top', horizontal: 'right' },
autoHideDuration: 2000
})
// }
})
.catch((err) => {
logger.error(err)
})
}
const fetchassignedstaffs = async () => {
// logger.info(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 = []
logger.info(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);
})
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
}
logger.info("grpnotifyobj")
logger.info(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) => {
logger.error(err)
})
}
const sendgroupnotification = async (obj1) => {
logger.info(obj1)
await axios.post(`${process.env.REACT_APP_URL2}/utils/notification/sendall`, obj1, {
headers: {
'Authorization': `Bearer ${process.env.REACT_APP_STAFF_TOKEN}`
}
}
)
.then((res) => {
logger.info(res)
if (res.data.status) {
// updateorderstatus();
enqueueSnackbar('Notification sent successfully', {
variant: 'success', anchorOrigin: { vertical: 'top', horizontal: 'right' },
autoHideDuration: 2000
})
fetchorderaddons();
}
})
.catch((err) => {
logger.error(err)
})
}
// const updateorderstatus = async () => {
// await axios.put(`${process.env.REACT_APP_URL2}/orders/updateorderstatus`,{
// "orderheaderid":orderheaderid,
// "tenantid":tenantid,
// "orderstatus":"processing",
// "pending":"",
// "processing":dayjs().format('YYYY-MM-DD HH:mm:ss'),
// "completed":""
// })
// .then((res) => {
// logger.info(res)
// fetchorderdetails();
// fetchorderaddons();
// fetchorderattires();
// })
// .catch((err) => {
// logger.error(err)
// fetchorderdetails();
// fetchorderaddons();
// fetchorderattires();
// })
// }
const fetchassignedcount = async () => {
// logger.info(obj1)
await axios.get(`${process.env.REACT_APP_URL2}/orders/getorderstatuscount?orderheaderid=${orderheaderid}`)
.then((res) => {
if (res.data.status) {
// let arr1=[];
logger.info(res)
setAssignedpendingcount(res.data.pendingcount)
fetchorderaddons()
} else {
setAssignedpendingcount(res.data.pendingcount)
fetchorderaddons()
}
})
.catch((err) => {
logger.error(err)
})
}
function AlertCustomerDelete({ open, handleClose }) {
const [deletepassword, setDeletepassword] = useState('');
const isMatch = deletepassword === orderid.slice(4);
return (
<AstryxDialog
isOpen={open}
onOpenChange={(o) => !o && handleClose(false)}
purpose="form"
width={420}
>
<Layout
header={
<LayoutHeader hasDivider padding={0}>
<div
style={{
width: '100%',
padding: '20px',
background: `linear-gradient(135deg, ${tint('#ef4444')} 0%, ${tint('#f59e0b')} 100%)`
}}
>
<Stack direction="horizontal" vAlign="center" gap={1.5}>
<CircleAvatar size={40} bg="#ef4444">
<DeleteFilled />
</CircleAvatar>
<Stack direction="vertical" gap={0}>
<Txt variant="h5" style={{ fontWeight: 500 }}>Cancel Order</Txt>
<Txt variant="caption" color="secondary" style={{ fontWeight: 400 }}>
Confirm to permanently cancel this order
</Txt>
</Stack>
</Stack>
</div>
</LayoutHeader>
}
content={
<LayoutContent>
<Stack direction="vertical" hAlign="center" gap={2.5}>
<Pill label={orderid.slice(4)} color="warning" variant="light" icon={<MdReceiptLong size={12} />} />
{invoiceeligible && (
<Banner
status="warning"
title="Order is within 24Hrs time frame."
description="The order will be invoiced with standard pricing as agreed."
container="section"
>
<AstryxLink href="https://thelegendarystaff.com/" isExternalLink>
Terms &amp; Condition link
</AstryxLink>
</Banner>
)}
<Txt variant="body1" align="center" color="secondary" style={{ fontWeight: 400 }}>
Please type in the order number to confirm.
</Txt>
<TextInput
label="Order number"
isLabelHidden
width="100%"
onChange={(v) => setDeletepassword(v)}
status={isMatch ? undefined : { type: 'error' }}
value={deletepassword}
placeholder={orderid.slice(4)}
/>
</Stack>
</LayoutContent>
}
footer={
<LayoutFooter hasDivider>
<Stack direction="horizontal" gap={1.5} width="100%">
<Button label="No" variant="secondary" width="100%" onClick={() => handleClose(false)} />
<Button
label="Yes, Cancel"
variant="destructive"
width="100%"
onClick={() => {
if (isMatch) {
cancelorder();
handleClose(true);
}
}}
/>
</Stack>
</LayoutFooter>
}
/>
</AstryxDialog>
);
}
return (
<>
{loading && <Loader />}
<AlertCustomerDelete open={open} handleClose={handleClose} />
{/* ============================================= || Assign Roles dialog || ============================================= */}
<AstryxDialog isOpen={dialogopen} onOpenChange={(o) => !o && dialogclose()} purpose="form" width="min(1100px, 92vw)" maxHeight="88vh">
<Layout
header={
<LayoutHeader hasDivider padding={0}>
<div
style={{
width: '100%',
padding: '20px',
background: `linear-gradient(135deg, ${tint(BRAND)} 0%, ${tint(BRAND_LIGHT)} 100%)`
}}
>
<Stack direction="horizontal" hAlign="between" vAlign="center" gap={1.5} wrap="wrap">
<Stack direction="horizontal" vAlign="center" gap={1.5}>
<CircleAvatar size={40} bg={BRAND} style={{ boxShadow: `0 6px 18px ${ring(BRAND)}` }}>
<MdAssignmentTurnedIn size={20} />
</CircleAvatar>
<Stack direction="vertical" gap={0}>
<Txt variant="h4" style={{ fontWeight: 500, lineHeight: 1.1 }}>Assign Roles</Txt>
<Txt variant="caption" color="secondary" style={{ fontWeight: 400 }}>
{clientname} · {currentrole}
</Txt>
</Stack>
</Stack>
<Pill label={orderid} color="warning" variant="light" icon={<MdReceiptLong size={12} />} />
</Stack>
<div
style={{
display: 'grid',
gridTemplateColumns: 'repeat(auto-fit, minmax(220px, 1fr))',
gap: 12,
marginTop: 16
}}
>
<div
role="button"
tabIndex={0}
onClick={() => setTabstatus((e) => (e === 0 ? 1 : 0))}
onKeyDown={(e) => (e.key === 'Enter' || e.key === ' ') && setTabstatus((v) => (v === 0 ? 1 : 0))}
style={{
display: 'inline-flex',
alignItems: 'center',
gap: 6,
padding: '5px 10px',
borderRadius: 999,
cursor: 'pointer',
backgroundColor: BRAND,
color: '#fff',
fontWeight: 500,
fontSize: 12,
width: 'fit-content',
boxShadow: `0 6px 18px ${ring(BRAND)}`
}}
>
<CircleAvatar size={22} bg="rgba(255,255,255,0.22)">
<MdAssignmentTurnedIn size={12} />
</CircleAvatar>
{currentrole || 'Role'}
</div>
<Stack direction="horizontal" hAlign="end" gap={1} wrap="wrap">
{[
{ label: 'Required', value: currentshiftobj.shifts, color: BRAND },
{ label: 'Assigned', value: currentshiftobj.assigned, color: '#10b981' },
{ label: 'Remaining', value: currentshiftobj.remaining, color: '#ef4444' }
].map((c) => (
<div
key={c.label}
style={{
display: 'inline-flex',
alignItems: 'center',
gap: 5,
padding: '4px 8px',
borderRadius: 999,
backgroundColor: tint(c.color),
border: `1px solid ${edge(c.color)}`,
color: c.color,
fontSize: 11.5,
fontWeight: 500
}}
>
{c.label}
<span
style={{
minWidth: 22,
height: 18,
padding: '0 4px',
display: 'inline-flex',
alignItems: 'center',
justifyContent: 'center',
borderRadius: 999,
fontSize: 11,
fontWeight: 500,
backgroundColor: '#fff',
color: c.color,
border: `1px solid ${edge(c.color)}`
}}
>
{c.value ?? 0}
</span>
</div>
))}
</Stack>
</div>
</div>
</LayoutHeader>
}
content={
<LayoutContent padding={0}>
{(stafflist.length === 0) ? (
(loading) ? (
<Stack direction="vertical" hAlign="center" style={{ padding: 24 }}>
<Spinner size="lg" />
</Stack>
) : (
<Txt style={{ padding: 20 }}>No Staffs Available</Txt>
)
) : (
<div style={{ overflowX: 'auto' }}>
<table style={{ width: '100%', borderCollapse: 'collapse' }}>
<thead>
<tr style={{ backgroundColor: 'var(--color-background-muted)' }}>
{['#', 'Staff', 'Category', 'Price', 'Experience', 'Level', 'City', 'Action', ''].map((h) => (
<th key={h} style={{ textAlign: 'left', padding: '10px 12px' }}>{h}</th>
))}
</tr>
</thead>
<tbody>
{stafflist.map((val, i) => {
const isSelected = !!staffarr.find((res) => res.userid == val.userid);
return (
<tr key={i} style={{ backgroundColor: isSelected ? '#f5f5f5' : 'transparent' }}>
<td style={{ padding: '10px 12px', borderTop: `1px solid ${DT.borderSubtle}` }}>{i + 1}</td>
<td style={{ padding: '10px 12px', borderTop: `1px solid ${DT.borderSubtle}` }}>
<Stack direction="horizontal" vAlign="center" gap={1}>
<CircleAvatar size={25} bg={DT.textMuted} />
<Stack direction="vertical" gap={0}>
<Txt variant="caption">{val.firstname}</Txt>
<Txt variant="caption" color="secondary">{val.contactno}</Txt>
</Stack>
</Stack>
</td>
<td style={{ padding: '10px 12px', borderTop: `1px solid ${DT.borderSubtle}` }}>
<Stack direction="vertical" hAlign="start" gap={0.5}>
<Txt variant="caption" color="secondary">{val.cateoryname}</Txt>
<Pill label={val.subcategoryname} color="info" size="small" variant="light" />
</Stack>
</td>
<td style={{ padding: '10px 12px', borderTop: `1px solid ${DT.borderSubtle}` }}>{val.rolecost}</td>
<td style={{ padding: '10px 12px', borderTop: `1px solid ${DT.borderSubtle}` }}>{val.experience} Years</td>
<td style={{ padding: '10px 12px', borderTop: `1px solid ${DT.borderSubtle}` }}>
<Pill label={val.levelofexperience} size="small" color="primary" variant="light" />
</td>
<td style={{ padding: '10px 12px', borderTop: `1px solid ${DT.borderSubtle}` }}>{val.city}</td>
<td style={{ padding: '10px 12px', borderTop: `1px solid ${DT.borderSubtle}` }}>
{(val.orderdetailid !== orderdetailid) ? (
<CheckboxInput
label="Select staff"
isLabelHidden
isDisabled={val.orderdetailid !== 0}
value={isSelected}
onChange={(checked) => {
logger.info(currentshiftobj)
if (currentshiftobj.remaining >= 0) {
if (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 && (!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 })
}
logger.info(staffarr);
}
}}
/>
) : (
<Stack direction="horizontal" vAlign="center" gap={0.5}>
<Pill label="Assigned" color="success" size="small" />
<Tooltip content="Unassign">
<IconButton
label="Unassign"
icon={<CloseOutlined />}
variant="ghost"
onClick={() => {
logger.info(val)
unassign(val)
}}
/>
</Tooltip>
<Tooltip content="Send Notification">
<IconButton
label="Send Notification"
icon={<NotificationOutlined />}
variant="ghost"
onClick={() => {
logger.info(val)
notificationpush(val)
}}
/>
</Tooltip>
</Stack>
)}
</td>
<td style={{ padding: '10px 12px', borderTop: `1px solid ${DT.borderSubtle}` }}>
{val.orderid && <Pill label={val.orderid} color="warning" size="small" variant="light" />}
</td>
</tr>
);
})}
</tbody>
</table>
</div>
)}
</LayoutContent>
}
footer={
<LayoutFooter hasDivider>
<Stack direction="horizontal" hAlign="end" gap={2}>
{stafflist.length > 0 && (
<>
<Button label="OK" variant="primary" style={{ width: 130 }} onClick={assignok} />
<Button
label="clear"
variant="secondary"
style={{ width: 130 }}
onClick={() => {
setStaffarr([]);
let obj = currentshiftobj;
obj.remaining = obj.shifts;
obj.assigned = 0;
setCurrentshiftobj(obj);
}}
/>
</>
)}
<Button label="Close" variant="destructive" style={{ width: 130 }} onClick={() => { dialogclose() }} />
</Stack>
</LayoutFooter>
}
/>
</AstryxDialog>
<div style={{ display: 'flex', flexDirection: 'column', gap: 20 }}>
{/* ============================================= || Sticky header || ============================================= */}
<div
style={{
position: 'sticky',
// Offset below the Astryx AppShell top nav instead of a hardcoded
// pixel value — otherwise this block slides up and covers the nav
// bar (and swallows clicks meant for fields underneath) as the
// page scrolls.
top: 'var(--appshell-header-height, 0px)',
zIndex: 100,
padding: '16px 20px',
borderRadius: DT.radiusCard,
border: `1px solid ${DT.borderSubtle}`,
background: `linear-gradient(135deg, ${tint(BRAND)} 0%, ${tint(BRAND_LIGHT)} 100%)`,
boxShadow: DT.shadowMd
}}
>
<Stack direction="horizontal" hAlign="between" vAlign="center" gap={1.5} wrap="wrap">
<Stack direction="horizontal" vAlign="center" gap={1.5}>
<IconButton
label="Back"
icon={<MdArrowBack size={18} />}
variant="secondary"
onClick={() => history.back()}
style={{
backgroundColor: '#fff',
border: `1px solid ${DT.borderSubtle}`,
color: DT.textPrimary
}}
/>
<CircleAvatar size={48} bg={BRAND} style={{ boxShadow: `0 6px 18px ${ring(BRAND)}` }}>
<MdReceiptLong size={22} />
</CircleAvatar>
<Stack direction="vertical" gap={0.5}>
<Txt variant="h3" style={{ fontWeight: 500, lineHeight: 1.1 }}>Order Details</Txt>
<Stack direction="horizontal" vAlign="center" gap={0.75} wrap="wrap">
<div
style={{
display: 'inline-flex',
alignItems: 'center',
gap: 4,
padding: '3px 8px',
borderRadius: 999,
backgroundColor: tint('#f59e0b'),
border: `1px solid ${edge('#f59e0b')}`,
color: '#f59e0b',
fontSize: 11,
fontWeight: 500
}}
>
<MdReceiptLong size={11} />
{orderid === '' ? <Skeleton width={80} height={14} /> : orderid}
</div>
<div
style={{
display: 'inline-flex',
alignItems: 'center',
gap: 4,
padding: '3px 8px',
borderRadius: 999,
backgroundColor: tint(BRAND),
border: `1px solid ${edge(BRAND)}`,
color: BRAND,
fontSize: 11,
fontWeight: 500
}}
>
<MdAccessTime size={11} />
{orderdate === '' ? <Skeleton width={80} height={14} /> : orderdate}
</div>
<StatusBadge status={orderstatus} />
</Stack>
</Stack>
</Stack>
<Stack direction="horizontal" gap={1.5} vAlign="center" wrap="wrap">
{((orderstatus === 'pending') ||
(orderstatus === 'assigned') ||
(orderstatus === 'confirmed') ||
(orderstatus === 'modified')) && (
<Tooltip content="Edit">
<Button
label="Edit Order"
variant="secondary"
icon={<MdEdit size={16} />}
style={{ borderRadius: 999, borderColor: edge(BRAND), color: BRAND, fontWeight: 400 }}
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' }
});
}
}}
/>
</Tooltip>
)}
{orderstatus !== 'cancelled' && orderstatus !== '' && orderstatus !== 'completed' && orderstatus !== 'closed' && (
<Button
label="Cancel Order"
variant="secondary"
icon={<MdCancel size={16} />}
style={{ borderRadius: 999, borderColor: edge('#ef4444'), color: '#ef4444', fontWeight: 400 }}
onClick={() => {
if ((dayjs(startdate).diff(dayjs(), 'm') / 60) > 24) {
setInvoiceeligible(false);
setOpen(true);
} else {
setInvoiceeligible(true);
setOpen(true);
}
}}
/>
)}
{orderstatus === 'cancelled' && (
<div
style={{
display: 'inline-flex',
alignItems: 'center',
gap: 4,
padding: '4px 10px',
borderRadius: 999,
backgroundColor: tint('#ef4444'),
border: `1px solid ${edge('#ef4444')}`,
color: '#ef4444',
fontSize: 12,
fontWeight: 500
}}
>
<MdCancel size={12} /> Cancelled on {cancelleddate}
</div>
)}
</Stack>
</Stack>
</div>
{/* ============================================= || Body || ============================================= */}
<MainCard content={false}>
<div style={{ padding: 20, display: 'flex', flexDirection: 'column', gap: 20 }}>
<div style={{ display: 'grid', gridTemplateColumns: 'repeat(auto-fit, minmax(320px, 1fr))', gap: 20 }}>
<MainCard sx={{ height: '100%' }}>
<Stack direction="vertical" gap={1}>
<Txt variant="h5">Client</Txt>
<Txt color="secondary">{clientname === '' ? <Skeleton width="40%" height={16} /> : clientname}</Txt>
<div style={{ width: '100%' }}>
<Txt color="secondary">{tenantaddress === '' ? <Skeleton width="90%" height={16} /> : tenantaddress}</Txt>
</div>
</Stack>
</MainCard>
<MainCard sx={{ height: '100%' }}>
<Stack direction="vertical" gap={1}>
<Txt variant="h5">Event</Txt>
<div style={{ width: '100%' }}>
<Txt color="secondary">{eventname === '' ? <Skeleton width="40%" height={16} /> : eventname}</Txt>
</div>
</Stack>
</MainCard>
</div>
{categoryarr.map((val5, j) => (
<Fragment key={val5.locationaddress}>
<MainCard sx={{ opacity: val5.shiftstatus == 0 ? '' : '0.7' }}>
<Stack direction="horizontal" hAlign="between" vAlign="center" gap={2} wrap="wrap" style={{ padding: 16 }}>
<Stack direction="horizontal" gap={2} vAlign="center" wrap="wrap">
<Txt variant="h5">Shift {j + 1}</Txt>
<Txt color="secondary">
<EnvironmentOutlined /> {val5.locationaddress}
</Txt>
{val5.shiftstatus === 1 && <Pill label="Cancelled" color="secondary" />}
</Stack>
<Stack direction="horizontal" gap={1}>
{val5.ordercontacts.map((val11) => (
<Tooltip key={val11.contactname} content={val11.contactname}>
<CircleAvatar size={30} bg="#2196f3">{val11.contactname.charAt(0).toUpperCase()}</CircleAvatar>
</Tooltip>
))}
</Stack>
</Stack>
<div style={{ overflowX: 'auto' }}>
<table style={{ width: '100%', borderCollapse: 'collapse' }}>
<thead>
<tr style={{ backgroundColor: 'var(--color-background-muted)' }}>
{['#', 'Role', 'Start Date', 'End Date', 'Unpaid break', 'Count', 'Assigned', 'Attire', 'Price', 'Amount', 'Action'].map((h) => (
<th key={h} style={{ textAlign: 'left', padding: '10px 12px' }}>{h}</th>
))}
</tr>
</thead>
<tbody>
{val5.orderdetails.length === 0 && (
<tr>
{Array.from({ length: 11 }).map((_, ci) => (
<td key={ci} style={{ padding: '10px 12px', borderTop: `1px solid ${DT.borderSubtle}` }}>
<Skeleton height={14} />
</td>
))}
</tr>
)}
{val5.orderdetails.map((row, i) => {
const isExpanded = expandopen[0] === j && expandopen[1] === i;
return (
<Fragment key={i}>
<tr style={{ opacity: row.status == 0 ? '' : '0.7' }}>
<td style={{ padding: '10px 12px', borderTop: `1px solid ${DT.borderSubtle}` }}>{i + 1}</td>
<td style={{ padding: '10px 12px', borderTop: `1px solid ${DT.borderSubtle}` }}>{row.productname}</td>
<td style={{ padding: '10px 12px', borderTop: `1px solid ${DT.borderSubtle}` }}>
<Stack direction="vertical" gap={0}>
<Txt variant="body1">{dayjs(row.starttime).format('MM/DD/YYYY')}</Txt>
<Txt variant="body2">{dayjs(row.starttime).format('hh:mm A')}</Txt>
</Stack>
</td>
<td style={{ padding: '10px 12px', borderTop: `1px solid ${DT.borderSubtle}` }}>
<Stack direction="vertical" gap={0}>
<Txt variant="body1">{dayjs(row.endtime).format('MM/DD/YYYY')}</Txt>
<Txt variant="body2">{dayjs(row.endtime).format('hh:mm A')}</Txt>
</Stack>
</td>
<td style={{ padding: '10px 12px', borderTop: `1px solid ${DT.borderSubtle}` }}>{row.unpaidbreak || 0}</td>
<td style={{ padding: '10px 12px', borderTop: `1px solid ${DT.borderSubtle}`, textAlign: 'center' }}>
<Pill label={row.orderqty} color="success" variant="light" size="small" />
</td>
<td style={{ padding: '10px 12px', borderTop: `1px solid ${DT.borderSubtle}`, textAlign: 'center' }}>
<Pill label={row.supplyqty} color={row.supplyqty === 0 ? 'error' : 'warning'} variant="light" size="small" />
</td>
<td style={{ padding: '10px 12px', borderTop: `1px solid ${DT.borderSubtle}`, width: 100 }} />
<td style={{ padding: '10px 12px', borderTop: `1px solid ${DT.borderSubtle}` }}>${row.price}</td>
<td style={{ padding: '10px 12px', borderTop: `1px solid ${DT.borderSubtle}` }}>${row.landingamount}</td>
<td style={{ padding: '10px 12px', borderTop: `1px solid ${DT.borderSubtle}` }}>
<Stack direction="horizontal" gap={0.5} vAlign="center">
<Tooltip content="Expand">
<IconButton
label="Expand row"
variant="ghost"
icon={isExpanded ? <MdKeyboardArrowUp color={BRAND} /> : <MdKeyboardArrowDown color={BRAND} />}
onClick={() => {
setStafflist([]);
setExpandopen(isExpanded ? ['', ''] : [j, i])
fetchstafflist(row.orderdetailid)
}}
/>
</Tooltip>
{orderstatus === 'cancelled' && (
<IconButton label="Edit (disabled)" icon={<EditTwoTone />} variant="ghost" isDisabled />
)}
{row.status === 1 && (
<Tooltip content="Cancelled">
<span style={{ display: 'inline-flex', padding: 6, color: '#ef4444' }}>
<MdCancel size={18} />
</span>
</Tooltip>
)}
{row.supplyqty > row.orderqty && (
<Tooltip content="Assigned count is greater than ordered count">
<span style={{ display: 'inline-flex', padding: 6, color: '#faad14' }}>
<WarningOutlined />
</span>
</Tooltip>
)}
</Stack>
</td>
</tr>
{isExpanded && (
<tr>
<td colSpan={11} style={{ padding: 0, width: '100%' }}>
<div style={{ padding: 16 }}>
<MainCard sx={{ width: '100%' }}>
{stafflist.length === 0 ? (
loading ? (
<Stack direction="vertical" hAlign="center">
<Spinner size="lg" />
</Stack>
) : (
<Txt style={{ padding: 8 }}>No Staffs has been Assigned</Txt>
)
) : (
<div style={{ overflowX: 'auto' }}>
<table style={{ width: '100%', borderCollapse: 'collapse' }}>
<thead>
<tr style={{ backgroundColor: 'var(--color-background-muted)' }}>
{['#', 'Staff', 'Start Time', 'End Time', 'Pay Rate', 'Clockin', 'Clockout', 'Hours Worked', 'Status'].map((h) => (
<th key={h} style={{ textAlign: 'left', padding: '10px 12px' }}>{h}</th>
))}
</tr>
</thead>
<tbody>
{stafflist.map((val, si) => (
<tr key={si}>
<td style={{ padding: '10px 12px', borderTop: `1px solid ${DT.borderSubtle}` }}>{si + 1}</td>
<td style={{ padding: '10px 12px', borderTop: `1px solid ${DT.borderSubtle}` }}>
<Stack direction="vertical" gap={0.5}>
<Txt variant="caption">{val.staffname}</Txt>
<Pill label={val.productname} color="info" variant="light" size="small" />
</Stack>
</td>
<td style={{ padding: '10px 12px', borderTop: `1px solid ${DT.borderSubtle}` }}>
<Stack direction="vertical" gap={0}>
<Txt variant="body2">{dayjs(val.Starttime).format('MM/DD/YYYY')}</Txt>
<Txt variant="caption">{dayjs(val.Starttime).format('hh:mm A')}</Txt>
</Stack>
</td>
<td style={{ padding: '10px 12px', borderTop: `1px solid ${DT.borderSubtle}` }}>
<Stack direction="vertical" gap={0}>
<Txt variant="body2">{dayjs(val.Endtime).format('MM/DD/YYYY')}</Txt>
<Txt variant="caption">{dayjs(val.Endtime).format('hh:mm A')}</Txt>
</Stack>
</td>
<td style={{ padding: '10px 12px', borderTop: `1px solid ${DT.borderSubtle}` }}>{val.rolecost}</td>
<td style={{ padding: '10px 12px', borderTop: `1px solid ${DT.borderSubtle}` }}>
<Stack direction="vertical" gap={0.5} hAlign="center">
<Pill label={val.clockin ? dayjs(val.clockin).format('MM/DD/YYYY') : ''} color="primary" variant="light" size="small" />
<Pill label={val.clockin ? dayjs(val.clockin).format('hh:mm A') : ''} color="info" variant="light" size="small" />
</Stack>
</td>
<td style={{ padding: '10px 12px', borderTop: `1px solid ${DT.borderSubtle}` }}>
<Stack direction="vertical" gap={0.5} hAlign="center">
<Pill label={val.clockout ? dayjs(val.clockout).format('MM/DD/YYYY') : ''} color="primary" variant="light" size="small" />
<Pill label={val.clockout ? dayjs(val.clockout).format('hh:mm A') : ''} color="info" variant="light" size="small" />
</Stack>
</td>
<td style={{ padding: '10px 12px', borderTop: `1px solid ${DT.borderSubtle}` }}>{val.hoursworked}</td>
<td style={{ padding: '10px 12px', borderTop: `1px solid ${DT.borderSubtle}` }}>
<Stack direction="horizontal">
{val.orderstatus === 'pending' && <Pill label="Pending" color="error" size="small" />}
{val.orderstatus === 'cancelled' && <Pill label="Cancelled" color="secondary" size="small" />}
{val.orderstatus === 'completed' && <Pill label="Completed" color="primary" size="small" />}
{val.orderstatus === 'processing' && <Pill label="Processing" color="primary" size="small" />}
{val.orderstatus === 'assigned' && <Pill label="Assigned" color="warning" size="small" />}
{val.orderstatus === 'confirmed' && <Pill label="Confirmed" color="success" size="small" />}
{val.orderstatus === 'active' && <Pill label="Active" color="info" size="small" />}
{val.orderstatus === 'closed' && <Pill label="Closed" color="info" size="small" />}
</Stack>
</td>
</tr>
))}
</tbody>
</table>
</div>
)}
</MainCard>
</div>
</td>
</tr>
)}
</Fragment>
);
})}
</tbody>
</table>
</div>
</MainCard>
</Fragment>
))}
<hr style={{ border: 'none', borderTop: `1px solid ${DT.borderSubtle}`, margin: 0 }} />
<div style={{ display: 'grid', gridTemplateColumns: 'repeat(auto-fit, minmax(320px, 1fr))', gap: 20 }}>
<MainCard title="Order Addons" sx={{ height: '100%' }}>
<div style={{ display: 'flex', flexWrap: 'wrap', gap: 8 }}>
{(orderaddons || []).map((val) => (
<Pill key={val.addon} label={val.addon} color="error" variant="outlined" icon={<MdDirectionsCar size={14} />} />
))}
</div>
</MainCard>
<MainCard title="Total" sx={{ height: '100%' }}>
<Stack direction="vertical" gap={2}>
<Stack direction="horizontal" hAlign="between">
<Txt color="secondary">Sub Total:</Txt>
<Txt>${subtotal === '' ? <Skeleton width={30} height={14} /> : subtotal}</Txt>
</Stack>
<Stack direction="horizontal" hAlign="between">
<Txt color="secondary">Tax:</Txt>
<Txt>{taxamount === '' ? <Skeleton width={30} height={14} /> : taxamount}</Txt>
</Stack>
<Stack direction="horizontal" hAlign="between">
<Txt variant="subtitle1">Grand Total:</Txt>
<Txt variant="subtitle1">{grandtotal === '' ? <Skeleton width={30} height={14} /> : `$${grandtotal}`}</Txt>
</Stack>
</Stack>
</MainCard>
</div>
<Stack direction="vertical">
<Txt color="secondary">Other Instructions:</Txt>
<Txt style={{ marginLeft: 24 }}>{otherinstructions}</Txt>
</Stack>
</div>
</MainCard>
</div>
</>
);
};
export default Details;