diff --git a/apps/dashboard/src/app/account/contracts/_components/DeployViaCLIOrImportCard.tsx b/apps/dashboard/src/app/account/contracts/_components/DeployViaCLIOrImportCard.tsx
index 52e86570066..f46f6aac87f 100644
--- a/apps/dashboard/src/app/account/contracts/_components/DeployViaCLIOrImportCard.tsx
+++ b/apps/dashboard/src/app/account/contracts/_components/DeployViaCLIOrImportCard.tsx
@@ -13,7 +13,7 @@ export function DeployViaCLIOrImportCard(props: {
const [importModalOpen, setImportModalOpen] = useState(false);
return (
-
+
{
@@ -26,14 +26,18 @@ export function DeployViaCLIOrImportCard(props: {
Already have a smart contract?
-
+
Import an already deployed contract or deploy a contract from source
code to easily manage permissions, upload assets, and interact with
contract functions
-
-
+
+
setImportModalOpen(true)}
>
diff --git a/apps/dashboard/src/app/team/[team_slug]/[project_slug]/components/ProjectFTUX/ClientIDSection.tsx b/apps/dashboard/src/app/team/[team_slug]/[project_slug]/components/ProjectFTUX/ClientIDSection.tsx
new file mode 100644
index 00000000000..cd28c9c5236
--- /dev/null
+++ b/apps/dashboard/src/app/team/[team_slug]/[project_slug]/components/ProjectFTUX/ClientIDSection.tsx
@@ -0,0 +1,22 @@
+import { CopyTextButton } from "@/components/ui/CopyTextButton";
+
+export function ClientIDSection(props: {
+ clientId: string;
+}) {
+ return (
+
+
Client ID
+
+ Identifies your application
+
+
+
+
+ );
+}
diff --git a/apps/dashboard/src/app/team/[team_slug]/[project_slug]/components/ProjectFTUX/IntegrateAPIKeyCodeTabs.tsx b/apps/dashboard/src/app/team/[team_slug]/[project_slug]/components/ProjectFTUX/IntegrateAPIKeyCodeTabs.tsx
index 6686ce5e380..9d971063ad9 100644
--- a/apps/dashboard/src/app/team/[team_slug]/[project_slug]/components/ProjectFTUX/IntegrateAPIKeyCodeTabs.tsx
+++ b/apps/dashboard/src/app/team/[team_slug]/[project_slug]/components/ProjectFTUX/IntegrateAPIKeyCodeTabs.tsx
@@ -29,7 +29,7 @@ export function IntegrateAPIKeyCodeTabs(props: {
isActive: tab === key,
}))}
/>
-
+
{props.tabs[tab]}
);
diff --git a/apps/dashboard/src/app/team/[team_slug]/[project_slug]/components/ProjectFTUX/ProjectFTUX.tsx b/apps/dashboard/src/app/team/[team_slug]/[project_slug]/components/ProjectFTUX/ProjectFTUX.tsx
index 14c168e896f..dae245ed81a 100644
--- a/apps/dashboard/src/app/team/[team_slug]/[project_slug]/components/ProjectFTUX/ProjectFTUX.tsx
+++ b/apps/dashboard/src/app/team/[team_slug]/[project_slug]/components/ProjectFTUX/ProjectFTUX.tsx
@@ -1,5 +1,4 @@
import type { Project } from "@/api/projects";
-import { CopyTextButton } from "@/components/ui/CopyTextButton";
import { UnderlineLink } from "@/components/ui/UnderlineLink";
import { Alert, AlertDescription, AlertTitle } from "@/components/ui/alert";
import { CodeServer } from "@/components/ui/code/code.server";
@@ -19,6 +18,7 @@ import { TypeScriptIcon } from "../../../../../../components/icons/brand-icons/T
import { UnityIcon } from "../../../../../../components/icons/brand-icons/UnityIcon";
import { UnrealIcon } from "../../../../../../components/icons/brand-icons/UnrealIcon";
import { NebulaIcon } from "../../../../../nebula-app/(app)/icons/NebulaIcon";
+import { ClientIDSection } from "./ClientIDSection";
import { IntegrateAPIKeyCodeTabs } from "./IntegrateAPIKeyCodeTabs";
import { SecretKeySection } from "./SecretKeySection";
@@ -59,21 +59,7 @@ function IntegrateAPIKeySection({
-
-
Client ID
-
- Identifies your application
-
-
-
-
-
+
{secretKeyMasked && (
- {/* Client ID */}
-
-
Client ID
-
- Identifies your application
-
-
-
-
-
-
-
+ {props.children}
{/* Code */}
{cta.label}
diff --git a/apps/dashboard/src/app/team/[team_slug]/[project_slug]/insight/insight-ftux.tsx b/apps/dashboard/src/app/team/[team_slug]/[project_slug]/insight/insight-ftux.tsx
index f854eebe279..699c0aedeb2 100644
--- a/apps/dashboard/src/app/team/[team_slug]/[project_slug]/insight/insight-ftux.tsx
+++ b/apps/dashboard/src/app/team/[team_slug]/[project_slug]/insight/insight-ftux.tsx
@@ -1,5 +1,6 @@
import { CodeServer } from "@/components/ui/code/code.server";
import { isProd } from "@/constants/env";
+import { ClientIDSection } from "../components/ProjectFTUX/ClientIDSection";
import { WaitingForIntegrationCard } from "../components/WaitingForIntegrationCard/WaitingForIntegrationCard";
export function InsightFTUX(props: {
@@ -8,7 +9,6 @@ export function InsightFTUX(props: {
return (
+ >
+
+
+
);
}
diff --git a/apps/dashboard/src/app/team/[team_slug]/[project_slug]/nebula/nebula-ftux.tsx b/apps/dashboard/src/app/team/[team_slug]/[project_slug]/nebula/nebula-ftux.tsx
new file mode 100644
index 00000000000..305e83cce29
--- /dev/null
+++ b/apps/dashboard/src/app/team/[team_slug]/[project_slug]/nebula/nebula-ftux.tsx
@@ -0,0 +1,104 @@
+import { CodeServer } from "@/components/ui/code/code.server";
+import { SecretKeySection } from "../components/ProjectFTUX/SecretKeySection";
+import { WaitingForIntegrationCard } from "../components/WaitingForIntegrationCard/WaitingForIntegrationCard";
+
+export function NebulaFTUX(props: {
+ secretKeyMasked: string;
+ projectId: string;
+}) {
+ return (
+
+ ),
+ },
+ {
+ label: "Python",
+ code: (
+
+ ),
+ },
+ {
+ label: "Curl",
+ code: (
+
+ ),
+ },
+ ]}
+ ctas={[
+ {
+ label: "Try on Playground",
+ href: "https://nebula.thirdweb.com/",
+ trackingLabel: "playground",
+ category: "nebula-ftux",
+ },
+ {
+ label: "View Docs",
+ href: "https://portal.thirdweb.com/nebula",
+ trackingLabel: "docs",
+ category: "nebula-ftux",
+ },
+ ]}
+ >
+
+
+
+ );
+}
+
+const jsCode = `\
+// Example: Send message to Nebula
+// Replace PROJECT_SECRET_KEY with your project's full secret key
+
+const res = await fetch("https://nebula-api.thirdweb.com/chat", {
+ method: "POST",
+ headers: {
+ "x-secret-key": "PROJECT_SECRET_KEY",
+ },
+ body: {
+ message: "Hello",
+ stream: false,
+ },
+});
+
+const data = await res.json();
+`;
+
+const curlCode = `\
+# Example: Send message to Nebula
+# Replace PROJECT_SECRET_KEY with your project's full secret key
+
+curl -X POST https://nebula-api.thirdweb.com/chat \
+-H "x-secret-key:PROJECT_SECRET_KEY" \
+-d '{
+ "message": "Hello",
+ "stream": false,
+}'
+`;
+
+const pythonCode = `\
+# Example: Send message to Nebula
+# Replace PROJECT_SECRET_KEY with your project's full secret key
+
+import requests
+
+response = requests.post("https://nebula-api.thirdweb.com/chat", headers={
+ "x-secret-key": "PROJECT_SECRET_KEY"
+}, json={
+ "message": "Hello",
+ "stream": False,
+})
+
+data = response.json()
+`;
diff --git a/apps/dashboard/src/app/team/[team_slug]/[project_slug]/nebula/page.tsx b/apps/dashboard/src/app/team/[team_slug]/[project_slug]/nebula/page.tsx
index 646965eb060..f7854db2ab4 100644
--- a/apps/dashboard/src/app/team/[team_slug]/[project_slug]/nebula/page.tsx
+++ b/apps/dashboard/src/app/team/[team_slug]/[project_slug]/nebula/page.tsx
@@ -1,3 +1,4 @@
+import { isProjectActive } from "@/api/analytics";
import { getProject } from "@/api/projects";
import { getTeamBySlug } from "@/api/team";
import { redirect } from "next/navigation";
@@ -5,6 +6,7 @@ import { getAuthToken } from "../../../../api/lib/getAuthToken";
import { loginRedirect } from "../../../../login/loginRedirect";
import { NebulaAnalyticsPage } from "./components/analytics/nebula-analytics-page";
import { NebulaWaitListPage } from "./components/nebula-waitlist-page";
+import { NebulaFTUX } from "./nebula-ftux";
export default async function Page(props: {
params: Promise<{
@@ -42,7 +44,26 @@ export default async function Page(props: {
const hasNebulaAccess = team.enabledScopes.includes("nebula");
+ const activeResponse = await isProjectActive({
+ teamId: team.id,
+ projectId: project.id,
+ });
+
+ const showFTUX = !activeResponse.nebula;
+
if (hasNebulaAccess) {
+ if (showFTUX) {
+ return (
+
+
Nebula
+
+
+ );
+ }
+
return (