diff --git a/broccolini-discord.js b/broccolini-discord.js index b72cca3..20f4f1e 100644 --- a/broccolini-discord.js +++ b/broccolini-discord.js @@ -99,6 +99,40 @@ client.on('interactionCreate', async interaction => { if (handled) return; } + if (interaction.isModalSubmit() && interaction.customId.startsWith('signature_modal_')) { + // Handle signature modal submit + try { + const valediction = interaction.fields.getTextInputValue('valediction'); + const displayName = interaction.fields.getTextInputValue('display_name'); + const tagline = interaction.fields.getTextInputValue('tagline'); + + const StaffSignature = mongoose.model('StaffSignature'); + await StaffSignature.findOneAndUpdate( + { userId: interaction.user.id }, + { + userId: interaction.user.id, + valediction, + displayName, + tagline, + updatedAt: new Date() + }, + { upsert: true, new: true } + ); + + await interaction.reply({ + content: 'Signature settings saved successfully!', + ephemeral: true + }); + } catch (err) { + console.error('Signature modal submit error:', err); + await interaction.reply({ + content: 'Failed to save signature settings.', + ephemeral: true + }); + } + return; + } + if (interaction.isModalSubmit() && ['ticket_modal', 'ticket_modal_thread', 'ticket_modal_channel'].includes(interaction.customId)) { return handleTicketModal(interaction); } diff --git a/commands/register.js b/commands/register.js index c525063..2edc0b1 100644 --- a/commands/register.js +++ b/commands/register.js @@ -572,8 +572,14 @@ async function registerCommands() { .addUserOption(opt => opt.setName('user').setDescription('Discord user').setRequired(true) ) - ) - ]; + ), + + new SlashCommandBuilder() + .setName('signature') + .setDescription('Set your personal email signature (valediction, display name, tagline)') + .setContexts([InteractionContextType.Guild]) + .setIntegrationTypes([ApplicationIntegrationType.GuildInstall]) + .setDefaultMemberPermissions(PermissionFlagsBits.ManageMessages) const contextMenuCommands = [ new ContextMenuCommandBuilder() diff --git a/handlers/commands.js b/handlers/commands.js index bc7c989..2191b04 100644 --- a/handlers/commands.js +++ b/handlers/commands.js @@ -874,6 +874,57 @@ async function handleCommand(interaction) { } } + // /signature + if (interaction.commandName === 'signature') { + try { + await interaction.deferReply({ ephemeral: true }); + + // Fetch existing signature data if it exists + const StaffSignature = mongoose.model('StaffSignature'); + const existingSignature = await StaffSignature.findOne({ userId: interaction.user.id }).lean(); + + // Create modal + const { ModalBuilder, ActionRowBuilder, TextInputBuilder, TextInputStyle } = require('discord.js'); + const modal = new ModalBuilder() + .setCustomId(`signature_modal_${interaction.user.id}`) + .setTitle('Staff Signature Settings'); + + // Add text inputs to modal + const valedictionInput = new TextInputBuilder() + .setCustomId('valediction') + .setLabel('Valediction (e.g. "Best regards", "Thanks")') + .setStyle(TextInputStyle.Short) + .setRequired(false) + .setValue(existingSignature?.valediction || ''); + + const displayNameInput = new TextInputBuilder() + .setCustomId('display_name') + .setLabel('Display Name (e.g. "Support Team")') + .setStyle(TextInputStyle.Short) + .setRequired(false) + .setValue(existingSignature?.displayName || ''); + + const taglineInput = new TextInputBuilder() + .setCustomId('tagline') + .setLabel('Tagline (e.g. "Technical Support Specialist")') + .setStyle(TextInputStyle.Short) + .setRequired(false) + .setValue(existingSignature?.tagline || ''); + + const valedictionRow = new ActionRowBuilder().addComponents(valedictionInput); + const displayNameRow = new ActionRowBuilder().addComponents(displayNameInput); + const taglineRow = new ActionRowBuilder().addComponents(taglineInput); + + modal.addComponents(valedictionRow, displayNameRow, taglineRow); + + await interaction.showModal(modal); + } catch (err) { + console.error('Signature command error:', err); + await interaction.editReply({ content: 'Failed to open signature settings.', ephemeral: true }); + } + return; + } + // /accountinfo if (interaction.commandName === 'accountinfo') { await handleAccountInfoCommand(interaction); diff --git a/models.js b/models.js index 618e860..345ccfb 100644 --- a/models.js +++ b/models.js @@ -860,9 +860,27 @@ mongoose.model('StaffSettings', new mongoose.Schema({ })); mongoose.model('StaffNotification', new mongoose.Schema({ + userId: { type: String, required: true, unique: true }, + guildId: String, + channelId: String, + cooldownHours: { type: Number, default: 1 }, + updatedAt: { type: Date, default: Date.now } +})); + +mongoose.model('StaffSignature', new mongoose.Schema({ + userId: { type: String, required: true, unique: true }, + guildId: { type: String, required: true }, + valediction: { type: String, default: '' }, + displayName: { type: String, default: '' }, + tagline: { type: String, default: '' }, + updatedAt: { type: Date, default: Date.now } +})); + +mongoose.model('StaffSignature', new mongoose.Schema({ userId: { type: String, required: true, unique: true }, - guildId: String, - channelId: String, - cooldownHours: { type: Number, default: 1 }, + guildId: { type: String, required: true }, + valediction: { type: String, default: '' }, + displayName: { type: String, default: '' }, + tagline: { type: String, default: '' }, updatedAt: { type: Date, default: Date.now } })); diff --git a/services/gmail.js b/services/gmail.js index af0962b..69ed16a 100644 --- a/services/gmail.js +++ b/services/gmail.js @@ -157,14 +157,63 @@ async function sendTicketClosedEmail(ticket, discordDisplayName) { } } +const { mongoose } = require('../db-connection'); +const StaffSignature = mongoose.model('StaffSignature'); + +/** + * Get formatted signature blocks (text and HTML) for a staff member + * @param {string} userId - Discord user ID + * @returns {Promise<{text: string, html: string}>} Signature blocks + */ +async function getStaffSignatureBlocks(userId) { + try { + const signature = await StaffSignature.findOne({ userId }).lean(); + + if (!signature) { + return { + text: '', + html: '' + }; + } + + const valediction = signature.valediction || ''; + const displayName = signature.displayName || ''; + const tagline = signature.tagline || ''; + + const textSignature = [ + valediction, + displayName, + tagline + ].filter(Boolean).join('\n'); + + const htmlSignature = [ + valediction ? `
${escapeHtml(valediction)}
` : '', + displayName ? `${escapeHtml(displayName)}
` : '', + tagline ? `${label}
-${label}
`} + ${signatureBlocks.html ? 'From: ${safeUser} on Discord
+${safeReply}
+|
+ ${safeLogoUrl ? ` |
+
+ ${signatureBlocks.html || ` ${safeUser} `} + ${signatureBlocks.html ? '' : ''} + ${signatureBlocks.html ? signatureBlocks.html : ` ${safeSignature} `}
+ |
+