feat: switch to a new form hook

This commit is contained in:
Aarnav Tale
2026-03-19 12:35:17 -04:00
parent 246bb90ef0
commit 718cbf3c40
8 changed files with 340 additions and 132 deletions
@@ -1,10 +1,15 @@
import { useMemo, useState } from "react";
import { type } from "arktype";
import Button from "~/components/button";
import Dialog, { DialogPanel } from "~/components/dialog";
import Input from "~/components/input";
import Text from "~/components/text";
import Title from "~/components/title";
import { useForm } from "~/hooks/use-form";
const domainSchema = type({
domain: "string > 0",
});
interface AddDomainProps {
domains: string[];
@@ -12,27 +17,29 @@ interface AddDomainProps {
}
export default function AddDomain({ domains, isDisabled }: AddDomainProps) {
const [domain, setDomain] = useState("");
const form = useForm({
schema: domainSchema,
validate: (values) => {
const domain = (values.domain as string).trim();
if (domain.length === 0) return undefined;
const isInvalid = useMemo(() => {
if (!domain || domain.trim().length === 0) {
// Empty domain is invalid, but no error shown
return false;
}
if (domains.includes(domain)) {
return { domain: "This domain already exists in the list." };
}
if (domains.includes(domain.trim())) {
return true;
}
try {
const url = new URL(`http://${domain}`);
if (url.hostname !== domain) {
return { domain: "This is not a valid domain." };
}
} catch {
return { domain: "This is not a valid domain." };
}
try {
// Check if domain is a valid FQDN
const url = new URL(`http://${domain.trim()}`);
return url.hostname !== domain.trim();
} catch (e) {
// If URL constructor fails, it's not a valid domain
return true;
}
}, [domain, domains]);
return undefined;
},
});
const domain = (form.values.domain as string).trim();
return (
<Dialog>
@@ -45,23 +52,16 @@ export default function AddDomain({ domains, isDisabled }: AddDomainProps) {
</Text>
<input name="action_id" type="hidden" value="add_domain" />
<Input
{...form.field("domain")}
description={
domain.trim().length > 0
? `Matches users with <user>@${domain.trim()}`
domain.length > 0
? `Matches users with <user>@${domain}`
: "Enter a domain to match users with their email addresses."
}
invalid={domain.trim().length === 0 || isInvalid}
required
label="Domain"
name="domain"
onChange={setDomain}
placeholder="example.com"
/>
{isInvalid && (
<p className="mt-2 text-sm text-red-500">
The domain you entered is invalid or already exists in the list.
</p>
)}
</DialogPanel>
</Dialog>
);
@@ -1,10 +1,15 @@
import { useMemo, useState } from "react";
import { type } from "arktype";
import Button from "~/components/button";
import Dialog, { DialogPanel } from "~/components/dialog";
import Input from "~/components/input";
import Text from "~/components/text";
import Title from "~/components/title";
import { useForm } from "~/hooks/use-form";
const groupSchema = type({
group: "string > 0",
});
interface AddGroupProps {
groups: string[];
@@ -12,18 +17,19 @@ interface AddGroupProps {
}
export default function AddGroup({ groups, isDisabled }: AddGroupProps) {
const [group, setGroup] = useState("");
const form = useForm({
schema: groupSchema,
validate: (values) => {
const group = (values.group as string).trim();
if (group.length === 0) return undefined;
const isInvalid = useMemo(() => {
if (!group || group.trim().length === 0) {
// Empty group is invalid, but no error shown
return false;
}
if (groups.includes(group)) {
return { group: "This group already exists in the list." };
}
if (groups.includes(group.trim())) {
return true;
}
}, [group, groups]);
return undefined;
},
});
return (
<Dialog>
@@ -35,19 +41,12 @@ export default function AddGroup({ groups, isDisabled }: AddGroupProps) {
</Text>
<input name="action_id" type="hidden" value="add_group" />
<Input
{...form.field("group")}
description="The group to allow for OIDC authentication."
invalid={group.trim().length === 0 || isInvalid}
required
label="Group"
name="group"
onChange={setGroup}
placeholder="admin"
/>
{isInvalid && (
<p className="mt-2 text-sm text-red-500">
The group you entered already exists in the list of allowed groups.
</p>
)}
</DialogPanel>
</Dialog>
);
@@ -1,10 +1,15 @@
import { useMemo, useState } from "react";
import { type } from "arktype";
import Button from "~/components/button";
import Dialog, { DialogPanel } from "~/components/dialog";
import Input from "~/components/input";
import Text from "~/components/text";
import Title from "~/components/title";
import { useForm } from "~/hooks/use-form";
const userSchema = type({
user: "string > 0",
});
interface AddUserProps {
users: string[];
@@ -12,18 +17,19 @@ interface AddUserProps {
}
export default function AddUser({ users, isDisabled }: AddUserProps) {
const [user, setUser] = useState("");
const form = useForm({
schema: userSchema,
validate: (values) => {
const user = (values.user as string).trim();
if (user.length === 0) return undefined;
const isInvalid = useMemo(() => {
if (!user || user.trim().length === 0) {
// Empty user is invalid, but no error shown
return false;
}
if (users.includes(user)) {
return { user: "This user already exists in the list." };
}
if (users.includes(user.trim())) {
return true;
}
}, [user, users]);
return undefined;
},
});
return (
<Dialog>
@@ -35,19 +41,12 @@ export default function AddUser({ users, isDisabled }: AddUserProps) {
</Text>
<input name="action_id" type="hidden" value="add_user" />
<Input
{...form.field("user")}
description="The user to allow for OIDC authentication."
invalid={user.trim().length === 0 || isInvalid}
required
label="User"
name="user"
onChange={setUser}
placeholder="john_doe"
/>
{isInvalid && (
<p className="mt-2 text-sm text-red-500">
The user you entered already exists in the list of allowed users.
</p>
)}
</DialogPanel>
</Dialog>
);