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 = () => (
)
+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
}