"use client"; import { useEffect, useState } from "react"; import { Button } from "@app/components/ui/button"; import { Input } from "@app/components/ui/input"; import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@app/components/ui/select"; import { Command, CommandEmpty, CommandGroup, CommandInput, CommandItem, CommandList } from "@app/components/ui/command"; import { Popover, PopoverContent, PopoverTrigger } from "@app/components/ui/popover"; import { Check, ChevronsUpDown } from "lucide-react"; import { useForm } from "react-hook-form"; import { zodResolver } from "@hookform/resolvers/zod"; import { z } from "zod"; import { Form, FormControl, FormDescription, FormField, FormItem, FormLabel, FormMessage } from "@app/components/ui/form"; import { Credenza, CredenzaBody, CredenzaClose, CredenzaContent, CredenzaDescription, CredenzaFooter, CredenzaHeader, CredenzaTitle } from "@app/components/Credenza"; import { toast } from "@app/hooks/useToast"; import { useTranslations } from "next-intl"; import { createApiClient, formatAxiosError } from "@app/lib/api"; import { useEnvContext } from "@app/hooks/useEnvContext"; import { ListSitesResponse } from "@server/routers/site"; import { cn } from "@app/lib/cn"; type Site = ListSitesResponse["sites"][0]; type CreateInternalResourceDialogProps = { open: boolean; setOpen: (val: boolean) => void; orgId: string; sites: Site[]; onSuccess?: () => void; }; export default function CreateInternalResourceDialog({ open, setOpen, orgId, sites, onSuccess }: CreateInternalResourceDialogProps) { const t = useTranslations(); const api = createApiClient(useEnvContext()); const [isSubmitting, setIsSubmitting] = useState(false); const formSchema = z.object({ name: z .string() .min(1, t("createInternalResourceDialogNameRequired")) .max(255, t("createInternalResourceDialogNameMaxLength")), siteId: z.number().int().positive(t("createInternalResourceDialogPleaseSelectSite")), protocol: z.enum(["tcp", "udp"]), proxyPort: z .number() .int() .positive() .min(1, t("createInternalResourceDialogProxyPortMin")) .max(65535, t("createInternalResourceDialogProxyPortMax")), destinationIp: z.string(), destinationPort: z .number() .int() .positive() .min(1, t("createInternalResourceDialogDestinationPortMin")) .max(65535, t("createInternalResourceDialogDestinationPortMax")) }); type FormData = z.infer; const availableSites = sites.filter( (site) => site.type === "newt" && site.subnet ); const form = useForm({ resolver: zodResolver(formSchema), defaultValues: { name: "", siteId: availableSites[0]?.siteId || 0, protocol: "tcp", proxyPort: undefined, destinationIp: "", destinationPort: undefined } }); useEffect(() => { if (open && availableSites.length > 0) { form.reset({ name: "", siteId: availableSites[0].siteId, protocol: "tcp", proxyPort: undefined, destinationIp: "", destinationPort: undefined }); } }, [open]); const handleSubmit = async (data: FormData) => { setIsSubmitting(true); try { await api.put(`/org/${orgId}/site/${data.siteId}/resource`, { name: data.name, protocol: data.protocol, proxyPort: data.proxyPort, destinationIp: data.destinationIp, destinationPort: data.destinationPort, enabled: true }); toast({ title: t("createInternalResourceDialogSuccess"), description: t("createInternalResourceDialogInternalResourceCreatedSuccessfully"), variant: "default" }); onSuccess?.(); setOpen(false); } catch (error) { console.error("Error creating internal resource:", error); toast({ title: t("createInternalResourceDialogError"), description: formatAxiosError( error, t("createInternalResourceDialogFailedToCreateInternalResource") ), variant: "destructive" }); } finally { setIsSubmitting(false); } }; if (availableSites.length === 0) { return ( {t("createInternalResourceDialogNoSitesAvailable")} {t("createInternalResourceDialogNoSitesAvailableDescription")} ); } return ( {t("createInternalResourceDialogCreateClientResource")} {t("createInternalResourceDialogCreateClientResourceDescription")}
{/* Resource Properties Form */}

{t("createInternalResourceDialogResourceProperties")}

( {t("createInternalResourceDialogName")} )} />
( {t("createInternalResourceDialogSite")} {t("createInternalResourceDialogNoSitesFound")} {availableSites.map((site) => ( { field.onChange(site.siteId); }} > {site.name} ))} )} /> ( {t("createInternalResourceDialogProtocol")} )} />
( {t("createInternalResourceDialogSitePort")} field.onChange( e.target.value === "" ? undefined : parseInt(e.target.value) ) } /> {t("createInternalResourceDialogSitePortDescription")} )} />
{/* Target Configuration Form */}

{t("createInternalResourceDialogTargetConfiguration")}

( {t("createInternalResourceDialogDestinationIP")} {t("createInternalResourceDialogDestinationIPDescription")} )} /> ( {t("createInternalResourceDialogDestinationPort")} field.onChange( e.target.value === "" ? undefined : parseInt(e.target.value) ) } /> {t("createInternalResourceDialogDestinationPortDescription")} )} />
); }