@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
@@ -3,7 +3,7 @@
3
3
  * @LastModified Sat 28 Jun 2025 at 01:00 AM
4
4
  **/
5
5
 
6
- import React, { memo, useCallback, useRef } from 'react';
6
+ import React, { memo, useCallback, useMemo, useRef } from 'react';
7
7
  import {
8
8
  View,
9
9
  FlatList,
@@ -24,7 +24,6 @@ import { useInternalTheme } from '../../../../theme/hook/useInternalTheme';
24
24
  import NavigateToMore from '../components/NavigateToMore';
25
25
  import { ThumbnailCard } from '../components/ThumbnailCard';
26
26
  import { Text } from '../../../Text';
27
- import { usePaginatedSection } from '../../../../hooks/usePaginatedSection';
28
27
  import type { ThemeOverride } from '../../../../theme/themes';
29
28
  import type {
30
29
  IGetSectionData,
@@ -34,10 +33,42 @@ import type {
34
33
  import { RFValue } from 'react-native-responsive-fontsize';
35
34
  import RentOrBuyIcon from '../components/RentOrBuyIcon';
36
35
  import type { IContentData } from '@zezosoft/zezo-ott-api-client';
36
+ import { useCards } from '../../../../hooks';
37
+
38
+ // Default dimensions and styling constants
37
39
  const DEFAULT_ITEM_WIDTH = moderateScale(160);
38
40
  const DEFAULT_BORDER_RADIUS = moderateScale(5);
39
41
  const DEFAULT_SKELETON_COUNT = 3;
40
42
 
43
+ // Spacing constants
44
+ const ITEM_MARGIN_LEFT = moderateScale(10);
45
+ const ITEM_MARGIN_TOP = verticalScale(4);
46
+ const FIRST_SKELETON_MARGIN_LEFT = moderateScale(12);
47
+ const SKELETON_MARGIN_RIGHT = moderateScale(12);
48
+ const CONTAINER_PADDING_HORIZONTAL = moderateScale(10);
49
+ const CONTAINER_MARGIN_BOTTOM = verticalScale(8);
50
+ const ROOT_MARGIN_VERTICAL = verticalScale(6);
51
+ const LIST_PADDING_RIGHT = moderateScale(15);
52
+
53
+ // Skeleton styling constants
54
+ const SKELETON_TITLE_WIDTH = moderateScale(100);
55
+ const SKELETON_TITLE_HEIGHT = moderateScale(20);
56
+ const SKELETON_TITLE_BORDER_RADIUS = moderateScale(4);
57
+ const SKELETON_TITLE_MARGIN_HORIZONTAL = moderateScale(15);
58
+ const SKELETON_TITLE_MARGIN_BOTTOM = verticalScale(6);
59
+ const SKELETON_THUMBNAIL_HEIGHT_RATIO = 9 / 16;
60
+ const SKELETON_TEXT_WIDTH_RATIO = 0.8;
61
+ const SKELETON_TEXT_HEIGHT = moderateScale(13);
62
+ const SKELETON_TEXT_BORDER_RADIUS = moderateScale(3);
63
+ const SKELETON_TEXT_MARGIN_TOP = verticalScale(6);
64
+
65
+ // FlatList performance constants
66
+ const INITIAL_NUM_TO_RENDER = 5;
67
+ const ON_END_REACHED_THRESHOLD = 0.5;
68
+
69
+ // Touchable opacity constant
70
+ const ACTIVE_OPACITY = 0.8;
71
+
41
72
  type MovieCardSixProps = {
42
73
  theme?: ThemeOverride;
43
74
  title: string;
@@ -54,6 +85,7 @@ type MovieCardSixProps = {
54
85
  itemWidth?: number;
55
86
  borderRadius?: number;
56
87
  skeletonCount?: number;
88
+ paginationSkeletonCount?: number;
57
89
  containerStyle?: StyleProp<ViewStyle>;
58
90
  titleStyle?: StyleProp<TextStyle>;
59
91
  itemStyle?: StyleProp<ViewStyle>;
@@ -65,13 +97,14 @@ const MovieCardSix: React.FC<MovieCardSixProps> = ({
65
97
  title,
66
98
  section_id,
67
99
  type,
68
- data: initialData,
100
+ data: externalData,
69
101
  moreFetchData,
70
102
  onPressItem,
71
103
  onPressMore,
72
104
  itemWidth = DEFAULT_ITEM_WIDTH,
73
105
  borderRadius = DEFAULT_BORDER_RADIUS,
74
106
  skeletonCount = DEFAULT_SKELETON_COUNT,
107
+ paginationSkeletonCount,
75
108
  containerStyle,
76
109
  titleStyle,
77
110
  itemStyle,
@@ -79,22 +112,31 @@ const MovieCardSix: React.FC<MovieCardSixProps> = ({
79
112
  accessibilityLabel,
80
113
  accessibilityHint,
81
114
  }) => {
115
+ // Refs
82
116
  const flatListRef = useRef<FlatList<IContentData>>(null);
83
117
  const onEndReachedCalledDuringMomentum = useRef(false);
84
- const { theme: appliedTheme } = useInternalTheme(theme);
85
118
 
86
- const paginated = usePaginatedSection(
87
- section_id,
88
- moreFetchData,
89
- initialData?.data,
90
- isLoading
91
- );
119
+ // Theme
120
+ const { theme: appliedTheme } = useInternalTheme(theme);
92
121
 
93
- const sectionData = paginated.data;
94
- const pagination = paginated.pagination;
95
- const isPaginating = paginated.loading;
96
- const loadMoreData = paginated.loadMoreData;
122
+ // Data management using custom hook
123
+ const {
124
+ listData,
125
+ pagination,
126
+ loadMore,
127
+ isEmpty,
128
+ isPaging: isPaginating,
129
+ } = useCards({
130
+ sectionId: section_id,
131
+ data: externalData,
132
+ fetchMore: moreFetchData,
133
+ loading: isLoading,
134
+ initialSkeleton: skeletonCount,
135
+ pagingSkeleton: paginationSkeletonCount,
136
+ adsRender: false,
137
+ });
97
138
 
139
+ // Event handlers
98
140
  const handleItemPress = useCallback(
99
141
  (item: IContentData) => {
100
142
  onPressItem?.(item);
@@ -113,161 +155,219 @@ const MovieCardSix: React.FC<MovieCardSixProps> = ({
113
155
  pagination?.nextPage
114
156
  ) {
115
157
  onEndReachedCalledDuringMomentum.current = true;
116
- loadMoreData(pagination.nextPage);
158
+ loadMore(pagination.nextPage);
117
159
  }
118
- }, [pagination?.hasNextPage, pagination?.nextPage, loadMoreData]);
160
+ }, [pagination?.hasNextPage, pagination?.nextPage, loadMore]);
161
+
162
+ const handleScrollBeginDrag = useCallback(() => {
163
+ onEndReachedCalledDuringMomentum.current = false;
164
+ }, []);
119
165
 
166
+ const handleMomentumScrollBegin = useCallback(() => {
167
+ onEndReachedCalledDuringMomentum.current = false;
168
+ }, []);
169
+
170
+ // Generate key for FlatList items
171
+ const keyExtractor = useCallback(
172
+ (item: IContentData, index: number) => `${item._id}-${index}`,
173
+ []
174
+ );
175
+
176
+ // Render functions
120
177
  const renderItem = useCallback(
121
- ({ item }: ListRenderItemInfo<IContentData>) => (
122
- <TouchableOpacity
123
- style={[styles.item, itemStyle]}
124
- onPress={() => handleItemPress(item)}
125
- activeOpacity={0.8}
126
- >
127
- <RentOrBuyIcon
128
- theme={appliedTheme}
129
- content_offering_type={item.content_offering_type}
130
- />
131
- <ThumbnailCard
132
- thumbnailUri={item.thumbnail}
133
- theme={appliedTheme}
134
- isLoading={false}
135
- borderRadius={borderRadius}
136
- wrapperStyle={{ width: itemWidth }}
137
- resizeMode={FastImage.resizeMode.cover}
138
- />
139
- <View style={{ width: itemWidth, marginTop: verticalScale(4) }}>
140
- <Text
141
- style={[
142
- styles.itemTitle,
143
- { color: appliedTheme.colors.textPrimary },
144
- ]}
145
- numberOfLines={1}
146
- >
147
- {item.name}
148
- </Text>
149
- </View>
150
- </TouchableOpacity>
151
- ),
178
+ ({ item }: ListRenderItemInfo<IContentData>) => {
179
+ const thumbnailWrapperStyle = { width: itemWidth };
180
+ const titleContainerStyle = {
181
+ width: itemWidth,
182
+ marginTop: ITEM_MARGIN_TOP,
183
+ };
184
+ const titleTextStyle = {
185
+ color: appliedTheme.colors.textPrimary,
186
+ };
187
+
188
+ return (
189
+ <TouchableOpacity
190
+ style={[styles.item, itemStyle]}
191
+ onPress={() => handleItemPress(item)}
192
+ activeOpacity={ACTIVE_OPACITY}
193
+ >
194
+ <RentOrBuyIcon
195
+ theme={appliedTheme}
196
+ content_offering_type={item.content_offering_type}
197
+ />
198
+ <ThumbnailCard
199
+ thumbnailUri={item.thumbnail}
200
+ theme={appliedTheme}
201
+ isLoading={false}
202
+ borderRadius={borderRadius}
203
+ wrapperStyle={thumbnailWrapperStyle}
204
+ resizeMode={FastImage.resizeMode.cover}
205
+ />
206
+ <View style={titleContainerStyle}>
207
+ <Text style={[styles.itemTitle, titleTextStyle]} numberOfLines={1}>
208
+ {item.name}
209
+ </Text>
210
+ </View>
211
+ </TouchableOpacity>
212
+ );
213
+ },
152
214
  [handleItemPress, itemStyle, appliedTheme, borderRadius, itemWidth]
153
215
  );
154
216
 
155
217
  const renderSkeletonItem = useCallback(
156
- (index: number) => (
157
- <SkeletonPlaceholder
158
- key={`skeleton-${index}`}
159
- highlightColor={appliedTheme.colors.skeletonHighlightColor}
160
- backgroundColor={appliedTheme.colors.skeletonBaseColor}
161
- borderRadius={borderRadius}
162
- >
163
- <SkeletonPlaceholder.Item
164
- flexDirection="column"
165
- alignItems="flex-start"
166
- marginLeft={index === 0 ? moderateScale(12) : moderateScale(0)}
167
- marginRight={moderateScale(12)}
218
+ (index: number) => {
219
+ const isFirstSkeleton = index === 0;
220
+ const thumbnailHeight = itemWidth * SKELETON_THUMBNAIL_HEIGHT_RATIO;
221
+ const textWidth = itemWidth * SKELETON_TEXT_WIDTH_RATIO;
222
+
223
+ return (
224
+ <SkeletonPlaceholder
225
+ key={`skeleton-${index}`}
226
+ highlightColor={appliedTheme.colors.skeletonHighlightColor}
227
+ backgroundColor={appliedTheme.colors.skeletonBaseColor}
228
+ borderRadius={borderRadius}
168
229
  >
169
- {/* Thumbnail */}
170
230
  <SkeletonPlaceholder.Item
171
- width={itemWidth}
172
- height={(itemWidth * 9) / 16}
173
- borderRadius={borderRadius}
174
- />
231
+ flexDirection="column"
232
+ alignItems="flex-start"
233
+ marginLeft={isFirstSkeleton ? FIRST_SKELETON_MARGIN_LEFT : 0}
234
+ marginRight={SKELETON_MARGIN_RIGHT}
235
+ >
236
+ {/* Thumbnail */}
237
+ <SkeletonPlaceholder.Item
238
+ width={itemWidth}
239
+ height={thumbnailHeight}
240
+ borderRadius={borderRadius}
241
+ />
175
242
 
176
- {/* Title */}
177
- <SkeletonPlaceholder.Item
178
- width={itemWidth * 0.8}
179
- height={moderateScale(13)}
180
- borderRadius={moderateScale(3)}
181
- marginTop={verticalScale(6)}
182
- />
183
- </SkeletonPlaceholder.Item>
184
- </SkeletonPlaceholder>
185
- ),
243
+ {/* Title */}
244
+ <SkeletonPlaceholder.Item
245
+ width={textWidth}
246
+ height={SKELETON_TEXT_HEIGHT}
247
+ borderRadius={SKELETON_TEXT_BORDER_RADIUS}
248
+ marginTop={SKELETON_TEXT_MARGIN_TOP}
249
+ />
250
+ </SkeletonPlaceholder.Item>
251
+ </SkeletonPlaceholder>
252
+ );
253
+ },
186
254
  [appliedTheme.colors, itemWidth, borderRadius]
187
255
  );
188
- if (!initialData) {
256
+
257
+ // Filter out ads to ensure only IContentData items are passed to FlatList
258
+ const contentData = useMemo(
259
+ () =>
260
+ listData.filter(
261
+ (item): item is IContentData => !('type' in item && item.type === 'ads')
262
+ ),
263
+ [listData]
264
+ );
265
+
266
+ // Render pagination skeleton footer
267
+ const renderPaginationSkeleton = useCallback(() => {
268
+ if (!isPaginating) {
269
+ return null;
270
+ }
271
+ return renderSkeletonItem(0);
272
+ }, [isPaginating, renderSkeletonItem]);
273
+
274
+ // Early returns for edge cases
275
+ if (!externalData) {
276
+ return null;
277
+ }
278
+
279
+ const shouldHideSection = !isLoading && contentData.length === 0 && !isEmpty;
280
+ if (shouldHideSection) {
189
281
  return null;
190
282
  }
191
- if (!isLoading && sectionData.length === 0) return null;
192
283
 
284
+ // Loading skeleton state
285
+ if (isLoading) {
286
+ const skeletonDataLength = isPaginating ? 1 : skeletonCount;
287
+ const skeletonData = Array.from(
288
+ { length: skeletonDataLength },
289
+ (_, i) => i
290
+ );
291
+
292
+ return (
293
+ <View
294
+ style={[styles.root, containerStyle]}
295
+ accessibilityLabel={accessibilityLabel || `Movie section: ${title}`}
296
+ accessibilityHint={accessibilityHint || 'Scroll to view content'}
297
+ >
298
+ <SkeletonPlaceholder
299
+ highlightColor={appliedTheme.colors.skeletonHighlightColor}
300
+ backgroundColor={appliedTheme.colors.skeletonBaseColor}
301
+ >
302
+ <SkeletonPlaceholder.Item
303
+ width={SKELETON_TITLE_WIDTH}
304
+ height={SKELETON_TITLE_HEIGHT}
305
+ borderRadius={SKELETON_TITLE_BORDER_RADIUS}
306
+ marginHorizontal={SKELETON_TITLE_MARGIN_HORIZONTAL}
307
+ marginBottom={SKELETON_TITLE_MARGIN_BOTTOM}
308
+ />
309
+ </SkeletonPlaceholder>
310
+ <ScrollView
311
+ horizontal
312
+ showsHorizontalScrollIndicator={false}
313
+ contentContainerStyle={styles.skeletonList}
314
+ >
315
+ {skeletonData.map((index) => renderSkeletonItem(index))}
316
+ </ScrollView>
317
+ </View>
318
+ );
319
+ }
320
+
321
+ // Main content render
193
322
  return (
194
323
  <View
195
324
  style={[styles.root, containerStyle]}
196
325
  accessibilityLabel={accessibilityLabel || `Movie section: ${title}`}
197
326
  accessibilityHint={accessibilityHint || 'Scroll to view content'}
198
327
  >
199
- {isLoading ? (
200
- <>
201
- <SkeletonPlaceholder
202
- highlightColor={appliedTheme.colors.skeletonHighlightColor}
203
- backgroundColor={appliedTheme.colors.skeletonBaseColor}
204
- >
205
- <SkeletonPlaceholder.Item
206
- width={moderateScale(100)}
207
- height={moderateScale(20)}
208
- borderRadius={moderateScale(4)}
209
- marginHorizontal={moderateScale(15)}
210
- marginBottom={verticalScale(6)}
211
- />
212
- </SkeletonPlaceholder>
213
- <ScrollView
214
- horizontal
215
- showsHorizontalScrollIndicator={false}
216
- contentContainerStyle={styles.skeletonList}
217
- >
218
- {Array.from({ length: isPaginating ? 1 : skeletonCount }).map(
219
- (_, index) => renderSkeletonItem(index)
220
- )}
221
- </ScrollView>
222
- </>
223
- ) : (
224
- <>
225
- <NavigateToMore
226
- title={title}
227
- onPress={handlePressMore}
228
- titleStyle={[
229
- styles.title,
230
- { color: appliedTheme.colors.textPrimary },
231
- titleStyle,
232
- ]}
233
- containerStyle={styles.navigateToMoreContainer}
234
- showAllProps={{ iconColor: appliedTheme.colors.textPrimary, theme }}
235
- />
236
- <FlatList
237
- ref={flatListRef}
238
- data={sectionData}
239
- horizontal
240
- keyExtractor={(item, index) => `${item._id}-${index}`}
241
- renderItem={renderItem}
242
- showsHorizontalScrollIndicator={false}
243
- contentContainerStyle={styles.listContent}
244
- initialNumToRender={5}
245
- onEndReached={handleEndReached}
246
- onEndReachedThreshold={0.5}
247
- onScrollBeginDrag={() => {
248
- onEndReachedCalledDuringMomentum.current = false;
249
- }}
250
- onMomentumScrollBegin={() => {
251
- onEndReachedCalledDuringMomentum.current = false;
252
- }}
253
- ListFooterComponent={isPaginating ? renderSkeletonItem(0) : null}
254
- />
255
- </>
256
- )}
328
+ <NavigateToMore
329
+ title={title}
330
+ onPress={handlePressMore}
331
+ titleStyle={[
332
+ styles.title,
333
+ { color: appliedTheme.colors.textPrimary },
334
+ titleStyle,
335
+ ]}
336
+ containerStyle={styles.navigateToMoreContainer}
337
+ showAllProps={{
338
+ iconColor: appliedTheme.colors.textPrimary,
339
+ theme,
340
+ }}
341
+ />
342
+ <FlatList
343
+ ref={flatListRef}
344
+ data={contentData}
345
+ horizontal
346
+ keyExtractor={keyExtractor}
347
+ renderItem={renderItem}
348
+ showsHorizontalScrollIndicator={false}
349
+ contentContainerStyle={styles.listContent}
350
+ initialNumToRender={INITIAL_NUM_TO_RENDER}
351
+ onEndReached={handleEndReached}
352
+ onEndReachedThreshold={ON_END_REACHED_THRESHOLD}
353
+ onScrollBeginDrag={handleScrollBeginDrag}
354
+ onMomentumScrollBegin={handleMomentumScrollBegin}
355
+ ListFooterComponent={renderPaginationSkeleton}
356
+ />
257
357
  </View>
258
358
  );
259
359
  };
260
360
 
261
361
  const styles = StyleSheet.create({
262
362
  root: {
263
- marginVertical: verticalScale(6),
363
+ marginVertical: ROOT_MARGIN_VERTICAL,
264
364
  },
265
365
  item: {
266
- marginLeft: moderateScale(10),
366
+ marginLeft: ITEM_MARGIN_LEFT,
267
367
  },
268
368
  navigateToMoreContainer: {
269
- paddingHorizontal: moderateScale(10),
270
- marginBottom: verticalScale(8),
369
+ paddingHorizontal: CONTAINER_PADDING_HORIZONTAL,
370
+ marginBottom: CONTAINER_MARGIN_BOTTOM,
271
371
  },
272
372
  title: {
273
373
  fontSize: RFValue(13),
@@ -276,16 +376,16 @@ const styles = StyleSheet.create({
276
376
  itemTitle: {
277
377
  fontSize: RFValue(9),
278
378
  fontWeight: '500',
279
- lineHeight: moderateScale(13),
280
- height: moderateScale(13),
379
+ lineHeight: SKELETON_TEXT_HEIGHT,
380
+ height: SKELETON_TEXT_HEIGHT,
281
381
  },
282
382
  listContent: {
283
- paddingRight: moderateScale(15),
383
+ paddingRight: LIST_PADDING_RIGHT,
284
384
  },
285
385
  skeletonList: {
286
386
  flexDirection: 'row',
287
387
  alignItems: 'flex-start',
288
- paddingRight: moderateScale(15),
388
+ paddingRight: LIST_PADDING_RIGHT,
289
389
  },
290
390
  });
291
391