wavelength_app/components/auth/SignInScreen.tsx

120 lines
4.0 KiB
TypeScript

import React from 'react';
import * as AppleAuthentication from 'expo-apple-authentication';
import { StyleSheet, Alert } from 'react-native';
import { ThemedView } from '@/components/theme/Theme';
import { useColorScheme } from '@/hooks/useColorScheme';
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,
});
console.log(
credential.user, credential.email, credential.fullName?.givenName,
credential.fullName?.familyName, pushToken
);
const initialDataResponse = await getInitialDataByAppleId(credential.user);
console.log(initialDataResponse);
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);
} else if (initialDataResponse.ok) {
const initialData: InitialData = await initialDataResponse.json() as InitialData;
console.log('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}>
<AppleAuthentication.AppleAuthenticationButton
buttonType={AppleAuthentication.AppleAuthenticationButtonType.SIGN_IN}
buttonStyle={(scheme === 'light') ?
AppleAuthentication.AppleAuthenticationButtonStyle.BLACK :
AppleAuthentication.AppleAuthenticationButtonStyle.WHITE
}
cornerRadius={5}
style={styles.button}
onPress={handleAppleSignIn}
/>
</ThemedView>
);
};
export default SignInScreen;
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
},
button: {
width: 200,
height: 45,
},
});