@servicetitan/dte-pdf-editor 1.86.0 → 1.88.0
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 +37 -30
- package/dist/components/display-conditions/condition-row.d.ts.map +1 -1
- package/dist/components/display-conditions/condition-row.js +51 -22
- package/dist/components/display-conditions/condition-row.js.map +1 -1
- package/dist/components/display-conditions/condition-value-control.d.ts.map +1 -1
- package/dist/components/display-conditions/condition-value-control.js +1 -2
- package/dist/components/display-conditions/condition-value-control.js.map +1 -1
- package/dist/components/display-conditions/display-condition-modal.d.ts.map +1 -1
- package/dist/components/display-conditions/display-condition-modal.js +6 -49
- package/dist/components/display-conditions/display-condition-modal.js.map +1 -1
- package/dist/components/field-config-panel/e-sign-date-rules-summary.d.ts +11 -0
- package/dist/components/field-config-panel/e-sign-date-rules-summary.d.ts.map +1 -0
- package/dist/components/field-config-panel/e-sign-date-rules-summary.js +36 -0
- package/dist/components/field-config-panel/e-sign-date-rules-summary.js.map +1 -0
- package/dist/components/field-config-panel/e-sign-date-signed-offset-modal.d.ts +16 -0
- package/dist/components/field-config-panel/e-sign-date-signed-offset-modal.d.ts.map +1 -0
- package/dist/components/field-config-panel/e-sign-date-signed-offset-modal.js +62 -0
- package/dist/components/field-config-panel/e-sign-date-signed-offset-modal.js.map +1 -0
- package/dist/components/field-config-panel/e-sign-offset-rule-row.d.ts +16 -0
- package/dist/components/field-config-panel/e-sign-offset-rule-row.d.ts.map +1 -0
- package/dist/components/field-config-panel/e-sign-offset-rule-row.js +25 -0
- package/dist/components/field-config-panel/e-sign-offset-rule-row.js.map +1 -0
- package/dist/components/field-config-panel/e-sign-options-modal.d.ts +15 -0
- package/dist/components/field-config-panel/e-sign-options-modal.d.ts.map +1 -0
- package/dist/components/field-config-panel/e-sign-options-modal.js +26 -0
- package/dist/components/field-config-panel/e-sign-options-modal.js.map +1 -0
- package/dist/components/field-config-panel/field-config-panel.d.ts.map +1 -1
- package/dist/components/field-config-panel/field-config-panel.js +30 -28
- package/dist/components/field-config-panel/field-config-panel.js.map +1 -1
- package/dist/components/field-sidebar/e-sign-field-type-list.d.ts.map +1 -1
- package/dist/components/field-sidebar/e-sign-field-type-list.js +1 -6
- package/dist/components/field-sidebar/e-sign-field-type-list.js.map +1 -1
- package/dist/components/pdf-fields-overlay/pdf-overlay-field-fillable.d.ts.map +1 -1
- package/dist/components/pdf-fields-overlay/pdf-overlay-field-fillable.js +22 -8
- package/dist/components/pdf-fields-overlay/pdf-overlay-field-fillable.js.map +1 -1
- package/dist/components/pdf-view/pdf-view-fillable.d.ts.map +1 -1
- package/dist/components/pdf-view/pdf-view-fillable.js +3 -3
- package/dist/components/pdf-view/pdf-view-fillable.js.map +1 -1
- package/dist/constants/field.constants.d.ts +1 -5
- package/dist/constants/field.constants.d.ts.map +1 -1
- package/dist/constants/field.constants.js +21 -7
- package/dist/constants/field.constants.js.map +1 -1
- package/dist/hooks/usePdfFieldDnD.d.ts.map +1 -1
- package/dist/hooks/usePdfFieldDnD.js +13 -5
- package/dist/hooks/usePdfFieldDnD.js.map +1 -1
- package/dist/interface/types.d.ts +26 -1
- package/dist/interface/types.d.ts.map +1 -1
- package/dist/interface/types.js +1 -0
- package/dist/interface/types.js.map +1 -1
- package/dist/styles/field-config-panel.css +11 -0
- package/dist/styles/field-type.css +12 -0
- package/dist/styles/index.css +1 -0
- package/dist/styles/variables.css +2 -0
- package/dist/utils/conditions/condition-match-type.utils.d.ts +14 -0
- package/dist/utils/conditions/condition-match-type.utils.d.ts.map +1 -0
- package/dist/utils/conditions/condition-match-type.utils.js +50 -0
- package/dist/utils/conditions/condition-match-type.utils.js.map +1 -0
- package/dist/utils/conditions/e-sign-offset-rules.utils.d.ts +12 -0
- package/dist/utils/conditions/e-sign-offset-rules.utils.d.ts.map +1 -0
- package/dist/utils/conditions/e-sign-offset-rules.utils.js +19 -0
- package/dist/utils/conditions/e-sign-offset-rules.utils.js.map +1 -0
- package/dist/utils/conditions/index.d.ts +2 -0
- package/dist/utils/conditions/index.d.ts.map +1 -1
- package/dist/utils/conditions/index.js +2 -0
- package/dist/utils/conditions/index.js.map +1 -1
- package/dist/utils/field/field-placeholder-text.utils.d.ts +1 -0
- package/dist/utils/field/field-placeholder-text.utils.d.ts.map +1 -1
- package/dist/utils/field/field-placeholder-text.utils.js +9 -4
- package/dist/utils/field/field-placeholder-text.utils.js.map +1 -1
- package/package.json +1 -1
- package/src/__tests__/field-types/custom-fields.test.ts +187 -0
- package/src/components/display-conditions/condition-row.tsx +114 -131
- package/src/components/display-conditions/condition-value-control.tsx +1 -2
- package/src/components/display-conditions/display-condition-modal.tsx +13 -63
- package/src/components/field-config-panel/e-sign-date-rules-summary.tsx +114 -0
- package/src/components/field-config-panel/e-sign-date-signed-offset-modal.tsx +197 -0
- package/src/components/field-config-panel/e-sign-offset-rule-row.tsx +91 -0
- package/src/components/field-config-panel/e-sign-options-modal.tsx +112 -0
- package/src/components/field-config-panel/field-config-panel.tsx +70 -91
- package/src/components/field-sidebar/e-sign-field-type-list.tsx +11 -14
- package/src/components/pdf-fields-overlay/pdf-overlay-field-fillable.tsx +46 -14
- package/src/components/pdf-view/pdf-view-fillable.tsx +3 -2
- package/src/constants/field.constants.ts +21 -8
- package/src/hooks/usePdfFieldDnD.ts +17 -2
- package/src/interface/types.ts +34 -1
- package/src/styles/field-config-panel.css +11 -0
- package/src/styles/field-type.css +12 -0
- package/src/styles/index.css +1 -0
- package/src/styles/variables.css +2 -0
- package/src/utils/conditions/__tests__/condition-match-type.utils.test.ts +104 -0
- package/src/utils/conditions/__tests__/e-sign-offset-rules.utils.test.ts +51 -0
- package/src/utils/conditions/condition-match-type.utils.ts +80 -0
- package/src/utils/conditions/e-sign-offset-rules.utils.ts +32 -0
- package/src/utils/conditions/index.ts +2 -0
- package/src/utils/field/__tests__/field-placeholder-text.utils.test.ts +17 -1
- package/src/utils/field/field-placeholder-text.utils.ts +10 -4
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Button, Chip,
|
|
1
|
+
import { Button, Chip, Flex, SelectFieldSync, Text } from '@servicetitan/anvil2';
|
|
2
2
|
import TrashIcon from '@servicetitan/anvil2/assets/icons/material/round/delete.svg';
|
|
3
3
|
import { useEffect, useMemo, useState } from 'react';
|
|
4
4
|
import {
|
|
@@ -220,6 +220,68 @@ export function ConditionRow({
|
|
|
220
220
|
[operatorItems, condition.operator],
|
|
221
221
|
);
|
|
222
222
|
|
|
223
|
+
const sourceKindSelectOptions = useMemo(
|
|
224
|
+
() => sourceKindOptions.map(option => ({ id: option.value, label: option.label })),
|
|
225
|
+
[sourceKindOptions],
|
|
226
|
+
);
|
|
227
|
+
|
|
228
|
+
const selectedSourceKindSelectOption = selectedSourceKindOption
|
|
229
|
+
? { id: selectedSourceKindOption.value, label: selectedSourceKindOption.label }
|
|
230
|
+
: null;
|
|
231
|
+
|
|
232
|
+
const handleSourceKindSelect = (option: { id: string; label: string } | null) => {
|
|
233
|
+
handleSourceKindChange(sourceKindOptions.find(o => o.value === option?.id) ?? null);
|
|
234
|
+
};
|
|
235
|
+
|
|
236
|
+
const formSelectOptions = useMemo(
|
|
237
|
+
() => sortedForms.map(form => ({ id: form.id, label: form.name })),
|
|
238
|
+
[sortedForms],
|
|
239
|
+
);
|
|
240
|
+
|
|
241
|
+
const selectedFormSelectOption = pickerForm
|
|
242
|
+
? { id: pickerForm.id, label: pickerForm.name }
|
|
243
|
+
: null;
|
|
244
|
+
|
|
245
|
+
const handleFormSelect = (option: { id: number; label: string }) => {
|
|
246
|
+
handlePickerFormChange(sortedForms.find(f => f.id === option?.id) ?? null);
|
|
247
|
+
};
|
|
248
|
+
|
|
249
|
+
const dataPointSelectOptions = useMemo(
|
|
250
|
+
() => dataPointItems.map(item => ({ id: item.fullKey, label: item.title })),
|
|
251
|
+
[dataPointItems],
|
|
252
|
+
);
|
|
253
|
+
|
|
254
|
+
const selectedDataPointSelectOption = selectedDataPoint
|
|
255
|
+
? { id: selectedDataPoint.fullKey, label: selectedDataPoint.title }
|
|
256
|
+
: null;
|
|
257
|
+
|
|
258
|
+
const handleDataPointSelect = (option: { id: string; label: string }) => {
|
|
259
|
+
handleDataPointChange(dataPointItems.find(item => item.fullKey === option?.id) ?? null);
|
|
260
|
+
};
|
|
261
|
+
|
|
262
|
+
const operatorSelectOptions = useMemo(
|
|
263
|
+
() => operatorItems.map(op => ({ id: op.value, label: op.label })),
|
|
264
|
+
[operatorItems],
|
|
265
|
+
);
|
|
266
|
+
|
|
267
|
+
const selectedOperatorSelectOption = selectedOperator
|
|
268
|
+
? { id: selectedOperator.value, label: selectedOperator.label }
|
|
269
|
+
: null;
|
|
270
|
+
|
|
271
|
+
const handleOperatorSelect = (option: { id: string; label: string } | null) => {
|
|
272
|
+
const nextOperator = (option?.id ?? 'is_equal_to') as DisplayConditionSingle['operator'];
|
|
273
|
+
onChange({
|
|
274
|
+
...condition,
|
|
275
|
+
operator: nextOperator,
|
|
276
|
+
...(isCheckbox
|
|
277
|
+
? {
|
|
278
|
+
value: CHECKBOX_CONDITION_VALUE,
|
|
279
|
+
valueLabel: undefined,
|
|
280
|
+
}
|
|
281
|
+
: {}),
|
|
282
|
+
});
|
|
283
|
+
};
|
|
284
|
+
|
|
223
285
|
const isValueLess =
|
|
224
286
|
isCheckbox || VALUE_LESS_OPERATORS.includes(condition.operator as ConditionOperator);
|
|
225
287
|
|
|
@@ -336,51 +398,27 @@ export function ConditionRow({
|
|
|
336
398
|
return (
|
|
337
399
|
<Flex direction="column" gap="4" flex={1}>
|
|
338
400
|
<Flex flex={1} gap="2">
|
|
339
|
-
<
|
|
401
|
+
<SelectFieldSync
|
|
340
402
|
flex={1}
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
<Combobox.Content>
|
|
350
|
-
{({ items }: { items: SourceKindOption[] }) => (
|
|
351
|
-
<Combobox.List>
|
|
352
|
-
{items.map((item, i) => (
|
|
353
|
-
<Combobox.Item index={i} item={item} key={item.value}>
|
|
354
|
-
{item.label}
|
|
355
|
-
</Combobox.Item>
|
|
356
|
-
))}
|
|
357
|
-
</Combobox.List>
|
|
358
|
-
)}
|
|
359
|
-
</Combobox.Content>
|
|
360
|
-
</Combobox>
|
|
403
|
+
disableSearch
|
|
404
|
+
disableClearButton
|
|
405
|
+
label="Source"
|
|
406
|
+
placeholder="Select source..."
|
|
407
|
+
options={sourceKindSelectOptions}
|
|
408
|
+
value={selectedSourceKindSelectOption}
|
|
409
|
+
onSelectedOptionChange={handleSourceKindSelect}
|
|
410
|
+
/>
|
|
361
411
|
{sourceKind === FieldTypeEnum.forms && (
|
|
362
|
-
<
|
|
412
|
+
<SelectFieldSync
|
|
363
413
|
flex={1}
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
<Combobox.Content>
|
|
373
|
-
{({ items }: { items: FormInfo[] }) => (
|
|
374
|
-
<Combobox.List>
|
|
375
|
-
{items.map((item, i) => (
|
|
376
|
-
<Combobox.Item index={i} item={item} key={item.id}>
|
|
377
|
-
{item.name}
|
|
378
|
-
</Combobox.Item>
|
|
379
|
-
))}
|
|
380
|
-
</Combobox.List>
|
|
381
|
-
)}
|
|
382
|
-
</Combobox.Content>
|
|
383
|
-
</Combobox>
|
|
414
|
+
disableSearch
|
|
415
|
+
disableClearButton
|
|
416
|
+
label="Select Form"
|
|
417
|
+
placeholder="Select form..."
|
|
418
|
+
options={formSelectOptions}
|
|
419
|
+
value={selectedFormSelectOption}
|
|
420
|
+
onSelectedOptionChange={handleFormSelect}
|
|
421
|
+
/>
|
|
384
422
|
)}
|
|
385
423
|
</Flex>
|
|
386
424
|
|
|
@@ -401,113 +439,58 @@ export function ConditionRow({
|
|
|
401
439
|
</Flex>
|
|
402
440
|
|
|
403
441
|
<Flex flex={1} style={{ minWidth: 160 }}>
|
|
404
|
-
<
|
|
442
|
+
<SelectFieldSync
|
|
405
443
|
flex={1}
|
|
444
|
+
disableSearch
|
|
445
|
+
disableClearButton
|
|
406
446
|
disabled={
|
|
407
447
|
sourceKind === FieldTypeEnum.forms &&
|
|
408
448
|
(!pickerForm || isLoadingFormFields)
|
|
409
449
|
}
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
: sourceKind === FieldTypeEnum.forms && !pickerForm
|
|
423
|
-
? 'Select a form first...'
|
|
424
|
-
: 'Select data point...'
|
|
425
|
-
}
|
|
426
|
-
/>
|
|
427
|
-
<Combobox.Content>
|
|
428
|
-
{({ items }: { items: DataPointOption[] }) => (
|
|
429
|
-
<Combobox.List>
|
|
430
|
-
{items.map((item, i) => (
|
|
431
|
-
<Combobox.Item index={i} item={item} key={item.fullKey}>
|
|
432
|
-
{item.title}
|
|
433
|
-
</Combobox.Item>
|
|
434
|
-
))}
|
|
435
|
-
</Combobox.List>
|
|
436
|
-
)}
|
|
437
|
-
</Combobox.Content>
|
|
438
|
-
</Combobox>
|
|
450
|
+
label="Data point"
|
|
451
|
+
placeholder={
|
|
452
|
+
sourceKind === FieldTypeEnum.forms && isLoadingFormFields
|
|
453
|
+
? 'Loading fields...'
|
|
454
|
+
: sourceKind === FieldTypeEnum.forms && !pickerForm
|
|
455
|
+
? 'Select a form first...'
|
|
456
|
+
: 'Select data point...'
|
|
457
|
+
}
|
|
458
|
+
options={dataPointSelectOptions}
|
|
459
|
+
value={selectedDataPointSelectOption}
|
|
460
|
+
onSelectedOptionChange={handleDataPointSelect}
|
|
461
|
+
/>
|
|
439
462
|
</Flex>
|
|
440
463
|
<Flex flex={1} style={{ minWidth: 160 }}>
|
|
441
|
-
<
|
|
464
|
+
<SelectFieldSync
|
|
442
465
|
flex={1}
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
...condition,
|
|
452
|
-
operator: nextOperator,
|
|
453
|
-
...(isCheckbox
|
|
454
|
-
? {
|
|
455
|
-
value: CHECKBOX_CONDITION_VALUE,
|
|
456
|
-
valueLabel: undefined,
|
|
457
|
-
}
|
|
458
|
-
: {}),
|
|
459
|
-
});
|
|
460
|
-
}}
|
|
461
|
-
filterOptions={{ keys: ['label'] }}
|
|
462
|
-
>
|
|
463
|
-
<Combobox.SelectTrigger label="Condition" placeholder="Select..." />
|
|
464
|
-
<Combobox.Content>
|
|
465
|
-
{({ items }: { items: OperatorOption[] }) => (
|
|
466
|
-
<Combobox.List>
|
|
467
|
-
{items.map((item, i) => (
|
|
468
|
-
<Combobox.Item index={i} item={item} key={item.value}>
|
|
469
|
-
{item.label}
|
|
470
|
-
</Combobox.Item>
|
|
471
|
-
))}
|
|
472
|
-
</Combobox.List>
|
|
473
|
-
)}
|
|
474
|
-
</Combobox.Content>
|
|
475
|
-
</Combobox>
|
|
466
|
+
disableSearch
|
|
467
|
+
disableClearButton
|
|
468
|
+
label="Condition"
|
|
469
|
+
placeholder="Select..."
|
|
470
|
+
options={operatorSelectOptions}
|
|
471
|
+
value={selectedOperatorSelectOption}
|
|
472
|
+
onSelectedOptionChange={handleOperatorSelect}
|
|
473
|
+
/>
|
|
476
474
|
</Flex>
|
|
477
475
|
{!isValueLess && (
|
|
478
476
|
<Flex flex={1} style={{ minWidth: 160 }}>
|
|
479
477
|
{isRadioGroup ? (
|
|
480
|
-
<
|
|
478
|
+
<SelectFieldSync
|
|
481
479
|
flex={1}
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
480
|
+
disableSearch
|
|
481
|
+
label="Value"
|
|
482
|
+
disableClearButton
|
|
483
|
+
placeholder="Select radio option..."
|
|
484
|
+
options={radioValueOptions}
|
|
485
|
+
value={selectedRadioValue}
|
|
486
|
+
onSelectedOptionChange={(item: RadioGroupOption | null) =>
|
|
487
487
|
onChange({
|
|
488
488
|
...condition,
|
|
489
489
|
value: item?.id ?? '',
|
|
490
490
|
valueLabel: undefined,
|
|
491
491
|
})
|
|
492
492
|
}
|
|
493
|
-
|
|
494
|
-
>
|
|
495
|
-
<Combobox.SelectTrigger
|
|
496
|
-
label="Value"
|
|
497
|
-
placeholder="Select radio option..."
|
|
498
|
-
/>
|
|
499
|
-
<Combobox.Content>
|
|
500
|
-
{({ items }) => (
|
|
501
|
-
<Combobox.List>
|
|
502
|
-
{items.map((item, i) => (
|
|
503
|
-
<Combobox.Item index={i} item={item} key={item.id}>
|
|
504
|
-
{item.label}
|
|
505
|
-
</Combobox.Item>
|
|
506
|
-
))}
|
|
507
|
-
</Combobox.List>
|
|
508
|
-
)}
|
|
509
|
-
</Combobox.Content>
|
|
510
|
-
</Combobox>
|
|
493
|
+
/>
|
|
511
494
|
) : (
|
|
512
495
|
<ConditionValueControl
|
|
513
496
|
value={condition.value}
|
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
import { TextField } from '@servicetitan/anvil2';
|
|
2
|
-
import { SelectField, SelectFieldOption, SelectFieldSync } from '@servicetitan/anvil2/beta';
|
|
1
|
+
import { SelectField, SelectFieldOption, SelectFieldSync, TextField } from '@servicetitan/anvil2';
|
|
3
2
|
import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
|
|
4
3
|
import { useLookupOptions } from '../../hooks';
|
|
5
4
|
import type { LookupOption } from '../../interface/host-events';
|
|
@@ -9,48 +9,15 @@ import type {
|
|
|
9
9
|
SchemaObject,
|
|
10
10
|
} from '../../interface/types';
|
|
11
11
|
import {
|
|
12
|
-
|
|
12
|
+
applyConditionMatchType,
|
|
13
|
+
type ConditionMatchType,
|
|
14
|
+
deriveConditionMatchType,
|
|
13
15
|
getDocumentFieldsDataPointOptions,
|
|
14
16
|
getSchemaDataPointOptions,
|
|
15
|
-
|
|
17
|
+
isValidConditionGroups,
|
|
16
18
|
} from '../../utils';
|
|
17
19
|
import { ConditionGroupsSection } from './condition-groups-section';
|
|
18
20
|
|
|
19
|
-
type ConditionMatchType = 'and' | 'or';
|
|
20
|
-
|
|
21
|
-
const deriveConditionMatchType = (conditionState: DisplayConditionState): ConditionMatchType => {
|
|
22
|
-
for (let g = 0; g < conditionState.groups.length; g++) {
|
|
23
|
-
const group = conditionState.groups[g];
|
|
24
|
-
if (g > 0 && group.logicalOperator === 'or') {
|
|
25
|
-
return 'or';
|
|
26
|
-
}
|
|
27
|
-
for (let i = 1; i < group.conditions.length; i++) {
|
|
28
|
-
if (group.conditions[i]?.logicalOperator === 'or') {
|
|
29
|
-
return 'or';
|
|
30
|
-
}
|
|
31
|
-
}
|
|
32
|
-
}
|
|
33
|
-
return 'and';
|
|
34
|
-
};
|
|
35
|
-
|
|
36
|
-
const applyConditionMatchType = (
|
|
37
|
-
conditionState: DisplayConditionState,
|
|
38
|
-
matchType: ConditionMatchType,
|
|
39
|
-
): DisplayConditionState => {
|
|
40
|
-
return {
|
|
41
|
-
...conditionState,
|
|
42
|
-
groups: conditionState.groups.map((group, groupIndex) => ({
|
|
43
|
-
...group,
|
|
44
|
-
...(groupIndex > 0 ? { logicalOperator: matchType } : {}),
|
|
45
|
-
conditions: group.conditions.map((c, i) =>
|
|
46
|
-
i === 0
|
|
47
|
-
? { ...c, logicalOperator: undefined }
|
|
48
|
-
: { ...c, logicalOperator: matchType },
|
|
49
|
-
),
|
|
50
|
-
})),
|
|
51
|
-
};
|
|
52
|
-
};
|
|
53
|
-
|
|
54
21
|
const BEHAVIOR_OPTIONS = [
|
|
55
22
|
{ label: 'Show', value: 'show' },
|
|
56
23
|
{ label: 'Hide', value: 'hide' },
|
|
@@ -159,32 +126,15 @@ export function DisplayConditionModal({
|
|
|
159
126
|
setState(prev => applyConditionMatchType(prev, value));
|
|
160
127
|
}, []);
|
|
161
128
|
|
|
162
|
-
const canSave = useMemo(
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
const trimmedValue = condition.value.trim();
|
|
172
|
-
if (!trimmedValue) {
|
|
173
|
-
return false;
|
|
174
|
-
}
|
|
175
|
-
const fieldType = getDisplayConditionFieldTypeForKey(
|
|
176
|
-
condition.dataPointKey,
|
|
177
|
-
mergeTagOptions,
|
|
178
|
-
fillableOptions,
|
|
179
|
-
formFieldsByFormId ?? {},
|
|
180
|
-
);
|
|
181
|
-
if (fieldType === 'number' && !isValidNumber(trimmedValue)) {
|
|
182
|
-
return false;
|
|
183
|
-
}
|
|
184
|
-
}
|
|
185
|
-
}
|
|
186
|
-
return state.groups.length > 0;
|
|
187
|
-
}, [fillableOptions, formFieldsByFormId, mergeTagOptions, state.groups]);
|
|
129
|
+
const canSave = useMemo(
|
|
130
|
+
() =>
|
|
131
|
+
isValidConditionGroups(state.groups, {
|
|
132
|
+
fillableOptions,
|
|
133
|
+
formFieldsByFormId,
|
|
134
|
+
mergeTagOptions,
|
|
135
|
+
}),
|
|
136
|
+
[fillableOptions, formFieldsByFormId, mergeTagOptions, state.groups],
|
|
137
|
+
);
|
|
188
138
|
|
|
189
139
|
return (
|
|
190
140
|
<Dialog open onClose={handleClose} size="xlarge">
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
import { Button, Flex, Text } from '@servicetitan/anvil2';
|
|
2
|
+
import EditIcon from '@servicetitan/anvil2/assets/icons/material/round/edit.svg';
|
|
3
|
+
import { FC, useMemo } from 'react';
|
|
4
|
+
import {
|
|
5
|
+
CHECKBOX_OPERATORS,
|
|
6
|
+
type ConditionOperator,
|
|
7
|
+
type DisplayConditionSingle,
|
|
8
|
+
type ESignDateSignedOffsetSettingsRule,
|
|
9
|
+
NUMBER_OPERATORS,
|
|
10
|
+
type PdfField,
|
|
11
|
+
RADIO_OPERATORS,
|
|
12
|
+
type SchemaObject,
|
|
13
|
+
STRING_OPERATORS,
|
|
14
|
+
VALUE_LESS_OPERATORS,
|
|
15
|
+
} from '../../interface/types';
|
|
16
|
+
import { getDataPointOptions } from '../../utils';
|
|
17
|
+
|
|
18
|
+
const ALL_OPERATORS = [
|
|
19
|
+
...NUMBER_OPERATORS,
|
|
20
|
+
...STRING_OPERATORS,
|
|
21
|
+
...RADIO_OPERATORS,
|
|
22
|
+
...CHECKBOX_OPERATORS,
|
|
23
|
+
];
|
|
24
|
+
|
|
25
|
+
const getOperatorSymbol = (operator: string): string =>
|
|
26
|
+
ALL_OPERATORS.find(op => op.value === operator)?.label.split(' (')[0] ?? operator;
|
|
27
|
+
|
|
28
|
+
export interface ESignDateRulesSummaryProps {
|
|
29
|
+
elseDays: number;
|
|
30
|
+
rulesWithConditions: ESignDateSignedOffsetSettingsRule[];
|
|
31
|
+
schema?: SchemaObject;
|
|
32
|
+
documentFields?: PdfField[];
|
|
33
|
+
onEdit: () => void;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export const ESignDateRulesSummary: FC<ESignDateRulesSummaryProps> = ({
|
|
37
|
+
documentFields,
|
|
38
|
+
elseDays,
|
|
39
|
+
onEdit,
|
|
40
|
+
rulesWithConditions,
|
|
41
|
+
schema,
|
|
42
|
+
}) => {
|
|
43
|
+
const dataPointOptions = useMemo(
|
|
44
|
+
() => getDataPointOptions(schema, documentFields),
|
|
45
|
+
[schema, documentFields],
|
|
46
|
+
);
|
|
47
|
+
|
|
48
|
+
const getConditionText = (condition: DisplayConditionSingle) => {
|
|
49
|
+
const dataPoint = dataPointOptions.find(
|
|
50
|
+
option => option.fullKey === condition.dataPointKey,
|
|
51
|
+
);
|
|
52
|
+
const label = dataPoint?.title ?? condition.dataPointKey;
|
|
53
|
+
const symbol = getOperatorSymbol(condition.operator).replace('==', '=');
|
|
54
|
+
const isValueLess =
|
|
55
|
+
dataPoint?.isCheckbox === true ||
|
|
56
|
+
VALUE_LESS_OPERATORS.includes(condition.operator as ConditionOperator);
|
|
57
|
+
const value = condition.valueLabel ?? condition.value;
|
|
58
|
+
|
|
59
|
+
return `${label} ${symbol}${isValueLess ? '' : ` ${value}`}`;
|
|
60
|
+
};
|
|
61
|
+
|
|
62
|
+
return (
|
|
63
|
+
<Flex direction="column" gap="1">
|
|
64
|
+
<Flex justifyContent="space-between" alignItems="center">
|
|
65
|
+
<Text variant="body" size="medium" style={{ fontWeight: 500 }}>
|
|
66
|
+
Calculated date rules
|
|
67
|
+
</Text>
|
|
68
|
+
<Button
|
|
69
|
+
appearance="ghost"
|
|
70
|
+
size="small"
|
|
71
|
+
icon={{ before: EditIcon }}
|
|
72
|
+
onClick={onEdit}
|
|
73
|
+
>
|
|
74
|
+
Edit
|
|
75
|
+
</Button>
|
|
76
|
+
</Flex>
|
|
77
|
+
<Flex direction="column" gap="2" className="dte-rule-card --active">
|
|
78
|
+
{rulesWithConditions.map((rule, index) => {
|
|
79
|
+
const condition = rule.condition.groups[0]?.conditions[0];
|
|
80
|
+
return (
|
|
81
|
+
<Flex key={rule.condition.groups[0]?.id ?? index} direction="column">
|
|
82
|
+
<Text variant="body">{rule.days} After Signing When:</Text>
|
|
83
|
+
{condition && (
|
|
84
|
+
<Text
|
|
85
|
+
variant="body"
|
|
86
|
+
size="small"
|
|
87
|
+
style={{
|
|
88
|
+
color: '#422799',
|
|
89
|
+
}}
|
|
90
|
+
>
|
|
91
|
+
{getConditionText(condition)}
|
|
92
|
+
</Text>
|
|
93
|
+
)}
|
|
94
|
+
</Flex>
|
|
95
|
+
);
|
|
96
|
+
})}
|
|
97
|
+
<Flex direction="column">
|
|
98
|
+
<Text variant="body" size="medium">
|
|
99
|
+
{elseDays} After Signing When:
|
|
100
|
+
</Text>
|
|
101
|
+
<Text
|
|
102
|
+
variant="body"
|
|
103
|
+
size="small"
|
|
104
|
+
style={{
|
|
105
|
+
color: '#422799',
|
|
106
|
+
}}
|
|
107
|
+
>
|
|
108
|
+
ELSE
|
|
109
|
+
</Text>
|
|
110
|
+
</Flex>
|
|
111
|
+
</Flex>
|
|
112
|
+
</Flex>
|
|
113
|
+
);
|
|
114
|
+
};
|