Skip to Content
DocumentationBackendFrontend Integration Guide

Frontend Integration Guide - Dynamic Insurance System

🎯 Overview

This guide provides comprehensive instructions for frontend developers to integrate with the dynamic insurance system APIs. It includes endpoint usage, UI/UX design patterns, and implementation suggestions.

📋 Table of Contents

  1. Authentication & Setup
  2. API Endpoint Categories
  3. UI/UX Design Patterns
  4. Implementation Examples
  5. Error Handling
  6. Performance Considerations
  7. Testing Guidelines

🔐 Authentication & Setup

Base Configuration

// config/api.ts const API_BASE_URL = process.env.REACT_APP_API_URL || 'http://localhost:8000'; const API_VERSION = 'v1'; export const API_ENDPOINTS = { base: `${API_BASE_URL}/api/${API_VERSION}`, private: `${API_BASE_URL}/api/${API_VERSION}/private`, dynamic: `${API_BASE_URL}/api/${API_VERSION}/private/dynamic`, };

Authentication Headers

// utils/auth.ts export const getAuthHeaders = () => { const token = localStorage.getItem('jwt_token'); return { 'Authorization': `Bearer ${token}`, 'Content-Type': 'application/json', }; };

🏗️ API Endpoint Categories

1. Insurance Provider Management

Purpose: Create and manage insurance providers UI Pattern: Admin dashboard with CRUD operations

Endpoints:

  • GET /api/v1/private/howden/insurance-provider/ - List all providers
  • POST /api/v1/private/howden/insurance-provider/ - Create provider
  • PUT /api/v1/private/howden/insurance-provider/{uuid} - Update provider
  • DELETE /api/v1/private/howden/insurance-provider/{uuid} - Delete provider

Suggested UI Design:

// Components/InsuranceProviderManagement.tsx interface ProviderFormData { name: string; address: string; number: string; } // Use a data table with inline editing <DataTable columns={[ { key: 'name', title: 'Provider Name', editable: true }, { key: 'address', title: 'Address', editable: true }, { key: 'number', title: 'Contact Number', editable: true }, ]} actions={['create', 'edit', 'delete']} modalComponent={ProviderModal} />

2. Dynamic Insurer Configuration

Purpose: Configure available options for each insurer UI Pattern: Tabbed interface with category-based organization

Endpoints:

  • GET /api/v1/private/dynamic/insurer/insurer/{insurerId}/configurations
  • POST /api/v1/private/dynamic/insurer/insurer/{insurerId}/configurations
  • PUT /api/v1/private/dynamic/insurer/configurations/{configUuid}
  • DELETE /api/v1/private/dynamic/insurer/configurations/{configUuid}

Suggested UI Design:

// Components/InsurerConfigurationManager.tsx interface ConfigurationCategory { type: string; // 'civil_status', 'plan_type', 'member_type' items: ConfigurationItem[]; } // Use tabs for different configuration types <Tabs> <Tab label="Civil Status"> <ConfigurationList type="civil_status" items={civilStatusConfigs} onAdd={handleAddConfiguration} onEdit={handleEditConfiguration} /> </Tab> <Tab label="Plan Types"> <ConfigurationList type="plan_type" items={planTypeConfigs} onAdd={handleAddConfiguration} onEdit={handleEditConfiguration} /> </Tab> </Tabs>

3. Company Plan Configuration

Purpose: Allow companies to select and customize their plans UI Pattern: Wizard-style setup with preview

Endpoints:

  • GET /api/v1/private/dynamic/company-plan/company/{companyUuid}/available-configurations
  • POST /api/v1/private/dynamic/company-plan/company/{companyUuid}/add-configuration
  • GET /api/v1/private/dynamic/company-plan/company/{companyUuid}/plan-summary

Suggested UI Design:

// Components/CompanyPlanSetup.tsx interface PlanSetupStep { title: string; component: React.ComponentType; validation: () => boolean; } const planSetupSteps: PlanSetupStep[] = [ { title: "Select Configuration Types", component: ConfigurationTypeSelector, validation: () => selectedTypes.length > 0 }, { title: "Configure Plans", component: PlanConfigurationForm, validation: () => plans.length > 0 }, { title: "Review & Confirm", component: PlanSummary, validation: () => true } ]; // Use a stepper component <Stepper steps={planSetupSteps} onComplete={handlePlanSetupComplete} />

4. File Upload Configuration

Purpose: Configure file upload formats and validation UI Pattern: Form builder with drag-and-drop header configuration

Endpoints:

  • POST /api/v1/private/dynamic/file-upload/company/{companyUuid}/file-upload-configurations
  • GET /api/v1/private/dynamic/file-upload/company/{companyUuid}/file-upload-configurations
  • POST /api/v1/private/dynamic/file-upload/file-upload-configuration/{configUuid}/headers

Suggested UI Design:

// Components/FileUploadConfigurationBuilder.tsx interface HeaderField { headerName: string; displayName: string; dataType: 'string' | 'number' | 'date' | 'boolean'; isRequired: boolean; isUnique: boolean; validationRules: ValidationRule[]; } // Use a form builder interface <FormBuilder> <Section title="Basic Configuration"> <InputField name="configName" label="Configuration Name" required /> <SelectField name="uploadType" label="Upload Type" options={uploadTypes} /> </Section> <Section title="Header Configuration"> <DragDropList items={headers} onReorder={handleHeaderReorder} renderItem={(header) => <HeaderFieldEditor header={header} />} /> </Section> <Section title="Validation Rules"> <ValidationRuleBuilder rules={validationRules} /> </Section> </FormBuilder>

5. UI Button Configuration

Purpose: Configure dynamic UI buttons with permissions UI Pattern: Button designer with permission matrix

Endpoints:

  • POST /api/v1/private/dynamic/ui-buttons/insurer/{insurerId}/ui-buttons
  • GET /api/v1/private/dynamic/ui-buttons/company/{companyUuid}/ui-buttons
  • POST /api/v1/private/dynamic/ui-buttons/ui-button/{buttonUuid}/permissions

Suggested UI Design:

// Components/UIButtonDesigner.tsx interface ButtonDesignerProps { buttonConfig: UIButtonConfiguration; onSave: (config: UIButtonConfiguration) => void; } // Use a visual button designer <ButtonDesigner> <ButtonPreview config={buttonConfig} onConfigChange={handleConfigChange} /> <DesignPanel> <PropertyEditor properties={buttonConfig} onChange={handlePropertyChange} /> <PermissionMatrix roles={['HR', 'BROKER', 'PRINCIPAL', 'ADMIN']} permissions={buttonConfig.permissions} onChange={handlePermissionChange} /> </DesignPanel> </ButtonDesigner>

🎨 UI/UX Design Patterns

1. Modal Patterns

Simple Form Modal

// Use for: Creating/editing single records <Modal title="Add Insurance Provider" size="medium" onClose={handleClose} > <Form onSubmit={handleSubmit}> <InputField name="name" label="Provider Name" required /> <TextAreaField name="address" label="Address" /> <InputField name="number" label="Contact Number" /> </Form> </Modal>

Wizard Modal

// Use for: Multi-step complex operations <WizardModal title="Setup Company Plan" steps={planSetupSteps} onComplete={handleComplete} onCancel={handleCancel} />

Confirmation Modal

// Use for: Destructive actions <ConfirmationModal title="Delete Configuration" message="Are you sure you want to delete this configuration? This action cannot be undone." onConfirm={handleDelete} onCancel={handleCancel} variant="danger" />

2. Data Table Patterns

Sortable Data Table

// Use for: Listing configurations with sorting/filtering <DataTable data={configurations} columns={[ { key: 'configName', title: 'Name', sortable: true }, { key: 'configType', title: 'Type', sortable: true }, { key: 'isActive', title: 'Status', render: (value) => <StatusBadge status={value} /> }, { key: 'actions', title: 'Actions', render: (item) => <ActionButtons item={item} /> } ]} pagination={{ page: 1, pageSize: 10 }} onSort={handleSort} onFilter={handleFilter} />

Expandable Rows

// Use for: Showing related data <DataTable data={configurations} expandableRows expandableRowComponent={({ item }) => ( <ConfigurationDetails configuration={item} /> )} />

3. Form Patterns

Multi-Step Form

// Use for: Complex configuration setup <MultiStepForm steps={[ { title: "Basic Info", component: BasicInfoStep }, { title: "Configuration", component: ConfigurationStep }, { title: "Validation", component: ValidationStep }, { title: "Review", component: ReviewStep } ]} onComplete={handleComplete} />

Dynamic Form Builder

// Use for: File upload header configuration <FormBuilder fields={headerFields} onFieldAdd={handleFieldAdd} onFieldRemove={handleFieldRemove} onFieldUpdate={handleFieldUpdate} validation={validationRules} />

4. Dashboard Patterns

Card-Based Dashboard

// Use for: Overview and quick actions <Dashboard> <StatsCard title="Total Configurations" value={totalConfigs} trend="+12%" icon="settings" /> <QuickActions> <ActionButton label="Add Configuration" icon="plus" onClick={handleAddConfig} /> </QuickActions> </Dashboard>

Tabbed Interface

// Use for: Different configuration types <Tabs> <Tab label="Insurance Providers" icon="building"> <InsuranceProviderList /> </Tab> <Tab label="Configurations" icon="settings"> <ConfigurationManager /> </Tab> <Tab label="File Uploads" icon="upload"> <FileUploadManager /> </Tab> </Tabs>

💻 Implementation Examples

1. API Service Layer

// services/configurationService.ts class ConfigurationService { private baseUrl = API_ENDPOINTS.dynamic; async getInsurerConfigurations(insurerId: string) { const response = await fetch( `${this.baseUrl}/insurer/insurer/${insurerId}/configurations`, { headers: getAuthHeaders() } ); return response.json(); } async createConfiguration(insurerId: string, data: ConfigurationData) { const response = await fetch( `${this.baseUrl}/insurer/insurer/${insurerId}/configurations`, { method: 'POST', headers: getAuthHeaders(), body: JSON.stringify(data) } ); return response.json(); } async updateConfiguration(configUuid: string, data: Partial<ConfigurationData>) { const response = await fetch( `${this.baseUrl}/insurer/configurations/${configUuid}`, { method: 'PUT', headers: getAuthHeaders(), body: JSON.stringify(data) } ); return response.json(); } }

2. React Hook for Data Management

// hooks/useConfigurations.ts export const useConfigurations = (insurerId: string) => { const [configurations, setConfigurations] = useState([]); const [loading, setLoading] = useState(false); const [error, setError] = useState(null); const fetchConfigurations = useCallback(async () => { setLoading(true); try { const data = await configurationService.getInsurerConfigurations(insurerId); setConfigurations(data); } catch (err) { setError(err.message); } finally { setLoading(false); } }, [insurerId]); const createConfiguration = useCallback(async (data: ConfigurationData) => { try { const newConfig = await configurationService.createConfiguration(insurerId, data); setConfigurations(prev => [...prev, newConfig]); } catch (err) { setError(err.message); } }, [insurerId]); const updateConfiguration = useCallback(async (configUuid: string, data: Partial<ConfigurationData>) => { try { const updatedConfig = await configurationService.updateConfiguration(configUuid, data); setConfigurations(prev => prev.map(config => config.configUuid === configUuid ? updatedConfig : config ) ); } catch (err) { setError(err.message); } }, []); useEffect(() => { fetchConfigurations(); }, [fetchConfigurations]); return { configurations, loading, error, createConfiguration, updateConfiguration, refetch: fetchConfigurations }; };

3. File Upload Component

// components/FileUploader.tsx interface FileUploaderProps { configUuid: string; onUploadComplete: (result: UploadResult) => void; onUploadError: (error: string) => void; } export const FileUploader: React.FC<FileUploaderProps> = ({ configUuid, onUploadComplete, onUploadError }) => { const [file, setFile] = useState<File | null>(null); const [uploading, setUploading] = useState(false); const [progress, setProgress] = useState(0); const handleFileSelect = (selectedFile: File) => { // Validate file type and size if (!selectedFile.name.endsWith('.xlsx') && !selectedFile.name.endsWith('.xls')) { onUploadError('Please select an Excel file (.xlsx or .xls)'); return; } if (selectedFile.size > 10 * 1024 * 1024) { // 10MB limit onUploadError('File size must be less than 10MB'); return; } setFile(selectedFile); }; const handleUpload = async () => { if (!file) return; setUploading(true); setProgress(0); try { const formData = new FormData(); formData.append('file', file); const response = await fetch( `${API_ENDPOINTS.dynamic}/file-upload/file-upload-configuration/${configUuid}/upload-file`, { method: 'POST', headers: { 'Authorization': `Bearer ${localStorage.getItem('jwt_token')}` }, body: formData } ); if (!response.ok) { throw new Error('Upload failed'); } const result = await response.json(); onUploadComplete(result); } catch (error) { onUploadError(error.message); } finally { setUploading(false); } }; return ( <div className="file-uploader"> <FileDropZone onFileSelect={handleFileSelect} /> {file && ( <div className="file-preview"> <span>{file.name}</span> <button onClick={handleUpload} disabled={uploading}> {uploading ? `Uploading... ${progress}%` : 'Upload'} </button> </div> )} </div> ); };

⚠️ Error Handling

1. API Error Response Format

interface APIError { success: false; message: string; errors?: string[]; statusCode: number; } // Error handling utility const handleAPIError = (error: APIError) => { if (error.statusCode === 401) { // Redirect to login window.location.href = '/login'; } else if (error.statusCode === 403) { // Show permission denied message showNotification('You do not have permission to perform this action', 'error'); } else { // Show generic error message showNotification(error.message || 'An error occurred', 'error'); } };

2. Form Validation

// Validation schemas using Yup const configurationSchema = yup.object({ configName: yup.string().required('Configuration name is required'), configType: yup.string().required('Configuration type is required'), configValue: yup.string().required('Configuration value is required'), isActive: yup.boolean(), sortOrder: yup.number().min(0, 'Sort order must be positive') }); // Form validation hook const useFormValidation = (schema: any) => { const [errors, setErrors] = useState({}); const validate = async (data: any) => { try { await schema.validate(data, { abortEarly: false }); setErrors({}); return true; } catch (err) { const validationErrors = {}; err.inner.forEach(error => { validationErrors[error.path] = error.message; }); setErrors(validationErrors); return false; } }; return { errors, validate }; };

🚀 Performance Considerations

1. Data Pagination

// Implement pagination for large datasets const usePaginatedData = (endpoint: string, pageSize: number = 10) => { const [data, setData] = useState([]); const [pagination, setPagination] = useState({ page: 1, pageSize, total: 0, totalPages: 0 }); const fetchData = useCallback(async (page: number) => { const response = await fetch( `${endpoint}?page=${page}&pageSize=${pageSize}`, { headers: getAuthHeaders() } ); const result = await response.json(); setData(result.data); setPagination(result.pagination); }, [endpoint, pageSize]); return { data, pagination, fetchData }; };

2. Caching Strategy

// Simple caching for frequently accessed data class CacheManager { private cache = new Map(); private ttl = 5 * 60 * 1000; // 5 minutes get(key: string) { const item = this.cache.get(key); if (item && Date.now() - item.timestamp < this.ttl) { return item.data; } this.cache.delete(key); return null; } set(key: string, data: any) { this.cache.set(key, { data, timestamp: Date.now() }); } }

3. Lazy Loading

// Lazy load components for better performance const ConfigurationManager = lazy(() => import('./ConfigurationManager')); const FileUploadManager = lazy(() => import('./FileUploadManager')); // Use with Suspense <Suspense fallback={<LoadingSpinner />}> <ConfigurationManager /> </Suspense>

🧪 Testing Guidelines

1. Unit Tests

// Test API service functions describe('ConfigurationService', () => { it('should fetch configurations successfully', async () => { const mockData = [{ configUuid: '123', configName: 'Test' }]; global.fetch = jest.fn().mockResolvedValue({ json: () => Promise.resolve(mockData) }); const service = new ConfigurationService(); const result = await service.getInsurerConfigurations('maxicare'); expect(result).toEqual(mockData); }); });

2. Integration Tests

// Test component integration describe('ConfigurationManager', () => { it('should create new configuration', async () => { render(<ConfigurationManager insurerId="maxicare" />); fireEvent.click(screen.getByText('Add Configuration')); fireEvent.change(screen.getByLabelText('Configuration Name'), { target: { value: 'New Config' } }); fireEvent.click(screen.getByText('Save')); await waitFor(() => { expect(screen.getByText('Configuration created successfully')).toBeInTheDocument(); }); }); });

📱 Mobile Considerations

1. Responsive Design

/* Mobile-first responsive design */ .configuration-grid { display: grid; grid-template-columns: 1fr; gap: 1rem; } @media (min-width: 768px) { .configuration-grid { grid-template-columns: repeat(2, 1fr); } } @media (min-width: 1024px) { .configuration-grid { grid-template-columns: repeat(3, 1fr); } }

2. Touch-Friendly Interface

// Use larger touch targets for mobile <Button size="large" minHeight="44px" // Minimum touch target size onTouchStart={handleTouch} > Add Configuration </Button>

🎯 Key Recommendations

1. User Experience

  • Use progressive disclosure - Show basic info first, details on demand
  • Provide clear feedback - Loading states, success/error messages
  • Implement undo functionality - For destructive actions
  • Use consistent patterns - Same UI patterns across similar features

2. Performance

  • Implement virtual scrolling - For large data tables
  • Use optimistic updates - Update UI before API confirmation
  • Cache frequently accessed data - Reduce API calls
  • Implement proper loading states - Better perceived performance

3. Accessibility

  • Use semantic HTML - Proper heading structure, form labels
  • Implement keyboard navigation - Full keyboard support
  • Provide ARIA labels - Screen reader support
  • Ensure color contrast - WCAG compliance

4. Security

  • Validate all inputs - Client and server-side validation
  • Sanitize data - Prevent XSS attacks
  • Use HTTPS - Secure data transmission
  • Implement proper authentication - Token-based auth

This guide provides a comprehensive foundation for frontend developers to integrate with your dynamic insurance system! 🚀

Last updated on