Skip to content

Commit 037fd31

Browse files
authored
Merge pull request #67 from chechojgb/buttonsLovers
refactor: cambio tablas pages marcacion
2 parents 30b0e00 + 2281db3 commit 037fd31

File tree

9 files changed

+308
-256
lines changed

9 files changed

+308
-256
lines changed

app/Http/Controllers/BLMarcacionController.php

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -19,11 +19,13 @@ public function index()
1919
$user = Auth::user();
2020
$orderCustomer = BLCliente::with(['pedidos.items.empaque.producto', 'pedidos.items.marcaciones.trabajador'])->get();
2121
$buttonUser = User::whereIn('proyecto', ['Button LoversM', 'Button LoversMN'])->get();
22+
$itemsPedidos = BLPedidoItem::with(['pedido.cliente', 'empaque.producto', 'marcaciones.trabajador'])->get();
2223
// dd($buttonUser);
2324
return Inertia::render('BLMarcacion', [
2425
'user' => $user,
2526
'orderCustomer' => $orderCustomer,
26-
'buttonUser' => $buttonUser
27+
'buttonUser' => $buttonUser,
28+
'itemsPedidos' => $itemsPedidos
2729
]);
2830
}
2931

@@ -89,10 +91,13 @@ public function actualizarEstado(BLPedidoItem $item, Request $request)
8991
$request->validate([
9092
'estado' => 'required|in:pendiente,en proceso,completado'
9193
]);
92-
9394
$item->estado = $request->estado;
9495
$item->save();
95-
96-
return response()->json(['message' => 'Estado actualizado correctamente']);
96+
return redirect()->back()->with([
97+
'toast' => [
98+
'type' => 'success',
99+
'message' => 'Estado actualizado correctamente',
100+
],
101+
]);
97102
}
98103
}

resources/js/components/BL/tablaMarcacionBL.jsx

Lines changed: 82 additions & 99 deletions
Original file line numberDiff line numberDiff line change
@@ -8,27 +8,20 @@ import {
88
import { useState } from 'react';
99
import { themeByProject } from '../utils/theme';
1010
import { usePage } from '@inertiajs/react';
11-
import axios from 'axios';
12-
import EditarProductForm from './EditProductModal';
13-
import AgentModalWrapper from '../agentsModalWrapper';
1411
import { router } from '@inertiajs/react';
1512
import { Toast } from "flowbite-react";
1613
import { useEffect } from 'react';
1714
import { HiCheck, HiX } from "react-icons/hi";
1815

19-
export default function TablaProductosBL() {
16+
export default function TablaMarcacionBL({itemsPedidos, search}) {
2017
const { props } = usePage();
2118
const proyecto = props?.auth?.user?.proyecto || 'AZZU';
2219
const theme = themeByProject[proyecto];
23-
const [productDetail, setProductDetail] = useState(null);
24-
const [colores, setColores] = useState(null);
25-
const [modalOpenProductEdit, setModalOpenProductEdit] = useState(false);
2620
const [toast, setToast] = useState({
27-
show: false,
28-
success: false,
29-
message: "",
21+
show: false,
22+
success: false,
23+
message: "",
3024
});
31-
3225
useEffect(() => {
3326
if (toast.show) {
3427
const timer = setTimeout(() => {
@@ -39,86 +32,82 @@ export default function TablaProductosBL() {
3932
}
4033
}, [toast]);
4134

42-
const openModalEditProduct = async(id) => {
43-
try {
44-
const response = await axios.get(`BLProductShow/${id}`);
45-
setProductDetail(response.data.productDetails);
46-
setColores(response.data.colores);
47-
setModalOpenProductEdit(true);
48-
} catch (error) {
49-
console.error("Error al cargar el producto", error);
50-
}
51-
}
52-
const closeModal = () => {
53-
setModalOpenProductEdit(false);
54-
};
55-
const handleEditarProducto = (productData) => {
56-
console.log("➡️ productData recibido:", productData);
57-
console.log("➡️ id:", productData?.id);
58-
router.put(route(`productBL.update`, {producto: productData.id}), productData, {
59-
preserveState: true,
60-
onSuccess: () => {
61-
setToast({
62-
show: true,
63-
success: true,
64-
message: "producto editado correctamente"
65-
});
66-
// closeModal();
67-
// Refrescar la lista de clientes
68-
// router.visit(route('clientes.index'));
69-
},
70-
onError: (errors) => {
71-
const primerError = Object.values(errors)[0];
72-
setToast({
73-
show: true,
74-
success: false,
75-
message: primerError || "Error al editar el producto"
76-
});
77-
},
78-
onFinish: (visit) => {
79-
// Si hubo error de servidor (status 500 o más)
80-
if (visit.response?.status >= 500) {
81-
const msg = visit.response?.data?.message || "Error interno del servidor";
82-
setToast({
83-
show: true,
84-
success: false,
85-
message: msg
86-
});
87-
}
88-
}
89-
});
90-
};
91-
92-
// <th className="px-2 sm:px-4 py-2 sm:py-3">Cliente</th>
93-
// <th className="px-2 sm:px-4 py-2 sm:py-3">Pedido</th>
94-
// <th className="px-2 sm:px-4 py-2 sm:py-3">Referencia</th>
95-
// <th className="px-2 sm:px-4 py-2 sm:py-3">Cantidad</th>
96-
// <th className="px-2 sm:px-4 py-2 sm:py-3">Nota</th>
97-
// <th className="px-2 sm:px-4 py-2 sm:py-3">Estado</th>
9835
const columns = [
99-
{ accessorKey: 'cliente', header: 'cliente' },
100-
{ accessorKey: 'pedido', header: 'pedido' },
101-
{ accessorKey: 'cantidad', header: 'cantidad' },
36+
{ accessorKey: 'pedido.cliente.nombre', header: 'cliente' },
37+
{
38+
header: 'pedido',
39+
accessorFn: (row) => 'PED #' + (row.pedido_id ? row.pedido_id : '') +' - ' + (row.empaque?.producto?.descripcion ?? '—') ?? '—'
40+
},
41+
{ accessorKey: 'cantidad_empaques', header: 'cantidad' },
10242
{ accessorKey: 'nota', header: 'nota' },
103-
{ accessorKey: 'estado', header: 'estado' },
10443
{
105-
id: 'acciones',
106-
header: 'Editar Producto',
107-
cell: ({ row }) => (
108-
<button
109-
className={`${theme.text} font-medium hover:underline cursor-pointer`}
110-
onClick={() => openModalEditProduct(row.original.id)}
111-
>
112-
Editar
113-
</button>
114-
),
44+
header: 'Estado',
45+
accessorKey: 'estado',
46+
cell: ({ row }) => {
47+
const value = row.getValue("estado"); // estado actual
48+
const itemId = row.original.id; // ID del item
49+
const handleChange = (nuevoEstado) => {
50+
router.patch(route('bl-historicos.actualizar-estado', itemId), { estado: nuevoEstado }, {
51+
preserveState: true,
52+
onSuccess: () => {
53+
setToast({
54+
show: true,
55+
success: true,
56+
message: "Item actualizado correctamente"
57+
});
58+
// Refrescar la lista de productos
59+
// router.visit(route('productos.index'));
60+
},
61+
onError: (errors) => {
62+
const primerError = Object.values(errors)[0];
63+
setToast({
64+
show: true,
65+
success: false,
66+
message: primerError || "Error al guardar el estado del item"
67+
});
68+
},
69+
onFinish: (visit) => {
70+
// Si hubo error de servidor (status 500 o más)
71+
if (visit.response?.status >= 500) {
72+
const msg = visit.response?.data?.message || "Error interno del servidor";
73+
setToast({
74+
show: true,
75+
success: false,
76+
message: msg
77+
});
78+
}
79+
}
80+
});
81+
};
82+
83+
84+
return (
85+
<select
86+
value={value}
87+
onChange={(e) => handleChange(e.target.value)}
88+
className={`px-2 py-1 rounded text-xs font-semibold border
89+
${value === "completado" ? "bg-green-100 text-green-800" :
90+
value === "pendiente" ? "bg-red-100 text-red-800" :
91+
"bg-yellow-100 text-yellow-800"}
92+
`}
93+
>
94+
<option value="pendiente">Pendiente</option>
95+
<option value="en proceso">En proceso</option>
96+
<option value="completado">Completado</option>
97+
</select>
98+
);
99+
}
115100
},
101+
{
102+
header: 'Completado por',
103+
accessorFn: row => row.marcaciones?.[0]?.trabajador?.name ?? 'Sin asignar'
104+
}
116105
];
117106

118107
const [sorting, setSorting] = useState([]);
119108

120109
const table = useReactTable({
121-
data: productos,
110+
data: itemsPedidos,
122111
columns,
123112
state: {
124113
sorting,
@@ -175,25 +164,19 @@ export default function TablaProductosBL() {
175164
))}
176165
</tbody>
177166
</table>
178-
{modalOpenProductEdit && (
179-
<AgentModalWrapper closeModal={closeModal}>
180-
<EditarProductForm onClose={closeModal} productDetail={productDetail} onSave={handleEditarProducto} colores={colores} />
181-
</AgentModalWrapper>
182-
)
183-
}
184167
{toast.show && (
185-
<div className="fixed bottom-6 right-6 z-51">
186-
<Toast>
187-
<div
188-
className={`inline-flex h-8 w-8 shrink-0 items-center justify-center rounded-lg ${
189-
toast.success ? "bg-green-100 text-green-500" : "bg-red-100 text-red-500"
190-
}`}
191-
>
192-
{toast.success ? <HiCheck className="h-5 w-5" /> : <HiX className="h-5 w-5" />}
168+
<div className="fixed bottom-6 right-6 z-51">
169+
<Toast>
170+
<div
171+
className={`inline-flex h-8 w-8 shrink-0 items-center justify-center rounded-lg ${
172+
toast.success ? "bg-green-100 text-green-500" : "bg-red-100 text-red-500"
173+
}`}
174+
>
175+
{toast.success ? <HiCheck className="h-5 w-5" /> : <HiX className="h-5 w-5" />}
176+
</div>
177+
<div className="ml-3 text-sm font-normal">{toast.message}</div>
178+
</Toast>
193179
</div>
194-
<div className="ml-3 text-sm font-normal">{toast.message}</div>
195-
</Toast>
196-
</div>
197180
)}
198181
</>
199182
);

resources/js/components/BLHistorico/ClienteSelector.jsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,12 +17,12 @@ const ClienteSelector = ({
1717
className="border rounded-lg p-2 w-full"
1818
/>
1919
{sugerencias.length > 0 && (
20-
<ul className="absolute z-10 bg-white border rounded-lg shadow-md mt-1 w-full max-h-40 overflow-y-auto">
20+
<ul className="absolute z-10 bg-white dark:bg-gray-800 border rounded-lg shadow-md mt-1 w-full max-h-40 overflow-y-auto">
2121
{sugerencias.map((c) => (
2222
<li
2323
key={c.id}
2424
onClick={() => seleccionarCliente(c)}
25-
className="px-3 py-2 cursor-pointer hover:bg-blue-100"
25+
className="px-3 py-2 cursor-pointer hover:bg-gray-100 dark:hover:bg-gray-600 transition-colors"
2626
>
2727
{c.nombre} ({c.nit})
2828
</li>

resources/js/components/BLHistorico/ItemsTable.jsx

Lines changed: 49 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -7,60 +7,86 @@ const ItemsTable = ({
77
precios,
88
setPrecios
99
}) => {
10+
11+
const toggleSeleccion = (id, checked) => {
12+
if (checked) {
13+
setSeleccionados([...seleccionados, id]);
14+
} else {
15+
setSeleccionados(seleccionados.filter(itemId => itemId !== id));
16+
}
17+
};
18+
1019
return (
11-
<div className="mt-4">
20+
<div className="mt-4 overflow-x-auto">
1221
<h3 className="font-medium mb-2">Items del Pedido</h3>
13-
<table className="w-full text-sm border rounded-lg">
14-
<thead className="bg-gray-100">
22+
<table className="w-full text-sm border rounded-lg bg-white dark:bg-gray-900/50">
23+
<thead className="bg-gray-100 dark:bg-gray-900">
1524
<tr>
1625
<th className="px-2 py-1">Referencia</th>
1726
<th className="px-2 py-1">Cantidad</th>
1827
<th className="px-2 py-1">Nota</th>
1928
{nuevo.proyecto === "Button LoversMN" && (
2029
<th className="px-2 py-1">💲 Precio Unitario</th>
2130
)}
22-
<th className="px-2 py-1">Seleccionar</th>
31+
<th className="px-2 py-1 text-center">Acción</th>
2332
</tr>
2433
</thead>
2534
<tbody>
2635
{itemsDisponibles.map((item) => {
27-
const yaMarcado = item.marcaciones && item.marcaciones.length > 0;
36+
const trabajador = item.marcaciones?.at(-1)?.trabajador?.name || "—";
37+
const esMarcado = item.estado === "completado";
38+
const esProceso = item.estado === "en proceso";
2839

2940
return (
30-
<tr key={item.id} className="border-t">
41+
<tr
42+
key={item.id}
43+
className={`border-t ${
44+
esMarcado
45+
? "bg-green-50 dark:bg-gray-900/50"
46+
: esProceso
47+
? "bg-yellow-50 dark:bg-gray-900/30"
48+
: ""
49+
}`}
50+
>
3151
<td className="px-2 py-1">{item.empaque?.producto?.descripcion}</td>
3252
<td className="px-2 py-1">{item.cantidad_empaques}</td>
3353
<td className="px-2 py-1">{item.nota || "—"}</td>
54+
55+
{/* Precios solo para Button LoversMN */}
3456
{nuevo.proyecto === "Button LoversMN" && (
3557
<td className="px-2 py-1">
3658
<input
3759
type="number"
3860
value={precios[item.id] || ""}
39-
onChange={(e) => setPrecios({
40-
...precios,
41-
[item.id]: e.target.value
42-
})}
43-
className="border rounded p-1 w-20"
44-
disabled={yaMarcado}
61+
onChange={(e) =>
62+
setPrecios({
63+
...precios,
64+
[item.id]: e.target.value,
65+
})
66+
}
67+
className={`border rounded p-1 w-20 ${
68+
(esMarcado || esProceso) ? "bg-gray-100 dark:bg-gray-700 text-gray-400" : ""
69+
}`}
70+
disabled={esMarcado || esProceso}
4571
/>
4672
</td>
4773
)}
74+
75+
{/* Acción */}
4876
<td className="px-2 py-1 text-center">
49-
{yaMarcado ? (
50-
<span className="text-red-500 font-semibold">
51-
En proceso por {item.marcaciones.slice(-1)[0]?.trabajador?.name}
77+
{esMarcado ? (
78+
<span className="text-green-100/60 font-semibold">
79+
Marcado por: {trabajador}
80+
</span>
81+
) : esProceso ? (
82+
<span className="text-yellow-100/70 font-semibold">
83+
En proceso por: {trabajador}
5284
</span>
5385
) : (
5486
<input
5587
type="checkbox"
5688
checked={seleccionados.includes(item.id)}
57-
onChange={(e) => {
58-
if (e.target.checked) {
59-
setSeleccionados([...seleccionados, item.id]);
60-
} else {
61-
setSeleccionados(seleccionados.filter(id => id !== item.id));
62-
}
63-
}}
89+
onChange={(e) => toggleSeleccion(item.id, e.target.checked)}
6490
/>
6591
)}
6692
</td>
@@ -73,4 +99,4 @@ const ItemsTable = ({
7399
);
74100
};
75101

76-
export default ItemsTable;
102+
export default ItemsTable;

0 commit comments

Comments
 (0)