From c4f228fba6cbb0fe9ce0ac007e05c0cf2bf1fff0 Mon Sep 17 00:00:00 2001 From: Fringg Date: Sat, 7 Feb 2026 03:36:25 +0300 Subject: [PATCH 1/2] feat: add SVG brand icons for payment methods Replace emoji icons with proper SVG brand-colored icons for all 12 payment providers (YooKassa, CloudPayments, CryptoBot, Telegram Stars, Heleket, MulenPay, PAL24, Platega, WATA, Freekassa, Tribute, Kassa AI). --- src/components/PaymentMethodIcon.tsx | 170 +++++++++++++++++++++++++++ src/pages/AdminPaymentMethodEdit.tsx | 21 +--- src/pages/AdminPaymentMethods.tsx | 27 +---- src/pages/TopUpMethodSelect.tsx | 8 +- 4 files changed, 184 insertions(+), 42 deletions(-) create mode 100644 src/components/PaymentMethodIcon.tsx diff --git a/src/components/PaymentMethodIcon.tsx b/src/components/PaymentMethodIcon.tsx new file mode 100644 index 0000000..3f4aa1b --- /dev/null +++ b/src/components/PaymentMethodIcon.tsx @@ -0,0 +1,170 @@ +interface PaymentMethodIconProps { + method: string; + className?: string; +} + +export default function PaymentMethodIcon({ + method, + className = 'h-8 w-8', +}: PaymentMethodIconProps) { + switch (method) { + case 'telegram_stars': + return ( + + + + + ); + + case 'cryptobot': + return ( + + + + + ); + + case 'yookassa': + return ( + + + + + + + + ); + + case 'heleket': + return ( + + + + + ); + + case 'mulenpay': + return ( + + + + + ); + + case 'pal24': + return ( + + + + + P24 + + + + ); + + case 'platega': + return ( + + + + + ); + + case 'wata': + return ( + + + + + + ); + + case 'freekassa': + return ( + + + + + FK + + + + ); + + case 'cloudpayments': + return ( + + + + + ); + + case 'tribute': + return ( + + + + + ); + + case 'kassa_ai': + return ( + + + + + + + + + + + AI + + + + ); + + default: + return ( + + + + + ); + } +} diff --git a/src/pages/AdminPaymentMethodEdit.tsx b/src/pages/AdminPaymentMethodEdit.tsx index b1e3622..29a9fdd 100644 --- a/src/pages/AdminPaymentMethodEdit.tsx +++ b/src/pages/AdminPaymentMethodEdit.tsx @@ -6,6 +6,7 @@ import { adminPaymentMethodsApi } from '../api/adminPaymentMethods'; import type { PromoGroupSimple } from '../types'; import { usePlatform } from '../platform/hooks/usePlatform'; import { createNumberInputHandler, toNumber } from '../utils/inputHelpers'; +import PaymentMethodIcon from '@/components/PaymentMethodIcon'; const BackIcon = () => ( ( ); -const METHOD_ICONS: Record = { - telegram_stars: '⭐', - tribute: '🎁', - cryptobot: '🪙', - heleket: '⚡', - yookassa: '🏦', - mulenpay: '💳', - pal24: '💸', - platega: '💰', - wata: '💧', - freekassa: '💵', - cloudpayments: '☁️', - kassa_ai: '🏦', -}; - const METHOD_LABELS: Record = { telegram_stars: 'Telegram Stars', tribute: 'Tribute', @@ -195,7 +181,6 @@ export default function AdminPaymentMethodEdit() { } const displayName = config.display_name || config.default_display_name; - const icon = METHOD_ICONS[config.method_id] || '💳'; return (
@@ -210,8 +195,8 @@ export default function AdminPaymentMethodEdit() { )} -
- {icon} +
+

{displayName}

diff --git a/src/pages/AdminPaymentMethods.tsx b/src/pages/AdminPaymentMethods.tsx index 0994386..1b129fb 100644 --- a/src/pages/AdminPaymentMethods.tsx +++ b/src/pages/AdminPaymentMethods.tsx @@ -23,6 +23,7 @@ import { import { CSS } from '@dnd-kit/utilities'; import { adminPaymentMethodsApi } from '../api/adminPaymentMethods'; import type { PaymentMethodConfig } from '../types'; +import PaymentMethodIcon from '@/components/PaymentMethodIcon'; // ============ Icons ============ @@ -64,23 +65,6 @@ const SaveIcon = () => ( ); -// ============ Method icon by type ============ - -const METHOD_ICONS: Record = { - telegram_stars: '\u2B50', - tribute: '\uD83C\uDF81', - cryptobot: '\uD83E\uDE99', - heleket: '\u26A1', - yookassa: '\uD83C\uDFE6', - mulenpay: '\uD83D\uDCB3', - pal24: '\uD83D\uDCB8', - platega: '\uD83D\uDCB0', - wata: '\uD83D\uDCA7', - freekassa: '\uD83D\uDCB5', - cloudpayments: '\u2601\uFE0F', - kassa_ai: '\uD83C\uDFE6', -}; - // ============ Sortable Card ============ interface SortableCardProps { @@ -102,7 +86,6 @@ function SortablePaymentCard({ config, onClick }: SortableCardProps) { }; const displayName = config.display_name || config.default_display_name; - const icon = METHOD_ICONS[config.method_id] || '\uD83D\uDCB3'; // Build condition summary chips const chips: string[] = []; @@ -153,8 +136,8 @@ function SortablePaymentCard({ config, onClick }: SortableCardProps) { {/* Method icon */} -
- {icon} +
+
{/* Content */} @@ -337,8 +320,8 @@ export default function AdminPaymentMethods() { ) : (
-
- {'\uD83D\uDCB3'} +
+
{t('admin.paymentMethods.noMethods')}
diff --git a/src/pages/TopUpMethodSelect.tsx b/src/pages/TopUpMethodSelect.tsx index 1801e6a..b5fa841 100644 --- a/src/pages/TopUpMethodSelect.tsx +++ b/src/pages/TopUpMethodSelect.tsx @@ -7,6 +7,7 @@ import { balanceApi } from '../api/balance'; import { useCurrency } from '../hooks/useCurrency'; import { Card } from '@/components/data-display/Card'; import { staggerContainer, staggerItem } from '@/components/motion/transitions'; +import PaymentMethodIcon from '@/components/PaymentMethodIcon'; export default function TopUpMethodSelect() { const { t } = useTranslation(); @@ -70,8 +71,11 @@ export default function TopUpMethodSelect() { className={!method.is_available ? 'cursor-not-allowed opacity-50' : ''} onClick={() => method.is_available && handleMethodClick(method.id)} > -
- {translatedName || method.name} +
+ +
+ {translatedName || method.name} +
{(translatedDesc || method.description) && (
From 2c0d265ff5c3ea9e3ed56fdb24cdd2301abba617 Mon Sep 17 00:00:00 2001 From: Fringg Date: Sat, 7 Feb 2026 03:36:31 +0300 Subject: [PATCH 2/2] fix: remove incorrect ruble top-up prompt from fortune wheel Trial users saw an "insufficient balance" prompt suggesting to top up rubles, but the wheel only accepts Telegram Stars (via invoice) or subscription days. Stars payment via invoice doesn't require ruble balance, so the spin button should not be disabled for it. --- src/pages/Wheel.tsx | 41 +++++++++++++++++++---------------------- 1 file changed, 19 insertions(+), 22 deletions(-) diff --git a/src/pages/Wheel.tsx b/src/pages/Wheel.tsx index 6a2cca0..1bb03f1 100644 --- a/src/pages/Wheel.tsx +++ b/src/pages/Wheel.tsx @@ -4,7 +4,6 @@ import { useTranslation } from 'react-i18next'; import { wheelApi, type SpinResult, type SpinHistoryItem } from '../api/wheel'; import FortuneWheel from '../components/wheel/FortuneWheel'; import WheelLegend from '../components/wheel/WheelLegend'; -import InsufficientBalancePrompt from '../components/InsufficientBalancePrompt'; import { usePlatform, useHaptic } from '@/platform'; import { useNotify } from '@/platform/hooks/useNotify'; import { Card } from '@/components/data-display/Card/Card'; @@ -461,11 +460,13 @@ export default function Wheel() { const daysEnabled = config.spin_cost_days_enabled && config.spin_cost_days; const bothMethodsAvailable = !!(starsEnabled && daysEnabled); + // Stars via Telegram invoice don't require ruble balance, so only check daily limit + const dailyLimitReached = config.daily_limit > 0 && config.user_spins_today >= config.daily_limit; const spinDisabled = - !config.can_spin || isSpinning || isPayingStars || - (config.daily_limit > 0 && config.user_spins_today >= config.daily_limit); + dailyLimitReached || + (paymentType === 'telegram_stars' ? !starsEnabled : !config.can_spin); return (
@@ -570,25 +571,21 @@ export default function Wheel() { )} - {/* Cannot spin hint */} - {!config.can_spin && !isSpinning && ( - <> - {config.can_spin_reason === 'daily_limit_reached' ? ( -
-

{t('wheel.errors.dailyLimitReached')}

-
- ) : config.can_spin_reason === 'insufficient_balance' ? ( - - ) : ( -
-

{t('wheel.errors.cannotSpin')}

-
- )} - + {/* Cannot spin hint — only show for days payment (Stars via invoice always works) */} + {!isSpinning && paymentType !== 'telegram_stars' && !config.can_spin && ( +
+

+ {config.can_spin_reason === 'daily_limit_reached' + ? t('wheel.errors.dailyLimitReached') + : t('wheel.errors.cannotSpin')} +

+
+ )} + {/* Daily limit hint for Stars payment (not covered by can_spin check) */} + {!isSpinning && paymentType === 'telegram_stars' && dailyLimitReached && ( +
+

{t('wheel.errors.dailyLimitReached')}

+
)} {/* Inline Result Card */}