From 42d5fddf3f662a75647447d335294bbc55709370 Mon Sep 17 00:00:00 2001 From: Nam Nguyen Date: Thu, 7 Sep 2023 17:42:49 +0700 Subject: [PATCH] feat(guess): allow guess game to be played inside a thread or played outside in a channel (#1478) --- src/commands/guess/end/slash.ts | 8 +-- src/commands/guess/new/slash.ts | 121 ++++++++++++++++++-------------- 2 files changed, 73 insertions(+), 56 deletions(-) diff --git a/src/commands/guess/end/slash.ts b/src/commands/guess/end/slash.ts index fb63dc978..21c4fcfcd 100644 --- a/src/commands/guess/end/slash.ts +++ b/src/commands/guess/end/slash.ts @@ -1,6 +1,6 @@ import { SlashCommandSubcommandBuilder, userMention } from "@discordjs/builders" import mochiGuess from "adapters/mochi-guess" -import { ThreadChannel, MessageOptions } from "discord.js" +import { ThreadChannel, MessageOptions, Message } from "discord.js" import { now, truncate, groupBy } from "lodash" import { logger } from "logger" import moment from "moment-timezone" @@ -27,7 +27,7 @@ export async function cleanupAfterEndGame( } export async function announceResult( - thread: ThreadChannel, + messageContext: ThreadChannel | Message["channel"], gameCode: string, answer: string, gameResult: any, @@ -41,7 +41,7 @@ export async function announceResult( const embed = composeEmbedMessage(null, { color: "GREEN", }) - embed.setTitle(`:crossed_swords: Result ${gameCode}`) + embed.setTitle(`:crossed_swords: Result - ${gameCode}`) embed.setDescription( "The rewards you received include taxes and transaction fees. Please be aware when receiving rewards. Contact us if you have questions or concerns. Thank you! \n\nHere is the result:", ) @@ -86,7 +86,7 @@ export async function announceResult( embeds: [embed], } - await thread.send(msgOpt).catch(() => null) + await messageContext.send(msgOpt).catch(() => null) } const slashCmd: SlashCommand = { diff --git a/src/commands/guess/new/slash.ts b/src/commands/guess/new/slash.ts index be366a7be..24468e915 100644 --- a/src/commands/guess/new/slash.ts +++ b/src/commands/guess/new/slash.ts @@ -126,6 +126,12 @@ const slashCmd: SlashCommand = { .setDescription("the label for no option (optional)") .setRequired(false), ) + .addBooleanOption((opt) => + opt + .setName("thread") + .setDescription("game played in thread (default false)") + .setRequired(false), + ) }, run: async (i) => { if (i.channel?.type !== "GUILD_TEXT") { @@ -152,15 +158,22 @@ const slashCmd: SlashCommand = { } } + const threadMode = i.options.getBoolean("thread", false) + const reply = (await i.editReply({ - content: [`${i.user} asked:`, `> ${question}`].join("\n"), + content: [`Hey @here, ${i.user}'s popped new Quiz.`].join("\n"), })) as Message - const thread = await reply.startThread({ - name: truncate(question, { length: 100 }), - }) - - await thread.members.add(referee) + let messageContext: any = reply.channel + let flowID = reply.channel.id + if (threadMode) { + const thread = await reply.startThread({ + name: truncate(question, { length: 100 }), + }) + await thread.members.add(referee) + messageContext = thread + flowID = thread.id + } const game = { duration: durationMin, @@ -168,7 +181,7 @@ const slashCmd: SlashCommand = { options: [yesLabel, noLabel], question, referee_id: referee.id, - thread_id: thread.id, + thread_id: flowID, } const { ok, data, originalError, error } = await mochiGuess.createGame(game) if (!ok) { @@ -179,6 +192,33 @@ const slashCmd: SlashCommand = { } } + const yesCode = data.options.find((opt: any) => + equalIgnoreCase(opt.option, yesLabel), + ).code + const noCode = data.options.find((opt: any) => + equalIgnoreCase(opt.option, noLabel), + ).code + + const options: Record = { + [yesCode]: yesLabel, + [noCode]: noLabel, + } + + const choices = [ + new MessageActionRow().addComponents( + new MessageButton({ + label: yesLabel, + style: "SECONDARY", + customId: yesCode, + }), + new MessageButton({ + label: noLabel, + style: "SECONDARY", + customId: noCode, + }), + ), + ] + const start = Date.now(), end = start + durationMs const updatePlayers = async function () { @@ -207,34 +247,7 @@ const slashCmd: SlashCommand = { } } - const yesCode = data.options.find((opt: any) => - equalIgnoreCase(opt.option, yesLabel), - ).code - const noCode = data.options.find((opt: any) => - equalIgnoreCase(opt.option, noLabel), - ).code - - const options: Record = { - [yesCode]: yesLabel, - [noCode]: noLabel, - } - - const choices = [ - new MessageActionRow().addComponents( - new MessageButton({ - label: yesLabel, - style: "SECONDARY", - customId: yesCode, - }), - new MessageButton({ - label: noLabel, - style: "SECONDARY", - customId: noCode, - }), - ), - ] - - const msg = await thread.send({ + const msg = await messageContext.send({ content: renderProgress( referee, question, @@ -255,12 +268,12 @@ const slashCmd: SlashCommand = { const embed = composeEmbedMessage(null, { color: "RED", }) - embed.setTitle(":loudspeaker: Judgement") + embed.setTitle(`:loudspeaker: Judgement - ${data.code}`) embed.setDescription( `Hey ${referee}, time is up:hourglass:\nPlease submit the game result to decide the winners of the game.`, ) - const msg = await thread + const msg = await messageContext .send({ embeds: [embed], components: choices, @@ -273,7 +286,7 @@ const slashCmd: SlashCommand = { // 10 minutes to decide time: 10 * 60 * 1000, }) - .on("collect", async (i) => { + .on("collect", async (i: any) => { await i.deferReply({ ephemeral: true }).catch(() => null) if (i.user.id !== referee.id) { await i.editReply({ @@ -290,14 +303,16 @@ const slashCmd: SlashCommand = { await i.deleteReply().catch(() => null) if (gameResult?.data) { await announceResult( - thread, + messageContext, data.code, options[i.customId as keyof typeof options], gameResult.data, ) } - await cleanupAfterEndGame(thread, data.code) + if (threadMode) { + await cleanupAfterEndGame(messageContext, data.code) + } }) }, durationMs + 30 * 1000, @@ -306,19 +321,21 @@ const slashCmd: SlashCommand = { timers.set(data.code, setInterval(updatePlayers, 10 * 1000)) - const editedReply = await reply - .edit({ - content: [`${i.user} asked:`, `> ${question}`].join("\n"), - components: choices, - }) - .catch(() => null) + if (threadMode) { + const editedReply = await reply + .edit({ + content: [`${i.user} asked:`, `> ${question}`].join("\n"), + components: choices, + }) + .catch(() => null) - editedReply - ?.createMessageComponentCollector({ - componentType: "BUTTON", - time: durationMs, - }) - .on("collect", collectPlayerChoice(data, referee)) + editedReply + ?.createMessageComponentCollector({ + componentType: "BUTTON", + time: durationMs, + }) + .on("collect", collectPlayerChoice(data, referee)) + } msg .createMessageComponentCollector({