// Referral — партнерская программа: ссылки-кампании, статистика, история начислений. const { useState: useRefState, useEffect: useRefEffect } = React; function ReferralPage({ user, botConfig, onNavigate }) { const [data, setData] = useRefState(null); const [bonuses, setBonuses] = useRefState([]); const [slug, setSlug] = useRefState(''); const [busy, setBusy] = useRefState(false); const [error, setError] = useRefState(''); const [copied, setCopied] = useRefState(''); const [tab, setTab] = useRefState('active'); // 'active' | 'hidden' const [page, setPage] = useRefState(0); const load = async () => { try { const d = await api.get('/api/me/referral'); if (d.__unauthorized) return onNavigate('auth'); setData(d); const b = await api.get('/api/me/referral/bonuses'); if (!b.__unauthorized) setBonuses(b); } catch (e) { setError(e.message || 'Ошибка загрузки'); } }; useRefEffect(() => { load(); }, []); const refCode = (l) => `${user.user_id}-${l.slug}`; const siteLink = (l) => `${window.location.origin}/?ref=${refCode(l)}`; const botLink = (l) => `${(botConfig && botConfig.bot_url) || 'https://t.me/AVITOPF_bot'}?start=ref_${refCode(l)}`; const copy = async (text, key) => { try { await navigator.clipboard.writeText(text); setCopied(key); setTimeout(() => setCopied(''), 1500); } catch (e) { setError('Не удалось скопировать'); } }; const createLink = async () => { setBusy(true); setError(''); try { await api.post('/api/me/referral/links', { slug: slug.trim().toLowerCase() }); setSlug(''); await load(); } catch (e) { setError(e.message || 'Ошибка'); } finally { setBusy(false); } }; // «Случайная» лишь подставляет валидный слаг в поле — ссылка создаётся // только после явного нажатия «Создать». const fillRandomSlug = () => { const abc = 'abcdefghijklmnopqrstuvwxyz0123456789'; let s = ''; for (let i = 0; i < 8; i++) s += abc[Math.floor(Math.random() * abc.length)]; setSlug(s); setError(''); }; const hide = async (id) => { if (!confirm('Скрыть ссылку? Она уйдёт в «Скрытые»: новых по ней не привести, но начисления по уже приведённым рефералам продолжатся. Вернуть можно в любой момент.')) return; setBusy(true); setError(''); try { await api.delete('/api/me/referral/links/' + id); await load(); } catch (e) { setError(e.message || 'Ошибка'); } finally { setBusy(false); } }; const restore = async (id) => { setBusy(true); setError(''); try { await api.post('/api/me/referral/links/' + id + '/restore'); await load(); } catch (e) { setError(e.message || 'Ошибка'); } finally { setBusy(false); } }; if (!data) return
Загрузка...
; const active = data.links.filter(l => !l.archived_at); const hidden = data.links.filter(l => l.archived_at); const PAGE_SIZE = 5; const shown = tab === 'active' ? active : hidden; const pageCount = Math.max(1, Math.ceil(shown.length / PAGE_SIZE)); const safePage = Math.min(page, pageCount - 1); const pageItems = shown.slice(safePage * PAGE_SIZE, safePage * PAGE_SIZE + PAGE_SIZE); const switchTab = (t) => { setTab(t); setPage(0); }; return (

🤝 Партнерка

Как это работает
Делитесь ссылкой — получайте {data.percent}% с каждого пополнения приведенных пользователей на баланс сервиса. Пожизненно.
Рефералов: {data.referrals_count}
Заработано: {data.total_earned.toLocaleString('ru-RU')} ₽
{error &&
{error}
}

Новая ссылка

setSlug(e.target.value)} disabled={busy} />
{tab === 'hidden' && hidden.length > 0 && (
Новых рефералов по ним не привести, но начисления по уже приведённым продолжаются. Можно вернуть в активные.
)} {shown.length === 0 ?
{tab === 'active' ? 'Пока нет — создайте первую выше.' : 'Скрытых ссылок нет.'}
: pageItems.map(l => (
{l.slug} {l.effective_percent}% · клики: {l.clicks} · регистрации: {l.registrations} · заработано: {l.earned.toLocaleString('ru-RU')} ₽
{tab === 'active' ? ( <> ) : ( )}
))} {pageCount > 1 && (
{safePage + 1} / {pageCount}
)}

История начислений

{bonuses.length === 0 ?
Начислений пока нет.
: bonuses.map(b => (
{formatDate ? formatDate(b.created_at) : b.created_at} · реферал #{b.referred_user_id}{b.link_slug ? ` · ${b.link_slug}` : ''} · {b.percent}% +{b.amount.toLocaleString('ru-RU')} ₽
))}
); } Object.assign(window, { ReferralPage });