@umituz/react-native-auth 4.3.71 → 4.3.73
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/.agents/workflows/setup-auth.md +49 -0
- package/package.json +2 -1
- package/src/presentation/components/AccountActions.tsx +16 -7
- package/src/presentation/components/AuthHeader.tsx +11 -3
- package/src/presentation/components/AuthLink.tsx +7 -12
- package/src/presentation/components/SocialLoginButtons.tsx +17 -12
- package/src/presentation/screens/AccountScreen.tsx +6 -3
- package/src/presentation/screens/LoginScreen.tsx +14 -5
- package/src/presentation/screens/RegisterScreen.tsx +14 -11
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: Sets up or updates the @umituz/react-native-auth package in a React Native app.
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
# Auth Module Setup Skill
|
|
6
|
+
|
|
7
|
+
When this workflow/skill is invoked, follow these explicit instructions to configure `@umituz/react-native-auth`.
|
|
8
|
+
|
|
9
|
+
## Step 1: Check and Update `package.json`
|
|
10
|
+
- Locate the project's `package.json`.
|
|
11
|
+
- Check if `@umituz/react-native-auth` is installed.
|
|
12
|
+
- If missing: Install with `npm install @umituz/react-native-auth`.
|
|
13
|
+
- If outdated: Update it to the latest version.
|
|
14
|
+
|
|
15
|
+
## Step 2: Ensure Peer Dependencies
|
|
16
|
+
This module strictly requires the Firebase package and other navigation/UI primitives. Check and install missing peer dependencies (use `npx expo install` for Expo):
|
|
17
|
+
- `@umituz/react-native-firebase`
|
|
18
|
+
- `@umituz/react-native-design-system`
|
|
19
|
+
- `@tanstack/react-query` & `zustand`
|
|
20
|
+
- `firebase`
|
|
21
|
+
- `expo-apple-authentication`, `expo-auth-session`, `expo-web-browser`, `expo-crypto`
|
|
22
|
+
- `@react-navigation/native` & `@react-navigation/stack`
|
|
23
|
+
|
|
24
|
+
// turbo
|
|
25
|
+
## Step 3: Run Pod Install (If bare React Native)
|
|
26
|
+
If targeting iOS and `ios/` folder is present, run:
|
|
27
|
+
```bash
|
|
28
|
+
cd ios && pod install
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
## Step 4: Inject Global Auth Provider
|
|
32
|
+
- Locate the main entry file (`App.tsx`, `app/_layout.tsx`, etc.).
|
|
33
|
+
- Import `AuthProvider` and `initializeAuth` (or `createAuthInitModule`) from `@umituz/react-native-auth`.
|
|
34
|
+
- Ensure the app component tree is wrapped in `<AuthProvider>`.
|
|
35
|
+
- Make sure that Firebase has been initialized first or initialized simultaneously, and then `initializeAuth` is called to bind the auth store to the Firebase driver.
|
|
36
|
+
```tsx
|
|
37
|
+
import { AuthProvider } from '@umituz/react-native-auth';
|
|
38
|
+
|
|
39
|
+
export default function App() {
|
|
40
|
+
return (
|
|
41
|
+
<AuthProvider>
|
|
42
|
+
<RootNavigation />
|
|
43
|
+
</AuthProvider>
|
|
44
|
+
);
|
|
45
|
+
}
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
## Step 5: Summary
|
|
49
|
+
Summarize the action: list which packages were upgraded/installed and the entry files modified to inject the `<AuthProvider>`.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@umituz/react-native-auth",
|
|
3
|
-
"version": "4.3.
|
|
3
|
+
"version": "4.3.73",
|
|
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",
|
|
@@ -115,6 +115,7 @@
|
|
|
115
115
|
},
|
|
116
116
|
"files": [
|
|
117
117
|
"src",
|
|
118
|
+
".agents",
|
|
118
119
|
"README.md",
|
|
119
120
|
"LICENSE"
|
|
120
121
|
]
|
|
@@ -1,4 +1,10 @@
|
|
|
1
|
-
|
|
1
|
+
/**
|
|
2
|
+
* Account Actions Component
|
|
3
|
+
* Logout and delete account actions
|
|
4
|
+
* PERFORMANCE: Memoized with useCallback for stable alert action handlers
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import React, { memo, useCallback } from "react";
|
|
2
8
|
import { View, TouchableOpacity, StyleSheet } from "react-native";
|
|
3
9
|
import { useAppDesignTokens } from "@umituz/react-native-design-system/theme";
|
|
4
10
|
import { AtomicIcon, AtomicText } from "@umituz/react-native-design-system/atoms";
|
|
@@ -26,7 +32,7 @@ interface AccountActionsProps {
|
|
|
26
32
|
config: AccountActionsConfig;
|
|
27
33
|
}
|
|
28
34
|
|
|
29
|
-
export const AccountActions
|
|
35
|
+
export const AccountActions = memo<AccountActionsProps>(({ config }) => {
|
|
30
36
|
const tokens = useAppDesignTokens();
|
|
31
37
|
const alert = useAlert();
|
|
32
38
|
const {
|
|
@@ -46,7 +52,8 @@ export const AccountActions: React.FC<AccountActionsProps> = ({ config }) => {
|
|
|
46
52
|
showChangePassword = false,
|
|
47
53
|
} = config;
|
|
48
54
|
|
|
49
|
-
|
|
55
|
+
// PERFORMANCE: Stable callback references prevent unnecessary re-renders
|
|
56
|
+
const handleLogout = useCallback(() => {
|
|
50
57
|
alert.show(AlertType.WARNING, AlertMode.MODAL, logoutConfirmTitle, logoutConfirmMessage, {
|
|
51
58
|
actions: [
|
|
52
59
|
{ id: "cancel", label: cancelText, style: "secondary", onPress: () => {} },
|
|
@@ -66,9 +73,9 @@ export const AccountActions: React.FC<AccountActionsProps> = ({ config }) => {
|
|
|
66
73
|
},
|
|
67
74
|
],
|
|
68
75
|
});
|
|
69
|
-
};
|
|
76
|
+
}, [alert, logoutText, logoutConfirmTitle, logoutConfirmMessage, cancelText, onLogout]);
|
|
70
77
|
|
|
71
|
-
const handleDeleteAccount = () => {
|
|
78
|
+
const handleDeleteAccount = useCallback(() => {
|
|
72
79
|
alert.show(AlertType.ERROR, AlertMode.MODAL, deleteConfirmTitle, deleteConfirmMessage, {
|
|
73
80
|
actions: [
|
|
74
81
|
{ id: "cancel", label: cancelText, style: "secondary", onPress: () => {} },
|
|
@@ -86,7 +93,7 @@ export const AccountActions: React.FC<AccountActionsProps> = ({ config }) => {
|
|
|
86
93
|
},
|
|
87
94
|
],
|
|
88
95
|
});
|
|
89
|
-
};
|
|
96
|
+
}, [alert, deleteAccountText, deleteConfirmTitle, deleteConfirmMessage, deleteErrorTitle, deleteErrorMessage, cancelText, onDeleteAccount]);
|
|
90
97
|
|
|
91
98
|
return (
|
|
92
99
|
<View style={styles.container}>
|
|
@@ -111,7 +118,9 @@ export const AccountActions: React.FC<AccountActionsProps> = ({ config }) => {
|
|
|
111
118
|
</TouchableOpacity>
|
|
112
119
|
</View>
|
|
113
120
|
);
|
|
114
|
-
};
|
|
121
|
+
});
|
|
122
|
+
|
|
123
|
+
AccountActions.displayName = 'AccountActions';
|
|
115
124
|
|
|
116
125
|
const styles = StyleSheet.create({
|
|
117
126
|
container: { gap: 12 },
|
|
@@ -1,4 +1,10 @@
|
|
|
1
|
-
|
|
1
|
+
/**
|
|
2
|
+
* Auth Header Component
|
|
3
|
+
* Displays auth screen title and optional subtitle
|
|
4
|
+
* PERFORMANCE: Memoized to prevent unnecessary re-renders
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import React, { memo } from "react";
|
|
2
8
|
import { View, StyleSheet } from "react-native";
|
|
3
9
|
import { useAppDesignTokens } from "@umituz/react-native-design-system/theme";
|
|
4
10
|
import { AtomicText } from "@umituz/react-native-design-system/atoms";
|
|
@@ -8,7 +14,7 @@ interface AuthHeaderProps {
|
|
|
8
14
|
subtitle?: string;
|
|
9
15
|
}
|
|
10
16
|
|
|
11
|
-
export const AuthHeader
|
|
17
|
+
export const AuthHeader = memo<AuthHeaderProps>(({ title, subtitle }) => {
|
|
12
18
|
const tokens = useAppDesignTokens();
|
|
13
19
|
|
|
14
20
|
return (
|
|
@@ -34,7 +40,9 @@ export const AuthHeader: React.FC<AuthHeaderProps> = ({ title, subtitle }) => {
|
|
|
34
40
|
)}
|
|
35
41
|
</View>
|
|
36
42
|
);
|
|
37
|
-
};
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
AuthHeader.displayName = 'AuthHeader';
|
|
38
46
|
|
|
39
47
|
const styles = StyleSheet.create({
|
|
40
48
|
header: {
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Auth Link Component
|
|
3
3
|
* Link text with button for navigation between auth screens
|
|
4
|
+
* PERFORMANCE: Memoized to prevent unnecessary re-renders
|
|
4
5
|
*/
|
|
5
6
|
|
|
6
|
-
import React from "react";
|
|
7
|
+
import React, { memo } from "react";
|
|
7
8
|
import { View, StyleSheet } from "react-native";
|
|
8
9
|
import { useAppDesignTokens } from "@umituz/react-native-design-system/theme";
|
|
9
10
|
import { AtomicText, AtomicButton } from "@umituz/react-native-design-system/atoms";
|
|
@@ -15,20 +16,12 @@ interface AuthLinkProps {
|
|
|
15
16
|
disabled?: boolean;
|
|
16
17
|
}
|
|
17
18
|
|
|
18
|
-
export const AuthLink
|
|
19
|
-
text,
|
|
20
|
-
linkText,
|
|
21
|
-
onPress,
|
|
22
|
-
disabled = false,
|
|
23
|
-
}) => {
|
|
19
|
+
export const AuthLink = memo<AuthLinkProps>(({ text, linkText, onPress, disabled = false }) => {
|
|
24
20
|
const tokens = useAppDesignTokens();
|
|
25
21
|
|
|
26
22
|
return (
|
|
27
23
|
<View style={[styles.container, { marginTop: tokens.spacing.xs, paddingTop: tokens.spacing.xs }]}>
|
|
28
|
-
<AtomicText
|
|
29
|
-
type="bodyMedium"
|
|
30
|
-
color="textSecondary"
|
|
31
|
-
>
|
|
24
|
+
<AtomicText type="bodyMedium" color="textSecondary">
|
|
32
25
|
{text}{" "}
|
|
33
26
|
</AtomicText>
|
|
34
27
|
<AtomicButton
|
|
@@ -41,7 +34,9 @@ export const AuthLink: React.FC<AuthLinkProps> = ({
|
|
|
41
34
|
</AtomicButton>
|
|
42
35
|
</View>
|
|
43
36
|
);
|
|
44
|
-
};
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
AuthLink.displayName = 'AuthLink';
|
|
45
40
|
|
|
46
41
|
const styles = StyleSheet.create({
|
|
47
42
|
container: {
|
|
@@ -1,4 +1,10 @@
|
|
|
1
|
-
|
|
1
|
+
/**
|
|
2
|
+
* Social Login Buttons Component
|
|
3
|
+
* Google and Apple sign-in buttons
|
|
4
|
+
* PERFORMANCE: Memoized and provider checks memoized to prevent re-renders
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import React, { useMemo, memo } from "react";
|
|
2
8
|
import { View, StyleSheet } from "react-native";
|
|
3
9
|
import { useAppDesignTokens } from "@umituz/react-native-design-system/theme";
|
|
4
10
|
import { AtomicText, AtomicButton } from "@umituz/react-native-design-system/atoms";
|
|
@@ -19,17 +25,14 @@ interface SocialLoginButtonsProps {
|
|
|
19
25
|
appleLoading?: boolean;
|
|
20
26
|
}
|
|
21
27
|
|
|
22
|
-
export const SocialLoginButtons
|
|
23
|
-
translations,
|
|
24
|
-
enabledProviders,
|
|
25
|
-
onGooglePress,
|
|
26
|
-
onApplePress,
|
|
27
|
-
googleLoading = false,
|
|
28
|
-
appleLoading = false,
|
|
29
|
-
}) => {
|
|
28
|
+
export const SocialLoginButtons = memo<SocialLoginButtonsProps>(({ translations, enabledProviders, onGooglePress, onApplePress, googleLoading = false, appleLoading = false }) => {
|
|
30
29
|
const tokens = useAppDesignTokens();
|
|
31
|
-
|
|
32
|
-
|
|
30
|
+
|
|
31
|
+
// PERFORMANCE: Memoize provider checks to prevent recalculation on every render
|
|
32
|
+
const { hasGoogle, hasApple } = useMemo(() => ({
|
|
33
|
+
hasGoogle: enabledProviders.includes("google"),
|
|
34
|
+
hasApple: enabledProviders.includes("apple"),
|
|
35
|
+
}), [enabledProviders]);
|
|
33
36
|
|
|
34
37
|
if (!hasGoogle && !hasApple) {
|
|
35
38
|
return null;
|
|
@@ -74,7 +77,9 @@ export const SocialLoginButtons: React.FC<SocialLoginButtonsProps> = ({
|
|
|
74
77
|
</View>
|
|
75
78
|
</View>
|
|
76
79
|
);
|
|
77
|
-
};
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
SocialLoginButtons.displayName = 'SocialLoginButtons';
|
|
78
83
|
|
|
79
84
|
const styles = StyleSheet.create({
|
|
80
85
|
container: {},
|
|
@@ -2,9 +2,10 @@
|
|
|
2
2
|
* Account Screen
|
|
3
3
|
* Pure UI component for account management
|
|
4
4
|
* Business logic provided via props from app layer
|
|
5
|
+
* PERFORMANCE: Memoized to prevent unnecessary re-renders
|
|
5
6
|
*/
|
|
6
7
|
|
|
7
|
-
import React from "react";
|
|
8
|
+
import React, { memo } from "react";
|
|
8
9
|
import { View, TouchableOpacity, StyleSheet } from "react-native";
|
|
9
10
|
import { useAppDesignTokens } from "@umituz/react-native-design-system/theme";
|
|
10
11
|
import { AtomicIcon, AtomicText } from "@umituz/react-native-design-system/atoms";
|
|
@@ -29,7 +30,7 @@ export interface AccountScreenProps {
|
|
|
29
30
|
config: AccountScreenConfig;
|
|
30
31
|
}
|
|
31
32
|
|
|
32
|
-
export const AccountScreen
|
|
33
|
+
export const AccountScreen = memo<AccountScreenProps>(({ config }) => {
|
|
33
34
|
const tokens = useAppDesignTokens();
|
|
34
35
|
|
|
35
36
|
return (
|
|
@@ -74,7 +75,9 @@ export const AccountScreen: React.FC<AccountScreenProps> = ({ config }) => {
|
|
|
74
75
|
{config.PasswordPromptComponent}
|
|
75
76
|
</>
|
|
76
77
|
);
|
|
77
|
-
};
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
AccountScreen.displayName = 'AccountScreen';
|
|
78
81
|
|
|
79
82
|
const styles = StyleSheet.create({
|
|
80
83
|
content: {
|
|
@@ -1,4 +1,10 @@
|
|
|
1
|
-
|
|
1
|
+
/**
|
|
2
|
+
* Login Screen Component
|
|
3
|
+
* Login form screen with navigation
|
|
4
|
+
* PERFORMANCE: Memoized to prevent unnecessary re-renders
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import React, { memo, useCallback } from "react";
|
|
2
8
|
import { useAppDesignTokens } from "@umituz/react-native-design-system/theme";
|
|
3
9
|
import { AtomicCard } from "@umituz/react-native-design-system/atoms";
|
|
4
10
|
import { useAppNavigation } from "@umituz/react-native-design-system/molecules";
|
|
@@ -16,13 +22,14 @@ export interface LoginScreenProps {
|
|
|
16
22
|
translations: LoginScreenTranslations;
|
|
17
23
|
}
|
|
18
24
|
|
|
19
|
-
export const LoginScreen
|
|
25
|
+
export const LoginScreen = memo<LoginScreenProps>(({ translations }) => {
|
|
20
26
|
const navigation = useAppNavigation();
|
|
21
27
|
const tokens = useAppDesignTokens();
|
|
22
28
|
|
|
23
|
-
|
|
29
|
+
// PERFORMANCE: Stable callback reference
|
|
30
|
+
const handleNavigateToRegister = useCallback(() => {
|
|
24
31
|
navigation.navigate("Register");
|
|
25
|
-
};
|
|
32
|
+
}, [navigation]);
|
|
26
33
|
|
|
27
34
|
return (
|
|
28
35
|
<ScreenLayout
|
|
@@ -41,4 +48,6 @@ export const LoginScreen: React.FC<LoginScreenProps> = ({ translations }) => {
|
|
|
41
48
|
</AtomicCard>
|
|
42
49
|
</ScreenLayout>
|
|
43
50
|
);
|
|
44
|
-
};
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
LoginScreen.displayName = 'LoginScreen';
|
|
@@ -1,4 +1,10 @@
|
|
|
1
|
-
|
|
1
|
+
/**
|
|
2
|
+
* Register Screen Component
|
|
3
|
+
* Registration form screen with navigation
|
|
4
|
+
* PERFORMANCE: Memoized to prevent unnecessary re-renders
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import React, { memo, useCallback } from "react";
|
|
2
8
|
import { useAppDesignTokens } from "@umituz/react-native-design-system/theme";
|
|
3
9
|
import { AtomicCard } from "@umituz/react-native-design-system/atoms";
|
|
4
10
|
import { useAppNavigation } from "@umituz/react-native-design-system/molecules";
|
|
@@ -20,19 +26,14 @@ export interface RegisterScreenProps {
|
|
|
20
26
|
onPrivacyPress?: () => void;
|
|
21
27
|
}
|
|
22
28
|
|
|
23
|
-
export const RegisterScreen
|
|
24
|
-
translations,
|
|
25
|
-
termsUrl,
|
|
26
|
-
privacyUrl,
|
|
27
|
-
onTermsPress,
|
|
28
|
-
onPrivacyPress,
|
|
29
|
-
}) => {
|
|
29
|
+
export const RegisterScreen = memo<RegisterScreenProps>(({ translations, termsUrl, privacyUrl, onTermsPress, onPrivacyPress }) => {
|
|
30
30
|
const navigation = useAppNavigation();
|
|
31
31
|
const tokens = useAppDesignTokens();
|
|
32
32
|
|
|
33
|
-
|
|
33
|
+
// PERFORMANCE: Stable callback reference
|
|
34
|
+
const handleNavigateToLogin = useCallback(() => {
|
|
34
35
|
navigation.navigate("Login");
|
|
35
|
-
};
|
|
36
|
+
}, [navigation]);
|
|
36
37
|
|
|
37
38
|
return (
|
|
38
39
|
<ScreenLayout
|
|
@@ -55,4 +56,6 @@ export const RegisterScreen: React.FC<RegisterScreenProps> = ({
|
|
|
55
56
|
</AtomicCard>
|
|
56
57
|
</ScreenLayout>
|
|
57
58
|
);
|
|
58
|
-
};
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
RegisterScreen.displayName = 'RegisterScreen';
|