|
| 1 | +import { |
| 2 | + useReactTable, |
| 3 | + getCoreRowModel, |
| 4 | + getSortedRowModel, |
| 5 | + getFilteredRowModel, |
| 6 | + flexRender, |
| 7 | +} from '@tanstack/react-table'; |
| 8 | +import { useState } from 'react'; |
| 9 | +import { themeByProject } from '../utils/theme'; |
| 10 | +import { usePage } from '@inertiajs/react'; |
| 11 | +import axios from 'axios'; |
| 12 | +import EditarProductForm from './EditProductModal'; |
| 13 | +import AgentModalWrapper from '../agentsModalWrapper'; |
| 14 | +import { router } from '@inertiajs/react'; |
| 15 | +import { Toast } from "flowbite-react"; |
| 16 | +import { useEffect } from 'react'; |
| 17 | +import { HiCheck, HiX } from "react-icons/hi"; |
| 18 | + |
| 19 | +export default function TablaProductosBL() { |
| 20 | + const { props } = usePage(); |
| 21 | + const proyecto = props?.auth?.user?.proyecto || 'AZZU'; |
| 22 | + const theme = themeByProject[proyecto]; |
| 23 | + const [productDetail, setProductDetail] = useState(null); |
| 24 | + const [colores, setColores] = useState(null); |
| 25 | + const [modalOpenProductEdit, setModalOpenProductEdit] = useState(false); |
| 26 | + const [toast, setToast] = useState({ |
| 27 | + show: false, |
| 28 | + success: false, |
| 29 | + message: "", |
| 30 | + }); |
| 31 | + |
| 32 | + useEffect(() => { |
| 33 | + if (toast.show) { |
| 34 | + const timer = setTimeout(() => { |
| 35 | + setToast({ show: false, success: false, message: '' }); |
| 36 | + }, 4000); |
| 37 | + |
| 38 | + return () => clearTimeout(timer); |
| 39 | + } |
| 40 | + }, [toast]); |
| 41 | + |
| 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> |
| 98 | + const columns = [ |
| 99 | + { accessorKey: 'cliente', header: 'cliente' }, |
| 100 | + { accessorKey: 'pedido', header: 'pedido' }, |
| 101 | + { accessorKey: 'cantidad', header: 'cantidad' }, |
| 102 | + { accessorKey: 'nota', header: 'nota' }, |
| 103 | + { accessorKey: 'estado', header: 'estado' }, |
| 104 | + { |
| 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 | + ), |
| 115 | + }, |
| 116 | + ]; |
| 117 | + |
| 118 | + const [sorting, setSorting] = useState([]); |
| 119 | + |
| 120 | + const table = useReactTable({ |
| 121 | + data: productos, |
| 122 | + columns, |
| 123 | + state: { |
| 124 | + sorting, |
| 125 | + globalFilter: search, |
| 126 | + }, |
| 127 | + onSortingChange: setSorting, |
| 128 | + getCoreRowModel: getCoreRowModel(), |
| 129 | + getSortedRowModel: getSortedRowModel(), |
| 130 | + getFilteredRowModel: getFilteredRowModel(), |
| 131 | + globalFilterFn: (row, columnId, value) => { |
| 132 | + const cellValue = String(row.getValue(columnId) ?? '').toLowerCase(); |
| 133 | + return cellValue.includes(value.toLowerCase()); |
| 134 | + }, |
| 135 | + }); |
| 136 | + |
| 137 | + return ( |
| 138 | + <> |
| 139 | + <table className="min-w-full text-sm text-left text-gray-500 dark:text-gray-400"> |
| 140 | + <thead className="text-xs text-gray-700 uppercase bg-gray-50 dark:bg-gray-800 dark:text-gray-400"> |
| 141 | + {table.getHeaderGroups().map(headerGroup => ( |
| 142 | + <tr key={headerGroup.id}> |
| 143 | + {headerGroup.headers.map(header => ( |
| 144 | + <th |
| 145 | + key={header.id} |
| 146 | + className="px-6 py-3 cursor-pointer select-none" |
| 147 | + onClick={header.column.getToggleSortingHandler()} |
| 148 | + > |
| 149 | + {flexRender(header.column.columnDef.header, header.getContext())} |
| 150 | + {{ |
| 151 | + asc: ' 🔼', |
| 152 | + desc: ' 🔽', |
| 153 | + }[header.column.getIsSorted()] ?? null} |
| 154 | + </th> |
| 155 | + ))} |
| 156 | + </tr> |
| 157 | + ))} |
| 158 | + </thead> |
| 159 | + <tbody> |
| 160 | + {table.getRowModel().rows.map((row, index) => ( |
| 161 | + <tr |
| 162 | + key={row.id} |
| 163 | + className={`${ |
| 164 | + index % 2 === 0 |
| 165 | + ? 'bg-white dark:bg-gray-800' |
| 166 | + : 'bg-gray-50 dark:bg-gray-700' |
| 167 | + } hover:bg-gray-100 dark:hover:bg-gray-600 transition-colors`} |
| 168 | + > |
| 169 | + {row.getVisibleCells().map(cell => ( |
| 170 | + <td key={cell.id} className="px-6 py-4 whitespace-nowrap"> |
| 171 | + {flexRender(cell.column.columnDef.cell, cell.getContext())} |
| 172 | + </td> |
| 173 | + ))} |
| 174 | + </tr> |
| 175 | + ))} |
| 176 | + </tbody> |
| 177 | + </table> |
| 178 | + {modalOpenProductEdit && ( |
| 179 | + <AgentModalWrapper closeModal={closeModal}> |
| 180 | + <EditarProductForm onClose={closeModal} productDetail={productDetail} onSave={handleEditarProducto} colores={colores} /> |
| 181 | + </AgentModalWrapper> |
| 182 | + ) |
| 183 | + } |
| 184 | + {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" />} |
| 193 | + </div> |
| 194 | + <div className="ml-3 text-sm font-normal">{toast.message}</div> |
| 195 | + </Toast> |
| 196 | + </div> |
| 197 | + )} |
| 198 | + </> |
| 199 | + ); |
| 200 | +} |
0 commit comments