import { Head, Link, router, useForm } from '@inertiajs/react'; import { ArrowLeft, Check, ImagePlus, Loader, Minus, Plus, Save, Search, ShoppingCart, Tag, Trash2, X } from 'lucide-react'; import React, { useMemo, useState } from 'react'; import { NumericFormat } from 'react-number-format'; import { toast } from 'sonner'; import { Badge } from '@/components/ui/badge'; import { Button } from '@/components/ui/button'; import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card'; import { Dialog, DialogContent, DialogFooter, DialogHeader, DialogTitle, } 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 { ScrollArea } from '@/components/ui/scroll-area'; import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue, } from "@/components/ui/select"; import { Sheet, SheetContent, SheetTrigger } from "@/components/ui/sheet"; import { cn } from '@/lib/utils'; import { formatCurrency, formatNumber } from '@/lib/formatters'; import * as orderRoutes from '@/routes/order'; import type { Product } from '@/types'; import type { OrderItem } from '@/types/order'; type CartItem = OrderItem & { id: number }; type EnumOption = { value: string, label: string }; export default function OrderCreate({ products, cartItems, orderStatus, orderChannels, paymentMethods, priceTypes }: { products: Product[], cartItems: CartItem[], orderStatus: EnumOption[], orderChannels: EnumOption[], paymentMethods: EnumOption[], priceTypes: EnumOption[] }) { const [search, setSearch] = useState(''); const [selectedCategory, setSelectedCategory] = useState('all'); const [qtyDialogIndex, setQtyDialogIndex] = useState(null); const [qtyInputValue, setQtyInputValue] = useState(''); // Default price type for the catalog const [globalPriceType, setGlobalPriceType] = useState('retail'); 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, post, processing, errors, transform } = useForm({ customer_name: '', subtotal: 0, discount: 0, payment: 0, payment_method: 'cash', order_status: 'delivered', order_channel: 'store', items: [] as any[], }); 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, priceType: string) => cartItems.find(item => item.product_id === productId && item.price_type === priceType); const getProductPrice = (product: Product, priceType: string) => { return product.prices?.find(p => p.price_type === priceType)?.price || 0; }; const addToCart = (product: Product, priceType: string) => { const price = getProductPrice(product, priceType); router.post(orderRoutes.addToCart().url, { product_id: product.id, qty: 1, price: price, price_type: priceType }, { preserveScroll: true, }); }; const decreaseQuantity = (item: CartItem, e: React.MouseEvent) => { e.stopPropagation(); router.post(orderRoutes.addToCart().url, { product_id: item.product_id, qty: -1, price: item.price, price_type: item.price_type }, { preserveScroll: true, }); }; const increaseQuantity = (item: CartItem, e: React.MouseEvent) => { e.stopPropagation(); router.post(orderRoutes.addToCart().url, { product_id: item.product_id, qty: 1, price: item.price, price_type: item.price_type }, { preserveScroll: true, }); }; const removeFromCart = (itemId: number) => { router.delete(orderRoutes.removeFromCart(itemId).url, { preserveScroll: true, }); }; const updateCartQuantity = (itemId: number, qty: number) => { if (qty < 1) { return; } router.patch(orderRoutes.updateCartItem(itemId).url, { qty }, { preserveScroll: true, }); }; const openQtyDialog = (item: CartItem, e: React.MouseEvent) => { e.stopPropagation(); setQtyInputValue(String(item.qty)); setQtyDialogIndex(item.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 (cartItems.length === 0) { toast.error('Pilih minimal satu produk'); return; } transform((data) => ({ ...data, subtotal: subtotal, items: cartItems.map(item => ({ product_id: item.product_id, qty: item.qty, price: item.price, total: item.total, price_type: item.price_type })) })); post(orderRoutes.store().url, { onSuccess: (response: any) => { const flash = response.props.flash; if (flash?.error) { toast.error(flash.error); } else if (flash?.success) { toast.success(flash.success); } }, }); }; const subtotal = useMemo(() => { return cartItems.reduce((acc, item) => acc + item.total, 0); }, [cartItems]); const total = subtotal - (Number(data.discount) || 0); const change = (Number(data.payment) || 0) - total; const cartTotalItems = cartItems.reduce((a, i) => a + i.qty, 0); const PriceTypeLabel = ({ type }: { type: string }) => { const option = priceTypes.find(opt => opt.value === type); return option ? option.label : type; }; const CartFormContent = () => (
Keranjang {cartTotalItems} pcs {cartItems.length === 0 ? (

Keranjang masih kosong

Klik produk untuk menambahkan

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

{item.product?.name}

{formatCurrency(item.total)}

{item.qty}
× {formatCurrency(item.price)}
))}
)}
setData('customer_name', e.target.value)} autoComplete="off" placeholder="Nama Pelanggan" />
Subtotal {formatCurrency(subtotal)}
Potongan / Diskon
{ setData('discount', values.floatValue || 0) }} placeholder="Rp 0" autoComplete='off' />
Total {formatCurrency(total)}
{ setData('payment', values.floatValue || 0) }} placeholder="Rp 0" autoComplete='off' /> {change >= 0 && (Number(data.payment) || 0) > 0 && (
Kembalian {formatCurrency(change)}
)}
); return (

Tambah Pesanan

setSearch(e.target.value)} />
{filteredProducts.map((product) => { const cartItem = getCartItem(product.id, globalPriceType); const currentPrice = getProductPrice(product, globalPriceType); return ( addToCart(product, globalPriceType)} >
{product.thumbnail_url ? ( {product.name} ) : (
)} {cartItem && (
{cartItem.qty}
)}
{product.categories?.map(cat => ( {cat.name} ))}

{product.name}

{/* Price + Stepper */}
e.stopPropagation()} >
Harga {formatCurrency(currentPrice)}
); })}
{filteredProducts.length === 0 && (
Produk tidak ditemukan Coba kata kunci lain atau kategori berbeda.
)}
{CartFormContent()}
{CartFormContent()}
{/* 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 />
); } OrderCreate.layout = { breadcrumbs: [ { title: 'Kelola' }, ], };