diff --git a/apps/web/src/app/(auth)/login/page.tsx b/apps/web/src/app/(auth)/login/page.tsx new file mode 100644 index 0000000..5f37ced --- /dev/null +++ b/apps/web/src/app/(auth)/login/page.tsx @@ -0,0 +1,176 @@ +"use client"; + +import { useRouter } from "next/navigation"; +import { signIn } from "@/lib/auth-client"; +import { Button } from "@/components/ui/button"; +import { + Card, + CardContent, + CardDescription, + CardHeader, + CardTitle, +} from "@/components/ui/card"; +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 router = useRouter(); + 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); + setIsEmailLoading(true); + + const { error } = await signIn.email({ + email, + password, + }); + + if (error) { + setError(error.message || "An unexpected error occurred."); + setIsEmailLoading(false); + return; + } + + 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} + + )} + + +
+
+ +
+
+ + Or continue with + +
+
+
+
+ + 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 ( +
+ + + + Welcome back + + Sign in to your account to continue + + + + + +
+ } + > + + +
+ 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 new file mode 100644 index 0000000..d1feece --- /dev/null +++ b/apps/web/src/app/(auth)/signup/page.tsx @@ -0,0 +1,201 @@ +"use client"; + +import { useRouter } from "next/navigation"; +import { signUp, signIn } from "@/lib/auth-client"; +import { Button } from "@/components/ui/button"; +import { + Card, + CardContent, + CardDescription, + CardHeader, + CardTitle, +} from "@/components/ui/card"; +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 router = useRouter(); + 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); + setIsEmailLoading(true); + + const { error } = await signUp.email({ + name, + email, + password, + }); + + if (error) { + setError(error.message || "An unexpected error occurred."); + setIsEmailLoading(false); + return; + } + + router.push("/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} + + )} + + + +
+
+ +
+
+ + Or continue with + +
+
+ +
+
+ + 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" + /> +
+ +
+
+ ); +} + +export default function SignUpPage() { + const router = useRouter(); + + return ( +
+ + + + + + Create your account + + + Get started with your free account today + + + + + +
+ } + > + + +
+ Already have an account?{" "} + + Sign in + +
+ + + + ); +} diff --git a/apps/web/src/app/auth/login/page.tsx b/apps/web/src/app/auth/login/page.tsx deleted file mode 100644 index 18117f4..0000000 --- a/apps/web/src/app/auth/login/page.tsx +++ /dev/null @@ -1,5 +0,0 @@ -import { AuthForm } from "@/components/auth-form"; - -export default function LoginPage() { - return ; -} diff --git a/apps/web/src/app/auth/signup/page.tsx b/apps/web/src/app/auth/signup/page.tsx deleted file mode 100644 index 109ae5c..0000000 --- a/apps/web/src/app/auth/signup/page.tsx +++ /dev/null @@ -1,5 +0,0 @@ -import { AuthForm } from "@/components/auth-form"; - -export default function SignUpPage() { - return ; -} diff --git a/apps/web/src/components/auth-form.tsx b/apps/web/src/components/auth-form.tsx index 182137e..3dd5603 100644 --- a/apps/web/src/components/auth-form.tsx +++ b/apps/web/src/components/auth-form.tsx @@ -54,7 +54,7 @@ const authConfig = { description: "Sign in to your account to continue", buttonText: "Sign in", linkText: "Don't have an account?", - linkHref: "/auth/signup", + linkHref: "/signup", linkLabel: "Sign up", successRedirect: "/editor", }, @@ -63,9 +63,9 @@ const authConfig = { description: "Get started with your free account today", buttonText: "Create account", linkText: "Already have an account?", - linkHref: "/auth/login", + linkHref: "/login", linkLabel: "Sign in", - successRedirect: "/auth/login", + successRedirect: "/login", }, } as const; diff --git a/apps/web/src/components/editor/properties-panel.tsx b/apps/web/src/components/editor/properties-panel.tsx index 2b211c2..c784dab 100644 --- a/apps/web/src/components/editor/properties-panel.tsx +++ b/apps/web/src/components/editor/properties-panel.tsx @@ -38,7 +38,6 @@ export function PropertiesPanel() { ? mediaItems.find((item) => item.id === firstVideoClip.mediaId) : null; - // Get the first image clip for preview (simplified) const firstImageClip = tracks .flatMap((track) => track.clips) .find((clip) => { diff --git a/apps/web/src/components/header.tsx b/apps/web/src/components/header.tsx index b742bf3..9f842b2 100644 --- a/apps/web/src/components/header.tsx +++ b/apps/web/src/components/header.tsx @@ -6,9 +6,27 @@ import { Button } from "./ui/button"; import { ArrowRight } from "lucide-react"; import { HeaderBase } from "./header-base"; import { useSession } from "@/lib/auth-client"; +import { getStars } from "@/lib/fetchGhStars"; +import { Star } from "lucide-react"; +import { useEffect, useState } from "react"; export function Header() { const { data: session } = useSession(); + const [star, setStar] = useState(""); + + useEffect(() => { + const fetchStars = async () => { + try { + const data = await getStars(); + setStar(data); + } catch (err) { + console.error("Failed to fetch GitHub stars", err); + } + }; + + fetchStars(); + }, []); + const leftContent = ( OpenCut Logo @@ -19,11 +37,18 @@ export function Header() { const rightContent = (