@devtravelcode/widget-native 1.0.2 → 1.0.3

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.
Files changed (32) hide show
  1. package/dist/App.js +8 -5
  2. package/dist/modules/hooks/useHotelMapData.d.ts +1 -1
  3. package/dist/modules/hooks/useHotelMapData.js +26 -32
  4. package/dist/modules/search-form/AgeSelector.js +4 -1
  5. package/dist/modules/search-form/NationalityInput.js +7 -3
  6. package/dist/modules/search-form/TimePicker.js +4 -3
  7. package/dist/modules/search-form/flight/AirlinesSelector.js +7 -3
  8. package/dist/modules/search-form/flight/DatePicker.js +14 -2
  9. package/dist/modules/search-form/flight/FlightSearchForm.js +2 -1
  10. package/dist/modules/search-form/flight/LocationInput.js +6 -2
  11. package/dist/modules/search-form/flight/PassengersPicker.js +9 -4
  12. package/dist/modules/search-form/flight/SwitchLocationBtn.js +4 -1
  13. package/dist/modules/search-form/flight/flight-filters/FiltersContent.d.ts +1 -0
  14. package/dist/modules/search-form/flight/flight-filters/FiltersContent.js +14 -13
  15. package/dist/modules/search-form/flight/flight-filters/FlightFiltersDynamic.js +3 -2
  16. package/dist/modules/search-form/flight/flight-filters/RangeBlock.d.ts +1 -0
  17. package/dist/modules/search-form/flight/flight-filters/RangeBlock.js +5 -3
  18. package/dist/modules/search-form/flight/flight-results/FlightCard.js +3 -2
  19. package/dist/modules/search-form/flight/flight-results/FlightPriceBlock.js +4 -1
  20. package/dist/modules/search-form/flight/flight-results/ProvidersLoader.js +4 -1
  21. package/dist/modules/search-form/hotel/GuestSelector.js +14 -9
  22. package/dist/modules/search-form/hotel/HotelLocation.js +6 -2
  23. package/dist/modules/search-form/hotel/HotelResults.d.ts +1 -0
  24. package/dist/modules/search-form/hotel/HotelResults.js +32 -6
  25. package/dist/modules/search-form/hotel/components/HotelCard.d.ts +1 -0
  26. package/dist/modules/search-form/hotel/components/HotelCard.js +39 -5
  27. package/dist/modules/search-form/hotel/components/HotelList.d.ts +1 -0
  28. package/dist/modules/search-form/hotel/components/HotelList.js +2 -2
  29. package/dist/modules/search-form/hotel/components/HotelMap.js +40 -9
  30. package/dist/modules/search-form/hotel/hotel-filters/HotelFilters.js +12 -5
  31. package/index.ts +7 -0
  32. package/package.json +2 -2
@@ -83,15 +83,45 @@ const CardGallery = React.memo(({ images }) => {
83
83
  setActiveIndex(idx);
84
84
  }, renderItem: ({ item }) => (_jsx(Image, { source: { uri: item }, style: styles.galleryImage, resizeMode: "cover" })) }), images.length > 1 && (_jsx(View, { style: styles.galleryDots, children: images.slice(0, 5).map((_, i) => (_jsx(View, { style: [styles.galleryDot, i === activeIndex && styles.galleryDotActive] }, i))) }))] }));
85
85
  });
86
- const HotelDetailCard = React.memo(({ hotelData, pin, translations, lang, token, basketLink, onClose, slideAnim }) => {
86
+ const HotelDetailCard = React.memo(({ hotelData, pin, translations, lang, token, basketLink, searchParams, btnColor, onClose, slideAnim }) => {
87
87
  const sign = getCurrencySign(pin.currency);
88
88
  const nightlyPrice = hotelData?.nightlyPrice || hotelData?.price;
89
89
  const totalPrice = hotelData?.totalPrice || hotelData?.total;
90
90
  const handleViewDetails = useCallback(() => {
91
91
  const HOST = basketLink || 'https://travel-code.com';
92
- const url = `${HOST}${hotelData?.url || '#'}&accessToken=${token}&language=${lang}`;
92
+ if (!searchParams) {
93
+ const url = `${HOST}${hotelData?.url || '#'}&accessToken=${token}&language=${lang}`;
94
+ Linking.openURL(url).catch(() => { });
95
+ return;
96
+ }
97
+ const propertyId = hotelData?.propertyId || hotelData?.id || pin.id;
98
+ if (!propertyId) {
99
+ Linking.openURL(`${HOST}${hotelData?.url || '#'}&accessToken=${token}&language=${lang}`).catch(() => { });
100
+ return;
101
+ }
102
+ const partnerId = hotelData?.partnerId || hotelData?.pId || 0;
103
+ const guestsClean = (searchParams.guests || []).map((r) => {
104
+ const g = { adults: r.adults };
105
+ if (r.children > 0) {
106
+ g.children = r.children;
107
+ if (r.childrenAges?.length)
108
+ g.childrenAges = r.childrenAges;
109
+ }
110
+ return g;
111
+ });
112
+ const guestsB64 = btoa(JSON.stringify(guestsClean));
113
+ const params = new URLSearchParams({
114
+ checkinDate: searchParams.checkin || '',
115
+ checkoutDate: searchParams.checkout || '',
116
+ guests: guestsB64,
117
+ nationality: searchParams.countryCode || '',
118
+ partner: '0',
119
+ cpPartner: String(partnerId),
120
+ location: String(searchParams.location || ''),
121
+ });
122
+ const url = `${HOST}/hotels/${propertyId}?${params.toString()}&accessToken=${token}&language=${lang}`;
93
123
  Linking.openURL(url).catch(() => { });
94
- }, [hotelData, token, lang, basketLink]);
124
+ }, [hotelData, pin, token, lang, basketLink, searchParams]);
95
125
  const panResponder = useRef(PanResponder.create({
96
126
  onStartShouldSetPanResponder: () => false,
97
127
  onMoveShouldSetPanResponder: (_, g) => g.dy > 10,
@@ -121,7 +151,7 @@ const HotelDetailCard = React.memo(({ hotelData, pin, translations, lang, token,
121
151
  !hotelData.refundable && styles.bottomCardRefundGray,
122
152
  ], numberOfLines: 1, children: hotelData.refundable
123
153
  ? translations['hotels_refundable'] || 'Free cancellation'
124
- : translations['hotels_non_refundable'] || 'Non refundable' })), nightlyPrice ? (_jsxs(Text, { style: styles.bottomCardPriceInfo, children: [translations['hotels_price_per_night_label'] || 'Price per night', " ", sign, nightlyPrice.toFixed?.(2) || nightlyPrice] })) : null, totalPrice ? (_jsxs(Text, { style: styles.bottomCardPriceInfo, children: [translations['hotels_total_for_stay'] || 'Total for stay', " ", sign, totalPrice.toFixed?.(2) || totalPrice] })) : null, _jsxs(View, { style: styles.bottomCardPriceRow, children: [_jsxs(Text, { style: styles.bottomCardPrice, children: [translations['hotels_per_night'] || 'per night', " ", sign, nightlyPrice ? (nightlyPrice.toFixed?.(2) || nightlyPrice) : pin.price] }), _jsx(TouchableOpacity, { style: styles.viewDetailsBtn, onPress: handleViewDetails, children: _jsx(Text, { style: styles.viewDetailsArrow, children: '\u2192' }) })] })] })] }));
154
+ : translations['hotels_non_refundable'] || 'Non refundable' })), nightlyPrice ? (_jsxs(Text, { style: styles.bottomCardPriceInfo, children: [translations['hotels_price_per_night_label'] || 'Price per night', " ", sign, nightlyPrice.toFixed?.(2) || nightlyPrice] })) : null, totalPrice ? (_jsxs(Text, { style: styles.bottomCardPriceInfo, children: [translations['hotels_total_for_stay'] || 'Total for stay', " ", sign, totalPrice.toFixed?.(2) || totalPrice] })) : null, _jsxs(View, { style: styles.bottomCardPriceRow, children: [_jsxs(Text, { style: styles.bottomCardPrice, children: [translations['hotels_per_night'] || 'per night', " ", sign, nightlyPrice ? (nightlyPrice.toFixed?.(2) || nightlyPrice) : pin.price] }), _jsx(TouchableOpacity, { style: [styles.viewDetailsBtn, { backgroundColor: btnColor }], onPress: handleViewDetails, children: _jsx(Text, { style: styles.viewDetailsArrow, children: '\u2192' }) })] })] })] }));
125
155
  });
126
156
  const ErrorCard = React.memo(({ translations, onClose, onRefresh, slideAnim }) => (_jsxs(Animated.View, { style: [
127
157
  styles.bottomCard,
@@ -129,7 +159,8 @@ const ErrorCard = React.memo(({ translations, onClose, onRefresh, slideAnim }) =
129
159
  ], children: [_jsx(View, { style: styles.bottomCardHandle }), _jsx(TouchableOpacity, { style: styles.bottomCardClose, onPress: onClose, children: _jsx(Text, { style: styles.bottomCardCloseText, children: '\u00D7' }) }), _jsxs(View, { style: styles.errorCardContent, children: [_jsx(Text, { style: styles.errorCardText, children: translations['map_search_expired'] || 'Your search may have expired. Please refresh to see current prices.' }), onRefresh && (_jsx(TouchableOpacity, { style: styles.errorCardBtn, onPress: onRefresh, activeOpacity: 0.8, children: _jsx(Text, { style: styles.errorCardBtnText, children: translations['map_refresh'] || 'Refresh search' }) }))] })] })));
130
160
  const HotelMap = ({ pins, allHotels = [], streamCompleted = false, loading = false, selectedHotelId: externalSelectedId, onHotelSelect, onRefreshSearch, translations, lang, searchParams, }) => {
131
161
  const token = useApiToken();
132
- const { config, currency } = useWidget();
162
+ const { config, currency, colors } = useWidget();
163
+ const btnColor = colors.primary || Colors.primary;
133
164
  const insets = useSafeAreaInsets();
134
165
  const mapRef = useRef(null);
135
166
  const [region, setRegion] = useState(DEFAULT_REGION);
@@ -296,8 +327,8 @@ const HotelMap = ({ pins, allHotels = [], streamCompleted = false, loading = fal
296
327
  return (_jsx(Marker, { coordinate: {
297
328
  latitude: geometry.coordinates[1],
298
329
  longitude: geometry.coordinates[0],
299
- }, onPress: onPress, tracksViewChanges: true, children: _jsx(View, { style: styles.clusterBubble, children: _jsxs(Text, { style: styles.clusterBubbleText, children: [count, " ", hotelsLabel] }) }) }, `cluster-${id}`));
300
- }, [hotelsLabel]);
330
+ }, onPress: onPress, tracksViewChanges: true, children: _jsx(View, { style: [styles.clusterBubble, { backgroundColor: btnColor }], children: _jsxs(Text, { style: styles.clusterBubbleText, children: [count, " ", hotelsLabel] }) }) }, `cluster-${id}`));
331
+ }, [hotelsLabel, btnColor]);
301
332
  const renderMarkers = useCallback(() => pins.map((pin) => {
302
333
  const isSelected = selectedPin?.id === pin.id;
303
334
  const isLoading = loadingPinId === pin.id;
@@ -306,9 +337,9 @@ const HotelMap = ({ pins, allHotels = [], streamCompleted = false, loading = fal
306
337
  return (_jsx(Marker, { coordinate: { latitude: pin.lat, longitude: pin.lng }, onPress: () => handlePinPress(pin), tracksViewChanges: true, zIndex: isSelected ? 1000 : 1, children: _jsx(PriceBadge, { price: pin.price, currency: pin.currency, selected: isSelected, soldOut: pin.soldOut, loading: isLoading, viewed: isViewed, error: isError }) }, `pin-${pin.id}`));
307
338
  }), [pins, selectedPin, loadingPinId, errorPinId, viewedPins, handlePinPress]);
308
339
  if (loading && pins.length === 0) {
309
- return (_jsxs(View, { style: styles.loaderContainer, children: [_jsx(ActivityIndicator, { size: "large", color: Colors.primary }), _jsx(Text, { style: styles.loaderText, children: translations['map_loader'] || 'Loading map...' })] }));
340
+ return (_jsxs(View, { style: styles.loaderContainer, children: [_jsx(ActivityIndicator, { size: "large", color: btnColor }), _jsx(Text, { style: styles.loaderText, children: translations['map_loader'] || 'Loading map...' })] }));
310
341
  }
311
- return (_jsxs(View, { style: styles.container, children: [_jsx(ClusteredMapView, { provider: PROVIDER_GOOGLE, ref: mapRef, style: styles.map, initialRegion: DEFAULT_REGION, onRegionChangeComplete: handleRegionChange, onPress: handleMapPress, showsUserLocation: false, showsPointsOfInterest: false, showsBuildings: false, mapPadding: { top: 0, right: 0, bottom: 0, left: 0 }, clusterColor: Colors.primary, clusterTextColor: Colors.white, clusterFontFamily: undefined, renderCluster: renderCluster, radius: 60, maxZoom: 16, minPoints: 2, animationEnabled: false, children: renderMarkers() }), loading && pins.length > 0 && (_jsx(View, { style: styles.loadingOverlay, children: _jsx(ActivityIndicator, { size: "small", color: Colors.primary }) })), _jsxs(View, { style: styles.zoomControls, children: [_jsx(TouchableOpacity, { style: styles.zoomBtn, onPress: handleZoomIn, activeOpacity: 0.7, children: _jsx(Text, { style: styles.zoomBtnText, children: "+" }) }), _jsx(View, { style: styles.zoomDivider }), _jsx(TouchableOpacity, { style: styles.zoomBtn, onPress: handleZoomOut, activeOpacity: 0.7, children: _jsx(Text, { style: styles.zoomBtnText, children: '\u2212' }) })] }), selectedPin && errorPinId && (_jsx(ErrorCard, { translations: translations, onClose: closeBottomCard, onRefresh: onRefreshSearch, slideAnim: slideAnim })), selectedPin && !errorPinId && (detailsLoading || hotelData) && (_jsx(HotelDetailCard, { hotelData: hotelData, pin: selectedPin, translations: translations, lang: lang, token: token, basketLink: config?.additional?.basket_link?.trim() || '', onClose: closeBottomCard, slideAnim: slideAnim })), _jsx(Modal, { visible: isFullscreen, animationType: "slide", presentationStyle: "fullScreen", onRequestClose: () => setIsFullscreen(false), children: _jsxs(View, { style: styles.fullscreenContainer, children: [_jsx(TouchableOpacity, { style: [styles.fullscreenCloseBtn, { top: insets.top + Spacing.sm }], onPress: () => setIsFullscreen(false), activeOpacity: 0.7, children: _jsx(Text, { style: styles.fullscreenCloseBtnText, children: '\u00D7' }) }), _jsx(ClusteredMapView, { provider: PROVIDER_GOOGLE, ref: mapRef, style: styles.map, initialRegion: region, onRegionChangeComplete: handleRegionChange, onPress: handleMapPress, showsUserLocation: false, showsPointsOfInterest: false, showsBuildings: false, clusterColor: Colors.primary, clusterTextColor: Colors.white, renderCluster: renderCluster, radius: 60, maxZoom: 16, minPoints: 2, animationEnabled: false, children: renderMarkers() }), _jsxs(View, { style: [styles.zoomControls, styles.zoomControlsFullscreen], children: [_jsx(TouchableOpacity, { style: styles.zoomBtn, onPress: handleZoomIn, activeOpacity: 0.7, children: _jsx(Text, { style: styles.zoomBtnText, children: "+" }) }), _jsx(View, { style: styles.zoomDivider }), _jsx(TouchableOpacity, { style: styles.zoomBtn, onPress: handleZoomOut, activeOpacity: 0.7, children: _jsx(Text, { style: styles.zoomBtnText, children: '\u2212' }) })] }), selectedPin && errorPinId && (_jsx(ErrorCard, { translations: translations, onClose: closeBottomCard, onRefresh: onRefreshSearch, slideAnim: slideAnim })), selectedPin && !errorPinId && (detailsLoading || hotelData) && (_jsx(HotelDetailCard, { hotelData: hotelData, pin: selectedPin, translations: translations, lang: lang, token: token, basketLink: config?.additional?.basket_link?.trim() || '', onClose: closeBottomCard, slideAnim: slideAnim }))] }) })] }));
342
+ return (_jsxs(View, { style: styles.container, children: [_jsx(ClusteredMapView, { provider: PROVIDER_GOOGLE, ref: mapRef, style: styles.map, initialRegion: DEFAULT_REGION, onRegionChangeComplete: handleRegionChange, onPress: handleMapPress, showsUserLocation: false, showsPointsOfInterest: false, showsBuildings: false, mapPadding: { top: 0, right: 0, bottom: 0, left: 0 }, clusterColor: btnColor, clusterTextColor: Colors.white, clusterFontFamily: undefined, renderCluster: renderCluster, radius: 60, maxZoom: 16, minPoints: 2, animationEnabled: false, children: renderMarkers() }), loading && pins.length > 0 && (_jsx(View, { style: styles.loadingOverlay, children: _jsx(ActivityIndicator, { size: "small", color: btnColor }) })), _jsxs(View, { style: styles.zoomControls, children: [_jsx(TouchableOpacity, { style: styles.zoomBtn, onPress: handleZoomIn, activeOpacity: 0.7, children: _jsx(Text, { style: styles.zoomBtnText, children: "+" }) }), _jsx(View, { style: styles.zoomDivider }), _jsx(TouchableOpacity, { style: styles.zoomBtn, onPress: handleZoomOut, activeOpacity: 0.7, children: _jsx(Text, { style: styles.zoomBtnText, children: '\u2212' }) })] }), selectedPin && errorPinId && (_jsx(ErrorCard, { translations: translations, onClose: closeBottomCard, onRefresh: onRefreshSearch, slideAnim: slideAnim })), selectedPin && !errorPinId && (detailsLoading || hotelData) && (_jsx(HotelDetailCard, { hotelData: hotelData, pin: selectedPin, translations: translations, lang: lang, token: token, basketLink: config?.additional?.basket_link?.trim() || '', searchParams: searchParams, btnColor: btnColor, onClose: closeBottomCard, slideAnim: slideAnim })), _jsx(Modal, { visible: isFullscreen, animationType: "slide", presentationStyle: "fullScreen", onRequestClose: () => setIsFullscreen(false), children: _jsxs(View, { style: styles.fullscreenContainer, children: [_jsx(TouchableOpacity, { style: [styles.fullscreenCloseBtn, { top: insets.top + Spacing.sm }], onPress: () => setIsFullscreen(false), activeOpacity: 0.7, children: _jsx(Text, { style: styles.fullscreenCloseBtnText, children: '\u00D7' }) }), _jsx(ClusteredMapView, { provider: PROVIDER_GOOGLE, ref: mapRef, style: styles.map, initialRegion: region, onRegionChangeComplete: handleRegionChange, onPress: handleMapPress, showsUserLocation: false, showsPointsOfInterest: false, showsBuildings: false, clusterColor: btnColor, clusterTextColor: Colors.white, renderCluster: renderCluster, radius: 60, maxZoom: 16, minPoints: 2, animationEnabled: false, children: renderMarkers() }), _jsxs(View, { style: [styles.zoomControls, styles.zoomControlsFullscreen], children: [_jsx(TouchableOpacity, { style: styles.zoomBtn, onPress: handleZoomIn, activeOpacity: 0.7, children: _jsx(Text, { style: styles.zoomBtnText, children: "+" }) }), _jsx(View, { style: styles.zoomDivider }), _jsx(TouchableOpacity, { style: styles.zoomBtn, onPress: handleZoomOut, activeOpacity: 0.7, children: _jsx(Text, { style: styles.zoomBtnText, children: '\u2212' }) })] }), selectedPin && errorPinId && (_jsx(ErrorCard, { translations: translations, onClose: closeBottomCard, onRefresh: onRefreshSearch, slideAnim: slideAnim })), selectedPin && !errorPinId && (detailsLoading || hotelData) && (_jsx(HotelDetailCard, { hotelData: hotelData, pin: selectedPin, translations: translations, lang: lang, token: token, basketLink: config?.additional?.basket_link?.trim() || '', searchParams: searchParams, btnColor: btnColor, onClose: closeBottomCard, slideAnim: slideAnim }))] }) })] }));
312
343
  };
313
344
  const styles = StyleSheet.create({
314
345
  container: {
@@ -53,7 +53,8 @@ const BOARD_OPTIONS = [
53
53
  { code: "AI", labelKey: "filter_all_inclusive", fallback: "All inclusive" },
54
54
  ];
55
55
  const HotelFilters = ({ translations, activeFilters, onQuickFilter, onOpenPopup, isPopupOpen, onClosePopup, onApplyFilters, onReset, externalValues, sessionId = null, filters = [], }) => {
56
- const { currency } = useWidget();
56
+ const { currency, colors } = useWidget();
57
+ const btnColor = colors.primary || Colors.primary;
57
58
  const insets = useSafeAreaInsets();
58
59
  const [values, setValues] = useState({ ...DEFAULT_VALUES });
59
60
  const [openSections, setOpenSections] = useState(["price"]);
@@ -134,29 +135,35 @@ const HotelFilters = ({ translations, activeFilters, onQuickFilter, onOpenPopup,
134
135
  : Array.from(new Set([...prev, stars])).sort((a, b) => a - b);
135
136
  updateFilterValue("starRating", next);
136
137
  };
137
- return (_jsxs(View, { children: [_jsxs(ScrollView, { horizontal: true, showsHorizontalScrollIndicator: false, style: styles.quickFiltersBar, contentContainerStyle: styles.quickFiltersContent, children: [_jsxs(TouchableOpacity, { style: styles.mainFilterChip, onPress: onOpenPopup, activeOpacity: 0.7, children: [_jsxs(Svg, { width: 18, height: 18, viewBox: "0 0 24 24", fill: "none", stroke: "#FFFFFF", strokeWidth: 2, strokeLinecap: "round", strokeLinejoin: "round", children: [_jsx(Line, { x1: 4, y1: 6, x2: 20, y2: 6 }), _jsx(Line, { x1: 8, y1: 12, x2: 16, y2: 12 }), _jsx(Line, { x1: 11, y1: 18, x2: 13, y2: 18 })] }), _jsx(Text, { style: styles.mainFilterText, children: t("filters_main", "Filters") })] }), QUICK_FILTERS.map((item) => (_jsx(TouchableOpacity, { style: [
138
+ return (_jsxs(View, { children: [_jsxs(ScrollView, { horizontal: true, showsHorizontalScrollIndicator: false, style: styles.quickFiltersBar, contentContainerStyle: styles.quickFiltersContent, children: [_jsxs(TouchableOpacity, { style: [styles.mainFilterChip, { backgroundColor: btnColor }], onPress: onOpenPopup, activeOpacity: 0.7, children: [_jsxs(Svg, { width: 18, height: 18, viewBox: "0 0 24 24", fill: "none", stroke: "#FFFFFF", strokeWidth: 2, strokeLinecap: "round", strokeLinejoin: "round", children: [_jsx(Line, { x1: 4, y1: 6, x2: 20, y2: 6 }), _jsx(Line, { x1: 8, y1: 12, x2: 16, y2: 12 }), _jsx(Line, { x1: 11, y1: 18, x2: 13, y2: 18 })] }), _jsx(Text, { style: styles.mainFilterText, children: t("filters_main", "Filters") })] }), QUICK_FILTERS.map((item) => (_jsx(TouchableOpacity, { style: [
138
139
  styles.filterChip,
139
140
  activeFilters.includes(item.key) && styles.filterChipActive,
141
+ activeFilters.includes(item.key) && { borderColor: btnColor, backgroundColor: btnColor + '1A' },
140
142
  ], onPress: () => onQuickFilter(item.key), activeOpacity: 0.7, children: _jsx(Text, { style: [
141
143
  styles.filterChipText,
142
144
  activeFilters.includes(item.key) && styles.filterChipTextActive,
143
- ], children: t(item.labelKey, item.fallback) }) }, item.key)))] }), _jsx(Modal, { visible: isPopupOpen, animationType: "slide", presentationStyle: "fullScreen", onRequestClose: onClosePopup, children: _jsxs(View, { style: [styles.modalContainer, { paddingTop: insets.top }], children: [_jsx(TouchableOpacity, { style: styles.closeButton, onPress: onClosePopup, hitSlop: { top: 8, bottom: 8, left: 8, right: 8 }, children: _jsx(CloseIcon, { size: 16 }) }), _jsx(View, { style: styles.modalHeader, children: _jsx(Text, { style: styles.modalTitle, children: t("filters_title", "Filters") }) }), _jsxs(ScrollView, { style: styles.modalContent, contentContainerStyle: styles.modalContentInner, showsVerticalScrollIndicator: false, scrollEnabled: scrollEnabled, children: [(has("price") || has("minprice") || has("maxprice")) && (_jsx(RangeBlock, { title: t("filter_price", "Price"), minName: "minPrice", maxName: "maxPrice", maxValue: 1000, step: 10, open: openSections.includes("price"), toggle: () => toggleSection("price"), getValue: getValue, handleRangeChange: handleRangeChange, getRangeStyle: getRangeStyle, formatter: (v) => `${v} ${currencySign}`, isShow: true, onDragStart: () => setScrollEnabled(false), onDragEnd: () => setScrollEnabled(true) })), has("starRating") && (_jsxs(View, { style: styles.section, children: [_jsx(View, { style: styles.sectionHeader, children: _jsx(Text, { style: styles.sectionTitle, children: t("filter_stars", "Number of stars") }) }), _jsx(View, { style: styles.sectionContent, children: [5, 4, 3, 2, 1].map((stars) => {
145
+ activeFilters.includes(item.key) && { color: btnColor },
146
+ ], children: t(item.labelKey, item.fallback) }) }, item.key)))] }), _jsx(Modal, { visible: isPopupOpen, animationType: "slide", presentationStyle: "fullScreen", onRequestClose: onClosePopup, children: _jsxs(View, { style: [styles.modalContainer, { paddingTop: insets.top }], children: [_jsx(TouchableOpacity, { style: styles.closeButton, onPress: onClosePopup, hitSlop: { top: 8, bottom: 8, left: 8, right: 8 }, children: _jsx(CloseIcon, { size: 16 }) }), _jsx(View, { style: styles.modalHeader, children: _jsx(Text, { style: styles.modalTitle, children: t("filters_title", "Filters") }) }), _jsxs(ScrollView, { style: styles.modalContent, contentContainerStyle: styles.modalContentInner, showsVerticalScrollIndicator: false, scrollEnabled: scrollEnabled, children: [(has("price") || has("minprice") || has("maxprice")) && (_jsx(RangeBlock, { title: t("filter_price", "Price"), minName: "minPrice", maxName: "maxPrice", maxValue: 1000, step: 10, open: openSections.includes("price"), toggle: () => toggleSection("price"), getValue: getValue, handleRangeChange: handleRangeChange, getRangeStyle: getRangeStyle, formatter: (v) => `${v} ${currencySign}`, isShow: true, onDragStart: () => setScrollEnabled(false), onDragEnd: () => setScrollEnabled(true), accentColor: btnColor })), has("starRating") && (_jsxs(View, { style: styles.section, children: [_jsx(View, { style: styles.sectionHeader, children: _jsx(Text, { style: styles.sectionTitle, children: t("filter_stars", "Number of stars") }) }), _jsx(View, { style: styles.sectionContent, children: [5, 4, 3, 2, 1].map((stars) => {
144
147
  const isChecked = Array.isArray(values.starRating) &&
145
148
  values.starRating.includes(stars);
146
149
  return (_jsxs(TouchableOpacity, { style: styles.checkboxRow, onPress: () => toggleStar(stars), activeOpacity: 0.7, children: [_jsx(View, { style: [
147
150
  styles.checkbox,
148
151
  isChecked && styles.checkboxChecked,
152
+ isChecked && { backgroundColor: btnColor, borderColor: btnColor },
149
153
  ], children: isChecked && (_jsx(Text, { style: styles.checkmark, children: "\u2713" })) }), _jsxs(Text, { style: styles.checkboxLabel, children: [stars, " ", t("filter_stars_suffix", "stars")] })] }, stars));
150
154
  }) })] })), has("payments") && (_jsxs(View, { style: styles.section, children: [_jsx(View, { style: styles.sectionHeader, children: _jsx(Text, { style: styles.sectionTitle, children: t("filter_payments", "Payment") }) }), _jsx(View, { style: styles.sectionContent, children: _jsxs(TouchableOpacity, { style: styles.checkboxRow, onPress: () => updateFilterValue("payments", values.payments === "full_refund" ? null : "full_refund"), activeOpacity: 0.7, children: [_jsx(View, { style: [
151
155
  styles.checkbox,
152
156
  values.payments === "full_refund" && styles.checkboxChecked,
157
+ values.payments === "full_refund" && { backgroundColor: btnColor, borderColor: btnColor },
153
158
  ], children: values.payments === "full_refund" && (_jsx(Text, { style: styles.checkmark, children: "\u2713" })) }), _jsx(Text, { style: styles.checkboxLabel, children: t("filter_full_refund", "Full refund") })] }) })] })), has("boards") && (_jsxs(View, { style: styles.section, children: [_jsx(View, { style: styles.sectionHeader, children: _jsx(Text, { style: styles.sectionTitle, children: t("filter_meals", "Meals") }) }), _jsxs(View, { style: styles.sectionContent, children: [_jsxs(TouchableOpacity, { style: styles.radioRow, onPress: () => updateFilterValue("boards", null), activeOpacity: 0.7, children: [_jsx(View, { style: [
154
159
  styles.radio,
155
160
  values.boards === null && styles.radioSelected,
156
- ], children: values.boards === null && (_jsx(View, { style: styles.radioInner })) }), _jsx(Text, { style: styles.checkboxLabel, children: t("filter_no_preference", "No preference") })] }), BOARD_OPTIONS.map((item) => (_jsxs(TouchableOpacity, { style: styles.radioRow, onPress: () => updateFilterValue("boards", item.code), activeOpacity: 0.7, children: [_jsx(View, { style: [
161
+ values.boards === null && { borderColor: btnColor },
162
+ ], children: values.boards === null && (_jsx(View, { style: [styles.radioInner, { backgroundColor: btnColor }] })) }), _jsx(Text, { style: styles.checkboxLabel, children: t("filter_no_preference", "No preference") })] }), BOARD_OPTIONS.map((item) => (_jsxs(TouchableOpacity, { style: styles.radioRow, onPress: () => updateFilterValue("boards", item.code), activeOpacity: 0.7, children: [_jsx(View, { style: [
157
163
  styles.radio,
158
164
  values.boards === item.code && styles.radioSelected,
159
- ], children: values.boards === item.code && (_jsx(View, { style: styles.radioInner })) }), _jsx(Text, { style: styles.checkboxLabel, children: t(item.labelKey, item.fallback) })] }, item.code)))] })] }))] }), _jsxs(View, { style: styles.modalFooter, children: [_jsx(TouchableOpacity, { style: styles.resetButton, onPress: handleReset, activeOpacity: 0.7, children: _jsx(Text, { style: styles.resetButtonText, children: t("filter_reset_btn", "Reset") }) }), _jsx(TouchableOpacity, { style: styles.applyButton, onPress: handleApply, activeOpacity: 0.8, children: _jsx(Text, { style: styles.applyButtonText, children: t("filter_apply_btn", "Apply") }) })] })] }) })] }));
165
+ values.boards === item.code && { borderColor: btnColor },
166
+ ], children: values.boards === item.code && (_jsx(View, { style: [styles.radioInner, { backgroundColor: btnColor }] })) }), _jsx(Text, { style: styles.checkboxLabel, children: t(item.labelKey, item.fallback) })] }, item.code)))] })] }))] }), _jsxs(View, { style: styles.modalFooter, children: [_jsx(TouchableOpacity, { style: styles.resetButton, onPress: handleReset, activeOpacity: 0.7, children: _jsx(Text, { style: styles.resetButtonText, children: t("filter_reset_btn", "Reset") }) }), _jsx(TouchableOpacity, { style: [styles.applyButton, { backgroundColor: btnColor }], onPress: handleApply, activeOpacity: 0.8, children: _jsx(Text, { style: styles.applyButtonText, children: t("filter_apply_btn", "Apply") }) })] })] }) })] }));
160
167
  };
161
168
  const styles = StyleSheet.create({
162
169
  quickFiltersBar: {
package/index.ts ADDED
@@ -0,0 +1,7 @@
1
+ import { registerRootComponent } from 'expo';
2
+ import App from './App';
3
+
4
+ registerRootComponent(App);
5
+
6
+ export { TravelCodeWidget } from './src/TravelCodeWidget';
7
+ export type { TravelCodeWidgetProps } from './src/TravelCodeWidget';
package/package.json CHANGED
@@ -1,8 +1,8 @@
1
1
  {
2
2
  "name": "@devtravelcode/widget-native",
3
- "version": "1.0.2",
3
+ "version": "1.0.3",
4
4
  "description": "TravelCode search widget for React Native (flights, hotels)",
5
- "main": "dist/index.js",
5
+ "main": "index.ts",
6
6
  "types": "dist/index.d.ts",
7
7
  "files": [
8
8
  "dist",