import { useState } from 'react'; import { useNavigate } from 'react-router'; import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query'; import { useTranslation } from 'react-i18next'; import { referralApi } from '../api/referral'; import { brandingApi } from '../api/branding'; import { partnerApi } from '../api/partners'; import { withdrawalApi } from '../api/withdrawals'; import { useCurrency } from '../hooks/useCurrency'; const LinkIcon = () => ( ); const CopyIcon = () => ( ); const CheckIcon = () => ( ); const ShareIcon = () => ( ); const PartnerIcon = () => ( ); const ClockIcon = () => ( ); const WalletIcon = () => ( ); function getWithdrawalStatusBadge(status: string): string { switch (status) { case 'completed': return 'badge-success'; case 'approved': return 'badge-info'; case 'pending': return 'badge-warning'; case 'rejected': case 'cancelled': return 'badge-error'; default: return 'badge-neutral'; } } export default function Referral() { const { t } = useTranslation(); const navigate = useNavigate(); const { formatAmount, currencySymbol, formatPositive, formatWithCurrency } = useCurrency(); const queryClient = useQueryClient(); const [copied, setCopied] = useState(false); const [copiedLink, setCopiedLink] = useState(null); const { data: info, isLoading } = useQuery({ queryKey: ['referral-info'], queryFn: referralApi.getReferralInfo, }); // Build referral link for cabinet registration const referralLink = info?.referral_code ? `${window.location.origin}/login?ref=${info.referral_code}` : ''; const { data: terms } = useQuery({ queryKey: ['referral-terms'], queryFn: referralApi.getReferralTerms, }); const { data: referralList } = useQuery({ queryKey: ['referral-list'], queryFn: () => referralApi.getReferralList({ per_page: 10 }), }); const { data: earnings } = useQuery({ queryKey: ['referral-earnings'], queryFn: () => referralApi.getReferralEarnings({ per_page: 10 }), }); const { data: branding } = useQuery({ queryKey: ['branding'], queryFn: brandingApi.getBranding, staleTime: 60000, }); // Partner status query const { data: partnerStatus } = useQuery({ queryKey: ['partner-status'], queryFn: partnerApi.getStatus, }); const isPartner = partnerStatus?.partner_status === 'approved'; // Withdrawal queries (only when partner is approved) const { data: withdrawalBalance } = useQuery({ queryKey: ['withdrawal-balance'], queryFn: withdrawalApi.getBalance, enabled: isPartner, }); const { data: withdrawalHistory } = useQuery({ queryKey: ['withdrawal-history'], queryFn: withdrawalApi.getHistory, enabled: isPartner, }); // Withdrawal cancel mutation const cancelWithdrawalMutation = useMutation({ mutationFn: withdrawalApi.cancel, onSuccess: () => { queryClient.invalidateQueries({ queryKey: ['withdrawal-balance'] }); queryClient.invalidateQueries({ queryKey: ['withdrawal-history'] }); }, }); const copyLink = () => { if (referralLink) { navigator.clipboard.writeText(referralLink); setCopied(true); setTimeout(() => setCopied(false), 2000); } }; const shareLink = () => { if (!referralLink) return; const shareText = t('referral.shareMessage', { percent: info?.commission_percent || 0, botName: branding?.name || import.meta.env.VITE_APP_NAME || 'Cabinet', }); if (navigator.share) { navigator .share({ title: t('referral.title'), text: shareText, url: referralLink, }) .catch(() => { // ignore cancellation errors }); return; } const telegramUrl = `https://t.me/share/url?url=${encodeURIComponent( referralLink, )}&text=${encodeURIComponent(shareText)}`; window.open(telegramUrl, '_blank', 'noopener,noreferrer'); }; if (isLoading) { return (
); } // Show disabled state if referral program is disabled if (terms && !terms.is_enabled) { return (

{t('referral.title')}

{t('referral.disabled')}

); } const partnerStatusValue = partnerStatus?.partner_status ?? 'none'; const showApplySection = partnerStatusValue === 'none'; const showPendingSection = partnerStatusValue === 'pending'; const showApprovedSection = partnerStatusValue === 'approved'; const showRejectedSection = partnerStatusValue === 'rejected'; return (

{t('referral.title')}

{/* Stats Cards */}
{t('referral.stats.totalReferrals')}
{info?.total_referrals || 0}
{info?.active_referrals || 0} {t('referral.stats.activeReferrals').toLowerCase()}
{t('referral.stats.totalEarnings')}
{formatPositive(info?.total_earnings_rubles || 0)}
{t('referral.stats.commissionRate')}
{info?.commission_percent || 0}%
{/* Referral Link */}

{t('referral.yourLink')}

{t('referral.shareHint', { percent: info?.commission_percent || 0 })}

{/* Program Terms */} {terms && (

{t('referral.terms.title')}

{t('referral.terms.commission')}
{terms.commission_percent}%
{t('referral.terms.minTopup')}
{formatAmount(terms.minimum_topup_rubles)} {currencySymbol}
{t('referral.terms.newUserBonus')}
{formatPositive(terms.first_topup_bonus_rubles)}
{t('referral.terms.inviterBonus')}
{formatPositive(terms.inviter_bonus_rubles)}
)} {/* Referrals List */}

{t('referral.yourReferrals')}

{referralList?.items && referralList.items.length > 0 ? (
{referralList.items.map((ref) => (
{ref.first_name || ref.username || `User #${ref.id}`}
{new Date(ref.created_at).toLocaleDateString()}
{ref.has_paid ? ( {t('referral.status.paid')} ) : ( {t('referral.status.pending')} )}
))}
) : (
{t('referral.noReferrals')}
)}
{/* Earnings History */} {earnings?.items && earnings.items.length > 0 && (

{t('referral.earningsHistory')}

{earnings.items.map((earning) => (
{earning.referral_first_name || earning.referral_username || 'Referral'}
{t(`referral.reasons.${earning.reason}`, earning.reason)} •{' '} {new Date(earning.created_at).toLocaleDateString()}
{formatPositive(earning.amount_rubles)}
))}
)} {/* ==================== Partner Application Section ==================== */} {/* Status: none — Become a Partner CTA */} {terms?.partner_section_visible !== false && showApplySection && (

{t('referral.partner.becomePartner')}

{t('referral.partner.becomePartnerDesc')}

)} {/* Status: pending — Application Under Review */} {terms?.partner_section_visible !== false && showPendingSection && (

{t('referral.partner.underReview')}

{t('referral.partner.underReviewDesc')}

{partnerStatus?.latest_application?.created_at && (

{t('referral.partner.submittedAt', { date: new Date( partnerStatus.latest_application.created_at, ).toLocaleDateString(), })}

)}
)} {/* Status: approved — Partner Badge */} {terms?.partner_section_visible !== false && showApprovedSection && (

{t('referral.partner.partnerStatus')}

{t('referral.partner.active')}

{t('referral.partner.commissionInfo', { percent: partnerStatus?.commission_percent ?? 0, })}

{t('referral.withdrawal.goToWithdrawal')}
)} {/* Status: rejected — Rejection Notice */} {terms?.partner_section_visible !== false && showRejectedSection && (

{t('referral.partner.rejected')}

{partnerStatus?.latest_application?.admin_comment && (

{partnerStatus.latest_application.admin_comment}

)}
)} {/* ==================== Partner Campaigns Section ==================== */} {terms?.partner_section_visible !== false && isPartner && partnerStatus?.campaigns && partnerStatus.campaigns.length > 0 && (

{t('referral.partner.yourCampaigns')}

{partnerStatus.campaigns.map((campaign) => { const copyLink = (url: string, key: string) => { navigator.clipboard.writeText(url); setCopiedLink(key); setTimeout(() => setCopiedLink(null), 2000); }; const botKey = `${campaign.id}-bot`; const webKey = `${campaign.id}-web`; return (
{/* Campaign header */}

{campaign.name}

{/* Bonus info */} {campaign.bonus_type !== 'none' && (
{t('referral.partner.campaignBonus.title')}
{campaign.bonus_type === 'balance' && t('referral.partner.campaignBonus.balanceDesc', { amount: formatWithCurrency(campaign.balance_bonus_kopeks / 100, 0), })} {campaign.bonus_type === 'subscription' && t('referral.partner.campaignBonus.subscriptionDesc', { days: campaign.subscription_duration_days ?? 0, ...(campaign.subscription_traffic_gb ? { traffic: campaign.subscription_traffic_gb } : {}), })} {campaign.bonus_type === 'tariff' && t('referral.partner.campaignBonus.tariffDesc')}
)} {/* Bot link */} {campaign.deep_link && (
{t('referral.partner.campaignLinks.bot')}
)} {/* Web link */} {campaign.web_link && (
{t('referral.partner.campaignLinks.web')}
)}
); })}
)} {/* ==================== Withdrawal Section (approved partners only) ==================== */} {terms?.partner_section_visible !== false && isPartner && (
{/* Withdrawal Balance Card */} {withdrawalBalance && (

{t('referral.withdrawal.title')}

{t('referral.withdrawal.available')}
{formatWithCurrency(withdrawalBalance.available_total / 100)}
{t('referral.withdrawal.totalEarned')}
{formatWithCurrency(withdrawalBalance.total_earned / 100)}
{t('referral.withdrawal.withdrawn')}
{formatWithCurrency(withdrawalBalance.withdrawn / 100)}
{t('referral.withdrawal.spent')}
{formatWithCurrency(withdrawalBalance.referral_spent / 100)}
{t('referral.withdrawal.pending')}
{formatWithCurrency(withdrawalBalance.pending / 100)}
{!withdrawalBalance.can_request && withdrawalBalance.cannot_request_reason ? (

{withdrawalBalance.cannot_request_reason}

) : ( withdrawalBalance.min_amount_kopeks > 0 && (

{t('referral.withdrawal.minAmount', { amount: formatWithCurrency(withdrawalBalance.min_amount_kopeks / 100), })}

) )}
)} {/* Withdrawal History */}

{t('referral.withdrawal.history')}

{withdrawalHistory?.items && withdrawalHistory.items.length > 0 ? (
{withdrawalHistory.items.map((item) => (
{formatWithCurrency(item.amount_rubles)} {t(`referral.withdrawal.status.${item.status}`, item.status)}
{new Date(item.created_at).toLocaleDateString()} {item.payment_details && ( •{' '} {item.payment_details.length > 40 ? `${item.payment_details.slice(0, 40)}...` : item.payment_details} )}
{item.admin_comment && (
{item.admin_comment}
)}
{item.status === 'pending' && ( )}
))}
) : (
{t('referral.withdrawal.noHistory')}
)}
)}
); }