@visns-studio/visns-components 5.15.14 → 5.15.16
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
|
@@ -13,6 +13,7 @@ VISNS Components is a React-based UI component library that provides a set of re
|
|
|
13
13
|
|
|
14
14
|
### Latest Enhancements
|
|
15
15
|
|
|
16
|
+
- **Phone and ABN Formatting**: Added specialized formatting for Australian phone numbers and ABNs across DataGrid, GenericDetail, and JSON fields with format support
|
|
16
17
|
- **CameraPlacement Legacy Import**: Added comprehensive legacy JSON file import functionality with support for multiple data formats, automatic image loading, and seamless database integration
|
|
17
18
|
- **CameraPlacement Module**: Enhanced interactive camera placement tool with improved UI consistency, better icon visibility, drag-and-drop image upload, professional export capabilities, and complete Verkada database integration
|
|
18
19
|
- **Complete StandardModal Migration**: All components now use StandardModal instead of reactjs-popup for consistent modal behavior across the entire library
|
|
@@ -586,6 +587,8 @@ The DataGrid component utilizes a modular column renderer system with 28 special
|
|
|
586
587
|
- `json` - JSON data extraction and display
|
|
587
588
|
- `number` - Numeric values
|
|
588
589
|
- `option` - Option mapping with placeholders
|
|
590
|
+
- `phone` - Phone number formatting for Australian numbers
|
|
591
|
+
- `abn` - Australian Business Number formatting
|
|
589
592
|
- `placeholder` - Static placeholder text
|
|
590
593
|
- `age` - Age calculation from dates
|
|
591
594
|
- `coding` - Custom coding logic
|
|
@@ -677,6 +680,72 @@ The `html5_date` column type provides native HTML5 date picker functionality in
|
|
|
677
680
|
}
|
|
678
681
|
```
|
|
679
682
|
|
|
683
|
+
#### Phone and ABN Formatting
|
|
684
|
+
|
|
685
|
+
The DataGrid and GenericDetail components include specialized formatting for Australian phone numbers and ABNs (Australian Business Numbers).
|
|
686
|
+
|
|
687
|
+
##### Phone Number Formatting
|
|
688
|
+
|
|
689
|
+
The `phone` column type automatically formats phone numbers according to Australian standards:
|
|
690
|
+
|
|
691
|
+
**Supported Formats:**
|
|
692
|
+
- **Mobile Numbers**: `0400 000 000` (04XX XXX XXX)
|
|
693
|
+
- **1300/1800 Numbers**: `1300 000 000` (1300 XXX XXX)
|
|
694
|
+
- **Landline Numbers**: `(02) 0000 0000` ((0X) XXXX XXXX)
|
|
695
|
+
- **Generic Formatting**: Applied to other number patterns
|
|
696
|
+
- **Fallback**: Returns original value if no pattern matches
|
|
697
|
+
|
|
698
|
+
**Configuration Examples:**
|
|
699
|
+
|
|
700
|
+
DataGrid:
|
|
701
|
+
```jsx
|
|
702
|
+
{
|
|
703
|
+
id: 'phone',
|
|
704
|
+
label: 'Phone Number',
|
|
705
|
+
type: 'phone',
|
|
706
|
+
width: '15%'
|
|
707
|
+
}
|
|
708
|
+
```
|
|
709
|
+
|
|
710
|
+
GenericDetail:
|
|
711
|
+
```jsx
|
|
712
|
+
{
|
|
713
|
+
id: 'phone',
|
|
714
|
+
label: 'Phone Number',
|
|
715
|
+
type: 'phone',
|
|
716
|
+
relation: ['company'] // Also works with relationship fields
|
|
717
|
+
}
|
|
718
|
+
```
|
|
719
|
+
|
|
720
|
+
JSON Fields with Format:
|
|
721
|
+
```jsx
|
|
722
|
+
{
|
|
723
|
+
id: 'contact_data',
|
|
724
|
+
label: 'Contact',
|
|
725
|
+
type: 'json',
|
|
726
|
+
jsonData: 'phone',
|
|
727
|
+
format: 'phone' // Applies phone formatting to JSON field values
|
|
728
|
+
}
|
|
729
|
+
```
|
|
730
|
+
|
|
731
|
+
##### ABN Formatting
|
|
732
|
+
|
|
733
|
+
The `abn` column type formats Australian Business Numbers:
|
|
734
|
+
|
|
735
|
+
**Format**: `00 000 000 000` (XX XXX XXX XXX)
|
|
736
|
+
- Validates 11-digit ABNs
|
|
737
|
+
- Returns original value if not valid format
|
|
738
|
+
|
|
739
|
+
**Configuration Example:**
|
|
740
|
+
```jsx
|
|
741
|
+
{
|
|
742
|
+
id: 'abn',
|
|
743
|
+
label: 'ABN',
|
|
744
|
+
type: 'abn',
|
|
745
|
+
width: '15%'
|
|
746
|
+
}
|
|
747
|
+
```
|
|
748
|
+
|
|
680
749
|
#### Intelligent Relationship Sorting
|
|
681
750
|
|
|
682
751
|
The DataGrid component includes intelligent sorting capabilities that automatically detect and enable sorting for relationship and JSON fields. This feature works seamlessly with the backend `HasRelationshipSorting` trait.
|
package/package.json
CHANGED
|
@@ -94,7 +94,7 @@
|
|
|
94
94
|
"react-dom": "^17.0.0 || ^18.0.0"
|
|
95
95
|
},
|
|
96
96
|
"name": "@visns-studio/visns-components",
|
|
97
|
-
"version": "5.15.
|
|
97
|
+
"version": "5.15.16",
|
|
98
98
|
"description": "Various packages to assist in the development of our Custom Applications.",
|
|
99
99
|
"main": "src/index.js",
|
|
100
100
|
"files": [
|
|
@@ -2412,6 +2412,22 @@ const DataGrid = forwardRef(
|
|
|
2412
2412
|
}
|
|
2413
2413
|
}
|
|
2414
2414
|
|
|
2415
|
+
// Check function-based condition if it exists
|
|
2416
|
+
if (allow && s.condition && typeof s.condition === 'function') {
|
|
2417
|
+
try {
|
|
2418
|
+
console.log('🔍 DataGrid: Evaluating condition for setting:', s.id, 'with data:', d);
|
|
2419
|
+
const conditionResult = s.condition(d);
|
|
2420
|
+
console.log('🔍 DataGrid: Condition result:', conditionResult, 'for setting:', s.id);
|
|
2421
|
+
if (!conditionResult) {
|
|
2422
|
+
allow = false;
|
|
2423
|
+
console.log('🔍 DataGrid: Setting blocked by condition:', s.id);
|
|
2424
|
+
}
|
|
2425
|
+
} catch (error) {
|
|
2426
|
+
console.warn('🔍 DataGrid: Condition function error for setting:', s.id, error);
|
|
2427
|
+
allow = false;
|
|
2428
|
+
}
|
|
2429
|
+
}
|
|
2430
|
+
|
|
2415
2431
|
if (allow) {
|
|
2416
2432
|
switch (s.id) {
|
|
2417
2433
|
case 'activate':
|
|
@@ -2456,6 +2472,8 @@ const DataGrid = forwardRef(
|
|
|
2456
2472
|
return getIconComponent(RotateCcw);
|
|
2457
2473
|
case 'update':
|
|
2458
2474
|
return getIconComponent(Edit);
|
|
2475
|
+
case 'romComplete':
|
|
2476
|
+
return getIconComponent(CheckCircle);
|
|
2459
2477
|
default:
|
|
2460
2478
|
return null;
|
|
2461
2479
|
}
|
|
@@ -1047,10 +1047,14 @@ export const renderJsonColumn = ({ column, commonProps }) => {
|
|
|
1047
1047
|
? val
|
|
1048
1048
|
? 'Yes'
|
|
1049
1049
|
: 'No'
|
|
1050
|
-
:
|
|
1051
|
-
|
|
1052
|
-
|
|
1053
|
-
|
|
1050
|
+
: (() => {
|
|
1051
|
+
// Check if column has format = 'phone' and apply phone formatting
|
|
1052
|
+
if (column.format === 'phone') {
|
|
1053
|
+
return formatPhoneNumber(String(val));
|
|
1054
|
+
}
|
|
1055
|
+
// Default string handling
|
|
1056
|
+
return String(val).substring(0, 15);
|
|
1057
|
+
})()
|
|
1054
1058
|
: 'N/A'}
|
|
1055
1059
|
</span>
|
|
1056
1060
|
</div>
|
|
@@ -1008,6 +1008,62 @@ function GenericDetail({
|
|
|
1008
1008
|
|
|
1009
1009
|
const renderDateTime = () => formatDateTimeValue(value);
|
|
1010
1010
|
|
|
1011
|
+
const renderPhone = () => {
|
|
1012
|
+
if (!value) return '';
|
|
1013
|
+
|
|
1014
|
+
// Remove all non-digit characters
|
|
1015
|
+
const cleanNumber = value.replace(/\D/g, '');
|
|
1016
|
+
|
|
1017
|
+
// Check if it's an Australian mobile number (starts with 04 and has 10 digits)
|
|
1018
|
+
if (cleanNumber.match(/^04\d{8}$/)) {
|
|
1019
|
+
// Mobile format: 0400 000 000
|
|
1020
|
+
return cleanNumber.replace(/(\d{4})(\d{3})(\d{3})/, '$1 $2 $3');
|
|
1021
|
+
}
|
|
1022
|
+
|
|
1023
|
+
// Check if it's a 1300/1800 number (10 digits starting with 1300 or 1800)
|
|
1024
|
+
if (cleanNumber.match(/^1[38]00\d{6}$/)) {
|
|
1025
|
+
// 1300/1800 format: 1300 000 000
|
|
1026
|
+
return cleanNumber.replace(/(\d{4})(\d{3})(\d{3})/, '$1 $2 $3');
|
|
1027
|
+
}
|
|
1028
|
+
|
|
1029
|
+
// Check if it's an Australian landline number (8 digits with area code, or 10 digits total)
|
|
1030
|
+
if (cleanNumber.match(/^0[2-9]\d{8}$/)) {
|
|
1031
|
+
// Landline format: (02) 0000 0000
|
|
1032
|
+
return cleanNumber.replace(/(\d{2})(\d{4})(\d{4})/, '($1) $2 $3');
|
|
1033
|
+
}
|
|
1034
|
+
|
|
1035
|
+
// If it doesn't match standard Australian patterns, return as is with some basic formatting
|
|
1036
|
+
if (cleanNumber.length >= 8) {
|
|
1037
|
+
// Generic formatting for longer numbers
|
|
1038
|
+
if (cleanNumber.length === 8) {
|
|
1039
|
+
return cleanNumber.replace(/(\d{4})(\d{4})/, '$1 $2');
|
|
1040
|
+
} else if (cleanNumber.length === 9) {
|
|
1041
|
+
return cleanNumber.replace(/(\d{1})(\d{4})(\d{4})/, '$1 $2 $3');
|
|
1042
|
+
} else if (cleanNumber.length === 10) {
|
|
1043
|
+
return cleanNumber.replace(/(\d{2})(\d{4})(\d{4})/, '($1) $2 $3');
|
|
1044
|
+
}
|
|
1045
|
+
}
|
|
1046
|
+
|
|
1047
|
+
// Return original if no formatting pattern matches
|
|
1048
|
+
return value;
|
|
1049
|
+
};
|
|
1050
|
+
|
|
1051
|
+
const renderABN = () => {
|
|
1052
|
+
if (!value) return '';
|
|
1053
|
+
|
|
1054
|
+
// Remove all non-digit characters
|
|
1055
|
+
const cleanABN = value.replace(/\D/g, '');
|
|
1056
|
+
|
|
1057
|
+
// Check if it's a valid 11-digit ABN
|
|
1058
|
+
if (cleanABN.length === 11) {
|
|
1059
|
+
// Format as: 00 000 000 000
|
|
1060
|
+
return cleanABN.replace(/(\d{2})(\d{3})(\d{3})(\d{3})/, '$1 $2 $3 $4');
|
|
1061
|
+
}
|
|
1062
|
+
|
|
1063
|
+
// Return original if not 11 digits
|
|
1064
|
+
return value;
|
|
1065
|
+
};
|
|
1066
|
+
|
|
1011
1067
|
const renderFile = () => {
|
|
1012
1068
|
if (value) {
|
|
1013
1069
|
return (
|
|
@@ -1222,9 +1278,15 @@ function GenericDetail({
|
|
|
1222
1278
|
return options[0];
|
|
1223
1279
|
}
|
|
1224
1280
|
} else {
|
|
1225
|
-
|
|
1226
|
-
|
|
1227
|
-
|
|
1281
|
+
// Check if this is a phone type and apply phone formatting
|
|
1282
|
+
let displayValue = truncatedValue;
|
|
1283
|
+
if (type === 'phone' && displayValue) {
|
|
1284
|
+
displayValue = renderPhone();
|
|
1285
|
+
}
|
|
1286
|
+
|
|
1287
|
+
return size === 'full' && displayValue
|
|
1288
|
+
? parse(`<br /><p>${displayValue}</p>`)
|
|
1289
|
+
: displayValue;
|
|
1228
1290
|
}
|
|
1229
1291
|
};
|
|
1230
1292
|
|
|
@@ -1476,6 +1538,10 @@ function GenericDetail({
|
|
|
1476
1538
|
return renderOptions();
|
|
1477
1539
|
case 'password':
|
|
1478
1540
|
return renderPassword();
|
|
1541
|
+
case 'phone':
|
|
1542
|
+
return renderPhone();
|
|
1543
|
+
case 'abn':
|
|
1544
|
+
return renderABN();
|
|
1479
1545
|
case 'relation':
|
|
1480
1546
|
return renderRelation();
|
|
1481
1547
|
case 'richtext':
|
|
@@ -15,6 +15,11 @@ const interpretBooleanValue = (value, column) => {
|
|
|
15
15
|
|
|
16
16
|
if (!isTrue && !isFalse) return value; // Return original if not clearly boolean
|
|
17
17
|
|
|
18
|
+
// Check for custom boolean labels first
|
|
19
|
+
if (column.booleanLabels && typeof column.booleanLabels === 'object') {
|
|
20
|
+
return isTrue ? column.booleanLabels.true : column.booleanLabels.false;
|
|
21
|
+
}
|
|
22
|
+
|
|
18
23
|
// Contextual interpretations based on column name patterns
|
|
19
24
|
const interpretations = {
|
|
20
25
|
// Status/State patterns
|