@umituz/react-native-subscription 2.37.13 → 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.
- package/package.json +1 -1
- package/src/domains/credits/application/PurchaseMetadataGenerator.ts +1 -1
- package/src/domains/credits/application/credit-strategies/CreditAllocationOrchestrator.ts +1 -1
- package/src/domains/credits/application/creditDocumentHelpers.ts +0 -14
- package/src/domains/credits/presentation/deduct-credit/index.ts +0 -1
- package/src/domains/credits/presentation/useCredits.ts +1 -6
- package/src/domains/credits/utils/creditValidation.ts +3 -3
- package/src/domains/paywall/components/PaywallFeatures.tsx +1 -1
- package/src/domains/paywall/hooks/usePaywallActions.ts +1 -1
- package/src/domains/revenuecat/core/errors/RevenueCatError.ts +1 -14
- package/src/domains/revenuecat/core/errors/RevenueCatErrorHandler.ts +1 -1
- package/src/domains/revenuecat/core/types/RevenueCatTypes.ts +3 -3
- package/src/domains/revenuecat/infrastructure/services/ConfigurationStateManager.ts +1 -1
- package/src/domains/revenuecat/infrastructure/services/RevenueCatInitializer.ts +0 -2
- package/src/domains/subscription/application/initializer/index.ts +1 -1
- package/src/domains/subscription/core/SubscriptionStatus.ts +4 -10
- package/src/domains/subscription/core/SubscriptionStatusHandlers.ts +1 -1
- package/src/domains/subscription/infrastructure/handlers/PackageHandler.ts +0 -2
- package/src/domains/subscription/infrastructure/hooks/usePurchasePackage.ts +1 -1
- package/src/domains/subscription/infrastructure/hooks/useRevenueCatTrialEligibility.ts +1 -2
- package/src/domains/subscription/infrastructure/hooks/useSubscriptionQueries.ts +0 -4
- package/src/domains/subscription/infrastructure/services/OfferingsFetcher.ts +1 -1
- package/src/domains/subscription/infrastructure/services/RestoreHandler.ts +1 -1
- package/src/domains/subscription/infrastructure/services/RevenueCatService.ts +1 -2
- package/src/domains/subscription/infrastructure/services/revenueCatServiceInstance.ts +0 -4
- package/src/domains/subscription/infrastructure/utils/renewal/index.ts +1 -1
- package/src/domains/subscription/presentation/components/details/CreditRow.tsx +1 -1
- package/src/domains/subscription/presentation/components/details/DetailRow.tsx +1 -1
- package/src/domains/subscription/presentation/components/feedback/FeedbackOption.tsx +0 -2
- package/src/domains/subscription/presentation/components/feedback/FeedbackTextInput.tsx +1 -1
- package/src/domains/subscription/presentation/featureGateRefs.ts +1 -1
- package/src/domains/subscription/presentation/screens/components/CreditsList.tsx +2 -2
- package/src/domains/subscription/presentation/screens/components/SubscriptionHeader.tsx +0 -2
- package/src/domains/subscription/presentation/stores/index.ts +0 -5
- package/src/domains/subscription/presentation/stores/purchaseLoadingStore.ts +3 -7
- package/src/domains/subscription/presentation/useAuthAwarePurchase.ts +2 -8
- package/src/domains/subscription/presentation/useFeatureGate.ts +0 -2
- package/src/domains/subscription/presentation/usePaywallVisibility.ts +1 -1
- package/src/domains/subscription/utils/authGuards.ts +0 -23
- package/src/domains/subscription/utils/syncStatus.ts +1 -1
- package/src/domains/wallet/index.ts +0 -112
- package/src/domains/wallet/infrastructure/config/walletConfig.ts +1 -23
- package/src/domains/wallet/infrastructure/repositories/transaction/CollectionBuilder.ts +1 -1
- package/src/domains/wallet/infrastructure/repositories/transaction/index.ts +0 -9
- package/src/domains/wallet/presentation/components/BalanceCard.tsx +1 -1
- package/src/domains/wallet/presentation/components/TransactionItem.tsx +0 -2
- package/src/domains/wallet/presentation/components/TransactionList.tsx +3 -2
- package/src/domains/wallet/presentation/hooks/useTransactionHistory.ts +2 -2
- package/src/domains/wallet/presentation/hooks/useWallet.ts +2 -2
- package/src/shared/application/FeedbackService.ts +2 -2
- package/src/shared/infrastructure/SubscriptionEventBus.ts +1 -1
- package/src/shared/infrastructure/firestore/collectionUtils.ts +0 -7
- package/src/shared/infrastructure/firestore/resultUtils.ts +3 -39
- package/src/shared/presentation/layouts/ScreenLayout.tsx +1 -1
- package/src/shared/utils/numberUtils.core.ts +0 -27
- package/src/shared/utils/numberUtils.ts +1 -9
- package/src/shared/utils/validators.ts +0 -58
- package/src/domains/config/domain/entities/Plan.ts +0 -44
- package/src/domains/config/domain/index.ts +0 -2
- package/src/domains/config/domain/value-objects/Config.ts +0 -49
- package/src/domains/config/index.ts +0 -6
- package/src/domains/config/utils/planSelectors.ts +0 -56
- package/src/domains/paywall/components/FeatureItem.tsx +0 -50
- package/src/domains/paywall/components/FeatureList.tsx +0 -34
- package/src/domains/paywall/components/PaywallHeader.tsx +0 -112
- package/src/domains/paywall/hooks/usePaywallTranslations.ts +0 -78
- package/src/domains/paywall/hooks/useSubscriptionModal.ts +0 -45
- package/src/domains/paywall/index.ts +0 -13
- package/src/domains/revenuecat/core/constants/RevenueCatConstants.ts +0 -201
- package/src/domains/revenuecat/core/constants/index.ts +0 -5
- package/src/domains/revenuecat/core/customerInfoHelpers.ts +0 -21
- package/src/domains/revenuecat/core/index.ts +0 -7
- package/src/domains/revenuecat/index.ts +0 -7
- package/src/domains/revenuecat/infrastructure/index.ts +0 -5
- package/src/domains/revenuecat/infrastructure/services/index.ts +0 -7
- package/src/domains/subscription/infrastructure/hooks/customer-info/index.ts +0 -2
- package/src/domains/subscription/infrastructure/hooks/customer-info/types.ts +0 -9
- package/src/domains/subscription/infrastructure/hooks/customer-info/useCustomerInfo.ts +0 -52
- package/src/domains/subscription/infrastructure/hooks/useInitializeSubscription.ts +0 -30
- package/src/domains/subscription/infrastructure/hooks/usePaywallFlow.ts +0 -78
- package/src/domains/subscription/infrastructure/hooks/useRevenueCat.ts +0 -119
- package/src/domains/subscription/presentation/components/feedback/FeedbackConstants.ts +0 -6
- package/src/domains/subscription/presentation/screens/components/SubscriptionActions.tsx +0 -56
- package/src/domains/subscription/utils/dateFormatters.ts +0 -28
- package/src/domains/wallet/domain/entities/CreditCost.ts +0 -45
- package/src/domains/wallet/domain/entities/README.md +0 -41
- package/src/domains/wallet/domain/errors/README.md +0 -40
- package/src/domains/wallet/domain/errors/WalletError.ts +0 -17
- package/src/domains/wallet/domain/errors/WalletError.types.ts +0 -30
- package/src/domains/wallet/domain/errors/WalletErrorClasses.ts +0 -82
- package/src/domains/wallet/domain/errors/WalletErrorFactory.ts +0 -24
- package/src/domains/wallet/domain/errors/WalletErrorMessages.ts +0 -17
- package/src/domains/wallet/domain/types/credit-cost.types.ts +0 -86
- package/src/domains/wallet/domain/types/index.ts +0 -33
- package/src/domains/wallet/domain/types/wallet.types.ts +0 -50
- package/src/domains/wallet/infrastructure/services/product-metadata/CacheManager.ts +0 -30
- package/src/domains/wallet/infrastructure/services/product-metadata/FirebaseFetcher.ts +0 -17
- package/src/domains/wallet/infrastructure/services/product-metadata/ProductMetadataService.ts +0 -57
- package/src/domains/wallet/infrastructure/services/product-metadata/ServiceManager.ts +0 -29
- package/src/domains/wallet/infrastructure/services/product-metadata/index.ts +0 -7
- package/src/domains/wallet/presentation/hooks/index.ts +0 -8
- package/src/domains/wallet/presentation/hooks/useProductMetadata.ts +0 -72
- package/src/domains/wallet/utils/index.ts +0 -1
- package/src/shared/application/ActivationHandler.ts +0 -108
- package/src/shared/application/ports/ISubscriptionService.ts +0 -27
- package/src/shared/infrastructure/index.ts +0 -6
- package/src/shared/infrastructure/react-query/queryInvalidation.ts +0 -46
- package/src/shared/presentation/hooks/index.ts +0 -6
- package/src/shared/presentation/hooks/useAsyncState.ts +0 -72
- package/src/shared/presentation/hooks/useServiceCall.ts +0 -77
- package/src/shared/types/ReactTypes.ts +0 -80
- package/src/shared/utils/InsufficientCreditsError.ts +0 -32
- package/src/shared/utils/Logger.ts +0 -81
- package/src/shared/utils/SubscriptionConfig.ts +0 -15
- package/src/shared/utils/SubscriptionError.ts +0 -47
- package/src/shared/utils/appValidators.ts +0 -38
- package/src/shared/utils/arrayUtils.core.ts +0 -81
- package/src/shared/utils/arrayUtils.query.ts +0 -118
- package/src/shared/utils/arrayUtils.transforms.ts +0 -116
- package/src/shared/utils/arrayUtils.ts +0 -19
- package/src/shared/utils/errorUtils.ts +0 -32
- package/src/shared/utils/index.ts +0 -14
- package/src/shared/utils/numberUtils.aggregate.ts +0 -35
- package/src/shared/utils/numberUtils.format.ts +0 -42
- package/src/shared/utils/numberUtils.math.ts +0 -48
- package/src/shared/utils/queryKeyFactory.ts +0 -9
- package/src/shared/utils/stringUtils.case.ts +0 -64
- package/src/shared/utils/stringUtils.check.ts +0 -65
- package/src/shared/utils/stringUtils.format.ts +0 -84
- package/src/shared/utils/stringUtils.generate.ts +0 -47
- package/src/shared/utils/stringUtils.modify.ts +0 -67
- 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
|
-
}
|
package/src/domains/wallet/infrastructure/services/product-metadata/ProductMetadataService.ts
DELETED
|
@@ -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,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,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,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
|
-
}
|