fix(ux): varredura de skeleton loading — 6 páginas do Financeiro + Iniciativas - #34
Merged
Merged
Conversation
fix(visao): esqueleto fiel e um carregamento só na Visão do Projeto O esqueleto não era só impreciso — ele escondia um carregamento duplicado. 1. A flag RETRATO_EMPRESA nascia `false` no cliente e só depois consultava o override no banco. Como ela está global ON, a árvore SEMPRE mudava de forma quando o override resolvia (<RaioXMesTab/> na raiz → <div><PremiumTabs/> <RaioXMesTab/></div>), o que desmontava a aba e refazia a leitura inteira: o esqueleto reaparecia do zero e a barra de abas caía na tela empurrando tudo. Corrigido com featureDefault() (isomórfico SSR↔cliente — não lê env, que não existe no bundle do browser) + slots fixos no shell. 2. A faixa "Composição & trajetória" tem ~1.100px reais (histórico 382 + entradas por forma ~254 + 2 gráficos de 422) e era representada por UM bloco de 288px. A página saltava quando o dado chegava. 3. A aba Retrato tinha DOIS esqueletos diferentes em sequência (intervalo de meses → seções). As leituras foram para o TanStack Query (mesmo QueryProvider do layout de projeto): trocar de aba passa a servir do cache em vez de refazer a tela, e trocar de período/janela mantém os números anteriores atenuados via keepPreviousData. Peças de esqueleto compartilhadas em components/visao/skeleton-pecas.tsx, com as medidas do DS documentadas (Card com título+subtítulo = 74px de header + p-6 + altura do gráfico; RetratoKpi = 112px; DreLinhaCard = 153px). Gate: tsc 0 · eslint 0 · next build 0 · vitest 1323/1323. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> @
fix(apuracao): DRE não afirma mais "sem dados" durante o load + grupo carrega 1x A Apuração tinha mais problema de carregamento do que de esqueleto. 1. A DRE MENTIA. ResultsTab caía no estado vazio "Sem dados no recorte — o período selecionado não tem transações categorizadas" (com CTA "Ir para Categorização") sempre que dreMultiMensal fosse null — e ele é null durante todo o load, porque selectedPeriod começa null e só é escolhido por effect depois dos exercícios. Pior: repetia a CADA troca de mês, porque a query do recorte zerava na troca de chave. O controller agora expõe isCarregandoResultado, cobrindo a janela inteira de ignorância (exercícios → escolha do recorte → transações → snapshots e detalhamentos; sem os dois últimos um mês FECHADO era desenhado como "cru" e trocava de valor na tela). Com keepPreviousData, trocar de mês mantém a DRE anterior atenuada em vez de sumir. 2. O SHELL CARREGAVA O GRUPO DUAS VEZES em toda entrada: carregar() rodava com o mês vigente, descobria o último mês FECHADO, chamava setMes() — e `mes` era dependência do próprio carregar, então o effect refazia projeto + grupo + cobertura do zero, com setLoading(true) no meio. Como o mês vigente quase nunca está fechado, era em praticamente toda visita. Viraram duas leituras separadas (escopo 1x / cobertura por mês) com o mês default derivado, sem effect. 3. A CATEGORIZAÇÃO QUICAVA esqueleto → tabela vazia com 0% → esqueleto → tabela: os effects de ano e mês trocavam a queryKey depois do load. keepPreviousData + isCarregandoCategorizacao (que inclui o vão entre "exercícios chegaram" e "o effect escolheu o ano") + atenuar in-place na troca. 4. `aba` era setState-em-effect (estado derivado disfarçado de sincronização) — o lint só acusou depois que as deps viraram valores derivados de render. Virou derivação pura, removendo o abaTocada. Fidelidade: DreSkeleton genérico → espelha PeriodPicker + faixa-veredito + cartão da DRE Gerencial; PeriodPickerSkeleton é compartilhado pelas duas etapas do load (shell → aba) pra a transição não trocar de desenho; chips de mês 48→60px; header da categorização 64→70px; tiles da ingestão 138→146px; o trilho não promete mais o card "Aguardando distribuição" (é condicional); o tile "Aguardando você" e a identidade do cabeçalho pulsam em vez de mostrar 0/"Grupo" e corrigir depois. Gate: tsc 0 · eslint 0 erros (as 9 warnings do ResultsTab são pré-existentes, provadas contra o HEAD) · next build 0 · vitest 1323/1323. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> @
…da tela O Cockpit (home do Financeiro) carregava em QUATRO ondas encadeadas, cada uma com o seu esqueleto: escopo+cobertura do grupo (Shell) → overview do Painel → pacing/prontidão/tesouraria (view) → ABC+ciclo e iniciativas dentro do conteúdo. As duas primeiras ondas nem alimentam a tela: o Cockpit não usa o `mes` nem a cobertura, e do overview usa só o runway — que aparece na visão Análise. - Shell: o corpo do Cockpit de empresa gateia só no escopo da URL (gvm). A identidade do cabeçalho segue pulsando sozinha (é dado). Falha de escopo/cobertura não derruba mais a home. - Painel: Cockpit renderiza direto; o runway chega pulsando no seu tile (FinKpiCard ganhou `loading`) em vez de segurar a tela inteira. - View: leitura única em TanStack Query (remontagem/volta serve do cache), com ABC+ciclo e iniciativas do HTR na mesma onda. Some o "meio carregado": o card de drivers escrevia a narrativa da causa ANTES do ciclo chegar (o texto mudava embaixo do olho do dono) e o ponteiro do HTR entrava depois, empurrando a página. - Esqueleto fiel: espelha a moldura real (Card do herói + caixa do gráfico de 440px + 4 tiles com spark + card dos drivers em 2 colunas), ~796px de herói no lugar de um bloco cinza de 560 — a página não cresce mais quando o dado chega. Conhece a visão (Rota|Análise) e não promete o ponteiro do HTR, que é condicional. Mesmo tratamento no cockpit de GRUPO. - FrescorSelo reserva a pílula enquanto lê: ela dividia a linha com o toggle Rota|Análise e o empurrava ao aparecer. Gate: tsc 0 · eslint 10 err (== baseline HEAD nos mesmos arquivos, 0 novos) · next build ✓ · vitest 1323/1323. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…a o esqueleto A página tinha TRÊS ondas escondidas depois que o esqueleto saía: o snapshot do mês (seção), os contratos do cadastro (RankingContratosTable, quando o mês não tem ranking) e as taxas de cartão + transações (CardRatesSection) — as duas últimas com **spinner girando dentro do conteúdo**, e a de cartão nem existia no esqueleto: a página crescia uma seção inteira quando o dado chegava. - Leituras centralizadas em `queries.ts` com chaves compartilhadas: a seção dispara as três em paralelo e só destrava a tela quando as três voltam; os filhos leem do mesmo cache (TanStack dedupa — uma requisição só) e seguem donos do próprio refresh depois de cadastrar/editar/remover. - Esqueleto agora espelha a tela inteira, com as molduras reais (hero "Leitura do mês", os KPIs com faixa-bar e a régua "O que significa", tabela de contratos, taxas de cartão, sinais) — e os títulos de seção, a nota do grupo e a legenda dos semáforos entram JÁ ESCRITOS: são estáticos, não têm por que pulsar. - Trocar de mês mantém a tela anterior (keepPreviousData) em vez de colapsar no esqueleto; o Shell já atenua o corpo enquanto o novo mês vem. - Shell: o corpo do Endividamento não espera mais a cobertura do grupo — ele só precisa do escopo da URL e do mês âncora. Mesmo tratamento que o Cockpit ganhou. - Guardas nos filhos: se um dia montarem sem o cache quente, pulsam em vez de afirmar "nenhum contrato/taxa cadastrada" — e se desmentir logo depois. Gate: tsc 0 · eslint 0 err / 0 warn (== baseline HEAD nos mesmos arquivos) · next build ✓ · vitest 1323/1323. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
O dado do Simulador já vinha numa onda só (4 fontes em paralelo) — o problema era o esqueleto: prometia uma fileira de 3 cards que NÃO EXISTE MAIS (o antigo tripé DRE/Caixa/Meta, absorvido pela "leitura da casa") e parava no primeiro grid, cobrindo cerca de um terço da altura real. O resto da página — conta inversa, retirada segura, o caixa em barras, as 5 decisões prontas, cenários salvos — nascia de uma vez. - Esqueleto espelha a tela inteira, com as molduras reais. Como quase tudo aqui é ESTÁTICO, entra escrito: os rótulos das alavancas (e no zero os valores são "como hoje" de qualquer jeito), os títulos das seções, o cabeçalho e os nomes das linhas da DRE (reusa `LINHAS_DRE`), os títulos das 5 decisões. Pulsa só o que vem do banco. O "Lado a lado" fica de fora — é condicional (≥2 colunas). - Leitura em TanStack Query: voltar pra mesa serve do cache em vez de refazer as 4 chamadas. - Componente partido em porta (`SimuladorCasaTab`, carrega e destrava) + mesa (`MesaDeDecisao`, só monta com dado). Assim os defaults editáveis — custo/cabeça medido da folha, mês do estoque — são semeados no `useState` inicial: com um effect pós-render, o card "Contratar pessoas" piscaria custo 0 antes do valor real. - Cenários salvos deixam de ser cópia local e passam a morar no cache (salvar/excluir escrevem lá): a lista local ficaria para trás e sair-e-voltar traria a lista velha, sem o cenário recém-salvo. - Shell: o Simulador em escopo de empresa não espera mais a cobertura do grupo (só o escopo da URL) — e no agregador o esqueleto passa a ser o do picker de empresa, que é o que a tela realmente entrega ali, em vez da mesa inteira. Gate: tsc 0 · eslint 0 err / 0 warn (== baseline HEAD nos mesmos arquivos) · next build ✓ · vitest 1323/1323. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…eletos fiéis O banner D1 — "extrato de <mês> pendente, o ciclo está travado" — é o recado mais importante da tela, e só existia na Visão Geral: o painel que o alimenta só era carregado quando `activeTabId === "overview"`. Quem abrisse a página direto em ?tab=execucao (link, bookmark, F5 na aba) não via aviso nenhum. E, mesmo na Visão Geral, ele nascia depois do resto e empurrava a página pra baixo. - O painel passa a carregar sempre (é do shell, não de uma aba), e a faixa do banner fica reservada enquanto vem — não empurra mais o conteúdo. - As 4 leituras viram chaves compartilhadas em `queries.ts` (TanStack Query). A tela é feita de pular entre workspaces: antes, cada volta refazia a consulta e repintava o esqueleto. Cada aba segue dona do seu refresh — e agora invalida também o painel, porque aprovar/relatar/abortar move o funil da Visão Geral na hora. - Esqueletos espelham a moldura real, com os títulos de seção e os 5 passos do funil escritos (são estáticos): Visão Geral (herói do laudo + funil + checklist do dia 1º), Ideação (3 seções), Execução (card de teste com escopo 2×2), Resultados (chips + dossiês). Antes eram 2-3 retângulos genéricos por aba. - Visão Geral não fica mais presa no esqueleto se a leitura falhar: `!painel` agora diz que não deu, em vez de pulsar para sempre. - Relato de execução: o texto já salvo volta a aparecer no campo (era semeado no estado local pelo fetch antigo; agora vem do dado, com o rascunho local por cima). Gate: tsc 0 · eslint 0 err / 0 warn (== baseline HEAD nos mesmos arquivos) · next build ✓ · vitest 1323/1323. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
|
This pull request has been ignored for the connected project Preview Branches by Supabase. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Varredura de carregamento página a página: o esqueleto passa a refletir a tela de forma fiel, e cada página carrega numa onda só. Seis páginas, validadas uma a uma no browser pelo Lucas.
O padrão que ficou
<Card>, mesmas grades, alturas medidas do DS — não blocos cinza genéricos.Por página
Visão do Projeto (
8c8cabe) — a flagRETRATO_EMPRESAnasciafalseno cliente e a árvore trocava de forma quando o override resolvia, desmontando a aba e refazendo a leitura inteira. Corrigido comfeatureDefault()isomórfico + slots fixos.Apuração (
d5c7824) — a DRE caía no estado vazio "Sem dados no recorte" (com CTA!) enquanto as transações vinham, e repetia a cada troca de mês. O shell carregava o grupo duas vezes por entrada (mesera dependência do própriocarregar).Cockpit (
d36ed57) — quatro ondas encadeadas, duas delas sem alimentar a tela: o Cockpit não usamesnem a cobertura do grupo, e do overview usa só o runway (visível apenas na visão Análise). O card de drivers escrevia a narrativa da causa antes do ciclo chegar; o ponteiro do HTR entrava depois e empurrava a página. Herói prometia 560px para ~796 reais.Endividamento (
5b3af9b) — doisLoader2girando dentro do conteúdo já pintado (contratos do cadastro e taxas de cartão), e a seção "Taxas de cartão" inteira faltava no esqueleto. Resolvido com query-options de chave compartilhada: a mãe dispara em paralelo e gateia; os filhos leem do mesmo cache e seguem donos do próprio refresh.Simulador (
f3824c6) — o esqueleto prometia uma fileira de 3 cards que não existe mais (o antigo tripé, absorvido pela "leitura da casa") e cobria ~1/3 da altura. Componente partido em porta + mesa para semear os defaults editáveis nouseStateinicial. Cenários salvos passaram a morar no cache — cópia local ficaria para trás e sair-e-voltar traria a lista velha.Iniciativas (
c7cb9f8) — o banner "extrato pendente, ciclo travado" só existia na Visão Geral: quem abrisse direto em?tab=execucaonão via aviso nenhum, e otabestá na URL. A Visão Geral também podia ficar presa no esqueleto para sempre se a leitura falhasse.Fora de escopo
Caixa & Projeção, Resultado, Capital de giro e Pessoas ficaram de fora (páginas ainda não prontas). O spinner de auth do
PageLayoutfica como está — decisão do Lucas.Gate
tsc0 ·eslint0 novos (comparado contra HEAD nos mesmos arquivos, a cada commit) ·next build✓ ·vitest1323/1323 · zero migration.🤖 Generated with Claude Code