siakad-itm/resources/js/pages/admin/feedback/columns.tsx
Yoga Pangestu e7664de711
Some checks failed
tests / ci (pull_request) Has been cancelled
feat: implement feedback management system with controller, service, and frontend components
2026-08-25 19:37:00 +07:00

123 lines
3.9 KiB
TypeScript

import type { ColumnDef } from '@tanstack/react-table';
import { format } from 'date-fns';
import { Pencil, Trash2 } from 'lucide-react';
import { RowActions } from '@/components/row-actions';
import { Badge } from '@/components/ui/badge';
import type { Feedback, FeedbackStatusValue } from '@/types/feedback';
import { FeedbackStatusLabels, FeedbackTypeLabels } from '@/types/feedback';
export type { Feedback } from '@/types/feedback';
type CreateColumnsParams = {
handleEdit: (feedback: Feedback) => void;
handleDeleteClick: (feedback: Feedback) => void;
};
function stripHtml(html: string): string {
return html
.replace(/<[^>]+>/g, ' ')
.replace(/\s+/g, ' ')
.trim();
}
function statusBadgeVariant(
status: FeedbackStatusValue,
): 'outline' | 'secondary' | 'default' {
if (status === 'resolved') {
return 'default';
}
if (status === 'in_review') {
return 'secondary';
}
return 'outline';
}
export function createFeedbackColumns(
params: CreateColumnsParams,
): ColumnDef<Feedback>[] {
const { handleEdit, handleDeleteClick } = params;
return [
{
accessorKey: 'subject',
header: () => <span>Subjek</span>,
cell: ({ row }) => {
const feedback = row.original;
return (
<div>
<p className="font-medium">{feedback.subject}</p>
<p className="line-clamp-1 text-xs text-muted-foreground">
{stripHtml(feedback.message)}
</p>
</div>
);
},
},
{
accessorKey: 'type',
header: () => <span className="block text-center">Jenis</span>,
meta: {
className: 'w-[110px] text-center',
headerClassName: 'w-[110px] text-center',
},
cell: ({ row }) => (
<div className="flex justify-center">
<Badge variant="outline">
{FeedbackTypeLabels[row.original.type]}
</Badge>
</div>
),
},
{
accessorKey: 'status',
header: () => <span className="block text-center">Status</span>,
meta: {
className: 'w-[130px] text-center',
headerClassName: 'w-[130px] text-center',
},
cell: ({ row }) => (
<div className="flex justify-center">
<Badge variant={statusBadgeVariant(row.original.status)}>
{FeedbackStatusLabels[row.original.status]}
</Badge>
</div>
),
},
{
accessorKey: 'created_at',
header: () => <span>Dikirim</span>,
cell: ({ row }) =>
format(new Date(row.original.created_at), 'd MMM yyyy, HH:mm'),
},
{
id: 'actions',
header: () => <span className="block text-center">Aksi</span>,
meta: {
className: 'w-[100px] text-center',
headerClassName: 'w-[100px] text-center',
},
cell: ({ row }) => (
<RowActions
actions={[
{
label: 'Edit',
icon: <Pencil className="h-4 w-4" />,
onClick: () => handleEdit(row.original),
},
{
label: 'Hapus',
icon: (
<Trash2 className="h-4 w-4 text-destructive" />
),
onClick: () => handleDeleteClick(row.original),
},
]}
/>
),
},
];
}