beta/components/create-project.tsx
Christopher Arraya 53c3cd3d6e initial commit
2023-11-04 14:57:25 -04:00

181 lines
5.4 KiB
TypeScript

"use client";
import * as z from "zod";
import { zodResolver } from "@hookform/resolvers/zod";
import { useForm } from "react-hook-form";
import { useState } from "react";
import { useRouter } from "next/navigation";
import {
Form,
FormControl,
FormDescription,
FormField,
FormItem,
FormLabel,
FormMessage,
} from "@/components/ui/form";
import {
Dialog,
DialogContent,
DialogDescription,
DialogHeader,
DialogTitle,
DialogTrigger,
} from "@/components/ui/dialog";
import { Button } from "@/components/ui/button";
import { Input } from "@/components/ui/input";
import { Badge } from "@/components/ui/badge";
import { X } from "lucide-react";
import { set } from "date-fns";
const formSchema = z.object({
name: z.string().min(2, {
message: "Name must be at least 2 characters.",
}),
description: z.string().min(2, {
message: "Description must be at least 2 characters.",
}),
stack: z.array(z.string()).min(1, {
message: "Project tech stack must have at least one item.",
}),
});
export function CreateProject({ workspaceID }: { workspaceID: string }) {
const form = useForm<z.infer<typeof formSchema>>({
resolver: zodResolver(formSchema),
defaultValues: {
name: "",
description: "",
stack: [],
},
});
const { setValue } = form;
const [stackInput, setStackInput] = useState("");
const [isLoading, setIsLoading] = useState(false);
const router = useRouter();
async function onSubmit(values: z.infer<typeof formSchema>) {
try {
setIsLoading(true);
const res = await fetch(`/w/${workspaceID}/p`, {
method: "POST",
body: JSON.stringify(values),
});
console.log("===>", res);
if (!res.ok) throw new Error("Something went wrong.");
router.refresh();
setIsLoading(false);
return res;
} catch (err) {
setIsLoading(false);
console.error(err);
}
}
const keyHandler = (e: React.KeyboardEvent<HTMLInputElement>) => {
if ((e.key === "Enter" || e.key === "Tab") && stackInput !== "") {
e.preventDefault();
setValue("stack", [...form.getValues("stack"), stackInput]);
setStackInput("");
}
};
return (
<Dialog>
<DialogTrigger asChild>
<Button variant="outline">Create Project</Button>
</DialogTrigger>
<DialogContent>
<DialogHeader>
<DialogTitle>Create a Project</DialogTitle>
<DialogDescription>
Give your project a name, description, and tech stack.
</DialogDescription>
</DialogHeader>
<Form {...form}>
<form onSubmit={form.handleSubmit(onSubmit)} className="space-y-8">
<FormField
control={form.control}
name="name"
render={({ field }) => (
<FormItem>
<FormLabel>Name</FormLabel>
<FormControl>
<Input placeholder="" {...field} />
</FormControl>
<FormDescription>This is your project name.</FormDescription>
<FormMessage />
</FormItem>
)}
/>
<FormField
control={form.control}
name="description"
render={({ field }) => (
<FormItem>
<FormLabel>Description</FormLabel>
<FormControl>
<Input placeholder="" {...field} />
</FormControl>
<FormDescription>
This is your project description.
</FormDescription>
<FormMessage />
</FormItem>
)}
/>
<FormField
control={form.control}
name="stack"
render={() => (
<FormItem>
<FormLabel>Tech Stack</FormLabel>
<FormControl>
<Input
value={stackInput}
onChange={(e) => setStackInput(e.target.value)}
onKeyDown={keyHandler}
/>
</FormControl>
<FormDescription>
This is your project tech stack.
</FormDescription>
<div>
{form.getValues("stack").map((stack) => (
<Badge
key={stack}
className="mr-2 font-normal rounded-md"
variant="outline"
>
<span className="mr-1">{stack}</span>
<X
className="inline font-light text-red-500"
size={16}
onClick={() =>
setValue(
"stack",
form.getValues("stack").filter((s) => s !== stack)
)
}
/>
</Badge>
))}
</div>
<FormMessage />
</FormItem>
)}
/>
<Button type="submit" disabled={isLoading}>
{isLoading ? "Generating Features..." : "Submit"}
</Button>
</form>
</Form>
</DialogContent>
</Dialog>
);
}