@elara-services/tickets 4.0.7 → 4.0.9

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.
package/index.d.ts CHANGED
@@ -50,8 +50,12 @@ declare module "@elara-services/tickets" {
50
50
  ticket?: {
51
51
  category?: string;
52
52
  closeReason?: boolean;
53
+ supportCommentThread?: boolean;
53
54
  limitOnePerUser?: boolean;
54
55
  open?: Pick<MessageOptions, "content" | "embeds">
56
+ close?: {
57
+ confirm?: Pick<MessageOptions, "content" | "embeds">
58
+ }
55
59
  }
56
60
  }
57
61
 
@@ -40,6 +40,7 @@ module.exports = {
40
40
  CLOSED_TICKET: "closed the ticket.",
41
41
  FORM_RESPONSE: "Form Response",
42
42
  MODAL_CONTENT: "Content",
43
+ SUPPORT_TALK: "Support Talk",
43
44
  ONLY_SUPPORT: "Only support staff can close tickets",
44
45
  GO_TO_TICKET: "Go to ticket",
45
46
  CLOSE_TICKET: "Close Ticket",
package/lib/base.js CHANGED
@@ -2,7 +2,7 @@ const { getWebhookInfo, displayMessages, de, webhook, getString } = require("./u
2
2
  const {
3
3
  Interactions: { button },
4
4
  } = require("@elara-services/packages");
5
- const { is } = require("@elara-services/utils");
5
+ const { is, status, isV13 } = require("@elara-services/utils");
6
6
  const { WebhookClient } = require("discord.js");
7
7
  const required = ["client", "prefix", "encryptToken"];
8
8
 
@@ -34,6 +34,7 @@ module.exports = class Tickets {
34
34
  return {
35
35
  roles: this.options.support?.roles || [],
36
36
  users: this.options.support?.users || [],
37
+ empty: [...(this.options.support?.roles || []), ...(this.options.support?.users || [])].length ? false : true,
37
38
  };
38
39
  }
39
40
 
@@ -51,6 +52,62 @@ module.exports = class Tickets {
51
52
  return this;
52
53
  }
53
54
 
55
+ get manage() {
56
+ return {
57
+ add: async (channelId, userId, permType = "member") => {
58
+ const channel = this.options.client.channels.resolve(channelId);
59
+ if (!channel) {
60
+ return status.error(`Unable to find (${channelId}) channel`);
61
+ }
62
+ let mod = permType === "mod";
63
+ let perms = {};
64
+ if (isV13()) {
65
+ perms = {
66
+ VIEW_CHANNEL: true,
67
+ SEND_MESSAGES: true,
68
+ READ_MESSAGE_HISTORY: true,
69
+ ATTACH_FILES: true,
70
+ EMBED_LINKS: true,
71
+ USE_EXTERNAL_EMOJIS: true,
72
+ };
73
+ if (mod) {
74
+ perms["MANAGE_MESSAGES"] = true;
75
+ perms["MANAGE_THREADS"] = true;
76
+ }
77
+ } else {
78
+ perms = {
79
+ ViewChannel: true,
80
+ SendMessages: true,
81
+ ReadMessageHistory: true,
82
+ AttachFiles: true,
83
+ EmbedLinks: true,
84
+ UseExternalEmojis: true,
85
+ };
86
+ if (mod) {
87
+ perms["ManageMessages"] = true;
88
+ perms["ManageThreads"] = true;
89
+ }
90
+ }
91
+ return channel.permissionOverwrites
92
+ .edit(userId, perms, {
93
+ reason: `Added to the ticket.`,
94
+ })
95
+ .then(() => status.success(`Added to the ticket.`))
96
+ .catch((e) => status.error(e.message || e));
97
+ },
98
+ remove: async (channelId, userId) => {
99
+ const channel = this.options.client.channels.resolve(channelId);
100
+ if (!channel) {
101
+ return status.error(`Unable to find (${channelId}) channel`);
102
+ }
103
+ return channel.permissionOverwrites
104
+ .delete(userId, `Removed from the ticket.`)
105
+ .then(() => status.success(`Removed from the ticket.`))
106
+ .catch((e) => status.error(e.message || e));
107
+ },
108
+ };
109
+ }
110
+
54
111
  /**
55
112
  * @param {keyof typeof import("../languages/en-US")} name
56
113
  */
@@ -83,6 +140,14 @@ module.exports = class Tickets {
83
140
  emoji: options.emoji,
84
141
  });
85
142
  }
143
+ /**
144
+ * @param {object} opts
145
+ * @param {import("discord.js").GuildMember} opts.member
146
+ * @param {import("discord.js").TextChannel} opts.channel
147
+ * @param {import("discord.js").Guild} opts.guild
148
+ * @param {import("discord.js").User} opts.user
149
+ * @param {string} opts.reason
150
+ */
86
151
  async closeTicket({ member, messages, channel, guild, user, reason } = {}) {
87
152
  const { id, token, username, avatar: avatarURL, threadId } = this.webhookOptions;
88
153
  if (!id || !token) {
package/lib/v13.js CHANGED
@@ -45,12 +45,12 @@ module.exports = class Tickets extends base {
45
45
  */
46
46
  const send = async (options = {}, defer = false) => {
47
47
  if (defer) {
48
- return int.deferReply(options).catch(this._debug);
48
+ return int.deferReply(options).catch((e) => this._debug(e));
49
49
  }
50
50
  if (int.replied || int.deferred) {
51
- return int.editReply(options).catch(this._debug);
51
+ return int.editReply(options).catch((e) => this._debug(e));
52
52
  }
53
- return int.reply(options).catch(this._debug);
53
+ return int.reply(options).catch((e) => this._debug(e));
54
54
  };
55
55
  switch (customId) {
56
56
  case this.prefix: {
@@ -87,7 +87,7 @@ module.exports = class Tickets extends base {
87
87
  { prefix: this.prefix, str: (name) => this.str(name, this?.options?.lang) },
88
88
  ),
89
89
  )
90
- .catch(this._debug);
90
+ .catch((e) => this._debug(e));
91
91
  }
92
92
  return this.handleCreate({ guild, member, category, send });
93
93
  }
@@ -111,15 +111,24 @@ module.exports = class Tickets extends base {
111
111
  }
112
112
  }
113
113
  }
114
+ let embs = await Promise.all(
115
+ (
116
+ this.options.ticket?.close?.confirm?.embeds || [
117
+ embed(undefined, {
118
+ description: this.str("TICKET_CLOSE_CONFIRM"),
119
+ title: `INFO`,
120
+ color: 0xff000,
121
+ guild,
122
+ str: (name) => this.str(name, this?.options?.lang),
123
+ }),
124
+ ]
125
+ ).map((c) => parser(c, { guild, member, user: member.user })),
126
+ );
127
+ const content = this.options.ticket?.close?.confirm?.content || ``;
114
128
  return send({
115
129
  ephemeral: true,
116
- embeds: [
117
- embed(this.str("TICKET_CLOSE_CONFIRM"), {
118
- color: 0xff000,
119
- guild,
120
- str: (name) => this.str(name, this?.options?.lang),
121
- }),
122
- ],
130
+ content,
131
+ embeds: [embs],
123
132
  components: [
124
133
  {
125
134
  type: 1,
@@ -216,7 +225,7 @@ module.exports = class Tickets extends base {
216
225
  embeds: [embed(this.str("NO_MESSAGES_FETCHED"), { str: (name) => this.str(name, this?.options?.lang) })],
217
226
  });
218
227
  }
219
- let closed = await channel.delete(`${member.user.tag} (${member.id}) ${this.str("CLOSED_TICKET")}`).catch(this._debug);
228
+ let closed = await channel.delete(`${member.user.tag} (${member.id}) ${this.str("CLOSED_TICKET")}`).catch((e) => this._debug(e));
220
229
  if (!closed) {
221
230
  return send({
222
231
  embeds: [embed(this.str("NO_CHANNEL_DELETE"), { str: (name) => this.str(name, this?.options?.lang) })],
@@ -259,7 +268,7 @@ module.exports = class Tickets extends base {
259
268
  ephemeral: true,
260
269
  });
261
270
  }
262
- return int.showModal(defs.modals.unbanReason(customId, server, (name) => this.str(name, this?.options?.lang), member, this.prefix)).catch(this._debug);
271
+ return int.showModal(defs.modals.unbanReason(customId, server, (name) => this.str(name, this?.options?.lang), member, this.prefix)).catch((e) => this._debug(e));
263
272
  }
264
273
 
265
274
  if (customId.startsWith(`${this.prefix}:unban_modal:`)) {
@@ -287,7 +296,7 @@ module.exports = class Tickets extends base {
287
296
  embeds: [embed(this.str("NO_BAN_PERMS_USER_IN_APPEAL_SERVER")(server), { str: (name) => this.str(name, this?.options?.lang) })],
288
297
  });
289
298
  }
290
- let isBanned = await server.bans.fetch({ user: id, force: true }).catch(this._debug);
299
+ let isBanned = await server.bans.fetch({ user: id, force: true }).catch((e) => this._debug(e));
291
300
  if (!isBanned) {
292
301
  return send({
293
302
  embeds: [embed(this.str("USER_NOT_BANNED")(id), { str: (name) => this.str(name, this?.options?.lang) })],
@@ -313,7 +322,7 @@ module.exports = class Tickets extends base {
313
322
  },
314
323
  ],
315
324
  })
316
- .catch(this._debug);
325
+ .catch((e) => this._debug(e));
317
326
  send({
318
327
  embeds: [embed(this.str("UNBAN_SUCCESS")(id, server.name), { str: (name) => this.str(name, this?.options?.lang) })],
319
328
  });
@@ -371,7 +380,7 @@ module.exports = class Tickets extends base {
371
380
  if (appeals?.enabled) {
372
381
  let server = getAppealServer(this.options);
373
382
  if (server) {
374
- let ban = await server.bans.fetch({ user: member.id, force: true }).catch(this._debug);
383
+ let ban = await server.bans.fetch({ user: member.id, force: true }).catch((e) => this._debug(e));
375
384
  if (!ban) {
376
385
  return send(
377
386
  typeof appeals.embeds?.not_banned === "object"
@@ -433,7 +442,7 @@ module.exports = class Tickets extends base {
433
442
  ...permissions,
434
443
  ],
435
444
  })
436
- .catch(this._debug);
445
+ .catch((e) => this._debug(e));
437
446
  if (!channel) {
438
447
  return send({ embeds: [embed(this.str("NO_CHANNEL_CREATE"), { str: (name) => this.str(name, this?.options?.lang) })] });
439
448
  }
@@ -473,16 +482,32 @@ module.exports = class Tickets extends base {
473
482
  roles: [...this.getSupportIds.roles],
474
483
  },
475
484
  })
476
- .catch(this._debug);
485
+ .catch((e) => this._debug(e));
477
486
  if (!msg) {
478
487
  return null;
479
488
  }
480
489
  if (sendBanReason) {
481
- await channel.send(sendBanReason).catch(this._debug);
490
+ await channel.send(sendBanReason).catch((e) => this._debug(e));
482
491
  }
483
492
  if (embeds?.length <= 10) {
484
493
  for await (const embed of embeds) {
485
- await channel.send({ embeds: [embed] }).catch(this._debug);
494
+ await channel.send({ embeds: [embed] }).catch((e) => this._debug(e));
495
+ }
496
+ }
497
+ if (this.options.ticket?.supportCommentThread === true) {
498
+ const thread = await channel.threads
499
+ .create({
500
+ name: this.str("SUPPORT_TALK"),
501
+ invitable: false,
502
+ type: 12,
503
+ })
504
+ .catch((e) => this._debug(e));
505
+ if (thread && !this.getSupportIds.empty) {
506
+ await thread
507
+ .send({
508
+ content: `${this.getSupportIds.roles.length ? this.getSupportIds.roles.map((c) => `<@&${c}>`).join(" ") : ""}${this.getSupportIds.users.length ? `${this.getSupportIds.roles.length ? ` | ` : ""}${this.getSupportIds.users.map((c) => `<@${c}>`).join(" ")}` : ""}`,
509
+ })
510
+ .catch((e) => this._debug(e));
486
511
  }
487
512
  }
488
513
  if (this.webhookOptions.id && this.webhookOptions.token) {
@@ -499,7 +524,7 @@ module.exports = class Tickets extends base {
499
524
  }),
500
525
  )
501
526
  .send()
502
- .catch(this._debug);
527
+ .catch((e) => this._debug(e));
503
528
  }
504
529
  return send({
505
530
  embeds: [
package/lib/v14.js CHANGED
@@ -41,12 +41,12 @@ module.exports = class Tickets extends base {
41
41
  */
42
42
  const send = async (options = {}, defer = false) => {
43
43
  if (defer) {
44
- return int.deferReply(options).catch(this._debug);
44
+ return int.deferReply(options).catch((e) => this._debug(e));
45
45
  }
46
46
  if (int.replied || int.deferred) {
47
- return int.editReply(options).catch(this._debug);
47
+ return int.editReply(options).catch((e) => this._debug(e));
48
48
  }
49
- return int.reply(options).catch(this._debug);
49
+ return int.reply(options).catch((e) => this._debug(e));
50
50
  };
51
51
  switch (customId) {
52
52
  case this.prefix: {
@@ -83,7 +83,7 @@ module.exports = class Tickets extends base {
83
83
  { prefix: this.prefix, str: (name) => this.str(name, this?.options?.lang) },
84
84
  ),
85
85
  )
86
- .catch(this._debug);
86
+ .catch((e) => this._debug(e));
87
87
  }
88
88
  return this.handleCreate({ guild, member, category, send });
89
89
  }
@@ -193,7 +193,7 @@ module.exports = class Tickets extends base {
193
193
  }
194
194
  if (customId.startsWith(`${this.prefix}:close:confirm`)) {
195
195
  if (customId.includes(`:modal_submit`)) {
196
- return int.showModal(defs.modals.reason(customId, (name) => this.str(name, this?.options?.lang))).catch(this._debug);
196
+ return int.showModal(defs.modals.reason(customId, (name) => this.str(name, this?.options?.lang))).catch((e) => this._debug(e));
197
197
  }
198
198
  await send({ ephemeral: true }, true);
199
199
  let reason = this.str("NO_REASON");
@@ -212,7 +212,7 @@ module.exports = class Tickets extends base {
212
212
  embeds: [embed(this.str("NO_MESSAGES_FETCHED"), { str: (name) => this.str(name, this?.options?.lang) })],
213
213
  });
214
214
  }
215
- let closed = await channel.delete(`${member.user.tag} (${member.id}) closed the ticket.`).catch(this._debug);
215
+ let closed = await channel.delete(`${member.user.tag} (${member.id}) closed the ticket.`).catch((e) => this._debug(e));
216
216
  if (!closed) {
217
217
  return send({
218
218
  embeds: [embed(this.str("NO_CHANNEL_DELETE"), { str: (name) => this.str(name, this?.options?.lang) })],
@@ -255,7 +255,7 @@ module.exports = class Tickets extends base {
255
255
  ephemeral: true,
256
256
  });
257
257
  }
258
- return int.showModal(defs.modals.unbanReason(customId, server, (name) => this.str(name, this?.options?.lang), member, this.prefix)).catch(this._debug);
258
+ return int.showModal(defs.modals.unbanReason(customId, server, (name) => this.str(name, this?.options?.lang), member, this.prefix)).catch((e) => this._debug(e));
259
259
  }
260
260
 
261
261
  if (customId.startsWith(`${this.prefix}:unban_modal:`)) {
@@ -283,7 +283,7 @@ module.exports = class Tickets extends base {
283
283
  embeds: [embed(this.str("NO_BAN_PERMS_USER_IN_APPEAL_SERVER")(server), { str: (name) => this.str(name, this?.options?.lang) })],
284
284
  });
285
285
  }
286
- let isBanned = await server.bans.fetch({ user: id, force: true }).catch(this._debug);
286
+ let isBanned = await server.bans.fetch({ user: id, force: true }).catch((e) => this._debug(e));
287
287
  if (!isBanned) {
288
288
  return send({
289
289
  embeds: [embed(this.str("USER_NOT_BANNED")(id), { str: (name) => this.str(name, this?.options?.lang) })],
@@ -309,7 +309,7 @@ module.exports = class Tickets extends base {
309
309
  },
310
310
  ],
311
311
  })
312
- .catch(this._debug);
312
+ .catch((e) => this._debug(e));
313
313
  send({
314
314
  embeds: [embed(this.str("UNBAN_SUCCESS")(id, server.name), { str: (name) => this.str(name, this?.options?.lang) })],
315
315
  });
@@ -335,7 +335,15 @@ module.exports = class Tickets extends base {
335
335
  }
336
336
  }
337
337
 
338
- /** @private */
338
+ /**
339
+ * @param {object} [opts]
340
+ * @param {import("discord.js").Guild} opts.guild
341
+ * @param {import("discord.js").GuildMember} opts.member
342
+ * @param {string} opts.category
343
+ * @param {Function} opts.send
344
+ * @param {import("discord.js").APIEmbed[]} opts.embeds
345
+ * @private
346
+ */
339
347
  async handleCreate({ guild, member, category, send, embeds = [] } = {}) {
340
348
  await send({ ephemeral: true }, true);
341
349
  let [permissions, { appeals }, sendBanReason] = [[], this.options ?? {}, null];
@@ -367,7 +375,7 @@ module.exports = class Tickets extends base {
367
375
  if (appeals?.enabled) {
368
376
  let server = getAppealServer(this.options);
369
377
  if (server) {
370
- let ban = await server.bans.fetch({ user: member.id, force: true }).catch(this._debug);
378
+ let ban = await server.bans.fetch({ user: member.id, force: true }).catch((e) => this._debug(e));
371
379
  if (!ban) {
372
380
  return send(
373
381
  typeof appeals.embeds?.not_banned === "object"
@@ -430,7 +438,7 @@ module.exports = class Tickets extends base {
430
438
  ...permissions,
431
439
  ],
432
440
  })
433
- .catch(this._debug);
441
+ .catch((e) => this._debug(e));
434
442
  if (!channel) {
435
443
  return send({ embeds: [embed(this.str("NO_CHANNEL_CREATE"), { str: (name) => this.str(name, this?.options?.lang) })] });
436
444
  }
@@ -470,16 +478,32 @@ module.exports = class Tickets extends base {
470
478
  roles: [...this.getSupportIds.roles],
471
479
  },
472
480
  })
473
- .catch(this._debug);
481
+ .catch((e) => this._debug(e));
474
482
  if (!msg) {
475
483
  return null;
476
484
  }
477
485
  if (sendBanReason) {
478
- await channel.send(sendBanReason).catch(this._debug);
486
+ await channel.send(sendBanReason).catch((e) => this._debug(e));
479
487
  }
480
488
  if (embeds?.length <= 10) {
481
489
  for await (const embed of embeds) {
482
- await channel.send({ embeds: [embed] }).catch(this._debug);
490
+ await channel.send({ embeds: [embed] }).catch((e) => this._debug(e));
491
+ }
492
+ }
493
+ if (this.options.ticket?.supportCommentThread === true) {
494
+ const thread = await channel.threads
495
+ .create({
496
+ name: this.str("SUPPORT_TALK"),
497
+ invitable: false,
498
+ type: 12,
499
+ })
500
+ .catch((e) => this._debug(e));
501
+ if (thread && !this.getSupportIds.empty) {
502
+ await thread
503
+ .send({
504
+ content: `${this.getSupportIds.roles.length ? this.getSupportIds.roles.map((c) => `<@&${c}>`).join(" ") : ""}${this.getSupportIds.users.length ? `${this.getSupportIds.roles.length ? ` | ` : ""}${this.getSupportIds.users.map((c) => `<@${c}>`).join(" ")}` : ""}`,
505
+ })
506
+ .catch((e) => this._debug(e));
483
507
  }
484
508
  }
485
509
  if (this.webhookOptions.id && this.webhookOptions.token) {
@@ -496,7 +520,7 @@ module.exports = class Tickets extends base {
496
520
  }),
497
521
  )
498
522
  .send()
499
- .catch(this._debug);
523
+ .catch((e) => this._debug(e));
500
524
  }
501
525
  return send({
502
526
  embeds: [
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@elara-services/tickets",
3
- "version": "4.0.7",
3
+ "version": "4.0.9",
4
4
  "description": "Helper for tickets",
5
5
  "main": "index.js",
6
6
  "types": "index.d.ts",
@@ -17,9 +17,9 @@
17
17
  "pc": "prettier --check **/**/*.js"
18
18
  },
19
19
  "dependencies": {
20
- "@elara-services/packages": "^6.0.7",
21
- "@elara-services/utils": "^1.2.33",
22
- "@elara-services/webhooks": "^2.1.9"
20
+ "@elara-services/packages": "^6.0.8",
21
+ "@elara-services/utils": "^1.3.1",
22
+ "@elara-services/webhooks": "^2.1.10"
23
23
  },
24
24
  "devDependencies": {
25
25
  "eslint": "8.20.0",