Files
GPI/src/client/components/modals/StockModal.tsx
2026-03-12 19:36:34 +00:00

269 lines
10 KiB
TypeScript

import React, { useState, useEffect } from 'react';
import { Modal } from '../Modal';
import { Input } from '../Input';
import { Button } from '../Button';
import { Select } from '../Select';
import { stockService, type StockItem } from '../../services/stockService';
import api from '../../services/api';
import { useAuth } from '../../context/useAuth';
import { useToast } from '../../hooks/useToast';
interface StockModalProps {
isOpen: boolean;
onClose: () => void;
onSuccess: () => void;
initialData?: StockItem;
initialType?: 'PAINT' | 'THINNER';
}
export const StockModal: React.FC<StockModalProps> = ({ isOpen, onClose, onSuccess, initialData, initialType = 'PAINT' }) => {
const { isGuest } = useAuth();
const { showGuestWarning } = useToast();
const [loading, setLoading] = useState(false);
const [dataSheets, setDataSheets] = useState<any[]>([]);
// Form Data
const [dataSheetId, setDataSheetId] = useState('');
const [rrNumber, setRrNumber] = useState('');
const [batchNumber, setBatchNumber] = useState('');
const [color, setColor] = useState('');
const [invoiceNumber, setInvoiceNumber] = useState('');
const [receivedBy, setReceivedBy] = useState('');
const [quantity, setQuantity] = useState('');
const [unit, setUnit] = useState('L');
const [expirationDate, setExpirationDate] = useState('');
const [minStock, setMinStock] = useState('');
const [notes, setNotes] = useState('');
useEffect(() => {
const fetchDataSheets = async () => {
try {
const res = await api.get('/datasheets'); // Assuming this endpoint exists and lists all
setDataSheets(res.data);
} catch (err) {
console.error("Error fetching datasheets", err);
}
};
if (isOpen) {
fetchDataSheets();
if (initialData) {
setDataSheetId(typeof initialData.dataSheetId === 'object' ? initialData.dataSheetId._id : initialData.dataSheetId);
setRrNumber(initialData.rrNumber);
setBatchNumber(initialData.batchNumber);
setColor(initialData.color || '');
setInvoiceNumber(initialData.invoiceNumber || '');
setReceivedBy(initialData.receivedBy || '');
setQuantity(String(initialData.quantity));
setUnit(initialData.unit);
setExpirationDate(initialData.expirationDate ? new Date(initialData.expirationDate).toISOString().split('T')[0] : '');
setMinStock(String(initialData.minStock || 0));
setNotes(initialData.notes || '');
} else {
// Reset form
setDataSheetId('');
setRrNumber('');
setBatchNumber('');
setColor('');
setInvoiceNumber('');
setReceivedBy('');
setQuantity('');
setUnit('L');
setExpirationDate('');
setMinStock('0');
setNotes('');
}
}
}, [isOpen, initialData]);
// Handle filling color etc if picking a DataSheet (Optional feature, not implemented yet)
const handleSubmit = async (e: React.FormEvent) => {
e.preventDefault();
if (isGuest()) {
showGuestWarning();
return;
}
setLoading(true);
const payload: any = {
dataSheetId,
rrNumber,
batchNumber,
color,
invoiceNumber,
receivedBy,
unit,
expirationDate: expirationDate || undefined,
minStock: Number(minStock) || 0,
notes
};
// If creating, send quantity. If updating, DO NOT send quantity (handled via adjusts)
if (!initialData) {
payload.quantity = Number(quantity);
}
try {
if (initialData) {
await stockService.update(initialData._id!, payload);
} else {
await stockService.create(payload);
}
onSuccess();
} catch (error: any) {
console.error('Error saving stock item:', error);
alert(error.response?.data?.error || 'Erro ao salvar item.');
} finally {
setLoading(false);
}
};
const isThinner = initialData
? (typeof initialData.dataSheetId === 'object' && (initialData.dataSheetId.type === 'THINNER' || initialData.dataSheetId.type === 'DILUENTE'))
: (initialType === 'THINNER');
const filteredDataSheets = dataSheets.filter(ds => {
const dsType = ds.type || 'PAINT';
const isDsThinner = dsType === 'THINNER' || dsType === 'DILUENTE';
return isThinner ? isDsThinner : !isDsThinner;
});
return (
<Modal
isOpen={isOpen}
onClose={onClose}
title={initialData ? "Editar Detalhes do Lote" : `Nova Entrada de Estoque (${isThinner ? 'Diluente' : 'Tinta'})`}
>
<form onSubmit={handleSubmit} className="space-y-4">
<Select
label="Produto (Ficha Técnica)"
name="dataSheetId"
value={dataSheetId}
onChange={(e) => {
const val = e.target.value;
setDataSheetId(val);
// Auto-fill minStock from DataSheet if set and current is empty/0
const ds = dataSheets.find(d => d._id === val);
if (ds && ds.minStock && (!minStock || minStock === '0')) {
setMinStock(String(ds.minStock));
}
}}
options={filteredDataSheets.map(ds => ({ label: `${ds.name} - ${ds.manufacturer}`, value: ds._id }))}
disabled={!!initialData} // Lock product on edit
/>
<div className="grid grid-cols-2 gap-4">
<Input
label="RR (Rastreabilidade)"
name="rrNumber"
value={rrNumber}
onChange={(e) => setRrNumber(e.target.value)}
required
disabled={!!initialData} // Usually unique ID shouldn't change easily
/>
<Input
label="Lote Fabricante"
name="batchNumber"
value={batchNumber}
onChange={(e) => setBatchNumber(e.target.value)}
required
/>
</div>
<div className="grid grid-cols-2 gap-4">
<Input
label="Nota Fiscal"
name="invoiceNumber"
value={invoiceNumber}
onChange={(e) => setInvoiceNumber(e.target.value)}
/>
<Input
label="Recebido Por"
name="receivedBy"
value={receivedBy}
onChange={(e) => setReceivedBy(e.target.value)}
/>
</div>
{!isThinner && (
<Input
label="Cor"
name="color"
value={color}
onChange={(e) => setColor(e.target.value)}
placeholder="Ex: Amarelo Segurança, CINZA N6.5"
/>
)}
{!initialData && (
<div className="grid grid-cols-2 gap-4">
<Input
label="Quantidade Inicial"
name="quantity"
type="number"
value={quantity}
onChange={(e) => setQuantity(e.target.value)}
required
/>
<Select
label="Unidade"
name="unit"
value={unit}
onChange={(e) => setUnit(e.target.value)}
options={[
{ label: 'Litros (L)', value: 'L' },
{ label: 'Galões (Gal)', value: 'Gal' },
{ label: 'Quartos (Qt)', value: 'Qt' },
{ label: 'Kg', value: 'Kg' },
{ label: 'Unidade (Un)', value: 'Un' }
]}
/>
</div>
)}
<div className="grid grid-cols-2 gap-4">
{!isThinner && (
<Input
label="Data de Validade"
name="expirationDate"
type="date"
value={expirationDate}
onChange={(e) => setExpirationDate(e.target.value)}
/>
)}
<div className={isThinner ? "col-span-2" : ""}>
<Input
label="Estoque Mínimo (L)"
name="minStock"
type="number"
value={minStock}
onChange={(e) => setMinStock(e.target.value)}
placeholder="Qtd de alerta"
/>
</div>
</div>
<Input
label="Observações"
name="notes"
value={notes}
onChange={(e) => setNotes(e.target.value)}
/>
<div className="flex justify-end gap-2 mt-6">
<Button type="button" variant="ghost" onClick={onClose} disabled={loading}>
Cancelar
</Button>
<Button type="submit" disabled={loading}>
{loading ? 'Salvando...' : 'Salvar'}
</Button>
</div>
</form>
</Modal >
);
};