2026-02-12 15:46:52 +05:30
|
|
|
import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
|
|
|
|
|
import { Table, Input, Select, Button } from 'antd';
|
|
|
|
|
import { PlusOutlined, DeleteOutlined, SaveOutlined, PrinterOutlined } from '@ant-design/icons';
|
2026-02-12 15:51:08 +05:30
|
|
|
import { Tables } from '../../../../Components/Tables/Table.jsx';
|
2026-02-12 15:46:52 +05:30
|
|
|
import { useDispatch } from 'react-redux';
|
|
|
|
|
import { postProductData, getDirectSaleProducts, getAllProductShortCodes, deleteProductData, getDirectSaleSearchedProduct } from '../../../../Features/ProductPage/ProductPage.js';
|
2026-02-12 15:51:08 +05:30
|
|
|
import { getSession, printDiv } from '../../../../Services/Others.js';
|
2026-02-12 15:46:52 +05:30
|
|
|
import { Messages } from '../../../../Components/Notifications/Messages.jsx';
|
|
|
|
|
import { FaStarOfLife } from "react-icons/fa6";
|
|
|
|
|
import { IoMdRefresh } from "react-icons/io";
|
|
|
|
|
import StickerPrintModel from '../../../Product/StickerPrintModal.jsx';
|
|
|
|
|
import { getPageStyle, style } from '../../../Product/Printstyles.js';
|
|
|
|
|
import { getBarcodeSessionsIDs, getBarcodeTemplate } from '../../../../Features/Barcode/Barcode.js';
|
|
|
|
|
import { generateBarcode, generateQRCode, generateQRCodeCopy } from '../../../../Services/utils.js';
|
|
|
|
|
import StickerPrintTemplates from '../../../Product/StickerTemplates.jsx';
|
|
|
|
|
import useBarcodeGenerator from './useBarcodeQRGenerator.js';
|
|
|
|
|
|
|
|
|
|
const DirectSale = ({ UomData = [], TaxData = [], ProductTypeData = [], ProdCatData = [], ProdSubCatData = [], SupplierData = [], activeTab = null }) => {
|
|
|
|
|
|
|
|
|
|
const formRef = useRef();
|
|
|
|
|
const tableRef = useRef();
|
|
|
|
|
const searchInputRef = useRef();
|
|
|
|
|
const dispatch = useDispatch();
|
|
|
|
|
const [messageType, setMessageType] = useState(null);
|
|
|
|
|
const [messageData, setMessageData] = useState(null);
|
|
|
|
|
const [currentPage, setCurrentPage] = useState(1);
|
|
|
|
|
|
|
|
|
|
const CompId = getSession('CompId');
|
|
|
|
|
const BranchId = getSession('BranchId');
|
|
|
|
|
const AppId = getSession('AppId');
|
|
|
|
|
const UserId = getSession('UserId');
|
|
|
|
|
|
|
|
|
|
const [dataSource, setDataSource] = useState([]);
|
|
|
|
|
const [editingKey, setEditingKey] = useState(null);
|
|
|
|
|
|
|
|
|
|
const [copies, setCopies] = useState(null);
|
|
|
|
|
const [dropdownValue, setDropdownValue] = useState(null);
|
|
|
|
|
const [multiProduct, setMultiProduct] = useState(false);
|
|
|
|
|
const [printReady, setPrintReady] = useState(false);
|
|
|
|
|
const [printProductName, setPrintProductName] = useState(false);
|
|
|
|
|
const [productShortCodes, setAllProductShortCodes] = useState([]);
|
|
|
|
|
const [searchText, setSearchText] = useState('');
|
|
|
|
|
console.log(searchText, "searchText")
|
|
|
|
|
const [stickerPrintModalOpen, setStickerPrintModalOpen] = useState(false);
|
|
|
|
|
const [barcodeTemplateDetails, setBarcodeTemplateDetails] = useState([]);
|
|
|
|
|
const [filteredProducts, setFilteredProducts] = useState([]);
|
|
|
|
|
const [labelPrintData, setLabelPrintData] = useState(null);
|
|
|
|
|
const [prodId, setProdId] = useState(null);
|
|
|
|
|
const [nickName, setNickName] = useState(null);
|
|
|
|
|
const [crossData, setCrossData] = useState(null);
|
|
|
|
|
const [triggerState, setTriggerState] = useState(1);
|
|
|
|
|
const [templateOptions, setTemplateOptions] = useState({
|
|
|
|
|
mrp: false,
|
|
|
|
|
barcode: false,
|
|
|
|
|
color: false,
|
|
|
|
|
eDate: false,
|
|
|
|
|
mDate: false,
|
|
|
|
|
sellingPrice: false,
|
|
|
|
|
productName: false,
|
|
|
|
|
value: '',
|
|
|
|
|
secondValue: '',
|
|
|
|
|
qrcode: false,
|
|
|
|
|
codeType: '',
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
console.log((searchText != null && searchText != ''), "filteredProducts")
|
|
|
|
|
|
|
|
|
|
const { qrBase64, barcodeBase64 } = useBarcodeGenerator(prodId);
|
|
|
|
|
|
|
|
|
|
const handleAdd = () => {
|
|
|
|
|
setDataSource([{
|
|
|
|
|
key: dataSource.length + 1,
|
|
|
|
|
productName: '',
|
|
|
|
|
shortCode: '',
|
|
|
|
|
sellingPrice: '',
|
|
|
|
|
uom: null,
|
|
|
|
|
tax: null,
|
|
|
|
|
prodId: null,
|
|
|
|
|
size: null,
|
|
|
|
|
uomName: null,
|
|
|
|
|
activeStatus: 'A'
|
|
|
|
|
}, ...dataSource]);
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const handleDelete = async (record) => {
|
|
|
|
|
if (record?.prodId) {
|
|
|
|
|
const deleteData = {
|
|
|
|
|
ProdId: record.prodId,
|
|
|
|
|
ActiveStatus: record.activeStatus === 'A' ? 'D' : 'A',
|
|
|
|
|
UpdatedBy: UserId,
|
|
|
|
|
};
|
|
|
|
|
const response = await dispatch(deleteProductData(deleteData))?.unwrap();
|
|
|
|
|
if (response?.data?.statusCode === 1) {
|
|
|
|
|
setMessageData(record.activeStatus === 'A' ? 'Product De-Activated Successfully' : 'Product Activated Successfully');
|
|
|
|
|
setMessageType('success');
|
|
|
|
|
await fetchDirectSaleProducts();
|
|
|
|
|
} else {
|
|
|
|
|
setMessageData(response?.data?.response || 'Failed to update status');
|
|
|
|
|
setMessageType('error');
|
|
|
|
|
}
|
|
|
|
|
return;
|
|
|
|
|
} else {
|
|
|
|
|
// const { key } = record;
|
|
|
|
|
// setDataSource(dataSource.filter(item => item.key !== key));
|
|
|
|
|
setMessageData('Atleast one empty row should be in table.');
|
|
|
|
|
setMessageType('warning');
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const handleChange = useCallback((key, field, value) => {
|
|
|
|
|
if (searchText) {
|
|
|
|
|
setFilteredProducts(prev =>
|
|
|
|
|
prev.map(item =>
|
|
|
|
|
item.key === key ? { ...item, [field]: value } : item
|
|
|
|
|
)
|
|
|
|
|
);
|
|
|
|
|
} else {
|
|
|
|
|
setDataSource(prev =>
|
|
|
|
|
prev.map(item =>
|
|
|
|
|
item.key === key ? { ...item, [field]: value } : item
|
|
|
|
|
)
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
}, [searchText]);
|
|
|
|
|
|
|
|
|
|
const handleSave = async (record) => {
|
|
|
|
|
|
|
|
|
|
if (!record.productName || !record.sellingPrice || !record.uom || !record.tax || !record?.shortCode) {
|
|
|
|
|
setMessageData('Please fill all the required fields!');
|
|
|
|
|
setMessageType('warning');
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const exists = isShortCodeDuplicate(record?.shortCode, record?.prodId);
|
|
|
|
|
|
|
|
|
|
if (exists) {
|
|
|
|
|
setMessageData('Short code already exists for another product');
|
|
|
|
|
setMessageType('error');
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const postData = {
|
|
|
|
|
ProdName: record.productName,
|
|
|
|
|
Size: '1',
|
|
|
|
|
UOM: record.uom,
|
|
|
|
|
MRP: record.sellingPrice,
|
|
|
|
|
SellPrice: record.sellingPrice,
|
|
|
|
|
TaxId: record.tax,
|
|
|
|
|
CompId: CompId,
|
|
|
|
|
BranchId: BranchId,
|
|
|
|
|
AppId: AppId,
|
|
|
|
|
ProdType: ProductTypeData?.find(item => item.ConfigName === 'Product')?.ConfigId,
|
|
|
|
|
ProdCat: ProdCatData?.find(item => item.ConfigName === 'General')?.ConfigId,
|
|
|
|
|
ProdSubCat: ProdSubCatData?.find(item => item.ConfigName === 'General')?.ConfigId,
|
|
|
|
|
QtyBasedPrice: 'N',
|
|
|
|
|
ProdQtywisePriceDetails: [],
|
|
|
|
|
StockAvailable: 'N',
|
|
|
|
|
TokenAvailable: 'N',
|
|
|
|
|
InwardDate: new Date().toJSON(),
|
|
|
|
|
SuppId: SupplierData?.find(item => item.SuppName?.toLowerCase() === 'self')?.SuppId,
|
|
|
|
|
AutoGenerateQr: 'N',
|
|
|
|
|
QRCode: null,
|
|
|
|
|
CreatedBy: UserId,
|
|
|
|
|
ProdLogo: '',
|
|
|
|
|
Cess: 0,
|
|
|
|
|
ProdShortCode: record?.shortCode
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
if (record?.prodId) {
|
|
|
|
|
console.log('Updating Product')
|
|
|
|
|
} else {
|
|
|
|
|
const response = await dispatch(postProductData(postData)).unwrap();
|
|
|
|
|
if (response?.data?.statusCode === 1) {
|
|
|
|
|
const prodId = response?.data?.ProductDetails?.[0]?.ProdId;
|
|
|
|
|
const size = response?.data?.ProductDetails?.[0]?.Size;
|
|
|
|
|
const uomName = response?.data?.ProductDetails?.[0]?.UomName;
|
|
|
|
|
const totalProducts = response?.data?.ProductDetails?.[0]?.TotalCount;
|
|
|
|
|
setSearchText(currentSearchText => {
|
|
|
|
|
if (currentSearchText != null && currentSearchText !== '') {
|
|
|
|
|
setCurrentPage(1);
|
|
|
|
|
setTriggerState(prev => prev + 1);
|
|
|
|
|
if (searchInputRef.current) {
|
|
|
|
|
searchInputRef.current.value = '';
|
|
|
|
|
}
|
|
|
|
|
return '';
|
|
|
|
|
} else {
|
|
|
|
|
setDataSource(prev => prev.map(item =>
|
|
|
|
|
item.key === record.key ? { ...item, prodId, size, uomName, totalProducts } : { ...item, totalProducts }
|
|
|
|
|
));
|
|
|
|
|
}
|
|
|
|
|
return currentSearchText;
|
|
|
|
|
});
|
|
|
|
|
setMessageData('Product saved successfully!');
|
|
|
|
|
setMessageType('success');
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
} catch (error) {
|
|
|
|
|
console.error('Error saving product:', error);
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const handlePrint = async (record) => {
|
|
|
|
|
const exists = isShortCodeDuplicate(record?.shortCode, record?.prodId);
|
|
|
|
|
if (exists) {
|
|
|
|
|
setMessageData('Short code already exists for another product. Cannot print.');
|
|
|
|
|
setMessageType('error');
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
setStickerPrintModalOpen(true);
|
|
|
|
|
setLabelPrintData({ ...record, MRP: record?.sellingPrice || 0, SellPrice: record?.sellingPrice || 0 });
|
|
|
|
|
setProdId(record?.shortCode + '' + record?.sellingPrice)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const columns = useMemo(() => [
|
|
|
|
|
{
|
|
|
|
|
title: 'SL.No',
|
|
|
|
|
width: 50,
|
|
|
|
|
align: 'center',
|
|
|
|
|
render: (_, __, index) => (currentPage - 1) * 10 + index + 1
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
title: () => <div style={{ textWrap: 'nowrap', display: "flex", gap: "4px " }}>Product Name
|
|
|
|
|
<span>
|
|
|
|
|
<FaStarOfLife size={10} color='red' className='requiredIcons' />
|
|
|
|
|
</span>
|
|
|
|
|
</div>,
|
|
|
|
|
dataIndex: 'productName',
|
|
|
|
|
width: 150,
|
|
|
|
|
render: (text, record) => (
|
|
|
|
|
record.prodId && editingKey !== record.key ?
|
|
|
|
|
<div>{text}</div> :
|
|
|
|
|
<Input
|
|
|
|
|
value={text}
|
|
|
|
|
onChange={(e) => handleChange(record.key, 'productName', e.target.value)}
|
|
|
|
|
placeholder="Enter product name"
|
|
|
|
|
/>
|
|
|
|
|
)
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
title: () => <div style={{ textWrap: 'nowrap', display: "flex", gap: "4px " }}>Short Code
|
|
|
|
|
<span>
|
|
|
|
|
<FaStarOfLife size={10} color='red' className='requiredIcons' />
|
|
|
|
|
</span>
|
|
|
|
|
</div>,
|
|
|
|
|
dataIndex: 'shortCode',
|
|
|
|
|
width: 100,
|
|
|
|
|
render: (text, record) => (
|
|
|
|
|
record.prodId && editingKey !== record.key ?
|
|
|
|
|
<div>{text}</div> :
|
|
|
|
|
<Input
|
|
|
|
|
value={text}
|
|
|
|
|
onInput={(e) => {
|
|
|
|
|
const originalValue = e.target.value;
|
|
|
|
|
const hasNonAlpha = /[^a-zA-Z]/.test(originalValue);
|
|
|
|
|
if (hasNonAlpha) {
|
|
|
|
|
setMessageData('Enter Alphabet Characters only');
|
|
|
|
|
setMessageType('warning');
|
|
|
|
|
}
|
|
|
|
|
}}
|
|
|
|
|
onChange={(e) => {
|
|
|
|
|
const value = e.target.value.replace(/[^a-zA-Z]/g, '').toUpperCase();
|
|
|
|
|
const exists = isShortCodeDuplicate(value, record?.prodId);
|
|
|
|
|
if (exists && value) {
|
|
|
|
|
setMessageData('Short code already exists for another product');
|
|
|
|
|
setMessageType('error');
|
|
|
|
|
}
|
|
|
|
|
handleChange(record.key, 'shortCode', value);
|
|
|
|
|
}}
|
|
|
|
|
placeholder="Short Code"
|
|
|
|
|
/>
|
|
|
|
|
)
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
title: () => <div style={{ textWrap: 'nowrap', display: "flex", gap: "4px " }}>Selling Price
|
|
|
|
|
<span>
|
|
|
|
|
<FaStarOfLife size={10} color='red' className='requiredIcons' />
|
|
|
|
|
</span>
|
|
|
|
|
</div>,
|
|
|
|
|
dataIndex: 'sellingPrice',
|
|
|
|
|
width: 120,
|
|
|
|
|
render: (text, record) => (
|
|
|
|
|
record.prodId && editingKey !== record.key ?
|
|
|
|
|
<div>{text}</div> :
|
|
|
|
|
<Input
|
|
|
|
|
value={text}
|
|
|
|
|
onChange={(e) => {
|
|
|
|
|
const value = e.target.value.replace(/[^0-9.]/g, '');
|
|
|
|
|
const parts = value.split('.');
|
|
|
|
|
const formatted = parts.length > 2 ? `${parts[0]}.${parts.slice(1).join('')}` : value;
|
|
|
|
|
handleChange(record.key, 'sellingPrice', formatted);
|
|
|
|
|
}}
|
|
|
|
|
placeholder="0.00"
|
|
|
|
|
/>
|
|
|
|
|
)
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
title: () => <div style={{ textWrap: 'nowrap', display: "flex", gap: "4px " }}>UOM
|
|
|
|
|
<span>
|
|
|
|
|
<FaStarOfLife size={10} color='red' className='requiredIcons' />
|
|
|
|
|
</span>
|
|
|
|
|
</div>,
|
|
|
|
|
dataIndex: 'uom',
|
|
|
|
|
width: 60,
|
|
|
|
|
render: (text, record) => (
|
|
|
|
|
record.prodId && editingKey !== record.key ?
|
|
|
|
|
<div>{UomData?.find(item => item.ConfigId === text)?.ConfigName || '-'}</div> :
|
|
|
|
|
<Select
|
|
|
|
|
disabled={record?.prodId}
|
|
|
|
|
className='uom-select'
|
|
|
|
|
value={text}
|
|
|
|
|
onChange={(value) => handleChange(record.key, 'uom', value)}
|
|
|
|
|
placeholder="UOM"
|
|
|
|
|
style={{ width: '100%' }}
|
|
|
|
|
options={UomData?.map(item => ({
|
|
|
|
|
value: item.ConfigId,
|
|
|
|
|
label: item.ConfigName
|
|
|
|
|
}))}
|
|
|
|
|
/>
|
|
|
|
|
)
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
title: () => <div style={{ textWrap: 'nowrap', display: "flex", gap: "4px " }}>Tax
|
|
|
|
|
<span>
|
|
|
|
|
<FaStarOfLife size={10} color='red' className='requiredIcons' />
|
|
|
|
|
</span>
|
|
|
|
|
</div>,
|
|
|
|
|
dataIndex: 'tax',
|
|
|
|
|
width: 70,
|
|
|
|
|
render: (text, record) => {
|
|
|
|
|
if (record.prodId && editingKey !== record.key) {
|
|
|
|
|
const tax = TaxData?.find(item => item.TaxId === text);
|
|
|
|
|
return <div>{tax ? tax?.TaxIdName + ' - ' + `${tax?.TaxPercentage}%` : '-'}</div>;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return (
|
|
|
|
|
<Select
|
|
|
|
|
className='tax-select'
|
|
|
|
|
value={text}
|
|
|
|
|
disabled={record?.prodId}
|
|
|
|
|
onChange={(value) => handleChange(record.key, 'tax', value)}
|
|
|
|
|
placeholder="Tax"
|
|
|
|
|
style={{ width: '100%' }}
|
|
|
|
|
options={TaxData?.map(item => ({
|
|
|
|
|
value: item.TaxId,
|
|
|
|
|
label: `${item.TaxIdName} - ${item.TaxPercentage}%`
|
|
|
|
|
}))}
|
|
|
|
|
/>
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
title: 'Save / Print',
|
|
|
|
|
width: 90,
|
|
|
|
|
align: 'center',
|
|
|
|
|
render: (_, record) => {
|
|
|
|
|
const existingProduct = record?.prodId;
|
|
|
|
|
|
|
|
|
|
return (
|
|
|
|
|
<div className='directsaleBTN' style={{ display: 'flex', gap: '8px', justifyContent: 'center' }}>
|
|
|
|
|
{!existingProduct && <Button
|
|
|
|
|
icon={<SaveOutlined />}
|
|
|
|
|
size="small"
|
|
|
|
|
disabled={existingProduct}
|
|
|
|
|
className='save-btn'
|
|
|
|
|
onClick={() => handleSave(record)}
|
|
|
|
|
>
|
|
|
|
|
Save
|
|
|
|
|
{/* {!existingProduct ? 'Save' : 'Update'} */}
|
|
|
|
|
</Button>}
|
|
|
|
|
{existingProduct && <Button
|
|
|
|
|
icon={<PrinterOutlined />}
|
|
|
|
|
size="small"
|
|
|
|
|
disabled={!existingProduct}
|
|
|
|
|
onClick={() => handlePrint(record)}
|
|
|
|
|
>
|
|
|
|
|
Print
|
|
|
|
|
</Button>}
|
|
|
|
|
</div>
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
title: 'Action',
|
|
|
|
|
width: 60,
|
|
|
|
|
align: "center",
|
|
|
|
|
render: (_, record) => {
|
|
|
|
|
if (record?.activeStatus === 'A') {
|
|
|
|
|
return <DeleteOutlined
|
|
|
|
|
onClick={() => handleDelete(record)}
|
|
|
|
|
style={{ color: 'red', cursor: 'pointer', fontSize: '18px' }}
|
|
|
|
|
/>
|
|
|
|
|
} else {
|
|
|
|
|
return <IoMdRefresh
|
|
|
|
|
style={{ color: 'blue', cursor: 'pointer', fontSize: '18px' }}
|
|
|
|
|
onClick={() => handleDelete(record)}
|
|
|
|
|
/>
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
], [
|
|
|
|
|
searchText,
|
|
|
|
|
editingKey,
|
|
|
|
|
productShortCodes,
|
|
|
|
|
UomData,
|
|
|
|
|
TaxData
|
|
|
|
|
]);
|
|
|
|
|
|
|
|
|
|
useEffect(() => {
|
|
|
|
|
if (activeTab === 'directSale' && AppId && CompId && BranchId) {
|
|
|
|
|
fetchDirectSaleProducts();
|
|
|
|
|
fetchAllProductShortCodes();
|
|
|
|
|
}
|
|
|
|
|
}, [activeTab, AppId, BranchId, CompId, currentPage, triggerState]);
|
|
|
|
|
|
|
|
|
|
useEffect(() => {
|
|
|
|
|
if (dataSource.every(row => row.prodId)) {
|
|
|
|
|
handleAdd();
|
|
|
|
|
}
|
|
|
|
|
}, [dataSource]);
|
|
|
|
|
|
|
|
|
|
useEffect(() => {
|
|
|
|
|
const timer = setTimeout(() => {
|
|
|
|
|
if (searchText) {
|
|
|
|
|
fetchSearchedProducts();
|
|
|
|
|
} else {
|
|
|
|
|
setFilteredProducts([{
|
|
|
|
|
key: 1,
|
|
|
|
|
productName: '',
|
|
|
|
|
shortCode: '',
|
|
|
|
|
sellingPrice: '',
|
|
|
|
|
uom: null,
|
|
|
|
|
tax: null,
|
|
|
|
|
prodId: null,
|
|
|
|
|
size: null,
|
|
|
|
|
uomName: null,
|
|
|
|
|
activeStatus: 'A'
|
|
|
|
|
}]);
|
|
|
|
|
}
|
|
|
|
|
}, 500);
|
|
|
|
|
|
|
|
|
|
return () => clearTimeout(timer);
|
|
|
|
|
}, [searchText, AppId, BranchId, CompId]);
|
|
|
|
|
|
|
|
|
|
useEffect(() => {
|
|
|
|
|
const handleClickOutside = (event) => {
|
|
|
|
|
if (tableRef.current && !tableRef.current.contains(event.target) && !event.target.closest('.ant-select-dropdown')) {
|
|
|
|
|
setEditingKey(null);
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
document.addEventListener('mousedown', handleClickOutside);
|
|
|
|
|
return () => document.removeEventListener('mousedown', handleClickOutside);
|
|
|
|
|
}, []);
|
|
|
|
|
|
|
|
|
|
useEffect(() => {
|
|
|
|
|
if (activeTab === 'directSale' && AppId && CompId && BranchId && stickerPrintModalOpen) {
|
|
|
|
|
getBarcodeSessionData();
|
|
|
|
|
fetchBarcodeTemplateDetails();
|
|
|
|
|
}
|
|
|
|
|
}, [activeTab, AppId, BranchId, CompId, stickerPrintModalOpen]);
|
|
|
|
|
|
|
|
|
|
const fetchSearchedProducts = async () => {
|
|
|
|
|
try {
|
|
|
|
|
const data = {
|
|
|
|
|
AppId: AppId,
|
|
|
|
|
CompId: CompId,
|
|
|
|
|
BranchId: BranchId,
|
|
|
|
|
prodName: searchText
|
|
|
|
|
}
|
|
|
|
|
const response = await dispatch(getDirectSaleSearchedProduct(data))?.unwrap();
|
|
|
|
|
if (response?.data?.data?.length > 0 && response?.data?.statusCode === 1) {
|
|
|
|
|
const products = response?.data?.data?.map((item, index) => ({
|
|
|
|
|
key: index + 1,
|
|
|
|
|
productName: item.ProdName,
|
|
|
|
|
shortCode: item.ProdShortCode,
|
|
|
|
|
sellingPrice: item.SellPrice,
|
|
|
|
|
uom: item.UOM,
|
|
|
|
|
tax: item.TaxId,
|
|
|
|
|
prodId: item.ProdId,
|
|
|
|
|
activeStatus: item?.ActiveStatus,
|
|
|
|
|
size: item.Size || 1,
|
|
|
|
|
uomName: item.UomName || 'PCS',
|
|
|
|
|
totalProducts: item?.TotalCount
|
|
|
|
|
}))
|
|
|
|
|
setFilteredProducts([{
|
|
|
|
|
key: products.length + 1,
|
|
|
|
|
productName: '',
|
|
|
|
|
shortCode: '',
|
|
|
|
|
sellingPrice: '',
|
|
|
|
|
uom: null,
|
|
|
|
|
tax: null,
|
|
|
|
|
prodId: null,
|
|
|
|
|
size: null,
|
|
|
|
|
uomName: null,
|
|
|
|
|
activeStatus: 'A'
|
|
|
|
|
}, ...products]);
|
|
|
|
|
} else {
|
|
|
|
|
setFilteredProducts([{
|
|
|
|
|
key: 1,
|
|
|
|
|
productName: '',
|
|
|
|
|
shortCode: '',
|
|
|
|
|
sellingPrice: '',
|
|
|
|
|
uom: null,
|
|
|
|
|
tax: null,
|
|
|
|
|
prodId: null,
|
|
|
|
|
size: null,
|
|
|
|
|
uomName: null,
|
|
|
|
|
activeStatus: 'A'
|
|
|
|
|
}]);
|
|
|
|
|
}
|
|
|
|
|
} catch (error) {
|
|
|
|
|
console.error(error?.message)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const isShortCodeDuplicate = useCallback((code, prodId) => {
|
|
|
|
|
return productShortCodes.some(
|
|
|
|
|
item =>
|
|
|
|
|
item.ProdShortCode.toUpperCase() === code.toUpperCase() &&
|
|
|
|
|
item.ProdId !== prodId
|
|
|
|
|
);
|
|
|
|
|
}, [productShortCodes]);
|
|
|
|
|
|
|
|
|
|
const fetchBarcodeTemplateDetails = async () => {
|
|
|
|
|
const response = await dispatch(
|
|
|
|
|
getBarcodeTemplate({ compId: CompId, appId: AppId, branchId: BranchId })
|
|
|
|
|
).unwrap();
|
|
|
|
|
if (response?.data?.statusCode === 1 && response?.data?.data?.length > 0) {
|
|
|
|
|
const { TemplateDetails } = response?.data?.data?.[0];
|
|
|
|
|
setBarcodeTemplateDetails(TemplateDetails);
|
|
|
|
|
} else {
|
|
|
|
|
setBarcodeTemplateDetails([]);
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const getBarcodeSessionData = async () => {
|
|
|
|
|
try {
|
|
|
|
|
let response = await dispatch(getBarcodeSessionsIDs()).unwrap();
|
|
|
|
|
if (response?.data?.statusCode === 1 && response?.data?.data?.length > 0) {
|
|
|
|
|
setCrossData(
|
|
|
|
|
response?.data?.data?.filter(
|
|
|
|
|
(item) => !item.ConfigName?.includes('100X13 (55MM Printable Gold)')
|
|
|
|
|
) || []
|
|
|
|
|
);
|
|
|
|
|
} else {
|
|
|
|
|
setCrossData([]);
|
|
|
|
|
}
|
|
|
|
|
} catch (error) {
|
|
|
|
|
console.error('Error fetching barcode session data:', error);
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const fetchDirectSaleProducts = async () => {
|
|
|
|
|
try {
|
|
|
|
|
const data = {
|
|
|
|
|
AppId: AppId,
|
|
|
|
|
CompId: CompId,
|
|
|
|
|
BranchId: BranchId,
|
|
|
|
|
page: currentPage
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const response = await dispatch(getDirectSaleProducts(data))?.unwrap();
|
|
|
|
|
if (response?.data?.statusCode === 1 && response?.data?.data?.length > 0) {
|
|
|
|
|
const products = response?.data?.data?.map((item, index) => ({
|
|
|
|
|
key: index + 1,
|
|
|
|
|
productName: item.ProdName,
|
|
|
|
|
shortCode: item.ProdShortCode,
|
|
|
|
|
sellingPrice: item.SellPrice,
|
|
|
|
|
uom: item.UOM,
|
|
|
|
|
tax: item.TaxId,
|
|
|
|
|
prodId: item.ProdId,
|
|
|
|
|
activeStatus: item?.ActiveStatus,
|
|
|
|
|
size: item.Size || 1,
|
|
|
|
|
uomName: item.UomName || 'PCS',
|
|
|
|
|
totalProducts: item?.TotalCount
|
|
|
|
|
}));
|
|
|
|
|
setDataSource([{
|
|
|
|
|
key: products.length + 1,
|
|
|
|
|
productName: '',
|
|
|
|
|
shortCode: '',
|
|
|
|
|
sellingPrice: '',
|
|
|
|
|
uom: null,
|
|
|
|
|
tax: null,
|
|
|
|
|
prodId: null,
|
|
|
|
|
size: null,
|
|
|
|
|
uomName: null,
|
|
|
|
|
activeStatus: 'A'
|
|
|
|
|
}, ...products]);
|
|
|
|
|
} else {
|
|
|
|
|
setDataSource([])
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
} catch (error) {
|
|
|
|
|
console.error('Error fetching direct sale products:', error);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const fetchAllProductShortCodes = async () => {
|
|
|
|
|
try {
|
|
|
|
|
const data = {
|
|
|
|
|
AppId: AppId,
|
|
|
|
|
CompId: CompId,
|
|
|
|
|
BranchId: BranchId,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const response = await dispatch(getAllProductShortCodes(data))?.unwrap();
|
|
|
|
|
if (response?.data?.statusCode === 1 && response?.data?.data?.length > 0) {
|
|
|
|
|
setAllProductShortCodes(response?.data?.data);
|
|
|
|
|
} else {
|
|
|
|
|
setAllProductShortCodes([]);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
console.log(response);
|
|
|
|
|
|
|
|
|
|
} catch (error) {
|
|
|
|
|
console.error('Error fetching product short codes:', error);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const handlePageChange = (current) => {
|
|
|
|
|
setCurrentPage(current);
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const onFinish = async () => {
|
|
|
|
|
const template = barcodeTemplateDetails?.find(
|
|
|
|
|
(find) => find.SessionName === dropdownValue
|
|
|
|
|
);
|
|
|
|
|
const templateAvailable = template === undefined ? false : true;
|
|
|
|
|
|
|
|
|
|
if (templateAvailable) {
|
|
|
|
|
const checkComponent = (name) =>
|
|
|
|
|
template?.OptionDetails?.some((some) => some.OptionName === name);
|
|
|
|
|
const mrp = checkComponent('MRP');
|
|
|
|
|
const barcode = checkComponent('Barcode');
|
|
|
|
|
const color = checkComponent('Color');
|
|
|
|
|
const eDate = checkComponent('E Date');
|
|
|
|
|
const mDate = checkComponent('M Date');
|
|
|
|
|
const sellingPrice = checkComponent('Selling Price');
|
|
|
|
|
const productName = checkComponent('Product Name');
|
|
|
|
|
const qrcode = checkComponent('Qrcode');
|
|
|
|
|
const position = template.Position !== '' ? template.Position : '';
|
|
|
|
|
const positionString =
|
|
|
|
|
template.PositionString !== '' ? template.PositionString : '';
|
|
|
|
|
|
|
|
|
|
setTemplateOptions({
|
|
|
|
|
mrp: mrp,
|
|
|
|
|
barcode: barcode,
|
|
|
|
|
color: color,
|
|
|
|
|
eDate: eDate,
|
|
|
|
|
mDate: mDate,
|
|
|
|
|
sellingPrice: sellingPrice,
|
|
|
|
|
productName: productName,
|
|
|
|
|
value: position,
|
|
|
|
|
secondValue: positionString,
|
|
|
|
|
qrcode: qrcode,
|
|
|
|
|
codeType: template?.CodeType,
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
setPrintReady(true);
|
|
|
|
|
|
|
|
|
|
setTimeout(async () => {
|
|
|
|
|
switch (dropdownValue) {
|
|
|
|
|
case '15X15 6cross': // COMPLETE
|
|
|
|
|
await printDiv(
|
|
|
|
|
templateAvailable ? 'label-15X156cross' : 'StickerPrints0',
|
|
|
|
|
style + getPageStyle(92)
|
|
|
|
|
);
|
|
|
|
|
handleModalClose();
|
|
|
|
|
break;
|
|
|
|
|
case '22X35 3cross': // Need to check
|
|
|
|
|
await printDiv(
|
|
|
|
|
templateAvailable ? '22X353cross' : 'StickerPrints1',
|
|
|
|
|
style + getPageStyle(105)
|
|
|
|
|
);
|
|
|
|
|
handleModalClose();
|
|
|
|
|
break;
|
|
|
|
|
case '25X25 4cross': // COMPLETE
|
|
|
|
|
await printDiv(
|
|
|
|
|
templateAvailable ? '25X254cross' : 'StickerPrints2',
|
|
|
|
|
style + getPageStyle(100)
|
|
|
|
|
);
|
|
|
|
|
handleModalClose();
|
|
|
|
|
break;
|
|
|
|
|
case '25X50 2cross': //Need to check
|
|
|
|
|
await printDiv(
|
|
|
|
|
templateAvailable ? '25X502cross' : 'StickerPrints3',
|
|
|
|
|
style + getPageStyle(100)
|
|
|
|
|
);
|
|
|
|
|
handleModalClose();
|
|
|
|
|
break;
|
|
|
|
|
case '50X30 Single': // COMPLETE
|
|
|
|
|
await printDiv(
|
|
|
|
|
templateAvailable ? '50X30Single' : 'StickerPrints4',
|
|
|
|
|
style
|
|
|
|
|
);
|
|
|
|
|
handleModalClose();
|
|
|
|
|
break;
|
|
|
|
|
case '50X25 Single': // COMPLETE
|
|
|
|
|
await printDiv(
|
|
|
|
|
templateAvailable ? '50X25Single' : 'StickerPrints5',
|
|
|
|
|
style
|
|
|
|
|
);
|
|
|
|
|
handleModalClose();
|
|
|
|
|
break;
|
|
|
|
|
case '100X13 (55MM Printable)': //Need to check
|
|
|
|
|
await printDiv(
|
|
|
|
|
templateAvailable ? '100X13(55MMPrintable)' : 'StickerPrints6',
|
|
|
|
|
style
|
|
|
|
|
);
|
|
|
|
|
handleModalClose();
|
|
|
|
|
break;
|
|
|
|
|
case '100X15 (70MM Printable)': // COMPLETE
|
|
|
|
|
await printDiv(
|
|
|
|
|
templateAvailable ? '100X15(70MMPrintable)' : 'StickerPrints7',
|
|
|
|
|
style
|
|
|
|
|
);
|
|
|
|
|
handleModalClose();
|
|
|
|
|
break;
|
|
|
|
|
case '100X150': // COMPLETE
|
|
|
|
|
await printDiv(
|
|
|
|
|
templateAvailable ? '100X150' : 'StickerPrints8',
|
|
|
|
|
style
|
|
|
|
|
);
|
|
|
|
|
handleModalClose();
|
|
|
|
|
setPrintReady(false);
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
alert('! Select correct cross ');
|
|
|
|
|
setPrintReady(false);
|
|
|
|
|
}
|
|
|
|
|
}, 100);
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const CoresOnChange = (params) => {
|
|
|
|
|
setDropdownValue(params);
|
|
|
|
|
formRef.current?.setFieldsValue({ Cross: params });
|
|
|
|
|
const template = barcodeTemplateDetails?.find(
|
|
|
|
|
(find) => find.SessionName === params
|
|
|
|
|
);
|
|
|
|
|
const checkComponent = (name) =>
|
|
|
|
|
template?.OptionDetails?.some((some) => some.OptionName === name);
|
|
|
|
|
const productName = checkComponent('Product Name');
|
|
|
|
|
setPrintProductName(productName);
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const CopiesOnChange = (params) => {
|
|
|
|
|
setCopies(params);
|
|
|
|
|
formRef.current?.setFieldsValue({ Copies: params });
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const handleModalClose = () => {
|
|
|
|
|
setCopies(null)
|
|
|
|
|
setDropdownValue('')
|
|
|
|
|
setStickerPrintModalOpen(false);
|
|
|
|
|
setLabelPrintData(null);
|
|
|
|
|
setNickName(null);
|
|
|
|
|
setProdId(null)
|
|
|
|
|
setMultiProduct(false);
|
|
|
|
|
formRef?.current?.resetFields();
|
|
|
|
|
setPrintReady(false);
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const imageTagBarcodeAndQR = useCallback(
|
|
|
|
|
(w = 'auto', fs = '6px', codeData = null) => {
|
|
|
|
|
const currentCode = codeData || prodId;
|
|
|
|
|
return (
|
|
|
|
|
(templateOptions.barcode || templateOptions.qrcode) && (
|
|
|
|
|
<>
|
|
|
|
|
<img
|
|
|
|
|
style={{ width: w }}
|
|
|
|
|
src={
|
|
|
|
|
templateOptions.codeType === 'B'
|
|
|
|
|
? !multiProduct
|
|
|
|
|
? barcodeBase64
|
|
|
|
|
: generateBarcode(currentCode)
|
|
|
|
|
: !multiProduct
|
|
|
|
|
? qrBase64
|
|
|
|
|
: generateQRCode(QrandbarcodeDatas, currentCode)
|
|
|
|
|
}
|
|
|
|
|
alt="Barcode"
|
|
|
|
|
/>
|
|
|
|
|
{templateOptions.codeType !== 'B' && (
|
|
|
|
|
<p style={{ margin: '0', padding: '0', fontSize: fs }}>
|
|
|
|
|
{currentCode}
|
|
|
|
|
</p>
|
|
|
|
|
)}
|
|
|
|
|
</>
|
|
|
|
|
)
|
|
|
|
|
);
|
|
|
|
|
},
|
|
|
|
|
[templateOptions, multiProduct, barcodeBase64, qrBase64, prodId]
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
const onComplete = useCallback(() => {
|
|
|
|
|
setMessageType(null);
|
|
|
|
|
setMessageData(null);
|
|
|
|
|
}, []);
|
|
|
|
|
|
|
|
|
|
return (
|
|
|
|
|
<div className='direct-sale-container'>
|
|
|
|
|
<Messages
|
|
|
|
|
messageType={messageType}
|
|
|
|
|
messageData={messageData}
|
|
|
|
|
onComplete={onComplete}
|
|
|
|
|
/>
|
|
|
|
|
<div className="bsreprintmodaltable-search">
|
|
|
|
|
<input
|
|
|
|
|
ref={searchInputRef}
|
|
|
|
|
type="text"
|
|
|
|
|
placeholder="Search Product / Short Code..."
|
|
|
|
|
onChange={(e) => setSearchText(e.target.value)}
|
|
|
|
|
/>
|
|
|
|
|
</div>
|
|
|
|
|
<div style={{ marginBottom: '10px', color: '#666', fontSize: '14px', fontStyle: 'italic' }}>
|
|
|
|
|
Note: Click on a row to modify the product details
|
|
|
|
|
</div>
|
|
|
|
|
<div className='DirectSaleTable' ref={tableRef}>
|
|
|
|
|
<Tables
|
|
|
|
|
rowKey="prodId"
|
|
|
|
|
data={(searchText != null && searchText != '') ? filteredProducts : dataSource}
|
|
|
|
|
dataSource={(searchText != null && searchText != '') ? filteredProducts : dataSource}
|
|
|
|
|
columns={columns}
|
|
|
|
|
onRow={(record) => ({
|
|
|
|
|
onClick: () => record.prodId && setEditingKey(record.key)
|
|
|
|
|
})}
|
|
|
|
|
ownPagination={true}
|
|
|
|
|
pagination={{
|
|
|
|
|
current: currentPage,
|
|
|
|
|
onChange: handlePageChange,
|
|
|
|
|
total: (searchText != null && searchText != '') ? filteredProducts?.length : ((dataSource[dataSource.length - 1]?.totalProducts || 0) + 1),
|
|
|
|
|
pageSize: 11,
|
|
|
|
|
showSizeChanger: false,
|
|
|
|
|
hideOnSinglePage: true,
|
|
|
|
|
}}
|
|
|
|
|
bordered
|
|
|
|
|
/>
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
{stickerPrintModalOpen && <StickerPrintModel
|
|
|
|
|
open={stickerPrintModalOpen}
|
|
|
|
|
handleCancel={handleModalClose}
|
|
|
|
|
formRef={formRef}
|
|
|
|
|
onFinish={onFinish}
|
|
|
|
|
MultiCode={multiProduct}
|
|
|
|
|
activeTab={null}
|
|
|
|
|
setActiveTab={() => { }}
|
|
|
|
|
selectedRecords={null}
|
|
|
|
|
coresdata={crossData}
|
|
|
|
|
dropdownValue={dropdownValue}
|
|
|
|
|
CoresOnChange={CoresOnChange}
|
|
|
|
|
barcodeTemplateDetails={barcodeTemplateDetails}
|
|
|
|
|
detail={labelPrintData}
|
|
|
|
|
proName={labelPrintData?.productName}
|
|
|
|
|
nickName={nickName}
|
|
|
|
|
ProdId={labelPrintData?.shortCode + '' + labelPrintData?.sellingPrice}
|
|
|
|
|
size={labelPrintData?.size}
|
|
|
|
|
// valueStyleColumn={valueStyleColumn}
|
|
|
|
|
// secondValueStyle={secondValueStyle}
|
|
|
|
|
// valueStyleRow={valueStyleRow}
|
|
|
|
|
CopiesOnChange={CopiesOnChange}
|
|
|
|
|
printProductName={printProductName}
|
|
|
|
|
totalCopies={null}
|
|
|
|
|
setstockWiseQrcode={null}
|
|
|
|
|
setProductWiseQrcode={null}
|
|
|
|
|
setNickName={setNickName}
|
|
|
|
|
templateOptions={templateOptions}
|
|
|
|
|
/>}
|
|
|
|
|
|
|
|
|
|
{printReady && (
|
|
|
|
|
<StickerPrintTemplates
|
|
|
|
|
selectedRecords={null}
|
|
|
|
|
copies={copies}
|
|
|
|
|
nickName={nickName}
|
|
|
|
|
proName={labelPrintData?.productName}
|
|
|
|
|
ProdId={labelPrintData?.shortCode + '' + labelPrintData?.sellingPrice}
|
|
|
|
|
size={labelPrintData?.size + ' ' + labelPrintData?.uomName}
|
|
|
|
|
detail={labelPrintData}
|
|
|
|
|
templateOptions={templateOptions}
|
|
|
|
|
base64Image={qrBase64}
|
|
|
|
|
QrandbarcodeDatas={null}
|
|
|
|
|
MultiCode={multiProduct}
|
|
|
|
|
generateQRCodeCopy={(code) =>
|
|
|
|
|
generateQRCodeCopy(null, code)
|
|
|
|
|
}
|
|
|
|
|
generateCodeImage={(code, codeType = 'Q') => generateCodeImage(code, codeType, null)}
|
|
|
|
|
imageTagBarcodeAndQR={imageTagBarcodeAndQR}
|
|
|
|
|
dropdownValue={dropdownValue}
|
|
|
|
|
barcodeTemplateDetails={barcodeTemplateDetails}
|
|
|
|
|
/>
|
|
|
|
|
)}
|
|
|
|
|
</div>
|
|
|
|
|
);
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
export default DirectSale;
|