full app is using live data now,
This commit is contained in:
@@ -1,6 +1,11 @@
|
||||
// app/gunbuilder/[categoryId]/[partId]/data.ts
|
||||
|
||||
// Simulated data functions - Replace these with API calls when ready
|
||||
// Example: export async function getPricingHistory(partId: string) { ... }
|
||||
|
||||
const API_BASE_URL =
|
||||
process.env.NEXT_PUBLIC_API_BASE_URL ?? "http://localhost:8080";
|
||||
|
||||
export interface PriceHistoryPoint {
|
||||
date: string; // ISO date string
|
||||
price: number;
|
||||
@@ -19,6 +24,8 @@ export interface RetailerOffer {
|
||||
/**
|
||||
* Get pricing history for a part
|
||||
* TODO: Replace with API call: GET /api/parts/{partId}/pricing-history
|
||||
*
|
||||
* For now, we keep this simulated.
|
||||
*/
|
||||
export function getPricingHistory(
|
||||
partId: string,
|
||||
@@ -48,40 +55,62 @@ export function getPricingHistory(
|
||||
|
||||
/**
|
||||
* Get retailer offers for a part
|
||||
* TODO: Replace with API call: GET /api/parts/{partId}/retailers
|
||||
* Real implementation using Ballistic backend:
|
||||
* GET /api/products/{productId}/offers
|
||||
*/
|
||||
export function getRetailerOffers(
|
||||
partId: string,
|
||||
basePrice: number,
|
||||
baseAffiliateUrl: string,
|
||||
): RetailerOffer[] {
|
||||
const retailers = [
|
||||
"Primary Arms",
|
||||
"Brownells",
|
||||
"Optics Planet",
|
||||
"MidwayUSA",
|
||||
"Palmetto State Armory",
|
||||
];
|
||||
export async function getRetailerOffers(
|
||||
productId: string,
|
||||
): Promise<RetailerOffer[]> {
|
||||
const res = await fetch(
|
||||
`${API_BASE_URL}/api/products/${productId}/offers`,
|
||||
{
|
||||
// This will be called from the client detail page,
|
||||
// so we *don't* use cache here.
|
||||
cache: "no-store",
|
||||
},
|
||||
);
|
||||
|
||||
return retailers.map((retailer, index) => {
|
||||
// Simulate price variations between retailers
|
||||
const priceVariation = (Math.random() - 0.4) * 0.2; // -8% to +12%
|
||||
const price = basePrice * (1 + priceVariation);
|
||||
const hasSale = Math.random() > 0.6; // 40% chance of sale
|
||||
const originalPrice = hasSale ? price * 1.15 : undefined;
|
||||
const inStock = Math.random() > 0.2; // 80% chance in stock
|
||||
if (!res.ok) {
|
||||
throw new Error(
|
||||
`Failed to load retailer offers (${res.status}) for product ${productId}`,
|
||||
);
|
||||
}
|
||||
|
||||
return {
|
||||
id: `retailer-${index}`,
|
||||
retailerName: retailer,
|
||||
price: Math.round(price * 100) / 100,
|
||||
originalPrice: originalPrice
|
||||
? Math.round(originalPrice * 100) / 100
|
||||
: undefined,
|
||||
inStock,
|
||||
affiliateUrl: baseAffiliateUrl.replace("example.com", `${retailer.toLowerCase().replace(/\s+/g, "")}.com`),
|
||||
lastUpdated: new Date().toISOString(),
|
||||
};
|
||||
}).sort((a, b) => a.price - b.price); // Sort by price ascending
|
||||
}
|
||||
// Expected backend payload (example):
|
||||
// [
|
||||
// {
|
||||
// "id": "uuid-or-int",
|
||||
// "merchantName": "Aero Precision",
|
||||
// "price": 189.99,
|
||||
// "originalPrice": 210.0,
|
||||
// "inStock": true,
|
||||
// "buyUrl": "https://classic.avantlink.com/click.php?...",
|
||||
// "lastUpdated": "2025-11-30T15:22:00Z"
|
||||
// },
|
||||
// ...
|
||||
// ]
|
||||
const data: Array<{
|
||||
id: string | number;
|
||||
merchantName: string;
|
||||
price: number;
|
||||
originalPrice?: number | null;
|
||||
inStock: boolean;
|
||||
buyUrl: string;
|
||||
lastUpdated: string;
|
||||
}> = await res.json();
|
||||
|
||||
const offers: RetailerOffer[] = data
|
||||
.map((o) => ({
|
||||
id: String(o.id),
|
||||
retailerName: o.merchantName,
|
||||
price: o.price,
|
||||
originalPrice: o.originalPrice ?? undefined,
|
||||
inStock: o.inStock,
|
||||
affiliateUrl: o.buyUrl,
|
||||
lastUpdated: o.lastUpdated,
|
||||
}))
|
||||
// Sort by lowest price first
|
||||
.sort((a, b) => a.price - b.price);
|
||||
|
||||
return offers;
|
||||
}
|
||||
Reference in New Issue
Block a user