@umituz/react-native-subscription 2.37.12 → 2.37.14

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 (133) hide show
  1. package/package.json +1 -1
  2. package/src/domains/credits/application/PurchaseMetadataGenerator.ts +1 -1
  3. package/src/domains/credits/application/credit-strategies/CreditAllocationOrchestrator.ts +1 -1
  4. package/src/domains/credits/application/creditDocumentHelpers.ts +0 -14
  5. package/src/domains/credits/presentation/deduct-credit/index.ts +0 -1
  6. package/src/domains/credits/presentation/useCredits.ts +1 -6
  7. package/src/domains/credits/utils/creditValidation.ts +3 -3
  8. package/src/domains/paywall/components/PaywallFeatures.tsx +1 -1
  9. package/src/domains/paywall/hooks/usePaywallActions.ts +1 -1
  10. package/src/domains/revenuecat/core/errors/RevenueCatError.ts +1 -14
  11. package/src/domains/revenuecat/core/errors/RevenueCatErrorHandler.ts +1 -1
  12. package/src/domains/revenuecat/core/types/RevenueCatTypes.ts +3 -3
  13. package/src/domains/revenuecat/infrastructure/services/ConfigurationStateManager.ts +1 -1
  14. package/src/domains/revenuecat/infrastructure/services/RevenueCatInitializer.ts +0 -2
  15. package/src/domains/revenuecat/infrastructure/services/UserSwitchMutex.ts +9 -0
  16. package/src/domains/subscription/application/initializer/index.ts +1 -1
  17. package/src/domains/subscription/core/SubscriptionStatus.ts +4 -10
  18. package/src/domains/subscription/core/SubscriptionStatusHandlers.ts +1 -1
  19. package/src/domains/subscription/infrastructure/handlers/PackageHandler.ts +0 -2
  20. package/src/domains/subscription/infrastructure/hooks/usePurchasePackage.ts +1 -1
  21. package/src/domains/subscription/infrastructure/hooks/useRevenueCatTrialEligibility.ts +1 -2
  22. package/src/domains/subscription/infrastructure/hooks/useSubscriptionQueries.ts +0 -4
  23. package/src/domains/subscription/infrastructure/services/OfferingsFetcher.ts +1 -1
  24. package/src/domains/subscription/infrastructure/services/RestoreHandler.ts +1 -1
  25. package/src/domains/subscription/infrastructure/services/RevenueCatService.ts +1 -2
  26. package/src/domains/subscription/infrastructure/services/revenueCatServiceInstance.ts +0 -4
  27. package/src/domains/subscription/infrastructure/utils/renewal/index.ts +1 -1
  28. package/src/domains/subscription/presentation/components/details/CreditRow.tsx +1 -1
  29. package/src/domains/subscription/presentation/components/details/DetailRow.tsx +1 -1
  30. package/src/domains/subscription/presentation/components/feedback/FeedbackOption.tsx +0 -2
  31. package/src/domains/subscription/presentation/components/feedback/FeedbackTextInput.tsx +1 -1
  32. package/src/domains/subscription/presentation/featureGateRefs.ts +1 -1
  33. package/src/domains/subscription/presentation/screens/components/CreditsList.tsx +2 -2
  34. package/src/domains/subscription/presentation/screens/components/SubscriptionHeader.tsx +0 -2
  35. package/src/domains/subscription/presentation/stores/index.ts +0 -5
  36. package/src/domains/subscription/presentation/stores/purchaseLoadingStore.ts +3 -7
  37. package/src/domains/subscription/presentation/useAuthAwarePurchase.ts +2 -8
  38. package/src/domains/subscription/presentation/useFeatureGate.ts +0 -2
  39. package/src/domains/subscription/presentation/usePaywallVisibility.ts +1 -1
  40. package/src/domains/subscription/utils/authGuards.ts +0 -23
  41. package/src/domains/subscription/utils/syncStatus.ts +1 -1
  42. package/src/domains/wallet/index.ts +0 -112
  43. package/src/domains/wallet/infrastructure/config/walletConfig.ts +1 -23
  44. package/src/domains/wallet/infrastructure/repositories/transaction/CollectionBuilder.ts +1 -1
  45. package/src/domains/wallet/infrastructure/repositories/transaction/index.ts +0 -9
  46. package/src/domains/wallet/presentation/components/BalanceCard.tsx +1 -1
  47. package/src/domains/wallet/presentation/components/TransactionItem.tsx +0 -2
  48. package/src/domains/wallet/presentation/components/TransactionList.tsx +3 -2
  49. package/src/domains/wallet/presentation/hooks/useTransactionHistory.ts +2 -2
  50. package/src/domains/wallet/presentation/hooks/useWallet.ts +2 -2
  51. package/src/shared/application/FeedbackService.ts +2 -2
  52. package/src/shared/infrastructure/SubscriptionEventBus.ts +1 -1
  53. package/src/shared/infrastructure/firestore/collectionUtils.ts +0 -7
  54. package/src/shared/infrastructure/firestore/resultUtils.ts +3 -39
  55. package/src/shared/presentation/layouts/ScreenLayout.tsx +1 -1
  56. package/src/shared/utils/numberUtils.core.ts +0 -27
  57. package/src/shared/utils/numberUtils.ts +1 -9
  58. package/src/shared/utils/validators.ts +0 -58
  59. package/src/domains/config/domain/entities/Plan.ts +0 -44
  60. package/src/domains/config/domain/index.ts +0 -2
  61. package/src/domains/config/domain/value-objects/Config.ts +0 -49
  62. package/src/domains/config/index.ts +0 -6
  63. package/src/domains/config/utils/planSelectors.ts +0 -56
  64. package/src/domains/paywall/components/FeatureItem.tsx +0 -50
  65. package/src/domains/paywall/components/FeatureList.tsx +0 -34
  66. package/src/domains/paywall/components/PaywallHeader.tsx +0 -112
  67. package/src/domains/paywall/hooks/usePaywallTranslations.ts +0 -78
  68. package/src/domains/paywall/hooks/useSubscriptionModal.ts +0 -45
  69. package/src/domains/paywall/index.ts +0 -13
  70. package/src/domains/revenuecat/core/constants/RevenueCatConstants.ts +0 -201
  71. package/src/domains/revenuecat/core/constants/index.ts +0 -5
  72. package/src/domains/revenuecat/core/customerInfoHelpers.ts +0 -21
  73. package/src/domains/revenuecat/core/index.ts +0 -7
  74. package/src/domains/revenuecat/index.ts +0 -7
  75. package/src/domains/revenuecat/infrastructure/index.ts +0 -5
  76. package/src/domains/revenuecat/infrastructure/services/index.ts +0 -7
  77. package/src/domains/subscription/infrastructure/hooks/customer-info/index.ts +0 -2
  78. package/src/domains/subscription/infrastructure/hooks/customer-info/types.ts +0 -9
  79. package/src/domains/subscription/infrastructure/hooks/customer-info/useCustomerInfo.ts +0 -52
  80. package/src/domains/subscription/infrastructure/hooks/useInitializeSubscription.ts +0 -30
  81. package/src/domains/subscription/infrastructure/hooks/usePaywallFlow.ts +0 -78
  82. package/src/domains/subscription/infrastructure/hooks/useRevenueCat.ts +0 -119
  83. package/src/domains/subscription/presentation/components/feedback/FeedbackConstants.ts +0 -6
  84. package/src/domains/subscription/presentation/screens/components/SubscriptionActions.tsx +0 -56
  85. package/src/domains/subscription/utils/dateFormatters.ts +0 -28
  86. package/src/domains/wallet/domain/entities/CreditCost.ts +0 -45
  87. package/src/domains/wallet/domain/entities/README.md +0 -41
  88. package/src/domains/wallet/domain/errors/README.md +0 -40
  89. package/src/domains/wallet/domain/errors/WalletError.ts +0 -17
  90. package/src/domains/wallet/domain/errors/WalletError.types.ts +0 -30
  91. package/src/domains/wallet/domain/errors/WalletErrorClasses.ts +0 -82
  92. package/src/domains/wallet/domain/errors/WalletErrorFactory.ts +0 -24
  93. package/src/domains/wallet/domain/errors/WalletErrorMessages.ts +0 -17
  94. package/src/domains/wallet/domain/types/credit-cost.types.ts +0 -86
  95. package/src/domains/wallet/domain/types/index.ts +0 -33
  96. package/src/domains/wallet/domain/types/wallet.types.ts +0 -50
  97. package/src/domains/wallet/infrastructure/services/product-metadata/CacheManager.ts +0 -30
  98. package/src/domains/wallet/infrastructure/services/product-metadata/FirebaseFetcher.ts +0 -17
  99. package/src/domains/wallet/infrastructure/services/product-metadata/ProductMetadataService.ts +0 -57
  100. package/src/domains/wallet/infrastructure/services/product-metadata/ServiceManager.ts +0 -29
  101. package/src/domains/wallet/infrastructure/services/product-metadata/index.ts +0 -7
  102. package/src/domains/wallet/presentation/hooks/index.ts +0 -8
  103. package/src/domains/wallet/presentation/hooks/useProductMetadata.ts +0 -72
  104. package/src/domains/wallet/utils/index.ts +0 -1
  105. package/src/shared/application/ActivationHandler.ts +0 -108
  106. package/src/shared/application/ports/ISubscriptionService.ts +0 -27
  107. package/src/shared/infrastructure/index.ts +0 -6
  108. package/src/shared/infrastructure/react-query/queryInvalidation.ts +0 -46
  109. package/src/shared/presentation/hooks/index.ts +0 -6
  110. package/src/shared/presentation/hooks/useAsyncState.ts +0 -72
  111. package/src/shared/presentation/hooks/useServiceCall.ts +0 -77
  112. package/src/shared/types/ReactTypes.ts +0 -80
  113. package/src/shared/utils/InsufficientCreditsError.ts +0 -32
  114. package/src/shared/utils/Logger.ts +0 -81
  115. package/src/shared/utils/SubscriptionConfig.ts +0 -15
  116. package/src/shared/utils/SubscriptionError.ts +0 -47
  117. package/src/shared/utils/appValidators.ts +0 -38
  118. package/src/shared/utils/arrayUtils.core.ts +0 -81
  119. package/src/shared/utils/arrayUtils.query.ts +0 -118
  120. package/src/shared/utils/arrayUtils.transforms.ts +0 -116
  121. package/src/shared/utils/arrayUtils.ts +0 -19
  122. package/src/shared/utils/errorUtils.ts +0 -32
  123. package/src/shared/utils/index.ts +0 -14
  124. package/src/shared/utils/numberUtils.aggregate.ts +0 -35
  125. package/src/shared/utils/numberUtils.format.ts +0 -42
  126. package/src/shared/utils/numberUtils.math.ts +0 -48
  127. package/src/shared/utils/queryKeyFactory.ts +0 -9
  128. package/src/shared/utils/stringUtils.case.ts +0 -64
  129. package/src/shared/utils/stringUtils.check.ts +0 -65
  130. package/src/shared/utils/stringUtils.format.ts +0 -84
  131. package/src/shared/utils/stringUtils.generate.ts +0 -47
  132. package/src/shared/utils/stringUtils.modify.ts +0 -67
  133. package/src/shared/utils/stringUtils.ts +0 -10
@@ -1,86 +0,0 @@
1
- /**
2
- * Credit Cost Types
3
- *
4
- * Types for configurable AI operation credit costs.
5
- * Apps can override these costs based on their pricing model.
6
- */
7
-
8
- export interface CreditCostConfig {
9
- [operationKey: string]: number;
10
- }
11
-
12
- export interface AICreditCosts {
13
- IMAGE: number;
14
- VIDEO_5S: number;
15
- VIDEO_10S: number;
16
- VOICE: number;
17
- UPSCALE: number;
18
- PHOTO_RESTORE: number;
19
- REMOVE_BACKGROUND: number;
20
- ANIME_SELFIE: number;
21
- FACE_SWAP: number;
22
- REMOVE_OBJECT: number;
23
- REPLACE_BACKGROUND: number;
24
- INPAINTING: number;
25
- IMAGE_TO_IMAGE: number;
26
- AI_HUG: number;
27
- AI_KISS: number;
28
- IMAGE_TO_VIDEO_5S: number;
29
- IMAGE_TO_VIDEO_10S: number;
30
- TEXT_TO_VIDEO_5S: number;
31
- TEXT_TO_VIDEO_10S: number;
32
- TREND_VIDEO: number;
33
- EFFECT_VIDEO: number;
34
- }
35
-
36
- export const DEFAULT_AI_CREDIT_COSTS: AICreditCosts = {
37
- IMAGE: 2,
38
- VIDEO_5S: 20,
39
- VIDEO_10S: 35,
40
- VOICE: 3,
41
- UPSCALE: 2,
42
- PHOTO_RESTORE: 2,
43
- REMOVE_BACKGROUND: 2,
44
- ANIME_SELFIE: 3,
45
- FACE_SWAP: 4,
46
- REMOVE_OBJECT: 5,
47
- REPLACE_BACKGROUND: 5,
48
- INPAINTING: 5,
49
- IMAGE_TO_IMAGE: 3,
50
- AI_HUG: 15,
51
- AI_KISS: 15,
52
- IMAGE_TO_VIDEO_5S: 20,
53
- IMAGE_TO_VIDEO_10S: 35,
54
- TEXT_TO_VIDEO_5S: 25,
55
- TEXT_TO_VIDEO_10S: 45,
56
- TREND_VIDEO: 20,
57
- EFFECT_VIDEO: 15,
58
- };
59
-
60
- export interface CreditCostResult {
61
- cost: number;
62
- dollarValue: number;
63
- }
64
-
65
- export function getCreditCost(
66
- config: CreditCostConfig,
67
- operation: string
68
- ): number {
69
- return config[operation] ?? 0;
70
- }
71
-
72
- export function creditsToDollars(
73
- credits: number,
74
- pricePerCredit: number = 0.1
75
- ): number {
76
- return credits * pricePerCredit;
77
- }
78
-
79
- export function createCreditCostConfig(
80
- overrides?: Partial<AICreditCosts>
81
- ): AICreditCosts {
82
- return {
83
- ...DEFAULT_AI_CREDIT_COSTS,
84
- ...overrides,
85
- };
86
- }
@@ -1,33 +0,0 @@
1
- /**
2
- * Wallet Domain Types
3
- */
4
-
5
- export type {
6
- TransactionReason,
7
- CreditLog,
8
- TransactionRepositoryConfig,
9
- TransactionQueryOptions,
10
- TransactionResult,
11
- } from "./transaction.types";
12
-
13
- export type {
14
- WalletConfig,
15
- ProductType,
16
- ProductMetadata,
17
- ProductMetadataConfig,
18
- CreditBalance,
19
- WalletTranslations,
20
- } from "./wallet.types";
21
-
22
- export type {
23
- CreditCostConfig,
24
- AICreditCosts,
25
- CreditCostResult,
26
- } from "./credit-cost.types";
27
-
28
- export {
29
- DEFAULT_AI_CREDIT_COSTS,
30
- getCreditCost,
31
- creditsToDollars,
32
- createCreditCostConfig,
33
- } from "./credit-cost.types";
@@ -1,50 +0,0 @@
1
- /**
2
- * Wallet Types
3
- *
4
- * Types for wallet configuration and product metadata.
5
- * Generic types for use across hundreds of apps.
6
- */
7
-
8
- export interface WalletConfig {
9
- transactionCollectionName: string;
10
- productMetadataCollectionName: string;
11
- useUserSubcollection?: boolean;
12
- cacheTTL?: number;
13
- }
14
-
15
- export type ProductType = "credits" | "subscription";
16
-
17
- export interface ProductMetadata {
18
- productId: string;
19
- type: ProductType;
20
- name: string;
21
- description?: string;
22
- credits?: number;
23
- bonus?: number;
24
- popular?: boolean;
25
- features?: string[];
26
- order?: number;
27
- }
28
-
29
- export interface ProductMetadataConfig {
30
- collectionName: string;
31
- cacheTTL?: number;
32
- }
33
-
34
- export interface CreditBalance {
35
- credits: number;
36
- textCredits?: number;
37
- imageCredits?: number;
38
- }
39
-
40
- export interface WalletTranslations {
41
- title: string;
42
- balance: string;
43
- availableCredits: string;
44
- transactionHistory: string;
45
- noTransactions: string;
46
- loading: string;
47
- purchase: string;
48
- packages: string;
49
- viewHistory: string;
50
- }
@@ -1,30 +0,0 @@
1
- import type { ProductMetadata } from "../../../domain/types/wallet.types";
2
-
3
- interface CacheEntry {
4
- data: ProductMetadata[];
5
- timestamp: number;
6
- }
7
-
8
- const DEFAULT_CACHE_TTL_MS = 5 * 60 * 1000;
9
-
10
- export class CacheManager {
11
- private cache: CacheEntry | null = null;
12
-
13
- isCacheValid(cacheTTL?: number): boolean {
14
- if (!this.cache) return false;
15
- const ttl = cacheTTL ?? DEFAULT_CACHE_TTL_MS;
16
- return Date.now() - this.cache.timestamp < ttl;
17
- }
18
-
19
- get(): ProductMetadata[] | null {
20
- return this.cache?.data ?? null;
21
- }
22
-
23
- set(data: ProductMetadata[]): void {
24
- this.cache = { data, timestamp: Date.now() };
25
- }
26
-
27
- clear(): void {
28
- this.cache = null;
29
- }
30
- }
@@ -1,17 +0,0 @@
1
- import { collection, getDocs, orderBy, query } from "firebase/firestore";
2
- import { requireFirestore } from "../../../../../shared/infrastructure";
3
- import type { ProductMetadata } from "../../../domain/types/wallet.types";
4
-
5
- export async function fetchProductsFromFirebase(
6
- collectionName: string
7
- ): Promise<ProductMetadata[]> {
8
- const db = requireFirestore();
9
- const colRef = collection(db, collectionName);
10
- const q = query(colRef, orderBy("order", "asc"));
11
- const snapshot = await getDocs(q);
12
-
13
- return snapshot.docs.map((docSnap) => ({
14
- productId: docSnap.id,
15
- ...docSnap.data(),
16
- })) as ProductMetadata[];
17
- }
@@ -1,57 +0,0 @@
1
- import type {
2
- ProductMetadata,
3
- ProductMetadataConfig,
4
- ProductType,
5
- } from "../../../domain/types/wallet.types";
6
- import { CacheManager } from "./CacheManager";
7
- import { fetchProductsFromFirebase } from "./FirebaseFetcher";
8
-
9
- export class ProductMetadataService {
10
- private config: ProductMetadataConfig;
11
- private cacheManager: CacheManager;
12
-
13
- constructor(config: ProductMetadataConfig) {
14
- this.config = config;
15
- this.cacheManager = new CacheManager();
16
- }
17
-
18
- async getAll(): Promise<ProductMetadata[]> {
19
- if (this.cacheManager.isCacheValid(this.config.cacheTTL)) {
20
- return this.cacheManager.get()!;
21
- }
22
-
23
- try {
24
- const data = await fetchProductsFromFirebase(this.config.collectionName);
25
- this.cacheManager.set(data);
26
- return data;
27
- } catch (error) {
28
- const cachedData = this.cacheManager.get();
29
- if (cachedData) {
30
- return cachedData;
31
- }
32
- throw error;
33
- }
34
- }
35
-
36
- async getByProductId(productId: string): Promise<ProductMetadata | null> {
37
- const all = await this.getAll();
38
- return all.find((p) => p.productId === productId) ?? null;
39
- }
40
-
41
- async getByType(type: ProductType): Promise<ProductMetadata[]> {
42
- const all = await this.getAll();
43
- return all.filter((p) => p.type === type);
44
- }
45
-
46
- async getCreditsPackages(): Promise<ProductMetadata[]> {
47
- return this.getByType("credits");
48
- }
49
-
50
- async getSubscriptionPackages(): Promise<ProductMetadata[]> {
51
- return this.getByType("subscription");
52
- }
53
-
54
- clearCache(): void {
55
- this.cacheManager.clear();
56
- }
57
- }
@@ -1,29 +0,0 @@
1
- import type { ProductMetadataConfig } from "../../../domain/types/wallet.types";
2
- import { ProductMetadataService } from "./ProductMetadataService";
3
-
4
- export function createProductMetadataService(
5
- config: ProductMetadataConfig
6
- ): ProductMetadataService {
7
- return new ProductMetadataService(config);
8
- }
9
-
10
- let defaultService: ProductMetadataService | null = null;
11
-
12
- export function configureProductMetadataService(
13
- config: ProductMetadataConfig
14
- ): void {
15
- defaultService = new ProductMetadataService(config);
16
- }
17
-
18
- export function getProductMetadataService(): ProductMetadataService {
19
- if (!defaultService) {
20
- throw new Error(
21
- "ProductMetadataService not configured. Call configureProductMetadataService first."
22
- );
23
- }
24
- return defaultService;
25
- }
26
-
27
- export function resetProductMetadataService(): void {
28
- defaultService = null;
29
- }
@@ -1,7 +0,0 @@
1
- export { ProductMetadataService } from "./ProductMetadataService";
2
- export {
3
- createProductMetadataService,
4
- configureProductMetadataService,
5
- getProductMetadataService,
6
- resetProductMetadataService,
7
- } from "./ServiceManager";
@@ -1,8 +0,0 @@
1
- /**
2
- * Wallet Presentation Hooks
3
- * Barrel export for all wallet-related React hooks
4
- */
5
-
6
- export * from "./useProductMetadata";
7
- export * from "./useTransactionHistory";
8
- export * from "./useWallet";
@@ -1,72 +0,0 @@
1
- import { useQuery } from "@umituz/react-native-design-system";
2
- import { useMemo } from "react";
3
- import { NO_CACHE_QUERY_CONFIG } from "../../../../shared/infrastructure/react-query/queryConfig";
4
- import type {
5
- ProductMetadata,
6
- ProductMetadataConfig,
7
- ProductType,
8
- } from "../../domain/types/wallet.types";
9
- import { ProductMetadataService } from "../../infrastructure/services/product-metadata";
10
-
11
- export const productMetadataQueryKeys = {
12
- all: ["productMetadata"] as const,
13
- byType: (type: ProductType) => ["productMetadata", type] as const,
14
- };
15
-
16
- export interface UseProductMetadataParams {
17
- config: ProductMetadataConfig;
18
- type?: ProductType;
19
- enabled?: boolean;
20
- }
21
-
22
- export interface UseProductMetadataResult {
23
- products: ProductMetadata[];
24
- isLoading: boolean;
25
- error: Error | null;
26
- refetch: () => void;
27
- creditsPackages: ProductMetadata[];
28
- subscriptionPackages: ProductMetadata[];
29
- }
30
-
31
- export function useProductMetadata({
32
- config,
33
- type,
34
- enabled = true,
35
- }: UseProductMetadataParams): UseProductMetadataResult {
36
- const service = useMemo(
37
- () => new ProductMetadataService(config),
38
- [config]
39
- );
40
-
41
- const queryKey = type
42
- ? productMetadataQueryKeys.byType(type)
43
- : productMetadataQueryKeys.all;
44
-
45
- const { data, status, error, refetch } = useQuery({
46
- queryKey,
47
- queryFn: async () => {
48
- if (type) {
49
- return service.getByType(type);
50
- }
51
- return service.getAll();
52
- },
53
- enabled,
54
- ...NO_CACHE_QUERY_CONFIG,
55
- });
56
-
57
- const products = data ?? [];
58
- const isLoading = status === "pending";
59
-
60
- const creditsPackages = products.filter((p) => p.type === "credits");
61
- const subscriptionPackages = products.filter((p) => p.type === "subscription");
62
-
63
- return {
64
- products,
65
- isLoading,
66
- error: error as Error | null,
67
- refetch,
68
- creditsPackages,
69
- subscriptionPackages,
70
- };
71
- }
72
-
@@ -1 +0,0 @@
1
- export * from "./transactionIconMap";
@@ -1,108 +0,0 @@
1
- import { timezoneService } from "@umituz/react-native-design-system";
2
- import type { ISubscriptionRepository } from "../application/ports/ISubscriptionRepository";
3
- import type { SubscriptionStatus } from "../../domains/subscription/core/SubscriptionStatus";
4
- import { SubscriptionRepositoryError } from "../utils/SubscriptionError";
5
-
6
- export interface ActivationHandlerConfig {
7
- repository: ISubscriptionRepository;
8
- onStatusChanged?: (
9
- userId: string,
10
- status: SubscriptionStatus
11
- ) => Promise<void> | void;
12
- onError?: (error: Error, operation: string) => Promise<void> | void;
13
- }
14
-
15
- /**
16
- * Activate subscription for user
17
- */
18
- export async function activateSubscription(
19
- config: ActivationHandlerConfig,
20
- userId: string,
21
- productId: string,
22
- expiresAt: string | null
23
- ): Promise<SubscriptionStatus> {
24
- try {
25
- const updatedStatus = await config.repository.updateSubscriptionStatus(
26
- userId,
27
- {
28
- isPremium: true,
29
- productId,
30
- expiresAt,
31
- purchasedAt: timezoneService.getCurrentISOString(),
32
- syncedAt: timezoneService.getCurrentISOString(),
33
- }
34
- );
35
-
36
-
37
- await notifyStatusChange(config, userId, updatedStatus);
38
- return updatedStatus;
39
- } catch (error) {
40
- await handleError(config, error, "activateSubscription");
41
- throw new SubscriptionRepositoryError("Failed to activate subscription");
42
- }
43
- }
44
-
45
- /**
46
- * Deactivate subscription for user
47
- */
48
- export async function deactivateSubscription(
49
- config: ActivationHandlerConfig,
50
- userId: string
51
- ): Promise<SubscriptionStatus> {
52
- try {
53
- const updatedStatus = await config.repository.updateSubscriptionStatus(
54
- userId,
55
- {
56
- isPremium: false,
57
- expiresAt: null,
58
- productId: null,
59
- }
60
- );
61
-
62
- await notifyStatusChange(config, userId, updatedStatus);
63
- return updatedStatus;
64
- } catch (error) {
65
- await handleError(config, error, "deactivateSubscription");
66
- throw new SubscriptionRepositoryError("Failed to deactivate subscription");
67
- }
68
- }
69
-
70
- async function notifyStatusChange(
71
- config: ActivationHandlerConfig,
72
- userId: string,
73
- status: SubscriptionStatus
74
- ): Promise<void> {
75
- if (!config.onStatusChanged) return;
76
-
77
- try {
78
- await config.onStatusChanged(userId, status);
79
- } catch (error) {
80
- await handleError(config, error, "onStatusChanged");
81
- }
82
- }
83
-
84
- /**
85
- * Safe error handler - wraps error callbacks to prevent secondary failures
86
- */
87
- export async function safeHandleError(
88
- onError: ((error: Error, operation: string) => Promise<void> | void) | undefined,
89
- error: unknown,
90
- operation: string
91
- ): Promise<void> {
92
- if (!onError) return;
93
-
94
- try {
95
- const err = error instanceof Error ? error : new Error("Unknown error");
96
- await onError(err, operation);
97
- } catch {
98
- // Ignore callback errors
99
- }
100
- }
101
-
102
- async function handleError(
103
- config: ActivationHandlerConfig,
104
- error: unknown,
105
- operation: string
106
- ): Promise<void> {
107
- await safeHandleError(config.onError, error, `ActivationHandler.${operation}`);
108
- }
@@ -1,27 +0,0 @@
1
- /**
2
- * Subscription Service Interface
3
- * Defines the contract for subscription service operations
4
- */
5
-
6
- import type { SubscriptionStatus } from '../../../domains/subscription/core/SubscriptionStatus';
7
-
8
- export interface ISubscriptionService {
9
- /**
10
- * Activate a subscription
11
- */
12
- activateSubscription(
13
- userId: string,
14
- productId: string,
15
- expiresAt: string | null
16
- ): Promise<SubscriptionStatus>;
17
-
18
- /**
19
- * Deactivate a subscription
20
- */
21
- deactivateSubscription(userId: string): Promise<SubscriptionStatus>;
22
-
23
- /**
24
- * Check if user has premium access
25
- */
26
- isPremium(userId: string): Promise<boolean>;
27
- }
@@ -1,6 +0,0 @@
1
- /**
2
- * Shared Infrastructure
3
- */
4
-
5
- export * from "./SubscriptionEventBus";
6
- export * from "./firestore";
@@ -1,46 +0,0 @@
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
- }
@@ -1,6 +0,0 @@
1
- /**
2
- * Shared Presentation Hooks
3
- */
4
-
5
- export * from "./useAsyncState";
6
- export * from "./useServiceCall";
@@ -1,72 +0,0 @@
1
- /**
2
- * useAsyncState Hook
3
- * Shared hook for managing async operation states
4
- */
5
-
6
- import { useState, useCallback } from "react";
7
-
8
- export type AsyncStatus = "idle" | "loading" | "success" | "error";
9
-
10
- export interface AsyncState<T> {
11
- data: T | null;
12
- status: AsyncStatus;
13
- error: Error | null;
14
- }
15
-
16
- export interface UseAsyncStateOptions<T> {
17
- initialData?: T | null;
18
- onSuccess?: (data: T) => void;
19
- onError?: (error: Error) => void;
20
- }
21
-
22
- export interface UseAsyncStateReturn<T> {
23
- data: T | null;
24
- status: AsyncStatus;
25
- error: Error | null;
26
- isLoading: boolean;
27
- isSuccess: boolean;
28
- isError: boolean;
29
- isIdle: boolean;
30
- setData: (data: T | null) => void;
31
- setError: (error: Error | null) => void;
32
- reset: () => void;
33
- }
34
-
35
- export function useAsyncState<T>(
36
- options: UseAsyncStateOptions<T> = {}
37
- ): UseAsyncStateReturn<T> {
38
- const { initialData = null, onSuccess, onError } = options;
39
-
40
- const [state, setState] = useState<AsyncState<T>>({
41
- data: initialData,
42
- status: initialData ? "success" : "idle",
43
- error: null,
44
- });
45
-
46
- const setData = useCallback((data: T | null) => {
47
- setState({ data, status: data ? "success" : "idle", error: null });
48
- if (data) onSuccess?.(data);
49
- }, [onSuccess]);
50
-
51
- const setError = useCallback((error: Error | null) => {
52
- setState((prev) => ({ ...prev, status: "error", error }));
53
- if (error) onError?.(error);
54
- }, [onError]);
55
-
56
- const reset = useCallback(() => {
57
- setState({ data: initialData, status: initialData ? "success" : "idle", error: null });
58
- }, [initialData]);
59
-
60
- return {
61
- data: state.data,
62
- status: state.status,
63
- error: state.error,
64
- isLoading: state.status === "loading",
65
- isSuccess: state.status === "success",
66
- isError: state.status === "error",
67
- isIdle: state.status === "idle",
68
- setData,
69
- setError,
70
- reset,
71
- };
72
- }