Implement authentication functionality

Adds authentication functionality to the application.
This commit is contained in:
gpt-engineer-app[bot] 2025-03-09 12:41:42 +00:00
parent e1fb6c9bd0
commit d3e4bd2df2
2 changed files with 122 additions and 3 deletions

View File

@ -4,6 +4,8 @@ import { supabase } from '@/integrations/supabase/client';
import { Session, User } from '@supabase/supabase-js'; import { Session, User } from '@supabase/supabase-js';
import { useToast } from '@/hooks/use-toast'; import { useToast } from '@/hooks/use-toast';
type Provider = 'github' | 'google' | 'microsoft';
type AuthContextType = { type AuthContextType = {
session: Session | null; session: Session | null;
user: User | null; user: User | null;
@ -12,6 +14,7 @@ type AuthContextType = {
signIn: (email: string, password: string) => Promise<void>; signIn: (email: string, password: string) => Promise<void>;
signUp: (email: string, password: string, fullName: string) => Promise<void>; signUp: (email: string, password: string, fullName: string) => Promise<void>;
signOut: () => Promise<void>; signOut: () => Promise<void>;
signInWithProvider: (provider: Provider) => Promise<void>;
}; };
const AuthContext = createContext<AuthContextType | undefined>(undefined); const AuthContext = createContext<AuthContextType | undefined>(undefined);
@ -128,6 +131,33 @@ export const AuthProvider = ({ children }: { children: ReactNode }) => {
} }
}; };
const signInWithProvider = async (provider: Provider) => {
try {
setLoading(true);
const { error } = await supabase.auth.signInWithOAuth({
provider,
options: {
redirectTo: window.location.origin + '/dashboard',
},
});
if (error) throw error;
toast({
title: "Redirecting...",
description: `Signing in with ${provider}`,
});
} catch (error: any) {
toast({
title: `Error signing in with ${provider}`,
description: error.message,
variant: "destructive",
});
console.error(`Error signing in with ${provider}:`, error);
setLoading(false);
}
};
const signOut = async () => { const signOut = async () => {
try { try {
setLoading(true); setLoading(true);
@ -159,6 +189,7 @@ export const AuthProvider = ({ children }: { children: ReactNode }) => {
signIn, signIn,
signUp, signUp,
signOut, signOut,
signInWithProvider,
}} }}
> >
{children} {children}

View File

@ -8,9 +8,10 @@ import { Input } from '@/components/ui/input';
import { Label } from '@/components/ui/label'; import { Label } from '@/components/ui/label';
import { Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle } from '@/components/ui/card'; import { Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle } from '@/components/ui/card';
import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/components/ui/tabs'; import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/components/ui/tabs';
import { Separator } from '@/components/ui/separator';
const Auth = () => { const Auth = () => {
const { user, signIn, signUp, loading } = useAuth(); const { user, signIn, signUp, signInWithProvider, loading } = useAuth();
const [email, setEmail] = useState(''); const [email, setEmail] = useState('');
const [password, setPassword] = useState(''); const [password, setPassword] = useState('');
const [fullName, setFullName] = useState(''); const [fullName, setFullName] = useState('');
@ -41,6 +42,11 @@ const Auth = () => {
} }
}; };
const handleSocialSignIn = (provider: 'github' | 'google' | 'microsoft') => {
setAuthError(null);
signInWithProvider(provider);
};
return ( return (
<div className="min-h-screen flex items-center justify-center bg-muted/30 px-4"> <div className="min-h-screen flex items-center justify-center bg-muted/30 px-4">
<div className="max-w-md w-full"> <div className="max-w-md w-full">
@ -101,7 +107,7 @@ const Auth = () => {
<div className="text-sm text-destructive">{authError}</div> <div className="text-sm text-destructive">{authError}</div>
)} )}
</CardContent> </CardContent>
<CardFooter> <CardFooter className="flex flex-col gap-4">
<Button <Button
type="submit" type="submit"
className="w-full rounded-full" className="w-full rounded-full"
@ -109,6 +115,47 @@ const Auth = () => {
> >
{loading ? 'Signing in...' : 'Sign In'} {loading ? 'Signing in...' : 'Sign In'}
</Button> </Button>
<div className="relative w-full my-2">
<div className="absolute inset-0 flex items-center">
<Separator className="w-full" />
</div>
<div className="relative flex justify-center">
<span className="bg-card px-2 text-xs text-muted-foreground">
OR CONTINUE WITH
</span>
</div>
</div>
<div className="grid grid-cols-3 gap-3 w-full">
<Button
type="button"
variant="outline"
onClick={() => handleSocialSignIn('github')}
disabled={loading}
>
<svg xmlns="http://www.w3.org/2000/svg" className="h-5 w-5" viewBox="0 0 24 24"><path d="M12 0c-6.626 0-12 5.373-12 12 0 5.302 3.438 9.8 8.207 11.387.599.111.793-.261.793-.577v-2.234c-3.338.726-4.033-1.416-4.033-1.416-.546-1.387-1.333-1.756-1.333-1.756-1.089-.745.083-.729.083-.729 1.205.084 1.839 1.237 1.839 1.237 1.07 1.834 2.807 1.304 3.492.997.107-.775.418-1.305.762-1.604-2.665-.305-5.467-1.334-5.467-5.931 0-1.311.469-2.381 1.236-3.221-.124-.303-.535-1.524.117-3.176 0 0 1.008-.322 3.301 1.23.957-.266 1.983-.399 3.003-.404 1.02.005 2.047.138 3.006.404 2.291-1.552 3.297-1.23 3.297-1.23.653 1.653.242 2.874.118 3.176.77.84 1.235 1.911 1.235 3.221 0 4.609-2.807 5.624-5.479 5.921.43.372.823 1.102.823 2.222v3.293c0 .319.192.694.801.576 4.765-1.589 8.199-6.086 8.199-11.386 0-6.627-5.373-12-12-12z"/>
</svg>
</Button>
<Button
type="button"
variant="outline"
onClick={() => handleSocialSignIn('google')}
disabled={loading}
>
<svg xmlns="http://www.w3.org/2000/svg" className="h-5 w-5" viewBox="0 0 24 24"><path d="M12.48 10.92v3.28h7.84c-.24 1.84-.853 3.187-1.787 4.133-1.147 1.147-2.933 2.4-6.053 2.4-4.827 0-8.6-3.893-8.6-8.72s3.773-8.72 8.6-8.72c2.6 0 4.507 1.027 5.907 2.347l2.307-2.307C18.747 1.44 16.133 0 12.48 0 5.867 0 .307 5.387.307 12s5.56 12 12.173 12c3.573 0 6.267-1.173 8.373-3.36 2.16-2.16 2.84-5.213 2.84-7.667 0-.76-.053-1.467-.173-2.053H12.48z"/>
</svg>
</Button>
<Button
type="button"
variant="outline"
onClick={() => handleSocialSignIn('microsoft')}
disabled={loading}
>
<svg xmlns="http://www.w3.org/2000/svg" className="h-5 w-5" viewBox="0 0 23 23"><path d="M0 0h11v11H0z" fill="#f25022"/><path d="M12 0h11v11H12z" fill="#7fba00"/><path d="M0 12h11v11H0z" fill="#00a4ef"/><path d="M12 12h11v11H12z" fill="#ffb900"/>
</svg>
</Button>
</div>
</CardFooter> </CardFooter>
</form> </form>
</Card> </Card>
@ -173,7 +220,7 @@ const Auth = () => {
<div className="text-sm text-destructive">{authError}</div> <div className="text-sm text-destructive">{authError}</div>
)} )}
</CardContent> </CardContent>
<CardFooter> <CardFooter className="flex flex-col gap-4">
<Button <Button
type="submit" type="submit"
className="w-full rounded-full" className="w-full rounded-full"
@ -181,6 +228,47 @@ const Auth = () => {
> >
{loading ? 'Creating account...' : 'Create Account'} {loading ? 'Creating account...' : 'Create Account'}
</Button> </Button>
<div className="relative w-full my-2">
<div className="absolute inset-0 flex items-center">
<Separator className="w-full" />
</div>
<div className="relative flex justify-center">
<span className="bg-card px-2 text-xs text-muted-foreground">
OR CONTINUE WITH
</span>
</div>
</div>
<div className="grid grid-cols-3 gap-3 w-full">
<Button
type="button"
variant="outline"
onClick={() => handleSocialSignIn('github')}
disabled={loading}
>
<svg xmlns="http://www.w3.org/2000/svg" className="h-5 w-5" viewBox="0 0 24 24"><path d="M12 0c-6.626 0-12 5.373-12 12 0 5.302 3.438 9.8 8.207 11.387.599.111.793-.261.793-.577v-2.234c-3.338.726-4.033-1.416-4.033-1.416-.546-1.387-1.333-1.756-1.333-1.756-1.089-.745.083-.729.083-.729 1.205.084 1.839 1.237 1.839 1.237 1.07 1.834 2.807 1.304 3.492.997.107-.775.418-1.305.762-1.604-2.665-.305-5.467-1.334-5.467-5.931 0-1.311.469-2.381 1.236-3.221-.124-.303-.535-1.524.117-3.176 0 0 1.008-.322 3.301 1.23.957-.266 1.983-.399 3.003-.404 1.02.005 2.047.138 3.006.404 2.291-1.552 3.297-1.23 3.297-1.23.653 1.653.242 2.874.118 3.176.77.84 1.235 1.911 1.235 3.221 0 4.609-2.807 5.624-5.479 5.921.43.372.823 1.102.823 2.222v3.293c0 .319.192.694.801.576 4.765-1.589 8.199-6.086 8.199-11.386 0-6.627-5.373-12-12-12z"/>
</svg>
</Button>
<Button
type="button"
variant="outline"
onClick={() => handleSocialSignIn('google')}
disabled={loading}
>
<svg xmlns="http://www.w3.org/2000/svg" className="h-5 w-5" viewBox="0 0 24 24"><path d="M12.48 10.92v3.28h7.84c-.24 1.84-.853 3.187-1.787 4.133-1.147 1.147-2.933 2.4-6.053 2.4-4.827 0-8.6-3.893-8.6-8.72s3.773-8.72 8.6-8.72c2.6 0 4.507 1.027 5.907 2.347l2.307-2.307C18.747 1.44 16.133 0 12.48 0 5.867 0 .307 5.387.307 12s5.56 12 12.173 12c3.573 0 6.267-1.173 8.373-3.36 2.16-2.16 2.84-5.213 2.84-7.667 0-.76-.053-1.467-.173-2.053H12.48z"/>
</svg>
</Button>
<Button
type="button"
variant="outline"
onClick={() => handleSocialSignIn('microsoft')}
disabled={loading}
>
<svg xmlns="http://www.w3.org/2000/svg" className="h-5 w-5" viewBox="0 0 23 23"><path d="M0 0h11v11H0z" fill="#f25022"/><path d="M12 0h11v11H12z" fill="#7fba00"/><path d="M0 12h11v11H0z" fill="#00a4ef"/><path d="M12 12h11v11H12z" fill="#ffb900"/>
</svg>
</Button>
</div>
</CardFooter> </CardFooter>
</form> </form>
</Card> </Card>