mirror of
https://github.com/fsolla/teqo.git
synced 2026-11-13 15:13:07 +00:00
docs(plans): register B109–B111 mobile drawer and Início polish
Capture confirmed product feedback as trackable plans linked to #148–#150.
This commit is contained in:
parent
97f7423f81
commit
1a4b5b6273
3 changed files with 383 additions and 0 deletions
150
docs/plans/bottom-drawer-busca-fullscreen-polimento.md
Normal file
150
docs/plans/bottom-drawer-busca-fullscreen-polimento.md
Normal file
|
|
@ -0,0 +1,150 @@
|
|||
# Bottom drawer — polimento dock + busca fullscreen + excluir entidade atual
|
||||
|
||||
Status: registrado
|
||||
Atualizado em: 2026-08-01
|
||||
Issue: #148
|
||||
Priority: P1
|
||||
Model: composer-2.5
|
||||
Impeccable: C — chrome `CampaignQuickActionsDrawer` (geometria dock + modo busca)
|
||||
Appetite: ~1–1,5d eng; snap + CSS botões + filtro de hits; sem migration
|
||||
Responsável: —
|
||||
|
||||
## Design (Impeccable)
|
||||
|
||||
Âncoras: `PRODUCT.md` (Clarity under pressure; Feel the action; Continuity) / `DESIGN.md` · B79/B91/B100/B105 · Início `focused` (B65) · tema `data-theme='campaign'`.
|
||||
|
||||
Na implementação (`work-issue`): craft compacto → critique → polish (viewport ~390; detalhe município + lista).
|
||||
|
||||
Brief compacto:
|
||||
|
||||
- **Persona / contexto:** CG/assessor no celular **fora do Início** — dock para ações + busca; ao digitar/focar a busca, precisa de tela inteira sem o strip competindo.
|
||||
- **Job principal:** (1) ler rótulos das ações sem corte; (2) busca com dock apertado na base; (3) ao focar a busca, drawer sobe cobrindo o header, só handle + input + resultados; (4) não sugerir/listar a entidade da página atual.
|
||||
- **Estratégia de cor:** Restrained.
|
||||
- **Edit where you see:** não — launchers / navegação.
|
||||
- **Anti-goals:** scrim modal no dock idle; segundo FAB; redesenhar catálogos B80–B90; wizard return (→ **B110**); polish do Início (→ **B111**).
|
||||
|
||||
### Wireframe (texto)
|
||||
|
||||
**1) Dock idle (não-Início):**
|
||||
|
||||
```text
|
||||
┌─ /campanha/municipios/foo ─────────────────────┐
|
||||
│ header + conteúdo │
|
||||
├─ drawer DOCK ──────────────────────────────────┤
|
||||
│ ═ handle │
|
||||
│ [● Ajustar] [● Mudar] [● …] ← labels 2 linhas │
|
||||
│ tendência cabe inteira; botão um pouco +largo│
|
||||
│ ┌ Buscar na campanha ────────────────────────┐ │
|
||||
│ └────────────────────────────────────────────┘ │
|
||||
│ ← gap curto até safe-area / bottom │
|
||||
└────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
**2) Busca focada / ativa (fullscreen):**
|
||||
|
||||
```text
|
||||
┌─ drawer FULL (cobre header) ───────────────────┐
|
||||
│ ═ handle │
|
||||
│ ┌ Buscar na campanha ────────────────────────┐ │
|
||||
│ └────────────────────────────────────────────┘ │
|
||||
│ Sugestões / resultados (sem a entidade atual) │
|
||||
│ … │
|
||||
│ … │
|
||||
└────────────────────────────────────────────────┘
|
||||
Fora: strip de ações oculto; página atrás opaca
|
||||
(não-modal continua — sem scrim que bloqueie? ver Decisões).
|
||||
```
|
||||
|
||||
## Dados → decisão → apresentação
|
||||
|
||||
Dados: N/A como métrica nova — hits de `POST /campanha/home-search` já existentes; só **filtro de exclusão** da entidade do contexto.
|
||||
|
||||
## Contexto
|
||||
|
||||
Pós **B100/B105** o drawer tem dock + collapsed + labels `line-clamp-2`. Feedback de campo (2026-08-01):
|
||||
|
||||
1. **Gap** entre a barra de busca e o fundo da tela **grande demais** no dock.
|
||||
2. Labels cortados na horizontal (ex. “Mudar tendênci”) — `CampaignHomeActionButton` fixa `w-[4.75rem]`.
|
||||
3. Foco na busca deve espelhar o ritual do Início (`CampaignHomeLayout` `focused`): strip some, superfície sobe — mas no drawer precisa **cobrir o header** também.
|
||||
4. Empty state / resultados ainda incluem a entidade da página atual (município/liderança/assessor/…), o que é ruído quando já se está nela.
|
||||
|
||||
## Objetivos
|
||||
|
||||
- Reduzir o espaçamento vertical **busca → bottom** no snap dock (gap do stack + padding do handle / safe-area); dock continua a caber strip + busca.
|
||||
- Largura dos botões da strip **o suficiente** para o maior rótulo do catálogo em **duas linhas**, centralizado; retirar padding horizontal residual do controle se ainda existir; sem encolher hit target do círculo (<44 px).
|
||||
- Ao **focus** do input de busca (e enquanto `uiFocused` / query ativa): snap **fullscreen** (`1` / `100dvh` — pin no craft); **ocultar** a strip de ações; sheet cobre o viewport inclusive `CampaignMobileTopBar`.
|
||||
- Ao blur com query vazia / clear: voltar ao dock (ou collapsed se o scroll da página já tiver recolhido — ver Questões).
|
||||
- Filtrar sugestões e resultados da busca para **excluir** a entidade do `CampaignQuickActionContext` da rota atual (slug/id por tipo).
|
||||
- Guardrails: sem migration / Consent / escrita; Início fora deste drawer; leader lockdown intacto.
|
||||
- **Tracer bullet:** e2e mobile em `/campanha/municipios/[slug]` — dock com label “Mudar tendência” legível → focus busca → strip ausente + handle no topo do viewport → hit do município atual **não** aparece nas sugestões.
|
||||
|
||||
## Decisões travadas
|
||||
|
||||
- **3º snap `full` só sob busca focada/ativa; idle continua dock|collapsed (B100).** Espelha Início `focused`. **Rejeitado:** sempre full; crescer só o dock sem snap novo (não cobre header de forma confiável).
|
||||
- **Fullscreen não-modal (sem bloquear pointer na página) no appetite v1 — sheet cobre visualmente o chrome.** Overlay `modal={false}` já é o contrato B79; se o critique exigir scrim no full, Adiado. **Rejeitado:** tornar o drawer modal só no focus (muda a família de gesto / dismiss).
|
||||
- **Exclusão client-side nos grupos de resultado + payload suggest, keyed pelo contexto da página** (`municipalitySlug` / `leadershipId` / `organizationSlug` / `activitySlug` / `demandSlug` / advisor id se houver). **Rejeitado:** mudar o ranking server-side do home-search neste item (blast maior; Início não precisa excluir “si mesmo”).
|
||||
- **Botão: aumentar `w-*` (ou `min-w`) o mínimo que caiba “Mudar tendência” / “Atualizar liderança” em 2 linhas; não multi-width por label.** **Rejeitado:** `w-auto` solto (quebra snap/pan da strip); fonte menor.
|
||||
- **Item novo (B109), não reabrir B105/B100.** Continuação de polimento. **Rejeitado:** editar só as-built antigo sem Issue.
|
||||
- **i18n:** ids `full` snap / `excludeCurrentEntity`; copy pt-BR intacta.
|
||||
|
||||
## Questões em aberto
|
||||
|
||||
- **Após blur da busca com query vazia, voltar a qual snap?** **Opções:** A) sempre dock | B) dock se `scrollTop` baixo, senão collapsed. **Recomendação:** **B** — respeita o ritual B100 de leitura. _(assumido)_
|
||||
- **Excluir também visitados recentes / geo suggest quando forem a entidade atual?** **Opções:** A) sim, qualquer hit com o mesmo id/slug | B) só grupo “Sugestões” server. **Recomendação:** **A**. _(assumido)_
|
||||
|
||||
## Abordagem proposta
|
||||
|
||||
```mermaid
|
||||
flowchart TB
|
||||
Focus["input focus / uiFocused"] --> Full["snap FULL"]
|
||||
Full --> Hide["strip hidden"]
|
||||
Full --> Cover["sheet cobre header"]
|
||||
Ctx["QuickActionContext"] --> Filter["excludeCurrentEntity(hits)"]
|
||||
Filter --> Groups["HomeSearch*Group"]
|
||||
Dock["snap DOCK"] --> Gap["menos gap busca↔bottom"]
|
||||
Dock --> Width["ActionButton w- maior"]
|
||||
```
|
||||
|
||||
Componentes:
|
||||
|
||||
- **`campaignQuickActionSnap.ts`**: adicionar `QUICK_ACTIONS_SNAP_FULL`; helpers `quickActionsSnapIsFull` / `isDock`.
|
||||
- **`CampaignQuickActionsDrawer.tsx`**: reagir a `uiFocused` (já em `HomeSearchContext` no host) → `setSnapPoint(FULL)`; ocultar strip; ordem visual handle → busca → resultados no full; apertar padding/gap no dock.
|
||||
- **`CampaignQuickActionsHost` / scroll peek**: peek height no full = full viewport (ou não reservar padding absurdo no content scroll enquanto full).
|
||||
- **`CampaignHomeActionButton.tsx`**: largura do controle; pin visual/unit se houver snapshot de classe.
|
||||
- **Filtro:** helper puro `excludeHomeSearchHitForContext(hit, context)` em `lib/`; aplicar nos grupos ou no merge do `HomeSearchResultsContext` quando montado sob o drawer (prop/`data-exclude` via provider leve). Evitar poluir o Início.
|
||||
- **Migration:** Sem migration, sem collection, sem server action nova.
|
||||
|
||||
## Dependências
|
||||
|
||||
- Soft: B100 ✓, B105 ✓, B91 ✓, B79 ✓. Nenhuma dura.
|
||||
- Paralelo: **B110** (return path wizard), **B111** (Início strip/delta) — sem `depends` duro.
|
||||
|
||||
## Não escopo
|
||||
|
||||
- Redirect pós-wizard → **B110**.
|
||||
- Faixas brancas / delta flat do Início → **B111**.
|
||||
- Redesign do catálogo de ações / novos verbos.
|
||||
- Busca leader / rotas fora do drawer staff.
|
||||
|
||||
## Rabbit holes
|
||||
|
||||
- **Reescrever o primitivo `Drawer.tsx` para todos os sheets.** Mitigação: override só no chassis quick-actions; Base UI snap já usado.
|
||||
- **Segundo `HomeSearchProvider` / fork do suggest API.** Mitigação: filtro no client com contexto já sincronizado.
|
||||
- **Animar header aparte do snap.** Mitigação: cobrir com o sheet; não esconder o top bar via layout.
|
||||
|
||||
## Adiado com gatilho
|
||||
|
||||
- **Scrim no snap full.** Revisitar se critique de campo disser que o conteúdo atrás distrai durante a busca.
|
||||
- **Exclusão server-side no `home-search`.** Revisitar se o payload vier grande demais para filtrar no client.
|
||||
|
||||
## Referências
|
||||
|
||||
- GitHub Issue #148 (spec + frontmatter `id/depends/priority/model`)
|
||||
- `src/components/campaign/shell/CampaignQuickActionsDrawer.tsx` — chassis
|
||||
- `src/lib/campaignQuickActionSnap.ts` — snaps
|
||||
- `src/components/campaign/dashboard/CampaignHomeActionButton.tsx` — `w-[4.75rem]`
|
||||
- `src/components/campaign/dashboard/CampaignHomeLayout.tsx` — precedente `focused`
|
||||
- `src/lib/campaignQuickActionContext.ts` — entidade atual
|
||||
- `docs/plans/bottom-drawer-peek-acoes-busca.md` (B100), `bottom-drawer-handle-scroll-peek.md` (B105)
|
||||
- AGENTS.md — Campaign auth; naming EN / copy pt-BR
|
||||
- `PRODUCT.md` / `DESIGN.md` — Field Desk / Continuity
|
||||
117
docs/plans/inicio-strip-bleed-delta-flat.md
Normal file
117
docs/plans/inicio-strip-bleed-delta-flat.md
Normal file
|
|
@ -0,0 +1,117 @@
|
|||
# Início — strip edge-to-edge de verdade + delta flat silencioso
|
||||
|
||||
Status: registrado
|
||||
Atualizado em: 2026-08-01
|
||||
Issue: #150
|
||||
Priority: P1
|
||||
Model: composer-2.5
|
||||
Impeccable: B — `CampaignHomeLayout` / `CampaignHomeSummary`
|
||||
Appetite: ~0,25–0,5d eng; CSS overflow + conditional delta; sem migration
|
||||
Responsável: —
|
||||
|
||||
## Design (Impeccable)
|
||||
|
||||
Âncoras: `PRODUCT.md` / `DESIGN.md` · B57 delta · B99/B101 bleed · tema `campaign`.
|
||||
|
||||
Na implementação: craft compacto → critique → polish (iPhone estreito).
|
||||
|
||||
Brief:
|
||||
|
||||
- **Persona:** CG no Início mobile — strip deve nascer na borda; Δ só quando houve movimento.
|
||||
- **Job principal:** (1) zero “trilho” branco nas laterais da strip; (2) sem traço/zero quando Δ = 0 nos últimos 7 dias.
|
||||
- **Anti-goals:** mexer no drawer não-Início (**B109**); redesenhar o bloco de cobertura.
|
||||
|
||||
### Wireframe (texto)
|
||||
|
||||
```text
|
||||
┌─ /campanha mobile ─────────────────────────────┐
|
||||
│ Votos estimados │
|
||||
│ 12.345 ← sem “−” / “0” / — │
|
||||
│ quando Δ flat │
|
||||
│ (se Δ≠0: ↑ 120 / ↓ 80 + “nos últimos 7 dias”)│
|
||||
│ │
|
||||
│[●][●][●][●]… →→→ ← cola nas bordas L/R │
|
||||
│ ▲ sem faixa branca lateral │
|
||||
│ ┌ Buscar … ──────────────────────────────────┐ │
|
||||
└────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
## Dados → decisão → apresentação
|
||||
|
||||
- **Vou apresentar dados?** Sim — o Δ 7d (**B57**) já existe; este item só muda a **forma no estado flat**.
|
||||
- **Decisões desbloqueadas:** CG: “houve movimento na semana?” — se não, não ocupar o campo visual com ruído.
|
||||
- **Forma escolhida:** seta + magnitude **somente** se `delta !== 0 && delta !== null`; flat e unavailable → **omitir** o chip inteiro (e a linha “nos últimos 7 dias”). **Rejeitado:** manter `MinusIcon` / “0” / em-dash como “sinal de estabilidade” (produto pediu vazio).
|
||||
- **Profile:** escalar assinado já carregado em `homeSummaryDelta`.
|
||||
- **Anti-goals de dado:** não inventar sparkline; não mudar a janela de 7 dias.
|
||||
|
||||
## Contexto
|
||||
|
||||
**Bleed (B99/B101):** `CampaignHomeLayout` já aplica `-mx-4 w-[calc(100%+2rem)]` em `home-actions`, mas o wrapper `HomeChromeRetractionShell` usa **`overflow-hidden`** no filho interno (necessário à animação de retraction). Isso **clipa** o bleed e deixa as faixas do `p-4` do `CampaignContentScroll` visíveis como “barras brancas” laterais. Diagnóstico preferido vs “margin na strip” ou `overflow: visible` solto no scroller.
|
||||
|
||||
**Delta (B57):** `HomeSummaryDelta` renderiza `MinusIcon` + magnitude `"0"` quando `delta === 0`, e `"—"` quando `null`. Produto (2026-08-01): no estado **sem mudança**, **não mostrar nada**.
|
||||
|
||||
## Objetivos
|
||||
|
||||
- Strip de ações no Início mobile **visualmente edge-to-edge** (primeiro/último círculo na borda ou com peek de pan, sem gutter branco do padding da página).
|
||||
- Quando `homeSummaryDelta === 0` **ou** `null`: não renderizar o span do Δ nem o caption do período; manter só o total.
|
||||
- Quando `delta > 0` / `< 0`: setas + magnitude + caption inalterados.
|
||||
- Unit: pins em `campaignHomeSummaryDelta` / render helper; layout pin se existir spec de classes.
|
||||
- Guardrails: sem migration; desktop `md:` pode manter gutter; pan B67 intacto.
|
||||
|
||||
## Decisões travadas
|
||||
|
||||
- **Corrigir o clip do bleed (overflow na shell de retraction), não remover `p-4` da página.** **Rejeitado:** `p-0` global; `overflow: visible` cego no `campaign-content-scroll` (risco de spill horizontal da página).
|
||||
- **Técnica recomendada:** tirar `overflow-hidden` do wrapper interno **só** do slot `home-actions-chrome` (ou estrutura em duas camadas: clip só na animação de altura, não no eixo X do bleed); validar que a retraction `grid-rows` continua sem flash. **Rejeitado:** duplicar a strip fora do scroll.
|
||||
- **Flat/unavailable = omitir UI do Δ** (não `Minus` / não `—` / não `0`). **Rejeitado:** traço como “estável”; sr-only com magnitude zero (desnecessário se não há chip).
|
||||
- **Item novo (B111), continuação de B99/B57 — não reabrir Issues fechadas.**
|
||||
- **i18n:** helpers existentes; copy do período só quando Δ ≠ 0.
|
||||
|
||||
## Questões em aberto
|
||||
|
||||
- **Unavailable (`null`, sem histórico 7d): também omite?** **Opções:** A) omitir igual ao flat | B) mostrar “—” só nesse caso. **Recomendação:** **A** — produto pediu vazio na ausência de mudança útil; buraco de histórico ≠ seta. _(assumido)_
|
||||
|
||||
## Abordagem proposta
|
||||
|
||||
```mermaid
|
||||
flowchart TB
|
||||
Shell["home-actions-chrome"] --> Bleed["-mx-4 sem clip X"]
|
||||
Bleed --> Strip["CampaignHomeActionStrip"]
|
||||
Delta["homeSummaryDelta"] -->|!==0| Chip["seta + mag + caption"]
|
||||
Delta -->|0 ou null| Hide["não renderiza"]
|
||||
```
|
||||
|
||||
Componentes:
|
||||
|
||||
- **`CampaignHomeLayout.tsx`**: ajustar `HomeChromeRetractionShell` / slot actions para permitir bleed horizontal.
|
||||
- **`CampaignHomeSummary.tsx`**: early-return em `HomeSummaryDelta` quando flat/unavailable; condicionar caption.
|
||||
- **`campaignHomeSummaryDelta.ts`**: opcional helper `shouldShowHomeSummaryDelta(delta)`; atualizar aria tests.
|
||||
- **Migration:** Sem migration.
|
||||
|
||||
## Dependências
|
||||
|
||||
- Soft: B57 ✓, B99 ✓, B101 ✓. Nenhuma dura.
|
||||
|
||||
## Não escopo
|
||||
|
||||
- Drawer não-Início → **B109**.
|
||||
- Wizard return → **B110**.
|
||||
- Mudar fórmula do snapshot / janela 7d.
|
||||
|
||||
## Rabbit holes
|
||||
|
||||
- **Refatorar retraction para Framer/WAAPI.** Mitigação: CSS grid rows já funciona; só isolar overflow.
|
||||
- **Recalcular Δ no client.** Mitigação: só apresentação.
|
||||
|
||||
## Adiado com gatilho
|
||||
|
||||
- **Caption “sem variação” em tooltip no total.** Revisitar se acessibilidade pedir explicação sem chip visível.
|
||||
|
||||
## Referências
|
||||
|
||||
- GitHub Issue #150 (spec + frontmatter `id/depends/priority/model`)
|
||||
- `src/components/campaign/dashboard/CampaignHomeLayout.tsx` — `-mx-4` + `overflow-hidden`
|
||||
- `src/components/campaign/dashboard/CampaignHomeSummary.tsx` — `MinusIcon` / `—`
|
||||
- `src/lib/campaignHomeSummaryDelta.ts`
|
||||
- `docs/plans/strip-acoes-edge-gap-inicio.md` (B99), `delta-7-dias-estimativa-inicio.md` (B57)
|
||||
- AGENTS.md — naming
|
||||
- `PRODUCT.md` / `DESIGN.md`
|
||||
116
docs/plans/wizard-retorno-pagina-origem.md
Normal file
116
docs/plans/wizard-retorno-pagina-origem.md
Normal file
|
|
@ -0,0 +1,116 @@
|
|||
# Wizard — ao terminar, voltar à página de origem (não ao Início)
|
||||
|
||||
Status: registrado
|
||||
Atualizado em: 2026-08-01
|
||||
Issue: #149
|
||||
Priority: P1
|
||||
Model: composer-2.5
|
||||
Impeccable: B — navegação pós-cadeia nos wizards `/campanha/acoes`
|
||||
Appetite: ~0,5–1d eng; query `from` allowlisted + `wizardChainContinueHref`; sem migration
|
||||
Responsável: —
|
||||
|
||||
## Design (Impeccable)
|
||||
|
||||
Âncoras: `PRODUCT.md` (Continuity; Ação → Local → Quem) / `DESIGN.md` · B98 cadeia · B75/B96 chrome · tema `campaign`.
|
||||
|
||||
Na implementação: craft compacto → critique → polish (fluxo município + um fluxo liderança).
|
||||
|
||||
Brief:
|
||||
|
||||
- **Persona:** staff dispara ação rápida **na página em que está** (detalhe de município, liderança, lista…).
|
||||
- **Job principal:** ao concluir (ou esgotar a cadeia B98), **voltar para essa página**, não para `/campanha`.
|
||||
- **Anti-goals:** segundo sistema de deep-link; gravar origem em cookie; mudar a matriz de encadeamento B98.
|
||||
|
||||
### Wireframe (texto)
|
||||
|
||||
```text
|
||||
/campanha/municipios/foo
|
||||
→ strip: Mudar tendência
|
||||
→ /acoes/mudar-tendencia?municipio=foo&from=/campanha/municipios/foo
|
||||
→ [cadeia B98…]
|
||||
→ fim → /campanha/municipios/foo ← não /campanha
|
||||
|
||||
/campanha (Início)
|
||||
→ mesma ação sem from (ou from=/campanha)
|
||||
→ fim → /campanha
|
||||
```
|
||||
|
||||
## Dados → decisão → apresentação
|
||||
|
||||
Dados: N/A — só navegação.
|
||||
|
||||
## Contexto
|
||||
|
||||
**B98** fechou a cadeia de ajustes e travou o fim em **Início** (`wizardChainContinueHref` → `CAMPAIGN_HOME`). Correto quando a entrada é o dock do Início. Incorreto quando a entrada é o **bottom drawer** (ou qualquer CTA) numa página de entidade: o usuário perde o contexto e precisa reencontrar o município.
|
||||
|
||||
Pedido de produto (2026-08-01): o fluxo de ação deve **sempre** redirecionar, ao final, para a página da qual foi disparado — município, liderança, assessor, lista, etc.
|
||||
|
||||
## Objetivos
|
||||
|
||||
- Propagar um **return path** allowlisted desde o href da ação rápida (e CTAs equivalentes) até o fim da cadeia / dismiss X da principal.
|
||||
- `wizardChainContinueHref` (e pontos que hoje hardcodam `CAMPAIGN_HOME` ao esgotar a fila) usam esse path; default permanece Início quando ausente/inválido.
|
||||
- X / cancel da **principal** também volta à origem (não só “sucesso”).
|
||||
- Unit pins: fim com `from` → origem; sem `from` → Início; `from` fora da allowlist → Início (fail-closed).
|
||||
- Guardrails: sem migration; access intacto; open-redirect impossível (só paths internos `/campanha/...`).
|
||||
|
||||
## Decisões travadas
|
||||
|
||||
- **Query `from` (path absoluto interno allowlisted), não `sessionStorage`.** Sobrevive a refresh e é auditável na URL; B98 já usa query (`entry`, `municipio`). **Rejeitado:** só “se tem `municipio=` voltar ao detalhe” (falha em liderança/lista/assessor sem município); `document.referrer` (frágil cross-flow).
|
||||
- **Allowlist:** pathname sob `/campanha` que **não** seja `/campanha/acoes/*` nem auth (`login`, `convite`, …) — helper puro `parseWizardReturnPath`. **Rejeitado:** qualquer string; URLs absolutas externas.
|
||||
- **Supersede o “Fim: Início” do B98 quando `from` presente; Início continua o default.** **Rejeitado:** reabrir a matriz de elos; tela intermediária de sucesso obrigatória.
|
||||
- **Quick actions / registry:** ao montar `href` com contexto de página, anexar `from=pathname` (pathname atual). Entrada pelo Início omite ou seta `/campanha`.
|
||||
- **i18n:** `WIZARD_RETURN_PATH_QUERY_KEY = 'from'`; ids EN.
|
||||
|
||||
## Questões em aberto
|
||||
|
||||
- **Pular o último elo da cadeia: ainda honra `from`?** **Opções:** A) sim | B) Início. **Recomendação:** **A** — “terminar o ritual” = origem. _(assumido)_
|
||||
- **Demandas / fluxos fora da cadeia B98?** **Opções:** A) mesmo `from` no redirect final | B) só cadeia. **Recomendação:** **A** onde já redirecionam para Início. _(assumido)_
|
||||
|
||||
## Abordagem proposta
|
||||
|
||||
```mermaid
|
||||
flowchart LR
|
||||
Page["pathname atual"] --> Href["action href + from"]
|
||||
Href --> Chain["elos B98 (propagam from)"]
|
||||
Chain -->|fila vazia| Ret["parseWizardReturnPath(from) ?? HOME"]
|
||||
X["dismiss X principal"] --> Ret
|
||||
```
|
||||
|
||||
Componentes:
|
||||
|
||||
- **`src/lib/campaignActionRoutes.ts`**: constante da query; `appendWizardReturnPath` / `parseWizardReturnPath` (allowlist).
|
||||
- **`src/lib/wizardActionChain.ts`**: `wizardChainContinueHref(..., returnPath?)` — fim = returnPath ?? HOME; propagar `from` nos hrefs dos elos.
|
||||
- **Registry / quick action builders** (`campaignQuickAction*.ts`): incluir `from` a partir do pathname (passado pelo host/registry).
|
||||
- **Chrome wizard (X / skip último):** ler `from` da URL.
|
||||
- **Unit:** `wizardActionChain` + parser allowlist.
|
||||
- **Migration:** Sem migration.
|
||||
|
||||
## Dependências
|
||||
|
||||
- Soft: B98 ✓. Nenhuma dura.
|
||||
- Paralelo a **B109** / **B111**.
|
||||
|
||||
## Não escopo
|
||||
|
||||
- Polimento visual do drawer → **B109**.
|
||||
- Mudar ordem dos elos B98.
|
||||
- Deep link pós-login.
|
||||
|
||||
## Rabbit holes
|
||||
|
||||
- **Histórico `router.back()` em vez de `from`.** Mitigação: back pode sair do app / pular elos; URL explícita.
|
||||
- **Allowlist por enum de rotas.** Mitigação: prefixo `/campanha` + denylist `acoes`/auth basta neste appetite.
|
||||
|
||||
## Adiado com gatilho
|
||||
|
||||
- **Toast “Salvo — voltando a …”.** Revisitar se campo pedir confirmação verbal do destino.
|
||||
|
||||
## Referências
|
||||
|
||||
- GitHub Issue #149 (spec + frontmatter `id/depends/priority/model`)
|
||||
- `src/lib/wizardActionChain.ts` — `CAMPAIGN_HOME` no fim
|
||||
- `src/lib/campaignActionRoutes.ts` — builders de href
|
||||
- `src/lib/campaignQuickActionRegistry.ts` + providers B80–B90
|
||||
- `docs/plans/encadear-ajustes-wizard.md` (B98)
|
||||
- AGENTS.md — naming; Campaign auth
|
||||
- `PRODUCT.md` — Continuity
|
||||
Loading…
Reference in a new issue