import { useState } from 'react'; import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query'; import { useTranslation } from 'react-i18next'; import { Link } from 'react-router-dom'; import { adminPaymentsApi } from '../api/adminPayments'; import { useCurrency } from '../hooks/useCurrency'; import type { PendingPayment, PaginatedResponse } from '../types'; export default function AdminPayments() { const { t } = useTranslation(); const queryClient = useQueryClient(); const { formatAmount, currencySymbol } = useCurrency(); const [page, setPage] = useState(1); const [methodFilter, setMethodFilter] = useState(''); const [checkingPaymentId, setCheckingPaymentId] = useState(null); // Fetch payments const { data: payments, isLoading, refetch, } = useQuery>({ queryKey: ['admin-payments', page, methodFilter], queryFn: () => adminPaymentsApi.getPendingPayments({ page, per_page: 20, method_filter: methodFilter || undefined, }), refetchInterval: 30000, // Auto-refresh every 30 seconds }); // Fetch stats const { data: stats } = useQuery({ queryKey: ['admin-payments-stats'], queryFn: adminPaymentsApi.getStats, refetchInterval: 30000, }); // Check payment mutation const checkPaymentMutation = useMutation({ mutationFn: ({ method, paymentId }: { method: string; paymentId: number }) => adminPaymentsApi.checkPaymentStatus(method, paymentId), onSuccess: async (result) => { if (result.status_changed) { await refetch(); queryClient.invalidateQueries({ queryKey: ['admin-payments-stats'] }); } else { await refetch(); } }, onSettled: () => { setCheckingPaymentId(null); }, }); const handleCheckPayment = (payment: PendingPayment) => { setCheckingPaymentId(`${payment.method}_${payment.id}`); checkPaymentMutation.mutate({ method: payment.method, paymentId: payment.id }); }; // Get unique methods from stats for filter const methodOptions = stats?.by_method ? Object.keys(stats.by_method) : []; return (
{/* Header */}

{t('admin.payments.title')}

{t('admin.payments.description')}

{/* Stats cards */} {stats && (
{stats.total_pending}
{t('admin.payments.totalPending')}
{Object.entries(stats.by_method).map(([method, count]) => (
setMethodFilter(methodFilter === method ? '' : method)} >
{count}
{method}
))}
)} {/* Filter */} {methodOptions.length > 0 && (
{t('admin.payments.filterByMethod')}: {methodOptions.map((method) => ( ))}
)} {/* Payments list */}
{isLoading ? (
) : payments?.items && payments.items.length > 0 ? (
{payments.items.map((payment) => { const paymentKey = `${payment.method}_${payment.id}`; const isChecking = checkingPaymentId === paymentKey; return (
{payment.method_display} {payment.status_emoji} {payment.status_text} {payment.is_paid && ( {t('admin.payments.paid')} )}
{formatAmount(payment.amount_rubles)} {currencySymbol}
ID: {payment.identifier}
{new Date(payment.created_at).toLocaleString()}
{/* User info */} {(payment.user_username || payment.user_telegram_id) && (
{t('admin.payments.user')}:{' '} {payment.user_username ? ( @{payment.user_username} ) : ( ID: {payment.user_telegram_id} )}
)}
{payment.payment_url && ( {t('admin.payments.openLink')} )} {payment.is_checkable && ( )}
{/* Show result after check */} {checkPaymentMutation.isSuccess && checkPaymentMutation.variables?.paymentId === payment.id && (
{checkPaymentMutation.data?.message}
)}
); })}
) : (
{t('admin.payments.noPayments')}
)} {/* Pagination */} {payments && payments.pages > 1 && (
{t('balance.page', '{current} / {total}', { current: payments.page, total: payments.pages, })}
)}
); }