feat(ui): Improve StaticIpv4Card and StaticIpv6Card with IP address validation

This commit is contained in:
Adam Shiervani 2025-08-11 16:36:03 +02:00
parent 59cfc25196
commit 9e09048f61
2 changed files with 45 additions and 37 deletions

View File

@ -1,13 +1,15 @@
import { LuPlus, LuX } from "react-icons/lu";
import { useFieldArray, useFormContext } from "react-hook-form";
import { useEffect } from "react";
import validator from "validator";
import { GridCard } from "@/components/Card";
import { Button } from "@/components/Button";
import { InputFieldWithLabel } from "@/components/InputField";
import { NetworkSettings } from "@/hooks/stores";
export default function StaticIpv4Card() {
const formMethods = useFormContext();
const formMethods = useFormContext<NetworkSettings>();
const { register, formState, watch } = formMethods;
const { fields, append, remove } = useFieldArray({ name: "ipv4_static.dns" });
@ -17,6 +19,12 @@ export default function StaticIpv4Card() {
}, [append, fields.length]);
const dns = watch("ipv4_static.dns");
const validate = (value: string) => {
if (!validator.isIP(value)) return "Invalid IP address";
return true;
};
return (
<GridCard>
<div className="animate-fadeIn p-4 text-black opacity-0 animation-duration-500 dark:text-white">
@ -31,7 +39,8 @@ export default function StaticIpv4Card() {
type="text"
size="SM"
placeholder="192.168.1.100"
{...register("ipv4_static.address")}
{...register("ipv4_static.address", { validate })}
error={formState.errors.ipv4_static?.address?.message}
/>
<InputFieldWithLabel
@ -39,7 +48,8 @@ export default function StaticIpv4Card() {
type="text"
size="SM"
placeholder="255.255.255.0"
{...register("ipv4_static.netmask")}
{...register("ipv4_static.netmask", { validate })}
error={formState.errors.ipv4_static?.netmask?.message}
/>
</div>
@ -48,7 +58,8 @@ export default function StaticIpv4Card() {
type="text"
size="SM"
placeholder="192.168.1.1"
{...register("ipv4_static.gateway")}
{...register("ipv4_static.gateway", { validate })}
error={formState.errors.ipv4_static?.gateway?.message}
/>
{/* DNS server fields */}
@ -63,14 +74,7 @@ export default function StaticIpv4Card() {
type="text"
size="SM"
placeholder="1.1.1.1"
{...register(`ipv4_static.dns.${index}`, {
// validate: (value: string) => {
// if (value === "") return true;
// if (!validator.isIP(value)) return "Invalid IP address";
// return true;
// },
})}
// @ts-expect-error - dns is not a field in the form
{...register(`ipv4_static.dns.${index}`, { validate })}
error={formState.errors.ipv4_static?.dns?.[index]?.message}
/>
</div>

View File

@ -6,9 +6,10 @@ import { useEffect } from "react";
import { GridCard } from "@/components/Card";
import { Button } from "@/components/Button";
import { InputFieldWithLabel } from "@/components/InputField";
import { NetworkSettings } from "@/hooks/stores";
export default function StaticIpv6Card() {
const formMethods = useFormContext();
const formMethods = useFormContext<NetworkSettings>();
const { register, formState, watch } = formMethods;
const { fields, append, remove } = useFieldArray({ name: "ipv6_static.dns" });
@ -18,6 +19,29 @@ export default function StaticIpv6Card() {
}, [append, fields.length]);
const dns = watch("ipv6_static.dns");
const cidrValidation = (value: string) => {
if (value === "") return true;
// Check if it's a valid IPv6 address with CIDR notation
const parts = value.split("/");
if (parts.length !== 2) return "Please use CIDR notation (e.g., 2001:db8::1/64)";
const [address, prefix] = parts;
if (!validator.isIP(address, 6)) return "Invalid IPv6 address";
const prefixNum = parseInt(prefix);
if (isNaN(prefixNum) || prefixNum < 0 || prefixNum > 128) {
return "Prefix must be between 0 and 128";
}
return true;
};
const ipv6Validation = (value: string) => {
if (!validator.isIP(value, 6)) return "Invalid IPv6 address";
return true;
};
return (
<GridCard>
<div className="animate-fadeIn p-4 text-black opacity-0 animation-duration-500 dark:text-white">
@ -31,23 +55,7 @@ export default function StaticIpv6Card() {
type="text"
size="SM"
placeholder="2001:db8::1/64"
{...register("ipv6_static.address", {
validate: (value: string) => {
if (value === "") return true;
// Check if it's a valid IPv6 address with CIDR notation
const parts = value.split("/");
if (parts.length !== 2)
return "Please use CIDR notation (e.g., 2001:db8::1/64)";
const [address, prefix] = parts;
if (!validator.isIP(address, 6)) return "Invalid IPv6 address";
const prefixNum = parseInt(prefix);
if (isNaN(prefixNum) || prefixNum < 0 || prefixNum > 128) {
return "Prefix must be between 0 and 128";
}
return true;
},
})}
// @ts-expect-error - address is not a field in the form
{...register("ipv6_static.address", { validate: cidrValidation })}
error={formState.errors.ipv6_static?.address?.message}
/>
@ -56,7 +64,8 @@ export default function StaticIpv6Card() {
type="text"
size="SM"
placeholder="2001:db8::1"
{...register("ipv6_static.gateway")}
{...register("ipv6_static.gateway", { validate: ipv6Validation })}
error={formState.errors.ipv6_static?.gateway?.message}
/>
{/* DNS server fields */}
@ -72,13 +81,8 @@ export default function StaticIpv6Card() {
size="SM"
placeholder="2001:4860:4860::8888"
{...register(`ipv6_static.dns.${index}`, {
validate: (value: string) => {
if (value === "") return true;
if (!validator.isIP(value)) return "Invalid IP address";
return true;
},
validate: ipv6Validation,
})}
// @ts-expect-error - dns is not a field in the form
error={formState.errors.ipv6_static?.dns?.[index]?.message}
/>
</div>