From 37c5ee0485a789253ec71793545b0c640e9976b8 Mon Sep 17 00:00:00 2001 From: jwford Date: Sun, 14 Apr 2024 19:23:45 -0400 Subject: [PATCH] feat(feedback): add feedback command --- prisma/schema.prisma | 9 +++ src/commands/System/feedback.ts | 77 ++++++++++++++++++++++ src/languages/en-US/commands/feedback.json | 11 ++++ src/lib/database/FeedbackSettings.ts | 24 +++++++ src/lib/database/SettingsProvider.ts | 3 + 5 files changed, 124 insertions(+) create mode 100644 src/commands/System/feedback.ts create mode 100644 src/languages/en-US/commands/feedback.json create mode 100644 src/lib/database/FeedbackSettings.ts diff --git a/prisma/schema.prisma b/prisma/schema.prisma index 3ab5140..98a9745 100644 --- a/prisma/schema.prisma +++ b/prisma/schema.prisma @@ -7,6 +7,15 @@ datasource db { url = env("DATABASE_URL") } +model Feedback { + id String @id @default(auto()) @map("_id") @db.ObjectId + content String + timestamp DateTime + user String + + @@map("feedback") +} + model Guild { id String @id @default(auto()) @map("_id") @db.ObjectId id_ String @unique @map("id") // snowflake diff --git a/src/commands/System/feedback.ts b/src/commands/System/feedback.ts new file mode 100644 index 0000000..c31e7fc --- /dev/null +++ b/src/commands/System/feedback.ts @@ -0,0 +1,77 @@ +import { SteveCommand } from "#lib/structures/commands/SteveCommand"; +import { registerBasicCommand } from "#utils/util"; +import { ApplyOptions } from "@sapphire/decorators"; +import { + ApplicationCommandRegistry, + CommandOptions, +} from "@sapphire/framework"; +import { TFunction, fetchT } from "@sapphire/plugin-i18next"; +import { Time } from "@sapphire/timestamp"; +import { + ActionRowBuilder, + ChatInputCommandInteraction, + ModalBuilder, + TextInputBuilder, + TextInputStyle, +} from "discord.js"; + +@ApplyOptions({ + description: "Send feedback to my developers.", +}) +export default class extends SteveCommand { + public override registerApplicationCommands( + registry: ApplicationCommandRegistry, + ) { + registerBasicCommand(registry, this.name, this.description); + } + + public override async chatInputRun(interaction: ChatInputCommandInteraction) { + const t = await fetchT(interaction); + + try { + await this.sendFeedbackModal(interaction, t); + + const submissionData = await interaction.awaitModalSubmit({ + time: Time.Minute * 5, + }); + + const feedback = + submissionData.fields.getTextInputValue("feedback_input"); + + await this.container.settings.feedback.addFeedback( + feedback, + submissionData.createdAt, + submissionData.user.id, + ); + + return submissionData.reply(t("commands/feedback:submissionSuccess")); + } catch (e) { + console.log(e); // TODO: set up logger plugin + return interaction.reply(t("commands/feedback:submissionFailure")); + } + } + + private sendFeedbackModal( + interaction: ChatInputCommandInteraction, + t: TFunction, + ) { + const input = new TextInputBuilder() + .setCustomId("feedback_input") + .setLabel(t("commands/feedback:modal.input.label")) + .setMaxLength(1900) + .setPlaceholder(t("commands/feedback:modal.input.placeholder")) + .setRequired(true) + .setStyle(TextInputStyle.Paragraph); + + const actionRow = new ActionRowBuilder().addComponents( + input, + ); + + const modal = new ModalBuilder() + .setCustomId("feedback_modal") + .setTitle(t("commands/feedback:modal.title")) + .addComponents(actionRow); + + return interaction.showModal(modal); + } +} diff --git a/src/languages/en-US/commands/feedback.json b/src/languages/en-US/commands/feedback.json new file mode 100644 index 0000000..75859ec --- /dev/null +++ b/src/languages/en-US/commands/feedback.json @@ -0,0 +1,11 @@ +{ + "modal": { + "input": { + "label": "What feedback do you have for us?", + "placeholder": "Help make Steve better!" + }, + "title": "Feedback" + }, + "submissionFailure": "There was a problem submitting your feedback, please try again later!", + "submissionSuccess": "Thanks for your feedback!" +} diff --git a/src/lib/database/FeedbackSettings.ts b/src/lib/database/FeedbackSettings.ts new file mode 100644 index 0000000..b626628 --- /dev/null +++ b/src/lib/database/FeedbackSettings.ts @@ -0,0 +1,24 @@ +import { PrismaClient } from "@prisma/client"; +import { Snowflake } from "discord.js"; + +export default class FeedbackSettings { + private prisma: PrismaClient; + + public constructor(prisma: PrismaClient) { + this.prisma = prisma; + } + + public addFeedback( + content: string, + timestamp: Date, + userSnowflake: Snowflake, + ) { + return this.prisma.feedback.create({ + data: { + content, + timestamp, + user: userSnowflake, + }, + }); + } +} diff --git a/src/lib/database/SettingsProvider.ts b/src/lib/database/SettingsProvider.ts index 712d427..97cfd03 100644 --- a/src/lib/database/SettingsProvider.ts +++ b/src/lib/database/SettingsProvider.ts @@ -1,13 +1,16 @@ import { PrismaClient } from "@prisma/client"; import GuildSettings from "./GuildSettings.js"; +import FeedbackSettings from "./FeedbackSettings.js"; export default class SettingsProvider { + public feedback: FeedbackSettings; public guilds: GuildSettings; private prisma: PrismaClient; public constructor() { this.prisma = new PrismaClient(); + this.feedback = new FeedbackSettings(this.prisma); this.guilds = new GuildSettings(this.prisma); } }