mirror of
https://github.com/chillpadclub/bedolaga-cabinet.git
synced 2026-07-28 09:33:46 +00:00
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).
This commit is contained in:
170
src/components/PaymentMethodIcon.tsx
Normal file
170
src/components/PaymentMethodIcon.tsx
Normal file
@@ -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 (
|
||||
<svg className={className} viewBox="0 0 40 40">
|
||||
<circle cx="20" cy="20" r="20" fill="#229ED9" />
|
||||
<path
|
||||
d="M20 8l3.09 6.26L30 15.27l-5 4.87 1.18 6.88L20 23.77l-6.18 3.25L15 20.14l-5-4.87 6.91-1.01L20 8z"
|
||||
fill="#FFD700"
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
|
||||
case 'cryptobot':
|
||||
return (
|
||||
<svg className={className} viewBox="0 0 40 40">
|
||||
<circle cx="20" cy="20" r="20" fill="#0088CC" />
|
||||
<path
|
||||
d="M20 7c-7.18 0-13 5.82-13 13s5.82 13 13 13 13-5.82 13-13S27.18 7 20 7zm1.5 18.75v2.5h-3v-2.4c-2.1-.3-3.8-1.2-4.6-2.1l1.8-2.4c.9.8 2.1 1.5 3.3 1.5 1.1 0 1.8-.5 1.8-1.3 0-.9-.8-1.3-2.5-1.9-2.3-.8-4.2-1.9-4.2-4.4 0-2.1 1.5-3.7 4.2-4.1v-2.4h3v2.3c1.6.2 2.9.9 3.8 1.7l-1.7 2.3c-.7-.6-1.7-1.1-2.8-1.1-1 0-1.6.4-1.6 1.2 0 .8.8 1.2 2.6 1.9 2.5.9 4.1 2 4.1 4.4 0 2.2-1.6 3.9-4.2 4.2z"
|
||||
fill="#fff"
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
|
||||
case 'yookassa':
|
||||
return (
|
||||
<svg className={className} viewBox="0 0 40 40">
|
||||
<circle cx="20" cy="20" r="20" fill="#0070F0" />
|
||||
<g fill="#fff">
|
||||
<rect x="11" y="11" width="4" height="18" rx="2" />
|
||||
<circle cx="23" cy="20" r="7" fill="none" stroke="#fff" strokeWidth="3.5" />
|
||||
</g>
|
||||
</svg>
|
||||
);
|
||||
|
||||
case 'heleket':
|
||||
return (
|
||||
<svg className={className} viewBox="0 0 40 40">
|
||||
<circle cx="20" cy="20" r="20" fill="#1A1A2E" />
|
||||
<path
|
||||
d="M20 8l2.47 5.01.55 1.12 1.23.18L30 15.27l-4 3.9-.89.87.21 1.22L26.18 27 20.9 24.22l-1.1-.58-1.1.58L13.62 27l.86-5.74.21-1.22-.89-.87-4-3.9 5.75-.96 1.23-.18.55-1.12L20 8z"
|
||||
fill="#00E68A"
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
|
||||
case 'mulenpay':
|
||||
return (
|
||||
<svg className={className} viewBox="0 0 40 40">
|
||||
<circle cx="20" cy="20" r="20" fill="#FF4D4D" />
|
||||
<path
|
||||
d="M10 14h20c1.1 0 2 .9 2 2v8c0 1.1-.9 2-2 2H10c-1.1 0-2-.9-2-2v-8c0-1.1.9-2 2-2zm0 3v6h20v-6H10zm2 2h4v2h-4v-2z"
|
||||
fill="#fff"
|
||||
fillRule="evenodd"
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
|
||||
case 'pal24':
|
||||
return (
|
||||
<svg className={className} viewBox="0 0 40 40">
|
||||
<circle cx="20" cy="20" r="20" fill="#00B341" />
|
||||
<g fill="#fff" fontFamily="Arial,sans-serif" fontWeight="700">
|
||||
<text x="20" y="26" textAnchor="middle" fontSize="16">
|
||||
P24
|
||||
</text>
|
||||
</g>
|
||||
</svg>
|
||||
);
|
||||
|
||||
case 'platega':
|
||||
return (
|
||||
<svg className={className} viewBox="0 0 40 40">
|
||||
<circle cx="20" cy="20" r="20" fill="#6C5CE7" />
|
||||
<path
|
||||
d="M14 12h8c3.31 0 6 2.69 6 6s-2.69 6-6 6h-4v4h-4V12zm4 8h4c1.1 0 2-.9 2-2s-.9-2-2-2h-4v4z"
|
||||
fill="#fff"
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
|
||||
case 'wata':
|
||||
return (
|
||||
<svg className={className} viewBox="0 0 40 40">
|
||||
<circle cx="20" cy="20" r="20" fill="#2D7FF9" />
|
||||
<path
|
||||
d="M20 10c-.55 0-1 .35-1.27.8L12 24c-.4.7.1 1.5.9 1.5h14.2c.8 0 1.3-.8.9-1.5l-6.73-13.2c-.27-.45-.72-.8-1.27-.8z"
|
||||
fill="#fff"
|
||||
opacity=".9"
|
||||
/>
|
||||
<path
|
||||
d="M20 30c3.87 0 7-2.24 7-5 0-2.76-7-10-7-10s-7 7.24-7 10c0 2.76 3.13 5 7 5z"
|
||||
fill="#fff"
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
|
||||
case 'freekassa':
|
||||
return (
|
||||
<svg className={className} viewBox="0 0 40 40">
|
||||
<circle cx="20" cy="20" r="20" fill="#FF6600" />
|
||||
<g fill="#fff" fontFamily="Arial,sans-serif" fontWeight="700">
|
||||
<text x="20" y="26" textAnchor="middle" fontSize="16">
|
||||
FK
|
||||
</text>
|
||||
</g>
|
||||
</svg>
|
||||
);
|
||||
|
||||
case 'cloudpayments':
|
||||
return (
|
||||
<svg className={className} viewBox="0 0 40 40">
|
||||
<circle cx="20" cy="20" r="20" fill="#004EBD" />
|
||||
<path
|
||||
d="M28.5 22c.83 0 1.5.67 1.5 1.5S29.33 25 28.5 25h-17c-1.93 0-3.5-1.57-3.5-3.5 0-1.72 1.24-3.15 2.88-3.45C11.15 15.17 13.86 13 17 13c2.48 0 4.65 1.3 5.89 3.25C23.56 15.48 24.7 15 26 15c2.76 0 5 2.24 5 5 0 .7-.15 1.37-.42 1.97-.02.01-.04.03-.08.03h-2z"
|
||||
fill="#fff"
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
|
||||
case 'tribute':
|
||||
return (
|
||||
<svg className={className} viewBox="0 0 40 40">
|
||||
<circle cx="20" cy="20" r="20" fill="#7B61FF" />
|
||||
<path
|
||||
d="M20 10l2.94 5.96L29 17.02l-4.5 4.39L25.56 28 20 25.14 14.44 28l1.06-6.59L11 17.02l6.06-.96L20 10z"
|
||||
fill="#fff"
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
|
||||
case 'kassa_ai':
|
||||
return (
|
||||
<svg className={className} viewBox="0 0 40 40">
|
||||
<defs>
|
||||
<linearGradient id="kassaAiGrad" x1="0" y1="0" x2="1" y2="1">
|
||||
<stop offset="0%" stopColor="#6366F1" />
|
||||
<stop offset="100%" stopColor="#8B5CF6" />
|
||||
</linearGradient>
|
||||
</defs>
|
||||
<circle cx="20" cy="20" r="20" fill="url(#kassaAiGrad)" />
|
||||
<g fill="#fff" fontFamily="Arial,sans-serif" fontWeight="700">
|
||||
<text x="20" y="26" textAnchor="middle" fontSize="15">
|
||||
AI
|
||||
</text>
|
||||
</g>
|
||||
</svg>
|
||||
);
|
||||
|
||||
default:
|
||||
return (
|
||||
<svg className={className} viewBox="0 0 40 40">
|
||||
<circle cx="20" cy="20" r="20" fill="#4B5563" />
|
||||
<path
|
||||
d="M10 14h20c1.1 0 2 .9 2 2v8c0 1.1-.9 2-2 2H10c-1.1 0-2-.9-2-2v-8c0-1.1.9-2 2-2zm0 3v6h20v-6H10z"
|
||||
fill="#fff"
|
||||
opacity=".7"
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -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 = () => (
|
||||
<svg
|
||||
@@ -19,21 +20,6 @@ const BackIcon = () => (
|
||||
</svg>
|
||||
);
|
||||
|
||||
const METHOD_ICONS: Record<string, string> = {
|
||||
telegram_stars: '⭐',
|
||||
tribute: '🎁',
|
||||
cryptobot: '🪙',
|
||||
heleket: '⚡',
|
||||
yookassa: '🏦',
|
||||
mulenpay: '💳',
|
||||
pal24: '💸',
|
||||
platega: '💰',
|
||||
wata: '💧',
|
||||
freekassa: '💵',
|
||||
cloudpayments: '☁️',
|
||||
kassa_ai: '🏦',
|
||||
};
|
||||
|
||||
const METHOD_LABELS: Record<string, string> = {
|
||||
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 (
|
||||
<div className="space-y-6">
|
||||
@@ -210,8 +195,8 @@ export default function AdminPaymentMethodEdit() {
|
||||
<BackIcon />
|
||||
</button>
|
||||
)}
|
||||
<div className="flex h-10 w-10 items-center justify-center rounded-xl bg-dark-700/50 text-xl">
|
||||
{icon}
|
||||
<div className="flex h-10 w-10 items-center justify-center">
|
||||
<PaymentMethodIcon method={config.method_id} className="h-10 w-10" />
|
||||
</div>
|
||||
<div>
|
||||
<h1 className="text-2xl font-bold text-dark-50">{displayName}</h1>
|
||||
|
||||
@@ -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 = () => (
|
||||
</svg>
|
||||
);
|
||||
|
||||
// ============ Method icon by type ============
|
||||
|
||||
const METHOD_ICONS: Record<string, string> = {
|
||||
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) {
|
||||
</button>
|
||||
|
||||
{/* Method icon */}
|
||||
<div className="flex h-10 w-10 flex-shrink-0 items-center justify-center rounded-xl bg-dark-700/50 text-xl">
|
||||
{icon}
|
||||
<div className="flex h-10 w-10 flex-shrink-0 items-center justify-center">
|
||||
<PaymentMethodIcon method={config.method_id} className="h-10 w-10" />
|
||||
</div>
|
||||
|
||||
{/* Content */}
|
||||
@@ -337,8 +320,8 @@ export default function AdminPaymentMethods() {
|
||||
</DndContext>
|
||||
) : (
|
||||
<div className="py-12 text-center">
|
||||
<div className="mx-auto mb-4 flex h-16 w-16 items-center justify-center rounded-2xl bg-dark-800">
|
||||
<span className="text-3xl">{'\uD83D\uDCB3'}</span>
|
||||
<div className="mx-auto mb-4 flex h-16 w-16 items-center justify-center">
|
||||
<PaymentMethodIcon method="" className="h-12 w-12" />
|
||||
</div>
|
||||
<div className="text-dark-400">{t('admin.paymentMethods.noMethods')}</div>
|
||||
</div>
|
||||
|
||||
@@ -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)}
|
||||
>
|
||||
<div className="font-semibold text-dark-100">
|
||||
{translatedName || method.name}
|
||||
<div className="flex items-center gap-3">
|
||||
<PaymentMethodIcon method={methodKey} className="h-8 w-8 flex-shrink-0" />
|
||||
<div className="font-semibold text-dark-100">
|
||||
{translatedName || method.name}
|
||||
</div>
|
||||
</div>
|
||||
{(translatedDesc || method.description) && (
|
||||
<div className="mt-1 text-sm text-dark-500">
|
||||
|
||||
Reference in New Issue
Block a user