users-columns.tsx 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180
  1. import { useMemo } from 'react'
  2. import { type ColumnDef } from '@tanstack/react-table'
  3. import { type User } from '@/types/users.types'
  4. import { cn } from '@/lib/utils'
  5. import { PERMISSIONS } from '@/constants/permissions'
  6. import { useCan } from '@/hooks/use-can'
  7. import { Badge } from '@/components/ui/badge'
  8. import { Checkbox } from '@/components/ui/checkbox'
  9. import { DataTableColumnHeader } from '@/components/data-table'
  10. import { LongText } from '@/components/long-text'
  11. import { DataTableRowActions } from './data-table-row-actions'
  12. import { UserSubscriptionCell } from './user-subscription-cell'
  13. const usersColumns: ColumnDef<User>[] = [
  14. {
  15. id: 'select',
  16. header: ({ table }) => (
  17. <Checkbox
  18. checked={
  19. table.getIsAllPageRowsSelected() ||
  20. (table.getIsSomePageRowsSelected() && 'indeterminate')
  21. }
  22. onCheckedChange={(value) => table.toggleAllPageRowsSelected(!!value)}
  23. aria-label='Select all'
  24. className='translate-y-0.5'
  25. />
  26. ),
  27. cell: ({ row }) => (
  28. <Checkbox
  29. checked={row.getIsSelected()}
  30. onCheckedChange={(value) => row.toggleSelected(!!value)}
  31. aria-label='Select row'
  32. className='translate-y-0.5'
  33. />
  34. ),
  35. enableSorting: false,
  36. enableHiding: false,
  37. meta: {
  38. className: cn('inset-s-0 z-10 rounded-tl-[inherit] max-md:sticky'),
  39. },
  40. },
  41. {
  42. accessorKey: 'id',
  43. header: ({ column }) => (
  44. <DataTableColumnHeader column={column} title='شناسه' />
  45. ),
  46. cell: ({ row }) => <div className='w-15'>#{row.original.id}</div>,
  47. enableSorting: true,
  48. },
  49. {
  50. accessorKey: 'username',
  51. header: ({ column }) => (
  52. <DataTableColumnHeader column={column} title='نام کاربری' />
  53. ),
  54. cell: ({ row }) => (
  55. <LongText className='max-w-36 ps-3'>{row.original.username}</LongText>
  56. ),
  57. enableHiding: false,
  58. meta: {
  59. className: cn(
  60. 'drop-shadow-[0_1px_2px_rgb(0_0_0_/_0.1)]',
  61. 'dark:drop-shadow-[0_1px_2px_rgb(255_255_255_/_0.1)]',
  62. 'inset-s-6 ps-0.5 max-md:sticky',
  63. '@4xl/content:table-cell',
  64. '@4xl/content:drop-shadow-none'
  65. ),
  66. },
  67. },
  68. {
  69. accessorKey: 'full_name',
  70. header: ({ column }) => (
  71. <DataTableColumnHeader column={column} title='نام کامل' />
  72. ),
  73. cell: ({ row }) => (
  74. <LongText className='max-w-40'>{row.original.full_name}</LongText>
  75. ),
  76. },
  77. {
  78. accessorKey: 'phone',
  79. header: ({ column }) => (
  80. <DataTableColumnHeader column={column} title='شماره موبایل' />
  81. ),
  82. cell: ({ row }) => <div>{row.original.phone}</div>,
  83. },
  84. // {
  85. // accessorKey: 'email',
  86. // header: ({ column }) => (
  87. // <DataTableColumnHeader column={column} title='ایمیل' />
  88. // ),
  89. // cell: ({ row }) => (
  90. // <div className='text-nowrap'>{row.original.email ?? '-'}</div>
  91. // ),
  92. // },
  93. {
  94. accessorKey: 'subscription',
  95. header: ({ column }) => (
  96. <DataTableColumnHeader column={column} title='اشتراک' />
  97. ),
  98. cell: ({ row }) => (
  99. <UserSubscriptionCell
  100. subscription={row.original.subscription}
  101. subscriptions={row.original.subscriptions}
  102. />
  103. ),
  104. },
  105. {
  106. accessorKey: 'followers_count',
  107. header: ({ column }) => (
  108. <DataTableColumnHeader column={column} title='دنبال‌کننده' />
  109. ),
  110. cell: ({ row }) => (
  111. <Badge variant='secondary'>{row.original.followers_count}</Badge>
  112. ),
  113. },
  114. {
  115. accessorKey: 'created_at',
  116. header: ({ column }) => (
  117. <DataTableColumnHeader column={column} title='تاریخ عضویت' />
  118. ),
  119. cell: ({ row }) => {
  120. return (
  121. <div className='text-sm text-muted-foreground'>
  122. {new Date(row.original.created_at).toLocaleDateString('fa-IR')}
  123. </div>
  124. )
  125. },
  126. },
  127. {
  128. id: 'subscription_type',
  129. accessorFn: (row) => row.subscription?.plan?.type ?? 'free',
  130. header: () => null,
  131. cell: () => null,
  132. filterFn: (row, columnId, filterValue: string) => {
  133. if (!filterValue) return true
  134. return row.getValue(columnId) === filterValue
  135. },
  136. },
  137. {
  138. id: 'actions',
  139. cell: DataTableRowActions,
  140. enableSorting: false,
  141. enableHiding: false,
  142. },
  143. ]
  144. function columnKey(column: ColumnDef<User>) {
  145. if ('accessorKey' in column && typeof column.accessorKey === 'string') {
  146. return column.accessorKey
  147. }
  148. return column.id
  149. }
  150. export function useUsersColumns() {
  151. const { can } = useCan()
  152. return useMemo(() => {
  153. return usersColumns.filter((column) => {
  154. const key = columnKey(column)
  155. if (key === 'phone') return can(PERMISSIONS.users.fields.phone.view)
  156. if (key === 'subscription' || key === 'subscription_type') {
  157. return can(PERMISSIONS.users.fields.subscription.view)
  158. }
  159. return true
  160. })
  161. }, [can])
  162. }