"use client"; import { Boardgame, searchBoardgames } from "@/lib/bgg"; import { Menu, Transition } from "@headlessui/react"; import { EllipsisVerticalIcon } from "@heroicons/react/20/solid"; import { PlusCircleIcon } from "@heroicons/react/24/outline"; import { Fragment, useEffect, useState } from "react"; const NewGameClientPage = () => { const [query, setQuery] = useState(""); const [searchOpen, setSearchOpen] = useState(false); const [items, setItems] = useState<Boardgame[] | null>(null); useEffect(() => { if (query === "") return setItems(null); const delayDebounceFn = setTimeout(async () => { if (query === "") return; const games = await searchBoardgames(query); if (!games.success) return; if (games.data) setItems(games.data.items); }, 500); return () => clearTimeout(delayDebounceFn); }, [query]); return ( <div className="p-2"> <div className="flex inline-flex gap-2 w-full"> <label htmlFor="email" className="sr-only"> Find boardgame </label> <input type="text" name="search boardgames" id="search-boardgames" className="block w-full rounded-md border-0 py-1.5 text-gray-900 shadow-sm ring-1 ring-inset ring-gray-300 placeholder:text-gray-400 focus:ring-2 focus:ring-inset focus:ring-indigo-600 sm:text-sm sm:leading-6" placeholder="Search / Enter new game" value={query} onChange={(e) => setQuery(e.target.value)} /> {query !== "" && ( <button type="button" className="inline-flex whitespace-nowrap items-center gap-x-1.5 rounded-md bg-indigo-600 px-3 py-2 text-sm font-semibold text-white shadow-sm hover:bg-indigo-500 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-indigo-600" > <PlusCircleIcon className="-ml-0.5 h-5 w-5" aria-hidden="true" /> Add new </button> )} </div> {items && <SearchOptionsTable options={items} />} </div> ); }; export default NewGameClientPage; function classNames(...classes: string[]) { return classes.filter(Boolean).join(" "); } function SearchOptionsTable({ options }: { options: Boardgame[] }) { return ( <ul role="list" className="divide-y divide-gray-100"> {options.map((option) => ( <li key={option.id} className="flex items-center justify-between gap-x-6 py-5" > <div className="min-w-0"> <div className="flex items-start gap-x-3"> <p className="text-sm font-semibold leading-6 text-gray-900"> {option.name} </p> </div> <div className="mt-1 flex items-center gap-x-2 text-xs leading-5 text-gray-500"> <p className="whitespace-nowrap"> Published: {option.yearpublished} </p> <svg viewBox="0 0 2 2" className="h-0.5 w-0.5 fill-current"> <circle cx={1} cy={1} r={1} /> </svg> </div> </div> <div className="flex flex-none items-center gap-x-4"> <a href={option.href} className="hidden rounded-md bg-white px-2.5 py-1.5 text-sm font-semibold text-gray-900 shadow-sm ring-1 ring-inset ring-gray-300 hover:bg-gray-50 sm:block" > View boardgame<span className="sr-only">, {option.name}</span> </a> <Menu as="div" className="relative flex-none"> <Menu.Button className="-m-2.5 block p-2.5 text-gray-500 hover:text-gray-900"> <span className="sr-only">Open options</span> <EllipsisVerticalIcon className="h-5 w-5" aria-hidden="true" /> </Menu.Button> <Transition as={Fragment} enter="transition ease-out duration-100" enterFrom="transform opacity-0 scale-95" enterTo="transform opacity-100 scale-100" leave="transition ease-in duration-75" leaveFrom="transform opacity-100 scale-100" leaveTo="transform opacity-0 scale-95" > <Menu.Items className="absolute right-0 z-10 mt-2 w-32 origin-top-right rounded-md bg-white py-2 shadow-lg ring-1 ring-gray-900/5 focus:outline-none"> <Menu.Item> {({ active }) => ( <a href="#" className={classNames( active ? "bg-gray-50" : "", "block px-3 py-1 text-sm leading-6 text-gray-900" )} > Edit<span className="sr-only">, {option.name}</span> </a> )} </Menu.Item> <Menu.Item> {({ active }) => ( <a href="#" className={classNames( active ? "bg-gray-50" : "", "block px-3 py-1 text-sm leading-6 text-gray-900" )} > Move<span className="sr-only">, {option.name}</span> </a> )} </Menu.Item> <Menu.Item> {({ active }) => ( <a href="#" className={classNames( active ? "bg-gray-50" : "", "block px-3 py-1 text-sm leading-6 text-gray-900" )} > Delete<span className="sr-only">, {option.name}</span> </a> )} </Menu.Item> </Menu.Items> </Transition> </Menu> </div> </li> ))} </ul> ); }