Spaces:
Running
Running
| import React, { useState, useEffect } from 'react'; | |
| import { | |
| ShoppingBag, | |
| Plus, | |
| Minus, | |
| Trash2, | |
| CreditCard, | |
| Receipt, | |
| CheckCircle, | |
| X, | |
| ArrowLeft, | |
| User | |
| } from 'lucide-react'; | |
| const CartSidebar = ({ | |
| cart, | |
| isOpen, | |
| onClose, | |
| onRemoveItem, | |
| onUpdateQuantity, | |
| onCheckout | |
| }) => { | |
| const [discount, setDiscount] = useState(0); | |
| const [taxRate, setTaxRate] = useState(7); | |
| const [paymentMethod, setPaymentMethod] = useState('cash'); | |
| const [showSuccess, setShowSuccess] = useState(false); | |
| useEffect(() => { | |
| // Reset form when cart is empty | |
| if (cart.length === 0) { | |
| setShowSuccess(false); | |
| } | |
| }, [cart]); | |
| const subtotal = cart.reduce((sum, item) => { | |
| const price = item.discount > 0 | |
| ? item.price * (1 - item.discount/100) | |
| : item.price; | |
| return sum + (price * item.quantity); | |
| }, 0); | |
| const tax = subtotal * (taxRate / 100); | |
| const total = subtotal + tax - discount; | |
| const formatPrice = (price) => { | |
| return new Intl.NumberFormat('th-TH', { | |
| style: 'currency', | |
| currency: 'THB' | |
| }).format(price); | |
| }; | |
| const handleCheckout = () => { | |
| if (cart.length === 0) return; | |
| setShowSuccess(true); | |
| setTimeout(() => { | |
| setShowSuccess(false); | |
| onCheckout(); | |
| }, 3000); | |
| }; | |
| if (isOpen && cart.length === 0 && !showSuccess) { | |
| return ( | |
| <div className="fixed inset-0 bg-black/50 z-40 flex items-center justify-center"> | |
| <div className="bg-white rounded-2xl p-8 max-w-md w-full mx-4 text-center"> | |
| <div className="w-20 h-20 bg-pos-bg rounded-full flex items-center justify-center mx-auto mb-6"> | |
| <ShoppingBag className="w-10 h-10 text-pos-text-secondary" /> | |
| </div> | |
| <h3 className="text-xl font-bold text-pos-text mb-2">ตะกร้าสินค้าว่างเปล่า</h3> | |
| <p className="text-pos-text-secondary mb-6">เริ่มเลือกสินค้าเพื่อเริ่มต้นขาย</p> | |
| <button | |
| onClick={onClose} | |
| className="px-6 py-3 bg-primary-600 text-white rounded-xl font-medium hover:bg-primary-700 transition-colors" | |
| > | |
| กลับไปเลือกสินค้า | |
| </button> | |
| </div> | |
| </div> | |
| ); | |
| } | |
| return ( | |
| <> | |
| {/* Overlay */} | |
| <div | |
| className={`fixed inset-0 bg-black/50 z-40 transition-opacity duration-300 ${isOpen ? 'opacity-100' : 'opacity-0 pointer-events-none'}`} | |
| onClick={onClose} | |
| /> | |
| {/* Sidebar */} | |
| <div | |
| className={` | |
| fixed right-0 top-0 h-full w-full md:w-96 bg-white shadow-2xl z-50 transform transition-transform duration-300 | |
| ${isOpen ? 'translate-x-0' : 'translate-x-full'} | |
| `} | |
| > | |
| {showSuccess ? ( | |
| <div className="h-full flex flex-col items-center justify-center p-8 text-center"> | |
| <div className="w-24 h-24 bg-success/10 rounded-full flex items-center justify-center mb-6"> | |
| <CheckCircle className="w-12 h-12 text-success" /> | |
| </div> | |
| <h3 className="text-2xl font-bold text-pos-text mb-2">ขายสำเร็จ!</h3> | |
| <p className="text-pos-text-secondary mb-6">คำสั่งซื้อ #{Math.floor(Math.random() * 10000)} เสร็จสมบูรณ์</p> | |
| <div className="w-full bg-pos-bg p-4 rounded-xl mb-8"> | |
| <div className="flex justify-between mb-2"> | |
| <span className="text-pos-text-secondary">ยอดรวม</span> | |
| <span className="font-medium">{formatPrice(subtotal)}</span> | |
| </div> | |
| <div className="flex justify-between mb-2"> | |
| <span className="text-pos-text-secondary">ภาษี (7%)</span> | |
| <span className="font-medium">{formatPrice(tax)}</span> | |
| </div> | |
| <div className="flex justify-between mb-2"> | |
| <span className="text-pos-text-secondary">ส่วนลด</span> | |
| <span className="font-medium text-danger">-{formatPrice(discount)}</span> | |
| </div> | |
| <div className="border-t border-pos-border pt-2 mt-2 flex justify-between font-bold text-lg"> | |
| <span>ยอดรวมทั้งสิ้น</span> | |
| <span className="text-primary-600">{formatPrice(total)}</span> | |
| </div> | |
| </div> | |
| <p className="text-sm text-pos-text-secondary">กำลังสร้างใบเสร็จ...</p> | |
| </div> | |
| ) : ( | |
| <div className="h-full flex flex-col"> | |
| {/* Header */} | |
| <div className="p-4 border-b border-pos-border flex items-center justify-between"> | |
| <div className="flex items-center gap-2"> | |
| <button | |
| onClick={onClose} | |
| className="p-2 rounded-lg hover:bg-pos-bg transition-colors md:hidden" | |
| > | |
| <ArrowLeft className="w-5 h-5 text-pos-text" /> | |
| </button> | |
| <div> | |
| <h2 className="text-lg font-bold text-pos-text">ตะกร้าสินค้า</h2> | |
| <p className="text-sm text-pos-text-secondary">{cart.length} รายการ</p> | |
| </div> | |
| </div> | |
| <button | |
| onClick={() => { | |
| if (window.confirm('ต้องการลบสินค้าทั้งหมดในตะกร้าหรือไม่?')) { | |
| onCheckout(true); | |
| } | |
| className="p-2 text-danger hover:bg-danger/10 rounded-lg transition-colors" | |
| > | |
| <Trash2 className="w-5 h-5" /> | |
| </button> | |
| </div> | |
| {/* Cart Items */} | |
| <div className="flex-1 overflow-y-auto p-4"> | |
| {cart.length === 0 ? ( | |
| <div className="h-full flex flex-col items-center justify-center text-center opacity-50"> | |
| <ShoppingBag className="w-16 h-16 mb-4 text-pos-text-secondary" /> | |
| <p className="text-pos-text-secondary">ไม่มีสินค้าในตะกร้า</p> | |
| </div> | |
| ) : ( | |
| <div className="space-y-4"> | |
| {cart.map((item) => { | |
| const price = item.discount > 0 | |
| ? item.price * (1 - item.discount/100) | |
| : item.price; | |
| const itemTotal = price * item.quantity; | |
| return ( | |
| <div key={item.id} className="flex gap-4 bg-pos-bg p-3 rounded-xl"> | |
| <div className="w-20 h-20 flex-shrink-0 rounded-lg overflow-hidden"> | |
| <img | |
| src={item.image} | |
| alt={item.name} | |
| className="w-full h-full object-cover" | |
| /> | |
| </div> | |
| <div className="flex-1 flex flex-col justify-between"> | |
| <div> | |
| <h3 className="font-medium text-pos-text line-clamp-1">{item.name}</h3> | |
| <p className="text-sm text-pos-text-secondary"> | |
| {formatPrice(price)} x {item.quantity} | |
| </p> | |
| </div> | |
| <div className="flex items-center justify-between mt-2"> | |
| <div className="flex items-center gap-2 bg-white rounded-lg p-1"> | |
| <button | |
| onClick={() => onUpdateQuantity(item.id, Math.max(1, item.quantity - 1))} | |
| className="w-6 h-6 flex items-center justify-center rounded-md bg-pos-bg hover:bg-primary-100 text-primary-600 transition-colors" | |
| > | |
| <Minus className="w-3 h-3" /> | |
| </button> | |
| <span className="text-sm font-medium w-6 text-center">{item.quantity}</span> | |
| <button | |
| onClick={() => onUpdateQuantity(item.id, item.quantity + 1)} | |
| className="w-6 h-6 flex items-center justify-center rounded-md bg-pos-bg hover:bg-primary-100 text-primary-600 transition-colors" | |
| > | |
| <Plus className="w-3 h-3" /> | |
| </button> | |
| </div> | |
| <div className="flex flex-col items-end"> | |
| <span className="font-bold text-primary-600">{formatPrice(itemTotal)}</span> | |
| {item.discount > 0 && ( | |
| <span className="text-xs text-danger"> | |
| -{item.discount}% ลดให้ | |
| </span> | |
| )} | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| ); | |
| })} | |
| </div> | |
| )} | |
| </div> | |
| {/* Cart Summary */} | |
| <div className="border-t border-pos-border p-4 bg-white"> | |
| <div className="space-y-3 mb-4"> | |
| <div className="flex justify-between items-center"> | |
| <span className="text-pos-text-secondary">ยอดรวมสินค้า</span> | |
| <span className="font-medium">{formatPrice(subtotal)}</span> | |
| </div> | |
| <div className="flex items-center justify-between"> | |
| <div className="flex items-center gap-2"> | |
| <span className="text-pos-text-secondary">ส่วนลด</span> | |
| <div className="relative"> | |
| <input | |
| type="number" | |
| value={discount} | |
| onChange={(e) => setDiscount(Math.max(0, Math.min(subtotal, parseFloat(e.target.value) || 0)))} | |
| className="w-20 p-2 rounded-lg border border-pos-border focus:ring-2 focus:ring-primary-500 focus:border-transparent outline-none text-right" | |
| placeholder="0.00" | |
| /> | |
| <span className="absolute right-3 top-1/2 transform -translate-y-1/2 text-pos-text-secondary">฿</span> | |
| </div> | |
| </div> | |
| <span className="text-danger font-medium">-{formatPrice(discount)}</span> | |
| </div> | |
| <div className="flex justify-between items-center"> | |
| <div className="flex items-center gap-2"> | |
| <span className="text-pos-text-secondary">ภาษี ({taxRate}%)</span> | |
| <span className="font-medium">{formatPrice(tax)}</span> | |
| </div> | |
| </div> | |
| <div className="border-t border-pos-border pt-3 flex justify-between items-center"> | |
| <span className="text-lg font-bold text-pos-text">ยอดรวมทั้งสิ้น</span> | |
| <span className="text-2xl font-bold text-primary-600">{formatPrice(total)}</span> | |
| </div> | |
| </div> | |
| {/* Payment Options */} | |
| <div className="mb-4"> | |
| <h3 className="text-sm font-medium text-pos-text mb-2">วิธีการชำระเงิน</h3> | |
| <div className="grid grid-cols-3 gap-2"> | |
| {[ | |
| { id: 'cash', icon: 'Cash', label: 'เงินสด' }, | |
| { id: 'card', icon: 'CreditCard', label: 'บัตรเครดิต' }, | |
| { id: 'qr', icon: 'Smartphone', label: 'QR Code' }, | |
| ].map((method) => ( | |
| <button | |
| key={method.id} | |
| onClick={() => setPaymentMethod(method.id)} | |
| className={`flex flex-col items-center p-3 rounded-xl border transition-all ${ | |
| paymentMethod === method.id | |
| ? 'border-primary-600 bg-primary-50 text-primary-600' | |
| : 'border-pos-border hover:bg-pos-bg' | |
| }`} | |
| > | |
| {method.id === 'cash' && <span className="text-lg font-bold mb-1">Cash</span>} | |
| {method.id === 'card' && <CreditCard className="w-5 h-5 mb-1" />} | |
| {method.id === 'qr' && <span className="text-lg font-bold mb-1">QR</span>} | |
| <span className="text-xs font-medium">{method.label}</span> | |
| </button> | |
| ))} | |
| </div> | |
| </div> | |
| {/* Checkout Button */} | |
| <button | |
| onClick={handleCheckout} | |
| disabled={cart.length === 0} | |
| className="w-full py-4 bg-primary-600 text-white rounded-xl font-bold text-lg hover:bg-primary-700 transition-colors disabled:opacity-50 disabled:cursor-not-allowed flex items-center justify-center gap-2" | |
| > | |
| <ShoppingBag className="w-5 h-5" /> | |
| {cart.length === 0 ? 'ตะกร้าว่างเปล่า' : `ชำระเงิน (${formatPrice(total)})`} | |
| </button> | |
| </div> | |
| </div> | |
| )} | |
| </div> | |
| </> | |
| ); | |
| }; | |
| export default CartSidebar; |