179 lines
5.0 KiB
TypeScript
179 lines
5.0 KiB
TypeScript
import type { ColumnDef } from '@tanstack/react-table';
|
|
import { ArrowDown, ArrowUp } from 'lucide-react';
|
|
|
|
export type StockMutation = {
|
|
id: number;
|
|
type: 'in' | 'out';
|
|
quantity: number;
|
|
formatted_quantity: string;
|
|
stock_before: number;
|
|
stock_after: number;
|
|
formatted_stock_before: string;
|
|
formatted_stock_after: string;
|
|
stock_quality: 'good' | 'reject' | 'retail';
|
|
description: string | null;
|
|
created_at: string;
|
|
formatted_created_at: string;
|
|
stockable: {
|
|
id: number;
|
|
name: string;
|
|
product: {
|
|
id: number;
|
|
name: string;
|
|
} | null;
|
|
} | null;
|
|
user: {
|
|
id: number;
|
|
username: string;
|
|
email: string;
|
|
user_profile?: {
|
|
full_name: string;
|
|
};
|
|
} | null;
|
|
};
|
|
|
|
function getQualityLabel(quality: string): string {
|
|
const labels: Record<string, string> = {
|
|
good: 'Bagus',
|
|
reject: 'Reject',
|
|
retail: 'Ecer',
|
|
};
|
|
|
|
return labels[quality] ?? quality;
|
|
}
|
|
|
|
function getQualityColor(quality: string): string {
|
|
const colors: Record<string, string> = {
|
|
good: 'bg-green-100 text-green-800',
|
|
reject: 'bg-red-100 text-red-800',
|
|
retail: 'bg-blue-100 text-blue-800',
|
|
};
|
|
|
|
return colors[quality] ?? 'bg-gray-100 text-gray-800';
|
|
}
|
|
|
|
export const columns: ColumnDef<StockMutation>[] = [
|
|
{
|
|
accessorKey: 'formatted_created_at',
|
|
header: () => <span>Tanggal</span>,
|
|
cell: ({ row }) => (
|
|
<span className="whitespace-nowrap">
|
|
{row.getValue('formatted_created_at') as string}
|
|
</span>
|
|
),
|
|
},
|
|
{
|
|
id: 'product',
|
|
header: () => <span>Produk</span>,
|
|
cell: ({ row }) => {
|
|
const stockable = row.original.stockable;
|
|
|
|
return (
|
|
<div className="flex flex-col">
|
|
<span className="font-medium">
|
|
{stockable?.product?.name ?? '-'}
|
|
</span>
|
|
<span className="text-xs text-muted-foreground">
|
|
{stockable?.name ?? '-'}
|
|
</span>
|
|
</div>
|
|
);
|
|
},
|
|
},
|
|
{
|
|
id: 'type',
|
|
header: () => <span>Tipe</span>,
|
|
cell: ({ row }) => {
|
|
const mutation = row.original;
|
|
const isIn = mutation.type === 'in';
|
|
|
|
return (
|
|
<span
|
|
className={`inline-flex items-center gap-1 rounded-md px-2 py-0.5 text-xs font-medium ${
|
|
isIn
|
|
? 'bg-green-100 text-green-800'
|
|
: 'bg-red-100 text-red-800'
|
|
}`}
|
|
>
|
|
{isIn ? (
|
|
<ArrowUp className="h-3 w-3" />
|
|
) : (
|
|
<ArrowDown className="h-3 w-3" />
|
|
)}
|
|
{isIn ? 'Masuk' : 'Keluar'}
|
|
</span>
|
|
);
|
|
},
|
|
},
|
|
{
|
|
id: 'stock_quality',
|
|
header: () => <span>Kualitas</span>,
|
|
cell: ({ row }) => {
|
|
const quality = row.original.stock_quality;
|
|
|
|
return (
|
|
<span
|
|
className={`inline-flex items-center rounded-md px-2 py-0.5 text-xs font-medium ${getQualityColor(quality)}`}
|
|
>
|
|
{getQualityLabel(quality)}
|
|
</span>
|
|
);
|
|
},
|
|
},
|
|
{
|
|
id: 'quantity',
|
|
header: () => <span>Qty</span>,
|
|
cell: ({ row }) => {
|
|
const mutation = row.original;
|
|
const isPositive = mutation.quantity > 0;
|
|
|
|
return (
|
|
<span
|
|
className={
|
|
isPositive
|
|
? 'font-medium text-green-600'
|
|
: 'font-medium text-red-600'
|
|
}
|
|
>
|
|
{isPositive ? '+' : ''}
|
|
{mutation.formatted_quantity}
|
|
</span>
|
|
);
|
|
},
|
|
},
|
|
{
|
|
id: 'stock_change',
|
|
header: () => <span>Stok</span>,
|
|
cell: ({ row }) => {
|
|
const mutation = row.original;
|
|
|
|
return (
|
|
<span className="whitespace-nowrap text-muted-foreground">
|
|
{mutation.formatted_stock_before} →{' '}
|
|
{mutation.formatted_stock_after}
|
|
</span>
|
|
);
|
|
},
|
|
},
|
|
{
|
|
accessorKey: 'description',
|
|
header: () => <span>Keterangan</span>,
|
|
cell: ({ row }) => (
|
|
<span className="block max-w-[220px]">
|
|
{(row.getValue('description') as string | null) ?? '-'}
|
|
</span>
|
|
),
|
|
},
|
|
{
|
|
id: 'user',
|
|
header: () => <span>Oleh</span>,
|
|
cell: ({ row }) => {
|
|
const user = row.original.user;
|
|
|
|
return (
|
|
<span>{user?.user_profile?.full_name ?? user?.username ?? '-'}</span>
|
|
);
|
|
},
|
|
},
|
|
];
|