// extras3.jsx — Hakkında + 404 + skeleton + hover preview helpers
const { useState: _x3S, useEffect: _x3E } = React;
// ═══════════════════════════════════════════════════════════════
// 1) HAKKINDA — kim olduğumuzu, neden güvenli olduğumuzu anlatır
// ═══════════════════════════════════════════════════════════════
function AboutScreen({ L, lang, theme }) {
const stats = [
{ v: '6.4K+', l: lang === 'tr' ? 'Tamamlanan satış' : 'Completed sales' },
{ v: '%99.2', l: lang === 'tr' ? 'Memnuniyet' : 'Satisfaction' },
{ v: '4 dk', l: lang === 'tr' ? 'Ortalama yanıt' : 'Avg response' },
{ v: '2022', l: lang === 'tr' ? 'Kuruluş' : 'Founded' },
];
const principles = lang === 'tr' ? [
{ t: 'Emanet model', d: 'Ödemen biz devir tamamlanana kadar emanet hesapta bekler. Sorun çıkarsa iadesi 24 saatte yapılır.' },
{ t: 'Her hesap doğrulanır', d: '3 katmanlı kontrol — yaş, organik takipçi oranı, içerik geçmişi. Sahte metrikleri filtreleyen iç skorlama sistemimiz var.' },
{ t: 'Şifre & e-posta devri', d: 'Wizard ile adım adım yönlendiriyoruz. 2FA dahil tüm bağlı her şeyi sıfırdan kuruyorsun. Eski sahip geri dönemiyor.' },
{ t: 'Şeffaf komisyon', d: 'İlan başına %8 + KDV. Gizli ücret yok. Satıcı ve alıcı her ikisi de neye ödediğini görür.' },
] : [
{ t: 'Escrow model', d: 'Your payment is held in escrow until the transfer is complete. Refund within 24h on issues.' },
{ t: 'Every account verified', d: '3-layer check — age, organic follower ratio, content history. Internal scoring filters fake metrics.' },
{ t: 'Password & email handover', d: 'Step-by-step wizard. You set up everything from scratch including 2FA. The seller can never come back.' },
{ t: 'Transparent commission', d: '8% + VAT per listing. No hidden fees. Both buyer and seller see what they pay for.' },
];
return (
{/* HERO */}
{lang === 'tr' ? 'INSTASATIŞ HAKKINDA' : 'ABOUT INSTASATIŞ'}
{lang === 'tr'
? <>Instagram hesabı satışını dürüst yaparız.>
: <>We make Instagram sales honest .>}
{lang === 'tr'
? 'InstaSatış 2022\'de DM\'lerde dolaşan dolandırıcılığa son vermek için kuruldu. Her hesap insan eliyle doğrulanır, ödemen emanette bekler, devir bizim wizard\'ımızla yapılır. Karanlık piyasayı aydınlatıyoruz.'
: 'InstaSatış launched in 2022 to end DM-based scams. Every account is human-verified, your payment sits in escrow, the transfer happens via our wizard. Lighting up the dark market.'}
{stats.map((s, i) => (
))}
{/* PRENSIPLER */}
{lang === 'tr' ? 'NASIL ÇALIŞIYORUZ' : 'HOW WE OPERATE'}
{lang === 'tr' ? 'Dört prensip, sıfır tolerans' : 'Four principles, zero tolerance'}
{principles.map((p, i) => (
))}
{/* CTA */}
{lang === 'tr' ? 'BAŞLAMAYA HAZIR MISIN?' : 'READY TO START?'}
{lang === 'tr' ? 'Hesabını saatler içinde sat veya al.' : 'Buy or sell in hours.'}
);
}
// ═══════════════════════════════════════════════════════════════
// 2) 404 — eğlenceli, marka-uyumlu
// ═══════════════════════════════════════════════════════════════
function NotFoundScreen({ L, lang, theme }) {
return (
{/* Arkaplan grad */}
{/* Big 404 */}
404
{lang === 'tr' ? 'KAYIP HESAP' : 'LOST ACCOUNT'}
{lang === 'tr' ? 'Bu sayfa unfollowed.' : 'This page unfollowed.'}
{lang === 'tr'
? 'Aradığın sayfa kaldırılmış, taşınmış veya hiç var olmamış olabilir. Belki ilanı sahibi geri çekmiştir.'
: 'The page you\'re looking for moved, was removed, or never existed. Maybe the seller pulled the listing.'}
);
}
// ═══════════════════════════════════════════════════════════════
// 3) PASSWORD RESET — sifre-sifirla.html için
// 3-step: e-posta → kod → yeni şifre. Mock akış (backend hazır).
// ═══════════════════════════════════════════════════════════════
function PasswordResetScreen({ L, lang, theme }) {
const [step, setStep] = _x3S(1);
const [email, setEmail] = _x3S('');
const [code, setCode] = _x3S('');
const [newPw, setNewPw] = _x3S('');
const [newPw2, setNewPw2] = _x3S('');
const [busy, setBusy] = _x3S(false);
const [err, setErr] = _x3S('');
const submitEmail = async (e) => {
e.preventDefault();
if (!email.match(/^[^@]+@[^@]+\.[^@]+$/)) { setErr(lang === 'tr' ? 'Geçerli bir e-posta gir.' : 'Enter a valid email.'); return; }
setErr(''); setBusy(true);
try {
if (window.api?.auth?.requestReset) {
await window.api.auth.requestReset(email);
}
} catch (e) { /* silent — always show success to avoid email enumeration */ }
setBusy(false);
setStep(2);
};
const submitCode = (e) => {
e.preventDefault();
if (code.length !== 6) { setErr(lang === 'tr' ? '6 haneli kodu gir.' : 'Enter 6-digit code.'); return; }
setErr('');
setStep(3);
};
const submitNewPw = async (e) => {
e.preventDefault();
if (newPw.length < 8) { setErr(lang === 'tr' ? 'En az 8 karakter olmalı.' : 'Min 8 chars.'); return; }
if (newPw !== newPw2) { setErr(lang === 'tr' ? 'Şifreler eşleşmiyor.' : 'Passwords do not match.'); return; }
setErr(''); setBusy(true);
try {
if (window.api?.auth?.resetPassword) {
await window.api.auth.resetPassword(email, code, newPw);
}
} catch (e) { setErr(e.message || 'Hata'); setBusy(false); return; }
setBusy(false);
setStep(4);
};
const Card = ({ children }) => (
{children}
);
return (
{/* Step indicator */}
{[1, 2, 3].map(s => (
= s ? 'var(--grad)' : 'var(--line-2)',
transition: 'background .3s',
}}/>
))}
{step === 1 && (
)}
{step === 2 && (
)}
{step === 3 && (
)}
{step === 4 && (
)}
);
}
// ═══════════════════════════════════════════════════════════════
// 4) SELLER VERIFICATION WIZARD — satici-dogrulama.html için
// 4 adımlı: kimlik + Instagram giriş kanıtı + iletişim + onay
// ═══════════════════════════════════════════════════════════════
function SellerVerifyWizard({ L, lang, theme }) {
const [step, setStep] = _x3S(1);
const [data, setData] = _x3S({
fullName: '', tckn: '', phone: '',
idFrontFile: null, idBackFile: null,
igHandle: '', igProofFile: null,
address: '', iban: '',
accept: false,
});
const [submitted, setSubmitted] = _x3S(false);
const set = (k, v) => setData(d => ({ ...d, [k]: v }));
const steps = [
{ n: 1, label: lang === 'tr' ? 'Kimlik' : 'Identity' },
{ n: 2, label: lang === 'tr' ? 'Hesap kanıtı' : 'Account proof' },
{ n: 3, label: lang === 'tr' ? 'İletişim' : 'Contact' },
{ n: 4, label: lang === 'tr' ? 'Gönder' : 'Submit' },
];
const canNext = () => {
if (step === 1) return data.fullName.length >= 4 && data.tckn.length === 11 && data.idFrontFile && data.idBackFile;
if (step === 2) return data.igHandle.length >= 2 && data.igProofFile;
if (step === 3) return data.phone.length >= 10 && data.address.length >= 10 && data.iban.length >= 16;
return data.accept;
};
const submit = async () => {
try {
if (window.api?.seller?.requestVerification) {
// Backend FormData bekliyor (dosya yüklemesi var)
const fd = new FormData();
fd.append('fullName', data.fullName);
fd.append('tckn', data.tckn);
fd.append('phone', data.phone);
fd.append('igHandle', data.igHandle);
fd.append('address', data.address);
fd.append('iban', data.iban);
if (data.idFrontFile) fd.append('idFrontFile', data.idFrontFile);
if (data.idBackFile) fd.append('idBackFile', data.idBackFile);
if (data.igProofFile) fd.append('igProofFile', data.igProofFile);
await window.api.seller.requestVerification(fd);
}
} catch (e) { /* fallback to local */ }
saveJson('is:seller_verify', {
// dosyaları localStorage'a JSON olarak kaydedemeyiz — sadece metadata sakla
fullName: data.fullName, tckn: data.tckn, phone: data.phone,
igHandle: data.igHandle, address: data.address, iban: data.iban,
hasIdFront: !!data.idFrontFile, hasIdBack: !!data.idBackFile, hasIgProof: !!data.igProofFile,
status: 'pending', submittedAt: Date.now(),
});
setSubmitted(true);
};
const FileInput = ({ label, value, onChange, accept = 'image/*,application/pdf' }) => (
{label}
{value ? value.name : (lang === 'tr' ? 'PDF veya görsel · max 8MB' : 'PDF or image · max 8MB')}
onChange(e.target.files[0] || null)} style={{ display: 'none' }}/>
);
if (submitted) {
return (
{lang === 'tr' ? 'Başvurun bize ulaştı' : 'We received your request'}
{lang === 'tr'
? '24 saat içinde ekibimiz belgelerini inceleyip e-posta ile dönüş yapacak. Onaylandıktan sonra ilan ver butonuyla hesabını listeleyebilirsin.'
: 'Our team will review your documents within 24 hours and reply via email. Once approved, you can list your account.'}
{lang === 'tr' ? 'BAŞVURU NUMARASI' : 'REFERENCE'}
#SV-{Date.now().toString(36).toUpperCase().slice(-8)}
{lang === 'tr' ? 'Panele dön' : 'Back to panel'}
);
}
return (
{/* Header */}
{lang === 'tr' ? 'SATICI DOĞRULAMA' : 'SELLER VERIFICATION'}
{lang === 'tr' ? 'Satışa hazırlık' : 'Get verified to sell'}
{lang === 'tr'
? 'KVKK ve MASAK uyumu için kimlik + hesap sahipliği kanıtı istiyoruz. Tüm belgeler şifrelenir, sadece doğrulama ekibi görür.'
: 'For KYC compliance, we need your ID + proof of account ownership. All documents are encrypted; only the verification team sees them.'}
{/* Steps */}
{steps.map((s) => (
= s.n ? 'var(--grad)' : 'var(--line-2)',
transition: 'background .3s',
}}/>
= s.n ? 'var(--ink)' : 'var(--ink-3)',
fontFamily: 'var(--font-mono)',
textTransform: 'uppercase', letterSpacing: '.06em',
}}>{s.n}. {s.label}
))}
{step === 1 && (
)}
{step === 2 && (
)}
{step === 3 && (
)}
{step === 4 && (
{lang === 'tr' ? 'Özet & onay' : 'Review & submit'}
{[
[lang === 'tr' ? 'Ad Soyad' : 'Name', data.fullName],
['TCKN', data.tckn ? data.tckn.slice(0, 3) + '••••••' + data.tckn.slice(-2) : '—'],
[lang === 'tr' ? 'Instagram' : 'Instagram', data.igHandle],
['IBAN', data.iban ? data.iban.slice(0, 6) + '••••' + data.iban.slice(-4) : '—'],
[lang === 'tr' ? 'Belgeler' : 'Documents', `${[data.idFrontFile, data.idBackFile, data.igProofFile].filter(Boolean).length} / 3`],
].map(([k, v]) => (
{k}
{v || '—'}
))}
set('accept', e.target.checked)}
style={{ marginTop: 2, accentColor: 'var(--accent)', width: 16, height: 16 }}/>
{lang === 'tr'
? <>Beyan ettiğim tüm bilgilerin doğru olduğunu, KVKK kapsamında verilerimin işlenmesine onay verdiğimi kabul ediyorum.>
: 'I confirm all information is accurate and consent to data processing under GDPR/KVKK.'}
)}
{/* Nav */}
setStep(s => Math.max(1, s - 1))}
disabled={step === 1}
style={{ background: 'none', border: 0, color: 'var(--ink-3)', fontSize: 13, cursor: step === 1 ? 'default' : 'pointer', opacity: step === 1 ? 0.4 : 1 }}>
← {lang === 'tr' ? 'Geri' : 'Back'}
{step < 4 ? (
canNext() && setStep(s => s + 1)} disabled={!canNext()}
className="is-btn is-btn-primary" style={{ opacity: canNext() ? 1 : 0.5 }}>
{lang === 'tr' ? 'Devam' : 'Continue'}
) : (
{lang === 'tr' ? 'Başvuruyu gönder' : 'Submit'}
)}
{/* Trust strip */}
{[
{ i: 'shield', t: lang === 'tr' ? 'Şifrelenir' : 'Encrypted' },
{ i: 'lock', t: lang === 'tr' ? 'KVKK uyumlu' : 'GDPR compliant' },
{ i: 'check', t: lang === 'tr' ? '24 saatte yanıt' : '24h response' },
].map((b, i) => (
{b.t}
))}
);
}
// ═══════════════════════════════════════════════════════════════
// 5) SECURITY PANEL — Dashboard'da "Güvenlik" sekmesinde
// 2FA aç/kapa + recovery codes + şifre değiştir
// ═══════════════════════════════════════════════════════════════
function SecurityPanel({ L, lang }) {
// Backend'den çekilen kullanıcı (totp_enabled var mı?)
const [me, setMe] = _x3S(null);
const [loading, setLoading] = _x3S(true);
// 2FA aktivasyon wizard state
const [stage, setStage] = _x3S('idle'); // idle | qr | verify | done | disable
const [setupData, setSetupData] = _x3S(null); // { secret, qrUrl }
const [code, setCode] = _x3S('');
const [recovery, setRecovery] = _x3S([]);
const [pwConfirm, setPwConfirm] = _x3S('');
const [busy, setBusy] = _x3S(false);
const [err, setErr] = _x3S('');
_x3E(() => {
(async () => {
try {
if (window.api?.auth?.me) {
const u = await window.api.auth.me();
setMe(u || {});
} else {
// Demo modu
setMe({ email: 'demo@instasatis.com', totp_enabled: 0 });
}
} catch (e) { setMe({}); }
setLoading(false);
})();
}, []);
const startEnable = async () => {
setErr(''); setBusy(true);
try {
const res = await window.api.auth.enable2FA();
setSetupData(res);
setStage('qr');
} catch (e) { setErr(e.message || 'Hata oluştu'); }
setBusy(false);
};
const verifyEnable = async () => {
if (code.length !== 6) { setErr('6 haneli kodu gir'); return; }
setErr(''); setBusy(true);
try {
const res = await window.api.auth.enable2FA(code);
setRecovery(res.recoveryCodes || []);
setStage('done');
// Kullanıcı state'i güncelle
setMe(m => ({ ...m, totp_enabled: 1 }));
setCode('');
} catch (e) { setErr(e.message || 'Kod hatalı'); }
setBusy(false);
};
const doDisable = async () => {
if (!pwConfirm) { setErr('Şifreni gir'); return; }
setErr(''); setBusy(true);
try {
await window.api.auth.disable2FA(pwConfirm);
setMe(m => ({ ...m, totp_enabled: 0 }));
setStage('idle');
setPwConfirm('');
} catch (e) { setErr(e.message || 'Şifre hatalı'); }
setBusy(false);
};
if (loading) {
return (
{lang === 'tr' ? 'Yükleniyor…' : 'Loading…'}
);
}
const enabled = !!me?.totp_enabled;
return (
{/* ─── 2FA card ─── */}
{lang === 'tr' ? 'İki adımlı doğrulama (2FA)' : 'Two-factor authentication'}
{enabled ? (
{lang === 'tr' ? 'Aktif' : 'Enabled'}
) : (
{lang === 'tr' ? 'Kapalı' : 'Disabled'}
)}
{lang === 'tr'
? 'Hesabını ekstra güvenlik katmanıyla koru. Her giriş Google Authenticator, Authy veya 1Password’den 6 haneli kod isteyecek.'
: 'Add an extra layer. Every sign-in will require a 6-digit code from Google Authenticator, Authy or 1Password.'}
{/* IDLE */}
{stage === 'idle' && (
{!enabled ? (
{busy ? '…' : (lang === 'tr' ? '2FA’yı aktif et' : 'Enable 2FA')}
) : (
setStage('disable')} className="is-btn is-btn-outline" style={{ color: '#dc2626', borderColor: 'rgba(220,38,38,0.3)' }}>
{lang === 'tr' ? '2FA’yı kapat' : 'Disable 2FA'}
)}
)}
{/* QR scan */}
{stage === 'qr' && setupData && (
{lang === 'tr' ? '1. Authenticator uygulamandan QR’ı tara' : '1. Scan QR with your authenticator app'}
{lang === 'tr' ? 'Manuel giriş kodu' : 'Manual entry'}
{setupData.secret}
{lang === 'tr' ? 'QR taramayı yapamazsan bu kodu manuel ekle.' : 'If you can\'t scan, enter this code manually.'}
setStage('verify')} className="is-btn is-btn-primary" style={{ marginTop: 16 }}>
{lang === 'tr' ? 'Devam' : 'Continue'}
)}
{/* VERIFY code */}
{stage === 'verify' && (
{lang === 'tr' ? '2. Uygulamada gözüken 6 haneli kodu gir' : '2. Enter the 6-digit code from your app'}
setCode(e.target.value.replace(/\D/g, '').slice(0, 6))}
inputMode="numeric"
autoFocus
className="is-input"
style={{
fontSize: 26, textAlign: 'center', letterSpacing: '0.4em',
fontFamily: 'var(--font-mono)', fontWeight: 600, padding: 16,
}}
placeholder="000000"
maxLength={6}
/>
{err &&
{err}
}
setStage('qr')} className="is-btn is-btn-outline">
← {lang === 'tr' ? 'QR\'a geri dön' : 'Back to QR'}
{busy ? '…' : (lang === 'tr' ? 'Doğrula ve aktif et' : 'Verify & enable')}
)}
{/* DONE — recovery codes */}
{stage === 'done' && recovery.length > 0 && (
{lang === 'tr' ? '2FA aktif edildi' : '2FA enabled'}
{lang === 'tr'
? 'Bu kurtarma kodlarını güvenli bir yerde sakla. Her kod tek kullanımlık. Telefonunu kaybedersen giriş için lazım olacak.'
: 'Save these recovery codes somewhere safe. Each is single-use; needed if you lose your phone.'}
{recovery.map((c, i) => (
{c}
))}
{
navigator.clipboard?.writeText(recovery.join('\n'));
}}
className="is-btn is-btn-outline"
>
{lang === 'tr' ? 'Kopyala' : 'Copy'}
{ setStage('idle'); setRecovery([]); }} className="is-btn is-btn-primary" style={{ flex: 1, justifyContent: 'center' }}>
{lang === 'tr' ? 'Sakladım, devam et' : 'I saved them, continue'}
)}
{/* DISABLE confirm */}
{stage === 'disable' && (
{lang === 'tr' ? '2FA’yı kapat' : 'Disable 2FA'}
{lang === 'tr' ? 'Onaylamak için şifreni gir.' : 'Enter your password to confirm.'}
setPwConfirm(e.target.value)}
className="is-input"
placeholder={lang === 'tr' ? 'Şifren' : 'Your password'}
/>
{err &&
{err}
}
{ setStage('idle'); setPwConfirm(''); setErr(''); }} className="is-btn is-btn-outline">
{lang === 'tr' ? 'Vazgeç' : 'Cancel'}
{busy ? '…' : (lang === 'tr' ? '2FA’yı kapat' : 'Disable')}
)}
{err && stage === 'idle' &&
{err}
}
{/* ─── Password change card ─── */}
{/* ─── Sessions / activity placeholder ─── */}
{lang === 'tr' ? 'Son aktiviteler' : 'Recent activity'}
{[
{ t: lang === 'tr' ? 'Bu cihazdan giriş' : 'Sign-in from this device', d: lang === 'tr' ? 'Şimdi · İstanbul' : 'Just now · Istanbul', mono: 'Chrome 134 · macOS' },
{ t: lang === 'tr' ? 'Önceki giriş' : 'Previous sign-in', d: lang === 'tr' ? '2 gün önce · İstanbul' : '2 days ago · Istanbul', mono: 'Safari · iOS 18' },
].map((s, i) => (
))}
);
}
Object.assign(window, { AboutScreen, NotFoundScreen, PasswordResetScreen, SellerVerifyWizard, SecurityPanel });