/* listgetbuy — Buyer scroll story (scroll-position driven, hız bağımsız) */ const { useState, useEffect, useRef } = React; const clamp = (v, a = 0, b = 1) => Math.max(a, Math.min(b, v)); const lerp = (a, b, t) => a + (b - a) * t; const easeIO = (t) => (t < 0.5 ? 2 * t * t : 1 - Math.pow(-2 * t + 2, 2) / 2); const TL = (n) => '€' + Math.round(n).toLocaleString('de-DE'); const BUDGET = 950; const LOW = 790; const TH = [0.04, 0.30, 0.58, 0.86]; // offer i appears at this t within offer band const B = { introEnd: 0.12, offEnd: 0.50, dealEnd: 0.66, payEnd: 0.84 }; const STEPS_LANG = { tr: [ { k: '01', t: 'İlanını aç, bütçeni koy', s: 'Aramak yok. Ne istediğini yaz, satıcılar sana gelsin.' }, { k: '02', t: 'Teklifler düşerek gelir', s: 'Satıcılar teklifleriyle yarışır. Sen izlersin, fiyat düşer.' }, { k: '03', t: 'Süre dolar, en ucuz kazanır', s: 'Pazarlık yok, kovalamaca yok. En düşük teklif anlaşmayı alır.' }, { k: '04', t: 'Tek dokunuşla güvenli öde', s: 'Anlaş, öde, bitir. Para satıcıya teslimde geçer.' }, { k: '05', t: 'Bütçenin altında aldın', s: 'İşte eksiltme: zahmetsiz, ucuza. Aradaki fark cebinde kalır.' }, ], en: [ { k: '01', t: 'Open your listing, set budget', s: 'No searching. Just write what you need, let sellers come to you.' }, { k: '02', t: 'Offers come dropping down', s: 'Each new seller underbids the previous one. Watch the price drop.' }, { k: '03', t: 'Time expires, cheapest wins', s: 'No bargaining, no chasing. The lowest offer secures the deal.' }, { k: '04', t: 'One-tap secure payment', s: 'Agree, pay, finish. Funds are transferred to the seller upon delivery.' }, { k: '05', t: 'You bought below budget', s: 'That\'s the reverse auction: effortless, cheap. The difference stays in your pocket.' }, ], de: [ { k: '01', t: 'Inserat erstellen, Budget festlegen', s: 'Kein Suchen. Schreibe, was du brauchst, lass Verkäufer zu dir kommen.' }, { k: '02', t: 'Angebote sinken automatisch', s: 'Jeder neue Verkäufer unterbietet den vorherigen. Sieh zu, wie der Preis fällt.' }, { k: '03', t: 'Zeit läuft ab, der Günstigste gewinnt', s: 'Kein Feilschen, kein Hinterherjagen. Das niedrigste Angebot erhält den Zuschlag.' }, { k: '04', t: 'Sichere Zahlung per Klick', s: 'Einigen, bezahlen, fertig. Das Geld geht erst bei Lieferung an den Verkäufer.' }, { k: '05', t: 'Unter dem Budget gekauft', s: 'Das ist die Rückwärtsauktion: mühelos, günstig. Die Differenz bleibt in deiner Tasche.' }, ], }; const L_LABELS = { tr: { budget: 'Bütçe', timeUp: 'Süre doldu', paidUp: 'ÖDENEN', lowestOffer: 'EN DÜŞÜK TEKLİF', initialBudget: 'BAŞLANGIÇ BÜTÇESİ', dropped: 'düştü', willBeat: 'Satıcılar bunu kırmaya çalışacak', livePending: 'İlanın yayında. Teklifler düşmeye başlamak üzere…', shop: 'MAĞAZA', lowest: 'EN DÜŞÜK', outbid: 'GEÇİLDİ', dealSecured: 'Anlaşma sağlandı', lowestGiver: 'En düşük teklifi verdi', securePay: 'Güvenli ödeme', payDesc: 'Para, ürün eline geçince satıcıya aktarılır.', amount: 'Tutar', makePay: 'Ödemeyi yap', confirming: 'Onaylanıyor…', paid: 'ödendi', below: 'altında', city: 'İstanbul', notes: { elif: 'Faturalı, temiz cihaz', burak: 'Deep Purple, kutulu', mert: 'Pil %91, çiziksiz', tekno: 'Kutulu · faturalı · 8 ay garanti' } }, en: { budget: 'Budget', timeUp: 'Time expired', paidUp: 'PAID', lowestOffer: 'LOWEST OFFER', initialBudget: 'INITIAL BUDGET', dropped: 'dropped', willBeat: 'Sellers will try to beat this', livePending: 'Your listing is live. Offers are about to start dropping…', shop: 'STORE', lowest: 'LOWEST', outbid: 'OUTBID', dealSecured: 'Deal secured', lowestGiver: 'Gave the lowest offer', securePay: 'Secure payment', payDesc: 'Funds are released to the seller upon delivery.', amount: 'Amount', makePay: 'Make payment', confirming: 'Confirming…', paid: 'paid', below: 'below', city: 'Istanbul', notes: { elif: 'Invoice included, clean device', burak: 'Deep Purple, boxed', mert: 'Battery 91%, scratchless', tekno: 'Boxed · Invoice · 8mo warranty' } }, de: { budget: 'Budget', timeUp: 'Abgelaufen', paidUp: 'BEZAHLT', lowestOffer: 'NIEDRIGSTES ANGEBOT', initialBudget: 'STARTBUDGET', dropped: 'gesunken', willBeat: 'Verkäufer werden dies unterbieten', livePending: 'Ihr Inserat ist live. Angebote starten in Kürze…', shop: 'SHOP', lowest: 'BESTES', outbid: 'ÜBERBOTEN', dealSecured: 'Deal gesichert', lowestGiver: 'Hat das niedrigste Angebot abgegeben', securePay: 'Sichere Zahlung', payDesc: 'Geld wird erst bei Lieferung freigegeben.', amount: 'Betrag', makePay: 'Zahlung tätigen', confirming: 'Bestätigen…', paid: 'bezahlt', below: 'unter', city: 'Istanbul', notes: { elif: 'Mit Rechnung, sauberes Gerät', burak: 'Deep Purple, mit OVP', mert: 'Batterie 91%, kratzfrei', tekno: 'Mit OVP · Rechnung · 8 Monate Garantie' } } }; function Avatar({ o, size = 38 }) { const url = o.avatar || o.avatar_url; return (
{url ? : o.initials}
); } function OfferRow({ o, leader, beaten, reveal = 1, labels }) { return (
{o.name} {o.shop && {labels.shop}}
{o.note}
{TL(o.price)}
{leader ? (
{labels.lowest}
) : beaten ? (
{labels.outbid}
) : null}
); } function Stage({ p, lang = 'tr' }) { const labels = L_LABELS[lang] || L_LABELS.tr; const OFFERS = [ { initials: 'ED', hue: 285, name: 'Elif D.', note: labels.notes.elif, price: 890, avatar: 'https://images.unsplash.com/photo-1494790108377-be9c29b29330?auto=format&fit=crop&w=120&h=120&q=80' }, { initials: 'BT', hue: 25, name: 'Burak T.', note: labels.notes.burak, price: 850, avatar: 'https://images.unsplash.com/photo-1507003211169-0a1dd7228f2d?auto=format&fit=crop&w=120&h=120&q=80' }, { initials: 'MK', hue: 158, name: 'Mert K.', note: labels.notes.mert, price: 820, avatar: 'https://images.unsplash.com/photo-1500648767791-00dcc994a43e?auto=format&fit=crop&w=120&h=120&q=80' }, { initials: 'TC', hue: 200, name: 'TeknoCenter', note: labels.notes.tekno, price: 790, shop: true, avatar: 'https://images.unsplash.com/photo-1535713875002-d1d0cf377fde?auto=format&fit=crop&w=120&h=120&q=80' }, ]; const started = p > 0.015; const tBand = clamp((p - B.introEnd) / (B.offEnd - B.introEnd)); const dealLocked = p >= B.offEnd; const paying = p >= B.dealEnd; const paid = p >= B.payEnd; const bigPrice = p < B.introEnd ? BUDGET : lerp(BUDGET, LOW, easeIO(tBand)); const showLow = p >= B.introEnd; const remain = clamp(1 - tBand); const totalMin = Math.round(remain * 154); // ~2h34m const hh = String(Math.floor(totalMin / 60)).padStart(2, '0'); const mm = String(totalMin % 60).padStart(2, '0'); const revealed = OFFERS.map((o, i) => ({ o, i, rev: p < B.introEnd ? 0 : clamp((tBand - TH[i]) / 0.07) })) .filter((x) => x.rev > 0.02); const shown = revealed.length; const ordered = [...revealed].sort((a, b) => a.o.price - b.o.price); // cheapest first const ovOp = clamp((p - (B.offEnd - 0.02)) / 0.04); const payProg = clamp((p - B.dealEnd) / (B.payEnd - B.dealEnd)); return (
{/* listing header */}
iPhone 14 Pro · 256GB
{labels.budget} {TL(BUDGET)} · {labels.city}
{dealLocked ? labels.timeUp : `${hh}:${mm}`}
{/* big descending price */}
{paid ? labels.paidUp : showLow ? labels.lowestOffer : labels.initialBudget}
{TL(Math.round((paid ? LOW : bigPrice) / 50) * 50)}
{showLow && !paid && (
↓ {TL(BUDGET - bigPrice)} {labels.dropped}
)} {!showLow && (
{labels.willBeat}
)}
{/* offers */}
{shown === 0 && (
{labels.livePending}
)} {ordered.map(({ o, rev }, idx) => ( ))}
{/* deal / payment / paid overlay */} {p >= B.offEnd - 0.02 && (
{/* deal sheet (anlaşma + ödeme) */} {!paid && (
{!paying ? (
{labels.dealSecured}
TeknoCenter 4.9★
{labels.lowestGiver}
{TL(LOW)}
) : (
{labels.securePay}
{labels.payDesc}
{labels.amount} {TL(LOW)}
{payProg > 0.92 ? labels.confirming : labels.makePay}
)}
)} {/* paid success */} {paid && (
{TL(LOW)} {labels.paid}
iPhone 14 Pro · TeknoCenter
{labels.budget} {TL(BUDGET - LOW)} {labels.below} 🎉
)}
)}
); } function BuyerStory({ lang = 'tr' }) { const ref = useRef(null); const [p, setP] = useState(0); useEffect(() => { let raf = 0; const update = () => { raf = 0; const el = ref.current; if (!el) return; const rect = el.getBoundingClientRect(); const total = rect.height - window.innerHeight; setP(clamp(-rect.top / total)); }; const onScroll = () => { if (!raf) raf = requestAnimationFrame(update); }; update(); window.addEventListener('scroll', onScroll, { passive: true }); window.addEventListener('resize', onScroll); return () => { window.removeEventListener('scroll', onScroll); window.removeEventListener('resize', onScroll); cancelAnimationFrame(raf); }; }, []); const STEPS = STEPS_LANG[lang] || STEPS_LANG.tr; const ai = p < B.introEnd ? 0 : p < B.offEnd ? 1 : p < B.dealEnd ? 2 : p < B.payEnd ? 3 : 4; const step = STEPS[ai]; return (
{/* narrative column */}
{/* step rail */}
{STEPS.map((s, i) => (
{s.k} {s.t}
))}

{step.t}

{step.s}

{/* pinned stage */}
); } window.BuyerStory = BuyerStory; window.Stage = Stage; window.__lgb = { TL, BUDGET, LOW, Avatar }; window.GREEN_THEME = { '--ink': '#ffffff', '--ink-2': 'rgba(255,255,255,0.84)', '--muted': 'rgba(255,255,255,0.55)', '--green-ink': 'oklch(0.90 0.11 158)', '--green': 'oklch(0.85 0.13 158)', '--green-soft': 'rgba(255,255,255,0.14)', '--line2': 'rgba(255,255,255,0.24)', '--line': 'rgba(255,255,255,0.16)', color: '#ffffff', }; window.BUYER_BG = 'radial-gradient(1100px 640px at 50% -8%, oklch(0.55 0.11 158), oklch(0.40 0.085 158) 64%)';