itmpwk.ac.id/resources/js/pages/admin/services/letter-requests/columns.tsx

197 lines
6.9 KiB
TypeScript

import type { ColumnDef } from '@tanstack/react-table';
import { format } from 'date-fns';
import { Pencil, Trash2, Upload } from 'lucide-react';
import { AttachmentPreviewDialog } from '@/components/attachment-preview-dialog';
import { RowActions } from '@/components/row-actions';
import { StatusBadge } from '@/components/status-badge';
import type { LetterRequest } from '@/types/letter-request';
import { LetterStatuses, LetterStatusLabels } from '@/types/letter-request';
export type { LetterRequest } from '@/types/letter-request';
const LetterStatusVariants: Record<
string,
'default' | 'secondary' | 'destructive' | 'outline'
> = {
submitted: 'outline',
in_process: 'secondary',
completed: 'default',
rejected: 'destructive',
};
const letterStatusOptions = LetterStatuses.map((status) => ({
value: status,
label: LetterStatusLabels[status],
}));
type CreateColumnsParams = {
handleEdit: (letterRequest: LetterRequest) => void;
handleDeleteClick: (letterRequest: LetterRequest) => void;
handleStatusChange: (letterRequest: LetterRequest, status: string) => void;
handleUploadClick: (letterRequest: LetterRequest) => void;
canUpdate: boolean;
canDelete: boolean;
canProcess: boolean;
};
export function createLetterRequestColumns(
params: CreateColumnsParams,
): ColumnDef<LetterRequest>[] {
const {
handleEdit,
handleDeleteClick,
handleStatusChange,
handleUploadClick,
canUpdate,
canDelete,
canProcess,
} = params;
const columns: ColumnDef<LetterRequest>[] = [
{
id: 'requester',
header: () => <span>Pemohon</span>,
cell: ({ row }) => {
const user = row.original.user;
const identifier = user?.student
? `${user.student.student_number} · ${user.student.department?.name ?? '-'}`
: user?.lecturer
? `${user.lecturer.lecturer_number} · ${user.lecturer.departments.map((d) => d.name).join(', ') || '-'}`
: '-';
return (
<div>
<p className="font-medium">
{user?.profile?.full_name ?? 'N/A'}
</p>
<p className="text-xs text-muted-foreground">
{identifier}
</p>
</div>
);
},
},
{
accessorKey: 'letter_type',
header: () => <span>Jenis Surat</span>,
cell: ({ row }) => {
const letterRequest = row.original;
return (
<div>
<p className="font-medium">
{letterRequest.letter_type}
</p>
{letterRequest.purpose && (
<p className="line-clamp-1 max-w-xs text-xs text-muted-foreground">
{letterRequest.purpose}
</p>
)}
</div>
);
},
},
{
accessorKey: 'status',
header: () => <span className="block text-center">Status</span>,
meta: {
className: 'w-[120px] text-center',
headerClassName: 'w-[120px] text-center',
},
cell: ({ row }) => (
<div className="flex justify-center">
<StatusBadge
status={row.original.status}
statuses={letterStatusOptions}
variants={LetterStatusVariants}
onChange={(status) =>
handleStatusChange(row.original, status)
}
disabled={!canProcess}
/>
</div>
),
},
{
accessorKey: 'processor.profile.full_name',
header: () => <span>Diproses Oleh</span>,
cell: ({ row }) =>
row.original.processor?.profile?.full_name ?? '-',
},
{
accessorKey: 'submitted_at',
header: () => <span>Diajukan</span>,
cell: ({ row }) => {
const submittedAt = row.original.submitted_at;
return submittedAt
? format(new Date(submittedAt), 'd MMM yyyy, HH:mm')
: '-';
},
},
{
accessorKey: 'result_name',
header: () => <span>Dokumen</span>,
cell: ({ row }) => {
const letterRequest = row.original;
if (!letterRequest.result_url || !letterRequest.result_name) {
return <span className="text-muted-foreground">-</span>;
}
return (
<AttachmentPreviewDialog
fileUrl={letterRequest.result_url}
fileName={letterRequest.result_name}
/>
);
},
},
];
if (canUpdate || canDelete || canProcess) {
columns.push({
id: 'actions',
header: () => <span className="block text-center">Aksi</span>,
meta: {
className: 'w-[100px] text-center',
headerClassName: 'w-[100px] text-center',
},
cell: ({ row }) => {
const isLocked = row.original.status !== 'submitted';
return (
<RowActions
actions={[
{
label: 'Upload File',
icon: <Upload className="h-4 w-4" />,
show:
canProcess &&
row.original.status === 'in_process',
onClick: () => handleUploadClick(row.original),
},
{
label: 'Edit',
icon: <Pencil className="h-4 w-4" />,
show: canUpdate && !isLocked,
onClick: () => handleEdit(row.original),
},
{
label: 'Hapus',
icon: (
<Trash2 className="h-4 w-4 text-destructive" />
),
show: canDelete && !isLocked,
onClick: () => handleDeleteClick(row.original),
},
]}
/>
);
},
});
}
return columns;
}