Skip to content

Commit 13663ca

Browse files
committed
Merge remote-tracking branch 'origin/main' into ph/engineWallets
2 parents f1ea5b3 + e29d80a commit 13663ca

File tree

17 files changed

+253
-72
lines changed

17 files changed

+253
-72
lines changed

.vscode/settings.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,5 +21,8 @@
2121
},
2222
"[markdown]": {
2323
"editor.defaultFormatter": "esbenp.prettier-vscode"
24+
},
25+
"[javascript]": {
26+
"editor.defaultFormatter": "biomejs.biome"
2427
}
2528
}

apps/dashboard/next-sitemap.config.js

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
*
44
*/
55
async function fetchChainsFromApi() {
6-
const res = await fetch(`https://api.thirdweb.com/v1/chains`, {
6+
const res = await fetch("https://api.thirdweb.com/v1/chains", {
77
headers: {
88
"Content-Type": "application/json",
99
},
@@ -55,7 +55,9 @@ module.exports = {
5555
],
5656
},
5757
exclude: ["/chain/validate"],
58-
transform: async (config, path) => {
58+
transform: async (config, _path) => {
59+
let path = _path;
60+
5961
// ignore og image paths
6062
if (path.includes("_og")) {
6163
return null;

apps/dashboard/next.config.js

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,11 @@ const securityHeaders = [
4040
const redirects = require("./redirects");
4141

4242
// add framer paths here
43-
const FRAMER_PATHS = ["/connect/sign-in", "/contracts/modular-contracts"];
43+
const FRAMER_PATHS = [
44+
"/connect/sign-in",
45+
"/contracts/modular-contracts",
46+
"/unlimited-wallets",
47+
];
4448

4549
/**
4650
* @returns {import('next').RemotePattern[]}

apps/dashboard/src/@3rdweb-sdk/react/hooks/useLoggedInUser.ts

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -56,9 +56,7 @@ export function useLoggedInUser(): {
5656
retry: false,
5757
queryFn: async () => {
5858
const searchParams = new URLSearchParams();
59-
if (pathname) {
60-
searchParams.set("pathname", pathname);
61-
}
59+
6260
if (connectedAddress) {
6361
searchParams.set("address", connectedAddress);
6462
}
@@ -76,10 +74,18 @@ export function useLoggedInUser(): {
7674
// legit use-case for now
7775
// eslint-disable-next-line no-restricted-syntax
7876
useEffect(() => {
79-
if (query.data?.redirectTo) {
80-
router.replace(query.data.redirectTo);
77+
if (query.data?.isLoggedIn === false) {
78+
// not using useSearchParams hook here to avoid adding Suspense boundaries everywhere this hook is being used
79+
const currentHref = new URL(window.location.href);
80+
const currentPathname = currentHref.pathname;
81+
const currentSearchParams = currentHref.searchParams.toString();
82+
router.replace(
83+
buildLoginPath(
84+
`${currentPathname}${currentSearchParams ? `?${currentSearchParams}` : ""}`,
85+
),
86+
);
8187
}
82-
}, [query.data?.redirectTo, router]);
88+
}, [query.data?.isLoggedIn, router]);
8389

8490
// if we are "disconnected" we are not logged in
8591
if (connectionStatus === "disconnected") {
@@ -135,3 +141,7 @@ export function useLoggedInUser(): {
135141
: null,
136142
};
137143
}
144+
145+
function buildLoginPath(pathname: string | undefined): string {
146+
return `/login${pathname ? `?next=${encodeURIComponent(pathname)}` : ""}`;
147+
}

apps/dashboard/src/app/api/auth/ensure-login/route.ts

Lines changed: 0 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -4,20 +4,13 @@ import { cookies } from "next/headers";
44
import { type NextRequest, NextResponse } from "next/server";
55
import { getAddress } from "thirdweb/utils";
66

7-
export type EnsureLoginPayload = {
8-
pathname: string;
9-
address?: string;
10-
};
11-
127
export type EnsureLoginResponse = {
138
isLoggedIn: boolean;
149
jwt?: string;
15-
redirectTo?: string;
1610
};
1711

1812
export const GET = async (req: NextRequest) => {
1913
const address = req.nextUrl.searchParams.get("address");
20-
const pathname = req.nextUrl.searchParams.get("pathname");
2114

2215
const cookieStore = cookies();
2316
// if we are "disconnected" we are not logged in, clear the cookie and redirect to login
@@ -34,7 +27,6 @@ export const GET = async (req: NextRequest) => {
3427
cookieStore.delete(COOKIE_ACTIVE_ACCOUNT);
3528
return NextResponse.json({
3629
isLoggedIn: false,
37-
redirectTo: buildLoginPath(pathname),
3830
});
3931
}
4032

@@ -49,7 +41,6 @@ export const GET = async (req: NextRequest) => {
4941
cookieStore.delete(COOKIE_ACTIVE_ACCOUNT);
5042
return NextResponse.json({
5143
isLoggedIn: false,
52-
redirectTo: buildLoginPath(pathname),
5344
});
5445
}
5546

@@ -65,7 +56,6 @@ export const GET = async (req: NextRequest) => {
6556
cookieStore.delete(authCookieName);
6657
return NextResponse.json({
6758
isLoggedIn: false,
68-
redirectTo: buildLoginPath(pathname),
6959
});
7060
}
7161

@@ -87,7 +77,3 @@ export const GET = async (req: NextRequest) => {
8777
// if everything is good simply return true
8878
return NextResponse.json({ isLoggedIn: true, jwt: token });
8979
};
90-
91-
function buildLoginPath(pathname?: string | null): string {
92-
return `/login${pathname ? `?next=${encodeURIComponent(pathname)}` : ""}`;
93-
}

apps/dashboard/src/components/settings/Account/Billing/ApplyCouponCard.stories.tsx

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,14 @@ function statusStub(status: number) {
5454
function Story() {
5555
return (
5656
<div className="container flex max-w-[1100px] flex-col gap-10 py-10">
57+
<BadgeContainer label="Prefill code - XYZ, Success - 200">
58+
<ApplyCouponCardUI
59+
submit={statusStub(200)}
60+
onCouponApplied={undefined}
61+
prefillPromoCode="XYZ"
62+
/>
63+
</BadgeContainer>
64+
5765
<BadgeContainer label="Success - 200">
5866
<ApplyCouponCardUI
5967
submit={statusStub(200)}

apps/dashboard/src/components/settings/Account/Billing/CouponCard.tsx

Lines changed: 47 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,8 @@ import { zodResolver } from "@hookform/resolvers/zod";
1616
import { useMutation, useQuery } from "@tanstack/react-query";
1717
import { format, fromUnixTime } from "date-fns";
1818
import { TagIcon } from "lucide-react";
19-
import { useState } from "react";
19+
import { useSearchParams } from "next/navigation";
20+
import { Suspense, useEffect, useRef, useState } from "react";
2021
import { useForm } from "react-hook-form";
2122
import { toast } from "sonner";
2223
import { z } from "zod";
@@ -37,9 +38,13 @@ function ApplyCouponCard(props: {
3738
teamId: string | undefined;
3839
onCouponApplied: (data: ActiveCouponResponse) => void;
3940
}) {
41+
const searchParams = useSearchParams();
42+
const couponCode = searchParams?.get("coupon");
4043
return (
4144
<ApplyCouponCardUI
4245
onCouponApplied={props.onCouponApplied}
46+
prefillPromoCode={couponCode || undefined}
47+
scrollIntoView={!!couponCode}
4348
submit={async (promoCode: string) => {
4449
const res = await fetch("/api/server-proxy/api/v1/coupons/redeem", {
4550
method: "POST",
@@ -79,14 +84,30 @@ export function ApplyCouponCardUI(props: {
7984
data: null | ActiveCouponResponse;
8085
}>;
8186
onCouponApplied: ((data: ActiveCouponResponse) => void) | undefined;
87+
prefillPromoCode?: string;
88+
scrollIntoView?: boolean;
8289
}) {
90+
const containerRef = useRef<HTMLFormElement | null>(null);
8391
const form = useForm<z.infer<typeof couponFormSchema>>({
8492
resolver: zodResolver(couponFormSchema),
8593
defaultValues: {
86-
promoCode: "",
94+
promoCode: props.prefillPromoCode,
8795
},
8896
});
8997

98+
const scrolled = useRef(false);
99+
// eslint-disable-next-line no-restricted-syntax
100+
useEffect(() => {
101+
if (props.scrollIntoView && !scrolled.current) {
102+
const el = containerRef.current;
103+
if (el) {
104+
el.scrollIntoView({ behavior: "smooth", block: "start" });
105+
el.querySelector("input")?.focus();
106+
scrolled.current = true;
107+
}
108+
}
109+
}, [props.scrollIntoView]);
110+
90111
const applyCoupon = useMutation({
91112
mutationFn: (promoCode: string) => props.submit(promoCode),
92113
});
@@ -133,7 +154,7 @@ export function ApplyCouponCardUI(props: {
133154

134155
return (
135156
<Form {...form}>
136-
<form onSubmit={form.handleSubmit(onSubmit)}>
157+
<form onSubmit={form.handleSubmit(onSubmit)} ref={containerRef}>
137158
<SettingsCard
138159
header={{
139160
title: "Apply Coupon",
@@ -272,11 +293,7 @@ export function CouponSection(props: { teamId: string | undefined }) {
272293
});
273294

274295
if (activeCoupon.isPending) {
275-
return (
276-
<div className="flex h-[300px] items-center justify-center rounded-lg border border-border bg-muted/50">
277-
<Spinner className="size-6" />
278-
</div>
279-
);
296+
return <LoadingCouponSection />;
280297
}
281298

282299
const couponData = optimisticCouponData
@@ -296,17 +313,27 @@ export function CouponSection(props: { teamId: string | undefined }) {
296313
}
297314

298315
return (
299-
<ApplyCouponCard
300-
teamId={props.teamId}
301-
onCouponApplied={(coupon) => {
302-
setOptimisticCouponData({
303-
type: "added",
304-
data: coupon,
305-
});
306-
activeCoupon.refetch().then(() => {
307-
setOptimisticCouponData(undefined);
308-
});
309-
}}
310-
/>
316+
<Suspense fallback={<LoadingCouponSection />}>
317+
<ApplyCouponCard
318+
teamId={props.teamId}
319+
onCouponApplied={(coupon) => {
320+
setOptimisticCouponData({
321+
type: "added",
322+
data: coupon,
323+
});
324+
activeCoupon.refetch().then(() => {
325+
setOptimisticCouponData(undefined);
326+
});
327+
}}
328+
/>
329+
</Suspense>
330+
);
331+
}
332+
333+
function LoadingCouponSection() {
334+
return (
335+
<div className="flex h-[300px] items-center justify-center rounded-lg border border-border bg-muted/50">
336+
<Spinner className="size-6" />
337+
</div>
311338
);
312339
}

apps/dashboard/src/components/smart-wallets/SponsorshipPolicies/index.tsx

Lines changed: 16 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -272,14 +272,14 @@ export function AccountAbstractionSettingsPage(
272272
>
273273
<FormControl>
274274
<Flex flexDir="column" gap={4}>
275-
<div className="flex flex-row items-center justify-between">
275+
<div className="flex flex-row items-center justify-between gap-6 lg:gap-12">
276276
<div>
277277
<FormLabel pointerEvents="none">Global spend limits</FormLabel>
278278
<Text>
279-
Maximum gas cost (in USD) that you want to sponsor. This
280-
applies for the duration of the billing period (monthly). Once
281-
this limit is reached, your users will have to fund their own
282-
gas costs.
279+
Maximum gas cost (in USD) that you want to sponsor. <br />{" "}
280+
This applies for the duration of the billing period (monthly).
281+
Once this limit is reached, your users will have to fund their
282+
own gas costs.
283283
</Text>
284284
</div>
285285

@@ -308,7 +308,7 @@ export function AccountAbstractionSettingsPage(
308308
}
309309
>
310310
<FormLabel>Spend limit</FormLabel>
311-
<div className="flex flex-row items-center">
311+
<div className="flex flex-row items-center gap-2">
312312
<Input
313313
w="xs"
314314
placeholder="Enter an amount"
@@ -343,14 +343,14 @@ export function AccountAbstractionSettingsPage(
343343
}
344344
>
345345
<Flex flexDir="column" gap={4}>
346-
<div className="flex flex-row items-center justify-between">
346+
<div className="flex flex-row items-center justify-between gap-6 lg:gap-12">
347347
<div>
348348
<FormLabel pointerEvents="none">
349349
Restrict to specific chains
350350
</FormLabel>
351351
<Text>
352-
Only sponsor transactions on the specified chains. By default,
353-
transactions can be sponsored on any of the{" "}
352+
Only sponsor transactions on the specified chains. <br /> By
353+
default, transactions can be sponsored on any of the{" "}
354354
<TrackedLink
355355
color="primary.500"
356356
isExternal
@@ -399,7 +399,7 @@ export function AccountAbstractionSettingsPage(
399399
}
400400
>
401401
<Flex flexDir="column" gap={4}>
402-
<div className="flex flex-row items-center justify-between">
402+
<div className="flex flex-row items-center justify-between gap-6 lg:gap-12">
403403
<div>
404404
<FormLabel pointerEvents="none">
405405
Restrict to specific contract addresses
@@ -442,7 +442,7 @@ export function AccountAbstractionSettingsPage(
442442
<Divider />
443443
<FormControl>
444444
<Flex flexDir="column" gap={4}>
445-
<div className="flex flex-row items-center justify-between">
445+
<div className="flex flex-row items-center justify-between gap-6 lg:gap-12">
446446
<div>
447447
<FormLabel pointerEvents="none">
448448
Allowlisted/Blocklisted accounts
@@ -519,13 +519,14 @@ export function AccountAbstractionSettingsPage(
519519
<Divider />
520520
<FormControl>
521521
<Flex flexDir="column" gap={4}>
522-
<div className="flex flex-row items-center justify-between">
522+
<div className="flex flex-row items-center justify-between gap-6 lg:gap-12">
523523
<div>
524524
<FormLabel pointerEvents="none">Server verifier</FormLabel>
525525
<Text>
526526
Specify your own endpoint that will verify each transaction
527-
and decide whether it should be sponsored or not. This gives
528-
you fine grained control and lets you build your own rules.{" "}
527+
and decide whether it should be sponsored or not. <br /> This
528+
gives you fine grained control and lets you build your own
529+
rules.{" "}
529530
<TrackedLink
530531
category={trackingCategory}
531532
href="https://portal.thirdweb.com/wallets/smart-wallet/sponsorship-rules#setting-up-a-server-verifier"
@@ -634,7 +635,7 @@ export function AccountAbstractionSettingsPage(
634635
}
635636
>
636637
<Flex flexDir="column" gap={4}>
637-
<div className="flex flex-row items-center justify-between">
638+
<div className="flex flex-row items-center justify-between gap-6 lg:gap-12">
638639
<div>
639640
<FormLabel pointerEvents="none">Admin accounts</FormLabel>
640641
<Text>

apps/dashboard/src/middleware.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,11 +32,13 @@ export async function middleware(request: NextRequest) {
3232
// check if the user is logged in (has a valid auth cookie)
3333

3434
if (!authCookie) {
35+
const searchParamsString = request.nextUrl.searchParams.toString();
36+
3537
// if not logged in, rewrite to login page
3638
return redirect(
3739
request,
3840
"/login",
39-
`next=${encodeURIComponent(pathname)}`,
41+
`next=${encodeURIComponent(`${pathname}${searchParamsString ? `?${searchParamsString}` : ""}`)}`,
4042
false,
4143
);
4244
}

packages/thirdweb/CHANGELOG.md

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,17 @@
11
# thirdweb
22

3+
## 5.61.4
4+
5+
### Patch Changes
6+
7+
- [#4969](https://github.com/thirdweb-dev/js/pull/4969) [`3446b4c`](https://github.com/thirdweb-dev/js/commit/3446b4cabf0a8b877c344d810f97fd571753df2e) Thanks [@MananTank](https://github.com/MananTank)! - Remove extra text shown in Error Message in Pay UI
8+
9+
## 5.61.3
10+
11+
### Patch Changes
12+
13+
- [#4965](https://github.com/thirdweb-dev/js/pull/4965) [`24981a7`](https://github.com/thirdweb-dev/js/commit/24981a7f60c2a45976c748826339822d81154ce3) Thanks [@joaquim-verges](https://github.com/joaquim-verges)! - Respect raw accountSalt passed as hex
14+
315
## 5.61.2
416

517
### Patch Changes

0 commit comments

Comments
 (0)