account for advanced edit

This commit is contained in:
Jake Kasper
2025-08-22 08:40:21 -04:00
parent bb365d918d
commit f95422325c
3 changed files with 98 additions and 15 deletions

View File

@@ -82,10 +82,12 @@ router.get('/', async (req, res, next) => {
// Get user's custom products // Get user's custom products
const userProductsQuery = ` const userProductsQuery = `
SELECT up.*, p.name as base_product_name, p.brand, p.product_type, pc.name as category_name SELECT up.*, p.name as base_product_name, p.brand as base_brand, p.product_type as base_product_type,
pc.name as category_name, upc.name as custom_category_name
FROM user_products up FROM user_products up
LEFT JOIN products p ON up.product_id = p.id LEFT JOIN products p ON up.product_id = p.id
LEFT JOIN product_categories pc ON p.category_id = pc.id LEFT JOIN product_categories pc ON p.category_id = pc.id
LEFT JOIN product_categories upc ON up.category_id = upc.id
WHERE up.user_id = $1 WHERE up.user_id = $1
ORDER BY COALESCE(up.custom_name, p.name) ORDER BY COALESCE(up.custom_name, p.name)
`; `;
@@ -112,14 +114,23 @@ router.get('/', async (req, res, next) => {
baseProductId: product.product_id, baseProductId: product.product_id,
baseProductName: product.base_product_name, baseProductName: product.base_product_name,
customName: product.custom_name, customName: product.custom_name,
brand: product.brand, // Use custom fields if available, otherwise fall back to base product
categoryName: product.category_name, brand: product.custom_brand || product.base_brand,
productType: product.product_type, customBrand: product.custom_brand,
categoryId: product.category_id,
categoryName: product.custom_category_name || product.category_name,
productType: product.custom_product_type || product.base_product_type,
customProductType: product.custom_product_type,
activeIngredients: product.custom_active_ingredients,
customActiveIngredients: product.custom_active_ingredients,
description: product.custom_description,
customDescription: product.custom_description,
customRateAmount: parseFloat(product.custom_rate_amount), customRateAmount: parseFloat(product.custom_rate_amount),
customRateUnit: product.custom_rate_unit, customRateUnit: product.custom_rate_unit,
notes: product.notes, notes: product.notes,
isShared: false, isShared: false,
createdAt: product.created_at createdAt: product.created_at,
updatedAt: product.updated_at
})) }))
} }
}); });
@@ -292,7 +303,19 @@ router.post('/:id/rates', validateParams(idParamSchema), validateRequest(product
// @access Private // @access Private
router.post('/user', validateRequest(userProductSchema), async (req, res, next) => { router.post('/user', validateRequest(userProductSchema), async (req, res, next) => {
try { try {
const { productId, customName, customRateAmount, customRateUnit, notes } = req.body; const {
productId,
customName,
customRateAmount,
customRateUnit,
notes,
// Advanced fields for creating custom products
brand,
categoryId,
productType,
activeIngredients,
description
} = req.body;
// If based on existing product, verify it exists // If based on existing product, verify it exists
if (productId) { if (productId) {
@@ -312,10 +335,13 @@ router.post('/user', validateRequest(userProductSchema), async (req, res, next)
} }
const result = await pool.query( const result = await pool.query(
`INSERT INTO user_products (user_id, product_id, custom_name, custom_rate_amount, custom_rate_unit, notes) `INSERT INTO user_products (user_id, product_id, custom_name, custom_brand, category_id,
VALUES ($1, $2, $3, $4, $5, $6) custom_product_type, custom_active_ingredients, custom_description,
custom_rate_amount, custom_rate_unit, notes)
VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11)
RETURNING *`, RETURNING *`,
[req.user.id, productId, customName, customRateAmount, customRateUnit, notes] [req.user.id, productId, customName, brand, categoryId, productType, activeIngredients,
description, customRateAmount, customRateUnit, notes]
); );
const userProduct = result.rows[0]; const userProduct = result.rows[0];
@@ -328,10 +354,16 @@ router.post('/user', validateRequest(userProductSchema), async (req, res, next)
id: userProduct.id, id: userProduct.id,
baseProductId: userProduct.product_id, baseProductId: userProduct.product_id,
customName: userProduct.custom_name, customName: userProduct.custom_name,
customBrand: userProduct.custom_brand,
categoryId: userProduct.category_id,
customProductType: userProduct.custom_product_type,
customActiveIngredients: userProduct.custom_active_ingredients,
customDescription: userProduct.custom_description,
customRateAmount: parseFloat(userProduct.custom_rate_amount), customRateAmount: parseFloat(userProduct.custom_rate_amount),
customRateUnit: userProduct.custom_rate_unit, customRateUnit: userProduct.custom_rate_unit,
notes: userProduct.notes, notes: userProduct.notes,
createdAt: userProduct.created_at createdAt: userProduct.created_at,
updatedAt: userProduct.updated_at
} }
} }
}); });
@@ -393,7 +425,25 @@ router.get('/user/:id', validateParams(idParamSchema), async (req, res, next) =>
router.put('/user/:id', validateParams(idParamSchema), validateRequest(userProductSchema), async (req, res, next) => { router.put('/user/:id', validateParams(idParamSchema), validateRequest(userProductSchema), async (req, res, next) => {
try { try {
const userProductId = req.params.id; const userProductId = req.params.id;
const { productId, customName, customRateAmount, customRateUnit, notes } = req.body; const {
productId,
customName,
customRateAmount,
customRateUnit,
notes,
isAdvancedEdit,
// Advanced edit fields (will be ignored for now as schema doesn't support them)
brand,
categoryId,
productType,
activeIngredients,
description
} = req.body;
// Log warning if advanced edit is attempted (not fully supported yet)
if (isAdvancedEdit) {
console.warn(`Advanced edit attempted for user product ${userProductId}. Only basic fields will be updated.`);
}
// Check if user product exists and belongs to user // Check if user product exists and belongs to user
const checkResult = await pool.query( const checkResult = await pool.query(
@@ -419,11 +469,24 @@ router.put('/user/:id', validateParams(idParamSchema), validateRequest(userProdu
const result = await pool.query( const result = await pool.query(
`UPDATE user_products `UPDATE user_products
SET product_id = $1, custom_name = $2, custom_rate_amount = $3, SET product_id = $1, custom_name = $2, custom_brand = $3, category_id = $4,
custom_rate_unit = $4, notes = $5, updated_at = CURRENT_TIMESTAMP custom_product_type = $5, custom_active_ingredients = $6, custom_description = $7,
WHERE id = $6 custom_rate_amount = $8, custom_rate_unit = $9, notes = $10, updated_at = CURRENT_TIMESTAMP
WHERE id = $11
RETURNING *`, RETURNING *`,
[productId, customName, customRateAmount, customRateUnit, notes, userProductId] [
productId,
customName,
brand,
categoryId,
productType,
activeIngredients,
description,
customRateAmount,
customRateUnit,
notes,
userProductId
]
); );
const userProduct = result.rows[0]; const userProduct = result.rows[0];
@@ -436,6 +499,11 @@ router.put('/user/:id', validateParams(idParamSchema), validateRequest(userProdu
id: userProduct.id, id: userProduct.id,
baseProductId: userProduct.product_id, baseProductId: userProduct.product_id,
customName: userProduct.custom_name, customName: userProduct.custom_name,
customBrand: userProduct.custom_brand,
categoryId: userProduct.category_id,
customProductType: userProduct.custom_product_type,
customActiveIngredients: userProduct.custom_active_ingredients,
customDescription: userProduct.custom_description,
customRateAmount: parseFloat(userProduct.custom_rate_amount), customRateAmount: parseFloat(userProduct.custom_rate_amount),
customRateUnit: userProduct.custom_rate_unit, customRateUnit: userProduct.custom_rate_unit,
notes: userProduct.notes, notes: userProduct.notes,

View File

@@ -100,6 +100,11 @@ CREATE TABLE user_products (
user_id INTEGER REFERENCES users(id) ON DELETE CASCADE, user_id INTEGER REFERENCES users(id) ON DELETE CASCADE,
product_id INTEGER REFERENCES products(id), product_id INTEGER REFERENCES products(id),
custom_name VARCHAR(255), custom_name VARCHAR(255),
custom_brand VARCHAR(100),
category_id INTEGER REFERENCES product_categories(id),
custom_product_type VARCHAR(50) CHECK (custom_product_type IN ('granular', 'liquid')),
custom_active_ingredients TEXT,
custom_description TEXT,
custom_rate_amount DECIMAL(8, 4), custom_rate_amount DECIMAL(8, 4),
custom_rate_unit VARCHAR(50), custom_rate_unit VARCHAR(50),
notes TEXT, notes TEXT,

View File

@@ -0,0 +1,10 @@
-- Migration: Add advanced fields to user_products table
-- This allows users to have fully customizable products with their own brand, category, etc.
-- Add the advanced fields
ALTER TABLE user_products
ADD COLUMN custom_brand VARCHAR(100),
ADD COLUMN category_id INTEGER REFERENCES product_categories(id),
ADD COLUMN custom_product_type VARCHAR(50) CHECK (custom_product_type IN ('granular', 'liquid')),
ADD COLUMN custom_active_ingredients TEXT,
ADD COLUMN custom_description TEXT;