Skip to content

Commit

Permalink
Clean up and refactor digital asset template (#121)
Browse files Browse the repository at this point in the history
* clean up and refactor digital asset template

* address comments
  • Loading branch information
0xmaayan authored Jun 24, 2024
1 parent 7358c5d commit 1c9b96f
Show file tree
Hide file tree
Showing 27 changed files with 342 additions and 320 deletions.
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,5 @@ node_modules

package-lock.json

templates/*/move/build
templates/*/move/build
templates/*/build
6 changes: 3 additions & 3 deletions templates/digital-asset-template/frontend/App.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import { Outlet, RouterProvider, createBrowserRouter } from "react-router-dom";

import { Mint } from "./pages/Mint";
import { CreateCollection } from "./pages/CreateCollection";
import { MyCollections } from "./pages/MyCollections";
import { Mint } from "@/pages/Mint";
import { CreateCollection } from "@/pages/CreateCollection";
import { MyCollections } from "@/pages/MyCollections";

function Layout() {
return (
Expand Down
20 changes: 6 additions & 14 deletions templates/digital-asset-template/frontend/components/Header.tsx
Original file line number Diff line number Diff line change
@@ -1,20 +1,16 @@
import { useMintData } from "@/pages/Mint/hooks/useMintData";
import { useGetCollectionData } from "@/hooks/useGetCollectionData";
import { useMemo } from "react";
import { Link } from "react-router-dom";
import { WalletSelector } from "./WalletSelector";
import { IS_DEV } from "@/constants";
import { buttonVariants } from "./ui/button";
import { buttonVariants } from "@/components/ui/button";
import { config } from "@/config";

export function Header() {
const { data } = useMintData();
const { data } = useGetCollectionData();

const title = useMemo(() => {
return (
data?.collection.collection_name ??
config.defaultCollection?.name ??
"NFT Collection Launchpad"
);
return data?.collection.collection_name ?? config.defaultCollection?.name ?? "NFT Collection Launchpad";
}, [data?.collection]);

return (
Expand All @@ -26,14 +22,10 @@ export function Header() {
<div className="flex gap-2 items-center flex-wrap">
{IS_DEV && (
<>
<Link
className={buttonVariants({ variant: "link" })}
to={"/my-collections"}>
<Link className={buttonVariants({ variant: "link" })} to={"/my-collections"}>
My Collections
</Link>
<Link
className={buttonVariants({ variant: "link" })}
to={"/create-collection"}>
<Link className={buttonVariants({ variant: "link" })} to={"/create-collection"}>
Create Collection
</Link>
</>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
import { Link, useLocation } from "react-router-dom";
import { WalletSelector } from "./WalletSelector";
import { buttonVariants } from "./ui/button";
import { FC } from "react";

import { WalletSelector } from "@/components/WalletSelector";
import { buttonVariants } from "@/components/ui/button";

interface LaunchpadHeaderProps {
title: string;
}
Expand All @@ -19,15 +20,11 @@ export const LaunchpadHeader: FC<LaunchpadHeaderProps> = ({ title }) => {
Mint Page
</Link>
{location.pathname === "/create-collection" ? (
<Link
className={buttonVariants({ variant: "link" })}
to={"/my-collections"}>
<Link className={buttonVariants({ variant: "link" })} to={"/my-collections"}>
My Collections
</Link>
) : (
<Link
className={buttonVariants({ variant: "link" })}
to={"/create-collection"}>
<Link className={buttonVariants({ variant: "link" })} to={"/create-collection"}>
Create Collection
</Link>
)}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
import { cn } from "@/lib/utils";
import { Spinner } from "./ui/spinner";
import { FC } from "react";

import { cn } from "@/lib/utils";
import { Spinner } from "@/components/ui/spinner";

export const UploadSpinner: FC<{ on: boolean }> = ({ on }) => {
return (
<div
className={cn(
"top-0 left-0 fixed w-full h-full bg-gray-500 bg-opacity-30 flex justify-center items-center flex-col transition-all",
on ? "opacity-100 z-10" : "opacity-0 z-0 pointer-events-none"
on ? "opacity-100 z-10" : "opacity-0 z-0 pointer-events-none",
)}
>
<p className="display">Uploading Files...</p>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { PropsWithChildren } from "react";
import { useToast } from "./ui/use-toast";
import { AptosWalletAdapterProvider } from "@aptos-labs/wallet-adapter-react";

import { useToast } from "@/components/ui/use-toast";
import { NETWORK } from "@/constants";

export function WalletProvider({ children }: PropsWithChildren) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,26 +12,17 @@ import {
import { useLocation } from "react-router-dom";
import { ChevronDown, Copy, LogOut, User } from "lucide-react";
import { useCallback, useState } from "react";
import { Button } from "./ui/button";
import {
Collapsible,
CollapsibleContent,
CollapsibleTrigger,
} from "./ui/collapsible";
import {
Dialog,
DialogContent,
DialogHeader,
DialogTitle,
DialogTrigger,
} from "./ui/dialog";

import { Button } from "@/components/ui/button";
import { Collapsible, CollapsibleContent, CollapsibleTrigger } from "@/components/ui/collapsible";
import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogTrigger } from "@/components/ui/dialog";
import {
DropdownMenu,
DropdownMenuContent,
DropdownMenuItem,
DropdownMenuTrigger,
} from "./ui/dropdown-menu";
import { useToast } from "./ui/use-toast";
} from "@/components/ui/dropdown-menu";
import { useToast } from "@/components/ui/use-toast";

export function WalletSelector() {
const { account, connected, disconnect, wallet } = useWallet();
Expand Down Expand Up @@ -60,22 +51,15 @@ export function WalletSelector() {
return connected ? (
<DropdownMenu>
<DropdownMenuTrigger asChild>
<Button>
{account?.ansName || truncateAddress(account?.address) || "Unknown"}
</Button>
<Button>{account?.ansName || truncateAddress(account?.address) || "Unknown"}</Button>
</DropdownMenuTrigger>
<DropdownMenuContent align="end">
<DropdownMenuItem onSelect={copyAddress} className="gap-2">
<Copy className="h-4 w-4" /> Copy address
</DropdownMenuItem>
{wallet && isAptosConnectWallet(wallet) && (
<DropdownMenuItem asChild>
<a
href={APTOS_CONNECT_ACCOUNT_URL}
target="_blank"
rel="noopener noreferrer"
className="flex gap-2"
>
<a href={APTOS_CONNECT_ACCOUNT_URL} target="_blank" rel="noopener noreferrer" className="flex gap-2">
<User className="h-4 w-4" /> Account
</a>
</DropdownMenuItem>
Expand Down Expand Up @@ -133,11 +117,7 @@ function ConnectWalletDialog({ close }: ConnectWalletDialogProps) {
</DialogHeader>
<div className="flex flex-col gap-3 pt-3">
{aptosConnectWallets.map((wallet) => (
<AptosConnectWalletRow
key={wallet.name}
wallet={wallet}
onConnect={close}
/>
<AptosConnectWalletRow key={wallet.name} wallet={wallet} onConnect={close} />
))}
</div>
<div className="flex items-center gap-3 pt-4 text-muted-foreground">
Expand Down Expand Up @@ -166,11 +146,7 @@ function ConnectWalletDialog({ close }: ConnectWalletDialogProps) {
</CollapsibleTrigger>
<CollapsibleContent className="flex flex-col gap-3">
{moreWallets.map((wallet) => (
<WalletRow
key={wallet.name}
wallet={wallet}
onConnect={close}
/>
<WalletRow key={wallet.name} wallet={wallet} onConnect={close} />
))}
</CollapsibleContent>
</Collapsible>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
import { AccountAddressInput } from "@aptos-labs/ts-sdk";
import { InputTransactionData } from "@aptos-labs/wallet-adapter-react";

import { APT_DECIMALS, dateToSeconds, convertAmountFromHumanReadableToOnChain } from "@/utils/helpers";

export type CreateCollectionArguments = {
collectionDescription: string; // The collection description
collectionName: string; // The collection name
projectUri: string; // The project URI (i.e https://mydomain.com)
maxSupply: number; // The amount of NFTs in a collection
royaltyPercentage?: number; // The percentage of trading value that collection creator gets when an NFT is sold on marketplaces
preMintAmount?: number; // amount of NFT to pre-mint for myself
allowList?: Array<AccountAddressInput>; // addresses in the allow list
allowListStartDate?: Date; // allow list start time (in seconds)
allowListEndDate?: Date; // allow list end time (in seconds)
allowListLimitPerAccount?: number; // mint limit per address in the allow list
allowListFeePerNFT?: number; // mint fee per NFT for the allow list
publicMintStartDate?: Date; // public mint start time (in seconds)
publicMintEndDate?: Date; // public mint end time (in seconds)
publicMintLimitPerAccount: number; // mint limit per address in the public mint
publicMintFeePerNFT?: number; // mint fee per NFT for the public mint, on chain stored in smallest unit of APT (i.e. 1e8 oAPT = 1 APT)
};

export const createCollection = (args: CreateCollectionArguments): InputTransactionData => {
const {
collectionDescription,
collectionName,
projectUri,
maxSupply,
royaltyPercentage,
preMintAmount,
allowList,
allowListStartDate,
allowListEndDate,
allowListLimitPerAccount,
allowListFeePerNFT,
publicMintStartDate,
publicMintEndDate,
publicMintLimitPerAccount,
publicMintFeePerNFT,
} = args;
return {
data: {
function: `${import.meta.env.VITE_MODULE_ADDRESS}::launchpad::create_collection`,
typeArguments: [],
functionArguments: [
collectionDescription,
collectionName,
projectUri,
maxSupply,
royaltyPercentage,
preMintAmount,
allowList,
dateToSeconds(allowListStartDate),
dateToSeconds(allowListEndDate),
allowListLimitPerAccount,
allowListFeePerNFT,
publicMintStartDate ? dateToSeconds(publicMintStartDate) : dateToSeconds(new Date()),
dateToSeconds(publicMintEndDate),
publicMintLimitPerAccount,
publicMintFeePerNFT ? convertAmountFromHumanReadableToOnChain(publicMintFeePerNFT, APT_DECIMALS) : 0,
],
},
};
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import { InputTransactionData } from "@aptos-labs/wallet-adapter-react";

export type MintNftArguments = {
collectionId: string;
amount: number;
};

export const mintNFT = (args: MintNftArguments): InputTransactionData => {
const { collectionId, amount } = args;
return {
data: {
function: `${import.meta.env.VITE_MODULE_ADDRESS}::launchpad::mint_nft`,
typeArguments: [],
functionArguments: [collectionId, amount],
},
};
};
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
import { AccountAddress } from "@aptos-labs/ts-sdk";
import { useQuery } from "@tanstack/react-query";

import { config } from "@/config";
import { MODULE_ADDRESS } from "@/constants";
import { aptosClient } from "@/utils/aptosClient";
import { AccountAddress } from "@aptos-labs/ts-sdk";
import { useQuery } from "@tanstack/react-query";

export interface Token {
token_name: string;
Expand Down Expand Up @@ -78,7 +79,7 @@ async function getStartAndEndTime(collection_id: string): Promise<[start: Date,
];
}

export function useMintData(collection_id: string = config.collection_id) {
export function useGetCollectionData(collection_id: string = config.collection_id) {
return useQuery({
queryKey: ["app-state", collection_id],
refetchInterval: 1000 * 30,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import { aptosClient } from "@/utils/aptosClient";
import { AccountAddress, GetCollectionDataResponse } from "@aptos-labs/ts-sdk";
import { useState, useEffect } from "react";

import { aptosClient } from "@/utils/aptosClient";

/**
* A react hook to get all collections under the current contract.
*
Expand All @@ -10,9 +11,7 @@ import { useState, useEffect } from "react";
*
*/
export function useGetCollections() {
const [collections, setCollections] = useState<
Array<GetCollectionDataResponse>
>([]);
const [collections, setCollections] = useState<Array<GetCollectionDataResponse>>([]);

useEffect(() => {
async function run() {
Expand All @@ -34,9 +33,7 @@ export function useGetCollections() {
const getRegistry = async () => {
const registry = await aptosClient().view<[[{ inner: string }]]>({
payload: {
function: `${AccountAddress.from(
import.meta.env.VITE_MODULE_ADDRESS
)}::launchpad::get_registry`,
function: `${AccountAddress.from(import.meta.env.VITE_MODULE_ADDRESS)}::launchpad::get_registry`,
},
});
return registry[0];
Expand All @@ -51,7 +48,7 @@ const getObjects = async (registry: [{ inner: string }]) => {
});

return object.owner_address;
})
}),
);
return objects;
};
Expand All @@ -66,7 +63,7 @@ const getCollections = async (objects: Array<string>) => {
});

return collection;
})
}),
);
return collections;
};
10 changes: 5 additions & 5 deletions templates/digital-asset-template/frontend/main.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,10 @@ import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
import React from "react";
import ReactDOM from "react-dom/client";

import App from "./App";
import { WalletProvider } from "./components/WalletProvider";
import { Toaster } from "./components/ui/toaster";
import { TooltipProvider } from "./components/ui/tooltip";
import App from "@/App";
import { WalletProvider } from "@/components/WalletProvider";
import { Toaster } from "@/components/ui/toaster";
import { TooltipProvider } from "@/components/ui/tooltip";

const queryClient = new QueryClient();

Expand All @@ -21,5 +21,5 @@ ReactDOM.createRoot(document.getElementById("root")!).render(
</TooltipProvider>
</QueryClientProvider>
</WalletProvider>
</React.StrictMode>
</React.StrictMode>,
);
Loading

0 comments on commit 1c9b96f

Please sign in to comment.