diff --git a/apps/webui/src/components/modules/scheduler-manager.tsx b/apps/webui/src/components/modules/scheduler-manager.tsx index c84507e..db83aa2 100644 --- a/apps/webui/src/components/modules/scheduler-manager.tsx +++ b/apps/webui/src/components/modules/scheduler-manager.tsx @@ -1,6 +1,6 @@ 'use client'; -import type { ScheduledMessageDashboard } from '@nexumi/shared'; +import type { ScheduledMessageDashboard, WelcomeEmbed } from '@nexumi/shared'; import { Plus, Trash2 } from 'lucide-react'; import { useState } from 'react'; import { toast } from 'sonner'; @@ -9,6 +9,7 @@ import { useTranslations } from '@/components/locale-provider'; import { Button } from '@/components/ui/button'; import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card'; import { DiscordChannelSelect } from '@/components/ui/discord-channel-select'; +import { DiscordEmbedBuilder, normalizeEmbed } from '@/components/ui/discord-embed-builder'; import { DiscordRoleSelect } from '@/components/ui/discord-role-select'; import { Input } from '@/components/ui/input'; import { Label } from '@/components/ui/label'; @@ -17,6 +18,7 @@ import { Textarea } from '@/components/ui/textarea'; const EMPTY_DRAFT = { channelId: '', content: '', + embed: null as WelcomeEmbed | null, rolePingId: '', cron: '', runAt: '' @@ -35,6 +37,19 @@ function formatTiming(schedule: ScheduledMessageDashboard, t: (key: string) => s return '—'; } +function schedulePreview(schedule: ScheduledMessageDashboard, t: (key: string) => string): string { + if (schedule.content?.trim()) { + return schedule.content; + } + if (schedule.embed?.title?.trim()) { + return schedule.embed.title; + } + if (schedule.embed?.description?.trim()) { + return schedule.embed.description; + } + return t('modulePages.scheduler.noContent'); +} + interface SchedulerManagerProps { guildId: string; initialSchedules: ScheduledMessageDashboard[]; @@ -47,7 +62,9 @@ export function SchedulerManager({ guildId, initialSchedules }: SchedulerManager const [creating, setCreating] = useState(false); async function handleCreate() { - if (!draft.channelId.trim() || !draft.content.trim() || (!draft.cron.trim() && !draft.runAt)) { + const embed = normalizeEmbed(draft.embed); + const hasContent = Boolean(draft.content.trim()) || Boolean(embed?.title) || Boolean(embed?.description); + if (!draft.channelId.trim() || !hasContent || (!draft.cron.trim() && !draft.runAt)) { toast.error(t('modulePages.scheduler.formIncomplete')); return; } @@ -58,7 +75,8 @@ export function SchedulerManager({ guildId, initialSchedules }: SchedulerManager headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ channelId: draft.channelId.trim(), - content: draft.content.trim(), + content: draft.content.trim() || null, + embed, rolePingId: draft.rolePingId.trim() || undefined, cron: draft.cron.trim() || null, runAt: draft.cron.trim() ? null : draft.runAt ? new Date(draft.runAt).toISOString() : null @@ -151,6 +169,10 @@ export function SchedulerManager({ guildId, initialSchedules }: SchedulerManager rows={3} /> +
+ + setDraft((prev) => ({ ...prev, embed }))} /> +

{t('modulePages.scheduler.cronHint')}