diff --git a/apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/connect/in-app-wallets/users/loading.tsx b/apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/universal-bridge/loading.tsx
similarity index 100%
rename from apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/connect/in-app-wallets/users/loading.tsx
rename to apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/universal-bridge/loading.tsx
diff --git a/apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/connect/universal-bridge/page.tsx b/apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/universal-bridge/page.tsx
similarity index 93%
rename from apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/connect/universal-bridge/page.tsx
rename to apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/universal-bridge/page.tsx
index e300789a929..dd7264b64c0 100644
--- a/apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/connect/universal-bridge/page.tsx
+++ b/apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/universal-bridge/page.tsx
@@ -1,3 +1,5 @@
+import { getAuthToken } from "@app/api/lib/getAuthToken";
+import { loginRedirect } from "@app/login/loginRedirect";
import { PayAnalyticsFilter } from "components/pay/PayAnalytics/components/PayAnalyticsFilter";
import { PayAnalytics } from "components/pay/PayAnalytics/PayAnalytics";
import { getUniversalBridgeFiltersFromSearchParams } from "lib/time";
@@ -10,8 +12,6 @@ import {
import { getProject } from "@/api/projects";
import { Spinner } from "@/components/ui/Spinner/Spinner";
import { getClientThirdwebClient } from "@/constants/thirdweb-client.client";
-import { getAuthToken } from "../../../../../../api/lib/getAuthToken";
-import { loginRedirect } from "../../../../../../login/loginRedirect";
export default async function Page(props: {
params: Promise<{
@@ -30,7 +30,7 @@ export default async function Page(props: {
if (!authToken) {
loginRedirect(
- `/team/${params.team_slug}/${params.project_slug}/connect/universal-bridge`,
+ `/team/${params.team_slug}/${params.project_slug}/universal-bridge`,
);
}
diff --git a/apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/connect/universal-bridge/settings/page.tsx b/apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/universal-bridge/settings/page.tsx
similarity index 85%
rename from apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/connect/universal-bridge/settings/page.tsx
rename to apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/universal-bridge/settings/page.tsx
index 9a006e4ee59..64eddd5b2e0 100644
--- a/apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/connect/universal-bridge/settings/page.tsx
+++ b/apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/universal-bridge/settings/page.tsx
@@ -1,3 +1,5 @@
+import { getAuthToken } from "@app/api/lib/getAuthToken";
+import { loginRedirect } from "@app/login/loginRedirect";
import { PayConfig } from "components/pay/PayConfig";
import { RouteDiscovery } from "components/pay/RouteDiscovery";
import { redirect } from "next/navigation";
@@ -5,8 +7,6 @@ import { getProject } from "@/api/projects";
import { getTeamBySlug } from "@/api/team";
import { getFees } from "@/api/universal-bridge/developer";
import { getClientThirdwebClient } from "@/constants/thirdweb-client.client";
-import { getAuthToken } from "../../../../../../../api/lib/getAuthToken";
-import { loginRedirect } from "../../../../../../../login/loginRedirect";
export default async function Page(props: {
params: Promise<{
@@ -24,7 +24,7 @@ export default async function Page(props: {
if (!authToken) {
loginRedirect(
- `/team/${team_slug}/${project_slug}/connect/universal-bridge/settings`,
+ `/team/${team_slug}/${project_slug}/universal-bridge/settings`,
);
}
@@ -63,7 +63,7 @@ export default async function Page(props: {
});
return (
-
+
-
-
Webhooks
-
-
-
-
-
-
-
@@ -142,6 +130,15 @@ export function PayWebhooksPage(props: PayWebhooksPageProps) {
+
+
+
+
+
+
);
}
diff --git a/apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/connect/universal-bridge/loading.tsx b/apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/universal-bridge/webhooks/loading.tsx
similarity index 100%
rename from apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/connect/universal-bridge/loading.tsx
rename to apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/universal-bridge/webhooks/loading.tsx
diff --git a/apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/universal-bridge/webhooks/page.tsx b/apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/universal-bridge/webhooks/page.tsx
new file mode 100644
index 00000000000..4b643e627e3
--- /dev/null
+++ b/apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/universal-bridge/webhooks/page.tsx
@@ -0,0 +1,39 @@
+import { redirect } from "next/navigation";
+import { getProject } from "@/api/projects";
+import { UnderlineLink } from "@/components/ui/UnderlineLink";
+import { PayWebhooksPage } from "./components/webhooks.client";
+
+export default async function Page(props: {
+ params: Promise<{
+ team_slug: string;
+ project_slug: string;
+ }>;
+}) {
+ const params = await props.params;
+ const project = await getProject(params.team_slug, params.project_slug);
+
+ if (!project) {
+ redirect(`/team/${params.team_slug}`);
+ }
+
+ return (
+
+
Webhooks
+
+ Get notified for Bridge, Swap and Onramp events.{" "}
+
+ Learn more
+
+
+
+
+
+ );
+}
diff --git a/apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/engine/cloud/vault/components/create-vault-account.client.tsx b/apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/vault/components/create-vault-account.client.tsx
similarity index 97%
rename from apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/engine/cloud/vault/components/create-vault-account.client.tsx
rename to apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/vault/components/create-vault-account.client.tsx
index b7f68abc3d8..2a2d50f9810 100644
--- a/apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/engine/cloud/vault/components/create-vault-account.client.tsx
+++ b/apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/vault/components/create-vault-account.client.tsx
@@ -1,7 +1,13 @@
"use client";
+
import { useMutation } from "@tanstack/react-query";
import { createServiceAccount } from "@thirdweb-dev/vault-sdk";
-import { CheckIcon, DownloadIcon, Loader2Icon, LockIcon } from "lucide-react";
+import {
+ CheckIcon,
+ DownloadIcon,
+ Loader2Icon,
+ UserLockIcon,
+} from "lucide-react";
import { useState } from "react";
import { toast } from "sonner";
import type { Project } from "@/api/projects";
@@ -18,15 +24,15 @@ import {
import { Spinner } from "@/components/ui/Spinner/Spinner";
import { useDashboardRouter } from "@/lib/DashboardRouter";
import { cn } from "@/lib/utils";
-import { storeUserAccessToken } from "../../analytics/utils";
+import { storeUserAccessToken } from "../../transactions/analytics/utils";
import {
createManagementAccessToken,
createWalletAccessToken,
initVaultClient,
maskSecret,
-} from "../../lib/vault.client";
+} from "../../transactions/lib/vault.client";
-export default function CreateVaultAccountButton(props: {
+export function CreateVaultAccountButton(props: {
project: Project;
onUserAccessTokenCreated?: (userAccessToken: string) => void;
}) {
@@ -151,7 +157,7 @@ export default function CreateVaultAccountButton(props: {
{isLoading ? (
) : (
-
+
)}
{"Create Vault Admin Account"}
diff --git a/apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/vault/components/key-management.tsx b/apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/vault/components/key-management.tsx
new file mode 100644
index 00000000000..f362e3033f6
--- /dev/null
+++ b/apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/vault/components/key-management.tsx
@@ -0,0 +1,87 @@
+import { InfoIcon } from "lucide-react";
+import Link from "next/link";
+import type { Project } from "@/api/projects";
+import { Alert, AlertDescription, AlertTitle } from "@/components/ui/alert";
+import { CreateVaultAccountButton } from "./create-vault-account.client";
+import ListAccessTokens from "./list-access-tokens.client";
+import RotateAdminKeyButton from "./rotate-admin-key.client";
+
+export function KeyManagement({
+ maskedAdminKey,
+ project,
+}: {
+ maskedAdminKey?: string;
+ project: Project;
+}) {
+ return (
+
+ {!maskedAdminKey &&
}
+
+ {maskedAdminKey && (
+ <>
+
+
+
+ Admin Key
+
+
+ This key is used to create new server wallets and access tokens.
+
We do not store this key. If you lose it, you can rotate
+ it to create a new one. Doing so will invalidate all existing
+ access tokens.
+
+
+
+
+
+
+ >
+ )}
+
+ );
+}
+
+async function CreateVaultAccountAlert(props: { project: Project }) {
+ return (
+
+
+
+
+ What is Vault?
+
+
+ Vault is thirdweb's non-custodial key management system for your
+ server wallets that allows you to:
+
+ - Create multiple server wallets.
+ - Create Vault access tokens.
+ - Sign transactions using a Vault access token.
+
+ Your keys are stored in a hardware enclave, and all requests are
+ end-to-end encrypted.{" "}
+
+ Learn more about Vault security model.
+
+
+ Creating server wallets and access tokens requires a Vault admin
+ account. Create one below to get started.
+
+
+
+
+
+
+ );
+}
diff --git a/apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/engine/cloud/vault/components/list-access-tokens.client.tsx b/apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/vault/components/list-access-tokens.client.tsx
similarity index 99%
rename from apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/engine/cloud/vault/components/list-access-tokens.client.tsx
rename to apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/vault/components/list-access-tokens.client.tsx
index 8ba79bd1ca9..33c18b3b4a1 100644
--- a/apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/engine/cloud/vault/components/list-access-tokens.client.tsx
+++ b/apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/vault/components/list-access-tokens.client.tsx
@@ -20,7 +20,7 @@ import {
createWalletAccessToken,
initVaultClient,
SERVER_WALLET_MANAGEMENT_ACCESS_TOKEN_PURPOSE,
-} from "../../lib/vault.client";
+} from "../../transactions/lib/vault.client";
export default function ListAccessTokens(props: { project: Project }) {
const [modalOpen, setModalOpen] = useState(false);
diff --git a/apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/engine/cloud/vault/components/rotate-admin-key.client.tsx b/apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/vault/components/rotate-admin-key.client.tsx
similarity index 99%
rename from apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/engine/cloud/vault/components/rotate-admin-key.client.tsx
rename to apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/vault/components/rotate-admin-key.client.tsx
index 92e8c5f227a..3a4733f3919 100644
--- a/apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/engine/cloud/vault/components/rotate-admin-key.client.tsx
+++ b/apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/vault/components/rotate-admin-key.client.tsx
@@ -31,7 +31,7 @@ import {
createWalletAccessToken,
initVaultClient,
maskSecret,
-} from "../../lib/vault.client";
+} from "../../transactions/lib/vault.client";
export default function RotateAdminKeyButton(props: { project: Project }) {
const [modalOpen, setModalOpen] = useState(false);
diff --git a/apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/vault/layout.tsx b/apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/vault/layout.tsx
new file mode 100644
index 00000000000..83c583b1744
--- /dev/null
+++ b/apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/vault/layout.tsx
@@ -0,0 +1,31 @@
+import Link from "next/link";
+
+export default function VaultLayout(props: { children: React.ReactNode }) {
+ return (
+
+
+
+
Vault
+
+ Secure, non-custodial key management system for your server wallets.{" "}
+
+ Learn more.
+
+
+
+
+
+
+
+ {props.children}
+
+
+
+
+ );
+}
diff --git a/apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/engine/cloud/vault/page.tsx b/apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/vault/page.tsx
similarity index 92%
rename from apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/engine/cloud/vault/page.tsx
rename to apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/vault/page.tsx
index 5651b521e2e..c27ea7701b9 100644
--- a/apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/engine/cloud/vault/page.tsx
+++ b/apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/vault/page.tsx
@@ -1,6 +1,7 @@
+import { getAuthToken } from "@app/api/lib/getAuthToken";
import { notFound } from "next/navigation";
import { getProject } from "@/api/projects";
-import { getAuthToken } from "../../../../../../../api/lib/getAuthToken";
+
import { KeyManagement } from "./components/key-management";
export default async function VaultPage(props: {
diff --git a/apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/connect/in-app-wallets/_components/footer.tsx b/apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/wallets/_components/footer.tsx
similarity index 96%
rename from apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/connect/in-app-wallets/_components/footer.tsx
rename to apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/wallets/_components/footer.tsx
index ecec0a930b3..862fc6b5dbe 100644
--- a/apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/connect/in-app-wallets/_components/footer.tsx
+++ b/apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/wallets/_components/footer.tsx
@@ -1,4 +1,4 @@
-import { FooterLinksSection } from "../../../components/footer/FooterLinksSection";
+import { FooterLinksSection } from "../../components/footer/FooterLinksSection";
export function InAppWalletsFooter() {
return (
diff --git a/apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/connect/in-app-wallets/_components/header.tsx b/apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/wallets/_components/header.tsx
similarity index 88%
rename from apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/connect/in-app-wallets/_components/header.tsx
rename to apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/wallets/_components/header.tsx
index f4914afabab..cce0bc726f4 100644
--- a/apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/connect/in-app-wallets/_components/header.tsx
+++ b/apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/wallets/_components/header.tsx
@@ -3,8 +3,8 @@ import { UnderlineLink } from "@/components/ui/UnderlineLink";
export async function InAppWalletsHeader() {
return (
-
- In-App Wallets
+
+ Wallets
A wallet infrastructure that enables apps to create, manage, and control
diff --git a/apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/connect/in-app-wallets/analytics/page.tsx b/apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/wallets/analytics/page.tsx
similarity index 74%
rename from apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/connect/in-app-wallets/analytics/page.tsx
rename to apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/wallets/analytics/page.tsx
index 45260aec949..ee465483d76 100644
--- a/apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/connect/in-app-wallets/analytics/page.tsx
+++ b/apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/wallets/analytics/page.tsx
@@ -10,7 +10,5 @@ export default async function Page(props: {
}) {
const params = await props.params;
// Default to the users tab
- redirect(
- `/team/${params.team_slug}/${params.project_slug}/connect/in-app-wallets`,
- );
+ redirect(`/team/${params.team_slug}/${params.project_slug}/wallets`);
}
diff --git a/apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/connect/in-app-wallets/layout.tsx b/apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/wallets/layout.tsx
similarity index 84%
rename from apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/connect/in-app-wallets/layout.tsx
rename to apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/wallets/layout.tsx
index db919afcfca..6a75875579b 100644
--- a/apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/connect/in-app-wallets/layout.tsx
+++ b/apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/wallets/layout.tsx
@@ -27,23 +27,23 @@ export default async function Layout(props: {
-
+
;
@@ -21,7 +21,7 @@ export default async function Page(props: {
]);
if (!authToken) {
- loginRedirect(`/team/${team_slug}/connect/in-app-wallets/settings`);
+ loginRedirect(`/team/${team_slug}/wallets/settings`);
}
if (!team) {
diff --git a/apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/connect/universal-bridge/webhooks/loading.tsx b/apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/wallets/users/loading.tsx
similarity index 100%
rename from apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/connect/universal-bridge/webhooks/loading.tsx
rename to apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/wallets/users/loading.tsx
diff --git a/apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/connect/in-app-wallets/users/page.tsx b/apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/wallets/users/page.tsx
similarity index 73%
rename from apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/connect/in-app-wallets/users/page.tsx
rename to apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/wallets/users/page.tsx
index daac9753981..e20009024c0 100644
--- a/apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/connect/in-app-wallets/users/page.tsx
+++ b/apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/wallets/users/page.tsx
@@ -1,10 +1,9 @@
+import { getAuthToken } from "@app/api/lib/getAuthToken";
+import { loginRedirect } from "@app/login/loginRedirect";
import { InAppWalletUsersPageContent } from "components/embedded-wallets/Users";
import { redirect } from "next/navigation";
import { getProject } from "@/api/projects";
import { getClientThirdwebClient } from "@/constants/thirdweb-client.client";
-import { getAuthToken } from "../../../../../../../api/lib/getAuthToken";
-import { loginRedirect } from "../../../../../../../login/loginRedirect";
-import { TRACKING_CATEGORY } from "../_constants";
export default async function Page(props: {
params: Promise<{ team_slug: string; project_slug: string }>;
@@ -17,7 +16,7 @@ export default async function Page(props: {
if (!authToken) {
loginRedirect(
- `/team/${params.team_slug}/${params.project_slug}/connect/in-app-wallets/users`,
+ `/team/${params.team_slug}/${params.project_slug}/wallets/users`,
);
}
@@ -35,7 +34,6 @@ export default async function Page(props: {
authToken={authToken}
client={client}
projectClientId={project.publishableKey}
- trackingCategory={TRACKING_CATEGORY}
/>
);
}
diff --git a/apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/webhooks/components/CreateWebhookModal.tsx b/apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/webhooks/components/CreateWebhookModal.tsx
index 0c341cd591c..40232ef2e9d 100644
--- a/apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/webhooks/components/CreateWebhookModal.tsx
+++ b/apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/webhooks/components/CreateWebhookModal.tsx
@@ -1,7 +1,7 @@
"use client";
import { zodResolver } from "@hookform/resolvers/zod";
-import { XIcon } from "lucide-react";
+import { PlusIcon, XIcon } from "lucide-react";
import { useState } from "react";
import { useForm, useWatch } from "react-hook-form";
import { toast } from "sonner";
@@ -43,7 +43,7 @@ interface CreateWebhookModalProps {
client: ThirdwebClient;
}
-export function CreateWebhookModal({
+export function CreateContractWebhookButton({
projectClientId,
supportedChainIds,
client,
@@ -222,7 +222,10 @@ export function CreateWebhookModal({
return (
);
}
diff --git a/apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/webhooks/contract-webhooks/contract-webhooks-page.tsx b/apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/webhooks/contract-webhooks/contract-webhooks-page.tsx
new file mode 100644
index 00000000000..b3fe91d55ae
--- /dev/null
+++ b/apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/webhooks/contract-webhooks/contract-webhooks-page.tsx
@@ -0,0 +1,80 @@
+import {
+ getSupportedWebhookChains,
+ getWebhooks,
+ type WebhookResponse,
+} from "@/api/insight/webhooks";
+import type { Project } from "@/api/projects";
+import { getClientThirdwebClient } from "@/constants/thirdweb-client.client";
+import { CreateContractWebhookButton } from "../components/CreateWebhookModal";
+import { ContractsWebhooksTable } from "../components/WebhooksTable";
+
+export async function ContractsWebhooksPageContent(props: {
+ project: Project;
+ authToken: string;
+}) {
+ let webhooks: WebhookResponse[] = [];
+ let errorMessage = "";
+ let supportedChainIds: number[] = [];
+
+ const projectClientId = props.project.publishableKey;
+
+ try {
+ const webhooksRes = await getWebhooks(projectClientId);
+ if (webhooksRes.error) {
+ errorMessage = webhooksRes.error;
+ } else if (webhooksRes.data) {
+ webhooks = webhooksRes.data;
+ }
+
+ const supportedChainsRes = await getSupportedWebhookChains();
+ if ("chains" in supportedChainsRes) {
+ supportedChainIds = supportedChainsRes.chains;
+ } else {
+ errorMessage = supportedChainsRes.error;
+ }
+ } catch (error) {
+ errorMessage = "Failed to load webhooks. Please try again later.";
+ console.error("Error loading project or webhooks", error);
+ }
+
+ const client = getClientThirdwebClient({
+ jwt: props.authToken,
+ teamId: props.project.teamId,
+ });
+
+ return (
+
+ {errorMessage ? (
+
+
+
+ Unable to load webhooks
+
+
{errorMessage}
+
+
+ ) : webhooks.length > 0 ? (
+
+ ) : (
+
+
+
No webhooks found
+
+ Create a webhook to get started.
+
+
+
+
+ )}
+
+ );
+}
diff --git a/apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/webhooks/layout.tsx b/apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/webhooks/layout.tsx
new file mode 100644
index 00000000000..c76bc502dfb
--- /dev/null
+++ b/apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/webhooks/layout.tsx
@@ -0,0 +1,45 @@
+import { TabPathLinks } from "@/components/ui/tabs";
+
+export default async function WebhooksLayout(props: {
+ children: React.ReactNode;
+ params: Promise<{
+ team_slug: string;
+ project_slug: string;
+ }>;
+}) {
+ const params = await props.params;
+ return (
+
+
+
+
+ Webhooks
+
+
+ Create and manage webhooks to get notified about events
+
+
+
+
+
+
+
+ {props.children}
+
+
+
+ );
+}
diff --git a/apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/webhooks/page.tsx b/apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/webhooks/page.tsx
index 6d413a75938..53e25b1b122 100644
--- a/apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/webhooks/page.tsx
+++ b/apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/webhooks/page.tsx
@@ -1,25 +1,14 @@
+import { getAuthToken } from "@app/api/lib/getAuthToken";
import { notFound } from "next/navigation";
-import {
- getSupportedWebhookChains,
- getWebhooks,
- type WebhookResponse,
-} from "@/api/insight/webhooks";
import { getProject } from "@/api/projects";
import { UnderlineLink } from "@/components/ui/UnderlineLink";
-import { getClientThirdwebClient } from "@/constants/thirdweb-client.client";
-import { getAuthToken } from "../../../../../api/lib/getAuthToken";
-import { CreateWebhookModal } from "./components/CreateWebhookModal";
-import { WebhooksTable } from "./components/WebhooksTable";
+import { ContractsWebhooksPageContent } from "./contract-webhooks/contract-webhooks-page";
export default async function WebhooksPage({
params,
}: {
params: Promise<{ team_slug: string; project_slug: string }>;
}) {
- let webhooks: WebhookResponse[] = [];
- let errorMessage = "";
- let supportedChainIds: number[] = [];
-
const [authToken, resolvedParams] = await Promise.all([
getAuthToken(),
params,
@@ -34,87 +23,23 @@ export default async function WebhooksPage({
notFound();
}
- const projectClientId = project.publishableKey;
-
- try {
- const webhooksRes = await getWebhooks(projectClientId);
- if (webhooksRes.error) {
- errorMessage = webhooksRes.error;
- } else if (webhooksRes.data) {
- webhooks = webhooksRes.data;
- }
-
- const supportedChainsRes = await getSupportedWebhookChains();
- if ("chains" in supportedChainsRes) {
- supportedChainIds = supportedChainsRes.chains;
- } else {
- errorMessage = supportedChainsRes.error;
- }
- } catch (error) {
- errorMessage = "Failed to load webhooks. Please try again later.";
- console.error("Error loading project or webhooks", error);
- }
-
- const client = getClientThirdwebClient({
- jwt: authToken,
- teamId: project.teamId,
- });
-
return (
-
-
-
-
- Webhooks
-
-
- Create and manage webhooks to get notified about blockchain events,
- transactions and more.{" "}
-
- Learn more about webhooks.
-
-
-
-
-
-
- {errorMessage ? (
-
-
-
- Unable to load webhooks
-
-
{errorMessage}
-
-
- ) : webhooks.length > 0 ? (
-
- ) : (
-
-
-
No webhooks found
-
- Create a webhook to get started.
-
-
-
-
- )}
-
-
+
+
+ Contract Webhooks
+
+
+ Get notified about blockchain events, transactions and more.{" "}
+
+ Learn more
+
+
+
+
);
}
diff --git a/apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/webhooks/universal-bridge/page.tsx b/apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/webhooks/universal-bridge/page.tsx
new file mode 100644
index 00000000000..dac9b2a071f
--- /dev/null
+++ b/apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/webhooks/universal-bridge/page.tsx
@@ -0,0 +1,41 @@
+import { redirect } from "next/navigation";
+import { getProject } from "@/api/projects";
+import { UnderlineLink } from "@/components/ui/UnderlineLink";
+import { PayWebhooksPage } from "../../universal-bridge/webhooks/components/webhooks.client";
+
+export default async function Page(props: {
+ params: Promise<{
+ team_slug: string;
+ project_slug: string;
+ }>;
+}) {
+ const params = await props.params;
+ const project = await getProject(params.team_slug, params.project_slug);
+
+ if (!project) {
+ redirect(`/team/${params.team_slug}`);
+ }
+
+ return (
+
+
+ Universal Bridge Webhooks
+
+
+ Get notified for Bridge, Swap and Onramp events.{" "}
+
+ Learn more
+
+
+
+
+
+ );
+}
diff --git a/apps/dashboard/src/components/contract-components/import-contract/modal.tsx b/apps/dashboard/src/components/contract-components/import-contract/modal.tsx
index 4e731405dc5..3f68ba246fd 100644
--- a/apps/dashboard/src/components/contract-components/import-contract/modal.tsx
+++ b/apps/dashboard/src/components/contract-components/import-contract/modal.tsx
@@ -58,7 +58,7 @@ export const ImportModal: React.FC
= (props) => {
>
- Import {props.type === "contract" ? "Contract" : "Asset"}
+ Import {props.type === "contract" ? "Contract" : "Token"}
Import a deployed contract in your project
diff --git a/apps/dashboard/src/components/contract-components/tables/contract-table.tsx b/apps/dashboard/src/components/contract-components/tables/contract-table.tsx
index 81de393a4ad..5e7abbcae8d 100644
--- a/apps/dashboard/src/components/contract-components/tables/contract-table.tsx
+++ b/apps/dashboard/src/components/contract-components/tables/contract-table.tsx
@@ -163,7 +163,7 @@ export function ContractTableUI(props: {
Contract Address
)}
- {props.variant === "asset" && Asset Page}
+ {props.variant === "asset" && Token Page}
Actions
@@ -262,7 +262,7 @@ export function ContractTableUI(props: {
{props.variant === "asset" ? (
-
No assets found
+
No tokens found
) : (
No contracts found
)}
diff --git a/apps/dashboard/src/components/dashboard/StepsCard.tsx b/apps/dashboard/src/components/dashboard/StepsCard.tsx
index 4f565c69ffb..eba5a9d2e8d 100644
--- a/apps/dashboard/src/components/dashboard/StepsCard.tsx
+++ b/apps/dashboard/src/components/dashboard/StepsCard.tsx
@@ -37,7 +37,7 @@ export const StepsCard: React.FC
= ({
return (
{/* Title + Desc */}
-
+
{title}
diff --git a/apps/dashboard/src/components/embedded-wallets/Users/index.tsx b/apps/dashboard/src/components/embedded-wallets/Users/index.tsx
index 280beebd2d4..4c58aaa43cb 100644
--- a/apps/dashboard/src/components/embedded-wallets/Users/index.tsx
+++ b/apps/dashboard/src/components/embedded-wallets/Users/index.tsx
@@ -36,7 +36,6 @@ const getUserIdentifier = (accounts: WalletUser["linkedAccounts"]) => {
const columnHelper = createColumnHelper();
export function InAppWalletUsersPageContent(props: {
- trackingCategory: string;
authToken: string;
projectClientId: string;
client: ThirdwebClient;
diff --git a/apps/dashboard/src/components/pay/PayAnalytics/PayAnalytics.tsx b/apps/dashboard/src/components/pay/PayAnalytics/PayAnalytics.tsx
index 00a9e329542..76d7b9aab22 100644
--- a/apps/dashboard/src/components/pay/PayAnalytics/PayAnalytics.tsx
+++ b/apps/dashboard/src/components/pay/PayAnalytics/PayAnalytics.tsx
@@ -3,7 +3,9 @@ import {
getUniversalBridgeUsage,
getUniversalBridgeWalletUsage,
} from "@/api/analytics";
+import { CodeServer } from "@/components/ui/code/code.server";
import type { Range } from "../../analytics/date-range-selector";
+import { apiCode, embedCode, sdkCode } from "./code-examples";
import { PayCustomersTable } from "./components/PayCustomersTable";
import { PaymentHistory } from "./components/PaymentHistory";
import { PaymentsSuccessRate } from "./components/PaymentsSuccessRate";
@@ -59,8 +61,38 @@ export async function PayAnalytics(props: {
const hasVolume = volumeData.some((d) => d.amountUsdCents > 0);
const hasWallet = walletData.some((d) => d.count > 0);
+
if (!hasVolume && !hasWallet) {
- return ;
+ return (
+
+ ),
+ embed: (
+
+ ),
+ sdk: (
+
+ ),
+ } as const
+ }
+ />
+ );
}
return (
diff --git a/apps/dashboard/src/components/pay/PayAnalytics/PayEmbedFTUX.tsx b/apps/dashboard/src/components/pay/PayAnalytics/PayEmbedFTUX.tsx
index 7cf3a02b736..7f199bb6df7 100644
--- a/apps/dashboard/src/components/pay/PayAnalytics/PayEmbedFTUX.tsx
+++ b/apps/dashboard/src/components/pay/PayAnalytics/PayEmbedFTUX.tsx
@@ -1,22 +1,31 @@
"use client";
+
import { ExternalLinkIcon } from "lucide-react";
import Link from "next/link";
import { useState } from "react";
import { Button } from "@/components/ui/button";
-import { CodeServer } from "@/components/ui/code/code.server";
import { TabButtons } from "@/components/ui/tabs";
-export function PayEmbedFTUX(props: { clientId: string }) {
- const [tab, setTab] = useState("embed");
+type Tab = "embed" | "sdk" | "api";
+
+export function PayEmbedFTUX(props: {
+ clientId: string;
+ codeExamples: {
+ embed: React.ReactNode;
+ sdk: React.ReactNode;
+ api: React.ReactNode;
+ };
+}) {
+ const [tab, setTab] = useState("embed");
return (
-
-
+
+
Start Monetizing Your App
-
+
- {tab === "embed" && (
-
- )}
- {tab === "sdk" && (
-
- )}
- {tab === "api" && (
-
- )}
+
+ {props.codeExamples[tab]}
-
+