-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathapplication.js
More file actions
346 lines (287 loc) · 13.9 KB
/
application.js
File metadata and controls
346 lines (287 loc) · 13.9 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
const { EmbedBuilder, ActionRowBuilder, ButtonBuilder, ButtonStyle } = require('discord.js');
const APPLICATION_CHANNEL_ID = '1426462066520358912';
// Store active applications (userId -> application data)
const activeApplications = new Map();
const applicationQuestions = [
{
id: 'ign',
question: '**What is your in-game username in Blue Protocol?**\nPlease provide your exact character name.',
field: 'In-Game Name'
},
{
id: 'power',
question: '**What is your current Power Level?**\nYou can find this in your character stats.',
field: 'Power Level'
},
{
id: 'activity',
question: '**How active will you be?**\nFor example: Daily, 3-4 times a week, weekends only, etc.',
field: 'Activity Level'
},
{
id: 'reason',
question: '**Why do you want to join Dawn | Starlight?**\nTell us what interests you about our guild!',
field: 'Reason for Joining'
},
{
id: 'experience',
question: '**What is your experience with Blue Protocol?**\nAre you new, returning, or a veteran player?',
field: 'Experience Level'
},
{
id: 'playstyle',
question: '**What is your preferred playstyle?**\nFor example: PvE, PvP, Casual, Competitive, etc.',
field: 'Playstyle'
},
{
id: 'additional',
question: '**Anything else you\'d like us to know?**\nFeel free to share anything else about yourself - hobbies, favorite games, fun facts, or whatever you want!',
field: 'Additional Comments'
}
];
async function handleApplicationCommand(interaction) {
console.log('[APPLICATION] Command started by', interaction.user.tag);
// Check if user already has an active application
if (activeApplications.has(interaction.user.id)) {
return interaction.reply({
content: '⚠️ You already have an application in progress! Please check your DMs to continue.',
flags: 64 // ephemeral
});
}
// Create the application embed for the channel
const embed = new EmbedBuilder()
.setTitle('**Blue Protocol Guild Application**')
.setAuthor({ name: '🌟 Dawn | Starlight 🌟', iconURL: interaction.guild.iconURL() })
.setColor(0x0099ff)
.setDescription('> Apply to join our Blue Protocol guild! Click the button below to start your application.\n\n**What to expect:**\n> • You will be sent a DM with a series of questions\n> • Answer each question one at a time\n> • Your application will be reviewed by our officers\n> • You will be notified of the decision')
.addFields(
{ name: '💫 **About Our Guild**', value: '> We are an active and friendly guild that welcomes players of all skill levels. Join us for raids, events, and a great community!' },
{ name: '📋 **Application Process**', value: '> 1️⃣ Click the "Apply Now" button\n> 2️⃣ Check your DMs from me\n> 3️⃣ Answer each question\n> 4️⃣ Wait for review (usually 24-48 hours)' }
)
.setFooter({ text: 'Dawn | Starlight', iconURL: interaction.guild.iconURL() })
.setTimestamp();
// Create apply button
const applyButton = new ButtonBuilder()
.setCustomId('bp_apply_button')
.setLabel('Apply Now')
.setEmoji('📝')
.setStyle(ButtonStyle.Primary);
const row = new ActionRowBuilder().addComponents(applyButton);
// Send to channel
await interaction.reply({ embeds: [embed], components: [row] });
console.log('[APPLICATION] Application embed posted');
}
async function handleApplicationButton(interaction) {
console.log('[APPLICATION] Button clicked by', interaction.user.tag);
// Check if user already has an active application
if (activeApplications.has(interaction.user.id)) {
return interaction.reply({
content: '⚠️ You already have an application in progress! Please check your DMs to continue.',
flags: 64 // ephemeral
});
}
// Defer the reply
await interaction.deferReply({ flags: 64 });
try {
// Try to DM the user
const dmChannel = await interaction.user.createDM();
// Initialize application data
activeApplications.set(interaction.user.id, {
userId: interaction.user.id,
username: interaction.user.tag,
guildId: interaction.guild.id,
guildName: interaction.guild.name,
startTime: Date.now(),
currentQuestion: 0,
answers: {}
});
// Send welcome message
const welcomeEmbed = new EmbedBuilder()
.setTitle('📝 Blue Protocol Guild Application')
.setColor(0x00ff00)
.setDescription(`Welcome ${interaction.user.username}! Thank you for your interest in joining **Dawn | Starlight**!\n\nI'll ask you a series of ${applicationQuestions.length} questions. Please answer each one in this DM.\n\nYou can type \`cancel\` at any time to cancel your application.`)
.setFooter({ text: 'Dawn | Starlight - Blue Protocol' })
.setTimestamp();
await dmChannel.send({ embeds: [welcomeEmbed] });
// Ask first question
await askQuestion(interaction.user, 0);
await interaction.editReply({
content: '✅ Application started! Please check your DMs to continue.'
});
console.log('[APPLICATION] Application started for', interaction.user.tag);
} catch (error) {
console.error('[APPLICATION] Error starting application:', error);
// User has DMs disabled
await interaction.editReply({
content: '❌ I couldn\'t send you a DM! Please enable DMs from server members and try again.\n\n**How to enable DMs:**\n1. Right-click the server name\n2. Go to Privacy Settings\n3. Enable "Direct Messages"'
});
}
}
async function askQuestion(user, questionIndex) {
const question = applicationQuestions[questionIndex];
const dmChannel = await user.createDM();
const questionEmbed = new EmbedBuilder()
.setTitle(`Question ${questionIndex + 1}/${applicationQuestions.length}`)
.setColor(0x0099ff)
.setDescription(question.question)
.setFooter({ text: `Type your answer below | Type "cancel" to cancel` })
.setTimestamp();
await dmChannel.send({ embeds: [questionEmbed] });
console.log(`[APPLICATION] Asked question ${questionIndex + 1} to ${user.tag}`);
}
async function handleDMResponse(message) {
// Ignore bot messages
if (message.author.bot) return;
// Check if user has an active application
const application = activeApplications.get(message.author.id);
if (!application) return;
console.log(`[APPLICATION] Received response from ${message.author.tag}: "${message.content}"`);
// Check for cancel
if (message.content.toLowerCase() === 'cancel') {
activeApplications.delete(message.author.id);
const cancelEmbed = new EmbedBuilder()
.setTitle('❌ Application Cancelled')
.setColor(0xff0000)
.setDescription('Your application has been cancelled. You can start a new one anytime!')
.setTimestamp();
await message.reply({ embeds: [cancelEmbed] });
console.log('[APPLICATION] Application cancelled by', message.author.tag);
return;
}
// Store the answer
const currentQuestion = applicationQuestions[application.currentQuestion];
application.answers[currentQuestion.id] = message.content;
// Move to next question
application.currentQuestion++;
if (application.currentQuestion < applicationQuestions.length) {
// Ask next question
await askQuestion(message.author, application.currentQuestion);
} else {
// Application complete
await submitApplication(message.author, application);
}
}
async function submitApplication(user, application) {
console.log('[APPLICATION] Submitting application for', user.tag);
try {
// Get the guild and channel
const guild = user.client.guilds.cache.get(application.guildId);
if (!guild) {
console.error('[APPLICATION] Could not find guild');
return;
}
const channel = guild.channels.cache.get(APPLICATION_CHANNEL_ID);
if (!channel) {
console.error('[APPLICATION] Could not find application channel');
await user.send('❌ There was an error submitting your application. Please contact an admin.');
activeApplications.delete(user.id);
return;
}
// Create the application embed
const applicationEmbed = new EmbedBuilder()
.setTitle('📋 New Blue Protocol Guild Application')
.setColor(0x0099ff)
.setAuthor({
name: `${user.tag} (${user.id})`,
iconURL: user.displayAvatarURL()
})
.setThumbnail(user.displayAvatarURL())
.setTimestamp();
// Add all answers as fields
applicationQuestions.forEach(q => {
applicationEmbed.addFields({
name: `📌 ${q.field}`,
value: application.answers[q.id] || 'No answer provided',
inline: false
});
});
applicationEmbed.addFields(
{ name: '👤 Discord User', value: `<@${user.id}>`, inline: true },
{ name: '🆔 User ID', value: user.id, inline: true },
{ name: '📅 Applied', value: `<t:${Math.floor(application.startTime / 1000)}:R>`, inline: true }
);
// Create action buttons for admins
const approveButton = new ButtonBuilder()
.setCustomId(`bp_approve_${user.id}`)
.setLabel('Approve')
.setEmoji('✅')
.setStyle(ButtonStyle.Success);
const denyButton = new ButtonBuilder()
.setCustomId(`bp_deny_${user.id}`)
.setLabel('Deny')
.setEmoji('❌')
.setStyle(ButtonStyle.Danger);
const row = new ActionRowBuilder().addComponents(approveButton, denyButton);
// Send to review channel
await channel.send({ embeds: [applicationEmbed], components: [row] });
// Confirm to user
const confirmEmbed = new EmbedBuilder()
.setTitle('✅ Application Submitted!')
.setColor(0x00ff00)
.setDescription(`Thank you for applying to **Dawn | Starlight**!\n\nYour application has been submitted and will be reviewed by our officers. You should hear back within 24-48 hours.\n\n**What happens next?**\n• Our officers will review your application\n• You'll receive a DM with the decision\n• If approved, you'll receive an invite link`)
.setFooter({ text: 'Dawn | Starlight' })
.setTimestamp();
await user.send({ embeds: [confirmEmbed] });
// Clean up
activeApplications.delete(user.id);
console.log('[APPLICATION] Application submitted successfully for', user.tag);
} catch (error) {
console.error('[APPLICATION] Error submitting application:', error);
await user.send('❌ There was an error submitting your application. Please contact an admin.');
activeApplications.delete(user.id);
}
}
async function handleApplicationReview(interaction, approved) {
const userId = interaction.customId.split('_')[2];
console.log(`[APPLICATION] Review action: ${approved ? 'APPROVE' : 'DENY'} for user ${userId}`);
try {
const user = await interaction.client.users.fetch(userId);
if (approved) {
const approveEmbed = new EmbedBuilder()
.setTitle('🎉 Application Approved!')
.setColor(0x00ff00)
.setDescription(`Congratulations! Your application to join **Dawn | Starlight** in Blue Protocol has been **approved**!\n\nWelcome to the guild! An officer will contact you in-game soon to send you an invite.\n\nSee you in Blue Protocol!`)
.setFooter({ text: 'Dawn | Starlight' })
.setTimestamp();
await user.send({ embeds: [approveEmbed] });
await interaction.reply({
content: `✅ Application approved! ${user.tag} has been notified.`,
flags: 64
});
} else {
const denyEmbed = new EmbedBuilder()
.setTitle('Application Update')
.setColor(0xff9900)
.setDescription(`Thank you for your interest in **Dawn | Starlight**.\n\nUnfortunately, we are unable to accept your application at this time. This could be due to various reasons such as guild capacity or requirements.\n\nYou're welcome to apply again in the future!`)
.setFooter({ text: 'Dawn | Starlight' })
.setTimestamp();
await user.send({ embeds: [denyEmbed] });
await interaction.reply({
content: `❌ Application denied. ${user.tag} has been notified.`,
flags: 64
});
}
// Update the original message to show it's been reviewed
const originalEmbed = interaction.message.embeds[0];
const updatedEmbed = EmbedBuilder.from(originalEmbed)
.setColor(approved ? 0x00ff00 : 0xff0000)
.setTitle(`${approved ? '✅ APPROVED' : '❌ DENIED'} - ${originalEmbed.title}`);
await interaction.message.edit({
embeds: [updatedEmbed],
components: [] // Remove buttons
});
console.log(`[APPLICATION] Review completed: ${approved ? 'APPROVED' : 'DENIED'}`);
} catch (error) {
console.error('[APPLICATION] Error in review process:', error);
await interaction.reply({
content: '❌ There was an error processing this review.',
flags: 64
});
}
}
module.exports = {
handleApplicationCommand,
handleApplicationButton,
handleDMResponse,
handleApplicationReview,
};