import {ConfigurationHandler, PathConfigurationFrom} from "./ConfigurationHandler"; import { AnyMenuItem, CollectionMenuItem, FieldMenuItem, FieldMenuItemContext, FieldMenuItemSaveValue, MenuItem, MenuItemType, PromptMenuItem } from "../Menu/MenuRenderer.types"; import {TraversalPath} from "../Menu/MenuTraversal.types"; import { channelMention, ChannelSelectMenuBuilder, ChannelType, italic, StringSelectMenuBuilder, TextInputBuilder, TextInputStyle } from "discord.js"; import {MessageActionRowComponentBuilder} from "@discordjs/builders"; import {TransformerType} from "./ConfigurationTransformer"; type FieldHandlerMenuItem = MenuItem & (Partial | Partial); type HandlerMenuItem = FieldHandlerMenuItem | CollectionMenuItem export class MenuHandler { constructor( private readonly config: ConfigurationHandler, ) { } public fillMenuItems( menuItems: HandlerMenuItem[] ): AnyMenuItem[] { const handler = this; function resolve(path: TraversalPath, menuItem: HandlerMenuItem): AnyMenuItem { path = [...path, menuItem.traversalKey]; if (menuItem.type === MenuItemType.Collection) { menuItem.children = menuItem.children.map((nextMenuItem) => resolve(path, nextMenuItem)) return menuItem; } const transformerType = handler.config.transformer.getTransformerType(path.join('.')); if (transformerType === undefined || transformerType === null) { throw new Error(`Can't resolve type for '${path.join('.')}'`); } menuItem.type = handler.findType(transformerType); menuItem.setValue = handler.setValue.bind(handler); menuItem.getCurrentValue = handler.findCurrentValueMethod(transformerType); menuItem.getActionRowBuilder = handler.findActionRowBuilderMethod(transformerType); return menuItem; } return menuItems.map((menuItem) => resolve([], menuItem)) } private findType(transformer: TransformerType): MenuItemType.Field | MenuItemType.Prompt { switch (transformer) { case TransformerType.String: case TransformerType.Paragraph: return MenuItemType.Prompt; default: return MenuItemType.Field; } } private findCurrentValueMethod(transformer: TransformerType): (context: FieldMenuItemContext) => string { switch (transformer) { case TransformerType.Channel: return this.getChannelValue.bind(this); case TransformerType.PermissionBoolean: return this.getPermissionBooleanValue.bind(this); case TransformerType.String: case TransformerType.Paragraph: return this.getStringValue.bind(this); } } private findActionRowBuilderMethod(transformer: TransformerType): ((context: FieldMenuItemContext) => MessageActionRowComponentBuilder) | ((context: FieldMenuItemContext) => TextInputBuilder) { switch (transformer) { case TransformerType.Channel: return this.getChannelMenuBuilder.bind(this); case TransformerType.PermissionBoolean: return this.getPermissionBooleanBuilder.bind(this); case TransformerType.String: return this.getStringBuilder.bind(this); case TransformerType.Paragraph: return this.getTextareaBuilder.bind(this); } } private getChannelValue(context: FieldMenuItemContext): string { const value = this.config.getConfigurationByPath(context.path.join('.')); const isDefault = value.from === PathConfigurationFrom.Default; const display = !value ? "None" : channelMention(value.value); if (isDefault) { return italic(`Default (${display})`) } return display; } private getChannelMenuBuilder(): MessageActionRowComponentBuilder { return new ChannelSelectMenuBuilder() .setChannelTypes(ChannelType.GuildText) .setPlaceholder("New Value"); } private getPermissionBooleanValue(context: FieldMenuItemContext) { const value = this.config.getConfigurationByPath(context.path.join('.')); const isDefault = value.from === PathConfigurationFrom.Default; const display = value.value === null ? "None" : value.value == true ? "Allowed" : "Disallowed"; if (isDefault) { return italic(`Default (${display})`) } return display; } private getPermissionBooleanBuilder() { return new StringSelectMenuBuilder() .setOptions( [ { label: "Allow", value: "1" }, { label: "Disallow", value: "0" } ] ) } private getStringValue(context: FieldMenuItemContext): string { const value = this.config.getConfigurationByPath(context.path.join('.')); return value.value === null ? "" : value.value; } private getStringBuilder(): TextInputBuilder { return new TextInputBuilder() .setStyle(TextInputStyle.Short) .setMaxLength(100) } private getTextareaBuilder(): 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.config.save(context.path.join('.'), savedValue); } }