sgmp/frontend/app/solicitacoes/[id]/page.tsx

580 lines
28 KiB
TypeScript

"use client";
import Link from "next/link";
import { useEffect, useMemo, useState } from "react";
import { useParams, useRouter } from "next/navigation";
import { apiPostFormData, apiPostJson, ApiError } from "@/lib/api/client";
type SolicitacaoDetalhe = {
id: string;
tipo: string;
tipo_display: string;
status: string;
status_display: string;
criado_em: string | null;
enviada_em: string | null;
finalizada_em: string | null;
solicitante: {
matricula: string | null;
nome: string | null;
} | null;
funcionario: {
id: string;
id_rm: string | null;
matricula: string | null;
nome: string | null;
cpf: string | null;
data_admissao: string | null;
situacao: string | null;
cargo: string | null;
setor: string | null;
centro_custo: string | null;
cod_funcao: string | null;
salario: string | null;
cod_sindicato: string | null;
saldo_banco_horas_minutos: number | null;
inicio_periodo_banco_horas: string | null;
fim_periodo_banco_horas: string | null;
sincronizado_em: string | null;
matricula_winthor: string | null;
} | null;
dados_winthor: {
basicos: { matricula: string | null; nome: string | null; cpf: string | null };
admissao: { admissao: string | null; situacao: string | null; dt_exclusao: string | null };
endereco: { endereco: string | null; bairro: string | null; cidade: string | null; estado: string | null };
} | null;
detalhes_tipo: {
tipo: string;
[key: string]: unknown;
} | null;
acoes: {
pode_aprovar: boolean;
pode_dar_parecer: boolean;
pode_enviar: boolean;
is_solicitante: boolean;
};
pareceres: Array<{
id: string;
etapa: string;
etapa_display: string;
texto: string;
criado_em: string | null;
usuario_nome: string | null;
anexo_url: string | null;
}>;
aprovacoes: Array<{
id: string;
etapa: string;
etapa_display: string;
decisao: string;
decisao_display: string;
justificativa: string;
decidido_em: string | null;
usuario_nome: string | null;
}>;
};
const DJANGO_BASE_URL = process.env.NEXT_PUBLIC_API_URL || "http://localhost:8888";
function toAbsoluteDjangoUrl(pathOrUrl: string) {
if (pathOrUrl.startsWith("http://") || pathOrUrl.startsWith("https://")) {
return pathOrUrl;
}
return `${DJANGO_BASE_URL}${pathOrUrl.startsWith("/") ? pathOrUrl : `/${pathOrUrl}`}`;
}
function formatarData(iso: string | null) {
if (!iso) return "—";
try {
return new Date(iso).toLocaleString("pt-BR");
} catch {
return iso;
}
}
function formatarDinheiro(valor: string | null) {
if (!valor) return "—";
const numero = Number(valor);
if (Number.isNaN(numero)) return valor;
return numero.toLocaleString("pt-BR", { style: "currency", currency: "BRL" });
}
// #region agent log
function debugLog(hypothesisId: string, message: string, data: Record<string, unknown>) {
fetch("http://localhost:7687/ingest/ee56ea93-ad22-4673-ab77-595d83a9b3c5", {
method: "POST",
headers: {
"Content-Type": "application/json",
"X-Debug-Session-Id": "6b638a",
},
body: JSON.stringify({
sessionId: "6b638a",
runId: "detail-permission-debug",
hypothesisId,
location: "frontend/app/solicitacoes/[id]/page.tsx",
message,
data,
timestamp: Date.now(),
}),
}).catch(() => {});
}
// #endregion
export default function SolicitacaoDetalhePage() {
const router = useRouter();
const params = useParams<{ id: string }>();
const solicitacaoId = useMemo(() => String(params?.id || ""), [params]);
const [data, setData] = useState<SolicitacaoDetalhe | null>(null);
const [loading, setLoading] = useState(true);
const [error, setError] = useState("");
const [actionLoading, setActionLoading] = useState(false);
const [actionFeedback, setActionFeedback] = useState("");
const [parecerTexto, setParecerTexto] = useState("");
const [parecerAnexo, setParecerAnexo] = useState<File | null>(null);
const [decisao, setDecisao] = useState<"APROVADO" | "REPROVADO">("APROVADO");
const [justificativaDecisao, setJustificativaDecisao] = useState("");
const [reloadTick, setReloadTick] = useState(0);
useEffect(() => {
async function carregarDetalhe() {
if (!solicitacaoId) {
setError("Solicitação inválida.");
setLoading(false);
return;
}
setLoading(true);
setError("");
try {
// #region agent log
debugLog("H1_H2", "detail_fetch_start", {
solicitacaoId,
endpoint: `/api/solicitacoes/${solicitacaoId}/`,
});
// #endregion
const res = await fetch(`/api/solicitacoes/${solicitacaoId}/`, {
credentials: "include",
});
// #region agent log
let responsePreview = "";
try {
responsePreview = (await res.clone().text()).slice(0, 300);
} catch {
responsePreview = "unreadable_response";
}
debugLog("H1_H3_H4", "detail_fetch_response", {
solicitacaoId,
status: res.status,
ok: res.ok,
responsePreview,
});
// #endregion
if (res.status === 401) {
// #region agent log
debugLog("H5", "detail_fetch_unauthorized_redirect", {
solicitacaoId,
});
// #endregion
router.push(`/tela_login?next=${encodeURIComponent(`/solicitacoes/${solicitacaoId}`)}`);
return;
}
if (!res.ok) {
if (res.status === 404) {
setError("Solicitação não encontrada ou sem permissão.");
} else {
setError("Erro ao carregar detalhes da solicitação.");
}
return;
}
const json = (await res.json()) as SolicitacaoDetalhe;
setData(json);
} catch {
setError("Erro de conexão ao carregar detalhes.");
} finally {
setLoading(false);
}
}
carregarDetalhe();
}, [router, solicitacaoId, reloadTick]);
async function handleEnviar() {
if (!data) return;
setActionLoading(true);
setActionFeedback("");
try {
await apiPostJson(`/api/solicitacoes/${data.id}/enviar/`, {});
setActionFeedback("Solicitação enviada para aprovação.");
setReloadTick((v) => v + 1);
} catch (err) {
setActionFeedback(err instanceof ApiError ? err.message : "Erro ao enviar solicitação.");
} finally {
setActionLoading(false);
}
}
async function handleParecer() {
if (!data) return;
if (!parecerTexto.trim()) {
setActionFeedback("Digite o texto do parecer.");
return;
}
setActionLoading(true);
setActionFeedback("");
try {
const fd = new FormData();
fd.append("texto", parecerTexto.trim());
if (parecerAnexo) fd.append("anexo", parecerAnexo);
await apiPostFormData(`/api/solicitacoes/${data.id}/parecer/`, fd);
setParecerTexto("");
setParecerAnexo(null);
setActionFeedback("Parecer registrado com sucesso.");
setReloadTick((v) => v + 1);
} catch (err) {
setActionFeedback(err instanceof ApiError ? err.message : "Erro ao registrar parecer.");
} finally {
setActionLoading(false);
}
}
async function handleDecisao() {
if (!data) return;
if (decisao === "REPROVADO" && !justificativaDecisao.trim()) {
setActionFeedback("Justificativa é obrigatória para reprovação.");
return;
}
setActionLoading(true);
setActionFeedback("");
try {
await apiPostJson(`/api/solicitacoes/${data.id}/decidir/`, {
decisao,
justificativa: justificativaDecisao,
});
setActionFeedback("Decisão registrada com sucesso.");
setJustificativaDecisao("");
setReloadTick((v) => v + 1);
} catch (err) {
setActionFeedback(err instanceof ApiError ? err.message : "Erro ao registrar decisão.");
} finally {
setActionLoading(false);
}
}
if (loading) {
return (
<div className="min-h-screen flex items-center justify-center bg-slate-100">
<p className="text-slate-600">Carregando detalhes</p>
</div>
);
}
if (error || !data) {
return (
<div className="min-h-screen bg-slate-100 p-6">
<div className="max-w-4xl mx-auto bg-white border border-slate-200 rounded-xl p-6">
<p className="text-red-600 font-medium">{error || "Falha ao carregar detalhes."}</p>
<div className="mt-4">
<Link href="/dashboard" className="text-blue-600 font-semibold hover:underline">
Voltar para dashboard
</Link>
</div>
</div>
</div>
);
}
return (
<div className="min-h-screen bg-slate-100 p-4 md:p-6">
<div className="max-w-5xl mx-auto space-y-4 text-slate-900">
<div className="bg-white border border-slate-200 rounded-xl p-5">
<div className="flex items-center justify-between gap-3 flex-wrap">
<h1 className="text-xl md:text-2xl font-bold text-slate-900">
{data.tipo_display}
</h1>
<span className="inline-flex py-1 px-2.5 rounded-full text-xs font-bold border bg-slate-100 text-slate-700 border-slate-200">
{data.status_display}
</span>
</div>
<p className="text-base text-slate-800 mt-2 font-medium">
Solicitação: <strong>{data.id}</strong>
</p>
<div className="mt-4 flex flex-wrap gap-4 text-base text-slate-800 font-medium">
<span>Criada em: {formatarData(data.criado_em)}</span>
<span>Enviada em: {formatarData(data.enviada_em)}</span>
<span>Finalizada em: {formatarData(data.finalizada_em)}</span>
</div>
<div className="mt-4 flex items-center gap-4 flex-wrap">
<Link href="/dashboard" className="text-blue-600 font-semibold hover:underline">
Voltar para dashboard
</Link>
<a
href={`${DJANGO_BASE_URL}/solicitacao/${data.id}/comprovante.pdf`}
target="_blank"
rel="noopener noreferrer"
className="text-blue-600 font-semibold hover:underline"
>
Download PDF
</a>
</div>
</div>
<section className="bg-white border border-slate-200 rounded-xl p-5">
<h2 className="text-base font-semibold text-slate-900 mb-3">Dados gerais</h2>
<div className="grid grid-cols-1 md:grid-cols-3 gap-4 text-base">
<div>
<div className="text-slate-700 uppercase text-sm font-bold mb-1">Tipo de processo</div>
<div className="text-slate-900 font-semibold">{data.tipo_display}</div>
</div>
<div>
<div className="text-slate-700 uppercase text-sm font-bold mb-1">Solicitante</div>
<div className="text-slate-900 font-semibold">
{data.solicitante?.nome || "—"} ({data.solicitante?.matricula || "—"})
</div>
</div>
<div>
<div className="text-slate-700 uppercase text-sm font-bold mb-1">Status</div>
<div className="text-slate-900 font-semibold">{data.status_display}</div>
</div>
</div>
</section>
{data.funcionario && (
<section className="bg-white border border-slate-200 rounded-xl p-5 border-l-4 border-l-blue-500">
<h2 className="text-base font-semibold text-slate-900 mb-3">Dados do colaborador (TOTVS RM)</h2>
<p className="text-sm text-slate-700 mb-4 font-medium">Snapshot no momento da criação da solicitação</p>
<div className="grid grid-cols-1 md:grid-cols-3 gap-4 text-base">
<div><div className="text-slate-700 uppercase text-sm font-bold mb-1">Matrícula</div><div className="font-semibold">{data.funcionario.matricula || "—"}</div></div>
<div><div className="text-slate-700 uppercase text-sm font-bold mb-1">Nome completo</div><div className="font-bold">{data.funcionario.nome || "—"}</div></div>
<div><div className="text-slate-700 uppercase text-sm font-bold mb-1">CPF</div><div className="font-semibold">{data.funcionario.cpf || "—"}</div></div>
<div><div className="text-slate-700 uppercase text-sm font-bold mb-1">Data admissão</div><div className="font-semibold">{formatarData(data.funcionario.data_admissao)}</div></div>
<div><div className="text-slate-700 uppercase text-sm font-bold mb-1">Cargo/Função</div><div className="font-semibold">{data.funcionario.cargo || "—"}</div></div>
<div><div className="text-slate-700 uppercase text-sm font-bold mb-1">Cód. função</div><div className="font-semibold">{data.funcionario.cod_funcao || "—"}</div></div>
<div><div className="text-slate-700 uppercase text-sm font-bold mb-1">Setor/Seção</div><div className="font-semibold">{data.funcionario.setor || "—"}</div></div>
<div><div className="text-slate-700 uppercase text-sm font-bold mb-1">Centro de custo</div><div className="font-semibold">{data.funcionario.centro_custo || "—"}</div></div>
<div><div className="text-slate-700 uppercase text-sm font-bold mb-1">Salário atual</div><div className="font-semibold text-emerald-700">{formatarDinheiro(data.funcionario.salario)}</div></div>
</div>
{data.funcionario.saldo_banco_horas_minutos !== null && (
<div className="mt-5 pt-4 border-t border-slate-100 grid grid-cols-1 md:grid-cols-2 gap-4 text-base">
<div>
<div className="text-slate-700 uppercase text-sm font-bold mb-1">Saldo banco de horas</div>
<div className="font-semibold">
{data.funcionario.saldo_banco_horas_minutos >= 0 ? "+" : ""}
{data.funcionario.saldo_banco_horas_minutos} min
</div>
</div>
<div>
<div className="text-slate-700 uppercase text-sm font-bold mb-1">Período referência</div>
<div className="font-semibold">
{formatarData(data.funcionario.inicio_periodo_banco_horas)} a {formatarData(data.funcionario.fim_periodo_banco_horas)}
</div>
</div>
</div>
)}
{data.funcionario.sincronizado_em && (
<p className="text-sm text-slate-600 mt-4 text-right font-medium">
Sincronizado com RM em {formatarData(data.funcionario.sincronizado_em)} | ID: {data.funcionario.id_rm || "—"}
</p>
)}
</section>
)}
{data.dados_winthor && (
<section className="bg-white border border-slate-200 rounded-xl p-5 border-l-4 border-l-blue-500">
<h2 className="text-base font-semibold text-slate-900 mb-3">Dados do colaborador (Winthor)</h2>
<div className="grid grid-cols-1 md:grid-cols-3 gap-4 text-base">
<div><div className="text-slate-700 uppercase text-sm font-bold mb-1">Matrícula</div><div className="font-semibold">{data.dados_winthor.basicos.matricula || "—"}</div></div>
<div><div className="text-slate-700 uppercase text-sm font-bold mb-1">Nome</div><div className="font-semibold">{data.dados_winthor.basicos.nome || "—"}</div></div>
<div><div className="text-slate-700 uppercase text-sm font-bold mb-1">CPF</div><div className="font-semibold">{data.dados_winthor.basicos.cpf || "—"}</div></div>
<div><div className="text-slate-700 uppercase text-sm font-bold mb-1">Data admissão</div><div className="font-semibold">{formatarData(data.dados_winthor.admissao.admissao)}</div></div>
<div><div className="text-slate-700 uppercase text-sm font-bold mb-1">Situação</div><div className="font-semibold">{data.dados_winthor.admissao.situacao || "—"}</div></div>
<div><div className="text-slate-700 uppercase text-sm font-bold mb-1">Data exclusão</div><div className="font-semibold">{formatarData(data.dados_winthor.admissao.dt_exclusao)}</div></div>
<div className="md:col-span-3"><div className="text-slate-700 uppercase text-sm font-bold mb-1">Endereço</div><div className="font-semibold">{data.dados_winthor.endereco.endereco || "—"}</div></div>
<div><div className="text-slate-700 uppercase text-sm font-bold mb-1">Bairro</div><div className="font-semibold">{data.dados_winthor.endereco.bairro || "—"}</div></div>
<div><div className="text-slate-700 uppercase text-sm font-bold mb-1">Cidade</div><div className="font-semibold">{data.dados_winthor.endereco.cidade || "—"}</div></div>
<div><div className="text-slate-700 uppercase text-sm font-bold mb-1">Estado</div><div className="font-semibold">{data.dados_winthor.endereco.estado || "—"}</div></div>
</div>
</section>
)}
{data.detalhes_tipo && (
<section className="bg-white border border-slate-200 rounded-xl p-5">
<h2 className="text-base font-semibold text-slate-900 mb-3">Detalhes da movimentação</h2>
{data.detalhes_tipo.tipo === "DESLIGAMENTO" && (
<div className="grid grid-cols-1 md:grid-cols-3 gap-4 text-base">
<div><div className="text-slate-700 uppercase text-sm font-bold mb-1">Tipo desligamento</div><div className="font-semibold">{(data.detalhes_tipo.tipo_desligamento_display as string) || "—"}</div></div>
<div><div className="text-slate-700 uppercase text-sm font-bold mb-1">Aviso prévio</div><div className="font-semibold">{(data.detalhes_tipo.aviso_previo_display as string) || "—"}</div></div>
<div><div className="text-slate-700 uppercase text-sm font-bold mb-1">Data prevista saída</div><div className="font-semibold">{formatarData((data.detalhes_tipo.data_prevista_desligamento as string) || null)}</div></div>
<div className="md:col-span-3"><div className="text-slate-700 uppercase text-sm font-bold mb-1">Motivo</div><div className="font-semibold whitespace-pre-wrap">{(data.detalhes_tipo.motivo as string) || "—"}</div></div>
{(data.detalhes_tipo.observacoes as string) && <div className="md:col-span-3"><div className="text-slate-700 uppercase text-sm font-bold mb-1">Observações</div><div className="font-semibold whitespace-pre-wrap">{data.detalhes_tipo.observacoes as string}</div></div>}
{(data.detalhes_tipo.arquivo_pedido_url as string) && (
<div className="md:col-span-3">
<a href={data.detalhes_tipo.arquivo_pedido_url as string} target="_blank" rel="noopener noreferrer" className="text-blue-600 font-semibold hover:underline">
📎 Ver carta de pedido
</a>
</div>
)}
</div>
)}
{data.detalhes_tipo.tipo === "MOVIMENTACAO" && (
<div className="grid grid-cols-1 md:grid-cols-3 gap-4 text-base">
<div><div className="text-slate-700 uppercase text-sm font-bold mb-1">Nova função</div><div className="font-semibold">{(data.detalhes_tipo.novo_cod_funcao as string) || "—"}</div></div>
<div><div className="text-slate-700 uppercase text-sm font-bold mb-1">Nova seção</div><div className="font-semibold">{(data.detalhes_tipo.novo_cod_secao as string) || "—"}</div></div>
<div><div className="text-slate-700 uppercase text-sm font-bold mb-1">Novo salário</div><div className="font-semibold">{formatarDinheiro((data.detalhes_tipo.novo_salario as string) || null)}</div></div>
<div><div className="text-slate-700 uppercase text-sm font-bold mb-1">Data efetivação</div><div className="font-semibold">{formatarData((data.detalhes_tipo.data_efetivacao as string) || null)}</div></div>
<div className="md:col-span-3"><div className="text-slate-700 uppercase text-sm font-bold mb-1">Justificativa</div><div className="font-semibold whitespace-pre-wrap">{(data.detalhes_tipo.justificativa as string) || "—"}</div></div>
</div>
)}
{data.detalhes_tipo.tipo === "ADM_SUBSTITUICAO" && (
<div className="grid grid-cols-1 md:grid-cols-3 gap-4 text-base">
<div><div className="text-slate-700 uppercase text-sm font-bold mb-1">Data prevista</div><div className="font-semibold">{formatarData((data.detalhes_tipo.data_previsao_contratacao as string) || null)}</div></div>
<div><div className="text-slate-700 uppercase text-sm font-bold mb-1">Coligada/Filial</div><div className="font-semibold">{String(data.detalhes_tipo.cod_coligada_destino || "—")} / {String(data.detalhes_tipo.cod_filial_destino || "—")}</div></div>
<div><div className="text-slate-700 uppercase text-sm font-bold mb-1">Seção destino</div><div className="font-semibold">{(data.detalhes_tipo.cod_secao_destino as string) || "—"}</div></div>
<div><div className="text-slate-700 uppercase text-sm font-bold mb-1">Função destino</div><div className="font-semibold">{(data.detalhes_tipo.cod_funcao_destino as string) || "—"}</div></div>
<div className="md:col-span-3"><div className="text-slate-700 uppercase text-sm font-bold mb-1">Justificativa</div><div className="font-semibold whitespace-pre-wrap">{(data.detalhes_tipo.justificativa as string) || "—"}</div></div>
</div>
)}
{data.detalhes_tipo.tipo === "ADM_AUMENTO" && (
<div className="grid grid-cols-1 md:grid-cols-3 gap-4 text-base">
<div><div className="text-slate-700 uppercase text-sm font-bold mb-1">Data prevista</div><div className="font-semibold">{formatarData((data.detalhes_tipo.data_previsao_contratacao as string) || null)}</div></div>
<div><div className="text-slate-700 uppercase text-sm font-bold mb-1">Local destino</div><div className="font-semibold">Col: {String(data.detalhes_tipo.cod_coligada_destino || "—")} / Fil: {String(data.detalhes_tipo.cod_filial_destino || "—")}</div></div>
<div><div className="text-slate-700 uppercase text-sm font-bold mb-1">Suplementação orçamentária</div><div className="font-semibold">{data.detalhes_tipo.requer_suplementacao_orcamentaria ? "Sim" : "Não"}</div></div>
<div className="md:col-span-3"><div className="text-slate-700 uppercase text-sm font-bold mb-1">Justificativa estratégica</div><div className="font-semibold whitespace-pre-wrap">{(data.detalhes_tipo.justificativa_estrategica as string) || "—"}</div></div>
</div>
)}
</section>
)}
<section className="bg-white border border-slate-200 rounded-xl p-5">
<h2 className="text-base font-semibold text-slate-900 mb-3">Pareceres</h2>
{data.pareceres.length === 0 ? (
<p className="text-base text-slate-700">Nenhum parecer registrado.</p>
) : (
<div className="grid grid-cols-1 md:grid-cols-2 gap-4">
{data.pareceres.map((parecer) => (
<article key={parecer.id} className="border border-slate-200 rounded-lg p-3">
<p className="text-base font-bold text-slate-900">
{parecer.etapa_display} · {parecer.usuario_nome || "Usuário"}
</p>
<p className="text-sm text-slate-700 mb-2 font-medium">{formatarData(parecer.criado_em)}</p>
<p className="text-base text-slate-800 whitespace-pre-wrap font-medium">{parecer.texto}</p>
{parecer.anexo_url && (
<a
href={toAbsoluteDjangoUrl(parecer.anexo_url)}
target="_blank"
rel="noopener noreferrer"
className="inline-block mt-2 text-blue-600 text-sm font-semibold hover:underline"
>
📎 Ver anexo
</a>
)}
</article>
))}
</div>
)}
</section>
<section className="bg-white border border-slate-200 rounded-xl p-5">
<h2 className="text-base font-semibold text-slate-900 mb-3">Aprovações</h2>
{data.aprovacoes.length === 0 ? (
<p className="text-base text-slate-700">Nenhuma aprovação registrada.</p>
) : (
<div className="space-y-3">
{data.aprovacoes.map((aprovacao) => (
<article key={aprovacao.id} className="border border-slate-200 rounded-lg p-3">
<p className="text-base font-bold text-slate-900">
{aprovacao.etapa_display} · {aprovacao.decisao_display}
</p>
<p className="text-sm text-slate-700 font-medium">
{aprovacao.usuario_nome || "Usuário"} · {formatarData(aprovacao.decidido_em)}
</p>
<p className="text-base text-slate-800 mt-1 whitespace-pre-wrap font-medium">
{aprovacao.justificativa || "Sem justificativa."}
</p>
</article>
))}
</div>
)}
</section>
{data.acoes.pode_enviar && data.acoes.is_solicitante && (
<section className="bg-sky-50 border border-sky-200 rounded-xl p-5">
<h2 className="text-base font-semibold text-sky-900 mb-1">Enviar para aprovação</h2>
<p className="text-sm text-sky-800 mb-3">
Sua solicitação está em rascunho. Revise os dados e envie para iniciar o fluxo.
</p>
<button
onClick={handleEnviar}
disabled={actionLoading}
className="inline-flex items-center gap-1.5 py-2 px-4 rounded-md text-sm font-semibold bg-blue-600 text-white no-underline hover:bg-blue-700 disabled:opacity-60"
>
Confirmar envio
</button>
</section>
)}
{data.acoes.pode_dar_parecer && (
<section className="bg-white border border-slate-200 rounded-xl p-5">
<h2 className="text-base font-semibold text-slate-900 mb-2">Registrar parecer</h2>
<textarea
className="w-full border border-slate-300 rounded-md p-2 min-h-24"
value={parecerTexto}
onChange={(e) => setParecerTexto(e.target.value)}
placeholder="Digite seu parecer técnico..."
/>
<input
type="file"
className="mt-3 w-full border border-slate-300 rounded-md p-2"
onChange={(e) => setParecerAnexo(e.target.files?.[0] || null)}
/>
<button
onClick={handleParecer}
disabled={actionLoading}
className="mt-3 px-4 py-2 rounded-md bg-blue-600 text-white font-semibold hover:bg-blue-700 disabled:opacity-60"
>
Salvar parecer
</button>
</section>
)}
{data.acoes.pode_aprovar && (
<section className="bg-white border border-slate-200 rounded-xl p-5">
<h2 className="text-base font-semibold text-slate-900 mb-2">Registrar decisão</h2>
<div className="grid grid-cols-1 md:grid-cols-2 gap-3">
<select
className="border border-slate-300 rounded-md p-2"
value={decisao}
onChange={(e) => setDecisao(e.target.value as "APROVADO" | "REPROVADO")}
>
<option value="APROVADO">Aprovar</option>
<option value="REPROVADO">Reprovar</option>
</select>
<input
className="border border-slate-300 rounded-md p-2"
placeholder="Justificativa (obrigatória para reprovação)"
value={justificativaDecisao}
onChange={(e) => setJustificativaDecisao(e.target.value)}
/>
</div>
<button
onClick={handleDecisao}
disabled={actionLoading}
className="mt-3 px-4 py-2 rounded-md bg-blue-600 text-white font-semibold hover:bg-blue-700 disabled:opacity-60"
>
Confirmar decisão
</button>
</section>
)}
{actionFeedback && (
<p className="text-sm font-semibold text-slate-800 bg-slate-200 px-3 py-2 rounded">
{actionFeedback}
</p>
)}
</div>
</div>
);
}