https://altly.madebydanny.uk
at main 154 lines 4.7 kB view raw
1import { useState, useEffect } from "react"; 2import { useNavigate } from "react-router-dom"; 3import { Eye, Loader2 } from "lucide-react"; 4import { Button } from "@/components/ui/button"; 5import { Input } from "@/components/ui/input"; 6import { Label } from "@/components/ui/label"; 7import { Card } from "@/components/ui/card"; 8import { useToast } from "@/hooks/use-toast"; 9import { supabase } from "@/integrations/supabase/client"; 10 11export default function Auth() { 12 const [email, setEmail] = useState(""); 13 const [password, setPassword] = useState(""); 14 const [isLogin, setIsLogin] = useState(true); 15 const [isLoading, setIsLoading] = useState(false); 16 const navigate = useNavigate(); 17 const { toast } = useToast(); 18 19 useEffect(() => { 20 // Check if user is already logged in 21 supabase.auth.getSession().then(({ data: { session } }) => { 22 if (session) { 23 navigate("/app"); 24 } 25 }); 26 27 const { data: { subscription } } = supabase.auth.onAuthStateChange((event, session) => { 28 if (session) { 29 navigate("/app"); 30 } 31 }); 32 33 return () => subscription.unsubscribe(); 34 }, [navigate]); 35 36 const handleSubmit = async (e: React.FormEvent) => { 37 e.preventDefault(); 38 setIsLoading(true); 39 40 try { 41 if (isLogin) { 42 const { error } = await supabase.auth.signInWithPassword({ 43 email, 44 password, 45 }); 46 47 if (error) throw error; 48 49 toast({ 50 title: "Welcome back!", 51 description: "You've successfully signed in.", 52 }); 53 } else { 54 const { error } = await supabase.auth.signUp({ 55 email, 56 password, 57 options: { 58 emailRedirectTo: `${window.location.origin}/`, 59 }, 60 }); 61 62 if (error) throw error; 63 64 toast({ 65 title: "Account created!", 66 description: "You've successfully signed up.", 67 }); 68 } 69 } catch (error: any) { 70 toast({ 71 title: "Error", 72 description: error.message || "An error occurred during authentication", 73 variant: "destructive", 74 }); 75 } finally { 76 setIsLoading(false); 77 } 78 }; 79 80 return ( 81 <div className="min-h-screen bg-background flex items-center justify-center px-4"> 82 <div className="w-full max-w-md"> 83 <div className="text-center mb-8"> 84 <div className="inline-flex items-center justify-center w-16 h-16 rounded-2xl bg-primary/20 mb-4"> 85 <Eye className="w-8 h-8 text-primary" /> 86 </div> 87 <h1 className="text-3xl font-bold text-foreground mb-2">ALTly</h1> 88 <p className="text-muted-foreground"> 89 {isLogin ? "Sign in to continue" : "Create your account"} 90 </p> 91 </div> 92 93 <Card className="p-6"> 94 <form onSubmit={handleSubmit} className="space-y-4"> 95 <div className="space-y-2"> 96 <Label htmlFor="email">Email</Label> 97 <Input 98 id="email" 99 type="email" 100 placeholder="you@example.com" 101 value={email} 102 onChange={(e) => setEmail(e.target.value)} 103 required 104 disabled={isLoading} 105 /> 106 </div> 107 108 <div className="space-y-2"> 109 <Label htmlFor="password">Password</Label> 110 <Input 111 id="password" 112 type="password" 113 placeholder="••••••••" 114 value={password} 115 onChange={(e) => setPassword(e.target.value)} 116 required 117 disabled={isLoading} 118 minLength={6} 119 /> 120 </div> 121 122 <Button 123 type="submit" 124 className="w-full" 125 disabled={isLoading} 126 > 127 {isLoading ? ( 128 <> 129 <Loader2 className="w-4 h-4 mr-2 animate-spin" /> 130 {isLogin ? "Signing in..." : "Creating account..."} 131 </> 132 ) : ( 133 <>{isLogin ? "Sign In" : "Sign Up"}</> 134 )} 135 </Button> 136 137 <div className="text-center text-sm"> 138 <button 139 type="button" 140 onClick={() => setIsLogin(!isLogin)} 141 className="text-primary hover:underline" 142 disabled={isLoading} 143 > 144 {isLogin 145 ? "Don't have an account? Sign up" 146 : "Already have an account? Sign in"} 147 </button> 148 </div> 149 </form> 150 </Card> 151 </div> 152 </div> 153 ); 154}