Skip to content

Commit c815d10

Browse files
committed
feat: use Paginator to split rep history
1 parent a5f037a commit c815d10

File tree

2 files changed

+134
-24
lines changed

2 files changed

+134
-24
lines changed

src/modules/rep.ts

Lines changed: 33 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import { TS_BLUE } from '../env';
1111

1212
import { RepGive } from '../entities/RepGive';
1313
import { RepUser } from '../entities/RepUser';
14+
import { Paginator } from '../util/Paginator';
1415

1516
export class RepModule extends Module {
1617
constructor(client: CookiecordClient) {
@@ -125,35 +126,43 @@ export class RepModule extends Module {
125126
description: "Reputation: View a user's reputation history",
126127
})
127128
async getrep(msg: Message, @optional user?: User) {
129+
if (!msg.member || msg.channel.type !== 'text') {
130+
return;
131+
}
128132
if (!user) user = msg.author;
129133

130134
const targetRU = await this.getOrMakeUser(user);
135+
const records = (await targetRU.got)
136+
.concat(await targetRU.given)
137+
// Decreasing chronologically
138+
.sort((a, b) => b.createdAt.getTime() - a.createdAt.getTime())
139+
.map(rg => {
140+
if (rg.from.id == targetRU.id)
141+
return `:white_small_square: Gave 1 rep to <@${
142+
rg.to.id
143+
}> (${prettyMilliseconds(
144+
Date.now() - rg.createdAt.getTime(),
145+
)} ago)`;
146+
else
147+
return `:white_small_square: Got 1 rep from <@${
148+
rg.from.id
149+
}> (${prettyMilliseconds(
150+
Date.now() - rg.createdAt.getTime(),
151+
)} ago)`;
152+
});
153+
const recordsPerPage = 30;
154+
const pages = records
155+
.reduce((acc, cur, index) => {
156+
const curChunk = Math.floor(index / recordsPerPage);
157+
acc[curChunk] ??= [];
158+
acc[curChunk].push(cur);
159+
return acc;
160+
}, [] as string[][])
161+
.map(page => page.join('\n'));
131162
const embed = new MessageEmbed()
132163
.setColor(TS_BLUE)
133-
.setAuthor(user.tag, user.displayAvatarURL())
134-
.setDescription(
135-
(
136-
await Promise.all(
137-
(await targetRU.got)
138-
.concat(await targetRU.given)
139-
.map(async rg => {
140-
if (rg.from.id == targetRU.id)
141-
return `:white_small_square: Gave 1 rep to <@${
142-
rg.to.id
143-
}> (${prettyMilliseconds(
144-
Date.now() - rg.createdAt.getTime(),
145-
)} ago)`;
146-
else
147-
return `:white_small_square: Got 1 rep from <@${
148-
rg.from.id
149-
}> (${prettyMilliseconds(
150-
Date.now() - rg.createdAt.getTime(),
151-
)} ago)`;
152-
}),
153-
)
154-
).join('\n'),
155-
);
156-
await msg.channel.send(embed, { split: true });
164+
.setAuthor(user.tag, user.displayAvatarURL());
165+
new Paginator(embed, pages, msg.member, msg.channel, 300000);
157166
}
158167

159168
@command({

src/util/Paginator.ts

Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
import {
2+
GuildMember,
3+
Message,
4+
MessageEmbed,
5+
MessageReaction,
6+
ReactionCollector,
7+
TextChannel,
8+
User,
9+
} from 'discord.js';
10+
11+
const emojis = {
12+
back: '◀',
13+
first: '⏮',
14+
last: '⏭',
15+
next: '▶',
16+
stop: '⏹',
17+
};
18+
19+
export class Paginator {
20+
private message!: Message;
21+
private curPage = 0;
22+
23+
private collector!: ReactionCollector;
24+
25+
public constructor(
26+
private readonly embed: MessageEmbed,
27+
private readonly pages: string[],
28+
private readonly member: GuildMember,
29+
private readonly channel: TextChannel,
30+
private readonly timeout: number = 100000,
31+
) {
32+
this.init();
33+
}
34+
35+
private async init(): Promise<void> {
36+
this.message = await this.channel.send(
37+
this.embed
38+
.setDescription(this.pages[this.curPage])
39+
.setFooter(`Page ${this.curPage + 1} of ${this.pages.length}`),
40+
);
41+
42+
if (this.pages.length === 1) return;
43+
44+
await this.message.react(emojis.first);
45+
await this.message.react(emojis.back);
46+
await this.message.react(emojis.stop);
47+
await this.message.react(emojis.next);
48+
await this.message.react(emojis.last);
49+
50+
this.collector = this.message.createReactionCollector(
51+
(reaction, user) =>
52+
reaction.me &&
53+
user.id === this.member.id &&
54+
user.id !== this.message.author!.id,
55+
{ time: this.timeout },
56+
);
57+
58+
this.collector.on(
59+
'collect',
60+
async (reaction: MessageReaction, user: User) => {
61+
await reaction.users.remove(user);
62+
63+
switch (reaction.emoji.toString()) {
64+
case emojis.first:
65+
this.curPage = 0;
66+
break;
67+
case emojis.last:
68+
this.curPage = this.pages.length - 1;
69+
break;
70+
case emojis.stop:
71+
await this.message.reactions.removeAll();
72+
break;
73+
case emojis.back:
74+
this.curPage--;
75+
if (this.curPage < 0)
76+
this.curPage = this.pages.length - 1;
77+
break;
78+
case emojis.next:
79+
this.curPage++;
80+
if (this.curPage > this.pages.length - 1)
81+
this.curPage = 0;
82+
break;
83+
}
84+
85+
await this.refresh();
86+
},
87+
);
88+
89+
this.collector.on('end', () => {
90+
this.message.reactions.removeAll();
91+
});
92+
}
93+
94+
private async refresh(): Promise<void> {
95+
await this.message.edit(
96+
this.embed
97+
.setDescription(this.pages[this.curPage])
98+
.setFooter(`Page ${this.curPage + 1} of ${this.pages.length}`),
99+
);
100+
}
101+
}

0 commit comments

Comments
 (0)