@umituz/react-native-auth 3.4.18 → 3.4.20
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.4.
|
|
3
|
+
"version": "3.4.20",
|
|
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",
|
|
@@ -39,7 +39,6 @@
|
|
|
39
39
|
"@umituz/react-native-validation": "^1.4.7"
|
|
40
40
|
},
|
|
41
41
|
"peerDependencies": {
|
|
42
|
-
"@gorhom/bottom-sheet": ">=4.0.0",
|
|
43
42
|
"@react-navigation/native": ">=6.0.0",
|
|
44
43
|
"@react-navigation/stack": ">=6.0.0",
|
|
45
44
|
"@tanstack/react-query": ">=5.0.0",
|
|
@@ -50,14 +49,12 @@
|
|
|
50
49
|
"react": ">=18.2.0",
|
|
51
50
|
"react-native": ">=0.74.0",
|
|
52
51
|
"react-native-gesture-handler": ">=2.0.0",
|
|
53
|
-
"react-native-reanimated": ">=3.0.0",
|
|
54
52
|
"react-native-safe-area-context": ">=4.0.0",
|
|
55
53
|
"react-native-svg": ">=13.0.0",
|
|
56
54
|
"zustand": ">=4.0.0"
|
|
57
55
|
},
|
|
58
56
|
"devDependencies": {
|
|
59
57
|
"@expo/vector-icons": "^15.0.3",
|
|
60
|
-
"@gorhom/bottom-sheet": "^5.0.0",
|
|
61
58
|
"@react-native-async-storage/async-storage": "^2.2.0",
|
|
62
59
|
"@react-native-community/datetimepicker": "^8.5.1",
|
|
63
60
|
"@react-navigation/bottom-tabs": "^7.9.0",
|
|
@@ -89,7 +86,6 @@
|
|
|
89
86
|
"react": "~19.1.0",
|
|
90
87
|
"react-native": "~0.81.5",
|
|
91
88
|
"react-native-gesture-handler": "^2.0.0",
|
|
92
|
-
"react-native-reanimated": "^3.0.0",
|
|
93
89
|
"react-native-safe-area-context": "^4.0.0",
|
|
94
90
|
"react-native-svg": "^15.15.1",
|
|
95
91
|
"rn-emoji-keyboard": "^1.7.0",
|
|
@@ -3,15 +3,16 @@
|
|
|
3
3
|
* Bottom sheet modal for authentication (Login/Register)
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
|
-
import React, { useEffect, useCallback, useRef, useState
|
|
7
|
-
import { View, TouchableOpacity } from "react-native";
|
|
6
|
+
import React, { useEffect, useCallback, useRef, useState } from "react";
|
|
7
|
+
import { View, TouchableOpacity, ScrollView } from "react-native";
|
|
8
8
|
import {
|
|
9
|
+
useAppDesignTokens,
|
|
10
|
+
AtomicText,
|
|
11
|
+
AtomicIcon,
|
|
12
|
+
AtomicKeyboardAvoidingView,
|
|
9
13
|
BottomSheetModal,
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
} from "@gorhom/bottom-sheet";
|
|
13
|
-
import type { BottomSheetBackdropProps } from "@gorhom/bottom-sheet";
|
|
14
|
-
import { useAppDesignTokens, AtomicText, AtomicIcon, AtomicKeyboardAvoidingView } from "@umituz/react-native-design-system";
|
|
14
|
+
type BottomSheetModalRef,
|
|
15
|
+
} from "@umituz/react-native-design-system";
|
|
15
16
|
import { useLocalization } from "@umituz/react-native-localization";
|
|
16
17
|
import { useAuthModalStore } from "../stores/authModalStore";
|
|
17
18
|
import { useAuth } from "../hooks/useAuth";
|
|
@@ -45,7 +46,7 @@ export const AuthBottomSheet: React.FC<AuthBottomSheetProps> = ({
|
|
|
45
46
|
}) => {
|
|
46
47
|
const tokens = useAppDesignTokens();
|
|
47
48
|
const { t } = useLocalization();
|
|
48
|
-
const modalRef = useRef<
|
|
49
|
+
const modalRef = useRef<BottomSheetModalRef>(null);
|
|
49
50
|
|
|
50
51
|
const [googleLoading, setGoogleLoading] = useState(false);
|
|
51
52
|
const [appleLoading, setAppleLoading] = useState(false);
|
|
@@ -62,13 +63,6 @@ export const AuthBottomSheet: React.FC<AuthBottomSheetProps> = ({
|
|
|
62
63
|
}
|
|
63
64
|
}, [isVisible]);
|
|
64
65
|
|
|
65
|
-
useEffect(() => {
|
|
66
|
-
if (isAuthenticated && !isAnonymous && isVisible) {
|
|
67
|
-
hideAuthModal();
|
|
68
|
-
executePendingCallback();
|
|
69
|
-
}
|
|
70
|
-
}, [isAuthenticated, isAnonymous, isVisible, hideAuthModal, executePendingCallback]);
|
|
71
|
-
|
|
72
66
|
const handleDismiss = useCallback(() => {
|
|
73
67
|
hideAuthModal();
|
|
74
68
|
clearPendingCallback();
|
|
@@ -79,6 +73,26 @@ export const AuthBottomSheet: React.FC<AuthBottomSheetProps> = ({
|
|
|
79
73
|
handleDismiss();
|
|
80
74
|
}, [handleDismiss]);
|
|
81
75
|
|
|
76
|
+
const prevIsAuthenticatedRef = useRef(isAuthenticated);
|
|
77
|
+
const prevIsVisibleRef = useRef(isVisible);
|
|
78
|
+
|
|
79
|
+
useEffect(() => {
|
|
80
|
+
// Only close the modal if the user was NOT authenticated and then BECOMES authenticated
|
|
81
|
+
// while the modal is visible.
|
|
82
|
+
if (!prevIsAuthenticatedRef.current && isAuthenticated && isVisible && !isAnonymous) {
|
|
83
|
+
if (typeof __DEV__ !== "undefined" && __DEV__) {
|
|
84
|
+
// eslint-disable-next-line no-console
|
|
85
|
+
console.log("[AuthBottomSheet] Auto-closing due to successful authentication transition");
|
|
86
|
+
}
|
|
87
|
+
handleClose();
|
|
88
|
+
executePendingCallback();
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
// Update ref for next render
|
|
92
|
+
prevIsAuthenticatedRef.current = isAuthenticated;
|
|
93
|
+
prevIsVisibleRef.current = isVisible;
|
|
94
|
+
}, [isAuthenticated, isVisible, isAnonymous, executePendingCallback, handleClose]);
|
|
95
|
+
|
|
82
96
|
const handleNavigateToRegister = useCallback(() => {
|
|
83
97
|
setMode("register");
|
|
84
98
|
}, [setMode]);
|
|
@@ -107,32 +121,17 @@ export const AuthBottomSheet: React.FC<AuthBottomSheetProps> = ({
|
|
|
107
121
|
}
|
|
108
122
|
}, [onAppleSignIn]);
|
|
109
123
|
|
|
110
|
-
const renderBackdrop = useCallback(
|
|
111
|
-
(props: BottomSheetBackdropProps) => (
|
|
112
|
-
<BottomSheetBackdrop {...props} appearsOnIndex={0} disappearsOnIndex={-1} pressBehavior="close" />
|
|
113
|
-
),
|
|
114
|
-
[],
|
|
115
|
-
);
|
|
116
|
-
|
|
117
|
-
const snapPoints = useMemo(() => ["95%"], []);
|
|
118
|
-
|
|
119
124
|
return (
|
|
120
125
|
<BottomSheetModal
|
|
121
126
|
ref={modalRef}
|
|
122
|
-
index={0}
|
|
123
|
-
snapPoints={snapPoints}
|
|
124
|
-
backdropComponent={renderBackdrop}
|
|
125
127
|
onDismiss={handleDismiss}
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
keyboardBlurBehavior="restore"
|
|
129
|
-
backgroundStyle={[styles.background, { backgroundColor: tokens.colors.backgroundPrimary }]}
|
|
130
|
-
handleIndicatorStyle={[styles.handleIndicator, { backgroundColor: tokens.colors.border }]}
|
|
128
|
+
preset="full"
|
|
129
|
+
backgroundColor={tokens.colors.backgroundPrimary}
|
|
131
130
|
>
|
|
132
131
|
<AtomicKeyboardAvoidingView
|
|
133
132
|
style={{ flex: 1 }}
|
|
134
133
|
>
|
|
135
|
-
<
|
|
134
|
+
<ScrollView
|
|
136
135
|
contentContainerStyle={styles.scrollContent}
|
|
137
136
|
showsVerticalScrollIndicator={false}
|
|
138
137
|
keyboardShouldPersistTaps="handled"
|
|
@@ -179,7 +178,7 @@ export const AuthBottomSheet: React.FC<AuthBottomSheetProps> = ({
|
|
|
179
178
|
/>
|
|
180
179
|
)}
|
|
181
180
|
</View>
|
|
182
|
-
</
|
|
181
|
+
</ScrollView>
|
|
183
182
|
</AtomicKeyboardAvoidingView>
|
|
184
183
|
</BottomSheetModal>
|
|
185
184
|
);
|
|
@@ -14,51 +14,10 @@ import {
|
|
|
14
14
|
type SocialAuthResult,
|
|
15
15
|
} from "@umituz/react-native-firebase";
|
|
16
16
|
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
iosClientId: string;
|
|
20
|
-
webClientId: string;
|
|
21
|
-
androidClientId: string;
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
interface AuthSessionAuthentication {
|
|
25
|
-
idToken?: string;
|
|
26
|
-
accessToken?: string;
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
interface AuthSessionResult {
|
|
30
|
-
type: "success" | "cancel" | "dismiss" | "error" | "locked";
|
|
31
|
-
authentication?: AuthSessionAuthentication;
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
interface AuthRequest {
|
|
35
|
-
promptAsync: () => Promise<AuthSessionResult>;
|
|
36
|
-
}
|
|
17
|
+
import * as Google from "expo-auth-session/providers/google";
|
|
18
|
+
import * as WebBrowser from "expo-web-browser";
|
|
37
19
|
|
|
38
|
-
|
|
39
|
-
AuthRequest | null,
|
|
40
|
-
AuthSessionResult | null,
|
|
41
|
-
() => Promise<AuthSessionResult>,
|
|
42
|
-
];
|
|
43
|
-
|
|
44
|
-
// Dynamic imports to handle optional dependencies
|
|
45
|
-
type GoogleModule = { useAuthRequest: (config: GoogleAuthRequestConfig) => UseAuthRequestReturn };
|
|
46
|
-
type WebBrowserModule = { maybeCompleteAuthSession: () => void };
|
|
47
|
-
|
|
48
|
-
let Google: GoogleModule | null = null;
|
|
49
|
-
let WebBrowser: WebBrowserModule | null = null;
|
|
50
|
-
|
|
51
|
-
try {
|
|
52
|
-
// eslint-disable-next-line @typescript-eslint/no-require-imports, @typescript-eslint/no-var-requires
|
|
53
|
-
Google = require("expo-auth-session/providers/google") as GoogleModule;
|
|
54
|
-
// eslint-disable-next-line @typescript-eslint/no-require-imports, @typescript-eslint/no-var-requires
|
|
55
|
-
WebBrowser = require("expo-web-browser") as WebBrowserModule;
|
|
56
|
-
if (WebBrowser) {
|
|
57
|
-
WebBrowser.maybeCompleteAuthSession();
|
|
58
|
-
}
|
|
59
|
-
} catch {
|
|
60
|
-
// expo-auth-session not available - silent fallback
|
|
61
|
-
}
|
|
20
|
+
WebBrowser.maybeCompleteAuthSession();
|
|
62
21
|
|
|
63
22
|
export interface GoogleAuthConfig {
|
|
64
23
|
iosClientId?: string;
|
|
@@ -123,7 +82,7 @@ export function useGoogleAuth(config?: GoogleAuthConfig): UseGoogleAuthResult {
|
|
|
123
82
|
}, [googleResponse, signInWithGoogleToken]);
|
|
124
83
|
|
|
125
84
|
const signInWithGoogle = useCallback(async (): Promise<SocialAuthResult> => {
|
|
126
|
-
if (!
|
|
85
|
+
if (!promptGoogleAsync) {
|
|
127
86
|
return { success: false, error: "expo-auth-session is not available" };
|
|
128
87
|
}
|
|
129
88
|
|