# 04 — Views, UX, JS e Assets

## 1. CMS — telas do operador

| View | Caminho | Função |
|---|---|---|
| Lista de questionários | `v6/resources/views/prefecture/dynamics-forms/questionnaire/index.blade.php` | Tabela `tabela_listagem_questionarios` (tbody preenchido por DataTable), botão "Cadastrar Formulário" (protegido por `has_access(['questionarios.create'])`) e botão de exclusão em lote (`has_access(['questionarios.delete'])`). |
| Criar | `v6/resources/views/prefecture/dynamics-forms/questionnaire/create.blade.php` | Wrapper do formulário; recebe `askTypes` e `askStyles` do controller. |
| Editar | `v6/resources/views/prefecture/dynamics-forms/questionnaire/edit.blade.php` | Mesmo formulário + `id`; o `edit.js` carrega o JSON do questionário. |
| Formulário | `v6/resources/views/prefecture/dynamics-forms/questionnaire/form.blade.php` | Campos do questionário + área `#Question.questions` (lista de categorias) + botão "Adicionar Campo" + `@include` dos modais. |
| Extras | `v6/resources/views/prefecture/dynamics-forms/questionnaire/extras.blade.php` | Blocos condicionais do modal de pergunta (opções, `isImg`, `min`/`max`, campo de valor padrão). |
| Modais | `v6/resources/views/prefecture/dynamics-forms/questionnaire/modals.blade.php` | Modal de pergunta, modal de categoria, modal de lista de opções (`modalOptionList`), modal de categoria pai. |
| Lista de preenchidos | `v6/resources/views/prefecture/dynamics-forms/filled-questionnaire/index.blade.php` | Tabela `tabela_listagem_questionarios_preenchidos`. |
| Conteúdo (ajax) | `v6/resources/views/prefecture/dynamics-forms/filled-questionnaire/content.blade.php` | HTML do painel de respostas (injetado por JS). |
| Respostas | `v6/resources/views/prefecture/dynamics-forms/filled-questionnaire/responses.blade.php` | Tela "Respostas do questionário" (resumo + painel individual + botão exportar). |

Componentes Blade compartilhados do CMS: `v6/resources/views/components/custom/contents/formularios-dinamicos/checkbox-label.blade.php`, `draggable-box.blade.php`, `select-icon.blade.php`, `table-modal.blade.php`.

### 1.1 Campos do formulário do questionário

Extraído de `v6/resources/views/prefecture/dynamics-forms/questionnaire/form.blade.php`:

| Campo | id | Validação |
|---|---|---|
| Habilitar formulário | `statusQuestionnaire` | checkbox |
| Habilitar resultados | `hasResultQuestionnaire` | checkbox (só na edição) |
| Link Permanente (slug) | `slugQuestionnaire` | espelha `route('portal.formularios.edit', '')` + `/` + slug |
| Título do Formulário | `titleQuestionnaire` (`name="title"`) | required |
| Data de publicação | `publishedAtQuestionnaire` | required, máscara `br-data-tempo`, formato `d/m/Y H:i` |
| Descrição | `descriptionQuestionnaire` | Summernote (HTML) |
| Aviso Sobre o Envio | `submitInfoQuestionnaire` (`name="submit_info"`) | texto simples |

## 2. Portal — telas do cidadão

### 2.1 Layout e view por modelo

O layout vem de `Configuration` key `layout` (`getTemplateActived()` em `v6/app/Http/Controllers/Admin/Controller.php:39`). Existem **seis** variantes de portal com as views do módulo:

- `v6/resources/views/portal/layouts/modelo1/dynamics-forms/questionnaire/edit.blade.php`
- `v6/resources/views/portal/layouts/modelo2/dynamics-forms/questionnaire/edit.blade.php`
- `v6/resources/views/portal/layouts/modelo3/dynamics-forms/questionnaire/edit.blade.php`
- `v6/resources/views/portal/layouts/modelo4/dynamics-forms/questionnaire/edit.blade.php`
- `v6/resources/views/portal/layouts/modelo5/dynamics-forms/questionnaire/edit.blade.php`
- `v6/resources/views/portal/layouts/modelo6/dynamics-forms/questionnaire/edit.blade.php`
- e, para cada modelo, a tela de resultado: `v6/resources/views/portal/layouts/modelo1/dynamics-forms/filled-questionnaire/show.blade.php`, `v6/resources/views/portal/layouts/modelo2/dynamics-forms/filled-questionnaire/show.blade.php`, `v6/resources/views/portal/layouts/modelo3/dynamics-forms/filled-questionnaire/show.blade.php`, `v6/resources/views/portal/layouts/modelo4/dynamics-forms/filled-questionnaire/show.blade.php`, `v6/resources/views/portal/layouts/modelo5/dynamics-forms/filled-questionnaire/show.blade.php` e `v6/resources/views/portal/layouts/modelo6/dynamics-forms/filled-questionnaire/show.blade.php`

O controller monta o nome dinamicamente (`v6/app/Http/Controllers/Portal/DynamicForms/Questionnaire/QuestionnaireController.php`):

```php
public function edit(string $slug)
{
    $title = 'Formulário';
    $model = $this->getTemplateActived();
    $modelNumber = str_replace('modelo', '', $model);
    $questionnaire = Questionnaire::query()->with('categories', 'asks')->where('status', true)->where('slug', $slug)->first();
    abort_unless($questionnaire, 404, 'Formulário não encontrado');
    return view("portal.layouts.$model.dynamics-forms.questionnaire.edit", compact('questionnaire', 'title', 'model', 'modelNumber'));
}
```

> Existe ainda a pasta `v6/resources/views/portal/layouts/dynamics-forms/questionnaire/` (sem modelo) com `render.blade.php` e `components/`. É o **partial compartilhado** por todos os modelos; a "view de modelo" apenas o inclui.

### 2.2 Componentes do formulário (motor visual)

Todos em `v6/resources/views/portal/layouts/dynamics-forms/questionnaire/components/`:

| Componente | Tipo | Observações |
|---|---|---|
| `categories.blade.php` | — | Filtra as perguntas por `ask_category_id` e monta `fieldset`/`legend`. |
| `asks.blade.php` | — | Dispatch por `ask_type_id` via `@includeWhen`, monta o array `$resource` e o `col-md-{size}`. |
| `text.blade.php` | TEXT (1) | Aplica `setQuestionnaireFieldStyle($styleId)` → classe de máscara. |
| `textarea.blade.php` | TEXTAREA (2) | — |
| `select.blade.php` | SELECT (3) / MULTI_SELECT (4) | Lê `config.options`; `multiple` → `name="x[]"` + `size="5"`. |
| `file.blade.php` | FILE (5) / MULTI_FILE (6) | `accept` muda conforme `config.isImg`; input hidden recebe o `ask_file.id`. |
| `radio.blade.php` | RADIO (7) | Lê `config.options`; o radio grava no input hidden `name="{ask}"`. |
| `range.blade.php` | RANGE (8) | Lê `config.min` (default 0) e `config.max` (default 100). |
| `checkbox.blade.php` | CHECKBOX (9) | Input hidden `value="false"` sincronizado pelo JS. |
| `satisfaction-level.blade.php` | SATISFACTION_LEVEL (10) | 5 botões com `data-value` 0..4 e imagens em `assets/images/formularios-dinâmicos/`. |
| `required-icon.blade.php` | — | Astérisco vermelho do campo obrigatório. |

### 2.3 O que o cidadão vê

Fluxo de `edit.blade.php` (modelo1 como referência):

1. Título do formulário (`{{ data_get($questionnaire, 'title', 'Formulário') }}`) e descrição em HTML.
2. Div `#handleMessages` — área de mensagens de sucesso/erro.
3. Form com `id="dynamicForm"` (**aberto com `route('contato.enviar')`**, mas o envio é interceptado por JS — ver `10-FLUXO-DE-PREENCHIMENTO-PORTAL.md`).
4. `@include('portal.layouts.dynamics-forms.questionnaire.render')` — as categorias e perguntas.
5. Bloco de reCAPTCHA (`{!! Recaptcha::render() !!}`).
6. `submit_info` (aviso sobre o envio).
7. Botão "Salvar" (`id="submitForm"`) e, se `has_result`, link "Resultado" para `portal.formularios.result.show`.

### 2.4 Tela de resultado

`filled-questionnaire/show.blade.php` (modelo1) traz o título, a descrição, um botão de compartilhamento (`addthis_inline_share_toolbox`), o input oculto `#idQuestionnaire` (id do questionário), o input oculto `#isAuth` e o container `#divResultado`, que é preenchido por `resultado.js` via `GET /formularios/resultado/{id}/list`.

Regras de visibilidade em `resultado.js`:

| Tipo | Visibilidade do resultado |
|---|---|
| TEXT (1), TEXTAREA (2) | apenas logado (`isAuth`) |
| SELECT (3), MULTI_SELECT (4), RADIO (7) | público (gráfico de pizza) |
| FILE (5), MULTI_FILE (6) | apenas logado |
| RANGE (8) | apenas logado |
| CHECKBOX (9) | apenas logado |
| SATISFACTION_LEVEL (10) | público (gráfico de pizza com 5 opções fixas) |

## 3. JavaScript

### 3.1 CMS — `/cms/formularios-dinamicos/questionarios`

| Arquivo | Linhas | Papel |
|---|---|---|
| `v6/public/assets/js/custom/contents/formularios-dinamicos/questionarios/script.js` | 10 | Ponto de entrada: instancia as entidades. |
| `v6/public/assets/js/custom/contents/formularios-dinamicos/questionarios/structure.js` | 1428 | Classes `ListController`, `QuestionnaireController`, `AskController`, `CategoryController`, `EditCategoryController`, `OptionController`, `EditCategoryTwoController`; estrutura de dados em memória, drag-and-drop (Sortable) e construção do `config`. |
| `v6/public/assets/js/custom/contents/formularios-dinamicos/questionarios/helpers.js` | 224 | Classes de abstração de DOM: `ElementHtml`, `Field`, `Input`, `Select`, `Textarea`, `Richtext`, `Checkbox`, `Button`. |
| `v6/public/assets/js/custom/contents/formularios-dinamicos/questionarios/listeners.js` | 546 | Eventos e chamadas XHR (`saveQuestionnaire`, `saveCategory`, `deleteCategory`). |
| `v6/public/assets/js/custom/contents/formularios-dinamicos/questionarios/edit.js` | 55 | Carrega o questionário via `GET /cms/formularios-dinamicos/questionarios/{id}` e hidrata o formulário. |
| `v6/public/assets/js/custom/contents/formularios-dinamicos/questionarios/datatable.js` | 49 | DataTable da listagem (consome `listagem_questionarios`). |

Endpoints chamados pelo JS do CMS (todos com `X-CSRF-TOKEN`):

```js
const saveQuestionnaire = (copy, edit = false) => {
    return xhrFunction({
        method: edit ? 'PUT' : 'POST',
        data: JSON.stringify(copy),
        url: "/cms/formularios-dinamicos/questionarios"
    })
}

const xhrCategory = ({ method, data = null }) => {
    return xhrFunction({ method, data, url: "/cms/formularios-dinamicos/questionarios/categoria" });
}
```

### 3.2 CMS — questionários preenchidos

| Arquivo | Linhas | Papel |
|---|---|---|
| `v6/public/assets/js/custom/contents/formularios-dinamicos/questionarios-preenchidos/script.js` | 91 | Bootstrap da tela. |
| `v6/public/assets/js/custom/contents/formularios-dinamicos/questionarios-preenchidos/utils.js` | 1210 | Utilidades de renderização dos painéis de resposta. |
| `v6/public/assets/js/custom/contents/formularios-dinamicos/questionarios-preenchidos/resumo-painel.js` | 178 | Painel "resumo" (agregado por pergunta). |
| `v6/public/assets/js/custom/contents/formularios-dinamicos/questionarios-preenchidos/individual-painel.js` | 196 | Painel de uma resposta individual. |
| `v6/public/assets/js/custom/contents/formularios-dinamicos/questionarios-preenchidos/pergunta-painel.js` | 106 | Painel por pergunta. |
| `v6/public/assets/js/custom/contents/formularios-dinamicos/questionarios-preenchidos/datatable.js` | 38 | DataTable da listagem de preenchidos. |

### 3.3 Portal

| Arquivo | Linhas | Papel |
|---|---|---|
| `v6/public/assets/js/custom/portal/dynamic-form/form-utils.js` | 563 | Máscaras, validação de CPF/CNPJ/data, upload de arquivo, `validate()`, `sendTrigger()`. |
| `v6/public/assets/js/custom/portal/dynamic-form/script.js` | 24 | Intercepta o clique em `#submitForm` e faz o XHR final. |
| `v6/public/assets/js/custom/portal/dynamic-form/resultado.js` | 184 | Carrega e renderiza os gráficos da tela de resultado. |

### 3.4 Other — módulo "revisões" (formulários de avaliação)

`v6/resources/views/prefecture/configurations/revisoes/formularios/{index,create,form}.blade.php` + `v6/resources/views/prefecture/configurations/revisoes/formularios/modal/modal.blade.php` e `v6/public/assets/js/custom/contents/revisoes/formulario/datatable.js` pertencem ao **módulo de revisões** (avaliação de conteúdo com nota), que reaproveita a mesma pasta de assets. Não faz parte do fluxo de `formularios-dinamicos`.

## 4. CSS e imagens

| Caminho | Uso |
|---|---|
| `v6/public/assets/css/custom/contents/formularios-dinamicos/style.css` | Estilos gerais do CMS do módulo. |
| `v6/public/assets/css/custom/contents/formularios-dinamicos/questionarios/style.css` | Estilos do construtor de questionários. |
| `v6/public/assets/css/custom/contents/formularios-dinamicos/questionarios-preenchidos/style.css` | Estilos do painel de respostas. |
| `v6/public/assets/css/portal/dynamic-form.css` | Estilos do formulário público. |
| `v6/public/assets/images/formularios-dinâmicos/muito_insatisfeito.png` (e `insatisfeito`, `neutro`, `satisfeito`, `muito_satisfeito`) | Ícones do nível de satisfação. |
| `v6/public/assets/plugins/jquery-mask/jquery.mask.js` | Máscaras de CPF/CNPJ/CEP/data/telefone. |
| `v6/public/assets/js/modulos/sweetalert/sweetalert2.min.js` | Alertas do upload de arquivo. |

## 5. Exportação

Gerada em `FilledQuestionnaireController@exportSpreadSheet`:

```php
$directoryPath = "content/formularios-dinamicos/exports/{$questionnaireId}";
$filePath = "{$directoryPath}/exported-data.xlsx";

if (!Storage::exists($directoryPath)) {
    mkdir(storage_path('app/public/' . $directoryPath), 0755);
}

Excel::store(new ResponsesExport($questionnaireId), $filePath);
```

Resposta JSON: `{"success":true,"message":"CSV exportado com sucesso!","file_path":"/storage/content/formularios-dinamicos/exports/{id}/exported-data.xlsx"}` — a mensagem diz "CSV", mas o arquivo é `.xlsx`. Detalhes em `11-RESPOSTAS-E-EXPORTACAO.md`.
