import * as z from 'zod' import { useForm } from 'react-hook-form' import { zodResolver } from '@hookform/resolvers/zod' 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 { Switch } from '@/components/ui/switch' import { SettingsSection } from '../components/settings-section' import { useResetForm } from '../hooks/use-reset-form' import { useUpdateOption } from '../hooks/use-update-option' const createEmailSchema = (t: (key: string) => string) => z.object({ SMTPServer: z.string(), SMTPPort: z.string().refine((value) => { const trimmed = value.trim() if (!trimmed) return true return /^\d+$/.test(trimmed) }, t('Port must be a positive integer')), SMTPAccount: z.string(), SMTPFrom: z.string().refine((value) => { const trimmed = value.trim() if (!trimmed) return true return /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(trimmed) }, t('Enter a valid email or leave blank')), SMTPToken: z.string(), SMTPSSLEnabled: z.boolean(), SMTPForceAuthLogin: z.boolean(), }) type EmailFormValues = z.infer> type EmailSettingsSectionProps = { defaultValues: EmailFormValues } export function EmailSettingsSection({ defaultValues, }: EmailSettingsSectionProps) { const { t } = useTranslation() const updateOption = useUpdateOption() const emailSchema = createEmailSchema(t) const form = useForm({ resolver: zodResolver(emailSchema), defaultValues, }) useResetForm(form, defaultValues) const onSubmit = async (values: EmailFormValues) => { const sanitized = { SMTPServer: values.SMTPServer.trim(), SMTPPort: values.SMTPPort.trim(), SMTPAccount: values.SMTPAccount.trim(), SMTPFrom: values.SMTPFrom.trim(), SMTPToken: values.SMTPToken.trim(), SMTPSSLEnabled: values.SMTPSSLEnabled, SMTPForceAuthLogin: values.SMTPForceAuthLogin, } const initial = { SMTPServer: defaultValues.SMTPServer.trim(), SMTPPort: defaultValues.SMTPPort.trim(), SMTPAccount: defaultValues.SMTPAccount.trim(), SMTPFrom: defaultValues.SMTPFrom.trim(), SMTPToken: defaultValues.SMTPToken.trim(), SMTPSSLEnabled: defaultValues.SMTPSSLEnabled, SMTPForceAuthLogin: defaultValues.SMTPForceAuthLogin, } const updates: Array<{ key: string; value: string | boolean }> = [] if (sanitized.SMTPServer !== initial.SMTPServer) { updates.push({ key: 'SMTPServer', value: sanitized.SMTPServer }) } if (sanitized.SMTPPort !== initial.SMTPPort) { updates.push({ key: 'SMTPPort', value: sanitized.SMTPPort }) } if (sanitized.SMTPAccount !== initial.SMTPAccount) { updates.push({ key: 'SMTPAccount', value: sanitized.SMTPAccount }) } if (sanitized.SMTPFrom !== initial.SMTPFrom) { updates.push({ key: 'SMTPFrom', value: sanitized.SMTPFrom }) } if (sanitized.SMTPToken && sanitized.SMTPToken !== initial.SMTPToken) { updates.push({ key: 'SMTPToken', value: sanitized.SMTPToken }) } if (sanitized.SMTPSSLEnabled !== initial.SMTPSSLEnabled) { updates.push({ key: 'SMTPSSLEnabled', value: sanitized.SMTPSSLEnabled, }) } if (sanitized.SMTPForceAuthLogin !== initial.SMTPForceAuthLogin) { updates.push({ key: 'SMTPForceAuthLogin', value: sanitized.SMTPForceAuthLogin, }) } for (const update of updates) { await updateOption.mutateAsync(update) } } return (
( {t('SMTP Host')} field.onChange(event.target.value)} /> {t('Hostname or IP of your SMTP provider')} )} />
( {t('Port')} field.onChange(event.target.value)} /> {t('Common ports include 25, 465, and 587')} )} /> (
{t('Enable SSL/TLS')} {t('Use secure connection when sending emails')}
)} /> (
{t('Force AUTH LOGIN')} {t('Force SMTP authentication using AUTH LOGIN method')}
)} />
( {t('Username')} field.onChange(event.target.value)} /> {t('Account used when authenticating with the SMTP server')} )} /> ( {t('From Address')} field.onChange(event.target.value)} /> {t('Display name and email used in outgoing messages')} )} /> ( {t('Password / Access Token')} field.onChange(event.target.value)} /> {t('Leave blank to keep the existing credential')} )} />
) }