refactor: initial moves

This commit is contained in:
syntaxbullet
2026-01-08 16:09:26 +01:00
parent 53a2f1ff0c
commit 88b266f81b
164 changed files with 529 additions and 280 deletions

View File

@@ -0,0 +1,79 @@
import type { Interaction } from "discord.js";
import { TextChannel, MessageFlags } from "discord.js";
import { config } from "@/lib/config";
import { AuroraClient } from "@/lib/BotClient";
import { buildFeedbackMessage, getFeedbackModal } from "./feedback.view";
import { FEEDBACK_CUSTOM_IDS, type FeedbackType, type FeedbackData } from "./feedback.types";
import { UserError } from "@/lib/errors";
export const handleFeedbackInteraction = async (interaction: Interaction) => {
// Handle select menu for choosing feedback type
if (interaction.isStringSelectMenu() && interaction.customId === "feedback_select_type") {
const feedbackType = interaction.values[0] as FeedbackType;
if (!feedbackType) {
throw new UserError("Invalid feedback type selected.");
}
const modal = getFeedbackModal(feedbackType);
await interaction.showModal(modal);
return;
}
// Handle modal submission
if (interaction.isModalSubmit() && interaction.customId.startsWith(FEEDBACK_CUSTOM_IDS.MODAL)) {
// Extract feedback type from customId (format: feedback_modal_FEATURE_REQUEST)
const parts = interaction.customId.split("_");
const feedbackType = parts.slice(2).join("_") as FeedbackType;
console.log(`Processing feedback modal. CustomId: ${interaction.customId}, Extracted type: ${feedbackType}`);
if (!feedbackType || !["FEATURE_REQUEST", "BUG_REPORT", "GENERAL"].includes(feedbackType)) {
console.error(`Invalid feedback type extracted: ${feedbackType} from customId: ${interaction.customId}`);
throw new UserError("An error occurred processing your feedback. Please try again.");
}
if (!config.feedbackChannelId) {
throw new UserError("Feedback channel is not configured. Please contact an administrator.");
}
// Parse modal inputs
const title = interaction.fields.getTextInputValue(FEEDBACK_CUSTOM_IDS.TITLE_FIELD);
const description = interaction.fields.getTextInputValue(FEEDBACK_CUSTOM_IDS.DESCRIPTION_FIELD);
// Build feedback data
const feedbackData: FeedbackData = {
type: feedbackType,
title,
description,
userId: interaction.user.id,
username: interaction.user.username,
timestamp: new Date()
};
// Get feedback channel
const channel = await AuroraClient.channels.fetch(config.feedbackChannelId).catch(() => null) as TextChannel | null;
if (!channel) {
throw new UserError("Feedback channel not found. Please contact an administrator.");
}
// Build and send beautiful message
const containers = buildFeedbackMessage(feedbackData);
const feedbackMessage = await channel.send({
components: containers as any,
flags: MessageFlags.IsComponentsV2
});
// Add reaction votes
await feedbackMessage.react("👍");
await feedbackMessage.react("👎");
// Confirm to user
await interaction.reply({
content: "✨ **Feedback Submitted**\nYour feedback has been submitted successfully! Thank you for helping improve Aurora.",
flags: MessageFlags.Ephemeral
});
}
};

View File

@@ -0,0 +1,23 @@
export type FeedbackType = "FEATURE_REQUEST" | "BUG_REPORT" | "GENERAL";
export interface FeedbackData {
type: FeedbackType;
title: string;
description: string;
userId: string;
username: string;
timestamp: Date;
}
export const FEEDBACK_TYPE_LABELS: Record<FeedbackType, string> = {
FEATURE_REQUEST: "💡 Feature Request",
BUG_REPORT: "🐛 Bug Report",
GENERAL: "💬 General Feedback"
};
export const FEEDBACK_CUSTOM_IDS = {
MODAL: "feedback_modal",
TYPE_FIELD: "feedback_type",
TITLE_FIELD: "feedback_title",
DESCRIPTION_FIELD: "feedback_description"
} as const;

View File

@@ -0,0 +1,123 @@
import {
ModalBuilder,
TextInputBuilder,
TextInputStyle,
ActionRowBuilder,
StringSelectMenuBuilder,
ActionRowBuilder as MessageActionRowBuilder,
ContainerBuilder,
TextDisplayBuilder,
ButtonBuilder,
ButtonStyle
} from "discord.js";
import { FEEDBACK_TYPE_LABELS, FEEDBACK_CUSTOM_IDS, type FeedbackData, type FeedbackType } from "./feedback.types";
export function getFeedbackTypeMenu() {
const select = new StringSelectMenuBuilder()
.setCustomId("feedback_select_type")
.setPlaceholder("Choose feedback type")
.addOptions([
{
label: "💡 Feature Request",
description: "Suggest a new feature or improvement",
value: "FEATURE_REQUEST"
},
{
label: "🐛 Bug Report",
description: "Report a bug or issue",
value: "BUG_REPORT"
},
{
label: "💬 General Feedback",
description: "Share your thoughts or suggestions",
value: "GENERAL"
}
]);
const row = new MessageActionRowBuilder<StringSelectMenuBuilder>().addComponents(select);
return { components: [row] };
}
export function getFeedbackModal(feedbackType: FeedbackType) {
const modal = new ModalBuilder()
.setCustomId(`${FEEDBACK_CUSTOM_IDS.MODAL}_${feedbackType}`)
.setTitle(FEEDBACK_TYPE_LABELS[feedbackType]);
// Title Input
const titleInput = new TextInputBuilder()
.setCustomId(FEEDBACK_CUSTOM_IDS.TITLE_FIELD)
.setLabel("Title")
.setStyle(TextInputStyle.Short)
.setPlaceholder("Brief summary of your feedback")
.setRequired(true)
.setMaxLength(100);
const titleRow = new ActionRowBuilder<TextInputBuilder>().addComponents(titleInput);
// Description Input
const descriptionInput = new TextInputBuilder()
.setCustomId(FEEDBACK_CUSTOM_IDS.DESCRIPTION_FIELD)
.setLabel("Description")
.setStyle(TextInputStyle.Paragraph)
.setPlaceholder("Provide detailed information about your feedback")
.setRequired(true)
.setMaxLength(1000);
const descriptionRow = new ActionRowBuilder<TextInputBuilder>().addComponents(descriptionInput);
modal.addComponents(titleRow, descriptionRow);
return modal;
}
export function buildFeedbackMessage(feedback: FeedbackData) {
// Define colors/themes for each feedback type
const themes = {
FEATURE_REQUEST: {
icon: "💡",
color: "Blue",
title: "FEATURE REQUEST",
description: "A new starlight suggestion has been received"
},
BUG_REPORT: {
icon: "🐛",
color: "Red",
title: "BUG REPORT",
description: "A cosmic anomaly has been detected"
},
GENERAL: {
icon: "💬",
color: "Gray",
title: "GENERAL FEEDBACK",
description: "A message from the cosmos"
}
};
const theme = themes[feedback.type];
if (!theme) {
console.error(`Unknown feedback type: ${feedback.type}`);
throw new Error(`Invalid feedback type: ${feedback.type}`);
}
const timestamp = Math.floor(feedback.timestamp.getTime() / 1000);
// Header Container
const headerContainer = new ContainerBuilder()
.addTextDisplayComponents(
new TextDisplayBuilder().setContent(`# ${theme.icon} ${theme.title}`),
new TextDisplayBuilder().setContent(`*${theme.description}*`)
);
// Content Container
const contentContainer = new ContainerBuilder()
.addTextDisplayComponents(
new TextDisplayBuilder().setContent(`## ${feedback.title}`),
new TextDisplayBuilder().setContent(`> ${feedback.description.split('\n').join('\n> ')}`),
new TextDisplayBuilder().setContent(
`**Submitted by:** <@${feedback.userId}>\n**Time:** <t:${timestamp}:F> (<t:${timestamp}:R>)`
)
);
return [headerContainer, contentContainer];
}