212 lines
7.8 KiB
TypeScript
212 lines
7.8 KiB
TypeScript
import { DataTableColumnHeader } from '@/components/data-table-column-header';
|
|
import { Button } from '@/components/ui/button';
|
|
import { Switch } from '@/components/ui/switch';
|
|
import { Tooltip, TooltipContent, TooltipTrigger } from '@/components/ui/tooltip';
|
|
import { UserInfo } from '@/components/user-info';
|
|
import { usePermission } from '@/hooks/use-permission';
|
|
import userRoutes from '@/routes/user';
|
|
import type { User } from '@/types';
|
|
import { Link } from '@inertiajs/react';
|
|
import type { ColumnDef } from '@tanstack/react-table';
|
|
import { KeyRound, Pencil, Trash2 } from 'lucide-react';
|
|
import { Badge } from '@/components/ui/badge';
|
|
import { formatCurrency, formatDate } from '@/lib/formatters';
|
|
|
|
interface ColumnProps {
|
|
onResetPassword: (user: User) => void;
|
|
onDelete: (user: User) => void;
|
|
onToggleStatus: (user: User) => void;
|
|
}
|
|
|
|
export const getColumns = ({ onResetPassword, onDelete, onToggleStatus }: ColumnProps): ColumnDef<User>[] => [
|
|
{
|
|
accessorKey: "name",
|
|
header: ({ column }) => (
|
|
<DataTableColumnHeader column={column} title="Nama dan Alamat Surel" />
|
|
),
|
|
meta: { title: "Nama dan Alamat Surel" },
|
|
cell: ({ row }) => {
|
|
const user = row.original;
|
|
|
|
return (
|
|
<div className="flex items-center gap-3">
|
|
<UserInfo user={user} showEmail={true} />
|
|
</div>
|
|
);
|
|
}
|
|
},
|
|
{
|
|
accessorKey: "username",
|
|
header: ({ column }) => (
|
|
<DataTableColumnHeader column={column} title="Nama Pengguna" />
|
|
),
|
|
meta: { title: "Nama Pengguna" },
|
|
},
|
|
{
|
|
accessorFn: (row) => row.roles?.map(role => role.name).join(', '),
|
|
id: "roles",
|
|
header: ({ column }) => (
|
|
<DataTableColumnHeader column={column} title="Peran" />
|
|
),
|
|
meta: { title: "Peran" },
|
|
cell: ({ row }) => {
|
|
const roles = row.original.roles;
|
|
return (
|
|
<div className="flex flex-wrap gap-1">
|
|
{roles?.map((role) => (
|
|
<Badge key={role.id} variant="outline" className="capitalize">
|
|
{role.name}
|
|
</Badge>
|
|
))}
|
|
</div>
|
|
);
|
|
}
|
|
},
|
|
{
|
|
accessorFn: (row) => row.profile?.nik,
|
|
id: "nik",
|
|
header: ({ column }) => (
|
|
<DataTableColumnHeader column={column} title="NIK" />
|
|
),
|
|
meta: { title: "NIK" },
|
|
},
|
|
{
|
|
accessorFn: (row) => row.profile?.full_name,
|
|
id: "full_name",
|
|
header: ({ column }) => (
|
|
<DataTableColumnHeader column={column} title="Nama Lengkap" />
|
|
),
|
|
meta: { title: "Nama Lengkap" },
|
|
},
|
|
{
|
|
accessorFn: (row) => row.profile?.phone_number,
|
|
id: "phone_number",
|
|
header: ({ column }) => (
|
|
<DataTableColumnHeader column={column} title="Nomor Telepon" />
|
|
),
|
|
meta: { title: "Nomor Telepon" },
|
|
},
|
|
{
|
|
accessorFn: (row) => row.profile?.address,
|
|
id: "address",
|
|
header: ({ column }) => (
|
|
<DataTableColumnHeader column={column} title="Alamat" />
|
|
),
|
|
meta: { title: "Alamat" },
|
|
cell: ({ row }) => (
|
|
<div className="max-w-[200px] truncate" title={row.original.profile?.address}>
|
|
{row.original.profile?.address || '-'}
|
|
</div>
|
|
)
|
|
},
|
|
{
|
|
accessorFn: (row) => `${row.profile?.birth_place}, ${row.profile?.birth_date}`,
|
|
id: "birth_info",
|
|
header: ({ column }) => (
|
|
<DataTableColumnHeader column={column} title="Tempat, Tgl Lahir" />
|
|
),
|
|
meta: { title: "Tempat, Tgl Lahir" },
|
|
cell: ({ row }) => {
|
|
const profile = row.original.profile;
|
|
if (!profile?.birth_place && !profile?.birth_date) return '-';
|
|
return (
|
|
<span>
|
|
{profile.birth_place || '-'}, {formatDate(profile.birth_date)}
|
|
</span>
|
|
);
|
|
}
|
|
},
|
|
{
|
|
accessorFn: (row) => row.profile?.base_salary,
|
|
id: "base_salary",
|
|
header: ({ column }) => (
|
|
<DataTableColumnHeader column={column} title="Gaji Pokok" />
|
|
),
|
|
meta: { title: "Gaji Pokok" },
|
|
cell: ({ row }) => formatCurrency(row.original.profile?.base_salary || 0)
|
|
},
|
|
{
|
|
accessorKey: "is_active",
|
|
header: "Status",
|
|
meta: { title: "Status" },
|
|
cell: ({ row }) => {
|
|
const user = row.original;
|
|
const { hasPermission } = usePermission();
|
|
|
|
return (
|
|
<Switch
|
|
checked={user.is_active}
|
|
onCheckedChange={() => onToggleStatus(user)}
|
|
disabled={!hasPermission('ToggleStatus:User')}
|
|
/>
|
|
);
|
|
}
|
|
},
|
|
{
|
|
id: "actions",
|
|
header: "Aksi",
|
|
cell: ({ row }) => {
|
|
const user = row.original;
|
|
const { hasPermission } = usePermission();
|
|
|
|
return (
|
|
<div className="flex items-center gap-2">
|
|
{hasPermission('ResetPassword:User') && (
|
|
<Tooltip>
|
|
<TooltipTrigger asChild>
|
|
<Button
|
|
variant="ghost"
|
|
size="icon"
|
|
className='text-blue-600 hover:text-blue-700 hover:bg-blue-50 dark:hover:bg-blue-950/20'
|
|
onClick={() => onResetPassword(user)}
|
|
>
|
|
<KeyRound className="size-4" />
|
|
</Button>
|
|
</TooltipTrigger>
|
|
<TooltipContent>
|
|
<p>Reset Kata Sandi</p>
|
|
</TooltipContent>
|
|
</Tooltip>
|
|
)}
|
|
{hasPermission('Edit:User') && (
|
|
<Tooltip>
|
|
<TooltipTrigger asChild>
|
|
<Link href={userRoutes.edit(user.id).url}>
|
|
<Button
|
|
variant="ghost"
|
|
size="icon"
|
|
className='text-yellow-600 hover:text-yellow-700 hover:bg-yellow-50 dark:hover:bg-yellow-950/20'
|
|
>
|
|
<Pencil className="size-4" />
|
|
</Button>
|
|
</Link>
|
|
</TooltipTrigger>
|
|
<TooltipContent>
|
|
<p>Ubah</p>
|
|
</TooltipContent>
|
|
</Tooltip>
|
|
)}
|
|
{hasPermission('Delete:User') && (
|
|
<Tooltip>
|
|
<TooltipTrigger asChild>
|
|
<Button
|
|
variant="ghost"
|
|
size="icon"
|
|
className='text-red-600 hover:text-red-700 hover:bg-red-50 dark:hover:bg-red-950/20'
|
|
onClick={() => onDelete(user)}
|
|
>
|
|
<Trash2 className="size-4" />
|
|
</Button>
|
|
</TooltipTrigger>
|
|
<TooltipContent>
|
|
<p>Hapus</p>
|
|
</TooltipContent>
|
|
</Tooltip>
|
|
)}
|
|
</div>
|
|
);
|
|
},
|
|
meta: { title: "Aksi" },
|
|
},
|
|
];
|