diff --git a/src/Components/Menu/PozoMenu.jsx b/src/Components/Menu/PozoMenu.jsx
index b9d861e..fa56b0d 100644
--- a/src/Components/Menu/PozoMenu.jsx
+++ b/src/Components/Menu/PozoMenu.jsx
@@ -1,5 +1,4 @@
-import React, { useState, useRef, useEffect } from 'react';
-import { AppstoreOutlined, MailOutlined, SettingOutlined, } from '@ant-design/icons';
+import { useState, useRef, useEffect } from 'react';
import { FaCaretRight } from "react-icons/fa";
import './PozoMenu.scss';
@@ -8,7 +7,6 @@ const PozoMenu = ({ items = [], mode = "vertical", style = {}, onClick, collapse
const [openKeys, setOpenKeys] = useState([]);
const [selectedKey, setSelectedKey] = useState('');
const [dropdownPositions, setDropdownPositions] = useState({});
- console.log(dropdownPositions, "dropdownPositions")
const [isMobile, setIsMobile] = useState(window.innerWidth <= 768);
const menuRef = useRef();
@@ -115,7 +113,7 @@ const PozoMenu = ({ items = [], mode = "vertical", style = {}, onClick, collapse
// Image 2: No space on right, space on left - open to LEFT
position.left = rect.left - dropdownWidth - gap + scrollX;
position.direction = 'left';
- console.log('✅ Opening LEFT - no space on right');
+
} else {
// Edge case: Limited space on both sides
if (spaceRight >= spaceLeft) {
@@ -245,7 +243,7 @@ const PozoMenu = ({ items = [], mode = "vertical", style = {}, onClick, collapse
// Calculate position and add to dropdown positions
const position = calculatePosition(event.currentTarget, parentKeys.length);
- console.log('🎯 Setting position for', itemKey, ':', position);
+
setDropdownPositions(prev => {
// Remove positions for closed items
@@ -254,7 +252,6 @@ const PozoMenu = ({ items = [], mode = "vertical", style = {}, onClick, collapse
if (prev[key]) newPos[key] = prev[key];
});
newPos[itemKey] = position;
- console.log('🎯 Updated dropdown positions:', newPos);
return newPos;
});
@@ -276,11 +273,6 @@ const PozoMenu = ({ items = [], mode = "vertical", style = {}, onClick, collapse
});
}
- console.log('Menu item clicked:', {
- key: item.key,
- keyPath: [...parentKeys, item.key],
- label: item.label
- });
}
};
@@ -415,8 +407,6 @@ const PozoMenu = ({ items = [], mode = "vertical", style = {}, onClick, collapse
}, [items, openKeys]);
- console.log(submenuRefs, "menuRef")
-
return (
{
- console.log(ProdData, 'ProdData');
if (
ProdData?.CompId != null &&
- ProdData?.CompId != undefined &&
ProdData?.BranchId != null &&
- ProdData?.BranchId != undefined &&
- ProdData?.AppId != null &&
- ProdData?.AppId != undefined &&
- ProdData?.OrderFromDate &&
- ProdData?.OrderToDate
+ ProdData?.AppId != null
) {
const params = new URLSearchParams({
compId: ProdData.CompId,
branchId: ProdData.BranchId,
appId: ProdData.AppId,
- fromDate: ProdData.OrderFromDate,
- toDate: ProdData.OrderToDate,
});
+ // ✅ Add dates only if present
+ if (ProdData?.OrderFromDate) {
+ params.append('fromDate', ProdData.OrderFromDate);
+ }
+
+ if (ProdData?.OrderToDate) {
+ params.append('toDate', ProdData.OrderToDate);
+ }
+
+ // ✅ Search
if (ProdData?.search) {
params.append('searchText', ProdData.search);
}
+
+ // ✅ Pagination
if (ProdData?.PageNumber) {
params.append('pageNumber', ProdData.PageNumber);
}
- return await axiosRetailInstanceData.get(
+ return axiosRetailInstanceData.get(
`/Purchase?${params.toString()}`
);
}
+
+ // optional safety
+ return Promise.reject('Missing required parameters');
}
);
+
export const putStockData = createAsyncThunk(
'Stock/postStockData',
async (putData) => {
diff --git a/src/Pages/StockMaster/AddAllProductGrid.jsx b/src/Pages/StockMaster/AddAllProductGrid.jsx
new file mode 100644
index 0000000..a8f8da1
--- /dev/null
+++ b/src/Pages/StockMaster/AddAllProductGrid.jsx
@@ -0,0 +1,151 @@
+import { Tooltip } from 'antd';
+import { v4 as uuidv4 } from 'uuid';
+
+const AddAllProductsButton = ({
+ productData = [],
+ purchaseData = [],
+ setPurchaseData,
+ form,
+ setIsLoading,
+ setLoadingText,
+ batchSize = 100,
+ SelectedPurcTaxType,
+}) => {
+ // This function just returns a prepared product object, no state changes
+
+ const ProductDropDownChange = async (
+ VariantName,
+ ProdId,
+ option,
+ productsList,
+ extractedProduct = false,
+ extractedItem
+ ) => {
+ const ProductData1 = (productsList || productData)?.find(
+ (p) => p.ProdId === ProdId && p.ProdVariantName === VariantName
+ );
+ if (!ProductData1) return null;
+
+ const DefaultVariant = ProductData1?.ProdVariantPriceDetails?.find(
+ (item) => item?.DefaultVariant === 'Y' && item?.ReceivedQty === 0
+ )?.DefaultVariant;
+
+ const qty = extractedProduct
+ ? parseFloat(extractedItem?.parsedData?.qty) || 0
+ : 0;
+ const acceptedQty = extractedProduct
+ ? parseFloat(extractedItem?.parsedData?.qty) || 0
+ : 0;
+ const rate = extractedProduct
+ ? parseFloat(extractedItem?.parsedData?.rate) || 0
+ : 0;
+
+ return {
+ DefaultVariant,
+ ProdId: ProductData1.ProdId,
+ MRP: ProductData1.MRP,
+ ProdName: ProductData1.ProdName,
+ UomName: ProductData1.UomName,
+ SellPrice: ProductData1.SellPrice,
+ StockAvailable: ProductData1.StockAvailable,
+ OnePcsAvailable: ProductData1.OnePcsAvailable,
+ OnePcsPrice: ProductData1.OnePcsPrice,
+ NoOfPcs: ProductData1.NoOfPcs,
+ TaxId: ProductData1.TaxId,
+ TaxPercentage: ProductData1.TaxPercentage,
+ ProdVariantName: ProductData1.ProdVariantName,
+ PurchaseTax: parseFloat(extractedItem?.parsedData?.tax) || 0,
+ BalanceQty: qty,
+ InwardPrice: rate,
+ PurcDisc: 0,
+ Amount: isNaN(rate) || isNaN(acceptedQty) ? 0 : rate * acceptedQty,
+ WhSalePrice: 0,
+ ReceivedQty: qty,
+ AcceptedQty: acceptedQty,
+ RejectedQty: qty - acceptedQty,
+ OfferPrice: 0,
+ SpecialPrice: 0,
+ FreeItem: 0,
+ TaxAmt: 0,
+ TaxType: SelectedPurcTaxType || 0,
+ PurcDiscType: 'P',
+ refImage: extractedItem?.parsedData?.image,
+ PurchaseHSNCode: extractedItem?.parsedData?.hsn || '',
+ localId: uuidv4(),
+ };
+ };
+
+ const handleAddAll = async () => {
+ try {
+ setIsLoading(true);
+ setLoadingText('Adding products...');
+
+ // allow UI paint
+ await new Promise((r) => requestAnimationFrame(r));
+
+ const allValidProducts = [];
+ const allFormValues = {};
+
+ for (let i = 0; i < productData.length; i += batchSize) {
+ const batch = productData.slice(i, i + batchSize);
+
+ setLoadingText(
+ `Processing ${Math.min(i + batchSize, productData.length)} / ${
+ productData.length
+ }`
+ );
+
+ const batchProducts = await Promise.all(
+ batch.map((product) =>
+ ProductDropDownChange(
+ product.ProdVariantName,
+ product.ProdId,
+ {
+ label: `${product.ProdName} (${product.Size} ${product.UomName})${
+ product.BrandName ? ` - ${product.BrandName}` : ''
+ }`,
+ },
+ productData
+ )
+ )
+ );
+
+ const valid = batchProducts.filter(Boolean);
+ allValidProducts.push(...valid);
+
+ valid.forEach((p) => {
+ const id = p.localId;
+ allFormValues[`SellPrice${id}`] = p.SellPrice;
+ allFormValues[`PurchaseTax${id}`] = p.PurchaseTax;
+ allFormValues[`BalanceQty${id}`] = p.BalanceQty;
+ allFormValues[`ReceivedQty${id}`] = p.ReceivedQty;
+ allFormValues[`AcceptedQty${id}`] = p.AcceptedQty;
+ allFormValues[`RejectedQty${id}`] = p.RejectedQty;
+ allFormValues[`InwardPrice${id}`] = p.InwardPrice;
+ allFormValues[`Amount${id}`] = p.Amount;
+ });
+
+ await new Promise((r) => setTimeout(r, 0));
+ }
+
+ // ✅ ONE state update
+ setPurchaseData((prev) => [...allValidProducts, ...prev]);
+
+ // ✅ ONE form update
+ form?.setFieldsValue(allFormValues);
+ } finally {
+ setIsLoading(false);
+ setLoadingText('');
+ }
+ };
+
+ return (
+
+
+
+ );
+};
+
+export default AddAllProductsButton;
diff --git a/src/Pages/StockMaster/SettingsIconWithModal.jsx b/src/Pages/StockMaster/SettingsIconWithModal.jsx
new file mode 100644
index 0000000..2b673c9
--- /dev/null
+++ b/src/Pages/StockMaster/SettingsIconWithModal.jsx
@@ -0,0 +1,99 @@
+import React, { useState } from 'react';
+import { Tooltip } from '@mui/material';
+import { IoSettingsOutline } from 'react-icons/io5';
+import { DefaultModal } from '../../Components/Modal/DefaultModal.jsx';
+
+
+const SettingsIconWithModal = ({
+ tooltipTitle = 'Add Fields',
+ tableFieldPreferences = [],
+ selectedAdditionalColumn = [],
+ onSubmit,
+}) => {
+ const [open, setOpen] = useState(false);
+ const [selectedFields, setSelectedFields] = useState([]);
+ const [tempSelectedColumns, setTempSelectedColumns] = useState([]);
+
+ const handleIconClick = () => {
+ // map labels → values
+ const mappedFields = selectedAdditionalColumn
+ .map(
+ (col) =>
+ tableFieldPreferences.find((pref) => pref.label === col)?.value
+ )
+ .filter(Boolean);
+
+ setSelectedFields(mappedFields);
+ setTempSelectedColumns([...selectedAdditionalColumn]);
+ setOpen(true);
+ };
+
+ const handleCancel = () => {
+ setOpen(false);
+ setTempSelectedColumns([]);
+ };
+
+ const handleApply = () => {
+ onSubmit({
+ selectedFields,
+ tempSelectedColumns,
+ closeModal: () => setOpen(false),
+ resetTemp: () => setTempSelectedColumns([]),
+ });
+ };
+
+ return (
+ <>
+ {/* ⚙️ ICON ONLY */}
+
+
+
+
+ {/* MODAL */}
+
+
+ {tableFieldPreferences.map((option) => (
+
+
+
+ ))}
+
+
+ >
+ );
+};
+
+export default SettingsIconWithModal;
diff --git a/src/Pages/StockMaster/StockList.jsx b/src/Pages/StockMaster/StockList.jsx
index ad84da5..28e9c20 100644
--- a/src/Pages/StockMaster/StockList.jsx
+++ b/src/Pages/StockMaster/StockList.jsx
@@ -2,7 +2,7 @@ import { useState, useEffect, useRef, useCallback } from 'react';
import { useNavigate, useLocation } from 'react-router-dom';
import { useDispatch, useSelector } from 'react-redux';
import { PlusOutlined, EyeOutlined, PrinterFilled } from '@ant-design/icons';
-import { Image, Pagination, Space, Table } from 'antd';
+import { Image, Pagination, Space, Table, Tooltip } from 'antd';
import {
changeBreadCrumb,
getEmpAccess,
@@ -59,6 +59,7 @@ import StickerPrintTemplates from '../Product/StickerTemplates.jsx';
import QRCodeCopiesModal from '../Product/QRCodeCopiesModal.jsx';
import { DatePicker } from 'antd';
import {
+ formatDateForAPI,
generateBarcode,
generateCodeImage,
generateQRCode,
@@ -142,7 +143,6 @@ const StockList = () => {
const [selectedRecords, setSelectedRecords] = useState([]);
const [activeTab, setActiveTab] = useState('stock');
const [MultiCode, setMultiCode] = useState(true);
- const [TotalCount, setTotalCount] = useState(null);
const [dateStrings, setDateStrings] = useState([
dayjs().format('YYYY-MM-DD'),
dayjs().format('YYYY-MM-DD'),
@@ -233,16 +233,15 @@ const StockList = () => {
AppId: AppId,
BranchId: BranchId,
CompId: CompId,
- OrderFromDate: dates?.[0] ?? '',
- OrderToDate: dates?.[1] ?? '',
+ OrderFromDate: formatDateForAPI(dates?.[0]) ?? '',
+ OrderToDate: formatDateForAPI(dates?.[1]) ?? '',
PageNumber: page,
})
).unwrap();
if (Response?.data?.statusCode === 1) {
- setTotalCount(Response?.data?.TotalCount);
return Response?.data?.data;
} else {
- setTotalCount(0);
+
return [];
}
};
@@ -287,17 +286,16 @@ const StockList = () => {
AppId: AppId,
BranchId: BranchId,
CompId: CompId,
- OrderFromDate: dateStrings?.[0] ?? '',
- OrderToDate: dateStrings?.[1] ?? '',
+ // OrderFromDate: dateStrings?.[0] ?? '',
+ // OrderToDate: dateStrings?.[1] ?? '',
search: SearchText,
})
).unwrap();
if (Response?.data?.statusCode === 1) {
- setTotalCount(Response?.data?.TotalCount);
setpage(1);
return Response?.data?.data;
} else {
- setTotalCount(0);
+
return [];
}
}
@@ -703,9 +701,9 @@ const StockList = () => {
dispatch(
getSupplierData({ AppId: AppId, BranchId: BranchId, CompId: CompId })
);
- dispatch(
- getPurchaseData({ AppId: AppId, BranchId: BranchId, CompId: CompId })
- );
+ // dispatch(
+ // getPurchaseData({ AppId: AppId, BranchId: BranchId, CompId: CompId })
+ // );
let ProdData = {
AppId: AppId,
@@ -894,25 +892,25 @@ const StockList = () => {
PaymentAmount: PaymentAmount.toFixed(2),
InvoiceDate: groupInfo.InwardDate
? moment(groupInfo.InwardDate, 'YYYY-MM-DD').format(
- 'YYYY-MM-DDTHH:mm:ss'
- )
+ 'YYYY-MM-DDTHH:mm:ss'
+ )
: null,
SuppInvoiceNo: groupInfo.SupplierInvoiceNumber,
SuppInvoiceDate: groupInfo.SupplierInvoiceDate
? moment(groupInfo.SupplierInvoiceDate, 'YYYY-MM-DD').format(
- 'YYYY-MM-DDTHH:mm:ss'
- )
+ 'YYYY-MM-DDTHH:mm:ss'
+ )
: null,
DeliveryChallanNo: groupInfo.DeliveryChallanNo,
DeliveryInvoiceDate: groupInfo.DeliveryInvoiceDate
? moment(groupInfo.DeliveryInvoiceDate, 'YYYY-MM-DD').format(
- 'YYYY-MM-DDTHH:mm:ss'
- )
+ 'YYYY-MM-DDTHH:mm:ss'
+ )
: null,
DueDate: groupInfo.DueDate
? moment(groupInfo.DueDate, 'YYYY-MM-DD').format(
- 'YYYY-MM-DDTHH:mm:ss'
- )
+ 'YYYY-MM-DDTHH:mm:ss'
+ )
: null,
InvoiceAmount: Totalamount.toFixed(2),
TaxAmount: Totaltax.toFixed(2),
@@ -930,13 +928,13 @@ const StockList = () => {
FreeQty: item.FreeQty,
ManufDate: item.ManufactureDate
? moment(item.ManufactureDate, 'YYYY-MM-DD').format(
- 'YYYY-MM-DDTHH:mm:ss'
- )
+ 'YYYY-MM-DDTHH:mm:ss'
+ )
: null,
ExpDate: item.ExpireDate
? moment(item.ExpireDate, 'YYYY-MM-DD').format(
- 'YYYY-MM-DDTHH:mm:ss'
- )
+ 'YYYY-MM-DDTHH:mm:ss'
+ )
: null,
BatchNo: item.BatchNo,
ModelNo: item.ModelNo,
@@ -989,14 +987,10 @@ const StockList = () => {
const productName = checkComponent('Product Name');
setPrintProductName(productName);
};
- // const ProductName = Productdata ?.map((e)=>e.ProdName+' '(+e.Size+' '+e.UomName))
const ProductName = Productdata?.map(
(e) => `${e.ProdName} (${e.Size} ${e.UomName})`
);
- // const ProductName = Varientdata?.map((e)=>e.ProdName)
- // const ProductName = Productdata?.map((e)=>e.ProdName)
- // const ProductSize = Productdata ?.map((e)=>e.Size)
- // const ProductUomName = Productdata ?.map((e)=>e.UomName)
+
const SupplierNames = SupplierData?.map((e) => e.SuppName);
@@ -1012,33 +1006,8 @@ const StockList = () => {
const InwardDtlIds = Varientdata?.map((e) => e.InwardDtlId);
const StockProductId = Varientdata?.map((e) => e.ProdId);
- // let proddetail = StockData?.map((e) => {
- // return {
- // ...e,
- // ProdDetails: e.ProdDetails?.map((d) => ({
- // ...d,
- // InvoiceNo: e.InvoiceNo,
- // InvoiceDate: e.InvoiceDate,
- // InvoiceAmt: e.InvoiceAmount
- // }))
- // };
- // });
- // let subObjectsArray = [];
- // // Iterate over mainObjects and concatenate subObjects arrays
- // proddetail.forEach(obj => {
- // subObjectsArray = subObjectsArray.concat(obj.ProdDetails);
- // });
- // function safeRound(amountStr) {
- // if (amountStr == null) return allowDecimal ? '0.00' : '0';
- // const cleaned = String(amountStr).replace(/[^0-9.-]+/g, '');
- // const num = Number(cleaned);
-
- // if (isNaN(num)) return allowDecimal ? '0.00' : '0';
-
- // return allowDecimal ? num.toFixed(2) : Math.round(num).toString();
- // }
const onFinish = async () => {
const template = barcodeTemplateDetails?.find(
@@ -1194,7 +1163,8 @@ const StockList = () => {
? countData?.length
? countData?.length
: 0
- : TotalCount;
+ : data?.[0]?.TotalCount;
+ console.log(debouncedSearchText, countData, data, "kkkk", countOfProduct)
return (
@@ -1210,14 +1180,15 @@ const StockList = () => {
-
-
-
+ >
+
+
+
+
{
data={filteredData}
dataSource={filteredData}
onChange={handleChange}
- // pagination={handlePageChange}
+ // pagination={handlePageChange}
/>{' '}
{countOfProduct > 10 && (
{
+ const timer = useRef(null);
+
+ return useCallback(
+ (...args) => {
+ if (timer.current) clearTimeout(timer.current);
+
+ timer.current = setTimeout(() => {
+ fn(...args);
+ }, delay);
+ },
+ [fn, delay]
+ );
+};
diff --git a/src/Pages/StockMaster/VirtualizedTable.jsx b/src/Pages/StockMaster/VirtualizedTable.jsx
new file mode 100644
index 0000000..b2b610f
--- /dev/null
+++ b/src/Pages/StockMaster/VirtualizedTable.jsx
@@ -0,0 +1,171 @@
+import { useRef } from 'react';
+import { useVirtualizer } from '@tanstack/react-virtual';
+
+const VirtualizedTable = ({
+ dataSource = [],
+ columns = [],
+ rowHeight = 54,
+ height = '50vh',
+ overscan = 10,
+ rowKey = 'id',
+}) => {
+ const parentRef = useRef();
+ const headerRef = useRef();
+
+ const rowVirtualizer = useVirtualizer({
+ count: dataSource.length,
+ getScrollElement: () => parentRef.current,
+ estimateSize: () => rowHeight,
+ overscan,
+ });
+
+ const handleBodyScroll = (e) => {
+ if (headerRef.current) {
+ headerRef.current.scrollLeft = e.target.scrollLeft;
+ }
+ };
+
+ const virtualItems = rowVirtualizer.getVirtualItems();
+ const totalSize = rowVirtualizer.getTotalSize();
+
+ return (
+
+ {/* Header */}
+
+
+
+
+ {columns.map((col) => (
+ |
+ {col.title}
+ |
+ ))}
+
+
+
+
+
+ {/* Body */}
+
+
+ {virtualItems.map((virtualRow) => {
+ const record = dataSource[virtualRow.index];
+ const key = record?.[rowKey] || virtualRow.index;
+
+ return (
+
+
+
+
+ {columns.map((col) => (
+ |
+ {col.render
+ ? col.render(
+ record?.[col.dataIndex],
+ record,
+ virtualRow.index
+ )
+ : record?.[col.dataIndex]}
+ |
+ ))}
+
+
+
+
+ );
+ })}
+
+
+
+ {dataSource.length === 0 && (
+
+ No data
+
+ )}
+
+ );
+};
+
+export default VirtualizedTable;
diff --git a/src/Styles/Stock/StockMaster.scss b/src/Styles/Stock/StockMaster.scss
index 8274819..28b0852 100644
--- a/src/Styles/Stock/StockMaster.scss
+++ b/src/Styles/Stock/StockMaster.scss
@@ -36,7 +36,6 @@
}
.Product-table {
-
table {
border-spacing: unset;
}
@@ -88,7 +87,7 @@
width: 180px !important;
}
- >div:nth-child(2) {
+ > div:nth-child(2) {
p {
display: none !important;
}
@@ -146,7 +145,7 @@
max-width: 130px !important;
}
- >td:nth-child(3) {
+ > td:nth-child(3) {
.ant-input {
width: max-content !important;
max-width: 70px !important;
@@ -154,7 +153,7 @@
}
}
- >td:nth-child(5) {
+ > td:nth-child(5) {
.ant-input {
width: max-content !important;
max-width: 100px !important;
@@ -325,12 +324,12 @@
}
.purchase-status {
- >div:nth-child(1) {
+ > div:nth-child(1) {
display: flex;
align-items: center;
gap: 10px;
- >p {
+ > p {
padding-bottom: 0 !important;
}
}
@@ -448,7 +447,7 @@
.invoice-date {
.ant-form-item-control-input-content {
- >label {
+ > label {
font-family: 'Poppins';
font-weight: 500;
}
@@ -474,7 +473,7 @@
gap: 1rem;
margin-bottom: 10px;
- >button {
+ > button {
font-family: 'Poppins';
background-color: #ef4444;
color: #fff;
@@ -482,8 +481,8 @@
align-items: center;
.ant-btn-icon {
- >span {
- >svg {
+ > span {
+ > svg {
width: 13px;
height: 13px;
}
@@ -566,8 +565,6 @@
width: 100%;
}
-
-
.stock-input {
// width: 100vw;
width: 100%;
@@ -608,8 +605,6 @@
width: 100%;
}
-
-
.stock-input {
width: 100vw;
}
@@ -781,13 +776,12 @@
}
}
-
.addallProductTBN {
border: none;
outline: none;
padding: 8px 16px;
width: max-content;
- font-family: "Poppins";
+ font-family: 'Poppins';
font-weight: 500;
font-size: 14px;
cursor: pointer;
@@ -822,9 +816,26 @@
}
.imeiSNTable {
-
.ant-input {
padding: 4px 4px !important;
text-align: center;
}
-}
\ No newline at end of file
+}
+
+
+.proReceiptTD {
+ .ant-input {
+ width: 100% !important;
+ height: 35px !important;
+ padding: 2px !important;
+ text-align: center;
+ }
+}
+
+@media (max-width: 500px) {
+ .tdProductrecipt,
+ .proReceiptTD {
+ font-size: 12px !important;
+ }
+
+}