fix: Starboard

This commit is contained in:
smueller
2026-07-24 10:46:12 +02:00
parent f2406fb6d7
commit ccdf9aafe8
13 changed files with 549 additions and 87 deletions

View File

@@ -12,7 +12,18 @@ import { Switch } from '@/components/ui/switch';
import type { SettingsSaveResult } from '@/components/settings/settings-form';
import { SettingsForm } from '@/components/settings/settings-form';
async function saveStarboard(guildId: string, value: StarboardConfigDashboard): Promise<SettingsSaveResult> {
async function saveStarboard(
guildId: string,
value: StarboardConfigDashboard,
t: (key: string) => string
): Promise<SettingsSaveResult> {
if (value.enabled && !value.channelId) {
return { ok: false, error: t('modulePages.starboard.errors.channelRequired') };
}
if (value.threshold < 1 || value.threshold > 100) {
return { ok: false, error: t('modulePages.starboard.errors.thresholdRange') };
}
try {
const response = await fetch(`/api/guilds/${guildId}/starboard`, {
method: 'PATCH',
@@ -42,7 +53,7 @@ export function StarboardForm({ guildId, initialValue }: StarboardFormProps) {
return (
<SettingsForm<StarboardConfigDashboard>
initialValue={initialValue}
onSave={(value) => saveStarboard(guildId, value)}
onSave={(value) => saveStarboard(guildId, value, t)}
>
{({ value, setValue }) => (
<Card>
@@ -52,50 +63,85 @@ export function StarboardForm({ guildId, initialValue }: StarboardFormProps) {
</CardHeader>
<CardContent className="space-y-4">
<FieldAnchor id="field-starboard-enabled">
<div className="flex items-center justify-between rounded-md border border-border p-4">
<Label>{t('modulePages.starboard.enabledLabel')}</Label>
<Switch checked={value.enabled} onCheckedChange={(enabled) => setValue((prev) => ({ ...prev, enabled }))} />
</div>
<div className="flex items-center justify-between rounded-md border border-border p-4">
<div className="space-y-0.5 pr-4">
<Label>{t('modulePages.starboard.enabledLabel')}</Label>
<p className="text-xs text-muted-foreground">{t('modulePages.starboard.enabledHint')}</p>
</div>
<Switch
checked={value.enabled}
onCheckedChange={(enabled) => setValue((prev) => ({ ...prev, enabled }))}
/>
</div>
</FieldAnchor>
<div className="grid gap-4 sm:grid-cols-3">
<FieldAnchor id="field-starboard-channel">
<div className="space-y-2">
<Label>{t('modulePages.starboard.channelId')}</Label>
<DiscordChannelSelect
guildId={guildId}
value={value.channelId}
onChange={(channelId) => setValue((prev) => ({ ...prev, channelId }))}
/>
</div>
<div className="space-y-2">
<Label>{t('modulePages.starboard.channelId')}</Label>
<DiscordChannelSelect
guildId={guildId}
value={value.channelId}
onChange={(channelId) => setValue((prev) => ({ ...prev, channelId }))}
/>
</div>
</FieldAnchor>
<FieldAnchor id="field-starboard-emoji">
<div className="space-y-2">
<Label htmlFor={emojiId}>{t('modulePages.starboard.emoji')}</Label>
<Input id={emojiId} value={value.emoji} onChange={(event) => setValue((prev) => ({ ...prev, emoji: event.target.value }))} />
</div>
<div className="space-y-2">
<Label htmlFor={emojiId}>{t('modulePages.starboard.emoji')}</Label>
<Input
id={emojiId}
value={value.emoji}
maxLength={80}
onChange={(event) =>
setValue((prev) => ({ ...prev, emoji: event.target.value }))
}
placeholder="⭐ or <:name:id>"
/>
<p className="text-xs text-muted-foreground">{t('modulePages.starboard.emojiHint')}</p>
</div>
</FieldAnchor>
<FieldAnchor id="field-starboard-threshold">
<div className="space-y-2">
<Label htmlFor={thresholdId}>{t('modulePages.starboard.threshold')}</Label>
<Input id={thresholdId} type="number" min={1} value={value.threshold} onChange={(event) => setValue((prev) => ({ ...prev, threshold: Number(event.target.value) || 1 }))} />
</div>
<div className="space-y-2">
<Label htmlFor={thresholdId}>{t('modulePages.starboard.threshold')}</Label>
<Input
id={thresholdId}
type="number"
min={1}
max={100}
value={value.threshold}
onChange={(event) =>
setValue((prev) => ({
...prev,
threshold: Number(event.target.value) || 1
}))
}
/>
</div>
</FieldAnchor>
</div>
<FieldAnchor id="field-starboard-self">
<div className="flex items-center justify-between rounded-md border border-border p-4">
<Label>{t('modulePages.starboard.allowSelfStar')}</Label>
<Switch checked={value.allowSelfStar} onCheckedChange={(allowSelfStar) => setValue((prev) => ({ ...prev, allowSelfStar }))} />
</div>
<div className="flex items-center justify-between rounded-md border border-border p-4">
<Label>{t('modulePages.starboard.allowSelfStar')}</Label>
<Switch
checked={value.allowSelfStar}
onCheckedChange={(allowSelfStar) =>
setValue((prev) => ({ ...prev, allowSelfStar }))
}
/>
</div>
</FieldAnchor>
<FieldAnchor id="field-starboard-ignored">
<div className="space-y-2">
<Label>{t('modulePages.starboard.ignoredChannelIds')}</Label>
<DiscordChannelMultiSelect
guildId={guildId}
value={value.ignoredChannelIds}
onChange={(ignoredChannelIds) => setValue((prev) => ({ ...prev, ignoredChannelIds }))}
/>
</div>
<div className="space-y-2">
<Label>{t('modulePages.starboard.ignoredChannelIds')}</Label>
<DiscordChannelMultiSelect
guildId={guildId}
value={value.ignoredChannelIds}
onChange={(ignoredChannelIds) =>
setValue((prev) => ({ ...prev, ignoredChannelIds }))
}
/>
<p className="text-xs text-muted-foreground">{t('modulePages.starboard.nsfwHint')}</p>
</div>
</FieldAnchor>
</CardContent>
</Card>