@umituz/react-native-auth 2.5.3 → 2.5.4

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": "2.5.3",
3
+ "version": "2.5.4",
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",
package/src/index.ts CHANGED
@@ -99,6 +99,9 @@ export type {
99
99
  export { useAuth } from './presentation/hooks/useAuth';
100
100
  export type { UseAuthResult } from './presentation/hooks/useAuth';
101
101
 
102
+ export { useUserProfile } from './presentation/hooks/useUserProfile';
103
+ export type { UserProfileData, UseUserProfileParams } from './presentation/hooks/useUserProfile';
104
+
102
105
  // =============================================================================
103
106
  // PRESENTATION LAYER - Screens & Navigation
104
107
  // =============================================================================
@@ -128,6 +131,8 @@ export { PasswordMatchIndicator } from './presentation/components/PasswordMatchI
128
131
  export type { PasswordMatchIndicatorProps } from './presentation/components/PasswordMatchIndicator';
129
132
  export { AuthBottomSheet } from './presentation/components/AuthBottomSheet';
130
133
  export type { AuthBottomSheetProps } from './presentation/components/AuthBottomSheet';
134
+ export { ProfileSection } from './presentation/components/ProfileSection';
135
+ export type { ProfileSectionConfig, ProfileSectionProps } from './presentation/components/ProfileSection';
131
136
 
132
137
  // =============================================================================
133
138
  // PRESENTATION LAYER - Stores
@@ -0,0 +1,188 @@
1
+ /**
2
+ * Profile Section Component
3
+ * Generic user profile section for settings screens
4
+ * Shows user info, sign in CTA for anonymous, or account navigation for signed in users
5
+ */
6
+
7
+ import React from "react";
8
+ import { View, Text, TouchableOpacity, StyleSheet } from "react-native";
9
+ import { useAppDesignTokens } from "@umituz/react-native-design-system-theme";
10
+
11
+ export interface ProfileSectionConfig {
12
+ displayName: string;
13
+ userId?: string;
14
+ isAnonymous: boolean;
15
+ avatarUrl?: string;
16
+ accountSettingsRoute?: string;
17
+ }
18
+
19
+ export interface ProfileSectionProps {
20
+ profile: ProfileSectionConfig;
21
+ onPress?: () => void;
22
+ onSignIn?: () => void;
23
+ signInText?: string;
24
+ anonymousText?: string;
25
+ }
26
+
27
+ export const ProfileSection: React.FC<ProfileSectionProps> = ({
28
+ profile,
29
+ onPress,
30
+ onSignIn,
31
+ signInText = "Sign In",
32
+ anonymousText = "Anonymous User",
33
+ }) => {
34
+ const tokens = useAppDesignTokens();
35
+
36
+ const handlePress = () => {
37
+ if (profile.isAnonymous && onSignIn) {
38
+ onSignIn();
39
+ } else if (onPress) {
40
+ onPress();
41
+ }
42
+ };
43
+
44
+ const getInitials = (name: string): string => {
45
+ return name
46
+ .split(" ")
47
+ .map((n) => n[0])
48
+ .join("")
49
+ .toUpperCase()
50
+ .slice(0, 2);
51
+ };
52
+
53
+ return (
54
+ <TouchableOpacity
55
+ style={[styles.container, { backgroundColor: tokens.colors.surface }]}
56
+ onPress={handlePress}
57
+ activeOpacity={0.7}
58
+ disabled={!onPress && !onSignIn}
59
+ >
60
+ <View style={styles.content}>
61
+ {/* Avatar */}
62
+ <View
63
+ style={[
64
+ styles.avatar,
65
+ { backgroundColor: profile.isAnonymous ? tokens.colors.warning : tokens.colors.primary },
66
+ ]}
67
+ >
68
+ {profile.avatarUrl ? (
69
+ <Text style={styles.avatarText}>
70
+ {getInitials(profile.displayName)}
71
+ </Text>
72
+ ) : (
73
+ <Text
74
+ style={[styles.avatarText, { color: tokens.colors.onPrimary }]}
75
+ >
76
+ {getInitials(profile.displayName)}
77
+ </Text>
78
+ )}
79
+ </View>
80
+
81
+ {/* User Info */}
82
+ <View style={styles.info}>
83
+ <Text
84
+ style={[styles.displayName, { color: tokens.colors.textPrimary }]}
85
+ numberOfLines={1}
86
+ >
87
+ {profile.displayName}
88
+ </Text>
89
+ {profile.userId && (
90
+ <Text
91
+ style={[styles.userId, { color: tokens.colors.textSecondary }]}
92
+ numberOfLines={1}
93
+ >
94
+ {profile.userId}
95
+ </Text>
96
+ )}
97
+ </View>
98
+
99
+ {/* Action Icon */}
100
+ {(onPress || onSignIn) && (
101
+ <Text style={[styles.chevron, { color: tokens.colors.textTertiary }]}>
102
+
103
+ </Text>)}
104
+ </View>
105
+
106
+ {/* Sign In CTA for Anonymous Users */}
107
+ {profile.isAnonymous && onSignIn && (
108
+ <View
109
+ style={[
110
+ styles.ctaContainer,
111
+ { borderTopColor: tokens.colors.border },
112
+ ]}
113
+ >
114
+ <TouchableOpacity
115
+ style={[
116
+ styles.ctaButton,
117
+ { backgroundColor: tokens.colors.primary },
118
+ ]}
119
+ onPress={onSignIn}
120
+ activeOpacity={0.8}
121
+ >
122
+ <Text
123
+ style={[
124
+ styles.ctaText,
125
+ { color: tokens.colors.onPrimary },
126
+ ]}
127
+ >
128
+ {signInText}
129
+ </Text>
130
+ </TouchableOpacity>
131
+ </View>
132
+ )}
133
+ </TouchableOpacity>
134
+ );
135
+ };
136
+
137
+ const styles = StyleSheet.create({
138
+ container: {
139
+ borderRadius: 12,
140
+ padding: 16,
141
+ marginBottom: 16,
142
+ },
143
+ content: {
144
+ flexDirection: "row",
145
+ alignItems: "center",
146
+ },
147
+ avatar: {
148
+ width: 56,
149
+ height: 56,
150
+ borderRadius: 28,
151
+ justifyContent: "center",
152
+ alignItems: "center",
153
+ marginRight: 12,
154
+ },
155
+ avatarText: {
156
+ fontSize: 20,
157
+ fontWeight: "600",
158
+ },
159
+ info: {
160
+ flex: 1,
161
+ },
162
+ displayName: {
163
+ fontSize: 18,
164
+ fontWeight: "600",
165
+ marginBottom: 2,
166
+ },
167
+ userId: {
168
+ fontSize: 13,
169
+ },
170
+ chevron: {
171
+ fontSize: 24,
172
+ fontWeight: "400",
173
+ },
174
+ ctaContainer: {
175
+ marginTop: 12,
176
+ paddingTop: 12,
177
+ borderTopWidth: 1,
178
+ },
179
+ ctaButton: {
180
+ paddingVertical: 12,
181
+ borderRadius: 8,
182
+ alignItems: "center",
183
+ },
184
+ ctaText: {
185
+ fontSize: 15,
186
+ fontWeight: "600",
187
+ },
188
+ });
@@ -0,0 +1,56 @@
1
+ /**
2
+ * useUserProfile Hook
3
+ * Generic hook for user profile configuration
4
+ * Returns profile data for display in settings or profile screens
5
+ */
6
+
7
+ import { useMemo } from "react";
8
+ import { useAuth } from "./useAuth";
9
+
10
+ export interface UserProfileData {
11
+ displayName: string;
12
+ userId?: string;
13
+ isAnonymous: boolean;
14
+ avatarUrl?: string;
15
+ accountSettingsRoute?: string;
16
+ }
17
+
18
+ export interface UseUserProfileParams {
19
+ anonymousDisplayName?: string;
20
+ guestDisplayName?: string;
21
+ accountRoute?: string;
22
+ }
23
+
24
+ export const useUserProfile = (
25
+ params?: UseUserProfileParams,
26
+ ): UserProfileData | undefined => {
27
+ const { user } = useAuth();
28
+
29
+ const anonymousName = params?.anonymousDisplayName || "Anonymous User";
30
+ const guestName = params?.guestDisplayName || "Guest User";
31
+ const accountRoute = params?.accountRoute || "Account";
32
+
33
+ return useMemo(() => {
34
+ if (!user) {
35
+ return undefined;
36
+ }
37
+
38
+ const isAnonymous = user.isAnonymous || false;
39
+
40
+ if (isAnonymous) {
41
+ return {
42
+ displayName: anonymousName,
43
+ userId: user.uid,
44
+ isAnonymous: true,
45
+ };
46
+ }
47
+
48
+ return {
49
+ accountSettingsRoute: accountRoute,
50
+ displayName: user.displayName || user.email || guestName,
51
+ userId: user.uid,
52
+ isAnonymous: false,
53
+ avatarUrl: user.photoURL || undefined,
54
+ };
55
+ }, [user, anonymousName, guestName, accountRoute]);
56
+ };