The "Municípios" column was dead text; it is now chips that navigate to the município, with a territory chip when a leadership covers a whole TI, and it is editable in place. What picks inline vs. Drawer is the `pointer:` media query, not viewport width: on a fine pointer the editor is always mounted (the "×" sits at the chip's corner, revealed on hover/focus) and on a coarse pointer a tap anywhere in the cell opens a Drawer with 44 px targets. `AdvisorMunicipalityCell` is promoted to `shared/MunicipalityPortfolioCell` and /campanha/assessores migrates onto it in the same change, so the second call site is born with the first. One batch action only; the single-id advisor twin is deleted with its int tests migrated. The anti-goal on always-mounted list inputs is amended for chip-based relations on fine pointers, not reopened. Also fixes a latent bug: `CampaignTableHead`'s `description` seam broke any RSC caller, because its two helpers lived in a 'use client' module.
33 lines
2.9 KiB
Text
33 lines
2.9 KiB
Text
---
|
|
description: /campanha staff UIs — edit mutable data in context (not read-only by default)
|
|
globs: src/app/(campaign)/**/*,src/components/campaign/**/*,src/utilities/campaign*/**,src/utilities/municipality*/**,src/utilities/votePledge*
|
|
alwaysApply: false
|
|
---
|
|
|
|
# Edit where you see (`/campanha`)
|
|
|
|
Canonical principles: `PRODUCT.md` § Design Principles — **Edit where you see** + **Auto-save, no Save button**. Precedente: B9 (`MunicipalityList*Control` + `municipalityStaffFormActions`).
|
|
|
|
When adding or changing a **staff** (coordinator / advisor) view that displays mutable campaign data:
|
|
|
|
1. **Default to in-context edit** if the role can update that field — list cell, detail card, queue row — not a dead readout that only links to `/editar`.
|
|
2. **Reuse existing server actions** and the **same access** as the full form. Thin route wrappers OK; do not invent a generic quick-edit service (<3 call sites → named controls).
|
|
3. **UX pattern:** named Popover / select / short number input per affordance; touch `min-h-11`. **Auto-save** on select change, blur, or short debounce — no “Salvar” button on single-field / in-context edits. Show pending / saved / error on the control (Feel the action). Then server revalidate / RSC refresh.
|
|
- **Exception — relation-by-chips cells** (B34, 2026-07-27): a column whose value is a set of related records (municípios de uma liderança, carteira de um assessor) may mount its editor inline, always, **with a fine pointer** — chips with a hover/focus-revealed remove button plus a trailing "add" input, no Popover trigger and no table-wide "Editar" toggle. On any other pointer the same cell is a read-only trigger that opens a **Drawer** for editing, because a coarse pointer scrolling a table cannot be asked to distinguish "tap to navigate" from "tap to delete". This is the only sanctioned always-mounted input; single-value fields keep the Popover.
|
|
4. **Keep `/editar` (or long Sheet) + explicit submit** only for multi-field strategy forms, rare fields, and flows that need a note, confirmation, or legal consent.
|
|
5. **Never** expose staff-only fields to `leader`. View models stay role-split.
|
|
|
|
## Anti-goals
|
|
|
|
- Full-row spreadsheet / data-grid mode
|
|
- A table-wide "Editar" toggle that flips every column into inputs
|
|
- Always-mounted inputs on every list row — except the relation-by-chips cell of rule 3
|
|
- Generic `EditableCell` / contentEditable mass edit
|
|
- Optimistic UI that skips server refresh when the list is source of truth
|
|
- Save buttons on Popovers / quick-edit cells “just in case”
|
|
- Silent auto-save with no status feedback
|
|
- Saving on every keystroke for free-text without debounce
|
|
|
|
## Plan / Impeccable brief
|
|
|
|
For UI items (B/C/D): answer explicitly — _does this surface need in-context edit?_ Cite these principles and B9 when yes; name rabbit hole “spreadsheet mode” when scoping. Prefer auto-save over an explicit Save button unless the write is multi-field / confirmatory / consent.
|