Merge pull request #440 from fsolla/plans/c92-c95-agenda-header-feed
docs(plans): C92–C95 — agenda: feed link, sem-filtros, combobox e header do app
This commit is contained in:
commit
d48cb9ed91
4 changed files with 310 additions and 0 deletions
72
docs/plans/c92-corrigir-criacao-link-import-agenda.md
Normal file
72
docs/plans/c92-corrigir-criacao-link-import-agenda.md
Normal file
|
|
@ -0,0 +1,72 @@
|
|||
# C92 — Link de import da agenda: corrigir criação do feed (erro ao gerar)
|
||||
|
||||
Status: rascunho
|
||||
Atualizado em: 2026-08-08
|
||||
Issue: #436
|
||||
Priority: P1
|
||||
Model: composer-2.5
|
||||
Model-local: deepseek-v4-flash-high
|
||||
Impeccable: A — N/A sem UI (mesmo diálogo; comportamento corrigido)
|
||||
Canvas UI: N/A — sem UI
|
||||
Appetite: ~0,5–1 dia eng; um outcome verificável — staff gera o link de import nomeando o feed
|
||||
Responsável: —
|
||||
|
||||
## Dependência rápida
|
||||
|
||||
- **Sucessor de C16 (#392, _done/in-prod_):** o fluxo de "link de import" foi entregue mas a criação quebra no ar. Plano de C16 imutável; este é um item novo.
|
||||
|
||||
## Intenção
|
||||
|
||||
A sincronização com Google Calendar (C16) foi entregue, mas **ninguém consegue gerar o link**: ao digitar um nome e confirmar, o app responde "Não foi possível criar o feed de calendário." A funcionalidade fica inútil exatamente onde deveria destravar o valor (assinar o recorte da agenda no GCal da equipe). Queremos que gerar o link funcione para todo o staff, com o fluxo real (nomear → link → copiar/revogar) intacto.
|
||||
|
||||
**Causa raiz verificada localmente (repro):** a collection `calendarFeed` marca `secretSlug`/`createdBy` como campos de sistema com acesso de escrita restrito a admin do Payload (`canSetCalendarFeedSystemField`). A server action cria o feed com `overrideAccess: false` e actor `campaignUser` — o create falha (campos "obrigatórios" não graváveis) e o `catch` engole o erro numa mensagem genérica. Repro: create OK com `overrideAccess: true`; falha com `overrideAccess: false` + `user` `campaignUser`. O executor reconfirma e decide o ajuste (acesso do campo vs forma do create) — aqui fica só o sintoma e o conjunto afetado.
|
||||
|
||||
## Persona e fluxo
|
||||
|
||||
- **Persona / contexto:** coordenador ou assessor (staff) na agenda, montando um recorte ("só deputado presente", "só meu município") para a equipe acompanhar no Google Calendar.
|
||||
- **Job principal:** obter o link de import do filtro atual para colar no GCal.
|
||||
- **Fluxo desejado:** aplica filtro → "Link de import" → nomeia o feed → recebe URL → copia/revoga. **Hoje morre no passo "nomeia".**
|
||||
- **Anti-goals de produto:** nenhum novo — manter C16: sem sync bidirecional; Teqo SoT; fail-closed do acesso no read do feed.
|
||||
|
||||
## Objetivo e aceite
|
||||
|
||||
- Coordenador, assessor e candidato conseguem **gerar o link de import** após nomear o feed (sem erro).
|
||||
- O link gerado abre o feed correto do recorte (endpoint `/campanha/agenda/ical/[secret]` responde).
|
||||
- Listar feeds ativos e **revogar** continuam funcionando.
|
||||
- O erro real não é mais engolido numa mensagem genérica sem rastro — o fallback segue amigável, mas sem mascarar quebra de acesso/configuração.
|
||||
- Não vaza municípios fora do escopo do criador (invariante de C16 preservado).
|
||||
|
||||
## Dados (intenção)
|
||||
|
||||
- **Vou apresentar dados?** Não.
|
||||
- **Decisões desbloqueadas:** "posso assinar o recorte da agenda no Google?" — desbloqueada ao funcionar.
|
||||
- **Forma:** N/A.
|
||||
|
||||
## Direção no codebase (hipótese)
|
||||
|
||||
- **Áreas prováveis:** `src/utilities/access/calendarFeeds.ts` (acesso de escrita dos campos de sistema `secretSlug`/`createdBy`), `src/app/(campaign)/campanha/actions/calendarFeed.ts` (`createCalendarFeedLinkRecord`, `overrideAccess`/`user`), `src/collections/CalendarFeed.ts` (definição dos campos de sistema), com repro provável em `src/utilities/calendarFeed.ts`.
|
||||
- **Precedente a olhar:** como outras server actions da campanha gravam campos `systemStampedActorField` com actor `campaignUser` (ex. `supporter`/`activity`) — o padrão que já funciona no repo.
|
||||
- **Risco de acoplamento:** acesso é área "nunca economizar" (AGENTS.md) — mudança mínima e com teste de acesso (staff cria; leader/especulador não; read do feed segue fail-closed).
|
||||
|
||||
## Dependências
|
||||
|
||||
- Nenhuma dura. Sequencia antes de C93 (sem criação funcionando, falar de "sem filtros" é prematuro).
|
||||
|
||||
## Fora de escopo
|
||||
|
||||
- Permitir gerar sem filtros → **C93**.
|
||||
- Layout do botão/diálogo → **C94**.
|
||||
|
||||
## Rabbit holes de produto
|
||||
|
||||
- **"Completar" o fix virando refactor de access.** Se alguém "só arrumar": mexer em todos os campos de sistema e padrões de access do repo. **Corte neste item:** ajuste local no `calendarFeed` (campo/action), validado por repro e teste de acesso.
|
||||
|
||||
## Questões em aberto (produto)
|
||||
|
||||
- Nenhuma — bug com causa raiz reproduzida; decisão é de execução.
|
||||
|
||||
## Referências
|
||||
|
||||
- GitHub Issue #392 (C16, intenção imutável)
|
||||
- `docs/plans/sync-teqo-google-calendar.md` / `-impl.md`
|
||||
- Repro local: create OK com `overrideAccess:true`; falha com `overrideAccess:false` + `user: campaignUser` (`calendarFeed` → campos `secretSlug`/`createdBy` com `setAccess` só admin)
|
||||
70
docs/plans/c93-gerar-link-import-sem-filtros.md
Normal file
70
docs/plans/c93-gerar-link-import-sem-filtros.md
Normal file
|
|
@ -0,0 +1,70 @@
|
|||
# C93 — Gerar link de import sem filtros (agenda completa do escopo)
|
||||
|
||||
Status: rascunho
|
||||
Atualizado em: 2026-08-08
|
||||
Issue: #437
|
||||
Priority: P2
|
||||
Model: composer-2.5
|
||||
Model-local: deepseek-v4-flash-high
|
||||
Impeccable: B — encaixe no botão "Link de import" (ativa ação hoje desabilitada; sem rearranjo de layout)
|
||||
Canvas UI: coberto pelo plan-c94-ui-draft.canvas.tsx (mesmo botão, estado-alvo do C94)
|
||||
Appetite: ~0,5 dia eng; um outcome verificável — com zero filtros, gera-se o link da agenda completa do meu escopo
|
||||
Responsável: —
|
||||
|
||||
## Dependência rápida
|
||||
|
||||
- **Sucessor de C16 (#392, _done/in-prod_):** a intenção de C16 condicionava o link a um filtro ativo; produto agora quer o caso "sem filtros". Plano de C16 imutável.
|
||||
- **Dura (soft): [C92](c92-corrigir-criacao-link-import-agenda.md)** — sem a criação funcionando, esse fluxo não se valida.
|
||||
|
||||
## Intenção
|
||||
|
||||
Hoje o botão "Link de import" fica **desabilitado sem filtros**: quem quer simplesmente assinar **toda** a agenda da campanha no Google não consegue. Na mesa do coordenador, "agenda completa do meu escopo" é um desejo legítimo — o time inteiro acompanhando tudo que está em Teqo, sem montar filtro nenhum. Queremos destravar o feed **sem filtro**: o recorte passa a ser tudo que o criador tem permissão de ver (portfólio acessível), mantendo revogação e fail-closed iguais.
|
||||
|
||||
## Persona e fluxo
|
||||
|
||||
- **Persona / contexto:** coordenador quer o calendário completo da campanha (ou assessor, todo o portfólio dos municípios que administra) sempre atualizado no GCal da equipe.
|
||||
- **Job principal:** gerar o link de import da agenda inteira — sem precisar inventar um filtro.
|
||||
- **Fluxo desejado:** abre a agenda (sem filtros) → "Link de import" habilitado → nomeia → copia/revoga. **Hoje:** botão cinza, sem ação.
|
||||
- **Anti-goals de produto:** feed "sem filtro" não é um backdoor — continua valendo o escopo do criador e a fail-closed (perdeu acesso a um município → feed para de incluir; criador desativado → feed para de servir).
|
||||
|
||||
## Objetivo e aceite
|
||||
|
||||
- Com **nenhum filtro ativo**, o botão "Link de import" permite gerar o link.
|
||||
- O feed sem filtro cobre a agenda completa **dentro do escopo de leitura do criador** (coordinator/candidate = tudo; advisor = municípios administrados).
|
||||
- Revogar/listar e o endpoint de leitura seguem com acesso fail-closed (invariante de C16).
|
||||
- Sem PII nova; sem Consent novo (mesma base de C16).
|
||||
|
||||
## Dados (intenção)
|
||||
|
||||
- **Vou apresentar dados?** Não.
|
||||
- **Decisões desbloqueadas:** "posso assinar a agenda completa do meu escopo?" — sim.
|
||||
- **Forma:** N/A.
|
||||
|
||||
## Direção no codebase (hipótese)
|
||||
|
||||
- **Áreas prováveis:** `src/components/campaign/activity/ActivityAgendaFilters.tsx` (gate `hasFilters` → disabled do botão) e `src/utilities/calendarFeed.ts` / action `src/app/(campaign)/campanha/actions/calendarFeed.ts` (construir feed sem filtros = só o escopo do criador).
|
||||
- **Precedente a olhar:** intenção e impl de C16 (`docs/plans/sync-teqo-google-calendar*`), que já previam `filterMunicipality` vazio = "todos os municípios do escopo do criador" (descrição do campo na collection).
|
||||
- **Risco de acoplamento:** o layout do botão muda no C94 — este item só destrava o **estado permitido**; o executor deve reconciliar com o estado final do C94.
|
||||
|
||||
## Dependências
|
||||
|
||||
- C92 (soft — validação pós-fix).
|
||||
|
||||
## Fora de escopo
|
||||
|
||||
- Layout do botão / ícone no header / ação rápida → **C94**.
|
||||
- Escolher "tudo" vs "recorte" por UX (pedido de confirmação) → não; o feed sem filtro é direto.
|
||||
|
||||
## Rabbit holes de produto
|
||||
|
||||
- **Feed sem filtro virando "exportar tudo para sempre".** Se alguém "só completar": janela temporal ilimitada ou sem fail-closed. **Corte neste item:** mantém janela deslizante e access por leitura (decisões de C16 intactas).
|
||||
|
||||
## Questões em aberto (produto)
|
||||
|
||||
- **Emparelhar com o estado-alvo do C94?** O botão do C94 vira ícone no header. **Recomendação:** C93 pode entrar antes (habilita o botão atual) e o C94 herda o estado habilitado; sem ordem obrigatória. _(assumido — validar)_
|
||||
|
||||
## Referências
|
||||
|
||||
- GitHub Issue #392 (C16, intenção imutável)
|
||||
- Canvas UI do C94: `plan-c94-ui-draft.canvas.tsx`
|
||||
- Campo `filterMunicipality` da collection `calendarFeed`: "Se vazio, inclui todos os municípios do escopo do criador" (base pronta para o sem-filtro)
|
||||
87
docs/plans/c94-agenda-combobox-header-acoes-rapidas.md
Normal file
87
docs/plans/c94-agenda-combobox-header-acoes-rapidas.md
Normal file
|
|
@ -0,0 +1,87 @@
|
|||
# C94 — Agenda: filtro combobox único, header compacto (ícones) e ações no FAB mobile
|
||||
|
||||
Status: rascunho
|
||||
Atualizado em: 2026-08-08
|
||||
Issue: #438
|
||||
Priority: P1
|
||||
Model: cursor-grok-4.5-medium
|
||||
Model-local: deepseek-v4-high
|
||||
Impeccable: C — redesign local da toolbar/header da agenda (`/campanha/agenda`)
|
||||
Canvas UI: /home/fsolla/.cursor/projects/home-fsolla-Code-teqo/canvases/plan-c94-ui-draft.canvas.tsx
|
||||
Appetite: ~1–1,5 dia eng; um outcome verificável — toolbar consolidada (combobox único + ícones) e uma só entrada "Nova atividade"/"Link de import" por viewport
|
||||
Responsável: —
|
||||
|
||||
## Intenção
|
||||
|
||||
A barra da agenda (C15) foi construída como 3 seletores avulsos (Município, Tag, "Deputado presente") + botões de ação, e hoje **duplica** caminhos: no mobile o usuário vê dois botões de criação na página **e** as mesmas ações no FAB; o "Link de import" vive dentro do card de filtros. Resultado: superfície sem hierarquia e fluxo redundante. Queremos consolidar:
|
||||
|
||||
1. **Um filtro combobox único** (chassis omnibox já usado em `/campanha/municipios` e nas listas) no lugar dos 3 seletores — com chips removíveis e sugestões agrupadas.
|
||||
2. **Mobile:** tirar os botões de criação da página; a entrada vira **ação rápida no FAB**. "Link de import" também entra como ação rápida.
|
||||
3. **Desktop:** um **ícone "+" (Nova atividade)** logo à direita do combobox, e o **"Link de import" como botão-ícone no header do app** (barra superior junto do AI chat e das notificações, agenda-contextual).
|
||||
|
||||
## Persona e fluxo
|
||||
|
||||
- **Persona / contexto:** coordenador e assessor de mesa (desktop) e de campo (mobile) usando a agenda para planejar e acompanhar compromissos.
|
||||
- **Job principal:** filtrar e criar/assinar de forma consistente, com um caminho só por gesto.
|
||||
- **Fluxo desejado (desktop):** combobox filtra (chips) → "+" ao lado abre o formulário de nova atividade com o recorte → ícone de calendário abre o diálogo de "Link de import" (mantém nomear → copiar → revogar).
|
||||
- **Fluxo desejado (mobile):** combobox filtra → FAB abre o drawer → ações: "Nova atividade", "Link de import", "Planejar giro" (as existentes de lista permanecem).
|
||||
- **Anti-goals de produto:** manter a criação inline por clique no slot (C91) e o fluxo de giro (compositor) intactos; não virar um header de segundo nível com stack de sub-nav.
|
||||
|
||||
### Esboço de fluxo (C)
|
||||
|
||||
```text
|
||||
desktop: [header app: título agenda … AI chat][Link de import][notif.] [toolbar: combobox][carrinho: giro][+ nova atividade]
|
||||
mobile : [top bar app: título agenda … Link de import/FAB][notif.] + FAB → drawer [Nova atividade][Link de import][Planejar giro]
|
||||
```
|
||||
|
||||
## Objetivo e aceite
|
||||
|
||||
- Os 3 filtros (Município, Tag, Deputado presente) ficam **num combobox único** com chips removíveis e "Limpar" (chassis omnibox), substituindo os seletores nativos e o botão "Limpar filtros".
|
||||
- **Toolbar da página (desktop):** `[combobox] [ícone carrinho: Planejar giro] [ícone "+": Nova atividade]` — decisão de produto confirmada no gate (`combobox→giro→+`).
|
||||
- **"Link de import" no header do app (desktop), não na toolbar:** vira **botão-ícone na barra superior** (`CampaignDesktopHeader`), no cluster à direita onde já ficam o botão do Sollinha/AI chat e o de notificações — **agenda-contextual** (só aparece na rota `/campanha/agenda`). O diálogo nomear→copiar→revogar permanece igual.
|
||||
- **Mobile:** nenhum botão de criação no corpo da página; "Nova atividade" e "Link de import" como ações rápidas no drawer do FAB (com o filtro atual); "Link de import" abre o mesmo diálogo como **sheet** (decisão confirmada no gate).
|
||||
- O estado do filtro segue refletido na URL (padrão de navegação das listas); reload e share continuam consistentes.
|
||||
- Sem regressão: criação inline no slot (C91), giros, revogação de feeds, leader lockdown.
|
||||
|
||||
## Dados (intenção)
|
||||
|
||||
- **Vou apresentar dados?** Não (filtro = navegação/URL, não apresentação de dados).
|
||||
- **Decisões desbloqueadas:** "vejo/dou manutenção ao recorte da agenda com um gesto só".
|
||||
- **Forma:** adiada (chips/sugestões do omnibox já é o padrão do repo).
|
||||
|
||||
## Direção no codebase (hipótese)
|
||||
|
||||
- **Áreas prováveis:** `src/components/campaign/activity/ActivityAgendaFilters.tsx` (vira o adaptador do combobox), `src/utilities/activityOmnibox.ts` (precedente de chips/sugestões para o estado de agenda — reuso ou adaptação), `src/components/campaign/shared/CampaignListOmnibox.tsx` (chassis), `src/app/(campaign)/campanha/(app)/agenda/page.tsx` (toolbar `[combobox][giro][+]`), e o registro de ações rápidas (`src/lib/activityQuickActions.ts` / `campaignQuickAction*`) para "Link de import" no mobile.
|
||||
- **Header do app (desktop):** o "Link de import" entra como controle **agenda-contextual** em `src/components/campaign/shell/CampaignDesktopHeader.tsx` (cluster à direita, ao lado de `CampaignAIHeaderButton` e do sino). O mesmo mecanismo de chrome por-página usado hoje pelo título (`CampaignPageChromeDisplay`/contexto) serve de pista para o slot contextual — o executor decide o encaixe menos invasivo (slot no header vs renderizar no shell pela rota).
|
||||
- **Precedente a olhar:** B127/B138 (omnibox nas listas), B126/B132 (FAB de ações rápidas), B120 (combobox mobile em municípios).
|
||||
- **Risco de acoplamento:** o header do app é **compartilhado por todas as rotas** `/campanha` — qualquer controle novo precisa ser agenda-contextual para não poluir as demais telas; coordenar com C95 (mesmo header, mesmo slot). C91 inline create só adiciona overlay; sem conflito de intent. Coordenar com C92/C93 (dialog de feed) para o ícone não ser porta morta.
|
||||
|
||||
## Dependências
|
||||
|
||||
- C92 (soft — o ícone de feeed só vale com criação funcionando).
|
||||
|
||||
## Fora de escopo
|
||||
|
||||
- Gerar feed sem filtros → **C93** (o ícone reflete apenas o estado habilitado/desabilitado do momento).
|
||||
- Redesign do calendário em si (C15) e do overlay de criação inline (C91).
|
||||
- Mudanças no compositor de giro.
|
||||
|
||||
## Rabbit holes de produto
|
||||
|
||||
- **Combobox vira "omnibox de busca global" da agenda.** Se alguém "só completar": busca por texto livre, presets de janela, múltiplos municípios simultâneos. **Corte neste item:** Município (único) + Tag + Deputado presente, como hoje; sem busca textual nem multi-seleção.
|
||||
- **Header vira barra de navegação.** Manter no máximo 3 controles + o botão de giro secundário; nada de stacks de sub-nav.
|
||||
|
||||
## Questões em aberto (produto)
|
||||
|
||||
- **"Planejar giro" no desktop?** **Decidido no gate:** vira **ícone carrinho**, na toolbar, entre o combobox e o "+" (ordem `[combobox][giro][+]`). Fora de questão.
|
||||
- **"Deputado presente" como chip?** **Decidido no gate:** chip bool no combobox. Fora de questão.
|
||||
- **Mobile: rápida de feed mantém o diálogo atual?** **Decidido no gate:** sim, como **sheet**. Fora de questão.
|
||||
- **Onde mora o "Link de import" desktop?** **Decidido no gate:** no **header do app** (cluster à direita, junto do AI chat/notificações), agenda-contextual — não na toolbar. Fora de questão.
|
||||
- **Chip de município permite trocar sem remover?** **Opções:** A) com sugestões marcando o ativo ao reabrir | B) só remove→re-adiciona. **Recomendação:** indistinguível ao usuário fora do detalhe; deixa o executor escolher a mecânica barata que satisfaz (A). _(assumido — validar)_
|
||||
- **Ordem no header do app (desktop):** **Decidido no gate** — `[título …][Semana ▾ (C95)][Link de import][Notificações][IA]`. Fora de questão.
|
||||
|
||||
## Referências
|
||||
|
||||
- GitHub Issue #392 (C16 — sync/feed), #390 (C15 — agenda), #428 (C91 — criar inline)
|
||||
- Canvas UI (gate): `/home/fsolla/.cursor/projects/home-fsolla-Code-teqo/canvases/plan-c94-ui-draft.canvas.tsx`
|
||||
- Precedente: `CampaignListOmnibox` (B127), `atividades-omnibox-presets-busca` (B138), FAB de ações rápidas (B126/B132)
|
||||
81
docs/plans/c95-agenda-seletor-modo-visualizacao.md
Normal file
81
docs/plans/c95-agenda-seletor-modo-visualizacao.md
Normal file
|
|
@ -0,0 +1,81 @@
|
|||
# C95 — Agenda: seletor do modo de visualização no header do app (mobile e desktop)
|
||||
|
||||
Status: rascunho
|
||||
Atualizado em: 2026-08-08
|
||||
Issue: #439
|
||||
Priority: P2
|
||||
Model: composer-2.5
|
||||
Model-local: deepseek-v4-flash-high
|
||||
Impeccable: B — encaixe no header global do shell (controle compacto; sem redesign)
|
||||
Canvas UI: coberto/atualizado com o plan-c94-ui-draft.canvas.tsx (header do app com o seletor)
|
||||
Appetite: ~0,5–1 dia eng; um outcome verificável — trocar o modo de visualização (semana/dia/mês/lista) por um seletor único no header do app, sem aumentar o header
|
||||
Responsável: —
|
||||
|
||||
## Dependência rápida
|
||||
|
||||
- **Com [C94](c94-agenda-combobox-header-acoes-rapidas.md) (coordenar):** os dois tocam o **header do app** (`CampaignDesktopHeader`/`CampaignMobileTopBar`) — C94 coloca o "Link de import" lá; C95 coloca o seletor de vista.**Sequenciar com C94** (slot agenda-contextual é construído por um, reutilizado pelo outro), mas sem ordem dura fixa.
|
||||
|
||||
## Intenção
|
||||
|
||||
Hoje o troca-modo do calendário (semana/dia/mês/lista) vive nos **botões embutidos** do próprio FullCalendar (cada modo com seu botão), no meio da página. Os controles do calendário devem morar no **header do app** — a barra superior do `/campanha` onde já ficam o título da página, o botão do Sollinha/AI chat e o de notificações — tanto em desktop quanto em mobile. Em vez de um botão por modo, **um seletor único** ("Semana ▾"), compacto o bastante para **não aumentar o tamanho do header**. No mobile, a mesma barra superior (título + sino) ganha o seletor no mesmo gesto.
|
||||
|
||||
## Persona e fluxo
|
||||
|
||||
- **Persona / contexto:** coordenador/assessor alternando entre vista de dia, semana, mês ou lista conforme o gesto: no campo (mobile) quer o dia; na mesa (desktop) quer a semana com o mês à esquerda para saltar.
|
||||
- **Job principal:** trocar o modo de visualização com um controle só, **no header do app** (onde já olha título/sino/AI), sem perder o estado do filtro nem o recorte.
|
||||
- **Fluxo desejado:** header do app → seletor "Semana ▾" → escolhe "Mês" → calendário muda a vista; escolha vale para a sessão e sobrevive ao reload (vira parte do estado da tela, junto do filtro).
|
||||
- **Anti-goals de produto:** não duplicar com os botões do FullCalendar (remover `end` do `headerToolbar`); não empilhar segunda linha de controles; não esconder o modo ativo; **não aumentar a altura/forma do header**.
|
||||
|
||||
### Esboço de fluxo (B)
|
||||
|
||||
```text
|
||||
[header] seletor "Semana ▾" → [Dia|Semana|Mês|Lista] → calendário muda → escolha persiste
|
||||
```
|
||||
|
||||
## Objetivo e aceite
|
||||
|
||||
- Um **seletor único** de modo de visualização no **header do app** (`CampaignDesktopHeader` no desktop; `CampaignMobileTopBar` no mobile), **agenda-contextual** (só na rota `/campanha/agenda`), substituindo os 4 botões do FullCalendar.
|
||||
- O seletor **não aumenta a altura do header** (mantém `min-h-11` desktop / `min-h-14` mobile; só insere o controle compacto na linha existente, junto do título/sino/AI chat).
|
||||
- Modos disponíveis: Dia (`timeGridDay`), Semana (`timeGridWeek`), Mês (`dayGridMonth`) e Lista (`listMonth`) — os mesmos de hoje.
|
||||
- A escolha persiste por sessão/reload (estado da tela, junto do filtro) e respeita o recorte do filtro.
|
||||
- Sem regressão: navegação prev/next/hj continua no FullCalendar; criação inline (C91) intacta; leader lockdown; demais telas `/campanha` sem o seletor (contextual).
|
||||
|
||||
## Dados (intenção)
|
||||
|
||||
- **Vou apresentar dados?** Não.
|
||||
- **Decisões desbloqueadas:** "estou olhando o recorte do jeito certo para o meu gesto".
|
||||
- **Forma:** adiada (select compacto vs segmented são igualmente válidos; cabe ao executor, respeitando "não crescer o header").
|
||||
|
||||
## Direção no codebase (hipótese)
|
||||
|
||||
- **Áreas prováveis:** `src/components/campaign/shell/CampaignDesktopHeader.tsx` + `src/components/campaign/shell/CampaignMobileTopBar.tsx` (slot do seletor, agenda-contextual; o mecanismo de chrome por-página do `CampaignPageChromeDisplay`/contexto é a pista para o encaixe), `src/components/campaign/activity/ActivityAgenda.tsx` (remover botões de modo do `headerToolbar`; conectar o seletor ao `changeView` via `calendarRef`), e o estado de vista eventualmente junto ao `ActivityAgendaState`/URL (persistência).
|
||||
- **Precedente a olhar:** C91 (`agenda-criar-evento-inline.md`) mexe no mesmo FullCalendar; o "Link de import" do C94 entra no mesmo header do app — coordenar slot/ordem.
|
||||
- **Risco de acoplamento:** o header do app é **compartilhado por todas as rotas** `/campanha` — o seletor precisa ser agenda-contextual para não poluir as demais telas. A lógica responsiva que hoje troca semana↔dia ao redimensionar (narrow) precisa reconciliar com um modo **escolhido pelo usuário** — a escolha do usuário deve vencer (detalhe de interação, não de layout).
|
||||
|
||||
## Dependências
|
||||
|
||||
- C94 (coordenar — mesmo header do app / slot agenda-contextual; serializar na fila).
|
||||
|
||||
## Fora de escopo
|
||||
|
||||
- Redesign do FullCalendar (C15); criação inline (C91).
|
||||
- Mover prev/next/"Hoje" para o header (mantém dentro do calendário).
|
||||
- Persistência entre dispositivos/contas (só sessão/tela).
|
||||
- O slot agenda-contextual do header em si — construído junto do "Link de import" (C94) e reutilizado aqui.
|
||||
|
||||
## Rabbit holes de produto
|
||||
|
||||
- **Seletor vira barra de controles.** Se alguém "só completar": arrastar prev/next/título/modo tudo pro header do app. **Corte neste item:** só o seletor de modo; navegação permanece no calendário.
|
||||
- **Crescer o header.** O gatilho "só mais um controle" vira segunda linha ou aumenta `min-h`. **Corte:** um controle único compacto, dentro da linha existente do header do app.
|
||||
|
||||
## Questões em aberto (produto)
|
||||
|
||||
- **Controle: select texto vs segmented de ícones.** **Opções:** A) select/dropdown compacto (rótulo do modo atual + ▾) | B) segmented com 4 ícones. **Recomendação:** A — é o que cabe na linha única sem crescer; 4 segmentos não. _(assumido — validar)_
|
||||
- **Posição no header do app (desktop).** **Decidido no gate:** cluster direito na ordem `[Semana ▾][Link de import][Notificações][IA]` — o seletor é o primeiro do cluster da agenda. No mobile, junto ao sino, à direita do título. Fora de questão.
|
||||
- **Escolha do usuário × auto-responsivo.** **Opções:** A) escolha do usuário vence e não é trocada por resize (só o default muda por viewport) | B) resize continua forçando de volta. **Recomendação:** A — o usuário que escolheu mês não deve ser jogado de volta ao fechar o teclado. _(assumido — validar)_
|
||||
|
||||
## Referências
|
||||
|
||||
- GitHub Issue #390 (C15 — agenda FullCalendar), #428 (C91 — criar inline)
|
||||
- Canvas UI (gate): `/home/fsolla/.cursor/projects/home-fsolla-Code-teqo/canvases/plan-c94-ui-draft.canvas.tsx` (header-alvo com o seletor)
|
||||
- `ActivityAgenda.tsx` (`headerToolbar` `end: 'timeGridWeek,timeGridDay,dayGridMonth,listMonth'`; `MOBILE_BREAKPOINT_PX`)
|
||||
Loading…
Reference in a new issue