blob: a643eaa70aeb9e9ddc7f309f44ada1d5c00e787a [file] [log] [blame]
gio5f2f1002025-03-20 18:38:48 +04001import { ChangeEvent, useCallback, useEffect, useState } from "react";
2import { Project, useProjectId, useStateStore } from "./lib/state";
3import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "./components/ui/select";
4import { useReactFlow } from "@xyflow/react";
5import { Input } from "./components/ui/input";
6import { Button } from "./components/ui/button";
7import { Dialog, DialogContent, DialogTrigger } from "./components/ui/dialog";
8import { useToast } from "@/hooks/use-toast";
giobc47f9f2025-05-12 08:31:07 +00009import { Separator } from "./components/ui/separator";
10import { Plus } from "lucide-react";
gio5f2f1002025-03-20 18:38:48 +040011
gio880de162025-05-11 07:26:00 +000012export function ProjectSelect() {
giod0026612025-05-08 13:00:36 +000013 const { toast } = useToast();
14 const store = useStateStore();
15 const [projects, setProjects] = useState<Project[]>([]);
16 const refreshProjects = useCallback(async () => {
17 try {
18 const resp = await fetch("/api/project");
19 setProjects(await resp.json());
20 } catch (e) {
21 console.log(e);
22 }
23 }, [setProjects]);
24 useEffect(() => {
25 refreshProjects();
26 }, [refreshProjects]);
27 const project = useProjectId();
28 const [createNewOpen, setCreateNewOpen] = useState(false);
29 const onSelect = useCallback(
30 (projectId: string) => {
31 if (projectId === "create-new") {
32 setCreateNewOpen(true);
33 } else {
34 store.setProject(projectId);
35 }
36 },
37 [store],
38 );
39 const instance = useReactFlow();
40 const restoreSaved = useCallback(
41 async (projectId: string) => {
42 const resp = await fetch(`/api/project/${projectId}/saved`, {
43 method: "GET",
44 });
45 const inst = await resp.json();
46 const { x = 0, y = 0, zoom = 1 } = inst.viewport;
47 instance.setNodes(inst.nodes || []);
48 instance.setEdges(inst.edges || []);
49 instance.setViewport({ x, y, zoom });
50 },
51 [instance],
52 );
53 useEffect(() => {
54 if (project == null) {
55 return;
56 }
57 restoreSaved(project);
58 }, [project, restoreSaved]);
59 const [name, setName] = useState<string | undefined>(undefined);
60 const updateName = useCallback(
61 (e: ChangeEvent<HTMLInputElement>) => {
62 setName(e.target.value);
63 },
64 [setName],
65 );
66 const createNew = useCallback(() => {
67 console.log(name);
68 if (!name) {
69 return;
70 }
71 fetch("/api/project", {
72 method: "POST",
73 headers: {
74 "Content-Type": "application/json",
75 },
76 body: JSON.stringify({
77 name: name,
78 }),
79 })
80 .then(async (resp) => {
81 if (!resp.ok) {
82 return;
83 }
84 const { id } = await resp.json();
85 await refreshProjects();
86 store.setProject(id as string);
87 setCreateNewOpen(false);
88 toast({
89 title: `Created project: ${name}`,
90 });
91 })
92 .catch((e) => {
93 console.log(e);
94 toast({
95 variant: "destructive",
96 title: `Failed to create project: ${name}`,
97 });
98 });
99 }, [name, setCreateNewOpen, toast, store, refreshProjects]);
100 return (
gio880de162025-05-11 07:26:00 +0000101 <Select onValueChange={onSelect} value={project}>
giobc47f9f2025-05-12 08:31:07 +0000102 <SelectTrigger className="w-[200px] !border-none !shadow-none !focus:ring-0 !focus:ring-offset-0">
gio880de162025-05-11 07:26:00 +0000103 <SelectValue placeholder="Choose Project" defaultValue={project} />
104 </SelectTrigger>
105 <SelectContent>
giobc47f9f2025-05-12 08:31:07 +0000106 {projects.map((p) => (
107 <SelectItem key={p.id} value={p.id}>
108 {p.name}
109 </SelectItem>
110 ))}
111 <Separator />
gio880de162025-05-11 07:26:00 +0000112 <SelectItem value={"create-new"}>
113 <Dialog open={createNewOpen} onOpenChange={setCreateNewOpen}>
giobc47f9f2025-05-12 08:31:07 +0000114 <DialogTrigger className="flex flex-row items-center">
115 <Plus />
116 Create New
117 </DialogTrigger>
gio880de162025-05-11 07:26:00 +0000118 <DialogContent>
119 <Input type="text" placeholder="Name" onChange={updateName} />
120 <Button onClick={createNew}>Create New</Button>
121 </DialogContent>
122 </Dialog>
123 </SelectItem>
gio880de162025-05-11 07:26:00 +0000124 </SelectContent>
125 </Select>
giod0026612025-05-08 13:00:36 +0000126 );
127}