1use crate::utils::{Context, Error};
2
3use poise::{
4 serenity_prelude::{
5 self as serenity, ButtonStyle, Color, CreateActionRow, CreateButton, CreateEmbed,
6 CreateEmbedFooter,
7 },
8 CreateReply,
9};
10
11#[derive(Debug, serde::Serialize, serde::Deserialize, Default)]
12pub struct ProgressCheck {
13 event: String,
14 duration: String,
15 progress: String,
16 improvements: String,
17 timestamp: String,
18 team: String,
19 other: String,
20}
21impl ProgressCheck {
22 pub fn event(&mut self, event: String) {
23 self.event = event;
24 }
25 pub fn duration(&mut self, duration: String) {
26 self.duration = duration;
27 }
28 pub fn progress(&mut self, progress: String) {
29 self.progress = progress;
30 }
31 pub fn improvements(&mut self, improvements: String) {
32 self.improvements = improvements;
33 }
34 pub fn timestamp(&mut self, timestamp: String) {
35 self.timestamp = timestamp;
36 }
37 pub fn team(&mut self, team: char) {
38 self.team = team.to_string();
39 }
40 pub fn other(&mut self, other: String) {
41 self.other = other;
42 }
43 pub fn to_vec_values(&self) -> Result<Vec<serde_json::Value>, crate::utils::Error> {
44 Ok(vec![
45 serde_json::to_value(self.event.clone())?,
46 serde_json::to_value(self.team.clone())?,
47 serde_json::to_value(self.duration.clone())?,
48 serde_json::to_value(self.progress.clone())?,
49 serde_json::to_value(self.improvements.clone())?,
50 serde_json::to_value(self.timestamp.clone())?,
51 serde_json::to_value(self.other.clone())?,
52 ])
53 }
54}
55
56pub async fn pc_start_embed(
57 ctx: Context<'_>,
58 event_list_ids: &Vec<(String, String)>,
59 abort_id: &String,
60) -> Result<(), Error> {
61 ctx.channel_id().broadcast_typing(ctx).await?;
62 let mut buttons = Vec::new();
63
64 for (event, event_id) in event_list_ids {
65 let button = CreateButton::new(event_id)
66 .label(event)
67 .style(ButtonStyle::Primary)
68 .emoji('📝');
69 buttons.push(button);
70 }
71
72 buttons.push(
73 CreateButton::new(abort_id)
74 .label("Abort")
75 .style(ButtonStyle::Danger)
76 .emoji('❌'),
77 );
78
79 let embed = CreateEmbed::default()
80 .title("Pick an event to start!")
81 .footer(CreateEmbedFooter::new("run !help for help!"));
82 let reply = CreateReply::default()
83 .embed(embed)
84 .components(vec![CreateActionRow::Buttons(buttons)]);
85
86 ctx.send(reply).await?;
87
88 Ok(())
89}
90pub async fn pc_abort_embed(
91 ctx: Context<'_>,
92 press: &serenity::ComponentInteraction,
93) -> Result<(), Error> {
94 let abort_embed = CreateEmbed::default()
95 .color(Color::RED)
96 .title("Progress Check Aborted")
97 .description("Your progress check has been aborted.");
98
99 let abort_components = vec![CreateActionRow::Buttons(vec![CreateButton::new(
100 "whatthefrik",
101 )
102 .emoji('❌')
103 .style(ButtonStyle::Danger)
104 .label("Aborted")
105 .disabled(true)])];
106
107 let builder = serenity::CreateInteractionResponse::UpdateMessage(
108 serenity::CreateInteractionResponseMessage::new()
109 .embed(abort_embed.clone())
110 .components(abort_components),
111 );
112
113 press.create_response(ctx, builder).await?;
114
115 Ok(())
116}
117
118pub async fn pc_event_handling(ctx: Context<'_>, event: &String) -> Result<ProgressCheck, Error> {
119 ctx.channel_id().broadcast_typing(ctx).await?;
120 let mut prog_check = ProgressCheck::default();
121 prog_check.event(event.clone());
122 let replyhandle = ctx.say("Starting progress check...").await?;
123
124 prog_check.duration(
125 send_questions(
126 &ctx,
127 &replyhandle,
128 "How long did you meet with your partner for".to_string(),
129 event,
130 )
131 .await?,
132 );
133
134 prog_check.progress(
135 send_questions(
136 &ctx,
137 &replyhandle,
138 "What progress did you make on".to_string(),
139 event,
140 )
141 .await?,
142 );
143
144 prog_check.improvements(
145 send_questions(
146 &ctx,
147 &replyhandle,
148 "What improvements can you make for".to_string(),
149 event,
150 )
151 .await?,
152 );
153
154 prog_check.other(
155 send_questions(
156 &ctx,
157 &replyhandle,
158 "Anything else you'd like to let us know?".to_string(),
159 &"".to_string(),
160 )
161 .await?,
162 );
163
164 prog_check.timestamp(
165 chrono::offset::Local::now()
166 .format("%B %d, %Y at %I:%M %P")
167 .to_string(),
168 );
169 println!("{}", prog_check.timestamp);
170
171 let confirmation_embed = CreateEmbed::default()
172 .title(format!("Confirm that your Progress Check for {} is correct: ", event))
173 .description(format!(
174 "1. Duration: {}\n 2. Progress: {}\n 3. Improvements: {}\n, 4. Notes: {}\n",
175 prog_check.duration, prog_check.progress, prog_check.improvements, prog_check.other
176 ))
177 .color(poise::serenity_prelude::Color::DARK_ORANGE)
178 .footer(CreateEmbedFooter::new(
179 "If you would like to change any of the above answers, type the number of the question you would like to change after pressing ❌'.",
180 ));
181
182 let reply = CreateReply::default()
183 .embed(confirmation_embed.clone())
184 .components(vec![CreateActionRow::Buttons(vec![
185 CreateButton::new("whatthefriksubmitit")
186 .emoji('✅')
187 .style(ButtonStyle::Success)
188 .label("Confirm"),
189 CreateButton::new("whatthefrikiswrong")
190 .emoji('❌')
191 .style(ButtonStyle::Danger)
192 .label("Nope"),
193 ])]);
194
195 ctx.send(reply).await?;
196
197 while let Some(press) = serenity::collector::ComponentInteractionCollector::new(ctx)
198 .author_id(ctx.author().id)
199 .filter(move |press| press.data.custom_id.starts_with("whatthefrik"))
200 .timeout(std::time::Duration::from_secs(100))
201 .await
202 {
203 press.defer(ctx).await?;
204 let final_embed = CreateEmbed::default()
205 .title("Progress Check Submitted")
206 .description("Your progress check has been submitted.")
207 .color(poise::serenity_prelude::Color::DARK_GREEN);
208 let final_response = serenity::EditInteractionResponse::default()
209 .embed(final_embed)
210 .components(vec![CreateActionRow::Buttons(vec![
211 CreateButton::new("whatthefriksubmitit")
212 .emoji('✅')
213 .style(ButtonStyle::Success)
214 .label("Confirm")
215 .disabled(true),
216 CreateButton::new("whatthefrikiswrong")
217 .emoji('❌')
218 .style(ButtonStyle::Danger)
219 .label("Nope")
220 .disabled(true),
221 ])]);
222
223 if press.data.custom_id == "whatthefrikiswrong" {
224 println!("time to fix xd");
225 edit_answers(&ctx, &press, &replyhandle, &mut prog_check, event).await?;
226 break;
227 } else if press.data.custom_id == "whatthefriksubmitit" {
228 println!("{:?}", press.data.custom_id);
229 press.edit_response(ctx, final_response).await?;
230 break;
231 }
232 }
233
234 Ok(prog_check)
235}
236
237async fn edit_answers(
238 ctx: &Context<'_>,
239 press: &serenity::ComponentInteraction,
240 replyhandle: &poise::ReplyHandle<'_>,
241 prog_check: &mut ProgressCheck,
242 event: &str,
243) -> Result<(), Error> {
244 let interaction_handler = async {
245 while let Some(press) = serenity::collector::ComponentInteractionCollector::new(ctx)
246 .author_id(ctx.author().id)
247 .filter(move |press| press.data.custom_id.starts_with("whatthefrik"))
248 .timeout(std::time::Duration::from_secs(100))
249 .await
250 {
251 let _ = press.defer(ctx).await;
252 if press.data.custom_id == "whatthefriksubmitit" {
253 let final_embed = CreateEmbed::default()
254 .title("Progress Check Submitted")
255 .description("Your progress check has been submitted.")
256 .color(poise::serenity_prelude::Color::DARK_GREEN);
257 let final_response = serenity::EditInteractionResponse::default()
258 .embed(final_embed)
259 .components(vec![CreateActionRow::Buttons(vec![CreateButton::new(
260 "whatthefriksubmitit",
261 )
262 .emoji('✅')
263 .style(ButtonStyle::Success)
264 .label("Confirm")
265 .disabled(true)])]);
266 let _ = press.edit_response(ctx, final_response).await;
267 return;
268 }
269 }
270 };
271
272 let other_task = async {
273 while let Some(messages) = ctx
274 .channel_id()
275 .await_reply(ctx)
276 .author_id(ctx.author().id)
277 .timeout(std::time::Duration::from_secs(60))
278 .await
279 {
280 let answer = messages.content;
281 println!("{}", answer);
282 if answer == "1" {
283 prog_check.duration(
284 send_questions(
285 ctx,
286 replyhandle,
287 "How long did you meet with your partner for".to_string(),
288 &event.to_string(),
289 )
290 .await
291 .unwrap(),
292 );
293 let _ = send_confirmation(ctx, press, prog_check).await;
294 } else if answer == "2" {
295 prog_check.progress(
296 send_questions(
297 ctx,
298 replyhandle,
299 "What progress did you make on".to_string(),
300 &event.to_string(),
301 )
302 .await
303 .unwrap(),
304 );
305 let _ = send_confirmation(ctx, press, prog_check).await;
306 } else if answer == "3" {
307 prog_check.improvements(
308 send_questions(
309 ctx,
310 replyhandle,
311 "What improvements can you make for".to_string(),
312 &event.to_string(),
313 )
314 .await
315 .unwrap(),
316 );
317 let _ = send_confirmation(ctx, press, prog_check).await;
318 } else if answer == "4" {
319 prog_check.other(
320 send_questions(
321 ctx,
322 replyhandle,
323 "Anything else you'd like to let us know?".to_string(),
324 &"".to_string(),
325 )
326 .await
327 .unwrap(),
328 );
329 let _ = send_confirmation(ctx, press, prog_check).await;
330 } else {
331 let _ = ctx.say(
332 "Invalid input. Please type the number of the question you would like to change.",
333 )
334 .await;
335 }
336 }
337 };
338 tokio::select!(
339 _ = interaction_handler => {},
340 _ = other_task => {}
341 );
342 Ok(())
343}
344
345async fn send_confirmation(
346 ctx: &Context<'_>,
347 press: &serenity::ComponentInteraction,
348 prog_check: &ProgressCheck,
349) -> Result<(), Error> {
350 let confirmation_embed = CreateEmbed::default()
351 .title(format!("Confirm that your Progress Check for {} is correct: ", prog_check.event))
352 .description(format!(
353 "1. Duration: {}\n 2. Progress: {}\n 3. Improvements: {}\n, 4. Notes: {}\n",
354 prog_check.duration, prog_check.progress, prog_check.improvements, prog_check.other
355 ))
356 .color(poise::serenity_prelude::Color::DARK_ORANGE)
357 .footer(CreateEmbedFooter::new(
358 "If you would like to change any of the above answers, type the number of the question you would like to change!'.",
359 ));
360
361 let reply = CreateReply::default()
362 .embed(confirmation_embed.clone())
363 .components(vec![CreateActionRow::Buttons(vec![CreateButton::new(
364 "whatthefriksubmitit",
365 )
366 .emoji('✅')
367 .style(ButtonStyle::Success)
368 .label("Confirm")])]);
369
370 ctx.send(reply).await?;
371
372 Ok(())
373}
374
375async fn send_questions<'a>(
376 ctx: &Context<'a>,
377 replyhandle: &poise::ReplyHandle<'a>,
378 question: String,
379 event: &String,
380) -> Result<String, Error> {
381 replyhandle
382 .message()
383 .await?
384 .reply(ctx, format!("{} {}?", &question, &event))
385 .await?;
386 let mut answer = String::new();
387 if let Some(messages) = ctx
388 .channel_id()
389 .await_reply(ctx)
390 .author_id(ctx.author().id)
391 .timeout(std::time::Duration::from_secs(60))
392 .await
393 {
394 answer = messages.content;
395 } else {
396 return Err(Error::from("No answer provided"));
397 }
398
399 Ok(answer)
400}