"use client" import { useEffect, useMemo, useState } from "react" import type { IpsecClientDto } from "@mmapp/contracts/ipsec" import { FormField, FormToggle, SectionTitle } from "@/components/form-kit" import { Button } from "@/components/ui/button" import { Input } from "@/components/ui/input" import { Sheet, SheetContent, SheetHeader, SheetTitle, SheetDescription, SheetFooter, SheetClose, } from "@/components/ui/sheet" export type IpsecAuthKind = "certificate" | "pre-shared-key" export type IpsecUserFormState = { serverId: string name: string peerName: string authMethod: IpsecAuthKind psk: string remoteId: string useStaticIp: boolean staticIp: string passphrase: string } export const defaultIpsecUserForm = (): IpsecUserFormState => ({ serverId: "", name: "", peerName: "", authMethod: "certificate", psk: "", remoteId: "", useStaticIp: false, staticIp: "", passphrase: "", }) type ServerOption = { id: string; name: string; host: string } export type PeerOption = { serverId: string; name: string; managed: boolean } function IpsecUserSheet({ open, onOpenChange, servers, peers, busy, defaultServerId, editing, freeIpHint, onSubmit, }: { open: boolean onOpenChange: (v: boolean) => void servers: ServerOption[] /** Доступные peers (серверы) для привязки identity при создании. */ peers?: PeerOption[] busy?: boolean defaultServerId?: string /** Режим редактирования: сервер и метод аутентификации не меняются. */ editing?: IpsecClientDto | null freeIpHint?: string onSubmit: (form: IpsecUserFormState) => void | Promise }) { const [form, setForm] = useState(defaultIpsecUserForm) const set = (k: K, v: IpsecUserFormState[K]) => setForm((f) => ({ ...f, [k]: v })) useEffect(() => { if (!open) return if (editing) { const edit = editing queueMicrotask(() => setForm({ serverId: edit.serverId, name: edit.name, peerName: edit.peerName ?? "", authMethod: edit.authMethod, psk: "", remoteId: edit.remoteId ?? "", useStaticIp: Boolean(edit.staticIp), staticIp: edit.staticIp ?? "", passphrase: "", })) return } queueMicrotask(() => setForm({ ...defaultIpsecUserForm(), serverId: defaultServerId ?? "" })) }, [open, defaultServerId, editing]) const canSubmit = useMemo(() => { if (!editing && !form.serverId) return false if (!form.name.trim()) return false if (!editing && form.authMethod === "pre-shared-key" && form.psk.trim().length < 8) return false if (form.useStaticIp && form.staticIp.trim() && !/^\d{1,3}(?:\.\d{1,3}){3}$/.test(form.staticIp.trim())) return false return true }, [form, editing]) return ( {editing ? `Клиент «${editing.name}»` : "Новый клиент IKEv2"} {editing ? "Имя, статический IP и secret (для PSK)" : "Identity на роутере; для сертификата — выпуск .p12 для авторизации"}
Основные {!editing ? ( ) : null} {!editing && (peers ?? []).some((p) => p.serverId === form.serverId) ? ( ) : null} set("name", e.target.value)} /> {!editing ? (
) : null} {form.authMethod === "pre-shared-key" ? ( <> set("psk", e.target.value)} /> {!editing ? ( set("remoteId", e.target.value)} /> ) : null} ) : ( !editing ? ( set("passphrase", e.target.value)} /> ) : null )}
IP-адрес

Статический IP

{freeIpHint ? `Свободный из пула: ${freeIpHint}` : "Иначе — выдача из пула"}

set("useStaticIp", v)} />
{form.useStaticIp && ( set("staticIp", e.target.value)} /> )}
}> Отмена
) } export { IpsecUserSheet }