dummyidp/src/components/UsersSettingsForm.tsx
Ulysse Carion acbef8f1ef
Move UI pages for app and login into pages router (#12)
The app router is causing too much grief to be worthwhile here. The
pages for individual apps are fine to have in the pages router -- we're
fine with straight-up SPA stuff -- so just stop using app router rather
than figure out how to get Next.js to understand the data-fetching
lifecycle.
2024-10-29 15:02:10 -07:00

162 lines
4.5 KiB
TypeScript

"use client";
import { z } from "zod";
import { useFieldArray, useForm } from "react-hook-form";
import { zodResolver } from "@hookform/resolvers/zod";
import { App } from "@/lib/app";
import {
Form,
FormControl,
FormDescription,
FormField,
FormItem,
FormLabel,
FormMessage,
} from "@/components/ui/form";
import { Button } from "@/components/ui/button";
import { Input } from "@/components/ui/input";
import { toast } from "sonner";
import {
Table,
TableBody,
TableCell,
TableHead,
TableHeader,
TableRow,
} from "@/components/ui/table";
import { TrashIcon } from "@radix-ui/react-icons";
import { useUpsertApp } from "@/lib/hooks";
const formSchema = z.object({
users: z.array(
z.object({
email: z
.string()
.min(1, { message: "Email is required" })
.email({ message: "Email must be a valid email" }),
firstName: z.string().min(1, { message: "First name is required" }),
lastName: z.string().min(1, { message: "Last name is required" }),
}),
),
});
export function UsersSettingsForm({ app }: { app: App }) {
const form = useForm<z.infer<typeof formSchema>>({
resolver: zodResolver(formSchema),
defaultValues: {
users: app.users ?? [],
},
});
const { fields, remove, append } = useFieldArray({
name: "users",
control: form.control,
});
const upsertApp = useUpsertApp();
async function onSubmit(values: z.infer<typeof formSchema>) {
await upsertApp.mutateAsync({
...app,
users: values.users,
});
toast.success("App user settings updated");
}
return (
<Form {...form}>
<form onSubmit={form.handleSubmit(onSubmit)} className="space-y-4">
<Table>
<TableHeader>
<TableRow>
<TableHead>Email</TableHead>
<TableHead>First Name</TableHead>
<TableHead>Last Name</TableHead>
<TableHead className="w-[36px]"></TableHead>
</TableRow>
</TableHeader>
<TableBody>
{fields.map((field, index) => (
<TableRow key={field.id}>
<TableCell>
<FormField
control={form.control}
name={`users.${index}.email`}
render={({ field }) => (
<FormItem>
<FormControl>
<Input
placeholder="john.doe@example.com"
{...field}
/>
</FormControl>
<FormMessage />
</FormItem>
)}
/>
</TableCell>
<TableCell>
<FormField
control={form.control}
name={`users.${index}.firstName`}
render={({ field }) => (
<FormItem>
<FormControl>
<Input placeholder="John" {...field} />
</FormControl>
<FormMessage />
</FormItem>
)}
/>
</TableCell>
<TableCell>
<FormField
control={form.control}
name={`users.${index}.lastName`}
render={({ field }) => (
<FormItem>
<FormControl>
<Input placeholder="Doe" {...field} />
</FormControl>
<FormMessage />
</FormItem>
)}
/>
</TableCell>
<TableCell>
<Button
variant="outline"
size="icon"
onClick={() => remove(index)}
>
<TrashIcon className="h-4 w-4" />
</Button>
</TableCell>
</TableRow>
))}
</TableBody>
</Table>
<Button
type="button"
variant="outline"
size="sm"
className="mt-2"
onClick={() => append({ email: "", firstName: "", lastName: "" })}
>
Add User
</Button>
<div>
<Button type="submit" disabled={form.formState.isSubmitting}>
{form.formState.isSubmitting ? "Saving" : "Save"}
</Button>
</div>
</form>
</Form>
);
}