@umituz/react-native-subscription 1.0.4 → 1.0.5

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": "1.0.4",
3
+ "version": "1.0.5",
4
4
  "description": "Subscription management system for React Native apps - Database-first approach with secure validation",
5
5
  "main": "./src/index.ts",
6
6
  "types": "./src/index.ts",
package/src/index.ts CHANGED
@@ -64,14 +64,19 @@ export type { UseSubscriptionResult } from './presentation/hooks/useSubscription
64
64
  // UTILS
65
65
  // =============================================================================
66
66
 
67
+ // Date utilities
67
68
  export {
68
69
  isSubscriptionExpired,
69
70
  getDaysUntilExpiration,
70
71
  formatExpirationDate,
71
72
  calculateExpirationDate,
72
- formatPrice,
73
- getPeriodText,
74
- } from './utils/subscriptionUtils';
73
+ } from './utils/dateUtils';
74
+
75
+ // Price utilities
76
+ export { formatPrice } from './utils/priceUtils';
77
+
78
+ // Period utilities
79
+ export { getPeriodText } from './utils/periodUtils';
75
80
 
76
81
  export {
77
82
  SUBSCRIPTION_PLAN_TYPES,
@@ -1,9 +1,9 @@
1
1
  /**
2
- * Subscription Utilities
3
- * Helper functions for subscription operations
2
+ * Date Utilities
3
+ * Subscription date-related helper functions
4
4
  *
5
5
  * Following SOLID, DRY, KISS principles:
6
- * - Single Responsibility: Each function does ONE thing
6
+ * - Single Responsibility: Only date-related operations
7
7
  * - DRY: No code duplication
8
8
  * - KISS: Simple, clear implementations
9
9
  */
@@ -14,7 +14,6 @@ import {
14
14
  MIN_SUBSCRIPTION_DURATIONS_DAYS,
15
15
  SUBSCRIPTION_PERIOD_DAYS,
16
16
  DATE_CONSTANTS,
17
- SUBSCRIPTION_PERIOD_UNITS,
18
17
  PRODUCT_ID_KEYWORDS,
19
18
  type SubscriptionPlanType,
20
19
  } from './subscriptionConstants';
@@ -47,7 +46,9 @@ function extractPlanFromProductId(
47
46
  /**
48
47
  * Check if subscription is expired
49
48
  */
50
- export function isSubscriptionExpired(status: SubscriptionStatus | null): boolean {
49
+ export function isSubscriptionExpired(
50
+ status: SubscriptionStatus | null,
51
+ ): boolean {
51
52
  if (!status || !status.isPremium) {
52
53
  return true;
53
54
  }
@@ -109,23 +110,23 @@ export function formatExpirationDate(
109
110
 
110
111
  /**
111
112
  * Calculate expiration date based on subscription plan
112
- *
113
+ *
113
114
  * This function handles:
114
115
  * - RevenueCat sandbox accelerated timers (detects and recalculates)
115
116
  * - Production dates (trusts RevenueCat's date if valid)
116
117
  * - Monthly subscriptions: Same day next month (e.g., Nov 10 → Dec 10)
117
118
  * - Yearly subscriptions: Same day next year (e.g., Nov 10, 2024 → Nov 10, 2025)
118
119
  * - Weekly subscriptions: +7 days
119
- *
120
+ *
120
121
  * @param productId - Product identifier (e.g., "com.umituz.app.monthly")
121
122
  * @param revenueCatExpiresAt - Optional expiration date from RevenueCat API
122
123
  * @returns ISO date string for expiration, or null if invalid
123
- *
124
+ *
124
125
  * @example
125
126
  * // Monthly subscription purchased on Nov 10, 2024
126
127
  * calculateExpirationDate('com.umituz.app.monthly', null)
127
128
  * // Returns: '2024-12-10T...' (Dec 10, 2024)
128
- *
129
+ *
129
130
  * @example
130
131
  * // Yearly subscription purchased on Nov 10, 2024
131
132
  * calculateExpirationDate('com.umituz.app.yearly', null)
@@ -208,108 +209,3 @@ export function calculateExpirationDate(
208
209
  return calculatedDate.toISOString();
209
210
  }
210
211
 
211
- /**
212
- * Format price for display
213
- * Formats a price value with currency code using Intl.NumberFormat
214
- *
215
- * @param price - Price value (e.g., 9.99)
216
- * @param currencyCode - ISO 4217 currency code (e.g., "USD", "EUR", "TRY")
217
- * @returns Formatted price string (e.g., "$9.99", "€9.99", "₺9.99")
218
- *
219
- * @example
220
- * formatPrice(9.99, "USD") // Returns: "$9.99"
221
- * formatPrice(229.99, "TRY") // Returns: "₺229.99"
222
- */
223
- export function formatPrice(price: number, currencyCode: string): string {
224
- return new Intl.NumberFormat(DATE_CONSTANTS.DEFAULT_LOCALE, {
225
- style: 'currency',
226
- currency: currencyCode,
227
- }).format(price);
228
- }
229
-
230
- /**
231
- * Get subscription period text from RevenueCat package
232
- * Extracts readable period text from PurchasesPackage or subscription period object
233
- *
234
- * @param input - RevenueCat PurchasesPackage or subscription period object
235
- * @returns Human-readable period text (e.g., "month", "year", "2 months")
236
- *
237
- * @example
238
- * // From PurchasesPackage
239
- * getPeriodText(pkg) // Returns: "month"
240
- *
241
- * @example
242
- * // From subscription period object
243
- * getPeriodText({ unit: "MONTH", numberOfUnits: 1 }) // Returns: "month"
244
- * getPeriodText({ unit: "YEAR", numberOfUnits: 1 }) // Returns: "year"
245
- * getPeriodText({ unit: "MONTH", numberOfUnits: 3 }) // Returns: "3 months"
246
- */
247
- export function getPeriodText(
248
- input:
249
- | {
250
- product?: {
251
- subscriptionPeriod?: {
252
- unit: string;
253
- numberOfUnits: number;
254
- } | null;
255
- };
256
- }
257
- | {
258
- unit: string;
259
- numberOfUnits: number;
260
- }
261
- | null
262
- | undefined,
263
- ): string {
264
- if (!input) return '';
265
-
266
- // Extract subscription period from PurchasesPackage or use directly
267
- let subscriptionPeriod:
268
- | {
269
- unit: string;
270
- numberOfUnits: number;
271
- }
272
- | null
273
- | undefined;
274
-
275
- // Check if input is PurchasesPackage (has product property)
276
- if ('product' in input && input.product?.subscriptionPeriod) {
277
- const period = input.product.subscriptionPeriod;
278
- // Type guard: check if period is an object with unit and numberOfUnits
279
- if (
280
- typeof period === 'object' &&
281
- 'unit' in period &&
282
- 'numberOfUnits' in period
283
- ) {
284
- subscriptionPeriod = {
285
- unit: period.unit as string,
286
- numberOfUnits: period.numberOfUnits as number,
287
- };
288
- }
289
- } else if ('unit' in input && 'numberOfUnits' in input) {
290
- // Input is already a subscription period object
291
- subscriptionPeriod = {
292
- unit: input.unit,
293
- numberOfUnits: input.numberOfUnits,
294
- };
295
- }
296
-
297
- if (!subscriptionPeriod) return '';
298
-
299
- const { unit, numberOfUnits } = subscriptionPeriod;
300
-
301
- if (unit === SUBSCRIPTION_PERIOD_UNITS.MONTH) {
302
- return numberOfUnits === 1 ? 'month' : `${numberOfUnits} months`;
303
- }
304
-
305
- if (unit === SUBSCRIPTION_PERIOD_UNITS.YEAR) {
306
- return numberOfUnits === 1 ? 'year' : `${numberOfUnits} years`;
307
- }
308
-
309
- if (unit === SUBSCRIPTION_PERIOD_UNITS.WEEK) {
310
- return numberOfUnits === 1 ? 'week' : `${numberOfUnits} weeks`;
311
- }
312
-
313
- return '';
314
- }
315
-
@@ -0,0 +1,98 @@
1
+ /**
2
+ * Period Utilities
3
+ * Subscription period-related helper functions
4
+ *
5
+ * Following SOLID, DRY, KISS principles:
6
+ * - Single Responsibility: Only period-related operations
7
+ * - DRY: No code duplication
8
+ * - KISS: Simple, clear implementations
9
+ */
10
+
11
+ import { SUBSCRIPTION_PERIOD_UNITS } from './subscriptionConstants';
12
+
13
+ /**
14
+ * Get subscription period text from RevenueCat package
15
+ * Extracts readable period text from PurchasesPackage or subscription period object
16
+ *
17
+ * @param input - RevenueCat PurchasesPackage or subscription period object
18
+ * @returns Human-readable period text (e.g., "month", "year", "2 months")
19
+ *
20
+ * @example
21
+ * // From PurchasesPackage
22
+ * getPeriodText(pkg) // Returns: "month"
23
+ *
24
+ * @example
25
+ * // From subscription period object
26
+ * getPeriodText({ unit: "MONTH", numberOfUnits: 1 }) // Returns: "month"
27
+ * getPeriodText({ unit: "YEAR", numberOfUnits: 1 }) // Returns: "year"
28
+ * getPeriodText({ unit: "MONTH", numberOfUnits: 3 }) // Returns: "3 months"
29
+ */
30
+ export function getPeriodText(
31
+ input:
32
+ | {
33
+ product?: {
34
+ subscriptionPeriod?: {
35
+ unit: string;
36
+ numberOfUnits: number;
37
+ } | null;
38
+ };
39
+ }
40
+ | {
41
+ unit: string;
42
+ numberOfUnits: number;
43
+ }
44
+ | null
45
+ | undefined,
46
+ ): string {
47
+ if (!input) return '';
48
+
49
+ // Extract subscription period from PurchasesPackage or use directly
50
+ let subscriptionPeriod:
51
+ | {
52
+ unit: string;
53
+ numberOfUnits: number;
54
+ }
55
+ | null
56
+ | undefined;
57
+
58
+ // Check if input is PurchasesPackage (has product property)
59
+ if ('product' in input && input.product?.subscriptionPeriod) {
60
+ const period = input.product.subscriptionPeriod;
61
+ // Type guard: check if period is an object with unit and numberOfUnits
62
+ if (
63
+ typeof period === 'object' &&
64
+ 'unit' in period &&
65
+ 'numberOfUnits' in period
66
+ ) {
67
+ subscriptionPeriod = {
68
+ unit: period.unit as string,
69
+ numberOfUnits: period.numberOfUnits as number,
70
+ };
71
+ }
72
+ } else if ('unit' in input && 'numberOfUnits' in input) {
73
+ // Input is already a subscription period object
74
+ subscriptionPeriod = {
75
+ unit: input.unit,
76
+ numberOfUnits: input.numberOfUnits,
77
+ };
78
+ }
79
+
80
+ if (!subscriptionPeriod) return '';
81
+
82
+ const { unit, numberOfUnits } = subscriptionPeriod;
83
+
84
+ if (unit === SUBSCRIPTION_PERIOD_UNITS.MONTH) {
85
+ return numberOfUnits === 1 ? 'month' : `${numberOfUnits} months`;
86
+ }
87
+
88
+ if (unit === SUBSCRIPTION_PERIOD_UNITS.YEAR) {
89
+ return numberOfUnits === 1 ? 'year' : `${numberOfUnits} years`;
90
+ }
91
+
92
+ if (unit === SUBSCRIPTION_PERIOD_UNITS.WEEK) {
93
+ return numberOfUnits === 1 ? 'week' : `${numberOfUnits} weeks`;
94
+ }
95
+
96
+ return '';
97
+ }
98
+
@@ -0,0 +1,31 @@
1
+ /**
2
+ * Price Utilities
3
+ * Subscription price-related helper functions
4
+ *
5
+ * Following SOLID, DRY, KISS principles:
6
+ * - Single Responsibility: Only price-related operations
7
+ * - DRY: No code duplication
8
+ * - KISS: Simple, clear implementations
9
+ */
10
+
11
+ import { DATE_CONSTANTS } from './subscriptionConstants';
12
+
13
+ /**
14
+ * Format price for display
15
+ * Formats a price value with currency code using Intl.NumberFormat
16
+ *
17
+ * @param price - Price value (e.g., 9.99)
18
+ * @param currencyCode - ISO 4217 currency code (e.g., "USD", "EUR", "TRY")
19
+ * @returns Formatted price string (e.g., "$9.99", "€9.99", "₺9.99")
20
+ *
21
+ * @example
22
+ * formatPrice(9.99, "USD") // Returns: "$9.99"
23
+ * formatPrice(229.99, "TRY") // Returns: "₺229.99"
24
+ */
25
+ export function formatPrice(price: number, currencyCode: string): string {
26
+ return new Intl.NumberFormat(DATE_CONSTANTS.DEFAULT_LOCALE, {
27
+ style: 'currency',
28
+ currency: currencyCode,
29
+ }).format(price);
30
+ }
31
+