Files
road-monitoring-ui/src/app/(modules)/users/components/UserColumns.tsx

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]);
}