@rajkrajpj/cultivate-ui-library
Version:
A modern, type-safe, accessible React component library for fintech investor forms. Build complete investor forms in minutes with zero configuration, supporting multiple regulations (RegA+, RegD, RegCF) and investor types.
484 lines (410 loc) • 13.5 kB
Markdown
# Cultivate UI Library – Implementation & Usage Examples
This document provides comprehensive examples for integrating and using the Cultivate UI Library in a frontend application. It covers the actual API patterns, step configuration, offering parameters, and advanced customization options.
## 1. Basic Usage (Zero Configuration)
The simplest way to get started with the library:
```tsx
import {
createDefaultSteps,
InvestorFormData,
InvestorFormWizard,
} from "@rajkrajpj/cultivate-ui-library"
export const BasicInvestorForm = () => {
// Define your offering parameters
const offeringParams = {
offeringId: "basic-offering-123",
companyName: "Basic Company",
sharePrice: 10,
minInvestment: 100,
maxInvestment: 10000,
deadline: new Date(Date.now() + 1000 * 60 * 60 * 24 * 30), // 30 days
regulation: "regA",
}
// Zero configuration - uses all defaults
const steps = createDefaultSteps({
regulation: offeringParams.regulation,
})
const handleComplete = async (formData: Partial<InvestorFormData>) => {
// Simple submission to your API
await fetch("/api/investments", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify(formData),
})
}
return (
<div className="max-w-md mx-auto p-8">
<InvestorFormWizard<InvestorFormData>
steps={steps}
regulation={offeringParams.regulation}
offeringParams={offeringParams}
onComplete={handleComplete}
/>
</div>
)
}
```
## 2. Advanced Usage with Custom Step Handlers
For production applications requiring fine-grained control over each step:
```tsx
import {
createDefaultSteps,
InvestorFormData,
InvestorFormWizard,
StepHandlers,
} from "@rajkrajpj/cultivate-ui-library"
export const AdvancedInvestorForm = () => {
const offeringParams = {
offeringId: "my-offering-123",
companyName: "My Startup Inc",
sharePrice: 15,
minInvestment: 500,
maxInvestment: 50000,
deadline: new Date(Date.now() + 1000 * 60 * 60 * 24 * 60), // 60 days
regulation: "regCF",
}
// Define custom API calls for specific steps
const stepHandlers: StepHandlers = {
onGetStartedSubmit: async (data: InvestorFormData) => {
// Save lead information immediately
await fetch("/api/leads", {
method: "POST",
body: JSON.stringify({
email: data.email,
firstName: data.firstName,
lastName: data.lastName,
offeringId: offeringParams.offeringId,
}),
})
},
onInvestmentAmountSubmit: async (data: InvestorFormData) => {
// Validate investment amount against offering limits
await fetch("/api/validate-investment", {
method: "POST",
body: JSON.stringify({
amount: data.investmentAmount,
offeringId: offeringParams.offeringId,
investorType: data.investorType,
}),
})
},
onIdentityInfoSubmit: async (data: InvestorFormData) => {
// Submit KYC/AML verification
await fetch("/api/kyc-verification", {
method: "POST",
body: JSON.stringify({
personalInfo: {
ssn: data.ssn,
birthDate: data.birthDate,
address: {
address1: data.address1,
city: data.city,
state: data.state,
zip: data.zip,
},
},
}),
})
},
onPaymentsSubmit: async (data: InvestorFormData) => {
// Process final investment
await fetch("/api/investments/submit", {
method: "POST",
body: JSON.stringify(data),
})
},
}
// Create steps with custom handlers
const steps = createDefaultSteps({
regulation: offeringParams.regulation,
enableDebugLogs: process.env.NODE_ENV === "development",
stepHandlers,
customSuccessHandler: () => {
window.location.href = "/investment-success"
},
})
// Handle completion
const handleComplete = async (formData: Partial<InvestorFormData>) => {
try {
const response = await fetch("/api/investments", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
...formData,
offeringId: offeringParams.offeringId,
}),
})
if (response.ok) {
console.log("Investment submitted successfully!")
}
} catch (error) {
console.error("Error submitting investment:", error)
}
}
return (
<div className="max-w-md mx-auto p-8">
<InvestorFormWizard<InvestorFormData>
steps={steps}
regulation={offeringParams.regulation}
offeringParams={offeringParams}
onComplete={handleComplete}
/>
</div>
)
}
```
## 3. Complete API Reference
### InvestorFormWizard Props
```tsx
interface InvestorFormWizardProps<T> {
steps: StepConfig<T>[] // Step configurations
regulation: string // "regA" | "regD" | "regCF" | "custom"
theme?: any // Theme configuration
offeringParams?: OfferingParams // Offering-specific parameters
apiHandlers?: FormContext<T>["api"] // API integration hooks
onStepChange?: (step: number, data: Partial<T>) => void // Step change callback
onComplete?: (data: Partial<T>) => Promise<void> // Form completion handler
onError?: (error: Error, step: string) => void // Error handler
persistenceKey?: string // LocalStorage key for form persistence
initialData?: Partial<T> // Pre-populate form data
className?: string // Custom CSS classes
}
```
### OfferingParams Interface
```tsx
interface OfferingParams {
offeringId: string // Unique offering identifier
companyName: string // Company name for display
sharePrice: number // Price per share
minInvestment: number // Minimum investment amount
maxInvestment: number // Maximum investment amount
deadline: Date // Offering deadline
regulation: "regA" | "regD" | "regCF" | "custom" // Regulation type
customContent?: {
welcomeMessage?: string // Custom welcome text
riskDisclosure?: string // Risk disclosure text
investmentTerms?: string // Investment terms
legalFooter?: string // Legal footer text
disclaimers?: string[] // Array of disclaimers
}
features?: {
allowInternational?: boolean // Allow international investors
requireAccreditation?: boolean // Require accreditation check
enableCrypto?: boolean // Accept cryptocurrency
}
}
```
### Available Step Handlers
The `StepHandlers` interface supports custom handlers for each step:
```tsx
interface StepHandlers {
onGetStartedSubmit?: (data: InvestorFormData) => Promise<void>
onInvestorTypeSubmit?: (data: InvestorFormData) => Promise<void>
onPersonalInfoSubmit?: (data: InvestorFormData) => Promise<void>
onAddressInfoSubmit?: (data: InvestorFormData) => Promise<void>
onIdentityInfoSubmit?: (data: InvestorFormData) => Promise<void>
onInvestmentAmountSubmit?: (data: InvestorFormData) => Promise<void>
onSelfAccreditationSubmit?: (data: InvestorFormData) => Promise<void>
onUnaccreditedInvestorSubmit?: (data: InvestorFormData) => Promise<void>
onAcknowledgementSubmit?: (data: InvestorFormData) => Promise<void>
onPaymentSelectionSubmit?: (data: InvestorFormData) => Promise<void>
onPaymentsSubmit?: (data: InvestorFormData) => Promise<void>
}
```
## 4. Default Form Steps
The `createDefaultSteps` function creates a 12-step investor form:
1. **Get Started** - Email, name collection, optional agreement (RegCF)
2. **Select Investor Type** - Individual, Joint, Company, Trust/IRA
3. **Personal Information** - Personal details based on investor type
4. **Address Information** - Address fields
5. **Identity Information** - SSN, DOB, identity verification
6. **Investment Amount** - Investment amount selection with validation
7. **Self Accreditation** - Accreditation verification (if required)
8. **Unaccredited Investor** - Income/net worth disclosure (conditional)
9. **Acknowledgement** - Agreements and certifications
10. **Payment Selection** - Payment method selection
11. **Payments** - Payment processing
12. **Success Investment** - Success confirmation page
## 5. Regulation-Specific Features
### RegA+ Configuration
```tsx
const steps = createDefaultSteps({
regulation: "regA",
// RegA+ supports both accredited and unaccredited investors
// No investment limits for qualified investors
})
```
### RegCF Configuration
```tsx
const steps = createDefaultSteps({
regulation: "regCF",
// RegCF shows agreement checkbox on first step for guest flows
// Implements annual investment limits
})
```
### RegD Configuration
```tsx
const steps = createDefaultSteps({
regulation: "regD",
// RegD requires accreditation verification
// No investment limits for accredited investors
})
```
## 6. Form Data Structure
The `InvestorFormData` type includes comprehensive fields:
```tsx
interface InvestorFormData {
// Basic Information
email: string
firstName: string
lastName: string
investorType: "individual" | "joint" | "company" | "trust" | "ira"
// Investment Data
investmentAmount: number
totalShares: number
isAccredited: boolean
// Identity Information
birthDate: string
ssn: string
tin?: string
// Address Information
address1: string
address2?: string
city: string
state: string
zip: string
country: string
// Joint Account Fields (when investorType === "joint")
joint_firstName?: string
joint_lastName?: string
joint_birthDate?: string
joint_ssn?: string
// Company Fields (when investorType === "company")
company_name?: string
company_title?: string
company_entityType?: string
company_stateOfFormation?: string
// Trust Fields (when investorType === "trust")
trust_name?: string
trust_title?: string
trust_dateOfFormation?: string
trust_stateOfFormation?: string
// IRA Fields (when investorType === "ira")
ira_accountType?: string
ira_custodianName?: string
ira_accountNumber?: string
// Payment Information
paymentMethod?: string
paymentUrl?: string
// Additional Fields
phone?: string
isUSCitizen?: boolean
// ... other fields as needed
}
```
## 7. Utilities and Helpers
### Available Utility Functions
```tsx
import {
createStepConfig,
mergeInvestorFormData
} from "@rajkrajpj/cultivate-ui-library"
// Create custom step configurations
const customSteps = createStepConfig([
{
id: "custom-step",
component: MyCustomStep,
title: "Custom Step",
validationSchema: myValidationSchema,
}
])
// Merge form data between steps (handles complex nested data)
const mergedData = mergeInvestorFormData(existingData, newStepData)
```
### Available UI Components
The library exports base UI components for custom implementations:
```tsx
import {
Button,
Card,
Checkbox,
Dialog,
Input,
Label,
Select,
Tabs
} from "@rajkrajpj/cultivate-ui-library"
```
## 8. Error Handling and Persistence
### Error Handling
```tsx
<InvestorFormWizard
steps={steps}
regulation="regA"
offeringParams={offeringParams}
onError={(error, stepId) => {
console.error(`Error in step ${stepId}:`, error)
// Handle step-specific errors
}}
onComplete={handleComplete}
/>
```
### Form Persistence
```tsx
<InvestorFormWizard
steps={steps}
regulation="regA"
offeringParams={offeringParams}
persistenceKey="investor-form-draft" // Auto-saves to localStorage
initialData={savedFormData} // Pre-populate with saved data
onComplete={handleComplete}
/>
```
## 9. Advanced Customization
### Custom Success Handler
```tsx
const steps = createDefaultSteps({
regulation: "regA",
customSuccessHandler: () => {
// Custom success behavior
window.location.href = "/custom-success-page"
}
})
```
### Debug Mode
```tsx
const steps = createDefaultSteps({
regulation: "regA",
enableDebugLogs: process.env.NODE_ENV === "development"
})
```
## 10. Migration from Legacy Forms
If you're migrating from an existing investor form implementation:
1. **Replace your form wizard** with `InvestorFormWizard`
2. **Convert step handlers** to the `StepHandlers` interface
3. **Map your data structure** to `InvestorFormData`
4. **Use offering parameters** instead of hard-coded values
5. **Leverage built-in persistence** instead of custom caching
**Before (Legacy):**
```tsx
// ~500 lines of boilerplate code
// Custom step management
// Manual validation
// Custom persistence logic
```
**After (Library):**
```tsx
// ~30 lines of business logic
const steps = createDefaultSteps({ regulation: "regA" })
return <InvestorFormWizard steps={steps} onComplete={handleComplete} />
```
This represents a significant reduction in code complexity while maintaining full functionality and adding regulation compliance features.