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 });