Untitled
unknown
plain_text
5 months ago
72 kB
6
Indexable
import { DeleteOutlined, LikeOutlined, ZoomInOutlined, } from "@ant-design/icons"; import CloseIcon from "@mui/icons-material/Close"; import { AgGridReact } from "ag-grid-react"; import { DatePicker, Select, TimePicker } from "antd"; import dayjs from "dayjs"; import _ from "lodash"; import moment from "moment"; import React, { useCallback, useEffect, useMemo, useRef, useState, } from "react"; import { Controller, useForm } from "react-hook-form"; import { useDispatch, useSelector } from "react-redux"; import CreatableSelect from "react-select/creatable"; import { useDebouncedCallback } from "use-debounce"; import { COUNTRY, GRID_CONSTANTS, ORDER_STATUS, PACKAGING_TYPE, PROVINCE_STATE, QUOTE_ITEM_CATEGORY, } from "../../constants"; import { setCustomersListData } from "../../redux/customer/customerReducer"; import { setNotificationData } from "../../redux/global/globalReducer"; import { addLoadItemData } from "../../redux/loadItems/loadItemsReducer"; import { addOrderAccessorialData, addOrderData, deleteOrderData, setOrdersListData, updateOrderTMSQuoteData, } from "../../redux/order/orderReducer"; import { fetchAccessorialsByAccount } from "../../services/accessorialServices"; import { fetchCustomersByAccount } from "../../services/customerServices"; import { addLoadItem, fetchLoadItemsByLoadId, updateLoadItems, } from "../../services/loadServices"; import { fetchSuggestions } from "../../services/mapServices"; import { addOrderAccessorial } from "../../services/orderAccessorialServices"; import { addOrder, deleteOrder, fetchOrdersFiltered, } from "../../services/orderServices"; import { updateTMSQuoteItems } from "../../services/tmsQuoteItemServices"; import { enumValueFormatter, formatCurrency, formatDateOnly, getFormattedProvinceStateName, getQuickFilterValue, } from "../../utils/formatUtils"; import { calculateQuoteItem } from "../../utils/quoteUtils"; import { selectStyle } from "../../utils/styleUtils"; import LoadingPage from "../Commons/Authorization/LoadingPage"; import { NumericCellEditor } from "../Commons/Editor/NumericCellEditor"; import ContentHeader from "../Commons/Layouts/ContentHeader"; import NoData from "../Commons/Layouts/NoData"; import CreateCustomerModal from "../Commons/Modals/CreateCustomerModal"; import CreateOrderModal from "../Commons/Modals/CreateOrderModal"; import DeleteItemActionRenderer from "../Templates/CellRenderers/Commons/DeleteItemActionRenderer"; import EditFormRenderer from "../Templates/CellRenderers/Commons/EditFormRenderer"; import OrderStatusRenderer from "../Templates/CellRenderers/Orders/OrderStatusRenderer"; import QuoteItemCategoryRenderer from "../Templates/CellRenderers/Quotes/QuoteItemCategoryRenderer"; import PackagingTypeEditor from "../Templates/Editor/PackagingTypeEditor"; import QuoteItemCategoryEditor from "../Templates/Editor/QuoteItemCategoryEditor"; import OrderForm from "./OrderForm"; import ReactSelect from "react-select"; const { Option } = Select; function Orders() { const dispatch = useDispatch(); const { register, handleSubmit, setValue, setError, clearErrors, reset, setFocus, control, formState, errors, checkPageEditable, selectedOrderOption, setSelectedOrderOption, } = useForm(); const accountId = useSelector((state) => state.auth.user.accountId); const userType = useSelector((state) => state.auth.user.userType); const orderState = useSelector((state) => state.order); const customerState = useSelector((state) => state.customer); const selectedAccountState = useSelector( (state) => state.account.selectedAccount ); // Modal Config const [createOrderModal, setCreateOrderModal] = useState(false); const createOrderToggle = () => setCreateOrderModal(!createOrderModal); const [createCustomerModal, setCreateCustomerModal] = useState(false); const createCustomerToggle = () => setCreateCustomerModal(!createCustomerModal); const [userOptions, setUserOptions] = useState([]); const [customerCreationInformation, setCustomerCreationInformation] = useState(null); const [customerOptions, setCustomerOptions] = useState([]); const [accessorialOptions, setAccessorialOptions] = useState([]); const [selectedOrderStatus, setSelectedOrderStatus] = useState(0); const [selectedCustomer, setSelectedCustomer] = useState(null); const [selectedShipper, setSelectedShipper] = useState(null); const [selectedReceiver, setSelectedReceiver] = useState(null); const [loadItems, setLoadItems] = useState([]); const [accessorials, setAccessorials] = useState([]); const [selectedAccessorial, setSelectedAccessorial] = useState(null); const [quoteItems, setQuoteItems] = useState([]); const [selectedQuotes, setSelectedQuote] = useState(null); const [pickupisTextFieldVisible, setpickupIsTextFieldVisible] = useState(false); const [dropoffisTextFieldVisible, setdropoffIsTextFieldVisible] = useState(false); const [selectedPickupAddress, setSelectedPickupAddress] = useState({}); const [pickupSearchInput, setPickupSearchInput] = useState(""); const [pickupSuggestions, setPickupSuggestions] = useState([]); const [formattedPickupSuggestions, setFormattedPickupSuggestions] = useState( [] ); const [dropoffSearchInput, setDropoffSearchInput] = useState(""); const [dropoffSuggestions, setDropoffSuggestions] = useState([]); const [formattedDropoffSuggestions, setFormattedDropoffSuggestions] = useState([]); const toggleFormDisplay = (isEdit = false, orderId = null) => { if (!isEdit && isFormHidden) { addInitialOrder(); } if (isFormHidden) { setSelectedOrderId(orderId); } else { setSelectedOrderId(null); } if (modal) { setModal(!modal); } setIsFormEdit(isEdit); setIsFormHidden(!isFormHidden); setTimeout(() => { if (!isFormHidden) { gridRef.current.api.sizeColumnsToFit(); } setIsQuickFormHidden(true); }, 50); }; const toggleFormCancelDisplay = () => { toggleFormDisplay(); }; const defaultColumnDefs = [ { field: "Load ID", minWidth: 150, cellClass: "grid-column", getQuickFilterText: (params) => { return params.value; }, }, { field: "Customer", minWidth: 150, cellClass: "grid-column gray", getQuickFilterText: (params) => { return params.value; }, }, { field: "Shipper", minWidth: 150, cellClass: "grid-column gray", getQuickFilterText: (params) => { return params.value; }, }, { field: "Receiver", minWidth: 150, cellClass: "grid-column gray", getQuickFilterText: (params) => { return params.value; }, }, { field: "Status", minWidth: 150, cellClass: "grid-column center gray d-flex", cellRenderer: OrderStatusRenderer, valueFormatter: (params) => { return enumValueFormatter(params, ORDER_STATUS); }, getQuickFilterText: (params) => { const statusValue = params.value; return getQuickFilterValue(statusValue, ORDER_STATUS); }, }, { field: "Load", minWidth: 150, cellClass: "grid-column gray", getQuickFilterText: (params) => { return params.value; }, }, { field: "Edit", minWidth: 150, headerName: "", cellClass: "d-flex flex-row-reverse", autoHeight: true, cellRenderer: EditFormRenderer, cellRendererParams: { toggleFormDisplay, deleteFunction: deleteOrder, deleteReduxFunction: deleteOrderData, header: "Order", }, }, ]; const defaultColDef = useMemo(() => { return { cellStyle: { whiteSpace: "pre-wrap", overflowWrap: "break-word", textAlign: "left", }, resizable: true, }; }, []); const onGridReady = useCallback((params) => { gridRef.current.api.sizeColumnsToFit(); loadItemsGridRef.current.api.sizeColumnsToFit(); quotesGridRef.current.api.sizeColumnsToFit(); }, []); const onColumnsSizeChanged = (params) => { var gridWidth = document.getElementById("grid-wrapper").offsetWidth; var columnsToShow = []; var columnsToHide = []; var totalColsWidth = 0; var allColumns = params.columnApi.getAllColumns(); for (var i = 0; i < allColumns.length; i++) { let column = allColumns[i]; totalColsWidth += column.getMinWidth(); if (totalColsWidth > gridWidth) { columnsToHide.push(column.colId); } else { columnsToShow.push(column.colId); } } params.columnApi.setColumnsVisible(columnsToShow, true); params.columnApi.setColumnsVisible(columnsToHide, false); params.api.sizeColumnsToFit(); }; const onGridSizeChanged = (params) => { if (isFormHidden) { params.api.sizeColumnsToFit(); } }; // useStates const [rowData, setRowData] = useState([]); const [columnDefs, setColumnDefs] = useState(defaultColumnDefs); const [orderList, setOrderList] = useState([]); const [isFormHidden, setIsFormHidden] = useState(true); const [isQuickFormHidden, setIsQuickFormHidden] = useState(true); const [isFormEdit, setIsFormEdit] = useState(false); const [selectedOrder, setSelectedOrder] = useState({}); const [selectedOrderId, setSelectedOrderId] = useState(null); const [selectedAccessorialList, setSelectedAccessorialList] = useState([]); const [selectedQuoteList, setSelectedQuoteList] = useState([]); const [selectedFieldType, setSelectedFieldType] = useState(""); const [isFormDirty, setIsFormDirty] = useState(null); const [isLoading, setIsLoading] = useState(true); const [modal, setModal] = useState(false); const toggle = () => setModal(!modal); // useEffects useEffect(() => { init(); }, []); useEffect(() => { setOrderList(orderState.data); }, [orderState.data]); useEffect(() => { let data = []; _.each(orderList, (order, index) => { data.push({ "Load ID": order.load.loadId, Customer: order.customerName, Shipper: order.shipperName, Receiver: order.receiverName, Status: order.status, Load: "-", Id: order.orderId, Edit: { id: order.orderId, btnClass: "btn-color-3", formType: "Order", status: order.status, }, }); }); setRowData(data); }, [orderList]); useEffect(() => { fillSelectedOrder(selectedOrderId); }, [selectedOrderId]); useEffect(() => { setCustomerOptions([ { value: 0, label: "+ Create Customer", name: "+ Create Customer" }, ...customerState.data.map((customer) => ({ id: customer.customerId, name: customer.customerName, contact: customer.primaryContact, email: customer.defaultEmail, addressLine1: customer.addressLine1, addressLine2: customer.addressLine2, phone: customer.phone, city: customer.city, provinceState: customer.provinceState, country: customer.country, postalCode: customer.postalCode, latitude: customer.latitude, longitude: customer.longitude, value: customer.customerId, label: customer.customerName, })), ]); }, [customerState.data]); // useRefs const gridRef = useRef(); const loadItemsGridRef = useRef(); const accessorialsGridRef = useRef(); const quotesGridRef = useRef(); const openOrCloseButtonRef = useRef(null); const filterData = (searchQuery) => { gridRef.current.api.setQuickFilter(searchQuery); }; const focusOnOpenOrCloseButton = () => { if (!isLoading) { openOrCloseButtonRef.current.focus(); } }; const init = () => { getOrdersData(); getCustomersData(); getAccessorialData(); focusOnOpenOrCloseButton(); setIsLoading(false); }; const getOrdersData = async () => { const response = selectedAccountState.accountId === null ? await fetchOrdersFiltered(accountId) : await fetchOrdersFiltered(selectedAccountState.accountId); dispatch(setOrdersListData(response)); }; const getCustomersData = async () => { const response = await fetchCustomersByAccount( userType, selectedAccountState.accountId, accountId ); dispatch(setCustomersListData(response)); setCustomerOptions( response.map((customer) => ({ id: customer.customerId, name: customer.customerName, contact: customer.primaryContact, email: customer.defaultEmail, addressLine1: customer.addressLine1, addressLine2: customer.addressLine2, phone: customer.phone, city: customer.city, provinceState: customer.provinceState, country: customer.country, postalCode: customer.postalCode, latitude: customer.latitude, longitude: customer.longitude, })) ); }; const getAccessorialData = async () => { const response = await fetchAccessorialsByAccount( userType, selectedAccountState.accountId, accountId ); setAccessorialOptions( response.map((accessorial) => ({ value: accessorial.accessorialId, label: accessorial.accessorialName, description: accessorial.description, accountId: accessorial.accountId, })) ); }; const fillSelectedOrder = (id) => { const order = _.find(orderList, { orderId: id }); setSelectedOrder(order); getLoadItemsData(order?.load?.loadId); getAccessorials(order); fillAccessorialTable(order?.orderAccessorial); getQuoteItems(order); fillQuoteTable(order?.tmsQuote); setSelectedOrderStatus(id !== null ? order?.status : 0); setValue("customerName", order?.customerName); setSelectedCustomer({ value: order?.customerId, label: order?.customerName, addressLine1: order?.customerAddress1, city: order?.customerCity, provinceState: order?.customerState, postalCode: order?.customerPostal, }); setValue("shipperName", order?.shipperName); setSelectedShipper({ value: order?.shipperId, label: order?.shipperName, addressLine1: order?.shipperAddress1, city: order?.shipperCity, provinceState: order?.shipperState, postalCode: order?.shipperPostal, }); setSelectedPickupAddress({ value: order?.shipperId, label: order?.shipperName, addressLine1: order?.shipperAddress1, city: order?.shipperCity, provinceState: order?.shipperState, postalCode: order?.shipperPostal, }); setValue("receiverName", order?.receiverName); setSelectedReceiver({ value: order?.receiverId, label: order?.receiverName, addressLine1: order?.receiverAddress1, city: order?.receiverCity, provinceState: order?.receiverState, postalCode: order?.receiverPostal, }); setValue("quoteName", order?.tmsQuote?.[0]?.quoteName); setValue("quoteDate", dayjs(order?.tmsQuote?.[0]?.quoteDate)); setValue("quoteId", `QID-${order?.tmsQuote?.[0]?.quoteSequenceId}`); setValue("quoteTotal", `$${order?.tmsQuote?.[0]?.total}`); }; const getLoadItemsData = async (loadId) => { const response = await fetchLoadItemsByLoadId(loadId); let data = []; _.each(response, (loadItem) => { data.push({ Description: loadItem?.description, Quantity: loadItem?.quantity, "Packaging Type": loadItem?.packagingType, Weight: loadItem?.weight, "Item Value": loadItem?.itemValue, loadItemId: loadItem?.loadItemId, }); }); setLoadItems(data); }; const getAccessorials = async (order) => { let data = []; _.each(order?.orderAccessorial, (accessorial, index) => { data.push({ Name: accessorial.accessorialName, Description: accessorial.description, }); }); setAccessorials(data); }; const fillAccessorialTable = (accessorialList) => { let data = []; _.each(accessorialList, (accessorial, index) => { data.push({ "#": index + 1, Name: accessorial.accessorialName, Description: accessorial.description, AccessorialId: accessorial.accessorialId, OrderAccessorialId: accessorial.orderAccessorialId, Id: accessorial.orderAccessorialId, AccountId: accessorial.accountId, OrderId: accessorial.orderId, }); }); setSelectedAccessorialList(data); }; const getQuoteItems = async (order) => { let data = []; _.each(order?.tmsQuote?.[0]?.tmsQuoteItem, (quoteItem, index) => { data.push({ AccountId: quoteItem.accountId, QuoteId: quoteItem.tmsQuoteId, QuoteItemId: quoteItem.tmsQuoteItemId, OrderId: quoteItem?.orderId, Category: quoteItem.category, Description: quoteItem.description, Quantity: quoteItem.quantity, Rate: quoteItem.rate, Total: quoteItem.cost, Type: quoteItem.type, UpdateStatus: 2, }); }); setQuoteItems(data); }; const fillQuoteTable = (quoteList) => { let data = []; _.each(quoteList, (quote, index) => { data.push({ "#": index + 1, QID: quote.quoteSequenceId, Name: quote.quoteName, Date: formatDateOnly(quote.quoteDate), Quote: quote.total, Status: quote.status, Notes: quote.notes, QuoteId: quote.tmsQuoteId, Id: quote.tmsQuoteId, OrderId: quote.orderId, AccountId: quote.accountId, QuoteItems: quote.tmsQuoteItem, }); }); setSelectedQuoteList(data); }; const removeUserFromOptions = (userId) => { const updatedUserOptions = userOptions.filter( (item) => item.value !== userId ); setUserOptions(updatedUserOptions); }; const addInitialOrder = async () => { // Initialize empty order payload const payload = { accountId: selectedAccountState.accountId === null ? accountId : selectedAccountState.accountId, orderId: 0, status: 1, customerId: -1, shipperId: -1, receiverId: -1, orderNickName: "", orderStatus: 1, taxType: 1, discount: 0, deposit: 0, totalTax: 0, subTotal: 0, totalQuote: 0, paymentDueDate: moment() .add(14, "days") .clone() .hour(7) .minute(0) .second(0) .format("YYYY-MM-DD"), // @TODO: Current date + New setting Payment Due Offset terms: "", active: true, orderDate: moment() .clone() .hour(7) .minute(0) .second(0) .format("YYYY-MM-DD"), pickupStartDate: moment() .clone() .hour(7) .minute(0) .second(0) .format("YYYY-MM-DD"), pickupStartTime: moment("09:00:00", "HH:mm:ss") .set({ seconds: 0 }) .format("HH:mm:ss"), pickupEndDate: moment() .clone() .hour(7) .minute(0) .second(0) .format("YYYY-MM-DD"), pickupEndTime: moment("17:00:00", "HH:mm:ss") .set({ seconds: 0 }) .format("HH:mm:ss"), dropoffStartDate: moment() .clone() .hour(7) .minute(0) .second(0) .add(1, "days") .format("YYYY-MM-DD"), dropoffStartTime: moment("9:00:00", "HH:mm:ss") .set({ seconds: 0 }) .format("HH:mm:ss"), dropoffEndDate: moment() .clone() .hour(7) .minute(0) .second(0) .add(1, "days") .format("YYYY-MM-DD"), dropoffEndTime: moment("17:00:00", "HH:mm:ss") .set({ seconds: 0 }) .format("HH:mm:ss"), isShipperCopyingCustomerDetails: true, isPickupCopyingShipperDetails: true, isDropoffCopyingReceiverDetails: true, }; // Add in Customer details if available if (!_.isNull(customerCreationInformation)) { payload.customerId = customerCreationInformation.id; payload.customerName = customerCreationInformation.name; payload.customerContactName = customerCreationInformation.contact; payload.customerDefaultEmail = customerCreationInformation.email; payload.customerPhoneNumber = customerCreationInformation.phone; payload.customerAddress1 = customerCreationInformation.addressLine1; payload.customerAddress2 = customerCreationInformation.addressLine2; payload.customerCity = customerCreationInformation.city; payload.customerPostal = customerCreationInformation.postalCode; payload.customerState = customerCreationInformation.provinceState; payload.customerCountry = customerCreationInformation.country; payload.customerLatitude = customerCreationInformation.latitude; payload.customerLongitude = customerCreationInformation.longitude; } const orderResponse = await addOrder(payload); const data = await orderResponse.json(); dispatch(addOrderData(data)); setSelectedOrderId(data.orderId); }; const showQuickOrderForm = (selectOrderData = {}) => { setSelectedOrderId(selectOrderData.Id); setIsQuickFormHidden(false); }; const hideQuickOrderForm = () => { setIsQuickFormHidden(true); }; const handleSelectCustomer = (selectedCustomer, type) => { if (selectedCustomer?.value === 0) { setCreateCustomerModal(true); setSelectedFieldType(type); return; } switch (type) { case "customer": setSelectedCustomer(selectedCustomer); break; case "shipper": setSelectedShipper(selectedCustomer); setSelectedPickupAddress(selectedCustomer); break; case "receiver": setSelectedReceiver(selectedCustomer); break; default: setSelectedCustomer(selectedCustomer); break; } }; const handleAddLoadItem = async () => { const payload = { accountId: accountId, orderId: selectedOrder.orderId, loadId: selectedOrder.load.loadId, description: "", quantity: 0, packagingType: 1, width: 0, height: 0, length: 0, weight: 0, linearFeet: 0, hazMatClass: "N/A", itemValue: 0, }; const response = await addLoadItem(payload); const data = await response.json(); dispatch(addLoadItemData(data)); dispatch( setNotificationData({ type: `${response.ok ? "success" : "error"}`, message: `${response.ok ? "Success!" : "Error!"}`, description: `${ response.ok ? "Successfully saved" : "Failed to save" } load item.`, }) ); getLoadItemsData(selectedOrder?.load?.loadId); }; const handleUpdateLoadItems = async (showNotification = true) => { var loadItems = []; if (loadItemsGridRef.current.api.getDisplayedRowCount() === 0) { if (showNotification) { dispatch( setNotificationData({ type: "error", message: "Error!", description: "Please add a load item.", }) ); } return; } loadItemsGridRef.current.api.forEachNode((node) => { const loadItem = node.data; var payloadData = { accountId: accountId, orderId: selectedOrder.orderId, loadId: selectedOrder.load.loadId, loadItemId: loadItem["loadItemId"], description: loadItem["Description"], quantity: parseFloat(loadItem.Quantity), weight: parseFloat(loadItem.Weight), itemValue: parseFloat(loadItem["Item Value"]), }; loadItems.push(payloadData); }); let response = await updateLoadItems(loadItems); if (showNotification) { dispatch( setNotificationData({ type: `${response.ok ? "success" : "error"}`, message: `${response.ok ? "Success!" : "Error!"}`, description: `${ response.ok ? "Successfully saved" : "Failed to save" } load item.`, }) ); } if (response.ok) { const returnedData = await response.json(); let data = []; _.each(returnedData, (loadItem) => { data.push({ Description: loadItem?.description, Quantity: loadItem?.quantity, "Packaging Type": loadItem?.packagingType, Weight: loadItem?.weight, "Item Value": loadItem?.itemValue, loadItemId: loadItem?.loadItemId, }); }); dispatch(setLoadItems(data)); } }; const handleAddAccessorial = async () => { if (selectedAccessorial) { const accessorial = _.find(accessorialOptions, (accessorialOption) => { return accessorialOption.value === selectedAccessorial; }); const payload = { accessorialName: accessorial.label, description: accessorial.description, accessorialId: accessorial.value, accountId: accessorial.accountId, orderId: selectedOrder?.orderId, }; const response = await addOrderAccessorial(payload); dispatch( setNotificationData({ type: `${response.ok ? "success" : "error"}`, message: `${response.ok ? "Success!" : "Error!"}`, description: `${ response.ok ? "Successfully saved" : "Failed to save" } item.`, }) ); if (response.ok) { const returnedData = await response.json(); const newItem = { "#": rowData.length + 1, Name: returnedData.accessorialName, Description: returnedData.description, AccessorialId: returnedData.accessorialId, OrderAccessorialId: returnedData.orderAccessorialId, Id: returnedData.orderAccessorialId, AccountId: returnedData.accountId, OrderId: returnedData.orderId, }; const transaction = { add: [newItem], }; accessorialsGridRef.current.api.applyTransaction(transaction); dispatch( addOrderAccessorialData({ orderId: selectedOrder?.orderId, orderAccessorial: returnedData, }) ); setSelectedAccessorial(null); } } else { dispatch( setNotificationData({ type: `error`, message: `Error!`, description: `Please select an accessorial`, }) ); } }; const handleAddQuoteItem = async () => { const newItem = { "#": rowData.length + 1, Type: 3, Category: 0, Description: "Other", Quantity: 1, Rate: 0, Total: 0, Notes: "", QuoteItemId: 0, Id: 0, QuoteId: selectedOrder?.tmsQuote?.[0]?.tmsQuoteId, OrderId: selectedOrder?.orderId, AccountId: accountId, UpdateStatus: 1, }; const transaction = { add: [newItem], addIndex: 0, }; quotesGridRef.current.api.applyTransaction(transaction); // setDirtyQuoteItemColumns(true); setTimeout(() => { quotesGridRef.current.api.startEditingCell({ rowIndex: 0, colKey: "Description", }); }, 200); }; const handleDeleteQuoteItem = async (currentData) => { const itemsToUpdate = []; const selectedRows = quotesGridRef.current.api.getSelectedRows(); const currentRow = selectedRows[0]; console.log("test", currentRow); currentRow["UpdateStatus"] = 3; itemsToUpdate.push(currentRow); quotesGridRef.current.api.applyTransaction({ update: itemsToUpdate }); handleUpdateQuoteItems(currentRow?.QuoteId, true); quotesGridRef.current.api.applyTransaction({ remove: [currentRow] }); }; const tabToNextCell = (params) => { const { previousCellPosition, nextCellPosition } = params; if (previousCellPosition?.rowIndex + 1 === nextCellPosition?.rowIndex) { const previousRow = quotesGridRef.current.api.getRowNode( previousCellPosition?.rowIndex ); handleUpdateQuoteItems(previousRow?.data?.QuoteId); } return nextCellPosition; }; const handleUpdateQuoteItems = async (id, isDelete = false) => { var quoteItems = []; if (quotesGridRef.current.api.getDisplayedRowCount() === 0) { dispatch( setNotificationData({ type: "error", message: "Error!", description: "Please add a load item.", }) ); return; } quotesGridRef.current.api.forEachNode((node) => { const quoteItem = node.data; var payloadData = { accountId: quoteItem?.AccountId, orderId: quoteItem?.OrderId, description: quoteItem?.Description, quantity: parseFloat(quoteItem?.Quantity), rate: parseFloat(quoteItem?.Rate), cost: parseFloat(quoteItem?.Total), notes: quoteItem?.notes, type: quoteItem?.Type, category: quoteItem?.Category, tmsQuoteId: quoteItem?.QuoteId, tmsQuoteItemId: quoteItem?.QuoteItemId, updateStatus: quoteItem?.UpdateStatus, }; quoteItems.push(payloadData); }); const payload = { accountId: accountId, orderId: selectedOrderId, tmsQuoteId: id, tmsQuoteItem: quoteItems, }; let response = await updateTMSQuoteItems(payload, "quote"); dispatch( setNotificationData({ type: `${response.ok ? "success" : "error"}`, message: `${response.ok ? "Success!" : "Error!"}`, description: `${ response.ok ? isDelete ? "Sucessfully deleted" : "Successfully saved" : "Failed to save" } quote.`, }) ); if (response.ok) { const returnedData = await response.json(); console.log("test 555", returnedData); dispatch( updateOrderTMSQuoteData({ orderId: selectedOrder?.orderId, updatedTMSQuote: returnedData, }) ); } }; const handleChange = useDebouncedCallback((value) => { setPickupSearchInput(value); }, 1000); const handlePickupSelect = (selected) => { if (_.isNull(selected)) { return; } try { const selectedSuggestion = pickupSuggestions.find( (suggestion) => suggestion?.properties?.place_id === selected?.value ); const firstUSState = PROVINCE_STATE.find( (provinceState) => provinceState.label === "Alabama" ).value; const selectedShipperProvinceState = _.find( PROVINCE_STATE, (provinceState) => { return provinceState.label === selectedSuggestion?.properties?.state; } ); const selectedCountry = _.find(COUNTRY, (country) => { return ( country.value === (selectedShipperProvinceState?.value >= firstUSState ? 2 : 1) ); }); setSelectedPickupAddress({ addressLine1: selectedSuggestion?.properties?.address_line1, city: selectedSuggestion?.properties?.city, provinceState: selectedShipperProvinceState?.label, postalCode: selectedSuggestion?.properties?.postcode, }); } catch (error) { dispatch( setNotificationData({ type: "error", message: "Error selecting address!", description: error, }) ); } }; useEffect(() => { const fetchAsyncSuggestions = async () => { if (pickupSearchInput.length > 2) { const results = await fetchSuggestions(pickupSearchInput); setPickupSuggestions(results); const formattedSuggestions = results.map((suggestion) => ({ value: suggestion?.properties?.place_id, label: suggestion?.properties?.formatted, })); setFormattedPickupSuggestions(formattedSuggestions); } }; fetchAsyncSuggestions(); }, [pickupSearchInput]); if (isLoading) { return <LoadingPage />; } return ( <div> <div className="row mb-0"> <div className="col-12"> <ContentHeader title={ isFormHidden ? "Orders" : isFormEdit ? "Edit Order" : "New Order" } subtitle={"orders"} dataCount={orderList.length} filterData={filterData} onClickAdd={createOrderToggle} onClickCancel={toggleFormCancelDisplay} isFormHidden={isFormHidden} openOrCloseButtonRef={openOrCloseButtonRef} /> </div> </div> <div className="content-body-container row mt-3"> <div className={`${ isFormHidden ? (isQuickFormHidden ? "col-12" : "col-7") : "d-none" } mb-2`} > {orderList?.length > 0 ? ( <div className={`ag-theme-alpine content-section-container no-header-cell-resize order-grid order-section p-0`} > <AgGridReact className="no-header" rowData={rowData} columnDefs={columnDefs} ref={gridRef} defaultColDef={defaultColDef} onGridReady={onGridReady} onColumnSizeChanged={onColumnsSizeChanged} onGridSizeChanged={onGridSizeChanged} rowHeight={GRID_CONSTANTS.ROW_HEIGHT} onRowClicked={(e) => showQuickOrderForm(e.data)} ></AgGridReact> </div> ) : ( <NoData color="color-3" content="order" /> )} </div> <div className={`col-12 ${isFormHidden ? "d-none" : ""}`}> <OrderForm isFormEdit={isFormEdit} selectedOrder={selectedOrder} selectedAccessorialList={selectedAccessorialList} selectedQuoteList={selectedQuoteList} setSelectedQuoteList={setSelectedQuoteList} isFormHidden={isFormHidden} toggleFormDisplay={toggleFormDisplay} setIsFormDirty={setIsFormDirty} modal={modal} setModal={setModal} toggle={toggle} focusOnOpenOrCloseButton={focusOnOpenOrCloseButton} customerCreationInformation={customerCreationInformation} setCustomerCreationInformation={setCustomerCreationInformation} removeUserFromOptions={removeUserFromOptions} accessorialOptions={accessorialOptions} selectedOrderStatus={selectedOrderStatus} setSelectedOrderStatus={setSelectedOrderStatus} /> </div> <div className={`col-5 mb-2 ${isQuickFormHidden ? "d-none" : ""}`}> <div className={`content-section-container color-3-grid color-3-section p-0`} > <div className="quick-form-header d-flex flex-row-reverse align-items-center"> <div onClick={hideQuickOrderForm}> <CloseIcon className="me-3" /> </div> </div> <form id="quick-order-form"> <div className="content-section-container"> <div className="row form-container mb-4" id="primary-details-form" > <div className="col-4"> <p className="mb-0 fw-bold h6">Order ID</p> <p>{selectedOrder?.orderId ?? "-"}</p> </div> <div className="col-4"> <p className="mb-0 fw-bold h6">Status</p> <p>Draft</p> </div> </div> <div className="row form-container" id="primary-details-form"> <div className="col-4"> <p className="mb-1 fw-bold h6">Client</p> <Controller name="customerName" control={control} register={register} rules={{ required: "Please select a Client" }} render={({ field }) => ( <CreatableSelect {...field} onChange={(e) => handleSelectCustomer(e, "customer")} value={selectedCustomer} options={customerOptions} className="quick-form-customer-select" classNamePrefix="react-select" placeholder={"Select Client"} id="customerName" styles={selectStyle} isClearable tabIndex={2} isValidNewOption={() => false} /> )} /> <div className="row mt-2"> <div className="col-12"> <p className="mb-0">{selectedCustomer?.addressLine1}</p> <p className="mb-0"> {`${ selectedCustomer?.city ?? "" } ${getFormattedProvinceStateName( selectedCustomer?.provinceState )}` ?? ""} </p> <p className="mb-0"> {selectedCustomer?.postalCode ?? ""} </p> </div> </div> </div> <div className="col-4"> <p className="mb-1 fw-bold h6">Shipper</p> <Controller name="shipperName" control={control} register={register} rules={{ required: "Please select a Shipper" }} render={({ field }) => ( <CreatableSelect {...field} onChange={(e) => handleSelectCustomer(e, "shipper")} value={selectedShipper} options={customerOptions} className="quick-form-customer-select" classNamePrefix="react-select" placeholder={"Select Shipper"} id="shipperName" styles={selectStyle} isClearable tabIndex={2} isValidNewOption={() => false} /> )} /> <div className="row mt-2"> <div className="col-12"> <p className="mb-0">{selectedShipper?.addressLine1}</p> <p className="mb-0"> {`${ selectedShipper?.city ?? "" } ${getFormattedProvinceStateName( selectedShipper?.provinceState )}` ?? ""} </p> <p className="mb-0"> {selectedShipper?.postalCode ?? ""} </p> </div> </div> </div> <div className="col-4"> <p className="mb-1 fw-bold h6 me-1">Receiver</p> <Controller name="receiverName" control={control} register={register} rules={{ required: "Please select a Receiver" }} render={({ field }) => ( <CreatableSelect {...field} onChange={(e) => handleSelectCustomer(e, "receiver")} value={selectedReceiver} options={customerOptions} className="quick-form-customer-select" classNamePrefix="react-select" placeholder={"Select Receiver"} id="customerName" styles={selectStyle} isClearable tabIndex={2} isValidNewOption={() => false} /> )} /> <div className="row mt-2"> <div className="col-12"> <p className="mb-0">{selectedReceiver?.addressLine1}</p> <p className="mb-0"> {`${ selectedReceiver?.city ?? "" } ${getFormattedProvinceStateName( selectedReceiver?.provinceState )}` ?? ""} </p> <p className="mb-0"> {selectedReceiver?.postalCode ?? ""} </p> </div> </div> </div> </div> <div className="row mt-5"> <div className="col-12"> <p className="fw-bold h6">Order Details</p> </div> <div className="col-6"> <div className="row"> <div className="col-12 mb-3"> <div className="d-flex align-items-center"> <p className="mb-1"> Pickup Details <ZoomInOutlined style={{ fontSize: "16px", marginLeft: "8px", cursor: "pointer", }} onClick={() => setpickupIsTextFieldVisible( !pickupisTextFieldVisible ) } /> </p> {pickupisTextFieldVisible && ( <div className="ms-auto"> <div className="custom-selector"> <Controller name="pickupSearchAddress" control={control} render={({ field }) => ( <ReactSelect {...field} options={formattedPickupSuggestions} className="country-select" classNamePrefix="react-select" placeholder={"Search Address"} id="pickupSearchAddress" styles={selectStyle} isClearable tabIndex={15} onInputChange={handleChange} onChange={handlePickupSelect} filterOption={() => true} // always show options /> )} /> </div> </div> )} </div> </div> <div className="col-6"> <div className="row mt-2"> <div className="col-12"> <p className="mb-0"> {selectedPickupAddress?.addressLine1} </p> <p className="mb-0"> {`${ selectedPickupAddress?.city ?? "" } ${selectedPickupAddress?.provinceState}` ?? ""} </p> <p className="mb-0"> {selectedPickupAddress?.postalCode ?? ""} </p> </div> </div> </div> <div className="col-6"> <Controller control={control} name="pickupDate" register={register} rules={{ required: "Pickup Date is required" }} render={({ field: { onChange, onBlur, value, ref }, }) => ( <DatePicker className="datepicker-field mb-3" onChange={onChange} value={value ? dayjs(value) : dayjs()} /> )} /> <Controller control={control} name="pickupTime" register={register} rules={{ required: "Pickup Time is required" }} render={({ field: { onChange, value } }) => ( <TimePicker className="timepicker-field" onChange={onChange} value={ value ? dayjs(value, "HH:mm") : dayjs("09:00", "HH:mm") } format="HH:mm" /> )} /> </div> </div> </div> <div className="col-6"> <div className="row"> <div className="col-12 mb-2"> <div className="d-flex align-items-center"> <p className="mb-1"> Dropoff Details <ZoomInOutlined style={{ fontSize: "16px", marginLeft: "8px", cursor: "pointer", }} onClick={() => setdropoffIsTextFieldVisible( !dropoffisTextFieldVisible ) } /> </p> {dropoffisTextFieldVisible && ( <div className="ms-auto"> <div className="custom-selector"> <Controller name="dropoffSearchAddress" control={control} render={({ field }) => ( <ReactSelect {...field} options={formattedDropoffSuggestions} className="country-select" classNamePrefix="react-select" placeholder={"Search Address"} id="dropoffSearchAddress" styles={selectStyle} isClearable tabIndex={15} onInputChange={handleChange} onChange={handlePickupSelect} filterOption={() => true} // always show options /> )} /> </div> </div> )} </div> </div> <div className="col-6 mt-2"> <div className="row mt-2"> <div className="col-12"> <p className="mb-0"> {selectedReceiver?.addressLine1} </p> <p className="mb-0"> {`${ selectedReceiver?.city ?? "" } ${getFormattedProvinceStateName( selectedReceiver?.provinceState )}` ?? ""} </p> <p className="mb-0"> {selectedReceiver?.postalCode ?? ""} </p> </div> </div> </div> <div className="col-6 mt-2"> <Controller control={control} name="dropoffDate" register={register} rules={{ required: "Dropoff Date is required" }} render={({ field: { onChange, onBlur, value, ref }, }) => ( <DatePicker className="datepicker-field mb-3" onChange={onChange} value={ value ? dayjs(value) : dayjs().add(2, "day") } /> )} /> <Controller control={control} name="dropoffTime" register={register} rules={{ required: "Dropoff Time is required" }} render={({ field: { onChange, value } }) => ( <TimePicker className="timepicker-field" onChange={onChange} value={ value ? dayjs(value, "HH:mm") : dayjs("09:00", "HH:mm") } format="HH:mm" /> )} /> </div> </div> </div> <div className="col-6 mt-4"> <p className="mb-1 h8 me-1">Address Notes</p> <div className="row mt-2"> <div className="col-12"> <textarea className="form-control" id="addressNotes1" rows="5" maxLength={1000} tabIndex={15} /> </div> </div> </div> <div className="col-6 mt-4"> <p className="mb-1 h8 me-1">Address Notes</p> <div className="row mt-2"> <div className="col-12"> <textarea className="form-control" id="addressNotes2" rows="5" maxLength={1000} tabIndex={16} /> </div> </div> </div> </div> <div className="row mt-5"> <div className="col-8"> <p className="fw-bold h6">Freight</p> </div> <div className="col-4"> <button type="button" className="btn btn-md btn-color-3 me-2 mb-4 w-100" onClick={handleAddLoadItem} > Add Load Item </button> </div> <div className={`col-12 mb-2`}> <div className={`ag-theme-alpine form-content-section-container color-3-grid p-0 shadow-sm`} > <AgGridReact className="no-header" rowData={loadItems} columnDefs={[ { field: "Description", minWidth: 140, cellClass: "grid-column gray", editable: true, }, { field: "Quantity", minWidth: 90, cellClass: "grid-column gray", editable: true, cellEditor: NumericCellEditor, }, { field: "Packaging Type", minWidth: 140, cellClass: "grid-column gray", editable: true, cellEditor: PackagingTypeEditor, cellEditorParams: { values: PACKAGING_TYPE, }, valueFormatter: (params) => { return enumValueFormatter(params, PACKAGING_TYPE); }, }, { field: "Weight", minWidth: 90, cellClass: "grid-column gray", editable: true, }, { field: "Item Value", minWidth: 100, cellClass: "grid-column gray", editable: true, cellEditor: NumericCellEditor, valueFormatter: (params) => { return formatCurrency(params.value); }, }, ]} ref={loadItemsGridRef} defaultColDef={defaultColDef} onGridReady={onGridReady} onColumnSizeChanged={onColumnsSizeChanged} domLayout="autoHeight" onGridSizeChanged={onGridSizeChanged} rowHeight={GRID_CONSTANTS.ROW_HEIGHT} ></AgGridReact> </div> </div> </div> <div className="row mt-5"> <div className="col-5"> <p className="fw-bold h6">Accessorials</p> </div> <div className="col-7 d-flex justify-content-end"> <Select onChange={(accessorial) => setSelectedAccessorial(accessorial) } options={accessorialOptions} value={selectedAccessorial} placeholder={"Select Accessorial"} className="order-select-container me-2" classNamePrefix="react-select" isClearable styles={selectStyle} /> <button type="button" className="btn btn-md btn-color-3 me-2 mb-4 w-100" onClick={handleAddAccessorial} > Add Accessorial </button> </div> <div className={`col-12 mb-2`}> <div className={`ag-theme-alpine form-content-section-container color-3-grid p-0 shadow-sm`} > <AgGridReact className="no-header" rowData={accessorials} columnDefs={[ { field: "Name", width: 80, cellClass: "grid-column gray", editable: true, }, { field: "Description", minWidth: 150, cellClass: "grid-column gray", editable: true, }, ]} ref={accessorialsGridRef} defaultColDef={defaultColDef} onGridReady={onGridReady} onColumnSizeChanged={onColumnsSizeChanged} domLayout="autoHeight" onGridSizeChanged={onGridSizeChanged} rowHeight={GRID_CONSTANTS.ROW_HEIGHT} ></AgGridReact> </div> </div> </div> <div className="row align-items-center mt-5 mb-4"> <div className="col-6"> <p className="fw-bold h6">Quote</p> </div> {/* <div className="col-6"> <button type="button" className="btn btn-md btn-color-3 w-100" // onClick={handleAddQuote} > Add Quote </button> </div> */} <div className="col-6 d-flex justify-content-end"> <div className={`d-flex justify-content-center align-items-center status-container status-draft me-2`} > <p className="status-text mb-0 fw-bold">DRAFT</p> </div> <button type="button" className={`btn btn-color-delete btn-sm me-2`} > <DeleteOutlined /> </button> <button type="button" className={`btn btn-color-1 btn-sm`}> <LikeOutlined /> </button> </div> </div> <div className="row mt-2"> <div className="col-3"> <input type="text" className="form-control quick-order-form-input" id="quoteName" tabIndex={1} placeholder="Quote Name" autoComplete="on" {...register("quoteName", { required: "Quote Name is required", })} /> </div> <div className="col-3"> <Controller control={control} name="quoteDate" register={register} rules={{ required: "Quote Date is required" }} render={({ field: { onChange, onBlur, value, ref } }) => ( <DatePicker className="datepicker-field" onChange={onChange} value={value} /> )} /> </div> <div className="col-3"> <input type="text" className="form-control quick-order-form-input" id="total" tabIndex={1} placeholder="Total" disabled {...register("quoteTotal")} /> </div> <div className="col-3"> <input type="text" className="form-control quick-order-form-input" id="quoteId" tabIndex={1} placeholder="Quote ID" disabled {...register("quoteId")} /> </div> <div className={`col-12 mb-2 mt-3`}> <div className={`ag-theme-alpine form-content-section-container color-3-grid p-0 shadow-sm`} > <AgGridReact className="no-header" rowData={quoteItems} columnDefs={[ { field: "Category", minWidth: 110, cellClass: (params) => [ "grid-column", `${params.data.UpdateStatus === 1 && "bold"}`, ], cellEditor: QuoteItemCategoryEditor, cellEditorParams: (params) => { if ( params.data && (params.data.Type === 1 || params.data.Type === 2) ) { const filteredCategory = params.data.Type === 1 ? QUOTE_ITEM_CATEGORY.filter( (item) => item.value !== 0 && item.value !== 3 ) : QUOTE_ITEM_CATEGORY.filter( (item) => item.value !== 0 ); return { values: filteredCategory, api: params.api, }; } else { return {}; } }, valueSetter: (params) => { const selectedValue = parseInt( params.newValue, 10 ); params.data.Category = selectedValue; params.data.Quantity = params.data.Category === 3 ? 0 : 1; calculateQuoteItem(params); return true; }, cellRenderer: QuoteItemCategoryRenderer, cellRendererParams: { editable: true }, editable: (params) => (params.data.Type === 1 || params.data.Type === 2) && true, getQuickFilterText: (params) => { const categoryValue = params.value; return getQuickFilterValue( categoryValue, QUOTE_ITEM_CATEGORY ); }, }, { field: "Description", minWidth: 120, cellClass: (params) => [ "grid-column gray", `${params.data.UpdateStatus === 1 && "bolded"}`, ], editable: (params) => params.data.Type === 3, }, { field: "Quantity", headerName: "Qty", cellClass: "grid-column gray", editable: true, valueFormatter: (params) => { return params.data.Category === 3 ? params.value + "%" : params.value; }, valueSetter: (params) => calculateQuoteItem(params), }, { field: "Rate", valueFormatter: (params) => { return formatCurrency(params.value); }, cellClass: "grid-column gray", editable: true, valueFormatter: (params) => { return formatCurrency(params.value); }, valueSetter: (params) => calculateQuoteItem(params), }, { field: "Total", valueFormatter: (params) => { return formatCurrency(params.value); }, cellClass: "grid-column gray", }, { field: "Edit", headerName: "", cellClass: "d-flex flex-row-reverse", autoHeight: true, cellRenderer: DeleteItemActionRenderer, cellRendererParams: (props) => ({ header: "Quote Item", parentType: "Quote", props: props, handleSubmit: handleSubmit, handleDeleteFunction: handleDeleteQuoteItem, }), }, ]} ref={quotesGridRef} defaultColDef={defaultColDef} onGridReady={onGridReady} onColumnSizeChanged={onColumnsSizeChanged} domLayout="autoHeight" rowSelection={"single"} onGridSizeChanged={onGridSizeChanged} rowHeight={GRID_CONSTANTS.ROW_HEIGHT} tabToNextCell={tabToNextCell} ></AgGridReact> </div> </div> <div className="d-flex justify-content-end"> <button type="button" className="btn btn-md btn-color-3 mt-2" onClick={handleAddQuoteItem} > Add Quote Item </button> </div> </div> <div className="col-12 mb-2 mt-1"> <label htmlFor="notes" className="form-label"> Notes: </label> <textarea className="form-control" id="notes" rows="5" tabIndex={9} {...register("notes")} // defaultValue={isQuoteEdit ? selectedQuote?.Notes || '' : ''} // onChange={updateNoteStatus} // disabled={checkPageEditable()} /> <small className="form-error-message"> {/* {errors?.notes && errors.notes.message} */} </small> </div> <div className="row mt-5"> <div className="col-12"> <div className="d-flex flex-row align-items-center"> <button className={`ms-auto btn btn-primary`} type="button" onClick={() => handleUpdateLoadItems(true)} > Save </button> </div> </div> </div> </div> </form> </div> </div> </div> <CreateOrderModal modal={createOrderModal} setModal={setCreateOrderModal} toggle={createOrderToggle} customerOptions={customerOptions} customerCreationInformation={customerCreationInformation} setCustomerCreationInformation={setCustomerCreationInformation} toggleFormCancelDisplay={toggleFormCancelDisplay} /> <CreateCustomerModal modal={createCustomerModal} setModal={setCreateCustomerModal} toggle={createCustomerToggle} handleSelectCustomer={handleSelectCustomer} selectedFieldType={selectedFieldType} /> </div> ); } export default Orders;
Editor is loading...
Leave a Comment