import { AnyMenuItem, FieldMenuItem, FieldMenuItemContext, FieldMenuItemSaveValue, MenuItem, MenuItemType, PromptMenuItem, RowBuilderFieldMenuItemContext } from "../Menu/MenuRenderer.types"; import {GroupConfigurationTransformers} from "./GroupConfigurationTransformers"; import {GroupConfigurationHandler} from "./GroupConfigurationHandler"; import { channelMention, ChannelSelectMenuBuilder, ChannelType, inlineCode, italic, Snowflake, StringSelectMenuBuilder, StringSelectMenuOptionBuilder, TextInputBuilder, TextInputStyle } from "discord.js"; import {ChannelId} from "../types/DiscordTypes"; import {MessageActionRowComponentBuilder} from "@discordjs/builders"; import {Prompt} from "../Menu/Modals/Prompt"; export class ConfigurationMenuHandler { constructor( private readonly configuration: GroupConfigurationHandler, private readonly transformer: GroupConfigurationTransformers ) { } public getMenuItems(): AnyMenuItem[] { return [ { traversalKey: "channels", label: "Channels", description: "Provides settings to define in what channels the bot sends messages, when not directly interacting with it.", type: MenuItemType.Collection, children: [ { traversalKey: "newPlaydates", label: "New Playdates", description: "Sets the channel, where the group gets notified, when new Playdates are set.", type: MenuItemType.Field, getCurrentValue: this.getChannelValue.bind(this), getActionRowBuilder: this.getChannelMenuBuilder.bind(this), setValue: this.setValue.bind(this) }, { traversalKey: "playdateReminders", label: 'Playdate Reminders', description: "Sets the channel, where the group gets reminded of upcoming playdates.", type: MenuItemType.Field, getCurrentValue: this.getChannelValue.bind(this), getActionRowBuilder: this.getChannelMenuBuilder.bind(this), setValue: this.setValue.bind(this) } ] }, { traversalKey: "permissions", label: "Permissions", description: "Allows customization, how the members are allowed to interact with the data stored in the group.", type: MenuItemType.Collection, children: [ { traversalKey: "allowMemberManagingPlaydates", label: "Manage Playdates", description: "Defines if the members are allowed to manage playdates like adding or deleting them.", type: MenuItemType.Field, getCurrentValue: this.getPermissionBooleanValue.bind(this), getActionRowBuilder: this.getPermissionBooleanBuilder.bind(this), setValue: this.setValue.bind(this) } ] }, { traversalKey: "calendar", label: "Calendar", description: "Provides settings for the metadata contained in the playdate exports.", type: MenuItemType.Collection, children: [ this.createStringMenuItem({ traversalKey: "title", label: "Title", description: "Defines how the calendar entry should be called.", }), this.createTextareaMenuItem({ traversalKey: "description", label: "Description", description: "Sets the description for the calendar entry.", }), this.createStringMenuItem({ traversalKey: "location", label: "Location", description: "Sets the location where the calendar should point to." }), ] }, ] } private createStringMenuItem(metadata: MenuItem): PromptMenuItem { return { ...metadata, type: MenuItemType.Prompt, getCurrentValue: this.getStringValue.bind(this), getActionRowBuilder: this.getStringBuilder.bind(this), setValue: this.setValue.bind(this) }; } private createTextareaMenuItem(metadata: MenuItem): PromptMenuItem { return { ...metadata, type: MenuItemType.Prompt, getCurrentValue: this.getStringValue.bind(this), getActionRowBuilder: this.getTextareaBuilder.bind(this), setValue: this.setValue.bind(this) }; } private getChannelValue(context: FieldMenuItemContext): string { const value = this.configuration.getConfigurationByPath(context.path.join('.')); if (value === undefined) { return italic("None"); } if (!value) { return inlineCode("None"); } return channelMention(value); } private getChannelMenuBuilder(context: FieldMenuItemContext): MessageActionRowComponentBuilder { return new ChannelSelectMenuBuilder() .setChannelTypes(ChannelType.GuildText) .setPlaceholder("New Value"); } private getLocaleValue(context: FieldMenuItemContext): string { const value = this.configuration.getConfigurationByPath(context.path.join('.')); if (value === undefined) { return italic("None"); } if (!value) { return inlineCode("Default"); } const displaynames = new Intl.DisplayNames(["en"], {type: "language"}); return displaynames.of((value)?.baseName) ?? "Unknown"; } private getLocaleMenuBuilder(context: FieldMenuItemContext): MessageActionRowComponentBuilder { const options = [ 'en-US', 'fr-FR', 'it-IT', 'de-DE' ] const displaynames = new Intl.DisplayNames(["en"], {type: "language"}); return new StringSelectMenuBuilder() .setOptions( options.map(intl => new StringSelectMenuOptionBuilder() .setLabel(displaynames.of(intl) ?? '') .setValue(intl) ) ) } private getPermissionBooleanValue(context: FieldMenuItemContext) { const value = this.configuration.getConfigurationByPath(context.path.join('.')); if (value === undefined) { return italic("None"); } return value ? 'Allowed' : "Disallowed"; } private getPermissionBooleanBuilder(context: FieldMenuItemContext) { return new StringSelectMenuBuilder() .setOptions( [ { label: "Allow", value: "1" }, { label: "Disallow", value: "0" } ] ) } private getStringValue(context: FieldMenuItemContext): string { const value = this.configuration.getConfigurationByPath(context.path.join('.')); if (!value) { return ""; } if (typeof value !== 'string') { throw new TypeError(`Value of type ${typeof value} can't be used for a string value!`) } return value; } private getStringBuilder(context: FieldMenuItemContext): TextInputBuilder { return new TextInputBuilder() .setStyle(TextInputStyle.Short) .setMaxLength(100) } private getTextareaBuilder(context: FieldMenuItemContext): TextInputBuilder { return new TextInputBuilder() .setStyle(TextInputStyle.Paragraph) .setMaxLength(2048) } private setValue(value: FieldMenuItemSaveValue[]|string, context: FieldMenuItemContext): void { const savedValue = typeof value !== 'string' ? value.join('; ') : value; this.configuration.saveConfiguration(context.path.join('.'), savedValue); } }