import * as z from 'zod'
import type { Resolver } from 'react-hook-form'
import { zodResolver } from '@hookform/resolvers/zod'
import { RotateCcw } from 'lucide-react'
import { useTranslation } from 'react-i18next'
import { Button } from '@/components/ui/button'
import {
Form,
FormControl,
FormDescription,
FormField,
FormItem,
FormLabel,
FormMessage,
} from '@/components/ui/form'
import { Input } from '@/components/ui/input'
import {
Select,
SelectContent,
SelectItem,
SelectTrigger,
SelectValue,
} from '@/components/ui/select'
import { Textarea } from '@/components/ui/textarea'
import { FormDirtyIndicator } from '../components/form-dirty-indicator'
import { FormNavigationGuard } from '../components/form-navigation-guard'
import { SettingsSection } from '../components/settings-section'
import { useSettingsForm } from '../hooks/use-settings-form'
import { useUpdateOption } from '../hooks/use-update-option'
const _systemInfoSchema = z.object({
theme: z.object({
frontend: z.enum(['default', 'classic']),
}),
Notice: z.string().optional(),
SystemName: z.string().min(1),
ServerAddress: z.string().optional(),
Logo: z.string().url().optional().or(z.literal('')),
Footer: z.string().optional(),
About: z.string().optional(),
HomePageContent: z.string().optional(),
legal: z.object({
user_agreement: z.string().optional(),
privacy_policy: z.string().optional(),
}),
})
type SystemInfoFormValues = z.infer
type SystemInfoSectionProps = {
defaultValues: SystemInfoFormValues
}
function normalizeValue(value: unknown): string {
if (value === undefined || value === null) return ''
return typeof value === 'string' ? value : String(value)
}
export function SystemInfoSection({ defaultValues }: SystemInfoSectionProps) {
const { t } = useTranslation()
const updateOption = useUpdateOption()
const normalizedDefaults: SystemInfoFormValues = {
theme: {
frontend:
defaultValues.theme?.frontend === 'classic' ? 'classic' : 'default',
},
Notice: normalizeValue(defaultValues.Notice),
SystemName: normalizeValue(defaultValues.SystemName),
ServerAddress: normalizeValue(defaultValues.ServerAddress),
Logo: normalizeValue(defaultValues.Logo),
Footer: normalizeValue(defaultValues.Footer),
About: normalizeValue(defaultValues.About),
HomePageContent: normalizeValue(defaultValues.HomePageContent),
legal: {
user_agreement: normalizeValue(defaultValues.legal?.user_agreement),
privacy_policy: normalizeValue(defaultValues.legal?.privacy_policy),
},
}
const systemInfoSchemaWithI18n = z.object({
theme: z.object({
frontend: z.enum(['default', 'classic']),
}),
Notice: z.string().optional(),
SystemName: z.string().min(1, {
error: () => t('System name is required'),
}),
ServerAddress: z.string().optional(),
Logo: z.string().url().optional().or(z.literal('')),
Footer: z.string().optional(),
About: z.string().optional(),
HomePageContent: z.string().optional(),
legal: z.object({
user_agreement: z.string().optional(),
privacy_policy: z.string().optional(),
}),
})
const { form, handleSubmit, handleReset, isDirty, isSubmitting } =
useSettingsForm({
resolver: zodResolver(systemInfoSchemaWithI18n) as Resolver<
SystemInfoFormValues,
unknown,
SystemInfoFormValues
>,
defaultValues: normalizedDefaults,
onSubmit: async (_data, changedFields) => {
for (const [key, value] of Object.entries(changedFields)) {
let v = normalizeValue(value)
if (key === 'ServerAddress') {
v = v.replace(/\/+$/, '')
}
await updateOption.mutateAsync({
key,
value: v,
})
}
},
})
return (
<>
) or a URL (e.g., https://example.com) to embed as iframe'
)}
rows={4}
{...field}
/>
{t(
'Supports HTML markup or iframe embedding. Enter HTML code directly, or provide a complete URL to automatically embed it as an iframe.'
)}
)}
/>
(
{t('Home Page Content')}
{t(
'Content displayed on the home page (supports Markdown)'
)}
)}
/>
(
{t('User Agreement')}
{t(
'Leave empty to disable the agreement requirement. Supports Markdown, HTML, or a full URL to redirect users.'
)}
)}
/>
(
{t('Privacy Policy')}
{t(
'Leave empty to disable the privacy policy requirement. Supports Markdown, HTML, or a full URL to redirect users.'
)}
)}
/>