djs-builder 0.5.41 → 0.5.42

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,323 +1,374 @@
1
1
  import {
2
- ButtonBuilder,
3
- ActionRowBuilder,
4
- EmbedBuilder,
5
- Message,
6
- MessageComponentInteraction,
7
- MessageActionRowComponentBuilder,
8
- ButtonStyle,
9
- StringSelectMenuBuilder,
10
- } from "discord.js";
11
-
12
- interface PagerOptions {
13
- firstLast?: boolean;
14
- deleteOption?: boolean;
15
- otherComponents?: ActionRowBuilder<MessageActionRowComponentBuilder>[];
16
- home?: {
17
- home_Option?: boolean;
18
- home_page?: number;
19
- };
20
- timeOption?: {
21
- timeOut?: number;
22
- disable?: boolean;
23
- deletes?: boolean;
24
- custom?: (() => void);
25
- };
26
- user_only?: {
27
- user_status?: boolean;
28
- reply?: string;
29
- };
30
- style?: {
31
- nextAndBack?: ButtonStyle;
32
- firstAndLast?: ButtonStyle;
33
- homeStyle?: ButtonStyle;
34
- deleteStyle?: ButtonStyle;
35
- };
36
- label?: {
37
- labelNext?: string | null;
38
- labelBack?: string | null;
39
- labelFirst?: string | null;
40
- labelLast?: string | null;
41
- labelHome?: string | null;
42
- labelDelete?: string | null;
43
- };
44
- emoji?: {
45
- emojiNext?: string;
46
- emojiBack?: string;
47
- emojiFirst?: string;
48
- emojiLast?: string;
49
- emojiHome?: string;
50
- emojiDelete?: string;
51
- };
52
- pages?: {
53
- embeds?: EmbedBuilder[];
54
- attachment?: (string | Buffer)[];
55
- content?: string[];
56
- };
57
- navigationMenu?: {
58
- enabled?: boolean;
59
- placeHolder?: string;
60
- selects?: string[];
61
- };
62
- }
63
-
64
- const CUSTOM_IDS = {
65
- NEXT: "next-discobase",
66
- BACK: "back-discobase",
67
- FIRST: "first-discobase",
68
- LAST: "last-discobase",
69
- DELETE: "delete-discobase",
70
- HOME: "home-discobase",
71
- SELECT: "select-discobase"
2
+ ButtonBuilder,
3
+ ActionRowBuilder,
4
+ EmbedBuilder,
5
+ Message,
6
+ MessageComponentInteraction,
7
+ MessageActionRowComponentBuilder,
8
+ ButtonStyle,
9
+ StringSelectMenuBuilder,
10
+ } from "discord.js";
11
+
12
+ interface PagerOptions {
13
+ firstLast?: boolean;
14
+ deleteOption?: boolean;
15
+ otherComponents?: ActionRowBuilder<MessageActionRowComponentBuilder>[];
16
+ home?: {
17
+ home_Option?: boolean;
18
+ home_page?: number;
72
19
  };
73
-
74
- const VALID_BUTTON_STYLES = [
75
- ButtonStyle.Primary,
76
- ButtonStyle.Secondary,
77
- ButtonStyle.Success,
78
- ButtonStyle.Danger
79
- ];
80
-
81
- const isValidEmoji = (emoji: string | undefined): boolean => {
82
- if (!emoji) return false;
83
- const unicodeEmojiPattern = /^[\u{1F600}-\u{1F64F}\u{1F300}-\u{1F5FF}\u{1F680}-\u{1F6FF}\u{1F700}-\u{1F77F}\u{1F780}-\u{1F7FF}\u{1F800}-\u{1F8FF}\u{1F900}-\u{1F9FF}\u{1FA00}-\u{1FA6F}\u{1FA70}-\u{1FAFF}\u{2600}-\u{26FF}\u{2700}-\u{27BF}\u{2300}-\u{23FF}\u{2B50}\u{2934}\u{2935}\u{3030}]+$/u;
84
- return unicodeEmojiPattern.test(emoji) || /^\d+$/.test(emoji);
20
+ timeOption?: {
21
+ timeOut?: number;
22
+ disable?: boolean;
23
+ deletes?: boolean;
24
+ custom?: (() => void);
85
25
  };
26
+ user_only?: {
27
+ user_status?: boolean;
28
+ reply?: string;
29
+ };
30
+ style?: {
31
+ nextAndBack?: ButtonStyle;
32
+ firstAndLast?: ButtonStyle;
33
+ homeStyle?: ButtonStyle;
34
+ deleteStyle?: ButtonStyle;
35
+ };
36
+ label?: {
37
+ labelNext?: string | null;
38
+ labelBack?: string | null;
39
+ labelFirst?: string | null;
40
+ labelLast?: string | null;
41
+ labelHome?: string | null;
42
+ labelDelete?: string | null;
43
+ };
44
+ emoji?: {
45
+ emojiNext?: string;
46
+ emojiBack?: string;
47
+ emojiFirst?: string;
48
+ emojiLast?: string;
49
+ emojiHome?: string;
50
+ emojiDelete?: string;
51
+ };
52
+ pages?: {
53
+ embeds?: EmbedBuilder[];
54
+ attachment?: (string | Buffer)[];
55
+ content?: string[];
56
+ };
57
+ navigationMenu?: {
58
+ enabled?: boolean;
59
+ placeHolder?: string;
60
+ selects?: string[];
61
+ };
62
+ }
63
+
64
+ const CUSTOM_IDS = {
65
+ NEXT: "next-discobase",
66
+ BACK: "back-discobase",
67
+ FIRST: "first-discobase",
68
+ LAST: "last-discobase",
69
+ DELETE: "delete-discobase",
70
+ HOME: "home-discobase",
71
+ SELECT: "select-discobase"
72
+ };
73
+
74
+ const VALID_BUTTON_STYLES = [
75
+ ButtonStyle.Primary,
76
+ ButtonStyle.Secondary,
77
+ ButtonStyle.Success,
78
+ ButtonStyle.Danger
79
+ ];
80
+
81
+ const isValidEmoji = (emoji: string | undefined): boolean => {
82
+ if (!emoji) return true; // No emoji is valid.
86
83
 
87
- export class Pagination {
88
- private message: Message;
89
- private options: Required<PagerOptions>;
90
- private buttons: ButtonBuilder[];
91
- private components: ActionRowBuilder<MessageActionRowComponentBuilder>[];
92
- private naw_page: number = 0;
93
-
94
- constructor(message: Message, options: PagerOptions) {
95
- this.message = message;
96
- this.options = {
97
- firstLast: false,
98
- deleteOption: false,
99
- otherComponents: [],
100
- home: { home_Option: false, home_page: 0 },
101
- timeOption: { timeOut: 86400000, disable: false, deletes: false, custom: undefined },
102
- user_only: { user_status: false, reply: "You are not the command owner" },
103
- style: { nextAndBack: ButtonStyle.Primary, firstAndLast: ButtonStyle.Secondary, homeStyle: ButtonStyle.Success, deleteStyle: ButtonStyle.Danger },
104
- label: {},
105
- emoji: { emojiNext: "➡", emojiBack: "⬅", emojiFirst: "⏪", emojiLast: "⏩", emojiHome: "🏠", emojiDelete: "🗑" },
106
- pages: { embeds: [], attachment: [], content: [] },
107
- navigationMenu: { enabled: false, placeHolder: "Choose a page", selects: [] },
108
- ...options,
109
- };
110
-
111
- this.validateOptions();
112
- this.buttons = this.createButtons();
113
- this.components = this.createComponents();
114
- }
115
- private validateOptions() {
116
- const { emoji } = this.options;
117
- if (!Object.values(emoji).every(isValidEmoji)) {
118
- throw new Error("Invalid emoji format. Must be either Unicode emojis or valid emoji IDs.");
119
- }
120
-
121
- const { style } = this.options;
122
- if (!Object.values(style).every(style => VALID_BUTTON_STYLES.includes(style))) {
123
- throw new Error("Invalid button style. Must be one of the predefined ButtonStyle values.");
124
- }
125
-
126
- if (this.options.deleteOption && this.options.home?.home_Option) {
127
- throw new Error("You can't use 'home' and 'delete' together.");
128
- }
129
-
130
- if (this.options.timeOption?.disable && this.options.timeOption?.deletes) {
131
- throw new Error("You can't use 'disable' and 'deletes' together.");
132
- }
84
+ const unicodeEmojiPattern = /[\u{1F600}-\u{1F64F}\u{1F300}-\u{1F5FF}\u{1F680}-\u{1F6FF}\u{1F700}-\u{1F77F}\u{1F780}-\u{1F7FF}\u{1F800}-\u{1F8FF}\u{1F900}-\u{1F9FF}\u{1FA00}-\u{1FA6F}\u{1FA70}-\u{1FAFF}\u{2600}-\u{26FF}\u{2700}-\u{27BF}\u{2300}-\u{23FF}\u{2B50}\u{2934}\u{2935}\u{3030}\u{20E3}\u{FE0F}]/u;
85
+ const discordCustomEmojiPattern = /^<:[a-zA-Z0-9_]+:[0-9]+>$/;
86
+ return unicodeEmojiPattern.test(emoji) || discordCustomEmojiPattern.test(emoji);
87
+ };
88
+
89
+ export class Pagination {
90
+ private message: Message;
91
+ private options: Required<PagerOptions>;
92
+ private buttons: ButtonBuilder[];
93
+ private components: ActionRowBuilder<MessageActionRowComponentBuilder>[];
94
+ private naw_page: number = 0;
95
+
96
+ constructor(message: Message, options: PagerOptions) {
97
+ this.message = message;
98
+ this.options = {
99
+ firstLast: false,
100
+ deleteOption: false,
101
+ otherComponents: [],
102
+ home: { home_Option: false, home_page: 0 },
103
+ timeOption: { timeOut: 86400000, disable: false, deletes: false, custom: undefined },
104
+ user_only: { user_status: false, reply: "You are not the command owner" },
105
+ style: { nextAndBack: ButtonStyle.Primary, firstAndLast: ButtonStyle.Secondary, homeStyle: ButtonStyle.Success, deleteStyle: ButtonStyle.Danger },
106
+ label: {},
107
+ emoji: { emojiNext: "➡️", emojiBack: "⬅️", emojiFirst: "⏪", emojiLast: "⏩", emojiHome: "🏠", emojiDelete: "🗑️" },
108
+ pages: { embeds: [], attachment: [], content: [] },
109
+ navigationMenu: { enabled: false, placeHolder: "Choose a page", selects: [] },
110
+ ...options,
111
+ };
112
+
113
+ this.validateOptions();
114
+ this.buttons = this.createButtons();
115
+ this.components = this.createComponents();
116
+ }
117
+
118
+ private validateOptions() {
119
+ const { emoji } = this.options;
120
+ const emojiValues = Object.values(emoji);
121
+
122
+ if (emojiValues.some(e => e && !isValidEmoji(e))) {
123
+ throw new Error("Invalid emoji format. Must be Unicode emojis, valid emoji IDs, or empty.");
133
124
  }
134
-
135
- private createButtons(): ButtonBuilder[] {
136
- const {
125
+
126
+ const { style } = this.options;
127
+ if (!Object.values(style).every(style => VALID_BUTTON_STYLES.includes(style))) {
128
+ throw new Error("Invalid button style. Must be one of the predefined ButtonStyle values.");
129
+ }
130
+
131
+ if (this.options.deleteOption && this.options.home?.home_Option) {
132
+ throw new Error("You can't use 'home' and 'delete' together.");
133
+ }
134
+
135
+ if (this.options.timeOption?.disable && this.options.timeOption?.deletes) {
136
+ throw new Error("You can't use 'disable' and 'deletes' together.");
137
+ }
138
+ }
139
+
140
+ private createButtons(): ButtonBuilder[] {
141
+ const {
137
142
  nextAndBack,
138
143
  firstAndLast,
139
144
  homeStyle,
140
145
  deleteStyle,
141
- } = this.options.style;
142
-
143
- const {
146
+ } = this.options.style;
147
+
148
+ const {
144
149
  emojiNext,
145
150
  emojiBack,
146
151
  emojiFirst,
147
152
  emojiLast,
148
153
  emojiHome,
149
154
  emojiDelete,
150
- } = this.options.emoji;
151
-
152
- const next = new ButtonBuilder().setCustomId(CUSTOM_IDS.NEXT).setEmoji(emojiNext!).setStyle(nextAndBack!);
153
- const back = new ButtonBuilder().setCustomId(CUSTOM_IDS.BACK).setEmoji(emojiBack!).setStyle(nextAndBack!);
154
- const first = new ButtonBuilder().setCustomId(CUSTOM_IDS.FIRST).setEmoji(emojiFirst!).setStyle(firstAndLast!);
155
- const last = new ButtonBuilder().setCustomId(CUSTOM_IDS.LAST).setEmoji(emojiLast!).setStyle(firstAndLast!);
156
- const home = new ButtonBuilder().setCustomId(CUSTOM_IDS.HOME).setEmoji(emojiHome!).setStyle(homeStyle!);
157
- const deleteBtn = new ButtonBuilder().setCustomId(CUSTOM_IDS.DELETE).setEmoji(emojiDelete!).setStyle(deleteStyle!);
158
-
159
- const {
155
+ } = this.options.emoji;
156
+
157
+ const next = new ButtonBuilder().setCustomId(CUSTOM_IDS.NEXT).setStyle(nextAndBack!);
158
+ if (emojiNext) next.setEmoji(emojiNext);
159
+
160
+ const back = new ButtonBuilder().setCustomId(CUSTOM_IDS.BACK).setStyle(nextAndBack!);
161
+ if (emojiBack) back.setEmoji(emojiBack);
162
+
163
+ const first = new ButtonBuilder().setCustomId(CUSTOM_IDS.FIRST).setStyle(firstAndLast!);
164
+ if (emojiFirst) first.setEmoji(emojiFirst);
165
+
166
+ const last = new ButtonBuilder().setCustomId(CUSTOM_IDS.LAST).setStyle(firstAndLast!);
167
+ if (emojiLast) last.setEmoji(emojiLast);
168
+
169
+ const home = new ButtonBuilder().setCustomId(CUSTOM_IDS.HOME).setStyle(homeStyle!);
170
+ if (emojiHome) home.setEmoji(emojiHome);
171
+
172
+ const deleteBtn = new ButtonBuilder().setCustomId(CUSTOM_IDS.DELETE).setStyle(deleteStyle!);
173
+ if (emojiDelete) deleteBtn.setEmoji(emojiDelete);
174
+
175
+ const {
160
176
  labelNext,
161
177
  labelBack,
162
178
  labelFirst,
163
179
  labelLast,
164
180
  labelHome,
165
181
  labelDelete,
166
- } = this.options.label;
167
-
168
- if (labelNext) next.setLabel(labelNext);
169
- if (labelBack) back.setLabel(labelBack);
170
- if (labelFirst) first.setLabel(labelFirst);
171
- if (labelLast) last.setLabel(labelLast);
172
- if (labelHome) home.setLabel(labelHome);
173
- if (labelDelete) deleteBtn.setLabel(labelDelete);
182
+ } = this.options.label;
183
+
184
+ if (labelNext) next.setLabel(labelNext);
185
+ if (labelBack) back.setLabel(labelBack);
186
+ if (labelFirst) first.setLabel(labelFirst);
187
+ if (labelLast) last.setLabel(labelLast);
188
+ if (labelHome) home.setLabel(labelHome);
189
+ if (labelDelete) deleteBtn.setLabel(labelDelete);
190
+
191
+ const buttons: ButtonBuilder[] = [];
192
+
193
+ if (this.options.firstLast) {
194
+ buttons.push(first);
195
+ }
196
+
197
+ buttons.push(back);
198
+
199
+ if (this.options.home?.home_Option) {
200
+ buttons.push(home);
201
+ if (this.options.firstLast) {
202
+ buttons.push(next);
203
+ buttons.push(last);
204
+ } else {
205
+ buttons.push(next);
206
+ }
207
+ } else {
208
+ if (this.options.deleteOption) {
209
+ buttons.push(deleteBtn);
210
+ }
211
+
212
+ buttons.push(next);
213
+
214
+ if (this.options.firstLast) {
215
+ buttons.push(last);
216
+ }
217
+ }
218
+
219
+
220
+ if (!this.options.firstLast) {
221
+ buttons.push(last);
222
+ }
223
+
224
+ return buttons;
225
+ }
226
+
227
+
228
+ private createComponents(): ActionRowBuilder<MessageActionRowComponentBuilder>[] {
229
+ const actionRow = new ActionRowBuilder<MessageActionRowComponentBuilder>().addComponents(this.buttons);
230
+ const components = [actionRow, ...this.options.otherComponents];
231
+
232
+ if (this.options.navigationMenu?.enabled) {
233
+ const menuOptions = this.options.navigationMenu.selects!.map((select, index) => ({
234
+ label: `Page ${index + 1}`,
235
+ description: select,
236
+ value: `${index}`,
237
+ }));
238
+
239
+ const selectMenu = new StringSelectMenuBuilder()
240
+ .setCustomId(CUSTOM_IDS.SELECT)
241
+ .setPlaceholder(this.options.navigationMenu.placeHolder || "Select a page")
242
+ .addOptions(menuOptions);
243
+
244
+ const row = new ActionRowBuilder<StringSelectMenuBuilder>().addComponents(selectMenu);
245
+ components.push(row);
246
+ }
247
+
248
+ return components;
249
+ }
250
+
251
+ public async send() {
252
+ const { embeds = [], content = [], attachment = [] } = this.options.pages || {};
174
253
 
175
- const buttons: ButtonBuilder[] = [];
254
+ const safeEmbeds = embeds ?? [];
255
+
256
+ if (safeEmbeds.length === 0) {
257
+ throw new Error("No embeds provided.");
258
+ }
176
259
 
177
- if (this.options.firstLast) buttons.push(first);
178
- buttons.push(back);
179
- if (this.options.home?.home_Option) buttons.push(home);
180
- else if (this.options.deleteOption) buttons.push(deleteBtn);
181
- buttons.push(next);
182
- if (this.options.firstLast) buttons.push(last);
260
+ try {
261
+ const msg = await this.message.reply({
262
+ embeds: [safeEmbeds[0]],
263
+ content: content[0] || "",
264
+ files: attachment[0] ? [attachment[0]] : undefined,
265
+ components: this.components,
266
+ });
183
267
 
184
- return buttons;
268
+ this.handleInteraction(msg);
269
+ } catch (error) {
270
+ console.error("Failed to send message:", error);
185
271
  }
272
+ }
186
273
 
187
- private createComponents(): ActionRowBuilder<MessageActionRowComponentBuilder>[] {
188
- const buttonRow = new ActionRowBuilder<MessageActionRowComponentBuilder>().addComponents(this.buttons);
189
-
190
- const otherRows = this.options.otherComponents || [];
191
- const selectMenus = this.options.navigationMenu?.enabled ? this.createSelectMenus() : [];
192
-
193
- return [buttonRow, ...selectMenus, ...otherRows];
194
- }
195
-
196
- private createSelectMenus(): ActionRowBuilder<StringSelectMenuBuilder>[] {
197
- const { embeds = [], content = [], attachment = [] } = this.options.pages || {};
198
- const longest_length = Math.max(embeds.length, content.length, attachment.length);
199
- const selectMenus: ActionRowBuilder<StringSelectMenuBuilder>[] = [];
200
- const select_status = this.options.navigationMenu?.enabled;
201
- const select_placeholder = this.options.navigationMenu?.placeHolder;
202
- const selects = this.options.navigationMenu?.selects || [];
203
-
204
- if (select_status) {
205
- for (let i = 0; i < longest_length; i += 25) {
206
- const menuOptions = Array.from({ length: Math.min(25, longest_length - i) }, (_, j) => ({
207
- label: selects[i + j] ? selects[i + j] : `Page ${i + j + 1}`,
208
- value: `${i + j}`
209
- }));
210
-
211
- const selectMenu = new StringSelectMenuBuilder()
212
- .setCustomId(`discobase_select_${i / 25}`)
213
- .setPlaceholder(`${select_placeholder || "Choose a page"} (${i + 1}-${Math.min(i + 25, longest_length)})`)
214
- .addOptions(menuOptions);
215
-
216
- selectMenus.push(new ActionRowBuilder<StringSelectMenuBuilder>().addComponents(selectMenu));
217
- }
218
- }
219
-
220
- return selectMenus;
221
- }
222
-
223
- public async send() {
224
- const { embeds = [], content = [], attachment = [] } = this.options.pages || {};
225
-
226
- if (embeds.length === 0) {
227
- throw new Error("No embeds provided.");
228
- }
229
-
230
- try {
231
- const msg = await this.message.reply({
232
- embeds: [embeds[0]],
233
- content: content[0] || "",
234
- files: attachment[0] ? [attachment[0]] : [],
235
- components: this.components,
236
- });
237
-
238
- const collector = this.createCollector(msg);
239
- collector.on("collect", async (i: MessageComponentInteraction) => this.handleCollect(i));
240
- collector.on("end", async () => this.handleEnd(msg));
241
- } catch (error) {
242
- console.error("Error sending message:", error);
243
- }
244
- }
274
+
275
+
276
+ private async handleInteraction(msg: Message) {
277
+ const filter = (i: MessageComponentInteraction) => i.user.id === this.message.author.id;
245
278
 
246
- private createCollector(msg: Message) {
247
- const filter = this.options.user_only?.user_status
248
- ? async (i: MessageComponentInteraction) => {
249
- if (i.user.id !== this.message.author.id) {
250
- await i.reply({ content: this.options.user_only.reply!, ephemeral: true });
251
- return false;
252
- }
253
- return true;
254
- }
255
- : undefined;
279
+ const collector = msg.createMessageComponentCollector({ filter, time: this.options.timeOption?.timeOut || 60000 });
280
+
281
+ collector.on("collect", async (interaction: MessageComponentInteraction) => {
282
+ try {
283
+ const embedsLength = this.options.pages.embeds?.length || 0;
256
284
 
257
- return msg.createMessageComponentCollector({
258
- filter,
259
- time: this.options.timeOption?.timeOut || 86400000,
260
- });
261
- }
262
-
263
-
264
- private async handleCollect(i: MessageComponentInteraction) {
265
- const { embeds = [], content = [], attachment = [] } = this.options.pages || {};
266
- const num = embeds.length;
267
-
268
- try {
269
- if (i.isButton()) {
270
- switch (i.customId) {
271
- case CUSTOM_IDS.NEXT:
272
- this.naw_page = (this.naw_page + 1) % num;
273
- break;
274
- case CUSTOM_IDS.BACK:
275
- this.naw_page = (this.naw_page - 1 + num) % num;
276
- break;
277
- case CUSTOM_IDS.FIRST:
278
- this.naw_page = 0;
279
- break;
280
- case CUSTOM_IDS.LAST:
281
- this.naw_page = num - 1;
282
- break;
283
- case CUSTOM_IDS.DELETE:
284
- await i.message.delete();
285
- return;
286
- case CUSTOM_IDS.HOME:
287
- this.naw_page = this.options.home?.home_page || 0;
288
- break;
289
- }
290
- } else if (i.isStringSelectMenu()) {
291
- if (i.customId.startsWith("discobase_select_")) {
292
- this.naw_page = parseInt(i.values[0], 10);
293
- }
285
+ // Handle interaction based on its type
286
+ if (interaction.isButton()) {
287
+ switch (interaction.customId) {
288
+ case CUSTOM_IDS.NEXT:
289
+ this.naw_page = (this.naw_page + 1) % embedsLength;
290
+ break;
291
+ case CUSTOM_IDS.BACK:
292
+ this.naw_page = (this.naw_page - 1 + embedsLength) % embedsLength;
293
+ break;
294
+ case CUSTOM_IDS.FIRST:
295
+ this.naw_page = 0;
296
+ break;
297
+ case CUSTOM_IDS.LAST:
298
+ this.naw_page = embedsLength - 1;
299
+ break;
300
+ case CUSTOM_IDS.DELETE:
301
+ await interaction.deferUpdate();
302
+ await msg.delete();
303
+ collector.stop();
304
+ return;
305
+ case CUSTOM_IDS.HOME:
306
+ this.naw_page = this.options.home?.home_page || 0;
307
+ break;
308
+ default:
309
+ break;
310
+ }
311
+ } else if (interaction.isStringSelectMenu()) {
312
+ if (interaction.customId === CUSTOM_IDS.SELECT) {
313
+ this.naw_page = Number(interaction.values[0]);
294
314
  }
295
- await i.update({
296
- embeds: [embeds[this.naw_page]],
297
- content: content[this.naw_page] || "",
298
- files: attachment[this.naw_page] ? [attachment[this.naw_page]] : [],
299
- components: this.createComponents(),
300
- });
301
- } catch (error) {
302
- console.error("Error handling interaction:", error);
303
315
  }
316
+
317
+ await interaction.deferUpdate();
318
+ await this.updateMessage(msg);
319
+ } catch (error) {
320
+ console.error("Interaction error:", error);
304
321
  }
305
-
306
- private async handleEnd(msg: Message) {
307
- try {
322
+ });
323
+
324
+ collector.on("end", async () => {
325
+ try {
326
+ const fetchedMsg = await this.message.channel.messages.fetch(msg.id);
327
+
308
328
  if (this.options.timeOption?.disable) {
309
- this.components[0].components.forEach((button) => button.setDisabled(true));
310
- await msg.edit({ components: this.components });
329
+ const disabledButtons = this.buttons.map(button =>
330
+ button.setDisabled(true)
331
+ );
332
+
333
+ const menuOptions: { label: string; description?: string; value: string }[] =
334
+ this.options.navigationMenu?.selects?.map((select, index) => ({
335
+ label: `Page ${index + 1}`,
336
+ description: select,
337
+ value: `${index}`,
338
+ })) || [];
339
+
340
+ const disabledComponents = new ActionRowBuilder<MessageActionRowComponentBuilder>().addComponents(disabledButtons);
341
+ const newComponents = [disabledComponents, ...this.options.otherComponents];
342
+
343
+ if (this.options.navigationMenu?.enabled) {
344
+ const selectMenu = new StringSelectMenuBuilder()
345
+ .setCustomId(CUSTOM_IDS.SELECT)
346
+ .setPlaceholder(this.options.navigationMenu.placeHolder || "Select a page")
347
+ .addOptions(menuOptions)
348
+ .setDisabled(true);
349
+
350
+ const row = new ActionRowBuilder<StringSelectMenuBuilder>().addComponents(selectMenu);
351
+ newComponents.push(row);
352
+ }
353
+
354
+ await fetchedMsg.edit({ components: newComponents });
311
355
  }
356
+
312
357
  if (this.options.timeOption?.deletes) {
313
- await msg.edit({ components: [] });
314
- }
315
- if (typeof this.options.timeOption?.custom === "function") {
316
- this.options.timeOption.custom();
358
+ await fetchedMsg.delete();
317
359
  }
318
- } catch (error) {
319
- console.error("Error handling end of collector:", error);
320
- }
321
- }
322
- }
323
-
360
+ } catch (error: any) {}
361
+ });
362
+ }
363
+
364
+ private async updateMessage(msg: Message) {
365
+ const { embeds = [], content = [], attachment = [] } = this.options.pages || {};
366
+
367
+ await msg.edit({
368
+ embeds: [embeds[this.naw_page]],
369
+ content: content[this.naw_page] || "",
370
+ files: attachment[this.naw_page] ? [attachment[this.naw_page]] : undefined,
371
+ components: this.components,
372
+ });
373
+ }
374
+ }
@@ -96,7 +96,7 @@ function Djs_Collectors<T extends EventSource>(
96
96
  idle: options.idle,
97
97
  });
98
98
 
99
- collectors.push(interactionCollector); // Store reference
99
+ collectors.push(interactionCollector);
100
100
  handleCollector(interactionCollector, events, options, metadata);
101
101
 
102
102
  } else if (source instanceof MessageReaction) {
@@ -107,7 +107,7 @@ function Djs_Collectors<T extends EventSource>(
107
107
  idle: options.idle,
108
108
  });
109
109
 
110
- collectors.push(reactionCollector); // Store reference
110
+ collectors.push(reactionCollector);
111
111
  handleCollector(reactionCollector, events, options, metadata);
112
112
 
113
113
  } else {