One Calendar is a privacy-first calendar web app built with Next.js. It has modern security features, including e2ee, password-protected sharing, and self-destructing share links ๐Ÿ“… calendar.xyehr.cn
5
fork

Configure Feed

Select the types of activity you want to include in your feed.

fix(auth): fix login problem

authored by

Evan Huang and committed by
GitHub
79abe386 2947ec69

+42 -98
+42 -98
components/auth/login-form.tsx
··· 2 2 3 3 import { Button } from "@/components/ui/button"; 4 4 import { cn } from "@/lib/utils"; 5 - import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"; 5 + import { 6 + Card, 7 + CardContent, 8 + CardHeader, 9 + CardTitle, 10 + } from "@/components/ui/card"; 6 11 import { Input } from "@/components/ui/input"; 7 12 import { Label } from "@/components/ui/label"; 8 13 import { useSignIn } from "@clerk/nextjs"; ··· 14 19 className, 15 20 ...props 16 21 }: React.ComponentPropsWithoutRef<"div">) { 17 - const { isLoaded, signIn, setActive } = useSignIn(); 22 + const { signIn, setActive } = useSignIn(); 18 23 const [email, setEmail] = useState(""); 19 24 const [password, setPassword] = useState(""); 20 25 const [isLoading, setIsLoading] = useState(false); 21 26 const [error, setError] = useState(""); 22 27 const [isCaptchaCompleted, setIsCaptchaCompleted] = useState( 23 - process.env.NEXT_PUBLIC_TURNSTILE_SITE_KEY ? false : true, 28 + process.env.NEXT_PUBLIC_TURNSTILE_SITE_KEY ? false : true 24 29 ); 25 30 const turnstileRef = useRef<any>(null); 26 31 const router = useRouter(); ··· 41 46 setError(""); 42 47 } else { 43 48 setIsCaptchaCompleted(false); 44 - setError( 45 - `CAPTCHA verification failed: ${data.details?.join(", ") || "Unknown error"}`, 46 - ); 49 + setError(`CAPTCHA verification failed: ${data.details?.join(", ") || "Unknown error"}`); 47 50 if (turnstileRef.current) { 48 51 turnstileRef.current.reset(); 49 52 } ··· 70 73 setError(""); 71 74 72 75 try { 73 - if (!isLoaded || !signIn) { 74 - setError("Auth service is still loading. Please try again in a moment."); 75 - return; 76 - } 77 - 78 76 const result = await signIn.create({ 79 77 identifier: email, 80 78 password, ··· 85 83 router.push("/app"); 86 84 } 87 85 } catch (err: any) { 88 - setError( 89 - err.errors?.[0]?.longMessage || "Login failed. Please try again.", 90 - ); 86 + setError(err.errors?.[0]?.longMessage || "Login failed. Please try again."); 91 87 if (siteKey) { 92 88 setIsCaptchaCompleted(false); 93 89 if (turnstileRef.current) { ··· 99 95 } 100 96 }; 101 97 102 - const handleOAuthLogin = ( 103 - strategy: "oauth_google" | "oauth_microsoft" | "oauth_github", 104 - ) => { 98 + const handleOAuthLogin = (strategy: "oauth_google" | "oauth_microsoft" | "oauth_github") => { 105 99 const siteKey = process.env.NEXT_PUBLIC_TURNSTILE_SITE_KEY; 106 100 if (siteKey && !isCaptchaCompleted) { 107 101 setError("Please complete the CAPTCHA verification."); 108 102 return; 109 103 } 110 - 111 - if (!isLoaded || !signIn) { 112 - setError("Auth service is still loading. Please try again in a moment."); 113 - return; 114 - } 115 - 116 - const redirect = 117 - signIn.authenticateWithRedirect ?? 118 - (signIn as unknown as { authWithRedirect?: typeof signIn.authenticateWithRedirect }) 119 - .authWithRedirect; 120 - 121 - if (!redirect) { 122 - setError("OAuth is unavailable right now. Please refresh and try again."); 123 - return; 124 - } 125 - 126 - redirect.call(signIn, { 104 + signIn.authenticateWithRedirect({ 127 105 strategy, 128 106 redirectUrl: "/sign-in/sso-callback", 129 107 redirectUrlComplete: "/app", ··· 148 126 type="button" 149 127 onClick={() => handleOAuthLogin("oauth_microsoft")} 150 128 > 151 - <svg 152 - xmlns="http://www.w3.org/2000/svg" 153 - viewBox="0 0 23 23" 154 - width="20" 155 - height="20" 156 - > 157 - <path fill="#f25022" d="M1 1h10v10H1z" /> 158 - <path fill="#00a4ef" d="M12 1h10v10H12z" /> 159 - <path fill="#7fba00" d="M1 12h10v10H1z" /> 160 - <path fill="#ffb900" d="M12 12h10v10H12z" /> 129 + <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 23 23" width="20" height="20"> 130 + <path fill="#f25022" d="M1 1h10v10H1z"/> 131 + <path fill="#00a4ef" d="M12 1h10v10H12z"/> 132 + <path fill="#7fba00" d="M1 12h10v10H1z"/> 133 + <path fill="#ffb900" d="M12 12h10v10H12z"/> 161 134 </svg> 162 135 <span className="ml-2">Login with Microsoft</span> 163 136 </Button> ··· 167 140 type="button" 168 141 onClick={() => handleOAuthLogin("oauth_google")} 169 142 > 170 - <svg 171 - xmlns="http://www.w3.org/2000/svg" 172 - height="24" 173 - viewBox="0 0 24 24" 174 - width="24" 175 - > 176 - <path 177 - d="M22.56 12.25c0-.78-.07-1.53-.2-2.25H12v4.26h5.92c-.26 1.37-1.04 2.53-2.21 3.31v2.77h3.57c2.08-1.92 3.28-4.74 3.28-8.09z" 178 - fill="#4285F4" 179 - /> 180 - <path 181 - d="M12 23c2.97 0 5.46-.98 7.28-2.66l-3.57-2.77c-.98.66-2.23 1.06-3.71 1.06-2.86 0-5.29-1.93-6.16-4.53H2.18v2.84C3.99 20.53 7.7 23 12 23z" 182 - fill="#34A853" 183 - /> 184 - <path 185 - d="M5.84 14.09c-.22-.66-.35-1.36-.35-2.09s.13-1.43.35-2.09V7.07H2.18C1.43 8.55 1 10.22 1 12s.43 3.45 1.18 4.93l2.85-2.22.81-.62z" 186 - fill="#FBBC05" 187 - /> 188 - <path 189 - d="M12 5.38c1.62 0 3.06.56 4.21 1.64l3.15-3.15C17.45 2.09 14.97 1 12 1 7.7 1 3.99 3.47 2.18 7.07l3.66 2.84c.87-2.6 3.3-4.53 6.16-4.53z" 190 - fill="#EA4335" 191 - /> 192 - <path d="M1 1h22v22H1z" fill="none" /> 143 + <svg xmlns="http://www.w3.org/2000/svg" height="24" viewBox="0 0 24 24" width="24"> 144 + <path d="M22.56 12.25c0-.78-.07-1.53-.2-2.25H12v4.26h5.92c-.26 1.37-1.04 2.53-2.21 3.31v2.77h3.57c2.08-1.92 3.28-4.74 3.28-8.09z" fill="#4285F4"/> 145 + <path d="M12 23c2.97 0 5.46-.98 7.28-2.66l-3.57-2.77c-.98.66-2.23 1.06-3.71 1.06-2.86 0-5.29-1.93-6.16-4.53H2.18v2.84C3.99 20.53 7.7 23 12 23z" fill="#34A853"/> 146 + <path d="M5.84 14.09c-.22-.66-.35-1.36-.35-2.09s.13-1.43.35-2.09V7.07H2.18C1.43 8.55 1 10.22 1 12s.43 3.45 1.18 4.93l2.85-2.22.81-.62z" fill="#FBBC05"/> 147 + <path d="M12 5.38c1.62 0 3.06.56 4.21 1.64l3.15-3.15C17.45 2.09 14.97 1 12 1 7.7 1 3.99 3.47 2.18 7.07l3.66 2.84c.87-2.6 3.3-4.53 6.16-4.53z" fill="#EA4335"/> 148 + <path d="M1 1h22v22H1z" fill="none"/> 193 149 </svg> 194 150 <span className="ml-2">Login with Google</span> 195 151 </Button> ··· 199 155 type="button" 200 156 onClick={() => handleOAuthLogin("oauth_github")} 201 157 > 202 - <svg 203 - xmlns="http://www.w3.org/2000/svg" 204 - viewBox="0 0 24 24" 205 - width="20" 206 - height="20" 207 - > 158 + <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="20" height="20"> 208 159 <path 209 160 d="M12 .297c-6.63 0-12 5.373-12 12 0 5.303 3.438 9.8 8.205 11.385.6.113.82-.258.82-.577 0-.285-.01-1.04-.015-2.04-3.338.724-4.042-1.61-4.042-1.61C4.422 18.07 3.633 17.7 3.633 17.7c-1.087-.744.084-.729.084-.729 1.205.084 1.838 1.236 1.838 1.236 1.07 1.835 2.809 1.305 3.495.998.108-.776.417-1.305.76-1.605-2.665-.3-5.466-1.332-5.466-5.93 0-1.31.465-2.38 1.235-3.22-.135-.303-.54-1.523.105-3.176 0 0 1.005-.322 3.3 1.23.96-.267 1.98-.399 3-.405 1.02.006 2.04.138 3 .405 2.28-1.552 3.285-1.23 3.285-1.23.645 1.653.24 2.873.12 3.176.765.84 1.23 1.91 1.23 3.22 0 4.61-2.805 5.625-5.475 5.92.42.36.81 1.096.81 2.22 0 1.606-.015 2.896-.015 3.286 0 .315.21.69.825.57C20.565 22.092 24 17.592 24 12.297c0-6.627-5.373-12-12-12" 210 161 fill="currentColor" ··· 249 200 /> 250 201 </div> 251 202 {siteKey && ( 252 - <div className="turnstile-container"> 253 - <Turnstile 254 - ref={turnstileRef} 255 - siteKey={siteKey} 256 - onSuccess={handleTurnstileSuccess} 257 - onError={() => { 258 - console.error("Turnstile widget error"); 259 - setIsCaptchaCompleted(false); 260 - setError( 261 - "CAPTCHA initialization failed. Please try again.", 262 - ); 263 - }} 264 - options={{ 265 - theme: "auto", 266 - action: "login", 267 - cData: "login-page", 268 - refreshExpired: "auto", 269 - size: "flexible", 270 - }} 271 - /> 272 - </div> 203 + <div className="turnstile-container"> 204 + <Turnstile 205 + ref={turnstileRef} 206 + siteKey={siteKey} 207 + onSuccess={handleTurnstileSuccess} 208 + onError={() => { 209 + console.error("Turnstile widget error"); 210 + setIsCaptchaCompleted(false); 211 + setError("CAPTCHA initialization failed. Please try again."); 212 + }} 213 + options={{ theme: "auto", action: "login", cData: "login-page", refreshExpired: "auto", size: "flexible" }} 214 + /> 215 + </div> 216 + )} 217 + {error && ( 218 + <div className="text-sm text-red-500">{error}</div> 273 219 )} 274 - {error && <div className="text-sm text-red-500">{error}</div>} 275 220 <Button 276 221 type="submit" 277 222 className="w-full bg-[#0066ff] hover:bg-[#0047cc] text-white" ··· 291 236 </CardContent> 292 237 </Card> 293 238 <div className="text-balance text-center text-xs text-muted-foreground [&_a]:underline [&_a]:underline-offset-4 [&_a]:hover:text-primary"> 294 - By clicking continue, you agree to our{" "} 295 - <a href="/terms">Terms of Service</a> and{" "} 296 - <a href="/privacy">Privacy Policy</a>. 239 + By clicking continue, you agree to our <a href="/terms">Terms of Service</a>{" "} 240 + and <a href="/privacy">Privacy Policy</a>. 297 241 </div> 298 242 </div> 299 243 );