Skip to content

Commit bef044d

Browse files
authored
Merge branch 'main' into yash/deploy-config-updates-2
2 parents 24313e9 + f693ab8 commit bef044d

File tree

127 files changed

+5547
-1997
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

127 files changed

+5547
-1997
lines changed

.changeset/config.json

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,13 @@
1010
"access": "public",
1111
"baseBranch": "main",
1212
"updateInternalDependencies": "patch",
13-
"ignore": ["playground-web", "thirdweb-dashboard", "wallet-ui", "portal"],
13+
"ignore": [
14+
"playground-web",
15+
"thirdweb-dashboard",
16+
"wallet-ui",
17+
"portal",
18+
"thirdweb-login"
19+
],
1420
"___experimentalUnsafeOptions_WILL_CHANGE_IN_PATCH": {
1521
"updateInternalDependents": "always",
1622
"onlyUpdatePeerDependentsWhenOutOfRange": true

README.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
<p align="center">
22
<br />
33
<a href="https://thirdweb.com">
4-
<img src="https://github.com/thirdweb-dev/js/blob/main/legacy_packages/sdk/logo.svg?raw=true" width="200" alt=""/></a>
4+
<img src="https://thirdweb.com/brand/thirdweb-icon.svg" width="200" alt=""/></a>
55
<br />
66
</p>
77

@@ -31,12 +31,12 @@
3131

3232
## Library Comparison
3333

34-
| | thirdweb | Wagmi + Viem | Ethers@6 |
34+
| | thirdweb | Wagmi + Viem | Ethers@6 |
3535
| ----------------------------------------- | -------- | ------------------ | -------- |
3636
| Type safe contract API ||||
3737
| Type safe wallet API ||||
3838
| EVM utils ||||
39-
| RPC for any EVM | ✅  | ⚠️ public RPC only ||
39+
| RPC for any EVM | ✅  | ⚠️ public RPC only ||
4040
| Automatic ABI Resolution ||||
4141
| IPFS Upload/Download ||||
4242
| Embedded wallet (email/ social login) || ⚠️ via 3rd party ||
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
"use server";
2+
3+
import { getAuthToken } from "../../app/api/lib/getAuthToken";
4+
import { API_SERVER_URL } from "../constants/env";
5+
6+
export async function acceptInvite(options: {
7+
teamId: string;
8+
inviteId: string;
9+
}) {
10+
const token = await getAuthToken();
11+
12+
if (!token) {
13+
return {
14+
ok: false,
15+
errorMessage: "You are not authorized to perform this action",
16+
};
17+
}
18+
19+
const res = await fetch(
20+
`${API_SERVER_URL}/v1/teams/${options.teamId}/invites/${options.inviteId}/accept`,
21+
{
22+
method: "POST",
23+
headers: {
24+
"Content-Type": "application/json",
25+
Authorization: `Bearer ${token}`,
26+
},
27+
body: JSON.stringify({}),
28+
},
29+
);
30+
31+
if (!res.ok) {
32+
let errorMessage = "Failed to accept invite";
33+
try {
34+
const result = (await res.json()) as {
35+
error: {
36+
code: string;
37+
message: string;
38+
statusCode: number;
39+
};
40+
};
41+
errorMessage = result.error.message;
42+
} catch {}
43+
44+
return {
45+
ok: false,
46+
errorMessage,
47+
};
48+
}
49+
50+
return {
51+
ok: true,
52+
};
53+
}
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
"use server";
2+
3+
import { getAuthToken } from "../../app/api/lib/getAuthToken";
4+
import { API_SERVER_URL } from "../constants/env";
5+
6+
export async function sendTeamInvites(options: {
7+
teamId: string;
8+
invites: Array<{ email: string; role: "OWNER" | "MEMBER" }>;
9+
}): Promise<
10+
| {
11+
ok: true;
12+
results: Array<"fulfilled" | "rejected">;
13+
}
14+
| {
15+
ok: false;
16+
errorMessage: string;
17+
}
18+
> {
19+
const token = await getAuthToken();
20+
21+
if (!token) {
22+
return {
23+
ok: false,
24+
errorMessage: "You are not authorized to perform this action",
25+
};
26+
}
27+
28+
const results = await Promise.allSettled(
29+
options.invites.map((invite) => sendInvite(options.teamId, invite, token)),
30+
);
31+
32+
return {
33+
ok: true,
34+
results: results.map((x) => x.status),
35+
};
36+
}
37+
38+
async function sendInvite(
39+
teamId: string,
40+
invite: { email: string; role: "OWNER" | "MEMBER" },
41+
token: string,
42+
) {
43+
const res = await fetch(`${API_SERVER_URL}/v1/teams/${teamId}/invites`, {
44+
method: "POST",
45+
headers: {
46+
Authorization: `Bearer ${token}`,
47+
"Content-Type": "application/json",
48+
},
49+
body: JSON.stringify({
50+
inviteEmail: invite.email,
51+
inviteRole: invite.role,
52+
}),
53+
});
54+
55+
if (!res.ok) {
56+
const errorMessage = await res.text();
57+
return {
58+
email: invite.email,
59+
ok: false,
60+
errorMessage,
61+
};
62+
}
63+
64+
return {
65+
email: invite.email,
66+
ok: true,
67+
};
68+
}
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
import { getAuthToken } from "../../app/api/lib/getAuthToken";
2+
import { API_SERVER_URL } from "../constants/env";
3+
4+
export type LinkedWallet = {
5+
createdAt: string;
6+
id: string;
7+
walletAddress: string;
8+
};
9+
10+
export async function getLinkedWallets() {
11+
const token = await getAuthToken();
12+
13+
if (!token) {
14+
return null;
15+
}
16+
17+
const res = await fetch(`${API_SERVER_URL}/v1/account/wallets`, {
18+
headers: {
19+
Authorization: `Bearer ${token}`,
20+
},
21+
});
22+
23+
if (res.ok) {
24+
const json = (await res.json()) as {
25+
data: LinkedWallet[];
26+
};
27+
28+
return json.data;
29+
}
30+
31+
return null;
32+
}
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
import { getAuthToken } from "../../app/api/lib/getAuthToken";
2+
import { API_SERVER_URL } from "../constants/env";
3+
4+
export type TeamInvite = {
5+
id: string;
6+
teamId: string;
7+
email: string;
8+
role: "OWNER" | "MEMBER";
9+
createdAt: string;
10+
status: "pending" | "accepted" | "expired";
11+
expiresAt: string;
12+
};
13+
14+
export async function getTeamInvites(
15+
teamId: string,
16+
options: {
17+
count: number;
18+
start: number;
19+
},
20+
) {
21+
const authToken = await getAuthToken();
22+
23+
if (!authToken) {
24+
throw new Error("Unauthorized");
25+
}
26+
27+
const res = await fetch(
28+
`${API_SERVER_URL}/v1/teams/${teamId}/invites?skip=${options.start}&take=${options.count}`,
29+
{
30+
headers: {
31+
Authorization: `Bearer ${authToken}`,
32+
},
33+
},
34+
);
35+
36+
if (!res.ok) {
37+
const errorMessage = await res.text();
38+
throw new Error(errorMessage);
39+
}
40+
41+
const json = (await res.json()) as {
42+
result: TeamInvite[];
43+
};
44+
45+
return json.result;
46+
}

apps/dashboard/src/@/api/team-members.ts

Lines changed: 28 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,15 +12,16 @@ export type TeamAccountRole =
1212

1313
export type TeamMember = {
1414
account: {
15+
creatorWalletAddress: string;
1516
name: string;
1617
email: string | null;
18+
image: string | null;
1719
};
18-
} & {
19-
deletedAt: Date | null;
20+
deletedAt: string | null;
2021
accountId: string;
2122
teamId: string;
22-
createdAt: Date;
23-
updatedAt: Date;
23+
createdAt: string;
24+
updatedAt: string;
2425
role: TeamAccountRole;
2526
};
2627

@@ -46,3 +47,26 @@ export async function getMembers(teamSlug: string) {
4647

4748
return undefined;
4849
}
50+
51+
export async function getMemberById(teamSlug: string, memberId: string) {
52+
const token = await getAuthToken();
53+
54+
if (!token) {
55+
return undefined;
56+
}
57+
58+
const res = await fetch(
59+
`${API_SERVER_URL}/v1/teams/${teamSlug}/members/${memberId}`,
60+
{
61+
headers: {
62+
Authorization: `Bearer ${token}`,
63+
},
64+
},
65+
);
66+
67+
if (res.ok) {
68+
return (await res.json())?.result as TeamMember;
69+
}
70+
71+
return undefined;
72+
}

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

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import "server-only";
2-
import { API_SERVER_URL } from "@/constants/env";
2+
import { API_SERVER_URL, THIRDWEB_API_SECRET } from "@/constants/env";
33
import type { TeamResponse } from "@thirdweb-dev/service-utils";
44
import { getAuthToken } from "../../app/api/lib/getAuthToken";
55

@@ -22,6 +22,20 @@ export async function getTeamBySlug(slug: string) {
2222
return null;
2323
}
2424

25+
export async function service_getTeamBySlug(slug: string) {
26+
const teamRes = await fetch(`${API_SERVER_URL}/v1/teams/${slug}`, {
27+
headers: {
28+
"x-service-api-key": THIRDWEB_API_SECRET,
29+
},
30+
});
31+
32+
if (teamRes.ok) {
33+
return (await teamRes.json())?.result as Team;
34+
}
35+
36+
return null;
37+
}
38+
2539
export function getTeamById(id: string) {
2640
return getTeamBySlug(id);
2741
}

apps/dashboard/src/@/components/blocks/DangerSettingCard.tsx

Lines changed: 17 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@ import {
66
DialogClose,
77
DialogContent,
88
DialogDescription,
9-
DialogFooter,
109
DialogHeader,
1110
DialogTitle,
1211
DialogTrigger,
@@ -17,13 +16,14 @@ export function DangerSettingCard(props: {
1716
title: string;
1817
className?: string;
1918
footerClassName?: string;
20-
description: string;
19+
description: React.ReactNode;
2120
buttonLabel: string;
2221
buttonOnClick: () => void;
22+
isDisabled?: boolean;
2323
isPending: boolean;
2424
confirmationDialog: {
2525
title: string;
26-
description: string;
26+
description: React.ReactNode;
2727
};
2828
children?: React.ReactNode;
2929
}) {
@@ -55,28 +55,30 @@ export function DangerSettingCard(props: {
5555
<Button
5656
variant="destructive"
5757
className="gap-2 bg-red-600 font-semibold text-white hover:bg-red-600/80"
58-
disabled={props.isPending}
58+
disabled={props.isDisabled || props.isPending}
5959
>
6060
{props.isPending && <Spinner className="size-3" />}
6161
{props.buttonLabel}
6262
</Button>
6363
</DialogTrigger>
6464

6565
<DialogContent
66-
className="z-[10001]"
66+
className="z-[10001] overflow-hidden p-0"
6767
dialogOverlayClassName="z-[10000]"
6868
>
69-
<DialogHeader className="pr-10">
70-
<DialogTitle className="leading-snug">
71-
{props.confirmationDialog.title}
72-
</DialogTitle>
69+
<div className="p-6">
70+
<DialogHeader className="pr-10">
71+
<DialogTitle className="leading-snug">
72+
{props.confirmationDialog.title}
73+
</DialogTitle>
7374

74-
<DialogDescription>
75-
{props.confirmationDialog.description}
76-
</DialogDescription>
77-
</DialogHeader>
75+
<DialogDescription>
76+
{props.confirmationDialog.description}
77+
</DialogDescription>
78+
</DialogHeader>
79+
</div>
7880

79-
<DialogFooter className="mt-4 gap-4 lg:gap-2">
81+
<div className="flex justify-end gap-4 border-t bg-card p-6 lg:gap-2">
8082
<DialogClose asChild>
8183
<Button variant="outline">Cancel</Button>
8284
</DialogClose>
@@ -90,7 +92,7 @@ export function DangerSettingCard(props: {
9092
{props.isPending && <Spinner className="size-3" />}
9193
{props.buttonLabel}
9294
</Button>
93-
</DialogFooter>
95+
</div>
9496
</DialogContent>
9597
</Dialog>
9698
</div>

0 commit comments

Comments
 (0)