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

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