- Added RawMaterialController and RawMaterialVariantController for managing raw materials and their variants. - Introduced RawMaterialRequest and RawMaterialVariantRequest for validation. - Implemented RawMaterialService and RawMaterialVariantService for business logic. - Created hooks for saving drafts of raw materials. - Developed UI components for creating, editing, and listing raw materials and variants.
147 lines
5.9 KiB
TypeScript
147 lines
5.9 KiB
TypeScript
import { Button } from '@/components/ui/button';
|
|
import { Card, CardContent } from '@/components/ui/card';
|
|
import { Switch } from '@/components/ui/switch';
|
|
import {
|
|
Tooltip,
|
|
TooltipContent,
|
|
TooltipProvider,
|
|
TooltipTrigger,
|
|
} from '@/components/ui/tooltip';
|
|
import { router } from '@inertiajs/react';
|
|
import { ChevronDown, Pencil, Trash2 } from 'lucide-react';
|
|
import type { RawMaterial } from './columns';
|
|
|
|
function formatNumber(num: number): string {
|
|
return new Intl.NumberFormat('id-ID', { maximumFractionDigits: 4 }).format(num);
|
|
}
|
|
|
|
function formatCurrency(amount: number): string {
|
|
return new Intl.NumberFormat('id-ID', {
|
|
style: 'currency',
|
|
currency: 'IDR',
|
|
minimumFractionDigits: 0,
|
|
}).format(amount);
|
|
}
|
|
|
|
export type RawMaterialCardRowParams = {
|
|
rawMaterial: RawMaterial;
|
|
index: number;
|
|
isExpanded: boolean;
|
|
onToggleExpand: () => void;
|
|
onEdit: (rawMaterial: RawMaterial) => void;
|
|
onDelete: (rawMaterial: RawMaterial) => void;
|
|
toggleStatusUrl: (id: number) => string;
|
|
};
|
|
|
|
export function RawMaterialCardRow({
|
|
rawMaterial,
|
|
index,
|
|
isExpanded,
|
|
onToggleExpand,
|
|
onEdit,
|
|
onDelete,
|
|
toggleStatusUrl,
|
|
}: RawMaterialCardRowParams) {
|
|
const variants = rawMaterial.raw_material_prices ?? [];
|
|
const totalStock = variants.reduce((sum, v) => sum + (Number(v.stock) || 0), 0);
|
|
const totalValue = variants.reduce((sum, v) => sum + (Number(v.price) || 0) * (Number(v.stock) || 0), 0);
|
|
|
|
function handleToggle() {
|
|
router.post(toggleStatusUrl(rawMaterial.id), {}, { preserveScroll: true });
|
|
}
|
|
|
|
return (
|
|
<Card className="overflow-hidden">
|
|
<CardContent className="p-0">
|
|
<div className="flex items-start gap-3 p-4">
|
|
<Button
|
|
variant="ghost"
|
|
size="icon"
|
|
className="mt-0.5 h-6 w-6 shrink-0"
|
|
onClick={onToggleExpand}
|
|
>
|
|
<ChevronDown
|
|
className={`h-4 w-4 transition-transform ${isExpanded ? 'rotate-180' : ''}`}
|
|
/>
|
|
</Button>
|
|
|
|
<div className="min-w-0 flex-1">
|
|
<div className="flex flex-wrap items-center gap-2">
|
|
<span className="text-xs text-muted-foreground">
|
|
{index}.
|
|
</span>
|
|
<h3 className="truncate font-medium">
|
|
{rawMaterial.name}
|
|
</h3>
|
|
</div>
|
|
|
|
<div className="mt-2 flex flex-wrap items-center gap-3 text-xs text-muted-foreground">
|
|
<span className="inline-flex items-center rounded-md bg-muted px-2 py-1 font-medium text-foreground">
|
|
{variants.length} varian
|
|
</span>
|
|
<span>
|
|
Total Stok:{' '}
|
|
<span className="font-medium text-foreground">
|
|
{formatNumber(totalStock)}
|
|
</span>
|
|
</span>
|
|
<span>
|
|
Total Nilai:{' '}
|
|
<span className="font-medium text-foreground">
|
|
{formatCurrency(totalValue)}
|
|
</span>
|
|
</span>
|
|
</div>
|
|
|
|
<div className="mt-2">
|
|
<div className="flex items-center gap-2">
|
|
<Switch
|
|
size="sm"
|
|
checked={rawMaterial.is_active}
|
|
onCheckedChange={handleToggle}
|
|
/>
|
|
<span
|
|
className={`text-xs font-medium ${rawMaterial.is_active ? 'text-green-700' : 'text-red-700'}`}
|
|
>
|
|
{rawMaterial.is_active ? 'Aktif' : 'Non Aktif'}
|
|
</span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<TooltipProvider>
|
|
<div className="flex shrink-0 items-center gap-1">
|
|
<Tooltip>
|
|
<TooltipTrigger asChild>
|
|
<Button
|
|
variant="ghost"
|
|
size="icon"
|
|
onClick={() => onEdit(rawMaterial)}
|
|
>
|
|
<Pencil className="h-4 w-4" />
|
|
</Button>
|
|
</TooltipTrigger>
|
|
<TooltipContent side="top">Edit</TooltipContent>
|
|
</Tooltip>
|
|
<Tooltip>
|
|
<TooltipTrigger asChild>
|
|
<Button
|
|
variant="ghost"
|
|
size="icon"
|
|
onClick={() => onDelete(rawMaterial)}
|
|
>
|
|
<Trash2 className="h-4 w-4 text-destructive" />
|
|
</Button>
|
|
</TooltipTrigger>
|
|
<TooltipContent side="top">
|
|
Hapus
|
|
</TooltipContent>
|
|
</Tooltip>
|
|
</div>
|
|
</TooltipProvider>
|
|
</div>
|
|
</CardContent>
|
|
</Card>
|
|
);
|
|
}
|