wavelength_app/components/auth/SignInScreen.tsx
2024-11-01 09:54:10 -05:00

144 lines
4.8 KiB
TypeScript

import React from 'react';
import * as AppleAuthentication from 'expo-apple-authentication';
import { StyleSheet, Alert, ImageBackground } from 'react-native';
import { ThemedText, ThemedView } from '@/components/theme/Theme';
import { SafeAreaView, SafeAreaProvider } from 'react-native-safe-area-context';
import { useColorScheme } from '@/hooks/useColorScheme';
import { Colors } from '@/constants/Colors';
import * as Notifications from 'expo-notifications';
import Constants from 'expo-constants';
import { saveUser, saveInitialData } from '@/components/services/SecureStore';
import {
getInitialDataByAppleId,
createUser,
updatePushToken
} from '@/constants/APIs';
import type { InitialData, User } from '@/constants/Types';
const SignInScreen = ({onSignIn}: {onSignIn: () => void}) => {
const scheme = useColorScheme() ?? 'dark';
const handleAppleSignIn = async () => {
try {
const credential = await AppleAuthentication.signInAsync({
requestedScopes: [
AppleAuthentication.AppleAuthenticationScope.EMAIL,
AppleAuthentication.AppleAuthenticationScope.FULL_NAME,
],
});
const projectId = Constants.expoConfig?.extra?.eas?.projectId;
if (!projectId) throw new Error('Project ID not found in eas.json');
const pushToken = await Notifications.getExpoPushTokenAsync({
projectId: projectId,
});
const initialDataResponse = await getInitialDataByAppleId(credential.user);
if (initialDataResponse.status === 404 || !initialDataResponse.ok) {
if (!credential.user || !credential.email ||
!credential.fullName?.givenName || !credential.fullName?.familyName ||
!pushToken || credential.email.length === 0) {
Alert.alert(
'Sign in error',
'Unable to create an account. ' +
'Remove App from Sign in with Apple & try again.',
);
throw new Error(
'Incomplete user data. This shouldn\'t happen & means that user has ' +
'previously signed in with Apple, but their user data did not ' +
'save in the database.'
);
}
const user: User = await createUser(
credential.user,
credential.email,
credential.fullName?.givenName + ' ' + credential.fullName?.familyName,
pushToken.data
) as User;
await saveUser(user);
//Alert.alert(`${user.appleId} - ${user.email} - ${user.fullName} - ${user.pushToken}`);
} else if (initialDataResponse.ok) {
const initialData: InitialData = await initialDataResponse.json() as InitialData;
console.log('Existing user found! Saving data...');
//Alert.alert('Existing user found! Saving data...');
if (initialData.user.pushToken !== pushToken.data) {
const updatePushTokenResponse = await updatePushToken(
initialData.user.id,
pushToken.data
);
} else {
console.log('Push token is up to date.');
}
initialData.user.pushToken = pushToken.data;
await saveInitialData(initialData);
}
onSignIn();
} catch (error: unknown) {
console.error('Error signing in:', error);
if (error.code === 'ERR_REQUEST_CANCELLED') {
Alert.alert('Sign in error', 'Sign in was cancelled.');
} else {
Alert.alert(
'Sign in error',
'An error occurred while signing in. Please try again or contact support.'
);
}
}
};
return (
<ThemedView style={styles.container}>
<ImageBackground
source={require('@/assets/images/splash.png')} resizeMode="cover"
style={styles.background}
>
<ThemedText style={[
styles.title,
{textShadowColor: Colors[scheme].background}
]}>
Wavelength
</ThemedText>
<AppleAuthentication.AppleAuthenticationButton
buttonType={AppleAuthentication.AppleAuthenticationButtonType.SIGN_IN}
buttonStyle={(scheme === 'light') ?
AppleAuthentication.AppleAuthenticationButtonStyle.BLACK :
AppleAuthentication.AppleAuthenticationButtonStyle.WHITE
}
cornerRadius={5}
style={styles.button}
onPress={handleAppleSignIn}
/>
</ImageBackground>
</ThemedView>
);
};
export default SignInScreen;
const styles = StyleSheet.create({
container: {
flex: 1,
},
background: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
},
title: {
fontSize: 48,
lineHeight: 48,
fontWeight: 'bold',
marginBottom: 80,
textShadowOffset: {
width: 1,
height: 1,
},
textShadowRadius: 5,
},
button: {
width: 200,
height: 45,
},
});