- view=week|day|month|list no contrato URL da agenda (canônico, fail-closed)
- seletor compacto 'Semana ▾' no header desktop e mobile (slot C94/C95)
- FullCalendar headerToolbar sem os 4 botões de modo; escolha vence resize
- effect normaliza a vista também quando a URL perde o param (sem vista órfã)
- useNarrowMeasured(breakpoint) em hooks/use-mobile (settle de hidratação)
- e2e reescrito no seletor + persistência + escolha-vence-resize + estabilização
dos waits de slot (grid lazy do FullCalendar substitui gridcells no load)
Adiciona entrada por voz ao chat: botão de mic no InputGroup grava no
browser (getUserMedia + MediaRecorder), envia o clip multipart para a nova
rota POST /campanha/api/ai-transcribe (auth cookie + rate limit no mesmo
balde + same-origin) e injeta a transcrição como rascunho editável — o
envio segue o fluxo normal do chat. O áudio nunca é persistido.
STT via Deep Infra whisper-large-v3 (DEEPINFRA_API_KEY, mesma do B174);
a costura de rede vive em utilities/ai/deepInfraTranscribe.ts; a máquina
de captura em useMicTranscript. Falha de permissão/provedor degrada a
mensagem em pt-BR sem quebrar o chat por texto.
Closes#448
B171 #443
- CampaignBottomNav: pt-2.5 no nav (respiro da borda superior) e rótulos
text-[10px] nowrap com gap-1 — sem encolher a área de toque.
- e2e: assert paddingTop >= 8px, rótulos < 12px e sem sobreposição horizontal.
- Converse (useChat) lifts to the provider: survives desktop panel <-> mobile
drawer swaps, internal /campanha navigation and resize (new tab still resets).
- Chat Panel/Separator always mounted (RRP panel-count change forces a full
navigation); footprint hidden via elementRef + .b167-ai-chat-hidden
(display:none !important), avoiding RRP's imperative collapse/expand races.
- Single 'open' flag drives both surfaces (open && viewport); reconciled with
the panel at desktop settle and on user drag-collapse (gated by isUserInteraction).
- Mobile Drawer extracted to CampaignAIDrawer; FAB/setOpen unified; focus moves
into the chat on the mobile->desktop swap.
- e2e campaignAiChatResize: desktop->mobile, mobile->desktop, closed stays
closed, fresh mobile visit closed, navigation survival, new tab resets.
- Impl plan: docs/plans/migrar-chat-painel-drawer-resize-impl.md
Closes#416
Ações de ajuste (votos, tendência, atualização, liderança) agora retornam à
origem ao salvar (toast + from allowlist B110 / Início), sem avançar sozinhas
para outro wizard. Removidos fila de encadeamento (wizardActionChain.ts),
param entry, skip/Pular (chrome mobile sempre X) e prefill de nota sem
produtor. Liderança: botão pós-save 'Continuar' → 'Concluir' (origem).
Sem migration.
The AI FAB (Sollinha) sits at bottom-20 (80px) with z-40 in a different
stacking context. Moving the Quick Actions FAB from bottom-4 to
bottom-[calc(4rem)] for the bottom nav caused overlap at the shared
z-40, so the AI button intercepted clicks. Raised to 7rem (112px) to
clear both the bottom nav (4rem) and the AI FAB button (ending at 7rem).
Mobile bottom nav (staff only): 5 items (Início, Municípios, Atualizações,
Agenda, Mais) with Drawer overflow for secondary destinations. Leader and
desktop remain sidebar-only. FAB + scroll padding adjusted for safe-area.
Resolves#400
Issue #390 — entrada operacional staff com FullCalendar v7 route-local
(semana/mês/lista), filtros compartilháveis por município/deputado/tag,
criação pelo slot, detalhe por URL e remarcação drag/resize sob RBAC,
transação e lock por atividade.
- /campanha/atividades e giros permanecem como lista/fluxos legados
- Sem migration/collection nova; reutiliza activity de C14
- Fuso Bahia, range exclusivo, erro/revert, loading/empty testados
- Leader negado, advisor limitado pelo access atual
- E2E cobre filtros, drag, mobile 390x844 e slot prefill
- Int specs cobrem RBAC, concorrência e defense-in-depth
Impl: docs/plans/fullcalendar-agenda-campanha-impl.md
Insert Organizações after Lideranças in staffNav so staff can discover
the existing /campanha/organizacoes list from the structural nav.
Leaders remain on leaderNav; isCampaignNavActive already covers list,
detail, and /nova paths.
Co-authored-by: Francisco Solla <fsolla@users.noreply.github.com>
- Move initial focus to sr-only title instead of void/body (a11y).
- Fold matchMedia mock into stubMobileViewport helper.
Co-authored-by: Francisco Solla <fsolla@users.noreply.github.com>
- wizardPreviousHref em wizardActionChain para todos os elos B98
- Avanço encadeado com router.push; Voltar no chrome com replace
- Testes unitários para href anterior e navegação pending
Co-authored-by: Francisco Solla <fsolla@users.noreply.github.com>
- Block Dialog onOpenAutoFocus and Drawer initialFocus so search does not
steal focus on open (actions stay visible per B132 idle state).
- Reserve md:pr-10 on search chrome so desktop close button does not overlap.
- Enable showSwipeHandle on mobile drawer (no X button).
- Unit tests for idle state, swipe handle, and close spacing.
Co-authored-by: Francisco Solla <fsolla@users.noreply.github.com>
- CampaignHomeActionStrip: grid-cols-3 no mobile; variante grid para overlay
- CampaignQuickActionsOverlay: grade no lugar da strip; altura por conteúdo;
pt-4 na busca focada; limpa query ao fechar
- CampaignQuickActionsHost: clear() em fechamento e mudança de rota
- Testes unit atualizados; impl plan em docs/plans/
Co-authored-by: Francisco Solla <fsolla@users.noreply.github.com>
Desktop chrome put title+subtitle in one text node; exact getByText
failed. Mobile subtitle matched Municípios case-insensitively. Mark the
title with data-slot and assert against that node.
Remove o bottom drawer não-modal (snap/peek/scroll-coupling) e introduz
um FAB em todas as larguras fora do Início e wizards. Abrir o FAB mostra
overlay modal: Dialog no desktop (busca em cima) e Drawer no mobile
(ações em cima), reutilizando strip e busca globais do Início.
Closes#260
Co-authored-by: Francisco Solla <fsolla@users.noreply.github.com>
- Add QUICK_ACTIONS_SNAP_FULL; drawer expands on search focus and hides action strip
- Tighten dock bottom gap; restore dock/collapsed on blur per scroll position (B100)
- Widen CampaignHomeActionButton to w-[5.5rem] for two-line labels
- Client-side filter excludes current page entity from drawer search hits
- Unit + e2e coverage for full snap, exclusion, and label readability