@umituz/react-native-subscription 2.27.150 → 2.27.154
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/creditOperationUtils.ts +5 -2
- package/src/domains/credits/presentation/useDeductCredit.ts +1 -1
- package/src/domains/credits/utils/creditValidation.ts +1 -1
- package/src/domains/subscription/infrastructure/handlers/PurchaseStatusResolver.ts +2 -3
- package/src/domains/subscription/infrastructure/hooks/usePurchasePackage.ts +1 -1
- package/src/domains/subscription/infrastructure/hooks/useRestorePurchase.ts +1 -1
- package/src/index.ts +1 -0
- package/src/shared/utils/dateConverter.ts +121 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@umituz/react-native-subscription",
|
|
3
|
-
"version": "2.27.
|
|
3
|
+
"version": "2.27.154",
|
|
4
4
|
"description": "Complete subscription management with RevenueCat, paywall UI, and credits system for React Native apps",
|
|
5
5
|
"main": "./src/index.ts",
|
|
6
6
|
"types": "./src/index.ts",
|
|
@@ -1,8 +1,9 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { serverTimestamp } from "firebase/firestore";
|
|
2
2
|
import { resolveSubscriptionStatus } from "../../subscription/core/SubscriptionStatus";
|
|
3
3
|
import { creditAllocationOrchestrator } from "./credit-strategies/CreditAllocationOrchestrator";
|
|
4
4
|
import { isPast } from "../../../utils/dateUtils";
|
|
5
5
|
import { isCreditPackage } from "../../../utils/packageTypeDetector";
|
|
6
|
+
import { toTimestamp } from "../../../shared/utils/dateConverter";
|
|
6
7
|
import {
|
|
7
8
|
CalculateCreditsParams,
|
|
8
9
|
BuildCreditsDataParams
|
|
@@ -61,7 +62,9 @@ export function buildCreditsData({
|
|
|
61
62
|
platform,
|
|
62
63
|
...(purchaseHistory.length > 0 && { purchaseHistory }),
|
|
63
64
|
...(isPurchaseOrRenewal && { lastPurchaseAt: serverTimestamp() }),
|
|
64
|
-
...(metadata.expirationDate && {
|
|
65
|
+
...(metadata.expirationDate && {
|
|
66
|
+
expirationDate: toTimestamp(metadata.expirationDate)
|
|
67
|
+
}),
|
|
65
68
|
...(metadata.willRenew !== undefined && { willRenew: metadata.willRenew }),
|
|
66
69
|
...(metadata.originalTransactionId && { originalTransactionId: metadata.originalTransactionId }),
|
|
67
70
|
};
|
|
@@ -7,7 +7,7 @@ import { useCallback } from "react";
|
|
|
7
7
|
import { useMutation, useQueryClient } from "@umituz/react-native-design-system";
|
|
8
8
|
import type { UserCredits } from "../core/Credits";
|
|
9
9
|
import { getCreditsRepository } from "../infrastructure/CreditsRepositoryManager";
|
|
10
|
-
import { creditsQueryKeys } from "./
|
|
10
|
+
import { creditsQueryKeys } from "./creditsQueryKeys";
|
|
11
11
|
import { calculateRemaining } from "../../../shared/utils/numberUtils";
|
|
12
12
|
|
|
13
13
|
import { timezoneService } from "@umituz/react-native-design-system";
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { isValidNumber, isNonNegative } from "../../../shared/utils/typeGuards";
|
|
2
2
|
|
|
3
3
|
export const isValidBalance = (balance: number | null | undefined): balance is number => {
|
|
4
4
|
return isValidNumber(balance) && isNonNegative(balance);
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { CustomerInfo } from "react-native-purchases";
|
|
2
2
|
import { getPremiumEntitlement } from "../../core/RevenueCatTypes";
|
|
3
|
+
import { toDate } from "../../../../shared/utils/dateConverter";
|
|
3
4
|
|
|
4
5
|
export interface PremiumStatus {
|
|
5
6
|
isPremium: boolean;
|
|
@@ -13,9 +14,7 @@ export class PurchaseStatusResolver {
|
|
|
13
14
|
if (entitlement) {
|
|
14
15
|
return {
|
|
15
16
|
isPremium: true,
|
|
16
|
-
expirationDate: entitlement.expirationDate
|
|
17
|
-
? new Date(entitlement.expirationDate)
|
|
18
|
-
: null,
|
|
17
|
+
expirationDate: toDate(entitlement.expirationDate),
|
|
19
18
|
};
|
|
20
19
|
}
|
|
21
20
|
|
|
@@ -15,7 +15,7 @@ import {
|
|
|
15
15
|
import { SubscriptionManager } from "../../infrastructure/managers/SubscriptionManager";
|
|
16
16
|
import { SUBSCRIPTION_QUERY_KEYS } from "./subscriptionQueryKeys";
|
|
17
17
|
import { subscriptionStatusQueryKeys } from "../../presentation/useSubscriptionStatus";
|
|
18
|
-
import { creditsQueryKeys } from "../../../credits/presentation/
|
|
18
|
+
import { creditsQueryKeys } from "../../../credits/presentation/creditsQueryKeys";
|
|
19
19
|
|
|
20
20
|
/** Purchase mutation result - simplified for presentation layer */
|
|
21
21
|
export interface PurchaseMutationResult {
|
|
@@ -13,7 +13,7 @@ import {
|
|
|
13
13
|
import { SubscriptionManager } from "../../infrastructure/managers/SubscriptionManager";
|
|
14
14
|
import { SUBSCRIPTION_QUERY_KEYS } from "./subscriptionQueryKeys";
|
|
15
15
|
import { subscriptionStatusQueryKeys } from "../../presentation/useSubscriptionStatus";
|
|
16
|
-
import { creditsQueryKeys } from "../../../credits/presentation/
|
|
16
|
+
import { creditsQueryKeys } from "../../../credits/presentation/creditsQueryKeys";
|
|
17
17
|
|
|
18
18
|
interface RestoreResult {
|
|
19
19
|
success: boolean;
|
package/src/index.ts
CHANGED
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Date Converter Utilities
|
|
3
|
+
* Centralized date conversion and validation logic
|
|
4
|
+
* Handles Date objects, ISO strings, timestamps, and null values safely
|
|
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
|
+
*/
|
|
11
|
+
export function toDate(value: Date | string | number | null | undefined): Date | null {
|
|
12
|
+
if (value === null || value === undefined) {
|
|
13
|
+
return null;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
if (value instanceof Date) {
|
|
17
|
+
return isValidDate(value) ? value : null;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
if (typeof value === 'string' || typeof value === 'number') {
|
|
21
|
+
const parsed = new Date(value);
|
|
22
|
+
return isValidDate(parsed) ? parsed : null;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
return null;
|
|
26
|
+
}
|
|
27
|
+
|
|
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
|
+
export function toISOString(value: Date | string | number | null | undefined): string | null {
|
|
33
|
+
if (value === null || value === undefined) {
|
|
34
|
+
return null;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
// If already a string, validate it
|
|
38
|
+
if (typeof value === 'string') {
|
|
39
|
+
const parsed = new Date(value);
|
|
40
|
+
return isValidDate(parsed) ? value : null;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
// Convert to Date and then to ISO string
|
|
44
|
+
const date = toDate(value);
|
|
45
|
+
return date ? date.toISOString() : null;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Checks if a Date object is valid (not Invalid Date)
|
|
50
|
+
* @internal - Use for internal validation only
|
|
51
|
+
*/
|
|
52
|
+
function isValidDate(date: Date): boolean {
|
|
53
|
+
return date instanceof Date && !isNaN(date.getTime());
|
|
54
|
+
}
|
|
55
|
+
|
|
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 {
|
|
61
|
+
const date = toDate(value);
|
|
62
|
+
if (!date) return null;
|
|
63
|
+
|
|
64
|
+
// Lazy import to avoid circular dependencies
|
|
65
|
+
const { Timestamp } = require('firebase/firestore');
|
|
66
|
+
return Timestamp.fromDate(date);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* Gets current date as ISO string
|
|
71
|
+
*/
|
|
72
|
+
export function getCurrentISOString(): string {
|
|
73
|
+
return new Date().toISOString();
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* Gets current date as Date object
|
|
78
|
+
*/
|
|
79
|
+
export function getCurrentDate(): Date {
|
|
80
|
+
return new Date();
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* Compares two dates and returns if first is before second
|
|
85
|
+
*/
|
|
86
|
+
export function isBefore(date1: Date | string | null | undefined, date2: Date | string | null | undefined): boolean {
|
|
87
|
+
const d1 = toDate(date1);
|
|
88
|
+
const d2 = toDate(date2);
|
|
89
|
+
|
|
90
|
+
if (!d1 || !d2) return false;
|
|
91
|
+
return d1.getTime() < d2.getTime();
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* Compares two dates and returns if first is after second
|
|
96
|
+
*/
|
|
97
|
+
export function isAfter(date1: Date | string | null | undefined, date2: Date | string | null | undefined): boolean {
|
|
98
|
+
const d1 = toDate(date1);
|
|
99
|
+
const d2 = toDate(date2);
|
|
100
|
+
|
|
101
|
+
if (!d1 || !d2) return false;
|
|
102
|
+
return d1.getTime() > d2.getTime();
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
/**
|
|
106
|
+
* Checks if a date is in the past
|
|
107
|
+
*/
|
|
108
|
+
export function isInPast(date: Date | string | null | undefined): boolean {
|
|
109
|
+
const d = toDate(date);
|
|
110
|
+
if (!d) return false;
|
|
111
|
+
return d.getTime() < Date.now();
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
/**
|
|
115
|
+
* Checks if a date is in the future
|
|
116
|
+
*/
|
|
117
|
+
export function isInFuture(date: Date | string | null | undefined): boolean {
|
|
118
|
+
const d = toDate(date);
|
|
119
|
+
if (!d) return false;
|
|
120
|
+
return d.getTime() > Date.now();
|
|
121
|
+
}
|