import React, { useState, useEffect } from 'react'; import { Card, Form, Input, Select, Button, Table, Modal, Descriptions, Divider, message, Space, Tag, Row, Col, InputNumber, Steps, Upload, Tooltip, Badge, Statistic, Progress, Alert, } from 'antd'; import { ShoppingCartOutlined, UploadOutlined, CheckCircleOutlined, CloseCircleOutlined, SyncOutlined, DownloadOutlined, FileExcelOutlined, UserOutlined, DeleteOutlined, EyeOutlined, } from '@ant-design/icons'; import type { ColumnsType } from 'antd/es/table'; import { b2bTradeDataSource, BatchOrder as BatchOrderType, BatchOrderItem, Customer } from '@/services/b2bTradeDataSource'; const { Option } = Select; const { TextArea } = Input; const BATCH_STATUS_MAP: Record = { DRAFT: { color: 'default', text: 'Draft', icon: }, PENDING_REVIEW: { color: 'processing', text: 'Pending Review', icon: }, CONFIRMED: { color: 'blue', text: 'Confirmed', icon: }, PROCESSING: { color: 'blue', text: 'Processing', icon: }, COMPLETED: { color: 'success', text: 'Completed', icon: }, CANCELLED: { color: 'error', text: 'Cancelled', icon: }, }; const ITEM_STATUS_MAP: Record = { VALID: { color: 'success', text: 'Valid' }, INVALID: { color: 'error', text: 'Invalid' }, PENDING: { color: 'warning', text: 'Pending' }, }; export const B2BTradeBatchOrder: React.FC = () => { const [form] = Form.useForm(); const [loading, setLoading] = useState(false); const [batchOrders, setBatchOrders] = useState([]); const [customers, setCustomers] = useState([]); const [orderItems, setOrderItems] = useState([]); const [currentStep, setCurrentStep] = useState(0); const [createModalVisible, setCreateModalVisible] = useState(false); const [detailModalVisible, setDetailModalVisible] = useState(false); const [selectedBatch, setSelectedBatch] = useState(null); const [selectedCustomer, setSelectedCustomer] = useState(null); const [fileList, setFileList] = useState([]); const [stats, setStats] = useState({ total: 0, pending: 0, processing: 0, completed: 0, totalAmount: 0, }); useEffect(() => { fetchBatchOrders(); fetchCustomers(); }, []); const fetchBatchOrders = async () => { setLoading(true); try { const orders = await b2bTradeDataSource.fetchBatchOrders(); setBatchOrders(orders); calculateStats(orders); } catch (error) { message.error('Failed to load batch orders'); } finally { setLoading(false); } }; const fetchCustomers = async () => { try { const data = await b2bTradeDataSource.fetchCustomers(); setCustomers(data); } catch (error) { message.error('Failed to load customers'); } }; const calculateStats = (orders: BatchOrderType[]) => { setStats({ total: orders.length, pending: orders.filter((o) => o.status === 'PENDING_REVIEW').length, processing: orders.filter((o) => o.status === 'PROCESSING').length, completed: orders.filter((o) => o.status === 'COMPLETED').length, totalAmount: orders.filter((o) => o.status === 'COMPLETED').reduce((sum, o) => sum + o.totalAmount, 0), }); }; const handleCustomerChange = (customerId: string) => { const customer = customers.find((c) => c.id === customerId); setSelectedCustomer(customer || null); }; const handleFileUpload = (info: any) => { setFileList(info.fileList.slice(-1)); if (info.file.status === 'done' || info.file) { parseUploadedFile(info.file); } }; const parseUploadedFile = async (file: any) => { try { const items = await b2bTradeDataSource.parseUploadFile(file, selectedCustomer?.id || ''); setOrderItems(items); setCurrentStep(1); message.success('File parsed successfully'); } catch (error) { message.error('Failed to parse file'); } }; const handleRemoveItem = (key: string) => { setOrderItems(orderItems.filter((item) => item.key !== key)); }; const handleValidateItems = async () => { setLoading(true); try { const result = await b2bTradeDataSource.validateItems(orderItems); setOrderItems(result); const validCount = result.filter(i => i.status === 'VALID').length; const invalidCount = result.filter(i => i.status === 'INVALID').length; message.success(`Validation complete: ${validCount} valid, ${invalidCount} invalid`); } catch (error) { message.error('Validation failed'); } finally { setLoading(false); } }; const handleSubmitBatch = async () => { try { const values = await form.validateFields(); const validItems = orderItems.filter((i) => i.status === 'VALID'); if (validItems.length === 0) { message.error('No valid items to submit'); return; } setLoading(true); await b2bTradeDataSource.createBatchOrder({ customerId: values.customerId, items: validItems, }); message.success('Batch order submitted successfully'); setCurrentStep(2); } catch (error) { message.error('Failed to submit batch order'); } finally { setLoading(false); } }; const handleViewDetail = (batch: BatchOrderType) => { setSelectedBatch(batch); setDetailModalVisible(true); }; const handleApproveBatch = async (batchId: string) => { setLoading(true); try { await b2bTradeDataSource.approveBatchOrder(batchId); message.success('Batch order approved'); fetchBatchOrders(); } catch (error) { message.error('Failed to approve batch order'); } finally { setLoading(false); } }; const handleDownloadTemplate = () => { message.info('Downloading template...'); }; const itemColumns: ColumnsType = [ { title: 'Line', dataIndex: 'lineNumber', key: 'lineNumber', width: 60 }, { title: 'SKU', dataIndex: 'sku', key: 'sku', width: 100 }, { title: 'Product', dataIndex: 'productName', key: 'productName' }, { title: 'Qty', dataIndex: 'quantity', key: 'quantity', width: 80 }, { title: 'Unit Price', dataIndex: 'unitPrice', key: 'unitPrice', width: 100, render: (price: number) => `$${price.toFixed(2)}`, }, { title: 'Total', dataIndex: 'totalPrice', key: 'totalPrice', width: 100, render: (price: number) => `$${price.toFixed(2)}`, }, { title: 'Status', dataIndex: 'status', key: 'status', width: 90, render: (status: string) => { const config = ITEM_STATUS_MAP[status]; return {config.text}; }, }, { title: 'Error', dataIndex: 'error', key: 'error', width: 150, render: (error?: string) => error ? {error} : '-', }, { title: 'Action', key: 'action', width: 80, render: (_, record) => ( } > `Total ${total} batches`, }} /> setCreateModalVisible(false)} footer={null} width={1000} > {currentStep === 0 && (
{selectedCustomer && ( )} Upload Order File
false} maxCount={1} >
Supported formats: Excel (.xlsx, .xls), CSV (.csv)
)} {currentStep === 1 && ( <>
} /> } />