Skip to content

Commit 03a1b1b

Browse files
authored
Merge pull request #26 from rezahedi/refactor-auth
Auth Using Google OAuth2.0
2 parents c5f9cfa + 7ac9a31 commit 03a1b1b

File tree

6 files changed

+132
-20
lines changed

6 files changed

+132
-20
lines changed

.env.example

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,4 +4,5 @@
44
# Don't share the key with anyone
55

66
VITE_API_BASE_URL=YOUR_KEY
7-
VITE_GOOGLE_MAP_API_KEY=YOUR_GOOGLE-MAP_API_KEY
7+
VITE_GOOGLE_MAP_API_KEY=YOUR_GOOGLE-MAP_API_KEY
8+
VITE_GOOGLE_OAUTH_CLIENT_ID=YOUR_GOOGLE-OAUTH_CLIENT_ID

package-lock.json

Lines changed: 14 additions & 3 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
"@radix-ui/react-separator": "^1.1.7",
2424
"@radix-ui/react-slot": "^1.2.3",
2525
"@radix-ui/react-tooltip": "^1.2.7",
26+
"@react-oauth/google": "^0.12.2",
2627
"@tailwindcss/vite": "^4.1.11",
2728
"@tanstack/react-query": "^5.90.3",
2829
"@vis.gl/react-google-maps": "^1.5.2",
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
import React from "react";
2+
import { CodeResponse, useGoogleLogin } from "@react-oauth/google";
3+
import { Button } from "../ui/button";
4+
import { Google } from "@/ui/icons";
5+
6+
const GoogleLoginButton = ({
7+
onLogin,
8+
}: {
9+
onLogin: (code: string) => void;
10+
}) => {
11+
const handleLogin = useGoogleLogin({
12+
flow: "auth-code",
13+
onSuccess: async (response: CodeResponse) => {
14+
onLogin(response.code);
15+
},
16+
onError: async (errorResponse) => {
17+
console.log("Login Failed", errorResponse);
18+
},
19+
});
20+
21+
return (
22+
<Button
23+
onClick={handleLogin}
24+
variant="ghost"
25+
className="my-2 w-full p-5 font-normal text-lg bg-foreground text-background hover:bg-foreground hover:text-background active:scale-95"
26+
>
27+
<Google className="size-8" /> Sign in with Google
28+
</Button>
29+
);
30+
};
31+
32+
export default GoogleLoginButton;

src/Components/Auth/Login.tsx

Lines changed: 57 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,12 @@
11
import React, { useState } from "react";
2-
import { Google } from "@/ui/icons";
32
import { postData } from "@/util";
43
import { useAuth } from "@/context/AuthContext";
54
import { useAuthModal } from "@/context/AuthModalContext";
65
import { User } from "@/types";
76
import { Dialog, DialogContent } from "@/Components/ui/dialog";
87
import { Button } from "@/Components/ui/button";
8+
import { GoogleOAuthProvider } from "@react-oauth/google";
9+
import GoogleLoginButton from "./GoogleLoginButton";
910

1011
const LoginPage = ({
1112
open,
@@ -78,8 +79,10 @@ const LoginPage = ({
7879
handleClose();
7980
};
8081

81-
const handleLogin = async () => {
82-
if (!email || !password || !isValid) {
82+
const handleLogin = async (
83+
demoData: { email: string; password: string } | null = null,
84+
) => {
85+
if (!demoData && (!email || !password || !isValid)) {
8386
setEmailError("Email is required");
8487
setPasswordError("Password is required");
8588
setIsValid(false);
@@ -89,7 +92,7 @@ const LoginPage = ({
8992
try {
9093
const userData: User = await postData(
9194
"auth/login",
92-
{ email, password },
95+
demoData || { email, password },
9396
setErrorMessage,
9497
);
9598
if (userData) {
@@ -103,19 +106,42 @@ const LoginPage = ({
103106
}
104107
};
105108

109+
const handleGoogleLogin = async (code: string) => {
110+
if (!code) return setErrorMessage("Code is required");
111+
112+
try {
113+
const userData = await postData(
114+
"auth/login/google",
115+
{ code },
116+
setErrorMessage,
117+
);
118+
if (userData) {
119+
await login(userData);
120+
handleDialogClose();
121+
}
122+
} catch (err: unknown) {
123+
let errorMessage = "";
124+
if (err instanceof Error) errorMessage = err.message;
125+
setErrorMessage(`Error sending data to server: ${errorMessage}`);
126+
}
127+
};
128+
129+
const handleDemoLogin = async (email: string, password: string) => {
130+
await handleLogin({ email, password });
131+
};
132+
106133
return (
107134
<Dialog open={open} onOpenChange={handleDialogClose} modal>
108135
<DialogContent className="px-3 py-8 w-full max-w-full h-full sm:w-auto sm:max-w-4xl sm:h-auto rounded-none sm:rounded-lg items-center">
109136
<div className="flex gap-8 md:p-8 md:w-3xl">
110137
{/* Left Section */}
111138
<div className="flex-1 md:flex-1/2 px-2 py-3 space-y-2">
112139
<h5 className="flex justify-center text-3xl">Sign In</h5>
113-
<Button
114-
variant="ghost"
115-
className="my-2 w-full p-5 font-normal text-lg bg-foreground text-background hover:bg-foreground hover:text-background active:scale-95"
140+
<GoogleOAuthProvider
141+
clientId={import.meta.env.VITE_GOOGLE_OAUTH_CLIENT_ID}
116142
>
117-
<Google className="size-8" /> Sign in with Google
118-
</Button>
143+
<GoogleLoginButton onLogin={handleGoogleLogin} />
144+
</GoogleOAuthProvider>
119145
<div className="my-4 text-foreground/60 text-center">OR</div>
120146
<label className="block">
121147
Email:
@@ -162,7 +188,7 @@ const LoginPage = ({
162188
<Button
163189
variant="default"
164190
className="w-full active:scale-95"
165-
onClick={handleLogin}
191+
onClick={() => handleLogin()}
166192
>
167193
Sign in
168194
</Button>
@@ -179,6 +205,27 @@ const LoginPage = ({
179205
Sign up
180206
</Button>
181207
</p>
208+
<p className="text-sm flex gap-1 items-center justify-center">
209+
<span className="italic">Demo login:</span>
210+
<Button
211+
variant={"outline"}
212+
className="hover:bg-primary"
213+
onClick={() =>
214+
handleDemoLogin("[email protected]", "B5TTP76m2NSBbye")
215+
}
216+
>
217+
John Doe
218+
</Button>
219+
<Button
220+
variant={"outline"}
221+
className="hover:bg-primary"
222+
onClick={() =>
223+
handleDemoLogin("[email protected]", "B5TTP76m2NSBbye")
224+
}
225+
>
226+
Sarah Smith
227+
</Button>
228+
</p>
182229
</div>
183230

184231
{/* Right Section */}

src/Components/Auth/Register.tsx

Lines changed: 26 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,12 @@
11
import React, { useState } from "react";
2-
import { Google } from "@/ui/icons";
32
import { Dialog, DialogContent } from "@/Components/ui/dialog";
43
import { Button } from "@/Components/ui/button";
54
import { postData } from "@/util";
65
import { useAuth } from "@/context/AuthContext";
76
import { useAuthModal } from "@/context/AuthModalContext";
87
import { User } from "@/types";
8+
import { GoogleOAuthProvider } from "@react-oauth/google";
9+
import GoogleLoginButton from "./GoogleLoginButton";
910

1011
const RegisterPage = ({
1112
open,
@@ -130,6 +131,26 @@ const RegisterPage = ({
130131
}
131132
};
132133

134+
const handleGoogleLogin = async (code: string) => {
135+
if (!code) return setErrorMessage("Code is required");
136+
137+
try {
138+
const userData = await postData(
139+
"auth/login/google",
140+
{ code },
141+
setErrorMessage,
142+
);
143+
if (userData) {
144+
await login(userData);
145+
handleDialogClose();
146+
}
147+
} catch (err: unknown) {
148+
let errorMessage = "";
149+
if (err instanceof Error) errorMessage = err.message;
150+
setErrorMessage(`Error sending data to server: ${errorMessage}`);
151+
}
152+
};
153+
133154
return (
134155
<Dialog open={open} onOpenChange={handleDialogClose} modal>
135156
<DialogContent className="px-3 py-8 w-full max-w-full h-full sm:w-auto sm:max-w-4xl sm:h-auto rounded-none sm:rounded-lg items-center">
@@ -138,12 +159,11 @@ const RegisterPage = ({
138159
<h5 className="flex justify-center text-3xl">
139160
Create Your Account
140161
</h5>
141-
<Button
142-
variant="ghost"
143-
className="my-2 w-full p-5 font-normal text-lg bg-foreground text-background hover:bg-foreground hover:text-background active:scale-95"
162+
<GoogleOAuthProvider
163+
clientId={import.meta.env.VITE_GOOGLE_OAUTH_CLIENT_ID}
144164
>
145-
<Google className="size-8" /> Sign up with Google
146-
</Button>
165+
<GoogleLoginButton onLogin={handleGoogleLogin} />
166+
</GoogleOAuthProvider>
147167
<div className="my-4 text-foreground/60 text-center">OR</div>
148168
<label className="block">
149169
Name:

0 commit comments

Comments
 (0)