diff --git a/.env b/.env deleted file mode 100644 index 7e0a5f8..0000000 --- a/.env +++ /dev/null @@ -1,2 +0,0 @@ -# .env.development -API_URI=https://api-dev.railbird.ai/graphql diff --git a/App.tsx b/App.tsx index 5026945..6d8beec 100644 --- a/App.tsx +++ b/App.tsx @@ -1,16 +1,30 @@ -import { DEV_USER_ID } from "@env"; -import React from "react"; +import React, { useEffect } from "react"; import { ClientProvider, useAuthHeader } from "./graphql/client"; import AppNavigator from "./navigation/app-navigator"; +import { DEV_USER_ID } from "@env"; +import AsyncStorage from "@react-native-async-storage/async-storage"; + +// TODO: move to different file? const SetAuthHeaderBasedOnEnv = () => { const { setAuthHeader } = useAuthHeader(); - React.useEffect(() => { - if (DEV_USER_ID) { - console.log("Setting fake authorization user to: ", DEV_USER_ID); - setAuthHeader({ key: "user_id", value: DEV_USER_ID }); - } + useEffect(() => { + const setAuthAsync = async () => { + if (DEV_USER_ID) { + console.log("Setting fake authorization user to: ", DEV_USER_ID); + setAuthHeader({ key: "user_id", value: DEV_USER_ID }); + } else { + // Fetch token for authenticated users in production + const token = await AsyncStorage.getItem("token"); // get from not firebase auth ASYNC + if (token) { + console.log("Setting firebase auth token"); + setAuthHeader({ key: "Authorization", value: `Bearer ${token}` }); + } + } + }; + + setAuthAsync(); }, [setAuthHeader]); return null; diff --git a/auth/firebase-auth.tsx b/auth/firebase-auth.tsx new file mode 100644 index 0000000..732b171 --- /dev/null +++ b/auth/firebase-auth.tsx @@ -0,0 +1,53 @@ +import AsyncStorage from "@react-native-async-storage/async-storage"; +import auth, { FirebaseAuthTypes } from "@react-native-firebase/auth"; +import { Alert } from "react-native"; + +export const handleSignInWithPhoneNumber = async ( + phoneNumber: string, +): Promise => { + if (!phoneNumber) { + Alert.alert("Please enter a valid phone number with a country code"); + return; + } + try { + const confirmation = await auth().signInWithPhoneNumber(phoneNumber); + return confirmation; + } catch (err) { + console.warn(err); + Alert.alert( + "There was an error. Make sure you are using a country code (ex: +1 for US)", + ); + } +}; + +export const confirmCode = async ( + confirm: FirebaseAuthTypes.ConfirmationResult, + code: string, +): Promise => { + try { + await confirm.confirm(code); + } catch { + Alert.alert("Invalid code, please try again."); + } +}; + +export const onAuthStateChanged = ( + // TODO: eslint not detecting ts? + // eslint-disable-next-line no-unused-vars + callback: (user: FirebaseAuthTypes.User | null) => void, +) => { + return auth().onAuthStateChanged(callback); +}; + +export const getCurrentUserToken = async (): Promise => { + const user = auth().currentUser; + if (user) { + return await user.getIdToken(); + } + return null; +}; + +export const handleSignOut = async (): Promise => { + await AsyncStorage.removeItem("token"); + await auth().signOut(); +}; diff --git a/auth/index.ts b/auth/index.ts new file mode 100644 index 0000000..89b62ac --- /dev/null +++ b/auth/index.ts @@ -0,0 +1,15 @@ +import { + confirmCode, + getCurrentUserToken, + handleSignInWithPhoneNumber, + handleSignOut, + onAuthStateChanged, +} from "./firebase-auth"; + +export { + confirmCode, + getCurrentUserToken, + handleSignInWithPhoneNumber, + handleSignOut, + onAuthStateChanged, +}; diff --git a/component/buttons/sign-out.tsx b/component/buttons/sign-out.tsx new file mode 100644 index 0000000..3c65bca --- /dev/null +++ b/component/buttons/sign-out.tsx @@ -0,0 +1,18 @@ +import React from "react"; +import { Button } from "react-native"; +import { handleSignOut } from "../../auth"; +import { useAuthHeader } from "../../graphql/client"; + +export default function SignOutButton(): React.JSX.Element { + const { setAuthHeader } = useAuthHeader(); + + return ( +