@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
|
@@ -0,0 +1,197 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Why not `DisplayConditionModal`:
|
|
3
|
+
*
|
|
4
|
+
* `DisplayConditionModal` manages exactly one `DisplayConditionState` (a show/hide behavior
|
|
5
|
+
* toggle plus a list of condition groups) for a single field. `ESignDateSignedOffsetSettings` is
|
|
6
|
+
* a different shape entirely: a *list* of independent `{ days, condition }` rules, with no
|
|
7
|
+
* show/hide concept at all (`ESignDateSignedOffsetSettingsRule.condition` is "only show" by
|
|
8
|
+
* contract). The trailing, condition-less "else" row required by that settings type is owned by
|
|
9
|
+
* `ESignOptionsModal` (its own always-visible "Day offset" field) — this modal only ever manages
|
|
10
|
+
* the conditioned rules that precede it.
|
|
11
|
+
*
|
|
12
|
+
* Instead, this modal follows the same Dialog/Header/Content/Footer structure and reuses the same
|
|
13
|
+
* building blocks `DisplayConditionModal` is built from: `ConditionGroup`/`ConditionRow` for the
|
|
14
|
+
* condition-editing UI, `getSchemaDataPointOptions`/`getDocumentFieldsDataPointOptions` for
|
|
15
|
+
* data-point resolution, and `isValidConditionGroups` extracted from `DisplayConditionModal`.
|
|
16
|
+
* Nothing ESign-specific was added to any of those shared pieces.
|
|
17
|
+
*/
|
|
18
|
+
import { Button, Chip, Dialog, Flex, NumberField, Text } from '@servicetitan/anvil2';
|
|
19
|
+
import PlusCircleIcon from '@servicetitan/anvil2/assets/icons/material/round/add_circle.svg';
|
|
20
|
+
import { FC, useCallback, useMemo, useState } from 'react';
|
|
21
|
+
import { MODAL_CONTENT_MAX_HEIGHT } from '../../constants';
|
|
22
|
+
import type {
|
|
23
|
+
ESignDateSignedOffsetSettingsFinalRule,
|
|
24
|
+
ESignDateSignedOffsetSettingsRule,
|
|
25
|
+
FormFieldsByFormIdI,
|
|
26
|
+
FormInfo,
|
|
27
|
+
PdfField,
|
|
28
|
+
SchemaObject,
|
|
29
|
+
} from '../../interface/types';
|
|
30
|
+
import {
|
|
31
|
+
addESignOffsetRule,
|
|
32
|
+
canAddESignOffsetRule,
|
|
33
|
+
createESignOffsetRule,
|
|
34
|
+
getDocumentFieldsDataPointOptions,
|
|
35
|
+
getSchemaDataPointOptions,
|
|
36
|
+
isValidConditionGroups,
|
|
37
|
+
updateESignOffsetRule,
|
|
38
|
+
} from '../../utils';
|
|
39
|
+
import { ESignOffsetRuleRow } from './e-sign-offset-rule-row';
|
|
40
|
+
|
|
41
|
+
export interface ESignDateSignedOffsetModalProps {
|
|
42
|
+
onClose: () => void;
|
|
43
|
+
onSave: (
|
|
44
|
+
state: ESignDateSignedOffsetSettingsRule[],
|
|
45
|
+
finalRule: ESignDateSignedOffsetSettingsFinalRule,
|
|
46
|
+
) => void;
|
|
47
|
+
initialState: ESignDateSignedOffsetSettingsRule[];
|
|
48
|
+
finalRule: ESignDateSignedOffsetSettingsFinalRule;
|
|
49
|
+
schema?: SchemaObject;
|
|
50
|
+
documentFields?: PdfField[];
|
|
51
|
+
forms?: FormInfo[];
|
|
52
|
+
formFieldsByFormId?: FormFieldsByFormIdI;
|
|
53
|
+
onRequestFormFields?: (formId: number) => void;
|
|
54
|
+
formFieldsLoadingFormId?: number | null;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
export const ESignDateSignedOffsetModal: FC<ESignDateSignedOffsetModalProps> = ({
|
|
58
|
+
documentFields,
|
|
59
|
+
finalRule,
|
|
60
|
+
formFieldsByFormId,
|
|
61
|
+
formFieldsLoadingFormId,
|
|
62
|
+
forms,
|
|
63
|
+
initialState,
|
|
64
|
+
onClose,
|
|
65
|
+
onRequestFormFields,
|
|
66
|
+
onSave,
|
|
67
|
+
schema,
|
|
68
|
+
}) => {
|
|
69
|
+
const [rules, setRules] = useState<ESignDateSignedOffsetSettingsRule[]>(
|
|
70
|
+
initialState.length === 0 ? [createESignOffsetRule()] : initialState,
|
|
71
|
+
);
|
|
72
|
+
const [finalRuleDays, setFinalRuleDays] = useState<number>(finalRule.days);
|
|
73
|
+
|
|
74
|
+
const mergeTagOptions = useMemo(() => getSchemaDataPointOptions(schema), [schema]);
|
|
75
|
+
|
|
76
|
+
const fillableOptions = useMemo(
|
|
77
|
+
() => getDocumentFieldsDataPointOptions(documentFields),
|
|
78
|
+
[documentFields],
|
|
79
|
+
);
|
|
80
|
+
|
|
81
|
+
const handleClose = useCallback(() => onClose(), [onClose]);
|
|
82
|
+
|
|
83
|
+
const handleSave = useCallback(() => {
|
|
84
|
+
onSave(rules, { days: finalRuleDays });
|
|
85
|
+
onClose();
|
|
86
|
+
}, [finalRuleDays, onClose, onSave, rules]);
|
|
87
|
+
|
|
88
|
+
const handleFinalRuleDaysChange = useCallback((days: number | null) => {
|
|
89
|
+
setFinalRuleDays(Math.max(Math.min(365, days ?? 0), 0));
|
|
90
|
+
}, []);
|
|
91
|
+
|
|
92
|
+
const handleAddRule = useCallback(() => {
|
|
93
|
+
setRules(prev => addESignOffsetRule(prev));
|
|
94
|
+
}, []);
|
|
95
|
+
|
|
96
|
+
const handleRemoveRule = useCallback((index: number) => {
|
|
97
|
+
setRules(prev => prev.filter((_, i) => i !== index));
|
|
98
|
+
}, []);
|
|
99
|
+
|
|
100
|
+
const handleUpdateRule = useCallback(
|
|
101
|
+
(index: number, rule: ESignDateSignedOffsetSettingsRule) => {
|
|
102
|
+
setRules(prev => updateESignOffsetRule(prev, index, rule));
|
|
103
|
+
},
|
|
104
|
+
[],
|
|
105
|
+
);
|
|
106
|
+
|
|
107
|
+
const canSave = useMemo(
|
|
108
|
+
() =>
|
|
109
|
+
rules.every(rule =>
|
|
110
|
+
isValidConditionGroups(rule.condition.groups, {
|
|
111
|
+
fillableOptions,
|
|
112
|
+
formFieldsByFormId,
|
|
113
|
+
mergeTagOptions,
|
|
114
|
+
}),
|
|
115
|
+
),
|
|
116
|
+
[fillableOptions, formFieldsByFormId, mergeTagOptions, rules],
|
|
117
|
+
);
|
|
118
|
+
|
|
119
|
+
return (
|
|
120
|
+
<Dialog open onClose={handleClose} size="xlarge">
|
|
121
|
+
<Dialog.Header>Date Signed Offset Rules</Dialog.Header>
|
|
122
|
+
<Dialog.Content>
|
|
123
|
+
<Flex
|
|
124
|
+
direction="column"
|
|
125
|
+
gap="4"
|
|
126
|
+
flex={1}
|
|
127
|
+
style={{
|
|
128
|
+
maxHeight: MODAL_CONTENT_MAX_HEIGHT,
|
|
129
|
+
overflowY: 'auto',
|
|
130
|
+
}}
|
|
131
|
+
>
|
|
132
|
+
{rules.length === 0 && (
|
|
133
|
+
<Flex justifyContent="center" alignItems="center">
|
|
134
|
+
<Text variant="body" size="xlarge" subdued>
|
|
135
|
+
Rule not configured yet.
|
|
136
|
+
</Text>
|
|
137
|
+
</Flex>
|
|
138
|
+
)}
|
|
139
|
+
|
|
140
|
+
{rules.map((rule, index) => (
|
|
141
|
+
<ESignOffsetRuleRow
|
|
142
|
+
key={rule.condition.groups[0]?.id ?? index}
|
|
143
|
+
onDelete={() => handleRemoveRule(index)}
|
|
144
|
+
fillableOptions={fillableOptions}
|
|
145
|
+
formFieldsByFormId={formFieldsByFormId}
|
|
146
|
+
formFieldsLoadingFormId={formFieldsLoadingFormId}
|
|
147
|
+
forms={forms}
|
|
148
|
+
mergeTagOptions={mergeTagOptions}
|
|
149
|
+
onChange={next => handleUpdateRule(index, next)}
|
|
150
|
+
onRequestFormFields={onRequestFormFields}
|
|
151
|
+
rule={rule}
|
|
152
|
+
canRemove={rules.length > 1}
|
|
153
|
+
/>
|
|
154
|
+
))}
|
|
155
|
+
<Button
|
|
156
|
+
size="small"
|
|
157
|
+
appearance="ghost"
|
|
158
|
+
icon={{ before: PlusCircleIcon }}
|
|
159
|
+
onClick={handleAddRule}
|
|
160
|
+
disabled={!canAddESignOffsetRule(rules)}
|
|
161
|
+
>
|
|
162
|
+
Add Else Condition
|
|
163
|
+
</Button>
|
|
164
|
+
|
|
165
|
+
<Flex className="dte-rule-card">
|
|
166
|
+
<Flex
|
|
167
|
+
alignItems="center"
|
|
168
|
+
style={{
|
|
169
|
+
padding: '8px 12px',
|
|
170
|
+
}}
|
|
171
|
+
>
|
|
172
|
+
<Chip label="THEN" size="medium" />
|
|
173
|
+
</Flex>
|
|
174
|
+
<Flex direction="column" gap="1">
|
|
175
|
+
<NumberField
|
|
176
|
+
size="small"
|
|
177
|
+
label="Number of days"
|
|
178
|
+
value={finalRuleDays}
|
|
179
|
+
onChange={handleFinalRuleDaysChange}
|
|
180
|
+
suffix="days"
|
|
181
|
+
/>
|
|
182
|
+
<Text variant="body" size="small" subdued>
|
|
183
|
+
days range up to 365
|
|
184
|
+
</Text>
|
|
185
|
+
</Flex>
|
|
186
|
+
</Flex>
|
|
187
|
+
</Flex>
|
|
188
|
+
</Dialog.Content>
|
|
189
|
+
<Dialog.Footer sticky>
|
|
190
|
+
<Dialog.CancelButton onClick={handleClose}>Cancel</Dialog.CancelButton>
|
|
191
|
+
<Button appearance="primary" disabled={!canSave} onClick={handleSave}>
|
|
192
|
+
Save Changes
|
|
193
|
+
</Button>
|
|
194
|
+
</Dialog.Footer>
|
|
195
|
+
</Dialog>
|
|
196
|
+
);
|
|
197
|
+
};
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
import { Chip, Flex, NumberField, Text } from '@servicetitan/anvil2';
|
|
2
|
+
import { FC } from 'react';
|
|
3
|
+
import { defaultCondition, defaultGroup } from '../../constants';
|
|
4
|
+
import type {
|
|
5
|
+
DataPointOption,
|
|
6
|
+
ESignDateSignedOffsetSettingsRule,
|
|
7
|
+
FormFieldsByFormIdI,
|
|
8
|
+
FormInfo,
|
|
9
|
+
} from '../../interface/types';
|
|
10
|
+
import { ConditionRow } from '../display-conditions/condition-row';
|
|
11
|
+
|
|
12
|
+
export interface ESignOffsetRuleRowProps {
|
|
13
|
+
canRemove: boolean;
|
|
14
|
+
rule: ESignDateSignedOffsetSettingsRule;
|
|
15
|
+
onChange: (rule: ESignDateSignedOffsetSettingsRule) => void;
|
|
16
|
+
onDelete: () => void;
|
|
17
|
+
fillableOptions: DataPointOption[];
|
|
18
|
+
mergeTagOptions: DataPointOption[];
|
|
19
|
+
forms?: FormInfo[];
|
|
20
|
+
formFieldsByFormId?: FormFieldsByFormIdI;
|
|
21
|
+
onRequestFormFields?: (formId: number) => void;
|
|
22
|
+
formFieldsLoadingFormId?: number | null;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export const ESignOffsetRuleRow: FC<ESignOffsetRuleRowProps> = ({
|
|
26
|
+
canRemove,
|
|
27
|
+
fillableOptions,
|
|
28
|
+
formFieldsByFormId,
|
|
29
|
+
formFieldsLoadingFormId,
|
|
30
|
+
forms,
|
|
31
|
+
mergeTagOptions,
|
|
32
|
+
onChange,
|
|
33
|
+
onDelete,
|
|
34
|
+
onRequestFormFields,
|
|
35
|
+
rule,
|
|
36
|
+
}) => {
|
|
37
|
+
const handleDaysChange = (days: number | null) => {
|
|
38
|
+
onChange({ ...rule, days: days ?? 0 });
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
const group = rule.condition.groups[0];
|
|
42
|
+
const condition = group?.conditions[0] ?? defaultCondition();
|
|
43
|
+
|
|
44
|
+
const handleConditionChange = (nextCondition: typeof condition) => {
|
|
45
|
+
onChange({
|
|
46
|
+
...rule,
|
|
47
|
+
condition: {
|
|
48
|
+
...rule.condition,
|
|
49
|
+
groups: [{ ...(group ?? defaultGroup()), conditions: [nextCondition] }],
|
|
50
|
+
},
|
|
51
|
+
});
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
return (
|
|
55
|
+
<Flex direction="column" gap="3" className="dte-rule-card">
|
|
56
|
+
<ConditionRow
|
|
57
|
+
canRemove={canRemove}
|
|
58
|
+
condition={condition}
|
|
59
|
+
fillableOptions={fillableOptions}
|
|
60
|
+
formFieldsByFormId={formFieldsByFormId}
|
|
61
|
+
formFieldsLoadingFormId={formFieldsLoadingFormId}
|
|
62
|
+
forms={forms}
|
|
63
|
+
mergeTagOptions={mergeTagOptions}
|
|
64
|
+
onChange={handleConditionChange}
|
|
65
|
+
onRemove={onDelete}
|
|
66
|
+
onRequestFormFields={onRequestFormFields}
|
|
67
|
+
/>
|
|
68
|
+
<Flex>
|
|
69
|
+
<Flex
|
|
70
|
+
alignItems="center"
|
|
71
|
+
style={{
|
|
72
|
+
padding: '8px 12px',
|
|
73
|
+
}}
|
|
74
|
+
>
|
|
75
|
+
<Chip label="THEN" size="medium" />
|
|
76
|
+
</Flex>
|
|
77
|
+
<Flex direction="column" gap="1">
|
|
78
|
+
<NumberField
|
|
79
|
+
label="Number of days"
|
|
80
|
+
value={rule.days}
|
|
81
|
+
onChange={handleDaysChange}
|
|
82
|
+
suffix="days"
|
|
83
|
+
/>
|
|
84
|
+
<Text variant="body" size="small" subdued>
|
|
85
|
+
days range up to 365
|
|
86
|
+
</Text>
|
|
87
|
+
</Flex>
|
|
88
|
+
</Flex>
|
|
89
|
+
</Flex>
|
|
90
|
+
);
|
|
91
|
+
};
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
import { Button, Flex, NumberField } from '@servicetitan/anvil2';
|
|
2
|
+
import AddIcon from '@servicetitan/anvil2/assets/icons/material/round/add_circle.svg';
|
|
3
|
+
import { FC, Fragment, useState } from 'react';
|
|
4
|
+
import {
|
|
5
|
+
ESignDateSignedOffsetSettings,
|
|
6
|
+
ESignDateSignedOffsetSettingsFinalRule,
|
|
7
|
+
ESignDateSignedOffsetSettingsRule,
|
|
8
|
+
FormFieldsByFormIdI,
|
|
9
|
+
FormInfo,
|
|
10
|
+
PdfField,
|
|
11
|
+
SchemaObject,
|
|
12
|
+
} from '../../interface/types';
|
|
13
|
+
import { ESignDateRulesSummary } from './e-sign-date-rules-summary';
|
|
14
|
+
import { ESignDateSignedOffsetModal } from './e-sign-date-signed-offset-modal';
|
|
15
|
+
|
|
16
|
+
interface ESignOptionsModalProps {
|
|
17
|
+
initialState: ESignDateSignedOffsetSettings;
|
|
18
|
+
onSave: (state: ESignDateSignedOffsetSettings) => void;
|
|
19
|
+
schema?: SchemaObject;
|
|
20
|
+
documentFields?: PdfField[];
|
|
21
|
+
forms?: FormInfo[];
|
|
22
|
+
formFieldsByFormId?: FormFieldsByFormIdI;
|
|
23
|
+
onRequestFormFields?: (formId: number) => void;
|
|
24
|
+
formFieldsLoadingFormId?: number | null;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export const ESignOptionsModal: FC<ESignOptionsModalProps> = ({
|
|
28
|
+
documentFields,
|
|
29
|
+
formFieldsByFormId,
|
|
30
|
+
formFieldsLoadingFormId,
|
|
31
|
+
forms,
|
|
32
|
+
initialState,
|
|
33
|
+
onRequestFormFields,
|
|
34
|
+
onSave,
|
|
35
|
+
schema,
|
|
36
|
+
}) => {
|
|
37
|
+
const [open, setOpen] = useState(false);
|
|
38
|
+
/*
|
|
39
|
+
* `rules` is a tuple: zero or more conditioned rules followed by exactly one condition-less
|
|
40
|
+
* final rule (enforced by `ESignDateSignedOffsetSettings['rules']`). Slicing/indexing a
|
|
41
|
+
* variadic tuple widens to the member union, so the split needs one explicit, deliberate cast.
|
|
42
|
+
*/
|
|
43
|
+
const ruleWithOutCondition = initialState.rules[
|
|
44
|
+
initialState.rules.length - 1
|
|
45
|
+
] as ESignDateSignedOffsetSettingsFinalRule;
|
|
46
|
+
const rulesWithConditions = initialState.rules.slice(
|
|
47
|
+
0,
|
|
48
|
+
-1,
|
|
49
|
+
) as ESignDateSignedOffsetSettingsRule[];
|
|
50
|
+
|
|
51
|
+
const handleDaysChange = (days: number | null) => {
|
|
52
|
+
onSave({
|
|
53
|
+
rules: [...rulesWithConditions, { days: Math.max(Math.min(365, days ?? 0), 0) }],
|
|
54
|
+
});
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
const handleSaveRules = (
|
|
58
|
+
rules: ESignDateSignedOffsetSettingsRule[],
|
|
59
|
+
finalRule: ESignDateSignedOffsetSettingsFinalRule,
|
|
60
|
+
) => {
|
|
61
|
+
onSave({ rules: [...rules, finalRule] });
|
|
62
|
+
};
|
|
63
|
+
|
|
64
|
+
return (
|
|
65
|
+
<Fragment>
|
|
66
|
+
{rulesWithConditions.length === 0 ? (
|
|
67
|
+
<Flex gap={1} direction="column" justifyContent="space-between">
|
|
68
|
+
<NumberField
|
|
69
|
+
size="small"
|
|
70
|
+
label="Number of days"
|
|
71
|
+
value={ruleWithOutCondition.days}
|
|
72
|
+
onChange={handleDaysChange}
|
|
73
|
+
suffix="days"
|
|
74
|
+
width="100%"
|
|
75
|
+
/>
|
|
76
|
+
|
|
77
|
+
<Button
|
|
78
|
+
appearance="ghost"
|
|
79
|
+
size="small"
|
|
80
|
+
icon={AddIcon}
|
|
81
|
+
onClick={() => setOpen(true)}
|
|
82
|
+
style={{ color: '#0265DC' }}
|
|
83
|
+
>
|
|
84
|
+
Set Date Rule
|
|
85
|
+
</Button>
|
|
86
|
+
</Flex>
|
|
87
|
+
) : (
|
|
88
|
+
<ESignDateRulesSummary
|
|
89
|
+
documentFields={documentFields}
|
|
90
|
+
onEdit={() => setOpen(true)}
|
|
91
|
+
rulesWithConditions={rulesWithConditions}
|
|
92
|
+
schema={schema}
|
|
93
|
+
elseDays={ruleWithOutCondition.days}
|
|
94
|
+
/>
|
|
95
|
+
)}
|
|
96
|
+
{open && (
|
|
97
|
+
<ESignDateSignedOffsetModal
|
|
98
|
+
onClose={() => setOpen(false)}
|
|
99
|
+
onSave={handleSaveRules}
|
|
100
|
+
documentFields={documentFields}
|
|
101
|
+
finalRule={ruleWithOutCondition}
|
|
102
|
+
formFieldsByFormId={formFieldsByFormId}
|
|
103
|
+
formFieldsLoadingFormId={formFieldsLoadingFormId}
|
|
104
|
+
forms={forms}
|
|
105
|
+
initialState={rulesWithConditions}
|
|
106
|
+
onRequestFormFields={onRequestFormFields}
|
|
107
|
+
schema={schema}
|
|
108
|
+
/>
|
|
109
|
+
)}
|
|
110
|
+
</Fragment>
|
|
111
|
+
);
|
|
112
|
+
};
|
|
@@ -1,7 +1,8 @@
|
|
|
1
|
-
import { Button, Checkbox,
|
|
1
|
+
import { Button, Checkbox, Flex, SelectFieldSync, Textarea, TextField } from '@servicetitan/anvil2';
|
|
2
2
|
import { FC, useMemo } from 'react';
|
|
3
|
-
import {
|
|
3
|
+
import { FIELD_FONT_SIZE_OPTIONS } from '../../constants';
|
|
4
4
|
import {
|
|
5
|
+
ESignDateSignedOffsetSettings,
|
|
5
6
|
ESignFieldType,
|
|
6
7
|
FieldTypeEnum,
|
|
7
8
|
type FormFieldsByFormIdI,
|
|
@@ -19,6 +20,7 @@ import {
|
|
|
19
20
|
supportsFieldFontSize,
|
|
20
21
|
} from '../../utils';
|
|
21
22
|
import { DisplayCondition } from '../display-conditions/display-condition';
|
|
23
|
+
import { ESignOptionsModal } from './e-sign-options-modal';
|
|
22
24
|
import { FormulaGenerator } from './formula-generator';
|
|
23
25
|
import { TableConfigs } from './table-configs';
|
|
24
26
|
|
|
@@ -56,39 +58,53 @@ export const FieldConfigPanel: FC<FieldConfigPanelProps> = ({
|
|
|
56
58
|
}) => {
|
|
57
59
|
const recipientOptions = useMemo(
|
|
58
60
|
() =>
|
|
59
|
-
field.type === FieldTypeEnum.fillable
|
|
61
|
+
(field.type === FieldTypeEnum.fillable
|
|
60
62
|
? getFillableFieldsRecipients(recipients)
|
|
61
|
-
: recipients
|
|
63
|
+
: recipients
|
|
64
|
+
).map(recipient => ({ id: recipient.name, label: recipient.displayName })),
|
|
62
65
|
[recipients, field.type],
|
|
63
66
|
);
|
|
64
67
|
|
|
65
68
|
const selectedRecipient = useMemo(
|
|
66
|
-
() => recipientOptions.find(
|
|
69
|
+
() => recipientOptions.find(option => option.id === field.recipient) ?? null,
|
|
67
70
|
[recipientOptions, field.recipient],
|
|
68
71
|
);
|
|
69
72
|
|
|
70
73
|
const isRadioGroupSibling = (documentField: PdfField) =>
|
|
71
74
|
documentField.subType === 'radio' && documentField.path === field.path;
|
|
72
75
|
|
|
73
|
-
const
|
|
76
|
+
const isDateSignedOffsetSibling = (documentField: PdfField) =>
|
|
77
|
+
documentField.type === FieldTypeEnum.eSign &&
|
|
78
|
+
documentField.subType === ESignFieldType.dateSignedOffset;
|
|
79
|
+
|
|
80
|
+
const handleDateSignedOffsetSave = (data: ESignDateSignedOffsetSettings) => {
|
|
81
|
+
if (onMatchingFieldsConfigChange) {
|
|
82
|
+
onMatchingFieldsConfigChange(isDateSignedOffsetSibling, { data });
|
|
83
|
+
return;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
onFieldConfigChange({ data });
|
|
87
|
+
};
|
|
88
|
+
|
|
89
|
+
const handleRecipientChange = (item: { id: string; label: string } | null) => {
|
|
74
90
|
if (!item) {
|
|
75
91
|
return;
|
|
76
92
|
}
|
|
77
93
|
|
|
78
94
|
let path = field.path;
|
|
79
95
|
if (field.type === FieldTypeEnum.eSign) {
|
|
80
|
-
path = generateESignPath(item.
|
|
96
|
+
path = generateESignPath(item.id, field.subType as ESignFieldType);
|
|
81
97
|
}
|
|
82
98
|
if (field.type === FieldTypeEnum.fillable) {
|
|
83
99
|
const pathName =
|
|
84
100
|
field.subType === 'radio' && field.path
|
|
85
101
|
? parseFillablePathName(field.path)
|
|
86
102
|
: field.id;
|
|
87
|
-
path = generateFillablePath(item.
|
|
103
|
+
path = generateFillablePath(item.id, pathName);
|
|
88
104
|
}
|
|
89
105
|
|
|
90
106
|
const updates = {
|
|
91
|
-
recipient: item.
|
|
107
|
+
recipient: item.id,
|
|
92
108
|
path,
|
|
93
109
|
};
|
|
94
110
|
|
|
@@ -105,31 +121,25 @@ export const FieldConfigPanel: FC<FieldConfigPanelProps> = ({
|
|
|
105
121
|
onFieldConfigChange(updates);
|
|
106
122
|
};
|
|
107
123
|
|
|
108
|
-
const
|
|
109
|
-
() => E_SIGN_FIELD_TYPE_OPTIONS.find(option => option.id === field.subType) ?? null,
|
|
110
|
-
[field],
|
|
111
|
-
);
|
|
124
|
+
const showFontSizeControl = supportsFieldFontSize(field);
|
|
112
125
|
|
|
113
|
-
const
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
path: generateESignPath(field.recipient!, item.id),
|
|
118
|
-
});
|
|
119
|
-
}
|
|
120
|
-
};
|
|
126
|
+
const fontSizeOptions = useMemo(
|
|
127
|
+
() => FIELD_FONT_SIZE_OPTIONS.map(size => ({ id: size, label: size.toString() })),
|
|
128
|
+
[],
|
|
129
|
+
);
|
|
121
130
|
|
|
122
|
-
const
|
|
131
|
+
const selectedFontSize = useMemo(
|
|
132
|
+
() => fontSizeOptions.find(option => option.id === getFieldFontSize(field)) ?? null,
|
|
133
|
+
[fontSizeOptions, field],
|
|
134
|
+
);
|
|
123
135
|
|
|
124
|
-
const handleFontSizeChange = (item: number
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
styles
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
});
|
|
132
|
-
}
|
|
136
|
+
const handleFontSizeChange = (item: { id: number; label: string }) => {
|
|
137
|
+
onFieldConfigChange({
|
|
138
|
+
styles: {
|
|
139
|
+
...field.styles,
|
|
140
|
+
fontSize: item.id,
|
|
141
|
+
},
|
|
142
|
+
});
|
|
133
143
|
};
|
|
134
144
|
|
|
135
145
|
const handleRadioGroupNameChange = (groupName: string) => {
|
|
@@ -184,47 +194,14 @@ export const FieldConfigPanel: FC<FieldConfigPanelProps> = ({
|
|
|
184
194
|
/>
|
|
185
195
|
)}
|
|
186
196
|
{(field.type === FieldTypeEnum.fillable || field.type === FieldTypeEnum.eSign) && (
|
|
187
|
-
<
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
<Combobox.Content>
|
|
196
|
-
{({ items }) => (
|
|
197
|
-
<Combobox.List>
|
|
198
|
-
{items.map((item, i) => (
|
|
199
|
-
<Combobox.Item key={item.name} item={item} index={i}>
|
|
200
|
-
{item.displayName}
|
|
201
|
-
</Combobox.Item>
|
|
202
|
-
))}
|
|
203
|
-
</Combobox.List>
|
|
204
|
-
)}
|
|
205
|
-
</Combobox.Content>
|
|
206
|
-
</Combobox>
|
|
207
|
-
)}
|
|
208
|
-
{field.type === FieldTypeEnum.eSign && (
|
|
209
|
-
<Combobox
|
|
210
|
-
items={E_SIGN_FIELD_TYPE_OPTIONS}
|
|
211
|
-
itemToString={item => item?.name ?? ''}
|
|
212
|
-
onChange={handleESignFieldTypeChange}
|
|
213
|
-
selectedItem={selectedESignFieldType}
|
|
214
|
-
>
|
|
215
|
-
<Combobox.SearchField label="Field Type" />
|
|
216
|
-
<Combobox.Content>
|
|
217
|
-
{({ items }) => (
|
|
218
|
-
<Combobox.List>
|
|
219
|
-
{items.map((item, i) => (
|
|
220
|
-
<Combobox.Item key={item.id} item={item} index={i}>
|
|
221
|
-
{item.name}
|
|
222
|
-
</Combobox.Item>
|
|
223
|
-
))}
|
|
224
|
-
</Combobox.List>
|
|
225
|
-
)}
|
|
226
|
-
</Combobox.Content>
|
|
227
|
-
</Combobox>
|
|
197
|
+
<SelectFieldSync
|
|
198
|
+
label="Recipient"
|
|
199
|
+
disableClearButton
|
|
200
|
+
options={recipientOptions}
|
|
201
|
+
value={selectedRecipient}
|
|
202
|
+
onSelectedOptionChange={handleRecipientChange}
|
|
203
|
+
filter={{ keys: ['label'] }}
|
|
204
|
+
/>
|
|
228
205
|
)}
|
|
229
206
|
{field.type !== FieldTypeEnum.generic && (
|
|
230
207
|
<TextField label="Data Path" value={field.path} disabled />
|
|
@@ -271,31 +248,33 @@ export const FieldConfigPanel: FC<FieldConfigPanelProps> = ({
|
|
|
271
248
|
)}
|
|
272
249
|
|
|
273
250
|
{showFontSizeControl && (
|
|
274
|
-
<
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
<Combobox.Content>
|
|
282
|
-
{({ items }) => (
|
|
283
|
-
<Combobox.List>
|
|
284
|
-
{items.map((item, i) => (
|
|
285
|
-
<Combobox.Item key={item} item={item} index={i}>
|
|
286
|
-
{item}
|
|
287
|
-
</Combobox.Item>
|
|
288
|
-
))}
|
|
289
|
-
</Combobox.List>
|
|
290
|
-
)}
|
|
291
|
-
</Combobox.Content>
|
|
292
|
-
</Combobox>
|
|
251
|
+
<SelectFieldSync
|
|
252
|
+
label="Font Size"
|
|
253
|
+
disableClearButton
|
|
254
|
+
options={fontSizeOptions}
|
|
255
|
+
value={selectedFontSize}
|
|
256
|
+
onSelectedOptionChange={handleFontSizeChange}
|
|
257
|
+
/>
|
|
293
258
|
)}
|
|
294
259
|
|
|
295
260
|
{field.type === FieldTypeEnum.generic && field.subType === 'table' && (
|
|
296
261
|
<TableConfigs field={field} onFieldConfigChange={onFieldConfigChange} />
|
|
297
262
|
)}
|
|
298
263
|
|
|
264
|
+
{field.type === FieldTypeEnum.eSign &&
|
|
265
|
+
field.subType === ESignFieldType.dateSignedOffset && (
|
|
266
|
+
<ESignOptionsModal
|
|
267
|
+
initialState={field.data as ESignDateSignedOffsetSettings}
|
|
268
|
+
onSave={handleDateSignedOffsetSave}
|
|
269
|
+
documentFields={documentFields}
|
|
270
|
+
formFieldsByFormId={formFieldsByFormId}
|
|
271
|
+
formFieldsLoadingFormId={formulaLoadingFormId}
|
|
272
|
+
forms={forms}
|
|
273
|
+
onRequestFormFields={onRequestFormFields}
|
|
274
|
+
schema={dataModel}
|
|
275
|
+
/>
|
|
276
|
+
)}
|
|
277
|
+
|
|
299
278
|
{!hideConditionalLogic && (
|
|
300
279
|
<DisplayCondition
|
|
301
280
|
onSave={onFieldConfigChange}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { FC
|
|
1
|
+
import { FC } from 'react';
|
|
2
2
|
import { E_SIGN_FIELD_TYPES } from '../../constants';
|
|
3
3
|
import { type FieldTypeOption } from '../../interface/types';
|
|
4
4
|
import { FieldType } from './field-type';
|
|
@@ -10,18 +10,15 @@ interface ESignFieldTypeListProps {
|
|
|
10
10
|
|
|
11
11
|
export const ESignFieldTypeList: FC<ESignFieldTypeListProps> = ({ onDragEnd, onDragStart }) => {
|
|
12
12
|
return (
|
|
13
|
-
<
|
|
14
|
-
{E_SIGN_FIELD_TYPES.map(fieldOption =>
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
);
|
|
24
|
-
})}
|
|
25
|
-
</Fragment>
|
|
13
|
+
<div className="dte-field-type-items-wrapper">
|
|
14
|
+
{E_SIGN_FIELD_TYPES.map(fieldOption => (
|
|
15
|
+
<FieldType
|
|
16
|
+
key={fieldOption.subType}
|
|
17
|
+
label={fieldOption.label}
|
|
18
|
+
onDragEnd={onDragEnd}
|
|
19
|
+
onDragStart={() => onDragStart(fieldOption)}
|
|
20
|
+
/>
|
|
21
|
+
))}
|
|
22
|
+
</div>
|
|
26
23
|
);
|
|
27
24
|
};
|