Use new categories correctly in existing components and handle category names with commas
This commit is contained in:
@@ -83,10 +83,36 @@ async function handleCategories(connection, productId, categoriesStr) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Split categories and clean them
|
// Special cases that should not be split
|
||||||
const categories = categoriesStr.split(',')
|
const specialCategories = [
|
||||||
|
'Paint, Dyes & Chalk',
|
||||||
|
'Fabric Paint, Markers, and Dye',
|
||||||
|
'Crystals, Gems & Rhinestones',
|
||||||
|
'Pens, Pencils & Markers'
|
||||||
|
];
|
||||||
|
|
||||||
|
// Split categories and clean them, preserving special cases
|
||||||
|
const categories = [];
|
||||||
|
let remainingStr = categoriesStr;
|
||||||
|
|
||||||
|
// First check for special categories
|
||||||
|
for (const special of specialCategories) {
|
||||||
|
if (remainingStr.includes(special)) {
|
||||||
|
categories.push(special);
|
||||||
|
// Remove the special category from the string
|
||||||
|
remainingStr = remainingStr.replace(special, '');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Then process any remaining regular categories
|
||||||
|
remainingStr.split(',')
|
||||||
.map(cat => cat.trim())
|
.map(cat => cat.trim())
|
||||||
.filter(cat => cat.length > 0);
|
.filter(cat => cat.length > 0)
|
||||||
|
.forEach(cat => {
|
||||||
|
if (!categories.includes(cat)) {
|
||||||
|
categories.push(cat);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
// Remove existing category relationships for this product
|
// Remove existing category relationships for this product
|
||||||
await connection.query(
|
await connection.query(
|
||||||
|
|||||||
@@ -65,7 +65,7 @@ router.get('/profit', async (req, res) => {
|
|||||||
// Get profit margins by category
|
// Get profit margins by category
|
||||||
const [byCategory] = await pool.query(`
|
const [byCategory] = await pool.query(`
|
||||||
SELECT
|
SELECT
|
||||||
COALESCE(p.categories, 'Uncategorized') as category,
|
c.name as category,
|
||||||
ROUND(
|
ROUND(
|
||||||
(SUM(o.price * o.quantity - p.cost_price * o.quantity) /
|
(SUM(o.price * o.quantity - p.cost_price * o.quantity) /
|
||||||
NULLIF(SUM(o.price * o.quantity), 0)) * 100, 1
|
NULLIF(SUM(o.price * o.quantity), 0)) * 100, 1
|
||||||
@@ -74,8 +74,10 @@ router.get('/profit', async (req, res) => {
|
|||||||
SUM(p.cost_price * o.quantity) as cost
|
SUM(p.cost_price * o.quantity) as cost
|
||||||
FROM products p
|
FROM products p
|
||||||
LEFT JOIN orders o ON p.product_id = o.product_id
|
LEFT JOIN orders o ON p.product_id = o.product_id
|
||||||
|
JOIN product_categories pc ON p.product_id = pc.product_id
|
||||||
|
JOIN categories c ON pc.category_id = c.id
|
||||||
WHERE o.date >= DATE_SUB(CURDATE(), INTERVAL 30 DAY)
|
WHERE o.date >= DATE_SUB(CURDATE(), INTERVAL 30 DAY)
|
||||||
GROUP BY p.categories
|
GROUP BY c.name
|
||||||
ORDER BY profitMargin DESC
|
ORDER BY profitMargin DESC
|
||||||
LIMIT 10
|
LIMIT 10
|
||||||
`);
|
`);
|
||||||
@@ -190,14 +192,16 @@ router.get('/stock', async (req, res) => {
|
|||||||
// Get turnover by category
|
// Get turnover by category
|
||||||
const [turnoverByCategory] = await pool.query(`
|
const [turnoverByCategory] = await pool.query(`
|
||||||
SELECT
|
SELECT
|
||||||
COALESCE(p.categories, 'Uncategorized') as category,
|
c.name as category,
|
||||||
ROUND(SUM(o.quantity) / NULLIF(AVG(p.stock_quantity), 0), 1) as turnoverRate,
|
ROUND(SUM(o.quantity) / NULLIF(AVG(p.stock_quantity), 0), 1) as turnoverRate,
|
||||||
ROUND(AVG(p.stock_quantity), 0) as averageStock,
|
ROUND(AVG(p.stock_quantity), 0) as averageStock,
|
||||||
SUM(o.quantity) as totalSales
|
SUM(o.quantity) as totalSales
|
||||||
FROM products p
|
FROM products p
|
||||||
LEFT JOIN orders o ON p.product_id = o.product_id
|
LEFT JOIN orders o ON p.product_id = o.product_id
|
||||||
|
JOIN product_categories pc ON p.product_id = pc.product_id
|
||||||
|
JOIN categories c ON pc.category_id = c.id
|
||||||
WHERE o.date >= DATE_SUB(CURDATE(), INTERVAL 30 DAY)
|
WHERE o.date >= DATE_SUB(CURDATE(), INTERVAL 30 DAY)
|
||||||
GROUP BY p.categories
|
GROUP BY c.name
|
||||||
HAVING turnoverRate > 0
|
HAVING turnoverRate > 0
|
||||||
ORDER BY turnoverRate DESC
|
ORDER BY turnoverRate DESC
|
||||||
LIMIT 10
|
LIMIT 10
|
||||||
@@ -328,7 +332,7 @@ router.get('/categories', async (req, res) => {
|
|||||||
// Get category performance metrics
|
// Get category performance metrics
|
||||||
const [performance] = await pool.query(`
|
const [performance] = await pool.query(`
|
||||||
SELECT
|
SELECT
|
||||||
COALESCE(p.categories, 'Uncategorized') as category,
|
c.name as category,
|
||||||
SUM(o.price * o.quantity) as revenue,
|
SUM(o.price * o.quantity) as revenue,
|
||||||
SUM(o.price * o.quantity - p.cost_price * o.quantity) as profit,
|
SUM(o.price * o.quantity - p.cost_price * o.quantity) as profit,
|
||||||
ROUND(
|
ROUND(
|
||||||
@@ -348,8 +352,10 @@ router.get('/categories', async (req, res) => {
|
|||||||
COUNT(DISTINCT p.product_id) as productCount
|
COUNT(DISTINCT p.product_id) as productCount
|
||||||
FROM products p
|
FROM products p
|
||||||
LEFT JOIN orders o ON p.product_id = o.product_id
|
LEFT JOIN orders o ON p.product_id = o.product_id
|
||||||
|
JOIN product_categories pc ON p.product_id = pc.product_id
|
||||||
|
JOIN categories c ON pc.category_id = c.id
|
||||||
WHERE o.date >= DATE_SUB(CURDATE(), INTERVAL 60 DAY)
|
WHERE o.date >= DATE_SUB(CURDATE(), INTERVAL 60 DAY)
|
||||||
GROUP BY p.categories
|
GROUP BY c.name
|
||||||
HAVING revenue > 0
|
HAVING revenue > 0
|
||||||
ORDER BY revenue DESC
|
ORDER BY revenue DESC
|
||||||
LIMIT 10
|
LIMIT 10
|
||||||
@@ -358,12 +364,14 @@ router.get('/categories', async (req, res) => {
|
|||||||
// Get category revenue distribution
|
// Get category revenue distribution
|
||||||
const [distribution] = await pool.query(`
|
const [distribution] = await pool.query(`
|
||||||
SELECT
|
SELECT
|
||||||
COALESCE(p.categories, 'Uncategorized') as category,
|
c.name as category,
|
||||||
SUM(o.price * o.quantity) as value
|
SUM(o.price * o.quantity) as value
|
||||||
FROM products p
|
FROM products p
|
||||||
LEFT JOIN orders o ON p.product_id = o.product_id
|
LEFT JOIN orders o ON p.product_id = o.product_id
|
||||||
|
JOIN product_categories pc ON p.product_id = pc.product_id
|
||||||
|
JOIN categories c ON pc.category_id = c.id
|
||||||
WHERE o.date >= DATE_SUB(CURDATE(), INTERVAL 30 DAY)
|
WHERE o.date >= DATE_SUB(CURDATE(), INTERVAL 30 DAY)
|
||||||
GROUP BY p.categories
|
GROUP BY c.name
|
||||||
HAVING value > 0
|
HAVING value > 0
|
||||||
ORDER BY value DESC
|
ORDER BY value DESC
|
||||||
LIMIT 6
|
LIMIT 6
|
||||||
|
|||||||
@@ -123,11 +123,13 @@ router.get('/category-stats', async (req, res) => {
|
|||||||
try {
|
try {
|
||||||
const [rows] = await pool.query(`
|
const [rows] = await pool.query(`
|
||||||
SELECT
|
SELECT
|
||||||
categories,
|
c.name as category,
|
||||||
COUNT(*) as count
|
COUNT(DISTINCT pc.product_id) as count
|
||||||
FROM products
|
FROM categories c
|
||||||
WHERE visible = true
|
LEFT JOIN product_categories pc ON c.id = pc.category_id
|
||||||
GROUP BY categories
|
LEFT JOIN products p ON pc.product_id = p.product_id
|
||||||
|
WHERE p.visible = true
|
||||||
|
GROUP BY c.name
|
||||||
ORDER BY count DESC
|
ORDER BY count DESC
|
||||||
LIMIT 10
|
LIMIT 10
|
||||||
`);
|
`);
|
||||||
@@ -164,13 +166,15 @@ router.get('/sales-by-category', async (req, res) => {
|
|||||||
try {
|
try {
|
||||||
const [rows] = await pool.query(`
|
const [rows] = await pool.query(`
|
||||||
SELECT
|
SELECT
|
||||||
p.categories as category,
|
c.name as category,
|
||||||
SUM(o.price * o.quantity) as total
|
SUM(o.price * o.quantity) as total
|
||||||
FROM orders o
|
FROM orders o
|
||||||
JOIN products p ON o.product_id = p.product_id
|
JOIN products p ON o.product_id = p.product_id
|
||||||
|
JOIN product_categories pc ON p.product_id = pc.product_id
|
||||||
|
JOIN categories c ON pc.category_id = c.id
|
||||||
WHERE o.canceled = false
|
WHERE o.canceled = false
|
||||||
AND DATE(o.date) >= DATE_SUB(CURDATE(), INTERVAL 30 DAY)
|
AND DATE(o.date) >= DATE_SUB(CURDATE(), INTERVAL 30 DAY)
|
||||||
GROUP BY p.categories
|
GROUP BY c.name
|
||||||
ORDER BY total DESC
|
ORDER BY total DESC
|
||||||
LIMIT 6
|
LIMIT 6
|
||||||
`);
|
`);
|
||||||
@@ -266,14 +270,16 @@ router.get('/inventory-metrics', async (req, res) => {
|
|||||||
// Get stock levels by category
|
// Get stock levels by category
|
||||||
const [stockLevels] = await pool.query(`
|
const [stockLevels] = await pool.query(`
|
||||||
SELECT
|
SELECT
|
||||||
categories as category,
|
c.name as category,
|
||||||
SUM(CASE WHEN stock_quantity > 5 THEN 1 ELSE 0 END) as inStock,
|
SUM(CASE WHEN stock_quantity > 5 THEN 1 ELSE 0 END) as inStock,
|
||||||
SUM(CASE WHEN stock_quantity > 0 AND stock_quantity <= 5 THEN 1 ELSE 0 END) as lowStock,
|
SUM(CASE WHEN stock_quantity > 0 AND stock_quantity <= 5 THEN 1 ELSE 0 END) as lowStock,
|
||||||
SUM(CASE WHEN stock_quantity = 0 THEN 1 ELSE 0 END) as outOfStock
|
SUM(CASE WHEN stock_quantity = 0 THEN 1 ELSE 0 END) as outOfStock
|
||||||
FROM products
|
FROM products p
|
||||||
|
JOIN product_categories pc ON p.product_id = pc.product_id
|
||||||
|
JOIN categories c ON pc.category_id = c.id
|
||||||
WHERE visible = true
|
WHERE visible = true
|
||||||
GROUP BY categories
|
GROUP BY c.name
|
||||||
ORDER BY categories ASC
|
ORDER BY c.name ASC
|
||||||
`);
|
`);
|
||||||
|
|
||||||
// Get top vendors with product counts and average stock
|
// Get top vendors with product counts and average stock
|
||||||
@@ -296,21 +302,25 @@ router.get('/inventory-metrics', async (req, res) => {
|
|||||||
const [stockTurnover] = await pool.query(`
|
const [stockTurnover] = await pool.query(`
|
||||||
WITH CategorySales AS (
|
WITH CategorySales AS (
|
||||||
SELECT
|
SELECT
|
||||||
p.categories as category,
|
c.name as category,
|
||||||
SUM(o.quantity) as units_sold
|
SUM(o.quantity) as units_sold
|
||||||
FROM products p
|
FROM products p
|
||||||
LEFT JOIN orders o ON p.product_id = o.product_id
|
LEFT JOIN orders o ON p.product_id = o.product_id
|
||||||
|
JOIN product_categories pc ON p.product_id = pc.product_id
|
||||||
|
JOIN categories c ON pc.category_id = c.id
|
||||||
WHERE o.canceled = false
|
WHERE o.canceled = false
|
||||||
AND DATE(o.date) >= DATE_SUB(CURDATE(), INTERVAL 30 DAY)
|
AND DATE(o.date) >= DATE_SUB(CURDATE(), INTERVAL 30 DAY)
|
||||||
GROUP BY p.categories
|
GROUP BY c.name
|
||||||
),
|
),
|
||||||
CategoryStock AS (
|
CategoryStock AS (
|
||||||
SELECT
|
SELECT
|
||||||
categories as category,
|
c.name as category,
|
||||||
AVG(stock_quantity) as avg_stock
|
AVG(p.stock_quantity) as avg_stock
|
||||||
FROM products
|
FROM products p
|
||||||
WHERE visible = true
|
JOIN product_categories pc ON p.product_id = pc.product_id
|
||||||
GROUP BY categories
|
JOIN categories c ON pc.category_id = c.id
|
||||||
|
WHERE p.visible = true
|
||||||
|
GROUP BY c.name
|
||||||
)
|
)
|
||||||
SELECT
|
SELECT
|
||||||
cs.category,
|
cs.category,
|
||||||
|
|||||||
@@ -32,7 +32,14 @@ router.get('/', async (req, res) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (category !== 'all') {
|
if (category !== 'all') {
|
||||||
conditions.push('categories = ?');
|
conditions.push(`
|
||||||
|
product_id IN (
|
||||||
|
SELECT pc.product_id
|
||||||
|
FROM product_categories pc
|
||||||
|
JOIN categories c ON pc.category_id = c.id
|
||||||
|
WHERE c.name = ?
|
||||||
|
)
|
||||||
|
`);
|
||||||
params.push(category);
|
params.push(category);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -75,37 +82,46 @@ router.get('/', async (req, res) => {
|
|||||||
// Get paginated results
|
// Get paginated results
|
||||||
const query = `
|
const query = `
|
||||||
SELECT
|
SELECT
|
||||||
product_id,
|
p.product_id,
|
||||||
title,
|
p.title,
|
||||||
SKU,
|
p.SKU,
|
||||||
stock_quantity,
|
p.stock_quantity,
|
||||||
price,
|
p.price,
|
||||||
regular_price,
|
p.regular_price,
|
||||||
cost_price,
|
p.cost_price,
|
||||||
vendor,
|
p.vendor,
|
||||||
brand,
|
p.brand,
|
||||||
categories,
|
p.visible,
|
||||||
visible,
|
p.managing_stock,
|
||||||
managing_stock,
|
p.image,
|
||||||
image
|
GROUP_CONCAT(c.name) as categories
|
||||||
FROM products
|
FROM products p
|
||||||
|
LEFT JOIN product_categories pc ON p.product_id = pc.product_id
|
||||||
|
LEFT JOIN categories c ON pc.category_id = c.id
|
||||||
WHERE ${conditions.join(' AND ')}
|
WHERE ${conditions.join(' AND ')}
|
||||||
|
GROUP BY p.product_id
|
||||||
ORDER BY ${sortColumn} ${sortDirection}
|
ORDER BY ${sortColumn} ${sortDirection}
|
||||||
LIMIT ? OFFSET ?
|
LIMIT ? OFFSET ?
|
||||||
`;
|
`;
|
||||||
|
|
||||||
const [rows] = await pool.query(query, [...params, limit, offset]);
|
const [rows] = await pool.query(query, [...params, limit, offset]);
|
||||||
|
|
||||||
|
// Transform the categories string into an array
|
||||||
|
const productsWithCategories = rows.map(product => ({
|
||||||
|
...product,
|
||||||
|
categories: product.categories ? product.categories.split(',') : []
|
||||||
|
}));
|
||||||
|
|
||||||
// Get unique categories and vendors for filters
|
// Get unique categories and vendors for filters
|
||||||
const [categories] = await pool.query(
|
const [categories] = await pool.query(
|
||||||
'SELECT DISTINCT categories FROM products WHERE visible = true AND categories IS NOT NULL AND categories != "" ORDER BY categories'
|
'SELECT name FROM categories ORDER BY name'
|
||||||
);
|
);
|
||||||
const [vendors] = await pool.query(
|
const [vendors] = await pool.query(
|
||||||
'SELECT DISTINCT vendor FROM products WHERE visible = true AND vendor IS NOT NULL AND vendor != "" ORDER BY vendor'
|
'SELECT DISTINCT vendor FROM products WHERE visible = true AND vendor IS NOT NULL AND vendor != "" ORDER BY vendor'
|
||||||
);
|
);
|
||||||
|
|
||||||
res.json({
|
res.json({
|
||||||
products: rows,
|
products: productsWithCategories,
|
||||||
pagination: {
|
pagination: {
|
||||||
total,
|
total,
|
||||||
pages: Math.ceil(total / limit),
|
pages: Math.ceil(total / limit),
|
||||||
@@ -113,7 +129,7 @@ router.get('/', async (req, res) => {
|
|||||||
limit
|
limit
|
||||||
},
|
},
|
||||||
filters: {
|
filters: {
|
||||||
categories: categories.map(c => c.categories),
|
categories: categories.map(c => c.name),
|
||||||
vendors: vendors.map(v => v.vendor)
|
vendors: vendors.map(v => v.vendor)
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -243,7 +243,7 @@ router.get('/cost-analysis', async (req, res) => {
|
|||||||
|
|
||||||
const [analysis] = await pool.query(`
|
const [analysis] = await pool.query(`
|
||||||
SELECT
|
SELECT
|
||||||
p.categories,
|
c.name as categories,
|
||||||
COUNT(DISTINCT po.product_id) as unique_products,
|
COUNT(DISTINCT po.product_id) as unique_products,
|
||||||
ROUND(AVG(po.cost_price), 2) as avg_cost,
|
ROUND(AVG(po.cost_price), 2) as avg_cost,
|
||||||
MIN(po.cost_price) as min_cost,
|
MIN(po.cost_price) as min_cost,
|
||||||
@@ -254,7 +254,9 @@ router.get('/cost-analysis', async (req, res) => {
|
|||||||
SUM(po.ordered * po.cost_price) as total_spend
|
SUM(po.ordered * po.cost_price) as total_spend
|
||||||
FROM purchase_orders po
|
FROM purchase_orders po
|
||||||
JOIN products p ON po.product_id = p.product_id
|
JOIN products p ON po.product_id = p.product_id
|
||||||
GROUP BY p.categories
|
JOIN product_categories pc ON p.product_id = pc.product_id
|
||||||
|
JOIN categories c ON pc.category_id = c.id
|
||||||
|
GROUP BY c.name
|
||||||
ORDER BY total_spend DESC
|
ORDER BY total_spend DESC
|
||||||
`);
|
`);
|
||||||
|
|
||||||
|
|||||||
433
inventory/package-lock.json
generated
433
inventory/package-lock.json
generated
@@ -28,6 +28,7 @@
|
|||||||
"@tanstack/virtual-core": "^3.11.2",
|
"@tanstack/virtual-core": "^3.11.2",
|
||||||
"class-variance-authority": "^0.7.1",
|
"class-variance-authority": "^0.7.1",
|
||||||
"clsx": "^2.1.1",
|
"clsx": "^2.1.1",
|
||||||
|
"cmdk": "^1.0.0",
|
||||||
"date-fns": "^3.6.0",
|
"date-fns": "^3.6.0",
|
||||||
"lucide-react": "^0.469.0",
|
"lucide-react": "^0.469.0",
|
||||||
"next-themes": "^0.4.4",
|
"next-themes": "^0.4.4",
|
||||||
@@ -3302,6 +3303,438 @@
|
|||||||
"node": ">=6"
|
"node": ">=6"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/cmdk": {
|
||||||
|
"version": "1.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/cmdk/-/cmdk-1.0.0.tgz",
|
||||||
|
"integrity": "sha512-gDzVf0a09TvoJ5jnuPvygTB77+XdOSwEmJ88L6XPFPlv7T3RxbP9jgenfylrAMD0+Le1aO0nVjQUzl2g+vjz5Q==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@radix-ui/react-dialog": "1.0.5",
|
||||||
|
"@radix-ui/react-primitive": "1.0.3"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"react": "^18.0.0",
|
||||||
|
"react-dom": "^18.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/cmdk/node_modules/@radix-ui/primitive": {
|
||||||
|
"version": "1.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/@radix-ui/primitive/-/primitive-1.0.1.tgz",
|
||||||
|
"integrity": "sha512-yQ8oGX2GVsEYMWGxcovu1uGWPCxV5BFfeeYxqPmuAzUyLT9qmaMXSAhXpb0WrspIeqYzdJpkh2vHModJPgRIaw==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@babel/runtime": "^7.13.10"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/cmdk/node_modules/@radix-ui/react-compose-refs": {
|
||||||
|
"version": "1.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/@radix-ui/react-compose-refs/-/react-compose-refs-1.0.1.tgz",
|
||||||
|
"integrity": "sha512-fDSBgd44FKHa1FRMU59qBMPFcl2PZE+2nmqunj+BWFyYYjnhIDWL2ItDs3rrbJDQOtzt5nIebLCQc4QRfz6LJw==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@babel/runtime": "^7.13.10"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"@types/react": "*",
|
||||||
|
"react": "^16.8 || ^17.0 || ^18.0"
|
||||||
|
},
|
||||||
|
"peerDependenciesMeta": {
|
||||||
|
"@types/react": {
|
||||||
|
"optional": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/cmdk/node_modules/@radix-ui/react-context": {
|
||||||
|
"version": "1.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/@radix-ui/react-context/-/react-context-1.0.1.tgz",
|
||||||
|
"integrity": "sha512-ebbrdFoYTcuZ0v4wG5tedGnp9tzcV8awzsxYph7gXUyvnNLuTIcCk1q17JEbnVhXAKG9oX3KtchwiMIAYp9NLg==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@babel/runtime": "^7.13.10"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"@types/react": "*",
|
||||||
|
"react": "^16.8 || ^17.0 || ^18.0"
|
||||||
|
},
|
||||||
|
"peerDependenciesMeta": {
|
||||||
|
"@types/react": {
|
||||||
|
"optional": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/cmdk/node_modules/@radix-ui/react-dialog": {
|
||||||
|
"version": "1.0.5",
|
||||||
|
"resolved": "https://registry.npmjs.org/@radix-ui/react-dialog/-/react-dialog-1.0.5.tgz",
|
||||||
|
"integrity": "sha512-GjWJX/AUpB703eEBanuBnIWdIXg6NvJFCXcNlSZk4xdszCdhrJgBoUd1cGk67vFO+WdA2pfI/plOpqz/5GUP6Q==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@babel/runtime": "^7.13.10",
|
||||||
|
"@radix-ui/primitive": "1.0.1",
|
||||||
|
"@radix-ui/react-compose-refs": "1.0.1",
|
||||||
|
"@radix-ui/react-context": "1.0.1",
|
||||||
|
"@radix-ui/react-dismissable-layer": "1.0.5",
|
||||||
|
"@radix-ui/react-focus-guards": "1.0.1",
|
||||||
|
"@radix-ui/react-focus-scope": "1.0.4",
|
||||||
|
"@radix-ui/react-id": "1.0.1",
|
||||||
|
"@radix-ui/react-portal": "1.0.4",
|
||||||
|
"@radix-ui/react-presence": "1.0.1",
|
||||||
|
"@radix-ui/react-primitive": "1.0.3",
|
||||||
|
"@radix-ui/react-slot": "1.0.2",
|
||||||
|
"@radix-ui/react-use-controllable-state": "1.0.1",
|
||||||
|
"aria-hidden": "^1.1.1",
|
||||||
|
"react-remove-scroll": "2.5.5"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"@types/react": "*",
|
||||||
|
"@types/react-dom": "*",
|
||||||
|
"react": "^16.8 || ^17.0 || ^18.0",
|
||||||
|
"react-dom": "^16.8 || ^17.0 || ^18.0"
|
||||||
|
},
|
||||||
|
"peerDependenciesMeta": {
|
||||||
|
"@types/react": {
|
||||||
|
"optional": true
|
||||||
|
},
|
||||||
|
"@types/react-dom": {
|
||||||
|
"optional": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/cmdk/node_modules/@radix-ui/react-dismissable-layer": {
|
||||||
|
"version": "1.0.5",
|
||||||
|
"resolved": "https://registry.npmjs.org/@radix-ui/react-dismissable-layer/-/react-dismissable-layer-1.0.5.tgz",
|
||||||
|
"integrity": "sha512-aJeDjQhywg9LBu2t/At58hCvr7pEm0o2Ke1x33B+MhjNmmZ17sy4KImo0KPLgsnc/zN7GPdce8Cnn0SWvwZO7g==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@babel/runtime": "^7.13.10",
|
||||||
|
"@radix-ui/primitive": "1.0.1",
|
||||||
|
"@radix-ui/react-compose-refs": "1.0.1",
|
||||||
|
"@radix-ui/react-primitive": "1.0.3",
|
||||||
|
"@radix-ui/react-use-callback-ref": "1.0.1",
|
||||||
|
"@radix-ui/react-use-escape-keydown": "1.0.3"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"@types/react": "*",
|
||||||
|
"@types/react-dom": "*",
|
||||||
|
"react": "^16.8 || ^17.0 || ^18.0",
|
||||||
|
"react-dom": "^16.8 || ^17.0 || ^18.0"
|
||||||
|
},
|
||||||
|
"peerDependenciesMeta": {
|
||||||
|
"@types/react": {
|
||||||
|
"optional": true
|
||||||
|
},
|
||||||
|
"@types/react-dom": {
|
||||||
|
"optional": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/cmdk/node_modules/@radix-ui/react-dismissable-layer/node_modules/@radix-ui/react-use-callback-ref": {
|
||||||
|
"version": "1.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/@radix-ui/react-use-callback-ref/-/react-use-callback-ref-1.0.1.tgz",
|
||||||
|
"integrity": "sha512-D94LjX4Sp0xJFVaoQOd3OO9k7tpBYNOXdVhkltUbGv2Qb9OXdrg/CpsjlZv7ia14Sylv398LswWBVVu5nqKzAQ==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@babel/runtime": "^7.13.10"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"@types/react": "*",
|
||||||
|
"react": "^16.8 || ^17.0 || ^18.0"
|
||||||
|
},
|
||||||
|
"peerDependenciesMeta": {
|
||||||
|
"@types/react": {
|
||||||
|
"optional": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/cmdk/node_modules/@radix-ui/react-dismissable-layer/node_modules/@radix-ui/react-use-escape-keydown": {
|
||||||
|
"version": "1.0.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/@radix-ui/react-use-escape-keydown/-/react-use-escape-keydown-1.0.3.tgz",
|
||||||
|
"integrity": "sha512-vyL82j40hcFicA+M4Ex7hVkB9vHgSse1ZWomAqV2Je3RleKGO5iM8KMOEtfoSB0PnIelMd2lATjTGMYqN5ylTg==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@babel/runtime": "^7.13.10",
|
||||||
|
"@radix-ui/react-use-callback-ref": "1.0.1"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"@types/react": "*",
|
||||||
|
"react": "^16.8 || ^17.0 || ^18.0"
|
||||||
|
},
|
||||||
|
"peerDependenciesMeta": {
|
||||||
|
"@types/react": {
|
||||||
|
"optional": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/cmdk/node_modules/@radix-ui/react-focus-guards": {
|
||||||
|
"version": "1.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/@radix-ui/react-focus-guards/-/react-focus-guards-1.0.1.tgz",
|
||||||
|
"integrity": "sha512-Rect2dWbQ8waGzhMavsIbmSVCgYxkXLxxR3ZvCX79JOglzdEy4JXMb98lq4hPxUbLr77nP0UOGf4rcMU+s1pUA==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@babel/runtime": "^7.13.10"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"@types/react": "*",
|
||||||
|
"react": "^16.8 || ^17.0 || ^18.0"
|
||||||
|
},
|
||||||
|
"peerDependenciesMeta": {
|
||||||
|
"@types/react": {
|
||||||
|
"optional": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/cmdk/node_modules/@radix-ui/react-focus-scope": {
|
||||||
|
"version": "1.0.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/@radix-ui/react-focus-scope/-/react-focus-scope-1.0.4.tgz",
|
||||||
|
"integrity": "sha512-sL04Mgvf+FmyvZeYfNu1EPAaaxD+aw7cYeIB9L9Fvq8+urhltTRaEo5ysKOpHuKPclsZcSUMKlN05x4u+CINpA==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@babel/runtime": "^7.13.10",
|
||||||
|
"@radix-ui/react-compose-refs": "1.0.1",
|
||||||
|
"@radix-ui/react-primitive": "1.0.3",
|
||||||
|
"@radix-ui/react-use-callback-ref": "1.0.1"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"@types/react": "*",
|
||||||
|
"@types/react-dom": "*",
|
||||||
|
"react": "^16.8 || ^17.0 || ^18.0",
|
||||||
|
"react-dom": "^16.8 || ^17.0 || ^18.0"
|
||||||
|
},
|
||||||
|
"peerDependenciesMeta": {
|
||||||
|
"@types/react": {
|
||||||
|
"optional": true
|
||||||
|
},
|
||||||
|
"@types/react-dom": {
|
||||||
|
"optional": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/cmdk/node_modules/@radix-ui/react-focus-scope/node_modules/@radix-ui/react-use-callback-ref": {
|
||||||
|
"version": "1.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/@radix-ui/react-use-callback-ref/-/react-use-callback-ref-1.0.1.tgz",
|
||||||
|
"integrity": "sha512-D94LjX4Sp0xJFVaoQOd3OO9k7tpBYNOXdVhkltUbGv2Qb9OXdrg/CpsjlZv7ia14Sylv398LswWBVVu5nqKzAQ==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@babel/runtime": "^7.13.10"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"@types/react": "*",
|
||||||
|
"react": "^16.8 || ^17.0 || ^18.0"
|
||||||
|
},
|
||||||
|
"peerDependenciesMeta": {
|
||||||
|
"@types/react": {
|
||||||
|
"optional": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/cmdk/node_modules/@radix-ui/react-id": {
|
||||||
|
"version": "1.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/@radix-ui/react-id/-/react-id-1.0.1.tgz",
|
||||||
|
"integrity": "sha512-tI7sT/kqYp8p96yGWY1OAnLHrqDgzHefRBKQ2YAkBS5ja7QLcZ9Z/uY7bEjPUatf8RomoXM8/1sMj1IJaE5UzQ==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@babel/runtime": "^7.13.10",
|
||||||
|
"@radix-ui/react-use-layout-effect": "1.0.1"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"@types/react": "*",
|
||||||
|
"react": "^16.8 || ^17.0 || ^18.0"
|
||||||
|
},
|
||||||
|
"peerDependenciesMeta": {
|
||||||
|
"@types/react": {
|
||||||
|
"optional": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/cmdk/node_modules/@radix-ui/react-id/node_modules/@radix-ui/react-use-layout-effect": {
|
||||||
|
"version": "1.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/@radix-ui/react-use-layout-effect/-/react-use-layout-effect-1.0.1.tgz",
|
||||||
|
"integrity": "sha512-v/5RegiJWYdoCvMnITBkNNx6bCj20fiaJnWtRkU18yITptraXjffz5Qbn05uOiQnOvi+dbkznkoaMltz1GnszQ==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@babel/runtime": "^7.13.10"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"@types/react": "*",
|
||||||
|
"react": "^16.8 || ^17.0 || ^18.0"
|
||||||
|
},
|
||||||
|
"peerDependenciesMeta": {
|
||||||
|
"@types/react": {
|
||||||
|
"optional": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/cmdk/node_modules/@radix-ui/react-portal": {
|
||||||
|
"version": "1.0.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/@radix-ui/react-portal/-/react-portal-1.0.4.tgz",
|
||||||
|
"integrity": "sha512-Qki+C/EuGUVCQTOTD5vzJzJuMUlewbzuKyUy+/iHM2uwGiru9gZeBJtHAPKAEkB5KWGi9mP/CHKcY0wt1aW45Q==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@babel/runtime": "^7.13.10",
|
||||||
|
"@radix-ui/react-primitive": "1.0.3"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"@types/react": "*",
|
||||||
|
"@types/react-dom": "*",
|
||||||
|
"react": "^16.8 || ^17.0 || ^18.0",
|
||||||
|
"react-dom": "^16.8 || ^17.0 || ^18.0"
|
||||||
|
},
|
||||||
|
"peerDependenciesMeta": {
|
||||||
|
"@types/react": {
|
||||||
|
"optional": true
|
||||||
|
},
|
||||||
|
"@types/react-dom": {
|
||||||
|
"optional": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/cmdk/node_modules/@radix-ui/react-presence": {
|
||||||
|
"version": "1.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/@radix-ui/react-presence/-/react-presence-1.0.1.tgz",
|
||||||
|
"integrity": "sha512-UXLW4UAbIY5ZjcvzjfRFo5gxva8QirC9hF7wRE4U5gz+TP0DbRk+//qyuAQ1McDxBt1xNMBTaciFGvEmJvAZCg==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@babel/runtime": "^7.13.10",
|
||||||
|
"@radix-ui/react-compose-refs": "1.0.1",
|
||||||
|
"@radix-ui/react-use-layout-effect": "1.0.1"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"@types/react": "*",
|
||||||
|
"@types/react-dom": "*",
|
||||||
|
"react": "^16.8 || ^17.0 || ^18.0",
|
||||||
|
"react-dom": "^16.8 || ^17.0 || ^18.0"
|
||||||
|
},
|
||||||
|
"peerDependenciesMeta": {
|
||||||
|
"@types/react": {
|
||||||
|
"optional": true
|
||||||
|
},
|
||||||
|
"@types/react-dom": {
|
||||||
|
"optional": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/cmdk/node_modules/@radix-ui/react-presence/node_modules/@radix-ui/react-use-layout-effect": {
|
||||||
|
"version": "1.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/@radix-ui/react-use-layout-effect/-/react-use-layout-effect-1.0.1.tgz",
|
||||||
|
"integrity": "sha512-v/5RegiJWYdoCvMnITBkNNx6bCj20fiaJnWtRkU18yITptraXjffz5Qbn05uOiQnOvi+dbkznkoaMltz1GnszQ==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@babel/runtime": "^7.13.10"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"@types/react": "*",
|
||||||
|
"react": "^16.8 || ^17.0 || ^18.0"
|
||||||
|
},
|
||||||
|
"peerDependenciesMeta": {
|
||||||
|
"@types/react": {
|
||||||
|
"optional": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/cmdk/node_modules/@radix-ui/react-primitive": {
|
||||||
|
"version": "1.0.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-1.0.3.tgz",
|
||||||
|
"integrity": "sha512-yi58uVyoAcK/Nq1inRY56ZSjKypBNKTa/1mcL8qdl6oJeEaDbOldlzrGn7P6Q3Id5d+SYNGc5AJgc4vGhjs5+g==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@babel/runtime": "^7.13.10",
|
||||||
|
"@radix-ui/react-slot": "1.0.2"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"@types/react": "*",
|
||||||
|
"@types/react-dom": "*",
|
||||||
|
"react": "^16.8 || ^17.0 || ^18.0",
|
||||||
|
"react-dom": "^16.8 || ^17.0 || ^18.0"
|
||||||
|
},
|
||||||
|
"peerDependenciesMeta": {
|
||||||
|
"@types/react": {
|
||||||
|
"optional": true
|
||||||
|
},
|
||||||
|
"@types/react-dom": {
|
||||||
|
"optional": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/cmdk/node_modules/@radix-ui/react-slot": {
|
||||||
|
"version": "1.0.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.0.2.tgz",
|
||||||
|
"integrity": "sha512-YeTpuq4deV+6DusvVUW4ivBgnkHwECUu0BiN43L5UCDFgdhsRUWAghhTF5MbvNTPzmiFOx90asDSUjWuCNapwg==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@babel/runtime": "^7.13.10",
|
||||||
|
"@radix-ui/react-compose-refs": "1.0.1"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"@types/react": "*",
|
||||||
|
"react": "^16.8 || ^17.0 || ^18.0"
|
||||||
|
},
|
||||||
|
"peerDependenciesMeta": {
|
||||||
|
"@types/react": {
|
||||||
|
"optional": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/cmdk/node_modules/@radix-ui/react-use-controllable-state": {
|
||||||
|
"version": "1.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/@radix-ui/react-use-controllable-state/-/react-use-controllable-state-1.0.1.tgz",
|
||||||
|
"integrity": "sha512-Svl5GY5FQeN758fWKrjM6Qb7asvXeiZltlT4U2gVfl8Gx5UAv2sMR0LWo8yhsIZh2oQ0eFdZ59aoOOMV7b47VA==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@babel/runtime": "^7.13.10",
|
||||||
|
"@radix-ui/react-use-callback-ref": "1.0.1"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"@types/react": "*",
|
||||||
|
"react": "^16.8 || ^17.0 || ^18.0"
|
||||||
|
},
|
||||||
|
"peerDependenciesMeta": {
|
||||||
|
"@types/react": {
|
||||||
|
"optional": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/cmdk/node_modules/@radix-ui/react-use-controllable-state/node_modules/@radix-ui/react-use-callback-ref": {
|
||||||
|
"version": "1.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/@radix-ui/react-use-callback-ref/-/react-use-callback-ref-1.0.1.tgz",
|
||||||
|
"integrity": "sha512-D94LjX4Sp0xJFVaoQOd3OO9k7tpBYNOXdVhkltUbGv2Qb9OXdrg/CpsjlZv7ia14Sylv398LswWBVVu5nqKzAQ==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@babel/runtime": "^7.13.10"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"@types/react": "*",
|
||||||
|
"react": "^16.8 || ^17.0 || ^18.0"
|
||||||
|
},
|
||||||
|
"peerDependenciesMeta": {
|
||||||
|
"@types/react": {
|
||||||
|
"optional": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/cmdk/node_modules/react-remove-scroll": {
|
||||||
|
"version": "2.5.5",
|
||||||
|
"resolved": "https://registry.npmjs.org/react-remove-scroll/-/react-remove-scroll-2.5.5.tgz",
|
||||||
|
"integrity": "sha512-ImKhrzJJsyXJfBZ4bzu8Bwpka14c/fQt0k+cyFp/PBhTfyDnU5hjOtM4AG/0AMyy8oKzOTR0lDgJIM7pYXI0kw==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"react-remove-scroll-bar": "^2.3.3",
|
||||||
|
"react-style-singleton": "^2.2.1",
|
||||||
|
"tslib": "^2.1.0",
|
||||||
|
"use-callback-ref": "^1.3.0",
|
||||||
|
"use-sidecar": "^1.1.2"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=10"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"@types/react": "^16.8.0 || ^17.0.0 || ^18.0.0",
|
||||||
|
"react": "^16.8.0 || ^17.0.0 || ^18.0.0"
|
||||||
|
},
|
||||||
|
"peerDependenciesMeta": {
|
||||||
|
"@types/react": {
|
||||||
|
"optional": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/color-convert": {
|
"node_modules/color-convert": {
|
||||||
"version": "2.0.1",
|
"version": "2.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
|
||||||
|
|||||||
@@ -30,6 +30,7 @@
|
|||||||
"@tanstack/virtual-core": "^3.11.2",
|
"@tanstack/virtual-core": "^3.11.2",
|
||||||
"class-variance-authority": "^0.7.1",
|
"class-variance-authority": "^0.7.1",
|
||||||
"clsx": "^2.1.1",
|
"clsx": "^2.1.1",
|
||||||
|
"cmdk": "^1.0.0",
|
||||||
"date-fns": "^3.6.0",
|
"date-fns": "^3.6.0",
|
||||||
"lucide-react": "^0.469.0",
|
"lucide-react": "^0.469.0",
|
||||||
"next-themes": "^0.4.4",
|
"next-themes": "^0.4.4",
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ interface Product {
|
|||||||
cost_price: number;
|
cost_price: number;
|
||||||
vendor: string;
|
vendor: string;
|
||||||
brand: string;
|
brand: string;
|
||||||
categories: string;
|
categories: string[];
|
||||||
visible: boolean;
|
visible: boolean;
|
||||||
managing_stock: boolean;
|
managing_stock: boolean;
|
||||||
image?: string;
|
image?: string;
|
||||||
@@ -173,7 +173,13 @@ export function ProductTable({
|
|||||||
<TableCell>${product.cost_price.toFixed(2)}</TableCell>
|
<TableCell>${product.cost_price.toFixed(2)}</TableCell>
|
||||||
<TableCell>{product.vendor || '-'}</TableCell>
|
<TableCell>{product.vendor || '-'}</TableCell>
|
||||||
<TableCell>{product.brand || '-'}</TableCell>
|
<TableCell>{product.brand || '-'}</TableCell>
|
||||||
<TableCell>{product.categories || '-'}</TableCell>
|
<TableCell>
|
||||||
|
<div className="flex flex-wrap gap-1">
|
||||||
|
{product.categories?.map((category) => (
|
||||||
|
<Badge key={category} variant="outline">{category}</Badge>
|
||||||
|
)) || '-'}
|
||||||
|
</div>
|
||||||
|
</TableCell>
|
||||||
<TableCell>
|
<TableCell>
|
||||||
{product.visible ? (
|
{product.visible ? (
|
||||||
<Badge variant="secondary">Active</Badge>
|
<Badge variant="secondary">Active</Badge>
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ interface Product {
|
|||||||
cost_price: number;
|
cost_price: number;
|
||||||
vendor: string;
|
vendor: string;
|
||||||
brand: string;
|
brand: string;
|
||||||
categories: string;
|
categories: string[];
|
||||||
visible: boolean;
|
visible: boolean;
|
||||||
managing_stock: boolean;
|
managing_stock: boolean;
|
||||||
image: string | null;
|
image: string | null;
|
||||||
@@ -108,7 +108,8 @@ export function Products() {
|
|||||||
cost_price: parseFloat(product.cost_price) || 0,
|
cost_price: parseFloat(product.cost_price) || 0,
|
||||||
stock_quantity: parseInt(product.stock_quantity) || 0,
|
stock_quantity: parseInt(product.stock_quantity) || 0,
|
||||||
sku: product.SKU || product.sku || '',
|
sku: product.SKU || product.sku || '',
|
||||||
image: product.image || null
|
image: product.image || null,
|
||||||
|
categories: Array.isArray(product.categories) ? product.categories : []
|
||||||
}))
|
}))
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
|||||||
Reference in New Issue
Block a user