import { useState } from 'react'; import { useNavigate } from 'react-router-dom'; import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query'; import { useTranslation } from 'react-i18next'; import i18n from '../i18n'; import { promocodesApi, PromoCode, PromoCodeType } from '../api/promocodes'; import { useBackButton } from '../platform/hooks/useBackButton'; import { usePlatform } from '../platform/hooks/usePlatform'; // Icons const BackIcon = () => ( ); const PlusIcon = () => ( ); const EditIcon = () => ( ); const TrashIcon = () => ( ); const CheckIcon = () => ( ); const CopyIcon = () => ( ); const ChartIcon = () => ( ); // Helper functions const getTypeLabel = (type: PromoCodeType): string => { const labels: Record = { balance: i18n.t('admin.promocodes.type.balance'), subscription_days: i18n.t('admin.promocodes.type.subscriptionDays'), trial_subscription: i18n.t('admin.promocodes.type.trialSubscription'), promo_group: i18n.t('admin.promocodes.type.promoGroup'), discount: i18n.t('admin.promocodes.type.discount'), }; return labels[type] || type; }; const getTypeColor = (type: PromoCodeType): string => { const colors: Record = { balance: 'bg-success-500/20 text-success-400', subscription_days: 'bg-accent-500/20 text-accent-400', trial_subscription: 'bg-accent-500/20 text-accent-400', promo_group: 'bg-warning-500/20 text-warning-400', discount: 'bg-pink-500/20 text-pink-400', }; return colors[type] || 'bg-dark-600 text-dark-300'; }; const formatDate = (date: string | null): string => { if (!date) return '-'; const localeMap: Record = { ru: 'ru-RU', en: 'en-US', zh: 'zh-CN', fa: 'fa-IR' }; const locale = localeMap[i18n.language] || 'ru-RU'; return new Date(date).toLocaleDateString(locale, { day: '2-digit', month: '2-digit', year: 'numeric', }); }; export default function AdminPromocodes() { const { t } = useTranslation(); const navigate = useNavigate(); const queryClient = useQueryClient(); const { capabilities } = usePlatform(); // Use native Telegram back button in Mini App useBackButton(() => navigate('/admin')); const [deleteConfirm, setDeleteConfirm] = useState(null); const [copiedCode, setCopiedCode] = useState(null); // Query const { data: promocodesData, isLoading } = useQuery({ queryKey: ['admin-promocodes'], queryFn: () => promocodesApi.getPromocodes({ limit: 100 }), }); // Delete mutation const deleteMutation = useMutation({ mutationFn: promocodesApi.deletePromocode, onSuccess: () => { queryClient.invalidateQueries({ queryKey: ['admin-promocodes'] }); setDeleteConfirm(null); }, }); const handleCopyCode = (code: string) => { navigator.clipboard.writeText(code); setCopiedCode(code); setTimeout(() => setCopiedCode(null), 2000); }; const promocodes = promocodesData?.items || []; return ( {/* Header */} {/* Show back button only on web, not in Telegram Mini App */} {!capabilities.hasBackButton && ( navigate('/admin')} className="flex h-10 w-10 items-center justify-center rounded-xl border border-dark-700 bg-dark-800 transition-colors hover:border-dark-600" > )} {t('admin.promocodes.title')} {t('admin.promocodes.subtitle')} navigate('/admin/promocodes/create')} className="flex items-center justify-center gap-2 rounded-lg bg-accent-500 px-4 py-2 text-white transition-colors hover:bg-accent-600" > {t('admin.promocodes.addPromocode')} {/* Stats Overview */} {promocodes.length > 0 && ( {promocodes.length} {t('admin.promocodes.stats.totalPromocodes')} {promocodes.filter((p) => p.is_active && p.is_valid).length} {t('admin.promocodes.stats.activeCount')} {promocodes.reduce((sum, p) => sum + p.current_uses, 0)} {t('admin.promocodes.stats.usagesCount')} {promocodes.filter((p) => p.uses_left === 0 && p.max_uses > 0).length} {t('admin.promocodes.stats.exhausted')} )} {/* Promocodes List */} {isLoading ? ( ) : promocodes.length === 0 ? ( {t('admin.promocodes.noPromocodes')} ) : ( {promocodes.map((promo: PromoCode) => ( {/* Mobile: stacked layout, Desktop: row layout */} {/* Code with copy button */} handleCopyCode(promo.code)} className="flex items-center gap-1.5 font-mono font-medium text-dark-100 transition-colors hover:text-accent-400" > {promo.code} {copiedCode === promo.code ? : } {/* Badges - wrap on mobile */} {getTypeLabel(promo.type)} {!promo.is_active && ( {t('admin.promocodes.stats.inactive')} )} {promo.first_purchase_only && ( {t('admin.promocodes.firstPurchase')} )} {/* Info line */} {promo.type === 'balance' && ( +{promo.balance_bonus_rubles} {t('admin.promocodes.form.rub')} )} {(promo.type === 'subscription_days' || promo.type === 'trial_subscription') && ( +{promo.subscription_days} {t('admin.promocodes.form.days')} )} {promo.type === 'discount' && ( {t('admin.promocodes.discountForHours', { percent: promo.balance_bonus_kopeks, hours: promo.subscription_days, })} )} {t('admin.promocodes.used')}: {promo.current_uses}/ {promo.max_uses === 0 ? '∞' : promo.max_uses} {promo.valid_until && ( {t('admin.promocodes.until')}: {formatDate(promo.valid_until)} )} {/* Action buttons - full width on mobile */} navigate(`/admin/promocodes/${promo.id}/stats`)} className="flex-1 rounded-lg bg-dark-700 p-2 text-dark-300 transition-colors hover:bg-accent-500/20 hover:text-accent-400 sm:flex-none" title={t('admin.promocodes.actions.stats')} > navigate(`/admin/promocodes/${promo.id}/edit`)} className="flex-1 rounded-lg bg-dark-700 p-2 text-dark-300 transition-colors hover:bg-dark-600 hover:text-dark-100 sm:flex-none" title={t('admin.promocodes.actions.edit')} > setDeleteConfirm(promo.id)} className="flex-1 rounded-lg bg-dark-700 p-2 text-dark-300 transition-colors hover:bg-error-500/20 hover:text-error-400 sm:flex-none" title={t('admin.promocodes.actions.delete')} > ))} )} {/* Delete Confirmation */} {deleteConfirm && ( {t('admin.promocodes.confirm.deletePromocode')} {t('admin.promocodes.confirm.deletePromocodeText')} setDeleteConfirm(null)} className="px-4 py-2 text-dark-300 transition-colors hover:text-dark-100" > {t('admin.promocodes.form.cancel')} deleteMutation.mutate(deleteConfirm)} className="rounded-lg bg-error-500 px-4 py-2 text-white transition-colors hover:bg-error-600" > {t('admin.promocodes.confirm.deleteButton')} )} ); }
{t('admin.promocodes.subtitle')}
{t('admin.promocodes.noPromocodes')}
{t('admin.promocodes.confirm.deletePromocodeText')}