"use client"; import { Dispatch, SetStateAction, useEffect, useMemo, useState, useTransition, } from "react"; import { zodResolver } from "@hookform/resolvers/zod"; import { User } from "@prisma/client"; import { useTranslations } from "next-intl"; import { useForm } from "react-hook-form"; import { toast } from "sonner"; import useSWR from "swr"; import { CreateDNSRecord, RecordType } from "@/lib/cloudflare"; import { UserRecordFormData } from "@/lib/dto/cloudflare-dns-record"; import { TTL_ENUMS } from "@/lib/enums"; import { fetcher } from "@/lib/utils"; import { createRecordSchema } from "@/lib/validations/record"; import { Button } from "@/components/ui/button"; import { Input } from "@/components/ui/input"; import { Label } from "@/components/ui/label"; import { Icons } from "@/components/shared/icons"; import { FormSectionColumns } from "../dashboard/form-section-columns"; import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue, } from "../ui/select"; import { Skeleton } from "../ui/skeleton"; import { Switch } from "../ui/switch"; import { Textarea } from "../ui/textarea"; export type FormData = CreateDNSRecord; export type FormType = "add" | "edit"; export interface RecordFormProps { user: Pick; isShowForm: boolean; setShowForm: Dispatch>; type: FormType; initData?: UserRecordFormData | null; action: string; onRefresh: () => void; } export function RecordForm({ user, isShowForm, setShowForm, type, initData, action, onRefresh, }: RecordFormProps) { const [isPending, startTransition] = useTransition(); const [isDeleting, startDeleteTransition] = useTransition(); const [currentRecordType, setCurrentRecordType] = useState( initData?.type || "A", ); const [currentZoneName, setCurrentZoneName] = useState(initData?.zone_name); const [limitLen, setLimitLen] = useState(3); const [email, setEmail] = useState(initData?.user.email || user.email); const [allowedRecordTypes, setAllowedRecordTypes] = useState([]); const isAdmin = action.indexOf("admin") > -1; const t = useTranslations("List"); const { handleSubmit, register, formState: { errors }, getValues, setValue, } = useForm({ resolver: zodResolver(createRecordSchema), defaultValues: { zone_name: initData?.zone_name, type: initData?.type || "A", ttl: initData?.ttl || 1, proxied: initData?.proxied || false, comment: initData?.comment || "", name: initData?.name ? initData.name.split(".")[0] : "", content: initData?.content || "", }, }); // Fetch the record domains const { data: recordDomains, isLoading } = useSWR< { domain_name: string; cf_record_types: string; min_record_length: number; }[] >("/api/domain?feature=record", fetcher, { revalidateOnFocus: false, dedupingInterval: 10000, }); const { data: configs } = useSWR>( "/api/configs?key=enable_subdomain_apply", fetcher, ); const validDefaultDomain = useMemo(() => { if (!recordDomains?.length) return undefined; if ( initData?.zone_name && recordDomains.some((d) => d.domain_name === initData.zone_name) ) { return initData.zone_name; } return recordDomains[0].domain_name; }, [recordDomains, initData?.zone_name]); useEffect(() => { if (validDefaultDomain) { setValue("zone_name", validDefaultDomain); setCurrentZoneName(validDefaultDomain); } }, [validDefaultDomain]); useEffect(() => { if (recordDomains && recordDomains.length > 0) { setAllowedRecordTypes( recordDomains .find((d) => d.domain_name === validDefaultDomain)! .cf_record_types.split(","), ); setLimitLen( recordDomains.find((d) => d.domain_name === currentZoneName) ?.min_record_length || 3, ); } }, [currentZoneName, recordDomains, validDefaultDomain]); const onSubmit = handleSubmit((data) => { if (isAdmin && type === "edit" && initData?.active === 2) { handleApplyRecord(data); } else if (type === "add") { handleCreateRecord(data); } else if (type === "edit") { handleUpdateRecord(data); } }); const handleCreateRecord = async (data: CreateDNSRecord) => { if (configs?.enable_subdomain_apply && data.comment!.length < 20) { toast.warning("Apply reason must be at least 20 characters!"); } else { startTransition(async () => { const response = await fetch(`${action}/add`, { method: "POST", body: JSON.stringify({ records: [data], email, }), }); if (!response.ok || response.status !== 200) { toast.error("Created Failed!", { description: await response.text(), }); } else { toast.success(`Created successfully!`); setShowForm(false); onRefresh(); } }); } }; const handleUpdateRecord = async (data: CreateDNSRecord) => { startTransition(async () => { if (type === "edit") { const response = await fetch(`${action}/update`, { method: "POST", body: JSON.stringify({ recordId: initData?.record_id, record: data, userId: initData?.userId, }), }); if (!response.ok || response.status !== 200) { toast.error("Update Failed", { description: await response.text(), }); } else { toast.success(`Update successfully!`); setShowForm(false); onRefresh(); } } }); }; const handleRejectRecord = async (data: CreateDNSRecord) => { startTransition(async () => { if (type === "edit") { const response = await fetch(`${action}/reject`, { method: "POST", body: JSON.stringify({ id: initData?.id, userId: initData?.userId, record: data, recordId: initData?.record_id, }), }); if (!response.ok || response.status !== 200) { toast.error("Update Failed", { description: await response.text(), }); } else { toast.success(`Update successfully!`); setShowForm(false); onRefresh(); } } }); }; const handleDeleteRecord = async () => { if (type === "edit") { startDeleteTransition(async () => { const response = await fetch(`${action}/delete`, { method: "POST", body: JSON.stringify({ record_id: initData?.record_id, zone_id: initData?.zone_id, active: initData?.active, userId: initData?.userId, }), }); if (!response.ok || response.status !== 200) { toast.error("Delete Failed", { description: await response.text(), }); } else { await response.json(); toast.success(`Success`); setShowForm(false); onRefresh(); } }); } }; const handleApplyRecord = async (data: CreateDNSRecord) => { startTransition(async () => { const response = await fetch(`${action}/apply`, { method: "POST", body: JSON.stringify({ record: data, recordId: initData?.record_id, userId: initData?.userId, id: initData?.id, }), }); if (!response.ok || response.status !== 200) { toast.error("Failed", { description: await response.text(), }); } else { await response.json(); toast.success(`Success`); setShowForm(false); onRefresh(); } }); }; return (
{type === "add" ? t("Create record") : t("Edit record")}
{configs?.enable_subdomain_apply && (
  • {t("The administrator has enabled application mode")}.
  • {t( "After submission, you need to wait for administrator approval before the record takes effect", )} .
)}
{isAdmin && (
setEmail(e.target.value)} disabled={type === "edit"} />
{errors?.content ? (

{errors.content.message}

) : (

Required. Enter user email

)}
)} {configs?.enable_subdomain_apply && (