@umituz/react-native-subscription 2.15.2 → 2.15.3

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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@umituz/react-native-subscription",
3
- "version": "2.15.2",
3
+ "version": "2.15.3",
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",
@@ -6,6 +6,7 @@
6
6
  import type { PurchasesPackage, CustomerInfo } from "react-native-purchases";
7
7
  import type { IRevenueCatService } from "../../application/ports/IRevenueCatService";
8
8
  import { getPremiumEntitlement } from "../../domain/types/RevenueCatTypes";
9
+ import { getExpirationDate } from "../utils/ExpirationDateCalculator";
9
10
 
10
11
  export interface PremiumStatus {
11
12
  isPremium: boolean;
@@ -114,22 +115,57 @@ export class PackageHandler {
114
115
  }
115
116
 
116
117
  checkPremiumStatusFromInfo(customerInfo: CustomerInfo): PremiumStatus {
117
- const entitlement = getPremiumEntitlement(
118
+ // First, check active entitlements (standard case)
119
+ const activeEntitlement = getPremiumEntitlement(
118
120
  customerInfo,
119
121
  this.entitlementId
120
122
  );
121
123
 
122
- if (entitlement) {
124
+ if (activeEntitlement) {
125
+ const adjustedExpiration = getExpirationDate(activeEntitlement);
123
126
  return {
124
127
  isPremium: true,
125
- expirationDate: entitlement.expirationDate
126
- ? new Date(entitlement.expirationDate)
127
- : null,
128
+ expirationDate: adjustedExpiration ? new Date(adjustedExpiration) : null,
128
129
  };
129
130
  }
130
131
 
132
+ // Edge case: Check all entitlements (including expired ones)
133
+ // This handles the bug where RevenueCat hasn't updated the expiration date yet
134
+ const allEntitlements = customerInfo.entitlements.all[this.entitlementId];
135
+
136
+ if (allEntitlements) {
137
+ const entitlementData = {
138
+ identifier: allEntitlements.identifier,
139
+ productIdentifier: allEntitlements.productIdentifier,
140
+ isSandbox: allEntitlements.isSandbox,
141
+ willRenew: allEntitlements.willRenew,
142
+ periodType: allEntitlements.periodType,
143
+ latestPurchaseDate: allEntitlements.latestPurchaseDate,
144
+ originalPurchaseDate: allEntitlements.originalPurchaseDate,
145
+ expirationDate: allEntitlements.expirationDate,
146
+ unsubscribeDetectedAt: allEntitlements.unsubscribeDetectedAt,
147
+ billingIssueDetectedAt: allEntitlements.billingIssueDetectedAt,
148
+ };
149
+
150
+ // Get adjusted expiration date
151
+ const adjustedExpiration = getExpirationDate(entitlementData);
152
+
153
+ if (adjustedExpiration) {
154
+ const expirationDate = new Date(adjustedExpiration);
155
+ const now = new Date();
156
+
157
+ // If adjusted expiration is in the future, user is premium
158
+ if (expirationDate > now) {
159
+ return {
160
+ isPremium: true,
161
+ expirationDate,
162
+ };
163
+ }
164
+ }
165
+ }
166
+
131
167
  return {
132
- isPremium: !!customerInfo.entitlements.active[this.entitlementId],
168
+ isPremium: false,
133
169
  expirationDate: null,
134
170
  };
135
171
  }
@@ -1,9 +1,63 @@
1
1
  /**
2
2
  * Expiration Date Calculator
3
- * Handles RevenueCat expiration date extraction
3
+ * Handles RevenueCat expiration date extraction with edge case handling
4
4
  */
5
5
 
6
6
  import type { RevenueCatEntitlement } from '../../domain/types/RevenueCatTypes';
7
+ import { detectPackageType, type SubscriptionPackageType } from '../../../utils/packageTypeDetector';
8
+
9
+ /**
10
+ * Add subscription period to a date
11
+ */
12
+ function addSubscriptionPeriod(date: Date, packageType: SubscriptionPackageType): Date {
13
+ const newDate = new Date(date);
14
+
15
+ switch (packageType) {
16
+ case 'weekly':
17
+ newDate.setDate(newDate.getDate() + 7);
18
+ break;
19
+ case 'monthly':
20
+ newDate.setDate(newDate.getDate() + 30);
21
+ break;
22
+ case 'yearly':
23
+ newDate.setDate(newDate.getDate() + 365);
24
+ break;
25
+ default:
26
+ // Unknown type, default to monthly
27
+ newDate.setDate(newDate.getDate() + 30);
28
+ break;
29
+ }
30
+
31
+ return newDate;
32
+ }
33
+
34
+ /**
35
+ * Adjust expiration date if it equals current date
36
+ *
37
+ * RevenueCat sometimes returns expiration date equal to purchase date
38
+ * immediately after purchase. This causes false "expired" status.
39
+ *
40
+ * Solution: If expiration date is today or in the past, add the subscription
41
+ * period (weekly/monthly/yearly) to prevent false expiration.
42
+ */
43
+ function adjustExpirationDate(
44
+ expirationDate: string,
45
+ productIdentifier: string
46
+ ): string {
47
+ const expDate = new Date(expirationDate);
48
+ const now = new Date();
49
+
50
+ // If expiration is in the future, no adjustment needed
51
+ if (expDate > now) {
52
+ return expirationDate;
53
+ }
54
+
55
+ // If expiration is today or past, add subscription period
56
+ const packageType = detectPackageType(productIdentifier);
57
+ const adjustedDate = addSubscriptionPeriod(expDate, packageType);
58
+
59
+ return adjustedDate.toISOString();
60
+ }
7
61
 
8
62
  export function getExpirationDate(
9
63
  entitlement: RevenueCatEntitlement | null
@@ -16,5 +70,9 @@ export function getExpirationDate(
16
70
  return null;
17
71
  }
18
72
 
19
- return new Date(entitlement.expirationDate).toISOString();
73
+ // Apply edge case fix for same-day expirations
74
+ return adjustExpirationDate(
75
+ entitlement.expirationDate,
76
+ entitlement.productIdentifier
77
+ );
20
78
  }