related-ui-components 1.3.1 → 1.3.2

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.
@@ -1,488 +1,479 @@
1
- import React, { useCallback, useEffect, useRef, useState } from "react";
2
- import {
3
- View,
4
- Text,
5
- StyleSheet,
6
- TouchableOpacity,
7
- TextStyle,
8
- ViewStyle,
9
- ImageSourcePropType,
10
- I18nManager,
11
- TouchableWithoutFeedback,
12
- } from "react-native";
13
- import { GestureHandlerRootView } from "react-native-gesture-handler";
14
- import BottomSheet, { BottomSheetView } from "@gorhom/bottom-sheet";
15
- import PointsRangeSelector from "./PointsRangeSelector";
16
- import { BrandIcon } from "../BrandIcon";
17
- import { Ionicons } from "@expo/vector-icons";
18
- import Checkbox from "expo-checkbox";
19
- import { useTheme, ThemeType } from "../../theme"; // Import ThemeType
1
+ import React, { useCallback, useEffect, useRef, useState } from "react";
2
+ import {
3
+ View,
4
+ Text,
5
+ StyleSheet,
6
+ TouchableOpacity,
7
+ TextStyle,
8
+ ViewStyle,
9
+ ImageSourcePropType,
10
+ I18nManager,
11
+ TouchableWithoutFeedback,
12
+ } from "react-native";
13
+ import { GestureHandlerRootView } from "react-native-gesture-handler";
14
+ import BottomSheet, { BottomSheetView } from "@gorhom/bottom-sheet";
15
+ import PointsRangeSelector from "./PointsRangeSelector";
16
+ import { BrandIcon } from "../BrandIcon";
17
+ import { Ionicons } from "@expo/vector-icons";
18
+ import Checkbox from "expo-checkbox";
19
+ import { useTheme, ThemeType } from "../../theme"; // Import ThemeType
20
20
 
21
- type SortOption = {
22
- name: string;
23
- value: string;
24
- id: number;
25
- };
26
- type Brand = {
27
- id: string;
28
- name: string;
29
- logo: ImageSourcePropType;
30
- };
31
- export type FilterResult = {
32
- sort: SortOption[];
33
- pointsRange: { min: number; max: number };
34
- selectedBrands: Brand[];
35
- };
36
- interface FiltersProps {
37
- isRTL?: boolean;
38
- sortOptions?: SortOption[];
39
- sortSectionTitle?: string;
40
- sectionTitleStyle?: TextStyle;
41
- sortSectionStyle?: ViewStyle;
42
- rangeMinLimit?: number;
43
- rangeMaxLimit?: number;
44
- rangeInitialMin?: number;
45
- rangeInitialMax?: number;
46
- showPointsRange?: boolean;
47
- pointsRangeSectionTitle?: string;
48
- pointsRangeContainerStyle?: ViewStyle;
49
- pointsRangeInputsContainerStyle?: ViewStyle;
50
- pointsRangeCustomInputContainerStyle?: ViewStyle;
51
- pointsRangeCustomInputFieldStyle?: ViewStyle;
52
- pointsRangeSliderContainerStyle?: ViewStyle;
53
- pointsRangeMultiSliderContainerStyle?: ViewStyle;
54
- pointsRangeTrackStyle?: ViewStyle;
55
- pointsRangeSelectedTrackStyle?: ViewStyle;
56
- pointsRangeUnselectedTrackStyle?: ViewStyle;
57
- pointsRangeMarkerStyle?: ViewStyle;
58
- pointsRangeMarkerEnabledStyle?: ViewStyle;
59
- pointsRangeMarkerDisabledStyle?: ViewStyle;
60
- pointsRangeMarkerDotStyle?: ViewStyle;
61
- pointsRangeInputProps?: any;
62
- pointsRangeMultiSliderProps?: any;
63
- brands?: Brand[];
64
- brandContainerStyle?: ViewStyle;
65
- brandActiveIcon?: React.ReactNode;
66
- brandActiveIconStyle?: ViewStyle;
67
- brandSectionTile?: string;
68
- onActionButtonPress?: (result: FilterResult) => void;
69
- containerStyle?: ViewStyle;
70
- headerStyle?: ViewStyle;
71
- titleStyle?: TextStyle;
72
- resetTextStyle?: TextStyle;
73
- sectionStyle?: ViewStyle;
74
- optionRowStyle?: ViewStyle;
75
- optionTextStyle?: TextStyle;
76
- checkboxColor?: string;
77
- applyButtonStyle?: ViewStyle;
78
- applyButtonTextStyle?: TextStyle;
79
- bottomSheetStyle?: ViewStyle;
80
- headerTitleText?: string;
81
- headerResetText?: string;
82
- bottomSheetIndex?: number;
83
- snapPoints?: string[];
84
- handleIndicatorStyle?: ViewStyle;
85
- applyButtonText?: string;
86
- overlayColor?: string;
87
- onClose?: () => void;
88
- visible?: boolean;
89
- }
21
+ type SortOption = {
22
+ name: string;
23
+ value: string;
24
+ id: number;
25
+ checked?: boolean;
26
+ };
27
+ type Brand = {
28
+ id: string;
29
+ name: string;
30
+ logo: ImageSourcePropType;
31
+ checked?: boolean;
32
+ };
33
+ export type FilterResult = {
34
+ sort: SortOption | undefined;
35
+ pointsRange: { min: number; max: number };
36
+ selectedBrands: Brand[];
37
+ };
38
+ interface FiltersProps {
39
+ isRTL?: boolean;
40
+ sortOptions?: SortOption[];
41
+ sortSectionTitle?: string;
42
+ sectionTitleStyle?: TextStyle;
43
+ sortSectionStyle?: ViewStyle;
44
+ rangeMinLimit?: number;
45
+ rangeMaxLimit?: number;
46
+ rangeInitialMin?: number;
47
+ rangeInitialMax?: number;
48
+ showPointsRange?: boolean;
49
+ pointsRangeSectionTitle?: string;
50
+ pointsRangeContainerStyle?: ViewStyle;
51
+ pointsRangeInputsContainerStyle?: ViewStyle;
52
+ pointsRangeCustomInputContainerStyle?: ViewStyle;
53
+ pointsRangeCustomInputFieldStyle?: ViewStyle;
54
+ pointsRangeSliderContainerStyle?: ViewStyle;
55
+ pointsRangeMultiSliderContainerStyle?: ViewStyle;
56
+ pointsRangeTrackStyle?: ViewStyle;
57
+ pointsRangeSelectedTrackStyle?: ViewStyle;
58
+ pointsRangeUnselectedTrackStyle?: ViewStyle;
59
+ pointsRangeMarkerStyle?: ViewStyle;
60
+ pointsRangeMarkerEnabledStyle?: ViewStyle;
61
+ pointsRangeMarkerDisabledStyle?: ViewStyle;
62
+ pointsRangeMarkerDotStyle?: ViewStyle;
63
+ pointsRangeInputProps?: any;
64
+ pointsRangeMultiSliderProps?: any;
65
+ brands?: Brand[];
66
+ brandContainerStyle?: ViewStyle;
67
+ brandActiveIcon?: React.ReactNode;
68
+ brandActiveIconStyle?: ViewStyle;
69
+ brandSectionTile?: string;
70
+ onActionButtonPress?: (result: FilterResult) => void;
71
+ containerStyle?: ViewStyle;
72
+ headerStyle?: ViewStyle;
73
+ titleStyle?: TextStyle;
74
+ resetTextStyle?: TextStyle;
75
+ sectionStyle?: ViewStyle;
76
+ optionRowStyle?: ViewStyle;
77
+ optionTextStyle?: TextStyle;
78
+ checkboxColor?: string;
79
+ applyButtonStyle?: ViewStyle;
80
+ applyButtonTextStyle?: TextStyle;
81
+ bottomSheetStyle?: ViewStyle;
82
+ headerTitleText?: string;
83
+ headerResetText?: string;
84
+ bottomSheetIndex?: number;
85
+ snapPoints?: string[];
86
+ handleIndicatorStyle?: ViewStyle;
87
+ applyButtonText?: string;
88
+ overlayColor?: string;
89
+ onClose?: () => void;
90
+ visible?: boolean;
91
+ }
90
92
 
91
- const Filters: React.FC<FiltersProps> = ({
92
- isRTL = I18nManager.isRTL,
93
- sortOptions = [],
94
- sortSectionTitle = "Sort",
95
- sectionTitleStyle,
96
- sortSectionStyle,
97
- onActionButtonPress,
98
- rangeInitialMax = 1000,
99
- rangeInitialMin = 0,
100
- rangeMaxLimit = 1000,
101
- rangeMinLimit = 0,
102
- pointsRangeContainerStyle,
103
- pointsRangeInputsContainerStyle,
104
- pointsRangeCustomInputContainerStyle,
105
- pointsRangeCustomInputFieldStyle,
106
- pointsRangeSliderContainerStyle,
107
- pointsRangeMultiSliderContainerStyle,
108
- pointsRangeTrackStyle,
109
- pointsRangeSelectedTrackStyle,
110
- pointsRangeUnselectedTrackStyle,
111
- pointsRangeMarkerStyle,
112
- pointsRangeMarkerEnabledStyle,
113
- pointsRangeMarkerDisabledStyle,
114
- pointsRangeMarkerDotStyle,
115
- pointsRangeInputProps,
116
- pointsRangeMultiSliderProps,
117
- containerStyle,
118
- headerStyle,
119
- titleStyle,
120
- resetTextStyle,
121
- sectionStyle,
122
- optionRowStyle,
123
- optionTextStyle,
124
- checkboxColor: checkboxColorProp,
125
- applyButtonStyle,
126
- applyButtonTextStyle,
127
- bottomSheetStyle,
128
- bottomSheetIndex = 0,
129
- snapPoints = ["50%", "90%"],
130
- handleIndicatorStyle,
131
- brands = [],
132
- brandContainerStyle,
133
- brandActiveIcon,
134
- showPointsRange = true,
135
- pointsRangeSectionTitle = "Points range",
136
- brandActiveIconStyle,
137
- brandSectionTile = "Brands",
138
- applyButtonText = "Apply Filter",
139
- headerResetText = "Reset All",
140
- headerTitleText = "Filter",
141
- overlayColor = "rgba(0, 0, 0, 0.5)",
142
- onClose,
143
- visible = true,
144
- }) => {
145
- const {theme, isRTL : rtl} = useTheme();
146
- isRTL = rtl || isRTL;
147
- const bottomSheetRef = useRef<BottomSheet>(null);
148
- const styles = createStyles(theme, isRTL);
149
- const checkboxColor = checkboxColorProp ?? theme.primary;
150
- const [isVisible, setIsVisible] = useState(visible);
93
+ const Filters: React.FC<FiltersProps> = ({
94
+ isRTL = I18nManager.isRTL,
95
+ sortOptions = [],
96
+ sortSectionTitle = "Sort",
97
+ sectionTitleStyle,
98
+ sortSectionStyle,
99
+ onActionButtonPress,
100
+ rangeInitialMax = 1000,
101
+ rangeInitialMin = 0,
102
+ rangeMaxLimit = 1000,
103
+ rangeMinLimit = 0,
104
+ pointsRangeContainerStyle,
105
+ pointsRangeInputsContainerStyle,
106
+ pointsRangeCustomInputContainerStyle,
107
+ pointsRangeCustomInputFieldStyle,
108
+ pointsRangeSliderContainerStyle,
109
+ pointsRangeMultiSliderContainerStyle,
110
+ pointsRangeTrackStyle,
111
+ pointsRangeSelectedTrackStyle,
112
+ pointsRangeUnselectedTrackStyle,
113
+ pointsRangeMarkerStyle,
114
+ pointsRangeMarkerEnabledStyle,
115
+ pointsRangeMarkerDisabledStyle,
116
+ pointsRangeMarkerDotStyle,
117
+ pointsRangeInputProps,
118
+ pointsRangeMultiSliderProps,
119
+ containerStyle,
120
+ headerStyle,
121
+ titleStyle,
122
+ resetTextStyle,
123
+ sectionStyle,
124
+ optionRowStyle,
125
+ optionTextStyle,
126
+ checkboxColor: checkboxColorProp,
127
+ applyButtonStyle,
128
+ applyButtonTextStyle,
129
+ bottomSheetStyle,
130
+ bottomSheetIndex = 0,
131
+ snapPoints = ["50%", "90%"],
132
+ handleIndicatorStyle,
133
+ brands = [],
134
+ brandContainerStyle,
135
+ brandActiveIcon,
136
+ showPointsRange = true,
137
+ pointsRangeSectionTitle = "Points range",
138
+ brandActiveIconStyle,
139
+ brandSectionTile = "Brands",
140
+ applyButtonText = "Apply Filter",
141
+ headerResetText = "Reset All",
142
+ headerTitleText = "Filter",
143
+ overlayColor = "rgba(0, 0, 0, 0.5)",
144
+ onClose,
145
+ visible = true,
146
+ }) => {
147
+ const {theme, isRTL : rtl} = useTheme();
148
+ isRTL = rtl || isRTL;
149
+ const bottomSheetRef = useRef<BottomSheet>(null);
150
+ const styles = createStyles(theme, isRTL);
151
+ const checkboxColor = checkboxColorProp ?? theme.primary;
152
+ const [isVisible, setIsVisible] = useState(visible);
151
153
 
152
- // Sync the internal isVisible state with the visible prop
153
- useEffect(() => {
154
- setIsVisible(visible);
155
- if (visible && bottomSheetRef.current) {
156
- bottomSheetRef.current.snapToIndex(0);
157
- }
158
- }, [visible]);
154
+ // Sync the internal isVisible state with the visible prop
155
+ useEffect(() => {
156
+ setIsVisible(visible);
157
+ if (visible && bottomSheetRef.current) {
158
+ bottomSheetRef.current.snapToIndex(0);
159
+ }
160
+ }, [visible]);
159
161
 
160
- const handleSheetChanges = useCallback((index: number) => {
161
- console.log("handleSheetChanges", index);
162
- // If the sheet is closed (index -1), handle visibility
163
- if (index === -1) {
164
- setIsVisible(false);
165
- }
166
- }, []);
162
+ const handleSheetChanges = useCallback((index: number) => {
163
+ if (index === -1) {
164
+ setIsVisible(false);
165
+ }
166
+ }, []);
167
167
 
168
- const [resetCounter, setResetCounter] = useState(0);
168
+ const [resetCounter, setResetCounter] = useState(0);
169
169
 
170
- const [checkedItems, setCheckedItems] = useState<Record<string, boolean>>(
171
- sortOptions.reduce((acc, option) => {
172
- acc[option.id] = false;
173
- return acc;
174
- }, {} as Record<string, boolean>)
175
- );
176
- const [selectedBrands, setSelectedBrands] = useState<Record<string, boolean>>(
177
- brands.reduce((acc, option) => {
178
- acc[option.id] = false;
179
- return acc;
180
- }, {} as Record<string, boolean>)
181
- );
182
- const [pointsRange, setPointsRange] = useState<{ min: number; max: number }>({
183
- min: rangeInitialMin,
184
- max: rangeInitialMax,
185
- });
186
170
 
187
- const handleCheckboxChange = (id: string) => {
188
- setCheckedItems((prevState) => ({
189
- ...prevState,
190
- [id]: !prevState[id],
191
- }));
192
- };
171
+ const [checkedItem, setCheckedItem] = useState<number | null>(
172
+ sortOptions.find(option => option.checked)?.id || null
173
+ );
193
174
 
194
- const handleBrandSelect = (id: string) => {
195
- setSelectedBrands((prevState) => ({
196
- ...prevState,
197
- [id]: !prevState[id],
198
- }));
199
- };
175
+ const [selectedBrands, setSelectedBrands] = useState<Record<string, boolean>>(
176
+ brands.reduce((acc, option) => {
177
+ acc[option.id] = option.checked || false;
178
+ return acc;
179
+ }, {} as Record<string, boolean>)
180
+ );
181
+ const [pointsRange, setPointsRange] = useState<{ min: number; max: number }>({
182
+ min: rangeInitialMin,
183
+ max: rangeInitialMax,
184
+ });
200
185
 
201
- const handleApplyFilter = () => {
202
- if (onActionButtonPress) {
203
- const selectedSortOptions = sortOptions.filter(
204
- (option) => checkedItems[option.id]
205
- );
186
+ const handleCheckboxChange = (id: number) => {
187
+ setCheckedItem(id);
188
+ };
206
189
 
207
- const selectedBrandsList = brands.filter(
208
- (brand) => selectedBrands[brand.id]
209
- );
190
+ const handleBrandSelect = (id: string) => {
191
+ setSelectedBrands((prevState) => ({
192
+ ...prevState,
193
+ [id]: !prevState[id],
194
+ }));
195
+ };
210
196
 
211
- const filterResult: FilterResult = {
212
- sort: selectedSortOptions,
213
- pointsRange: pointsRange,
214
- selectedBrands: selectedBrandsList,
215
- };
197
+ const handleApplyFilter = () => {
198
+ if (onActionButtonPress) {
199
+ const selectedSortOption = sortOptions.find(
200
+ (option) => option.id == checkedItem
201
+ );
216
202
 
217
- onActionButtonPress(filterResult);
218
- closeBottomSheet(); // Close the filter after applying
219
- }
220
- };
203
+ const selectedBrandsList = brands.filter(
204
+ (brand) => selectedBrands[brand.id]
205
+ );
221
206
 
222
- const handleResetAll = () => {
223
- const resetState = sortOptions.reduce((acc, option) => {
224
- acc[option.id] = false;
225
- return acc;
226
- }, {} as Record<string, boolean>);
207
+ const filterResult: FilterResult = {
208
+ sort: selectedSortOption,
209
+ pointsRange: pointsRange,
210
+ selectedBrands: selectedBrandsList,
211
+ };
227
212
 
228
- const resetBrands = brands.reduce((acc, option) => {
229
- acc[option.id] = false;
230
- return acc;
231
- }, {} as Record<string, boolean>);
213
+ onActionButtonPress(filterResult);
214
+ closeBottomSheet(); // Close the filter after applying
215
+ }
216
+ };
232
217
 
233
- setCheckedItems(resetState);
234
- setSelectedBrands(resetBrands);
235
- setPointsRange({ min: rangeInitialMin, max: rangeInitialMax });
236
- setResetCounter((prev) => prev + 1);
237
- };
238
-
239
- const closeBottomSheet = useCallback(() => {
240
- if (bottomSheetRef.current) {
241
- bottomSheetRef.current.close();
242
- }
243
- setIsVisible(false);
244
- if (onClose) {
245
- onClose();
246
- }
247
- }, [onClose]);
218
+ const handleResetAll = () => {
219
+ const resetBrands = brands.reduce((acc, option) => {
220
+ acc[option.id] = false;
221
+ return acc;
222
+ }, {} as Record<string, boolean>);
248
223
 
249
- // If not visible, don't render anything
250
- if (!isVisible) {
251
- return null;
252
- }
224
+ setCheckedItem(null);
225
+ setSelectedBrands(resetBrands);
226
+ setPointsRange({ min: rangeInitialMin, max: rangeInitialMax });
227
+ setResetCounter((prev) => prev + 1);
228
+ };
253
229
 
254
- return (
255
- <GestureHandlerRootView style={styles.overlayContainer}>
256
- {/* Semi-transparent overlay */}
257
- <TouchableWithoutFeedback onPress={closeBottomSheet}>
258
- <View style={[styles.overlay, { backgroundColor: overlayColor }]} />
259
- </TouchableWithoutFeedback>
260
-
261
- <BottomSheet
262
- ref={bottomSheetRef}
263
- index={bottomSheetIndex}
264
- handleComponent={() => null}
265
- onChange={handleSheetChanges}
266
- style={bottomSheetStyle}
267
- backgroundStyle={{ backgroundColor: theme.surface }}
268
- handleIndicatorStyle={[styles.handleIndicator, handleIndicatorStyle]}
269
- // snapPoints={snapPoints}
270
- enablePanDownToClose={true}
271
- // onClose={() => {
272
- // setIsVisible(false);
273
- // if (onClose) onClose();
274
- // }}
275
- >
276
- <View style={[styles.container, containerStyle]}>
277
- <View style={[styles.header, headerStyle]}>
278
- <Text style={[styles.title, titleStyle]}>{headerTitleText}</Text>
279
- <TouchableOpacity onPress={handleResetAll}>
280
- <Text style={[styles.resetText, resetTextStyle]}>
281
- {headerResetText}
282
- </Text>
283
- </TouchableOpacity>
284
- </View>
285
- <BottomSheetView style={{ paddingBottom: 75 }}>
286
- {sortOptions && sortOptions.length > 0 && (
287
- <View style={[styles.section, sectionStyle, sortSectionStyle]}>
288
- <Text style={[styles.sectionTitle, sectionTitleStyle]}>
289
- {sortSectionTitle}
290
- </Text>
291
- {sortOptions.map((option) => (
292
- <View
293
- style={[styles.optionRow, optionRowStyle]}
294
- key={option.id}
295
- >
296
- <Checkbox
297
- value={checkedItems[option.id]}
298
- color={checkboxColor}
299
- hitSlop={{ top: 10, right: 10, bottom: 10, left: 10 }}
300
- onValueChange={() =>
301
- handleCheckboxChange(option.id.toString())
302
- }
303
- />
304
- <Text style={[styles.optionText, optionTextStyle]}>
305
- {option.name}
306
- </Text>
307
- </View>
308
- ))}
309
- </View>
310
- )}
230
+ const closeBottomSheet = useCallback(() => {
231
+ if (bottomSheetRef.current) {
232
+ bottomSheetRef.current.close();
233
+ }
234
+ setIsVisible(false);
235
+ if (onClose) {
236
+ onClose();
237
+ }
238
+ }, [onClose]);
311
239
 
312
- {showPointsRange && (
313
- <View style={[styles.section, sectionStyle]}>
314
- <Text style={[styles.sectionTitle, sectionTitleStyle]}>
315
- {pointsRangeSectionTitle}
316
- </Text>
317
- <PointsRangeSelector
318
- resetKey={resetCounter}
319
- initialMax={rangeInitialMax}
320
- initialMin={rangeInitialMin}
321
- minLimit={rangeMinLimit}
322
- maxLimit={rangeMaxLimit}
323
- isRTL={isRTL}
324
- containerStyle={pointsRangeContainerStyle}
325
- inputsContainerStyle={pointsRangeInputsContainerStyle}
326
- customInputContainerStyle={
327
- pointsRangeCustomInputContainerStyle
328
- }
329
- customInputFieldStyle={pointsRangeCustomInputFieldStyle}
330
- sliderContainerStyle={pointsRangeSliderContainerStyle}
331
- multiSliderContainerStyle={
332
- pointsRangeMultiSliderContainerStyle
333
- }
334
- trackStyle={pointsRangeTrackStyle}
335
- selectedTrackStyle={pointsRangeSelectedTrackStyle}
336
- unselectedTrackStyle={pointsRangeUnselectedTrackStyle}
337
- markerStyle={pointsRangeMarkerStyle}
338
- markerEnabledStyle={pointsRangeMarkerEnabledStyle}
339
- markerDisabledStyle={pointsRangeMarkerDisabledStyle}
340
- markerDotStyle={pointsRangeMarkerDotStyle}
341
- inputProps={pointsRangeInputProps}
342
- multiSliderProps={pointsRangeMultiSliderProps}
343
- onChange={(min: number, max: number) => {
344
- setPointsRange({ min, max });
345
- }}
346
- />
347
- </View>
348
- )}
240
+ // If not visible, don't render anything
241
+ if (!isVisible) {
242
+ return null;
243
+ }
349
244
 
350
- {brands && brands.length > 0 && (
351
- <View style={[styles.section, sectionStyle]}>
352
- <Text style={[styles.sectionTitle, sectionTitleStyle]}>
353
- {brandSectionTile}
245
+ return (
246
+ <GestureHandlerRootView style={styles.overlayContainer}>
247
+ {/* Semi-transparent overlay */}
248
+ <TouchableWithoutFeedback onPress={closeBottomSheet}>
249
+ <View style={[styles.overlay, { backgroundColor: overlayColor }]} />
250
+ </TouchableWithoutFeedback>
251
+
252
+ <BottomSheet
253
+ ref={bottomSheetRef}
254
+ index={bottomSheetIndex}
255
+ handleComponent={() => null}
256
+ onChange={handleSheetChanges}
257
+ style={bottomSheetStyle}
258
+ backgroundStyle={{ backgroundColor: theme.surface }}
259
+ handleIndicatorStyle={[styles.handleIndicator, handleIndicatorStyle]}
260
+ // snapPoints={snapPoints}
261
+ enablePanDownToClose={true}
262
+ onClose={() => {
263
+ setIsVisible(false);
264
+ if (onClose) onClose();
265
+ }}
266
+ >
267
+ <View style={[styles.container, containerStyle]}>
268
+ <View style={[styles.header, headerStyle]}>
269
+ <Text style={[styles.title, titleStyle]}>{headerTitleText}</Text>
270
+ <TouchableOpacity onPress={handleResetAll}>
271
+ <Text style={[styles.resetText, resetTextStyle]}>
272
+ {headerResetText}
354
273
  </Text>
355
- <View style={[styles.brandsGrid, brandContainerStyle]}>
356
- {brands.map((brand) => (
357
- <BrandIcon
358
- key={brand.id}
359
- size={50}
360
- selected={selectedBrands[brand.id]}
361
- onPress={() => handleBrandSelect(brand.id.toString())}
362
- brand={{
363
- id: brand.id,
364
- name: brand.name,
365
- logo: brand.logo,
366
- }}
367
- selectionIndicatorIcon={
368
- brandActiveIcon || (
369
- <Ionicons
370
- name="checkmark-outline"
371
- color={theme.onPrimary}
372
- />
373
- )
374
- }
375
- selectionIndicatorStyle={brandActiveIconStyle}
376
- />
274
+ </TouchableOpacity>
275
+ </View>
276
+ <BottomSheetView style={{ paddingBottom: 75 }}>
277
+ {sortOptions && sortOptions.length > 0 && (
278
+ <View style={[styles.section, sectionStyle, sortSectionStyle]}>
279
+ <Text style={[styles.sectionTitle, sectionTitleStyle]}>
280
+ {sortSectionTitle}
281
+ </Text>
282
+ {sortOptions.map((option) => (
283
+ <View
284
+ style={[styles.optionRow, optionRowStyle]}
285
+ key={option.id}
286
+ >
287
+ <Checkbox
288
+ value={option.id == checkedItem}
289
+ color={checkboxColor}
290
+ hitSlop={{ top: 10, right: 10, bottom: 10, left: 10 }}
291
+ onValueChange={() =>
292
+ handleCheckboxChange(option.id)
293
+ }
294
+ />
295
+ <Text style={[styles.optionText, optionTextStyle]}>
296
+ {option.name}
297
+ </Text>
298
+ </View>
377
299
  ))}
378
300
  </View>
379
- </View>
380
- )}
301
+ )}
381
302
 
382
- <TouchableOpacity
383
- style={[styles.applyButton, applyButtonStyle]}
384
- onPress={handleApplyFilter}
385
- >
386
- <Text style={[styles.applyButtonText, applyButtonTextStyle]}>
387
- {applyButtonText}
388
- </Text>
389
- </TouchableOpacity>
390
- </BottomSheetView>
391
- </View>
392
- </BottomSheet>
393
- </GestureHandlerRootView>
394
- );
395
- };
303
+ {showPointsRange && (
304
+ <View style={[styles.section, sectionStyle]}>
305
+ <Text style={[styles.sectionTitle, sectionTitleStyle]}>
306
+ {pointsRangeSectionTitle}
307
+ </Text>
308
+ <PointsRangeSelector
309
+ resetKey={resetCounter}
310
+ initialMax={rangeInitialMax}
311
+ initialMin={rangeInitialMin}
312
+ minLimit={rangeMinLimit}
313
+ maxLimit={rangeMaxLimit}
314
+ isRTL={isRTL}
315
+ containerStyle={pointsRangeContainerStyle}
316
+ inputsContainerStyle={pointsRangeInputsContainerStyle}
317
+ customInputContainerStyle={
318
+ pointsRangeCustomInputContainerStyle
319
+ }
320
+ customInputFieldStyle={pointsRangeCustomInputFieldStyle}
321
+ sliderContainerStyle={pointsRangeSliderContainerStyle}
322
+ multiSliderContainerStyle={
323
+ pointsRangeMultiSliderContainerStyle
324
+ }
325
+ trackStyle={pointsRangeTrackStyle}
326
+ selectedTrackStyle={pointsRangeSelectedTrackStyle}
327
+ unselectedTrackStyle={pointsRangeUnselectedTrackStyle}
328
+ markerStyle={pointsRangeMarkerStyle}
329
+ markerEnabledStyle={pointsRangeMarkerEnabledStyle}
330
+ markerDisabledStyle={pointsRangeMarkerDisabledStyle}
331
+ markerDotStyle={pointsRangeMarkerDotStyle}
332
+ inputProps={pointsRangeInputProps}
333
+ multiSliderProps={pointsRangeMultiSliderProps}
334
+ onChange={(min: number, max: number) => {
335
+ setPointsRange({ min, max });
336
+ }}
337
+ />
338
+ </View>
339
+ )}
340
+
341
+ {brands && brands.length > 0 && (
342
+ <View style={[styles.section, sectionStyle]}>
343
+ <Text style={[styles.sectionTitle, sectionTitleStyle]}>
344
+ {brandSectionTile}
345
+ </Text>
346
+ <View style={[styles.brandsGrid, brandContainerStyle]}>
347
+ {brands.map((brand) => (
348
+ <BrandIcon
349
+ key={brand.id}
350
+ size={50}
351
+ selected={selectedBrands[brand.id]}
352
+ onPress={() => handleBrandSelect(brand.id.toString())}
353
+ brand={{
354
+ id: brand.id,
355
+ name: brand.name,
356
+ logo: brand.logo,
357
+ }}
358
+ selectionIndicatorIcon={
359
+ brandActiveIcon || (
360
+ <Ionicons
361
+ name="checkmark-outline"
362
+ color={theme.onPrimary}
363
+ />
364
+ )
365
+ }
366
+ selectionIndicatorStyle={brandActiveIconStyle}
367
+ />
368
+ ))}
369
+ </View>
370
+ </View>
371
+ )}
372
+
373
+ <TouchableOpacity
374
+ style={[styles.applyButton, applyButtonStyle]}
375
+ onPress={handleApplyFilter}
376
+ >
377
+ <Text style={[styles.applyButtonText, applyButtonTextStyle]}>
378
+ {applyButtonText}
379
+ </Text>
380
+ </TouchableOpacity>
381
+ </BottomSheetView>
382
+ </View>
383
+ </BottomSheet>
384
+ </GestureHandlerRootView>
385
+ );
386
+ };
396
387
 
397
- const createStyles = (theme: ThemeType, isRTL: boolean) =>
398
- StyleSheet.create({
399
- overlayContainer: {
400
- flex: 1,
401
- position: 'absolute',
402
- top: 0,
403
- left: 0,
404
- right: 0,
405
- bottom: 0,
406
- zIndex: 1000,
407
- },
408
- overlay: {
409
- ...StyleSheet.absoluteFillObject,
410
- backgroundColor: 'rgba(0, 0, 0, 0.5)',
411
- },
412
- container: {
413
- flex: 1,
414
- paddingHorizontal: 25,
415
- backgroundColor: theme.surface,
416
- },
417
- handleIndicator: {
418
- width: 40,
419
- height: 4,
420
- backgroundColor: theme.border,
421
- alignSelf: "center",
422
- marginTop: 8,
423
- borderRadius: 2,
424
- },
425
- header: {
426
- flexDirection: isRTL ? "row-reverse" : "row",
427
- justifyContent: "space-between",
428
- alignItems: "center",
429
- paddingVertical: 15,
430
- borderBottomWidth: 1,
431
- borderBottomColor: theme.border,
432
- },
433
- title: {
434
- fontSize: 18,
435
- fontWeight: "bold",
436
- color: theme.text,
437
- textAlign: isRTL ? "right" : "left",
438
- },
439
- resetText: {
440
- fontSize: 14,
441
- color: theme.primary,
442
- fontWeight: "500",
443
- textAlign: isRTL ? "left" : "right",
444
- },
445
- section: {
446
- marginTop: 20,
447
- },
448
- sectionTitle: {
449
- fontSize: 16,
450
- fontWeight: "500",
451
- color: theme.helper,
452
- marginBottom: 15,
453
- textAlign: isRTL ? "right" : "left",
454
- },
455
- optionRow: {
456
- flexDirection: isRTL ? "row-reverse" : "row",
457
- alignItems: "center",
458
- marginBottom: 15,
459
- gap: 5,
460
- },
461
- optionText: {
462
- fontSize: 15,
463
- color: theme.text,
464
- textAlign: isRTL ? "right" : "left",
465
- marginLeft: isRTL ? 0 : 8,
466
- marginRight: isRTL ? 8 : 0,
467
- },
468
- brandsGrid: {
469
- flexDirection: "row",
470
- flexWrap: "wrap",
471
- gap: 10,
472
- justifyContent: isRTL ? "flex-end" : "flex-start",
473
- },
474
- applyButton: {
475
- backgroundColor: theme.primary,
476
- borderRadius: 30,
477
- paddingVertical: 15,
478
- alignItems: "center",
479
- marginTop: 30,
480
- },
481
- applyButtonText: {
482
- color: theme.onPrimary,
483
- fontSize: 16,
484
- fontWeight: "bold",
485
- },
486
- });
388
+ const createStyles = (theme: ThemeType, isRTL: boolean) =>
389
+ StyleSheet.create({
390
+ overlayContainer: {
391
+ flex: 1,
392
+ position: 'absolute',
393
+ top: 0,
394
+ left: 0,
395
+ right: 0,
396
+ bottom: 0,
397
+ zIndex: 1000,
398
+ },
399
+ overlay: {
400
+ ...StyleSheet.absoluteFillObject,
401
+ backgroundColor: 'rgba(0, 0, 0, 0.5)',
402
+ },
403
+ container: {
404
+ flex: 1,
405
+ paddingHorizontal: 25,
406
+ backgroundColor: theme.surface,
407
+ },
408
+ handleIndicator: {
409
+ width: 40,
410
+ height: 4,
411
+ backgroundColor: theme.border,
412
+ alignSelf: "center",
413
+ marginTop: 8,
414
+ borderRadius: 2,
415
+ },
416
+ header: {
417
+ flexDirection: isRTL ? "row-reverse" : "row",
418
+ justifyContent: "space-between",
419
+ alignItems: "center",
420
+ paddingVertical: 15,
421
+ borderBottomWidth: 1,
422
+ borderBottomColor: theme.border,
423
+ },
424
+ title: {
425
+ fontSize: 18,
426
+ fontWeight: "bold",
427
+ color: theme.text,
428
+ textAlign: isRTL ? "right" : "left",
429
+ },
430
+ resetText: {
431
+ fontSize: 14,
432
+ color: theme.primary,
433
+ fontWeight: "500",
434
+ textAlign: isRTL ? "left" : "right",
435
+ },
436
+ section: {
437
+ marginTop: 20,
438
+ },
439
+ sectionTitle: {
440
+ fontSize: 16,
441
+ fontWeight: "500",
442
+ color: theme.helper,
443
+ marginBottom: 15,
444
+ textAlign: isRTL ? "right" : "left",
445
+ },
446
+ optionRow: {
447
+ flexDirection: isRTL ? "row-reverse" : "row",
448
+ alignItems: "center",
449
+ marginBottom: 15,
450
+ gap: 5,
451
+ },
452
+ optionText: {
453
+ fontSize: 15,
454
+ color: theme.text,
455
+ textAlign: isRTL ? "right" : "left",
456
+ marginLeft: isRTL ? 0 : 8,
457
+ marginRight: isRTL ? 8 : 0,
458
+ },
459
+ brandsGrid: {
460
+ flexDirection: "row",
461
+ flexWrap: "wrap",
462
+ gap: 10,
463
+ justifyContent: isRTL ? "flex-end" : "flex-start",
464
+ },
465
+ applyButton: {
466
+ backgroundColor: theme.primary,
467
+ borderRadius: 30,
468
+ paddingVertical: 15,
469
+ alignItems: "center",
470
+ marginTop: 30,
471
+ },
472
+ applyButtonText: {
473
+ color: theme.onPrimary,
474
+ fontSize: 16,
475
+ fontWeight: "bold",
476
+ },
477
+ });
487
478
 
488
- export default Filters;
479
+ export default Filters;