Skip to content

Commit e47732f

Browse files
authored
Remove prefixWorkspaceId from recordLink, update admin (#3024)
1 parent 69de8fd commit e47732f

File tree

5 files changed

+150
-86
lines changed

5 files changed

+150
-86
lines changed

apps/web/app/(ee)/admin.dub.co/(dashboard)/components/user-info.tsx

Lines changed: 110 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
"use client";
2-
import { Badge, Copy, Tick, useCopyToClipboard } from "@dub/ui";
2+
import { PartnerStatusBadges } from "@/ui/partners/partner-status-badges";
3+
import { Badge, Copy, StatusBadge, Tick, useCopyToClipboard } from "@dub/ui";
34
import { capitalize, nFormatter } from "@dub/utils";
45
import { toast } from "sonner";
56

@@ -15,22 +16,41 @@ export interface UserInfoProps {
1516
totalClicks: number;
1617
totalLinks: number;
1718
}[];
19+
programs: {
20+
id: string;
21+
name: string;
22+
slug: string;
23+
status: string;
24+
totalClicks: number;
25+
totalLeads: number;
26+
totalConversions: number;
27+
totalSaleAmount: number;
28+
totalCommissions: number;
29+
}[];
1830
impersonateUrl: {
1931
app: string;
2032
partners: string;
2133
};
2234
}
2335

24-
const items = [
36+
const workspaceItems = [
2537
{ id: "clicks", label: "Clicks" },
2638
{ id: "links", label: "Links" },
2739
{ id: "totalClicks", label: "Total Clicks" },
2840
{ id: "totalLinks", label: "Total Links" },
2941
];
3042

43+
const programItems = [
44+
{ id: "totalClicks", label: "Total Clicks" },
45+
{ id: "totalLeads", label: "Total Leads" },
46+
{ id: "totalConversions", label: "Total Conversions" },
47+
{ id: "totalSaleAmount", label: "Total Sales", isCurrency: true },
48+
{ id: "totalCommissions", label: "Total Commissions", isCurrency: true },
49+
];
50+
3151
export default function UserInfo({ data }: { data: UserInfoProps }) {
3252
return (
33-
<div className="grid gap-2">
53+
<div className="grid gap-4">
3454
<LoginLinkCopyButton text={data.email} url={data.email} />
3555
<LoginLinkCopyButton
3656
text="app.dub.co login link"
@@ -40,39 +60,96 @@ export default function UserInfo({ data }: { data: UserInfoProps }) {
4060
text="partners.dub.co login link"
4161
url={data.impersonateUrl.partners}
4262
/>
43-
<div className="grid grid-cols-2 gap-4">
44-
{data.workspaces.map((workspace) => (
45-
<div
46-
key={workspace.slug}
47-
className="flex flex-col space-y-2 rounded-lg border border-neutral-200 p-2"
48-
>
49-
<div className="flex items-center space-x-2">
50-
<p className="font-semibold">{workspace.name}</p>
51-
<Badge className="lowercase">{workspace.slug}</Badge>
52-
</div>
53-
<div className="flex justify-between text-sm">
54-
<span className="font-medium text-neutral-700">ID</span>
55-
<span className="text-neutral-500">{workspace.id}</span>
56-
</div>
57-
<div className="flex justify-between text-sm">
58-
<span className="font-medium text-neutral-700">Plan</span>
59-
<span className="text-neutral-500">
60-
{capitalize(workspace.plan)}
61-
</span>
62-
</div>
63-
{items.map((item) => (
64-
<div className="flex justify-between text-sm">
65-
<span className="font-medium text-neutral-700">
66-
{item.label}
67-
</span>
68-
<span className="text-neutral-500">
69-
{nFormatter(workspace[item.id], { full: true })}
70-
</span>
63+
64+
{data.workspaces.length > 0 && (
65+
<div>
66+
<h3 className="mb-2 text-sm font-semibold text-neutral-900">
67+
Workspaces
68+
</h3>
69+
<div className="grid grid-cols-2 gap-4">
70+
{data.workspaces.map((workspace) => (
71+
<div
72+
key={workspace.slug}
73+
className="flex flex-col space-y-2 rounded-lg border border-neutral-200 p-2"
74+
>
75+
<div className="flex items-center space-x-2">
76+
<p className="font-semibold">{workspace.name}</p>
77+
<Badge className="lowercase">{workspace.slug}</Badge>
78+
</div>
79+
<div className="flex justify-between text-sm">
80+
<span className="font-medium text-neutral-700">ID</span>
81+
<span className="text-neutral-500">{workspace.id}</span>
82+
</div>
83+
<div className="flex justify-between text-sm">
84+
<span className="font-medium text-neutral-700">Plan</span>
85+
<span className="text-neutral-500">
86+
{capitalize(workspace.plan)}
87+
</span>
88+
</div>
89+
{workspaceItems.map((item) => (
90+
<div key={item.id} className="flex justify-between text-sm">
91+
<span className="font-medium text-neutral-700">
92+
{item.label}
93+
</span>
94+
<span className="text-neutral-500">
95+
{nFormatter(workspace[item.id], { full: true })}
96+
</span>
97+
</div>
98+
))}
7199
</div>
72100
))}
73101
</div>
74-
))}
75-
</div>
102+
</div>
103+
)}
104+
105+
{data.workspaces.length > 0 && data.programs.length > 0 && (
106+
<div className="my-2 border-b border-neutral-200" />
107+
)}
108+
109+
{data.programs.length > 0 && (
110+
<div>
111+
<h3 className="mb-2 text-sm font-semibold text-neutral-900">
112+
Programs
113+
</h3>
114+
<div className="grid grid-cols-2 gap-4">
115+
{data.programs.map((program) => (
116+
<div
117+
key={program.id}
118+
className="flex flex-col space-y-2 rounded-lg border border-neutral-200 p-2"
119+
>
120+
<div className="flex items-center space-x-2">
121+
<p className="font-semibold">{program.name}</p>
122+
<Badge className="lowercase">{program.slug}</Badge>
123+
</div>
124+
<div className="flex justify-between text-sm">
125+
<span className="font-medium text-neutral-700">ID</span>
126+
<span className="text-neutral-500">{program.id}</span>
127+
</div>
128+
<div className="flex justify-between text-sm">
129+
<span className="font-medium text-neutral-700">Status</span>
130+
<StatusBadge
131+
variant={PartnerStatusBadges[program.status].variant}
132+
>
133+
{PartnerStatusBadges[program.status].label}
134+
</StatusBadge>
135+
</div>
136+
{programItems.map((item) => (
137+
<div key={item.id} className="flex justify-between text-sm">
138+
<span className="font-medium text-neutral-700">
139+
{item.label}
140+
</span>
141+
<span className="text-neutral-500">
142+
{item.isCurrency
143+
? `$${nFormatter(program[item.id], { full: true })}`
144+
: nFormatter(program[item.id], { full: true })}
145+
</span>
146+
</div>
147+
))}
148+
</div>
149+
))}
150+
</div>
151+
</div>
152+
)}
76153
</div>
77154
);
78155
}

apps/web/app/(ee)/api/admin/impersonate/route.ts

Lines changed: 39 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
import { prefixWorkspaceId } from "@/lib/api/workspaces/workspace-id";
21
import { hashToken, withAdmin } from "@/lib/auth";
32
import { prisma } from "@dub/prisma";
43
import { APP_DOMAIN, PARTNERS_DOMAIN } from "@dub/utils";
@@ -39,6 +38,39 @@ export const POST = withAdmin(async ({ req }) => {
3938
},
4039
},
4140
},
41+
orderBy: {
42+
project: {
43+
totalClicks: "desc",
44+
},
45+
},
46+
},
47+
partners: {
48+
select: {
49+
partner: {
50+
select: {
51+
programs: {
52+
select: {
53+
program: {
54+
select: {
55+
id: true,
56+
name: true,
57+
slug: true,
58+
},
59+
},
60+
status: true,
61+
totalClicks: true,
62+
totalLeads: true,
63+
totalConversions: true,
64+
totalSaleAmount: true,
65+
totalCommissions: true,
66+
},
67+
orderBy: {
68+
totalCommissions: "desc",
69+
},
70+
},
71+
},
72+
},
73+
},
4274
},
4375
},
4476
});
@@ -51,12 +83,17 @@ export const POST = withAdmin(async ({ req }) => {
5183
email: response.email,
5284
workspaces: response.projects.map(({ project }) => ({
5385
...project,
54-
id: prefixWorkspaceId(project.id),
5586
clicks: project.usage,
5687
links: project.linksUsage,
5788
totalClicks: project.totalClicks,
5889
totalLinks: project.totalLinks,
5990
})),
91+
programs: response.partners[0].partner.programs.map(
92+
({ program, ...rest }) => ({
93+
...program,
94+
...rest,
95+
}),
96+
),
6097
impersonateUrl: await getImpersonateUrl(response.email),
6198
};
6299

apps/web/app/app.dub.co/(dashboard)/[slug]/settings/(basic-layout)/page-client.tsx

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@ import { clientAccessCheck } from "@/lib/api/tokens/permissions";
44
import useWorkspace from "@/lib/swr/use-workspace";
55
import DeleteWorkspace from "@/ui/workspaces/delete-workspace";
66
import UploadLogo from "@/ui/workspaces/upload-logo";
7-
import WorkspaceId from "@/ui/workspaces/workspace-id";
87
import { Form } from "@dub/ui";
98
import { useSession } from "next-auth/react";
109
import { useRouter } from "next/navigation";
@@ -92,7 +91,6 @@ export default function WorkspaceSettingsClient() {
9291
}
9392
/>
9493
<UploadLogo />
95-
<WorkspaceId />
9694
<DeleteWorkspace />
9795
</>
9896
);

apps/web/lib/tinybird/record-link.ts

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@ import { waitUntil } from "@vercel/functions";
22
import { z } from "zod";
33
import { ExpandedLink } from "../api/links";
44
import { decodeKeyIfCaseSensitive } from "../api/links/case-sensitivity";
5-
import { prefixWorkspaceId } from "../api/workspaces/workspace-id";
65
import { tb, tbOld } from "./client";
76

87
export const dubLinksMetadataSchema = z.object({
@@ -46,10 +45,7 @@ export const recordLinkTB = tb.buildIngestEndpoint({
4645
workspace_id: z
4746
.string()
4847
.nullish()
49-
.transform((v) => {
50-
if (!v) return ""; // return empty string if null or undefined
51-
return prefixWorkspaceId(v);
52-
}),
48+
.transform((v) => (v ? v : "")),
5349
}),
5450
wait: true,
5551
});

apps/web/ui/workspaces/workspace-id.tsx

Lines changed: 0 additions & 44 deletions
This file was deleted.

0 commit comments

Comments
 (0)