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
- Authentication & Setup
- API Endpoint Categories
- UI/UX Design Patterns
- Implementation Examples
- Error Handling
- Performance Considerations
- 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 providersPOST /api/v1/private/howden/insurance-provider/- Create providerPUT /api/v1/private/howden/insurance-provider/{uuid}- Update providerDELETE /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}/configurationsPOST /api/v1/private/dynamic/insurer/insurer/{insurerId}/configurationsPUT /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-configurationsPOST /api/v1/private/dynamic/company-plan/company/{companyUuid}/add-configurationGET /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-configurationsGET /api/v1/private/dynamic/file-upload/company/{companyUuid}/file-upload-configurationsPOST /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-buttonsGET /api/v1/private/dynamic/ui-buttons/company/{companyUuid}/ui-buttonsPOST /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! 🚀