diff --git a/docs/plans/sidebar-perfil-sair-icone-impl.md b/docs/plans/sidebar-perfil-sair-icone-impl.md new file mode 100644 index 00000000..69b954b8 --- /dev/null +++ b/docs/plans/sidebar-perfil-sair-icone-impl.md @@ -0,0 +1,64 @@ +# Impl: Sidebar — papel no perfil + Sair como ícone + +Status: aprovado +Atualizado em: 2026-08-02 +Issue: #272 +Intenção: docs/plans/sidebar-perfil-sair-icone.md +Appetite restante: ~0,5 dia eng (dentro) + +## Leitura da intenção + +- **Outcome:** Rodapé da sidebar mostra nome + papel; logout vira ícone à direita na mesma linha — sem botão full-width “Sair”. +- **O que NÃO negociar:** destino `/campanha/perfil`; limpeza client-side no logout; rótulos pt-BR existentes; leader lockdown; não mexer no badge de escopo do topo (B130 é outro item). +- **O que reavaliar:** hipótese de manter `
` separado abaixo do link — melhor linha única com flex. + +## Abordagem recomendada + +```mermaid +flowchart LR + A[SidebarFooter flex row] --> B[Link perfil flex-1] + A --> C[form + icon Button] + B --> D[campaignRoleLabels role] + C --> E[handleLogout inalterado] +``` + +**Opções consideradas:** + +- **A:** Ícone dentro do `` com stopPropagation — rejeitada (acidental logout / a11y confusa). +- **B:** `DropdownMenu` de conta — rejeitada (fora de escopo / rabbit hole). +- **C (recomendada):** Flex row: link de perfil (`flex-1`) + `` com `Button` ghost `size-11` + `LogOutIcon`; subtítulo = `campaignRoleLabels[user.role]`. + +**Recomendação:** C — mínimo diff no dono `CampaignSidebar.tsx`; comportamento de logout preservado. + +### Componentes / mudanças + +- **`CampaignSidebar.tsx`:** footer em `flex`; subtítulo papel; `LogOutIcon`; botão ícone com `aria-label` dinâmico; `handleLogout` e limpezas intactas. +- **Migration:** sem migration. +- **Access / Consent:** N/A. +- **UI:** Impeccable B — shape (linha única) + craft (ghost icon 44px) + a11y (`aria-label`, `sr-only` não necessário se label no botão). + +### Dados → forma + +N/A — rótulo de papel já na sessão (`campaignRoleLabels`). + +## Fases verificáveis + +1. **UI** — footer densificado em `CampaignSidebar.tsx`. +2. **Testes** — unit existente de tokens sidebar; opcional assert de `campaignRoleLabels` no source. +3. **Gates** — `pnpm gate:fast`; `pnpm push`. + +## Rabbit holes / Não escopo (engenharia) + +- Remover `CampaignScopeBadge` do topo (B130). +- Bottom nav / perfil page / confirmação de logout. + +## Riscos e mitigação + +- **Toque acidental:** alvos separados (link vs botão) — mitigado por layout flex explícito. +- **Spinner sem texto:** `aria-label` “Saindo…” no submit — mitigado. + +## Aceite de engenharia + +- [x] Aceite de produto da intenção coberto +- [x] Invariantes AGENTS/engineering-standards +- [x] Testes de domínio: shell unit spec de tokens mantido diff --git a/src/components/campaign/shell/CampaignSidebar.tsx b/src/components/campaign/shell/CampaignSidebar.tsx index 503cda8b..988d6c2a 100644 --- a/src/components/campaign/shell/CampaignSidebar.tsx +++ b/src/components/campaign/shell/CampaignSidebar.tsx @@ -4,6 +4,8 @@ import Link from 'next/link' import { usePathname } from 'next/navigation' import { useState, type FormEvent, type ReactNode } from 'react' +import { LogOutIcon } from 'lucide-react' + import { logoutCampaign } from '@/app/(campaign)/campanha/actions/auth' import { CampaignUserAvatar } from '@/components/campaign/shared/CampaignUserAvatar' import { MunicipalityNavSavedFilters } from '@/components/campaign/shell/MunicipalityNavSavedFilters' @@ -30,6 +32,7 @@ import { Spinner } from '@/components/ui/Spinner' import { clearLastActedMunicipality } from '@/lib/campaignLastActedMunicipality' import { clearCampaignPwaCaches } from '@/utilities/campaignPwaClient' import type { CampaignUserShellView } from '@/utilities/campaignUserProfile' +import { campaignRoleLabels } from '@/utilities/campaignUserProfile' import { clearMunicipalitySavedFilters } from '@/utilities/municipality/municipalitySavedFilters' import { clearRecentVisits } from '@/utilities/recentVisits' @@ -123,30 +126,34 @@ export const CampaignSidebar = ({ user }: { user: CampaignSidebarUser }) => { - - -
- - {user.name} - - Meu perfil -
- - - - + +
+ + {user.name} + + + {campaignRoleLabels[user.role]} + +
+ +
+ +
+
)