implementacao de logs de auditoria e alterar multiplos registros de competencia
This commit is contained in:
@@ -413,7 +413,12 @@ export default function CompetenciaFechamentos() {
|
|||||||
<TableRow>
|
<TableRow>
|
||||||
<TableHead className="min-w-[100px]">Logo</TableHead>
|
<TableHead className="min-w-[100px]">Logo</TableHead>
|
||||||
<TableHead className="min-w-[280px]">Nome</TableHead>
|
<TableHead className="min-w-[280px]">Nome</TableHead>
|
||||||
<TableHead className="min-w-[140px] text-right">Pontuação Total</TableHead>
|
<TableHead
|
||||||
|
className="min-w-[140px] text-right"
|
||||||
|
title="Soma de todas as tarefas do fechamento (revisadas ou não), igual ao total do mês no detalhe e ao dashboard."
|
||||||
|
>
|
||||||
|
Pontuação Total
|
||||||
|
</TableHead>
|
||||||
<TableHead className="min-w-[150px] text-right">Pontuação Paga</TableHead>
|
<TableHead className="min-w-[150px] text-right">Pontuação Paga</TableHead>
|
||||||
<TableHead className="min-w-[120px]">Status</TableHead>
|
<TableHead className="min-w-[120px]">Status</TableHead>
|
||||||
<TableHead className="text-center">Ações</TableHead>
|
<TableHead className="text-center">Ações</TableHead>
|
||||||
@@ -639,7 +644,7 @@ export default function CompetenciaFechamentos() {
|
|||||||
>
|
>
|
||||||
<p className="text-sm font-semibold">Buscar novos fechamentos</p>
|
<p className="text-sm font-semibold">Buscar novos fechamentos</p>
|
||||||
<p className="mt-1 text-xs text-muted-foreground">
|
<p className="mt-1 text-xs text-muted-foreground">
|
||||||
Busca no Asana e cria apenas os fechamentos que ainda não existem.
|
Busca no Asana e cria fechamentos que ainda não existem (inclusive vazios, se o parceiro não tiver tasks no período).
|
||||||
</p>
|
</p>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -279,7 +279,8 @@ export default function DashboardPontos() {
|
|||||||
Dashboard
|
Dashboard
|
||||||
</h1>
|
</h1>
|
||||||
<p className="max-w-xl text-sm text-muted-foreground">
|
<p className="max-w-xl text-sm text-muted-foreground">
|
||||||
Distribuição de pontos por cliente — visão rápida do que cada parceiro entregou no período.
|
Distribuição por cliente — total da competência no período (todas as tarefas do fechamento, alinhado à
|
||||||
|
pontuação total do mês na tela de fechamento).
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<Button
|
<Button
|
||||||
|
|||||||
@@ -302,7 +302,9 @@ export default function FechamentoDetalhes() {
|
|||||||
const [loadingCompetenciasAbertas, setLoadingCompetenciasAbertas] = useState(false);
|
const [loadingCompetenciasAbertas, setLoadingCompetenciasAbertas] = useState(false);
|
||||||
const [savingAlteracaoCompetencia, setSavingAlteracaoCompetencia] = useState(false);
|
const [savingAlteracaoCompetencia, setSavingAlteracaoCompetencia] = useState(false);
|
||||||
const [competenciasAbertas, setCompetenciasAbertas] = useState<CompetenciaItem[]>([]);
|
const [competenciasAbertas, setCompetenciasAbertas] = useState<CompetenciaItem[]>([]);
|
||||||
const [tarefaAlteracaoCompetencia, setTarefaAlteracaoCompetencia] = useState<FechamentoTarefaItem | null>(null);
|
const [tarefasAlteracaoCompetencia, setTarefasAlteracaoCompetencia] = useState<FechamentoTarefaItem[]>([]);
|
||||||
|
const [selectedTarefaIds, setSelectedTarefaIds] = useState<Set<string>>(() => new Set());
|
||||||
|
const [modoSelecaoAlterarCompetencia, setModoSelecaoAlterarCompetencia] = useState(false);
|
||||||
const [competenciaDestinoId, setCompetenciaDestinoId] = useState("");
|
const [competenciaDestinoId, setCompetenciaDestinoId] = useState("");
|
||||||
const [motivoAlteracaoCompetencia, setMotivoAlteracaoCompetencia] = useState("");
|
const [motivoAlteracaoCompetencia, setMotivoAlteracaoCompetencia] = useState("");
|
||||||
const [isEditarOpen, setIsEditarOpen] = useState(false);
|
const [isEditarOpen, setIsEditarOpen] = useState(false);
|
||||||
@@ -442,6 +444,16 @@ export default function FechamentoDetalhes() {
|
|||||||
filtroDataConclusaoFim,
|
filtroDataConclusaoFim,
|
||||||
intervaloDataConclusaoInvalido,
|
intervaloDataConclusaoInvalido,
|
||||||
]);
|
]);
|
||||||
|
const tarefasSelecionaveisCompetencia = useMemo(
|
||||||
|
() => tarefasFiltradas.filter((t) => t.tipo === "tarefa"),
|
||||||
|
[tarefasFiltradas],
|
||||||
|
);
|
||||||
|
const selectedTarefaCount = selectedTarefaIds.size;
|
||||||
|
const todasVisiveisSelecionadas =
|
||||||
|
tarefasSelecionaveisCompetencia.length > 0 &&
|
||||||
|
tarefasSelecionaveisCompetencia.every((t) => selectedTarefaIds.has(t.id));
|
||||||
|
const exibirColunaSelecaoCompetencia = podeAlterarCompetenciaTarefa && modoSelecaoAlterarCompetencia;
|
||||||
|
const tabelaColSpan = exibirColunaSelecaoCompetencia ? 12 : 11;
|
||||||
|
|
||||||
const loadTarefas = async () => {
|
const loadTarefas = async () => {
|
||||||
try {
|
try {
|
||||||
@@ -947,33 +959,91 @@ export default function FechamentoDetalhes() {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const openAlterarCompetencia = async (tarefa: FechamentoTarefaItem) => {
|
const assertPodeAlterarCompetencia = (): boolean => {
|
||||||
if (!podeAlterarCompetenciaTarefa) {
|
if (!podeAlterarCompetenciaTarefa) {
|
||||||
toast.error("Sem permissão para alterar competência da tarefa.");
|
toast.error("Sem permissão para alterar competência da tarefa.");
|
||||||
return;
|
return false;
|
||||||
}
|
}
|
||||||
if (isCompetenciaConcluida) {
|
if (isCompetenciaConcluida) {
|
||||||
toastBloqueioCompetenciaConcluida();
|
toastBloqueioCompetenciaConcluida();
|
||||||
return;
|
return false;
|
||||||
}
|
}
|
||||||
if (isFechado) {
|
if (isFechado) {
|
||||||
toastBloqueioFechado();
|
toastBloqueioFechado();
|
||||||
return;
|
return false;
|
||||||
}
|
}
|
||||||
const competencias = await carregarCompetenciasAbertas();
|
return true;
|
||||||
const opcoes = competencias.filter((item) => item.id !== competenciaId);
|
};
|
||||||
if (opcoes.length === 0) {
|
|
||||||
toast.error("Não há outra competência em aberto para mover a tarefa.");
|
const abrirDialogAlterarCompetencia = (lista: FechamentoTarefaItem[], opcoes: CompetenciaItem[]) => {
|
||||||
return;
|
setTarefasAlteracaoCompetencia(lista);
|
||||||
}
|
|
||||||
setTarefaAlteracaoCompetencia(tarefa);
|
|
||||||
setCompetenciaDestinoId(opcoes[0]?.id ?? "");
|
setCompetenciaDestinoId(opcoes[0]?.id ?? "");
|
||||||
setMotivoAlteracaoCompetencia("");
|
setMotivoAlteracaoCompetencia("");
|
||||||
setIsAlterarCompetenciaOpen(true);
|
setIsAlterarCompetenciaOpen(true);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const sairModoSelecaoAlterarCompetencia = () => {
|
||||||
|
setModoSelecaoAlterarCompetencia(false);
|
||||||
|
setSelectedTarefaIds(new Set());
|
||||||
|
};
|
||||||
|
|
||||||
|
const entrarModoSelecaoAlterarCompetencia = () => {
|
||||||
|
if (!assertPodeAlterarCompetencia()) return;
|
||||||
|
setModoSelecaoAlterarCompetencia(true);
|
||||||
|
setSelectedTarefaIds(new Set());
|
||||||
|
};
|
||||||
|
|
||||||
|
const openAlterarCompetenciaEmLote = async () => {
|
||||||
|
if (!assertPodeAlterarCompetencia()) return;
|
||||||
|
if (selectedTarefaCount === 0) {
|
||||||
|
toast.error("Selecione ao menos uma tarefa.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const lista = tarefas.filter((t) => selectedTarefaIds.has(t.id) && t.tipo === "tarefa");
|
||||||
|
if (lista.length === 0) {
|
||||||
|
toast.error("Nenhuma tarefa válida selecionada.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const competencias = await carregarCompetenciasAbertas();
|
||||||
|
const opcoes = competencias.filter((item) => item.id !== competenciaId);
|
||||||
|
if (opcoes.length === 0) {
|
||||||
|
toast.error("Não há outra competência em aberto para mover as tarefas.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
abrirDialogAlterarCompetencia(lista, opcoes);
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleToggleSelecaoTarefa = (tarefaId: string, checked: boolean) => {
|
||||||
|
setSelectedTarefaIds((prev) => {
|
||||||
|
const next = new Set(prev);
|
||||||
|
if (checked) next.add(tarefaId);
|
||||||
|
else next.delete(tarefaId);
|
||||||
|
return next;
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleSelecionarTodasVisiveisCompetencia = () => {
|
||||||
|
if (todasVisiveisSelecionadas) {
|
||||||
|
setSelectedTarefaIds((prev) => {
|
||||||
|
const next = new Set(prev);
|
||||||
|
for (const t of tarefasSelecionaveisCompetencia) next.delete(t.id);
|
||||||
|
return next;
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
setSelectedTarefaIds((prev) => {
|
||||||
|
const next = new Set(prev);
|
||||||
|
for (const t of tarefasSelecionaveisCompetencia) next.add(t.id);
|
||||||
|
return next;
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleLimparSelecaoTarefas = () => {
|
||||||
|
setSelectedTarefaIds(new Set());
|
||||||
|
};
|
||||||
|
|
||||||
const handleConfirmarAlteracaoCompetencia = async () => {
|
const handleConfirmarAlteracaoCompetencia = async () => {
|
||||||
if (!tarefaAlteracaoCompetencia) return;
|
if (tarefasAlteracaoCompetencia.length === 0) return;
|
||||||
if (!me?.id) {
|
if (!me?.id) {
|
||||||
toast.error("Não foi possível identificar o usuário para registrar a alteração.");
|
toast.error("Não foi possível identificar o usuário para registrar a alteração.");
|
||||||
return;
|
return;
|
||||||
@@ -982,21 +1052,33 @@ export default function FechamentoDetalhes() {
|
|||||||
toast.error("Selecione a competência de destino.");
|
toast.error("Selecione a competência de destino.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
try {
|
const payload = {
|
||||||
setSavingAlteracaoCompetencia(true);
|
|
||||||
await fechamentoFechamentosService.alterarCompetenciaTarefa(fechamentoId, tarefaAlteracaoCompetencia.id, {
|
|
||||||
competenciaDestinoId,
|
competenciaDestinoId,
|
||||||
alteradoPorId: me.id,
|
alteradoPorId: me.id,
|
||||||
motivo: motivoAlteracaoCompetencia,
|
motivo: motivoAlteracaoCompetencia,
|
||||||
});
|
};
|
||||||
|
try {
|
||||||
|
setSavingAlteracaoCompetencia(true);
|
||||||
|
const ids = tarefasAlteracaoCompetencia.map((t) => t.id);
|
||||||
|
if (ids.length === 1) {
|
||||||
|
await fechamentoFechamentosService.alterarCompetenciaTarefa(fechamentoId, ids[0]!, payload);
|
||||||
toast.success("Competência da tarefa alterada com sucesso.");
|
toast.success("Competência da tarefa alterada com sucesso.");
|
||||||
|
} else {
|
||||||
|
const res = await fechamentoFechamentosService.alterarCompetenciaTarefasEmLote(fechamentoId, {
|
||||||
|
tarefaIds: ids,
|
||||||
|
...payload,
|
||||||
|
});
|
||||||
|
toast.success(`Competência alterada em ${res.alteradas} tarefa(s).`);
|
||||||
|
}
|
||||||
setIsAlterarCompetenciaOpen(false);
|
setIsAlterarCompetenciaOpen(false);
|
||||||
setTarefaAlteracaoCompetencia(null);
|
setTarefasAlteracaoCompetencia([]);
|
||||||
setCompetenciaDestinoId("");
|
setCompetenciaDestinoId("");
|
||||||
setMotivoAlteracaoCompetencia("");
|
setMotivoAlteracaoCompetencia("");
|
||||||
|
setSelectedTarefaIds(new Set());
|
||||||
|
setModoSelecaoAlterarCompetencia(false);
|
||||||
await loadTarefas();
|
await loadTarefas();
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
const message = error instanceof Error ? error.message : "Erro ao alterar competência da tarefa.";
|
const message = error instanceof Error ? error.message : "Erro ao alterar competência da(s) tarefa(s).";
|
||||||
toast.error(message);
|
toast.error(message);
|
||||||
} finally {
|
} finally {
|
||||||
setSavingAlteracaoCompetencia(false);
|
setSavingAlteracaoCompetencia(false);
|
||||||
@@ -1244,6 +1326,66 @@ export default function FechamentoDetalhes() {
|
|||||||
{!loading ? (
|
{!loading ? (
|
||||||
<div className="space-y-3">
|
<div className="space-y-3">
|
||||||
<div className="flex flex-wrap items-center justify-end gap-2">
|
<div className="flex flex-wrap items-center justify-end gap-2">
|
||||||
|
{podeAlterarCompetenciaTarefa ? (
|
||||||
|
modoSelecaoAlterarCompetencia ? (
|
||||||
|
<>
|
||||||
|
<Button
|
||||||
|
type="button"
|
||||||
|
size="sm"
|
||||||
|
variant="ghost"
|
||||||
|
onClick={sairModoSelecaoAlterarCompetencia}
|
||||||
|
disabled={savingAlteracaoCompetencia}
|
||||||
|
>
|
||||||
|
Cancelar
|
||||||
|
</Button>
|
||||||
|
<Button
|
||||||
|
type="button"
|
||||||
|
size="sm"
|
||||||
|
variant="outline"
|
||||||
|
onClick={handleSelecionarTodasVisiveisCompetencia}
|
||||||
|
disabled={
|
||||||
|
bloqueioEdicaoTarefa ||
|
||||||
|
tarefasSelecionaveisCompetencia.length === 0 ||
|
||||||
|
savingAlteracaoCompetencia
|
||||||
|
}
|
||||||
|
>
|
||||||
|
{todasVisiveisSelecionadas ? "Desmarcar visíveis" : "Selecionar visíveis"}
|
||||||
|
</Button>
|
||||||
|
<Button
|
||||||
|
type="button"
|
||||||
|
size="sm"
|
||||||
|
variant="outline"
|
||||||
|
onClick={handleLimparSelecaoTarefas}
|
||||||
|
disabled={selectedTarefaCount === 0 || savingAlteracaoCompetencia}
|
||||||
|
>
|
||||||
|
Limpar seleção
|
||||||
|
</Button>
|
||||||
|
<Button
|
||||||
|
type="button"
|
||||||
|
size="sm"
|
||||||
|
variant="default"
|
||||||
|
onClick={() => void openAlterarCompetenciaEmLote()}
|
||||||
|
disabled={
|
||||||
|
bloqueioEdicaoTarefa || selectedTarefaCount === 0 || savingAlteracaoCompetencia
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<Repeat className="mr-2 h-4 w-4" />
|
||||||
|
Continuar ({selectedTarefaCount})
|
||||||
|
</Button>
|
||||||
|
</>
|
||||||
|
) : (
|
||||||
|
<Button
|
||||||
|
type="button"
|
||||||
|
size="sm"
|
||||||
|
variant="outline"
|
||||||
|
onClick={entrarModoSelecaoAlterarCompetencia}
|
||||||
|
disabled={bloqueioEdicaoTarefa || savingAlteracaoCompetencia}
|
||||||
|
>
|
||||||
|
<Repeat className="mr-2 h-4 w-4" />
|
||||||
|
Alterar competência
|
||||||
|
</Button>
|
||||||
|
)
|
||||||
|
) : null}
|
||||||
<Button type="button" size="sm" variant="outline" onClick={() => setShowFilters((prev) => !prev)}>
|
<Button type="button" size="sm" variant="outline" onClick={() => setShowFilters((prev) => !prev)}>
|
||||||
{showFilters ? "Ocultar filtros" : "Exibir filtros"}
|
{showFilters ? "Ocultar filtros" : "Exibir filtros"}
|
||||||
</Button>
|
</Button>
|
||||||
@@ -1399,6 +1541,9 @@ export default function FechamentoDetalhes() {
|
|||||||
<Table>
|
<Table>
|
||||||
<TableHeader>
|
<TableHeader>
|
||||||
<TableRow>
|
<TableRow>
|
||||||
|
{exibirColunaSelecaoCompetencia ? (
|
||||||
|
<TableHead className="min-w-[88px] whitespace-nowrap px-2">Selecionar</TableHead>
|
||||||
|
) : null}
|
||||||
<TableHead className="min-w-[120px]">Aprovada</TableHead>
|
<TableHead className="min-w-[120px]">Aprovada</TableHead>
|
||||||
<TableHead className="min-w-[120px]">Ticket</TableHead>
|
<TableHead className="min-w-[120px]">Ticket</TableHead>
|
||||||
<TableHead className="min-w-[320px]">Descrição</TableHead>
|
<TableHead className="min-w-[320px]">Descrição</TableHead>
|
||||||
@@ -1415,25 +1560,47 @@ export default function FechamentoDetalhes() {
|
|||||||
<TableBody>
|
<TableBody>
|
||||||
{loading ? (
|
{loading ? (
|
||||||
<TableRow>
|
<TableRow>
|
||||||
<TableCell colSpan={11} className="py-8 text-center text-muted-foreground">
|
<TableCell colSpan={tabelaColSpan} className="py-8 text-center text-muted-foreground">
|
||||||
Carregando tarefas...
|
Carregando tarefas...
|
||||||
</TableCell>
|
</TableCell>
|
||||||
</TableRow>
|
</TableRow>
|
||||||
) : tarefasFiltradas.length === 0 ? (
|
) : tarefasFiltradas.length === 0 ? (
|
||||||
<TableRow>
|
<TableRow>
|
||||||
<TableCell colSpan={11} className="py-8 text-center text-muted-foreground">
|
<TableCell colSpan={tabelaColSpan} className="py-8 text-center text-muted-foreground">
|
||||||
Nenhuma tarefa encontrada com os filtros aplicados.
|
Nenhuma tarefa encontrada com os filtros aplicados.
|
||||||
</TableCell>
|
</TableCell>
|
||||||
</TableRow>
|
</TableRow>
|
||||||
) : (
|
) : (
|
||||||
tarefasFiltradas.map((tarefa) => (
|
tarefasFiltradas.map((tarefa) => (
|
||||||
<TableRow key={tarefa.id}>
|
<TableRow
|
||||||
|
key={tarefa.id}
|
||||||
|
className={cn(
|
||||||
|
exibirColunaSelecaoCompetencia &&
|
||||||
|
selectedTarefaIds.has(tarefa.id) &&
|
||||||
|
"bg-primary/5",
|
||||||
|
)}
|
||||||
|
>
|
||||||
|
{exibirColunaSelecaoCompetencia ? (
|
||||||
|
<TableCell className="min-w-[88px] px-2">
|
||||||
|
{tarefa.tipo === "tarefa" ? (
|
||||||
|
<Checkbox
|
||||||
|
checked={selectedTarefaIds.has(tarefa.id)}
|
||||||
|
onCheckedChange={(checked) =>
|
||||||
|
handleToggleSelecaoTarefa(tarefa.id, Boolean(checked))
|
||||||
|
}
|
||||||
|
disabled={bloqueioEdicaoTarefa || savingAlteracaoCompetencia}
|
||||||
|
aria-label={`Selecionar tarefa ${tarefa.descricao}`}
|
||||||
|
/>
|
||||||
|
) : null}
|
||||||
|
</TableCell>
|
||||||
|
) : null}
|
||||||
<TableCell>
|
<TableCell>
|
||||||
<div className="flex items-center gap-2">
|
<div className="flex items-center gap-2">
|
||||||
<Checkbox
|
<Checkbox
|
||||||
checked={tarefa.estaRevisada}
|
checked={tarefa.estaRevisada}
|
||||||
onCheckedChange={(checked) => void handleToggleAprovada(tarefa, Boolean(checked))}
|
onCheckedChange={(checked) => void handleToggleAprovada(tarefa, Boolean(checked))}
|
||||||
disabled={bloqueioEdicaoTarefa || bulkUpdatingRevisao}
|
disabled={bloqueioEdicaoTarefa || bulkUpdatingRevisao}
|
||||||
|
className="border-emerald-600/70 data-[state=checked]:border-emerald-600 data-[state=checked]:bg-emerald-600 data-[state=checked]:text-white focus-visible:ring-emerald-500/40"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</TableCell>
|
</TableCell>
|
||||||
@@ -1478,18 +1645,6 @@ export default function FechamentoDetalhes() {
|
|||||||
<Pencil className="h-4 w-4" />
|
<Pencil className="h-4 w-4" />
|
||||||
<span className="ml-1">Editar</span>
|
<span className="ml-1">Editar</span>
|
||||||
</Button>
|
</Button>
|
||||||
{podeAlterarCompetenciaTarefa && tarefa.tipo === "tarefa" ? (
|
|
||||||
<Button
|
|
||||||
type="button"
|
|
||||||
size="sm"
|
|
||||||
variant="ghost"
|
|
||||||
onClick={() => void openAlterarCompetencia(tarefa)}
|
|
||||||
disabled={bloqueioEdicaoTarefa || savingAlteracaoCompetencia}
|
|
||||||
>
|
|
||||||
<Repeat className="h-4 w-4" />
|
|
||||||
<span className="ml-1">Alterar competência</span>
|
|
||||||
</Button>
|
|
||||||
) : null}
|
|
||||||
{tarefa.tipo === "bonus" || tarefa.tipo === "desconto" ? (
|
{tarefa.tipo === "bonus" || tarefa.tipo === "desconto" ? (
|
||||||
<Button
|
<Button
|
||||||
type="button"
|
type="button"
|
||||||
@@ -1671,7 +1826,7 @@ export default function FechamentoDetalhes() {
|
|||||||
onOpenChange={(open) => {
|
onOpenChange={(open) => {
|
||||||
setIsAlterarCompetenciaOpen(open);
|
setIsAlterarCompetenciaOpen(open);
|
||||||
if (!open) {
|
if (!open) {
|
||||||
setTarefaAlteracaoCompetencia(null);
|
setTarefasAlteracaoCompetencia([]);
|
||||||
setMotivoAlteracaoCompetencia("");
|
setMotivoAlteracaoCompetencia("");
|
||||||
setCompetenciaDestinoId("");
|
setCompetenciaDestinoId("");
|
||||||
}
|
}
|
||||||
@@ -1679,12 +1834,35 @@ export default function FechamentoDetalhes() {
|
|||||||
>
|
>
|
||||||
<DialogContent className="sm:max-w-lg">
|
<DialogContent className="sm:max-w-lg">
|
||||||
<DialogHeader>
|
<DialogHeader>
|
||||||
<DialogTitle>Alterar competência da tarefa</DialogTitle>
|
<DialogTitle>
|
||||||
|
{tarefasAlteracaoCompetencia.length <= 1
|
||||||
|
? "Alterar competência da tarefa"
|
||||||
|
: `Alterar competência de ${tarefasAlteracaoCompetencia.length} tarefas`}
|
||||||
|
</DialogTitle>
|
||||||
<DialogDescription>
|
<DialogDescription>
|
||||||
Mova a tarefa para outra competência em aberto. O histórico da alteração ficará registrado.
|
{tarefasAlteracaoCompetencia.length <= 1
|
||||||
|
? "Mova a tarefa para outra competência em aberto. O histórico da alteração ficará registrado."
|
||||||
|
: "Mova as tarefas selecionadas para outra competência em aberto. O histórico de cada alteração ficará registrado."}
|
||||||
</DialogDescription>
|
</DialogDescription>
|
||||||
</DialogHeader>
|
</DialogHeader>
|
||||||
<div className="space-y-4">
|
<div className="space-y-4">
|
||||||
|
{tarefasAlteracaoCompetencia.length > 1 ? (
|
||||||
|
<div className="space-y-2">
|
||||||
|
<Label>Tarefas selecionadas</Label>
|
||||||
|
<ul className="max-h-32 space-y-1 overflow-y-auto rounded-md border bg-muted/30 px-3 py-2 text-sm text-muted-foreground">
|
||||||
|
{tarefasAlteracaoCompetencia.slice(0, 5).map((t) => (
|
||||||
|
<li key={t.id} className="truncate">
|
||||||
|
{t.descricao}
|
||||||
|
</li>
|
||||||
|
))}
|
||||||
|
{tarefasAlteracaoCompetencia.length > 5 ? (
|
||||||
|
<li className="font-medium text-foreground">
|
||||||
|
e mais {tarefasAlteracaoCompetencia.length - 5} tarefa(s)…
|
||||||
|
</li>
|
||||||
|
) : null}
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
) : null}
|
||||||
<div className="space-y-2">
|
<div className="space-y-2">
|
||||||
<Label>Competência atual</Label>
|
<Label>Competência atual</Label>
|
||||||
<p className="rounded-md border bg-muted/30 px-3 py-2 text-sm text-muted-foreground">
|
<p className="rounded-md border bg-muted/30 px-3 py-2 text-sm text-muted-foreground">
|
||||||
@@ -1741,7 +1919,11 @@ export default function FechamentoDetalhes() {
|
|||||||
onClick={() => void handleConfirmarAlteracaoCompetencia()}
|
onClick={() => void handleConfirmarAlteracaoCompetencia()}
|
||||||
disabled={savingAlteracaoCompetencia || !competenciaDestinoId}
|
disabled={savingAlteracaoCompetencia || !competenciaDestinoId}
|
||||||
>
|
>
|
||||||
{savingAlteracaoCompetencia ? "Alterando..." : "Confirmar alteração"}
|
{savingAlteracaoCompetencia
|
||||||
|
? "Alterando..."
|
||||||
|
: tarefasAlteracaoCompetencia.length > 1
|
||||||
|
? `Confirmar (${tarefasAlteracaoCompetencia.length})`
|
||||||
|
: "Confirmar alteração"}
|
||||||
</Button>
|
</Button>
|
||||||
</DialogFooter>
|
</DialogFooter>
|
||||||
</DialogContent>
|
</DialogContent>
|
||||||
|
|||||||
@@ -392,6 +392,27 @@ class FechamentoFechamentosService {
|
|||||||
this.handleAxiosError(error, "Erro ao alterar competência da tarefa.");
|
this.handleAxiosError(error, "Erro ao alterar competência da tarefa.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async alterarCompetenciaTarefasEmLote(
|
||||||
|
fechamentoId: string,
|
||||||
|
input: { tarefaIds: string[]; competenciaDestinoId: string; alteradoPorId: string; motivo?: string },
|
||||||
|
): Promise<{ alteradas: number; tarefas: FechamentoTarefaItem[] }> {
|
||||||
|
try {
|
||||||
|
const headers = await buildCommanderHeaders();
|
||||||
|
const baseUrl = resolveCommanderBaseUrl();
|
||||||
|
const response = await axios.post<{
|
||||||
|
data: { alteradas: number; tarefas: FechamentoTarefaItem[] };
|
||||||
|
}>(`${baseUrl}/fechamentos/${fechamentoId}/tarefas/alterar-competencia`, {
|
||||||
|
tarefa_ids: input.tarefaIds,
|
||||||
|
competencia_destino_id: input.competenciaDestinoId,
|
||||||
|
alterado_por_id: input.alteradoPorId,
|
||||||
|
...(input.motivo?.trim() ? { motivo: input.motivo.trim() } : {}),
|
||||||
|
}, { headers });
|
||||||
|
return response.data.data;
|
||||||
|
} catch (error) {
|
||||||
|
this.handleAxiosError(error, "Erro ao alterar competência das tarefas.");
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export const fechamentoFechamentosService = new FechamentoFechamentosService();
|
export const fechamentoFechamentosService = new FechamentoFechamentosService();
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
Reference in New Issue
Block a user