diff --git a/public/icons/apple.png b/public/icons/apple.png new file mode 100644 index 0000000..eea2e3b Binary files /dev/null and b/public/icons/apple.png differ diff --git a/src/app/(auth-pages)/sign-in/page.tsx b/src/app/(auth-pages)/sign-in/page.tsx index 92c06c4..79fb481 100644 --- a/src/app/(auth-pages)/sign-in/page.tsx +++ b/src/app/(auth-pages)/sign-in/page.tsx @@ -18,13 +18,14 @@ import { Input, } from '@/components/ui'; import Link from 'next/link'; -import { signIn, signInWithMicrosoft } from '@/lib/actions'; +import { signIn } from '@/lib/actions'; import { useRouter } from 'next/navigation'; import { useAuth } from '@/components/context/auth'; import { useEffect, useState } from 'react'; import { StatusMessage, SubmitButton } from '@/components/default'; import { Separator } from '@/components/ui'; import { SignInWithMicrosoft } from '@/components/default/auth/SignInWithMicrosoft'; +import { SignInWithApple } from '@/components/default/auth/SignInWithApple'; const formSchema = z.object({ email: z.string().email({ @@ -148,6 +149,8 @@ const Login = () => { + + ); diff --git a/src/components/default/auth/SignInWithApple.tsx b/src/components/default/auth/SignInWithApple.tsx new file mode 100644 index 0000000..b74395b --- /dev/null +++ b/src/components/default/auth/SignInWithApple.tsx @@ -0,0 +1,58 @@ +'use client'; +import { signInWithApple } from '@/lib/actions'; +import { StatusMessage, SubmitButton } from '@/components/default'; +import { useAuth } from '@/components/context/auth'; +import { useRouter } from 'next/navigation'; +import { useState } from 'react'; +import Image from 'next/image'; + +export const SignInWithApple = () => { + const router = useRouter(); + const { isLoading, refreshUserData } = useAuth(); + const [statusMessage, setStatusMessage] = useState(''); + const [isSigningIn, setIsSigningIn] = useState(false); + + const handleSignInWithApple = async (e: React.FormEvent) => { + e.preventDefault(); + try { + setStatusMessage(''); + setIsSigningIn(true); + + const result = await signInWithApple(); + + if (result?.success && result.data) { + // Redirect to Apple OAuth page + window.location.href = result.data; + } else { + setStatusMessage(`Error: ${result.error}`); + } + } catch (error) { + setStatusMessage( + `Error: ${error instanceof Error ? error.message : 'Could not sign in!'}` + ); + } finally { + setIsSigningIn(false); + await refreshUserData(); + router.push(''); + } + }; + + return ( +
+ +
+ Apple logo +

Sign in with Apple

+
+
+ {statusMessage && ( + + )} + + ); +}; diff --git a/src/components/default/auth/SignInWithMicrosoft.tsx b/src/components/default/auth/SignInWithMicrosoft.tsx index 1334a27..e5911e6 100644 --- a/src/components/default/auth/SignInWithMicrosoft.tsx +++ b/src/components/default/auth/SignInWithMicrosoft.tsx @@ -1,4 +1,3 @@ -// src/components/default/auth/SignInWithMicrosoft.tsx 'use client'; import { signInWithMicrosoft } from '@/lib/actions'; import { StatusMessage, SubmitButton } from '@/components/default'; diff --git a/src/lib/actions/auth.ts b/src/lib/actions/auth.ts index 49483e4..ed2a0fa 100644 --- a/src/lib/actions/auth.ts +++ b/src/lib/actions/auth.ts @@ -67,7 +67,19 @@ export const signInWithMicrosoft = async (): Promise> => { const { data, error } = await supabase.auth.signInWithOAuth({ provider: 'azure', options: { - scopes: 'email', + scopes: 'openid, profile email offline_access', + } + }); + if (error) return { success: false, error: error.message }; + return { success: true, data: data.url}; +}; + +export const signInWithApple = async (): Promise> => { + const supabase = await createServerClient(); + const { data, error } = await supabase.auth.signInWithOAuth({ + provider: 'apple', + options: { + scopes: 'openid, profile email offline_access', } }); if (error) return { success: false, error: error.message };