@umituz/react-native-subscription 2.37.38 → 2.37.40
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 +1 -9
- package/src/domains/credits/application/CreditsInitializer.ts +5 -20
- package/src/domains/credits/application/DeductCreditsCommand.ts +13 -6
- package/src/domains/credits/application/RefundCreditsCommand.ts +1 -5
- package/src/domains/credits/application/credit-strategies/CreditAllocationOrchestrator.ts +1 -9
- package/src/domains/credits/application/credit-strategies/ICreditStrategy.ts +1 -5
- package/src/domains/credits/application/credit-strategies/TrialCreditStrategy.ts +1 -5
- package/src/domains/credits/application/creditDocumentHelpers.ts +2 -9
- package/src/domains/credits/application/creditOperationUtils.ts +1 -43
- package/src/domains/credits/core/Credits.ts +0 -23
- package/src/domains/credits/core/CreditsConstants.ts +0 -11
- package/src/domains/credits/core/CreditsMapper.ts +0 -6
- package/src/domains/credits/core/UserCreditsDocument.ts +0 -12
- package/src/domains/credits/infrastructure/CreditsRepository.ts +6 -1
- package/src/domains/credits/infrastructure/CreditsRepositoryManager.ts +0 -21
- package/src/domains/credits/infrastructure/operations/CreditsWriter.ts +52 -1
- package/src/domains/credits/presentation/deduct-credit/useDeductCredit.ts +2 -2
- package/src/domains/credits/presentation/useCredits.ts +10 -9
- package/src/domains/paywall/components/PaywallContainer.types.ts +0 -28
- package/src/domains/paywall/components/PaywallModal.styles.ts +0 -4
- package/src/domains/paywall/entities/types.ts +0 -5
- package/src/domains/paywall/hooks/usePaywallActions.ts +1 -15
- package/src/domains/revenuecat/core/errors/RevenueCatError.ts +0 -6
- package/src/domains/revenuecat/core/errors/RevenueCatErrorHandler.ts +0 -24
- package/src/domains/revenuecat/core/errors/RevenueCatErrorMessages.ts +0 -18
- package/src/domains/revenuecat/core/errors/index.ts +0 -4
- package/src/domains/revenuecat/core/types/RevenueCatConfig.ts +3 -7
- package/src/domains/revenuecat/core/types/RevenueCatData.ts +4 -9
- package/src/domains/revenuecat/core/types/RevenueCatTypes.ts +5 -65
- package/src/domains/revenuecat/core/types/index.ts +0 -4
- package/src/domains/revenuecat/infrastructure/services/UserSwitchMutex.ts +1 -24
- package/src/domains/subscription/application/SubscriptionAuthListener.ts +5 -21
- package/src/domains/subscription/application/SubscriptionInitializerTypes.ts +1 -5
- package/src/domains/subscription/application/SubscriptionSyncProcessor.ts +0 -4
- package/src/domains/subscription/application/SubscriptionSyncService.ts +4 -8
- package/src/domains/subscription/application/SubscriptionSyncUtils.ts +1 -1
- package/src/domains/subscription/application/initializer/BackgroundInitializer.ts +15 -2
- package/src/domains/subscription/application/initializer/ServiceConfigurator.ts +9 -2
- package/src/domains/subscription/application/statusChangeHandlers.ts +14 -27
- package/src/domains/subscription/application/syncIdGenerators.ts +0 -4
- package/src/domains/subscription/constants/thresholds.ts +0 -9
- package/src/domains/subscription/core/SubscriptionConstants.ts +0 -4
- package/src/domains/subscription/core/SubscriptionStatus.ts +11 -21
- package/src/domains/subscription/core/SubscriptionStatusHandlers.ts +4 -7
- package/src/domains/subscription/infrastructure/handlers/PurchaseStatusResolver.ts +1 -1
- package/src/domains/subscription/infrastructure/hooks/subscriptionQueryKeys.ts +0 -13
- package/src/domains/subscription/infrastructure/hooks/usePurchasePackage.ts +0 -18
- package/src/domains/subscription/infrastructure/hooks/useRestorePurchase.ts +3 -17
- package/src/domains/subscription/infrastructure/hooks/useRevenueCatTrialEligibility.ts +0 -17
- package/src/domains/subscription/infrastructure/hooks/useSubscriptionPackages.ts +0 -19
- package/src/domains/subscription/infrastructure/hooks/useSubscriptionQueries.ts +0 -6
- package/src/domains/subscription/infrastructure/managers/subscriptionManagerUtils.ts +0 -17
- package/src/domains/subscription/infrastructure/state/initializationState.ts +0 -25
- package/src/domains/subscription/infrastructure/utils/InitializationCache.ts +0 -21
- package/src/domains/subscription/infrastructure/utils/PremiumStatusSyncer.ts +3 -17
- package/src/domains/subscription/infrastructure/utils/authPurchaseState.ts +0 -5
- package/src/domains/subscription/infrastructure/utils/renewal/PackageTierComparator.ts +1 -0
- package/src/domains/subscription/infrastructure/utils/trialEligibilityUtils.ts +0 -18
- package/src/domains/subscription/presentation/components/details/PremiumDetailsCard.styles.ts +0 -5
- package/src/domains/subscription/presentation/components/details/PremiumDetailsCardTypes.ts +0 -5
- package/src/domains/subscription/presentation/components/feedback/paywallFeedbackStyles.ts +0 -5
- package/src/domains/subscription/presentation/stores/index.ts +0 -4
- package/src/domains/subscription/presentation/stores/purchaseLoadingStore.ts +0 -13
- package/src/domains/subscription/presentation/useAuthAwarePurchase.ts +30 -21
- package/src/domains/subscription/presentation/usePaywallVisibility.ts +0 -9
- package/src/domains/subscription/presentation/useSubscriptionStatus.ts +8 -11
- package/src/domains/subscription/utils/authGuards.ts +3 -0
- package/src/domains/trial/application/TrialService.ts +0 -9
- package/src/domains/trial/core/TrialTypes.ts +0 -8
- package/src/domains/wallet/domain/mappers/TransactionMapper.ts +0 -5
- package/src/domains/wallet/domain/types/transaction.types.ts +0 -7
- package/src/domains/wallet/index.ts +0 -7
- package/src/domains/wallet/infrastructure/config/walletConfig.ts +0 -11
- package/src/domains/wallet/presentation/hooks/useTransactionHistory.ts +6 -3
- package/src/domains/wallet/presentation/hooks/useWallet.ts +0 -7
- package/src/domains/wallet/utils/transactionIconMap.ts +0 -10
- package/src/global.d.ts +0 -6
- package/src/index.ts +1 -4
- package/src/init/createSubscriptionInitModule.ts +12 -2
- package/src/init/index.ts +1 -5
- package/src/presentation/hooks/feedback/useFeedbackSubmit.ts +0 -11
- package/src/shared/application/FeedbackService.ts +3 -21
- package/src/shared/application/ports/ISubscriptionRepository.ts +0 -4
- package/src/shared/infrastructure/SubscriptionEventBus.ts +0 -13
- package/src/shared/infrastructure/firestore/collectionUtils.ts +1 -17
- package/src/shared/infrastructure/firestore/index.ts +0 -4
- package/src/shared/infrastructure/firestore/resultUtils.ts +0 -12
- package/src/shared/infrastructure/react-query/hooks/usePreviousUserCleanup.ts +0 -17
- package/src/shared/infrastructure/react-query/queryConfig.ts +0 -15
- package/src/shared/utils/BaseError.ts +0 -5
- package/src/shared/utils/Result.ts +0 -20
- package/src/shared/utils/dateConverter.ts +6 -46
- package/src/utils/appUtils.ts +0 -16
- package/src/utils/creditMapper.ts +0 -7
- package/src/utils/dateUtils.compare.ts +0 -24
- package/src/utils/dateUtils.core.ts +0 -39
- package/src/utils/dateUtils.format.ts +0 -41
- package/src/utils/dateUtils.math.ts +0 -41
- package/src/utils/dateUtils.ts +0 -5
- package/src/utils/packagePeriodUtils.ts +0 -20
- package/src/utils/packageTypeDetector.ts +1 -21
- package/src/utils/premiumStatusUtils.ts +1 -14
- package/src/utils/priceUtils.ts +0 -35
- package/src/utils/tierUtils.ts +1 -8
- package/src/utils/types.ts +1 -25
- package/src/utils/validation.ts +1 -7
- package/src/domains/README.md +0 -52
- package/src/domains/config/domain/README.md +0 -37
- package/src/domains/config/domain/entities/README.md +0 -41
- package/src/domains/credits/application/credit-strategies/SyncCreditStrategy.ts +0 -24
- package/src/domains/paywall/README.md +0 -101
- package/src/domains/paywall/entities/README.md +0 -40
- package/src/domains/paywall/hooks/README.md +0 -41
- package/src/domains/subscription/application/syncConstants.ts +0 -1
- package/src/domains/subscription/infrastructure/README.md +0 -41
- package/src/domains/subscription/infrastructure/config/README.md +0 -49
- package/src/domains/subscription/infrastructure/handlers/README.md +0 -41
- package/src/domains/subscription/infrastructure/hooks/README.md +0 -50
- package/src/domains/subscription/infrastructure/managers/README.md +0 -41
- package/src/domains/subscription/infrastructure/services/README.md +0 -42
- package/src/domains/subscription/infrastructure/utils/README.md +0 -41
- package/src/domains/subscription/presentation/components/README.md +0 -155
- package/src/domains/subscription/presentation/components/details/CreditRow.md +0 -92
- package/src/domains/subscription/presentation/components/details/DetailRow.md +0 -91
- package/src/domains/subscription/presentation/components/details/PremiumDetailsCard.md +0 -93
- package/src/domains/subscription/presentation/components/details/PremiumStatusBadge.md +0 -91
- package/src/domains/subscription/presentation/components/details/README.md +0 -99
- package/src/domains/subscription/presentation/components/feedback/PaywallFeedbackModal.md +0 -90
- package/src/domains/subscription/presentation/components/feedback/README.md +0 -99
- package/src/domains/subscription/presentation/components/paywall/PaywallModal.md +0 -94
- package/src/domains/subscription/presentation/components/paywall/README.md +0 -54
- package/src/domains/subscription/presentation/components/sections/README.md +0 -99
- package/src/domains/subscription/presentation/components/sections/SubscriptionSection.md +0 -94
- package/src/domains/subscription/presentation/utils/README.md +0 -31
- package/src/domains/wallet/README.md +0 -51
- package/src/domains/wallet/domain/README.md +0 -41
- package/src/domains/wallet/infrastructure/README.md +0 -41
- package/src/domains/wallet/presentation/components/README.md +0 -41
- package/src/domains/wallet/presentation/hooks/README.md +0 -41
- package/src/shared/application/ports/README.md +0 -48
|
@@ -1,11 +1,5 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Feedback Service
|
|
3
|
-
* Handles feedback submission to Firestore
|
|
4
|
-
* Feedback is stored under users/{userId}/feedback/{feedbackId}
|
|
5
|
-
*/
|
|
6
|
-
|
|
7
1
|
import { collection, addDoc, doc } from "firebase/firestore";
|
|
8
|
-
import { getFirestore } from "@umituz/react-native-firebase";
|
|
2
|
+
import { getFirestore, serverTimestamp } from "@umituz/react-native-firebase";
|
|
9
3
|
|
|
10
4
|
interface FeedbackData {
|
|
11
5
|
userId: string | null;
|
|
@@ -22,10 +16,6 @@ export interface FeedbackSubmitResult {
|
|
|
22
16
|
error?: Error;
|
|
23
17
|
}
|
|
24
18
|
|
|
25
|
-
/**
|
|
26
|
-
* Submit feedback to Firestore
|
|
27
|
-
* Stores under users/{userId}/feedback
|
|
28
|
-
*/
|
|
29
19
|
async function submitFeedback(
|
|
30
20
|
data: FeedbackData
|
|
31
21
|
): Promise<FeedbackSubmitResult> {
|
|
@@ -40,8 +30,6 @@ async function submitFeedback(
|
|
|
40
30
|
}
|
|
41
31
|
|
|
42
32
|
try {
|
|
43
|
-
const now = new Date().toISOString();
|
|
44
|
-
|
|
45
33
|
const userDocRef = doc(db, "users", data.userId);
|
|
46
34
|
const feedbackCollectionRef = collection(userDocRef, "feedback");
|
|
47
35
|
|
|
@@ -52,8 +40,8 @@ async function submitFeedback(
|
|
|
52
40
|
description: data.description,
|
|
53
41
|
rating: data.rating ?? null,
|
|
54
42
|
status: data.status ?? "pending",
|
|
55
|
-
createdAt:
|
|
56
|
-
updatedAt:
|
|
43
|
+
createdAt: serverTimestamp(),
|
|
44
|
+
updatedAt: serverTimestamp(),
|
|
57
45
|
});
|
|
58
46
|
|
|
59
47
|
return { success: true };
|
|
@@ -65,9 +53,6 @@ async function submitFeedback(
|
|
|
65
53
|
}
|
|
66
54
|
}
|
|
67
55
|
|
|
68
|
-
/**
|
|
69
|
-
* Submit paywall decline feedback
|
|
70
|
-
*/
|
|
71
56
|
export async function submitPaywallFeedback(
|
|
72
57
|
userId: string | null,
|
|
73
58
|
userEmail: string | null,
|
|
@@ -82,9 +67,6 @@ export async function submitPaywallFeedback(
|
|
|
82
67
|
});
|
|
83
68
|
}
|
|
84
69
|
|
|
85
|
-
/**
|
|
86
|
-
* Submit general settings feedback
|
|
87
|
-
*/
|
|
88
70
|
export async function submitSettingsFeedback(
|
|
89
71
|
userId: string | null,
|
|
90
72
|
userEmail: string | null,
|
|
@@ -1,9 +1,5 @@
|
|
|
1
1
|
type EventCallback<T = unknown> = (data: T) => void;
|
|
2
2
|
|
|
3
|
-
/**
|
|
4
|
-
* Simple EventBus Implementation
|
|
5
|
-
* Used to decouple services and provide an observer pattern for subscription events.
|
|
6
|
-
*/
|
|
7
3
|
class SubscriptionEventBus {
|
|
8
4
|
private static instance: SubscriptionEventBus;
|
|
9
5
|
private listeners: Record<string, EventCallback<any>[]> = {};
|
|
@@ -23,13 +19,11 @@ class SubscriptionEventBus {
|
|
|
23
19
|
}
|
|
24
20
|
this.listeners[event].push(callback);
|
|
25
21
|
|
|
26
|
-
// Return unsubscribe function
|
|
27
22
|
return () => {
|
|
28
23
|
const listeners = this.listeners[event];
|
|
29
24
|
if (listeners) {
|
|
30
25
|
this.listeners[event] = listeners.filter(l => l !== callback);
|
|
31
26
|
|
|
32
|
-
// Clean up empty event arrays to prevent memory leak
|
|
33
27
|
if (this.listeners[event].length === 0) {
|
|
34
28
|
delete this.listeners[event];
|
|
35
29
|
}
|
|
@@ -53,10 +47,6 @@ class SubscriptionEventBus {
|
|
|
53
47
|
});
|
|
54
48
|
}
|
|
55
49
|
|
|
56
|
-
/**
|
|
57
|
-
* Clear all listeners for a specific event or all events
|
|
58
|
-
* Useful for cleanup during testing or app state reset
|
|
59
|
-
*/
|
|
60
50
|
clear(event?: string): void {
|
|
61
51
|
if (event) {
|
|
62
52
|
delete this.listeners[event];
|
|
@@ -65,9 +55,6 @@ class SubscriptionEventBus {
|
|
|
65
55
|
}
|
|
66
56
|
}
|
|
67
57
|
|
|
68
|
-
/**
|
|
69
|
-
* Get listener count for debugging
|
|
70
|
-
*/
|
|
71
58
|
getListenerCount(event?: string): number {
|
|
72
59
|
if (event) {
|
|
73
60
|
return this.listeners[event]?.length ?? 0;
|
|
@@ -1,8 +1,3 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Firestore Collection Utilities
|
|
3
|
-
* Shared utilities for building Firestore collection and document references
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
1
|
import { collection, doc } from "firebase/firestore";
|
|
7
2
|
import {
|
|
8
3
|
getFirestore,
|
|
@@ -16,10 +11,6 @@ export interface CollectionConfig {
|
|
|
16
11
|
useUserSubcollection: boolean;
|
|
17
12
|
}
|
|
18
13
|
|
|
19
|
-
/**
|
|
20
|
-
* Build a collection reference based on configuration
|
|
21
|
-
* Supports both root collections and user subcollections
|
|
22
|
-
*/
|
|
23
14
|
export function buildCollectionRef(
|
|
24
15
|
db: Firestore,
|
|
25
16
|
userId: string,
|
|
@@ -31,10 +22,6 @@ export function buildCollectionRef(
|
|
|
31
22
|
return collection(db, config.collectionName);
|
|
32
23
|
}
|
|
33
24
|
|
|
34
|
-
/**
|
|
35
|
-
* Build a document reference based on configuration
|
|
36
|
-
* Supports both root collections and user subcollections
|
|
37
|
-
*/
|
|
38
25
|
export function buildDocRef(
|
|
39
26
|
db: Firestore,
|
|
40
27
|
userId: string,
|
|
@@ -44,12 +31,9 @@ export function buildDocRef(
|
|
|
44
31
|
if (config.useUserSubcollection) {
|
|
45
32
|
return doc(db, "users", userId, config.collectionName, docId);
|
|
46
33
|
}
|
|
47
|
-
return doc(db, config.collectionName,
|
|
34
|
+
return doc(db, config.collectionName, userId);
|
|
48
35
|
}
|
|
49
36
|
|
|
50
|
-
/**
|
|
51
|
-
* Get Firestore instance or throw error
|
|
52
|
-
*/
|
|
53
37
|
export function requireFirestore(): Firestore {
|
|
54
38
|
const db = getFirestore();
|
|
55
39
|
if (!db) {
|
|
@@ -1,8 +1,3 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Result Utilities
|
|
3
|
-
* Shared helpers for working with Result pattern
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
1
|
import type { Result } from "../../utils/Result";
|
|
7
2
|
import { failure } from "../../utils/Result";
|
|
8
3
|
|
|
@@ -11,9 +6,6 @@ interface ApiError {
|
|
|
11
6
|
code: string;
|
|
12
7
|
}
|
|
13
8
|
|
|
14
|
-
/**
|
|
15
|
-
* Create a standard error result
|
|
16
|
-
*/
|
|
17
9
|
function createErrorResult(
|
|
18
10
|
message: string,
|
|
19
11
|
code: string = "UNKNOWN_ERROR"
|
|
@@ -21,12 +13,8 @@ function createErrorResult(
|
|
|
21
13
|
return failure({ message, code });
|
|
22
14
|
}
|
|
23
15
|
|
|
24
|
-
/**
|
|
25
|
-
* Map Error to ApiError result
|
|
26
|
-
*/
|
|
27
16
|
export function mapErrorToResult<T>(error: unknown): Result<T, ApiError> {
|
|
28
17
|
const message = error instanceof Error ? error.message : "An unknown error occurred";
|
|
29
18
|
const code = error instanceof Error && "code" in error ? String(error.code) : "UNKNOWN_ERROR";
|
|
30
19
|
return createErrorResult(message, code);
|
|
31
20
|
}
|
|
32
|
-
|
|
@@ -1,23 +1,7 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* User Cache Cleanup Hook
|
|
3
|
-
* Automatically cleans up previous user's query cache when userId changes
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
1
|
import { useEffect, useRef } from "react";
|
|
7
2
|
import type { QueryClient } from "@umituz/react-native-design-system";
|
|
8
3
|
import { isAuthenticated } from "../../../../domains/subscription/utils/authGuards";
|
|
9
4
|
|
|
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
5
|
export function usePreviousUserCleanup(
|
|
22
6
|
userId: string | null | undefined,
|
|
23
7
|
queryClient: QueryClient,
|
|
@@ -29,7 +13,6 @@ export function usePreviousUserCleanup(
|
|
|
29
13
|
const prevUserId = prevUserIdRef.current;
|
|
30
14
|
prevUserIdRef.current = userId;
|
|
31
15
|
|
|
32
|
-
// Clear previous user's cache when userId changes (logout or user switch)
|
|
33
16
|
if (prevUserId !== userId && isAuthenticated(prevUserId)) {
|
|
34
17
|
queryClient.removeQueries({
|
|
35
18
|
queryKey: queryKey(prevUserId),
|
|
@@ -1,18 +1,3 @@
|
|
|
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
1
|
export const NO_CACHE_QUERY_CONFIG = {
|
|
17
2
|
gcTime: 0,
|
|
18
3
|
staleTime: 0,
|
|
@@ -1,47 +1,33 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Result Pattern
|
|
3
|
-
* Type-safe error handling without exceptions.
|
|
4
|
-
* Inspired by Rust's Result<T, E> and functional programming patterns.
|
|
5
|
-
*/
|
|
6
|
-
|
|
7
|
-
/** Success result containing data */
|
|
8
1
|
export interface Success<T> {
|
|
9
2
|
readonly success: true;
|
|
10
3
|
readonly data: T;
|
|
11
4
|
readonly error?: never;
|
|
12
5
|
}
|
|
13
6
|
|
|
14
|
-
/** Failure result containing error */
|
|
15
7
|
export interface Failure<E = Error> {
|
|
16
8
|
readonly success: false;
|
|
17
9
|
readonly data?: never;
|
|
18
10
|
readonly error: E;
|
|
19
11
|
}
|
|
20
12
|
|
|
21
|
-
/** Union type representing either success or failure */
|
|
22
13
|
export type Result<T, E = Error> = Success<T> | Failure<E>;
|
|
23
14
|
|
|
24
|
-
/** Create a success result */
|
|
25
15
|
export function success<T>(data: T): Success<T> {
|
|
26
16
|
return { success: true, data };
|
|
27
17
|
}
|
|
28
18
|
|
|
29
|
-
/** Create a failure result */
|
|
30
19
|
export function failure<E = Error>(error: E): Failure<E> {
|
|
31
20
|
return { success: false, error };
|
|
32
21
|
}
|
|
33
22
|
|
|
34
|
-
/** Type guard to check if result is success */
|
|
35
23
|
export function isSuccess<T, E>(result: Result<T, E>): result is Success<T> {
|
|
36
24
|
return result.success === true;
|
|
37
25
|
}
|
|
38
26
|
|
|
39
|
-
/** Type guard to check if result is failure */
|
|
40
27
|
export function isFailure<T, E>(result: Result<T, E>): result is Failure<E> {
|
|
41
28
|
return result.success === false;
|
|
42
29
|
}
|
|
43
30
|
|
|
44
|
-
/** Unwrap result or throw if failure */
|
|
45
31
|
export function unwrap<T, E extends Error>(result: Result<T, E>): T {
|
|
46
32
|
if (isSuccess(result)) {
|
|
47
33
|
return result.data;
|
|
@@ -49,7 +35,6 @@ export function unwrap<T, E extends Error>(result: Result<T, E>): T {
|
|
|
49
35
|
throw result.error;
|
|
50
36
|
}
|
|
51
37
|
|
|
52
|
-
/** Unwrap result or return default value */
|
|
53
38
|
export function unwrapOr<T, E>(result: Result<T, E>, defaultValue: T): T {
|
|
54
39
|
if (isSuccess(result)) {
|
|
55
40
|
return result.data;
|
|
@@ -57,7 +42,6 @@ export function unwrapOr<T, E>(result: Result<T, E>, defaultValue: T): T {
|
|
|
57
42
|
return defaultValue;
|
|
58
43
|
}
|
|
59
44
|
|
|
60
|
-
/** Map success value to new value */
|
|
61
45
|
export function map<T, U, E>(
|
|
62
46
|
result: Result<T, E>,
|
|
63
47
|
fn: (data: T) => U
|
|
@@ -68,7 +52,6 @@ export function map<T, U, E>(
|
|
|
68
52
|
return result;
|
|
69
53
|
}
|
|
70
54
|
|
|
71
|
-
/** Chain results (flatMap) */
|
|
72
55
|
export function flatMap<T, U, E>(
|
|
73
56
|
result: Result<T, E>,
|
|
74
57
|
fn: (data: T) => Result<U, E>
|
|
@@ -79,7 +62,6 @@ export function flatMap<T, U, E>(
|
|
|
79
62
|
return result;
|
|
80
63
|
}
|
|
81
64
|
|
|
82
|
-
/** Execute async function and wrap result */
|
|
83
65
|
export async function tryCatch<T>(
|
|
84
66
|
fn: () => Promise<T>,
|
|
85
67
|
errorMapper?: (error: unknown) => Error
|
|
@@ -97,7 +79,6 @@ export async function tryCatch<T>(
|
|
|
97
79
|
}
|
|
98
80
|
}
|
|
99
81
|
|
|
100
|
-
/** Execute sync function and wrap result */
|
|
101
82
|
export function tryCatchSync<T>(
|
|
102
83
|
fn: () => T,
|
|
103
84
|
errorMapper?: (error: unknown) => Error
|
|
@@ -115,7 +96,6 @@ export function tryCatchSync<T>(
|
|
|
115
96
|
}
|
|
116
97
|
}
|
|
117
98
|
|
|
118
|
-
/** Combine multiple results into one */
|
|
119
99
|
export function combine<T, E>(results: Result<T, E>[]): Result<T[], E> {
|
|
120
100
|
const data: T[] = [];
|
|
121
101
|
for (const result of results) {
|
|
@@ -1,13 +1,7 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
*/
|
|
6
|
-
|
|
7
|
-
/**
|
|
8
|
-
* Safely converts any date-like value to a Date object or null
|
|
9
|
-
* Handles: Date objects, ISO strings, timestamps, null, undefined, invalid values
|
|
10
|
-
*/
|
|
1
|
+
import { Timestamp } from "@umituz/react-native-firebase";
|
|
2
|
+
|
|
3
|
+
type FirestoreTimestamp = ReturnType<typeof Timestamp.fromDate>;
|
|
4
|
+
|
|
11
5
|
export function toDate(value: Date | string | number | null | undefined): Date | null {
|
|
12
6
|
if (value === null || value === undefined) {
|
|
13
7
|
return null;
|
|
@@ -25,64 +19,39 @@ export function toDate(value: Date | string | number | null | undefined): Date |
|
|
|
25
19
|
return null;
|
|
26
20
|
}
|
|
27
21
|
|
|
28
|
-
/**
|
|
29
|
-
* Safely converts any date-like value to an ISO string or null
|
|
30
|
-
* Handles: Date objects, ISO strings, timestamps, null, undefined, invalid values
|
|
31
|
-
*/
|
|
32
22
|
export function toISOString(value: Date | string | number | null | undefined): string | null {
|
|
33
23
|
if (value === null || value === undefined) {
|
|
34
24
|
return null;
|
|
35
25
|
}
|
|
36
26
|
|
|
37
|
-
// If already a string, validate it
|
|
38
27
|
if (typeof value === 'string') {
|
|
39
28
|
const parsed = new Date(value);
|
|
40
|
-
return isValidDate(parsed) ?
|
|
29
|
+
return isValidDate(parsed) ? parsed.toISOString() : null;
|
|
41
30
|
}
|
|
42
31
|
|
|
43
|
-
// Convert to Date and then to ISO string
|
|
44
32
|
const date = toDate(value);
|
|
45
33
|
return date ? date.toISOString() : null;
|
|
46
34
|
}
|
|
47
35
|
|
|
48
|
-
/**
|
|
49
|
-
* Checks if a Date object is valid (not Invalid Date)
|
|
50
|
-
* @internal - Use for internal validation only
|
|
51
|
-
*/
|
|
52
36
|
function isValidDate(date: Date): boolean {
|
|
53
37
|
return date instanceof Date && !isNaN(date.getTime());
|
|
54
38
|
}
|
|
55
39
|
|
|
56
|
-
|
|
57
|
-
* Safely converts a Date or string to a Firestore Timestamp
|
|
58
|
-
* Returns null if the value is invalid
|
|
59
|
-
*/
|
|
60
|
-
export function toTimestamp(value: Date | string | number | null | undefined): any {
|
|
40
|
+
export function toTimestamp(value: Date | string | number | null | undefined): FirestoreTimestamp | null {
|
|
61
41
|
const date = toDate(value);
|
|
62
42
|
if (!date) return null;
|
|
63
43
|
|
|
64
|
-
// Lazy import to avoid circular dependencies
|
|
65
|
-
const { Timestamp } = require('firebase/firestore');
|
|
66
44
|
return Timestamp.fromDate(date);
|
|
67
45
|
}
|
|
68
46
|
|
|
69
|
-
/**
|
|
70
|
-
* Gets current date as ISO string
|
|
71
|
-
*/
|
|
72
47
|
export function getCurrentISOString(): string {
|
|
73
48
|
return new Date().toISOString();
|
|
74
49
|
}
|
|
75
50
|
|
|
76
|
-
/**
|
|
77
|
-
* Gets current date as Date object
|
|
78
|
-
*/
|
|
79
51
|
export function getCurrentDate(): Date {
|
|
80
52
|
return new Date();
|
|
81
53
|
}
|
|
82
54
|
|
|
83
|
-
/**
|
|
84
|
-
* Compares two dates and returns if first is before second
|
|
85
|
-
*/
|
|
86
55
|
export function isBefore(date1: Date | string | null | undefined, date2: Date | string | null | undefined): boolean {
|
|
87
56
|
const d1 = toDate(date1);
|
|
88
57
|
const d2 = toDate(date2);
|
|
@@ -91,9 +60,6 @@ export function isBefore(date1: Date | string | null | undefined, date2: Date |
|
|
|
91
60
|
return d1.getTime() < d2.getTime();
|
|
92
61
|
}
|
|
93
62
|
|
|
94
|
-
/**
|
|
95
|
-
* Compares two dates and returns if first is after second
|
|
96
|
-
*/
|
|
97
63
|
export function isAfter(date1: Date | string | null | undefined, date2: Date | string | null | undefined): boolean {
|
|
98
64
|
const d1 = toDate(date1);
|
|
99
65
|
const d2 = toDate(date2);
|
|
@@ -102,18 +68,12 @@ export function isAfter(date1: Date | string | null | undefined, date2: Date | s
|
|
|
102
68
|
return d1.getTime() > d2.getTime();
|
|
103
69
|
}
|
|
104
70
|
|
|
105
|
-
/**
|
|
106
|
-
* Checks if a date is in the past
|
|
107
|
-
*/
|
|
108
71
|
export function isInPast(date: Date | string | null | undefined): boolean {
|
|
109
72
|
const d = toDate(date);
|
|
110
73
|
if (!d) return false;
|
|
111
74
|
return d.getTime() < Date.now();
|
|
112
75
|
}
|
|
113
76
|
|
|
114
|
-
/**
|
|
115
|
-
* Checks if a date is in the future
|
|
116
|
-
*/
|
|
117
77
|
export function isInFuture(date: Date | string | null | undefined): boolean {
|
|
118
78
|
const d = toDate(date);
|
|
119
79
|
if (!d) return false;
|
package/src/utils/appUtils.ts
CHANGED
|
@@ -1,18 +1,8 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* App and Platform Utilities
|
|
3
|
-
*/
|
|
4
1
|
import { Platform } from "react-native";
|
|
5
2
|
import Constants from "expo-constants";
|
|
6
3
|
|
|
7
|
-
/**
|
|
8
|
-
* Development mode flag
|
|
9
|
-
* Safe check for __DEV__ that works in all environments
|
|
10
|
-
*/
|
|
11
4
|
export const IS_DEV_MODE = typeof __DEV__ !== "undefined" && __DEV__;
|
|
12
5
|
|
|
13
|
-
/**
|
|
14
|
-
* Gets the current app version from Expo constants
|
|
15
|
-
*/
|
|
16
6
|
export function getAppVersion(): string {
|
|
17
7
|
const version = Constants.expoConfig?.version;
|
|
18
8
|
|
|
@@ -22,9 +12,6 @@ export function getAppVersion(): string {
|
|
|
22
12
|
return version;
|
|
23
13
|
}
|
|
24
14
|
|
|
25
|
-
/**
|
|
26
|
-
* Validates if the current platform is supported
|
|
27
|
-
*/
|
|
28
15
|
export function validatePlatform(): "ios" | "android" {
|
|
29
16
|
const platform = Platform.OS;
|
|
30
17
|
if (platform !== "ios" && platform !== "android") {
|
|
@@ -33,9 +20,6 @@ export function validatePlatform(): "ios" | "android" {
|
|
|
33
20
|
return platform;
|
|
34
21
|
}
|
|
35
22
|
|
|
36
|
-
/**
|
|
37
|
-
* Checks if the app is currently in development mode
|
|
38
|
-
*/
|
|
39
23
|
export function isDev(): boolean {
|
|
40
24
|
return __DEV__;
|
|
41
25
|
}
|
|
@@ -1,9 +1,6 @@
|
|
|
1
1
|
import { detectPackageType, type SubscriptionPackageType } from "./packageTypeDetector";
|
|
2
2
|
import type { PackageAllocationMap } from "../domains/credits/core/Credits";
|
|
3
3
|
|
|
4
|
-
/**
|
|
5
|
-
* Get credit allocation for a package type from provided allocations map
|
|
6
|
-
*/
|
|
7
4
|
export function getCreditAllocation(
|
|
8
5
|
packageType: SubscriptionPackageType,
|
|
9
6
|
allocations?: PackageAllocationMap
|
|
@@ -12,10 +9,6 @@ export function getCreditAllocation(
|
|
|
12
9
|
return allocations[packageType]?.credits ?? null;
|
|
13
10
|
}
|
|
14
11
|
|
|
15
|
-
/**
|
|
16
|
-
* Create credit amounts mapping for PaywallModal from RevenueCat packages
|
|
17
|
-
* Maps product.identifier to credit amount using dynamic allocations
|
|
18
|
-
*/
|
|
19
12
|
export function createCreditAmountsFromPackages(
|
|
20
13
|
packages: Array<{ product: { identifier: string } }>,
|
|
21
14
|
allocations?: PackageAllocationMap
|
|
@@ -1,14 +1,6 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Date Utilities - Comparison Operations
|
|
3
|
-
* Date comparison and calculation functions
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
1
|
import { isValidDate, isPast, currentDate } from "./dateUtils.core";
|
|
7
2
|
import { addDays } from "./dateUtils.math";
|
|
8
3
|
|
|
9
|
-
/**
|
|
10
|
-
* Calculate difference in days between two dates
|
|
11
|
-
*/
|
|
12
4
|
export function daysBetween(date1: Date | string | number, date2: Date | string | number): number {
|
|
13
5
|
const d1 = new Date(date1);
|
|
14
6
|
const d2 = new Date(date2);
|
|
@@ -16,10 +8,6 @@ export function daysBetween(date1: Date | string | number, date2: Date | string
|
|
|
16
8
|
return Math.floor(diffTime / (1000 * 60 * 60 * 24));
|
|
17
9
|
}
|
|
18
10
|
|
|
19
|
-
/**
|
|
20
|
-
* Calculate days remaining until a date
|
|
21
|
-
* Returns null if date is in the past or invalid
|
|
22
|
-
*/
|
|
23
11
|
export function daysUntil(date: Date | string | number): number | null {
|
|
24
12
|
const target = new Date(date);
|
|
25
13
|
if (!isValidDate(target) || isPast(target)) {
|
|
@@ -28,9 +16,6 @@ export function daysUntil(date: Date | string | number): number | null {
|
|
|
28
16
|
return daysBetween(currentDate(), target);
|
|
29
17
|
}
|
|
30
18
|
|
|
31
|
-
/**
|
|
32
|
-
* Check if two dates are the same day
|
|
33
|
-
*/
|
|
34
19
|
export function isSameDay(date1: Date | string | number, date2: Date | string | number): boolean {
|
|
35
20
|
const d1 = new Date(date1);
|
|
36
21
|
const d2 = new Date(date2);
|
|
@@ -41,24 +26,15 @@ export function isSameDay(date1: Date | string | number, date2: Date | string |
|
|
|
41
26
|
);
|
|
42
27
|
}
|
|
43
28
|
|
|
44
|
-
/**
|
|
45
|
-
* Check if a date is today
|
|
46
|
-
*/
|
|
47
29
|
export function isToday(date: Date | string | number): boolean {
|
|
48
30
|
return isSameDay(date, currentDate());
|
|
49
31
|
}
|
|
50
32
|
|
|
51
|
-
/**
|
|
52
|
-
* Check if a date is yesterday
|
|
53
|
-
*/
|
|
54
33
|
export function isYesterday(date: Date | string | number): boolean {
|
|
55
34
|
const yesterday = addDays(currentDate(), -1);
|
|
56
35
|
return isSameDay(date, yesterday);
|
|
57
36
|
}
|
|
58
37
|
|
|
59
|
-
/**
|
|
60
|
-
* Check if a date is tomorrow
|
|
61
|
-
*/
|
|
62
38
|
export function isTomorrow(date: Date | string | number): boolean {
|
|
63
39
|
const tomorrow = addDays(currentDate(), 1);
|
|
64
40
|
return isSameDay(date, tomorrow);
|
|
@@ -1,56 +1,26 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Date Utilities - Core Operations
|
|
3
|
-
* Basic date manipulation and validation functions
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
1
|
export type DateLike = Date | string | number;
|
|
7
2
|
|
|
8
|
-
/**
|
|
9
|
-
* Checks if a date is in the past (strictly before now)
|
|
10
|
-
* @param date - The date to check
|
|
11
|
-
* @returns true if date < now, false if date >= now
|
|
12
|
-
* @note A date exactly equal to Date.now() returns false (not past)
|
|
13
|
-
*/
|
|
14
3
|
export function isPast(date: DateLike): boolean {
|
|
15
4
|
const d = new Date(date);
|
|
16
5
|
return d.getTime() < Date.now();
|
|
17
6
|
}
|
|
18
7
|
|
|
19
|
-
/**
|
|
20
|
-
* Checks if a date is in the future (strictly after now)
|
|
21
|
-
* @param date - The date to check
|
|
22
|
-
* @returns true if date > now, false if date <= now
|
|
23
|
-
* @note A date exactly equal to Date.now() returns false (not future)
|
|
24
|
-
*/
|
|
25
8
|
export function isFuture(date: DateLike): boolean {
|
|
26
9
|
const d = new Date(date);
|
|
27
10
|
return d.getTime() > Date.now();
|
|
28
11
|
}
|
|
29
12
|
|
|
30
|
-
/**
|
|
31
|
-
* Checks if a date is approximately now (within margin)
|
|
32
|
-
* Useful for handling edge cases where isPast/isFuture might flicker
|
|
33
|
-
* @param date - The date to check
|
|
34
|
-
* @param marginMs - Margin in milliseconds (default: 1000ms)
|
|
35
|
-
* @returns true if date is within margin of Date.now()
|
|
36
|
-
*/
|
|
37
13
|
export function isNow(date: DateLike, marginMs: number = 1000): boolean {
|
|
38
14
|
const d = new Date(date);
|
|
39
15
|
const diff = Math.abs(d.getTime() - Date.now());
|
|
40
16
|
return diff <= marginMs;
|
|
41
17
|
}
|
|
42
18
|
|
|
43
|
-
/**
|
|
44
|
-
* Checks if a date is valid
|
|
45
|
-
*/
|
|
46
19
|
export function isValidDate(date: DateLike): boolean {
|
|
47
20
|
const d = date instanceof Date ? date : new Date(date);
|
|
48
21
|
return !isNaN(d.getTime());
|
|
49
22
|
}
|
|
50
23
|
|
|
51
|
-
/**
|
|
52
|
-
* Converts various timestamp formats to a safe Date object
|
|
53
|
-
*/
|
|
54
24
|
export function toSafeDate(ts: unknown): Date | null {
|
|
55
25
|
if (!ts) return null;
|
|
56
26
|
if (typeof ts === "object" && ts !== null && "toDate" in ts && typeof ts.toDate === "function") {
|
|
@@ -64,23 +34,14 @@ export function toSafeDate(ts: unknown): Date | null {
|
|
|
64
34
|
return null;
|
|
65
35
|
}
|
|
66
36
|
|
|
67
|
-
/**
|
|
68
|
-
* Formats a date to ISO string safely
|
|
69
|
-
*/
|
|
70
37
|
export function formatISO(date: Date | null): string | null {
|
|
71
38
|
return date ? date.toISOString() : null;
|
|
72
39
|
}
|
|
73
40
|
|
|
74
|
-
/**
|
|
75
|
-
* Get current timestamp in milliseconds
|
|
76
|
-
*/
|
|
77
41
|
export function now(): number {
|
|
78
42
|
return Date.now();
|
|
79
43
|
}
|
|
80
44
|
|
|
81
|
-
/**
|
|
82
|
-
* Get current date
|
|
83
|
-
*/
|
|
84
45
|
export function currentDate(): Date {
|
|
85
46
|
return new Date();
|
|
86
47
|
}
|