@umituz/react-native-auth 3.1.11 → 3.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@umituz/react-native-auth",
3
- "version": "3.1.11",
3
+ "version": "3.2.1",
4
4
  "description": "Authentication service for React Native apps - Secure, type-safe, and production-ready. Provider-agnostic design with dependency injection, configurable validation, and comprehensive error handling.",
5
5
  "main": "./src/index.ts",
6
6
  "types": "./src/index.ts",
@@ -43,7 +43,9 @@
43
43
  "@umituz/react-native-storage": "*",
44
44
  "@umituz/react-native-tanstack": "*",
45
45
  "@umituz/react-native-validation": "*",
46
+ "expo-auth-session": ">=5.0.0",
46
47
  "expo-linear-gradient": ">=13.0.0",
48
+ "expo-web-browser": ">=12.0.0",
47
49
  "firebase": ">=11.0.0",
48
50
  "react": ">=18.2.0",
49
51
  "react-native": ">=0.74.0",
@@ -59,8 +61,8 @@
59
61
  "@react-native-async-storage/async-storage": "^1.24.0",
60
62
  "@react-native-community/datetimepicker": "^8.5.1",
61
63
  "@react-navigation/bottom-tabs": "^7.9.0",
62
- "@react-navigation/native": "^6.0.0",
63
- "@react-navigation/stack": "^6.0.0",
64
+ "@react-navigation/native": "^7.1.26",
65
+ "@react-navigation/stack": "^7.6.13",
64
66
  "@sentry/react-native": "^7.8.0",
65
67
  "@sentry/types": "^10.32.1",
66
68
  "@tanstack/react-query": "^5.0.0",
@@ -69,15 +71,15 @@
69
71
  "@typescript-eslint/eslint-plugin": "^7.0.0",
70
72
  "@typescript-eslint/parser": "^7.0.0",
71
73
  "@umituz/react-native-design-system": "latest",
72
- "@umituz/react-native-design-system-theme": "latest",
74
+ "@umituz/react-native-design-system-theme": "*",
73
75
  "@umituz/react-native-firebase": "^1.13.27",
74
- "@umituz/react-native-haptics": "latest",
75
- "@umituz/react-native-localization": "latest",
76
- "@umituz/react-native-sentry": "latest",
77
- "@umituz/react-native-storage": "latest",
78
- "@umituz/react-native-tanstack": "latest",
79
- "@umituz/react-native-uuid": "latest",
80
- "@umituz/react-native-validation": "latest",
76
+ "@umituz/react-native-haptics": "*",
77
+ "@umituz/react-native-localization": "*",
78
+ "@umituz/react-native-sentry": "*",
79
+ "@umituz/react-native-storage": "*",
80
+ "@umituz/react-native-tanstack": "*",
81
+ "@umituz/react-native-uuid": "*",
82
+ "@umituz/react-native-validation": "*",
81
83
  "eslint": "^8.57.0",
82
84
  "expo-apple-authentication": "^6.0.0",
83
85
  "expo-application": "^7.0.8",
@@ -86,8 +88,10 @@
86
88
  "expo-device": "^8.0.10",
87
89
  "expo-file-system": "^19.0.21",
88
90
  "expo-haptics": "^15.0.8",
91
+ "expo-auth-session": "^5.0.0",
89
92
  "expo-linear-gradient": "^13.0.0",
90
93
  "expo-sharing": "^14.0.8",
94
+ "expo-web-browser": "^12.0.0",
91
95
  "firebase": "^11.0.0",
92
96
  "react": "~19.1.0",
93
97
  "react-native": "~0.81.5",
package/src/index.ts CHANGED
@@ -135,6 +135,15 @@ export type { UseProfileUpdateReturn } from './presentation/hooks/useProfileUpda
135
135
  export { useProfileEdit } from './presentation/hooks/useProfileEdit';
136
136
  export type { UseProfileEditReturn, ProfileEditFormState } from './presentation/hooks/useProfileEdit';
137
137
 
138
+ export { useSocialLogin } from './presentation/hooks/useSocialLogin';
139
+ export type { UseSocialLoginConfig, UseSocialLoginResult } from './presentation/hooks/useSocialLogin';
140
+
141
+ export { useGoogleAuth } from './presentation/hooks/useGoogleAuth';
142
+ export type { UseGoogleAuthResult, GoogleAuthConfig as GoogleAuthHookConfig } from './presentation/hooks/useGoogleAuth';
143
+
144
+ export { useAppleAuth } from './presentation/hooks/useAppleAuth';
145
+ export type { UseAppleAuthResult } from './presentation/hooks/useAppleAuth';
146
+
138
147
  export type { UserProfile, UpdateProfileParams } from './domain/entities/UserProfile';
139
148
 
140
149
  // Domain Utils - Guest Names
@@ -175,6 +184,11 @@ export { PasswordMatchIndicator } from './presentation/components/PasswordMatchI
175
184
  export type { PasswordMatchIndicatorProps } from './presentation/components/PasswordMatchIndicator';
176
185
  export { AuthBottomSheet } from './presentation/components/AuthBottomSheet';
177
186
  export type { AuthBottomSheetProps } from './presentation/components/AuthBottomSheet';
187
+ export { AuthBottomSheetWrapper } from './presentation/components/AuthBottomSheetWrapper';
188
+ export type {
189
+ AuthBottomSheetWrapperProps,
190
+ SocialAuthConfiguration,
191
+ } from './presentation/components/AuthBottomSheetWrapper';
178
192
  export { SocialLoginButtons } from './presentation/components/SocialLoginButtons';
179
193
  export type { SocialLoginButtonsProps } from './presentation/components/SocialLoginButtons';
180
194
  export { ProfileSection } from './presentation/components/ProfileSection';
@@ -0,0 +1,115 @@
1
+ /**
2
+ * AuthBottomSheetWrapper Component
3
+ * Self-contained auth modal with integrated social login
4
+ *
5
+ * This wrapper component combines AuthBottomSheet with social auth hooks,
6
+ * providing a complete authentication solution for apps.
7
+ *
8
+ * Usage:
9
+ * ```tsx
10
+ * <AuthBottomSheetWrapper
11
+ * termsUrl="https://myapp.com/terms"
12
+ * privacyUrl="https://myapp.com/privacy"
13
+ * socialConfig={{
14
+ * google: { webClientId: '...', iosClientId: '...' },
15
+ * apple: { enabled: true }
16
+ * }}
17
+ * />
18
+ * ```
19
+ */
20
+
21
+ import React, { useCallback, useMemo } from "react";
22
+ import { Platform } from "react-native";
23
+ import { AuthBottomSheet } from "./AuthBottomSheet";
24
+ import { useGoogleAuth, type GoogleAuthConfig } from "../hooks/useGoogleAuth";
25
+ import { useAppleAuth } from "../hooks/useAppleAuth";
26
+ import type { SocialAuthProvider } from "../../domain/value-objects/AuthConfig";
27
+
28
+ declare const __DEV__: boolean;
29
+
30
+ export interface SocialAuthConfiguration {
31
+ google?: GoogleAuthConfig;
32
+ apple?: { enabled: boolean };
33
+ }
34
+
35
+ export interface AuthBottomSheetWrapperProps {
36
+ /** Terms of Service URL */
37
+ termsUrl?: string;
38
+ /** Privacy Policy URL */
39
+ privacyUrl?: string;
40
+ /** Called when Terms link is pressed (overrides default behavior) */
41
+ onTermsPress?: () => void;
42
+ /** Called when Privacy link is pressed (overrides default behavior) */
43
+ onPrivacyPress?: () => void;
44
+ /** Social auth configuration */
45
+ socialConfig?: SocialAuthConfiguration;
46
+ }
47
+
48
+ /**
49
+ * Self-contained auth bottom sheet with integrated social login
50
+ */
51
+ export const AuthBottomSheetWrapper: React.FC<AuthBottomSheetWrapperProps> = ({
52
+ termsUrl,
53
+ privacyUrl,
54
+ onTermsPress,
55
+ onPrivacyPress,
56
+ socialConfig,
57
+ }) => {
58
+ const { signInWithGoogle, googleConfigured } = useGoogleAuth(socialConfig?.google);
59
+ const { signInWithApple, appleAvailable } = useAppleAuth();
60
+
61
+ const providers = useMemo<SocialAuthProvider[]>(() => {
62
+ const result: SocialAuthProvider[] = [];
63
+
64
+ if (Platform.OS === "ios" && socialConfig?.apple?.enabled && appleAvailable) {
65
+ result.push("apple");
66
+ }
67
+
68
+ if (googleConfigured) {
69
+ result.push("google");
70
+ }
71
+
72
+ if (__DEV__) {
73
+ // eslint-disable-next-line no-console
74
+ console.log("[AuthBottomSheetWrapper] Enabled providers:", result);
75
+ }
76
+
77
+ return result;
78
+ }, [socialConfig?.apple?.enabled, appleAvailable, googleConfigured]);
79
+
80
+ const handleGoogleSignIn = useCallback(async () => {
81
+ if (__DEV__) {
82
+ // eslint-disable-next-line no-console
83
+ console.log("[AuthBottomSheetWrapper] Google sign-in requested");
84
+ }
85
+ const result = await signInWithGoogle();
86
+ if (__DEV__) {
87
+ // eslint-disable-next-line no-console
88
+ console.log("[AuthBottomSheetWrapper] Google result:", result);
89
+ }
90
+ }, [signInWithGoogle]);
91
+
92
+ const handleAppleSignIn = useCallback(async () => {
93
+ if (__DEV__) {
94
+ // eslint-disable-next-line no-console
95
+ console.log("[AuthBottomSheetWrapper] Apple sign-in requested");
96
+ }
97
+ const result = await signInWithApple();
98
+ if (__DEV__) {
99
+ // eslint-disable-next-line no-console
100
+ console.log("[AuthBottomSheetWrapper] Apple result:", result);
101
+ }
102
+ }, [signInWithApple]);
103
+
104
+ return (
105
+ <AuthBottomSheet
106
+ termsUrl={termsUrl}
107
+ privacyUrl={privacyUrl}
108
+ onTermsPress={onTermsPress}
109
+ onPrivacyPress={onPrivacyPress}
110
+ socialProviders={providers}
111
+ onGoogleSignIn={handleGoogleSignIn}
112
+ onAppleSignIn={handleAppleSignIn}
113
+ />
114
+ );
115
+ };
@@ -5,11 +5,11 @@
5
5
 
6
6
  import React from "react";
7
7
  import { View, StyleSheet } from "react-native";
8
- import { AtomicText, useResponsiveDesignTokens } from "@umituz/react-native-design-system";
8
+ import { AtomicText, useAppDesignTokens } from "@umituz/react-native-design-system";
9
9
  import { useLocalization } from "@umituz/react-native-localization";
10
10
 
11
11
  export const AuthDivider: React.FC = () => {
12
- const tokens = useResponsiveDesignTokens();
12
+ const tokens = useAppDesignTokens();
13
13
  const { t } = useLocalization();
14
14
 
15
15
  return (
@@ -27,7 +27,6 @@ export const AuthDivider: React.FC = () => {
27
27
  textTransform: "uppercase",
28
28
  letterSpacing: 0.5,
29
29
  }}
30
- responsive
31
30
  >
32
31
  {t("general.or")}
33
32
  </AtomicText>
@@ -5,14 +5,14 @@
5
5
 
6
6
  import React from "react";
7
7
  import { View, StyleSheet } from "react-native";
8
- import { useResponsiveDesignTokens } from "@umituz/react-native-design-system";
8
+ import { useAppDesignTokens } from "@umituz/react-native-design-system";
9
9
 
10
10
  interface AuthFormCardProps {
11
11
  children: React.ReactNode;
12
12
  }
13
13
 
14
14
  export const AuthFormCard: React.FC<AuthFormCardProps> = ({ children }) => {
15
- const tokens = useResponsiveDesignTokens();
15
+ const tokens = useAppDesignTokens();
16
16
 
17
17
  return (
18
18
  <View
@@ -5,7 +5,7 @@
5
5
 
6
6
  import React from "react";
7
7
  import { View, StyleSheet } from "react-native";
8
- import { AtomicText, useResponsiveDesignTokens } from "@umituz/react-native-design-system";
8
+ import { AtomicText, useAppDesignTokens } from "@umituz/react-native-design-system";
9
9
  import { useLocalization } from "@umituz/react-native-localization";
10
10
 
11
11
  interface AuthHeaderProps {
@@ -14,7 +14,7 @@ interface AuthHeaderProps {
14
14
  }
15
15
 
16
16
  export const AuthHeader: React.FC<AuthHeaderProps> = ({ title, subtitle }) => {
17
- const tokens = useResponsiveDesignTokens();
17
+ const tokens = useAppDesignTokens();
18
18
  const { t } = useLocalization();
19
19
 
20
20
  return (
@@ -22,7 +22,6 @@ export const AuthHeader: React.FC<AuthHeaderProps> = ({ title, subtitle }) => {
22
22
  <AtomicText
23
23
  type="headlineLarge"
24
24
  style={{ color: tokens.colors.onPrimary, textAlign: "center" }}
25
- responsive
26
25
  >
27
26
  {title}
28
27
  </AtomicText>
@@ -34,7 +33,6 @@ export const AuthHeader: React.FC<AuthHeaderProps> = ({ title, subtitle }) => {
34
33
  textAlign: "center",
35
34
  marginTop: tokens.spacing.xs,
36
35
  }}
37
- responsive
38
36
  >
39
37
  {subtitle || t("auth.subtitle")}
40
38
  </AtomicText>
@@ -5,7 +5,7 @@
5
5
 
6
6
  import React from "react";
7
7
  import { View, StyleSheet } from "react-native";
8
- import { AtomicText, AtomicButton, useResponsiveDesignTokens } from "@umituz/react-native-design-system";
8
+ import { AtomicText, AtomicButton, useAppDesignTokens } from "@umituz/react-native-design-system";
9
9
 
10
10
  interface AuthLinkProps {
11
11
  text: string;
@@ -20,14 +20,13 @@ export const AuthLink: React.FC<AuthLinkProps> = ({
20
20
  onPress,
21
21
  disabled = false,
22
22
  }) => {
23
- const tokens = useResponsiveDesignTokens();
23
+ const tokens = useAppDesignTokens();
24
24
 
25
25
  return (
26
26
  <View style={[styles.container, { marginTop: tokens.spacing.xs, paddingTop: tokens.spacing.xs }]}>
27
27
  <AtomicText
28
28
  type="bodyMedium"
29
29
  style={{ color: tokens.colors.textSecondary }}
30
- responsive
31
30
  >
32
31
  {text}{" "}
33
32
  </AtomicText>
@@ -0,0 +1,61 @@
1
+ /**
2
+ * useAppleAuth Hook
3
+ * Handles Apple Sign-In using Firebase auth
4
+ *
5
+ * This is a convenience wrapper around useSocialAuth from Firebase package
6
+ * specifically for Apple authentication.
7
+ */
8
+
9
+ import { useCallback } from "react";
10
+ import { Platform } from "react-native";
11
+ import {
12
+ useSocialAuth,
13
+ type SocialAuthResult,
14
+ } from "@umituz/react-native-firebase";
15
+
16
+ declare const __DEV__: boolean;
17
+
18
+ export interface UseAppleAuthResult {
19
+ signInWithApple: () => Promise<SocialAuthResult>;
20
+ appleLoading: boolean;
21
+ appleAvailable: boolean;
22
+ }
23
+
24
+ /**
25
+ * Hook for Apple authentication
26
+ */
27
+ export function useAppleAuth(): UseAppleAuthResult {
28
+ const { signInWithApple, appleLoading, appleAvailable } = useSocialAuth({
29
+ apple: { enabled: Platform.OS === "ios" },
30
+ });
31
+
32
+ const handleSignInWithApple = useCallback(async (): Promise<SocialAuthResult> => {
33
+ if (Platform.OS !== "ios") {
34
+ return { success: false, error: "Apple Sign-In is only available on iOS" };
35
+ }
36
+
37
+ if (!appleAvailable) {
38
+ return { success: false, error: "Apple Sign-In is not available" };
39
+ }
40
+
41
+ if (__DEV__) {
42
+ // eslint-disable-next-line no-console
43
+ console.log("[useAppleAuth] Apple sign-in requested");
44
+ }
45
+
46
+ const result = await signInWithApple();
47
+
48
+ if (__DEV__) {
49
+ // eslint-disable-next-line no-console
50
+ console.log("[useAppleAuth] Apple sign-in result:", result);
51
+ }
52
+
53
+ return result;
54
+ }, [appleAvailable, signInWithApple]);
55
+
56
+ return {
57
+ signInWithApple: handleSignInWithApple,
58
+ appleLoading,
59
+ appleAvailable,
60
+ };
61
+ }
@@ -0,0 +1,184 @@
1
+ /**
2
+ * useGoogleAuth Hook
3
+ * Handles Google OAuth flow using expo-auth-session and Firebase auth
4
+ *
5
+ * This hook provides complete Google sign-in flow:
6
+ * 1. OAuth flow via expo-auth-session
7
+ * 2. Firebase authentication with the obtained token
8
+ */
9
+
10
+ import { useState, useCallback, useEffect } from "react";
11
+ import {
12
+ useSocialAuth,
13
+ type SocialAuthConfig,
14
+ type SocialAuthResult,
15
+ } from "@umituz/react-native-firebase";
16
+
17
+ declare const __DEV__: boolean;
18
+
19
+ // Type declarations for expo-auth-session
20
+ interface GoogleAuthRequestConfig {
21
+ iosClientId: string;
22
+ webClientId: string;
23
+ androidClientId: string;
24
+ }
25
+
26
+ interface AuthSessionAuthentication {
27
+ idToken?: string;
28
+ accessToken?: string;
29
+ }
30
+
31
+ interface AuthSessionResult {
32
+ type: "success" | "cancel" | "dismiss" | "error" | "locked";
33
+ authentication?: AuthSessionAuthentication;
34
+ }
35
+
36
+ interface AuthRequest {
37
+ promptAsync: () => Promise<AuthSessionResult>;
38
+ }
39
+
40
+ type UseAuthRequestReturn = [
41
+ AuthRequest | null,
42
+ AuthSessionResult | null,
43
+ () => Promise<AuthSessionResult>,
44
+ ];
45
+
46
+ // Dynamic imports to handle optional dependencies
47
+ type GoogleModule = { useAuthRequest: (config: GoogleAuthRequestConfig) => UseAuthRequestReturn };
48
+ type WebBrowserModule = { maybeCompleteAuthSession: () => void };
49
+
50
+ let Google: GoogleModule | null = null;
51
+ let WebBrowser: WebBrowserModule | null = null;
52
+
53
+ try {
54
+ // eslint-disable-next-line @typescript-eslint/no-require-imports, @typescript-eslint/no-var-requires
55
+ Google = require("expo-auth-session/providers/google") as GoogleModule;
56
+ // eslint-disable-next-line @typescript-eslint/no-require-imports, @typescript-eslint/no-var-requires
57
+ WebBrowser = require("expo-web-browser") as WebBrowserModule;
58
+ if (WebBrowser) {
59
+ WebBrowser.maybeCompleteAuthSession();
60
+ }
61
+ } catch {
62
+ // expo-auth-session not available
63
+ if (__DEV__) {
64
+ // eslint-disable-next-line no-console
65
+ console.log("[useGoogleAuth] expo-auth-session not available");
66
+ }
67
+ }
68
+
69
+ export interface GoogleAuthConfig {
70
+ iosClientId?: string;
71
+ webClientId?: string;
72
+ androidClientId?: string;
73
+ }
74
+
75
+ export interface UseGoogleAuthResult {
76
+ signInWithGoogle: () => Promise<SocialAuthResult>;
77
+ googleLoading: boolean;
78
+ googleConfigured: boolean;
79
+ }
80
+
81
+ const PLACEHOLDER_CLIENT_ID = "000000000000-placeholder.apps.googleusercontent.com";
82
+
83
+ /**
84
+ * Hook for Google authentication with expo-auth-session
85
+ */
86
+ export function useGoogleAuth(config?: GoogleAuthConfig): UseGoogleAuthResult {
87
+ const [isLoading, setIsLoading] = useState(false);
88
+
89
+ const googleConfigured = !!(
90
+ config?.iosClientId ||
91
+ config?.webClientId ||
92
+ config?.androidClientId
93
+ );
94
+
95
+ const socialAuthConfig: SocialAuthConfig = {
96
+ google: config,
97
+ apple: { enabled: false },
98
+ };
99
+
100
+ const { signInWithGoogleToken, googleLoading: firebaseLoading } =
101
+ useSocialAuth(socialAuthConfig);
102
+
103
+ // Use Google auth request if available
104
+ const authRequest = Google?.useAuthRequest({
105
+ iosClientId: config?.iosClientId || PLACEHOLDER_CLIENT_ID,
106
+ webClientId: config?.webClientId || PLACEHOLDER_CLIENT_ID,
107
+ androidClientId: config?.androidClientId || PLACEHOLDER_CLIENT_ID,
108
+ });
109
+
110
+ const request = authRequest?.[0] ?? null;
111
+ const googleResponse = authRequest?.[1] ?? null;
112
+ const promptGoogleAsync = authRequest?.[2];
113
+
114
+ // Handle Google OAuth response
115
+ useEffect(() => {
116
+ if (googleResponse?.type === "success") {
117
+ const idToken = googleResponse.authentication?.idToken;
118
+ if (idToken) {
119
+ setIsLoading(true);
120
+ signInWithGoogleToken(idToken)
121
+ .catch((error: unknown) => {
122
+ if (__DEV__) {
123
+ // eslint-disable-next-line no-console
124
+ console.error("[useGoogleAuth] Firebase sign-in error:", error);
125
+ }
126
+ })
127
+ .finally(() => {
128
+ setIsLoading(false);
129
+ });
130
+ }
131
+ }
132
+ }, [googleResponse, signInWithGoogleToken]);
133
+
134
+ const signInWithGoogle = useCallback(async (): Promise<SocialAuthResult> => {
135
+ if (!Google || !promptGoogleAsync) {
136
+ return { success: false, error: "expo-auth-session is not available" };
137
+ }
138
+
139
+ if (!googleConfigured) {
140
+ return { success: false, error: "Google Sign-In is not configured" };
141
+ }
142
+
143
+ if (!request) {
144
+ return { success: false, error: "Google Sign-In not ready" };
145
+ }
146
+
147
+ setIsLoading(true);
148
+ try {
149
+ const result = await promptGoogleAsync();
150
+
151
+ if (result.type === "success" && result.authentication?.idToken) {
152
+ const firebaseResult = await signInWithGoogleToken(
153
+ result.authentication.idToken,
154
+ );
155
+
156
+ if (__DEV__) {
157
+ // eslint-disable-next-line no-console
158
+ console.log("[useGoogleAuth] Sign-in successful:", firebaseResult);
159
+ }
160
+
161
+ return firebaseResult;
162
+ }
163
+
164
+ if (result.type === "cancel") {
165
+ return { success: false, error: "Google Sign-In was cancelled" };
166
+ }
167
+
168
+ return { success: false, error: "Google Sign-In failed" };
169
+ } catch (error) {
170
+ return {
171
+ success: false,
172
+ error: error instanceof Error ? error.message : "Google sign-in failed",
173
+ };
174
+ } finally {
175
+ setIsLoading(false);
176
+ }
177
+ }, [googleConfigured, request, promptGoogleAsync, signInWithGoogleToken]);
178
+
179
+ return {
180
+ signInWithGoogle,
181
+ googleLoading: isLoading || firebaseLoading,
182
+ googleConfigured,
183
+ };
184
+ }
@@ -0,0 +1,115 @@
1
+ /**
2
+ * useSocialLogin Hook
3
+ * Provides unified social login functionality using Firebase package
4
+ *
5
+ * This hook wraps @umituz/react-native-firebase's useSocialAuth
6
+ * and provides a simple interface for social authentication.
7
+ *
8
+ * Usage:
9
+ * ```typescript
10
+ * const { signInWithGoogle, signInWithApple, googleLoading, appleLoading } = useSocialLogin({
11
+ * google: { webClientId: '...', iosClientId: '...' },
12
+ * apple: { enabled: true }
13
+ * });
14
+ * ```
15
+ */
16
+
17
+ import { useCallback } from "react";
18
+ import { Platform } from "react-native";
19
+ import {
20
+ useSocialAuth,
21
+ type SocialAuthConfig,
22
+ type SocialAuthResult,
23
+ } from "@umituz/react-native-firebase";
24
+
25
+ declare const __DEV__: boolean;
26
+
27
+ export interface UseSocialLoginConfig extends SocialAuthConfig {}
28
+
29
+ export interface UseSocialLoginResult {
30
+ /** Sign in with Google (handles OAuth flow internally if configured) */
31
+ signInWithGoogle: () => Promise<SocialAuthResult>;
32
+ /** Sign in with Apple */
33
+ signInWithApple: () => Promise<SocialAuthResult>;
34
+ /** Whether Google sign-in is in progress */
35
+ googleLoading: boolean;
36
+ /** Whether Apple sign-in is in progress */
37
+ appleLoading: boolean;
38
+ /** Whether Google is configured */
39
+ googleConfigured: boolean;
40
+ /** Whether Apple is available */
41
+ appleAvailable: boolean;
42
+ }
43
+
44
+ /**
45
+ * Hook for social authentication
46
+ * Integrates with @umituz/react-native-firebase for Firebase auth
47
+ */
48
+ export function useSocialLogin(config?: UseSocialLoginConfig): UseSocialLoginResult {
49
+ const {
50
+ signInWithApple: firebaseSignInWithApple,
51
+ googleLoading,
52
+ appleLoading,
53
+ googleConfigured,
54
+ appleAvailable,
55
+ } = useSocialAuth(config);
56
+
57
+ /**
58
+ * Sign in with Google
59
+ * Note: For full OAuth flow, use useGoogleAuth hook which handles
60
+ * expo-auth-session OAuth flow and Firebase authentication
61
+ */
62
+ const signInWithGoogle = useCallback((): Promise<SocialAuthResult> => {
63
+ if (!googleConfigured) {
64
+ return Promise.resolve({ success: false, error: "Google Sign-In is not configured" });
65
+ }
66
+
67
+ if (__DEV__) {
68
+ // eslint-disable-next-line no-console
69
+ console.log("[useSocialLogin] Use useGoogleAuth hook for Google OAuth flow");
70
+ }
71
+
72
+ return Promise.resolve({
73
+ success: false,
74
+ error: "Use useGoogleAuth hook for Google OAuth flow",
75
+ });
76
+ }, [googleConfigured]);
77
+
78
+ /**
79
+ * Sign in with Apple (full flow handled by Firebase package)
80
+ */
81
+ const signInWithApple = useCallback(async (): Promise<SocialAuthResult> => {
82
+ if (Platform.OS !== "ios") {
83
+ return { success: false, error: "Apple Sign-In is only available on iOS" };
84
+ }
85
+
86
+ if (!appleAvailable) {
87
+ return { success: false, error: "Apple Sign-In is not available" };
88
+ }
89
+
90
+ if (__DEV__) {
91
+ // eslint-disable-next-line no-console
92
+ console.log("[useSocialLogin] Apple sign-in requested");
93
+ }
94
+
95
+ const result = await firebaseSignInWithApple();
96
+
97
+ if (__DEV__) {
98
+ // eslint-disable-next-line no-console
99
+ console.log("[useSocialLogin] Apple sign-in result:", result);
100
+ }
101
+
102
+ return result;
103
+ }, [appleAvailable, firebaseSignInWithApple]);
104
+
105
+ return {
106
+ signInWithGoogle,
107
+ signInWithApple,
108
+ googleLoading,
109
+ appleLoading,
110
+ googleConfigured,
111
+ appleAvailable,
112
+ };
113
+ }
114
+
115
+ export { type SocialAuthConfig, type SocialAuthResult };