mirror of
https://github.com/fsolla/teqo.git
synced 2026-11-13 23:53:05 +00:00
docs(plans): C145 — plano permissão do assessor em modal central + bottom drawer
This commit is contained in:
parent
cd26fb8ce2
commit
aec6ec2edd
4 changed files with 338 additions and 0 deletions
Binary file not shown.
|
After Width: | Height: | Size: 98 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 76 KiB |
244
docs/plans/permissao-assessores-modal-central-ui-draft.html
Normal file
244
docs/plans/permissao-assessores-modal-central-ui-draft.html
Normal file
|
|
@ -0,0 +1,244 @@
|
|||
<!doctype html>
|
||||
<html lang="pt-BR">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
<script src="https://cdn.jsdelivr.net/npm/@tailwindcss/browser@4"></script>
|
||||
<title>UI draft — C145 · Permissão do assessor em modal central / bottom drawer</title>
|
||||
</head>
|
||||
<body class="bg-zinc-950 text-zinc-100 antialiased">
|
||||
<main class="mx-auto max-w-6xl p-8">
|
||||
<p class="text-sm text-zinc-400">
|
||||
C145 — o editor Visão × Edição sai do popover ancorado (que estoura a tela) e vira overlay
|
||||
centralizado: Dialog central no desktop, bottom drawer no celular. Conteúdo do editor (C141)
|
||||
intacto — muda só o invólucro. Cenas: desktop e mobile.
|
||||
</p>
|
||||
|
||||
<!-- ============ CENA 1: DESKTOP — Dialog central ============ -->
|
||||
<section data-shot="desktop" class="mt-6 overflow-hidden rounded-xl border border-zinc-800">
|
||||
<div
|
||||
class="flex items-center justify-between border-b border-zinc-200 bg-zinc-100 px-6 py-4"
|
||||
>
|
||||
<div>
|
||||
<div class="h-5 w-44 rounded bg-zinc-500"></div>
|
||||
<div class="mt-1 h-2 w-64 rounded bg-zinc-400"></div>
|
||||
</div>
|
||||
<div class="flex items-center gap-3">
|
||||
<div
|
||||
class="h-9 w-44 rounded-full border border-zinc-300 bg-white px-3 text-sm text-zinc-500"
|
||||
>
|
||||
Buscar assessor…
|
||||
</div>
|
||||
<div
|
||||
class="inline-flex h-9 items-center rounded-lg bg-red-600 px-4 text-sm font-extrabold text-white"
|
||||
>
|
||||
+ Novo assessor
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="relative bg-zinc-100 px-6 pb-6 pt-6">
|
||||
<!-- tabela -->
|
||||
<div class="overflow-hidden rounded-lg border border-zinc-200 bg-white">
|
||||
<div
|
||||
class="grid grid-cols-[1.3fr_1.7fr_1.1fr_1.7fr_1.5fr] gap-2 border-b border-zinc-200 bg-zinc-50 px-4 py-2 text-xs font-bold text-zinc-500"
|
||||
>
|
||||
<div>Nome</div>
|
||||
<div>E-mail</div>
|
||||
<div>Celular</div>
|
||||
<div>Municípios</div>
|
||||
<div>Permissão</div>
|
||||
</div>
|
||||
<div
|
||||
class="grid grid-cols-[1.3fr_1.7fr_1.1fr_1.7fr_1.5fr] items-center gap-2 border-b border-zinc-100 px-4 py-3 text-sm"
|
||||
>
|
||||
<div class="font-semibold text-zinc-900">Nome do assessor</div>
|
||||
<div class="text-zinc-600">assessor@exemplo.org</div>
|
||||
<div class="text-zinc-600">(71) 90000-0000</div>
|
||||
<div class="flex flex-wrap gap-1">
|
||||
<span class="rounded bg-zinc-200 px-1.5 py-0.5 text-xs text-zinc-700"
|
||||
>Salvador (19)</span
|
||||
>
|
||||
<span class="rounded bg-zinc-200 px-1.5 py-0.5 text-xs text-zinc-700"
|
||||
>Feira de Santana</span
|
||||
>
|
||||
</div>
|
||||
<div>
|
||||
<span
|
||||
class="inline-flex items-center rounded bg-muted px-2 py-0.5 text-xs font-bold text-zinc-800 ring-1 ring-zinc-300"
|
||||
>Carteira · Edita carteira</span
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="grid grid-cols-[1.3fr_1.7fr_1.1fr_1.7fr_1.5fr] items-center gap-2 border-b border-zinc-100 px-4 py-3 text-sm"
|
||||
>
|
||||
<div class="font-semibold text-zinc-900">Outra assessora</div>
|
||||
<div class="text-zinc-600">outra@exemplo.org</div>
|
||||
<div class="text-zinc-600">(71) 90000-0001</div>
|
||||
<div class="flex flex-wrap gap-1">
|
||||
<span class="rounded bg-zinc-200 px-1.5 py-0.5 text-xs text-zinc-700"
|
||||
>Camaçari</span
|
||||
>
|
||||
</div>
|
||||
<div>
|
||||
<span class="rounded bg-zinc-300 px-2 py-0.5 text-xs font-bold text-zinc-800"
|
||||
>Tudo · Somente leitura</span
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- overlay escuro do Dialog -->
|
||||
<div class="absolute inset-0 z-10 flex items-center justify-center bg-zinc-950/60 px-6">
|
||||
<!-- Dialog central -->
|
||||
<div class="w-full max-w-md rounded-xl bg-white p-5 shadow-2xl">
|
||||
<div>
|
||||
<p class="text-sm font-bold text-zinc-900">Permissão da conta</p>
|
||||
<p class="mt-1 text-xs text-zinc-500">Vale para todas as telas do /campanha.</p>
|
||||
</div>
|
||||
|
||||
<div class="mt-4 flex flex-col gap-1.5">
|
||||
<label class="text-xs font-bold text-zinc-900" for="d-visibility">Visão</label>
|
||||
<select
|
||||
id="d-visibility"
|
||||
class="h-9 w-full rounded-md border border-zinc-300 bg-white px-3 text-sm text-zinc-900"
|
||||
>
|
||||
<option>Edita tudo — Edita tudo o que vê</option>
|
||||
<option>Carteira — Municípios que administra</option>
|
||||
</select>
|
||||
<p class="text-[11px] leading-relaxed text-zinc-500">
|
||||
Enxerga todos os municípios e lideranças.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="mt-3 flex flex-col gap-1.5">
|
||||
<label class="text-xs font-bold text-zinc-900" for="d-editing">Edição</label>
|
||||
<select
|
||||
id="d-editing"
|
||||
class="h-9 w-full rounded-md border border-zinc-300 bg-white px-3 text-sm text-zinc-900"
|
||||
>
|
||||
<option>Edita tudo — Edita tudo o que vê</option>
|
||||
<option>Edita carteira — Edita só o que administra</option>
|
||||
<option>Somente leitura — Nenhum controle de edição</option>
|
||||
</select>
|
||||
<p class="text-[11px] leading-relaxed text-zinc-500">
|
||||
Edita tudo o que vê — contas, carteiras, nível de envolvimento e demandas
|
||||
escaladas seguem com a coordenação.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div
|
||||
class="mt-3 rounded-md bg-zinc-100 px-3 py-2 text-[11px] leading-relaxed text-zinc-600"
|
||||
>
|
||||
Demandas seguem regra própria: só quem é responsável pela demanda (e
|
||||
candidato/coordenador) a vê — mesmo com visão "Tudo". Decisões de coordenação
|
||||
(contas, carteiras, nível de envolvimento, demandas escaladas) continuam restritas a
|
||||
coordenador e candidato.
|
||||
</div>
|
||||
|
||||
<div class="mt-4 flex justify-end gap-2">
|
||||
<button
|
||||
type="button"
|
||||
class="inline-flex h-9 items-center rounded-md border border-zinc-300 bg-white px-4 text-sm font-semibold text-zinc-700"
|
||||
>
|
||||
Cancelar
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
class="inline-flex h-9 items-center rounded-md bg-red-600 px-4 text-sm font-extrabold text-white"
|
||||
>
|
||||
Salvar
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- ============ CENA 2: MOBILE — bottom drawer ============ -->
|
||||
<section data-shot="mobile" class="mt-10 overflow-hidden rounded-xl border border-zinc-800">
|
||||
<div
|
||||
class="flex items-center justify-between border-b border-zinc-200 bg-zinc-100 px-4 py-3"
|
||||
>
|
||||
<div class="h-5 w-32 rounded bg-zinc-500"></div>
|
||||
<div class="h-8 w-8 rounded-lg bg-red-600"></div>
|
||||
</div>
|
||||
|
||||
<div class="relative bg-zinc-100 p-3 pb-[17rem]">
|
||||
<!-- linha da lista com o badge tocado -->
|
||||
<div class="rounded-lg border border-zinc-200 bg-white p-3 text-sm">
|
||||
<div class="font-semibold text-zinc-900">Assessora de campo</div>
|
||||
<div class="mt-1 text-xs text-zinc-500">campo@exemplo.org · (71) 90000-0002</div>
|
||||
<div class="mt-2 flex flex-wrap gap-1">
|
||||
<span class="rounded bg-zinc-200 px-1.5 py-0.5 text-xs text-zinc-700">Ilhéus</span>
|
||||
<span class="rounded bg-zinc-200 px-1.5 py-0.5 text-xs text-zinc-700">Itabuna</span>
|
||||
<span
|
||||
class="inline-flex items-center rounded bg-zinc-200 px-2 py-0.5 text-xs font-bold text-zinc-800"
|
||||
>Carteira · Edita carteira</span
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- bottom drawer -->
|
||||
<div class="absolute inset-x-3 bottom-3 z-10 rounded-t-xl bg-white shadow-2xl">
|
||||
<div class="mx-auto mt-2 h-1 w-10 rounded-full bg-zinc-300"></div>
|
||||
<div class="p-5">
|
||||
<div>
|
||||
<p class="text-sm font-bold text-zinc-900">Permissão da conta</p>
|
||||
<p class="mt-1 text-xs text-zinc-500">Vale para todas as telas do /campanha.</p>
|
||||
</div>
|
||||
|
||||
<div class="mt-4 flex flex-col gap-1.5">
|
||||
<label class="text-xs font-bold text-zinc-900" for="m-visibility">Visão</label>
|
||||
<select
|
||||
id="m-visibility"
|
||||
class="h-10 w-full rounded-md border border-zinc-300 bg-white px-3 text-sm text-zinc-900"
|
||||
>
|
||||
<option>Carteira — Municípios que administra</option>
|
||||
<option>Edita tudo — Edita tudo o que vê</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div class="mt-3 flex flex-col gap-1.5">
|
||||
<label class="text-xs font-bold text-zinc-900" for="m-editing">Edição</label>
|
||||
<select
|
||||
id="m-editing"
|
||||
class="h-10 w-full rounded-md border border-zinc-300 bg-white px-3 text-sm text-zinc-900"
|
||||
>
|
||||
<option>Edita carteira — Edita só o que administra</option>
|
||||
<option>Edita tudo — Edita tudo o que vê</option>
|
||||
<option>Somente leitura — Nenhum controle de edição</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div
|
||||
class="mt-3 rounded-md bg-zinc-100 px-3 py-2 text-[11px] leading-relaxed text-zinc-600"
|
||||
>
|
||||
Demandas seguem regra própria: só quem é responsável pela demanda (e
|
||||
candidato/coordenador) a vê — mesmo com visão "Tudo". Decisões de coordenação
|
||||
(contas, carteiras, nível de envolvimento, demandas escaladas) continuam restritas a
|
||||
coordenador e candidato.
|
||||
</div>
|
||||
|
||||
<div class="mt-4 grid grid-cols-2 gap-2">
|
||||
<button
|
||||
type="button"
|
||||
class="inline-flex h-11 items-center justify-center rounded-md border border-zinc-300 bg-white text-sm font-semibold text-zinc-700"
|
||||
>
|
||||
Cancelar
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
class="inline-flex h-11 items-center justify-center rounded-md bg-red-600 text-sm font-extrabold text-white"
|
||||
>
|
||||
Salvar
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</main>
|
||||
</body>
|
||||
</html>
|
||||
94
docs/plans/permissao-assessores-modal-central.md
Normal file
94
docs/plans/permissao-assessores-modal-central.md
Normal file
|
|
@ -0,0 +1,94 @@
|
|||
# Assessores — editor de permissão em modal central (desktop) + bottom drawer (mobile) no lugar do popover
|
||||
|
||||
Status: rascunho
|
||||
Atualizado em: 2026-08-23
|
||||
Issue: #813
|
||||
Priority: P2
|
||||
Impeccable: B — encaixe na superfície existente do C141
|
||||
Rascunho UI: `docs/plans/permissao-assessores-modal-central-ui-draft.html`
|
||||
Appetite: ~0,5–1 dia eng
|
||||
Responsável: —
|
||||
|
||||
## Intenção
|
||||
|
||||
Na lista de assessores (`/campanha/assessores`), a célula "Permissão" é um badge que abre o editor Visão × Edição num popover ancorado — e a tabela é larga (`min-w-[56rem]`, com scroll horizontal), então o popover estoura o viewport com frequência. Quem está configurando o assessor precisa ver e salvar a permissão sem brigar com a janela: no desktop, um modal central (Dialog); no celular, um bottom drawer. Só o invólucro muda — o editor e as regras do C141 ficam intactos.
|
||||
|
||||
## Persona e fluxo
|
||||
|
||||
- **Persona / contexto:** coordenador(a) (ou candidato(a)) na tela de assessores, configurando o que cada assessor vê e edita; mesa com listas longas, celular ou notebook.
|
||||
- **Job principal:** abrir a permissão de um assessor e definir Visão × Edição com o conteúdo sempre à vista.
|
||||
- **Fluxo desejado:** toca no badge "Permissão" → abre modal centralizado (desktop) ou bottom drawer (mobile) com o editor → ajusta Visão/Edição → Salvar → overlay fecha e o badge reflete o novo perfil.
|
||||
- **Anti-goals de produto:** não virar uma campanha geral de popover→modal (outras superfícies mantêm seus contêineres); não mexer no conteúdo, combos, nota ou regras de coerência do editor; não criar um segundo componente de editor.
|
||||
|
||||
### Esboço de fluxo (B/C/D)
|
||||
|
||||
```text
|
||||
[badge "Permissão" na linha do assessor]
|
||||
→ toque/clique
|
||||
→ desktop: Dialog central (visor fixo) | mobile: bottom drawer (polegares na base)
|
||||
→ editor Visão × Edição (mesmos combos, mesma nota, regras de coerência)
|
||||
→ Salvar (ou Cancelar)
|
||||
→ overlay fecha, badge atualizado
|
||||
```
|
||||
|
||||
### Rascunho UI (gate)
|
||||
|
||||

|
||||
|
||||

|
||||
|
||||
- Rascunho UI (gate): `docs/plans/permissao-assessores-modal-central-ui-draft.html` — duas cenas estáticas: dialog central desktop (~1280px) e bottom drawer mobile (~390px), tema zinc do draft C141.
|
||||
|
||||
## Objetivo e aceite
|
||||
|
||||
- A permissão de qualquer assessor é editada num overlay centralizado que nunca estoura o viewport, no desktop e no celular.
|
||||
- O editor continua sendo o mesmo do C141: mesmos combos Visão/Edição, mesma nota, Cancelar/Salvar, regras de coerência (edição 'tudo' ⇒ visão 'tudo'; visão 'carteira' ⇒ edição cai para 'carteira').
|
||||
- Ao salvar, o overlay fecha e o badge mostra o perfil novo; a linha de assessor em rascunho continua usando `onDraftChange` local (não salva no servidor).
|
||||
- O `aria-label` do badge e os ids dos selects (`advisor-permission-visibility` / `advisor-permission-editing`) são preservados.
|
||||
- O editor embutido na página de detalhe do assessor segue exatamente como está — não participa desta entrega.
|
||||
|
||||
## Dados (intenção)
|
||||
|
||||
- **Vou apresentar dados?** Não.
|
||||
- **Decisões desbloqueadas:** N/A — sem métrica e sem decisão de dados; é re-superfície do editor existente, server actions e escrita em banco intactas.
|
||||
- **Forma:** N/A.
|
||||
|
||||
## Direção no codebase (hipótese)
|
||||
|
||||
- **Áreas prováveis:** `src/components/campaign/advisor/` (`AdvisorPermissionBadge.tsx` é o único ponto de troca de invólucro; `AdvisorsTable.tsx` não muda além do que o badge já expõe), `src/components/ui/Dialog.tsx` e `src/components/ui/Drawer.tsx`, `src/hooks/use-mobile.ts` (`useNarrowMeasured(640)`).
|
||||
- **Precedente a olhar:** C123 — `docs/plans/agenda-criacao-modal-central-impl.md` (Dialog desktop + Drawer mobile selecionados por `useNarrowMeasured`); célula "Carteira do assessor" da mesma tabela já abre sheet compartilhada em ponteiros grossos (`RelationChipCell` variant="sheet" → `CampaignListSheetProvider`); drawer default de `src/components/ui/Drawer.tsx` já é bottom-anchored.
|
||||
- **Risco de acoplamento:** troca de contêiner só dentro do `AdvisorPermissionBadge` — o badge é usado em dois pontos (linha de dados com `advisorId`+`formAction`, linha de rascunho sem `advisorId` com `onDraftChange`); o editor do detalhe não pode herdar a troca; a tabela continua com scroll horizontal e o overlay não depende do layout da tabela.
|
||||
|
||||
## Dependências
|
||||
|
||||
- Nenhuma (C141 entregue — badge + editor; C142 entregue — e2e `campaignPermissionProfile` não toca o badge, sem risco de seletor).
|
||||
|
||||
## Fora de escopo
|
||||
|
||||
- Outros popovers do `/campanha` (mantêm seus contêineres atuais).
|
||||
- Editor embutido na página de detalhe do assessor.
|
||||
- Conteúdo, combos, nota e regras de permissão do C141.
|
||||
- Cards mobile da tabela de assessores.
|
||||
|
||||
## Rabbit holes de produto
|
||||
|
||||
- **Cascata de troca de popovers.** Se alguém "só completar": converter todas as superfícies com popover do `/campanha`. **Corte neste item:** só o badge de permissão; outras superfícies decidem em itens próprios.
|
||||
- **Editor embutido no badge.** Se alguém "só completar": o badge abrir um editor inline na célula. **Corte neste item:** overlay central/drawer, sempre.
|
||||
- **Breakpoint na tabela.** Se alguém "só completar": introduzir estado responsivo na `AdvisorsTable`. **Corte neste item:** o sinal `useNarrowMeasured(640)` vive no badge/overlay, não na tabela.
|
||||
|
||||
## Questões em aberto (produto)
|
||||
|
||||
- **Bottom vs top drawer?** **Opções:** bottom (default do primitivo) | top (como C123 usou para a agenda). **Recomendação:** bottom — o editor é curto, o botão Salvar fica perto dos polegares e o `max-h` do drawer mantém tudo na tela; o top do C123 era um quirk do C103, não um padrão. _(assumido — validar com produto)_
|
||||
- **Salvar fecha o overlay?** **Opções:** fecha | mantém aberto com feedback. **Recomendação:** fecha, como o popover atual já faz (`onSaved` → fecha); o badge atualizado é o feedback. _(assumido — validar com produto)_
|
||||
- **Footer Cancelar/Salvar no modal?** **Opções:** mantém o footer do editor (Cancelar condicional) | só Salvar. **Recomendação:** mantém o footer exatamente como está — o conteúdo do editor é intocável.
|
||||
|
||||
## Referências
|
||||
|
||||
- Rascunho UI (gate): `docs/plans/permissao-assessores-modal-central-ui-draft.html` (novo; tema do `docs/plans/permissao-granular-assessores-ui-draft.html` do C141)
|
||||
- `src/components/campaign/advisor/AdvisorPermissionBadge.tsx` — ponto único da troca de invólucro
|
||||
- `src/components/campaign/advisor/AdvisorPermissionEditor.tsx` — conteúdo intocado
|
||||
- `src/components/campaign/advisor/AdvisorsTable.tsx` — usos do badge (linha de dados ~473, rascunho ~351)
|
||||
- `src/app/(campaign)/campanha/(app)/assessores/[id]/page.tsx` — editor embutido no detalhe (fora de escopo)
|
||||
- `src/hooks/use-mobile.ts` (`useNarrowMeasured(640)`) + `src/components/ui/Dialog.tsx` + `src/components/ui/Drawer.tsx` (default bottom-anchored)
|
||||
- Precedente C123: `docs/plans/agenda-criacao-modal-central-impl.md`
|
||||
- Célula "Carteira do assessor" da mesma tabela (`RelationChipCell` variant="sheet" → `CampaignListSheetProvider`)
|
||||
Loading…
Reference in a new issue