@onehat/ui 0.4.108 → 0.4.111
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/package.json +1 -1
- package/src/Components/Form/Field/Tag/Tag.js +1 -1
- package/src/Components/Form/Form.js +31 -12
- package/src/Components/Hoc/withPdfButtons.js +2 -2
- package/src/Components/Hoc/withPermissions.js +1 -1
- package/src/Components/Hoc/withPresetButtons.js +6 -2
- package/src/Components/Layout/UserIndicator.js +3 -1
- package/src/Components/Viewer/Viewer.js +20 -12
- package/src/Components/Window/UploadsDownloadsWindow.js +30 -12
- package/src/Constants/Auth.js +3 -0
- package/src/Functions/authFunctions.js +98 -0
- package/src/Functions/getTokenHeaders.js +3 -0
- package/src/Hooks/useCrossTabSecureSync.js +37 -0
- package/src/Models/Slices/AuthSlice.js +584 -0
- package/src/Components/Form/Field/FormikForm.js +0 -1019
|
@@ -1,1019 +0,0 @@
|
|
|
1
|
-
import React, { useEffect, useState, useRef, isValidElement, } from 'react';
|
|
2
|
-
import {
|
|
3
|
-
Box,
|
|
4
|
-
HStack,
|
|
5
|
-
Icon,
|
|
6
|
-
ScrollView,
|
|
7
|
-
Text,
|
|
8
|
-
TextNative,
|
|
9
|
-
VStack,
|
|
10
|
-
VStackNative,
|
|
11
|
-
} from '@project-components/Gluestack';
|
|
12
|
-
import clsx from 'clsx';
|
|
13
|
-
import { View, } from 'react-native';
|
|
14
|
-
import {
|
|
15
|
-
EDITOR_TYPE__INLINE,
|
|
16
|
-
EDITOR_TYPE__WINDOWED,
|
|
17
|
-
EDITOR_TYPE__SIDE,
|
|
18
|
-
EDITOR_TYPE__SMART,
|
|
19
|
-
EDITOR_TYPE__PLAIN,
|
|
20
|
-
EDITOR_MODE__VIEW,
|
|
21
|
-
EDITOR_MODE__ADD,
|
|
22
|
-
EDITOR_MODE__EDIT,
|
|
23
|
-
} from '../../../Constants/Editor.js';
|
|
24
|
-
import { Form, Formik, Field } from "formik"; // https://formik.org/docs/overview
|
|
25
|
-
import { useForm, Controller } from 'react-hook-form'; // https://react-hook-form.com/api/
|
|
26
|
-
import * as yup from 'yup'; // https://github.com/jquense/yup#string
|
|
27
|
-
import { yupResolver } from '@hookform/resolvers/yup';
|
|
28
|
-
import useForceUpdate from '../../../Hooks/useForceUpdate.js';
|
|
29
|
-
import UiGlobals from '../../../UiGlobals.js';
|
|
30
|
-
import withAlert from '../../../Hoc/withAlert.js';
|
|
31
|
-
import withComponent from '../../../Hoc/withComponent.js';
|
|
32
|
-
import withEditor from '../../../Hoc/withEditor.js';
|
|
33
|
-
import withPdfButton from '../../../Hoc/withPdfButton.js';
|
|
34
|
-
import inArray from '../../../Functions/inArray.js';
|
|
35
|
-
import getComponentFromType from '../../../Functions/getComponentFromType.js';
|
|
36
|
-
import buildAdditionalButtons from '../../../Functions/buildAdditionalButtons.js';
|
|
37
|
-
import Button from '../../../Buttons/Button.js';
|
|
38
|
-
import IconButton from '../../../Buttons/IconButton.js';
|
|
39
|
-
import AngleLeft from '../../../Icons/AngleLeft.js';
|
|
40
|
-
import Eye from '../../../Icons/Eye.js';
|
|
41
|
-
import Rotate from '../../../Icons/Rotate.js';
|
|
42
|
-
import Pencil from '../../../Icons/Pencil.js';
|
|
43
|
-
import Footer from '../../../Layout/Footer.js';
|
|
44
|
-
import Label from '../../../Form/Label.js';
|
|
45
|
-
import _ from 'lodash';
|
|
46
|
-
|
|
47
|
-
// TODO: memoize field Components
|
|
48
|
-
|
|
49
|
-
// Modes:
|
|
50
|
-
// EDITOR_TYPE__INLINE
|
|
51
|
-
// Form is a single scrollable row, based on columnsConfig and Repository
|
|
52
|
-
//
|
|
53
|
-
// EDITOR_TYPE__WINDOWED
|
|
54
|
-
// EDITOR_TYPE__SIDE
|
|
55
|
-
// Form is a popup or side window, used for editing items in a grid. Integrated with Repository
|
|
56
|
-
//
|
|
57
|
-
// EDITOR_TYPE__SMART
|
|
58
|
-
// Form is a standalone editor
|
|
59
|
-
//
|
|
60
|
-
// EDITOR_TYPE__PLAIN
|
|
61
|
-
// Form is embedded on screen in some other way. Mainly use startingValues, items, validator
|
|
62
|
-
|
|
63
|
-
function FormikForm(props) {
|
|
64
|
-
const
|
|
65
|
-
{
|
|
66
|
-
editorType = EDITOR_TYPE__WINDOWED, // EDITOR_TYPE__INLINE | EDITOR_TYPE__WINDOWED | EDITOR_TYPE__SIDE | EDITOR_TYPE__SMART | EDITOR_TYPE__PLAIN
|
|
67
|
-
startingValues = {},
|
|
68
|
-
items = [], // Columns, FieldSets, Fields, etc to define the form
|
|
69
|
-
ancillaryItems = [], // additional items which are not controllable form elements, but should appear in the form
|
|
70
|
-
columnDefaults = {}, // defaults for each Column defined in items (above)
|
|
71
|
-
columnsConfig, // Which columns are shown in Grid, so the inline editor can match. Used only for EDITOR_TYPE__INLINE
|
|
72
|
-
validator, // custom validator, mainly for EDITOR_TYPE__PLAIN
|
|
73
|
-
footerProps = {},
|
|
74
|
-
buttonGroupProps = {}, // buttons in footer
|
|
75
|
-
checkIsEditingDisabled = true,
|
|
76
|
-
disableLabels = false,
|
|
77
|
-
disableDirtyIcon = false,
|
|
78
|
-
onBack,
|
|
79
|
-
onReset,
|
|
80
|
-
onInit,
|
|
81
|
-
onViewMode,
|
|
82
|
-
submitBtnLabel,
|
|
83
|
-
onSubmit,
|
|
84
|
-
formSetup, // this fn will be executed after the form setup is complete
|
|
85
|
-
additionalEditButtons,
|
|
86
|
-
useAdditionalEditButtons = true,
|
|
87
|
-
additionalFooterButtons,
|
|
88
|
-
|
|
89
|
-
// sizing of outer container
|
|
90
|
-
h,
|
|
91
|
-
maxHeight,
|
|
92
|
-
minHeight = 0,
|
|
93
|
-
w,
|
|
94
|
-
maxWidth,
|
|
95
|
-
flex,
|
|
96
|
-
onLayout, // onLayout handler for main view
|
|
97
|
-
|
|
98
|
-
// withComponent
|
|
99
|
-
self,
|
|
100
|
-
|
|
101
|
-
// withData
|
|
102
|
-
Repository,
|
|
103
|
-
|
|
104
|
-
// withEditor
|
|
105
|
-
isEditorViewOnly = false,
|
|
106
|
-
isSaving = false,
|
|
107
|
-
editorMode,
|
|
108
|
-
onCancel,
|
|
109
|
-
onSave,
|
|
110
|
-
onClose,
|
|
111
|
-
onDelete,
|
|
112
|
-
editorStateRef,
|
|
113
|
-
disableView,
|
|
114
|
-
|
|
115
|
-
// parent container
|
|
116
|
-
selectorId,
|
|
117
|
-
selectorSelected,
|
|
118
|
-
|
|
119
|
-
// withAlert
|
|
120
|
-
alert,
|
|
121
|
-
} = props,
|
|
122
|
-
formRef = useRef(),
|
|
123
|
-
styles = UiGlobals.styles,
|
|
124
|
-
record = props.record?.length === 1 ? props.record[0] : props.record;
|
|
125
|
-
let skipAll = false;
|
|
126
|
-
if (record?.isDestroyed) {
|
|
127
|
-
skipAll = true; // if record is destroyed, skip render, but allow hooks to still be called
|
|
128
|
-
if (self?.parent?.parent?.setIsEditorShown) {
|
|
129
|
-
self.parent.parent.setIsEditorShown(false); // close the editor
|
|
130
|
-
}
|
|
131
|
-
}
|
|
132
|
-
const
|
|
133
|
-
isMultiple = _.isArray(record),
|
|
134
|
-
isSingle = !isMultiple, // for convenience
|
|
135
|
-
isPhantom = !skipAll && !!record?.isPhantom, //
|
|
136
|
-
forceUpdate = useForceUpdate(),
|
|
137
|
-
[previousRecord, setPreviousRecord] = useState(record),
|
|
138
|
-
[containerWidth, setContainerWidth] = useState(),
|
|
139
|
-
initialValues = _.merge(startingValues, (record && !record.isDestroyed ? record.submitValues : {})),
|
|
140
|
-
defaultValues = isMultiple ? getNullFieldValues(initialValues, Repository) : initialValues, // when multiple entities, set all default values to null
|
|
141
|
-
validatorToUse = validator || (isMultiple ? disableRequiredYupFields(Repository?.schema?.model?.validator) : Repository?.schema?.model?.validator) || yup.object(),
|
|
142
|
-
{
|
|
143
|
-
control,
|
|
144
|
-
formState,
|
|
145
|
-
handleSubmit,
|
|
146
|
-
// register,
|
|
147
|
-
// unregister,
|
|
148
|
-
reset,
|
|
149
|
-
// watch,
|
|
150
|
-
// resetField,
|
|
151
|
-
// setError,
|
|
152
|
-
// clearErrors,
|
|
153
|
-
setValue: formSetValue,
|
|
154
|
-
// setFocus,
|
|
155
|
-
getValues: formGetValues,
|
|
156
|
-
// getFieldState,
|
|
157
|
-
trigger,
|
|
158
|
-
} = useForm({
|
|
159
|
-
mode: 'onChange', // onChange | onBlur | onSubmit | onTouched | all
|
|
160
|
-
// reValidateMode: 'onChange', // onChange | onBlur | onSubmit
|
|
161
|
-
defaultValues,
|
|
162
|
-
// values: defaultValues,
|
|
163
|
-
// resetOptions: {
|
|
164
|
-
// keepDirtyValues: false, // user-interacted input will be retained
|
|
165
|
-
// keepErrors: false, // input errors will be retained with value update
|
|
166
|
-
// },
|
|
167
|
-
// criteriaMode: 'firstError', // firstError | all
|
|
168
|
-
// shouldFocusError: false,
|
|
169
|
-
// delayError: 0,
|
|
170
|
-
// shouldUnregister: false,
|
|
171
|
-
// shouldUseNativeValidation: false,
|
|
172
|
-
resolver: yupResolver(validatorToUse),
|
|
173
|
-
context: { isPhantom },
|
|
174
|
-
}),
|
|
175
|
-
buildFromColumnsConfig = () => {
|
|
176
|
-
// For InlineEditor
|
|
177
|
-
// Build the fields that match the current columnsConfig in the grid
|
|
178
|
-
const
|
|
179
|
-
model = Repository.getSchema().model,
|
|
180
|
-
elements = [],
|
|
181
|
-
columnProps = {
|
|
182
|
-
justifyContent: 'center',
|
|
183
|
-
alignItems: 'center',
|
|
184
|
-
borderRightWidth: 1,
|
|
185
|
-
borderRightColor: 'grey-200',
|
|
186
|
-
px: 1,
|
|
187
|
-
};
|
|
188
|
-
|
|
189
|
-
if (editorType === EDITOR_TYPE__INLINE) {
|
|
190
|
-
columnProps.minWidth = styles.INLINE_EDITOR_MIN_WIDTH;
|
|
191
|
-
}
|
|
192
|
-
|
|
193
|
-
_.each(columnsConfig, (config, ix) => {
|
|
194
|
-
let {
|
|
195
|
-
fieldName,
|
|
196
|
-
isEditable,
|
|
197
|
-
editor,
|
|
198
|
-
renderer,
|
|
199
|
-
w,
|
|
200
|
-
flex,
|
|
201
|
-
useSelectorId = false,
|
|
202
|
-
} = config;
|
|
203
|
-
|
|
204
|
-
if (!isEditable) {
|
|
205
|
-
let renderedValue = renderer ? renderer(record) : record[fieldName];
|
|
206
|
-
if (_.isBoolean(renderedValue)) {
|
|
207
|
-
renderedValue = renderedValue.toString();
|
|
208
|
-
}
|
|
209
|
-
renderedValue += "\n(not editable)";
|
|
210
|
-
elements.push(<Box key={ix} {...columnProps} className={` flex-${flex} w-${w} `}>
|
|
211
|
-
<TextNative numberOfLines={1} ellipsizeMode="head">{renderedValue}</TextNative>
|
|
212
|
-
</Box>);
|
|
213
|
-
} else {
|
|
214
|
-
elements.push(<Controller
|
|
215
|
-
key={'controller-' + ix}
|
|
216
|
-
name={fieldName}
|
|
217
|
-
// rules={rules}
|
|
218
|
-
control={control}
|
|
219
|
-
render={(args) => {
|
|
220
|
-
const {
|
|
221
|
-
field,
|
|
222
|
-
fieldState,
|
|
223
|
-
// formState,
|
|
224
|
-
} = args,
|
|
225
|
-
{
|
|
226
|
-
onChange,
|
|
227
|
-
onBlur,
|
|
228
|
-
name,
|
|
229
|
-
value,
|
|
230
|
-
// ref,
|
|
231
|
-
} = field,
|
|
232
|
-
{
|
|
233
|
-
isTouched,
|
|
234
|
-
isDirty,
|
|
235
|
-
error,
|
|
236
|
-
} = fieldState;
|
|
237
|
-
let _editor = {};
|
|
238
|
-
if (!editor) {
|
|
239
|
-
const propertyDef = fieldName && Repository?.getSchema().getPropertyDefinition(fieldName);
|
|
240
|
-
editor = propertyDef && propertyDef[fieldName].editorType;
|
|
241
|
-
if (_.isPlainObject(editor)) {
|
|
242
|
-
const {
|
|
243
|
-
type,
|
|
244
|
-
onChange: onEditorChange,
|
|
245
|
-
...p
|
|
246
|
-
} = editor;
|
|
247
|
-
_editor = p;
|
|
248
|
-
editor = type;
|
|
249
|
-
}
|
|
250
|
-
}
|
|
251
|
-
const Element = getComponentFromType(editor);
|
|
252
|
-
|
|
253
|
-
if (useSelectorId) {
|
|
254
|
-
_editor.selectorId = selectorId;
|
|
255
|
-
_editor.selectorSelected = _editor;
|
|
256
|
-
}
|
|
257
|
-
|
|
258
|
-
let element = <Element
|
|
259
|
-
name={name}
|
|
260
|
-
value={value}
|
|
261
|
-
setValue={(newValue) => {
|
|
262
|
-
onChange(newValue);
|
|
263
|
-
if (onEditorChange) {
|
|
264
|
-
onEditorChange(newValue, formSetValue, formGetValues, formState);
|
|
265
|
-
}
|
|
266
|
-
}}
|
|
267
|
-
onBlur={onBlur}
|
|
268
|
-
flex={1}
|
|
269
|
-
{..._editor}
|
|
270
|
-
parent={self}
|
|
271
|
-
reference={fieldName}
|
|
272
|
-
// {...defaults}
|
|
273
|
-
// {...propsToPass}
|
|
274
|
-
/>;
|
|
275
|
-
|
|
276
|
-
// element = <Tooltip key={ix} label={header} placement="bottom">
|
|
277
|
-
// {element}
|
|
278
|
-
// </Tooltip>;
|
|
279
|
-
// if (error) {
|
|
280
|
-
// element = <VStack className="pt-1 flex-1">
|
|
281
|
-
// {element}
|
|
282
|
-
// <Text color="#f00">{error.message}</Text>
|
|
283
|
-
// </VStack>;
|
|
284
|
-
// }
|
|
285
|
-
|
|
286
|
-
const dirtyIcon = isDirty && !disableDirtyIcon ? <Icon
|
|
287
|
-
as={Pencil}
|
|
288
|
-
size="2xs"
|
|
289
|
-
className="text-grey-300 absolute top-[2px] left-[2px]"
|
|
290
|
-
/> : null;
|
|
291
|
-
return <HStack
|
|
292
|
-
key={ix}
|
|
293
|
-
{...columnProps}
|
|
294
|
-
className={` flex-${flex} w-${w} ${error ? "bg-[#fdd]" : "bg-white"} `}
|
|
295
|
-
>{dirtyIcon}{element}</HStack>;
|
|
296
|
-
}}
|
|
297
|
-
/>);
|
|
298
|
-
}
|
|
299
|
-
});
|
|
300
|
-
return <HStack>{elements}</HStack>;
|
|
301
|
-
},
|
|
302
|
-
buildFromItems = () => {
|
|
303
|
-
return _.map(items, (item, ix) => buildFromItem(item, ix, columnDefaults));
|
|
304
|
-
},
|
|
305
|
-
buildFromItem = (item, ix, defaults) => {
|
|
306
|
-
if (!item) {
|
|
307
|
-
return null;
|
|
308
|
-
}
|
|
309
|
-
if (React.isValidElement(item)) {
|
|
310
|
-
return item;
|
|
311
|
-
}
|
|
312
|
-
let {
|
|
313
|
-
type,
|
|
314
|
-
title,
|
|
315
|
-
name,
|
|
316
|
-
isEditable = true,
|
|
317
|
-
label,
|
|
318
|
-
items,
|
|
319
|
-
onChange: onEditorChange,
|
|
320
|
-
useSelectorId = false,
|
|
321
|
-
isHidden = false,
|
|
322
|
-
getDynamicProps,
|
|
323
|
-
getIsRequired,
|
|
324
|
-
...propsToPass
|
|
325
|
-
} = item,
|
|
326
|
-
editorTypeProps = {};
|
|
327
|
-
|
|
328
|
-
if (isHidden) {
|
|
329
|
-
return null;
|
|
330
|
-
}
|
|
331
|
-
if (type === 'DisplayField') {
|
|
332
|
-
isEditable = false;
|
|
333
|
-
}
|
|
334
|
-
const propertyDef = name && Repository?.getSchema().getPropertyDefinition(name);
|
|
335
|
-
if (!useAdditionalEditButtons) {
|
|
336
|
-
item = _.omit(item, 'additionalEditButtons');
|
|
337
|
-
}
|
|
338
|
-
if (propertyDef?.isEditingDisabled && checkIsEditingDisabled) {
|
|
339
|
-
isEditable = false;
|
|
340
|
-
}
|
|
341
|
-
if (!type) {
|
|
342
|
-
if (isEditable) {
|
|
343
|
-
const
|
|
344
|
-
{
|
|
345
|
-
type: t,
|
|
346
|
-
...p
|
|
347
|
-
} = propertyDef?.editorType;
|
|
348
|
-
type = t;
|
|
349
|
-
editorTypeProps = p;
|
|
350
|
-
} else if (propertyDef?.viewerType) {
|
|
351
|
-
const
|
|
352
|
-
{
|
|
353
|
-
type: t,
|
|
354
|
-
...p
|
|
355
|
-
} = propertyDef?.viewerType;
|
|
356
|
-
type = t;
|
|
357
|
-
} else {
|
|
358
|
-
type = 'Text';
|
|
359
|
-
}
|
|
360
|
-
}
|
|
361
|
-
const isCombo = type?.match && type.match(/Combo/);
|
|
362
|
-
if (item.hasOwnProperty('autoLoad')) {
|
|
363
|
-
editorTypeProps.autoLoad = item.autoLoad;
|
|
364
|
-
} else {
|
|
365
|
-
if (isCombo && Repository?.isRemote && !Repository?.isLoaded) {
|
|
366
|
-
editorTypeProps.autoLoad = true;
|
|
367
|
-
}
|
|
368
|
-
}
|
|
369
|
-
if (isCombo) {
|
|
370
|
-
// editorTypeProps.showEyeButton = true;
|
|
371
|
-
if (_.isNil(propsToPass.showXButton)) {
|
|
372
|
-
editorTypeProps.showXButton = true;
|
|
373
|
-
}
|
|
374
|
-
}
|
|
375
|
-
const Element = getComponentFromType(type);
|
|
376
|
-
let children;
|
|
377
|
-
|
|
378
|
-
if (inArray(type, ['Column', 'Row', 'FieldSet'])) {
|
|
379
|
-
if (_.isEmpty(items)) {
|
|
380
|
-
return null;
|
|
381
|
-
}
|
|
382
|
-
if (type === 'Column') {
|
|
383
|
-
if (containerWidth < styles.FORM_ONE_COLUMN_THRESHOLD) {
|
|
384
|
-
// everything is in one column
|
|
385
|
-
if (propsToPass.hasOwnProperty('flex')) {
|
|
386
|
-
delete propsToPass.flex;
|
|
387
|
-
}
|
|
388
|
-
if (propsToPass.hasOwnProperty('width')) {
|
|
389
|
-
delete propsToPass.width;
|
|
390
|
-
}
|
|
391
|
-
if (propsToPass.hasOwnProperty('w')) {
|
|
392
|
-
delete propsToPass.w;
|
|
393
|
-
}
|
|
394
|
-
propsToPass.w = '100%';
|
|
395
|
-
propsToPass.mb = 1;
|
|
396
|
-
}
|
|
397
|
-
propsToPass.pl = 3;
|
|
398
|
-
}
|
|
399
|
-
if (type === 'Row') {
|
|
400
|
-
propsToPass.w = '100%';
|
|
401
|
-
}
|
|
402
|
-
const itemDefaults = item.defaults;
|
|
403
|
-
children = _.map(items, (item, ix) => {
|
|
404
|
-
return buildFromItem(item, ix, itemDefaults);
|
|
405
|
-
});
|
|
406
|
-
return <Element key={ix} title={title} {...itemDefaults} {...propsToPass} {...editorTypeProps}>{children}</Element>;
|
|
407
|
-
}
|
|
408
|
-
|
|
409
|
-
if (!label && Repository && propertyDef?.title) {
|
|
410
|
-
label = propertyDef.title;
|
|
411
|
-
}
|
|
412
|
-
|
|
413
|
-
if (isEditorViewOnly || !isEditable) {
|
|
414
|
-
let value = null;
|
|
415
|
-
if (record?.properties && record.properties[name]) {
|
|
416
|
-
value = record.properties[name].displayValue;
|
|
417
|
-
}
|
|
418
|
-
if (_.isNil(value) && record && record[name]) {
|
|
419
|
-
value = record[name];
|
|
420
|
-
}
|
|
421
|
-
if (_.isNil(value) && startingValues && startingValues[name]) {
|
|
422
|
-
value = startingValues[name];
|
|
423
|
-
}
|
|
424
|
-
|
|
425
|
-
let element = <Element
|
|
426
|
-
value={value}
|
|
427
|
-
parent={self}
|
|
428
|
-
reference={name}
|
|
429
|
-
{...propsToPass}
|
|
430
|
-
/>;
|
|
431
|
-
if (!disableLabels && label) {
|
|
432
|
-
const labelProps = {};
|
|
433
|
-
if (defaults?.labelWidth) {
|
|
434
|
-
labelProps.w = defaults.labelWidth;
|
|
435
|
-
}
|
|
436
|
-
if (containerWidth > styles.FORM_STACK_ROW_THRESHOLD) {
|
|
437
|
-
element = <><Label {...labelProps}>{label}</Label>{element}</>;
|
|
438
|
-
} else {
|
|
439
|
-
element = <VStack><Label {...labelProps}>{label}</Label>{element}</VStack>;
|
|
440
|
-
}
|
|
441
|
-
}
|
|
442
|
-
return <HStack key={ix} className="px-2 pb-1">{element}</HStack>;
|
|
443
|
-
}
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
// // These rules are for fields *outside* the model
|
|
448
|
-
// // but which want validation on the form anyway.
|
|
449
|
-
// // The useForm() resolver disables this
|
|
450
|
-
// const
|
|
451
|
-
// rules = {},
|
|
452
|
-
// rulesToCheck = [
|
|
453
|
-
// 'required',
|
|
454
|
-
// 'min',
|
|
455
|
-
// 'max',
|
|
456
|
-
// 'minLength',
|
|
457
|
-
// 'maxLength',
|
|
458
|
-
// 'pattern',
|
|
459
|
-
// 'validate',
|
|
460
|
-
// ];
|
|
461
|
-
// _.each(rulesToCheck, (rule) => {
|
|
462
|
-
// if (item.hasOwnProperty(rule)) {
|
|
463
|
-
// rules[rule] = item[rule];
|
|
464
|
-
// }
|
|
465
|
-
// });
|
|
466
|
-
|
|
467
|
-
return <Controller
|
|
468
|
-
key={'controller-' + ix}
|
|
469
|
-
name={name}
|
|
470
|
-
// rules={rules}
|
|
471
|
-
control={control}
|
|
472
|
-
render={(args) => {
|
|
473
|
-
const {
|
|
474
|
-
field,
|
|
475
|
-
fieldState,
|
|
476
|
-
// formState,
|
|
477
|
-
} = args,
|
|
478
|
-
{
|
|
479
|
-
onChange,
|
|
480
|
-
onBlur,
|
|
481
|
-
name,
|
|
482
|
-
value,
|
|
483
|
-
// ref,
|
|
484
|
-
} = field,
|
|
485
|
-
{
|
|
486
|
-
isTouched,
|
|
487
|
-
isDirty,
|
|
488
|
-
error,
|
|
489
|
-
} = fieldState;
|
|
490
|
-
if (isValidElement(Element)) {
|
|
491
|
-
throw new Error('Should not yet be valid React element. Did you use <Element> instead of () => <Element> when defining it?')
|
|
492
|
-
}
|
|
493
|
-
|
|
494
|
-
if (useSelectorId) { // This causes the whole form to use selectorId
|
|
495
|
-
editorTypeProps.selectorId = selectorId;
|
|
496
|
-
}
|
|
497
|
-
if (propsToPass.selectorId || editorTypeProps.selectorId) { // editorTypeProps.selectorId causes just this one field to use selectorId
|
|
498
|
-
if (_.isNil(propsToPass.selectorSelected)) {
|
|
499
|
-
editorTypeProps.selectorSelected = record;
|
|
500
|
-
}
|
|
501
|
-
}
|
|
502
|
-
let dynamicProps = {};
|
|
503
|
-
if (getDynamicProps) {
|
|
504
|
-
dynamicProps = getDynamicProps({ fieldState, formSetValue, formGetValues, formState });
|
|
505
|
-
}
|
|
506
|
-
let element = <Element
|
|
507
|
-
name={name}
|
|
508
|
-
value={value}
|
|
509
|
-
onChangeValue={(newValue) => {
|
|
510
|
-
if (newValue === undefined) {
|
|
511
|
-
newValue = null; // React Hook Form doesn't respond well when setting value to undefined
|
|
512
|
-
}
|
|
513
|
-
onChange(newValue);
|
|
514
|
-
if (onEditorChange) {
|
|
515
|
-
onEditorChange(newValue, formSetValue, formGetValues, formState, trigger);
|
|
516
|
-
}
|
|
517
|
-
}}
|
|
518
|
-
onBlur={onBlur}
|
|
519
|
-
flex={1}
|
|
520
|
-
parent={self}
|
|
521
|
-
reference={name}
|
|
522
|
-
{...defaults}
|
|
523
|
-
{...propsToPass}
|
|
524
|
-
{...editorTypeProps}
|
|
525
|
-
{...dynamicProps}
|
|
526
|
-
/>;
|
|
527
|
-
if (editorType !== EDITOR_TYPE__INLINE) {
|
|
528
|
-
let message = null;
|
|
529
|
-
if (error) {
|
|
530
|
-
message = error.message;
|
|
531
|
-
if (label && error.ref?.name) {
|
|
532
|
-
message = message.replace(error.ref.name, label);
|
|
533
|
-
}
|
|
534
|
-
}
|
|
535
|
-
if (message) {
|
|
536
|
-
message = <Text className="text-[#f00]">{message}</Text>;
|
|
537
|
-
}
|
|
538
|
-
element = <VStack className="pt-1 flex-1">
|
|
539
|
-
{element}
|
|
540
|
-
{message}
|
|
541
|
-
</VStack>;
|
|
542
|
-
}
|
|
543
|
-
|
|
544
|
-
if (item.additionalEditButtons) {
|
|
545
|
-
const buttons = buildAdditionalButtons(item.additionalEditButtons, self, { fieldState, formSetValue, formGetValues, formState });
|
|
546
|
-
if (containerWidth > styles.FORM_STACK_ROW_THRESHOLD) {
|
|
547
|
-
element = <HStack className="flex-1 flex-wrap">
|
|
548
|
-
{element}
|
|
549
|
-
{buttons}
|
|
550
|
-
</HStack>;
|
|
551
|
-
} else {
|
|
552
|
-
element = <VStack className="flex-1 w-full">
|
|
553
|
-
{element}
|
|
554
|
-
<HStack className="flex-1 w-full mt-2 flex-wrap">
|
|
555
|
-
{buttons}
|
|
556
|
-
</HStack>
|
|
557
|
-
</VStack>;
|
|
558
|
-
}
|
|
559
|
-
}
|
|
560
|
-
|
|
561
|
-
let isRequired = false,
|
|
562
|
-
requiredIndicator = null;
|
|
563
|
-
if (!isMultiple) { // Don't require fields if editing multiple records
|
|
564
|
-
if (getIsRequired) {
|
|
565
|
-
isRequired = getIsRequired(formGetValues, formState);
|
|
566
|
-
} else if (validatorToUse?.fields && validatorToUse.fields[name]?.exclusiveTests?.required) {
|
|
567
|
-
// submitted validator
|
|
568
|
-
isRequired = true;
|
|
569
|
-
} else if ((propertyDef?.validator?.spec && !propertyDef.validator.spec.optional) ||
|
|
570
|
-
(propertyDef?.requiredIfPhantom && isPhantom) ||
|
|
571
|
-
(propertyDef?.requiredIfNotPhantom && !isPhantom)) {
|
|
572
|
-
// property definition
|
|
573
|
-
isRequired = true;
|
|
574
|
-
}
|
|
575
|
-
if (isRequired) {
|
|
576
|
-
requiredIndicator = <Text className="text-[#f00] text-[30px] pr-1">*</Text>;
|
|
577
|
-
}
|
|
578
|
-
}
|
|
579
|
-
if (!disableLabels && label && editorType !== EDITOR_TYPE__INLINE) {
|
|
580
|
-
const labelProps = {};
|
|
581
|
-
if (defaults?.labelWidth) {
|
|
582
|
-
labelProps.w = defaults.labelWidth;
|
|
583
|
-
}
|
|
584
|
-
if (containerWidth > styles.FORM_STACK_ROW_THRESHOLD) {
|
|
585
|
-
element = <HStack className="w-full py-1">
|
|
586
|
-
<Label {...labelProps}>{requiredIndicator}{label}</Label>
|
|
587
|
-
{element}
|
|
588
|
-
</HStack>;
|
|
589
|
-
} else {
|
|
590
|
-
element = <VStack className="w-full py-1 mt-3">
|
|
591
|
-
<Label {...labelProps}>{requiredIndicator}{label}</Label>
|
|
592
|
-
{element}
|
|
593
|
-
</VStack>;
|
|
594
|
-
}
|
|
595
|
-
} else if (disableLabels && requiredIndicator) {
|
|
596
|
-
element = <HStack className="w-full py-1">
|
|
597
|
-
{requiredIndicator}
|
|
598
|
-
{element}
|
|
599
|
-
</HStack>;
|
|
600
|
-
}
|
|
601
|
-
|
|
602
|
-
const dirtyIcon = isDirty && !disableDirtyIcon ? <Icon
|
|
603
|
-
as={Pencil}
|
|
604
|
-
size="2xs"
|
|
605
|
-
className="text-grey-300 absolute top-[2px] left-[2px]" /> : null;
|
|
606
|
-
return (
|
|
607
|
-
<HStack
|
|
608
|
-
key={ix}
|
|
609
|
-
className={` ${error ? "bg-[#fdd]" : "bg-[null]"} px-2 pb-1 `}>{dirtyIcon}{element}</HStack>
|
|
610
|
-
);
|
|
611
|
-
}}
|
|
612
|
-
/>;
|
|
613
|
-
},
|
|
614
|
-
buildAncillary = () => {
|
|
615
|
-
const components = [];
|
|
616
|
-
if (ancillaryItems.length) {
|
|
617
|
-
_.each(ancillaryItems, (item, ix) => {
|
|
618
|
-
let {
|
|
619
|
-
type,
|
|
620
|
-
title = null,
|
|
621
|
-
description = null,
|
|
622
|
-
selectorId,
|
|
623
|
-
...propsToPass
|
|
624
|
-
} = item;
|
|
625
|
-
if (isMultiple && type !== 'Attachments') {
|
|
626
|
-
return;
|
|
627
|
-
}
|
|
628
|
-
if (!propsToPass.h) {
|
|
629
|
-
propsToPass.h = 400;
|
|
630
|
-
}
|
|
631
|
-
const
|
|
632
|
-
Element = getComponentFromType(type),
|
|
633
|
-
element = <Element
|
|
634
|
-
selectorId={selectorId}
|
|
635
|
-
selectorSelected={selectorSelected || record}
|
|
636
|
-
flex={1}
|
|
637
|
-
uniqueRepository={true}
|
|
638
|
-
parent={self}
|
|
639
|
-
{...propsToPass}
|
|
640
|
-
/>;
|
|
641
|
-
if (title) {
|
|
642
|
-
if (record?.displayValue) {
|
|
643
|
-
title += ' for ' + record.displayValue;
|
|
644
|
-
}
|
|
645
|
-
title = <Text
|
|
646
|
-
className={` ${styles.FORM_ANCILLARY_TITLE_CLASSNAME} font-bold `}
|
|
647
|
-
>{title}</Text>;
|
|
648
|
-
}
|
|
649
|
-
if (description) {
|
|
650
|
-
description = <Text
|
|
651
|
-
className={` ${styles.FORM_ANCILLARY_DESCRIPTION_CLASSNAME} italic-italic `}
|
|
652
|
-
>{description}</Text>;
|
|
653
|
-
}
|
|
654
|
-
components.push(<VStack key={'ancillary-' + ix} className="mx-1 my-3">{title}{description}{element}</VStack>);
|
|
655
|
-
});
|
|
656
|
-
}
|
|
657
|
-
return components;
|
|
658
|
-
},
|
|
659
|
-
onSubmitError = (errors, e) => {
|
|
660
|
-
if (editorType === EDITOR_TYPE__INLINE) {
|
|
661
|
-
alert(errors.message);
|
|
662
|
-
}
|
|
663
|
-
},
|
|
664
|
-
doReset = (values) => {
|
|
665
|
-
reset(values);
|
|
666
|
-
if (onReset) {
|
|
667
|
-
onReset(values, formSetValue, formGetValues);
|
|
668
|
-
}
|
|
669
|
-
},
|
|
670
|
-
onSaveDecorated = async (data, e) => {
|
|
671
|
-
// reset the form after a save
|
|
672
|
-
const result = await onSave(data, e);
|
|
673
|
-
if (result) {
|
|
674
|
-
const values = record.submitValues;
|
|
675
|
-
doReset(values);
|
|
676
|
-
}
|
|
677
|
-
},
|
|
678
|
-
onSubmitDecorated = async (data, e) => {
|
|
679
|
-
const result = await onSubmit(data, e);
|
|
680
|
-
if (result) {
|
|
681
|
-
const values = record.submitValues;
|
|
682
|
-
doReset(values);
|
|
683
|
-
}
|
|
684
|
-
},
|
|
685
|
-
onLayoutDecorated = (e) => {
|
|
686
|
-
if (onLayout) {
|
|
687
|
-
onLayout(e);
|
|
688
|
-
}
|
|
689
|
-
|
|
690
|
-
setContainerWidth(e.nativeEvent.layout.width);
|
|
691
|
-
};
|
|
692
|
-
|
|
693
|
-
useEffect(() => {
|
|
694
|
-
if (skipAll) {
|
|
695
|
-
return;
|
|
696
|
-
}
|
|
697
|
-
if (record === previousRecord) {
|
|
698
|
-
if (onInit) {
|
|
699
|
-
onInit(initialValues, formSetValue, formGetValues);
|
|
700
|
-
}
|
|
701
|
-
} else {
|
|
702
|
-
setPreviousRecord(record);
|
|
703
|
-
doReset(defaultValues);
|
|
704
|
-
}
|
|
705
|
-
if (formSetup) {
|
|
706
|
-
formSetup(formSetValue, formGetValues, formState)
|
|
707
|
-
}
|
|
708
|
-
}, [record]);
|
|
709
|
-
|
|
710
|
-
useEffect(() => {
|
|
711
|
-
if (skipAll) {
|
|
712
|
-
return;
|
|
713
|
-
}
|
|
714
|
-
if (!Repository) {
|
|
715
|
-
return () => {
|
|
716
|
-
if (!_.isNil(editorStateRef)) {
|
|
717
|
-
editorStateRef.current = null; // clean up the editorStateRef on unmount
|
|
718
|
-
}
|
|
719
|
-
};
|
|
720
|
-
}
|
|
721
|
-
|
|
722
|
-
Repository.ons(['changeData', 'change'], forceUpdate);
|
|
723
|
-
|
|
724
|
-
return () => {
|
|
725
|
-
Repository.offs(['changeData', 'change'], forceUpdate);
|
|
726
|
-
if (!_.isNil(editorStateRef)) {
|
|
727
|
-
editorStateRef.current = null; // clean up the editorStateRef on unmount
|
|
728
|
-
}
|
|
729
|
-
};
|
|
730
|
-
}, [Repository]);
|
|
731
|
-
|
|
732
|
-
if (skipAll) {
|
|
733
|
-
return null;
|
|
734
|
-
}
|
|
735
|
-
|
|
736
|
-
// if (Repository && (!record || _.isEmpty(record) || record.isDestroyed)) {
|
|
737
|
-
// return null;
|
|
738
|
-
// }
|
|
739
|
-
|
|
740
|
-
if (!_.isNil(editorStateRef)) {
|
|
741
|
-
editorStateRef.current = formState; // Update state so HOC can know what's going on
|
|
742
|
-
}
|
|
743
|
-
|
|
744
|
-
if (self) {
|
|
745
|
-
self.ref = formRef;
|
|
746
|
-
self.formState = formState;
|
|
747
|
-
self.formSetValue = formSetValue;
|
|
748
|
-
self.formGetValues = formGetValues;
|
|
749
|
-
}
|
|
750
|
-
|
|
751
|
-
const sizeProps = {};
|
|
752
|
-
if (!flex && !h && !w) {
|
|
753
|
-
sizeProps.flex = 1;
|
|
754
|
-
} else {
|
|
755
|
-
if (h) {
|
|
756
|
-
sizeProps.h = h;
|
|
757
|
-
}
|
|
758
|
-
if (w) {
|
|
759
|
-
sizeProps.w = w;
|
|
760
|
-
}
|
|
761
|
-
if (flex) {
|
|
762
|
-
sizeProps.flex = flex;
|
|
763
|
-
}
|
|
764
|
-
}
|
|
765
|
-
if (maxWidth) {
|
|
766
|
-
sizeProps.maxWidth = maxWidth;
|
|
767
|
-
}
|
|
768
|
-
if (maxHeight) {
|
|
769
|
-
sizeProps.maxHeight = maxHeight;
|
|
770
|
-
}
|
|
771
|
-
|
|
772
|
-
const formButtons = [];
|
|
773
|
-
let formComponents,
|
|
774
|
-
editor,
|
|
775
|
-
additionalButtons,
|
|
776
|
-
isSaveDisabled = false,
|
|
777
|
-
isSubmitDisabled = false,
|
|
778
|
-
savingProps = {},
|
|
779
|
-
|
|
780
|
-
showDeleteBtn = false,
|
|
781
|
-
showResetBtn = false,
|
|
782
|
-
showCloseBtn = false,
|
|
783
|
-
showCancelBtn = false,
|
|
784
|
-
showSaveBtn = false,
|
|
785
|
-
showSubmitBtn = false;
|
|
786
|
-
|
|
787
|
-
if (containerWidth) { // we need to render this component twice in order to get the container width. Skip this on first render
|
|
788
|
-
|
|
789
|
-
if (isSaving) {
|
|
790
|
-
savingProps.borderTopWidth = 2;
|
|
791
|
-
savingProps.borderTopColor = '#f00';
|
|
792
|
-
}
|
|
793
|
-
|
|
794
|
-
if (editorType === EDITOR_TYPE__INLINE) {
|
|
795
|
-
editor = buildFromColumnsConfig();
|
|
796
|
-
// } else if (editorType === EDITOR_TYPE__PLAIN) {
|
|
797
|
-
// formComponents = buildFromItems();
|
|
798
|
-
// const formAncillaryComponents = buildAncillary();
|
|
799
|
-
// editor = <>
|
|
800
|
-
// <VStack className="p-4">{formComponents}</VStack>
|
|
801
|
-
// <VStack className="pt-4">{formAncillaryComponents}</VStack>
|
|
802
|
-
// </>;
|
|
803
|
-
} else {
|
|
804
|
-
formComponents = buildFromItems();
|
|
805
|
-
const formAncillaryComponents = buildAncillary();
|
|
806
|
-
editor = <>
|
|
807
|
-
{containerWidth >= styles.FORM_ONE_COLUMN_THRESHOLD ? <HStack className="p-4 pl-0">{formComponents}</HStack> : null}
|
|
808
|
-
{containerWidth < styles.FORM_ONE_COLUMN_THRESHOLD ? <VStack className="p-4">{formComponents}</VStack> : null}
|
|
809
|
-
<VStack className="m-2 pt-4 px-2">{formAncillaryComponents}</VStack>
|
|
810
|
-
</>;
|
|
811
|
-
|
|
812
|
-
additionalButtons = buildAdditionalButtons(additionalEditButtons);
|
|
813
|
-
|
|
814
|
-
formButtons.push(<HStack key="buttonsRow" className="px-4 pt-4 items-center justify-end">
|
|
815
|
-
{isSingle && editorMode === EDITOR_MODE__EDIT && onBack &&
|
|
816
|
-
<Button
|
|
817
|
-
key="backBtn"
|
|
818
|
-
onPress={onBack}
|
|
819
|
-
leftIcon={<Icon as={AngleLeft} size="sm" className="text-white" />}
|
|
820
|
-
color="#fff"
|
|
821
|
-
>Back</Button>}
|
|
822
|
-
{isSingle && editorMode === EDITOR_MODE__EDIT && onViewMode && !disableView &&
|
|
823
|
-
<Button
|
|
824
|
-
key="viewBtn"
|
|
825
|
-
onPress={onViewMode}
|
|
826
|
-
leftIcon={<Icon as={Eye} size="sm" className="text-white" />}
|
|
827
|
-
color="#fff"
|
|
828
|
-
>To View</Button>}
|
|
829
|
-
</HStack>);
|
|
830
|
-
if (editorMode === EDITOR_MODE__EDIT && !_.isEmpty(additionalButtons)) {
|
|
831
|
-
formButtons.push(<HStack
|
|
832
|
-
key="additionalButtonsRow"
|
|
833
|
-
className="p-[4px] items-center justify-end flex-wrap"
|
|
834
|
-
>
|
|
835
|
-
{additionalButtons}
|
|
836
|
-
</HStack>)
|
|
837
|
-
}
|
|
838
|
-
}
|
|
839
|
-
|
|
840
|
-
if (!formState.isValid) {
|
|
841
|
-
isSaveDisabled = true;
|
|
842
|
-
isSubmitDisabled = true;
|
|
843
|
-
}
|
|
844
|
-
if (_.isEmpty(formState.dirtyFields) && !isPhantom) {
|
|
845
|
-
isSaveDisabled = true;
|
|
846
|
-
}
|
|
847
|
-
|
|
848
|
-
if (editorType === EDITOR_TYPE__INLINE) {
|
|
849
|
-
buttonGroupProps.position = 'fixed';
|
|
850
|
-
buttonGroupProps.left = 10; // TODO: I would prefer to have this be centered, but it's a lot more complex than just making it stick to the left
|
|
851
|
-
footerProps.alignItems = 'flex-start';
|
|
852
|
-
}
|
|
853
|
-
|
|
854
|
-
if (onDelete && editorMode === EDITOR_MODE__EDIT && isSingle) {
|
|
855
|
-
showDeleteBtn = true;
|
|
856
|
-
}
|
|
857
|
-
if (!isEditorViewOnly) {
|
|
858
|
-
showResetBtn = true;
|
|
859
|
-
}
|
|
860
|
-
if (editorType !== EDITOR_TYPE__SIDE) { // side editor won't show either close or cancel buttons!
|
|
861
|
-
// determine whether we should show the close or cancel button
|
|
862
|
-
if (isEditorViewOnly) {
|
|
863
|
-
showCloseBtn = true;
|
|
864
|
-
} else {
|
|
865
|
-
const formIsDirty = formState.isDirty;
|
|
866
|
-
// console.log('formIsDirty', formIsDirty);
|
|
867
|
-
// console.log('isPhantom', isPhantom);
|
|
868
|
-
if (formIsDirty || isPhantom) {
|
|
869
|
-
if (isSingle && onCancel) {
|
|
870
|
-
showCancelBtn = true;
|
|
871
|
-
}
|
|
872
|
-
} else {
|
|
873
|
-
if (onClose) {
|
|
874
|
-
showCloseBtn = true;
|
|
875
|
-
}
|
|
876
|
-
}
|
|
877
|
-
}
|
|
878
|
-
}
|
|
879
|
-
if (!isEditorViewOnly && onSave) {
|
|
880
|
-
showSaveBtn = true;
|
|
881
|
-
}
|
|
882
|
-
if (!!onSubmit) {
|
|
883
|
-
showSubmitBtn = true;
|
|
884
|
-
}
|
|
885
|
-
}
|
|
886
|
-
|
|
887
|
-
return <VStackNative
|
|
888
|
-
{...sizeProps}
|
|
889
|
-
onLayout={onLayoutDecorated}
|
|
890
|
-
ref={formRef}
|
|
891
|
-
>
|
|
892
|
-
{!!containerWidth && <>
|
|
893
|
-
{editorType === EDITOR_TYPE__INLINE &&
|
|
894
|
-
<ScrollView
|
|
895
|
-
horizontal={true}
|
|
896
|
-
className="flex-1 bg-white py-1 border-t-[3px] border-b-[5px] border-t-primary-100 border-b-primary-100">{editor}</ScrollView>}
|
|
897
|
-
{editorType !== EDITOR_TYPE__INLINE &&
|
|
898
|
-
<ScrollView _web={{ minHeight, }} className="w-full pb-1">
|
|
899
|
-
{formButtons}
|
|
900
|
-
{editor}
|
|
901
|
-
</ScrollView>}
|
|
902
|
-
|
|
903
|
-
<Footer className="justify-end" {...footerProps} {...savingProps}>
|
|
904
|
-
{onDelete && editorMode === EDITOR_MODE__EDIT && isSingle &&
|
|
905
|
-
|
|
906
|
-
<HStack className="flex-1 justify-start">
|
|
907
|
-
<Button
|
|
908
|
-
key="deleteBtn"
|
|
909
|
-
onPress={onDelete}
|
|
910
|
-
bg="warning"
|
|
911
|
-
_hover={{
|
|
912
|
-
bg: 'warningHover',
|
|
913
|
-
}}
|
|
914
|
-
color="#fff"
|
|
915
|
-
>Delete</Button>
|
|
916
|
-
</HStack>}
|
|
917
|
-
|
|
918
|
-
{showResetBtn &&
|
|
919
|
-
<IconButton
|
|
920
|
-
key="resetBtn"
|
|
921
|
-
onPress={() => doReset()}
|
|
922
|
-
icon={Rotate}
|
|
923
|
-
_icon={{
|
|
924
|
-
color: !formState.isDirty ? 'grey-400' : '#000',
|
|
925
|
-
}}
|
|
926
|
-
isDisabled={!formState.isDirty}
|
|
927
|
-
mr={2}
|
|
928
|
-
/>}
|
|
929
|
-
|
|
930
|
-
{showCancelBtn &&
|
|
931
|
-
<Button
|
|
932
|
-
key="cancelBtn"
|
|
933
|
-
variant="outline"
|
|
934
|
-
onPress={onCancel}
|
|
935
|
-
color="#fff"
|
|
936
|
-
>Cancel</Button>}
|
|
937
|
-
|
|
938
|
-
{showCloseBtn &&
|
|
939
|
-
<Button
|
|
940
|
-
key="closeBtn"
|
|
941
|
-
variant="outline"
|
|
942
|
-
onPress={onClose}
|
|
943
|
-
color="#fff"
|
|
944
|
-
>Close</Button>}
|
|
945
|
-
|
|
946
|
-
{showSaveBtn &&
|
|
947
|
-
<Button
|
|
948
|
-
key="saveBtn"
|
|
949
|
-
onPress={(e) => handleSubmit(onSaveDecorated, onSubmitError)(e)}
|
|
950
|
-
isDisabled={isSaveDisabled}
|
|
951
|
-
color="#fff"
|
|
952
|
-
>{editorMode === EDITOR_MODE__ADD ? 'Add' : 'Save'}</Button>}
|
|
953
|
-
|
|
954
|
-
{showSubmitBtn &&
|
|
955
|
-
<Button
|
|
956
|
-
key="submitBtn"
|
|
957
|
-
onPress={(e) => handleSubmit(onSubmitDecorated, onSubmitError)(e)}
|
|
958
|
-
isDisabled={isSubmitDisabled}
|
|
959
|
-
color="#fff"
|
|
960
|
-
>{submitBtnLabel || 'Submit'}</Button>}
|
|
961
|
-
|
|
962
|
-
{additionalFooterButtons && _.map(additionalFooterButtons, (props) => {
|
|
963
|
-
return <Button
|
|
964
|
-
{...props}
|
|
965
|
-
onPress={(e) => handleSubmit(props.onPress, onSubmitError)(e)}
|
|
966
|
-
>{props.text}</Button>;
|
|
967
|
-
})}
|
|
968
|
-
</Footer>
|
|
969
|
-
</>}
|
|
970
|
-
</VStackNative>;
|
|
971
|
-
}
|
|
972
|
-
|
|
973
|
-
// helper fns
|
|
974
|
-
function disableRequiredYupFields(validator) {
|
|
975
|
-
// based on https://github.com/jquense/yup/issues/1466#issuecomment-944386480
|
|
976
|
-
if (!validator) {
|
|
977
|
-
return null;
|
|
978
|
-
}
|
|
979
|
-
|
|
980
|
-
const nextSchema = validator.clone();
|
|
981
|
-
return nextSchema.withMutation((next) => {
|
|
982
|
-
if (typeof next.fields === 'object' && next.fields != null) {
|
|
983
|
-
for (const key in next.fields) {
|
|
984
|
-
const nestedField = next.fields[key];
|
|
985
|
-
|
|
986
|
-
let nestedFieldNext = nestedField.notRequired();
|
|
987
|
-
|
|
988
|
-
if (Array.isArray(nestedField.conditions) && nestedField.conditions.length > 0) {
|
|
989
|
-
// Next is done to disable required() inside a condition
|
|
990
|
-
// https://github.com/jquense/yup/issues/1002
|
|
991
|
-
nestedFieldNext = nestedFieldNext.when('whatever', (unused, schema) => {
|
|
992
|
-
return schema.notRequired();
|
|
993
|
-
});
|
|
994
|
-
}
|
|
995
|
-
|
|
996
|
-
next.fields[key] = nestedFieldNext;
|
|
997
|
-
}
|
|
998
|
-
}
|
|
999
|
-
});
|
|
1000
|
-
}
|
|
1001
|
-
function getNullFieldValues(initialValues, Repository) {
|
|
1002
|
-
const ret = {};
|
|
1003
|
-
if (Repository) {
|
|
1004
|
-
const properties = Repository.getSchema().model.properties;
|
|
1005
|
-
_.each(properties, (propertyDef) => {
|
|
1006
|
-
ret[propertyDef.name] = null;
|
|
1007
|
-
});
|
|
1008
|
-
} else {
|
|
1009
|
-
// takes a JSON object of fieldValues and sets them all to null
|
|
1010
|
-
_.each(initialValues, (value, field) => {
|
|
1011
|
-
ret[field] = null;
|
|
1012
|
-
});
|
|
1013
|
-
}
|
|
1014
|
-
return ret;
|
|
1015
|
-
}
|
|
1016
|
-
|
|
1017
|
-
export const FormEditor = withComponent(withAlert(withEditor(withPdfButton(FormikForm))));
|
|
1018
|
-
|
|
1019
|
-
export default withComponent(withAlert(withPdfButton(FormikForm)));
|