From 452c030713f2ce3b8859bdfd576123c80d453c3e Mon Sep 17 00:00:00 2001 From: Tamilselvan Date: Fri, 27 Mar 2026 01:18:00 +0530 Subject: [PATCH 1/2] capacitor dwld options --- capacitor.config.json | 10 + package.json | 9 +- src/Pages/CommonMaster/ConfigExcelUpload.jsx | 48 +- src/Pages/Product/ExcelUpload.jsx | 7164 +++++++++-------- .../PurchaseOrder/PurchaseOrderBulkUpload.jsx | 21 +- src/Pages/Reports/MenuQRCode/MenuQRCode.jsx | 39 +- src/Pages/StockMaster/StockBulkUpload.jsx | 26 +- .../StockPriceUpdate/StockPriceUpdate.jsx | 348 +- src/Pages/openingStock/OpeningStockExcel.jsx | 26 +- src/utils/downloadFile.js | 62 + vite.config.js | 2 +- 11 files changed, 3958 insertions(+), 3797 deletions(-) create mode 100644 capacitor.config.json create mode 100644 src/utils/downloadFile.js diff --git a/capacitor.config.json b/capacitor.config.json new file mode 100644 index 0000000..2a7f3c4 --- /dev/null +++ b/capacitor.config.json @@ -0,0 +1,10 @@ +{ + "appId": "com.example.app", + "appName": "PozoApp", + "webDir": "dist", + "plugins": { + "StatusBar": { + "overlay": false + } + } +} \ No newline at end of file diff --git a/package.json b/package.json index b880d73..51320e1 100644 --- a/package.json +++ b/package.json @@ -12,10 +12,14 @@ }, "dependencies": { "@ant-design/plots": "^2.6.8", + "@capacitor-community/file-opener": "^8.0.0", "@capacitor-community/speech-recognition": "^7.0.1", "@capacitor-mlkit/barcode-scanning": "^8.0.1", + "@capacitor/android": "^8.3.0", "@capacitor/app": "^8.0.1", - "@capacitor/core": "^8.1.0", + "@capacitor/cli": "^8.3.0", + "@capacitor/core": "^8.3.0", + "@capacitor/filesystem": "^8.1.2", "@dnd-kit/core": "^6.3.1", "@dnd-kit/sortable": "^10.0.0", "@emotion/react": "^11.11.4", @@ -27,6 +31,7 @@ "@tanstack/react-query-devtools": "^5.91.1", "@tanstack/react-virtual": "^3.13.18", "@types/node": "^25.5.0", + "@vitejs/plugin-legacy": "^8.0.1", "@zxing/library": "^0.21.3", "antd": "^5.17.4", "antd-img-crop": "^4.22.0", @@ -92,7 +97,7 @@ "eslint-plugin-react-refresh": "^0.4.7", "prettier": "^3.5.3", "rollup-plugin-obfuscator": "^1.1.0", - "sass": "^1.77.2", + "sass": "^1.98.0", "terser": "^5.31.3", "vite": "^8.0.0", "vite-plugin-obfuscator": "^1.0.5", diff --git a/src/Pages/CommonMaster/ConfigExcelUpload.jsx b/src/Pages/CommonMaster/ConfigExcelUpload.jsx index fefcbd2..5c2a590 100644 --- a/src/Pages/CommonMaster/ConfigExcelUpload.jsx +++ b/src/Pages/CommonMaster/ConfigExcelUpload.jsx @@ -16,6 +16,7 @@ import { RadioGrpButton } from '../../Components/Forms/RadioGroup.jsx'; import { AiFillDelete } from 'react-icons/ai'; import upldimg from '../../Images/upldimg.png'; import { FiDelete, FiDownload } from 'react-icons/fi'; +import { downloadFile } from '../../utils/downloadFile.js'; const allowedExcelTypes = [ 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', // .xlsx 'application/vnd.ms-excel', // .xls @@ -328,10 +329,17 @@ const ConfigExcel = ({ handleSubmit, CategoryNames, SubCatData }) => { window.navigator.msSaveOrOpenBlob(blob, filename); } else { // For other browsers - const downloadLink = document.createElement('a'); - downloadLink.href = window.URL.createObjectURL(blob); - downloadLink.download = filename; - downloadLink.click(); + downloadFile( + buffer, + "CategoryDatas.xlsx", + "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", + (success) => { + if (!success) { + console.error("error occured while downloading") + } + } + ); + } } }; @@ -415,10 +423,17 @@ const ConfigExcel = ({ handleSubmit, CategoryNames, SubCatData }) => { window.navigator.msSaveOrOpenBlob(blob, filename); } else { // For other browsers - const downloadLink = document.createElement('a'); - downloadLink.href = window.URL.createObjectURL(blob); - downloadLink.download = filename; - downloadLink.click(); + + downloadFile( + buffer, + "SubcatagoryDatas.xlsx", + "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", + (success) => { + if (!success) { + console.error("Failed to download the file. Please try again.") + } + } + ); } } }; @@ -529,10 +544,17 @@ const ConfigExcel = ({ handleSubmit, CategoryNames, SubCatData }) => { window.navigator.msSaveOrOpenBlob(blob, filename); } else { // For other browsers - const downloadLink = document.createElement('a'); - downloadLink.href = window.URL.createObjectURL(blob); - downloadLink.download = filename; - downloadLink.click(); + downloadFile( + buffer, + "BrandDatas.xlsx", + "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", + (success) => { + if (!success) { + console.error("Failed to download the file. Please try again.") + + } + } + ); } } }; @@ -673,7 +695,7 @@ const ConfigExcel = ({ handleSubmit, CategoryNames, SubCatData }) => { ...record, ...values, }); - } catch (errInfo) {} + } catch (errInfo) { } }; let childNode = children; diff --git a/src/Pages/Product/ExcelUpload.jsx b/src/Pages/Product/ExcelUpload.jsx index 08040aa..bf78ecc 100644 --- a/src/Pages/Product/ExcelUpload.jsx +++ b/src/Pages/Product/ExcelUpload.jsx @@ -4,18 +4,18 @@ import { useDispatch, useSelector } from 'react-redux'; import ExcelJS from 'exceljs'; import { Table, Form, Input, Tooltip, Modal, Select } from 'antd'; import { - emptyExcelData, - excelDataSelector, - excelFileSelector, - excelFileErrorSelector, - fileInputRefSelector, - uploadExcel, + emptyExcelData, + excelDataSelector, + excelFileSelector, + excelFileErrorSelector, + fileInputRefSelector, + uploadExcel, } from '../../Features/ExcelUploadPage/ExcelUploadPage.js'; import { - getProductData, - onlineimages, - postFieldSetup, - getFieldSetupData, + getProductData, + onlineimages, + postFieldSetup, + getFieldSetupData, } from '../../Features/ProductPage/ProductPage.js'; import Imageupload from '../../Components/Forms/Upload.jsx'; import { BiSolidFileExport } from 'react-icons/bi'; @@ -32,9 +32,9 @@ import { getSession } from '../../Services/Others.js'; import { ArrowRightOutlined, CloseCircleOutlined } from '@ant-design/icons'; import stringSimilarity from 'string-similarity'; import { - getCommonAppPreference, - ApplicationPreferences, - getApplicationDetails, + getCommonAppPreference, + ApplicationPreferences, + getApplicationDetails, } from '../../Features/BrachLogin/BranchLogin.js'; import { MdOutlineAppRegistration } from 'react-icons/md'; import FormHeader from '../PageComponents/FormHeader.jsx'; @@ -43,517 +43,502 @@ 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'; +import { downloadFile } from '../../utils/downloadFile.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', + 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', + }, + ], }, - { - 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', + }, + ], }, - ], - }, - 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', + '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', + }, + ], }, - { - productName: 'Whole Wheat Bread', - quantity: 1, - uom: 'LOAF', - salesPrice: 35, - category: 'Breads', - subCategory: 'Wheat Breads', + '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', + }, + ], }, - ], - }, - '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', + 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', + }, + ], }, - { - productName: 'Extension Board 4 Socket', - quantity: 1, - uom: 'PCS', - salesPrice: 350, - category: 'Electrical Accessories', - subCategory: 'Power Strips', + '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', + }, + ], }, - ], - }, - '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', + 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', + }, + ], }, - { - productName: 'Wireless Earbuds', - quantity: 1, - uom: 'PAIR', - salesPrice: 1599, - category: 'Audio', - subCategory: 'Bluetooth Earphones', + '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', + }, + ], }, - ], - }, - 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', + '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', + }, + ], }, - { - productName: 'Refined Oil', - quantity: 1, - uom: 'LITER', - salesPrice: 110, - category: 'Cooking Oil', - subCategory: 'Sunflower Oil', + 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', + }, + ], }, - ], - }, - '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', + 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', + }, + ], }, - { - productName: 'Laundry Detergent', - quantity: 1, - uom: 'KG', - salesPrice: 85, - category: 'Household', - subCategory: 'Washing Powder', + 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', + }, + ], }, - ], - }, - 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', + 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', + }, + ], }, - { - productName: 'Diamond Pendant', - quantity: 1, - uom: 'PCS', - salesPrice: 15000, - category: 'Diamond Jewellery', - subCategory: 'Pendants', + 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', + }, + ], }, - ], - }, - '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', + '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', + }, + ], }, - { - 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: [], - } - ); + // 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 + '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, @@ -568,2833 +553,2871 @@ const ProductExcel = ({ 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'); +}) => { + 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 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 [OrginalData, setOrginalData] = useState([]); - const handleTableChange = (pagination, filters, sorter) => { - setCurrentPage(pagination.current); - }; + 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 [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: '', - }); - }); + 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 = ` + 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); + 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(() => { - 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 = async (e) => { - const buffer = e.target.result; - - const workbook = new ExcelJS.Workbook(); - await workbook.xlsx.load(buffer); - - const worksheet = workbook.worksheets[0]; - - // ๐Ÿ”ฅ convert to same format as xlsx (array of arrays) - const jsonData = []; - worksheet.eachRow((row) => { - const rowValues = row.values.slice(1); // remove first empty index - jsonData.push(rowValues); - }); - - const nonEmptyRows = jsonData.filter((row) => - row.some((cell) => cell !== '' && cell !== null && cell !== undefined) - ); - - const header = nonEmptyRows[0]; - const rows = nonEmptyRows.slice(1); - - const dateFields = [ - 'Available From', - 'Available To', - 'Manufacture Date', - 'Expire Date', - 'Stock Date', - ]; - - function convertToDisplayFormat(dateString) { - if (!dateString) return ''; - - const date = new Date(dateString); - if (isNaN(date)) return 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') - ); - - 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'], - ProdId: item['ProdId'] || null, - })); - - 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); - - setHeaders(extractedHeaders); - autoMapFields(extractedHeaders); - - dispatch(uploadExcel({ file, jsonData: nonEmptyRows })); - - setWorksheet(worksheet); - setDatas([]); - setExcelData([]); - } - - // โš ๏ธ keep your original flow (no break) - dispatch(uploadExcel({ file, jsonData: nonEmptyRows })); - setWorksheet(worksheet); - setWorksheet1(worksheet1); - setDatas(formattedData); - }; - - reader.readAsArrayBuffer(file); - }; - - // 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'], - // 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: [`Sheet2!$B$2:$B$${(CategoryNames?.length || 0) + 1}`], - }, - 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, // set dynamically per row below - 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, // set dynamically per row below - 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: null, // set via Sheet2 range reference below - sampleValue: sampleData?.tax || '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: 'OnePiecePrice', - 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: 'AutoGenOnePieceQr', - 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: 'AutoGenOnePieceQrNum', - 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', - width: 20, - style: { - ...headerStyle, - font: { bold: true, color: { argb: '#000000' } }, - numFmt: '@', - }, - validation: null, - sampleValue: '08:00:00', - headerColor: '52c41a', - isTimeField: true, - }, - AvailableTo: { - header: 'Available To', - key: 'AvailableTo', - width: 20, - style: { - ...headerStyle, - font: { bold: true, color: { argb: '#000000' } }, - numFmt: '@', - }, - validation: null, - sampleValue: '22:00:00', - headerColor: '52c41a', - isTimeField: true, - }, - }; - - 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 โ€” time fields forced to text format - selectedColumns.forEach((config, index) => { - const columnLetter = getExcelColumnLetter(index + 1); - const cell = worksheet.getCell(`${columnLetter}2`); - if (config.isTimeField) { - cell.numFmt = '@'; - cell.value = String(config.sampleValue); - } else { - cell.value = config.sampleValue; - } - }); - - // Force text format on all data rows for time fields - selectedColumns.forEach((config, index) => { - if (config.isTimeField) { - const columnLetter = getExcelColumnLetter(index + 1); - for (let r = 2; r <= 1002; r++) { - worksheet.getCell(`${columnLetter}${r}`).numFmt = '@'; - } - } - }); - - // 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; - } - } - }); - - // // 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 }; - // }); - // Add empty rows for data entry - for (let i = 1; i <= 1000; i++) { - worksheet.addRow({}); - } - - // Explicitly unlock all data-entry cells (rows 3+) for every column - for (let rowNum = 3; rowNum <= worksheet.rowCount; rowNum++) { - for (let colNum = 1; colNum <= selectedColumns.length; colNum++) { - const config = selectedColumns[colNum - 1]; - worksheet.getCell(rowNum, colNum).protection = { - locked: config?.locked || false, - }; - } - } - - // Lock header row (row 1) and sample row (row 2) - for (let colNum = 1; colNum <= selectedColumns.length; colNum++) { - worksheet.getCell(1, colNum).protection = { locked: true }; - worksheet.getCell(2, colNum).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], + return () => { + document.head.removeChild(style); }; - } - }); - } - - 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], - }; - } - }); - } - - // Write TaxDatas into Sheet2 column N for range-based dropdown (avoids 255-char limit) - if (typeof TaxDatas !== 'undefined' && TaxDatas?.length > 0) { - TaxDatas.forEach((taxItem, idx) => { - worksheet1.getCell(`N${idx + 2}`).value = taxItem - .replace(/,/g, '') - .trim(); - }); - } - - // Apply Tax validation using Sheet2 column N range - const taxColIndex = selectedColumns.findIndex((c) => c.key === 'TaxId') + 1; - if (taxColIndex > 0 && TaxDatas?.length > 0) { - for (let rowNumber = 3; rowNumber <= 1002; rowNumber++) { - worksheet.getCell(rowNumber, taxColIndex).dataValidation = { - type: 'list', - allowBlank: true, - formulae: [`Sheet2!$N$2:$N$${TaxDatas.length + 1}`], - showErrorMessage: false, - }; - } - } - - // โ”€โ”€ Dynamic SubCategory dropdown per Category โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ - // Build a map: categoryName โ†’ [subcat names] - const catSubcatMap = {}; - if (CategoryNames && SubCatData && Subcatnumfid) { - CategoryNames.forEach((catName, catIdx) => { - const catId = CategoryId?.[catIdx]; - const subcats = SubCatData.filter( - (_, sIdx) => Subcatnumfid[sIdx] == catId - ); - catSubcatMap[catName] = subcats; - }); - } - - // Write each category's subcats into Sheet2 starting at column O (col 15) - // Row 1 = category name header, rows 2+ = subcat names - const catSubcatStartCol = 15; // column O - const catNameToColLetter = {}; - - if (CategoryNames) { - CategoryNames.forEach((catName, catIdx) => { - const colIndex = catSubcatStartCol + catIdx; - const colLetter = getExcelColumnLetter(colIndex); - catNameToColLetter[catName] = colLetter; - - // Write header (category name) - worksheet1.getCell(`${colLetter}1`).value = catName; - - // Write subcats for this category - const subcats = catSubcatMap[catName] || []; - subcats.forEach((subcat, sIdx) => { - worksheet1.getCell(`${colLetter}${sIdx + 2}`).value = subcat; - }); - - // Define a named range for this category's subcats - const safeName = catName.replace(/[^A-Za-z0-9_]/g, '_'); - const rangeRef = - subcats.length > 0 - ? `Sheet2!$${colLetter}$2:$${colLetter}$${subcats.length + 1}` - : `Sheet2!$${colLetter}$2:$${colLetter}$2`; - - workbook.definedNames.add(rangeRef, safeName); - }); - } - - // Find which column index ProdCat and ProdSubCat are in Sheet1 - const catColIndex = - selectedColumns.findIndex((c) => c.key === 'ProdCat') + 1; - const subCatColIndex = - selectedColumns.findIndex((c) => c.key === 'ProdSubCat') + 1; - - if (catColIndex > 0 && subCatColIndex > 0) { - const catColLetter = getExcelColumnLetter(catColIndex); - - for (let rowNumber = 3; rowNumber <= 1002; rowNumber++) { - const cell = worksheet.getCell(rowNumber, subCatColIndex); - cell.dataValidation = { - type: 'list', - allowBlank: true, - formulae: [ - `INDIRECT(SUBSTITUTE(${catColLetter}${rowNumber}," ","_"))`, - ], - showErrorMessage: false, - }; - } - } - - // โ”€โ”€ Dynamic Brand dropdown per SubCategory โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ - // Build a map: subcatName โ†’ [brand names] using Allbranddatanumfid (parent subcat ID) - const subcatBrandMap = {}; - if (SubCatData && Allbranddata && Allbranddatanumfid) { - SubCatData.forEach((subcatName, sIdx) => { - const subcatId = SubcatId?.[sIdx]; - const brands = Allbranddata.filter( - (_, bIdx) => Allbranddatanumfid[bIdx] == subcatId - ); - subcatBrandMap[subcatName] = brands; - }); - } - - // Write each subcat's brands into Sheet2 starting after the category columns - const brandStartCol = catSubcatStartCol + (CategoryNames?.length || 0) + 1; - - if (SubCatData) { - SubCatData.forEach((subcatName, sIdx) => { - const colIndex = brandStartCol + sIdx; - const colLetter = getExcelColumnLetter(colIndex); - - worksheet1.getCell(`${colLetter}1`).value = `B_${subcatName}`; - - const brands = subcatBrandMap[subcatName] || []; - brands.forEach((brand, bIdx) => { - worksheet1.getCell(`${colLetter}${bIdx + 2}`).value = brand; - }); - - const safeName = `B_${subcatName.replace(/[^A-Za-z0-9_]/g, '_')}`; - const rangeRef = - brands.length > 0 - ? `Sheet2!$${colLetter}$2:$${colLetter}$${brands.length + 1}` - : `Sheet2!$${colLetter}$2:$${colLetter}$2`; - workbook.definedNames.add(rangeRef, safeName); - }); - } - - // Apply INDIRECT brand validation based on selected SubCategory - const brandColIndex = - selectedColumns.findIndex((c) => c.key === 'Brand') + 1; - if (subCatColIndex > 0 && brandColIndex > 0) { - const subCatColLetter = getExcelColumnLetter(subCatColIndex); - for (let rowNumber = 3; rowNumber <= 1002; rowNumber++) { - const cell = worksheet.getCell(rowNumber, brandColIndex); - cell.dataValidation = { - type: 'list', - allowBlank: true, - formulae: [ - `INDIRECT("B_"&SUBSTITUTE(${subCatColLetter}${rowNumber}," ","_"))`, - ], - showErrorMessage: false, - }; - } - } - // โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ - - // 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 ? ( - {record.Productimage} - ) : ( - <> -
- - updateImageUrl(url, index, record.key) - } - // 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} - /> - - - addOnlineImage(record, index)} - /> - -
- - )} - - ); - }, - }, - ]; - - 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 ( -
- - - -
- ); - }; - - const EditableCell = ({ - title, - editable, - children, - dataIndex, - record, - handleSave, - index, - ...restProps - }) => { - const [editing, setEditing] = useState(false); - const inputRef = useRef(null); - const form = useContext(EditableContext); + }, [excelData]); 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 ? ( - - - - ) : ( -
- {children} -
- ); - } - - return {childNode}; - }; - - 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, - isModified: true, - 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 { - ProdId: item.ProdId, - '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}%`, - 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 fetchData = async () => { + if (AppId) { + const response = await dispatch( + getApplicationDetails({ AppId }) + )?.unwrap(); + setAppName(response?.data?.data?.[0]?.AppName); + } }; - }); + fetchData(); + }, [AppId]); - const workbook = new ExcelJS.Workbook(); - const worksheet = workbook.addWorksheet('Products'); + useEffect(() => { + // Call handleSubmit when Datas is updated + if (Datas) { + handleSubmit(Datas); + } + }, [Datas, handleSubmit]); - worksheet.columns = Object.keys(formattedData[0]).map((key) => ({ - header: key, - key: key, - width: 20, - })); + // 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; - formattedData.forEach((row) => worksheet.addRow(row)); + // โœ… Process mandatory fields (retain value even if unmapped) + mandatoryFields.forEach((field) => { + const mappedHeader = fieldMapping[field]; - worksheet.eachRow((row, rowNumber) => { - row.eachCell((cell, colNumber) => { - cell.protection = { locked: colNumber === 1 }; - }); - }); + 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, '') + ); - await worksheet.protect('', { - selectLockedCells: true, - selectUnlockedCells: true, - }); - - const buffer = await workbook.xlsx.writeBuffer(); - const blob = new Blob([buffer], { - type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', - }); - const downloadLink = document.createElement('a'); - downloadLink.href = window.URL.createObjectURL(blob); - downloadLink.download = 'Product_Data.xlsx'; - downloadLink.click(); - - setLoading(false); - } else { - setLoading(false); - setMessage(true); - } - }; - - const handleExportBulkdata = async () => { - 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 { - ProdId: item.ProdId, - '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}%`, - 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, - }; - }); - - setOrginalData(formattedData); - } - }; - - 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 = column.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: ( -
-
- {col.title} - {!isMapped && ( - Not mapped - )} -
- -
- - {fieldMapping[col.dataIndex] && ( - { - 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, - }} - /> - )} -
-
- ), - render: (text, record, index) => { - const mappedField = fieldMapping[col.dataIndex]; + // โœ… 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(() => { + 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 ( - mappedField && - originalUploadedRawData?.[index]?.[mappedField] !== undefined + value === undefined || + value === null || + value === '' || + value === 'NaN-NaN-NaN' ) { - return originalUploadedRawData[index][mappedField]; + return ''; } - 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); - } - }, - }), + // 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 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 originalHashMap = new Map(); - const autoMapFields = (headers) => { - const updatedMapping = {}; - const cleanedHeaders = headers.map((h) => - h?.toLowerCase().replace(/\s+/g, '') - ); + for (const product of originalData) { + if (!product.ProdId) continue; + originalHashMap.set(product.ProdId, hashProduct(product)); + } - requiredFields.forEach((requiredField) => { - const cleanedField = requiredField?.toLowerCase(); + // Step 2: Compare updated products + const modifiedProducts = []; - // 1. Try exact match (cleaned) - const match = stringSimilarity.findBestMatch( - cleanedField, - cleanedHeaders - ); - const bestMatchIndex = match.bestMatchIndex; - const bestMatchScore = match.bestMatch.rating; + for (const product of updatedData) { + if (!product.ProdId) continue; - if (bestMatchScore > 0.6) { - updatedMapping[requiredField] = headers[bestMatchIndex]; - return; - } + const originalHash = originalHashMap.get(product.ProdId); + if (!originalHash) continue; // new product, not modified - // 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, '') - ) - ); + const updatedHash = hashProduct(product); - if (matchedHeader) { - updatedMapping[requiredField] = matchedHeader; - } + 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 = async (e) => { + const buffer = e.target.result; + + const workbook = new ExcelJS.Workbook(); + await workbook.xlsx.load(buffer); + + const worksheet = workbook.worksheets[0]; + + // ๐Ÿ”ฅ convert to same format as xlsx (array of arrays) + const jsonData = []; + worksheet.eachRow((row) => { + const rowValues = row.values.slice(1); // remove first empty index + jsonData.push(rowValues); + }); + + const nonEmptyRows = jsonData.filter((row) => + row.some((cell) => cell !== '' && cell !== null && cell !== undefined) + ); + + const header = nonEmptyRows[0]; + const rows = nonEmptyRows.slice(1); + + const dateFields = [ + 'Available From', + 'Available To', + 'Manufacture Date', + 'Expire Date', + 'Stock Date', + ]; + + function convertToDisplayFormat(dateString) { + if (!dateString) return ''; + + const date = new Date(dateString); + if (isNaN(date)) return 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') + ); + + 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'], + ProdId: item['ProdId'] || null, + })); + + 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); + + setHeaders(extractedHeaders); + autoMapFields(extractedHeaders); + + dispatch(uploadExcel({ file, jsonData: nonEmptyRows })); + + setWorksheet(worksheet); + setDatas([]); + setExcelData([]); + } + + // โš ๏ธ keep your original flow (no break) + dispatch(uploadExcel({ file, jsonData: nonEmptyRows })); + setWorksheet(worksheet); + setWorksheet1(worksheet1); + setDatas(formattedData); + }; + + reader.readAsArrayBuffer(file); + }; + + // 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'], + // 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: [`Sheet2!$B$2:$B$${(CategoryNames?.length || 0) + 1}`], + }, + 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, // set dynamically per row below + 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, // set dynamically per row below + 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: null, // set via Sheet2 range reference below + sampleValue: sampleData?.tax || '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: 'OnePiecePrice', + 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: 'AutoGenOnePieceQr', + 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: 'AutoGenOnePieceQrNum', + 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', + width: 20, + style: { + ...headerStyle, + font: { bold: true, color: { argb: '#000000' } }, + numFmt: '@', + }, + validation: null, + sampleValue: '08:00:00', + headerColor: '52c41a', + isTimeField: true, + }, + AvailableTo: { + header: 'Available To', + key: 'AvailableTo', + width: 20, + style: { + ...headerStyle, + font: { bold: true, color: { argb: '#000000' } }, + numFmt: '@', + }, + validation: null, + sampleValue: '22:00:00', + headerColor: '52c41a', + isTimeField: true, + }, + }; + + 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 โ€” time fields forced to text format + selectedColumns.forEach((config, index) => { + const columnLetter = getExcelColumnLetter(index + 1); + const cell = worksheet.getCell(`${columnLetter}2`); + if (config.isTimeField) { + cell.numFmt = '@'; + cell.value = String(config.sampleValue); + } else { + cell.value = config.sampleValue; + } + }); + + // Force text format on all data rows for time fields + selectedColumns.forEach((config, index) => { + if (config.isTimeField) { + const columnLetter = getExcelColumnLetter(index + 1); + for (let r = 2; r <= 1002; r++) { + worksheet.getCell(`${columnLetter}${r}`).numFmt = '@'; + } + } + }); + + // 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; + } + } + }); + + // // 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 }; + // }); + // Add empty rows for data entry + for (let i = 1; i <= 1000; i++) { + worksheet.addRow({}); + } + + // Explicitly unlock all data-entry cells (rows 3+) for every column + for (let rowNum = 3; rowNum <= worksheet.rowCount; rowNum++) { + for (let colNum = 1; colNum <= selectedColumns.length; colNum++) { + const config = selectedColumns[colNum - 1]; + worksheet.getCell(rowNum, colNum).protection = { + locked: config?.locked || false, + }; + } + } + + // Lock header row (row 1) and sample row (row 2) + for (let colNum = 1; colNum <= selectedColumns.length; colNum++) { + worksheet.getCell(1, colNum).protection = { locked: true }; + worksheet.getCell(2, colNum).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], + }; + } + }); + } + + // Write TaxDatas into Sheet2 column N for range-based dropdown (avoids 255-char limit) + if (typeof TaxDatas !== 'undefined' && TaxDatas?.length > 0) { + TaxDatas.forEach((taxItem, idx) => { + worksheet1.getCell(`N${idx + 2}`).value = taxItem + .replace(/,/g, '') + .trim(); + }); + } + + // Apply Tax validation using Sheet2 column N range + const taxColIndex = selectedColumns.findIndex((c) => c.key === 'TaxId') + 1; + if (taxColIndex > 0 && TaxDatas?.length > 0) { + for (let rowNumber = 3; rowNumber <= 1002; rowNumber++) { + worksheet.getCell(rowNumber, taxColIndex).dataValidation = { + type: 'list', + allowBlank: true, + formulae: [`Sheet2!$N$2:$N$${TaxDatas.length + 1}`], + showErrorMessage: false, + }; + } + } + + // โ”€โ”€ Dynamic SubCategory dropdown per Category โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ + // Build a map: categoryName โ†’ [subcat names] + const catSubcatMap = {}; + if (CategoryNames && SubCatData && Subcatnumfid) { + CategoryNames.forEach((catName, catIdx) => { + const catId = CategoryId?.[catIdx]; + const subcats = SubCatData.filter( + (_, sIdx) => Subcatnumfid[sIdx] == catId + ); + catSubcatMap[catName] = subcats; + }); + } + + // Write each category's subcats into Sheet2 starting at column O (col 15) + // Row 1 = category name header, rows 2+ = subcat names + const catSubcatStartCol = 15; // column O + const catNameToColLetter = {}; + + if (CategoryNames) { + CategoryNames.forEach((catName, catIdx) => { + const colIndex = catSubcatStartCol + catIdx; + const colLetter = getExcelColumnLetter(colIndex); + catNameToColLetter[catName] = colLetter; + + // Write header (category name) + worksheet1.getCell(`${colLetter}1`).value = catName; + + // Write subcats for this category + const subcats = catSubcatMap[catName] || []; + subcats.forEach((subcat, sIdx) => { + worksheet1.getCell(`${colLetter}${sIdx + 2}`).value = subcat; + }); + + // Define a named range for this category's subcats + const safeName = catName.replace(/[^A-Za-z0-9_]/g, '_'); + const rangeRef = + subcats.length > 0 + ? `Sheet2!$${colLetter}$2:$${colLetter}$${subcats.length + 1}` + : `Sheet2!$${colLetter}$2:$${colLetter}$2`; + + workbook.definedNames.add(rangeRef, safeName); + }); + } + + // Find which column index ProdCat and ProdSubCat are in Sheet1 + const catColIndex = + selectedColumns.findIndex((c) => c.key === 'ProdCat') + 1; + const subCatColIndex = + selectedColumns.findIndex((c) => c.key === 'ProdSubCat') + 1; + + if (catColIndex > 0 && subCatColIndex > 0) { + const catColLetter = getExcelColumnLetter(catColIndex); + + for (let rowNumber = 3; rowNumber <= 1002; rowNumber++) { + const cell = worksheet.getCell(rowNumber, subCatColIndex); + cell.dataValidation = { + type: 'list', + allowBlank: true, + formulae: [ + `INDIRECT(SUBSTITUTE(${catColLetter}${rowNumber}," ","_"))`, + ], + showErrorMessage: false, + }; + } + } + + // โ”€โ”€ Dynamic Brand dropdown per SubCategory โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ + // Build a map: subcatName โ†’ [brand names] using Allbranddatanumfid (parent subcat ID) + const subcatBrandMap = {}; + if (SubCatData && Allbranddata && Allbranddatanumfid) { + SubCatData.forEach((subcatName, sIdx) => { + const subcatId = SubcatId?.[sIdx]; + const brands = Allbranddata.filter( + (_, bIdx) => Allbranddatanumfid[bIdx] == subcatId + ); + subcatBrandMap[subcatName] = brands; + }); + } + + // Write each subcat's brands into Sheet2 starting after the category columns + const brandStartCol = catSubcatStartCol + (CategoryNames?.length || 0) + 1; + + if (SubCatData) { + SubCatData.forEach((subcatName, sIdx) => { + const colIndex = brandStartCol + sIdx; + const colLetter = getExcelColumnLetter(colIndex); + + worksheet1.getCell(`${colLetter}1`).value = `B_${subcatName}`; + + const brands = subcatBrandMap[subcatName] || []; + brands.forEach((brand, bIdx) => { + worksheet1.getCell(`${colLetter}${bIdx + 2}`).value = brand; + }); + + const safeName = `B_${subcatName.replace(/[^A-Za-z0-9_]/g, '_')}`; + const rangeRef = + brands.length > 0 + ? `Sheet2!$${colLetter}$2:$${colLetter}$${brands.length + 1}` + : `Sheet2!$${colLetter}$2:$${colLetter}$2`; + workbook.definedNames.add(rangeRef, safeName); + }); + } + + // Apply INDIRECT brand validation based on selected SubCategory + const brandColIndex = + selectedColumns.findIndex((c) => c.key === 'Brand') + 1; + if (subCatColIndex > 0 && brandColIndex > 0) { + const subCatColLetter = getExcelColumnLetter(subCatColIndex); + for (let rowNumber = 3; rowNumber <= 1002; rowNumber++) { + const cell = worksheet.getCell(rowNumber, brandColIndex); + cell.dataValidation = { + type: 'list', + allowBlank: true, + formulae: [ + `INDIRECT("B_"&SUBSTITUTE(${subCatColLetter}${rowNumber}," ","_"))`, + ], + showErrorMessage: false, + }; + } + } + // โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ + + // 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(); + // } + // } + + const buffer = await workbook.xlsx.writeBuffer(); + + downloadFile( + buffer, + "Product Data.xlsx", + "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", + (success) => { + if (success) { + console.log("File downloaded and opened successfully!"); + } else { + console.log("Failed to download/open file."); + } + } + ); + + }; + + // 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 ? ( + {record.Productimage} + ) : ( + <> +
+ + updateImageUrl(url, index, record.key) + } + // 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} + /> + + + addOnlineImage(record, index)} + /> + +
+ + )} + + ); + }, + }, + ]; + + 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), + }), + }; }); - setFieldMapping(updatedMapping); - }; + const EditableContext = React.createContext(null); - const COMPARE_FIELDS = [ - 'Product Name', - 'Quantity', - 'MRP', - 'Sales Price', - 'WholeSale Price', - 'Category', - 'Sub Category', - 'Brand', - 'Stock Available', - ]; + const EditableRow = ({ index, dataIndex, ...props }) => { + const [form] = Form.useForm(); + return ( +
+ + + +
+ ); + }; - return ( -
- { - setMessageData(null); - setMessageType(null); - }} - /> + const EditableCell = ({ + title, + editable, + children, + dataIndex, + record, + handleSave, + index, + ...restProps + }) => { + const [editing, setEditing] = useState(false); + const inputRef = useRef(null); + const form = useContext(EditableContext); -
-
-
-

- Upload Your Excel -

+ useEffect(() => { + if (editing) { + inputRef?.current?.focus(); + } + }, [editing]); -
- -
{ + 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 ? ( + - + + + ) : ( +
+ {children}
- -
handleExportData()} - > -
- + ); + } + + return {childNode}; + }; + + 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, + isModified: true, + 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 { + ProdId: item.ProdId, + '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}%`, + 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 workbook = new ExcelJS.Workbook(); + const worksheet = workbook.addWorksheet('Products'); + + worksheet.columns = Object.keys(formattedData[0]).map((key) => ({ + header: key, + key: key, + width: 20, + })); + + formattedData.forEach((row) => worksheet.addRow(row)); + + worksheet.eachRow((row, rowNumber) => { + row.eachCell((cell, colNumber) => { + cell.protection = { locked: colNumber === 1 }; + }); + }); + + await worksheet.protect('', { + selectLockedCells: true, + selectUnlockedCells: true, + }); + + // const buffer = await workbook.xlsx.writeBuffer(); + // const blob = new Blob([buffer], { + // type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', + // }); + // const downloadLink = document.createElement('a'); + // downloadLink.href = window.URL.createObjectURL(blob); + // downloadLink.download = 'Product_Data.xlsx'; + // downloadLink.click(); + const buffer = await workbook.xlsx.writeBuffer(); + + downloadFile( + buffer, + "Product_Data.xlsx", + "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet" + ); + setLoading(false); + } else { + setLoading(false); + setMessage(true); + } + }; + + const handleExportBulkdata = async () => { + 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 { + ProdId: item.ProdId, + '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}%`, + 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, + }; + }); + + setOrginalData(formattedData); + } + }; + + 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 = column.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: ( +
+
+ {col.title} + {!isMapped && ( + Not mapped + )} +
+ +
+ + + {fieldMapping[col.dataIndex] && ( + { + 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, + }} + /> + )} +
-
- Export Excel -
-
- {/* {excelData?.length > 0 && excelData && + ), + 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); + }; + + const COMPARE_FIELDS = [ + 'Product Name', + 'Quantity', + 'MRP', + 'Sales Price', + 'WholeSale Price', + 'Category', + 'Sub Category', + 'Brand', + 'Stock Available', + ]; + + return ( +
+ { + setMessageData(null); + setMessageType(null); + }} + /> + +
+ +
+

+ Upload Your Excel +

+ +
+ +
+ +
+
+
handleExportData()} + > +
+ +
+
+ Export Excel +
+
+ {/* {excelData?.length > 0 && excelData &&
setMappingOpen(true)}>
@@ -3404,307 +3427,306 @@ const ProductExcel = ({
} */} - {loading &&
Loading...
} - {message &&
No Data Found
} + {loading &&
Loading...
} + {message &&
No Data Found
} +
+ + {excelData?.length > 0 && excelData && ( +
+ + + +
+ )} +
+
0 ? 'space-between' : 'flex-end', + width: '100%', + }} + > + {excelData?.length > 0 && ( +
+
+

+ Modified +
+
+

+ Not Modified +
+
+ )} + + + + +
+ + {(!excelData || excelData?.length === 0) && ( + <> +
+
+ {/* */} + +
+
+ + )} + + {excelFileError && ( +
+ {excelFileError} +
+ )} +
- - {excelData?.length > 0 && excelData && ( -
- - - -
- )} -
-
0 ? 'space-between' : 'flex-end', - width: '100%', - }} - > - {excelData?.length > 0 && ( -
-
-

- Modified -
-
-

- Not Modified -
-
- )} - - - - -
- - {(!excelData || excelData?.length === 0) && ( - <> -
+ {excelData && excelData?.length > 0 ? ( + + record.isModified ? 'modified-row' : 'old-row' + } + >
+ ) : ( +

+ )} +
+
-
- {/* */} - -
-
- - )} - - {excelFileError && ( -
- {excelFileError} -
- )} - -
-
- {excelData && excelData?.length > 0 ? ( - - record.isModified ? 'modified-row' : 'old-row' - } - >
- ) : ( -

- )} -
-
- {/* + > + {/* */} - {excelData && excelData?.length > 0 && ( - - )} -
- setFieldSetup(false)} - footer={false} - children={ -
-
- + {excelData && excelData?.length > 0 && ( + + )}
-
-
- - !selectedFields?.some((s) => s === p.value) - )} - /> - -
- {selectedFields - ?.map((id) => - tableFieldPreferences?.find((p) => p.value === id) - ) - .filter(Boolean) - .map((field) => ( -
-
{field.label}
-
handleFieldRemove(field.value)} - > - + setFieldSetup(false)} + footer={false} + children={ +
+
+
-
- ))} -
-
- } - htmlType={true} - /> -
- -
-
- } - /> - -
- -
- {imagedata?.map((item, index) => ( -
setSelectedImage(item)} - > - no image -
- ))} -
- - } - handleSubmit={submitimage} - handleCancel={handleimage} - >
-
- - 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 ( -
- - + handleSubmit={submitimage} + handleCancel={handleimage} + >
- ); - })} -
-
- ); + + 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 ( +
+ + +
+ ); + })} +
+
+ ); }; export default ProductExcel; diff --git a/src/Pages/PurchaseOrder/PurchaseOrderBulkUpload.jsx b/src/Pages/PurchaseOrder/PurchaseOrderBulkUpload.jsx index 5767788..ee2700c 100644 --- a/src/Pages/PurchaseOrder/PurchaseOrderBulkUpload.jsx +++ b/src/Pages/PurchaseOrder/PurchaseOrderBulkUpload.jsx @@ -29,6 +29,7 @@ import { DefaultModal } from '../../Components/Modal/DefaultModal.jsx'; import Buttons from '../../Components/Forms/Buttons.jsx'; import { getPurchaseSupplierAndWareHouseData } from '../../Features/PurchaseOrder/PurchaseOrder.js'; import { Messages } from '../../Components/Notifications/Messages.jsx'; +import { downloadFile } from '../../utils/downloadFile.js'; // Constants const ALLOWED_EXCEL_TYPES = [ @@ -522,15 +523,19 @@ const PurchaseExcel = ({ handleSubmit }) => { // Step 7: Export file const buffer = await workbook.xlsx.writeBuffer(); - const blob = new Blob([buffer], { - type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', - }); - const filename = `PurchaseOrder_${supplierDisplayName}.xlsx`; - const link = document.createElement('a'); - link.href = URL.createObjectURL(blob); - link.download = filename; - link.click(); + + downloadFile( + buffer, + filename, + "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", + (success) => { + if (!success) { + setMessageType('error'); + setMessageData('Failed to download the file. Please try again.'); + } + } + ); setSupplierProducts([]); setSelectedSupplierData(null); diff --git a/src/Pages/Reports/MenuQRCode/MenuQRCode.jsx b/src/Pages/Reports/MenuQRCode/MenuQRCode.jsx index 1805311..83e49ef 100644 --- a/src/Pages/Reports/MenuQRCode/MenuQRCode.jsx +++ b/src/Pages/Reports/MenuQRCode/MenuQRCode.jsx @@ -19,6 +19,7 @@ import { import QRCodeLib from 'qrcode'; import { LuDownload } from 'react-icons/lu'; import { BsFileEarmarkPdf } from 'react-icons/bs'; +import { downloadFile } from '../../../utils/downloadFile'; const subDirectory = import.meta.env.ENV_MAIN_BASE_URL || '/'; @@ -312,7 +313,19 @@ const MenuQRCode = () => { if (openPreview) { setIsPreviewModalOpen(true); } else { - pdf.save('menu-qr.pdf'); + // pdf.save('menu-qr.pdf'); + const pdfBuffer = pdf.output('arraybuffer'); // โœ… arraybuffer for downloadFile + downloadFile( + pdfBuffer, + "menu-qr.pdf", + "application/pdf", + (success) => { + if (!success) { + setMessageType('error'); + setMessageData('Failed to download the PDF. Please try again.'); + } + } + ); } } catch (err) { console.error('PDF generation failed', err); @@ -323,17 +336,21 @@ const MenuQRCode = () => { const downloadPreviewPdf = () => { if (!pdfPreviewUrl) return; + fetch(pdfPreviewUrl) - .then((r) => r.blob()) - .then((blob) => { - const url = URL.createObjectURL(blob); - const a = document.createElement('a'); - a.href = url; - a.download = 'menu-qr.pdf'; - document.body.appendChild(a); - a.click(); - a.remove(); - URL.revokeObjectURL(url); + .then((r) => r.arrayBuffer()) // โœ… arrayBuffer instead of blob + .then((buffer) => { + downloadFile( + buffer, + "menu-qr.pdf", + "application/pdf", + (success) => { + if (!success) { + setMessageType('error'); + setMessageData('Failed to download the file. Please try again.'); + } + } + ); }); }; diff --git a/src/Pages/StockMaster/StockBulkUpload.jsx b/src/Pages/StockMaster/StockBulkUpload.jsx index cbb9629..bec8dfe 100644 --- a/src/Pages/StockMaster/StockBulkUpload.jsx +++ b/src/Pages/StockMaster/StockBulkUpload.jsx @@ -37,6 +37,7 @@ import { import { Messages } from '../../Components/Notifications/Messages.jsx'; import { getPurchaseSupplierAndWareHouseData } from '../../Features/PurchaseOrder/PurchaseOrder.js'; import { getSupplaierIdwithTypeBasedProducts } from '../../Features/SupplierProductMapping/SupplierProductMapping.js'; +import { downloadFile } from '../../utils/downloadFile.js'; const allowedExcelTypes = [ 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', // .xlsx @@ -478,8 +479,8 @@ const StockExcel = ({ : c.key === 'Quantity' ? 10 : c.key === 'Supplier' || - c.key === 'InvoiceDeliveryChallan' || - c.key === 'SupplierInvoiceNumber' + c.key === 'InvoiceDeliveryChallan' || + c.key === 'SupplierInvoiceNumber' ? 30 : 20, })); @@ -1007,14 +1008,19 @@ const StockExcel = ({ }); const buffer = await workbook.xlsx.writeBuffer(); - const blob = new Blob([buffer], { - type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', - }); const filename = `PurchaseEntry_${supplierDisplayName}_${Date.now()}.xlsx`; - const link = document.createElement('a'); - link.href = URL.createObjectURL(blob); - link.download = filename; - link.click(); + + downloadFile( + buffer, + filename, + "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", + (success) => { + if (!success) { + setMessageType('error'); + setMessageData('Failed to download the file. Please try again.'); + } + } + ); setSupplierProducts([]); setSelectedSupplierData(null); @@ -1332,7 +1338,7 @@ const StockExcel = ({ ...record, ...values, }); - } catch (errInfo) {} + } catch (errInfo) { } }; let childNode = children; diff --git a/src/Pages/StockPriceUpdate/StockPriceUpdate.jsx b/src/Pages/StockPriceUpdate/StockPriceUpdate.jsx index 1888fdd..82b6274 100644 --- a/src/Pages/StockPriceUpdate/StockPriceUpdate.jsx +++ b/src/Pages/StockPriceUpdate/StockPriceUpdate.jsx @@ -60,6 +60,7 @@ import { getCommonAppPreference, } from '../../Features/BrachLogin/BranchLogin.js'; import { IoClose } from 'react-icons/io5'; +import { downloadFile } from '../../utils/downloadFile.js'; const StockPriceUpdate = () => { const { SadminuserAccess } = useAuth(); @@ -179,53 +180,53 @@ const StockPriceUpdate = () => { }, ...(hasFieldExists('Stock') ? [ - { - title: 'Stock', - dataIndex: 'Stock', - key: 'Stock', - width: 80, - }, - ] + { + title: 'Stock', + dataIndex: 'Stock', + key: 'Stock', + width: 80, + }, + ] : []), ...(hasFieldExists('Stock Date') ? [ - { - title: 'Stock Date', - dataIndex: 'StockDate', - key: 'StockDate', - width: 80, - }, - ] + { + title: 'Stock Date', + dataIndex: 'StockDate', + key: 'StockDate', + width: 80, + }, + ] : []), ...(hasFieldExists('Old MRP') ? [ - { - title: 'Old MRP', - dataIndex: 'OldMRP', - key: 'OldMRP', - width: 100, - }, - ] + { + title: 'Old MRP', + dataIndex: 'OldMRP', + key: 'OldMRP', + width: 100, + }, + ] : []), ...(hasFieldExists('Old SP') ? [ - { - title: 'Old SP', - dataIndex: 'OldSP', - key: 'OldSP', - width: 100, - }, - ] + { + title: 'Old SP', + dataIndex: 'OldSP', + key: 'OldSP', + width: 100, + }, + ] : []), ...(hasFieldExists('Old Wholesale Price') ? [ - { - title: 'Old Wholesale Price', - dataIndex: 'OldWholeSalePrice', - key: 'OldWholeSalePrice', - width: 140, - }, - ] + { + title: 'Old Wholesale Price', + dataIndex: 'OldWholeSalePrice', + key: 'OldWholeSalePrice', + width: 140, + }, + ] : []), // โœ… EDITABLE @@ -322,7 +323,7 @@ const StockPriceUpdate = () => { ); excelDataRef.current ?.validateFields([`NewSellPrice${record.localId}`]) - .catch(() => {}); + .catch(() => { }); } }} /> @@ -331,40 +332,40 @@ const StockPriceUpdate = () => { }, ...(hasFieldExists('New Wholesale Price') ? [ - { - title: 'New Wholesale Price', - dataIndex: 'NewWholeSalePrice', - key: 'NewWholeSalePrice', - width: 160, - render: (value, record, index) => ( - - - handlePriceChange( - index, - 'NewWholeSalePrice', - e.target.value, - record.localId - ) + { + title: 'New Wholesale Price', + dataIndex: 'NewWholeSalePrice', + key: 'NewWholeSalePrice', + width: 160, + render: (value, record, index) => ( + + + handlePriceChange( + index, + 'NewWholeSalePrice', + e.target.value, + record.localId + ) + } + placeholder="New Wholesale" + inputMode="decimal" + onInput={(e) => { + let cleanedValue = e.target.value.replace(/[^0-9.]/g, ''); + const parts = cleanedValue.split('.'); + if (cleanedValue.startsWith('.')) { + cleanedValue = '0' + cleanedValue; } - placeholder="New Wholesale" - inputMode="decimal" - onInput={(e) => { - let cleanedValue = e.target.value.replace(/[^0-9.]/g, ''); - const parts = cleanedValue.split('.'); - if (cleanedValue.startsWith('.')) { - cleanedValue = '0' + cleanedValue; - } - e.target.value = - parts.length > 2 - ? `${parts[0]}.${parts.slice(1).join('')}` - : cleanedValue; - }} - /> - - ), - }, - ] + e.target.value = + parts.length > 2 + ? `${parts[0]}.${parts.slice(1).join('')}` + : cleanedValue; + }} + /> + + ), + }, + ] : []), { title: 'Action', @@ -1092,79 +1093,79 @@ const StockPriceUpdate = () => { }, ...(hasField('Stock Date') ? [ - { - title: 'stock Date', - dataIndex: 'InwardDate', - key: 'InwardDate', - align: 'center', - width: 120, - render: (InwardDate) => - InwardDate !== null ? ExtractDateFormate(InwardDate) : '-', - }, - ] + { + title: 'stock Date', + dataIndex: 'InwardDate', + key: 'InwardDate', + align: 'center', + width: 120, + render: (InwardDate) => + InwardDate !== null ? ExtractDateFormate(InwardDate) : '-', + }, + ] : []), ...(hasField('Expiry Date') ? [ - { - title: 'Exp date', - dataIndex: 'ExpDate', - key: 'ExpDate', - align: 'center', - width: 100, - render: (ExpDate) => - ExpDate !== null ? ExtractDateFormate(ExpDate) : '-', - }, - ] + { + title: 'Exp date', + dataIndex: 'ExpDate', + key: 'ExpDate', + align: 'center', + width: 100, + render: (ExpDate) => + ExpDate !== null ? ExtractDateFormate(ExpDate) : '-', + }, + ] : []), ...(hasField('Stock') ? [ - { - title: 'stock', - dataIndex: 'BalanceQty', - key: 'BalanceQty', - align: 'right', - width: '60px', - render: (BalanceQty) => (BalanceQty !== null ? BalanceQty : '-'), - }, - ] + { + title: 'stock', + dataIndex: 'BalanceQty', + key: 'BalanceQty', + align: 'right', + width: '60px', + render: (BalanceQty) => (BalanceQty !== null ? BalanceQty : '-'), + }, + ] : []), ...(hasField('Old MRP') ? [ - { - title: 'Old MRP', - dataIndex: 'MRP', - key: 'MRP', - align: 'right', - width: '70px', - render: (MRP) => (safeRound(MRP) !== null ? safeRound(MRP) : '-'), - }, - ] + { + title: 'Old MRP', + dataIndex: 'MRP', + key: 'MRP', + align: 'right', + width: '70px', + render: (MRP) => (safeRound(MRP) !== null ? safeRound(MRP) : '-'), + }, + ] : []), ...(hasField('Old SP') ? [ - { - title: 'Old SP', - dataIndex: 'SellPrice', - key: 'SellPrice', - align: 'right', - width: '70px', - render: (SellPrice) => - safeRound(SellPrice) !== null ? safeRound(SellPrice) : '-', - }, - ] + { + title: 'Old SP', + dataIndex: 'SellPrice', + key: 'SellPrice', + align: 'right', + width: '70px', + render: (SellPrice) => + safeRound(SellPrice) !== null ? safeRound(SellPrice) : '-', + }, + ] : []), ...(hasField('Old Wholesale Price') ? [ - { - title: 'Old Wholesale Price', - dataIndex: 'WhSalePrice', - key: 'WhSalePrice', - align: 'right', - width: '120px', - render: (WhSalePrice) => - safeRound(WhSalePrice) !== null ? safeRound(WhSalePrice) : '-', - }, - ] + { + title: 'Old Wholesale Price', + dataIndex: 'WhSalePrice', + key: 'WhSalePrice', + align: 'right', + width: '120px', + render: (WhSalePrice) => + safeRound(WhSalePrice) !== null ? safeRound(WhSalePrice) : '-', + }, + ] : []), { title: 'New MRP', @@ -1188,19 +1189,19 @@ const StockPriceUpdate = () => { }, ...(hasField('New Wholesale Price') ? [ - { - title: 'New Wholesale Price', - dataIndex: 'CurrentWhAmt', - key: 'CurrentWhAmt', - align: 'center', - with: '4rem', - editable: true, - render: (text, record) => ( -

{text ? text : 'Enter Wholesale Price'}

- ), - width: 120, - }, - ] + { + title: 'New Wholesale Price', + dataIndex: 'CurrentWhAmt', + key: 'CurrentWhAmt', + align: 'center', + with: '4rem', + editable: true, + render: (text, record) => ( +

{text ? text : 'Enter Wholesale Price'}

+ ), + width: 120, + }, + ] : []), ]; @@ -1481,9 +1482,9 @@ const StockPriceUpdate = () => { isStockVariantBased === 'Yes' ? BulkProductData || [] : (BulkProductData || [])?.filter( - (item, index, self) => - index === self.findIndex((p) => p.ProdId === item.ProdId) - ); + (item, index, self) => + index === self.findIndex((p) => p.ProdId === item.ProdId) + ); if (!uniqueBulkProductData?.length) { setMessageType('error'); @@ -1596,9 +1597,9 @@ const StockPriceUpdate = () => { cell.border = isHiddenCol ? undefined : { - right: { style: 'thin', color: { argb: 'FF000000' } }, - bottom: { style: 'thin', color: { argb: 'FF000000' } }, - }; + right: { style: 'thin', color: { argb: 'FF000000' } }, + bottom: { style: 'thin', color: { argb: 'FF000000' } }, + }; }); /* ---------------- ADD DATA ---------------- */ @@ -1713,14 +1714,19 @@ const StockPriceUpdate = () => { /* ---------------- DOWNLOAD ---------------- */ const buffer = await workbook.xlsx.writeBuffer(); - const blob = new Blob([buffer], { - type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', - }); - - const link = document.createElement('a'); - link.href = URL.createObjectURL(blob); - link.download = 'PriceChange_Data.xlsx'; - link.click(); + downloadFile( + buffer, + "PriceChange_Data.xlsx", + "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", + (success) => { + if (success) { + console.log("Template downloaded successfully!"); + } else { + setMessageType('error'); + setMessageData('Failed to download the template. Please try again.'); + } + } + ) setExportLoading(false); }; @@ -1780,7 +1786,7 @@ const StockPriceUpdate = () => { Number(current.MRP) !== Number(uploaded.NewMRP) || Number(current.SellPrice) !== Number(uploaded.NewSellPrice) || Number(current.WhSalePrice || 0) !== - Number(uploaded.NewWholeSalePrice || 0); + Number(uploaded.NewWholeSalePrice || 0); return { ...uploaded, @@ -2297,17 +2303,17 @@ const StockPriceUpdate = () => {
{(RadioSelection == 'Bulk' || (RadioSelection == 'Single' && StockDetails.length > 0)) && ( -
- } - disabled={addnewAccess} - > -
- )} +
+ } + disabled={addnewAccess} + > +
+ )}
{RadioSelection == 'Single' && ( @@ -2325,10 +2331,10 @@ const StockPriceUpdate = () => { StockDetails?.length < 11 ? false : { - current: page, - pageSize: pageSize, - onChange: handlePageChange, - } + current: page, + pageSize: pageSize, + onChange: handlePageChange, + } } onChange={handleChange} > @@ -2395,7 +2401,7 @@ const StockPriceUpdate = () => {
{} : () => showPriceChangeModal() + exportLoading ? () => { } : () => showPriceChangeModal() } >
diff --git a/src/Pages/openingStock/OpeningStockExcel.jsx b/src/Pages/openingStock/OpeningStockExcel.jsx index b8c5e5b..d680b7a 100644 --- a/src/Pages/openingStock/OpeningStockExcel.jsx +++ b/src/Pages/openingStock/OpeningStockExcel.jsx @@ -7,6 +7,7 @@ import { RiFileExcel2Fill } from 'react-icons/ri'; import { Messages } from '../../Components/Notifications/Messages.jsx'; import { getSession } from '../../Services/Others.js'; import './OpeningStockExcel.scss'; +import { downloadFile } from '../../utils/downloadFile.js'; const TEMPLATE_HEADERS = [ { key: 'ProdName', header: 'Product Name' }, @@ -203,15 +204,20 @@ const OpeningStockExcel = ({ products = [], onApply, onCancel }) => { } const buffer = await workbook.xlsx.writeBuffer(); - const blob = new Blob([buffer], { - type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', - }); - const link = document.createElement('a'); - link.href = URL.createObjectURL(blob); - link.download = 'opening_stock_template.xlsx'; - link.click(); - URL.revokeObjectURL(link.href); + downloadFile( + buffer, + "opening_stock_template.xlsx", + "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", + (success) => { + if (success) { + console.log("Template downloaded successfully!"); + } else { + setMessageType('error'); + setMessageData('Failed to download the template. Please try again.'); + } + } + ) } catch (error) { console.error('Template download failed:', error); setMessageType('error'); @@ -562,8 +568,8 @@ const OpeningStockExcel = ({ products = [], onApply, onCancel }) => { : '', TotalPcs: row.OnePcsAvailable === 'Y' && - row.TotalPiece !== undefined && - row.TotalPiece !== null + row.TotalPiece !== undefined && + row.TotalPiece !== null ? row.TotalPiece.toString() : 0, InwardDetails: [], diff --git a/src/utils/downloadFile.js b/src/utils/downloadFile.js new file mode 100644 index 0000000..96acce5 --- /dev/null +++ b/src/utils/downloadFile.js @@ -0,0 +1,62 @@ +import { Capacitor } from "@capacitor/core"; +import { Filesystem, Directory } from "@capacitor/filesystem"; +import { FileOpener } from "@capacitor-community/file-opener"; + +/** + * Download and open a file (Excel, PDF, etc.) + * @param {ArrayBuffer | Blob} buffer - File data + * @param {string} filename - File name with extension + * @param {string} mimeType - File MIME type (example: application/vnd.openxmlformats-officedocument.spreadsheetml.sheet) + * @param {Function} onSuccess - Optional callback, called with true/false + */ +export const downloadFile = async (buffer, filename, mimeType, onSuccess) => { + try { + const isWeb = Capacitor.getPlatform() === "web"; + + // ๐ŸŒ Web download + if (isWeb) { + const blob = buffer instanceof Blob ? buffer : new Blob([buffer], { type: mimeType }); + + const link = document.createElement("a"); + link.href = URL.createObjectURL(blob); + link.download = filename; + link.click(); + + URL.revokeObjectURL(link.href); + onSuccess?.(true); + return; + } + + // ๐Ÿ“ฑ Mobile (Android / iOS) + + // Convert ArrayBuffer โ†’ Base64 + let binary = ""; + const bytes = new Uint8Array(buffer); + for (let i = 0; i < bytes.length; i++) { + binary += String.fromCharCode(bytes[i]); + } + const base64Data = btoa(binary); + + // Save file inside app's Documents folder + + const savedFile = await Filesystem.writeFile({ + path: filename, + data: base64Data, + directory: Directory.Data, // โ† was Directory.Documents + recursive: true, + }); + + // FileOpener requires removing "file://" + + await FileOpener.open({ + filePath: savedFile.uri, // โ† was savedFile.uri.replace("file://", "") + contentType: mimeType, + }); + + onSuccess?.(true); + + } catch (err) { + console.error("File download/open error:", err); + onSuccess?.(false); + } +}; \ No newline at end of file diff --git a/vite.config.js b/vite.config.js index 245c478..8552f81 100644 --- a/vite.config.js +++ b/vite.config.js @@ -7,7 +7,7 @@ export default defineConfig(({ mode }) => { return { plugins: [react()], - base: isProd ? "/apps/retail/" : "/", + base: isProd ? "/apps/retail/" : "/", //for capcitor base: isProd ? "/" : "/", envDir: "src", envPrefix: "ENV_", From 5640d36ca78a1a698bc470f4fe9bf7f516562474 Mon Sep 17 00:00:00 2001 From: TamilSelvan Date: Fri, 27 Mar 2026 15:05:13 +0530 Subject: [PATCH 2/2] Add README.md --- README.md | 2556 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 2556 insertions(+) create mode 100644 README.md diff --git a/README.md b/README.md new file mode 100644 index 0000000..a1f2377 --- /dev/null +++ b/README.md @@ -0,0 +1,2556 @@ +# POZO Retail Web to Andriod by using capcitor package + +A short description of what the project does. + +--- + +## ๐Ÿ“ฆ Prerequisites + +Make sure you have the following installed: + +- Node.js (v20+ recommended) +- npm or yarn + +--- + +## ๐Ÿ”ง Required Changes Before Running the App + +Before running the application, make the following updates: + +### 1๏ธโƒฃ Update Vite Config +Open the file: + + +// this is ProtecedRoute.jsx make sure need to cmd or add some thng like this before changing react to capcitor +import { useEffect, useState } from 'react'; +import { Routes, Route, useNavigate } from 'react-router-dom'; +import { useDispatch } from 'react-redux'; +import { + getEmpAccesData, + GenerateLogout, + getSAdminUserAccesData, + PricingAppPricingName, + checkSession, + getCompBranchData, + getCommonAppPreference, + changeWarehouse, +} from './Features/BrachLogin/BranchLogin.js'; +import { clearSession, getSession, sessionStore } from './Services/Others'; +import { + FeatureAddon, + GlobalFeatAddOnData, +} from './Features/BookingScreen/BookingData/BookingData.js'; +import { Suspense } from 'react'; +import { gettableData } from './Features/PreferenceMaster/PreferenceMaster.js'; +import { useSelector } from 'react-redux'; +import { useTemplate } from './utils/useTemplate.js'; + +const commonUrl = import.meta.env.ENV_COMMON_BASE_URL; +const subDirectory = import.meta.env.BASE_URL; + +const ProtectedRoutes = ({ routesConfig }) => { + // useTemplate( + // getSession('CompId'), + // getSession('BranchId'), + // getSession('AppId') + // ); + sessionStore('AppId', 2); + sessionStore('BranchId', 791); + sessionStore('AppName', 'Bakery'); + sessionStore('CompId', 657); + sessionStore('MobileNo', '8888888888'); + sessionStore('UserType', 'Admin'); + sessionStore('UserId', 286); + sessionStore('userName', 'Karthiga'); + + sessionStore( + 'auth','eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJodHRwOi8vc2NoZW1hcy54bWxzb2FwLm9yZy93cy8yMDA1LzA1L2lkZW50aXR5L2NsYWltcy9uYW1lIjoiODg4ODg4ODg4OCIsIlBhc3N3b3JkIjoiWkB6MTIzNCIsImF1ZCI6WyJodHRwczovL2FwaS5wb3pvLmRldi9wb3pvLXJldGFpbC1hcGkiLCJodHRwczovL2FwaS5wb3pvLmRldi9wb3pvLWNvbW1vbi1hcGkiLCJodHRwczovL2FwaS5wb3pvLmRldi9wb3pvLXNtcy1lbWFpbC10ZW1wbGF0ZS1hcGkiLCJodHRwczovL2FwaS5wb3pvLmRldi9wb3pvLWNvbW1vbi1hcGkiXSwiZXhwIjoxNzc0NjM3OTA5LCJpc3MiOiJodHRwczovL2FwaS5wb3pvLmRldi9Kd3RUb2tlbiJ9.TWDS0cuHGIDW_16EH2RS4z2B-wnuuPmMNd_lre505qY' + ); + const navigate = useNavigate(); + const dispatch = useDispatch(); + const UserType = getSession('UserType'); + const [hasRedirected, setHasRedirected] = useState(false); + const AppId = getSession('AppId'); + const CompId = getSession('CompId'); + const BranchId = getSession('BranchId'); + const UserId = getSession('UserId'); + const sessionId = getSession('SessionId'); + const Warehouse = getSession('Warehouse'); + const [accessCheckComplete, setAccessCheckComplete] = useState(false); + const FeatureAddonData = useSelector(GlobalFeatAddOnData); + useTemplate(657, 791, 2); + + useEffect(() => { + getApplicationPreference(); + }, []); + //sri + // useEffect(() => { + // if (Warehouse) { + // dispatch(changeWarehouse(true)); + // } + // }, [Warehouse]); + const getApplicationPreference = async () => { + await dispatch(getCommonAppPreference(AppId)).unwrap(); + }; + + const getEmpAccess = async () => { + let data = { + UserId: UserId, + AppId: AppId, + CompId: CompId, + BranchId: BranchId, + }; + + const response = await dispatch(getEmpAccesData(data)).unwrap(); + if (response?.data?.statusCode === 1) { + return response?.data?.data?.[0]?.EmpAccessDetails; + } + return null; + }; + + const getSadminUserAccess = async () => { + let data = { + UserId: UserId, + AppId: AppId, + }; + const response = await dispatch(getSAdminUserAccesData(data)).unwrap(); + if (response?.data?.statusCode === 1) { + return response?.data?.data?.[0]?.AppMenuAccessDetails; + } + return null; + }; + + const Dinein = async () => { + if (AppId && CompId && BranchId) { + let DineinData = { + AppId: AppId, + CompId: CompId, + BranchId: BranchId, + UserId: UserId, + }; + const response = await dispatch(gettableData(DineinData)).unwrap(); + if (response?.data?.statusCode === 1) { + const SettingValueData = response?.data?.data + ?.find((e) => e.AppId === AppId) + ?.SettingDtlDetails?.some( + (e) => e.SettingIdName === 'DineIn' && e.SettingValue === 'Y' + ); + const EstimateValueData = response?.data?.data + ?.find((e) => e.AppId === AppId) + ?.SettingDtlDetails?.some( + (e) => e.SettingIdName === 'Estimation' && e.SettingValue === 'Y' + ); + return (SettingValueData, EstimateValueData); + } + } + }; + + const checkAccess = async (empAccess) => { + if (!empAccess) return false; + let DineinData, + EstimateData = await Dinein(); + switch (empAccess) { + case 'Dine In': + case 'KOT': + return !!DineinData; + case 'Estimate': + return !!EstimateData; + default: + return false; // Restrict access if no valid match found + } + }; + + const getPricingName = async () => { + if (!AppId || !UserId) return; + const data = { + appId: AppId, + userId: UserId, + }; + try { + const response = await dispatch(PricingAppPricingName(data)).unwrap(); + const responseData = response?.data; + const pricingData = responseData?.data; + const hasAdvance = pricingData?.some( + (item) => item.PricingName === 'Premium' + ); + const hasProOrAdvance = + hasAdvance || + pricingData.some((item) => item.PricingName === 'Customized'); + return (hasAdvance, hasProOrAdvance); + } catch (error) { + console.error('Error fetching pricing name:', error); + } + }; + + const checkPlanAccess = async (empAccess, featureAddonData) => { + if (!empAccess) return false; + let Advance, + ProORAdvance = await getPricingName(); + switch (empAccess) { + case 'Product Catalogue': + return ( + ProORAdvance || + featureAddonData?.some( + (item) => item?.FeatureAddonName?.toLowerCase() === 'catalog' + ) + ); + case 'Sales Setup': + case 'Print Setup': + return ( + Advance || + featureAddonData?.some( + (item) => + item?.FeatureAddonName?.toLowerCase() === 'customized template' + ) + ); + case 'Kiosk Setup': + case 'Kiosk Sales': + return featureAddonData?.some( + (item) => item?.FeatureAddonName?.toLowerCase() === 'kiosk sales' + ); + default: + return false; // Restrict access if no valid match found + } + }; + + const checkEmpAccess = async (empAccess, currentPath) => { + if (!empAccess) return false; + const Access = await getEmpAccess(); + let accessType; + if (currentPath.endsWith('/new')) { + accessType = 'AddAccess'; + } else if (currentPath.endsWith('/update')) { + accessType = 'UpdateAccess'; + } else { + accessType = 'ReadAccess'; + } + // const config = Access?.find(config => + // config.ConfigName === empAccess && config[accessType] === 'Y' + // ); + const config = Access?.find( + (config) => + (config.ConfigName === empAccess && config[accessType] === 'Y') || + (currentPath.includes('supplier-master') && + (config.ConfigName === 'Supplier' || + config.ConfigName === 'Seller') && + config[accessType] === 'Y') + ); + + return !!config; + }; + + const checkSuperAdminUserAccess = async (empAccess, currentPath) => { + console.log('empAccessData1', empAccess, currentPath); + if (!empAccess) return false; + const Access = await getSadminUserAccess(); + let accessType; + if (currentPath.endsWith('/new')) { + accessType = 'AddAccess'; + } else if (currentPath.endsWith('/update')) { + accessType = 'UpdateAccess'; + } else { + accessType = 'ReadAccess'; + } + console.log('empAccessData2', Access, accessType); + // const config = Access?.find(config => + // config.MenuName === empAccess && config[accessType] === 'Y' + // ); + const config = Access?.find( + (config) => + (config.MenuName === empAccess && config[accessType] === 'Y') || + (currentPath.includes('supplier-master') && + (config.MenuName === 'Supplier' || config.MenuName === 'Seller') && + config[accessType] === 'Y') + ); + console.log('empAccessData3', config); + + return !!config; + }; + + const getEmpAccessFromChildren = (route, currentPath) => { + if (route.path === currentPath) { + return route.empAccess || null; + } + + if (route.children) { + for (const child of route.children) { + const childPath = `${route.path}/${child.path}`; + if (childPath === currentPath) { + return child.empAccess || null; + } + } + } + + return null; + }; + + const getEmpAccessDataFromChildren = (route, currentPath) => { + if (route.path === currentPath) { + return route.access || null; + } + if (route.children) { + for (const child of route.children) { + const childPath = `${route.path}/${child.path}`; + if (childPath === currentPath) { + return child.access || null; + } + } + } + return null; + }; + + const fetchBranchData = async () => { + const response = await dispatch( + getCompBranchData({ CompId: CompId, AppId: AppId }) + ).unwrap(); + if (response?.data?.statusCode === 1) { + if (response?.data?.data?.length == 1) { + navigate(`${subDirectory}`); + } else { + navigate(`${subDirectory}app-page/branch-login`); + } + } + }; + + + const Logout = async () => { + const status = 'N'; // replace with your actual status + const res = await dispatch(GenerateLogout({ UserId, status })).unwrap(); + if (res?.data?.statusCode === 1) { + sessionStorage.clear(); + window.location.replace(`${commonUrl}`); + } + }; + + const renderRoutes = (routes) => { + return routes.map(({ path, component: Component, children }) => { + const fullPath = `${path}`; + + if (!Component) { + console.error(`Component not found for path: ${fullPath}`); + return null; + } + + if (children) { + return ( + }> + {children.map(({ path: childPath, component: ChildComponent }) => { + if (!ChildComponent) { + console.error( + `Child component not found for path: ${childPath}` + ); + return null; + } + return ( + } + /> + ); + })} + + ); + } + + return } />; + }); + }; + + return ( +
}> + {renderRoutes(routesConfig)} + + ); +}; + +export default ProtectedRoutes; +/// Routes config +import React from 'react'; +import { lazy } from 'react'; +const CommonMaster = lazy( + () => import('./Pages/CommonMaster/CommonMaster.jsx') +); +const ConfigType = lazy(() => import('./Pages/ConfigType/ConfigTypeForm.jsx')); +const AdminTax = lazy(() => import('./Pages/AdminTax/AdminTaxForm.jsx')); +const ProductForm = lazy(() => import('./Pages/Product/ProductForm.jsx')); +const Sport_ProductForm = lazy( + () => import('./Pages/Product/SportsMaster.jsx') +); +const ShiftMasterList = lazy( + () => import('./Pages/ShiftMaster/ShiftMasterList.jsx') +); +const ShiftMasterForm = lazy( + () => import('./Pages/ShiftMaster/ShiftMasterForm.jsx') +); +const EmployeeMasterList = lazy( + () => import('./Pages/EmpMaster/EmpMasterList.jsx') +); +const EmployeeMasterForm = lazy( + () => import('./Pages/EmpMaster/EmpMasterForm.jsx') +); + +const SupplierMasterList = lazy( + () => import('./Pages/SupplierMaster/SupplierMasterList.jsx') +); +const SupplierMasterForm = lazy( + () => import('./Pages/SupplierMaster/SupplierMasterForm.jsx') +); + +const ComponentMasterForm = lazy( + () => import('./Pages/UiComponentPage/ComponentForm.jsx') +); +const ComponentMasterList = lazy( + () => import('./Pages/UiComponentPage/ComponentList.jsx') +); + +const CustomerForm = lazy( + () => import('./Pages/CustomerMaster/CustMasterForm.jsx') +); +const CustomerMasterList = lazy( + () => import('./Pages/CustomerMaster/CustMasterList.jsx') +); + +const DateWiseReport = lazy( + () => import('./Pages/Reports/DateWiseReport/DateWiseReport.jsx') +); + +const ItemWiseReport = lazy( + () => import('./Pages/Reports/ItemWiseReport/ItemWiseReport.jsx') +); + +const Reprint = lazy( + () => + import('./Pages/BookingScreen/Components/OtherConponents/Reprint/BSReprint.jsx') +); + +const BookingSelectionPage = lazy( + () => import('./Pages/BookingScreen/Components/MainPage/MainPage.jsx') +); + +const PrintSelectionPage = lazy( + () => import('./Pages/BookingScreen/Components/PrintMainPage/MainPage.jsx') +); +const KioskMainPage = lazy( + () => import('./Pages/BookingScreen/Components/Kiosk/KioskMainPage.jsx') +); + +const BookingPage = lazy(() => import('./Pages/BookingScreen/BookingPage.jsx')); + +const StockForm = lazy(() => import('./Pages/StockMaster/StockForm.jsx')); + +const StockList = lazy(() => import('./Pages/StockMaster/StockList.jsx')); + +const DiningMasterList = lazy(() => import('./Pages/Dining/DiningList.jsx')); + +const DiningMasterForm = lazy(() => import('./Pages/Dining/DiningForm.jsx')); + +const TableBooking = lazy( + () => import('./Pages/Tablebooking/TableBooking.jsx') +); + +const ComboMaster = lazy(() => import('./Pages/ComboPack/ComboMaster.jsx')); + +const ComboList = lazy(() => import('./Pages/ComboPack/ComboMasterlist.jsx')); +const EmpAccessForm = lazy(() => import('./Pages/EmpAccess/EmpAccessForm.jsx')); +const EmpAccessList = lazy(() => import('./Pages/EmpAccess/EmpAccessList.jsx')); + +const EmpScreenAccessList = lazy( + () => import('./Pages/EmpScreenAccess/EmpScreenAccessList.jsx') +); +const EmpScreenRightsAccess = lazy( + () => import('./Pages/EmpScreenAccess/EmpScreenRightsAccess.jsx') +); + +const PreferenceList = lazy( + () => import('./Pages/Preference/PreferenceList.jsx') +); + +const PaymentOptions = lazy( + () => import('./Pages/Payment/PaymentOptions/PaymentOptions.jsx') +); +const PaymentDetails = lazy( + () => import('./Pages/Payment/PaymentDetails/PaymentDetailsForm.jsx') +); +const PaymentDetailsList = lazy( + () => import('./Pages/Payment/PaymentDetails/PaymentDetailsList.jsx') +); +const PaymentReceivedRetail = lazy( + () => + import('./Pages/Payment/PaymentReceivedRetail/PaymentReceivedRetail.jsx') +); + +const ExtraChargesList = lazy( + () => import('./Pages/ExtraCharges/ExtraChargesList.jsx') +); + +const BranchLogin = lazy(() => import('./Pages/BranchLogin/BranchLogin.jsx')); +const BackToBranchLogin = lazy( + () => import('./Pages/BranchLogin/BackToBranchLogin.jsx') +); +const Logout = lazy(() => import('./Pages/Logout.jsx')); + +const BacktoLogin = lazy(() => import('./Pages/BranchLogin/BacktoLogin.jsx')); + +const StockPriceUpdate = lazy( + () => import('./Pages/StockPriceUpdate/StockPriceUpdate.jsx') +); + +const ProductCatalogueList = lazy( + () => import('./Pages/ProductCatlogue/ProductcatlogueList.jsx') +); + +const KOT = lazy(() => import('./Pages/Reports/KOT/kot.jsx')); + +const CustomerKOTDisplay = lazy( + () => import('./Pages/Reports/KOT/CustomerKOTDisplay.jsx') +); + +const RedirectApps = lazy(() => import('./Pages/RedirectApps.jsx')); + +const WSTransaction = lazy( + () => import('./Pages/WholeSaleTransaction/WSSalesTransaction.jsx') +); + +const LedgerReport = lazy( + () => import('./Pages/Reports/LedgerReport/LedgerReport.jsx') +); +const PaymentDetailsPage = lazy( + () => + import('./Pages/BookingScreen/Components/BookingFunctionality/PaymentDetailsPage.jsx') +); + +const CreditCustomerPrint = lazy( + () => + import('./Pages/BookingScreen/Components/BookingFunctionality/CreditDownloadpage.jsx') +); + +const Cancellation = lazy( + () => import('./Pages/CancelReschedule/Cancellation.jsx') +); + +const ChangePaymentmode = lazy( + () => import('./Pages/CancelReschedule/ChangePaymentmode.jsx') +); + +const CancellationList = lazy( + () => import('./Pages/CancelReschedule/CancellationList.jsx') +); + +const CancelApplicableProd = lazy( + () => import('./Pages/CancelReschedule/CancelApplicableProd.jsx') +); + +const CancellationListPending = lazy( + () => import('./Pages/CancelReschedule/CancelPendingPayment.jsx') +); + +const AndroidApp = lazy(() => import('./Pages/AndroidApp/AndroidApp.jsx')); + +const EstimateItemWiseReport = lazy( + () => import('./Pages/Reports/Estimate/EstimateItemWiseReport.jsx') +); + +const EstimateDateWiseReport = lazy( + () => import('./Pages/Reports/Estimate/EstimateDateWiseReport.jsx') +); + +const OfferForm = lazy(() => import('./Pages/Offer/Offer/OfferFormNew.jsx')); + +const OfferList = lazy(() => import('./Pages/Offer/Offer/OfferListNew.jsx')); + +const ItemWise = lazy(() => import('./Pages/Offer/ItemOffer/ItemWiseForm.jsx')); +const SalesWiseForm = lazy( + () => import('./Pages/Offer/SalesOffer/SalesWiseForm.jsx') +); +const SalesWiseList = lazy( + () => import('./Pages/Offer/SalesOffer/SalesWiseList.jsx') +); + +const QuantityWise = lazy( + () => import('./Pages/Offer/QuantityOffer/QuantityWiseForm.jsx') +); + +const BuyOneGetOneForm = lazy( + () => import('./Pages/Offer/BuyOneGetOneOffer/BuyOneGetOneForm.jsx') +); + +const LoyaltyPointsList = lazy( + () => import('./Pages/Offer/LoyaltyPoints/LoyaltyPointsList.jsx') +); + +const BundleOfferForm = lazy( + () => import('./Pages/Offer/BundleOffer/BundleOfferForm.jsx') +); +const BundleOfferList = lazy( + () => import('./Pages/Offer/BundleOffer/BundleOfferList.jsx') +); +const CouponWiseOfferlist = lazy( + () => import('./Pages/Offer/CouponOffer/CouponWiseOfferlist.jsx') +); + +const PromocodeList = lazy( + () => import('./Pages/Offer/PromoCode/PromocodeList.jsx') +); + +const OfferCodeList = lazy( + () => import('./Pages/Offer/OfferCode/OfferCodeList.jsx') +); + +const PricingPage = lazy( + () => + import('./Pages/BookingScreen/Components/UtillComponents/PricingPage.jsx') +); + +const PurchaseOrder = lazy( + () => import('./Pages/PurchaseOrder/PurchaseOrder.jsx') +); + +const PurchaseOrderMail = lazy( + () => import('./Pages/PurchaseOrder/PurchaseOrderMail.jsx') +); + +const PurchaseOrderList = lazy( + () => import('./Pages/PurchaseOrder/PurchaseOrderList.jsx') +); + +const StockReceivedList = lazy( + () => import('./Pages/StockTransfer/StockReceivedList.jsx') +); + +const GstInvoiceSetUpForm = lazy( + () => import('./Pages/GstInvoiceSetup/GstInvoiceSetUpForm.jsx') +); + +const gstInvoiceSetUpList = lazy( + () => import('./Pages/GstInvoiceSetup/GstInvoiceSetupList.jsx') +); + +const StockinHand = lazy(() => import('./Pages/StockinHand/StockinHand.jsx')); + +const PurchaseReturn = lazy( + () => import('./Pages/PurchaseReturn/purchaseReturn.jsx') +); + +const PurchaseReturnget = lazy( + () => import('./Pages/PurchaseReturn/PurchaseReturnGet.jsx') +); + +const KioskBookingPage = lazy( + () => import('./Pages/Kiosk/KioskBookingPage.jsx') +); + +const KioskBookingReceipt = lazy( + () => import('./Pages/Kiosk/PaymentGateway/PaymentGatewayReceipt.jsx') +); + +const KioskComponentList = lazy( + () => import('./Pages/KioskComponent/KioskComponentList.jsx') +); + +const CustomerDisplay = lazy( + () => import('./Pages/CustomerDisplay/CustomerDisplay.jsx') +); + +const PurchaseQuotationForm = lazy( + () => import('./Pages/PurchaseQuotation/PurchaseQuotationForm.jsx') +); + +const DeliveryChallanForm = lazy( + () => import('./Pages/DeliveryChallan/Deliverychallan.jsx') +); + +const DeliveryChallanList = lazy( + () => import('./Pages/DeliveryChallan/DeliverychallanList.jsx') +); + +const ComboOfferMaster = lazy( + () => import('./Pages/Offer/ComboOfferPack/ComboOfferForm.jsx') +); + +const PaymentDeviceForm = lazy( + () => import('./Pages/Payment/PaymentDevice/PaymentDeviceForm.jsx') +); +const PaymentFailedDetailsList = lazy( + () => + import('./Pages/Payment/PaymentFailedDetails/PaymentFailedDetailsList.jsx') +); + +const CounterCategoryMappingForm = lazy( + () => import('./Pages/CounterCategoryMapping/CounterCategoryMappingForm.jsx') +); + +const ImageBulkUpload = lazy( + () => import('./Pages/ImageBulkUpload/ImageBulkUpload.jsx') +); + +const WholesaleBookingPage = lazy( + () => import('./Pages/PurchaseScreen/LayoutScreen8/LayoutScreen8.jsx') +); + +const WholeSaleProductList = lazy( + () => import('./Pages/Wholesale/ProductList.jsx') +); + +const ProductEntry = lazy(() => import('./Pages/Wholesale/ProductEntry.jsx')); + +const ProductEntryList = lazy( + () => import('./Pages/Wholesale/ProductEntryList.jsx') +); +const ItemEntry = lazy( + () => import('./Pages/Wholesale/ItemEntry/ItemEntry.jsx') +); + +const WsPreorder = lazy( + () => import('./Pages/Wholesalespreorder/WholesalePreorderList.jsx') +); + +const WsPreorderForm = lazy( + () => import('./Pages/Wholesalespreorder/WholesalePreorderForm.jsx') +); + +const ExtraChrgesList = lazy( + () => import('./Pages/Wholesale/ItemEntry/ExtraChrgesList.jsx') +); + +const SalesBillCancel = lazy( + () => import('./Pages/SalesRemoval/SalesBillCancelList.jsx') +); + +const WholeSaleAbstract = lazy( + () => import('./Pages/WholeSaleAbstract/WholeSaleAbstract.jsx') +); + +const WholeSaleSellerAbstract = lazy( + () => import('./Pages/WholeSaleAbstract/WholeSaleSellerAbstract.jsx') +); + +const PaymentReceived = lazy( + () => import('./Pages/WholeSaleTransaction/PaymentReceived.jsx') +); + +const WholeSaleSalesReport = lazy( + () => import('./Pages/WholeSaleReport/WholeSalesSalesReport.jsx') +); + +const WholeSalePurchaseReport = lazy( + () => import('./Pages/WholeSaleReport/WholeSalePurchaseReport.jsx') +); +const WholeSalePaymentPurchaseReport = lazy( + () => + import('./Pages/WholesalePaymentReport/WholeSalePaymentPurchaseReport.jsx') +); + +const WholeSalePaymentSalesReport = lazy( + () => + import('./Pages/WholesalePaymentReport/WholeSalePaymementSaleReport.jsx') +); + +const SpeechLanguagesList = lazy( + () => import('./Pages/SpeechLanguages/SpeechLanguagesList.jsx') +); + +const LegderList = lazy( + () => import('./Pages/WholeSaleLedger/WholeSaleLedger.jsx') +); + +const SellerMasterTran = lazy( + () => import('./Pages/WholeSaleTransaction/SellerMasterTransaction.jsx') +); + +const TicketForm = lazy(() => import('./Pages/Ticket/TicketForm.jsx')); + +const ThemeCreation = lazy( + () => import('./Pages/BookingScreen/Components/ThemeCreation/ThemeList.jsx') +); + +const ThemeSelection = lazy( + () => + import('./Pages/BookingScreen/Components/ThemeCreation/ThemePreview.jsx') +); + +const BarcodeTemplateSetup = lazy( + () => import('./Pages/BarcodeSetup/BarcodeTemplateSetup.jsx') +); + +const BarcodeComponentList = lazy( + () => import('./Pages/BarcodeComponent/BarcodeComponentList.jsx') +); + +const StoreRecipelist = lazy( + () => import('./Pages/StoreKitchen/StoreRecipe/StoreRecipelist.jsx') +); + +const StoreRecipeform = lazy( + () => import('./Pages/StoreKitchen/StoreRecipe/StoreRecipeform.jsx') +); + +const Storekitchenlist = lazy( + () => import('./Pages/StoreKitchen/StoretoKitchen/StoretoKitchenlist.jsx') +); + +const StoreKitchenform = lazy( + () => import('./Pages/StoreKitchen/StoretoKitchen/Storetokitchenform.jsx') +); +import { getSession, sessionStore } from './Services/Others'; +import axios from 'axios'; +const KitchenFinishlist = lazy( + () => import('./Pages/StoreKitchen/StoreKitchenFinish/KitchenFinishlist.jsx') +); +const KitechenFinishform = lazy( + () => import('./Pages/StoreKitchen/StoreKitchenFinish/KitechenFinishform.jsx') +); + +const FreeProductList = lazy( + () => import('./Pages/FreeProducts/FreeProduct/FreeProductList.jsx') +); + +const FreePurchaseEnteryForm = lazy( + () => + import('./Pages/FreeProducts/FreePurchase/FreePurchaseEntery/FreePurchaseEnteryForm.jsx') +); +const FreePurchaseEnteryList = lazy( + () => + import('./Pages/FreeProducts/FreePurchase/FreePurchaseEntery/FreePurchaseEnteryList.jsx') +); + +const FreePurchaseOrderList = lazy( + () => + import('./Pages/FreeProducts/FreePurchase/FreePurchaseOrder/FreePurchaseOrderList.jsx') +); +const FreePurchaseOrderForm = lazy( + () => + import('./Pages/FreeProducts/FreePurchase/FreePurchaseOrder/FreePurchaseOrderForm.jsx') +); + +const FreePurchaseReturnList = lazy( + () => + import('./Pages/FreeProducts/FreePurchase/FreePurchaseReturn/FreePurchaseReturnList.jsx') +); +const FreePurchaseReturnForm = lazy( + () => + import('./Pages/FreeProducts/FreePurchase/FreePurchaseReturn/FreePurchaseReturnForm.jsx') +); +const CommonForm = lazy( + () => import('./Pages/Offer/LoyaltyPoints/CommonForm.jsx') +); + +const ReprintReasonReportList = lazy( + () => + import('./Pages/Reports/ReprintReasonReport/ReprintReasonReportList.jsx') +); + +const RevenueItemWiseReport = lazy( + () => import('./Pages/Reports/Revenue/RevenueItemWiseReport.jsx') +); + +const LinkUrlCreate = lazy( + () => import('./Pages/paymentpdfPage/LinkUrlCreate.jsx') +); + +const SupplierProductMapping = lazy( + () => import('./Pages/SupplierProductMapping/SupplierProductMapping.jsx') +); + +const RedirectUserProfile = lazy( + () => import('./Pages/RedirectUserProfile.jsx') +); + +const RelieveRequestForm = lazy( + () => import('./Pages/EmpMaster/EmpRelieve.jsx') +); + +const PurchaseQuotationList = lazy( + () => import('./Pages/PurchaseQuotation/PurchaseQuotationList.jsx') +); + +const ExchangeAndReplacementList = lazy( + () => import('./Pages/ExchangeAndReplacement/ExchangeAndReplacementList.jsx') +); +const ExchangeAndReplacementForm = lazy( + () => import('./Pages/ExchangeAndReplacement/ExchangeAndReplacementForm.jsx') +); + +const ExchangeReturnMapForm = lazy( + () => import('./Pages/ExchangeReturnMap/ExchangeReturnMapForm.jsx') +); +const ExchangeReturnMapList = lazy( + () => import('./Pages/ExchangeReturnMap/ExchangeReturnMapList.jsx') +); + +const OtherServicesForm = lazy( + () => import('./Pages/OtherServices/OtherServicesForm.jsx') +); +const OtherServicesList = lazy( + () => import('./Pages/OtherServices/OtherServicesList.jsx') +); +const EmpCommisionOrIncentiveForm = lazy( + () => + import('./Pages/EmpCommissionOrIncentive/EmpCommisionOrIncentiveForm.jsx') +); + +const EmpCommisionOrIncentiveList = lazy( + () => + import('./Pages/EmpCommissionOrIncentive/EmpCommisionOrIncentiveList.jsx') +); + +const SalesBillProductsReturnList = lazy( + () => import('./Pages/CancelReschedule/SalesBillProductReturnList.jsx') +); + +const SalesBillProductsReturn = lazy( + () => import('./Pages/CancelReschedule/SalesBillProductsReturn.jsx') +); + +const DeliveryChallanToInvoiceForm = lazy( + () => + import('./Pages/DeliveryChallanToInvoice/DeliveryChallanToInvoiceForm.jsx') +); + +const DeliveryChallanToInvoiceList = lazy( + () => + import('./Pages/DeliveryChallanToInvoice/DeliveryChallanToInvoiceList.jsx') +); + +const TipAmountSettlementList = lazy( + () => + import('./Pages/Reports/TipAmountSettlement/TipAmountSettlementList.jsx') +); + +const EmployeeSettlement = lazy( + () => import('./Pages/Reports/EmployeeSettlement/EmployeeSettlement.jsx') +); +const Settlement = lazy( + () => import('./Pages/Reports/TipAmountSettlement/Settlement.jsx') +); +const PublicQrCode = lazy(() => import('./Pages/Reports/PublicQrCode.jsx')); + +const TableMapping = lazy( + () => import('./Pages/TableMapping/TableMapping.jsx') +); +const TableMAppingList = lazy( + () => import('./Pages/TableMapping/TableMAppingList.jsx') +); + +const PurchaseOrderReport = lazy( + () => import('./Pages/Reports/PurchaseReport/PurchaseOrderReport.jsx') +); + +const SalesOrder = lazy(() => import('./Pages/SalesOrder/SalesOrder.jsx')); + +const LoyaltyBased = lazy( + () => import('./Pages/Offer/LoyaltyBased/LoyaltyBased.jsx') +); +const LoyaltyBasedList = lazy( + () => import('./Pages/Offer/LoyaltyBased/LoyaltyBasedList.jsx') +); +const CodeBase = lazy(() => import('./Pages/Offer/CodeBase/CodeBase.jsx')); +const CodeBaseList = lazy( + () => import('./Pages/Offer/CodeBase/CodeBaseList.jsx') +); + +const TurboAddForm = lazy(() => import('./Pages/Product/TurboAddForm.jsx')); + +const ProductMaster = lazy(() => import('./Pages/Product/ProductMaster.jsx')); + +const GatewayMasterConfiguration = lazy( + () => + import('./Pages/GatewayMasterConfiguration/GatewayMasterConfiguration.jsx') +); +const GatewayMasterConfigurationList = lazy( + () => + import('./Pages/GatewayMasterConfiguration/GatewayMasterConfigurationList.jsx') +); + +const MembershipForm = lazy( + () => import('./Pages/Membership/MembershipForm.jsx') +); +const MembershipList = lazy( + () => import('./Pages/Membership/MembershipList.jsx') +); +const SlotManagementForm = lazy( + () => import('./Pages/SlotManagement/SlotManagement.jsx') +); +const SlotManagementList = lazy( + () => import('./Pages/SlotManagement/SlotManagementList.jsx') +); + +const BookingReScedule = lazy( + () => import('./Pages/CancelReschedule/BookingReScedule.jsx') +); +const BookingReSceduleList = lazy( + () => import('./Pages/CancelReschedule/BookingReSceduleList.jsx') +); + +const MembershipReport = lazy( + () => import('./Pages/Reports/Membership/MembershipReport.jsx') +); +const OpeningStock = lazy( + () => import('./Pages/openingStock/openingstockForm.jsx') +); +const OpeningStockList = lazy( + () => import('./Pages/openingStock/OpeningStockList.jsx') +); + +const StockAdjustment = lazy( + () => import('./Pages/StockAdjustment/StockAdjustment.jsx') +); +const StockAdjustmentList = lazy( + () => import('./Pages/StockAdjustment/StockAdjustmentList.jsx') +); +const TopSellingProducts = lazy( + () => import('./Pages/DashBoard/TopSellingProductsChart.jsx') +); + +const AutomatedReorder = lazy( + () => import('./Pages/Automated Reorder/AutomatedReorder.jsx') +); +const AutomatedReorderList = lazy( + () => import('./Pages/Automated Reorder/AutomatedReorderList.jsx') +); + +const CustomerPurchaseConfirm = lazy( + () => + import('./Pages/PurchaseOrder/CustomerPurchaseConfirm/CustomerPurchaseConfirm.jsx') +); + +const MenuQRCode = lazy( + () => import('./Pages/Reports/MenuQRCode/MenuQRCode.jsx') +); + +const PurchaseLink = lazy( + () => import('./Pages/PurchaseOrder/CustomerPurchaseConfirm/PurchaseLink.jsx') +); +const RackForm = lazy(() => import('./Pages/Rack/RackForm.jsx')); +const RackList = lazy(() => import('./Pages/Rack/RackList.jsx')); + +const CreateTransfer = lazy( + () => import('./Pages/StockTransfer/CreateTransfer.jsx') +); +const Dispatch = lazy(() => import('./Pages/StockTransfer/Dispatch.jsx')); +const StockTransferList = lazy( + () => import('./Pages/StockTransfer/TransferList.jsx') +); + +const ComboLayout3 = lazy( + () => import('./Pages/BookingScreen/Template/ComboLayout3/ComboLayout3.jsx') +); + +const Productcatlogue = lazy( + () => import('./Pages/ProductCatlogue/Productcatalogue.jsx') +); + +const subDirectory = import.meta.env.BASE_URL; +const apiCommonUrl = import.meta.env.ENV_API_URL_COMMON; + +const initSession = () => { + sessionStore('AppId', 2); + sessionStore('BranchId', 791); + sessionStore('AppName', 'Bakery'); + sessionStore('CompId', 657); + sessionStore('MobileNo', '8888888888'); + sessionStore('UserType', 'Admin'); + sessionStore('UserId', 286); + sessionStore('userName', 'Karthiga'); + + sessionStore( + 'auth','eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJodHRwOi8vc2NoZW1hcy54bWxzb2FwLm9yZy93cy8yMDA1LzA1L2lkZW50aXR5L2NsYWltcy9uYW1lIjoiODg4ODg4ODg4OCIsIlBhc3N3b3JkIjoiWkB6MTIzNCIsImF1ZCI6WyJodHRwczovL2FwaS5wb3pvLmRldi9wb3pvLXJldGFpbC1hcGkiLCJodHRwczovL2FwaS5wb3pvLmRldi9wb3pvLWNvbW1vbi1hcGkiLCJodHRwczovL2FwaS5wb3pvLmRldi9wb3pvLXNtcy1lbWFpbC10ZW1wbGF0ZS1hcGkiLCJodHRwczovL2FwaS5wb3pvLmRldi9wb3pvLWNvbW1vbi1hcGkiXSwiZXhwIjoxNzc0NjM3OTA5LCJpc3MiOiJodHRwczovL2FwaS5wb3pvLmRldi9Kd3RUb2tlbiJ9.TWDS0cuHGIDW_16EH2RS4z2B-wnuuPmMNd_lre505qY' + ); +}; + +const getAppType = async () => { + // ๐Ÿ”ฅ If already stored, don't call API again + const storedType = getSession('AppType'); + if (storedType) { + return storedType === 'Wholesale'; + } + + const AppId = getSession('AppId'); + if (!AppId) return null; + + const response = await axios.get( + `${apiCommonUrl}/application?AppId=${AppId}` + ); + + const subCategoryName = + response?.data?.data?.[0]?.SubCategoryName?.toLowerCase(); + + const isWholesale = subCategoryName === 'wholesale'; + + sessionStore('AppType', isWholesale ? 'Wholesale' : 'Sale'); + + return isWholesale; +}; + +const fetchComponent = async () => { + try { + initSession(); + + const isWholesale = await getAppType(); + if (isWholesale === null) return null; + + return isWholesale + ? import('./Pages/AppPage/WholesaleAppPage.jsx') + : import('./Pages/AppPage/AppPage.jsx'); + } catch (err) { + console.error('API call failed:', err); + return null; + } +}; +const fetchHomeComponent = async () => { + try { + initSession(); + + const isWholesale = await getAppType(); + if (isWholesale === null) return null; + + return isWholesale + ? import('./Pages/DashBoard/WholesaleDashboard.jsx') + : import('./Pages/DashBoard/RetailDashboard.jsx'); + } catch (err) { + console.error('API call failed:', err); + return null; + } +}; + +export const routesConfig = [ + { path: `${subDirectory}customer-display`, component: CustomerDisplay }, + { path: `${subDirectory}PricingPage`, component: PricingPage }, + { + path: `${subDirectory}android-app`, + component: AndroidApp, + empAccess: 'Android App', + }, + { path: `${subDirectory}purchaseordermail`, component: PurchaseOrderMail }, + { + path: `${subDirectory}viewbill`, + component: LinkUrlCreate, + empAccess: 'View Bill', + }, + // writed b=y sree + // { + // path: `${subDirectory}MenuQRCode`, + // component: CustomerMenuPage, + // }, + { + path: `${subDirectory}purchaseconfirm`, + component: CustomerPurchaseConfirm, + }, + { + path: `${subDirectory}viewpurchaseorder`, + component: PurchaseLink, + }, + { + path: `${subDirectory}combolayout3`, + component: ComboLayout3, + }, + + { + path: `${subDirectory}`, + component: React.lazy(() => + fetchComponent().then((module) => ({ default: module.default })) + ), + children: [ + { + path: '/', + component: React.lazy(() => + fetchHomeComponent().then((module) => ({ default: module.default })) + ), + }, + { path: `relieve-request`, component: RelieveRequestForm }, + { path: 'branch-login', component: BranchLogin }, + { path: 'branch-all', component: BackToBranchLogin }, + { path: 'back-to-login', component: BacktoLogin }, + { path: 'logout', component: Logout }, + { path: 'redirect-apps', component: RedirectApps }, + { path: 'redirect-userprofile', component: RedirectUserProfile }, + // { path: 'transaction', component: WSTransaction } + ], + }, + { + path: `${subDirectory}qrprint`, + component: CreditCustomerPrint, + empAccess: 'Public', + }, + { path: `${subDirectory}sales`, component: BookingPage, empAccess: 'Sales' }, + { + path: `${subDirectory}wholesales`, + component: WholesaleBookingPage, + empAccess: 'Whole Sales', + }, + { + path: `${subDirectory}kiosksales`, + component: KioskBookingPage, + empAccess: 'Kiosk Sales', + }, + { + path: `${subDirectory}kiosk-receipt`, + component: KioskBookingReceipt, + empAccess: 'Public', + }, + { + path: `${subDirectory}payment-page`, + component: PaymentDetailsPage, + empAccess: 'Public', + }, + { path: `${subDirectory}reprint`, component: Reprint }, + { + path: `${subDirectory}transaction`, + component: React.lazy(() => + fetchComponent().then((module) => ({ default: module.default })) + ), + children: [ + { path: 'sales', component: WSTransaction, empAccess: 'Sales' }, + { path: 'payment-received', component: PaymentReceived }, + { path: 'seller-payment', component: SellerMasterTran }, + ], + }, + { + path: `${subDirectory}kitchen`, + component: React.lazy(() => + fetchComponent().then((module) => ({ default: module.default })) + ), + children: [ + { path: 'kot', component: KOT, empAccess: 'KOT' }, + { + path: 'kot-display', + component: CustomerKOTDisplay, + empAccess: 'KOT Display', + }, + ], + }, + { + path: `${subDirectory}report`, + component: React.lazy(() => + fetchComponent().then((module) => ({ default: module.default })) + ), + children: [ + { + path: 'PublicQrCode', + component: PublicQrCode, + empAccess: 'SelfBooking QR Code', + }, + { + path: 'MenuQRCode', + component: MenuQRCode, + empAccess: 'MenuQRCode', + }, + // { + // path: 'tipamountsettlementlist', + // component: TipAmountSettlementList, + // empAccess: 'Tips', + // }, + // { + // path: 'EmployeeSettlement', + // component: EmployeeSettlement, + // empAccess: 'Incentive', + // }, + { + path: 'Settlement', + component: Settlement, + empAccess: 'Settlement', + }, + + { + path: 'datewisereport', + component: DateWiseReport, + empAccess: 'Daily Sales', + }, + { + path: 'itemwisereport', + component: ItemWiseReport, + empAccess: 'By Item', + }, + { + path: 'top-selling-products', + component: TopSellingProducts, + empAccess: 'Top Selling Products', + }, + { + path: 'estimateitemwisereport', + component: EstimateItemWiseReport, + empAccess: 'By Item', + }, + { + path: 'estimatedatewisereport', + component: EstimateDateWiseReport, + empAccess: 'Daily Sales', + }, + { path: 'ledgerreport', component: LedgerReport, empAccess: 'Ledger' }, + { path: 'ledger', component: LegderList, empAccess: 'Ledger' }, + { + path: 'stock-in-hand', + component: StockinHand, + empAccess: 'Stock Inhand', + }, + { + path: 'abstract', + component: WholeSaleAbstract, + empAccess: 'Abstract For Sales', + }, + { + path: 'sellerabstract', + component: WholeSaleSellerAbstract, + empAccess: 'Abstract For Purchase', + }, + { + path: 'salesreport', + component: WholeSaleSalesReport, + empAccess: 'Daily Sales', + }, + { + path: 'purchasereport', + component: WholeSalePurchaseReport, + empAccess: 'Purchase', + }, + { + path: 'paymentpurchasereport', + component: WholeSalePaymentPurchaseReport, + empAccess: 'Purchase Payment', + }, + { + path: 'paymentsalesreport', + component: WholeSalePaymentSalesReport, + empAccess: 'Sales Payment', + }, + { + path: 'reprintreasonreport', + component: ReprintReasonReportList, + empAccess: 'Reprint Details', + }, + { + path: 'membership', + component: MembershipReport, + empAccess: 'Membership Report', + }, + { + path: 'revenueitemWisereport', + component: RevenueItemWiseReport, + empAccess: 'Gross Margin', + }, + + { + path: 'PurchaseOrderReport', + component: PurchaseOrderReport, + empAccess: 'Purchase', + }, + ], + }, + { + path: `${subDirectory}setting`, + component: React.lazy(() => + fetchComponent().then((module) => ({ default: module.default })) + ), + children: [ + { + path: 'common-master', + component: CommonMaster, + empAccess: 'Common Master', + }, + { + path: 'other-services', + component: OtherServicesList, + empAccess: 'OtherServices', + }, + { + path: 'other-services/new', + component: (props) => , + empAccess: 'OtherServices', + }, + { + path: 'other-services/update', + component: (props) => , + empAccess: 'OtherServices', + }, + { + path: 'config-type', + component: ConfigType, + access: 'Super Admin', + empAccess: 'Config Type', + }, + { + path: 'languages', + component: SpeechLanguagesList, + access: 'Super Admin', + empAccess: 'Languages', + }, + { + path: 'preference', + component: PreferenceList, + empAccess: 'Preference', + }, + { + path: 'price-change', + component: StockPriceUpdate, + empAccess: 'Price Change', + }, + { + path: 'extra-charges', + component: ExtraChargesList, + empAccess: 'Extra Charges', + }, + { + path: 'Exchange-Return-policy', + component: ExchangeAndReplacementList, + empAccess: 'Exchange / Return', + }, + { + path: 'Exchange-Return-policy/new', + component: (props) => ( + + ), + empAccess: 'Exchange / Return', + }, + { + path: 'exchange-return-mapping', + component: ExchangeReturnMapList, + empAccess: 'Rules Mapping', + }, + { + path: 'exchange-return-mapping/new', + component: (props) => ( + + ), + empAccess: 'Rules Mapping', + }, + + { + path: 'product-catalogue-list', + component: ProductCatalogueList, + empAccess: 'Product Catalogue', + }, + { + path: 'product-catalogue', + component: Productcatlogue, + empAccess: 'Product Catalogue', + }, + { path: 'admin-tax', component: AdminTax, empAccess: 'Tax' }, + { + path: 'create-ticket', + component: TicketForm, + empAccess: 'Create Ticket', + }, + { + path: 'payment-options', + component: PaymentOptions, + empAccess: 'Payment Options', + }, + { + path: 'payment-received-retail', + component: PaymentReceivedRetail, + empAccess: 'Payment Updates', + }, + { + path: 'payment-device-access', + component: PaymentDeviceForm, + empAccess: 'Payment Device Access', + }, + { + path: 'counter-category-mapping', + component: CounterCategoryMappingForm, + empAccess: 'Counter Mapping', + }, + + { + path: 'wholesale-product-master', + component: WholeSaleProductList, + empAccess: 'Product', + }, + { + path: 'product-entry', + component: ProductEntryList, + empAccess: 'Product Entry', + }, + { + path: 'product', + component: ProductMaster, + empAccess: 'Product Entry', + }, + + { + path: 'product-entry/new', + component: (props) => , + empAccess: 'Product Entry', + }, + { + path: 'wholesale-extracharges/new', + component: ItemEntry, + empAccess: 'Extra Charges', + }, + { + path: 'wholesale-extracharges', + component: ExtraChrgesList, + empAccess: 'Extra Charges', + }, + { + path: 'membership-master/list', + component: MembershipList, + empAccess: 'Membership', + }, + { + path: 'membership-master/new', + component: (props) => , + empAccess: 'Membership', + }, + { + path: 'membership-master/update', + component: (props) => , + empAccess: 'Membership', + }, + + { + path: 'opening-stock/new', + component: OpeningStock, + empAccess: 'Opening Stock', + }, + { + path: 'opening-stock', + component: OpeningStockList, + empAccess: 'Opening Stock', + }, + { + path: 'stock-adjustment', + component: StockAdjustment, + empAccess: 'Stock Adjustment', + }, + { + path: 'stock-adjustment-list', + component: StockAdjustmentList, + empAccess: 'Stock Adjustment', + }, + { + path: 'product-master', + component: ProductMaster, + empAccess: 'Add Product', + }, + { + path: 'product-master/combo', + component: ProductMaster, + component: (props) => , + empAccess: 'Add Product', + }, + { + path: 'product-master/new', + component: (props) => , + empAccess: 'Add Product', + }, + { + path: 'products-master/new', + component: (props) => , + empAccess: 'Add Product', + }, + { + path: 'products-master/update', + component: (props) => , + empAccess: 'Add Product', + }, + { + path: 'product-master/update', + component: (props) => , + empAccess: 'Add Product', + }, + { + path: 'product-master/turbo-add', + component: (props) => , + empAccess: 'Add Product', + }, + { + path: 'image-bulk-upload', + component: ImageBulkUpload, + empAccess: 'Image Upload', + }, + { + path: 'rack-master', + component: RackList, + empAccess: 'Add Rack', + }, + { + path: 'rack-master/new', + component: (props) => , + empAccess: 'Add Rack', + }, + { + path: 'rack-master/update', + component: (props) => , + empAccess: 'Add Rack', + }, + { + path: 'slot-management', + component: (props) => , + empAccess: 'Slot Management', + }, + { + path: 'slot-management-list', + component: (props) => , + empAccess: 'Slot Management', + }, + { + path: 'productBased-offer', + component: OfferList, + empAccess: 'Product Based', + }, + + { + path: 'productBased-offer/new', + component: (props) => , + empAccess: 'Product Based', + }, + { + path: 'productBased-offer/update', + component: (props) => , + empAccess: 'Product Based', + }, + { + path: 'code-base', + component: CodeBaseList, + empAccess: 'Code Based', + }, + { + path: 'code-base/new', + component: (props) => , + empAccess: 'Code Based', + }, + { + path: 'code-base/new', + component: (props) => , + empAccess: 'Code Based', + }, + + { path: 'item-wise', component: ItemWise, empAccess: 'Item Wise Offer' }, + { + path: 'quantity-wise', + component: QuantityWise, + empAccess: 'Quantity Wise Offer', + }, + { + path: 'buyone-getone', + component: BuyOneGetOneForm, + empAccess: 'Buy X and Get X or Y', + }, + + { + path: 'sales-wise', + component: SalesWiseList, + empAccess: 'Sales Wise Offer', + }, + { + path: 'sales-wise/new', + component: (props) => , + empAccess: 'Sales Wise Offer', + }, + { + path: 'sales-wise/update', + component: (props) => , + empAccess: 'Sales Wise Offer', + }, + + { + path: 'loyalty-point', + component: LoyaltyPointsList, + empAccess: 'Loyalty Cards', + }, + { + path: 'loyalty-based', + // component: LoyaltyBased, + component: LoyaltyBasedList, + empAccess: 'Loyalty Points', + }, + { + path: 'loyalty-based/new', + component: (props) => , + empAccess: 'Loyalty Points', + }, + { + path: 'loyalty-based/update', + component: (props) => , + empAccess: 'Loyalty Points', + }, + + { + path: 'loyalty-point/new', + component: (props) => ( + + ), + empAccess: 'Loyalty Cards', + }, + { + path: 'loyalty-point/update', + component: (props) => ( + + ), + empAccess: 'Loyalty Cards', + }, + // { path: 'loyalty-point/new', component: (props) => , empAccess: "Loyalty Cards" }, + // { path: 'loyalty-point/update', component: (props) => , empAccess: "Loyalty Cards" }, + + { + path: 'bundle-offer', + component: BundleOfferList, + empAccess: 'Bundle Offer', + }, + { + path: 'bundle-offer/new', + component: (props) => , + empAccess: 'Bundle Offer', + }, + { + path: 'bundle-offer/update', + component: (props) => , + empAccess: 'Bundle Offer', + }, + + { + path: 'coupon', + component: CouponWiseOfferlist, + empAccess: 'Coupon Wise Offer', + }, + { + path: 'coupon/new', + component: (props) => ( + + ), + empAccess: 'Coupon Wise Offer', + }, + { + path: 'coupon/update', + component: (props) => ( + + ), + empAccess: 'Coupon Wise Offer', + }, + // { path: 'coupon/new', component: (props) => , empAccess: "Coupon Wise Offer" }, + // { path: 'coupon/update', component: (props) => , empAccess: "Coupon Wise Offer" }, + + { path: 'promo-code', component: PromocodeList, empAccess: 'Promo Code' }, + { + path: 'promo-code/new', + component: (props) => ( + + ), + empAccess: 'Promo Code', + }, + { + path: 'promo-code/update', + component: (props) => ( + + ), + empAccess: 'Promo Code', + }, + // { path: 'promo-code/new', component: (props) => , empAccess: "Promo Code" }, + // { path: 'promo-code/update', component: (props) => , empAccess: "Promo Code" }, + + { path: 'offer-code', component: OfferCodeList, empAccess: 'Offer Code' }, + { + path: 'offer-code/new', + component: (props) => ( + + ), + empAccess: 'Offer Code', + }, + { + path: 'offer-code/update', + component: (props) => ( + + ), + empAccess: 'Offer Code', + }, + // { path: 'offer-code/new', component: (props) => , empAccess: "Offer Code" }, + // { path: 'offer-code/update', component: (props) => , empAccess: "Offer Code" }, + + { + path: 'customer-master', + component: CustomerMasterList, + empAccess: 'Customer', + }, + { + path: 'customer-master/new', + component: (props) => , + empAccess: 'Customer', + }, + { + path: 'customer-master/update', + component: (props) => , + empAccess: 'Customer', + }, + { + path: 'automated-reorder', + component: AutomatedReorderList, + empAccess: 'Automated Reorder', + }, + { + path: 'automated-reorder/new', + component: (props) => , + empAccess: 'Automated Reorder', + }, + { + path: 'automated-reorder/update', + component: (props) => , + empAccess: 'Automated Reorder', + }, + { + path: 'purchase-entry', + component: StockList, + empAccess: 'Product Receipt', + }, + { + path: 'purchase-entry/new', + component: (props) => , + empAccess: 'Product Receipt', + }, + { + path: 'purchase-entry/update', + component: (props) => , + empAccess: 'Product Receipt', + }, + + { + path: 'receive-stocks', + component: StockReceivedList, + empAccess: 'Purchase Order', + }, + { + path: 'gst-invoice-setup/new', + component: (props) => , + empAccess: 'Gst Invoice Setup', + }, + { + path: 'gst-invoice-setup/update', + component: (props) => ( + + ), + empAccess: 'Gst Invoice Setup', + }, + { + path: 'gst-invoice-setup', + component: gstInvoiceSetUpList, + empAccess: 'Gst Invoice Setup', + }, + { + path: 'purchase-order', + component: PurchaseOrderList, + empAccess: 'Purchase Order', + }, + { + path: 'purchase-order/new', + component: (props) => , + empAccess: 'Purchase Order', + }, + + { + path: 'purchase-return/list', + component: PurchaseReturnget, + empAccess: 'Product Return', + }, + { + path: 'purchaseconfirm', + component: CustomerPurchaseConfirm, + // empAccess: 'View Bill', + }, + { + path: 'purchase-return', + component: PurchaseReturn, + empAccess: 'Product Return', + }, + //free Products + { + path: 'free-product-master', + component: FreeProductList, + empAccess: 'Add Product', + }, + + { + path: 'free-purchase-entry', + component: FreePurchaseEnteryList, + empAccess: 'Purchase Entry', + }, + { + path: 'free-purchase-entry/new', + component: (props) => ( + + ), + empAccess: 'Purchase Entry', + }, + { + path: 'free-purchase-entry/update', + component: (props) => ( + + ), + empAccess: 'Purchase Entry', + }, + + { + path: 'free-purchase-order', + component: FreePurchaseOrderList, + empAccess: 'Purchase Order', + }, + { + path: 'free-purchase-order/new', + component: (props) => ( + + ), + empAccess: 'Purchase Order', + }, + + { + path: 'free-purchase-return', + component: FreePurchaseReturnList, + empAccess: 'Purchase Return', + }, + { + path: 'free-purchase-return/new', + component: FreePurchaseReturnForm, + empAccess: 'Purchase Return', + }, + //free Products + { + path: 'sales-quotation', + component: PurchaseQuotationForm, + empAccess: 'Sales Quotation', + }, + { + path: 'sales-quotation/list', + component: PurchaseQuotationList, + empAccess: 'Sales Quotation', + }, + { + path: 'sales-order', + component: SalesOrder, + empAccess: 'Sales Order', + }, + // { path: 'delivery-challan', + // component: DeliveryChallanList, + // empAccess: 'Delivery Challan' + // }, + { + path: 'delivery-challan/list', + component: DeliveryChallanList, + empAccess: 'Delivery Challan', + }, + { + path: 'delivery-challan', + component: DeliveryChallanForm, + empAccess: 'Delivery Challan', + }, + { + path: 'delivery-challan-to-invoice/list', + component: DeliveryChallanToInvoiceList, + empAccess: 'DC to Invoice', + }, + { + path: 'delivery-challan-to-invoice', + component: DeliveryChallanToInvoiceForm, + empAccess: 'DC to Invoice', + }, + + { path: 'shift-master', component: ShiftMasterList, empAccess: 'Shift' }, + { + path: 'shift-master/new', + component: (props) => , + empAccess: 'Shift', + }, + { + path: 'shift-master/update', + component: (props) => , + empAccess: 'Shift', + }, + + { + path: 'employee-master', + component: EmployeeMasterList, + empAccess: 'Add Employee', + }, + { + path: 'employee-master/new', + component: (props) => , + empAccess: 'Add Employee', + }, + { + path: 'employee-master/update', + component: (props) => , + empAccess: 'Add Employee', + }, + { + path: 'commission-or-incentive-master', + component: EmpCommisionOrIncentiveList, + empAccess: 'Incentive', + }, + { + path: 'commission-or-incentive-master/new', + component: (props) => ( + + ), + empAccess: 'Incentive', + }, + { + path: 'commission-or-incentive-master/update', + component: (props) => ( + + ), + empAccess: 'Incentive', + }, + { + path: 'supplier-master', + component: SupplierMasterList, + empAccess: 'Add Supplier', + }, + { + path: 'supplier-master/new', + component: (props) => , + empAccess: 'Add Supplier', + }, + { + path: 'supplier-master/update', + component: (props) => , + empAccess: 'Add Supplier', + }, + { + path: 'stock-transfer', + component: CreateTransfer, + empAccess: 'Create Transfer', + }, + { + path: 'stock-dispatch', + component: Dispatch, + empAccess: 'Dispatch', + }, + { + path: 'stock-transferlist', + component: StockTransferList, + empAccess: 'Create Transfer', + }, + { + path: 'supplierproductmapping-master', + component: SupplierProductMapping, + empAccess: 'Product Mapping', + }, + // { path: 'supplier-master/new', component: (props) => , empAccess: "Supplier" }, + // { path: 'supplier-master/update', component: (props) => , empAccess: "Supplier" }, + + { + path: 'dinein-master', + component: DiningMasterList, + empAccess: 'Dine In', + }, + { + path: 'dinein-master/new', + component: (props) => , + empAccess: 'Dine In', + }, + { + path: 'dinein-master/edit', + component: (props) => , + empAccess: 'Dine In', + }, + + { + path: 'combo-master', + component: ComboList, + empAccess: 'Add Product', + }, + { + path: 'combo-master/new', + component: (props) => , + empAccess: 'Add Product', + }, + { + path: 'combo-master/update', + component: (props) => , + empAccess: 'Add Product', + }, + + { + path: 'combo-offer-master', + component: ComboOfferMaster, + empAccess: 'Combo Price', + }, + + { + path: 'payment-details', + component: PaymentDetailsList, + empAccess: 'Payment Details', + }, + { + path: 'payment-details/new', + component: (props) => , + empAccess: 'Payment Details', + }, + { + path: 'payment-details/update', + component: (props) => , + empAccess: 'Payment Details', + }, + + { + path: 'payment-failed-details', + component: PaymentFailedDetailsList, + empAccess: 'Payment Failed Details', + }, + { + path: 'TableMapping/update', + component: (props) => , + empAccess: 'Table Mapping', + }, + { + path: 'TableMapping', + component: TableMAppingList, + empAccess: 'Table Mapping', + }, + { + path: 'employee-access', + component: EmpAccessList, + empAccess: 'Employee Access', + }, + { + path: 'employee-access/new', + component: (props) => , + empAccess: 'Employee Access', + }, + { + path: 'employee-access/update', + component: (props) => , + empAccess: 'Employee Access', + }, + { + path: 'employee-screenrights', + component: EmpScreenAccessList, + empAccess: 'Employee Screen Rights', + }, + { + path: 'employee-screenrights/new', + component: (props) => ( + + ), + empAccess: 'Employee Screen Rights', + }, + { + path: 'employee-screenrights/update', + component: (props) => ( + + ), + empAccess: 'Employee Screen Rights', + }, + + { + path: 'cancel-reschedule-rules', + component: CancellationList, + empAccess: 'Cancel / Reschedule', + }, + { + path: 'cancel-reschedule-rules/new', + component: (props) => , + empAccess: 'Cancel / Reschedule', + }, + { + path: 'cancel-reschedule-rules/update', + component: (props) => , + empAccess: 'Cancel / Reschedule', + }, + + { + path: 'cancel-applicable-product', + component: CancelApplicableProd, + empAccess: 'Cancel Applicable Products', + }, + { + path: 'cancel-paymentchange', + component: ChangePaymentmode, + empAccess: 'Payment Mode Change', + }, + { + path: 'cancel-pendingpayment', + component: CancellationListPending, + empAccess: 'Cancel Unpaid Order', + }, + { + path: 'sales-bill-cancel', + component: SalesBillCancel, + empAccess: 'Sales Entry Cancel', + }, + { + path: 'sales-bill-product-return/list', + component: SalesBillProductsReturnList, + empAccess: 'Sales Product Return', + }, + { + path: 'sales-bill-product-return', + component: SalesBillProductsReturn, + empAccess: 'Sales Product Return', + }, + { + path: 'booking-reschedule', + component: BookingReScedule, + empAccess: 'Booking Reschedule', + }, + { + path: 'booking-reschedule/list', + component: BookingReSceduleList, + empAccess: 'Booking Reschedule', + }, + + { + path: 'wholesale-preorder', + component: WsPreorder, + empAccess: 'Preorder', + }, + { + path: 'wholesale-preorder/new', + component: (props) => , + empAccess: 'Preorder', + }, + { + path: 'wholesale-preorder/update', + component: (props) => , + empAccess: 'Preorder', + }, + + { + path: 'custom-product', + component: StoreRecipelist, + empAccess: 'Bill Of Material', + }, + { + path: 'custom-product/new', + component: (props) => , + empAccess: 'Bill Of Material', + }, + { + path: 'custom-product/update', + component: (props) => , + empAccess: 'Bill Of Material', + }, + + { + path: 'store-to-production', + component: Storekitchenlist, + empAccess: 'Material Issue', + }, + { + path: 'store-to-production/new', + component: (props) => , + empAccess: 'Material Issue', + }, + { + path: 'store-to-production/update', + component: (props) => , + empAccess: 'Material Issue', + }, + + { + path: 'ready-for-sale', + component: KitchenFinishlist, + empAccess: 'Finished Goods', + }, + { + path: 'ready-for-sale/new', + component: (props) => , + empAccess: 'Finished Goods', + }, + { + path: 'ready-for-sale/update', + component: (props) => , + empAccess: 'Finished Goods', + }, + + { + path: 'gateway-master-configuration/new', + component: (props) => ( + + ), + empAccess: 'Gateway Master Configuration', + }, + { + path: 'gateway-master-configuration/update', + component: (props) => ( + + ), + empAccess: 'Gateway Master Configuration', + }, + { + path: 'gateway-master-configuration/list', + component: GatewayMasterConfigurationList, + empAccess: 'Gateway Master Configuration', + }, + ], + }, + { + path: `${subDirectory}sales`, + component: React.lazy(() => + fetchComponent().then((module) => ({ default: module.default })) + ), + children: [{ path: 'dine-in', component: TableBooking }], + empAccess: 'Sales Entry', + }, + { + path: `${subDirectory}saleslayouts`, + component: React.lazy(() => + fetchComponent().then((module) => ({ default: module.default })) + ), + children: [ + { + path: 'sales-selection', + component: BookingSelectionPage, + empAccess: 'Sales Screen', + }, + { + path: 'print-selection', + component: PrintSelectionPage, + empAccess: 'Print Forms', + }, + { + path: 'kiosk-selection', + component: KioskMainPage, + empAccess: 'Kiosk Screen', + }, + { + path: `barcode-qr-selection`, + component: BarcodeTemplateSetup, + empAccess: 'Barcode / QR', + }, + { + path: 'kiosk-component', + component: KioskComponentList, + access: 'Super Admin', + empAccess: 'Kiosk Component', + }, + { + path: 'component-master', + component: ComponentMasterList, + access: 'Super Admin', + empAccess: 'Component Master', + }, + { + path: 'barcode-master', + component: BarcodeComponentList, + access: 'Super Admin', + empAccess: 'Barcode Component', + }, + { + path: 'component-master/new', + component: (props) => , + access: 'Super Admin', + empAccess: 'Component Master', + }, + { + path: 'component-master/update', + component: (props) => ( + + ), + access: 'Super Admin', + empAccess: 'Component Master', + }, + { + path: 'theme-creation', + component: ThemeCreation, + access: 'Super Admin', + empAccess: 'Theme Creation', + }, + { + path: 'themeselection/new', + component: (props) => , + access: 'Super Admin', + empAccess: 'Theme Creation', + }, + { + path: 'themeselection/update', + component: (props) => , + access: 'Super Admin', + empAccess: 'Theme Creation', + }, + ], + }, +]; +// this is vite file +import { defineConfig } from "vite"; +import react from "@vitejs/plugin-react"; + +export default defineConfig(({ mode }) => { + const isProd = mode === "production"; + + return { + plugins: [react()], + + base: isProd ? "/apps/retail/" : "/", //for capcitor base: isProd ? "/" : "/", + + envDir: "src", + envPrefix: "ENV_", + + server: { + host: true, // ๐Ÿ”ฅ auto detect your IP + port: process.env.PORT || 3015, + }, + + build: { + minify: "esbuild", + esbuild: { + drop: isProd ? ["console", "debugger"] : [], + }, + }, + }; +}); +/// android xml file ; + + + + + + + + + + + + + + + + + + + + + + + + +//pathfile android\app\src\main\res\xml\file_paths.xml + + + + + +///package.json + +{ + "name": "retail-application", + "private": true, + "version": "0.0.0", + "type": "module", + "scripts": { + "dev": "vite", + "build": "node --max-old-space-size=4096 node_modules/vite/bin/vite.js build", + "lint": "eslint . --ext js,jsx --report-unused-disable-directives --max-warnings 0", + "preview": "vite preview", + "format": "prettier --write ." + }, + "dependencies": { + "@ant-design/plots": "^2.6.8", + "@capacitor-community/file-opener": "^8.0.0", + "@capacitor-community/speech-recognition": "^7.0.1", + "@capacitor-mlkit/barcode-scanning": "^8.0.1", + "@capacitor/android": "^8.3.0", + "@capacitor/app": "^8.0.1", + "@capacitor/cli": "^8.3.0", + "@capacitor/core": "^8.3.0", + "@capacitor/filesystem": "^8.1.2", + "@dnd-kit/core": "^6.3.1", + "@dnd-kit/sortable": "^10.0.0", + "@emotion/react": "^11.11.4", + "@emotion/styled": "^11.11.5", + "@mui/material": "^5.15.18", + "@react-google-maps/api": "^2.20.8", + "@reduxjs/toolkit": "^1.9.5", + "@tanstack/react-query": "^5.90.11", + "@tanstack/react-query-devtools": "^5.91.1", + "@tanstack/react-virtual": "^3.13.18", + "@types/node": "^25.5.0", + "@vitejs/plugin-legacy": "^8.0.1", + "@zxing/library": "^0.21.3", + "antd": "^5.17.4", + "antd-img-crop": "^4.22.0", + "aos": "^2.3.4", + "apexcharts": "^5.10.4", + "axios": "^1.13.6", + "browser-image-compression": "^2.0.2", + "classnames": "^2.5.1", + "cropperjs": "^1.6.2", + "crypto-js": "^4.1.1", + "date-fns": "^4.1.0", + "devtools-detect": "^4.0.2", + "exceljs": "^4.4.0", + "file-saver": "^2.0.5", + "history": "^5.3.0", + "html2canvas": "^1.4.1", + "html2pdf": "^0.0.11", + "html5-qrcode": "^2.3.8", + "jquery": "^3.7.1", + "js-cookie": "^3.0.5", + "jsbarcode": "^3.11.6", + "jspdf": "^4.2.1", + "lucide": "^0.577.0", + "lucide-react": "^0.536.0", + "moment": "^2.30.1", + "number-to-words": "^1.2.4", + "pdf-lib": "^1.17.1", + "qr-scanner": "^1.4.2", + "qrcode": "^1.5.3", + "qrcode.react": "^4.2.0", + "react": "^18.3.1", + "react-apexcharts": "^2.1.0", + "react-beautiful-dnd": "^13.1.1", + "react-color": "^2.19.3", + "react-countup": "^6.5.3", + "react-device-detect": "^2.2.3", + "react-dom": "^18.3.1", + "react-icons": "^4.12.0", + "react-image-crop": "^11.0.10", + "react-qr-code": "^2.0.13", + "react-redux": "^8.1.2", + "react-router-dom": "^6.23.1", + "react-select": "^5.8.0", + "react-signature-canvas": "^1.0.7", + "react-speech-recognition": "^3.10.0", + "react-timer-hook": "^3.0.7", + "react-transition-group": "^4.4.5", + "recharts": "^3.5.0", + "string-similarity": "^4.0.4", + "tesseract.js": "^6.0.0", + "universal-cookie": "^8.0.1", + "webfontloader": "^1.6.28", + "zustand": "^5.0.8" + }, + "devDependencies": { + "@types/react": "^18.3.3", + "@types/react-dom": "^18.3.0", + "@vitejs/plugin-react": "^6.0.1", + "esbuild": "^0.27.4", + "eslint": "^8.57.0", + "eslint-plugin-react": "^7.34.2", + "eslint-plugin-react-hooks": "^4.6.2", + "eslint-plugin-react-refresh": "^0.4.7", + "prettier": "^3.5.3", + "rollup-plugin-obfuscator": "^1.1.0", + "sass": "^1.98.0", + "terser": "^5.31.3", + "vite": "^8.0.0", + "vite-plugin-obfuscator": "^1.0.5", + "vite-plugin-remove-console": "^2.2.0" + } +} +