diff --git a/frontend/src/app/faturas/page.tsx b/frontend/src/app/faturas/page.tsx index 7936562..e120759 100644 --- a/frontend/src/app/faturas/page.tsx +++ b/frontend/src/app/faturas/page.tsx @@ -1,4 +1,4 @@ -'use client'; +'use client'; import { useEffect, useState } from 'react'; import { useRouter } from 'next/navigation'; @@ -11,14 +11,15 @@ import FaturaList from '@/components/FaturaList'; import { useFaturas, FaturaFormData } from '@/hooks/useFaturas'; import { RoleGuard } from '@/components/auth/RoleGuard'; import { UserRole } from '@/types/auth'; +import { FaturaDocument } from '@/types/legacyEntities'; const GestaoFaturas = () => { const router = useRouter(); const [user, setUser] = useState | null>(null); - const [editing, setEditing] = useState(null); + const [editing, setEditing] = useState(null); const [activeTab, setActiveTab] = useState<'lista' | 'cadastro'>('lista'); const [searchTerm, setSearchTerm] = useState(''); - + const { faturas, loading, @@ -30,21 +31,19 @@ const GestaoFaturas = () => { cadastrarFatura, atualizarFatura, deletarFatura, - setCurrentPage } = useFaturas(); - // 🔐 Verificar autenticação useEffect(() => { const initializeUser = async () => { try { const currentUser = await account.get(); setUser(currentUser); - + if (activeTab === 'lista') { await listarFaturas(); } } catch (error) { - console.error('❌ Usuário não autenticado:', error); + console.error('Usurio no autenticado:', error); router.push('/'); } }; @@ -60,16 +59,16 @@ const GestaoFaturas = () => { setActiveTab('lista'); } return success; - } else { - const success = await cadastrarFatura(formData); - if (success) { - setTimeout(() => setActiveTab('lista'), 2000); - } - return success; } + + const success = await cadastrarFatura(formData); + if (success) { + setTimeout(() => setActiveTab('lista'), 2000); + } + return success; }; - const handleEdit = (fatura: Models.Document) => { + const handleEdit = (fatura: FaturaDocument) => { setEditing(fatura); setActiveTab('cadastro'); }; @@ -80,33 +79,40 @@ const GestaoFaturas = () => { }; const handlePrevPage = async () => { - if (currentPage > 1) { - if (searchTerm.trim()) { - await buscarFaturas(searchTerm, currentPage - 1); - } else { - await listarFaturas(currentPage - 1); - } + if (currentPage <= 1) { + return; } + + if (searchTerm.trim()) { + await buscarFaturas(searchTerm, currentPage - 1); + return; + } + + await listarFaturas(currentPage - 1); }; const handleSearch = async (term: string) => { setSearchTerm(term); if (term.trim()) { await buscarFaturas(term, 1); - } else { - await listarFaturas(1); + return; } + + await listarFaturas(1); }; const handleNextPage = async () => { const totalPages = Math.ceil(totalFaturas / 10); - if (currentPage < totalPages) { - if (searchTerm.trim()) { - await buscarFaturas(searchTerm, currentPage + 1); - } else { - await listarFaturas(currentPage + 1); - } + if (currentPage >= totalPages) { + return; } + + if (searchTerm.trim()) { + await buscarFaturas(searchTerm, currentPage + 1); + return; + } + + await listarFaturas(currentPage + 1); }; if (!user) { @@ -114,7 +120,7 @@ const GestaoFaturas = () => {
-

Verificando autenticação...

+

Verificando autenticao...

); @@ -123,75 +129,73 @@ const GestaoFaturas = () => { return (
-
- -
- {/* Navegação por Tabs */} -
- -
- {/* Conteúdo das Tabs */} - {activeTab === 'lista' && ( - - searchTerm.trim() - ? buscarFaturas(searchTerm, currentPage) - : listarFaturas(currentPage) - } - onPrevPage={handlePrevPage} - onNextPage={handleNextPage} - onSearch={handleSearch} - /> - )} +
+
+ +
- {activeTab === 'cadastro' && ( - - )} + {activeTab === 'lista' && ( + + searchTerm.trim() + ? buscarFaturas(searchTerm, currentPage) + : listarFaturas(currentPage) + } + onPrevPage={handlePrevPage} + onNextPage={handleNextPage} + onSearch={handleSearch} + /> + )} + + {activeTab === 'cadastro' && ( + + )}
@@ -199,4 +203,3 @@ const GestaoFaturas = () => { }; export default GestaoFaturas; - diff --git a/frontend/src/components/CategoriaForm.tsx b/frontend/src/components/CategoriaForm.tsx index 2086e74..68928dd 100644 --- a/frontend/src/components/CategoriaForm.tsx +++ b/frontend/src/components/CategoriaForm.tsx @@ -1,67 +1,66 @@ -import React, { useState, useEffect } from 'react'; -import { Models } from '@/lib/appwrite'; +import React, { useState, useEffect } from 'react'; import { CategoriaFormData } from '@/hooks/useCategorias'; import { Plus } from 'lucide-react'; +import { CategoriaDocument } from '@/types/legacyEntities'; interface CategoriaFormProps { onSubmit: (data: CategoriaFormData) => Promise; onCancel?: () => void; - initialData?: Models.Document | null; + initialData?: CategoriaDocument | null; loading?: boolean; } -type CategoriaDocument = Models.Document & { - nome?: string; -}; - const CategoriaForm: React.FC = ({ onSubmit, onCancel, initialData, - loading = false + loading = false, }) => { const [formData, setFormData] = useState({ - nome: '' + nome: '', }); const [message, setMessage] = useState<{ type: 'success' | 'error'; text: string } | null>(null); useEffect(() => { if (initialData) { - const document = initialData as CategoriaDocument; - setFormData({ nome: document.nome || '' }); - } else { - setFormData({ nome: '' }); + setFormData({ nome: initialData.nome || '' }); + return; } + + setFormData({ nome: '' }); }, [initialData]); const handleSubmit = async (e: React.FormEvent) => { e.preventDefault(); - + const success = await onSubmit(formData); - + if (success) { - setMessage({ - type: 'success', - text: initialData ? '🔄 Categoria atualizada com sucesso!' : '🎉 Categoria cadastrada com sucesso!' + setMessage({ + type: 'success', + text: initialData ? 'Categoria atualizada com sucesso!' : 'Categoria cadastrada com sucesso!', }); - + if (!initialData) { setFormData({ nome: '' }); } - + setTimeout(() => setMessage(null), 3000); - } else { - setMessage({ - type: 'error', - text: initialData ? 'Erro ao atualizar categoria' : 'Erro ao cadastrar categoria' - }); + return; } + + setMessage({ + type: 'error', + text: initialData ? 'Erro ao atualizar categoria' : 'Erro ao cadastrar categoria', + }); }; const handleInputChange = (e: React.ChangeEvent) => { const { name, value } = e.target; setFormData(prev => ({ ...prev, [name]: value })); - if (message) setMessage(null); + if (message) { + setMessage(null); + } }; return ( @@ -109,7 +108,7 @@ const CategoriaForm: React.FC = ({ > {loading ? 'Processando...' : (initialData ? 'Atualizar' : <> Cadastrar)} - + {onCancel && ( {onCancel && ( )} @@ -114,5 +114,3 @@ const FaturaForm: React.FC = ({ }; export default FaturaForm; - - diff --git a/frontend/src/components/FaturaList.tsx b/frontend/src/components/FaturaList.tsx index 0d3a863..e738468 100644 --- a/frontend/src/components/FaturaList.tsx +++ b/frontend/src/components/FaturaList.tsx @@ -1,20 +1,20 @@ -import React from 'react'; -import { Models } from '@/lib/appwrite'; +import React from 'react'; import SearchBar from './SearchBar'; import RefreshButton from './RefreshButton'; import ListHeader from './ListHeader'; import DataTable, { Column } from './DataTable'; import Pagination from './Pagination'; import TableActions from './TableActions'; +import { FaturaDocument } from '@/types/legacyEntities'; interface FaturaListProps { - faturas: Models.Document[]; + faturas: FaturaDocument[]; loading: boolean; error: string | null; totalFaturas: number; currentPage: number; pageSize: number; - onEdit: (fatura: Models.Document) => void; + onEdit: (fatura: FaturaDocument) => void; onDelete: (id: string) => Promise; onRefresh: () => void; onPrevPage: () => void; @@ -34,7 +34,7 @@ const FaturaList: React.FC = ({ onRefresh, onPrevPage, onNextPage, - onSearch + onSearch, }) => { const totalPages = Math.ceil(totalFaturas / pageSize); const startItem = (currentPage - 1) * pageSize + 1; @@ -52,10 +52,14 @@ const FaturaList: React.FC = ({ } }; - const columns: Column[] = [ + const columns: Column[] = [ { key: 'nome', header: 'Nome' }, { key: '$id', header: 'ID' }, - { key: '$createdAt', header: 'Data de Criação', render: row => new Date(row.$createdAt).toLocaleDateString('pt-BR') }, + { + key: '$createdAt', + header: 'Data de Criao', + render: row => new Date(row.$createdAt).toLocaleDateString('pt-BR'), + }, ]; return ( @@ -85,7 +89,7 @@ const FaturaList: React.FC = ({ ( + actions={fatura => ( onEdit(fatura)} onDelete={() => handleDelete(fatura.$id)} diff --git a/frontend/src/hooks/useCategorias.ts b/frontend/src/hooks/useCategorias.ts index 68bdfe1..7611e5f 100644 --- a/frontend/src/hooks/useCategorias.ts +++ b/frontend/src/hooks/useCategorias.ts @@ -1,13 +1,13 @@ -import { useState, useCallback, useRef, useEffect } from 'react'; -import { Models } from '@/lib/appwrite'; +import { useState, useCallback, useRef, useEffect } from 'react'; import { categoriaService } from '@/services/categoriaService'; +import { CategoriaDocument } from '@/types/legacyEntities'; export interface CategoriaFormData { nome: string; } export interface UseCategoriasReturn { - categorias: Models.Document[]; + categorias: CategoriaDocument[]; loading: boolean; isChangingPage: boolean; isCreating: boolean; @@ -27,7 +27,7 @@ export interface UseCategoriasReturn { const PAGE_SIZE = 10; export const useCategorias = (): UseCategoriasReturn => { - const [categorias, setCategorias] = useState([]); + const [categorias, setCategorias] = useState([]); const [loading, setLoading] = useState(false); const [error, setError] = useState(null); const [totalCategorias, setTotalCategorias] = useState(0); @@ -37,9 +37,7 @@ export const useCategorias = (): UseCategoriasReturn => { const [searchTerm, setSearchTerm] = useState(''); const isInitialMount = useRef(true); - // Listagem via API - const listarCategorias = useCallback( - async (page = currentPage, search = searchTerm) => { + const listarCategorias = useCallback(async (page = currentPage, search = searchTerm) => { setIsChangingPage(true); setLoading(true); setError(null); @@ -50,53 +48,47 @@ export const useCategorias = (): UseCategoriasReturn => { : await categoriaService.listar(page, PAGE_SIZE); if (response.success) { - setCategorias((response.documents || []) as Models.Document[]); + setCategorias(response.documents || []); setTotalCategorias(response.total || 0); setCurrentPage(page); setSearchTerm(search); - } else { - setError(response.error || 'Erro ao carregar categorias'); + return; } - } catch (err) { - setError('Erro de conexão ao carregar categorias'); + + setError(response.error || 'Erro ao carregar categorias'); + } catch { + setError('Erro de conexo ao carregar categorias'); } finally { setLoading(false); setIsChangingPage(false); } }, [currentPage, searchTerm]); - const buscarCategorias = useCallback( - async (nome: string, page = 1) => { - setIsChangingPage(true); - setLoading(true); - setError(null); + const buscarCategorias = useCallback(async (nome: string, page = 1) => { + setIsChangingPage(true); + setLoading(true); + setError(null); - try { - const response = await categoriaService.buscarPorNome( - nome, - page, - PAGE_SIZE - ); + try { + const response = await categoriaService.buscarPorNome(nome, page, PAGE_SIZE); - if (response.success) { - setCategorias((response.documents || []) as Models.Document[]); - setTotalCategorias(response.total || 0); - setCurrentPage(page); - setSearchTerm(nome); - } else { - setError(response.error || 'Erro ao buscar categorias'); - } - } catch (err) { - setError('Erro de conexão ao buscar categorias'); - } finally { - setLoading(false); - setIsChangingPage(false); + if (response.success) { + setCategorias(response.documents || []); + setTotalCategorias(response.total || 0); + setCurrentPage(page); + setSearchTerm(nome); + return; } - }, - [] - ); - // Operações de criação, atualização e exclusão continuam usando API REST + setError(response.error || 'Erro ao buscar categorias'); + } catch { + setError('Erro de conexo ao buscar categorias'); + } finally { + setLoading(false); + setIsChangingPage(false); + } + }, []); + const cadastrarCategoria = useCallback(async (formData: CategoriaFormData): Promise => { setIsCreating(true); setError(null); @@ -107,12 +99,12 @@ export const useCategorias = (): UseCategoriasReturn => { if (response.success) { await listarCategorias(1, searchTerm); return true; - } else { - setError(response.error || 'Erro ao cadastrar categoria'); - return false; } - } catch (err) { - setError('Erro de conexão ao cadastrar categoria'); + + setError(response.error || 'Erro ao cadastrar categoria'); + return false; + } catch { + setError('Erro de conexo ao cadastrar categoria'); return false; } finally { setIsCreating(false); @@ -129,17 +121,17 @@ export const useCategorias = (): UseCategoriasReturn => { if (response.success) { await listarCategorias(currentPage, searchTerm); return true; - } else { - setError(response.error || 'Erro ao atualizar categoria'); - return false; } - } catch (err) { - setError('Erro de conexão ao atualizar categoria'); + + setError(response.error || 'Erro ao atualizar categoria'); + return false; + } catch { + setError('Erro de conexo ao atualizar categoria'); return false; } finally { setLoading(false); } - }, [currentPage, listarCategorias]); + }, [currentPage, listarCategorias, searchTerm]); const deletarCategoria = useCallback(async (id: string): Promise => { setLoading(true); @@ -151,17 +143,17 @@ export const useCategorias = (): UseCategoriasReturn => { if (response.success) { await listarCategorias(currentPage, searchTerm); return true; - } else { - setError(response.error || 'Erro ao deletar categoria'); - return false; } - } catch (err) { - setError('Erro de conexão ao deletar categoria'); + + setError(response.error || 'Erro ao deletar categoria'); + return false; + } catch { + setError('Erro de conexo ao deletar categoria'); return false; } finally { setLoading(false); } - }, [currentPage, listarCategorias]); + }, [currentPage, listarCategorias, searchTerm]); useEffect(() => { if (isInitialMount.current) { @@ -171,9 +163,10 @@ export const useCategorias = (): UseCategoriasReturn => { if (searchTerm.trim()) { buscarCategorias(searchTerm, currentPage); - } else { - listarCategorias(currentPage); + return; } + + listarCategorias(currentPage); }, [currentPage, searchTerm, listarCategorias, buscarCategorias]); return { @@ -191,7 +184,6 @@ export const useCategorias = (): UseCategoriasReturn => { deletarCategoria, setCurrentPage, searchTerm, - setSearchTerm + setSearchTerm, }; }; - diff --git a/frontend/src/hooks/useFaturas.ts b/frontend/src/hooks/useFaturas.ts index 003e8a5..e4d632a 100644 --- a/frontend/src/hooks/useFaturas.ts +++ b/frontend/src/hooks/useFaturas.ts @@ -1,13 +1,13 @@ -import { useState, useCallback } from 'react'; -import { Models } from '@/lib/appwrite'; +import { useState, useCallback } from 'react'; import { faturaService } from '@/services/faturaService'; +import { FaturaDocument } from '@/types/legacyEntities'; export interface FaturaFormData { nome: string; } export interface UseFaturasReturn { - faturas: Models.Document[]; + faturas: FaturaDocument[]; loading: boolean; error: string | null; totalFaturas: number; @@ -23,13 +23,12 @@ export interface UseFaturasReturn { const PAGE_SIZE = 10; export const useFaturas = (): UseFaturasReturn => { - const [faturas, setFaturas] = useState([]); + const [faturas, setFaturas] = useState([]); const [loading, setLoading] = useState(false); const [error, setError] = useState(null); const [totalFaturas, setTotalFaturas] = useState(0); const [currentPage, setCurrentPage] = useState(1); - // Listagem usando SDK do Appwrite const listarFaturas = useCallback(async (page = currentPage) => { setLoading(true); setError(null); @@ -38,48 +37,42 @@ export const useFaturas = (): UseFaturasReturn => { const response = await faturaService.listar(page, PAGE_SIZE); if (response.success) { - setFaturas((response.documents || []) as Models.Document[]); + setFaturas(response.documents || []); setTotalFaturas(response.total || 0); setCurrentPage(page); - } else { - setError(response.error || 'Erro ao carregar faturas'); + return; } - } catch (err) { - setError('Erro de conexão ao carregar faturas'); + + setError(response.error || 'Erro ao carregar faturas'); + } catch { + setError('Erro de conexo ao carregar faturas'); } finally { setLoading(false); } }, [currentPage]); - const buscarFaturas = useCallback( - async (nome: string, page = 1) => { - setLoading(true); - setError(null); + const buscarFaturas = useCallback(async (nome: string, page = 1) => { + setLoading(true); + setError(null); - try { - const response = await faturaService.buscarPorNome( - nome, - page, - PAGE_SIZE - ); + try { + const response = await faturaService.buscarPorNome(nome, page, PAGE_SIZE); - if (response.success) { - setFaturas((response.documents || []) as Models.Document[]); - setTotalFaturas(response.total || 0); - setCurrentPage(page); - } else { - setError(response.error || 'Erro ao buscar faturas'); - } - } catch (err) { - setError('Erro de conexão ao buscar faturas'); - } finally { - setLoading(false); + if (response.success) { + setFaturas(response.documents || []); + setTotalFaturas(response.total || 0); + setCurrentPage(page); + return; } - }, - [] - ); - // Operações de criação, atualização e exclusão continuam usando API REST + setError(response.error || 'Erro ao buscar faturas'); + } catch { + setError('Erro de conexo ao buscar faturas'); + } finally { + setLoading(false); + } + }, []); + const cadastrarFatura = useCallback(async (formData: FaturaFormData): Promise => { setLoading(true); setError(null); @@ -90,12 +83,12 @@ export const useFaturas = (): UseFaturasReturn => { if (response.success) { await listarFaturas(currentPage); return true; - } else { - setError(response.error || 'Erro ao cadastrar fatura'); - return false; } - } catch (err) { - setError('Erro de conexão ao cadastrar fatura'); + + setError(response.error || 'Erro ao cadastrar fatura'); + return false; + } catch { + setError('Erro de conexo ao cadastrar fatura'); return false; } finally { setLoading(false); @@ -112,12 +105,12 @@ export const useFaturas = (): UseFaturasReturn => { if (response.success) { await listarFaturas(currentPage); return true; - } else { - setError(response.error || 'Erro ao atualizar fatura'); - return false; } - } catch (err) { - setError('Erro de conexão ao atualizar fatura'); + + setError(response.error || 'Erro ao atualizar fatura'); + return false; + } catch { + setError('Erro de conexo ao atualizar fatura'); return false; } finally { setLoading(false); @@ -134,12 +127,12 @@ export const useFaturas = (): UseFaturasReturn => { if (response.success) { await listarFaturas(currentPage); return true; - } else { - setError(response.error || 'Erro ao deletar fatura'); - return false; } - } catch (err) { - setError('Erro de conexão ao deletar fatura'); + + setError(response.error || 'Erro ao deletar fatura'); + return false; + } catch { + setError('Erro de conexo ao deletar fatura'); return false; } finally { setLoading(false); @@ -160,5 +153,3 @@ export const useFaturas = (): UseFaturasReturn => { setCurrentPage, }; }; - - diff --git a/frontend/src/services/categoriaService.ts b/frontend/src/services/categoriaService.ts index 930aab6..a3e34cf 100644 --- a/frontend/src/services/categoriaService.ts +++ b/frontend/src/services/categoriaService.ts @@ -1,29 +1,29 @@ -// @ts-nocheck -interface CategoriaData { +import { CategoriaDocument, ServiceResponse } from '@/types/legacyEntities'; + +export interface CategoriaData { id?: string; nome?: string; - [key: string]: any; } -interface ServiceResponse { - success: boolean; - data?: T; - documents?: T[]; - total?: number; - error?: string; - message?: string; -} +const emptyList = (): ServiceResponse => ({ + success: true, + data: null, + documents: [], + total: 0, +}); -const emptyList = (): ServiceResponse => ({ success: true, data: [], documents: [], total: 0 }); -const removed = (message = 'Service removido'): ServiceResponse => ({ success: false, error: message, message }); +const removed = (message = 'Service removido'): ServiceResponse => ({ + success: false, + error: message, + message, +}); export const categoriaService = { - listarTodas: async () => emptyList(), - listar: async (_page = 1, _limit = 10) => emptyList(), - buscarPorNome: async (_nome: string, _page = 1, _limit = 10) => emptyList(), - buscarPorId: async (_id?: string) => ({ success: true, data: null as CategoriaData | null }), + listarTodas: async () => emptyList(), + listar: async (_page = 1, _limit = 10) => emptyList(), + buscarPorNome: async (_nome: string, _page = 1, _limit = 10) => emptyList(), + buscarPorId: async (_id?: string): Promise> => ({ success: true, data: null }), criar: async (_data?: CategoriaData) => removed(), atualizar: async (_id?: string, _data?: Partial) => removed(), deletar: async (_id?: string) => removed(), }; - diff --git a/frontend/src/services/faturaService.ts b/frontend/src/services/faturaService.ts index 18c0039..3bd7d7d 100644 --- a/frontend/src/services/faturaService.ts +++ b/frontend/src/services/faturaService.ts @@ -1,27 +1,30 @@ -interface FaturaData { +import { FaturaDocument, ServiceResponse } from '@/types/legacyEntities'; + +export interface FaturaData { id?: string; - [key: string]: any; + nome?: string; } -interface ServiceResponse { - success: boolean; - data?: T; - documents?: T[]; - total?: number; - error?: string; - message?: string; -} +const emptyList = (): ServiceResponse => ({ + success: true, + data: null, + documents: [], + total: 0, +}); -const emptyList = (): ServiceResponse => ({ success: true, documents: [], total: 0 }); -const removed = (message = 'Service removido'): ServiceResponse => ({ success: false, error: message, message }); +const removed = (message = 'Service removido'): ServiceResponse => ({ + success: false, + error: message, + message, +}); export const faturaService = { - listar: async (_page = 1, _limit = 10) => emptyList(), - buscarPorNome: async (_nome: string, _page = 1, _limit = 10) => emptyList(), + listar: async (_page = 1, _limit = 10) => emptyList(), + buscarPorNome: async (_nome: string, _page = 1, _limit = 10) => emptyList(), criar: async (_data?: FaturaData) => removed(), criarFatura: async (_data?: FaturaData) => removed(), - buscarPorUserId: async () => emptyList(), - buscarPorId: async (_id?: string) => ({ success: true, data: null as FaturaData | null }), + buscarPorUserId: async () => emptyList(), + buscarPorId: async (_id?: string): Promise> => ({ success: true, data: null }), atualizar: async (_id?: string, _data?: Partial) => removed(), deletar: async (_id?: string) => removed(), atualizarFaturaParcial: async (_id?: string, _data?: Partial) => removed(), diff --git a/frontend/src/types/legacyEntities.ts b/frontend/src/types/legacyEntities.ts new file mode 100644 index 0000000..86f1802 --- /dev/null +++ b/frontend/src/types/legacyEntities.ts @@ -0,0 +1,23 @@ +export interface LegacyDocument { + $id: string; + $createdAt: string; + $updatedAt?: string; + [key: string]: unknown; +} + +export interface CategoriaDocument extends LegacyDocument { + nome?: string; +} + +export interface FaturaDocument extends LegacyDocument { + nome?: string; +} + +export interface ServiceResponse { + success: boolean; + data?: TDocument | null; + documents?: TDocument[]; + total?: number; + error?: string; + message?: string; +}