// ============================================================ // COMPONENTS — shared UI bits // ============================================================ const { useState, useEffect, useRef, useMemo } = React; // ---------- Icons (inline SVG) ---------- const Icon = { search: , cart: , heart: , user: , arrow: , arrowL: , paw: , share: , filter: , }; // ---------- Top bar ---------- function TopBar({ active, onNav, cartCount }) { return (
{ e.preventDefault(); onNav('home'); }}> P Pootje
); } // ---------- Footer ---------- function Footer({ onNav }) { return ( ); } // ---------- Breed Card ---------- function BreedCard({ breed, onClick }) { return (
PHOTO · {breed.name.split(' ')[0].toUpperCase()}

{breed.name}

{breed.group} · {breed.size} · {breed.lifespan}

{breed.short}

{breed.tags.slice(0, 3).map((t, i) => {t})}
); } // ---------- Trait bars ---------- function TraitBars({ traits, max = 5 }) { const labels = { energie: 'Energie', vriendelijk: 'Vriendelijk', training: 'Trainbaarheid', verzorging: 'Verzorging', kindvriendelijk: 'Met kinderen', alleenZijn: 'Alleen kunnen zijn', blaffen: 'Blaffen', allergie: 'Hypoallergeen' }; return (
{Object.entries(labels).map(([k, label]) => { const v = traits[k] || 0; return (
{label}
{v}/{max}
); })}
); } // ---------- Cost chart ---------- function CostChart({ breed }) { const items = [ { label: 'Voer/mnd', val: parseInt(breed.care.voer.match(/\d+/)?.[0] || 50), max: 120, color: '' }, { label: 'Verzekering', val: 35, max: 120, color: '' }, { label: 'Dierenarts', val: 28, max: 120, color: '' }, { label: 'Trimmer', val: breed.traits.verzorging * 12, max: 120, color: 'alt' }, { label: 'Speelgoed', val: 12, max: 120, color: 'alt' }, { label: 'Verzekering+', val: 18, max: 120, color: 'alt' }, ]; const total = items.reduce((s, i) => s + i.val, 0); return (
{items.map((it, i) => (
€{it.val}
{it.label}
))}
Geschat per maand
€{total},–
Per jaar
€{total * 12},–
); } // ---------- Schedule chart ---------- function ScheduleChart({ breed }) { const days = ['Ma','Di','Wo','Do','Vr','Za','Zo']; const energie = breed.traits.energie || 3; // Build daily blocks based on energy const buildDay = (i) => { const blocks = []; blocks.push('b-walk'); // morning walk if (energie >= 3) blocks.push('b-train'); blocks.push('b-rest'); if (energie >= 4) blocks.push('b-walk'); blocks.push('b-play'); blocks.push('b-rest'); blocks.push('b-walk'); // evening walk if (i === 5 || i === 6) blocks.push('b-play'); // weekend extras return blocks; }; return (
{days.map((d, i) => (
{d}
{buildDay(i).map((b, j) => )}
))}
Wandelen Training Spelen Rust
); } // ---------- Product card ---------- function ProductCard({ product, inCart, onAdd }) { return (
{product.badge && {product.badge}} {product.tag}
{product.brand}
{product.name}
★★★★★ {product.rating} · {product.reviews} reviews
€{product.price.toFixed(2)} {product.old && €{product.old.toFixed(2)}}
); } // Export to window Object.assign(window, { Icon, TopBar, Footer, BreedCard, TraitBars, CostChart, ScheduleChart, ProductCard, });