From 6a2fb50e336fcf20e1cb7b184a03fd010043bff7 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Joona=20Kyt=C3=B6niemi?= <jnkyto@utu.fi>
Date: Mon, 24 Apr 2023 16:03:47 +0300
Subject: [PATCH] Add thread-making capabilities

---
 src/buttons/NewThreadButton.ts | 11 ++++
 src/cmd/MenuCommand.ts         | 91 +++++++++++++++++++---------------
 src/models/InternalModel.ts    |  8 ---
 src/utils/getFormattedDate.ts  |  6 +++
 tsconfig.json                  |  2 +-
 5 files changed, 68 insertions(+), 50 deletions(-)
 create mode 100644 src/buttons/NewThreadButton.ts
 delete mode 100644 src/models/InternalModel.ts
 create mode 100644 src/utils/getFormattedDate.ts

diff --git a/src/buttons/NewThreadButton.ts b/src/buttons/NewThreadButton.ts
new file mode 100644
index 0000000..d7b6af8
--- /dev/null
+++ b/src/buttons/NewThreadButton.ts
@@ -0,0 +1,11 @@
+export default {
+    type: 1,
+    components: [
+        {
+            type: 2,
+            label: "🍴 Mennään syömään!",
+            style: 1,
+            customId: "make_thread",
+        }
+    ]
+};
\ No newline at end of file
diff --git a/src/cmd/MenuCommand.ts b/src/cmd/MenuCommand.ts
index ea17bb3..3b28db3 100644
--- a/src/cmd/MenuCommand.ts
+++ b/src/cmd/MenuCommand.ts
@@ -1,8 +1,10 @@
-import {Client, CommandInteraction} from "discord.js";
+import {Client, CollectorFilter, CommandInteraction} from "discord.js";
 
+import NewThreadButton from "../buttons/NewThreadButton";
 import {Command} from "../interfaces/Command";
 import { RestaurantIdNamePair, RestaurantObject } from "../interfaces/Restaurant";
 import { menuToString } from "../utils/formatMenu";
+import {getFormattedDate} from "../utils/getFormattedDate";
 
 const getIdNamePairs = (): Promise<RestaurantIdNamePair[]> => {
     let IdNamePairs: RestaurantIdNamePair[] = [];
@@ -27,26 +29,26 @@ let command = {
     options: [
         {
             name: "today",
-            description: "What's on the menu today?",
+            description: "Mitäs tänään syötäisiin?",
             type: 1,
             options: [
                 {
                     name: "restaurant",
-                    description: "Fetches the menu of a specific restaurant",
+                    description: "Hakee tietyn ravintolan ruokalistan.",
                     type: 3,
-                    required: false,
+                    required: true,
                     choices: [] as RestaurantIdNamePair[] //fetched below with getIdnamePairs() 
                 }
             ]
         },
         {
             name: "week",
-            description: "Okay",
+            description: "Mitäs tällä viikolla olis?",
             type: 1,
             options: [
                 {
                     name: "restaurant",
-                    description: "Fetches the week menu of a specific restaurant",
+                    description: "Hakee tietyn ravintolan ruokalistan.",
                     type: 3,
                     required: true,
                     choices: [] as RestaurantIdNamePair[] //fetched below with getIdnamePairs() 
@@ -55,45 +57,52 @@ let command = {
         }
     ],
     run: async (client: Client, interaction: CommandInteraction) => {
+
         switch (interaction.options.data[0].name) {
         case "today":
             if(interaction.options.data[0].options === undefined || interaction.options.data[0].options.length == 0){
-                fetch("http://127.0.0.1:5000/restaurants/")
-                    .then(r => r.json())
-                    .then(data => {
-                        console.log(`Last updated on ${data.updated}`);
-                        for (const [restaurantEntryId, restaurantData] of Object.entries(data.restaurants)) {
-                            const restaurantDataObj = Object(restaurantData); // assure restaurantData is an object
-                            console.log(`Restaurant ID: ${restaurantEntryId}, Name: ${restaurantDataObj.name}`);
-                            try {
-                                if (restaurantDataObj.meals[0].name !== undefined) {
-                                    let mealStringBldr = "Meals: ";
-                                    for (const [mealEntryId, mealData] of Object.entries(restaurantDataObj.meals)) {
-                                        const mealDataObj = Object(mealData); // assure mealData is an object
-                                        mealStringBldr += `${mealEntryId}: ${mealDataObj.name}, `;
-                                    }
-                                    console.log(mealStringBldr.slice(0, -2)); // finally remove last 2 chars
-                                }
-                            } catch (e) { /* ignored exception */ }
-                            console.log();
-                        }
-                        interaction.followUp("lmao, en mä pysty laittaa kaikkien raflojen ruokalistoi kun tulee 2000 merkin merkkiraja vastaan.");
-                    })
-                    .catch(e => {
-                        console.error(e);
-                        interaction.followUp("Something went wrong");
-                    });
-            } else  {
+                await interaction.followUp("Miten sä edes onnistuit tässä? Anyway, en voi tulostaa kaikkien raflojen tietoja koska enimmäismerkkimäärä tulee vastaan.");
+            } else {
                 const restaurantEntryId = interaction.options.data[0].options[0].value;
                 fetch(`http://127.0.0.1:5000/restaurants/${restaurantEntryId}/today`)
                     .then(r => r.json())
-                    .then(data => {
-                        interaction.followUp(`**Todays menu for ${data.name}:**\n` + menuToString(data));
-                        console.log(`Todays menu for ${data.name}:\n` + menuToString(data));
+                    .then(async data => {
+                        const { guild } = interaction;
+                        const response = await interaction.followUp(
+                            {
+                                content: `**Ravintolan ${data.name} tämän päivän ruokalista:**\n${menuToString(data)}`,
+                                components: [
+                                    NewThreadButton
+                                ]
+                            }
+                        );
+                        console.debug(`Todays menu for ${data.name}:\n` + menuToString(data));
+                        const collectorFilter: CollectorFilter<any> = (i: any) => i.customId === "make_thread";
+                        try {
+                            const confirmation = await response.awaitMessageComponent({filter: collectorFilter});
+
+                            const targetChannel = await guild?.channels.fetch(interaction.channelId);
+                            if (!targetChannel) {
+                                confirmation.reply(`En löytänyt kanavaa ${targetChannel}! Tätä virhettä ei pitäis tapahtua lol`);
+                            }
+
+                            const foodDateThread = await response.startThread({
+                                name: `${getFormattedDate(new Date())} ${data.name}`,
+                                autoArchiveDuration: 1440,
+                                reason: "Tässä langassa voitte sopia tarkemmin syöntitreffeistä!"
+                            });
+
+                            confirmation.reply(`${response.interaction?.user} on menossa syömään ravintolaan ${data.name}! Luotiin uusi lanka.`);
+                            console.debug(`Started a thread: ${foodDateThread.name}`);
+
+                        } catch (e) {
+                            console.error(e);
+                            await interaction.followUp("Jokin meni pieleen napinpainallukseen reagoimisessa.");
+                        }
                     })
                     .catch(e => {
                         console.error(e);
-                        interaction.followUp("Something went wrong");
+                        interaction.followUp("Jokin meni pieleen. Hups.");
                     });
             }
             break;
@@ -104,10 +113,10 @@ let command = {
                     .then(r => r.json())
                     .then(data => {
                         let messageIndex = 0;
-                        const messages: string[] = [`**This weeks menu for restaurant id ${restaurantEntryId}:**\n`];
+                        const messages: string[] = [`**Ravintolan ${data.name} tämän viikon ruokalista:**\n`];
                         for(const [key, value] of Object.entries(data)){
                             const menu = Object(value);
-                            const daymenu = `__**Day ${key}:**__\n` + menuToString(menu) + "\n";
+                            const daymenu = `__**Päivä ${key}:**__\n` + menuToString(menu) + "\n";
 
                             // Messages must be less than 2000 characters in length, breaking messages into parts if max length is exceeded.
                             if(messages[messageIndex].length + daymenu.length <= 2000){
@@ -115,7 +124,7 @@ let command = {
                             } else {
                                 console.log(messages[messageIndex]);
                                 interaction.followUp(messages[messageIndex]);
-                                messages[++messageIndex] = `Command response part ${messageIndex + 1} (Maximum Discord message length exceeded)\n` + daymenu;
+                                messages[++messageIndex] = `Vastauksen osa ${messageIndex + 1} (Discord-viestin enimmäismerkkimäärä ylitetty)\n` + daymenu;
                             }
                         }
                         console.log(messages[messageIndex]);
@@ -123,12 +132,12 @@ let command = {
                     })
                     .catch(e => {
                         console.error(e);
-                        interaction.followUp("Something went wrong");
+                        interaction.followUp("Jokin meni pieleen.");
                     });
             }
             break;
         default:
-            interaction.followUp("Invalid subcommand. Not my fault bro.");
+            await interaction.followUp("Virheellinen alakomento. Ei oo mun vika bro.");
         }
     }
 };
diff --git a/src/models/InternalModel.ts b/src/models/InternalModel.ts
deleted file mode 100644
index 4e79d5d..0000000
--- a/src/models/InternalModel.ts
+++ /dev/null
@@ -1,8 +0,0 @@
-import {Locale} from "discord.js";
-
-export class EventData {
-    constructor(
-    public lang: Locale,
-    public langGuild: Locale
-    ) {}
-}
\ No newline at end of file
diff --git a/src/utils/getFormattedDate.ts b/src/utils/getFormattedDate.ts
new file mode 100644
index 0000000..e08278f
--- /dev/null
+++ b/src/utils/getFormattedDate.ts
@@ -0,0 +1,6 @@
+export const getFormattedDate = (date : Date) : string => {
+    const day : string = String(date.getDate()).padStart(2, "0");
+    const month : string= String(date.getMonth() + 1).padStart(2, "0");
+    const year : number = date.getFullYear();
+    return `${day}.${month}.${year}`;
+};
\ No newline at end of file
diff --git a/tsconfig.json b/tsconfig.json
index 0fd5409..0ef743d 100644
--- a/tsconfig.json
+++ b/tsconfig.json
@@ -97,7 +97,7 @@
     // "noImplicitReturns": true,                        /* Enable error reporting for codepaths that do not explicitly return in a function. */
     // "noFallthroughCasesInSwitch": true,               /* Enable error reporting for fallthrough cases in switch statements. */
     // "noUncheckedIndexedAccess": true,                 /* Add 'undefined' to a type when accessed using an index. */
-    // "noImplicitOverride": true,                       /* Ensure overriding members in derived classes are marked with an override modifier. */
+    // "noImplicitOverride": true,                       /* Ensure overriding members in derived buttons are marked with an override modifier. */
     // "noPropertyAccessFromIndexSignature": true,       /* Enforces using indexed accessors for keys declared using an indexed type. */
     // "allowUnusedLabels": true,                        /* Disable error reporting for unused labels. */
     "allowUnreachableCode": true,                     /* Disable error reporting for unreachable code. */
-- 
GitLab