Implement leveling rewards feature with UI and backend support
- Added functionality to manage role rewards based on user levels in the leveling system. - Updated the LevelingForm component to include fields for defining rewards, including validation for unique levels. - Enhanced backend logic to handle reward data storage and retrieval, ensuring proper integration with the existing leveling configuration. - Introduced localization keys for rewards in both English and German, improving user experience. - Updated dashboard search index to include rewards settings for easier access.
This commit is contained in:
@@ -499,6 +499,13 @@ export const SETTINGS_SEARCH_FIELDS: SearchIndexEntry[] = [
|
||||
href: 'leveling',
|
||||
hash: 'field-leveling-stack'
|
||||
},
|
||||
{
|
||||
id: 'setting-leveling-rewards',
|
||||
kind: 'setting',
|
||||
labelKey: 'modulePages.leveling.rewardsTitle',
|
||||
href: 'leveling',
|
||||
hash: 'field-leveling-rewards'
|
||||
},
|
||||
{
|
||||
id: 'setting-leveling-rank-card',
|
||||
kind: 'setting',
|
||||
|
||||
@@ -1,4 +1,9 @@
|
||||
import type { LevelingConfigDashboard, LevelingConfigDashboardPatch } from '@nexumi/shared';
|
||||
import {
|
||||
hasUniqueRewardLevels,
|
||||
type LevelingConfigDashboard,
|
||||
type LevelingConfigDashboardPatch,
|
||||
type LevelRewardDashboard
|
||||
} from '@nexumi/shared';
|
||||
import type { Prisma } from '@prisma/client';
|
||||
import { prisma } from '../prisma';
|
||||
|
||||
@@ -21,7 +26,10 @@ function toMultiplierMap(raw: unknown): Record<string, number> {
|
||||
return Object.fromEntries(entries);
|
||||
}
|
||||
|
||||
function toDashboard(config: Awaited<ReturnType<typeof ensureLevelingConfig>>): LevelingConfigDashboard {
|
||||
function toDashboard(
|
||||
config: Awaited<ReturnType<typeof ensureLevelingConfig>>,
|
||||
rewards: LevelRewardDashboard[]
|
||||
): LevelingConfigDashboard {
|
||||
return {
|
||||
enabled: config.enabled,
|
||||
textXpMin: config.textXpMin,
|
||||
@@ -36,14 +44,25 @@ function toDashboard(config: Awaited<ReturnType<typeof ensureLevelingConfig>>):
|
||||
levelUpChannelId: config.levelUpChannelId ?? '',
|
||||
levelUpMessage: config.levelUpMessage,
|
||||
stackRewards: config.stackRewards,
|
||||
rewards,
|
||||
cardAccentColor: config.cardAccentColor,
|
||||
cardBackgroundColor: config.cardBackgroundColor
|
||||
};
|
||||
}
|
||||
|
||||
async function loadRewards(guildId: string): Promise<LevelRewardDashboard[]> {
|
||||
const rows = await prisma.levelReward.findMany({
|
||||
where: { guildId },
|
||||
orderBy: { level: 'asc' },
|
||||
select: { level: true, roleId: true }
|
||||
});
|
||||
return rows.map((row) => ({ level: row.level, roleId: row.roleId }));
|
||||
}
|
||||
|
||||
export async function getLevelingDashboard(guildId: string): Promise<LevelingConfigDashboard> {
|
||||
const config = await ensureLevelingConfig(guildId);
|
||||
return toDashboard(config);
|
||||
const rewards = await loadRewards(guildId);
|
||||
return toDashboard(config, rewards);
|
||||
}
|
||||
|
||||
export async function updateLevelingDashboard(
|
||||
@@ -52,7 +71,11 @@ export async function updateLevelingDashboard(
|
||||
): Promise<LevelingConfigDashboard> {
|
||||
await ensureLevelingConfig(guildId);
|
||||
|
||||
const { levelUpChannelId, roleMultipliers, channelMultipliers, ...rest } = patch;
|
||||
if (patch.rewards !== undefined && !hasUniqueRewardLevels(patch.rewards)) {
|
||||
throw new Error('Duplicate reward levels are not allowed');
|
||||
}
|
||||
|
||||
const { levelUpChannelId, roleMultipliers, channelMultipliers, rewards, ...rest } = patch;
|
||||
const data: Prisma.LevelingConfigUpdateInput = { ...rest };
|
||||
if (levelUpChannelId !== undefined) {
|
||||
data.levelUpChannelId = levelUpChannelId === '' ? null : levelUpChannelId;
|
||||
@@ -64,6 +87,23 @@ export async function updateLevelingDashboard(
|
||||
data.channelMultipliers = channelMultipliers as Prisma.InputJsonValue;
|
||||
}
|
||||
|
||||
const updated = await prisma.levelingConfig.update({ where: { guildId }, data });
|
||||
return toDashboard(updated);
|
||||
await prisma.$transaction(async (tx) => {
|
||||
if (Object.keys(data).length > 0) {
|
||||
await tx.levelingConfig.update({ where: { guildId }, data });
|
||||
}
|
||||
if (rewards !== undefined) {
|
||||
await tx.levelReward.deleteMany({ where: { guildId } });
|
||||
if (rewards.length > 0) {
|
||||
await tx.levelReward.createMany({
|
||||
data: rewards.map((reward) => ({
|
||||
guildId,
|
||||
level: reward.level,
|
||||
roleId: reward.roleId
|
||||
}))
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
return getLevelingDashboard(guildId);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user