-
Notifications
You must be signed in to change notification settings - Fork 0
/
with-oauth.tsx
162 lines (141 loc) · 5.5 KB
/
with-oauth.tsx
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
import React, { useEffect, useState } from "react";
import { OAuthMethod } from "@usecapsule/web-sdk";
import { useAtom } from "jotai";
import { Card, CardContent } from "../../demo-ui/components/card";
import SuccessMessage from "../../demo-ui/components/success-message";
import { OAuthOptions } from "../../demo-ui/constants";
import { disableNextAtom, disablePrevAtom, isLoadingAtom, isLoggedInAtom } from "../../demo-ui/state";
import { withMinimumLoadingTime } from "../../demo-ui/lib/utils";
import { capsuleClient } from "../capsule-client";
type AuthWithOAuthProps = {};
const AuthWithOAuth: React.FC<AuthWithOAuthProps> = () => {
const [internalStep, setInternalStep] = useState(0);
const [isLoggedIn, setIsLoggedIn] = useAtom(isLoggedInAtom);
const [, setIsLoading] = useAtom(isLoadingAtom);
const [, setDisableNext] = useAtom(disableNextAtom);
const [, setDisablePrev] = useAtom(disablePrevAtom);
const [hoveredOption, setHoveredOption] = useState<string | null>(null);
useEffect(() => {
checkLoginStatus();
}, []);
const checkLoginStatus = () => {
withMinimumLoadingTime(
async () => {
const loggedIn = await capsuleClient.isFullyLoggedIn();
setIsLoggedIn(loggedIn);
setDisableNext(!loggedIn);
if (loggedIn) {
setInternalStep(1);
}
},
250,
setIsLoading
);
};
useEffect(() => {
if (isLoggedIn && internalStep === 1) {
setDisableNext(false);
setDisablePrev(true);
}
}, [isLoggedIn, internalStep]);
const handleAuthentication = async (method: OAuthMethod) => {
setIsLoading(true);
if (method === OAuthMethod.FARCASTER) {
await handleFarcasterAuth();
} else {
await handleRegularOAuth(method);
}
setIsLoggedIn(true);
setInternalStep(1);
setIsLoading(false);
};
const handleFarcasterAuth = async () => {
const connectUri = await capsuleClient.getFarcasterConnectURL();
window.open(connectUri, "farcasterConnectPopup", "popup=true");
const { userExists, username } = await capsuleClient.waitForFarcasterStatus();
const authUrl = userExists
? await capsuleClient.initiateUserLogin(username, false, "farcaster")
: await capsuleClient.getSetUpBiometricsURL(false, "farcaster");
const popupWindow = window.open(authUrl, userExists ? "loginPopup" : "signUpPopup", "popup=true");
await (userExists
? capsuleClient.waitForLoginAndSetup(popupWindow!)
: capsuleClient.waitForPasskeyAndCreateWallet());
};
const handleRegularOAuth = async (method: OAuthMethod) => {
const oAuthURL = await capsuleClient.getOAuthURL(method);
window.open(oAuthURL, "oAuthPopup", "popup=true");
const { email, userExists } = await capsuleClient.waitForOAuth();
const authUrl = userExists
? await capsuleClient.initiateUserLogin(email!, false, "email")
: await capsuleClient.getSetUpBiometricsURL(false, "email");
const popupWindow = window.open(authUrl, userExists ? "loginPopup" : "signUpPopup", "popup=true");
const result = await (userExists
? capsuleClient.waitForLoginAndSetup(popupWindow!)
: capsuleClient.waitForPasskeyAndCreateWallet());
if ("needsWallet" in result && result.needsWallet) {
await capsuleClient.createWallet();
}
if ("recoverySecret" in result) {
const recoverySecret = result.recoverySecret;
}
};
return (
<div>
{internalStep === 0 ? (
<div className="grid grid-cols-1 sm:grid-cols-2 md:grid-cols-3 lg:grid-cols-4 gap-4 w-full">
{Object.entries(OAuthOptions).map(([key, option], index) => (
<Card
key={option.label}
className={`
relative overflow-hidden cursor-pointer
transition-smooth animate-slide-in-from-bottom fill-both
hover:shadow-lg hover:scale-[1.02] hover:bg-accent/5
border-border hover:border-accent
${`delay-${(index % 4) + 1}`}
`}
onMouseEnter={() => setHoveredOption(option.label)}
onMouseLeave={() => setHoveredOption(null)}
onClick={() => handleAuthentication(key as OAuthMethod)}>
<CardContent className="p-4 h-24 flex flex-col items-center justify-center transition-smooth relative group">
<option.icon
className={`
h-6 w-6 transition-smooth
text-muted-foreground
group-hover:text-accent
`}
/>
<h3
className={`
mt-2 text-sm font-medium text-center
text-foreground
group-hover:text-accent
transition-smooth
`}>
{option.label}
</h3>
{hoveredOption === option.label && (
<div
className="
absolute inset-0
bg-primary text-primary-foreground
flex items-center justify-center
text-sm font-medium
animate-fade-in fill-both
backdrop-blur-sm
">
Click to connect
</div>
)}
</CardContent>
</Card>
))}
</div>
) : (
<div className="animate-fade-in fill-both delay-1">
<SuccessMessage message="You have successfully authenticated with OAuth. Click next below to continue to selecting a signer." />
</div>
)}
</div>
);
};
export default AuthWithOAuth;