import { useState, useEffect, useMemo, useRef } from 'react'; import { sheetsApi } from '../api/client'; import { useAuth } from '../context/AuthContext'; import { useSheetAutoSave } from '../hooks/useSheetAutoSave'; import { useGestionView } from '../hooks/useGestionView'; import SaveStatus from './SaveStatus'; import GestionBanner from './GestionBanner'; import GestionesSidebar from './GestionesSidebar'; import { emptyGastoRow, formatMoney } from '../utils/calc'; import { isRowEditable } from '../utils/gestion'; export default function GastoSheet({ sheetType, title, defaultClasificacion }) { const { canEdit, user } = useAuth(); const editable = canEdit(sheetType); const isAdmin = !!user?.isAdmin; const { selectedGestionId, selectGestion, sidebarGestiones } = useGestionView(); const [rows, setRows] = useState([emptyGastoRow()]); const [gestion, setGestion] = useState(null); const [gestionVista, setGestionVista] = useState(null); const [esHistorial, setEsHistorial] = useState(false); const [loading, setLoading] = useState(true); const [loadError, setLoadError] = useState(null); const skipNotifyRef = useRef(false); const emptyRow = () => ({ ...emptyGastoRow(), clasificacion: defaultClasificacion }); const canEditSheet = editable && !esHistorial; const { status, error: saveError, setReady, notifyChange, saveNow } = useSheetAutoSave({ enabled: canEditSheet, sheetType, }); useEffect(() => { let active = true; setLoading(true); setLoadError(null); setReady(false); (async () => { try { const data = await sheetsApi.get(sheetType, { gestionId: selectedGestionId }); if (!active) return; const loaded = data.rows || []; skipNotifyRef.current = true; if (loaded.length) { setRows(loaded.map((r) => ({ ...r, clasificacion: r.clasificacion || defaultClasificacion }))); } else if (!data.esHistorial && canEditSheet) { setRows([emptyRow()]); } else { setRows([]); } setGestion(data.gestion || null); setGestionVista(data.gestionVista || null); setEsHistorial(!!data.esHistorial); setReady(!data.esHistorial); } catch (e) { if (active) setLoadError(e.message); } finally { if (active) setLoading(false); } })(); return () => { active = false; }; }, [sheetType, defaultClasificacion, selectedGestionId, setReady, canEditSheet]); useEffect(() => { if (loading || !canEditSheet) return; if (skipNotifyRef.current) { skipNotifyRef.current = false; return; } notifyChange({ rows }); }, [rows, loading, canEditSheet, notifyChange]); const total = useMemo( () => rows.reduce((acc, r) => acc + (Number(r.monto) || 0), 0), [rows] ); const updateRow = (index, field, value) => { if (!isRowEditable(rows[index], canEditSheet, isAdmin)) return; setRows((prev) => prev.map((r, i) => (i === index ? { ...r, [field]: value } : r))); }; const addRow = () => setRows((prev) => [...prev, emptyRow()]); const removeRow = (index) => { if (!isRowEditable(rows[index], canEditSheet, isAdmin)) return; skipNotifyRef.current = true; const next = rows.filter((_, i) => i !== index); const result = next.length > 0 ? next : [emptyRow()]; setRows(result); saveNow({ rows: result }); }; const clearSheet = () => { const msg = gestion?.fechaCierreGestion && !isAdmin ? '¿Eliminar solo las filas editables? Las del período cerrado se conservarán.' : '¿Vaciar toda la planilla? Se eliminarán todas las filas de la gestión actual.'; if (!window.confirm(msg)) return; skipNotifyRef.current = true; if (isAdmin || !gestion?.fechaCierreGestion) { const blank = [emptyRow()]; setRows(blank); saveNow({ rows: blank }); return; } const kept = rows.filter((r) => r.bloqueada); const result = kept.length ? kept : [emptyRow()]; setRows(result); saveNow({ rows: result }); }; if (loading) return

Cargando planilla…

; return (

{title}

{loadError &&
{loadError}
} {esHistorial && gestionVista && (
Historial: {gestionVista.etiqueta} ({gestionVista.fechaInicio} →{' '} {gestionVista.fechaFin}) — solo lectura
)} {!esHistorial && } {canEditSheet && } {esHistorial &&
Gestión cerrada — solo consulta
} {!editable && !esHistorial &&
Solo lectura
}
{canEditSheet && ( <> )}
{rows.length === 0 ? (

Sin registros en esta gestión.

) : (
{canEditSheet && } {rows.map((row, i) => { const rowEditable = isRowEditable(row, canEditSheet, isAdmin); return ( {canEditSheet && ( )} ); })}
Fecha Detalle Impuestos Nº Factura Monto Clasificación
updateRow(i, 'fecha', e.target.value)} /> updateRow(i, 'detalle', e.target.value)} /> updateRow(i, 'impuestos', e.target.value)} /> updateRow(i, 'numeroFactura', e.target.value)} /> updateRow(i, 'monto', e.target.value)} />
)}
Total gastos: {formatMoney(total)}
); }