From 31bd488c1e9d16dc397ddce768554d394ded2ded Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Francisco=20Ign=C3=A1cio=20Fontoura=20Solla?= Date: Thu, 30 Jul 2026 01:21:00 -0300 Subject: [PATCH] B66: retract home chrome on search focus with animated transition. Emends B47 so focusing the input clears strip/summary before typing; hardens hit rows against blur-before-click. --- .cursor/rules/projects/nucleos-eleitorais.mdc | 1 + docs/plans/modo-focado-busca-no-focus.md | 4 +- docs/roadmap.md | 6 +- .../campaign/dashboard/CampaignHomeLayout.tsx | 66 ++++++++++++++----- .../campaign/dashboard/HomeSearchHitRow.tsx | 4 ++ tests/e2e/campaignHomeActions.e2e.spec.ts | 25 ++++++- tests/unit/campaignHomeLayout.unit.spec.tsx | 29 +++++--- tests/unit/campaignHomeSearch.unit.spec.tsx | 31 --------- 8 files changed, 104 insertions(+), 62 deletions(-) diff --git a/.cursor/rules/projects/nucleos-eleitorais.mdc b/.cursor/rules/projects/nucleos-eleitorais.mdc index 9c1e44ff..09e8c1f5 100644 --- a/.cursor/rules/projects/nucleos-eleitorais.mdc +++ b/.cursor/rules/projects/nucleos-eleitorais.mdc @@ -7,6 +7,7 @@ alwaysApply: false ## Status +- **B66 entregue em código (2026-07-30):** modo focado da busca no **focus** (emenda B47) — `homeSearchUiFocused` (`inputFocused || query.isActive`) já no contrato/hook; overlap B68 (sugestões no focus vazio). **Nesta entrega:** `CampaignHomeLayout` retrai summary+spacer (`data-slot="home-chrome"`) e actions com grid `0fr/1fr` + opacity 220ms (`motion-reduce:transition-none`) em vez de `hidden`; `md:flex-none` no chrome; `HomeSearchHitRow` `onMouseDown` preventDefault (blur→click); e2e focus sem digitar + regressão com digitação. Sem migration. Plano: [`modo-focado-busca-no-focus.md`](../../../docs/plans/modo-focado-busca-no-focus.md). - **B61 entregue em código (2026-07-29):** etapa de ajuste de votos no wizard A1 — `WizardExpectedVotesStep` substitui o stub B60 em `atualizar-votos` com `?municipio=`; três passos explícitos média→pessimista→otimista via `?cenario=`; atalhos `2×`/±50/±100; validação client com jump+warning (`getWizardVoteViolation`); **um POST batch** ao concluir otimista (`POST /campanha/municipios/expected-votes`). Helpers em `wizardVoteEstimate.ts` + `wizardActionHref` estendido. Sem migration/Consent. Unit `wizardVoteEstimate`; e2e avanço de cenário + violação. Plano: [`ajuste-votos-wizard.md`](../../../docs/plans/ajuste-votos-wizard.md). Desbloqueia wiring A1 / **B64** (prefill votos). - **B62 entregue em código (2026-07-29):** modelo de sinal simplificado — `municipalityUpdate` kind `sinal` agora é só `signalType` + `body`; migration `20260730_010601_simplify_municipality_signal_fields` dropa `signal_source`/`triangulated` (o gerador reemitiu `ADD VALUE 'adiada'` por drift de snapshot — removido à mão, e o snapshot novo sara a cadeia); labels/descriptions dos 5 tipos reescritas para a mesa (`Rede esfriou`, `Adversário apareceu`, `Alguém pediu algo` — sem "broker" no modelo de sinal; `activity.origin` `pedido_broker` e a copy do suggestionCatalog ficaram fora por decisão da sessão). Forms: `MunicipalitySignalFields` (lista B26) e o bloco inline de `MunicipalityUpdateForm` perderam Fonte/Triangulado; feed/dossiê (`MunicipalityUpdateFeed` + `municipalityUpdatePageData`) só exibem o badge do tipo. **E11: presença de sinal de adversário lê como confirmada — triage 1** (decisão do usuário: "eles não vão adicionar sinais improváveis"), `adversarySignal: { present: true } | null`, fator único "Sinal de adversário registrado", glossário E18 alinhado. Fixa B63. Bônus: teste e2e `campaignMunicipalities` "advisor scopes…" estava obsoleto desde B43 (home da liderança) — atualizado para `/campanha/contatos` + redirect pós-B43, e o pin de bypass do `municipalityElectoralBaseline` baixado 9→8 (drift pré-existente). Gate: tsc/lint/format/cycles/knip(P3 pré-existente)/876 unit/489 int/e2e alvo verde/build (`/campanha` 233 kB); Aikido 0 findings. Plano: [`simplificar-modelo-sinal.md`](../../../docs/plans/simplificar-modelo-sinal.md). Desbloqueia **B63** (wizard registrar sinal). - **E10+ entregue em código (2026-07-29):** Escala e DRY pós-E10 — F1: `loadMunicipalityScopeFromDocs` no `municipalityPageData.ts` evita a segunda query de `municipality` quando `isPagedByPayload === false`; F2: `computeAllMunicipalityPotentials` memoizado por processo (retorna cache `Map`); F3: `TooltipProvider` movido para o layout de `(app)`, restaurando o agrupamento de delay do Radix para os tooltips das listas; F4: DRY nos filtros multi do mobile em `MunicipalityFilters` via `.map` sobre `municipalityFilterDefinitions` (que ganhou `emptyLabel`). Sem migration/UI nova. Plano: [`escala-dry-pos-e10.md`](../../../docs/plans/escala-dry-pos-e10.md). diff --git a/docs/plans/modo-focado-busca-no-focus.md b/docs/plans/modo-focado-busca-no-focus.md index 7b43055d..f9acae45 100644 --- a/docs/plans/modo-focado-busca-no-focus.md +++ b/docs/plans/modo-focado-busca-no-focus.md @@ -1,7 +1,7 @@ # Modo focado da busca no focus (não na digitação) -Status: rascunho -Atualizado em: 2026-07-29 +Status: entregue (2026-07-30) +Atualizado em: 2026-07-30 — as-built: predicado `homeSearchUiFocused` (`inputFocused || query.isActive`) já no contrato/hook (overlap B68); `CampaignHomeLayout` retrai summary+spacer (`data-slot="home-chrome"`) e actions (grid `0fr/1fr` + opacity 220ms ease-out, `motion-reduce:transition-none`) em vez de `hidden`; `md:flex-none` no chrome para não crescer no desktop; `HomeSearchHitRow` `onMouseDown` preventDefault (blur→click); e2e focus sem digitar + regressão com digitação; unit layout/search atualizados. Sem migration. Item do roadmap: [docs/roadmap.md](../roadmap.md) (Trilha B, item B66 — UX-1 busca Início) Impeccable: B — encaixe de motion/estado no chrome do Início (`CampaignHomeLayout` / `CampaignHomeStaffChrome`) sob tema `campaign` Appetite: ~0,5–0,75 dia eng; estado `focused` ≠ `query.isActive` + transição CSS; sem migration diff --git a/docs/roadmap.md b/docs/roadmap.md index 13e10ab2..6497e0ce 100644 --- a/docs/roadmap.md +++ b/docs/roadmap.md @@ -1,6 +1,6 @@ # Roadmap — Teqo -Atualizado em: 2026-07-29 — ~~**B51**~~ ✓; ~~**B52**~~ ✓; ~~**B72**~~ ✓ gap strip ações; **B71** polish busca (bullets/título/hover full-bleed); **B69**–**B70** A4 liderança; ~~**B62**~~ ✓ simplificar sinal (E11 triage 1 por presença); ~~**B56**~~ ✓; ~~**B67**~~ ✓; ~~**B68**~~ ✓; **B66**; ~~**B59**~~ ✓; ~~**B65**~~ ✓; ~~**B60**~~ ✓; ~~**B61**~~ ✓; ~~**B48**~~ ✓; ~~**B49**~~ ✓; ~~**B50**~~ ✓; B53–B55; wizards ~~B60~~ ✓/~~**B61**~~ ✓/B63–B64. +Atualizado em: 2026-07-30 — ~~**B66**~~ ✓ busca no focus; ~~**B51**~~ ✓; ~~**B52**~~ ✓; ~~**B72**~~ ✓ gap strip ações; **B71** polish busca (bullets/título/hover full-bleed); **B69**–**B70** A4 liderança; ~~**B62**~~ ✓ simplificar sinal (E11 triage 1 por presença); ~~**B56**~~ ✓; ~~**B67**~~ ✓; ~~**B68**~~ ✓; ~~**B59**~~ ✓; ~~**B65**~~ ✓; ~~**B60**~~ ✓; ~~**B61**~~ ✓; ~~**B48**~~ ✓; ~~**B49**~~ ✓; ~~**B50**~~ ✓; B53–B55; wizards ~~B60~~ ✓/~~**B61**~~ ✓/B63–B64. 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) @@ -83,7 +83,7 @@ O discovery literatura→persona→entrevista ([relatório aprovado](research/re ### Demais itens abertos -- **UX-1 fluxos ação-primeiro (prioridade pós-sessão 29/07)** — evidência: [snapshot](plans/sessao-observada-coordenador-2026-07-29-snapshot.md) · O9–O11 em CUSTOMER.md · **rascunho:** [fluxos-acao-primeiro-inicio.md](plans/fluxos-acao-primeiro-inicio.md). Soft deadline: **03/08**. **Chassis Início:** ~~**B43**~~ ✓ → ~~**B44**~~ ✓ → ~~**B45**~~ ✓ → ~~**B46**~~ ✓ → ~~**B47**~~ ✓ → ~~**B58**~~ ✓ → ~~**B67**~~ ✓ (pan strip) → ~~**B65**~~ ✓ (âncora inferior mobile) → **B66** (focus limpa tela + animação) → ~~**B48**~~ ✓ → ~~**B49**~~ ✓ → ~~**B68**~~ ✓ → **B71** (polish resultados busca) · ~~**B72**~~ ✓ (gap strip) → ~~**B50**~~ ✓ → ~~**B51**~~ ✓ → ~~**B52**~~ ✓ → **B53–B55** · ~~**B56**~~ ✓ · **B57** futuro. **Wizards:** ~~**B59**~~ ✓ → ~~**B60**~~ ✓/**B61**/**B64** · ~~**B62**~~ ✓ → **B63** · **B69** → **B70** (A4 liderança). +- **UX-1 fluxos ação-primeiro (prioridade pós-sessão 29/07)** — evidência: [snapshot](plans/sessao-observada-coordenador-2026-07-29-snapshot.md) · O9–O11 em CUSTOMER.md · **rascunho:** [fluxos-acao-primeiro-inicio.md](plans/fluxos-acao-primeiro-inicio.md). Soft deadline: **03/08**. **Chassis Início:** ~~**B43**~~ ✓ → ~~**B44**~~ ✓ → ~~**B45**~~ ✓ → ~~**B46**~~ ✓ → ~~**B47**~~ ✓ → ~~**B58**~~ ✓ → ~~**B67**~~ ✓ (pan strip) → ~~**B65**~~ ✓ (âncora inferior mobile) → ~~**B66**~~ ✓ (focus limpa tela + animação) → ~~**B48**~~ ✓ → ~~**B49**~~ ✓ → ~~**B68**~~ ✓ → **B71** (polish resultados busca) · ~~**B72**~~ ✓ (gap strip) → ~~**B50**~~ ✓ → ~~**B51**~~ ✓ → ~~**B52**~~ ✓ → **B53–B55** · ~~**B56**~~ ✓ · **B57** futuro. **Wizards:** ~~**B59**~~ ✓ → ~~**B60**~~ ✓/**B61**/**B64** · ~~**B62**~~ ✓ → **B63** · **B69** → **B70** (A4 liderança). - ~~**B43** Início em branco + Quadro~~ — **entregue 2026-07-29** (`/campanha` blank; staff dashboard em `/campanha/quadro`; liderança em `/campanha/contatos`; nav Início+Quadro / Início+Meus contatos; `requireCampaignPageActor` manda leader bloqueado → `/campanha/contatos`; sem migration) · [plano](plans/inicio-em-branco-quadro.md) - ~~**B44** Botão de ação do Início + lista horizontal~~ — **entregue 2026-07-29** (`CampaignHomeActionButton` + `CampaignHomeActionStrip`; Tooltip fine / long-press Drawer coarse; montado no Início por B45 ✓) · ~1d · Janela 1 · Impeccable C · [plano](plans/botao-acao-inicio-strip.md) - ~~**B45** Catálogo de ações por persona~~ — **entregue 2026-07-29** (`src/lib/campaignHomeActions.ts` + `CampaignHomeActions`; staff 6 ações com `uncovered-municipalities` → `?coverage=sem_assessor&sort=votos`; leader 2 com `my-contacts` → `/campanha/contatos`; demais inertes; ilha client por limite RSC↔ícones Lucide) · [plano](plans/catalogo-acoes-inicio-por-persona.md) @@ -99,7 +99,7 @@ O discovery literatura→persona→entrevista ([relatório aprovado](research/re - **B70** Wizard atualizar liderança (grid 2/3/4 + form curto + skip + Continuar dirty + focus) · Depende de B59 + B69 · soft B60 · ~1,25–1,5d · Janela 1 · Impeccable C · [plano](plans/wizard-atualizar-lideranca.md) - ~~**B46** Posição dos botões de ação (thumb zone)~~ — **entregue 2026-07-29** (`CampaignHomeLayout`: coluna `min-h-full` + spacer `flex-1` só em mobile; `data-slot="home-actions"` / `home-search`; ordem flex `order-*` — mobile ações→busca, `md+` busca→ações); `/campanha` usa `CampaignPageShell` `min-h-full` + layout; decisão sticky vs coluna = coluna (opção B). Unit `campaignHomeLayout.unit.spec.ts`; e2e B45 intacto. Sem migration. Âncora inferior no mobile corrigida por **B65** ✓ (2026-07-29). · [plano](plans/posicao-botoes-acao-inicio-thumb-zone.md) - ~~**B47** Busca global — input (debounce, sem botão; modo focado: sobe e esconde o resto)~~ — **entregue 2026-07-29** (`CampaignHomeStaffChrome` + `CampaignHomeSearch` + `useHomeSearchQuery`; debounce 250 ms; query ativa ≥2 chars; `HomeSearchContext` para B48+; staff-only via `isStaffCampaignRole`; Escape limpa; região `aria-live` sem hits ainda; sem migration) · [plano](plans/busca-global-inicio-input.md) · **emenda B66:** limpeza no **focus** (não só na digitação) + animação -- **B66** Modo focado da busca no **focus** (não na digitação) + animação de retração do chrome (strip/spacer/resumo) como se a barra expandisse — emenda a decisão B47 “expand = query”; hits continuam gated por limiar ≥2 · Depende de B47 ✓ · soft ~~B65~~ ✓ · ~0,5–0,75d · Janela 1 · Paralelizável com B49–B53 / B59 / B62 · Impeccable B · [plano](plans/modo-focado-busca-no-focus.md) · empty útil → **B68** +- **B66** ~~Modo focado da busca no **focus** (não na digitação) + animação de retração do chrome (strip/spacer/resumo) como se a barra expandisse — emenda a decisão B47 “expand = query”; hits continuam gated por limiar ≥2~~ — **entregue 2026-07-30** (`homeSearchUiFocused`; `CampaignHomeLayout` grid `0fr/1fr` + opacity 220ms + `motion-reduce`; `HomeSearchHitRow` blur→click; e2e focus sem digitar) · Depende de B47 ✓ · soft ~~B65~~ ✓ · ~0,5–0,75d · Janela 1 · Impeccable B · [plano](plans/modo-focado-busca-no-focus.md) · empty útil → **B68** ✓ - ~~**B65** Ancorar busca + ações do Início no limite inferior (mobile)~~ — **entregue 2026-07-29** (`h-full min-h-0` em `CampaignPageShell` + `CampaignHomeStaffChrome` + `CampaignHomeLayout`; `data-slot="home-dock"` agrupa strip + busca; spacer `flex-1` empurra o dock acima da bottom nav; `md+` inalterado; modo focado B47/B66 intacto; sem `fixed`/`mt-auto`) · Depende de B46 ✓ / B47 ✓ · [plano](plans/ancorar-busca-acoes-inicio-mobile.md) - ~~**B48** Busca — resultados Municípios (+ TIs no mesmo grupo; flag de prioridade alinhada; “2022” / agregado à direita; sem card)~~ — **entregue 2026-07-29** (`POST /campanha/home-search`, `searchHomeMunicipalities`, `HomeSearchMunicipalityGroup`; word-start; assessor scoped; TIs via `loadTerritoryOverview`) · [plano](plans/busca-global-resultados-municipios.md) - ~~**B68** Sugestões na busca aberta (empty state por papel)~~ — **entregue 2026-07-29** (`POST /campanha/home-search` com `mode: 'suggest'`; `loadHomeSearchSuggestions` + `rankHomeSearchSuggestMunicipalities`; assessor = carteira fria; CG/candidato = `priority === 'alta'` por déficit central + frescor; `homeSearchUiFocused` + seção **Sugestões**; `resultKind`; sem migration) · [plano](plans/sugestoes-busca-vazia-inicio.md) diff --git a/src/components/campaign/dashboard/CampaignHomeLayout.tsx b/src/components/campaign/dashboard/CampaignHomeLayout.tsx index bca56110..5dfeb880 100644 --- a/src/components/campaign/dashboard/CampaignHomeLayout.tsx +++ b/src/components/campaign/dashboard/CampaignHomeLayout.tsx @@ -2,6 +2,35 @@ import type { ReactNode } from 'react' import { cn } from '@/lib/utils' +const homeChromeRetractionClass = (retracted: boolean) => + cn( + 'grid min-h-0 transition-[grid-template-rows,opacity] duration-[220ms] ease-out motion-reduce:transition-none', + retracted + ? 'grid-rows-[0fr] opacity-0 pointer-events-none motion-reduce:opacity-0' + : 'grid-rows-[1fr] opacity-100 motion-reduce:opacity-100', + ) + +const HomeChromeRetractionShell = ({ + retracted, + slot, + className, + children, +}: { + retracted: boolean + slot?: string + className?: string + children: ReactNode +}) => ( +
+
{children}
+
+) + export const CampaignHomeLayout = ({ actions, searchSlot, @@ -11,27 +40,34 @@ export const CampaignHomeLayout = ({ actions: ReactNode searchSlot?: ReactNode summarySlot?: ReactNode - /** When true (input focused or query active), hide thumb-zone spacer and action strip. */ + /** When true (input focused or query active), retract thumb-zone spacer and action strip. */ focused?: boolean }) => (
- {summarySlot ? ( -
- {summarySlot} + +
+ {summarySlot ? ( +
+ {summarySlot} +
+ ) : null} +
- ) : null} -
+
-
- {actions} -
+
+ {actions} +
+ {searchSlot ? (
( { + // Combobox/list precedent: RelationChipCell — keep input focused until navigation (B66). + event.preventDefault() + }} className={cn( 'flex min-h-11 w-full items-center gap-3 py-2.5 text-left text-foreground', 'rounded-md outline-none hover:bg-muted/60 focus-visible:ring-2 focus-visible:ring-ring', diff --git a/tests/e2e/campaignHomeActions.e2e.spec.ts b/tests/e2e/campaignHomeActions.e2e.spec.ts index 2b3a34c6..a6d45866 100644 --- a/tests/e2e/campaignHomeActions.e2e.spec.ts +++ b/tests/e2e/campaignHomeActions.e2e.spec.ts @@ -31,7 +31,10 @@ test.describe('Início — busca global (B47)', () => { await expect(page.getByLabel('Buscar na campanha')).toHaveCount(0) }) - test('staff focused search hides action strip after debounce', async ({ campaign, page }) => { + test('staff focused search hides action strip on input focus (B66)', async ({ + campaign, + page, + }) => { const { fixtures } = campaign const coordinator = await fixtures.createCampaignUser('coordinator', { name: fixtures.value('Coordenadora Geral'), @@ -42,6 +45,26 @@ test.describe('Início — busca global (B47)', () => { await expect(actionsSlot).toBeVisible() await expect(page.getByLabel('Ações rápidas')).toBeVisible() + await page.getByLabel('Buscar na campanha').focus() + await expect(actionsSlot).toBeHidden({ timeout: 5000 }) + + await page.getByLabel('Buscar na campanha').blur() + await expect(actionsSlot).toBeVisible({ timeout: 5000 }) + }) + + test('staff typing in search keeps action strip hidden after debounce', async ({ + campaign, + page, + }) => { + const { fixtures } = campaign + const coordinator = await fixtures.createCampaignUser('coordinator', { + name: fixtures.value('Coordenadora Geral'), + }) + + await campaign.login(page, coordinator.email!, coordinator.password) + const actionsSlot = page.locator('[data-slot="home-actions"]') + await expect(actionsSlot).toBeVisible() + await page.getByLabel('Buscar na campanha').fill('ca') await expect(actionsSlot).toBeHidden({ timeout: 5000 }) diff --git a/tests/unit/campaignHomeLayout.unit.spec.tsx b/tests/unit/campaignHomeLayout.unit.spec.tsx index 53322dc6..8219b14e 100644 --- a/tests/unit/campaignHomeLayout.unit.spec.tsx +++ b/tests/unit/campaignHomeLayout.unit.spec.tsx @@ -40,18 +40,20 @@ describe('CampaignHomeLayout', () => { expect(container.querySelector('[data-slot="home-dock"]')).not.toBeNull() }) - it('renders mobile thumb-zone spacer above home-dock', () => { + it('renders mobile thumb-zone spacer inside home-chrome above home-dock', () => { const { container } = render(Actions block

} />) - const dock = container.querySelector('[data-slot="home-dock"]') - const spacer = dock?.previousElementSibling - expect(spacer?.getAttribute('data-slot')).toBe('home-thumb-spacer') + const chrome = container.querySelector('[data-slot="home-chrome"]') + const spacer = chrome?.querySelector('[data-slot="home-thumb-spacer"]') + expect(chrome).not.toBeNull() + expect(spacer).not.toBeNull() expect(spacer?.getAttribute('aria-hidden')).toBe('true') expect(spacer?.className).toContain('flex-1') expect(spacer?.className).toContain('md:hidden') + expect(chrome?.nextElementSibling?.getAttribute('data-slot')).toBe('home-dock') }) - it('hides spacer, summary, and actions when focused but keeps search', () => { + it('retracts spacer, summary, and actions when focused but keeps search', () => { const { container } = render( Actions block

} @@ -61,11 +63,18 @@ describe('CampaignHomeLayout', () => { />, ) - expect(container.querySelector('[data-slot="home-thumb-spacer"]')?.className).toContain( - 'hidden', - ) - expect(container.querySelector('[data-slot="home-summary"]')?.className).toContain('hidden') - expect(container.querySelector('[data-slot="home-actions"]')?.className).toContain('hidden') + const homeChrome = container.querySelector('[data-slot="home-chrome"]') + expect(homeChrome?.getAttribute('data-retracted')).toBe('true') + expect(homeChrome?.className).toContain('grid-rows-[0fr]') + expect(homeChrome?.className).toContain('opacity-0') + + const actionsChrome = container.querySelector('[data-slot="home-actions-chrome"]') + expect(actionsChrome?.getAttribute('data-retracted')).toBe('true') + expect(actionsChrome?.className).toContain('grid-rows-[0fr]') + + expect(container.querySelector('[data-slot="home-thumb-spacer"]')).not.toBeNull() + expect(container.querySelector('[data-slot="home-summary"]')).not.toBeNull() + expect(container.querySelector('[data-slot="home-actions"]')).not.toBeNull() expect(container.querySelector('[data-slot="home-search"]')).not.toBeNull() expect(container.querySelector('[data-slot="home-dock"]')).not.toBeNull() }) diff --git a/tests/unit/campaignHomeSearch.unit.spec.tsx b/tests/unit/campaignHomeSearch.unit.spec.tsx index a41d60a9..1f40f99f 100644 --- a/tests/unit/campaignHomeSearch.unit.spec.tsx +++ b/tests/unit/campaignHomeSearch.unit.spec.tsx @@ -1,7 +1,6 @@ import { render, screen } from '@testing-library/react' import { describe, expect, it, vi } from 'vitest' -import { CampaignHomeLayout } from '@/components/campaign/dashboard/CampaignHomeLayout' import { CampaignHomeSearch } from '@/components/campaign/dashboard/CampaignHomeSearch' import { HomeSearchProvider } from '@/components/campaign/dashboard/HomeSearchContext' @@ -15,36 +14,6 @@ const providerValue = { uiFocused: true, } -describe('CampaignHomeLayout focused mode', () => { - it('hides actions, thumb spacer, and summary when focused', () => { - const { container } = render( - Actions block

} - searchSlot={

Search

} - summarySlot={

Summary block

} - />, - ) - - expect(container.querySelector('[data-slot="home-thumb-spacer"]')).toBeNull() - expect(container.querySelector('[data-slot="home-actions"]')?.className).toContain('hidden') - expect(container.querySelector('[data-slot="home-summary"]')?.className).toContain('hidden') - }) - - it('shows summary when not focused', () => { - render( - Actions block

} - summarySlot={

Summary stub

} - />, - ) - - expect( - screen.getByTestId('home-summary-stub').closest('[data-slot="home-summary"]'), - ).not.toBeNull() - }) -}) - describe('CampaignHomeSearch', () => { it('renders search input and results region', () => { render(