Add multiple admin improvements and bug fixes

- Email settings: Add separate sender display name field
- Rounds page: Drag-and-drop reordering with visible order numbers
- Round creation: Auto-assign projects to filtering rounds, auto-activate if voting started
- Round detail: Fix incorrect "voting period ended" message for draft rounds
- Projects page: Add delete option with confirmation dialog
- AI filtering: Add configurable batch size and parallel request settings
- Filtering results: Fix duplicate criteria display
- Add seed scripts for notification settings and MOPC onboarding form

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
2026-02-03 23:19:45 +01:00
parent 1d137ce93e
commit 3be6a743ed
12 changed files with 895 additions and 192 deletions

View File

@@ -33,6 +33,7 @@ const formSchema = z.object({
smtp_port: z.string().regex(/^\d+$/, 'Port must be a number'),
smtp_user: z.string().min(1, 'SMTP user is required'),
smtp_password: z.string().optional(),
email_from_name: z.string().min(1, 'Sender name is required'),
email_from: z.string().email('Invalid email address'),
})
@@ -44,6 +45,7 @@ interface EmailSettingsFormProps {
smtp_port?: string
smtp_user?: string
smtp_password?: string
email_from_name?: string
email_from?: string
}
}
@@ -60,6 +62,7 @@ export function EmailSettingsForm({ settings }: EmailSettingsFormProps) {
smtp_port: settings.smtp_port || '587',
smtp_user: settings.smtp_user || '',
smtp_password: '',
email_from_name: settings.email_from_name || 'MOPC Portal',
email_from: settings.email_from || 'noreply@monaco-opc.com',
},
})
@@ -93,6 +96,7 @@ export function EmailSettingsForm({ settings }: EmailSettingsFormProps) {
{ key: 'smtp_host', value: data.smtp_host },
{ key: 'smtp_port', value: data.smtp_port },
{ key: 'smtp_user', value: data.smtp_user },
{ key: 'email_from_name', value: data.email_from_name },
{ key: 'email_from', value: data.email_from },
]
@@ -188,22 +192,41 @@ export function EmailSettingsForm({ settings }: EmailSettingsFormProps) {
/>
</div>
<FormField
control={form.control}
name="email_from"
render={({ field }) => (
<FormItem>
<FormLabel>From Email Address</FormLabel>
<FormControl>
<Input placeholder="noreply@monaco-opc.com" {...field} />
</FormControl>
<FormDescription>
Email address that will appear as the sender
</FormDescription>
<FormMessage />
</FormItem>
)}
/>
<div className="grid gap-4 md:grid-cols-2">
<FormField
control={form.control}
name="email_from_name"
render={({ field }) => (
<FormItem>
<FormLabel>Sender Display Name</FormLabel>
<FormControl>
<Input placeholder="MOPC Portal" {...field} />
</FormControl>
<FormDescription>
Name shown to recipients (e.g., "MOPC Portal")
</FormDescription>
<FormMessage />
</FormItem>
)}
/>
<FormField
control={form.control}
name="email_from"
render={({ field }) => (
<FormItem>
<FormLabel>Sender Email Address</FormLabel>
<FormControl>
<Input placeholder="noreply@monaco-opc.com" {...field} />
</FormControl>
<FormDescription>
Email address for replies
</FormDescription>
<FormMessage />
</FormItem>
)}
/>
</div>
<div className="flex gap-2">
<Button type="submit" disabled={updateSettings.isPending}>