import { CheckOutlined, CloudOutlined, CodeOutlined, MailOutlined, SendOutlined } from '@ant-design/icons'; import { Alert, Button, Checkbox, Collapse, Descriptions, Drawer, Form, Input, Radio, Select, Space, Steps, Typography } from 'antd'; import { useEffect, useMemo, useState } from 'react'; import { StatusPill } from '../common/StatusPill'; import { useI18n } from '../../frontend/i18n/react'; import type { AddDomainPayload, DnsCredential, RuntimeConfig, SmtpRelay } from '../../frontend/types'; interface AddDomainDrawerProps { open: boolean; loading?: boolean; config: RuntimeConfig | null; dnsCredentials: DnsCredential[]; smtpRelays: SmtpRelay[]; onClose: () => void; onSubmit: (values: AddDomainPayload) => Promise; } interface DomainWizardValues extends AddDomainPayload { purpose: 'sending' | 'sending-receiving'; dnsMode: 'automatic' | 'manual'; } export function AddDomainDrawer({ open, loading, config, dnsCredentials, smtpRelays, onClose, onSubmit }: AddDomainDrawerProps) { const { locale } = useI18n(); const copy = locale.startsWith('en') ? enCopy : zhCopy; const [form] = Form.useForm(); const [current, setCurrent] = useState(0); const values = Form.useWatch([], form); const dnsMode = Form.useWatch('dnsMode', form); const steps = useMemo(() => [copy.domainAndPurpose, copy.dnsAndDelivery, copy.reviewAndCreate], [copy]); useEffect(() => { if (!open) return; form.resetFields(); form.setFieldsValue({ purpose: 'sending', dnsMode: dnsCredentials.length ? 'automatic' : 'manual', dnsCredentialId: dnsCredentials[0]?.id, smtpRelayId: undefined, senderHost: config?.mailHostname || '', sendingIp: config?.sendingIp || '', selector: defaultSelector(), dmarcPolicy: config?.dmarcPolicy || 'none', spfExtra: config?.defaultSpfMechanisms || '', immediateCheck: true }); setCurrent(0); }, [config, dnsCredentials, form, open]); async function next() { try { await form.validateFields(stepFields(current)); } catch { return; } if (current === 1 && dnsMode === 'automatic' && !form.getFieldValue('dnsCredentialId')) { form.setFields([{ name: 'dnsCredentialId', errors: [copy.selectDnsCredential] }]); return; } setCurrent((value) => Math.min(value + 1, steps.length - 1)); } async function submit() { let result: DomainWizardValues; try { result = await form.validateFields(); } catch { return; } const payload: AddDomainPayload = { domain: result.domain.trim().toLowerCase(), senderHost: result.senderHost?.trim(), sendingIp: result.sendingIp?.trim(), dnsCredentialId: result.dnsMode === 'automatic' ? result.dnsCredentialId : undefined, smtpRelayId: result.smtpRelayId || null, selector: result.selector?.trim(), dmarcPolicy: result.dmarcPolicy, spfExtra: result.spfExtra?.trim(), immediateCheck: result.immediateCheck }; try { await onSubmit(payload); } catch { return; } form.resetFields(); setCurrent(0); } return ( {current < steps.length - 1 ? ( ) : ( )} } > ({ title }))} responsive aria-label={copy.progress} />