wip: domains stuff

This commit is contained in:
Derock 2024-01-25 22:12:02 -05:00
parent c2b84fbe9f
commit 74372c9426
No known key found for this signature in database
3 changed files with 123 additions and 27 deletions

View file

@ -1,9 +1,30 @@
"use client";
import { ArrowRight, PlusIcon } from "lucide-react";
import { useFieldArray } from "react-hook-form";
import { z } from "zod";
import { Form } from "~/components/ui/form";
import { FormSubmit, SimpleFormField, useForm } from "~/hooks/forms";
import { Button } from "~/components/ui/button";
import {
Form,
FormControl,
FormField,
FormItem,
FormLabel,
FormMessage,
} from "~/components/ui/form";
import {
Select,
SelectContent,
SelectItem,
SelectTrigger,
SelectValue,
} from "~/components/ui/select";
import {
FormSubmit,
FormUnsavedChangesIndicator,
SimpleFormField,
useForm,
} from "~/hooks/forms";
const formValidator = z.object({
domains: z.array(
@ -15,9 +36,9 @@ const formValidator = z.object({
{ message: "Invalid domain name" },
),
internalPort: z.number().int().min(1).max(65535),
https: z.boolean(),
forceSSL: z.boolean(),
internalPort: z.coerce.number().int().min(1).max(65535).default(8080),
https: z.boolean().default(true),
forceSSL: z.boolean().default(true),
}),
),
});
@ -30,14 +51,14 @@ export default function DomainsList(
},
) {
const form = useForm(formValidator, {
defaultValues: {},
});
const { fields, append, prepend, remove, swap, move, insert } = useFieldArray(
{
control: form.control,
name: "domains",
defaultValues: {
domains: [],
},
);
});
const domainsForm = useFieldArray({
control: form.control,
name: "domains",
});
return (
<Form {...form}>
@ -45,23 +66,79 @@ export default function DomainsList(
onSubmit={form.handleSubmit(async (data) => {
console.log(data);
})}
className="grid grid-cols-2 gap-4"
className="flex flex-col gap-4"
>
<h1 className="col-span-2">Domains</h1>
{fields.map((field, index) => (
<div className="flex gap-4" key={field.id}>
{domainsForm.fields.map((field, index) => (
<div className="flex flex-row gap-4" key={field.id}>
<FormField
control={form.control}
name={`domains.${index}.https`}
render={({ field }) => (
<FormItem>
<FormLabel>Protocol</FormLabel>
<Select
onValueChange={(value) => field.onChange(value === "https")}
defaultValue={field.value ? "https" : "http"}
>
<FormControl>
<SelectTrigger>
<SelectValue />
</SelectTrigger>
</FormControl>
<SelectContent>
<SelectItem value="http">http://</SelectItem>
<SelectItem value="https">https://</SelectItem>
</SelectContent>
</Select>
<FormMessage />
</FormItem>
)}
/>
{/* toggle */}
{/* <SimpleFormField
control={form.control}
name={`domains.${index}.forceSSL`}
friendlyName="Use HTTPS"
render={({ field }) => <Switch {...field} className="block" />}
/> */}
<SimpleFormField
control={form.control}
name={`domains.${index}.domain`}
friendlyName="Domain"
required
className="flex-1"
/>
<ArrowRight className="mt-9 flex-shrink-0" />
<SimpleFormField
control={form.control}
name={`domains.${index}.internalPort`}
friendlyName="Internal Port"
className="w-60"
/>
</div>
))}
<FormSubmit form={form} className="col-span-2" />
<div className="flex flex-row flex-wrap items-center gap-4">
<FormSubmit
form={form}
className="col-span-2"
hideUnsavedChangesIndicator
/>
<Button
variant="secondary"
icon={PlusIcon}
onClick={() => domainsForm.append()}
>
Add Domain
</Button>
<FormUnsavedChangesIndicator form={form} />
</div>
</form>
</Form>
);

View file

@ -1,7 +1,9 @@
import DomainsList from "./DomainsList";
export default function DomainsPage() {
return (
<div>
<Form
<DomainsList />
</div>
)
}
);
}

View file

@ -115,10 +115,12 @@ export function SimpleFormField<
export function FormSubmit({
form,
className,
hideUnsavedChangesIndicator,
}: {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
form: UseFormReturn<z.infer<any>>;
className?: string;
hideUnsavedChangesIndicator?: boolean;
}) {
return (
<div className={cn("flex flex-row items-center gap-2", className)}>
@ -126,13 +128,28 @@ export function FormSubmit({
Save
</Button>
{/* unsaved changes indicator */}
<p
className={`text-sm text-red-500 duration-200 animate-in fade-in ${
form.formState.isDirty ? "opacity-100" : "invisible opacity-0"
}`}
>
You have unsaved changes!
</p>
{!hideUnsavedChangesIndicator && (
<FormUnsavedChangesIndicator form={form} />
)}
</div>
);
}
export function FormUnsavedChangesIndicator({
form,
className,
}: {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
form: UseFormReturn<z.infer<any>>;
className?: string;
}) {
return (
<p
className={`text-sm text-red-500 duration-200 animate-in fade-in ${
form.formState.isDirty ? "opacity-100" : "invisible opacity-0"
} ${className}`}
>
You have unsaved changes!
</p>
);
}