const { useState } = React; const { Search, Trash2, Calendar, FileText, ShoppingCart, User, ChevronDown, ChevronUp, RefreshCw, Table, AlertCircle, CheckCircle2, FileSpreadsheet, Download } = window.lucide; function ScanHistory({ records, onRecordDeleted, onRecordSyncUpdated }) { const [search, setSearch] = useState(''); const [selectedCategory, setSelectedCategory] = useState('All'); const [expandedId, setExpandedId] = useState(null); const [syncingId, setSyncingId] = useState(null); const [clearing, setClearing] = useState(false); const [showExportDropdown, setShowExportDropdown] = useState(false); const filteredRecords = records.filter(record => { const matchesSearch = (record.orderId || '').toLowerCase().includes(search.toLowerCase()) || (record.customerName || '').toLowerCase().includes(search.toLowerCase()) || (record.fileName || '').toLowerCase().includes(search.toLowerCase()) || (record.items || []).some(item => (item.productName || '').toLowerCase().includes(search.toLowerCase())) || (record.trackingNumber || '').toLowerCase().includes(search.toLowerCase()) || (record.shippingProvider || '').toLowerCase().includes(search.toLowerCase()) || (record.routeCode || '').toLowerCase().includes(search.toLowerCase()); const matchesCategory = selectedCategory === 'All' || record.category === selectedCategory; return matchesSearch && matchesCategory; }); const totalAmount = filteredRecords .filter(r => r.status === 'success') .reduce((sum, r) => sum + r.totalAmount, 0); const stats = { total: filteredRecords.length, lazada: filteredRecords.filter(r => r.category === 'Lazada').length, shopee: filteredRecords.filter(r => r.category === 'Shopee').length, tiktok: filteredRecords.filter(r => r.category === 'TikTok Shop').length, others: filteredRecords.filter(r => r.category === 'Other').length }; const exportToCSV = (mode) => { if (filteredRecords.length === 0) return; let headers = []; let rows = []; if (mode === 'items') { headers = [ 'วันที่แสกน', 'หมวดหมู่', 'เลขที่คำสั่งซื้อ', 'วันที่สั่งซื้อ', 'บริษัทขนส่ง', 'หมายเลขพัสดุ (Tracking)', 'รหัสเส้นทาง', 'ช่องทางการชำระเงิน', 'ชื่อสินค้า', 'ราคาต่อหน่วย (บาท)', 'จำนวน', 'จำนวนเงินรวม (บาท)', 'ชื่อร้านค้าผู้ส่ง', 'ที่อยู่ผู้ส่ง', 'เบอร์โทรศัพท์ผู้ส่ง', 'ชื่อผู้รับ/ลูกค้า', 'ที่อยู่ผู้รับ', 'เบอร์โทรศัพท์ผู้รับ' ]; filteredRecords.forEach(record => { const baseData = [ new Date(record.timestamp).toLocaleString('th-TH'), record.category, record.orderId || '', record.orderDate || '', record.shippingProvider || '', record.trackingNumber || '', record.routeCode || '', record.paymentMethod || '' ]; const senderReceiverData = [ record.senderName || '', (record.senderAddress || '').replace(/"/g, '""').replace(/\n/g, ' '), record.senderPhone || '', record.customerName || '', (record.receiverAddress || '').replace(/"/g, '""').replace(/\n/g, ' '), record.receiverPhone || '' ]; if (record.items && record.items.length > 0) { record.items.forEach(item => { rows.push([ ...baseData, item.productName.replace(/"/g, '""').replace(/\n/g, ' '), item.price.toString(), item.quantity.toString(), item.amount.toString(), ...senderReceiverData ]); }); } else { rows.push([...baseData, '', '0', '0', '0', ...senderReceiverData]); } }); } else { headers = [ 'วันที่แสกน', 'หมวดหมู่', 'เลขที่คำสั่งซื้อ', 'วันที่สั่งซื้อ', 'บริษัทขนส่ง', 'หมายเลขพัสดุ (Tracking)', 'รหัสเส้นทาง', 'ช่องทางการชำระเงิน', 'ยอดชำระสุทธิ (บาท)', 'จำนวนรายการสินค้าทั้งหมด', 'ชื่อร้านค้าผู้ส่ง', 'ที่อยู่ผู้ส่ง', 'เบอร์โทรศัพท์ผู้ส่ง', 'ชื่อผู้รับ/ลูกค้า', 'ที่อยู่ผู้รับ', 'เบอร์โทรศัพท์ผู้รับ', 'รายการสินค้าด่วน' ]; filteredRecords.forEach(record => { const itemsSummary = (record.items || []).map(item => `${item.productName} (x${item.quantity})`).join(' | '); rows.push([ new Date(record.timestamp).toLocaleString('th-TH'), record.category, record.orderId || '', record.orderDate || '', record.shippingProvider || '', record.trackingNumber || '', record.routeCode || '', record.paymentMethod || '', record.totalAmount.toString(), (record.items || []).length.toString(), record.senderName || '', (record.senderAddress || '').replace(/"/g, '""').replace(/\n/g, ' '), record.senderPhone || '', record.customerName || '', (record.receiverAddress || '').replace(/"/g, '""').replace(/\n/g, ' '), record.receiverPhone || '', itemsSummary.replace(/"/g, '""').replace(/\n/g, ' ') ]); }); } const csvContent = [headers.join(','), ...rows.map(r => r.map(val => `"${val}"`).join(','))].join('\n'); const blob = new Blob([new Uint8Array([0xEF, 0xBB, 0xBF]), csvContent], { type: 'text/csv;charset=utf-8;' }); const link = document.createElement('a'); const url = URL.createObjectURL(blob); link.setAttribute('href', url); link.setAttribute('download', `sheetocr_export_${mode}_${Date.now()}.csv`); link.style.visibility = 'hidden'; document.body.appendChild(link); link.click(); document.body.removeChild(link); setShowExportDropdown(false); }; const exportSingleRecordToCSV = (record) => { const headers = [ 'เลขที่คำสั่งซื้อ', 'วันที่สั่งซื้อ', 'บริษัทขนส่ง', 'หมายเลขพัสดุ', 'รหัสเส้นทาง', 'ช่องการชำระเงิน', 'ชื่อผู้ส่ง', 'ที่อยู่ผู้ส่ง', 'เบอร์ผู้ส่ง', 'ชื่อผู้รับ', 'ที่อยู่ผู้รับ', 'เบอร์ผู้รับ', 'ชื่อสินค้า', 'ราคาต่อหน่วย', 'จำนวน', 'รวมราคา' ]; const rows = []; const baseData = [ record.orderId || '', record.orderDate || '', record.shippingProvider || '', record.trackingNumber || '', record.routeCode || '', record.paymentMethod || '', record.senderName || '', (record.senderAddress || '').replace(/"/g, '""').replace(/\n/g, ' '), record.senderPhone || '', record.customerName || '', (record.receiverAddress || '').replace(/"/g, '""').replace(/\n/g, ' '), record.receiverPhone || '' ]; if (record.items && record.items.length > 0) { record.items.forEach(item => { rows.push([ ...baseData, item.productName.replace(/"/g, '""').replace(/\n/g, ' '), item.price.toString(), item.quantity.toString(), item.amount.toString() ]); }); } else { rows.push([...baseData, '', '0', '0', '0']); } const csvContent = [headers.join(','), ...rows.map(r => r.map(val => `"${val}"`).join(','))].join('\n'); const blob = new Blob([new Uint8Array([0xEF, 0xBB, 0xBF]), csvContent], { type: 'text/csv;charset=utf-8;' }); const link = document.createElement('a'); const url = URL.createObjectURL(blob); link.setAttribute('href', url); link.setAttribute('download', `sheetocr_order_${record.orderId || record.id}.csv`); link.style.visibility = 'hidden'; document.body.appendChild(link); link.click(); document.body.removeChild(link); }; const handleDelete = async (id, e) => { e.stopPropagation(); if (!confirm('ยืนยันต้องการลบประวัติการสแกนรายการนี้หรือไม่?')) return; try { const res = await fetch(`api.php?action=history_delete&id=${id}`, { method: 'DELETE' }); if (res.ok) { onRecordDeleted(); } } catch (error) { console.error('Failed to delete history record:', error); } }; const handleClearAll = async () => { if (!confirm('คุณแน่ใจหรือไม่ว่าต้องการล้างประวัติการสแกนทั้งหมด? การกระทำนี้ไม่สามารถเรียกคืนได้')) return; setClearing(true); try { const res = await fetch('api.php?action=history_clear', { method: 'POST' }); if (res.ok) { onRecordDeleted(); } } catch (e) { console.error(e); } finally { setClearing(false); } }; const handleReSyncSheets = async (recordId, e) => { e.stopPropagation(); setSyncingId(recordId); try { const res = await fetch('api.php?action=re_sync_sheets', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ recordId }) }); if (res.ok) { onRecordSyncUpdated(); } } catch (err) { console.error(err); } finally { setSyncingId(null); } }; const toggleExpand = (id) => { setExpandedId(expandedId === id ? null : id); }; const getCategoryTheme = (category) => { switch (category) { case 'Lazada': return 'bg-blue-100 text-blue-800 border-blue-200'; case 'Shopee': return 'bg-orange-100 text-orange-800 border-orange-200'; case 'TikTok Shop': return 'bg-slate-100 text-slate-800 border-slate-200'; default: return 'bg-gray-100 text-gray-800 border-gray-200'; } }; return (
{/* Analytics Dashboard Grid */}
สแกนทั้งหมด {stats.total} ไฟล์
Lazada {stats.lazada} ใบปะหน้า
Shopee {stats.shopee} ใบปะหน้า
TikTok Shop {stats.tiktok} ใบปะหน้า
มูลค่ารวมที่สแกน {totalAmount.toLocaleString('th-TH', { maximumFractionDigits: 0 })} บาท (฿)
{/* Control bar */}
{/* Search */}
setSearch(e.target.value)} className="w-full text-xs pl-10 pr-4 py-2 border border-gray-200 rounded-lg focus:ring-2 focus:ring-indigo-100 focus:border-indigo-500 outline-none transition-all" />
{/* Filters & Export */}
{['All', 'Lazada', 'Shopee', 'TikTok Shop', 'Other'].map((cat) => ( ))} {/* Export Dropdown */} {filteredRecords.length > 0 && (
{showExportDropdown && ( <>
setShowExportDropdown(false)} />
)} {/* Record action buttons */}
{!isFailed ? ( ) : ( )}
)}
); })}
)} ); } window.ScanHistory = ScanHistory;