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) {
-