Skip to content

Commit e6827d1

Browse files
authored
feat: confirm paper wallet email on auth success (#1813)
feat: confirm paper wallet email fixes PROD-314
1 parent 7d8028c commit e6827d1

File tree

4 files changed

+91
-16
lines changed

4 files changed

+91
-16
lines changed

@3rdweb-sdk/react/hooks/useApi.ts

+37
Original file line numberDiff line numberDiff line change
@@ -355,6 +355,43 @@ export function useConfirmEmail() {
355355
);
356356
}
357357

358+
export function useConfirmPaperEmail() {
359+
const { user } = useLoggedInUser();
360+
const queryClient = useQueryClient();
361+
362+
return useMutationWithInvalidate(
363+
async ({ paperJwt }: { paperJwt: string }) => {
364+
invariant(user?.address, "walletAddress is required");
365+
366+
const res = await fetch(
367+
`${THIRDWEB_API_HOST}/v1/account/confirmPaperEmail`,
368+
{
369+
method: "PUT",
370+
credentials: "include",
371+
headers: {
372+
"Content-Type": "application/json",
373+
},
374+
body: JSON.stringify({ paperJwt }),
375+
},
376+
);
377+
const json = await res.json();
378+
379+
if (json.error) {
380+
throw new Error(json.message);
381+
}
382+
383+
return json.data;
384+
},
385+
{
386+
onSuccess: () => {
387+
return queryClient.invalidateQueries(
388+
accountKeys.me(user?.address as string),
389+
);
390+
},
391+
},
392+
);
393+
}
394+
358395
export function useResendEmailConfirmation() {
359396
const { user } = useLoggedInUser();
360397
const queryClient = useQueryClient();

components/app-layouts/providers.tsx

+8-1
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,10 @@ import {
1818
walletConnect,
1919
zerionWallet,
2020
} from "@thirdweb-dev/react";
21-
import { GLOBAL_AUTH_TOKEN_KEY } from "constants/app";
21+
import {
22+
GLOBAL_AUTH_TOKEN_KEY,
23+
GLOBAL_PAPER_AUTH_TOKEN_KEY,
24+
} from "constants/app";
2225
import {
2326
DASHBOARD_THIRDWEB_CLIENT_ID,
2427
DASHBOARD_THIRDWEB_SECRET_KEY,
@@ -53,6 +56,10 @@ const personalWallets = [
5356
advancedOptions: {
5457
recoveryShareManagement: "AWS_MANAGED",
5558
},
59+
onAuthSuccess: ({ storedToken }) => {
60+
// expose paper auth token for onboarding screens to pick up and clear up
61+
(window as any)[GLOBAL_PAPER_AUTH_TOKEN_KEY] = storedToken.cookieString;
62+
},
5663
}),
5764
localWallet(),
5865
];

components/onboarding/index.tsx

+45-15
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,8 @@
1-
import { Account, useAccount } from "@3rdweb-sdk/react/hooks/useApi";
1+
import {
2+
Account,
3+
useAccount,
4+
useConfirmPaperEmail,
5+
} from "@3rdweb-sdk/react/hooks/useApi";
26
import { useEffect, useState } from "react";
37
import { OnboardingModal } from "./Modal";
48
import { OnboardingGeneral } from "./General";
@@ -7,12 +11,23 @@ import { useRouter } from "next/router";
711
import { OnboardingBilling } from "./Billing";
812
import { useTrack } from "hooks/analytics/useTrack";
913
import { useLoggedInUser } from "@3rdweb-sdk/react/hooks/useLoggedInUser";
14+
import { useWallet } from "@thirdweb-dev/react";
15+
import { GLOBAL_PAPER_AUTH_TOKEN_KEY } from "constants/app";
16+
17+
const skipBilling = (account: Account) => {
18+
return (
19+
["validPayment", "paymentVerification"].includes(account.status) ||
20+
account.onboardSkipped
21+
);
22+
};
1023

1124
export const Onboarding: React.FC = () => {
1225
const meQuery = useAccount();
1326
const router = useRouter();
1427
const { isLoggedIn } = useLoggedInUser();
1528
const trackEvent = useTrack();
29+
const wallet = useWallet();
30+
const paperConfirmMutation = useConfirmPaperEmail();
1631

1732
const [state, setState] = useState<
1833
"onboarding" | "confirming" | "billing" | "skipped" | undefined
@@ -45,11 +60,7 @@ export const Onboarding: React.FC = () => {
4560
},
4661
});
4762
} else if (state === "confirming") {
48-
const newState =
49-
["validPayment", "paymentVerification"].includes(account.status) ||
50-
account.onboardSkipped
51-
? "skipped"
52-
: "billing";
63+
const newState = skipBilling(account) ? "skipped" : "billing";
5364
setState(newState);
5465

5566
trackEvent({
@@ -72,28 +83,47 @@ export const Onboarding: React.FC = () => {
7283
}
7384
};
7485

86+
const handlePaperWallet = () => {
87+
const paperJwt = (window as any)[GLOBAL_PAPER_AUTH_TOKEN_KEY];
88+
89+
if (paperJwt) {
90+
paperConfirmMutation.mutate(
91+
{ paperJwt },
92+
{
93+
onSuccess: (data) => {
94+
if (!skipBilling(data as Account)) {
95+
setState("billing");
96+
}
97+
(window as any)[GLOBAL_PAPER_AUTH_TOKEN_KEY] = undefined;
98+
},
99+
},
100+
);
101+
}
102+
};
103+
75104
useEffect(() => {
76-
if (!isLoggedIn || !account || state) {
105+
if (!isLoggedIn || !account || state || !wallet) {
77106
return;
78107
}
79-
80108
// user hasn't confirmed email
81109
if (!account.emailConfirmedAt && !account.unconfirmedEmail) {
82-
setState("onboarding");
110+
// if its a paper email wallet, try to confirm it
111+
if (wallet.walletId === "paper") {
112+
handlePaperWallet();
113+
} else {
114+
setState("onboarding");
115+
}
83116
}
84117
// user has changed email and needs to confirm
85118
else if (account.unconfirmedEmail) {
86119
setState("confirming");
87120
}
88121
// user hasn't skipped onboarding, has valid email and no valid payment yet
89-
else if (
90-
account.email &&
91-
!account.onboardSkipped &&
92-
!["validPayment", "paymentVerification"].includes(account.status)
93-
) {
122+
else if (!skipBilling(account)) {
94123
setState("billing");
95124
}
96-
}, [isLoggedIn, account, router, state]);
125+
// eslint-disable-next-line react-hooks/exhaustive-deps
126+
}, [isLoggedIn, account, router, state, wallet]);
97127

98128
if (!isLoggedIn || !account || state === "skipped" || !state) {
99129
return null;

constants/app.ts

+1
Original file line numberDiff line numberDiff line change
@@ -1 +1,2 @@
11
export const GLOBAL_AUTH_TOKEN_KEY = "TW_AUTH_TOKEN";
2+
export const GLOBAL_PAPER_AUTH_TOKEN_KEY = "TW_PAPER_AUTH_TOKEN";

0 commit comments

Comments
 (0)