import { Form, Head, Link, usePage } from '@inertiajs/react'; import { ArrowLeft, Check, ClipboardPaste, Copy, Plus, Trash2, } from 'lucide-react'; import { useCallback, useRef, useState } from 'react'; import { toast } from 'sonner'; import { ConfirmDialog } from '@/components/dialogs'; import { FileUpload } from '@/components/inputs'; import { InputError } from '@/components/ui'; import { NumberInput } from '@/components/inputs'; import { RupiahInput } from '@/components/inputs'; import { Button } from '@/components/ui/button'; import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card'; import { Input } from '@/components/ui/input'; import { Label } from '@/components/ui/label'; import { RadioGroup, RadioGroupItem } from '@/components/ui/radio-group'; import { useRawMaterialDraftSave } from '@/hooks/use-raw-material-draft'; import { UNITS } from '@/lib/constants'; import { loadRawMaterialDraft } from '@/lib/raw-material-draft'; import { getTemporaryUrl } from '@/lib/upload'; import { index as rawMaterialIndex, store, } from '@/routes/admin/master/raw-materials'; type VariantState = { variant: string; price: number; stock: number; photo: string | null; photoUrl: string | null; uploading: boolean; }; export default function RawMaterialCreate() { const { auth } = usePage().props as { auth: { user?: { id?: number } } }; const userId = auth.user?.id; const draft = loadRawMaterialDraft('create', userId); const [name, setName] = useState(draft?.name ?? ''); const [unit, setUnit] = useState(draft?.unit ?? 'kg'); const [variants, setVariants] = useState(() => { if (draft?.variants && draft.variants.length > 0) { return draft.variants.map((v) => ({ variant: v.variant, price: v.price, stock: v.stock, photo: v.photo ?? null, photoUrl: v.photo ? getTemporaryUrl(v.photo) : null, uploading: false, })); } return [ { variant: '', price: 0, stock: 0, photo: null, photoUrl: null, uploading: false, }, ]; }); const variantsRef = useRef(variants); variantsRef.current = variants; const draftData = { name, unit, isActive: true, variants: variants.map((v) => ({ variant: v.variant, price: v.price, stock: v.stock, photo: v.photo ?? undefined, })), }; useRawMaterialDraftSave('create', draftData, userId); 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)[field] = value; return updated; }); }, [], ); const [copiedIndex, setCopiedIndex] = useState(null); const [deleteConfirmOpen, setDeleteConfirmOpen] = useState(false); const [deleteVariantIndex, setDeleteVariantIndex] = useState( 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 }, ); }); }, []); function getPayload() { return { name, unit, is_active: true, variants: variantsRef.current.map((v) => ({ variant: v.variant, price: Number(v.price), stock: Number(v.stock), photo_key: v.photo, })), }; } return ( <>

Tambah Bahan Baku

({ ...data, ...getPayload(), })} onError={() => { toast.error('Ada data yang belum sesuai, silakan periksa kembali input Anda.'); }} > {({ errors, processing }) => ( <>
Informasi Bahan Baku
setName(e.target.value) } placeholder="Masukkan nama bahan baku" />
{UNITS.map((u) => (
))}
Varian Bahan Baku {variants.map( (variant, variantIndex) => (

Varian{' '} {variantIndex + 1}

{variants.length > 1 && ( )}
updateVariant( variantIndex, 'variant', e.target .value, ) } placeholder="Contoh: Ukuran L, Warna Merah" />
updateVariant( variantIndex, 'price', val, ) } />
updateVariant( variantIndex, 'stock', val, ) } />
{ updateVariant( variantIndex, 'photo', key, ); updateVariant( variantIndex, 'photoUrl', key ? getTemporaryUrl( key, ) : null, ); }} folder="raw-material-variant" existingUrl={ variant.photoUrl } onUploadingChange={( uploading, ) => updateVariant( variantIndex, 'uploading', uploading, ) } />
), )}
)}
{ 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); }} />
); }