13
13
import net .dv8tion .jda .api .entities .emoji .EmojiUnion ;
14
14
import net .dv8tion .jda .api .events .interaction .ModalInteractionEvent ;
15
15
import net .dv8tion .jda .api .events .interaction .command .SlashCommandInteractionEvent ;
16
- import net .dv8tion .jda .api .events .interaction .component .ButtonInteractionEvent ;
17
16
import net .dv8tion .jda .api .events .interaction .component .StringSelectInteractionEvent ;
18
17
import net .dv8tion .jda .api .interactions .commands .CommandInteraction ;
18
+ import net .dv8tion .jda .api .interactions .commands .OptionMapping ;
19
+ import net .dv8tion .jda .api .interactions .commands .OptionType ;
20
+ import net .dv8tion .jda .api .interactions .commands .build .SlashCommandData ;
19
21
import net .dv8tion .jda .api .interactions .components .ActionRow ;
20
- import net .dv8tion .jda .api .interactions .components .buttons .Button ;
21
22
import net .dv8tion .jda .api .interactions .components .selections .SelectOption ;
22
23
import net .dv8tion .jda .api .interactions .components .selections .StringSelectMenu ;
23
24
import net .dv8tion .jda .api .interactions .components .text .TextInput ;
38
39
import java .time .Duration ;
39
40
import java .time .Instant ;
40
41
import java .time .OffsetDateTime ;
42
+ import java .util .HashMap ;
41
43
import java .util .List ;
44
+ import java .util .Map ;
42
45
import java .util .Optional ;
43
46
import java .util .concurrent .TimeUnit ;
44
47
import java .util .function .Predicate ;
45
48
import java .util .regex .Pattern ;
49
+ import java .util .stream .IntStream ;
46
50
47
51
/**
48
52
* Represents a command to create an application form for members to apply for roles.
@@ -59,6 +63,8 @@ public class ApplicationCreateCommand extends SlashCommandAdapter {
59
63
private static final int APPLICATION_SUBMIT_COOLDOWN = 5 ;
60
64
private static final String DEFAULT_QUESTION =
61
65
"What makes you a valuable addition to the team? 😎" ;
66
+ private static final int OPTIONAL_ROLES_AMOUNT = 5 ;
67
+ private static final String ROLE_COMPONENT_ID_HEADER = "application-create" ;
62
68
63
69
private final Cache <Member , OffsetDateTime > applicationSubmitCooldown ;
64
70
private final Predicate <String > applicationChannelPattern ;
@@ -82,6 +88,24 @@ public ApplicationCreateCommand(Config config) {
82
88
this .applicationSubmitCooldown = Caffeine .newBuilder ()
83
89
.expireAfterWrite (APPLICATION_SUBMIT_COOLDOWN , TimeUnit .MINUTES )
84
90
.build ();
91
+
92
+ generateRoleOptions (getData ());
93
+ }
94
+
95
+ /**
96
+ * Populates a {@link SlashCommandData} object with the proper arguments.
97
+ *
98
+ * @param data the object to populate
99
+ */
100
+ private void generateRoleOptions (SlashCommandData data ) {
101
+ IntStream .range (0 , OPTIONAL_ROLES_AMOUNT ).forEach (index -> {
102
+ int renderNumber = index + 1 ;
103
+
104
+ data .addOption (OptionType .STRING , "title" + renderNumber , "The title of the role" );
105
+ data .addOption (OptionType .STRING , "description" + renderNumber ,
106
+ "The description of the role" );
107
+ data .addOption (OptionType .STRING , "emoji" + renderNumber , "The emoji of the role" );
108
+ });
85
109
}
86
110
87
111
@ Override
@@ -90,22 +114,15 @@ public void onSlashCommand(SlashCommandInteractionEvent event) {
90
114
return ;
91
115
}
92
116
93
- sendMenu (event );
94
- }
95
-
96
- @ Override
97
- public void onButtonClick (ButtonInteractionEvent event , List <String > args ) {
98
- User user = event .getUser ();
99
- StringSelectMenu .Builder menu = StringSelectMenu
100
- .create (generateComponentId (Lifespan .REGULAR , event .getUser ().getId ()))
101
- .setPlaceholder ("Select role to apply for" );
102
-
103
- config .applyRoleConfig ()
104
- .stream ()
105
- .map (option -> mapToSelectOption (user , option ))
106
- .forEach (menu ::addOptions );
117
+ long incorrectArgsCount = getIncorrectRoleArgsCount (event .getInteraction ().getOptions ());
118
+ if (incorrectArgsCount > 0 ) {
119
+ event .reply ("Missing information for %d roles." .formatted (incorrectArgsCount ))
120
+ .setEphemeral (true )
121
+ .queue ();
122
+ return ;
123
+ }
107
124
108
- event . reply ( "" ). addActionRow ( menu . build ()). setEphemeral ( true ). queue ( );
125
+ sendMenu ( event );
109
126
}
110
127
111
128
/**
@@ -172,6 +189,58 @@ public void onStringSelectSelection(StringSelectInteractionEvent event, List<Str
172
189
event .replyModal (modal ).queue ();
173
190
}
174
191
192
+ /**
193
+ * Checks a given list of passed arguments (from a user) and calculates how many roles have
194
+ * missing data.
195
+ *
196
+ * @param args the list of passed arguments
197
+ * @return the amount of roles with missing data
198
+ */
199
+ private static long getIncorrectRoleArgsCount (final List <OptionMapping > args ) {
200
+ final Map <Character , Integer > frequencyMap = new HashMap <>();
201
+
202
+ args .stream ()
203
+ .map (OptionMapping ::getName )
204
+ .map (name -> name .charAt (name .length () - 1 ))
205
+ .forEach (number -> frequencyMap .merge (number , 1 , Integer ::sum ));
206
+
207
+ return frequencyMap .values ().stream ().filter (value -> value != 3 ).count ();
208
+ }
209
+
210
+ /**
211
+ * Populates a {@link StringSelectMenu.Builder} with application roles.
212
+ *
213
+ * @param menuBuilder the menu builder to populate
214
+ * @param args the arguments which contain data about the roles
215
+ */
216
+ private void addRolesToMenu (StringSelectMenu .Builder menuBuilder ,
217
+ final List <OptionMapping > args ) {
218
+ final Map <Character , MenuRole > roles = new HashMap <>();
219
+
220
+ args .forEach (arg -> {
221
+ final String name = arg .getName ();
222
+ final String argValue = arg .getAsString ();
223
+ final char roleId = name .charAt (name .length () - 1 );
224
+ MenuRole role = roles .computeIfAbsent (roleId , k -> new MenuRole ());
225
+
226
+ if (name .startsWith ("title" )) {
227
+ String value = generateComponentId (ROLE_COMPONENT_ID_HEADER , argValue );
228
+
229
+ role .setValue (value );
230
+ role .setLabel (argValue );
231
+ } else if (name .startsWith ("description" )) {
232
+ role .setDescription (argValue );
233
+ } else if (name .startsWith ("emoji" )) {
234
+ role .setEmoji (Emoji .fromFormatted (argValue ));
235
+ }
236
+ });
237
+
238
+ roles .values ().forEach (role -> {
239
+ menuBuilder .addOption (role .getLabel (), role .getValue (), role .getDescription (),
240
+ role .getEmoji ());
241
+ });
242
+ }
243
+
175
244
@ Override
176
245
public void onModalSubmitted (ModalInteractionEvent event , List <String > args ) {
177
246
Guild guild = event .getGuild ();
@@ -282,10 +351,14 @@ private void sendApplicationResult(final ModalInteractionEvent event, List<Strin
282
351
private void sendMenu (final CommandInteraction event ) {
283
352
MessageEmbed embed = createApplicationEmbed ();
284
353
285
- String buttonComponentId = generateComponentId (Lifespan .PERMANENT , event .getUser ().getId ());
286
- Button button = Button .primary (buttonComponentId , "Check openings" );
354
+ StringSelectMenu .Builder menuBuilder = StringSelectMenu
355
+ .create (generateComponentId (Lifespan .REGULAR , event .getUser ().getId ()))
356
+ .setPlaceholder ("Select role to apply for" )
357
+ .setRequiredRange (1 , 1 );
358
+
359
+ addRolesToMenu (menuBuilder , event .getOptions ());
287
360
288
- event .replyEmbeds (embed ).addActionRow (button ).queue ();
361
+ event .replyEmbeds (embed ).addActionRow (menuBuilder . build () ).queue ();
289
362
}
290
363
291
364
private static MessageEmbed createApplicationEmbed () {
@@ -297,4 +370,50 @@ private static MessageEmbed createApplicationEmbed() {
297
370
.setColor (AMBIENT_COLOR )
298
371
.build ();
299
372
}
373
+
374
+ /**
375
+ * Wrapper class which represents a menu role for the application create command.
376
+ * <p>
377
+ * The reason this exists is due to the fact that {@link StringSelectMenu.Builder} does not have
378
+ * a method which takes emojis as input as of writing this, so we have to elegantly pass in
379
+ * custom data from this POJO.
380
+ */
381
+ private static class MenuRole {
382
+ private String label ;
383
+ private String value ;
384
+ private String description ;
385
+ private Emoji emoji ;
386
+
387
+ public String getLabel () {
388
+ return label ;
389
+ }
390
+
391
+ public void setLabel (String label ) {
392
+ this .label = label ;
393
+ }
394
+
395
+ public String getValue () {
396
+ return value ;
397
+ }
398
+
399
+ public void setValue (String value ) {
400
+ this .value = value ;
401
+ }
402
+
403
+ public String getDescription () {
404
+ return description ;
405
+ }
406
+
407
+ public void setDescription (String description ) {
408
+ this .description = description ;
409
+ }
410
+
411
+ public Emoji getEmoji () {
412
+ return emoji ;
413
+ }
414
+
415
+ public void setEmoji (Emoji emoji ) {
416
+ this .emoji = emoji ;
417
+ }
418
+ }
300
419
}
0 commit comments