@solvapay/react 1.0.0-preview.2 → 1.0.0-preview.21

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/dist/index.d.ts CHANGED
@@ -1,84 +1,927 @@
1
- import React from 'react';
2
- import { Stripe } from '@stripe/stripe-js';
1
+ import React$1 from 'react';
2
+ import { PaymentIntent, Stripe } from '@stripe/stripe-js';
3
+ import { ProcessPaymentResult } from '@solvapay/server';
4
+ import { AuthAdapter } from './adapters/auth.js';
5
+ export { defaultAuthAdapter } from './adapters/auth.js';
3
6
 
7
+ /**
8
+ * TypeScript type definitions for @solvapay/react
9
+ */
10
+
11
+ interface PurchaseInfo {
12
+ reference: string;
13
+ productName: string;
14
+ productReference?: string;
15
+ status: string;
16
+ startDate: string;
17
+ endDate?: string;
18
+ cancelledAt?: string;
19
+ cancellationReason?: string;
20
+ amount?: number;
21
+ currency?: string;
22
+ planType?: string;
23
+ isRecurring?: boolean;
24
+ nextBillingDate?: string;
25
+ billingCycle?: string;
26
+ transactionId?: string;
27
+ planSnapshot?: {
28
+ reference?: string;
29
+ meterId?: string;
30
+ limit?: number;
31
+ freeUnits?: number;
32
+ pricePerUnit?: number;
33
+ planType?: string;
34
+ billingCycle?: string | null;
35
+ features?: Record<string, unknown> | null;
36
+ };
37
+ usage?: {
38
+ used: number;
39
+ overageUnits?: number;
40
+ overageCost?: number;
41
+ periodStart?: string;
42
+ periodEnd?: string;
43
+ };
44
+ }
45
+ interface CustomerPurchaseData {
46
+ customerRef?: string;
47
+ email?: string;
48
+ name?: string;
49
+ purchases: PurchaseInfo[];
50
+ }
51
+ interface PaymentIntentResult {
52
+ clientSecret: string;
53
+ publishableKey: string;
54
+ accountId?: string;
55
+ customerRef?: string;
56
+ }
57
+ interface PurchaseStatus {
58
+ loading: boolean;
59
+ customerRef?: string;
60
+ email?: string;
61
+ name?: string;
62
+ purchases: PurchaseInfo[];
63
+ hasProduct: (productName: string) => boolean;
64
+ /** @deprecated Use hasProduct instead */
65
+ hasPlan: (productName: string) => boolean;
66
+ /**
67
+ * Primary active purchase (paid or free) - most recent purchase with status === 'active'
68
+ * Backend keeps purchases as 'active' until expiration, even when cancelled.
69
+ * null if no active purchase exists
70
+ */
71
+ activePurchase: PurchaseInfo | null;
72
+ /**
73
+ * Check if user has any active paid purchase (amount > 0)
74
+ * Checks purchases with status === 'active'.
75
+ * Backend keeps purchases as 'active' until expiration, even when cancelled.
76
+ */
77
+ hasPaidPurchase: boolean;
78
+ /**
79
+ * Most recent active paid purchase (sorted by startDate)
80
+ * Returns purchase with status === 'active' and amount > 0.
81
+ * null if no active paid purchase exists
82
+ */
83
+ activePaidPurchase: PurchaseInfo | null;
84
+ }
85
+ /**
86
+ * SolvaPay Provider Configuration
87
+ * Sensible defaults for minimal code, but fully customizable
88
+ */
89
+ interface SolvaPayConfig {
90
+ /**
91
+ * API route configuration
92
+ * Defaults to standard Next.js API routes
93
+ */
94
+ api?: {
95
+ checkPurchase?: string;
96
+ createPayment?: string;
97
+ processPayment?: string;
98
+ };
99
+ /**
100
+ * Authentication configuration
101
+ * Uses adapter pattern for flexible auth provider support
102
+ */
103
+ auth?: {
104
+ /**
105
+ * Auth adapter instance
106
+ * Default: checks localStorage for 'auth_token' key
107
+ *
108
+ * @example
109
+ * ```tsx
110
+ * import { createSupabaseAuthAdapter } from '@solvapay/react-supabase';
111
+ *
112
+ * <SolvaPayProvider
113
+ * config={{
114
+ * auth: {
115
+ * adapter: createSupabaseAuthAdapter({
116
+ * supabaseUrl: process.env.NEXT_PUBLIC_SUPABASE_URL!,
117
+ * supabaseAnonKey: process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!,
118
+ * })
119
+ * }
120
+ * }}
121
+ * >
122
+ * ```
123
+ */
124
+ adapter?: AuthAdapter;
125
+ /**
126
+ * @deprecated Use `adapter` instead. Will be removed in a future version.
127
+ * Function to get auth token
128
+ */
129
+ getToken?: () => Promise<string | null>;
130
+ /**
131
+ * @deprecated Use `adapter` instead. Will be removed in a future version.
132
+ * Function to get user ID (for cache key)
133
+ */
134
+ getUserId?: () => Promise<string | null>;
135
+ };
136
+ /**
137
+ * Custom fetch implementation
138
+ * Default: uses global fetch
139
+ */
140
+ fetch?: typeof fetch;
141
+ /**
142
+ * Request headers to include in all API calls
143
+ * Default: empty
144
+ */
145
+ headers?: HeadersInit | (() => Promise<HeadersInit>);
146
+ /**
147
+ * Custom error handler
148
+ * Default: logs to console
149
+ */
150
+ onError?: (error: Error, context: string) => void;
151
+ }
152
+ interface SolvaPayContextValue {
153
+ purchase: PurchaseStatus;
154
+ refetchPurchase: () => Promise<void>;
155
+ createPayment: (params: {
156
+ planRef: string;
157
+ productRef?: string;
158
+ }) => Promise<PaymentIntentResult>;
159
+ processPayment?: (params: {
160
+ paymentIntentId: string;
161
+ productRef: string;
162
+ planRef?: string;
163
+ }) => Promise<ProcessPaymentResult>;
164
+ customerRef?: string;
165
+ updateCustomerRef?: (newCustomerRef: string) => void;
166
+ }
4
167
  interface SolvaPayProviderProps {
168
+ /**
169
+ * Configuration object with sensible defaults
170
+ * If not provided, uses standard Next.js API routes
171
+ */
172
+ config?: SolvaPayConfig;
173
+ /**
174
+ * Custom API functions (override config defaults)
175
+ * Use only if you need custom logic beyond standard API routes
176
+ */
177
+ createPayment?: (params: {
178
+ planRef: string;
179
+ productRef?: string;
180
+ }) => Promise<PaymentIntentResult>;
181
+ checkPurchase?: () => Promise<CustomerPurchaseData>;
182
+ processPayment?: (params: {
183
+ paymentIntentId: string;
184
+ productRef: string;
185
+ planRef?: string;
186
+ }) => Promise<ProcessPaymentResult>;
5
187
  children: React.ReactNode;
6
- amount?: number;
188
+ }
189
+ interface ProductBadgeProps {
190
+ children?: (props: {
191
+ purchases: PurchaseInfo[];
192
+ loading: boolean;
193
+ displayPlan: string | null;
194
+ shouldShow: boolean;
195
+ }) => React.ReactNode;
196
+ as?: React.ElementType;
197
+ className?: string | ((props: {
198
+ purchases: PurchaseInfo[];
199
+ }) => string);
200
+ }
201
+ /** @deprecated Use ProductBadgeProps instead */
202
+ type PlanBadgeProps = ProductBadgeProps;
203
+ interface PurchaseGateProps {
204
+ /** @deprecated Use requireProduct instead */
205
+ requirePlan?: string;
206
+ requireProduct?: string;
207
+ children: (props: {
208
+ hasAccess: boolean;
209
+ purchases: PurchaseInfo[];
210
+ loading: boolean;
211
+ }) => React.ReactNode;
212
+ }
213
+ /**
214
+ * Error type for payment operations
215
+ */
216
+ interface PaymentError extends Error {
217
+ code?: string;
218
+ type?: string;
219
+ }
220
+ /**
221
+ * Plan interface for plans
222
+ */
223
+ interface Plan {
224
+ reference: string;
225
+ price?: number;
7
226
  currency?: string;
227
+ interval?: string;
228
+ features?: string[];
229
+ isFreeTier?: boolean;
230
+ metadata?: Record<string, unknown>;
231
+ }
232
+ /**
233
+ * Options for usePlans hook
234
+ */
235
+ interface UsePlansOptions {
236
+ /**
237
+ * Fetcher function to retrieve plans
238
+ */
239
+ fetcher: (productRef: string) => Promise<Plan[]>;
240
+ /**
241
+ * Product reference to fetch plans for
242
+ */
243
+ productRef?: string;
244
+ /**
245
+ * Optional filter function to filter plans
246
+ */
247
+ filter?: (plan: Plan) => boolean;
248
+ /**
249
+ * Optional sort function to sort plans
250
+ */
251
+ sortBy?: (a: Plan, b: Plan) => number;
252
+ /**
253
+ * Auto-select first paid plan on load
254
+ */
255
+ autoSelectFirstPaid?: boolean;
256
+ }
257
+ /**
258
+ * Return type for usePlans hook
259
+ */
260
+ interface UsePlansReturn {
261
+ plans: Plan[];
262
+ loading: boolean;
263
+ error: Error | null;
264
+ selectedPlanIndex: number;
265
+ selectedPlan: Plan | null;
266
+ setSelectedPlanIndex: (index: number) => void;
267
+ selectPlan: (planRef: string) => void;
268
+ refetch: () => Promise<void>;
269
+ }
270
+ /**
271
+ * Props for headless PricingSelector component
272
+ */
273
+ interface PricingSelectorProps {
274
+ /**
275
+ * Product reference to fetch plans for
276
+ */
277
+ productRef?: string;
278
+ /**
279
+ * Fetcher function to retrieve plans
280
+ */
281
+ fetcher: (productRef: string) => Promise<Plan[]>;
282
+ /**
283
+ * Optional filter function
284
+ */
285
+ filter?: (plan: Plan) => boolean;
286
+ /**
287
+ * Optional sort function
288
+ */
289
+ sortBy?: (a: Plan, b: Plan) => number;
290
+ /**
291
+ * Auto-select first paid plan on load
292
+ */
293
+ autoSelectFirstPaid?: boolean;
294
+ /**
295
+ * Render prop function
296
+ */
297
+ children: (props: UsePlansReturn & {
298
+ purchases: PurchaseInfo[];
299
+ isPaidPlan: (planRef: string) => boolean;
300
+ isCurrentPlan: (planRef: string) => boolean;
301
+ }) => React.ReactNode;
302
+ }
303
+ /** @deprecated Use PricingSelectorProps instead */
304
+ type PlanSelectorProps = PricingSelectorProps;
305
+ /**
306
+ * Return type for usePurchaseStatus hook
307
+ *
308
+ * Provides advanced purchase status helpers and utilities.
309
+ * Focuses on cancelled purchase logic and date formatting.
310
+ * For basic purchase data and paid status, use usePurchase() instead.
311
+ */
312
+ interface PurchaseStatusReturn {
313
+ /**
314
+ * Most recent cancelled paid purchase (sorted by startDate)
315
+ * null if no cancelled paid purchase exists
316
+ */
317
+ cancelledPurchase: PurchaseInfo | null;
318
+ /**
319
+ * Whether to show cancelled purchase notice
320
+ * true if cancelledPurchase exists
321
+ */
322
+ shouldShowCancelledNotice: boolean;
323
+ /**
324
+ * Format a date string to locale format (e.g., "January 15, 2024")
325
+ * Returns null if dateString is not provided
326
+ */
327
+ formatDate: (dateString?: string) => string | null;
328
+ /**
329
+ * Calculate days until expiration date
330
+ * Returns null if endDate is not provided, otherwise returns days (0 or positive)
331
+ */
332
+ getDaysUntilExpiration: (endDate?: string) => number | null;
333
+ }
334
+ /**
335
+ * Payment form props - simplified and minimal
336
+ */
337
+ interface PaymentFormProps {
338
+ /**
339
+ * Plan reference to checkout. PaymentForm handles the entire checkout flow internally
340
+ * including Stripe initialization and payment intent creation.
341
+ */
8
342
  planRef: string;
9
- agentRef: string;
10
- apiBaseUrl?: string;
11
- onPaymentReady?: (stripe: Stripe | null, clientSecret: string) => void;
343
+ /**
344
+ * Product reference. Required for processing payment after confirmation.
345
+ */
346
+ productRef?: string;
347
+ /**
348
+ * Callback when payment succeeds
349
+ */
350
+ onSuccess?: (paymentIntent: PaymentIntent) => void;
351
+ /**
352
+ * Callback when payment fails
353
+ */
354
+ onError?: (error: Error) => void;
355
+ /**
356
+ * Return URL after payment completion. Defaults to current page URL if not provided.
357
+ */
358
+ returnUrl?: string;
359
+ /**
360
+ * Text for the submit button. Defaults to "Pay Now"
361
+ */
362
+ submitButtonText?: string;
363
+ /**
364
+ * Optional className for the form container
365
+ */
366
+ className?: string;
367
+ /**
368
+ * Optional className for the submit button
369
+ */
370
+ buttonClassName?: string;
12
371
  }
372
+ type PurchaseStatusValue = 'pending' | 'active' | 'trialing' | 'past_due' | 'cancelled' | 'expired' | 'suspended' | 'refunded';
373
+
13
374
  /**
14
- * SolvaPay Payment Provider Component
375
+ * SolvaPay Provider - Headless Context Provider for React.
376
+ *
377
+ * Provides purchase state, payment methods, and customer data to child components
378
+ * via React Context. This is the root component that must wrap your app to use
379
+ * SolvaPay React hooks and components.
15
380
  *
16
- * Wraps children with Stripe Elements context after initializing a payment intent
17
- * via the backend API. This component handles the secure payment flow:
381
+ * Features:
382
+ * - Automatic purchase status checking
383
+ * - Customer reference caching in localStorage
384
+ * - Payment intent creation and processing
385
+ * - Authentication adapter support (Supabase, custom, etc.)
386
+ * - Zero-config with sensible defaults, or full customization
18
387
  *
19
- * 1. Calls backend API route to create payment intent (backend uses secret key)
20
- * 2. Backend returns clientSecret and publishableKey from Stripe
21
- * 3. Initializes Stripe.js with publishableKey
22
- * 4. Wraps children in Stripe Elements provider
388
+ * @param props - Provider configuration
389
+ * @param props.config - Configuration object for API routes and authentication
390
+ * @param props.config.api - API route configuration (optional, uses defaults if not provided)
391
+ * @param props.config.api.checkPurchase - Endpoint for checking purchase status (default: '/api/check-purchase')
392
+ * @param props.config.api.createPayment - Endpoint for creating payment intents (default: '/api/create-payment-intent')
393
+ * @param props.config.api.processPayment - Endpoint for processing payments (default: '/api/process-payment')
394
+ * @param props.config.auth - Authentication configuration (optional)
395
+ * @param props.config.auth.adapter - Auth adapter for extracting user ID and token
396
+ * @param props.children - React children components
23
397
  *
24
398
  * @example
25
399
  * ```tsx
26
- * // In your Next.js page
27
- * import { SolvaPayProvider, PaymentForm } from '@solvapay/react';
400
+ * import { SolvaPayProvider } from '@solvapay/react';
28
401
  *
29
- * export default function CheckoutPage() {
402
+ * // Zero config (uses defaults)
403
+ * function App() {
404
+ * return (
405
+ * <SolvaPayProvider>
406
+ * <YourApp />
407
+ * </SolvaPayProvider>
408
+ * );
409
+ * }
410
+ *
411
+ * // Custom API routes
412
+ * function App() {
30
413
  * return (
31
414
  * <SolvaPayProvider
32
- * amount={999}
33
- * currency="USD"
34
- * planRef="pln_abc123"
35
- * agentRef="agt_xyz789"
36
- * onPaymentReady={(stripe, clientSecret) => {
37
- * console.log('Payment ready!');
415
+ * config={{
416
+ * api: {
417
+ * checkPurchase: '/custom/api/purchase',
418
+ * createPayment: '/custom/api/payment'
419
+ * }
38
420
  * }}
39
421
  * >
40
- * <PaymentForm />
422
+ * <YourApp />
423
+ * </SolvaPayProvider>
424
+ * );
425
+ * }
426
+ *
427
+ * // With Supabase auth adapter
428
+ * import { createSupabaseAuthAdapter } from '@solvapay/react-supabase';
429
+ *
430
+ * function App() {
431
+ * const adapter = createSupabaseAuthAdapter({
432
+ * supabaseUrl: process.env.NEXT_PUBLIC_SUPABASE_URL!,
433
+ * supabaseAnonKey: process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!,
434
+ * });
435
+ *
436
+ * return (
437
+ * <SolvaPayProvider
438
+ * config={{
439
+ * auth: { adapter }
440
+ * }}
441
+ * >
442
+ * <YourApp />
41
443
  * </SolvaPayProvider>
42
444
  * );
43
445
  * }
44
446
  * ```
447
+ *
448
+ * @see {@link usePurchase} for accessing purchase data
449
+ * @see {@link useCheckout} for payment checkout flow
450
+ * @see {@link useSolvaPay} for accessing provider methods
451
+ * @since 1.0.0
45
452
  */
46
- declare const SolvaPayProvider: React.FC<SolvaPayProviderProps>;
453
+ declare const SolvaPayProvider: React$1.FC<SolvaPayProviderProps>;
47
454
 
48
- interface PaymentFormProps {
49
- onSuccess?: (paymentIntent: any) => void;
455
+ /**
456
+ * Payment form component for handling Stripe checkout.
457
+ *
458
+ * This component provides a complete payment form with Stripe integration,
459
+ * including card input, plan selection, and payment processing. It handles
460
+ * the entire checkout flow including payment intent creation and confirmation.
461
+ *
462
+ * Features:
463
+ * - Automatic Stripe Elements initialization
464
+ * - Payment intent creation on mount
465
+ * - Card input and validation
466
+ * - Payment processing with error handling
467
+ * - Automatic purchase refresh after payment
468
+ *
469
+ * @param props - Payment form configuration
470
+ * @param props.planRef - Plan reference to purchase (required)
471
+ * @param props.productRef - Product reference for usage tracking
472
+ * @param props.onSuccess - Callback when payment succeeds
473
+ * @param props.onError - Callback when payment fails
474
+ * @param props.returnUrl - Optional return URL after payment (for redirects)
475
+ * @param props.submitButtonText - Custom text for submit button (default: 'Pay Now')
476
+ * @param props.className - Custom CSS class for the form container
477
+ * @param props.buttonClassName - Custom CSS class for the submit button
478
+ *
479
+ * @example
480
+ * ```tsx
481
+ * import { PaymentForm } from '@solvapay/react';
482
+ * import { useRouter } from 'next/navigation';
483
+ *
484
+ * function CheckoutPage() {
485
+ * const router = useRouter();
486
+ *
487
+ * return (
488
+ * <PaymentForm
489
+ * planRef="pln_premium"
490
+ * productRef="prd_myapi"
491
+ * onSuccess={() => {
492
+ * console.log('Payment successful!');
493
+ * router.push('/dashboard');
494
+ * }}
495
+ * onError={(error) => {
496
+ * console.error('Payment failed:', error);
497
+ * }}
498
+ * />
499
+ * );
500
+ * }
501
+ * ```
502
+ *
503
+ * @see {@link useCheckout} for programmatic checkout handling
504
+ * @see {@link SolvaPayProvider} for required context provider
505
+ * @since 1.0.0
506
+ */
507
+ declare const PaymentForm: React$1.FC<PaymentFormProps>;
508
+
509
+ /**
510
+ * Headless Product Badge Component
511
+ *
512
+ * Displays purchase status with complete styling control.
513
+ * Supports render props, custom components, or className patterns.
514
+ *
515
+ * Prevents flickering by hiding the badge during initial load and when no purchase exists.
516
+ * Shows the badge once loading completes AND an active purchase exists (paid or free).
517
+ * Badge only updates when the product name actually changes (prevents unnecessary re-renders).
518
+ *
519
+ * Displays the primary active purchase (paid or free) to show current product status.
520
+ *
521
+ * @example
522
+ * ```tsx
523
+ * // Render prop pattern
524
+ * <ProductBadge>
525
+ * {({ purchases, loading, displayPlan, shouldShow }) => (
526
+ * shouldShow ? (
527
+ * <div>{displayPlan}</div>
528
+ * ) : null
529
+ * )}
530
+ * </ProductBadge>
531
+ *
532
+ * //ClassName pattern
533
+ * <ProductBadge className="badge badge-primary" />
534
+ * ```
535
+ */
536
+ declare const ProductBadge: React$1.FC<ProductBadgeProps>;
537
+ /** @deprecated Use ProductBadge instead */
538
+ declare const PlanBadge: React$1.FC<ProductBadgeProps>;
539
+
540
+ /**
541
+ * Headless Purchase Gate Component
542
+ *
543
+ * Controls access to content based on purchase status.
544
+ * Uses render props to give developers full control over locked/unlocked states.
545
+ *
546
+ * @example
547
+ * ```tsx
548
+ * <PurchaseGate requireProduct="Pro Plan">
549
+ * {({ hasAccess, loading }) => {
550
+ * if (loading) return <Skeleton />;
551
+ * if (!hasAccess) return <Paywall />;
552
+ * return <PremiumContent />;
553
+ * }}
554
+ * </PurchaseGate>
555
+ * ```
556
+ */
557
+ declare const PurchaseGate: React$1.FC<PurchaseGateProps>;
558
+
559
+ /**
560
+ * Headless Pricing Selector Component
561
+ *
562
+ * Provides pricing selection logic with complete styling control via render props.
563
+ * Integrates plan fetching, purchase status, and selection state management.
564
+ *
565
+ * Features:
566
+ * - Fetches and manages pricing options
567
+ * - Tracks selected option
568
+ * - Provides helpers for checking if option is current/paid
569
+ * - Integrates with purchase context
570
+ *
571
+ * @example
572
+ * ```tsx
573
+ * <PricingSelector
574
+ * productRef="prd_123"
575
+ * fetcher={async (productRef) => {
576
+ * const res = await fetch(`/api/list-plans?productRef=${productRef}`);
577
+ * const data = await res.json();
578
+ * return data.plans;
579
+ * }}
580
+ * sortBy={(a, b) => (a.price || 0) - (b.price || 0)}
581
+ * autoSelectFirstPaid
582
+ * >
583
+ * {({ plans, selectedPlan, setSelectedPlanIndex, loading, isPaidPlan, isCurrentPlan }) => (
584
+ * <div>
585
+ * {loading ? (
586
+ * <div>Loading...</div>
587
+ * ) : (
588
+ * plans.map((plan, index) => (
589
+ * <button
590
+ * key={plan.reference}
591
+ * onClick={() => setSelectedPlanIndex(index)}
592
+ * disabled={!isPaidPlan(plan.reference)}
593
+ * >
594
+ * ${plan.price}/{plan.interval}
595
+ * {isCurrentPlan(plan.reference) && ' (Current)'}
596
+ * </button>
597
+ * ))
598
+ * )}
599
+ * </div>
600
+ * )}
601
+ * </PricingSelector>
602
+ * ```
603
+ */
604
+ declare const PricingSelector: React$1.FC<PricingSelectorProps>;
605
+ /** @deprecated Use PricingSelector instead */
606
+ declare const PlanSelector: React$1.FC<PricingSelectorProps>;
607
+
608
+ /**
609
+ * SVG-based spinner component using CSS animations
610
+ * Uses the same spinner design as the rest of the site
611
+ */
612
+ declare const Spinner: React$1.FC<{
613
+ className?: string;
614
+ size?: 'sm' | 'md' | 'lg';
615
+ }>;
616
+
617
+ interface StripePaymentFormWrapperProps {
618
+ onSuccess?: (paymentIntent: unknown) => void | Promise<void>;
50
619
  onError?: (error: Error) => void;
51
620
  returnUrl?: string;
52
621
  submitButtonText?: string;
53
- className?: string;
622
+ buttonClassName?: string;
623
+ clientSecret: string;
54
624
  }
55
625
  /**
56
- * SolvaPay Payment Form Component
626
+ * Stripe Payment Form Wrapper Component
627
+ * Renders inside Stripe Elements context and handles the payment flow
628
+ * All hooks are called unconditionally to comply with React Rules of Hooks
629
+ */
630
+ declare const StripePaymentFormWrapper: React$1.FC<StripePaymentFormWrapperProps>;
631
+
632
+ /**
633
+ * Hook to get current purchase status and information.
57
634
  *
58
- * Renders a payment form using Stripe's PaymentElement for secure card input.
59
- * This component must be wrapped in a SolvaPayProvider to work properly.
635
+ * Returns the current user's purchase status, including active
636
+ * purchases, plan details, and payment information. Automatically
637
+ * syncs with the SolvaPay backend and handles loading and error states.
638
+ *
639
+ * @returns Purchase data and status
640
+ * @returns purchases - Array of active purchases
641
+ * @returns hasPaidPurchase - Whether user has any paid purchase
642
+ * @returns isLoading - Loading state
643
+ * @returns error - Error state if purchase check fails
644
+ * @returns refetch - Function to manually refetch purchase data
60
645
  *
61
646
  * @example
62
647
  * ```tsx
63
- * import { SolvaPayProvider, PaymentForm } from '@solvapay/react';
648
+ * import { usePurchase } from '@solvapay/react';
649
+ *
650
+ * function Dashboard() {
651
+ * const { purchases, hasPaidPurchase, isLoading, refetch } = usePurchase();
652
+ *
653
+ * if (isLoading) return <Spinner />;
654
+ *
655
+ * if (!hasPaidPurchase) {
656
+ * return <UpgradePrompt />;
657
+ * }
64
658
  *
65
- * export default function CheckoutPage() {
66
659
  * return (
67
- * <SolvaPayProvider amount={999} planRef="pln_abc123">
68
- * <PaymentForm
69
- * returnUrl={`${window.location.origin}/checkout/success`}
70
- * onSuccess={(paymentIntent) => {
71
- * console.log('Payment successful!', paymentIntent);
72
- * }}
73
- * onError={(error) => {
74
- * console.error('Payment failed:', error);
75
- * }}
76
- * />
77
- * </SolvaPayProvider>
660
+ * <div>
661
+ * <h2>Welcome, Premium User!</h2>
662
+ * <p>Active purchases: {purchases.length}</p>
663
+ * <button onClick={() => refetch()}>Refresh</button>
664
+ * </div>
665
+ * );
666
+ * }
667
+ * ```
668
+ *
669
+ * @see {@link SolvaPayProvider} for required context provider
670
+ * @see {@link usePurchaseStatus} for detailed status information
671
+ * @since 1.0.0
672
+ */
673
+ declare function usePurchase(): PurchaseStatus & {
674
+ refetch: () => Promise<void>;
675
+ };
676
+
677
+ /**
678
+ * Customer information interface
679
+ */
680
+ interface CustomerInfo {
681
+ /**
682
+ * Customer reference ID
683
+ */
684
+ customerRef?: string;
685
+ /**
686
+ * Customer email address
687
+ */
688
+ email?: string;
689
+ /**
690
+ * Customer name
691
+ */
692
+ name?: string;
693
+ /**
694
+ * Whether customer data is currently loading
695
+ */
696
+ loading: boolean;
697
+ }
698
+ /**
699
+ * Hook to access customer information
700
+ * Returns customer data (email, name, customerRef) separate from purchase data
701
+ *
702
+ * @example
703
+ * ```tsx
704
+ * import { useCustomer } from '@solvapay/react';
705
+ *
706
+ * function MyComponent() {
707
+ * const { email, name, customerRef } = useCustomer();
708
+ *
709
+ * return (
710
+ * <div>
711
+ * <p>Email: {email || 'Not provided'}</p>
712
+ * <p>Name: {name || 'Not provided'}</p>
713
+ * </div>
78
714
  * );
79
715
  * }
80
716
  * ```
81
717
  */
82
- declare const PaymentForm: React.FC<PaymentFormProps>;
718
+ declare function useCustomer(): CustomerInfo;
719
+
720
+ interface UseCheckoutReturn {
721
+ loading: boolean;
722
+ error: Error | null;
723
+ stripePromise: Promise<Stripe | null> | null;
724
+ clientSecret: string | null;
725
+ startCheckout: () => Promise<void>;
726
+ reset: () => void;
727
+ }
728
+ /**
729
+ * Hook to manage checkout flow for payment processing.
730
+ *
731
+ * Handles payment intent creation and Stripe initialization. This hook
732
+ * manages the checkout state including loading, errors, Stripe instance,
733
+ * and client secret. Use this for programmatic checkout flows.
734
+ *
735
+ * @param options - Checkout options
736
+ * @param options.planRef - Plan reference to purchase (required)
737
+ * @param options.productRef - Optional product reference for usage tracking
738
+ * @returns Checkout state and methods
739
+ * @returns loading - Whether checkout is in progress
740
+ * @returns error - Error state if checkout fails
741
+ * @returns stripePromise - Promise resolving to Stripe instance
742
+ * @returns clientSecret - Stripe payment intent client secret
743
+ * @returns startCheckout - Function to start the checkout process
744
+ * @returns reset - Function to reset checkout state
745
+ *
746
+ * @example
747
+ * ```tsx
748
+ * import { useCheckout } from '@solvapay/react';
749
+ * import { PaymentElement } from '@stripe/react-stripe-js';
750
+ *
751
+ * function CustomCheckout() {
752
+ * const { loading, error, stripePromise, clientSecret, startCheckout } = useCheckout({
753
+ * planRef: 'pln_premium',
754
+ * productRef: 'prd_myapi',
755
+ * });
756
+ *
757
+ * useEffect(() => {
758
+ * startCheckout();
759
+ * }, []);
760
+ *
761
+ * if (loading) return <Spinner />;
762
+ * if (error) return <div>Error: {error.message}</div>;
763
+ * if (!clientSecret || !stripePromise) return null;
764
+ *
765
+ * return (
766
+ * <Elements stripe={await stripePromise} options={{ clientSecret }}>
767
+ * <PaymentElement />
768
+ * </Elements>
769
+ * );
770
+ * }
771
+ * ```
772
+ *
773
+ * @see {@link PaymentForm} for a complete payment form component
774
+ * @see {@link SolvaPayProvider} for required context provider
775
+ * @since 1.0.0
776
+ */
777
+ declare function useCheckout(options: {
778
+ planRef: string;
779
+ productRef?: string;
780
+ }): UseCheckoutReturn;
781
+
782
+ /**
783
+ * Hook to access SolvaPay context and provider methods.
784
+ *
785
+ * This is the base hook that provides access to all SolvaPay functionality
786
+ * including purchase data, payment methods, and customer information.
787
+ * Other hooks like `usePurchase` and `useCheckout` use this internally.
788
+ *
789
+ * Must be used within a `SolvaPayProvider` component.
790
+ *
791
+ * @returns SolvaPay context value with all provider methods and state
792
+ * @returns purchase - Purchase status and data
793
+ * @returns createPayment - Function to create payment intents
794
+ * @returns processPayment - Function to process payments
795
+ * @returns customerRef - Current customer reference
796
+ * @returns refetchPurchase - Function to refetch purchase data
797
+ *
798
+ * @example
799
+ * ```tsx
800
+ * import { useSolvaPay } from '@solvapay/react';
801
+ *
802
+ * function CustomComponent() {
803
+ * const { purchase, createPayment, processPayment } = useSolvaPay();
804
+ *
805
+ * const handlePayment = async () => {
806
+ * const intent = await createPayment({
807
+ * planRef: 'pln_premium',
808
+ * productRef: 'prd_myapi'
809
+ * });
810
+ * // Process payment...
811
+ * };
812
+ *
813
+ * return <div>Purchase status: {purchase.hasPaidPurchase ? 'Active' : 'None'}</div>;
814
+ * }
815
+ * ```
816
+ *
817
+ * @throws {Error} If used outside of SolvaPayProvider
818
+ * @see {@link SolvaPayProvider} for required context provider
819
+ * @see {@link usePurchase} for purchase-specific hook
820
+ * @see {@link useCheckout} for checkout-specific hook
821
+ * @since 1.0.0
822
+ */
823
+ declare function useSolvaPay(): SolvaPayContextValue;
824
+
825
+ /**
826
+ * Hook to manage plan fetching and selection
827
+ *
828
+ * Provides a reusable way to fetch, filter, sort and select plans.
829
+ * Handles loading and error states automatically.
830
+ * Uses a global cache to prevent duplicate fetches when multiple components use the same productRef.
831
+ *
832
+ * @example
833
+ * ```tsx
834
+ * const plans = usePlans({
835
+ * productRef: 'prd_123',
836
+ * fetcher: async (productRef) => {
837
+ * const res = await fetch(`/api/list-plans?productRef=${productRef}`);
838
+ * const data = await res.json();
839
+ * return data.plans;
840
+ * },
841
+ * sortBy: (a, b) => (a.price || 0) - (b.price || 0),
842
+ * autoSelectFirstPaid: true,
843
+ * });
844
+ *
845
+ * // Use in component
846
+ * if (plans.loading) return <div>Loading...</div>;
847
+ * if (plans.error) return <div>Error: {plans.error.message}</div>;
848
+ * ```
849
+ */
850
+ declare function usePlans(options: UsePlansOptions): UsePlansReturn;
851
+
852
+ /**
853
+ * Hook providing advanced status and helper functions for purchase management
854
+ *
855
+ * Focuses on cancelled purchase logic and date formatting utilities.
856
+ * For basic purchase data and paid status checks, use usePurchase() instead.
857
+ *
858
+ * @example
859
+ * ```tsx
860
+ * const { cancelledPurchase, shouldShowCancelledNotice, formatDate, getDaysUntilExpiration } = usePurchaseStatus();
861
+ *
862
+ * if (shouldShowCancelledNotice && cancelledPurchase) {
863
+ * const formattedDate = formatDate(cancelledPurchase.endDate);
864
+ * const daysLeft = getDaysUntilExpiration(cancelledPurchase.endDate);
865
+ * }
866
+ * ```
867
+ */
868
+ declare function usePurchaseStatus(): PurchaseStatusReturn;
869
+
870
+ /**
871
+ * Purchase utility functions
872
+ *
873
+ * Provides shared logic for filtering and prioritizing purchases
874
+ */
875
+
876
+ /**
877
+ * Filter purchases to only include active ones
878
+ *
879
+ * Rules:
880
+ * - Keep purchases with status === 'active'
881
+ * - Filter out purchases with status === 'cancelled', 'expired', 'suspended', 'refunded', etc.
882
+ *
883
+ * Note: Backend now keeps purchases with status 'active' until expiration,
884
+ * even when cancelled. Cancellation is tracked via cancelledAt field.
885
+ */
886
+ declare function filterPurchases(purchases: PurchaseInfo[]): PurchaseInfo[];
887
+ /**
888
+ * Get active purchases
889
+ *
890
+ * Returns purchases with status === 'active'.
891
+ * Note: Backend keeps purchases as 'active' until expiration, even when cancelled.
892
+ * Use cancelledAt field to check if a purchase is cancelled.
893
+ */
894
+ declare function getActivePurchases(purchases: PurchaseInfo[]): PurchaseInfo[];
895
+ /**
896
+ * Get cancelled purchases with valid endDate (not expired)
897
+ *
898
+ * Returns purchases with cancelledAt set and status === 'active' that have a future endDate.
899
+ * Backend keeps cancelled purchases as 'active' until expiration.
900
+ */
901
+ declare function getCancelledPurchasesWithEndDate(purchases: PurchaseInfo[]): PurchaseInfo[];
902
+ /**
903
+ * Get the most recent purchase by startDate
904
+ */
905
+ declare function getMostRecentPurchase(purchases: PurchaseInfo[]): PurchaseInfo | null;
906
+ /**
907
+ * Get the primary purchase to display
908
+ *
909
+ * Prioritization:
910
+ * 1. Active purchases (most recent by startDate)
911
+ * 2. null if no valid purchases
912
+ *
913
+ * Note: Backend keeps purchases as 'active' until expiration, so we only
914
+ * need to check for active purchases. Cancelled purchases are still
915
+ * active until their endDate.
916
+ */
917
+ declare function getPrimaryPurchase(purchases: PurchaseInfo[]): PurchaseInfo | null;
918
+ /**
919
+ * Check if a purchase is paid
920
+ * Uses purchase amount field: amount > 0 = paid, amount === 0 or undefined = free
921
+ *
922
+ * @param purchase - Purchase to check
923
+ * @returns true if purchase is paid (amount > 0)
924
+ */
925
+ declare function isPaidPurchase(purchase: PurchaseInfo): boolean;
83
926
 
84
- export { PaymentForm, type PaymentFormProps, SolvaPayProvider, type SolvaPayProviderProps };
927
+ export { AuthAdapter, type CustomerInfo, type CustomerPurchaseData, type PaymentError, PaymentForm, type PaymentFormProps, type PaymentIntentResult, type Plan, PlanBadge, type PlanBadgeProps, PlanSelector, type PlanSelectorProps, PricingSelector, type PricingSelectorProps, ProductBadge, type ProductBadgeProps, PurchaseGate, type PurchaseGateProps, type PurchaseInfo, type PurchaseStatus, type PurchaseStatusReturn, type PurchaseStatusValue, type SolvaPayConfig, type SolvaPayContextValue, SolvaPayProvider, type SolvaPayProviderProps, Spinner, StripePaymentFormWrapper, type UsePlansOptions, type UsePlansReturn, filterPurchases, getActivePurchases, getCancelledPurchasesWithEndDate, getMostRecentPurchase, getPrimaryPurchase, isPaidPurchase, useCheckout, useCustomer, usePlans, usePurchase, usePurchaseStatus, useSolvaPay };