import { router, publicProcedure } from '@/src/trpc/trpc-index'; import { z } from 'zod'; import { db } from '@/src/db/db_index'; import { storeInfo, productInfo, units } from '@/src/db/schema'; import { eq, and, sql } from 'drizzle-orm'; import { scaffoldAssetUrl } from '@/src/lib/s3-client'; import { ApiError } from '@/src/lib/api-error'; import { getTagsByStoreId } from '@/src/stores/product-tag-store'; export async function scaffoldStores() { const storesData = await db .select({ id: storeInfo.id, name: storeInfo.name, description: storeInfo.description, imageUrl: storeInfo.imageUrl, productCount: sql`count(${productInfo.id})`.as('productCount'), }) .from(storeInfo) .leftJoin( productInfo, and(eq(productInfo.storeId, storeInfo.id), eq(productInfo.isSuspended, false)) ) .groupBy(storeInfo.id); // Generate signed URLs for store images and fetch sample products const storesWithDetails = await Promise.all( storesData.map(async (store) => { const signedImageUrl = store.imageUrl ? scaffoldAssetUrl(store.imageUrl) : null; // Fetch up to 3 products for this store const sampleProducts = await db .select({ id: productInfo.id, name: productInfo.name, images: productInfo.images, }) .from(productInfo) .where(and(eq(productInfo.storeId, store.id), eq(productInfo.isSuspended, false))) .limit(3); // Generate signed URLs for product images const productsWithSignedUrls = await Promise.all( sampleProducts.map(async (product) => { const images = product.images as string[]; return { id: product.id, name: product.name, signedImageUrl: (images && images.length > 0) ? scaffoldAssetUrl(images[0]) : null, }; }) ); return { id: store.id, name: store.name, description: store.description, signedImageUrl, productCount: store.productCount, sampleProducts: productsWithSignedUrls, }; }) ); return { stores: storesWithDetails, }; } export async function scaffoldStoreWithProducts(storeId: number) { // Fetch store info const storeData = await db.query.storeInfo.findFirst({ where: eq(storeInfo.id, storeId), columns: { id: true, name: true, description: true, imageUrl: true, }, }); if (!storeData) { throw new ApiError('Store not found', 404); } // Generate signed URL for store image const signedImageUrl = storeData.imageUrl ? scaffoldAssetUrl(storeData.imageUrl) : null; // Fetch products for this store const productsData = await db .select({ id: productInfo.id, name: productInfo.name, shortDescription: productInfo.shortDescription, price: productInfo.price, marketPrice: productInfo.marketPrice, images: productInfo.images, isOutOfStock: productInfo.isOutOfStock, incrementStep: productInfo.incrementStep, unitShortNotation: units.shortNotation, unitNotation: units.shortNotation, productQuantity: productInfo.productQuantity, }) .from(productInfo) .innerJoin(units, eq(productInfo.unitId, units.id)) .where(and(eq(productInfo.storeId, storeId), eq(productInfo.isSuspended, false))); // Generate signed URLs for product images const productsWithSignedUrls = await Promise.all( productsData.map(async (product) => ({ id: product.id, name: product.name, shortDescription: product.shortDescription, price: product.price, marketPrice: product.marketPrice, incrementStep: product.incrementStep, unit: product.unitShortNotation, unitNotation: product.unitNotation, images: scaffoldAssetUrl((product.images as string[]) || []), isOutOfStock: product.isOutOfStock, productQuantity: product.productQuantity })) ); const tags = await getTagsByStoreId(storeId); return { store: { id: storeData.id, name: storeData.name, description: storeData.description, signedImageUrl, }, products: productsWithSignedUrls, tags: tags.map(tag => ({ id: tag.id, tagName: tag.tagName, tagDescription: tag.tagDescription, imageUrl: tag.imageUrl, productIds: tag.productIds, })), }; } export const storesRouter = router({ getStores: publicProcedure .query(async () => { const response = await scaffoldStores(); return response; }), getStoreWithProducts: publicProcedure .input(z.object({ storeId: z.number(), })) .query(async ({ input }) => { const { storeId } = input; const response = await scaffoldStoreWithProducts(storeId); return response; }), });