Skip to content

Commit 492a6a5

Browse files
committed
feat: dashboard analytics for webhooks
1 parent 7353f8b commit 492a6a5

File tree

11 files changed

+111
-164
lines changed

11 files changed

+111
-164
lines changed

apps/dashboard/.storybook/main.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,15 +9,13 @@ function getAbsolutePath(value: string): string {
99
return dirname(require.resolve(join(value, "package.json")));
1010
}
1111
const config: StorybookConfig = {
12+
stories: ["../src/**/*.stories.tsx"],
1213
addons: [
1314
getAbsolutePath("@storybook/addon-onboarding"),
1415
getAbsolutePath("@storybook/addon-links"),
1516
getAbsolutePath("@chromatic-com/storybook"),
1617
getAbsolutePath("@storybook/addon-docs"),
1718
],
18-
features: {
19-
experimentalRSC: true,
20-
},
2119
framework: {
2220
name: getAbsolutePath("@storybook/nextjs"),
2321
options: {},
@@ -28,6 +26,8 @@ const config: StorybookConfig = {
2826
},
2927
},
3028
staticDirs: ["../public"],
31-
stories: ["../src/**/*.stories.tsx"],
29+
features: {
30+
experimentalRSC: true,
31+
},
3232
};
3333
export default config;

apps/dashboard/.storybook/preview.tsx

Lines changed: 29 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,11 @@ import type { Preview } from "@storybook/nextjs";
22
import "../src/global.css";
33
import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
44
import { MoonIcon, SunIcon } from "lucide-react";
5-
import { Inter as interFont } from "next/font/google";
65
import { ThemeProvider, useTheme } from "next-themes";
6+
import { Inter as interFont } from "next/font/google";
77
// biome-ignore lint/style/useImportType: <explanation>
8-
import React, { useEffect } from "react";
8+
import React from "react";
9+
import { useEffect } from "react";
910
import { Toaster } from "sonner";
1011
import { Button } from "../src/@/components/ui/button";
1112

@@ -17,33 +18,45 @@ const fontSans = interFont({
1718
});
1819

1920
const customViewports = {
20-
sm: {
21-
// Larger phones (iphone 15 plus / 15 pro max)
22-
name: "iPhone Plus",
23-
styles: {
24-
height: "932px",
25-
width: "430px",
26-
},
27-
},
2821
xs: {
2922
// Regular sized phones (iphone 15 / 15 pro)
3023
name: "iPhone",
3124
styles: {
32-
height: "844px",
3325
width: "390px",
26+
height: "844px",
27+
},
28+
},
29+
sm: {
30+
// Larger phones (iphone 15 plus / 15 pro max)
31+
name: "iPhone Plus",
32+
styles: {
33+
width: "430px",
34+
height: "932px",
3435
},
3536
},
3637
};
3738

3839
const preview: Preview = {
40+
parameters: {
41+
viewport: {
42+
viewports: customViewports,
43+
},
44+
controls: {
45+
matchers: {
46+
color: /(background|color)$/i,
47+
date: /Date$/i,
48+
},
49+
},
50+
},
51+
3952
decorators: [
4053
(Story) => {
4154
return (
4255
<ThemeProvider
4356
attribute="class"
44-
defaultTheme="dark"
4557
disableTransitionOnChange
4658
enableSystem={false}
59+
defaultTheme="dark"
4760
>
4861
<StoryLayout>
4962
<Story />
@@ -52,22 +65,13 @@ const preview: Preview = {
5265
);
5366
},
5467
],
55-
parameters: {
56-
controls: {
57-
matchers: {
58-
color: /(background|color)$/i,
59-
date: /Date$/i,
60-
},
61-
},
62-
viewport: {
63-
viewports: customViewports,
64-
},
65-
},
6668
};
6769

6870
export default preview;
6971

70-
function StoryLayout(props: { children: React.ReactNode }) {
72+
function StoryLayout(props: {
73+
children: React.ReactNode;
74+
}) {
7175
const { setTheme, theme } = useTheme();
7276

7377
useEffect(() => {
@@ -79,10 +83,10 @@ function StoryLayout(props: { children: React.ReactNode }) {
7983
<div className="flex min-h-dvh min-w-0 flex-col bg-background text-foreground">
8084
<div className="fixed right-0 bottom-0 z-50 flex justify-end gap-2 p-4">
8185
<Button
82-
className="h-auto w-auto shrink-0 rounded-full p-2"
8386
onClick={() => setTheme(theme === "dark" ? "light" : "dark")}
8487
size="sm"
8588
variant="outline"
89+
className="h-auto w-auto shrink-0 rounded-full p-2"
8690
>
8791
{theme === "dark" ? (
8892
<MoonIcon className="size-4" />

apps/dashboard/public/assets/examples/example.json

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
11
[
22
{
3+
"name": "Your Collection #1",
4+
"description": "Remember to replace this description",
5+
"image": "ipfs://NewUriToReplace/1.png",
36
"attributes": [
47
{
58
"trait_type": "Background",
@@ -29,12 +32,12 @@
2932
"trait_type": "Top lid",
3033
"value": "High"
3134
}
32-
],
33-
"description": "Remember to replace this description",
34-
"image": "ipfs://NewUriToReplace/1.png",
35-
"name": "Your Collection #1"
35+
]
3636
},
3737
{
38+
"name": "Your Collection #2",
39+
"description": "Remember to replace this description",
40+
"image": "ipfs://NewUriToReplace/2.png",
3841
"attributes": [
3942
{
4043
"trait_type": "Background",
@@ -64,9 +67,6 @@
6467
"trait_type": "Top lid",
6568
"value": "Middle"
6669
}
67-
],
68-
"description": "Remember to replace this description",
69-
"image": "ipfs://NewUriToReplace/2.png",
70-
"name": "Your Collection #2"
70+
]
7171
}
7272
]

apps/dashboard/redirects.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -106,9 +106,9 @@ const projectPageRedirects = [
106106
source: `${projectRoute}/nebula/:path*`,
107107
},
108108
{
109+
source: `${projectRoute}/connect/analytics`,
109110
destination: `${projectRoute}`,
110111
permanent: false,
111-
source: `${projectRoute}/connect/analytics`,
112112
},
113113
];
114114

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

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,9 +24,7 @@ async function fetchAnalytics(
2424
input: string | URL,
2525
init?: RequestInit,
2626
): Promise<Response> {
27-
// const token = await getAuthToken();
28-
// DEBUG
29-
const token = 'eyJhbGciOiJFUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiIweDAxNjc1N2REZjJBYjZhOTk4YTQ3MjlBODBhMDkxMzA4ZDkwNTlFMTciLCJzdWIiOiIweGE1Qjg0OTJEODIyM0QyNTVkQjI3OUM3YzNlYmRBMzRCZTVlQzlEODUiLCJhdWQiOiJ0aGlyZHdlYi5jb20iLCJleHAiOjE3NTA4NjU2NzQsIm5iZiI6MTc1MDYwNTg3MiwiaWF0IjoxNzUwNjA2NDc0LCJqdGkiOiIzNmNjOGExYjBhYWY5ODA4ZWEyMjIyOTc4MzI5NDEwMzlkNDA2OTE0ZTJhN2U3YTQxYmM4ZDc1MWJiOTAzODk4IiwiY3R4Ijp7fX0.MHgzZGE4ZGUyM2M1Y2U2ZGExNWY0MTM4OGM3YjFjM2ZhNWNjODlkMDM3M2Q0ZjJkZDg0NGNmZWM1OTJlNTY4MDY3NGY2MmJkNWY1ZWIxMWIyYWRkNmRkN2Q3NmFlNWJjNTgxNWYzNTYwNDk3NzVkYjNiZGJlNTVjNDQyNDFjMTYzZTFi';
27+
const token = await getAuthToken();
3028
if (!token) {
3129
throw new Error("You are not authorized to perform this action");
3230
}

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

Lines changed: 24 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -4,26 +4,26 @@ import "server-only";
44
import { NEXT_PUBLIC_THIRDWEB_API_HOST } from "@/constants/public-envs";
55
import { getAuthToken } from "./auth-token";
66

7-
export type WebhookConfig = {
8-
id: string;
9-
description: string | null;
10-
createdAt: Date;
11-
updatedAt: Date;
12-
deletedAt: Date | null;
13-
teamId: string;
14-
projectId: string;
15-
destinationUrl: string;
16-
pausedAt: Date | null;
17-
webhookSecret: string;
18-
}
7+
export type WebhookConfig = {
8+
id: string;
9+
description: string | null;
10+
createdAt: Date;
11+
updatedAt: Date;
12+
deletedAt: Date | null;
13+
teamId: string;
14+
projectId: string;
15+
destinationUrl: string;
16+
pausedAt: Date | null;
17+
webhookSecret: string;
18+
};
1919

2020
export async function getWebhookConfigs(
2121
teamIdOrSlug: string,
2222
projectIdOrSlug: string,
23-
): Promise< {data: WebhookConfig[] } | {error: string}> {
23+
): Promise<{ data: WebhookConfig[] } | { error: string }> {
2424
const token = await getAuthToken();
2525
if (!token) {
26-
return { error: "Unauthorized." }
26+
return { error: "Unauthorized." };
2727
}
2828

2929
const res = await fetch(
@@ -35,14 +35,15 @@ export async function getWebhookConfigs(
3535
},
3636
);
3737
try {
38-
const json = (await res.json()) as { data: WebhookConfig[],
39-
error: { message: string};
40-
};
41-
if (json.error) {
42-
return { error: json.error.message }
43-
}
44-
return { data: json.data }
45-
} catch (e) {
46-
return { error: "Failed to fetch webhooks." }
38+
const json = (await res.json()) as {
39+
data: WebhookConfig[];
40+
error: { message: string };
41+
};
42+
if (json.error) {
43+
return { error: json.error.message };
44+
}
45+
return { data: json.data };
46+
} catch {
47+
return { error: "Failed to fetch webhooks." };
4748
}
4849
}

0 commit comments

Comments
 (0)