import { useState } from 'react' import { createFileRoute } from '@tanstack/react-router' import { useQuery } from '@tanstack/react-query' import { useTranslation } from 'react-i18next' import { Input } from '@/shared/ui/input' import { Button } from '@/shared/ui/button' import { Badge } from '@/shared/ui/badge' import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/shared/ui/select' import { PaidUntilBadge } from '@/features/billing/PaidUntilBadge' import { listUsers } from '@/features/admin/users/api' import { listRoles } from '@/features/admin/roles/api' import { UserManageDialog } from '@/features/admin/users/UserManageDialog' export const Route = createFileRoute('/admin/users')({ component: AdminUsersPage }) const PAGE_SIZE = 20 type StatusFilter = 'all' | 'active' | 'pending' | 'blocked' type BillingFilter = 'all' | 'expired' | 'paid' function AdminUsersPage() { const { t } = useTranslation() const [search, setSearch] = useState('') const [roleId, setRoleId] = useState('all') const [status, setStatus] = useState('all') const [billing, setBilling] = useState('all') const [page, setPage] = useState(1) // Id, не сам объект — иначе диалог держит "замороженный" снимок пользователя и не видит // изменения, сделанные им же самим (гифт/блок/смена роли инвалидируют этот запрос, но проп // диалога от этого не обновится, если хранить готовый объект). Ищем свежую версию в live-данных // запроса на каждый рендер. const [managingId, setManagingId] = useState(null) const rolesQuery = useQuery({ queryKey: ['admin-roles'], queryFn: listRoles }) const roleFilter = roleId === 'all' ? undefined : roleId const isActivated = status === 'active' ? true : status === 'pending' ? false : undefined const isBlocked = status === 'blocked' ? true : status === 'all' ? undefined : false const billingExpired = billing === 'all' ? undefined : billing === 'expired' const { data, isLoading, isError, refetch } = useQuery({ queryKey: ['admin-users', page, search, roleFilter, isActivated, isBlocked, billingExpired], queryFn: () => listUsers(page, PAGE_SIZE, search || undefined, roleFilter, isActivated, isBlocked, billingExpired), }) const managingUser = managingId ? (data?.items.find((u) => u.id === managingId) ?? null) : null return (
{ setSearch(e.target.value) setPage(1) }} className="max-w-sm" />
{isLoading &&

} {isError && (

{t('auth.genericError')}

)} {data && ( <>
{data.items.map((user) => ( ))}
{t('admin.users.userName')} {t('admin.users.role')} {t('admin.users.statusLabel')} {t('admin.users.configQuota')} {t('admin.users.billingLabel')}
{user.userName} {user.role} {user.isBlocked ? t('admin.users.status.blocked') : user.isActivated ? t('admin.users.status.active') : t('admin.users.status.pending')} {user.configQuota === -1 ? '∞' : user.configQuota} {user.configQuota === -1 ? t('admin.users.unlimitedQuota') : (user.planName ?? t('admin.users.customQuota'))} {user.billingEnabled ? ( ) : ( )}
{data.items.length === 0 &&

{t('admin.users.empty')}

}
{t('admin.users.total', { count: data.total })}
)} {managingUser && ( !open && setManagingId(null)} /> )}
) }