130 lines
3.6 KiB
TypeScript
130 lines
3.6 KiB
TypeScript
import React, { useState, useEffect } from 'react';
|
|
import { StyleSheet, Alert, Platform } from 'react-native';
|
|
import * as AppleAuthentication from 'expo-apple-authentication';
|
|
import { supabase } from '@/lib/supabase';
|
|
import { useColorScheme } from '@/hooks/useColorScheme';
|
|
|
|
type AppleSignInProps = {
|
|
onSignInStart?: () => void;
|
|
onSignInComplete?: () => void;
|
|
onSignInError?: (error: any) => void;
|
|
};
|
|
|
|
const AppleSignIn: React.FC<AppleSignInProps> = ({
|
|
onSignInStart,
|
|
onSignInComplete,
|
|
onSignInError,
|
|
}) => {
|
|
const scheme = useColorScheme() ?? 'dark';
|
|
const [isAppleAuthAvailable, setIsAppleAuthAvailable] = useState(false);
|
|
|
|
useEffect(() => {
|
|
if (Platform.OS === 'ios') {
|
|
AppleAuthentication.isAvailableAsync().then(setIsAppleAuthAvailable);
|
|
}
|
|
}, []);
|
|
|
|
const handleAppleSignIn = async () => {
|
|
try {
|
|
onSignInStart?.();
|
|
|
|
// Get credentials from Apple
|
|
const credential = await AppleAuthentication.signInAsync({
|
|
requestedScopes: [
|
|
AppleAuthentication.AppleAuthenticationScope.FULL_NAME,
|
|
AppleAuthentication.AppleAuthenticationScope.EMAIL,
|
|
],
|
|
});
|
|
|
|
if (!credential.email) {
|
|
throw new Error('Email is required for Apple Sign In');
|
|
}
|
|
|
|
// Extract user information
|
|
const { email, fullName, user: appleUserId } = credential;
|
|
|
|
// Create a name from the fullName object if available
|
|
let name = null;
|
|
if (fullName?.givenName || fullName?.familyName) {
|
|
name = `${fullName?.givenName || ''} ${fullName?.familyName || ''}`.trim();
|
|
}
|
|
|
|
// Create a deterministic password based on the Apple user ID
|
|
// This way the user can sign in again with the same password
|
|
const password = `Apple-${appleUserId.substring(0, 16)}`;
|
|
|
|
// First try to sign in (in case the user already exists)
|
|
const { data: signInData, error: signInError } = await supabase.auth.signInWithPassword({
|
|
email,
|
|
password,
|
|
});
|
|
|
|
if (!signInError && signInData?.user) {
|
|
// User exists and signed in successfully
|
|
onSignInComplete?.();
|
|
return;
|
|
}
|
|
|
|
// If sign-in failed, create a new user
|
|
const { data: signUpData, error: signUpError } = await supabase.auth.signUp({
|
|
email,
|
|
password,
|
|
options: {
|
|
data: {
|
|
full_name: name,
|
|
}
|
|
}
|
|
});
|
|
|
|
if (signUpError) {
|
|
throw signUpError;
|
|
}
|
|
|
|
// User created successfully
|
|
onSignInComplete?.();
|
|
|
|
} catch (error) {
|
|
console.error('Apple sign in error:', error);
|
|
|
|
if (error.code === 'ERR_REQUEST_CANCELED') {
|
|
console.log('Sign in was canceled');
|
|
} else {
|
|
Alert.alert(
|
|
'Sign in error',
|
|
'An error occurred while signing in with Apple. Please try again.'
|
|
);
|
|
onSignInError?.(error);
|
|
}
|
|
}
|
|
};
|
|
|
|
// Only render on iOS and if Apple Authentication is available
|
|
if (Platform.OS !== 'ios' || !isAppleAuthAvailable) {
|
|
return null;
|
|
}
|
|
|
|
return (
|
|
<AppleAuthentication.AppleAuthenticationButton
|
|
buttonType={AppleAuthentication.AppleAuthenticationButtonType.SIGN_IN}
|
|
buttonStyle={
|
|
scheme === 'light'
|
|
? AppleAuthentication.AppleAuthenticationButtonStyle.BLACK
|
|
: AppleAuthentication.AppleAuthenticationButtonStyle.WHITE
|
|
}
|
|
cornerRadius={10}
|
|
style={styles.button}
|
|
onPress={handleAppleSignIn}
|
|
/>
|
|
);
|
|
};
|
|
|
|
const styles = StyleSheet.create({
|
|
button: {
|
|
width: 320,
|
|
height: 50,
|
|
marginVertical: 10,
|
|
},
|
|
});
|
|
|
|
export default AppleSignIn;
|