@qazuor/qzpay-react
v1.1.0
Published
React hooks and components for QZPay billing library
Maintainers
Readme
@qazuor/qzpay-react
React hooks and components for the QZPay billing library.
Installation
pnpm add @qazuor/qzpay-react reactFeatures
- Provider Context: Global billing context
- Data Hooks: Fetch and manage billing data
- Mutation Hooks: Create/update operations
- Theme System: Customizable styling
- Accessibility: WCAG 2.1 AA compliant with ARIA support
- Error Boundary: Graceful error handling for components
- TypeScript: Full type safety
Usage
Provider Setup
import { QZPayProvider } from '@qazuor/qzpay-react';
function App() {
return (
<QZPayProvider config={{
baseUrl: '/api/billing',
headers: { 'Authorization': 'Bearer token' }
}}>
<YourApp />
</QZPayProvider>
);
}Customer Hooks
import { useCustomer, useCustomers } from '@qazuor/qzpay-react';
function CustomerProfile() {
const { customer, isLoading, error } = useCustomer('cus_123');
if (isLoading) return <div>Loading...</div>;
if (error) return <div>Error: {error.message}</div>;
return (
<div>
<h1>{customer?.name}</h1>
<p>{customer?.email}</p>
</div>
);
}Subscription Hooks
import { useSubscriptions, useCreateSubscription } from '@qazuor/qzpay-react';
function SubscriptionManager({ customerId }) {
const { subscriptions, isLoading } = useSubscriptions(customerId);
const { createSubscription, isCreating } = useCreateSubscription();
const handleSubscribe = async (planId) => {
await createSubscription({ customerId, planId });
};
return (
<div>
{subscriptions?.map(sub => (
<div key={sub.id}>
{sub.planId} - {sub.status}
</div>
))}
</div>
);
}Payment Hooks
import { usePayments, useProcessPayment } from '@qazuor/qzpay-react';
function PaymentHistory({ customerId }) {
const { payments } = usePayments(customerId);
const { processPayment, isProcessing } = useProcessPayment();
const handlePayment = async () => {
await processPayment({
customerId,
amount: 2999,
currency: 'USD'
});
};
return (
<div>
<button onClick={handlePayment} disabled={isProcessing}>
Pay $29.99
</button>
{payments?.map(p => (
<div key={p.id}>{p.amount} - {p.status}</div>
))}
</div>
);
}Plan Hooks
import { usePlans } from '@qazuor/qzpay-react';
function PlanSelector({ onSelect }) {
const { plans, isLoading } = usePlans();
return (
<div className="plans-grid">
{plans?.map(plan => (
<div key={plan.id} onClick={() => onSelect(plan)}>
<h3>{plan.name}</h3>
<p>{plan.description}</p>
</div>
))}
</div>
);
}Available Hooks
Context Hooks
useQZPayContext()- Get the full QZPay context (billing instance, customer, etc.)useQZPay()- Get the billing instance directlyuseQZPayLivemode()- Check if running in live modeuseCurrentCustomer()- Get the current customer from context
Data Hooks
useCustomer(customerId)- Get customer by ID with helper methodsuseSubscription(customerId, options?)- Get active subscription with helpersusePlans()- Get available plans with pricinguseEntitlements(customerId)- Check feature entitlementsuseLimits(customerId)- Check usage limitsusePayment(customerId, options?)- Process paymentsuseInvoices(customerId, options?)- List customer invoices
Utility Hooks
useIsomorphicLayoutEffect()- SSR-safe useLayoutEffect
Components
PricingTable
Display pricing plans with selection:
import { PricingTable } from '@qazuor/qzpay-react';
<PricingTable
plans={plans}
currentPlanId={subscription?.planId}
onSelect={(plan) => handlePlanSelect(plan)}
currency="USD"
/>SubscriptionStatus
Display subscription status with actions:
import { SubscriptionStatus } from '@qazuor/qzpay-react';
<SubscriptionStatus
subscription={subscription}
onCancel={() => handleCancel()}
onPause={() => handlePause()}
onResume={() => handleResume()}
/>EntitlementGate
Conditionally render content based on entitlements:
import { EntitlementGate } from '@qazuor/qzpay-react';
<EntitlementGate
customerId="cus_123"
entitlementKey="advanced_analytics"
fallback={<UpgradePrompt />}
>
<AdvancedAnalyticsDashboard />
</EntitlementGate>LimitGate
Conditionally render content based on usage limits:
import { LimitGate } from '@qazuor/qzpay-react';
<LimitGate
customerId="cus_123"
limitKey="api_calls"
fallback={<LimitReachedMessage />}
>
<APICallButton />
</LimitGate>PaymentForm
Collect payment information:
import { PaymentForm } from '@qazuor/qzpay-react';
<PaymentForm
amount={2999}
currency="USD"
onSubmit={async (data) => {
await processPayment(data);
}}
onSuccess={() => showSuccessMessage()}
onError={(error) => showErrorMessage(error)}
/>CheckoutButton
Quick checkout button:
import { CheckoutButton } from '@qazuor/qzpay-react';
<CheckoutButton
planId="plan_pro"
customerId="cus_123"
onSuccess={(result) => redirectToSuccess(result)}
>
Subscribe to Pro
</CheckoutButton>InvoiceList
Display customer invoices:
import { InvoiceList } from '@qazuor/qzpay-react';
<InvoiceList
customerId="cus_123"
onDownload={(invoice) => downloadInvoicePdf(invoice)}
onPay={(invoice) => payInvoice(invoice)}
/>PaymentMethodManager
Manage customer payment methods:
import { PaymentMethodManager } from '@qazuor/qzpay-react';
<PaymentMethodManager
customerId="cus_123"
onAdd={() => openAddPaymentMethodModal()}
onRemove={(pm) => removePaymentMethod(pm)}
onSetDefault={(pm) => setDefaultPaymentMethod(pm)}
/>Theme System
import { QZPayThemeProvider } from '@qazuor/qzpay-react';
const customTheme = {
colors: {
primary: '#6366f1',
success: '#22c55e',
error: '#ef4444'
},
spacing: {
sm: '0.5rem',
md: '1rem',
lg: '1.5rem'
}
};
function App() {
return (
<QZPayThemeProvider theme={customTheme}>
<QZPayProvider config={config}>
<YourApp />
</QZPayProvider>
</QZPayThemeProvider>
);
}Accessibility
All components are WCAG 2.1 AA compliant with full accessibility support:
import { PricingTable, SubscriptionStatus, PaymentForm } from '@qazuor/qzpay-react';
// All components include:
// - ARIA labels and descriptions
// - Semantic HTML roles
// - Keyboard navigation support
// - Screen reader announcements
// - Focus management
function AccessibleBillingUI() {
return (
<div>
{/* PricingTable with ARIA attributes */}
<PricingTable
plans={plans}
onSelect={handleSelect}
// Automatically includes:
// - role="region"
// - aria-label="Pricing plans"
// - aria-describedby for plan descriptions
/>
{/* SubscriptionStatus with live region */}
<SubscriptionStatus
subscription={subscription}
// Includes:
// - aria-live="polite" for status changes
// - Semantic status indicators
/>
{/* PaymentForm with validation messages */}
<PaymentForm
onSubmit={handlePayment}
// Includes:
// - aria-invalid for validation
// - aria-describedby for error messages
// - Keyboard accessible buttons
/>
</div>
);
}Error Boundary
Wrap components with ErrorBoundary for graceful error handling:
import { QZPayErrorBoundary } from '@qazuor/qzpay-react';
// Basic usage with default fallback
function App() {
return (
<QZPayErrorBoundary>
<PricingTable plans={plans} onSelect={handleSelect} />
</QZPayErrorBoundary>
);
}
// Custom fallback UI
function AppWithCustomFallback() {
return (
<QZPayErrorBoundary
fallback={
<div>
<h3>Oops! Something went wrong</h3>
<button onClick={() => window.location.reload()}>
Reload Page
</button>
</div>
}
>
<PaymentForm {...props} />
</QZPayErrorBoundary>
);
}
// Dynamic fallback based on error
function AppWithDynamicFallback() {
return (
<QZPayErrorBoundary
fallback={(error) => (
<div>
<h3>Payment Error</h3>
<p>{error.message}</p>
<button onClick={retryPayment}>Try Again</button>
</div>
)}
onError={(error, errorInfo) => {
// Log to error tracking service
logErrorToSentry(error, errorInfo);
}}
>
<CheckoutFlow {...props} />
</QZPayErrorBoundary>
);
}Fixed Issues
- usePlans Hook: Fixed API endpoint call and data fetching logic.
- Accessibility: All components now include proper ARIA attributes.
- Error Handling: Added ErrorBoundary component for robust error management.
License
MIT
