From d6bc43c34d3340e2fe39cf4a0697884bbb2293ea Mon Sep 17 00:00:00 2001 From: Yash094 <67926590+Yash094@users.noreply.github.com> Date: Fri, 14 Nov 2025 20:55:30 +0000 Subject: [PATCH 1/4] support form changes (#8414) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ## PR-Codex overview This PR focuses on refactoring and enhancing various support forms in the application, including the removal of outdated components and the introduction of new fields to improve user input for support tickets. ### Detailed summary - Deleted `payments`, `contracts`, and `AffectedAreaInput` components. - Updated `OtherSupportForm` with a new label. - Modified `TokensMarketplaceSupportForm` to include a new input for "Support ID in logs". - Removed dynamic imports for `ContractSupportForm` and `PaymentsSupportForm`. - Updated `productOptions` labels for clarity. - Replaced `ENGINE_TYPES` and `ENGINE_PROBLEM_AREAS` with `API_SDK_OPTIONS`. - Enhanced `EngineSupportForm` with new inputs and logic based on selected SDK. - Introduced new components for user wallet issues and account abstraction. - Updated `PROBLEM_AREAS` to include new components for social/email login and user wallet custom auth. > ✨ Ask PR-Codex anything about this PR by commenting with `/codex {your question}` ## Summary by CodeRabbit * **New Features** * Added "Agents/x402 and AI" support option and an optional "Support ID in logs" field. * **Improvements** * Reorganized and simplified support forms: Wallets → Working with User Wallets, Transactions → API/SDKs, Tokens/Marketplace → Creating, Bridging and swapping tokens; token input accepts address or symbol. * Streamlined Connect and Engine flows with focused issue categories (social/email login, custom auth, account abstraction, third‑party wallets, API/SDK selection). * **Chores** * Removed legacy Contracts, Payments and affected-area form screens. --- .../support/_components/SupportTicketForm.tsx | 27 +--- .../connect/AffectedAreaInput.tsx | 67 -------- .../contact-forms/connect/index.tsx | 145 ++++++++---------- .../contact-forms/contracts/index.tsx | 138 ----------------- .../contact-forms/engine/index.tsx | 76 ++++----- .../_components/contact-forms/other/index.tsx | 1 + .../contact-forms/payments/index.tsx | 55 ------- .../tokens-marketplace/index.tsx | 13 +- 8 files changed, 118 insertions(+), 404 deletions(-) delete mode 100644 apps/dashboard/src/app/(app)/team/[team_slug]/(team)/~/support/_components/contact-forms/connect/AffectedAreaInput.tsx delete mode 100644 apps/dashboard/src/app/(app)/team/[team_slug]/(team)/~/support/_components/contact-forms/contracts/index.tsx delete mode 100644 apps/dashboard/src/app/(app)/team/[team_slug]/(team)/~/support/_components/contact-forms/payments/index.tsx diff --git a/apps/dashboard/src/app/(app)/team/[team_slug]/(team)/~/support/_components/SupportTicketForm.tsx b/apps/dashboard/src/app/(app)/team/[team_slug]/(team)/~/support/_components/SupportTicketForm.tsx index b623117fcad..967b2826698 100644 --- a/apps/dashboard/src/app/(app)/team/[team_slug]/(team)/~/support/_components/SupportTicketForm.tsx +++ b/apps/dashboard/src/app/(app)/team/[team_slug]/(team)/~/support/_components/SupportTicketForm.tsx @@ -26,14 +26,6 @@ const EngineSupportForm = dynamic( ssr: false, }, ); -const ContractSupportForm = dynamic( - () => - import("./contact-forms/contracts").then((mod) => mod.ContractSupportForm), - { - loading: () => , - ssr: false, - }, -); const AccountSupportForm = dynamic( () => import("./contact-forms/account").then((mod) => mod.AccountSupportForm), { @@ -48,14 +40,6 @@ const OtherSupportForm = dynamic( ssr: false, }, ); -const PaymentsSupportForm = dynamic( - () => - import("./contact-forms/payments").then((mod) => mod.PaymentsSupportForm), - { - loading: () => , - ssr: false, - }, -); const TokensMarketplaceSupportForm = dynamic( () => import("./contact-forms/tokens-marketplace").then( @@ -68,13 +52,14 @@ const TokensMarketplaceSupportForm = dynamic( ); const productOptions = [ - { component: , label: "Wallets" }, - { component: , label: "Transactions" }, - { component: , label: "Payments" }, - { component: , label: "Contracts" }, + { component: , label: "Working with User Wallets" }, + { + component: , + label: "Using API/SDK’s, errored transactions", + }, { component: , - label: "Tokens / Marketplace", + label: "Creating, Bridging and swapping tokens", }, { component: , label: "Account" }, { component: , label: "Other" }, diff --git a/apps/dashboard/src/app/(app)/team/[team_slug]/(team)/~/support/_components/contact-forms/connect/AffectedAreaInput.tsx b/apps/dashboard/src/app/(app)/team/[team_slug]/(team)/~/support/_components/contact-forms/connect/AffectedAreaInput.tsx deleted file mode 100644 index 9f0d8170098..00000000000 --- a/apps/dashboard/src/app/(app)/team/[team_slug]/(team)/~/support/_components/contact-forms/connect/AffectedAreaInput.tsx +++ /dev/null @@ -1,67 +0,0 @@ -"use client"; - -import { useState } from "react"; -import { DescriptionInput } from "../../shared/SupportForm_DescriptionInput"; -import { SupportForm_SelectInput } from "../../shared/SupportForm_SelectInput"; -import { SupportForm_TextInput } from "../../shared/SupportForm_TextInput"; -import { UnitySupportForm } from "../../shared/SupportForm_UnityInput"; - -const AFFECTED_AREAS = ["Dashboard", "Application"]; - -export const AffectedAreaInput = () => { - const [selectedAffectedArea, setSelectedAffectedArea] = useState(""); - const [selectedSDK, setSelectedSDK] = useState(""); - const [description, setDescription] = useState(""); - const [sdkDescription, setSdkDescription] = useState(""); - - return ( - <> - - {selectedAffectedArea && - (selectedAffectedArea === "Application" ? ( - <> - - {selectedSDK && ( - <> - {selectedSDK === "Unity" && } - - - - - )} - - ) : ( - - ))} - - ); -}; diff --git a/apps/dashboard/src/app/(app)/team/[team_slug]/(team)/~/support/_components/contact-forms/connect/index.tsx b/apps/dashboard/src/app/(app)/team/[team_slug]/(team)/~/support/_components/contact-forms/connect/index.tsx index 5bcd72eea3c..e2c69ba865c 100644 --- a/apps/dashboard/src/app/(app)/team/[team_slug]/(team)/~/support/_components/contact-forms/connect/index.tsx +++ b/apps/dashboard/src/app/(app)/team/[team_slug]/(team)/~/support/_components/contact-forms/connect/index.tsx @@ -1,116 +1,91 @@ +"use client"; + import { type ReactElement, useState } from "react"; import { DescriptionInput } from "../../shared/SupportForm_DescriptionInput"; import { SupportForm_SelectInput } from "../../shared/SupportForm_SelectInput"; import { SupportForm_TextInput } from "../../shared/SupportForm_TextInput"; -import { UnitySupportForm } from "../../shared/SupportForm_UnityInput"; -import { AffectedAreaInput } from "./AffectedAreaInput"; type ProblemAreaItem = { label: string; component: ReactElement; }; -const SDKVersionInput = () => ( - -); +const SocialEmailLoginIssuesComponent = () => { + const [description, setDescription] = useState(""); + return ( + <> + + + + ); +}; -const OSSelect = () => { - const [selectedOS, setSelectedOS] = useState(""); +const UserWalletCustomAuthComponent = () => { + const [description, setDescription] = useState(""); return ( - + <> + + + + ); }; -const DescriptionInputWrapper = () => { +const AccountAbstractionComponent = () => { + const [description, setDescription] = useState(""); + return ( + <> + + + + ); +}; + +const ThirdPartyEOAWalletsComponent = () => { const [description, setDescription] = useState(""); return ; }; const PROBLEM_AREAS: ProblemAreaItem[] = [ { - component: , - label: "In-app wallet login issues", - }, - { - component: , - label: "In-app wallet transaction issues", + component: , + label: "Social/Email login issues", }, { - component: , - label: "In-app wallet Custom Auth", + component: , + label: "User wallet with custom auth", }, { - component: , + component: , label: "Account Abstraction", }, { - component: ( - <> - - - - - ), - label: "thirdweb SDKs", - }, - { - component: ( - <> - - - - - ), - label: "Unity SDK", - }, - { - component: ( - <> - - - - - - - ), - label: ".NET SDK", - }, - { - component: , - label: "Pay", - }, - { - component: , - label: "Auth", + component: , + label: "Third party/EOA wallets", }, ]; diff --git a/apps/dashboard/src/app/(app)/team/[team_slug]/(team)/~/support/_components/contact-forms/contracts/index.tsx b/apps/dashboard/src/app/(app)/team/[team_slug]/(team)/~/support/_components/contact-forms/contracts/index.tsx deleted file mode 100644 index d9413073ed0..00000000000 --- a/apps/dashboard/src/app/(app)/team/[team_slug]/(team)/~/support/_components/contact-forms/contracts/index.tsx +++ /dev/null @@ -1,138 +0,0 @@ -import { type ReactElement, useState } from "react"; -import { DescriptionInput } from "../../shared/SupportForm_DescriptionInput"; -import { SupportForm_SelectInput } from "../../shared/SupportForm_SelectInput"; -import { SupportForm_TextInput } from "../../shared/SupportForm_TextInput"; - -type ProblemAreaItem = { - label: string; - component: ReactElement; -}; - -const NetworkInput = () => ( - -); - -const ContractAddressInput = () => ( - -); - -const ContractFunctionInput = () => ( - -); - -const ContractTypeInput = () => ( - -); - -const ContractAffectedAreaInput = () => { - const [selectedAffectedArea, setSelectedAffectedArea] = useState(""); - return ( - - ); -}; - -const DescriptionInputWrapper = () => { - const [description, setDescription] = useState(""); - return ; -}; - -const CONTRACT_PROBLEM_AREAS: ProblemAreaItem[] = [ - { - component: ( - <> - - - - - - ), - label: "Deploying a contract", - }, - { - component: ( - <> - - - - - - ), - label: "Contract verification", - }, - { - component: ( - <> - - - - - - - ), - label: "Calling a function in my contract", - }, - { - component: ( - <> - - - ), - label: "Developing a custom contract", - }, - { - component: ( - <> - - - ), - label: "Other", - }, -]; - -export function ContractSupportForm() { - const [problemArea, setProblemArea] = useState(""); - return ( - <> - o.label)} - promptText="Select a problem area" - required={true} - value={problemArea} - /> - {CONTRACT_PROBLEM_AREAS.find((o) => o.label === problemArea)?.component} - - ); -} diff --git a/apps/dashboard/src/app/(app)/team/[team_slug]/(team)/~/support/_components/contact-forms/engine/index.tsx b/apps/dashboard/src/app/(app)/team/[team_slug]/(team)/~/support/_components/contact-forms/engine/index.tsx index 4ba340c4614..beb718e0ef0 100644 --- a/apps/dashboard/src/app/(app)/team/[team_slug]/(team)/~/support/_components/contact-forms/engine/index.tsx +++ b/apps/dashboard/src/app/(app)/team/[team_slug]/(team)/~/support/_components/contact-forms/engine/index.tsx @@ -2,56 +2,62 @@ import { useState } from "react"; import { DescriptionInput } from "../../shared/SupportForm_DescriptionInput"; import { SupportForm_SelectInput } from "../../shared/SupportForm_SelectInput"; import { SupportForm_TextInput } from "../../shared/SupportForm_TextInput"; +import { UnitySupportForm } from "../../shared/SupportForm_UnityInput"; -const ENGINE_TYPES = ["Cloud (V3)", "Dedicated (V2)"]; -const ENGINE_PROBLEM_AREAS = [ - "SSL Issues", - "Transaction queueing issues", - "401 - Unauthorized", - "404 - Endpoint Not Found", - "Other", +const API_SDK_OPTIONS = [ + "API endpoint", + "React/TypeScript", + "Unity/.NET", + "React Native", ]; export function EngineSupportForm() { - const [selectedEngineType, setSelectedEngineType] = useState(""); - const [problemArea, setProblemArea] = useState(""); + const [selectedSDK, setSelectedSDK] = useState(""); const [description, setDescription] = useState(""); return ( <> {" "} - {selectedEngineType && ( + value={selectedSDK} + /> + {selectedSDK && ( <> - - - {problemArea && ( - <> + {selectedSDK === "Unity/.NET" ? ( + + ) : ( + selectedSDK !== "API endpoint" && ( - - + ) + )} + + {selectedSDK === "API endpoint" && ( + )} + )} diff --git a/apps/dashboard/src/app/(app)/team/[team_slug]/(team)/~/support/_components/contact-forms/other/index.tsx b/apps/dashboard/src/app/(app)/team/[team_slug]/(team)/~/support/_components/contact-forms/other/index.tsx index 075b94f55a1..e0a4b474ea7 100644 --- a/apps/dashboard/src/app/(app)/team/[team_slug]/(team)/~/support/_components/contact-forms/other/index.tsx +++ b/apps/dashboard/src/app/(app)/team/[team_slug]/(team)/~/support/_components/contact-forms/other/index.tsx @@ -14,6 +14,7 @@ const OTHER_PROBLEM_AREAS = [ "Bug report", "Documentation", "Integration help", + "Agents/x402 and AI", "Other", ]; export function OtherSupportForm() { diff --git a/apps/dashboard/src/app/(app)/team/[team_slug]/(team)/~/support/_components/contact-forms/payments/index.tsx b/apps/dashboard/src/app/(app)/team/[team_slug]/(team)/~/support/_components/contact-forms/payments/index.tsx deleted file mode 100644 index 052245261b1..00000000000 --- a/apps/dashboard/src/app/(app)/team/[team_slug]/(team)/~/support/_components/contact-forms/payments/index.tsx +++ /dev/null @@ -1,55 +0,0 @@ -"use client"; - -import { useState } from "react"; -import { DescriptionInput } from "../../shared/SupportForm_DescriptionInput"; -import { SupportForm_SelectInput } from "../../shared/SupportForm_SelectInput"; -import { SupportForm_TextInput } from "../../shared/SupportForm_TextInput"; - -const PAYMENT_AREAS = ["Dashboard", "Application"]; - -export function PaymentsSupportForm() { - const [area, setArea] = useState(""); - const [description, setDescription] = useState(""); - - return ( - <> - - {area === "Application" && ( - <> - - - - - )} - {(area === "Application" || area === "Dashboard") && ( - - )} - - ); -} diff --git a/apps/dashboard/src/app/(app)/team/[team_slug]/(team)/~/support/_components/contact-forms/tokens-marketplace/index.tsx b/apps/dashboard/src/app/(app)/team/[team_slug]/(team)/~/support/_components/contact-forms/tokens-marketplace/index.tsx index 89d80267649..911b886bdfd 100644 --- a/apps/dashboard/src/app/(app)/team/[team_slug]/(team)/~/support/_components/contact-forms/tokens-marketplace/index.tsx +++ b/apps/dashboard/src/app/(app)/team/[team_slug]/(team)/~/support/_components/contact-forms/tokens-marketplace/index.tsx @@ -8,10 +8,10 @@ export function TokensMarketplaceSupportForm() { return ( <> + ); From 5080b4707ffbcbf20724f633d6a55b62ee46275f Mon Sep 17 00:00:00 2001 From: MananTank Date: Fri, 14 Nov 2025 21:08:47 +0000 Subject: [PATCH 2/4] [PRO-98] Update Project FTUX UI (#8418) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ## PR-Codex overview This PR primarily focuses on updating the UI components by replacing the `NebulaIcon` with `BotIcon`, enhancing styling, and refactoring code for better readability and functionality across various components. ### Detailed summary - Replaced `NebulaIcon` with `BotIcon` in multiple components. - Improved styles for headings and paragraphs in `ClientIDSection` and `SecretKeySection`. - Updated layout properties in `ProjectWalletSection` and other components. - Added a new `CodeShowcase` component to display code examples. - Enhanced `ProjectFTUX` to accept a `projectWalletSection` prop. - Refactored several components for better structure and readability. - Adjusted margins and paddings for improved UI consistency. > ✨ Ask PR-Codex anything about this PR by commenting with `/codex {your question}` ## Summary by CodeRabbit * **New Features** * Multi-language code showcase with a language selector for integration examples * Configurable wallet layouts and ability to inject a wallet area into onboarding/FTUX * **UI/UX Improvements** * Refined spacing, typography, and responsive layouts across project pages and sidebar * Added popular framework/product brand icons; replaced several AI/sidebar icons with a unified Bot icon * Simplified sidebar footer links and adjusted paddings and avatar sizes * **Chores** * Updated story examples to include new layout args --- .../blocks/full-width-sidebar-layout.tsx | 2 +- .../project-page/project-page-header.tsx | 5 +- .../blocks/project-page/project-page.tsx | 14 +- apps/dashboard/src/@/icons/NebulaIcon.tsx | 24 -- .../src/@/icons/brand-icons/ExpoIcon.tsx | 21 ++ .../src/@/icons/brand-icons/NextjsIcon.tsx | 59 +++ .../src/@/icons/brand-icons/NodeJSIcon.tsx | 20 + .../src/@/icons/brand-icons/ViteIcon.tsx | 23 ++ .../(chain)/components/server/products.ts | 4 +- .../analytics/chart/AiTokenUsageChartCard.tsx | 4 +- .../(sidebar)/ai/analytics/page.tsx | 4 +- .../(sidebar)/ai/components/ChatSidebar.tsx | 4 +- .../(sidebar)/ai/components/Chats.tsx | 7 +- .../components/EmptyStateChatPageContent.tsx | 5 +- .../ProjectFTUX/ClientIDSection.tsx | 4 +- .../components/ProjectFTUX/CodeSelector.tsx | 45 +++ .../ProjectFTUX/ProjectFTUX.stories.tsx | 1 + .../components/ProjectFTUX/ProjectFTUX.tsx | 349 +++++++++++------- .../ProjectFTUX/SecretKeySection.tsx | 8 +- .../components/ProjectSidebarLayout.tsx | 23 +- .../project-wallet/project-wallet-details.tsx | 4 +- .../project-wallet/project-wallet.stories.tsx | 6 + .../project-wallet/project-wallet.tsx | 41 +- .../[project_slug]/(sidebar)/page.tsx | 54 ++- 24 files changed, 503 insertions(+), 228 deletions(-) delete mode 100644 apps/dashboard/src/@/icons/NebulaIcon.tsx create mode 100644 apps/dashboard/src/@/icons/brand-icons/ExpoIcon.tsx create mode 100644 apps/dashboard/src/@/icons/brand-icons/NextjsIcon.tsx create mode 100644 apps/dashboard/src/@/icons/brand-icons/NodeJSIcon.tsx create mode 100644 apps/dashboard/src/@/icons/brand-icons/ViteIcon.tsx create mode 100644 apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/components/ProjectFTUX/CodeSelector.tsx diff --git a/apps/dashboard/src/@/components/blocks/full-width-sidebar-layout.tsx b/apps/dashboard/src/@/components/blocks/full-width-sidebar-layout.tsx index 892d6ba1671..26ce5518be2 100644 --- a/apps/dashboard/src/@/components/blocks/full-width-sidebar-layout.tsx +++ b/apps/dashboard/src/@/components/blocks/full-width-sidebar-layout.tsx @@ -67,7 +67,7 @@ export function FullWidthSidebarLayout(props: { )} > {/* left - sidebar */} - + diff --git a/apps/dashboard/src/@/components/blocks/project-page/project-page-header.tsx b/apps/dashboard/src/@/components/blocks/project-page/project-page-header.tsx index 6a027f917f4..f7877cfbca3 100644 --- a/apps/dashboard/src/@/components/blocks/project-page/project-page-header.tsx +++ b/apps/dashboard/src/@/components/blocks/project-page/project-page-header.tsx @@ -66,13 +66,16 @@ export type ProjectPageHeaderProps = { href: string; }; + className?: string; // TODO: add task card component task?: never; }; export function ProjectPageHeader(props: ProjectPageHeaderProps) { return ( -
+
{/* top row */}
{/* left - icon */} diff --git a/apps/dashboard/src/@/components/blocks/project-page/project-page.tsx b/apps/dashboard/src/@/components/blocks/project-page/project-page.tsx index f72bf644ed0..fa2f04083f0 100644 --- a/apps/dashboard/src/@/components/blocks/project-page/project-page.tsx +++ b/apps/dashboard/src/@/components/blocks/project-page/project-page.tsx @@ -13,13 +13,19 @@ type ProjectPageProps = { header: ProjectPageHeaderProps; footer?: ProjectPageFooterProps; tabs?: TabPathLink[]; + containerClassName?: string; }; export function ProjectPage(props: React.PropsWithChildren) { return (
- + 0 ? "pt-8 pb-6" : "py-8", + )} + /> {props.tabs && ( ) { )}
-
{props.children}
+
+ {props.children} +
{props.footer && (
diff --git a/apps/dashboard/src/@/icons/NebulaIcon.tsx b/apps/dashboard/src/@/icons/NebulaIcon.tsx deleted file mode 100644 index 1a59d089f01..00000000000 --- a/apps/dashboard/src/@/icons/NebulaIcon.tsx +++ /dev/null @@ -1,24 +0,0 @@ -export function NebulaIcon(props: { className?: string }) { - return ( - - - - - ); -} diff --git a/apps/dashboard/src/@/icons/brand-icons/ExpoIcon.tsx b/apps/dashboard/src/@/icons/brand-icons/ExpoIcon.tsx new file mode 100644 index 00000000000..3b45bc2cab5 --- /dev/null +++ b/apps/dashboard/src/@/icons/brand-icons/ExpoIcon.tsx @@ -0,0 +1,21 @@ +export function ExpoIcon(props: { className?: string }) { + return ( + + ); +} diff --git a/apps/dashboard/src/@/icons/brand-icons/NextjsIcon.tsx b/apps/dashboard/src/@/icons/brand-icons/NextjsIcon.tsx new file mode 100644 index 00000000000..0fd37729730 --- /dev/null +++ b/apps/dashboard/src/@/icons/brand-icons/NextjsIcon.tsx @@ -0,0 +1,59 @@ +export function NextjsIcon(props: { className?: string }) { + return ( + + ); +} diff --git a/apps/dashboard/src/@/icons/brand-icons/NodeJSIcon.tsx b/apps/dashboard/src/@/icons/brand-icons/NodeJSIcon.tsx new file mode 100644 index 00000000000..0f430bee249 --- /dev/null +++ b/apps/dashboard/src/@/icons/brand-icons/NodeJSIcon.tsx @@ -0,0 +1,20 @@ +export function NodeJSIcon(props: { className?: string }) { + return ( + + ); +} diff --git a/apps/dashboard/src/@/icons/brand-icons/ViteIcon.tsx b/apps/dashboard/src/@/icons/brand-icons/ViteIcon.tsx new file mode 100644 index 00000000000..d08367f5d9f --- /dev/null +++ b/apps/dashboard/src/@/icons/brand-icons/ViteIcon.tsx @@ -0,0 +1,23 @@ +export function ViteIcon(props: { className?: string }) { + return ( + + ); +} diff --git a/apps/dashboard/src/app/(app)/(dashboard)/(chain)/components/server/products.ts b/apps/dashboard/src/app/(app)/(dashboard)/(chain)/components/server/products.ts index b425f8219d1..fcdb457611c 100644 --- a/apps/dashboard/src/app/(app)/(dashboard)/(chain)/components/server/products.ts +++ b/apps/dashboard/src/app/(app)/(dashboard)/(chain)/components/server/products.ts @@ -1,7 +1,7 @@ +import { BotIcon } from "lucide-react"; import { ConnectSDKIcon } from "@/icons/ConnectSDKIcon"; import { ContractIcon } from "@/icons/ContractIcon"; import { EngineIcon } from "@/icons/EngineIcon"; -import { NebulaIcon } from "@/icons/NebulaIcon"; import { PayIcon } from "@/icons/PayIcon"; import { RPCIcon } from "@/icons/RPCIcon"; import { SmartAccountIcon } from "@/icons/SmartAccountIcon"; @@ -52,7 +52,7 @@ export const products = [ }, { description: "The most powerful AI for interacting with the blockchain", - icon: NebulaIcon, + icon: BotIcon, id: "nebula", link: "https://thirdweb.com/ai", name: "thirdweb AI", diff --git a/apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/ai/analytics/chart/AiTokenUsageChartCard.tsx b/apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/ai/analytics/chart/AiTokenUsageChartCard.tsx index b38e0505a6c..c5ca8895970 100644 --- a/apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/ai/analytics/chart/AiTokenUsageChartCard.tsx +++ b/apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/ai/analytics/chart/AiTokenUsageChartCard.tsx @@ -1,11 +1,11 @@ "use client"; import { format } from "date-fns"; +import { BotIcon } from "lucide-react"; import { useMemo } from "react"; import { ThirdwebBarChart } from "@/components/blocks/charts/bar-chart"; import { DocLink } from "@/components/blocks/DocLink"; import { ExportToCSVButton } from "@/components/blocks/ExportToCSVButton"; import type { ChartConfig } from "@/components/ui/chart"; -import { NebulaIcon } from "@/icons/NebulaIcon"; import type { AIUsageStats } from "@/types/analytics"; type ChartData = Record & { @@ -106,7 +106,7 @@ function AiTokenUsageEmptyChartState() {
diff --git a/apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/ai/analytics/page.tsx b/apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/ai/analytics/page.tsx index 2f818455eec..661426788dd 100644 --- a/apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/ai/analytics/page.tsx +++ b/apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/ai/analytics/page.tsx @@ -1,3 +1,4 @@ +import { BotIcon } from "lucide-react"; import { redirect } from "next/navigation"; import { ResponsiveSearchParamsProvider } from "responsive-rsc"; import { getAuthToken } from "@/api/auth-token"; @@ -6,7 +7,6 @@ import type { DurationId } from "@/components/analytics/date-range-selector"; import { ResponsiveTimeFilters } from "@/components/analytics/responsive-time-filters"; import { ProjectPage } from "@/components/blocks/project-page/project-page"; import { getClientThirdwebClient } from "@/constants/thirdweb-client.client"; -import { NebulaIcon } from "@/icons/NebulaIcon"; import { getFiltersFromSearchParams } from "@/lib/time"; import { loginRedirect } from "@/utils/redirects"; import { AiAnalytics } from "./chart"; @@ -58,7 +58,7 @@ export default async function Page(props: {
- + thirdweb AI
diff --git a/apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/ai/components/Chats.tsx b/apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/ai/components/Chats.tsx index f5c41ed3440..7dc23ca4b67 100644 --- a/apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/ai/components/Chats.tsx +++ b/apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/ai/components/Chats.tsx @@ -1,10 +1,9 @@ import { MarkdownRenderer } from "@workspace/ui/components/markdown-renderer"; import { ScrollShadow } from "@workspace/ui/components/scroll-shadow"; -import { AlertCircleIcon } from "lucide-react"; +import { AlertCircleIcon, BotIcon } from "lucide-react"; import { useEffect, useRef } from "react"; import type { ThirdwebClient } from "thirdweb"; import type { Project } from "@/api/project/projects"; -import { NebulaIcon } from "@/icons/NebulaIcon"; import { cn } from "@/lib/utils"; import type { NebulaSwapData, @@ -238,11 +237,11 @@ function RenderMessage(props: { )} > {message.type === "presence" && ( - + )} {message.type === "assistant" && ( - + )} {message.type === "error" && ( diff --git a/apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/ai/components/EmptyStateChatPageContent.tsx b/apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/ai/components/EmptyStateChatPageContent.tsx index b2614f74ee9..ad0c25a9578 100644 --- a/apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/ai/components/EmptyStateChatPageContent.tsx +++ b/apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/ai/components/EmptyStateChatPageContent.tsx @@ -1,9 +1,8 @@ "use client"; -import { ArrowUpRightIcon, InfoIcon } from "lucide-react"; +import { ArrowUpRightIcon, BotIcon, InfoIcon } from "lucide-react"; import type { ThirdwebClient } from "thirdweb"; import { Button } from "@/components/ui/button"; -import { NebulaIcon } from "@/icons/NebulaIcon"; import { cn } from "@/lib/utils"; import type { NebulaContext, NebulaUserMessage } from "../api/types"; import { examplePrompts } from "../data/examplePrompts"; @@ -33,7 +32,7 @@ export function EmptyStateChatPageContent(props: {
- +
diff --git a/apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/components/ProjectFTUX/ClientIDSection.tsx b/apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/components/ProjectFTUX/ClientIDSection.tsx index 0dd8e8119f4..d9f9d0bc1f3 100644 --- a/apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/components/ProjectFTUX/ClientIDSection.tsx +++ b/apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/components/ProjectFTUX/ClientIDSection.tsx @@ -3,8 +3,8 @@ import { CopyTextButton } from "@/components/ui/CopyTextButton"; export function ClientIDSection(props: { clientId: string }) { return (
-

Client ID

-

+

Client ID

+

Identifies your application

diff --git a/apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/components/ProjectFTUX/CodeSelector.tsx b/apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/components/ProjectFTUX/CodeSelector.tsx new file mode 100644 index 00000000000..4c6d4fd6e8d --- /dev/null +++ b/apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/components/ProjectFTUX/CodeSelector.tsx @@ -0,0 +1,45 @@ +"use client"; + +import { useState } from "react"; +import { + Select, + SelectContent, + SelectItem, + SelectTrigger, + SelectValue, +} from "@/components/ui/select"; + +export function CodeShowcase(props: { + title: string; + tabs: Array<{ + label: string; + code: React.ReactNode; + }>; +}) { + const [selectedTab, setSelectedTab] = useState(props.tabs[0]?.label || ""); + + return ( +
+
+

{props.title}

+ +
+ + {props.tabs.find((tab) => tab.label === selectedTab)?.code} +
+ ); +} diff --git a/apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/components/ProjectFTUX/ProjectFTUX.stories.tsx b/apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/components/ProjectFTUX/ProjectFTUX.stories.tsx index e48d6d82575..190484c7c55 100644 --- a/apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/components/ProjectFTUX/ProjectFTUX.stories.tsx +++ b/apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/components/ProjectFTUX/ProjectFTUX.stories.tsx @@ -24,6 +24,7 @@ type Story = StoryObj; export const Default: Story = { args: { + projectWalletSection: undefined, project: { ...projectStub("foo", "bar"), secretKeys: [ diff --git a/apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/components/ProjectFTUX/ProjectFTUX.tsx b/apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/components/ProjectFTUX/ProjectFTUX.tsx index b1f51f3857f..5ddec808e09 100644 --- a/apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/components/ProjectFTUX/ProjectFTUX.tsx +++ b/apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/components/ProjectFTUX/ProjectFTUX.tsx @@ -1,26 +1,40 @@ +import { Button } from "@workspace/ui/components/button"; +import { CodeServer } from "@workspace/ui/components/code/code.server"; import { - ArrowLeftRightIcon, + ArrowUpRightIcon, + BotIcon, ChevronRightIcon, - ExternalLinkIcon, + CoinsIcon, + DoorOpenIcon, } from "lucide-react"; import Link from "next/link"; import type { Project } from "@/api/project/projects"; -import { CodeServer } from "@/components/ui/code/code.server"; +import { BridgeIcon } from "@/icons/BridgeIcon"; import { DotNetIcon } from "@/icons/brand-icons/DotNetIcon"; -import { GithubIcon } from "@/icons/brand-icons/GithubIcon"; +import { ExpoIcon } from "@/icons/brand-icons/ExpoIcon"; +import { NextjsIcon } from "@/icons/brand-icons/NextjsIcon"; +import { NodeJSIcon } from "@/icons/brand-icons/NodeJSIcon"; import { ReactIcon } from "@/icons/brand-icons/ReactIcon"; import { TypeScriptIcon } from "@/icons/brand-icons/TypeScriptIcon"; import { UnityIcon } from "@/icons/brand-icons/UnityIcon"; import { UnrealIcon } from "@/icons/brand-icons/UnrealIcon"; -import { ContractIcon } from "@/icons/ContractIcon"; +import { ViteIcon } from "@/icons/brand-icons/ViteIcon"; import { PayIcon } from "@/icons/PayIcon"; +import { WalletProductIcon } from "@/icons/WalletProductIcon"; import { ClientIDSection } from "./ClientIDSection"; +import { CodeShowcase } from "./CodeSelector"; import { SecretKeySection } from "./SecretKeySection"; -export function ProjectFTUX(props: { project: Project; teamSlug: string }) { +export function ProjectFTUX(props: { + project: Project; + teamSlug: string; + projectWalletSection: React.ReactNode; +}) { return ( -
+
+ {props.projectWalletSection} + -

- Integrate API key -

+
+
+

API Keys

+

+ Your API key is used to authenticate and integrate your application. +

+ +
-
+
{secretKeyMasked && ( @@ -53,23 +84,74 @@ function IntegrateAPIKeySection({ project }: { project: Project }) { /> )}
+
+
+ ); +} -
-
-

- Run this command in your terminal to send a test transaction using - your Project Wallet. -

- -
+function GetStartedSection({ project }: { project: Project }) { + return ( +
+
+

+ Get Started +

+

+ Send a test transaction using your project wallet +

+ +
+ + + ), + }, + { + label: "JavaScript", + code: ( + + ), + }, + { + label: "Python", + code: ( + + ), + }, + ]} + />
); } + const curlCodeExample = (project: Project): string => `\ curl https://api.thirdweb.com/v1/transactions \\ --request POST \\ @@ -87,6 +169,40 @@ curl https://api.thirdweb.com/v1/transactions \\ }' `; +const fetchJSCodeExample = (project: Project): string => `\ +fetch("https://github.com/service/https://api.thirdweb.com/v1/transactions", { + method: "POST", + headers: { + "Content-Type": "application/json", + "x-secret-key": "${project.secretKeys[0]?.masked ?? ""}", + }, + body: JSON.stringify({ + chainId: 421614, + transactions: [ + { data: "0x", to: "vitalik.eth", value: "0" }, + ], + }), +}); +`; + +const pythonCodeExample = (project: Project): string => `\ +import requests + +url = "https://api.thirdweb.com/v1/transactions" +headers = { + "Content-Type": "application/json", + "x-secret-key": "${project.secretKeys[0]?.masked ?? ""}", +} +payload = { + "chainId": 421614, + "transactions": [ + { "data": "0x", "to": "vitalik.eth", "value": "0" }, + ], +} +response = requests.post(url, headers=headers, json=payload) +result = response.json() +`; + // products section ------------------------------------------------------------ function ProductsSection(props: { teamSlug: string; projectSlug: string }) { @@ -97,49 +213,60 @@ function ProductsSection(props: { teamSlug: string; projectSlug: string }) { icon: React.FC<{ className?: string }>; }> = [ { - description: - "Scale your application with a backend server to read, write, and deploy contracts at production-grade.", - href: `/team/${props.teamSlug}/${props.projectSlug}/transactions`, - icon: ArrowLeftRightIcon, - title: "Transactions", + icon: WalletProductIcon, + title: "Wallets", + description: "Wallets to read, write and transact", + href: `/team/${props.teamSlug}/${props.projectSlug}/wallets/user-wallets`, }, { - description: - "Deploy your own contracts or leverage existing solutions for onchain implementation", - href: `/team/${props.teamSlug}/${props.projectSlug}/contracts`, - icon: ContractIcon, - title: "Contracts", + icon: BridgeIcon, + title: "Bridge", + description: "Swap and bridge tokens", + href: `/team/${props.teamSlug}/${props.projectSlug}/bridge`, }, { - description: - "Bridge, swap, and purchase cryptocurrencies with any fiat options or tokens via cross-chain routing", - href: `/team/${props.teamSlug}/${props.projectSlug}/payments`, icon: PayIcon, - title: "Payments", + title: "x402", + description: "Native internet payments", + href: `/team/${props.teamSlug}/${props.projectSlug}/x402`, + }, + { + icon: DoorOpenIcon, + title: "Gateway", + description: "Blockchain connectivity and data access", + href: `/team/${props.teamSlug}/${props.projectSlug}/gateway/rpc`, + }, + { + icon: CoinsIcon, + title: "Tokens", + description: "Launch tokens and markets", + href: `/team/${props.teamSlug}/${props.projectSlug}/tokens`, + }, + { + icon: BotIcon, + title: "AI", + description: "Read and write onchain via AI agents", + href: `/team/${props.teamSlug}/${props.projectSlug}/ai`, }, ]; return (
-

- Complete your full-stack application -

-

- Tools to build frontend, backend, and onchain with built-in - infrastructure and analytics. +

Products

+

+ Everything you need to build full-stack applications, games, and agents.

- {/* Feature Cards */} -
+
{products.map((product) => ( - ))}
@@ -147,72 +274,51 @@ function ProductsSection(props: { teamSlug: string; projectSlug: string }) { ); } -function ProductCard(props: { - title: string; - description: string; - href: string; - icon: React.FC<{ className?: string }>; -}) { - return ( -
-
- -
-

- - {props.title} - -

-

{props.description}

-
- ); -} - // sdk section ------------------------------------------------------------ -type SDKCardProps = { +type IconCardProps = { name: string; + description: string | undefined; href: string; icon: React.FC<{ className?: string }>; - trackingLabel: string; }; -const sdks: SDKCardProps[] = [ +const sdks: IconCardProps[] = [ { href: "https://portal.thirdweb.com/sdk/typescript", icon: TypeScriptIcon, name: "TypeScript", - trackingLabel: "typescript", + description: undefined, }, { href: "https://portal.thirdweb.com/react/v5", icon: ReactIcon, name: "React", - trackingLabel: "react", + description: undefined, }, { href: "https://portal.thirdweb.com/react-native/v5", icon: ReactIcon, name: "React Native", - trackingLabel: "react_native", + description: undefined, }, { href: "https://portal.thirdweb.com/unity/v5", icon: UnityIcon, name: "Unity", - trackingLabel: "unity", + description: undefined, }, { href: "https://portal.thirdweb.com/unreal-engine", icon: UnrealIcon, name: "Unreal Engine", - trackingLabel: "unreal", + description: undefined, }, { href: "https://portal.thirdweb.com/dotnet", icon: DotNetIcon, name: ".NET", - trackingLabel: "dotnet", + description: undefined, }, ]; @@ -220,14 +326,14 @@ function SDKSection() { return (

Client SDKs

-
+
{sdks.map((sdk) => ( - ))}
@@ -235,10 +341,10 @@ function SDKSection() { ); } -function SDKCard(props: SDKCardProps) { +function IconCard(props: IconCardProps) { return ( -
-
+
+
@@ -246,16 +352,14 @@ function SDKCard(props: SDKCardProps) { {props.name}

-

- View Docs - -

+ {props.description && ( +

{props.description}

+ )}
); @@ -263,42 +367,47 @@ function SDKCard(props: SDKCardProps) { // starter kits section ------------------------------------------------------------ -type StartedKitCardProps = { - name: string; - href: string; - trackingLabel: string; -}; - -const startedKits: StartedKitCardProps[] = [ +const startedKits: IconCardProps[] = [ { href: "https://github.com/thirdweb-example/next-starter", name: "Next Starter", - trackingLabel: "next_starter", + icon: NextjsIcon, + description: undefined, }, { href: "https://github.com/thirdweb-example/vite-starter", name: "Vite Starter", - trackingLabel: "vite_starter", + icon: ViteIcon, + description: undefined, }, { href: "https://github.com/thirdweb-example/expo-starter", name: "Expo Starter", - trackingLabel: "expo_starter", + icon: ExpoIcon, + description: undefined, }, { href: "https://github.com/thirdweb-example/node-starter", name: "Node Starter", - trackingLabel: "node_starter", + icon: NodeJSIcon, + description: undefined, }, ]; function StarterKitsSection() { return (
-
-

Starter Kits

+
+
+

+ Starters +

+

+ Kickstart your development process with ready-to-ship repositories. +

+
-
+
{startedKits.map((kit) => ( - ))}
); } - -function StarterKitCard(props: StartedKitCardProps) { - return ( -
-
- -
- -
- - {props.name} - -

- View Repo - -

-
-
- ); -} diff --git a/apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/components/ProjectFTUX/SecretKeySection.tsx b/apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/components/ProjectFTUX/SecretKeySection.tsx index 3a6f24c9294..f7b6e4df883 100644 --- a/apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/components/ProjectFTUX/SecretKeySection.tsx +++ b/apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/components/ProjectFTUX/SecretKeySection.tsx @@ -13,15 +13,15 @@ export function SecretKeySection(props: { return (
-

Secret Key

-

+

Secret Key

+

Identifies and authenticates your application from a backend.
{" "} This is not the full secret key, Refer to your saved secret key at the time of creation for the full secret key.

-
-
+
+
{secretKeyMasked}
diff --git a/apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/components/ProjectSidebarLayout.tsx b/apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/components/ProjectSidebarLayout.tsx index 009229c4ac2..bd40487cb3e 100644 --- a/apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/components/ProjectSidebarLayout.tsx +++ b/apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/components/ProjectSidebarLayout.tsx @@ -1,11 +1,10 @@ "use client"; import { Badge } from "@workspace/ui/components/badge"; import { - BookTextIcon, - BoxIcon, + BotIcon, DatabaseIcon, + DoorOpenIcon, HomeIcon, - RssIcon, Settings2Icon, WebhookIcon, } from "lucide-react"; @@ -15,7 +14,6 @@ import { } from "@/components/blocks/full-width-sidebar-layout"; import { BridgeIcon } from "@/icons/BridgeIcon"; import { ContractIcon } from "@/icons/ContractIcon"; -import { NebulaIcon } from "@/icons/NebulaIcon"; import { PayIcon } from "@/icons/PayIcon"; import { TokenIcon } from "@/icons/TokenIcon"; import { WalletProductIcon } from "@/icons/WalletProductIcon"; @@ -81,12 +79,12 @@ export function ProjectSidebarLayout(props: { }, { href: `${props.layoutPath}/ai`, - icon: NebulaIcon, + icon: BotIcon, label: "AI", }, { subMenu: { - icon: RssIcon, + icon: DoorOpenIcon, label: "Gateway", }, links: [ @@ -129,19 +127,6 @@ export function ProjectSidebarLayout(props: { icon: Settings2Icon, label: "Project Settings", }, - { - separator: true, - }, - { - href: "https://portal.thirdweb.com/", - icon: BookTextIcon, - label: "Documentation", - }, - { - href: "https://playground.thirdweb.com/wallets/sign-in/button", - icon: BoxIcon, - label: "Playground", - }, ] satisfies ShadcnSidebarLink[]; return ( diff --git a/apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/components/project-wallet/project-wallet-details.tsx b/apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/components/project-wallet/project-wallet-details.tsx index 819d0c652f4..38f5d8da1c1 100644 --- a/apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/components/project-wallet/project-wallet-details.tsx +++ b/apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/components/project-wallet/project-wallet-details.tsx @@ -177,7 +177,7 @@ export function ProjectWalletDetailsSection(props: ProjectWalletControlsProps) { -
+

Wallet Address

-
+

Balance

diff --git a/apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/components/project-wallet/project-wallet.stories.tsx b/apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/components/project-wallet/project-wallet.stories.tsx index 750c51f3328..4d64cb51ca8 100644 --- a/apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/components/project-wallet/project-wallet.stories.tsx +++ b/apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/components/project-wallet/project-wallet.stories.tsx @@ -49,6 +49,7 @@ const projectWallet2: ProjectWalletSummary = { export const NoProjectWalletSetNoManagedAccessToken: Story = { args: { + layout: "column", project: projectWithoutManagedAccessToken, client: storybookThirdwebClient, teamSlug: "bar", @@ -62,6 +63,7 @@ export const NoProjectWalletSetNoManagedAccessToken: Story = { export const NoProjectWalletSetWithManagedAccessToken: Story = { args: { + layout: "column", project: projectWithManagedAccessToken, client: storybookThirdwebClient, teamSlug: "bar", @@ -75,6 +77,7 @@ export const NoProjectWalletSetWithManagedAccessToken: Story = { export const NoProjectWalletSetWithManagedAccessTokenAndServerWallets: Story = { args: { + layout: "column", project: projectWithManagedAccessToken, teamSlug: "bar", client: storybookThirdwebClient, @@ -88,6 +91,7 @@ export const NoProjectWalletSetWithManagedAccessTokenAndServerWallets: Story = { export const NoProjectWalletSetLoading: Story = { args: { + layout: "column", project: projectWithManagedAccessToken, teamSlug: "bar", client: storybookThirdwebClient, @@ -101,6 +105,7 @@ export const NoProjectWalletSetLoading: Story = { export const ProjectWalletSetMultipleServerWallets: Story = { args: { + layout: "column", project: projectWithManagedAccessToken, teamSlug: "bar", client: storybookThirdwebClient, @@ -114,6 +119,7 @@ export const ProjectWalletSetMultipleServerWallets: Story = { export const ProjectWalletSetSingleServerWallet: Story = { args: { + layout: "column", project: projectWithManagedAccessToken, teamSlug: "bar", projectWallet: projectWallet1, diff --git a/apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/components/project-wallet/project-wallet.tsx b/apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/components/project-wallet/project-wallet.tsx index e2a44ce2208..8175644e889 100644 --- a/apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/components/project-wallet/project-wallet.tsx +++ b/apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/components/project-wallet/project-wallet.tsx @@ -2,7 +2,8 @@ import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query"; import { UnderlineLink } from "@workspace/ui/components/UnderlineLink"; -import { ChevronDownIcon, XIcon } from "lucide-react"; +import { ArrowUpRightIcon, ChevronDownIcon, XIcon } from "lucide-react"; +import Link from "next/link"; import { useMemo, useState } from "react"; import { toast } from "sonner"; import type { ThirdwebClient } from "thirdweb"; @@ -29,6 +30,7 @@ import { Skeleton } from "@/components/ui/skeleton"; import { getClientThirdwebClient } from "@/constants/thirdweb-client.client"; import { useDashboardRouter } from "@/lib/DashboardRouter"; import type { ProjectWalletSummary } from "@/lib/server/project-wallet"; +import { cn } from "@/lib/utils"; import { updateDefaultProjectWallet } from "../../transactions/lib/vault.client"; import { CreateServerWallet } from "../../transactions/server-wallets/components/create-server-wallet.client"; import { ProjectWalletDetailsSection } from "./project-wallet-details"; @@ -131,11 +133,11 @@ function CreateProjectWalletSection(props: { Boolean(managementAccessToken) && serverWallets.length > 0; return ( -
+
- +
-

+

No Project Wallet set

@@ -276,10 +278,17 @@ export function ProjectWalletSectionUI(props: { projectWallet: ProjectWalletSummary | undefined; getProjectServerWallets: GetProjectServerWallets; client: ThirdwebClient; + layout: "row" | "column"; }) { return ( -

-
+
+

Project Wallet

@@ -292,6 +301,24 @@ export function ProjectWalletSectionUI(props: { thirdweb API

+ {props.layout === "row" && ( +
+ +
+ )}
{props.projectWallet ? ( @@ -318,6 +345,7 @@ export function ProjectWalletSection(props: { teamSlug: string; projectWallet: ProjectWalletSummary | undefined; client: ThirdwebClient; + layout: "row" | "column"; }) { return ( ); } diff --git a/apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/page.tsx b/apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/page.tsx index 3226572d485..ff2b14933a3 100644 --- a/apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/page.tsx +++ b/apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/page.tsx @@ -119,7 +119,7 @@ export default async function ProjectOverviewPage(props: PageProps) { isProjectIcon: true, icon: () => ( @@ -130,30 +130,44 @@ export default async function ProjectOverviewPage(props: PageProps) { actions: null, }} > - - -
- {isActive ? ( -
- - + +
+ + +
) : ( - +
+ + } + /> +
)} From b06a9184c10cc0caa40a0bf4895282576b31d094 Mon Sep 17 00:00:00 2001 From: MananTank Date: Fri, 14 Nov 2025 21:08:47 +0000 Subject: [PATCH 3/4] [PRO-105] Dashboard: Update service names (#8419) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ## PR-Codex overview This PR focuses on renaming and refactoring the usage of `products` to `services` across various components, updating service definitions, and improving the rendering of product cards in the UI. ### Detailed summary - Renamed `products` to `services` in relevant components. - Updated service definitions with new titles and descriptions. - Modified the `ChainListRow` and `ChainServiceFilter` components to use `services`. - Enhanced `SupportedProductsSection` to conditionally render `ProductCard`. - Added new `ProductCard` component for UI rendering. > ✨ Ask PR-Codex anything about this PR by commenting with `/codex {your question}` --- apps/dashboard/src/@/icons/ConnectSDKIcon.tsx | 21 --- .../server/SupportedProductsSection.tsx | 135 +++++++++++++----- .../chainlist/components/client/filters.tsx | 6 +- .../components/server/chainlist-row.tsx | 4 +- .../(chain)/components/server/products.ts | 60 ++++---- packages/service-utils/src/core/services.ts | 12 +- 6 files changed, 135 insertions(+), 103 deletions(-) delete mode 100644 apps/dashboard/src/@/icons/ConnectSDKIcon.tsx diff --git a/apps/dashboard/src/@/icons/ConnectSDKIcon.tsx b/apps/dashboard/src/@/icons/ConnectSDKIcon.tsx deleted file mode 100644 index fa1e9a2e7f8..00000000000 --- a/apps/dashboard/src/@/icons/ConnectSDKIcon.tsx +++ /dev/null @@ -1,21 +0,0 @@ -export function ConnectSDKIcon(props: { className?: string }) { - return ( - - - - ); -} diff --git a/apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/(chainPage)/components/server/SupportedProductsSection.tsx b/apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/(chainPage)/components/server/SupportedProductsSection.tsx index ec7ec06c3af..957e8c64255 100644 --- a/apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/(chainPage)/components/server/SupportedProductsSection.tsx +++ b/apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/(chainPage)/components/server/SupportedProductsSection.tsx @@ -1,55 +1,112 @@ +import { BotIcon, CodeIcon, CoinsIcon } from "lucide-react"; import Link from "next/link"; -import type { ChainMetadataWithServices } from "@/types/chain"; -import { products } from "../../../../components/server/products"; +import { useMemo } from "react"; +import { BridgeIcon } from "@/icons/BridgeIcon"; +import { PayIcon } from "@/icons/PayIcon"; +import { WalletProductIcon } from "@/icons/WalletProductIcon"; +import type { + ChainMetadataWithServices, + ChainSupportedService, +} from "@/types/chain"; import { SectionTitle } from "./SectionTitle"; export function SupportedProductsSection(props: { services: ChainMetadataWithServices["services"]; }) { - const enabledProducts = products.filter((product) => { - return props.services.find( - (service) => service.service === product.id && service.enabled, + const enabledServices = useMemo(() => { + return props.services.reduce( + (acc, service) => { + acc[service.service] = service.enabled; + return acc; + }, + {} as Record, ); - }); - - if (enabledProducts.length === 0) { - return null; - } + }, [props.services]); return (
- {enabledProducts.map((product) => { - return ( -
-
-
- -
-
-
-

- - {product.name} - -

-

- {product.description} -

-
-
- ); - })} + {enabledServices["connect-sdk"] && ( + + )} + + {enabledServices["account-abstraction"] && ( + + )} + + {enabledServices.pay && ( + + )} + + {enabledServices.contracts && ( + + )} + + + +
); } + +function ProductCard(props: { + icon: React.FC<{ className?: string }>; + link: string; + name: string; + description: string; +}) { + return ( +
+
+
+ +
+
+
+

+ + {props.name} + +

+

{props.description}

+
+
+ ); +} diff --git a/apps/dashboard/src/app/(app)/(dashboard)/(chain)/chainlist/components/client/filters.tsx b/apps/dashboard/src/app/(app)/(dashboard)/(chain)/chainlist/components/client/filters.tsx index cb69e35cdd2..5a3f34c480a 100644 --- a/apps/dashboard/src/app/(app)/(dashboard)/(chain)/chainlist/components/client/filters.tsx +++ b/apps/dashboard/src/app/(app)/(dashboard)/(chain)/chainlist/components/client/filters.tsx @@ -15,7 +15,7 @@ import { import { RadioGroup, RadioGroupItem } from "@/components/ui/radio-group"; import { Separator } from "@/components/ui/separator"; import { useDashboardRouter } from "@/lib/DashboardRouter"; -import { products } from "../../../components/server/products"; +import { services } from "../../../components/server/products"; function cleanUrl(url: string) { if (url.endsWith("?")) { @@ -345,7 +345,7 @@ export const ChainServiceFilter: React.FC = ({ const section = ( - {products.map((product) => ( + {services.map((product) => (
= ({ } const firstFilter = allFilters[0]; - const name = products.find((p) => p.id === firstFilter)?.name; + const name = services.find((p) => p.id === firstFilter)?.name; const plus = allFilters.length > 1 ? ` +${allFilters.length - 1}` : ""; return [`${name}${plus}`, true]; diff --git a/apps/dashboard/src/app/(app)/(dashboard)/(chain)/chainlist/components/server/chainlist-row.tsx b/apps/dashboard/src/app/(app)/(dashboard)/(chain)/chainlist/components/server/chainlist-row.tsx index fefb8e26749..01dc2d26000 100644 --- a/apps/dashboard/src/app/(app)/(dashboard)/(chain)/chainlist/components/server/chainlist-row.tsx +++ b/apps/dashboard/src/app/(app)/(dashboard)/(chain)/chainlist/components/server/chainlist-row.tsx @@ -12,7 +12,7 @@ import { ToolTipLabel } from "@/components/ui/tooltip"; import { cn } from "@/lib/utils"; import type { ChainSupportedService } from "@/types/chain"; import { ChainIcon } from "../../../components/server/chain-icon"; -import { products } from "../../../components/server/products"; +import { services } from "../../../components/server/products"; import { getCustomChainMetadata } from "../../../utils"; type ChainListRowProps = { @@ -83,7 +83,7 @@ export function ChainListRow({
- {products.map((p) => { + {services.map((p) => { return ( ; - description: string; link: string; }>; diff --git a/packages/service-utils/src/core/services.ts b/packages/service-utils/src/core/services.ts index ffaead9ae84..bdcb373370d 100644 --- a/packages/service-utils/src/core/services.ts +++ b/packages/service-utils/src/core/services.ts @@ -4,7 +4,7 @@ export const SERVICE_DEFINITIONS = { actions: [], description: "Bundler & Paymaster services", name: "bundler", - title: "Account Abstraction", + title: "Gas Sponsorship", }, chainsaw: { // all actions allowed @@ -18,7 +18,7 @@ export const SERVICE_DEFINITIONS = { actions: [], description: "E-mail and social login wallets for easy web3 onboarding", name: "embeddedWallets", - title: "Wallets", + title: "User Wallets", }, engineCloud: { @@ -27,14 +27,14 @@ export const SERVICE_DEFINITIONS = { description: "Transaction API and Server wallets with high transaction throughput and low latency", name: "engineCloud", - title: "Transactions", + title: "Server Wallets", }, insight: { // all actions allowed actions: [], description: "Indexed data for any EVM chain", name: "insight", - title: "Insight", + title: "Indexer", }, nebula: { // all actions allowed @@ -42,7 +42,7 @@ export const SERVICE_DEFINITIONS = { description: "Advanced blockchain reasoning and execution capabilities with AI", name: "nebula", - title: "thirdweb AI", + title: "AI", }, pay: { // all actions allowed @@ -50,7 +50,7 @@ export const SERVICE_DEFINITIONS = { description: "Bridge, swap, and purchase cryptocurrencies and execute transactions with any fiat or tokens via cross-chain routing", name: "pay", - title: "Payments", + title: "Bridge", }, relayer: { // all actions allowed From c7ff3b1020034b9061b668de464e491efded7bb3 Mon Sep 17 00:00:00 2001 From: Jonas Daniels Date: Fri, 14 Nov 2025 14:59:40 -0800 Subject: [PATCH 4/4] Add /gateway to framer-rewrites.js --- apps/dashboard/framer-rewrites.js | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/dashboard/framer-rewrites.js b/apps/dashboard/framer-rewrites.js index a51116e63b7..c957cd5177e 100644 --- a/apps/dashboard/framer-rewrites.js +++ b/apps/dashboard/framer-rewrites.js @@ -21,6 +21,7 @@ module.exports = [ "/rpc", "/insight", "/storage", + "/gateway", // -- end scale category // -- ai