# Outras Configurações — Views e UX

> Módulo `outras-configuracoes`. As telas são compartilhadas com o módulo
> `configuracoes-da-instituicao` (`../configuracoes-da-instituicao/`).

---

## 1. Inventário de telas

| Arquivo | Função | Usado pelo módulo |
|---|---|---|
| `v6/resources/views/prefecture/configurations/index.blade.php` | Listagem (DataTable) — **tela do módulo** | Sim (destino final do clique no menu) |
| `v6/resources/views/prefecture/configurations/create.blade.php` | Formulário de cadastro | Sim (botão "Cadastrar Configuração") |
| `v6/resources/views/prefecture/configurations/edit.blade.php` | Formulário de edição | Sim (botão editar da tabela) |
| `v6/resources/views/prefecture/configurations/form.blade.php` | Formulário compartilhado (incluído pelos dois anteriores) | Sim |
| `v6/resources/views/prefecture/configurations/show.blade.php` | Detalhe de uma configuração (rota `configuracoes.show`) | Não usado no fluxo |
| `v6/resources/views/vendor/adminlte/page.blade.php` | Layout AdminLTE + sidebar do CMS | Sim (entrada do menu) |

**Não existe** `v6/resources/views/prefecture/configurations/outros/` — não há
tela de categoria para `outros`. As categorias com formulário próprio
(`configuracoes`, `temas`, `barra-privacidade`) têm diretórios próprios em
`v6/resources/views/prefecture/configurations/`.

## 2. A tela de listagem

`v6/resources/views/prefecture/configurations/index.blade.php` (completo):

```blade
@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 Configurações</h3>
                    <div class="float-right">
                        <a href="{{ route('configuracoes.create') }}" class="btn btn-success font-weight-bold btn-sm"
                            role="button"><i class="fa fa-plus"></i> Cadastrar Configuração</a>
                    </div>
                </div>
                <!-- /.box-header -->
                <div class="box-body table-responsive">
                    <table id="tabela_configuracoes" class="table table-striped ">
                        <thead>
                            <tr>
                                <th whidth="5%">ID</th>
                                <th>Título</th>
                                <th>Tipo</th>
                                <th>Categoria</th>
                                <th class="column-actions text-center">Ações</th>
                            </tr>
                        </thead>

                        <tbody>

                        </tbody>
                    </table>

                </div>
                <!-- /.box-body -->
            </div>
            <!-- /.box -->
        </div>
    </div>
@endsection

@section('other-scripts')
    @parent
    <script src="{{ asset('assets/js/custom/config/configuracoes/datatable.js') }}"></script>
@endsection
```

Observações de UX:

| Ponto | Comportamento |
|---|---|
| `<tbody>` vazio | Preenchido **somente** por AJAX; a variável `$configurations` recebida do controller não é usada na view |
| Coluna "ID" | Mostra o `row_number()` da view SQL, não o `id` real (desalinhado com a URL de edição) |
| Coluna "Categoria" | Mostra o `slug` da categoria (`site`, `temas`, `covid`, `barra-privacidade`, `dashboard`) |
| Botão "Cadastrar Configuração" | Visível para qualquer usuário que chegue à tela; o `create()` bloqueia quem não for `super-admin` |
| Exportação | Botões Excel/PDF/CSV/TXT injetados pelo helper `runDatatables` |

## 3. Formulário

`v6/resources/views/prefecture/configurations/form.blade.php` — campos:

| Campo | Controle | Observações |
|---|---|---|
| `category_configurations_id` | `Form::select` | Default **4** (`outros`) quando não há `$configuration` |
| `type` | `Form::select` | `text`, `textarea`, `file`, `checkbox` |
| `title` | `Form::text` | |
| `max_input` | `Form::text` | "Nº Máximo de Caracteres" |
| `min_input` | `Form::text` | "Nº Mínimo de Caracteres" |
| `description` | `Form::text` | |
| `small_description` | `Form::text` | |
| `placeholder` | `Form::text` | |
| `order` | `Form::text` | "Posição" |
| `notnull` | hidden 0 + checkbox 1 | "Obrigatório?" |
| `key` | `Form::text` | **Fica `disabled`** quando `status_create == true` |
| `value` | texto / textarea / file / checkbox | Muda conforme `type`; no cadastro é sempre texto |

Trecho real da seleção de categoria (default `outros`):

```blade
{{ Form::select( 'category_configurations_id', $categories, (isset($configuration)) ? $configuration->category_configurations_id : 4,
[
    'class' => 'form-control',
]) }}
```

Trecho real da imutabilidade da chave:

```blade
@if(isset($configuration) && $configuration->status_create == true)
    {{ Form::text( 'key', (isset($configuration)) ? $configuration->key : old('key'),
    [
        'class' => 'form-control',
        'placeholder' => 'Chave',
        'disabled' => 'true'
    ]) }}
@else
    {{ Form::text( 'key', (isset($configuration)) ? $configuration->key : old('key'),
    [
        'class' => 'form-control',
         'placeholder' => 'Chave'
    ]) }}
@endif
```

> Campo `disabled` **não é enviado** pelo navegador. Logo, uma configuração com
> `status_create = true` tem a `key` preservada apenas porque o `update()`
> usa `$request->all()` — se a chave não vier no POST, ela não é alterada.

## 4. JavaScript

| Arquivo | Papel |
|---|---|
| `v6/public/assets/js/custom/config/configuracoes/datatable.js` | Define as colunas da DataTable deste módulo |
| `v6/public/assets/js/custom/utilities/table.js` | `runDatatables()`, `createBTN()`, botões de exportação, `addDelete()` |
| `v6/public/assets/js/custom/utilities/exec.js` | Confirmação de exclusão (`[data-toggle=delete_btn]`) |

Colunas (`v6/public/assets/js/custom/config/configuracoes/datatable.js`):

```js
let collums = [

    {
        data: 'titulo',
        render: function (data) {
            return `<div class='vertical-middle' style='padding:8px'>${data}</div>`;
        }
    },
    {
        data: 'tipo',
        render: function (data) {
            return `<div class='vertical-middle' style='padding:8px'>${data}</div>`;
        }
    },
    {
        data: 'categoria',
        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 vertical-middle'>`
                + createBTN(data.id, `/cms/configuracoes/${data.id}/edit`, data.edit, data.delete, `/cms/configuracoes/${data.id}`)
                + `</div>`;
        }
    }
];

runDatatables('configuracoes', collums);
```

Comportamento do `runDatatables()` (`v6/public/assets/js/custom/utilities/table.js`):

| Item | Detalhe |
|---|---|
| Endpoint AJAX | `/cms/datatable/${url}` → `/cms/datatable/configuracoes` |
| Coluna extra | A helper insere uma coluna inicial com `data: 'value'` (o `row_number()` da view SQL) |
| Exportações | Excel, PDF (A4 paisagem, larguras de coluna calculadas), CSV e TXT |
| Exclusão | `createBTN` gera botão com `data-toggle="delete_btn"` e `target="/cms/configuracoes/{id}"`; `addDelete()` faz `myFetch(url, 'DELETE')` e recarrega a DataTable |
| Feedback | `toastr.success(result.success)` / `toastr.error(result.erro)` |

```js
function addDelete() {
    if (document.querySelector('.delete_btn')) {
        [...document.querySelectorAll('.delete_btn')].map(value => {
            value.onclick = async (e) => {
                e.preventDefault();
                let url = `/cms/conteudo/${value.id}`;
                if (value.getAttribute('target')) url = value.getAttribute('target');
                let result = await myFetch(url, 'DELETE');

                if (result) {
                    if (result.erro || result.success) {
                        if (result.erro) {
                            toastr.error(result.erro);
                        } else {
                            toastr.success(result.success);
                        }
                    }
                }

                datatable.ajax.reload();
            };
        })
    }
}
```

> O `url` padrão é `/cms/conteudo/${id}` (copy-paste de outro módulo); no
> módulo de configurações o atributo `target` sempre sobrescreve com
> `/cms/configuracoes/{id}`.

## 5. Script inline de troca de tipo

`create.blade.php` e `edit.blade.php` trazem o mesmo script que troca o campo
`value` conforme o `type` selecionado:

```js
$('select[name="type"]').on('change', function () {
    var opt = $(this).val();

    if (opt == 'text') {
        $('.config-value').empty();
        $('.config-value').append('{{ Form::text( "value", (isset($configuration)) ? $configuration->value : old("value"),[ "class" => "form-control","placeholder" => "Valor"   ]) }}')
    }
    if (opt == 'textarea') {
        $('.config-value').empty();
        $('.config-value').append("<textarea class='form-control' name='value'> @if(isset($configuration)) {{$configuration->value or old("value")}}@endif </textarea> ");
    }

    if (opt == 'file') {
        $('.config-value').empty();
        $('.config-value').append("<input type='file' name='value'> ");
    }

    if (opt == 'checkbox') {
        $('.config-value').empty();
        $('.config-value').append("<input name='value'  type='checkbox' value='1'>");
    }
});
```

## 6. O que o operador vê (CMS) vs. o que o cidadão vê (portal)

| Faixa | Observação |
|---|---|
| CMS | Menu "Outras Configurações" (ícone `fa fa-cubes`) → listagem com todas as configurações do sistema; cadastro/edição restritos a `super-admin` |
| Portal público | Nada. Não há rota pública nem view de portal associada à categoria `outros` |
| Efeito indireto | Chaves técnicas alteradas em `site`/`dashboard` afetam o portal (e-mail, analytics), mas pela tela do módulo `configuracoes-da-instituicao` (`../configuracoes-da-instituicao/`) |

## 7. Layout do CMS

| Item | Valor |
|---|---|
| Layout | `admin.layouts.app` (AdminLTE 1.22) |
| Wrapper do menu | `v6/resources/views/vendor/adminlte/page.blade.php` |
| Variável `$modulos` | Injetada na sidebar via `@inject('modulos', 'App\Http\Model\Admin\Modulos')` e filtrada por `whereIn('slug', [... 'outras-configuracoes' ...])` (linhas 115-124) |
| Layout do portal | Não se aplica a este módulo |

> **Risco verificado**: `admin.layouts.app` e `adminlte::page` **não** estão
> entre as views compostas por `v6/app/Providers/ModulosServiceProvider.php`
> (apenas `admin.layouts.dashboard` e `admin.layouts.dashboard-legacy`). Na
> prática, fora do dashboard, o menu "Outras Configurações" **não é exibido**,
> embora as telas existam e funcionem. Detalhamento em
> `08-GAPS-E-DIVIDAS.md`.
