@zezosoft/zezo-ott-react-native-ui-kit 1.1.5 → 1.1.7
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.
- package/lib/module/components/Content/Card/Sliders/Styles/Three.js +5 -4
- package/lib/module/components/Content/Card/Sliders/Styles/Three.js.map +1 -1
- package/lib/module/components/Headers/Four.js +1 -1
- package/lib/module/components/Headers/Three.js +2 -1
- package/lib/module/components/Headers/Three.js.map +1 -1
- package/lib/typescript/src/components/Content/Card/Sliders/Styles/Three.d.ts.map +1 -1
- package/package.json +2 -14
- package/src/Styles/globalStyles.ts +0 -70
- package/src/assets/animations/135037-payment-processing-error.json +0 -1347
- package/src/assets/animations/7227-vui-animation.json +0 -3377
- package/src/assets/animations/Failed.json +0 -2103
- package/src/assets/animations/Pending.json +0 -522
- package/src/assets/animations/Successful.json +0 -2289
- package/src/assets/animations/heart.json +0 -788
- package/src/assets/animations/succesfull-payment.json +0 -2379
- package/src/assets/animations/voice-icon.json +0 -542
- package/src/assets/img/back.png +0 -0
- package/src/assets/img/bottom-panel.png +0 -0
- package/src/assets/img/camera.png +0 -0
- package/src/assets/img/camera2.png +0 -0
- package/src/assets/img/home.png +0 -0
- package/src/assets/img/lock.png +0 -0
- package/src/assets/img/play.png +0 -0
- package/src/assets/img/profile.jpg +0 -0
- package/src/assets/img/qr-code.png +0 -0
- package/src/assets/img/shadow.png +0 -0
- package/src/assets/img/shadow2.png +0 -0
- package/src/assets/img/user.png +0 -0
- package/src/assets/svg/Account.svg +0 -4
- package/src/assets/svg/Favourite.svg +0 -14
- package/src/assets/svg/Upcoming.svg +0 -4
- package/src/assets/svg/content-error.svg +0 -28
- package/src/assets/svg/download.svg +0 -3
- package/src/assets/svg/eye-off.svg +0 -10
- package/src/assets/svg/favorites.svg +0 -3
- package/src/assets/svg/h.svg +0 -4
- package/src/assets/svg/home.svg +0 -5
- package/src/assets/svg/home1.svg +0 -3
- package/src/assets/svg/menu-bar.svg +0 -4
- package/src/assets/svg/my-space.svg +0 -14
- package/src/assets/svg/play-icon-with-bg.svg +0 -5
- package/src/assets/svg/profile.svg +0 -4
- package/src/assets/svg/search.svg +0 -5
- package/src/assets/svg/search1.svg +0 -4
- package/src/assets/svg/server-error.svg +0 -139
- package/src/components/Account/Account.tsx +0 -367
- package/src/components/Account/index.ts +0 -1
- package/src/components/Alert/AlertDialog.tsx +0 -247
- package/src/components/Alert/UAAlert.tsx +0 -170
- package/src/components/Alert/index.ts +0 -2
- package/src/components/Auth/AuthProvider/AuthProvider.tsx +0 -419
- package/src/components/Auth/One/ForgotPassword/ForgotPassword.tsx +0 -324
- package/src/components/Auth/One/Login/LoginWithEmail.tsx +0 -455
- package/src/components/Auth/One/Login/LoginWithPhone.tsx +0 -306
- package/src/components/Auth/One/OTP/OTP.tsx +0 -465
- package/src/components/Auth/One/QrLogin/QrLogin.tsx +0 -602
- package/src/components/Auth/One/QrLogin/components/QrViewArea.tsx +0 -423
- package/src/components/Auth/One/SignUp/SignUp.tsx +0 -479
- package/src/components/Auth/One/SplashScreen/SplashScreen.tsx +0 -249
- package/src/components/Auth/One/SplashScreen/components/SplashImage/SplashImage.tsx +0 -103
- package/src/components/Auth/One/SplashScreen/components/SplashLottie/SplashLottie.tsx +0 -77
- package/src/components/Auth/One/SplashScreen/components/SplashVideo/SplashVideo.tsx +0 -174
- package/src/components/Auth/One/index.ts +0 -24
- package/src/components/Auth/Two/AuthHeader/AuthHeader.tsx +0 -108
- package/src/components/Auth/Two/ForgotPassword/ForgotPassword.tsx +0 -335
- package/src/components/Auth/Two/Login/AuthLoginShell.tsx +0 -173
- package/src/components/Auth/Two/Login/LoginWithEmail.tsx +0 -279
- package/src/components/Auth/Two/Login/LoginWithPhone.tsx +0 -188
- package/src/components/Auth/Two/OTP/OTP.tsx +0 -465
- package/src/components/Auth/Two/QrLogin/QrLogin.tsx +0 -602
- package/src/components/Auth/Two/QrLogin/components/QrViewArea.tsx +0 -423
- package/src/components/Auth/Two/SignUp/SignUp.tsx +0 -472
- package/src/components/Auth/Two/SplashScreen/SplashScreen.tsx +0 -248
- package/src/components/Auth/Two/SplashScreen/components/SplashImage/SplashImage.tsx +0 -92
- package/src/components/Auth/Two/SplashScreen/components/SplashLottie/SplashLottie.tsx +0 -77
- package/src/components/Auth/Two/SplashScreen/components/SplashVideo/SplashVideo.tsx +0 -178
- package/src/components/Auth/Two/index.ts +0 -28
- package/src/components/Auth/index.ts +0 -11
- package/src/components/BackgroundLayout/BackgroundLayout.tsx +0 -174
- package/src/components/BackgroundLayout/BackgroundLayoutOne.tsx +0 -56
- package/src/components/BlogView/BlogView.tsx +0 -276
- package/src/components/BlogView/index.ts +0 -8
- package/src/components/BlurView/BlurView.tsx +0 -199
- package/src/components/BlurView/index.ts +0 -7
- package/src/components/BottomSheet/BottomSheet.tsx +0 -200
- package/src/components/BottomSheet/BottomSheetOne.tsx +0 -220
- package/src/components/BottomSheet/index.ts +0 -4
- package/src/components/Button/BackBtn.tsx +0 -168
- package/src/components/Button/MenuBtn.tsx +0 -229
- package/src/components/Button/PrimaryBtn.tsx +0 -134
- package/src/components/Button/SecondaryBtn.tsx +0 -132
- package/src/components/Button/TextButton.tsx +0 -145
- package/src/components/Button/index.ts +0 -18
- package/src/components/Content/Card/Category/Category.tsx +0 -436
- package/src/components/Content/Card/Category/CategroyTwo.tsx +0 -429
- package/src/components/Content/Card/NowWatching/NowWatching.tsx +0 -624
- package/src/components/Content/Card/Sliders/Styles/One.tsx +0 -490
- package/src/components/Content/Card/Sliders/Styles/Three.tsx +0 -935
- package/src/components/Content/Card/Sliders/Styles/Two.tsx +0 -391
- package/src/components/Content/Card/Sliders/index.ts +0 -17
- package/src/components/Content/Card/Styles/Five.tsx +0 -385
- package/src/components/Content/Card/Styles/Four.tsx +0 -379
- package/src/components/Content/Card/Styles/One.tsx +0 -386
- package/src/components/Content/Card/Styles/RotateInOut.tsx +0 -413
- package/src/components/Content/Card/Styles/Six.tsx +0 -392
- package/src/components/Content/Card/Styles/Three.tsx +0 -314
- package/src/components/Content/Card/Styles/TopTen.tsx +0 -412
- package/src/components/Content/Card/Styles/Two.tsx +0 -416
- package/src/components/Content/Card/components/AdsPoster.tsx +0 -202
- package/src/components/Content/Card/components/CardPoster.tsx +0 -377
- package/src/components/Content/Card/components/NavigateToMore.tsx +0 -97
- package/src/components/Content/Card/components/RentOrBuyIcon.tsx +0 -129
- package/src/components/Content/Card/components/ShowAllButton.tsx +0 -92
- package/src/components/Content/Card/components/ThumbnailCard.tsx +0 -234
- package/src/components/Content/Card/components/index.ts +0 -1
- package/src/components/Content/Card/index.ts +0 -30
- package/src/components/Content/Content.tsx +0 -315
- package/src/components/Content/Sections.tsx +0 -238
- package/src/components/Content/types.ts +0 -176
- package/src/components/ContentView/MoreContentList.tsx +0 -327
- package/src/components/ContentView/One/ContentViewOne.tsx +0 -243
- package/src/components/ContentView/One/components/AboutSection.tsx +0 -216
- package/src/components/ContentView/One/components/CastCard.tsx +0 -265
- package/src/components/ContentView/One/components/EpisodeCard.tsx +0 -535
- package/src/components/ContentView/One/components/GenreTags.tsx +0 -132
- package/src/components/ContentView/One/components/HeroBanner.tsx +0 -357
- package/src/components/ContentView/One/components/MiniInfo.tsx +0 -356
- package/src/components/ContentView/One/components/PlayButton.tsx +0 -56
- package/src/components/ContentView/One/components/Title.tsx +0 -149
- package/src/components/ContentView/One/components/TrailerButton.tsx +0 -76
- package/src/components/ContentView/Two/ContentViewTwo.tsx +0 -343
- package/src/components/ContentView/Two/components/AboutSection.tsx +0 -216
- package/src/components/ContentView/Two/components/Details.tsx +0 -193
- package/src/components/ContentView/Two/components/EpisodeCard.tsx +0 -602
- package/src/components/ContentView/Two/components/GenreTags.tsx +0 -123
- package/src/components/ContentView/Two/components/HeroBanner.tsx +0 -402
- package/src/components/ContentView/Two/components/LikeShareActions.tsx +0 -125
- package/src/components/ContentView/Two/components/MoreLikeThisContentList .tsx +0 -305
- package/src/components/ContentView/Two/components/PlayOrTrailer.tsx +0 -133
- package/src/components/ContentView/Two/components/SectionTabs.tsx +0 -177
- package/src/components/ContentView/Two/components/Title.tsx +0 -226
- package/src/components/ContentView/Two/components/index.ts +0 -15
- package/src/components/ContentView/index.ts +0 -13
- package/src/components/Fallbacks/NoContentFallback.tsx +0 -176
- package/src/components/Fallbacks/NotFoundFallback.tsx +0 -94
- package/src/components/Fallbacks/index.ts +0 -2
- package/src/components/Headers/AppHeader.tsx +0 -150
- package/src/components/Headers/Four.tsx +0 -83
- package/src/components/Headers/One.tsx +0 -115
- package/src/components/Headers/Three.tsx +0 -135
- package/src/components/Headers/Two.tsx +0 -100
- package/src/components/Headers/index.ts +0 -18
- package/src/components/Input/Input.ts +0 -20
- package/src/components/Input/InputOne.tsx +0 -259
- package/src/components/Input/InputThree.tsx +0 -212
- package/src/components/Input/InputTwo.tsx +0 -212
- package/src/components/Input/PhoneNumberInput.tsx +0 -431
- package/src/components/Input/PhoneNumberInputTwo.tsx +0 -418
- package/src/components/Keyboard/HideKeyboard.tsx +0 -88
- package/src/components/Loader/Loader.tsx +0 -44
- package/src/components/Logo/Logo.tsx +0 -145
- package/src/components/NewRelease/NewReleaseSheet.tsx +0 -250
- package/src/components/NewRelease/index.ts +0 -1
- package/src/components/Reels/ReelsSeries/MediaControls/BottomControls.tsx +0 -221
- package/src/components/Reels/ReelsSeries/MediaControls/MediaControlsProvider.tsx +0 -314
- package/src/components/Reels/ReelsSeries/MediaControls/MiddleControls.tsx +0 -196
- package/src/components/Reels/ReelsSeries/MediaControls/RightControls.tsx +0 -95
- package/src/components/Reels/ReelsSeries/MediaControls/TopControls.tsx +0 -163
- package/src/components/Reels/ReelsSeries/Model/DetailsModal.tsx +0 -210
- package/src/components/Reels/ReelsSeries/Model/SettingModal.tsx +0 -146
- package/src/components/Reels/ReelsSeries/Model/UnlockModal.tsx +0 -154
- package/src/components/Reels/ReelsSeries/ReelsSeries.tsx +0 -264
- package/src/components/Reels/ReelsSeries/ReelsSeriesItem.tsx +0 -494
- package/src/components/Reels/ReelsSeries/components/AnimatedThreeLines.tsx +0 -184
- package/src/components/Reels/ReelsSeries/components/Episodes.tsx +0 -154
- package/src/components/Reels/ReelsSeries/components/GradientOverlay.tsx +0 -41
- package/src/components/Reels/ReelsSeries/components/Like.tsx +0 -40
- package/src/components/Reels/ReelsSeries/components/RotatingLoader.tsx +0 -79
- package/src/components/Reels/ReelsSeries/components/Synopsis.tsx +0 -332
- package/src/components/Reels/ReelsSeries/components/VideoControls/QualityControl.tsx +0 -187
- package/src/components/Reels/ReelsSeries/components/VideoControls/SpeedControl.tsx +0 -80
- package/src/components/Reels/ReelsSeries/components/VideoControls/index.ts +0 -2
- package/src/components/Reels/ReelsSeries/types.ts +0 -54
- package/src/components/Reels/ReelsSeries/useReelsWatchProgress.ts +0 -85
- package/src/components/Reels/ReelsSeries/utils/quality.ts +0 -48
- package/src/components/Reels/index.ts +0 -9
- package/src/components/Reels/utils/Controls/gestureUtils.ts +0 -42
- package/src/components/Reels/utils/Controls/index.ts +0 -4
- package/src/components/Reels/utils/Controls/overlayUtils.ts +0 -35
- package/src/components/Reels/utils/Controls/videoControlsConstants.ts +0 -25
- package/src/components/Reels/utils/Controls/videoRef.ts +0 -4
- package/src/components/Reels/utils/index.ts +0 -1
- package/src/components/Reels/utils/timeoutUtils.ts +0 -29
- package/src/components/Search/One.tsx +0 -256
- package/src/components/Search/components/RecentSearchesSection.tsx +0 -181
- package/src/components/Search/components/SearchCard.tsx +0 -275
- package/src/components/Search/index.ts +0 -16
- package/src/components/Settings/AppSettings.tsx +0 -428
- package/src/components/Settings/index.ts +0 -1
- package/src/components/Subscription/SubOne.tsx +0 -874
- package/src/components/Subscription/index.ts +0 -12
- package/src/components/TabBar/One.tsx +0 -148
- package/src/components/TabBar/Three.tsx +0 -169
- package/src/components/TabBar/Two.tsx +0 -189
- package/src/components/TabBar/index.ts +0 -20
- package/src/components/Text/Text.tsx +0 -85
- package/src/components/Text/index.ts +0 -5
- package/src/components/User/DeviceSessions/DeviceSessions.tsx +0 -468
- package/src/components/User/ProfileUpdate/ProfileUpdate.tsx +0 -278
- package/src/components/User/PurchaseHistory/PurchaseHistory.tsx +0 -494
- package/src/components/User/WatchHistory/WatchHistory.tsx +0 -227
- package/src/components/User/WatchLater/WatchLater.tsx +0 -397
- package/src/components/User/components/UserAvatar.tsx +0 -120
- package/src/components/User/components/UserSection.tsx +0 -228
- package/src/components/User/index.ts +0 -18
- package/src/components/View/View.tsx +0 -37
- package/src/components/View/index.ts +0 -5
- package/src/components/common/AppStatusBar.tsx +0 -57
- package/src/components/index.ts +0 -29
- package/src/components/layout/SafeAreaWrapper.tsx +0 -45
- package/src/components/layout/index.ts +0 -1
- package/src/constants/dummySections.ts +0 -98
- package/src/hooks/Images/index.ts +0 -2
- package/src/hooks/Images/useImageLoader.ts +0 -206
- package/src/hooks/Images/useImageValidation.ts +0 -36
- package/src/hooks/index.ts +0 -17
- package/src/hooks/useAdTracking.ts +0 -349
- package/src/hooks/useCards.ts +0 -228
- package/src/hooks/useDebounce.ts +0 -35
- package/src/hooks/useKeyboard.ts +0 -43
- package/src/hooks/useNavigationMode.ts +0 -46
- package/src/hooks/usePaginatedSection.ts +0 -101
- package/src/hooks/usePrevious.ts +0 -28
- package/src/hooks/useSafeCallback.ts +0 -43
- package/src/hooks/useSkeletonItems.ts +0 -30
- package/src/hooks/useSplashCache.ts +0 -186
- package/src/hooks/useThemeColors.ts +0 -51
- package/src/index.tsx +0 -8
- package/src/store/RecentSearchesStore.ts +0 -78
- package/src/store/splashStore.ts +0 -91
- package/src/store/themeStore.ts +0 -43
- package/src/theme/ThemeProvider.tsx +0 -112
- package/src/theme/hook/index.ts +0 -1
- package/src/theme/hook/useInternalTheme.ts +0 -98
- package/src/theme/index.ts +0 -7
- package/src/theme/themes.ts +0 -336
- package/src/theme/utils/validateColor.ts +0 -127
- package/src/types/content/content-view.types.ts +0 -206
- package/src/types/hook/index.ts +0 -5
- package/src/types/hook/usePaginatedSetion.ts +0 -19
- package/src/types/index.ts +0 -7
- package/src/types/sections/index.ts +0 -84
- package/src/utils/Display.ts +0 -14
- package/src/utils/Formater.ts +0 -14
- package/src/utils/PlatformSelector.ts +0 -29
- package/src/utils/SizeMatters.ts +0 -7
- package/src/utils/Spacing.ts +0 -27
- package/src/utils/colorUtils.ts +0 -70
|
@@ -1,206 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @author Naresh Dhamu
|
|
3
|
-
* @lastModified Wed 26 Nov 2025 at 02:19 PM
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
import { useState, useEffect, useMemo, useCallback, useRef } from 'react';
|
|
7
|
-
import FastImage from 'react-native-fast-image';
|
|
8
|
-
import { isValidImageUrl, isLocalFile } from './useImageValidation';
|
|
9
|
-
|
|
10
|
-
// Module-level cache to track successfully loaded images
|
|
11
|
-
const loadedImageCache = new Set<string>();
|
|
12
|
-
|
|
13
|
-
export type UseImageLoaderOptions = {
|
|
14
|
-
imageUri: string;
|
|
15
|
-
isLoading?: boolean;
|
|
16
|
-
enablePreload?: boolean;
|
|
17
|
-
onError?: () => void;
|
|
18
|
-
onLoad?: () => void;
|
|
19
|
-
onLoadStart?: () => void;
|
|
20
|
-
};
|
|
21
|
-
|
|
22
|
-
export type UseImageLoaderReturn = {
|
|
23
|
-
imageLoading: boolean;
|
|
24
|
-
imageError: boolean;
|
|
25
|
-
hasValidImage: boolean;
|
|
26
|
-
isImageCached: boolean;
|
|
27
|
-
showSkeleton: boolean;
|
|
28
|
-
showFallback: boolean;
|
|
29
|
-
imageSource: {
|
|
30
|
-
uri: string;
|
|
31
|
-
cache?: typeof FastImage.cacheControl.immutable;
|
|
32
|
-
priority?: typeof FastImage.priority.normal;
|
|
33
|
-
};
|
|
34
|
-
handleLoad: () => void;
|
|
35
|
-
handleError: () => void;
|
|
36
|
-
handleLoadStart?: () => void;
|
|
37
|
-
};
|
|
38
|
-
|
|
39
|
-
/**
|
|
40
|
-
* Custom hook to manage image loading state, caching, and validation
|
|
41
|
-
* @param options - Configuration options for image loading
|
|
42
|
-
* @returns Object containing image state and handlers
|
|
43
|
-
*/
|
|
44
|
-
export const useImageLoader = ({
|
|
45
|
-
imageUri,
|
|
46
|
-
isLoading = false,
|
|
47
|
-
enablePreload = false,
|
|
48
|
-
onError,
|
|
49
|
-
onLoad,
|
|
50
|
-
onLoadStart,
|
|
51
|
-
}: UseImageLoaderOptions): UseImageLoaderReturn => {
|
|
52
|
-
const [imageLoading, setImageLoading] = useState(true);
|
|
53
|
-
const [imageError, setImageError] = useState(false);
|
|
54
|
-
const previousUriRef = useRef<string>('');
|
|
55
|
-
const onErrorRef = useRef(onError);
|
|
56
|
-
|
|
57
|
-
// Keep onError ref updated
|
|
58
|
-
useEffect(() => {
|
|
59
|
-
onErrorRef.current = onError;
|
|
60
|
-
}, [onError]);
|
|
61
|
-
|
|
62
|
-
// Validate image URL
|
|
63
|
-
const hasValidImage = useMemo(() => isValidImageUrl(imageUri), [imageUri]);
|
|
64
|
-
|
|
65
|
-
// Check if image is already cached
|
|
66
|
-
const isImageCached = useMemo(
|
|
67
|
-
() => loadedImageCache.has(imageUri),
|
|
68
|
-
[imageUri]
|
|
69
|
-
);
|
|
70
|
-
|
|
71
|
-
// Handle image state changes
|
|
72
|
-
useEffect(() => {
|
|
73
|
-
const uriChanged = previousUriRef.current !== imageUri;
|
|
74
|
-
|
|
75
|
-
// Update ref when URI changes
|
|
76
|
-
if (uriChanged) {
|
|
77
|
-
previousUriRef.current = imageUri;
|
|
78
|
-
// Reset error state when URI changes to allow new image to load
|
|
79
|
-
setImageError(false);
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
// Reset states when loading
|
|
83
|
-
if (isLoading) {
|
|
84
|
-
setImageLoading(true);
|
|
85
|
-
setImageError(false);
|
|
86
|
-
return;
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
// Handle valid image URL
|
|
90
|
-
if (hasValidImage) {
|
|
91
|
-
const isLocal = isLocalFile(imageUri);
|
|
92
|
-
|
|
93
|
-
if (isImageCached) {
|
|
94
|
-
// Image is cached, mark as loaded
|
|
95
|
-
setImageLoading(false);
|
|
96
|
-
setImageError(false);
|
|
97
|
-
} else {
|
|
98
|
-
// Image not cached, start loading
|
|
99
|
-
setImageLoading(true);
|
|
100
|
-
setImageError(false);
|
|
101
|
-
// Preload image if enabled (only for remote URLs, not local files)
|
|
102
|
-
if (enablePreload && !isLocal && uriChanged) {
|
|
103
|
-
FastImage.preload([{ uri: imageUri }]);
|
|
104
|
-
}
|
|
105
|
-
}
|
|
106
|
-
} else {
|
|
107
|
-
// For empty or invalid URLs
|
|
108
|
-
if (!imageUri || imageUri.trim() === '') {
|
|
109
|
-
// Empty URI - show error immediately (no point in trying to load)
|
|
110
|
-
setImageLoading(false);
|
|
111
|
-
setImageError(true);
|
|
112
|
-
} else {
|
|
113
|
-
// Invalid URL format - attempt to load anyway
|
|
114
|
-
// FastImage might still be able to load it, so keep loading state
|
|
115
|
-
setImageLoading(true);
|
|
116
|
-
setImageError(false);
|
|
117
|
-
}
|
|
118
|
-
}
|
|
119
|
-
}, [imageUri, hasValidImage, isLoading, isImageCached, enablePreload]);
|
|
120
|
-
|
|
121
|
-
// Determine if skeleton should be shown
|
|
122
|
-
const showSkeleton = useMemo(
|
|
123
|
-
() => isLoading || (imageLoading && !imageError),
|
|
124
|
-
[isLoading, imageLoading, imageError]
|
|
125
|
-
);
|
|
126
|
-
|
|
127
|
-
// Determine if fallback should be shown
|
|
128
|
-
// Show fallback when:
|
|
129
|
-
// 1. Not showing skeleton
|
|
130
|
-
// 2. AND (imageError is true OR URI is empty/invalid)
|
|
131
|
-
// This allows images with invalid format to attempt loading, but shows fallback for empty URIs
|
|
132
|
-
const showFallback = useMemo(() => {
|
|
133
|
-
if (showSkeleton) return false;
|
|
134
|
-
// Empty URI - show fallback immediately
|
|
135
|
-
if (!imageUri || imageUri.trim() === '') return true;
|
|
136
|
-
// Show fallback only after actual error (not just invalid format)
|
|
137
|
-
return imageError && !imageLoading;
|
|
138
|
-
}, [showSkeleton, imageError, imageLoading, imageUri]);
|
|
139
|
-
|
|
140
|
-
// Check if image is a local file
|
|
141
|
-
const isLocal = useMemo(() => isLocalFile(imageUri), [imageUri]);
|
|
142
|
-
|
|
143
|
-
// Image source configuration
|
|
144
|
-
// Local files don't need cache control, cloud URIs do
|
|
145
|
-
const imageSource = useMemo(() => {
|
|
146
|
-
const source: {
|
|
147
|
-
uri: string;
|
|
148
|
-
cache?: typeof FastImage.cacheControl.immutable;
|
|
149
|
-
priority?: typeof FastImage.priority.normal;
|
|
150
|
-
} = {
|
|
151
|
-
uri: imageUri,
|
|
152
|
-
};
|
|
153
|
-
|
|
154
|
-
// Only add cache control for remote URLs, not local files
|
|
155
|
-
if (!isLocal) {
|
|
156
|
-
source.cache = FastImage.cacheControl.immutable;
|
|
157
|
-
source.priority = FastImage.priority.normal;
|
|
158
|
-
}
|
|
159
|
-
|
|
160
|
-
return source;
|
|
161
|
-
}, [imageUri, isLocal]);
|
|
162
|
-
|
|
163
|
-
// Image event handlers
|
|
164
|
-
const handleLoad = useCallback(() => {
|
|
165
|
-
setImageLoading(false);
|
|
166
|
-
setImageError(false);
|
|
167
|
-
if (imageUri) {
|
|
168
|
-
loadedImageCache.add(imageUri);
|
|
169
|
-
}
|
|
170
|
-
if (onLoad) {
|
|
171
|
-
onLoad();
|
|
172
|
-
}
|
|
173
|
-
}, [imageUri, onLoad]);
|
|
174
|
-
|
|
175
|
-
const handleError = useCallback(() => {
|
|
176
|
-
setImageLoading(false);
|
|
177
|
-
|
|
178
|
-
setImageError(true);
|
|
179
|
-
if (onError) {
|
|
180
|
-
onError();
|
|
181
|
-
}
|
|
182
|
-
}, [onError]);
|
|
183
|
-
|
|
184
|
-
const handleLoadStart = useCallback(() => {
|
|
185
|
-
if (!isImageCached) {
|
|
186
|
-
setImageLoading(true);
|
|
187
|
-
setImageError(false);
|
|
188
|
-
if (onLoadStart) {
|
|
189
|
-
onLoadStart();
|
|
190
|
-
}
|
|
191
|
-
}
|
|
192
|
-
}, [isImageCached, onLoadStart]);
|
|
193
|
-
|
|
194
|
-
return {
|
|
195
|
-
imageLoading,
|
|
196
|
-
imageError,
|
|
197
|
-
hasValidImage,
|
|
198
|
-
isImageCached,
|
|
199
|
-
showSkeleton,
|
|
200
|
-
showFallback,
|
|
201
|
-
imageSource,
|
|
202
|
-
handleLoad,
|
|
203
|
-
handleError,
|
|
204
|
-
handleLoadStart: enablePreload ? handleLoadStart : undefined,
|
|
205
|
-
};
|
|
206
|
-
};
|
|
@@ -1,36 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @author Naresh Dhamu
|
|
3
|
-
* @lastModified Wed 26 Nov 2025 at 02:19 PM
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
const IMAGE_URL_REGEX = /\.(jpg|jpeg|png|webp|gif|bmp)$/i;
|
|
7
|
-
|
|
8
|
-
/**
|
|
9
|
-
* Utility function to check if URL is a local file path
|
|
10
|
-
* @param url - The URL to check
|
|
11
|
-
* @returns true if the URL is a local file path, false otherwise
|
|
12
|
-
*/
|
|
13
|
-
export const isLocalFile = (url: string): boolean => {
|
|
14
|
-
return url?.startsWith?.('file://') || url?.startsWith?.('/');
|
|
15
|
-
};
|
|
16
|
-
|
|
17
|
-
/**
|
|
18
|
-
* Utility function to validate image URL (supports both cloud URIs and local file paths)
|
|
19
|
-
* @param url - The URL to validate
|
|
20
|
-
* @returns true if the URL is a valid image URL, false otherwise
|
|
21
|
-
*/
|
|
22
|
-
export const isValidImageUrl = (url: string | null | undefined): boolean => {
|
|
23
|
-
if (!url || typeof url !== 'string') return false;
|
|
24
|
-
const cleaned = url.trim();
|
|
25
|
-
|
|
26
|
-
// Check for local file paths
|
|
27
|
-
if (isLocalFile(cleaned)) {
|
|
28
|
-
return IMAGE_URL_REGEX.test(cleaned) || cleaned.length > 0;
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
// Check for cloud URIs (http/https)
|
|
32
|
-
return (
|
|
33
|
-
(cleaned?.startsWith?.('http://') || cleaned?.startsWith?.('https://')) &&
|
|
34
|
-
IMAGE_URL_REGEX.test(cleaned)
|
|
35
|
-
);
|
|
36
|
-
};
|
package/src/hooks/index.ts
DELETED
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @author Naresh Dhamu
|
|
3
|
-
* @lastModified Optimized for performance
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
export * from './useDebounce';
|
|
7
|
-
export * from './useKeyboard';
|
|
8
|
-
export * from './useNavigationMode';
|
|
9
|
-
export * from './usePaginatedSection';
|
|
10
|
-
export * from './useSplashCache';
|
|
11
|
-
export * from './usePrevious';
|
|
12
|
-
export * from './useSafeCallback';
|
|
13
|
-
export * from './useSkeletonItems';
|
|
14
|
-
export * from './useThemeColors';
|
|
15
|
-
export * from './useCards';
|
|
16
|
-
export * from './Images';
|
|
17
|
-
export * from './useAdTracking';
|
|
@@ -1,349 +0,0 @@
|
|
|
1
|
-
import { useRef, useMemo, useCallback, useEffect } from 'react';
|
|
2
|
-
import { type View, Dimensions } from 'react-native';
|
|
3
|
-
import type { IServeAd } from '@zezosoft/zezo-ott-api-client';
|
|
4
|
-
|
|
5
|
-
const CHECK_INTERVAL = 500;
|
|
6
|
-
const INITIAL_CHECK_DELAY = 100;
|
|
7
|
-
|
|
8
|
-
export interface ViewportOffsets {
|
|
9
|
-
top: number;
|
|
10
|
-
bottom: number;
|
|
11
|
-
left: number;
|
|
12
|
-
right: number;
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
export interface ScreenDimensions {
|
|
16
|
-
width: number;
|
|
17
|
-
height: number;
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
export interface UseAdTrackingOptions {
|
|
21
|
-
ad: IServeAd;
|
|
22
|
-
onDisplayAds?: (ad: IServeAd) => void;
|
|
23
|
-
isLoading?: boolean;
|
|
24
|
-
screenDimensions?: ScreenDimensions;
|
|
25
|
-
viewportOffsets?: ViewportOffsets;
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
export interface UseAdTrackingReturn {
|
|
29
|
-
viewRef: React.RefObject<View | null>;
|
|
30
|
-
layoutRef: React.MutableRefObject<{
|
|
31
|
-
x: number;
|
|
32
|
-
y: number;
|
|
33
|
-
width: number;
|
|
34
|
-
height: number;
|
|
35
|
-
} | null>;
|
|
36
|
-
hasDisplayed: React.MutableRefObject<boolean>;
|
|
37
|
-
adUniqueId: string;
|
|
38
|
-
handleLayout: () => void;
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
// Global set to track displayed ads - prevents duplicate tracking
|
|
42
|
-
const globalDisplayedAds = new Set<string>();
|
|
43
|
-
// Lock to prevent race conditions when checking and adding ads
|
|
44
|
-
const trackingLock = new Map<string, boolean>();
|
|
45
|
-
|
|
46
|
-
export const extractToken = (trackingUrl?: string): string => {
|
|
47
|
-
if (!trackingUrl) return '';
|
|
48
|
-
try {
|
|
49
|
-
const url = new URL(trackingUrl);
|
|
50
|
-
return url.searchParams.get('token') || '';
|
|
51
|
-
} catch {
|
|
52
|
-
const match = trackingUrl.match(/[?&]token=([^&]+)/);
|
|
53
|
-
return match?.[1] || '';
|
|
54
|
-
}
|
|
55
|
-
};
|
|
56
|
-
|
|
57
|
-
/**
|
|
58
|
-
* Creates a unique ID for an ad to prevent duplicate tracking
|
|
59
|
-
* Priority: _id > token > mediaUrl > fallback
|
|
60
|
-
*/
|
|
61
|
-
export const createAdUniqueId = (ad: IServeAd): string => {
|
|
62
|
-
// First try to use _id if available (most reliable)
|
|
63
|
-
if ('_id' in ad && ad._id) {
|
|
64
|
-
return `ad-${String(ad._id)}`;
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
// Then try token from tracking URL
|
|
68
|
-
const token = extractToken(ad.tracking?.impression);
|
|
69
|
-
if (token) {
|
|
70
|
-
return `ad-token-${token}`;
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
// Then use mediaUrl
|
|
74
|
-
const mediaUrl = ad.mediaUrl || '';
|
|
75
|
-
if (mediaUrl) {
|
|
76
|
-
return `ad-media-${mediaUrl}`;
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
// Last resort: use a combination of available fields
|
|
80
|
-
const clickUrl = ad.tracking?.click || '';
|
|
81
|
-
if (clickUrl) {
|
|
82
|
-
return `ad-click-${clickUrl}`;
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
// Fallback (should rarely happen)
|
|
86
|
-
return `ad-fallback-${Date.now()}-${Math.random()}`;
|
|
87
|
-
};
|
|
88
|
-
|
|
89
|
-
export const useAdTracking = (
|
|
90
|
-
options: UseAdTrackingOptions
|
|
91
|
-
): UseAdTrackingReturn => {
|
|
92
|
-
const {
|
|
93
|
-
ad,
|
|
94
|
-
onDisplayAds,
|
|
95
|
-
isLoading = false,
|
|
96
|
-
screenDimensions: propScreenDimensions,
|
|
97
|
-
viewportOffsets: propViewportOffsets,
|
|
98
|
-
} = options;
|
|
99
|
-
|
|
100
|
-
const viewRef = useRef<View>(null);
|
|
101
|
-
const layoutRef = useRef<{
|
|
102
|
-
x: number;
|
|
103
|
-
y: number;
|
|
104
|
-
width: number;
|
|
105
|
-
height: number;
|
|
106
|
-
} | null>(null);
|
|
107
|
-
const hasDisplayedRef = useRef<boolean>(false);
|
|
108
|
-
|
|
109
|
-
const onDisplayAdsRef = useRef(onDisplayAds);
|
|
110
|
-
const adRef = useRef(ad);
|
|
111
|
-
const isLoadingRef = useRef(isLoading);
|
|
112
|
-
|
|
113
|
-
useEffect(() => {
|
|
114
|
-
onDisplayAdsRef.current = onDisplayAds;
|
|
115
|
-
adRef.current = ad;
|
|
116
|
-
isLoadingRef.current = isLoading;
|
|
117
|
-
}, [onDisplayAds, ad, isLoading]);
|
|
118
|
-
|
|
119
|
-
const adUniqueId = useMemo(() => createAdUniqueId(ad), [ad]);
|
|
120
|
-
|
|
121
|
-
const screenDimensions = useMemo(
|
|
122
|
-
() => propScreenDimensions || Dimensions.get('window'),
|
|
123
|
-
[propScreenDimensions]
|
|
124
|
-
);
|
|
125
|
-
|
|
126
|
-
const viewportOffsets = useMemo(
|
|
127
|
-
() => ({
|
|
128
|
-
top: propViewportOffsets?.top ?? 50,
|
|
129
|
-
bottom: propViewportOffsets?.bottom ?? 100,
|
|
130
|
-
left: propViewportOffsets?.left ?? 20,
|
|
131
|
-
right: propViewportOffsets?.right ?? 20,
|
|
132
|
-
}),
|
|
133
|
-
[
|
|
134
|
-
propViewportOffsets?.top,
|
|
135
|
-
propViewportOffsets?.bottom,
|
|
136
|
-
propViewportOffsets?.left,
|
|
137
|
-
propViewportOffsets?.right,
|
|
138
|
-
]
|
|
139
|
-
);
|
|
140
|
-
|
|
141
|
-
const viewportBounds = useMemo(() => {
|
|
142
|
-
const { width: screenWidth, height: screenHeight } = screenDimensions;
|
|
143
|
-
return {
|
|
144
|
-
left: viewportOffsets.left,
|
|
145
|
-
right: screenWidth - viewportOffsets.right,
|
|
146
|
-
top: viewportOffsets.top,
|
|
147
|
-
bottom: screenHeight - viewportOffsets.bottom,
|
|
148
|
-
};
|
|
149
|
-
}, [screenDimensions, viewportOffsets]);
|
|
150
|
-
|
|
151
|
-
const checkVisibility = useCallback((): boolean => {
|
|
152
|
-
const layout = layoutRef.current;
|
|
153
|
-
if (!layout) {
|
|
154
|
-
return false;
|
|
155
|
-
}
|
|
156
|
-
|
|
157
|
-
const { x, y, width, height } = layout;
|
|
158
|
-
|
|
159
|
-
const isVisible =
|
|
160
|
-
x + width > viewportBounds.left &&
|
|
161
|
-
x < viewportBounds.right &&
|
|
162
|
-
y + height > viewportBounds.top &&
|
|
163
|
-
y < viewportBounds.bottom;
|
|
164
|
-
|
|
165
|
-
return isVisible;
|
|
166
|
-
}, [viewportBounds]);
|
|
167
|
-
|
|
168
|
-
const measureInWindow = useCallback((): void => {
|
|
169
|
-
const view = viewRef.current;
|
|
170
|
-
if (!view) return;
|
|
171
|
-
|
|
172
|
-
view.measureInWindow((x, y, width, height) => {
|
|
173
|
-
layoutRef.current = { x, y, width, height };
|
|
174
|
-
});
|
|
175
|
-
}, []);
|
|
176
|
-
|
|
177
|
-
/**
|
|
178
|
-
* Atomically checks and tracks ad display to prevent duplicate tracking
|
|
179
|
-
* Uses a lock mechanism to ensure only one instance can track the same ad
|
|
180
|
-
*/
|
|
181
|
-
const trackAdDisplay = useCallback((): boolean => {
|
|
182
|
-
const currentOnDisplayAds = onDisplayAdsRef.current;
|
|
183
|
-
const currentIsLoading = isLoadingRef.current;
|
|
184
|
-
|
|
185
|
-
if (!currentOnDisplayAds || currentIsLoading) {
|
|
186
|
-
return false;
|
|
187
|
-
}
|
|
188
|
-
|
|
189
|
-
// Early return if already displayed by this instance
|
|
190
|
-
if (hasDisplayedRef.current) {
|
|
191
|
-
return false;
|
|
192
|
-
}
|
|
193
|
-
|
|
194
|
-
// Atomic check-and-set: if ad is already being tracked or displayed, return false
|
|
195
|
-
if (globalDisplayedAds.has(adUniqueId)) {
|
|
196
|
-
// Mark this instance as displayed to prevent further checks
|
|
197
|
-
hasDisplayedRef.current = true;
|
|
198
|
-
return false;
|
|
199
|
-
}
|
|
200
|
-
|
|
201
|
-
// Set lock to prevent other instances from tracking the same ad
|
|
202
|
-
if (trackingLock.get(adUniqueId) === true) {
|
|
203
|
-
return false;
|
|
204
|
-
}
|
|
205
|
-
|
|
206
|
-
// Acquire lock
|
|
207
|
-
trackingLock.set(adUniqueId, true);
|
|
208
|
-
|
|
209
|
-
try {
|
|
210
|
-
// Double-check after acquiring lock (another instance might have added it)
|
|
211
|
-
if (globalDisplayedAds.has(adUniqueId)) {
|
|
212
|
-
hasDisplayedRef.current = true;
|
|
213
|
-
return false;
|
|
214
|
-
}
|
|
215
|
-
|
|
216
|
-
// Mark as displayed in both local and global state
|
|
217
|
-
hasDisplayedRef.current = true;
|
|
218
|
-
globalDisplayedAds.add(adUniqueId);
|
|
219
|
-
|
|
220
|
-
// Call the tracking callback
|
|
221
|
-
currentOnDisplayAds(adRef.current);
|
|
222
|
-
|
|
223
|
-
return true;
|
|
224
|
-
} finally {
|
|
225
|
-
// Release lock after a short delay to ensure callback completes
|
|
226
|
-
setTimeout(() => {
|
|
227
|
-
trackingLock.delete(adUniqueId);
|
|
228
|
-
}, 100);
|
|
229
|
-
}
|
|
230
|
-
}, [adUniqueId]);
|
|
231
|
-
|
|
232
|
-
const checkAndTrackVisibility = useCallback((): void => {
|
|
233
|
-
// Early exit if already displayed
|
|
234
|
-
if (hasDisplayedRef.current) {
|
|
235
|
-
return;
|
|
236
|
-
}
|
|
237
|
-
|
|
238
|
-
// Early exit if ad is already tracked globally or locked
|
|
239
|
-
if (
|
|
240
|
-
globalDisplayedAds.has(adUniqueId) ||
|
|
241
|
-
trackingLock.get(adUniqueId) === true
|
|
242
|
-
) {
|
|
243
|
-
// Mark this instance as displayed to prevent further checks
|
|
244
|
-
hasDisplayedRef.current = true;
|
|
245
|
-
return;
|
|
246
|
-
}
|
|
247
|
-
|
|
248
|
-
// Check visibility before tracking
|
|
249
|
-
if (!checkVisibility()) {
|
|
250
|
-
return;
|
|
251
|
-
}
|
|
252
|
-
|
|
253
|
-
// Attempt to track (will handle duplicate prevention internally)
|
|
254
|
-
trackAdDisplay();
|
|
255
|
-
}, [adUniqueId, checkVisibility, trackAdDisplay]);
|
|
256
|
-
|
|
257
|
-
const handleLayout = useCallback(() => {
|
|
258
|
-
const view = viewRef.current;
|
|
259
|
-
if (!view) return;
|
|
260
|
-
|
|
261
|
-
view.measureInWindow((x, y, width, height) => {
|
|
262
|
-
layoutRef.current = { x, y, width, height };
|
|
263
|
-
requestAnimationFrame(() => {
|
|
264
|
-
checkAndTrackVisibility();
|
|
265
|
-
});
|
|
266
|
-
});
|
|
267
|
-
}, [checkAndTrackVisibility]);
|
|
268
|
-
|
|
269
|
-
useEffect(() => {
|
|
270
|
-
if (isLoadingRef.current) {
|
|
271
|
-
return undefined;
|
|
272
|
-
}
|
|
273
|
-
|
|
274
|
-
let timeoutId: NodeJS.Timeout | null = null;
|
|
275
|
-
let rafId: number | null = null;
|
|
276
|
-
|
|
277
|
-
rafId = requestAnimationFrame(() => {
|
|
278
|
-
timeoutId = setTimeout(() => {
|
|
279
|
-
measureInWindow();
|
|
280
|
-
requestAnimationFrame(() => {
|
|
281
|
-
checkAndTrackVisibility();
|
|
282
|
-
});
|
|
283
|
-
}, INITIAL_CHECK_DELAY);
|
|
284
|
-
});
|
|
285
|
-
|
|
286
|
-
return () => {
|
|
287
|
-
if (rafId !== null) {
|
|
288
|
-
cancelAnimationFrame(rafId);
|
|
289
|
-
}
|
|
290
|
-
if (timeoutId !== null) {
|
|
291
|
-
clearTimeout(timeoutId);
|
|
292
|
-
}
|
|
293
|
-
};
|
|
294
|
-
}, [isLoading, checkAndTrackVisibility, measureInWindow]);
|
|
295
|
-
|
|
296
|
-
useEffect(() => {
|
|
297
|
-
if (
|
|
298
|
-
!onDisplayAdsRef.current ||
|
|
299
|
-
hasDisplayedRef.current ||
|
|
300
|
-
isLoadingRef.current
|
|
301
|
-
) {
|
|
302
|
-
return undefined;
|
|
303
|
-
}
|
|
304
|
-
|
|
305
|
-
let rafId: number | null = null;
|
|
306
|
-
let lastCheckTime = 0;
|
|
307
|
-
|
|
308
|
-
const checkWithThrottle = () => {
|
|
309
|
-
const now = Date.now();
|
|
310
|
-
|
|
311
|
-
if (now - lastCheckTime < CHECK_INTERVAL) {
|
|
312
|
-
rafId = requestAnimationFrame(checkWithThrottle);
|
|
313
|
-
return;
|
|
314
|
-
}
|
|
315
|
-
|
|
316
|
-
lastCheckTime = now;
|
|
317
|
-
|
|
318
|
-
if (hasDisplayedRef.current || !viewRef.current) {
|
|
319
|
-
return;
|
|
320
|
-
}
|
|
321
|
-
|
|
322
|
-
measureInWindow();
|
|
323
|
-
requestAnimationFrame(() => {
|
|
324
|
-
if (!hasDisplayedRef.current) {
|
|
325
|
-
checkAndTrackVisibility();
|
|
326
|
-
}
|
|
327
|
-
if (!hasDisplayedRef.current) {
|
|
328
|
-
rafId = requestAnimationFrame(checkWithThrottle);
|
|
329
|
-
}
|
|
330
|
-
});
|
|
331
|
-
};
|
|
332
|
-
|
|
333
|
-
rafId = requestAnimationFrame(checkWithThrottle);
|
|
334
|
-
|
|
335
|
-
return () => {
|
|
336
|
-
if (rafId !== null) {
|
|
337
|
-
cancelAnimationFrame(rafId);
|
|
338
|
-
}
|
|
339
|
-
};
|
|
340
|
-
}, [checkAndTrackVisibility, measureInWindow]);
|
|
341
|
-
|
|
342
|
-
return {
|
|
343
|
-
viewRef,
|
|
344
|
-
layoutRef,
|
|
345
|
-
hasDisplayed: hasDisplayedRef,
|
|
346
|
-
adUniqueId,
|
|
347
|
-
handleLayout,
|
|
348
|
-
};
|
|
349
|
-
};
|