import { InventoryLotLineResult, InventoryResult } from "@/app/api/inventory"; import { Dispatch, SetStateAction, useCallback, useEffect, useMemo, useRef, useState } from "react"; import SaveIcon from "@mui/icons-material/Save"; import EditIcon from "@mui/icons-material/Edit"; import RestartAltIcon from "@mui/icons-material/RestartAlt"; import { useTranslation } from "react-i18next"; import { Column } from "../SearchResults"; import SearchResults, { defaultPagingController, defaultSetPagingController } from "../SearchResults/SearchResults"; import { arrayToDateString } from "@/app/utils/formatUtil"; import { Box, Card, Checkbox, FormControlLabel, Grid, IconButton, Modal, TextField, Typography, Button, Chip } from "@mui/material"; import useUploadContext from "../UploadProvider/useUploadContext"; import { downloadFile } from "@/app/utils/commonUtil"; import { fetchQrCodeByLotLineId, LotLineToQrcode } from "@/app/api/pdf/actions"; import QrCodeIcon from "@mui/icons-material/QrCode"; import PrintIcon from "@mui/icons-material/Print"; import SwapHoriz from "@mui/icons-material/SwapHoriz"; import CloseIcon from "@mui/icons-material/Close"; import { Autocomplete } from "@mui/material"; import { WarehouseResult } from "@/app/api/warehouse"; import { fetchWarehouseListClient } from "@/app/api/warehouse/client"; import { createStockTransfer } from "@/app/api/inventory/actions"; import { msg, msgError } from "@/components/Swal/CustomAlerts"; import { PrinterCombo } from "@/app/api/settings/printer"; import { printLabelForInventoryLotLine } from "@/app/api/pdf/actions"; import TuneIcon from "@mui/icons-material/Tune"; import AddIcon from "@mui/icons-material/Add"; import { Table, TableBody, TableCell, TableHead, TableRow } from "@mui/material"; import DeleteIcon from "@mui/icons-material/Delete"; import { INPUT_DATE_FORMAT } from "@/app/utils/formatUtil"; import { LocalizationProvider } from "@mui/x-date-pickers/LocalizationProvider"; import { DatePicker } from "@mui/x-date-pickers/DatePicker"; import { AdapterDayjs } from "@mui/x-date-pickers/AdapterDayjs"; import dayjs from "dayjs"; import CheckIcon from "@mui/icons-material/Check"; import { submitStockAdjustment, StockAdjustmentLineRequest } from "@/app/api/stockAdjustment/actions"; type AdjustmentEntry = InventoryLotLineResult & { adjustedQty: number; originalQty?: number; productlotNo?: string; dnNo?: string; isNew?: boolean; isOpeningInventory?: boolean; remarks?: string; }; interface Props { inventoryLotLines: InventoryLotLineResult[] | null; setPagingController: defaultSetPagingController; pagingController: typeof defaultPagingController; totalCount: number; inventory: InventoryResult | null; filterLotNo?: string; onStockTransferSuccess?: () => void | Promise; printerCombo?: PrinterCombo[]; onStockAdjustmentSuccess?: () => void | Promise; } const InventoryLotLineTable: React.FC = ({ inventoryLotLines, pagingController, setPagingController, totalCount, inventory, filterLotNo, onStockTransferSuccess, printerCombo = [], onStockAdjustmentSuccess, }) => { const { t } = useTranslation(["inventory"]); const PRINT_PRINTER_ID_KEY = 'inventoryLotLinePrintPrinterId'; const { setIsUploading } = useUploadContext(); const [stockTransferModalOpen, setStockTransferModalOpen] = useState(false); const [selectedLotLine, setSelectedLotLine] = useState(null); const [startLocation, setStartLocation] = useState(""); const [targetLocation, setTargetLocation] = useState(null); // Store warehouse ID instead of code const [targetLocationInput, setTargetLocationInput] = useState(""); const [qtyToBeTransferred, setQtyToBeTransferred] = useState(""); const [warehouses, setWarehouses] = useState([]); const [printModalOpen, setPrintModalOpen] = useState(false); const [lotLineForPrint, setLotLineForPrint] = useState(null); const [printPrinter, setPrintPrinter] = useState(null); const [printQty, setPrintQty] = useState(1); const [stockAdjustmentModalOpen, setStockAdjustmentModalOpen] = useState(false); const [pendingRemovalLineId, setPendingRemovalLineId] = useState(null); const [removalReasons, setRemovalReasons] = useState>({}); const [addEntryModalOpen, setAddEntryModalOpen] = useState(false); const [addEntryForm, setAddEntryForm] = useState({ lotNo: '', qty: 0, expiryDate: '', locationId: null as number | null, locationInput: '', productlotNo: '', dnNo: '', isOpeningInventory: false, remarks: '', }); const originalAdjustmentLinesRef = useRef([]); const [adjustmentEntries, setAdjustmentEntries] = useState([]); useEffect(() => { if (stockTransferModalOpen) { fetchWarehouseListClient() .then(setWarehouses) .catch(console.error); } }, [stockTransferModalOpen]); useEffect(() => { if (addEntryModalOpen) { fetchWarehouseListClient() .then(setWarehouses) .catch(console.error); } }, [addEntryModalOpen]); const availableLotLines = useMemo(() => { const base = (inventoryLotLines ?? []).filter((line) => line.status?.toLowerCase() === "available"); const f = filterLotNo?.trim?.() ? filterLotNo.trim() : ''; if (!f) return base; return base.filter((line) => line.lotNo === f); }, [inventoryLotLines, filterLotNo]); const originalQty = selectedLotLine?.availableQty || 0; const validatedTransferQty = useMemo(() => { const raw = (qtyToBeTransferred ?? '').replace(/\D/g, ''); if (raw === '') return 0; const parsed = parseInt(raw, 10); if (Number.isNaN(parsed)) return 0; if (originalQty < 1) return 0; const minClamped = Math.max(1, parsed); return Math.min(minClamped, originalQty); }, [qtyToBeTransferred, originalQty]); const remainingQty = originalQty - validatedTransferQty; const prevAdjustmentModalOpenRef = useRef(false); useEffect(() => { const wasOpen = prevAdjustmentModalOpenRef.current; prevAdjustmentModalOpenRef.current = stockAdjustmentModalOpen; if (stockAdjustmentModalOpen && inventory) { // Only init when we transition to open (modal just opened) if (!wasOpen) { const initial = (availableLotLines ?? []).map((line) => ({ ...line, adjustedQty: line.availableQty ?? 0, originalQty: line.availableQty ?? 0, remarks: '', })); setAdjustmentEntries(initial); originalAdjustmentLinesRef.current = initial; } setPendingRemovalLineId(null); setRemovalReasons({}); } }, [stockAdjustmentModalOpen, inventory, availableLotLines]); const handleAdjustmentReset = useCallback(() => { setPendingRemovalLineId(null); setRemovalReasons({}); setAdjustmentEntries( (availableLotLines ?? []).map((line) => ({ ...line, adjustedQty: line.availableQty ?? 0, originalQty: line.availableQty ?? 0, remarks: '', })) ); }, [availableLotLines]); const handleAdjustmentQtyChange = useCallback((lineId: number, value: number) => { setAdjustmentEntries((prev) => prev.map((line) => line.id === lineId ? { ...line, adjustedQty: Math.max(0, value) } : line ) ); }, []); const handleAdjustmentRemarksChange = useCallback((lineId: number, value: string) => { setAdjustmentEntries((prev) => prev.map((line) => line.id === lineId ? { ...line, remarks: value } : line ) ); }, []); const handleRemoveAdjustmentLine = useCallback((lineId: number) => { setAdjustmentEntries((prev) => prev.filter((line) => line.id !== lineId)); }, []); const handleRemoveClick = useCallback((lineId: number) => { setPendingRemovalLineId((prev) => (prev === lineId ? null : lineId)); }, []); const handleRemovalReasonChange = useCallback((lineId: number, value: string) => { setRemovalReasons((prev) => ({ ...prev, [lineId]: value })); }, []); const handleConfirmRemoval = useCallback((lineId: number) => { setAdjustmentEntries((prev) => prev.filter((line) => line.id !== lineId)); setPendingRemovalLineId(null); }, []); const handleCancelRemoval = useCallback(() => { setPendingRemovalLineId(null); }, []); const hasAdjustmentChange = useMemo(() => { const original = originalAdjustmentLinesRef.current; const current = adjustmentEntries; if (original.length !== current.length) return true; const origById = new Map(original.map((line) => [line.id, { adjustedQty: line.adjustedQty ?? 0, remarks: line.remarks ?? '' }])); for (const line of current) { const o = origById.get(line.id); if (!o) return true; if (o.adjustedQty !== (line.adjustedQty ?? 0) || (o.remarks ?? '') !== (line.remarks ?? '')) return true; } return false; }, [adjustmentEntries]); const toApiLine = useCallback((line: AdjustmentEntry, itemCode: string): StockAdjustmentLineRequest => { const [y, m, d] = Array.isArray(line.expiryDate) ? line.expiryDate : []; const expiryDate = y != null && m != null && d != null ? `${y}-${String(m).padStart(2, '0')}-${String(d).padStart(2, '0')}` : ''; return { id: line.id, lotNo: line.lotNo ?? null, adjustedQty: line.adjustedQty ?? 0, productlotNo: line.productlotNo ?? null, dnNo: line.dnNo ?? null, isOpeningInventory: line.isOpeningInventory ?? false, isNew: line.isNew ?? false, itemId: line.item?.id ?? 0, itemNo: line.item?.code ?? itemCode, expiryDate, warehouseId: line.warehouse?.id ?? 0, uom: line.uom ?? null, }; }, []); const handleAdjustmentSave = useCallback(async () => { if (!inventory) return; const itemCode = inventory.itemCode; const originalLines = originalAdjustmentLinesRef.current.map((line) => toApiLine(line, itemCode)); const currentLines = adjustmentEntries.map((line) => toApiLine(line, itemCode)); try { setIsUploading(true); await submitStockAdjustment({ itemId: inventory.itemId, originalLines, currentLines, }); msg(t("Saved successfully")); setStockAdjustmentModalOpen(false); await onStockAdjustmentSuccess?.(); } catch (e: unknown) { const message = e instanceof Error ? e.message : String(e); msgError(message || t("Save failed")); } finally { setIsUploading(false); } }, [adjustmentEntries, inventory, t, toApiLine, onStockAdjustmentSuccess]); const handleOpenAddEntry = useCallback(() => { setAddEntryForm({ lotNo: '', qty: 0, expiryDate: '', locationId: null, locationInput: '', productlotNo: '', dnNo: '', isOpeningInventory: false, remarks: '', }); setAddEntryModalOpen(true); }, []); const handleAddEntrySubmit = useCallback(() => { if (addEntryForm.qty < 0 || !addEntryForm.expiryDate || !addEntryForm.locationId || !inventory) return; const warehouse = warehouses.find(w => w.id === addEntryForm.locationId); if (!warehouse) return; const [y, m, d] = addEntryForm.expiryDate.split('-').map(Number); const newEntry: AdjustmentEntry = { id: -Date.now(), lotNo: addEntryForm.lotNo.trim() || '', item: { id: inventory.itemId, code: inventory.itemCode, name: inventory.itemName, type: inventory.itemType }, warehouse: { id: warehouse.id, code: warehouse.code, name: warehouse.name }, inQty: 0, outQty: 0, holdQty: 0, expiryDate: [y, m, d], status: 'available', availableQty: addEntryForm.qty, uom: inventory.uomUdfudesc || inventory.uomShortDesc || inventory.uomCode, qtyPerSmallestUnit: inventory.qtyPerSmallestUnit ?? 1, baseUom: inventory.baseUom || '', stockInLineId: 0, originalQty: 0, adjustedQty: addEntryForm.qty, productlotNo: addEntryForm.productlotNo.trim() || undefined, dnNo: addEntryForm.dnNo.trim() || undefined, isNew: true, isOpeningInventory: addEntryForm.isOpeningInventory, remarks: addEntryForm.remarks?.trim() ?? '', }; setAdjustmentEntries(prev => [...prev, newEntry]); setAddEntryModalOpen(false); }, [addEntryForm, inventory, warehouses]); const downloadQrCode = useCallback(async (lotLineId: number) => { setIsUploading(true); // const postData = { stockInLineIds: [42,43,44] }; const postData: LotLineToQrcode = { inventoryLotLineId: lotLineId } const response = await fetchQrCodeByLotLineId(postData); if (response) { downloadFile(new Uint8Array(response.blobValue), response.filename!); } setIsUploading(false); }, [setIsUploading]); const handleStockTransfer = useCallback( (lotLine: InventoryLotLineResult) => { setSelectedLotLine(lotLine); setStockTransferModalOpen(true); setStartLocation(lotLine.warehouse.code || ""); setTargetLocation(null); setTargetLocationInput(""); setQtyToBeTransferred(""); }, [], ); const handlePrintClick = useCallback((lotLine: InventoryLotLineResult) => { setLotLineForPrint(lotLine); const labelPrinters = (printerCombo || []).filter(p => p.type === 'Label'); const savedId = typeof sessionStorage !== 'undefined' ? sessionStorage.getItem(PRINT_PRINTER_ID_KEY) : null; const savedPrinter = savedId ? labelPrinters.find(p => p.id === Number(savedId)) : null; setPrintPrinter(savedPrinter ?? labelPrinters[0] ?? null); setPrintQty(1); setPrintModalOpen(true); }, [printerCombo]); const handlePrintConfirm = useCallback(async () => { if (!lotLineForPrint || !printPrinter) return; try { setIsUploading(true); await printLabelForInventoryLotLine({ inventoryLotLineId: lotLineForPrint.id, printerId: printPrinter.id, printQty, }); msg(t("Print sent")); setPrintModalOpen(false); } catch (e: any) { msgError(e?.message ?? t("Print failed")); } finally { setIsUploading(false); } }, [lotLineForPrint, printPrinter, printQty, setIsUploading, t]); const onDetailClick = useCallback( (lotLine: InventoryLotLineResult) => { downloadQrCode(lotLine.id) // lot line id to find stock in line }, [downloadQrCode], ); const columns = useMemo[]>( () => [ // { // name: "item", // label: t("Code"), // renderCell: (params) => { // return params.item.code; // }, // }, // { // name: "item", // label: t("Name"), // renderCell: (params) => { // return params.item.name; // }, // }, { name: "lotNo", label: t("Lot No"), }, // { // name: "item", // label: t("Type"), // renderCell: (params) => { // return t(params.item.type); // }, // }, { name: "availableQty", label: t("Available Qty"), align: "right", headerAlign: "right", type: "integer", }, { name: "uom", label: t("Stock UoM"), align: "left", headerAlign: "left", }, // { // name: "qtyPerSmallestUnit", // label: t("Available Qty Per Smallest Unit"), // align: "right", // headerAlign: "right", // type: "integer", // }, // { // name: "baseUom", // label: t("Base UoM"), // align: "left", // headerAlign: "left", // }, { name: "expiryDate", label: t("Expiry Date"), renderCell: (params) => { return arrayToDateString(params.expiryDate) }, }, { name: "warehouse", label: t("Warehouse"), renderCell: (params) => { return `${params.warehouse.code}` }, }, { name: "id", label: t("Download QR Code"), onClick: onDetailClick, buttonIcon: , align: "center", headerAlign: "center", }, { name: "id", label: t("Print QR Code"), onClick: handlePrintClick, buttonIcon: , align: "center", headerAlign: "center", }, { name: "id", label: t("Stock Transfer"), onClick: handleStockTransfer, buttonIcon: , align: "center", headerAlign: "center", }, // { // name: "status", // label: t("Status"), // type: "icon", // icons: { // available: , // unavailable: , // }, // colors: { // available: "success", // unavailable: "error", // } // }, ], [t, onDetailClick, downloadQrCode, handleStockTransfer, handlePrintClick], ); const handleCloseStockTransferModal = useCallback(() => { setStockTransferModalOpen(false); setSelectedLotLine(null); setStartLocation(""); setTargetLocation(null); setTargetLocationInput(""); setQtyToBeTransferred(""); }, []); const handleSubmitStockTransfer = useCallback(async () => { if (!selectedLotLine || !targetLocation || validatedTransferQty < 1 || validatedTransferQty > originalQty) { return; } try { setIsUploading(true); const request = { inventoryLotLineId: selectedLotLine.id, transferredQty: validatedTransferQty, warehouseId: targetLocation, // targetLocation now contains warehouse ID }; const response = await createStockTransfer(request); if (response && response.type === "success") { msg(t("Stock transfer successful")); handleCloseStockTransferModal(); await onStockTransferSuccess?.(); } else { throw new Error(response?.message || t("Failed to transfer stock")); } } catch (error: any) { console.error("Error transferring stock:", error); msgError(error?.message || t("Failed to transfer stock. Please try again.")); } finally { setIsUploading(false); } }, [selectedLotLine, targetLocation, validatedTransferQty, originalQty, handleCloseStockTransferModal, setIsUploading, t, onStockTransferSuccess]); return <> {inventory ? `${t("Item selected")}: ${inventory.itemCode} | ${inventory.itemName} (${t(inventory.itemType)})` : t("No items are selected yet.")} {inventory && ( } label={t("Stock Adjustment")} onClick={() => setStockAdjustmentModalOpen(true)} sx={{ cursor: 'pointer', height: 30, fontWeight: 'bold', '& .MuiChip-label': { fontSize: '0.875rem', fontWeight: 'bold', }, '& .MuiChip-icon': { fontSize: '1rem', }, }} /> )} items={availableLotLines} columns={columns} pagingController={pagingController} setPagingController={setPagingController} totalCount={totalCount} /> {inventory && selectedLotLine ? `${inventory.itemCode} ${inventory.itemName} (${selectedLotLine.lotNo})` : t("Stock Transfer") } {t("to")} w.code !== startLocation)} getOptionLabel={(option) => option.code || ""} value={targetLocation ? warehouses.find(w => w.id === targetLocation) || null : null} inputValue={targetLocationInput} onInputChange={(event, newInputValue) => { setTargetLocationInput(newInputValue); if (targetLocation && newInputValue !== warehouses.find(w => w.id === targetLocation)?.code) { setTargetLocation(null); } }} onChange={(event, newValue) => { if (newValue) { setTargetLocation(newValue.id); setTargetLocationInput(newValue.code); } else { setTargetLocation(null); setTargetLocationInput(""); } }} filterOptions={(options, { inputValue }) => { if (!inputValue || inputValue.trim() === "") return options; const searchTerm = inputValue.toLowerCase().trim(); return options.filter((option) => (option.code || "").toLowerCase().includes(searchTerm) || (option.name || "").toLowerCase().includes(searchTerm) || (option.description || "").toLowerCase().includes(searchTerm) ); }} isOptionEqualToValue={(option, value) => option.id === value.id} autoHighlight={false} autoSelect={false} clearOnBlur={false} renderOption={(props, option) => (
  • {option.code}
  • )} renderInput={(params) => ( )} />
    - { const raw = e.target.value.replace(/\D/g, ''); if (raw === '') { setQtyToBeTransferred(''); return; } const parsed = parseInt(raw, 10); if (Number.isNaN(parsed)) { setQtyToBeTransferred(''); return; } if (originalQty < 1) { setQtyToBeTransferred(''); return; } const clamped = Math.min(Math.max(1, parsed), originalQty); setQtyToBeTransferred(String(clamped)); }} onFocus={(e) => (e.target as HTMLInputElement).select()} inputProps={{ pattern: "[0-9]*" }} InputLabelProps={{ shrink: true, sx: { fontSize: "0.9375rem" }, }} /> =
    setPrintModalOpen(false)} sx={{ display: 'flex', alignItems: 'center', justifyContent: 'center' }} > {t("Print QR Code")} setPrintModalOpen(false)}> printer.type === 'Label')} getOptionLabel={(opt) => opt.name ?? opt.label ?? opt.code ?? `Printer ${opt.id}`} value={printPrinter} onChange={(_, v) => { setPrintPrinter(v); if (typeof sessionStorage !== 'undefined') { if (v?.id != null) sessionStorage.setItem(PRINT_PRINTER_ID_KEY, String(v.id)); else sessionStorage.removeItem(PRINT_PRINTER_ID_KEY); } }} renderInput={(params) => } /> setPrintQty(Math.max(1, parseInt(e.target.value) || 1))} inputProps={{ min: 1 }} fullWidth /> setStockAdjustmentModalOpen(false)} sx={{ display: 'flex', alignItems: 'center', justifyContent: 'center', }} > {inventory ? `${t("Edit mode")}: ${inventory.itemCode} ${inventory.itemName}` : t("Stock Adjustment") } setStockAdjustmentModalOpen(false)}> {/* List view */} {t("Lot No")} {t("Original Qty")} {t("Adjusted Qty")} {t("Difference")} {t("Stock UoM")} {t("Expiry Date")} {t("Location")} {t("Remarks")} {t("Action")} {adjustmentEntries.map((line) => ( {line.lotNo?.trim() ? line.lotNo : t("No lot no entered, will be generated by system.")} {line.isOpeningInventory && ` (${t("Opening Inventory")})`} {line.productlotNo && {t("productLotNo")}: {line.productlotNo}} {line.dnNo && {t("dnNo")}: {line.dnNo}} {line.originalQty ?? 0} { const raw = e.target.value.replace(/\D/g, ''); if (raw === '') { handleAdjustmentQtyChange(line.id, 0); return; } const num = parseInt(raw, 10); if (!Number.isNaN(num) && num >= 0) handleAdjustmentQtyChange(line.id, num); }} inputProps={{ style: { textAlign: 'right' } }} size="small" sx={{ width: 120, '& .MuiInputBase-root': { display: 'flex', alignItems: 'center', height: 56, }, '& .MuiInputBase-input': { fontSize: 16, textAlign: 'right', height: 40, lineHeight: '40px', paddingTop: 0, paddingBottom: 0, boxSizing: 'border-box', MozAppearance: 'textfield', }, '& .MuiInputBase-input::-webkit-outer-spin-button': { WebkitAppearance: 'none', margin: 0, }, '& .MuiInputBase-input::-webkit-inner-spin-button': { WebkitAppearance: 'none', margin: 0, }, }} /> {(() => { const diff = line.adjustedQty - (line.originalQty ?? 0); const text = diff > 0 ? `+${diff}` : diff < 0 ? `${diff}` : '±0'; const color = diff > 0 ? 'success.main' : diff < 0 ? 'error.main' : 'text.secondary'; return {text}; })()} {line.uom} {arrayToDateString(line.expiryDate)} {line.warehouse?.code ?? ""} {pendingRemovalLineId === line.id ? ( handleRemovalReasonChange(line.id, e.target.value)} sx={{ width: 160, maxWidth: '100%', '& .MuiInputBase-root': { display: 'flex', alignItems: 'center', height: 56, }, '& .MuiInputBase-input': { fontSize: '1rem', height: 40, lineHeight: '40px', paddingTop: 0, paddingBottom: 0, boxSizing: 'border-box', '&::placeholder': { color: '#9e9e9e', opacity: 1 }, }, }} /> ) : (line.adjustedQty - (line.originalQty ?? 0)) !== 0 ? ( handleAdjustmentRemarksChange(line.id, e.target.value)} sx={{ width: 160, maxWidth: '100%', '& .MuiInputBase-root': { display: 'flex', alignItems: 'center', height: 56, }, '& .MuiInputBase-input': { fontSize: '1rem', height: 40, lineHeight: '40px', paddingTop: 0, paddingBottom: 0, boxSizing: 'border-box', '&::placeholder': { color: '#9e9e9e', opacity: 1 }, }, }} /> ) : null} {pendingRemovalLineId === line.id ? ( ) : ( handleRemoveClick(line.id)} color="error" title={t("Remove")} > )} ))}
    setAddEntryModalOpen(false)} sx={{ display: 'flex', alignItems: 'center', justifyContent: 'center' }} > {t("Add entry")} setAddEntryModalOpen(false)}> setAddEntryForm(f => ({ ...f, qty: Math.max(0, parseInt(e.target.value) || 0) }))} inputProps={{ min: 0 }} /> setAddEntryForm(f => ({ ...f, expiryDate: value ? dayjs(value).format(INPUT_DATE_FORMAT) : '' }))} slotProps={{ textField: { fullWidth: true, required: true } }} /> o.code || ''} value={addEntryForm.locationId ? warehouses.find(w => w.id === addEntryForm.locationId) ?? null : null} inputValue={addEntryForm.locationInput} onInputChange={(_, v) => setAddEntryForm(f => ({ ...f, locationInput: v }))} onChange={(_, v) => setAddEntryForm(f => ({ ...f, locationId: v?.id ?? null, locationInput: v?.code ?? '' }))} renderInput={(params) => } /> setAddEntryForm(f => ({ ...f, isOpeningInventory: e.target.checked }))} />} label={t("Opening Inventory")} /> setAddEntryForm(f => ({ ...f, productlotNo: e.target.value }))} sx={{ '& .MuiInputBase-input::placeholder': { color: '#9e9e9e', opacity: 1 } }} /> setAddEntryForm(f => ({ ...f, dnNo: e.target.value }))} sx={{ '& .MuiInputBase-input::placeholder': { color: '#9e9e9e', opacity: 1 } }} /> setAddEntryForm(f => ({ ...f, lotNo: e.target.value }))} sx={{ '& .MuiInputBase-input::placeholder': { color: '#9e9e9e', opacity: 1 } }} /> setAddEntryForm(f => ({ ...f, remarks: e.target.value }))} multiline minRows={2} sx={{ '& .MuiInputBase-input::placeholder': { color: '#9e9e9e', opacity: 1 } }} /> } export default InventoryLotLineTable;