@umituz/react-native-settings 4.20.56 → 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,482 @@
|
|
|
1
|
+
# Video Tutorials Domain
|
|
2
|
+
|
|
3
|
+
The Video Tutorials domain provides components for displaying and managing video tutorials in your React Native app. It supports featured tutorials, categorized lists, and external video linking.
|
|
4
|
+
|
|
5
|
+
## Features
|
|
6
|
+
|
|
7
|
+
- **Video Tutorials Screen**: Full-screen viewer for tutorial collections
|
|
8
|
+
- **Featured Tutorials**: Horizontal scrolling list for featured content
|
|
9
|
+
- **Tutorial Cards**: Rich cards with thumbnails, titles, and metadata
|
|
10
|
+
- **Categorized Sections**: Organize tutorials by topic or category
|
|
11
|
+
- **Loading States**: Built-in loading and empty states
|
|
12
|
+
- **External Video Support**: Link to YouTube, Vimeo, and other platforms
|
|
13
|
+
|
|
14
|
+
## Installation
|
|
15
|
+
|
|
16
|
+
This domain is part of `@umituz/react-native-settings`. Install the package to use it:
|
|
17
|
+
|
|
18
|
+
```bash
|
|
19
|
+
npm install @umituz/react-native-settings
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
## Components
|
|
23
|
+
|
|
24
|
+
### VideoTutorialsScreen
|
|
25
|
+
|
|
26
|
+
Main screen for displaying video tutorials with featured and all tutorials sections.
|
|
27
|
+
|
|
28
|
+
```tsx
|
|
29
|
+
import { VideoTutorialsScreen } from '@umituz/react-native-settings';
|
|
30
|
+
|
|
31
|
+
function MyVideoTutorials() {
|
|
32
|
+
const tutorials = [
|
|
33
|
+
{
|
|
34
|
+
id: '1',
|
|
35
|
+
title: 'Getting Started',
|
|
36
|
+
description: 'Learn the basics',
|
|
37
|
+
thumbnailUrl: 'https://example.com/thumb1.jpg',
|
|
38
|
+
videoUrl: 'https://youtube.com/watch?v=xxx',
|
|
39
|
+
duration: '5:30',
|
|
40
|
+
category: 'Basics',
|
|
41
|
+
},
|
|
42
|
+
// ... more tutorials
|
|
43
|
+
];
|
|
44
|
+
|
|
45
|
+
return (
|
|
46
|
+
<VideoTutorialsScreen
|
|
47
|
+
tutorials={tutorials}
|
|
48
|
+
featuredTutorials={tutorials.slice(0, 3)}
|
|
49
|
+
title="Video Tutorials"
|
|
50
|
+
onTutorialPress={(tutorial) => {
|
|
51
|
+
// Open video player or navigate
|
|
52
|
+
openVideo(tutorial.videoUrl);
|
|
53
|
+
}}
|
|
54
|
+
/>
|
|
55
|
+
);
|
|
56
|
+
}
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
#### Props
|
|
60
|
+
|
|
61
|
+
| Prop | Type | Default | Description |
|
|
62
|
+
|------|------|---------|-------------|
|
|
63
|
+
| `tutorials` | `VideoTutorial[]` | **Required** | All tutorials to display |
|
|
64
|
+
| `featuredTutorials` | `VideoTutorial[]` | `undefined` | Featured tutorials |
|
|
65
|
+
| `title` | `string` | `'Video Tutorials'` | Screen title |
|
|
66
|
+
| `featuredTitle` | `string` | `'Featured'` | Featured section title |
|
|
67
|
+
| `allTutorialsTitle` | `string` | `'All Tutorials'` | All tutorials section title |
|
|
68
|
+
| `emptyMessage` | `string` | `'No tutorials available'` | Empty state message |
|
|
69
|
+
| `isLoading` | `boolean` | `false` | Loading state |
|
|
70
|
+
| `onTutorialPress` | `(tutorial) => void` | `undefined` | Tutorial press handler |
|
|
71
|
+
|
|
72
|
+
### VideoTutorialCard
|
|
73
|
+
|
|
74
|
+
Individual tutorial card with thumbnail, title, and metadata.
|
|
75
|
+
|
|
76
|
+
```tsx
|
|
77
|
+
import { VideoTutorialCard } from '@umituz/react-native-settings';
|
|
78
|
+
|
|
79
|
+
function MyTutorialCard() {
|
|
80
|
+
const tutorial = {
|
|
81
|
+
id: '1',
|
|
82
|
+
title: 'Tutorial Title',
|
|
83
|
+
description: 'Tutorial description',
|
|
84
|
+
thumbnailUrl: 'https://example.com/thumb.jpg',
|
|
85
|
+
videoUrl: 'https://youtube.com/watch?v=xxx',
|
|
86
|
+
duration: '10:25',
|
|
87
|
+
views: 1500,
|
|
88
|
+
};
|
|
89
|
+
|
|
90
|
+
return (
|
|
91
|
+
<VideoTutorialCard
|
|
92
|
+
tutorial={tutorial}
|
|
93
|
+
onPress={() => console.log('Play video')}
|
|
94
|
+
/>
|
|
95
|
+
);
|
|
96
|
+
}
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
#### Props
|
|
100
|
+
|
|
101
|
+
| Prop | Type | Default | Description |
|
|
102
|
+
|------|------|---------|-------------|
|
|
103
|
+
| `tutorial` | `VideoTutorial` | **Required** | Tutorial data |
|
|
104
|
+
| `onPress` | `() => void` | **Required** | Press handler |
|
|
105
|
+
| `horizontal` | `boolean` | `false` | Horizontal card variant |
|
|
106
|
+
|
|
107
|
+
### VideoTutorialSection
|
|
108
|
+
|
|
109
|
+
Section component for grouping tutorials by category.
|
|
110
|
+
|
|
111
|
+
```tsx
|
|
112
|
+
import { VideoTutorialSection } from '@umituz/react-native-settings';
|
|
113
|
+
|
|
114
|
+
function MyTutorialSection() {
|
|
115
|
+
const tutorials = [ /* tutorial data */ ];
|
|
116
|
+
|
|
117
|
+
return (
|
|
118
|
+
<VideoTutorialSection
|
|
119
|
+
title="Getting Started"
|
|
120
|
+
tutorials={tutorials}
|
|
121
|
+
onTutorialPress={(tutorial) => playVideo(tutorial)}
|
|
122
|
+
/>
|
|
123
|
+
);
|
|
124
|
+
}
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
#### Props
|
|
128
|
+
|
|
129
|
+
| Prop | Type | Default | Description |
|
|
130
|
+
|------|------|---------|-------------|
|
|
131
|
+
| `title` | `string` | **Required** | Section title |
|
|
132
|
+
| `tutorials` | `VideoTutorial[]` | **Required** | Tutorials in section |
|
|
133
|
+
| `onTutorialPress` | `(tutorial) => void` | **Required** | Tutorial press handler |
|
|
134
|
+
|
|
135
|
+
## Types
|
|
136
|
+
|
|
137
|
+
### VideoTutorial
|
|
138
|
+
|
|
139
|
+
```typescript
|
|
140
|
+
interface VideoTutorial {
|
|
141
|
+
id: string;
|
|
142
|
+
title: string;
|
|
143
|
+
description?: string;
|
|
144
|
+
thumbnailUrl?: string;
|
|
145
|
+
videoUrl: string;
|
|
146
|
+
duration?: string;
|
|
147
|
+
views?: number;
|
|
148
|
+
category?: string;
|
|
149
|
+
publishedAt?: string;
|
|
150
|
+
author?: string;
|
|
151
|
+
}
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
## Examples
|
|
155
|
+
|
|
156
|
+
### Basic Video Tutorials Screen
|
|
157
|
+
|
|
158
|
+
```tsx
|
|
159
|
+
import React from 'react';
|
|
160
|
+
import { VideoTutorialsScreen } from '@umituz/react-native-settings';
|
|
161
|
+
|
|
162
|
+
const TUTORIALS = [
|
|
163
|
+
{
|
|
164
|
+
id: '1',
|
|
165
|
+
title: 'Introduction to the App',
|
|
166
|
+
description: 'Learn the basic features',
|
|
167
|
+
thumbnailUrl: 'https://picsum.photos/300/200?random=1',
|
|
168
|
+
videoUrl: 'https://youtube.com/watch?v=abc123',
|
|
169
|
+
duration: '5:30',
|
|
170
|
+
category: 'Getting Started',
|
|
171
|
+
views: 12500,
|
|
172
|
+
},
|
|
173
|
+
{
|
|
174
|
+
id: '2',
|
|
175
|
+
title: 'Advanced Features',
|
|
176
|
+
description: 'Master advanced functionality',
|
|
177
|
+
thumbnailUrl: 'https://picsum.photos/300/200?random=2',
|
|
178
|
+
videoUrl: 'https://youtube.com/watch?v=def456',
|
|
179
|
+
duration: '12:45',
|
|
180
|
+
category: 'Advanced',
|
|
181
|
+
views: 8300,
|
|
182
|
+
},
|
|
183
|
+
{
|
|
184
|
+
id: '3',
|
|
185
|
+
title: 'Tips and Tricks',
|
|
186
|
+
description: 'Helpful tips for power users',
|
|
187
|
+
thumbnailUrl: 'https://picsum.photos/300/200?random=3',
|
|
188
|
+
videoUrl: 'https://youtube.com/watch?v=ghi789',
|
|
189
|
+
duration: '8:15',
|
|
190
|
+
category: 'Tips',
|
|
191
|
+
views: 15600,
|
|
192
|
+
},
|
|
193
|
+
];
|
|
194
|
+
|
|
195
|
+
export default function TutorialsScreen() {
|
|
196
|
+
return (
|
|
197
|
+
<VideoTutorialsScreen
|
|
198
|
+
tutorials={TUTORIALS}
|
|
199
|
+
featuredTutorials={TUTORIALS.slice(0, 2)}
|
|
200
|
+
title="Help & Tutorials"
|
|
201
|
+
featuredTitle="Featured Videos"
|
|
202
|
+
allTutorialsTitle="All Tutorials"
|
|
203
|
+
onTutorialPress={(tutorial) => {
|
|
204
|
+
// Open in WebView or navigate to video player
|
|
205
|
+
navigation.navigate('VideoPlayer', { tutorial });
|
|
206
|
+
}}
|
|
207
|
+
/>
|
|
208
|
+
);
|
|
209
|
+
}
|
|
210
|
+
```
|
|
211
|
+
|
|
212
|
+
### With Loading State
|
|
213
|
+
|
|
214
|
+
```tsx
|
|
215
|
+
function TutorialsScreenWithLoading() {
|
|
216
|
+
const [tutorials, setTutorials] = useState([]);
|
|
217
|
+
const [loading, setLoading] = useState(true);
|
|
218
|
+
|
|
219
|
+
useEffect(() => {
|
|
220
|
+
loadTutorials();
|
|
221
|
+
}, []);
|
|
222
|
+
|
|
223
|
+
const loadTutorials = async () => {
|
|
224
|
+
try {
|
|
225
|
+
const data = await api.fetchTutorials();
|
|
226
|
+
setTutorials(data);
|
|
227
|
+
} catch (error) {
|
|
228
|
+
console.error('Failed to load tutorials:', error);
|
|
229
|
+
} finally {
|
|
230
|
+
setLoading(false);
|
|
231
|
+
}
|
|
232
|
+
};
|
|
233
|
+
|
|
234
|
+
return (
|
|
235
|
+
<VideoTutorialsScreen
|
|
236
|
+
tutorials={tutorials}
|
|
237
|
+
isLoading={loading}
|
|
238
|
+
onTutorialPress={handleTutorialPress}
|
|
239
|
+
/>
|
|
240
|
+
);
|
|
241
|
+
}
|
|
242
|
+
```
|
|
243
|
+
|
|
244
|
+
### Custom Empty State
|
|
245
|
+
|
|
246
|
+
```tsx
|
|
247
|
+
function EmptyTutorialsScreen() {
|
|
248
|
+
return (
|
|
249
|
+
<VideoTutorialsScreen
|
|
250
|
+
tutorials={[]}
|
|
251
|
+
emptyMessage="No tutorials available right now. Check back later!"
|
|
252
|
+
onTutorialPress={() => {}}
|
|
253
|
+
/>
|
|
254
|
+
);
|
|
255
|
+
}
|
|
256
|
+
```
|
|
257
|
+
|
|
258
|
+
### With Video Player Integration
|
|
259
|
+
|
|
260
|
+
```tsx
|
|
261
|
+
import { VideoTutorialsScreen } from '@umituz/react-native-settings';
|
|
262
|
+
import { WebView } from 'react-native-webview';
|
|
263
|
+
|
|
264
|
+
function TutorialsWithPlayer() {
|
|
265
|
+
const [selectedTutorial, setSelectedTutorial] = useState(null);
|
|
266
|
+
|
|
267
|
+
if (selectedTutorial) {
|
|
268
|
+
return (
|
|
269
|
+
<WebView
|
|
270
|
+
source={{ uri: selectedTutorial.videoUrl }}
|
|
271
|
+
style={{ flex: 1 }}
|
|
272
|
+
/>
|
|
273
|
+
);
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
return (
|
|
277
|
+
<VideoTutorialsScreen
|
|
278
|
+
tutorials={TUTORIALS}
|
|
279
|
+
onTutorialPress={setSelectedTutorial}
|
|
280
|
+
/>
|
|
281
|
+
);
|
|
282
|
+
}
|
|
283
|
+
```
|
|
284
|
+
|
|
285
|
+
### Using Tutorial Cards Directly
|
|
286
|
+
|
|
287
|
+
```tsx
|
|
288
|
+
import { VideoTutorialCard } from '@umituz/react-native-settings';
|
|
289
|
+
import { ScrollView } from 'react-native';
|
|
290
|
+
|
|
291
|
+
function CustomTutorialsList() {
|
|
292
|
+
return (
|
|
293
|
+
<ScrollView>
|
|
294
|
+
{TUTORIALS.map((tutorial) => (
|
|
295
|
+
<VideoTutorialCard
|
|
296
|
+
key={tutorial.id}
|
|
297
|
+
tutorial={tutorial}
|
|
298
|
+
onPress={() => playVideo(tutorial)}
|
|
299
|
+
/>
|
|
300
|
+
))}
|
|
301
|
+
</ScrollView>
|
|
302
|
+
);
|
|
303
|
+
}
|
|
304
|
+
```
|
|
305
|
+
|
|
306
|
+
### Horizontal Featured Section
|
|
307
|
+
|
|
308
|
+
```tsx
|
|
309
|
+
function FeaturedSection() {
|
|
310
|
+
const featuredTutorials = TUTORIALS.filter(t => t.featured);
|
|
311
|
+
|
|
312
|
+
return (
|
|
313
|
+
<View>
|
|
314
|
+
<Text style={{ fontSize: 20, fontWeight: 'bold', marginBottom: 12 }}>
|
|
315
|
+
Featured Tutorials
|
|
316
|
+
</Text>
|
|
317
|
+
<ScrollView horizontal showsHorizontalScrollIndicator={false}>
|
|
318
|
+
{featuredTutorials.map((tutorial) => (
|
|
319
|
+
<View key={tutorial.id} style={{ marginRight: 12 }}>
|
|
320
|
+
<VideoTutorialCard
|
|
321
|
+
tutorial={tutorial}
|
|
322
|
+
horizontal={true}
|
|
323
|
+
onPress={() => playVideo(tutorial)}
|
|
324
|
+
/>
|
|
325
|
+
</View>
|
|
326
|
+
))}
|
|
327
|
+
</ScrollView>
|
|
328
|
+
</View>
|
|
329
|
+
);
|
|
330
|
+
}
|
|
331
|
+
```
|
|
332
|
+
|
|
333
|
+
### Categorized Tutorials
|
|
334
|
+
|
|
335
|
+
```tsx
|
|
336
|
+
function CategorizedTutorialsScreen() {
|
|
337
|
+
const categories = {
|
|
338
|
+
'Getting Started': TUTORIALS.filter(t => t.category === 'Getting Started'),
|
|
339
|
+
'Advanced': TUTORIALS.filter(t => t.category === 'Advanced'),
|
|
340
|
+
'Tips': TUTORIALS.filter(t => t.category === 'Tips'),
|
|
341
|
+
};
|
|
342
|
+
|
|
343
|
+
return (
|
|
344
|
+
<ScrollView>
|
|
345
|
+
{Object.entries(categories).map(([category, tutorials]) => (
|
|
346
|
+
<VideoTutorialSection
|
|
347
|
+
key={category}
|
|
348
|
+
title={category}
|
|
349
|
+
tutorials={tutorials}
|
|
350
|
+
onTutorialPress={playVideo}
|
|
351
|
+
/>
|
|
352
|
+
))}
|
|
353
|
+
</ScrollView>
|
|
354
|
+
);
|
|
355
|
+
}
|
|
356
|
+
```
|
|
357
|
+
|
|
358
|
+
### With Search
|
|
359
|
+
|
|
360
|
+
```tsx
|
|
361
|
+
function SearchableTutorials() {
|
|
362
|
+
const [searchQuery, setSearchQuery] = useState('');
|
|
363
|
+
const [filteredTutorials, setFilteredTutorials] = useState(TUTORIALS);
|
|
364
|
+
|
|
365
|
+
useEffect(() => {
|
|
366
|
+
if (searchQuery.trim() === '') {
|
|
367
|
+
setFilteredTutorials(TUTORIALS);
|
|
368
|
+
} else {
|
|
369
|
+
const filtered = TUTORIALS.filter(t =>
|
|
370
|
+
t.title.toLowerCase().includes(searchQuery.toLowerCase()) ||
|
|
371
|
+
t.description?.toLowerCase().includes(searchQuery.toLowerCase())
|
|
372
|
+
);
|
|
373
|
+
setFilteredTutorials(filtered);
|
|
374
|
+
}
|
|
375
|
+
}, [searchQuery]);
|
|
376
|
+
|
|
377
|
+
return (
|
|
378
|
+
<View>
|
|
379
|
+
<TextInput
|
|
380
|
+
value={searchQuery}
|
|
381
|
+
onChangeText={setSearchQuery}
|
|
382
|
+
placeholder="Search tutorials..."
|
|
383
|
+
style={{ padding: 12, backgroundColor: '#FFF' }}
|
|
384
|
+
/>
|
|
385
|
+
|
|
386
|
+
<VideoTutorialsScreen
|
|
387
|
+
tutorials={filteredTutorials}
|
|
388
|
+
onTutorialPress={playVideo}
|
|
389
|
+
/>
|
|
390
|
+
</View>
|
|
391
|
+
);
|
|
392
|
+
}
|
|
393
|
+
```
|
|
394
|
+
|
|
395
|
+
## Architecture
|
|
396
|
+
|
|
397
|
+
```
|
|
398
|
+
src/domains/video-tutorials/
|
|
399
|
+
├── types/
|
|
400
|
+
│ └── index.ts # VideoTutorial types
|
|
401
|
+
├── presentation/
|
|
402
|
+
│ ├── screens/
|
|
403
|
+
│ │ └── VideoTutorialsScreen.tsx
|
|
404
|
+
│ └── components/
|
|
405
|
+
│ ├── VideoTutorialCard.tsx
|
|
406
|
+
│ └── VideoTutorialSection.tsx
|
|
407
|
+
└── index.ts # Public API exports
|
|
408
|
+
```
|
|
409
|
+
|
|
410
|
+
## Best Practices
|
|
411
|
+
|
|
412
|
+
1. **Quality Thumbnails**: Use high-quality, consistent thumbnail sizes
|
|
413
|
+
2. **Accurate Metadata**: Keep duration and view counts up to date
|
|
414
|
+
3. **Categorization**: Organize tutorials logically for easy browsing
|
|
415
|
+
4. **Featured Content**: Highlight important or new tutorials
|
|
416
|
+
5. **Loading States**: Show proper loading indicators for better UX
|
|
417
|
+
6. **Error Handling**: Handle video playback errors gracefully
|
|
418
|
+
7. **Offline Support**: Consider caching video information for offline viewing
|
|
419
|
+
8. **Progress Tracking**: Track which tutorials users have watched
|
|
420
|
+
|
|
421
|
+
## Testing
|
|
422
|
+
|
|
423
|
+
```tsx
|
|
424
|
+
import { render, fireEvent } from '@testing-library/react-native';
|
|
425
|
+
import { VideoTutorialsScreen } from '@umituz/react-native-settings';
|
|
426
|
+
|
|
427
|
+
describe('VideoTutorialsScreen', () => {
|
|
428
|
+
const tutorials = [
|
|
429
|
+
{
|
|
430
|
+
id: '1',
|
|
431
|
+
title: 'Test Tutorial',
|
|
432
|
+
videoUrl: 'https://youtube.com/watch?v=test',
|
|
433
|
+
},
|
|
434
|
+
];
|
|
435
|
+
|
|
436
|
+
it('renders tutorials list', () => {
|
|
437
|
+
const { getByText } = render(
|
|
438
|
+
<VideoTutorialsScreen
|
|
439
|
+
tutorials={tutorials}
|
|
440
|
+
onTutorialPress={() => {}}
|
|
441
|
+
/>
|
|
442
|
+
);
|
|
443
|
+
|
|
444
|
+
expect(getByText('Test Tutorial')).toBeTruthy();
|
|
445
|
+
});
|
|
446
|
+
|
|
447
|
+
it('calls onTutorialPress when tutorial is pressed', () => {
|
|
448
|
+
const mockPress = jest.fn();
|
|
449
|
+
const { getByText } = render(
|
|
450
|
+
<VideoTutorialsScreen
|
|
451
|
+
tutorials={tutorials}
|
|
452
|
+
onTutorialPress={mockPress}
|
|
453
|
+
/>
|
|
454
|
+
);
|
|
455
|
+
|
|
456
|
+
fireEvent.press(getByText('Test Tutorial'));
|
|
457
|
+
expect(mockPress).toHaveBeenCalledWith(tutorials[0]);
|
|
458
|
+
});
|
|
459
|
+
|
|
460
|
+
it('shows empty state when no tutorials', () => {
|
|
461
|
+
const { getByText } = render(
|
|
462
|
+
<VideoTutorialsScreen
|
|
463
|
+
tutorials={[]}
|
|
464
|
+
emptyMessage="No tutorials found"
|
|
465
|
+
onTutorialPress={() => {}}
|
|
466
|
+
/>
|
|
467
|
+
);
|
|
468
|
+
|
|
469
|
+
expect(getByText('No tutorials found')).toBeTruthy();
|
|
470
|
+
});
|
|
471
|
+
});
|
|
472
|
+
```
|
|
473
|
+
|
|
474
|
+
## Related
|
|
475
|
+
|
|
476
|
+
- **Settings**: Main settings management
|
|
477
|
+
- **Help**: Help and support content
|
|
478
|
+
- **FAQs**: Frequently asked questions
|
|
479
|
+
|
|
480
|
+
## License
|
|
481
|
+
|
|
482
|
+
MIT
|