/* Copyright (C) 2023-2026 QuantumNous This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . For commercial licensing, please contact support@quantumnous.com */ import type { ColumnDef } from '@tanstack/react-table' import { useTranslation } from 'react-i18next' import { BadgeCell } from '@/components/data-table' import { GroupBadge } from '@/components/group-badge' import { LongText } from '@/components/long-text' import { StatusBadge } from '@/components/status-badge' import { TableId } from '@/components/table-id' import { Checkbox } from '@/components/ui/checkbox' import { Tooltip, TooltipContent, TooltipTrigger, } from '@/components/ui/tooltip' import { formatQuota, formatTimestamp } from '@/lib/format' import { USER_STATUS, USER_STATUSES, USER_ROLES, isUserDeleted, } from '../constants' import type { User } from '../types' import { DataTableRowActions } from './data-table-row-actions' import { UserQuotaCell } from './user-quota-cell' export function useUsersColumns(): ColumnDef[] { const { t } = useTranslation() return [ { id: 'select', header: ({ table }) => ( table.toggleAllPageRowsSelected(!!value)} aria-label='Select all' className='translate-y-[2px]' /> ), cell: ({ row }) => ( row.toggleSelected(!!value)} aria-label='Select row' className='translate-y-[2px]' /> ), enableSorting: false, enableHiding: false, size: 40, }, { accessorKey: 'id', header: t('ID'), cell: ({ row }) => { return ( ) }, size: 80, meta: { mobileOrder: 10 }, }, { accessorKey: 'username', header: t('Username'), cell: ({ row }) => { const username = row.getValue('username') as string const displayName = row.original.display_name const remark = row.original.remark return (
{username} {remark && ( } > {remark}

{remark}

)}
{displayName && displayName !== username && ( {displayName} )}
) }, enableHiding: false, size: 220, meta: { mobileTitle: true }, }, { accessorKey: 'status', header: t('Status'), cell: ({ row }) => { const user = row.original const requestCount = user.request_count const statusConfig = isUserDeleted(user) ? USER_STATUSES[USER_STATUS.DELETED] : USER_STATUSES[user.status as keyof typeof USER_STATUSES] if (!statusConfig) { return null } return ( }>

{t('Requests:')} {requestCount.toLocaleString()}

) }, filterFn: (row, id, value) => { return value.includes(String(row.getValue(id))) }, enableSorting: false, size: 120, meta: { mobileBadge: true }, }, { id: 'quota', accessorKey: 'quota', header: t('Quota'), cell: ({ row }) => { const user = row.original return }, size: 300, minSize: 260, meta: { mobileOrder: 40 }, }, { accessorKey: 'group', header: t('Group'), cell: ({ row }) => { const group = row.getValue('group') as string return ( ) }, filterFn: (row, id, value) => { const group = String(row.getValue(id) || t('User Group')).toLowerCase() const searchValue = String(value).toLowerCase() return group.includes(searchValue) }, size: 140, meta: { mobileOrder: 30 }, }, { accessorKey: 'role', header: t('Role'), cell: ({ row }) => { const roleValue = row.getValue('role') as number const roleConfig = USER_ROLES[roleValue as keyof typeof USER_ROLES] if (!roleConfig) { return null } return (
{roleConfig.icon && ( )} {t(roleConfig.labelKey)}
) }, filterFn: (row, id, value) => { return value.includes(String(row.getValue(id))) }, enableSorting: false, size: 120, meta: { mobileOrder: 20 }, }, { id: 'invite_info', header: t('Invite Info'), cell: ({ row }) => { const user = row.original const affCount = user.aff_count || 0 const affHistoryQuota = user.aff_history_quota || 0 const inviterId = user.inviter_id || 0 return (
} />

{t('Number of users invited')}

} />

{t('Total invitation revenue')}

{inviterId > 0 && ( } />

{t('Invited by user ID')} {inviterId}

)} {inviterId === 0 && ( )}
) }, size: 240, enableSorting: false, meta: { mobileHidden: true }, }, { accessorKey: 'created_at', header: t('Created At'), cell: ({ row }) => { const ts = row.getValue('created_at') as number | undefined return ( {ts ? formatTimestamp(ts) : '-'} ) }, size: 180, meta: { mobileHidden: true }, }, { accessorKey: 'last_login_at', header: t('Last Login'), cell: ({ row }) => { const ts = row.getValue('last_login_at') as number | undefined return ( {ts ? formatTimestamp(ts) : '-'} ) }, size: 180, meta: { mobileHidden: true }, }, { id: 'actions', header: () => t('Actions'), cell: ({ row }) => , meta: { pinned: 'right' as const }, }, ] }