@umituz/react-native-subscription 2.39.9 → 2.39.11
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/package.json +1 -1
- package/src/domains/credits/application/CreditLimitCalculator.ts +6 -17
- package/src/domains/credits/core/UserCreditsDocument.ts +1 -1
- package/src/domains/credits/infrastructure/CreditsRepository.ts +3 -3
- package/src/domains/credits/infrastructure/operations/CreditsInitializer.ts +1 -1
- package/src/domains/credits/infrastructure/operations/CreditsWriter.ts +1 -1
- package/src/domains/paywall/components/PaywallFeatures.tsx +1 -1
- package/src/domains/paywall/components/PaywallFooter.tsx +1 -1
- package/src/domains/paywall/components/PaywallScreen.tsx +21 -28
- package/src/domains/paywall/components/PlanCard.tsx +7 -2
- package/src/domains/paywall/components/PlanCard.types.ts +3 -2
- package/src/domains/paywall/utils/paywallLayoutUtils.ts +55 -0
- package/src/domains/revenuecat/core/types/RevenueCatData.ts +1 -1
- package/src/domains/revenuecat/core/types/RevenueCatTypes.ts +2 -2
- package/src/domains/revenuecat/infrastructure/services/RevenueCatInitializer.types.ts +1 -1
- package/src/domains/revenuecat/infrastructure/services/userSwitchHandler.ts +1 -1
- package/src/domains/subscription/application/SubscriptionInitializerTypes.ts +1 -1
- package/src/domains/subscription/application/SubscriptionSyncProcessor.ts +5 -22
- package/src/domains/subscription/application/SubscriptionSyncUtils.ts +1 -1
- package/src/domains/subscription/application/featureGate/featureGateBusinessRules.ts +27 -10
- package/src/domains/subscription/application/initializer/BackgroundInitializer.ts +42 -41
- package/src/domains/subscription/core/SubscriptionEvents.ts +1 -1
- package/src/domains/subscription/core/SubscriptionStatusHandlers.ts +1 -5
- package/src/domains/subscription/infrastructure/handlers/PackageHandler.ts +4 -6
- package/src/domains/subscription/infrastructure/handlers/PurchaseStatusResolver.ts +2 -2
- package/src/domains/subscription/infrastructure/handlers/package-operations/PackageRestorer.ts +1 -1
- package/src/domains/subscription/infrastructure/hooks/usePurchasePackage.ts +1 -1
- package/src/domains/subscription/infrastructure/hooks/useRestorePurchase.ts +1 -1
- package/src/domains/subscription/infrastructure/managers/SubscriptionManager.types.ts +2 -2
- package/src/domains/subscription/infrastructure/managers/initializationHandler.ts +1 -1
- package/src/domains/subscription/infrastructure/services/CustomerInfoListenerManager.ts +1 -1
- package/src/domains/subscription/infrastructure/services/PurchaseHandler.ts +2 -2
- package/src/domains/subscription/infrastructure/services/RestoreHandler.ts +4 -4
- package/src/domains/subscription/infrastructure/services/RevenueCatService.types.ts +1 -1
- package/src/domains/subscription/infrastructure/services/ServiceStateManager.ts +1 -1
- package/src/domains/subscription/infrastructure/services/listeners/CustomerInfoHandler.ts +4 -2
- package/src/domains/subscription/infrastructure/services/listeners/ListenerState.ts +1 -1
- package/src/domains/subscription/infrastructure/services/purchase/PurchaseErrorHandler.ts +3 -3
- package/src/domains/subscription/infrastructure/services/purchase/PurchaseExecutor.ts +2 -1
- package/src/domains/subscription/infrastructure/services/purchase/PurchaseValidator.ts +1 -1
- package/src/domains/subscription/infrastructure/services/revenueCatServiceInstance.ts +1 -1
- package/src/domains/subscription/infrastructure/utils/InitializationCache.ts +35 -42
- package/src/domains/subscription/infrastructure/utils/PremiumStatusSyncer.ts +3 -3
- package/src/domains/subscription/presentation/components/details/PremiumDetailsCardTypes.ts +1 -1
- package/src/domains/subscription/presentation/components/sections/SubscriptionSection.types.ts +1 -1
- package/src/domains/subscription/presentation/screens/SubscriptionDetailScreen.tsx +1 -1
- package/src/domains/subscription/presentation/screens/SubscriptionDetailScreen.types.ts +1 -1
- package/src/domains/subscription/presentation/useSubscriptionStatus.types.ts +1 -1
- package/src/domains/subscription/utils/featureGateUtils.ts +37 -0
- package/src/domains/subscription/utils/packageTypeFormatter.ts +1 -1
- package/src/domains/wallet/infrastructure/repositories/transaction/CollectionBuilder.ts +1 -1
- package/src/domains/wallet/infrastructure/repositories/transaction/TransactionFetcher.ts +2 -1
- package/src/domains/wallet/infrastructure/repositories/transaction/TransactionWriter.ts +2 -1
- package/src/domains/wallet/presentation/screens/WalletScreen.tsx +1 -1
- package/src/index.ts +5 -2
- package/src/init/createSubscriptionInitModule.ts +2 -1
- package/src/domains/revenuecat/core/errors/index.ts +0 -3
- package/src/domains/revenuecat/core/types/index.ts +0 -3
- package/src/domains/subscription/application/initializer/index.ts +0 -2
- package/src/domains/subscription/core/types/index.ts +0 -3
- package/src/domains/subscription/infrastructure/handlers/package-operations/index.ts +0 -4
- package/src/domains/subscription/infrastructure/utils/renewal/index.ts +0 -3
- package/src/shared/infrastructure/firestore/index.ts +0 -2
- package/src/shared/presentation/index.ts +0 -1
|
@@ -13,10 +13,6 @@ abstract class BaseStatusHandler {
|
|
|
13
13
|
}
|
|
14
14
|
|
|
15
15
|
abstract handle(input: StatusResolverInput): SubscriptionStatusType;
|
|
16
|
-
|
|
17
|
-
protected nextOrFallback(input: StatusResolverInput, fallback: SubscriptionStatusType): SubscriptionStatusType {
|
|
18
|
-
return this.next ? this.next.handle(input) : fallback;
|
|
19
|
-
}
|
|
20
16
|
}
|
|
21
17
|
|
|
22
18
|
export class InactiveStatusHandler extends BaseStatusHandler {
|
|
@@ -26,7 +22,7 @@ export class InactiveStatusHandler extends BaseStatusHandler {
|
|
|
26
22
|
if (!input.isPremium || isExpired) {
|
|
27
23
|
return isExpired ? SUBSCRIPTION_STATUS.EXPIRED : SUBSCRIPTION_STATUS.NONE;
|
|
28
24
|
}
|
|
29
|
-
return this.
|
|
25
|
+
return this.next ? this.next.handle(input) : SUBSCRIPTION_STATUS.NONE;
|
|
30
26
|
}
|
|
31
27
|
}
|
|
32
28
|
|
|
@@ -1,12 +1,10 @@
|
|
|
1
1
|
import type { PurchasesPackage, CustomerInfo } from "react-native-purchases";
|
|
2
2
|
import type { IRevenueCatService } from "../../../../shared/application/ports/IRevenueCatService";
|
|
3
3
|
import { PurchaseStatusResolver, type PremiumStatus } from "./PurchaseStatusResolver";
|
|
4
|
-
import {
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
type RestoreResultInfo,
|
|
9
|
-
} from "./package-operations";
|
|
4
|
+
import { fetchPackages } from "./package-operations/PackageFetcher";
|
|
5
|
+
import { executePurchase } from "./package-operations/PackagePurchaser";
|
|
6
|
+
import { restorePurchases } from "./package-operations/PackageRestorer";
|
|
7
|
+
import type { RestoreResultInfo } from "./package-operations/types";
|
|
10
8
|
|
|
11
9
|
export class PackageHandler {
|
|
12
10
|
constructor(
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import type { CustomerInfo } from "react-native-purchases";
|
|
2
|
-
import { getPremiumEntitlement } from "../../../revenuecat/core/types";
|
|
2
|
+
import { getPremiumEntitlement } from "../../../revenuecat/core/types/RevenueCatTypes";
|
|
3
3
|
import { toDate } from "../../../../shared/utils/dateConverter";
|
|
4
4
|
import { detectPackageType } from "../../../../utils/packageTypeDetector";
|
|
5
|
-
import type { PremiumStatus } from "../../core/types";
|
|
5
|
+
import type { PremiumStatus } from "../../core/types/PremiumStatus";
|
|
6
6
|
|
|
7
7
|
export type { PremiumStatus };
|
|
8
8
|
|
package/src/domains/subscription/infrastructure/handlers/package-operations/PackageRestorer.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { IRevenueCatService } from "../../../../../shared/application/ports/IRevenueCatService";
|
|
2
|
-
import { getPremiumEntitlement } from "../../../../revenuecat/core/types";
|
|
2
|
+
import { getPremiumEntitlement } from "../../../../revenuecat/core/types/RevenueCatTypes";
|
|
3
3
|
import type { RestoreResultInfo } from "./types";
|
|
4
4
|
|
|
5
5
|
export async function restorePurchases(
|
|
@@ -9,7 +9,7 @@ import { SubscriptionManager } from "../../infrastructure/managers/SubscriptionM
|
|
|
9
9
|
import { SUBSCRIPTION_QUERY_KEYS } from "./subscriptionQueryKeys";
|
|
10
10
|
import { subscriptionStatusQueryKeys } from "../../presentation/useSubscriptionStatus";
|
|
11
11
|
import { creditsQueryKeys } from "../../../credits/presentation/creditsQueryKeys";
|
|
12
|
-
import { getErrorMessage } from "../../../revenuecat/core/errors";
|
|
12
|
+
import { getErrorMessage } from "../../../revenuecat/core/errors/RevenueCatErrorHandler";
|
|
13
13
|
|
|
14
14
|
interface PurchaseMutationResult {
|
|
15
15
|
success: boolean;
|
|
@@ -8,7 +8,7 @@ import { SubscriptionManager } from "../../infrastructure/managers/SubscriptionM
|
|
|
8
8
|
import { SUBSCRIPTION_QUERY_KEYS } from "./subscriptionQueryKeys";
|
|
9
9
|
import { subscriptionStatusQueryKeys } from "../../presentation/useSubscriptionStatus";
|
|
10
10
|
import { creditsQueryKeys } from "../../../credits/presentation/creditsQueryKeys";
|
|
11
|
-
import { getErrorMessage } from "../../../revenuecat/core/errors";
|
|
11
|
+
import { getErrorMessage } from "../../../revenuecat/core/errors/RevenueCatErrorHandler";
|
|
12
12
|
|
|
13
13
|
interface RestoreResult {
|
|
14
14
|
success: boolean;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import type { RevenueCatConfig } from "../../../revenuecat/core/types";
|
|
2
|
-
import type { PremiumStatus } from "../../core/types";
|
|
1
|
+
import type { RevenueCatConfig } from "../../../revenuecat/core/types/RevenueCatConfig";
|
|
2
|
+
import type { PremiumStatus } from "../../core/types/PremiumStatus";
|
|
3
3
|
import type { RestoreResultInfo } from "../handlers/package-operations/types";
|
|
4
4
|
|
|
5
5
|
export interface SubscriptionManagerConfig {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { IRevenueCatService } from "../../../../shared/application/ports/IRevenueCatService";
|
|
2
2
|
import { initializeRevenueCatService, getRevenueCatService } from "../services/revenueCatServiceInstance";
|
|
3
3
|
import { ensureServiceAvailable } from "./subscriptionManagerUtils";
|
|
4
|
-
import type { RevenueCatConfig } from "../../../revenuecat/core/types";
|
|
4
|
+
import type { RevenueCatConfig } from "../../../revenuecat/core/types/RevenueCatConfig";
|
|
5
5
|
|
|
6
6
|
export const performServiceInitialization = async (config: RevenueCatConfig, userId: string): Promise<{ service: IRevenueCatService; success: boolean }> => {
|
|
7
7
|
await initializeRevenueCatService(config);
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import Purchases, { type CustomerInfo } from "react-native-purchases";
|
|
2
|
-
import type { RevenueCatConfig } from "../../../revenuecat/core/types";
|
|
2
|
+
import type { RevenueCatConfig } from "../../../revenuecat/core/types/RevenueCatConfig";
|
|
3
3
|
import { ListenerState } from "./listeners/ListenerState";
|
|
4
4
|
import { processCustomerInfo } from "./listeners/CustomerInfoHandler";
|
|
5
5
|
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { PurchasesPackage } from "react-native-purchases";
|
|
2
2
|
import type { PurchaseResult } from "../../../../shared/application/ports/IRevenueCatService";
|
|
3
|
-
import type { RevenueCatConfig } from "../../../revenuecat/core/types";
|
|
4
|
-
import { isUserCancelledError, isAlreadyPurchasedError } from "../../../revenuecat/core/types";
|
|
3
|
+
import type { RevenueCatConfig } from "../../../revenuecat/core/types/RevenueCatConfig";
|
|
4
|
+
import { isUserCancelledError, isAlreadyPurchasedError } from "../../../revenuecat/core/types/RevenueCatTypes";
|
|
5
5
|
import { validatePurchaseReady, isConsumableProduct } from "./purchase/PurchaseValidator";
|
|
6
6
|
import { executePurchase } from "./purchase/PurchaseExecutor";
|
|
7
7
|
import { handleAlreadyPurchasedError, handlePurchaseError } from "./purchase/PurchaseErrorHandler";
|
|
@@ -4,14 +4,14 @@ import {
|
|
|
4
4
|
RevenueCatRestoreError,
|
|
5
5
|
RevenueCatInitializationError,
|
|
6
6
|
RevenueCatNetworkError,
|
|
7
|
-
} from "../../../revenuecat/core/errors";
|
|
8
|
-
import type { RevenueCatConfig } from "../../../revenuecat/core/types";
|
|
7
|
+
} from "../../../revenuecat/core/errors/RevenueCatError";
|
|
8
|
+
import type { RevenueCatConfig } from "../../../revenuecat/core/types/RevenueCatConfig";
|
|
9
9
|
import {
|
|
10
10
|
getRawErrorMessage,
|
|
11
11
|
getErrorCode,
|
|
12
12
|
isNetworkError,
|
|
13
13
|
isInvalidCredentialsError,
|
|
14
|
-
} from "../../../revenuecat/core/types";
|
|
14
|
+
} from "../../../revenuecat/core/types/RevenueCatTypes";
|
|
15
15
|
import { notifyRestoreCompleted } from "../utils/PremiumStatusSyncer";
|
|
16
16
|
|
|
17
17
|
interface RestoreHandlerDeps {
|
|
@@ -50,7 +50,7 @@ export async function handleRestore(deps: RestoreHandlerDeps, userId: string): P
|
|
|
50
50
|
|
|
51
51
|
// Generic error with code
|
|
52
52
|
const errorCode = getErrorCode(error);
|
|
53
|
-
const errorMessage = getRawErrorMessage(error
|
|
53
|
+
const errorMessage = getRawErrorMessage(error);
|
|
54
54
|
const enhancedMessage = errorCode
|
|
55
55
|
? `${errorMessage} (Code: ${errorCode})`
|
|
56
56
|
: errorMessage;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import Purchases from "react-native-purchases";
|
|
2
2
|
import type { PurchasesOffering, PurchasesPackage, CustomerInfo } from "react-native-purchases";
|
|
3
3
|
import type { IRevenueCatService, InitializeResult, PurchaseResult, RestoreResult } from "../../../../shared/application/ports/IRevenueCatService";
|
|
4
|
-
import type { RevenueCatConfig } from "../../../revenuecat/core/types";
|
|
4
|
+
import type { RevenueCatConfig } from "../../../revenuecat/core/types/RevenueCatConfig";
|
|
5
5
|
import { initializeSDK } from "../../../revenuecat/infrastructure/services/RevenueCatInitializer";
|
|
6
6
|
import { fetchOfferings } from "./OfferingsFetcher";
|
|
7
7
|
import { handlePurchase } from "./PurchaseHandler";
|
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
import type { CustomerInfo } from "react-native-purchases";
|
|
2
|
-
import type { RevenueCatConfig } from "../../../../revenuecat/core/types";
|
|
2
|
+
import type { RevenueCatConfig } from "../../../../revenuecat/core/types/RevenueCatConfig";
|
|
3
3
|
import { syncPremiumStatus } from "../../utils/PremiumStatusSyncer";
|
|
4
|
-
import { detectRenewal
|
|
4
|
+
import { detectRenewal } from "../../utils/renewal/RenewalDetector";
|
|
5
|
+
import { updateRenewalState } from "../../utils/renewal/RenewalStateUpdater";
|
|
6
|
+
import type { RenewalState } from "../../utils/renewal/types";
|
|
5
7
|
|
|
6
8
|
async function handleRenewal(
|
|
7
9
|
userId: string,
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { CustomerInfoUpdateListener } from "react-native-purchases";
|
|
2
|
-
import type { RenewalState } from "../../utils/renewal";
|
|
2
|
+
import type { RenewalState } from "../../utils/renewal/types";
|
|
3
3
|
|
|
4
4
|
export class ListenerState {
|
|
5
5
|
listener: CustomerInfoUpdateListener | null = null;
|
|
@@ -3,14 +3,14 @@ import type { PurchaseResult } from "../../../../../shared/application/ports/IRe
|
|
|
3
3
|
import {
|
|
4
4
|
RevenueCatPurchaseError,
|
|
5
5
|
RevenueCatNetworkError,
|
|
6
|
-
} from "../../../../revenuecat/core/errors";
|
|
6
|
+
} from "../../../../revenuecat/core/errors/RevenueCatError";
|
|
7
7
|
import {
|
|
8
8
|
isUserCancelledError,
|
|
9
9
|
isNetworkError,
|
|
10
10
|
isInvalidCredentialsError,
|
|
11
11
|
getRawErrorMessage,
|
|
12
12
|
getErrorCode,
|
|
13
|
-
} from "../../../../revenuecat/core/types";
|
|
13
|
+
} from "../../../../revenuecat/core/types/RevenueCatTypes";
|
|
14
14
|
import { getSavedPurchase, clearSavedPurchase } from "../../../presentation/useAuthAwarePurchase";
|
|
15
15
|
import { notifyPurchaseCompleted } from "../../utils/PremiumStatusSyncer";
|
|
16
16
|
import { handleRestore } from "../RestoreHandler";
|
|
@@ -80,7 +80,7 @@ export function handlePurchaseError(
|
|
|
80
80
|
}
|
|
81
81
|
|
|
82
82
|
const errorCode = getErrorCode(error);
|
|
83
|
-
const errorMessage = getRawErrorMessage(error
|
|
83
|
+
const errorMessage = getRawErrorMessage(error);
|
|
84
84
|
const enhancedMessage = errorCode
|
|
85
85
|
? `${errorMessage} (Code: ${errorCode})`
|
|
86
86
|
: errorMessage;
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import Purchases, { type PurchasesPackage, type CustomerInfo } from "react-native-purchases";
|
|
2
2
|
import type { PurchaseResult } from "../../../../../shared/application/ports/IRevenueCatService";
|
|
3
|
-
import type { RevenueCatConfig
|
|
3
|
+
import type { RevenueCatConfig } from "../../../../revenuecat/core/types/RevenueCatConfig";
|
|
4
|
+
import type { PackageType } from "../../../../revenuecat/core/types/RevenueCatTypes";
|
|
4
5
|
import { notifyPurchaseCompleted, syncPremiumStatus } from "../../utils/PremiumStatusSyncer";
|
|
5
6
|
import { getSavedPurchase, clearSavedPurchase } from "../../../presentation/useAuthAwarePurchase";
|
|
6
7
|
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { PurchasesPackage } from "react-native-purchases";
|
|
2
|
-
import { RevenueCatInitializationError } from "../../../../revenuecat/core/errors";
|
|
2
|
+
import { RevenueCatInitializationError } from "../../../../revenuecat/core/errors/RevenueCatError";
|
|
3
3
|
|
|
4
4
|
export function validatePurchaseReady(isInitialized: boolean): void {
|
|
5
5
|
if (!isInitialized) {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { RevenueCatService } from "./RevenueCatService.types";
|
|
2
|
-
import type { RevenueCatConfig } from "../../../revenuecat/core/types";
|
|
2
|
+
import type { RevenueCatConfig } from "../../../revenuecat/core/types/RevenueCatConfig";
|
|
3
3
|
|
|
4
4
|
let revenueCatServiceInstance: RevenueCatService | null = null;
|
|
5
5
|
|
|
@@ -1,71 +1,64 @@
|
|
|
1
|
+
interface CacheEntry {
|
|
2
|
+
promise: Promise<boolean>;
|
|
3
|
+
resolvedUserId: string | null;
|
|
4
|
+
completed: boolean;
|
|
5
|
+
}
|
|
6
|
+
|
|
1
7
|
export class InitializationCache {
|
|
2
|
-
private
|
|
3
|
-
private cacheKey: string | null = null;
|
|
4
|
-
private promiseCacheKey: string | null = null;
|
|
5
|
-
private resolvedUserId: string | null = null;
|
|
6
|
-
private promiseCompleted = true;
|
|
7
|
-
private pendingQueue: Map<string, Promise<boolean>> = new Map();
|
|
8
|
+
private entries: Map<string, CacheEntry> = new Map();
|
|
8
9
|
|
|
9
10
|
tryAcquireInitialization(cacheKey: string): { shouldInit: boolean; existingPromise: Promise<boolean> | null } {
|
|
10
|
-
const
|
|
11
|
-
if (
|
|
12
|
-
return { shouldInit: false, existingPromise:
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
if (
|
|
16
|
-
this.initPromise &&
|
|
17
|
-
this.cacheKey === cacheKey &&
|
|
18
|
-
this.promiseCompleted &&
|
|
19
|
-
this.promiseCacheKey === cacheKey
|
|
20
|
-
) {
|
|
21
|
-
return { shouldInit: false, existingPromise: this.initPromise };
|
|
11
|
+
const entry = this.entries.get(cacheKey);
|
|
12
|
+
if (entry) {
|
|
13
|
+
return { shouldInit: false, existingPromise: entry.promise };
|
|
22
14
|
}
|
|
23
15
|
|
|
24
16
|
return { shouldInit: true, existingPromise: null };
|
|
25
17
|
}
|
|
26
18
|
|
|
27
19
|
setPromise(promise: Promise<boolean>, cacheKey: string, realUserId: string | null): void {
|
|
28
|
-
|
|
29
|
-
|
|
20
|
+
const entry: CacheEntry = {
|
|
21
|
+
promise: null as any, // Placeholder to be assigned immediately
|
|
22
|
+
resolvedUserId: realUserId,
|
|
23
|
+
completed: false,
|
|
24
|
+
};
|
|
30
25
|
|
|
31
26
|
const chain: Promise<boolean> = promise
|
|
32
27
|
.then((result) => {
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
28
|
+
const currentEntry = this.entries.get(cacheKey);
|
|
29
|
+
if (currentEntry === entry) {
|
|
30
|
+
currentEntry.completed = true;
|
|
31
|
+
if (!result) {
|
|
32
|
+
this.entries.delete(cacheKey);
|
|
33
|
+
}
|
|
36
34
|
}
|
|
37
|
-
this.promiseCompleted = true;
|
|
38
35
|
return result;
|
|
39
36
|
})
|
|
40
37
|
.catch((error) => {
|
|
41
|
-
if (this.
|
|
42
|
-
this.
|
|
43
|
-
this.promiseCacheKey = null;
|
|
44
|
-
this.cacheKey = null;
|
|
45
|
-
this.resolvedUserId = null;
|
|
38
|
+
if (this.entries.get(cacheKey) === entry) {
|
|
39
|
+
this.entries.delete(cacheKey);
|
|
46
40
|
}
|
|
47
|
-
this.promiseCompleted = true;
|
|
48
41
|
console.error('[InitializationCache] Initialization failed', { cacheKey, error });
|
|
49
42
|
return false;
|
|
50
|
-
})
|
|
51
|
-
.finally(() => {
|
|
52
|
-
this.pendingQueue.delete(cacheKey);
|
|
53
43
|
});
|
|
54
44
|
|
|
55
|
-
|
|
56
|
-
this.
|
|
45
|
+
entry.promise = chain;
|
|
46
|
+
this.entries.set(cacheKey, entry);
|
|
57
47
|
}
|
|
58
48
|
|
|
59
49
|
getCurrentUserId(): string | null {
|
|
60
|
-
|
|
50
|
+
// Find the first completed entry. This assumes we usually only have one active at a time,
|
|
51
|
+
// but it's much safer than shared state variables.
|
|
52
|
+
// In reality, SubscriptionManager.reset() clears this map on user switch.
|
|
53
|
+
for (const entry of this.entries.values()) {
|
|
54
|
+
if (entry.completed) {
|
|
55
|
+
return entry.resolvedUserId;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
return null;
|
|
61
59
|
}
|
|
62
60
|
|
|
63
61
|
reset(): void {
|
|
64
|
-
this.
|
|
65
|
-
this.cacheKey = null;
|
|
66
|
-
this.promiseCacheKey = null;
|
|
67
|
-
this.resolvedUserId = null;
|
|
68
|
-
this.promiseCompleted = true;
|
|
69
|
-
this.pendingQueue.clear();
|
|
62
|
+
this.entries.clear();
|
|
70
63
|
}
|
|
71
64
|
}
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import type { CustomerInfo } from "react-native-purchases";
|
|
2
|
-
import type { RevenueCatConfig } from "../../../revenuecat/core/types";
|
|
2
|
+
import type { RevenueCatConfig } from "../../../revenuecat/core/types/RevenueCatConfig";
|
|
3
3
|
import type { PurchaseSource } from "../../core/SubscriptionConstants";
|
|
4
|
-
import type { PackageType } from "../../../revenuecat/core/types";
|
|
5
|
-
import { getPremiumEntitlement } from "../../../revenuecat/core/types";
|
|
4
|
+
import type { PackageType } from "../../../revenuecat/core/types/RevenueCatTypes";
|
|
5
|
+
import { getPremiumEntitlement } from "../../../revenuecat/core/types/RevenueCatTypes";
|
|
6
6
|
|
|
7
7
|
export async function syncPremiumStatus(
|
|
8
8
|
config: RevenueCatConfig,
|
package/src/domains/subscription/presentation/components/sections/SubscriptionSection.types.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { StyleProp, ViewStyle } from "react-native";
|
|
2
2
|
import type { SubscriptionStatusType } from "../../../core/SubscriptionConstants";
|
|
3
|
-
import type { CreditInfo } from "../../../core/types";
|
|
3
|
+
import type { CreditInfo } from "../../../core/types/CreditInfo";
|
|
4
4
|
import type { PremiumDetailsTranslations } from "../details/PremiumDetailsCardTypes";
|
|
5
5
|
|
|
6
6
|
export interface SubscriptionSectionConfig {
|
|
@@ -5,7 +5,7 @@ import { AtomicIcon, AtomicText } from "@umituz/react-native-design-system/atoms
|
|
|
5
5
|
import { NavigationHeader } from "@umituz/react-native-design-system/molecules";
|
|
6
6
|
import { useAppDesignTokens } from "@umituz/react-native-design-system/theme";
|
|
7
7
|
import { useAuthStore, selectUserId } from "@umituz/react-native-auth";
|
|
8
|
-
import { ScreenLayout } from "../../../../shared/presentation";
|
|
8
|
+
import { ScreenLayout } from "../../../../shared/presentation/layouts/ScreenLayout";
|
|
9
9
|
import { getCreditsRepository } from "../../../credits/infrastructure/CreditsRepositoryManager";
|
|
10
10
|
import { subscriptionEventBus, SUBSCRIPTION_EVENTS } from "../../../../shared/infrastructure/SubscriptionEventBus";
|
|
11
11
|
import { SubscriptionHeader } from "./components/SubscriptionHeader";
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
export const DEFAULT_REQUIRED_CREDITS = 1;
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Checks if an action that requires auth-based credits can be executed.
|
|
5
|
+
*/
|
|
6
|
+
export function canExecuteAuthAction(
|
|
7
|
+
isWaitingForAuthCredits: boolean,
|
|
8
|
+
isCreditsLoaded: boolean,
|
|
9
|
+
hasPendingAction: boolean,
|
|
10
|
+
hasSubscription: boolean,
|
|
11
|
+
creditBalance: number,
|
|
12
|
+
requiredCredits: number
|
|
13
|
+
): boolean {
|
|
14
|
+
if (!isWaitingForAuthCredits || !isCreditsLoaded || !hasPendingAction) {
|
|
15
|
+
return false;
|
|
16
|
+
}
|
|
17
|
+
return hasSubscription || creditBalance >= requiredCredits;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Checks if a purchase action can be executed, typically after a purchase flow.
|
|
22
|
+
*/
|
|
23
|
+
export function canExecutePurchaseAction(
|
|
24
|
+
isWaitingForPurchase: boolean,
|
|
25
|
+
creditBalance: number,
|
|
26
|
+
prevBalance: number,
|
|
27
|
+
hasSubscription: boolean,
|
|
28
|
+
prevHasSubscription: boolean,
|
|
29
|
+
hasPendingAction: boolean
|
|
30
|
+
): boolean {
|
|
31
|
+
if (!isWaitingForPurchase || !hasPendingAction) {
|
|
32
|
+
return false;
|
|
33
|
+
}
|
|
34
|
+
const creditsIncreased = creditBalance > prevBalance;
|
|
35
|
+
const subscriptionAcquired = hasSubscription && !prevHasSubscription;
|
|
36
|
+
return creditsIncreased || subscriptionAcquired;
|
|
37
|
+
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { PackageType } from "../../revenuecat/core/types";
|
|
1
|
+
import type { PackageType } from "../../revenuecat/core/types/RevenueCatTypes";
|
|
2
2
|
|
|
3
3
|
export function formatPackageTypeForDisplay(packageType: PackageType | string | null | undefined): string {
|
|
4
4
|
if (!packageType) {
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { buildCollectionRef, type CollectionConfig } from "../../../../../shared/infrastructure/firestore";
|
|
1
|
+
import { buildCollectionRef, type CollectionConfig } from "../../../../../shared/infrastructure/firestore/collectionUtils";
|
|
2
2
|
import type { Firestore } from "@umituz/react-native-firebase";
|
|
3
3
|
import type { TransactionRepositoryConfig } from "../../../domain/types/transaction.types";
|
|
4
4
|
|
|
@@ -13,7 +13,8 @@ import type {
|
|
|
13
13
|
TransactionResult,
|
|
14
14
|
} from "../../../domain/types/transaction.types";
|
|
15
15
|
import { TransactionMapper } from "../../../domain/mappers/TransactionMapper";
|
|
16
|
-
import { requireFirestore
|
|
16
|
+
import { requireFirestore } from "../../../../../shared/infrastructure/firestore/collectionUtils";
|
|
17
|
+
import { mapErrorToResult } from "../../../../../shared/infrastructure/firestore/resultUtils";
|
|
17
18
|
import { getCollectionRef } from "./CollectionBuilder";
|
|
18
19
|
|
|
19
20
|
export async function fetchTransactions(
|
|
@@ -7,7 +7,8 @@ import type {
|
|
|
7
7
|
TransactionReason,
|
|
8
8
|
} from "../../../domain/types/transaction.types";
|
|
9
9
|
import { TransactionMapper } from "../../../domain/mappers/TransactionMapper";
|
|
10
|
-
import { requireFirestore
|
|
10
|
+
import { requireFirestore } from "../../../../../shared/infrastructure/firestore/collectionUtils";
|
|
11
|
+
import { mapErrorToResult } from "../../../../../shared/infrastructure/firestore/resultUtils";
|
|
11
12
|
import { getCollectionRef } from "./CollectionBuilder";
|
|
12
13
|
|
|
13
14
|
export async function addTransaction(
|
|
@@ -2,7 +2,7 @@ import React from "react";
|
|
|
2
2
|
import { View, StyleSheet, TouchableOpacity } from "react-native";
|
|
3
3
|
import { AtomicText, AtomicIcon, AtomicSpinner } from "@umituz/react-native-design-system/atoms";
|
|
4
4
|
import { useAppDesignTokens } from "@umituz/react-native-design-system/theme";
|
|
5
|
-
import { ScreenLayout } from "../../../../shared/presentation";
|
|
5
|
+
import { ScreenLayout } from "../../../../shared/presentation/layouts/ScreenLayout";
|
|
6
6
|
import { useNavigation } from "@react-navigation/native";
|
|
7
7
|
import { useWallet } from "../hooks/useWallet";
|
|
8
8
|
import { getWalletConfig } from "../../infrastructure/config/walletConfig";
|
package/src/index.ts
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
// Domain Layer - Constants & Types
|
|
2
2
|
export * from "./domains/subscription/core/SubscriptionConstants";
|
|
3
|
-
export type { SubscriptionMetadata
|
|
3
|
+
export type { SubscriptionMetadata } from "./domains/subscription/core/types/SubscriptionMetadata";
|
|
4
|
+
export type { PremiumStatus } from "./domains/subscription/core/types/PremiumStatus";
|
|
5
|
+
export type { CreditInfo } from "./domains/subscription/core/types/CreditInfo";
|
|
4
6
|
export {
|
|
5
7
|
createDefaultSubscriptionStatus,
|
|
6
8
|
isSubscriptionValid,
|
|
@@ -25,7 +27,8 @@ export {
|
|
|
25
27
|
export type { Result, Success, Failure } from "./shared/utils/Result";
|
|
26
28
|
|
|
27
29
|
// Infrastructure Layer (Services & Repositories)
|
|
28
|
-
export { initializeSubscription
|
|
30
|
+
export { initializeSubscription } from "./domains/subscription/application/initializer/SubscriptionInitializer";
|
|
31
|
+
export type { SubscriptionInitConfig, CreditPackageConfig } from "./domains/subscription/application/SubscriptionInitializerTypes";
|
|
29
32
|
|
|
30
33
|
export { CreditsRepository } from "./domains/credits/infrastructure/CreditsRepository";
|
|
31
34
|
export {
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { InitModule } from '@umituz/react-native-design-system/init';
|
|
2
|
-
import { initializeSubscription
|
|
2
|
+
import { initializeSubscription } from "../domains/subscription/application/initializer/SubscriptionInitializer";
|
|
3
|
+
import type { SubscriptionInitConfig } from "../domains/subscription/application/SubscriptionInitializerTypes";
|
|
3
4
|
|
|
4
5
|
export interface SubscriptionInitModuleConfig extends Omit<SubscriptionInitConfig, 'apiKey'> {
|
|
5
6
|
getApiKey: () => string | undefined;
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export * from "./layouts/ScreenLayout";
|