126 lines
4.0 KiB
TypeScript
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'),
|
|
]),
|
|
])
|
|
)
|
|
},
|
|
},
|
|
]
|
|
}
|