UNPKG

@invoiceddd/react

Version:

React integration utilities for InvoiceDDD system

478 lines (467 loc) 14.2 kB
import * as react_jsx_runtime from 'react/jsx-runtime'; import { ManagedRuntime, Effect } from 'effect'; import { InvoiceSystemOptions, InvoiceSystemInstance, AppConfig } from 'invoiceddd'; import { ReactNode, ComponentType } from 'react'; import { CreateInvoiceOutput, CreateInvoiceInput, InvoiceDraft, RequestInvoiceInput, GetInvoiceInput, GetInvoiceOutput, ListInvoicesInput, ListInvoicesOutput } from '@invoiceddd/application'; /** * Context value containing the invoice system instance and utilities */ interface InvoiceSystemContextValue { /** The invoice system instance */ system: InvoiceSystemInstance | null; /** The current configuration */ config: AppConfig | null; /** Whether the system is currently loading */ isLoading: boolean; /** Any error that occurred during initialization */ error: Error | null; /** The Effect runtime for advanced usage */ runtime: ManagedRuntime.ManagedRuntime<unknown, Error> | null; } /** * Props for the InvoiceSystemProvider component */ interface InvoiceSystemProviderProps { /** Child components */ children: ReactNode; /** Options for creating the invoice system */ options?: InvoiceSystemOptions; /** Whether to auto-start the system on mount */ autoStart?: boolean; } /** * Provider component that initializes and provides the InvoiceDDD system to React components * * @example * ```tsx * function App() { * return ( * <InvoiceSystemProvider * options={{ * config: { database: { url: 'file:./invoices.db' } }, * autoStartServer: false * }} * autoStart={true} * > * <MyInvoiceApp /> * </InvoiceSystemProvider> * ); * } * ``` */ declare function InvoiceSystemProvider({ children, options, autoStart, }: InvoiceSystemProviderProps): react_jsx_runtime.JSX.Element; /** * Hook to access the invoice system from React components * * @throws {Error} If used outside of InvoiceSystemProvider * * @example * ```tsx * function InvoiceList() { * const { system, isLoading, error } = useInvoiceSystem(); * * if (isLoading) return <div>Loading...</div>; * if (error) return <div>Error: {error.message}</div>; * if (!system) return <div>System not available</div>; * * // Use system for invoice operations * return <div>Invoice system ready!</div>; * } * ``` */ declare function useInvoiceSystem(): InvoiceSystemContextValue; /** * @fileoverview React Hooks for InvoiceDDD Operations * * Provides React hooks for common invoice operations with proper state management * and Effect integration. */ /** * Hook for creating invoices with state management * * @example * ```tsx * function CreateInvoiceForm() { * const { createInvoice, isLoading, error } = useCreateInvoice(); * * const handleSubmit = async (input: CreateInvoiceInput) => { * const result = await createInvoice(input); * if (result) { * console.log('Invoice created:', result.invoice.invoiceId); * } * }; * * return ( * <form onSubmit={handleSubmit}> * {isLoading && <div>Creating invoice...</div>} * {error && <div>Error: {error.message}</div>} * </form> * ); * } * ``` */ declare function useCreateInvoice(): { data: CreateInvoiceOutput | null; isLoading: boolean; error: Error | null; createInvoice: (input: CreateInvoiceInput) => Promise<CreateInvoiceOutput | null>; }; /** * Hook for requesting invoice drafts * * @example * ```tsx * function RequestInvoiceButton() { * const { requestInvoice, isLoading } = useRequestInvoice(); * * const handleRequest = async () => { * const input: RequestInvoiceInput = { * orderId: "order-123", * requestedBy: "user-456" * }; * await requestInvoice(input); * }; * * return ( * <button onClick={handleRequest} disabled={isLoading}> * {isLoading ? 'Requesting...' : 'Request Invoice'} * </button> * ); * } * ``` */ declare function useRequestInvoice(): { data: InvoiceDraft | null; isLoading: boolean; error: Error | null; requestInvoice: (input: RequestInvoiceInput) => Promise<InvoiceDraft | null>; }; /** * Hook for fetching a single invoice by ID or invoice number * * @example * ```tsx * function InvoiceDetail({ orderId }: { orderId: string }) { * const { invoice, isLoading, error, refetch } = useInvoice({ orderId }); * * if (isLoading) return <div>Loading invoice...</div>; * if (error) return <div>Error: {error.message}</div>; * if (!invoice) return <div>Invoice not found</div>; * * return ( * <div> * <h1>Invoice {invoice.invoice.invoiceNumber}</h1> * <button onClick={refetch}>Refresh</button> * </div> * ); * } * ``` */ declare function useInvoice(input: GetInvoiceInput): { invoice: GetInvoiceOutput | null; isLoading: boolean; error: Error | null; refetch: () => Promise<void>; }; /** * Hook for listing invoices with pagination and filtering * * @example * ```tsx * function InvoiceList() { * const { * invoices, * isLoading, * error, * loadMore, * hasMore, * refetch * } = useInvoices({ * pagination: { limit: 10 }, * filters: { createdBy: "user-123" } * }); * * if (isLoading && !invoices) return <div>Loading...</div>; * if (error) return <div>Error: {error.message}</div>; * * return ( * <div> * {invoices?.invoices.map(invoice => ( * <div key={invoice.invoiceId}>{invoice.invoiceNumber}</div> * ))} * {hasMore && ( * <button onClick={loadMore} disabled={isLoading}> * {isLoading ? 'Loading...' : 'Load More'} * </button> * )} * <button onClick={refetch}>Refresh</button> * </div> * ); * } * ``` */ declare function useInvoices(input?: ListInvoicesInput): { invoices: ListInvoicesOutput | null; isLoading: boolean; error: Error | null; loadMore: () => void; hasMore: boolean; refetch: () => void; }; /** * @fileoverview Higher-Order Components for InvoiceDDD Integration * * Provides HOCs for integrating Effect-based invoice operations with React components. */ /** * Props injected by withInvoiceSystem HOC */ interface WithInvoiceSystemProps { /** The Effect runtime for running invoice operations */ invoiceRuntime: ManagedRuntime.ManagedRuntime<unknown, Error>; /** Helper function to run Effect operations and return promises */ runInvoiceEffect: <A>(effect: Effect.Effect<A, Error, any>) => Promise<A>; } /** * Higher-order component that injects invoice system runtime and utilities * * @example * ```tsx * interface MyComponentProps { * title: string; * } * * function MyComponent({ * title, * invoiceRuntime, * runInvoiceEffect * }: MyComponentProps & WithInvoiceSystemProps) { * const handleCreateInvoice = async () => { * const effect = Effect.gen(function* () { * const createUseCase = yield* CreateInvoiceUseCase; * return yield* createUseCase.execute(orderData); * }); * * const invoice = await runInvoiceEffect(effect); * console.log('Created invoice:', invoice); * }; * * return ( * <div> * <h1>{title}</h1> * <button onClick={handleCreateInvoice}>Create Invoice</button> * </div> * ); * } * * export default withInvoiceSystem(MyComponent); * ``` */ declare function withInvoiceSystem<P extends object>(Component: ComponentType<P & WithInvoiceSystemProps>): ComponentType<P>; /** * Props for components that need loading and error states */ interface WithLoadingProps { isLoading: boolean; error: Error | null; } /** * Higher-order component that provides loading and error state management * * @example * ```tsx * function MyComponent({ * data, * isLoading, * error * }: { data: string } & WithLoadingProps) { * if (isLoading) return <div>Loading...</div>; * if (error) return <div>Error: {error.message}</div>; * * return <div>Data: {data}</div>; * } * * export default withInvoiceSystemLoading(MyComponent); * ``` */ declare function withInvoiceSystemLoading<P extends object>(Component: ComponentType<P & WithLoadingProps>): ComponentType<P>; /** * @fileoverview Utility functions for Effect-to-Promise bridge * * Provides utilities for converting Effect operations to Promises for easier * integration with React components and standard JavaScript async patterns. */ /** * Configuration for Effect-to-Promise conversion */ interface EffectBridgeConfig { /** Timeout in milliseconds for Effect operations */ timeout?: number; /** Whether to log errors to console */ logErrors?: boolean; } /** * Creates a bridge function that converts Effect operations to Promises * * @example * ```tsx * function MyComponent() { * const { runtime } = useInvoiceSystem(); * const bridge = createEffectBridge(runtime); * * const handleOperation = async () => { * try { * const result = await bridge(myEffect); * console.log('Success:', result); * } catch (error) { * console.error('Failed:', error); * } * }; * * return <button onClick={handleOperation}>Run Operation</button>; * } * ``` */ declare function createEffectBridge(runtime: ManagedRuntime.ManagedRuntime<any, Error>, config?: EffectBridgeConfig): <A, E, R>(effect: Effect.Effect<A, E, R>) => Promise<A>; /** * Utility for running multiple Effect operations in parallel and converting to Promise * * @example * ```tsx * const results = await runEffectsInParallel(runtime, [ * getInvoiceEffect, * getOrderEffect, * getCustomerEffect * ]); * ``` */ declare function runEffectsInParallel<A>(runtime: ManagedRuntime.ManagedRuntime<any, Error>, effects: Effect.Effect<A, Error, any>[], config?: EffectBridgeConfig): Promise<A[]>; /** * Utility for running Effect operations with retry logic * * @example * ```tsx * const result = await runEffectWithRetry( * runtime, * unstableEffect, * { maxRetries: 3, retryDelay: 1000 } * ); * ``` */ declare function runEffectWithRetry<A, E, R>(runtime: ManagedRuntime.ManagedRuntime<any, Error>, effect: Effect.Effect<A, E, R>, options?: { maxRetries?: number; retryDelay?: number; config?: EffectBridgeConfig; }): Promise<A>; /** * Creates a debounced Effect runner for UI operations * * @example * ```tsx * function SearchComponent() { * const { runtime } = useInvoiceSystem(); * const debouncedSearch = createDebouncedEffectRunner(runtime, 300); * * const handleSearch = (query: string) => { * debouncedSearch(searchInvoicesEffect(query)) * .then(results => setSearchResults(results)) * .catch(error => setError(error)); * }; * * return <input onChange={e => handleSearch(e.target.value)} />; * } * ``` */ declare function createDebouncedEffectRunner(runtime: ManagedRuntime.ManagedRuntime<any, Error>, delay: number, config?: EffectBridgeConfig): <A, E, R>(effect: Effect.Effect<A, E, R>) => Promise<A>; /** * Utility for converting Effect streams to async iterators for React * * @example * ```tsx * function StreamingComponent() { * const { runtime } = useInvoiceSystem(); * const [items, setItems] = useState([]); * * useEffect(() => { * const processStream = async () => { * const iterator = effectStreamToAsyncIterator(runtime, invoiceStream); * * for await (const invoice of iterator) { * setItems(prev => [...prev, invoice]); * } * }; * * processStream(); * }, [runtime]); * * return <div>{items.map(item => <div key={item.id}>{item.name}</div>)}</div>; * } * ``` */ declare function effectStreamToAsyncIterator<A, E, R>(runtime: ManagedRuntime.ManagedRuntime<any, Error>, streamEffect: Effect.Effect<AsyncIterable<A>, E, R>): AsyncIterableIterator<A>; /** * Type guard to check if an error is an Effect timeout error */ declare function isTimeoutError(error: unknown): boolean; /** * Utility to wrap Effect operations with React-friendly error handling */ declare function createReactSafeEffectRunner(runtime: ManagedRuntime.ManagedRuntime<any, Error>, config?: EffectBridgeConfig): <A, E, R>(effect: Effect.Effect<A, E, R>, onError?: (error: Error) => void) => Promise<A | null>; /** * @fileoverview React Integration for InvoiceDDD * * Provides React hooks, components, and utilities for integrating the InvoiceDDD * system with React applications. * * @example * ```tsx * import { InvoiceSystemProvider, useInvoiceSystem, useCreateInvoice } from '@invoiceddd/react'; * * function App() { * return ( * <InvoiceSystemProvider options={{ config: { database: { url: 'file:./invoices.db' } } }}> * <InvoiceApp /> * </InvoiceSystemProvider> * ); * } * * function InvoiceApp() { * const { system, isLoading } = useInvoiceSystem(); * const { createInvoice } = useCreateInvoice(); * * if (isLoading) return <div>Loading...</div>; * * return <div>Invoice system ready!</div>; * } * ``` * * @packageDocumentation * @since 0.1.0 */ /** * React context and provider for invoice system integration * * @example * ```tsx * import { InvoiceSystemProvider, useInvoiceSystem } from '@invoiceddd/react'; * * function App() { * return ( * <InvoiceSystemProvider * options={{ * config: { database: { url: 'file:./invoices.db' } }, * autoStartServer: false * }} * > * <MyApp /> * </InvoiceSystemProvider> * ); * } * ``` */ /** * Package version and metadata */ declare const VERSION = "0.1.0"; declare const PACKAGE_NAME = "@invoiceddd/react"; export { type EffectBridgeConfig, type InvoiceSystemContextValue, InvoiceSystemProvider, type InvoiceSystemProviderProps, PACKAGE_NAME, VERSION, type WithInvoiceSystemProps, type WithLoadingProps, createDebouncedEffectRunner, createEffectBridge, createReactSafeEffectRunner, effectStreamToAsyncIterator, isTimeoutError, runEffectWithRetry, runEffectsInParallel, useCreateInvoice, useInvoice, useInvoiceSystem, useInvoices, useRequestInvoice, withInvoiceSystem, withInvoiceSystemLoading };