feta: inclusão da funcionalidade de expandir e recolher os dados sintéticos

This commit is contained in:
Alessandro Gonçaalves 2025-10-22 10:51:41 -03:00
parent 324730c830
commit acb094271b
1 changed files with 157 additions and 22 deletions

View File

@ -202,6 +202,7 @@ export default function Teste() {
const [isFilterOpen, setIsFilterOpen] = useState(false);
const [dadosFiltrados, setDadosFiltrados] = useState<DREItem[]>([]);
const [filtrosAplicados, setFiltrosAplicados] = useState(false);
const [ordemHierarquiaContasPrimeiro, setOrdemHierarquiaContasPrimeiro] = useState(false);
// Estados para opções dos filtros
const [opcoesGrupos, setOpcoesGrupos] = useState<string[]>([]);
@ -526,6 +527,7 @@ export default function Teste() {
setFiltrosAplicados(false);
setMesesDisponiveis([]);
setIsAllExpanded(false);
setOrdemHierarquiaContasPrimeiro(false);
// Recarregar opções e selecionar todos novamente
carregarPeriodosDisponiveis();
@ -786,8 +788,52 @@ export default function Teste() {
});
if (expandedSubgrupos.has(`${grupo}-${subgrupo}`)) {
// Agrupar por centro de custo dentro do subgrupo
const centros = subgrupoItems.reduce((acc, item) => {
if (ordemHierarquiaContasPrimeiro) {
// NOVA ORDEM: Contas primeiro, depois Centros de Custo
// Agrupar por conta dentro do subgrupo
const contas = subgrupoItems.reduce((acc, item) => {
if (!acc[item.conta]) {
acc[item.conta] = [];
}
acc[item.conta].push(item);
return acc;
}, {} as Record<string, DREItem[]>);
// Ordenar contas
const sortedContas = Object.entries(contas).sort(([a], [b]) =>
a.localeCompare(b)
);
sortedContas.forEach(([conta, contaItems]) => {
const totalConta = contaItems.reduce(
(sum, item) => sum + parseFloat(item.valor),
0
);
// Linha da conta (Level 2 - antes era Level 3)
const valoresContaPorMes = calcularValoresPorMes(contaItems);
rows.push({
type: "conta",
level: 2,
grupo,
subgrupo,
conta,
codigo_conta: contaItems[0].codigo_conta,
total: totalConta,
isExpanded: expandedCentros.has(
`${grupo}-${subgrupo}-${conta}`
),
valoresPorMes: valoresContaPorMes,
percentuaisPorMes: calcularPercentuaisPorMes(
valoresContaPorMes,
grupo
),
});
if (expandedCentros.has(`${grupo}-${subgrupo}-${conta}`)) {
// Agrupar por centro de custo dentro da conta
const centros = contaItems.reduce((acc, item) => {
if (!acc[item.centro_custo]) {
acc[item.centro_custo] = [];
}
@ -796,9 +842,51 @@ export default function Teste() {
}, {} as Record<string, DREItem[]>);
// Ordenar centros de custo
const sortedCentros = Object.entries(centros).sort(([a], [b]) =>
a.localeCompare(b)
);
const sortedCentros = Object.entries(centros).sort(([a], [b]) =>
a.localeCompare(b)
);
sortedCentros.forEach(([centro, centroItems]) => {
const totalCentro = centroItems.reduce(
(sum, item) => sum + parseFloat(item.valor),
0
);
// Linha do centro de custo (Level 3 - antes era Level 2)
const valoresCentroPorMes = calcularValoresPorMes(centroItems);
rows.push({
type: "centro_custo",
level: 3,
grupo,
subgrupo,
centro_custo: centro,
conta,
total: totalCentro,
valoresPorMes: valoresCentroPorMes,
percentuaisPorMes: calcularPercentuaisPorMes(
valoresCentroPorMes,
grupo
),
});
});
}
});
} else {
// ORDEM ORIGINAL: Centros de Custo primeiro, depois Contas
// Agrupar por centro de custo dentro do subgrupo
const centros = subgrupoItems.reduce((acc, item) => {
if (!acc[item.centro_custo]) {
acc[item.centro_custo] = [];
}
acc[item.centro_custo].push(item);
return acc;
}, {} as Record<string, DREItem[]>);
// Ordenar centros de custo
const sortedCentros = Object.entries(centros).sort(([a], [b]) =>
a.localeCompare(b)
);
sortedCentros.forEach(([centro, centroItems]) => {
const totalCentro = centroItems.reduce(
@ -809,7 +897,7 @@ export default function Teste() {
// Linha do centro de custo
const valoresCentroPorMes = calcularValoresPorMes(centroItems);
rows.push({
type: "centro_custo",
type: "centro_custo",
level: 2,
grupo,
subgrupo,
@ -836,9 +924,9 @@ export default function Teste() {
}, {} as Record<string, DREItem[]>);
// Ordenar contas
const sortedContas = Object.entries(contas).sort(([a], [b]) =>
a.localeCompare(b)
);
const sortedContas = Object.entries(contas).sort(([a], [b]) =>
a.localeCompare(b)
);
sortedContas.forEach(([conta, contaItems]) => {
const totalConta = contaItems.reduce(
@ -846,10 +934,10 @@ export default function Teste() {
0
);
// Linha da conta (sem ano/mês no nome)
// Linha da conta
const valoresContaPorMes = calcularValoresPorMes(contaItems);
rows.push({
type: "conta",
type: "conta",
level: 3,
grupo,
subgrupo,
@ -866,6 +954,7 @@ export default function Teste() {
});
}
});
}
}
});
}
@ -976,18 +1065,26 @@ export default function Teste() {
case "centro_custo":
return (
<div className="flex items-center gap-2 whitespace-nowrap">
{ordemHierarquiaContasPrimeiro ? (
// Nova ordem: Centro de custo é level 3 (sem botão de toggle)
<div className="w-8 h-8 flex items-center justify-center flex-shrink-0">
<span className="text-gray-400 font-bold text-lg"></span>
</div>
) : (
// Ordem original: Centro de custo é level 2 (com botão de toggle)
<button
onClick={() =>
toggleCentro(`${row.grupo}-${row.subgrupo}-${row.centro_custo}`)
}
className="p-2 hover:bg-blue-100 rounded-lg transition-all duration-150 ease-in-out flex items-center justify-center w-8 h-8 flex-shrink-0 transform hover:scale-105"
>
{row.isExpanded ? (
<ChevronDown className="w-4 h-4 text-blue-600 transition-transform duration-150" />
) : (
<ChevronRight className="w-4 h-4 text-blue-600 transition-transform duration-150" />
)}
className="p-2 hover:bg-blue-100 rounded-lg transition-all duration-150 ease-in-out flex items-center justify-center w-8 h-8 flex-shrink-0 transform hover:scale-105"
>
{row.isExpanded ? (
<ChevronDown className="w-4 h-4 text-blue-600 transition-transform duration-150" />
) : (
<ChevronRight className="w-4 h-4 text-blue-600 transition-transform duration-150" />
)}
</button>
)}
<button
onClick={() => handleRowClick(row)}
className="flex-1 text-left hover:bg-blue-50/50 p-2 rounded-lg cursor-pointer transition-all duration-200 truncate"
@ -1001,9 +1098,26 @@ export default function Teste() {
case "conta":
return (
<div className="flex items-center gap-2 whitespace-nowrap">
<div className="w-8 h-8 flex items-center justify-center flex-shrink-0">
<span className="text-gray-400 font-bold text-lg"></span>
</div>
{ordemHierarquiaContasPrimeiro ? (
// Nova ordem: Conta é level 2 (com botão de toggle)
<button
onClick={() =>
toggleCentro(`${row.grupo}-${row.subgrupo}-${row.conta}`)
}
className="p-2 hover:bg-blue-100 rounded-lg transition-all duration-150 ease-in-out flex items-center justify-center w-8 h-8 flex-shrink-0 transform hover:scale-105"
>
{row.isExpanded ? (
<ChevronDown className="w-4 h-4 text-blue-600 transition-transform duration-150" />
) : (
<ChevronRight className="w-4 h-4 text-blue-600 transition-transform duration-150" />
)}
</button>
) : (
// Ordem original: Conta é level 3 (sem botão de toggle)
<div className="w-8 h-8 flex items-center justify-center flex-shrink-0">
<span className="text-gray-400 font-bold text-lg"></span>
</div>
)}
<button
onClick={() => handleRowClick(row)}
className="flex-1 text-left hover:bg-blue-50/50 p-2 rounded-lg cursor-pointer transition-all duration-200 truncate"
@ -1214,7 +1328,7 @@ export default function Teste() {
>
Limpar
</Button>
</div>
</div>
</div>
<div className="max-h-32 overflow-y-auto border rounded-md p-1 space-y-1">
{opcoesContas.map(conta => (
@ -1283,6 +1397,27 @@ export default function Teste() {
placeholder="Pesquise por grupo, subgrupo, centro ou conta"
/>
</div>*/}
{/* Ordem da Hierarquia */}
<div className="grid gap-2">
<Label>Ordem da Hierarquia</Label>
<div className="flex items-center space-x-2">
<Checkbox
id="ordem-hierarquia"
checked={ordemHierarquiaContasPrimeiro}
onCheckedChange={(checked: boolean) => setOrdemHierarquiaContasPrimeiro(checked)}
/>
<Label htmlFor="ordem-hierarquia" className="text-sm">
Contas antes de Centros de Custo
</Label>
</div>
<div className="text-xs text-gray-500">
{ordemHierarquiaContasPrimeiro
? "📄 Contas → 🏢 Centros de Custo"
: "🏢 Centros de Custo → 📄 Contas"
}
</div>
</div>
</div>
<SheetFooter className="flex gap-2">