Android_Retail/src/Pages/Product/ExcelUpload.jsx

2940 lines
108 KiB
React
Raw Normal View History

2026-01-27 18:27:29 +05:30
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";
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,
}) => {
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();
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 handleTableChange = (pagination, filters, sorter) => {
setCurrentPage(pagination.current);
};
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 };
// ✅ 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 (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 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"],
"Available To":
item["Available To"] == "NaN-NaN-NaN" ? "" : item["Available To"],
}));
// ✅ Set only once with final data
setHeaders(extractedHeaders);
setUploadedRawData(updatedData); // Final, cleaned and enriched data
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 = {
'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) => {
cell.protection = { 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 ? (
<img
src={Img}
alt={record.Productimage}
style={{ maxWidth: "50px", maxHeight: "50px" }}
/>
) : (
<>
<div className="imgUpldr" style={{ fontSize: '15px' }}>
<Imageupload
singleImage={true}
updateImageUrl={(url) => updateImageUrl(url, index)}
// ImageLink={record.Productimage || ""}
ImageLink={
onlineImage
? onlineImage
: record.Productimage
? record.Productimage
: ""
}
listType="picture-card"
// onlineImage={onlineImage?onlineImage:""}
// ImageLink={record.Productimage }
// updateImageUrl={updateImageUrl}
// singleImage={true}
recordMaintainKey={record.key}
/>
<Tooltip title="Online Search">
<TbWorldSearch
style={{ fontSize: "30px" }}
onClick={() => addOnlineImage(record, index)}
/>
</Tooltip>
</div>
</>
)}
</>
);
},
},
];
const column = columns?.map((col) => {
if (!col.editable) {
return col;
}
let onClickHandler = null;
if (editdelete === "Delete") {
onClickHandler = (record) => removeFromTable(record);
}
return {
...col,
onCell: (record) => ({
record,
editable: col.editable,
dataIndex: col.dataIndex,
title: col.title,
handleSave,
onClick: () => onClickHandler(record),
}),
};
});
const EditableContext = React.createContext(null);
const EditableRow = ({ index, dataIndex, ...props }) => {
const [form] = Form.useForm();
return (
<Form form={form} component={false}>
<EditableContext.Provider value={form}>
<tr {...props} />
</EditableContext.Provider>
</Form>
);
};
const EditableCell = ({
title,
editable,
children,
dataIndex,
record,
handleSave,
index,
...restProps
}) => {
const [editing, setEditing] = useState(false);
const inputRef = useRef(null);
const form = useContext(EditableContext);
useEffect(() => {
if (editing) {
inputRef?.current?.focus();
}
}, [editing]);
const toggleEdit = () => {
setEditing(!editing);
form.setFieldsValue({
[dataIndex]: record[dataIndex],
});
};
const save = async () => {
try {
const values = await form.validateFields();
toggleEdit();
handleSave({
...record,
...values,
});
} catch (errInfo) { }
};
let childNode = children;
if (editable) {
childNode = editing ? (
<Form.Item
style={{
margin: 0,
}}
name={dataIndex}
>
<Input ref={inputRef} onPressEnter={save} onBlur={save} />
</Form.Item>
) : (
<div
className="editable-cell-value-wrap"
style={{
paddingRight: 24,
}}
onClick={toggleEdit}
>
{children}
</div>
);
}
return <td {...restProps}>{childNode}</td>;
};
const components = {
body: {
row: EditableRow,
cell: EditableCell,
},
};
const handleSave = (row) => {
const newDatas = [...Datas];
const item = newDatas.filter(item => item.key === row.key);
// const item = newDatas[index];
const UpdatedData = {
ProductName: row?.ProductName,
ProductVariantName: row?.ProductVariantName ? row?.ProductVariantName : "Variant 1",
Quantity: row?.Quantity,
UOM: row?.UOM,
MRP: row?.MRP,
WhSalePrice: row?.WhSalePrice,
SellPrice: row?.SellPrice,
Category: row?.Category,
SubCategory: row?.SubCategory,
Brand: row?.Brand,
AutoGenerateQrcode: row?.AutoGenerateQrcode,
AddQrCode: row?.AddQrCode,
StockAvailable: row?.StockAvailable,
// NumberOfPieceInside:row?.NumberOfPieceInside,
TokenAvailable: row?.TokenAvailable,
OnePieceAvailable: row?.OnePieceAvailable,
OnePiecePrice: row?.OnePiecePrice,
AutoGenerateOnePieceQrcode: row?.AutoGenerateOnePieceQrcode,
AutoGenerateOnePieceQrcodeNumber: row?.AutoGenerateOnePieceQrcodeNumber,
ProductType: row?.ProductType,
Tax: row?.Tax,
CESS: row?.CESS,
HSN: row?.HSN,
PartNumber: row?.PartNumber,
Rack: row?.Rack,
ManufactureDate: row?.ManufactureDate,
ExpireDate: row?.ExpireDate,
AvailableFrom: row?.AvailableFrom,
AvailableTo: row?.AvailableTo,
Productimage: row?.Productimage,
key: row?.key,
};
newDatas.splice(item?.[0]?.key, 1, {
...item?.[0],
...UpdatedData,
});
setDatas(newDatas);
setExcelData(newDatas);
};
const handlechange22 = (index) => {
if (editdelete === "Delete") {
seteditdelete("");
} else {
seteditdelete("Delete");
}
};
const removeFromTable = (record) => {
const indexToRemove = Datas.findIndex((item) => item.key === record.key);
if (indexToRemove !== -1) {
const updatedDataSource = [...Datas];
updatedDataSource.splice(indexToRemove, 1);
setDatas(updatedDataSource);
setExcelData(updatedDataSource);
}
};
const handleExportData = async () => {
setLoading(true)
let response = await dispatch(getProductData({ CompId: CompId, BranchId: BranchId, AppId: AppId })).unwrap();
if (response?.data?.statusCode == 1 && response?.data?.data?.length > 0) {
const formattedData = response?.data?.data?.map(item => {
return {
"Product Name": item.ProdName,
"Product Variant Name": item.ProdVarientName,
"Quantity": item.Size,
"UOM": item.UomName,
"MRP": item.MRP,
"WholeSale Price": item.WhSalePrice,
"Sales Price": item.SellPrice,
"Category": item.CategoryName,
"Sub Category": item.SubCategoryName,
"Brand": item.BrandName,
"Auto Generate Qrcode": item.AutoGenerateQr ? item.AutoGenerateQr : "N",
"Add Qr Code": item.QRCode,
"Stock Available": item.StockAvailable ? item.StockAvailable : "N",
"Token Available": item.TokenAvailable ? item.TokenAvailable : "N",
"One Piece Available": item.OnePcsAvailable ? item.OnePcsAvailable : "N",
"One Piece Price": item.OnePcsPrice,
"Auto Generate One Piece Qrcode": item.AutoGenerateSingleQr ? item.AutoGenerateSingleQr : "N",
"Auto Generate One Piece Qrcode Number": item.OnePcQR,
"Product Type": item.ProdTypeName ? item.ProdTypeName : "Product",
"Tax": `${item.TaxName || "NIL"} - ${item.TaxPercentage || 0}%`, // Ensures a valid tax format
"CESS": item.CESS,
"HSN": item.HSNCode,
"Part Number": item.PartNumber,
"Rack": item.Rack,
"Manufacture Date": null,
"Expire Date": null,
"Available From": item.AvailableFrom != "00:00:00" ? item.AvailableFrom : null,
"Available To": item.AvailableTo != "00:00:00" ? item.AvailableTo : null
};
});
const ws = XLSX.utils.json_to_sheet(formattedData);
// Create a new workbook and append the worksheet
const wb = XLSX.utils.book_new();
XLSX.utils.book_append_sheet(wb, ws, "Products");
setLoading(false)
// Trigger the file download
XLSX.writeFile(wb, "Product_Data.xlsx");
}
else {
setLoading(false)
setMessage(true)
}
}
const requiredFields = [
"ProductName",
"ProductVariantName",
"Quantity",
"UOM",
"MRP",
"SellPrice",
"WhSalePrice",
"Category",
"SubCategory",
"Brand",
"StockAvailable",
"TokenAvailable",
"ProductType",
"Tax",
"AutoGenerateQrcode",
"AddQrCode",
"OnePieceAvailable",
"OnePiecePrice",
"AutoGenerateOnePieceQrcode",
"AutoGenerateOnePieceQrcodeNumber",
"CESS",
"HSN",
"PartNumber",
"Rack",
"ManufactureDate",
"ExpireDate",
"AvailableFrom",
"AvailableTo"
];
const enhancedColumns = columns.map((col) => {
if (col.dataIndex === "Productimage") return col;
// Get all used fields *except* the current column (to allow remap)
const usedFields = Object.entries(fieldMapping)
.filter(([key]) => key !== col.dataIndex)
.map(([, value]) => value);
// Fields left for dropdown (excluding already selected ones)
const availableHeaders = headers?.filter(h => !usedFields?.includes(h) && h !== "__isSampleRow");
const isMapped = !!fieldMapping[col.dataIndex];
return {
...col,
title: (
<div style={{ display: "flex", flexDirection: "column", justifyContent: "space-between", height: "80%" }}>
<div style={{ display: 'flex', flexDirection: 'column' }}>
<span>{col.title}</span>
{!isMapped && (
<span style={{ color: 'red', fontSize: '11px' }}>
Not mapped
</span>
)}
</div>
<div style={{ position: "relative", width: '80%', marginTop: 5 }}>
<Select
// allowClear
style={{ width: '100%' }}
placeholder="Select"
value={fieldMapping[col.dataIndex] || undefined}
onChange={(selectedField) => {
setFieldMapping((prev) => {
const updated = { ...prev };
// Remove the same field from other mappings
Object.entries(updated).forEach(([key, val]) => {
if (val === selectedField) delete updated[key];
});
if (selectedField) {
updated[col.dataIndex] = selectedField;
} else {
delete updated[col.dataIndex];
}
return updated;
});
}}
>
{availableHeaders.map((header) => (
<Select.Option key={header} value={header}>
{header}
</Select.Option>
))}
</Select>
{fieldMapping[col.dataIndex] && (
<CloseCircleOutlined
onClick={() => {
setFieldMapping((prev) => {
const updated = { ...prev };
delete updated[col.dataIndex];
return updated;
});
}}
className="SelectCancelicon"
style={{
position: 'absolute',
right: "-17px",
top: '80%',
transform: 'translateY(-50%)',
color: 'red',
fontSize: 14,
cursor: 'pointer',
zIndex: 1,
}}
/>
)}
</div>
</div>
),
render: (text, record, index) => {
const mappedField = fieldMapping[col.dataIndex];
if (mappedField && originalUploadedRawData?.[index]?.[mappedField] !== undefined) {
return originalUploadedRawData[index][mappedField];
}
return record[col.dataIndex] !== undefined ? record[col.dataIndex] : '';
},
onCell: (record) => ({
record,
editable: col.editable,
dataIndex: col.dataIndex,
title: col.title,
handleSave,
onClick: () => {
if (editdelete === "Delete") {
removeFromTable(record);
}
},
}),
};
});
const aliasMap = {
ProductName: ["product name", "product", "item", "item name", "prodname"],
ProductVariantName: ["variant", "product variant", "variant name", "productvariant",],
Quantity: ["qty", "quantity", "qty size", "quantitysize", "qnt"],
UOM: ["uom", "unit", "unit of measure"],
MRP: ["mrp", "mrp price", "m.r.p"],
SellPrice: ["retail", "retail price", "sales price", "selling price"],
WhSalePrice: ["wholesale", "wholesale price", "wholesaleprice"],
Category: ["category", "product category", "cat"],
SubCategory: ["subcategory", "sub category", "sub cat", "sub-cat"],
Tax: ["tax", "tax percent", "gst", "vat"],
CESS: ["cess"],
HSN: ["hsn", "hsn code"],
Brand: ["brand", "brand name"],
// Add more as needed...
};
const autoMapFields = (headers) => {
const updatedMapping = {};
const cleanedHeaders = headers.map((h) => h?.toLowerCase().replace(/\s+/g, ''));
requiredFields.forEach((requiredField) => {
const cleanedField = requiredField?.toLowerCase();
// 1. Try exact match (cleaned)
const match = stringSimilarity.findBestMatch(cleanedField, cleanedHeaders);
const bestMatchIndex = match.bestMatchIndex;
const bestMatchScore = match.bestMatch.rating;
if (bestMatchScore > 0.6) {
updatedMapping[requiredField] = headers[bestMatchIndex];
return;
}
// 2. Try alias match
const aliases = aliasMap[requiredField] || [];
const matchedHeader = headers.find((header) =>
aliases.some(
(alias) => header?.toLowerCase().replace(/\s+/g, '') === alias.replace(/\s+/g, '')
)
);
if (matchedHeader) {
updatedMapping[requiredField] = matchedHeader;
}
});
setFieldMapping(updatedMapping);
};
return (
<div>
<Messages messageType={messageType} messageData={messageData} onComplete={() => { setMessageData(null); setMessageType(null); }} />
<div className="form">
<form
className="form-group"
autoComplete="off"
onSubmit={handleFileSubmit}
>
<div style={{ display: "flex", justifyContent: "space-between", flexWrap: "wrap" }}>
<p style={{ fontSize: "20px", fontWeight: "500" }}>
Upload Your Excel
</p>
<div style={{ display: "flex", flexDirection: "row", gap: "0.5rem", margin: "1rem 0" }}>
<Tooltip title="Field Setup">
<div className="btn btn--info" style={{
background: "#00694aff",
color: "#fff",
display: "flex",
alignItems: "center",
justifyContent: "center",
padding: "5px 12px",
borderRadius: "4px"
}} onClick={handleFieldSetup}><MdOutlineAppRegistration size={19} /></div>
</Tooltip>
<div className="export-excel-div" onClick={() => handleExportData()}>
<div>
<CiExport size={20} strokeWidth={1} />
</div>
<div style={{ fontSize: "14px", letterSpacing: "0.2px" }}>
Export Excel
</div>
</div>
{/* {excelData?.length > 0 && excelData &&
<div className="export-excel-div" onClick={() => setMappingOpen(true)}>
<div>
<CiBoxList />
</div>
<div>
Map Your Fields
</div>
</div>
} */}
{loading &&
<div style={{ color: "#ff4d4f" }}>Loading...</div>
}
{message &&
<div style={{ color: "#ff4d4f" }}>No Data Found</div>
}
</div>
{excelData?.length > 0 && excelData &&
<div >
<Tooltip title="Delete">
<AiFillDelete
onClick={handlechange22} style={{
fontSize: "23px", color: editdelete ? "#52c41a" : "#1292ee",
}} />
</Tooltip>
</div>
}
</div>
<Tooltip
title={"Format Sheet"}
placement="bottom"
>
<div
className="download-link"
style={{
display: 'flex',
alignItems: "flex-end",
justifyContent: "flex-end",
}}
>
<button onClick={handleDownload}>
<FiDownload style={{ fontSize: '20px' }} />
<span >Download Sample Sheet</span>
</button>
</div>
</Tooltip>
{(!excelData || excelData?.length === 0) && (
<>
<div style={{
display: 'flex', alignItems: 'center', border: "1px dashed #000",
width: "max-content", padding: "10px", borderRadius: "6px"
}} >
<div style={{ position: 'relative', display: 'inline-block', }}>
{/* <Imageupload size="2x" /> */}
<div style={{ display: 'flex', flexDirection: 'column', alignItems: 'center', }}>
<img src={Excelupldimg} width={"80px"}
style={{ cursor: 'pointer', margin: "0 0 1rem 0" }}
onClick={handleClick} />
<input
type="file"
className="form-control"
onChange={handleFileUpload}
ref={fileInputRef}
style={{
position: 'absolute',
top: 0,
left: 0,
width: '100%',
height: '100%',
opacity: 0,
cursor: 'pointer',
}}
/>
<a style={{ color: '#000', fontSize: "12px" }}> Upload Sheet </a>
</div>
</div>
</div>
</>
)}
{excelFileError && (
<div className="text-danger" style={{ marginTop: "5px" }}>
{excelFileError}
</div>
)}
</form>
</div>
<div className="viewerExcelupload" style={{ maxHeight: "90vh", overflowX: "auto" }}>
{excelData && excelData?.length > 0 ? (
<Table
columns={enhancedColumns}
components={components}
bordered
dataSource={ExcelData}
className="tableExcelUpload"
onChange={handleTableChange}
></Table>
) :
(
<p></p>
)}
</div>
<div style={{ display: 'flex', alignItems: 'center', width: '100%', gap: '2rem', margin: '1rem 0rem' }}>
{/* <Tooltip title="Format Sheet" placement="bottom">
<div className="download-link" onClick={handleDownload} style={{ display: 'flex', alignItems: 'center', gap: '.5rem', padding: '0.3rem 0.4rem', borderRadius: '6px', backgroundColor: 'ghostwhite' }} >
<FiDownload style={{ fontSize: '20px', }} />
<a style={{ color: '#000' }}> Download</a>
</div>
</Tooltip> */}
{excelData && excelData?.length > 0 &&
<div
className="cancel-link"
onClick={handleCancelData}
style={{ display: 'flex', alignItems: 'center', gap: '.5rem', padding: '0.3rem 0.4rem', borderRadius: '6px', backgroundColor: 'ghostwhite' }}
>
<FiDelete style={{ fontSize: '20px', color: "#1292EE" }} />
<a style={{ color: '#000' }}> Remove File</a>
</div>
}
</div>
<DefaultModal
open={fieldSetup}
handleCancel={() => setFieldSetup(false)}
footer={false}
children={
<div className="field-setup-container">
<div className="field-setup-header">
<FormHeader title={'Select the fields you want to include in the table'} />
</div>
<div className="field-setup-content">
<Form onFinish={handleFieldSetupSubmit} ref={formRef}>
<Form.Item name="fields">
<DropDowns
label="Select fields"
// valueData={selectedFields}
onChangeFunction={handleFieldSelect}
options={tableFieldPreferences?.filter(p => !selectedFields?.some(s => s === p.value))} />
</Form.Item>
<div className="field-setup-selected-fields">
{selectedFields
?.map((id) => tableFieldPreferences?.find((p) => p.value === id))
.filter(Boolean)
.map((field) => (
<div className="selected-field" key={field.value}>
<div>{field.label}</div>
<div
className="close-icon"
onClick={() => handleFieldRemove(field.value)}
>
<IoClose size={15} />
</div>
</div>
))}
</div>
<div style={{ display: 'flex', justifyContent: 'flex-end' }}>
<Buttons
buttonText="SUBMIT"
color="901D77"
icon={<ArrowRightOutlined />}
htmlType={true}
/>
</div>
</Form>
</div>
</div>
}
/>
<div className="catalogueproductImg">
<DefaultModal
title="ONLINE IMAGE UPLOADER"
width={800}
open={imageopen}
footer={true}
buttonText="Submit"
children={
<Form className="">
<div className="productonlineImg">
{imagedata?.map((item, index) => (
<div
className={`singleimg ${selectedImage === item ? "selected" : ""
}`}
key={index}
onClick={() => setSelectedImage(item)}
>
<img src={item.image} alt="no image" style={{ height: "100%", width: "100%" }} />
</div>
))}
</div>
</Form>
}
handleSubmit={submitimage}
handleCancel={handleimage}
></DefaultModal>
</div>
<Modal
title="Map Your Fields"
open={MappingOpen}
// onOk={handleMappingConfirm}
onCancel={() => setMappingOpen(false)}
>
{requiredFields.map((field) => {
const usedHeaders = Object.entries(fieldMapping)
.filter(([key]) => key !== field)
.map(([, value]) => value);
const availableHeaders = headers?.filter(header => !usedHeaders?.includes(header));
return (
<div key={field} style={{ marginBottom: 10 }}>
<label>{field}</label>
<Select
allowClear
style={{ width: '100%' }}
placeholder="Select column"
value={fieldMapping[field] || undefined}
clearIcon={<CloseCircleOutlined style={{ color: 'red', fontSize: 20 }} />}
onChange={(value) => {
setFieldMapping((prev) => {
const updated = { ...prev };
if (!value) {
delete updated[field];
} else {
updated[field] = value;
}
return updated;
});
}}
>
{availableHeaders.map((header) => (
<Select.Option key={header} value={header}>
{header}
</Select.Option>
))}
</Select>
</div>
);
})}
</Modal>
</div>
);
};
export default ProductExcel;