Compare commits
23
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
755e5d40ca | ||
|
|
a2f561f97b | ||
|
|
72a4ac5a98 | ||
|
|
69ec6e0553 | ||
|
|
21cc01a0aa | ||
|
|
c03734aea9 | ||
|
|
8da0c1fdcd | ||
|
|
8dc27ffcc4 | ||
|
|
f85163edee | ||
|
|
7965d93b7a | ||
|
|
4ccf06260b | ||
|
|
d7dc83f9e6 | ||
|
|
9877176f65 | ||
|
|
67768ac375 | ||
|
|
8937d5511e | ||
|
|
bf81deeb35 | ||
|
|
25a7ad7eb9 | ||
|
|
ac8b09f35e | ||
|
|
f7f179c771 | ||
|
|
d0bf3f3f5e | ||
|
|
96689c6e2a | ||
|
|
0c5c918b21 | ||
|
|
e1763e216a |
@@ -89,7 +89,7 @@ jobs:
|
||||
- run: pnpm test
|
||||
|
||||
- name: Code Coverage
|
||||
uses: codecov/codecov-action@0565863a31f2c772f9f0395002a31e3f06189574 # v5.4.0
|
||||
uses: codecov/codecov-action@ad3126e916f78f00edff4ed0317cf185271ccc2d # v5.4.2
|
||||
with:
|
||||
directory: packages/
|
||||
flags: packages
|
||||
|
||||
@@ -46,7 +46,7 @@ jobs:
|
||||
|
||||
# Initializes the CodeQL tools for scanning.
|
||||
- name: Initialize CodeQL
|
||||
uses: github/codeql-action/init@6bb031afdd8eb862ea3fc1848194185e076637e5 # v3.28.11
|
||||
uses: github/codeql-action/init@45775bd8235c68ba998cffa5171334d58593da47 # v3.28.15
|
||||
with:
|
||||
languages: ${{ matrix.language }}
|
||||
# If you wish to specify custom queries, you can do so here or in a config file.
|
||||
@@ -59,7 +59,7 @@ jobs:
|
||||
# Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
|
||||
# If this step fails, then you should remove it and run the build manually (see below)
|
||||
- name: Autobuild
|
||||
uses: github/codeql-action/autobuild@6bb031afdd8eb862ea3fc1848194185e076637e5 # v3.28.11
|
||||
uses: github/codeql-action/autobuild@45775bd8235c68ba998cffa5171334d58593da47 # v3.28.15
|
||||
|
||||
# ℹ️ Command-line programs to run using the OS shell.
|
||||
# 📚 See https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsrun
|
||||
@@ -72,4 +72,4 @@ jobs:
|
||||
# ./location_of_script_within_repo/buildscript.sh
|
||||
|
||||
- name: Perform CodeQL Analysis
|
||||
uses: github/codeql-action/analyze@6bb031afdd8eb862ea3fc1848194185e076637e5 # v3.28.11
|
||||
uses: github/codeql-action/analyze@45775bd8235c68ba998cffa5171334d58593da47 # v3.28.15
|
||||
|
||||
+31
-31
@@ -29,26 +29,26 @@
|
||||
"@emotion/styled": "11.14.0",
|
||||
"@hookform/resolvers": "^3.9.1",
|
||||
"@marsidev/react-turnstile": "^1.1.0",
|
||||
"@radix-ui/react-accordion": "^1.2.4",
|
||||
"@radix-ui/react-alert-dialog": "^1.1.7",
|
||||
"@radix-ui/react-avatar": "^1.1.4",
|
||||
"@radix-ui/react-checkbox": "^1.1.5",
|
||||
"@radix-ui/react-dialog": "1.1.7",
|
||||
"@radix-ui/react-dropdown-menu": "^2.1.7",
|
||||
"@radix-ui/react-hover-card": "^1.1.7",
|
||||
"@radix-ui/react-label": "^2.1.3",
|
||||
"@radix-ui/react-popover": "^1.1.7",
|
||||
"@radix-ui/react-progress": "^1.1.3",
|
||||
"@radix-ui/react-radio-group": "^1.2.4",
|
||||
"@radix-ui/react-select": "^2.1.7",
|
||||
"@radix-ui/react-separator": "^1.1.3",
|
||||
"@radix-ui/react-accordion": "^1.2.7",
|
||||
"@radix-ui/react-alert-dialog": "^1.1.10",
|
||||
"@radix-ui/react-avatar": "^1.1.6",
|
||||
"@radix-ui/react-checkbox": "^1.2.2",
|
||||
"@radix-ui/react-dialog": "1.1.10",
|
||||
"@radix-ui/react-dropdown-menu": "^2.1.11",
|
||||
"@radix-ui/react-hover-card": "^1.1.10",
|
||||
"@radix-ui/react-label": "^2.1.4",
|
||||
"@radix-ui/react-popover": "^1.1.10",
|
||||
"@radix-ui/react-progress": "^1.1.4",
|
||||
"@radix-ui/react-radio-group": "^1.3.3",
|
||||
"@radix-ui/react-select": "^2.2.2",
|
||||
"@radix-ui/react-separator": "^1.1.4",
|
||||
"@radix-ui/react-slot": "^1.2.0",
|
||||
"@radix-ui/react-switch": "^1.1.4",
|
||||
"@radix-ui/react-tooltip": "1.2.0",
|
||||
"@sentry/nextjs": "9.12.0",
|
||||
"@radix-ui/react-switch": "^1.2.2",
|
||||
"@radix-ui/react-tooltip": "1.2.3",
|
||||
"@sentry/nextjs": "9.13.0",
|
||||
"@shazow/whatsabi": "0.21.0",
|
||||
"@tanstack/react-query": "5.72.1",
|
||||
"@tanstack/react-table": "^8.21.2",
|
||||
"@tanstack/react-query": "5.74.4",
|
||||
"@tanstack/react-table": "^8.21.3",
|
||||
"@thirdweb-dev/service-utils": "workspace:*",
|
||||
"@vercel/functions": "2.0.0",
|
||||
"@vercel/og": "^0.6.8",
|
||||
@@ -66,14 +66,14 @@
|
||||
"fuse.js": "7.1.0",
|
||||
"idb-keyval": "^6.2.1",
|
||||
"input-otp": "^1.4.1",
|
||||
"ioredis": "^5.6.0",
|
||||
"ioredis": "^5.6.1",
|
||||
"ipaddr.js": "^2.2.0",
|
||||
"lucide-react": "0.487.0",
|
||||
"next": "15.2.4",
|
||||
"lucide-react": "0.503.0",
|
||||
"next": "15.3.1",
|
||||
"next-plausible": "^3.12.4",
|
||||
"next-themes": "^0.4.6",
|
||||
"nextjs-toploader": "^1.6.12",
|
||||
"nuqs": "^2.4.1",
|
||||
"nuqs": "^2.4.3",
|
||||
"p-limit": "^6.2.0",
|
||||
"papaparse": "^5.5.2",
|
||||
"pluralize": "^8.0.0",
|
||||
@@ -89,7 +89,7 @@
|
||||
"react-hook-form": "7.55.0",
|
||||
"react-markdown": "^9.0.1",
|
||||
"react-table": "^7.8.0",
|
||||
"recharts": "2.15.2",
|
||||
"recharts": "2.15.3",
|
||||
"remark-gfm": "4.0.1",
|
||||
"responsive-rsc": "0.0.7",
|
||||
"server-only": "^0.0.1",
|
||||
@@ -97,20 +97,20 @@
|
||||
"sonner": "2.0.3",
|
||||
"spdx-correct": "^3.2.0",
|
||||
"stripe": "17.7.0",
|
||||
"swagger-ui-react": "^5.20.7",
|
||||
"swagger-ui-react": "^5.21.0",
|
||||
"tailwind-merge": "^2.6.0",
|
||||
"tailwindcss-animate": "^1.0.7",
|
||||
"thirdweb": "workspace:*",
|
||||
"tiny-invariant": "^1.3.3",
|
||||
"use-debounce": "^10.0.4",
|
||||
"zod": "3.24.2"
|
||||
"zod": "3.24.3"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@chakra-ui/cli": "^2.4.1",
|
||||
"@chromatic-com/storybook": "3.2.6",
|
||||
"@next/bundle-analyzer": "15.2.4",
|
||||
"@next/eslint-plugin-next": "15.2.4",
|
||||
"@playwright/test": "1.51.1",
|
||||
"@next/bundle-analyzer": "15.3.1",
|
||||
"@next/eslint-plugin-next": "15.3.1",
|
||||
"@playwright/test": "1.52.0",
|
||||
"@storybook/addon-essentials": "8.6.12",
|
||||
"@storybook/addon-interactions": "8.6.12",
|
||||
"@storybook/addon-links": "8.6.12",
|
||||
@@ -121,11 +121,11 @@
|
||||
"@storybook/react": "8.6.12",
|
||||
"@storybook/test": "8.6.12",
|
||||
"@types/color": "4.2.0",
|
||||
"@types/node": "22.14.0",
|
||||
"@types/node": "22.14.1",
|
||||
"@types/papaparse": "^5.3.15",
|
||||
"@types/pluralize": "^0.0.33",
|
||||
"@types/qrcode": "^1.5.5",
|
||||
"@types/react": "19.1.0",
|
||||
"@types/react": "19.1.2",
|
||||
"@types/react-dom": "19.1.2",
|
||||
"@types/react-table": "^7.7.20",
|
||||
"@types/spdx-correct": "^3.1.3",
|
||||
@@ -138,7 +138,7 @@
|
||||
"eslint-config-biome": "1.9.4",
|
||||
"eslint-plugin-react-compiler": "19.0.0-beta-e993439-20250405",
|
||||
"eslint-plugin-storybook": "0.12.0",
|
||||
"knip": "5.47.0",
|
||||
"knip": "5.50.5",
|
||||
"next-sitemap": "^4.2.3",
|
||||
"postcss": "8.5.3",
|
||||
"storybook": "8.6.12",
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
"use server";
|
||||
|
||||
import { getThirdwebClient } from "@/constants/thirdweb.server";
|
||||
import { defineDashboardChain } from "lib/defineDashboardChain";
|
||||
import { ZERO_ADDRESS, isAddress, toTokens } from "thirdweb";
|
||||
import { getWalletBalance } from "thirdweb/wallets";
|
||||
import { getUserThirdwebClient } from "../../app/api/lib/getAuthToken";
|
||||
|
||||
type BalanceQueryResponse = Array<{
|
||||
balance: string;
|
||||
@@ -24,6 +23,7 @@ export async function getTokenBalancesFromMoralis(params: {
|
||||
error: string;
|
||||
}
|
||||
> {
|
||||
const client = await getUserThirdwebClient();
|
||||
const { contractAddress, chainId } = params;
|
||||
|
||||
if (!isAddress(contractAddress)) {
|
||||
@@ -39,7 +39,7 @@ export async function getTokenBalancesFromMoralis(params: {
|
||||
const balance = await getWalletBalance({
|
||||
address: contractAddress,
|
||||
chain,
|
||||
client: getThirdwebClient(),
|
||||
client,
|
||||
});
|
||||
return [
|
||||
{
|
||||
|
||||
@@ -2,16 +2,16 @@
|
||||
|
||||
import {
|
||||
generateAlchemyUrl,
|
||||
isAlchemySupported,
|
||||
transformAlchemyResponseToNFT,
|
||||
} from "lib/wallet/nfts/alchemy";
|
||||
import {
|
||||
generateMoralisUrl,
|
||||
isMoralisSupported,
|
||||
transformMoralisResponseToNFT,
|
||||
} from "lib/wallet/nfts/moralis";
|
||||
import type { WalletNFT } from "lib/wallet/nfts/types";
|
||||
import { getVercelEnv } from "../../lib/vercel-utils";
|
||||
import { isAlchemySupported } from "../../lib/wallet/nfts/isAlchemySupported";
|
||||
import { isMoralisSupported } from "../../lib/wallet/nfts/isMoralisSupported";
|
||||
import { DASHBOARD_THIRDWEB_CLIENT_ID } from "../constants/env";
|
||||
|
||||
type WalletNFTApiReturn =
|
||||
|
||||
@@ -1,48 +0,0 @@
|
||||
"use server";
|
||||
|
||||
import type { Account } from "@3rdweb-sdk/react/hooks/useApi";
|
||||
import { cookies } from "next/headers";
|
||||
import { getAddress } from "thirdweb";
|
||||
import { COOKIE_PREFIX_TOKEN } from "../constants/cookie";
|
||||
import { API_SERVER_URL } from "../constants/env";
|
||||
|
||||
/**
|
||||
* Check that the connected wallet is valid for the current active account
|
||||
*/
|
||||
export async function isWalletValidForActiveAccount(params: {
|
||||
address: string;
|
||||
account: Account;
|
||||
authToken: string;
|
||||
}) {
|
||||
const cookieStore = await cookies();
|
||||
const authCookieNameForAddress =
|
||||
COOKIE_PREFIX_TOKEN + getAddress(params.address);
|
||||
|
||||
// authToken for this wallet address should be present
|
||||
const authTokenForAddress = cookieStore.get(authCookieNameForAddress)?.value;
|
||||
if (!authTokenForAddress) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// this authToken should be same as current active authToken
|
||||
if (authTokenForAddress !== params.authToken) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// authToken should be valid
|
||||
const accountRes = await fetch(`${API_SERVER_URL}/v1/account/me`, {
|
||||
method: "GET",
|
||||
headers: {
|
||||
Authorization: `Bearer ${authTokenForAddress}`,
|
||||
},
|
||||
});
|
||||
|
||||
if (accountRes.status !== 200) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const account = (await accountRes.json()).data as Account;
|
||||
|
||||
// the current account should match the account fetched for the authToken
|
||||
return account.id === params.account.id;
|
||||
}
|
||||
@@ -0,0 +1,148 @@
|
||||
"use server";
|
||||
import { getAuthToken } from "app/api/lib/getAuthToken";
|
||||
|
||||
const UB_BASE_URL = process.env.NEXT_PUBLIC_THIRDWEB_BRIDGE_HOST;
|
||||
|
||||
type Webhook = {
|
||||
url: string;
|
||||
label: string;
|
||||
active: boolean;
|
||||
createdAt: string;
|
||||
id: string;
|
||||
secret: string;
|
||||
version?: number; // TODO (UB) make this mandatory after migration
|
||||
};
|
||||
|
||||
export async function getWebhooks(props: {
|
||||
clientId: string;
|
||||
}) {
|
||||
const authToken = await getAuthToken();
|
||||
const res = await fetch(`${UB_BASE_URL}/v1/developer/webhooks`, {
|
||||
method: "GET",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
"x-client-id-override": props.clientId,
|
||||
Authorization: `Bearer ${authToken}`,
|
||||
},
|
||||
});
|
||||
|
||||
if (!res.ok) {
|
||||
const text = await res.text();
|
||||
throw new Error(text);
|
||||
}
|
||||
|
||||
const json = await res.json();
|
||||
return json.data as Array<Webhook>;
|
||||
}
|
||||
|
||||
export async function createWebhook(props: {
|
||||
clientId: string;
|
||||
version?: number;
|
||||
url: string;
|
||||
label: string;
|
||||
secret?: string;
|
||||
}) {
|
||||
const authToken = await getAuthToken();
|
||||
const res = await fetch(`${UB_BASE_URL}/v1/developer/webhooks`, {
|
||||
method: "POST",
|
||||
body: JSON.stringify({
|
||||
url: props.url,
|
||||
label: props.label,
|
||||
version: props.version,
|
||||
secret: props.secret,
|
||||
}),
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
"x-client-id-override": props.clientId,
|
||||
Authorization: `Bearer ${authToken}`,
|
||||
},
|
||||
});
|
||||
|
||||
if (!res.ok) {
|
||||
const text = await res.text();
|
||||
throw new Error(text);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
export async function deleteWebhook(props: {
|
||||
clientId: string;
|
||||
webhookId: string;
|
||||
}) {
|
||||
const authToken = await getAuthToken();
|
||||
const res = await fetch(
|
||||
`${UB_BASE_URL}/v1/developer/webhooks/${props.webhookId}`,
|
||||
{
|
||||
method: "DELETE",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
"x-client-id-override": props.clientId,
|
||||
Authorization: `Bearer ${authToken}`,
|
||||
},
|
||||
},
|
||||
);
|
||||
|
||||
if (!res.ok) {
|
||||
const text = await res.text();
|
||||
throw new Error(text);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
export type Fee = {
|
||||
feeRecipient: string;
|
||||
feeBps: number;
|
||||
createdAt: string;
|
||||
updatedAt: string;
|
||||
};
|
||||
|
||||
export async function getFees(props: {
|
||||
clientId: string;
|
||||
}) {
|
||||
const authToken = await getAuthToken();
|
||||
const res = await fetch(`${UB_BASE_URL}/v1/developer/fees`, {
|
||||
method: "GET",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
"x-client-id-override": props.clientId,
|
||||
Authorization: `Bearer ${authToken}`,
|
||||
},
|
||||
});
|
||||
|
||||
if (!res.ok) {
|
||||
const text = await res.text();
|
||||
throw new Error(text);
|
||||
}
|
||||
|
||||
const json = await res.json();
|
||||
return json.data as Fee;
|
||||
}
|
||||
|
||||
export async function updateFee(props: {
|
||||
clientId: string;
|
||||
feeRecipient: string;
|
||||
feeBps: number;
|
||||
}) {
|
||||
const authToken = await getAuthToken();
|
||||
const res = await fetch(`${UB_BASE_URL}/v1/developer/fees`, {
|
||||
method: "PUT",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
"x-client-id-override": props.clientId,
|
||||
Authorization: `Bearer ${authToken}`,
|
||||
},
|
||||
body: JSON.stringify({
|
||||
feeRecipient: props.feeRecipient,
|
||||
feeBps: props.feeBps,
|
||||
}),
|
||||
});
|
||||
|
||||
if (!res.ok) {
|
||||
const text = await res.text();
|
||||
throw new Error(text);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
@@ -1,7 +1,9 @@
|
||||
import type { Meta, StoryObj } from "@storybook/react";
|
||||
import { useState } from "react";
|
||||
import { BadgeContainer } from "../../../../stories/utils";
|
||||
import { getThirdwebClient } from "../../../constants/thirdweb.server";
|
||||
import {
|
||||
BadgeContainer,
|
||||
storybookThirdwebClient,
|
||||
} from "../../../../stories/utils";
|
||||
import { Button } from "../../ui/button";
|
||||
import { GradientAvatar } from "./GradientAvatar";
|
||||
|
||||
@@ -17,8 +19,6 @@ export const Variants: Story = {
|
||||
args: {},
|
||||
};
|
||||
|
||||
const client = getThirdwebClient();
|
||||
|
||||
function Story() {
|
||||
return (
|
||||
<div className="container flex max-w-6xl flex-col gap-10 py-10">
|
||||
@@ -29,7 +29,7 @@ function Story() {
|
||||
id={undefined}
|
||||
src={undefined}
|
||||
className="size-20"
|
||||
client={client}
|
||||
client={storybookThirdwebClient}
|
||||
/>
|
||||
</BadgeContainer>
|
||||
|
||||
@@ -38,7 +38,7 @@ function Story() {
|
||||
id={"foo"}
|
||||
src={undefined}
|
||||
className="size-20"
|
||||
client={client}
|
||||
client={storybookThirdwebClient}
|
||||
/>
|
||||
</BadgeContainer>
|
||||
|
||||
@@ -47,7 +47,7 @@ function Story() {
|
||||
id={"foo"}
|
||||
src={""}
|
||||
className="size-20"
|
||||
client={client}
|
||||
client={storybookThirdwebClient}
|
||||
/>
|
||||
</BadgeContainer>
|
||||
|
||||
@@ -56,7 +56,7 @@ function Story() {
|
||||
id={"bar"}
|
||||
src={""}
|
||||
className="size-20"
|
||||
client={client}
|
||||
client={storybookThirdwebClient}
|
||||
/>
|
||||
</BadgeContainer>
|
||||
|
||||
@@ -65,7 +65,7 @@ function Story() {
|
||||
src="invalid-src"
|
||||
id={undefined}
|
||||
className="size-20"
|
||||
client={client}
|
||||
client={storybookThirdwebClient}
|
||||
/>
|
||||
</BadgeContainer>
|
||||
|
||||
@@ -74,7 +74,7 @@ function Story() {
|
||||
src="https://picsum.photos/200/300"
|
||||
id={undefined}
|
||||
className="size-20"
|
||||
client={client}
|
||||
client={storybookThirdwebClient}
|
||||
/>
|
||||
</BadgeContainer>
|
||||
|
||||
@@ -83,7 +83,7 @@ function Story() {
|
||||
src="ipfs://QmZbeJYEs7kCJHyQxjxU2SJUtjSAr4m87wzJFJUyWomKdj/Smily.svg"
|
||||
id={undefined}
|
||||
className="size-20"
|
||||
client={client}
|
||||
client={storybookThirdwebClient}
|
||||
/>
|
||||
</BadgeContainer>
|
||||
|
||||
@@ -123,7 +123,7 @@ function ToggleTest() {
|
||||
src={data?.src}
|
||||
id={data?.id}
|
||||
className="size-20"
|
||||
client={client}
|
||||
client={storybookThirdwebClient}
|
||||
/>
|
||||
</BadgeContainer>
|
||||
|
||||
@@ -132,7 +132,7 @@ function ToggleTest() {
|
||||
className="size-20"
|
||||
src={data ? "invalid-src" : undefined}
|
||||
id={undefined}
|
||||
client={client}
|
||||
client={storybookThirdwebClient}
|
||||
/>
|
||||
</BadgeContainer>
|
||||
</div>
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
import type { Meta, StoryObj } from "@storybook/react";
|
||||
import { useState } from "react";
|
||||
import { BadgeContainer } from "../../../../stories/utils";
|
||||
import { getThirdwebClient } from "../../../constants/thirdweb.server";
|
||||
import {
|
||||
BadgeContainer,
|
||||
storybookThirdwebClient,
|
||||
} from "../../../../stories/utils";
|
||||
import { Button } from "../../ui/button";
|
||||
import { ProjectAvatar } from "./ProjectAvatar";
|
||||
|
||||
@@ -18,19 +20,25 @@ export const Variants: Story = {
|
||||
args: {},
|
||||
};
|
||||
|
||||
const client = getThirdwebClient();
|
||||
|
||||
function Story() {
|
||||
return (
|
||||
<div className="container flex max-w-6xl flex-col gap-10 py-10">
|
||||
<p> All images below are set with size-6 className </p>
|
||||
|
||||
<BadgeContainer label="No Src - Skeleton">
|
||||
<ProjectAvatar src={undefined} className="size-6" client={client} />
|
||||
<ProjectAvatar
|
||||
src={undefined}
|
||||
className="size-6"
|
||||
client={storybookThirdwebClient}
|
||||
/>
|
||||
</BadgeContainer>
|
||||
|
||||
<BadgeContainer label="Invalid/Empty Src - BoxIcon Fallback">
|
||||
<ProjectAvatar src={""} className="size-6" client={client} />
|
||||
<ProjectAvatar
|
||||
src={""}
|
||||
className="size-6"
|
||||
client={storybookThirdwebClient}
|
||||
/>
|
||||
</BadgeContainer>
|
||||
|
||||
<ToggleTest />
|
||||
@@ -65,14 +73,18 @@ function ToggleTest() {
|
||||
<p> Src+Name is: {data ? "set" : "not set"} </p>
|
||||
|
||||
<BadgeContainer label="Valid Src">
|
||||
<ProjectAvatar src={data?.src} className="size-6" client={client} />
|
||||
<ProjectAvatar
|
||||
src={data?.src}
|
||||
className="size-6"
|
||||
client={storybookThirdwebClient}
|
||||
/>
|
||||
</BadgeContainer>
|
||||
|
||||
<BadgeContainer label="invalid Src">
|
||||
<ProjectAvatar
|
||||
src={data ? "invalid-src" : undefined}
|
||||
className="size-6"
|
||||
client={client}
|
||||
client={storybookThirdwebClient}
|
||||
/>
|
||||
</BadgeContainer>
|
||||
</div>
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
import type { Meta, StoryObj } from "@storybook/react";
|
||||
import { useState } from "react";
|
||||
import { BadgeContainer } from "../../../stories/utils";
|
||||
import {
|
||||
BadgeContainer,
|
||||
storybookThirdwebClient,
|
||||
} from "../../../stories/utils";
|
||||
import { MultiNetworkSelector } from "./NetworkSelectors";
|
||||
|
||||
const meta = {
|
||||
@@ -41,6 +44,7 @@ function Variant(props: {
|
||||
<BadgeContainer label={props.label}>
|
||||
<MultiNetworkSelector
|
||||
selectedChainIds={chainIds}
|
||||
client={storybookThirdwebClient}
|
||||
onChange={setChainIds}
|
||||
/>
|
||||
</BadgeContainer>
|
||||
|
||||
@@ -4,6 +4,7 @@ import { MultiSelect } from "@/components/blocks/multi-select";
|
||||
import { SelectWithSearch } from "@/components/blocks/select-with-search";
|
||||
import { Badge } from "@/components/ui/badge";
|
||||
import { useCallback, useMemo } from "react";
|
||||
import type { ThirdwebClient } from "thirdweb";
|
||||
import { ChainIconClient } from "../../../components/icons/ChainIcon";
|
||||
import { useAllChainsData } from "../../../hooks/chains/allChains";
|
||||
|
||||
@@ -20,6 +21,12 @@ export function MultiNetworkSelector(props: {
|
||||
className?: string;
|
||||
priorityChains?: number[];
|
||||
hideTestnets?: boolean;
|
||||
popoverContentClassName?: string;
|
||||
customTrigger?: React.ReactNode;
|
||||
align?: "center" | "start" | "end";
|
||||
side?: "left" | "right" | "top" | "bottom";
|
||||
showSelectedValuesInModal?: boolean;
|
||||
client: ThirdwebClient;
|
||||
}) {
|
||||
const { allChains, idToChain } = useAllChainsData();
|
||||
|
||||
@@ -84,8 +91,9 @@ export function MultiNetworkSelector(props: {
|
||||
<span className="flex grow gap-2 truncate text-left">
|
||||
<ChainIconClient
|
||||
className="size-5"
|
||||
ipfsSrc={chain.icon?.url}
|
||||
loading="lazy"
|
||||
src={chain.icon?.url}
|
||||
client={props.client}
|
||||
/>
|
||||
{cleanChainName(chain.name)}
|
||||
</span>
|
||||
@@ -99,14 +107,19 @@ export function MultiNetworkSelector(props: {
|
||||
</div>
|
||||
);
|
||||
},
|
||||
[idToChain, props.disableChainId],
|
||||
[idToChain, props.disableChainId, props.client],
|
||||
);
|
||||
|
||||
return (
|
||||
<MultiSelect
|
||||
searchPlaceholder="Search by Name or Chain Id"
|
||||
selectedValues={props.selectedChainIds.map(String)}
|
||||
popoverContentClassName={props.popoverContentClassName}
|
||||
customTrigger={props.customTrigger}
|
||||
options={options}
|
||||
align={props.align}
|
||||
side={props.side}
|
||||
showSelectedValuesInModal={props.showSelectedValuesInModal}
|
||||
onSelectedValuesChange={(chainIds) => {
|
||||
props.onChange(chainIds.map(Number));
|
||||
}}
|
||||
@@ -132,6 +145,7 @@ export function SingleNetworkSelector(props: {
|
||||
disableChainId?: boolean;
|
||||
align?: "center" | "start" | "end";
|
||||
placeholder?: string;
|
||||
client: ThirdwebClient;
|
||||
}) {
|
||||
const { allChains, idToChain } = useAllChainsData();
|
||||
|
||||
@@ -179,7 +193,8 @@ export function SingleNetworkSelector(props: {
|
||||
<span className="flex grow gap-2 truncate text-left">
|
||||
<ChainIconClient
|
||||
className="size-5"
|
||||
ipfsSrc={chain.icon?.url}
|
||||
src={chain.icon?.url}
|
||||
client={props.client}
|
||||
loading="lazy"
|
||||
/>
|
||||
{cleanChainName(chain.name)}
|
||||
@@ -194,7 +209,7 @@ export function SingleNetworkSelector(props: {
|
||||
</div>
|
||||
);
|
||||
},
|
||||
[idToChain, props.disableChainId],
|
||||
[idToChain, props.disableChainId, props.client],
|
||||
);
|
||||
|
||||
const isLoadingChains = allChains.length === 0;
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
import type { Meta, StoryObj } from "@storybook/react";
|
||||
import { useState } from "react";
|
||||
import { BadgeContainer } from "../../../stories/utils";
|
||||
import {
|
||||
BadgeContainer,
|
||||
storybookThirdwebClient,
|
||||
} from "../../../stories/utils";
|
||||
import { SingleNetworkSelector } from "./NetworkSelectors";
|
||||
|
||||
const meta = {
|
||||
@@ -43,6 +46,7 @@ function Variant(props: {
|
||||
return (
|
||||
<BadgeContainer label={props.label}>
|
||||
<SingleNetworkSelector
|
||||
client={storybookThirdwebClient}
|
||||
chainId={chainId}
|
||||
onChange={setChainId}
|
||||
chainIds={props.chainIds}
|
||||
|
||||
@@ -47,7 +47,12 @@ interface MultiSelectProps
|
||||
searchTerm: string,
|
||||
) => boolean;
|
||||
|
||||
popoverContentClassName?: string;
|
||||
customTrigger?: React.ReactNode;
|
||||
renderOption?: (option: { value: string; label: string }) => React.ReactNode;
|
||||
align?: "center" | "start" | "end";
|
||||
side?: "left" | "right" | "top" | "bottom";
|
||||
showSelectedValuesInModal?: boolean;
|
||||
}
|
||||
|
||||
export const MultiSelect = forwardRef<HTMLButtonElement, MultiSelectProps>(
|
||||
@@ -62,6 +67,8 @@ export const MultiSelect = forwardRef<HTMLButtonElement, MultiSelectProps>(
|
||||
overrideSearchFn,
|
||||
renderOption,
|
||||
searchPlaceholder,
|
||||
popoverContentClassName,
|
||||
showSelectedValuesInModal = false,
|
||||
...props
|
||||
},
|
||||
ref,
|
||||
@@ -155,111 +162,100 @@ export const MultiSelect = forwardRef<HTMLButtonElement, MultiSelectProps>(
|
||||
return (
|
||||
<Popover open={isPopoverOpen} onOpenChange={setIsPopoverOpen} modal>
|
||||
<PopoverTrigger asChild>
|
||||
<Button
|
||||
ref={ref}
|
||||
{...props}
|
||||
onClick={handleTogglePopover}
|
||||
className={cn(
|
||||
"flex h-auto min-h-10 w-full items-center justify-between rounded-md border border-border bg-inherit p-3 hover:bg-inherit",
|
||||
className,
|
||||
)}
|
||||
>
|
||||
{selectedValues.length > 0 ? (
|
||||
<div className="flex w-full justify-between">
|
||||
{/* badges */}
|
||||
<div className="flex flex-wrap items-center gap-1.5">
|
||||
{selectedValues.slice(0, maxCount).map((value) => {
|
||||
const option = options.find((o) => o.value === value);
|
||||
if (!option) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<ClosableBadge
|
||||
key={value}
|
||||
label={option.label}
|
||||
onClose={() => toggleOption(value)}
|
||||
/>
|
||||
);
|
||||
})}
|
||||
|
||||
{/* +X more */}
|
||||
{selectedValues.length > maxCount && (
|
||||
<ClosableBadge
|
||||
label={`+ ${selectedValues.length - maxCount} more`}
|
||||
onClose={clearExtraOptions}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
|
||||
<div className="flex items-center justify-between gap-2">
|
||||
{/* Clear All */}
|
||||
{/* biome-ignore lint/a11y/useKeyWithClickEvents: <explanation> */}
|
||||
{/* biome-ignore lint/a11y/useFocusableInteractive: <explanation> */}
|
||||
<div
|
||||
role="button"
|
||||
onClick={(event) => {
|
||||
event.stopPropagation();
|
||||
handleClear();
|
||||
}}
|
||||
className="rounded p-1 hover:bg-accent"
|
||||
>
|
||||
<XIcon className="h-4 cursor-pointer text-muted-foreground" />
|
||||
</div>
|
||||
|
||||
<Separator
|
||||
orientation="vertical"
|
||||
className="flex h-full min-h-6"
|
||||
{props.customTrigger || (
|
||||
<Button
|
||||
ref={ref}
|
||||
{...props}
|
||||
onClick={handleTogglePopover}
|
||||
className={cn(
|
||||
"flex h-auto min-h-10 w-full items-center justify-between rounded-md border border-border bg-inherit p-3 hover:bg-inherit",
|
||||
className,
|
||||
)}
|
||||
>
|
||||
{selectedValues.length > 0 ? (
|
||||
<div className="flex w-full items-center justify-between">
|
||||
<SelectedChainsBadges
|
||||
selectedValues={selectedValues}
|
||||
options={options}
|
||||
maxCount={maxCount}
|
||||
onClose={handleClear}
|
||||
toggleOption={toggleOption}
|
||||
clearExtraOptions={clearExtraOptions}
|
||||
/>
|
||||
<div className="flex items-center justify-between gap-2">
|
||||
{/* Clear All */}
|
||||
{/* biome-ignore lint/a11y/useKeyWithClickEvents: <explanation> */}
|
||||
{/* biome-ignore lint/a11y/useFocusableInteractive: <explanation> */}
|
||||
<div
|
||||
role="button"
|
||||
onClick={(event) => {
|
||||
event.stopPropagation();
|
||||
handleClear();
|
||||
}}
|
||||
className="rounded p-1 hover:bg-accent"
|
||||
>
|
||||
<XIcon className="h-4 cursor-pointer text-muted-foreground" />
|
||||
</div>
|
||||
|
||||
<Separator
|
||||
orientation="vertical"
|
||||
className="flex h-full min-h-6"
|
||||
/>
|
||||
<ChevronDown className="h-4 cursor-pointer text-muted-foreground" />
|
||||
</div>
|
||||
</div>
|
||||
) : (
|
||||
<div className="flex w-full items-center justify-between">
|
||||
<span className="text-muted-foreground text-sm">
|
||||
{placeholder}
|
||||
</span>
|
||||
<ChevronDown className="h-4 cursor-pointer text-muted-foreground" />
|
||||
</div>
|
||||
</div>
|
||||
) : (
|
||||
<div className="flex w-full items-center justify-between">
|
||||
<span className="text-muted-foreground text-sm">
|
||||
{placeholder}
|
||||
</span>
|
||||
<ChevronDown className="h-4 cursor-pointer text-muted-foreground" />
|
||||
</div>
|
||||
)}
|
||||
</Button>
|
||||
)}
|
||||
</Button>
|
||||
)}
|
||||
</PopoverTrigger>
|
||||
<PopoverContent
|
||||
className="p-0"
|
||||
align="center"
|
||||
className={cn(
|
||||
"flex max-h-[60vh] flex-col p-0",
|
||||
popoverContentClassName,
|
||||
)}
|
||||
align={props.align}
|
||||
side={props.side}
|
||||
sideOffset={10}
|
||||
onEscapeKeyDown={() => setIsPopoverOpen(false)}
|
||||
style={{
|
||||
width: "var(--radix-popover-trigger-width)",
|
||||
maxHeight: "var(--radix-popover-content-available-height)",
|
||||
height:
|
||||
"calc(var(--radix-popover-content-available-height) - 40px)",
|
||||
}}
|
||||
ref={popoverElRef}
|
||||
>
|
||||
<div>
|
||||
{/* Search */}
|
||||
<div className="relative">
|
||||
<Input
|
||||
placeholder={searchPlaceholder || "Search"}
|
||||
value={searchValue}
|
||||
onChange={(e) => setSearchValue(e.target.value)}
|
||||
className="!h-auto rounded-b-none border-0 border-border border-b py-4 pl-10 focus-visible:ring-0 focus-visible:ring-offset-0"
|
||||
onKeyDown={handleInputKeyDown}
|
||||
/>
|
||||
<SearchIcon className="-translate-y-1/2 absolute top-1/2 left-4 size-4 text-muted-foreground" />
|
||||
</div>
|
||||
{/* Search */}
|
||||
<div className="relative">
|
||||
<Input
|
||||
placeholder={searchPlaceholder || "Search"}
|
||||
value={searchValue}
|
||||
onChange={(e) => setSearchValue(e.target.value)}
|
||||
className="!h-auto rounded-b-none border-0 border-border border-b py-4 pl-10 focus-visible:ring-0 focus-visible:ring-offset-0"
|
||||
onKeyDown={handleInputKeyDown}
|
||||
/>
|
||||
<SearchIcon className="-translate-y-1/2 absolute top-1/2 left-4 size-4 text-muted-foreground" />
|
||||
</div>
|
||||
|
||||
{optionsToShow.length === 0 && (
|
||||
<div className="flex flex-1 flex-col items-center justify-center py-10 text-sm">
|
||||
No results found
|
||||
</div>
|
||||
)}
|
||||
|
||||
{optionsToShow.length > 0 && (
|
||||
<ScrollShadow
|
||||
scrollableClassName="max-h-[min(calc(var(--radix-popover-content-available-height)-60px),350px)] p-1"
|
||||
className="rounded"
|
||||
scrollableClassName="p-1 h-full"
|
||||
className="flex-1 rounded"
|
||||
>
|
||||
{/* List */}
|
||||
<div>
|
||||
{optionsToShow.length === 0 && (
|
||||
<div className="flex justify-center py-10">
|
||||
No results found
|
||||
</div>
|
||||
)}
|
||||
|
||||
{optionsToShow.map((option, i) => {
|
||||
const isSelected = selectedValues.includes(option.value);
|
||||
return (
|
||||
@@ -293,7 +289,20 @@ export const MultiSelect = forwardRef<HTMLButtonElement, MultiSelectProps>(
|
||||
})}
|
||||
</div>
|
||||
</ScrollShadow>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{showSelectedValuesInModal && selectedValues.length > 0 && (
|
||||
<div className="border-t px-3 py-3">
|
||||
<SelectedChainsBadges
|
||||
selectedValues={selectedValues}
|
||||
options={options}
|
||||
maxCount={maxCount}
|
||||
onClose={handleClear}
|
||||
toggleOption={toggleOption}
|
||||
clearExtraOptions={clearExtraOptions}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
</PopoverContent>
|
||||
</Popover>
|
||||
);
|
||||
@@ -319,3 +328,44 @@ function ClosableBadge(props: {
|
||||
}
|
||||
|
||||
MultiSelect.displayName = "MultiSelect";
|
||||
|
||||
function SelectedChainsBadges(props: {
|
||||
selectedValues: string[];
|
||||
options: {
|
||||
label: string;
|
||||
value: string;
|
||||
}[];
|
||||
maxCount: number;
|
||||
onClose: () => void;
|
||||
toggleOption: (value: string) => void;
|
||||
clearExtraOptions: () => void;
|
||||
}) {
|
||||
const { selectedValues, options, maxCount, toggleOption, clearExtraOptions } =
|
||||
props;
|
||||
return (
|
||||
<div className="flex flex-wrap items-center gap-1.5">
|
||||
{selectedValues.slice(0, maxCount).map((value) => {
|
||||
const option = options.find((o) => o.value === value);
|
||||
if (!option) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<ClosableBadge
|
||||
key={value}
|
||||
label={option.label}
|
||||
onClose={() => toggleOption(value)}
|
||||
/>
|
||||
);
|
||||
})}
|
||||
|
||||
{/* +X more */}
|
||||
{selectedValues.length > maxCount && (
|
||||
<ClosableBadge
|
||||
label={`+ ${selectedValues.length - maxCount} more`}
|
||||
onClose={clearExtraOptions}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -24,11 +24,7 @@ const TableHeader = React.forwardRef<
|
||||
>(({ className, ...props }, ref) => (
|
||||
<thead
|
||||
ref={ref}
|
||||
className={cn(
|
||||
"border-border border-b bg-background",
|
||||
"sticky top-0 z-20 border-none before:absolute before:inset-0 before:border-border before:border-b",
|
||||
className,
|
||||
)}
|
||||
className={cn("relative border-b bg-background", className)}
|
||||
{...props}
|
||||
/>
|
||||
));
|
||||
|
||||
@@ -2,12 +2,16 @@ import { useQuery } from "@tanstack/react-query";
|
||||
import { useMemo } from "react";
|
||||
import { useActiveAccount } from "thirdweb/react";
|
||||
import type { GetAuthTokenResponse } from "../../app/api/auth/get-auth-token/route";
|
||||
import { LAST_USED_TEAM_ID } from "../../constants/cookies";
|
||||
import { getCookie } from "../../lib/cookie";
|
||||
import { getThirdwebClient } from "./thirdweb.server";
|
||||
|
||||
// returns a thirdweb client with optional JWT passed i
|
||||
|
||||
export function useThirdwebClient(jwt?: string) {
|
||||
const account = useActiveAccount();
|
||||
const lastUsedTeamId = getCookie(LAST_USED_TEAM_ID);
|
||||
|
||||
const query = useQuery({
|
||||
queryKey: ["jwt", account?.address],
|
||||
// only enable the query if there is an account and no JWT is passed in directly
|
||||
@@ -33,8 +37,12 @@ export function useThirdwebClient(jwt?: string) {
|
||||
|
||||
return useMemo(
|
||||
// prefer jwt from props over the one from the token query if it exists
|
||||
() => getThirdwebClient(jwt || query.data),
|
||||
[jwt, query.data],
|
||||
() =>
|
||||
getThirdwebClient({
|
||||
jwt: jwt || query.data,
|
||||
teamId: lastUsedTeamId,
|
||||
}),
|
||||
[jwt, query.data, lastUsedTeamId],
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -23,7 +23,14 @@ import { getZkPaymasterData } from "thirdweb/wallets/smart";
|
||||
import { getVercelEnv } from "../../lib/vercel-utils";
|
||||
|
||||
// returns a thirdweb client with optional JWT passed in
|
||||
export function getThirdwebClient(jwt?: string) {
|
||||
export function getThirdwebClient(
|
||||
options:
|
||||
| {
|
||||
jwt: string | null | undefined;
|
||||
teamId: string | undefined;
|
||||
}
|
||||
| undefined,
|
||||
) {
|
||||
if (getVercelEnv() !== "production") {
|
||||
// if not on production: run this when creating a client to set the domains
|
||||
setThirdwebDomains({
|
||||
@@ -71,7 +78,8 @@ export function getThirdwebClient(jwt?: string) {
|
||||
}
|
||||
|
||||
return createThirdwebClient({
|
||||
secretKey: jwt ? jwt : DASHBOARD_THIRDWEB_SECRET_KEY,
|
||||
teamId: options?.teamId,
|
||||
secretKey: options?.jwt ? options.jwt : DASHBOARD_THIRDWEB_SECRET_KEY,
|
||||
clientId: DASHBOARD_THIRDWEB_CLIENT_ID,
|
||||
config: {
|
||||
storage: {
|
||||
|
||||
@@ -175,6 +175,7 @@ export const CustomConnectWallet = (props: {
|
||||
renderChain(props) {
|
||||
return (
|
||||
<CustomChainRenderer
|
||||
client={thirdwebClient}
|
||||
{...props}
|
||||
openEditChainModal={(c) => {
|
||||
setIsNetworkConfigModalOpen(true);
|
||||
|
||||
+7
-3
@@ -1,17 +1,21 @@
|
||||
"use client";
|
||||
import { getThirdwebClient } from "@/constants/thirdweb.server";
|
||||
|
||||
import { getSDKTheme } from "app/components/sdk-component-theme";
|
||||
import { useV5DashboardChain } from "lib/v5-adapter";
|
||||
import { useTheme } from "next-themes";
|
||||
import type { ThirdwebClient } from "thirdweb";
|
||||
import { PayEmbed } from "thirdweb/react";
|
||||
|
||||
export function UniversalBridgeEmbed({ chainId }: { chainId?: number }) {
|
||||
export function UniversalBridgeEmbed({
|
||||
chainId,
|
||||
client,
|
||||
}: { chainId?: number; client: ThirdwebClient }) {
|
||||
const { theme } = useTheme();
|
||||
const chain = useV5DashboardChain(chainId || 1);
|
||||
|
||||
return (
|
||||
<PayEmbed
|
||||
client={getThirdwebClient()}
|
||||
client={client}
|
||||
payOptions={{
|
||||
mode: "fund_wallet",
|
||||
prefillBuy: {
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import { getThirdwebClient } from "@/constants/thirdweb.server";
|
||||
import type { Metadata } from "next";
|
||||
import { UniversalBridgeEmbed } from "./components/client/UniversalBridgeEmbed";
|
||||
|
||||
@@ -18,10 +19,14 @@ export default async function RoutesPage({
|
||||
searchParams,
|
||||
}: { searchParams: Record<string, string | string[]> }) {
|
||||
const { chainId } = searchParams;
|
||||
const client = getThirdwebClient(undefined);
|
||||
return (
|
||||
<div className="relative mx-auto flex h-screen w-full flex-col items-center justify-center overflow-hidden border py-10">
|
||||
<main className="container z-10 flex justify-center">
|
||||
<UniversalBridgeEmbed chainId={chainId ? Number(chainId) : undefined} />
|
||||
<UniversalBridgeEmbed
|
||||
chainId={chainId ? Number(chainId) : undefined}
|
||||
client={client}
|
||||
/>
|
||||
</main>
|
||||
|
||||
{/* eslint-disable-next-line @next/next/no-img-element */}
|
||||
|
||||
+5
-3
@@ -1,6 +1,6 @@
|
||||
import { Card, CardContent, CardHeader } from "@/components/ui/card";
|
||||
import { getThirdwebClient } from "@/constants/thirdweb.server";
|
||||
import { resolveSchemeWithErrorHandler } from "@/lib/resolveSchemeWithErrorHandler";
|
||||
import type { ThirdwebClient } from "thirdweb";
|
||||
import { defineChain } from "thirdweb";
|
||||
import { getChainMetadata } from "thirdweb/chains";
|
||||
|
||||
@@ -15,6 +15,7 @@ type RouteListCardProps = {
|
||||
destinationTokenIconUri?: string | null;
|
||||
destinationTokenSymbol: string;
|
||||
destinationTokenName: string;
|
||||
client: ThirdwebClient;
|
||||
};
|
||||
|
||||
export async function RouteListCard({
|
||||
@@ -26,6 +27,7 @@ export async function RouteListCard({
|
||||
destinationTokenAddress,
|
||||
destinationTokenIconUri,
|
||||
destinationTokenName,
|
||||
client,
|
||||
}: RouteListCardProps) {
|
||||
const [
|
||||
originChain,
|
||||
@@ -40,13 +42,13 @@ export async function RouteListCard({
|
||||
originTokenIconUri
|
||||
? resolveSchemeWithErrorHandler({
|
||||
uri: originTokenIconUri,
|
||||
client: getThirdwebClient(),
|
||||
client,
|
||||
})
|
||||
: undefined,
|
||||
destinationTokenIconUri
|
||||
? resolveSchemeWithErrorHandler({
|
||||
uri: destinationTokenIconUri,
|
||||
client: getThirdwebClient(),
|
||||
client,
|
||||
})
|
||||
: undefined,
|
||||
]);
|
||||
|
||||
+5
-3
@@ -1,7 +1,7 @@
|
||||
import { CopyTextButton } from "@/components/ui/CopyTextButton";
|
||||
import { TableCell, TableRow } from "@/components/ui/table";
|
||||
import { getThirdwebClient } from "@/constants/thirdweb.server";
|
||||
import { resolveSchemeWithErrorHandler } from "@/lib/resolveSchemeWithErrorHandler";
|
||||
import type { ThirdwebClient } from "thirdweb";
|
||||
import { defineChain, getChainMetadata } from "thirdweb/chains";
|
||||
|
||||
type RouteListRowProps = {
|
||||
@@ -15,6 +15,7 @@ type RouteListRowProps = {
|
||||
destinationTokenIconUri?: string | null;
|
||||
destinationTokenSymbol?: string;
|
||||
destinationTokenName?: string;
|
||||
client: ThirdwebClient;
|
||||
};
|
||||
|
||||
export async function RouteListRow({
|
||||
@@ -26,6 +27,7 @@ export async function RouteListRow({
|
||||
destinationTokenAddress,
|
||||
destinationTokenIconUri,
|
||||
destinationTokenSymbol,
|
||||
client,
|
||||
}: RouteListRowProps) {
|
||||
const [
|
||||
originChain,
|
||||
@@ -40,13 +42,13 @@ export async function RouteListRow({
|
||||
originTokenIconUri
|
||||
? resolveSchemeWithErrorHandler({
|
||||
uri: originTokenIconUri,
|
||||
client: getThirdwebClient(),
|
||||
client,
|
||||
})
|
||||
: undefined,
|
||||
destinationTokenIconUri
|
||||
? resolveSchemeWithErrorHandler({
|
||||
uri: destinationTokenIconUri,
|
||||
client: getThirdwebClient(),
|
||||
client,
|
||||
})
|
||||
: undefined,
|
||||
]);
|
||||
|
||||
@@ -6,6 +6,7 @@ import {
|
||||
TableHeader,
|
||||
TableRow,
|
||||
} from "@/components/ui/table";
|
||||
import { getThirdwebClient } from "@/constants/thirdweb.server";
|
||||
import type { Address } from "thirdweb";
|
||||
import { checksumAddress } from "thirdweb/utils";
|
||||
import { getRoutes } from "../../../utils";
|
||||
@@ -136,6 +137,7 @@ export async function RoutesData(props: {
|
||||
const startIndex = (activePage - 1) * pageSize;
|
||||
const endIndex = startIndex + pageSize;
|
||||
const paginatedRoutes = routesToRender.slice(startIndex, endIndex);
|
||||
const client = getThirdwebClient(undefined);
|
||||
|
||||
return (
|
||||
<>
|
||||
@@ -170,6 +172,7 @@ export async function RoutesData(props: {
|
||||
destinationTokenIconUri={route.destinationToken.iconUri}
|
||||
destinationTokenSymbol={route.destinationToken.symbol}
|
||||
destinationTokenName={route.destinationToken.name}
|
||||
client={client}
|
||||
/>
|
||||
))}
|
||||
</TableBody>
|
||||
@@ -193,6 +196,7 @@ export async function RoutesData(props: {
|
||||
destinationTokenIconUri={route.destinationToken.iconUri}
|
||||
destinationTokenSymbol={route.destinationToken.symbol}
|
||||
destinationTokenName={route.destinationToken.name}
|
||||
client={client}
|
||||
/>
|
||||
</li>
|
||||
))}
|
||||
|
||||
+4
-20
@@ -25,7 +25,6 @@ import {
|
||||
} from "@/constants/env";
|
||||
import { useThirdwebClient } from "@/constants/thirdweb.client";
|
||||
import { CustomConnectWallet } from "@3rdweb-sdk/react/components/connect-wallet";
|
||||
import type { Account } from "@3rdweb-sdk/react/hooks/useApi";
|
||||
import { zodResolver } from "@hookform/resolvers/zod";
|
||||
import { Turnstile } from "@marsidev/react-turnstile";
|
||||
import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
|
||||
@@ -52,7 +51,6 @@ import {
|
||||
useWalletBalance,
|
||||
} from "thirdweb/react";
|
||||
import { z } from "zod";
|
||||
import { isAccountOnboardingComplete } from "../../../../../../login/onboarding/isOnboardingRequired";
|
||||
|
||||
function formatTime(seconds: number) {
|
||||
const rtf = new Intl.RelativeTimeFormat("en", { numeric: "auto" });
|
||||
@@ -78,11 +76,11 @@ const claimFaucetSchema = z.object({
|
||||
export function FaucetButton({
|
||||
chain,
|
||||
amount,
|
||||
twAccount,
|
||||
isLoggedIn,
|
||||
}: {
|
||||
chain: ChainMetadata;
|
||||
amount: number;
|
||||
twAccount: Account | undefined;
|
||||
isLoggedIn: boolean;
|
||||
}) {
|
||||
const pathname = usePathname();
|
||||
const client = useThirdwebClient();
|
||||
@@ -186,7 +184,7 @@ export function FaucetButton({
|
||||
</div>
|
||||
<SendFundsToFaucetModalButton
|
||||
chain={definedChain}
|
||||
isLoggedIn={!!twAccount}
|
||||
isLoggedIn={isLoggedIn}
|
||||
client={client}
|
||||
chainMeta={chain}
|
||||
onFaucetRefill={() => {
|
||||
@@ -198,7 +196,7 @@ export function FaucetButton({
|
||||
}
|
||||
|
||||
// Force users to log in to claim the faucet
|
||||
if (!address || !twAccount) {
|
||||
if (!address || !isLoggedIn) {
|
||||
return (
|
||||
<Button variant="primary" className="w-full" asChild>
|
||||
<Link
|
||||
@@ -210,20 +208,6 @@ export function FaucetButton({
|
||||
);
|
||||
}
|
||||
|
||||
if (!isAccountOnboardingComplete(twAccount)) {
|
||||
return (
|
||||
<Button asChild className="w-full">
|
||||
<Link
|
||||
href={
|
||||
pathname ? `/login?next=${encodeURIComponent(pathname)}` : "/login"
|
||||
}
|
||||
>
|
||||
Verify your Email
|
||||
</Link>
|
||||
</Button>
|
||||
);
|
||||
}
|
||||
|
||||
// Can not claim
|
||||
if (canClaimFaucetQuery.data && canClaimFaucetQuery.data.canClaim === false) {
|
||||
return (
|
||||
|
||||
+6
-1
@@ -1,12 +1,16 @@
|
||||
import { ExternalLinkIcon } from "lucide-react";
|
||||
import Link from "next/link";
|
||||
import type { ThirdwebClient } from "thirdweb";
|
||||
import type { ChainMetadata } from "thirdweb/chains";
|
||||
import { ChainIcon } from "../../../../components/server/chain-icon";
|
||||
import { PayModalButton } from "../client/PayModal";
|
||||
import { CreditCardIcon } from "../icons/CreditCardIcon";
|
||||
import { SectionTitle } from "./SectionTitle";
|
||||
|
||||
export function BuyFundsSection(props: { chain: ChainMetadata }) {
|
||||
export function BuyFundsSection(props: {
|
||||
chain: ChainMetadata;
|
||||
client: ThirdwebClient;
|
||||
}) {
|
||||
const sanitizedChainName = props.chain.name.replace("Mainnet", "").trim();
|
||||
|
||||
return (
|
||||
@@ -18,6 +22,7 @@ export function BuyFundsSection(props: { chain: ChainMetadata }) {
|
||||
<ChainIcon
|
||||
className="-mr-2 size-12 rounded-full border p-1"
|
||||
iconUrl={props.chain.icon?.url}
|
||||
client={props.client}
|
||||
/>
|
||||
<CreditCardIcon
|
||||
bg="hsl(var(--background))"
|
||||
|
||||
+6
-4
@@ -1,4 +1,4 @@
|
||||
import type { Account } from "@3rdweb-sdk/react/hooks/useApi";
|
||||
import type { ThirdwebClient } from "thirdweb";
|
||||
import type { ChainMetadata } from "thirdweb/chains";
|
||||
import { getFaucetClaimAmount } from "../../../../../../api/testnet-faucet/claim/claim-amount";
|
||||
import { ChainIcon } from "../../../../components/server/chain-icon";
|
||||
@@ -8,9 +8,10 @@ import { SectionTitle } from "./SectionTitle";
|
||||
|
||||
export async function FaucetSection(props: {
|
||||
chain: ChainMetadata;
|
||||
twAccount: Account | undefined;
|
||||
isLoggedIn: boolean;
|
||||
client: ThirdwebClient;
|
||||
}) {
|
||||
const { chain, twAccount } = props;
|
||||
const { chain, isLoggedIn, client } = props;
|
||||
|
||||
// Check eligibility.
|
||||
const sanitizedChainName = chain.name.replace("Mainnet", "").trim();
|
||||
@@ -25,6 +26,7 @@ export async function FaucetSection(props: {
|
||||
<ChainIcon
|
||||
className="-mr-2 size-12 rounded-full border p-1"
|
||||
iconUrl={props.chain.icon?.url}
|
||||
client={client}
|
||||
/>
|
||||
<GiftIcon bg="hsl(var(--background))" className="-ml-2 size-12" />
|
||||
</div>
|
||||
@@ -47,7 +49,7 @@ export async function FaucetSection(props: {
|
||||
<FaucetButton
|
||||
chain={chain}
|
||||
amount={amountToGive}
|
||||
twAccount={twAccount}
|
||||
isLoggedIn={isLoggedIn}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
+3
@@ -1,6 +1,7 @@
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { cn } from "@/lib/utils";
|
||||
import Link from "next/link";
|
||||
import type { ThirdwebClient } from "thirdweb";
|
||||
import type { ChainMetadata } from "thirdweb/chains";
|
||||
import { mapV4ChainToV5Chain } from "../../../../../../../contexts/map-chains";
|
||||
import { ChainIcon } from "../../../../components/server/chain-icon";
|
||||
@@ -10,6 +11,7 @@ type ChainHeaderProps = {
|
||||
headerImageUrl?: string;
|
||||
logoUrl?: string;
|
||||
chain: ChainMetadata;
|
||||
client: ThirdwebClient;
|
||||
};
|
||||
|
||||
// TODO: improve the behavior when clicking "Get started with thirdweb", currently just redirects to the dashboard
|
||||
@@ -39,6 +41,7 @@ export function ChainHeader(props: ChainHeaderProps) {
|
||||
{/* chain logo */}
|
||||
|
||||
<ChainIcon
|
||||
client={props.client}
|
||||
iconUrl={props.logoUrl}
|
||||
className={cn(
|
||||
"-translate-y-[50%] absolute top-0 left-0 size-20 overflow-hidden rounded-full border border-border bg-muted p-2 lg:size-36 lg:p-4",
|
||||
|
||||
@@ -13,13 +13,12 @@ import {
|
||||
DropdownMenuItem,
|
||||
DropdownMenuTrigger,
|
||||
} from "@/components/ui/dropdown-menu";
|
||||
import { getThirdwebClient } from "@/constants/thirdweb.server";
|
||||
import { ChevronDownIcon, TicketCheckIcon } from "lucide-react";
|
||||
import type { Metadata } from "next";
|
||||
import Link from "next/link";
|
||||
import { redirect } from "next/navigation";
|
||||
import { getThirdwebClient } from "../../../../../@/constants/thirdweb.server";
|
||||
import { mapV4ChainToV5Chain } from "../../../../../contexts/map-chains";
|
||||
import { getRawAccount } from "../../../../account/settings/getAccount";
|
||||
import {
|
||||
getAuthToken,
|
||||
getAuthTokenWalletAddress,
|
||||
@@ -61,10 +60,9 @@ export default async function ChainPageLayout(props: {
|
||||
}) {
|
||||
const params = await props.params;
|
||||
const { children } = props;
|
||||
const [chain, authToken, account, accountAddress] = await Promise.all([
|
||||
const [chain, authToken, accountAddress] = await Promise.all([
|
||||
getChain(params.chain_id),
|
||||
getAuthToken(),
|
||||
getRawAccount(),
|
||||
getAuthTokenWalletAddress(),
|
||||
]);
|
||||
|
||||
@@ -73,7 +71,10 @@ export default async function ChainPageLayout(props: {
|
||||
}
|
||||
|
||||
const chainMetadata = await getChainMetadata(chain.chainId);
|
||||
const client = getThirdwebClient(authToken ?? undefined);
|
||||
const client = getThirdwebClient({
|
||||
jwt: authToken,
|
||||
teamId: undefined,
|
||||
});
|
||||
|
||||
const chainPromptPrefix = `\
|
||||
You are assisting users exploring the chain ${chain.name} (Chain ID: ${chain.chainId}). Provide concise insights into the types of applications and activities prevalent on this chain, such as DeFi protocols, NFT marketplaces, or gaming platforms. Highlight notable projects or trends without delving into technical details like consensus mechanisms or gas fees.
|
||||
@@ -99,8 +100,8 @@ The following is the user's message:
|
||||
return (
|
||||
<>
|
||||
<NebulaFloatingChatButton
|
||||
pageType="chain"
|
||||
authToken={authToken ?? undefined}
|
||||
account={account}
|
||||
label="Ask AI about this chain"
|
||||
client={client}
|
||||
nebulaParams={{
|
||||
@@ -160,6 +161,7 @@ The following is the user's message:
|
||||
headerImageUrl={chainMetadata?.headerImgUrl}
|
||||
logoUrl={chain.icon?.url}
|
||||
chain={chain}
|
||||
client={client}
|
||||
/>
|
||||
|
||||
<div className="h-4 md:h-8" />
|
||||
|
||||
+4
-3
@@ -77,9 +77,10 @@ export default async function Image({
|
||||
),
|
||||
// download the chain icon if there is one
|
||||
chain.icon?.url && hasWorkingChainIcon
|
||||
? download({ uri: chain.icon.url, client: getThirdwebClient() }).then(
|
||||
(res) => res.arrayBuffer(),
|
||||
)
|
||||
? download({
|
||||
uri: chain.icon.url,
|
||||
client: getThirdwebClient(undefined),
|
||||
}).then((res) => res.arrayBuffer())
|
||||
: undefined,
|
||||
// download the background image (based on chain)
|
||||
fetch(
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { CircleAlertIcon } from "lucide-react";
|
||||
import { getRawAccount } from "../../../../account/settings/getAccount";
|
||||
import { getUserThirdwebClient } from "../../../../api/lib/getAuthToken";
|
||||
import { getChain, getChainMetadata } from "../../utils";
|
||||
import NextSteps from "./components/client/NextSteps";
|
||||
import { BuyFundsSection } from "./components/server/BuyFundsSection";
|
||||
@@ -18,6 +19,7 @@ export default async function Page(props: {
|
||||
const chainMetadata = await getChainMetadata(chain.chainId);
|
||||
const isDeprecated = chain.status === "deprecated";
|
||||
|
||||
const client = await getUserThirdwebClient();
|
||||
const account = await getRawAccount();
|
||||
|
||||
return (
|
||||
@@ -42,9 +44,9 @@ export default async function Page(props: {
|
||||
|
||||
{/* Faucet / Buy Funds */}
|
||||
{chain.testnet ? (
|
||||
<FaucetSection chain={chain} twAccount={account} />
|
||||
<FaucetSection chain={chain} isLoggedIn={!!account} client={client} />
|
||||
) : chain.services.find((c) => c.service === "pay" && c.enabled) ? (
|
||||
<BuyFundsSection chain={chain} />
|
||||
<BuyFundsSection chain={chain} client={client} />
|
||||
) : null}
|
||||
|
||||
{/* Chain Overview */}
|
||||
|
||||
+3
-5
@@ -1,6 +1,4 @@
|
||||
"use client";
|
||||
|
||||
import type { Account } from "@3rdweb-sdk/react/hooks/useApi";
|
||||
import { TransactionButton } from "components/buttons/TransactionButton";
|
||||
import { useTrack } from "hooks/analytics/useTrack";
|
||||
import { useAllChainsData } from "hooks/chains/allChains";
|
||||
@@ -13,14 +11,14 @@ interface CancelTabProps {
|
||||
id: string;
|
||||
contract: ThirdwebContract;
|
||||
isAuction?: boolean;
|
||||
twAccount: Account | undefined;
|
||||
isLoggedIn: boolean;
|
||||
}
|
||||
|
||||
export const CancelTab: React.FC<CancelTabProps> = ({
|
||||
id,
|
||||
contract,
|
||||
isAuction,
|
||||
twAccount,
|
||||
isLoggedIn,
|
||||
}) => {
|
||||
const trackEvent = useTrack();
|
||||
const { idToChain } = useAllChainsData();
|
||||
@@ -32,7 +30,7 @@ export const CancelTab: React.FC<CancelTabProps> = ({
|
||||
return (
|
||||
<div className="flex flex-col gap-3 pt-3">
|
||||
<TransactionButton
|
||||
twAccount={twAccount}
|
||||
isLoggedIn={isLoggedIn}
|
||||
txChainID={contract.chain.id}
|
||||
transactionCount={1}
|
||||
isPending={cancelQuery.isPending}
|
||||
|
||||
+6
-7
@@ -10,20 +10,19 @@ import {
|
||||
} from "@/components/ui/sheet";
|
||||
import { TabButtons } from "@/components/ui/tabs";
|
||||
import { ListerOnly } from "@3rdweb-sdk/react/components/roles/lister-only";
|
||||
import type { Account } from "@3rdweb-sdk/react/hooks/useApi";
|
||||
import { isAlchemySupported } from "lib/wallet/nfts/alchemy";
|
||||
import { isMoralisSupported } from "lib/wallet/nfts/moralis";
|
||||
import { PlusIcon } from "lucide-react";
|
||||
import { useState } from "react";
|
||||
import type { ThirdwebContract } from "thirdweb";
|
||||
import { useActiveAccount } from "thirdweb/react";
|
||||
import { isAlchemySupported } from "../../../../../../../lib/wallet/nfts/isAlchemySupported";
|
||||
import { isMoralisSupported } from "../../../../../../../lib/wallet/nfts/isMoralisSupported";
|
||||
import { CreateListingsForm } from "./list-form";
|
||||
|
||||
interface CreateListingButtonProps {
|
||||
contract: ThirdwebContract;
|
||||
createText?: string;
|
||||
type?: "direct-listings" | "english-auctions";
|
||||
twAccount: Account | undefined;
|
||||
isLoggedIn: boolean;
|
||||
isInsightSupported: boolean;
|
||||
}
|
||||
|
||||
@@ -33,7 +32,7 @@ export const CreateListingButton: React.FC<CreateListingButtonProps> = ({
|
||||
createText = "Create",
|
||||
type,
|
||||
contract,
|
||||
twAccount,
|
||||
isLoggedIn,
|
||||
isInsightSupported,
|
||||
...restButtonProps
|
||||
}) => {
|
||||
@@ -77,7 +76,7 @@ export const CreateListingButton: React.FC<CreateListingButtonProps> = ({
|
||||
/>
|
||||
<div className="mt-5">
|
||||
<CreateListingsForm
|
||||
twAccount={twAccount}
|
||||
isLoggedIn={isLoggedIn}
|
||||
contract={contract}
|
||||
type={type}
|
||||
actionText={createText}
|
||||
@@ -90,7 +89,7 @@ export const CreateListingButton: React.FC<CreateListingButtonProps> = ({
|
||||
) : (
|
||||
<div className="mt-5">
|
||||
<CreateListingsForm
|
||||
twAccount={twAccount}
|
||||
isLoggedIn={isLoggedIn}
|
||||
contract={contract}
|
||||
type={type}
|
||||
actionText={createText}
|
||||
|
||||
+5
-6
@@ -1,7 +1,6 @@
|
||||
import { Alert, AlertTitle } from "@/components/ui/alert";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { Card } from "@/components/ui/card";
|
||||
import type { Account } from "@3rdweb-sdk/react/hooks/useApi";
|
||||
import { useDashboardOwnedNFTs } from "@3rdweb-sdk/react/hooks/useDashboardOwnedNFTs";
|
||||
import { useWalletNFTs } from "@3rdweb-sdk/react/hooks/useWalletNFTs";
|
||||
import {
|
||||
@@ -19,8 +18,6 @@ import { SolidityInput } from "contract-ui/components/solidity-inputs";
|
||||
import { useTrack } from "hooks/analytics/useTrack";
|
||||
import { useAllChainsData } from "hooks/chains/allChains";
|
||||
import { useTxNotifications } from "hooks/useTxNotifications";
|
||||
import { isAlchemySupported } from "lib/wallet/nfts/alchemy";
|
||||
import { isMoralisSupported } from "lib/wallet/nfts/moralis";
|
||||
import type { WalletNFT } from "lib/wallet/nfts/types";
|
||||
import { CircleAlertIcon, InfoIcon } from "lucide-react";
|
||||
import Link from "next/link";
|
||||
@@ -57,6 +54,8 @@ import { shortenAddress } from "thirdweb/utils";
|
||||
import { FormErrorMessage, FormHelperText, FormLabel } from "tw-components";
|
||||
import { NFTMediaWithEmptyState } from "tw-components/nft-media";
|
||||
import { shortenIfAddress } from "utils/usedapp-external";
|
||||
import { isAlchemySupported } from "../../../../../../../lib/wallet/nfts/isAlchemySupported";
|
||||
import { isMoralisSupported } from "../../../../../../../lib/wallet/nfts/isMoralisSupported";
|
||||
|
||||
const LIST_FORM_ID = "marketplace-list-form";
|
||||
|
||||
@@ -85,7 +84,7 @@ type CreateListingsFormProps = {
|
||||
setOpen: Dispatch<SetStateAction<boolean>>;
|
||||
mode: "automatic" | "manual";
|
||||
type?: "direct-listings" | "english-auctions";
|
||||
twAccount: Account | undefined;
|
||||
isLoggedIn: boolean;
|
||||
isInsightSupported: boolean;
|
||||
};
|
||||
|
||||
@@ -104,7 +103,7 @@ export const CreateListingsForm: React.FC<CreateListingsFormProps> = ({
|
||||
type,
|
||||
actionText,
|
||||
setOpen,
|
||||
twAccount,
|
||||
isLoggedIn,
|
||||
mode,
|
||||
isInsightSupported,
|
||||
}) => {
|
||||
@@ -659,7 +658,7 @@ export const CreateListingsForm: React.FC<CreateListingsFormProps> = ({
|
||||
Cancel
|
||||
</Button>
|
||||
<TransactionButton
|
||||
twAccount={twAccount}
|
||||
isLoggedIn={isLoggedIn}
|
||||
txChainID={contract.chain.id}
|
||||
isPending={isFormLoading}
|
||||
transactionCount={2}
|
||||
|
||||
+5
-7
@@ -3,18 +3,16 @@ import { CopyAddressButton } from "@/components/ui/CopyAddressButton";
|
||||
import { CopyTextButton } from "@/components/ui/CopyTextButton";
|
||||
import { Badge } from "@/components/ui/badge";
|
||||
import { Card } from "@/components/ui/card";
|
||||
import { CodeClient } from "@/components/ui/code/code.client";
|
||||
import { Sheet, SheetContent } from "@/components/ui/sheet";
|
||||
import { Flex, GridItem, SimpleGrid, usePrevious } from "@chakra-ui/react";
|
||||
import { toast } from "sonner";
|
||||
import type { ThirdwebContract } from "thirdweb";
|
||||
import type {
|
||||
DirectListing,
|
||||
EnglishAuction,
|
||||
} from "thirdweb/extensions/marketplace";
|
||||
import { BuyDirectListingButton, useActiveAccount } from "thirdweb/react";
|
||||
|
||||
import { CodeClient } from "@/components/ui/code/code.client";
|
||||
import type { Account } from "@3rdweb-sdk/react/hooks/useApi";
|
||||
import { toast } from "sonner";
|
||||
import { NFTMediaWithEmptyState } from "tw-components/nft-media";
|
||||
import { CancelTab } from "./cancel-tab";
|
||||
import { LISTING_STATUS } from "./types";
|
||||
@@ -24,7 +22,7 @@ interface NFTDrawerProps {
|
||||
isOpen: boolean;
|
||||
onClose: () => void;
|
||||
data: DirectListing | EnglishAuction | null;
|
||||
twAccount: Account | undefined;
|
||||
isLoggedIn: boolean;
|
||||
}
|
||||
|
||||
export const ListingDrawer: React.FC<NFTDrawerProps> = ({
|
||||
@@ -32,7 +30,7 @@ export const ListingDrawer: React.FC<NFTDrawerProps> = ({
|
||||
isOpen,
|
||||
onClose,
|
||||
data,
|
||||
twAccount,
|
||||
isLoggedIn,
|
||||
}) => {
|
||||
const address = useActiveAccount()?.address;
|
||||
const prevData = usePrevious(data);
|
||||
@@ -161,7 +159,7 @@ export const ListingDrawer: React.FC<NFTDrawerProps> = ({
|
||||
contract={contract}
|
||||
id={renderData.id.toString()}
|
||||
isAuction={renderData.type === "english-auction"}
|
||||
twAccount={twAccount}
|
||||
isLoggedIn={isLoggedIn}
|
||||
/>
|
||||
)}
|
||||
|
||||
|
||||
+3
-4
@@ -1,6 +1,5 @@
|
||||
import { WalletAddress } from "@/components/blocks/wallet-address";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import type { Account } from "@3rdweb-sdk/react/hooks/useApi";
|
||||
import {
|
||||
IconButton,
|
||||
Select,
|
||||
@@ -99,7 +98,7 @@ interface MarketplaceTableProps {
|
||||
start: number;
|
||||
}>
|
||||
>;
|
||||
twAccount: Account | undefined;
|
||||
isLoggedIn: boolean;
|
||||
}
|
||||
|
||||
const DEFAULT_QUERY_STATE = { count: 50, start: 0 };
|
||||
@@ -111,7 +110,7 @@ export const MarketplaceTable: React.FC<MarketplaceTableProps> = ({
|
||||
totalCountQuery,
|
||||
queryParams,
|
||||
setQueryParams,
|
||||
twAccount,
|
||||
isLoggedIn,
|
||||
}) => {
|
||||
const [listingsToShow, setListingsToShow_] = useState<"all" | "valid">("all");
|
||||
|
||||
@@ -216,7 +215,7 @@ export const MarketplaceTable: React.FC<MarketplaceTableProps> = ({
|
||||
data={tokenRow}
|
||||
isOpen={!!tokenRow}
|
||||
onClose={() => setTokenRow(null)}
|
||||
twAccount={twAccount}
|
||||
isLoggedIn={isLoggedIn}
|
||||
/>
|
||||
<Table {...getTableProps()}>
|
||||
<Thead>
|
||||
|
||||
+2
-3
@@ -1,6 +1,5 @@
|
||||
"use client";
|
||||
|
||||
import type { Account } from "@3rdweb-sdk/react/hooks/useApi";
|
||||
import type { ThirdwebContract } from "thirdweb";
|
||||
import { ErrorPage, LoadingPage } from "../../_components/page-skeletons";
|
||||
import { RedirectToContractOverview } from "../../_components/redirect-contract-overview.client";
|
||||
@@ -9,7 +8,7 @@ import { ContractDirectListingsPage } from "./ContractDirectListingsPage";
|
||||
|
||||
export function ContractDirectListingsPageClient(props: {
|
||||
contract: ThirdwebContract;
|
||||
twAccount: Account | undefined;
|
||||
isLoggedIn: boolean;
|
||||
}) {
|
||||
const metadataQuery = useContractPageMetadata(props.contract);
|
||||
|
||||
@@ -28,7 +27,7 @@ export function ContractDirectListingsPageClient(props: {
|
||||
return (
|
||||
<ContractDirectListingsPage
|
||||
contract={props.contract}
|
||||
twAccount={props.twAccount}
|
||||
isLoggedIn={props.isLoggedIn}
|
||||
isInsightSupported={metadataQuery.data.isInsightSupported}
|
||||
/>
|
||||
);
|
||||
|
||||
+4
-5
@@ -1,19 +1,18 @@
|
||||
"use client";
|
||||
|
||||
import type { Account } from "@3rdweb-sdk/react/hooks/useApi";
|
||||
import type { ThirdwebContract } from "thirdweb";
|
||||
import { CreateListingButton } from "../components/list-button";
|
||||
import { DirectListingsTable } from "./components/table";
|
||||
|
||||
interface ContractDirectListingsPageProps {
|
||||
contract: ThirdwebContract;
|
||||
twAccount: Account | undefined;
|
||||
isLoggedIn: boolean;
|
||||
isInsightSupported: boolean;
|
||||
}
|
||||
|
||||
export const ContractDirectListingsPage: React.FC<
|
||||
ContractDirectListingsPageProps
|
||||
> = ({ contract, twAccount, isInsightSupported }) => {
|
||||
> = ({ contract, isLoggedIn, isInsightSupported }) => {
|
||||
return (
|
||||
<div className="flex flex-col gap-6">
|
||||
<div className="flex flex-row items-center justify-between">
|
||||
@@ -26,12 +25,12 @@ export const ContractDirectListingsPage: React.FC<
|
||||
contract={contract}
|
||||
type="direct-listings"
|
||||
createText="Create Direct Listing"
|
||||
twAccount={twAccount}
|
||||
isLoggedIn={isLoggedIn}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<DirectListingsTable contract={contract} twAccount={twAccount} />
|
||||
<DirectListingsTable contract={contract} isLoggedIn={isLoggedIn} />
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
+3
-4
@@ -1,6 +1,5 @@
|
||||
"use client";
|
||||
|
||||
import type { Account } from "@3rdweb-sdk/react/hooks/useApi";
|
||||
import { useState } from "react";
|
||||
import type { ThirdwebContract } from "thirdweb";
|
||||
import {
|
||||
@@ -13,14 +12,14 @@ import { MarketplaceTable } from "../../components/marketplace-table";
|
||||
|
||||
interface DirectListingsTableProps {
|
||||
contract: ThirdwebContract;
|
||||
twAccount: Account | undefined;
|
||||
isLoggedIn: boolean;
|
||||
}
|
||||
|
||||
const DEFAULT_QUERY_STATE = { count: 50, start: 0 };
|
||||
|
||||
export const DirectListingsTable: React.FC<DirectListingsTableProps> = ({
|
||||
contract,
|
||||
twAccount,
|
||||
isLoggedIn,
|
||||
}) => {
|
||||
const [queryParams, setQueryParams] = useState(DEFAULT_QUERY_STATE);
|
||||
const getAllQueryResult = useReadContract(getAllListings, {
|
||||
@@ -43,7 +42,7 @@ export const DirectListingsTable: React.FC<DirectListingsTableProps> = ({
|
||||
totalCountQuery={totalCountQuery}
|
||||
queryParams={queryParams}
|
||||
setQueryParams={setQueryParams}
|
||||
twAccount={twAccount}
|
||||
isLoggedIn={isLoggedIn}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
+2
-2
@@ -24,7 +24,7 @@ export default async function Page(props: {
|
||||
return (
|
||||
<ContractDirectListingsPageClient
|
||||
contract={info.contract}
|
||||
twAccount={account}
|
||||
isLoggedIn={!!account}
|
||||
/>
|
||||
);
|
||||
}
|
||||
@@ -39,7 +39,7 @@ export default async function Page(props: {
|
||||
return (
|
||||
<ContractDirectListingsPage
|
||||
contract={info.contract}
|
||||
twAccount={account}
|
||||
isLoggedIn={!!account}
|
||||
isInsightSupported={isInsightSupported}
|
||||
/>
|
||||
);
|
||||
|
||||
+2
-3
@@ -1,6 +1,5 @@
|
||||
"use client";
|
||||
|
||||
import type { Account } from "@3rdweb-sdk/react/hooks/useApi";
|
||||
import type { ThirdwebContract } from "thirdweb";
|
||||
import { ErrorPage, LoadingPage } from "../../_components/page-skeletons";
|
||||
import { RedirectToContractOverview } from "../../_components/redirect-contract-overview.client";
|
||||
@@ -9,7 +8,7 @@ import { ContractEnglishAuctionsPage } from "./ContractEnglishAuctionsPage";
|
||||
|
||||
export function ContractEnglishAuctionsPageClient(props: {
|
||||
contract: ThirdwebContract;
|
||||
twAccount: Account | undefined;
|
||||
isLoggedIn: boolean;
|
||||
}) {
|
||||
const metadataQuery = useContractPageMetadata(props.contract);
|
||||
|
||||
@@ -28,7 +27,7 @@ export function ContractEnglishAuctionsPageClient(props: {
|
||||
return (
|
||||
<ContractEnglishAuctionsPage
|
||||
contract={props.contract}
|
||||
twAccount={props.twAccount}
|
||||
isLoggedIn={props.isLoggedIn}
|
||||
isInsightSupported={metadataQuery.data.isInsightSupported}
|
||||
/>
|
||||
);
|
||||
|
||||
+4
-5
@@ -1,19 +1,18 @@
|
||||
"use client";
|
||||
|
||||
import type { Account } from "@3rdweb-sdk/react/hooks/useApi";
|
||||
import type { ThirdwebContract } from "thirdweb";
|
||||
import { CreateListingButton } from "../components/list-button";
|
||||
import { EnglishAuctionsTable } from "./components/table";
|
||||
|
||||
interface ContractEnglishAuctionsProps {
|
||||
contract: ThirdwebContract;
|
||||
twAccount: Account | undefined;
|
||||
isLoggedIn: boolean;
|
||||
isInsightSupported: boolean;
|
||||
}
|
||||
|
||||
export const ContractEnglishAuctionsPage: React.FC<
|
||||
ContractEnglishAuctionsProps
|
||||
> = ({ contract, twAccount, isInsightSupported }) => {
|
||||
> = ({ contract, isLoggedIn, isInsightSupported }) => {
|
||||
return (
|
||||
<div className="flex flex-col gap-6">
|
||||
<div className="flex flex-row items-center justify-between">
|
||||
@@ -25,13 +24,13 @@ export const ContractEnglishAuctionsPage: React.FC<
|
||||
contract={contract}
|
||||
type="english-auctions"
|
||||
createText="Create English Auction"
|
||||
twAccount={twAccount}
|
||||
isLoggedIn={isLoggedIn}
|
||||
isInsightSupported={isInsightSupported}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<EnglishAuctionsTable contract={contract} twAccount={twAccount} />
|
||||
<EnglishAuctionsTable contract={contract} isLoggedIn={isLoggedIn} />
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
+3
-4
@@ -1,6 +1,5 @@
|
||||
"use client";
|
||||
|
||||
import type { Account } from "@3rdweb-sdk/react/hooks/useApi";
|
||||
import { useState } from "react";
|
||||
import type { ThirdwebContract } from "thirdweb";
|
||||
import {
|
||||
@@ -13,14 +12,14 @@ import { MarketplaceTable } from "../../components/marketplace-table";
|
||||
|
||||
interface EnglishAuctionsTableProps {
|
||||
contract: ThirdwebContract;
|
||||
twAccount: Account | undefined;
|
||||
isLoggedIn: boolean;
|
||||
}
|
||||
|
||||
const DEFAULT_QUERY_STATE = { count: 50, start: 0 };
|
||||
|
||||
export const EnglishAuctionsTable: React.FC<EnglishAuctionsTableProps> = ({
|
||||
contract,
|
||||
twAccount,
|
||||
isLoggedIn,
|
||||
}) => {
|
||||
const [queryParams, setQueryParams] = useState(DEFAULT_QUERY_STATE);
|
||||
const getAllQueryResult = useReadContract(getAllAuctions, {
|
||||
@@ -37,7 +36,7 @@ export const EnglishAuctionsTable: React.FC<EnglishAuctionsTableProps> = ({
|
||||
|
||||
return (
|
||||
<MarketplaceTable
|
||||
twAccount={twAccount}
|
||||
isLoggedIn={isLoggedIn}
|
||||
contract={contract}
|
||||
getAllQueryResult={getAllQueryResult}
|
||||
getValidQueryResult={getValidQueryResult}
|
||||
|
||||
+2
-2
@@ -25,7 +25,7 @@ export default async function Page(props: {
|
||||
return (
|
||||
<ContractEnglishAuctionsPageClient
|
||||
contract={info.contract}
|
||||
twAccount={twAccount}
|
||||
isLoggedIn={!!twAccount}
|
||||
/>
|
||||
);
|
||||
}
|
||||
@@ -40,7 +40,7 @@ export default async function Page(props: {
|
||||
return (
|
||||
<ContractEnglishAuctionsPage
|
||||
contract={info.contract}
|
||||
twAccount={twAccount}
|
||||
isLoggedIn={!!twAccount}
|
||||
isInsightSupported={isInsightSupported}
|
||||
/>
|
||||
);
|
||||
|
||||
+4
-5
@@ -3,7 +3,6 @@
|
||||
import { Spinner } from "@/components/ui/Spinner/Spinner";
|
||||
import { ToolTipLabel } from "@/components/ui/tooltip";
|
||||
import { AdminOnly } from "@3rdweb-sdk/react/components/roles/admin-only";
|
||||
import type { Account } from "@3rdweb-sdk/react/hooks/useApi";
|
||||
import { useIsAdmin } from "@3rdweb-sdk/react/hooks/useContractRoles";
|
||||
import {
|
||||
Alert,
|
||||
@@ -187,7 +186,7 @@ interface ClaimConditionsFormProps {
|
||||
isColumn?: true;
|
||||
isErc20: boolean;
|
||||
isMultiPhase: boolean;
|
||||
twAccount: Account | undefined;
|
||||
isLoggedIn: boolean;
|
||||
}
|
||||
|
||||
export const ClaimConditionsForm: React.FC<ClaimConditionsFormProps> = ({
|
||||
@@ -196,7 +195,7 @@ export const ClaimConditionsForm: React.FC<ClaimConditionsFormProps> = ({
|
||||
isColumn,
|
||||
isErc20,
|
||||
isMultiPhase,
|
||||
twAccount,
|
||||
isLoggedIn,
|
||||
}) => {
|
||||
// assume 1155 if we have a tokenId
|
||||
const isErc1155 = tokenId !== undefined;
|
||||
@@ -636,7 +635,7 @@ export const ClaimConditionsForm: React.FC<ClaimConditionsFormProps> = ({
|
||||
|
||||
{controlledFields.some((field) => field.fromSdk) && (
|
||||
<ResetClaimEligibility
|
||||
twAccount={twAccount}
|
||||
isLoggedIn={isLoggedIn}
|
||||
isErc20={isErc20}
|
||||
contract={contract}
|
||||
tokenId={tokenId}
|
||||
@@ -657,7 +656,7 @@ export const ClaimConditionsForm: React.FC<ClaimConditionsFormProps> = ({
|
||||
hasRemovedPhases ||
|
||||
!isMultiPhase ? (
|
||||
<TransactionButton
|
||||
twAccount={twAccount}
|
||||
isLoggedIn={isLoggedIn}
|
||||
txChainID={contract.chain.id}
|
||||
transactionCount={1}
|
||||
disabled={claimConditionsQuery.isPending}
|
||||
|
||||
+3
-4
@@ -1,6 +1,5 @@
|
||||
"use client";
|
||||
|
||||
import type { Account } from "@3rdweb-sdk/react/hooks/useApi";
|
||||
import type { ThirdwebContract } from "thirdweb";
|
||||
import { ClaimConditionsForm } from "./claim-conditions-form/index";
|
||||
|
||||
@@ -9,7 +8,7 @@ interface ClaimConditionsProps {
|
||||
tokenId?: string;
|
||||
isColumn?: true;
|
||||
isERC20: boolean;
|
||||
twAccount: Account | undefined;
|
||||
isLoggedIn: boolean;
|
||||
isMultiphase: boolean;
|
||||
}
|
||||
export const ClaimConditions: React.FC<ClaimConditionsProps> = ({
|
||||
@@ -17,7 +16,7 @@ export const ClaimConditions: React.FC<ClaimConditionsProps> = ({
|
||||
tokenId,
|
||||
isColumn,
|
||||
isERC20,
|
||||
twAccount,
|
||||
isLoggedIn,
|
||||
isMultiphase,
|
||||
}) => {
|
||||
return (
|
||||
@@ -34,7 +33,7 @@ export const ClaimConditions: React.FC<ClaimConditionsProps> = ({
|
||||
|
||||
{/* Set Claim Conditions */}
|
||||
<ClaimConditionsForm
|
||||
twAccount={twAccount}
|
||||
isLoggedIn={isLoggedIn}
|
||||
isErc20={isERC20}
|
||||
contract={contract}
|
||||
tokenId={tokenId}
|
||||
|
||||
+3
-4
@@ -2,7 +2,6 @@
|
||||
|
||||
import { ToolTipLabel } from "@/components/ui/tooltip";
|
||||
import { AdminOnly } from "@3rdweb-sdk/react/components/roles/admin-only";
|
||||
import type { Account } from "@3rdweb-sdk/react/hooks/useApi";
|
||||
import { TransactionButton } from "components/buttons/TransactionButton";
|
||||
import { useTrack } from "hooks/analytics/useTrack";
|
||||
import { useTxNotifications } from "hooks/useTxNotifications";
|
||||
@@ -17,7 +16,7 @@ interface ResetClaimEligibilityProps {
|
||||
isErc20: boolean;
|
||||
contract: ThirdwebContract;
|
||||
tokenId?: string;
|
||||
twAccount: Account | undefined;
|
||||
isLoggedIn: boolean;
|
||||
isMultiphase: boolean;
|
||||
}
|
||||
|
||||
@@ -25,7 +24,7 @@ export const ResetClaimEligibility: React.FC<ResetClaimEligibilityProps> = ({
|
||||
contract,
|
||||
tokenId,
|
||||
isErc20,
|
||||
twAccount,
|
||||
isLoggedIn,
|
||||
isMultiphase,
|
||||
}) => {
|
||||
const trackEvent = useTrack();
|
||||
@@ -95,7 +94,7 @@ export const ResetClaimEligibility: React.FC<ResetClaimEligibilityProps> = ({
|
||||
return (
|
||||
<AdminOnly contract={contract} fallback={<div className="pb-5" />}>
|
||||
<TransactionButton
|
||||
twAccount={twAccount}
|
||||
isLoggedIn={isLoggedIn}
|
||||
transactionCount={1}
|
||||
type="button"
|
||||
isPending={sendTxMutation.isPending}
|
||||
|
||||
+2
-2
@@ -1,4 +1,3 @@
|
||||
import { getThirdwebClient } from "@/constants/thirdweb.server";
|
||||
import {
|
||||
type DashboardContractMetadata,
|
||||
fetchDashboardContractMetadata,
|
||||
@@ -32,6 +31,7 @@ export function ContractMetadata({
|
||||
chain={chain}
|
||||
address={contract.address}
|
||||
externalLinks={externalLinks}
|
||||
client={contract.client}
|
||||
/>
|
||||
);
|
||||
}
|
||||
@@ -43,7 +43,7 @@ export async function getContractMetadataHeaderData(
|
||||
fetchDashboardContractMetadata(contract),
|
||||
fetchPublishedContractsFromDeploy({
|
||||
contract,
|
||||
client: getThirdwebClient(),
|
||||
client: contract.client,
|
||||
}),
|
||||
]);
|
||||
|
||||
|
||||
+9
-3
@@ -2,10 +2,10 @@
|
||||
|
||||
import { CopyAddressButton } from "@/components/ui/CopyAddressButton";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { getThirdwebClient } from "@/constants/thirdweb.server";
|
||||
import { ChainIconClient } from "components/icons/ChainIcon";
|
||||
import { ExternalLinkIcon } from "lucide-react";
|
||||
import Link from "next/link";
|
||||
import type { ThirdwebClient } from "thirdweb";
|
||||
import type { ChainMetadata } from "thirdweb/chains";
|
||||
import { MediaRenderer } from "thirdweb/react";
|
||||
|
||||
@@ -22,6 +22,7 @@ interface MetadataHeaderProps {
|
||||
};
|
||||
chain: ChainMetadata;
|
||||
externalLinks?: ExternalLink[];
|
||||
client: ThirdwebClient;
|
||||
}
|
||||
|
||||
export const MetadataHeader: React.FC<MetadataHeaderProps> = ({
|
||||
@@ -29,6 +30,7 @@ export const MetadataHeader: React.FC<MetadataHeaderProps> = ({
|
||||
data,
|
||||
chain,
|
||||
externalLinks,
|
||||
client,
|
||||
}) => {
|
||||
const cleanedChainName = chain?.name?.replace("Mainnet", "").trim();
|
||||
const validBlockExplorers = chain?.explorers
|
||||
@@ -56,7 +58,7 @@ export const MetadataHeader: React.FC<MetadataHeaderProps> = ({
|
||||
<div className="size-16 shrink-0 overflow-hidden rounded-lg border border-border bg-muted md:size-20">
|
||||
<MediaRenderer
|
||||
src={data?.image}
|
||||
client={getThirdwebClient()}
|
||||
client={client}
|
||||
alt={""}
|
||||
className="h-full w-full"
|
||||
style={{
|
||||
@@ -85,7 +87,11 @@ export const MetadataHeader: React.FC<MetadataHeaderProps> = ({
|
||||
href={`/${chain.slug}`}
|
||||
className="flex w-fit shrink-0 items-center gap-2 rounded-3xl border border-border bg-card px-2.5 py-1.5 hover:bg-accent"
|
||||
>
|
||||
<ChainIconClient ipfsSrc={chain.icon?.url} className="size-4" />
|
||||
<ChainIconClient
|
||||
src={chain.icon?.url}
|
||||
client={client}
|
||||
className="size-4"
|
||||
/>
|
||||
{cleanedChainName && (
|
||||
<span className="text-xs">{cleanedChainName}</span>
|
||||
)}
|
||||
|
||||
+7
-1
@@ -5,6 +5,7 @@ import { TW_LOCAL_CHAIN_STORE } from "stores/storageKeys";
|
||||
import { getAddress, getContract, isAddress } from "thirdweb";
|
||||
import type { ChainMetadata } from "thirdweb/chains";
|
||||
import { fetchChain } from "utils/fetchChain";
|
||||
import { LAST_USED_TEAM_ID } from "../../../../../../constants/cookies";
|
||||
import { getAuthToken } from "../../../../../api/lib/getAuthToken";
|
||||
|
||||
export async function getContractPageParamsInfo(params: {
|
||||
@@ -43,13 +44,18 @@ export async function getContractPageParamsInfo(params: {
|
||||
|
||||
// attempt to get the auth token
|
||||
const token = await getAuthToken();
|
||||
const cookiesObj = await cookies();
|
||||
const teamId = cookiesObj.get(LAST_USED_TEAM_ID)?.value;
|
||||
|
||||
const contract = getContract({
|
||||
address: contractAddress,
|
||||
// eslint-disable-next-line no-restricted-syntax
|
||||
chain: mapV4ChainToV5Chain(chainMetadata),
|
||||
// if we have the auth token pass it into the client
|
||||
client: getThirdwebClient(token || undefined),
|
||||
client: getThirdwebClient({
|
||||
jwt: token || undefined,
|
||||
teamId,
|
||||
}),
|
||||
});
|
||||
|
||||
return {
|
||||
|
||||
+2
-3
@@ -1,6 +1,5 @@
|
||||
"use client";
|
||||
|
||||
import type { Account } from "@3rdweb-sdk/react/hooks/useApi";
|
||||
import type { ThirdwebContract } from "thirdweb";
|
||||
import type { ChainMetadata } from "thirdweb/chains";
|
||||
import { ErrorPage, LoadingPage } from "../_components/page-skeletons";
|
||||
@@ -11,7 +10,7 @@ import { AccountPage } from "./AccountPage";
|
||||
export function AccountPageClient(props: {
|
||||
contract: ThirdwebContract;
|
||||
chainMetadata: ChainMetadata;
|
||||
twAccount: Account | undefined;
|
||||
isLoggedIn: boolean;
|
||||
}) {
|
||||
const metadataQuery = useContractPageMetadata(props.contract);
|
||||
|
||||
@@ -31,7 +30,7 @@ export function AccountPageClient(props: {
|
||||
<AccountPage
|
||||
contract={props.contract}
|
||||
chainMetadata={props.chainMetadata}
|
||||
twAccount={props.twAccount}
|
||||
isLoggedIn={props.isLoggedIn}
|
||||
isInsightSupported={metadataQuery.data.isInsightSupported}
|
||||
/>
|
||||
);
|
||||
|
||||
+3
-4
@@ -1,6 +1,5 @@
|
||||
"use client";
|
||||
|
||||
import type { Account } from "@3rdweb-sdk/react/hooks/useApi";
|
||||
import type { ThirdwebContract } from "thirdweb";
|
||||
import type { ChainMetadata } from "thirdweb/chains";
|
||||
import { Heading } from "tw-components";
|
||||
@@ -11,14 +10,14 @@ import { NftsOwned } from "./components/nfts-owned";
|
||||
interface AccountPageProps {
|
||||
contract: ThirdwebContract;
|
||||
chainMetadata: ChainMetadata;
|
||||
twAccount: Account | undefined;
|
||||
isLoggedIn: boolean;
|
||||
isInsightSupported: boolean;
|
||||
}
|
||||
|
||||
export const AccountPage: React.FC<AccountPageProps> = ({
|
||||
contract,
|
||||
chainMetadata,
|
||||
twAccount,
|
||||
isLoggedIn,
|
||||
isInsightSupported,
|
||||
}) => {
|
||||
const symbol = chainMetadata.nativeCurrency.symbol || "Native Token";
|
||||
@@ -35,7 +34,7 @@ export const AccountPage: React.FC<AccountPageProps> = ({
|
||||
|
||||
{chainMetadata && (
|
||||
<DepositNative
|
||||
twAccount={twAccount}
|
||||
isLoggedIn={isLoggedIn}
|
||||
address={contract.address}
|
||||
symbol={symbol}
|
||||
chain={chainMetadata}
|
||||
|
||||
+3
-4
@@ -1,7 +1,6 @@
|
||||
"use client";
|
||||
|
||||
import { useThirdwebClient } from "@/constants/thirdweb.client";
|
||||
import type { Account } from "@3rdweb-sdk/react/hooks/useApi";
|
||||
import { Input } from "@chakra-ui/react";
|
||||
import { TransactionButton } from "components/buttons/TransactionButton";
|
||||
import { useV5DashboardChain } from "lib/v5-adapter";
|
||||
@@ -15,14 +14,14 @@ interface DepositNativeProps {
|
||||
address: string;
|
||||
symbol: string;
|
||||
chain: StoredChain;
|
||||
twAccount: Account | undefined;
|
||||
isLoggedIn: boolean;
|
||||
}
|
||||
|
||||
export const DepositNative: React.FC<DepositNativeProps> = ({
|
||||
address,
|
||||
symbol,
|
||||
chain,
|
||||
twAccount,
|
||||
isLoggedIn,
|
||||
}) => {
|
||||
const client = useThirdwebClient();
|
||||
const { mutate: transfer, isPending } = useSendAndConfirmTransaction();
|
||||
@@ -49,7 +48,7 @@ export const DepositNative: React.FC<DepositNativeProps> = ({
|
||||
value={amount}
|
||||
/>
|
||||
<TransactionButton
|
||||
twAccount={twAccount}
|
||||
isLoggedIn={isLoggedIn}
|
||||
txChainID={v5Chain.id}
|
||||
transactionCount={1}
|
||||
isPending={isPending}
|
||||
|
||||
+2
-2
@@ -28,7 +28,7 @@ export default async function Page(props: {
|
||||
<AccountPageClient
|
||||
contract={contract}
|
||||
chainMetadata={chainMetadata}
|
||||
twAccount={account}
|
||||
isLoggedIn={!!account}
|
||||
/>
|
||||
);
|
||||
}
|
||||
@@ -44,7 +44,7 @@ export default async function Page(props: {
|
||||
<AccountPage
|
||||
contract={contract}
|
||||
chainMetadata={chainMetadata}
|
||||
twAccount={account}
|
||||
isLoggedIn={!!account}
|
||||
isInsightSupported={isInsightSupported}
|
||||
/>
|
||||
);
|
||||
|
||||
+4
-3
@@ -1,6 +1,5 @@
|
||||
"use client";
|
||||
|
||||
import type { Account } from "@3rdweb-sdk/react/hooks/useApi";
|
||||
import type { ThirdwebContract } from "thirdweb";
|
||||
import { ErrorPage, LoadingPage } from "../_components/page-skeletons";
|
||||
import { RedirectToContractOverview } from "../_components/redirect-contract-overview.client";
|
||||
@@ -9,7 +8,7 @@ import { AccountsPage } from "./AccountsPage";
|
||||
|
||||
export function AccountsPageClient(props: {
|
||||
contract: ThirdwebContract;
|
||||
twAccount: Account | undefined;
|
||||
isLoggedIn: boolean;
|
||||
}) {
|
||||
const metadataQuery = useContractPageMetadata(props.contract);
|
||||
|
||||
@@ -25,5 +24,7 @@ export function AccountsPageClient(props: {
|
||||
return <RedirectToContractOverview contract={props.contract} />;
|
||||
}
|
||||
|
||||
return <AccountsPage contract={props.contract} twAccount={props.twAccount} />;
|
||||
return (
|
||||
<AccountsPage contract={props.contract} isLoggedIn={props.isLoggedIn} />
|
||||
);
|
||||
}
|
||||
|
||||
+3
-4
@@ -1,6 +1,5 @@
|
||||
"use client";
|
||||
|
||||
import type { Account } from "@3rdweb-sdk/react/hooks/useApi";
|
||||
import { ButtonGroup, Flex } from "@chakra-ui/react";
|
||||
import type { ThirdwebContract } from "thirdweb";
|
||||
import { Heading, TrackedLinkButton } from "tw-components";
|
||||
@@ -10,12 +9,12 @@ import { CreateAccountButton } from "./components/create-account-button";
|
||||
|
||||
interface AccountsPageProps {
|
||||
contract: ThirdwebContract;
|
||||
twAccount: Account | undefined;
|
||||
isLoggedIn: boolean;
|
||||
}
|
||||
|
||||
export const AccountsPage: React.FC<AccountsPageProps> = ({
|
||||
contract,
|
||||
twAccount,
|
||||
isLoggedIn,
|
||||
}) => {
|
||||
return (
|
||||
<Flex direction="column" gap={6}>
|
||||
@@ -40,7 +39,7 @@ export const AccountsPage: React.FC<AccountsPageProps> = ({
|
||||
>
|
||||
View Documentation
|
||||
</TrackedLinkButton>
|
||||
<CreateAccountButton contract={contract} twAccount={twAccount} />
|
||||
<CreateAccountButton contract={contract} isLoggedIn={isLoggedIn} />
|
||||
</ButtonGroup>
|
||||
</Flex>
|
||||
<AccountsCount contract={contract} />
|
||||
|
||||
+3
-4
@@ -2,7 +2,6 @@
|
||||
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { ToolTipLabel } from "@/components/ui/tooltip";
|
||||
import type { Account } from "@3rdweb-sdk/react/hooks/useApi";
|
||||
import { TransactionButton } from "components/buttons/TransactionButton";
|
||||
import type { ThirdwebContract } from "thirdweb";
|
||||
import * as ERC4337Ext from "thirdweb/extensions/erc4337";
|
||||
@@ -14,12 +13,12 @@ import {
|
||||
|
||||
interface CreateAccountButtonProps {
|
||||
contract: ThirdwebContract;
|
||||
twAccount: Account | undefined;
|
||||
isLoggedIn: boolean;
|
||||
}
|
||||
|
||||
export const CreateAccountButton: React.FC<CreateAccountButtonProps> = ({
|
||||
contract,
|
||||
twAccount,
|
||||
isLoggedIn,
|
||||
...restButtonProps
|
||||
}) => {
|
||||
const sendTxMutation = useSendAndConfirmTransaction();
|
||||
@@ -62,7 +61,7 @@ export const CreateAccountButton: React.FC<CreateAccountButtonProps> = ({
|
||||
|
||||
return (
|
||||
<TransactionButton
|
||||
twAccount={twAccount}
|
||||
isLoggedIn={isLoggedIn}
|
||||
txChainID={contract.chain.id}
|
||||
onClick={() => {
|
||||
const tx = ERC4337Ext.createAccount({
|
||||
|
||||
+2
-2
@@ -24,7 +24,7 @@ export default async function Page(props: {
|
||||
const account = await getRawAccount();
|
||||
|
||||
if (chainMetadata.chainId === localhost.id) {
|
||||
return <AccountsPageClient contract={contract} twAccount={account} />;
|
||||
return <AccountsPageClient contract={contract} isLoggedIn={!!account} />;
|
||||
}
|
||||
|
||||
const { isAccountFactory } = await getContractPageMetadata(contract);
|
||||
@@ -33,5 +33,5 @@ export default async function Page(props: {
|
||||
redirect(`/${params.chain_id}/${params.contractAddress}`);
|
||||
}
|
||||
|
||||
return <AccountsPage contract={contract} twAccount={account} />;
|
||||
return <AccountsPage contract={contract} isLoggedIn={!!account} />;
|
||||
}
|
||||
|
||||
+2
-3
@@ -1,6 +1,5 @@
|
||||
"use client";
|
||||
|
||||
import type { Account } from "@3rdweb-sdk/react/hooks/useApi";
|
||||
import type { ThirdwebContract } from "thirdweb";
|
||||
import { ClaimConditions } from "../_components/claim-conditions/claim-conditions";
|
||||
import { ErrorPage, LoadingPage } from "../_components/page-skeletons";
|
||||
@@ -9,7 +8,7 @@ import { useContractPageMetadata } from "../_hooks/useContractPageMetadata";
|
||||
|
||||
export function ClaimConditionsClient(props: {
|
||||
contract: ThirdwebContract;
|
||||
twAccount: Account | undefined;
|
||||
isLoggedIn: boolean;
|
||||
}) {
|
||||
const metadataQuery = useContractPageMetadata(props.contract);
|
||||
|
||||
@@ -35,7 +34,7 @@ export function ClaimConditionsClient(props: {
|
||||
<ClaimConditions
|
||||
contract={props.contract}
|
||||
isERC20={supportedERCs.isERC20}
|
||||
twAccount={props.twAccount}
|
||||
isLoggedIn={props.isLoggedIn}
|
||||
isMultiphase={true}
|
||||
/>
|
||||
);
|
||||
|
||||
+2
-2
@@ -23,7 +23,7 @@ export default async function Page(props: {
|
||||
const account = await getRawAccount();
|
||||
|
||||
if (chainMetadata.chainId === localhost.id) {
|
||||
return <ClaimConditionsClient contract={contract} twAccount={account} />;
|
||||
return <ClaimConditionsClient contract={contract} isLoggedIn={!!account} />;
|
||||
}
|
||||
|
||||
const {
|
||||
@@ -40,7 +40,7 @@ export default async function Page(props: {
|
||||
<ClaimConditions
|
||||
contract={contract}
|
||||
isERC20={supportedERCs.isERC20}
|
||||
twAccount={account}
|
||||
isLoggedIn={!!account}
|
||||
isMultiphase={true}
|
||||
/>
|
||||
);
|
||||
|
||||
+6
-5
@@ -19,7 +19,6 @@ import {
|
||||
TableRow,
|
||||
} from "@/components/ui/table";
|
||||
import { ToolTipLabel } from "@/components/ui/tooltip";
|
||||
import { getThirdwebClient } from "@/constants/thirdweb.server";
|
||||
import { zodResolver } from "@hookform/resolvers/zod";
|
||||
import { useMutation } from "@tanstack/react-query";
|
||||
import {
|
||||
@@ -39,6 +38,7 @@ import Link from "next/link";
|
||||
import { useEffect, useMemo, useState } from "react";
|
||||
import { useForm } from "react-hook-form";
|
||||
import {
|
||||
type ThirdwebClient,
|
||||
defineChain,
|
||||
eth_getCode,
|
||||
getContract,
|
||||
@@ -113,6 +113,7 @@ export function DataTable({
|
||||
(m) => m.name === "SuperChainInterop",
|
||||
);
|
||||
|
||||
const client = coreContract.client;
|
||||
const addRowMutation = useMutation({
|
||||
mutationFn: async (chain: { chainId: number; name: string }) => {
|
||||
if (coreContract.chain.id === chain.chainId) {
|
||||
@@ -122,7 +123,7 @@ export function DataTable({
|
||||
const c = defineChain(chain.chainId);
|
||||
const code = await eth_getCode(
|
||||
getRpcClient({
|
||||
client: getThirdwebClient(),
|
||||
client: client,
|
||||
chain: c,
|
||||
}),
|
||||
{ address: coreContract.address },
|
||||
@@ -261,7 +262,7 @@ export function DataTable({
|
||||
return (
|
||||
<Button
|
||||
type="button"
|
||||
onClick={() => deployContract(row.getValue("chainId"))}
|
||||
onClick={() => deployContract(row.getValue("chainId"), client)}
|
||||
>
|
||||
Deploy
|
||||
</Button>
|
||||
@@ -324,7 +325,7 @@ export function DataTable({
|
||||
getCoreRowModel: getCoreRowModel(),
|
||||
});
|
||||
|
||||
const deployContract = async (chainId: number) => {
|
||||
const deployContract = async (chainId: number, client: ThirdwebClient) => {
|
||||
try {
|
||||
if (!activeAccount) {
|
||||
throw new Error("No active account");
|
||||
@@ -332,7 +333,6 @@ export function DataTable({
|
||||
|
||||
// eslint-disable-next-line no-restricted-syntax
|
||||
const chain = defineChain(chainId);
|
||||
const client = getThirdwebClient();
|
||||
const salt =
|
||||
inputSalt || concatHex(["0x03", padHex("0x", { size: 31 })]).toString();
|
||||
|
||||
@@ -487,6 +487,7 @@ export function DataTable({
|
||||
|
||||
<div className="mt-4">
|
||||
<SingleNetworkSelector
|
||||
client={client}
|
||||
onAddRow={addRowMutation.mutate}
|
||||
isAddingRow={addRowMutation.isPending}
|
||||
className="w-full"
|
||||
|
||||
+5
-2
@@ -3,6 +3,7 @@ import { Badge } from "@/components/ui/badge";
|
||||
import { ChainIconClient } from "components/icons/ChainIcon";
|
||||
import { useAllChainsData } from "hooks/chains/allChains";
|
||||
import { useCallback, useMemo } from "react";
|
||||
import type { ThirdwebClient } from "thirdweb";
|
||||
|
||||
type Option = { label: string; value: string };
|
||||
|
||||
@@ -10,6 +11,7 @@ export function SingleNetworkSelector(props: {
|
||||
onAddRow: (chain: { chainId: number; name: string }) => void;
|
||||
isAddingRow: boolean;
|
||||
className?: string;
|
||||
client: ThirdwebClient;
|
||||
}) {
|
||||
const { allChains, idToChain } = useAllChainsData();
|
||||
|
||||
@@ -47,7 +49,8 @@ export function SingleNetworkSelector(props: {
|
||||
<span className="flex grow gap-2 truncate text-left">
|
||||
<ChainIconClient
|
||||
className="size-5"
|
||||
ipfsSrc={chain.icon?.url}
|
||||
src={chain.icon?.url}
|
||||
client={props.client}
|
||||
loading="lazy"
|
||||
/>
|
||||
{chain.name}
|
||||
@@ -59,7 +62,7 @@ export function SingleNetworkSelector(props: {
|
||||
</div>
|
||||
);
|
||||
},
|
||||
[idToChain],
|
||||
[idToChain, props.client],
|
||||
);
|
||||
|
||||
const handleChange = async (chainId: string) => {
|
||||
|
||||
+3
-4
@@ -1,6 +1,5 @@
|
||||
"use client";
|
||||
|
||||
import type { Account } from "@3rdweb-sdk/react/hooks/useApi";
|
||||
import type { ThirdwebContract } from "thirdweb";
|
||||
import type { ChainMetadata } from "thirdweb/chains";
|
||||
import { LoadingPage } from "../_components/page-skeletons";
|
||||
@@ -10,13 +9,13 @@ import { ContractExplorerPage } from "./ContractExplorerPage";
|
||||
interface ContractExplorePageProps {
|
||||
contract: ThirdwebContract;
|
||||
chainMetadata: ChainMetadata;
|
||||
twAccount: Account | undefined;
|
||||
isLoggedIn: boolean;
|
||||
}
|
||||
|
||||
export const ContractExplorerPageClient: React.FC<ContractExplorePageProps> = ({
|
||||
contract,
|
||||
chainMetadata,
|
||||
twAccount,
|
||||
isLoggedIn,
|
||||
}) => {
|
||||
const abiQuery = useResolveContractABI(contract);
|
||||
|
||||
@@ -29,7 +28,7 @@ export const ContractExplorerPageClient: React.FC<ContractExplorePageProps> = ({
|
||||
abi={abiQuery.data}
|
||||
contract={contract}
|
||||
chainMetadata={chainMetadata}
|
||||
twAccount={twAccount}
|
||||
isLoggedIn={isLoggedIn}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
+3
-4
@@ -1,5 +1,4 @@
|
||||
import { Alert, AlertDescription, AlertTitle } from "@/components/ui/alert";
|
||||
import type { Account } from "@3rdweb-sdk/react/hooks/useApi";
|
||||
import type { Abi } from "abitype";
|
||||
import { getContractFunctionsFromAbi } from "components/contract-components/getContractFunctionsFromAbi";
|
||||
import { ContractFunctionsOverview } from "components/contract-functions/contract-functions";
|
||||
@@ -11,14 +10,14 @@ interface ContractExplorePageProps {
|
||||
contract: ThirdwebContract;
|
||||
abi: Abi | undefined;
|
||||
chainMetadata: ChainMetadata;
|
||||
twAccount: Account | undefined;
|
||||
isLoggedIn: boolean;
|
||||
}
|
||||
|
||||
export const ContractExplorerPage: React.FC<ContractExplorePageProps> = ({
|
||||
contract,
|
||||
abi,
|
||||
chainMetadata,
|
||||
twAccount,
|
||||
isLoggedIn,
|
||||
}) => {
|
||||
if (!abi) {
|
||||
return (
|
||||
@@ -41,7 +40,7 @@ export const ContractExplorerPage: React.FC<ContractExplorePageProps> = ({
|
||||
onlyFunctions
|
||||
functions={functions}
|
||||
contract={contract}
|
||||
twAccount={twAccount}
|
||||
isLoggedIn={isLoggedIn}
|
||||
/>
|
||||
) : (
|
||||
<div className="flex flex-col items-center justify-center gap-2 bg-card text-center">
|
||||
|
||||
+2
-2
@@ -28,7 +28,7 @@ export default async function Page(props: {
|
||||
<ContractExplorerPageClient
|
||||
contract={contract}
|
||||
chainMetadata={chainMetadata}
|
||||
twAccount={account}
|
||||
isLoggedIn={!!account}
|
||||
/>
|
||||
);
|
||||
}
|
||||
@@ -40,7 +40,7 @@ export default async function Page(props: {
|
||||
contract={contract}
|
||||
abi={abi}
|
||||
chainMetadata={chainMetadata}
|
||||
twAccount={account}
|
||||
isLoggedIn={!!account}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import { getProjects } from "@/api/projects";
|
||||
import { getTeams } from "@/api/team";
|
||||
import { getThirdwebClient } from "@/constants/thirdweb.server";
|
||||
import type { Metadata } from "next";
|
||||
import { notFound } from "next/navigation";
|
||||
import { localhost } from "thirdweb/chains";
|
||||
@@ -9,10 +8,10 @@ import { isAddress, isContractDeployed } from "thirdweb/utils";
|
||||
import type { MinimalTeamsAndProjects } from "../../../../../components/contract-components/contract-deploy-form/add-to-project-card";
|
||||
import { resolveFunctionSelectors } from "../../../../../lib/selectors";
|
||||
import { shortenIfAddress } from "../../../../../utils/usedapp-external";
|
||||
import { getRawAccount } from "../../../../account/settings/getAccount";
|
||||
import {
|
||||
getAuthToken,
|
||||
getAuthTokenWalletAddress,
|
||||
getUserThirdwebClient,
|
||||
} from "../../../../api/lib/getAuthToken";
|
||||
import { NebulaFloatingChatButton } from "../../../../nebula-app/(app)/components/FloatingChat/FloatingChat";
|
||||
import { ConfigureCustomChain } from "./_layout/ConfigureCustomChain";
|
||||
@@ -48,13 +47,12 @@ export default async function Layout(props: {
|
||||
notFound();
|
||||
}
|
||||
|
||||
const [authToken, account, accountAddress] = await Promise.all([
|
||||
const [authToken, accountAddress] = await Promise.all([
|
||||
getAuthToken(),
|
||||
getRawAccount(),
|
||||
getAuthTokenWalletAddress(),
|
||||
]);
|
||||
|
||||
const client = getThirdwebClient();
|
||||
const client = await getUserThirdwebClient();
|
||||
const teamsAndProjects = await getTeamsAndProjectsIfLoggedIn();
|
||||
|
||||
if (contract.chain.id === localhost.id) {
|
||||
@@ -117,8 +115,8 @@ The following is the user's message:`;
|
||||
client={client}
|
||||
>
|
||||
<NebulaFloatingChatButton
|
||||
pageType="contract"
|
||||
authToken={authToken ?? undefined}
|
||||
account={account}
|
||||
label="Ask AI about this contract"
|
||||
client={client}
|
||||
nebulaParams={{
|
||||
|
||||
+2
-3
@@ -1,6 +1,5 @@
|
||||
"use client";
|
||||
|
||||
import type { Account } from "@3rdweb-sdk/react/hooks/useApi";
|
||||
import type { ThirdwebContract } from "thirdweb";
|
||||
import { ErrorPage, LoadingPage } from "../_components/page-skeletons";
|
||||
import { RedirectToContractOverview } from "../_components/redirect-contract-overview.client";
|
||||
@@ -9,7 +8,7 @@ import { ContractEditModulesPage } from "./ContractEditModulesPage";
|
||||
|
||||
export function ContractEditModulesPageClient(props: {
|
||||
contract: ThirdwebContract;
|
||||
twAccount: Account | undefined;
|
||||
isLoggedIn: boolean;
|
||||
}) {
|
||||
const metadataQuery = useContractPageMetadata(props.contract);
|
||||
|
||||
@@ -28,7 +27,7 @@ export function ContractEditModulesPageClient(props: {
|
||||
return (
|
||||
<ContractEditModulesPage
|
||||
contract={props.contract}
|
||||
twAccount={props.twAccount}
|
||||
isLoggedIn={props.isLoggedIn}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
+4
-5
@@ -2,7 +2,6 @@
|
||||
|
||||
import { Spinner } from "@/components/ui/Spinner/Spinner";
|
||||
import { Alert, AlertDescription, AlertTitle } from "@/components/ui/alert";
|
||||
import type { Account } from "@3rdweb-sdk/react/hooks/useApi";
|
||||
import { UserXIcon } from "lucide-react";
|
||||
import type { ThirdwebContract } from "thirdweb";
|
||||
import { getInstalledModules, owner } from "thirdweb/modules";
|
||||
@@ -12,12 +11,12 @@ import { InstallModuleForm } from "./components/ModuleForm";
|
||||
|
||||
interface ContractEditModulesPageProps {
|
||||
contract: ThirdwebContract;
|
||||
twAccount: Account | undefined;
|
||||
isLoggedIn: boolean;
|
||||
}
|
||||
|
||||
export const ContractEditModulesPage: React.FC<
|
||||
ContractEditModulesPageProps
|
||||
> = ({ contract, twAccount }) => {
|
||||
> = ({ contract, isLoggedIn }) => {
|
||||
const account = useActiveAccount();
|
||||
|
||||
const installedModulesQuery = useReadContract(getInstalledModules, {
|
||||
@@ -68,7 +67,7 @@ export const ContractEditModulesPage: React.FC<
|
||||
</div>
|
||||
<div className="h-10" />
|
||||
<InstallModuleForm
|
||||
twAccount={twAccount}
|
||||
isLoggedIn={isLoggedIn}
|
||||
contract={contract}
|
||||
refetchModules={() => installedModulesQuery.refetch()}
|
||||
account={account}
|
||||
@@ -100,7 +99,7 @@ export const ContractEditModulesPage: React.FC<
|
||||
refetchModules={() => installedModulesQuery.refetch()}
|
||||
contract={contract}
|
||||
ownerAccount={isOwner ? account : undefined}
|
||||
twAccount={twAccount}
|
||||
isLoggedIn={isLoggedIn}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
|
||||
+4
-5
@@ -16,7 +16,6 @@ import {
|
||||
} from "@/components/ui/form";
|
||||
import { Input } from "@/components/ui/input";
|
||||
import { Textarea } from "@/components/ui/textarea";
|
||||
import type { Account } from "@3rdweb-sdk/react/hooks/useApi";
|
||||
import { zodResolver } from "@hookform/resolvers/zod";
|
||||
import { useMutation } from "@tanstack/react-query";
|
||||
import { TransactionButton } from "components/buttons/TransactionButton";
|
||||
@@ -104,7 +103,7 @@ export function BatchMetadataModuleUI(
|
||||
isOwnerAccount: boolean;
|
||||
uploadMetadata: (values: UploadMetadataFormValues) => Promise<void>;
|
||||
contractChainId: number;
|
||||
twAccount: Account | undefined;
|
||||
isLoggedIn: boolean;
|
||||
},
|
||||
) {
|
||||
return (
|
||||
@@ -119,7 +118,7 @@ export function BatchMetadataModuleUI(
|
||||
<AccordionContent className="px-1">
|
||||
{props.isOwnerAccount && (
|
||||
<UploadMetadataNFTSection
|
||||
twAccount={props.twAccount}
|
||||
isLoggedIn={props.isLoggedIn}
|
||||
uploadMetadata={props.uploadMetadata}
|
||||
contractChainId={props.contractChainId}
|
||||
/>
|
||||
@@ -163,7 +162,7 @@ export function BatchMetadataModuleUI(
|
||||
function UploadMetadataNFTSection(props: {
|
||||
uploadMetadata: (values: UploadMetadataFormValues) => Promise<void>;
|
||||
contractChainId: number;
|
||||
twAccount: Account | undefined;
|
||||
isLoggedIn: boolean;
|
||||
}) {
|
||||
const form = useForm<UploadMetadataFormValues>({
|
||||
resolver: zodResolver(uploadMetadataFormSchema),
|
||||
@@ -262,7 +261,7 @@ function UploadMetadataNFTSection(props: {
|
||||
|
||||
<div className="flex justify-end">
|
||||
<TransactionButton
|
||||
twAccount={props.twAccount}
|
||||
isLoggedIn={props.isLoggedIn}
|
||||
size="sm"
|
||||
className="min-w-24"
|
||||
disabled={uploadMetadataMutation.isPending}
|
||||
|
||||
+10
-11
@@ -23,7 +23,6 @@ import { Label } from "@/components/ui/label";
|
||||
import { Separator } from "@/components/ui/separator";
|
||||
import { Skeleton } from "@/components/ui/skeleton";
|
||||
import { ToolTipLabel } from "@/components/ui/tooltip";
|
||||
import type { Account } from "@3rdweb-sdk/react/hooks/useApi";
|
||||
import { zodResolver } from "@hookform/resolvers/zod";
|
||||
import { useMutation } from "@tanstack/react-query";
|
||||
import { useQuery } from "@tanstack/react-query";
|
||||
@@ -342,7 +341,7 @@ export function ClaimableModuleUI(
|
||||
| undefined;
|
||||
isLoading: boolean;
|
||||
};
|
||||
twAccount: Account | undefined;
|
||||
isLoggedIn: boolean;
|
||||
},
|
||||
) {
|
||||
return (
|
||||
@@ -361,7 +360,7 @@ export function ClaimableModuleUI(
|
||||
mint={props.mintSection.mint}
|
||||
name={props.name}
|
||||
contractChainId={props.contractChainId}
|
||||
twAccount={props.twAccount}
|
||||
isLoggedIn={props.isLoggedIn}
|
||||
/>
|
||||
</AccordionContent>
|
||||
</AccordionItem>
|
||||
@@ -390,7 +389,7 @@ export function ClaimableModuleUI(
|
||||
{props.name !== "ClaimableERC1155" || props.isValidTokenId ? (
|
||||
props.claimConditionSection.data ? (
|
||||
<ClaimConditionSection
|
||||
twAccount={props.twAccount}
|
||||
isLoggedIn={props.isLoggedIn}
|
||||
isOwnerAccount={props.isOwnerAccount}
|
||||
claimCondition={
|
||||
props.claimConditionSection.data.claimCondition
|
||||
@@ -424,7 +423,7 @@ export function ClaimableModuleUI(
|
||||
<AccordionContent className="px-1">
|
||||
{props.primarySaleRecipientSection.data ? (
|
||||
<PrimarySaleRecipientSection
|
||||
twAccount={props.twAccount}
|
||||
isLoggedIn={props.isLoggedIn}
|
||||
isOwnerAccount={props.isOwnerAccount}
|
||||
primarySaleRecipient={
|
||||
props.primarySaleRecipientSection.data.primarySaleRecipient
|
||||
@@ -489,7 +488,7 @@ function ClaimConditionSection(props: {
|
||||
tokenDecimals?: number | undefined;
|
||||
tokenId: string;
|
||||
noClaimConditionSet: boolean;
|
||||
twAccount: Account | undefined;
|
||||
isLoggedIn: boolean;
|
||||
}) {
|
||||
const { idToChain } = useAllChainsData();
|
||||
const chain = idToChain.get(props.chainId);
|
||||
@@ -741,7 +740,7 @@ function ClaimConditionSection(props: {
|
||||
|
||||
<div className="flex justify-end">
|
||||
<TransactionButton
|
||||
twAccount={props.twAccount}
|
||||
isLoggedIn={props.isLoggedIn}
|
||||
size="sm"
|
||||
className="min-w-24"
|
||||
disabled={updateMutation.isPending || !props.isOwnerAccount}
|
||||
@@ -774,7 +773,7 @@ function PrimarySaleRecipientSection(props: {
|
||||
update: (values: PrimarySaleRecipientFormValues) => Promise<void>;
|
||||
isOwnerAccount: boolean;
|
||||
contractChainId: number;
|
||||
twAccount: Account | undefined;
|
||||
isLoggedIn: boolean;
|
||||
}) {
|
||||
const form = useForm<PrimarySaleRecipientFormValues>({
|
||||
resolver: zodResolver(primarySaleRecipientFormSchema),
|
||||
@@ -823,7 +822,7 @@ function PrimarySaleRecipientSection(props: {
|
||||
|
||||
<div className="flex justify-end">
|
||||
<TransactionButton
|
||||
twAccount={props.twAccount}
|
||||
isLoggedIn={props.isLoggedIn}
|
||||
size="sm"
|
||||
className="min-w-24 gap-2"
|
||||
disabled={
|
||||
@@ -858,7 +857,7 @@ function MintNFTSection(props: {
|
||||
mint: (values: MintFormValues) => Promise<void>;
|
||||
name: string;
|
||||
contractChainId: number;
|
||||
twAccount: Account | undefined;
|
||||
isLoggedIn: boolean;
|
||||
}) {
|
||||
const form = useForm<MintFormValues>({
|
||||
resolver: zodResolver(mintFormSchema),
|
||||
@@ -947,7 +946,7 @@ function MintNFTSection(props: {
|
||||
isPending={mintMutation.isPending}
|
||||
txChainID={props.contractChainId}
|
||||
transactionCount={1}
|
||||
twAccount={props.twAccount}
|
||||
isLoggedIn={props.isLoggedIn}
|
||||
>
|
||||
Mint
|
||||
</TransactionButton>
|
||||
|
||||
+2
-3
@@ -2,7 +2,6 @@
|
||||
|
||||
import { ScrollShadow } from "@/components/ui/ScrollShadow/ScrollShadow";
|
||||
import { Alert, AlertTitle } from "@/components/ui/alert";
|
||||
import type { Account as TWAccount } from "@3rdweb-sdk/react/hooks/useApi";
|
||||
import { CircleSlash } from "lucide-react";
|
||||
import type { ThirdwebContract } from "thirdweb/contract";
|
||||
import type { Account } from "thirdweb/wallets";
|
||||
@@ -17,7 +16,7 @@ export const InstalledModulesTable = (props: {
|
||||
};
|
||||
refetchModules: () => void;
|
||||
ownerAccount: Account | undefined;
|
||||
twAccount: TWAccount | undefined;
|
||||
isLoggedIn: boolean;
|
||||
}) => {
|
||||
const { installedModules, ownerAccount } = props;
|
||||
|
||||
@@ -59,7 +58,7 @@ export const InstalledModulesTable = (props: {
|
||||
contract={props.contract}
|
||||
onRemoveModule={props.refetchModules}
|
||||
ownerAccount={ownerAccount}
|
||||
twAccount={props.twAccount}
|
||||
isLoggedIn={props.isLoggedIn}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
|
||||
+7
-8
@@ -20,7 +20,6 @@ import { Input } from "@/components/ui/input";
|
||||
import { Separator } from "@/components/ui/separator";
|
||||
import { Skeleton } from "@/components/ui/skeleton";
|
||||
import { Textarea } from "@/components/ui/textarea";
|
||||
import type { Account } from "@3rdweb-sdk/react/hooks/useApi";
|
||||
import { zodResolver } from "@hookform/resolvers/zod";
|
||||
import { useMutation } from "@tanstack/react-query";
|
||||
import { TransactionButton } from "components/buttons/TransactionButton";
|
||||
@@ -192,7 +191,7 @@ export function MintableModuleUI(
|
||||
name: string;
|
||||
isBatchMetadataInstalled: boolean;
|
||||
contractChainId: number;
|
||||
twAccount: Account | undefined;
|
||||
isLoggedIn: boolean;
|
||||
},
|
||||
) {
|
||||
return (
|
||||
@@ -211,7 +210,7 @@ export function MintableModuleUI(
|
||||
<AccordionContent className="px-1">
|
||||
{props.isOwnerAccount && (
|
||||
<MintNFTSection
|
||||
twAccount={props.twAccount}
|
||||
isLoggedIn={props.isLoggedIn}
|
||||
mint={props.mint}
|
||||
name={props.name}
|
||||
isBatchMetadataInstalled={props.isBatchMetadataInstalled}
|
||||
@@ -242,7 +241,7 @@ export function MintableModuleUI(
|
||||
primarySaleRecipient={props.primarySaleRecipient}
|
||||
update={props.updatePrimaryRecipient}
|
||||
contractChainId={props.contractChainId}
|
||||
twAccount={props.twAccount}
|
||||
isLoggedIn={props.isLoggedIn}
|
||||
/>
|
||||
</AccordionContent>
|
||||
</AccordionItem>
|
||||
@@ -262,7 +261,7 @@ function PrimarySalesSection(props: {
|
||||
update: (values: UpdateFormValues) => Promise<void>;
|
||||
isOwnerAccount: boolean;
|
||||
contractChainId: number;
|
||||
twAccount: Account | undefined;
|
||||
isLoggedIn: boolean;
|
||||
}) {
|
||||
const form = useForm<UpdateFormValues>({
|
||||
resolver: zodResolver(primarySaleRecipientFormSchema),
|
||||
@@ -312,7 +311,7 @@ function PrimarySalesSection(props: {
|
||||
|
||||
<div className="mt-4 flex justify-end">
|
||||
<TransactionButton
|
||||
twAccount={props.twAccount}
|
||||
isLoggedIn={props.isLoggedIn}
|
||||
size="sm"
|
||||
className="min-w-24"
|
||||
disabled={updateMutation.isPending || !props.isOwnerAccount}
|
||||
@@ -340,7 +339,7 @@ function MintNFTSection(props: {
|
||||
name: string;
|
||||
isBatchMetadataInstalled: boolean;
|
||||
contractChainId: number;
|
||||
twAccount: Account | undefined;
|
||||
isLoggedIn: boolean;
|
||||
}) {
|
||||
const form = useForm<MintFormValues>({
|
||||
resolver: zodResolver(mintFormSchema),
|
||||
@@ -524,7 +523,7 @@ function MintNFTSection(props: {
|
||||
|
||||
<div className="flex justify-end">
|
||||
<TransactionButton
|
||||
twAccount={props.twAccount}
|
||||
isLoggedIn={props.isLoggedIn}
|
||||
size="sm"
|
||||
className="min-w-24"
|
||||
disabled={mintMutation.isPending}
|
||||
|
||||
+2
-3
@@ -2,7 +2,6 @@
|
||||
|
||||
import { Spinner } from "@/components/ui/Spinner/Spinner";
|
||||
import { useThirdwebClient } from "@/constants/thirdweb.client";
|
||||
import type { Account as TWAccount } from "@3rdweb-sdk/react/hooks/useApi";
|
||||
import { FormControl, Input, Select, Skeleton, Spacer } from "@chakra-ui/react";
|
||||
import { useMutation, useQuery } from "@tanstack/react-query";
|
||||
import { TransactionButton } from "components/buttons/TransactionButton";
|
||||
@@ -55,7 +54,7 @@ type InstallModuleFormProps = {
|
||||
data?: string[];
|
||||
isPending: boolean;
|
||||
};
|
||||
twAccount: TWAccount | undefined;
|
||||
isLoggedIn: boolean;
|
||||
};
|
||||
|
||||
export type InstallModuleForm = UseFormReturn<FormData>;
|
||||
@@ -388,7 +387,7 @@ export const InstallModuleForm = (props: InstallModuleFormProps) => {
|
||||
{/* Submit */}
|
||||
<div className="flex justify-end">
|
||||
<TransactionButton
|
||||
twAccount={props.twAccount}
|
||||
isLoggedIn={props.isLoggedIn}
|
||||
txChainID={contract.chain.id}
|
||||
transactionCount={1}
|
||||
isPending={installMutation.isPending}
|
||||
|
||||
+4
-5
@@ -16,7 +16,6 @@ import {
|
||||
} from "@/components/ui/form";
|
||||
import { Input } from "@/components/ui/input";
|
||||
import { Textarea } from "@/components/ui/textarea";
|
||||
import type { Account } from "@3rdweb-sdk/react/hooks/useApi";
|
||||
import { zodResolver } from "@hookform/resolvers/zod";
|
||||
import { useMutation } from "@tanstack/react-query";
|
||||
import { TransactionButton } from "components/buttons/TransactionButton";
|
||||
@@ -83,7 +82,7 @@ export function OpenEditionMetadataModuleUI(
|
||||
isOwnerAccount: boolean;
|
||||
setSharedMetadata: (values: SetSharedMetadataFormValues) => Promise<void>;
|
||||
contractChainId: number;
|
||||
twAccount: Account | undefined;
|
||||
isLoggedIn: boolean;
|
||||
},
|
||||
) {
|
||||
return (
|
||||
@@ -99,7 +98,7 @@ export function OpenEditionMetadataModuleUI(
|
||||
<SetSharedMetadataSection
|
||||
setSharedMetadata={props.setSharedMetadata}
|
||||
contractChainId={props.contractChainId}
|
||||
twAccount={props.twAccount}
|
||||
isLoggedIn={props.isLoggedIn}
|
||||
/>
|
||||
)}
|
||||
{!props.isOwnerAccount && (
|
||||
@@ -121,7 +120,7 @@ export function OpenEditionMetadataModuleUI(
|
||||
function SetSharedMetadataSection(props: {
|
||||
setSharedMetadata: (values: SetSharedMetadataFormValues) => Promise<void>;
|
||||
contractChainId: number;
|
||||
twAccount: Account | undefined;
|
||||
isLoggedIn: boolean;
|
||||
}) {
|
||||
const form = useForm<SetSharedMetadataFormValues>({
|
||||
resolver: zodResolver(setSharedMetadataFormSchema),
|
||||
@@ -219,7 +218,7 @@ function SetSharedMetadataSection(props: {
|
||||
isPending={setSharedMetadataMutation.isPending}
|
||||
transactionCount={1}
|
||||
txChainID={props.contractChainId}
|
||||
twAccount={props.twAccount}
|
||||
isLoggedIn={props.isLoggedIn}
|
||||
>
|
||||
Update
|
||||
</TransactionButton>
|
||||
|
||||
+10
-11
@@ -16,7 +16,6 @@ import {
|
||||
} from "@/components/ui/form";
|
||||
import { Input } from "@/components/ui/input";
|
||||
import { Skeleton } from "@/components/ui/skeleton";
|
||||
import type { Account } from "@3rdweb-sdk/react/hooks/useApi";
|
||||
import { zodResolver } from "@hookform/resolvers/zod";
|
||||
import { useMutation } from "@tanstack/react-query";
|
||||
import { TransactionButton } from "components/buttons/TransactionButton";
|
||||
@@ -167,7 +166,7 @@ export function RoyaltyModuleUI(
|
||||
) => Promise<void>;
|
||||
setRoyaltyInfoForToken: (values: RoyaltyInfoFormValues) => Promise<void>;
|
||||
contractChainId: number;
|
||||
twAccount: Account | undefined;
|
||||
isLoggedIn: boolean;
|
||||
},
|
||||
) {
|
||||
return (
|
||||
@@ -186,7 +185,7 @@ export function RoyaltyModuleUI(
|
||||
<RoyaltyInfoPerTokenSection
|
||||
setRoyaltyInfoForToken={props.setRoyaltyInfoForToken}
|
||||
contractChainId={props.contractChainId}
|
||||
twAccount={props.twAccount}
|
||||
isLoggedIn={props.isLoggedIn}
|
||||
/>
|
||||
) : (
|
||||
<Alert variant="info">
|
||||
@@ -209,7 +208,7 @@ export function RoyaltyModuleUI(
|
||||
update={props.setDefaultRoyaltyInfo}
|
||||
defaultRoyaltyInfo={props.defaultRoyaltyInfo}
|
||||
contractChainId={props.contractChainId}
|
||||
twAccount={props.twAccount}
|
||||
isLoggedIn={props.isLoggedIn}
|
||||
/>
|
||||
) : (
|
||||
<Alert variant="info">
|
||||
@@ -232,7 +231,7 @@ export function RoyaltyModuleUI(
|
||||
update={props.setTransferValidator}
|
||||
transferValidator={props.transferValidator}
|
||||
contractChainId={props.contractChainId}
|
||||
twAccount={props.twAccount}
|
||||
isLoggedIn={props.isLoggedIn}
|
||||
/>
|
||||
) : (
|
||||
<Alert variant="info">
|
||||
@@ -269,7 +268,7 @@ export type RoyaltyInfoFormValues = z.infer<typeof royaltyInfoFormSchema>;
|
||||
function RoyaltyInfoPerTokenSection(props: {
|
||||
setRoyaltyInfoForToken: (values: RoyaltyInfoFormValues) => Promise<void>;
|
||||
contractChainId: number;
|
||||
twAccount: Account | undefined;
|
||||
isLoggedIn: boolean;
|
||||
}) {
|
||||
const form = useForm<RoyaltyInfoFormValues>({
|
||||
resolver: zodResolver(royaltyInfoFormSchema),
|
||||
@@ -349,7 +348,7 @@ function RoyaltyInfoPerTokenSection(props: {
|
||||
|
||||
<div className="mt-4 flex justify-end">
|
||||
<TransactionButton
|
||||
twAccount={props.twAccount}
|
||||
isLoggedIn={props.isLoggedIn}
|
||||
size="sm"
|
||||
className="min-w-24"
|
||||
disabled={setRoyaltyInfoForTokenMutation.isPending}
|
||||
@@ -383,7 +382,7 @@ function DefaultRoyaltyInfoSection(props: {
|
||||
defaultRoyaltyInfo?: readonly [string, number];
|
||||
update: (values: DefaultRoyaltyFormValues) => Promise<void>;
|
||||
contractChainId: number;
|
||||
twAccount: Account | undefined;
|
||||
isLoggedIn: boolean;
|
||||
}) {
|
||||
const [defaultRoyaltyRecipient, defaultRoyaltyPercentage] =
|
||||
props.defaultRoyaltyInfo || [];
|
||||
@@ -460,7 +459,7 @@ function DefaultRoyaltyInfoSection(props: {
|
||||
transactionCount={1}
|
||||
isPending={updateMutation.isPending}
|
||||
txChainID={props.contractChainId}
|
||||
twAccount={props.twAccount}
|
||||
isLoggedIn={props.isLoggedIn}
|
||||
>
|
||||
Update
|
||||
</TransactionButton>
|
||||
@@ -483,7 +482,7 @@ function TransferValidatorSection(props: {
|
||||
transferValidator: string | undefined;
|
||||
update: (values: TransferValidatorFormValues) => Promise<void>;
|
||||
contractChainId: number;
|
||||
twAccount: Account | undefined;
|
||||
isLoggedIn: boolean;
|
||||
}) {
|
||||
const form = useForm<TransferValidatorFormValues>({
|
||||
resolver: zodResolver(transferValidatorFormSchema),
|
||||
@@ -531,7 +530,7 @@ function TransferValidatorSection(props: {
|
||||
|
||||
<div className="mt-4 flex justify-end">
|
||||
<TransactionButton
|
||||
twAccount={props.twAccount}
|
||||
isLoggedIn={props.isLoggedIn}
|
||||
size="sm"
|
||||
className="min-w-24 gap-2"
|
||||
disabled={updateMutation.isPending}
|
||||
|
||||
+2
-3
@@ -14,7 +14,6 @@ import { Input } from "@/components/ui/input";
|
||||
import { Skeleton } from "@/components/ui/skeleton";
|
||||
import { Switch } from "@/components/ui/switch";
|
||||
import { ToolTipLabel } from "@/components/ui/tooltip";
|
||||
import type { Account } from "@3rdweb-sdk/react/hooks/useApi";
|
||||
import { zodResolver } from "@hookform/resolvers/zod";
|
||||
import { useMutation } from "@tanstack/react-query";
|
||||
import { TransactionButton } from "components/buttons/TransactionButton";
|
||||
@@ -137,7 +136,7 @@ export function TransferableModuleUI(
|
||||
isOwnerAccount: boolean;
|
||||
update: (values: TransferableModuleFormValues) => Promise<void>;
|
||||
contractChainId: number;
|
||||
twAccount: Account | undefined;
|
||||
isLoggedIn: boolean;
|
||||
},
|
||||
) {
|
||||
const form = useForm<TransferableModuleFormValues>({
|
||||
@@ -200,7 +199,7 @@ export function TransferableModuleUI(
|
||||
(props.isRestricted ? 0 : 1) + allowListLength
|
||||
}
|
||||
txChainID={props.contractChainId}
|
||||
twAccount={props.twAccount}
|
||||
isLoggedIn={props.isLoggedIn}
|
||||
>
|
||||
Update
|
||||
</TransactionButton>
|
||||
|
||||
+3
-5
@@ -1,14 +1,12 @@
|
||||
import { Checkbox } from "@/components/ui/checkbox";
|
||||
import { getThirdwebClient } from "@/constants/thirdweb.server";
|
||||
import type { Meta, StoryObj } from "@storybook/react";
|
||||
import { useMutation } from "@tanstack/react-query";
|
||||
import { useState } from "react";
|
||||
import { toast } from "sonner";
|
||||
import { BadgeContainer } from "stories/utils";
|
||||
import { BadgeContainer, storybookThirdwebClient } from "stories/utils";
|
||||
import { ZERO_ADDRESS } from "thirdweb";
|
||||
import { ConnectButton, ThirdwebProvider } from "thirdweb/react";
|
||||
import type { TransactionError } from "../../../../../../../contexts/error-handler";
|
||||
import { accountStub } from "../../../../../../../stories/stubs";
|
||||
import {
|
||||
BatchMetadataModuleUI,
|
||||
type UploadMetadataFormValues,
|
||||
@@ -71,7 +69,7 @@ function Component() {
|
||||
<ThirdwebProvider>
|
||||
<div className="container flex max-w-6xl flex-col gap-10 py-10">
|
||||
<div>
|
||||
<ConnectButton client={getThirdwebClient()} />
|
||||
<ConnectButton client={storybookThirdwebClient} />
|
||||
</div>
|
||||
|
||||
<div className="flex items-center gap-5">
|
||||
@@ -85,7 +83,7 @@ function Component() {
|
||||
|
||||
<BadgeContainer label="Default">
|
||||
<BatchMetadataModuleUI
|
||||
twAccount={accountStub()}
|
||||
isLoggedIn={true}
|
||||
contractInfo={contractInfo}
|
||||
moduleAddress="0x0000000000000000000000000000000000000000"
|
||||
uploadMetadata={uploadMetadataStub}
|
||||
|
||||
+3
-4
@@ -6,7 +6,6 @@ import {
|
||||
SelectTrigger,
|
||||
SelectValue,
|
||||
} from "@/components/ui/select";
|
||||
import { getThirdwebClient } from "@/constants/thirdweb.server";
|
||||
import type { Meta, StoryObj } from "@storybook/react";
|
||||
import { useMutation } from "@tanstack/react-query";
|
||||
import { subDays } from "date-fns";
|
||||
@@ -15,7 +14,7 @@ import { toast } from "sonner";
|
||||
import { NATIVE_TOKEN_ADDRESS, ZERO_ADDRESS } from "thirdweb";
|
||||
import { ConnectButton, ThirdwebProvider } from "thirdweb/react";
|
||||
import { checksumAddress } from "thirdweb/utils";
|
||||
import { accountStub } from "../../../../../../../stories/stubs";
|
||||
import { storybookThirdwebClient } from "../../../../../../../stories/utils";
|
||||
import {
|
||||
type ClaimConditionFormValues,
|
||||
type ClaimConditionValue,
|
||||
@@ -103,7 +102,7 @@ function Component() {
|
||||
<ThirdwebProvider>
|
||||
<div className="container flex max-w-6xl flex-col gap-10 py-10">
|
||||
<div>
|
||||
<ConnectButton client={getThirdwebClient()} />
|
||||
<ConnectButton client={storybookThirdwebClient} />
|
||||
</div>
|
||||
|
||||
<div className="flex flex-wrap items-center gap-5">
|
||||
@@ -148,7 +147,7 @@ function Component() {
|
||||
</div>
|
||||
|
||||
<ClaimableModuleUI
|
||||
twAccount={accountStub()}
|
||||
isLoggedIn={true}
|
||||
contractInfo={contractInfo}
|
||||
moduleAddress="0x0000000000000000000000000000000000000000"
|
||||
primarySaleRecipientSection={{
|
||||
|
||||
+8
-4
@@ -1,21 +1,23 @@
|
||||
import { getThirdwebClient } from "@/constants/thirdweb.server";
|
||||
import {
|
||||
fetchLatestPublishedContractVersion,
|
||||
fetchPublishedContractVersions,
|
||||
} from "components/contract-components/fetch-contracts-with-versions";
|
||||
import { isAddress } from "thirdweb";
|
||||
import { type ThirdwebClient, isAddress } from "thirdweb";
|
||||
import type { FetchDeployMetadataResult } from "thirdweb/contract";
|
||||
import { resolveAddress } from "thirdweb/extensions/ens";
|
||||
import invariant from "tiny-invariant";
|
||||
import type { ModuleMeta } from "./install-module-params";
|
||||
|
||||
export async function getModuleInstalledParams(ext: ModuleMeta) {
|
||||
export async function getModuleInstalledParams(
|
||||
ext: ModuleMeta,
|
||||
client: ThirdwebClient,
|
||||
) {
|
||||
// get all versions of the module
|
||||
// if the publisher is an ens name, resolve it
|
||||
const publisherAddress = isAddress(ext.publisherAddress)
|
||||
? ext.publisherAddress
|
||||
: await resolveAddress({
|
||||
client: getThirdwebClient(),
|
||||
client,
|
||||
name: ext.publisherAddress,
|
||||
});
|
||||
|
||||
@@ -25,11 +27,13 @@ export async function getModuleInstalledParams(ext: ModuleMeta) {
|
||||
publishedModule = await fetchLatestPublishedContractVersion(
|
||||
publisherAddress,
|
||||
ext.moduleName,
|
||||
client,
|
||||
);
|
||||
} else {
|
||||
const allPublishedModules = await fetchPublishedContractVersions(
|
||||
publisherAddress,
|
||||
ext.moduleName,
|
||||
client,
|
||||
);
|
||||
|
||||
publishedModule = allPublishedModules.find(
|
||||
|
||||
+3
-1
@@ -1,3 +1,4 @@
|
||||
import { useThirdwebClient } from "@/constants/thirdweb.client";
|
||||
import { FormControl } from "@chakra-ui/react";
|
||||
import { useQuery } from "@tanstack/react-query";
|
||||
import { SolidityInput } from "contract-ui/components/solidity-inputs";
|
||||
@@ -20,12 +21,13 @@ export function useModuleInstallParams(props: {
|
||||
module?: ModuleMeta;
|
||||
isQueryEnabled: boolean;
|
||||
}) {
|
||||
const client = useThirdwebClient();
|
||||
const { module, isQueryEnabled } = props;
|
||||
return useQuery({
|
||||
queryKey: ["useModuleInstallParams", module],
|
||||
queryFn: async () => {
|
||||
invariant(module, "module must be defined");
|
||||
return await getModuleInstalledParams(module);
|
||||
return await getModuleInstalledParams(module, client);
|
||||
},
|
||||
enabled: !!(isQueryEnabled && module),
|
||||
refetchOnWindowFocus: false,
|
||||
|
||||
+5
-9
@@ -7,14 +7,12 @@ import {
|
||||
SelectTrigger,
|
||||
SelectValue,
|
||||
} from "@/components/ui/select";
|
||||
import { getThirdwebClient } from "@/constants/thirdweb.server";
|
||||
import type { Meta, StoryObj } from "@storybook/react";
|
||||
import { useMutation } from "@tanstack/react-query";
|
||||
import { useState } from "react";
|
||||
import { toast } from "sonner";
|
||||
import { BadgeContainer } from "stories/utils";
|
||||
import { BadgeContainer, storybookThirdwebClient } from "stories/utils";
|
||||
import { ConnectButton, ThirdwebProvider } from "thirdweb/react";
|
||||
import { accountStub } from "../../../../../../../stories/stubs";
|
||||
import {
|
||||
type MintFormValues,
|
||||
MintableModuleUI,
|
||||
@@ -72,13 +70,11 @@ function Component() {
|
||||
version: "1.0.0",
|
||||
};
|
||||
|
||||
const twAccount = accountStub();
|
||||
|
||||
return (
|
||||
<ThirdwebProvider>
|
||||
<div className="container flex max-w-6xl flex-col gap-10 py-10">
|
||||
<div>
|
||||
<ConnectButton client={getThirdwebClient()} />
|
||||
<ConnectButton client={storybookThirdwebClient} />
|
||||
</div>
|
||||
|
||||
<div className="flex flex-wrap items-center gap-5">
|
||||
@@ -110,7 +106,7 @@ function Component() {
|
||||
|
||||
<BadgeContainer label="Empty Primary Sale Recipient">
|
||||
<MintableModuleUI
|
||||
twAccount={twAccount}
|
||||
isLoggedIn={true}
|
||||
contractInfo={contractInfo}
|
||||
moduleAddress="0x0000000000000000000000000000000000000000"
|
||||
isPending={false}
|
||||
@@ -130,7 +126,7 @@ function Component() {
|
||||
|
||||
<BadgeContainer label="Filled Primary Sale Recipient">
|
||||
<MintableModuleUI
|
||||
twAccount={twAccount}
|
||||
isLoggedIn={true}
|
||||
contractInfo={contractInfo}
|
||||
moduleAddress="0x0000000000000000000000000000000000000000"
|
||||
isPending={false}
|
||||
@@ -150,7 +146,7 @@ function Component() {
|
||||
|
||||
<BadgeContainer label="Pending">
|
||||
<MintableModuleUI
|
||||
twAccount={twAccount}
|
||||
isLoggedIn={true}
|
||||
contractInfo={contractInfo}
|
||||
moduleAddress="0x0000000000000000000000000000000000000000"
|
||||
isPending={true}
|
||||
|
||||
+3
-4
@@ -14,7 +14,6 @@ import {
|
||||
DialogTrigger,
|
||||
} from "@/components/ui/dialog";
|
||||
import { Skeleton } from "@/components/ui/skeleton";
|
||||
import type { Account as TWAccount } from "@3rdweb-sdk/react/hooks/useApi";
|
||||
import * as Sentry from "@sentry/nextjs";
|
||||
import { useMutation } from "@tanstack/react-query";
|
||||
import { TransactionButton } from "components/buttons/TransactionButton";
|
||||
@@ -44,7 +43,7 @@ type ModuleCardProps = {
|
||||
version?: string;
|
||||
publisher?: string;
|
||||
}[];
|
||||
twAccount: TWAccount | undefined;
|
||||
isLoggedIn: boolean;
|
||||
};
|
||||
|
||||
export function ModuleCard(props: ModuleCardProps) {
|
||||
@@ -108,7 +107,7 @@ export function ModuleCard(props: ModuleCardProps) {
|
||||
)}
|
||||
>
|
||||
<ModuleInstance
|
||||
twAccount={props.twAccount}
|
||||
isLoggedIn={props.isLoggedIn}
|
||||
contract={contract}
|
||||
contractInfo={{
|
||||
name: contractInfo.name,
|
||||
@@ -161,7 +160,7 @@ export function ModuleCard(props: ModuleCardProps) {
|
||||
</Button>
|
||||
|
||||
<TransactionButton
|
||||
twAccount={props.twAccount}
|
||||
isLoggedIn={props.isLoggedIn}
|
||||
txChainID={contract.chain.id}
|
||||
transactionCount={1}
|
||||
isPending={uninstallMutation.isPending}
|
||||
|
||||
+1
-2
@@ -1,6 +1,5 @@
|
||||
"use client";
|
||||
|
||||
import type { Account as TWAccount } from "@3rdweb-sdk/react/hooks/useApi";
|
||||
import { lazy } from "react";
|
||||
import type { ThirdwebContract } from "thirdweb";
|
||||
import type { Account } from "thirdweb/wallets";
|
||||
@@ -25,7 +24,7 @@ export type ModuleInstanceProps = Omit<
|
||||
version?: string;
|
||||
publisher?: string;
|
||||
}[];
|
||||
twAccount: TWAccount | undefined;
|
||||
isLoggedIn: boolean;
|
||||
};
|
||||
|
||||
export function ModuleInstance(props: ModuleInstanceProps) {
|
||||
|
||||
+3
-5
@@ -1,12 +1,10 @@
|
||||
import { Checkbox } from "@/components/ui/checkbox";
|
||||
import { getThirdwebClient } from "@/constants/thirdweb.server";
|
||||
import type { Meta, StoryObj } from "@storybook/react";
|
||||
import { useMutation } from "@tanstack/react-query";
|
||||
import { useState } from "react";
|
||||
import { toast } from "sonner";
|
||||
import { BadgeContainer } from "stories/utils";
|
||||
import { BadgeContainer, storybookThirdwebClient } from "stories/utils";
|
||||
import { ConnectButton, ThirdwebProvider } from "thirdweb/react";
|
||||
import { accountStub } from "../../../../../../../stories/stubs";
|
||||
import {
|
||||
OpenEditionMetadataModuleUI,
|
||||
type SetSharedMetadataFormValues,
|
||||
@@ -57,7 +55,7 @@ function Component() {
|
||||
<ThirdwebProvider>
|
||||
<div className="container flex max-w-[1150px] flex-col gap-10 py-10">
|
||||
<div>
|
||||
<ConnectButton client={getThirdwebClient()} />
|
||||
<ConnectButton client={storybookThirdwebClient} />
|
||||
</div>
|
||||
|
||||
<div className="flex gap-2">
|
||||
@@ -87,7 +85,7 @@ function Component() {
|
||||
}}
|
||||
isOwnerAccount={isOwner}
|
||||
contractChainId={1}
|
||||
twAccount={accountStub()}
|
||||
isLoggedIn={true}
|
||||
/>
|
||||
</BadgeContainer>
|
||||
</div>
|
||||
|
||||
+6
-10
@@ -1,12 +1,10 @@
|
||||
import { Checkbox } from "@/components/ui/checkbox";
|
||||
import { getThirdwebClient } from "@/constants/thirdweb.server";
|
||||
import type { Meta, StoryObj } from "@storybook/react";
|
||||
import { useMutation } from "@tanstack/react-query";
|
||||
import { useState } from "react";
|
||||
import { toast } from "sonner";
|
||||
import { BadgeContainer } from "stories/utils";
|
||||
import { BadgeContainer, storybookThirdwebClient } from "stories/utils";
|
||||
import { ConnectButton, ThirdwebProvider } from "thirdweb/react";
|
||||
import { accountStub } from "../../../../../../../stories/stubs";
|
||||
import {
|
||||
type DefaultRoyaltyFormValues,
|
||||
type RoyaltyInfoFormValues,
|
||||
@@ -67,13 +65,11 @@ function Component() {
|
||||
version: "1.0.0",
|
||||
};
|
||||
|
||||
const twAccount = accountStub();
|
||||
|
||||
return (
|
||||
<ThirdwebProvider>
|
||||
<div className="container flex max-w-6xl flex-col gap-10 py-10">
|
||||
<div>
|
||||
<ConnectButton client={getThirdwebClient()} />
|
||||
<ConnectButton client={storybookThirdwebClient} />
|
||||
</div>
|
||||
|
||||
<div className="flex items-center gap-5">
|
||||
@@ -99,7 +95,7 @@ function Component() {
|
||||
}}
|
||||
isOwnerAccount={isOwner}
|
||||
contractChainId={1}
|
||||
twAccount={twAccount}
|
||||
isLoggedIn={true}
|
||||
/>
|
||||
</BadgeContainer>
|
||||
|
||||
@@ -118,7 +114,7 @@ function Component() {
|
||||
}}
|
||||
isOwnerAccount={isOwner}
|
||||
contractChainId={1}
|
||||
twAccount={twAccount}
|
||||
isLoggedIn={true}
|
||||
/>
|
||||
</BadgeContainer>
|
||||
|
||||
@@ -137,7 +133,7 @@ function Component() {
|
||||
}}
|
||||
isOwnerAccount={isOwner}
|
||||
contractChainId={1}
|
||||
twAccount={twAccount}
|
||||
isLoggedIn={true}
|
||||
/>
|
||||
</BadgeContainer>
|
||||
|
||||
@@ -157,7 +153,7 @@ function Component() {
|
||||
}}
|
||||
isOwnerAccount={isOwner}
|
||||
contractChainId={1}
|
||||
twAccount={twAccount}
|
||||
isLoggedIn={true}
|
||||
/>
|
||||
</BadgeContainer>
|
||||
</div>
|
||||
|
||||
+5
-7
@@ -1,12 +1,10 @@
|
||||
import { Checkbox } from "@/components/ui/checkbox";
|
||||
import { getThirdwebClient } from "@/constants/thirdweb.server";
|
||||
import type { Meta, StoryObj } from "@storybook/react";
|
||||
import { useMutation } from "@tanstack/react-query";
|
||||
import { useState } from "react";
|
||||
import { toast } from "sonner";
|
||||
import { BadgeContainer } from "stories/utils";
|
||||
import { BadgeContainer, storybookThirdwebClient } from "stories/utils";
|
||||
import { ConnectButton, ThirdwebProvider } from "thirdweb/react";
|
||||
import { accountStub } from "../../../../../../../stories/stubs";
|
||||
import {
|
||||
type TransferableModuleFormValues,
|
||||
TransferableModuleUI,
|
||||
@@ -75,7 +73,7 @@ function Component() {
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<ConnectButton client={getThirdwebClient()} />
|
||||
<ConnectButton client={storybookThirdwebClient} />
|
||||
</div>
|
||||
|
||||
<BadgeContainer label="Empty AllowList, Not Restricted">
|
||||
@@ -92,7 +90,7 @@ function Component() {
|
||||
}}
|
||||
isOwnerAccount={isOwner}
|
||||
contractChainId={1}
|
||||
twAccount={accountStub()}
|
||||
isLoggedIn={true}
|
||||
/>
|
||||
</BadgeContainer>
|
||||
|
||||
@@ -110,7 +108,7 @@ function Component() {
|
||||
}}
|
||||
isOwnerAccount={isOwner}
|
||||
contractChainId={1}
|
||||
twAccount={accountStub()}
|
||||
isLoggedIn={true}
|
||||
/>
|
||||
</BadgeContainer>
|
||||
|
||||
@@ -128,7 +126,7 @@ function Component() {
|
||||
}}
|
||||
isOwnerAccount={isOwner}
|
||||
contractChainId={1}
|
||||
twAccount={accountStub()}
|
||||
isLoggedIn={true}
|
||||
/>
|
||||
</BadgeContainer>
|
||||
</div>
|
||||
|
||||
+5
-2
@@ -25,7 +25,10 @@ export default async function Page(props: {
|
||||
|
||||
if (contract.chain.id === localhost.id) {
|
||||
return (
|
||||
<ContractEditModulesPageClient contract={contract} twAccount={account} />
|
||||
<ContractEditModulesPageClient
|
||||
contract={contract}
|
||||
isLoggedIn={!!account}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -35,5 +38,5 @@ export default async function Page(props: {
|
||||
redirect(`/${params.chain_id}/${params.contractAddress}`);
|
||||
}
|
||||
|
||||
return <ContractEditModulesPage contract={contract} twAccount={account} />;
|
||||
return <ContractEditModulesPage contract={contract} isLoggedIn={!!account} />;
|
||||
}
|
||||
|
||||
+2
-3
@@ -1,6 +1,5 @@
|
||||
"use client";
|
||||
|
||||
import type { Account } from "@3rdweb-sdk/react/hooks/useApi";
|
||||
import type { ThirdwebContract } from "thirdweb";
|
||||
import { ErrorPage, LoadingPage } from "../_components/page-skeletons";
|
||||
import { RedirectToContractOverview } from "../_components/redirect-contract-overview.client";
|
||||
@@ -9,7 +8,7 @@ import { ContractNFTPage } from "./ContractNFTPage";
|
||||
|
||||
export function ContractNFTPageClient(props: {
|
||||
contract: ThirdwebContract;
|
||||
twAccount: Account | undefined;
|
||||
isLoggedIn: boolean;
|
||||
}) {
|
||||
const metadataQuery = useContractPageMetadata(props.contract);
|
||||
|
||||
@@ -32,7 +31,7 @@ export function ContractNFTPageClient(props: {
|
||||
contract={props.contract}
|
||||
isErc721={supportedERCs.isERC721}
|
||||
functionSelectors={functionSelectors}
|
||||
twAccount={props.twAccount}
|
||||
isLoggedIn={props.isLoggedIn}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
+8
-9
@@ -1,4 +1,3 @@
|
||||
import type { Account } from "@3rdweb-sdk/react/hooks/useApi";
|
||||
import type { ThirdwebContract } from "thirdweb";
|
||||
import * as ERC721Ext from "thirdweb/extensions/erc721";
|
||||
import * as ERC1155Ext from "thirdweb/extensions/erc1155";
|
||||
@@ -16,14 +15,14 @@ interface NftOverviewPageProps {
|
||||
isErc721: boolean;
|
||||
tokenId?: string;
|
||||
functionSelectors: string[];
|
||||
twAccount: Account | undefined;
|
||||
isLoggedIn: boolean;
|
||||
}
|
||||
|
||||
export const ContractNFTPage: React.FC<NftOverviewPageProps> = ({
|
||||
contract,
|
||||
isErc721,
|
||||
functionSelectors,
|
||||
twAccount,
|
||||
isLoggedIn,
|
||||
}) => {
|
||||
const isERC721ClaimToSupported =
|
||||
ERC721Ext.isClaimToSupported(functionSelectors);
|
||||
@@ -63,38 +62,38 @@ export const ContractNFTPage: React.FC<NftOverviewPageProps> = ({
|
||||
<h2 className="font-semibold text-2xl tracking-tight">NFTs</h2>
|
||||
<div className="grid grid-cols-2 gap-2 md:flex">
|
||||
{isRevealable && (
|
||||
<NFTRevealButton contract={contract} twAccount={twAccount} />
|
||||
<NFTRevealButton contract={contract} isLoggedIn={isLoggedIn} />
|
||||
)}
|
||||
{isERC721ClaimToSupported && (
|
||||
/**
|
||||
* This button is used for claiming NFT Drop contract (erc721) only!
|
||||
* For Edition Drop we have a dedicated ClaimTabERC1155 inside each Edition's page
|
||||
*/
|
||||
<NFTClaimButton contract={contract} twAccount={twAccount} />
|
||||
<NFTClaimButton contract={contract} isLoggedIn={isLoggedIn} />
|
||||
)}
|
||||
{isMintToSupported && (
|
||||
<NFTMintButton
|
||||
contract={contract}
|
||||
isErc721={isErc721}
|
||||
twAccount={twAccount}
|
||||
isLoggedIn={isLoggedIn}
|
||||
/>
|
||||
)}
|
||||
{isSetSharedMetadataSupported && (
|
||||
<NFTSharedMetadataButton
|
||||
contract={contract}
|
||||
twAccount={twAccount}
|
||||
isLoggedIn={isLoggedIn}
|
||||
/>
|
||||
)}
|
||||
{isLazyMintable && (
|
||||
<NFTLazyMintButton
|
||||
contract={contract}
|
||||
isErc721={isErc721}
|
||||
twAccount={twAccount}
|
||||
isLoggedIn={isLoggedIn}
|
||||
/>
|
||||
)}
|
||||
{isLazyMintable && (
|
||||
<BatchLazyMintButton
|
||||
twAccount={twAccount}
|
||||
isLoggedIn={isLoggedIn}
|
||||
canCreateDelayedRevealBatch={canCreateDelayedRevealBatch}
|
||||
isErc721={isErc721}
|
||||
contract={contract}
|
||||
|
||||
+4
-3
@@ -1,6 +1,5 @@
|
||||
"use client";
|
||||
|
||||
import type { Account } from "@3rdweb-sdk/react/hooks/useApi";
|
||||
import type { ThirdwebContract } from "thirdweb";
|
||||
import { ErrorPage, LoadingPage } from "../../_components/page-skeletons";
|
||||
import { RedirectToContractOverview } from "../../_components/redirect-contract-overview.client";
|
||||
@@ -10,7 +9,8 @@ import { TokenIdPage } from "./token-id";
|
||||
export function TokenIdPageClient(props: {
|
||||
contract: ThirdwebContract;
|
||||
tokenId: string;
|
||||
twAccount: Account | undefined;
|
||||
isLoggedIn: boolean;
|
||||
accountAddress: string | undefined;
|
||||
}) {
|
||||
const { contract } = props;
|
||||
const metadataQuery = useContractPageMetadata(props.contract);
|
||||
@@ -34,7 +34,8 @@ export function TokenIdPageClient(props: {
|
||||
contract={contract}
|
||||
isErc721={supportedERCs.isERC721}
|
||||
tokenId={props.tokenId}
|
||||
twAccount={props.twAccount}
|
||||
isLoggedIn={props.isLoggedIn}
|
||||
accountAddress={props.accountAddress}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
+3
-4
@@ -9,7 +9,6 @@ import {
|
||||
SheetTrigger,
|
||||
} from "@/components/ui/sheet";
|
||||
import { cn } from "@/lib/utils";
|
||||
import type { Account } from "@3rdweb-sdk/react/hooks/useApi";
|
||||
import { TransactionButton } from "components/buttons/TransactionButton";
|
||||
import { useTrack } from "hooks/analytics/useTrack";
|
||||
import { useTxNotifications } from "hooks/useTxNotifications";
|
||||
@@ -29,7 +28,7 @@ import {
|
||||
interface AirdropTabProps {
|
||||
contract: ThirdwebContract;
|
||||
tokenId: string;
|
||||
twAccount: Account | undefined;
|
||||
isLoggedIn: boolean;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -38,7 +37,7 @@ interface AirdropTabProps {
|
||||
const AirdropTab: React.FC<AirdropTabProps> = ({
|
||||
contract,
|
||||
tokenId,
|
||||
twAccount,
|
||||
isLoggedIn,
|
||||
}) => {
|
||||
const address = useActiveAccount()?.address;
|
||||
const { handleSubmit, setValue, watch, reset } = useForm<{
|
||||
@@ -163,7 +162,7 @@ const AirdropTab: React.FC<AirdropTabProps> = ({
|
||||
more, please do it in multiple transactions.
|
||||
</p>
|
||||
<TransactionButton
|
||||
twAccount={twAccount}
|
||||
isLoggedIn={isLoggedIn}
|
||||
txChainID={contract.chain.id}
|
||||
transactionCount={1}
|
||||
isPending={sendAndConfirmTx.isPending}
|
||||
|
||||
+3
-4
@@ -1,6 +1,5 @@
|
||||
"use client";
|
||||
|
||||
import type { Account } from "@3rdweb-sdk/react/hooks/useApi";
|
||||
import { FormControl, Input } from "@chakra-ui/react";
|
||||
import { TransactionButton } from "components/buttons/TransactionButton";
|
||||
import { useTrack } from "hooks/analytics/useTrack";
|
||||
@@ -25,10 +24,10 @@ import {
|
||||
interface BurnTabProps {
|
||||
tokenId: string;
|
||||
contract: ThirdwebContract;
|
||||
twAccount: Account | undefined;
|
||||
isLoggedIn: boolean;
|
||||
}
|
||||
|
||||
const BurnTab: React.FC<BurnTabProps> = ({ contract, tokenId, twAccount }) => {
|
||||
const BurnTab: React.FC<BurnTabProps> = ({ contract, tokenId, isLoggedIn }) => {
|
||||
const account = useActiveAccount();
|
||||
const trackEvent = useTrack();
|
||||
const {
|
||||
@@ -137,7 +136,7 @@ const BurnTab: React.FC<BurnTabProps> = ({ contract, tokenId, twAccount }) => {
|
||||
type="submit"
|
||||
className="self-end"
|
||||
txChainID={contract.chain.id}
|
||||
twAccount={twAccount}
|
||||
isLoggedIn={isLoggedIn}
|
||||
>
|
||||
Burn
|
||||
</TransactionButton>
|
||||
|
||||
+3
-4
@@ -1,6 +1,5 @@
|
||||
"use client";
|
||||
|
||||
import type { Account } from "@3rdweb-sdk/react/hooks/useApi";
|
||||
import { Flex, FormControl, Input } from "@chakra-ui/react";
|
||||
import { TransactionButton } from "components/buttons/TransactionButton";
|
||||
import { useTrack } from "hooks/analytics/useTrack";
|
||||
@@ -15,13 +14,13 @@ import { FormErrorMessage, FormHelperText, FormLabel } from "tw-components";
|
||||
interface ClaimTabProps {
|
||||
contract: ThirdwebContract;
|
||||
tokenId: string;
|
||||
twAccount: Account | undefined;
|
||||
isLoggedIn: boolean;
|
||||
}
|
||||
|
||||
const ClaimTabERC1155: React.FC<ClaimTabProps> = ({
|
||||
contract,
|
||||
tokenId,
|
||||
twAccount,
|
||||
isLoggedIn,
|
||||
}) => {
|
||||
const trackEvent = useTrack();
|
||||
const address = useActiveAccount()?.address;
|
||||
@@ -125,12 +124,12 @@ const ClaimTabERC1155: React.FC<ClaimTabProps> = ({
|
||||
</Flex>
|
||||
|
||||
<TransactionButton
|
||||
isLoggedIn={isLoggedIn}
|
||||
txChainID={contract.chain.id}
|
||||
transactionCount={1}
|
||||
isPending={form.formState.isSubmitting}
|
||||
type="submit"
|
||||
className="self-end"
|
||||
twAccount={twAccount}
|
||||
>
|
||||
Claim
|
||||
</TransactionButton>
|
||||
|
||||
+3
-4
@@ -10,7 +10,6 @@ import {
|
||||
FormMessage,
|
||||
} from "@/components/ui/form";
|
||||
import { Input } from "@/components/ui/input";
|
||||
import type { Account } from "@3rdweb-sdk/react/hooks/useApi";
|
||||
import { zodResolver } from "@hookform/resolvers/zod";
|
||||
import { TransactionButton } from "components/buttons/TransactionButton";
|
||||
import { useTrack } from "hooks/analytics/useTrack";
|
||||
@@ -24,7 +23,7 @@ import { z } from "zod";
|
||||
interface MintSupplyTabProps {
|
||||
contract: ThirdwebContract;
|
||||
tokenId: string;
|
||||
twAccount: Account | undefined;
|
||||
isLoggedIn: boolean;
|
||||
}
|
||||
|
||||
const mintAdditionalSupplyFormSchema = z.object({
|
||||
@@ -37,7 +36,7 @@ const mintAdditionalSupplyFormSchema = z.object({
|
||||
const MintSupplyTab: React.FC<MintSupplyTabProps> = ({
|
||||
contract,
|
||||
tokenId,
|
||||
twAccount,
|
||||
isLoggedIn,
|
||||
}) => {
|
||||
const trackEvent = useTrack();
|
||||
const address = useActiveAccount()?.address;
|
||||
@@ -132,7 +131,7 @@ const MintSupplyTab: React.FC<MintSupplyTabProps> = ({
|
||||
isPending={sendAndConfirmTx.isPending}
|
||||
type="submit"
|
||||
className="self-end"
|
||||
twAccount={twAccount}
|
||||
isLoggedIn={isLoggedIn}
|
||||
>
|
||||
Mint
|
||||
</TransactionButton>
|
||||
|
||||
+15
-8
@@ -1,6 +1,6 @@
|
||||
"use client";
|
||||
|
||||
import type { Account } from "@3rdweb-sdk/react/hooks/useApi";
|
||||
import { GenericLoadingPage } from "@/components/blocks/skeletons/GenericLoadingPage";
|
||||
import { FormControl, Input } from "@chakra-ui/react";
|
||||
import { TransactionButton } from "components/buttons/TransactionButton";
|
||||
import { SolidityInput } from "contract-ui/components/solidity-inputs";
|
||||
@@ -20,13 +20,13 @@ import { FormErrorMessage, FormHelperText, FormLabel } from "tw-components";
|
||||
interface TransferTabProps {
|
||||
contract: ThirdwebContract;
|
||||
tokenId: string;
|
||||
twAccount: Account | undefined;
|
||||
isLoggedIn: boolean;
|
||||
}
|
||||
|
||||
const TransferTab: React.FC<TransferTabProps> = ({
|
||||
contract,
|
||||
tokenId,
|
||||
twAccount,
|
||||
isLoggedIn,
|
||||
}) => {
|
||||
const account = useActiveAccount();
|
||||
|
||||
@@ -46,7 +46,11 @@ const TransferTab: React.FC<TransferTabProps> = ({
|
||||
{ contract },
|
||||
);
|
||||
|
||||
const { mutate, isPending } = useSendAndConfirmTransaction();
|
||||
const sendTxAndConfirm = useSendAndConfirmTransaction();
|
||||
|
||||
if (checking1155) {
|
||||
return <GenericLoadingPage />;
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="flex w-full flex-col gap-2">
|
||||
@@ -72,7 +76,7 @@ const TransferTab: React.FC<TransferTabProps> = ({
|
||||
tokenId: BigInt(tokenId),
|
||||
from: account?.address ?? "",
|
||||
});
|
||||
mutate(transaction, {
|
||||
sendTxAndConfirm.mutate(transaction, {
|
||||
onSuccess: () => {
|
||||
trackEvent({
|
||||
category: "nft",
|
||||
@@ -126,14 +130,17 @@ const TransferTab: React.FC<TransferTabProps> = ({
|
||||
)}
|
||||
</div>
|
||||
<TransactionButton
|
||||
twAccount={twAccount}
|
||||
isLoggedIn={isLoggedIn}
|
||||
txChainID={contract.chain.id}
|
||||
transactionCount={1}
|
||||
isPending={isPending || checking1155}
|
||||
isPending={sendTxAndConfirm.isPending}
|
||||
type="submit"
|
||||
className="self-end"
|
||||
disabled={
|
||||
!form.formState.isDirty || checking1155 || isPending || !account
|
||||
!form.formState.isDirty ||
|
||||
checking1155 ||
|
||||
sendTxAndConfirm.isPending ||
|
||||
!account
|
||||
}
|
||||
>
|
||||
Transfer
|
||||
|
||||
+3
-4
@@ -1,6 +1,5 @@
|
||||
"use client";
|
||||
|
||||
import type { Account } from "@3rdweb-sdk/react/hooks/useApi";
|
||||
import {
|
||||
Accordion,
|
||||
AccordionButton,
|
||||
@@ -54,7 +53,7 @@ type UpdateNftMetadataForm = {
|
||||
* else (NFT Collection, Edition) -> use `setTokenURI`
|
||||
*/
|
||||
useUpdateMetadata: boolean;
|
||||
twAccount: Account | undefined;
|
||||
isLoggedIn: boolean;
|
||||
};
|
||||
|
||||
export const UpdateNftMetadata: React.FC<UpdateNftMetadataForm> = ({
|
||||
@@ -62,7 +61,7 @@ export const UpdateNftMetadata: React.FC<UpdateNftMetadataForm> = ({
|
||||
nft,
|
||||
useUpdateMetadata,
|
||||
setOpen,
|
||||
twAccount,
|
||||
isLoggedIn,
|
||||
}) => {
|
||||
const trackEvent = useTrack();
|
||||
const address = useActiveAccount()?.address;
|
||||
@@ -408,7 +407,7 @@ export const UpdateNftMetadata: React.FC<UpdateNftMetadataForm> = ({
|
||||
Cancel
|
||||
</Button>
|
||||
<TransactionButton
|
||||
twAccount={twAccount}
|
||||
isLoggedIn={isLoggedIn}
|
||||
txChainID={contract.chain.id}
|
||||
transactionCount={1}
|
||||
isPending={sendAndConfirmTx.isPending}
|
||||
|
||||
+3
-4
@@ -6,7 +6,6 @@ import {
|
||||
SheetTitle,
|
||||
SheetTrigger,
|
||||
} from "@/components/ui/sheet";
|
||||
import type { Account } from "@3rdweb-sdk/react/hooks/useApi";
|
||||
import { useState } from "react";
|
||||
import type { NFT, ThirdwebContract } from "thirdweb";
|
||||
import { UpdateNftMetadata } from "./update-metadata-form";
|
||||
@@ -19,14 +18,14 @@ interface UpdateMetadataTabProps {
|
||||
* else (NFT Collection, Edition) -> use `setTokenURI`
|
||||
*/
|
||||
useUpdateMetadata: boolean;
|
||||
twAccount: Account | undefined;
|
||||
isLoggedIn: boolean;
|
||||
}
|
||||
|
||||
const UpdateMetadataTab: React.FC<UpdateMetadataTabProps> = ({
|
||||
contract,
|
||||
nft,
|
||||
useUpdateMetadata,
|
||||
twAccount,
|
||||
isLoggedIn,
|
||||
}) => {
|
||||
const [open, setOpen] = useState(false);
|
||||
|
||||
@@ -40,7 +39,7 @@ const UpdateMetadataTab: React.FC<UpdateMetadataTabProps> = ({
|
||||
<SheetTitle className="text-left">Update NFT Metadata</SheetTitle>
|
||||
</SheetHeader>
|
||||
<UpdateNftMetadata
|
||||
twAccount={twAccount}
|
||||
isLoggedIn={isLoggedIn}
|
||||
contract={contract}
|
||||
nft={nft}
|
||||
useUpdateMetadata={useUpdateMetadata}
|
||||
|
||||
+9
-3
@@ -1,6 +1,7 @@
|
||||
import { notFound, redirect } from "next/navigation";
|
||||
import { localhost } from "thirdweb/chains";
|
||||
import { getRawAccount } from "../../../../../../account/settings/getAccount";
|
||||
import { getAuthTokenWalletAddress } from "../../../../../../api/lib/getAuthToken";
|
||||
import { getContractPageParamsInfo } from "../../_utils/getContractFromParams";
|
||||
import { getContractPageMetadata } from "../../_utils/getContractPageMetadata";
|
||||
import { TokenIdPageClient } from "./TokenIdPage.client";
|
||||
@@ -24,7 +25,10 @@ export default async function Page(props: {
|
||||
redirect(`/${params.chain_id}/${params.contractAddress}/nfts`);
|
||||
}
|
||||
|
||||
const account = await getRawAccount();
|
||||
const [accountAddress, account] = await Promise.all([
|
||||
getAuthTokenWalletAddress(),
|
||||
getRawAccount(),
|
||||
]);
|
||||
|
||||
const { contract } = info;
|
||||
if (contract.chain.id === localhost.id) {
|
||||
@@ -32,7 +36,8 @@ export default async function Page(props: {
|
||||
<TokenIdPageClient
|
||||
contract={contract}
|
||||
tokenId={params.tokenId}
|
||||
twAccount={account}
|
||||
isLoggedIn={!!account}
|
||||
accountAddress={accountAddress || undefined}
|
||||
/>
|
||||
);
|
||||
}
|
||||
@@ -48,7 +53,8 @@ export default async function Page(props: {
|
||||
contract={contract}
|
||||
isErc721={supportedERCs.isERC721}
|
||||
tokenId={params.tokenId}
|
||||
twAccount={account}
|
||||
isLoggedIn={!!account}
|
||||
accountAddress={accountAddress || undefined}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
+6
-4
@@ -19,7 +19,6 @@ import { ToolTipLabel } from "@/components/ui/tooltip";
|
||||
import { useThirdwebClient } from "@/constants/thirdweb.client";
|
||||
import { useDashboardRouter } from "@/lib/DashboardRouter";
|
||||
import { resolveSchemeWithErrorHandler } from "@/lib/resolveSchemeWithErrorHandler";
|
||||
import type { Account } from "@3rdweb-sdk/react/hooks/useApi";
|
||||
import { useChainSlug } from "hooks/chains/chainSlug";
|
||||
import { ExternalLinkIcon } from "lucide-react";
|
||||
import Link from "next/link";
|
||||
@@ -52,7 +51,8 @@ interface TokenIdPageProps {
|
||||
tokenId: string;
|
||||
contract: ThirdwebContract;
|
||||
isErc721: boolean;
|
||||
twAccount: Account | undefined;
|
||||
isLoggedIn: boolean;
|
||||
accountAddress: string | undefined;
|
||||
}
|
||||
|
||||
// TODO: verify the entire nft object with zod schema and display an error message
|
||||
@@ -61,7 +61,8 @@ export const TokenIdPage: React.FC<TokenIdPageProps> = ({
|
||||
contract,
|
||||
tokenId,
|
||||
isErc721,
|
||||
twAccount,
|
||||
isLoggedIn,
|
||||
accountAddress,
|
||||
}) => {
|
||||
const [tab, setTab] = useState("Details");
|
||||
const router = useDashboardRouter();
|
||||
@@ -71,7 +72,8 @@ export const TokenIdPage: React.FC<TokenIdPageProps> = ({
|
||||
const tabs = useNFTDrawerTabs({
|
||||
contract,
|
||||
tokenId,
|
||||
twAccount,
|
||||
isLoggedIn,
|
||||
accountAddress,
|
||||
});
|
||||
|
||||
const client = useThirdwebClient();
|
||||
|
||||
+16
-24
@@ -1,4 +1,3 @@
|
||||
import type { Account } from "@3rdweb-sdk/react/hooks/useApi";
|
||||
import { useIsMinter } from "@3rdweb-sdk/react/hooks/useContractRoles";
|
||||
import { useContractFunctionSelectors } from "contract-ui/hooks/useContractFunctionSelectors";
|
||||
import dynamic from "next/dynamic";
|
||||
@@ -6,13 +5,14 @@ import { useMemo } from "react";
|
||||
import type { ThirdwebContract } from "thirdweb";
|
||||
import * as ERC721Ext from "thirdweb/extensions/erc721";
|
||||
import * as ERC1155Ext from "thirdweb/extensions/erc1155";
|
||||
import { useActiveAccount, useReadContract } from "thirdweb/react";
|
||||
import { useReadContract } from "thirdweb/react";
|
||||
import type { NFTDrawerTab } from "./types";
|
||||
|
||||
type UseNFTDrawerTabsParams = {
|
||||
contract: ThirdwebContract;
|
||||
tokenId: string;
|
||||
twAccount: Account | undefined;
|
||||
isLoggedIn: boolean;
|
||||
accountAddress: string | undefined;
|
||||
};
|
||||
|
||||
const TransferTab = dynamic(() => import("./components/transfer-tab"));
|
||||
@@ -32,11 +32,11 @@ const UpdateMetadataTab = dynamic(
|
||||
export function useNFTDrawerTabs({
|
||||
contract,
|
||||
tokenId,
|
||||
twAccount,
|
||||
isLoggedIn,
|
||||
accountAddress,
|
||||
}: UseNFTDrawerTabsParams): NFTDrawerTab[] {
|
||||
const functionSelectorQuery = useContractFunctionSelectors(contract);
|
||||
const functionSelectors = functionSelectorQuery.data || [];
|
||||
const address = useActiveAccount()?.address;
|
||||
|
||||
const isERC721Query = useReadContract(ERC721Ext.isERC721, { contract });
|
||||
|
||||
@@ -46,13 +46,6 @@ export function useNFTDrawerTabs({
|
||||
: isERC721Query.data || false;
|
||||
const isERC1155 = isERC721Query.isPending ? false : !isERC721;
|
||||
|
||||
const balanceOfQuery = useReadContract(ERC1155Ext.balanceOf, {
|
||||
contract,
|
||||
owner: address || "",
|
||||
tokenId: BigInt(tokenId || 0),
|
||||
queryOptions: { enabled: isERC1155 },
|
||||
});
|
||||
|
||||
const { data: nft } = useReadContract(
|
||||
isERC721 ? ERC721Ext.getNFT : ERC1155Ext.getNFT,
|
||||
{
|
||||
@@ -112,10 +105,10 @@ export function useNFTDrawerTabs({
|
||||
|
||||
const isOwner = (() => {
|
||||
if (isERC1155) {
|
||||
return balanceOfQuery?.data ? balanceOfQuery.data > 0n : false;
|
||||
return true;
|
||||
}
|
||||
if (isERC721) {
|
||||
return nft?.owner === address;
|
||||
return nft?.owner === accountAddress;
|
||||
}
|
||||
return false;
|
||||
})();
|
||||
@@ -132,7 +125,7 @@ export function useNFTDrawerTabs({
|
||||
contract={contract}
|
||||
tokenId={tokenId}
|
||||
isColumn
|
||||
twAccount={twAccount}
|
||||
isLoggedIn={isLoggedIn}
|
||||
isMultiphase={isERC1155Multiphase}
|
||||
/>
|
||||
),
|
||||
@@ -151,7 +144,7 @@ export function useNFTDrawerTabs({
|
||||
<TransferTab
|
||||
contract={contract}
|
||||
tokenId={tokenId}
|
||||
twAccount={twAccount}
|
||||
isLoggedIn={isLoggedIn}
|
||||
/>
|
||||
),
|
||||
},
|
||||
@@ -167,7 +160,7 @@ export function useNFTDrawerTabs({
|
||||
<AirdropTab
|
||||
contract={contract}
|
||||
tokenId={tokenId}
|
||||
twAccount={twAccount}
|
||||
isLoggedIn={isLoggedIn}
|
||||
/>
|
||||
),
|
||||
},
|
||||
@@ -183,7 +176,7 @@ export function useNFTDrawerTabs({
|
||||
<BurnTab
|
||||
contract={contract}
|
||||
tokenId={tokenId}
|
||||
twAccount={twAccount}
|
||||
isLoggedIn={isLoggedIn}
|
||||
/>
|
||||
),
|
||||
},
|
||||
@@ -199,7 +192,7 @@ export function useNFTDrawerTabs({
|
||||
<MintSupplyTab
|
||||
contract={contract}
|
||||
tokenId={tokenId}
|
||||
twAccount={twAccount}
|
||||
isLoggedIn={isLoggedIn}
|
||||
/>
|
||||
),
|
||||
},
|
||||
@@ -214,7 +207,7 @@ export function useNFTDrawerTabs({
|
||||
<ClaimTabERC1155
|
||||
contract={contract}
|
||||
tokenId={tokenId}
|
||||
twAccount={twAccount}
|
||||
isLoggedIn={isLoggedIn}
|
||||
/>
|
||||
),
|
||||
},
|
||||
@@ -232,7 +225,7 @@ export function useNFTDrawerTabs({
|
||||
contract={contract}
|
||||
nft={nft}
|
||||
useUpdateMetadata={supportsUpdateMetadata}
|
||||
twAccount={twAccount}
|
||||
isLoggedIn={isLoggedIn}
|
||||
/>
|
||||
),
|
||||
},
|
||||
@@ -242,14 +235,13 @@ export function useNFTDrawerTabs({
|
||||
return tabs;
|
||||
}, [
|
||||
isERC1155,
|
||||
balanceOfQuery?.data,
|
||||
isERC721,
|
||||
nft,
|
||||
address,
|
||||
accountAddress,
|
||||
tokenId,
|
||||
isMinterRole,
|
||||
contract,
|
||||
functionSelectors,
|
||||
twAccount,
|
||||
isLoggedIn,
|
||||
]);
|
||||
}
|
||||
|
||||
+3
-4
@@ -9,7 +9,6 @@ import {
|
||||
SheetTrigger,
|
||||
} from "@/components/ui/sheet";
|
||||
import { MinterOnly } from "@3rdweb-sdk/react/components/roles/minter-only";
|
||||
import type { Account } from "@3rdweb-sdk/react/hooks/useApi";
|
||||
import { BatchLazyMint } from "core-ui/batch-upload/batch-lazy-mint";
|
||||
import { useTrack } from "hooks/analytics/useTrack";
|
||||
import { useTxNotifications } from "hooks/useTxNotifications";
|
||||
@@ -24,14 +23,14 @@ interface BatchLazyMintButtonProps {
|
||||
canCreateDelayedRevealBatch: boolean;
|
||||
contract: ThirdwebContract;
|
||||
isErc721: boolean;
|
||||
twAccount: Account | undefined;
|
||||
isLoggedIn: boolean;
|
||||
}
|
||||
|
||||
export const BatchLazyMintButton: React.FC<BatchLazyMintButtonProps> = ({
|
||||
contract,
|
||||
canCreateDelayedRevealBatch,
|
||||
isErc721,
|
||||
twAccount,
|
||||
isLoggedIn,
|
||||
}) => {
|
||||
const trackEvent = useTrack();
|
||||
const [open, setOpen] = useState(false);
|
||||
@@ -68,7 +67,7 @@ export const BatchLazyMintButton: React.FC<BatchLazyMintButtonProps> = ({
|
||||
<SheetTitle className="text-left">Upload NFTs</SheetTitle>
|
||||
</SheetHeader>
|
||||
<BatchLazyMint
|
||||
twAccount={twAccount}
|
||||
isLoggedIn={isLoggedIn}
|
||||
chainId={contract.chain.id}
|
||||
onSubmit={async ({ revealType, data }) => {
|
||||
// nice, we can set up everything the same for both the only thing that changes is the action string
|
||||
|
||||
+3
-4
@@ -8,7 +8,6 @@ import {
|
||||
SheetTitle,
|
||||
SheetTrigger,
|
||||
} from "@/components/ui/sheet";
|
||||
import type { Account } from "@3rdweb-sdk/react/hooks/useApi";
|
||||
import { FormControl, Input } from "@chakra-ui/react";
|
||||
import { TransactionButton } from "components/buttons/TransactionButton";
|
||||
import { useTrack } from "hooks/analytics/useTrack";
|
||||
@@ -27,7 +26,7 @@ const CLAIM_FORM_ID = "nft-claim-form";
|
||||
|
||||
interface NFTClaimButtonProps {
|
||||
contract: ThirdwebContract;
|
||||
twAccount: Account | undefined;
|
||||
isLoggedIn: boolean;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -36,7 +35,7 @@ interface NFTClaimButtonProps {
|
||||
*/
|
||||
export const NFTClaimButton: React.FC<NFTClaimButtonProps> = ({
|
||||
contract,
|
||||
twAccount,
|
||||
isLoggedIn,
|
||||
}) => {
|
||||
const trackEvent = useTrack();
|
||||
const address = useActiveAccount()?.address;
|
||||
@@ -108,7 +107,7 @@ export const NFTClaimButton: React.FC<NFTClaimButtonProps> = ({
|
||||
</form>
|
||||
<div className="mt-4 flex justify-end">
|
||||
<TransactionButton
|
||||
twAccount={twAccount}
|
||||
isLoggedIn={isLoggedIn}
|
||||
txChainID={contract.chain.id}
|
||||
transactionCount={1}
|
||||
form={CLAIM_FORM_ID}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user