From 46ff0f8d27f63a5059382e579022fcf11db4c484 Mon Sep 17 00:00:00 2001 From: Srinath Date: Mon, 23 Mar 2026 10:47:26 +0530 Subject: [PATCH 1/3] Implement date range feature with disabled out-of-range dates --- .../OtherConponents/Reprint/ReprintPDFDataShare.jsx | 8 ++++++-- src/Pages/Product/ExcelUpload.jsx | 9 +++++++++ 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/src/Pages/BookingScreen/Components/OtherConponents/Reprint/ReprintPDFDataShare.jsx b/src/Pages/BookingScreen/Components/OtherConponents/Reprint/ReprintPDFDataShare.jsx index d36f282..fb98ef1 100644 --- a/src/Pages/BookingScreen/Components/OtherConponents/Reprint/ReprintPDFDataShare.jsx +++ b/src/Pages/BookingScreen/Components/OtherConponents/Reprint/ReprintPDFDataShare.jsx @@ -12,6 +12,7 @@ import { uploadImage } from "../../../../../Features/upload/upload"; import { SelfBookingEmailSendLink } from "../../../../../Features/ConfigMasterPage/ConfigMasterPage"; import { Messages } from "../../../../../Components/Notifications/Messages"; const { RangePicker } = DatePicker; +import dayjs from "dayjs"; const uploadApiUrl = import.meta.env.ENV_IMAGE_UPLOAD_API_URL; const ReprintPDFDataShare = ({ printDatas, printerTemplateStyle, SettingDataSelector, open = false, onClose = () => { } }) => { @@ -40,7 +41,9 @@ const ReprintPDFDataShare = ({ printDatas, printerTemplateStyle, SettingDataSele fetchData(dateStrings); } }; - +const disabledDate = (current) => { + return current && current > dayjs().endOf("day"); +}; const fetchData = async (dates = dateStrings) => { setIsFetching(true); try { @@ -184,8 +187,9 @@ Thank you for choosing us!`;
diff --git a/src/Pages/Product/ExcelUpload.jsx b/src/Pages/Product/ExcelUpload.jsx index 367bd07..f452a3f 100644 --- a/src/Pages/Product/ExcelUpload.jsx +++ b/src/Pages/Product/ExcelUpload.jsx @@ -606,6 +606,8 @@ const ProductExcel = ({ const [loading, setLoading] = useState(false); const [message, setMessage] = useState(false); const [Datas, setDatas] = useState(); + console.log(Datas, 'Datas32323232'); + const [currentPage, setCurrentPage] = useState(1); const [MappingOpen, setMappingOpen] = useState(false); const [fieldMapping, setFieldMapping] = useState({}); @@ -843,6 +845,7 @@ const ProductExcel = ({ }; const handleFileUpload = (e) => { + const file = e.target.files[0]; const reader = new FileReader(); @@ -999,6 +1002,12 @@ const ProductExcel = ({ item['Product Varient Name'] === undefined ? 'Variant 1' : item['Product Varient Name'], + 'Manufacture Date': + item['Manufacture Date'] == 'NaN-NaN-NaN' ? '' : item['Manufacture Date'], + 'Expire Date': + item['Expire Date'] == 'NaN-NaN-NaN' ? '' : item['Expire Date'], + 'Available From': + item['Available From'] == 'NaN-NaN-NaN' ? '' : item['Available From'], 'Available To': item['Available To'] == 'NaN-NaN-NaN' ? '' : item['Available To'], ProdId: item['ProdId'] || null, From cf77675d5a8e4b2f36c69edd5ddf73575b1ca68e Mon Sep 17 00:00:00 2001 From: Srinath Date: Mon, 23 Mar 2026 10:53:39 +0530 Subject: [PATCH 2/3] Fix issue with variant editing --- src/Pages/Product/ProductForm.jsx | 54 ++++++++++++++++++------------- 1 file changed, 31 insertions(+), 23 deletions(-) diff --git a/src/Pages/Product/ProductForm.jsx b/src/Pages/Product/ProductForm.jsx index b312e56..f1cf7a1 100644 --- a/src/Pages/Product/ProductForm.jsx +++ b/src/Pages/Product/ProductForm.jsx @@ -629,6 +629,10 @@ const ProductForm = ({ formType }) => { }, [editstate?.Rack, RackData]); useEffect(() => { + // Auto-fill "Variant X" only when we are adding a new variant. + // When editing, another effect will populate the full data. + if (!openVariant || variantEdit) return; + let variantAddData11 = [...variantPriceData]; if (variantAddData11?.length > 0) { const lastAddProdVariantName11 = @@ -677,7 +681,32 @@ const ProductForm = ({ formType }) => { ProdVariantName: `Variant ${parseInt(variantAddData11?.length) + parseInt(2)}`, }); } - }, [openVariant]); + }, [openVariant, variantEdit, variantPriceData]); + + useEffect(() => { + // Populate edit values only after the variant form is mounted. + if (!openVariant || !variantEdit) return; + if ( + variantEditIndex === undefined || + variantEditIndex === null || + !variantPriceData?.length + ) { + return; + } + + const row = variantPriceData?.[variantEditIndex]; + if (!row) return; + + formVariantRef?.current?.setFieldsValue({ + ProdVariantName: row?.ProdVariantName, + AmountOfPiece: row?.OnePcsPrice, + MRP: row?.MRP, + SellPrice: row?.SellPrice, + WhSalePrice: row?.WhSalePrice, + OfferPrice: row?.OfferPrice, + SpecialPrice: row?.SpecialPrice, + }); + }, [openVariant, variantEdit, variantEditIndex, variantPriceData]); const onComplete = useCallback(() => { setMessageData(null); @@ -1573,28 +1602,7 @@ const ProductForm = ({ formType }) => { }; const variantActionsFormatter = (row, index) => { - if (StockOpen == 'Y') { - formVariantRef?.current?.setFieldsValue({ - ProdVariantName: row?.ProdVariantName, - AmountOfPiece: row?.OnePcsPrice, - MRP: row?.MRP, - SellPrice: row?.SellPrice, - WhSalePrice: row?.WhSalePrice, - OfferPrice: row?.OfferPrice, - SpecialPrice: row?.SpecialPrice, - }); - } else { - formVariantRef?.current?.setFieldsValue({ - ProdVariantName: row?.ProdVariantName, - AmountOfPiece: row?.OnePcsPrice, - MRP: row?.MRP, - SellPrice: row?.SellPrice, - WhSalePrice: row?.WhSalePrice, - OfferPrice: row?.OfferPrice, - SpecialPrice: row?.SpecialPrice, - }); - } - + setOpenVariant(true); setVariantEdit(true); setVariantEditIndex(index); }; From 012d3124ef3a9ebd9fb69dd027fd20e80b3c15dd Mon Sep 17 00:00:00 2001 From: Srinath Date: Mon, 23 Mar 2026 10:55:21 +0530 Subject: [PATCH 3/3] Fix issues with date, subcategory, category, and brand --- src/Pages/Product/ExcelUpload.jsx | 270 ++++++++++++++++++++++++------ 1 file changed, 215 insertions(+), 55 deletions(-) diff --git a/src/Pages/Product/ExcelUpload.jsx b/src/Pages/Product/ExcelUpload.jsx index f452a3f..18e7388 100644 --- a/src/Pages/Product/ExcelUpload.jsx +++ b/src/Pages/Product/ExcelUpload.jsx @@ -960,15 +960,28 @@ const ProductExcel = ({ const rows = nonEmptyRows.slice(1); const dateFields = [ - 'Available From', - 'Available To', 'Manufacture Date', 'Expire Date', 'Stock Date', ]; function convertToDisplayFormat(dateString) { + if (!dateString) return ''; + // Handle DD/MM/YY or DD/MM/YYYY (from Excel dateNF format) + const slashParts = String(dateString).split('/'); + if (slashParts.length === 3) { + const [d, m, y] = slashParts; + const fullYear = y.length === 2 ? '20' + y : y; + return `${d.padStart(2,'0')}-${m.padStart(2,'0')}-${fullYear}`; + } + // Handle DD-MM-YYYY already in correct format + const dashParts = String(dateString).split('-'); + if (dashParts.length === 3 && dashParts[2].length === 4) { + return dateString; // already DD-MM-YYYY + } + // Fallback: try native Date parse (YYYY-MM-DD etc) const date = new Date(dateString); + if (isNaN(date.getTime())) return ''; const day = date.getDate().toString().padStart(2, '0'); const month = (date.getMonth() + 1).toString().padStart(2, '0'); const year = date.getFullYear().toString(); @@ -1070,9 +1083,9 @@ const ProductExcel = ({ }; const updateImageUrl = (url, index, key) => { + const newData1 = [...Datas]; newData1[key] = { ...newData1[key], Productimage: url }; - setDatas(newData1); setExcelData(newData1); }; @@ -1087,7 +1100,7 @@ const ProductExcel = ({ if (selectedImageIndex != null && selectedImageIndex != undefined) { try { - if (selectedImage.image !== undefined) { + if (selectedImage?.image !== undefined) { const response = await fetch(selectedImage.image); const datas = await response.blob(); const metadata = { @@ -1305,13 +1318,7 @@ const ProductExcel = ({ validation: { type: 'list', allowBlank: true, - formulae: [ - '"' + - (typeof CategoryNames !== 'undefined' - ? CategoryNames.join(',') - : 'Sample Category') + - '"', - ], + formulae: [`Sheet2!$B$2:$B$${(CategoryNames?.length || 0) + 1}`], }, sampleValue: sampleData?.category || 'Sample Category', headerColor: 'FF2929', @@ -1324,7 +1331,7 @@ const ProductExcel = ({ ...headerStyle, font: { bold: true, color: { argb: '#000000' } }, }, - validation: null, + validation: null, // set dynamically per row below sampleValue: sampleData?.subCategory || 'Sample Sub Category', headerColor: '52c41a', }, @@ -1336,7 +1343,7 @@ const ProductExcel = ({ ...headerStyle, font: { bold: true, color: { argb: '#000000' } }, }, - validation: null, + validation: null, // set dynamically per row below sampleValue: sampleData?.brand || 'Sample Brand', headerColor: '52c41a', }, @@ -1448,20 +1455,8 @@ const ProductExcel = ({ ...headerStyle, font: { bold: true, color: { argb: '#000000' } }, }, - validation: { - type: 'list', - allowBlank: true, - formulae: [ - '"' + - (typeof TaxDatas !== 'undefined' - ? TaxDatas.map((item) => - item.replace(/,/g, '').replace('-', '-').trim() - ).join(',') - : 'NIL - 0%') + - '"', - ], - }, - sampleValue: 'NIL - 0%', + validation: null, // set via Sheet2 range reference below + sampleValue: sampleData?.tax || 'NIL - 0%', headerColor: '52c41a', }, AutoGenerateQr: { @@ -1510,7 +1505,7 @@ const ProductExcel = ({ }, OnePiecePrice: { header: 'OnePiece Price', - key: 'StockAvailable', + key: 'OnePiecePrice', width: 20, style: { ...headerStyle, @@ -1529,7 +1524,7 @@ const ProductExcel = ({ }, AutoGenOnePieceQr: { header: 'Auto Generate One Piece Qrcode', - key: 'StockDate', + key: 'AutoGenOnePieceQr', width: 30, style: { ...headerStyle, @@ -1545,7 +1540,7 @@ const ProductExcel = ({ }, AutoGenOnePieceQrNum: { header: 'Auto Generate One Piece Qrcode Number', - key: 'StockDate', + key: 'AutoGenOnePieceQrNum', width: 40, style: { ...headerStyle, @@ -1629,27 +1624,31 @@ const ProductExcel = ({ }, AvailableFrom: { header: 'Available From', - key: 'AvailableFrom TIME', + key: 'AvailableFrom', width: 20, style: { ...headerStyle, font: { bold: true, color: { argb: '#000000' } }, + numFmt: '@', }, validation: null, - sampleValue: new Date(), + sampleValue: '08:00:00', headerColor: '52c41a', + isTimeField: true, }, AvailableTo: { header: 'Available To', - key: 'AvailableTo TIME', + key: 'AvailableTo', width: 20, style: { ...headerStyle, font: { bold: true, color: { argb: '#000000' } }, + numFmt: '@', }, validation: null, - sampleValue: new Date(), + sampleValue: '22:00:00', headerColor: '52c41a', + isTimeField: true, }, }; @@ -1781,11 +1780,26 @@ const ProductExcel = ({ }; }); - // Add sample data in row 2 - + // Add sample data in row 2 — time fields forced to text format selectedColumns.forEach((config, index) => { - const columnLetter = getExcelColumnLetter(index + 1); // ✅ FIXED - worksheet.getCell(`${columnLetter}2`).value = config.sampleValue; + 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 @@ -1812,29 +1826,42 @@ const ProductExcel = ({ } }); +// // 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({}); } - // 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 }; - }); + // 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 }; + } } - // 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 }; - }); + // 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('', { @@ -2158,6 +2185,139 @@ const ProductExcel = ({ }); } + // 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') @@ -2536,7 +2696,7 @@ const ProductExcel = ({
updateImageUrl(url, index)} + updateImageUrl={(url) => updateImageUrl(url, index, record.key)} // ImageLink={record.Productimage || ""} ImageLink={ onlineImage