# Solicitações LAI (e-SIC) — Views e UX

> Views do portal: `v6/resources/views/portal/layouts/**`
> Views do CMS: `v6/resources/views/prefecture/**`
> JS: `v6/public/assets/js/custom/**`

---

## 1. Visão geral das telas

| Tela | Arquivo | Quem vê |
|---|---|---|
| Formulário de solicitação (PF/PJ) | `v6/resources/views/portal/layouts/default/pages/statics/transparencia-fiscal/solicitacao-form.blade.php` e `v6/resources/views/portal/layouts/{modelo1..modelo6}/transparencia/solicitacao-form.blade.php` | Cidadão |
| Confirmação do protocolo | `v6/resources/views/portal/layouts/{modelo1..modelo6}/transparencia-fiscal/informacao-solicitada.blade.php` e `v6/resources/views/portal/layouts/default/pages/statics/transparencia-fiscal/informacao-solicitada.blade.php` | Cidadão |
| Acompanhar solicitação | `v6/resources/views/portal/layouts/{modelo1..modelo6}/informacoes-instituicao/acesso-rapido/acompanhe-sua-solicitacao.blade.php` e `v6/resources/views/portal/layouts/default/pages/statics/transparencia-fiscal/acompanhe-sua-solicitacao.blade.php` | Cidadão |
| Relatório Estatístico | `v6/resources/views/portal/layouts/{modelo1..modelo6}/transparencia-fiscal/relatorio-estatistico/index.blade.php` (+ `js.blade.php`) e `v6/resources/views/portal/layouts/default/pages/statics/transparencia-fiscal/relatorio-estatistico.blade.php` | Cidadão |
| Listagem por status (CMS) | `v6/resources/views/prefecture/informations-requests/index.blade.php` | Operador |
| Detalhe da solicitação (CMS) | `v6/resources/views/prefecture/informations-requests/show.blade.php` | Operador |
| Formulário de resposta (CMS) | `v6/resources/views/prefecture/answers/form-answer.blade.php` | Operador |
| Formulário de indeferimento (CMS) | `v6/resources/views/prefecture/answers/form-rejected.blade.php` | Operador |
| E-mails | `v6/resources/views/prefecture/emails/informations-requests/{email_user,email_admin,email_header,email_footer}.blade.php` e `v6/resources/views/prefecture/emails/answer/{email_answer_attach,email_answer_no_attach,email_rejected,email_to_extend,email_header,email_footer}.blade.php` | Cidadão / servidor |

## 2. Portal — o que o cidadão vê

### 2.1 Formulário de solicitação

A view inclui o formulário com `Form::open(['route' => 'requested-information', 'method' => 'post'])`
e campos:

| Campo | Tipo | Observação |
|---|---|---|
| `protocol` | hidden | `value="{{date('YmdHis')}}"` — gerado no Blade, não no servidor |
| `person-type` | radio | `0` = Pessoa Física (default), `1` = Pessoa Jurídica |
| `rg` | text | oculto quando PJ |
| `cnpj` | text | `data-mask="AA.AAA.AAA/AAAA-00"`, oculto quando PF |
| `fantasy_name` | text | oculto quando PF |
| `cpf` | text | `data-mask="000.000.000-00"`, oculto quando PJ |
| `name` | text | oculto quando PJ |
| `social_name` | text | oculto quando PF |
| `email_address` | email | obrigatório |
| `phone_number` | text | `data-mask="(00) 00000-0000"` |
| `zip_code` | text | `data-mask="00.000-000"` |
| `street_name`, `street_number`, `neighborhood`, `complement` | text | endereço |
| `state` | select | populado por `State::pluck('name','id')`; dispara ajax `ajax.get.city.by.state` para preencher `cities_id` |
| `cities_id` | select | populado por ajax conforme o estado |
| `request` | textarea | 6 linhas, obrigatório, mínimo de 20 caracteres |
| reCAPTCHA | widget | `Recaptcha::render()` |

A alternância PF/PJ é feita em JS puro nas views: o bloco `<script>` inline de
`solicitar-informacao.blade.php` mostra/esconde `#cpf`, `#name`, `#rg`,
`#cnpj`, `#social_name`, `#fantasy_name` conforme o radio alterado.

> A view `v6/resources/views/portal/layouts/newsbit/informacoes-instituicao/acesso-rapido/solicitar-informacao.blade.php` faz o mesmo com as
> classes `.pf` e `.pj` no lugar de ids, e referencia um script inexistente:
> `assets/js/custom/portal/lai/state.js` — **esse arquivo não existe** na v6
> (verificado com `ls`), o que produz um 404 de asset no console.

### 2.2 Confirmação

Mostra: "Sua solicitação foi recebida com sucesso!", o nome do solicitante (ou
razão social), o **protocolo em claro**, a data/hora e a frase
**"Em até 20 (vinte) dias retornaremos seu contato."** O prazo está fixo no
texto, sem leitura da configuração.

### 2.3 Acompanhar solicitação

Campo de protocolo + botão "Consultar". Duas chamadas ajax:

| Chamada | Endpoint | O que preenche |
|---|---|---|
| 1ª | `POST {{route('ajax.get.information.by.protocol')}}` | cabeçalho colorido por status (`EM TRAMITAÇÃO` amarelo `#FDC02F`, `ATENDIDO` verde `#30A64A`, `PRORROGADO` azul `#25A2B7`, `INDEFERIDO` vermelho `#DA3849`), protocolo, nome do solicitante, data e **descrição do pedido (`response.request`, sem máscara)** |
| 2ª | `POST {{route('ajax.get.answer.by/information')}}` | lista de respostas, cada uma com data, texto e o HTML de arquivos já renderizado (`val.view`) |

Em caso de erro na 1ª chamada, exibe "Não foi possível encontrar o pedido
solicitado.".

> Observação de LGPD: a tela mostra o **nome completo** e o **texto integral**
> do pedido a qualquer pessoa que tenha o número de protocolo — que é um
> carimbo de data/hora (`date('YmdHis')`) e portanto adivinhável.

### 2.4 Relatório Estatístico (público)

- Filtro por "Ano de Gestão" (de `date('Y')` até 1990) via
  `?ano=YYYY`; botão "Limpar filtro" aponta para `/pagina/relatorio-estatistico`.
- Gráfico de pizza (Google Charts) com 8 fatias: Em tramitação / Atendido /
  Indeferido / Prorrogado, cada uma em "Dentro do Prazo" e "Fora do Prazo".
- Botões de exportação: **xls**, **pdf**, **csv**, **txt** — todos via
  `exportarRelatorio(type)`, que redireciona para
  `{{ route('relatorio-estatistico') }}?ano=...&type=...`.
- Acordeão "Listagem completa das solicitações" — **oculto** quando
  `fullListRequestsDisabled == 1`.
- A listagem mostra `masked_protocol` e `masked_name` (nos modelos
  `modelo1..modelo6`); o template `default` mostra `protocol` e
  `person->name` **sem máscara** — divergência entre templates.
- Modal "Ver solicitação" (`abrirModal(id)`) chama `POST {{route('get.answers')}}`
  e preenche `#soliModal` com `data.request.mask_request`.

## 3. CMS — o que o operador vê

### 3.1 Listagem (`prefecture.informations-requests.index`)

Tabela AdminLTE (`box box-success`) com colunas **ID, Status, Solicitante,
Protocolo, Criado Em, Ações**. O `id` da tabela e o JS carregado são
interpolados com a variável `$status`:

```blade
<table id="tabela_{{ $status }}" class="table table-striped w-100">
    <thead>
        <tr>
            <th>ID</th>
            <th>Status</th>
            <th>Solicitante</th>
            <th>Protocolo</th>
            <th>Criado Em</th>
            <th class="column-actions text-center vertical-bottom">Ações</th>
        </tr>
    </thead>
    <tbody>
    </tbody>
</table>
```

O script carregado no `@section('other-scripts')` da mesma view é:

```blade
<script src="{{ asset("assets/js/custom/contents/solicitacao-lai/$status/datatables.js") }}"></script>
```

Os quatro JS (`em-tramitacao`, `atendidos`, `prorrogados`, `indeferidos`) em
`v6/public/assets/js/custom/contents/solicitacao-lai/*/datatables.js` definem as
colunas e chamam `runDatatables(status, colunas)`.

| Arquivo | Colunas | Botões |
|---|---|---|
| `v6/public/assets/js/custom/contents/solicitacao-lai/em-tramitacao/datatables.js` | status (amarelo), solicitante, protocolo, criado_em | "Responder" → `/cms/respostas-lai/{id}`; "Prorrogar" → `/cms/solicitacoes/{id}/lai/4` |
| `v6/public/assets/js/custom/contents/solicitacao-lai/atendidos/datatables.js` | status (verde) | "Nova resposta" → `/cms/respostas-lai/{id}` |
| `v6/public/assets/js/custom/contents/solicitacao-lai/prorrogados/datatables.js` | status (azul) | "Responder" → `/cms/respostas-lai/{id}` |
| `v6/public/assets/js/custom/contents/solicitacao-lai/indeferidos/datatables.js` | status (vermelho) | "Visualizar" → `/cms/respostas-lai/{id}` |

`runDatatables` (`v6/public/assets/js/custom/utilities/table.js:3`) monta a
requisição `GET /cms/datatable/{url}` e adiciona botões de exportação
**Excel**, **PDF** e **CSV** (com larguras de coluna calculadas por número de
colunas), além de busca, paginação e `stateSave: true`.

### 3.2 Detalhe (`prefecture.informations-requests.show`)

Cabeçalho com a faixa colorida do status:

| status_id | Faixa | Classe CSS |
|---|---|---|
| 1 | Em tramitação | `bg-yellow text-bold` |
| 2 | Atendido | `bg-green text-bold` |
| 3 | Indeferido | `bg-red text-bold` |
| 4 | Prorrogado | `bg-blue text-bold` |

Depois: IP, Navegador, Protocolo, Data e Hora da solicitação, tipo de pessoa
(PF: nome/CPF/RG; PJ: razão social/nome fantasia/CNPJ), e-mail, telefone,
endereço (logradouro, número, complemento, bairro, cidade/UF, CEP) e o texto
integral do pedido.

Em seguida, a lista de **Resposta(s)**: data, texto da resposta (renderizado
com `{!! !!}`, HTML) e os arquivos para download (link `url($archive->path)`).

Botões no rodapé da lista:

| Situação | Botões |
|---|---|
| tem respostas (status 1/2/3/4 com respostas) | "Nova resposta" |
| status 2 (Atendido) | "Nova resposta" |
| status 1 ou 4 | "Responder" e "Indeferir" |
| sempre | "Voltar" → `route('info-request-by-status', $informationRequest->status->id)` |

Os dois formulários (`#answer` e `#rejected`) ficam ocultos e são exibidos pelo
JS `viewAnswer()` / `viewRejected()`, com `animate({scrollTop: ...})` para a
caixa correspondente. O JS inline também reabre a caixa correta quando há
erro de validação (`$errors->has('answer')` / `$errors->has('rejected')`).

O editor de texto usa **bootstrap-wysihtml5**
(`assets/plugins/bootstrap-wysihtml5/bootstrap3-wysihtml5.all.min.js`).

### 3.3 Formulário de resposta

`prefecture/answers/form-answer.blade.php`:

- `Form::open(['route' => ['answer.store'], 'files' => true])`
- hidden `information_request_id` e `type = 1`
- textarea `answer` com classe `textarea` (wysihtml5)
- bloco de anexos dinâmico (`.data-itens`, botão `#btn-adicionar` com JS inline
  que clona o markup de um novo item de upload) e listagem de arquivos já
  enviados com ações de download/visualizar/excluir (`deleteArchive(id)`)
- botão "Enviar Resposta"

`prefecture/answers/form-rejected.blade.php` é idêntico, com `type = 0` e
textarea `rejected` ("Enviar Indeferimento").

## 4. Exportações

| Formato | Como é gerado | Conteúdo |
|---|---|---|
| xls | `Maatwebsite\Excel` + `App\Exports\InformationsRequestsExport` (implementa `FromView`) | View `v6/resources/views/exports/informations-requests.blade.php` — colunas Status, Protocolo, Solicitante, Data do pedido, com `masked_protocol` e `masked_name` |
| csv | mesma classe de exportação | idem |
| pdf | `Barryvdh\DomPDF` → `PDF::loadView('exports.informations-requests')` | mesma view, em HTML |
| txt | `Portal\TransparencyController@exportTxt` | texto alinhado com `status->name`, `masked_protocol`, `masked_name` e data |
| Excel/PDF/CSV do CMS | botões padrão do `runDatatables` (DataTables Buttons) | colunas da vista SQL, com **protocolo e nome do solicitante em claro** |

## 5. Assets e JS do módulo

| Arquivo | Função |
|---|---|
| `v6/public/assets/js/custom/contents/solicitacao-lai/em-tramitacao/datatables.js` | colunas e ações da listagem em tramitação |
| `v6/public/assets/js/custom/contents/solicitacao-lai/atendidos/datatables.js` | idem para atendidos |
| `v6/public/assets/js/custom/contents/solicitacao-lai/prorrogados/datatables.js` | idem para prorrogados |
| `v6/public/assets/js/custom/contents/solicitacao-lai/indeferidos/datatables.js` | idem para indeferidos |
| `v6/public/assets/js/custom/utilities/table.js` | `runDatatables()` genérico (ajax, paginação, export buttons) |
| `v6/resources/views/portal/layouts/modelo1/transparencia-fiscal/relatorio-estatistico/js.blade.php` | `drawChart()` (Google Charts) e `abrirModal(id)` |
| `v6/resources/views/prefecture/answers/form-answer.blade.php` | clone de linhas de upload (`#btn-adicionar`) |

> O template `default` do portal **não** possui `transparencia-fiscal/` na raiz
> (verificado com `ls`): as views do relatório e da confirmação estão em
> `default/pages/statics/transparencia-fiscal/`. O controller monta o caminho
> `portal.layouts.$template.transparencia-fiscal.informacao-solicitada`, que
> **não resolve** para o template `default` (verificado com
> `view()->exists()`: `no`). O template ativo no banco é `modelo1`
> (`configurations.key = 'layout'`), onde o caminho resolve.

## 6. Acessibilidade e LGPD na interface

- O portal usa Bootstrap 4 com classe de contraste configurável
  (`assets/js/custom/portal/contrast.js`), VLibras
  (`assets/js/custom/portal/vlibras.js`) e barra de privacidade
  (`assets/js/custom/portal/barra-privacidade.js`) — recursos globais, não do
  módulo.
- O texto mascarado (`mask_request`) só aparece no **modal do relatório
  estatístico**; nem o acompanhamento por protocolo nem a listagem completa do
  template `default` o utilizam.
- A tela de acompanhamento exibe o texto **original** do pedido e o nome
  completo do solicitante.
