1+ import AppLayout from '@/layouts/app-layout' ;
2+ import { Head } from '@inertiajs/react' ;
3+ import { useState } from 'react' ;
4+
5+ const breadcrumbs = [
6+ {
7+ title : 'Cuentas de cobro' ,
8+ href : '/BLCuentaCobro' ,
9+ } ,
10+ ] ;
11+
12+ // Datos de prueba (en producción vendrían del backend)
13+ const datosPrueba = [
14+ {
15+ id : 1 ,
16+ numero : "CC-001-2023" ,
17+ cliente : "Empresa ABC S.A.S." ,
18+ fecha_emision : "2023-10-15" ,
19+ fecha_vencimiento : "2023-11-15" ,
20+ monto : 2500000 ,
21+ estado : "pendiente"
22+ } ,
23+ {
24+ id : 2 ,
25+ numero : "CC-002-2023" ,
26+ cliente : "Comercial XYZ Ltda" ,
27+ fecha_emision : "2023-10-10" ,
28+ fecha_vencimiento : "2023-10-25" ,
29+ monto : 1800000 ,
30+ estado : "pagado"
31+ } ,
32+ {
33+ id : 3 ,
34+ numero : "CC-003-2023" ,
35+ cliente : "Distribuidora Norte" ,
36+ fecha_emision : "2023-09-20" ,
37+ fecha_vencimiento : "2023-10-20" ,
38+ monto : 3200000 ,
39+ estado : "vencido"
40+ }
41+ ] ;
42+
43+ export default function CuentasCobro ( { user, cuentas = datosPrueba } ) {
44+ const [ filtroEstado , setFiltroEstado ] = useState ( 'todos' ) ;
45+ const [ busqueda , setBusqueda ] = useState ( '' ) ;
46+
47+ // Asegurarse de que cuentas siempre sea un array
48+ const cuentasSeguras = cuentas || datosPrueba ;
49+
50+ // Filtrar cuentas según estado y búsqueda
51+ const cuentasFiltradas = cuentasSeguras . filter ( cuenta => {
52+ const coincideEstado = filtroEstado === 'todos' || cuenta . estado === filtroEstado ;
53+ const coincideBusqueda = cuenta . cliente . toLowerCase ( ) . includes ( busqueda . toLowerCase ( ) ) ||
54+ cuenta . numero . toString ( ) . includes ( busqueda ) ;
55+ return coincideEstado && coincideBusqueda ;
56+ } ) ;
57+
58+ // Calcular totales
59+ const totalPendiente = cuentasSeguras . filter ( c => c . estado === 'pendiente' )
60+ . reduce ( ( sum , c ) => sum + c . monto , 0 ) ;
61+ const totalPagado = cuentasSeguras . filter ( c => c . estado === 'pagado' )
62+ . reduce ( ( sum , c ) => sum + c . monto , 0 ) ;
63+
64+ return (
65+ < AppLayout breadcrumbs = { breadcrumbs } >
66+ < Head title = "Cuentas de Cobro" />
67+
68+ < div className = "container mx-auto px-4 py-6" >
69+ { /* Header con estadísticas */ }
70+ < div className = "grid grid-cols-1 md:grid-cols-3 gap-6 mb-8" >
71+ < div className = "bg-white rounded-lg shadow p-6" >
72+ < h3 className = "text-lg font-semibold text-gray-600" > Total Pendiente</ h3 >
73+ < p className = "text-3xl font-bold text-red-500" > ${ totalPendiente . toLocaleString ( ) } </ p >
74+ </ div >
75+ < div className = "bg-white rounded-lg shadow p-6" >
76+ < h3 className = "text-lg font-semibold text-gray-600" > Total Pagado</ h3 >
77+ < p className = "text-3xl font-bold text-green-500" > ${ totalPagado . toLocaleString ( ) } </ p >
78+ </ div >
79+ < div className = "bg-white rounded-lg shadow p-6" >
80+ < h3 className = "text-lg font-semibold text-gray-600" > Cuentas Totales</ h3 >
81+ < p className = "text-3xl font-bold text-blue-500" > { cuentasSeguras . length } </ p >
82+ </ div >
83+ </ div >
84+
85+ { /* Controles de filtrado y búsqueda */ }
86+ < div className = "bg-white rounded-lg shadow p-6 mb-6" >
87+ < div className = "flex flex-col md:flex-row md:items-center md:justify-between gap-4" >
88+ < div className = "flex flex-col md:flex-row gap-4" >
89+ < div >
90+ < label htmlFor = "filtro" className = "block text-sm font-medium text-gray-700 mb-1" >
91+ Filtrar por estado
92+ </ label >
93+ < select
94+ id = "filtro"
95+ className = "rounded-md border-gray-300 shadow-sm focus:border-indigo-500 focus:ring-indigo-500"
96+ value = { filtroEstado }
97+ onChange = { ( e ) => setFiltroEstado ( e . target . value ) }
98+ >
99+ < option value = "todos" > Todos</ option >
100+ < option value = "pendiente" > Pendiente</ option >
101+ < option value = "pagado" > Pagado</ option >
102+ < option value = "vencido" > Vencido</ option >
103+ </ select >
104+ </ div >
105+
106+ < div >
107+ < label htmlFor = "busqueda" className = "block text-sm font-medium text-gray-700 mb-1" >
108+ Buscar
109+ </ label >
110+ < input
111+ type = "text"
112+ id = "busqueda"
113+ placeholder = "Cliente o número de cuenta"
114+ className = "rounded-md border-gray-300 shadow-sm focus:border-indigo-500 focus:ring-indigo-500"
115+ value = { busqueda }
116+ onChange = { ( e ) => setBusqueda ( e . target . value ) }
117+ />
118+ </ div >
119+ </ div >
120+
121+ < button className = "bg-indigo-600 hover:bg-indigo-700 text-white font-medium py-2 px-4 rounded-md" >
122+ Nueva Cuenta de Cobro
123+ </ button >
124+ </ div >
125+ </ div >
126+
127+ { /* Tabla de cuentas de cobro */ }
128+ < div className = "bg-white rounded-lg shadow overflow-hidden" >
129+ < div className = "overflow-x-auto" >
130+ < table className = "min-w-full divide-y divide-gray-200" >
131+ < thead className = "bg-gray-50" >
132+ < tr >
133+ < th scope = "col" className = "px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider" >
134+ Número
135+ </ th >
136+ < th scope = "col" className = "px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider" >
137+ Cliente
138+ </ th >
139+ < th scope = "col" className = "px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider" >
140+ Fecha Emisión
141+ </ th >
142+ < th scope = "col" className = "px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider" >
143+ Fecha Vencimiento
144+ </ th >
145+ < th scope = "col" className = "px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider" >
146+ Monto
147+ </ th >
148+ < th scope = "col" className = "px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider" >
149+ Estado
150+ </ th >
151+ < th scope = "col" className = "px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider" >
152+ Acciones
153+ </ th >
154+ </ tr >
155+ </ thead >
156+ < tbody className = "bg-white divide-y divide-gray-200" >
157+ { cuentasFiltradas . length > 0 ? (
158+ cuentasFiltradas . map ( ( cuenta ) => (
159+ < tr key = { cuenta . id } className = "hover:bg-gray-50" >
160+ < td className = "px-6 py-4 whitespace-nowrap text-sm font-medium text-gray-900" >
161+ #{ cuenta . numero }
162+ </ td >
163+ < td className = "px-6 py-4 whitespace-nowrap text-sm text-gray-500" >
164+ { cuenta . cliente }
165+ </ td >
166+ < td className = "px-6 py-4 whitespace-nowrap text-sm text-gray-500" >
167+ { new Date ( cuenta . fecha_emision ) . toLocaleDateString ( ) }
168+ </ td >
169+ < td className = "px-6 py-4 whitespace-nowrap text-sm text-gray-500" >
170+ { new Date ( cuenta . fecha_vencimiento ) . toLocaleDateString ( ) }
171+ </ td >
172+ < td className = "px-6 py-4 whitespace-nowrap text-sm text-gray-900" >
173+ ${ cuenta . monto . toLocaleString ( ) }
174+ </ td >
175+ < td className = "px-6 py-4 whitespace-nowrap" >
176+ < span className = { `px-2 inline-flex text-xs leading-5 font-semibold rounded-full
177+ ${ cuenta . estado === 'pagado' ? 'bg-green-100 text-green-800' :
178+ cuenta . estado === 'pendiente' ? 'bg-yellow-100 text-yellow-800' :
179+ 'bg-red-100 text-red-800' } `} >
180+ { cuenta . estado }
181+ </ span >
182+ </ td >
183+ < td className = "px-6 py-4 whitespace-nowrap text-sm font-medium" >
184+ < button className = "text-indigo-600 hover:text-indigo-900 mr-3" >
185+ Ver
186+ </ button >
187+ < button className = "text-blue-600 hover:text-blue-900 mr-3" >
188+ Editar
189+ </ button >
190+ < button className = "text-red-600 hover:text-red-900" >
191+ Eliminar
192+ </ button >
193+ </ td >
194+ </ tr >
195+ ) )
196+ ) : (
197+ < tr >
198+ < td colSpan = "7" className = "px-6 py-4 text-center text-sm text-gray-500" >
199+ No se encontraron cuentas de cobro
200+ </ td >
201+ </ tr >
202+ ) }
203+ </ tbody >
204+ </ table >
205+ </ div >
206+ </ div >
207+ </ div >
208+ </ AppLayout >
209+ ) ;
210+ }
0 commit comments