refactor: remove unused variant handling and clean up PurchaseEdit component
This commit is contained in:
parent
fb70cca1dc
commit
f49cebb35a
@ -3,15 +3,12 @@
|
|||||||
import { Form, Head, Link } from '@inertiajs/react';
|
import { Form, Head, Link } from '@inertiajs/react';
|
||||||
import {
|
import {
|
||||||
ArrowLeft,
|
ArrowLeft,
|
||||||
Check,
|
|
||||||
ClipboardPaste,
|
|
||||||
Copy,
|
|
||||||
Minus,
|
Minus,
|
||||||
Plus,
|
Plus,
|
||||||
ShoppingCart,
|
ShoppingCart,
|
||||||
Trash2,
|
Trash2,
|
||||||
} from 'lucide-react';
|
} from 'lucide-react';
|
||||||
import { useCallback, useMemo, useRef, useState } from 'react';
|
import { useCallback, useMemo, useState } from 'react';
|
||||||
import { ConfirmDialog } from '@/components/confirm-dialog';
|
import { ConfirmDialog } from '@/components/confirm-dialog';
|
||||||
import { FileUpload } from '@/components/file-upload';
|
import { FileUpload } from '@/components/file-upload';
|
||||||
import { ImagePreviewModal } from '@/components/image-preview-modal';
|
import { ImagePreviewModal } from '@/components/image-preview-modal';
|
||||||
@ -28,7 +25,6 @@ import {
|
|||||||
ComboboxItem,
|
ComboboxItem,
|
||||||
ComboboxList,
|
ComboboxList,
|
||||||
} from '@/components/ui/combobox';
|
} from '@/components/ui/combobox';
|
||||||
import { Input } from '@/components/ui/input';
|
|
||||||
import { Label } from '@/components/ui/label';
|
import { Label } from '@/components/ui/label';
|
||||||
import {
|
import {
|
||||||
Sheet,
|
Sheet,
|
||||||
@ -37,10 +33,8 @@ import {
|
|||||||
SheetHeader,
|
SheetHeader,
|
||||||
SheetTitle,
|
SheetTitle,
|
||||||
} from '@/components/ui/sheet';
|
} from '@/components/ui/sheet';
|
||||||
import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/components/ui/tabs';
|
|
||||||
import { Textarea } from '@/components/ui/textarea';
|
import { Textarea } from '@/components/ui/textarea';
|
||||||
import { formatNumber } from '@/lib/format';
|
import { formatNumber } from '@/lib/format';
|
||||||
import { getTemporaryUrl } from '@/lib/upload';
|
|
||||||
import { formatCurrency } from '@/lib/utils';
|
import { formatCurrency } from '@/lib/utils';
|
||||||
import {
|
import {
|
||||||
index as purchaseIndex,
|
index as purchaseIndex,
|
||||||
@ -48,16 +42,6 @@ import {
|
|||||||
} from '@/routes/admin/manage/purchases';
|
} from '@/routes/admin/manage/purchases';
|
||||||
import type { PurchaseCreateData, PurchaseForEdit } from './columns';
|
import type { PurchaseCreateData, PurchaseForEdit } from './columns';
|
||||||
|
|
||||||
type VariantState = {
|
|
||||||
id?: number;
|
|
||||||
variant: string;
|
|
||||||
price: number;
|
|
||||||
stock: number;
|
|
||||||
photo: string | null;
|
|
||||||
photoUrl: string | null;
|
|
||||||
uploading: boolean;
|
|
||||||
};
|
|
||||||
|
|
||||||
type CartLine = {
|
type CartLine = {
|
||||||
key: string;
|
key: string;
|
||||||
photoUrl: string | null;
|
photoUrl: string | null;
|
||||||
@ -78,19 +62,6 @@ type Props = {
|
|||||||
export default function PurchaseEdit({ purchase, data }: Props) {
|
export default function PurchaseEdit({ purchase, data }: Props) {
|
||||||
const { suppliers, rawMaterials } = data;
|
const { suppliers, rawMaterials } = data;
|
||||||
|
|
||||||
const [name] = useState(purchase.name);
|
|
||||||
const [variants, setVariants] = useState<VariantState[]>(() =>
|
|
||||||
purchase.variants.map((v) => ({
|
|
||||||
id: v.id,
|
|
||||||
variant: v.variant,
|
|
||||||
price: v.price,
|
|
||||||
stock: v.stock,
|
|
||||||
photo: v.photo_key ?? null,
|
|
||||||
photoUrl: v.photo_url ?? null,
|
|
||||||
uploading: false,
|
|
||||||
})),
|
|
||||||
);
|
|
||||||
|
|
||||||
const [supplierId, setSupplierId] = useState(String(purchase.supplier_id));
|
const [supplierId, setSupplierId] = useState(String(purchase.supplier_id));
|
||||||
const selectedSupplier =
|
const selectedSupplier =
|
||||||
suppliers.find((s) => String(s.id) === supplierId) ?? null;
|
suppliers.find((s) => String(s.id) === supplierId) ?? null;
|
||||||
@ -101,7 +72,6 @@ export default function PurchaseEdit({ purchase, data }: Props) {
|
|||||||
const [photoUrl, setPhotoUrl] = useState<string | null>(purchase.photo_url);
|
const [photoUrl, setPhotoUrl] = useState<string | null>(purchase.photo_url);
|
||||||
const [uploading, setUploading] = useState(false);
|
const [uploading, setUploading] = useState(false);
|
||||||
|
|
||||||
const [mode, setMode] = useState<'new' | 'existing'>(purchase.default_mode);
|
|
||||||
const [selectedMaterialName, setSelectedMaterialName] = useState(
|
const [selectedMaterialName, setSelectedMaterialName] = useState(
|
||||||
purchase.existing_material_name ?? '',
|
purchase.existing_material_name ?? '',
|
||||||
);
|
);
|
||||||
@ -117,9 +87,6 @@ export default function PurchaseEdit({ purchase, data }: Props) {
|
|||||||
const [previewKey, setPreviewKey] = useState<string | null>(null);
|
const [previewKey, setPreviewKey] = useState<string | null>(null);
|
||||||
const [cartRemoveKey, setCartRemoveKey] = useState<string | null>(null);
|
const [cartRemoveKey, setCartRemoveKey] = useState<string | null>(null);
|
||||||
|
|
||||||
const variantsRef = useRef(variants);
|
|
||||||
variantsRef.current = variants;
|
|
||||||
|
|
||||||
const priceMap = useMemo(
|
const priceMap = useMemo(
|
||||||
() =>
|
() =>
|
||||||
new Map(
|
new Map(
|
||||||
@ -143,11 +110,7 @@ export default function PurchaseEdit({ purchase, data }: Props) {
|
|||||||
[rawMaterials],
|
[rawMaterials],
|
||||||
);
|
);
|
||||||
|
|
||||||
const newSubtotal = variants.reduce(
|
const subtotal = Object.entries(quantities).reduce(
|
||||||
(sum, v) => sum + Number(v.price) * Number(v.stock),
|
|
||||||
0,
|
|
||||||
);
|
|
||||||
const existingSubtotal = Object.entries(quantities).reduce(
|
|
||||||
(sum, [priceId, quantity]) => {
|
(sum, [priceId, quantity]) => {
|
||||||
const price = priceMap.get(Number(priceId));
|
const price = priceMap.get(Number(priceId));
|
||||||
|
|
||||||
@ -155,93 +118,8 @@ export default function PurchaseEdit({ purchase, data }: Props) {
|
|||||||
},
|
},
|
||||||
0,
|
0,
|
||||||
);
|
);
|
||||||
const subtotal = mode === 'existing' ? existingSubtotal : newSubtotal;
|
|
||||||
const total = subtotal - discount + shippingCost;
|
const total = subtotal - discount + shippingCost;
|
||||||
|
|
||||||
const addVariant = useCallback(() => {
|
|
||||||
setVariants((prev) => [
|
|
||||||
...prev,
|
|
||||||
{
|
|
||||||
variant: '',
|
|
||||||
price: 0,
|
|
||||||
stock: 0,
|
|
||||||
photo: null,
|
|
||||||
photoUrl: null,
|
|
||||||
uploading: false,
|
|
||||||
},
|
|
||||||
]);
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
const removeVariant = useCallback((index: number) => {
|
|
||||||
setVariants((prev) => prev.filter((_, i) => i !== index));
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
const updateVariant = useCallback(
|
|
||||||
(index: number, field: keyof VariantState, value: unknown) => {
|
|
||||||
setVariants((prev) => {
|
|
||||||
const updated = [...prev];
|
|
||||||
(updated[index] as Record<string, unknown>)[field] = value;
|
|
||||||
|
|
||||||
return updated;
|
|
||||||
});
|
|
||||||
},
|
|
||||||
[],
|
|
||||||
);
|
|
||||||
|
|
||||||
const [copiedIndex, setCopiedIndex] = useState<number | null>(null);
|
|
||||||
const [deleteConfirmOpen, setDeleteConfirmOpen] = useState(false);
|
|
||||||
const [deleteVariantIndex, setDeleteVariantIndex] = useState<number | null>(
|
|
||||||
null,
|
|
||||||
);
|
|
||||||
|
|
||||||
const confirmRemoveVariant = useCallback((index: number) => {
|
|
||||||
setDeleteVariantIndex(index);
|
|
||||||
setDeleteConfirmOpen(true);
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
const copyPrice = useCallback((variantIndex: number) => {
|
|
||||||
setVariants((prev) => {
|
|
||||||
const price = prev[variantIndex].price;
|
|
||||||
navigator.clipboard.writeText(String(price));
|
|
||||||
setCopiedIndex(variantIndex);
|
|
||||||
setTimeout(() => setCopiedIndex(null), 1500);
|
|
||||||
|
|
||||||
return prev;
|
|
||||||
});
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
const pastePrice = useCallback((variantIndex: number) => {
|
|
||||||
navigator.clipboard.readText().then((text) => {
|
|
||||||
try {
|
|
||||||
const price = Number(text);
|
|
||||||
|
|
||||||
if (!isNaN(price)) {
|
|
||||||
setVariants((prev) => {
|
|
||||||
const updated = [...prev];
|
|
||||||
updated[variantIndex] = {
|
|
||||||
...updated[variantIndex],
|
|
||||||
price,
|
|
||||||
};
|
|
||||||
|
|
||||||
return updated;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
} catch {
|
|
||||||
// invalid clipboard data
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
const applyToAll = useCallback((variantIndex: number) => {
|
|
||||||
setVariants((prev) => {
|
|
||||||
const sourcePrice = prev[variantIndex].price;
|
|
||||||
|
|
||||||
return prev.map((v, i) =>
|
|
||||||
i === variantIndex ? v : { ...v, price: sourcePrice },
|
|
||||||
);
|
|
||||||
});
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
const selectedMaterial = useMemo(
|
const selectedMaterial = useMemo(
|
||||||
() => rawMaterials.find((m) => m.name === selectedMaterialName) ?? null,
|
() => rawMaterials.find((m) => m.name === selectedMaterialName) ?? null,
|
||||||
[rawMaterials, selectedMaterialName],
|
[rawMaterials, selectedMaterialName],
|
||||||
@ -261,20 +139,7 @@ export default function PurchaseEdit({ purchase, data }: Props) {
|
|||||||
}));
|
}));
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
const adjustVariantStock = useCallback((index: number, amount: number) => {
|
|
||||||
setVariants((prev) => {
|
|
||||||
const updated = [...prev];
|
|
||||||
updated[index] = {
|
|
||||||
...updated[index],
|
|
||||||
stock: Math.max(0, Number(updated[index].stock) + amount),
|
|
||||||
};
|
|
||||||
|
|
||||||
return updated;
|
|
||||||
});
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
const cartItems: CartLine[] = (() => {
|
const cartItems: CartLine[] = (() => {
|
||||||
if (mode === 'existing') {
|
|
||||||
const lines: CartLine[] = [];
|
const lines: CartLine[] = [];
|
||||||
|
|
||||||
for (const [priceId, quantity] of Object.entries(quantities)) {
|
for (const [priceId, quantity] of Object.entries(quantities)) {
|
||||||
@ -302,21 +167,6 @@ export default function PurchaseEdit({ purchase, data }: Props) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return lines.sort((a, b) => a.title.localeCompare(b.title));
|
return lines.sort((a, b) => a.title.localeCompare(b.title));
|
||||||
}
|
|
||||||
|
|
||||||
return variants
|
|
||||||
.map((v, index): CartLine => ({
|
|
||||||
key: `new-${index}`,
|
|
||||||
photoUrl: v.photoUrl,
|
|
||||||
title: `${name || 'Bahan Baku Baru'} — ${v.variant || `Varian ${index + 1}`}`,
|
|
||||||
subtitle: `${formatCurrency(v.price)} / ${purchase.unit}`,
|
|
||||||
price: v.price,
|
|
||||||
quantity: v.stock,
|
|
||||||
onAdjust: (delta) => adjustVariantStock(index, delta),
|
|
||||||
onSet: (value) => updateVariant(index, 'stock', value),
|
|
||||||
onRemove: () => removeVariant(index),
|
|
||||||
}))
|
|
||||||
.filter((line) => line.quantity > 0);
|
|
||||||
})();
|
})();
|
||||||
|
|
||||||
function formatQuantity(value: number): string {
|
function formatQuantity(value: number): string {
|
||||||
@ -324,18 +174,13 @@ export default function PurchaseEdit({ purchase, data }: Props) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function getPayload() {
|
function getPayload() {
|
||||||
const base = {
|
return {
|
||||||
mode,
|
mode: 'existing',
|
||||||
supplier_id: supplierId ? Number(supplierId) : null,
|
supplier_id: supplierId ? Number(supplierId) : null,
|
||||||
discount,
|
discount,
|
||||||
shipping_cost: shippingCost,
|
shipping_cost: shippingCost,
|
||||||
notes: notes || null,
|
notes: notes || null,
|
||||||
photo_key: photo,
|
photo_key: photo,
|
||||||
};
|
|
||||||
|
|
||||||
if (mode === 'existing') {
|
|
||||||
return {
|
|
||||||
...base,
|
|
||||||
existing_items: Object.entries(quantities)
|
existing_items: Object.entries(quantities)
|
||||||
.map(([priceId, quantity]) => ({
|
.map(([priceId, quantity]) => ({
|
||||||
raw_material_price_id: Number(priceId),
|
raw_material_price_id: Number(priceId),
|
||||||
@ -346,19 +191,6 @@ export default function PurchaseEdit({ purchase, data }: Props) {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
|
||||||
...base,
|
|
||||||
name,
|
|
||||||
variants: variantsRef.current.map((v) => ({
|
|
||||||
id: v.id,
|
|
||||||
variant: v.variant,
|
|
||||||
price: Number(v.price),
|
|
||||||
stock: Number(v.stock),
|
|
||||||
photo_key: v.photo,
|
|
||||||
})),
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Head title="Edit Belanja" />
|
<Head title="Edit Belanja" />
|
||||||
@ -387,303 +219,6 @@ export default function PurchaseEdit({ purchase, data }: Props) {
|
|||||||
{({ errors, processing }) => (
|
{({ errors, processing }) => (
|
||||||
<div className="grid gap-6 md:grid-cols-3">
|
<div className="grid gap-6 md:grid-cols-3">
|
||||||
<div className="space-y-6 md:col-span-2">
|
<div className="space-y-6 md:col-span-2">
|
||||||
<Tabs
|
|
||||||
value={mode}
|
|
||||||
onValueChange={(value) =>
|
|
||||||
setMode(value as 'new' | 'existing')
|
|
||||||
}
|
|
||||||
>
|
|
||||||
<TabsList>
|
|
||||||
<TabsTrigger value="new">
|
|
||||||
Baru
|
|
||||||
</TabsTrigger>
|
|
||||||
<TabsTrigger value="existing">
|
|
||||||
Lama
|
|
||||||
</TabsTrigger>
|
|
||||||
</TabsList>
|
|
||||||
|
|
||||||
<TabsContent
|
|
||||||
value="new"
|
|
||||||
className="mt-0 space-y-6"
|
|
||||||
>
|
|
||||||
<Card>
|
|
||||||
<CardHeader>
|
|
||||||
<CardTitle>
|
|
||||||
Informasi Bahan Baku
|
|
||||||
</CardTitle>
|
|
||||||
</CardHeader>
|
|
||||||
<CardContent className="grid grid-cols-1 gap-4">
|
|
||||||
<div className="grid gap-2">
|
|
||||||
<Label htmlFor="edit-name">
|
|
||||||
Nama Bahan Baku{' '}
|
|
||||||
<span className="text-destructive">
|
|
||||||
*
|
|
||||||
</span>
|
|
||||||
</Label>
|
|
||||||
<Input
|
|
||||||
id="edit-name"
|
|
||||||
name="name"
|
|
||||||
value={name}
|
|
||||||
disabled
|
|
||||||
placeholder="Masukkan nama bahan baku"
|
|
||||||
/>
|
|
||||||
<InputError
|
|
||||||
message={errors.name}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</CardContent>
|
|
||||||
</Card>
|
|
||||||
|
|
||||||
<Card>
|
|
||||||
<CardHeader>
|
|
||||||
<CardTitle>
|
|
||||||
Varian Bahan Baku
|
|
||||||
</CardTitle>
|
|
||||||
</CardHeader>
|
|
||||||
<CardContent className="space-y-4">
|
|
||||||
{variants.map(
|
|
||||||
(variant, variantIndex) => (
|
|
||||||
<div
|
|
||||||
key={variantIndex}
|
|
||||||
className="space-y-4 rounded-lg border p-4"
|
|
||||||
>
|
|
||||||
<div className="flex flex-col gap-2 sm:flex-row sm:items-center sm:justify-between">
|
|
||||||
<h4 className="font-medium">
|
|
||||||
Varian{' '}
|
|
||||||
{variantIndex +
|
|
||||||
1}
|
|
||||||
</h4>
|
|
||||||
<div className="flex flex-wrap items-center gap-1">
|
|
||||||
<Button
|
|
||||||
type="button"
|
|
||||||
variant="outline"
|
|
||||||
size="sm"
|
|
||||||
className="whitespace-nowrap"
|
|
||||||
onClick={() =>
|
|
||||||
copyPrice(
|
|
||||||
variantIndex,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
>
|
|
||||||
{copiedIndex ===
|
|
||||||
variantIndex ? (
|
|
||||||
<Check className="h-4 w-4 text-green-600" />
|
|
||||||
) : (
|
|
||||||
<Copy className="h-4 w-4" />
|
|
||||||
)}
|
|
||||||
Salin
|
|
||||||
Harga
|
|
||||||
</Button>
|
|
||||||
<Button
|
|
||||||
type="button"
|
|
||||||
variant="outline"
|
|
||||||
size="sm"
|
|
||||||
className="whitespace-nowrap"
|
|
||||||
onClick={() =>
|
|
||||||
pastePrice(
|
|
||||||
variantIndex,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
>
|
|
||||||
<ClipboardPaste className="h-4 w-4" />
|
|
||||||
Tempel
|
|
||||||
Harga
|
|
||||||
</Button>
|
|
||||||
<Button
|
|
||||||
type="button"
|
|
||||||
variant="outline"
|
|
||||||
size="sm"
|
|
||||||
className="whitespace-nowrap"
|
|
||||||
onClick={() =>
|
|
||||||
applyToAll(
|
|
||||||
variantIndex,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
>
|
|
||||||
Terapkan
|
|
||||||
ke Semua
|
|
||||||
</Button>
|
|
||||||
{variantIndex >
|
|
||||||
0 && (
|
|
||||||
<Button
|
|
||||||
type="button"
|
|
||||||
variant="outline"
|
|
||||||
size="icon"
|
|
||||||
onClick={() =>
|
|
||||||
confirmRemoveVariant(
|
|
||||||
variantIndex,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
>
|
|
||||||
<Trash2 className="h-4 w-4 text-destructive" />
|
|
||||||
</Button>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div className="grid grid-cols-1 gap-4 md:grid-cols-3">
|
|
||||||
<div className="grid gap-2">
|
|
||||||
<Label>
|
|
||||||
Nama
|
|
||||||
Varian{' '}
|
|
||||||
<span className="text-destructive">
|
|
||||||
*
|
|
||||||
</span>
|
|
||||||
</Label>
|
|
||||||
<Input
|
|
||||||
value={
|
|
||||||
variant.variant
|
|
||||||
}
|
|
||||||
onChange={(
|
|
||||||
e,
|
|
||||||
) =>
|
|
||||||
updateVariant(
|
|
||||||
variantIndex,
|
|
||||||
'variant',
|
|
||||||
e
|
|
||||||
.target
|
|
||||||
.value,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
placeholder="Contoh: Ukuran L, Warna Merah"
|
|
||||||
/>
|
|
||||||
<InputError
|
|
||||||
message={
|
|
||||||
errors[
|
|
||||||
`variants.${variantIndex}.variant`
|
|
||||||
]
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<div className="grid gap-2">
|
|
||||||
<Label>
|
|
||||||
Harga{' '}
|
|
||||||
<span className="text-destructive">
|
|
||||||
*
|
|
||||||
</span>
|
|
||||||
</Label>
|
|
||||||
<RupiahInput
|
|
||||||
value={
|
|
||||||
variant.price
|
|
||||||
}
|
|
||||||
onValueChange={(
|
|
||||||
val,
|
|
||||||
) =>
|
|
||||||
updateVariant(
|
|
||||||
variantIndex,
|
|
||||||
'price',
|
|
||||||
val,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
<InputError
|
|
||||||
message={
|
|
||||||
errors[
|
|
||||||
`variants.${variantIndex}.price`
|
|
||||||
]
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<div className="grid gap-2">
|
|
||||||
<Label>
|
|
||||||
Stok{' '}
|
|
||||||
<span className="text-destructive">
|
|
||||||
*
|
|
||||||
</span>
|
|
||||||
</Label>
|
|
||||||
<NumberInput
|
|
||||||
value={
|
|
||||||
variant.stock
|
|
||||||
}
|
|
||||||
onValueChange={(
|
|
||||||
val,
|
|
||||||
) =>
|
|
||||||
updateVariant(
|
|
||||||
variantIndex,
|
|
||||||
'stock',
|
|
||||||
val,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
<InputError
|
|
||||||
message={
|
|
||||||
errors[
|
|
||||||
`variants.${variantIndex}.stock`
|
|
||||||
]
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div className="grid gap-2">
|
|
||||||
<Label>
|
|
||||||
Foto Varian{' '}
|
|
||||||
<span className="text-destructive">
|
|
||||||
*
|
|
||||||
</span>
|
|
||||||
</Label>
|
|
||||||
<FileUpload
|
|
||||||
value={
|
|
||||||
variant.photo
|
|
||||||
}
|
|
||||||
onChange={(
|
|
||||||
key,
|
|
||||||
) => {
|
|
||||||
updateVariant(
|
|
||||||
variantIndex,
|
|
||||||
'photo',
|
|
||||||
key,
|
|
||||||
);
|
|
||||||
updateVariant(
|
|
||||||
variantIndex,
|
|
||||||
'photoUrl',
|
|
||||||
key
|
|
||||||
? getTemporaryUrl(
|
|
||||||
key,
|
|
||||||
)
|
|
||||||
: null,
|
|
||||||
);
|
|
||||||
}}
|
|
||||||
folder="raw-material-variant"
|
|
||||||
existingUrl={
|
|
||||||
variant.photoUrl
|
|
||||||
}
|
|
||||||
onUploadingChange={(
|
|
||||||
uploading,
|
|
||||||
) =>
|
|
||||||
updateVariant(
|
|
||||||
variantIndex,
|
|
||||||
'uploading',
|
|
||||||
uploading,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
<InputError
|
|
||||||
message={
|
|
||||||
errors[
|
|
||||||
`variants.${variantIndex}.photo_key`
|
|
||||||
]
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
),
|
|
||||||
)}
|
|
||||||
|
|
||||||
<Button
|
|
||||||
type="button"
|
|
||||||
variant="outline"
|
|
||||||
onClick={addVariant}
|
|
||||||
>
|
|
||||||
<Plus className="h-4 w-4" />
|
|
||||||
Tambah Varian
|
|
||||||
</Button>
|
|
||||||
</CardContent>
|
|
||||||
</Card>
|
|
||||||
</TabsContent>
|
|
||||||
|
|
||||||
<TabsContent
|
|
||||||
value="existing"
|
|
||||||
className="mt-0 space-y-6"
|
|
||||||
>
|
|
||||||
<Card>
|
<Card>
|
||||||
<CardHeader>
|
<CardHeader>
|
||||||
<CardTitle>
|
<CardTitle>
|
||||||
@ -716,6 +251,7 @@ export default function PurchaseEdit({ purchase, data }: Props) {
|
|||||||
<ComboboxInput
|
<ComboboxInput
|
||||||
placeholder="Cari bahan baku..."
|
placeholder="Cari bahan baku..."
|
||||||
className="w-full"
|
className="w-full"
|
||||||
|
disabled
|
||||||
/>
|
/>
|
||||||
<ComboboxContent>
|
<ComboboxContent>
|
||||||
<ComboboxEmpty>
|
<ComboboxEmpty>
|
||||||
@ -868,8 +404,6 @@ export default function PurchaseEdit({ purchase, data }: Props) {
|
|||||||
)}
|
)}
|
||||||
</CardContent>
|
</CardContent>
|
||||||
</Card>
|
</Card>
|
||||||
</TabsContent>
|
|
||||||
</Tabs>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="space-y-6 md:col-span-1">
|
<div className="space-y-6 md:col-span-1">
|
||||||
@ -1020,15 +554,10 @@ export default function PurchaseEdit({ purchase, data }: Props) {
|
|||||||
disabled={
|
disabled={
|
||||||
processing ||
|
processing ||
|
||||||
uploading ||
|
uploading ||
|
||||||
variants.some(
|
|
||||||
(v) => v.uploading,
|
|
||||||
) ||
|
|
||||||
!supplierId ||
|
!supplierId ||
|
||||||
(mode === 'existing'
|
Object.values(
|
||||||
? Object.values(
|
|
||||||
quantities,
|
quantities,
|
||||||
).every((q) => q <= 0)
|
).every((q) => q <= 0)
|
||||||
: !name)
|
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
{processing
|
{processing
|
||||||
@ -1184,27 +713,6 @@ export default function PurchaseEdit({ purchase, data }: Props) {
|
|||||||
title={cartItems.find((i) => i.key === previewKey)?.title}
|
title={cartItems.find((i) => i.key === previewKey)?.title}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<ConfirmDialog
|
|
||||||
open={deleteConfirmOpen}
|
|
||||||
onOpenChange={(open) => {
|
|
||||||
if (!open) {
|
|
||||||
setDeleteConfirmOpen(false);
|
|
||||||
setDeleteVariantIndex(null);
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
title="Hapus Varian"
|
|
||||||
description="Apakah Anda yakin ingin menghapus varian ini?"
|
|
||||||
confirmLabel="Hapus"
|
|
||||||
onConfirm={() => {
|
|
||||||
if (deleteVariantIndex !== null) {
|
|
||||||
removeVariant(deleteVariantIndex);
|
|
||||||
}
|
|
||||||
|
|
||||||
setDeleteConfirmOpen(false);
|
|
||||||
setDeleteVariantIndex(null);
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
|
|
||||||
<ConfirmDialog
|
<ConfirmDialog
|
||||||
open={cartRemoveKey !== null}
|
open={cartRemoveKey !== null}
|
||||||
onOpenChange={(open) => {
|
onOpenChange={(open) => {
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user