// screens-misc.jsx — Referrals + History + Profile/Settings const { useState: _ms_useState, useEffect: _ms_useEffect } = React; // ============================================================ // Referrals // ============================================================ function ReferralsScreen({ ctx }){ const { t: T, premium, navigate, campaign, miniContext } = ctx; const ref = window.RAVANA_DATA.referral_user; const [copied, setCopied] = _ms_useState(false); const [view, setView] = _ms_useState( campaign === 'referral_challenge' || miniContext === 'referral_challenge' ? 'challenge' : 'overview' ); const copy = () => { setCopied(true); if (navigator.clipboard) navigator.clipboard.writeText(ref.invite_link).catch(()=>{}); setTimeout(()=>setCopied(false), 1600); }; return (
}/> {/* Tab switcher */}
{view === 'overview' && } {view === 'challenge' && }
); } function ReferralOverview({ referral, copy, copied, ctx, premium }){ const { t: T } = ctx; return ( <> {/* Referral Premium status */} {premium === 'ref_premium' && (
{T('referral_premium_active')}
{T('referral_premium_sub')}
)} {/* Invite link */}
{T('your_link')}
{referral.invite_link}
{/* Rewards explanation */}
{T('reward_per_friend')}
{T('reward_per_paid')}
{/* Stats */}

Your stats

} color="cyan"/> } color="success"/> } color="gold"/> } color="purple"/>
); } function StatCard({ label, value, icon, color }){ const colors = { cyan: { bg: 'rgba(34,211,238,0.12)', col: 'var(--cyan)' }, purple: { bg: 'rgba(155,92,255,0.14)', col: 'var(--purple-3)' }, gold: { bg: 'rgba(246,200,95,0.14)', col: 'var(--gold)' }, success: { bg: 'rgba(46,230,166,0.12)', col: 'var(--success)' }, }; const c = colors[color] || colors.purple; return (
{icon}
{label}
{value}
); } function ReferralChallenge({ ctx }){ const { t: T } = ctx; const lb = window.RAVANA_DATA.leaderboard; const tiers = window.RAVANA_DATA.prize_tiers; return ( <>
{T('challenge_active')}
{T('challenge_ends')}: 3d 14h
May invite race
Top 50 referrers split 1500+ video minutes
{/* Your rank */}
{T('challenge_rank')}
#47 +12
Next tier in
3 more
{/* Prize tiers */}

{T('prize_tiers')}

{tiers.map((tier, i) => (
#{tier.rank}
{tier.reward}
))}
{/* Leaderboard */}

{T('leaderboard')}

{lb.map((row, i) => (
{row.isMe ? '#' + row.displayRank : '#' + row.rank}
{row.isMe ? 'You' : row.name}
{row.invited} invited · {row.paid} paid
{row.paid * 50 + row.invited}
))}
); } // ============================================================ // History // ============================================================ function HistoryScreen({ ctx }){ const { t: T, navigate } = ctx; const items = window.RAVANA_DATA.history; const [filter, setFilter] = _ms_useState('all'); const filtered = items.filter(item => { if (filter === 'all') return true; if (filter === 'face_swap') return item.type === 'face_swap'; if (filter === 'multiface') return item.type === 'multiface'; if (filter === 'image_gen') return item.type === 'image_gen'; if (filter === 'photo') return item.media === 'photo'; if (filter === 'video') return item.media === 'video'; return true; }); return (
}/>
{[ ['all', T('filter_all')], ['face_swap', T('face_swap')], ['multiface', T('multiface')], ['image_gen', T('image_gen')], ['photo', T('photo')], ['video', T('video')], ].map(([k, label]) => ( ))}
{filtered.length === 0 ? (
{T('empty_history')}
{T('empty_history_sub')}
) : (
{filtered.map(item => )}
)}
); } function HistoryRow({ item, ctx }){ const { t: T, navigate } = ctx; const statusChip = item.status === 'ready' ? ● {T('status_ready')} : item.status === 'processing' ? ● {T('status_processing')} : item.status === 'failed' ? {T('status_failed')} : {item.status}; const TypeIcon = item.type === 'multiface' ? Icon.multiface : item.type === 'image_gen' ? Icon.wand : Icon.face; return (
{item.media === 'video' && (
)}
{item.name}
{statusChip} {item.duration && {item.duration}} {item.enhanced && HQ}
{item.time} · {item.cost > 0 ? item.cost + (item.media === 'video' ? ' min' : ' cr') : 'no charge'}
{item.status === 'ready' ? : item.status === 'failed' ? : }
); } // ============================================================ // Profile / Settings // ============================================================ function ProfileScreen({ ctx }){ const { t: T, navigate, lang, premium, setLang, user } = ctx; const displayName = (user && (user.name || user.username)) || 'Mira'; const username = user && user.username ? `@${user.username}` : '@miraq'; const tgId = user && user.id ? user.id : 4218; return (
navigate('home')}/>
{displayName}
{username} · TG ID {tgId}

{T('settings')}

} label={T('language')} value={lang === 'ru' ? 'Русский' : 'English'} onClick={()=>setLang(lang === 'ru' ? 'en' : 'ru')}/> } label={T('manage_subscription')} onClick={()=>navigate('manage_subscription')}/> } label={T('support')} onClick={()=>navigate('support')}/> } label={T('manual')} onClick={()=>navigate('manual')}/> } label={T('terms')} onClick={()=>navigate('terms')}/> } label="Open in Telegram" badge="Web"/>
{T('version')} 1.0.0 · Build 2026.05.27
); } function SettingsRow({ icon, label, value, badge, onClick }){ return ( ); } // Simple support / manual / terms screens function SupportScreen({ ctx }){ const { t: T, navigate } = ctx; return (
navigate('profile')}/>
Need help?
Our team usually replies within a few hours.
); } function ManualScreen({ ctx }){ const { t: T, navigate } = ctx; return (
navigate('profile')}/>
{[ { t: 'Face Swap', d: 'Upload a clear source face, then your target photo or video. Best with front-facing shots.', i: }, { t: 'MultiFace', d: 'Premium feature. Detects every face in your media and lets you replace each one individually.', i: }, { t: 'Image Gen', d: 'Describe what you want and pick an aspect ratio. Costs 1 photo credit per generation.', i: }, { t: 'Fortune', d: 'Spin daily for rewards. Earn extra spins via referrals, purchases, and streaks.', i: }, { t: 'Limits', d: 'Free users: videos under 60 seconds, Telegram-size files. Premium removes both.', i: }, ].map((it, i) => (
{it.i}
{it.t}
{it.d}
))}
); } function TermsScreen({ ctx }){ const { t: T, navigate } = ctx; return (
navigate('profile')}/>

18+ acknowledgement. By using Ravana Swap you confirm you are at least 18 years old and consent to the processing of biometric data for face-swap operations.

You retain ownership of any source/target media you upload. We process it temporarily for your selected action.

Purchases are non-refundable unless required by Telegram or local law. New Stripe subscriptions are disabled; existing auto-renewals can be cancelled in Manage subscription.

Do not use Ravana Swap to deceive, harass, or harm others. Violation results in immediate access revocation.

); } window.ReferralsScreen = ReferralsScreen; window.HistoryScreen = HistoryScreen; window.ProfileScreen = ProfileScreen; window.SupportScreen = SupportScreen; window.ManualScreen = ManualScreen; window.TermsScreen = TermsScreen;