refactor(frontend): type legacy payments and catalog flows
This commit is contained in:
parent
b633939d4e
commit
48a54a616e
8 changed files with 279 additions and 285 deletions
|
|
@ -1,4 +1,3 @@
|
||||||
// @ts-nocheck
|
|
||||||
'use client';
|
'use client';
|
||||||
|
|
||||||
import { useEffect, useState } from 'react';
|
import { useEffect, useState } from 'react';
|
||||||
|
|
@ -11,11 +10,12 @@ import PagamentoForm from '@/components/PagamentoForm';
|
||||||
import PagamentoList from '@/components/PagamentoList';
|
import PagamentoList from '@/components/PagamentoList';
|
||||||
import { usePagamentos } from '@/hooks/usePagamentos';
|
import { usePagamentos } from '@/hooks/usePagamentos';
|
||||||
import { PagamentoData } from '@/services/pagamentoService';
|
import { PagamentoData } from '@/services/pagamentoService';
|
||||||
|
import { PagamentoDocument } from '@/types/legacyEntities';
|
||||||
|
|
||||||
const GestaoPagamentos = () => {
|
const GestaoPagamentos = () => {
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const [user, setUser] = useState<Models.User<Models.Preferences> | null>(null);
|
const [user, setUser] = useState<Models.User<Models.Preferences> | null>(null);
|
||||||
const [editing, setEditing] = useState<Models.Document | null>(null);
|
const [editing, setEditing] = useState<PagamentoDocument | null>(null);
|
||||||
const [activeTab, setActiveTab] = useState<'lista' | 'cadastro'>('lista');
|
const [activeTab, setActiveTab] = useState<'lista' | 'cadastro'>('lista');
|
||||||
const [searchTerm, setSearchTerm] = useState('');
|
const [searchTerm, setSearchTerm] = useState('');
|
||||||
|
|
||||||
|
|
@ -41,7 +41,7 @@ const GestaoPagamentos = () => {
|
||||||
await listarPagamentos(1, searchTerm);
|
await listarPagamentos(1, searchTerm);
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Usuário não autenticado:', error);
|
console.error('Usuário não autenticado:', error);
|
||||||
router.push('/');
|
router.push('/');
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
@ -57,17 +57,17 @@ const GestaoPagamentos = () => {
|
||||||
setActiveTab('lista');
|
setActiveTab('lista');
|
||||||
}
|
}
|
||||||
return success;
|
return success;
|
||||||
} else {
|
|
||||||
const success = await cadastrarPagamento(formData);
|
|
||||||
if (success) {
|
|
||||||
setTimeout(() => setActiveTab('lista'), 2000);
|
|
||||||
}
|
|
||||||
return success;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const success = await cadastrarPagamento(formData);
|
||||||
|
if (success) {
|
||||||
|
setTimeout(() => setActiveTab('lista'), 2000);
|
||||||
|
}
|
||||||
|
return success;
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleEdit = (pag: Models.Document) => {
|
const handleEdit = (pagamento: PagamentoDocument) => {
|
||||||
setEditing(pag);
|
setEditing(pagamento);
|
||||||
setActiveTab('cadastro');
|
setActiveTab('cadastro');
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -99,7 +99,7 @@ const GestaoPagamentos = () => {
|
||||||
<div className="min-h-screen bg-gray-50 flex items-center justify-center">
|
<div className="min-h-screen bg-gray-50 flex items-center justify-center">
|
||||||
<div className="text-center">
|
<div className="text-center">
|
||||||
<div className="animate-spin rounded-full h-12 w-12 border-b-2 border-blue-600 mx-auto mb-4"></div>
|
<div className="animate-spin rounded-full h-12 w-12 border-b-2 border-blue-600 mx-auto mb-4"></div>
|
||||||
<p className="text-gray-600">Verificando autenticação...</p>
|
<p className="text-gray-600">Verificando autenticação...</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|
@ -109,7 +109,7 @@ const GestaoPagamentos = () => {
|
||||||
<div className="min-h-screen bg-gray-50">
|
<div className="min-h-screen bg-gray-50">
|
||||||
<Header
|
<Header
|
||||||
user={user}
|
user={user}
|
||||||
title="Gestão de Pagamentos"
|
title="Gestão de Pagamentos"
|
||||||
subtitle="Gerencie os pagamentos da plataforma"
|
subtitle="Gerencie os pagamentos da plataforma"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
|
@ -178,4 +178,3 @@ const GestaoPagamentos = () => {
|
||||||
};
|
};
|
||||||
|
|
||||||
export default GestaoPagamentos;
|
export default GestaoPagamentos;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,20 +1,20 @@
|
||||||
import React from "react";
|
import React from 'react';
|
||||||
import { Models } from "@/lib/appwrite";
|
import TableActions from './TableActions';
|
||||||
import TableActions from "./TableActions";
|
import { CatalogoProdutoDocument } from '@/types/legacyEntities';
|
||||||
|
|
||||||
interface CatalogoProdutosListProps {
|
interface CatalogoProdutosListProps {
|
||||||
produtos: Models.Document[];
|
produtos: CatalogoProdutoDocument[];
|
||||||
loading: boolean;
|
loading: boolean;
|
||||||
isChangingPage?: boolean;
|
isChangingPage?: boolean;
|
||||||
totalProdutos: number;
|
totalProdutos: number;
|
||||||
currentPage: number;
|
currentPage: number;
|
||||||
pageSize: number;
|
pageSize: number;
|
||||||
onEdit: (produto: Models.Document) => void;
|
onEdit: (produto: CatalogoProdutoDocument) => void;
|
||||||
onDelete: (id: string) => void;
|
onDelete: (id: string) => void;
|
||||||
onView: (produto: Models.Document) => void;
|
onView: (produto: CatalogoProdutoDocument) => void;
|
||||||
onPrevPage: () => void;
|
onPrevPage: () => void;
|
||||||
onNextPage: () => void;
|
onNextPage: () => void;
|
||||||
onRowClick?: (produto: Models.Document) => void;
|
onRowClick?: (produto: CatalogoProdutoDocument) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
const CatalogoProdutosList: React.FC<CatalogoProdutosListProps> = ({
|
const CatalogoProdutosList: React.FC<CatalogoProdutosListProps> = ({
|
||||||
|
|
@ -42,7 +42,7 @@ const CatalogoProdutosList: React.FC<CatalogoProdutosListProps> = ({
|
||||||
<div className="flex items-center justify-center p-8">
|
<div className="flex items-center justify-center p-8">
|
||||||
<div className="animate-spin rounded-full h-8 w-8 border-b-2 border-blue-600"></div>
|
<div className="animate-spin rounded-full h-8 w-8 border-b-2 border-blue-600"></div>
|
||||||
<span className="ml-2 text-gray-600">
|
<span className="ml-2 text-gray-600">
|
||||||
{isChangingPage ? "Carregando página..." : "Carregando produtos..."}
|
{isChangingPage ? 'Carregando página...' : 'Carregando produtos...'}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -67,36 +67,17 @@ const CatalogoProdutosList: React.FC<CatalogoProdutosListProps> = ({
|
||||||
<table className="laboratory-table w-full">
|
<table className="laboratory-table w-full">
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th className="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider bg-gray-50/50">
|
<th className="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider bg-gray-50/50">Nome do Produto</th>
|
||||||
Nome do Produto
|
<th className="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider bg-gray-50/50">Código Interno</th>
|
||||||
</th>
|
<th className="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider bg-gray-50/50">Código EAN</th>
|
||||||
<th className="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider bg-gray-50/50">
|
<th className="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider bg-gray-50/50">Descrição</th>
|
||||||
Código Interno
|
<th className="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider bg-gray-50/50">Preço Atual</th>
|
||||||
</th>
|
<th className="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider bg-gray-50/50">Ações</th>
|
||||||
<th className="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider bg-gray-50/50">
|
|
||||||
Código EAN
|
|
||||||
</th>
|
|
||||||
<th className="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider bg-gray-50/50">
|
|
||||||
Descrição
|
|
||||||
</th>
|
|
||||||
<th className="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider bg-gray-50/50">
|
|
||||||
Preço Atual
|
|
||||||
</th>
|
|
||||||
<th className="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider bg-gray-50/50">
|
|
||||||
Ações
|
|
||||||
</th>
|
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody className="bg-white divide-y divide-gray-200">
|
<tbody className="bg-white divide-y divide-gray-200">
|
||||||
{produtos.map((produto) => {
|
{produtos.map(produto => {
|
||||||
const produtoData = produto as any;
|
const nomeProduto = produto.nome || produto.descricao || 'N/A';
|
||||||
const catalogoProduto = produtoData["catalogo-produtos"];
|
|
||||||
const nomeProduto =
|
|
||||||
produtoData.nome ||
|
|
||||||
catalogoProduto?.nome ||
|
|
||||||
produtoData.descricao ||
|
|
||||||
catalogoProduto?.descricao ||
|
|
||||||
"N/A";
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<tr
|
<tr
|
||||||
|
|
@ -105,19 +86,11 @@ const CatalogoProdutosList: React.FC<CatalogoProdutosListProps> = ({
|
||||||
onClick={() => onRowClick?.(produto)}
|
onClick={() => onRowClick?.(produto)}
|
||||||
>
|
>
|
||||||
<td className="px-6 py-4 max-w-xs font-medium text-gray-900 line-clamp-2">{nomeProduto}</td>
|
<td className="px-6 py-4 max-w-xs font-medium text-gray-900 line-clamp-2">{nomeProduto}</td>
|
||||||
|
<td className="px-6 py-4 text-sm text-gray-700">{produto['codigo-interno'] || 'N/A'}</td>
|
||||||
|
<td className="px-6 py-4 text-sm text-gray-700">{produto['codigo-ean'] || 'N/A'}</td>
|
||||||
|
<td className="px-6 py-4 max-w-xs text-sm text-gray-700 line-clamp-2">{produto.descricao || 'N/A'}</td>
|
||||||
<td className="px-6 py-4 text-sm text-gray-700">
|
<td className="px-6 py-4 text-sm text-gray-700">
|
||||||
{produtoData["codigo-interno"] || catalogoProduto?.["codigo-interno"] || "N/A"}
|
{typeof produto['preco-atual'] === 'number' ? `R$ ${produto['preco-atual'].toFixed(2)}` : 'N/A'}
|
||||||
</td>
|
|
||||||
<td className="px-6 py-4 text-sm text-gray-700">
|
|
||||||
{produtoData["codigo-ean"] || catalogoProduto?.["codigo-ean"] || "N/A"}
|
|
||||||
</td>
|
|
||||||
<td className="px-6 py-4 max-w-xs text-sm text-gray-700 line-clamp-2">
|
|
||||||
{produtoData.descricao || catalogoProduto?.descricao || "N/A"}
|
|
||||||
</td>
|
|
||||||
<td className="px-6 py-4 text-sm text-gray-700">
|
|
||||||
{typeof produtoData["preco-atual"] === "number"
|
|
||||||
? `R$ ${produtoData["preco-atual"].toFixed(2)}`
|
|
||||||
: "N/A"}
|
|
||||||
</td>
|
</td>
|
||||||
<td className="px-6 py-4 whitespace-nowrap">
|
<td className="px-6 py-4 whitespace-nowrap">
|
||||||
<TableActions
|
<TableActions
|
||||||
|
|
@ -143,25 +116,23 @@ const CatalogoProdutosList: React.FC<CatalogoProdutosListProps> = ({
|
||||||
disabled={currentPage === 1}
|
disabled={currentPage === 1}
|
||||||
className={`px-3 py-1 rounded-md text-sm font-medium ${
|
className={`px-3 py-1 rounded-md text-sm font-medium ${
|
||||||
currentPage === 1
|
currentPage === 1
|
||||||
? "bg-gray-100 text-gray-400 cursor-not-allowed"
|
? 'bg-gray-100 text-gray-400 cursor-not-allowed'
|
||||||
: "bg-white text-gray-700 hover:bg-gray-50 border border-gray-300"
|
: 'bg-white text-gray-700 hover:bg-gray-50 border border-gray-300'
|
||||||
}`}
|
}`}
|
||||||
>
|
>
|
||||||
Anterior
|
Anterior
|
||||||
</button>
|
</button>
|
||||||
<span className="px-3 py-1 text-sm text-gray-700">
|
<span className="px-3 py-1 text-sm text-gray-700">Página {currentPage} de {totalPages}</span>
|
||||||
Página {currentPage} de {totalPages}
|
|
||||||
</span>
|
|
||||||
<button
|
<button
|
||||||
onClick={onNextPage}
|
onClick={onNextPage}
|
||||||
disabled={currentPage === totalPages}
|
disabled={currentPage === totalPages}
|
||||||
className={`px-3 py-1 rounded-md text-sm font-medium ${
|
className={`px-3 py-1 rounded-md text-sm font-medium ${
|
||||||
currentPage === totalPages
|
currentPage === totalPages
|
||||||
? "bg-gray-100 text-gray-400 cursor-not-allowed"
|
? 'bg-gray-100 text-gray-400 cursor-not-allowed'
|
||||||
: "bg-white text-gray-700 hover:bg-gray-50 border border-gray-300"
|
: 'bg-white text-gray-700 hover:bg-gray-50 border border-gray-300'
|
||||||
}`}
|
}`}
|
||||||
>
|
>
|
||||||
Próxima
|
Próxima
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -171,4 +142,3 @@ const CatalogoProdutosList: React.FC<CatalogoProdutosListProps> = ({
|
||||||
};
|
};
|
||||||
|
|
||||||
export default CatalogoProdutosList;
|
export default CatalogoProdutosList;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,86 +1,112 @@
|
||||||
import React, { useState, useEffect } from 'react';
|
import React, { useState, useEffect } from 'react';
|
||||||
import { Models } from '@/lib/appwrite';
|
import type { PagamentoData } from '@/services/pagamentoService';
|
||||||
|
import { PagamentoDocument } from '@/types/legacyEntities';
|
||||||
// Interface para dados do pagamento
|
|
||||||
interface PagamentoData {
|
|
||||||
pedidos: string;
|
|
||||||
status: 'pendente' | 'pago' | 'cancelado';
|
|
||||||
metodo: 'pix' | 'cartao';
|
|
||||||
valor: number;
|
|
||||||
}
|
|
||||||
|
|
||||||
interface PagamentoFormProps {
|
interface PagamentoFormProps {
|
||||||
onSubmit: (data: PagamentoData) => Promise<boolean>;
|
onSubmit: (data: PagamentoData) => Promise<boolean>;
|
||||||
onCancel?: () => void;
|
onCancel?: () => void;
|
||||||
initialData?: PagamentoData | null;
|
initialData?: PagamentoDocument | null;
|
||||||
loading?: boolean;
|
loading?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
const statusOptions = ['pendente', 'pago', 'cancelado'];
|
const statusOptions: PagamentoData['status'][] = ['pendente', 'pago', 'cancelado'];
|
||||||
const metodoOptions = ['pix', 'cartao'];
|
const metodoOptions: PagamentoData['metodo'][] = ['pix', 'cartao'];
|
||||||
|
|
||||||
|
const normalizePedidos = (pedidos: PagamentoDocument['pedidos']): string[] => {
|
||||||
|
if (Array.isArray(pedidos)) {
|
||||||
|
return pedidos.map(item => String(item));
|
||||||
|
}
|
||||||
|
if (pedidos && typeof pedidos === 'object') {
|
||||||
|
return pedidos.$id ? [pedidos.$id] : [];
|
||||||
|
}
|
||||||
|
if (typeof pedidos === 'string' && pedidos.trim()) {
|
||||||
|
return [pedidos.trim()];
|
||||||
|
}
|
||||||
|
return [];
|
||||||
|
};
|
||||||
|
|
||||||
const PagamentoForm: React.FC<PagamentoFormProps> = ({
|
const PagamentoForm: React.FC<PagamentoFormProps> = ({
|
||||||
onSubmit,
|
onSubmit,
|
||||||
onCancel,
|
onCancel,
|
||||||
initialData,
|
initialData,
|
||||||
loading = false
|
loading = false,
|
||||||
}) => {
|
}) => {
|
||||||
const [formData, setFormData] = useState<PagamentoData>({
|
const [formData, setFormData] = useState<PagamentoData>({
|
||||||
pedidos: '',
|
pedidos: [],
|
||||||
status: 'pendente',
|
status: 'pendente',
|
||||||
metodo: 'pix',
|
metodo: 'pix',
|
||||||
valor: 0
|
valor: 0,
|
||||||
});
|
});
|
||||||
|
const [pedidoInput, setPedidoInput] = useState('');
|
||||||
const [message, setMessage] = useState<{ type: 'success' | 'error'; text: string } | null>(null);
|
const [message, setMessage] = useState<{ type: 'success' | 'error'; text: string } | null>(null);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (initialData) {
|
if (initialData) {
|
||||||
|
const pedidos = normalizePedidos(initialData.pedidos);
|
||||||
setFormData({
|
setFormData({
|
||||||
pedidos: initialData.pedidos || '',
|
pedidos,
|
||||||
status: initialData.status || 'pendente',
|
status: initialData.status || 'pendente',
|
||||||
metodo: initialData.metodo || 'pix',
|
metodo: initialData.metodo || 'pix',
|
||||||
valor: Number(initialData.valor) || 0
|
valor: Number(initialData.valor) || 0,
|
||||||
});
|
});
|
||||||
} else {
|
setPedidoInput(pedidos.join(', '));
|
||||||
setFormData({ pedidos: '', status: 'pendente', metodo: 'pix', valor: 0 });
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
setFormData({ pedidos: [], status: 'pendente', metodo: 'pix', valor: 0 });
|
||||||
|
setPedidoInput('');
|
||||||
}, [initialData]);
|
}, [initialData]);
|
||||||
|
|
||||||
const handleSubmit = async (e: React.FormEvent) => {
|
const handleSubmit = async (e: React.FormEvent) => {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
|
const pedidos = pedidoInput
|
||||||
|
.split(',')
|
||||||
|
.map(item => item.trim())
|
||||||
|
.filter(Boolean);
|
||||||
|
|
||||||
const success = await onSubmit(formData);
|
const success = await onSubmit({ ...formData, pedidos });
|
||||||
|
|
||||||
if (success) {
|
if (success) {
|
||||||
setMessage({
|
setMessage({
|
||||||
type: 'success',
|
type: 'success',
|
||||||
text: initialData ? '🔄 Pagamento atualizado com sucesso!' : '🎉 Pagamento cadastrado com sucesso!'
|
text: initialData ? 'Pagamento atualizado com sucesso!' : 'Pagamento cadastrado com sucesso!',
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!initialData) {
|
if (!initialData) {
|
||||||
setFormData({ pedidos: '', status: 'pendente', metodo: 'pix', valor: 0 });
|
setFormData({ pedidos: [], status: 'pendente', metodo: 'pix', valor: 0 });
|
||||||
|
setPedidoInput('');
|
||||||
}
|
}
|
||||||
|
|
||||||
setTimeout(() => setMessage(null), 3000);
|
setTimeout(() => setMessage(null), 3000);
|
||||||
} else {
|
return;
|
||||||
setMessage({
|
}
|
||||||
type: 'error',
|
|
||||||
text: initialData ? 'Erro ao atualizar pagamento' : 'Erro ao cadastrar pagamento'
|
setMessage({
|
||||||
});
|
type: 'error',
|
||||||
|
text: initialData ? 'Erro ao atualizar pagamento' : 'Erro ao cadastrar pagamento',
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleSelectChange = (e: React.ChangeEvent<HTMLSelectElement>) => {
|
||||||
|
const { name, value } = e.target;
|
||||||
|
setFormData(prev => ({ ...prev, [name]: value }));
|
||||||
|
if (message) {
|
||||||
|
setMessage(null);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleInputChange = (e: React.ChangeEvent<HTMLInputElement | HTMLSelectElement>) => {
|
const handleValueChange = (e: React.ChangeEvent<HTMLInputElement>) => {
|
||||||
const { name, value } = e.target;
|
setFormData(prev => ({ ...prev, valor: Number(e.target.value) }));
|
||||||
setFormData((prev: PagamentoData) => ({ ...prev, [name]: name === 'valor' ? Number(value) : value }));
|
if (message) {
|
||||||
if (message) setMessage(null);
|
setMessage(null);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="bg-white rounded-lg shadow-md p-6">
|
<div className="bg-white rounded-lg shadow-md p-6">
|
||||||
<div className="mb-6">
|
<div className="mb-6">
|
||||||
<h2 className="text-2xl font-bold text-gray-900 mb-2">
|
<h2 className="text-2xl font-bold text-gray-900 mb-2">
|
||||||
{initialData ? 'âœï¸ Editar Pagamento' : 'Novo Pagamento'}
|
{initialData ? 'Editar Pagamento' : 'Novo Pagamento'}
|
||||||
</h2>
|
</h2>
|
||||||
<p className="text-gray-600">
|
<p className="text-gray-600">
|
||||||
{initialData ? 'Atualize os dados do pagamento.' : 'Cadastre um novo pagamento.'}
|
{initialData ? 'Atualize os dados do pagamento.' : 'Cadastre um novo pagamento.'}
|
||||||
|
|
@ -105,12 +131,12 @@ const PagamentoForm: React.FC<PagamentoFormProps> = ({
|
||||||
type="text"
|
type="text"
|
||||||
id="pedidos"
|
id="pedidos"
|
||||||
name="pedidos"
|
name="pedidos"
|
||||||
value={formData.pedidos}
|
value={pedidoInput}
|
||||||
onChange={handleInputChange}
|
onChange={e => setPedidoInput(e.target.value)}
|
||||||
required
|
required
|
||||||
disabled={loading}
|
disabled={loading}
|
||||||
className="w-full px-4 py-2 border border-gray-300 rounded-md focus:ring-2 focus:ring-blue-500 focus:border-transparent disabled:bg-gray-100 disabled:cursor-not-allowed"
|
className="w-full px-4 py-2 border border-gray-300 rounded-md focus:ring-2 focus:ring-blue-500 focus:border-transparent disabled:bg-gray-100 disabled:cursor-not-allowed"
|
||||||
placeholder="ID do pedido"
|
placeholder="ID do pedido ou lista separada por vírgula"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
@ -122,7 +148,7 @@ const PagamentoForm: React.FC<PagamentoFormProps> = ({
|
||||||
id="status"
|
id="status"
|
||||||
name="status"
|
name="status"
|
||||||
value={formData.status}
|
value={formData.status}
|
||||||
onChange={handleInputChange}
|
onChange={handleSelectChange}
|
||||||
className="w-full px-4 py-2 border border-gray-300 rounded-md focus:ring-2 focus:ring-blue-500 focus:border-transparent disabled:bg-gray-100 disabled:cursor-not-allowed"
|
className="w-full px-4 py-2 border border-gray-300 rounded-md focus:ring-2 focus:ring-blue-500 focus:border-transparent disabled:bg-gray-100 disabled:cursor-not-allowed"
|
||||||
disabled={loading}
|
disabled={loading}
|
||||||
>
|
>
|
||||||
|
|
@ -134,13 +160,13 @@ const PagamentoForm: React.FC<PagamentoFormProps> = ({
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
<label htmlFor="metodo" className="block text-sm font-medium text-gray-700 mb-2">
|
<label htmlFor="metodo" className="block text-sm font-medium text-gray-700 mb-2">
|
||||||
Método *
|
Método *
|
||||||
</label>
|
</label>
|
||||||
<select
|
<select
|
||||||
id="metodo"
|
id="metodo"
|
||||||
name="metodo"
|
name="metodo"
|
||||||
value={formData.metodo}
|
value={formData.metodo}
|
||||||
onChange={handleInputChange}
|
onChange={handleSelectChange}
|
||||||
className="w-full px-4 py-2 border border-gray-300 rounded-md focus:ring-2 focus:ring-blue-500 focus:border-transparent disabled:bg-gray-100 disabled:cursor-not-allowed"
|
className="w-full px-4 py-2 border border-gray-300 rounded-md focus:ring-2 focus:ring-blue-500 focus:border-transparent disabled:bg-gray-100 disabled:cursor-not-allowed"
|
||||||
disabled={loading}
|
disabled={loading}
|
||||||
>
|
>
|
||||||
|
|
@ -159,8 +185,8 @@ const PagamentoForm: React.FC<PagamentoFormProps> = ({
|
||||||
step="0.01"
|
step="0.01"
|
||||||
id="valor"
|
id="valor"
|
||||||
name="valor"
|
name="valor"
|
||||||
value={formData.valor}
|
value={formData.valor || 0}
|
||||||
onChange={handleInputChange}
|
onChange={handleValueChange}
|
||||||
required
|
required
|
||||||
disabled={loading}
|
disabled={loading}
|
||||||
className="w-full px-4 py-2 border border-gray-300 rounded-md focus:ring-2 focus:ring-blue-500 focus:border-transparent disabled:bg-gray-100 disabled:cursor-not-allowed"
|
className="w-full px-4 py-2 border border-gray-300 rounded-md focus:ring-2 focus:ring-blue-500 focus:border-transparent disabled:bg-gray-100 disabled:cursor-not-allowed"
|
||||||
|
|
@ -175,7 +201,7 @@ const PagamentoForm: React.FC<PagamentoFormProps> = ({
|
||||||
disabled={loading}
|
disabled={loading}
|
||||||
className="flex-1 bg-blue-600 text-white py-2 px-4 rounded-md hover:bg-blue-700 focus:ring-2 focus:ring-blue-500 focus:ring-offset-2 disabled:bg-gray-400 disabled:cursor-not-allowed transition-colors cursor-pointer"
|
className="flex-1 bg-blue-600 text-white py-2 px-4 rounded-md hover:bg-blue-700 focus:ring-2 focus:ring-blue-500 focus:ring-offset-2 disabled:bg-gray-400 disabled:cursor-not-allowed transition-colors cursor-pointer"
|
||||||
>
|
>
|
||||||
{loading ? 'ⳠProcessando...' : (initialData ? '🔄 Atualizar' : '➕ Cadastrar')}
|
{loading ? 'Processando...' : (initialData ? 'Atualizar' : 'Cadastrar')}
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
{onCancel && (
|
{onCancel && (
|
||||||
|
|
@ -185,7 +211,7 @@ const PagamentoForm: React.FC<PagamentoFormProps> = ({
|
||||||
disabled={loading}
|
disabled={loading}
|
||||||
className="flex-1 bg-gray-600 text-white py-2 px-4 rounded-md hover:bg-gray-700 focus:ring-2 focus:ring-gray-500 focus:ring-offset-2 disabled:bg-gray-400 disabled:cursor-not-allowed transition-colors cursor-pointer"
|
className="flex-1 bg-gray-600 text-white py-2 px-4 rounded-md hover:bg-gray-700 focus:ring-2 focus:ring-gray-500 focus:ring-offset-2 disabled:bg-gray-400 disabled:cursor-not-allowed transition-colors cursor-pointer"
|
||||||
>
|
>
|
||||||
⌠Cancelar
|
Cancelar
|
||||||
</button>
|
</button>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -1,20 +1,20 @@
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { Models } from '@/lib/appwrite';
|
|
||||||
import RefreshButton from './RefreshButton';
|
import RefreshButton from './RefreshButton';
|
||||||
import ListHeader from './ListHeader';
|
import ListHeader from './ListHeader';
|
||||||
import DataTable, { Column } from './DataTable';
|
import DataTable, { Column } from './DataTable';
|
||||||
import Pagination from './Pagination';
|
import Pagination from './Pagination';
|
||||||
import TableActions from './TableActions';
|
import TableActions from './TableActions';
|
||||||
import SearchBar from './SearchBar';
|
import SearchBar from './SearchBar';
|
||||||
|
import { PagamentoDocument } from '@/types/legacyEntities';
|
||||||
|
|
||||||
interface PagamentoListProps {
|
interface PagamentoListProps {
|
||||||
pagamentos: Models.Document[];
|
pagamentos: PagamentoDocument[];
|
||||||
loading: boolean;
|
loading: boolean;
|
||||||
error: string | null;
|
error: string | null;
|
||||||
totalPagamentos: number;
|
totalPagamentos: number;
|
||||||
currentPage: number;
|
currentPage: number;
|
||||||
pageSize: number;
|
pageSize: number;
|
||||||
onEdit: (p: Models.Document) => void;
|
onEdit: (pagamento: PagamentoDocument) => void;
|
||||||
onDelete: (id: string) => Promise<boolean>;
|
onDelete: (id: string) => Promise<boolean>;
|
||||||
onRefresh: () => void;
|
onRefresh: () => void;
|
||||||
onPrevPage: () => void;
|
onPrevPage: () => void;
|
||||||
|
|
@ -22,11 +22,6 @@ interface PagamentoListProps {
|
||||||
onSearch: (term: string) => void;
|
onSearch: (term: string) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
type PagamentoDocument = Models.Document & {
|
|
||||||
pedidos?: string[] | { $id?: string } | string | null;
|
|
||||||
valor?: number | string;
|
|
||||||
};
|
|
||||||
|
|
||||||
const PagamentoList: React.FC<PagamentoListProps> = ({
|
const PagamentoList: React.FC<PagamentoListProps> = ({
|
||||||
pagamentos,
|
pagamentos,
|
||||||
loading,
|
loading,
|
||||||
|
|
@ -52,18 +47,28 @@ const PagamentoList: React.FC<PagamentoListProps> = ({
|
||||||
header: 'Pedido',
|
header: 'Pedido',
|
||||||
render: row => {
|
render: row => {
|
||||||
const pedidos = row.pedidos;
|
const pedidos = row.pedidos;
|
||||||
if (Array.isArray(pedidos)) return pedidos.join(', ');
|
if (Array.isArray(pedidos)) {
|
||||||
if (pedidos && typeof pedidos === 'object') return pedidos.$id || 'N/A';
|
return pedidos.join(', ');
|
||||||
|
}
|
||||||
|
if (pedidos && typeof pedidos === 'object') {
|
||||||
|
return pedidos.$id || 'N/A';
|
||||||
|
}
|
||||||
return pedidos ?? 'N/A';
|
return pedidos ?? 'N/A';
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{ key: 'status', header: 'Status' },
|
{ key: 'status', header: 'Status' },
|
||||||
{ key: 'metodo', header: 'Método' },
|
{ key: 'metodo', header: 'Método' },
|
||||||
{ key: 'valor', header: 'Valor', render: row =>
|
{
|
||||||
Number(row.valor).toLocaleString('pt-BR', { style: 'currency', currency: 'BRL' }) },
|
key: 'valor',
|
||||||
|
header: 'Valor',
|
||||||
|
render: row => Number(row.valor || 0).toLocaleString('pt-BR', { style: 'currency', currency: 'BRL' }),
|
||||||
|
},
|
||||||
{ key: '$id', header: 'ID' },
|
{ 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 Criação',
|
||||||
|
render: row => new Date(row.$createdAt).toLocaleDateString('pt-BR'),
|
||||||
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
const handleDelete = async (id: string) => {
|
const handleDelete = async (id: string) => {
|
||||||
|
|
@ -99,10 +104,10 @@ const PagamentoList: React.FC<PagamentoListProps> = ({
|
||||||
<DataTable
|
<DataTable
|
||||||
columns={columns}
|
columns={columns}
|
||||||
data={pagamentos}
|
data={pagamentos}
|
||||||
actions={(pag) => (
|
actions={pagamento => (
|
||||||
<TableActions
|
<TableActions
|
||||||
onEdit={() => onEdit(pag)}
|
onEdit={() => onEdit(pagamento)}
|
||||||
onDelete={() => handleDelete(pag.$id)}
|
onDelete={() => handleDelete(pagamento.$id)}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
|
|
@ -130,5 +135,3 @@ const PagamentoList: React.FC<PagamentoListProps> = ({
|
||||||
};
|
};
|
||||||
|
|
||||||
export default PagamentoList;
|
export default PagamentoList;
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
import { useCallback, useState } from "react";
|
import { useCallback, useState } from 'react';
|
||||||
import { Models } from "@/lib/appwrite";
|
import { catalogoProdutoService } from '../services/catalogoProdutoService';
|
||||||
import { catalogoProdutoService } from "../services/catalogoProdutoService";
|
import { CatalogoProdutoDocument } from '@/types/legacyEntities';
|
||||||
|
|
||||||
export interface CatalogoProdutoFormData {
|
export interface CatalogoProdutoFormData {
|
||||||
descricao: string;
|
descricao: string;
|
||||||
|
|
@ -24,7 +24,7 @@ export interface CatalogoProdutoStats {
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface UseCatalogoProdutosReturn {
|
export interface UseCatalogoProdutosReturn {
|
||||||
catalogoProdutos: Models.Document[];
|
catalogoProdutos: CatalogoProdutoDocument[];
|
||||||
loading: boolean;
|
loading: boolean;
|
||||||
isChangingPage: boolean;
|
isChangingPage: boolean;
|
||||||
isCreating: boolean;
|
isCreating: boolean;
|
||||||
|
|
@ -44,20 +44,20 @@ const PAGE_SIZE = 10;
|
||||||
|
|
||||||
const toApiPayload = (data: CatalogoProdutoFormData) => ({
|
const toApiPayload = (data: CatalogoProdutoFormData) => ({
|
||||||
descricao: data.descricao,
|
descricao: data.descricao,
|
||||||
"codigo-interno": data.codigo_interno,
|
'codigo-interno': data.codigo_interno,
|
||||||
"codigo-ean": data.codigo_ean,
|
'codigo-ean': data.codigo_ean,
|
||||||
"preco-fabrica": data.preco_fabrica,
|
'preco-fabrica': data.preco_fabrica,
|
||||||
pmc: data.pmc,
|
pmc: data.pmc,
|
||||||
"desconto-comercial": data.desconto_comercial,
|
'desconto-comercial': data.desconto_comercial,
|
||||||
"valor-substituicao-tributaria": data.valor_substituicao_tributaria,
|
'valor-substituicao-tributaria': data.valor_substituicao_tributaria,
|
||||||
"preco-nf": data.preco_nf,
|
'preco-nf': data.preco_nf,
|
||||||
laboratorio: data.laboratorio,
|
laboratorio: data.laboratorio,
|
||||||
categoria: data.categoria,
|
categoria: data.categoria,
|
||||||
subcategoria: data.subcategoria,
|
subcategoria: data.subcategoria,
|
||||||
});
|
});
|
||||||
|
|
||||||
export const useCatalogoProdutos = (): UseCatalogoProdutosReturn => {
|
export const useCatalogoProdutos = (): UseCatalogoProdutosReturn => {
|
||||||
const [catalogoProdutos, setCatalogoProdutos] = useState<Models.Document[]>([]);
|
const [catalogoProdutos, setCatalogoProdutos] = useState<CatalogoProdutoDocument[]>([]);
|
||||||
const [loading, setLoading] = useState(false);
|
const [loading, setLoading] = useState(false);
|
||||||
const [error, setError] = useState<string | null>(null);
|
const [error, setError] = useState<string | null>(null);
|
||||||
const [totalCatalogoProdutos, setTotalCatalogoProdutos] = useState(0);
|
const [totalCatalogoProdutos, setTotalCatalogoProdutos] = useState(0);
|
||||||
|
|
@ -65,18 +65,18 @@ export const useCatalogoProdutos = (): UseCatalogoProdutosReturn => {
|
||||||
const [isChangingPage, setIsChangingPage] = useState(false);
|
const [isChangingPage, setIsChangingPage] = useState(false);
|
||||||
const [isCreating, setIsCreating] = useState(false);
|
const [isCreating, setIsCreating] = useState(false);
|
||||||
|
|
||||||
const listarCatalogo = useCallback(async (page = 1, termoBusca = "") => {
|
const listarCatalogo = useCallback(async (page = 1, termoBusca = '') => {
|
||||||
setLoading(true);
|
setLoading(true);
|
||||||
setIsChangingPage(true);
|
setIsChangingPage(true);
|
||||||
setError(null);
|
setError(null);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const response = await catalogoProdutoService.listar(page, PAGE_SIZE, termoBusca);
|
const response = await catalogoProdutoService.listar(page, PAGE_SIZE, termoBusca);
|
||||||
setCatalogoProdutos(response.documents as Models.Document[]);
|
setCatalogoProdutos(response.documents);
|
||||||
setTotalCatalogoProdutos(response.total);
|
setTotalCatalogoProdutos(response.total);
|
||||||
setCurrentPage(page);
|
setCurrentPage(page);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
const message = err instanceof Error ? err.message : "Erro ao listar catálogo de produtos";
|
const message = err instanceof Error ? err.message : 'Erro ao listar catálogo de produtos';
|
||||||
setError(message);
|
setError(message);
|
||||||
setCatalogoProdutos([]);
|
setCatalogoProdutos([]);
|
||||||
setTotalCatalogoProdutos(0);
|
setTotalCatalogoProdutos(0);
|
||||||
|
|
@ -86,99 +86,83 @@ export const useCatalogoProdutos = (): UseCatalogoProdutosReturn => {
|
||||||
}
|
}
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
const buscarCatalogo = useCallback(
|
const buscarCatalogo = useCallback(async (params: { termo: string; filtros: unknown }, page = 1) => {
|
||||||
async (params: { termo: string; filtros: unknown }, page = 1) => {
|
await listarCatalogo(page, params.termo);
|
||||||
await listarCatalogo(page, params.termo);
|
}, [listarCatalogo]);
|
||||||
},
|
|
||||||
[listarCatalogo]
|
|
||||||
);
|
|
||||||
|
|
||||||
const cadastrarCatalogo = useCallback(
|
const cadastrarCatalogo = useCallback(async (data: CatalogoProdutoFormData): Promise<boolean> => {
|
||||||
async (data: CatalogoProdutoFormData): Promise<boolean> => {
|
setIsCreating(true);
|
||||||
setIsCreating(true);
|
setError(null);
|
||||||
setError(null);
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await catalogoProdutoService.criar(toApiPayload(data));
|
await catalogoProdutoService.criar(toApiPayload(data));
|
||||||
await listarCatalogo(currentPage);
|
await listarCatalogo(currentPage);
|
||||||
return true;
|
return true;
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
const message = err instanceof Error ? err.message : "Erro ao cadastrar produto";
|
const message = err instanceof Error ? err.message : 'Erro ao cadastrar produto';
|
||||||
setError(message);
|
setError(message);
|
||||||
return false;
|
return false;
|
||||||
} finally {
|
} finally {
|
||||||
setIsCreating(false);
|
setIsCreating(false);
|
||||||
}
|
}
|
||||||
},
|
}, [currentPage, listarCatalogo]);
|
||||||
[currentPage, listarCatalogo]
|
|
||||||
);
|
|
||||||
|
|
||||||
const atualizarCatalogo = useCallback(
|
const atualizarCatalogo = useCallback(async (id: string, data: CatalogoProdutoFormData): Promise<boolean> => {
|
||||||
async (id: string, data: CatalogoProdutoFormData): Promise<boolean> => {
|
setLoading(true);
|
||||||
setLoading(true);
|
setError(null);
|
||||||
setError(null);
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await catalogoProdutoService.atualizar(id, toApiPayload(data));
|
await catalogoProdutoService.atualizar(id, toApiPayload(data));
|
||||||
await listarCatalogo(currentPage);
|
await listarCatalogo(currentPage);
|
||||||
return true;
|
return true;
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
const message = err instanceof Error ? err.message : "Erro ao atualizar produto";
|
const message = err instanceof Error ? err.message : 'Erro ao atualizar produto';
|
||||||
setError(message);
|
setError(message);
|
||||||
return false;
|
return false;
|
||||||
} finally {
|
} finally {
|
||||||
setLoading(false);
|
setLoading(false);
|
||||||
}
|
}
|
||||||
},
|
}, [currentPage, listarCatalogo]);
|
||||||
[currentPage, listarCatalogo]
|
|
||||||
);
|
|
||||||
|
|
||||||
const deletarCatalogo = useCallback(
|
const deletarCatalogo = useCallback(async (id: string): Promise<boolean> => {
|
||||||
async (id: string): Promise<boolean> => {
|
setLoading(true);
|
||||||
setLoading(true);
|
setError(null);
|
||||||
setError(null);
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await catalogoProdutoService.deletar(id);
|
await catalogoProdutoService.deletar(id);
|
||||||
await listarCatalogo(currentPage);
|
await listarCatalogo(currentPage);
|
||||||
return true;
|
return true;
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
const message = err instanceof Error ? err.message : "Erro ao deletar produto";
|
const message = err instanceof Error ? err.message : 'Erro ao deletar produto';
|
||||||
setError(message);
|
setError(message);
|
||||||
return false;
|
return false;
|
||||||
} finally {
|
} finally {
|
||||||
setLoading(false);
|
setLoading(false);
|
||||||
}
|
}
|
||||||
},
|
}, [currentPage, listarCatalogo]);
|
||||||
[currentPage, listarCatalogo]
|
|
||||||
);
|
|
||||||
|
|
||||||
const obterEstatisticas = useCallback((): CatalogoProdutoStats => {
|
const obterEstatisticas = useCallback((): CatalogoProdutoStats => {
|
||||||
return catalogoProdutos.reduce<CatalogoProdutoStats>(
|
return catalogoProdutos.reduce<CatalogoProdutoStats>((stats, produto) => {
|
||||||
(stats, produto) => {
|
const categoria = typeof produto.categoria === 'string' ? produto.categoria : 'Sem categoria';
|
||||||
const produtoData = produto as Models.Document & Record<string, unknown>;
|
|
||||||
const categoria = typeof produtoData.categoria === "string" ? produtoData.categoria : "Sem categoria";
|
|
||||||
|
|
||||||
stats.total += 1;
|
stats.total += 1;
|
||||||
|
|
||||||
if (produtoData.laboratorio) {
|
if (produto.laboratorio) {
|
||||||
stats.comLaboratorio += 1;
|
stats.comLaboratorio += 1;
|
||||||
}
|
|
||||||
|
|
||||||
if (typeof produtoData["preco-nf"] === "number" && produtoData["preco-nf"] > 0) {
|
|
||||||
stats.comPreco += 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
stats.porCategoria[categoria] = (stats.porCategoria[categoria] || 0) + 1;
|
|
||||||
return stats;
|
|
||||||
},
|
|
||||||
{
|
|
||||||
total: 0,
|
|
||||||
comLaboratorio: 0,
|
|
||||||
comPreco: 0,
|
|
||||||
porCategoria: {},
|
|
||||||
}
|
}
|
||||||
);
|
|
||||||
|
if (typeof produto['preco-nf'] === 'number' && produto['preco-nf'] > 0) {
|
||||||
|
stats.comPreco += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
stats.porCategoria[categoria] = (stats.porCategoria[categoria] || 0) + 1;
|
||||||
|
return stats;
|
||||||
|
}, {
|
||||||
|
total: 0,
|
||||||
|
comLaboratorio: 0,
|
||||||
|
comPreco: 0,
|
||||||
|
porCategoria: {},
|
||||||
|
});
|
||||||
}, [catalogoProdutos]);
|
}, [catalogoProdutos]);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
|
@ -198,4 +182,3 @@ export const useCatalogoProdutos = (): UseCatalogoProdutosReturn => {
|
||||||
setCurrentPage,
|
setCurrentPage,
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,11 +1,10 @@
|
||||||
// @ts-nocheck
|
|
||||||
import { useState, useCallback } from 'react';
|
import { useState, useCallback } from 'react';
|
||||||
import { Models } from '@/lib/appwrite';
|
|
||||||
import { pagamentoService, PagamentoData } from '@/services/pagamentoService';
|
import { pagamentoService, PagamentoData } from '@/services/pagamentoService';
|
||||||
|
import { PagamentoDocument } from '@/types/legacyEntities';
|
||||||
export type { PagamentoData };
|
export type { PagamentoData };
|
||||||
|
|
||||||
export interface UsePagamentosReturn {
|
export interface UsePagamentosReturn {
|
||||||
pagamentos: Models.Document[];
|
pagamentos: PagamentoDocument[];
|
||||||
loading: boolean;
|
loading: boolean;
|
||||||
error: string | null;
|
error: string | null;
|
||||||
totalPagamentos: number;
|
totalPagamentos: number;
|
||||||
|
|
@ -21,53 +20,43 @@ export interface UsePagamentosReturn {
|
||||||
const PAGE_SIZE = 10;
|
const PAGE_SIZE = 10;
|
||||||
|
|
||||||
export const usePagamentos = (): UsePagamentosReturn => {
|
export const usePagamentos = (): UsePagamentosReturn => {
|
||||||
const [pagamentos, setPagamentos] = useState<Models.Document[]>([]);
|
const [pagamentos, setPagamentos] = useState<PagamentoDocument[]>([]);
|
||||||
const [loading, setLoading] = useState(false);
|
const [loading, setLoading] = useState(false);
|
||||||
const [error, setError] = useState<string | null>(null);
|
const [error, setError] = useState<string | null>(null);
|
||||||
const [totalPagamentos, setTotalPagamentos] = useState(0);
|
const [totalPagamentos, setTotalPagamentos] = useState(0);
|
||||||
const [currentPage, setCurrentPage] = useState(1);
|
const [currentPage, setCurrentPage] = useState(1);
|
||||||
|
|
||||||
const listarPagamentos = useCallback(
|
const listarPagamentos = useCallback(async (page = currentPage, search = '') => {
|
||||||
async (page = currentPage, search = '') => {
|
|
||||||
setLoading(true);
|
setLoading(true);
|
||||||
setError(null);
|
setError(null);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const response = await pagamentoService.listar(page, PAGE_SIZE, search);
|
const response = await pagamentoService.listar(page, PAGE_SIZE, search);
|
||||||
|
|
||||||
setPagamentos(response.documents || []);
|
setPagamentos(response.documents || []);
|
||||||
setTotalPagamentos(response.total || 0);
|
setTotalPagamentos(response.total || 0);
|
||||||
setCurrentPage(page);
|
setCurrentPage(page);
|
||||||
} catch (err) {
|
} catch {
|
||||||
setError('Erro de conexão ao carregar pagamentos');
|
setError('Erro de conexão ao carregar pagamentos');
|
||||||
} finally {
|
} finally {
|
||||||
setLoading(false);
|
setLoading(false);
|
||||||
}
|
}
|
||||||
}, [currentPage]);
|
}, [currentPage]);
|
||||||
|
|
||||||
const buscarPagamentos = useCallback(
|
const buscarPagamentos = useCallback(async (termo: string, page = 1) => {
|
||||||
async (termo: string, page = 1) => {
|
setLoading(true);
|
||||||
setLoading(true);
|
setError(null);
|
||||||
setError(null);
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const response = await pagamentoService.buscarPorNome(
|
const response = await pagamentoService.buscarPorNome(termo, page, PAGE_SIZE);
|
||||||
termo,
|
setPagamentos(response.documents || []);
|
||||||
page,
|
setTotalPagamentos(response.total || 0);
|
||||||
PAGE_SIZE
|
setCurrentPage(page);
|
||||||
);
|
} catch {
|
||||||
|
setError('Erro de conexão ao buscar pagamentos');
|
||||||
setPagamentos(response.documents || []);
|
} finally {
|
||||||
setTotalPagamentos(response.total || 0);
|
setLoading(false);
|
||||||
setCurrentPage(page);
|
}
|
||||||
} catch (err) {
|
}, []);
|
||||||
setError('Erro de conexão ao buscar pagamentos');
|
|
||||||
} finally {
|
|
||||||
setLoading(false);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
[]
|
|
||||||
);
|
|
||||||
|
|
||||||
const cadastrarPagamento = useCallback(async (formData: PagamentoData): Promise<boolean> => {
|
const cadastrarPagamento = useCallback(async (formData: PagamentoData): Promise<boolean> => {
|
||||||
setLoading(true);
|
setLoading(true);
|
||||||
|
|
@ -77,8 +66,8 @@ export const usePagamentos = (): UsePagamentosReturn => {
|
||||||
await pagamentoService.criar(formData);
|
await pagamentoService.criar(formData);
|
||||||
await listarPagamentos(currentPage);
|
await listarPagamentos(currentPage);
|
||||||
return true;
|
return true;
|
||||||
} catch (err) {
|
} catch {
|
||||||
setError('Erro de conexão ao cadastrar pagamento');
|
setError('Erro de conexão ao cadastrar pagamento');
|
||||||
return false;
|
return false;
|
||||||
} finally {
|
} finally {
|
||||||
setLoading(false);
|
setLoading(false);
|
||||||
|
|
@ -93,8 +82,8 @@ export const usePagamentos = (): UsePagamentosReturn => {
|
||||||
await pagamentoService.atualizar(id, formData);
|
await pagamentoService.atualizar(id, formData);
|
||||||
await listarPagamentos(currentPage);
|
await listarPagamentos(currentPage);
|
||||||
return true;
|
return true;
|
||||||
} catch (err) {
|
} catch {
|
||||||
setError('Erro de conexão ao atualizar pagamento');
|
setError('Erro de conexão ao atualizar pagamento');
|
||||||
return false;
|
return false;
|
||||||
} finally {
|
} finally {
|
||||||
setLoading(false);
|
setLoading(false);
|
||||||
|
|
@ -109,8 +98,8 @@ export const usePagamentos = (): UsePagamentosReturn => {
|
||||||
await pagamentoService.deletar(id);
|
await pagamentoService.deletar(id);
|
||||||
await listarPagamentos(currentPage);
|
await listarPagamentos(currentPage);
|
||||||
return true;
|
return true;
|
||||||
} catch (err) {
|
} catch {
|
||||||
setError('Erro de conexão ao deletar pagamento');
|
setError('Erro de conexão ao deletar pagamento');
|
||||||
return false;
|
return false;
|
||||||
} finally {
|
} finally {
|
||||||
setLoading(false);
|
setLoading(false);
|
||||||
|
|
@ -131,4 +120,3 @@ export const usePagamentos = (): UsePagamentosReturn => {
|
||||||
setCurrentPage,
|
setCurrentPage,
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,31 +1,33 @@
|
||||||
export interface PagamentoData {
|
import { PagamentoDocument, ServiceResponse } from '@/types/legacyEntities';
|
||||||
|
|
||||||
|
export interface PagamentoData {
|
||||||
id?: string;
|
id?: string;
|
||||||
pedidos?: string[];
|
pedidos?: string[];
|
||||||
status?: string;
|
status?: string;
|
||||||
metodo?: string;
|
metodo?: string;
|
||||||
valor?: number;
|
valor?: number;
|
||||||
[key: string]: any;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
interface ServiceResponse<T = unknown> {
|
const emptyList = (): ServiceResponse<PagamentoDocument> => ({
|
||||||
success: boolean;
|
success: true,
|
||||||
data?: T;
|
data: null,
|
||||||
documents?: T[];
|
documents: [],
|
||||||
total?: number;
|
total: 0,
|
||||||
error?: string;
|
});
|
||||||
message?: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
const emptyList = <T,>(): ServiceResponse<T> => ({ success: true, documents: [], total: 0 });
|
const removed = (message = 'Service removido'): ServiceResponse<PagamentoDocument> => ({
|
||||||
const removed = (message = 'Service removido'): ServiceResponse => ({ success: false, error: message, message });
|
success: false,
|
||||||
|
error: message,
|
||||||
|
message,
|
||||||
|
});
|
||||||
|
|
||||||
export const pagamentoService = {
|
export const pagamentoService = {
|
||||||
listar: async (_page = 1, _limit = 10, _search = '') => emptyList<PagamentoData>(),
|
listar: async (_page = 1, _limit = 10, _search = '') => emptyList(),
|
||||||
buscarPorNome: async (_nome: string, _page = 1, _limit = 10) => emptyList<PagamentoData>(),
|
buscarPorNome: async (_nome: string, _page = 1, _limit = 10) => emptyList(),
|
||||||
criar: async (_data?: PagamentoData) => removed(),
|
criar: async (_data?: PagamentoData) => removed(),
|
||||||
criarPagamento: async (_data?: PagamentoData) => removed(),
|
criarPagamento: async (_data?: PagamentoData) => removed(),
|
||||||
buscarPorUserId: async () => emptyList<PagamentoData>(),
|
buscarPorUserId: async () => emptyList(),
|
||||||
buscarPorId: async (_id?: string) => ({ success: true, data: null as PagamentoData | null }),
|
buscarPorId: async (_id?: string): Promise<ServiceResponse<PagamentoDocument>> => ({ success: true, data: null }),
|
||||||
atualizar: async (_id?: string, _data?: Partial<PagamentoData>) => removed(),
|
atualizar: async (_id?: string, _data?: Partial<PagamentoData>) => removed(),
|
||||||
deletar: async (_id?: string) => removed(),
|
deletar: async (_id?: string) => removed(),
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -13,6 +13,29 @@ export interface FaturaDocument extends LegacyDocument {
|
||||||
nome?: string;
|
nome?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface PagamentoDocument extends LegacyDocument {
|
||||||
|
pedidos?: string[] | { $id?: string } | string | null;
|
||||||
|
status?: string;
|
||||||
|
metodo?: string;
|
||||||
|
valor?: number | string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface CatalogoProdutoDocument extends LegacyDocument {
|
||||||
|
descricao: string;
|
||||||
|
nome?: string;
|
||||||
|
'codigo-interno'?: string;
|
||||||
|
'codigo-ean'?: string;
|
||||||
|
'preco-original'?: number;
|
||||||
|
'preco-atual'?: number;
|
||||||
|
'preco-fabrica'?: number;
|
||||||
|
'preco-nf'?: number;
|
||||||
|
pmc?: number;
|
||||||
|
quantidade?: number;
|
||||||
|
laboratorio?: string;
|
||||||
|
categoria?: string;
|
||||||
|
subcategoria?: string;
|
||||||
|
}
|
||||||
|
|
||||||
export interface ServiceResponse<TDocument> {
|
export interface ServiceResponse<TDocument> {
|
||||||
success: boolean;
|
success: boolean;
|
||||||
data?: TDocument | null;
|
data?: TDocument | null;
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue