import { useState } from 'react';
import type { ShopOffer } from '../data/mock';
import { trackClick, getPageSource } from '../lib/tracking';
interface Props {
offers: ShopOffer[];
lowestPrice: number;
selectedSize?: string | null;
productId?: string;
sneakerData?: {
item_id: string;
item_name: string;
item_brand: string;
price: number;
};
}
function SizeChips({ sizes }: { sizes: string[] }) {
const [open, setOpen] = useState(false);
const sorted = [...sizes].sort((a, b) => parseFloat(a) - parseFloat(b));
const maxShow = 10;
const hasMore = sorted.length > maxShow;
const visible = open ? sorted : sorted.slice(0, maxShow);
return (
{open && (
{visible.map((size) => (
{size}
))}
{hasMore && !open && (
en {sorted.length - maxShow} meer
)}
)}
);
}
export default function PriceComparisonTable({ offers, lowestPrice, selectedSize, productId, sneakerData }: Props) {
const filtered = selectedSize
? offers.filter((o) => o.sizes.includes(selectedSize))
: offers;
// When a size is selected, use the size-specific price and URL from sizeDetails
const withEffectivePricing = filtered.map((o) => {
if (!selectedSize) return o;
const detail = o.sizeDetails?.find((d) => d.size === selectedSize);
if (!detail) return o;
return {
...o,
price: detail.price,
url: detail.url ?? o.url,
};
});
const sorted = [...withEffectivePricing].sort((a, b) => a.price - b.price);
const handleOutboundClick = async (e: React.MouseEvent, offer: ShopOffer, position: number) => {
e.preventDefault();
// GA4 dataLayer events
if (sneakerData) {
window.dataLayer = window.dataLayer || [];
window.dataLayer.push({ ecommerce: null });
window.dataLayer.push({
event: 'select_promotion',
ecommerce: {
promotion_id: offer.shop,
promotion_name: offer.shop,
items: [sneakerData],
},
});
window.dataLayer.push({
event: 'outbound_click',
destination_url: offer.url,
shop_name: offer.shop,
});
}
// Track click server-side and get redirect URL with clickRef
const result = await trackClick({
product_id: productId || sneakerData?.item_id || '0',
shop_id: offer.shop,
url: offer.url,
source: getPageSource(),
source_detail: offer.shop,
position,
});
// Klaviyo affiliate_click event (clickRef comes from redirect URL)
const redirectUrl = result?.redirect_url || offer.url;
let clickRef = '';
try { clickRef = new URL(redirectUrl).searchParams.get('clickRef') || ''; } catch (_) {}
window.dataLayer = window.dataLayer || [];
window.dataLayer.push({
event: 'affiliate_click',
product_id: sneakerData?.item_id || productId || '',
product_name: sneakerData?.item_name || '',
brand: sneakerData?.item_brand || '',
shop: offer.shop,
price: offer.price,
click_ref: clickRef,
affiliate_url: redirectUrl,
});
// Redirect to affiliate URL (with clickRef appended)
window.open(redirectUrl, '_blank', 'noopener,noreferrer');
};
return (
Prijsvergelijking
{selectedSize && · Maat {selectedSize}}
{sorted.length === 0 ? (
Geen shops gevonden met maat {selectedSize}
) : (
{sorted.map((offer, i) => {
const isLowest = offer.price === Math.min(...sorted.map(o => o.price));
return (
);
})}
)}
);
}