From 8bcd226bdb4eb3468df0590dbe6d3d8d68b2acbd Mon Sep 17 00:00:00 2001 From: Deepanshu Mishra Date: Mon, 23 Jun 2025 22:51:34 +0530 Subject: [PATCH] Added google auth and some auth page ui optimisations --- apps/web/.env.example | 6 +- apps/web/src/app/auth/login/page.tsx | 134 +++++++++++++++------ apps/web/src/app/auth/signup/page.tsx | 163 +++++++++++++++++++------- apps/web/src/components/header.tsx | 4 +- apps/web/src/components/icons.tsx | 22 ++++ apps/web/src/lib/auth-client.ts | 2 +- apps/web/src/lib/auth.ts | 6 + 7 files changed, 254 insertions(+), 83 deletions(-) create mode 100644 apps/web/src/components/icons.tsx diff --git a/apps/web/.env.example b/apps/web/.env.example index 8477646..0b4c649 100644 --- a/apps/web/.env.example +++ b/apps/web/.env.example @@ -7,9 +7,13 @@ DATABASE_URL="postgresql://opencut:opencutthegoat@localhost:5432/opencut" BETTER_AUTH_URL=http://localhost:3000 BETTER_AUTH_SECRET=your-secret-key-here +#Google Clients +GOOGLE_CLIENT_ID= +GOOGLE_CLIENT_SECRET= + # Development Environment NODE_ENV=development # Redis UPSTASH_REDIS_REST_URL=http://localhost:8079 -UPSTASH_REDIS_REST_TOKEN=example_token \ No newline at end of file +UPSTASH_REDIS_REST_TOKEN=example_token diff --git a/apps/web/src/app/auth/login/page.tsx b/apps/web/src/app/auth/login/page.tsx index 5eadb85..ebf2eb3 100644 --- a/apps/web/src/app/auth/login/page.tsx +++ b/apps/web/src/app/auth/login/page.tsx @@ -1,7 +1,7 @@ "use client"; -import { useSearchParams, useRouter } from "next/navigation"; -import { authClient } from "@/lib/auth-client"; +import { useRouter } from "next/navigation"; +import { signIn } from "@/lib/auth-client"; import { Button } from "@/components/ui/button"; import { Card, @@ -13,81 +13,145 @@ import { import { Suspense, useState } from "react"; import { Input } from "@/components/ui/input"; import { Label } from "@/components/ui/label"; +import { Separator } from "@/components/ui/separator"; import Link from "next/link"; import { Alert, AlertDescription, AlertTitle } from "@/components/ui/alert"; +import { ArrowLeft, Loader2 } from "lucide-react"; +import { GoogleIcon } from "@/components/icons"; function LoginForm() { - const searchParams = useSearchParams(); const router = useRouter(); - const redirectUrl = searchParams.get("redirect"); const [email, setEmail] = useState(""); const [password, setPassword] = useState(""); const [error, setError] = useState(null); + const [isEmailLoading, setIsEmailLoading] = useState(false); + const [isGoogleLoading, setIsGoogleLoading] = useState(false); const handleLogin = async () => { setError(null); - const { error } = await authClient.signIn.email({ + setIsEmailLoading(true); + + const { error } = await signIn.email({ email, password, }); if (error) { setError(error.message || "An unexpected error occurred."); + setIsEmailLoading(false); return; } - router.push(redirectUrl || "/"); + router.push("/editor"); }; + const handleGoogleLogin = async () => { + setError(null); + setIsGoogleLoading(true); + + try { + await signIn.social({ + provider: "google", + }); + router.push("/editor"); + } catch (error) { + setError("Failed to sign in with Google. Please try again."); + setIsGoogleLoading(false); + } + }; + + const isAnyLoading = isEmailLoading || isGoogleLoading; + return ( -
+
{error && ( Error {error} )} -
- - setEmail(e.target.value)} - /> + + +
+
+ +
+
+ Or continue with +
-
- - setPassword(e.target.value)} - /> +
+
+ + setEmail(e.target.value)} + disabled={isAnyLoading} + className="h-11" + /> +
+
+ + setPassword(e.target.value)} + disabled={isAnyLoading} + className="h-11" + /> +
+
-
); } export default function LoginPage() { + const router = useRouter(); + return ( -
- - - Login - - Enter your email and password to login. +
+ + + + Welcome back + + Sign in to your account to continue - - Loading...
}> + + + +
}> -
+
Don't have an account?{" "} - + Sign up
diff --git a/apps/web/src/app/auth/signup/page.tsx b/apps/web/src/app/auth/signup/page.tsx index f328851..3d125a0 100644 --- a/apps/web/src/app/auth/signup/page.tsx +++ b/apps/web/src/app/auth/signup/page.tsx @@ -1,7 +1,7 @@ "use client"; -import { useSearchParams, useRouter } from "next/navigation"; -import { authClient } from "@/lib/auth-client"; +import { useRouter } from "next/navigation"; +import { signUp, signIn } from "@/lib/auth-client"; import { Button } from "@/components/ui/button"; import { Card, @@ -13,21 +13,26 @@ import { import { Suspense, useState } from "react"; import { Input } from "@/components/ui/input"; import { Label } from "@/components/ui/label"; +import { Separator } from "@/components/ui/separator"; import Link from "next/link"; import { Alert, AlertDescription, AlertTitle } from "@/components/ui/alert"; +import { Loader2, ArrowLeft } from "lucide-react"; +import { GoogleIcon } from "@/components/icons"; function SignUpForm() { - const searchParams = useSearchParams(); const router = useRouter(); - const redirectUrl = searchParams.get("redirect"); const [name, setName] = useState(""); const [email, setEmail] = useState(""); const [password, setPassword] = useState(""); const [error, setError] = useState(null); + const [isEmailLoading, setIsEmailLoading] = useState(false); + const [isGoogleLoading, setIsGoogleLoading] = useState(false); const handleSignUp = async () => { setError(null); - const { error } = await authClient.signUp.email({ + setIsEmailLoading(true); + + const { error } = await signUp.email({ name, email, password, @@ -35,70 +40,138 @@ function SignUpForm() { if (error) { setError(error.message || "An unexpected error occurred."); + setIsEmailLoading(false); return; } - router.push(redirectUrl || "/"); + router.push("/auth/login"); }; + const handleGoogleSignUp = async () => { + setError(null); + setIsGoogleLoading(true); + + try { + await signIn.social({ + provider: "google", + }); + + router.push("/editor"); + } catch (error) { + setError("Failed to sign up with Google. Please try again."); + setIsGoogleLoading(false); + } + }; + + const isAnyLoading = isEmailLoading || isGoogleLoading; + return ( -
+
{error && ( Error {error} )} -
- - setName(e.target.value)} - /> + + + +
+
+ +
+
+ Or continue with +
-
- - setEmail(e.target.value)} - /> + +
+
+ + setName(e.target.value)} + disabled={isAnyLoading} + className="h-11" + /> +
+
+ + setEmail(e.target.value)} + disabled={isAnyLoading} + className="h-11" + /> +
+
+ + setPassword(e.target.value)} + disabled={isAnyLoading} + className="h-11" + /> +
+
-
- - setPassword(e.target.value)} - /> -
-
); } export default function SignUpPage() { + const router = useRouter(); + return ( -
- - - Sign Up - Create an account to get started. +
+ + + + + Create your account + + Get started with your free account today + - - Loading...
}> + + + +
}> -
+
Already have an account?{" "} - - Login + + Sign in
diff --git a/apps/web/src/components/header.tsx b/apps/web/src/components/header.tsx index 004863d..109d022 100644 --- a/apps/web/src/components/header.tsx +++ b/apps/web/src/components/header.tsx @@ -5,8 +5,10 @@ import Image from "next/image"; import { Button } from "./ui/button"; import { ArrowRight } from "lucide-react"; import { HeaderBase } from "./header-base"; +import { useSession } from "@/lib/auth-client"; export function Header() { + const { data: session } = useSession(); const leftContent = ( OpenCut Logo @@ -21,7 +23,7 @@ export function Header() { GitHub - +