UNPKG

@cardql/react

Version:

CardQL SDK for React web applications with hooks and context providers

585 lines (461 loc) 11.6 kB
# @cardql/react CardQL SDK for React web applications with hooks, context providers, and pre-built components. ## Installation ```bash npm install @cardql/react # or yarn add @cardql/react # or pnpm add @cardql/react ``` ## Quick Start ### 1. Setup Provider Wrap your app with the CardQL provider: ```tsx import React from "react"; import { CardQLProvider } from "@cardql/react"; function App() { return ( <CardQLProvider config={{ apiKey: "your-api-key", endpoint: "https://api.cardql.com/graphql", }}> <YourApp /> </CardQLProvider> ); } ``` ### 2. Use Hooks Use CardQL hooks in your components: ```tsx import React from "react"; import { usePayments, useCreatePayment } from "@cardql/react"; function PaymentList() { const { data: paymentsData, loading, error } = usePayments(); const createPayment = useCreatePayment({ onSuccess: (data) => { console.log("Payment created:", data.createPayment); }, }); const handleCreatePayment = async () => { await createPayment.mutateAsync({ amount: "10.00", currency: "USD", merchantID: "merchant_123", userID: "user_456", }); }; if (loading) return <div>Loading...</div>; if (error) return <div>Error: {error.message}</div>; return ( <div> <h2>Payments</h2> <button onClick={handleCreatePayment} disabled={createPayment.loading}> {createPayment.loading ? "Creating..." : "Create Payment"} </button> {paymentsData?.payments.map((payment) => ( <div key={payment.id}> {payment.amount} {payment.currency} - {payment.status} </div> ))} </div> ); } ``` ### 3. Use Pre-built Components Use ready-made components: ```tsx import React from "react"; import { PaymentForm } from "@cardql/react"; function CheckoutPage() { return ( <div> <h1>Checkout</h1> <PaymentForm merchantID="merchant_123" userID="user_456" onSuccess={(payment) => { console.log("Payment successful:", payment); // Redirect to success page }} onError={(error) => { console.error("Payment failed:", error); // Show error message }} /> </div> ); } ``` ## API Reference ### Provider #### CardQLProvider ```tsx interface CardQLProviderProps { config: CardQLConfig; children: ReactNode; } <CardQLProvider config={{ apiKey: "...", endpoint: "..." }}> <App /> </CardQLProvider>; ``` ### Context Hooks #### useCardQL() Access the CardQL context: ```tsx const { cardql, config } = useCardQL(); ``` #### useCardQLClient() Get the CardQL client directly: ```tsx const cardql = useCardQLClient(); ``` #### useCardQLApi() Get the CardQL API directly: ```tsx const api = useCardQLApi(); ``` ### Data Fetching Hooks #### useQuery() Generic hook for GraphQL queries: ```tsx const { data, loading, error, refetch } = useQuery( "query GetPayments { payments { id amount status } }", variables, { enabled: true, refetchOnMount: true, refetchInterval: 30000, onSuccess: (data) => console.log(data), onError: (error) => console.error(error), } ); ``` #### useMutation() Generic hook for GraphQL mutations: ```tsx const { data, loading, error, mutate, mutateAsync } = useMutation( "mutation CreatePayment($input: CreatePaymentInput!) { createPayment(input: $input) { id } }", { onSuccess: (data, variables) => console.log("Success:", data), onError: (error, variables) => console.error("Error:", error), onSettled: (data, error, variables) => console.log("Settled"), } ); ``` ### Entity-Specific Hooks #### Account Hooks ```tsx // Query hooks const { data, loading, error } = useAccounts(); const { data, loading, error } = useAccount(accountID); // Mutation hooks const createAccount = useCreateAccount(); const updateAccount = useUpdateAccount(); const deleteAccount = useDeleteAccount(); ``` #### Customer Hooks ```tsx // Query hooks const { data, loading, error } = useCustomers(); const { data, loading, error } = useCustomer(customerID); // Mutation hooks const createCustomer = useCreateCustomer({ onSuccess: (data) => { console.log("Customer created:", data.createCustomer); }, }); // Usage await createCustomer.mutateAsync({ firstName: "John", lastName: "Doe", email: "john@example.com", }); ``` #### Payment Hooks ```tsx // Query hooks const { data, loading, error } = usePayments(); const { data, loading, error } = usePayment(paymentID); // Mutation hooks const createPayment = useCreatePayment(); const updatePayment = useUpdatePayment(); const deletePayment = useDeletePayment(); // Usage const handlePayment = async () => { try { const result = await createPayment.mutateAsync({ amount: "25.99", currency: "USD", merchantID: "merchant_123", userID: "user_456", description: "Product purchase", }); console.log("Payment created:", result.createPayment); } catch (error) { console.error("Payment failed:", error); } }; ``` #### Merchant Hooks ```tsx const { data, loading, error } = useMerchants(); const { data, loading, error } = useMerchant(merchantID); const createMerchant = useCreateMerchant(); const updateMerchant = useUpdateMerchant(); const deleteMerchant = useDeleteMerchant(); ``` #### Ledger Hooks ```tsx const { data, loading, error } = useLedgers(); const { data, loading, error } = useLedger(ledgerID); const createLedger = useCreateLedger(); const updateLedger = useUpdateLedger(); const deleteLedger = useDeleteLedger(); ``` ### Components #### PaymentForm Pre-built payment form component: ```tsx <PaymentForm merchantID="merchant_123" userID="user_456" onSuccess={(payment) => { // Handle successful payment router.push("/success"); }} onError={(error) => { // Handle payment error setErrorMessage(error.message); }} className="custom-payment-form" disabled={false} /> ``` ## Advanced Usage ### Custom Queries Execute custom GraphQL queries: ```tsx import { useQuery } from "@cardql/react"; function CustomPaymentList() { const { data, loading, error } = useQuery( ` query GetPaymentsByMerchant($merchantID: String!) { payments(where: { merchantID: $merchantID }) { id amount currency status customer { firstName lastName } } } `, { merchantID: "merchant_123", } ); // ... render logic } ``` ### Polling and Real-time Updates ```tsx // Poll every 30 seconds const { data } = usePayments({ refetchInterval: 30000, }); // Manual refetch const { data, refetch } = usePayments(); const handleRefresh = () => { refetch(); }; ``` ### Error Handling ```tsx import { usePayments, useCreatePayment } from "@cardql/react"; function PaymentComponent() { const { data, loading, error } = usePayments({ onError: (error) => { console.error("Failed to load payments:", error); // Send to error tracking service }, }); const createPayment = useCreatePayment({ onError: (error, variables) => { console.error("Payment creation failed:", error); // Show user-friendly error message if (error.code === "INSUFFICIENT_FUNDS") { alert("Insufficient funds"); } else { alert("Payment failed. Please try again."); } }, }); // ... component logic } ``` ### Loading States ```tsx function PaymentList() { const { data, loading, error } = usePayments(); const createPayment = useCreatePayment(); if (loading) { return <PaymentSkeleton />; } if (error) { return <ErrorMessage error={error} />; } return ( <div> <button onClick={() => createPayment.mutate(paymentData)} disabled={createPayment.loading}> {createPayment.loading ? <Spinner /> : "Create Payment"} </button> {/* Payment list */} </div> ); } ``` ### Form Integration ```tsx import { useForm } from "react-hook-form"; import { useCreateCustomer } from "@cardql/react"; function CustomerForm() { const { register, handleSubmit, reset } = useForm(); const createCustomer = useCreateCustomer({ onSuccess: () => { reset(); // Clear form on success }, }); const onSubmit = async (data) => { await createCustomer.mutateAsync(data); }; return ( <form onSubmit={handleSubmit(onSubmit)}> <input {...register("firstName")} placeholder="First Name" /> <input {...register("lastName")} placeholder="Last Name" /> <input {...register("email")} placeholder="Email" /> <button type="submit" disabled={createCustomer.loading}> {createCustomer.loading ? "Creating..." : "Create Customer"} </button> </form> ); } ``` ## TypeScript Support The React SDK is fully typed: ```tsx import type { Payment, CreatePaymentInput } from "@cardql/react"; const createPayment = useCreatePayment(); // TypeScript knows the exact shape of the data const handleSubmit = async (input: CreatePaymentInput) => { const result = await createPayment.mutateAsync(input); // result.createPayment is typed as Payment console.log(result.createPayment.id); }; ``` ## Styling The pre-built components use CSS classes that you can style: ```css .cardql-payment-form { max-width: 400px; padding: 20px; border: 1px solid #ddd; border-radius: 8px; } .cardql-form-field { margin-bottom: 16px; } .cardql-form-field label { display: block; margin-bottom: 4px; font-weight: 500; } .cardql-form-field input, .cardql-form-field select { width: 100%; padding: 8px 12px; border: 1px solid #ccc; border-radius: 4px; } .cardql-error { color: #dc3545; margin-bottom: 16px; padding: 8px; background-color: #f8d7da; border-radius: 4px; } .cardql-submit-button { width: 100%; padding: 12px; background-color: #007bff; color: white; border: none; border-radius: 4px; cursor: pointer; } .cardql-submit-button:disabled { background-color: #6c757d; cursor: not-allowed; } ``` ## Best Practices ### 1. Provider Placement Place the CardQL provider at the highest level where you need CardQL functionality: ```tsx // ✅ Good - wrap entire app function App() { return ( <CardQLProvider config={config}> <Router> <Routes> <Route path="/payments" component={PaymentPage} /> <Route path="/customers" component={CustomerPage} /> </Routes> </Router> </CardQLProvider> ); } ``` ### 2. Error Boundaries Use error boundaries to catch and handle errors: ```tsx import { ErrorBoundary } from "react-error-boundary"; function ErrorFallback({ error, resetErrorBoundary }) { return ( <div role="alert"> <h2>Something went wrong:</h2> <pre>{error.message}</pre> <button onClick={resetErrorBoundary}>Try again</button> </div> ); } function App() { return ( <CardQLProvider config={config}> <ErrorBoundary FallbackComponent={ErrorFallback}> <YourApp /> </ErrorBoundary> </CardQLProvider> ); } ``` ### 3. Loading States Always handle loading states for better UX: ```tsx function PaymentList() { const { data, loading, error } = usePayments(); if (loading) return <PaymentSkeleton />; if (error) return <ErrorMessage error={error} />; if (!data?.payments.length) return <EmptyState />; return <PaymentGrid payments={data.payments} />; } ``` ## License MIT ## Support For support, please contact the CardQL team or visit our documentation.