Skip to content

Commit 6c99355

Browse files
committed
[Feat]: implement open ticket management and persistence in ticket system
1 parent 5816d4b commit 6c99355

File tree

3 files changed

+32
-11
lines changed

3 files changed

+32
-11
lines changed

src/commands/ticket-close.ts

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import { SlashCommandBuilder, PermissionsBitField } from 'discord.js';
22
import { buildEmbed } from '../utils/embed';
3+
import { getGuildConfig, upsertGuildConfig } from '../config/store';
34

45
const EPHEMERAL_FLAG = 1 << 6;
56

@@ -17,6 +18,9 @@ async function execute(interaction: any) {
1718
}
1819
const channel = interaction.channel;
1920
const category = channel?.parent;
21+
const guildId = interaction.guildId;
22+
const cfg = guildId ? getGuildConfig(guildId) : undefined;
23+
2024
try {
2125
const respond =
2226
interaction.deferred || interaction.replied
@@ -28,6 +32,15 @@ async function execute(interaction: any) {
2832
flags: EPHEMERAL_FLAG,
2933
});
3034

35+
// Clean up stored open ticket if it matches
36+
if (cfg?.openTickets) {
37+
const entry = Object.entries(cfg.openTickets).find(([, t]) => t.categoryId === category?.id);
38+
if (entry) {
39+
delete cfg.openTickets[entry[0]];
40+
upsertGuildConfig({ ...cfg, guildId });
41+
}
42+
}
43+
3144
if (channel && channel.deletable) await channel.delete('Ticket cerrado');
3245
if (category && category.children) {
3346
for await (const child of category.children.cache.values()) {

src/config/store.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ export interface GuildConfig {
1515
voiceCategory?: string;
1616
};
1717
ticketMessageId?: string;
18+
openTickets?: Record<string, { categoryId: string; textId?: string; voiceId?: string }>; // key: userId
1819
}
1920

2021
interface ConfigFile {

src/events/messageReactionAdd.ts

Lines changed: 18 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { buildEmbed } from '../utils/embed';
2-
import { getGuildConfig } from '../config/store';
2+
import { getGuildConfig, upsertGuildConfig } from '../config/store';
33

44
const EPHEMERAL_FLAG = 1 << 6; // Discord API flag
55

@@ -23,21 +23,24 @@ export default {
2323
// Remove the user's reaction to keep the trigger clean
2424
await reaction.users.remove(user.id).catch(() => {});
2525

26-
// Enforce one open ticket per user: if a category with their ticket name exists, ping them in their ticket text channel instead of creating a new one.
27-
const existingCategory: any = guild.channels.cache.find(
28-
(ch: any) => ch.type === 4 && ch.name === `ticket-${user.username}`,
29-
);
30-
if (existingCategory) {
31-
const ticketText = guild.channels.cache.find(
32-
(ch: any) =>
33-
ch.parentId === existingCategory.id && ch.name === `ticket-${user.username}-txt`,
34-
);
26+
const openTickets = cfg.openTickets || {};
27+
const existingTicket = openTickets[user.id];
28+
29+
// Enforce one open ticket per user: if exists, ping in their ticket text channel
30+
if (existingTicket) {
31+
const ticketText = existingTicket.textId
32+
? guild.channels.cache.get(existingTicket.textId)
33+
: guild.channels.cache.find(
34+
(ch: any) =>
35+
ch.parentId === existingTicket.categoryId &&
36+
ch.name === `ticket-${user.username}-txt`,
37+
);
3538
const notifyPayload = {
3639
content: `<@${user.id}> ya tienes un ticket abierto.`,
3740
flags: EPHEMERAL_FLAG,
3841
};
3942
if (ticketText && ticketText.isTextBased?.()) {
40-
await ticketText.send(notifyPayload).catch(() => {});
43+
await (ticketText as any).send(notifyPayload).catch(() => {});
4144
} else {
4245
await reaction.message.channel.send(notifyPayload).catch(() => {});
4346
}
@@ -79,6 +82,10 @@ export default {
7982
})),
8083
});
8184

85+
// Persist open ticket for this user
86+
openTickets[user.id] = { categoryId: category.id, textId: text.id, voiceId: voice.id };
87+
upsertGuildConfig({ ...cfg, guildId: guild.id, openTickets });
88+
8289
const embed = buildEmbed({
8390
title: 'Ticket creado',
8491
description: 'Un miembro de JUNTA te atenderá pronto.',

0 commit comments

Comments
 (0)