Skip to content

Commit a5d8226

Browse files
committed
[TOOL-3765] Dashboard: Add Insight FTUX
1 parent c7346f8 commit a5d8226

File tree

6 files changed

+313
-100
lines changed

6 files changed

+313
-100
lines changed

apps/dashboard/src/@/api/analytics.ts

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -270,9 +270,10 @@ type ActiveStatus = {
270270
ecosystemWallet: boolean;
271271
};
272272

273-
export async function isProjectActive(
274-
params: AnalyticsQueryParams,
275-
): Promise<ActiveStatus> {
273+
export async function isProjectActive(params: {
274+
teamId: string;
275+
projectId: string;
276+
}): Promise<ActiveStatus> {
276277
const searchParams = buildSearchParams(params);
277278
const res = await fetchAnalytics(
278279
`v2/active-usage?${searchParams.toString()}`,

apps/dashboard/src/app/team/[team_slug]/[project_slug]/components/ProjectFTUX/ProjectFTUX.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ function IntegrateAPIKeySection({
6262
<div>
6363
<h3>Client ID</h3>
6464
<p className="mb-2 text-muted-foreground text-sm">
65-
Identifies your application.
65+
Identifies your application
6666
</p>
6767

6868
<CopyTextButton
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
"use client";
2+
3+
import { CopyTextButton } from "@/components/ui/CopyTextButton";
4+
import { Button } from "@/components/ui/button";
5+
import { TabButtons } from "@/components/ui/tabs";
6+
import { TrackedLinkTW } from "@/components/ui/tracked-link";
7+
import { ExternalLinkIcon } from "lucide-react";
8+
import { useState } from "react";
9+
10+
export function WaitingForIntegrationCard(props: {
11+
title: string;
12+
clientId: string;
13+
codeTabs: {
14+
code: React.ReactNode;
15+
label: string;
16+
}[];
17+
ctas: {
18+
label: string;
19+
href: string;
20+
trackingLabel: string;
21+
}[];
22+
}) {
23+
const [selectedTab, setSelectedTab] = useState(props.codeTabs[0]?.label);
24+
return (
25+
<div className="rounded-lg border bg-card">
26+
<div className="border-b px-4 py-4 lg:px-6">
27+
<h2 className="font-semibold text-xl tracking-tight">{props.title}</h2>
28+
</div>
29+
30+
<div className="px-4 py-6 lg:p-6">
31+
{/* Client ID */}
32+
<div className="flex w-full flex-col">
33+
<h3 className="font-medium">Client ID</h3>
34+
<p className="mb-2 text-muted-foreground text-sm">
35+
Identifies your application
36+
</p>
37+
38+
<CopyTextButton
39+
textToCopy={props.clientId}
40+
className="!h-auto w-full max-w-[400px] justify-between truncate bg-background px-3 py-3 font-mono"
41+
textToShow={props.clientId}
42+
copyIconPosition="right"
43+
tooltip="Copy Client ID"
44+
/>
45+
</div>
46+
47+
<div className="h-4" />
48+
49+
{/* Code */}
50+
<div>
51+
<TabButtons
52+
tabClassName="!text-sm"
53+
tabs={props.codeTabs.map((tab) => ({
54+
name: tab.label,
55+
onClick: () => setSelectedTab(tab.label),
56+
isActive: tab.label === selectedTab,
57+
}))}
58+
/>
59+
<div className="h-2" />
60+
{props.codeTabs.find((tab) => tab.label === selectedTab)?.code}
61+
</div>
62+
</div>
63+
64+
<div className="flex flex-col gap-3 border-t p-4 lg:flex-row lg:items-center lg:justify-between lg:p-6">
65+
<div className="flex gap-3">
66+
{props.ctas.map((cta) => (
67+
<Button asChild key={cta.label} variant="outline" size="sm">
68+
<TrackedLinkTW
69+
href={cta.href}
70+
key={cta.label}
71+
target="_blank"
72+
className="gap-2"
73+
category="insight-ftux"
74+
label={cta.trackingLabel}
75+
>
76+
{cta.label}
77+
<ExternalLinkIcon className="size-4 text-muted-foreground" />
78+
</TrackedLinkTW>
79+
</Button>
80+
))}
81+
</div>
82+
83+
<p className="flex items-center gap-2 rounded-full border bg-background px-3.5 py-1.5 text-sm">
84+
<span className="!pointer-events-auto relative flex size-2">
85+
<span className="absolute inline-flex h-full w-full animate-ping rounded-full bg-sky-400 opacity-75" />
86+
<span className="relative inline-flex size-2 rounded-full bg-primary" />
87+
</span>
88+
Waiting for integration
89+
</p>
90+
</div>
91+
</div>
92+
);
93+
}
Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
import { Button } from "@/components/ui/button";
2+
import {
3+
Code2Icon,
4+
DatabaseIcon,
5+
ExternalLinkIcon,
6+
ZapIcon,
7+
} from "lucide-react";
8+
import Link from "next/link";
9+
10+
export function BlueprintCard() {
11+
const features = [
12+
{
13+
icon: Code2Icon,
14+
title: "Easy-to-Use API",
15+
description: "RESTful endpoints for any application",
16+
},
17+
{
18+
icon: DatabaseIcon,
19+
title: "Managed Infrastructure",
20+
description:
21+
"No need to index blockchains yourself or manage infrastructure and RPC costs.",
22+
},
23+
{
24+
icon: ZapIcon,
25+
title: "Lightning-Fast Queries",
26+
description: "Access any transaction, event or token API data",
27+
},
28+
];
29+
30+
return (
31+
<div className="rounded-lg border bg-card">
32+
{/* header */}
33+
<div className="border-b p-4 lg:px-6 lg:py-4">
34+
<div className="flex items-center justify-between">
35+
<h2 className="font-semibold text-2xl tracking-tight">Blueprints</h2>
36+
37+
<div className="flex items-center gap-2">
38+
<Button asChild variant="outline" className="gap-2 bg-background">
39+
<Link
40+
href="https://portal.thirdweb.com/insight/blueprints"
41+
target="_blank"
42+
>
43+
Docs <ExternalLinkIcon className="size-4" />
44+
</Link>
45+
</Button>
46+
</div>
47+
</div>
48+
</div>
49+
50+
{/* Content */}
51+
<div className="p-4 lg:p-6">
52+
<p className="mb-2 font-semibold text-xl leading-tight tracking-tight lg:mb-1">
53+
Simple endpoints for querying rich blockchain data
54+
</p>
55+
<p className="text-muted-foreground text-sm">
56+
A blueprint is an API that provides access to on-chain data in a
57+
user-friendly format. <br /> No need for ABIs, decoding, RPC, or web3
58+
knowledge required to fetch blockchain data.
59+
</p>
60+
61+
<div className="h-6" />
62+
63+
{/* Features */}
64+
<div className="flex flex-col gap-6">
65+
{features.map((feature) => (
66+
<div key={feature.title} className="flex items-start gap-3">
67+
<div className="rounded-full border p-2">
68+
<feature.icon className="size-4 text-muted-foreground" />
69+
</div>
70+
<div>
71+
<h4 className="font-medium">{feature.title}</h4>
72+
<p className="text-muted-foreground text-sm">
73+
{feature.description}
74+
</p>
75+
</div>
76+
</div>
77+
))}
78+
</div>
79+
</div>
80+
81+
{/* Playground link */}
82+
<div className="border-t p-4 lg:p-6">
83+
<Button className="w-full gap-2" asChild>
84+
<Link href="https://playground.thirdweb.com/insight" target="_blank">
85+
Try Insight blueprints in the playground
86+
<ExternalLinkIcon className="size-4" />
87+
</Link>
88+
</Button>
89+
</div>
90+
</div>
91+
);
92+
}
Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
import { CodeServer } from "@/components/ui/code/code.server";
2+
import { isProd } from "@/constants/env";
3+
import { WaitingForIntegrationCard } from "../components/WaitingForIntegrationCard/WaitingForIntegrationCard";
4+
5+
export function InsightFTUX(props: {
6+
clientId: string;
7+
}) {
8+
return (
9+
<WaitingForIntegrationCard
10+
title="Integrate Insight"
11+
clientId={props.clientId}
12+
codeTabs={[
13+
{
14+
label: "JavaScript",
15+
code: (
16+
<CodeServer
17+
code={jsCode(props.clientId)}
18+
className="bg-background"
19+
lang="ts"
20+
/>
21+
),
22+
},
23+
{
24+
label: "Python",
25+
code: (
26+
<CodeServer
27+
code={pythonCode(props.clientId)}
28+
className="bg-background"
29+
lang="python"
30+
/>
31+
),
32+
},
33+
{
34+
label: "Curl",
35+
code: (
36+
<CodeServer
37+
code={curlCode(props.clientId)}
38+
className="bg-background"
39+
lang="bash"
40+
/>
41+
),
42+
},
43+
]}
44+
ctas={[
45+
{
46+
label: "Try on Playground",
47+
href: "https://playground.thirdweb.com/insight",
48+
trackingLabel: "playground",
49+
},
50+
{
51+
label: "View Docs",
52+
href: "https://portal.thirdweb.com/insight",
53+
trackingLabel: "docs",
54+
},
55+
]}
56+
/>
57+
);
58+
}
59+
60+
const twDomain = isProd ? "thirdweb" : "thirdweb-dev";
61+
62+
const jsCode = (clientId: string) => `\
63+
// Example: Get latest 10 transactions on Ethereum
64+
const res = await fetch("https://insight.${twDomain}.com/v1/transactions?chain=1&limit=10&clientId=${clientId}");
65+
const data = await res.json();
66+
`;
67+
68+
const curlCode = (clientId: string) => `\
69+
# Example: Get latest 10 transactions on Ethereum
70+
curl -X GET "https://insight.${twDomain}.com/v1/transactions?chain=1&limit=10&clientId=${clientId}"
71+
`;
72+
73+
const pythonCode = (clientId: string) => `\
74+
# Example: Get latest 10 transactions on Ethereum
75+
import requests
76+
77+
response = requests.get("https://insight.${twDomain}.com/v1/transactions?chain=1&limit=10&clientId=${clientId}")
78+
data = response.json()
79+
`;

0 commit comments

Comments
 (0)