From 7888ccb7e6c00463e8fd00de7c888ebbd1c75e54 Mon Sep 17 00:00:00 2001 From: TheOnlyMace <0815cracky@gmail.com> Date: Wed, 22 Jul 2026 21:34:29 +0200 Subject: [PATCH] Refactor leveling form to use Discord multiplier editor and enhance localization - Replaced text area inputs for role and channel multipliers with DiscordMultiplierEditor components for improved user experience. - Updated state management to handle multiplier entries as objects instead of text, enhancing data integrity. - Enhanced localization messages for multipliers, including error handling and hints for user guidance. --- .../src/components/modules/leveling-form.tsx | 87 ++++++------- .../components/modules/ticket-config-form.tsx | 4 +- .../ui/discord-multiplier-editor.tsx | 122 ++++++++++++++++++ apps/webui/src/messages/de.json | 27 ++-- apps/webui/src/messages/en.json | 27 ++-- 5 files changed, 198 insertions(+), 69 deletions(-) create mode 100644 apps/webui/src/components/ui/discord-multiplier-editor.tsx diff --git a/apps/webui/src/components/modules/leveling-form.tsx b/apps/webui/src/components/modules/leveling-form.tsx index 3aab9a2..885f4e0 100644 --- a/apps/webui/src/components/modules/leveling-form.tsx +++ b/apps/webui/src/components/modules/leveling-form.tsx @@ -5,6 +5,12 @@ import { FieldAnchor } from '@/components/layout/field-anchor'; import { useTranslations } from '@/components/locale-provider'; import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card'; import { DiscordChannelMultiSelect, DiscordChannelSelect } from '@/components/ui/discord-channel-select'; +import { + DiscordMultiplierEditor, + mapToMultiplierEntries, + multiplierEntriesToMap, + type MultiplierEntry +} from '@/components/ui/discord-multiplier-editor'; import { DiscordRoleMultiSelect } from '@/components/ui/discord-role-select'; import { Input } from '@/components/ui/input'; import { Label } from '@/components/ui/label'; @@ -16,55 +22,34 @@ import { SettingsForm } from '@/components/settings/settings-form'; interface LocalLevelingValue extends Omit { - roleMultipliersText: string; - channelMultipliersText: string; -} - -function toMultiplierText(map: Record): string { - return Object.entries(map) - .map(([id, multiplier]) => `${id}:${multiplier}`) - .join('\n'); -} - -function fromMultiplierText(text: string): { value: Record; error?: string } { - const value: Record = {}; - const lines = text - .split('\n') - .map((line) => line.trim()) - .filter((line) => line.length > 0); - - for (const line of lines) { - const [id, multiplierRaw] = line.split(':').map((part) => part.trim()); - const multiplier = Number(multiplierRaw); - if (!id || Number.isNaN(multiplier) || multiplier <= 0) { - return { value: {}, error: `Invalid multiplier line: "${line}" (expected id:number)` }; - } - value[id] = multiplier; - } - - return { value }; + roleMultiplierEntries: MultiplierEntry[]; + channelMultiplierEntries: MultiplierEntry[]; } function toLocal(config: LevelingConfigDashboard): LocalLevelingValue { const { roleMultipliers, channelMultipliers, ...rest } = config; return { ...rest, - roleMultipliersText: toMultiplierText(roleMultipliers), - channelMultipliersText: toMultiplierText(channelMultipliers) + roleMultiplierEntries: mapToMultiplierEntries(roleMultipliers), + channelMultiplierEntries: mapToMultiplierEntries(channelMultipliers) }; } -async function saveLeveling(guildId: string, value: LocalLevelingValue): Promise { - const roleMultipliers = fromMultiplierText(value.roleMultipliersText); +async function saveLeveling(guildId: string, value: LocalLevelingValue, t: (key: string) => string): Promise { + const roleMultipliers = multiplierEntriesToMap(value.roleMultiplierEntries); if (roleMultipliers.error) { - return { ok: false, error: roleMultipliers.error }; + return { ok: false, error: t(`modulePages.leveling.errors.${roleMultipliers.error}`) }; } - const channelMultipliers = fromMultiplierText(value.channelMultipliersText); + const channelMultipliers = multiplierEntriesToMap(value.channelMultiplierEntries); if (channelMultipliers.error) { - return { ok: false, error: channelMultipliers.error }; + return { ok: false, error: t(`modulePages.leveling.errors.${channelMultipliers.error}`) }; } - const { roleMultipliersText: _roleMultipliersText, channelMultipliersText: _channelMultipliersText, ...rest } = value; + const { + roleMultiplierEntries: _roleMultiplierEntries, + channelMultiplierEntries: _channelMultiplierEntries, + ...rest + } = value; const payload: LevelingConfigDashboard = { ...rest, @@ -99,7 +84,7 @@ export function LevelingForm({ guildId, initialValue }: LevelingFormProps) { return ( initialValue={toLocal(initialValue)} - onSave={(value) => saveLeveling(guildId, value)} + onSave={(value) => saveLeveling(guildId, value, t)} > {({ value, setValue }) => (
@@ -197,12 +182,11 @@ export function LevelingForm({ guildId, initialValue }: LevelingFormProps) {
-