# Páginas Estáticas — Views e UX

## 1. CMS — telas

Pasta: `v6/resources/views/prefecture/static-pages/`

| Arquivo | Linhas | Função |
|---|---|---|
| `index.blade.php` | 59 | Listagem (datatable `tabela_paginas_staticas`) |
| `create.blade.php` | 60 | Wrapper do formulário de criação |
| `edit.blade.php` | 86 | Wrapper do formulário de edição (galeria + Link Permanente) |
| `form.blade.php` | 164 | Formulário completo |
| `show.blade.php` | 30 | Pré-visualização |

Estrutura da listagem (`index.blade.php`):

```blade
<h3 class="box-title align-middle">Lista de Páginas</h3>
@if (has_access(['pagina-estatica.create']))
    <a href="{{ route('pagina-estatica.create') }}" class="btn btn-success font-weight-bold btn-sm"
        role="button"><i class="fa fa-plus"></i>
        Cadastrar Página Estática</a>
@endif
@if (has_access(['pagina-estatica.delete']))
    <div class="float-right pr-3">
        @component('prefecture.components.deleteByLoteSubmitButton', ['route' => 'ajax.static-page.deleteByLote'])
        @endcomponent
    </div>
@endif
<table id="tabela_paginas_staticas" class="table  table-striped table-responsive w-100">
    <thead>
        <tr>
            <th width="5%">
                    @if (has_access(['pagina-estatica.delete']))
                        @component('prefecture.components.deleteByLoteMasterCheckbox')
                        @endcomponent
                    @endif
            </th>
            <th>ID</th>
            <th>Título</th>
            <th class="column-actions text-center">Ações</th>
        </tr>
    </thead>
```

Scripts (`index.blade.php`):

```blade
<script src="{{ url('assets/js/custom/utilities/deleteAll.js') }}"></script>
<script src="{{ asset('assets/js/custom/contents/paginas-estaticas/datatable.js') }}"></script>
```

Layout do CMS: `admin.layouts.app` (AdminLTE 1.22 / Bootstrap 3).

## 2. CMS — formulário

`v6/resources/views/prefecture/static-pages/form.blade.php`

| Campo | Componente | Observações |
|---|---|---|
| Link Permanente | `components.inputs.input` `id = 'slug'` | Exibido **apenas** quando `status_create == 0`; prefixo `url('/') . '/'`; botão "Acessar" |
| Título | `components.inputs.input` `id = 'title'` | obrigatório, `maxlen = 120` |
| Link | `components.inputs.input` `id = 'link'` | `maxlen = 180`; valor vem de `$content->linksUnique['link']` |
| Redirecionar para Link Externo | `components.inputs.checkbox` `id = 'is_external'` | marcado com `$content->is_external` |
| Layout de exibição | `components.inputs.radio` `name = 'layout'` | `1` = Com Barra Lateral, `2` = Sem Barra Lateral |
| Texto | `components.inputs.textarea` `id = 'text'` | Summernote |
| Ativar Galeria | `components.inputs.checkbox` `id = 'galery'` | classe `active-galery` |
| Arquivos | `components.inputs.archive` | `delete_function = 'deleteArchiveStaticPage'` |
| Galeria | `prefecture.contents.components.galerias.index` | incluída só quando `galery == 1` |

Trechos relevantes:

```blade
@if (isset($content) && $content->status_create == 0)
<div class="row d-flex">
    @include('components.inputs.input', [
    'size' => 4,
    'id' => 'slug',
    'placeholder' => 'URL',
    'mandatory' => true,
    'titulo' => 'Link Permanente',
    'link_permanente' => url('/') . '/',
    'maxlenght' => '120',
    'data' => isset($content) ? $content->slug : old('slug'),
    ])

    <div class="d-inline-block ml-3 mt-5">
        <a href="{{ url("/$content->slug") }}" target="_blank">Acessar <i class="fa fa-external-link fa-1x"></i></a>
    </div>
</div>
@endif
```

```blade
@include('components.inputs.checkbox', [
'size' => 12,
'id' => 'is_external',
'titulo' => 'Redirecionar para Link Externo',
'data' => isset($content) ? $content->is_external : null,
])
```

> O botão "Ir para galeria" só aparece quando a página **já** tem
> `galery == 1`; na criação, é preciso salvar uma vez para habilitar a
> galeria.

## 3. CMS — JavaScript

| Arquivo | Função |
|---|---|
| `v6/public/assets/js/custom/contents/paginas-estaticas/datatable.js` | Colunas e ações da datatable |
| `v6/public/assets/js/custom/contents/paginas-estaticas/archives-pages.js` | Exclusão de arquivo da galeria |
| `v6/public/assets/js/custom/utilities/deleteAll.js` | Exclusão em lote |
| `v6/public/assets/js/custom/utilities/table.js` | `createLinkButton`, `createGaleryButton`, `createBTN` |

Colunas da datatable (`datatable.js`):

```js
let collums = [{
        data: 'titulo',
        render: function(data) {
            return `<div class='vertical-middle' style='padding:8px'>${data}</div>`;
        }
    },
    {
        data: null,
        orderable: false,
        render: function(data) {
            return `<div class='flex justify-center'>` +
                createLinkButton(data.slug) +
                createGaleryButton(`pagina-estatica/${data.id}/edit#galeria`, data.galery, data.edit) +
                createBTN(data.id, `pagina-estatica/${data.id}/edit`, data.edit, data.delete, `pagina-estatica/${data.id}`) +
                `</div>`;
        }
    }
];

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

O botão de link abre a página na raiz do domínio:

```js
function createLinkButton(slug) {
    let url = `${window.location.origin}/${slug}`;
    return `<a href="${url}" class="btn btn-default" data-toggle="tooltip" target=”_blank” data-title="Abrir Página estática"><i class="fa fa-link"></i></a>`;
}
```

> **Bug:** `data.galery` não existe na view SQL `paginas_estaticas` (a coluna
> foi removida em `2024_10_10_120559_update_view_static_pages.php`), logo
> `createGaleryButton` recebe `undefined` e **desabilita** o botão
> (`v6/public/assets/js/custom/utilities/table.js:310-318`).

Exclusão de arquivo da galeria (`archives-pages.js`):

```js
async function deleteArchiveStaticPage(id) {
    let result = await myFetch(`/cms/galeria/delete/${id}`, 'post');

    if (result.success) {
        let elementToRemove = document.querySelector(`.id_${id}`);
        if (elementToRemove) elementToRemove.remove();
        toastr.success(result.success);
    } else {
        toastr.error(result.erro);
    }

    location.reload();
}
```

> O endpoint chamado é `/cms/galeria/delete/{id}`, que **não** é a rota
> `ajax.delete.static.files.gallery` do `StaticPageController` (que espera
> `archive_id` e `content` no corpo). O endpoint do `ArchiveController`
> (rotas `galeria.*`) é que remove o arquivo; a rota do
> `StaticPageController` fica sem uso por este JS.

## 4. Portal — view de exibição

Arquivo único: `v6/resources/views/portal/statics/show.blade.php`
(o layout do portal é escolhido dinamicamente por
`@extends("portal.layouts.$modelo.layout.layout")`).

```blade
@section('content')
    @if ($modelo == 'modelo4')
        <div class="row pt-5">
    @endif
    <div class="{{ $content->layout == 1 ? 'col-xl-9 col-lg-8' : 'col-lg-12' }}">
        @if ($null == false)
            @if ($modelo != 'modelo4')
                <p class="h4 text-uppercase txt-color-2 font-or">{{ $content->title }}</p>
                <i class="border-title d-block bg-color-1 mb-4"></i>
            @endif

            {{-- dentro dos textos podem conter iframes, isso impede de quebrar o layout --}}
            <style>
                #pg_estatica iframe {
                    max-width: 100%;
                }
            </style>
            <div id="pg_estatica" class="text-secondary text-content">{!! $content->text !!}</div>

            @if (count($archives) > 0 || $view_pdf != null)
                @include('portal.components.view_pdf.files-list')
            @endif

            @if ($content->galery == true && count($galery) > 0)
                @include('portal.components.galerias.index')
            @endif

            @if (!empty($content->linksUnique->link))
                @include('portal.statics.video')
            @endif
        @else
            <div class="text-center  p-4 font-mr">
                <h4 style="color: #ef6464;">PÁGINA NÃO ENCONTRADA.</h4>
                <div class="mt-5 text-secondary">
                    <i class="far fa-frown fa-9x"></i>
                </div>
            </div>
        @endif
    </div>

    {{-- Sidebar --}}
    @if ($content->layout == 1)
        <div class="col-xl-3 col-lg-4">
            <div class="pl-20 pl-md-0">
                @include("portal.layouts.$modelo.layout.sidebar.layout")
            </div>
        </div>
    @endif
    @if ($modelo == 'modelo4')
        </div>
    @endif
@endsection
```

| Elemento | Condição |
|---|---|
| Título | `$null == false` e `$modelo != 'modelo4'` |
| Corpo HTML | sempre (quando a página existe) |
| Anexos + PDF inline | `count($archives) > 0 || $view_pdf != null` |
| Galeria | `$content->galery == true && count($galery) > 0` |
| Vídeo | `!empty($content->linksUnique->link)` |
| Barra lateral | `$content->layout == 1` |
| Mensagem "PÁGINA NÃO ENCONTRADA" | `$null == true` |

> O `layout` decide a largura da coluna (`col-xl-9 col-lg-8` vs
> `col-lg-12`) **e** a presença da barra lateral.

Componentes do portal utilizados:

| Componente | Caminho |
|---|---|
| Arquivos / PDF inline | `v6/resources/views/portal/components/view_pdf/files-list.blade.php` |
| Galeria | `v6/resources/views/portal/components/galerias/index.blade.php` |
| Vídeo | `v6/resources/views/portal/statics/video.blade.php` |
| Barra lateral | `v6/resources/views/portal/layouts/{modelo}/layout/sidebar/layout.blade.php` |

## 5. Portal — outras telas do pacote

| Arquivo | Função |
|---|---|
| `v6/resources/views/portal/statics/contact.blade.php` | Página de contato (template próprio) |
| `v6/resources/views/portal/statics/form-contact.blade.php` | Formulário de contato |
| `v6/resources/views/portal/statics/video.blade.php` | Player de vídeo (YouTube/Vimeo) |

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

- Ao acessar `/{slug}`: breadcrumb "Home > {título}", título, corpo HTML
  (com iframes ajustados para não quebrar o layout), anexos, PDF inline,
  galeria e vídeo.
- Se a página não existir: a mesma URL devolve **200** com a mensagem
  "PÁGINA NÃO ENCONTRADA." e um ícone de tristeza.
- Se a página for marcada como externa: redirecionamento imediato para a
  URL configurada (sem renderizar nada).
- Se a slug for reservada (`contato`, `ouvidoria`, ...): redirecionamento
  para o módulo correspondente.

## 7. O que o operador vê

| Elemento | Origem |
|---|---|
| Coluna "ID" e "Título" | view `paginas_estaticas` |
| Botão de link | `createLinkButton(data.slug)` -> `https://{dominio}/{slug}` |
| Botão de galeria | `createGaleryButton(...)` (hoje sempre desabilitado) |
| Botão de edição | `pagina-estatica/{id}/edit` |
| Botão de exclusão | `pagina-estatica/{id}` |
| Auditoria | `activity()` em create/edit/delete/acesso |
| Métrica de menu | `menuClicks('pagina-estatica')` |

## 8. Exportações

Não há exportação neste módulo.
