Skip to content

Commit f6c33c4

Browse files
committed
[TOOL-3684] Dashboard: Add FTUX in project overview page
1 parent 6fc6c6e commit f6c33c4

File tree

15 files changed

+272
-23
lines changed

15 files changed

+272
-23
lines changed

apps/dashboard/src/@/components/blocks/code-segment.client.tsx

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,6 @@ export const CodeSegment: React.FC<CodeSegmentProps> = ({
9696
onClick: () => setEnvironment(env.environment),
9797
isActive: activeEnvironment === env.environment,
9898
name: env.title,
99-
isEnabled: true,
10099
}))}
101100
tabClassName="text-sm gap-2 !text-sm"
102101
tabIconClassName="size-4"

apps/dashboard/src/@/components/ui/DatePickerWithRange.tsx

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -91,13 +91,11 @@ export function DatePickerWithRange(props: {
9191
name: "From",
9292
onClick: () => setScreen("from"),
9393
isActive: screen === "from",
94-
isEnabled: true,
9594
},
9695
{
9796
name: "To",
9897
onClick: () => setScreen("to"),
9998
isActive: screen === "to",
100-
isEnabled: true,
10199
},
102100
]}
103101
/>

apps/dashboard/src/@/components/ui/tabs.tsx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,7 @@ export function TabButtons(props: {
7979
name: React.ReactNode;
8080
onClick: () => void;
8181
isActive: boolean;
82-
isEnabled?: boolean;
82+
isDisabled?: boolean;
8383
icon?: React.FC<{ className?: string }>;
8484
}[];
8585
tabClassName?: string;
@@ -119,11 +119,11 @@ export function TabButtons(props: {
119119
"relative inline-flex h-auto items-center gap-1.5 rounded-lg px-2 font-medium text-sm hover:bg-accent lg:px-3 lg:text-base",
120120
!tab.isActive &&
121121
"text-muted-foreground hover:text-foreground",
122-
!tab.isEnabled && "cursor-not-allowed opacity-50",
122+
tab.isDisabled && "cursor-not-allowed opacity-50",
123123
props.tabClassName,
124124
tab.isActive && props.activeTabClassName,
125125
)}
126-
onClick={tab.isEnabled ? tab.onClick : undefined}
126+
onClick={!tab.isDisabled ? tab.onClick : undefined}
127127
>
128128
{tab.icon && (
129129
<tab.icon className={cn("size-6", props.tabIconClassName)} />

apps/dashboard/src/app/(dashboard)/(chain)/[chain_id]/[contractAddress]/(marketplace)/components/list-button.tsx

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,6 @@ export const CreateListingButton: React.FC<CreateListingButtonProps> = ({
7171
name: mode,
7272
isActive: mode === listingMode,
7373
onClick: () => setListingMode(mode),
74-
isEnabled: true,
7574
}))}
7675
tabClassName="text-sm gap-2 !text-sm"
7776
tabContainerClassName="gap-0.5"

apps/dashboard/src/app/account/contracts/_components/GetStartedWithContractsDeploy.tsx

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,6 @@ const DeployOptions = (props: {
100100
key,
101101
name: value.title,
102102
isActive: activeTab === key,
103-
isEnabled: true,
104103
onClick: () => setActiveTab(key as TabId),
105104
}))}
106105
tabClassName="font-medium"

apps/dashboard/src/app/login/onboarding/LoginOrSignup/LoginOrSignup.tsx

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -89,13 +89,11 @@ export function LoginOrSignup(props: {
8989
name: "Create account",
9090
onClick: () => setTab("signup"),
9191
isActive: tab === "signup",
92-
isEnabled: true,
9392
},
9493
{
9594
name: "I already have an account",
9695
onClick: () => setTab("login"),
9796
isActive: tab === "login",
98-
isEnabled: true,
9997
},
10098
]}
10199
/>

apps/dashboard/src/app/login/onboarding/team-onboarding/InviteTeamMembers.tsx

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -227,13 +227,11 @@ function InviteModalContent(props: {
227227
name: "Starter",
228228
onClick: () => setPlanToShow("starter"),
229229
isActive: planToShow === "starter",
230-
isEnabled: true,
231230
},
232231
{
233232
name: "Growth",
234233
onClick: () => setPlanToShow("growth"),
235234
isActive: planToShow === "growth",
236-
isEnabled: true,
237235
},
238236
]}
239237
/>

apps/dashboard/src/app/team/[team_slug]/(team)/~/engine/(instance)/[engineId]/configuration/components/engine-wallet-config.tsx

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,6 @@ export const EngineWalletConfig: React.FC<EngineWalletConfigProps> = ({
8686
key,
8787
name,
8888
isActive: activeTab === key,
89-
isEnabled: true,
9089
onClick: () => setActiveTab(key),
9190
icon:
9291
(key === "aws-kms" && !isAwsKmsConfigured) ||

apps/dashboard/src/app/team/[team_slug]/(team)/~/settings/members/TeamMembersSettingsPage.tsx

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -62,13 +62,11 @@ export function TeamMembersSettingsPage(props: {
6262
isActive: manageTab === "members",
6363
name: "Team Members",
6464
onClick: () => setManageTab("members"),
65-
isEnabled: true,
6665
},
6766
{
6867
isActive: manageTab === "invites",
6968
name: "Pending Invites",
7069
onClick: () => setManageTab("invites"),
71-
isEnabled: true,
7270
},
7371
]}
7472
/>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
"use client";
2+
3+
import { useState } from "react";
4+
import { TabButtons } from "../../../../../../@/components/ui/tabs";
5+
6+
type Tab = "ts" | "react" | "react-native" | "dotnet" | "unity" | "unreal";
7+
8+
export function IntegrateAPIKeyCodeTabs(props: {
9+
tabs: Record<Tab, React.ReactNode>;
10+
}) {
11+
const [tab, setTab] = useState<Tab>("ts");
12+
13+
return (
14+
<div>
15+
<TabButtons
16+
tabs={[
17+
{
18+
name: "TypeScript",
19+
onClick: () => setTab("ts"),
20+
isActive: tab === "ts",
21+
},
22+
{
23+
name: "React",
24+
onClick: () => setTab("react"),
25+
isActive: tab === "react",
26+
},
27+
{
28+
name: "React Native",
29+
onClick: () => setTab("react-native"),
30+
isActive: tab === "react-native",
31+
},
32+
{
33+
name: ".NET",
34+
onClick: () => setTab("dotnet"),
35+
isActive: tab === "dotnet",
36+
},
37+
{
38+
name: "Unity",
39+
onClick: () => setTab("unity"),
40+
isActive: tab === "unity",
41+
},
42+
{
43+
name: "Unreal Engine",
44+
onClick: () => setTab("unreal"),
45+
isActive: tab === "unreal",
46+
},
47+
]}
48+
/>
49+
<div className="h-3" />
50+
{props.tabs[tab]}
51+
</div>
52+
);
53+
}
Lines changed: 193 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,193 @@
1+
import type { Project } from "@/api/projects";
2+
import { CopyTextButton } from "@/components/ui/CopyTextButton";
3+
import { CircleAlertIcon } from "lucide-react";
4+
import { UnderlineLink } from "../../../../../../@/components/ui/UnderlineLink";
5+
import {
6+
Alert,
7+
AlertDescription,
8+
AlertTitle,
9+
} from "../../../../../../@/components/ui/alert";
10+
import { CodeServer } from "../../../../../../@/components/ui/code/code.server";
11+
import { IntegrateAPIKeyCodeTabs } from "./IntegrateAPIKeyCodeTabs";
12+
import { dotNotCodeExample, typescriptCodeExample } from "./codeExamples";
13+
14+
export function ProjectFTUX(props: { project: Project; teamSlug: string }) {
15+
return (
16+
<div>
17+
<ProjectKeyDetailsCard
18+
project={props.project}
19+
teamSlug={props.teamSlug}
20+
/>
21+
</div>
22+
);
23+
}
24+
25+
function ProjectKeyDetailsCard({
26+
project,
27+
teamSlug,
28+
}: {
29+
project: Project;
30+
teamSlug: string;
31+
}) {
32+
const secretKeyMasked = project.secretKeys[0]?.masked;
33+
const clientId = project.publishableKey;
34+
35+
return (
36+
<div className="rounded-lg border border-border bg-card px-4 py-6 lg:px-6">
37+
<h2 className="font-semibold text-xl tracking-tight">
38+
Integrate API key
39+
</h2>
40+
41+
<div className="h-4" />
42+
43+
<div className="flex flex-col gap-6 ">
44+
<div>
45+
<h3>Client ID</h3>
46+
<p className="mb-2 text-muted-foreground text-sm">
47+
Identifies your application.
48+
</p>
49+
50+
<CopyTextButton
51+
textToCopy={clientId}
52+
className="!h-auto w-full max-w-[350px] justify-between truncate bg-background px-3 py-3 font-mono"
53+
textToShow={clientId}
54+
copyIconPosition="right"
55+
tooltip="Copy Client ID"
56+
/>
57+
</div>
58+
59+
{/* NOTE: for very old api keys the secret might be `null`, if that's the case we skip it */}
60+
{secretKeyMasked && (
61+
<div>
62+
<h3>Secret Key</h3>
63+
<p className="mb-2 text-muted-foreground text-sm">
64+
Identifies and authenticates your application from a backend.{" "}
65+
<br /> This is not the full secret key, Refer to your saved secret
66+
key at the time of creation for the full secret key.
67+
</p>
68+
69+
<div className="flex flex-col gap-3 lg:flex-row lg:items-center">
70+
<div className="rounded-lg border border-border bg-background px-4 py-3 font-mono text-sm lg:w-[350px]">
71+
{secretKeyMasked}
72+
</div>
73+
</div>
74+
</div>
75+
)}
76+
</div>
77+
78+
<div className="h-6" />
79+
80+
<ProjectKeyTabs project={project} teamSlug={teamSlug} />
81+
</div>
82+
);
83+
}
84+
85+
function ProjectKeyTabs(props: { project: Project; teamSlug: string }) {
86+
return (
87+
<IntegrateAPIKeyCodeTabs
88+
tabs={{
89+
ts: (
90+
<CodeServer
91+
code={typescriptCodeExample(props.project)}
92+
lang="ts"
93+
className="bg-background"
94+
/>
95+
),
96+
react: (
97+
<CodeServer
98+
code={typescriptCodeExample(props.project)}
99+
lang="ts"
100+
className="bg-background"
101+
/>
102+
),
103+
"react-native": (
104+
<CodeServer
105+
code={typescriptCodeExample(props.project)}
106+
lang="ts"
107+
className="bg-background"
108+
/>
109+
),
110+
unity: (
111+
<Alert variant="info" className="bg-background">
112+
<CircleAlertIcon className="size-5" />
113+
<AlertTitle>
114+
Configure Client ID in Thirdweb Manager prefab
115+
</AlertTitle>
116+
<AlertDescription className="leading-relaxed">
117+
Configure "Client ID" and "Bundle ID" in{" "}
118+
<UnderlineLink
119+
href="https://portal.thirdweb.com/unity/v5/thirdwebmanager"
120+
target="_blank"
121+
>
122+
Thirdweb Manager prefab
123+
</UnderlineLink>
124+
<span className="block text-sm">
125+
Make sure to configure your app's bundle ID in "Allowed Bundle
126+
IDs" in{" "}
127+
<UnderlineLink
128+
target="_blank"
129+
href={`/team/${props.teamSlug}/${props.project.slug}/settings`}
130+
>
131+
Project settings
132+
</UnderlineLink>
133+
</span>
134+
</AlertDescription>
135+
</Alert>
136+
),
137+
dotnet: (
138+
<div className="flex flex-col gap-3">
139+
<CodeServer
140+
code={dotNotCodeExample(props.project)}
141+
lang="csharp"
142+
className="bg-background"
143+
/>
144+
<Alert variant="info" className="bg-background">
145+
<CircleAlertIcon className="size-5" />
146+
<AlertTitle>
147+
Configure your app's bundle ID in "Allowed Bundle IDs" in
148+
Project
149+
</AlertTitle>
150+
<AlertDescription>
151+
Go to{" "}
152+
<UnderlineLink
153+
target="_blank"
154+
href={`/team/${props.teamSlug}/${props.project.slug}/settings`}
155+
>
156+
Project settings
157+
</UnderlineLink>{" "}
158+
and add your app's bundle ID to the "Allowed Bundle IDs" list.
159+
</AlertDescription>
160+
</Alert>
161+
</div>
162+
),
163+
unreal: (
164+
<Alert variant="info" className="bg-background">
165+
<CircleAlertIcon className="size-5" />
166+
<AlertTitle>
167+
Configure Client ID in Thirdweb Unreal Plugin{" "}
168+
</AlertTitle>
169+
<AlertDescription className="leading-relaxed">
170+
Follow the steps mentioned in{" "}
171+
<UnderlineLink
172+
href="https://portal.thirdweb.com/unity/v5/thirdwebmanager"
173+
target="_blank"
174+
>
175+
Getting Started with Thirdweb Unreal Plugin
176+
</UnderlineLink>
177+
<span className="block text-sm">
178+
Make sure to configure your app's bundle ID in "Allowed Bundle
179+
IDs" in{" "}
180+
<UnderlineLink
181+
target="_blank"
182+
href={`/team/${props.teamSlug}/${props.project.slug}/settings`}
183+
>
184+
Project settings
185+
</UnderlineLink>
186+
</span>
187+
</AlertDescription>
188+
</Alert>
189+
),
190+
}}
191+
/>
192+
);
193+
}
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
import type { Project } from "@/api/projects";
2+
3+
export const typescriptCodeExample = (project: Project) => `\
4+
import { createThirdwebClient } from "thirdweb";
5+
6+
const client = createThirdwebClient({
7+
// use clientId for client side usage
8+
clientId: "${project.publishableKey}",
9+
// use secretKey for server side usage
10+
secretKey: "${project.secretKeys[0]?.masked}", // replace this with full secret key
11+
});`;
12+
13+
export const dotNotCodeExample = (project: Project) => `\
14+
// For web applications
15+
var client = ThirdwebClient.Create(clientId: "${project.publishableKey}");
16+
17+
// For native applications - Replace "yourBundleId" with your app's bundle ID
18+
var client = ThirdwebClient.Create(clientId: "${project.publishableKey}", bundleId: "yourBundleId");
19+
20+
// For backend applications (Note: below shown secret key is not the full secret key)
21+
var client = ThirdwebClient.Create(secretKey: "${project.secretKeys[0]?.masked}");`;

0 commit comments

Comments
 (0)