/[sudobot]/trunk/src/utils/Pagination.ts
ViewVC logotype

Contents of /trunk/src/utils/Pagination.ts

Parent Directory Parent Directory | Revision Log Revision Log


Revision 447 - (show annotations)
Mon Jul 29 17:30:17 2024 UTC (8 months, 1 week ago) by rakin
File MIME type: application/typescript
File size: 6861 byte(s)
style: remove unneeded imports
1 import DiscordClient from "../client/Client";
2 import MessageEmbed from "../client/MessageEmbed";
3 import { v4 as uuid } from 'uuid';
4 import { ButtonInteraction, InteractionCollector, InteractionReplyOptions, Message, MessageActionRow, MessageButton, MessageEditOptions, MessageOptions, ReplyMessageOptions } from "discord.js";
5
6 export interface EmbedBuilderOptions<T> {
7 data: Array<T>;
8 currentPage: number;
9 maxPages: number;
10 }
11
12 export interface PaginationOptions<T> {
13 limit: number;
14 guild_id: string;
15 channel_id: string;
16 user_id?: string;
17 embedBuilder: (options: EmbedBuilderOptions<T>) => MessageEmbed;
18 actionRowBuilder?: (options: { first: boolean, last: boolean, next: boolean, back: boolean }) => MessageActionRow<MessageButton>;
19 }
20
21 export default class Pagination<T> {
22 protected readonly client = DiscordClient.client;
23 protected readonly id: string;
24 protected currentPage: number = 1;
25
26 constructor(protected readonly data: Array<T> = [], protected readonly options: PaginationOptions<T>) {
27 this.id = uuid();
28 }
29
30 getOffset(page: number = 1) {
31 return (page - 1) * this.options.limit;
32 }
33
34 getPaginatedData(page: number = 1) {
35 console.log(page, this.getOffset(page));
36 return this.data.slice(this.getOffset(page), this.getOffset(page) + this.options.limit);
37 }
38
39 getEmbed(page: number = 1): MessageEmbed {
40 return this.options.embedBuilder({
41 data: this.getPaginatedData(page),
42 currentPage: this.currentPage,
43 maxPages: Math.ceil(this.data.length / this.options.limit),
44 });
45 }
46
47 getMessageOptions(page: number = 1, actionRowOptions: { first: boolean, last: boolean, next: boolean, back: boolean } | undefined = undefined, optionsToMerge: ReplyMessageOptions & MessageOptions & InteractionReplyOptions & MessageEditOptions = {}) {
48 const options = {...optionsToMerge};
49 const actionRowOptionsDup = actionRowOptions ? {...actionRowOptions} : { first: true, last: true, next: true, back: true };
50
51 if (actionRowOptionsDup && page <= 1) {
52 actionRowOptionsDup.back = false;
53 actionRowOptionsDup.first = false;
54 }
55
56 if (actionRowOptionsDup && page >= Math.ceil(this.data.length / this.options.limit)) {
57 actionRowOptionsDup.last = false
58 actionRowOptionsDup.next = false;
59 }
60
61 options.embeds ??= [];
62 options.embeds.push(this.getEmbed(page));
63 console.log(options.embeds);
64 options.components ??= [];
65 options.components.push(this.getActionRow(actionRowOptionsDup));
66
67 return options;
68 }
69
70 getActionRow({ first, last, next, back }: { first: boolean, last: boolean, next: boolean, back: boolean } = { first: true, last: true, next: true, back: true }) {
71 if (this.options.actionRowBuilder) {
72 return this.options.actionRowBuilder({ first, last, next, back });
73 }
74
75 const actionRow = new MessageActionRow<MessageButton>;
76
77 actionRow.addComponents(
78 new MessageButton()
79 .setCustomId(`pagination_first_${this.id}`)
80 .setStyle("PRIMARY")
81 .setLabel('⏪')
82 .setDisabled(!first),
83 new MessageButton()
84 .setCustomId(`pagination_back_${this.id}`)
85 .setStyle("PRIMARY")
86 .setLabel('◀')
87 .setDisabled(!back),
88 new MessageButton()
89 .setCustomId(`pagination_next_${this.id}`)
90 .setStyle("PRIMARY")
91 .setLabel('▶')
92 .setDisabled(!next),
93 new MessageButton()
94 .setCustomId(`pagination_last_${this.id}`)
95 .setStyle("PRIMARY")
96 .setLabel('⏩')
97 .setDisabled(!last)
98 );
99
100 return actionRow;
101 }
102
103 async start(message: Message) {
104 const collector = new InteractionCollector(this.client, {
105 guild: this.options.guild_id,
106 channel: this.options.channel_id,
107 interactionType: 'MESSAGE_COMPONENT',
108 componentType: 'BUTTON',
109 message,
110 time: 60_000,
111 filter: interaction => {
112 if (interaction.inGuild() && (!this.options.user_id || interaction.user.id === this.options.user_id)) {
113 return true;
114 }
115
116 if (interaction.isRepliable()) {
117 interaction.reply({ content: 'That\'t not under your control or the button controls are expired', ephemeral: true });
118 }
119
120 return false;
121 },
122 });
123
124 collector.on("collect", async (interaction: ButtonInteraction) => {
125 if (!interaction.customId.endsWith(this.id)) {
126 return;
127 }
128
129 const maxPage = Math.ceil(this.data.length / this.options.limit);
130 const componentOptions = { first: true, last: true, next: true, back: true };
131
132 if ([`pagination_next_${this.id}`, `pagination_back_${this.id}`].includes(interaction.customId)) {
133 console.log('here');
134
135 if (this.currentPage >= maxPage && interaction.customId === `pagination_next_${this.id}`) {
136 console.log('here');
137 await interaction.reply({ content: maxPage === 1 ? "This is the only page!" : "You've reached the last page!", ephemeral: true });
138 return;
139 }
140
141 if (this.currentPage <= 1 && interaction.customId === `pagination_back_${this.id}`) {
142 console.log('here');
143 await interaction.reply({ content: maxPage === 1 ? "This is the only page!" : "You're in the very first page!", ephemeral: true });
144 return;
145 }
146 }
147
148 if (interaction.customId === `pagination_first_${this.id}`)
149 this.currentPage = 1;
150 else if (interaction.customId === `pagination_last_${this.id}`)
151 this.currentPage = maxPage;
152
153 await interaction.update(this.getMessageOptions(
154 interaction.customId === `pagination_first_${this.id}` ? 1 :
155 interaction.customId === `pagination_last_${this.id}` ? maxPage :
156 (interaction.customId === `pagination_next_${this.id}` ? (this.currentPage >= maxPage ? this.currentPage : ++this.currentPage) : --this.currentPage),
157 componentOptions,
158 {
159 embeds: []
160 }
161 ));
162 });
163
164 collector.on("end", async () => {
165 await message.edit({ components: [this.getActionRow({ first: false, last: false, next: false, back: false })] });
166 });
167 }
168 }

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26