124 lines
3.6 KiB
TypeScript
124 lines
3.6 KiB
TypeScript
'use client';
|
|
|
|
import { useMemo } from 'react';
|
|
import type { ColumnDef } from '@tanstack/react-table';
|
|
import { Edit, RotateCcw } from 'lucide-react';
|
|
|
|
import { Badge } from '@/components/ui/badge';
|
|
import { Button } from '@/components/ui/button';
|
|
import { PERMISSIONS } from '@/constants/permissions';
|
|
import { usePermissions } from '@/hooks/usePermissions';
|
|
import type { AdministrationUser } from '@/types';
|
|
|
|
function formatDate(value?: string | null) {
|
|
if (!value) return '-';
|
|
return new Intl.DateTimeFormat('en-IN', {
|
|
day: '2-digit',
|
|
month: 'short',
|
|
year: 'numeric',
|
|
}).format(new Date(value));
|
|
}
|
|
|
|
interface UseUserColumnsParams {
|
|
onEdit: (user: AdministrationUser) => void;
|
|
onToggleStatus: (user: AdministrationUser) => void;
|
|
pendingUserId?: number;
|
|
}
|
|
|
|
export function useUserColumns({
|
|
onEdit,
|
|
onToggleStatus,
|
|
pendingUserId,
|
|
}: UseUserColumnsParams): ColumnDef<AdministrationUser>[] {
|
|
const { hasPermission } = usePermissions();
|
|
const canEdit = hasPermission(PERMISSIONS.USER.UPDATE);
|
|
const canDelete = hasPermission(PERMISSIONS.USER.DELETE);
|
|
|
|
return useMemo(() => {
|
|
const columns: ColumnDef<AdministrationUser>[] = [
|
|
{
|
|
accessorKey: 'first_name',
|
|
header: 'Name',
|
|
cell: ({ row }) => (
|
|
<span className="font-medium">
|
|
{[row.original.first_name, row.original.last_name].filter(Boolean).join(' ') ||
|
|
row.original.username}
|
|
</span>
|
|
),
|
|
},
|
|
{
|
|
accessorKey: 'email',
|
|
header: 'Email',
|
|
},
|
|
{
|
|
accessorKey: 'phone_number',
|
|
header: 'Phone',
|
|
cell: ({ row }) => row.original.phone_number || '-',
|
|
},
|
|
{
|
|
accessorKey: 'roles',
|
|
header: 'Roles',
|
|
cell: ({ row }) => (
|
|
<div className="flex flex-wrap gap-1">
|
|
{row.original.roles?.length ? (
|
|
row.original.roles.map((role) => (
|
|
<Badge key={role.id ?? role.name} variant="outline">
|
|
{role.display_name || role.name}
|
|
</Badge>
|
|
))
|
|
) : (
|
|
<span className="text-muted-foreground">-</span>
|
|
)}
|
|
</div>
|
|
),
|
|
},
|
|
{
|
|
accessorKey: 'created_at',
|
|
header: 'Created',
|
|
cell: ({ row }) => formatDate(row.original.created_at),
|
|
},
|
|
{
|
|
accessorKey: 'effective_status',
|
|
header: 'Status',
|
|
cell: ({ row }) => (
|
|
<Badge variant={row.original.effective_status === 'active' ? 'default' : 'secondary'}>
|
|
{row.original.effective_status}
|
|
</Badge>
|
|
),
|
|
},
|
|
];
|
|
|
|
if (!canEdit && !canDelete) return columns;
|
|
|
|
columns.push({
|
|
id: 'actions',
|
|
header: () => <div className="text-right">Actions</div>,
|
|
cell: ({ row }) => {
|
|
const user = row.original;
|
|
return (
|
|
<div className="flex justify-end gap-2">
|
|
{canEdit ? (
|
|
<Button variant="outline" size="sm" onClick={() => onEdit(user)}>
|
|
<Edit className="size-4" />
|
|
</Button>
|
|
) : null}
|
|
{canDelete ? (
|
|
<Button
|
|
variant="outline"
|
|
size="sm"
|
|
disabled={pendingUserId === user.id || user.effective_status === 'pending'}
|
|
onClick={() => onToggleStatus(user)}
|
|
>
|
|
<RotateCcw className="mr-2 size-4" />
|
|
{user.effective_status === 'active' ? 'Deactivate' : 'Activate'}
|
|
</Button>
|
|
) : null}
|
|
</div>
|
|
);
|
|
},
|
|
});
|
|
|
|
return columns;
|
|
}, [canDelete, canEdit, onEdit, onToggleStatus, pendingUserId]);
|
|
}
|