11package com .workingdead .chatbot .command ;
22
33import com .workingdead .chatbot .scheduler .WendyScheduler ;
4- import com .workingdead .meet .service .WendyService ;
4+ import com .workingdead .chatbot .service .WendyService ;
5+ import java .util .concurrent .CompletableFuture ;
6+ import java .util .concurrent .TimeUnit ;
57import net .dv8tion .jda .api .entities .Member ;
68import net .dv8tion .jda .api .entities .channel .concrete .TextChannel ;
79import net .dv8tion .jda .api .entities .emoji .Emoji ;
10+ import net .dv8tion .jda .api .events .interaction .component .EntitySelectInteractionEvent ;
11+ import net .dv8tion .jda .api .events .interaction .component .StringSelectInteractionEvent ;
812import net .dv8tion .jda .api .events .message .MessageReceivedEvent ;
913import net .dv8tion .jda .api .events .message .react .MessageReactionAddEvent ;
1014import net .dv8tion .jda .api .hooks .ListenerAdapter ;
15+ import net .dv8tion .jda .api .interactions .components .selections .EntitySelectMenu ;
16+ import net .dv8tion .jda .api .interactions .components .selections .StringSelectMenu ;
1117import org .springframework .stereotype .Component ;
1218
1319import java .util .List ;
@@ -22,12 +28,27 @@ public class WendyCommand extends ListenerAdapter {
2228
2329 private final Map <String , String > participantCheckMessages = new ConcurrentHashMap <>();
2430 private final Map <String , Boolean > waitingForDateInput = new ConcurrentHashMap <>();
31+
32+ private static final String ATTENDEE_SELECT_MENU_ID = "wendy-attendees" ;
33+ private static final String WEEK_SELECT_MENU_ID = "wendy-weeks" ;
34+ private static final String WEEK_SELECT_MENU_REVOTE_ID = "wendy-weeks-revote" ;
2535
2636 public WendyCommand (WendyService wendyService , WendyScheduler wendyScheduler ) {
2737 this .wendyService = wendyService ;
2838 this .wendyScheduler = wendyScheduler ;
2939 }
30-
40+
41+ @ Override
42+ public void onGuildJoin (net .dv8tion .jda .api .events .guild .GuildJoinEvent event ) {
43+ TextChannel defaultChannel = event .getGuild ().getDefaultChannel ().asTextChannel ();
44+ if (defaultChannel != null ) {
45+ defaultChannel .sendMessage ("""
46+ 안녕하세요! 일정 조율 도우미 웬디가 서버에 합류했어요 :D
47+ 일정을 조율하려면 채팅에 **'웬디 시작'** 이라고 입력해 주세요!
48+ """ ).queue ();
49+ }
50+ }
51+
3152 @ Override
3253 public void onMessageReceived (MessageReceivedEvent event ) {
3354 if (event .getAuthor ().isBot ()) return ;
@@ -54,14 +75,14 @@ public void onMessageReceived(MessageReceivedEvent event) {
5475 return ;
5576 }
5677
57- // 2.1~2.2 날짜 범위 입력
58- if (waitingForDateInput .getOrDefault (channelId , false )) {
59- Integer weeks = extractWeeks (content );
60- if (weeks != null ) {
61- handleDateInput (channel , member , weeks , false );
62- return ;
63- }
64- }
78+ // // 2.1~2.2 날짜 범위 입력
79+ // if (waitingForDateInput.getOrDefault(channelId, false)) {
80+ // Integer weeks = extractWeeks(content);
81+ // if (weeks != null) {
82+ // handleDateInput(channel, member, weeks, false);
83+ // return;
84+ // }
85+ // }
6586
6687 // 4.2 재투표
6788 if (content .equals ("웬디 재투표" )) {
@@ -75,30 +96,84 @@ public void onMessageReceived(MessageReceivedEvent event) {
7596 return ;
7697 }
7798 }
78-
99+
79100 @ Override
80- public void onMessageReactionAdd (MessageReactionAddEvent event ) {
81- if (event .getUser () != null && event .getUser ().isBot ()) return ;
82-
83- String channelId = event .getChannel ().getId ();
84- String messageId = event .getMessageId ();
85-
86- String checkMessageId = participantCheckMessages .get (channelId );
87- if (checkMessageId == null || !checkMessageId .equals (messageId )) {
101+ public void onEntitySelectInteraction (EntitySelectInteractionEvent event ) {
102+ if (!ATTENDEE_SELECT_MENU_ID .equals (event .getComponentId ())) {
88103 return ;
89104 }
90-
91- if (!event .getReaction ().getEmoji ().equals (Emoji .fromUnicode ("✅" ))) {
105+
106+ String channelId = event .getChannel ().getId ();
107+ if (!wendyService .isSessionActive (channelId )) {
92108 return ;
93109 }
94-
95- event .retrieveMember ().queue (member -> {
96- if (member != null ) {
97- wendyService .addParticipant (channelId , member .getId (), member .getEffectiveName ());
98- System .out .println ("[Command] Participant added: " + member .getEffectiveName ());
99- }
110+
111+ event .getMentions ().getMembers ().forEach (member -> {
112+ wendyService .addParticipant (channelId , member .getId (), member .getEffectiveName ());
113+ System .out .println ("[Command] Participant added via select menu: " + member .getEffectiveName ());
100114 });
115+
116+ event .reply ("참석자 명단이 업데이트됐어요!" ).setEphemeral (true ).queue ();
117+
101118 }
119+
120+ @ Override
121+ public void onStringSelectInteraction (StringSelectInteractionEvent event ) {
122+ String componentId = event .getComponentId ();
123+ if (!WEEK_SELECT_MENU_ID .equals (componentId ) && !WEEK_SELECT_MENU_REVOTE_ID .equals (componentId )) {
124+ return ;
125+ }
126+
127+ String channelId = event .getChannel ().getId ();
128+ if (!wendyService .isSessionActive (channelId )) {
129+ return ;
130+ }
131+
132+ // 하나만 선택하게 설정할 예정이므로 첫 번째 값만 사용
133+ String value = event .getValues ().get (0 );
134+ int weeks ;
135+ try {
136+ weeks = Integer .parseInt (value );
137+ } catch (NumberFormatException e ) {
138+ event .reply ("선택한 값이 올바르지 않아요. 다시 시도해주세요!" ).setEphemeral (true ).queue ();
139+ return ;
140+ }
141+
142+ TextChannel channel = event .getChannel ().asTextChannel ();
143+ Member member = event .getMember ();
144+ if (member == null ) {
145+ event .reply ("사용자 정보를 가져올 수 없어요. 다시 시도해주세요!" ).setEphemeral (true ).queue ();
146+ return ;
147+ }
148+
149+ boolean isRevote = WEEK_SELECT_MENU_REVOTE_ID .equals (componentId );
150+ handleDateInput (channel , member , weeks , isRevote );
151+ event .reply ("투표 날짜 범위를 선택하셨어요!" ).setEphemeral (true ).queue ();
152+ }
153+
154+ // @Override
155+ // public void onMessageReactionAdd(MessageReactionAddEvent event) {
156+ // if (event.getUser() != null && event.getUser().isBot()) return;
157+ //
158+ // String channelId = event.getChannel().getId();
159+ // String messageId = event.getMessageId();
160+ //
161+ // String checkMessageId = participantCheckMessages.get(channelId);
162+ // if (checkMessageId == null || !checkMessageId.equals(messageId)) {
163+ // return;
164+ // }
165+ //
166+ // if (!event.getReaction().getEmoji().equals(Emoji.fromUnicode("✅"))) {
167+ // return;
168+ // }
169+ //
170+ // event.retrieveMember().queue(member -> {
171+ // if (member != null) {
172+ // wendyService.addParticipant(channelId, member.getId(), member.getEffectiveName());
173+ // System.out.println("[Command] Participant added: " + member.getEffectiveName());
174+ // }
175+ // });
176+ // }
102177
103178 private void handleStart (TextChannel channel ) {
104179 String channelId = channel .getId ();
@@ -110,35 +185,70 @@ private void handleStart(TextChannel channel) {
110185 안녕하세요! 일정 조율 도우미 웬디에요 :D
111186 지금부터 여러분의 일정 조율을 도와드릴게요
112187 """ ).queue ();
113-
114- channel .sendMessage ("인원 파악을 위해 참석자분들은 ✅를 남겨주세요!" )
115- .queue (message -> {
116- participantCheckMessages .put (channelId , message .getId ());
117- message .addReaction (Emoji .fromUnicode ("✅" )).queue ();
118- System .out .println ("[Command] Session started: " + channelId );
119- });
120-
121- channel .sendMessage ("몇 주 뒤의 일정을 계획하시나요? :D\n (ex. 2주 뒤)" ).queue ();
122- waitingForDateInput .put (channelId , true );
188+
189+
190+ // 참석자 입력용 엔티티 셀렉트 메뉴 (유저 선택 드롭다운)
191+ EntitySelectMenu attendeeMenu = EntitySelectMenu .create (ATTENDEE_SELECT_MENU_ID , EntitySelectMenu .SelectTarget .USER )
192+ .setPlaceholder ("참석자를 선택 / 검색해 주세요." )
193+ .setRequiredRange (1 , 25 )
194+ .build ();
195+
196+ channel .sendMessage ("인원 파악을 위해 참석자분들을 알려주세요!\n 원하는 참석자들을 아래 드롭다운에서 선택해주세요." )
197+ .setActionRow (attendeeMenu )
198+ .queue ();
199+
200+ // 2.1 날짜 범위 파악 질문 (드롭다운 방식)
201+ StringSelectMenu weekMenu = StringSelectMenu .create (WEEK_SELECT_MENU_ID )
202+ .setPlaceholder ("몇 주 뒤의 일정을 계획하시나요?" )
203+ .addOption ("이번 주" , "0" )
204+ .addOption ("1주 뒤" , "1" )
205+ .addOption ("2주 뒤" , "2" )
206+ .addOption ("3주 뒤" , "3" )
207+ .addOption ("4주 뒤" , "4" )
208+ .addOption ("5주 뒤" , "5" )
209+ .addOption ("6주 뒤" , "6" )
210+ .build ();
211+
212+ channel .sendMessage ("몇 주 뒤의 일정을 계획하시나요? :D" )
213+ .setActionRow (weekMenu )
214+ .queue ();
123215 }
124216
125217 private void handleDateInput (TextChannel channel , Member member , int weeks , boolean isRevote ) {
126218 String channelId = channel .getId ();
127- String userName = member .getEffectiveName ();
219+ String userMention = member .getAsMention ();
220+ String channelName = channel .getName ();
128221
129222 waitingForDateInput .put (channelId , false );
130223
131- channel .sendMessage (userName + " 님이 " + weeks + "주 뒤를 선택하셨어요!" ).queue ();
224+ channel .sendMessage (userMention + " 님이 " + weeks + "주 뒤를 선택하셨어요!" ).queue ();
132225 channel .sendMessage ("해당 일정의 투표를 만들어드릴게요 :D" ).queue ();
133226 channel .sendMessage ("(투표 늦게 하는 사람 대머리🧑🦲)" ).queue ();
134227 channel .sendMessage ("투표를 생성 중입니다🛜" ).queue ();
135228
136229 String voteUrl = isRevote
137- ? wendyService .recreateVote (channelId , weeks )
138- : wendyService .createVote (channelId , weeks );
230+ ? wendyService .recreateVote (channelId , channelName , weeks )
231+ : wendyService .createVote (channelId , channelName , weeks );
139232
140233 channel .sendMessage (voteUrl ).queue ();
141234 wendyScheduler .startSchedule (channel );
235+
236+
237+ // // 투표 제한시간(24시간) + 30분 후 자동 종료 스케줄
238+ // CompletableFuture
239+ // .delayedExecutor(3 * 60 + 30, TimeUnit.SECONDS)
240+ // .execute(() -> {
241+ // String chId = channel.getId();
242+ // // 스케줄러 정리 + 세션 종료
243+ // wendyScheduler.stopSchedule(chId);
244+ // wendyService.endSession(chId);
245+ //
246+ // // 안내 메시지 전송
247+ // channel.sendMessage("""
248+ // 투표 제한 시간이 지나 웬디가 자동으로 종료되었어요 :D
249+ // 다시 일정 조율이 필요하시면 '웬디 시작'을 입력해 주세요!
250+ // """).queue();
251+ // });
142252 }
143253
144254 private void handleRevote (TextChannel channel ) {
@@ -150,8 +260,22 @@ private void handleRevote(TextChannel channel) {
150260 }
151261
152262 wendyScheduler .stopSchedule (channelId );
153- channel .sendMessage ("몇 주 뒤의 일정을 계획하시나요? :D\n (ex. 2주 뒤)" ).queue ();
154- waitingForDateInput .put (channelId , true );
263+
264+
265+ StringSelectMenu weekMenu = StringSelectMenu .create (WEEK_SELECT_MENU_REVOTE_ID )
266+ .setPlaceholder ("몇 주 뒤의 일정을 다시 계획하시나요?" )
267+ .addOption ("이번 주" , "0" )
268+ .addOption ("1주 뒤" , "1" )
269+ .addOption ("2주 뒤" , "2" )
270+ .addOption ("3주 뒤" , "3" )
271+ .addOption ("4주 뒤" , "4" )
272+ .addOption ("5주 뒤" , "5" )
273+ .addOption ("6주 뒤" , "6" )
274+ .build ();
275+
276+ channel .sendMessage ("몇 주 뒤의 일정을 계획하시나요? :D" )
277+ .setActionRow (weekMenu )
278+ .queue ();
155279 }
156280
157281 private void handleEnd (TextChannel channel ) {
0 commit comments