- Backend Node.js/Express con PostgreSQL - Frontend React 19 con Vite - Docker Compose para orquestacion - Documentacion completa en README.md - Scripts SQL para base de datos - Configuracion de ejemplo (.env.example)
157 lines
4.8 KiB
JavaScript
157 lines
4.8 KiB
JavaScript
import React, { useEffect, useState } from 'react';
|
|
import ConfirmationModal from '../../components/Modals/ConfirmationModal';
|
|
import Table from '../../components/Table/HotelTable';
|
|
import { Link } from 'react-router-dom';
|
|
import axios from 'axios';
|
|
import { useContext } from 'react';
|
|
import { langContext } from '../../context/LenguageContext';
|
|
//**////** */ */ REVISAR DELIVERED NULL
|
|
export default function PurchaseEntries() {
|
|
const { lang } = useContext(langContext);
|
|
const [purchases, setPurchases] = useState([]);
|
|
const [searchTerm, setSearchTerm] = useState('');
|
|
const [modalOpen, setModalOpen] = useState(false);
|
|
const [checking, setChecking] = useState(null);
|
|
const [selectedId, setSelectedId] = useState(null);
|
|
|
|
const loadPurchases = () => {
|
|
fetch(import.meta.env.VITE_API_BASE_URL + '/purchases/getpurchases')
|
|
.then(res => res.json())
|
|
.then(resData => {
|
|
const mapped = resData.data.map(item => ({
|
|
id: item.id_purchase_dt,
|
|
expense_id: item.id_expense,
|
|
name: item.product_name,
|
|
quantity: item.quantity,
|
|
delivered: item.delivered,
|
|
check: 0,
|
|
}));
|
|
setPurchases(mapped);
|
|
})
|
|
.catch(err => console.error('Error loading expense report:', err));
|
|
};
|
|
|
|
useEffect(() => {
|
|
loadPurchases();
|
|
}, []);
|
|
|
|
const filteredPurchases = purchases.filter(purchase =>
|
|
purchase.name.toLowerCase().includes(searchTerm.toLowerCase())
|
|
);
|
|
|
|
const columns = [
|
|
{ header: lang === "en" ? "PURCHASE ID" : "ID DE COMPRA", key: 'id' },
|
|
{ header: lang === "en" ? "EXPENSE ID" : "ID DE GASTO", key: 'expense_id' },
|
|
{ header: lang === "en" ? "PRODUCT" : "PRODUCTO", key: 'name' },
|
|
{ header: lang === "en" ? "REQUESTED" : "SOLICITADOS", key: 'quantity' },
|
|
{ header: lang === "en" ? "DELIVERED" : "ENTREGADOS", key: 'delivered' },
|
|
{
|
|
header: lang === "en" ? "CHECKING" : "RECIBIENDO",
|
|
key: 'check',
|
|
render: (check, row) => (
|
|
<input
|
|
type="number"
|
|
value={check} // opcional, para mantener sincronía
|
|
onChange={(e) => handleCheckingChange(row.id, e.target.value)}
|
|
placeholder={lang === "en" ? "Checking" : "Recibiendo"}
|
|
/>
|
|
),
|
|
},
|
|
{
|
|
header: lang === "en" ? "CONFIRM RECEIVED" : "CONFIRMAR RECEPCIÓN",
|
|
key: 'id',
|
|
headerStyle: { textAlign: 'center' },
|
|
render: (id, row) => (
|
|
<div style={{ textAlign: 'center' }}>
|
|
<button
|
|
className='status-button'
|
|
onClick={() => handleOpenModal(id, row.check)}
|
|
>
|
|
{lang === "en" ? "CONFIRM" : "CONFIRMAR"}
|
|
</button>
|
|
</div>
|
|
),
|
|
},
|
|
];
|
|
|
|
const handleCheckingChange = (id, value) => {
|
|
setPurchases(prev =>
|
|
prev.map(p =>
|
|
p.id === id ? { ...p, check: value } : p
|
|
)
|
|
);
|
|
};
|
|
|
|
|
|
const handleOpenModal = (id, check) => {
|
|
setSelectedId(id);
|
|
setChecking(check);
|
|
setModalOpen(true);
|
|
};
|
|
|
|
const handleConfirm = () => {
|
|
if (!selectedId || !checking) return;
|
|
|
|
axios.put(`${import.meta.env.VITE_API_BASE_URL}/purchases/entry/${selectedId}`, {
|
|
checking: parseInt(checking)
|
|
})
|
|
.then((res) => {
|
|
console.log(res.data.message || 'Estado actualizado correctamente');
|
|
|
|
//Actualizar purchases
|
|
loadPurchases();
|
|
|
|
// Cerrar el modal y limpiar selección
|
|
setModalOpen(false);
|
|
setSelectedId(null);
|
|
setChecking(null);
|
|
})
|
|
.catch((err) => {
|
|
console.error(`Error al actualizar el estado del gasto ${selectedId}:`, err);
|
|
alert('❌ Error al actualizar el estado. Intenta nuevamente.');
|
|
});
|
|
};
|
|
|
|
const handleCancel = () => {
|
|
setModalOpen(false);
|
|
};
|
|
|
|
return (
|
|
<div className="report-page">
|
|
<h2>{lang === "en" ? "Purchase Entries" : "Entradas de compras"}</h2>
|
|
|
|
<div style={{ marginBottom: '20px' }}>
|
|
<input
|
|
type="text"
|
|
placeholder={lang === "en" ? "Search by product name..." : "Buscar por nombre del producto..."}
|
|
value={searchTerm}
|
|
onChange={(e) => setSearchTerm(e.target.value)}
|
|
style={{
|
|
padding: '10px 16px',
|
|
border: 'none',
|
|
borderRadius: '30px',
|
|
backgroundColor: 'white',
|
|
boxShadow: '0 0 0 2px #f4f4f4',
|
|
fontSize: '14px',
|
|
color: '#333',
|
|
fontFamily: "'Segoe UI', Tahoma, Geneva, Verdana, sans-serif",
|
|
fontWeight: 'bold',
|
|
minWidth: '250px',
|
|
width: '100%',
|
|
maxWidth: '400px'
|
|
}}
|
|
/>
|
|
</div>
|
|
|
|
<Table columns={columns} data={filteredPurchases} />
|
|
<ConfirmationModal
|
|
isOpen={modalOpen}
|
|
statusType={checking}
|
|
onConfirm={handleConfirm}
|
|
onCancel={handleCancel}
|
|
/>
|
|
</div>
|
|
|
|
);
|
|
}
|