'use client'; import type { LogChannelMapping, LogEventTypeDashboard, LoggingConfigDashboard } from '@nexumi/shared'; import { Plus, Trash2 } from 'lucide-react'; import { useId } from 'react'; import { FieldAnchor } from '@/components/layout/field-anchor'; import { useTranslations } from '@/components/locale-provider'; import { Button } from '@/components/ui/button'; import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card'; import { Input } from '@/components/ui/input'; import { Label } from '@/components/ui/label'; import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select'; import { Switch } from '@/components/ui/switch'; import { Textarea } from '@/components/ui/textarea'; import type { SettingsSaveResult } from '@/components/settings/settings-form'; import { SettingsForm } from '@/components/settings/settings-form'; const LOG_EVENT_TYPES: LogEventTypeDashboard[] = [ 'MESSAGE_EDIT', 'MESSAGE_DELETE', 'MESSAGE_BULK_DELETE', 'MEMBER_JOIN', 'MEMBER_LEAVE', 'MEMBER_BAN', 'MEMBER_UNBAN', 'MEMBER_UPDATE', 'CHANNEL_CREATE', 'CHANNEL_DELETE', 'CHANNEL_UPDATE', 'VOICE_JOIN', 'VOICE_LEAVE', 'VOICE_MOVE', 'INVITE_CREATE', 'EMOJI_CREATE', 'EMOJI_UPDATE', 'EMOJI_DELETE', 'STICKER_CREATE', 'STICKER_UPDATE', 'STICKER_DELETE', 'THREAD_CREATE', 'THREAD_UPDATE', 'THREAD_DELETE', 'GUILD_UPDATE', 'MOD_ACTION' ]; interface LocalLogChannel extends LogChannelMapping { clientKey: string; } interface LocalLoggingValue { enabled: boolean; ignoreBots: boolean; ignoredChannelIdsText: string; ignoredRoleIdsText: string; retentionDays: number; logChannels: LocalLogChannel[]; } function toCsv(ids: string[]): string { return ids.join(', '); } function fromCsv(text: string): string[] { return text .split(',') .map((entry) => entry.trim()) .filter((entry) => entry.length > 0); } function toLocal(config: LoggingConfigDashboard): LocalLoggingValue { return { enabled: config.enabled, ignoreBots: config.ignoreBots, ignoredChannelIdsText: toCsv(config.ignoredChannelIds), ignoredRoleIdsText: toCsv(config.ignoredRoleIds), retentionDays: config.retentionDays, logChannels: config.logChannels.map((mapping, index) => ({ ...mapping, clientKey: `${mapping.eventType}-${index}` })) }; } function toRemote(value: LocalLoggingValue): LoggingConfigDashboard { return { enabled: value.enabled, ignoreBots: value.ignoreBots, ignoredChannelIds: fromCsv(value.ignoredChannelIdsText), ignoredRoleIds: fromCsv(value.ignoredRoleIdsText), retentionDays: value.retentionDays, logChannels: value.logChannels.map(({ clientKey: _clientKey, ...rest }) => rest) }; } async function saveLogging(guildId: string, value: LocalLoggingValue): Promise { try { const response = await fetch(`/api/guilds/${guildId}/logging`, { method: 'PATCH', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(toRemote(value)) }); if (!response.ok) { const body = (await response.json().catch(() => null)) as { error?: string } | null; return { ok: false, error: body?.error ?? `Request failed with status ${response.status}` }; } return { ok: true }; } catch { return { ok: false, error: 'Network error' }; } } interface LoggingFormProps { guildId: string; initialValue: LoggingConfigDashboard; } export function LoggingForm({ guildId, initialValue }: LoggingFormProps) { const t = useTranslations(); const ignoredChannelsId = useId(); const ignoredRolesId = useId(); return ( initialValue={toLocal(initialValue)} onSave={(value) => saveLogging(guildId, value)} > {({ value, setValue }) => (
{t('modulePages.logging.title')} {t('modulePages.logging.description')}
setValue((prev) => ({ ...prev, enabled: checked }))} />
setValue((prev) => ({ ...prev, ignoreBots: checked }))} />