# Acesso Rápido — Views e UX

## 1. Views do CMS (AdminLTE)

Pasta: `v6/resources/views/prefecture/contents/acesso-rapido/`

| Arquivo | Função |
|---|---|
| `index.blade.php` | Listagem em DataTable (`tabela_acesso_rapido`), botão "Cadastrar Acesso Rápido" (visível se `has_access(['acesso-rapido.create'])`), cabeçalho "Acesso Rápido". |
| `create.blade.php` | Formulário de criação; delega para `prefecture.contents.acesso-rapido.form`. |
| `edit.blade.php` | Formulário de edição; delega para o mesmo `form`. |
| `form.blade.php` | Campos: `title` (Título), `text` (Descrição), `icon` (Ícone), `link` (URL), `status` (Ativar no portal), `isBlank` (Abrir em nova guia) + `category_contents_id` oculto. |

Fragmentos do `form.blade.php`:

```blade
<input type="hidden" name="category_contents_id" value="{{ $categoryContent->id }}">

@include('components.inputs.input', [
    'size' => 5, 'id' => 'title', 'titulo' => 'Título',
    'maxlen' => '25', 'placeholder' => 'Título', 'mandatory' => true,
    'data' => isset($content) ? $content->title : old('title'),
])

@include('components.inputs.checkbox', [
    'id' => 'status', 'titulo' => 'Ativar no portal',
    'data' => isset($content) ? $content->status == 1 ? true : false : true,
])
```

O seletor de ícone usa o plugin **fontawesome-iconpicker**
(`assets/plugins/fontawesome-iconpicker/dist/js/fontawesome-iconpicker.js`),
inicializado por `$('#icon').iconpicker();`.

### 1.1 Listagem (DataTable)

Colunas do `index.blade.php`: `#` (checkbox mestre), `ID`, `Título`, `Ações`.
A coluna "Título" é preenchida pelo JS com `data: 'titulo'`, ou seja, pela coluna
`titulo` da view SQL `acesso_rapido` (que é `contents.title`).

A ordenação é por *drag-and-drop* (jQuery UI `sortable`) gravando em
`contents.order`:

```js
// v6/resources/views/prefecture/contents/acesso-rapido/index.blade.php:45-61
            $("table tbody").sortable({
                cursor: 'grabbing',
                stop: function(event, ui) {
                    var token = '{{ csrf_token() }}';

                    var sortable_data = [];
                    $.each($(".item-list"), function() {
                        sortable_data.push(this.id);
                    });
                    $.ajax({
                        cache: false,
                        data: {
                            _token: token,
                            sortable_data: sortable_data
                        },
                        type: 'POST',
                        url: "{{ route('ajust.banners') }}",
```

> O trecho acima vai até a linha 61 do Blade; o `$.ajax` continua com os
> handlers `beforeSend` (linha 62), `success` (67) e `error` (77), que
> escrevem no bloco `#update` o aviso de progresso em azul e, no sucesso, a
> confirmação em verde (ver seção 6).

> O endpoint é o **mesmo** usado por banners (`ajust.banners` ->
> `ContentController@ajustOrder`), que faz `reorder(new Content(), $request->sortable_data)`
> para qualquer conteúdo. O rótulo da rota é enganoso, mas o efeito (gravar `order`)
> é o desejado.

## 2. Views do Portal

O portal exibe **duas** estruturas diferentes chamadas "acesso rápido". Elas
usam fontes de dados distintas e **não são a mesma coisa**:

| Estrutura | Fonte dos dados | Variável | Onde aparece |
|---|---|---|---|
| **A. Menu "Acesso Rápido"** (barra de atalhos) | `menu_items` do menu `menus.id = 3` | `$menuRapido` | cabeçalho do modelo1/modelo2/modelo6, home do modelo3/modelo4 |
| **B. Cards de links rápidos** (home) | `contents` da categoria `acesso-rapido` + `links` | `$acessos` | home do modelo1/modelo2, `links-rapidos` do modelo3/modelo4, sidebar do modelo5/modelo6 |

### 2.1 Estrutura A — Menu "Acesso Rápido" (`$menuRapido`)

Consulta (view composer em `v6/app/Providers/MenuServiceProvider.php:438-440`):

```php
$menuRapido =
    MenuItem::with('links')->where('menus_id', 3)->where('is_active', true)
        ->whereNull('menus_items_id')->orderBy('order')->get();
```

| Layout | Arquivo | Inclusão |
|---|---|---|
| modelo1 | `v6/resources/views/portal/layouts/modelo1/layout/header.blade.php:77-91` | navbar colapsável "Acesso Rápido" (`#navbarQuickLinks`) |
| modelo2 | `v6/resources/views/portal/layouts/modelo2/layout/header.blade.php:116` | idem |
| modelo3 | `v6/resources/views/portal/layouts/modelo3/home/acesso-rapido.blade.php:116-131` | 5 cards centralizados na home |
| modelo4 | `v6/resources/views/portal/layouts/modelo4/home/acesso-rapido.blade.php:121` | idem |
| modelo6 | `v6/resources/views/portal/layouts/modelo6/layout/header/acesso-rapido.blade.php:11-25` | navbar "Acesso Rápido" (`#menu-acesso-rapido`) |
| modelo5 | — | **não encontrado** |

O destino de cada item é resolvido por `MenuItemPresenter::getLink()`
(`v6/app/Http/Presenters/MenuItemPresenter.php:10-40`):

```php
// v6/app/Http/Presenters/MenuItemPresenter.php:20-45 (ramo type == 2)
        } elseif ($this->type == 2) {
            if (isset($this->content->slug) && !empty($this->content->slug)) {
                $content_slug = '/' . $this->content->slug;
            } else {
                $content_slug = '';
            }

            if($this->categoryContent){
                
                if ($this->categoryContent->category_contents_id == 3) {
                    return url('publicacoes/' . $this->categoryContent->slug . $content_slug);
                } elseif ($this->categoryContent->category_contents_id == 2) {
                    return url('legislacao/' . $this->categoryContent->slug . $content_slug);
                } elseif ($this->categoryContent->id == 7) {
                    return url('a-instituicao/' . $this->categoryContent->slug . $content_slug);
                } elseif ($this->categoryContent->id == 32) {
                    return url('a-instituicao/' . $this->categoryContent->slug . $content_slug);
                } elseif ($this->categoryContent->id == 12) {
                    return url('acesso-rapido/' . $this->categoryContent->slug . $content_slug);
                } elseif (isset($this->categoryContent->categoryContentsBelongings->slug) && $this->categoryContent->categoryContentsBelongings->slug == 'conselhos') {
                    return url('portal/' . $this->categoryContent->categoryContentsBelongings->slug . '/' . $this->categoryContent->slug);
                } else {
                    return url('/' . $this->categoryContent->slug . $content_slug);
                }
            }
        }
```

Itens do menu `menus_id = 3` na base (consulta somente-leitura):

| id | Rótulo | `type` | Destino resolvido |
|---|---|---|---|
| 93 | "Perguntas Frequentes" | 2 (categoria) | `/acesso-rapido/perguntas-frequentes` (`category_contents_id = 12`) |
| 94 | "Manual de Navegação" | 1 (página estática) | `/acesso-rapido/relatorio-estatistico` (`static_pages_id = 5`) |
| 95 | "Solicitar Informação" | 1 | `/acesso-rapido/ouvidoria` (`static_pages_id = 2`) |
| 96 | "Acompanhe sua solicitação" | 1 | `/acesso-rapido/solicitar-informacao` (`static_pages_id = 3`) |
| 97 | "Transparência Fiscal" | 2 (categoria) | `category_contents_id = 25` |

> **Vários destinos estão trocados** (ver `08-GAPS-E-DIVIDAS.md`, bug B18):
> "Manual de Navegação" aponta para "Relatório Estatístico", "Solicitar
> Informação" aponta para "Ouvidoria" e "Acompanhe sua solicitação" aponta para
> "Solicitar Informação". A causa está no seed
> `v6/database/seeds/MenuItemsTableSeeder.php:1045-1077`, que fixa
> `static_pages_id` 5, 2 e 3.

### 2.2 Estrutura B — Cards de links rápidos (`$acessos`)

| Layout | Arquivo | Onde é incluído |
|---|---|---|
| modelo1 | `v6/resources/views/portal/layouts/modelo1/home/acesso-rapido.blade.php` | `v6/resources/views/portal/layouts/modelo1/home/elementos.blade.php:82` |
| modelo2 | `v6/resources/views/portal/layouts/modelo2/home/acesso-rapido.blade.php` | `v6/resources/views/portal/layouts/modelo2/home/destaque.blade.php:146` |
| modelo3 | `v6/resources/views/portal/layouts/modelo3/home/links-rapidos.blade.php` | `v6/resources/views/portal/layouts/modelo3/home/elementos.blade.php:8` |
| modelo4 | `v6/resources/views/portal/layouts/modelo4/home/links-rapidos.blade.php` | `v6/resources/views/portal/layouts/modelo4/home/index.blade.php:29` |
| modelo5 | `v6/resources/views/portal/layouts/modelo5/home/news/sidebar/acesso-rapido.blade.php` | **nenhuma inclusão encontrada** (ver nota abaixo) |
| modelo6 | `v6/resources/views/portal/layouts/modelo6/layout/sidebar/acesso-rapido.blade.php` | `v6/resources/views/portal/layouts/modelo6/layout/sidebar/layout.blade.php:2` e `v6/resources/views/portal/layouts/modelo6/noticias/layouts-home/layout.blade.php:16,21` |

> **modelo5:** a view existe e o `ConfigHeaderServiceProvider` injeta `$acessos` nela,
> mas **nenhum Blade a inclui** (busca por `home.news.sidebar` só encontra o próprio
> provider). O bloco do modelo5 é controlado pelo "modelo personalizável": a
> migration `v6/database/migrations/2026_05_19_104500_sync_acesso_rapido_modelo_5.php`
> registra `layouts.key = 'acesso-rapido'` com `path = 'portal.layouts.modelo5.home.news.sidebar'`
> e **`status = 0`** (desativado por padrão), além de injetar o HTML de preview em
> `layouts.tags`.

> O **modelo6 não possui** `home/acesso-rapido.blade.php`; o bloco fica na sidebar.

Condições de exibição (idênticas em todos os layouts):

```blade
@if (isset($modulos['acesso-rapido']) && $modulos['acesso-rapido'])
    @inject('configSite', 'App\Prefecture\Configuration')

    @if ($configSite->where('key', 'links_rapidos')->first()->value == '1')
        <section class="row quick-access m-0 pb-4 mb-3 d-flex align-items-stretch">
            @foreach ($acessos as $acesso)
```

> Trecho de `v6/resources/views/portal/layouts/modelo1/home/acesso-rapido.blade.php:1-6`
> e `:62-63`; o bloco `<style>` do CSS dos cards fica entre as duas condições e foi
> omitido aqui.

Cada card:

```blade
// v6/resources/views/portal/layouts/modelo1/home/acesso-rapido.blade.php:76-95
                    <a href="{{ $acesso->linksUnique->link ?? '#' }}"
                        class="rounded bg-color-3 txt-color-dinamic-3 quick-access-card h-100"
                        @if (isset($acesso->linksUnique) && $acesso->linksUnique->isBlank == true) target="_blank" @endif>

                        <div class="top-content w-100">
                            <i class="{{ $acesso->icon }} icon"></i>

                            <div class="card-title">
                                {{ $acesso->title }}
                            </div>

                            <div class="card-description">
                                {{ $acesso->text ?? 'Descrição geral ou informações adicionais do módulo.' }}
                            </div>
                        </div>

                        <div class="btn-veja-mais">
                            VEJA MAIS
                        </div>
                    </a>
```


### 2.3 Telas internas (informacoes-instituicao/acesso-rapido)

Telas replicadas por layout (modelo1..modelo6 e `newsbit`):

| Tela | Função | Layouts que possuem o arquivo |
|---|---|---|
| `perguntas-frequentes.blade.php` | Lista as perguntas da categoria com filtro client-side (`#txtBusca` / `#ulItens li`). | modelo1..modelo6, newsbit |
| `solicitar-informacao.blade.php` | Página do e-SIC: texto da página estática, links para o PDF de pedido presencial (PF/PJ) e o formulário de solicitação. | modelo1, modelo2, modelo5, modelo6, newsbit |
| `solicitacao-form.blade.php` | Formulário PF/PJ (RG/CNPJ, nome, e-mail, telefone, endereço, estado/cidade, mensagem, reCAPTCHA). | modelo1, modelo2, modelo5, modelo6 |
| `acompanhe-sua-solicitacao.blade.php` | Consulta de protocolo e exibição do status/answers. | modelo1..modelo6, newsbit |
| `consulta-solicitacao-ouvidoria.blade.php` | Consulta de protocolo de ouvidoria. | modelo1..modelo6 |
| `manual-de-navegacao.blade.php` | Texto da página + `iframe` com `links.link`. | modelo1..modelo6, newsbit |
| `files-list.blade.php` | Lista de arquivos para download (`$archives`). | modelo1, modelo2, modelo6 |

> **Cobertura desigual:** `modelo3` e `modelo4` **não possuem**
> `solicitar-informacao.blade.php`, `solicitacao-form.blade.php` nem
> `files-list.blade.php`. Se o layout ativo for `modelo3`/`modelo4`, a rota
> `/acesso-rapido/solicitar-informacao` cai no `getIndexStatic()` e tenta renderizar
> `portal.layouts.modelo3.informacoes-instituicao.acesso-rapido.solicitar-informacao`
> -> **View not found** (exceto o slug `solicitar-informacao`, que é hardcoded para
> o layout `newsbit` e funciona).

### 2.4 Layout `newsbit`

`v6/resources/views/portal/layouts/newsbit/` **não possui** a pasta `home/`, logo
`getTemplateActived()` aborta com 404 se `configurations.layout = 'newsbit'`
(pois `portal.layouts.newsbit.home.index` não existe). Ele existe apenas como
casca de renderização para a tela de solicitação de informação:

```php
// v6/app/Http/Controllers/Portal/QuickAccessController.php:62-66
if($slug1 === "solicitar-informacao"){
    $modelo = $this->getTemplateActived();
    $content = $contents;
    return view('portal.layouts.newsbit.informacoes-instituicao.acesso-rapido.solicitar-informacao',
        compact('contentCategoriesNews','content','states','cities', 'modelo', 'archives', 'view_pdf'));
}
```

O `$modelo` (layout ativo) é repassado para a view, que o usa para escolher o
componente de estados/cidades.

## 3. JS / Ajax

| Endpoint | Chamado de | Evento |
|---|---|---|
| `GET /cms/datatable/acesso_rapido` | `v6/public/assets/js/custom/contents/acesso-rapido/datatable.js` | carregamento da tabela |
| `POST /cms/ajax/ajust-banners` | `index.blade.php` (sortable) | fim do drag-and-drop |
| `POST /cms/set-status` | botão liga/desliga (`createActiveButton`, `alt_url` padrão `/cms/set-status`) | clique |
| `DELETE /cms/conteudo/delete/{id}` | botão excluir (`delete_btn`) | clique |
| `POST /informacao-solicitada-ajax` | `solicitar-informacao.blade.php` | clique em "#submit" |
| `POST /cms/ajax/get/acidade/by/state` | `solicitar-informacao.blade.php` | `change` em `select[name="state"]` |
| `POST /cms/ajax/get/information/by/protocol` | `acompanhe-sua-solicitacao.blade.php` | clique em "#btn-submit" |
| `POST /cms/ajax/get/answer/by/information` | `acompanhe-sua-solicitacao.blade.php` | clique em "#btn-submit" |
| `POST /cms/ajax/get/ombudsman/by/protocol` | `consulta-solicitacao-ouvidoria.blade.php` | consulta de protocolo |
| `POST /cms/ajax/get/answer/by/ombudsman` | `consulta-solicitacao-ouvidoria.blade.php` | consulta de protocolo |
| `POST /ajax/new-message/ouvidoria` (`new.message.ombudsman`) | `consulta-solicitacao-ouvidoria.blade.php` | nova mensagem |

### 3.1 DataTable do CMS

```js
// v6/public/assets/js/custom/contents/acesso-rapido/datatable.js
let collums = [
    { data: 'titulo', render: function (data) { return `<div class="p-10-0">${data}</div>`; } },
    { data: null, name: "actions", orderable: false, render: function (data) {
        return `<div class='flex justify-center vertical-middle'>`
            + createDragglabeButton(data.edit, data.id, 'item-list')
            + createActiveButton(data.status, data.id, 'item', data.active, data.inactivate)
            + createBTN(data.id, 'editar/acesso-rapido/' + data.id, data.edit, data.delete)
            + `</div>`;
    }}
];

runDatatables('acesso_rapido', collums, true, 'ASC', null);
```

O helper `runDatatables` (`v6/public/assets/js/custom/utilities/table.js:3`) faz
`GET /cms/datatable/{url}` (linha 183) e adiciona botões de exportação
**Excel, PDF, CSV e TXT** (linhas 29-135) com o título
`Prefeitura de {cidade} - {data}` (linha 27). A coluna de ações é excluída da
exportação (`columns: ':visible:not(.column-actions)'`).

### 3.2 Validação client-side do formulário e-SIC

`v6/resources/views/portal/layouts/modelo1/informacoes-instituicao/acesso-rapido/solicitar-informacao.blade.php`
carrega `assets/functions/contato-validate.js` e usa `check_string()`,
`check_email()`, `check_number()` e `check_mensagem()` antes do `$.ajax`.

## 4. Exportações

| Contexto | Formato | Como é gerado |
|---|---|---|
| Listagem do CMS | Excel, PDF, CSV, TXT | Botões do DataTable (yajra + DataTables Buttons), **client-side**, a partir do JSON retornado por `/cms/datatable/acesso_rapido`. |
| Portal | — | O módulo não exporta nada. |

## 5. O que o cidadão vê

1. **Home / cabeçalho** — barra "Acesso Rápido" (Estrutura A) com 5 atalhos
   (Perguntas Frequentes, Manual de Navegação, Solicitar Informação, Acompanhe sua
   solicitação, Transparência Fiscal) e/ou a seção de cards (Estrutura B) com os
   `contents` da categoria `acesso-rapido`.
2. **Página de atalho** — clique no card leva ao destino configurado.
3. **Perguntas Frequentes** — Título "Perguntas / Frequentes", campo de busca que
   filtra a lista sem reload.
4. **Solicitar Informação** — texto institucional + botões "Pedido Presencial PF/PJ"
   (PDFs em `/storage/formularios/solicitacao-informacao-pf.pdf` e `-pj.pdf`) +
   formulário online com reCAPTCHA; a resposta exibe o **protocolo** gerado no
   servidor.
5. **Acompanhe sua Solicitação** — busca por protocolo; exibe status
   ("EM TRAMITAÇÃO" / "ATENDIDO" / "PRORROGADO" / "INDEFERIDO"), solicitante, data,
   descrição e a lista de respostas com anexos.
6. **Consultar Solicitação de Ouvidoria** — mesma mecânica para ouvidoria.
7. **Manual de Navegação** — texto + vídeo/iframe incorporado.

## 6. O que o operador vê

1. **Listagem** — DataTable com ID, Título e Ações (arrastar, ligar/desligar, editar, excluir).
2. **Formulário** — Título, Descrição, Ícone (com seletor visual), URL, "Ativar no portal",
   "Abrir em nova guia".
3. **Feedback** — durante o drag-and-drop, o `beforeSend` do `$.ajax` insere no
   bloco `#update` um parágrafo azul com o texto "Atualizando" seguido de
   reticências; o `success` o substitui pelo parágrafo verde "Posições
   atualizadas!", que é removido após 2 s pelo `setTimeout`
   (`v6/resources/views/prefecture/contents/acesso-rapido/index.blade.php:62-74`).
4. **Menu do site** — em "Menus do Site", o menu "Acesso Rápido" (`menus.id = 3`) lista
   os 5 itens com `name` + `second_name`, `icon`, `type` (link / página estática /
   conteúdo) e ordem.

## 7. Acessibilidade e responsividade

- O bloco da home do modelo1 tem CSS próprio (`.quick-access-card`, hover com
  `translateY(-5px)`) e usa `col-sm-12 col-md-4` (3 colunas no desktop, 1 no mobile).
- A barra "Acesso Rápido" dos headers usa navbar colapsável com `navbar-toggler`
  (modelo1/modelo2) ou `data-bs-toggle` (modelo6) — as duas variantes Bootstrap
  coexistem no mesmo repositório.
- Os campos do formulário e-SIC têm `aria-label` explícito.
- O bloco da home é renderizado somente quando as duas flags estão ativas, o que
  evita elementos vazios na página.
