"use client"; import React, { useState } from "react"; import { Box, Grid, Paper, Typography, Button, Dialog, DialogTitle, DialogContent, DialogActions, TextField, Stack, Table, TableBody, TableCell, TableContainer, TableHead, TableRow, Tabs, Tab // ← Added for tabs } from "@mui/material"; import { FileDownload, Print, SettingsEthernet, Lan, Router } from "@mui/icons-material"; import dayjs from "dayjs"; import { NEXT_PUBLIC_API_URL } from "@/config/api"; import { clientAuthFetch } from "@/app/utils/clientAuthFetch"; import * as XLSX from "xlsx"; // Simple TabPanel component for conditional rendering interface TabPanelProps { children?: React.ReactNode; index: number; value: number; } function TabPanel(props: TabPanelProps) { const { children, value, index, ...other } = props; return ( ); } export default function TestingPage() { // Tab state const [tabValue, setTabValue] = useState(0); const handleTabChange = (event: React.SyntheticEvent, newValue: number) => { setTabValue(newValue); }; // --- 1. TSC Section States --- const [tscConfig, setTscConfig] = useState({ ip: '192.168.1.100', port: '9100' }); const [tscItems, setTscItems] = useState([ { id: 1, itemCode: 'FG-001', itemName: 'Yellow Curry Sauce', lotNo: 'LOT-TSC-01', expiryDate: '2025-12-01' }, { id: 2, itemCode: 'FG-002', itemName: 'Red Curry Paste', lotNo: 'LOT-TSC-02', expiryDate: '2025-12-05' }, ]); // --- 2. DataFlex Section States --- const [dfConfig, setDfConfig] = useState({ ip: '192.168.1.101', port: '9100' }); const [dfItems, setDfItems] = useState([ { id: 1, itemCode: 'DF-101', itemName: 'Instant Noodle A', lotNo: 'LOT-DF-01', expiryDate: '2026-01-10' }, { id: 2, itemCode: 'DF-102', itemName: 'Instant Noodle B', lotNo: 'LOT-DF-02', expiryDate: '2026-01-15' }, ]); // --- 3. OnPack Section States --- const [isPrinterModalOpen, setIsPrinterModalOpen] = useState(false); const [printerFormData, setPrinterFormData] = useState({ itemCode: '', lotNo: '', expiryDate: dayjs().format('YYYY-MM-DD'), productName: '' }); // --- 4. Laser Section States --- const [laserConfig, setLaserConfig] = useState({ ip: '192.168.1.102', port: '8080' }); const [laserItems, setLaserItems] = useState([ { id: 1, templateId: 'JOB_001', lotNo: 'L-LASER-01', expiryDate: '2025-12-31', power: '50' }, ]); // --- 5. HANS600S-M Section States --- const [hansConfig, setHansConfig] = useState({ ip: '192.168.76.10', port: '45678' }); const [hansItems, setHansItems] = useState([ { id: 1, textChannel3: 'SN-HANS-001-20260117', // channel 3 (e.g. serial / text1) textChannel4: 'BATCH-HK-TEST-OK', // channel 4 (e.g. batch / text2) text3ObjectName: 'Text3', // EZCAD object name for channel 3 text4ObjectName: 'Text4' // EZCAD object name for channel 4 }, ]); // --- 6. GRN Preview (M18) --- const [grnPreviewReceiptDate, setGrnPreviewReceiptDate] = useState("2026-03-16"); // --- 7. M18 PO Sync by Code --- const [m18PoCode, setM18PoCode] = useState(""); const [isSyncingM18Po, setIsSyncingM18Po] = useState(false); const [m18PoSyncResult, setM18PoSyncResult] = useState(""); // Generic handler for inline table edits const handleItemChange = (setter: any, id: number, field: string, value: string) => { setter((prev: any[]) => prev.map(item => item.id === id ? { ...item, [field]: value } : item )); }; // --- API CALLS --- // TSC Print (Section 1) const handleTscPrint = async (row: any) => { const payload = { ...row, printerIp: tscConfig.ip, printerPort: tscConfig.port }; try { const response = await clientAuthFetch(`${NEXT_PUBLIC_API_URL}/plastic/print-tsc`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(payload) }); if (response.status === 401 || response.status === 403) return; if (response.ok) alert(`TSC Print Command Sent for ${row.itemCode}!`); else alert("TSC Print Failed"); } catch (e) { console.error("TSC Error:", e); } }; // DataFlex Print (Section 2) const handleDfPrint = async (row: any) => { const payload = { ...row, printerIp: dfConfig.ip, printerPort: dfConfig.port }; try { const response = await clientAuthFetch(`${NEXT_PUBLIC_API_URL}/plastic/print-dataflex`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(payload) }); if (response.status === 401 || response.status === 403) return; if (response.ok) alert(`DataFlex Print Command Sent for ${row.itemCode}!`); else alert("DataFlex Print Failed"); } catch (e) { console.error("DataFlex Error:", e); } }; // OnPack Zip Download (Section 3) const handleDownloadPrintJob = async () => { const params = new URLSearchParams(printerFormData); try { const response = await clientAuthFetch(`${NEXT_PUBLIC_API_URL}/plastic/get-printer6?${params.toString()}`, { method: 'GET', }); if (response.status === 401 || response.status === 403) return; if (!response.ok) throw new Error('Download failed'); const blob = await response.blob(); const url = window.URL.createObjectURL(blob); const link = document.createElement('a'); link.href = url; link.setAttribute('download', `${printerFormData.lotNo || 'OnPack'}.zip`); document.body.appendChild(link); link.click(); link.remove(); window.URL.revokeObjectURL(url); setIsPrinterModalOpen(false); } catch (e) { console.error("OnPack Error:", e); } }; // Laser Print (Section 4 - original) const handleLaserPrint = async (row: any) => { const payload = { ...row, printerIp: laserConfig.ip, printerPort: laserConfig.port }; try { const response = await clientAuthFetch(`${NEXT_PUBLIC_API_URL}/plastic/print-laser`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(payload) }); if (response.status === 401 || response.status === 403) return; if (response.ok) alert(`Laser Command Sent: ${row.templateId}`); } catch (e) { console.error(e); } }; const handleLaserPreview = async (row: any) => { const payload = { ...row, printerIp: laserConfig.ip, printerPort: parseInt(laserConfig.port) }; try { const response = await clientAuthFetch(`${NEXT_PUBLIC_API_URL}/plastic/preview-laser`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(payload) }); if (response.status === 401 || response.status === 403) return; if (response.ok) alert("Red light preview active!"); } catch (e) { console.error("Preview Error:", e); } }; // HANS600S-M TCP Print (Section 5) const handleHansPrint = async (row: any) => { const payload = { printerIp: hansConfig.ip, printerPort: hansConfig.port, textChannel3: row.textChannel3, textChannel4: row.textChannel4, text3ObjectName: row.text3ObjectName, text4ObjectName: row.text4ObjectName }; try { const response = await clientAuthFetch(`${NEXT_PUBLIC_API_URL}/plastic/print-laser-tcp`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(payload) }); if (response.status === 401 || response.status === 403) return; const result = await response.text(); if (response.ok) { alert(`HANS600S-M Mark Success: ${result}`); } else { alert(`HANS600S-M Failed: ${result}`); } } catch (e) { console.error("HANS600S-M Error:", e); alert("HANS600S-M Connection Error"); } }; // GRN Preview CSV Download (Section 6) const handleDownloadGrnPreviewXlsx = async () => { try { const response = await clientAuthFetch( `${NEXT_PUBLIC_API_URL}/report/grn-preview-m18?receiptDate=${encodeURIComponent(grnPreviewReceiptDate)}`, { method: "GET" }, ); if (response.status === 401 || response.status === 403) return; if (!response.ok) throw new Error(`Download failed: ${response.status}`); const data = await response.json(); const rows = Array.isArray(data?.rows) ? data.rows : []; const ws = XLSX.utils.json_to_sheet(rows); const wb = XLSX.utils.book_new(); XLSX.utils.book_append_sheet(wb, ws, "GRN Preview"); const xlsxArrayBuffer = XLSX.write(wb, { bookType: "xlsx", type: "array" }); const blob = new Blob([xlsxArrayBuffer], { type: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", }); const url = window.URL.createObjectURL(blob); const link = document.createElement("a"); link.href = url; link.setAttribute("download", `grn-preview-m18-${grnPreviewReceiptDate}.xlsx`); document.body.appendChild(link); link.click(); link.remove(); window.URL.revokeObjectURL(url); } catch (e) { console.error("GRN Preview XLSX Download Error:", e); alert("GRN Preview XLSX download failed. Check console/network."); } }; // M18 PO Sync By Code (Section 7) const handleSyncM18PoByCode = async () => { if (!m18PoCode.trim()) { alert("Please enter PO code."); return; } setIsSyncingM18Po(true); setM18PoSyncResult(""); try { const response = await clientAuthFetch( `${NEXT_PUBLIC_API_URL}/m18/test/po-by-code?code=${encodeURIComponent(m18PoCode.trim())}`, { method: "GET" }, ); if (response.status === 401 || response.status === 403) return; const text = await response.text(); setM18PoSyncResult(text); if (!response.ok) { alert(`Sync failed: ${response.status}`); } } catch (e) { console.error("M18 PO Sync By Code Error:", e); alert("M18 PO sync failed. Check console/network."); } finally { setIsSyncingM18Po(false); } }; // Layout Helper const Section = ({ title, children }: { title: string, children?: React.ReactNode }) => ( {title} {children || Waiting for implementation...} ); return ( Printer Testing
setTscConfig({...tscConfig, ip: e.target.value})} /> setTscConfig({...tscConfig, port: e.target.value})} /> Code Name Lot Expiry Action {tscItems.map(row => ( handleItemChange(setTscItems, row.id, 'itemCode', e.target.value)} /> handleItemChange(setTscItems, row.id, 'itemName', e.target.value)} /> handleItemChange(setTscItems, row.id, 'lotNo', e.target.value)} /> handleItemChange(setTscItems, row.id, 'expiryDate', e.target.value)} /> ))}
setDfConfig({...dfConfig, ip: e.target.value})} /> setDfConfig({...dfConfig, port: e.target.value})} /> Code Name Lot Expiry Action {dfItems.map(row => ( handleItemChange(setDfItems, row.id, 'itemCode', e.target.value)} /> handleItemChange(setDfItems, row.id, 'itemName', e.target.value)} /> handleItemChange(setDfItems, row.id, 'lotNo', e.target.value)} /> handleItemChange(setDfItems, row.id, 'expiryDate', e.target.value)} /> ))}
Calls /plastic/get-printer6 to generate CoLOS .job bundle.
setLaserConfig({...laserConfig, ip: e.target.value})} /> setLaserConfig({...laserConfig, port: e.target.value})} /> Template Lot Exp Pwr% Action {laserItems.map(row => ( handleItemChange(setLaserItems, row.id, 'templateId', e.target.value)} /> handleItemChange(setLaserItems, row.id, 'lotNo', e.target.value)} /> handleItemChange(setLaserItems, row.id, 'expiryDate', e.target.value)} /> handleItemChange(setLaserItems, row.id, 'power', e.target.value)} /> ))}
Note: HANS Laser requires pre-saved templates on the controller.
setHansConfig({...hansConfig, ip: e.target.value})} /> setHansConfig({...hansConfig, port: e.target.value})} /> Ch3 Text (SN) Ch4 Text (Batch) Obj3 Name Obj4 Name Action {hansItems.map(row => ( handleItemChange(setHansItems, row.id, 'textChannel3', e.target.value)} sx={{ minWidth: 180 }} /> handleItemChange(setHansItems, row.id, 'textChannel4', e.target.value)} sx={{ minWidth: 140 }} /> handleItemChange(setHansItems, row.id, 'text3ObjectName', e.target.value)} size="small" /> handleItemChange(setHansItems, row.id, 'text4ObjectName', e.target.value)} size="small" /> ))}
TCP Push to EZCAD3 (Ch3/Ch4 via E3_SetTextObject) | IP:192.168.76.10:45678 | Backend: /print-laser-tcp
setGrnPreviewReceiptDate(e.target.value)} InputLabelProps={{ shrink: true }} /> Backend endpoint: /report/grn-preview-m18?receiptDate=YYYY-MM-DD
setM18PoCode(e.target.value)} placeholder="e.g. PFP002PO26030341" sx={{ minWidth: 320 }} /> Backend endpoint: /m18/test/po-by-code?code=YOUR_CODE {m18PoSyncResult ? ( ) : null}
{/* Dialog for OnPack */} setIsPrinterModalOpen(false)} fullWidth maxWidth="sm"> OnPack Printer Job Details setPrinterFormData({ ...printerFormData, itemCode: e.target.value })} /> setPrinterFormData({ ...printerFormData, lotNo: e.target.value })} /> setPrinterFormData({ ...printerFormData, productName: e.target.value })} /> setPrinterFormData({ ...printerFormData, expiryDate: e.target.value })} />
); }