# Menus do Site — O menu especial "Tags" e a integracao com o editor de layout

> Este documento detalha um item **nao portado** da v5 para a v6 e o mecanismo
> que o substituiu. Ele responde a pergunta "o que era o menu Tags e onde ele
> esta hoje".

---

## 1. O que era o menu "Tags" na v5

Na v5 existia um **quinto menu**, com `id = 5`, `name = 'Tags'` e `slug = 'tags'`,
criado por um seeder dedicado:

**Arquivo:** `v5/database/seeds/AddMenuTagsToProductionSeeder.php`

```php
public function run()
{
    // Only insert if not exists to be safe for production
    if (!DB::table('menus')->where('slug', 'tags')->exists()) {
        DB::table('menus')->insert([
            'id' => 5,
            'name' => 'Tags',
            'slug' => 'tags',
            'status_create' => '1'
        ]);
    }
}
```

O seeder **nao** e chamado pelo `v5/database/seeds/DatabaseSeeder.php` — e
executado manualmente (tipicamente em producao).

### 1.1 O widget que o consumia

**Arquivo:** `v5/database/seeds/AddMenuTagsWidgetSeeder.php`

```php
DB::table('layouts')->updateOrInsert(
    [
        'key' => 'menu-tags-widget',
    ],
    [
        'section' => 'tags',
        'type' => 'element',
        'title' => 'Itens do menu TAGS',
        'value' => '<div class="menu-tags-sample"><div class="menu-tags-default text-center py-2" style="color:#000;text-align:center;">Itens do menu TAGS</div><ul class="list-unstyled d-flex flex-wrap gap-2" style="margin:0;padding:0;"></ul></div>',
        'order' => 0,
        'style' => 'width: 100%;',
        'status' => 1,
        'path' => 'portal.layouts.modelo5.layout.menus.menu_tags'
    ]
);
```

O `path` aponta para a view que renderiza o widget:

**Arquivo:** `v5/resources/views/portal/layouts/modelo5/layout/menus/menu_tags.blade.php`

```php
$menu = Menu::where('slug', 'tags')->first();
$items = collect();
if ($menu) {
    $items = MenuItem::with(['links', 'categoryContent', 'content'])
        ->where('menus_id', $menu->id)
        ->whereNull('menus_items_id')
        ->where(function($q){
            $q->where('is_active', 1)
              ->orWhere('is_active', true);
        })
        ->orderBy('order')
        ->get();
}
```

O widget renderiza os itens **raiz** do menu `tags` como etiquetas (tags) com
icone e link:

```php
<a href="{{ $presenter->getLink() }}" {!! $presenter->targetLink() !!} class="tag-link">{{ $item->name }}</a>
```

Se o menu `tags` nao existir, mostra "Nenhum item de menu cadastrado no menu Tags.".

---

## 2. Situacao na v6 (verificada)

| Item | v5 | v6 | Verificacao |
|---|---|---|---|
| `AddMenuTagsToProductionSeeder.php` | existe | **nao existe** | `ls v6/database/seeds/` — ausente |
| `AddMenuTagsWidgetSeeder.php` | existe | **nao existe** | idem |
| `portal/layouts/modelo5/layout/menus/menu_tags.blade.php` | existe | **nao existe** | `ls v6/resources/views/portal/layouts/modelo5/layout/menus/` -> "No such file or directory" |
| Linha `menus` com `slug = 'tags'` | criada pelo seeder | **nao existe** | `SELECT id,name,slug FROM menus ORDER BY id` -> 4 linhas (1 Principal, 2 Rodape, 3 Acesso Rapido, 4 Atalhos) |
| Layout `menu-tags-widget` | criado pelo seeder | **nao existe** | `SELECT key FROM layouts WHERE key='menu-tags-widget'` -> 0 linhas |
| Bloco `#modulos-select` na chave `tags` de `layouts` | n/a | **presente apenas no seeder** `UpdateModuloSelectOptions.php`; **nao aplicado** na base v6 | `SELECT (value like '%modulos-select%') FROM layouts WHERE key='tags'` -> `f` (o blob tem 76.302 caracteres e nao contem o bloco) |

**Conclusao:** na v6 o menu "Tags" **nao existe** e o widget de tags de menu
**nao existe**. O mecanismo foi substituido por outro (§3).

---

## 3. O substituto na v6: seletor de modulo do editor de layout

### 3.1 O seeder `UpdateModuloSelectOptions`

**Arquivo:** `v6/database/seeds/UpdateModuloSelectOptions.php`

O seeder **reescreve** o HTML da chave `tags` da tabela `layouts` (o "bloco de
tags" do editor de layout), substituindo o `div#modulos-select` por um novo:

```php
$novoBloco = '
        <div class="form-group mb-3" id="modulos-select" style="display: none;">
            <label style="color: #fff; font-weight: bold; display: block; margin-bottom: 8px;">Módulo</label>
            <select id="select-modulo" class="form-control" style="width: 100%; padding: 8px; border-radius: 4px; border: 1px solid #ced4da;">
                <option value="transparencia">Transparência Fiscal</option>
                <option value="secretaria">Secretaria</option>
                <option value="menus">Menus do Site</option>
                <option value="a-instituicao">A Instituição</option>
                <option value="paginas-estaticas">Páginas Estáticas</option>
            </select>
            <div id="sub-select-container"></div>
        </div>';
```

Caracteristicas do bloco:

- **Idempotente**: o seeder localiza o bloco antigo pelo atributo
  `id="modulos-select"` e, se nao existir, apenas adiciona o novo ao final.
- A localizacao do bloco usa **contagem de divs aninhadas**
  (`extrairBloco()` percorre o HTML contando `<div` e `</div>`), para nao corromper
  o HTML vizinho.
- O seeder **nao** e chamado pelo `v6/database/seeds/DatabaseSeeder.php` — precisa
  ser executado manualmente.
- A opcao `"Menus do Site"` (value `menus`) e a **ponte** entre o editor de
  layout e o modulo de menus.

### 3.2 O JavaScript do seletor

**Arquivo:** `v6/public/assets/js/custom/modelos_personalizados/module-selector.js`

```js
const MODULE_HAS_SUB = ['transparencia', 'menus'];
```

- `menus` e um dos modulos que exigem um **segundo select** (quais menus?).
- As opcoes do segundo select vem de `menusDisponiveis`, injetado no Blade por
  `LayoutController@edit`.
- Ao escolher, o JS faz `POST /cms/update-module-status` com
  `{ module: 'menus', subId: <id do menu> }` e grava no hidden
  `#modulo-selecionado` o valor `"menus:<id>"`.

### 3.3 O controller do editor de layout

**Arquivo:** `v6/app/Http/Controllers/Prefecture/LayoutController.php`

```php
$rawValue  = Layout::where('key', 'secretarias-grid')->value('value') ?? 'transparencia';
$legacyMap = ['0' => 'transparencia', '1' => 'secretaria', '2' => 'menus', '3' => 'transparencia'];
if (isset($legacyMap[$rawValue])) $rawValue = $legacyMap[$rawValue];

$parts        = explode(':', $rawValue, 2);
$activeModule = $parts[0];
$activeSubId  = $parts[1] ?? null;

$menusDisponiveis = \DB::table('menus')->orderBy('name')->get(['id', 'name', 'slug']);
```

E a persistencia:

```php
public function updateModuleStatus(Request $request): JsonResponse
{
    $module = $request->input('module');
    $subId  = $request->input('subId');
    $value  = $subId ? "{$module}:{$subId}" : $module;
    \DB::table('layouts')->updateOrInsert(
        ['key' => 'secretarias-grid'],
        ['value' => $value, 'type' => 'config', 'status' => 0, 'section' => '', 'order' => 0]
    );
    return response()->json(['success' => true]);
}
```

Ponto de armazenamento: a tabela `layouts`, chave `secretarias-grid`, com o
formato `"<modulo>"` ou `"<modulo>:<subId>"`.

> Na base v6 analisada **nao existe** a linha `secretarias-grid`; o valor
> effective e o fallback `'transparencia'`.

### 3.4 O consumo no portal (modelo5)

**Arquivo:**
`v6/resources/views/portal/layouts/modelo5/home/transparencia/transparencia-fiscal-grid.blade.php:34-49`

```php
} elseif ($isMenuAbas) {
    $menuTarget = $subId
        ? \App\Prefecture\Menu::find($subId)
        : \App\Prefecture\Menu::where('slug', 'abas')->first();
    $items = $menuTarget
        ? \App\Prefecture\MenuItem::where('menus_id', $menuTarget->id)
            ->whereNull('menus_items_id')
            ->orderBy('order')
            ->get()
        : collect();
    $itemsSearch = $items->map(function($item) {
        return [
            'title'   => $item->name,
            'url'     => $item->present()->getLink,
            'isBlank' => $item->isBlank ? 1 : 0,
        ];
    });
```

Quando o modulo escolhido e `menus`, a home do modelo5 renderiza os **itens raiz**
do menu escolhido como uma grade de cards (secao "Servicos"), com busca por
filtro (o `itemsSearch` alimenta o suggestions list do `input[type=search]`).

O fallback quando nao ha `subId` e o menu de slug `abas` — **que nao existe** na
base v6 (a tabela `menus` tem apenas 4 linhas). Resultado: a grade fica vazia.

---

## 4. Comparacao funcional v5 -> v6

| Capacidade | v5 | v6 |
|---|---|---|
| Menu especial de tags | Sim (`menus.slug = 'tags'`, id 5) | **Nao** |
| Widget de tags de menu no editor | Sim (`layouts.key = 'menu-tags-widget'`, `path = portal.layouts.modelo5.layout.menus.menu_tags`) | **Nao** |
| Renderizacao das tags no portal | Sim (etiquetas com icone e link) | **Nao** |
| Escolha de um menu para a home | Nao | **Sim** (`layouts.secretarias-grid = 'menus:{id}'`) |
| Opcao "Menus do Site" no seletor de modulo do editor | Nao | **Sim** (no seeder `UpdateModuloSelectOptions.php`) |

**Equivalencia funcional:** na v5, o menu `tags` era um menu como qualquer outro
(selecionado no CMS em `/cms/menu-item/5`) e o editor de layout apenas o
*renderizava* de um jeito especial (como etiquetas). Na v6, o conteudo exibido
pelo editor de layout **nao** e mais um item de layout fixo: e uma escolha
dinamica de modulo (e, dentro do modulo `menus`, de um menu). Isso e mais
flexivel (qualquer menu pode virar a grade "Servicos"), mas **perde** a
capacidade de exibir os itens de um menu como etiquetas.

---

## 5. Pendencias e riscos

| # | Pendencia | Impacto | Sugestao para a v7 |
|---|---|---|---|
| T1 | O seeder `UpdateModuloSelectOptions` nao e idempotente quanto ao **conteudo** das opcoes: se a lista de modulos mudar, ele reescreve o bloco por inteiro — OK — mas nao ha registro do que foi aplicado | Auditoria | Guardar a versao do bloco em `layouts` ou em um seed versionado |
| T2 | O seeder nao esta no `DatabaseSeeder` | Instalações novas nao tem o seletor de modulo | Incluir no fluxo de instalacao, ou transformar o bloco em **view** (em vez de HTML em `layouts.value`) |
| T3 | `secretarias-grid` nao existe na base v6 | O modulo selecionado nunca e persistido nao ha escolha | Tratar a ausencia como estado inicial valido |
| T4 | O fallback `slug = 'abas'` nao existe em `menus` | Escolher "Menus do Site" **sem** selecionar um menu especifico produz grade vazia | Criar um menu `abas` no seed ou exigir a selecao de um menu |
| T5 | O valor do menu e guardado como `menus:{id}` (string) em uma coluna `text` | Nada valida o id | Migrar para uma tabela de configuracao tipada |
| T6 | O widget `menu-tags-widget` da v5 sumiu sem substituto equivalente | Perde-se a apresentacao "em etiquetas" | Avaliar com o negocio se o recurso e necessario; se sim, reimplementar como componente Blade do editor, consumindo `menu_items` do menu escolhido |
| T7 | A v5 protegia o seeder com `where('slug','tags')->exists()`; a v6 nao tem equivalente | — | — |

---

## 6. Como verificar no ambiente

```bash
# 1. A linha de menu "tags" existe?
docker exec v6_6f22e1bd-postgres-1 psql -U postgres -d prefeituras_v5 \
  -c "select id,name,slug from menus order by id;"

# 2. O widget de tags existe?
docker exec v6_6f22e1bd-postgres-1 psql -U postgres -d prefeituras_v5 \
  -c "select key,type,path from layouts where key like '%tag%' or key='secretarias-grid';"

# 3. O bloco #modulos-select ja foi aplicado no blob de tags?
docker exec v6_6f22e1bd-postgres-1 psql -U postgres -d prefeituras_v5 \
  -t -c "select (value like '%modulos-select%') from layouts where key='tags';"

# 4. O seeder da v5 existe e a view correspondente?
ls v5/database/seeds/AddMenuTagsToProductionSeeder.php
ls v5/resources/views/portal/layouts/modelo5/layout/menus/menu_tags.blade.php
ls v6/database/seeds/ | grep -i AddMenuTagsToProductionSeeder   # esperado: sem resultados
# (na v5 o arquivo existe: v5/database/seeds/AddMenuTagsToProductionSeeder.php)
```

---

## 7. Resumo

O menu "Tags" era, na v5, um menu comum (id 5, slug `tags`) criado por um seeder
manual e consumido por um widget do editor de layout que o renderizava como
etiquetas. **Nada disso existe na v6**: nem o seeder, nem o widget, nem a view,
nem a linha em `menus`. A v6 substituiu a ideia por um **seletor de modulo**
persistido em `layouts.secretarias-grid` (formato `modulo:subId`), em que a
opcao `menus` permite transformar **qualquer menu** na grade "Servicos" da home
do modelo5. O preco da troca e a perda do formato "tags"; o ganho e a
flexibilidade de escolher o menu. O seeder que instala o seletor
(`v6/database/seeds/UpdateModuloSelectOptions.php`) **nao esta no
`DatabaseSeeder`** e **nao foi aplicado** na base v6 analisada — o bloco
`#modulos-select` nao existe no blob da chave `tags`.
