diff --git a/src/pages/Info.tsx b/src/pages/Info.tsx index 1ba1e16..1e9f7e5 100644 --- a/src/pages/Info.tsx +++ b/src/pages/Info.tsx @@ -3,6 +3,7 @@ import { useQuery } from '@tanstack/react-query' import { useTranslation } from 'react-i18next' import DOMPurify from 'dompurify' import { infoApi, FaqPage } from '../api/info' +import { promoApi, LoyaltyTierInfo } from '../api/promo' const InfoIcon = () => ( @@ -28,6 +29,12 @@ const ShieldIcon = () => ( ) +const StarIcon = () => ( + + + +) + const ChevronIcon = ({ expanded }: { expanded: boolean }) => ( ( ) -type TabType = 'faq' | 'rules' | 'privacy' | 'offer' +type TabType = 'faq' | 'rules' | 'privacy' | 'offer' | 'loyalty' // Sanitize HTML content to prevent XSS const sanitizeHtml = (html: string): string => { @@ -134,11 +141,20 @@ export default function Info() { refetchOnMount: 'always', }) + const { data: loyaltyData, isLoading: loyaltyLoading } = useQuery({ + queryKey: ['loyalty-tiers'], + queryFn: promoApi.getLoyaltyTiers, + enabled: activeTab === 'loyalty', + staleTime: 0, + refetchOnMount: 'always', + }) + const tabs = [ { id: 'faq' as TabType, label: t('info.faq'), icon: QuestionIcon }, { id: 'rules' as TabType, label: t('info.rules'), icon: DocumentIcon }, { id: 'privacy' as TabType, label: t('info.privacy'), icon: ShieldIcon }, { id: 'offer' as TabType, label: t('info.offer'), icon: DocumentIcon }, + { id: 'loyalty' as TabType, label: t('info.loyalty'), icon: StarIcon }, ] const toggleFaq = (id: number) => { @@ -272,6 +288,181 @@ export default function Info() { ) } + if (activeTab === 'loyalty') { + if (loyaltyLoading) { + return ( +
+
+
+ ) + } + + if (!loyaltyData || loyaltyData.tiers.length === 0) { + return ( +
+ {t('info.noLoyaltyTiers')} +
+ ) + } + + const formatCurrency = (amount: number) => { + return new Intl.NumberFormat('ru-RU', { + style: 'currency', + currency: 'RUB', + minimumFractionDigits: 0, + maximumFractionDigits: 0, + }).format(amount) + } + + const getStatusBadge = (tier: LoyaltyTierInfo) => { + if (tier.is_current) { + return ( + + {t('info.statusCurrent')} + + ) + } + if (tier.is_achieved) { + return ( + + {t('info.statusAchieved')} + + ) + } + return ( + + {t('info.statusLocked')} + + ) + } + + const hasAnyDiscount = (tier: LoyaltyTierInfo) => { + return ( + tier.server_discount_percent > 0 || + tier.traffic_discount_percent > 0 || + tier.device_discount_percent > 0 || + Object.keys(tier.period_discounts).length > 0 + ) + } + + return ( +
+ {/* Progress Card */} +
+

{t('info.yourProgress')}

+ +
+
+
{t('info.totalSpent')}
+
+ {formatCurrency(loyaltyData.current_spent_rubles)} +
+
+
+
{t('info.currentStatus')}
+
+ {loyaltyData.current_tier_name || '-'} +
+
+
+ + {/* Progress bar to next tier */} + {loyaltyData.next_tier_name && loyaltyData.next_tier_threshold_rubles ? ( +
+
+ {t('info.nextStatus')}: {loyaltyData.next_tier_name} + {t('info.toNextStatus')}: {formatCurrency(loyaltyData.next_tier_threshold_rubles - loyaltyData.current_spent_rubles)} +
+
+
+
+
+ {loyaltyData.progress_percent.toFixed(1)}% +
+
+ ) : ( +
+ {t('info.allStatusesAchieved')} +
+ )} +
+ + {/* Tiers List */} +
+ {loyaltyData.tiers.map((tier) => ( +
+
+
+
+ +
+
+

{tier.name}

+

+ {t('info.threshold')}: {formatCurrency(tier.threshold_rubles)} +

+
+
+ {getStatusBadge(tier)} +
+ + {/* Discounts */} + {hasAnyDiscount(tier) ? ( +
+
{t('info.discounts')}:
+
+ {tier.server_discount_percent > 0 && ( + + {t('info.serverDiscount')}: -{tier.server_discount_percent}% + + )} + {tier.traffic_discount_percent > 0 && ( + + {t('info.trafficDiscount')}: -{tier.traffic_discount_percent}% + + )} + {tier.device_discount_percent > 0 && ( + + {t('info.deviceDiscount')}: -{tier.device_discount_percent}% + + )} + {Object.entries(tier.period_discounts).map(([days, percent]) => ( + + {t('info.periodDiscount', { days })}: -{percent}% + + ))} +
+
+ ) : ( +
{t('info.noDiscounts')}
+ )} +
+ ))} +
+
+ ) + } + return null }