"use client"; import { useState, useEffect } from "react"; import Link from "next/link"; import { Project } from "@/types/models"; import { Button, buttonVariants } from "@/components/ui/button"; import { Input } from "@/components/ui/input"; import { Badge } from "@/components/ui/badge"; import { Progress } from "@/components/ui/progress"; import { X } from "lucide-react"; import { Dialog, DialogContent, DialogDescription, DialogHeader, DialogTitle, DialogTrigger, } from "@/components/ui/dialog"; import { Form, FormDescription, FormControl, FormField, FormItem, FormLabel, FormMessage, } from "@/components/ui/form"; import { useForm } from "react-hook-form"; import { zodResolver } from "@hookform/resolvers/zod"; import * as z from "zod"; import { OpenAIChatApi } from "llm-api"; import { completion } from "zod-gpt"; const projectSchema = z.object({ title: z.string().min(3, "Title must be at least 3 characters"), description: z.string().min(10, "Description must be at least 10 characters"), github: z.string().url("Invalid URL").optional(), stack: z.string().array(), }); export default function Projects() { const [projects, setProjects] = useState([]); const [stackInput, setStackInput] = useState(""); const [loading, setLoading] = useState(true); const [open, setOpen] = useState(false); const [features, setFeatures] = useState([]); const [step, setStep] = useState(0); const [progress, setProgress] = useState(0); const form = useForm>({ resolver: zodResolver(projectSchema), defaultValues: { title: "", description: "", github: "", stack: [], }, }); const { setValue } = form; const fetchProjects = async () => { try { setLoading(true); const res = await fetch("/api/projects"); if (!res.ok) throw new Error("HTTP status " + res.status); const data = await res.json(); setProjects(data); setLoading(false); } catch (err) { console.error("Failed to fetch projects:", err); } }; useEffect(() => { fetchProjects(); }, []); async function handleSubmit(values: z.infer) { try { // 1. Create a new project const res = await fetch("/api/projects", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify(values), }); if (!res.ok) throw new Error("HTTP status " + res.status); const newProject = await res.json(); setProjects([...projects, newProject]); // 2. Initialize OpenAI client setStep(1); const openai = new OpenAIChatApi( { apiKey: "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", }, { model: "gpt-3.5-turbo-16k" } ); // 3. Generate features const prompt = `Based on the following project information, generate features for this tech project: Project Description: ${newProject.description} Tech Stack: ${newProject.stack.join(", ")}`; const featuresRes = await completion(openai, prompt, { schema: z.object({ features: z.array(z.object({ feature: z.string() })), }), }); const features = featuresRes.data.features.map((f) => f.feature); setFeatures(features); setStep(2); } catch (err) { console.error("Failed to create project:", err); } } async function handleGenerateTasks() { try { // Move to the task generation step and reset progress setStep(3); setProgress(0); // Get the newly created project const newProject = projects[projects.length - 1]; // Initialize OpenAI client const openai = new OpenAIChatApi( { apiKey: "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", }, { model: "gpt-3.5-turbo-16k" } ); // Generate tasks for each feature const taskList = []; for (let i = 0; i < features.length; i++) { const feature = features[i]; const taskPrompt = ` Given the following project description, feature description, and tech stack, generate a list of tasks needed to implement the feature: Project: ${newProject.title} Feature: ${feature} Tech Stack: ${newProject.stack.join(", ")}`; // Get tasks for the current feature const tasksRes = await completion(openai, taskPrompt, { schema: z.object({ tasks: z.array(z.object({ task: z.string() })) }), }); // Add the tasks to the task list taskList.push(...tasksRes.data.tasks); // Update the progress setProgress(((i + 1) / features.length) * 100); } // Post the generated tasks to the project const taskRes = await fetch(`/api/projects/${newProject.id}/tasks`, { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify(taskList), }); if (!taskRes.ok) throw new Error("HTTP status " + taskRes.status); // Log the created tasks const createdTasks = await taskRes.json(); console.log("Tasks created:", createdTasks); // Close the dialog setOpen(false); } catch (err) { console.error("Failed to generate tasks:", err); } } const keyHandler = (e: React.KeyboardEvent) => { if (e.key === "Enter" || e.key === "Tab") { e.preventDefault(); setValue("stack", [...form.getValues("stack"), stackInput]); setStackInput(""); } }; return (

Projects

Open {step === 0 && ( Add Project
( Project Title )} /> ( Project Description )} /> ( Github Repository URL )} /> ( Tech Stack setStackInput(e.target.value)} onKeyDown={keyHandler} /> {form.getValues("stack").map((stack) => ( {stack}{" "} setValue( "stack", form .getValues("stack") .filter((s) => s !== stack) ) } /> ))} )} />
)} {step === 1 && ( Generating Features

Generating features for your project...

)} {step === 2 && ( Features Generated
{features.map((feature, index) => ( {feature}{" "} setFeatures(features.filter((_, i) => i !== index)) } /> ))}
)} {step === 3 && ( Generating Tasks )}
{loading ? (

Loading...

) : (
{projects.map((project) => (

{project.title}

{project.description}

))}
)}
); }