# Interações
> Entenda respostas, modais, autocomplete e o contexto normalizado usado em todos os fluxos interativos.

- Área: Base do Core
- URL humana: https://ninenity.vercel.app/doc/interacoes
- URL Markdown: https://ninenity.vercel.app/doc/markdown/interacoes
- Pacotes e conceitos: Replies, Modal, Autocomplete

## O ciclo de uma resposta

Uma interação pode receber uma resposta inicial e depois ser editada ou acompanhada por mensagens adicionais.

| Método | Quando usar |
| --- | --- |
| `reply()` | Primeira resposta imediata |
| `deferReply()` | Reserva a resposta quando o trabalho demora |
| `editReply()` | Finaliza ou atualiza a resposta reservada |
| `followUp()` | Envia uma resposta adicional |
| `deleteReply()` | Remove a resposta original |

### resposta demorada

```text

Client.slash({
  data: new SlashCommandBuilder()
    .setName('relatorio')
    .setDescription('Gera um relatório detalhado.'),
  execute: async interaction => {
    await interaction.deferReply({ flags: 64 })

    const report = await generateReport(interaction.guildId)

    await interaction.editReply('Relatório pronto: ' + report.url)
    await interaction.followUp({
      content: 'A exportação expira em 24 horas.',
      flags: 64
    })
  }
})
```


## Contexto normalizado

O Core fornece uma superfície comum e mantém a interação original em `interaction.interaction` quando você precisa estreitar o tipo.

- **Identidade**: `user`, `member`, `guild`, `guildId`, `channel` e `channelId`.
- **Resposta**: `reply`, `deferReply`, `editReply`, `followUp` e estado da resposta.
- **Core**: `promptRequest`, `paginatorRequest`, configuração e contexto isolado.
- **Discord.js**: A propriedade `interaction` preserva a interação nativa completa.

### acesso à configuração da guild atual

```text

Client.slash({
  data: new SlashCommandBuilder()
    .setName('canal-suporte')
    .setDescription('Mostra o canal configurado.'),
  execute: async interaction => {
    const config = Client.appConfig()
    const supportChannel = Client.getAppChannels().support

    await interaction.reply({
      content: 'Canal: ' + (supportChannel?.toString() ?? 'não configurado'),
      flags: 64
    })
  }
})
```


## Abrindo um modal

O comando constrói o modal; um módulo separado registra o handler para o mesmo `customId`.

### Discord/Commands/Feedback.ts

```text

import {
  ActionRowBuilder,
  ModalBuilder,
  SlashCommandBuilder,
  TextInputBuilder,
  TextInputStyle
} from '@ninenity/core'
import Client from '../../Shared/Settings/Client'

Client.slash({
  data: new SlashCommandBuilder()
    .setName('feedback')
    .setDescription('Abre o formulário de feedback.'),
  execute: async interaction => {
    const input = new TextInputBuilder()
      .setCustomId('message')
      .setLabel('Como podemos melhorar?')
      .setStyle(TextInputStyle.Paragraph)
      .setMinLength(10)
      .setMaxLength(1000)
      .setRequired(true)

    const modal = new ModalBuilder()
      .setCustomId('feedback-modal')
      .setTitle('Enviar feedback')
      .addComponents(new ActionRowBuilder<TextInputBuilder>().addComponents(input))

    await interaction.interaction.showModal(modal)
  }
})
```


### Discord/Interactions/FeedbackModal.ts

```text

import Client from '../../Shared/Settings/Client'

Client.modal({
  customId: 'feedback-modal',
  execute: async interaction => {
    const text = interaction.fields.getTextInputValue('message')

    await saveFeedback({
      authorId: interaction.user.id,
      guildId: interaction.guildId,
      text
    })

    await interaction.reply({
      content: 'Obrigado pelo feedback!',
      flags: 64
    })
  }
})
```


## Autocomplete

Declare a opção com autocomplete no comando e responda com até 25 sugestões.

### Discord/Commands/Search.ts

```text

Client.slash({
  data: new SlashCommandBuilder()
    .setName('buscar')
    .setDescription('Busca um projeto.')
    .addStringOption(option => option
      .setName('projeto')
      .setDescription('Nome do projeto')
      .setAutocomplete(true)
      .setRequired(true)),
  autocomplete: async interaction => {
    const query = interaction.options.getFocused().toLowerCase()
    const choices = projects
      .filter(project => project.name.toLowerCase().includes(query))
      .slice(0, 25)
      .map(project => ({ name: project.name, value: project.id }))

    await interaction.respond(choices)
  },
  execute: async interaction => {
    const projectId = interaction.options.getString('projeto', true)
    await interaction.reply('Projeto escolhido: ' + projectId)
  }
})
```


> **Autocomplete precisa ser rápido:** Filtre dados em memória ou use consultas indexadas. O Discord espera a lista enquanto o usuário digita; uma busca lenta torna o comando frustrante.

## Prompts e paginações registrados

Depois de registrar uma definição uma vez, qualquer slash ou prefix pode iniciar uma instância isolada para o usuário.

### Discord/Commands/Flows.ts

```text

Client.slash({
  data: new SlashCommandBuilder()
    .setName('confirmar')
    .setDescription('Abre um prompt.'),
  execute: async interaction => {
    await interaction.promptRequest('delete-prompt', { ephemeral: true })
  }
})

Client.prefix({
  data: new PrefixCommandBuilder().setName('confirmar'),
  execute: async interaction => {
    await interaction.promptRequest('delete-prompt', { ephemeral: true })
  }
})

Client.slash({
  data: new SlashCommandBuilder()
    .setName('catalogo')
    .setDescription('Abre o catálogo paginado.'),
  execute: async interaction => {
    await interaction.paginatorRequest('catalog-pages', {
      ephemeral: true,
      pageIndex: 0
    })
  }
})
```


A criação das definições fica em `Discord/Interactions`. Consulte as páginas **Prompts** e **Paginação** para montar templates, callbacks e controles personalizados.
