// screens.jsx — the 4 main screens: Home, Detail, Auth, Dashboard const { useState: _uS, useEffect: _uE, useMemo: _uM, useRef: _uR } = React; // ───────────────────────────────────────────────────────────── // HOME — hero + filter + grid of listings // ───────────────────────────────────────────────────────────── function HomeScreen({ L, lang, setLang, theme, layout, filters, setFilters, favs, setFavs, onView, onAuth, sort, setSort, onLayout }) { const filtered = _uM(() => { let out = LISTINGS.slice(); if (filters.age && filters.age !== 'any') { const min = +filters.age * 12; out = out.filter(l => l.age >= min); } if (filters.niche) out = out.filter(l => l.niche === filters.niche); if (filters.followers === '10k') out = out.filter(l => l.followers < 10000); else if (filters.followers === '100k') out = out.filter(l => l.followers >= 10000 && l.followers < 100000); else if (filters.followers === '1m') out = out.filter(l => l.followers >= 100000); if (filters.priceMax) out = out.filter(l => l.price <= filters.priceMax); if (sort === 'price_low') out.sort((a,b) => a.price - b.price); else if (sort === 'price_high') out.sort((a,b) => b.price - a.price); else if (sort === 'followers') out.sort((a,b) => b.followers - a.followers); else if (sort === 'age') out.sort((a,b) => b.age - a.age); return out; }, [filters, sort]); const toggleFav = (id) => setFavs(f => f.includes(id) ? f.filter(x => x !== id) : [...f, id]); return (
{/* HERO — animated gradient + floating post mosaic */}
{L.hero_kicker}

{L.hero_title.split(',')[0]},
{L.hero_title.split(',')[1]?.trim()}

{L.hero_sub}

{/* Social proof: rating + sales */}
{[0,1,2,3,4].map(i => )}
4.9 · 312 yorum
1.847 hesap teslim edildi
{/* Right: floating listing previews */}
{/* Stats strip */}
{[ { n: '2.847', l: L.stat_listings }, { n: '14.2K', l: L.stat_sold }, { n: '99.6%', l: L.stat_uptime }, ].map((s, i) => (
{s.n}
{s.l}
))}
{/* Marketplace grid */}
{filtered.map((l, i) => (
))}
); } function FloatingPreview({ listing, L, lang, layout = 'grid', style }) { return (
{}} onView={() => {}}/>
); } // ───────────────────────────────────────────────────────────── // DETAIL screen // ───────────────────────────────────────────────────────────── function DetailScreen({ L, lang, setLang, theme, listing, onBack, onAuth, favs, setFavs }) { const l = listing || LISTINGS[0]; const isFav = favs.includes(l.id); const [contactOpen, setContactOpen] = _uS(false); const niche = L[`niche_${l.niche}`] || l.niche; const toggleFav = () => setFavs(f => f.includes(l.id) ? f.filter(x => x !== l.id) : [...f, l.id]); // SEO: Product JSON-LD + dynamic title/meta per listing React.useEffect(() => { if (typeof document === 'undefined') return; document.title = `${l.handle} — ${niche} · ${fmtNum(l.followers)} takipçi · InstaSatış`; let descTag = document.querySelector('meta[name="description"]'); if (!descTag) { descTag = document.createElement('meta'); descTag.setAttribute('name', 'description'); document.head.appendChild(descTag); } descTag.setAttribute('content', `${l.handle} — ${niche} kategorisinde ${fmtNum(l.followers)} takipçili Instagram hesabı. ${l.age} aylık, %${l.er} etkileşim. ${fmtPrice(l.price, lang)}.`); // Inject Product schema const oldLd = document.getElementById('__listing_jsonld'); if (oldLd) oldLd.remove(); const ld = document.createElement('script'); ld.id = '__listing_jsonld'; ld.type = 'application/ld+json'; ld.textContent = JSON.stringify({ "@context": "https://schema.org", "@type": "Product", "name": `${l.handle} — Instagram ${niche} hesabı`, "description": `${fmtNum(l.followers)} takipçili, ${l.age} aylık, ${niche} kategorisinde Instagram hesabı.`, "category": niche, "brand": { "@type": "Brand", "name": "InstaSatış" }, "offers": { "@type": "Offer", "price": l.price, "priceCurrency": "TRY", "availability": l.status === 'sold' ? "https://schema.org/SoldOut" : "https://schema.org/InStock", "url": `https://instasatis.com/ilan.html?id=${l.id}`, "seller": { "@type": "Organization", "name": "InstaSatış" } }, "aggregateRating": l.er >= 3 ? { "@type": "AggregateRating", "ratingValue": Math.min(5, 3 + l.er / 5).toFixed(1), "reviewCount": Math.floor(l.followers / 1000) } : undefined, }); document.head.appendChild(ld); return () => { const el = document.getElementById('__listing_jsonld'); if (el) el.remove(); }; }, [l.id, l.handle, l.followers, l.price, niche, lang]); return (
{L.nav_explore}
{/* LEFT — profile, posts, metrics */}
{/* Profile card */}

{l.handle}

{l.verified && }
{niche} · {l.country} · listed 2 days ago
{fmtNum(l.followers)} {L.card_followers} {fmtAge(l.age, lang, L)} {l.er.toFixed(1)}% ER
{/* Metrics — novel: radial chart + bars */}
{L.detail_metrics}
{/* Post samples */}
{L.detail_content}
12 of 428 posts
{Array.from({ length: 12 }).map((_, i) => (
))}
{/* Account age "rings" — novel visualization */}
Account timeline
{/* Reviews / yorumlar */}
{/* RIGHT — purchase card sticky */}
{contactOpen && typeof ContactModal !== 'undefined' && ( setContactOpen(false)}/> )}
); } function MetricRadial({ er }) { const pct = Math.min(er / 10, 1); const r = 56; const c = 2 * Math.PI * r; return (
{er.toFixed(1)}%
ENGAGEMENT
); } function MetricBar({ label, value, max, fmt }) { const pct = Math.min(value / max, 1); return (
{label} {fmt(value)}
); } function AgeTimeline({ months }) { const years = Math.ceil(months / 12); const now = new Date(); const start = new Date(now); start.setMonth(start.getMonth() - months); return (
{Array.from({ length: months }).map((_, i) => { const h = 20 + ((i * 37) % 20); return
; })}
{start.toLocaleDateString('tr-TR', { month: 'short', year: 'numeric' })} {years} year{years > 1 ? 's' : ''} active · {months} posts/month avg Today
); } // ───────────────────────────────────────────────────────────── // AUTH screen // ───────────────────────────────────────────────────────────── function AuthScreen({ L, lang, setLang, theme, mode = 'login', onMode, onBack }) { const [m, setM] = _uS(mode); const [name, setName] = _uS(''); const [email, setEmail] = _uS(''); const [pass, setPass] = _uS(''); const [phone, setPhone] = _uS(''); const [loading, setLoading] = _uS(false); const [error, setError] = _uS(''); // 2FA aşaması const [needs2FA, setNeeds2FA] = _uS(false); const [totpCode, setTotpCode] = _uS(''); _uE(() => setM(mode), [mode]); const handleSubmit = async (e) => { e?.preventDefault?.(); setError(''); if (!email || !pass) return setError(lang === 'tr' ? 'E-posta ve şifre gerekli' : 'Email and password required'); if (m === 'signup' && !name) return setError(lang === 'tr' ? 'İsim gerekli' : 'Name required'); if (m === 'signup' && pass.length < 8) return setError(lang === 'tr' ? 'Şifre en az 8 karakter' : 'Password min 8 chars'); if (needs2FA && totpCode.length !== 6) return setError(lang === 'tr' ? '6 haneli kodu gir' : 'Enter 6-digit code'); if (!window.api) { // API yüklü değil → demo modu (localStorage) localStorage.setItem('instasatis_user', JSON.stringify({ email, name: name || email.split('@')[0] })); window.location.href = 'panelim.html'; return; } setLoading(true); try { if (m === 'login') { const res = await window.api.auth.login(email, pass, needs2FA ? totpCode : undefined); // 2FA gerekiyorsa ikinci aşamaya geç if (res && res.needs2FA) { setNeeds2FA(true); setLoading(false); return; } } else { await window.api.auth.register(email, pass, name, phone); } window.location.href = 'panelim.html'; } catch (err) { setError(err.message || (lang === 'tr' ? 'Bir hata oluştu' : 'An error occurred')); } finally { setLoading(false); } }; return (
{/* LEFT — brand panel */}
instasatis.com
{L.hero_title.split(',')[0]},
{L.hero_title.split(',')[1]?.trim()}
{[L.trust_ssl, L.trust_escrow, L.trust_refund, L.trust_verified].map((t,i) => (
{t}
))}
{/* decorative post mosaic */}
{/* RIGHT — form */}
{L.nav_explore}
{L.auth_welcome}

{m === 'login' ? L.auth_login : L.auth_signup}

{L.auth_sub}

{/* Tabs */}
{['login','signup'].map(t => ( ))}
{needs2FA ? ( /* ── 2FA aşaması ── */ <>
İki adımlı doğrulama
Authenticator uygulamandan 6 haneli kodu gir
setTotpCode(e.target.value.replace(/\D/g, ''))} placeholder="000000" style={{ width: '100%', padding: '16px', fontSize: 24, textAlign: 'center', letterSpacing: '0.5em', fontFamily: 'var(--font-mono, ui-monospace, monospace)', fontWeight: 600, background: 'var(--card)', color: 'var(--ink)', border: '1.5px solid var(--line)', borderRadius: 12, outline: 'none', boxSizing: 'border-box', }} />
Telefonunu kaybettin mi? Kurtarma kodlarından birini gir.
) : ( /* ── Normal giriş/kayıt aşaması ── */ <> {m === 'signup' && ( )} {m === 'signup' && ( )} {m === 'login' && ( )} )} {error && (
{error}
)} {needs2FA ? ( ) : ( <>
{L.auth_or}

{L.auth_tos}

)}
); } function Field({ icon, placeholder, type = 'text', defaultValue, value, onChange }) { const isControlled = value !== undefined && onChange; return (
{isControlled ? ( onChange(e.target.value)} style={{ paddingLeft: 40 }}/> ) : ( )}
); } // ───────────────────────────────────────────────────────────── // DASHBOARD — buyer side // ───────────────────────────────────────────────────────────── function DashboardScreen({ L, lang, setLang, theme, favs, setFavs, onView, onAuth }) { const [tab, setTab] = _uS('fav'); const favItems = LISTINGS.filter(l => favs.includes(l.id)); return (
{/* Sidebar */} {/* Main */}

{tab === 'fav' ? L.dash_fav : tab === 'watch' ? L.dash_watch : tab === 'offers' ? L.dash_offers : tab === 'security' ? (lang === 'tr' ? 'Güvenlik' : 'Security') : L.dash_purchases}

{tab === 'fav' ? favs.length : tab === 'watch' ? 3 : tab === 'offers' ? 1 : 2} items
{tab === 'fav' && ( favItems.length === 0 ? (
{L.empty_fav}
) : (
{favItems.map(l => ( setFavs(f => f.filter(x => x !== id))} onView={onView}/> ))}
) )} {tab === 'offers' && (
)} {tab === 'watch' && (
{[LISTINGS[3], LISTINGS[6], LISTINGS[11]].map(l => ( setFavs(f => f.includes(id) ? f.filter(x => x !== id) : [...f, id])} onView={onView}/> ))}
)} {tab === 'purchases' && (
{[ { l: LISTINGS[2], date: '12 Nis 2026', status: 'delivered' }, { l: LISTINGS[5], date: '28 Mar 2026', status: 'delivered' }, ].map((p, i) => ( ))}
)} {tab === 'security' && }
); } function OfferRow({ L, lang, listing, status, amount }) { return (
{listing.handle}
{L[`niche_${listing.niche}`]} · {fmtNum(listing.followers)} {L.card_followers}
Teklifin
{fmtPrice(amount, lang)}
Bekliyor
); } function PurchaseRow({ L, lang, l, date, status, isFirst }) { return (
{l.handle}
{date} · Teslim edildi
{fmtPrice(l.price, lang)}
Teslim
); } // ───────────────────────────────────────────────────────────── // Satıcı kartı — listing aside'da gösterilen mini profil // ───────────────────────────────────────────────────────────── function SellerCard({ listing, lang, L }) { const l = listing; // Mock satıcı verisi (API olunca gerçek gelecek) const seller = { name: l.seller_name || (l.handle.replace('@','').split('.')[0].charAt(0).toUpperCase() + l.handle.replace('@','').split('.')[0].slice(1) + ' Y.'), handle: '@seller_' + l.handle.replace('@','').slice(0, 8), rating: 4.8, review_count: 23, listings_count: 7, response_time: lang === 'tr' ? '~2 saat' : '~2h', member_since: 2023, verified_seller: true, }; return (
{lang === 'tr' ? 'Satıcı' : 'Seller'}
{seller.name.charAt(0)}
{seller.name}
{seller.verified_seller && }
{lang === 'tr' ? 'Üye' : 'Member'} {seller.member_since}
{/* Rating */}
{seller.rating} ({seller.review_count} {lang === 'tr' ? 'yorum' : 'reviews'})
{/* İstatistikler */}
{lang === 'tr' ? 'Toplam İlan' : 'Listings'}
{seller.listings_count}
{lang === 'tr' ? 'Cevap Süresi' : 'Response'}
{seller.response_time}
{lang === 'tr' ? 'Tüm ilanlarını gör →' : 'View all listings →'}
); } // Yıldız puanlama function StarRating({ value, size = 16, interactive = false, onChange }) { const stars = [1, 2, 3, 4, 5]; return (
{stars.map(s => { const filled = value >= s; const half = !filled && value >= s - 0.5; return ( ); })}
); } // ───────────────────────────────────────────────────────────── // Yorumlar bölümü // ───────────────────────────────────────────────────────────── function ReviewsSection({ listing, lang, L }) { // Mock yorumlar (API'den gelecek) const reviews = [ { id: 1, name: 'Ahmet K.', initials: 'AK', rating: 5, date: '2 hafta önce', text: lang === 'tr' ? 'Süreç çok pürüzsüzdü, hesap aynen ilanda yazdığı gibiydi. Komisyon karşılığında bu güvenliği almak çok değerli.' : 'Smooth process, account exactly as listed. Worth the commission for the security.', verified_purchase: true }, { id: 2, name: 'Selin Ö.', initials: 'SÖ', rating: 5, date: '1 ay önce', text: lang === 'tr' ? 'Satıcı çok hızlı yanıt verdi ve devir 24 saat içinde tamamlandı. Tavsiye ederim.' : 'Seller responded quickly, transfer completed within 24 hours. Recommended.', verified_purchase: true }, { id: 3, name: 'Mert D.', initials: 'MD', rating: 4, date: '2 ay önce', text: lang === 'tr' ? 'Hesap iyi, takipçi sayısı doğru. Tek eksik birkaç eski post silinmesi gerekti.' : 'Good account, follower count accurate. Only minor: had to delete some old posts.', verified_purchase: true }, ]; const avg = reviews.reduce((s, r) => s + r.rating, 0) / reviews.length; const distribution = [5,4,3,2,1].map(n => ({ n, count: reviews.filter(r => r.rating === n).length, pct: (reviews.filter(r => r.rating === n).length / reviews.length) * 100, })); return (
{lang === 'tr' ? 'Yorumlar & Değerlendirmeler' : 'Reviews & Ratings'}
{reviews.length} {lang === 'tr' ? 'yorum' : 'reviews'}
{/* Özet */}
{avg.toFixed(1)}
{reviews.length} {lang === 'tr' ? 'değerlendirme' : 'ratings'}
{distribution.map(d => (
{d.n}
{d.count}
))}
{/* Yorum listesi */}
{reviews.map(r => (
{r.initials}
{r.name} {r.verified_purchase && ( {lang === 'tr' ? 'DOĞRULANMIŞ ALIM' : 'VERIFIED'} )} {r.date}

{r.text}

))}
); } Object.assign(window, { HomeScreen, DetailScreen, AuthScreen, DashboardScreen, SellerCard, StarRating, ReviewsSection });