Skip to content

Commit 8e6c138

Browse files
authored
Refactor/notes on button pt3 (#49)
* feat: checkin detail button * feat: checkin detail button handler * chore: remove unused update checkin message * chore: typography
1 parent d4e60f5 commit 8e6c138

5 files changed

Lines changed: 95 additions & 45 deletions

File tree

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
import type { GuildMember, TextChannel } from 'discord.js'
2+
import { EVENT_PATH } from '@events/index'
3+
import { registerInteractionHandler } from '@events/interaction-create/registry'
4+
import { generateCustomId } from '@utils/component'
5+
import { sendReply } from '@utils/discord'
6+
import { DiscordBaseError } from '@utils/discord/error'
7+
import { getModuleName } from '@utils/io'
8+
import { Checkin } from '../validators'
9+
10+
export class CheckinDetailButtonError extends DiscordBaseError {
11+
constructor(message: string, options?: { cause?: unknown }) {
12+
super('CheckinDetailButtonError', message, options)
13+
}
14+
}
15+
16+
const moduleName = getModuleName(EVENT_PATH, __filename)
17+
export const CHECKIN_DETAIL_BUTTON_ID = `${generateCustomId(EVENT_PATH, __filename)}`
18+
19+
registerInteractionHandler({
20+
desc: 'Handles displaying more details for a user check-in when the detail button is pressed.',
21+
id: CHECKIN_DETAIL_BUTTON_ID,
22+
errorTag: () => `${moduleName}: ${Checkin.ERR.UnexpectedButton}`,
23+
async exec(client, interaction) {
24+
if (!interaction.isButton())
25+
return
26+
27+
try {
28+
if (!interaction.inCachedGuild())
29+
throw new CheckinDetailButtonError(Checkin.ERR.NotGuild)
30+
31+
const { checkinId } = Checkin.getButtonId(interaction, interaction.customId)
32+
33+
const channel = interaction.channel as TextChannel
34+
const member = interaction.member as GuildMember
35+
Checkin.assertMissPerms(interaction.client.user, channel)
36+
Checkin.assertMember(member)
37+
Checkin.assertMemberGrindRoles(member)
38+
39+
const checkin = await Checkin.getCheckin(client.prisma, checkinId)
40+
const prevCheckin = await Checkin.getPrevCheckin(client.prisma, checkin.user!.id, checkin.checkin_streak!, checkin)
41+
42+
await sendReply(interaction, Checkin.MSG.GrinderDetails(member, checkin, checkin.checkin_streak!.streak, prevCheckin))
43+
}
44+
catch (err: any) {
45+
if (err instanceof DiscordBaseError)
46+
await sendReply(interaction, err.message)
47+
else throw err
48+
}
49+
},
50+
})

src/bot/events/interaction-create/checkin/handlers/modal.ts

Lines changed: 2 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -42,23 +42,12 @@ registerInteractionHandler({
4242
Checkin.assertMemberGrindRoles(member)
4343
Checkin.assertCheckinToday(user)
4444

45-
const {
46-
checkinStreak,
47-
checkin,
48-
prevCheckin,
49-
} = await Checkin.validateCheckinStreak(client.prisma, user.id, user.checkin_streaks?.[0], todo)
50-
45+
const { checkin } = await Checkin.validateCheckinStreak(client.prisma, user.id, user.checkin_streaks?.[0], todo)
5146
const buttons = Checkin.generateButtons(interaction.guildId, checkin.id.toString())
5247

5348
const msg = await sendReply(
5449
interaction,
55-
Checkin.MSG.CheckinSuccess(
56-
member,
57-
attachments,
58-
checkinStreak.streak,
59-
todo,
60-
prevCheckin,
61-
),
50+
Checkin.MSG.CheckinSuccess(todo),
6251
false,
6352
{
6453
files: attachments.length ? attachments : undefined,

src/bot/events/interaction-create/checkin/messages/index.ts

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import type { Checkin } from '@type/checkin'
2-
import type { Attachment, GuildMember } from 'discord.js'
2+
import type { GuildMember } from 'discord.js'
33
import { FLAMEWARDEN_ROLE } from '@config/discord'
44
import { getNow, getParsedNow } from '@utils/date'
55
import { DiscordAssert } from '@utils/discord'
@@ -17,21 +17,24 @@ export class CheckinMessage extends DiscordAssert {
1717

1818
static override readonly MSG = {
1919
...DiscordAssert.MSG,
20-
CheckinSuccess: (member: GuildMember, checkinAttachments: Attachment[], streakCount: number, todo: string, lastCheckin?: Checkin) => `
20+
CheckinSuccess: (todo: string) => `
2121
# ✅ Check-In Baru Terdeteksi!
2222
*Kindly take a look and do a review for this one, <@&${FLAMEWARDEN_ROLE}>*
2323
24-
✨─────✨/✨━━━━✨
25-
🌟 **Grinder:** <@${member.id}>
26-
📁 **Attachment:** ${checkinAttachments.length > 0 ? '✅' : '❌'}
27-
🕓 **Date:** ${getParsedNow()}
28-
🔥 **Current Streak:** ${streakCount} day(s)
29-
🗓 **Last Check-In:** ${lastCheckin ? getParsedNow(getNow(lastCheckin.created_at)) : '-'}
3024
⋆。˚ ☁︎ ˚。⋆。˚☽˚。⋆
3125
${todo}
3226
3327
> ${DUMMY.FOOTER}`,
3428

29+
GrinderDetails: (member: GuildMember, checkin: Checkin, streakCount: number, lastCheckin?: Checkin) => `
30+
✨─────✨/✨━━━━✨
31+
🌟 **Grinder:** <@${member.id}>
32+
📁 **Attachment:** ${checkin.attachments && checkin.attachments.length > 0 ? '✅' : '❌'}
33+
🕓 **Date:** ${getParsedNow()}
34+
🔥 **Current Streak:** ${streakCount} day(s)
35+
🗓 **Last Check-In:** ${lastCheckin ? `[${getParsedNow(getNow(lastCheckin.created_at))}](${lastCheckin.link})` : '-'}
36+
`,
37+
3538
CheckinSuccessToMember: (checkin: Checkin) => `
3639
Sebuah [check-in](${checkin.link}) baru telah Tuan/Nona serahkan dan kini menunggu pemeriksaan dari Flamewarden.
3740
🆔 **Check-In ID**:

src/bot/events/interaction-create/checkin/validators/index.ts

Lines changed: 31 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ import { ActionRowBuilder, ButtonBuilder, ButtonStyle, messageLink, PermissionsB
1818
import { CHECKIN_APPROVE_BUTTON_ID } from '../handlers/approve-button'
1919
import { CHECKIN_CUSTOM_BUTTON_ID } from '../handlers/custom-button'
2020
import { CheckinCustomButtonModalError } from '../handlers/custom-button-modal'
21+
import { CHECKIN_DETAIL_BUTTON_ID } from '../handlers/detail-button'
2122
import { CheckinModalError } from '../handlers/modal'
2223
import { CHECKIN_REJECT_BUTTON_ID } from '../handlers/reject-button'
2324
import { CheckinMessage } from '../messages'
@@ -100,6 +101,12 @@ export class Checkin extends CheckinMessage {
100101
}
101102

102103
static generateButtons(guildId: string, checkinId: string): ActionRowBuilder<ButtonBuilder> {
104+
const detailButtonId = getCustomId([CHECKIN_DETAIL_BUTTON_ID, encodeSnowflake(guildId), encodeSnowflake(checkinId)])
105+
const detailButton = new ButtonBuilder()
106+
.setCustomId(detailButtonId)
107+
.setLabel('🔍 Detail')
108+
.setStyle(ButtonStyle.Primary)
109+
103110
const approveButtonId = getCustomId([CHECKIN_APPROVE_BUTTON_ID, encodeSnowflake(guildId), encodeSnowflake(checkinId)])
104111
const approveButton = new ButtonBuilder()
105112
.setCustomId(approveButtonId)
@@ -116,9 +123,9 @@ export class Checkin extends CheckinMessage {
116123
const customButton = new ButtonBuilder()
117124
.setCustomId(customButtonId)
118125
.setLabel('⚙️ Review')
119-
.setStyle(ButtonStyle.Primary)
126+
.setStyle(ButtonStyle.Secondary)
120127

121-
return new ActionRowBuilder<ButtonBuilder>().addComponents(approveButton, rejectButton, customButton)
128+
return new ActionRowBuilder<ButtonBuilder>().addComponents(detailButton, approveButton, rejectButton, customButton)
122129
}
123130

124131
static getNewGrindRole(guild: Guild, streakCount: number) {
@@ -323,6 +330,26 @@ export class Checkin extends CheckinMessage {
323330
}) as CheckinType
324331
}
325332

333+
static async getCheckin(
334+
prisma: PrismaClient,
335+
checkinId: number,
336+
): Promise<CheckinType> {
337+
const checkin = await prisma.checkin.findUnique({
338+
where: { id: checkinId },
339+
include: {
340+
checkin_streak: true,
341+
user: true,
342+
},
343+
}) as CheckinType
344+
345+
if (!checkin)
346+
throw new SubmittedCheckinError(this.ERR.PlainMessage)
347+
348+
await this.setAttachments(prisma, checkin)
349+
350+
return checkin
351+
}
352+
326353
static async createAttachments(
327354
prisma: PrismaClient,
328355
checkin: CheckinType,
@@ -368,13 +395,8 @@ export class Checkin extends CheckinMessage {
368395
return prisma.$transaction(async (tx) => {
369396
const checkinStreak = await this.upsertStreak(tx, userId, lastCheckinStreak, decision)
370397
const checkin = await this.createCheckin(tx, userId, checkinStreak, description)
371-
const prevCheckin = await this.getPrevCheckin(tx, userId, checkinStreak, checkin)
372398

373-
return {
374-
checkinStreak,
375-
checkin,
376-
prevCheckin,
377-
}
399+
return { checkinStreak, checkin }
378400
})
379401
}
380402

@@ -392,7 +414,7 @@ export class Checkin extends CheckinMessage {
392414
const updatedCheckin = await this.updateCheckinStatus(prisma, flamewarden, checkin, checkinStatus, comment) as CheckinType
393415

394416
await this.validateCheckinHandleToUser(guild, flamewarden, checkin.user!.discord_id, updatedCheckin)
395-
await this.validateCheckinHandleSubmittedMsg(message, updatedCheckin, checkinStatus)
417+
await message.react(this.REVERSED_EMOJI_STATUS[checkinStatus])
396418
}
397419

398420
static async validateCheckinHandleToUser(guild: Guild, flamewarden: GuildMember, userDiscordId: string, updatedCheckin: CheckinType) {
@@ -403,11 +425,6 @@ export class Checkin extends CheckinMessage {
403425
await this.sendCheckinStatusToMember(flamewarden, member, updatedCheckin)
404426
}
405427

406-
static async validateCheckinHandleSubmittedMsg(message: Message, updatedCheckin: CheckinType, checkinStatus: CheckinStatusType) {
407-
await this.updateSubmittedCheckin(message, updatedCheckin.checkin_streak!.streak)
408-
await message.react(this.REVERSED_EMOJI_STATUS[checkinStatus])
409-
}
410-
411428
static async updateCheckinMsgLink(interaction: Interaction, prisma: PrismaClient, checkin: CheckinType, msg: Message): Promise<CheckinType> {
412429
const msgLink = messageLink(interaction.channelId!, msg.id, interaction.guildId!)
413430

@@ -491,13 +508,4 @@ export class Checkin extends CheckinMessage {
491508

492509
await member.send({ embeds: [embed] })
493510
}
494-
495-
static async updateSubmittedCheckin(message: Message, newStreak: number) {
496-
await message.edit(
497-
message.content.replace(
498-
/🔥\s*\*\*Current Streak:\*\*\s*\d+\s*day\(s\)/i,
499-
`🔥 **Current Streak:** ${newStreak} day(s)`,
500-
),
501-
)
502-
}
503511
}

src/utils/component.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -142,7 +142,7 @@ ${checkin.public_id}
142142
🔥 **Current Streak**: ${checkin.checkin_streak!.streak} day(s)
143143
## Notulen Grinder
144144
${checkin.description}
145-
✰⋆。:゚・*☽:゚・⋆。✰⋆。:゚`))
145+
⋆。˚ ☁︎ ˚。⋆。˚☽˚。⋆`))
146146
.addTextDisplayComponents(textDisplay => textDisplay.setContent(DUMMY.MARKDOWN))
147147

148148
return modal

0 commit comments

Comments
 (0)