diff --git a/apps/admin-ui/app/(drawer)/products/edit.tsx b/apps/admin-ui/app/(drawer)/products/edit.tsx index e343794..9cf0a7d 100644 --- a/apps/admin-ui/app/(drawer)/products/edit.tsx +++ b/apps/admin-ui/app/(drawer)/products/edit.tsx @@ -42,6 +42,7 @@ export default function EditProduct() { longDescription: productData.longDescription || '', storeId: productData.storeId || 1, variants: (productData.skus || []).map((sku) => ({ + id: sku.id, name: sku.name || '', price: sku.price || '', marketPrice: sku.marketPrice || '', @@ -106,6 +107,7 @@ export default function EditProduct() { const allUrls = [...existingUrls, ...newUrls] return { + id: variant.id, name: variant.name || null, price: parseFloat(variant.price), marketPrice: variant.marketPrice ? parseFloat(variant.marketPrice) : undefined, diff --git a/apps/admin-ui/src/components/ProductForm.tsx b/apps/admin-ui/src/components/ProductForm.tsx index 7b660ca..b87a346 100644 --- a/apps/admin-ui/src/components/ProductForm.tsx +++ b/apps/admin-ui/src/components/ProductForm.tsx @@ -11,6 +11,7 @@ interface Attribute { } interface Variant { + id?: number name: string price: string marketPrice: string diff --git a/apps/backend/src/sqliteImporter.ts b/apps/backend/src/sqliteImporter.ts index b55fb03..1e9fc4d 100644 --- a/apps/backend/src/sqliteImporter.ts +++ b/apps/backend/src/sqliteImporter.ts @@ -69,11 +69,11 @@ export { checkProductExistsByName, checkUnitExists, getProductImagesById, - createSpecialDealsForProduct, - updateProductDeals, + createSpecialDealsForSku, + updateSkuDeals, replaceProductTags, mergeSkus, - toggleProductOutOfStock, + toggleSkuOutOfStock, updateSlotProducts, getSlotProductIds, getSlotsProductIds, diff --git a/apps/backend/src/trpc/apis/admin-apis/apis/product.ts b/apps/backend/src/trpc/apis/admin-apis/apis/product.ts index 0eb8a5d..55eccc6 100644 --- a/apps/backend/src/trpc/apis/admin-apis/apis/product.ts +++ b/apps/backend/src/trpc/apis/admin-apis/apis/product.ts @@ -310,6 +310,7 @@ export const productRouter = router({ storeId: z.number().min(1, 'Store is required'), incrementStep: z.number().optional().default(1), skus: z.array(z.object({ + id: z.number().optional(), name: z.string().optional().nullable(), price: z.number().positive('Price must be positive'), marketPrice: z.number().optional().nullable(), @@ -334,6 +335,7 @@ export const productRouter = router({ const allUploadUrls: string[] = skus.flatMap((sku) => sku.images) const skuInputs = skus.map((sku) => ({ + id: sku.id, name: sku.name ?? null, price: sku.price, marketPrice: sku.marketPrice ?? null, diff --git a/apps/backend/src/trpc/apis/admin-apis/apis/slots.ts b/apps/backend/src/trpc/apis/admin-apis/apis/slots.ts index 2de0549..c2e622c 100644 --- a/apps/backend/src/trpc/apis/admin-apis/apis/slots.ts +++ b/apps/backend/src/trpc/apis/admin-apis/apis/slots.ts @@ -209,7 +209,7 @@ export const slotsRouter = router({ }); } - const result = await updateSlotProductsInDb(String(slotId), productIds.map(String)) + const result = await updateSlotProductsInDb(String(slotId), skuIds.map(String)) /* // Old implementation - direct DB queries: diff --git a/apps/backend/src/trpc/apis/admin-apis/apis/vendor-snippets.ts b/apps/backend/src/trpc/apis/admin-apis/apis/vendor-snippets.ts index 196671a..d077771 100644 --- a/apps/backend/src/trpc/apis/admin-apis/apis/vendor-snippets.ts +++ b/apps/backend/src/trpc/apis/admin-apis/apis/vendor-snippets.ts @@ -403,7 +403,7 @@ export const vendorSnippetsRouter = router({ const filteredOrders = matchingOrders.filter(order => { const status = order.orderStatus; if (status[0].isCancelled) return false; - const orderProductIds = order.orderItems.map(item => item.productId); + const orderProductIds = order.orderItems.map(item => item.skuId); return snippet.skuIds.some(productId => orderProductIds.includes(productId)); }); @@ -411,17 +411,17 @@ export const vendorSnippetsRouter = router({ const formattedOrders = filteredOrders.map(order => { // Filter orderItems to only include products attached to the snippet const attachedOrderItems = order.orderItems.filter(item => - snippet.skuIds.includes(item.productId) + snippet.skuIds.includes(item.skuId) ); const products = attachedOrderItems.map(item => ({ orderItemId: item.id, - productId: item.productId, - productName: item.product.name, + productId: item.skuId, + productName: item.sku?.product?.name || 'Unknown', quantity: parseFloat(item.quantity), - productSize: item.product.productQuantity, + productSize: 1, price: parseFloat((item.price ?? 0).toString()), - unit: item.product.unit?.shortNotation || 'unit', + unit: (item.sku?.features || []).map((f: any) => f.featureValue).join(' ') || 'unit', subtotal: parseFloat((item.price ?? 0).toString()) * parseFloat(item.quantity), is_packaged: item.is_packaged, is_package_verified: item.is_package_verified, @@ -488,9 +488,9 @@ export const vendorSnippetsRouter = router({ orderDate: order.createdAt ? order.createdAt.toISOString() : new Date(0).toISOString(), totalQuantity: order.orderItems.reduce((sum, item) => sum + parseFloat(item.quantity || '0'), 0), products: order.orderItems.map(item => ({ - name: item.product.name, + name: item.sku?.product?.name || 'Unknown', quantity: parseFloat(item.quantity || '0'), - unit: item.product.unit?.shortNotation || 'unit', + unit: (item.sku?.features || []).map((f: any) => f.featureValue).join(' ') || 'unit', })), })) }), @@ -588,7 +588,7 @@ export const vendorSnippetsRouter = router({ const filteredOrders = matchingOrders.filter(order => { const status = order.orderStatus; if (status[0]?.isCancelled) return false; - const orderProductIds = order.orderItems.map(item => item.productId); + const orderProductIds = order.orderItems.map(item => item.skuId); return snippet.skuIds.some(productId => orderProductIds.includes(productId)); }); @@ -596,18 +596,18 @@ export const vendorSnippetsRouter = router({ const formattedOrders = filteredOrders.map(order => { // Filter orderItems to only include products attached to the snippet const attachedOrderItems = order.orderItems.filter(item => - snippet.skuIds.includes(item.productId) + snippet.skuIds.includes(item.skuId) ); const products = attachedOrderItems.map(item => ({ orderItemId: item.id, - productId: item.productId, - productName: item.product.name, + productId: item.skuId, + productName: item.sku?.product?.name || 'Unknown', quantity: parseFloat(item.quantity), price: parseFloat((item.price ?? 0).toString()), - unit: item.product.unit?.shortNotation || 'unit', + unit: (item.sku?.features || []).map((f: any) => f.featureValue).join(' ') || 'unit', subtotal: parseFloat((item.price ?? 0).toString()) * parseFloat(item.quantity), - productSize: item.product.productQuantity, + productSize: 1, is_packaged: item.is_packaged, is_package_verified: item.is_package_verified, })); diff --git a/apps/user-ui/components/cart-page.tsx b/apps/user-ui/components/cart-page.tsx index c4202bb..af73daa 100644 --- a/apps/user-ui/components/cart-page.tsx +++ b/apps/user-ui/components/cart-page.tsx @@ -461,6 +461,7 @@ export default function CartPage({ isFlashDelivery = false }: CartPageProps) { {(() => { + const unit = product?.unitNotation || ''; return unit; })()} diff --git a/apps/user-ui/src/components/AddToCartDialog.tsx b/apps/user-ui/src/components/AddToCartDialog.tsx index 2f04705..b7f2d49 100644 --- a/apps/user-ui/src/components/AddToCartDialog.tsx +++ b/apps/user-ui/src/components/AddToCartDialog.tsx @@ -67,7 +67,7 @@ export default function AddToCartDialog() { // Pre-select cart's slotId and quantity if item is already in cart useEffect(() => { if (isOpen && product) { - const cartItem = cartData?.items?.find((item: any) => item.productId === product.id); + const cartItem = cartData?.items?.find((item: any) => item.skuId === product.id); const cartQuantity = cartItem?.quantity || 0; // Set quantity: 0 → 1, >1 → keep as is @@ -109,7 +109,7 @@ export default function AddToCartDialog() { .filter((slot) => dayjs(slot.freezeTime).isAfter(dayjs())); // Find cart item for this product - const cartItem = cartData?.items?.find((item: any) => item.productId === product?.id); + const cartItem = cartData?.items?.find((item: any) => item.skuId === product?.id); // Determine if updating existing item (quantity > 1 means it's an update) const isUpdate = (cartItem?.quantity || 0) >= 1; diff --git a/packages/db_helper_sqlite/index.ts b/packages/db_helper_sqlite/index.ts index f40fb44..d275d72 100644 --- a/packages/db_helper_sqlite/index.ts +++ b/packages/db_helper_sqlite/index.ts @@ -79,11 +79,11 @@ export { checkProductExistsByName, checkUnitExists, getProductImagesById, - createSpecialDealsForProduct, - updateProductDeals, + createSpecialDealsForSku, + updateSkuDeals, replaceProductTags, mergeSkus, - toggleProductOutOfStock, + toggleSkuOutOfStock, updateSlotProducts, getSlotProductIds, getSlotsProductIds, diff --git a/packages/db_helper_sqlite/src/admin-apis/product.ts b/packages/db_helper_sqlite/src/admin-apis/product.ts index 1275a67..35637d2 100644 --- a/packages/db_helper_sqlite/src/admin-apis/product.ts +++ b/packages/db_helper_sqlite/src/admin-apis/product.ts @@ -109,7 +109,7 @@ const mapSku = (sku: SkuRow, features: SkuFeatureRow[] = []): AdminSku => ({ const mapSpecialDeal = (deal: SpecialDealRow): AdminSpecialDeal => ({ id: deal.id, - productId: deal.productId, + skuId: deal.skuId, quantity: String(deal.quantity ?? '0'), price: String(deal.price ?? '0'), validTill: deal.validTill, @@ -298,37 +298,54 @@ export async function updateProduct(id: number, input: any): Promise skus.map((sku) => sku.id)) + }) + const existingSkuIdSet = new Set(existingSkus.map((s) => s.id)) - if (existingSkuIds.length > 0) { - await db.delete(skuFeatures).where(inArray(skuFeatures.skuId, existingSkuIds)) - await db.delete(productSkus).where(inArray(productSkus.id, existingSkuIds)) - } + for (const sku of skus) { + if (sku.id != null && existingSkuIdSet.has(sku.id)) { + // Update existing SKU + await db.update(productSkus) + .set({ + name: sku.name ?? null, + price: String(sku.price), + marketPrice: sku.marketPrice != null ? String(sku.marketPrice) : null, + images: sku.images ?? null, + isFlashAvailable: sku.isFlashAvailable ?? false, + flashPrice: sku.flashPrice != null ? String(sku.flashPrice) : null, + }) + .where(eq(productSkus.id, sku.id)) - const skuRows = await db.insert(productSkus).values( - skus.map((sku: any) => ({ - productId: id, - name: sku.name ?? null, - price: String(sku.price), - marketPrice: sku.marketPrice != null ? String(sku.marketPrice) : null, - images: sku.images ?? null, - isFlashAvailable: sku.isFlashAvailable ?? false, - flashPrice: sku.flashPrice != null ? String(sku.flashPrice) : null, - })) - ).returning() + await db.delete(skuFeatures).where(eq(skuFeatures.skuId, sku.id)) + await db.insert(skuFeatures).values( + sku.features.map((f: any) => ({ + skuId: sku.id, + featureName: f.featureName, + featureValue: f.featureValue, + })) + ) + } else { + // Insert new SKU + const [newSku] = await db.insert(productSkus).values({ + productId: id, + name: sku.name ?? null, + price: String(sku.price), + marketPrice: sku.marketPrice != null ? String(sku.marketPrice) : null, + images: sku.images ?? null, + isFlashAvailable: sku.isFlashAvailable ?? false, + flashPrice: sku.flashPrice != null ? String(sku.flashPrice) : null, + }).returning() - for (let i = 0; i < skuRows.length; i++) { - const sku = skus[i] - await db.insert(skuFeatures).values( - sku.features.map((f: any) => ({ - skuId: skuRows[i].id, - featureName: f.featureName, - featureValue: f.featureValue, - })) - ) + await db.insert(skuFeatures).values( + sku.features.map((f: any) => ({ + skuId: newSku.id, + featureName: f.featureName, + featureValue: f.featureValue, + })) + ) + } } } @@ -353,9 +370,9 @@ export async function updateProduct(id: number, input: any): Promise { - const product = await db.query.productInfo.findFirst({ - where: eq(productInfo.id, id), +export async function toggleSkuOutOfStock(id: number): Promise { + const product = await db.query.productSkus.findFirst({ + where: eq(productSkus.id, id), }) if (!product) { @@ -363,18 +380,18 @@ export async function toggleProductOutOfStock(id: number): Promise { @@ -386,16 +403,15 @@ export async function updateSlotProducts(slotId: string, productIds: string[]): throw new Error(`Slot ${slotId} not found`) } - const currentProductIds = slot.productIds || [] - const newProductIds = productIds.map((id: string) => parseInt(id)) + const currentSkuIds = slot.skuIds || [] + const newSkuIds = productIds.map((id: string) => parseInt(id)) - // Simply update the productIds array await db.update(deliverySlotInfo) - .set({ productIds: newProductIds }) + .set({ skuIds: newSkuIds }) .where(eq(deliverySlotInfo.id, parseInt(slotId))) - const productsToAdd = newProductIds.filter((id: number) => !currentProductIds.includes(id)) - const productsToRemove = currentProductIds.filter((id: number) => !newProductIds.includes(id)) + const productsToAdd = newSkuIds.filter((id: number) => !currentSkuIds.includes(id)) + const productsToRemove = currentSkuIds.filter((id: number) => !newSkuIds.includes(id)) return { message: 'Slot products updated successfully', @@ -409,7 +425,7 @@ export async function getSlotProductIds(slotId: string): Promise { where: eq(deliverySlotInfo.id, parseInt(slotId)), }) - return slot?.productIds || [] + return slot?.skuIds || [] } export async function getAllUnits(): Promise { @@ -573,7 +589,7 @@ export async function getSlotsProductIds(slotIds: number[]): Promise = {} for (const slot of slots) { - result[slot.id] = slot.productIds || [] + result[slot.id] = slot.skuIds || [] } slotIds.forEach((slotId) => { @@ -856,8 +872,8 @@ export async function checkUnitExists(unitId: number): Promise { } export async function getProductImagesById(productId: number): Promise { - const product = await db.query.productInfo.findFirst({ - where: eq(productInfo.id, productId), + const product = await db.query.productSkus.findFirst({ + where: eq(productSkus.id, productId), columns: { images: true }, }) @@ -874,7 +890,7 @@ export interface CreateSpecialDealInput { validTill: string | Date } -export async function createSpecialDealsForProduct( +export async function createSpecialDealsForSku( productId: number, deals: CreateSpecialDealInput[] ): Promise { @@ -897,17 +913,17 @@ export async function createSpecialDealsForProduct( return createdDeals.map(mapSpecialDeal) } -export async function updateProductDeals( +export async function updateSkuDeals( productId: number, deals: CreateSpecialDealInput[] ): Promise { if (deals.length === 0) { - await db.delete(specialDeals).where(eq(specialDeals.productId, productId)) + await db.delete(specialDeals).where(eq(specialDeals.skuId, productId)) return } const existingDeals = await db.query.specialDeals.findMany({ - where: eq(specialDeals.productId, productId), + where: eq(specialDeals.skuId, productId), }) const existingDealsMap = new Map( diff --git a/packages/db_helper_sqlite/src/admin-apis/vendor-snippets.ts b/packages/db_helper_sqlite/src/admin-apis/vendor-snippets.ts index b32107c..07a58ef 100644 --- a/packages/db_helper_sqlite/src/admin-apis/vendor-snippets.ts +++ b/packages/db_helper_sqlite/src/admin-apis/vendor-snippets.ts @@ -156,9 +156,10 @@ export async function getVendorOrdersBySlotId(slotId: number) { with: { orderItems: { with: { - product: { + sku: { with: { - unit: true, + product: true, + features: true, }, }, }, @@ -177,9 +178,10 @@ export async function getVendorOrders() { user: true, orderItems: { with: { - product: { + sku: { with: { - unit: true, + product: true, + features: true, }, }, }, @@ -193,9 +195,10 @@ export async function getOrderItemsByOrderIds(orderIds: number[]) { return await db.query.orderItems.findMany({ where: inArray(orderItems.orderId, orderIds), with: { - product: { + sku: { with: { - unit: true, + product: true, + features: true, }, }, }, diff --git a/packages/db_helper_sqlite/src/db/porter.ts b/packages/db_helper_sqlite/src/db/porter.ts index fcb94f9..76c08a6 100644 --- a/packages/db_helper_sqlite/src/db/porter.ts +++ b/packages/db_helper_sqlite/src/db/porter.ts @@ -5,7 +5,7 @@ import { db } from '@/src/db/db_index' import { userDetails, - productInfo, + productSkus, productTagInfo, complaints, } from '@/src/db/schema' @@ -43,21 +43,21 @@ async function migrateUserDetails() { } async function migrateProductInfo() { - console.log('Migrating productInfo...') - const products = await db.select().from(productInfo).where(not(isNull(productInfo.images))) + console.log('Migrating productSkus...') + const products = await db.select().from(productSkus).where(not(isNull(productSkus.images))) console.log(`Found ${products.length} product records with images`) for (const product of products) { if (product.images && Array.isArray(product.images)) { const cleanedUrls = cleanImageUrls(product.images) - await db.update(productInfo) + await db.update(productSkus) .set({ images: cleanedUrls }) - .where(eq(productInfo.id, product.id)) + .where(eq(productSkus.id, product.id)) } } - console.log('productInfo migration completed') + console.log('productSkus migration completed') } async function migrateProductTagInfo() { diff --git a/packages/db_helper_sqlite/src/user-apis/cart.ts b/packages/db_helper_sqlite/src/user-apis/cart.ts index 563122e..5ae13f2 100644 --- a/packages/db_helper_sqlite/src/user-apis/cart.ts +++ b/packages/db_helper_sqlite/src/user-apis/cart.ts @@ -1,5 +1,5 @@ import { db } from '../db/db_index' -import { cartItems, productInfo, units } from '../db/schema' +import { cartItems, productSkus } from '../db/schema' import { and, eq, sql } from 'drizzle-orm' import type { UserCartItem } from '@packages/shared' @@ -9,55 +9,51 @@ const getStringArray = (value: unknown): string[] => { } export async function getCartItemsWithProducts(userId: number): Promise { - const cartItemsWithProducts = await db - .select({ - cartId: cartItems.id, - productId: productInfo.id, - productName: productInfo.name, - productPrice: productInfo.price, - productImages: productInfo.images, - productQuantity: productInfo.productQuantity, - isOutOfStock: productInfo.isOutOfStock, - unitShortNotation: units.shortNotation, - quantity: cartItems.quantity, - addedAt: cartItems.addedAt, - }) - .from(cartItems) - .innerJoin(productInfo, eq(cartItems.productId, productInfo.id)) - .innerJoin(units, eq(productInfo.unitId, units.id)) - .where(eq(cartItems.userId, userId)) + const cartItemsWithProducts = await db.query.cartItems.findMany({ + where: eq(cartItems.userId, userId), + with: { + sku: { + with: { + product: true, + features: true, + }, + }, + }, + }) return cartItemsWithProducts.map((item) => { - const priceValue = item.productPrice ?? '0' + const sku = item.sku + const features = sku?.features || [] + const priceValue = sku?.price ?? '0' const quantityValue = item.quantity ?? '0' return { - id: item.cartId, - productId: item.productId, + id: item.id, + skuId: item.skuId, quantity: parseFloat(quantityValue), addedAt: item.addedAt, - product: { - id: item.productId, - name: item.productName, - price: priceValue.toString(), - productQuantity: item.productQuantity, - unit: item.unitShortNotation, - isOutOfStock: item.isOutOfStock, - images: getStringArray(item.productImages), - }, - subtotal: parseFloat(priceValue.toString()) * parseFloat(quantityValue), + product: { + id: sku?.id ?? 0, + name: sku?.product?.name ?? 'Unknown', + price: String(priceValue), + productQuantity: 1, + unit: features.map((f) => f.featureValue).join(' '), + isOutOfStock: sku?.isOutOfStock ?? false, + images: getStringArray(sku?.images), + }, + subtotal: parseFloat(String(priceValue)) * parseFloat(quantityValue), } }) } -export async function getProductById(productId: number) { - return db.query.productInfo.findFirst({ - where: eq(productInfo.id, productId), +export async function getProductById(skuId: number) { + return db.query.productSkus.findFirst({ + where: eq(productSkus.id, skuId), }) } -export async function getCartItemByUserProduct(userId: number, productId: number) { +export async function getCartItemByUserProduct(userId: number, skuId: number) { return db.query.cartItems.findFirst({ - where: and(eq(cartItems.userId, userId), eq(cartItems.productId, productId)), + where: and(eq(cartItems.userId, userId), eq(cartItems.skuId, skuId)), }) } @@ -69,10 +65,10 @@ export async function incrementCartItemQuantity(itemId: number, quantity: number .where(eq(cartItems.id, itemId)) } -export async function insertCartItem(userId: number, productId: number, quantity: number): Promise { +export async function insertCartItem(userId: number, skuId: number, quantity: number): Promise { await db.insert(cartItems).values({ userId, - productId, + skuId, quantity: quantity.toString(), }) } diff --git a/packages/db_helper_sqlite/src/user-apis/order.ts b/packages/db_helper_sqlite/src/user-apis/order.ts index acc4bc9..52ded76 100644 --- a/packages/db_helper_sqlite/src/user-apis/order.ts +++ b/packages/db_helper_sqlite/src/user-apis/order.ts @@ -649,32 +649,32 @@ export async function getProductsForRecentOrders( productIds: number[], limit: number ): Promise { - const results = await db - .select({ - id: productInfo.id, - name: productInfo.name, - shortDescription: productInfo.shortDescription, - price: productInfo.price, - images: productInfo.images, - isOutOfStock: productInfo.isOutOfStock, - unitShortNotation: units.shortNotation, - incrementStep: productInfo.incrementStep, - }) - .from(productInfo) - .innerJoin(units, eq(productInfo.unitId, units.id)) - .where( - and( - inArray(productInfo.id, productIds), - eq(productInfo.isSuspended, false) - ) - ) - .orderBy(desc(productInfo.createdAt)) - .limit(limit) + const skus = await db.query.productSkus.findMany({ + where: and( + inArray(productSkus.id, productIds), + eq(productSkus.isSuspended, false) + ), + with: { + product: true, + features: true, + }, + orderBy: desc(productSkus.createdAt), + limit, + }) - return results.map((product) => ({ - ...product, - price: String(product.price ?? '0'), - })) + return skus.map((sku) => { + const features = sku.features || [] + return { + id: sku.id, + name: sku.product?.name ?? 'Unknown', + shortDescription: sku.product?.shortDescription ?? null, + price: String(sku.price ?? '0'), + images: sku.images, + isOutOfStock: sku.isOutOfStock, + unitShortNotation: features.map((f) => f.featureValue).join(' '), + incrementStep: sku.product?.incrementStep ?? 1, + } + }) } // ============================================================================ @@ -697,8 +697,10 @@ export interface OrderWithFullData { } | null orderItems: Array<{ quantity: string - product: { - name: string + sku: { + product: { + name: string + } | null } | null }> slot: { @@ -778,9 +780,13 @@ export async function getOrderByIdWithFullData( }, orderItems: { with: { - product: { - columns: { - name: true, + sku: { + with: { + product: { + columns: { + name: true, + }, + }, }, }, }, diff --git a/packages/db_helper_sqlite/src/user-apis/product.ts b/packages/db_helper_sqlite/src/user-apis/product.ts index 17d8194..6c30982 100644 --- a/packages/db_helper_sqlite/src/user-apis/product.ts +++ b/packages/db_helper_sqlite/src/user-apis/product.ts @@ -1,5 +1,5 @@ import { db } from '../db/db_index' -import { deliverySlotInfo, productInfo, productSkus, productReviews, productTags, specialDeals, storeInfo, units, users } from '../db/schema' +import { deliverySlotInfo, productInfo, productSkus, productReviews, productTags, specialDeals, storeInfo, users } from '../db/schema' import { and, desc, eq, gt, sql } from 'drizzle-orm' import type { UserProductDetailData, UserProductReview } from '@packages/shared' @@ -177,30 +177,32 @@ export async function getAllProductsWithUnits(tagId?: number): Promise 0) { - whereCondition = inArray(productInfo.id, productIds) + whereCondition = inArray(productSkus.productId, productIds) } - const results = await db - .select({ - id: productInfo.id, - name: productInfo.name, - shortDescription: productInfo.shortDescription, - price: productInfo.price, - marketPrice: productInfo.marketPrice, - images: productInfo.images, - isOutOfStock: productInfo.isOutOfStock, - unitShortNotation: units.shortNotation, - productQuantity: productInfo.productQuantity, - }) - .from(productInfo) - .innerJoin(units, eq(productInfo.unitId, units.id)) - .where(whereCondition) + const skus = await db.query.productSkus.findMany({ + where: whereCondition, + with: { + product: true, + features: true, + }, + }) - return results.map((product) => ({ - ...product, - price: String(product.price ?? '0'), - marketPrice: product.marketPrice ? String(product.marketPrice) : null, - })) + return skus.map((sku) => { + const features = sku.features || [] + return { + id: sku.product?.id ?? 0, + name: sku.product?.name ?? 'Unknown', + skuId: sku.id, + skuName: sku.name ?? null, + shortDescription: sku.product?.shortDescription ?? null, + price: String(sku.price ?? '0'), + marketPrice: sku.marketPrice ? String(sku.marketPrice) : null, + images: sku.images, + isOutOfStock: sku.isOutOfStock, + features: features.map((f) => ({ featureName: f.featureName, featureValue: f.featureValue })), + } + }) } /** diff --git a/packages/shared/types/admin.ts b/packages/shared/types/admin.ts index 809df52..72e64a6 100644 --- a/packages/shared/types/admin.ts +++ b/packages/shared/types/admin.ts @@ -372,13 +372,7 @@ export interface AdminSkuVariant { export interface AdminSku { id: number productId: number - productName?: string - skuCode: string | null - displayName: string - unitId: number - unit?: AdminUnit - productQuantity: number - incrementStep: number + name: string | null price: string marketPrice: string | null images: string[] | null @@ -387,11 +381,9 @@ export interface AdminSku { isSuspended: boolean isFlashAvailable: boolean flashPrice: string | null - isComboOnly: boolean - sortOrder: number - isDefault: boolean createdAt: Date - variants: AdminSkuVariant[] + features: AdminSkuFeature[] +} } export interface AdminProduct { @@ -443,6 +435,8 @@ export interface CreateProductInput { incrementStep?: number skus: CreateSkuInput[] } + +export interface AdminProductTagInfo { id: number; tagName: string; tagDescription: string | null; @@ -465,7 +459,7 @@ export interface AdminProductTagWithProducts extends AdminProductTagInfo { export interface AdminSpecialDeal { id: number; - productId: number; + skuId: number; quantity: string; price: string; validTill: Date;