@visns-studio/visns-components 5.11.4 → 5.11.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -951,6 +951,766 @@ File upload component with drag and drop support.
951
951
  />
952
952
  ```
953
953
 
954
+ ### Association Management Components
955
+
956
+ #### AssociationManager
957
+
958
+ A sophisticated component for managing entity relationships and associations within your application. The AssociationManager provides an intuitive interface for creating, viewing, and managing complex many-to-many relationships between different data entities.
959
+
960
+ ```jsx
961
+ <AssociationManager
962
+ config={{
963
+ title: "Client Associations",
964
+ description: "Manage relationships between clients and projects",
965
+ primaryEntity: {
966
+ id: "clients",
967
+ label: "Clients",
968
+ displayKey: "name",
969
+ fetchUrl: "/api/clients"
970
+ },
971
+ secondaryEntity: {
972
+ id: "projects",
973
+ label: "Projects",
974
+ displayKey: "title",
975
+ fetchUrl: "/api/projects"
976
+ },
977
+ association: {
978
+ fetchUrl: "/api/client-project-associations",
979
+ createUrl: "/api/client-project-associations",
980
+ deleteUrl: "/api/client-project-associations",
981
+ pivotTable: "client_project"
982
+ },
983
+ permissions: {
984
+ canCreate: true,
985
+ canDelete: true,
986
+ canView: true
987
+ },
988
+ ui: {
989
+ searchPlaceholder: "Search clients or projects...",
990
+ emptyStateMessage: "No associations found",
991
+ confirmDeleteMessage: "Are you sure you want to remove this association?"
992
+ }
993
+ }}
994
+ userProfile={userProfile}
995
+ onAssociationChange={(data) => console.log('Association changed:', data)}
996
+ />
997
+ ```
998
+
999
+ **Key Features:**
1000
+
1001
+ 1. **Bidirectional Relationship Management**:
1002
+ - Create associations from either entity perspective
1003
+ - Automatic relationship synchronization
1004
+ - Real-time updates across related views
1005
+
1006
+ 2. **Advanced Search and Filtering**:
1007
+ - Multi-entity search capabilities
1008
+ - Filter by entity type, status, or custom attributes
1009
+ - Debounced search to optimize performance
1010
+
1011
+ 3. **Bulk Operations**:
1012
+ - Select multiple entities for batch association
1013
+ - Bulk delete with confirmation dialogs
1014
+ - Mass import/export functionality
1015
+
1016
+ 4. **Visual Association Mapping**:
1017
+ - Interactive relationship visualization
1018
+ - Drag-and-drop association creation
1019
+ - Color-coded entity types
1020
+
1021
+ 5. **Permission-Based Access Control**:
1022
+ - Granular permissions for create, read, update, delete
1023
+ - Role-based access to specific entity types
1024
+ - Custom permission validation
1025
+
1026
+ **Configuration Options:**
1027
+
1028
+ ```jsx
1029
+ const associationConfig = {
1030
+ // Required: Basic entity configuration
1031
+ primaryEntity: {
1032
+ id: "clients", // Unique identifier
1033
+ label: "Clients", // Display name
1034
+ displayKey: "name", // Field to show in lists
1035
+ fetchUrl: "/api/clients", // API endpoint
1036
+ searchFields: ["name", "email"], // Fields to search
1037
+ icon: "Users", // Lucide icon name
1038
+ color: "#3b82f6" // Brand color
1039
+ },
1040
+
1041
+ secondaryEntity: {
1042
+ id: "projects",
1043
+ label: "Projects",
1044
+ displayKey: "title",
1045
+ fetchUrl: "/api/projects",
1046
+ searchFields: ["title", "description"],
1047
+ icon: "FolderOpen",
1048
+ color: "#10b981"
1049
+ },
1050
+
1051
+ // Association configuration
1052
+ association: {
1053
+ fetchUrl: "/api/associations", // Get existing associations
1054
+ createUrl: "/api/associations", // Create new associations
1055
+ updateUrl: "/api/associations", // Update associations (optional)
1056
+ deleteUrl: "/api/associations", // Delete associations
1057
+ pivotTable: "client_project", // Database table name
1058
+
1059
+ // Additional pivot data
1060
+ pivotFields: [
1061
+ {
1062
+ name: "role",
1063
+ label: "Role",
1064
+ type: "select",
1065
+ options: [
1066
+ { value: "manager", label: "Manager" },
1067
+ { value: "contributor", label: "Contributor" }
1068
+ ]
1069
+ },
1070
+ {
1071
+ name: "start_date",
1072
+ label: "Start Date",
1073
+ type: "date"
1074
+ }
1075
+ ]
1076
+ },
1077
+
1078
+ // UI customization
1079
+ ui: {
1080
+ layout: "split", // "split", "tabs", "cards"
1081
+ theme: "default", // "default", "compact", "detailed"
1082
+ showEntityCounts: true, // Show association counts
1083
+ showLastModified: true, // Show modification timestamps
1084
+ enableDragDrop: true, // Enable drag-and-drop
1085
+ confirmActions: true, // Show confirmation dialogs
1086
+
1087
+ // Custom labels and messages
1088
+ labels: {
1089
+ createButton: "Add Association",
1090
+ deleteButton: "Remove",
1091
+ searchPlaceholder: "Search entities...",
1092
+ noResultsMessage: "No entities found",
1093
+ loadingMessage: "Loading associations..."
1094
+ }
1095
+ },
1096
+
1097
+ // Validation rules
1098
+ validation: {
1099
+ preventDuplicates: true, // Prevent duplicate associations
1100
+ requirePivotData: false, // Require additional pivot fields
1101
+ customValidation: (primary, secondary, pivotData) => {
1102
+ // Custom validation logic
1103
+ return { valid: true, message: "" };
1104
+ }
1105
+ },
1106
+
1107
+ // Performance optimization
1108
+ performance: {
1109
+ enableVirtualization: true, // For large datasets
1110
+ pageSize: 50, // Pagination size
1111
+ debounceMs: 300, // Search debounce
1112
+ cacheResults: true // Cache API responses
1113
+ }
1114
+ };
1115
+ ```
1116
+
1117
+ **API Integration:**
1118
+
1119
+ The AssociationManager expects specific API response formats:
1120
+
1121
+ ```javascript
1122
+ // GET /api/clients (Primary Entity)
1123
+ {
1124
+ "data": [
1125
+ {
1126
+ "id": 1,
1127
+ "name": "Acme Corp",
1128
+ "email": "contact@acme.com",
1129
+ "created_at": "2023-01-01T00:00:00Z"
1130
+ }
1131
+ ],
1132
+ "total": 150,
1133
+ "page": 1,
1134
+ "per_page": 50
1135
+ }
1136
+
1137
+ // GET /api/associations (Existing Associations)
1138
+ {
1139
+ "data": [
1140
+ {
1141
+ "id": 1,
1142
+ "primary_id": 1,
1143
+ "secondary_id": 5,
1144
+ "pivot_data": {
1145
+ "role": "manager",
1146
+ "start_date": "2023-01-01"
1147
+ },
1148
+ "primary": {
1149
+ "id": 1,
1150
+ "name": "Acme Corp"
1151
+ },
1152
+ "secondary": {
1153
+ "id": 5,
1154
+ "title": "Website Redesign"
1155
+ },
1156
+ "created_at": "2023-01-01T00:00:00Z"
1157
+ }
1158
+ ]
1159
+ }
1160
+
1161
+ // POST /api/associations (Create Association)
1162
+ {
1163
+ "primary_id": 1,
1164
+ "secondary_id": 5,
1165
+ "pivot_data": {
1166
+ "role": "manager",
1167
+ "start_date": "2023-01-01"
1168
+ }
1169
+ }
1170
+
1171
+ // Response:
1172
+ {
1173
+ "success": true,
1174
+ "data": {
1175
+ "id": 1,
1176
+ "primary_id": 1,
1177
+ "secondary_id": 5,
1178
+ "created_at": "2023-01-01T00:00:00Z"
1179
+ },
1180
+ "message": "Association created successfully"
1181
+ }
1182
+ ```
1183
+
1184
+ **Event Handling:**
1185
+
1186
+ ```jsx
1187
+ <AssociationManager
1188
+ config={associationConfig}
1189
+ onAssociationChange={(event) => {
1190
+ // event.type: 'created', 'updated', 'deleted'
1191
+ // event.data: Association data
1192
+ // event.entities: Affected entities
1193
+ console.log('Association event:', event);
1194
+ }}
1195
+ onEntitySelect={(entity, type) => {
1196
+ // Handle entity selection
1197
+ console.log('Entity selected:', entity, type);
1198
+ }}
1199
+ onError={(error) => {
1200
+ // Handle errors
1201
+ console.error('Association error:', error);
1202
+ }}
1203
+ />
1204
+ ```
1205
+
1206
+ **Advanced Usage Examples:**
1207
+
1208
+ 1. **Client-Project Association with Roles**:
1209
+ ```jsx
1210
+ // Managing client assignments to projects with specific roles
1211
+ <AssociationManager
1212
+ config={{
1213
+ primaryEntity: { id: "clients", label: "Clients", ... },
1214
+ secondaryEntity: { id: "projects", label: "Projects", ... },
1215
+ association: {
1216
+ pivotFields: [
1217
+ {
1218
+ name: "role",
1219
+ label: "Role in Project",
1220
+ type: "select",
1221
+ required: true,
1222
+ options: [
1223
+ { value: "sponsor", label: "Project Sponsor" },
1224
+ { value: "stakeholder", label: "Key Stakeholder" },
1225
+ { value: "user", label: "End User" }
1226
+ ]
1227
+ }
1228
+ ]
1229
+ }
1230
+ }}
1231
+ />
1232
+ ```
1233
+
1234
+ 2. **User-Permission Association**:
1235
+ ```jsx
1236
+ // Managing user permissions with expiration dates
1237
+ <AssociationManager
1238
+ config={{
1239
+ primaryEntity: { id: "users", label: "Users", ... },
1240
+ secondaryEntity: { id: "permissions", label: "Permissions", ... },
1241
+ association: {
1242
+ pivotFields: [
1243
+ {
1244
+ name: "expires_at",
1245
+ label: "Expiration Date",
1246
+ type: "datetime",
1247
+ required: false
1248
+ },
1249
+ {
1250
+ name: "granted_by",
1251
+ label: "Granted By",
1252
+ type: "select",
1253
+ fetchUrl: "/api/users/managers"
1254
+ }
1255
+ ]
1256
+ }
1257
+ }}
1258
+ />
1259
+ ```
1260
+
1261
+ ### Business Card OCR Component
1262
+
1263
+ #### BusinessCardOcr (Enhanced v5.11.1+)
1264
+
1265
+ An advanced OCR (Optical Character Recognition) component specifically designed for scanning business cards and automatically extracting contact information. The component provides intelligent text recognition, client matching, and seamless contact management integration.
1266
+
1267
+ ```jsx
1268
+ <BusinessCardOcr
1269
+ isOpen={showScanner}
1270
+ onClose={() => setShowScanner(false)}
1271
+ onContactSaved={(contact) => {
1272
+ console.log('Contact saved:', contact);
1273
+ // Handle the saved contact data
1274
+ }}
1275
+ fields={[
1276
+ { id: 'name', label: 'Full Name', required: true },
1277
+ { id: 'email', label: 'Email', type: 'email' },
1278
+ { id: 'phone', label: 'Phone', type: 'tel' },
1279
+ { id: 'company', label: 'Company' },
1280
+ { id: 'position', label: 'Position' },
1281
+ { id: 'address', label: 'Address', type: 'textarea' }
1282
+ ]}
1283
+ fetchConfig={{
1284
+ ocrUrl: '/api/ocr/business-card',
1285
+ saveUrl: '/api/contacts',
1286
+ clientSearchUrl: '/api/clients/search',
1287
+ duplicateCheckUrl: '/api/contacts/check-duplicate'
1288
+ }}
1289
+ settings={{
1290
+ enableClientMatching: true,
1291
+ enableDuplicateCheck: true,
1292
+ autoSave: false,
1293
+ imageQuality: 0.8,
1294
+ supportedFormats: ['image/jpeg', 'image/png', 'image/webp']
1295
+ }}
1296
+ />
1297
+ ```
1298
+
1299
+ **Key Features:**
1300
+
1301
+ 1. **Advanced OCR Processing**:
1302
+ - High-accuracy text extraction from business card images
1303
+ - Intelligent field mapping and recognition
1304
+ - Support for multiple languages and formats
1305
+ - Automatic rotation and perspective correction
1306
+
1307
+ 2. **Smart Client Matching**:
1308
+ - Automatic company name recognition
1309
+ - Fuzzy matching against existing client database
1310
+ - Confidence scoring for match suggestions
1311
+ - Manual override and confirmation options
1312
+
1313
+ 3. **Duplicate Detection**:
1314
+ - Email and phone number duplicate checking
1315
+ - Visual comparison with existing contacts
1316
+ - Merge or create new contact options
1317
+ - Conflict resolution interface
1318
+
1319
+ 4. **Interactive Editing Interface**:
1320
+ - Real-time field editing and validation
1321
+ - Drag-and-drop image upload
1322
+ - Live camera capture (mobile devices)
1323
+ - Field confidence indicators
1324
+
1325
+ 5. **Contact Management Integration**:
1326
+ - Direct save to contact database
1327
+ - Custom field mapping and validation
1328
+ - Bulk import capabilities
1329
+ - Export to various formats
1330
+
1331
+ **Configuration Options:**
1332
+
1333
+ ```jsx
1334
+ const businessCardConfig = {
1335
+ // Field definitions for extracted data
1336
+ fields: [
1337
+ {
1338
+ id: 'name',
1339
+ label: 'Full Name',
1340
+ type: 'text',
1341
+ required: true,
1342
+ validation: {
1343
+ minLength: 2,
1344
+ pattern: /^[a-zA-Z\s]+$/
1345
+ },
1346
+ ocrMapping: ['name', 'full_name', 'contact_name']
1347
+ },
1348
+ {
1349
+ id: 'email',
1350
+ label: 'Email Address',
1351
+ type: 'email',
1352
+ required: false,
1353
+ validation: {
1354
+ pattern: /^[^\s@]+@[^\s@]+\.[^\s@]+$/
1355
+ },
1356
+ ocrMapping: ['email', 'e_mail', 'email_address']
1357
+ },
1358
+ {
1359
+ id: 'phone',
1360
+ label: 'Phone Number',
1361
+ type: 'tel',
1362
+ required: false,
1363
+ formatting: {
1364
+ mask: '(000) 000-0000',
1365
+ international: true
1366
+ },
1367
+ ocrMapping: ['phone', 'mobile', 'telephone', 'cell']
1368
+ },
1369
+ {
1370
+ id: 'company',
1371
+ label: 'Company Name',
1372
+ type: 'text',
1373
+ required: false,
1374
+ clientMatching: true, // Enable client matching for this field
1375
+ ocrMapping: ['company', 'organization', 'business_name']
1376
+ },
1377
+ {
1378
+ id: 'position',
1379
+ label: 'Job Title',
1380
+ type: 'text',
1381
+ required: false,
1382
+ ocrMapping: ['title', 'position', 'job_title', 'role']
1383
+ },
1384
+ {
1385
+ id: 'address',
1386
+ label: 'Address',
1387
+ type: 'textarea',
1388
+ required: false,
1389
+ formatting: {
1390
+ multiline: true,
1391
+ rows: 3
1392
+ },
1393
+ ocrMapping: ['address', 'location', 'street_address']
1394
+ },
1395
+ {
1396
+ id: 'website',
1397
+ label: 'Website',
1398
+ type: 'url',
1399
+ required: false,
1400
+ validation: {
1401
+ pattern: /^https?:\/\/.+/
1402
+ },
1403
+ ocrMapping: ['website', 'url', 'web', 'site']
1404
+ }
1405
+ ],
1406
+
1407
+ // API endpoint configuration
1408
+ fetchConfig: {
1409
+ ocrUrl: '/api/ocr/business-card', // OCR processing endpoint
1410
+ saveUrl: '/api/contacts', // Contact save endpoint
1411
+ clientSearchUrl: '/api/clients/search', // Client matching endpoint
1412
+ duplicateCheckUrl: '/api/contacts/check', // Duplicate check endpoint
1413
+ uploadUrl: '/api/files/upload', // Image upload endpoint
1414
+
1415
+ // Request configuration
1416
+ timeout: 30000, // 30 second timeout
1417
+ retries: 3, // Retry failed requests
1418
+ headers: {
1419
+ 'Accept': 'application/json',
1420
+ 'X-Requested-With': 'XMLHttpRequest'
1421
+ }
1422
+ },
1423
+
1424
+ // Component behavior settings
1425
+ settings: {
1426
+ // OCR settings
1427
+ imageQuality: 0.8, // Image compression quality
1428
+ maxImageSize: 5242880, // 5MB max file size
1429
+ supportedFormats: [ // Accepted image formats
1430
+ 'image/jpeg',
1431
+ 'image/png',
1432
+ 'image/webp',
1433
+ 'image/bmp'
1434
+ ],
1435
+
1436
+ // Processing options
1437
+ enableClientMatching: true, // Enable company matching
1438
+ enableDuplicateCheck: true, // Check for duplicates
1439
+ autoSave: false, // Auto-save after OCR
1440
+ requireConfirmation: true, // Confirm before saving
1441
+
1442
+ // UI options
1443
+ showConfidenceScores: true, // Show OCR confidence
1444
+ enableManualEdit: true, // Allow manual editing
1445
+ showImagePreview: true, // Show uploaded image
1446
+ enableCameraCapture: true, // Enable camera on mobile
1447
+
1448
+ // Validation options
1449
+ validateOnBlur: true, // Validate fields on blur
1450
+ highlightErrors: true, // Highlight validation errors
1451
+ showTooltips: true, // Show field tooltips
1452
+
1453
+ // Performance options
1454
+ debounceMs: 500, // Debounce for auto-save
1455
+ cacheResults: true, // Cache OCR results
1456
+ enablePreprocessing: true // Image preprocessing
1457
+ },
1458
+
1459
+ // UI customization
1460
+ ui: {
1461
+ theme: 'default', // 'default', 'compact', 'minimal'
1462
+ layout: 'modal', // 'modal', 'inline', 'drawer'
1463
+ size: 'large', // 'small', 'medium', 'large'
1464
+
1465
+ // Labels and messages
1466
+ labels: {
1467
+ uploadButton: 'Upload Business Card',
1468
+ scanButton: 'Scan with Camera',
1469
+ saveButton: 'Save Contact',
1470
+ cancelButton: 'Cancel',
1471
+ editButton: 'Edit Information',
1472
+ processButton: 'Process Image'
1473
+ },
1474
+
1475
+ messages: {
1476
+ uploadPrompt: 'Drop an image here or click to upload',
1477
+ processing: 'Processing business card...',
1478
+ ocrSuccess: 'Text extracted successfully',
1479
+ ocrError: 'Failed to process image',
1480
+ saveSuccess: 'Contact saved successfully',
1481
+ duplicateFound: 'Duplicate contact detected'
1482
+ },
1483
+
1484
+ // Style customization
1485
+ styles: {
1486
+ primaryColor: '#3b82f6',
1487
+ successColor: '#10b981',
1488
+ errorColor: '#ef4444',
1489
+ borderRadius: '8px',
1490
+ boxShadow: '0 4px 6px rgba(0, 0, 0, 0.1)'
1491
+ }
1492
+ }
1493
+ };
1494
+ ```
1495
+
1496
+ **API Integration:**
1497
+
1498
+ The BusinessCardOcr component expects specific API response formats:
1499
+
1500
+ ```javascript
1501
+ // POST /api/ocr/business-card (OCR Processing)
1502
+ // Request: FormData with image file
1503
+ {
1504
+ "image": File
1505
+ }
1506
+
1507
+ // Response:
1508
+ {
1509
+ "success": true,
1510
+ "data": {
1511
+ "extracted_text": "John Smith\nSenior Developer\nAcme Corp\nj.smith@acme.com\n(555) 123-4567",
1512
+ "fields": {
1513
+ "name": {
1514
+ "value": "John Smith",
1515
+ "confidence": 0.95,
1516
+ "position": { "x": 100, "y": 50, "width": 200, "height": 30 }
1517
+ },
1518
+ "email": {
1519
+ "value": "j.smith@acme.com",
1520
+ "confidence": 0.92,
1521
+ "position": { "x": 100, "y": 120, "width": 250, "height": 25 }
1522
+ },
1523
+ "company": {
1524
+ "value": "Acme Corp",
1525
+ "confidence": 0.88,
1526
+ "position": { "x": 100, "y": 80, "width": 150, "height": 25 }
1527
+ }
1528
+ },
1529
+ "processing_time": 2.3,
1530
+ "image_url": "/storage/uploads/card_123.jpg"
1531
+ }
1532
+ }
1533
+
1534
+ // GET /api/clients/search (Client Matching)
1535
+ {
1536
+ "query": "Acme Corp"
1537
+ }
1538
+
1539
+ // Response:
1540
+ {
1541
+ "data": [
1542
+ {
1543
+ "id": 5,
1544
+ "name": "Acme Corporation",
1545
+ "match_score": 0.85,
1546
+ "address": "123 Business St",
1547
+ "phone": "(555) 987-6543",
1548
+ "website": "https://acme.com"
1549
+ }
1550
+ ]
1551
+ }
1552
+
1553
+ // POST /api/contacts/check (Duplicate Check)
1554
+ {
1555
+ "email": "j.smith@acme.com",
1556
+ "phone": "(555) 123-4567"
1557
+ }
1558
+
1559
+ // Response:
1560
+ {
1561
+ "duplicates": [
1562
+ {
1563
+ "id": 10,
1564
+ "name": "John Smith",
1565
+ "email": "j.smith@acme.com",
1566
+ "match_type": "email",
1567
+ "match_score": 1.0,
1568
+ "created_at": "2023-01-01T00:00:00Z"
1569
+ }
1570
+ ]
1571
+ }
1572
+
1573
+ // POST /api/contacts (Save Contact)
1574
+ {
1575
+ "name": "John Smith",
1576
+ "email": "j.smith@acme.com",
1577
+ "phone": "(555) 123-4567",
1578
+ "company": "Acme Corp",
1579
+ "position": "Senior Developer",
1580
+ "client_id": 5,
1581
+ "source": "business_card_ocr",
1582
+ "confidence_scores": {
1583
+ "name": 0.95,
1584
+ "email": 0.92,
1585
+ "company": 0.88
1586
+ }
1587
+ }
1588
+
1589
+ // Response:
1590
+ {
1591
+ "success": true,
1592
+ "data": {
1593
+ "id": 15,
1594
+ "name": "John Smith",
1595
+ "created_at": "2023-01-01T00:00:00Z"
1596
+ },
1597
+ "message": "Contact created successfully"
1598
+ }
1599
+ ```
1600
+
1601
+ **Event Handling:**
1602
+
1603
+ ```jsx
1604
+ <BusinessCardOcr
1605
+ isOpen={showScanner}
1606
+ onClose={() => setShowScanner(false)}
1607
+ onContactSaved={(contact) => {
1608
+ // Handle successful contact save
1609
+ console.log('New contact saved:', contact);
1610
+
1611
+ // Optional: Update parent component state
1612
+ setContacts(prev => [...prev, contact]);
1613
+
1614
+ // Optional: Show success notification
1615
+ toast.success(`Contact ${contact.name} saved successfully`);
1616
+ }}
1617
+ onOcrComplete={(extractedData) => {
1618
+ // Handle OCR completion
1619
+ console.log('OCR extraction completed:', extractedData);
1620
+
1621
+ // Optional: Custom processing of extracted data
1622
+ if (extractedData.confidence < 0.7) {
1623
+ toast.warning('Low confidence OCR results. Please review carefully.');
1624
+ }
1625
+ }}
1626
+ onClientMatch={(matches) => {
1627
+ // Handle client matching results
1628
+ console.log('Client matches found:', matches);
1629
+
1630
+ // Optional: Auto-select high confidence matches
1631
+ if (matches.length === 1 && matches[0].match_score > 0.9) {
1632
+ // Auto-select the best match
1633
+ return matches[0];
1634
+ }
1635
+ }}
1636
+ onDuplicateDetected={(duplicates) => {
1637
+ // Handle duplicate detection
1638
+ console.log('Duplicate contacts found:', duplicates);
1639
+
1640
+ // Optional: Custom duplicate handling logic
1641
+ return new Promise((resolve) => {
1642
+ // Show custom duplicate resolution UI
1643
+ showDuplicateDialog(duplicates, resolve);
1644
+ });
1645
+ }}
1646
+ onError={(error) => {
1647
+ // Handle errors
1648
+ console.error('OCR error:', error);
1649
+
1650
+ // Optional: Custom error handling
1651
+ if (error.type === 'network') {
1652
+ toast.error('Network error. Please check your connection.');
1653
+ } else if (error.type === 'validation') {
1654
+ toast.error('Please correct the highlighted fields.');
1655
+ }
1656
+ }}
1657
+ />
1658
+ ```
1659
+
1660
+ **Advanced Usage Examples:**
1661
+
1662
+ 1. **Integration with Existing Contact Form**:
1663
+ ```jsx
1664
+ const ContactForm = () => {
1665
+ const [showOcr, setShowOcr] = useState(false);
1666
+ const [formData, setFormData] = useState({});
1667
+
1668
+ return (
1669
+ <div>
1670
+ <Form data={formData} onChange={setFormData}>
1671
+ {/* Regular form fields */}
1672
+ </Form>
1673
+
1674
+ <button onClick={() => setShowOcr(true)}>
1675
+ Scan Business Card
1676
+ </button>
1677
+
1678
+ <BusinessCardOcr
1679
+ isOpen={showOcr}
1680
+ onClose={() => setShowOcr(false)}
1681
+ onContactSaved={(contact) => {
1682
+ // Pre-fill form with OCR data
1683
+ setFormData(contact);
1684
+ setShowOcr(false);
1685
+ }}
1686
+ />
1687
+ </div>
1688
+ );
1689
+ };
1690
+ ```
1691
+
1692
+ 2. **Bulk Business Card Processing**:
1693
+ ```jsx
1694
+ const BulkCardProcessor = () => {
1695
+ const [queue, setQueue] = useState([]);
1696
+
1697
+ return (
1698
+ <BusinessCardOcr
1699
+ settings={{
1700
+ autoSave: true,
1701
+ enableBulkMode: true
1702
+ }}
1703
+ onContactSaved={(contact) => {
1704
+ setQueue(prev => [...prev, contact]);
1705
+ }}
1706
+ onBulkComplete={(contacts) => {
1707
+ console.log(`Processed ${contacts.length} business cards`);
1708
+ }}
1709
+ />
1710
+ );
1711
+ };
1712
+ ```
1713
+
954
1714
  ### Utility Components
955
1715
 
956
1716
  #### CustomFetch
@@ -1309,9 +2069,9 @@ Response:
1309
2069
 
1310
2070
  ### Report Builder Component
1311
2071
 
1312
- #### GenericReport
2072
+ #### GenericReport (Enhanced v5.10.11+)
1313
2073
 
1314
- A powerful report building component that allows users to create custom reports by selecting tables, columns, and configuring joins, filters, and sorting.
2074
+ A powerful and enhanced report building component that provides an intuitive wizard-based interface for creating custom reports. The component has been significantly improved with new features and better user experience.
1315
2075
 
1316
2076
  ```jsx
1317
2077
  <GenericReport
@@ -1322,19 +2082,108 @@ A powerful report building component that allows users to create custom reports
1322
2082
  executeUrl: '/ajax/reportBuilder/execute',
1323
2083
  suggestedJoinsUrl: '/ajax/reportBuilder/getSuggestedJoins',
1324
2084
  }}
2085
+ userProfile={userProfile}
2086
+ businessTemplates={businessTemplates} // Optional pre-built templates
1325
2087
  />
1326
2088
  ```
1327
2089
 
1328
- The GenericReport component provides these features:
2090
+ **Major Enhancements:**
2091
+
2092
+ - **5-Step Wizard Interface**: Guided workflow with visual progress indicators
2093
+ - **Business Templates**: Pre-built report templates for common business scenarios
2094
+ - **Calculated Fields**: Create custom formulas and calculations within reports
2095
+ - **Smart Column Selection**: Automatic suggestions based on table relationships
2096
+ - **Enhanced Filtering**: Advanced filter options with AND/OR logic and grouping
2097
+ - **Live Preview**: Real-time preview of report data as you build
2098
+ - **Intelligent Currency Formatting**: Automatic detection and formatting of monetary fields
2099
+ - **Expandable Field Summary**: View selected fields in a collapsible overview
2100
+ - **Template Management**: Save, load, and share report templates
2101
+ - **Multiple Export Formats**: Export to Excel, CSV, PDF with formatting options
2102
+
2103
+ **New Features in Recent Updates:**
2104
+
2105
+ 1. **Calculated Fields (v5.10.12+)**:
2106
+ ```jsx
2107
+ // Users can create custom calculated fields
2108
+ {
2109
+ id: 'profit_margin',
2110
+ displayName: 'Profit Margin %',
2111
+ formula: 'ROUND(((revenue - cost) / revenue) * 100, 2)',
2112
+ type: 'decimal'
2113
+ }
2114
+ ```
2115
+
2116
+ 2. **Business Templates (v5.11.0+)**:
2117
+ ```jsx
2118
+ // Pre-built templates for common scenarios
2119
+ const businessTemplates = [
2120
+ {
2121
+ id: 'utilization_planning',
2122
+ name: 'Utilization Planning',
2123
+ description: 'Weekly resource allocation and laydown utilization',
2124
+ icon: 'Calendar',
2125
+ mainTable: 'leads',
2126
+ defaultColumns: [...],
2127
+ calculatedFields: [...]
2128
+ }
2129
+ ];
2130
+ ```
2131
+
2132
+ 3. **Smart Currency Detection**:
2133
+ - Automatically formats fields containing 'value', 'price', 'cost', 'amount', etc.
2134
+ - Supports Australian Dollar (AUD) formatting by default
2135
+ - Configurable currency formatting options
2136
+
2137
+ 4. **Enhanced UI/UX**:
2138
+ - Lucide React icons throughout for consistency
2139
+ - Larger calculated field display for better visibility
2140
+ - Expandable selected fields summary
2141
+ - Step-by-step guidance with tooltips and help text
2142
+
2143
+ **The 5-Step Wizard Process:**
2144
+
2145
+ 1. **Select Data Source**: Choose main table and review business templates
2146
+ 2. **Choose Columns**: Select specific data fields with drag-and-drop reordering
2147
+ 3. **Add Relationships**: Connect related tables with automatic join suggestions
2148
+ 4. **Apply Filters**: Set conditions and date ranges with advanced logic
2149
+ 5. **Generate & Export**: Preview results and export in multiple formats
2150
+
2151
+ **API Integration:**
2152
+
2153
+ The component expects these endpoint responses:
2154
+
2155
+ ```javascript
2156
+ // Tables endpoint
2157
+ {
2158
+ "tables": [
2159
+ {
2160
+ "id": "clients",
2161
+ "label": "Clients",
2162
+ "description": "Customer information"
2163
+ }
2164
+ ]
2165
+ }
2166
+
2167
+ // Columns endpoint
2168
+ {
2169
+ "columns": [
2170
+ {
2171
+ "name": "id",
2172
+ "type": "integer",
2173
+ "nullable": false,
2174
+ "key": "primary"
2175
+ }
2176
+ ]
2177
+ }
1329
2178
 
1330
- - **Table Selection**: Choose a main table for the report
1331
- - **Column Selection**: Select columns to include in the report
1332
- - **Table Joins**: Add related tables with automatic relationship detection
1333
- - **Filtering**: Apply filters to the report data
1334
- - **Sorting**: Sort the report results
1335
- - **Report Preview**: View a preview of the report data
1336
- - **Save/Load Reports**: Save reports for future use and load saved reports
1337
- - **Export**: Export reports in various formats
2179
+ // Execute endpoint
2180
+ {
2181
+ "success": true,
2182
+ "data": [...],
2183
+ "total": 150,
2184
+ "query": "SELECT ... FROM ..."
2185
+ }
2186
+ ```
1338
2187
 
1339
2188
  ### Sketch Field Component
1340
2189
 
@@ -1501,6 +2350,359 @@ We welcome contributions! Please follow these steps:
1501
2350
 
1502
2351
  [MIT License](LICENSE)
1503
2352
 
2353
+ ### Quote Management Components
2354
+
2355
+ #### GenericQuote (Enhanced with Proposal System v5.12.0+)
2356
+
2357
+ The GenericQuote component provides comprehensive quote management with integrated proposal generation capabilities. It supports both traditional quote display and full proposal creation with cover pages, table of contents, and customizable sections.
2358
+
2359
+ ```jsx
2360
+ <GenericQuote
2361
+ config={{
2362
+ // Basic quote configuration
2363
+ data: quoteData,
2364
+ currency: "AUD",
2365
+ companyLogo: "/path/to/logo.png",
2366
+
2367
+ // Standard features
2368
+ showLineItems: true,
2369
+ allowEditing: true,
2370
+ showNotes: true,
2371
+
2372
+ // Enhanced proposal features (v5.12.0+)
2373
+ proposalMode: {
2374
+ enabled: true,
2375
+ templateId: 1,
2376
+ brandingProfileId: 2,
2377
+ customSections: [
2378
+ {
2379
+ type: 'overview',
2380
+ title: 'Project Overview',
2381
+ content: '<h1>Executive Summary</h1><p>This proposal outlines...</p>'
2382
+ },
2383
+ {
2384
+ type: 'terms_conditions',
2385
+ title: 'Terms & Conditions',
2386
+ content: '<h3>Payment Terms</h3><p>Net 30 days...</p>'
2387
+ }
2388
+ ]
2389
+ }
2390
+ }}
2391
+ userProfile={userProfile}
2392
+ onQuoteSave={(quoteData) => handleQuoteSave(quoteData)}
2393
+ onProposalGenerate={(proposalData) => handleProposalGeneration(proposalData)}
2394
+ />
2395
+ ```
2396
+
2397
+ **New Proposal Features:**
2398
+
2399
+ 1. **Proposal Mode Toggle**:
2400
+ - Seamlessly switch between quote view and proposal generation mode
2401
+ - Maintains full backward compatibility with existing quote functionality
2402
+ - Context-aware interface that adapts based on proposal configuration
2403
+
2404
+ 2. **Template Management Integration**:
2405
+ - Select from pre-configured proposal templates
2406
+ - Template preview with variable substitution
2407
+ - Custom section creation and ordering
2408
+ - Dynamic content population from quote data
2409
+
2410
+ 3. **Branding Profile Support**:
2411
+ - Company logo and branding integration
2412
+ - Custom color schemes and styling
2413
+ - Professional cover page generation
2414
+ - Consistent brand presentation
2415
+
2416
+ 4. **Advanced Section Management**:
2417
+ - **Cover Page**: Company branding with proposal title and customer details
2418
+ - **Table of Contents**: Auto-generated from all proposal sections
2419
+ - **Overview**: Executive summary with custom headers (H1, H2, H3) and content
2420
+ - **Quote Items**: Pricing table following original quote structure
2421
+ - **Terms & Conditions**: Static legal terms (rarely changes)
2422
+ - **Payment Terms**: Dynamic payment schedules and due dates
2423
+ - **Review Log**: Version history and change tracking
2424
+ - **Agreement & Signatures**: Static signature section for approvals
2425
+
2426
+ 5. **Dynamic Content System**:
2427
+ - Variable replacement throughout all sections
2428
+ - Real-time preview of populated content
2429
+ - Support for both static and dynamic sections
2430
+ - Custom variable definitions per template
2431
+
2432
+ **Configuration Options:**
2433
+
2434
+ ```jsx
2435
+ const proposalConfig = {
2436
+ // Enable proposal features
2437
+ enabled: true,
2438
+
2439
+ // Template selection
2440
+ templateId: 1, // Selected proposal template
2441
+ allowTemplateChange: true, // Allow template switching
2442
+
2443
+ // Branding configuration
2444
+ brandingProfileId: 2, // Selected branding profile
2445
+ allowBrandingChange: true, // Allow branding changes
2446
+
2447
+ // Section customization
2448
+ customSections: [
2449
+ {
2450
+ type: 'overview',
2451
+ title: 'Project Overview',
2452
+ content: '<h1>Executive Summary</h1><p>Custom content...</p>',
2453
+ variables: {
2454
+ 'project_scope': 'Website development and maintenance',
2455
+ 'timeline': '8-12 weeks'
2456
+ }
2457
+ }
2458
+ ],
2459
+
2460
+ // Generation settings
2461
+ autoGenerateTOC: true, // Auto-generate table of contents
2462
+ includePageNumbers: true, // Add page numbers to PDF
2463
+ watermark: false, // Add watermark to pages
2464
+
2465
+ // PDF export options
2466
+ paperSize: 'A4', // Paper size for PDF generation
2467
+ orientation: 'portrait', // Page orientation
2468
+ margins: '40px', // Page margins
2469
+
2470
+ // UI customization
2471
+ showPreview: true, // Show live preview panel
2472
+ previewMode: 'split', // 'split', 'modal', 'tabs'
2473
+ enableSectionReorder: true, // Allow section drag-and-drop
2474
+ showVariableHelper: true, // Show available variables
2475
+ };
2476
+ ```
2477
+
2478
+ **Available Variables for Dynamic Content:**
2479
+
2480
+ The proposal system supports these built-in variables that are automatically populated from quote and customer data:
2481
+
2482
+ ```javascript
2483
+ // Customer Information
2484
+ {{customer_name}} // Customer company name
2485
+ {{customer_address}} // Customer full address
2486
+ {{customer_contact}} // Primary contact name
2487
+ {{customer_email}} // Primary contact email
2488
+ {{customer_phone}} // Primary contact phone
2489
+
2490
+ // Quote Information
2491
+ {{quote_number}} // Quote/proposal number
2492
+ {{quote_date}} // Quote creation date
2493
+ {{quote_valid_until}} // Quote expiration date
2494
+ {{total_amount}} // Total quote amount (formatted)
2495
+ {{total_ex_gst}} // Total excluding GST
2496
+ {{total_gst}} // GST amount
2497
+ {{currency}} // Currency symbol/code
2498
+
2499
+ // Company Information
2500
+ {{company_name}} // Your company name
2501
+ {{company_address}} // Your company address
2502
+ {{company_phone}} // Your company phone
2503
+ {{company_email}} // Your company email
2504
+ {{company_website}} // Your company website
2505
+ {{company_abn}} // Australian Business Number
2506
+
2507
+ // Project Information
2508
+ {{project_manager}} // Assigned project manager
2509
+ {{project_timeline}} // Estimated timeline
2510
+ {{project_scope}} // Project scope description
2511
+
2512
+ // Date Variables
2513
+ {{current_date}} // Current date
2514
+ {{due_date}} // Payment due date
2515
+ {{start_date}} // Project start date
2516
+
2517
+ // Item-Specific Variables
2518
+ {{items_onceoff}} // One-time purchase items table
2519
+ {{items_monthly}} // Monthly subscription items table
2520
+ {{items_yearly}} // Yearly subscription items table
2521
+ {{line_items_total}} // Total number of line items
2522
+ ```
2523
+
2524
+ **Integration with visns-packages Backend:**
2525
+
2526
+ The GenericQuote component seamlessly integrates with the visns-packages proposal system:
2527
+
2528
+ ```jsx
2529
+ // Backend integration endpoints
2530
+ const proposalEndpoints = {
2531
+ // Template management
2532
+ templates: '/ajax/proposal-templates',
2533
+ templatePreview: '/ajax/proposal-templates/{id}/preview',
2534
+
2535
+ // Branding profiles
2536
+ brandingProfiles: '/ajax/branding-profiles',
2537
+ brandingCSS: '/ajax/branding-profiles/{id}/css',
2538
+
2539
+ // PDF generation
2540
+ generatePDF: '/ajax/pdf/generate-proposal',
2541
+ previewHTML: '/ajax/pdf/preview-proposal',
2542
+
2543
+ // Variable helpers
2544
+ availableVariables: '/ajax/proposal-templates/variables/available'
2545
+ };
2546
+ ```
2547
+
2548
+ **Event Handling:**
2549
+
2550
+ ```jsx
2551
+ <GenericQuote
2552
+ config={quoteConfig}
2553
+ // Quote events (existing)
2554
+ onQuoteSave={(data) => console.log('Quote saved:', data)}
2555
+ onLineItemChange={(items) => console.log('Line items updated:', items)}
2556
+
2557
+ // New proposal events
2558
+ onProposalGenerate={(proposalData) => {
2559
+ console.log('Proposal generated:', proposalData);
2560
+ // Handle PDF generation or preview
2561
+ }}
2562
+ onTemplateChange={(templateId) => {
2563
+ console.log('Template changed to:', templateId);
2564
+ // Update template-specific settings
2565
+ }}
2566
+ onBrandingChange={(brandingId) => {
2567
+ console.log('Branding changed to:', brandingId);
2568
+ // Update branding-specific styling
2569
+ }}
2570
+ onSectionUpdate={(sections) => {
2571
+ console.log('Sections updated:', sections);
2572
+ // Handle custom section changes
2573
+ }}
2574
+ onVariableChange={(variables) => {
2575
+ console.log('Variables updated:', variables);
2576
+ // Handle variable substitution updates
2577
+ }}
2578
+ />
2579
+ ```
2580
+
2581
+ **Backward Compatibility:**
2582
+
2583
+ All existing GenericQuote functionality remains unchanged:
2584
+ - Standard quote display and editing
2585
+ - Line item management
2586
+ - Notes and attachments
2587
+ - Export capabilities
2588
+ - Custom actions and workflows
2589
+
2590
+ Proposal features are **opt-in** and activated only when `proposalConfig.enabled: true` is set.
2591
+
2592
+ **Advanced Usage Example:**
2593
+
2594
+ ```jsx
2595
+ import React, { useState } from 'react';
2596
+ import { GenericQuote } from '@visns-studio/visns-components';
2597
+
2598
+ const QuoteProposalManager = () => {
2599
+ const [quoteData, setQuoteData] = useState({
2600
+ id: 1,
2601
+ number: 'Q-2024-001',
2602
+ customer: {
2603
+ name: 'Acme Corporation',
2604
+ address: '123 Business St, Sydney NSW 2000',
2605
+ contact: 'John Smith',
2606
+ email: 'john@acme.com'
2607
+ },
2608
+ items: [
2609
+ {
2610
+ description: 'Website Development',
2611
+ quantity: 1,
2612
+ rate: 5000,
2613
+ total: 5000,
2614
+ type: 'onceoff'
2615
+ },
2616
+ {
2617
+ description: 'Monthly Hosting',
2618
+ quantity: 1,
2619
+ rate: 99,
2620
+ total: 99,
2621
+ type: 'monthly'
2622
+ }
2623
+ ],
2624
+ total: 5099
2625
+ });
2626
+
2627
+ const [proposalMode, setProposalMode] = useState(false);
2628
+
2629
+ const proposalConfig = {
2630
+ enabled: true,
2631
+ templateId: 1,
2632
+ brandingProfileId: 1,
2633
+ customSections: [
2634
+ {
2635
+ type: 'overview',
2636
+ title: 'Project Overview',
2637
+ content: `
2638
+ <h1>Executive Summary</h1>
2639
+ <p>This proposal outlines our recommended solution for {{customer_name}}.</p>
2640
+
2641
+ <h2>Project Scope</h2>
2642
+ <p>We will develop a modern, responsive website that meets your business requirements.</p>
2643
+
2644
+ <h3>Key Deliverables</h3>
2645
+ <ul>
2646
+ <li>Custom website design and development</li>
2647
+ <li>Content management system</li>
2648
+ <li>Mobile-responsive design</li>
2649
+ <li>SEO optimization</li>
2650
+ </ul>
2651
+ `
2652
+ }
2653
+ ],
2654
+ autoGenerateTOC: true,
2655
+ showPreview: true,
2656
+ previewMode: 'split'
2657
+ };
2658
+
2659
+ return (
2660
+ <div className="quote-proposal-manager">
2661
+ <div className="mode-toggle">
2662
+ <button
2663
+ onClick={() => setProposalMode(false)}
2664
+ className={!proposalMode ? 'active' : ''}
2665
+ >
2666
+ Quote View
2667
+ </button>
2668
+ <button
2669
+ onClick={() => setProposalMode(true)}
2670
+ className={proposalMode ? 'active' : ''}
2671
+ >
2672
+ Proposal Builder
2673
+ </button>
2674
+ </div>
2675
+
2676
+ <GenericQuote
2677
+ config={{
2678
+ data: quoteData,
2679
+ currency: "AUD",
2680
+ showLineItems: true,
2681
+ allowEditing: !proposalMode,
2682
+
2683
+ // Enable proposal features based on mode
2684
+ proposalMode: proposalMode ? proposalConfig : { enabled: false }
2685
+ }}
2686
+ userProfile={userProfile}
2687
+ onQuoteSave={(data) => {
2688
+ setQuoteData(data);
2689
+ console.log('Quote updated:', data);
2690
+ }}
2691
+ onProposalGenerate={(proposalData) => {
2692
+ // Generate PDF or handle proposal data
2693
+ console.log('Generating proposal PDF:', proposalData);
2694
+
2695
+ // Example: Download PDF
2696
+ window.open(`/ajax/pdf/generate-proposal?quote_id=${quoteData.id}`, '_blank');
2697
+ }}
2698
+ />
2699
+ </div>
2700
+ );
2701
+ };
2702
+
2703
+ export default QuoteProposalManager;
2704
+ ```
2705
+
1504
2706
  ## Modal Actions in Components
1505
2707
 
1506
2708
  ### Using Modal Actions in GenericQuote Component