mirror of
https://github.com/SrIzan10/vinci.git
synced 2026-06-06 01:07:00 +00:00
feat: suggestions
This commit is contained in:
15
TODO.md
15
TODO.md
@@ -16,6 +16,7 @@
|
||||
- [ ] /infinitecraft - InfiniteCraft recipe solver
|
||||
- [ ] /letra - Song lyrics search via Genius API
|
||||
- [x] /google - Google search results
|
||||
- [x] /sugerencias - Suggestion system with upvote/downvote
|
||||
- [ ] /wikipedia - Wikipedia search (Spanish/English)
|
||||
- [ ] /faq - FAQ system with Minecraft questions
|
||||
- [ ] /afk - AFK status management
|
||||
@@ -27,10 +28,10 @@
|
||||
- [ ] /ip - Minecraft server IP information
|
||||
|
||||
# Button Handlers
|
||||
- [ ] suggestions-yes - Upvote button handler
|
||||
- [ ] suggestions-no - Downvote button handler
|
||||
- [ ] suggestions-yes-who - Show upvoters
|
||||
- [ ] suggestions-no-who - Show downvoters
|
||||
- [x] suggestions-yes - Upvote button handler
|
||||
- [x] suggestions-no - Downvote button handler
|
||||
- [x] suggestions-yes-who - Show upvoters
|
||||
- [x] suggestions-no-who - Show downvoters
|
||||
|
||||
# Context Menu Commands
|
||||
- [ ] bonzify - Text-to-speech with Bonzi Buddy voice
|
||||
@@ -55,10 +56,8 @@
|
||||
- [ ] Minecraft server status checker
|
||||
- [ ] Activity status rotation
|
||||
|
||||
# Database Schemas to Rewrite
|
||||
- [ ] Suggestions voting system
|
||||
- [ ] AFK status tracking
|
||||
- [ ] Question/answer system (askjavi)
|
||||
# Database
|
||||
- [x] Migration to sqlite
|
||||
|
||||
# Command Features to Preserve
|
||||
- [ ] Autocomplete functionality for various commands
|
||||
|
||||
85
src/commands/handlers/sugerencias.ts
Normal file
85
src/commands/handlers/sugerencias.ts
Normal file
@@ -0,0 +1,85 @@
|
||||
import { commandModule, CommandType } from '@sern/handler';
|
||||
import { ActionRowBuilder, ButtonBuilder, ButtonStyle, EmbedBuilder } from 'discord.js';
|
||||
import { ThreadAutoArchiveDuration } from 'discord.js';
|
||||
|
||||
export default commandModule({
|
||||
type: CommandType.Modal,
|
||||
async execute(modal) {
|
||||
const value = modal.fields.getTextInputValue('sugerenciasInput');
|
||||
|
||||
if (onlySpaces(value) === true) {
|
||||
return await modal.reply({
|
||||
content: 'Buen intento enviando un mensaje vacío >:D',
|
||||
ephemeral: true,
|
||||
});
|
||||
}
|
||||
|
||||
const embed = new EmbedBuilder()
|
||||
.setColor('Random')
|
||||
.setTitle('Sugerencia')
|
||||
.setAuthor({
|
||||
name: `${modal.user.username}`,
|
||||
iconURL: `${modal.user.displayAvatarURL()}`,
|
||||
})
|
||||
.setDescription(value);
|
||||
const row = new ActionRowBuilder<ButtonBuilder>().addComponents(
|
||||
new ButtonBuilder()
|
||||
.setCustomId('suggestions-yes')
|
||||
.setEmoji('✅')
|
||||
.setLabel('0')
|
||||
.setStyle(ButtonStyle.Success),
|
||||
new ButtonBuilder()
|
||||
.setCustomId('suggestions-no')
|
||||
.setEmoji('❎')
|
||||
.setLabel('0')
|
||||
.setStyle(ButtonStyle.Danger)
|
||||
);
|
||||
const row2 = new ActionRowBuilder<ButtonBuilder>().addComponents(
|
||||
new ButtonBuilder()
|
||||
.setCustomId('suggestions-yes-who')
|
||||
.setEmoji('✅')
|
||||
.setLabel('Quién')
|
||||
.setStyle(ButtonStyle.Secondary),
|
||||
new ButtonBuilder()
|
||||
.setCustomId('suggestions-no-who')
|
||||
.setEmoji('❎')
|
||||
.setLabel('Quién')
|
||||
.setStyle(ButtonStyle.Secondary)
|
||||
);
|
||||
|
||||
const guild = await modal.client.guilds.fetch(process.env.GUILDID!);
|
||||
const channel = await guild.channels.fetch(process.env.SUGGESTIONS_CHANNEL!);
|
||||
if (!channel || !channel.isTextBased()) {
|
||||
return await modal.reply({
|
||||
content: 'ERROR: Canal de sugerencias no encontrado.',
|
||||
ephemeral: true,
|
||||
});
|
||||
}
|
||||
|
||||
const msg = await channel.send({ embeds: [embed], components: [row, row2] });
|
||||
msg.startThread({
|
||||
name: `Sugerencia de ${modal.user.username}`,
|
||||
autoArchiveDuration: ThreadAutoArchiveDuration.ThreeDays,
|
||||
reason: 'AUTOMATIZADO: Hilo para discutir sobre la sugerencia.',
|
||||
});
|
||||
|
||||
const rowSuccess = new ActionRowBuilder<ButtonBuilder>().addComponents(
|
||||
new ButtonBuilder()
|
||||
.setURL(msg.url)
|
||||
.setLabel('Ver sugerencia')
|
||||
.setStyle(ButtonStyle.Link)
|
||||
);
|
||||
const modalReply = await modal.reply({
|
||||
content: '¡Enviado!',
|
||||
ephemeral: true,
|
||||
components: [rowSuccess],
|
||||
});
|
||||
setTimeout(() => {
|
||||
modalReply.delete().catch(() => {});
|
||||
}, 3000);
|
||||
},
|
||||
});
|
||||
|
||||
function onlySpaces(str: string) {
|
||||
return str.trim().length === 0;
|
||||
}
|
||||
23
src/commands/handlers/suggestions-no-who.ts
Normal file
23
src/commands/handlers/suggestions-no-who.ts
Normal file
@@ -0,0 +1,23 @@
|
||||
import { commandModule, CommandType } from '@sern/handler';
|
||||
import db from '../../utils/db';
|
||||
|
||||
export default commandModule({
|
||||
type: CommandType.Button,
|
||||
async execute(interaction) {
|
||||
await interaction.deferReply({ ephemeral: true });
|
||||
const votes = await db.suggestion.findMany({
|
||||
where: { msgId: interaction.message.id, upDown: -1 },
|
||||
});
|
||||
const fetchedIds = await Promise.all(
|
||||
votes.map(async (v) => {
|
||||
return interaction.client.users.fetch(v.userId);
|
||||
})
|
||||
);
|
||||
await interaction.editReply({
|
||||
content: `Gente que ha hecho downvote:\n${
|
||||
fetchedIds.length > 0 ? fetchedIds.join(', ') : 'Nadie, de momento'
|
||||
}`,
|
||||
allowedMentions: { repliedUser: false },
|
||||
});
|
||||
},
|
||||
});
|
||||
73
src/commands/handlers/suggestions-no.ts
Normal file
73
src/commands/handlers/suggestions-no.ts
Normal file
@@ -0,0 +1,73 @@
|
||||
import { commandModule, CommandType } from '@sern/handler';
|
||||
import {
|
||||
ActionRow,
|
||||
ActionRowBuilder,
|
||||
APIButtonComponentWithCustomId,
|
||||
ButtonBuilder,
|
||||
ButtonComponent,
|
||||
ButtonComponentData,
|
||||
ButtonStyle,
|
||||
MessageActionRowComponent,
|
||||
} from 'discord.js';
|
||||
import db from '../../utils/db';
|
||||
|
||||
export default commandModule({
|
||||
type: CommandType.Button,
|
||||
async execute(interaction) {
|
||||
const row1 = interaction.message!.components[0] as ActionRow<MessageActionRowComponent>;
|
||||
const row2 = interaction.message!.components[1] as ActionRow<MessageActionRowComponent>;
|
||||
const rows = {
|
||||
yes: row1.components[0],
|
||||
no: row1.components[1],
|
||||
yesWho: row2.components[0],
|
||||
noWho: row2.components[1],
|
||||
} as {
|
||||
yes: ButtonComponent;
|
||||
no: ButtonComponent;
|
||||
yesWho: ButtonComponent;
|
||||
noWho: ButtonComponent;
|
||||
};
|
||||
const upvoteData = rows.yes.data as APIButtonComponentWithCustomId;
|
||||
const downvoteData = rows.no.data as APIButtonComponentWithCustomId;
|
||||
const userSuggestion = await db.suggestion.findFirst({
|
||||
where: { msgId: interaction.message.id, userId: interaction.user.id },
|
||||
});
|
||||
|
||||
if (!userSuggestion) {
|
||||
const row1 = new ActionRowBuilder<ButtonBuilder>().setComponents(
|
||||
new ButtonBuilder(rows.yes.data),
|
||||
new ButtonBuilder(rows.no.data).setLabel((parseInt(downvoteData.label!) + 1).toString())
|
||||
);
|
||||
|
||||
await db.suggestion.create({
|
||||
data: {
|
||||
msgId: interaction.message.id,
|
||||
userId: interaction.user.id,
|
||||
upDown: -1,
|
||||
},
|
||||
});
|
||||
await interaction.message.edit({ components: [row1, row2] });
|
||||
await interaction.deferUpdate();
|
||||
return;
|
||||
}
|
||||
|
||||
const userSuggestionUpDown = userSuggestion.upDown === 1;
|
||||
if (userSuggestionUpDown) {
|
||||
await db.suggestion.updateMany({
|
||||
where: { msgId: interaction.message.id, userId: interaction.user.id, upDown: 1 },
|
||||
data: { upDown: -1 },
|
||||
});
|
||||
|
||||
const row1 = new ActionRowBuilder<ButtonBuilder>().setComponents(
|
||||
new ButtonBuilder(rows.yes.data).setLabel((parseInt(upvoteData.label!) - 1).toString()),
|
||||
new ButtonBuilder(rows.no.data).setLabel((parseInt(downvoteData.label!) + 1).toString())
|
||||
);
|
||||
await interaction.message.edit({ components: [row1, row2] });
|
||||
await interaction.deferUpdate();
|
||||
return;
|
||||
} else {
|
||||
await interaction.deferUpdate()
|
||||
return;
|
||||
}
|
||||
},
|
||||
});
|
||||
23
src/commands/handlers/suggestions-yes-who.ts
Normal file
23
src/commands/handlers/suggestions-yes-who.ts
Normal file
@@ -0,0 +1,23 @@
|
||||
import { commandModule, CommandType } from '@sern/handler';
|
||||
import db from '../../utils/db';
|
||||
|
||||
export default commandModule({
|
||||
type: CommandType.Button,
|
||||
async execute(interaction) {
|
||||
await interaction.deferReply({ ephemeral: true });
|
||||
const votes = await db.suggestion.findMany({
|
||||
where: { msgId: interaction.message.id, upDown: 1 },
|
||||
});
|
||||
const fetchedIds = await Promise.all(
|
||||
votes.map(async (v) => {
|
||||
return interaction.client.users.fetch(v.userId);
|
||||
})
|
||||
);
|
||||
await interaction.editReply({
|
||||
content: `Gente que ha hecho upvote:\n${
|
||||
fetchedIds.length > 0 ? fetchedIds.join(', ') : 'Nadie, de momento'
|
||||
}`,
|
||||
allowedMentions: { repliedUser: false },
|
||||
});
|
||||
},
|
||||
});
|
||||
74
src/commands/handlers/suggestions-yes.ts
Normal file
74
src/commands/handlers/suggestions-yes.ts
Normal file
@@ -0,0 +1,74 @@
|
||||
import { commandModule, CommandType } from '@sern/handler';
|
||||
import {
|
||||
ActionRow,
|
||||
ActionRowBuilder,
|
||||
APIButtonComponentWithCustomId,
|
||||
ButtonBuilder,
|
||||
ButtonComponent,
|
||||
ButtonComponentData,
|
||||
ButtonStyle,
|
||||
MessageActionRowComponent,
|
||||
} from 'discord.js';
|
||||
import db from '../../utils/db';
|
||||
|
||||
export default commandModule({
|
||||
type: CommandType.Button,
|
||||
async execute(interaction) {
|
||||
const convertToNumber = parseInt((interaction.component as ButtonComponent).label!);
|
||||
const row1 = interaction.message!.components[0] as ActionRow<MessageActionRowComponent>;
|
||||
const row2 = interaction.message!.components[1] as ActionRow<MessageActionRowComponent>;
|
||||
const rows = {
|
||||
yes: row1.components[0],
|
||||
no: row1.components[1],
|
||||
yesWho: row2.components[0],
|
||||
noWho: row2.components[1],
|
||||
} as {
|
||||
yes: ButtonComponent;
|
||||
no: ButtonComponent;
|
||||
yesWho: ButtonComponent;
|
||||
noWho: ButtonComponent;
|
||||
};
|
||||
const upvoteData = rows.yes.data as APIButtonComponentWithCustomId;
|
||||
const downvoteData = rows.no.data as APIButtonComponentWithCustomId;
|
||||
const userSuggestion = await db.suggestion.findFirst({
|
||||
where: { msgId: interaction.message.id, userId: interaction.user.id },
|
||||
});
|
||||
|
||||
if (!userSuggestion) {
|
||||
const row1 = new ActionRowBuilder<ButtonBuilder>().setComponents(
|
||||
new ButtonBuilder(rows.yes.data).setLabel((parseInt(upvoteData.label!) + 1).toString()),
|
||||
new ButtonBuilder(rows.no.data)
|
||||
);
|
||||
|
||||
await db.suggestion.create({
|
||||
data: {
|
||||
msgId: interaction.message.id,
|
||||
userId: interaction.user.id,
|
||||
upDown: 1,
|
||||
},
|
||||
});
|
||||
await interaction.message.edit({ components: [row1, row2] });
|
||||
await interaction.deferUpdate();
|
||||
return;
|
||||
}
|
||||
|
||||
const userSuggestionUpDown = userSuggestion.upDown === 1;
|
||||
if (userSuggestionUpDown) {
|
||||
await interaction.deferUpdate()
|
||||
return;
|
||||
} else {
|
||||
await db.suggestion.updateMany({
|
||||
where: { msgId: interaction.message.id, userId: interaction.user.id, upDown: -1 },
|
||||
data: { upDown: 1 },
|
||||
});
|
||||
|
||||
const row1 = new ActionRowBuilder<ButtonBuilder>().setComponents(
|
||||
new ButtonBuilder(rows.yes.data).setLabel((parseInt(upvoteData.label!) + 1).toString()),
|
||||
new ButtonBuilder(rows.no.data).setLabel((parseInt(downvoteData.label!) - 1).toString())
|
||||
);
|
||||
await interaction.message.edit({ components: [row1, row2] });
|
||||
await interaction.deferUpdate();
|
||||
return;
|
||||
}
|
||||
},
|
||||
});
|
||||
27
src/commands/misc/sugerencias.ts
Normal file
27
src/commands/misc/sugerencias.ts
Normal file
@@ -0,0 +1,27 @@
|
||||
import { commandModule, CommandType } from '@sern/handler';
|
||||
import {
|
||||
ActionRowBuilder,
|
||||
ModalBuilder,
|
||||
TextInputBuilder,
|
||||
TextInputStyle,
|
||||
ModalActionRowComponentBuilder,
|
||||
} from 'discord.js';
|
||||
|
||||
export default commandModule({
|
||||
name: 'sugerencias',
|
||||
type: CommandType.Slash,
|
||||
plugins: [],
|
||||
description: 'Envia una sugerencia.',
|
||||
execute: async (ctx) => {
|
||||
const modal = new ModalBuilder().setCustomId('sugerencias').setTitle('Sugerencias');
|
||||
|
||||
const input = new TextInputBuilder()
|
||||
.setCustomId('sugerenciasInput')
|
||||
.setLabel('Tienes sugerencias?')
|
||||
.setStyle(TextInputStyle.Paragraph);
|
||||
const suggestionsActionRow =
|
||||
new ActionRowBuilder<ModalActionRowComponentBuilder>().addComponents(input);
|
||||
modal.addComponents(suggestionsActionRow);
|
||||
await ctx.interaction.showModal(modal);
|
||||
},
|
||||
});
|
||||
Reference in New Issue
Block a user