Skip to content

Commit 6c95cbd

Browse files
committed
Reverting the accidental ticket changes while keeping CONTRIBUTING.md and README.md.
1 parent 6676dc5 commit 6c95cbd

6 files changed

Lines changed: 77 additions & 812 deletions

File tree

src/commands/Ticket/modules/ticket_dashboard.js

Lines changed: 55 additions & 200 deletions
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,6 @@ import {
1515
MessageFlags,
1616
ComponentType,
1717
EmbedBuilder,
18-
LabelBuilder,
19-
FileUploadBuilder,
20-
TextDisplayBuilder,
2118
} from 'discord.js';
2219
import { InteractionHelper } from '../../../utils/interactionHelper.js';
2320
import { successEmbed, infoEmbed } from '../../../utils/embeds.js';
@@ -29,20 +26,10 @@ import { getGuildTicketStats } from '../../../utils/database/tickets.js';
2926
import { getUserTicketCount } from '../../../services/ticket.js';
3027
import {
3128
getTicketPanelStatus,
32-
messageHasButtonCustomIdPrefix,
29+
messageHasButtonCustomId,
3330
formatPanelStatusField,
3431
} from '../../../utils/panelStatus.js';
3532
import { startDashboardSession } from '../../../utils/dashboardSession.js';
36-
import {
37-
MAX_TICKET_PANEL_BUTTONS,
38-
buildTicketPanelEmbed,
39-
buildTicketPanelButtonRows,
40-
formatPanelButtonCombinedValue,
41-
getTicketPanelButtons,
42-
normalizeTicketPanelConfig,
43-
parsePanelButtonCombinedFields,
44-
validatePanelImageUrl,
45-
} from '../../../utils/ticketPanel.js';
4633

4734
function buildButtonRow(guildConfig, guildId, disabled = false, panelStatus = null) {
4835
const dmEnabled = guildConfig.dmOnClose !== false;
@@ -93,6 +80,23 @@ async function persistPanelMessageId(client, guildId, guildConfig, messageId) {
9380
}
9481
}
9582

83+
function buildPanelEmbed(config) {
84+
return new EmbedBuilder()
85+
.setTitle('Support Tickets')
86+
.setDescription(config.ticketPanelMessage || 'Click the button below to create a support ticket.')
87+
.setColor(getColor('info'));
88+
}
89+
90+
function buildPanelButtonRow(config) {
91+
return new ActionRowBuilder().addComponents(
92+
new ButtonBuilder()
93+
.setCustomId('create_ticket')
94+
.setLabel(config.ticketButtonLabel || 'Create Ticket')
95+
.setStyle(ButtonStyle.Primary)
96+
.setEmoji('📩'),
97+
);
98+
}
99+
96100
async function repostTicketPanel(client, guild, guildConfig, guildId) {
97101
const channel = await guild.channels.fetch(guildConfig.ticketPanelChannelId).catch(() => null);
98102
if (!channel) {
@@ -104,8 +108,8 @@ async function repostTicketPanel(client, guild, guildConfig, guildId) {
104108
}
105109

106110
const sentPanel = await channel.send({
107-
embeds: [buildTicketPanelEmbed(guildConfig)],
108-
components: buildTicketPanelButtonRows(guildConfig),
111+
embeds: [buildPanelEmbed(guildConfig)],
112+
components: [buildPanelButtonRow(guildConfig)],
109113
});
110114

111115
await persistPanelMessageId(client, guildId, guildConfig, sentPanel.id);
@@ -134,7 +138,7 @@ function buildDashboardEmbed(config, guild, panelStatus = null, ticketStats = nu
134138

135139
const rawMsg = config.ticketPanelMessage || 'Click the button below to create a support ticket.';
136140
const panelMsg = `\`${rawMsg.length > 60 ? rawMsg.substring(0, 60) + '…' : rawMsg}\``;
137-
const panelBanner = config.ticketPanelImage ? `[View banner](${config.ticketPanelImage})` : '`Not set`';
141+
const btnLabel = `\`${config.ticketButtonLabel || 'Create Ticket'}\``;
138142

139143
let panelStatusValue = formatPanelStatusField(panelStatus);
140144

@@ -157,7 +161,7 @@ function buildDashboardEmbed(config, guild, panelStatus = null, ticketStats = nu
157161
{ name: 'Closed Tickets Category', value: closedCategory, inline: true },
158162
{ name: '\u200B', value: '\u200B', inline: true },
159163
{ name: 'Panel Message', value: panelMsg, inline: false },
160-
{ name: 'Panel Banner', value: panelBanner, inline: true },
164+
{ name: 'Button Label', value: btnLabel, inline: true },
161165
{ name: 'Max Tickets/User', value: String(config.maxTicketsPerUser || 3), inline: true },
162166
{ name: 'DM on Close', value: config.dmOnClose !== false ? 'Enabled' : 'Disabled', inline: true },
163167
{ name: 'Ticket Logs Channel', value: ticketLogsChannel, inline: true },
@@ -182,14 +186,9 @@ function buildSelectMenu(guildId) {
182186
.setValue('panel_message')
183187
.setEmoji('📝'),
184188
new StringSelectMenuOptionBuilder()
185-
.setLabel('Edit Panel Banner')
186-
.setDescription('Add or remove a banner image on the ticket panel embed')
187-
.setValue('panel_banner')
188-
.setEmoji('🖼️'),
189-
new StringSelectMenuOptionBuilder()
190-
.setLabel('Manage Panel Buttons')
191-
.setDescription('Set emoji + label for up to 5 panel buttons in one modal')
192-
.setValue('panel_buttons')
189+
.setLabel('Edit Button Label')
190+
.setDescription('Change the label on the Create Ticket button')
191+
.setValue('button_label')
193192
.setEmoji('🏷️'),
194193
new StringSelectMenuOptionBuilder()
195194
.setLabel('Change Open Tickets Category')
@@ -247,8 +246,8 @@ async function updateLivePanel(client, guild, config, guildId) {
247246
if (!panelStatus.exists || !panelStatus.message) return false;
248247

249248
await panelStatus.message.edit({
250-
embeds: [buildTicketPanelEmbed(config)],
251-
components: buildTicketPanelButtonRows(config),
249+
embeds: [buildPanelEmbed(config)],
250+
components: [buildPanelButtonRow(config)],
252251
});
253252
return true;
254253
} catch (error) {
@@ -298,11 +297,8 @@ export default {
298297
case 'panel_message':
299298
await handlePanelMessage(selectInteraction, interaction, guildConfig, guildId, client);
300299
break;
301-
case 'panel_banner':
302-
await handlePanelBanner(selectInteraction, interaction, guildConfig, guildId, client);
303-
break;
304-
case 'panel_buttons':
305-
await handlePanelButtons(selectInteraction, interaction, guildConfig, guildId, client);
300+
case 'button_label':
301+
await handleButtonLabel(selectInteraction, interaction, guildConfig, guildId, client);
306302
break;
307303
case 'staff_role':
308304
await handleStaffRole(selectInteraction, interaction, guildConfig, guildId, client);
@@ -373,7 +369,7 @@ async function handlePanelMessage(selectInteraction, rootInteraction, guildConfi
373369

374370
const submitted = await selectInteraction
375371
.awaitModalSubmit({
376-
filter: (i) =>
372+
filter: i =>
377373
i.customId === 'ticket_cfg_panel_msg' && i.user.id === selectInteraction.user.id,
378374
time: 120_000,
379375
})
@@ -404,188 +400,51 @@ async function handlePanelMessage(selectInteraction, rootInteraction, guildConfi
404400
await refreshDashboard(rootInteraction, guildConfig, guildId, client);
405401
}
406402

407-
async function handlePanelBanner(selectInteraction, rootInteraction, guildConfig, guildId, client) {
408-
const modal = new ModalBuilder()
409-
.setCustomId('ticket_cfg_panel_banner')
410-
.setTitle('🖼️ Edit Panel Banner');
411-
412-
const imageHint = new TextDisplayBuilder().setContent(
413-
'Provide a direct image URL **or** upload a file below. If both are given, the uploaded file takes priority. Leave the URL blank and skip the upload to remove the banner.\n\n**Note:** Uploaded files use Discord\'s CDN and may stop working over time. For a permanent panel banner, use a hosted URL (Imgur, your website, etc.).',
414-
);
415-
416-
const urlLabel = new LabelBuilder()
417-
.setLabel('Image URL (optional)')
418-
.setTextInputComponent(
419-
new TextInputBuilder()
420-
.setCustomId('panel_banner_input')
421-
.setPlaceholder('https://example.com/banner.png')
422-
.setStyle(TextInputStyle.Short)
423-
.setValue(guildConfig.ticketPanelImage || '')
424-
.setRequired(false),
425-
);
426-
427-
const uploadLabel = new LabelBuilder()
428-
.setLabel('Or upload an image file (optional)')
429-
.setFileUploadComponent(
430-
new FileUploadBuilder().setCustomId('panel_banner_upload').setRequired(false),
431-
);
432-
433-
modal.addTextDisplayComponents(imageHint).addLabelComponents(urlLabel, uploadLabel);
434-
435-
try {
436-
await selectInteraction.showModal(modal);
437-
} catch {
438-
return;
439-
}
440-
441-
const submitted = await selectInteraction
442-
.awaitModalSubmit({
443-
filter: (i) =>
444-
i.customId === 'ticket_cfg_panel_banner' && i.user.id === selectInteraction.user.id,
445-
time: 120_000,
446-
})
447-
.catch(() => null);
448-
449-
if (!submitted) return;
450-
451-
const uploadedFiles = submitted.fields.getUploadedFiles('panel_banner_upload');
452-
let imageUrl =
453-
uploadedFiles?.at(0)?.url ?? submitted.fields.getTextInputValue('panel_banner_input').trim();
454-
455-
const validation = validatePanelImageUrl(imageUrl);
456-
if (!validation.ok) {
457-
await replyUserError(submitted, { type: ErrorTypes.VALIDATION, message: validation.error });
458-
return;
459-
}
460-
461-
if (validation.url) {
462-
guildConfig.ticketPanelImage = validation.url;
463-
} else {
464-
delete guildConfig.ticketPanelImage;
465-
}
466-
467-
await client.db.set(getGuildConfigKey(guildId), guildConfig);
468-
469-
const panelUpdated = await updateLivePanel(client, rootInteraction.guild, guildConfig, guildId);
470-
471-
await submitted.reply({
472-
embeds: [
473-
successEmbed(
474-
validation.url ? '✅ Panel Banner Updated' : '✅ Panel Banner Removed',
475-
(validation.url
476-
? 'The panel banner has been updated.'
477-
: 'The panel banner has been removed.') +
478-
(panelUpdated
479-
? '\nThe live ticket panel has also been refreshed.'
480-
: '\n> **Note:** The live panel could not be located. Use **Repost Panel** on the dashboard to restore it.'),
481-
),
482-
],
483-
flags: MessageFlags.Ephemeral,
484-
});
485-
486-
await refreshDashboard(rootInteraction, guildConfig, guildId, client);
487-
}
488-
489-
function buildPanelButtonModal(guildConfig) {
490-
const currentButtons = getTicketPanelButtons(guildConfig);
403+
async function handleButtonLabel(selectInteraction, rootInteraction, guildConfig, guildId, client) {
491404
const modal = new ModalBuilder()
492-
.setCustomId('ticket_cfg_panel_buttons')
493-
.setTitle('Manage Panel Buttons');
494-
495-
const labelComponents = [];
496-
497-
for (let index = 1; index <= MAX_TICKET_PANEL_BUTTONS; index += 1) {
498-
const button = currentButtons[index - 1];
499-
const label = new LabelBuilder()
500-
.setLabel(index === 1 ? 'Button 1 (required)' : `Button ${index} (optional)`)
501-
.setTextInputComponent(
405+
.setCustomId('ticket_cfg_btn_label')
406+
.setTitle('🏷️ Edit Button Label')
407+
.addComponents(
408+
new ActionRowBuilder().addComponents(
502409
new TextInputBuilder()
503-
.setCustomId(`btn_${index}_combined`)
410+
.setCustomId('btn_label_input')
411+
.setLabel('Button Label (max 80 characters)')
504412
.setStyle(TextInputStyle.Short)
505-
.setValue(button ? formatPanelButtonCombinedValue(button) : '')
506-
.setMaxLength(90)
507-
.setRequired(index === 1)
508-
.setPlaceholder(
509-
index === 1
510-
? '📩 Create Ticket or ticket Help'
511-
: '💳 Billing or support General',
512-
),
513-
);
514-
515-
if (index === 1) {
516-
label.setDescription(
517-
'Emoji + label. Paste 📩 Support, or type keywords like ticket, billing, support, help, bug, staff, mail.',
518-
);
519-
}
520-
521-
labelComponents.push(label);
522-
}
523-
524-
modal.addLabelComponents(...labelComponents);
525-
return modal;
526-
}
527-
528-
async function handlePanelButtons(selectInteraction, rootInteraction, guildConfig, guildId, client) {
529-
try {
530-
await selectInteraction.showModal(buildPanelButtonModal(guildConfig));
531-
} catch (error) {
532-
logger.warn('Panel button modal v2 unavailable, falling back to classic layout:', error.message);
533-
534-
const currentButtons = getTicketPanelButtons(guildConfig);
535-
const fallbackModal = new ModalBuilder()
536-
.setCustomId('ticket_cfg_panel_buttons')
537-
.setTitle('Manage Panel Buttons');
538-
539-
for (let index = 1; index <= MAX_TICKET_PANEL_BUTTONS; index += 1) {
540-
const button = currentButtons[index - 1];
541-
fallbackModal.addComponents(
542-
new ActionRowBuilder().addComponents(
543-
new TextInputBuilder()
544-
.setCustomId(`btn_${index}_combined`)
545-
.setLabel(index === 1 ? 'Button 1 (required)' : `Button ${index} (optional)`)
546-
.setStyle(TextInputStyle.Short)
547-
.setValue(button ? formatPanelButtonCombinedValue(button) : '')
548-
.setMaxLength(90)
549-
.setRequired(index === 1)
550-
.setPlaceholder(index === 1 ? '📩 Create Ticket' : '💳 Billing'),
551-
),
552-
);
553-
}
413+
.setValue(guildConfig.ticketButtonLabel || 'Create Ticket')
414+
.setMaxLength(80)
415+
.setMinLength(1)
416+
.setRequired(true)
417+
.setPlaceholder('Create Ticket'),
418+
),
419+
);
554420

555-
await selectInteraction.showModal(fallbackModal);
556-
}
421+
await selectInteraction.showModal(modal);
557422

558423
const submitted = await selectInteraction
559424
.awaitModalSubmit({
560-
filter: (i) =>
561-
i.customId === 'ticket_cfg_panel_buttons' && i.user.id === selectInteraction.user.id,
425+
filter: i =>
426+
i.customId === 'ticket_cfg_btn_label' && i.user.id === selectInteraction.user.id,
562427
time: 120_000,
563428
})
564429
.catch(() => null);
565430

566431
if (!submitted) return;
567432

568-
const parsed = parsePanelButtonCombinedFields(submitted.fields);
569-
if (!parsed.ok) {
570-
await replyUserError(submitted, { type: ErrorTypes.VALIDATION, message: parsed.error });
571-
return;
572-
}
573-
574-
guildConfig.ticketPanelButtons = parsed.buttons;
575-
normalizeTicketPanelConfig(guildConfig);
433+
const newLabel = submitted.fields.getTextInputValue('btn_label_input').trim();
434+
guildConfig.ticketButtonLabel = newLabel;
576435
await client.db.set(getGuildConfigKey(guildId), guildConfig);
577436

578437
const panelUpdated = await updateLivePanel(client, rootInteraction.guild, guildConfig, guildId);
579438

580439
await submitted.reply({
581440
embeds: [
582441
successEmbed(
583-
'✅ Panel Buttons Updated',
584-
`The panel now has **${parsed.buttons.length}** button${parsed.buttons.length !== 1 ? 's' : ''}.${
442+
'✅ Button Label Updated',
443+
`Button label changed to \`${newLabel}\`.${
585444
panelUpdated
586-
? '\n\nThe live ticket panel has also been refreshed.'
587-
: '\n\n> **Note:** The live panel could not be located. Use **Repost Panel** on the dashboard to restore it.'
588-
}\n\nAll buttons open the same ticket creation form.`,
445+
? '\nThe live ticket panel button has also been updated.'
446+
: '\n> **Note:** The live panel could not be located. Use **Repost Panel** on the dashboard to restore it.'
447+
}`,
589448
),
590449
],
591450
flags: MessageFlags.Ephemeral,
@@ -1094,8 +953,6 @@ async function handleDeleteSystem(btnInteraction, rootInteraction, guildConfig,
1094953
'ticketCategoryId',
1095954
'ticketClosedCategoryId',
1096955
'ticketPanelMessage',
1097-
'ticketPanelImage',
1098-
'ticketPanelButtons',
1099956
'ticketButtonLabel',
1100957
'maxTicketsPerUser',
1101958
'dmOnClose',
@@ -1113,9 +970,7 @@ async function handleDeleteSystem(btnInteraction, rootInteraction, guildConfig,
1113970
const messages = await panelChannel.messages.fetch({ limit: 50 }).catch(() => null);
1114971
if (messages) {
1115972
const found = messages.find(
1116-
(m) =>
1117-
m.author.id === client.user.id &&
1118-
messageHasButtonCustomIdPrefix(m, 'create_ticket'),
973+
m => m.author.id === client.user.id && messageHasButtonCustomId(m, 'create_ticket'),
1119974
);
1120975
if (found) await found.delete().catch(() => {});
1121976
}

0 commit comments

Comments
 (0)