Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Clean up and refactor digital asset template #121

Merged
merged 2 commits into from
Jun 24, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading