diff --git a/src/components/board/add-card.tsx b/src/components/board/add-card.tsx new file mode 100644 index 0000000..6bbb688 --- /dev/null +++ b/src/components/board/add-card.tsx @@ -0,0 +1,132 @@ +"use client"; + +import { useState, useTransition } from "react"; +import { useRouter } from "next/navigation"; +import { Plus } from "lucide-react"; + +import { createCard } from "@/app/actions/cards"; +import type { Role } from "@/lib/pb/types"; + +export function AddCard({ + role, + projectId, + columnId, + clientSlug, + projectSlug, +}: { + role: Role; + projectId: string; + columnId: string; + clientSlug: string; + projectSlug: string; +}) { + const router = useRouter(); + const [open, setOpen] = useState(false); + const [title, setTitle] = useState(""); + const [pending, startTransition] = useTransition(); + const [error, setError] = useState(null); + + // Takes the minimal shape rather than React.FormEvent, because it is called + // both from onSubmit and from the Enter handler in onKeyDown, and those + // carry different event types. + async function submit(event: { preventDefault: () => void }) { + event.preventDefault(); + const value = title.trim(); + if (!value) return; + + setError(null); + + if (role === "owner") { + setTitle(""); + setOpen(false); + startTransition(() => + createCard({ + projectId, + columnId, + title: value, + clientSlug, + projectSlug, + }).then(() => undefined) + ); + return; + } + + // A client manager's card is a request: the route decides the column, + // the priority and the accepted flag, whatever is sent here. + const response = await fetch("/api/client/cards", { + method: "POST", + headers: { "content-type": "application/json" }, + body: JSON.stringify({ project: projectId, title: value }), + }); + + if (!response.ok) { + setError("Could not add that"); + return; + } + + setTitle(""); + setOpen(false); + router.refresh(); + } + + if (!open) { + return ( + + ); + } + + return ( +
+