Add product search and template creation functionality to validation step
This commit is contained in:
@@ -566,6 +566,9 @@ router.get('/field-options', async (req, res) => {
|
|||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Add debugging to verify category types
|
||||||
|
console.log(`Returning ${result.categories.length} categories with types: ${Array.from(new Set(result.categories.map(c => c.type))).join(', ')}`);
|
||||||
|
|
||||||
res.json(result);
|
res.json(result);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Error fetching import field options:', error);
|
console.error('Error fetching import field options:', error);
|
||||||
@@ -715,4 +718,232 @@ router.get('/list-uploads', (req, res) => {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Search products from production database
|
||||||
|
router.get('/search-products', async (req, res) => {
|
||||||
|
const { q, company, dateRange } = req.query;
|
||||||
|
|
||||||
|
if (!q) {
|
||||||
|
return res.status(400).json({ error: 'Search term is required' });
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
const { connection } = await getDbConnection();
|
||||||
|
|
||||||
|
// Build WHERE clause with additional filters
|
||||||
|
let whereClause = `
|
||||||
|
WHERE (
|
||||||
|
p.description LIKE ? OR
|
||||||
|
p.itemnumber LIKE ? OR
|
||||||
|
p.upc LIKE ? OR
|
||||||
|
pc1.name LIKE ? OR
|
||||||
|
s.companyname LIKE ?
|
||||||
|
)`;
|
||||||
|
|
||||||
|
// Add company filter if provided
|
||||||
|
if (company) {
|
||||||
|
whereClause += ` AND p.company = ${connection.escape(company)}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add date range filter if provided
|
||||||
|
if (dateRange) {
|
||||||
|
let dateCondition;
|
||||||
|
const now = new Date();
|
||||||
|
|
||||||
|
switch(dateRange) {
|
||||||
|
case '1week':
|
||||||
|
// Last week: date is after (current date - 7 days)
|
||||||
|
const weekAgo = new Date(now);
|
||||||
|
weekAgo.setDate(now.getDate() - 7);
|
||||||
|
dateCondition = `p.datein >= ${connection.escape(weekAgo.toISOString().slice(0, 10))}`;
|
||||||
|
break;
|
||||||
|
case '1month':
|
||||||
|
// Last month: date is after (current date - 30 days)
|
||||||
|
const monthAgo = new Date(now);
|
||||||
|
monthAgo.setDate(now.getDate() - 30);
|
||||||
|
dateCondition = `p.datein >= ${connection.escape(monthAgo.toISOString().slice(0, 10))}`;
|
||||||
|
break;
|
||||||
|
case '2months':
|
||||||
|
// Last 2 months: date is after (current date - 60 days)
|
||||||
|
const twoMonthsAgo = new Date(now);
|
||||||
|
twoMonthsAgo.setDate(now.getDate() - 60);
|
||||||
|
dateCondition = `p.datein >= ${connection.escape(twoMonthsAgo.toISOString().slice(0, 10))}`;
|
||||||
|
break;
|
||||||
|
case '3months':
|
||||||
|
// Last 3 months: date is after (current date - 90 days)
|
||||||
|
const threeMonthsAgo = new Date(now);
|
||||||
|
threeMonthsAgo.setDate(now.getDate() - 90);
|
||||||
|
dateCondition = `p.datein >= ${connection.escape(threeMonthsAgo.toISOString().slice(0, 10))}`;
|
||||||
|
break;
|
||||||
|
case '6months':
|
||||||
|
// Last 6 months: date is after (current date - 180 days)
|
||||||
|
const sixMonthsAgo = new Date(now);
|
||||||
|
sixMonthsAgo.setDate(now.getDate() - 180);
|
||||||
|
dateCondition = `p.datein >= ${connection.escape(sixMonthsAgo.toISOString().slice(0, 10))}`;
|
||||||
|
break;
|
||||||
|
case '1year':
|
||||||
|
// Last year: date is after (current date - 365 days)
|
||||||
|
const yearAgo = new Date(now);
|
||||||
|
yearAgo.setDate(now.getDate() - 365);
|
||||||
|
dateCondition = `p.datein >= ${connection.escape(yearAgo.toISOString().slice(0, 10))}`;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
// If an unrecognized value is provided, don't add a date condition
|
||||||
|
dateCondition = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dateCondition) {
|
||||||
|
whereClause += ` AND ${dateCondition}`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Special case for wildcard search
|
||||||
|
const isWildcardSearch = q === '*';
|
||||||
|
const searchPattern = isWildcardSearch ? '%' : `%${q}%`;
|
||||||
|
const exactPattern = isWildcardSearch ? '%' : q;
|
||||||
|
|
||||||
|
// Search for products based on various fields
|
||||||
|
const query = `
|
||||||
|
SELECT
|
||||||
|
p.pid,
|
||||||
|
p.description AS title,
|
||||||
|
p.notes AS description,
|
||||||
|
p.itemnumber AS sku,
|
||||||
|
p.upc AS barcode,
|
||||||
|
p.harmonized_tariff_code,
|
||||||
|
pcp.price_each AS price,
|
||||||
|
p.sellingprice AS regular_price,
|
||||||
|
CASE
|
||||||
|
WHEN EXISTS (SELECT 1 FROM product_inventory WHERE pid = p.pid AND count > 0)
|
||||||
|
THEN (SELECT ROUND(AVG(costeach), 5) FROM product_inventory WHERE pid = p.pid AND count > 0)
|
||||||
|
ELSE (SELECT costeach FROM product_inventory WHERE pid = p.pid ORDER BY daterec DESC LIMIT 1)
|
||||||
|
END AS cost_price,
|
||||||
|
s.companyname AS vendor,
|
||||||
|
sid.supplier_itemnumber AS vendor_reference,
|
||||||
|
sid.notions_itemnumber AS notions_reference,
|
||||||
|
pc1.name AS brand,
|
||||||
|
p.company AS brand_id,
|
||||||
|
pc2.name AS line,
|
||||||
|
p.line AS line_id,
|
||||||
|
pc3.name AS subline,
|
||||||
|
p.subline AS subline_id,
|
||||||
|
pc4.name AS artist,
|
||||||
|
p.artist AS artist_id,
|
||||||
|
COALESCE(CASE
|
||||||
|
WHEN sid.supplier_id = 92 THEN sid.notions_qty_per_unit
|
||||||
|
ELSE sid.supplier_qty_per_unit
|
||||||
|
END, sid.notions_qty_per_unit) AS moq,
|
||||||
|
p.weight,
|
||||||
|
p.length,
|
||||||
|
p.width,
|
||||||
|
p.height,
|
||||||
|
p.country_of_origin,
|
||||||
|
p.totalsold AS total_sold,
|
||||||
|
p.datein AS first_received,
|
||||||
|
pls.date_sold AS date_last_sold
|
||||||
|
FROM products p
|
||||||
|
LEFT JOIN product_current_prices pcp ON p.pid = pcp.pid AND pcp.active = 1
|
||||||
|
LEFT JOIN supplier_item_data sid ON p.pid = sid.pid
|
||||||
|
LEFT JOIN suppliers s ON sid.supplier_id = s.supplierid
|
||||||
|
LEFT JOIN product_categories pc1 ON p.company = pc1.cat_id
|
||||||
|
LEFT JOIN product_categories pc2 ON p.line = pc2.cat_id
|
||||||
|
LEFT JOIN product_categories pc3 ON p.subline = pc3.cat_id
|
||||||
|
LEFT JOIN product_categories pc4 ON p.artist = pc4.cat_id
|
||||||
|
LEFT JOIN product_last_sold pls ON p.pid = pls.pid
|
||||||
|
${whereClause}
|
||||||
|
GROUP BY p.pid
|
||||||
|
${isWildcardSearch ? 'ORDER BY p.datein DESC' : `
|
||||||
|
ORDER BY
|
||||||
|
CASE
|
||||||
|
WHEN p.description LIKE ? THEN 1
|
||||||
|
WHEN p.itemnumber = ? THEN 2
|
||||||
|
WHEN p.upc = ? THEN 3
|
||||||
|
WHEN pc1.name LIKE ? THEN 4
|
||||||
|
WHEN s.companyname LIKE ? THEN 5
|
||||||
|
ELSE 6
|
||||||
|
END
|
||||||
|
`}
|
||||||
|
`;
|
||||||
|
|
||||||
|
// Prepare query parameters based on whether it's a wildcard search
|
||||||
|
let queryParams;
|
||||||
|
if (isWildcardSearch) {
|
||||||
|
queryParams = [
|
||||||
|
searchPattern, // LIKE for description
|
||||||
|
searchPattern, // LIKE for itemnumber
|
||||||
|
searchPattern, // LIKE for upc
|
||||||
|
searchPattern, // LIKE for brand name
|
||||||
|
searchPattern // LIKE for company name
|
||||||
|
];
|
||||||
|
} else {
|
||||||
|
queryParams = [
|
||||||
|
searchPattern, // LIKE for description
|
||||||
|
searchPattern, // LIKE for itemnumber
|
||||||
|
searchPattern, // LIKE for upc
|
||||||
|
searchPattern, // LIKE for brand name
|
||||||
|
searchPattern, // LIKE for company name
|
||||||
|
// For ORDER BY clause
|
||||||
|
searchPattern, // LIKE for description
|
||||||
|
exactPattern, // Exact match for itemnumber
|
||||||
|
exactPattern, // Exact match for upc
|
||||||
|
searchPattern, // LIKE for brand name
|
||||||
|
searchPattern // LIKE for company name
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
const [results] = await connection.query(query, queryParams);
|
||||||
|
|
||||||
|
res.json(results);
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error searching products:', error);
|
||||||
|
res.status(500).json({ error: 'Failed to search products' });
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Get product categories for a specific product
|
||||||
|
router.get('/product-categories/:pid', async (req, res) => {
|
||||||
|
try {
|
||||||
|
const { pid } = req.params;
|
||||||
|
|
||||||
|
if (!pid || isNaN(parseInt(pid))) {
|
||||||
|
return res.status(400).json({ error: 'Valid product ID is required' });
|
||||||
|
}
|
||||||
|
|
||||||
|
// Use the getDbConnection function instead of getPool
|
||||||
|
const { connection } = await getDbConnection();
|
||||||
|
|
||||||
|
// Query to get categories for a specific product
|
||||||
|
const query = `
|
||||||
|
SELECT pc.cat_id, pc.name, pc.type, pc.combined_name
|
||||||
|
FROM product_category_index pci
|
||||||
|
JOIN product_categories pc ON pci.cat_id = pc.cat_id
|
||||||
|
WHERE pci.pid = ?
|
||||||
|
ORDER BY pc.type, pc.name
|
||||||
|
`;
|
||||||
|
|
||||||
|
const [rows] = await connection.query(query, [pid]);
|
||||||
|
|
||||||
|
// Add debugging to log category types
|
||||||
|
const categoryTypes = rows.map(row => row.type);
|
||||||
|
const uniqueTypes = [...new Set(categoryTypes)];
|
||||||
|
console.log(`Product ${pid} has ${rows.length} categories with types: ${uniqueTypes.join(', ')}`);
|
||||||
|
console.log('Categories:', rows.map(row => ({ id: row.cat_id, name: row.name, type: row.type })));
|
||||||
|
|
||||||
|
// Format the response to match the expected format in the frontend
|
||||||
|
const categories = rows.map(category => ({
|
||||||
|
value: category.cat_id.toString(),
|
||||||
|
label: category.name,
|
||||||
|
type: category.type,
|
||||||
|
combined_name: category.combined_name
|
||||||
|
}));
|
||||||
|
|
||||||
|
res.json(categories);
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error fetching product categories:', error);
|
||||||
|
res.status(500).json({
|
||||||
|
error: 'Failed to fetch product categories',
|
||||||
|
details: error.message
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
module.exports = router;
|
module.exports = router;
|
||||||
260
inventory/package-lock.json
generated
260
inventory/package-lock.json
generated
@@ -42,7 +42,7 @@
|
|||||||
"@radix-ui/react-scroll-area": "^1.2.2",
|
"@radix-ui/react-scroll-area": "^1.2.2",
|
||||||
"@radix-ui/react-select": "^2.1.4",
|
"@radix-ui/react-select": "^2.1.4",
|
||||||
"@radix-ui/react-separator": "^1.1.1",
|
"@radix-ui/react-separator": "^1.1.1",
|
||||||
"@radix-ui/react-slot": "^1.1.1",
|
"@radix-ui/react-slot": "^1.1.2",
|
||||||
"@radix-ui/react-switch": "^1.1.2",
|
"@radix-ui/react-switch": "^1.1.2",
|
||||||
"@radix-ui/react-tabs": "^1.1.2",
|
"@radix-ui/react-tabs": "^1.1.2",
|
||||||
"@radix-ui/react-toast": "^1.2.6",
|
"@radix-ui/react-toast": "^1.2.6",
|
||||||
@@ -57,6 +57,7 @@
|
|||||||
"@tanstack/virtual-core": "^3.11.2",
|
"@tanstack/virtual-core": "^3.11.2",
|
||||||
"@types/js-levenshtein": "^1.1.3",
|
"@types/js-levenshtein": "^1.1.3",
|
||||||
"@types/uuid": "^10.0.0",
|
"@types/uuid": "^10.0.0",
|
||||||
|
"axios": "^1.8.1",
|
||||||
"chakra-react-select": "^4.7.5",
|
"chakra-react-select": "^4.7.5",
|
||||||
"chakra-ui-steps": "^2.0.4",
|
"chakra-ui-steps": "^2.0.4",
|
||||||
"chart.js": "^4.4.7",
|
"chart.js": "^4.4.7",
|
||||||
@@ -5316,6 +5317,12 @@
|
|||||||
"node": ">=10"
|
"node": ">=10"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/asynckit": {
|
||||||
|
"version": "0.4.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
|
||||||
|
"integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
"node_modules/attr-accept": {
|
"node_modules/attr-accept": {
|
||||||
"version": "2.2.5",
|
"version": "2.2.5",
|
||||||
"resolved": "https://registry.npmjs.org/attr-accept/-/attr-accept-2.2.5.tgz",
|
"resolved": "https://registry.npmjs.org/attr-accept/-/attr-accept-2.2.5.tgz",
|
||||||
@@ -5363,6 +5370,17 @@
|
|||||||
"postcss": "^8.1.0"
|
"postcss": "^8.1.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/axios": {
|
||||||
|
"version": "1.8.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/axios/-/axios-1.8.1.tgz",
|
||||||
|
"integrity": "sha512-NN+fvwH/kV01dYUQ3PTOZns4LWtWhOFCAhQ/pHb88WQ1hNe5V/dvFwc4VJcDL11LT9xSX0QtsR8sWUuyOuOq7g==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"follow-redirects": "^1.15.6",
|
||||||
|
"form-data": "^4.0.0",
|
||||||
|
"proxy-from-env": "^1.1.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/babel-plugin-macros": {
|
"node_modules/babel-plugin-macros": {
|
||||||
"version": "3.1.0",
|
"version": "3.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/babel-plugin-macros/-/babel-plugin-macros-3.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/babel-plugin-macros/-/babel-plugin-macros-3.1.0.tgz",
|
||||||
@@ -5507,6 +5525,19 @@
|
|||||||
"ieee754": "^1.2.1"
|
"ieee754": "^1.2.1"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/call-bind-apply-helpers": {
|
||||||
|
"version": "1.0.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz",
|
||||||
|
"integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"es-errors": "^1.3.0",
|
||||||
|
"function-bind": "^1.1.2"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 0.4"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/callsites": {
|
"node_modules/callsites": {
|
||||||
"version": "3.1.0",
|
"version": "3.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz",
|
||||||
@@ -6185,6 +6216,18 @@
|
|||||||
"integrity": "sha512-zW190nQTIoXcGCaU08DvVNFTmQhUpnJfVuAKfWqUQkflXKpaDdpaYoM0iluLS9lgJNHyBF58KKA2FBEwkD7wog==",
|
"integrity": "sha512-zW190nQTIoXcGCaU08DvVNFTmQhUpnJfVuAKfWqUQkflXKpaDdpaYoM0iluLS9lgJNHyBF58KKA2FBEwkD7wog==",
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
|
"node_modules/combined-stream": {
|
||||||
|
"version": "1.0.8",
|
||||||
|
"resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz",
|
||||||
|
"integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"delayed-stream": "~1.0.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 0.8"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/commander": {
|
"node_modules/commander": {
|
||||||
"version": "10.0.1",
|
"version": "10.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/commander/-/commander-10.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/commander/-/commander-10.0.1.tgz",
|
||||||
@@ -6491,6 +6534,15 @@
|
|||||||
"url": "https://github.com/sponsors/sindresorhus"
|
"url": "https://github.com/sponsors/sindresorhus"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/delayed-stream": {
|
||||||
|
"version": "1.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
|
||||||
|
"integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==",
|
||||||
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=0.4.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/detect-node-es": {
|
"node_modules/detect-node-es": {
|
||||||
"version": "1.1.0",
|
"version": "1.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/detect-node-es/-/detect-node-es-1.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/detect-node-es/-/detect-node-es-1.1.0.tgz",
|
||||||
@@ -6528,6 +6580,20 @@
|
|||||||
"csstype": "^3.0.2"
|
"csstype": "^3.0.2"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/dunder-proto": {
|
||||||
|
"version": "1.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz",
|
||||||
|
"integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"call-bind-apply-helpers": "^1.0.1",
|
||||||
|
"es-errors": "^1.3.0",
|
||||||
|
"gopd": "^1.2.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 0.4"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/eastasianwidth": {
|
"node_modules/eastasianwidth": {
|
||||||
"version": "0.2.0",
|
"version": "0.2.0",
|
||||||
"resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz",
|
"resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz",
|
||||||
@@ -6556,6 +6622,51 @@
|
|||||||
"is-arrayish": "^0.2.1"
|
"is-arrayish": "^0.2.1"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/es-define-property": {
|
||||||
|
"version": "1.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz",
|
||||||
|
"integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==",
|
||||||
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 0.4"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/es-errors": {
|
||||||
|
"version": "1.3.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz",
|
||||||
|
"integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==",
|
||||||
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 0.4"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/es-object-atoms": {
|
||||||
|
"version": "1.1.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz",
|
||||||
|
"integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"es-errors": "^1.3.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 0.4"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/es-set-tostringtag": {
|
||||||
|
"version": "2.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz",
|
||||||
|
"integrity": "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"es-errors": "^1.3.0",
|
||||||
|
"get-intrinsic": "^1.2.6",
|
||||||
|
"has-tostringtag": "^1.0.2",
|
||||||
|
"hasown": "^2.0.2"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 0.4"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/esbuild": {
|
"node_modules/esbuild": {
|
||||||
"version": "0.24.2",
|
"version": "0.24.2",
|
||||||
"resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.24.2.tgz",
|
"resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.24.2.tgz",
|
||||||
@@ -7041,6 +7152,26 @@
|
|||||||
"node": ">=10"
|
"node": ">=10"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/follow-redirects": {
|
||||||
|
"version": "1.15.9",
|
||||||
|
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.9.tgz",
|
||||||
|
"integrity": "sha512-gew4GsXizNgdoRyqmyfMHyAmXsZDk6mHkSxZFCzW9gwlbtOW44CDtYavM+y+72qD/Vq2l550kMF52DT8fOLJqQ==",
|
||||||
|
"funding": [
|
||||||
|
{
|
||||||
|
"type": "individual",
|
||||||
|
"url": "https://github.com/sponsors/RubenVerborgh"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=4.0"
|
||||||
|
},
|
||||||
|
"peerDependenciesMeta": {
|
||||||
|
"debug": {
|
||||||
|
"optional": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/foreground-child": {
|
"node_modules/foreground-child": {
|
||||||
"version": "3.3.0",
|
"version": "3.3.0",
|
||||||
"resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.3.0.tgz",
|
"resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.3.0.tgz",
|
||||||
@@ -7069,6 +7200,21 @@
|
|||||||
"url": "https://github.com/sponsors/isaacs"
|
"url": "https://github.com/sponsors/isaacs"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/form-data": {
|
||||||
|
"version": "4.0.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.2.tgz",
|
||||||
|
"integrity": "sha512-hGfm/slu0ZabnNt4oaRZ6uREyfCj6P4fT/n6A1rGV+Z0VdGXjfOhVUpkn6qVQONHGIFwmveGXyDs75+nr6FM8w==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"asynckit": "^0.4.0",
|
||||||
|
"combined-stream": "^1.0.8",
|
||||||
|
"es-set-tostringtag": "^2.1.0",
|
||||||
|
"mime-types": "^2.1.12"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 6"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/formdata-polyfill": {
|
"node_modules/formdata-polyfill": {
|
||||||
"version": "4.0.10",
|
"version": "4.0.10",
|
||||||
"resolved": "https://registry.npmjs.org/formdata-polyfill/-/formdata-polyfill-4.0.10.tgz",
|
"resolved": "https://registry.npmjs.org/formdata-polyfill/-/formdata-polyfill-4.0.10.tgz",
|
||||||
@@ -7193,6 +7339,30 @@
|
|||||||
"node": ">=6.9.0"
|
"node": ">=6.9.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/get-intrinsic": {
|
||||||
|
"version": "1.3.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz",
|
||||||
|
"integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"call-bind-apply-helpers": "^1.0.2",
|
||||||
|
"es-define-property": "^1.0.1",
|
||||||
|
"es-errors": "^1.3.0",
|
||||||
|
"es-object-atoms": "^1.1.1",
|
||||||
|
"function-bind": "^1.1.2",
|
||||||
|
"get-proto": "^1.0.1",
|
||||||
|
"gopd": "^1.2.0",
|
||||||
|
"has-symbols": "^1.1.0",
|
||||||
|
"hasown": "^2.0.2",
|
||||||
|
"math-intrinsics": "^1.1.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 0.4"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/sponsors/ljharb"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/get-nonce": {
|
"node_modules/get-nonce": {
|
||||||
"version": "1.0.1",
|
"version": "1.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/get-nonce/-/get-nonce-1.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/get-nonce/-/get-nonce-1.0.1.tgz",
|
||||||
@@ -7202,6 +7372,19 @@
|
|||||||
"node": ">=6"
|
"node": ">=6"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/get-proto": {
|
||||||
|
"version": "1.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz",
|
||||||
|
"integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"dunder-proto": "^1.0.1",
|
||||||
|
"es-object-atoms": "^1.0.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 0.4"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/get-stream": {
|
"node_modules/get-stream": {
|
||||||
"version": "6.0.1",
|
"version": "6.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz",
|
||||||
@@ -7283,6 +7466,18 @@
|
|||||||
"url": "https://github.com/sponsors/sindresorhus"
|
"url": "https://github.com/sponsors/sindresorhus"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/gopd": {
|
||||||
|
"version": "1.2.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz",
|
||||||
|
"integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==",
|
||||||
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 0.4"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/sponsors/ljharb"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/graceful-fs": {
|
"node_modules/graceful-fs": {
|
||||||
"version": "4.2.11",
|
"version": "4.2.11",
|
||||||
"resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz",
|
"resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz",
|
||||||
@@ -7306,6 +7501,33 @@
|
|||||||
"node": ">=8"
|
"node": ">=8"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/has-symbols": {
|
||||||
|
"version": "1.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz",
|
||||||
|
"integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==",
|
||||||
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 0.4"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/sponsors/ljharb"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/has-tostringtag": {
|
||||||
|
"version": "1.0.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz",
|
||||||
|
"integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"has-symbols": "^1.0.3"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 0.4"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/sponsors/ljharb"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/hasown": {
|
"node_modules/hasown": {
|
||||||
"version": "2.0.2",
|
"version": "2.0.2",
|
||||||
"resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz",
|
||||||
@@ -7770,6 +7992,15 @@
|
|||||||
"react": "^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0"
|
"react": "^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/math-intrinsics": {
|
||||||
|
"version": "1.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz",
|
||||||
|
"integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==",
|
||||||
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 0.4"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/memoize-one": {
|
"node_modules/memoize-one": {
|
||||||
"version": "6.0.0",
|
"version": "6.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/memoize-one/-/memoize-one-6.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/memoize-one/-/memoize-one-6.0.0.tgz",
|
||||||
@@ -7804,6 +8035,27 @@
|
|||||||
"node": ">=8.6"
|
"node": ">=8.6"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/mime-db": {
|
||||||
|
"version": "1.52.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz",
|
||||||
|
"integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==",
|
||||||
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 0.6"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/mime-types": {
|
||||||
|
"version": "2.1.35",
|
||||||
|
"resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz",
|
||||||
|
"integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"mime-db": "1.52.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 0.6"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/mimic-fn": {
|
"node_modules/mimic-fn": {
|
||||||
"version": "4.0.0",
|
"version": "4.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-4.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-4.0.0.tgz",
|
||||||
@@ -8474,6 +8726,12 @@
|
|||||||
"react-is": "^16.13.1"
|
"react-is": "^16.13.1"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/proxy-from-env": {
|
||||||
|
"version": "1.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz",
|
||||||
|
"integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
"node_modules/punycode": {
|
"node_modules/punycode": {
|
||||||
"version": "2.3.1",
|
"version": "2.3.1",
|
||||||
"resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz",
|
"resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz",
|
||||||
|
|||||||
@@ -44,7 +44,7 @@
|
|||||||
"@radix-ui/react-scroll-area": "^1.2.2",
|
"@radix-ui/react-scroll-area": "^1.2.2",
|
||||||
"@radix-ui/react-select": "^2.1.4",
|
"@radix-ui/react-select": "^2.1.4",
|
||||||
"@radix-ui/react-separator": "^1.1.1",
|
"@radix-ui/react-separator": "^1.1.1",
|
||||||
"@radix-ui/react-slot": "^1.1.1",
|
"@radix-ui/react-slot": "^1.1.2",
|
||||||
"@radix-ui/react-switch": "^1.1.2",
|
"@radix-ui/react-switch": "^1.1.2",
|
||||||
"@radix-ui/react-tabs": "^1.1.2",
|
"@radix-ui/react-tabs": "^1.1.2",
|
||||||
"@radix-ui/react-toast": "^1.2.6",
|
"@radix-ui/react-toast": "^1.2.6",
|
||||||
@@ -59,6 +59,7 @@
|
|||||||
"@tanstack/virtual-core": "^3.11.2",
|
"@tanstack/virtual-core": "^3.11.2",
|
||||||
"@types/js-levenshtein": "^1.1.3",
|
"@types/js-levenshtein": "^1.1.3",
|
||||||
"@types/uuid": "^10.0.0",
|
"@types/uuid": "^10.0.0",
|
||||||
|
"axios": "^1.8.1",
|
||||||
"chakra-react-select": "^4.7.5",
|
"chakra-react-select": "^4.7.5",
|
||||||
"chakra-ui-steps": "^2.0.4",
|
"chakra-ui-steps": "^2.0.4",
|
||||||
"chart.js": "^4.4.7",
|
"chart.js": "^4.4.7",
|
||||||
|
|||||||
1569
inventory/src/components/products/ProductSearchDialog.tsx
Normal file
1569
inventory/src/components/products/ProductSearchDialog.tsx
Normal file
File diff suppressed because it is too large
Load Diff
@@ -296,24 +296,54 @@ export const ImageUploadStep = <T extends string>({
|
|||||||
// Get the current product
|
// Get the current product
|
||||||
const product = newData[productIndex];
|
const product = newData[productIndex];
|
||||||
|
|
||||||
// We need to update product_images array directly instead of the image_url field
|
// Initialize product_images array if it doesn't exist
|
||||||
if (!product.product_images) {
|
if (!product.product_images) {
|
||||||
product.product_images = [];
|
product.product_images = [];
|
||||||
} else if (typeof product.product_images === 'string') {
|
return newData;
|
||||||
// Handle case where it might be a comma-separated string
|
}
|
||||||
product.product_images = product.product_images.split(',').filter(Boolean);
|
|
||||||
|
// Handle different formats of product_images
|
||||||
|
let images: any[] = [];
|
||||||
|
|
||||||
|
if (typeof product.product_images === 'string') {
|
||||||
|
try {
|
||||||
|
// Try to parse as JSON
|
||||||
|
images = JSON.parse(product.product_images);
|
||||||
|
} catch (e) {
|
||||||
|
// If not JSON, split by comma if it's a string
|
||||||
|
images = product.product_images.split(',').filter(Boolean).map(url => ({
|
||||||
|
imageUrl: url.trim(),
|
||||||
|
pid: product.id || 0,
|
||||||
|
iid: 0,
|
||||||
|
type: 0,
|
||||||
|
order: 255,
|
||||||
|
width: 0,
|
||||||
|
height: 0,
|
||||||
|
hidden: 0
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
} else if (Array.isArray(product.product_images)) {
|
||||||
|
// Use the array directly
|
||||||
|
images = product.product_images;
|
||||||
|
} else if (product.product_images) {
|
||||||
|
// Handle case where it might be a single value
|
||||||
|
images = [product.product_images];
|
||||||
}
|
}
|
||||||
|
|
||||||
// Filter out the image URL we're removing
|
// Filter out the image URL we're removing
|
||||||
if (Array.isArray(product.product_images)) {
|
const filteredImages = images.filter(img => {
|
||||||
product.product_images = product.product_images.filter((url: string) => url && url !== imageUrl);
|
const imgUrl = typeof img === 'string' ? img : img.imageUrl;
|
||||||
}
|
return imgUrl !== imageUrl;
|
||||||
|
});
|
||||||
|
|
||||||
|
// Update the product_images field
|
||||||
|
product.product_images = filteredImages;
|
||||||
|
|
||||||
return newData;
|
return newData;
|
||||||
};
|
};
|
||||||
|
|
||||||
// Function to add an image URL to a product
|
// Function to add an image URL to a product
|
||||||
const addImageToProduct = (productIndex: number, imageUrl: string) => {
|
const addImageToProduct = (productIndex: number, imageUrl: string, imageData?: any) => {
|
||||||
// Create a copy of the data
|
// Create a copy of the data
|
||||||
const newData = [...data];
|
const newData = [...data];
|
||||||
|
|
||||||
@@ -323,21 +353,76 @@ export const ImageUploadStep = <T extends string>({
|
|||||||
// Initialize product_images array if it doesn't exist
|
// Initialize product_images array if it doesn't exist
|
||||||
if (!product.product_images) {
|
if (!product.product_images) {
|
||||||
product.product_images = [];
|
product.product_images = [];
|
||||||
} else if (typeof product.product_images === 'string') {
|
|
||||||
// Handle case where it might be a comma-separated string
|
|
||||||
product.product_images = product.product_images.split(',').filter(Boolean);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Ensure it's an array
|
// Handle different formats of product_images
|
||||||
if (!Array.isArray(product.product_images)) {
|
let images: any[] = [];
|
||||||
product.product_images = [product.product_images].filter(Boolean);
|
|
||||||
|
if (typeof product.product_images === 'string') {
|
||||||
|
try {
|
||||||
|
// Try to parse as JSON
|
||||||
|
images = JSON.parse(product.product_images);
|
||||||
|
} catch (e) {
|
||||||
|
// If not JSON, split by comma if it's a string
|
||||||
|
images = product.product_images.split(',').filter(Boolean).map(url => ({
|
||||||
|
imageUrl: url.trim(),
|
||||||
|
pid: product.id || 0,
|
||||||
|
iid: 0,
|
||||||
|
type: 0,
|
||||||
|
order: 255,
|
||||||
|
width: 0,
|
||||||
|
height: 0,
|
||||||
|
hidden: 0
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
} else if (Array.isArray(product.product_images)) {
|
||||||
|
// Use the array directly
|
||||||
|
images = product.product_images;
|
||||||
|
} else if (product.product_images) {
|
||||||
|
// Handle case where it might be a single value
|
||||||
|
images = [product.product_images];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Check if the image URL already exists
|
||||||
|
const exists = images.some(img => {
|
||||||
|
const imgUrl = typeof img === 'string' ? img : img.imageUrl;
|
||||||
|
return imgUrl === imageUrl;
|
||||||
|
});
|
||||||
|
|
||||||
// Only add if the URL doesn't already exist
|
// Only add if the URL doesn't already exist
|
||||||
if (!product.product_images.includes(imageUrl)) {
|
if (!exists) {
|
||||||
product.product_images.push(imageUrl);
|
// Create a new image object with schema fields
|
||||||
|
const newImage = imageData || {
|
||||||
|
imageUrl,
|
||||||
|
pid: product.id || 0,
|
||||||
|
iid: Math.floor(Math.random() * 10000), // Generate a temporary iid
|
||||||
|
type: 0,
|
||||||
|
order: images.length,
|
||||||
|
width: 0,
|
||||||
|
height: 0,
|
||||||
|
hidden: 0
|
||||||
|
};
|
||||||
|
|
||||||
|
// If imageData is a string, convert it to an object
|
||||||
|
if (typeof newImage === 'string') {
|
||||||
|
newImage = {
|
||||||
|
imageUrl: newImage,
|
||||||
|
pid: product.id || 0,
|
||||||
|
iid: Math.floor(Math.random() * 10000),
|
||||||
|
type: 0,
|
||||||
|
order: images.length,
|
||||||
|
width: 0,
|
||||||
|
height: 0,
|
||||||
|
hidden: 0
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
images.push(newImage);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Update the product_images field
|
||||||
|
product.product_images = images;
|
||||||
|
|
||||||
return newData;
|
return newData;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -530,7 +615,15 @@ export const ImageUploadStep = <T extends string>({
|
|||||||
productIndex,
|
productIndex,
|
||||||
imageUrl: '',
|
imageUrl: '',
|
||||||
loading: true,
|
loading: true,
|
||||||
fileName: file.name
|
fileName: file.name,
|
||||||
|
// Add schema fields
|
||||||
|
pid: data[productIndex].id || 0,
|
||||||
|
iid: 0, // Will be assigned by server
|
||||||
|
type: 0,
|
||||||
|
order: productImages.filter(img => img.productIndex === productIndex).length + i,
|
||||||
|
width: 0,
|
||||||
|
height: 0,
|
||||||
|
hidden: 0
|
||||||
};
|
};
|
||||||
|
|
||||||
setProductImages(prev => [...prev, newImage]);
|
setProductImages(prev => [...prev, newImage]);
|
||||||
@@ -559,13 +652,21 @@ export const ImageUploadStep = <T extends string>({
|
|||||||
setProductImages(prev =>
|
setProductImages(prev =>
|
||||||
prev.map(img =>
|
prev.map(img =>
|
||||||
(img.loading && img.productIndex === productIndex && img.fileName === file.name)
|
(img.loading && img.productIndex === productIndex && img.fileName === file.name)
|
||||||
? { ...img, imageUrl: result.imageUrl, loading: false }
|
? {
|
||||||
|
...img,
|
||||||
|
imageUrl: result.imageUrl,
|
||||||
|
loading: false,
|
||||||
|
// Update schema fields if returned from server
|
||||||
|
iid: result.iid || img.iid,
|
||||||
|
width: result.width || img.width,
|
||||||
|
height: result.height || img.height
|
||||||
|
}
|
||||||
: img
|
: img
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
// Update the product data with the new image URL
|
// Update the product data with the new image URL
|
||||||
addImageToProduct(productIndex, result.imageUrl);
|
addImageToProduct(productIndex, result.imageUrl, result);
|
||||||
|
|
||||||
toast.success(`Image uploaded for ${data[productIndex].name || `Product #${productIndex + 1}`}`);
|
toast.success(`Image uploaded for ${data[productIndex].name || `Product #${productIndex + 1}`}`);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
@@ -1305,20 +1406,33 @@ export const ImageUploadStep = <T extends string>({
|
|||||||
// Create a unique ID for this image
|
// Create a unique ID for this image
|
||||||
const imageId = `image-${productIndex}-url-${Date.now()}-${Math.random().toString(36).substring(2, 9)}`;
|
const imageId = `image-${productIndex}-url-${Date.now()}-${Math.random().toString(36).substring(2, 9)}`;
|
||||||
|
|
||||||
|
// Get the next order value for this product
|
||||||
|
const nextOrder = productImages
|
||||||
|
.filter(img => img.productIndex === productIndex)
|
||||||
|
.length;
|
||||||
|
|
||||||
// Create the new image object with the URL
|
// Create the new image object with the URL
|
||||||
const newImage: ProductImageSortable = {
|
const newImage: ProductImageSortable = {
|
||||||
id: imageId,
|
id: imageId,
|
||||||
productIndex,
|
productIndex,
|
||||||
imageUrl: validatedUrl,
|
imageUrl: validatedUrl,
|
||||||
loading: false, // We're not loading from server, so it's ready immediately
|
loading: false, // We're not loading from server, so it's ready immediately
|
||||||
fileName: "From URL"
|
fileName: "From URL",
|
||||||
|
// Add schema fields
|
||||||
|
pid: data[productIndex].id || 0,
|
||||||
|
iid: Math.floor(Math.random() * 10000), // Generate a temporary iid
|
||||||
|
type: 0,
|
||||||
|
order: nextOrder,
|
||||||
|
width: 0,
|
||||||
|
height: 0,
|
||||||
|
hidden: 0
|
||||||
};
|
};
|
||||||
|
|
||||||
// Add the image directly to the product images list
|
// Add the image directly to the product images list
|
||||||
setProductImages(prev => [...prev, newImage]);
|
setProductImages(prev => [...prev, newImage]);
|
||||||
|
|
||||||
// Update the product data with the new image URL
|
// Update the product data with the new image URL
|
||||||
addImageToProduct(productIndex, validatedUrl);
|
addImageToProduct(productIndex, validatedUrl, newImage);
|
||||||
|
|
||||||
// Clear the URL input field on success
|
// Clear the URL input field on success
|
||||||
setUrlInputs(prev => ({ ...prev, [productIndex]: '' }));
|
setUrlInputs(prev => ({ ...prev, [productIndex]: '' }));
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -314,7 +314,7 @@ const BASE_IMPORT_FIELDS = [
|
|||||||
key: "categories",
|
key: "categories",
|
||||||
description: "Product categories",
|
description: "Product categories",
|
||||||
fieldType: {
|
fieldType: {
|
||||||
type: "select",
|
type: "multi-select",
|
||||||
options: [], // Will be populated from API
|
options: [], // Will be populated from API
|
||||||
},
|
},
|
||||||
width: 350,
|
width: 350,
|
||||||
@@ -484,7 +484,7 @@ export function Import() {
|
|||||||
return {
|
return {
|
||||||
...field,
|
...field,
|
||||||
fieldType: {
|
fieldType: {
|
||||||
type: "select" as const,
|
type: "multi-select" as const,
|
||||||
options: fieldOptions.categories || [],
|
options: fieldOptions.categories || [],
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user