diff --git a/xtablo-expo/app.json b/xtablo-expo/app.json index 5c42203..f7c725e 100644 --- a/xtablo-expo/app.json +++ b/xtablo-expo/app.json @@ -9,6 +9,7 @@ "userInterfaceStyle": "automatic", "newArchEnabled": true, "ios": { + "usesAppleSignIn": true, "supportsTablet": true, "bundleIdentifier": "com.xtablo.app", "infoPlist": { @@ -38,7 +39,8 @@ "backgroundColor": "#ffffff" } ], - "expo-secure-store" + "expo-secure-store", + "expo-apple-authentication" ], "experiments": { "typedRoutes": true diff --git a/xtablo-expo/app/_layout.tsx b/xtablo-expo/app/_layout.tsx index b28c3db..67be6eb 100644 --- a/xtablo-expo/app/_layout.tsx +++ b/xtablo-expo/app/_layout.tsx @@ -66,9 +66,6 @@ export default function RootLayout() { const RootNavigator = () => { const { isLoading, isLoggedIn } = useInitializeApp(); - console.log("isLoading", isLoading); - console.log("isLoggedIn", isLoggedIn); - if (isLoading) { return ; } diff --git a/xtablo-expo/app/login.tsx b/xtablo-expo/app/login.tsx index 22a9e3d..0f8f6b0 100644 --- a/xtablo-expo/app/login.tsx +++ b/xtablo-expo/app/login.tsx @@ -5,6 +5,7 @@ import { Text, Image, ImageSourcePropType, + Platform, } from "react-native"; import { Button, Input } from "@rn-vui/themed"; import { useAuthStore } from "@/stores/auth"; @@ -22,6 +23,7 @@ export default function Auth() { const login = useAuthStore((state) => state.login); const authLoading = useAuthStore((state) => state.loading); const performOAuth = useAuthStore((state) => state.performOAuth); + const signInWithApple = useAuthStore((state) => state.signInWithApple); // Theme-aware colors const backgroundColor = useThemeColor( @@ -93,9 +95,12 @@ export default function Auth() { performOAuth("google")} /> - - performOAuth("apple")} /> - + + {Platform.OS === "ios" && ( + + signInWithApple()} /> + + )} Pas encore de compte ?{" "} diff --git a/xtablo-expo/package-lock.json b/xtablo-expo/package-lock.json index f46803a..2666973 100644 --- a/xtablo-expo/package-lock.json +++ b/xtablo-expo/package-lock.json @@ -18,6 +18,7 @@ "@tanstack/react-query": "^5.75.2", "aes-js": "^3.1.2", "expo": "^53.0.19", + "expo-apple-authentication": "~7.2.4", "expo-auth-session": "~6.2.1", "expo-av": "~15.1.7", "expo-blur": "~14.1.5", @@ -5704,6 +5705,15 @@ } } }, + "node_modules/expo-apple-authentication": { + "version": "7.2.4", + "resolved": "https://registry.npmjs.org/expo-apple-authentication/-/expo-apple-authentication-7.2.4.tgz", + "integrity": "sha512-T2agaLLPT4Ax97FeXImB7BCCEzEJ0gB+ZwlFa/FXBtbp6WFKcGRlTVKiX2YPYLZzN5QjXcmQ9HHJ17jRthNHMg==", + "peerDependencies": { + "expo": "*", + "react-native": "*" + } + }, "node_modules/expo-application": { "version": "6.1.5", "resolved": "https://registry.npmjs.org/expo-application/-/expo-application-6.1.5.tgz", diff --git a/xtablo-expo/package.json b/xtablo-expo/package.json index 77cd438..6a4199b 100644 --- a/xtablo-expo/package.json +++ b/xtablo-expo/package.json @@ -59,7 +59,8 @@ "react-native-webview": "13.13.5", "stream-chat-expo": "^6.7.3", "zustand": "^5.0.4", - "expo-dev-client": "~5.2.4" + "expo-dev-client": "~5.2.4", + "expo-apple-authentication": "~7.2.4" }, "devDependencies": { "@babel/core": "^7.25.2", diff --git a/xtablo-expo/stores/auth.tsx b/xtablo-expo/stores/auth.tsx index f3239df..88646d7 100644 --- a/xtablo-expo/stores/auth.tsx +++ b/xtablo-expo/stores/auth.tsx @@ -8,6 +8,7 @@ import { Linking } from "react-native"; import { QueryClient } from "@tanstack/react-query"; import { User } from "@/types/user.types"; import { api } from "@/lib/api"; +import * as AppleAuthentication from "expo-apple-authentication"; interface AuthState { session: Session | null; @@ -25,6 +26,7 @@ interface AuthState { companyName: string ) => Promise; performOAuth: (provider: Provider) => Promise; + signInWithApple: () => Promise; signOut: () => Promise; createSessionFromUrl: (url: string) => Promise; fetchAndSetUser: (session: Session | null) => Promise; @@ -63,8 +65,6 @@ export const useAuthStore = create((set, get) => ({ }); supabase.auth.onAuthStateChange(async (event, session) => { - console.log("event", event); - console.log("session exists", !!session); set({ session, }); @@ -139,6 +139,41 @@ export const useAuthStore = create((set, get) => ({ await get().createSessionFromUrl(url); } }, + signInWithApple: async () => { + try { + const credential = await AppleAuthentication.signInAsync({ + requestedScopes: [ + AppleAuthentication.AppleAuthenticationScope.FULL_NAME, + AppleAuthentication.AppleAuthenticationScope.EMAIL, + ], + }); + + if (credential.identityToken) { + const { + error, + data: { user, session }, + } = await supabase.auth.signInWithIdToken({ + provider: "apple", + token: credential.identityToken, + }); + if (!error && user) { + const userProfile = { + id: user.id, + email: user.email ?? "", + name: user.user_metadata.name, + avatar_url: user.user_metadata.picture, + streamToken: user.user_metadata.streamToken, + }; + + await set({ user: userProfile, session }); + } + } else { + throw new Error("No identityToken."); + } + } catch (e) { + console.error("Error signing in with Apple:", e); + } + }, signOut: async () => { await supabase.auth.signOut(); set({ loading: false, user: null, session: null });