first commit
This commit is contained in:
commit
c9fb67e751
423 files changed
+53287
No files matched your search
@@ -0,0 +1,309 @@
|
||||
import { useState } from "react";
|
||||
import { useParams, useNavigate } from "react-router-dom";
|
||||
import { useQuery, useQueryClient } from "react-query";
|
||||
import { Tab } from "@headlessui/react";
|
||||
import { classNames } from "../../utils/classNames";
|
||||
import {
|
||||
ArrowLeftIcon,
|
||||
DocumentTextIcon,
|
||||
ClockIcon,
|
||||
PencilIcon,
|
||||
TrashIcon,
|
||||
CurrencyDollarIcon,
|
||||
} from "@heroicons/react/24/outline";
|
||||
import { formatCurrency } from "../../utils/format";
|
||||
import { useProcessosAdministrativos } from "../../hooks/useProcessosAdministrativos";
|
||||
import { ProcessoAdminModal } from "./ProcessoAdminModal";
|
||||
import { MovimentacaoAdministrativaDialog } from "./MovimentacaoAdministrativaDialog";
|
||||
import { MovimentacaoAdminActions } from "./MovimentacaoAdminActions"; // Adicionar esta importação
|
||||
import api from "../../services/api";
|
||||
import { CustaAdministrativaPanel } from "./CustaAdministrativaPanel";
|
||||
|
||||
const tabs = [
|
||||
{ id: "geral", name: "Informações Gerais", icon: DocumentTextIcon },
|
||||
{ id: "movimentacoes", name: "Movimentações", icon: ClockIcon },
|
||||
{ id: "financeiro", name: "Financeiro", icon: CurrencyDollarIcon }, // Adicionar nova tab
|
||||
];
|
||||
|
||||
export function ProcessoAdminDetalhes() {
|
||||
const { id } = useParams<{ id: string }>();
|
||||
const navigate = useNavigate();
|
||||
const queryClient = useQueryClient();
|
||||
const [selectedTab, setSelectedTab] = useState(0);
|
||||
const [isMovimentacaoModalOpen, setIsMovimentacaoModalOpen] = useState(false);
|
||||
const [isEditModalOpen, setIsEditModalOpen] = useState(false);
|
||||
const [isDeleteModalOpen, setIsDeleteModalOpen] = useState(false);
|
||||
const [movimentacaoParaEditar, setMovimentacaoParaEditar] = useState<MovimentacaoAdministrativa | null>(null);
|
||||
|
||||
// Se o id for "novo", renderizar diretamente o modal de criação
|
||||
if (id === "novo") {
|
||||
return (
|
||||
<ProcessoAdminModal
|
||||
isOpen={true}
|
||||
onClose={() => navigate("/processos-administrativos")}
|
||||
onSuccess={() => navigate("/processos-administrativos")}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
const { data: processo, isLoading, error } = useQuery(
|
||||
["processo-administrativo", id],
|
||||
async () => {
|
||||
const response = await api.get(`/processos-administrativos/${id}`);
|
||||
return response.data;
|
||||
},
|
||||
{
|
||||
enabled: !!id && id !== "novo", // Só executa se tiver um id válido
|
||||
retry: 2, // Tenta no máximo 2 vezes em caso de erro
|
||||
onError: (error) => {
|
||||
console.error("Erro ao carregar processo:", error);
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
const { deleteProcesso } = useProcessosAdministrativos();
|
||||
|
||||
const handleDelete = async () => {
|
||||
try {
|
||||
await deleteProcesso.mutateAsync(id!);
|
||||
navigate("/processos-administrativos");
|
||||
} catch (error) {
|
||||
console.error("Erro ao excluir processo:", error);
|
||||
}
|
||||
};
|
||||
|
||||
const handleSaveMovimentacao = async (data: any) => {
|
||||
try {
|
||||
await api.post(`/processos-administrativos/${id}/movimentacoes`, data);
|
||||
// Recarregar dados
|
||||
queryClient.invalidateQueries(["processo-administrativo", id]);
|
||||
} catch (error) {
|
||||
console.error("Erro ao salvar movimentação:", error);
|
||||
}
|
||||
};
|
||||
|
||||
const handleEditMovimentacao = async (data: any) => {
|
||||
try {
|
||||
// Atualizar URL para usar a nova rota
|
||||
await api.put(`/processos-administrativos/movimentacoes/${data.id}`, data);
|
||||
queryClient.invalidateQueries(["processo-administrativo", id]);
|
||||
setMovimentacaoParaEditar(null);
|
||||
} catch (error) {
|
||||
console.error("Erro ao editar movimentação:", error);
|
||||
}
|
||||
};
|
||||
|
||||
const handleDeleteMovimentacao = async (movimentacaoId: string) => {
|
||||
if (!window.confirm("Deseja realmente excluir esta movimentação?")) return;
|
||||
|
||||
try {
|
||||
// Atualizar URL para usar a nova rota
|
||||
await api.delete(`/processos-administrativos/movimentacoes/${movimentacaoId}`);
|
||||
queryClient.invalidateQueries(["processo-administrativo", id]);
|
||||
} catch (error) {
|
||||
console.error("Erro ao excluir movimentação:", error);
|
||||
}
|
||||
};
|
||||
|
||||
if (!processo) return <div>Processo não encontrado</div>;
|
||||
if (isLoading) return <div>Carregando...</div>;
|
||||
if (error) return <div>Erro ao carregar processo</div>;
|
||||
|
||||
return (
|
||||
<div className="space-y-6">
|
||||
{/* Header */}
|
||||
<div className="flex items-center justify-between">
|
||||
<div className="flex items-center space-x-4">
|
||||
<button
|
||||
onClick={() => navigate("/processos-administrativos")}
|
||||
className="p-2 hover:bg-gray-100 rounded-full"
|
||||
>
|
||||
<ArrowLeftIcon className="h-5 w-5 text-gray-500" />
|
||||
</button>
|
||||
<div>
|
||||
<h1 className="text-xl font-semibold text-gray-900">
|
||||
{processo.numero}
|
||||
</h1>
|
||||
<p className="text-sm text-gray-500">{processo.orgao}</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="flex items-center space-x-2">
|
||||
<button
|
||||
onClick={() => setIsEditModalOpen(true)}
|
||||
className="flex items-center px-4 py-2 text-sm text-blue-600 hover:bg-blue-50 rounded-lg"
|
||||
>
|
||||
<PencilIcon className="h-4 w-4 mr-2" />
|
||||
Editar
|
||||
</button>
|
||||
<button
|
||||
onClick={() => setIsDeleteModalOpen(true)}
|
||||
className="flex items-center px-4 py-2 text-sm text-red-600 hover:bg-red-50 rounded-lg"
|
||||
>
|
||||
<TrashIcon className="h-4 w-4 mr-2" />
|
||||
Excluir
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Tabs */}
|
||||
<Tab.Group selectedIndex={selectedTab} onChange={setSelectedTab}>
|
||||
<Tab.List className="flex space-x-1 rounded-xl bg-blue-900/20 p-1">
|
||||
{tabs.map((tab) => (
|
||||
<Tab
|
||||
key={tab.id}
|
||||
className={({ selected }) =>
|
||||
classNames(
|
||||
"w-full rounded-lg py-2.5 text-sm font-medium leading-5",
|
||||
"flex items-center justify-center",
|
||||
selected
|
||||
? "bg-white text-blue-700 shadow"
|
||||
: "text-gray-600 hover:bg-white/[0.12] hover:text-blue-600"
|
||||
)
|
||||
}
|
||||
>
|
||||
<tab.icon className="h-4 w-4 mr-2" />
|
||||
{tab.name}
|
||||
</Tab>
|
||||
))}
|
||||
</Tab.List>
|
||||
|
||||
<Tab.Panels className="mt-4">
|
||||
{/* Informações Gerais */}
|
||||
<Tab.Panel className="bg-white rounded-xl p-6">
|
||||
<dl className="grid grid-cols-1 md:grid-cols-2 gap-6">
|
||||
<div>
|
||||
<dt className="text-sm font-medium text-gray-500">
|
||||
Número/Protocolo
|
||||
</dt>
|
||||
<dd className="mt-1 text-sm text-gray-900">{processo.numero}</dd>
|
||||
</div>
|
||||
<div>
|
||||
<dt className="text-sm font-medium text-gray-500">Órgão</dt>
|
||||
<dd className="mt-1 text-sm text-gray-900">{processo.orgao}</dd>
|
||||
</div>
|
||||
<div>
|
||||
<dt className="text-sm font-medium text-gray-500">Status</dt>
|
||||
<dd className="mt-1 text-sm text-gray-900">{processo.status}</dd>
|
||||
</div>
|
||||
<div>
|
||||
<dt className="text-sm font-medium text-gray-500">
|
||||
Valor da Pretensão
|
||||
</dt>
|
||||
<dd className="mt-1 text-sm text-gray-900">
|
||||
{processo.valorPretensao
|
||||
? formatCurrency(processo.valorPretensao)
|
||||
: "-"}
|
||||
</dd>
|
||||
</div>
|
||||
<div className="col-span-2">
|
||||
<dt className="text-sm font-medium text-gray-500">Descrição</dt>
|
||||
<dd className="mt-1 text-sm text-gray-900">
|
||||
{processo.descricao}
|
||||
</dd>
|
||||
</div>
|
||||
<div className="col-span-2">
|
||||
<dt className="text-sm font-medium text-gray-500">Observações</dt>
|
||||
<dd className="mt-1 text-sm text-gray-900">
|
||||
{processo.observacoes || "-"}
|
||||
</dd>
|
||||
</div>
|
||||
</dl>
|
||||
</Tab.Panel>
|
||||
|
||||
{/* Movimentações */}
|
||||
<Tab.Panel className="bg-white rounded-xl p-6">
|
||||
<div className="flex justify-between items-center mb-4">
|
||||
<h3 className="text-lg font-medium text-gray-900">Movimentações</h3>
|
||||
<button
|
||||
onClick={() => setIsMovimentacaoModalOpen(true)}
|
||||
className="flex items-center px-4 py-2 text-sm text-blue-600 hover:bg-blue-50 rounded-lg"
|
||||
>
|
||||
Nova Movimentação
|
||||
</button>
|
||||
</div>
|
||||
|
||||
{processo.movimentacoes?.length > 0 ? (
|
||||
<div className="flow-root">
|
||||
<ul role="list" className="-mb-8">
|
||||
{processo.movimentacoes.map((mov, idx) => (
|
||||
<li key={mov.id}>
|
||||
<div className="relative pb-8">
|
||||
{idx !== processo.movimentacoes.length - 1 ? (
|
||||
<span
|
||||
className="absolute top-4 left-4 -ml-px h-full w-0.5 bg-gray-200"
|
||||
aria-hidden="true"
|
||||
/>
|
||||
) : null}
|
||||
<div className="relative flex space-x-3">
|
||||
<div>
|
||||
<span className="h-8 w-8 rounded-full bg-gray-100 flex items-center justify-center">
|
||||
<ClockIcon className="h-5 w-5 text-gray-500" />
|
||||
</span>
|
||||
</div>
|
||||
<div className="min-w-0 flex-1">
|
||||
<div className="flex justify-between items-start">
|
||||
<div className="text-sm text-gray-500">
|
||||
<time>{new Date(mov.data).toLocaleDateString()}</time>
|
||||
</div>
|
||||
<MovimentacaoAdminActions
|
||||
movimentacao={mov}
|
||||
onEdit={setMovimentacaoParaEditar}
|
||||
onDelete={handleDeleteMovimentacao}
|
||||
/>
|
||||
</div>
|
||||
<div className="mt-1">
|
||||
<p className="text-sm text-gray-900">
|
||||
{mov.descricao}
|
||||
</p>
|
||||
{mov.observacoes && (
|
||||
<p className="mt-1 text-sm text-gray-500">
|
||||
{mov.observacoes}
|
||||
</p>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
</div>
|
||||
) : (
|
||||
<p className="text-sm text-gray-500 text-center py-4">
|
||||
Nenhuma movimentação registrada
|
||||
</p>
|
||||
)}
|
||||
</Tab.Panel>
|
||||
|
||||
{/* Painel Financeiro */}
|
||||
<Tab.Panel className="bg-white rounded-xl p-6">
|
||||
<CustaAdministrativaPanel processoId={id} />
|
||||
</Tab.Panel>
|
||||
</Tab.Panels>
|
||||
</Tab.Group>
|
||||
|
||||
{/* Modais */}
|
||||
<ProcessoAdminModal
|
||||
isOpen={isEditModalOpen}
|
||||
onClose={() => setIsEditModalOpen(false)}
|
||||
processo={processo}
|
||||
onSuccess={() => {
|
||||
queryClient.invalidateQueries(["processo-administrativo", id]);
|
||||
setIsEditModalOpen(false);
|
||||
}}
|
||||
/>
|
||||
<MovimentacaoAdministrativaDialog
|
||||
isOpen={isMovimentacaoModalOpen}
|
||||
onClose={() => setIsMovimentacaoModalOpen(false)}
|
||||
onSave={handleSaveMovimentacao}
|
||||
/>
|
||||
<MovimentacaoAdministrativaDialog
|
||||
isOpen={!!movimentacaoParaEditar}
|
||||
onClose={() => setMovimentacaoParaEditar(null)}
|
||||
onSave={handleEditMovimentacao}
|
||||
movimentacao={movimentacaoParaEditar}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
Reference in new issue
Block a user