@umituz/react-native-settings 4.20.58 → 4.20.60
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/.github/ISSUE_TEMPLATE/bug_report.md +51 -0
- package/.github/ISSUE_TEMPLATE/documentation.md +52 -0
- package/.github/ISSUE_TEMPLATE/feature_request.md +63 -0
- package/.github/PULL_REQUEST_TEMPLATE.md +84 -0
- package/AI_AGENT_GUIDELINES.md +367 -0
- package/ARCHITECTURE.md +246 -0
- package/CHANGELOG.md +67 -0
- package/CODE_OF_CONDUCT.md +75 -0
- package/CONTRIBUTING.md +107 -0
- package/DOCUMENTATION_MIGRATION.md +319 -0
- package/DOCUMENTATION_TEMPLATE.md +155 -0
- package/LICENSE +21 -0
- package/README.md +321 -498
- package/SECURITY.md +98 -0
- package/SETTINGS_SCREEN_GUIDE.md +185 -0
- package/TESTING.md +358 -0
- package/package.json +13 -2
- package/src/application/README.md +85 -271
- package/src/domains/about/README.md +85 -440
- package/src/domains/about/presentation/hooks/README.md +93 -348
- package/src/domains/appearance/README.md +95 -584
- package/src/domains/appearance/hooks/README.md +95 -303
- package/src/domains/appearance/infrastructure/services/README.md +83 -397
- package/src/domains/appearance/presentation/components/README.md +95 -489
- package/src/domains/cloud-sync/README.md +73 -439
- package/src/domains/cloud-sync/presentation/components/README.md +95 -493
- package/src/domains/dev/README.md +71 -457
- package/src/domains/disclaimer/README.md +77 -411
- package/src/domains/disclaimer/presentation/components/README.md +95 -392
- package/src/domains/faqs/README.md +86 -574
- package/src/domains/feedback/README.md +79 -553
- package/src/domains/feedback/presentation/hooks/README.md +93 -426
- package/src/domains/legal/README.md +88 -537
- package/src/domains/rating/README.md +73 -440
- package/src/domains/rating/presentation/components/README.md +95 -475
- package/src/domains/video-tutorials/README.md +77 -470
- package/src/domains/video-tutorials/presentation/components/README.md +95 -431
- package/src/infrastructure/README.md +78 -425
- package/src/infrastructure/repositories/README.md +88 -420
- package/src/infrastructure/services/README.md +74 -460
- package/src/presentation/components/README.md +97 -480
- package/src/presentation/components/SettingsErrorBoundary/README.md +48 -436
- package/src/presentation/components/SettingsFooter/README.md +48 -427
- package/src/presentation/components/SettingsItemCard/README.md +152 -391
- package/src/presentation/components/SettingsItemCard/STRATEGY.md +164 -0
- package/src/presentation/components/SettingsSection/README.md +47 -401
- package/src/presentation/hooks/README.md +95 -389
- package/src/presentation/hooks/mutations/README.md +99 -376
- package/src/presentation/hooks/queries/README.md +111 -353
- package/src/presentation/navigation/README.md +70 -502
- package/src/presentation/navigation/SettingsStackNavigator.tsx +2 -0
- package/src/presentation/navigation/components/README.md +70 -295
- package/src/presentation/navigation/components/wrappers/SettingsScreenWrapper.tsx +3 -0
- package/src/presentation/navigation/hooks/README.md +75 -367
- package/src/presentation/navigation/types.ts +1 -0
- package/src/presentation/navigation/utils/README.md +100 -380
- package/src/presentation/screens/README.md +53 -504
- package/src/presentation/screens/SettingsScreen.tsx +4 -2
- package/src/presentation/screens/components/SettingsContent/README.md +53 -382
- package/src/presentation/screens/components/SettingsHeader/README.md +48 -303
- package/src/presentation/screens/components/sections/CustomSettingsList/README.md +47 -359
- package/src/presentation/screens/components/sections/FeatureSettingsSection/README.md +81 -176
- package/src/presentation/screens/components/sections/IdentitySettingsSection/README.md +40 -297
- package/src/presentation/screens/components/sections/ProfileSectionLoader/README.md +47 -451
- package/src/presentation/screens/components/sections/SupportSettingsSection/README.md +45 -361
- package/src/presentation/screens/hooks/README.md +64 -354
- package/src/presentation/screens/types/README.md +79 -409
- package/src/presentation/screens/utils/README.md +65 -255
|
@@ -2,479 +2,75 @@
|
|
|
2
2
|
|
|
3
3
|
Dynamic loader component that fetches and displays user profile information in the settings screen header.
|
|
4
4
|
|
|
5
|
-
##
|
|
5
|
+
## Purpose
|
|
6
6
|
|
|
7
|
-
|
|
8
|
-
- **Loading States**: Shows skeleton while loading
|
|
9
|
-
- **Error Handling**: Graceful error display with retry
|
|
10
|
-
- **Customizable**: Custom profile data injection
|
|
11
|
-
- **Action Handler**: Configurable press handler
|
|
12
|
-
- **Avatar Support**: Display user avatar with fallback
|
|
7
|
+
Provides a reusable component for displaying user profile information at the top of the settings screen. Handles loading states, error states, and supports both authenticated and anonymous user profiles with customizable display options.
|
|
13
8
|
|
|
14
|
-
##
|
|
9
|
+
## File Paths
|
|
15
10
|
|
|
16
|
-
|
|
11
|
+
- **Component**: `/Users/umituz/Desktop/github/umituz/apps/artificial_intelligence/npm-packages/react-native-settings/src/presentation/screens/components/sections/ProfileSectionLoader/ProfileSectionLoader.tsx`
|
|
12
|
+
- **Use Profile Info Hook**: `/Users/umituz/Desktop/github/umituz/apps/artificial_intelligence/npm-packages/react-native-settings/src/domain/profile/hooks/useAboutInfo.ts`
|
|
17
13
|
|
|
18
|
-
##
|
|
14
|
+
## Strategy
|
|
19
15
|
|
|
20
|
-
|
|
16
|
+
1. **Data Fetching**: Use useAboutInfo hook to dynamically fetch user profile information when userId is provided
|
|
17
|
+
2. **State Management**: Handle loading, error, and success states with appropriate UI feedback
|
|
18
|
+
3. **Profile Injection**: Support pre-loaded profile data via userProfile prop to bypass fetching
|
|
19
|
+
4. **Avatar Handling**: Display user avatars with fallback options for missing or failed loads
|
|
20
|
+
5. **Anonymous Support**: Clearly distinguish between authenticated and anonymous user profiles
|
|
21
21
|
|
|
22
|
-
|
|
23
|
-
import { ProfileSectionLoader } from '@umituz/react-native-settings';
|
|
22
|
+
## Restrictions
|
|
24
23
|
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
}
|
|
33
|
-
```
|
|
24
|
+
- ❌ DO NOT make API calls directly; always use useAboutInfo hook for data fetching
|
|
25
|
+
- ❌ DO NOT hardcode profile data; always use provided props or fetched data
|
|
26
|
+
- ❌ NEVER ignore error states; always provide error feedback
|
|
27
|
+
- ❌ AVOID bypassing loading states when data is being fetched
|
|
28
|
+
- ❌ DO NOT mix profile display logic with authentication logic
|
|
29
|
+
- ❌ NEVER assume profile data exists; always handle undefined/null cases
|
|
30
|
+
- ❌ AVOID adding authentication actions (sign in/out) within this component
|
|
34
31
|
|
|
35
|
-
|
|
32
|
+
## Rules
|
|
36
33
|
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
};
|
|
34
|
+
- ✅ MUST accept either userProfile or userId prop (not both)
|
|
35
|
+
- ✅ MUST display loading state when fetching profile data
|
|
36
|
+
- ✅ MUST display error state when fetch fails
|
|
37
|
+
- ✅ MUST support anonymous user profiles with distinct visual treatment
|
|
38
|
+
- ✅ MUST provide onPress handler for profile interaction
|
|
39
|
+
- ✅ SHOULD show avatar when available and showAvatar is true
|
|
40
|
+
- ✅ MUST handle missing avatarUrl gracefully
|
|
41
|
+
- ✅ SHOULD use custom loading/error components when provided
|
|
46
42
|
|
|
47
|
-
|
|
48
|
-
<ProfileSectionLoader userProfile={userProfile} />
|
|
49
|
-
);
|
|
50
|
-
}
|
|
51
|
-
```
|
|
43
|
+
## AI Agent Guidelines
|
|
52
44
|
|
|
53
|
-
|
|
45
|
+
When working with ProfileSectionLoader:
|
|
54
46
|
|
|
55
|
-
|
|
56
|
-
function SettingsScreen() {
|
|
57
|
-
const userProfile = {
|
|
58
|
-
displayName: 'Guest',
|
|
59
|
-
userId: 'guest-123',
|
|
60
|
-
isAnonymous: true,
|
|
61
|
-
anonymousDisplayName: 'Guest User',
|
|
62
|
-
onPress: () => navigation.navigate('Auth'),
|
|
63
|
-
};
|
|
47
|
+
1. **Data Source Priority**: Use userProfile prop when data is already available. Use userId prop only when fetching is needed. Never provide both props simultaneously.
|
|
64
48
|
|
|
65
|
-
|
|
66
|
-
<ProfileSectionLoader userProfile={userProfile} />
|
|
67
|
-
);
|
|
68
|
-
}
|
|
69
|
-
```
|
|
49
|
+
2. **Loading States**: Always provide visual feedback during data fetching. Use skeleton loaders or spinner components for better UX.
|
|
70
50
|
|
|
71
|
-
|
|
51
|
+
3. **Error Handling**: Implement retry mechanisms for failed profile fetches. Provide clear error messages to users.
|
|
72
52
|
|
|
73
|
-
|
|
53
|
+
4. **Avatar Management**: Handle avatar loading failures. Implement fallback to initials or default avatar when image fails to load.
|
|
74
54
|
|
|
75
|
-
|
|
76
|
-
|------|------|---------|-------------|
|
|
77
|
-
| `userProfile` | `UserProfile` | `undefined` | Pre-loaded profile data |
|
|
78
|
-
| `userId` | `string` | `undefined` | User ID for fetching profile |
|
|
79
|
-
| `showAvatar` | `boolean` | `true` | Show user avatar |
|
|
80
|
-
| `showEmail` | `boolean` | `true` | Show email address |
|
|
81
|
-
| `onPress` | `() => void` | `undefined` | Press handler |
|
|
82
|
-
| `loadingComponent` | `ReactNode` | `undefined` | Custom loading component |
|
|
83
|
-
| `errorComponent` | `ReactNode` | `undefined` | Custom error component |
|
|
84
|
-
| `style` | `ViewStyle` | `undefined` | Custom container style |
|
|
55
|
+
5. **Anonymous Users**: Clearly distinguish anonymous users from authenticated users. Use different visual treatments (badges, labels, etc.).
|
|
85
56
|
|
|
86
|
-
|
|
57
|
+
6. **Privacy Considerations**: For anonymous users, display minimal information. Do not expose sensitive profile details.
|
|
87
58
|
|
|
88
|
-
|
|
89
|
-
ProfileSectionLoader
|
|
90
|
-
├── Loading State (if loading)
|
|
91
|
-
│ └── Skeleton / LoadingSpinner
|
|
92
|
-
├── Error State (if error)
|
|
93
|
-
│ └── Error message with retry
|
|
94
|
-
└── Profile Content (when loaded)
|
|
95
|
-
├── Avatar
|
|
96
|
-
├── User Info
|
|
97
|
-
│ ├── Display Name
|
|
98
|
-
│ ├── Email (optional)
|
|
99
|
-
│ └── Anonymous badge (if applicable)
|
|
100
|
-
└── Chevron/Arrow
|
|
101
|
-
```
|
|
59
|
+
7. **Customization**: Use custom loading and error components to match app design system. Maintain consistent styling.
|
|
102
60
|
|
|
103
|
-
|
|
61
|
+
8. **Action Handling**: The onPress handler should navigate to account settings or profile edit screen. Do not handle authentication (sign in/out) within this component.
|
|
104
62
|
|
|
105
|
-
|
|
63
|
+
9. **Performance**: Profile data fetching should be efficient. Implement caching strategies to avoid unnecessary refetches.
|
|
106
64
|
|
|
107
|
-
|
|
108
|
-
function ProfileWithLoading() {
|
|
109
|
-
const [profile, setProfile] = useState(null);
|
|
110
|
-
const [loading, setLoading] = useState(true);
|
|
65
|
+
10. **Accessibility**: Add proper accessibility labels for profile elements. Ensure screen readers can announce profile information correctly.
|
|
111
66
|
|
|
112
|
-
|
|
113
|
-
fetchProfile('user123').then(data => {
|
|
114
|
-
setProfile(data);
|
|
115
|
-
setLoading(false);
|
|
116
|
-
});
|
|
117
|
-
}, []);
|
|
67
|
+
11. **Responsive Design**: Ensure profile section displays correctly on different screen sizes and orientations.
|
|
118
68
|
|
|
119
|
-
|
|
120
|
-
return <ProfileSectionLoader loadingComponent={<ProfileSkeleton />} />;
|
|
121
|
-
}
|
|
69
|
+
12. **Integration**: This component should be placed at the top of SettingsContent, before all other sections.
|
|
122
70
|
|
|
123
|
-
|
|
124
|
-
}
|
|
125
|
-
```
|
|
71
|
+
## Related Components
|
|
126
72
|
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
const [error, setError] = useState(null);
|
|
132
|
-
const [profile, setProfile] = useState(null);
|
|
133
|
-
|
|
134
|
-
useEffect(() => {
|
|
135
|
-
fetchProfile('user123')
|
|
136
|
-
.then(setProfile)
|
|
137
|
-
.catch(setError);
|
|
138
|
-
}, []);
|
|
139
|
-
|
|
140
|
-
if (error) {
|
|
141
|
-
return (
|
|
142
|
-
<ProfileSectionLoader
|
|
143
|
-
errorComponent={
|
|
144
|
-
<ProfileError
|
|
145
|
-
message="Failed to load profile"
|
|
146
|
-
onRetry={() => window.location.reload()}
|
|
147
|
-
/>
|
|
148
|
-
}
|
|
149
|
-
/>
|
|
150
|
-
);
|
|
151
|
-
}
|
|
152
|
-
|
|
153
|
-
return <ProfileSectionLoader userProfile={profile} />;
|
|
154
|
-
}
|
|
155
|
-
```
|
|
156
|
-
|
|
157
|
-
### Custom Avatar Service
|
|
158
|
-
|
|
159
|
-
```tsx
|
|
160
|
-
function CustomAvatarProfile() {
|
|
161
|
-
const profile = {
|
|
162
|
-
displayName: 'John Doe',
|
|
163
|
-
userId: 'user123',
|
|
164
|
-
avatarUrl: 'https://ui-avatars.com/api/?name=John+Doe&background=2196F3&color=fff',
|
|
165
|
-
onPress: () => navigation.navigate('Account'),
|
|
166
|
-
};
|
|
167
|
-
|
|
168
|
-
return <ProfileSectionLoader userProfile={profile} />;
|
|
169
|
-
}
|
|
170
|
-
```
|
|
171
|
-
|
|
172
|
-
### With Sign Out Action
|
|
173
|
-
|
|
174
|
-
```tsx
|
|
175
|
-
function ProfileWithSignOut() {
|
|
176
|
-
const [profile, setProfile] = useState(null);
|
|
177
|
-
const navigation = useNavigation();
|
|
178
|
-
|
|
179
|
-
const handleSignOut = async () => {
|
|
180
|
-
await signOut();
|
|
181
|
-
navigation.reset({ index: 0, routes: [{ name: 'Login' }] });
|
|
182
|
-
};
|
|
183
|
-
|
|
184
|
-
return (
|
|
185
|
-
<View>
|
|
186
|
-
<ProfileSectionLoader userProfile={profile} />
|
|
187
|
-
|
|
188
|
-
<TouchableOpacity onPress={handleSignOut} style={styles.signOut}>
|
|
189
|
-
<Text>Sign Out</Text>
|
|
190
|
-
</TouchableOpacity>
|
|
191
|
-
</View>
|
|
192
|
-
);
|
|
193
|
-
}
|
|
194
|
-
```
|
|
195
|
-
|
|
196
|
-
### Anonymous vs Authenticated
|
|
197
|
-
|
|
198
|
-
```tsx
|
|
199
|
-
function AdaptiveProfile() {
|
|
200
|
-
const user = useAuth();
|
|
201
|
-
|
|
202
|
-
if (user?.isAnonymous) {
|
|
203
|
-
return (
|
|
204
|
-
<ProfileSectionLoader
|
|
205
|
-
userProfile={{
|
|
206
|
-
displayName: 'Guest',
|
|
207
|
-
isAnonymous: true,
|
|
208
|
-
anonymousDisplayName: 'Guest User',
|
|
209
|
-
onPress: () => navigation.navigate('SignIn'),
|
|
210
|
-
}}
|
|
211
|
-
/>
|
|
212
|
-
);
|
|
213
|
-
}
|
|
214
|
-
|
|
215
|
-
return (
|
|
216
|
-
<ProfileSectionLoader
|
|
217
|
-
userProfile={{
|
|
218
|
-
displayName: user.displayName,
|
|
219
|
-
userId: user.uid,
|
|
220
|
-
avatarUrl: user.photoURL,
|
|
221
|
-
isAnonymous: false,
|
|
222
|
-
onPress: () => navigation.navigate('Account'),
|
|
223
|
-
}}
|
|
224
|
-
/>
|
|
225
|
-
);
|
|
226
|
-
}
|
|
227
|
-
```
|
|
228
|
-
|
|
229
|
-
## Data Types
|
|
230
|
-
|
|
231
|
-
### UserProfile
|
|
232
|
-
|
|
233
|
-
```typescript
|
|
234
|
-
interface UserProfile {
|
|
235
|
-
displayName: string; // Display name
|
|
236
|
-
userId: string; // User ID
|
|
237
|
-
avatarUrl?: string; // Avatar URL
|
|
238
|
-
isAnonymous?: boolean; // Anonymous user flag
|
|
239
|
-
anonymousDisplayName?: string; // Anonymous display name
|
|
240
|
-
avatarServiceUrl?: string; // Avatar service URL
|
|
241
|
-
accountSettingsRoute?: string; // Account settings route
|
|
242
|
-
onPress?: () => void; // Press handler
|
|
243
|
-
}
|
|
244
|
-
```
|
|
245
|
-
|
|
246
|
-
## Styling
|
|
247
|
-
|
|
248
|
-
### Default Styles
|
|
249
|
-
|
|
250
|
-
```typescript
|
|
251
|
-
const styles = StyleSheet.create({
|
|
252
|
-
container: {
|
|
253
|
-
flexDirection: 'row',
|
|
254
|
-
alignItems: 'center',
|
|
255
|
-
padding: tokens.spacing.lg,
|
|
256
|
-
backgroundColor: tokens.colors.surface,
|
|
257
|
-
},
|
|
258
|
-
avatar: {
|
|
259
|
-
width: 60,
|
|
260
|
-
height: 60,
|
|
261
|
-
borderRadius: 30,
|
|
262
|
-
marginRight: tokens.spacing.md,
|
|
263
|
-
},
|
|
264
|
-
content: {
|
|
265
|
-
flex: 1,
|
|
266
|
-
},
|
|
267
|
-
displayName: {
|
|
268
|
-
fontSize: tokens.typography.fontSize.lg,
|
|
269
|
-
fontWeight: '600',
|
|
270
|
-
color: tokens.colors.textPrimary,
|
|
271
|
-
},
|
|
272
|
-
email: {
|
|
273
|
-
fontSize: tokens.typography.fontSize.sm,
|
|
274
|
-
color: tokens.colors.textSecondary,
|
|
275
|
-
marginTop: 2,
|
|
276
|
-
},
|
|
277
|
-
anonymousBadge: {
|
|
278
|
-
backgroundColor: tokens.colors.warning,
|
|
279
|
-
paddingHorizontal: 8,
|
|
280
|
-
paddingVertical: 2,
|
|
281
|
-
borderRadius: 4,
|
|
282
|
-
marginTop: 4,
|
|
283
|
-
alignSelf: 'flex-start',
|
|
284
|
-
},
|
|
285
|
-
anonymousText: {
|
|
286
|
-
fontSize: tokens.typography.fontSize.xs,
|
|
287
|
-
color: tokens.colors.surface,
|
|
288
|
-
fontWeight: '600',
|
|
289
|
-
},
|
|
290
|
-
chevron: {
|
|
291
|
-
marginLeft: tokens.spacing.sm,
|
|
292
|
-
},
|
|
293
|
-
});
|
|
294
|
-
```
|
|
295
|
-
|
|
296
|
-
### Custom Styling
|
|
297
|
-
|
|
298
|
-
```tsx
|
|
299
|
-
<ProfileSectionLoader
|
|
300
|
-
userProfile={profile}
|
|
301
|
-
style={{
|
|
302
|
-
backgroundColor: '#f5f5f5',
|
|
303
|
-
paddingVertical: 20,
|
|
304
|
-
borderBottomWidth: 1,
|
|
305
|
-
borderBottomColor: '#e0e0e0',
|
|
306
|
-
}}
|
|
307
|
-
/>
|
|
308
|
-
```
|
|
309
|
-
|
|
310
|
-
### Avatar Styling
|
|
311
|
-
|
|
312
|
-
```tsx
|
|
313
|
-
function CustomAvatarProfile() {
|
|
314
|
-
return (
|
|
315
|
-
<ProfileSectionLoader
|
|
316
|
-
userProfile={profile}
|
|
317
|
-
avatarStyle={{
|
|
318
|
-
borderWidth: 2,
|
|
319
|
-
borderColor: '#2196F3',
|
|
320
|
-
}}
|
|
321
|
-
/>
|
|
322
|
-
);
|
|
323
|
-
}
|
|
324
|
-
```
|
|
325
|
-
|
|
326
|
-
## Loading States
|
|
327
|
-
|
|
328
|
-
### Skeleton Loader
|
|
329
|
-
|
|
330
|
-
```tsx
|
|
331
|
-
function ProfileSkeleton() {
|
|
332
|
-
return (
|
|
333
|
-
<View style={styles.container}>
|
|
334
|
-
<View style={[styles.avatar, styles.skeleton]} />
|
|
335
|
-
<View style={styles.content}>
|
|
336
|
-
<View style={[styles.text, styles.skeleton]} />
|
|
337
|
-
<View style={[styles.textSm, styles.skeleton]} />
|
|
338
|
-
</View>
|
|
339
|
-
</View>
|
|
340
|
-
);
|
|
341
|
-
}
|
|
342
|
-
|
|
343
|
-
const skeletonStyles = StyleSheet.create({
|
|
344
|
-
skeleton: {
|
|
345
|
-
backgroundColor: '#e0e0e0',
|
|
346
|
-
},
|
|
347
|
-
text: {
|
|
348
|
-
height: 20,
|
|
349
|
-
width: 150,
|
|
350
|
-
borderRadius: 4,
|
|
351
|
-
},
|
|
352
|
-
textSm: {
|
|
353
|
-
height: 16,
|
|
354
|
-
width: 200,
|
|
355
|
-
borderRadius: 4,
|
|
356
|
-
marginTop: 8,
|
|
357
|
-
},
|
|
358
|
-
});
|
|
359
|
-
```
|
|
360
|
-
|
|
361
|
-
### Spinner Loader
|
|
362
|
-
|
|
363
|
-
```tsx
|
|
364
|
-
function SpinnerLoader() {
|
|
365
|
-
return (
|
|
366
|
-
<View style={styles.loaderContainer}>
|
|
367
|
-
<ActivityIndicator size="large" color="#2196F3" />
|
|
368
|
-
<Text style={styles.loadingText}>Loading profile...</Text>
|
|
369
|
-
</View>
|
|
370
|
-
);
|
|
371
|
-
}
|
|
372
|
-
```
|
|
373
|
-
|
|
374
|
-
## Error States
|
|
375
|
-
|
|
376
|
-
### Error Message with Retry
|
|
377
|
-
|
|
378
|
-
```tsx
|
|
379
|
-
function ProfileError({ message, onRetry }) {
|
|
380
|
-
return (
|
|
381
|
-
<View style={styles.errorContainer}>
|
|
382
|
-
<Ionicons name="person-outline" size={48} color="#ccc" />
|
|
383
|
-
<Text style={styles.errorTitle}>Profile Error</Text>
|
|
384
|
-
<Text style={styles.errorMessage}>{message}</Text>
|
|
385
|
-
<Button onPress={onRetry} title="Retry" />
|
|
386
|
-
</View>
|
|
387
|
-
);
|
|
388
|
-
}
|
|
389
|
-
```
|
|
390
|
-
|
|
391
|
-
### Fallback Display
|
|
392
|
-
|
|
393
|
-
```tsx
|
|
394
|
-
function ProfileFallback({ onPress }) {
|
|
395
|
-
return (
|
|
396
|
-
<TouchableOpacity onPress={onPress} style={styles.container}>
|
|
397
|
-
<View style={styles.avatarPlaceholder}>
|
|
398
|
-
<Ionicons name="person-outline" size={32} color="#999" />
|
|
399
|
-
</View>
|
|
400
|
-
<View style={styles.content}>
|
|
401
|
-
<Text style={styles.name}>Sign In</Text>
|
|
402
|
-
<Text style={styles.description}>Access your profile</Text>
|
|
403
|
-
</View>
|
|
404
|
-
<Ionicons name="chevron-forward" size={24} color="#999" />
|
|
405
|
-
</TouchableOpacity>
|
|
406
|
-
);
|
|
407
|
-
}
|
|
408
|
-
```
|
|
409
|
-
|
|
410
|
-
## Avatar Sources
|
|
411
|
-
|
|
412
|
-
### From URL
|
|
413
|
-
|
|
414
|
-
```tsx
|
|
415
|
-
const profile = {
|
|
416
|
-
displayName: 'John Doe',
|
|
417
|
-
avatarUrl: 'https://example.com/avatar.jpg',
|
|
418
|
-
};
|
|
419
|
-
```
|
|
420
|
-
|
|
421
|
-
### From Avatar Service
|
|
422
|
-
|
|
423
|
-
```tsx
|
|
424
|
-
const profile = {
|
|
425
|
-
displayName: 'John Doe',
|
|
426
|
-
avatarServiceUrl: 'https://ui-avatars.com/api/?name=John+Doe',
|
|
427
|
-
};
|
|
428
|
-
```
|
|
429
|
-
|
|
430
|
-
### From Local Storage
|
|
431
|
-
|
|
432
|
-
```tsx
|
|
433
|
-
const profile = {
|
|
434
|
-
displayName: 'John Doe',
|
|
435
|
-
avatarUrl: require('../../assets/images/default-avatar.png'),
|
|
436
|
-
};
|
|
437
|
-
```
|
|
438
|
-
|
|
439
|
-
### Initials Fallback
|
|
440
|
-
|
|
441
|
-
```tsx
|
|
442
|
-
function AvatarWithInitials({ displayName }) {
|
|
443
|
-
const initials = displayName
|
|
444
|
-
.split(' ')
|
|
445
|
-
.map(name => name[0])
|
|
446
|
-
.join('')
|
|
447
|
-
.toUpperCase()
|
|
448
|
-
.slice(0, 2);
|
|
449
|
-
|
|
450
|
-
return (
|
|
451
|
-
<View style={styles.avatar}>
|
|
452
|
-
{avatarUrl ? (
|
|
453
|
-
<Image source={{ uri: avatarUrl }} style={styles.image} />
|
|
454
|
-
) : (
|
|
455
|
-
<Text style={styles.initials}>{initials}</Text>
|
|
456
|
-
)}
|
|
457
|
-
</View>
|
|
458
|
-
);
|
|
459
|
-
}
|
|
460
|
-
```
|
|
461
|
-
|
|
462
|
-
## Best Practices
|
|
463
|
-
|
|
464
|
-
1. **Loading States**: Always show loading indicator
|
|
465
|
-
2. **Error Handling**: Provide retry options on error
|
|
466
|
-
3. **Avatar Fallbacks**: Use initials or default avatar
|
|
467
|
-
4. **Anonymous Users**: Clearly indicate anonymous status
|
|
468
|
-
5. **Press Handler**: Always provide press handler
|
|
469
|
-
6. **Privacy**: Show minimal info for anonymous users
|
|
470
|
-
7. **Accessibility**: Add proper accessibility labels
|
|
471
|
-
|
|
472
|
-
## Related
|
|
473
|
-
|
|
474
|
-
- **SettingsContent**: Content component
|
|
475
|
-
- **SettingsScreen**: Main screen component
|
|
476
|
-
- **UserProfile**: Profile type definition
|
|
477
|
-
|
|
478
|
-
## License
|
|
479
|
-
|
|
480
|
-
MIT
|
|
73
|
+
- **Settings Content**: Content component that uses ProfileSectionLoader
|
|
74
|
+
- **Settings Screen**: Main screen component
|
|
75
|
+
- **User Profile**: Profile type definition
|
|
76
|
+
- **Use About Info**: Hook for fetching profile information
|