# VIAP — Views e UX

> Telas do CMS (AdminLTE) e do portal público (Bootstrap 4 + tema `modelo1..6`),
> JavaScript/Ajax e Mechanismos de exportação.

---

## 1. Views do CMS

Diretório: `v6/resources/views/prefecture/viap/`

| Arquivo | Função |
|---|---|
| `v6/resources/views/prefecture/viap/index.blade.php` | Listagem (DataTable) com cabeçalho, botões e tabela `#tabela_viap` |
| `v6/resources/views/prefecture/viap/create.blade.php` | Wrapper do formulário de cadastro (`Form::open(['route' => 'viap.store', 'files' => true])`) |
| `v6/resources/views/prefecture/viap/edit.blade.php` | Wrapper do formulário de edição (`Form::model($viap, ['route' => ['viap.update', $viap->id], 'method' => 'PUT', 'files' => true])`) + script de remoção de anexo |
| `v6/resources/views/prefecture/viap/form.blade.php` | Formulário compartilhado entre create/edit |

Todos estendem `@extends('admin.layouts.app')`.

### 1.1 Tela de listagem (operador)

`v6/resources/views/prefecture/viap/index.blade.php`:

- Título do box: `{{ $title }}` → *"VIAP - Verba Indenizatória de Apoio Parlamentar"*.
- Botão **"Cadastrar VIAP"** — exibido apenas com `has_access(['viap.create'])`.
- Botão **"Excluir Registro(s)"** (componente
  `v6/resources/views/prefecture/components/deleteByLoteSubmitButton.blade.php`) —
  exibido com `has_access(['viap.delete'])`, com contador `(0)` atualizado por JS.
- Cabeçalho da tabela: coluna de seleção (master checkbox do componente
  `v6/resources/views/prefecture/components/deleteByLoteMasterCheckbox.blade.php`),
  `ID`, `Data Publicação`, `Referência`, `Vínculo` e `Ações`.
- Scripts carregados: `v6/public/assets/js/custom/utilities/deleteAll.js` e
  `v6/public/assets/js/custom/contents/viap/datatable.js`.

### 1.2 Formulário (operador)

`v6/resources/views/prefecture/viap/form.blade.php`:

| Campo | Tipo | Componente | Observações |
|---|---|---|---|
| `publication_date` | date | `components.inputs.date` | Máscara `br-data`, formato `d/m/Y`, obrigatório |
| `reference_month` | select | inline (array PHP) | 1..12 com nomes em português; obrigatório |
| `reference_year` | select | inline (`range(date('Y'), date('Y') - 10)`) | Ano atual e 10 anteriores; obrigatório |
| `link_type` | select | inline | `gabinete` \| `outro_orgao`; **alternador de visibilidade** |
| `councilman_id` | select | `components.inputs.select` | Visível só quando `link_type = gabinete` (`#wrapper_councilman`) |
| `organ_id` | select | `components.inputs.select` | Visível só quando `link_type = outro_orgao` (`#wrapper_organ`) |
| `description` | textarea | `components.inputs.textarea` | Máscara `summernote` (texto rico) |
| `archive[i][]` | multi-file | inline (JS) | Multi-upload dinâmico com descrição por arquivo |

Comportamento do JavaScript do formulário (bloco `<script>` inline):

```js
$('#link_type').change(function() {
    const type = $(this).val();
    if (type === 'gabinete') {
        $('#wrapper_councilman').show();
        $('#wrapper_organ').hide();
    } else if (type === 'outro_orgao') {
        $('#wrapper_councilman').hide();
        $('#wrapper_organ').show();
    } else {
        $('#wrapper_councilman').hide();
        $('#wrapper_organ').hide();
    }
});
```

- `#btn-adicionar` clona um bloco `.data-itens` com
  `<input type="file" name="archive[${n}][]">` e
  `<input type="text" name="archive[${n}][description]">`.
- `.js-remove-item` remove o bloco `.data-itens` mais próximo.
- Select2 é inicializado com `width: '100%'`.
- Summernote é carregado de `v6/public/assets/plugins/summernote/summernote.min.js`
  (+ `summernote-pt-BR.js`) e configurado em
  `v6/public/assets/js/custom/utilities/richtext/summernote.js`.

**Não há campo para `amount`.** Ver Gap G-02.

### 1.3 Remoção de anexo (AJAX)

`v6/resources/views/prefecture/viap/edit.blade.php` define `deleteArchive(archive_id)`:

```js
$.ajax({
    type: 'POST',
    url: "{{ route('viap.ajax.delete.files') }}",
    data: { _token: '{{ csrf_token() }}', archive_id: archive_id },
    success: function(data) { ... toastr.success('Arquivo apagado com sucesso!'); },
    error: function() { toastr.error('Erro ao apagar arquivo.'); }
});
```

### 1.4 Componente de anexos

`v6/resources/views/components/inputs/archive.blade.php` exibe os arquivos já
enviados (ordenados por `order`), com edição inline da descrição, botão de
download (`/{{ $file->path }}`) e botão de exclusão (chama `deleteArchive`).
Com `has_storage = true`, o `path` é prefixado com `storage/`.

## 2. Views do Portal (público)

O controller escolhe a view pelo **layout ativo** do portal:

```php
// v6/app/Http/Controllers/Portal/ViapPortalController.php:71
return view('portal.layouts.' . $this->getTemplateActived() . '.viap.index', ...);
```

`getTemplateActived()` (`v6/app/Http/Controllers/Admin/Controller.php:39-50`)
lê `configurations.key = 'layout'`. **No banco de análise o valor é
`modelo1`** (`pagina_em_manutencao = 0`).

| Arquivo | Função |
|---|---|
| `v6/resources/views/portal/layouts/modelo1/viap/index.blade.php` | Listagem pública (modelo1 — **ativo**) |
| `v6/resources/views/portal/layouts/modelo1/viap/show.blade.php` | Detalhe de um lançamento (modelo1) |
| `v6/resources/views/portal/layouts/modelo2/viap/index.blade.php` | idem para o modelo2 |
| `v6/resources/views/portal/layouts/modelo2/viap/show.blade.php` | idem para o modelo2 |
| `v6/resources/views/portal/layouts/modelo3/viap/index.blade.php` | idem para o modelo3 |
| `v6/resources/views/portal/layouts/modelo3/viap/show.blade.php` | idem para o modelo3 |
| `v6/resources/views/portal/layouts/modelo4/viap/index.blade.php` | idem para o modelo4 |
| `v6/resources/views/portal/layouts/modelo4/viap/show.blade.php` | idem para o modelo4 |
| `v6/resources/views/portal/layouts/modelo5/viap/index.blade.php` | idem para o modelo5 |
| `v6/resources/views/portal/layouts/modelo5/viap/show.blade.php` | idem para o modelo5 |
| `v6/resources/views/portal/layouts/modelo6/viap/index.blade.php` | idem para o modelo6 |
| `v6/resources/views/portal/layouts/modelo6/viap/show.blade.php` | idem para o modelo6 |
| `v6/resources/views/portal/viap/index.blade.php` | **Cópia órfã** (não referenciada pelo controller); estende `modelo5` |
| `v6/resources/views/portal/viap/show.blade.php` | **Cópia órfã** |
| `v6/resources/views/exports/viap.blade.php` | Layout HTML das exportações XLSX/CSV/PDF |

Os seis pares `modelo1..6` são **cópias** com apenas o `@extends` e o
breadcrumb trocados (`diff` entre `modelo1` e `modelo2` mostra exatamente
isso) — Gap G-11.

Não há view do VIAP no layout `default`.

### 2.1 O que o cidadão vê (index)

1. Título "VIAP" + **texto institucional**: o conteúdo da *static page* com
   `slug = 'viap'` quando existir (`$viap_static_page->text`), senão o texto
   fixo sobre a Resolução nº 1885/2020.
   - No banco de análise **não existe** static page `viap`
     (`select id,title,slug from static_pages where slug='viap'` → 0 linhas),
     logo o texto fixo é o exibido.
2. Formulário de filtros (GET) com: Tipo de Vínculo (Todos / Gabinete
   Parlamentar / Outros Órgãos), Parlamentar (condicional), Órgão
   (condicional), Mês, Ano, botões **Filtrar** e **Limpar**.
3. Tabela: `Data Pub.` | `Referência` | `Vínculo` | `Valor` | `Ações`.
   - `Valor` mostra `R$ {{ number_format($viap->amount, 2, ',', '.') }}` —
     **sempre `R$ 0,00`** porque `amount` nunca é gravado.
   - `Vínculo` mostra um *badge* (`Gabinete` / `Órgão`) + nome do parlamentar
     ou título do órgão.
4. Botão "Ver detalhes" → `route('portal.viap.show', $viap->slug ?? $viap->id)`.
5. Botões **"Salvar como:"** (`xls`, `pdf`, `csv`, `txt`) — exibidos **somente
   quando `$viaps->count() > 0`**, ou seja, apenas quando há filtro aplicado
   (ver Gap G-01). O JavaScript `exportar(type)` repassa os filtros da URL:

```js
function exportar(type) {
    const url = new URL(window.location.href);
    url.searchParams.set('type', type);
    window.location.href = '/viap/export?' + url.searchParams.toString();
}
```

6. Paginação (`$viaps->links()`), 15 itens por página.

### 2.2 O que o cidadão vê (show)

`v6/resources/views/portal/layouts/modelo1/viap/show.blade.php`:

- Cabeçalho `{{ $viap->display_title }}` (accessor do model).
- Tabela com **Data de Publicação**, **Período de Referência** e **Vínculo**.
- Lista de **Arquivos Anexos** (se houver), com link para
  `url('storage/' . $archive->path)`.
- Botão "Voltar" → `route('portal.viap.index')`.
- Breadcrumb: `Breadcrumbs::view('portal.layouts.modelo1.layout.breadcrumb', 'viap-show', $viap)`.

## 3. JavaScript / Ajax

### 3.1 DataTable do CMS

`v6/public/assets/js/custom/contents/viap/datatable.js`:

- Define 4 colunas: `publication_date` (formatada `dd/mm/aaaa hh:mm`), uma
  coluna `data: null` para `Referência` (`mês/ano`), `linked_name` (vínculo) e
  a coluna de **Ações**.
- A coluna de ações monta:
  - botão "Ver no Portal" apontando para `/viap/{slug ?? id}` (nova aba);
  - `createBTN(data.id, '/cms/viap/{id}/edit', data.edit, data.delete, '/cms/viap/{id}')`
    — editar/excluir condicionados pelas flags de permissão vindas do backend.
- Finaliza com `runDatatables('viap', collums, true, 'DESC', null, true)`.

`v6/public/assets/js/custom/utilities/table.js` implementa `runDatatables()`:

- URL do AJAX: **`/cms/datatable/viap`** (GET, `contentType: application/json`).
- `stateSave: true` (o estado da tabela persiste no `localStorage`).
- Botões de exportação embutidos: **Excel**, **PDF**, **CSV** e **TXT**
  (exportação client-side via DataTables Buttons, colunas visíveis exceto
  `.column-actions`).
- Ordem padrão: coluna 1 (`deleteAll = true` → índice 1), tipo `desc`.
- No `draw.dt`, executa `addConfirmation()`, `addDelete()`, `addDeleteAll()`,
  `addDestaque()`, `refreshActive()`, `refreshAllActive()`.

### 3.2 Exclusão em lote

`v6/public/assets/js/custom/utilities/deleteAll.js` → `submitDeleteAll(route)`:

- Coleta `input[name="toDeleteAll[]"]:checked` → array `toDelete`.
- Confirmação com **SweetAlert2**.
- POST para `route('viap.delete-por-lote')` com `_token` e `toDelete`.
- Em sucesso, recarrega o DataTable (`datatable.ajax.reload()`).

### 3.3 Filtros do portal

Script inline em `v6/resources/views/portal/layouts/modelo1/viap/index.blade.php`:
ao mudar o radio `filter-link-type`, mostra/esconde `#wrapper_portal_councilman` /
`#wrapper_portal_organ` e limpa o campo do vínculo oposto.

### 3.4 PDF client-side (quebrado)

`v6/public/assets/js/modulos/jspdf/gerar-pdf-viap.js` implementa `gerarPdf()`
com `jsPDF` + `autoTable`, usando a variável global `viaps`:

```js
function gerarPdf() {
    if (!viaps || !Array.isArray(viaps) || viaps.length === 0) {
        alert('Não há dados para exportar. Selecione os filtros e clique em Filtrar primeiro.');
        return;
    }
    // monta o cabeçalho e as linhas com doc.autoTable
    doc.save('viap.pdf');
}
```

O arquivo **é carregado** pelas views do portal
(`v6/resources/views/portal/layouts/modelo1/viap/index.blade.php:215-217`,
junto de `jspdf.umd.min.js` e `jspdf-autotable.min.js`), mas a variável global
`viaps` **nunca é definida** — o controller envia `$viaps` para a view Blade,
sem expô-la em JavaScript. Na prática, o botão **"pdf" sempre mostra o alert**
"Não há dados para exportar" — Gap G-12. O PDF funcional é o gerado no
servidor (`/viap/export?type=pdf`).

## 4. Exportações

| Formato | Como é gerado | Endpoint |
|---|---|---|
| XLSX | `Excel::download(new ViapExport($viaps, $months), 'viap.xlsx')` — `maatwebsite/excel` com `FromView` | `GET /viap/export?type=xls` |
| CSV | `Excel::download(new ViapExport($viaps, $months), 'viap.csv')` (mesma view HTML) | `GET /viap/export?type=csv` |
| PDF | `PDF::loadView('exports.viap', compact('viaps','months','pdf'))->download('viap.pdf')` — dompdf | `GET /viap/export?type=pdf` |
| TXT | `ViapPortalController::exportTxt()` — texto com cabeçalho `Data Publicação \| Referência \| Vínculo` e separador `---` | `GET /viap/export` (sem `type`) |
| Excel/PDF/CSV/TXT (CMS) | DataTables Buttons, **client-side**, a partir do JSON de `/cms/datatable/viap` | botão na listagem do CMS |

A view `v6/resources/views/exports/viap.blade.php` é o layout HTML usado
tanto pelo Excel quanto pelo PDF; no PDF ela acrescenta o cabeçalho com o nome
do município (`config('app.name')`) e a data da pesquisa.

**Limitação:** as exportações do portal usam **apenas 3 colunas** —
Data Publicação, Referência e Vínculo. **Valor, descrição e anexos não são
exportados.**

## 5. Resumo das telas

| Ator | Tela | URL | Como chegar |
|---|---|---|---|
| Operador | Listagem | `/cms/viap` | Menu lateral "VIAP" (`MenuServiceProvider`, `case 'viap'`) |
| Operador | Cadastro | `/cms/viap/create` | Botão "Cadastrar VIAP" |
| Operador | Edição | `/cms/viap/{id}/edit` | Botão de lápis na DataTable |
| Operador | Detalhe | `/cms/viap/{id}` | — (**rota quebrada**, 500) |
| Cidadão | Listagem | `/viap` | Menu/links do portal |
| Cidadão | Detalhe | `/viap/{slug}` | Botão "Ver detalhes" |
| Cidadão | Exportação | `/viap/export?type=…` | Botões "Salvar como: xls / pdf / csv / txt" (só com filtro aplicado) |
