@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,586 @@
|
|
|
1
|
+
# FAQs Domain
|
|
2
|
+
|
|
3
|
+
The FAQs domain provides comprehensive FAQ (Frequently Asked Questions) management with search functionality, categorization, and expandable items for your React Native app.
|
|
4
|
+
|
|
5
|
+
## Features
|
|
6
|
+
|
|
7
|
+
- **FAQ Screen**: Full-screen FAQ viewer with search
|
|
8
|
+
- **Search Functionality**: Real-time search across all FAQs
|
|
9
|
+
- **Categorized Questions**: Organize FAQs into categories
|
|
10
|
+
- **Expandable Items**: Tap to expand/collapse answers
|
|
11
|
+
- **Empty States**: Handle no search results gracefully
|
|
12
|
+
- **Custom Styling**: Fully customizable appearance
|
|
13
|
+
- **Performance Optimized**: Efficient search and rendering
|
|
14
|
+
|
|
15
|
+
## Installation
|
|
16
|
+
|
|
17
|
+
This domain is part of `@umituz/react-native-settings`. Install the package to use it:
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
npm install @umituz/react-native-settings
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
## Components
|
|
24
|
+
|
|
25
|
+
### FAQScreen
|
|
26
|
+
|
|
27
|
+
Main screen for displaying FAQs with search functionality.
|
|
28
|
+
|
|
29
|
+
```tsx
|
|
30
|
+
import { FAQScreen } from '@umituz/react-native-settings';
|
|
31
|
+
|
|
32
|
+
function MyFAQScreen() {
|
|
33
|
+
const categories = [
|
|
34
|
+
{
|
|
35
|
+
id: 'general',
|
|
36
|
+
title: 'General',
|
|
37
|
+
questions: [
|
|
38
|
+
{
|
|
39
|
+
id: 'q1',
|
|
40
|
+
question: 'What is this app?',
|
|
41
|
+
answer: 'This app helps you manage your tasks efficiently.',
|
|
42
|
+
},
|
|
43
|
+
{
|
|
44
|
+
id: 'q2',
|
|
45
|
+
question: 'Is it free?',
|
|
46
|
+
answer: 'Yes, the basic version is completely free.',
|
|
47
|
+
},
|
|
48
|
+
],
|
|
49
|
+
},
|
|
50
|
+
{
|
|
51
|
+
id: 'account',
|
|
52
|
+
title: 'Account',
|
|
53
|
+
questions: [
|
|
54
|
+
{
|
|
55
|
+
id: 'q3',
|
|
56
|
+
question: 'How do I reset my password?',
|
|
57
|
+
answer: 'Go to Settings > Account > Reset Password.',
|
|
58
|
+
},
|
|
59
|
+
],
|
|
60
|
+
},
|
|
61
|
+
];
|
|
62
|
+
|
|
63
|
+
return (
|
|
64
|
+
<FAQScreen
|
|
65
|
+
categories={categories}
|
|
66
|
+
searchPlaceholder="Search FAQs..."
|
|
67
|
+
emptySearchTitle="No results found"
|
|
68
|
+
emptySearchMessage="Try different keywords"
|
|
69
|
+
headerTitle="Frequently Asked Questions"
|
|
70
|
+
/>
|
|
71
|
+
);
|
|
72
|
+
}
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
#### Props
|
|
76
|
+
|
|
77
|
+
| Prop | Type | Default | Description |
|
|
78
|
+
|------|------|---------|-------------|
|
|
79
|
+
| `categories` | `FAQCategory[]` | **Required** | FAQ categories |
|
|
80
|
+
| `searchPlaceholder` | `string` | **Required** | Search input placeholder |
|
|
81
|
+
| `emptySearchTitle` | `string` | **Required** | Empty state title |
|
|
82
|
+
| `emptySearchMessage` | `string` | **Required** | Empty state message |
|
|
83
|
+
| `headerTitle` | `string` | **Required** | Screen header title |
|
|
84
|
+
| `onBack` | `() => void` | `undefined` | Back button handler |
|
|
85
|
+
| `renderHeader` | `(props) => ReactElement` | `undefined` | Custom header renderer |
|
|
86
|
+
| `styles` | `FAQScreenStyles` | `undefined` | Custom styles |
|
|
87
|
+
|
|
88
|
+
### FAQCategory
|
|
89
|
+
|
|
90
|
+
Component for rendering a single FAQ category with questions.
|
|
91
|
+
|
|
92
|
+
```tsx
|
|
93
|
+
import { FAQCategory } from '@umituz/react-native-settings';
|
|
94
|
+
|
|
95
|
+
function MyFAQCategory() {
|
|
96
|
+
const category = {
|
|
97
|
+
id: 'general',
|
|
98
|
+
title: 'General Questions',
|
|
99
|
+
questions: [
|
|
100
|
+
{
|
|
101
|
+
id: 'q1',
|
|
102
|
+
question: 'What is this?',
|
|
103
|
+
answer: 'Answer here...',
|
|
104
|
+
},
|
|
105
|
+
],
|
|
106
|
+
};
|
|
107
|
+
|
|
108
|
+
const isExpanded = { q1: true };
|
|
109
|
+
const onToggle = (id) => console.log('Toggle:', id);
|
|
110
|
+
|
|
111
|
+
return (
|
|
112
|
+
<FAQCategory
|
|
113
|
+
category={category}
|
|
114
|
+
isExpanded={isExpanded}
|
|
115
|
+
onToggleItem={onToggle}
|
|
116
|
+
/>
|
|
117
|
+
);
|
|
118
|
+
}
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
#### Props
|
|
122
|
+
|
|
123
|
+
| Prop | Type | Default | Description |
|
|
124
|
+
|------|------|---------|-------------|
|
|
125
|
+
| `category` | `FAQCategory` | **Required** | Category data |
|
|
126
|
+
| `isExpanded` | `Record<string, boolean>` | **Required** | Expansion state |
|
|
127
|
+
| `onToggleItem` | `(id) => void` | **Required** | Toggle handler |
|
|
128
|
+
| `styles` | `FAQCategoryStyles` | `undefined` | Custom styles |
|
|
129
|
+
|
|
130
|
+
### FAQItem
|
|
131
|
+
|
|
132
|
+
Individual FAQ item with expandable answer.
|
|
133
|
+
|
|
134
|
+
```tsx
|
|
135
|
+
import { FAQItem } from '@umituz/react-native-settings';
|
|
136
|
+
|
|
137
|
+
function MyFAQItem() {
|
|
138
|
+
return (
|
|
139
|
+
<FAQItem
|
|
140
|
+
question="What is your return policy?"
|
|
141
|
+
answer="You can return items within 30 days of purchase."
|
|
142
|
+
isExpanded={true}
|
|
143
|
+
onToggle={() => console.log('Toggle')}
|
|
144
|
+
/>
|
|
145
|
+
);
|
|
146
|
+
}
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
#### Props
|
|
150
|
+
|
|
151
|
+
| Prop | Type | Default | Description |
|
|
152
|
+
|------|------|---------|-------------|
|
|
153
|
+
| `question` | `string` | **Required** | Question text |
|
|
154
|
+
| `answer` | `string` | **Required** | Answer text |
|
|
155
|
+
| `isExpanded` | `boolean` | **Required** | Expansion state |
|
|
156
|
+
| `onToggle` | `() => void` | **Required** | Toggle handler |
|
|
157
|
+
|
|
158
|
+
### FAQSearchBar
|
|
159
|
+
|
|
160
|
+
Search input component for filtering FAQs.
|
|
161
|
+
|
|
162
|
+
```tsx
|
|
163
|
+
import { FAQSearchBar } from '@umituz/react-native-settings';
|
|
164
|
+
|
|
165
|
+
function MyFAQSearch() {
|
|
166
|
+
const [query, setQuery] = useState('');
|
|
167
|
+
|
|
168
|
+
return (
|
|
169
|
+
<FAQSearchBar
|
|
170
|
+
value={query}
|
|
171
|
+
onChangeText={setQuery}
|
|
172
|
+
placeholder="Search questions..."
|
|
173
|
+
/>
|
|
174
|
+
);
|
|
175
|
+
}
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
#### Props
|
|
179
|
+
|
|
180
|
+
| Prop | Type | Default | Description |
|
|
181
|
+
|------|------|---------|-------------|
|
|
182
|
+
| `value` | `string` | **Required** | Search query |
|
|
183
|
+
| `onChangeText` | `(text) => void` | **Required** | Text change handler |
|
|
184
|
+
| `placeholder` | `string` | **Required** | Placeholder text |
|
|
185
|
+
| `styles` | `FAQSearchBarStyles` | `undefined` | Custom styles |
|
|
186
|
+
|
|
187
|
+
### FAQEmptyState
|
|
188
|
+
|
|
189
|
+
Empty state component for no search results.
|
|
190
|
+
|
|
191
|
+
```tsx
|
|
192
|
+
import { FAQEmptyState } from '@umituz/react-native-settings';
|
|
193
|
+
|
|
194
|
+
function MyEmptyState() {
|
|
195
|
+
return (
|
|
196
|
+
<FAQEmptyState
|
|
197
|
+
title="No FAQs Found"
|
|
198
|
+
message="We couldn't find any FAQs matching your search."
|
|
199
|
+
iconName="search"
|
|
200
|
+
/>
|
|
201
|
+
);
|
|
202
|
+
}
|
|
203
|
+
```
|
|
204
|
+
|
|
205
|
+
#### Props
|
|
206
|
+
|
|
207
|
+
| Prop | Type | Default | Description |
|
|
208
|
+
|------|------|---------|-------------|
|
|
209
|
+
| `title` | `string` | **Required** | Empty state title |
|
|
210
|
+
| `message` | `string` | **Required** | Empty state message |
|
|
211
|
+
| `iconName` | `string` | `undefined` | Custom icon name |
|
|
212
|
+
| `styles` | `FAQEmptyStateStyles` | `undefined` | Custom styles |
|
|
213
|
+
|
|
214
|
+
## Hooks
|
|
215
|
+
|
|
216
|
+
### useFAQSearch
|
|
217
|
+
|
|
218
|
+
Hook for managing FAQ search state and filtering.
|
|
219
|
+
|
|
220
|
+
```tsx
|
|
221
|
+
import { useFAQSearch } from '@umituz/react-native-settings';
|
|
222
|
+
|
|
223
|
+
function FAQSearchComponent() {
|
|
224
|
+
const categories = [ /* FAQ categories */ ];
|
|
225
|
+
|
|
226
|
+
const {
|
|
227
|
+
searchQuery,
|
|
228
|
+
setSearchQuery,
|
|
229
|
+
filteredCategories,
|
|
230
|
+
hasResults,
|
|
231
|
+
} = useFAQSearch(categories);
|
|
232
|
+
|
|
233
|
+
return (
|
|
234
|
+
<View>
|
|
235
|
+
<TextInput
|
|
236
|
+
value={searchQuery}
|
|
237
|
+
onChangeText={setSearchQuery}
|
|
238
|
+
placeholder="Search..."
|
|
239
|
+
/>
|
|
240
|
+
{hasResults ? (
|
|
241
|
+
<FAQList categories={filteredCategories} />
|
|
242
|
+
) : (
|
|
243
|
+
<Text>No results</Text>
|
|
244
|
+
)}
|
|
245
|
+
</View>
|
|
246
|
+
);
|
|
247
|
+
}
|
|
248
|
+
```
|
|
249
|
+
|
|
250
|
+
#### Return Value
|
|
251
|
+
|
|
252
|
+
| Property | Type | Description |
|
|
253
|
+
|----------|------|-------------|
|
|
254
|
+
| `searchQuery` | `string` | Current search query |
|
|
255
|
+
| `setSearchQuery` | `(query) => void` | Set search query |
|
|
256
|
+
| `filteredCategories` | `FAQCategory[]` | Filtered categories |
|
|
257
|
+
| `hasResults` | `boolean` | Whether search has results |
|
|
258
|
+
|
|
259
|
+
### useFAQExpansion
|
|
260
|
+
|
|
261
|
+
Hook for managing FAQ item expansion state.
|
|
262
|
+
|
|
263
|
+
```tsx
|
|
264
|
+
import { useFAQExpansion } from '@umituz/react-native-settings';
|
|
265
|
+
|
|
266
|
+
function FAQExpansionComponent() {
|
|
267
|
+
const { isExpanded, toggleExpansion } = useFAQExpansion();
|
|
268
|
+
|
|
269
|
+
return (
|
|
270
|
+
<FAQItem
|
|
271
|
+
question="Question"
|
|
272
|
+
answer="Answer"
|
|
273
|
+
isExpanded={isExpanded['q1']}
|
|
274
|
+
onToggle={() => toggleExpansion('q1')}
|
|
275
|
+
/>
|
|
276
|
+
);
|
|
277
|
+
}
|
|
278
|
+
```
|
|
279
|
+
|
|
280
|
+
#### Return Value
|
|
281
|
+
|
|
282
|
+
| Property | Type | Description |
|
|
283
|
+
|----------|------|-------------|
|
|
284
|
+
| `isExpanded` | `Record<string, boolean>` | Expansion state map |
|
|
285
|
+
| `toggleExpansion` | `(id) => void` | Toggle item expansion |
|
|
286
|
+
|
|
287
|
+
## Types
|
|
288
|
+
|
|
289
|
+
### FAQCategory
|
|
290
|
+
|
|
291
|
+
```typescript
|
|
292
|
+
interface FAQCategory {
|
|
293
|
+
id: string;
|
|
294
|
+
title: string;
|
|
295
|
+
questions: FAQItem[];
|
|
296
|
+
}
|
|
297
|
+
```
|
|
298
|
+
|
|
299
|
+
### FAQItem
|
|
300
|
+
|
|
301
|
+
```typescript
|
|
302
|
+
interface FAQItem {
|
|
303
|
+
id: string;
|
|
304
|
+
question: string;
|
|
305
|
+
answer: string;
|
|
306
|
+
}
|
|
307
|
+
```
|
|
308
|
+
|
|
309
|
+
### FAQScreenStyles
|
|
310
|
+
|
|
311
|
+
```typescript
|
|
312
|
+
interface FAQScreenStyles {
|
|
313
|
+
container?: ViewStyle;
|
|
314
|
+
header?: ViewStyle;
|
|
315
|
+
title?: TextStyle;
|
|
316
|
+
content?: ViewStyle;
|
|
317
|
+
searchBar?: FAQSearchBarStyles;
|
|
318
|
+
emptyState?: FAQEmptyStateStyles;
|
|
319
|
+
category?: FAQCategoryStyles;
|
|
320
|
+
}
|
|
321
|
+
```
|
|
322
|
+
|
|
323
|
+
## Examples
|
|
324
|
+
|
|
325
|
+
### Basic FAQ Screen
|
|
326
|
+
|
|
327
|
+
```tsx
|
|
328
|
+
import React from 'react';
|
|
329
|
+
import { FAQScreen } from '@umituz/react-native-settings';
|
|
330
|
+
|
|
331
|
+
const FAQ_DATA = [
|
|
332
|
+
{
|
|
333
|
+
id: 'getting-started',
|
|
334
|
+
title: 'Getting Started',
|
|
335
|
+
questions: [
|
|
336
|
+
{
|
|
337
|
+
id: 'gs1',
|
|
338
|
+
question: 'How do I create an account?',
|
|
339
|
+
answer: 'Tap the "Sign Up" button and enter your email and password.',
|
|
340
|
+
},
|
|
341
|
+
{
|
|
342
|
+
id: 'gs2',
|
|
343
|
+
question: 'Is the app free to use?',
|
|
344
|
+
answer: 'Yes, the basic features are completely free. Premium features require a subscription.',
|
|
345
|
+
},
|
|
346
|
+
],
|
|
347
|
+
},
|
|
348
|
+
{
|
|
349
|
+
id: 'features',
|
|
350
|
+
title: 'Features',
|
|
351
|
+
questions: [
|
|
352
|
+
{
|
|
353
|
+
id: 'f1',
|
|
354
|
+
question: 'Can I use the app offline?',
|
|
355
|
+
answer: 'Yes, you can access cached content offline. Some features require internet.',
|
|
356
|
+
},
|
|
357
|
+
{
|
|
358
|
+
id: 'f2',
|
|
359
|
+
question: 'How do I sync my data?',
|
|
360
|
+
answer: 'Data syncs automatically when you\'re connected to the internet.',
|
|
361
|
+
},
|
|
362
|
+
],
|
|
363
|
+
},
|
|
364
|
+
];
|
|
365
|
+
|
|
366
|
+
export default function FAQScreenExample() {
|
|
367
|
+
return (
|
|
368
|
+
<FAQScreen
|
|
369
|
+
categories={FAQ_DATA}
|
|
370
|
+
searchPlaceholder="Search for answers..."
|
|
371
|
+
emptySearchTitle="No FAQs found"
|
|
372
|
+
emptySearchMessage="Try searching with different keywords"
|
|
373
|
+
headerTitle="Help & FAQs"
|
|
374
|
+
/>
|
|
375
|
+
);
|
|
376
|
+
}
|
|
377
|
+
```
|
|
378
|
+
|
|
379
|
+
### Custom Styled FAQ Screen
|
|
380
|
+
|
|
381
|
+
```tsx
|
|
382
|
+
import { FAQScreen } from '@umituz/react-native-settings';
|
|
383
|
+
import { StyleSheet } from 'react-native';
|
|
384
|
+
|
|
385
|
+
const customStyles = {
|
|
386
|
+
container: {
|
|
387
|
+
backgroundColor: '#F5F5F5',
|
|
388
|
+
},
|
|
389
|
+
header: {
|
|
390
|
+
padding: 24,
|
|
391
|
+
},
|
|
392
|
+
category: {
|
|
393
|
+
marginBottom: 16,
|
|
394
|
+
},
|
|
395
|
+
};
|
|
396
|
+
|
|
397
|
+
function CustomStyledFAQ() {
|
|
398
|
+
return (
|
|
399
|
+
<FAQScreen
|
|
400
|
+
categories={FAQ_DATA}
|
|
401
|
+
searchPlaceholder="Type your question..."
|
|
402
|
+
emptySearchTitle="No results"
|
|
403
|
+
emptySearchMessage="We couldn't find an answer"
|
|
404
|
+
headerTitle="FAQ"
|
|
405
|
+
styles={customStyles}
|
|
406
|
+
/>
|
|
407
|
+
);
|
|
408
|
+
}
|
|
409
|
+
```
|
|
410
|
+
|
|
411
|
+
### Using Individual Components
|
|
412
|
+
|
|
413
|
+
```tsx
|
|
414
|
+
import { FAQCategory, FAQItem } from '@umituz/react-native-settings';
|
|
415
|
+
|
|
416
|
+
function CustomFAQSection() {
|
|
417
|
+
const [expanded, setExpanded] = useState({});
|
|
418
|
+
|
|
419
|
+
const toggleItem = (id) => {
|
|
420
|
+
setExpanded(prev => ({
|
|
421
|
+
...prev,
|
|
422
|
+
[id]: !prev[id],
|
|
423
|
+
}));
|
|
424
|
+
};
|
|
425
|
+
|
|
426
|
+
return (
|
|
427
|
+
<ScrollView>
|
|
428
|
+
<FAQCategory
|
|
429
|
+
category={{
|
|
430
|
+
id: 'general',
|
|
431
|
+
title: 'General',
|
|
432
|
+
questions: [
|
|
433
|
+
{
|
|
434
|
+
id: 'q1',
|
|
435
|
+
question: 'Question 1?',
|
|
436
|
+
answer: 'Answer 1',
|
|
437
|
+
},
|
|
438
|
+
],
|
|
439
|
+
}}
|
|
440
|
+
isExpanded={expanded}
|
|
441
|
+
onToggleItem={toggleItem}
|
|
442
|
+
/>
|
|
443
|
+
</ScrollView>
|
|
444
|
+
);
|
|
445
|
+
}
|
|
446
|
+
```
|
|
447
|
+
|
|
448
|
+
### Using Search Hook
|
|
449
|
+
|
|
450
|
+
```tsx
|
|
451
|
+
import { useFAQSearch } from '@umituz/react-native-settings';
|
|
452
|
+
|
|
453
|
+
function CustomFAQSearch() {
|
|
454
|
+
const categories = [/* FAQ data */];
|
|
455
|
+
const {
|
|
456
|
+
searchQuery,
|
|
457
|
+
setSearchQuery,
|
|
458
|
+
filteredCategories,
|
|
459
|
+
hasResults,
|
|
460
|
+
} = useFAQSearch(categories);
|
|
461
|
+
|
|
462
|
+
return (
|
|
463
|
+
<View>
|
|
464
|
+
<TextInput
|
|
465
|
+
value={searchQuery}
|
|
466
|
+
onChangeText={setSearchQuery}
|
|
467
|
+
placeholder="Search..."
|
|
468
|
+
style={{ padding: 16, backgroundColor: '#FFF' }}
|
|
469
|
+
/>
|
|
470
|
+
|
|
471
|
+
{!hasResults && searchQuery ? (
|
|
472
|
+
<View style={{ padding: 32, alignItems: 'center' }}>
|
|
473
|
+
<Text>No FAQs found for "{searchQuery}"</Text>
|
|
474
|
+
</View>
|
|
475
|
+
) : (
|
|
476
|
+
filteredCategories.map(cat => (
|
|
477
|
+
<FAQCategory
|
|
478
|
+
key={cat.id}
|
|
479
|
+
category={cat}
|
|
480
|
+
isExpanded={expanded}
|
|
481
|
+
onToggleItem={toggleItem}
|
|
482
|
+
/>
|
|
483
|
+
))
|
|
484
|
+
)}
|
|
485
|
+
</View>
|
|
486
|
+
);
|
|
487
|
+
}
|
|
488
|
+
```
|
|
489
|
+
|
|
490
|
+
## Architecture
|
|
491
|
+
|
|
492
|
+
```
|
|
493
|
+
src/domains/faqs/
|
|
494
|
+
├── domain/
|
|
495
|
+
│ ├── entities/
|
|
496
|
+
│ │ └── FAQEntity.ts # FAQ types and interfaces
|
|
497
|
+
│ └── services/
|
|
498
|
+
│ └── FAQSearchService.ts # Search logic
|
|
499
|
+
├── presentation/
|
|
500
|
+
│ ├── screens/
|
|
501
|
+
│ │ └── FAQScreen.tsx
|
|
502
|
+
│ ├── components/
|
|
503
|
+
│ │ ├── FAQCategory.tsx
|
|
504
|
+
│ │ ├── FAQItem.tsx
|
|
505
|
+
│ │ ├── FAQSearchBar.tsx
|
|
506
|
+
│ │ └── FAQEmptyState.tsx
|
|
507
|
+
│ └── hooks/
|
|
508
|
+
│ ├── useFAQSearch.ts
|
|
509
|
+
│ └── useFAQExpansion.ts
|
|
510
|
+
└── index.ts # Public API exports
|
|
511
|
+
```
|
|
512
|
+
|
|
513
|
+
## Best Practices
|
|
514
|
+
|
|
515
|
+
1. **Organize by Category**: Group related questions together
|
|
516
|
+
2. **Clear Answers**: Keep answers concise and easy to understand
|
|
517
|
+
3. **Searchable Content**: Use clear keywords in questions and answers
|
|
518
|
+
4. **Keep Updated**: Regularly update FAQs based on user feedback
|
|
519
|
+
5. **Multiple Languages**: Provide FAQs in all supported languages
|
|
520
|
+
6. **Visual Hierarchy**: Use proper spacing and typography
|
|
521
|
+
7. **Performance**: Optimize for large FAQ lists with pagination
|
|
522
|
+
|
|
523
|
+
## Testing
|
|
524
|
+
|
|
525
|
+
```tsx
|
|
526
|
+
import { render, fireEvent } from '@testing-library/react-native';
|
|
527
|
+
import { FAQScreen } from '@umituz/react-native-settings';
|
|
528
|
+
|
|
529
|
+
describe('FAQScreen', () => {
|
|
530
|
+
const categories = [
|
|
531
|
+
{
|
|
532
|
+
id: 'test',
|
|
533
|
+
title: 'Test Category',
|
|
534
|
+
questions: [
|
|
535
|
+
{
|
|
536
|
+
id: 'q1',
|
|
537
|
+
question: 'Test Question?',
|
|
538
|
+
answer: 'Test Answer',
|
|
539
|
+
},
|
|
540
|
+
],
|
|
541
|
+
},
|
|
542
|
+
];
|
|
543
|
+
|
|
544
|
+
it('renders FAQ categories', () => {
|
|
545
|
+
const { getByText } = render(
|
|
546
|
+
<FAQScreen
|
|
547
|
+
categories={categories}
|
|
548
|
+
searchPlaceholder="Search"
|
|
549
|
+
emptySearchTitle="No results"
|
|
550
|
+
emptySearchMessage="Try again"
|
|
551
|
+
headerTitle="FAQ"
|
|
552
|
+
/>
|
|
553
|
+
);
|
|
554
|
+
|
|
555
|
+
expect(getByText('Test Category')).toBeTruthy();
|
|
556
|
+
expect(getByText('Test Question?')).toBeTruthy();
|
|
557
|
+
});
|
|
558
|
+
|
|
559
|
+
it('filters FAQs by search query', () => {
|
|
560
|
+
const { getByPlaceholderText, queryByText } = render(
|
|
561
|
+
<FAQScreen
|
|
562
|
+
categories={categories}
|
|
563
|
+
searchPlaceholder="Search"
|
|
564
|
+
emptySearchTitle="No results"
|
|
565
|
+
emptySearchMessage="Try again"
|
|
566
|
+
headerTitle="FAQ"
|
|
567
|
+
/>
|
|
568
|
+
);
|
|
569
|
+
|
|
570
|
+
const searchInput = getByPlaceholderText('Search');
|
|
571
|
+
fireEvent.changeText(searchInput, 'nonexistent');
|
|
572
|
+
|
|
573
|
+
expect(queryByText('Test Question?')).toBeNull();
|
|
574
|
+
});
|
|
575
|
+
});
|
|
576
|
+
```
|
|
577
|
+
|
|
578
|
+
## Related
|
|
579
|
+
|
|
580
|
+
- **Settings**: Main settings management
|
|
581
|
+
- **Support**: Customer support components
|
|
582
|
+
- **Help**: Help documentation
|
|
583
|
+
|
|
584
|
+
## License
|
|
585
|
+
|
|
586
|
+
MIT
|