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:
TheOnlyMace
2026-07-22 21:49:38 +02:00
parent 6a223892dd
commit 55a4f7bf09
10 changed files with 392 additions and 82 deletions

View File

@@ -1,4 +1,5 @@
import { z } from 'zod';
import { WelcomeEmbedSchema } from './phase2.js';
import {
SelfRoleBehaviorSchema,
SelfRoleEntrySchema,
@@ -9,6 +10,10 @@ import {
} from './phase4.js';
import { SocialFeedTypeSchema } from './phase5.js';
/** Dashboard embed payload shared by Welcome, Tags, Scheduler, etc. */
export const DashboardEmbedSchema = WelcomeEmbedSchema;
export type DashboardEmbed = z.infer<typeof DashboardEmbedSchema>;
/**
* Discord snowflake ID: 17-20 digit numeric string.
*/
@@ -192,9 +197,9 @@ export const WelcomeConfigDashboardSchema = z.object({
leaveChannelId: OptionalSnowflakeSchema,
welcomeType: WelcomeMessageTypeDashboardSchema,
welcomeContent: z.string().max(2000).nullable().optional(),
welcomeEmbed: z.record(z.string(), z.unknown()).nullable().optional(),
welcomeEmbed: DashboardEmbedSchema.nullable().optional(),
leaveContent: z.string().max(2000).nullable().optional(),
leaveEmbed: z.record(z.string(), z.unknown()).nullable().optional(),
leaveEmbed: DashboardEmbedSchema.nullable().optional(),
welcomeDmEnabled: z.boolean(),
welcomeDmContent: z.string().max(2000).nullable().optional(),
userAutoroleIds: z.array(z.string()),
@@ -390,6 +395,7 @@ export const TagDashboardSchema = z.object({
id: z.string().optional(),
name: z.string().min(1).max(50),
content: z.string().max(2000).nullable().optional(),
embed: DashboardEmbedSchema.nullable().optional(),
responseType: TagResponseTypeSchema,
triggerWord: z.string().max(100).nullable().optional(),
allowedRoleIds: z.array(z.string()),
@@ -397,10 +403,16 @@ export const TagDashboardSchema = z.object({
});
export type TagDashboard = z.infer<typeof TagDashboardSchema>;
export const TagDashboardCreateSchema = TagDashboardSchema.omit({ id: true });
export const TagDashboardCreateSchema = TagDashboardSchema.omit({ id: true }).refine(
(value) =>
value.responseType !== 'EMBED' ||
Boolean(value.embed?.title?.trim()) ||
Boolean(value.embed?.description?.trim()),
{ message: 'Embed title or description is required for EMBED tags', path: ['embed'] }
);
export type TagDashboardCreate = z.infer<typeof TagDashboardCreateSchema>;
export const TagDashboardUpdateSchema = nonEmptyPatch(TagDashboardCreateSchema);
export const TagDashboardUpdateSchema = nonEmptyPatch(TagDashboardSchema.omit({ id: true }));
export type TagDashboardUpdate = z.infer<typeof TagDashboardUpdateSchema>;
// ---------------------------------------------------------------------------
@@ -547,6 +559,7 @@ export const ScheduledMessageDashboardSchema = z.object({
channelId: z.string(),
creatorId: z.string(),
content: z.string().nullable(),
embed: DashboardEmbedSchema.nullable().optional(),
rolePingId: z.string().nullable(),
cron: z.string().nullable(),
runAt: z.string().nullable(),
@@ -559,6 +572,7 @@ export const ScheduledMessageDashboardCreateSchema = z
.object({
channelId: SnowflakeSchema,
content: z.string().max(2000).nullable().optional(),
embed: DashboardEmbedSchema.nullable().optional(),
rolePingId: OptionalSnowflakeSchema.optional(),
cron: z.string().min(1).max(100).nullable().optional(),
runAt: z
@@ -570,9 +584,13 @@ export const ScheduledMessageDashboardCreateSchema = z
.refine((value) => Boolean(value.cron?.trim()) || Boolean(value.runAt), {
message: 'Either cron or runAt is required'
})
.refine((value) => Boolean(value.content?.trim()), {
message: 'Content is required'
});
.refine(
(value) =>
Boolean(value.content?.trim()) ||
Boolean(value.embed?.title?.trim()) ||
Boolean(value.embed?.description?.trim()),
{ message: 'Content or embed is required' }
);
export type ScheduledMessageDashboardCreate = z.infer<typeof ScheduledMessageDashboardCreateSchema>;
// ---------------------------------------------------------------------------