import { Head, Link, useForm } from '@inertiajs/react'; import { format } from 'date-fns'; import { Plus, Trash2, CalendarIcon, Minus, ShoppingCart, Search, ImagePlus, X, Loader, Save, ArrowLeft } from 'lucide-react'; import React, { useMemo, useState } from 'react'; import { toast } from 'sonner'; import { Badge } from '@/components/ui/badge'; import { Button } from '@/components/ui/button'; import { Calendar } from '@/components/ui/calendar'; import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card'; import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogFooter, } from "@/components/ui/dialog"; import { Empty, EmptyDescription, EmptyHeader, EmptyTitle } from '@/components/ui/empty'; import { Field, FieldError } from "@/components/ui/field"; import { Input } from "@/components/ui/input"; import { Label } from "@/components/ui/label"; import { Popover, PopoverContent, PopoverTrigger } from '@/components/ui/popover'; import { ScrollArea } from '@/components/ui/scroll-area'; import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue, } from "@/components/ui/select"; import { Sheet, SheetContent, SheetTrigger, SheetClose, } from "@/components/ui/sheet"; import { cn } from '@/lib/utils'; import purchaseRoutes from '@/routes/purchase'; import type { Product, ProductPrice, Purchase } from '@/types'; type CartItem = { product_id: number; quantity: number; unit_price: number; product: Product }; function getPurchasePrice(prices: ProductPrice[] | undefined): number { return prices?.find(p => p.price_type === 'purchase')?.price ?? 0; } function getPurchasePriceLabel(prices: ProductPrice[] | undefined): string { return prices?.find(p => p.price_type === 'purchase')?.price_formatted ?? 'Rp 0'; } export default function PurchaseEdit({ purchase, products }: { purchase: Purchase, products: Product[] }) { const [isCalendarOpen, setIsCalendarOpen] = useState(false); const [search, setSearch] = useState(''); const [selectedCategory, setSelectedCategory] = useState('all'); const [qtyDialogIndex, setQtyDialogIndex] = useState(null); const [qtyInputValue, setQtyInputValue] = useState(''); const categories = useMemo(() => { const map = new Map(); products.forEach(p => p.categories?.forEach(c => map.set(c.id, c.name))); return Array.from(map.entries()).map(([id, name]) => ({ id, name })); }, [products]); const { data, setData, patch, processing, errors } = useForm({ purchase_date: purchase.purchase_date || format(new Date(), 'yyyy-MM-dd'), note: purchase.note || '', items: (purchase.items?.map(item => ({ product_id: item.product_id, quantity: item.quantity, unit_price: item.unit_price, product: products.find(p => p.id === item.product_id) ?? item.product, })) ?? []) as CartItem[], }); const filteredProducts = products.filter(p => { const matchesSearch = p.name.toLowerCase().includes(search.toLowerCase()); const matchesCategory = selectedCategory === 'all' || p.categories?.some(c => String(c.id) === selectedCategory); return matchesSearch && matchesCategory; }); const getCartItem = (productId: number) => data.items.find(item => item.product_id === productId); const addToCart = (product: Product) => { const existingIndex = data.items.findIndex(i => i.product_id === product.id); const unitPrice = getPurchasePrice(product.prices); if (existingIndex > -1) { const newItems = [...data.items]; newItems[existingIndex].quantity += 1; setData('items', newItems); } else { setData('items', [ ...data.items, { product_id: product.id, quantity: 1, unit_price: unitPrice, product } ]); } }; const decreaseQuantity = (product: Product, e: React.MouseEvent) => { e.stopPropagation(); const existingIndex = data.items.findIndex(i => i.product_id === product.id); if (existingIndex === -1) { return; } const newItems = [...data.items]; if (newItems[existingIndex].quantity <= 1) { newItems.splice(existingIndex, 1); } else { newItems[existingIndex].quantity -= 1; } setData('items', newItems); }; const increaseQuantity = (product: Product, e: React.MouseEvent) => { e.stopPropagation(); addToCart(product); }; const removeFromCart = (productId: number) => { const newItems = data.items.filter(item => item.product_id !== productId); setData('items', newItems); }; const updateCartQuantity = (productId: number, quantity: number) => { if (quantity < 1) { return; } const newItems = [...data.items]; const index = newItems.findIndex(i => i.product_id === productId); if (index > -1) { newItems[index].quantity = quantity; setData('items', newItems); } }; const openQtyDialog = (item: CartItem, e: React.MouseEvent) => { e.stopPropagation(); setQtyInputValue(String(item.quantity)); setQtyDialogIndex(item.product_id); }; const confirmQty = () => { const val = parseInt(qtyInputValue); if (!isNaN(val) && val >= 1 && qtyDialogIndex !== null) { updateCartQuantity(qtyDialogIndex, val); } setQtyDialogIndex(null); }; const onSubmit = (e: React.FormEvent) => { e.preventDefault(); if (data.items.length === 0) { toast.error('Pilih minimal satu produk'); return; } patch(purchaseRoutes.update(purchase.id).url, { onSuccess: (response: any) => { toast.success(response.props.flash.success); }, }); }; const total = useMemo(() => { return data.items.reduce((acc, item) => acc + (item.quantity * item.unit_price), 0); }, [data.items]); const cartTotalItems = data.items.reduce((a, i) => a + i.quantity, 0); const CartFormContent = () => (
Keranjang {cartTotalItems} pcs {data.items.length === 0 ? (

Keranjang masih kosong

Klik produk untuk menambahkan

) : (
{data.items.map((item) => (
{/* Product info row */}
{item.product?.thumbnail_url ? ( {item.product.name} ) : (
)}

{item.product?.name}

Rp {(item.quantity * item.unit_price).toLocaleString('id-ID')}

{/* Qty + price text */}
{item.quantity} pcs
× Rp {item.unit_price.toLocaleString('id-ID')}
))}
)}
{/* Footer */}
{ if (selectedDate) { setData('purchase_date', format(selectedDate, 'yyyy-MM-dd')); } else { setData('purchase_date', ''); } setIsCalendarOpen(false); }} /> setData('note', e.target.value)} placeholder="...." />

Total Belanja

Rp {total.toLocaleString('id-ID')}

{data.items.length} produk

{cartTotalItems} pcs

); return (

Ubah Belanja

{/* ── Product Grid (Scrollable) ── */}
{/* Search + Category Filter */}
setSearch(e.target.value)} />
{/* Scrollable Area for Product Cards */}
{filteredProducts.map((product) => { const cartItem = getCartItem(product.id); const displayPrice = getPurchasePriceLabel(product.prices); return ( addToCart(product)} > {/* Full Image */}
{product.thumbnail_url ? ( {product.name} ) : (
)}
{/* Categories + Name */}
{product.categories?.map(cat => ( {cat.name} ))}

{product.name}

{/* Price + Stepper */}
e.stopPropagation()} >
{displayPrice}
); })} {filteredProducts.length === 0 && (
Ooops... Tidak ada data yang ditemukan.
)}
{/* ── Cart Sidebar (Fixed on Desktop) ── */}
Keranjang {cartTotalItems} pcs {data.items.length === 0 ? (

Keranjang masih kosong

Klik produk untuk menambahkan

) : (
{data.items.map((item) => (
{item.product?.thumbnail_url ? ( {item.product.name} ) : (
)}

{item.product?.name}

Rp {(item.quantity * item.unit_price).toLocaleString('id-ID')}

{item.quantity} pcs
× Rp {item.unit_price.toLocaleString('id-ID')}
))}
)}
{ if (selectedDate) { setData('purchase_date', format(selectedDate, 'yyyy-MM-dd')); } else { setData('purchase_date', ''); } setIsCalendarOpen(false); }} /> setData('note', e.target.value)} placeholder="...." />

Total Belanja

Rp {total.toLocaleString('id-ID')}

{data.items.length} produk

{cartTotalItems} pcs

{/* ── Floating Mobile Cart Trigger ── */}
{/* Header */}
Keranjang
{cartTotalItems} pcs
{/* Scrollable cart items — min-h-0 wajib agar flex-1 bisa scroll */}
{data.items.length === 0 ? (

Keranjang masih kosong

Klik produk untuk menambahkan

) : (
{data.items.map((item) => (
{item.product?.thumbnail_url ? ( {item.product.name} ) : (
)}

{item.product?.name}

Rp {(item.quantity * item.unit_price).toLocaleString('id-ID')}

{item.quantity} pcs
× Rp {item.unit_price.toLocaleString('id-ID')}
))}
)}
{/* Footer */}
{ if (selectedDate) { setData('purchase_date', format(selectedDate, 'yyyy-MM-dd')); } else { setData('purchase_date', ''); } }} /> setData('note', e.target.value)} placeholder="...." />

Total Belanja

Rp {total.toLocaleString('id-ID')}

{data.items.length} produk

{cartTotalItems} pcs

{/* Quantity Input Dialog */} { if (!open) { setQtyDialogIndex(null); } }}> Ubah Jumlah
setQtyInputValue(e.target.value)} onKeyDown={e => { if (e.key === 'Enter') { confirmQty(); } }} className="text-lg font-bold" autoFocus />
); } PurchaseEdit.layout = { breadcrumbs: [{ title: 'Kelola' }], };