"use client"; import Image from 'next/image'; import React from 'react'; import type { TcgCard } from '@/types/pokemon'; import SetBadge from './SetBadge'; import type { VariantKey, VariantState } from '@/lib/checklist'; import { useUsdGbpRate } from '@/lib/useExchangeRate'; import { dispatchReverseOverride, loadOverridesClient } from '@/lib/overrides'; export default function CardItem({ card, checked, onToggle }:{ card: TcgCard; checked: VariantState; onToggle: (id:string, key: VariantKey)=>void }) { const rate = useUsdGbpRate(); const [imageFailed, setImageFailed] = React.useState(false); const hasHolo = !!(card.variants?.holofoil || (card.tcgplayer as any)?.prices?.holofoil); const hasReverseDetected = !!(card.variants?.reverseHolofoil || (card.tcgplayer as any)?.prices?.reverseHolofoil); const [reverseOverride, setReverseOverride] = React.useState(false); const [reverseRemoved, setReverseRemoved] = React.useState(false); const hasReverse = (hasReverseDetected && !reverseRemoved) || reverseOverride; const prices = (card as any).tcgplayer?.prices || {}; const rarityFull = card.rarity || ''; const rarityAbbr = (() => { const r = rarityFull.toLowerCase(); // Specific token-based shortcuts first if (r.includes('vmax')) return 'VMAX'; if (r.includes('vstar')) return 'VSTAR'; if (r.includes('gx')) return 'GX'; if (r.includes('ex')) return 'EX'; if (r.includes('v ')) return 'V'; if (r === 'v') return 'V'; if (r.includes('secret')) return 'SR'; if (r.includes('ultra')) return 'UR'; if (r.includes('reverse')) return 'RH'; if (r.includes('holo')) return 'HR'; if (r.includes('promo')) return 'P'; // Specific before generic 'rare' if (r.includes('illustration') && r.includes('rare')) return 'IR'; if (r.includes('rare')) return 'R'; if (r.includes('uncommon')) return 'U'; if (r.includes('common')) return 'C'; // Fallback: first letter of first word uppercased return rarityFull ? rarityFull.charAt(0).toUpperCase() : ''; })(); // Initialize local override based on server overrides to show the − toggle on reloads React.useEffect(() => { let cancelled = false; (async () => { const map = await loadOverridesClient(); if (!cancelled && map && typeof map === 'object') { if (map[card.id]) { setReverseOverride(true); setReverseRemoved(false); } } })(); return () => { cancelled = true; }; }, [card.id]); const getPrice = (key: VariantKey): number | undefined => { const map: Record = { base: 'normal', holofoil: 'holofoil', reverseHolofoil: 'reverseHolofoil', }; const entry = prices[map[key]]; if (!entry) return undefined; const value = entry.market ?? entry.mid ?? entry.low ?? entry.high; return typeof value === 'number' ? value : undefined; }; const fmtGBP = (usd?: number) => { if (typeof usd !== 'number') return undefined; const gbp = usd * rate; try { return new Intl.NumberFormat('en-GB', { style: 'currency', currency: 'GBP', maximumFractionDigits: 2 }).format(gbp); } catch { return `£${gbp.toFixed(2)}`; } }; return (
setImageFailed(true)} alt={`${card.name} #${card.number}`} fill className="object-contain p-3" sizes="(max-width: 768px) 50vw, (max-width: 1200px) 25vw, 20vw" />
{(() => { const titleText = `${card.name} #${card.number}`; const len = titleText.length; const size = len > 34 ? 'text-xs' : len > 24 ? 'text-sm' : 'text-base'; return (

{card.name} #{card.number}

{/* Show + only if no detected reverse and no override; show − only if override currently active */} {(!hasReverseDetected && !reverseOverride) && ( )} {reverseOverride && ( )}
); })()} {rarityFull ? ( {rarityAbbr} ) : null}
{hasHolo && ( )} {hasReverse && ( )}
); }