Files
wireguard-ui/src/pages/admin/clients/(partials)/client-form-modal.tsx
T

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>
);
}