mirror of
https://github.com/fsolla/teqo.git
synced 2026-11-13 15:13:07 +00:00
feat(B131): sidebar footer role label + logout icon
Co-authored-by: Francisco Solla <fsolla@users.noreply.github.com>
This commit is contained in:
parent
0400d0fdc5
commit
b6f16557ce
2 changed files with 93 additions and 23 deletions
64
docs/plans/sidebar-perfil-sair-icone-impl.md
Normal file
64
docs/plans/sidebar-perfil-sair-icone-impl.md
Normal file
|
|
@ -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 `<form>` 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 `<Link>` 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`) + `<form>` 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
|
||||
|
|
@ -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 { CampaignScopeBadge } from '@/components/campaign/shared/CampaignScopeBadge'
|
||||
import { CampaignUserAvatar } from '@/components/campaign/shared/CampaignUserAvatar'
|
||||
|
|
@ -139,30 +141,34 @@ export const CampaignSidebar = ({ user }: { user: CampaignSidebarUser }) => {
|
|||
</SidebarContent>
|
||||
|
||||
<SidebarFooter className="border-t border-sidebar-border">
|
||||
<Link
|
||||
href="/campanha/perfil"
|
||||
className="flex min-w-0 items-center gap-3 rounded-md px-1 py-2 outline-none focus-visible:ring-2 focus-visible:ring-sidebar-ring"
|
||||
>
|
||||
<CampaignUserAvatar name={user.name} avatarUrl={user.avatarUrl} size="sm" />
|
||||
<div className="flex min-w-0 flex-col gap-0.5 leading-none">
|
||||
<span className="truncate text-sm font-medium text-sidebar-foreground">
|
||||
{user.name}
|
||||
</span>
|
||||
<span className="truncate text-xs text-muted-foreground">Meu perfil</span>
|
||||
</div>
|
||||
</Link>
|
||||
<form onSubmit={handleLogout}>
|
||||
<Button
|
||||
type="submit"
|
||||
variant="outline"
|
||||
size="sm"
|
||||
disabled={isLoggingOut}
|
||||
className="min-h-11 w-full border-sidebar-border bg-sidebar font-medium text-sidebar-foreground hover:bg-sidebar-accent hover:text-sidebar-accent-foreground"
|
||||
<div className="flex items-center gap-1">
|
||||
<Link
|
||||
href="/campanha/perfil"
|
||||
className="flex min-w-0 flex-1 items-center gap-3 rounded-md px-1 py-2 outline-none focus-visible:ring-2 focus-visible:ring-sidebar-ring"
|
||||
>
|
||||
{isLoggingOut ? <Spinner aria-hidden="true" /> : null}
|
||||
{isLoggingOut ? 'Saindo…' : 'Sair'}
|
||||
</Button>
|
||||
</form>
|
||||
<CampaignUserAvatar name={user.name} avatarUrl={user.avatarUrl} size="sm" />
|
||||
<div className="flex min-w-0 flex-col gap-0.5 leading-none">
|
||||
<span className="truncate text-sm font-medium text-sidebar-foreground">
|
||||
{user.name}
|
||||
</span>
|
||||
<span className="truncate text-xs text-muted-foreground">
|
||||
{campaignRoleLabels[user.role]}
|
||||
</span>
|
||||
</div>
|
||||
</Link>
|
||||
<form onSubmit={handleLogout} className="shrink-0">
|
||||
<Button
|
||||
type="submit"
|
||||
variant="ghost"
|
||||
size="icon"
|
||||
disabled={isLoggingOut}
|
||||
aria-label={isLoggingOut ? 'Saindo…' : 'Sair'}
|
||||
className="size-11 text-sidebar-foreground hover:bg-sidebar-accent hover:text-sidebar-accent-foreground"
|
||||
>
|
||||
{isLoggingOut ? <Spinner aria-hidden="true" /> : <LogOutIcon />}
|
||||
</Button>
|
||||
</form>
|
||||
</div>
|
||||
</SidebarFooter>
|
||||
</Sidebar>
|
||||
)
|
||||
|
|
|
|||
Loading…
Reference in a new issue