diff --git a/apps/api/src/modules/listings/repositories/listing-repository.js b/apps/api/src/modules/listings/repositories/listing-repository.js index b7cb17a..3ab93f6 100644 --- a/apps/api/src/modules/listings/repositories/listing-repository.js +++ b/apps/api/src/modules/listings/repositories/listing-repository.js @@ -1,8 +1,11 @@ import { and, asc, count, desc, eq, ilike, inArray, or, sql } from 'drizzle-orm'; import { + conditions, inventoryItems, listings, + marketValueOverrides, + marketValuations, products, } from '../../../infrastructure/database/schema.js'; @@ -134,17 +137,31 @@ export function createListingRepository(db) { async findPublicById(listingId) { const [result] = await db - .select({ listing: listings }) + .select({ listing: listings, condition: conditions }) .from(listings) .innerJoin(inventoryItems, eq(inventoryItems.id, listings.inventoryItemId)) .innerJoin(products, eq(products.id, inventoryItems.productId)) + .innerJoin(conditions, eq(conditions.id, inventoryItems.conditionId)) .where(and( eq(listings.id, listingId), inArray(listings.status, ['AVAILABLE', 'PENDING']), eq(inventoryItems.status, 'ACTIVE'), )); - return result?.listing ?? null; + if (!result) return null; + const [override] = await db.select().from(marketValueOverrides) + .where(eq(marketValueOverrides.inventoryItemId, result.listing.inventoryItemId)) + .orderBy(desc(marketValueOverrides.createdAt)).limit(1); + const [valuation] = await db.select().from(marketValuations) + .where(eq(marketValuations.inventoryItemId, result.listing.inventoryItemId)) + .orderBy(desc(marketValuations.calculatedAt)).limit(1); + return { + ...result.listing, + conditionName: result.condition.name, + conditionCode: result.condition.code, + marketValueMinor: override?.valueMinor ?? valuation?.valueMinor ?? null, + marketValueCurrency: override?.currency ?? valuation?.currency ?? null, + }; }, async updateStatus(listingId, status) { diff --git a/apps/web/src/components/organisms/CollectibleDetail.stories.js b/apps/web/src/components/organisms/CollectibleDetail.stories.js index c1dd6ed..448fc46 100644 --- a/apps/web/src/components/organisms/CollectibleDetail.stories.js +++ b/apps/web/src/components/organisms/CollectibleDetail.stories.js @@ -7,6 +7,7 @@ export const ListingDetail = { title: 'Charizard ex #199/165', status: 'AVAILABLE', priceMinor: 11500, + marketValueMinor: 12000, condition: 'Near Mint', description: 'A clean collector copy with a clear front and back.', facts: [ diff --git a/apps/web/src/components/organisms/CollectibleDetail.vue b/apps/web/src/components/organisms/CollectibleDetail.vue index 4d95aa7..14f9e93 100644 --- a/apps/web/src/components/organisms/CollectibleDetail.vue +++ b/apps/web/src/components/organisms/CollectibleDetail.vue @@ -8,6 +8,8 @@ defineProps({ title: { type: String, required: true }, status: { type: String, default: '' }, priceMinor: { type: Number, default: null }, + marketValueMinor: { type: Number, default: null }, + marketValueCurrency: { type: String, default: 'USD' }, condition: { type: String, default: '' }, description: { type: String, default: '' }, facts: { type: Array, default: () => [] }, @@ -27,6 +29,7 @@ defineProps({

{{ description }}

+
diff --git a/apps/web/src/pages/ListingDetailPage.vue b/apps/web/src/pages/ListingDetailPage.vue index 06ccb59..583236f 100644 --- a/apps/web/src/pages/ListingDetailPage.vue +++ b/apps/web/src/pages/ListingDetailPage.vue @@ -31,7 +31,9 @@ onMounted(async () => { :title="listing.productName" :status="listing.status" :price-minor="listing.askingPriceMinor" - :condition="listing.conditionId" + :market-value-minor="listing.marketValueMinor" + :market-value-currency="listing.marketValueCurrency" + :condition="listing.conditionName ? `${listing.conditionName} (${listing.conditionCode})` : listing.conditionId" :description="listing.notes" :images="listing.images" /> diff --git a/packages/contracts/public-listing.js b/packages/contracts/public-listing.js index 95cf22f..ba7ec9d 100644 --- a/packages/contracts/public-listing.js +++ b/packages/contracts/public-listing.js @@ -8,7 +8,11 @@ export function toPublicListingDto(listing) { productName: listing.productName, categoryId: listing.categoryId, conditionId: listing.conditionId, + conditionName: listing.conditionName ?? null, + conditionCode: listing.conditionCode ?? null, askingPriceMinor: listing.askingPriceMinor, + marketValueMinor: listing.marketValueMinor ?? null, + marketValueCurrency: listing.marketValueCurrency ?? null, status: listing.status, notes: listing.notes ?? null, images: listing.images ?? [],