Scrapboard.org client
1"use client";
2
3import * as React from "react";
4import { CheckIcon, ChevronsUpDownIcon, PlusIcon } from "lucide-react";
5
6import { cn } from "@/lib/utils";
7import { Button } from "@/components/ui/button";
8import {
9 Command,
10 CommandEmpty,
11 CommandGroup,
12 CommandInput,
13 CommandItem,
14 CommandList,
15} from "@/components/ui/command";
16import {
17 Popover,
18 PopoverContent,
19 PopoverTrigger,
20} from "@/components/ui/popover";
21import { Board } from "@/lib/stores/boards";
22import clsx from "clsx";
23import { useAuth } from "@/lib/hooks/useAuth";
24
25export function BoardsPicker({
26 boards,
27 onCreateBoard,
28 onSelected: setValue,
29 selected: value,
30}: {
31 selected: string;
32 onSelected: (value: string) => unknown;
33 boards: Record<
34 string,
35 Record<
36 string,
37 {
38 name: string;
39 description: string;
40 }
41 >
42 >;
43 onCreateBoard: (name: string) => void; // New prop
44}) {
45 const [open, setOpen] = React.useState(false);
46 const [search, setSearch] = React.useState("");
47 const { agent } = useAuth();
48
49 if (!agent) return <div>Not logged in :(</div>;
50
51 const entries = Array.from(Object.entries(boards[agent?.assertDid])).filter(
52 ([_, board]) => board.name.toLowerCase().includes(search.toLowerCase())
53 );
54
55 const selectedBoard = boards[agent?.assertDid]?.[value];
56
57 return (
58 <Popover open={open} onOpenChange={setOpen}>
59 <PopoverTrigger asChild>
60 <Button
61 variant="outline"
62 role="combobox"
63 aria-expanded={open}
64 className={clsx(
65 "w-full justify-between",
66 selectedBoard ? "dark:text-white text-black" : ""
67 )}
68 >
69 {selectedBoard ? selectedBoard.name : "Select board..."}
70 <ChevronsUpDownIcon className="ml-2 h-4 w-4 shrink-0 opacity-50" />
71 </Button>
72 </PopoverTrigger>
73 <PopoverContent className="w-full p-0">
74 <Command shouldFilter={false}>
75 <CommandInput
76 placeholder="Search or create a board..."
77 onValueChange={(val) => setSearch(val)}
78 />
79 <CommandList>
80 <CommandGroup>
81 {entries.length > 0 ? (
82 entries.map(([key, it]) => (
83 <CommandItem
84 key={key}
85 value={it.name}
86 onSelect={() => {
87 setValue(key === value ? "" : key);
88 setOpen(false);
89 }}
90 >
91 <CheckIcon
92 className={cn(
93 "mr-2 h-4 w-4",
94 value === key ? "opacity-100" : "opacity-0"
95 )}
96 />
97 {it.name}
98 </CommandItem>
99 ))
100 ) : (
101 <CommandItem
102 onSelect={() => {
103 onCreateBoard(search.trim());
104 setSearch("");
105 setOpen(false);
106 }}
107 >
108 <PlusIcon className="h-4 w-4" />
109 <span>
110 Create board: <b>{search.trim()}</b>
111 </span>
112 </CommandItem>
113 )}
114 </CommandGroup>
115 </CommandList>
116 </Command>
117 </PopoverContent>
118 </Popover>
119 );
120}