Register fill-in to replace the priority badge with an icon+tooltip on the municipalities list.

This commit is contained in:
Francisco Ignácio Fontoura Solla 2026-07-24 18:25:36 -03:00
parent 6523824b3a
commit 4cda9ad86a
2 changed files with 109 additions and 2 deletions

View file

@ -0,0 +1,106 @@
# Ícone de prioridade na lista de Municípios
Status: rascunho
Atualizado em: 2026-07-24
Item do roadmap: [docs/roadmap.md](../roadmap.md) (Fill-ins)
Impeccable: B — encaixe em `MunicipalityList` (`/campanha/municipios`); sem rota nova
Appetite: ~0,25 dia eng; troca Badge→ícone+tooltip na coluna do nome; sem migration
Responsável: —
## Design (Impeccable)
Âncoras: `PRODUCT.md` (princípio 2 — clareza sob pressão) / `DESIGN.md` (register `product`; Field Desk) · tema `data-theme='campaign'` · shell `MunicipalityList` + shadcn `Tooltip` (`src/components/ui/tooltip.tsx`).
Na implementação (`implement-roadmap-item`): craft compacto → critique → polish (só affordance de prioridade na lista; sem redesign da tabela).
Brief compacto:
- **Persona / contexto:** Assessor / CG varre a lista densa de municípios; o chip “Prioritária” compete com o nome e ocupa largura na coluna.
- **Job principal:** reconhecer de relance quais linhas são prioritárias, sem ler um badge de texto; confirmar o significado no hover.
- **Estratégia de cor:** Restrained — ícone com tom de ênfase do tema (`text-primary` ou equivalente ao `Badge destructive` atual), sem segundo sistema de chips.
- **Edit where you see:** não — prioridade continua mutável só no form/estratégia (`MunicipalityStrategyForm` / card); lista só sinaliza.
- **Anti-goals:** segundo badge colorido; tooltip em toda a célula do nome; Popover “?” (`CampaignInfoHint`) para um flag binário; redesign do card de estratégia neste item.
## Dados → decisão → apresentação
Dados: N/A — este item **não** muda métricas, agregação nem o significado de `priority`; só a affordance visual do flag já exibido (`alta` → chip). Filtro `?priority=alta` e labels em forms/overview permanecem.
## Contexto
Em `/campanha/municipios` (staff), `MunicipalityList` (`src/components/campaign/MunicipalityList.tsx`) mostra, ao lado do nome na coluna da tabela desktop **e** no card mobile, um `Badge variant="destructive"` com o texto de `municipalityPriorityLabels.alta` (“Prioritária”) quando `municipality.priority === 'alta'`. A lista é Server Component; o chip é só leitura.
Pedido de produto (2026-07-24): na coluna do município da tabela, trocar o chip por um **ícone** que indique prioridade + **tooltip no hover** com o texto **“Município prioritário”** (ortografia correta; tipografia do pedido tinha “Muncípio”).
`MunicipalityList` já importa ícones Lucide (`CircleAlertIcon` / `CircleCheckIcon` na cobertura). Existe `Tooltip` shadcn client-only; o único uso de produto hoje é o `Sidebar`. `CampaignInfoHint` é Popover touch-friendly para “?” — padrão errado para flag binário.
## Objetivos
- Staff em `/campanha/municipios`: quando `priority === 'alta'`, na coluna do nome (tabela desktop) **e** no header do card mobile do mesmo componente, renderizar ícone + tooltip “Município prioritário” em vez do `Badge` “Prioritária”.
- Acessibilidade: `aria-label` (ou equivalente) no trigger com o mesmo texto do tooltip — hover não é a única via.
- Guardrails: sem migration, sem collection, sem Consent, sem server action; semântica `priority` / filtro / forms intactos; `leader` não vê o sinal (já gated por `isStaffView`).
## Decisões travadas
- **Fill-in com plano próprio (não ID B novo; não absorver só em R6).** Polish cosmético, ~¼ dia, paralelizável, cortável. (2026-07-24, classificação roadmap-item.) **Rejeitado:** B16 de trilha (infla grafo); só R6 (atrasa quick win no critique largo); fase informal sem plano (precedente fill-in: Cenário junto aos filtros).
- **Ícone Lucide `Flag` (ou `FlagIcon`) ao lado do link do nome.** Sinal de prioridade sem competir com “favorito” / alerta de cobertura. **Rejeitado:** `Star` (lê como favorito); `CircleAlert` (já usado na coluna Cobertura); manter Badge de texto (pedido explícito); `title=` nativo sem Tooltip (UX inconsistente com shadcn).
- **Client island mínima** (ex. `MunicipalityPriorityIndicator.tsx` `'use client'`) usada nos 2 loci de `MunicipalityList` (tabela + card). Lista permanece Server Component. **Rejeitado:** `'use client'` em todo `MunicipalityList`; `title` só no SSR; abstrair shared `PriorityChip` genérico (<3 call sites fora desta lista).
- **Copy fixa: “Município prioritário”.** Não reusar o label curto “Prioritária” do Badge/filtro. **Rejeitado:** “Prioritária” no tooltip (pedido de produto); tipografia “Muncípio”.
- **Escopo = só lista (`MunicipalityList`).** Card de estratégia no detalhe (`MunicipalityStrategyCard`) mantém Badge por enquanto. **Rejeitado:** unificar todas as superfícies de `priority` neste item (estoura appetite e mistura leitura de lista com card de estratégia).
- **i18n e naming** (AGENTS.md): identificador inglês (`MunicipalityPriorityIndicator`); string visível pt-BR “Município prioritário”.
## Questões em aberto
- **Cor do ícone: `text-primary` (Signal Red do tema) vs. herdar o tom do `Badge destructive`?** **Opções:** A) `text-primary` | B) classes alinhadas ao destructive | C) `text-muted-foreground`. **Recomendação:** **A** — ênfase Field Desk sem reintroduzir um chip vermelho cheio. _(assumido — validar no craft/critique)_
- **Touch / mobile: tooltip Radix é hover — basta `aria-label` no ícone no card?** **Opções:** A) só aria-label no mobile | B) Popover on tap | C) texto curto visível no card. **Recomendação:** **A** — pedido é hover na tabela; card já é denso; Popover seria overkill. _(assumido)_
## Abordagem proposta
```mermaid
flowchart LR
list["MunicipalityList RSC"] --> name["Link nome"]
list --> island["MunicipalityPriorityIndicator client"]
island --> icon["Flag Lucide"]
island --> tip["Tooltip shadcn"]
tip --> copy["Município prioritário"]
```
Componentes:
- **`MunicipalityPriorityIndicator`** (novo, `src/components/campaign/MunicipalityPriorityIndicator.tsx`, `'use client'`): renderiza trigger (botão ou `span` com `asChild` conforme padrão shadcn) com ícone `Flag`, `aria-label="Município prioritário"`, envolvido em `TooltipProvider` local (ou provider pai se já houver) + `Tooltip` / `TooltipTrigger` / `TooltipContent` com o mesmo texto. Props mínimas (sem view-model).
- **`MunicipalityList`** (`src/components/campaign/MunicipalityList.tsx`): nos dois ramos `priority === 'alta' && isStaffView`, trocar `<Badge…>` por `<MunicipalityPriorityIndicator />`; remover import de `Badge` / `municipalityPriorityLabels` se ficarem órfãos neste arquivo.
- **Migration**: Sem migration, sem collection, sem server action.
Depth check: reusa `tooltip.tsx` e Lucide já no produto; um island local (&lt;3 call sites) — sem helper shared prematuro.
## Dependências
- Nenhuma de outro plano aberto. Reusa `priority` / `isStaffView` já no loader/VM e o `Tooltip` shadcn existente.
## Não escopo
- Badge de prioridade em `MunicipalityStrategyCard` / form de edição / filtro “Prioritárias” — permanecem texto.
- Coluna dedicada “Prioridade” ou sort por `priority` (B15 rejeitou sort sem coluna; filtro `?priority=` basta).
- Rename do header “Praça” → “Município” (débito de copy da remodelagem / R6).
- Mudança de semântica `alta|normal` ou seed E4R.
## Rabbit holes
- **Popover touch “completo” / `CampaignInfoHint`.** Explode um “?” genérico para flag binário. **Mitigação:** Tooltip + `aria-label`; defer Popover só se critique R6 mostrar falha de descoberta no mobile.
- **Componente shared de prioridade em todo `/campanha`.** Classitis com 1–2 call sites. **Mitigação:** island só na lista; unificar quando o 3º call site aparecer (ex. se StrategyCard pedir o mesmo ícone).
- **Tooltip no link inteiro do nome.** Atrapalha clique/navegação e a11y. **Mitigação:** trigger só no ícone.
## Adiado com gatilho
- **Mesmo ícone+tooltip no `MunicipalityStrategyCard`.** Revisitar quando: R6 critique o card de estratégia ou produto pedir paridade lista↔detalhe.
- **Popover on-tap no card mobile.** Revisitar quando: evidência de campo de que staff não entende o Flag sem hover (improvável no desktop-first da lista).
## Referências
- `docs/roadmap.md` (Fill-ins abertos)
- `src/components/campaign/MunicipalityList.tsx` — Badge atual (mobile ~L80–82; desktop ~L171–173)
- `src/components/ui/tooltip.tsx` — primitivo a reusar
- `src/utilities/municipalityUi.ts` — `municipalityPriorityLabels` (forms/filtro; não necessariamente o tooltip)
- `src/components/campaign/MunicipalityStrategyCard.tsx` — Badge fora de escopo
- [cenario-junto-filtros-municipios.md](cenario-junto-filtros-municipios.md) — precedente de fill-in Impeccable B na mesma vertical
- AGENTS.md — naming; staff vs leader
- `PRODUCT.md` / `DESIGN.md` — Field Desk, clareza sob pressão

View file

@ -1,6 +1,6 @@
# Roadmap — Teqo
Atualizado em: 2026-07-24 (B15 ordenação por coluna na lista; fill-in Cenário junto aos filtros — [plano](plans/cenario-junto-filtros-municipios.md); E4R ✓; E17 ✓ tabela TI no Início; B14; janela 1: smoke, A11, B15, R6, E8)
Atualizado em: 2026-07-24 (fill-in ícone+tooltip de prioridade na lista — [plano](plans/icone-prioridade-lista-municipios.md); B15; fill-in Cenário junto aos filtros; E4R ✓; E17 ✓; B14; janela 1: smoke, A11, B15, R6, E8)
Registro canônico dos **próximos** planos e débitos. Histórico de entregas: resumo abaixo + planos em [`docs/plans/`](plans/) + notebook [`.cursor/rules/projects/nucleos-eleitorais.mdc`](../.cursor/rules/projects/nucleos-eleitorais.mdc).
## Âncoras do calendário eleitoral 2026 (Res. TSE 23.760/2026)
@ -87,6 +87,7 @@ O discovery literatura→persona→entrevista ([relatório aprovado](research/re
### Fill-ins abertos
- **Ícone de prioridade na lista** em `/campanha/municipios` — trocar Badge “Prioritária” por ícone Flag + tooltip “Município prioritário” (hover) na coluna do nome · ~0,25d · Impeccable B · [plano](plans/icone-prioridade-lista-municipios.md)
- **Cenário junto aos filtros** em `/campanha/municipios` — mover `VoteEstimateScenarioField` para a fileira de `MunicipalityFilters`; overview só consome o contexto · ~0,25–0,5d · Impeccable B · [plano](plans/cenario-junto-filtros-municipios.md)
- **O0+** escala/DRY pós-Onda 0 · [plano](plans/escala-dry-pos-onda0.md)
- **RS+** auth read leve + shells de senha · [plano](plans/escala-dry-pos-reset-senha-perfil.md)
@ -159,7 +160,7 @@ flowchart TD
B8F2 -.ZE Salvador.-> B14n
```
Paralelizáveis agora: **B15** (sort por coluna na lista; barato, desbloqueia UX de A11), **A11** (semana de onboarding; E4R ✓ seedou o quadro; A11 soft-dep B15), **E8** (A10 ✓ e remodelagem em produção), **C12** (paralelo a E8), **E16** (compõe o existente), **B14** (atalho geo no Início; soft B8 F2 só para ZE Salvador), fill-ins (Cenário junto aos filtros, O0+, RS+). **D3** só após smoke + folga e só se o fluxo sede-digita (C12) não absorver os deltas do ZAP (não compete com E8/E9).
Paralelizáveis agora: **B15** (sort por coluna na lista; barato, desbloqueia UX de A11), **A11** (semana de onboarding; E4R ✓ seedou o quadro; A11 soft-dep B15), **E8** (A10 ✓ e remodelagem em produção), **C12** (paralelo a E8), **E16** (compõe o existente), **B14** (atalho geo no Início; soft B8 F2 só para ZE Salvador), fill-ins (ícone de prioridade na lista, Cenário junto aos filtros, O0+, RS+). **D3** só após smoke + folga e só se o fluxo sede-digita (C12) não absorver os deltas do ZAP (não compete com E8/E9).
### Sequência por janela (só pendentes)