portal_publico/docs/favoritos/favoritos.md

15 lines
2.4 KiB
Markdown

# Favoritos: como o ID de uma aplicação é derivado
> Movido do `CLAUDE.md` da raiz em 2026-08-26 para reduzir conflito de edição entre aplicações. Ver `CLAUDE.md` na raiz para arquitetura geral/transversal do Portal. Este arquivo não é auto-carregado pelo Claude Code — leia manualmente ao mexer em `favorites.js` ou no sidebar/menu.
`favorites.js` não depende de nenhum atributo `data-*` dedicado para identificar "o que é favoritável" — ele varre `.sidebar a.nav-item, .sidebar a.nav-subitem` e deriva um ID estável a partir da própria estrutura/texto do menu (`pidCollectFavoritableApps`), igual a antes da migração. Esse ID é o que vira `app_id` em `POST /api/favoritos/` e na URL de `DELETE /api/favoritos/{app_id}/`:
- Se o `<li>` do link já tem `data-section`, o ID é esse valor (ex.: `"ramais"`).
- Caso contrário (é um sub-item dentro de um `nav-group`), o ID é `"<data-section do grupo pai>__<slug do texto do link>"` (ex.: `"portais__portal-do-cliente"`).
O slug (`pidSlug`) normaliza acentos (NFD) e troca sequências de caracteres não `[a-z0-9]` por `-`. Se o texto de um label mudar, o `app_id` derivado muda junto (favoritos existentes referenciando o ID antigo deixam de casar) — mesmo caveat vale se a estrutura do menu mudar (ex.: um item vira `nav-group` expansível, ver `docs/links-ferramentas-acessos-gerais/links-ferramentas-acessos-gerais.md`, "Links & Ferramentas": um favorito antigo `app_id === "links-ferramentas"` parou de casar quando a seção virou dois sub-itens).
**Reordenar os cards favoritos**: `Favorito.ordem` (`PositiveIntegerField`, `Meta.ordering = ["ordem", "id"]`) — mesmo padrão de `LinkFerramenta`/`WidgetUsuario`: `FavoritoViewSet.perform_create` atribui `ordem = max(ordem atual do usuário) + 1`, e reordenar é drag-and-drop nativo em `#app-card-grid` (`favorites.js`, `dragstart`/`dragover`/`drop`, `PATCH /api/favoritos/{app_id}/` só nos itens cujo `ordem` mudou) — mesma mecânica de Widgets/Links & Ferramentas (ver `docs/calendario-individual/calendario-individual.md`/`docs/links-ferramentas-acessos-gerais/links-ferramentas-acessos-gerais.md`). `.app-card` inteiro é `draggable="true"` (não precisa de um handle separado como os widgets, já que não tem `resize` pra conflitar); o botão de remover (`.app-card__remove`) é `draggable="false"` pra não interferir.
`.app-card*` mora em `components.css` (junto de outra UI genérica reutilizável).