wavelength_app/components/auth/SignInScreen.tsx

154 lines
5.3 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 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 initialData = await
fetch(`${process.env.NEXT_PUBLIC_API_URL}/api/users/getUserByAppleId` +
`?appleId=${credential.user}`, {
method: 'GET',
headers: {
'Content-Type': 'application/json',
'x-api-key': process.env.NEXT_PUBLIC_API_KEY ?? '',
},
});
console.log(initialData);
if (initialData.status === 404 || !initialData.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 userResponse = await
fetch(`${process.env.NEXT_PUBLIC_API_URL}/api/users/createUser`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'x-api-key': process.env.NEXT_PUBLIC_API_KEY ?? '',
},
body: JSON.stringify({
appleId: credential.user,
email: credential.email,
fullName:
`${credential.fullName?.givenName} ${credential.fullName?.familyName}`,
pushToken: pushToken,
}),
});
if (!userResponse.ok) {
const errorBody = await userResponse.text();
console.error(
'API error: No user returned: ',
userResponse.status, errorBody
);
throw new Error(`Failed to create user: ${userResponse.status} ${errorBody}`);
}
const user: User = await userResponse.json() as User;
await saveUser(user);
} else if (initialData.ok) {
const allData: InitialData = await initialData.json() as InitialData;
console.log('Existing user found! Saving data...');
if (allData.user.pushToken !== pushToken.data) {
const updatePushTokenResponse =
await fetch(`${process.env.NEXT_PUBLIC_API_URL}/api/users/updatePushToken`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'x-api-key': process.env.NEXT_PUBLIC_API_KEY ?? '',
},
body: JSON.stringify({
userId: allData.user.id,
pushToken: pushToken.data,
}),
});
if (!updatePushTokenResponse.ok) {
throw new Error(
`Failed to update push token: ${updatePushTokenResponse.status}`
);
}
} else {
console.log('Push token is up to date.');
}
allData.user.pushToken = pushToken.data;
await saveInitialData(allData);
}
onSignIn();
} catch (error) {
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,
},
});