1"use client";
2
3
14import { useState } from "react";
15import { useRouter } from "next/navigation";
16import { Database as DatabaseIcon, FileText, Loader2, PenTool } from "lucide-react";
17import { toast } from "@/stores/ui-store";
18import { useCreatePage } from "@/hooks/use-pages";
19import { useCreateDatabase } from "@/hooks/use-database";
20import { Dialog, DialogFooter } from "@/components/dialogs/dialog";
21
22type Kind = "page" | "database" | "whiteboard";
23
24export interface CreateDialogProps {
25 open: boolean;
26 workspaceId: string;
27
28 workspaceSlug: string;
29
30 pageId?: string | null;
31 onClose: () => void;
32}
33
34export function CreateDialog({ open, workspaceId, workspaceSlug, pageId, onClose }: CreateDialogProps) {
35 const router = useRouter();
36 const [kind, setKind] = useState<Kind>("page");
37 const [title, setTitle] = useState("");
38 const [icon, setIcon] = useState("");
39
40 const createPage = useCreatePage(workspaceId);
41 const createDatabase = useCreateDatabase();
42 const busy = createPage.isPending || createDatabase.isPending;
43
44 const reset = () => {
45 setTitle("");
46 setIcon("");
47 };
48
49 const submit = () => {
50 if (!title.trim() && kind === "page") return;
51 if (kind === "database") {
52 createDatabase.mutate(
53 {
54 title: title.trim() || "Untitled database",
55 icon: icon || undefined,
56 pageId: pageId ?? null
57 },
58 {
59 onSuccess: (db) => {
60 onClose();
61 reset();
62 if (db.pageId) router.push(`/w/${workspaceSlug}/page/${db.pageId}`);
63 else toast("success", "Database created", db.title);
64 },
65 onError: (e) => toast("error", "Create failed", (e as Error).message)
66 }
67 );
68 return;
69 }
70
71 createPage.mutate(
72 { parentId: null, title: title.trim(), type: kind === "whiteboard" ? "whiteboard" : undefined },
73 {
74 onSuccess: (page) => {
75 onClose();
76 reset();
77 router.push(`/w/${workspaceSlug}/page/${page.id}`);
78 },
79 onError: (e) => toast("error", "Create failed", (e as Error).message)
80 }
81 );
82 };
83
84 return (
85 <Dialog
86 open={open}
87 title="Create new"
88 description="Add a page, whiteboard, or database to this workspace."
89 onClose={() => {
90 onClose();
91 reset();
92 }}
93 footer={
94 <DialogFooter
95 onCancel={() => {
96 onClose();
97 reset();
98 }}
99 onAction={submit}
100 actionLabel={kind === "page" ? "Create page" : kind === "whiteboard" ? "Create whiteboard" : "Create database"}
101 busy={busy}
102 disabled={kind === "database" && !title.trim()}
103 />
104 }
105 >
106 <div className="space-y-3">
107 {}
108 <div className="grid grid-cols-3 gap-2">
109 <button
110 type="button"
111 className={
112 "flex items-center gap-2 rounded-md border p-2.5 text-sm " +
113 (kind === "page" ? "border-primary bg-primary/10 text-primary" : "border-border hover:bg-muted")
114 }
115 onClick={() => setKind("page")}
116 >
117 <FileText className="size-4" aria-hidden /> Page
118 </button>
119 <button
120 type="button"
121 className={
122 "flex items-center gap-2 rounded-md border p-2.5 text-sm " +
123 (kind === "whiteboard" ? "border-primary bg-primary/10 text-primary" : "border-border hover:bg-muted")
124 }
125 onClick={() => setKind("whiteboard")}
126 >
127 <PenTool className="size-4" aria-hidden /> Whiteboard
128 </button>
129 <button
130 type="button"
131 className={
132 "flex items-center gap-2 rounded-md border p-2.5 text-sm " +
133 (kind === "database" ? "border-primary bg-primary/10 text-primary" : "border-border hover:bg-muted")
134 }
135 onClick={() => setKind("database")}
136 >
137 <DatabaseIcon className="size-4" aria-hidden /> Database
138 </button>
139 </div>
140
141 {}
142 {kind === "database" && (
143 <div>
144 <label className="mb-1 block text-xs text-muted-foreground">Icon (emoji)</label>
145 <div className="flex items-center gap-2">
146 <span className="text-2xl" aria-hidden>
147 {icon || "📊"}
148 </span>
149 <input
150 className="flex-1 rounded-md border border-input bg-background px-2.5 py-1.5 text-sm outline-none focus-visible:ring-1 focus-visible:ring-ring"
151 value={icon}
152 maxLength={4}
153 placeholder="📊"
154 onChange={(e) => setIcon(e.target.value)}
155 />
156 </div>
157 </div>
158 )}
159
160 {}
161 <div>
162 <label className="mb-1 block text-xs text-muted-foreground">Name</label>
163 <input
164 autoFocus
165 className="w-full rounded-md border border-input bg-background px-2.5 py-1.5 text-sm outline-none focus-visible:ring-1 focus-visible:ring-ring"
166 placeholder={kind === "page" ? "Untitled" : kind === "whiteboard" ? "Untitled whiteboard" : "Untitled database"}
167 value={title}
168 onChange={(e) => setTitle(e.target.value)}
169 onKeyDown={(e) => e.key === "Enter" && submit()}
170 />
171 </div>
172
173 {kind === "database" && pageId && (
174 <p className="text-xs text-muted-foreground">
175 The database will be embedded at the top of the current page.
176 </p>
177 )}
178 {busy && (
179 <p className="inline-flex items-center gap-1 text-xs text-muted-foreground">
180 <Loader2 className="size-3 animate-spin" aria-hidden /> Creating…
181 </p>
182 )}
183 </div>
184 </Dialog>
185 );
186}
187