diff --git a/apps/dashboard/src/@/components/ui/decimal-input.tsx b/apps/dashboard/src/@/components/ui/decimal-input.tsx new file mode 100644 index 00000000000..23fac415a00 --- /dev/null +++ b/apps/dashboard/src/@/components/ui/decimal-input.tsx @@ -0,0 +1,40 @@ +import { Input } from "./input"; + +export function DecimalInput(props: { + value: string; + onChange: (value: string) => void; + maxValue?: number; + id?: string; + className?: string; +}) { + return ( + { + const number = Number(e.target.value); + // ignore if string becomes invalid number + if (Number.isNaN(number)) { + return; + } + + if (props.maxValue && number > props.maxValue) { + return; + } + + // replace leading multiple zeros with single zero + let cleanedValue = e.target.value.replace(/^0+/, "0"); + + // replace leading zero before decimal point + if (!cleanedValue.includes(".")) { + cleanedValue = cleanedValue.replace(/^0+/, ""); + } + + props.onChange(cleanedValue || "0"); + }} + /> + ); +} diff --git a/apps/dashboard/src/@/constants/thirdweb-client.client.ts b/apps/dashboard/src/@/constants/thirdweb-client.client.ts index 428684ca171..c4181b41469 100644 --- a/apps/dashboard/src/@/constants/thirdweb-client.client.ts +++ b/apps/dashboard/src/@/constants/thirdweb-client.client.ts @@ -1,3 +1,4 @@ +import { NEXT_PUBLIC_DASHBOARD_CLIENT_ID } from "./public-envs"; import { getConfiguredThirdwebClient } from "./thirdweb.server"; export function getClientThirdwebClient(params?: { @@ -7,5 +8,7 @@ export function getClientThirdwebClient(params?: { return getConfiguredThirdwebClient({ secretKey: params?.jwt ?? undefined, teamId: params?.teamId ?? undefined, + type: "client", + clientId: NEXT_PUBLIC_DASHBOARD_CLIENT_ID, }); } diff --git a/apps/dashboard/src/@/constants/thirdweb-client.server.ts b/apps/dashboard/src/@/constants/thirdweb-client.server.ts index caca885ad2f..e14c71aff7e 100644 --- a/apps/dashboard/src/@/constants/thirdweb-client.server.ts +++ b/apps/dashboard/src/@/constants/thirdweb-client.server.ts @@ -1,9 +1,12 @@ import "server-only"; +import { NEXT_PUBLIC_DASHBOARD_CLIENT_ID } from "./public-envs"; import { DASHBOARD_THIRDWEB_SECRET_KEY } from "./server-envs"; import { getConfiguredThirdwebClient } from "./thirdweb.server"; export const serverThirdwebClient = getConfiguredThirdwebClient({ teamId: undefined, secretKey: DASHBOARD_THIRDWEB_SECRET_KEY, + clientId: NEXT_PUBLIC_DASHBOARD_CLIENT_ID, + type: "server", }); diff --git a/apps/dashboard/src/@/constants/thirdweb.server.ts b/apps/dashboard/src/@/constants/thirdweb.server.ts index 07b68599c6d..a93ebf46d9d 100644 --- a/apps/dashboard/src/@/constants/thirdweb.server.ts +++ b/apps/dashboard/src/@/constants/thirdweb.server.ts @@ -1,7 +1,4 @@ -import { - NEXT_PUBLIC_DASHBOARD_CLIENT_ID, - NEXT_PUBLIC_IPFS_GATEWAY_URL, -} from "@/constants/public-envs"; +import { NEXT_PUBLIC_IPFS_GATEWAY_URL } from "@/constants/public-envs"; import { THIRDWEB_BRIDGE_URL, THIRDWEB_BUNDLER_DOMAIN, @@ -22,10 +19,21 @@ import { import { getZkPaymasterData } from "thirdweb/wallets/smart"; import { getVercelEnv } from "../../lib/vercel-utils"; -export function getConfiguredThirdwebClient(options: { - secretKey: string | undefined; - teamId: string | undefined; -}): ThirdwebClient { +export function getConfiguredThirdwebClient( + options: + | { + type: "server"; + secretKey: string; + clientId: string | undefined; + teamId: string | undefined; + } + | { + type: "client"; + clientId: string; + secretKey: string | undefined; + teamId: string | undefined; + }, +): ThirdwebClient { if (getVercelEnv() !== "production") { // if not on production: run this when creating a client to set the domains setThirdwebDomains({ @@ -73,16 +81,30 @@ export function getConfiguredThirdwebClient(options: { }); } - return createThirdwebClient({ - teamId: options.teamId, - secretKey: options.secretKey, - clientId: NEXT_PUBLIC_DASHBOARD_CLIENT_ID, - config: { - storage: { - gatewayUrl: NEXT_PUBLIC_IPFS_GATEWAY_URL, - }, - }, - }); + return createThirdwebClient( + // this ternary is purely for making typescript happy - both are same object + options.type === "server" + ? { + teamId: options.teamId, + secretKey: options.secretKey, + clientId: options.clientId, + config: { + storage: { + gatewayUrl: NEXT_PUBLIC_IPFS_GATEWAY_URL, + }, + }, + } + : { + teamId: options.teamId, + secretKey: options.secretKey, + clientId: options.clientId, + config: { + storage: { + gatewayUrl: NEXT_PUBLIC_IPFS_GATEWAY_URL, + }, + }, + }, + ); } /** diff --git a/apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/public-pages/erc20/_components/RecentTransfers.tsx b/apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/public-pages/erc20/_components/RecentTransfers.tsx index 0872a27475a..0a52fbc4ef6 100644 --- a/apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/public-pages/erc20/_components/RecentTransfers.tsx +++ b/apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/public-pages/erc20/_components/RecentTransfers.tsx @@ -18,7 +18,7 @@ import { ChevronRightIcon, ExternalLinkIcon, } from "lucide-react"; -import { useState } from "react"; +import { useEffect, useState } from "react"; import { type ThirdwebContract, toTokens } from "thirdweb"; import type { ChainMetadata } from "thirdweb/chains"; import { @@ -199,6 +199,7 @@ export function RecentTransfers(props: { }) { const rowsPerPage = 10; const [page, setPage] = useState(0); + const [hasFetchedOnce, setHasFetchedOnce] = useState(false); const tokenQuery = useTokenTransfers({ chainId: props.clientContract.chain.id, @@ -207,11 +208,18 @@ export function RecentTransfers(props: { limit: rowsPerPage, }); + // eslint-disable-next-line no-restricted-syntax + useEffect(() => { + if (!tokenQuery.isPending) { + setHasFetchedOnce(true); + } + }, [tokenQuery.isPending]); + return (
Maximum purchasable: {tokenData.maxPurchasable} tokens
*/}