saveinmed/frontend/src/hooks/useProdutos.ts
Tiago Yamamoto b0ffceefa8 fix: resolve infinite loop in useEffect/useCallback hooks
- useProdutos: replaced useCallback([currentPage]) with useRef + useCallback([])
- useEntregas: same fix for listarEntregas
- produtos/page: removed unstable listarProdutos from useEffect deps
- entregas/page: removed unstable listarEntregas from useEffect deps

Root cause: useCallback depended on currentPage but setCurrentPage inside caused circular dependency.
2026-03-04 20:57:00 -06:00

136 lines
3.7 KiB
TypeScript

import { useState, useCallback, useRef } from 'react';
import { Models } from 'appwrite';
import { produtoService, ProdutoData } from '@/services/produtoService';
export interface ProdutoFormData {
'preco-original': number;
'preco-atual': number;
'catalogo-produto-id': string;
'empresa-id': string;
}
export interface UseProdutosReturn {
produtos: Models.Document[];
loading: boolean;
error: string | null;
totalProdutos: number;
currentPage: number;
listarProdutos: (page?: number) => Promise<void>;
cadastrarProduto: (data: ProdutoFormData) => Promise<boolean>;
atualizarProduto: (id: string, data: ProdutoFormData) => Promise<boolean>;
deletarProduto: (id: string) => Promise<boolean>;
setCurrentPage: (page: number) => void;
}
const PAGE_SIZE = 10;
export const useProdutos = (): UseProdutosReturn => {
const [produtos, setProdutos] = useState<Models.Document[]>([]);
const [loading, setLoading] = useState(false);
const [error, setError] = useState<string | null>(null);
const [totalProdutos, setTotalProdutos] = useState(0);
const [currentPage, setCurrentPage] = useState(1);
const currentPageRef = useRef(currentPage);
currentPageRef.current = currentPage;
const listarProdutos = useCallback(async (page?: number) => {
const targetPage = page ?? currentPageRef.current;
setLoading(true);
setError(null);
try {
const response = await produtoService.listar(targetPage, PAGE_SIZE);
if (response.success) {
setProdutos(response.documents || []);
setTotalProdutos(response.total || 0);
setCurrentPage(targetPage);
} else {
setError(response.error || 'Erro ao carregar produtos');
}
} catch (err) {
setError('Erro de conexão ao carregar produtos');
} finally {
setLoading(false);
}
}, []);
const cadastrarProduto = useCallback(async (formData: ProdutoFormData): Promise<boolean> => {
setLoading(true);
setError(null);
try {
const response = await produtoService.criar(formData);
if (response.success) {
await listarProdutos(currentPageRef.current);
return true;
} else {
setError(response.error || 'Erro ao cadastrar produto');
return false;
}
} catch (err) {
setError('Erro de conexão ao cadastrar produto');
return false;
} finally {
setLoading(false);
}
}, [listarProdutos]);
const atualizarProduto = useCallback(async (id: string, formData: ProdutoFormData): Promise<boolean> => {
setLoading(true);
setError(null);
try {
const response = await produtoService.atualizar(id, formData);
if (response.success) {
await listarProdutos(currentPageRef.current);
return true;
} else {
setError(response.error || 'Erro ao atualizar produto');
return false;
}
} catch (err) {
setError('Erro de conexão ao atualizar produto');
return false;
} finally {
setLoading(false);
}
}, [listarProdutos]);
const deletarProduto = useCallback(async (id: string): Promise<boolean> => {
setLoading(true);
setError(null);
try {
const response = await produtoService.deletar(id);
if (response.success) {
await listarProdutos(currentPageRef.current);
return true;
} else {
setError(response.error || 'Erro ao deletar produto');
return false;
}
} catch (err) {
setError('Erro de conexão ao deletar produto');
return false;
} finally {
setLoading(false);
}
}, [listarProdutos]);
return {
produtos,
loading,
error,
totalProdutos,
currentPage,
listarProdutos,
cadastrarProduto,
atualizarProduto,
deletarProduto,
setCurrentPage
};
};