Commit inicial - Sistema de Gestion Hotelera Hacienda San Angel
- 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)
This commit is contained in:
156
frontend/Frontend-Hotel/src/pages/Expenses/PurchaseEntries.jsx
Normal file
156
frontend/Frontend-Hotel/src/pages/Expenses/PurchaseEntries.jsx
Normal file
@@ -0,0 +1,156 @@
|
||||
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>
|
||||
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user