@evoke-platform/ui-components 1.6.0-dev.15 → 1.6.0-dev.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/dist/published/components/custom/FormV2/components/FormFieldTypes/AddressFields.d.ts +17 -0
- package/dist/published/components/custom/FormV2/components/FormFieldTypes/AddressFields.js +50 -0
- package/dist/published/components/custom/FormV2/components/FormFieldTypes/Criteria.d.ts +12 -0
- package/dist/published/components/custom/FormV2/components/FormFieldTypes/Criteria.js +94 -0
- package/dist/published/components/custom/FormV2/components/FormFieldTypes/Image.d.ts +12 -0
- package/dist/published/components/custom/FormV2/components/FormFieldTypes/Image.js +108 -0
- package/dist/published/components/custom/FormV2/components/FormFieldTypes/UserProperty.d.ts +16 -0
- package/dist/published/components/custom/FormV2/components/FormFieldTypes/UserProperty.js +126 -0
- package/dist/published/components/custom/FormV2/components/types.d.ts +8 -0
- package/dist/published/components/custom/FormV2/components/types.js +1 -0
- package/dist/published/components/custom/FormV2/components/utils.d.ts +5 -0
- package/dist/published/components/custom/FormV2/components/utils.js +59 -0
- package/dist/published/theme/hooks.d.ts +8 -0
- package/dist/published/theme/hooks.js +9 -0
- package/package.json +1 -1
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { InputField, InputParameter, InputParameterReference, Property, ReadonlyField } from '@evoke-platform/context';
|
|
2
|
+
import React from 'react';
|
|
3
|
+
import { FieldErrors, FieldValues } from 'react-hook-form';
|
|
4
|
+
import { Address } from '../../../FormField/AddressFieldComponent';
|
|
5
|
+
interface AddressProps {
|
|
6
|
+
entry: InputParameterReference | ReadonlyField | InputField;
|
|
7
|
+
errors?: FieldErrors;
|
|
8
|
+
handleChange: (propertyId: string, value: string | Address | undefined) => void;
|
|
9
|
+
fieldHeight?: 'small' | 'medium';
|
|
10
|
+
readOnly?: boolean;
|
|
11
|
+
parameters?: InputParameter[];
|
|
12
|
+
instance?: FieldValues;
|
|
13
|
+
entryId: string;
|
|
14
|
+
fieldDefinition: InputParameter | Property;
|
|
15
|
+
}
|
|
16
|
+
declare function AddressFields(props: AddressProps): React.JSX.Element;
|
|
17
|
+
export default AddressFields;
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { useApiServices, } from '@evoke-platform/context';
|
|
2
|
+
import React from 'react';
|
|
3
|
+
import { useFormContext } from '../../../../../theme/hooks';
|
|
4
|
+
import { Typography } from '../../../../core';
|
|
5
|
+
import FormField from '../../../FormField';
|
|
6
|
+
import FieldWrapper from '../FieldWrapper';
|
|
7
|
+
import { getPrefixedUrl, isOptionEqualToValue } from '../utils';
|
|
8
|
+
function AddressFields(props) {
|
|
9
|
+
const { entry, errors, handleChange, fieldHeight, readOnly, parameters, instance, entryId, fieldDefinition } = props;
|
|
10
|
+
const { getValues } = useFormContext();
|
|
11
|
+
const apiServices = useApiServices();
|
|
12
|
+
const addressObject = entryId.split('.')[0];
|
|
13
|
+
const addressField = entryId.split('.')[1];
|
|
14
|
+
const addressValues = entry.type === 'readonlyField' ? instance?.[addressObject] : getValues(addressObject);
|
|
15
|
+
const fieldValue = addressValues?.[addressField];
|
|
16
|
+
const display = entry?.display;
|
|
17
|
+
const validation = fieldDefinition?.validation
|
|
18
|
+
? fieldDefinition.validation
|
|
19
|
+
: {};
|
|
20
|
+
const queryAddresses = async (query) => {
|
|
21
|
+
return await apiServices.get(getPrefixedUrl(`/locations/search`), {
|
|
22
|
+
params: { query: query },
|
|
23
|
+
});
|
|
24
|
+
};
|
|
25
|
+
const handleAddressChange = (name, value) => {
|
|
26
|
+
if (addressField === 'line1' && typeof value === 'object' && value.line1) {
|
|
27
|
+
const addressKeys = ['line1', 'city', 'county', 'state', 'zipCode'];
|
|
28
|
+
addressKeys.forEach((key) => {
|
|
29
|
+
const fullKey = `${addressObject}.${key}`;
|
|
30
|
+
if (parameters?.some((p) => p.id === fullKey)) {
|
|
31
|
+
const fieldValue = value[key];
|
|
32
|
+
handleChange(fullKey, fieldValue);
|
|
33
|
+
}
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
else {
|
|
37
|
+
handleChange(name, value);
|
|
38
|
+
}
|
|
39
|
+
};
|
|
40
|
+
const addressErrors = errors?.[addressObject];
|
|
41
|
+
const addressFieldError = addressErrors?.[addressField];
|
|
42
|
+
return (React.createElement(FieldWrapper, { inputId: entryId, inputType: "string", label: display?.label || 'default', description: !readOnly ? display?.description : undefined, tooltip: display?.tooltip, value: fieldValue, maxLength: 'maxLength' in validation ? validation?.maxLength : 0, required: fieldDefinition?.required || false, showCharCount: !readOnly && display?.charCount, viewOnly: !!readOnly, prefix: display?.prefix, suffix: display?.suffix }, !readOnly ? (React.createElement(FormField, { property: fieldDefinition, defaultValue: fieldValue, onChange: handleAddressChange, isMultiLineText: !!display?.rowCount, readOnly: entry.type === 'readonlyField', ...(addressField === 'line1' && { queryAddresses }), mask: validation?.mask, placeholder: display?.placeholder, isOptionEqualToValue: isOptionEqualToValue, size: fieldHeight, error: !!addressFieldError, errorMessage: addressFieldError?.message, additionalProps: {
|
|
43
|
+
...(display?.description && {
|
|
44
|
+
inputProps: {
|
|
45
|
+
'aria-describedby': `${entryId}-description`,
|
|
46
|
+
},
|
|
47
|
+
}),
|
|
48
|
+
} })) : (React.createElement(Typography, { variant: "body1", key: entryId, sx: { height: '24px', paddingTop: '6px' } }, fieldValue))));
|
|
49
|
+
}
|
|
50
|
+
export default AddressFields;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { InputParameter, Property } from '@evoke-platform/context';
|
|
2
|
+
import React from 'react';
|
|
3
|
+
type CriteriaProps = {
|
|
4
|
+
fieldDefinition: InputParameter | Property;
|
|
5
|
+
value?: CriteriaValue | null;
|
|
6
|
+
handleChange: (propertyId: string, value: CriteriaValue | null) => void;
|
|
7
|
+
canUpdateProperty: boolean;
|
|
8
|
+
error?: boolean;
|
|
9
|
+
};
|
|
10
|
+
type CriteriaValue = Record<string, unknown>;
|
|
11
|
+
export default function Criteria(props: CriteriaProps): React.JSX.Element;
|
|
12
|
+
export {};
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
import { useApiServices } from '@evoke-platform/context';
|
|
2
|
+
import React, { useCallback, useEffect, useState } from 'react';
|
|
3
|
+
import { useFormContext } from '../../../../../theme/hooks';
|
|
4
|
+
import { Button, CircularProgress, Typography } from '../../../../core';
|
|
5
|
+
import { Box } from '../../../../layout';
|
|
6
|
+
import CriteriaBuilder from '../../../CriteriaBuilder';
|
|
7
|
+
import { addressProperties, getPrefixedUrl } from '../utils';
|
|
8
|
+
export default function Criteria(props) {
|
|
9
|
+
const { handleChange, value, canUpdateProperty, fieldDefinition, error } = props;
|
|
10
|
+
const apiServices = useApiServices();
|
|
11
|
+
const { fetchedOptions, setFetchedOptions } = useFormContext();
|
|
12
|
+
const [loadingError, setLoadingError] = useState(false);
|
|
13
|
+
const [loading, setLoading] = useState(false);
|
|
14
|
+
const [properties, setProperties] = useState(fetchedOptions[`${fieldDefinition.id}Options`] || []);
|
|
15
|
+
const fetchProperties = useCallback(async () => {
|
|
16
|
+
if (fieldDefinition.objectId && !fetchedOptions[`${fieldDefinition.id}Options`]) {
|
|
17
|
+
setLoading(true);
|
|
18
|
+
apiServices.get(getPrefixedUrl(`/objects/${fieldDefinition.objectId}/effective/properties`), { params: { fields: ['properties'] } }, (error, properties) => {
|
|
19
|
+
if (error) {
|
|
20
|
+
console.error('Error fetching object properties', error);
|
|
21
|
+
setLoadingError(true);
|
|
22
|
+
}
|
|
23
|
+
if (properties) {
|
|
24
|
+
const flattenProperties = properties.flatMap((prop) => {
|
|
25
|
+
if (prop.type === 'object' || prop.type === 'user') {
|
|
26
|
+
return [
|
|
27
|
+
{
|
|
28
|
+
id: `${prop.id}.id`,
|
|
29
|
+
name: `${prop.name} Id`,
|
|
30
|
+
type: 'string',
|
|
31
|
+
},
|
|
32
|
+
{
|
|
33
|
+
id: `${prop.id}.name`,
|
|
34
|
+
name: `${prop.name} Name`,
|
|
35
|
+
type: 'string',
|
|
36
|
+
},
|
|
37
|
+
];
|
|
38
|
+
}
|
|
39
|
+
else if (prop.type === 'address') {
|
|
40
|
+
return addressProperties(prop);
|
|
41
|
+
}
|
|
42
|
+
return prop;
|
|
43
|
+
});
|
|
44
|
+
setProperties(flattenProperties);
|
|
45
|
+
setFetchedOptions((prev) => ({
|
|
46
|
+
...prev,
|
|
47
|
+
[`${fieldDefinition.id}Options`]: flattenProperties.map((prop) => ({
|
|
48
|
+
id: prop.id,
|
|
49
|
+
name: prop.name,
|
|
50
|
+
})),
|
|
51
|
+
}));
|
|
52
|
+
setLoadingError(false);
|
|
53
|
+
}
|
|
54
|
+
setLoading(false);
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
}, [fieldDefinition.objectId, apiServices]);
|
|
58
|
+
useEffect(() => {
|
|
59
|
+
fetchProperties();
|
|
60
|
+
}, [fetchProperties]);
|
|
61
|
+
const handleUpdate = (criteria) => {
|
|
62
|
+
if (criteria || value) {
|
|
63
|
+
handleChange(fieldDefinition.id, criteria ?? null);
|
|
64
|
+
}
|
|
65
|
+
};
|
|
66
|
+
if (loadingError) {
|
|
67
|
+
return (React.createElement(Box, { sx: { display: 'flex', alignItems: 'center' } },
|
|
68
|
+
React.createElement(Typography, { sx: { color: 'rgb(114 124 132)', fontSize: '14px', paddingLeft: '10px' } }, "An error occurred when retrieving data needed for this criteria."),
|
|
69
|
+
React.createElement(Button, { sx: {
|
|
70
|
+
padding: 0,
|
|
71
|
+
'&:hover': { backgroundColor: 'transparent' },
|
|
72
|
+
minWidth: '44px',
|
|
73
|
+
}, variant: "text", onClick: fetchProperties, disabled: loading }, "Retry"),
|
|
74
|
+
loading && React.createElement(CircularProgress, { size: 20, sx: { paddingLeft: '10px' } })));
|
|
75
|
+
}
|
|
76
|
+
return !!value || canUpdateProperty ? (React.createElement(Box, { sx: { borderRadius: '8px', border: error ? '1px solid #FF0000' : '1px solid #ddd' } },
|
|
77
|
+
React.createElement(CriteriaBuilder, { criteria: value ?? undefined, properties: properties, setCriteria: handleUpdate, disabled: !canUpdateProperty, hideBorder: true, presetValues: [
|
|
78
|
+
{
|
|
79
|
+
label: 'Current Date',
|
|
80
|
+
value: { name: '{{{currentDate}}}', label: 'Current Date' },
|
|
81
|
+
type: 'date',
|
|
82
|
+
},
|
|
83
|
+
{
|
|
84
|
+
label: 'Current Time',
|
|
85
|
+
value: { name: '{{{currentTime}}}', label: 'Current Time' },
|
|
86
|
+
type: 'time',
|
|
87
|
+
},
|
|
88
|
+
{
|
|
89
|
+
label: 'Current Date Time',
|
|
90
|
+
value: { name: '{{{currentDateTime}}}', label: 'Current Date Time' },
|
|
91
|
+
type: 'date-time',
|
|
92
|
+
},
|
|
93
|
+
], enablePresetValues: true }))) : (React.createElement(Typography, { variant: "body2", sx: { color: '#637381' } }, "No criteria"));
|
|
94
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
export declare function blobToDataUrl(blob: Blob): Promise<string>;
|
|
3
|
+
type ImageProps = {
|
|
4
|
+
id: string;
|
|
5
|
+
handleChange: (propertyId: string, value: string | null) => void;
|
|
6
|
+
canUpdateProperty?: boolean;
|
|
7
|
+
error?: boolean;
|
|
8
|
+
value?: string;
|
|
9
|
+
hasDescription?: boolean;
|
|
10
|
+
};
|
|
11
|
+
export declare const Image: (props: ImageProps) => React.JSX.Element;
|
|
12
|
+
export {};
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
import { BackupOutlined, ClearRounded } from '@mui/icons-material';
|
|
2
|
+
import { CardMedia } from '@mui/material';
|
|
3
|
+
import React, { useEffect, useState } from 'react';
|
|
4
|
+
import { useDropzone } from 'react-dropzone';
|
|
5
|
+
import { IconButton, Typography } from '../../../../core';
|
|
6
|
+
import { Box, Grid } from '../../../../layout';
|
|
7
|
+
export function blobToDataUrl(blob) {
|
|
8
|
+
const reader = new FileReader();
|
|
9
|
+
return new Promise((resolve) => {
|
|
10
|
+
reader.onloadend = () => resolve(reader.result);
|
|
11
|
+
reader.readAsDataURL(blob);
|
|
12
|
+
});
|
|
13
|
+
}
|
|
14
|
+
const styles = {
|
|
15
|
+
imageContainer: {
|
|
16
|
+
margin: '5px 0',
|
|
17
|
+
height: '160px',
|
|
18
|
+
borderRadius: '8px',
|
|
19
|
+
maxWidth: '100%',
|
|
20
|
+
},
|
|
21
|
+
dropzoneContainer: {
|
|
22
|
+
margin: '5px 0',
|
|
23
|
+
height: '160px',
|
|
24
|
+
borderRadius: '8px',
|
|
25
|
+
display: 'flex',
|
|
26
|
+
justifyContent: 'center',
|
|
27
|
+
alignItems: 'center',
|
|
28
|
+
border: '1px dashed #858585',
|
|
29
|
+
position: 'relative',
|
|
30
|
+
cursor: 'pointer',
|
|
31
|
+
},
|
|
32
|
+
icon: {
|
|
33
|
+
color: '#fff',
|
|
34
|
+
zIndex: 40,
|
|
35
|
+
fontSize: '16px',
|
|
36
|
+
},
|
|
37
|
+
deleteIcon: {
|
|
38
|
+
borderRadius: '50%',
|
|
39
|
+
padding: '3px',
|
|
40
|
+
backgroundColor: '#212B36',
|
|
41
|
+
':hover': { backgroundColor: '#212B36', cursor: 'pointer' },
|
|
42
|
+
color: '#fff',
|
|
43
|
+
right: '29px',
|
|
44
|
+
bottom: '138px',
|
|
45
|
+
},
|
|
46
|
+
image: {
|
|
47
|
+
borderRadius: '8px',
|
|
48
|
+
width: 'fit-content',
|
|
49
|
+
maxWidth: '95%',
|
|
50
|
+
height: '160px',
|
|
51
|
+
position: 'relative',
|
|
52
|
+
display: 'inline-block',
|
|
53
|
+
objectFit: 'contain',
|
|
54
|
+
},
|
|
55
|
+
};
|
|
56
|
+
export const Image = (props) => {
|
|
57
|
+
const { id, handleChange, canUpdateProperty, error, value, hasDescription } = props;
|
|
58
|
+
const [image, setImage] = useState();
|
|
59
|
+
useEffect(() => {
|
|
60
|
+
if (typeof value === 'string') {
|
|
61
|
+
setImage(value);
|
|
62
|
+
}
|
|
63
|
+
}, [value]);
|
|
64
|
+
const handleUpload = async (file) => {
|
|
65
|
+
if (file?.size && file.size <= 300000) {
|
|
66
|
+
const dataUrl = file ? await blobToDataUrl(file) : null;
|
|
67
|
+
setImage(dataUrl);
|
|
68
|
+
handleChange(id, dataUrl);
|
|
69
|
+
}
|
|
70
|
+
};
|
|
71
|
+
const handleRemove = (e) => {
|
|
72
|
+
setImage(null);
|
|
73
|
+
handleChange(id, '');
|
|
74
|
+
e.stopPropagation();
|
|
75
|
+
};
|
|
76
|
+
const { getRootProps, getInputProps, open } = useDropzone({
|
|
77
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
78
|
+
onDrop: (files) => handleUpload(files?.[0]),
|
|
79
|
+
accept: { 'image/*': ['.png', '.jpg', '.jpeg', '.gif', '.svg'] },
|
|
80
|
+
});
|
|
81
|
+
return (React.createElement(React.Fragment, null, image ? (React.createElement(Box, { sx: styles.imageContainer },
|
|
82
|
+
React.createElement(Box, { sx: { position: 'relative', left: 0, zIndex: 5 } },
|
|
83
|
+
React.createElement(CardMedia, { component: "img", image: image, alt: 'Uploaded Image', sx: styles.image }),
|
|
84
|
+
canUpdateProperty && (React.createElement(IconButton, { onClick: handleRemove, "aria-label": "Remove image", sx: styles.deleteIcon },
|
|
85
|
+
React.createElement(ClearRounded, { sx: styles.icon })))))) : canUpdateProperty ? (React.createElement(Box, { sx: {
|
|
86
|
+
...styles.dropzoneContainer,
|
|
87
|
+
borderColor: error ? 'red' : '#858585',
|
|
88
|
+
}, ...getRootProps(), onClick: open },
|
|
89
|
+
React.createElement("input", { ...getInputProps({ id }), multiple: false, ...(hasDescription ? { 'aria-describedby': `${id}-description` } : undefined) }),
|
|
90
|
+
React.createElement(Grid, { container: true, sx: { width: '100%' } },
|
|
91
|
+
React.createElement(Grid, { item: true, xs: 12, sx: {
|
|
92
|
+
display: 'flex',
|
|
93
|
+
justifyContent: 'center',
|
|
94
|
+
paddingBottom: '5px',
|
|
95
|
+
} },
|
|
96
|
+
React.createElement(BackupOutlined, { sx: { color: '#919EAB', height: '1.5em', width: '1.5em' } })),
|
|
97
|
+
React.createElement(Grid, { item: true, xs: 12 },
|
|
98
|
+
React.createElement(Typography, { variant: "body2", sx: { textAlign: 'center' } },
|
|
99
|
+
"Drag and drop or",
|
|
100
|
+
' ',
|
|
101
|
+
React.createElement(Typography, { component: 'span', color: 'primary', sx: { fontSize: '14px' } }, "select a file"),
|
|
102
|
+
' ',
|
|
103
|
+
"to upload")),
|
|
104
|
+
React.createElement(Grid, { item: true, xs: 12 },
|
|
105
|
+
React.createElement(Typography, { variant: "body2", sx: { color: '#637381', textAlign: 'center' } }, "Max file size of 300KB")),
|
|
106
|
+
React.createElement(Grid, { item: true, xs: 12 },
|
|
107
|
+
React.createElement(Typography, { variant: "body2", sx: { color: '#637381', textAlign: 'center' } }, "JPG, PNG, or GIF"))))) : (React.createElement(Typography, { variant: "body2", sx: { color: '#637381' } }, "No image"))));
|
|
108
|
+
};
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { AutocompleteOption } from '../../../../core';
|
|
3
|
+
export type UserPropertyProps = {
|
|
4
|
+
id: string;
|
|
5
|
+
handleChangeUserProperty: (id: string, user: AutocompleteOption) => void;
|
|
6
|
+
error?: boolean;
|
|
7
|
+
value?: {
|
|
8
|
+
id: string;
|
|
9
|
+
name: string;
|
|
10
|
+
};
|
|
11
|
+
fieldHeight?: 'small' | 'medium';
|
|
12
|
+
readOnly?: boolean;
|
|
13
|
+
hasDescription?: boolean;
|
|
14
|
+
};
|
|
15
|
+
declare const UserProperty: (props: UserPropertyProps) => React.JSX.Element;
|
|
16
|
+
export default UserProperty;
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
import { useApiServices } from '@evoke-platform/context';
|
|
2
|
+
import { ExpandMore } from '@mui/icons-material';
|
|
3
|
+
import React, { useEffect, useState } from 'react';
|
|
4
|
+
import { useFormContext } from '../../../../../theme/hooks';
|
|
5
|
+
import { Autocomplete, Paper, TextField, Typography } from '../../../../core';
|
|
6
|
+
import { getPrefixedUrl, isOptionEqualToValue } from '../utils';
|
|
7
|
+
const UserProperty = (props) => {
|
|
8
|
+
const { id, handleChangeUserProperty, error, value, fieldHeight, readOnly, hasDescription } = props;
|
|
9
|
+
const { fetchedOptions, setFetchedOptions } = useFormContext();
|
|
10
|
+
const [loadingOptions, setLoadingOptions] = useState(false);
|
|
11
|
+
const apiServices = useApiServices();
|
|
12
|
+
const [options, setOptions] = useState(fetchedOptions[`${id}Options`] || []);
|
|
13
|
+
const [openOptions, setOpenOptions] = useState(false);
|
|
14
|
+
const [users, setUsers] = useState();
|
|
15
|
+
const [userValue, setUserValue] = useState();
|
|
16
|
+
useEffect(() => {
|
|
17
|
+
if (value && typeof value == 'object' && 'name' in value && 'id' in value) {
|
|
18
|
+
setUserValue({ label: value.name, value: value.id });
|
|
19
|
+
}
|
|
20
|
+
else {
|
|
21
|
+
setUserValue(undefined);
|
|
22
|
+
}
|
|
23
|
+
}, [value]);
|
|
24
|
+
useEffect(() => {
|
|
25
|
+
if (!fetchedOptions[`${id}Options`]) {
|
|
26
|
+
setLoadingOptions(true);
|
|
27
|
+
apiServices.get(getPrefixedUrl(`/users`), (error, userList) => {
|
|
28
|
+
setUsers(userList);
|
|
29
|
+
setOptions((userList ?? []).map((user) => ({
|
|
30
|
+
label: user.name,
|
|
31
|
+
value: user.id,
|
|
32
|
+
})));
|
|
33
|
+
setFetchedOptions((prev) => ({
|
|
34
|
+
...prev,
|
|
35
|
+
[`${id}Options`]: (userList ?? []).map((user) => ({
|
|
36
|
+
label: user.name,
|
|
37
|
+
value: user.id,
|
|
38
|
+
})),
|
|
39
|
+
}));
|
|
40
|
+
setLoadingOptions(false);
|
|
41
|
+
});
|
|
42
|
+
}
|
|
43
|
+
}, [id]);
|
|
44
|
+
return (options && (React.createElement(Autocomplete, { id: id, fullWidth: true, open: openOptions, popupIcon: userValue || readOnly ? '' : React.createElement(ExpandMore, null), PaperComponent: ({ children }) => {
|
|
45
|
+
return (React.createElement(Paper, { sx: {
|
|
46
|
+
borderRadius: '12px',
|
|
47
|
+
boxShadow: '0px 24px 48px 0px rgba(145, 158, 171, 0.2)',
|
|
48
|
+
'& .MuiAutocomplete-listbox': {
|
|
49
|
+
maxHeight: '25vh',
|
|
50
|
+
},
|
|
51
|
+
'& .MuiAutocomplete-noOptions': {
|
|
52
|
+
fontFamily: 'sans-serif',
|
|
53
|
+
fontSize: '14px',
|
|
54
|
+
paddingLeft: '24px',
|
|
55
|
+
color: 'rgba(145, 158, 171, 1)',
|
|
56
|
+
},
|
|
57
|
+
'& .MuiAutocomplete-loading': {
|
|
58
|
+
fontFamily: 'sans-serif',
|
|
59
|
+
fontSize: '14px',
|
|
60
|
+
paddingLeft: '24px',
|
|
61
|
+
color: 'rgba(145, 158, 171, 1)',
|
|
62
|
+
},
|
|
63
|
+
} }, children));
|
|
64
|
+
}, sx: {
|
|
65
|
+
'& button.MuiButtonBase-root': {
|
|
66
|
+
...(!loadingOptions && value ? { visibility: 'visible' } : {}),
|
|
67
|
+
},
|
|
68
|
+
'.MuiAutocomplete-clearIndicator': {
|
|
69
|
+
...(!value ? { display: 'none' } : undefined),
|
|
70
|
+
},
|
|
71
|
+
}, noOptionsText: 'No options available', renderOption: (props, option) => {
|
|
72
|
+
return (React.createElement("li", { ...props, key: option.id },
|
|
73
|
+
React.createElement(Typography, { sx: { marginLeft: '8px', fontSize: '14px' } },
|
|
74
|
+
option.label,
|
|
75
|
+
" ",
|
|
76
|
+
'',
|
|
77
|
+
users?.find((user) => option.value === user.id)?.status === 'Inactive' ? (React.createElement("span", null, "(Inactive)")) : (''))));
|
|
78
|
+
}, onOpen: () => {
|
|
79
|
+
setOpenOptions(true);
|
|
80
|
+
}, onClose: () => setOpenOptions(false), value: userValue ?? '', options: options, getOptionLabel: (option) => {
|
|
81
|
+
if (typeof option === 'string') {
|
|
82
|
+
return options.find((o) => o.value === option)?.label ?? '';
|
|
83
|
+
}
|
|
84
|
+
else {
|
|
85
|
+
{
|
|
86
|
+
if (users?.find((user) => option.value === user.id)?.status === 'Inactive') {
|
|
87
|
+
return option.label + ' (Inactive)';
|
|
88
|
+
}
|
|
89
|
+
else {
|
|
90
|
+
return option.label ?? '';
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
}, onKeyDownCapture: (e) => {
|
|
95
|
+
// prevents keyboard trap
|
|
96
|
+
if (e.key === 'Tab') {
|
|
97
|
+
return;
|
|
98
|
+
}
|
|
99
|
+
if (value) {
|
|
100
|
+
e.preventDefault();
|
|
101
|
+
}
|
|
102
|
+
}, loading: loadingOptions, isOptionEqualToValue: isOptionEqualToValue, onChange: (event, value) => {
|
|
103
|
+
handleChangeUserProperty(id, value);
|
|
104
|
+
}, renderInput: (params) => (React.createElement(TextField, { ...params, placeholder: !readOnly ? 'Select' : undefined, readOnly: !loadingOptions && !value && readOnly, inputProps: {
|
|
105
|
+
...params.inputProps,
|
|
106
|
+
...(hasDescription ? { 'aria-describedby': `${id}-description` } : undefined),
|
|
107
|
+
}, sx: {
|
|
108
|
+
...(!loadingOptions && value
|
|
109
|
+
? {
|
|
110
|
+
'.MuiOutlinedInput-root': {
|
|
111
|
+
background: 'white',
|
|
112
|
+
border: 'auto',
|
|
113
|
+
},
|
|
114
|
+
'& fieldset': { borderColor: 'auto' },
|
|
115
|
+
'&:hover .MuiOutlinedInput-notchedOutline': {
|
|
116
|
+
border: 'auto',
|
|
117
|
+
},
|
|
118
|
+
caretColor: 'white',
|
|
119
|
+
'& svg': {
|
|
120
|
+
display: readOnly ? 'none' : 'block',
|
|
121
|
+
},
|
|
122
|
+
}
|
|
123
|
+
: {}),
|
|
124
|
+
} })), size: fieldHeight ?? 'medium', readOnly: readOnly, error: error })));
|
|
125
|
+
};
|
|
126
|
+
export default UserProperty;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import { Property } from '@evoke-platform/context';
|
|
2
|
+
import { AutocompleteOption } from '../../../core';
|
|
3
|
+
export declare function getPrefixedUrl(url: string): string;
|
|
4
|
+
export declare const isOptionEqualToValue: (option: AutocompleteOption | string, value: unknown) => boolean;
|
|
5
|
+
export declare function addressProperties(addressProperty: Property): Property[];
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
export function getPrefixedUrl(url) {
|
|
2
|
+
const wcsMatchers = ['/apps', '/pages', '/widgets'];
|
|
3
|
+
const dataMatchers = ['/objects', '/correspondenceTemplates', '/documents', '/payments', '/locations'];
|
|
4
|
+
const signalrMatchers = ['/hubs'];
|
|
5
|
+
const accessManagementMatchers = ['/users'];
|
|
6
|
+
const workflowMatchers = ['/workflows'];
|
|
7
|
+
if (wcsMatchers.some((endpoint) => url.startsWith(endpoint)))
|
|
8
|
+
return `/webContent${url}`;
|
|
9
|
+
if (dataMatchers.some((endpoint) => url.startsWith(endpoint)))
|
|
10
|
+
return `/data${url}`;
|
|
11
|
+
if (signalrMatchers.some((endpoint) => url.startsWith(endpoint)))
|
|
12
|
+
return `/signalr${url}`;
|
|
13
|
+
if (accessManagementMatchers.some((endpoint) => url.startsWith(endpoint)))
|
|
14
|
+
return `/accessManagement${url}`;
|
|
15
|
+
if (workflowMatchers.some((endpoint) => url.startsWith(endpoint)))
|
|
16
|
+
return `/workflow${url}`;
|
|
17
|
+
console.error('Invalid URL');
|
|
18
|
+
return url;
|
|
19
|
+
}
|
|
20
|
+
export const isOptionEqualToValue = (option, value) => {
|
|
21
|
+
if (typeof option === 'string') {
|
|
22
|
+
return option === value;
|
|
23
|
+
}
|
|
24
|
+
return option.value === value;
|
|
25
|
+
};
|
|
26
|
+
export function addressProperties(addressProperty) {
|
|
27
|
+
return [
|
|
28
|
+
{
|
|
29
|
+
id: `${addressProperty.id}.line1`,
|
|
30
|
+
name: `${addressProperty.name} Line 1`,
|
|
31
|
+
type: 'string',
|
|
32
|
+
},
|
|
33
|
+
{
|
|
34
|
+
id: `${addressProperty.id}.line2`,
|
|
35
|
+
name: `${addressProperty.name} Line 2`,
|
|
36
|
+
type: 'string',
|
|
37
|
+
},
|
|
38
|
+
{
|
|
39
|
+
id: `${addressProperty.id}.city`,
|
|
40
|
+
name: `${addressProperty.name} City`,
|
|
41
|
+
type: 'string',
|
|
42
|
+
},
|
|
43
|
+
{
|
|
44
|
+
id: `${addressProperty.id}.county`,
|
|
45
|
+
name: `${addressProperty.name} County`,
|
|
46
|
+
type: 'string',
|
|
47
|
+
},
|
|
48
|
+
{
|
|
49
|
+
id: `${addressProperty.id}.state`,
|
|
50
|
+
name: `${addressProperty.name} State`,
|
|
51
|
+
type: 'string',
|
|
52
|
+
},
|
|
53
|
+
{
|
|
54
|
+
id: `${addressProperty.id}.zipCode`,
|
|
55
|
+
name: `${addressProperty.name} Zip Code`,
|
|
56
|
+
type: 'string',
|
|
57
|
+
},
|
|
58
|
+
];
|
|
59
|
+
}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
/// <reference types="react" />
|
|
1
2
|
import { Breakpoint } from '@mui/material/styles';
|
|
2
3
|
/**
|
|
3
4
|
* Custom hook for responsive design breakpoints using size terminology.
|
|
@@ -107,3 +108,10 @@ export declare const useWidgetSize: (options?: {
|
|
|
107
108
|
resize?: boolean;
|
|
108
109
|
}) => WidgetSizeInfo;
|
|
109
110
|
export default useWidgetSize;
|
|
111
|
+
export declare function useFormContext(): {
|
|
112
|
+
fetchedOptions: import("react-hook-form").FieldValues;
|
|
113
|
+
setFetchedOptions: import("react").Dispatch<import("react").SetStateAction<import("react-hook-form").FieldValues>>;
|
|
114
|
+
getValues: import("react-hook-form").UseFormGetValues<import("react-hook-form").FieldValues>;
|
|
115
|
+
stickyFooter?: boolean | undefined;
|
|
116
|
+
object?: import("@evoke-platform/context").Obj | undefined;
|
|
117
|
+
};
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import { useTheme } from '@mui/material';
|
|
2
2
|
import useMediaQuery from '@mui/material/useMediaQuery';
|
|
3
|
+
import { useContext } from 'react';
|
|
3
4
|
import useMeasure from 'react-use-measure';
|
|
5
|
+
import { FormContext } from '../components/custom/FormV2/components/FormContext';
|
|
4
6
|
/**
|
|
5
7
|
* Custom hook for responsive design breakpoints using size terminology.
|
|
6
8
|
* Breakpoints based on MUI default theme:
|
|
@@ -98,3 +100,10 @@ export const useWidgetSize = (options) => {
|
|
|
98
100
|
};
|
|
99
101
|
};
|
|
100
102
|
export default useWidgetSize;
|
|
103
|
+
export function useFormContext() {
|
|
104
|
+
const context = useContext(FormContext);
|
|
105
|
+
if (!context) {
|
|
106
|
+
throw new Error('useFormContext must be used within a FormContext.Provider');
|
|
107
|
+
}
|
|
108
|
+
return context;
|
|
109
|
+
}
|