@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
@@ -26,10 +26,35 @@ import RentOrBuyIcon from '../../components/RentOrBuyIcon';
26
26
  import type { ThemeOverride } from '../../../../../theme/themes';
27
27
  import type { IContentData } from '@zezosoft/zezo-ott-api-client';
28
28
 
29
+ // ============================================================================
30
+ // Constants
31
+ // ============================================================================
29
32
  const FULL_WIDTH = Display.fullWidth;
30
- const FULL_HEIGHT = FULL_WIDTH * (9 / 16);
33
+ const ASPECT_RATIO = 9 / 16;
34
+ const FULL_HEIGHT = FULL_WIDTH * ASPECT_RATIO;
35
+ const DEFAULT_SKELETON_COUNT = 3;
36
+ const SCROLL_ANIMATION_DURATION = 300;
37
+ const AUTO_PLAY_INTERVAL = 3000;
38
+ const CAROUSEL_WINDOW_SIZE = 2;
39
+ const SNAP_DEBOUNCE_DELAY = 50;
40
+ const SKELETON_SPEED = 2000;
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.7)'] as [
44
+ string,
45
+ string,
46
+ ];
47
+ const GRADIENT_START = { x: 0.5, y: 0 };
48
+ const GRADIENT_END = { x: 0.5, y: 1 };
49
+ const INDICATOR_WIDTH_ACTIVE = scale(18);
50
+ const INDICATOR_WIDTH_INACTIVE = scale(8);
51
+ const INDICATOR_HEIGHT = scale(8);
52
+ const INDICATOR_BORDER_RADIUS = scale(50);
53
+ const TOUCH_OPACITY = 0.85;
31
54
 
32
- // Memoized carousel item component for better performance
55
+ // ============================================================================
56
+ // Types
57
+ // ============================================================================
33
58
  type CarouselItemProps = {
34
59
  item: IContentData;
35
60
  onPressItem?: (item: IContentData) => void;
@@ -41,10 +66,21 @@ type CarouselItemProps = {
41
66
  };
42
67
  };
43
68
 
69
+ type SliderTwoProps = {
70
+ data: ISectionContent | null;
71
+ onPressItem?: (item: IContentData) => void;
72
+ isLoading?: boolean;
73
+ skeletonCount?: number;
74
+ theme?: ThemeOverride;
75
+ } & AccessibilityProps;
76
+
77
+ // ============================================================================
78
+ // Helper Components
79
+ // ============================================================================
44
80
  const CarouselItem = memo<CarouselItemProps>(
45
81
  ({ item, onPressItem, appliedTheme, gradientConfig }) => (
46
82
  <TouchableOpacity
47
- activeOpacity={0.85}
83
+ activeOpacity={TOUCH_OPACITY}
48
84
  onPress={() => onPressItem?.(item)}
49
85
  style={styles.itemWrapper}
50
86
  accessibilityRole="button"
@@ -71,85 +107,127 @@ const CarouselItem = memo<CarouselItemProps>(
71
107
  )
72
108
  );
73
109
 
74
- type SliderTwoProps = {
75
- data: ISectionContent | null;
76
- onPressItem?: (item: IContentData) => void;
77
- isLoading?: boolean;
78
- skeletonCount?: number;
79
- theme?: ThemeOverride;
80
- } & AccessibilityProps;
110
+ CarouselItem.displayName = 'CarouselItem';
81
111
 
112
+ // ============================================================================
113
+ // Main Component
114
+ // ============================================================================
82
115
  const SliderTwo: React.FC<SliderTwoProps> = ({
83
116
  data,
84
117
  onPressItem,
85
118
  isLoading = true,
86
- skeletonCount = 3,
119
+ skeletonCount = DEFAULT_SKELETON_COUNT,
87
120
  accessibilityLabel = 'Full Width Slider',
88
121
  accessibilityHint = 'Swipe to view content',
89
122
  theme,
90
123
  }) => {
124
+ // ========================================================================
125
+ // Hooks & State
126
+ // ========================================================================
91
127
  const { theme: appliedTheme } = useInternalTheme(theme);
92
- const contentData = useMemo(() => data?.data ?? [], [data]);
93
128
  const [activeIndex, setActiveIndex] = useState(0);
94
- const gradientColors = useMemo(
95
- () => [appliedTheme.colors.primary, appliedTheme.colors.primary],
96
- [appliedTheme.colors.primary]
97
- );
98
- // Debounce snap handler to prevent stuttering
99
129
  const snapTimeoutRef = useRef<NodeJS.Timeout | null>(null);
100
- const handleSnapToItem = useCallback((i: number) => {
101
- if (snapTimeoutRef.current) {
102
- clearTimeout(snapTimeoutRef.current);
103
- }
104
- snapTimeoutRef.current = setTimeout(() => {
105
- InteractionManager.runAfterInteractions(() => {
106
- setActiveIndex(i);
107
- });
108
- }, 50);
109
- }, []);
110
130
 
111
- // Memoize skeleton items
131
+ // ========================================================================
132
+ // Data Processing
133
+ // ========================================================================
134
+ const contentData = useMemo(() => data?.data ?? [], [data]);
112
135
  const skeletonItems = useSkeletonItems(skeletonCount);
113
136
 
114
- // Memoize indicator array
115
137
  const indicatorArray = useMemo(
116
- () => Array.from({ length: contentData.length }, (_, i) => i),
117
- [contentData.length]
138
+ () =>
139
+ Array.from(
140
+ { length: isLoading ? skeletonItems.length : contentData.length },
141
+ (_, i) => i
142
+ ),
143
+ [isLoading, skeletonItems.length, contentData.length]
118
144
  );
119
145
 
120
- // Memoize carousel data
121
146
  const carouselData = useMemo(
122
147
  () => (isLoading ? skeletonItems : contentData),
123
148
  [isLoading, skeletonItems, contentData]
124
149
  );
125
150
 
126
- // Memoize gradient configuration
151
+ // ========================================================================
152
+ // Memoized Values
153
+ // ========================================================================
154
+ const gradientColors = useMemo(
155
+ () => [appliedTheme.colors.primary, appliedTheme.colors.primary],
156
+ [appliedTheme.colors.primary]
157
+ );
158
+
127
159
  const gradientConfig = useMemo(
128
160
  () => ({
129
- colors: ['transparent', 'rgba(0,0,0,0.7)'] as [string, string],
130
- start: { x: 0.5, y: 0 },
131
- end: { x: 0.5, y: 1 },
161
+ colors: GRADIENT_OVERLAY_COLORS,
162
+ start: GRADIENT_START,
163
+ end: GRADIENT_END,
132
164
  }),
133
165
  []
134
166
  );
135
167
 
136
- // Memoize pan gesture handler for smooth scrolling
137
- const configurePanGesture = useCallback((gesture: any) => {
138
- gesture.activeOffsetX([-10, 10]).failOffsetY([-5, 5]);
168
+ const carouselProps = useMemo(
169
+ () => ({
170
+ width: FULL_WIDTH,
171
+ height: FULL_HEIGHT,
172
+ autoPlay: !isLoading && contentData.length > 1,
173
+ loop: !isLoading && contentData.length > 1,
174
+ scrollAnimationDuration: SCROLL_ANIMATION_DURATION,
175
+ autoPlayInterval: AUTO_PLAY_INTERVAL,
176
+ windowSize: CAROUSEL_WINDOW_SIZE,
177
+ enabled: true,
178
+ }),
179
+ [isLoading, contentData.length]
180
+ );
181
+
182
+ const inactiveIndicatorStyle = useMemo(
183
+ () => [
184
+ styles.inactiveIndicator,
185
+ { backgroundColor: appliedTheme.colors.onSurface },
186
+ ],
187
+ [appliedTheme.colors.onSurface]
188
+ );
189
+
190
+ // ========================================================================
191
+ // Event Handlers
192
+ // ========================================================================
193
+ const handleSnapToItem = useCallback((i: number) => {
194
+ if (snapTimeoutRef.current) {
195
+ clearTimeout(snapTimeoutRef.current);
196
+ }
197
+ snapTimeoutRef.current = setTimeout(() => {
198
+ InteractionManager.runAfterInteractions(() => {
199
+ setActiveIndex(i);
200
+ });
201
+ }, SNAP_DEBOUNCE_DELAY);
139
202
  }, []);
140
203
 
204
+ const configurePanGesture = useCallback(
205
+ (gesture: any) =>
206
+ gesture
207
+ .activeOffsetX(PAN_GESTURE_ACTIVE_OFFSET_X)
208
+ .failOffsetY(PAN_GESTURE_FAIL_OFFSET_Y),
209
+ []
210
+ );
211
+
212
+ // ========================================================================
213
+ // Render Functions
214
+ // ========================================================================
141
215
  const renderSkeletonItem = useCallback(
142
- () => (
216
+ ({ item: _item }: { item: any }) => (
143
217
  <View style={styles.itemWrapper}>
144
218
  <SkeletonPlaceholder
145
219
  backgroundColor={appliedTheme.colors.skeletonBaseColor}
146
220
  highlightColor={appliedTheme.colors.skeletonHighlightColor}
221
+ speed={SKELETON_SPEED}
147
222
  >
148
223
  <SkeletonPlaceholder.Item width={FULL_WIDTH} height={FULL_HEIGHT} />
149
224
  </SkeletonPlaceholder>
150
225
  </View>
151
226
  ),
152
- [appliedTheme.colors]
227
+ [
228
+ appliedTheme.colors.skeletonBaseColor,
229
+ appliedTheme.colors.skeletonHighlightColor,
230
+ ]
153
231
  );
154
232
 
155
233
  const renderCarouselItem = useCallback(
@@ -164,63 +242,42 @@ const SliderTwo: React.FC<SliderTwoProps> = ({
164
242
  [appliedTheme, onPressItem, gradientConfig]
165
243
  );
166
244
 
167
- // Memoize renderItem to prevent switching functions
168
245
  const renderItem = useMemo(
169
246
  () => (isLoading ? renderSkeletonItem : renderCarouselItem),
170
247
  [isLoading, renderSkeletonItem, renderCarouselItem]
171
248
  );
172
249
 
173
- // Memoize carousel props for smooth scrolling
174
- const carouselProps = useMemo(
175
- () => ({
176
- width: FULL_WIDTH,
177
- height: FULL_HEIGHT,
178
- autoPlay: !isLoading && contentData.length > 1,
179
- loop: !isLoading && contentData.length > 1,
180
- scrollAnimationDuration: 300, // Reduced for smoother scrolling
181
- autoPlayInterval: 3000,
182
- windowSize: 2, // Reduced window size for better performance
183
- enabled: true,
184
- }),
185
- [isLoading, contentData.length]
186
- );
187
-
188
- // Memoize inactive indicator style
189
- const inactiveIndicatorStyle = useMemo(
190
- () => [
191
- styles.inactiveIndicator,
192
- { backgroundColor: appliedTheme.colors.onSurface },
193
- ],
194
- [appliedTheme.colors.onSurface]
195
- );
196
-
197
250
  const renderIndicator = useCallback(
198
- (_: number, i: number) => (
199
- <View key={i} style={styles.indicatorWrapper}>
200
- {isLoading ? (
201
- <SkeletonPlaceholder
202
- backgroundColor={appliedTheme.colors.skeletonBaseColor}
203
- highlightColor={appliedTheme.colors.skeletonHighlightColor}
204
- speed={2000}
205
- >
206
- <SkeletonPlaceholder.Item
207
- width={scale(18)}
208
- height={scale(8)}
209
- borderRadius={scale(50)}
251
+ (_: number, i: number) => {
252
+ const isActive = i === activeIndex;
253
+
254
+ return (
255
+ <View key={i} style={styles.indicatorWrapper}>
256
+ {isLoading ? (
257
+ <SkeletonPlaceholder
258
+ backgroundColor={appliedTheme.colors.skeletonBaseColor}
259
+ highlightColor={appliedTheme.colors.skeletonHighlightColor}
260
+ speed={SKELETON_SPEED}
261
+ >
262
+ <SkeletonPlaceholder.Item
263
+ width={INDICATOR_WIDTH_ACTIVE}
264
+ height={INDICATOR_HEIGHT}
265
+ borderRadius={INDICATOR_BORDER_RADIUS}
266
+ />
267
+ </SkeletonPlaceholder>
268
+ ) : isActive ? (
269
+ <LinearGradient
270
+ start={{ x: 0, y: 0 }}
271
+ end={{ x: 1, y: 0 }}
272
+ colors={gradientColors}
273
+ style={styles.activeIndicator}
210
274
  />
211
- </SkeletonPlaceholder>
212
- ) : i === activeIndex ? (
213
- <LinearGradient
214
- start={{ x: 0, y: 0 }}
215
- end={{ x: 1, y: 0 }}
216
- colors={gradientColors}
217
- style={styles.activeIndicator}
218
- />
219
- ) : (
220
- <View style={inactiveIndicatorStyle} />
221
- )}
222
- </View>
223
- ),
275
+ ) : (
276
+ <View style={inactiveIndicatorStyle} />
277
+ )}
278
+ </View>
279
+ );
280
+ },
224
281
  [
225
282
  isLoading,
226
283
  appliedTheme.colors.skeletonBaseColor,
@@ -231,7 +288,11 @@ const SliderTwo: React.FC<SliderTwoProps> = ({
231
288
  ]
232
289
  );
233
290
 
234
- if (!data || (!isLoading && contentData.length === 0)) {
291
+ // ========================================================================
292
+ // Early Returns
293
+ // ========================================================================
294
+ // Don't return early if loading - we need to show skeleton
295
+ if (!isLoading && (!data || contentData.length === 0)) {
235
296
  return (
236
297
  <View style={[styles.container, styles.emptyState]}>
237
298
  <Text style={styles.emptyText}>No content available</Text>
@@ -239,6 +300,9 @@ const SliderTwo: React.FC<SliderTwoProps> = ({
239
300
  );
240
301
  }
241
302
 
303
+ // ========================================================================
304
+ // Render Main Content
305
+ // ========================================================================
242
306
  return (
243
307
  <View
244
308
  style={styles.container}
@@ -252,15 +316,20 @@ const SliderTwo: React.FC<SliderTwoProps> = ({
252
316
  onSnapToItem={handleSnapToItem}
253
317
  onConfigurePanGesture={configurePanGesture}
254
318
  />
255
- <View style={styles.indicatorContainer}>
256
- <View style={styles.indicator}>
257
- {indicatorArray.map((i) => renderIndicator(0, i))}
319
+ {indicatorArray.length > 0 && (
320
+ <View style={styles.indicatorContainer}>
321
+ <View style={styles.indicator}>
322
+ {indicatorArray.map((i) => renderIndicator(0, i))}
323
+ </View>
258
324
  </View>
259
- </View>
325
+ )}
260
326
  </View>
261
327
  );
262
328
  };
263
329
 
330
+ // ============================================================================
331
+ // Styles
332
+ // ============================================================================
264
333
  const styles = StyleSheet.create({
265
334
  container: {
266
335
  flex: 1,
@@ -297,14 +366,14 @@ const styles = StyleSheet.create({
297
366
  justifyContent: 'center',
298
367
  },
299
368
  activeIndicator: {
300
- width: scale(18),
301
- height: scale(8),
302
- borderRadius: scale(50),
369
+ width: INDICATOR_WIDTH_ACTIVE,
370
+ height: INDICATOR_HEIGHT,
371
+ borderRadius: INDICATOR_BORDER_RADIUS,
303
372
  },
304
373
  inactiveIndicator: {
305
- width: scale(8),
306
- height: scale(8),
307
- borderRadius: scale(50),
374
+ width: INDICATOR_WIDTH_INACTIVE,
375
+ height: INDICATOR_HEIGHT,
376
+ borderRadius: INDICATOR_BORDER_RADIUS,
308
377
  },
309
378
  emptyState: {
310
379
  padding: scale(12),