Advertisement
Richbadniss

Forhire draft system

Aug 20th, 2023
888
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. const { StringSelectMenuBuilder, ActionRowBuilder, StringSelectMenuOptionBuilder, EmbedBuilder, inlineCode, bold, italic, ButtonBuilder, ButtonStyle, CommandInteraction } = require('discord.js');
  2. const uuid = require("../../../utils/generateUUID");
  3. const userGlobalData = require("../../../model/userGlobalData");
  4. const { forhire } = require("../../../model/postApplication");
  5.  
  6. /**
  7.  * Function to handle creating or updating a draft for a "for hire" post.
  8.  * @param {Client} client - The Discord bot client.
  9.  * @param {CommandInteraction} interaction - The command interaction object.
  10.  * @param {Array} userRoleData - An array of user role data.
  11.  * @param {String} postId - Optional post ID.
  12.  */
  13. module.exports = async (client, interaction, userRoleData, postId) => {
  14.     const id = postId || uuid();
  15.     const userPostData = await forhire.findOne({ postId: postId || id });
  16.     const userData = await userGlobalData.findOne({ userId: interaction.user.id });
  17.  
  18.     const draftTemplate = {
  19.         draftId: id,
  20.         draftType: "forhire",
  21.         draftTitle: userPostData?.postTitle || "<Untitled Post>",
  22.     }
  23.  
  24.     if (!userPostData) {
  25.         await forhire.create({
  26.             postId: id,
  27.             userId: interaction.user.id
  28.         });
  29.  
  30.         userData.postDrafts = [...userData.postDrafts, draftTemplate];
  31.         await userData.save();
  32.     } else {
  33.         let draft = userData.postDrafts.find((x) => x.draftId === postId);
  34.         if (draft) {
  35.             draft = draftTemplate
  36.             await userData.save();
  37.         } else {
  38.             userData.postDrafts = [...userData.postDrafts, draftTemplate];
  39.             await userData.save();
  40.         };
  41.  
  42.     };
  43.  
  44.     // Checking if the string is a Valid URL
  45.     const isValidUrl = urlString=> {
  46.         try {
  47.             return Boolean(new URL(urlString));
  48.         }
  49.         catch(e){
  50.             return false;
  51.         }
  52.     }
  53.  
  54.     const text = `Here's a preview of your post. Use the editor below to change how it looks.
  55.     Your changes are saved automatically. If you'd like to continue where you left off, run ${inlineCode("/post")} and select "Edit an existing post"
  56.    
  57.     You cannot submit for approval until required fields (*) are filled out.
  58.     If the bot does not allow you to post in a particular hireable channel, you do not have the relevant role for that channel.`
  59.  
  60.     const money = `${bold("Robux")}: R$${userPostData?.robuxValue || "null"}\n${bold("USD")}: $${userPostData?.usdValue || "null"}\n${bold("Percentage")}: ${userPostData?.percentageValue || "null"}%`
  61.  
  62.     const links = userPostData?.pastworkLinks || ""
  63.     let separator = " ";
  64.     if (links.includes(",")) {
  65.       separator = ",";
  66.     }
  67.    
  68.     // Split the links based on the separator
  69.     const linkArray = links.split(separator).map(link => link.trim());
  70.    
  71.     // Format the links using Markdown syntax
  72.     const formattedLinks = linkArray.map(link => {
  73.       const [url] = link.split(" ");
  74.       return `[link](${url})`;
  75.     });
  76.    
  77.     // Join the formatted links back together with the same separator
  78.     const markdownFormatted = formattedLinks.join(separator + ", ");
  79.  
  80.     // Draft embed
  81.     const embed = new EmbedBuilder()
  82.         .setTitle(`${userPostData?.postTitle || "<Untitled Post>"}`)
  83.         .setAuthor({ name: interaction.user.username, iconURL: interaction.user.avatarURL() })
  84.         .setDescription(`${userPostData?.postDescription || "<No description provided>"}`)
  85.         .setFooter({ text: `Post ID: (${userPostData?.postId || id}) • Draft` })
  86.         .addFields(
  87.             { name: "Payment", value: money, inline: true },
  88.             { name: "Payment Type", value: userPostData?.paymentType || italic("Nothing provided"), inline: true },
  89.             { name: "Portfolio", value: userPostData?.protfolioLink || italic("Nothing provided") },
  90.             { name: "Past Works", value: markdownFormatted || italic("Nothing provided") },
  91.             { name: "Contact", value: `<@${interaction.user.id}>` },
  92.         )
  93.         .setColor("Green");
  94.  
  95.     if (userPostData?.postThumbnail !== "" && isValidUrl(userPostData?.postThumbnail)) {
  96.         embed.setThumbnail(userPostData?.postThumbnail)
  97.     };
  98.  
  99.     if (userPostData?.postImage !== "" && isValidUrl(userPostData?.postImage)) {
  100.         embed.setImage(userPostData?.postImage)
  101.     };
  102.  
  103.     await interaction.update({ content: text, embeds: [embed], components: await createPostButtons(interaction.user.id, id, userPostData) })
  104.         .catch(error => console.log(error));
  105. }
  106.  
  107.  
  108.  
  109. async function createPostButtons(userId, postId, userPostData) {
  110.     const menuChannelHolder = [];
  111.     const avaliableChannels = await getChannelsFromSkills(userId);
  112.  
  113.     for (const channel of avaliableChannels) {
  114.         menuChannelHolder.push(
  115.             new StringSelectMenuOptionBuilder()
  116.                 .setLabel(`${channel[0]}`)
  117.                 .setEmoji("📦")
  118.                 .setDefault(channel[0] === userPostData?.channel)
  119.                 .setDescription(channel[1])
  120.                 .setValue(channel[0])
  121.         );
  122.     };
  123.  
  124.     let editRequiredText = "*Edit post info (2 required)"
  125.     let editRequiredColor = ButtonStyle.Danger
  126.  
  127.     let portfolioRequiredText = "*Edit portfolio (at least 1 required)"
  128.     let portfolioRequiredColor = ButtonStyle.Danger
  129.  
  130.     let paymentRequiredText = "*Edit payment info (at least 1 required)"
  131.     let paymentRequiredColor = ButtonStyle.Danger
  132.  
  133.     const addedValue =
  134.         userPostData?.robuxValue !== "" ||
  135.         userPostData?.usdValue !== "" ||
  136.         userPostData?.percentageValue !== "";
  137.  
  138.  
  139.     // Helper function to check if a value is defined and not empty
  140.     function isDefinedAndNotEmpty(value) {
  141.         return value !== undefined && value !== "";
  142.     }
  143.  
  144.     // Check payment requirements
  145.     if (addedValue && isDefinedAndNotEmpty(userPostData?.paymentType)) {
  146.         paymentRequiredText = "Edit payment info";
  147.         paymentRequiredColor = ButtonStyle.Secondary;
  148.     }
  149.  
  150.     // Check edit requirements
  151.     if (isDefinedAndNotEmpty(userPostData?.postTitle) || isDefinedAndNotEmpty(userPostData?.postDescription)) {
  152.         editRequiredText = "*Edit post info (1 required)";
  153.         editRequiredColor = ButtonStyle.Danger;
  154.     }
  155.  
  156.     // Check full edit requirements
  157.     if (isDefinedAndNotEmpty(userPostData?.postTitle) && isDefinedAndNotEmpty(userPostData?.postDescription)) {
  158.         editRequiredText = "Edit post info";
  159.         editRequiredColor = ButtonStyle.Secondary;
  160.     }
  161.  
  162.     // Check portfolio requirements
  163.     if (isDefinedAndNotEmpty(userPostData?.protfolioLink) && isDefinedAndNotEmpty(userPostData?.paymentType)) {
  164.         portfolioRequiredText = "Edit portfolio";
  165.         portfolioRequiredColor = ButtonStyle.Secondary;
  166.     }
  167.  
  168.  
  169.     const canSubmit =
  170.         userPostData?.paymentType !== "" &&
  171.         userPostData?.channel !== "" &&
  172.         addedValue &&
  173.         editRequiredColor !== ButtonStyle.Danger &&
  174.         portfolioRequiredColor !== ButtonStyle.Danger &&
  175.         paymentRequiredColor !== ButtonStyle.Danger;
  176.  
  177.  
  178.     let enabled = undefined
  179.     if (
  180.         portfolioRequiredColor === 2 &&
  181.         editRequiredColor === 2 &&
  182.         isDefinedAndNotEmpty(userPostData?.paymentType)
  183.     ) {
  184.         enabled = true
  185.     } else {
  186.         enabled = false
  187.     }
  188.  
  189.  
  190.     const buttons = [
  191.         edit = new ButtonBuilder()
  192.             .setCustomId(`edit_forhire_post_info|${postId}`)
  193.             .setLabel(editRequiredText)
  194.             .setStyle(editRequiredColor),
  195.  
  196.         payment = new ButtonBuilder()
  197.             .setCustomId(`edit_forhire_post_payment|${postId}`)
  198.             .setLabel(paymentRequiredText)
  199.             .setDisabled(!enabled)
  200.             .setStyle(paymentRequiredColor),
  201.  
  202.  
  203.         portfolio = new ButtonBuilder()
  204.             .setCustomId(`edit_forhire_post_portfolio|${postId}`)
  205.             .setLabel(portfolioRequiredText)
  206.             .setStyle(portfolioRequiredColor)
  207.     ];
  208.  
  209.     const lastButtons = [
  210.         submit = new ButtonBuilder()
  211.             .setCustomId(`submit_forhire_post|${postId}`)
  212.             .setLabel('Submit for approval')
  213.             .setDisabled(!canSubmit)
  214.             .setStyle(ButtonStyle.Success),
  215.  
  216.         back = new ButtonBuilder()
  217.             .setCustomId(`back_to_drafts|${postId}`)
  218.             .setLabel("Go back")
  219.             .setStyle(ButtonStyle.Secondary)
  220.     ]
  221.  
  222.     const channel = new StringSelectMenuBuilder()
  223.         .setCustomId(`edit_forhire_channel_type|${postId}`)
  224.         .setPlaceholder('Select a channel to post in')
  225.         .setMaxValues(1)
  226.         .addOptions(menuChannelHolder);
  227.  
  228.     const paymentTypes = new StringSelectMenuBuilder()
  229.         .setCustomId(`edit_forhire_post_payment_type|${postId}`)
  230.         .setPlaceholder('Select a payment type')
  231.         .setMaxValues(1)
  232.         .addOptions([
  233.             new StringSelectMenuOptionBuilder()
  234.                 .setLabel('Up-front')
  235.                 .setDescription("Up-front payment.")
  236.                 .setValue('Up-front'),
  237.  
  238.             new StringSelectMenuOptionBuilder()
  239.                 .setLabel('Partial up-front')
  240.                 .setDescription("Partial up-front payment.")
  241.                 .setValue('Partial up-front'),
  242.  
  243.             new StringSelectMenuOptionBuilder()
  244.                 .setLabel('Upon completion')
  245.                 .setDescription("One-time payment.")
  246.                 .setValue('Upon completion'),
  247.  
  248.             new StringSelectMenuOptionBuilder()
  249.                 .setLabel('Per-task')
  250.                 .setDescription("Per-task payment.")
  251.                 .setValue('Per-task'),
  252.         ]);
  253.  
  254.  
  255.     for (const option of paymentTypes.options) {
  256.         const eOP = option.data
  257.         if (eOP.value === userPostData?.paymentType) {
  258.             eOP.default = true;
  259.         } else {
  260.             eOP.default = false;
  261.         }
  262.     };
  263.  
  264.     return [
  265.         new ActionRowBuilder()
  266.             .addComponents(buttons),
  267.  
  268.         new ActionRowBuilder()
  269.             .addComponents(channel),
  270.  
  271.         new ActionRowBuilder()
  272.             .addComponents(paymentTypes),
  273.  
  274.         new ActionRowBuilder()
  275.             .addComponents(lastButtons),
  276.     ];
  277. }
  278.  
  279.  
  280. const channels = {
  281.     ["Luau Programmer"]: [
  282.         cName = "scripter-hiring",
  283.         desc = "For hiring Roblox-related scripting jobs"
  284.     ],
  285.     ["JavaScript Programmer"]: [
  286.         cName = "programmer-hiring",
  287.         desc = "For hiring Off-site programming jobs"
  288.     ],
  289. }
  290.  
  291. async function getChannelsFromSkills(userId) {
  292.     const data = await userGlobalData.findOne({ userId });
  293.     if (!data) return [];
  294.  
  295.     const skillChannels = []
  296.     for (const skill of data.skillRoles) {
  297.         if (channels[skill]) {
  298.             skillChannels.push(channels[skill]);
  299.         }
  300.     }
  301.     return skillChannels;
  302. }
  303.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement