Enhance embed functionality across scheduler and welcome components
- Updated SchedulerManager and WelcomeForm to integrate DiscordEmbedBuilder for managing embeds, replacing JSON text areas with a more user-friendly interface. - Modified data handling in the scheduler and welcome configurations to support embed structures, ensuring proper parsing and validation. - Updated localization files to reflect changes in embed handling, improving user guidance and clarity in both English and German. - Enhanced validation schemas to require embed titles or descriptions where necessary, ensuring robust data integrity.
This commit is contained in:
@@ -1,10 +1,15 @@
|
||||
'use client';
|
||||
|
||||
import type { WelcomeConfigDashboard } from '@nexumi/shared';
|
||||
import type { WelcomeConfigDashboard, WelcomeEmbed } from '@nexumi/shared';
|
||||
import { FieldAnchor } from '@/components/layout/field-anchor';
|
||||
import { useTranslations } from '@/components/locale-provider';
|
||||
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card';
|
||||
import { DiscordChannelSelect } from '@/components/ui/discord-channel-select';
|
||||
import {
|
||||
DiscordEmbedBuilder,
|
||||
embedFromUnknown,
|
||||
normalizeEmbed
|
||||
} from '@/components/ui/discord-embed-builder';
|
||||
import { DiscordRoleMultiSelect } from '@/components/ui/discord-role-select';
|
||||
import { Input } from '@/components/ui/input';
|
||||
import { Label } from '@/components/ui/label';
|
||||
@@ -14,55 +19,33 @@ import { Textarea } from '@/components/ui/textarea';
|
||||
import type { SettingsSaveResult } from '@/components/settings/settings-form';
|
||||
import { SettingsForm } from '@/components/settings/settings-form';
|
||||
|
||||
interface LocalWelcomeValue extends Omit<WelcomeConfigDashboard, 'welcomeEmbed' | 'leaveEmbed'> {
|
||||
welcomeEmbedText: string;
|
||||
leaveEmbedText: string;
|
||||
}
|
||||
const WELCOME_PREVIEW_VARS = {
|
||||
user: '@Alex',
|
||||
'user.name': 'Alex',
|
||||
'user.tag': 'Alex',
|
||||
'user.id': '123456789012345678',
|
||||
server: 'Nexumi',
|
||||
memberCount: '128'
|
||||
};
|
||||
|
||||
function toJsonText(value: Record<string, unknown> | null | undefined): string {
|
||||
return value ? JSON.stringify(value, null, 2) : '';
|
||||
interface LocalWelcomeValue extends Omit<WelcomeConfigDashboard, 'welcomeEmbed' | 'leaveEmbed'> {
|
||||
welcomeEmbed: WelcomeEmbed | null;
|
||||
leaveEmbed: WelcomeEmbed | null;
|
||||
}
|
||||
|
||||
function toLocal(config: WelcomeConfigDashboard): LocalWelcomeValue {
|
||||
const { welcomeEmbed, leaveEmbed, ...rest } = config;
|
||||
return {
|
||||
...rest,
|
||||
welcomeEmbedText: toJsonText(welcomeEmbed),
|
||||
leaveEmbedText: toJsonText(leaveEmbed)
|
||||
...config,
|
||||
welcomeEmbed: embedFromUnknown(config.welcomeEmbed),
|
||||
leaveEmbed: embedFromUnknown(config.leaveEmbed)
|
||||
};
|
||||
}
|
||||
|
||||
function parseEmbedJson(text: string): { value: Record<string, unknown> | null; error?: string } {
|
||||
if (!text.trim()) {
|
||||
return { value: null };
|
||||
}
|
||||
try {
|
||||
const parsed = JSON.parse(text);
|
||||
if (parsed && typeof parsed === 'object' && !Array.isArray(parsed)) {
|
||||
return { value: parsed as Record<string, unknown> };
|
||||
}
|
||||
return { value: null, error: 'Invalid embed JSON (must be an object)' };
|
||||
} catch {
|
||||
return { value: null, error: 'Invalid embed JSON' };
|
||||
}
|
||||
}
|
||||
|
||||
async function saveWelcome(guildId: string, value: LocalWelcomeValue): Promise<SettingsSaveResult> {
|
||||
const welcomeEmbed = parseEmbedJson(value.welcomeEmbedText);
|
||||
if (welcomeEmbed.error) {
|
||||
return { ok: false, error: welcomeEmbed.error };
|
||||
}
|
||||
const leaveEmbed = parseEmbedJson(value.leaveEmbedText);
|
||||
if (leaveEmbed.error) {
|
||||
return { ok: false, error: leaveEmbed.error };
|
||||
}
|
||||
|
||||
const { welcomeEmbedText: _welcomeEmbedText, leaveEmbedText: _leaveEmbedText, ...rest } = value;
|
||||
|
||||
const payload: WelcomeConfigDashboard = {
|
||||
...rest,
|
||||
welcomeEmbed: welcomeEmbed.value,
|
||||
leaveEmbed: leaveEmbed.value
|
||||
...value,
|
||||
welcomeEmbed: normalizeEmbed(value.welcomeEmbed),
|
||||
leaveEmbed: normalizeEmbed(value.leaveEmbed)
|
||||
};
|
||||
|
||||
try {
|
||||
@@ -154,12 +137,10 @@ export function WelcomeForm({ guildId, initialValue }: WelcomeFormProps) {
|
||||
<FieldAnchor id="field-welcome-embed">
|
||||
<div className="space-y-2">
|
||||
<Label>{t('modulePages.welcome.welcomeEmbed')}</Label>
|
||||
<Textarea
|
||||
className="font-mono"
|
||||
rows={6}
|
||||
value={value.welcomeEmbedText}
|
||||
onChange={(event) => setValue((prev) => ({ ...prev, welcomeEmbedText: event.target.value }))}
|
||||
placeholder='{ "title": "Welcome!", "color": 6591981 }'
|
||||
<DiscordEmbedBuilder
|
||||
value={value.welcomeEmbed}
|
||||
onChange={(welcomeEmbed) => setValue((prev) => ({ ...prev, welcomeEmbed }))}
|
||||
previewVars={WELCOME_PREVIEW_VARS}
|
||||
/>
|
||||
</div>
|
||||
</FieldAnchor>
|
||||
@@ -260,12 +241,10 @@ export function WelcomeForm({ guildId, initialValue }: WelcomeFormProps) {
|
||||
<FieldAnchor id="field-leave-embed">
|
||||
<div className="space-y-2">
|
||||
<Label>{t('modulePages.welcome.leaveEmbed')}</Label>
|
||||
<Textarea
|
||||
className="font-mono"
|
||||
rows={6}
|
||||
value={value.leaveEmbedText}
|
||||
onChange={(event) => setValue((prev) => ({ ...prev, leaveEmbedText: event.target.value }))}
|
||||
placeholder='{ "title": "Goodbye", "color": 15158332 }'
|
||||
<DiscordEmbedBuilder
|
||||
value={value.leaveEmbed}
|
||||
onChange={(leaveEmbed) => setValue((prev) => ({ ...prev, leaveEmbed }))}
|
||||
previewVars={WELCOME_PREVIEW_VARS}
|
||||
/>
|
||||
</div>
|
||||
</FieldAnchor>
|
||||
|
||||
Reference in New Issue
Block a user