# Unidade Gestora — Views e UX

## 1. Views do CMS (AdminLTE)

Pasta: `v6/resources/views/prefecture/management-units/`.
Os cinco arquivos são **byte-idênticos** entre `v5/` e `v6/`.

| Arquivo | Linhas | Função |
|---|---|---|
| `index.blade.php` | 57 | Listagem (DataTable), botão "Cadastrar Unidade Gestora", botão de exclusão em lote, colunas ID/Nome/Ações. |
| `create.blade.php` | 48 | Formulário de cadastro (usa `prefecture.management-units.form`). |
| `edit.blade.php` | 31 | Formulário de edição (usa `prefecture.management-units.form`). |
| `form.blade.php` | 39 | Campos `code` (Código) e `name` (Nome), ambos obrigatórios e com `maxlenght = 120`. |
| `show.blade.php` | 30 | **Órfã**: exibe `$functionality->name`, `$functionality->description` e `$functionality->created_at` — variáveis que o controller nunca envia (bug U10). |

### 1.1 Listagem (`index.blade.php`)

```blade
// v6/resources/views/prefecture/management-units/index.blade.php:1-42
@extends('admin.layouts.app')

@section('content')

    <div class="row">
        <div class="col-xs-12">
            <div class="box box-success">
                <div class="box-header with-border">
                    <h3 class="box-title align-middle">Lista de Unidades Gestoras</h3>
                    <div class="float-right">
                        @if (has_access(['unidade-gestora.create']))
                            <a href="{{ route('unidade-gestora.create') }}" class="btn btn-success font-weight-bold btn-sm"
                                role="button"><i class="fa fa-plus"></i> Cadastrar Unidade Gestora</a>
                        @endif
                    </div>
                    @if (has_access(['unidade-gestora.delete']))
                        <div class="float-right pr-1">
                            @component('prefecture.components.deleteByLoteSubmitButton', ['route' => 'ajax.management-unit.deleteByLote'])
                            @endcomponent
                        </div>
                    @endif
                </div>
                <!-- /.box-header -->
                <div class="box-body table-responsive">
                    <table id="tabela_unidade-gestora" class="table table-striped w-100">
                        <thead>
                            <tr>
                                <th>
                                    @if (has_access(['unidade-gestora.delete']))
                                        @component('prefecture.components.deleteByLoteMasterCheckbox')
                                        @endcomponent
                                    @endif
                                </th>
                                <th>ID</th>
                                <th>Nome</th>
                                <th class="column-actions text-center"> Ações </th>
                            </tr>
                        </thead>
                        <tbody>

                        </tbody>
                    </table>
```


Pontos de UX:

- A coluna de seleção (checkbox mestre) só aparece com `unidade-gestora.delete`.
- O botão "Excluir Registro(s)" é o componente
  `prefecture.components.deleteByLoteSubmitButton`, que chama
  `submitDeleteAll("{{ route('ajax.management-unit.deleteByLote') }}")`.
- O ID da tabela (`tabela_unidade-gestora`) é usado pelo JS para montar a URL do
  DataTable: `/cms/datatable/unidade-gestora`.

### 1.2 Formulário (`form.blade.php`)

```blade
@include('components.inputs.input', [
    'size' => 6,
    'id' => 'code',
    'classes' => 'form-control',
    'titulo' => 'Código',
    'placeholder' => 'Código',
    'mandatory' => true,
    'maxlenght' => '120',
    'data' => isset($managementUnits) ? $managementUnits->code : old('code'),
])

@include('components.inputs.input', [
    'size' => 6,
    'id' => 'name',
    'classes' => 'form-control',
    'titulo' => 'Nome',
    'placeholder' => 'Nome',
    'mandatory' => true,
    'maxlenght' => '120',
    'data' => isset($managementUnits) ? $managementUnits->name : old('name'),
])
```

> **Bug U11 (confirmado):** o componente `components.inputs.input` renderiza o
> atributo HTML a partir da chave **`maxlen`**
> (`v6/resources/views/components/inputs/input.blade.php:47`:
> `@isset($maxlen) maxlength="{{ $maxlen }}" @endisset`), mas o formulário do
> módulo passa a chave **`maxlenght`** (com "h"). O atributo `maxlength`
> **não é emitido** no HTML — o limite de 120 caracteres só é aplicado no
> servidor, pela regra `max:120` do `ManagementUnitRequest`. O operador pode,
> portanto, digitar mais de 120 caracteres e só ver o erro após o envio.

Os erros de validação são exibidos no topo do formulário:

```blade
@if ($errors->any())
    <ul class="list-unstyled">
        @foreach ($errors->all() as $error)
            <li style="font-size: 13px; border-radius: 3px " class="font-weight-bold bg-red text-light px-2 my-1">{{ $error }}</li>
        @endforeach
    </ul>
@endif
```

### 1.3 Formulário de criação (`create.blade.php`)

```blade
{{ Form::open(['route' => ['unidade-gestora.index'], 'id' => 'form']) }}
{!! csrf_field() !!}
@include('prefecture.management-units.form')
<div class="box-footer">
<button class="btn btn-primary btn-flat" id="btn-submit" onclick="desabilitaBotao()">
    {{ trans('adminlte::adminlte.register') }}
</button>
```

O `onclick="desabilitaBotao()"` desabilita o botão e exibe um GIF de carregamento
(`/assets/images/loading.gif`) durante o envio.

> O `Form::open` aponta para `unidade-gestora.index` (bug U7) — funciona apenas
> porque `POST /cms/unidade-gestora` é a rota `store` do `Route::resource`.

### 1.4 Formulário de edição (`edit.blade.php`)

```blade
{{ Form::model($managementUnits, ['route' => ['unidade-gestora.update',$managementUnits->id], 'method' => 'PUT', 'id' => "unidade-gestora-form"])}}
@include('prefecture.management-units.form')
```

> `Form::model` com `method => 'PUT'` gera o campo oculto `_method = PUT`, que o
> Laravel transforma em PUT real.

## 2. Componentes reutilizados

| Componente | Caminho | Uso |
|---|---|---|
| `prefecture.components.deleteByLoteSubmitButton` | `v6/resources/views/prefecture/components/deleteByLoteSubmitButton.blade.php` | Botão "Excluir Registro(s)" com contador de selecionados; `onclick='submitDeleteAll("{{route($route)}}")'`. |
| `prefecture.components.deleteByLoteMasterCheckbox` | `v6/resources/views/prefecture/components/deleteByLoteMasterCheckbox.blade.php` | Checkbox mestre `#checkAll`. |
| `prefecture.components.deleteByLoteCheckbox` | `v6/resources/views/prefecture/components/deleteByLoteCheckbox.blade.php` | Checkbox de linha: `<input class="select" type="checkbox" name="toDeleteAll[]" value={{ $value }}>`. |
| `components.inputs.input` | `v6/resources/views/components/inputs/input.blade.php` | Campo de texto com rótulo, placeholder, obrigatório e máscara. |
| `admin.layouts.app` | `v6/resources/views/admin/layouts/app.blade.php` | Layout AdminLTE do CMS. |

## 3. JS / Ajax

### 3.1 DataTable da listagem

`v6/public/assets/js/custom/contents/licitacoes/unidades-gestoras/datatable.js`:

```js
let collums = [
    {
        data: 'nome',
        render: function (data) {
            return `<div class='vertical-middle' style='padding:8px'>${data}</div>`;
        }
    },
    {
        data: null,
        name: "actions",
        orderable: false,
        render: function (data) {
            return `<div class='flex justify-center'>`
                + createBTN(data.id, `unidade-gestora/${data.id}/edit`, data.edit, data.delete, `unidade-gestora/${data.id}`)
                + `</div>`;
        }
    }
];

runDatatables('unidade-gestora', collums, true, 'ASC', null, true);
```

Parâmetros de `runDatatables`
(`v6/public/assets/js/custom/utilities/table.js:3`):

| Posição | Valor | Efeito |
|---|---|---|
| `url` | `'unidade-gestora'` | `GET /cms/datatable/unidade-gestora` |
| `columns` | `collums` | 2 colunas + a coluna `value` inserida automaticamente |
| `ordenavel` | `true` | habilita ordenação |
| `type_order` | `'ASC'` | ordenação inicial |
| `callback` | `null` | — |
| `deleteAll` | `true` | **habilita a coluna de checkbox de seleção** (`createDeleteAllButton(data.id, data.delete)`) |

O helper usa `url: /cms/datatable/${url}` (linha 183) e oferece exportação
**Excel, PDF, CSV e TXT** (linhas 29-135). A coluna de ações é excluída da
exportação via `columns: ':visible:not(.column-actions)'`.

> Os botões são **URLs relativas**: `unidade-gestora/{id}/edit` e
> `unidade-gestora/{id}`. Como a listagem está em `/cms/unidade-gestora`, eles
> resolvem para `/cms/unidade-gestora/{id}/edit` e `/cms/unidade-gestora/{id}` —
> funcional, mas frágil (a URL base é implícita).

### 3.2 Exclusão em lote

`v6/public/assets/js/custom/utilities/deleteAll.js`:

```js
// v6/public/assets/js/custom/utilities/deleteAll.js
function submitDeleteAll(routeDelete) {

    const toDelete = $('input[name="toDeleteAll[]"]:checked').map(function () {
        return this.value
    }).get();

    if (!toDelete.length) return Swal.fire('Erro', 'Nenhum registro foi selecionado para exclusão.', 'info');

    Swal.fire({
        icon: 'info',
        title: 'Você tem certeza?',
        text: `Foram selecionado(s) ${toDelete.length} registros para serem excluídos`,
        customClass: {
            confirmButton: 'btn btn-success m-2',
            cancelButton: 'btn btn-danger m-2'
        },
        buttonsStyling: false,
        showCancelButton: true,
        confirmButtonText: 'Sim, pode excluir',
        cancelButtonText: 'Não, voltar',
    }).then((result) => {
        if (result.isConfirmed) {
            $.ajax({
                url: routeDelete,
                method: 'POST',
                dataType: 'json',
                data: {
                    _token: $('meta[name="csrf-token"]').attr('content'),
                    toDelete: toDelete
                },
                success: function (response) {
                    let message = 'Registro(s) deletados com sucesso!';
                    if (response.success) message = response.success;

                    Swal.fire(message, '', 'success').then(() => {
                        datatable ? datatable.ajax.reload() : window.location.reload();
                        $('#checkAll').prop('checked', false);
                        $('#countDeleteLote').html(`(0)`);
                    });
                },
                error: function (err) {
                    if (err.responseJSON.erro) {
                        return Swal.fire('Erro', err.responseJSON.erro, 'error');
                    } else {
                        return Swal.fire('Erro', 'Ocorreu um erro! Por favor entre em contato com o suporte técnico.', 'error');
                    }
                }
            });
        }
    })
};
```

Pontos:

- A confirmação é um `Swal.fire` (SweetAlert2) com a contagem de selecionados.
- O envio é `POST` com `toDelete` como **array** (o `$.ajax` do jQuery serializa
  arrays como `toDelete[]=1&toDelete[]=2`).
- Em sucesso, a resposta é `true`/`false` (JSON cru) — o JS testa
  `response.success`, que é `undefined`; a mensagem exibida é sempre
  "Registro(s) deletados com sucesso!".
- Em erro, o JS procura `err.responseJSON.erro` — campo que existe na resposta
  do `destroy` individual, mas **não** na do `deleteByLote` (que devolve
  `false`).

### 3.3 Exclusão individual

O botão `delete_btn` gerado por `createBTN`
(`v6/public/assets/js/custom/utilities/table.js:227-264`) faz a requisição de
exclusão. O `target` do botão é `unidade-gestora/{id}` (rota `destroy`).

## 4. Exportações

| Formato | Como é gerado |
|---|---|
| Excel, PDF, CSV, TXT | Botões do DataTable (yajra + DataTables Buttons), **client-side**, a partir do JSON de `/cms/datatable/unidade-gestora`. O título do arquivo é `Prefeitura de {cidade} - {data}` (`table.js:27`). |

A exportação **não inclui a coluna `code`** (a view SQL não a expõe) — apenas
ID, Nome e (na planilha) a coluna de valor.

## 5. O que o operador vê

1. **Listagem** — tabela com "ID", "Nome" e "Ações"; ordenação por nome
   crescente; botões de exportação no topo.
2. **Ações por linha** — pencil (editar) e lixeira (excluir), condicionados às
   permissões `unidade-gestora.edit` / `unidade-gestora.delete` (enviadas pelo
   `struct_views` no JSON).
3. **Formulário** — dois campos (Código, Nome), ambos com asterisco de obrigatório
   e limite de 120 caracteres.
4. **Feedback** — flashes "Unidade Gestora cadastrada com sucesso.",
   "Unidade Gestora atualizada com sucesso.", "Ocorreu um erro ao tentar salvar
   no banco de dados." e "Ocorreu um erro! Por favor entre em contato com o
   suporte técnico.".
5. **Exclusão em lote** — botão vermelho "Excluir Registro(s) (N)" que só aparece
   quando há seleção.

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

**Nada.** O módulo não tem página pública, rota em `web.php` nem entrada no
menu do portal. O efeito no cidadão é indireto: a classificação correta das
licitações por unidade gestora, exibida na área de licitações do portal.

## 7. Integração com o módulo de Licitações

No formulário de licitação (`v6/resources/views/prefecture/biddings/form.blade.php:33-42`):

```blade
@include('components.inputs.select', [
    'size' => 4,
    'alt_default' => 'Selecione a Unidade Gestora',
    'id' => 'management_units_id',
    'titulo' => 'Unidade Gestora',
    'mandatory' => true,
    'data' => $unidadeGestora,
    'value' => isset($licitacao->management_units_id)
        ? $licitacao->management_units_id
        : old('management_units_id'),
])
```

`$unidadeGestora` é preenchido por
`ManagementUnit::get(['name', 'id'])` no `BiddingController` (linhas 74 e 136).
O componente `components.inputs.select` renderiza `value = $content->id` e o
rótulo `$content->name`.

> O `select` mostra **apenas o nome**; o `code` da unidade não é exibido. Como o
> `code` é o identificador funcional (por exemplo, `1`, `2`, `3`), duas unidades
> com nomes parecidos são indistinguíveis para o operador.
