126 lines
4.2 KiB
TypeScript
126 lines
4.2 KiB
TypeScript
import { useState, type Dispatch, type ReactNode, type SetStateAction } from "react";
|
|
import { X } from "lucide-react";
|
|
import Modal from "@/src/components/twui/elements/Modal";
|
|
import Input from "@/src/components/twui/form/Input";
|
|
import AdminButton from "@/src/components/general/admin-button";
|
|
import Form from "@/src/components/twui/form/Form";
|
|
import Stack from "@/src/components/twui/layout/Stack";
|
|
import Span from "@/src/components/twui/layout/Span";
|
|
import H3 from "@/src/components/twui/layout/H3";
|
|
import Row from "@/src/components/twui/layout/Row";
|
|
import adminCrudHandler from "@/src/functions/frontend/admin-crud-handler";
|
|
import type { BUN_SQLITE_WGUI_CLIENTS } from "@/db/types/db";
|
|
|
|
type Props = {
|
|
open: boolean;
|
|
setOpen: Dispatch<SetStateAction<boolean>>;
|
|
onCreated?: () => void;
|
|
};
|
|
|
|
type FormFieldProps = {
|
|
label: string;
|
|
htmlFor: string;
|
|
children: ReactNode;
|
|
};
|
|
|
|
type FormData = {
|
|
client_name?: string;
|
|
tunnel_ip?: string;
|
|
allowed_ips?: string;
|
|
};
|
|
|
|
export default function ClientFormModal({ open, setOpen, onCreated }: Props) {
|
|
const [busy, setBusy] = useState(false);
|
|
const [error, setError] = useState<string>();
|
|
|
|
async function handleSubmit(data: FormData) {
|
|
setBusy(true);
|
|
setError(undefined);
|
|
|
|
const res = await adminCrudHandler<BUN_SQLITE_WGUI_CLIENTS>({
|
|
action: "insert",
|
|
table: "clients",
|
|
insert_data: [
|
|
{
|
|
name: data.client_name || "",
|
|
wg_ip_address: data.tunnel_ip || "",
|
|
allowed_ips: data.allowed_ips || "",
|
|
},
|
|
],
|
|
});
|
|
|
|
setBusy(false);
|
|
|
|
if (!res.success) {
|
|
setError(res.msg || "Could not add client");
|
|
return;
|
|
}
|
|
|
|
setOpen(false);
|
|
onCreated?.();
|
|
}
|
|
|
|
return (
|
|
<Modal open={open} setOpen={setOpen} className="p-6">
|
|
<Stack className="gap-4 mb-6">
|
|
<H3 className="text-lg font-bold text-foreground-light dark:text-foreground-dark">
|
|
Add client
|
|
</H3>
|
|
<Span className="" variant="faded">
|
|
The client is added to your WireGuard network
|
|
</Span>
|
|
</Stack>
|
|
|
|
<Form
|
|
submitHandler={(e, data) => {
|
|
handleSubmit(data as FormData);
|
|
}}
|
|
>
|
|
<Stack className="w-full items-stretch gap-6">
|
|
<Input
|
|
name="client_name"
|
|
id="client_name"
|
|
placeholder="e.g. MacBook Pro"
|
|
label="Client name"
|
|
autoFocus
|
|
showLabel
|
|
required
|
|
/>
|
|
<Row className="grid grid-cols-1 sm:grid-cols-2 gap-4">
|
|
<Input
|
|
name="tunnel_ip"
|
|
id="tunnel_ip"
|
|
placeholder="10.0.0.10"
|
|
label="Tunnel IP"
|
|
showLabel
|
|
/>
|
|
<Input
|
|
name="allowed_ips"
|
|
id="allowed_ips"
|
|
placeholder="10.0.0.10/32"
|
|
label="Allowed IPs"
|
|
showLabel
|
|
/>
|
|
</Row>
|
|
{error ? (
|
|
<Span className="text-[12.5px] text-error dark:text-error">
|
|
{error}
|
|
</Span>
|
|
) : null}
|
|
<Row className="justify-end gap-2 mt-2">
|
|
<AdminButton onClick={() => setOpen(false)} disabled={busy}>
|
|
Cancel
|
|
</AdminButton>
|
|
<AdminButton
|
|
variant="primary"
|
|
type="submit"
|
|
disabled={busy}
|
|
>
|
|
{busy ? "Adding…" : "Add client"}
|
|
</AdminButton>
|
|
</Row>
|
|
</Stack>
|
|
</Form>
|
|
</Modal>
|
|
);
|
|
} |