|
| 1 | +interface ApiVariant { |
| 2 | + variantId: string; |
| 3 | + name: string; |
| 4 | + description?: string; |
| 5 | + imageUrl?: string; |
| 6 | + memberLists: string[]; |
| 7 | + inventoryCount?: number | null; |
| 8 | + exchangesAllowed: boolean; |
| 9 | + memberPriceCents: number; |
| 10 | + nonmemberPriceCents: number; |
| 11 | +} |
| 12 | + |
| 13 | +interface ApiProduct { |
| 14 | + productId: string; |
| 15 | + name: string; |
| 16 | + description?: string; |
| 17 | + imageUrl?: string; |
| 18 | + openAt?: number; |
| 19 | + closeAt?: number; |
| 20 | + limitConfiguration?: { |
| 21 | + limitType: "PER_PRODUCT" | "PER_VARIANT"; |
| 22 | + maxQuantity: number; |
| 23 | + }; |
| 24 | + verifiedIdentityRequired: boolean; |
| 25 | + inventoryMode: "PER_PRODUCT" | "PER_VARIANT"; |
| 26 | + totalInventoryCount?: number | null; |
| 27 | + variants: ApiVariant[]; |
| 28 | +} |
| 29 | + |
| 30 | +interface ApiResponse { |
| 31 | + products: ApiProduct[]; |
| 32 | +} |
| 33 | + |
| 34 | +interface LegacyItem { |
| 35 | + member_price: string; |
| 36 | + nonmember_price: string; |
| 37 | + item_image: string; |
| 38 | + sizes: string[]; |
| 39 | + item_price: { paid: number; others: number }; |
| 40 | + eventDetails: string; |
| 41 | + item_id: string; |
| 42 | + total_sold: Record<string, number>; |
| 43 | + total_avail: Record<string, number>; |
| 44 | + limit_per_person: number; |
| 45 | + item_sales_active_utc: number; |
| 46 | + item_name: string; |
| 47 | +} |
| 48 | + |
| 49 | +function formatPriceRange(prices: number[]): string { |
| 50 | + if (prices.length === 0) return ""; |
| 51 | + |
| 52 | + const uniquePrices = Array.from(new Set(prices)).sort((a, b) => a - b); |
| 53 | + const formatPrice = (cents: number) => `$${(cents / 100).toFixed(2)}`; |
| 54 | + |
| 55 | + if (uniquePrices.length === 1) { |
| 56 | + return formatPrice(uniquePrices[0] / 100); |
| 57 | + } |
| 58 | + |
| 59 | + return `${formatPrice(uniquePrices[0] / 100)} - ${formatPrice(uniquePrices[uniquePrices.length - 1] / 100)}`; |
| 60 | +} |
| 61 | + |
| 62 | +export function transformApiResponse(apiResponse: ApiResponse): LegacyItem[] { |
| 63 | + return apiResponse.products.map((product) => { |
| 64 | + const memberPrices = product.variants.map((v) => v.memberPriceCents); |
| 65 | + const nonmemberPrices = product.variants.map((v) => v.nonmemberPriceCents); |
| 66 | + |
| 67 | + // For item_price, use the minimum prices (or you could use average, etc.) |
| 68 | + const minMemberPrice = Math.min(...memberPrices); |
| 69 | + const minNonmemberPrice = Math.min(...nonmemberPrices); |
| 70 | + |
| 71 | + // Build total_avail from variant inventory |
| 72 | + const total_avail: Record<string, number> = {}; |
| 73 | + if (product.inventoryMode === "PER_VARIANT") { |
| 74 | + product.variants.forEach((variant) => { |
| 75 | + if (variant.inventoryCount != null) { |
| 76 | + total_avail[variant.variantId] = variant.inventoryCount; |
| 77 | + } |
| 78 | + }); |
| 79 | + } else if (product.totalInventoryCount != null) { |
| 80 | + // For PER_PRODUCT mode, could assign total to a generic key or distribute |
| 81 | + total_avail["total"] = product.totalInventoryCount; |
| 82 | + } |
| 83 | + |
| 84 | + return { |
| 85 | + item_id: product.productId, |
| 86 | + item_name: product.name, |
| 87 | + item_image: product.imageUrl ?? "", |
| 88 | + description: product.description, |
| 89 | + member_price: formatPriceRange(memberPrices), |
| 90 | + nonmember_price: formatPriceRange(nonmemberPrices), |
| 91 | + item_price: { |
| 92 | + paid: minMemberPrice / 100, |
| 93 | + others: minNonmemberPrice / 100, |
| 94 | + }, |
| 95 | + sizes: product.variants.map((v) => v.name), |
| 96 | + variants: product.variants.map(v => ({ |
| 97 | + id: v.variantId, |
| 98 | + name: v.name |
| 99 | + })), |
| 100 | + eventDetails: product.description ?? "", |
| 101 | + total_sold: {}, // API doesn't provide this; initialize empty |
| 102 | + total_avail, |
| 103 | + limit_per_person: product.limitConfiguration?.maxQuantity ?? -1, |
| 104 | + item_sales_active_utc: product.openAt ?? -1, |
| 105 | + }; |
| 106 | + }); |
| 107 | +} |
0 commit comments