Elimino los embedBuilder y los cambio por Components Message V2, algo tardado.
This commit is contained in:
BIN
prisma/dev.db
BIN
prisma/dev.db
Binary file not shown.
@@ -1,62 +0,0 @@
|
|||||||
-- CreateTable
|
|
||||||
CREATE TABLE "Guild" (
|
|
||||||
"id" TEXT NOT NULL PRIMARY KEY,
|
|
||||||
"name" TEXT NOT NULL
|
|
||||||
);
|
|
||||||
|
|
||||||
-- CreateTable
|
|
||||||
CREATE TABLE "User" (
|
|
||||||
"id" TEXT NOT NULL PRIMARY KEY
|
|
||||||
);
|
|
||||||
|
|
||||||
-- CreateTable
|
|
||||||
CREATE TABLE "PartnershipStats" (
|
|
||||||
"totalPoints" INTEGER NOT NULL DEFAULT 0,
|
|
||||||
"weeklyPoints" INTEGER NOT NULL DEFAULT 0,
|
|
||||||
"monthlyPoints" INTEGER NOT NULL DEFAULT 0,
|
|
||||||
"lastWeeklyReset" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
||||||
"lastMonthlyReset" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
||||||
"userId" TEXT NOT NULL,
|
|
||||||
"guildId" TEXT NOT NULL,
|
|
||||||
|
|
||||||
PRIMARY KEY ("userId", "guildId"),
|
|
||||||
CONSTRAINT "PartnershipStats_userId_fkey" FOREIGN KEY ("userId") REFERENCES "User" ("id") ON DELETE RESTRICT ON UPDATE CASCADE,
|
|
||||||
CONSTRAINT "PartnershipStats_guildId_fkey" FOREIGN KEY ("guildId") REFERENCES "Guild" ("id") ON DELETE RESTRICT ON UPDATE CASCADE
|
|
||||||
);
|
|
||||||
|
|
||||||
-- CreateTable
|
|
||||||
CREATE TABLE "Alliance" (
|
|
||||||
"id" TEXT NOT NULL PRIMARY KEY,
|
|
||||||
"channelId" TEXT NOT NULL,
|
|
||||||
"messageId" TEXT NOT NULL,
|
|
||||||
"createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
||||||
"guildId" TEXT NOT NULL,
|
|
||||||
"creatorId" TEXT NOT NULL,
|
|
||||||
CONSTRAINT "Alliance_guildId_fkey" FOREIGN KEY ("guildId") REFERENCES "Guild" ("id") ON DELETE RESTRICT ON UPDATE CASCADE,
|
|
||||||
CONSTRAINT "Alliance_creatorId_fkey" FOREIGN KEY ("creatorId") REFERENCES "User" ("id") ON DELETE RESTRICT ON UPDATE CASCADE
|
|
||||||
);
|
|
||||||
|
|
||||||
-- CreateTable
|
|
||||||
CREATE TABLE "EmbedConfig" (
|
|
||||||
"id" TEXT NOT NULL PRIMARY KEY,
|
|
||||||
"color" TEXT,
|
|
||||||
"title" TEXT,
|
|
||||||
"url" TEXT,
|
|
||||||
"authorName" TEXT,
|
|
||||||
"authorIconURL" TEXT,
|
|
||||||
"authorURL" TEXT,
|
|
||||||
"description" TEXT,
|
|
||||||
"thumbnailURL" TEXT,
|
|
||||||
"imageURL" TEXT,
|
|
||||||
"footerText" TEXT,
|
|
||||||
"footerIconURL" TEXT,
|
|
||||||
"fields" TEXT DEFAULT '[]',
|
|
||||||
"guildId" TEXT NOT NULL,
|
|
||||||
CONSTRAINT "EmbedConfig_guildId_fkey" FOREIGN KEY ("guildId") REFERENCES "Guild" ("id") ON DELETE RESTRICT ON UPDATE CASCADE
|
|
||||||
);
|
|
||||||
|
|
||||||
-- CreateIndex
|
|
||||||
CREATE UNIQUE INDEX "Alliance_messageId_key" ON "Alliance"("messageId");
|
|
||||||
|
|
||||||
-- CreateIndex
|
|
||||||
CREATE UNIQUE INDEX "EmbedConfig_guildId_key" ON "EmbedConfig"("guildId");
|
|
||||||
@@ -1,33 +0,0 @@
|
|||||||
/*
|
|
||||||
Warnings:
|
|
||||||
|
|
||||||
- Added the required column `name` to the `EmbedConfig` table without a default value. This is not possible if the table is not empty.
|
|
||||||
|
|
||||||
*/
|
|
||||||
-- RedefineTables
|
|
||||||
PRAGMA defer_foreign_keys=ON;
|
|
||||||
PRAGMA foreign_keys=OFF;
|
|
||||||
CREATE TABLE "new_EmbedConfig" (
|
|
||||||
"id" TEXT NOT NULL PRIMARY KEY,
|
|
||||||
"name" TEXT NOT NULL,
|
|
||||||
"color" TEXT,
|
|
||||||
"title" TEXT,
|
|
||||||
"url" TEXT,
|
|
||||||
"authorName" TEXT,
|
|
||||||
"authorIconURL" TEXT,
|
|
||||||
"authorURL" TEXT,
|
|
||||||
"description" TEXT,
|
|
||||||
"thumbnailURL" TEXT,
|
|
||||||
"imageURL" TEXT,
|
|
||||||
"footerText" TEXT,
|
|
||||||
"footerIconURL" TEXT,
|
|
||||||
"fields" TEXT DEFAULT '[]',
|
|
||||||
"guildId" TEXT NOT NULL,
|
|
||||||
CONSTRAINT "EmbedConfig_guildId_fkey" FOREIGN KEY ("guildId") REFERENCES "Guild" ("id") ON DELETE RESTRICT ON UPDATE CASCADE
|
|
||||||
);
|
|
||||||
INSERT INTO "new_EmbedConfig" ("authorIconURL", "authorName", "authorURL", "color", "description", "fields", "footerIconURL", "footerText", "guildId", "id", "imageURL", "thumbnailURL", "title", "url") SELECT "authorIconURL", "authorName", "authorURL", "color", "description", "fields", "footerIconURL", "footerText", "guildId", "id", "imageURL", "thumbnailURL", "title", "url" FROM "EmbedConfig";
|
|
||||||
DROP TABLE "EmbedConfig";
|
|
||||||
ALTER TABLE "new_EmbedConfig" RENAME TO "EmbedConfig";
|
|
||||||
CREATE UNIQUE INDEX "EmbedConfig_guildId_name_key" ON "EmbedConfig"("guildId", "name");
|
|
||||||
PRAGMA foreign_keys=ON;
|
|
||||||
PRAGMA defer_foreign_keys=OFF;
|
|
||||||
@@ -1,13 +0,0 @@
|
|||||||
-- RedefineTables
|
|
||||||
PRAGMA defer_foreign_keys=ON;
|
|
||||||
PRAGMA foreign_keys=OFF;
|
|
||||||
CREATE TABLE "new_Guild" (
|
|
||||||
"id" TEXT NOT NULL PRIMARY KEY,
|
|
||||||
"name" TEXT NOT NULL,
|
|
||||||
"prefix" TEXT NOT NULL DEFAULT '!'
|
|
||||||
);
|
|
||||||
INSERT INTO "new_Guild" ("id", "name") SELECT "id", "name" FROM "Guild";
|
|
||||||
DROP TABLE "Guild";
|
|
||||||
ALTER TABLE "new_Guild" RENAME TO "Guild";
|
|
||||||
PRAGMA foreign_keys=ON;
|
|
||||||
PRAGMA defer_foreign_keys=OFF;
|
|
||||||
@@ -1,3 +0,0 @@
|
|||||||
# Please do not edit this file manually
|
|
||||||
# It should be added in your version-control system (e.g., Git)
|
|
||||||
provider = "sqlite"
|
|
||||||
@@ -29,6 +29,7 @@ model Guild {
|
|||||||
|
|
||||||
// ✅ CAMBIO: Ahora un Guild puede tener MÚLTIPLES configuraciones de embed.
|
// ✅ CAMBIO: Ahora un Guild puede tener MÚLTIPLES configuraciones de embed.
|
||||||
embedConfigs EmbedConfig[]
|
embedConfigs EmbedConfig[]
|
||||||
|
BlockV2Config BlockV2Config[]
|
||||||
}
|
}
|
||||||
/*
|
/*
|
||||||
* -----------------------------------------------------------------------------
|
* -----------------------------------------------------------------------------
|
||||||
@@ -131,3 +132,26 @@ model EmbedConfig {
|
|||||||
// No puedes tener dos embeds llamados "alianza" en el mismo servidor.
|
// No puedes tener dos embeds llamados "alianza" en el mismo servidor.
|
||||||
@@unique([guildId, name])
|
@@unique([guildId, name])
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* -----------------------------------------------------------------------------
|
||||||
|
* Modelo para la Configuración de Bloques V2
|
||||||
|
* -----------------------------------------------------------------------------
|
||||||
|
*/
|
||||||
|
model BlockV2Config {
|
||||||
|
id String @id @default(cuid())
|
||||||
|
|
||||||
|
// ✅ Nombre único dentro de cada servidor
|
||||||
|
name String
|
||||||
|
|
||||||
|
// Configuración en JSON (embed + componentes, botones, etc.)
|
||||||
|
config Json
|
||||||
|
|
||||||
|
|
||||||
|
// Relación con el servidor
|
||||||
|
guild Guild @relation(fields: [guildId], references: [id])
|
||||||
|
guildId String
|
||||||
|
|
||||||
|
// 🔒 Asegura que un nombre no se repita dentro del mismo servidor
|
||||||
|
@@unique([guildId, name])
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,9 +1,66 @@
|
|||||||
import { CommandMessage } from "../../../core/types/commands";
|
import {CommandMessage} from "../core/types/commands";
|
||||||
// @ts-ignore
|
|
||||||
import { EmbedBuilder, ActionRowBuilder, ButtonBuilder, TextChannel, ChannelType } from "discord.js";
|
import {
|
||||||
//@ts-ignore
|
ActionRowBuilder,
|
||||||
import { ButtonStyle, ComponentType } from "discord.js";
|
ButtonBuilder,
|
||||||
import { replaceVars } from "../../../core/lib/vars";
|
//@ts-ignore
|
||||||
|
ButtonStyle,
|
||||||
|
//@ts-ignore
|
||||||
|
ChannelType,
|
||||||
|
//@ts-ignore
|
||||||
|
ComponentType,
|
||||||
|
EmbedBuilder,
|
||||||
|
TextChannel
|
||||||
|
} from "discord.js";
|
||||||
|
import {replaceVars} from "../core/lib/vars";
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* VARIABLES COMPONENTS V2
|
||||||
|
*/
|
||||||
|
|
||||||
|
const variables_text = {
|
||||||
|
"flags": 32768,
|
||||||
|
"components": [
|
||||||
|
{
|
||||||
|
"type": 17,
|
||||||
|
"components": [
|
||||||
|
{
|
||||||
|
"type": 10,
|
||||||
|
"content": "﹒⌒ Variables Text ╰୧﹒"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": 14,
|
||||||
|
"spacing": 1,
|
||||||
|
"divider": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": 10,
|
||||||
|
"content": "**✿ ૮ ․ ․ ྀིა User Var**"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": 10,
|
||||||
|
"content": "\n(user.id) **-** 𝑀𝑢𝑒𝑠𝑡𝑟𝑎 𝑒𝑙 𝑖𝑑𝑒𝑛𝑡𝑖𝑓𝑖𝑐𝑎𝑑𝑜𝑟 𝑑𝑒 𝑢𝑛 𝑢𝑠𝑢𝑎𝑟𝑖𝑜.\n(user.name) **-** 𝑀𝑢𝑒𝑠𝑡𝑟𝑎 𝑒𝑙 𝑛𝑜𝑚𝑏𝑟𝑒 𝑑𝑒 𝑢𝑛 𝑢𝑠𝑢𝑎𝑟𝑖𝑜\n(user.avatar) **-** 𝑀𝑢𝑒𝑠𝑡𝑟𝑎 𝑙𝑎 𝑢𝑟𝑙 𝑑𝑒𝑙 𝑎𝑣𝑎𝑡𝑎𝑟 𝑑𝑒𝑙 𝑢𝑠𝑢𝑎𝑟𝑖𝑜.\n(user.mention) **-** 𝑀𝑒𝑛𝑐𝑖𝑜𝑛𝑎 𝑎 𝑢𝑛 𝑢𝑠𝑢𝑎𝑟𝑖𝑜 𝑐𝑜𝑛 𝑠𝑢 @"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": 10,
|
||||||
|
"content": "**✿ ૮ ․ ․ ྀིა Guild Var**"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": 10,
|
||||||
|
"content": "(guild.icon) **-** 𝑀𝑢𝑒𝑠𝑡𝑟𝑎 𝑒𝑙 𝑖𝑐𝑜𝑛𝑜 𝑑𝑒𝑙 𝑠𝑒𝑟𝑣𝑖𝑑𝑜𝑟.\n(guild.name) **-** 𝑀𝑢𝑒𝑠𝑡𝑟𝑎 𝑒𝑙 𝑛𝑜𝑚𝑏𝑟𝑒 𝑑𝑒𝑙 𝑠𝑒𝑟𝑣𝑖𝑑𝑜𝑟.\n"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"accent_color": null,
|
||||||
|
"spoiler": true
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* COMMAND EXECUTE
|
||||||
|
*/
|
||||||
|
|
||||||
export const command: CommandMessage = {
|
export const command: CommandMessage = {
|
||||||
name: "embedcreate",
|
name: "embedcreate",
|
||||||
@@ -35,6 +92,8 @@ export const command: CommandMessage = {
|
|||||||
title?: string;
|
title?: string;
|
||||||
description?: string;
|
description?: string;
|
||||||
color?: number;
|
color?: number;
|
||||||
|
imageUrl?: string;
|
||||||
|
thumbnail?: string;
|
||||||
footer?: string;
|
footer?: string;
|
||||||
} = {
|
} = {
|
||||||
title: `Editor de Embed: ${embedName}`,
|
title: `Editor de Embed: ${embedName}`,
|
||||||
@@ -42,6 +101,8 @@ export const command: CommandMessage = {
|
|||||||
"Usa los botones de abajo para configurar este embed.\n\n_Ejemplo de variable: `{user.name}`_",
|
"Usa los botones de abajo para configurar este embed.\n\n_Ejemplo de variable: `{user.name}`_",
|
||||||
color: 0x5865f2,
|
color: 0x5865f2,
|
||||||
footer: "Haz clic en Guardar cuando termines.",
|
footer: "Haz clic en Guardar cuando termines.",
|
||||||
|
thumbnail: `${message.guild!.iconURL()}`,
|
||||||
|
imageUrl: `https://i.pinimg.com/originals/d2/c3/79/d2c3798684709cef3ed532b59c59bad4.gif`
|
||||||
};
|
};
|
||||||
|
|
||||||
// 📌 Función para construir un embed a partir del estado
|
// 📌 Función para construir un embed a partir del estado
|
||||||
@@ -52,18 +113,28 @@ export const command: CommandMessage = {
|
|||||||
if (embedState.title)
|
if (embedState.title)
|
||||||
preview.setTitle(
|
preview.setTitle(
|
||||||
//@ts-ignore
|
//@ts-ignore
|
||||||
await replaceVars(embedState.title, message.member)
|
await replaceVars(embedState.title, message.member, message.guild)
|
||||||
);
|
);
|
||||||
if (embedState.description)
|
if (embedState.description)
|
||||||
preview.setDescription(
|
preview.setDescription(
|
||||||
//@ts-ignore
|
//@ts-ignore
|
||||||
await replaceVars(embedState.description, message.member)
|
await replaceVars(embedState.description, message.member, message.guild)
|
||||||
);
|
);
|
||||||
if (embedState.footer)
|
if (embedState.footer)
|
||||||
preview.setFooter({
|
preview.setFooter({
|
||||||
//@ts-ignore
|
//@ts-ignore
|
||||||
text: await replaceVars(embedState.footer, message.member),
|
text: await replaceVars(embedState.footer, message.member, message.guild),
|
||||||
});
|
});
|
||||||
|
if (embedState.imageUrl)
|
||||||
|
preview.setImage(
|
||||||
|
//@ts-ignore
|
||||||
|
await replaceVars(embedState.imageUrl, message.member, message.guild)
|
||||||
|
);
|
||||||
|
if (embedState.thumbnail)
|
||||||
|
preview.setThumbnail(
|
||||||
|
//@ts-ignore
|
||||||
|
await replaceVars(embedState.thumbnail, message.member, message.guild)
|
||||||
|
)
|
||||||
|
|
||||||
return preview;
|
return preview;
|
||||||
};
|
};
|
||||||
@@ -85,6 +156,16 @@ export const command: CommandMessage = {
|
|||||||
.setCustomId("edit_color")
|
.setCustomId("edit_color")
|
||||||
.setLabel("Color")
|
.setLabel("Color")
|
||||||
.setStyle(ButtonStyle.Primary)
|
.setStyle(ButtonStyle.Primary)
|
||||||
|
.setDisabled(disabled),
|
||||||
|
new ButtonBuilder()
|
||||||
|
.setCustomId('edit_imageurl')
|
||||||
|
.setLabel('Image')
|
||||||
|
.setStyle(ButtonStyle.Secondary)
|
||||||
|
.setDisabled(disabled),
|
||||||
|
new ButtonBuilder()
|
||||||
|
.setCustomId('edit_thumbnail')
|
||||||
|
.setLabel('Thumbnail')
|
||||||
|
.setStyle(ButtonStyle.Secondary)
|
||||||
.setDisabled(disabled)
|
.setDisabled(disabled)
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -112,12 +193,109 @@ export const command: CommandMessage = {
|
|||||||
return [primaryRow, secondaryRow, controlRow];
|
return [primaryRow, secondaryRow, controlRow];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Botones Custom
|
||||||
|
*/
|
||||||
|
|
||||||
|
const btns = (disabled = false) => ({
|
||||||
|
flags: 32768,
|
||||||
|
components: [
|
||||||
|
{
|
||||||
|
type: 17,
|
||||||
|
components: [
|
||||||
|
{
|
||||||
|
type: 10,
|
||||||
|
content: "﹒⌒ Options ╰୧﹒"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 14,
|
||||||
|
divider: true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 1,
|
||||||
|
components: [
|
||||||
|
{
|
||||||
|
style: 2,
|
||||||
|
type: 2,
|
||||||
|
label: "Titulo",
|
||||||
|
disabled: disabled, // 👈 aquí ya funciona
|
||||||
|
custom_id: "edit_title"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
style: 2,
|
||||||
|
type: 2,
|
||||||
|
label: "Descripción",
|
||||||
|
disabled: disabled,
|
||||||
|
custom_id: "edit_description"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
style: 2,
|
||||||
|
type: 2,
|
||||||
|
label: "Color",
|
||||||
|
disabled: disabled,
|
||||||
|
custom_id: "edit_color"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
style: 2,
|
||||||
|
type: 2,
|
||||||
|
label: "Imagen",
|
||||||
|
disabled: disabled,
|
||||||
|
custom_id: 'edit_imageurl'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
style: 2,
|
||||||
|
type: 2,
|
||||||
|
label: "Thumbnail",
|
||||||
|
disabled: disabled,
|
||||||
|
custom_id: 'edit_thumbnail'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 1,
|
||||||
|
components: [
|
||||||
|
{
|
||||||
|
style: 2,
|
||||||
|
type: 2,
|
||||||
|
label: "Footer",
|
||||||
|
disabled: disabled,
|
||||||
|
custom_id: "edit_footer"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 1,
|
||||||
|
components: [
|
||||||
|
{
|
||||||
|
style: 3,
|
||||||
|
type: 2,
|
||||||
|
label: "Guardar",
|
||||||
|
disabled: disabled,
|
||||||
|
custom_id: "save_embed"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
style: 4,
|
||||||
|
type: 2,
|
||||||
|
label: "Eliminar",
|
||||||
|
disabled: disabled,
|
||||||
|
custom_id: "cancel_embed"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
accent_color: null
|
||||||
|
}
|
||||||
|
]
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
if (message.channel.type === ChannelType.GuildText) {
|
if (message.channel.type === ChannelType.GuildText) {
|
||||||
const channel = message.channel as TextChannel;
|
const channel = message.channel as TextChannel;
|
||||||
|
|
||||||
const editorMessage = await channel.send({
|
const editorMessage = await channel.send({
|
||||||
embeds: [await renderPreview()],
|
embeds: [await renderPreview()],
|
||||||
components: generateButtonRows(),
|
//components: generateButtonRows(),
|
||||||
});
|
});
|
||||||
|
|
||||||
const collector = editorMessage.createMessageComponentCollector({
|
const collector = editorMessage.createMessageComponentCollector({
|
||||||
@@ -203,32 +381,51 @@ export const command: CommandMessage = {
|
|||||||
|
|
||||||
// Edición
|
// Edición
|
||||||
let promptContent = "";
|
let promptContent = "";
|
||||||
let fieldToEdit: "title" | "description" | "color" | "footer" | null =
|
let variableContent;
|
||||||
|
let fieldToEdit: "title" | "description" | "color" | "footer" | "image" | "thumbnail" | null =
|
||||||
null;
|
null;
|
||||||
|
|
||||||
switch (i.customId) {
|
switch (i.customId) {
|
||||||
case "edit_title":
|
case "edit_title":
|
||||||
promptContent =
|
promptContent =
|
||||||
"Escribe el nuevo **título** (puedes usar variables como `{user.name}`).";
|
"Escribe el nuevo **título** (puedes usar variables como `(guild.name)`).";
|
||||||
|
variableContent = variables_text
|
||||||
fieldToEdit = "title";
|
fieldToEdit = "title";
|
||||||
break;
|
break;
|
||||||
case "edit_description":
|
case "edit_description":
|
||||||
promptContent =
|
promptContent =
|
||||||
"Escribe la nueva **descripción** (puedes usar variables).";
|
"Escribe la nueva **descripción** (puedes usar variables).";
|
||||||
|
variableContent = variables_text
|
||||||
fieldToEdit = "description";
|
fieldToEdit = "description";
|
||||||
break;
|
break;
|
||||||
case "edit_color":
|
case "edit_color":
|
||||||
promptContent =
|
promptContent =
|
||||||
"Escribe el nuevo **color** en formato hexadecimal (ej: `#FF0000`).";
|
"Escribe el nuevo **color** en formato hexadecimal (ej: `#FF0000`).";
|
||||||
|
variableContent = variables_text
|
||||||
fieldToEdit = "color";
|
fieldToEdit = "color";
|
||||||
break;
|
break;
|
||||||
case "edit_footer":
|
case "edit_footer":
|
||||||
promptContent =
|
promptContent =
|
||||||
"Escribe el nuevo **texto del footer** (puedes usar variables).";
|
"Escribe el nuevo **texto del footer** (puedes usar variables).";
|
||||||
|
variableContent = variables_text
|
||||||
fieldToEdit = "footer";
|
fieldToEdit = "footer";
|
||||||
break;
|
break;
|
||||||
|
case "edit_imageurl":
|
||||||
|
promptContent =
|
||||||
|
"Pega el url **de la imagen** (puedes usar variables).";
|
||||||
|
variableContent = variables_text
|
||||||
|
fieldToEdit = "image";
|
||||||
|
break;
|
||||||
|
case "edit_thumbnail":
|
||||||
|
promptContent =
|
||||||
|
"Pega el url **del thumbnail** (puedes usar variables).";
|
||||||
|
variableContent = variables_text
|
||||||
|
fieldToEdit = "thumbnail";
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//@ts-ignore
|
||||||
|
const variableMessage = await i.channel.send(variableContent)
|
||||||
//@ts-ignore
|
//@ts-ignore
|
||||||
const promptMessage = await i.channel.send(promptContent);
|
const promptMessage = await i.channel.send(promptContent);
|
||||||
|
|
||||||
@@ -246,6 +443,9 @@ export const command: CommandMessage = {
|
|||||||
if (fieldToEdit === "title") embedState.title = newValue;
|
if (fieldToEdit === "title") embedState.title = newValue;
|
||||||
if (fieldToEdit === "description") embedState.description = newValue;
|
if (fieldToEdit === "description") embedState.description = newValue;
|
||||||
if (fieldToEdit === "footer") embedState.footer = newValue;
|
if (fieldToEdit === "footer") embedState.footer = newValue;
|
||||||
|
// added v0.0.1.1
|
||||||
|
if (fieldToEdit === "image") embedState.imageUrl = newValue;
|
||||||
|
if (fieldToEdit === "thumbnail") embedState.thumbnail = newValue;
|
||||||
|
|
||||||
if (fieldToEdit === "color") {
|
if (fieldToEdit === "color") {
|
||||||
try {
|
try {
|
||||||
@@ -258,6 +458,7 @@ export const command: CommandMessage = {
|
|||||||
|
|
||||||
await collectedMessage.delete();
|
await collectedMessage.delete();
|
||||||
await promptMessage.delete();
|
await promptMessage.delete();
|
||||||
|
await variableMessage.delete();
|
||||||
|
|
||||||
await editorMessage.edit({
|
await editorMessage.edit({
|
||||||
embeds: [await renderPreview()],
|
embeds: [await renderPreview()],
|
||||||
@@ -268,6 +469,7 @@ export const command: CommandMessage = {
|
|||||||
messageCollector.on("end", async (collected) => {
|
messageCollector.on("end", async (collected) => {
|
||||||
if (collected.size === 0) {
|
if (collected.size === 0) {
|
||||||
await promptMessage.delete();
|
await promptMessage.delete();
|
||||||
|
await variableMessage.delete();
|
||||||
await editorMessage.edit({
|
await editorMessage.edit({
|
||||||
components: generateButtonRows(false),
|
components: generateButtonRows(false),
|
||||||
});
|
});
|
||||||
@@ -1,9 +1,9 @@
|
|||||||
import { CommandMessage } from "../../../core/types/commands";
|
import { CommandMessage } from "../core/types/commands";
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
import { EmbedBuilder, ActionRowBuilder, ButtonBuilder, TextChannel, ChannelType } from "discord.js";
|
import { EmbedBuilder, ActionRowBuilder, ButtonBuilder, TextChannel, ChannelType } from "discord.js";
|
||||||
//@ts-ignore
|
//@ts-ignore
|
||||||
import { ButtonStyle, ComponentType } from "discord.js";
|
import { ButtonStyle, ComponentType } from "discord.js";
|
||||||
import { replaceVars } from "../../../core/lib/vars";
|
import { replaceVars } from "../core/lib/vars";
|
||||||
|
|
||||||
export const command: CommandMessage = {
|
export const command: CommandMessage = {
|
||||||
name: "editembed",
|
name: "editembed",
|
||||||
729
src/commands/messages/alliaces/createEmbedv2.ts
Normal file
729
src/commands/messages/alliaces/createEmbedv2.ts
Normal file
@@ -0,0 +1,729 @@
|
|||||||
|
import { CommandMessage } from "../../../core/types/commands";
|
||||||
|
// @ts-ignore
|
||||||
|
import { ComponentType, ButtonStyle } from "discord.js";
|
||||||
|
import { replaceVars } from "../../../core/lib/vars";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Botones de edición
|
||||||
|
*/
|
||||||
|
const btns = (disabled = false) => ([
|
||||||
|
{
|
||||||
|
type: 1,
|
||||||
|
components: [
|
||||||
|
{ style: ButtonStyle.Secondary, type: 2, label: "Editar Título", disabled, custom_id: "edit_title" },
|
||||||
|
{ style: ButtonStyle.Secondary, type: 2, label: "Editar Descripción", disabled, custom_id: "edit_description" },
|
||||||
|
{ style: ButtonStyle.Secondary, type: 2, label: "Editar Color", disabled, custom_id: "edit_color" },
|
||||||
|
{ style: ButtonStyle.Secondary, type: 2, label: "Añadir Contenido", disabled, custom_id: "add_content" },
|
||||||
|
{ style: ButtonStyle.Secondary, type: 2, label: "Añadir Separador", disabled, custom_id: "add_separator" }
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 1,
|
||||||
|
components: [
|
||||||
|
{ style: ButtonStyle.Secondary, type: 2, label: "Añadir Imagen", disabled, custom_id: "add_image" },
|
||||||
|
{ style: ButtonStyle.Secondary, type: 2, label: "Imagen Portada", disabled, custom_id: "cover_image" },
|
||||||
|
{ style: ButtonStyle.Primary, type: 2, label: "Mover Bloque", disabled, custom_id: "move_block" },
|
||||||
|
{ style: ButtonStyle.Danger, type: 2, label: "Eliminar Bloque", disabled, custom_id: "delete_block" },
|
||||||
|
{ style: ButtonStyle.Secondary, type: 2, label: "Editar Thumbnail", disabled, custom_id: "edit_thumbnail" }
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 1,
|
||||||
|
components: [
|
||||||
|
{ style: ButtonStyle.Success, type: 2, label: "Guardar", disabled, custom_id: "save_block" },
|
||||||
|
{ style: ButtonStyle.Danger, type: 2, label: "Cancelar", disabled, custom_id: "cancel_block" }
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Validar si una URL es válida
|
||||||
|
*/
|
||||||
|
const isValidUrl = (url: string): boolean => {
|
||||||
|
if (!url || typeof url !== 'string') return false;
|
||||||
|
try {
|
||||||
|
new URL(url);
|
||||||
|
return url.startsWith('http://') || url.startsWith('https://');
|
||||||
|
} catch {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generar vista previa
|
||||||
|
*/
|
||||||
|
const renderPreview = async (blockState: any, member: any, guild: any) => {
|
||||||
|
const previewComponents = [];
|
||||||
|
|
||||||
|
// Añadir imagen de portada primero si existe
|
||||||
|
if (blockState.coverImage && isValidUrl(blockState.coverImage)) {
|
||||||
|
//@ts-ignore
|
||||||
|
const processedCoverUrl = await replaceVars(blockState.coverImage, member, guild);
|
||||||
|
if (isValidUrl(processedCoverUrl)) {
|
||||||
|
previewComponents.push({
|
||||||
|
type: 12,
|
||||||
|
items: [{ media: { url: processedCoverUrl } }]
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Añadir título después de la portada
|
||||||
|
previewComponents.push({
|
||||||
|
type: 10,
|
||||||
|
//@ts-ignore
|
||||||
|
content: await replaceVars(blockState.title ?? "Sin título", member, guild)
|
||||||
|
});
|
||||||
|
|
||||||
|
// Procesar componentes en orden
|
||||||
|
for (const c of blockState.components) {
|
||||||
|
if (c.type === 10) {
|
||||||
|
// Componente de texto con thumbnail opcional
|
||||||
|
//@ts-ignore
|
||||||
|
const processedThumbnail = c.thumbnail ? await replaceVars(c.thumbnail, member, guild) : null;
|
||||||
|
|
||||||
|
if (processedThumbnail && isValidUrl(processedThumbnail)) {
|
||||||
|
// Si tiene thumbnail válido, usar contenedor tipo 9 con accessory
|
||||||
|
previewComponents.push({
|
||||||
|
type: 9,
|
||||||
|
components: [
|
||||||
|
{
|
||||||
|
type: 10,
|
||||||
|
//@ts-ignore
|
||||||
|
content: await replaceVars(c.content || " ", member, guild)
|
||||||
|
}
|
||||||
|
],
|
||||||
|
accessory: {
|
||||||
|
type: 11,
|
||||||
|
media: { url: processedThumbnail }
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
// Sin thumbnail o thumbnail inválido, componente normal
|
||||||
|
previewComponents.push({
|
||||||
|
type: 10,
|
||||||
|
//@ts-ignore
|
||||||
|
content: await replaceVars(c.content || " ", member, guild)
|
||||||
|
});
|
||||||
|
}
|
||||||
|
} else if (c.type === 14) {
|
||||||
|
// Separador
|
||||||
|
previewComponents.push({
|
||||||
|
type: 14,
|
||||||
|
divider: c.divider ?? true,
|
||||||
|
spacing: c.spacing ?? 1
|
||||||
|
});
|
||||||
|
} else if (c.type === 12) {
|
||||||
|
// Imagen - validar URL también
|
||||||
|
//@ts-ignore
|
||||||
|
const processedImageUrl = await replaceVars(c.url, member, guild);
|
||||||
|
|
||||||
|
if (isValidUrl(processedImageUrl)) {
|
||||||
|
previewComponents.push({
|
||||||
|
type: 12,
|
||||||
|
items: [{ media: { url: processedImageUrl } }]
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
type: 17,
|
||||||
|
accent_color: blockState.color ?? null,
|
||||||
|
components: previewComponents
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
export const command: CommandMessage = {
|
||||||
|
name: "blockcreatev2",
|
||||||
|
type: "message",
|
||||||
|
cooldown: 20,
|
||||||
|
run: async (message, args, client) => {
|
||||||
|
if (!message.member?.permissions.has("Administrator")) {
|
||||||
|
return message.reply("❌ No tienes permisos de Administrador.");
|
||||||
|
}
|
||||||
|
|
||||||
|
const blockName: string | null = args[0] ?? null;
|
||||||
|
if (!blockName) {
|
||||||
|
return message.reply("Debes proporcionar un nombre. Uso: `!blockcreatev2 <nombre>`");
|
||||||
|
}
|
||||||
|
|
||||||
|
const nameIsValid = await client.prisma.blockV2Config.findFirst({
|
||||||
|
where: { guildId: message.guild!.id, name: blockName }
|
||||||
|
});
|
||||||
|
if (nameIsValid) return message.reply("❌ Nombre ya usado!");
|
||||||
|
|
||||||
|
// Estado inicial
|
||||||
|
let blockState: any = {
|
||||||
|
title: `Editor de Block: ${blockName}`,
|
||||||
|
color: null,
|
||||||
|
coverImage: null, // Nueva propiedad para imagen de portada
|
||||||
|
components: [
|
||||||
|
{ type: 14, divider: false },
|
||||||
|
{ type: 10, content: "Usa los botones para configurar.", thumbnail: null }
|
||||||
|
]
|
||||||
|
};
|
||||||
|
|
||||||
|
//@ts-ignore
|
||||||
|
const editorMessage = await message.channel.send({
|
||||||
|
flags: 32768,
|
||||||
|
components: [
|
||||||
|
await renderPreview(blockState, message.member, message.guild),
|
||||||
|
...btns(false)
|
||||||
|
]
|
||||||
|
});
|
||||||
|
|
||||||
|
const collector = editorMessage.createMessageComponentCollector({
|
||||||
|
time: 300000
|
||||||
|
});
|
||||||
|
|
||||||
|
collector.on("collect", async (i) => {
|
||||||
|
if (i.user.id !== message.author.id) {
|
||||||
|
await i.reply({ content: "No puedes usar este menú.", ephemeral: true });
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- BOTONES ---
|
||||||
|
if (i.isButton()) {
|
||||||
|
await editorMessage.edit({
|
||||||
|
components: [await renderPreview(blockState, message.member, message.guild), ...btns(true)]
|
||||||
|
});
|
||||||
|
await i.deferUpdate();
|
||||||
|
|
||||||
|
switch (i.customId) {
|
||||||
|
case "save_block": {
|
||||||
|
await client.prisma.blockV2Config.upsert({
|
||||||
|
where: { guildId_name: { guildId: message.guildId!, name: blockName } },
|
||||||
|
update: { config: blockState },
|
||||||
|
create: {
|
||||||
|
name: blockName,
|
||||||
|
config: blockState,
|
||||||
|
guild: {
|
||||||
|
connectOrCreate: {
|
||||||
|
where: { id: message.guildId! },
|
||||||
|
create: { id: message.guildId!, name: message.guild!.name }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
await editorMessage.edit({
|
||||||
|
components: [
|
||||||
|
{
|
||||||
|
type: 17,
|
||||||
|
accent_color: blockState.color ?? null,
|
||||||
|
components: [
|
||||||
|
{ type: 10, content: `✅ Guardado: ${blockName}` },
|
||||||
|
{ type: 10, content: "Configuración guardada en la base de datos (JSON)." }
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
});
|
||||||
|
collector.stop();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
case "cancel_block": {
|
||||||
|
await editorMessage.delete();
|
||||||
|
collector.stop();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
case "edit_title": {
|
||||||
|
const prompt = await message.channel.send("Escribe el nuevo **título**.");
|
||||||
|
const mc = message.channel.createMessageCollector({
|
||||||
|
filter: (m) => m.author.id === message.author.id,
|
||||||
|
max: 1,
|
||||||
|
time: 60000
|
||||||
|
});
|
||||||
|
mc.on("collect", async (collected) => {
|
||||||
|
blockState.title = collected.content;
|
||||||
|
await collected.delete();
|
||||||
|
await prompt.delete();
|
||||||
|
await editorMessage.edit({
|
||||||
|
components: [await renderPreview(blockState, message.member, message.guild), ...btns(false)]
|
||||||
|
});
|
||||||
|
});
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case "cover_image": {
|
||||||
|
if (blockState.coverImage) {
|
||||||
|
// Si ya tiene portada, preguntar si editar o eliminar
|
||||||
|
//@ts-ignore
|
||||||
|
const reply = await i.followUp({
|
||||||
|
ephemeral: true,
|
||||||
|
content: "Ya tienes una imagen de portada. ¿Qué quieres hacer?",
|
||||||
|
components: [
|
||||||
|
{
|
||||||
|
type: 1,
|
||||||
|
components: [
|
||||||
|
{ type: 2, style: ButtonStyle.Primary, label: "✏️ Editar", custom_id: "edit_cover" },
|
||||||
|
{ type: 2, style: ButtonStyle.Danger, label: "🗑️ Eliminar", custom_id: "delete_cover" }
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
fetchReply: true
|
||||||
|
});
|
||||||
|
|
||||||
|
//@ts-ignore
|
||||||
|
const coverCollector = reply.createMessageComponentCollector({
|
||||||
|
componentType: ComponentType.Button,
|
||||||
|
max: 1,
|
||||||
|
time: 60000,
|
||||||
|
filter: (b: any) => b.user.id === message.author.id
|
||||||
|
});
|
||||||
|
|
||||||
|
coverCollector.on("collect", async (b: any) => {
|
||||||
|
if (b.customId === "edit_cover") {
|
||||||
|
await b.update({ content: "Escribe la nueva **URL de la imagen de portada**:", components: [] });
|
||||||
|
|
||||||
|
const prompt = await message.channel.send("Nueva URL de portada:");
|
||||||
|
const mc = message.channel.createMessageCollector({
|
||||||
|
filter: (m) => m.author.id === message.author.id,
|
||||||
|
max: 1,
|
||||||
|
time: 60000
|
||||||
|
});
|
||||||
|
|
||||||
|
mc.on("collect", async (collected) => {
|
||||||
|
blockState.coverImage = collected.content;
|
||||||
|
await collected.delete();
|
||||||
|
await prompt.delete();
|
||||||
|
await editorMessage.edit({
|
||||||
|
components: [await renderPreview(blockState, message.member, message.guild), ...btns(false)]
|
||||||
|
});
|
||||||
|
});
|
||||||
|
} else if (b.customId === "delete_cover") {
|
||||||
|
blockState.coverImage = null;
|
||||||
|
await b.update({ content: "✅ Imagen de portada eliminada.", components: [] });
|
||||||
|
await editorMessage.edit({
|
||||||
|
components: [await renderPreview(blockState, message.member, message.guild), ...btns(false)]
|
||||||
|
});
|
||||||
|
}
|
||||||
|
coverCollector.stop();
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
// No tiene portada, añadir nueva
|
||||||
|
const prompt = await message.channel.send("Escribe la **URL de la imagen de portada**.");
|
||||||
|
const mc = message.channel.createMessageCollector({
|
||||||
|
filter: (m) => m.author.id === message.author.id,
|
||||||
|
max: 1,
|
||||||
|
time: 60000
|
||||||
|
});
|
||||||
|
mc.on("collect", async (collected) => {
|
||||||
|
blockState.coverImage = collected.content;
|
||||||
|
await collected.delete();
|
||||||
|
await prompt.delete();
|
||||||
|
await editorMessage.edit({
|
||||||
|
components: [await renderPreview(blockState, message.member, message.guild), ...btns(false)]
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case "edit_description": {
|
||||||
|
const prompt = await message.channel.send("Escribe la nueva **descripción**.");
|
||||||
|
const mc = message.channel.createMessageCollector({
|
||||||
|
filter: (m) => m.author.id === message.author.id,
|
||||||
|
max: 1,
|
||||||
|
time: 60000
|
||||||
|
});
|
||||||
|
mc.on("collect", async (collected) => {
|
||||||
|
const descComp = blockState.components.find((c: any) => c.type === 10);
|
||||||
|
if (descComp) descComp.content = collected.content;
|
||||||
|
await collected.delete();
|
||||||
|
await prompt.delete();
|
||||||
|
await editorMessage.edit({
|
||||||
|
components: [await renderPreview(blockState, message.member, message.guild), ...btns(false)]
|
||||||
|
});
|
||||||
|
});
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case "edit_color": {
|
||||||
|
const prompt = await message.channel.send("Escribe el nuevo **color** en HEX (#RRGGBB).");
|
||||||
|
const mc = message.channel.createMessageCollector({
|
||||||
|
filter: (m) => m.author.id === message.author.id,
|
||||||
|
max: 1,
|
||||||
|
time: 60000
|
||||||
|
});
|
||||||
|
mc.on("collect", async (collected) => {
|
||||||
|
const newValue = collected.content;
|
||||||
|
let parsed: number | null = null;
|
||||||
|
if (/^#?[0-9A-Fa-f]{6}$/.test(newValue)) {
|
||||||
|
parsed = parseInt(newValue.replace("#", ""), 16);
|
||||||
|
}
|
||||||
|
blockState.color = parsed;
|
||||||
|
await collected.delete();
|
||||||
|
await prompt.delete();
|
||||||
|
await editorMessage.edit({
|
||||||
|
components: [await renderPreview(blockState, message.member, message.guild), ...btns(false)]
|
||||||
|
});
|
||||||
|
});
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case "add_content": {
|
||||||
|
const prompt = await message.channel.send("Escribe el nuevo **contenido**.");
|
||||||
|
const mc = message.channel.createMessageCollector({
|
||||||
|
filter: (m) => m.author.id === message.author.id,
|
||||||
|
max: 1,
|
||||||
|
time: 60000
|
||||||
|
});
|
||||||
|
mc.on("collect", async (collected) => {
|
||||||
|
blockState.components.push({ type: 10, content: collected.content, thumbnail: null });
|
||||||
|
await collected.delete();
|
||||||
|
await prompt.delete();
|
||||||
|
await editorMessage.edit({
|
||||||
|
components: [await renderPreview(blockState, message.member, message.guild), ...btns(false)]
|
||||||
|
});
|
||||||
|
});
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case "add_separator": {
|
||||||
|
//@ts-ignore
|
||||||
|
const reply = await i.followUp({
|
||||||
|
ephemeral: true,
|
||||||
|
content: "¿El separador debe ser visible?",
|
||||||
|
components: [
|
||||||
|
{
|
||||||
|
type: 1,
|
||||||
|
components: [
|
||||||
|
{ type: 2, style: ButtonStyle.Success, label: "✅ Visible", custom_id: "separator_visible" },
|
||||||
|
{ type: 2, style: ButtonStyle.Secondary, label: "❌ Invisible", custom_id: "separator_invisible" }
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
fetchReply: true
|
||||||
|
});
|
||||||
|
|
||||||
|
//@ts-ignore
|
||||||
|
const sepCollector = reply.createMessageComponentCollector({
|
||||||
|
componentType: ComponentType.Button,
|
||||||
|
max: 1,
|
||||||
|
time: 60000,
|
||||||
|
filter: (b: any) => b.user.id === message.author.id
|
||||||
|
});
|
||||||
|
|
||||||
|
sepCollector.on("collect", async (b: any) => {
|
||||||
|
const isVisible = b.customId === "separator_visible";
|
||||||
|
blockState.components.push({ type: 14, divider: isVisible, spacing: 1 });
|
||||||
|
|
||||||
|
await b.update({
|
||||||
|
content: `✅ Separador ${isVisible ? 'visible' : 'invisible'} añadido.`,
|
||||||
|
components: []
|
||||||
|
});
|
||||||
|
|
||||||
|
await editorMessage.edit({
|
||||||
|
components: [await renderPreview(blockState, message.member, message.guild), ...btns(false)]
|
||||||
|
});
|
||||||
|
|
||||||
|
sepCollector.stop();
|
||||||
|
});
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case "add_image": {
|
||||||
|
const prompt = await message.channel.send("Escribe la **URL de la imagen**.");
|
||||||
|
const mc = message.channel.createMessageCollector({
|
||||||
|
filter: (m) => m.author.id === message.author.id,
|
||||||
|
max: 1,
|
||||||
|
time: 60000
|
||||||
|
});
|
||||||
|
mc.on("collect", async (collected) => {
|
||||||
|
blockState.components.push({ type: 12, url: collected.content });
|
||||||
|
await collected.delete();
|
||||||
|
await prompt.delete();
|
||||||
|
await editorMessage.edit({
|
||||||
|
components: [await renderPreview(blockState, message.member, message.guild), ...btns(false)]
|
||||||
|
});
|
||||||
|
});
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case "edit_thumbnail": {
|
||||||
|
// Buscar componentes de texto para seleccionar cuál editar
|
||||||
|
const textComponents = blockState.components
|
||||||
|
.map((c: any, idx: number) => ({ component: c, index: idx }))
|
||||||
|
.filter(({ component }) => component.type === 10);
|
||||||
|
|
||||||
|
if (textComponents.length === 0) {
|
||||||
|
//@ts-ignore
|
||||||
|
await i.followUp({
|
||||||
|
content: "❌ No hay componentes de texto para añadir thumbnail.",
|
||||||
|
ephemeral: true
|
||||||
|
});
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (textComponents.length === 1) {
|
||||||
|
// Solo un componente de texto, editarlo directamente
|
||||||
|
const prompt = await message.channel.send("Escribe la **URL del thumbnail**.");
|
||||||
|
const mc = message.channel.createMessageCollector({
|
||||||
|
filter: (m) => m.author.id === message.author.id,
|
||||||
|
max: 1,
|
||||||
|
time: 60000
|
||||||
|
});
|
||||||
|
mc.on("collect", async (collected) => {
|
||||||
|
textComponents[0].component.thumbnail = collected.content;
|
||||||
|
await collected.delete();
|
||||||
|
await prompt.delete();
|
||||||
|
await editorMessage.edit({
|
||||||
|
components: [await renderPreview(blockState, message.member, message.guild), ...btns(false)]
|
||||||
|
});
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
// Múltiples componentes de texto, mostrar selector
|
||||||
|
const options = textComponents.map(({ component, index }) => ({
|
||||||
|
label: `Texto: ${component.content?.slice(0, 30) || "..."}`,
|
||||||
|
value: index.toString(),
|
||||||
|
description: component.thumbnail ? "Ya tiene thumbnail" : "Sin thumbnail"
|
||||||
|
}));
|
||||||
|
|
||||||
|
//@ts-ignore
|
||||||
|
const reply = await i.followUp({
|
||||||
|
ephemeral: true,
|
||||||
|
content: "Selecciona el texto al que quieres añadir/editar thumbnail:",
|
||||||
|
components: [
|
||||||
|
{
|
||||||
|
type: 1,
|
||||||
|
components: [
|
||||||
|
{
|
||||||
|
type: 3,
|
||||||
|
custom_id: "select_text_for_thumbnail",
|
||||||
|
placeholder: "Elige un texto",
|
||||||
|
options
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
fetchReply: true
|
||||||
|
});
|
||||||
|
|
||||||
|
//@ts-ignore
|
||||||
|
const selCollector = reply.createMessageComponentCollector({
|
||||||
|
componentType: ComponentType.StringSelect,
|
||||||
|
max: 1,
|
||||||
|
time: 60000,
|
||||||
|
filter: (sel: any) => sel.user.id === message.author.id
|
||||||
|
});
|
||||||
|
|
||||||
|
selCollector.on("collect", async (sel: any) => {
|
||||||
|
const selectedIndex = parseInt(sel.values[0]);
|
||||||
|
|
||||||
|
await sel.update({
|
||||||
|
content: "Escribe la **URL del thumbnail**:",
|
||||||
|
components: []
|
||||||
|
});
|
||||||
|
|
||||||
|
const prompt = await message.channel.send("URL del thumbnail:");
|
||||||
|
const mc = message.channel.createMessageCollector({
|
||||||
|
filter: (m) => m.author.id === message.author.id,
|
||||||
|
max: 1,
|
||||||
|
time: 60000
|
||||||
|
});
|
||||||
|
|
||||||
|
mc.on("collect", async (collected) => {
|
||||||
|
blockState.components[selectedIndex].thumbnail = collected.content;
|
||||||
|
await collected.delete();
|
||||||
|
await prompt.delete();
|
||||||
|
await editorMessage.edit({
|
||||||
|
components: [await renderPreview(blockState, message.member, message.guild), ...btns(false)]
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case "move_block": {
|
||||||
|
const options = blockState.components.map((c: any, idx: number) => ({
|
||||||
|
label:
|
||||||
|
c.type === 10
|
||||||
|
? `Texto: ${c.content?.slice(0, 30) || "..."}`
|
||||||
|
: c.type === 14
|
||||||
|
? "Separador"
|
||||||
|
: c.type === 12
|
||||||
|
? `Imagen: ${c.url?.slice(-30) || "..."}`
|
||||||
|
: `Componente ${c.type}`,
|
||||||
|
value: idx.toString(),
|
||||||
|
description:
|
||||||
|
c.type === 10 && c.thumbnail
|
||||||
|
? "Con thumbnail"
|
||||||
|
: undefined
|
||||||
|
}));
|
||||||
|
|
||||||
|
//@ts-ignore
|
||||||
|
const reply = await i.followUp({
|
||||||
|
ephemeral: true,
|
||||||
|
content: "Selecciona el bloque que quieres mover:",
|
||||||
|
components: [
|
||||||
|
{
|
||||||
|
type: 1,
|
||||||
|
components: [
|
||||||
|
{ type: 3, custom_id: "move_block_select", placeholder: "Elige un bloque", options }
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
fetchReply: true
|
||||||
|
});
|
||||||
|
|
||||||
|
//@ts-ignore
|
||||||
|
const selCollector = reply.createMessageComponentCollector({
|
||||||
|
componentType: ComponentType.StringSelect,
|
||||||
|
max: 1,
|
||||||
|
time: 60000,
|
||||||
|
filter: (it: any) => it.user.id === message.author.id
|
||||||
|
});
|
||||||
|
|
||||||
|
selCollector.on("collect", async (sel: any) => {
|
||||||
|
const idx = parseInt(sel.values[0]);
|
||||||
|
|
||||||
|
await sel.update({
|
||||||
|
content: "¿Quieres mover este bloque?",
|
||||||
|
components: [
|
||||||
|
{
|
||||||
|
type: 1,
|
||||||
|
components: [
|
||||||
|
{ type: 2, style: ButtonStyle.Secondary, label: "⬆️ Subir", custom_id: `move_up_${idx}`, disabled: idx === 0 },
|
||||||
|
{ type: 2, style: ButtonStyle.Secondary, label: "⬇️ Bajar", custom_id: `move_down_${idx}`, disabled: idx === blockState.components.length - 1 }
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
});
|
||||||
|
|
||||||
|
//@ts-ignore
|
||||||
|
const btnCollector = reply.createMessageComponentCollector({
|
||||||
|
componentType: ComponentType.Button,
|
||||||
|
max: 1,
|
||||||
|
time: 60000,
|
||||||
|
filter: (b: any) => b.user.id === message.author.id
|
||||||
|
});
|
||||||
|
|
||||||
|
btnCollector.on("collect", async (b: any) => {
|
||||||
|
if (b.customId.startsWith("move_up_")) {
|
||||||
|
const i2 = parseInt(b.customId.replace("move_up_", ""));
|
||||||
|
if (i2 > 0) {
|
||||||
|
const item = blockState.components[i2];
|
||||||
|
blockState.components.splice(i2, 1);
|
||||||
|
blockState.components.splice(i2 - 1, 0, item);
|
||||||
|
}
|
||||||
|
await b.update({ content: "✅ Bloque movido arriba.", components: [] });
|
||||||
|
} else if (b.customId.startsWith("move_down_")) {
|
||||||
|
const i2 = parseInt(b.customId.replace("move_down_", ""));
|
||||||
|
if (i2 < blockState.components.length - 1) {
|
||||||
|
const item = blockState.components[i2];
|
||||||
|
blockState.components.splice(i2, 1);
|
||||||
|
blockState.components.splice(i2 + 1, 0, item);
|
||||||
|
}
|
||||||
|
await b.update({ content: "✅ Bloque movido abajo.", components: [] });
|
||||||
|
}
|
||||||
|
|
||||||
|
await editorMessage.edit({
|
||||||
|
components: [await renderPreview(blockState, message.member, message.guild), ...btns(false)]
|
||||||
|
});
|
||||||
|
|
||||||
|
btnCollector.stop();
|
||||||
|
selCollector.stop();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case "delete_block": {
|
||||||
|
// Incluir portada en las opciones si existe
|
||||||
|
const options = [];
|
||||||
|
|
||||||
|
// Añadir portada como opción si existe
|
||||||
|
if (blockState.coverImage) {
|
||||||
|
options.push({
|
||||||
|
label: "🖼️ Imagen de Portada",
|
||||||
|
value: "cover_image",
|
||||||
|
description: "Imagen principal del bloque"
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Añadir componentes regulares
|
||||||
|
blockState.components.forEach((c: any, idx: number) => {
|
||||||
|
options.push({
|
||||||
|
label:
|
||||||
|
c.type === 10
|
||||||
|
? `Texto: ${c.content?.slice(0, 30) || "..."}`
|
||||||
|
: c.type === 14
|
||||||
|
? `Separador ${c.divider ? '(Visible)' : '(Invisible)'}`
|
||||||
|
: c.type === 12
|
||||||
|
? `Imagen: ${c.url?.slice(-30) || "..."}`
|
||||||
|
: `Componente ${c.type}`,
|
||||||
|
value: idx.toString(),
|
||||||
|
description:
|
||||||
|
c.type === 10 && c.thumbnail
|
||||||
|
? "Con thumbnail"
|
||||||
|
: undefined
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
if (options.length === 0) {
|
||||||
|
//@ts-ignore
|
||||||
|
await i.followUp({
|
||||||
|
content: "❌ No hay elementos para eliminar.",
|
||||||
|
ephemeral: true
|
||||||
|
});
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
//@ts-ignore
|
||||||
|
const reply = await i.followUp({
|
||||||
|
ephemeral: true,
|
||||||
|
content: "Selecciona el elemento que quieres eliminar:",
|
||||||
|
components: [
|
||||||
|
{
|
||||||
|
type: 1,
|
||||||
|
components: [
|
||||||
|
{ type: 3, custom_id: "delete_block_select", placeholder: "Elige un elemento", options }
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
fetchReply: true
|
||||||
|
});
|
||||||
|
|
||||||
|
//@ts-ignore
|
||||||
|
const selCollector = reply.createMessageComponentCollector({
|
||||||
|
componentType: ComponentType.StringSelect,
|
||||||
|
max: 1,
|
||||||
|
time: 60000,
|
||||||
|
filter: (it: any) => it.user.id === message.author.id
|
||||||
|
});
|
||||||
|
|
||||||
|
selCollector.on("collect", async (sel: any) => {
|
||||||
|
const selectedValue = sel.values[0];
|
||||||
|
|
||||||
|
if (selectedValue === "cover_image") {
|
||||||
|
blockState.coverImage = null;
|
||||||
|
await sel.update({ content: "✅ Imagen de portada eliminada.", components: [] });
|
||||||
|
} else {
|
||||||
|
const idx = parseInt(selectedValue);
|
||||||
|
blockState.components.splice(idx, 1);
|
||||||
|
await sel.update({ content: "✅ Elemento eliminado.", components: [] });
|
||||||
|
}
|
||||||
|
|
||||||
|
await editorMessage.edit({
|
||||||
|
components: [await renderPreview(blockState, message.member, message.guild), ...btns(false)]
|
||||||
|
});
|
||||||
|
|
||||||
|
selCollector.stop();
|
||||||
|
});
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
await editorMessage.edit({
|
||||||
|
components: [await renderPreview(blockState, message.member, message.guild), ...btns(false)]
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
//@ts-ignore
|
||||||
|
collector.on("end", async (_, reason) => {
|
||||||
|
if (reason === "time") {
|
||||||
|
await editorMessage.edit({
|
||||||
|
components: [
|
||||||
|
{ type: 17, components: [{ type: 10, content: "⏰ Editor finalizado por inactividad." }] }
|
||||||
|
]
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
732
src/commands/messages/alliaces/editEmbedv2.ts
Normal file
732
src/commands/messages/alliaces/editEmbedv2.ts
Normal file
@@ -0,0 +1,732 @@
|
|||||||
|
import { CommandMessage } from "../../../core/types/commands";
|
||||||
|
// @ts-ignore
|
||||||
|
import { ComponentType, ButtonStyle } from "discord.js";
|
||||||
|
import { replaceVars } from "../../../core/lib/vars";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Validar si una URL es válida
|
||||||
|
*/
|
||||||
|
const isValidUrl = (url: string): boolean => {
|
||||||
|
if (!url || typeof url !== 'string') return false;
|
||||||
|
try {
|
||||||
|
new URL(url);
|
||||||
|
return url.startsWith('http://') || url.startsWith('https://');
|
||||||
|
} catch {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Botones de edición
|
||||||
|
*/
|
||||||
|
const btns = (disabled = false) => ([
|
||||||
|
{
|
||||||
|
type: 1,
|
||||||
|
components: [
|
||||||
|
{ style: ButtonStyle.Secondary, type: 2, label: "Editar Título", disabled, custom_id: "edit_title" },
|
||||||
|
{ style: ButtonStyle.Secondary, type: 2, label: "Editar Descripción", disabled, custom_id: "edit_description" },
|
||||||
|
{ style: ButtonStyle.Secondary, type: 2, label: "Editar Color", disabled, custom_id: "edit_color" },
|
||||||
|
{ style: ButtonStyle.Secondary, type: 2, label: "Añadir Contenido", disabled, custom_id: "add_content" },
|
||||||
|
{ style: ButtonStyle.Secondary, type: 2, label: "Añadir Separador", disabled, custom_id: "add_separator" }
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 1,
|
||||||
|
components: [
|
||||||
|
{ style: ButtonStyle.Secondary, type: 2, label: "Añadir Imagen", disabled, custom_id: "add_image" },
|
||||||
|
{ style: ButtonStyle.Secondary, type: 2, label: "Imagen Portada", disabled, custom_id: "cover_image" },
|
||||||
|
{ style: ButtonStyle.Primary, type: 2, label: "Mover Bloque", disabled, custom_id: "move_block" },
|
||||||
|
{ style: ButtonStyle.Danger, type: 2, label: "Eliminar Bloque", disabled, custom_id: "delete_block" },
|
||||||
|
{ style: ButtonStyle.Secondary, type: 2, label: "Editar Thumbnail", disabled, custom_id: "edit_thumbnail" }
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 1,
|
||||||
|
components: [
|
||||||
|
{ style: ButtonStyle.Success, type: 2, label: "Guardar", disabled, custom_id: "save_block" },
|
||||||
|
{ style: ButtonStyle.Danger, type: 2, label: "Cancelar", disabled, custom_id: "cancel_block" }
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generar vista previa
|
||||||
|
*/
|
||||||
|
const renderPreview = async (blockState: any, member: any, guild: any) => {
|
||||||
|
const previewComponents = [];
|
||||||
|
|
||||||
|
// Añadir imagen de portada primero si existe
|
||||||
|
if (blockState.coverImage && isValidUrl(blockState.coverImage)) {
|
||||||
|
//@ts-ignore
|
||||||
|
const processedCoverUrl = await replaceVars(blockState.coverImage, member, guild);
|
||||||
|
if (isValidUrl(processedCoverUrl)) {
|
||||||
|
previewComponents.push({
|
||||||
|
type: 12,
|
||||||
|
items: [{ media: { url: processedCoverUrl } }]
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Añadir título después de la portada
|
||||||
|
previewComponents.push({
|
||||||
|
type: 10,
|
||||||
|
//@ts-ignore
|
||||||
|
content: await replaceVars(blockState.title ?? "Sin título", member, guild)
|
||||||
|
});
|
||||||
|
|
||||||
|
// Procesar componentes en orden
|
||||||
|
for (const c of blockState.components) {
|
||||||
|
if (c.type === 10) {
|
||||||
|
// Componente de texto con thumbnail opcional
|
||||||
|
//@ts-ignore
|
||||||
|
const processedThumbnail = c.thumbnail ? await replaceVars(c.thumbnail, member, guild) : null;
|
||||||
|
|
||||||
|
if (processedThumbnail && isValidUrl(processedThumbnail)) {
|
||||||
|
// Si tiene thumbnail válido, usar contenedor tipo 9 con accessory
|
||||||
|
previewComponents.push({
|
||||||
|
type: 9,
|
||||||
|
components: [
|
||||||
|
{
|
||||||
|
type: 10,
|
||||||
|
//@ts-ignore
|
||||||
|
content: await replaceVars(c.content || " ", member, guild)
|
||||||
|
}
|
||||||
|
],
|
||||||
|
accessory: {
|
||||||
|
type: 11,
|
||||||
|
media: { url: processedThumbnail }
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
// Sin thumbnail o thumbnail inválido, componente normal
|
||||||
|
previewComponents.push({
|
||||||
|
type: 10,
|
||||||
|
//@ts-ignore
|
||||||
|
content: await replaceVars(c.content || " ", member, guild)
|
||||||
|
});
|
||||||
|
}
|
||||||
|
} else if (c.type === 14) {
|
||||||
|
// Separador
|
||||||
|
previewComponents.push({
|
||||||
|
type: 14,
|
||||||
|
divider: c.divider ?? true,
|
||||||
|
spacing: c.spacing ?? 1
|
||||||
|
});
|
||||||
|
} else if (c.type === 12) {
|
||||||
|
// Imagen - validar URL también
|
||||||
|
//@ts-ignore
|
||||||
|
const processedImageUrl = await replaceVars(c.url, member, guild);
|
||||||
|
|
||||||
|
if (isValidUrl(processedImageUrl)) {
|
||||||
|
previewComponents.push({
|
||||||
|
type: 12,
|
||||||
|
items: [{ media: { url: processedImageUrl } }]
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
type: 17,
|
||||||
|
accent_color: blockState.color ?? null,
|
||||||
|
components: previewComponents
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
export const command: CommandMessage = {
|
||||||
|
name: "blockedit",
|
||||||
|
type: "message",
|
||||||
|
cooldown: 20,
|
||||||
|
run: async (message, args, client) => {
|
||||||
|
if (!message.member?.permissions.has("Administrator")) {
|
||||||
|
return message.reply("❌ No tienes permisos de Administrador.");
|
||||||
|
}
|
||||||
|
|
||||||
|
const blockName: string | null = args[0] ?? null;
|
||||||
|
if (!blockName) {
|
||||||
|
return message.reply("Debes proporcionar un nombre. Uso: `!blockedit <nombre>`");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Buscar el block existente
|
||||||
|
const existingBlock = await client.prisma.blockV2Config.findFirst({
|
||||||
|
where: { guildId: message.guild!.id, name: blockName }
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!existingBlock) {
|
||||||
|
return message.reply(`❌ No se encontró un block con el nombre: **${blockName}**`);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Cargar configuración existente
|
||||||
|
let blockState: any = {
|
||||||
|
...existingBlock.config,
|
||||||
|
// Asegurar que las propiedades necesarias existan
|
||||||
|
title: existingBlock.config.title || `Block: ${blockName}`,
|
||||||
|
color: existingBlock.config.color || null,
|
||||||
|
coverImage: existingBlock.config.coverImage || null,
|
||||||
|
components: existingBlock.config.components || []
|
||||||
|
};
|
||||||
|
|
||||||
|
//@ts-ignore
|
||||||
|
const editorMessage = await message.channel.send({
|
||||||
|
flags: 32768,
|
||||||
|
components: [
|
||||||
|
await renderPreview(blockState, message.member, message.guild),
|
||||||
|
...btns(false)
|
||||||
|
]
|
||||||
|
});
|
||||||
|
|
||||||
|
const collector = editorMessage.createMessageComponentCollector({
|
||||||
|
time: 300000
|
||||||
|
});
|
||||||
|
|
||||||
|
collector.on("collect", async (i) => {
|
||||||
|
if (i.user.id !== message.author.id) {
|
||||||
|
await i.reply({ content: "No puedes usar este menú.", ephemeral: true });
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- BOTONES ---
|
||||||
|
if (i.isButton()) {
|
||||||
|
await editorMessage.edit({
|
||||||
|
components: [await renderPreview(blockState, message.member, message.guild), ...btns(true)]
|
||||||
|
});
|
||||||
|
await i.deferUpdate();
|
||||||
|
|
||||||
|
switch (i.customId) {
|
||||||
|
case "save_block": {
|
||||||
|
await client.prisma.blockV2Config.update({
|
||||||
|
where: { guildId_name: { guildId: message.guildId!, name: blockName } },
|
||||||
|
data: { config: blockState }
|
||||||
|
});
|
||||||
|
await editorMessage.edit({
|
||||||
|
components: [
|
||||||
|
{
|
||||||
|
type: 17,
|
||||||
|
accent_color: blockState.color ?? null,
|
||||||
|
components: [
|
||||||
|
{ type: 10, content: `✅ Block actualizado: ${blockName}` },
|
||||||
|
{ type: 10, content: "Configuración guardada exitosamente." }
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
});
|
||||||
|
collector.stop();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
case "cancel_block": {
|
||||||
|
await editorMessage.edit({
|
||||||
|
components: [
|
||||||
|
{
|
||||||
|
type: 17,
|
||||||
|
components: [
|
||||||
|
{ type: 10, content: "❌ Edición cancelada." },
|
||||||
|
{ type: 10, content: "No se guardaron los cambios." }
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
});
|
||||||
|
collector.stop();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
case "edit_title": {
|
||||||
|
const prompt = await message.channel.send("Escribe el nuevo **título**.");
|
||||||
|
const mc = message.channel.createMessageCollector({
|
||||||
|
filter: (m) => m.author.id === message.author.id,
|
||||||
|
max: 1,
|
||||||
|
time: 60000
|
||||||
|
});
|
||||||
|
mc.on("collect", async (collected) => {
|
||||||
|
blockState.title = collected.content;
|
||||||
|
await collected.delete();
|
||||||
|
await prompt.delete();
|
||||||
|
await editorMessage.edit({
|
||||||
|
components: [await renderPreview(blockState, message.member, message.guild), ...btns(false)]
|
||||||
|
});
|
||||||
|
});
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case "edit_description": {
|
||||||
|
const prompt = await message.channel.send("Escribe la nueva **descripción**.");
|
||||||
|
const mc = message.channel.createMessageCollector({
|
||||||
|
filter: (m) => m.author.id === message.author.id,
|
||||||
|
max: 1,
|
||||||
|
time: 60000
|
||||||
|
});
|
||||||
|
mc.on("collect", async (collected) => {
|
||||||
|
const descComp = blockState.components.find((c: any) => c.type === 10);
|
||||||
|
if (descComp) descComp.content = collected.content;
|
||||||
|
await collected.delete();
|
||||||
|
await prompt.delete();
|
||||||
|
await editorMessage.edit({
|
||||||
|
components: [await renderPreview(blockState, message.member, message.guild), ...btns(false)]
|
||||||
|
});
|
||||||
|
});
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case "edit_color": {
|
||||||
|
const prompt = await message.channel.send("Escribe el nuevo **color** en HEX (#RRGGBB).");
|
||||||
|
const mc = message.channel.createMessageCollector({
|
||||||
|
filter: (m) => m.author.id === message.author.id,
|
||||||
|
max: 1,
|
||||||
|
time: 60000
|
||||||
|
});
|
||||||
|
mc.on("collect", async (collected) => {
|
||||||
|
const newValue = collected.content;
|
||||||
|
let parsed: number | null = null;
|
||||||
|
if (/^#?[0-9A-Fa-f]{6}$/.test(newValue)) {
|
||||||
|
parsed = parseInt(newValue.replace("#", ""), 16);
|
||||||
|
}
|
||||||
|
blockState.color = parsed;
|
||||||
|
await collected.delete();
|
||||||
|
await prompt.delete();
|
||||||
|
await editorMessage.edit({
|
||||||
|
components: [await renderPreview(blockState, message.member, message.guild), ...btns(false)]
|
||||||
|
});
|
||||||
|
});
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case "add_content": {
|
||||||
|
const prompt = await message.channel.send("Escribe el nuevo **contenido**.");
|
||||||
|
const mc = message.channel.createMessageCollector({
|
||||||
|
filter: (m) => m.author.id === message.author.id,
|
||||||
|
max: 1,
|
||||||
|
time: 60000
|
||||||
|
});
|
||||||
|
mc.on("collect", async (collected) => {
|
||||||
|
blockState.components.push({ type: 10, content: collected.content, thumbnail: null });
|
||||||
|
await collected.delete();
|
||||||
|
await prompt.delete();
|
||||||
|
await editorMessage.edit({
|
||||||
|
components: [await renderPreview(blockState, message.member, message.guild), ...btns(false)]
|
||||||
|
});
|
||||||
|
});
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case "add_separator": {
|
||||||
|
//@ts-ignore
|
||||||
|
const reply = await i.followUp({
|
||||||
|
ephemeral: true,
|
||||||
|
content: "¿El separador debe ser visible?",
|
||||||
|
components: [
|
||||||
|
{
|
||||||
|
type: 1,
|
||||||
|
components: [
|
||||||
|
{ type: 2, style: ButtonStyle.Success, label: "✅ Visible", custom_id: "separator_visible" },
|
||||||
|
{ type: 2, style: ButtonStyle.Secondary, label: "❌ Invisible", custom_id: "separator_invisible" }
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
fetchReply: true
|
||||||
|
});
|
||||||
|
|
||||||
|
//@ts-ignore
|
||||||
|
const sepCollector = reply.createMessageComponentCollector({
|
||||||
|
componentType: ComponentType.Button,
|
||||||
|
max: 1,
|
||||||
|
time: 60000,
|
||||||
|
filter: (b: any) => b.user.id === message.author.id
|
||||||
|
});
|
||||||
|
|
||||||
|
sepCollector.on("collect", async (b: any) => {
|
||||||
|
const isVisible = b.customId === "separator_visible";
|
||||||
|
blockState.components.push({ type: 14, divider: isVisible, spacing: 1 });
|
||||||
|
|
||||||
|
await b.update({
|
||||||
|
content: `✅ Separador ${isVisible ? 'visible' : 'invisible'} añadido.`,
|
||||||
|
components: []
|
||||||
|
});
|
||||||
|
|
||||||
|
await editorMessage.edit({
|
||||||
|
components: [await renderPreview(blockState, message.member, message.guild), ...btns(false)]
|
||||||
|
});
|
||||||
|
|
||||||
|
sepCollector.stop();
|
||||||
|
});
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case "add_image": {
|
||||||
|
const prompt = await message.channel.send("Escribe la **URL de la imagen**.");
|
||||||
|
const mc = message.channel.createMessageCollector({
|
||||||
|
filter: (m) => m.author.id === message.author.id,
|
||||||
|
max: 1,
|
||||||
|
time: 60000
|
||||||
|
});
|
||||||
|
mc.on("collect", async (collected) => {
|
||||||
|
blockState.components.push({ type: 12, url: collected.content });
|
||||||
|
await collected.delete();
|
||||||
|
await prompt.delete();
|
||||||
|
await editorMessage.edit({
|
||||||
|
components: [await renderPreview(blockState, message.member, message.guild), ...btns(false)]
|
||||||
|
});
|
||||||
|
});
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case "cover_image": {
|
||||||
|
if (blockState.coverImage) {
|
||||||
|
// Si ya tiene portada, preguntar si editar o eliminar
|
||||||
|
//@ts-ignore
|
||||||
|
const reply = await i.followUp({
|
||||||
|
ephemeral: true,
|
||||||
|
content: "Ya tienes una imagen de portada. ¿Qué quieres hacer?",
|
||||||
|
components: [
|
||||||
|
{
|
||||||
|
type: 1,
|
||||||
|
components: [
|
||||||
|
{ type: 2, style: ButtonStyle.Primary, label: "✏️ Editar", custom_id: "edit_cover" },
|
||||||
|
{ type: 2, style: ButtonStyle.Danger, label: "🗑️ Eliminar", custom_id: "delete_cover" }
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
fetchReply: true
|
||||||
|
});
|
||||||
|
|
||||||
|
//@ts-ignore
|
||||||
|
const coverCollector = reply.createMessageComponentCollector({
|
||||||
|
componentType: ComponentType.Button,
|
||||||
|
max: 1,
|
||||||
|
time: 60000,
|
||||||
|
filter: (b: any) => b.user.id === message.author.id
|
||||||
|
});
|
||||||
|
|
||||||
|
coverCollector.on("collect", async (b: any) => {
|
||||||
|
if (b.customId === "edit_cover") {
|
||||||
|
await b.update({ content: "Escribe la nueva **URL de la imagen de portada**:", components: [] });
|
||||||
|
|
||||||
|
const prompt = await message.channel.send("Nueva URL de portada:");
|
||||||
|
const mc = message.channel.createMessageCollector({
|
||||||
|
filter: (m) => m.author.id === message.author.id,
|
||||||
|
max: 1,
|
||||||
|
time: 60000
|
||||||
|
});
|
||||||
|
|
||||||
|
mc.on("collect", async (collected) => {
|
||||||
|
blockState.coverImage = collected.content;
|
||||||
|
await collected.delete();
|
||||||
|
await prompt.delete();
|
||||||
|
await editorMessage.edit({
|
||||||
|
components: [await renderPreview(blockState, message.member, message.guild), ...btns(false)]
|
||||||
|
});
|
||||||
|
});
|
||||||
|
} else if (b.customId === "delete_cover") {
|
||||||
|
blockState.coverImage = null;
|
||||||
|
await b.update({ content: "✅ Imagen de portada eliminada.", components: [] });
|
||||||
|
await editorMessage.edit({
|
||||||
|
components: [await renderPreview(blockState, message.member, message.guild), ...btns(false)]
|
||||||
|
});
|
||||||
|
}
|
||||||
|
coverCollector.stop();
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
// No tiene portada, añadir nueva
|
||||||
|
const prompt = await message.channel.send("Escribe la **URL de la imagen de portada**.");
|
||||||
|
const mc = message.channel.createMessageCollector({
|
||||||
|
filter: (m) => m.author.id === message.author.id,
|
||||||
|
max: 1,
|
||||||
|
time: 60000
|
||||||
|
});
|
||||||
|
mc.on("collect", async (collected) => {
|
||||||
|
blockState.coverImage = collected.content;
|
||||||
|
await collected.delete();
|
||||||
|
await prompt.delete();
|
||||||
|
await editorMessage.edit({
|
||||||
|
components: [await renderPreview(blockState, message.member, message.guild), ...btns(false)]
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case "edit_thumbnail": {
|
||||||
|
// Buscar componentes de texto para seleccionar cuál editar
|
||||||
|
const textComponents = blockState.components
|
||||||
|
.map((c: any, idx: number) => ({ component: c, index: idx }))
|
||||||
|
.filter(({ component }) => component.type === 10);
|
||||||
|
|
||||||
|
if (textComponents.length === 0) {
|
||||||
|
//@ts-ignore
|
||||||
|
await i.followUp({
|
||||||
|
content: "❌ No hay componentes de texto para añadir thumbnail.",
|
||||||
|
ephemeral: true
|
||||||
|
});
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (textComponents.length === 1) {
|
||||||
|
// Solo un componente de texto, editarlo directamente
|
||||||
|
const prompt = await message.channel.send("Escribe la **URL del thumbnail**.");
|
||||||
|
const mc = message.channel.createMessageCollector({
|
||||||
|
filter: (m) => m.author.id === message.author.id,
|
||||||
|
max: 1,
|
||||||
|
time: 60000
|
||||||
|
});
|
||||||
|
mc.on("collect", async (collected) => {
|
||||||
|
textComponents[0].component.thumbnail = collected.content;
|
||||||
|
await collected.delete();
|
||||||
|
await prompt.delete();
|
||||||
|
await editorMessage.edit({
|
||||||
|
components: [await renderPreview(blockState, message.member, message.guild), ...btns(false)]
|
||||||
|
});
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
// Múltiples componentes de texto, mostrar selector
|
||||||
|
const options = textComponents.map(({ component, index }) => ({
|
||||||
|
label: `Texto: ${component.content?.slice(0, 30) || "..."}`,
|
||||||
|
value: index.toString(),
|
||||||
|
description: component.thumbnail ? "Ya tiene thumbnail" : "Sin thumbnail"
|
||||||
|
}));
|
||||||
|
|
||||||
|
//@ts-ignore
|
||||||
|
const reply = await i.followUp({
|
||||||
|
ephemeral: true,
|
||||||
|
content: "Selecciona el texto al que quieres añadir/editar thumbnail:",
|
||||||
|
components: [
|
||||||
|
{
|
||||||
|
type: 1,
|
||||||
|
components: [
|
||||||
|
{
|
||||||
|
type: 3,
|
||||||
|
custom_id: "select_text_for_thumbnail",
|
||||||
|
placeholder: "Elige un texto",
|
||||||
|
options
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
fetchReply: true
|
||||||
|
});
|
||||||
|
|
||||||
|
//@ts-ignore
|
||||||
|
const selCollector = reply.createMessageComponentCollector({
|
||||||
|
componentType: ComponentType.StringSelect,
|
||||||
|
max: 1,
|
||||||
|
time: 60000,
|
||||||
|
filter: (sel: any) => sel.user.id === message.author.id
|
||||||
|
});
|
||||||
|
|
||||||
|
selCollector.on("collect", async (sel: any) => {
|
||||||
|
const selectedIndex = parseInt(sel.values[0]);
|
||||||
|
|
||||||
|
await sel.update({
|
||||||
|
content: "Escribe la **URL del thumbnail**:",
|
||||||
|
components: []
|
||||||
|
});
|
||||||
|
|
||||||
|
const prompt = await message.channel.send("URL del thumbnail:");
|
||||||
|
const mc = message.channel.createMessageCollector({
|
||||||
|
filter: (m) => m.author.id === message.author.id,
|
||||||
|
max: 1,
|
||||||
|
time: 60000
|
||||||
|
});
|
||||||
|
|
||||||
|
mc.on("collect", async (collected) => {
|
||||||
|
blockState.components[selectedIndex].thumbnail = collected.content;
|
||||||
|
await collected.delete();
|
||||||
|
await prompt.delete();
|
||||||
|
await editorMessage.edit({
|
||||||
|
components: [await renderPreview(blockState, message.member, message.guild), ...btns(false)]
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case "move_block": {
|
||||||
|
const options = blockState.components.map((c: any, idx: number) => ({
|
||||||
|
label:
|
||||||
|
c.type === 10
|
||||||
|
? `Texto: ${c.content?.slice(0, 30) || "..."}`
|
||||||
|
: c.type === 14
|
||||||
|
? `Separador ${c.divider ? '(Visible)' : '(Invisible)'}`
|
||||||
|
: c.type === 12
|
||||||
|
? `Imagen: ${c.url?.slice(-30) || "..."}`
|
||||||
|
: `Componente ${c.type}`,
|
||||||
|
value: idx.toString(),
|
||||||
|
description:
|
||||||
|
c.type === 10 && c.thumbnail
|
||||||
|
? "Con thumbnail"
|
||||||
|
: undefined
|
||||||
|
}));
|
||||||
|
|
||||||
|
//@ts-ignore
|
||||||
|
const reply = await i.followUp({
|
||||||
|
ephemeral: true,
|
||||||
|
content: "Selecciona el bloque que quieres mover:",
|
||||||
|
components: [
|
||||||
|
{
|
||||||
|
type: 1,
|
||||||
|
components: [
|
||||||
|
{ type: 3, custom_id: "move_block_select", placeholder: "Elige un bloque", options }
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
fetchReply: true
|
||||||
|
});
|
||||||
|
|
||||||
|
//@ts-ignore
|
||||||
|
const selCollector = reply.createMessageComponentCollector({
|
||||||
|
componentType: ComponentType.StringSelect,
|
||||||
|
max: 1,
|
||||||
|
time: 60000,
|
||||||
|
filter: (it: any) => it.user.id === message.author.id
|
||||||
|
});
|
||||||
|
|
||||||
|
selCollector.on("collect", async (sel: any) => {
|
||||||
|
const idx = parseInt(sel.values[0]);
|
||||||
|
|
||||||
|
await sel.update({
|
||||||
|
content: "¿Quieres mover este bloque?",
|
||||||
|
components: [
|
||||||
|
{
|
||||||
|
type: 1,
|
||||||
|
components: [
|
||||||
|
{ type: 2, style: ButtonStyle.Secondary, label: "⬆️ Subir", custom_id: `move_up_${idx}`, disabled: idx === 0 },
|
||||||
|
{ type: 2, style: ButtonStyle.Secondary, label: "⬇️ Bajar", custom_id: `move_down_${idx}`, disabled: idx === blockState.components.length - 1 }
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
});
|
||||||
|
|
||||||
|
//@ts-ignore
|
||||||
|
const btnCollector = reply.createMessageComponentCollector({
|
||||||
|
componentType: ComponentType.Button,
|
||||||
|
max: 1,
|
||||||
|
time: 60000,
|
||||||
|
filter: (b: any) => b.user.id === message.author.id
|
||||||
|
});
|
||||||
|
|
||||||
|
btnCollector.on("collect", async (b: any) => {
|
||||||
|
if (b.customId.startsWith("move_up_")) {
|
||||||
|
const i2 = parseInt(b.customId.replace("move_up_", ""));
|
||||||
|
if (i2 > 0) {
|
||||||
|
const item = blockState.components[i2];
|
||||||
|
blockState.components.splice(i2, 1);
|
||||||
|
blockState.components.splice(i2 - 1, 0, item);
|
||||||
|
}
|
||||||
|
await b.update({ content: "✅ Bloque movido arriba.", components: [] });
|
||||||
|
} else if (b.customId.startsWith("move_down_")) {
|
||||||
|
const i2 = parseInt(b.customId.replace("move_down_", ""));
|
||||||
|
if (i2 < blockState.components.length - 1) {
|
||||||
|
const item = blockState.components[i2];
|
||||||
|
blockState.components.splice(i2, 1);
|
||||||
|
blockState.components.splice(i2 + 1, 0, item);
|
||||||
|
}
|
||||||
|
await b.update({ content: "✅ Bloque movido abajo.", components: [] });
|
||||||
|
}
|
||||||
|
|
||||||
|
await editorMessage.edit({
|
||||||
|
components: [await renderPreview(blockState, message.member, message.guild), ...btns(false)]
|
||||||
|
});
|
||||||
|
|
||||||
|
btnCollector.stop();
|
||||||
|
selCollector.stop();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case "delete_block": {
|
||||||
|
// Incluir portada en las opciones si existe
|
||||||
|
const options = [];
|
||||||
|
|
||||||
|
// Añadir portada como opción si existe
|
||||||
|
if (blockState.coverImage) {
|
||||||
|
options.push({
|
||||||
|
label: "🖼️ Imagen de Portada",
|
||||||
|
value: "cover_image",
|
||||||
|
description: "Imagen principal del bloque"
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Añadir componentes regulares
|
||||||
|
blockState.components.forEach((c: any, idx: number) => {
|
||||||
|
options.push({
|
||||||
|
label:
|
||||||
|
c.type === 10
|
||||||
|
? `Texto: ${c.content?.slice(0, 30) || "..."}`
|
||||||
|
: c.type === 14
|
||||||
|
? `Separador ${c.divider ? '(Visible)' : '(Invisible)'}`
|
||||||
|
: c.type === 12
|
||||||
|
? `Imagen: ${c.url?.slice(-30) || "..."}`
|
||||||
|
: `Componente ${c.type}`,
|
||||||
|
value: idx.toString(),
|
||||||
|
description:
|
||||||
|
c.type === 10 && c.thumbnail
|
||||||
|
? "Con thumbnail"
|
||||||
|
: undefined
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
if (options.length === 0) {
|
||||||
|
//@ts-ignore
|
||||||
|
await i.followUp({
|
||||||
|
content: "❌ No hay elementos para eliminar.",
|
||||||
|
ephemeral: true
|
||||||
|
});
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
//@ts-ignore
|
||||||
|
const reply = await i.followUp({
|
||||||
|
ephemeral: true,
|
||||||
|
content: "Selecciona el elemento que quieres eliminar:",
|
||||||
|
components: [
|
||||||
|
{
|
||||||
|
type: 1,
|
||||||
|
components: [
|
||||||
|
{ type: 3, custom_id: "delete_block_select", placeholder: "Elige un elemento", options }
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
fetchReply: true
|
||||||
|
});
|
||||||
|
|
||||||
|
//@ts-ignore
|
||||||
|
const selCollector = reply.createMessageComponentCollector({
|
||||||
|
componentType: ComponentType.StringSelect,
|
||||||
|
max: 1,
|
||||||
|
time: 60000,
|
||||||
|
filter: (it: any) => it.user.id === message.author.id
|
||||||
|
});
|
||||||
|
|
||||||
|
selCollector.on("collect", async (sel: any) => {
|
||||||
|
const selectedValue = sel.values[0];
|
||||||
|
|
||||||
|
if (selectedValue === "cover_image") {
|
||||||
|
blockState.coverImage = null;
|
||||||
|
await sel.update({ content: "✅ Imagen de portada eliminada.", components: [] });
|
||||||
|
} else {
|
||||||
|
const idx = parseInt(selectedValue);
|
||||||
|
blockState.components.splice(idx, 1);
|
||||||
|
await sel.update({ content: "✅ Elemento eliminado.", components: [] });
|
||||||
|
}
|
||||||
|
|
||||||
|
await editorMessage.edit({
|
||||||
|
components: [await renderPreview(blockState, message.member, message.guild), ...btns(false)]
|
||||||
|
});
|
||||||
|
|
||||||
|
selCollector.stop();
|
||||||
|
});
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
await editorMessage.edit({
|
||||||
|
components: [await renderPreview(blockState, message.member, message.guild), ...btns(false)]
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
//@ts-ignore
|
||||||
|
collector.on("end", async (_, reason) => {
|
||||||
|
if (reason === "time") {
|
||||||
|
await editorMessage.edit({
|
||||||
|
components: [
|
||||||
|
{ type: 17, components: [{ type: 10, content: "⏰ Editor finalizado por inactividad." }] }
|
||||||
|
]
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
@@ -17,7 +17,7 @@ export const command: CommandMessage = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await client.prisma.embedConfig.delete({
|
await client.prisma.blockV2Config.delete({
|
||||||
where: {
|
where: {
|
||||||
guildId_name: {
|
guildId_name: {
|
||||||
guildId: message.guildId!,
|
guildId: message.guildId!,
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ export const command: CommandMessage = {
|
|||||||
return message.reply("❌ No tienes permisos de Administrador.");
|
return message.reply("❌ No tienes permisos de Administrador.");
|
||||||
}
|
}
|
||||||
|
|
||||||
const embeds = await client.prisma.embedConfig.findMany({
|
const embeds = await client.prisma.blockV2Config.findMany({
|
||||||
where: { guildId: message.guildId! },
|
where: { guildId: message.guildId! },
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -1,12 +1,20 @@
|
|||||||
import {Guild, User} from "discord.js";
|
import {Guild, User} from "discord.js";
|
||||||
|
|
||||||
export async function replaceVars(text: string, user: User | undefined, guild:
|
export async function replaceVars(text: string, user: User | undefined, guild: Guild | undefined, stats?: any): Promise<string> {
|
||||||
Guild | undefined, stats: any) {
|
if(!text) return '';
|
||||||
if(!text) return;
|
|
||||||
|
|
||||||
return text
|
return text
|
||||||
.replace(/(user.name)/g, user!.username ?? '')
|
/**
|
||||||
.replace(/(user.id)/g, user!.id ?? '')
|
* USER INFO
|
||||||
.replace(/(user.mention)/g, `<@${user!.id}>`)
|
*/
|
||||||
.replace(/(user.avatar)/g, user!.displayAvatarURL({ forceStatic: false }))
|
.replace(/(user\.name)/g, user?.username ?? '')
|
||||||
|
.replace(/(user\.id)/g, user?.id ?? '')
|
||||||
|
.replace(/(user\.mention)/g, user ? `<@${user.id}>` : '')
|
||||||
|
.replace(/(user\.avatar)/g, user?.displayAvatarURL({ forceStatic: false }) ?? '')
|
||||||
|
|
||||||
|
/**
|
||||||
|
* GUILD INFO
|
||||||
|
*/
|
||||||
|
.replace(/(guild\.name)/g, guild?.name ?? '')
|
||||||
|
.replace(/(guild\.icon)/g, guild?.iconURL({ forceStatic: false }) ?? '');
|
||||||
}
|
}
|
||||||
0
src/events/extras/alliace.ts
Normal file
0
src/events/extras/alliace.ts
Normal file
@@ -6,8 +6,17 @@ import {commands} from "../core/loader";
|
|||||||
|
|
||||||
bot.on(Events.MessageCreate, async (message) => {
|
bot.on(Events.MessageCreate, async (message) => {
|
||||||
if (message.author.bot) return;
|
if (message.author.bot) return;
|
||||||
const server = await bot.prisma.guild.findFirst({ where: { id: message.guild!.id } }) || "!";
|
const server = await bot.prisma.guild.upsert({
|
||||||
const PREFIX = server.prefix
|
where: {
|
||||||
|
id: message.guildId
|
||||||
|
},
|
||||||
|
create: {
|
||||||
|
id: message.guildId,
|
||||||
|
name: message.guild!.name
|
||||||
|
},
|
||||||
|
update: {}
|
||||||
|
})
|
||||||
|
const PREFIX = server.prefix || "!"
|
||||||
if (!message.content.startsWith(PREFIX)) return;
|
if (!message.content.startsWith(PREFIX)) return;
|
||||||
|
|
||||||
const [cmdName, ...args] = message.content.slice(PREFIX.length).trim().split(/\s+/);
|
const [cmdName, ...args] = message.content.slice(PREFIX.length).trim().split(/\s+/);
|
||||||
|
|||||||
Reference in New Issue
Block a user