# Unidades de Atendimento — Views, UX e Front-end

---

## 1. Visão geral das telas

| Contexto | Arquivo | Papel |
|---|---|---|
| Portal | `v6/resources/views/portal/layouts/modelo1/unidades-de-atendimento/index.blade.php` | Listagem (modelo1). |
| Portal | `v6/resources/views/portal/layouts/modelo1/unidades-de-atendimento/show.blade.php` | Detalhe (modelo1). |
| Portal | `v6/resources/views/portal/layouts/modelo2/unidades-de-atendimento/{index,show}.blade.php` | Variantes do modelo2. |
| Portal | `v6/resources/views/portal/layouts/modelo3/unidades-de-atendimento/{index,show}.blade.php` | Variantes do modelo3. |
| Portal | `v6/resources/views/portal/layouts/modelo4/unidades-de-atendimento/{index,show}.blade.php` | Variantes do modelo4. |
| Portal | `v6/resources/views/portal/layouts/modelo5/unidades-de-atendimento/{index,show}.blade.php` | Variantes do modelo5. |
| Portal | `v6/resources/views/portal/layouts/modelo6/unidades-de-atendimento/{index,show}.blade.php` | Variantes do modelo6. |
| CMS | `v6/resources/views/prefecture/contents/unidades-de-atendimento/index.blade.php` | Listagem no AdminLTE. |
| CMS | `v6/resources/views/prefecture/contents/unidades-de-atendimento/create.blade.php` | Formulário de cadastro. |
| CMS | `v6/resources/views/prefecture/contents/unidades-de-atendimento/edit.blade.php` | Formulário de edição. |
| CMS | `v6/resources/views/prefecture/contents/unidades-de-atendimento/form.blade.php` | Campos compartilhados entre create/edit. |
| CMS (parcial) | `v6/resources/views/prefecture/contents/components/galerias/index.blade.php` | Aba "Galeria" (uploads múltiplos). |
| CMS (parcial) | `v6/resources/views/prefecture/contents/components/editor-de-imagem/index.blade.php` | Editor/crop da imagem de destaque. |
| Portal (parcial) | `v6/resources/views/portal/components/galerias/index.blade.php` | Galeria de fotos (lightgallery). |

> **Armadilha:** a pasta `unidades-de-atendimento` **só existe** em
> `modelo1`..`modelo6`. Os layouts `default`, `newsbit`, `surveys`,
> `calendar-events`, `contratos`, `diario-oficial`, `dynamics-forms`,
> `busca-diarias` e `barra-privacidade` **não** a possuem. Se
> `configurations.key = 'layout'` apontar para um deles, a rota pública falha.

## 2. Portal — listagem (`index`)

Estrutura comum às variantes: `@extends` do layout do modelo, uma seção
`breadcrumb` e a seção `content` com o `@foreach($contents as $content)` e a
paginação no rodapé. Trecho real de
`v6/resources/views/portal/layouts/modelo1/unidades-de-atendimento/index.blade.php:14-21`:

```blade
@section('content')
    <div class="col-12">
        @if(isset($contents) && count($contents) > 0)
            <ul class="list-unstyled more-news row">
                @foreach($contents as $content)
                
                <li class="col-lg-4 col-md-6 mb-2 mx-sm-auto m-md-0 mb-md-3">
                    <a target="_blank" href="{{route('unidades-de-atendimento.show', $content->slug)}}" class="row m-0 p-1  ">
```

O bloco `breadcrumb` do modelo1 é
`{{ Breadcrumbs::render('category-content', $category) }}`; os modelos 3 e 6
usam `Breadcrumbs::view('portal.layouts.modelo3.layout.breadcrumb', 'category-content', $category)`
e `Breadcrumbs::view('portal.layouts.modelo6.layout.breadcrumb','category-content', $category)`.

Diferenças entre modelos (extraídas das views):

| Modelo | Imagem do card | Título | Observações |
|---|---|---|---|
| `modelo1` | `$content->archives[0]->path` com fallback `/storage/img/exemplos/sem-imagem.png` | `str_limit($content->title, 50)` | Abre em nova aba (`target="_blank"`). |
| `modelo2` | idem modelo1 | idem | Idem modelo1. |
| `modelo3` | `getMedFile($content->present()->getArchiveContentHighlightOrThumbnail(1, 1))` | `-webkit-line-clamp: 4` | Usa o presenter. |
| `modelo4` | `getArchiveContentHighlightOrThumbnail(1, 1)` | clamp 4, cor do tema | Mostra `$content->categoryContents->name` como "categoria". |
| `modelo5` | idem modelo1 | idem | — |
| `modelo6` | `getMinFile($content->archives[0]->path)` com fallback `/storage/img/exemplos/sem-imagem-min.png` | clamp 4 | Breadcrumb via `Breadcrumbs::view('portal.layouts.modelo6.layout.breadcrumb','category-content', $category)`. |

Estado vazio: `<p class="text-muted text-center">Nenhuma registro encontrado.</p>`
(typo legado "Nenhuma registro").

Paginação: `{{ $contents->links() }}` (paginação padrão do Laravel 5.5, com as
views de paginação do layout); o modelo3 usa a variante
`{{ $contents->links('vendor.pagination.modelo3') }}`.

## 3. Portal — detalhe (`show`)

`modelo1/unidades-de-atendimento/show.blade.php`:

- Título em caixa alta (`txt-color-2`).
- Linha de metadados: `Do(a) {source} por {author} | Publicado em {d/m/Y} às {H:i}`.
- Botão de compartilhamento `addthis_inline_share_toolbox`.
- Imagem de destaque: `$content->archives->where('highlight', 1)->first()`.
- Corpo: `{!! $content->text !!}` — **HTML sem escape** (conteúdo do Summernote).
- Galeria: `@if ($content->galery === true) @include('portal.components.galerias.index') @endif`.
  O componente usa a variável `$archives` (arquivos **sem** `highlight`) e filtra
  extensões de imagem (`jpg, jpeg, png, gif, bmp, tiff, svg, webp, ico, heic, raw`).
- Barra lateral: `@include('portal.layouts.modelo1.layout.sidebar.layout')`.

`modelo3` usa `getLargFile($content->archives[0]->path)`
(`v6/resources/views/portal/layouts/modelo3/unidades-de-atendimento/show.blade.php:22`)
e `Carbon::parse($content->publication_date)`.

> **Risco de segurança:** `{!! $content->text !!}` renderiza HTML do banco sem
> sanitização. Quem tem acesso ao CMS consegue injetar script. Na v7, sanear
> com `strip_tags`/purifier na gravação.

## 4. CMS — listagem (`index`)

- Layout `admin.layouts.app` (AdminLTE 1.22).
- Cabeçalho: "Lista de Unidades de Atendimento".
- Botão "Cadastrar Unidade" → `cadastrar/unidades-de-atendimento` (exige
  `unidades-de-atendimento.create`).
- Botão de exclusão em lote (exige `unidades-de-atendimento.delete`),
  apontando para a rota `ajax.generic.content.deleteAll`.
- Tabela `id="tabela_unidades-de-atendimento"` com colunas: (checkbox de seleção
  em lote), ID, Título (70%), Ações.
- Scripts: `v6/public/assets/js/custom/utilities/deleteAll.js` e
  `v6/public/assets/js/custom/contents/unidades-de-atendimento/datatable.js`.

## 5. CMS — formulário (`form.blade.php`)

Campos:

| Campo | Tipo | Observações |
|---|---|---|
| `title` | texto, `maxlength=120` | Obrigatório. |
| `text` | textarea Summernote | Corpo em HTML. |
| `link` | texto, `maxlength=200` | Link/ID de YouTube → gravado em `links`. |
| `archive_highlight` | upload de imagem | Imagem de destaque (`archives.highlight = 1`), mimes jpg/jpeg/png/gif/webp, máx. 20 MB. |
| `galery` | checkbox | "Ativar Galeria" → `contents.galery`. |
| `category_contents_id` | hidden | Filled com `$categoryContent->id` (categoria 44). |

Blocos condicionais:

- Aba "Galeria" (`#galeria`) exibida quando `$content->galery == 1`
  (inclui `prefecture.contents.components.galerias.index`).
- Link de exibição, apenas na edição:
  `{{url('/portal/unidades-de-atendimento/'.$content->slug)}}`
  — **caminho divergente da rota real** (`/unidades-de-atendimento/{slug}`,
  sem o prefixo `/portal`): o link copiado pelo operador não funciona.

## 6. JS/Ajax

### 6.1 DataTable do CMS

`v6/public/assets/js/custom/contents/unidades-de-atendimento/datatable.js`:

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

runDatatables('unidades-de-atendimento', collums, true, 'ASC', null, true);
```

Pontos:
- `runDatatables(url, columns, ordenavel, type_order, callback, deleteAll)` em
  `v6/public/assets/js/custom/utilities/table.js:3`; o `ajax.url` é
  `/cms/datatable/${url}` (`table.js:183`).
- `deleteAll = true` → injeta a coluna de seleção múltipla e o botão de
  exclusão em lote (`table.js:16-24`).
- Exportação **Excel / PDF / CSV** habilitada por padrão em `table.js:29-140`
  (botões `excel`, `pdf`, `csv` com nome do arquivo
  `dados_exportados_YYYY-MM-DD` e título "Prefeitura de {cidade} - {data}").
- A coluna `data_e_hora` da view **não** é exibida (não existe no array de
  colunas).
- `data.galeria` corresponde ao alias `c.galery as galeria` da view SQL.

### 6.2 Uploads e galeria (CMS)

Scripts carregados no `form.blade.php`:

| Script | Função |
|---|---|
| `v6/public/assets/js/custom/utilities/helpers/add_archive.js` | Adição de arquivo ao conteúdo. |
| `v6/public/assets/js/custom/utilities/helpers/select-image.js` | Seleção da imagem de destaque. |
| `v6/public/assets/js/custom/utilities/helpers/editor-de-imagem.js` | Edição/crop. |
| `v6/public/assets/js/modulos/cropper-min.js` | Cropper. |
| `v6/public/assets/js/custom/utilities/richtext/summernote.js` | Editor Summernote. |
| `v6/public/assets/js/custom/contents/noticias/edit.js` | Comportamento de edição **compartilhado com o módulo Notícias**. |

### 6.3 Portal

Sem Ajax no módulo: listagem é renderizada no servidor com paginação nativa.
A galeria usa o plugin `lightgallery` (`v6/resources/views/portal/components/galerias/index.blade.php`).

## 7. Exportações

| Formato | Onde | Como |
|---|---|---|
| Excel / PDF / CSV | CMS (DataTable) | Botões do DataTables (`table.js`), client-side, sobre o JSON da view `unidades_de_atendimento`. |
| PDF de arquivos | Portal | Somente via `archives` com `view_pdf`; não há rota de download dedicated no módulo (usa `url($archive->path)`). |

## 8. O que o usuário vê

**Cidadão**: grade de unidades com miniatura, data e título; clique abre a
unidade com texto, imagem de destaque, autor/data e galeria de fotos;
paginação de 12 itens por página.

**Operador**: tabela ordenável com ID, título e botões de ação (galeria,
editar, excluir), exportação em três formatos, formulário com título, texto
ricco, vídeo, imagem de destaque e galeria opcional.

## 9. Acessibilidade e SEO (estado atual)

- Sem `<meta>`/canonical específico: o módulo reaproveita o layout do portal.
- Sem `alt` descritivo no card das listagens (apenas no modelo3).
- O texto do corpo é HTML livre: acessível, porém sem controle editorial.
