128 lines
3.8 KiB
TypeScript
128 lines
3.8 KiB
TypeScript
import { db } from '../db/db_index'
|
|
import { productInfo, productSkus, storeInfo } from '../db/schema'
|
|
import { and, asc, eq, inArray } from 'drizzle-orm'
|
|
import type { InferSelectModel } from 'drizzle-orm'
|
|
import type { UserStoreDetailData, UserStoreProductData, UserStoreSummaryData, StoreSummary } from '@packages/shared'
|
|
import { composeSkuName, composeUnitNotation } from '../lib/sku-features'
|
|
|
|
type StoreRow = InferSelectModel<typeof storeInfo>
|
|
|
|
const getStringArray = (value: unknown): string[] | null => {
|
|
if (!Array.isArray(value)) return null
|
|
return value.map((item) => String(item))
|
|
}
|
|
|
|
export async function getStoreSummaries(): Promise<UserStoreSummaryData[]> {
|
|
const storesData = await db.select({
|
|
id: storeInfo.id,
|
|
name: storeInfo.name,
|
|
description: storeInfo.description,
|
|
imageUrl: storeInfo.imageUrl,
|
|
}).from(storeInfo)
|
|
|
|
const skus = await db.query.productSkus.findMany({
|
|
with: { product: true, marketStats: true },
|
|
orderBy: asc(productSkus.id),
|
|
})
|
|
const activeSkus = skus.filter((sku) => !sku.marketStats?.isSuspended && !sku.isDeleted)
|
|
|
|
const skusByStore = new Map<number, typeof skus>()
|
|
for (const sku of activeSkus) {
|
|
const storeId = sku.product?.storeId
|
|
if (storeId == null) continue
|
|
if (!skusByStore.has(storeId)) skusByStore.set(storeId, [])
|
|
skusByStore.get(storeId)!.push(sku)
|
|
}
|
|
|
|
return storesData.map((store) => {
|
|
const storeSkus = skusByStore.get(store.id) || []
|
|
const sampleProducts = storeSkus.slice(0, 3).map((sku) => ({
|
|
id: sku.id,
|
|
name: sku.product?.name ?? sku.name ?? 'Unknown',
|
|
images: getStringArray(sku.images),
|
|
}))
|
|
|
|
return {
|
|
id: store.id,
|
|
name: store.name,
|
|
description: store.description ?? null,
|
|
imageUrl: store.imageUrl ?? null,
|
|
productCount: storeSkus.length,
|
|
sampleProducts,
|
|
}
|
|
})
|
|
}
|
|
|
|
export async function getStoreDetail(storeId: number): Promise<UserStoreDetailData | null> {
|
|
const storeData = await db.query.storeInfo.findFirst({
|
|
where: eq(storeInfo.id, storeId),
|
|
columns: {
|
|
id: true,
|
|
name: true,
|
|
description: true,
|
|
imageUrl: true,
|
|
},
|
|
})
|
|
|
|
if (!storeData) {
|
|
return null
|
|
}
|
|
|
|
const storeProductIds = await db
|
|
.select({ id: productInfo.id })
|
|
.from(productInfo)
|
|
.where(eq(productInfo.storeId, storeId))
|
|
|
|
const productIdArr = storeProductIds.map((p) => p.id)
|
|
|
|
const skus = productIdArr.length > 0
|
|
? await db.query.productSkus.findMany({
|
|
where: inArray(productSkus.productId, productIdArr),
|
|
with: {
|
|
product: true,
|
|
features: true,
|
|
marketStats: true,
|
|
},
|
|
})
|
|
: []
|
|
|
|
const products: UserStoreProductData[] = skus
|
|
.filter((sku) => !sku.marketStats?.isSuspended && !sku.isDeleted)
|
|
.map((sku) => {
|
|
const features = sku.features || []
|
|
const marketStats = sku.marketStats
|
|
return {
|
|
id: sku.id,
|
|
name: composeSkuName(sku.product?.name ?? 'Unknown', features, sku.name),
|
|
shortDescription: sku.product?.shortDescription ?? null,
|
|
price: marketStats?.ourPrice ? String(marketStats.ourPrice) : '0',
|
|
marketPrice: marketStats?.marketPrice ? String(marketStats.marketPrice) : null,
|
|
incrementStep: sku.product?.incrementStep ?? 1,
|
|
unit: composeUnitNotation(features),
|
|
unitNotation: composeUnitNotation(features),
|
|
images: getStringArray(sku.images),
|
|
isOutOfStock: marketStats?.isOutOfStock ?? false,
|
|
productQuantity: 1,
|
|
}
|
|
})
|
|
|
|
return {
|
|
store: {
|
|
id: storeData.id,
|
|
name: storeData.name,
|
|
description: storeData.description ?? null,
|
|
imageUrl: storeData.imageUrl ?? null,
|
|
},
|
|
products,
|
|
}
|
|
}
|
|
|
|
export async function getStoresSummary(): Promise<StoreSummary[]> {
|
|
return db.query.storeInfo.findMany({
|
|
columns: {
|
|
id: true,
|
|
name: true,
|
|
description: true,
|
|
},
|
|
})
|
|
}
|