import { useState, useEffect, useCallback } from 'react'; import { financialApi } from '../api/financial.api'; import type { Account, AccountFilters, CreateAccountDto, UpdateAccountDto, AccountType, Journal, JournalFilters, CreateJournalDto, UpdateJournalDto, JournalEntry, JournalEntryFilters, CreateJournalEntryDto, UpdateJournalEntryDto, FinancialInvoice, InvoiceFilters, CreateInvoiceDto, UpdateInvoiceDto, Payment, PaymentFilters, CreatePaymentDto, UpdatePaymentDto, } from '../types'; // ==================== Account Types Hook ==================== export function useAccountTypes() { const [accountTypes, setAccountTypes] = useState([]); const [isLoading, setIsLoading] = useState(false); const [error, setError] = useState(null); const fetchAccountTypes = useCallback(async () => { setIsLoading(true); setError(null); try { const data = await financialApi.getAccountTypes(); setAccountTypes(data); } catch (err) { setError(err instanceof Error ? err.message : 'Error al cargar tipos de cuenta'); } finally { setIsLoading(false); } }, []); useEffect(() => { fetchAccountTypes(); }, [fetchAccountTypes]); return { accountTypes, isLoading, error, refresh: fetchAccountTypes, }; } // ==================== Accounts Hook ==================== export interface UseAccountsOptions extends AccountFilters { autoFetch?: boolean; } export function useAccounts(options: UseAccountsOptions = {}) { const { autoFetch = true, ...filters } = options; const [accounts, setAccounts] = useState([]); const [total, setTotal] = useState(0); const [page, setPage] = useState(filters.page || 1); const [totalPages, setTotalPages] = useState(1); const [isLoading, setIsLoading] = useState(false); const [error, setError] = useState(null); const fetchAccounts = useCallback(async () => { setIsLoading(true); setError(null); try { const response = await financialApi.getAccounts({ ...filters, page }); setAccounts(response.data); setTotal(response.meta.total); setTotalPages(response.meta.totalPages); } catch (err) { setError(err instanceof Error ? err.message : 'Error al cargar cuentas'); } finally { setIsLoading(false); } }, [filters.companyId, filters.accountTypeId, filters.parentId, filters.isReconcilable, filters.isDeprecated, filters.search, filters.limit, filters.sortBy, filters.sortOrder, page]); useEffect(() => { if (autoFetch) { fetchAccounts(); } }, [fetchAccounts, autoFetch]); const createAccount = async (data: CreateAccountDto) => { setIsLoading(true); try { const newAccount = await financialApi.createAccount(data); await fetchAccounts(); return newAccount; } catch (err) { setError(err instanceof Error ? err.message : 'Error al crear cuenta'); throw err; } finally { setIsLoading(false); } }; const updateAccount = async (id: string, data: UpdateAccountDto) => { setIsLoading(true); try { const updated = await financialApi.updateAccount(id, data); await fetchAccounts(); return updated; } catch (err) { setError(err instanceof Error ? err.message : 'Error al actualizar cuenta'); throw err; } finally { setIsLoading(false); } }; const deleteAccount = async (id: string) => { setIsLoading(true); try { await financialApi.deleteAccount(id); await fetchAccounts(); } catch (err) { setError(err instanceof Error ? err.message : 'Error al eliminar cuenta'); throw err; } finally { setIsLoading(false); } }; return { accounts, total, page, totalPages, isLoading, error, setPage, refresh: fetchAccounts, createAccount, updateAccount, deleteAccount, }; } // ==================== Single Account Hook ==================== export function useAccount(accountId: string | null) { const [account, setAccount] = useState(null); const [isLoading, setIsLoading] = useState(false); const [error, setError] = useState(null); const fetchAccount = useCallback(async () => { if (!accountId) { setAccount(null); return; } setIsLoading(true); setError(null); try { const data = await financialApi.getAccountById(accountId); setAccount(data); } catch (err) { setError(err instanceof Error ? err.message : 'Error al cargar cuenta'); } finally { setIsLoading(false); } }, [accountId]); useEffect(() => { fetchAccount(); }, [fetchAccount]); return { account, isLoading, error, refresh: fetchAccount, }; } // ==================== Journals Hook ==================== export interface UseJournalsOptions extends JournalFilters { autoFetch?: boolean; } export function useJournals(options: UseJournalsOptions = {}) { const { autoFetch = true, ...filters } = options; const [journals, setJournals] = useState([]); const [total, setTotal] = useState(0); const [page, setPage] = useState(filters.page || 1); const [totalPages, setTotalPages] = useState(1); const [isLoading, setIsLoading] = useState(false); const [error, setError] = useState(null); const fetchJournals = useCallback(async () => { setIsLoading(true); setError(null); try { const response = await financialApi.getJournals({ ...filters, page }); setJournals(response.data); setTotal(response.meta.total); setTotalPages(response.meta.totalPages); } catch (err) { setError(err instanceof Error ? err.message : 'Error al cargar diarios'); } finally { setIsLoading(false); } }, [filters.companyId, filters.journalType, filters.active, filters.search, filters.limit, page]); useEffect(() => { if (autoFetch) { fetchJournals(); } }, [fetchJournals, autoFetch]); const createJournal = async (data: CreateJournalDto) => { setIsLoading(true); try { const newJournal = await financialApi.createJournal(data); await fetchJournals(); return newJournal; } catch (err) { setError(err instanceof Error ? err.message : 'Error al crear diario'); throw err; } finally { setIsLoading(false); } }; const updateJournal = async (id: string, data: UpdateJournalDto) => { setIsLoading(true); try { const updated = await financialApi.updateJournal(id, data); await fetchJournals(); return updated; } catch (err) { setError(err instanceof Error ? err.message : 'Error al actualizar diario'); throw err; } finally { setIsLoading(false); } }; const deleteJournal = async (id: string) => { setIsLoading(true); try { await financialApi.deleteJournal(id); await fetchJournals(); } catch (err) { setError(err instanceof Error ? err.message : 'Error al eliminar diario'); throw err; } finally { setIsLoading(false); } }; return { journals, total, page, totalPages, isLoading, error, setPage, refresh: fetchJournals, createJournal, updateJournal, deleteJournal, }; } // ==================== Journal Entries Hook ==================== export interface UseJournalEntriesOptions extends JournalEntryFilters { autoFetch?: boolean; } export function useJournalEntries(options: UseJournalEntriesOptions = {}) { const { autoFetch = true, ...filters } = options; const [entries, setEntries] = useState([]); const [total, setTotal] = useState(0); const [page, setPage] = useState(filters.page || 1); const [totalPages, setTotalPages] = useState(1); const [isLoading, setIsLoading] = useState(false); const [error, setError] = useState(null); const fetchEntries = useCallback(async () => { setIsLoading(true); setError(null); try { const response = await financialApi.getEntries({ ...filters, page }); setEntries(response.data); setTotal(response.meta.total); setTotalPages(response.meta.totalPages); } catch (err) { setError(err instanceof Error ? err.message : 'Error al cargar asientos'); } finally { setIsLoading(false); } }, [filters.companyId, filters.journalId, filters.status, filters.dateFrom, filters.dateTo, filters.search, filters.limit, filters.sortBy, filters.sortOrder, page]); useEffect(() => { if (autoFetch) { fetchEntries(); } }, [fetchEntries, autoFetch]); const createEntry = async (data: CreateJournalEntryDto) => { setIsLoading(true); try { const newEntry = await financialApi.createEntry(data); await fetchEntries(); return newEntry; } catch (err) { setError(err instanceof Error ? err.message : 'Error al crear asiento'); throw err; } finally { setIsLoading(false); } }; const updateEntry = async (id: string, data: UpdateJournalEntryDto) => { setIsLoading(true); try { const updated = await financialApi.updateEntry(id, data); await fetchEntries(); return updated; } catch (err) { setError(err instanceof Error ? err.message : 'Error al actualizar asiento'); throw err; } finally { setIsLoading(false); } }; const deleteEntry = async (id: string) => { setIsLoading(true); try { await financialApi.deleteEntry(id); await fetchEntries(); } catch (err) { setError(err instanceof Error ? err.message : 'Error al eliminar asiento'); throw err; } finally { setIsLoading(false); } }; const postEntry = async (id: string) => { setIsLoading(true); try { await financialApi.postEntry(id); await fetchEntries(); } catch (err) { setError(err instanceof Error ? err.message : 'Error al publicar asiento'); throw err; } finally { setIsLoading(false); } }; const cancelEntry = async (id: string) => { setIsLoading(true); try { await financialApi.cancelEntry(id); await fetchEntries(); } catch (err) { setError(err instanceof Error ? err.message : 'Error al cancelar asiento'); throw err; } finally { setIsLoading(false); } }; return { entries, total, page, totalPages, isLoading, error, setPage, refresh: fetchEntries, createEntry, updateEntry, deleteEntry, postEntry, cancelEntry, }; } // ==================== Single Journal Entry Hook ==================== export function useJournalEntry(entryId: string | null) { const [entry, setEntry] = useState(null); const [isLoading, setIsLoading] = useState(false); const [error, setError] = useState(null); const fetchEntry = useCallback(async () => { if (!entryId) { setEntry(null); return; } setIsLoading(true); setError(null); try { const data = await financialApi.getEntryById(entryId); setEntry(data); } catch (err) { setError(err instanceof Error ? err.message : 'Error al cargar asiento'); } finally { setIsLoading(false); } }, [entryId]); useEffect(() => { fetchEntry(); }, [fetchEntry]); return { entry, isLoading, error, refresh: fetchEntry, }; } // ==================== Invoices Hook ==================== export interface UseInvoicesOptions extends InvoiceFilters { autoFetch?: boolean; } export function useInvoices(options: UseInvoicesOptions = {}) { const { autoFetch = true, ...filters } = options; const [invoices, setInvoices] = useState([]); const [total, setTotal] = useState(0); const [page, setPage] = useState(filters.page || 1); const [totalPages, setTotalPages] = useState(1); const [isLoading, setIsLoading] = useState(false); const [error, setError] = useState(null); const fetchInvoices = useCallback(async () => { setIsLoading(true); setError(null); try { const response = await financialApi.getInvoices({ ...filters, page }); setInvoices(response.data); setTotal(response.meta.total); setTotalPages(response.meta.totalPages); } catch (err) { setError(err instanceof Error ? err.message : 'Error al cargar facturas'); } finally { setIsLoading(false); } }, [filters.companyId, filters.partnerId, filters.invoiceType, filters.status, filters.dateFrom, filters.dateTo, filters.search, filters.limit, filters.sortBy, filters.sortOrder, page]); useEffect(() => { if (autoFetch) { fetchInvoices(); } }, [fetchInvoices, autoFetch]); const createInvoice = async (data: CreateInvoiceDto) => { setIsLoading(true); try { const newInvoice = await financialApi.createInvoice(data); await fetchInvoices(); return newInvoice; } catch (err) { setError(err instanceof Error ? err.message : 'Error al crear factura'); throw err; } finally { setIsLoading(false); } }; const updateInvoice = async (id: string, data: UpdateInvoiceDto) => { setIsLoading(true); try { const updated = await financialApi.updateInvoice(id, data); await fetchInvoices(); return updated; } catch (err) { setError(err instanceof Error ? err.message : 'Error al actualizar factura'); throw err; } finally { setIsLoading(false); } }; const deleteInvoice = async (id: string) => { setIsLoading(true); try { await financialApi.deleteInvoice(id); await fetchInvoices(); } catch (err) { setError(err instanceof Error ? err.message : 'Error al eliminar factura'); throw err; } finally { setIsLoading(false); } }; const validateInvoice = async (id: string) => { setIsLoading(true); try { await financialApi.validateInvoice(id); await fetchInvoices(); } catch (err) { setError(err instanceof Error ? err.message : 'Error al validar factura'); throw err; } finally { setIsLoading(false); } }; const cancelInvoice = async (id: string) => { setIsLoading(true); try { await financialApi.cancelInvoice(id); await fetchInvoices(); } catch (err) { setError(err instanceof Error ? err.message : 'Error al cancelar factura'); throw err; } finally { setIsLoading(false); } }; return { invoices, total, page, totalPages, isLoading, error, setPage, refresh: fetchInvoices, createInvoice, updateInvoice, deleteInvoice, validateInvoice, cancelInvoice, }; } // ==================== Single Invoice Hook ==================== export function useInvoice(invoiceId: string | null) { const [invoice, setInvoice] = useState(null); const [isLoading, setIsLoading] = useState(false); const [error, setError] = useState(null); const fetchInvoice = useCallback(async () => { if (!invoiceId) { setInvoice(null); return; } setIsLoading(true); setError(null); try { const data = await financialApi.getInvoiceById(invoiceId); setInvoice(data); } catch (err) { setError(err instanceof Error ? err.message : 'Error al cargar factura'); } finally { setIsLoading(false); } }, [invoiceId]); useEffect(() => { fetchInvoice(); }, [fetchInvoice]); return { invoice, isLoading, error, refresh: fetchInvoice, }; } // ==================== Payments Hook ==================== export interface UsePaymentsOptions extends PaymentFilters { autoFetch?: boolean; } export function usePayments(options: UsePaymentsOptions = {}) { const { autoFetch = true, ...filters } = options; const [payments, setPayments] = useState([]); const [total, setTotal] = useState(0); const [page, setPage] = useState(filters.page || 1); const [totalPages, setTotalPages] = useState(1); const [isLoading, setIsLoading] = useState(false); const [error, setError] = useState(null); const fetchPayments = useCallback(async () => { setIsLoading(true); setError(null); try { const response = await financialApi.getPayments({ ...filters, page }); setPayments(response.data); setTotal(response.meta.total); setTotalPages(response.meta.totalPages); } catch (err) { setError(err instanceof Error ? err.message : 'Error al cargar pagos'); } finally { setIsLoading(false); } }, [filters.companyId, filters.partnerId, filters.paymentType, filters.paymentMethod, filters.status, filters.dateFrom, filters.dateTo, filters.search, filters.limit, filters.sortBy, filters.sortOrder, page]); useEffect(() => { if (autoFetch) { fetchPayments(); } }, [fetchPayments, autoFetch]); const createPayment = async (data: CreatePaymentDto) => { setIsLoading(true); try { const newPayment = await financialApi.createPayment(data); await fetchPayments(); return newPayment; } catch (err) { setError(err instanceof Error ? err.message : 'Error al crear pago'); throw err; } finally { setIsLoading(false); } }; const updatePayment = async (id: string, data: UpdatePaymentDto) => { setIsLoading(true); try { const updated = await financialApi.updatePayment(id, data); await fetchPayments(); return updated; } catch (err) { setError(err instanceof Error ? err.message : 'Error al actualizar pago'); throw err; } finally { setIsLoading(false); } }; const deletePayment = async (id: string) => { setIsLoading(true); try { await financialApi.deletePayment(id); await fetchPayments(); } catch (err) { setError(err instanceof Error ? err.message : 'Error al eliminar pago'); throw err; } finally { setIsLoading(false); } }; const postPayment = async (id: string) => { setIsLoading(true); try { await financialApi.postPayment(id); await fetchPayments(); } catch (err) { setError(err instanceof Error ? err.message : 'Error al publicar pago'); throw err; } finally { setIsLoading(false); } }; const cancelPayment = async (id: string) => { setIsLoading(true); try { await financialApi.cancelPayment(id); await fetchPayments(); } catch (err) { setError(err instanceof Error ? err.message : 'Error al cancelar pago'); throw err; } finally { setIsLoading(false); } }; return { payments, total, page, totalPages, isLoading, error, setPage, refresh: fetchPayments, createPayment, updatePayment, deletePayment, postPayment, cancelPayment, }; } // ==================== Single Payment Hook ==================== export function usePayment(paymentId: string | null) { const [payment, setPayment] = useState(null); const [isLoading, setIsLoading] = useState(false); const [error, setError] = useState(null); const fetchPayment = useCallback(async () => { if (!paymentId) { setPayment(null); return; } setIsLoading(true); setError(null); try { const data = await financialApi.getPaymentById(paymentId); setPayment(data); } catch (err) { setError(err instanceof Error ? err.message : 'Error al cargar pago'); } finally { setIsLoading(false); } }, [paymentId]); useEffect(() => { fetchPayment(); }, [fetchPayment]); return { payment, isLoading, error, refresh: fetchPayment, }; }