# Arquivo (Drive) — Views e UX

> **Escopo:** v5. Views do CMS em `v5/resources/views/prefecture/**`, views do
> portal em `v5/resources/views/portal/**`, JS em `v5/public/assets/js/**`.

---

## 1. Telas do CMS

### 1.1 Drive — galeria de mídias

| Arquivo | Função |
|---|---|
| `v5/resources/views/prefecture/contents/midias/edit.blade.php` | Tela do Drive. Inclui `prefecture.contents.midias.form` e carrega o JS da galeria. |
| `v5/resources/views/prefecture/contents/midias/form.blade.php` | Corpo da tela: campo de busca, botão "Adicionar Categoria", área `#imageBox`, modal de edição de imagem, include do editor de imagem. |

Layout: `admin.layouts.app` (AdminLTE 1.22), com o JS em
`@section('other-scripts')`:

```blade
<script src="{{ url('assets/plugins/jquery-upload-files/jquery.uploadfile.min.js') }}"></script>
<script src="{{ url('assets/js/custom/contents/midias/index.js') }}"></script>

<script>
    chargeGallery();
    setupGallery();
</script>
```

> A rota da tela é `/cms/conteudos/cadastrar/midias`
> (`v5/app/Http/Controllers/Prefecture/ContentController.php:175`:
> `if ($slug == 'midias') return $this->returnData('Drive', $slug, null, [], $id);`).
> O item de menu é adicionado em
> `v5/app/Providers/MenuServiceProvider.php:283-285`:
> `case 'midias': $event->menu->add(['text' => 'Drive', 'url' => '/cms/conteudos/cadastrar/midias', 'icon' => 'upload']);`

### 1.2 Componente de galeria embutido nos formulários de conteúdo

`v5/resources/views/prefecture/contents/components/galerias/index.blade.php`
é o include `@include('prefecture.contents.components.galerias.index')`
presente em: agenda de eventos, A Cidade, A Prefeitura, Notícias, Órgãos,
Secretarias, Páginas Estáticas e Obras
(`grep -rn "components.galerias.index" v5/resources/views/prefecture/`).

Ele tem a **mesma estrutura** do Drive (`#multipleupload`, `#imageBox`,
`#searchInput`) mas **sem** o botão de categoria nem o modal de edição.

### 1.3 Formulários que usam o componente `archive` (anexos)

`v5/resources/views/components/inputs/archive.blade.php` é o componente
que lista os arquivos anexados com download/visualizar/excluir e o botão
"Ativar exibição na página" (`view_pdf`).

Ele é incluído por `prefecture/static-pages/form.blade.php` e friends. A
diferença para a v6 está detalhada em `08-GAPS-E-DIVIDAS.md`.

### 1.4 Uso de `add_archive.js` e `delete_archive.js`

| Script | Onde é incluído | O que faz |
|---|---|---|
| `v5/public/assets/js/custom/utilities/helpers/add_archive.js` | `prefecture/contents/legislacao/form.blade.php:106`, `…/noticias/form.blade.php:277`, `…/publicacoes/form.blade.php:139`, `…/secretarias/menu/index.blade.php:149`, `…/secretarias/paginas/form.blade.php:92`, `prefecture/static-pages/form.blade.php:164` | Cria dinamicamente linhas de input de arquivo (`add_archive[][]`), com descrição e o toggle `view_pdf` (`setArchive`). |
| `v5/public/assets/js/custom/utilities/helpers/delete_archive.js` | `prefecture/contents/requerimento-diarias/configuracoes/form.blade.php:47` | Redireciona para `/deletar-arquivo-padrao` ao clicar em `#btn_delete`. |
| `v5/public/assets/js/custom/contents/paginas-estaticas/archives-pages.js` | `prefecture/static-pages/edit.blade.php:33` | `deleteArchiveStaticPage(id)` → `POST /cms/galeria/delete/{id}`. |

## 2. Telas do portal

### 2.1 Bloco "Arquivos para Download"

| Arquivo | Onde aparece |
|---|---|
| `v5/resources/views/portal/layouts/default/pages/elements/files-list.blade.php` | Bloco padrão (template `default`). |
| `v5/resources/views/portal/components/view_pdf/files-list.blade.php` | Variante que embute o PDF/imagem e filtra extensões. |
| `v5/resources/views/portal/layouts/modelo1/informacoes-prefeitura/arquivo/index.blade.php` | Bloco da página "Arquivos" do menu de informações da prefeitura (modelo1). |
| `v5/resources/views/portal/components/obras/arquivos.blade.php` | Arquivos das obras. |

Estrutura padrão:

```blade
@foreach($archives as $archive)
    <li class="d-block p-1" >
        @if (file_exist($archive->path))
            <a href="{{url($archive->path)}}" target="_blank" class="text-dark" ...>
                <div class="d-flex">
                    <span class=" d-inline-block text-center"><i class="far fa-file-archive fa-2x"></i></span>
                    <small class="d-inline-block ml-3 pt-1">{{$archive->description or $archive->name}}</small>
                </div>
            </a>
        @endif
    </li>
@endforeach
```

Pontos de atenção:

- **`file_exist($archive->path)`** usa `file_exists()` com caminho
  **relativo ao CWD do PHP**, não à raiz pública. Para `path` =
  `storage/content/...` o `public/storage` é um symlink para
  `storage/app/public`, mas `file_exists('storage/…')` a partir do
  `public/` **falha** — os arquivos podem não aparecer.
- Quando há `description`, o **nome do arquivo desaparece** (a descrição o
  substitui) — o usuário não sabe qual arquivo vai baixar.
- `view_pdf/files-list.blade.php` usa `getLargFile($view_pdf->path)` para a
  imagem e `<iframe src="/{{ $view_pdf->path }}">` para o PDF; detecta
  mobile por User-Agent e **esconde o embed em mobile** (só a lista de
  download).

### 2.2 Galeria de fotos

`v5/resources/views/portal/components/galerias/index.blade.php`:

```blade
@php
    $archives = count($archives) ? $archives->whereIn('extension', ["jpg", "jpeg", "png", "gif", "bmp", "tiff", "svg", "webp", "ico", "heic", "raw"]) : [];
@endphp

@if (count($archives))
    <div class="card p-3 news-details my-4 ">
        <h6 title="Imagens" class="text-secondary mb-4">Galeria de fotos</h6>
        <ul class="list-unstyled text-center" id="lightgallery">
            @foreach ($archives as $archive)
                @if ($archive->highlight == null && $archive->view_pdf == null)
                    <li class="d-inline-block" data-thumb="{{ url(getMinFile($archive->path)) }}"
                        data-src="{{ url(getLargFile($archive->path)) }}">
```

- Filtra por **extensão** e exclui `highlight` e `view_pdf`.
- Usa `getMinFile()`/`getLargFile()` (`v5/app/Helpers/functions.php:909-940`),
  que procuram as variantes `_min`/`_larg` geradas por `FileTrait::compress()`
  e caem para o caminho original se não existirem.

### 2.3 Layouts do portal

> O portal usa os templates `modelo1` … `modelo6` e `default`
> (`v5/resources/views/portal/layouts/`). Todos os 7 templates incluem o
> bloco de arquivos, mas **com views diferentes**:
>
> | Template | Include | Nº de telas |
> |---|---|---|
> | `default` | `portal.layouts.default.pages.elements.files-list` | 5 |
> | `modelo1` … `modelo6` | `portal.components.view_pdf.files-list` | 11 cada |
>
> Consequência: **o mesmo conteúdo mostra "Arquivos para Download" com
> comportamentos diferentes conforme o template ativo** — no `default` o
> bloco lista apenas `$archives`; nos `modelo1..6` o bloco é o de
> `view_pdf`, que **embute o PDF** e **filtra extensões**
> (`rar, zip, doc, docx, pdf, odt, xls, xlsx, xlsb, xslm, ppt, pptx`),
> além de **esconder o embed em dispositivos móveis** (detecção por
> User-Agent).

## 3. Exportações

**O módulo não gera nenhuma exportação** (sem Excel/PDF/CSV). Não há
classe em `v5/app/Exports/` associada a arquivos, nem `view_pdf` de
exportação. A "exportação" do módulo é o **download** direto do binário
armazenado.

## 4. O que o usuário final vê

| Cenário | O que aparece |
|---|---|
| Notícia com galeria | Card "Galeria de fotos" com lightgallery (imagens `_min`/`_larg`). |
| Notícia/Página com anexos | Card "Arquivos para Download" com ícone de arquivo e o nome/descrição. |
| Página com `view_pdf` | PDF (ou imagem) embutido em `<iframe>` + lista de downloads (desktop). |
| Downloads no celular | Sem embed; só a lista de arquivos. |
| Arquivo inexistente no disco | **Silenciosamente omitido** (`@if (file_exist(...))`). |
| Licitação com documentos | Card de arquivos (via `biddings_has_archives`). |
| Obra com anexos | Card de arquivos (via `work_archives`, filtro `type = file`). |
| Emenda parlamentar | Lista de arquivos (via `emendas_has_archives`) + link de download da emenda. |

## 5. O que o operador vê (CMS)

| Ação | Feedback |
|---|---|
| Upload ok | Swal "✅ Sucesso!" + item inserido no topo da galeria. |
| Upload sem categoria (modo avançado) | Swal "Preencha todos os campos!" (validação de front). |
| Categoria criada | Swal "Categoria adicionada!" (a lista exibida **não** é recarregada do servidor: `categories.push(formValues)` insere um **string**, não um objeto — o `<li>` mostra o texto puro). |
| Exclusão | `toastr.success('Arquivo deletado com sucesso.')` e o item sai da tela. |
| Erro de exclusão | `toastr.error(result.erro)`. |
| Reordenação | **Silencioso** (o `success` do AJAX não exibe nada). |
| Busca | Filtro instantâneo (client-side), sem indicação de "0 resultados". |

> A lista exibida no modal de categorias usa
> `categories.map(c => `<li>${c.name}</li>`)`. Após o `push(formValues)` o
> array passa a conter uma string; o `map` seguinte chamaria
> `c.name` de uma string → `undefined` (não quebra, mas exibe vazio).

## 6. Referências de assets

| Asset | Caminho |
|---|---|
| JS principal do Drive | `v5/public/assets/js/custom/contents/midias/index.js` |
| JS de páginas estáticas | `v5/public/assets/js/custom/contents/paginas-estaticas/archives-pages.js` |
| Helper de anexos | `v5/public/assets/js/custom/utilities/helpers/add_archive.js` |
| Helper de exclusão padrão | `v5/public/assets/js/custom/utilities/helpers/delete_archive.js` |
| Helper de ordenação (morto) | `v5/public/assets/js/custom/utilities/helpers/sortable-galerias.js` |
| Helper `myFetch` | `v5/public/assets/js/custom/utilities/functions.js` |
| CSS do editor de imagem | `v5/resources/views/prefecture/contents/components/editor-de-imagem/index.blade.php` |
| CSS sortable | `v5/public/assets/css/sortable.css` |
| CSS galeria | `v5/public/assets/css/prefecture/galeria/galeria.css` |
| CSS spinner | `v5/public/assets/css/prefecture/galeria/spinner.css` |
| Plugin de upload | `v5/public/assets/plugins/jquery-upload-files/jquery.uploadfile.min.js` |
| Lightgallery (portal) | `v5/public/assets/vendor/portal/js/lightgallery-all.min.js` |
