core/app/pages/admin/users/columns.ts

126 lines
4.0 KiB
TypeScript

import type { ColumnDef, FilterFn } from '@tanstack/vue-table'
import { ArrowUpDown, Pencil, Trash2 } from '@lucide/vue'
import { h } from 'vue'
import { Badge } from '@/components/ui/badge'
import { Button } from '@/components/ui/button'
import {
Tooltip,
TooltipContent,
TooltipProvider,
TooltipTrigger,
} from '@/components/ui/tooltip'
export interface User {
id: string
email: string
username: string
status: string
profile: {
full_name: string
phone: string | null
address: string | null
pob: string | null
dob: string | null
} | null
created_at: string
}
const statusConfig: Record<string, { label: string, class: string }> = {
ACTIVE: { label: 'Aktif', class: 'border-emerald-500 text-emerald-600 bg-emerald-50' },
ONBOARDING: { label: 'Onboarding', class: 'border-blue-500 text-blue-600 bg-blue-50' },
INACTIVE: { label: 'Nonaktif', class: 'border-gray-500 text-gray-600 bg-gray-50' },
SUSPENDED: { label: 'Ditangguhkan', class: 'border-orange-500 text-orange-600 bg-orange-50' },
DISABLED: { label: 'Dinonaktifkan', class: 'border-red-500 text-red-600 bg-red-50' },
}
const searchFilter: FilterFn<User> = (row, _columnId, filterValue) => {
const search = (filterValue as string).toLowerCase()
const email = (row.original.email as string).toLowerCase()
const username = (row.original.username as string).toLowerCase()
const name = (row.original.profile?.full_name ?? '').toLowerCase()
return email.includes(search) || username.includes(search) || name.includes(search)
}
export function getColumns(callbacks: {
onEdit: (user: User) => void
onDelete: (user: User) => void
}): ColumnDef<User>[] {
return [
{
id: 'search',
accessorFn: row => row.email,
header: 'Akun',
cell: ({ row }) => h('div', { class: 'flex flex-col' }, [
h('span', { class: 'font-medium' }, row.original.email),
h('span', { class: 'text-xs text-muted-foreground' }, `@${row.original.username}`),
]),
filterFn: searchFilter,
enableHiding: false,
},
{
accessorFn: row => row.profile?.full_name ?? '-',
id: 'full_name',
header: 'Nama Lengkap',
cell: ({ row }) => h('div', { class: 'text-muted-foreground' }, row.original.profile?.full_name ?? '-'),
},
{
accessorFn: row => row.profile?.phone ?? '-',
id: 'phone',
header: 'No. Telepon',
cell: ({ row }) => h('div', { class: 'text-muted-foreground' }, row.original.profile?.phone ?? '-'),
},
{
accessorKey: 'status',
header: 'Status',
cell: ({ row }) => {
const cfg = statusConfig[row.original.status] ?? { label: row.original.status, class: '' }
return h(Badge, {
variant: 'outline',
class: cfg.class,
}, () => cfg.label)
},
},
{
id: 'actions',
header: ' ',
size: 0,
minSize: 0,
enableHiding: false,
cell: ({ row }) => {
const user = row.original
return h(TooltipProvider, null, () =>
h('div', { class: 'flex items-center gap-1' }, [
h(Tooltip, null, () => [
h(TooltipTrigger, { asChild: true }, () =>
h(Button, {
variant: 'ghost',
size: 'icon',
class: 'h-8 w-8 text-yellow-500',
onClick: () => callbacks.onEdit(user),
}, () =>
h(Pencil, { class: 'h-4 w-4' })
)
),
h(TooltipContent, null, () => 'Edit'),
]),
h(Tooltip, null, () => [
h(TooltipTrigger, { asChild: true }, () =>
h(Button, {
variant: 'ghost',
size: 'icon',
class: 'h-8 w-8 text-destructive',
onClick: () => callbacks.onDelete(user),
}, () =>
h(Trash2, { class: 'h-4 w-4' })
)
),
h(TooltipContent, null, () => 'Hapus'),
]),
])
)
},
},
]
}