From 3de2dce384436b1a4e84627e904d0b498977d72f Mon Sep 17 00:00:00 2001 From: jnsdls Date: Mon, 22 Jul 2024 15:28:44 +0000 Subject: [PATCH] [Feature] Add placeholder chain to provider setup and custom SDK context, make middleware method async (#3773) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## PR-Codex overview The focus of this PR is to enhance the app setup process by adding placeholder chains and improving dynamic routing. ### Detailed summary - Added `PLACEHOLDER_CHAIN` object in `Billing.tsx` and `provider-setup.tsx` - Updated context with placeholder chain if configured chains are empty - Added dynamic routing logic in `middleware.ts` for chain IDs > ✨ Ask PR-Codex anything about this PR by commenting with `/codex {your question}` --- .../components/app-layouts/provider-setup.tsx | 22 +++++++++++++++++-- .../src/components/onboarding/Billing.tsx | 5 ++++- .../src/contexts/custom-sdk-context.tsx | 21 +++++++++++++++++- apps/dashboard/src/middleware.ts | 21 ++++++++++++++++-- 4 files changed, 63 insertions(+), 6 deletions(-) diff --git a/apps/dashboard/src/components/app-layouts/provider-setup.tsx b/apps/dashboard/src/components/app-layouts/provider-setup.tsx index 9b5852c9dcb..e112a8bca87 100644 --- a/apps/dashboard/src/components/app-layouts/provider-setup.tsx +++ b/apps/dashboard/src/components/app-layouts/provider-setup.tsx @@ -18,7 +18,7 @@ import { getDashboardChainRpc } from "lib/rpc"; import { StorageSingleton } from "lib/sdk"; import { useEffect, useMemo, useState } from "react"; import { ethers5Adapter } from "thirdweb/adapters/ethers5"; -import type { ChainMetadata } from "thirdweb/chains"; +import { type ChainMetadata, ethereum } from "thirdweb/chains"; import { useActiveAccount, useActiveWallet, @@ -26,6 +26,22 @@ import { } from "thirdweb/react"; import { setThirdwebDomains } from "thirdweb/utils"; import type { ComponentWithChildren } from "types/component-with-children"; +import type { StoredChain } from "../../contexts/configured-chains"; + +const PLACEHOLDER_CHAIN: StoredChain = { + chainId: 1, + chain: "ETH", + name: "Ethereum", + rpc: [ethereum.rpc], + nativeCurrency: { + decimals: 18, + name: "Ether", + symbol: "ETH", + }, + shortName: "eth", + slug: "ethereum", + testnet: false, +}; const THIRDWEB_API_HOST = new URL( process.env.NEXT_PUBLIC_THIRDWEB_API_HOST || "https://api.thirdweb.com", @@ -76,7 +92,9 @@ export const DashboardThirdwebProviderSetup: ComponentWithChildren< queryClient={queryClient} signer={ethersSigner} activeChain={activeChain} - supportedChains={supportedChains} + supportedChains={ + supportedChains.length ? supportedChains : [PLACEHOLDER_CHAIN] + } sdkOptions={{ gasSettings: { maxPriceInGwei: 650 }, readonlySettings, diff --git a/apps/dashboard/src/components/onboarding/Billing.tsx b/apps/dashboard/src/components/onboarding/Billing.tsx index a00cab99ff7..8f76304bd58 100644 --- a/apps/dashboard/src/components/onboarding/Billing.tsx +++ b/apps/dashboard/src/components/onboarding/Billing.tsx @@ -9,7 +9,10 @@ import { useTrack } from "hooks/analytics/useTrack"; import { OnboardingPaymentForm } from "./PaymentForm"; import { OnboardingTitle } from "./Title"; -const stripePromise = loadStripe(process.env.NEXT_PUBLIC_STRIPE_KEY ?? ""); +// only load stripe if the key is available +const stripePromise = process.env.NEXT_PUBLIC_STRIPE_KEY + ? loadStripe(process.env.NEXT_PUBLIC_STRIPE_KEY) + : null; interface OnboardingBillingProps { onSave: () => void; diff --git a/apps/dashboard/src/contexts/custom-sdk-context.tsx b/apps/dashboard/src/contexts/custom-sdk-context.tsx index 8f54d06cbff..f90e8fcd5f6 100644 --- a/apps/dashboard/src/contexts/custom-sdk-context.tsx +++ b/apps/dashboard/src/contexts/custom-sdk-context.tsx @@ -11,7 +11,24 @@ import { } from "hooks/chains/configureChains"; import { getDashboardChainRpc } from "lib/rpc"; import { StorageSingleton } from "lib/sdk"; +import { ethereum } from "thirdweb/chains"; import type { ComponentWithChildren } from "types/component-with-children"; +import type { StoredChain } from "./configured-chains"; + +const PLACEHOLDER_CHAIN: StoredChain = { + chainId: 1, + chain: "ETH", + name: "Ethereum", + rpc: [ethereum.rpc], + nativeCurrency: { + decimals: 18, + name: "Ether", + symbol: "ETH", + }, + shortName: "eth", + slug: "ethereum", + testnet: false, +}; export const CustomSDKContext: ComponentWithChildren<{ desiredChainId?: number; @@ -27,7 +44,9 @@ export const CustomSDKContext: ComponentWithChildren<{ activeChain={desiredChainId} signer={signer} queryClient={queryClient} - supportedChains={configuredChains} + supportedChains={ + configuredChains.length ? configuredChains : [PLACEHOLDER_CHAIN] + } sdkOptions={{ gasSettings: { maxPriceInGwei: 650, diff --git a/apps/dashboard/src/middleware.ts b/apps/dashboard/src/middleware.ts index 3c2b150950f..409d10d8b64 100644 --- a/apps/dashboard/src/middleware.ts +++ b/apps/dashboard/src/middleware.ts @@ -1,8 +1,8 @@ import { LOGGED_IN_ONLY_PATHS } from "@/constants/auth"; import { COOKIE_ACTIVE_ACCOUNT, COOKIE_PREFIX_TOKEN } from "@/constants/cookie"; -// middleware.ts import { type NextRequest, NextResponse } from "next/server"; import { getAddress } from "thirdweb"; +import { defineChain, getChainMetadata } from "thirdweb/chains"; // ignore assets, api - only intercept page routes export const config = { @@ -19,7 +19,7 @@ export const config = { ], }; -export function middleware(request: NextRequest) { +export async function middleware(request: NextRequest) { const { pathname } = request.nextUrl; const activeAccount = request.cookies.get(COOKIE_ACTIVE_ACCOUNT)?.value; const authCookie = activeAccount @@ -49,6 +49,23 @@ export function middleware(request: NextRequest) { // remove '/' in front and then split by '/' const paths = pathname.slice(1).split("/"); + // if the first section of the path is a number, check if it's a valid chain_id and re-write it to the slug + const possibleChainId = Number.parseInt(paths[0]); + if (!Number.isNaN(possibleChainId)) { + const possibleChain = defineChain(possibleChainId); + try { + const chainMetadata = await getChainMetadata(possibleChain); + if (chainMetadata.slug) { + return redirect( + request, + `/${chainMetadata.slug}/${paths.slice(1).join("/")}`, + ); + } + } catch { + // no-op, we continue with the default routing + } + } + // DIFFERENT DYNAMIC ROUTING CASES // /
/... case