"use client"; import { useTranslations } from "next-intl"; import { useEnvContext } from "@app/hooks/useEnvContext"; import { useDomainContext } from "@app/hooks/useDomainContext"; import { SettingsContainer, SettingsSection, SettingsSectionBody, SettingsSectionFooter, SettingsSectionForm, SettingsSectionHeader, SettingsSectionTitle } from "./Settings"; import { Button } from "./ui/button"; import { Form, FormControl, FormField, FormItem, FormLabel, FormMessage, FormDescription } from "@app/components/ui/form"; import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "./ui/select"; import { Input } from "./ui/input"; import { useForm } from "react-hook-form"; import z from "zod"; import { toASCII } from "punycode"; import { zodResolver } from "@hookform/resolvers/zod"; import { build } from "@server/build"; import { Switch } from "./ui/switch"; import { useEffect, useState } from "react"; import { createApiClient } from "@app/lib/api"; import { useToast } from "@app/hooks/useToast"; import { formatAxiosError } from "@app/lib/api"; import { GetDomainResponse } from "@server/routers/domain"; type DomainInfoCardProps = { orgId?: string; domainId?: string; domain: GetDomainResponse; }; // Helper functions for Unicode domain handling function toPunycode(domain: string): string { try { const parts = toASCII(domain); return parts; } catch (error) { return domain.toLowerCase(); } } function isValidDomainFormat(domain: string): boolean { const unicodeRegex = /^(?!:\/\/)([^\s.]+\.)*[^\s.]+$/; if (!unicodeRegex.test(domain)) { return false; } const parts = domain.split("."); for (const part of parts) { if (part.length === 0 || part.startsWith("-") || part.endsWith("-")) { return false; } if (part.length > 63) { return false; } } if (domain.length > 253) { return false; } return true; } const formSchema = z.object({ baseDomain: z .string() .min(1, "Domain is required") .refine((val) => isValidDomainFormat(val), "Invalid domain format") .transform((val) => toPunycode(val)), type: z.enum(["ns", "cname", "wildcard"]), certResolver: z.string().nullable().optional(), preferWildcardCert: z.boolean().optional() }); type FormValues = z.infer; const certResolverOptions = [ { id: "default", title: "Default" }, { id: "custom", title: "Custom Resolver" } ]; export default function DomainCertForm({ orgId, domainId, domain }: DomainInfoCardProps) { const t = useTranslations(); const { env } = useEnvContext(); const api = createApiClient(useEnvContext()); const { toast } = useToast(); const [saveLoading, setSaveLoading] = useState(false); const form = useForm({ resolver: zodResolver(formSchema), defaultValues: { baseDomain: "", type: build == "oss" || !env.flags.usePangolinDns ? "wildcard" : "ns", certResolver: domain.certResolver, preferWildcardCert: false } }); useEffect(() => { if (domain.domainId) { const certResolverValue = domain.certResolver && domain.certResolver.trim() !== "" ? domain.certResolver : null; form.reset({ baseDomain: domain.baseDomain || "", type: (domain.type as "ns" | "cname" | "wildcard") || "wildcard", certResolver: certResolverValue, preferWildcardCert: domain.preferWildcardCert || false }); } }, [domain]); const onSubmit = async (values: FormValues) => { if (!orgId || !domainId) { toast({ title: t("error"), description: t("orgOrDomainIdMissing", { fallback: "Organization or Domain ID is missing" }), variant: "destructive" }); return; } setSaveLoading(true); try { if (!values.certResolver) { values.certResolver = null; } await api.patch(`/org/${orgId}/domain/${domainId}`, { certResolver: values.certResolver, preferWildcardCert: values.preferWildcardCert }); toast({ title: t("success"), description: t("domainSettingsUpdated", { fallback: "Domain settings updated successfully" }), variant: "default" }); } catch (error) { toast({ title: t("error"), description: formatAxiosError(error), variant: "destructive" }); } finally { setSaveLoading(false); } }; return ( {t("domainSetting")}
<> ( {t("certResolver")} )} /> {form.watch("certResolver") !== null && form.watch("certResolver") !== "default" && ( ( field.onChange( e.target .value ) } /> )} /> )} {form.watch("certResolver") !== null && form.watch("certResolver") !== "default" && ( (
{t( "preferWildcardCert" )}
{t( "preferWildcardCertDescription" )}
)} /> )}
); }