Ticket System
Sistema de tickets de suporte com workflow completo
Funcionalidades
- Criação de tickets via comando
- Modal para descrever o problema
- Criação automática de canal privado
- Transições de estado (aberto/resolvido/fechado)
Código
typescript
1import { 2 FlowRegistry, FlowEngine, MemoryStore, createServer,3 Container, Section, TextDisplay, Button, ActionRow,4 DiscordAPI, ChannelType5} from 'discord-flow';6 7const registry = new FlowRegistry();8const engine = new FlowEngine(registry, new MemoryStore());9const discord = new DiscordAPI({ token: process.env.DISCORD_TOKEN! });10 11registry.define('tickets', (flow) => {12 flow.start('idle');13 14 // Comando para abrir ticket15 flow.state('idle')16 .on.command({17 name: 'ticket',18 description: 'Abre um ticket de suporte'19 }, () => ({20 response: {21 flags: 64,22 content: 'Clique no botão para abrir um ticket:',23 components: [24 ActionRow({25 components: [26 Button({ 27 customId: 'open_ticket', 28 label: 'Abrir Ticket', 29 style: 1 30 })31 ]32 })33 ]34 }35 }));36 37 // Botão para abrir ticket38 flow.state('idle')39 .on.button('open_ticket', () => ({40 response: {41 type: 9, // Modal42 data: {43 custom_id: 'ticket_modal',44 title: 'Novo Ticket',45 components: [{46 type: 1,47 components: [{48 type: 4,49 custom_id: 'description',50 label: 'Descreva seu problema',51 style: 2,52 placeholder: 'Seja detalhado...',53 required: true54 }]55 }]56 }57 }58 }));59 60 // Submissão do modal61 flow.state('idle')62 .on.modal('ticket_modal', async (ctx) => {63 const description = ctx.interaction.data64 ?.components?.[0]?.components?.[0]?.value;65 66 // Criar canal privado67 const channel = await discord.createChannel(ctx.guild!.id, {68 name: `ticket-${ctx.user.id.slice(-4)}`,69 type: ChannelType.GuildText,70 permissionOverwrites: [71 {72 id: ctx.guild!.id,73 type: 0,74 deny: '1024' // VIEW_CHANNEL75 },76 {77 id: ctx.user.id,78 type: 1,79 allow: '1024'80 }81 ]82 });83 84 // Enviar mensagem no canal85 await discord.sendMessage(channel.id, {86 components: [87 Container({88 accentColor: 0xFFA500,89 components: [90 TextDisplay({ content: '# Ticket Aberto' }),91 TextDisplay({ content: `**Usuário:** <@${ctx.user.id}>` }),92 TextDisplay({ content: `**Problema:**\n${description}` }),93 ActionRow({94 components: [95 Button({ customId: 'resolve', label: 'Resolver', style: 3 }),96 Button({ customId: 'close', label: 'Fechar', style: 4 })97 ]98 })99 ]100 })101 ]102 });103 104 return {105 response: {106 flags: 64,107 content: `Ticket criado em <#${channel.id}>`108 },109 transition: 'open'110 };111 });112 113 // Estado: Ticket aberto114 flow.state('open')115 .on.button('resolve', (ctx) => ({116 response: {117 content: 'Ticket marcado como resolvido!',118 components: [119 Container({120 accentColor: 0x1EBE38,121 components: [122 TextDisplay({ content: '# Ticket Resolvido' }),123 ActionRow({124 components: [125 Button({ customId: 'close', label: 'Fechar', style: 2 })126 ]127 })128 ]129 })130 ]131 },132 transition: 'resolved'133 }));134 135 // Estado: Resolvido136 flow.state('resolved')137 .on.button('close', async (ctx) => {138 // Deletar canal após 5 segundos139 setTimeout(async () => {140 await discord.deleteChannel(ctx.channel.id);141 }, 5000);142 143 return {144 response: {145 content: 'Canal será fechado em 5 segundos...'146 },147 transition: 'idle'148 };149 });150});151 152createServer({153 publicKey: process.env.DISCORD_PUBLIC_KEY!,154 token: process.env.DISCORD_TOKEN!,155 engine156}).start();