@umituz/react-native-settings 4.20.55 → 4.20.57
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/README.md +145 -3
- package/package.json +1 -2
- package/src/application/README.md +322 -0
- package/src/domains/about/README.md +452 -0
- package/src/domains/about/presentation/hooks/README.md +350 -0
- package/src/domains/appearance/README.md +596 -0
- package/src/domains/appearance/hooks/README.md +366 -0
- package/src/domains/appearance/infrastructure/services/README.md +455 -0
- package/src/domains/cloud-sync/README.md +451 -0
- package/src/domains/cloud-sync/presentation/components/README.md +493 -0
- package/src/domains/dev/README.md +477 -0
- package/src/domains/disclaimer/README.md +421 -0
- package/src/domains/disclaimer/presentation/components/README.md +394 -0
- package/src/domains/faqs/README.md +586 -0
- package/src/domains/feedback/README.md +565 -0
- package/src/domains/feedback/presentation/hooks/README.md +428 -0
- package/src/domains/legal/README.md +549 -0
- package/src/domains/rating/README.md +452 -0
- package/src/domains/rating/presentation/components/README.md +475 -0
- package/src/domains/video-tutorials/README.md +482 -0
- package/src/domains/video-tutorials/presentation/components/README.md +433 -0
- package/src/infrastructure/README.md +509 -0
- package/src/infrastructure/repositories/README.md +475 -0
- package/src/infrastructure/services/README.md +510 -0
- package/src/presentation/components/README.md +482 -0
- package/src/presentation/components/SettingsErrorBoundary/README.md +461 -0
- package/src/presentation/components/SettingsFooter/README.md +446 -0
- package/src/presentation/components/SettingsItemCard/README.md +457 -0
- package/src/presentation/components/SettingsSection/README.md +421 -0
- package/src/presentation/hooks/README.md +413 -0
- package/src/presentation/hooks/mutations/README.md +430 -0
- package/src/presentation/hooks/queries/README.md +441 -0
- package/src/presentation/navigation/README.md +532 -0
- package/src/presentation/navigation/components/README.md +330 -0
- package/src/presentation/navigation/hooks/README.md +399 -0
- package/src/presentation/navigation/utils/README.md +442 -0
- package/src/presentation/screens/README.md +525 -0
- package/src/presentation/screens/components/SettingsContent/README.md +404 -0
- package/src/presentation/screens/components/SettingsHeader/README.md +322 -0
- package/src/presentation/screens/components/sections/CustomSettingsList/README.md +388 -0
- package/src/presentation/screens/components/sections/FeatureSettingsSection/README.md +232 -0
- package/src/presentation/screens/components/sections/IdentitySettingsSection/README.md +325 -0
- package/src/presentation/screens/components/sections/ProfileSectionLoader/README.md +480 -0
- package/src/presentation/screens/components/sections/SupportSettingsSection/README.md +391 -0
- package/src/presentation/screens/hooks/README.md +383 -0
- package/src/presentation/screens/types/README.md +439 -0
- package/src/presentation/screens/utils/README.md +288 -0
|
@@ -0,0 +1,480 @@
|
|
|
1
|
+
# ProfileSectionLoader
|
|
2
|
+
|
|
3
|
+
Dynamic loader component that fetches and displays user profile information in the settings screen header.
|
|
4
|
+
|
|
5
|
+
## Features
|
|
6
|
+
|
|
7
|
+
- **Dynamic Loading**: Fetches user profile data on mount
|
|
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
|
|
13
|
+
|
|
14
|
+
## Installation
|
|
15
|
+
|
|
16
|
+
This component is part of `@umituz/react-native-settings`.
|
|
17
|
+
|
|
18
|
+
## Usage
|
|
19
|
+
|
|
20
|
+
### Basic Usage
|
|
21
|
+
|
|
22
|
+
```tsx
|
|
23
|
+
import { ProfileSectionLoader } from '@umituz/react-native-settings';
|
|
24
|
+
|
|
25
|
+
function SettingsScreen() {
|
|
26
|
+
return (
|
|
27
|
+
<ProfileSectionLoader
|
|
28
|
+
userId="user123"
|
|
29
|
+
onPress={() => navigation.navigate('Account')}
|
|
30
|
+
/>
|
|
31
|
+
);
|
|
32
|
+
}
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
### With Custom Profile Data
|
|
36
|
+
|
|
37
|
+
```tsx
|
|
38
|
+
function SettingsScreen() {
|
|
39
|
+
const userProfile = {
|
|
40
|
+
displayName: 'John Doe',
|
|
41
|
+
userId: 'user123',
|
|
42
|
+
avatarUrl: 'https://example.com/avatar.jpg',
|
|
43
|
+
isAnonymous: false,
|
|
44
|
+
onPress: () => navigation.navigate('Account'),
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
return (
|
|
48
|
+
<ProfileSectionLoader userProfile={userProfile} />
|
|
49
|
+
);
|
|
50
|
+
}
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
### With Anonymous User
|
|
54
|
+
|
|
55
|
+
```tsx
|
|
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
|
+
};
|
|
64
|
+
|
|
65
|
+
return (
|
|
66
|
+
<ProfileSectionLoader userProfile={userProfile} />
|
|
67
|
+
);
|
|
68
|
+
}
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
## Props
|
|
72
|
+
|
|
73
|
+
### ProfileSectionLoaderProps
|
|
74
|
+
|
|
75
|
+
| Prop | Type | Default | Description |
|
|
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 |
|
|
85
|
+
|
|
86
|
+
## Component Structure
|
|
87
|
+
|
|
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
|
+
```
|
|
102
|
+
|
|
103
|
+
## Examples
|
|
104
|
+
|
|
105
|
+
### With Loading State
|
|
106
|
+
|
|
107
|
+
```tsx
|
|
108
|
+
function ProfileWithLoading() {
|
|
109
|
+
const [profile, setProfile] = useState(null);
|
|
110
|
+
const [loading, setLoading] = useState(true);
|
|
111
|
+
|
|
112
|
+
useEffect(() => {
|
|
113
|
+
fetchProfile('user123').then(data => {
|
|
114
|
+
setProfile(data);
|
|
115
|
+
setLoading(false);
|
|
116
|
+
});
|
|
117
|
+
}, []);
|
|
118
|
+
|
|
119
|
+
if (loading) {
|
|
120
|
+
return <ProfileSectionLoader loadingComponent={<ProfileSkeleton />} />;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
return <ProfileSectionLoader userProfile={profile} />;
|
|
124
|
+
}
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
### With Error Handling
|
|
128
|
+
|
|
129
|
+
```tsx
|
|
130
|
+
function ProfileWithError() {
|
|
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
|