- Updated import paths for various components to align with new directory structure. - Changed imports from 'row-actions', 'confirm-dialog', 'image-preview-button', and 'file-upload' to their respective new locations in 'data-display', 'dialogs', and 'inputs'. - Adjusted imports in multiple pages including purchase, restock, transaction, category, customer, product, raw-material, supplier, roles, and settings. - Ensured all relevant components are imported from their new locations to maintain functionality.
282 lines
15 KiB
TypeScript
282 lines
15 KiB
TypeScript
import { Fragment } from 'react';
|
|
import { ImagePreviewButton } from '@/components/dialogs';
|
|
import {
|
|
Table,
|
|
TableBody,
|
|
TableCell,
|
|
TableHead,
|
|
TableHeader,
|
|
TableRow,
|
|
} from '@/components/ui/table';
|
|
import { formatNumber } from '@/lib/format';
|
|
import type { Cutting } from './columns';
|
|
|
|
export function CuttingItemSubRow({ cutting }: { cutting: Cutting }) {
|
|
const items = cutting.cutting_materials ?? [];
|
|
const combinations = cutting.cutting_material_combinations ?? [];
|
|
|
|
const singles = items.filter((item) => item.combination_id === null);
|
|
const comboItems = items.filter((item) => item.combination_id !== null);
|
|
|
|
const comboGroups: Record<number, typeof items> = {};
|
|
comboItems.forEach((item) => {
|
|
const comboId = item.combination_id!;
|
|
|
|
if (!comboGroups[comboId]) {
|
|
comboGroups[comboId] = [];
|
|
}
|
|
|
|
comboGroups[comboId].push(item);
|
|
});
|
|
|
|
const singleByRawMaterial = singles.reduce(
|
|
(acc, item) => {
|
|
const name =
|
|
item.raw_material_price?.raw_material?.name ?? 'BING';
|
|
|
|
if (!acc[name]) {
|
|
acc[name] = [];
|
|
}
|
|
|
|
acc[name].push(item);
|
|
|
|
return acc;
|
|
},
|
|
{} as Record<string, typeof singles>,
|
|
);
|
|
|
|
const hasSingle = singles.length > 0;
|
|
const hasCombo = comboItems.length > 0;
|
|
|
|
let counter = 0;
|
|
|
|
return (
|
|
<div className="overflow-x-auto">
|
|
<Table>
|
|
<TableHeader>
|
|
<TableRow>
|
|
<TableHead className="w-[50px] text-center">
|
|
No
|
|
</TableHead>
|
|
<TableHead className="w-[60px]">Foto</TableHead>
|
|
<TableHead>Varian</TableHead>
|
|
<TableHead className="text-right">
|
|
Pemakaian
|
|
</TableHead>
|
|
<TableHead className="text-right">Hasil</TableHead>
|
|
</TableRow>
|
|
</TableHeader>
|
|
<TableBody>
|
|
{hasSingle && (
|
|
<>
|
|
<TableRow>
|
|
<TableCell
|
|
colSpan={5}
|
|
className="text-center font-bold bg-muted/50"
|
|
>
|
|
Single
|
|
</TableCell>
|
|
</TableRow>
|
|
{Object.entries(singleByRawMaterial).map(
|
|
([rawMaterialName, groupItems]) => {
|
|
const totalPemakaian = groupItems.reduce(
|
|
(sum, item) =>
|
|
sum + Number(item.material_usage),
|
|
0,
|
|
);
|
|
const totalHasil = groupItems.reduce(
|
|
(sum, item) =>
|
|
sum +
|
|
(item.material_result !== null
|
|
? Number(item.material_result)
|
|
: 0),
|
|
0,
|
|
);
|
|
|
|
return (
|
|
<Fragment key={rawMaterialName}>
|
|
<TableRow>
|
|
<TableCell
|
|
colSpan={3}
|
|
className="text-center font-medium text-muted-foreground bg-muted/20"
|
|
>
|
|
{rawMaterialName}
|
|
</TableCell>
|
|
<TableCell className="text-right font-medium text-muted-foreground bg-muted/20">
|
|
{formatNumber(
|
|
totalPemakaian,
|
|
)}
|
|
</TableCell>
|
|
<TableCell className="text-right font-medium text-muted-foreground bg-muted/20">
|
|
{formatNumber(
|
|
totalHasil,
|
|
)}
|
|
</TableCell>
|
|
</TableRow>
|
|
{groupItems.map((item) => {
|
|
counter++;
|
|
|
|
return (
|
|
<TableRow key={item.id}>
|
|
<TableCell className="text-center">
|
|
{counter}
|
|
</TableCell>
|
|
<TableCell>
|
|
{item.raw_material_price
|
|
?.photo_url ? (
|
|
<ImagePreviewButton
|
|
srcs={[
|
|
item
|
|
.raw_material_price
|
|
.photo_url,
|
|
]}
|
|
title={
|
|
item
|
|
.raw_material_price
|
|
.variant
|
|
}
|
|
/>
|
|
) : (
|
|
<div className="flex h-10 w-10 items-center justify-center rounded-md bg-muted text-xs text-muted-foreground">
|
|
N/A
|
|
</div>
|
|
)}
|
|
</TableCell>
|
|
<TableCell>
|
|
{item.raw_material_price
|
|
?.variant ?? '-'}
|
|
</TableCell>
|
|
<TableCell className="text-right">
|
|
{formatNumber(
|
|
item.material_usage,
|
|
)}
|
|
</TableCell>
|
|
<TableCell className="text-right">
|
|
{item.material_result !==
|
|
null
|
|
? formatNumber(
|
|
item.material_result,
|
|
)
|
|
: '-'}
|
|
</TableCell>
|
|
</TableRow>
|
|
);
|
|
})}
|
|
</Fragment>
|
|
);
|
|
},
|
|
)}
|
|
</>
|
|
)}
|
|
|
|
{hasCombo && (
|
|
<>
|
|
<TableRow>
|
|
<TableCell
|
|
colSpan={5}
|
|
className="text-center font-bold bg-muted/50"
|
|
>
|
|
Kombinasi
|
|
</TableCell>
|
|
</TableRow>
|
|
{Object.entries(comboGroups).map(
|
|
([comboId, materials]) => {
|
|
counter++;
|
|
const combo = combinations.find(
|
|
(c) => c.id === Number(comboId),
|
|
);
|
|
|
|
return (
|
|
<Fragment key={comboId}>
|
|
<TableRow>
|
|
<TableCell className="text-center font-medium">
|
|
{counter}
|
|
</TableCell>
|
|
<TableCell
|
|
colSpan={4}
|
|
className="font-medium text-muted-foreground bg-muted/20"
|
|
>
|
|
Kombinasi{' '}
|
|
{counter}
|
|
{combo?.material_result !==
|
|
null &&
|
|
combo?.material_result !==
|
|
undefined && (
|
|
<span className="ml-2">
|
|
(Hasil:{' '}
|
|
{formatNumber(
|
|
combo.material_result,
|
|
)}
|
|
)
|
|
</span>
|
|
)}
|
|
</TableCell>
|
|
</TableRow>
|
|
{materials.map((item) => (
|
|
<TableRow key={item.id}>
|
|
<TableCell></TableCell>
|
|
<TableCell>
|
|
{item
|
|
.raw_material_price
|
|
?.photo_url ? (
|
|
<ImagePreviewButton
|
|
srcs={[
|
|
item
|
|
.raw_material_price
|
|
.photo_url,
|
|
]}
|
|
title={
|
|
item
|
|
.raw_material_price
|
|
.variant
|
|
}
|
|
/>
|
|
) : (
|
|
<div className="flex h-10 w-10 items-center justify-center rounded-md bg-muted text-xs text-muted-foreground">
|
|
N/A
|
|
</div>
|
|
)}
|
|
</TableCell>
|
|
<TableCell>
|
|
{item
|
|
.raw_material_price
|
|
?.raw_material
|
|
?.name ?? '-'}{' '}
|
|
-{' '}
|
|
{item
|
|
.raw_material_price
|
|
?.variant ?? '-'}
|
|
</TableCell>
|
|
<TableCell className="text-right">
|
|
{formatNumber(
|
|
item.material_usage,
|
|
)}
|
|
</TableCell>
|
|
<TableCell className="text-right">
|
|
-
|
|
</TableCell>
|
|
</TableRow>
|
|
))}
|
|
</Fragment>
|
|
);
|
|
},
|
|
)}
|
|
</>
|
|
)}
|
|
|
|
{items.length === 0 && (
|
|
<TableRow>
|
|
<TableCell
|
|
colSpan={5}
|
|
className="text-center text-muted-foreground"
|
|
>
|
|
Tidak ada bahan baku.
|
|
</TableCell>
|
|
</TableRow>
|
|
)}
|
|
</TableBody>
|
|
</Table>
|
|
</div>
|
|
);
|
|
}
|