@umituz/react-native-subscription 2.35.16 → 2.35.18

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 (37) hide show
  1. package/package.json +1 -1
  2. package/src/domains/config/utils/planSelectors.ts +1 -1
  3. package/src/domains/credits/presentation/useCredits.ts +6 -20
  4. package/src/domains/paywall/hooks/usePaywallActions.ts +2 -82
  5. package/src/domains/revenuecat/core/customerInfoHelpers.ts +21 -0
  6. package/src/domains/subscription/application/SubscriptionAuthListener.ts +0 -19
  7. package/src/domains/subscription/application/initializer/BackgroundInitializer.ts +2 -8
  8. package/src/domains/subscription/application/statusChangeHandlers.ts +0 -30
  9. package/src/domains/subscription/constants/thresholds.ts +10 -0
  10. package/src/domains/subscription/infrastructure/handlers/PurchaseStatusResolver.ts +3 -3
  11. package/src/domains/subscription/infrastructure/handlers/package-operations/PackageFetcher.ts +0 -19
  12. package/src/domains/subscription/infrastructure/hooks/customer-info/useCustomerInfo.ts +1 -1
  13. package/src/domains/subscription/infrastructure/hooks/useInitializeSubscription.ts +2 -4
  14. package/src/domains/subscription/infrastructure/hooks/usePurchasePackage.ts +0 -44
  15. package/src/domains/subscription/infrastructure/services/CustomerInfoListenerManager.ts +1 -31
  16. package/src/domains/subscription/infrastructure/services/OfferingsFetcher.ts +0 -21
  17. package/src/domains/subscription/infrastructure/services/listeners/CustomerInfoHandler.ts +6 -36
  18. package/src/domains/subscription/infrastructure/services/purchase/PurchaseExecutor.ts +0 -6
  19. package/src/domains/subscription/infrastructure/utils/PremiumStatusSyncer.ts +3 -44
  20. package/src/domains/subscription/presentation/featureGateActions.ts +0 -37
  21. package/src/domains/subscription/presentation/screens/components/SubscriptionHeader.tsx +1 -1
  22. package/src/domains/subscription/presentation/screens/components/SubscriptionHeaderContent.tsx +1 -1
  23. package/src/domains/subscription/presentation/useAuthAwarePurchase.ts +0 -43
  24. package/src/domains/subscription/presentation/useFeatureGate.ts +0 -39
  25. package/src/domains/subscription/presentation/useSubscriptionStatus.ts +6 -20
  26. package/src/domains/subscription/utils/authGuards.ts +26 -2
  27. package/src/domains/subscription/utils/expirationHelpers.ts +2 -2
  28. package/src/domains/wallet/presentation/hooks/useProductMetadata.ts +3 -6
  29. package/src/domains/wallet/presentation/hooks/useTransactionHistory.ts +3 -6
  30. package/src/shared/infrastructure/react-query/hooks/usePreviousUserCleanup.ts +39 -0
  31. package/src/shared/infrastructure/react-query/queryConfig.ts +22 -0
  32. package/src/shared/infrastructure/react-query/queryInvalidation.ts +46 -0
  33. package/src/shared/presentation/hooks/useServiceCall.ts +2 -1
  34. package/src/shared/utils/errorUtils.ts +32 -0
  35. package/src/utils/appUtils.ts +6 -0
  36. package/src/domains/subscription/presentation/components/details/PremiumDetailsCard.constants.ts +0 -1
  37. package/src/domains/subscription/presentation/screens/components/SubscriptionHeader.constants.ts +0 -1
@@ -0,0 +1,39 @@
1
+ /**
2
+ * User Cache Cleanup Hook
3
+ * Automatically cleans up previous user's query cache when userId changes
4
+ */
5
+
6
+ import { useEffect, useRef } from "react";
7
+ import type { QueryClient } from "@umituz/react-native-design-system";
8
+ import { isAuthenticated } from "../../../../domains/subscription/utils/authGuards";
9
+
10
+ /**
11
+ * Cleans up previous user's cache when userId changes (logout or user switch)
12
+ * Prevents data leakage between users
13
+ *
14
+ * @param userId - Current user ID
15
+ * @param queryClient - TanStack Query client
16
+ * @param queryKey - Query key factory function that takes userId
17
+ *
18
+ * @example
19
+ * usePreviousUserCleanup(userId, queryClient, (id) => creditsQueryKeys.user(id));
20
+ */
21
+ export function usePreviousUserCleanup(
22
+ userId: string | null | undefined,
23
+ queryClient: QueryClient,
24
+ queryKey: (userId: string) => readonly unknown[]
25
+ ): void {
26
+ const prevUserIdRef = useRef(userId);
27
+
28
+ useEffect(() => {
29
+ const prevUserId = prevUserIdRef.current;
30
+ prevUserIdRef.current = userId;
31
+
32
+ // Clear previous user's cache when userId changes (logout or user switch)
33
+ if (prevUserId !== userId && isAuthenticated(prevUserId)) {
34
+ queryClient.removeQueries({
35
+ queryKey: queryKey(prevUserId),
36
+ });
37
+ }
38
+ }, [userId, queryClient, queryKey]);
39
+ }
@@ -0,0 +1,22 @@
1
+ /**
2
+ * Shared TanStack Query Configuration
3
+ * Common query configurations to ensure consistency across hooks
4
+ */
5
+
6
+ /**
7
+ * Configuration for queries that should never cache
8
+ * Used for real-time sensitive data (subscriptions, credits, transactions)
9
+ *
10
+ * - gcTime: 0 - Don't keep unused data in memory
11
+ * - staleTime: 0 - Always consider data stale
12
+ * - refetchOnMount: "always" - Always refetch when component mounts
13
+ * - refetchOnWindowFocus: "always" - Always refetch when window regains focus
14
+ * - refetchOnReconnect: "always" - Always refetch when reconnecting
15
+ */
16
+ export const NO_CACHE_QUERY_CONFIG = {
17
+ gcTime: 0,
18
+ staleTime: 0,
19
+ refetchOnMount: "always" as const,
20
+ refetchOnWindowFocus: "always" as const,
21
+ refetchOnReconnect: "always" as const,
22
+ };
@@ -0,0 +1,46 @@
1
+ /**
2
+ * Query Invalidation Utilities
3
+ * Centralized functions for invalidating multiple related queries
4
+ */
5
+
6
+ import type { QueryClient } from "@umituz/react-native-design-system";
7
+ import { creditsQueryKeys } from "../../../domains/credits/presentation/creditsQueryKeys";
8
+ import { subscriptionStatusQueryKeys } from "../../../domains/subscription/presentation/useSubscriptionStatus";
9
+
10
+ // Subscription packages query key
11
+ export const SUBSCRIPTION_QUERY_KEYS = {
12
+ packages: ["subscription", "packages"] as const,
13
+ };
14
+
15
+ /**
16
+ * Invalidates all subscription-related queries
17
+ * Use after purchases, restores, or subscription changes
18
+ *
19
+ * @param queryClient - TanStack Query client
20
+ * @param userId - Optional user ID to invalidate user-specific queries
21
+ *
22
+ * @example
23
+ * // After successful purchase
24
+ * await invalidateSubscriptionQueries(queryClient, userId);
25
+ */
26
+ export async function invalidateSubscriptionQueries(
27
+ queryClient: QueryClient,
28
+ userId?: string | null
29
+ ): Promise<void> {
30
+ // Invalidate packages (affects all users)
31
+ await queryClient.invalidateQueries({
32
+ queryKey: SUBSCRIPTION_QUERY_KEYS.packages,
33
+ });
34
+
35
+ // Invalidate user-specific queries if userId provided
36
+ if (userId) {
37
+ await Promise.all([
38
+ queryClient.invalidateQueries({
39
+ queryKey: subscriptionStatusQueryKeys.user(userId),
40
+ }),
41
+ queryClient.invalidateQueries({
42
+ queryKey: creditsQueryKeys.user(userId),
43
+ }),
44
+ ]);
45
+ }
46
+ }
@@ -4,6 +4,7 @@
4
4
  */
5
5
 
6
6
  import { useState, useCallback, useRef, useEffect } from "react";
7
+ import { normalizeError } from "../../utils/errorUtils";
7
8
 
8
9
  export interface ServiceCallState<T> {
9
10
  data: T | null;
@@ -54,7 +55,7 @@ export function useServiceCall<T>(
54
55
  setState({ data, isLoading: false, error: null });
55
56
  onSuccessRef.current?.(data);
56
57
  } catch (error) {
57
- const errorObj = error instanceof Error ? error : new Error("Service call failed");
58
+ const errorObj = normalizeError(error, "Service call failed");
58
59
  setState({ data: null, isLoading: false, error: errorObj });
59
60
  onErrorRef.current?.(errorObj);
60
61
  } finally {
@@ -0,0 +1,32 @@
1
+ /**
2
+ * Error Utilities
3
+ * Common error handling and normalization functions
4
+ */
5
+
6
+ /**
7
+ * Normalizes unknown error types to Error objects
8
+ * Useful for catch blocks where error type is unknown
9
+ *
10
+ * @param error - The error to normalize (unknown type)
11
+ * @param fallbackMessage - Message to use if error is not an Error object
12
+ * @returns Always returns an Error object
13
+ *
14
+ * @example
15
+ * try {
16
+ * await someOperation();
17
+ * } catch (error) {
18
+ * const err = normalizeError(error, "Operation failed");
19
+ * console.error(err.message);
20
+ * }
21
+ */
22
+ export function normalizeError(
23
+ error: unknown,
24
+ fallbackMessage = "Unknown error"
25
+ ): Error {
26
+ if (error instanceof Error) {
27
+ return error;
28
+ }
29
+
30
+ const message = typeof error === "string" ? error : String(error);
31
+ return new Error(message || fallbackMessage);
32
+ }
@@ -4,6 +4,12 @@
4
4
  import { Platform } from "react-native";
5
5
  import Constants from "expo-constants";
6
6
 
7
+ /**
8
+ * Development mode flag
9
+ * Safe check for __DEV__ that works in all environments
10
+ */
11
+ export const IS_DEV_MODE = typeof __DEV__ !== "undefined" && __DEV__;
12
+
7
13
  /**
8
14
  * Gets the current app version from Expo constants
9
15
  */
@@ -1 +0,0 @@
1
- export const DAYS_REMAINING_WARNING_THRESHOLD = 7;
@@ -1 +0,0 @@
1
- export const EXPIRING_SOON_THRESHOLD_DAYS = 7;