import React, { useState, useRef, useEffect, useContext, useMemo } from 'react';
import { useDispatch, useSelector } from 'react-redux';
import { read, utils } from 'xlsx';
import ExcelJS from 'exceljs';
import { Table, Form, Input, Button, Tooltip, Modal, Select } from 'antd';
import {
emptyExcelData,
excelDataSelector,
excelFileSelector,
excelFileErrorSelector,
fileInputRefSelector,
uploadExcel,
} from '../../Features/ExcelUploadPage/ExcelUploadPage.js';
import {
getProductData,
onlineimages,
postFieldSetup,
getFieldSetupData,
} from '../../Features/ProductPage/ProductPage.js';
import Imageupload from '../../Components/Forms/Upload.jsx';
import { BiSolidFileExport } from 'react-icons/bi';
import { CiExport } from 'react-icons/ci';
import { uploadImage } from '../../Features/upload/upload.js';
import { TbWorldSearch } from 'react-icons/tb';
import { DefaultModal } from '../../Components/Modal/DefaultModal.jsx';
import '../../Styles/Product/excel.scss';
import { AiFillDelete } from 'react-icons/ai';
import upldimg from '../../Images/upldimg.png';
import Excelupldimg from '../../Images/Excel.png';
import { FiDelete, FiDownload } from 'react-icons/fi';
import { getSession } from '../../Services/Others.js';
import * as XLSX from 'xlsx';
import { CiBoxList } from 'react-icons/ci';
import { ArrowRightOutlined, CloseCircleOutlined } from '@ant-design/icons';
import stringSimilarity from 'string-similarity';
import {
getCommonAppPreference,
ApplicationPreferences,
getApplicationDetails,
} from '../../Features/BrachLogin/BranchLogin.js';
import { MdOutlineAppRegistration } from 'react-icons/md';
import FormHeader from '../PageComponents/FormHeader.jsx';
import { DropDowns } from '../../Components/Forms/DropDown.jsx';
import Buttons from '../../Components/Forms/Buttons.jsx';
import { IoClose } from 'react-icons/io5';
import { Messages } from '../../Components/Notifications/Messages.jsx';
import useWhyDidYouUpdate from '../../Services/findrerender.js';
const getApplicationSampleData = (appName) => {
const sampleDataMap = {
Restaurant: {
productName: 'Chicken Biryani',
quantity: 1,
uom: 'PLT',
salesPrice: 250,
mrp: 280,
category: 'Non-Vegetarian',
subCategory: 'Biryani',
brand: 'Chef Special',
variantName: 'Large',
tax: 'CGST+SGST - 5%',
hsn: '21069030',
additionalSamples: [
{
productName: 'Masala Dosa',
quantity: 1,
uom: 'PLT',
salesPrice: 120,
category: 'Vegetarian',
subCategory: 'South Indian',
},
{
productName: 'Paneer Butter Masala',
quantity: 1,
uom: 'PLT',
salesPrice: 200,
category: 'Vegetarian',
subCategory: 'North Indian',
},
],
},
Bakery: {
productName: 'Chocolate Cake',
quantity: 1,
uom: 'PCS',
salesPrice: 500,
mrp: 550,
category: 'Cakes',
subCategory: 'Birthday Cakes',
brand: 'Fresh Bakes',
variantName: '1 Kg',
tax: 'CGST+SGST - 5%',
hsn: '19053100',
additionalSamples: [
{
productName: 'Croissant',
quantity: 1,
uom: 'PCS',
salesPrice: 45,
category: 'Pastries',
subCategory: 'French Pastries',
},
{
productName: 'Whole Wheat Bread',
quantity: 1,
uom: 'LOAF',
salesPrice: 35,
category: 'Breads',
subCategory: 'Wheat Breads',
},
],
},
'Electrical, Electronics and Computers': {
productName: 'LED Bulb 9W',
quantity: 1,
uom: 'PCS',
salesPrice: 120,
mrp: 150,
category: 'Lighting',
subCategory: 'LED Bulbs',
brand: 'Philips',
variantName: 'Cool White',
tax: 'CGST+SGST - 18%',
hsn: '85395000',
additionalSamples: [
{
productName: 'Mobile Charger',
quantity: 1,
uom: 'PCS',
salesPrice: 299,
category: 'Mobile Accessories',
subCategory: 'Chargers',
},
{
productName: 'Extension Board 4 Socket',
quantity: 1,
uom: 'PCS',
salesPrice: 350,
category: 'Electrical Accessories',
subCategory: 'Power Strips',
},
],
},
'Mobile Phone and Accessories': {
productName: 'Smartphone Screen Guard',
quantity: 1,
uom: 'PCS',
salesPrice: 199,
mrp: 299,
category: 'Screen Protection',
subCategory: 'Tempered Glass',
brand: 'TechGuard',
variantName: 'iPhone 14',
tax: 'CGST+SGST - 18%',
hsn: '70071900',
additionalSamples: [
{
productName: 'Phone Case',
quantity: 1,
uom: 'PCS',
salesPrice: 149,
category: 'Protection',
subCategory: 'Back Covers',
},
{
productName: 'Wireless Earbuds',
quantity: 1,
uom: 'PAIR',
salesPrice: 1599,
category: 'Audio',
subCategory: 'Bluetooth Earphones',
},
],
},
Grocery: {
productName: 'Basmati Rice',
quantity: 1,
uom: 'KG',
salesPrice: 85,
mrp: 90,
category: 'Food Grains',
subCategory: 'Rice',
brand: 'India Gate',
variantName: '1 Kg Pack',
tax: 'NIL - 0%',
hsn: '10063020',
additionalSamples: [
{
productName: 'Toor Dal',
quantity: 1,
uom: 'KG',
salesPrice: 120,
category: 'Pulses',
subCategory: 'Arhar Dal',
},
{
productName: 'Refined Oil',
quantity: 1,
uom: 'LITER',
salesPrice: 110,
category: 'Cooking Oil',
subCategory: 'Sunflower Oil',
},
],
},
'Departmental Stores': {
productName: 'Shampoo',
quantity: 1,
uom: 'BTL',
salesPrice: 180,
mrp: 200,
category: 'Personal Care',
subCategory: 'Hair Care',
brand: 'Head & Shoulders',
variantName: '200ml',
tax: 'CGST+SGST - 18%',
hsn: '33051000',
additionalSamples: [
{
productName: 'Toothpaste',
quantity: 1,
uom: 'TUBE',
salesPrice: 45,
category: 'Oral Care',
subCategory: 'Toothpaste',
},
{
productName: 'Laundry Detergent',
quantity: 1,
uom: 'KG',
salesPrice: 85,
category: 'Household',
subCategory: 'Washing Powder',
},
],
},
Jewellery: {
productName: 'Gold Ring',
quantity: 1,
uom: 'PCS',
salesPrice: 25000,
mrp: 26000,
category: 'Gold Jewellery',
subCategory: 'Rings',
brand: 'Tanishq',
variantName: '22K Gold',
tax: 'CGST+SGST - 3%',
hsn: '71131900',
additionalSamples: [
{
productName: 'Silver Earrings',
quantity: 1,
uom: 'PAIR',
salesPrice: 1200,
category: 'Silver Jewellery',
subCategory: 'Earrings',
},
{
productName: 'Diamond Pendant',
quantity: 1,
uom: 'PCS',
salesPrice: 15000,
category: 'Diamond Jewellery',
subCategory: 'Pendants',
},
],
},
'Lifestyle and Fashion': {
productName: 'Cotton T-Shirt',
quantity: 1,
uom: 'PCS',
salesPrice: 499,
mrp: 599,
category: 'Apparel',
subCategory: 'T-Shirts',
brand: 'Nike',
variantName: 'Medium',
tax: 'CGST+SGST - 5%',
hsn: '61091000',
additionalSamples: [
{
productName: 'Jeans',
quantity: 1,
uom: 'PCS',
salesPrice: 1299,
category: 'Bottoms',
subCategory: 'Denim',
},
{
productName: 'Sneakers',
quantity: 1,
uom: 'PAIR',
salesPrice: 2499,
category: 'Footwear',
subCategory: 'Casual Shoes',
},
],
},
'Salon, Spa and Beauty Parlour': {
productName: 'Hair Cut Service',
quantity: 1,
uom: 'SERVICE',
salesPrice: 300,
mrp: 350,
category: 'Hair Services',
subCategory: 'Cutting',
brand: 'Premium Salon',
variantName: 'Regular Cut',
tax: 'CGST+SGST - 18%',
hsn: '99820000',
additionalSamples: [
{
productName: 'Facial Treatment',
quantity: 1,
uom: 'SERVICE',
salesPrice: 800,
category: 'Skin Care',
subCategory: 'Facial',
},
{
productName: 'Hair Color',
quantity: 1,
uom: 'SERVICE',
salesPrice: 1200,
category: 'Hair Services',
subCategory: 'Coloring',
},
],
},
Stationery: {
productName: 'A4 Paper Pack',
quantity: 1,
uom: 'PACK',
salesPrice: 280,
mrp: 300,
category: 'Paper Products',
subCategory: 'Copy Paper',
brand: 'JK Copier',
variantName: '500 Sheets',
tax: 'CGST+SGST - 12%',
hsn: '48025510',
additionalSamples: [
{
productName: 'Ball Pen',
quantity: 1,
uom: 'PCS',
salesPrice: 15,
category: 'Writing Instruments',
subCategory: 'Pens',
},
{
productName: 'Notebook',
quantity: 1,
uom: 'PCS',
salesPrice: 45,
category: 'Books & Notebooks',
subCategory: 'Exercise Books',
},
],
},
Pharmacy: {
productName: 'Paracetamol 500mg',
quantity: 1,
uom: 'STRIP',
salesPrice: 12,
mrp: 15,
category: 'Medicines',
subCategory: 'Fever & Pain',
brand: 'Crocin',
variantName: '10 Tablets',
tax: 'CGST+SGST - 12%',
hsn: '30049099',
additionalSamples: [
{
productName: 'Hand Sanitizer',
quantity: 1,
uom: 'BTL',
salesPrice: 65,
category: 'Healthcare',
subCategory: 'Sanitizers',
},
{
productName: 'Bandage Roll',
quantity: 1,
uom: 'PCS',
salesPrice: 25,
category: 'Medical Supplies',
subCategory: 'First Aid',
},
],
},
Furniture: {
productName: 'Wooden Dining Table',
quantity: 1,
uom: 'PCS',
salesPrice: 15000,
mrp: 18000,
category: 'Dining Furniture',
subCategory: 'Dining Tables',
brand: 'Royal Oak',
variantName: '6 Seater',
tax: 'CGST+SGST - 12%',
hsn: '94036090',
additionalSamples: [
{
productName: 'Office Chair',
quantity: 1,
uom: 'PCS',
salesPrice: 5500,
category: 'Office Furniture',
subCategory: 'Chairs',
},
{
productName: 'Queen Size Bed',
quantity: 1,
uom: 'PCS',
salesPrice: 12000,
category: 'Bedroom Furniture',
subCategory: 'Beds',
},
],
},
Fruits: {
productName: 'Fresh Apples',
quantity: 1,
uom: 'KG',
salesPrice: 180,
mrp: 200,
category: 'Fresh Fruits',
subCategory: 'Seasonal Fruits',
brand: 'Farm Fresh',
variantName: 'Kashmiri Apple',
tax: 'NIL - 0%',
hsn: '08081000',
additionalSamples: [
{
productName: 'Bananas',
quantity: 1,
uom: 'DOZEN',
salesPrice: 60,
category: 'Fresh Fruits',
subCategory: 'Tropical Fruits',
},
{
productName: 'Orange Juice',
quantity: 1,
uom: 'LITER',
salesPrice: 120,
category: 'Fruit Juices',
subCategory: 'Fresh Juice',
},
],
},
Textiles: {
productName: 'Cotton Fabric',
quantity: 1,
uom: 'METER',
salesPrice: 85,
mrp: 100,
category: 'Fabric',
subCategory: 'Cotton Fabric',
brand: 'Raymond',
variantName: 'Plain White',
tax: 'CGST+SGST - 5%',
hsn: '52081900',
additionalSamples: [
{
productName: 'Silk Saree',
quantity: 1,
uom: 'PCS',
salesPrice: 2500,
category: 'Ready Made',
subCategory: 'Sarees',
},
{
productName: 'Woolen Shawl',
quantity: 1,
uom: 'PCS',
salesPrice: 800,
category: 'Accessories',
subCategory: 'Shawls',
},
],
},
'Computer Sales Shop': {
productName: 'Gaming Laptop',
quantity: 1,
uom: 'PCS',
salesPrice: 55000,
mrp: 60000,
category: 'Laptops',
subCategory: 'Gaming Laptops',
brand: 'ASUS',
variantName: 'ROG Strix G15',
tax: 'CGST+SGST - 18%',
hsn: '84713000',
additionalSamples: [
{
productName: 'Wireless Mouse',
quantity: 1,
uom: 'PCS',
salesPrice: 1200,
category: 'Computer Accessories',
subCategory: 'Mouse',
},
{
productName: 'SSD 500GB',
quantity: 1,
uom: 'PCS',
salesPrice: 4500,
category: 'Storage',
subCategory: 'Solid State Drive',
},
],
},
};
// Return sample data for the specified app, or generic data if not found
return (
sampleDataMap[appName] || {
productName: 'Sample Product Name',
quantity: 1,
uom: 'PCS',
salesPrice: 100,
mrp: 100,
category: 'Sample Category',
subCategory: 'Sample Sub Category',
brand: 'Sample Brand',
variantName: 'Sample Variant Name',
tax: 'NIL - 0%',
hsn: '12345678',
additionalSamples: [],
}
);
};
const allowedExcelTypes = [
'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', // .xlsx
'application/vnd.ms-excel', // .xls
];
const ProductExcel = ({
handleSubmit,
CategoryId,
CategoryNames,
SubcatId,
SubCatData,
AllBrandId,
Allbranddata,
Allbranddatanumfid,
Subcatnumfid,
Unit,
TaxDatas,
SuplierNames,
CategoryName1,
Catconfigid,
}) => {
useWhyDidYouUpdate('ProductExcel', {
handleSubmit,
CategoryId,
CategoryNames,
SubcatId,
SubCatData,
AllBrandId,
Allbranddata,
Allbranddatanumfid,
Subcatnumfid,
Unit,
TaxDatas,
SuplierNames,
CategoryName1,
Catconfigid,
});
const dispatch = useDispatch();
const formRef = useRef(null);
const CompId = getSession('CompId');
const BranchId = getSession('BranchId');
const AppId = getSession('AppId');
const UserId = getSession('UserId');
const fileInputRef = useRef(fileInputRefSelector);
const excelData = useSelector(excelDataSelector);
const excelFile = useSelector(excelFileSelector);
const excelFileError = useSelector(excelFileErrorSelector);
const ApplicationPreferenceData = useSelector(ApplicationPreferences);
const productBulkUploadCatId = ApplicationPreferenceData?.find(
(p) => p?.PreferredCatName?.toLowerCase() === 'product bulk upload'
)?.PreferredCatId;
const [appName, setAppName] = useState(null);
const [messageType, setMessageType] = useState(null);
const [messageData, setMessageData] = useState(null);
const [selectedFields, setSelectedFields] = useState([]);
const [tableFieldPreferences, setTableFieldPreferences] = useState([]);
const [worksheet, setWorksheet] = useState(null);
const [worksheet1, setWorksheet1] = useState(null);
const [editdelete, seteditdelete] = useState('');
const [fieldSetup, setFieldSetup] = useState(false);
const [selectedImageIndex, setSelectedImageIndex] = useState(null);
const [selectedProductName, setSelectedProductName] = useState(null);
const [imagedata, setimagedata] = useState();
const [selectedImage, setSelectedImage] = useState(null);
const [imageopen, setimageOpen] = useState();
const [onlineImage, setOnlineImage] = useState(null);
const [loading, setLoading] = useState(false);
const [message, setMessage] = useState(false);
const [Datas, setDatas] = useState();
console.log(Datas, 'Datas32323232');
const [currentPage, setCurrentPage] = useState(1);
const [MappingOpen, setMappingOpen] = useState(false);
const [fieldMapping, setFieldMapping] = useState({});
const [headers, setHeaders] = useState([]);
const [UploadedRawData, setUploadedRawData] = useState([]);
const [ExcelData, setExcelData] = useState([]);
const [originalUploadedRawData, setOriginalUploadedRawData] = useState([]);
const [FieldValues, setFieldValues] = useState([]);
const [OrginalData, setOrginalData] = useState([]);
const handleTableChange = (pagination, filters, sorter) => {
setCurrentPage(pagination.current);
};
console.log(tableFieldPreferences, 'tableFieldPreferences');
useEffect(() => {
if (excelData && excelData?.length > 0) {
let ExecelToJsConvertion = [];
let slicedData = excelData?.slice(1);
let filteredData = slicedData?.filter(
(item) => item?.[item?.length - 1]?.trim() !== 'sample row'
);
filteredData?.map((item, index) => {
ExecelToJsConvertion.push({
key: index,
ProductName: item?.['0'],
Quantity: item?.['1'],
UOM: item?.['2'],
SellPrice: item?.['3'],
Category: item?.['4'],
SubCategory: item?.['5'],
Brand: item?.['6'],
ProductVariantName: item?.['7'] ? item?.['7'] : 'Variant 1',
MRP: item?.['8'],
WhSalePrice: item?.['9'],
StockAvailable: item?.['10'] ? item?.['10'] : 'No',
TokenAvailable: item?.['11'] ? item?.['11'] : 'No',
ProductType: item?.['12'],
Tax: item?.['13'],
AutoGenerateQrcode: item?.['14'],
AddQrCode: item?.['15'],
OnePeiceAvailable: item?.['16'] ? item?.['16'] : 'No',
OnePeicePrice: item?.['17'],
AutoGenerateOnePieceQrcode: item?.['18'] ? item?.['18'] : 'No',
AutoGenerateOnePieceQrcodeNumber: item?.['19'],
CESS: item?.['20'],
HSN: item?.['21'],
PartNumber: item?.['22'],
Rack: item?.['23'],
ManufactureDate: item?.['24'],
ExpireDate: item?.['25'],
AvailableFrom: item?.['26'] ? item?.['26'] : '',
AvailableTo: item?.['27'] ? item?.['27'] : '',
Productimage: '',
});
});
setDatas(ExecelToJsConvertion);
// setExcelData(ExecelToJsConvertion);
// setOriginalUploadedRawData(ExecelToJsConvertion);
const style = document.createElement('style');
style.type = 'text/css';
style.innerHTML = `
.viewerExcelupload::-webkit-scrollbar {
display: block !important;
}
`;
document.head.appendChild(style);
return () => {
document.head.removeChild(style);
};
}
}, [excelData]);
useEffect(() => {
const fetchData = async () => {
if (AppId) {
const response = await dispatch(
getApplicationDetails({ AppId })
)?.unwrap();
setAppName(response?.data?.data?.[0]?.AppName);
}
};
fetchData();
}, [AppId]);
useEffect(() => {
// Call handleSubmit when Datas is updated
if (Datas) {
handleSubmit(Datas);
}
}, [Datas, handleSubmit]);
// Automatically update preview data on mapping change
const mandatoryFields = [
'ProductName',
'Quantity',
'UOM',
'SellPrice',
'Category',
];
useEffect(() => {
if (UploadedRawData.length > 0) {
const updatedMappedData = UploadedRawData.map((row, index) => {
const newRow = { key: index };
newRow['isModified'] = row?.isModified;
// โ
Process mandatory fields (retain value even if unmapped)
mandatoryFields.forEach((field) => {
const mappedHeader = fieldMapping[field];
if (mappedHeader && row[mappedHeader] !== undefined) {
newRow[field] = row[mappedHeader];
} else {
// Fallback: try original headers (case-insensitive, whitespace-insensitive)
const fallbackHeader = headers.find(
(header) =>
header?.toLowerCase().replace(/\s+/g, '') ===
field.toLowerCase().replace(/\s+/g, '')
);
if (fallbackHeader && row[fallbackHeader] !== undefined) {
newRow[field] = row[fallbackHeader];
} else {
// Preserve existing value if present
newRow[field] = ExcelData?.[index]?.[field] ?? '';
}
}
});
// โ
Process non-mandatory mapped fields
Object.entries(fieldMapping).forEach(([field, header]) => {
if (!mandatoryFields.includes(field)) {
newRow[field] = headers.includes(header) ? (row[header] ?? '') : '';
}
});
// โ
Clean up unmapped columns
headers.forEach((header) => {
const isMapped = Object.values(fieldMapping).includes(header);
const mappedField = Object.keys(fieldMapping).find(
(key) => fieldMapping[key] === header
);
const isMandatory = mandatoryFields.includes(mappedField);
if (!isMapped && !(header in newRow)) {
newRow[header] = isMandatory ? (row[header] ?? '') : '';
}
});
return newRow;
});
setExcelData(updatedMappedData);
setDatas(updatedMappedData);
}
}, [fieldMapping, UploadedRawData, headers]);
useEffect(() => {
if (AppId && BranchId && CompId) {
handleExportBulkdata();
}
}, [AppId, BranchId, CompId]);
// useEffect(() => {
// if (UploadedRawData.length > 0) {
// const updatedMappedData = UploadedRawData.map((row, index) => {
// const newRow = { key: index };
// requiredFields.forEach((requiredField) => {
// const mappedHeader = fieldMapping[requiredField];
// if (mappedHeader && row.hasOwnProperty(mappedHeader)) {
// // โ
Use only the mapped header if it exists in row
// newRow[requiredField] = row[mappedHeader];
// } else {
// // ๐ซ Do not fallback โ keep it clean
// newRow[requiredField] = '';
// }
// });
// // Optional: add unmapped fields if needed
// headers.forEach((header) => {
// const isMapped = Object.values(fieldMapping).includes(header);
// const mappedKey = Object.keys(fieldMapping).find(key => fieldMapping[key] === header);
// if (!isMapped && !(header in newRow) && !requiredFields.includes(mappedKey)) {
// newRow[header] = row[header] ?? '';
// }
// });
// return newRow;
// });
// setDatas(updatedMappedData);
// setExcelData(updatedMappedData);
// }
// }, [fieldMapping, UploadedRawData, headers]);
useEffect(() => {
getFieldSetup();
}, [productBulkUploadCatId]);
const getFieldSetup = async () => {
try {
const response = await dispatch(
getFieldSetupData({
AppId,
CompId,
BranchId,
categoryId: productBulkUploadCatId,
Type: 'EB',
})
).unwrap();
if (response?.data?.statusCode === 1) {
console.log(response?.data?.data?.[0]?.ConfigDtl, 'Field Setup Data');
setSelectedFields(
response?.data?.data?.[0]?.ConfigDtl?.filter(
(c) => c.ConfigId && c.Access === 'Y'
)?.map((c) => c.ConfigId) || []
);
setTableFieldPreferences(
response?.data?.data?.[0]?.ConfigDtl?.map((c) => ({
value: c.ConfigId,
label: c.ConfigName,
access: c.Access,
})) || []
);
setFieldValues(response?.data?.data?.[0]?.ConfigDtl);
} else {
setMessageType('error');
setMessageData('Failed to fetch field setup');
}
} catch (error) {
console.error('Error fetching field setup:', error);
}
};
const handleFileUpload = (e) => {
const file = e.target.files[0];
const reader = new FileReader();
if (file) {
const isAllowed = allowedExcelTypes?.includes(file.type);
if (!isAllowed) {
Modal.error({
title: 'Invalid File Type',
content: 'Only Excel files (.xls, .xlsx) are allowed.',
});
handleCancelData();
} else {
reader.readAsDataURL(file);
uploadAndProcessExcel(file);
}
} else {
dispatch(emptyExcelData());
}
};
const handleClick = () => {
// Programmatically trigger the file input click event
fileInputRef.current.click();
};
const getFieldValue = (product, field) => {
const aliasField = FIELD_ALIAS[field];
return normalize(product[field] ?? product[aliasField]);
};
const normalize = (value) => {
// Empty / invalid values
if (
value === undefined ||
value === null ||
value === '' ||
value === 'NaN-NaN-NaN'
) {
return '';
}
// Y / N flags
if (value === 'Y') return true;
if (value === 'N') return false;
// Numbers (handles "150", 150, "0")
if (
typeof value === 'number' ||
(typeof value === 'string' &&
value.trim() !== '' &&
!Number.isNaN(Number(value)))
) {
return Number(value);
}
// Default string
return String(value).trim();
};
const hashProduct = (product) =>
COMPARE_FIELDS.map((field) => getFieldValue(product, field)).join('ยง');
function findModifiedProducts(originalData, updatedData) {
if (!originalData?.length || !updatedData?.length) return [];
const originalHashMap = new Map();
for (const product of originalData) {
if (!product.ProdId) continue;
originalHashMap.set(product.ProdId, hashProduct(product));
}
// Step 2: Compare updated products
const modifiedProducts = [];
for (const product of updatedData) {
if (!product.ProdId) continue;
const originalHash = originalHashMap.get(product.ProdId);
if (!originalHash) continue; // new product, not modified
const updatedHash = hashProduct(product);
if (originalHash !== updatedHash) {
modifiedProducts.push(product);
}
}
return modifiedProducts;
}
const FIELD_ALIAS = {
'Product Variant Name': 'Product Varient Name',
};
const uploadAndProcessExcel = (file) => {
const reader = new FileReader();
reader.onload = (e) => {
const data = new Uint8Array(e.target.result);
const workbook = read(data, { type: 'array' });
const worksheet = workbook.Sheets[workbook.SheetNames[0]];
const jsonData = utils.sheet_to_json(worksheet, {
header: 1,
raw: false,
dateNF: 'DD/MM/YY',
});
const nonEmptyRows = jsonData.filter((row) =>
row.some((cell) => cell !== '')
);
const header = nonEmptyRows[0];
const rows = nonEmptyRows.slice(1);
const dateFields = [
'Available From',
'Available To',
'Manufacture Date',
'Expire Date',
'Stock Date',
];
function convertToDisplayFormat(dateString) {
const date = new Date(dateString);
const day = date.getDate().toString().padStart(2, '0');
const month = (date.getMonth() + 1).toString().padStart(2, '0');
const year = date.getFullYear().toString();
return `${day}-${month}-${year}`;
}
const formattedData = rows.map((row) => {
let rowData = header.reduce((acc, col, columnIndex) => {
if (dateFields?.includes(col)) {
acc[col] = convertToDisplayFormat(row[columnIndex]);
} else {
acc[col] = row[columnIndex];
}
return acc;
}, {});
return rowData;
});
if (jsonData.length > 0) {
const extractedHeaders = Object.keys(formattedData[0]);
const filteredData = formattedData.filter(
(item) => !Object.values(item)?.includes('sample row')
);
// โ
Add default variant name if missing
const updatedData = filteredData.map((item) => ({
...item,
'Product Varient Name':
item['Product Varient Name'] === undefined
? 'Variant 1'
: item['Product Varient Name'],
'Manufacture Date':
item['Manufacture Date'] == 'NaN-NaN-NaN' ? '' : item['Manufacture Date'],
'Expire Date':
item['Expire Date'] == 'NaN-NaN-NaN' ? '' : item['Expire Date'],
'Available From':
item['Available From'] == 'NaN-NaN-NaN' ? '' : item['Available From'],
'Available To':
item['Available To'] == 'NaN-NaN-NaN' ? '' : item['Available To'],
ProdId: item['ProdId'] || null,
}));
// Detect modified products
const modifiedProducts = findModifiedProducts(OrginalData, updatedData);
const modifiedIds = new Set(modifiedProducts.map((p) => p.ProdId));
const originalIds = new Set(OrginalData?.map((p) => p.ProdId) || []);
const markedData = updatedData
.map((item) => ({
...item,
isModified:
modifiedIds.has(item.ProdId) || !originalIds.has(item.ProdId),
}))
.sort((a, b) => b.isModified - a.isModified);
setUploadedRawData(markedData);
console.log(modifiedProducts, 'modifiedProducts');
// โ
Set only once with final data
setHeaders(extractedHeaders);
autoMapFields(extractedHeaders);
dispatch(uploadExcel({ file, jsonData: nonEmptyRows }));
setWorksheet(worksheet);
setDatas([]); // Clear mapped state initially
setExcelData([]);
}
// setMappingOpen(true);
dispatch(uploadExcel({ file, jsonData: nonEmptyRows }));
setWorksheet(worksheet);
setWorksheet1(worksheet1);
setDatas(formattedData); // Update Datas state here
// setExcelData(formattedData);
};
reader.readAsArrayBuffer(file);
};
useEffect(() => {
imagecall();
addOnlineImage();
Fielddatas();
}, []);
const imagecall = async (ProdName) => {
if (selectedProductName !== null) {
let response = await dispatch(onlineimages(ProdName)).unwrap();
setimagedata(response?.data?.data);
}
};
const addOnlineImage = (item, index) => {
item?.ProductName && setimageOpen(true);
imagecall(item?.ProductName);
setSelectedProductName(item?.ProductName);
setSelectedImageIndex(index);
};
const updateImageUrl = (url, index, key) => {
const newData1 = [...Datas];
newData1[key] = { ...newData1[key], Productimage: url };
setDatas(newData1);
setExcelData(newData1);
};
const handleimage = () => {
setimageOpen(false);
setSelectedImageIndex(null);
};
const submitimage = async () => {
const pageNo = currentPage * 10 + selectedImageIndex - 10;
if (selectedImageIndex != null && selectedImageIndex != undefined) {
try {
if (selectedImage.image !== undefined) {
const response = await fetch(selectedImage.image);
const datas = await response.blob();
const metadata = {
type: 'image/jpeg',
};
const file = new File([datas], 'image.jpg', metadata);
const uploadImgData = await dispatch(uploadImage(file)).unwrap();
if (uploadImgData?.data?.status == 1) {
let tempData = Datas;
const selectedIndex = tempData.findIndex(
(_, index) => index === pageNo
);
if (selectedIndex !== -1) {
tempData[selectedIndex].Productimage = uploadImgData?.data?.image;
}
setDatas(tempData);
setExcelData(tempData);
}
}
} finally {
handleimage();
}
}
};
const fieldOrder = [
'Product Name',
'Quantity',
'UOM',
'Sales Price',
'MRP',
'WholeSale Price',
'Category',
'Sub Category',
'Brand',
'Product Variant Name',
'Stock Available',
'Token Available',
'Product Type',
'Tax',
'Auto Generate QRCode',
'Add Qr Code',
'One Piece Available',
'OnePiece Price',
'Auto Generate One Piece Qrcode',
'Auto Generate One Piece Qrcode Number',
'CESS',
'HSN',
'Part Number',
'Rack',
'Manufacture Date',
'Expire Date',
'Available From',
'Available To',
];
const sortPreferredFields = (fields) => {
const fieldMap = {};
fields.forEach((field) => {
fieldMap[field.ConfigName] = field;
});
const sorted = [];
fieldOrder.forEach((name) => {
if (fieldMap[name] && fieldMap[name].Access === 'Y') {
sorted.push(fieldMap[name]);
}
});
return sorted;
};
// Usage inside your Fielddatas
const Fielddatas = async () => {
const res = await dispatch(getCommonAppPreference(AppId)).unwrap();
const productbulkUploadCatId =
res?.data?.data?.[0]?.PreferenceDetails?.find(
(p) => p?.PreferredCatName?.toLowerCase() === 'product bulk upload'
)?.PreferredCatId;
const response = await dispatch(
getFieldSetupData({
AppId,
CompId,
BranchId,
categoryId: productbulkUploadCatId,
Type: 'EB',
})
).unwrap();
const productBulkUploadFields = response?.data?.data?.[0]?.ConfigDtl || [];
const sortedFields = sortPreferredFields(productBulkUploadFields);
setFieldValues(sortedFields);
};
const handleDownload = async () => {
const workbook = new ExcelJS.Workbook();
const worksheet = workbook.addWorksheet('Sheet1');
const worksheet1 = workbook.addWorksheet('Sheet2');
const headerStyle = {
font: { bold: true },
border: {
top: { style: 'thin' },
left: { style: 'thin' },
bottom: { style: 'thin' },
right: { style: 'thin' },
},
alignment: { horizontal: 'center', vertical: 'middle' },
};
// Define all possible field configurations
const sampleData = getApplicationSampleData(appName);
console.log(sampleData, 'sampleData');
const fieldConfigs = {
ProdId: {
header: 'ProdId',
key: 'ProdId',
width: 15,
style: {
...headerStyle,
font: { bold: true, color: { argb: '#000000' } },
},
validation: null,
sampleValue: '',
headerColor: 'D3D3D3',
locked: true,
},
ProdName: {
header: 'Product Name',
key: 'ProdName',
width: 20,
Height: 20,
style: {
...headerStyle,
font: { bold: true, color: { argb: '#000000' } },
},
validation: null,
sampleValue: sampleData?.productName || 'Sample Product Name',
headerColor: 'FF2929',
},
Size: {
header: 'Quantity',
key: 'Size',
width: 10,
style: {
...headerStyle,
font: { bold: true, color: { argb: '#000000' } },
},
validation: {
type: 'custom',
allowBlank: true,
formulae: ['ISNUMBER({COLUMN}{ROW})'],
showErrorMessage: true,
errorTitle: 'Validation Error',
error: 'Please enter a Number.',
},
sampleValue: sampleData?.quantity || 1,
headerColor: 'FF2929',
},
UOM: {
header: 'UOM',
key: 'UOM',
width: 10,
style: {
...headerStyle,
font: { bold: true, color: { argb: '#000000' } },
},
validation: {
type: 'list',
allowBlank: true,
formulae: [
'"' +
(typeof Unit !== 'undefined' ? Unit.join(',') : 'KGS,PCS,LITER') +
'"',
],
},
sampleValue: sampleData?.uom || 'KGS',
headerColor: 'FF2929',
},
SellPrice: {
header: 'Sales Price',
key: 'SellPrice',
width: 15,
style: {
...headerStyle,
font: { bold: true, color: { argb: '#000000' } },
},
validation: {
type: 'custom',
allowBlank: true,
formulae: ['ISNUMBER({COLUMN}{ROW})'],
showErrorMessage: true,
errorTitle: 'Validation Error',
error: 'Please enter a Number.',
},
sampleValue: sampleData?.salesPrice || 100,
headerColor: 'FF2929',
},
ProdCat: {
header: 'Category',
key: 'ProdCat',
width: 20,
style: {
...headerStyle,
font: { bold: true, color: { argb: '#000000' } },
},
validation: {
type: 'list',
allowBlank: true,
formulae: [
'"' +
(typeof CategoryNames !== 'undefined'
? CategoryNames.join(',')
: 'Sample Category') +
'"',
],
},
sampleValue: sampleData?.category || 'Sample Category',
headerColor: 'FF2929',
},
ProdSubCat: {
header: 'Sub Category',
key: 'ProdSubCat',
width: 20,
style: {
...headerStyle,
font: { bold: true, color: { argb: '#000000' } },
},
validation: null,
sampleValue: sampleData?.subCategory || 'Sample Sub Category',
headerColor: '52c41a',
},
Brand: {
header: 'Brand',
key: 'Brand',
width: 20,
style: {
...headerStyle,
font: { bold: true, color: { argb: '#000000' } },
},
validation: null,
sampleValue: sampleData?.brand || 'Sample Brand',
headerColor: '52c41a',
},
ProdVarientName: {
header: 'Product Variant Name',
key: 'ProdVarientName',
width: 20,
Height: 20,
style: {
...headerStyle,
font: { bold: true, color: { argb: '#000000' } },
},
validation: null,
sampleValue: sampleData?.variantName || 'Sample Variant Name',
headerColor: '52c41a',
},
MRP: {
header: 'MRP',
key: 'MRP',
width: 10,
style: {
...headerStyle,
font: { bold: true, color: { argb: '#000000' } },
},
validation: {
type: 'custom',
allowBlank: true,
formulae: ['ISNUMBER({COLUMN}{ROW})'],
showErrorMessage: true,
errorTitle: 'Validation Error',
error: 'Please enter a Number.',
},
sampleValue: sampleData?.mrp || 100,
headerColor: '52c41a',
},
WhSalePrice: {
header: 'WholeSale Price',
key: 'WhSalePrice',
width: 15,
style: {
...headerStyle,
font: { bold: true, color: { argb: '#000000' } },
},
validation: {
type: 'custom',
allowBlank: true,
formulae: ['ISNUMBER({COLUMN}{ROW})'],
showErrorMessage: true,
errorTitle: 'Validation Error',
error: 'Please enter a Number.',
},
sampleValue: 100,
headerColor: '52c41a',
},
StockAvailable: {
header: 'Stock Available',
key: 'StockAvailable',
width: 20,
style: {
...headerStyle,
font: { bold: true, color: { argb: '#000000' } },
},
validation: {
type: 'list',
allowBlank: true,
formulae: ['"Yes,No"'],
},
sampleValue: 'Choose Yes or No',
headerColor: '52c41a',
},
OfferPrice: {
header: 'Token Available',
key: 'OfferPrice',
width: 15,
style: {
...headerStyle,
font: { bold: true, color: { argb: '#000000' } },
},
validation: {
type: 'list',
allowBlank: true,
formulae: ['"Yes,No"'],
},
sampleValue: 'Choose Yes or No',
headerColor: '52c41a',
},
Supplier: {
header: 'Product Type',
key: 'Supplier',
width: 20,
style: {
...headerStyle,
font: { bold: true, color: { argb: '#000000' } },
},
validation: {
type: 'list',
allowBlank: true,
formulae: ['"Product"'],
},
sampleValue: 'Product',
headerColor: '52c41a',
},
TaxId: {
header: 'Tax',
key: 'TaxId',
width: 20,
style: {
...headerStyle,
font: { bold: true, color: { argb: '#000000' } },
},
validation: {
type: 'list',
allowBlank: true,
formulae: [
'"' +
(typeof TaxDatas !== 'undefined'
? TaxDatas.map((item) =>
item.replace(/,/g, '').replace('-', '-').trim()
).join(',')
: 'NIL - 0%') +
'"',
],
},
sampleValue: 'NIL - 0%',
headerColor: '52c41a',
},
AutoGenerateQr: {
header: 'Auto Generate Qrcode',
key: 'AutoGenerateQr',
width: 20,
style: {
...headerStyle,
font: { bold: true, color: { argb: '#000000' } },
},
validation: {
type: 'list',
allowBlank: true,
formulae: ['"Yes,No"'],
},
sampleValue: 'Choose Yes or No',
headerColor: '52c41a',
},
AddQrCode: {
header: 'Add Qr Code',
key: 'AddQrCode',
width: 20,
style: {
...headerStyle,
font: { bold: true, color: { argb: '#000000' } },
},
validation: null,
sampleValue: 'Sample Qr eg:12345',
headerColor: '52c41a',
},
SpecialPrice: {
header: 'One Piece Available',
key: 'SpecialPrice',
width: 20,
style: {
...headerStyle,
font: { bold: true, color: { argb: '#000000' } },
},
validation: {
type: 'list',
allowBlank: true,
formulae: ['"Yes,No"'],
},
sampleValue: 'Choose Yes or No',
headerColor: '52c41a',
},
OnePiecePrice: {
header: 'OnePiece Price',
key: 'StockAvailable',
width: 20,
style: {
...headerStyle,
font: { bold: true, color: { argb: '#000000' } },
},
validation: {
type: 'custom',
allowBlank: true,
formulae: ['ISNUMBER({COLUMN}{ROW})'],
showErrorMessage: true,
errorTitle: 'Validation Error',
error: 'Please enter a Number.',
},
sampleValue: 'OnePiecePrice',
headerColor: '52c41a',
},
AutoGenOnePieceQr: {
header: 'Auto Generate One Piece Qrcode',
key: 'StockDate',
width: 30,
style: {
...headerStyle,
font: { bold: true, color: { argb: '#000000' } },
},
validation: {
type: 'list',
allowBlank: true,
formulae: ['"Yes,No"'],
},
sampleValue: 'Choose Yes or No',
headerColor: '52c41a',
},
AutoGenOnePieceQrNum: {
header: 'Auto Generate One Piece Qrcode Number',
key: 'StockDate',
width: 40,
style: {
...headerStyle,
font: { bold: true, color: { argb: '#000000' } },
},
validation: null,
sampleValue: 'Qr Number eg:ABC123',
headerColor: '52c41a',
},
CESS: {
header: 'CESS',
key: 'CESS',
width: 20,
style: {
...headerStyle,
font: { bold: true, color: { argb: '#000000' } },
},
validation: null,
sampleValue: 'Cess eg:0.5',
headerColor: '52c41a',
},
HSNCode: {
header: 'HSN',
key: 'HSNCode',
width: 20,
style: {
...headerStyle,
font: { bold: true, color: { argb: '#000000' } },
},
validation: null,
sampleValue: 'Hsn Number eg:100190',
headerColor: '52c41a',
},
PartNumber: {
header: 'Part Number',
key: 'PartNumber',
width: 20,
style: {
...headerStyle,
font: { bold: true, color: { argb: '#000000' } },
},
validation: null,
sampleValue: 'Part Number eg:1234-5678',
headerColor: '52c41a',
},
Rack: {
header: 'Rack',
key: 'Rack',
width: 20,
style: {
...headerStyle,
font: { bold: true, color: { argb: '#000000' } },
},
validation: null,
sampleValue: 'Rack Number eg:2200302',
headerColor: '52c41a',
},
ManufDate: {
header: 'Manufacture Date',
key: 'ManufDate DATETIME',
width: 20,
style: {
...headerStyle,
font: { bold: true, color: { argb: '#000000' } },
},
validation: null,
sampleValue: new Date(),
headerColor: '52c41a',
},
ExpDate: {
header: 'Expire Date',
key: 'ExpDate DATETIME',
width: 20,
style: {
...headerStyle,
font: { bold: true, color: { argb: '#000000' } },
},
validation: null,
sampleValue: new Date(),
headerColor: '52c41a',
},
AvailableFrom: {
header: 'Available From',
key: 'AvailableFrom TIME',
width: 20,
style: {
...headerStyle,
font: { bold: true, color: { argb: '#000000' } },
},
validation: null,
sampleValue: new Date(),
headerColor: '52c41a',
},
AvailableTo: {
header: 'Available To',
key: 'AvailableTo TIME',
width: 20,
style: {
...headerStyle,
font: { bold: true, color: { argb: '#000000' } },
},
validation: null,
sampleValue: new Date(),
headerColor: '52c41a',
},
};
function getExcelColumnLetter(colIndex) {
let temp = '';
let letter = '';
while (colIndex > 0) {
temp = (colIndex - 1) % 26;
letter = String.fromCharCode(temp + 65) + letter;
colIndex = Math.floor((colIndex - temp - 1) / 26);
}
return letter;
}
const mandatoryFields = ['ProdName', 'Size', 'UOM', 'SellPrice', 'ProdCat'];
const apiToInternalFieldMap = {
'Product Name': 'ProdName',
Quantity: 'Size',
UOM: 'UOM',
'Sales Price': 'SellPrice',
MRP: 'MRP',
'WholeSale Price': 'WhSalePrice',
Category: 'ProdCat',
'Sub Category': 'ProdSubCat',
Brand: 'Brand',
'Product Variant Name': 'ProdVarientName',
'Token Available': 'OfferPrice',
'Stock Available': 'StockAvailable',
Tax: 'TaxId',
'Auto Generate QRCode': 'AutoGenerateQr',
'Add Qr Code': 'AddQrCode',
'One Piece Available': 'SpecialPrice',
'OnePiece Price': 'OnePiecePrice',
'Auto Generate One Piece Qrcode': 'AutoGenOnePieceQr',
'Auto Generate One Piece Qrcode Number': 'AutoGenOnePieceQrNum',
CESS: 'CESS',
HSN: 'HSNCode',
'Part Number': 'PartNumber',
Rack: 'Rack',
'Manufacture Date': 'ManufDate',
'Expire Date': 'ExpDate',
'Available From': 'AvailableFrom',
'Available To': 'AvailableTo',
'Product Type': 'Supplier',
};
// Define dependent relationships
const dependentFieldMap = {
'Auto Generate QRCode': 'Add Qr Code',
'One Piece Available': 'OnePiece Price',
'Auto Generate One Piece Qrcode': 'Auto Generate One Piece Qrcode Number',
};
// Step 1: Sort preferred fields
const sortedPreferredFields = sortPreferredFields(FieldValues); // Your existing sort function
// Step 2: Convert API names to internal keys while skipping dependent fields initially
const preferredFieldKeys = [];
const preferredFieldSet = new Set();
sortedPreferredFields.forEach((field) => {
const fieldName = field.ConfigName;
const status = field.Access;
// Skip dependent fields for now
if (Object.values(dependentFieldMap).includes(fieldName)) return;
if (status === 'Y') {
const internalKey = apiToInternalFieldMap[fieldName];
if (internalKey) {
preferredFieldKeys.push(internalKey);
preferredFieldSet.add(fieldName);
}
// If this field has a dependent field, and it's enabled, add dependent too
const dependentFieldName = dependentFieldMap[fieldName];
if (dependentFieldName) {
const dependentInternalKey =
apiToInternalFieldMap[dependentFieldName];
if (dependentInternalKey) {
preferredFieldKeys.push(dependentInternalKey);
}
}
}
});
// Step 3: Merge Mandatory + Preferred (no duplicates)
const finalFieldKeys = [
...mandatoryFields,
...preferredFieldKeys.filter((key) => !mandatoryFields.includes(key)),
];
// Step 4: Map to ExcelJS column configs
const selectedColumns = finalFieldKeys
.map((fieldKey) => {
const config = fieldConfigs[fieldKey];
if (!config) {
console.warn(`Field configuration not found for: ${fieldKey}`);
return null;
}
return config;
})
.filter(Boolean);
selectedColumns.push({
header: '__isSampleRow',
key: '__isSampleRow',
width: 10, // width can be any value
style: { font: { size: 1 }, alignment: { horizontal: 'left' } },
sampleValue: 'sample row', // Mark sample row
headerColor: 'FFFFFF',
});
worksheet.columns = selectedColumns;
worksheet.getColumn(selectedColumns.length).hidden = true;
selectedColumns.forEach((config, index) => {
const columnLetter = getExcelColumnLetter(index + 1); // โ
FIXED
const headerCell = worksheet.getCell(`${columnLetter}1`);
headerCell.style = {
...config.style,
fill: {
type: 'pattern',
pattern: 'solid',
fgColor: { argb: config.headerColor },
},
};
});
// Add sample data in row 2
selectedColumns.forEach((config, index) => {
const columnLetter = getExcelColumnLetter(index + 1); // โ
FIXED
worksheet.getCell(`${columnLetter}2`).value = config.sampleValue;
});
// Add validation to columns
selectedColumns.forEach((config, colIndex) => {
if (config.validation) {
const colNumber = colIndex + 1; // Excel is 1-based
const columnLetter = getExcelColumnLetter(colNumber); // โ
FIXED
for (let rowNumber = 2; rowNumber <= 1001; rowNumber++) {
const cell = worksheet.getCell(rowNumber, colNumber); // โ
Use (row, col) instead of letter
let validation = { ...config.validation };
if (validation.formulae) {
validation.formulae = validation.formulae.map((formula) =>
formula
.replace('{COLUMN}', columnLetter)
.replace('{ROW}', rowNumber.toString())
);
}
cell.dataValidation = validation;
}
}
});
// Add empty rows for data entry
for (let i = 1; i <= 1000; i++) {
worksheet.addRow({});
}
// Now set protection for all rows
// First, unlock ALL cells in the worksheet
for (let rowNum = 1; rowNum <= worksheet.rowCount; rowNum++) {
const row = worksheet.getRow(rowNum);
row.eachCell({ includeEmpty: true }, (cell, colNumber) => {
const config = selectedColumns[colNumber - 1];
cell.protection = { locked: config?.locked || false };
});
}
// Then lock ONLY the header row (row 1) and sample row (row 2)
worksheet.getRow(1).eachCell({ includeEmpty: true }, (cell) => {
cell.protection = { locked: true };
});
worksheet.getRow(2).eachCell({ includeEmpty: true }, (cell) => {
cell.protection = { locked: true };
});
// Protect the worksheet
await worksheet.protect('', {
selectLockedCells: true, // Allow selecting locked cells (header/sample)
selectUnlockedCells: true, // Allow selecting unlocked cells (data rows)
formatCells: false,
formatColumns: false,
formatRows: false,
insertColumns: false,
insertRows: false,
deleteColumns: false,
deleteRows: false,
});
// Configure Sheet2 with all original columns and functionality
worksheet1.columns = [
{
header: 'Category Id',
key: 'CategoryId',
width: 15,
style: {
...headerStyle,
font: { bold: true, color: { argb: '#000000' } },
},
},
{
header: 'Category Name',
key: 'Category',
width: 30,
style: {
...headerStyle,
font: { bold: true, color: { argb: '#000000' } },
},
},
{
header: 'SUBCAT DATAS OF PARTICULAR CATEGORY',
key: 'SDPC',
width: 180,
style: {
...headerStyle,
font: { bold: true, color: { argb: '#000000' } },
},
},
{
header: 'SUBCAT ID',
key: 'SubcayID',
width: 10,
style: {
...headerStyle,
font: { bold: true, color: { argb: '#000000' } },
},
},
{
header: 'Sub Category name',
key: 'SubCategory',
width: 25,
style: {
...headerStyle,
font: { bold: true, color: { argb: '#000000' } },
},
},
{
header: '',
key: '',
width: 5,
style: {
...headerStyle,
font: { bold: true, color: { argb: '#000000' } },
},
},
{
header: 'SUBCAT NUMFID',
key: 'SubcatnumfId',
width: 20,
style: {
...headerStyle,
font: { bold: true, color: { argb: '#000000' } },
},
},
{
header: '',
key: 'smallIcon',
width: 5,
style: {
...headerStyle,
font: { bold: true, color: { argb: '#000000' } },
},
},
{
header: 'Brand ID',
key: 'BrandId',
width: 20,
style: {
...headerStyle,
font: { bold: true, color: { argb: '#000000' } },
},
},
{
header: 'Brand Name',
key: 'Brandname',
width: 20,
style: {
...headerStyle,
font: { bold: true, color: { argb: '#000000' } },
},
},
{
header: 'Brand NumfId',
key: 'BrandnumfId',
width: 20,
style: {
...headerStyle,
font: { bold: true, color: { argb: '#000000' } },
},
},
{
header: '',
key: 'smallIcon',
width: 5,
style: {
...headerStyle,
font: { bold: true, color: { argb: '#000000' } },
},
},
{
header: 'Brand Details',
key: 'Branddetails',
width: 150,
style: {
...headerStyle,
font: { bold: true, color: { argb: '#000000' } },
},
},
];
// Add data to Sheet2
for (let i = 1; i <= 100; i++) {
worksheet1.addRow({
CategoryId: '',
Category: '',
SDPC: '',
SubcayID: '',
SubCategory: '',
SubcatnumfId: '',
BrandId: '',
Brandname: '',
BrandnumfId: '',
Branddetails: '',
});
}
// All the original dropdown and validation logic for Sheet2
const dropdownOptions = {
Option1: ['Yes', 'No'],
Option2: ['Product'],
Option3: ['ValueX', 'ValueY', 'ValueZ'],
};
const selectedOptionA = 'Option1';
const selectedOptionB = 'Option2';
// Create category and brand data maps (original logic)
const categoryDataMap = {};
if (typeof CategoryId !== 'undefined') {
CategoryId.forEach((categoryId, index) => {
categoryDataMap[categoryId] =
typeof SubCatData !== 'undefined' ? SubCatData[index] : '';
});
}
const BrandDataMap = {};
if (typeof AllBrandId !== 'undefined') {
AllBrandId.forEach((AllBrandId, index) => {
BrandDataMap[AllBrandId] =
typeof SubCatData !== 'undefined' ? SubCatData[index] : '';
});
}
// Apply all original Sheet2 validations and logic
if (typeof CategoryId !== 'undefined') {
worksheet1
.getColumn('A')
.eachCell({ includeEmpty: true }, function (cell, rowNumber) {
if (rowNumber > 1) {
const dynamicValidValues = '"' + CategoryId.join(',') + '"';
const defaultCategoryId = CategoryId[rowNumber - 2];
cell.value = defaultCategoryId;
cell.dataValidation = {
type: 'list',
allowBlank: true,
formulae: [dynamicValidValues],
};
}
});
}
if (typeof CategoryNames !== 'undefined') {
worksheet1
.getColumn('B')
.eachCell({ includeEmpty: true }, function (cell, rowNumber) {
if (rowNumber > 1) {
const dynamicValidValues = '"' + CategoryNames.join(',') + '"';
const defaultCategoryName = CategoryNames[rowNumber - 2];
cell.value = defaultCategoryName;
cell.dataValidation = {
type: 'list',
allowBlank: true,
formulae: [dynamicValidValues],
};
}
});
}
if (typeof SubcatId !== 'undefined') {
worksheet1
.getColumn('D')
.eachCell({ includeEmpty: true }, function (cell, rowNumber) {
if (rowNumber > 1) {
const dynamicValidValues = '"' + SubcatId.join(',') + '"';
const defaultCategorysubName = SubcatId[rowNumber - 2];
cell.value = defaultCategorysubName;
cell.dataValidation = {
type: 'list',
allowBlank: true,
formulae: [dynamicValidValues],
};
}
});
}
if (typeof SubCatData !== 'undefined') {
worksheet1
.getColumn('E')
.eachCell({ includeEmpty: true }, function (cell, rowNumber) {
if (rowNumber > 1) {
const dynamicValidValues = '"' + SubCatData.join(',') + '"';
const defaultCategorysubName = SubCatData[rowNumber - 2];
cell.value = defaultCategorysubName;
cell.dataValidation = {
type: 'list',
allowBlank: true,
formulae: [dynamicValidValues],
};
}
});
}
if (typeof Subcatnumfid !== 'undefined') {
worksheet1
.getColumn('G')
.eachCell({ includeEmpty: true }, function (cell, rowNumber) {
if (rowNumber > 1) {
const dynamicValidValues = '"' + Subcatnumfid.join(',') + '"';
const defaultCategorysubName = Subcatnumfid[rowNumber - 2];
cell.value = defaultCategorysubName;
cell.dataValidation = {
type: 'list',
allowBlank: true,
formulae: [dynamicValidValues],
};
}
});
}
if (typeof AllBrandId !== 'undefined') {
worksheet1
.getColumn('I')
.eachCell({ includeEmpty: true }, function (cell, rowNumber) {
if (rowNumber > 1) {
const dynamicValidValues = '"' + AllBrandId.join(',') + '"';
const defaultCategorysubName = AllBrandId[rowNumber - 2];
cell.value = defaultCategorysubName;
cell.dataValidation = {
type: 'list',
allowBlank: true,
formulae: [dynamicValidValues],
};
}
});
}
if (typeof Allbranddata !== 'undefined') {
worksheet1
.getColumn('J')
.eachCell({ includeEmpty: true }, function (cell, rowNumber) {
if (rowNumber > 1) {
const dynamicValidValues = '"' + Allbranddata.join(',') + '"';
const defaultCategorysubName = Allbranddata[rowNumber - 2];
cell.value = defaultCategorysubName;
cell.dataValidation = {
type: 'list',
allowBlank: true,
formulae: [dynamicValidValues],
};
}
});
}
if (typeof Allbranddatanumfid !== 'undefined') {
worksheet1
.getColumn('K')
.eachCell({ includeEmpty: true }, function (cell, rowNumber) {
if (rowNumber > 1) {
const dynamicValidValues = '"' + Allbranddatanumfid.join(',') + '"';
const defaultCategorysubName = Allbranddatanumfid[rowNumber - 2];
cell.value = defaultCategorysubName;
cell.dataValidation = {
type: 'list',
allowBlank: true,
formulae: [dynamicValidValues],
};
}
});
}
// Original complex logic for column C (SUBCAT DATAS)
worksheet1
.getColumn('C')
.eachCell({ includeEmpty: true }, function (cell, rowNumber) {
if (rowNumber > 1) {
const categoryId = worksheet1.getCell(`A${rowNumber}`).value;
if (categoryId !== null) {
const uniqueSubCategoryData = new Set();
const matchedData = [];
worksheet1
.getColumn('G')
.eachCell(
{ includeEmpty: true },
function (subCatCell, subCatRowNumber) {
if (subCatRowNumber > 1 && subCatCell.value === categoryId) {
const subCategoryName = worksheet1.getCell(
`E${subCatRowNumber}`
).value;
const subCatId = worksheet1.getCell(
`D${subCatRowNumber}`
).value;
const fullSubCategoryName = `${subCatId} - ${subCategoryName}`;
uniqueSubCategoryData.add({
subCategoryId: subCatId,
subCategoryName: subCategoryName,
});
const subCatData = categoryDataMap[categoryId]
? categoryDataMap[categoryId].subCatData
: null;
const data = {
subCategoryId: subCatId,
subCategoryName: subCategoryName,
subCatData: subCatData,
};
matchedData.push(data);
}
}
);
cell.value = JSON.stringify(Array.from(uniqueSubCategoryData));
}
}
});
// Original complex logic for column M (Brand Details)
worksheet1
.getColumn('M')
.eachCell({ includeEmpty: true }, function (cell, rowNumber) {
if (rowNumber > 1) {
const SubcatId = worksheet1.getCell(`D${rowNumber}`).value;
if (SubcatId !== null) {
const uniqueSubCategoryData = new Set();
const matchedData = [];
worksheet1
.getColumn('K')
.eachCell(
{ includeEmpty: true },
function (BrandCell, BrandRowNumber) {
if (BrandRowNumber > 1 && BrandCell.value === SubcatId) {
const BrandName = worksheet1.getCell(
`J${BrandRowNumber}`
).value;
const BrandId = worksheet1.getCell(
`I${BrandRowNumber}`
).value;
const fullSubCategoryName = `${BrandId} - ${BrandName}`;
uniqueSubCategoryData.add({
BrandId: BrandId,
BrandName: BrandName,
});
const BrandData = BrandDataMap[SubcatId]
? BrandDataMap[SubcatId].BrandData
: null;
const data = {
BrandId: BrandId,
BrandName: BrandName,
BrandData: BrandData,
};
matchedData.push(data);
}
}
);
cell.value = JSON.stringify(Array.from(uniqueSubCategoryData));
}
}
});
// Generate and download the file
const buffer = await workbook.xlsx.writeBuffer();
const blob = new Blob([buffer], {
type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
});
const filename = 'Product Data.xlsx';
if (typeof window !== 'undefined') {
if (window.navigator && window.navigator.msSaveOrOpenBlob) {
window.navigator.msSaveOrOpenBlob(blob, filename);
} else {
const downloadLink = document.createElement('a');
downloadLink.href = window.URL.createObjectURL(blob);
downloadLink.download = filename;
downloadLink.click();
}
}
};
// Usage examples:
// Download only specific fields:
// handleDownload(['ProdName', 'Size']); // Only Product Name and Quantity
// handleDownload(['ProdName', 'Size', 'UOM', 'SellPrice']); // Multiple fields
// handleDownload(['ProdName', 'Size', 'UOM', 'SellPrice', 'ProdCat', 'Brand']); // More fields
// Available field names:
// 'ProdName', 'Size', 'UOM', 'SellPrice', 'ProdCat', 'ProdSubCat', 'Brand',
// 'ProdVarientName', 'MRP', 'StockAvailable', 'OfferPrice', 'Supplier', 'TaxId',
// 'AutoGenerateQr', 'AddQrCode', 'SpecialPrice', 'OnePiecePrice', 'AutoGenOnePieceQr',
// 'AutoGenOnePieceQrNum', 'CESS', 'HSNCode', 'PartNumber', 'Rack', 'ManufDate',
// 'ExpDate', 'AvailableFrom', 'AvailableTo'
const handleFileSubmit = (e) => {
e.preventDefault();
if (excelFile === null) {
excelFileError('Please select an Excel file.');
} else {
handleSubmit(Datas);
}
};
const handleFieldSetup = () => {
setFieldSetup(true);
};
const handleFieldSetupSubmit = async () => {
const postData = {
AppId: AppId,
CompId: CompId,
BranchId: BranchId,
Type: 'EB',
FormType: 'Product',
TypeId: productBulkUploadCatId,
ConfigDtl: selectedFields?.map((field) => ({
ConfigId: field,
Access: 'Y',
})),
CreatedBy: UserId,
};
const response = await dispatch(postFieldSetup(postData))?.unwrap();
if (response?.data?.statusCode === 1) {
setMessageType('success');
setMessageData(response?.data?.response);
setFieldSetup(false);
await getFieldSetup();
} else {
setMessageType('error');
setMessageData('Failed to set up fields');
}
};
const handleFieldSelect = (value) => {
setSelectedFields((prev) => {
if (prev.includes(value)) {
return prev;
}
return [value, ...prev];
});
};
const handleFieldRemove = (id) => {
setSelectedFields((prev) => prev.filter((field) => field !== id));
};
const handleCancelData = () => {
dispatch(emptyExcelData());
if (fileInputRef.current) {
fileInputRef.current.value = '';
}
};
const columns = [
{
title: 'Product Name',
dataIndex: 'ProductName',
key: 'ProductName',
editable: true,
},
{
title: 'Qty',
dataIndex: 'Quantity',
key: 'Quantity',
editable: true,
},
{
title: 'UOM',
dataIndex: 'UOM',
key: 'UOM',
editable: true,
},
{
title: 'Sales Price',
dataIndex: 'SellPrice',
key: 'SellPrice',
editable: true,
},
{
title: 'Category',
dataIndex: 'Category',
key: 'Category',
editable: true,
},
{
title: 'Sub Category',
dataIndex: 'SubCategory',
key: 'SubCategory',
editable: true,
},
{
title: 'Brand',
dataIndex: 'Brand',
key: 'Brand',
editable: true,
},
{
title: 'Variant Name',
dataIndex: 'ProductVariantName',
key: 'ProductVariantName',
editable: true,
},
{
title: 'MRP',
dataIndex: 'MRP',
key: 'MRP',
editable: true,
},
{
title: 'WholeSale Price',
dataIndex: 'WhSalePrice',
key: 'WhSalePrice',
editable: true,
},
{
title: 'Auto Qrcode',
dataIndex: 'AutoGenerateQrcode',
key: 'AutoGenerateQrcode',
editable: true,
},
{
title: 'Add QrCode',
dataIndex: 'AddQrCode',
key: 'AddQrCode',
editable: true,
},
{
title: 'Stock Available',
dataIndex: 'StockAvailable',
key: 'StockAvailable',
editable: true,
},
{
title: 'Token Available',
dataIndex: 'TokenAvailable',
key: 'TokenAvailable',
editable: true,
},
{
title: 'One Piece Available',
dataIndex: 'OnePieceAvailable',
key: 'OnePieceAvailable',
editable: true,
},
{
title: 'One Piece Price',
dataIndex: 'OnePiecePrice',
key: 'OnePiecePrice',
editable: true,
},
{
title: 'Auto Gen One Piece Qr',
dataIndex: 'AutoGenerateOnePieceQrcode',
key: 'AutoGenerateOnePieceQrcode',
editable: true,
},
{
title: 'Auto Gen One Piece Qr No',
dataIndex: 'AutoGenerateOnePieceQrcodeNumber',
key: 'AutoGenerateOnePieceQrcodeNumber',
editable: true,
},
{
title: 'Product Type',
dataIndex: 'ProductType',
key: 'ProductType',
editable: true,
},
{
title: 'Tax',
dataIndex: 'Tax',
key: 'Tax',
editable: true,
},
{
title: 'Cess',
dataIndex: 'CESS',
key: 'CESS',
editable: true,
},
{
title: 'HSN',
dataIndex: 'HSN',
key: 'HSN',
editable: true,
},
{
title: 'Part Number',
dataIndex: 'PartNumber',
key: 'PartNumber',
editable: true,
},
{
title: 'Rack',
dataIndex: 'Rack',
key: 'Rack',
editable: true,
},
{
title: 'Mfg Date',
dataIndex: 'ManufactureDate',
key: 'ManufactureDate',
editable: true,
},
{
title: 'Exp Date',
dataIndex: 'ExpireDate',
key: 'ExpireDate',
editable: true,
},
{
title: 'Avl From',
dataIndex: 'AvailableFrom',
key: 'AvailableFrom',
editable: true,
},
{
title: 'Avl To',
dataIndex: 'AvailableTo',
key: 'AvailableTo',
editable: true,
},
{
title: 'Image',
dataIndex: 'Productimage',
key: 'Productimage',
render: (ProdImage, record, index) => {
const Img = ProdImage;
return (
<>
{Img ? (
) : (
<>