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'; const { Option } = Select; const { TextArea } = Input; interface BatchOrderItem { key: string; lineNumber: number; productId: string; sku: string; productName: string; quantity: number; unitPrice: number; totalPrice: number; customerId: string; customerName: string; status: 'VALID' | 'INVALID' | 'PENDING'; error?: string; } interface BatchOrder { id: string; batchId: string; customerId: string; customerName: string; totalItems: number; totalAmount: number; currency: string; status: 'DRAFT' | 'PENDING_REVIEW' | 'CONFIRMED' | 'PROCESSING' | 'COMPLETED' | 'CANCELLED'; createdAt: string; validItems: number; invalidItems: number; } interface Customer { id: string; name: string; company: string; tier: 'BASIC' | 'PRO' | 'ENTERPRISE'; } 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 BatchOrder: 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 mockOrders: BatchOrder[] = [ { id: '1', batchId: 'BO-2026-001', customerId: 'CUST_001', customerName: 'ABC Trading Co.', totalItems: 50, totalAmount: 25000.00, currency: 'USD', status: 'CONFIRMED', createdAt: '2026-03-18 10:00:00', validItems: 48, invalidItems: 2, }, { id: '2', batchId: 'BO-2026-002', customerId: 'CUST_002', customerName: 'XYZ Electronics Ltd.', totalItems: 100, totalAmount: 45000.00, currency: 'USD', status: 'PENDING_REVIEW', createdAt: '2026-03-17 14:30:00', validItems: 95, invalidItems: 5, }, { id: '3', batchId: 'BO-2026-003', customerId: 'CUST_003', customerName: 'Global Import Inc.', totalItems: 200, totalAmount: 85000.00, currency: 'USD', status: 'COMPLETED', createdAt: '2026-03-15 09:00:00', validItems: 200, invalidItems: 0, }, ]; setBatchOrders(mockOrders); calculateStats(mockOrders); } catch (error) { message.error('Failed to load batch orders'); } finally { setLoading(false); } }; const fetchCustomers = async () => { const mockCustomers: Customer[] = [ { id: 'CUST_001', name: 'ABC Trading Co.', company: 'ABC Trading', tier: 'ENTERPRISE' }, { id: 'CUST_002', name: 'XYZ Electronics Ltd.', company: 'XYZ Electronics', tier: 'PRO' }, { id: 'CUST_003', name: 'Global Import Inc.', company: 'Global Import', tier: 'ENTERPRISE' }, ]; setCustomers(mockCustomers); }; const calculateStats = (orders: BatchOrder[]) => { 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 = (file: any) => { const mockItems: BatchOrderItem[] = [ { key: '1', lineNumber: 1, productId: 'PROD_001', sku: 'SKU-001', productName: 'Wireless Headphones', quantity: 100, unitPrice: 22.00, totalPrice: 2200.00, customerId: selectedCustomer?.id || '', customerName: selectedCustomer?.name || '', status: 'VALID' }, { key: '2', lineNumber: 2, productId: 'PROD_002', sku: 'SKU-002', productName: 'USB-C Cable', quantity: 500, unitPrice: 4.50, totalPrice: 2250.00, customerId: selectedCustomer?.id || '', customerName: selectedCustomer?.name || '', status: 'VALID' }, { key: '3', lineNumber: 3, productId: 'PROD_003', sku: 'SKU-003', productName: 'Phone Case', quantity: 200, unitPrice: 7.00, totalPrice: 1400.00, customerId: selectedCustomer?.id || '', customerName: selectedCustomer?.name || '', status: 'VALID' }, { key: '4', lineNumber: 4, productId: 'PROD_004', sku: 'SKU-004', productName: 'Invalid Product', quantity: 50, unitPrice: 0, totalPrice: 0, customerId: selectedCustomer?.id || '', customerName: selectedCustomer?.name || '', status: 'INVALID', error: 'Product not found' }, ]; setOrderItems(mockItems); setCurrentStep(1); message.success('File parsed successfully'); }; const handleRemoveItem = (key: string) => { setOrderItems(orderItems.filter((item) => item.key !== key)); }; const handleValidateItems = () => { setLoading(true); setTimeout(() => { const validCount = orderItems.filter((i) => i.status === 'VALID').length; const invalidCount = orderItems.filter((i) => i.status === 'INVALID').length; message.success(`Validation complete: ${validCount} valid, ${invalidCount} invalid`); setLoading(false); }, 1000); }; 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); const totalAmount = validItems.reduce((sum, item) => sum + item.totalPrice, 0); const batchData = { customerId: values.customerId, items: validItems, totalAmount, note: values.note, }; console.log('Submitting batch order:', batchData); await new Promise((resolve) => setTimeout(resolve, 1000)); message.success('Batch order submitted successfully'); setCurrentStep(2); } catch (error) { message.error('Failed to submit batch order'); } finally { setLoading(false); } }; const handleViewDetail = (batch: BatchOrder) => { setSelectedBatch(batch); setDetailModalVisible(true); }; const handleApproveBatch = async (batchId: string) => { setLoading(true); try { console.log('Approving batch order:', batchId); await new Promise((resolve) => setTimeout(resolve, 500)); 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 && ( <>
} /> } />