import { useState } from 'react' 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 QuestionIcon = () => ( ) const DocumentIcon = () => ( ) const ShieldIcon = () => ( ) const StarIcon = () => ( ) const ChevronIcon = ({ expanded }: { expanded: boolean }) => ( ) type TabType = 'faq' | 'rules' | 'privacy' | 'offer' | 'loyalty' // Sanitize HTML content to prevent XSS const sanitizeHtml = (html: string): string => { return DOMPurify.sanitize(html, { ALLOWED_TAGS: ['p', 'br', 'b', 'i', 'u', 'strong', 'em', 'a', 'ul', 'ol', 'li', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'blockquote', 'code', 'pre', 'span', 'div'], ALLOWED_ATTR: ['href', 'target', 'rel', 'class'], ALLOW_DATA_ATTR: false, }) } // Convert plain text to HTML with proper formatting const formatContent = (content: string): string => { if (!content) return '' // Check if content already has HTML tags const hasHtmlTags = /<[a-z][\s\S]*>/i.test(content) if (hasHtmlTags) { return sanitizeHtml(content) } // Convert plain text to formatted HTML const result = content .split(/\n\n+/) // Split by double newlines (paragraphs) .map(paragraph => { // Check if it's a header (starts with # or numeric like "1.") if (/^#{1,4}\s/.test(paragraph)) { const level = paragraph.match(/^(#{1,4})/)?.[1].length || 1 const text = paragraph.replace(/^#{1,4}\s*/, '') return `${text}` } // Check for list items if (/^[-•]\s/.test(paragraph) || /^\d+[.)]\s/.test(paragraph)) { const lines = paragraph.split('\n') const isOrdered = /^\d+[.)]\s/.test(lines[0]) const listItems = lines .map(line => line.replace(/^[-•]\s*/, '').replace(/^\d+[.)]\s*/, '')) .filter(line => line.trim()) .map(line => `
  • ${line}
  • `) .join('') return isOrdered ? `
      ${listItems}
    ` : `` } // Regular paragraph - handle single line breaks within const formattedParagraph = paragraph .split('\n') .join('
    ') return `

    ${formattedParagraph}

    ` }) .join('') return sanitizeHtml(result) } export default function Info() { const { t } = useTranslation() const [activeTab, setActiveTab] = useState('faq') const [expandedFaq, setExpandedFaq] = useState(null) const { data: faqPages, isLoading: faqLoading } = useQuery({ queryKey: ['faq-pages'], queryFn: infoApi.getFaqPages, enabled: activeTab === 'faq', staleTime: 0, refetchOnMount: 'always', }) const { data: rules, isLoading: rulesLoading } = useQuery({ queryKey: ['rules'], queryFn: infoApi.getRules, enabled: activeTab === 'rules', staleTime: 0, refetchOnMount: 'always', }) const { data: privacy, isLoading: privacyLoading } = useQuery({ queryKey: ['privacy-policy'], queryFn: infoApi.getPrivacyPolicy, enabled: activeTab === 'privacy', staleTime: 0, refetchOnMount: 'always', }) const { data: offer, isLoading: offerLoading } = useQuery({ queryKey: ['public-offer'], queryFn: infoApi.getPublicOffer, enabled: activeTab === 'offer', staleTime: 0, 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) => { setExpandedFaq(expandedFaq === id ? null : id) } const renderContent = () => { if (activeTab === 'faq') { if (faqLoading) { return (
    ) } if (!faqPages || faqPages.length === 0) { return (
    {t('info.noFaq')}
    ) } return (
    {faqPages.map((faq: FaqPage) => (
    {expandedFaq === faq.id && (
    )}
    ))}
    ) } if (activeTab === 'rules') { if (rulesLoading) { return (
    ) } if (!rules?.content) { return (
    {t('info.noContent')}
    ) } return (
    {rules.updated_at && (

    {t('info.updatedAt')}: {new Date(rules.updated_at).toLocaleDateString()}

    )}
    ) } if (activeTab === 'privacy') { if (privacyLoading) { return (
    ) } if (!privacy?.content) { return (
    {t('info.noContent')}
    ) } return (
    {privacy.updated_at && (

    {t('info.updatedAt')}: {new Date(privacy.updated_at).toLocaleDateString()}

    )}
    ) } if (activeTab === 'offer') { if (offerLoading) { return (
    ) } if (!offer?.content) { return (
    {t('info.noContent')}
    ) } return (
    {offer.updated_at && (

    {t('info.updatedAt')}: {new Date(offer.updated_at).toLocaleDateString()}

    )}
    ) } 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 } return (

    {t('info.title')}

    {/* Tabs */}
    {tabs.map((tab) => ( ))}
    {/* Content */} {renderContent()}
    ) }