import React, { useState, useEffect, Fragment } from "react"; import { useMoralis } from "react-moralis"; import { Listbox } from "@headlessui/react"; import NftGridItem from "./NftGridItem"; import Account from "./Account/Account"; import { ToastContainer } from "react-toastify"; const sortOptions = [ { id: 0, name: "Recently Received", sortCode: "recently-received" }, { id: 1, name: "Name: A-Z", sortCode: "name-a-z" }, { id: 2, name: "Name: Z-A", sortCode: "name-z-a" }, { id: 3, name: "Collection: A-Z", sortCode: "collection-a-z" }, { id: 4, name: "Collection: Z-A", sortCode: "collection-z-a" }, { id: 5, name: "Oldest", sortCode: "oldest" }, ]; const NftGrid = () => { const { isAuthenticated, account } = useMoralis(); const [fetchLoading, setFetchLoading] = useState(false); const [assets, setAssets] = useState([]); const [cursorNext, setCursorNext] = useState(null); const [cursorPrev, setCursorPrev] = useState(null); const [selectedSortOption, setSelectedSortOption] = useState(sortOptions[0]); const fetchAssets = async () => { let assetsUrl = `/api/assets?owner=${account}`; if (cursorNext) assetsUrl += `&cursor=${cursorNext}`; setFetchLoading(true); const response = await fetch(assetsUrl); const data = await response.json(); setAssets([...assets, ...data.data.assets]); setCursorNext(data?.data?.next); setCursorPrev(data?.data?.previous); setFetchLoading(false); }; const handleLoadMoreAssets = () => { fetchAssets(); }; useEffect(() => { if (account && assets?.length == 0) { fetchAssets(); } }, [account]); // TODO: Implement sorting for grid items const handleSortAZ = () => { const sorted = [...assets.sort((a, b) => a.name.localeCompare(b.name))]; // setNumbers((num) => [...num.sort()]); console.log(sorted); setAssets(sorted); }; const toastMarkup = ( <div className="absolute bg-zinc-800"> <ToastContainer position="bottom-left" autoClose={5000} hideProgressBar={false} newestOnTop={false} closeOnClick={true} rtl={false} pauseOnFocusLoss={false} draggable={false} pauseOnHover={true} theme="dark" /> </div> ); const sortByMarkup = ( <div className="mb-4 inline-block"> <Listbox value={selectedSortOption} onChange={setSelectedSortOption}> <Listbox.Button className="inline-flex items-center rounded-lg border-2 border-transparent bg-zinc-700 bg-opacity-30 px-4 py-2.5 text-center text-sm font-medium text-white backdrop-blur-lg backdrop-filter hover:border-[#5cd4ac]"> Sort by <svg xmlns="http://www.w3.org/2000/svg" className="ml-2 h-4 w-4" fill="none" viewBox="0 0 24 24" stroke="currentColor" strokeWidth={2} > <path strokeLinecap="round" strokeLinejoin="round" d="M19 9l-7 7-7-7" /> </svg> </Listbox.Button> <Listbox.Options className="absolute z-20 mt-2 rounded-lg bg-zinc-800 bg-opacity-80 py-2 text-sm text-white shadow backdrop-blur-lg backdrop-filter"> {sortOptions.map((sortOption) => ( /* Use the `active` state to conditionally style the active option. */ /* Use the `selected` state to conditionally style the selected option. */ <Listbox.Option key={sortOption.id} value={sortOption} as={Fragment} className="block cursor-pointer px-4 py-2 hover:bg-zinc-600" > {({ active, selected }) => ( <li className={`${ active ? "bg-blue-500 text-white" : "bg-white text-black" }`} > <div className="flex flex-row items-center justify-start"> {selected ? ( <> <svg xmlns="http://www.w3.org/2000/svg" className="mr-2 h-6 w-6" fill="none" viewBox="0 0 24 24" stroke="#5cd4ac" strokeWidth={2} > <path strokeLinecap="round" strokeLinejoin="round" d="M5 13l4 4L19 7" /> </svg> {sortOption.name} </> ) : ( <div className="ml-8">{sortOption.name}</div> )} </div> </li> )} </Listbox.Option> ))} </Listbox.Options> </Listbox> </div> ); return ( <div className="container mx-auto py-4"> {toastMarkup} {!isAuthenticated || !account ? ( <div className="mt-24 flex flex-col items-center justify-start"> <h3 className="mt-12 mb-6 text-base font-semibold text-white lg:text-xl"> Connect your wallet to continue </h3> <Account /> </div> ) : ( <> {/* TODO: Implement sort and filter */} {/* {sortByMarkup} */} <div className="mb-4 flex flex-row"> <div className="grid grid-cols-1 gap-6 md:grid-cols-3 lg:grid-cols-4 xl:grid-cols-5"> {assets.length > 0 && assets.map((asset, index) => { return <NftGridItem asset={asset} key={index} />; })} </div> </div> {cursorNext ? ( <div className="flex flex-row items-center justify-center"> <button type="button" className="inline-flex items-center rounded-lg border-2 border-transparent bg-zinc-700 bg-opacity-30 px-5 py-2.5 text-center text-sm font-medium text-white backdrop-blur-lg backdrop-filter hover:border-[#5cd4ac]" onClick={handleLoadMoreAssets} disabled={fetchLoading} > {fetchLoading ? ( <svg width="20" height="20" viewBox="0 0 38 38" xmlns="http://www.w3.org/2000/svg" stroke="#fff" > <g fill="none" fillRule="evenodd"> <g transform="translate(1 1)" strokeWidth="2"> <circle strokeOpacity=".5" cx="18" cy="18" r="18" /> <path d="M36 18c0-9.94-8.06-18-18-18"> <animateTransform attributeName="transform" type="rotate" from="0 18 18" to="360 18 18" dur="1s" repeatCount="indefinite" /> </path> </g> </g> </svg> ) : ( <p>Load More</p> )} </button> </div> ) : null} </> )} </div> ); }; export default NftGrid;