diff --git a/.gitignore b/.gitignore index 27a6f5d..7aadb01 100644 --- a/.gitignore +++ b/.gitignore @@ -44,4 +44,8 @@ app-example # Continuous Native Generation android/ -ios/ \ No newline at end of file +ios/ + +# Google Auth +google-services.json +GoogleService-Info.plist \ No newline at end of file diff --git a/GoogleService-Info.plist b/GoogleService-Info.plist new file mode 100644 index 0000000..f88603e --- /dev/null +++ b/GoogleService-Info.plist @@ -0,0 +1,14 @@ + + + + + CLIENT_ID + 742231570327-s21pt82lc97lc35obefgn5nrdq4m0rn6.apps.googleusercontent.com + REVERSED_CLIENT_ID + com.googleusercontent.apps.742231570327-s21pt82lc97lc35obefgn5nrdq4m0rn6 + PLIST_VERSION + 1 + BUNDLE_ID + pt.findit.clientapp + + \ No newline at end of file diff --git a/app.json b/app.json index fe9ac54..44b2937 100644 --- a/app.json +++ b/app.json @@ -15,7 +15,8 @@ "dark": "./assets/images/logos/ios-dark.png", "light": "./assets/images/logos/ios-light.png", "tinted": "./assets/images/logos/ios-tinted.png" - } + }, + "googleServicesFile": "./GoogleService-Info.plist" }, "android": { "adaptiveIcon": { @@ -53,6 +54,13 @@ { "locationAlwaysAndWhenInUsePermission": "Allow $(PRODUCT_NAME) to use your location." } + ], + "@maplibre/maplibre-react-native", + [ + "@react-native-google-signin/google-signin", + { + "iosUrlScheme": "com.googleusercontent.apps.742231570327-s21pt82lc97lc35obefgn5nrdq4m0rn6" + } ] ], "experiments": { @@ -74,4 +82,4 @@ "url": "https://u.expo.dev/0bab4576-b4ae-4290-9835-f6e61e1b2bf8" } } -} \ No newline at end of file +} diff --git a/bun.lock b/bun.lock index 9ed39c3..f9f818c 100644 --- a/bun.lock +++ b/bun.lock @@ -15,6 +15,7 @@ "@graphql-typed-document-node/core": "~3.2.0", "@legendapp/list": "^1.0.10", "@maplibre/maplibre-react-native": "~10.1.4", + "@react-native-google-signin/google-signin": "^14.0.1", "@react-native-masked-view/masked-view": "~0.3.2", "@react-native-picker/picker": "^2.11.0", "@react-navigation/bottom-tabs": "~7.2.0", @@ -681,6 +682,8 @@ "@radix-ui/react-slot": ["@radix-ui/react-slot@1.0.1", "", { "dependencies": { "@babel/runtime": "^7.13.10", "@radix-ui/react-compose-refs": "1.0.0" }, "peerDependencies": { "react": "^16.8 || ^17.0 || ^18.0" } }, "sha512-avutXAFL1ehGvAXtPquu0YK5oz6ctS474iM3vNGQIkswrVhdrS52e3uoMQBzZhNRAIE0jBnUyXWNmSjGHhCFcw=="], + "@react-native-google-signin/google-signin": ["@react-native-google-signin/google-signin@14.0.1", "", { "peerDependencies": { "expo": ">=52.0.40", "react": "*", "react-dom": "*", "react-native": "*" }, "optionalPeers": ["expo", "react-dom"] }, "sha512-2f903eaHiv/Ob96vsWZitz+Z0k2J2W0/C7Ygrr6ejAT2JVzJCatmjF/eq62MWhuTNdU2WDX/oePxMbpQW6k2UA=="], + "@react-native-masked-view/masked-view": ["@react-native-masked-view/masked-view@0.3.2", "", { "peerDependencies": { "react": ">=16", "react-native": ">=0.57" } }, "sha512-XwuQoW7/GEgWRMovOQtX3A4PrXhyaZm0lVUiY8qJDvdngjLms9Cpdck6SmGAUNqQwcj2EadHC1HwL0bEyoa/SQ=="], "@react-native-picker/picker": ["@react-native-picker/picker@2.11.0", "", { "peerDependencies": { "react": "*", "react-native": "*" } }, "sha512-QuZU6gbxmOID5zZgd/H90NgBnbJ3VV6qVzp6c7/dDrmWdX8S0X5YFYgDcQFjE3dRen9wB9FWnj2VVdPU64adSg=="], diff --git a/components/LoginBottomSheet.tsx b/components/LoginBottomSheet.tsx index 7b98628..057232a 100644 --- a/components/LoginBottomSheet.tsx +++ b/components/LoginBottomSheet.tsx @@ -1,21 +1,20 @@ import { GradientPill } from "@/components/GradientPill"; import Background from "@/components/Background"; import BottomSheet, { BottomSheetView } from "@gorhom/bottom-sheet"; -import { Platform, View } from "react-native"; +import { View } from "react-native"; import { ThemedText } from "@/components/ThemedText"; import { Button } from "@/components/Button"; -import AppleIcon from "@/assets/images/brands/apple.svg"; import GoogleIcon from "@/assets/images/brands/google.svg"; -import React, { useRef } from "react"; +import React, { useEffect, useRef } from "react"; import { useSafeAreaInsets } from "react-native-safe-area-context"; import { useBackground } from "@/hooks/useBackground"; import { Redirect, useRouter } from "expo-router"; import { SharedValue } from "react-native-reanimated"; import { gql } from "@/graphql"; -import { FetchResult, useMutation } from "@apollo/client"; -import { UpsertUserMutation } from "@/graphql/graphql"; +import { useMutation } from "@apollo/client"; import { useToast } from "@/hooks/useToast"; import { useAuth } from "@/hooks/useAuth"; +import { GoogleSignin } from "@react-native-google-signin/google-signin"; interface LoginBottomSheetProps { animatedPosition: SharedValue; @@ -24,7 +23,7 @@ interface LoginBottomSheetProps { interface LoginMethod { name: string; icon: React.ComponentProps["Icon"]; - onPress: () => Promise>; + onPress: () => Promise; type: "primary" | "secondary"; } @@ -46,16 +45,11 @@ export const LoginBottomSheet = ({ const { id, setId } = useAuth(); const { toast, toastOnError } = useToast(); + useEffect(() => { + GoogleSignin.configure({}); + }, []); + const [upsertUser, { loading }] = useMutation(UPSERT_USER, { - variables: { - // Temporary user data - model: { - birth_date: "2003-11-08", - email: "matilde@findit-app.pt", - first_name: "Matilde", - last_name: "Silva", - }, - }, onCompleted: async (data) => { if (!data.upsertUser) { toast({ @@ -71,22 +65,40 @@ export const LoginBottomSheet = ({ onError: toastOnError, }); + const signIn = async () => { + try { + const signInResponse = await GoogleSignin.signIn(); + const userInfo = signInResponse.data?.user; + if (signInResponse.type === "success") { + await upsertUser({ + variables: { + model: { + email: userInfo?.email ?? "", + first_name: userInfo?.givenName ?? "", + last_name: userInfo?.familyName ?? "", + birth_date: "", + }, + }, + }); + } else if (signInResponse.type === "cancelled" || !userInfo) { + toast({ title: "Sign in cancelled", text: "Please try again." }); + return; + } + } catch (error) { + toast({ title: "Error signing in", text: error as string }); + } + }; + if (id) { return ; } const methods: LoginMethod[] = [ - { - name: "Apple", - icon: AppleIcon, - onPress: async () => await upsertUser(), - type: Platform.OS === "ios" ? "primary" : "secondary", - }, { name: "Google", icon: GoogleIcon, - onPress: async () => await upsertUser(), - type: Platform.OS === "android" ? "primary" : "secondary", + onPress: async () => await signIn(), + type: "primary", }, ]; @@ -108,12 +120,7 @@ export const LoginBottomSheet = ({ by logging in. - + {methods.map((method) => (