# Views e UX

## 1. Inventário de blades

| Blade | Superfície | Função | Extends |
|---|---|---|---|
| `V2/Modules/DadosAbertos/TransparenciaFiscal/Views/cms/index.blade.php` | CMS | tabela paginada, filtros, ações | `v2-cms::layouts.app` |
| `V2/Modules/DadosAbertos/TransparenciaFiscal/Views/cms/create.blade.php` | CMS | formulário de criação | `v2-cms::layouts.app` |
| `V2/Modules/DadosAbertos/TransparenciaFiscal/Views/cms/edit.blade.php` | CMS | formulário de edição | `v2-cms::layouts.app` |
| `V2/Modules/DadosAbertos/TransparenciaFiscal/Views/portal/index.blade.php` | Portal | cards por categoria raiz + blocos de filhas | `v2-portal::app-layout` |
| `V2/Modules/DadosAbertos/TransparenciaFiscal/Views/portal/show.blade.php` | Portal | detalhe do item | `v2-portal::app-layout` |

Namespace `v2-transparenciafiscal::` derivado de `strtolower('TransparenciaFiscal')`
(`V2/Core/Providers/V2ServiceProvider.php:120`).

Layouts:

- **CMS**: `v2-cms::layouts.app` → `V2/layouts/cms/layouts/app.blade.php`,
  com Bootstrap 5, Bootstrap Icons e blocos `page-breadcrumbs`, `page-actions`,
  `content`.
- **Portal**: `v2-portal::app-layout` → `V2/layouts/portal/app-layout.blade.php`,
  com blocos `main-header-area` e `main-section-area`.

## 2. CMS — `V2/Modules/DadosAbertos/TransparenciaFiscal/Views/cms/index.blade.php`

Estrutura:

1. bloco `@php` (`:1-52`) monta closures de render por coluna e o array
   `$columns`;
2. `page-breadcrumbs` — "Dados Abertos" › "Transparência Fiscal";
3. `page-actions` — botão "Novo Item" protegido por `@v2can('transparencia',
   'write')` (`:67-72`);
4. contador `{{ $items->total() }} registro(s) encontrado(s)` (`:76`);
5. `@component('v2-cms::partials.filter-card')` com busca por título e select de
   categoria (`:78-93`);
6. `@include('v2-cms::partials.table')` com sort server-side, paginação, estado
   vazio e CTA (`:95-113`).

Colunas declaradas (`:44-51`):

| Chave | Rótulo | Tipo | Ordenável | Render |
|---|---|---|---|---|
| `title` | Título | texto | sim | padrão |
| `category` | Categoria | texto | não | `$row->category->name ?? '—'` |
| `value` | Valor | number | sim | `R$ 1.234,56` ou `—` |
| `reference_date` | Referência | date | sim | padrão |
| `is_active` | Status | status | sim | badge via `v2-cms::partials.status-badge` |
| `actions` | Ações | actions | não | editar + excluir |

A coluna `category` acessa `$row->category` **por linha**, sem eager load no
controller — N+1 de até 20 queries por página (uma por item com categoria
distinta).

Ações (`:21-42`):

- editar sempre visível, inclusive para perfil `read`: o middleware deixa passar
  GET, e o `abort(403)` do controller é quem barra (`V2/Modules/DadosAbertos/TransparenciaFiscal/Controllers/Admin/TransparencyCmsController.php:83-85`);
- excluir só com `$canWrite`;
- exclusão via botão `data-v2-confirm` com `action/method/title/body/btn`,
  consumido por `V2/layouts/cms/partials/v2-confirm-modal.blade.php`.

Formatação monetária no PHP da view (`number_format((float) $row->value, 2, ',',
'.')`) — não há helper compartilhado de moeda.

## 3. CMS — formulários

`V2/Modules/DadosAbertos/TransparenciaFiscal/Views/cms/create.blade.php` e `V2/Modules/DadosAbertos/TransparenciaFiscal/Views/cms/edit.blade.php` são quase idênticos:

| Campo | Input | Obrigatório | Observações |
|---|---|---|---|
| Título | `text` | sim (`required`) | sem contador |
| Categoria | `select` | não | opção "Sem categoria"; lista **plana**, todas as categorias, incluindo inativas e filhas sem indentação |
| Valor | `number step=0.01 min=0` | não | sem máscara `R$` |
| Referência | `date` | não | corresponde a `reference_date` (competência) |
| Descrição | `textarea rows=4` | não | texto puro |
| Ativo | `checkbox value=1` | — | `checked` por padrão no create |

Diferenças entre os dois:

| Item | create | edit |
|---|---|---|
| `action` | `route('...store')` | `route('...update', $item->id)` |
| valores | `old()` | `old(..., $item->...)` |
| data | `value="{{ old('reference_date') }}"` | `$item->reference_date->format('Y-m-d')` |
| checkbox | sempre `checked` | `old('is_active', $item->is_active) ? 'checked' : ''` |

Não há `@method('PUT')`: a rota de update é POST (`V2/Modules/DadosAbertos/TransparenciaFiscal/Routes/cms.php:10`).

Erros de validação aparecem em bloco `alert-danger` no topo (`create:19-27`,
`edit:19-27`) e não por campo.

## 4. Portal — `V2/Modules/DadosAbertos/TransparenciaFiscal/Views/portal/index.blade.php`

Cabeçalho: breadcrumb com microdados Schema.org `BreadcrumbList`
(`:4-15`) e `<h1>` com ícone `bi-database` (`:17-20`).

Corpo:

```blade
{{-- V2/Modules/DadosAbertos/TransparenciaFiscal/Views/portal/index.blade.php:25-33 --}}
@forelse($categories as $cat)
    <div class="card mb-4">
        <div class="card-header bg-light">
            <h2 class="h5 mb-0">{{ $cat->name }}</h2>
            @if($cat->description)
                <p class="text-muted small mb-0 mt-1">{{ $cat->description }}</p>
            @endif
        </div>
        <div class="list-group list-group-flush">
            @foreach($cat->items as $item)
```

Depois das filhas:

```blade
{{-- V2/Modules/DadosAbertos/TransparenciaFiscal/Views/portal/index.blade.php:51-66 --}}
@foreach($cat->children as $child)
    <div class="list-group-item">
        <h3 class="h6 text-muted mb-2">{{ $child->name }}</h3>
        @forelse($child->items as $item)
            <a href="{{ route('v2.transparencia.portal.show', $item->slug) }}"
               class="d-flex justify-content-between align-items-center py-2 text-decoration-none border-bottom">
```

Problemas de UX/implementação:

1. **Itens inativos em filhas** — `$child->items` não aplica `active()`
   (`V2/Modules/DadosAbertos/TransparenciaFiscal/Controllers/Portal/TransparencyPortalController.php:17-19`), logo item desativado aparece
   apenas dentro de categoria filha.
2. **N+1** — `children` são eager-loaded, mas `$child->items` dispara uma query
   por filha.
3. **Dados misturados** — itens da raiz aparecem como `list-group-item` de
   primeiro nível; itens das filhas aparecem com markup diferente (sem data,
   com borda inferior). A leitura fica inconsistente.
4. **Sem ordenação temporal** — a view usa a ordem da relação
   (`hasMany` sem `orderBy`), não o escopo `ordered()` (`reference_date DESC`).
   Na prática, ordem do banco (indefinida).
5. **Sem paginação/busca** — todas as categorias e itens são renderizados de uma
   vez.
6. Categoria vazia (sem itens e sem filhas) exibe um card com cabeçalho e corpo
   vazio, sem mensagem de estado.
7. `@forelse` externo só cobre "nenhuma categoria raiz"; as filhas têm
   `@empty` ("Nenhum item publicado nesta categoria.") mas a raiz não.

## 5. Portal — `V2/Modules/DadosAbertos/TransparenciaFiscal/Views/portal/show.blade.php`

| Bloco | Conteúdo |
|---|---|
| Breadcrumb | Início › Transparência › título (microdados) |
| Cabeçalho | `<h1>` com o título e, se houver categoria, `<p class="lead">` |
| Coluna principal (8/12) | card com descrição ou "Sem descrição adicional." |
| Lateral (4/12) | card "Informações": Valor, Referência, Categoria, Status |
| Rodapé | botão "Voltar para Transparência" |

Observações:

- o status é exibido ao cidadão (`Publicado`/`Inativo`) — mas um item inativo
  nem chega aqui (`active()->firstOrFail()`), tornando o badge `Inativo`
  inalcançável;
- valor e data são condicionais (`@if($item->value !== null)`,
  `@if($item->reference_date)`);
- descrição é impressa com `{{ }}` (escapada), sem interpretar HTML nem
  Markdown; não há RichText;
- não há anexos, links de download nem "atualizado em".

## 6. JavaScript / Ajax

**Nenhum JavaScript específico do módulo.** Não há `<script>`, endpoint XHR,
polling ou evento customizado nos cinco blades.

Dependências de JS herdadas dos layouts:

| Recurso | Origem | Uso no módulo |
|---|---|---|
| Modal de confirmação | `v2-cms::partials.v2-confirm-modal` | exclusão de item |
| Bootstrap JS | layout CMS | modal/select |
| Busca/filtro | formulário GET nativo (`filter-card`) | `search`, `category`, `sort`, `dir` |

O `data-v2-confirm-*` é a única ponte declarativa; o handler vive no layout do
CMS, não no módulo.

## 7. Acessibilidade (WCAG 2.2 AA — leitura)

| Item | Situação |
|---|---|
| Landmarks | herdados dos layouts (`header`/`main`/`footer`) |
| Breadcrumb | `<nav aria-label="Breadcrumb">` + `aria-current="page"` |
| Ícones | `aria-hidden="true"` nos decorativos |
| Botões de ação | `title` + `aria-label` descritivos na tabela |
| Tabela | `ariaLabel` passado ao partial |
| Status | badge textual ("Publicado"/"Inativo"), não só cor |
| Formulários | `<label for>` em todos os campos |
| Contraste | classes Bootstrap `text-muted` sobre `bg-light` — depende do tema |
| Headings | portal: `h1` (página) → `h2` (categoria) → `h3` (filha) — hierarquia correta |

Lacunas: o select de filtro e o de categoria não têm estado de erro associado
(`aria-invalid`/`aria-describedby`); o contador "N registro(s)" não é anunciado
como região viva.

## 8. Exportações

**Não existem.** Não há Excel, PDF, CSV, JSON nem impressão dedicada. Os blades
não referenciam `Maatwebsite\Excel`, `Barryvdh\DomPDF` ou `Storage`.

Consequência direta: o módulo não cumpre o eixo "dado aberto" da LAI — o cidadão
só lê HTML formatado.

## 9. O que cada perfil vê

| Perfil | Portal | CMS |
|---|---|---|
| Cidadão (anônimo) | categorias raiz ativas, itens ativos da raiz e das filhas (inclui inativos nas filhas), detalhe por slug | — |
| Usuário CMS `read` | igual | lista + filtros; botão "Novo Item" oculto; editar visível mas bloqueado pelo middleware |
| Usuário CMS `write` | igual | CRUD completo de **itens** |
| Suporte / super-admin | igual | CRUD completo + bypass |

Nenhum perfil, em nenhuma superfície, gerencia categorias.
