@zezosoft/zezo-ott-react-native-ui-kit 1.1.2 → 1.1.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 (136) hide show
  1. package/lib/module/components/Auth/QrLogin/QrLogin.js +304 -138
  2. package/lib/module/components/Auth/QrLogin/QrLogin.js.map +1 -1
  3. package/lib/module/components/Auth/QrLogin/components/QrViewArea.js +193 -141
  4. package/lib/module/components/Auth/QrLogin/components/QrViewArea.js.map +1 -1
  5. package/lib/module/components/Content/Card/Category/Category.js +83 -11
  6. package/lib/module/components/Content/Card/Category/Category.js.map +1 -1
  7. package/lib/module/components/Content/Card/NowWatching/NowWatching.js +237 -108
  8. package/lib/module/components/Content/Card/NowWatching/NowWatching.js.map +1 -1
  9. package/lib/module/components/Content/Card/Sliders/Styles/One.js +185 -126
  10. package/lib/module/components/Content/Card/Sliders/Styles/One.js.map +1 -1
  11. package/lib/module/components/Content/Card/Sliders/Styles/Two.js +139 -92
  12. package/lib/module/components/Content/Card/Sliders/Styles/Two.js.map +1 -1
  13. package/lib/module/components/Content/Card/Styles/Five.js +131 -48
  14. package/lib/module/components/Content/Card/Styles/Five.js.map +1 -1
  15. package/lib/module/components/Content/Card/Styles/Four.js +126 -59
  16. package/lib/module/components/Content/Card/Styles/Four.js.map +1 -1
  17. package/lib/module/components/Content/Card/Styles/One.js +125 -50
  18. package/lib/module/components/Content/Card/Styles/One.js.map +1 -1
  19. package/lib/module/components/Content/Card/Styles/RotateInOut.js +138 -53
  20. package/lib/module/components/Content/Card/Styles/RotateInOut.js.map +1 -1
  21. package/lib/module/components/Content/Card/Styles/Six.js +207 -115
  22. package/lib/module/components/Content/Card/Styles/Six.js.map +1 -1
  23. package/lib/module/components/Content/Card/Styles/Three.js +134 -79
  24. package/lib/module/components/Content/Card/Styles/Three.js.map +1 -1
  25. package/lib/module/components/Content/Card/Styles/TopTen.js +186 -171
  26. package/lib/module/components/Content/Card/Styles/TopTen.js.map +1 -1
  27. package/lib/module/components/Content/Card/Styles/Two.js +144 -64
  28. package/lib/module/components/Content/Card/Styles/Two.js.map +1 -1
  29. package/lib/module/components/Content/Card/components/AdsPoster.js +162 -0
  30. package/lib/module/components/Content/Card/components/AdsPoster.js.map +1 -0
  31. package/lib/module/components/Content/Card/components/CardPoster.js +120 -136
  32. package/lib/module/components/Content/Card/components/CardPoster.js.map +1 -1
  33. package/lib/module/components/Content/Card/components/index.js +4 -0
  34. package/lib/module/components/Content/Card/components/index.js.map +1 -0
  35. package/lib/module/components/Content/Content.js +67 -27
  36. package/lib/module/components/Content/Content.js.map +1 -1
  37. package/lib/module/components/Content/Sections.js +32 -11
  38. package/lib/module/components/Content/Sections.js.map +1 -1
  39. package/lib/module/constants/dummySections.js +44 -4
  40. package/lib/module/constants/dummySections.js.map +1 -1
  41. package/lib/module/hooks/Images/index.js +5 -0
  42. package/lib/module/hooks/Images/index.js.map +1 -0
  43. package/lib/module/hooks/Images/useImageLoader.js +168 -0
  44. package/lib/module/hooks/Images/useImageLoader.js.map +1 -0
  45. package/lib/module/hooks/Images/useImageValidation.js +36 -0
  46. package/lib/module/hooks/Images/useImageValidation.js.map +1 -0
  47. package/lib/module/hooks/index.js +3 -0
  48. package/lib/module/hooks/index.js.map +1 -1
  49. package/lib/module/hooks/useAdTracking.js +270 -0
  50. package/lib/module/hooks/useAdTracking.js.map +1 -0
  51. package/lib/module/hooks/useCards.js +164 -0
  52. package/lib/module/hooks/useCards.js.map +1 -0
  53. package/lib/module/hooks/usePaginatedSection.js +11 -6
  54. package/lib/module/hooks/usePaginatedSection.js.map +1 -1
  55. package/lib/typescript/src/components/Auth/QrLogin/QrLogin.d.ts +2 -0
  56. package/lib/typescript/src/components/Auth/QrLogin/QrLogin.d.ts.map +1 -1
  57. package/lib/typescript/src/components/Auth/QrLogin/components/QrViewArea.d.ts.map +1 -1
  58. package/lib/typescript/src/components/Content/Card/Category/Category.d.ts.map +1 -1
  59. package/lib/typescript/src/components/Content/Card/NowWatching/NowWatching.d.ts.map +1 -1
  60. package/lib/typescript/src/components/Content/Card/Sliders/Styles/One.d.ts.map +1 -1
  61. package/lib/typescript/src/components/Content/Card/Sliders/Styles/Two.d.ts.map +1 -1
  62. package/lib/typescript/src/components/Content/Card/Styles/Five.d.ts +13 -1
  63. package/lib/typescript/src/components/Content/Card/Styles/Five.d.ts.map +1 -1
  64. package/lib/typescript/src/components/Content/Card/Styles/Four.d.ts +13 -1
  65. package/lib/typescript/src/components/Content/Card/Styles/Four.d.ts.map +1 -1
  66. package/lib/typescript/src/components/Content/Card/Styles/One.d.ts +15 -3
  67. package/lib/typescript/src/components/Content/Card/Styles/One.d.ts.map +1 -1
  68. package/lib/typescript/src/components/Content/Card/Styles/RotateInOut.d.ts +13 -1
  69. package/lib/typescript/src/components/Content/Card/Styles/RotateInOut.d.ts.map +1 -1
  70. package/lib/typescript/src/components/Content/Card/Styles/Six.d.ts +1 -0
  71. package/lib/typescript/src/components/Content/Card/Styles/Six.d.ts.map +1 -1
  72. package/lib/typescript/src/components/Content/Card/Styles/Three.d.ts +13 -5
  73. package/lib/typescript/src/components/Content/Card/Styles/Three.d.ts.map +1 -1
  74. package/lib/typescript/src/components/Content/Card/Styles/TopTen.d.ts +1 -0
  75. package/lib/typescript/src/components/Content/Card/Styles/TopTen.d.ts.map +1 -1
  76. package/lib/typescript/src/components/Content/Card/Styles/Two.d.ts +13 -1
  77. package/lib/typescript/src/components/Content/Card/Styles/Two.d.ts.map +1 -1
  78. package/lib/typescript/src/components/Content/Card/components/AdsPoster.d.ts +26 -0
  79. package/lib/typescript/src/components/Content/Card/components/AdsPoster.d.ts.map +1 -0
  80. package/lib/typescript/src/components/Content/Card/components/CardPoster.d.ts +3 -1
  81. package/lib/typescript/src/components/Content/Card/components/CardPoster.d.ts.map +1 -1
  82. package/lib/typescript/src/components/Content/Card/components/index.d.ts +2 -0
  83. package/lib/typescript/src/components/Content/Card/components/index.d.ts.map +1 -0
  84. package/lib/typescript/src/components/Content/Card/index.d.ts +76 -6
  85. package/lib/typescript/src/components/Content/Card/index.d.ts.map +1 -1
  86. package/lib/typescript/src/components/Content/Content.d.ts +4 -3
  87. package/lib/typescript/src/components/Content/Content.d.ts.map +1 -1
  88. package/lib/typescript/src/components/Content/Sections.d.ts +20 -6
  89. package/lib/typescript/src/components/Content/Sections.d.ts.map +1 -1
  90. package/lib/typescript/src/constants/dummySections.d.ts +5 -0
  91. package/lib/typescript/src/constants/dummySections.d.ts.map +1 -1
  92. package/lib/typescript/src/hooks/Images/index.d.ts +3 -0
  93. package/lib/typescript/src/hooks/Images/index.d.ts.map +1 -0
  94. package/lib/typescript/src/hooks/Images/useImageLoader.d.ts +36 -0
  95. package/lib/typescript/src/hooks/Images/useImageLoader.d.ts.map +1 -0
  96. package/lib/typescript/src/hooks/Images/useImageValidation.d.ts +17 -0
  97. package/lib/typescript/src/hooks/Images/useImageValidation.d.ts.map +1 -0
  98. package/lib/typescript/src/hooks/index.d.ts +3 -0
  99. package/lib/typescript/src/hooks/index.d.ts.map +1 -1
  100. package/lib/typescript/src/hooks/useAdTracking.d.ts +39 -0
  101. package/lib/typescript/src/hooks/useAdTracking.d.ts.map +1 -0
  102. package/lib/typescript/src/hooks/useCards.d.ts +36 -0
  103. package/lib/typescript/src/hooks/useCards.d.ts.map +1 -0
  104. package/lib/typescript/src/hooks/usePaginatedSection.d.ts +12 -2
  105. package/lib/typescript/src/hooks/usePaginatedSection.d.ts.map +1 -1
  106. package/lib/typescript/src/types/sections/index.d.ts +7 -4
  107. package/lib/typescript/src/types/sections/index.d.ts.map +1 -1
  108. package/package.json +6 -3
  109. package/src/components/Auth/QrLogin/QrLogin.tsx +382 -122
  110. package/src/components/Auth/QrLogin/components/QrViewArea.tsx +291 -197
  111. package/src/components/Content/Card/Category/Category.tsx +95 -8
  112. package/src/components/Content/Card/NowWatching/NowWatching.tsx +281 -136
  113. package/src/components/Content/Card/Sliders/Styles/One.tsx +244 -148
  114. package/src/components/Content/Card/Sliders/Styles/Two.tsx +171 -102
  115. package/src/components/Content/Card/Styles/Five.tsx +161 -62
  116. package/src/components/Content/Card/Styles/Four.tsx +164 -85
  117. package/src/components/Content/Card/Styles/One.tsx +161 -71
  118. package/src/components/Content/Card/Styles/RotateInOut.tsx +157 -60
  119. package/src/components/Content/Card/Styles/Six.tsx +242 -142
  120. package/src/components/Content/Card/Styles/Three.tsx +166 -133
  121. package/src/components/Content/Card/Styles/TopTen.tsx +230 -191
  122. package/src/components/Content/Card/Styles/Two.tsx +182 -79
  123. package/src/components/Content/Card/components/AdsPoster.tsx +202 -0
  124. package/src/components/Content/Card/components/CardPoster.tsx +134 -154
  125. package/src/components/Content/Card/components/index.ts +1 -0
  126. package/src/components/Content/Content.tsx +83 -45
  127. package/src/components/Content/Sections.tsx +51 -10
  128. package/src/constants/dummySections.ts +48 -1
  129. package/src/hooks/Images/index.ts +2 -0
  130. package/src/hooks/Images/useImageLoader.ts +206 -0
  131. package/src/hooks/Images/useImageValidation.ts +36 -0
  132. package/src/hooks/index.ts +3 -0
  133. package/src/hooks/useAdTracking.ts +349 -0
  134. package/src/hooks/useCards.ts +228 -0
  135. package/src/hooks/usePaginatedSection.ts +26 -7
  136. package/src/types/sections/index.ts +7 -4
@@ -27,13 +27,31 @@ import { ThumbnailCard } from '../../components/ThumbnailCard';
27
27
  import type { ThemeOverride } from '../../../../../theme/themes';
28
28
  import type { IContentData } from '@zezosoft/zezo-ott-api-client';
29
29
 
30
+ // ============================================================================
30
31
  // Constants
32
+ // ============================================================================
31
33
  const DEFAULT_SKELETON_COUNT = 3;
32
34
  const CAROUSEL_WIDTH = Display.fullWidth;
33
35
  const CAROUSEL_HEIGHT = verticalScale(180);
34
36
  const BORDER_RADIUS = scale(10);
37
+ const SCROLL_ANIMATION_DURATION = 1000;
38
+ const AUTO_PLAY_INTERVAL = 2500;
39
+ const PARALLAX_SCROLLING_OFFSET = 48;
40
+ const PARALLAX_SCROLLING_SCALE = 0.9;
41
+ const PAN_GESTURE_ACTIVE_OFFSET_X = [-10, 10];
42
+ const PAN_GESTURE_FAIL_OFFSET_Y = [-5, 5];
43
+ const GRADIENT_OVERLAY_COLORS = ['transparent', 'rgba(0,0,0,0.6)'];
44
+ const INDICATOR_WIDTH_ACTIVE = scale(18);
45
+ const INDICATOR_WIDTH_INACTIVE = scale(8);
46
+ const INDICATOR_HEIGHT = scale(8);
47
+ const INDICATOR_BORDER_RADIUS = scale(50);
48
+ const PLAY_ICON_SIZE = scale(25);
49
+ const PLAY_ICON_CONTAINER_SIZE = scale(40);
50
+ const PLAY_TEXT_MAX_WIDTH = scale(220);
35
51
 
36
- // Define props
52
+ // ============================================================================
53
+ // Types
54
+ // ============================================================================
37
55
  type SliderOneProps = {
38
56
  index: number;
39
57
  data: ISectionContent | null;
@@ -44,12 +62,15 @@ type SliderOneProps = {
44
62
  theme?: ThemeOverride;
45
63
  } & AccessibilityProps;
46
64
 
47
- // ImageTouchable component
48
65
  type ImageTouchableProps = {
49
66
  children: React.ReactNode;
50
67
  onImagePress?: () => void;
51
68
  };
52
69
 
70
+ // ============================================================================
71
+ // Helper Components
72
+ // ============================================================================
73
+
53
74
  const ImageTouchable = memo<ImageTouchableProps>(
54
75
  ({ children, onImagePress }) => (
55
76
  <TouchableOpacity
@@ -64,7 +85,11 @@ const ImageTouchable = memo<ImageTouchableProps>(
64
85
  )
65
86
  );
66
87
 
67
- // Main component
88
+ ImageTouchable.displayName = 'ImageTouchable';
89
+
90
+ // ============================================================================
91
+ // Main Component
92
+ // ============================================================================
68
93
  const SliderOne: React.FC<SliderOneProps> = ({
69
94
  index,
70
95
  data,
@@ -76,99 +101,162 @@ const SliderOne: React.FC<SliderOneProps> = ({
76
101
  accessibilityLabel = 'Content carousel',
77
102
  accessibilityHint = 'Swipe to view content',
78
103
  }) => {
104
+ // ========================================================================
105
+ // Hooks & State
106
+ // ========================================================================
79
107
  const { theme: appliedTheme } = useInternalTheme(theme);
80
- const contentData = useMemo(() => data?.data ?? [], [data]);
81
108
  const [activeIndex, setActiveIndex] = useState<number>(0);
82
109
 
83
- const gradientColors = useMemo(
84
- () => [appliedTheme.colors.primary, appliedTheme.colors.primary],
85
- [appliedTheme.colors.primary]
110
+ // ========================================================================
111
+ // Data Processing
112
+ // ========================================================================
113
+ const contentData = useMemo(
114
+ () =>
115
+ (data?.data ?? []).filter(
116
+ (item): item is IContentData => !('type' in item && item.type === 'ads')
117
+ ),
118
+ [data]
86
119
  );
87
120
 
88
- const handleSnapToItem = useCallback((i: number) => setActiveIndex(i), []);
89
-
90
- // Memoize skeleton items
91
121
  const skeletonItems = useSkeletonItems(skeletonCount);
92
122
 
93
- // Memoize indicator array
94
123
  const indicatorArray = useMemo(
95
- () => Array.from({ length: contentData.length }, (_, i) => i),
96
- [contentData.length]
124
+ () =>
125
+ Array.from(
126
+ { length: isLoading ? skeletonItems.length : contentData.length },
127
+ (_, i) => i
128
+ ),
129
+ [isLoading, skeletonItems.length, contentData.length]
130
+ );
131
+
132
+ // ========================================================================
133
+ // Memoized Values
134
+ // ========================================================================
135
+ const gradientColors = useMemo(
136
+ () => [appliedTheme.colors.primary, appliedTheme.colors.primary],
137
+ [appliedTheme.colors.primary]
97
138
  );
98
139
 
99
- // Memoize play icon style
100
140
  const playIconStyle = useMemo(
101
141
  () => [styles.playIcon, { backgroundColor: appliedTheme.colors.button }],
102
142
  [appliedTheme.colors.button]
103
143
  );
104
144
 
105
- // Memoize play text style
106
145
  const playTextStyle = useMemo(
107
146
  () => [styles.playText, { color: appliedTheme.colors.white }],
108
147
  [appliedTheme.colors.white]
109
148
  );
110
149
 
111
- // Render carousel item
150
+ const carouselProps = useMemo(
151
+ () => ({
152
+ width: CAROUSEL_WIDTH,
153
+ height: CAROUSEL_HEIGHT,
154
+ autoPlay: !isLoading && contentData.length > 1,
155
+ loop: !isLoading && contentData.length > 1,
156
+ scrollAnimationDuration: SCROLL_ANIMATION_DURATION,
157
+ autoPlayInterval: AUTO_PLAY_INTERVAL,
158
+ style: styles.carousel,
159
+ // Optimize rendering
160
+ windowSize: 3,
161
+ enabled: true,
162
+ }),
163
+ [isLoading, contentData.length]
164
+ );
165
+
166
+ const parallaxConfig = useMemo(
167
+ () => ({
168
+ parallaxScrollingOffset: PARALLAX_SCROLLING_OFFSET,
169
+ parallaxScrollingScale: PARALLAX_SCROLLING_SCALE,
170
+ }),
171
+ []
172
+ );
173
+
174
+ const panGestureConfig = useCallback(
175
+ (gesture: any) =>
176
+ gesture
177
+ .activeOffsetX(PAN_GESTURE_ACTIVE_OFFSET_X)
178
+ .failOffsetY(PAN_GESTURE_FAIL_OFFSET_Y),
179
+ []
180
+ );
181
+
182
+ // ========================================================================
183
+ // Event Handlers
184
+ // ========================================================================
185
+ const handleSnapToItem = useCallback((i: number) => setActiveIndex(i), []);
186
+
187
+ const handleItemPress = useCallback(
188
+ (item: IContentData) => {
189
+ onPressItem?.(item);
190
+ },
191
+ [onPressItem]
192
+ );
193
+
194
+ // ========================================================================
195
+ // Render Functions
196
+ // ========================================================================
112
197
  const renderCarouselItem = useCallback(
113
- ({ item }: { item: IContentData }) => (
114
- <View style={styles.sliderContainer}>
115
- <ImageTouchable onImagePress={() => onPressItem?.(item)}>
116
- <RentOrBuyIcon
117
- theme={appliedTheme}
118
- content_offering_type={item.content_offering_type}
119
- />
120
- <ThumbnailCard
121
- thumbnailUri={item.thumbnail}
122
- theme={appliedTheme}
123
- isLoading={false}
124
- borderRadius={BORDER_RADIUS}
125
- wrapperStyle={styles.imageWrapper}
126
- imageStyle={styles.sliderImage}
127
- resizeMode={FastImage.resizeMode.cover}
128
- />
129
- {showPlayIcon && (
130
- <LinearGradient
131
- colors={['transparent', 'rgba(0,0,0,0.6)']}
132
- style={styles.gradientOverlay}
133
- >
134
- <View style={styles.playOverlay}>
135
- <TouchableOpacity
136
- onPress={() => onPressItem?.(item)}
137
- style={playIconStyle}
138
- activeOpacity={0.8}
139
- accessibilityRole="button"
140
- accessibilityLabel="Play content"
141
- >
142
- <Play
143
- size={scale(25)}
144
- color={appliedTheme.colors.black}
145
- fill={appliedTheme.colors.black}
146
- />
147
- </TouchableOpacity>
148
- <Text
149
- style={playTextStyle}
150
- numberOfLines={1}
151
- accessibilityLabel={item.name}
152
- >
153
- {item.name}
154
- </Text>
155
- </View>
156
- </LinearGradient>
157
- )}
158
- </ImageTouchable>
159
- </View>
160
- ),
161
- [appliedTheme, showPlayIcon, onPressItem, playIconStyle, playTextStyle]
198
+ ({ item }: { item: IContentData }) => {
199
+ const handlePress = () => handleItemPress(item);
200
+
201
+ return (
202
+ <View style={styles.sliderContainer}>
203
+ <ImageTouchable onImagePress={handlePress}>
204
+ <RentOrBuyIcon
205
+ theme={appliedTheme}
206
+ content_offering_type={item.content_offering_type}
207
+ />
208
+ <ThumbnailCard
209
+ thumbnailUri={item.thumbnail}
210
+ theme={appliedTheme}
211
+ isLoading={false}
212
+ borderRadius={BORDER_RADIUS}
213
+ wrapperStyle={styles.imageWrapper}
214
+ imageStyle={styles.sliderImage}
215
+ resizeMode={FastImage.resizeMode.cover}
216
+ />
217
+ {showPlayIcon && (
218
+ <LinearGradient
219
+ colors={GRADIENT_OVERLAY_COLORS}
220
+ style={styles.gradientOverlay}
221
+ >
222
+ <View style={styles.playOverlay}>
223
+ <TouchableOpacity
224
+ onPress={handlePress}
225
+ style={playIconStyle}
226
+ activeOpacity={0.8}
227
+ accessibilityRole="button"
228
+ accessibilityLabel="Play content"
229
+ >
230
+ <Play
231
+ size={PLAY_ICON_SIZE}
232
+ color={appliedTheme.colors.black}
233
+ fill={appliedTheme.colors.black}
234
+ />
235
+ </TouchableOpacity>
236
+ <Text
237
+ style={playTextStyle}
238
+ numberOfLines={1}
239
+ accessibilityLabel={item.name}
240
+ >
241
+ {item.name}
242
+ </Text>
243
+ </View>
244
+ </LinearGradient>
245
+ )}
246
+ </ImageTouchable>
247
+ </View>
248
+ );
249
+ },
250
+ [appliedTheme, showPlayIcon, handleItemPress, playIconStyle, playTextStyle]
162
251
  );
163
252
 
164
- // Render skeleton item
165
253
  const renderSkeletonItem = useCallback(
166
- () => (
254
+ ({ item: _item }: { item: any }) => (
167
255
  <View style={styles.sliderContainer}>
168
256
  <SkeletonPlaceholder
169
257
  backgroundColor={appliedTheme.colors.skeletonBaseColor}
170
258
  highlightColor={appliedTheme.colors.skeletonHighlightColor}
171
- speed={1000}
259
+ speed={SCROLL_ANIMATION_DURATION}
172
260
  >
173
261
  <SkeletonPlaceholder.Item
174
262
  width={CAROUSEL_WIDTH}
@@ -178,42 +266,48 @@ const SliderOne: React.FC<SliderOneProps> = ({
178
266
  </SkeletonPlaceholder>
179
267
  </View>
180
268
  ),
181
- [appliedTheme.colors]
269
+ [
270
+ appliedTheme.colors.skeletonBaseColor,
271
+ appliedTheme.colors.skeletonHighlightColor,
272
+ ]
182
273
  );
183
274
 
184
- // Render indicator
185
275
  const renderIndicator = useCallback(
186
- (_: number, i: number) => (
187
- <View key={i} style={styles.indicatorWrapper}>
188
- {isLoading ? (
189
- <SkeletonPlaceholder
190
- backgroundColor={appliedTheme.colors.skeletonBaseColor}
191
- highlightColor={appliedTheme.colors.skeletonHighlightColor}
192
- speed={2000}
193
- >
194
- <SkeletonPlaceholder.Item
195
- width={scale(18)}
196
- height={scale(8)}
197
- borderRadius={scale(50)}
276
+ (_: number, i: number) => {
277
+ const isActive = i === activeIndex;
278
+
279
+ return (
280
+ <View key={i} style={styles.indicatorWrapper}>
281
+ {isLoading ? (
282
+ <SkeletonPlaceholder
283
+ backgroundColor={appliedTheme.colors.skeletonBaseColor}
284
+ highlightColor={appliedTheme.colors.skeletonHighlightColor}
285
+ speed={AUTO_PLAY_INTERVAL}
286
+ >
287
+ <SkeletonPlaceholder.Item
288
+ width={INDICATOR_WIDTH_ACTIVE}
289
+ height={INDICATOR_HEIGHT}
290
+ borderRadius={INDICATOR_BORDER_RADIUS}
291
+ />
292
+ </SkeletonPlaceholder>
293
+ ) : isActive ? (
294
+ <LinearGradient
295
+ start={{ x: 0, y: 0 }}
296
+ end={{ x: 1, y: 0 }}
297
+ colors={gradientColors}
298
+ style={styles.activeIndicator}
198
299
  />
199
- </SkeletonPlaceholder>
200
- ) : i === activeIndex ? (
201
- <LinearGradient
202
- start={{ x: 0, y: 0 }}
203
- end={{ x: 1, y: 0 }}
204
- colors={gradientColors}
205
- style={styles.activeIndicator}
206
- />
207
- ) : (
208
- <View
209
- style={[
210
- styles.inactiveIndicator,
211
- { backgroundColor: appliedTheme.colors.onSurface },
212
- ]}
213
- />
214
- )}
215
- </View>
216
- ),
300
+ ) : (
301
+ <View
302
+ style={[
303
+ styles.inactiveIndicator,
304
+ { backgroundColor: appliedTheme.colors.onSurface },
305
+ ]}
306
+ />
307
+ )}
308
+ </View>
309
+ );
310
+ },
217
311
  [
218
312
  isLoading,
219
313
  appliedTheme.colors.skeletonBaseColor,
@@ -224,23 +318,21 @@ const SliderOne: React.FC<SliderOneProps> = ({
224
318
  ]
225
319
  );
226
320
 
227
- // Common carousel props - memoized
228
- const carouselProps = useMemo(
229
- () => ({
230
- width: CAROUSEL_WIDTH,
231
- height: CAROUSEL_HEIGHT,
232
- autoPlay: !isLoading && contentData.length > 1,
233
- loop: true,
234
- scrollAnimationDuration: 1000,
235
- autoPlayInterval: 2500,
236
- style: styles.carousel,
237
- }),
238
- [isLoading, contentData.length]
239
- );
240
- if (!data) {
241
- return null;
242
- }
243
- if (isLoading) {
321
+ // ========================================================================
322
+ // Early Returns & Loading State
323
+ // ========================================================================
324
+ // Show skeleton immediately if:
325
+ // 1. Loading is true, OR
326
+ // 2. Data is null/undefined (initial state), OR
327
+ // 3. No content data available
328
+ const shouldShowSkeleton =
329
+ isLoading ||
330
+ !data ||
331
+ !contentData.length ||
332
+ (skeletonItems.length > 0 && !contentData.length);
333
+
334
+ // Show skeleton immediately while data is loading or not available
335
+ if (shouldShowSkeleton && skeletonItems.length > 0) {
244
336
  return (
245
337
  <View
246
338
  style={styles.container}
@@ -252,27 +344,34 @@ const SliderOne: React.FC<SliderOneProps> = ({
252
344
  data={skeletonItems}
253
345
  renderItem={renderSkeletonItem}
254
346
  mode="parallax"
255
- modeConfig={{
256
- parallaxScrollingOffset: 48,
257
- parallaxScrollingScale: 0.9,
258
- }}
259
- onConfigurePanGesture={(gesture) =>
260
- gesture.activeOffsetX([-10, 10]).failOffsetY([-5, 5])
261
- }
347
+ modeConfig={parallaxConfig}
348
+ onConfigurePanGesture={panGestureConfig}
262
349
  />
263
- <View style={styles.indicatorContainer}>
264
- <View style={styles.indicator}>
265
- {isLoading
266
- ? skeletonItems.map((_, i) => renderIndicator(0, i))
267
- : indicatorArray.map((i) => renderIndicator(0, i))}
350
+ {indicatorArray.length > 0 && (
351
+ <View style={styles.indicatorContainer}>
352
+ <View style={styles.indicator}>
353
+ {indicatorArray.map((i) => renderIndicator(0, i))}
354
+ </View>
268
355
  </View>
269
- </View>
356
+ )}
270
357
  </View>
271
358
  );
272
359
  }
360
+
361
+ // If not loading and no data, return null
362
+ if (!isLoading && !data) {
363
+ return null;
364
+ }
365
+
273
366
  if (!isLoading && !contentData.length) {
274
367
  return null;
275
368
  }
369
+
370
+ // ========================================================================
371
+ // Render Main Content
372
+ // ========================================================================
373
+ const shouldShowIndicators = index === 0;
374
+
276
375
  return (
277
376
  <View
278
377
  style={styles.container}
@@ -285,15 +384,10 @@ const SliderOne: React.FC<SliderOneProps> = ({
285
384
  renderItem={renderCarouselItem}
286
385
  onSnapToItem={handleSnapToItem}
287
386
  mode="parallax"
288
- modeConfig={{
289
- parallaxScrollingOffset: 48,
290
- parallaxScrollingScale: 0.9,
291
- }}
292
- onConfigurePanGesture={(gesture) =>
293
- gesture.activeOffsetX([-10, 10]).failOffsetY([-5, 5])
294
- }
387
+ modeConfig={parallaxConfig}
388
+ onConfigurePanGesture={panGestureConfig}
295
389
  />
296
- {index === 0 && (
390
+ {shouldShowIndicators && (
297
391
  <View style={styles.indicatorContainer}>
298
392
  <View style={styles.indicator}>
299
393
  {indicatorArray.map((i) => renderIndicator(0, i))}
@@ -304,7 +398,9 @@ const SliderOne: React.FC<SliderOneProps> = ({
304
398
  );
305
399
  };
306
400
 
401
+ // ============================================================================
307
402
  // Styles
403
+ // ============================================================================
308
404
  const styles = StyleSheet.create({
309
405
  container: {
310
406
  flex: 1,
@@ -342,16 +438,16 @@ const styles = StyleSheet.create({
342
438
  paddingHorizontal: scale(12),
343
439
  },
344
440
  playIcon: {
345
- width: scale(40),
346
- height: scale(40),
347
- borderRadius: scale(50),
441
+ width: PLAY_ICON_CONTAINER_SIZE,
442
+ height: PLAY_ICON_CONTAINER_SIZE,
443
+ borderRadius: INDICATOR_BORDER_RADIUS,
348
444
  alignItems: 'center',
349
445
  justifyContent: 'center',
350
446
  },
351
447
  playText: {
352
448
  fontSize: RFValue(15),
353
449
  fontWeight: 'bold',
354
- maxWidth: scale(220),
450
+ maxWidth: PLAY_TEXT_MAX_WIDTH,
355
451
  },
356
452
  indicatorContainer: {
357
453
  alignItems: 'center',
@@ -369,14 +465,14 @@ const styles = StyleSheet.create({
369
465
  justifyContent: 'center',
370
466
  },
371
467
  activeIndicator: {
372
- width: scale(18),
373
- height: scale(8),
374
- borderRadius: scale(50),
468
+ width: INDICATOR_WIDTH_ACTIVE,
469
+ height: INDICATOR_HEIGHT,
470
+ borderRadius: INDICATOR_BORDER_RADIUS,
375
471
  },
376
472
  inactiveIndicator: {
377
- width: scale(8),
378
- height: scale(8),
379
- borderRadius: scale(50),
473
+ width: INDICATOR_WIDTH_INACTIVE,
474
+ height: INDICATOR_HEIGHT,
475
+ borderRadius: INDICATOR_BORDER_RADIUS,
380
476
  },
381
477
  emptyState: {
382
478
  padding: scale(12),