@servicetitan/dte-pdf-editor 1.96.1 → 1.96.2
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 +16 -7
- package/dist/components/field-config-panel/field-config-panel-overlay.d.ts.map +1 -1
- package/dist/components/field-config-panel/field-config-panel-overlay.js +23 -15
- package/dist/components/field-config-panel/field-config-panel-overlay.js.map +1 -1
- package/dist/components/pdf-editor/pdf-editor.d.ts +6 -1
- package/dist/components/pdf-editor/pdf-editor.d.ts.map +1 -1
- package/dist/components/pdf-editor/pdf-editor.js.map +1 -1
- package/package.json +1 -1
- package/src/components/field-config-panel/__tests__/field-config-panel-overlay.test.tsx +184 -0
- package/src/components/field-config-panel/__tests__/schedule-switch-visibility.test.tsx +206 -0
- package/src/components/field-config-panel/field-config-panel-overlay.tsx +25 -16
- package/src/components/pdf-editor/pdf-editor.tsx +6 -1
package/README.md
CHANGED
|
@@ -31,6 +31,9 @@ formulas.
|
|
|
31
31
|
|
|
32
32
|
### Recent changes
|
|
33
33
|
|
|
34
|
+
- **fix/hide-sceduler** (schedule UI) — the schedule switch, picker and the e-sign schedule are shown only when
|
|
35
|
+
`onScheduleBindingsChange` is passed. See [RELEASE_NOTES.md](./RELEASE_NOTES.md) and
|
|
36
|
+
[Business-day calendars](#business-day-calendars).
|
|
34
37
|
- **fix/shared-incloud-on-BYOD-build** (installable package) — the package no longer depends on the unpublished
|
|
35
38
|
`@servicetitan/dte-shared`; its code is bundled in, so `npm install` works. See
|
|
36
39
|
[RELEASE_NOTES.md](./RELEASE_NOTES.md).
|
|
@@ -138,16 +141,16 @@ The main component for editing PDF documents and placing fields.
|
|
|
138
141
|
| `holidays` | `string[]` | No | Holidays of the default business-day calendar, for the formula builder preview; as on `PdfView` |
|
|
139
142
|
| `fieldCalendars` | `Record<string, BusinessCalendar>` | No | Calendars of date calculated fields bound to a schedule, by field id; as on `PdfView` |
|
|
140
143
|
| `scheduleBindings` | `FieldScheduleBinding[]` | No | Date fields whose exclusion toggle is on, and the schedule each uses; as on `PdfView` — see [Business-day calendars](#business-day-calendars) |
|
|
141
|
-
| `onScheduleBindingsChange` | `(bindings: FieldScheduleBinding[]) => void` | No | Called with the complete desired `scheduleBindings` when the toggle or picker changes the selected field's binding
|
|
142
|
-
| `holidayCatalog` | `HolidayCatalog` | No | The tenant's known holidays, for the schedule editor's checklist
|
|
144
|
+
| `onScheduleBindingsChange` | `(bindings: FieldScheduleBinding[]) => void` | No | Called with the complete desired `scheduleBindings` when the toggle or picker changes the selected field's binding. Passing it turns the schedule UI on; without it the switch, picker and e-sign schedule are not shown. It is not called for the e-sign schedule, which is stored in the field's `data` |
|
|
145
|
+
| `holidayCatalog` | `HolidayCatalog` | No | The tenant's known holidays, for the schedule editor's checklist (the schedule UI needs `onScheduleBindingsChange`) |
|
|
143
146
|
| `holidayCatalogLoading`| `boolean` | No | Whether `holidayCatalog` is still loading |
|
|
144
147
|
| `holidayCatalogError` | `string` | No | Error message shown in the schedule editor if the catalog failed to load |
|
|
145
|
-
| `schedules` | `BusinessDaySchedule[]` | No | The schedules the tenant can pick from the Formula Builder's schedule picker, default schedule first
|
|
148
|
+
| `schedules` | `BusinessDaySchedule[]` | No | The schedules the tenant can pick from the Formula Builder's schedule picker, default schedule first (the schedule UI needs `onScheduleBindingsChange`) |
|
|
146
149
|
| `schedulesLoading` | `boolean` | No | Whether `schedules` is still loading |
|
|
147
150
|
| `schedulesError` | `string` | No | Error message shown in the picker if the schedule list failed to load |
|
|
148
|
-
| `onCreateSchedule` | `(request: SaveScheduleRequest) => Promise<BusinessDaySchedule>` | No | Creates a tenant schedule from the "Create New Schedule" drawer; a rejected promise's `message` is shown as its error
|
|
149
|
-
| `onUpdateSchedule` | `(id: number, request: SaveScheduleRequest) => Promise<BusinessDaySchedule>` | No | Replaces a tenant schedule in place from the picker's "Edit" action; same error handling as `onCreateSchedule`
|
|
150
|
-
| `onDeleteSchedule` | `(id: number) => Promise<void>` | No | Permanently deletes a tenant schedule from the picker's delete action
|
|
151
|
+
| `onCreateSchedule` | `(request: SaveScheduleRequest) => Promise<BusinessDaySchedule>` | No | Creates a tenant schedule from the "Create New Schedule" drawer; a rejected promise's `message` is shown as its error (the schedule UI needs `onScheduleBindingsChange`) |
|
|
152
|
+
| `onUpdateSchedule` | `(id: number, request: SaveScheduleRequest) => Promise<BusinessDaySchedule>` | No | Replaces a tenant schedule in place from the picker's "Edit" action; same error handling as `onCreateSchedule` (the schedule UI needs `onScheduleBindingsChange`) |
|
|
153
|
+
| `onDeleteSchedule` | `(id: number) => Promise<void>` | No | Permanently deletes a tenant schedule from the picker's delete action (the schedule UI needs `onScheduleBindingsChange`) |
|
|
151
154
|
|
|
152
155
|
#### Example
|
|
153
156
|
|
|
@@ -340,7 +343,9 @@ Types of e-signature fields:
|
|
|
340
343
|
backend, at signing time.
|
|
341
344
|
- **`businessCalendarEnabled`** / **`scheduleId`**: the same business-day exclusion toggle and schedule choice as a
|
|
342
345
|
calculated field's (see **Business-day calendars** below), stored here instead of in `scheduleBindings` because,
|
|
343
|
-
like `rules`, it applies to every `dateSignedOffset` field in the document at once, not one field at a time.
|
|
346
|
+
like `rules`, it applies to every `dateSignedOffset` field in the document at once, not one field at a time. The
|
|
347
|
+
e-sign schedule is shown only when `onScheduleBindingsChange` is passed to `PdfEditor`; the callback is not called
|
|
348
|
+
for it.
|
|
344
349
|
|
|
345
350
|
All `dateSignedOffset` fields in a document share one `data` object — editing any one of them (days, rules, or the
|
|
346
351
|
business-calendar toggle) updates every sibling via `onMatchingFieldsConfigChange`, and a newly dropped
|
|
@@ -407,6 +412,10 @@ shown inline in its own config panel (see **ESignDateSignedOffsetSettings** abov
|
|
|
407
412
|
schedules (`holidayCatalog`, `schedules`, `onCreateSchedule`/`onUpdateSchedule`/`onDeleteSchedule`) but storing the
|
|
408
413
|
choice on the field's `data` instead of in `scheduleBindings`.
|
|
409
414
|
|
|
415
|
+
- **Showing and hiding the UI**: the switch, the picker and the e-sign schedule are offered only when
|
|
416
|
+
`onScheduleBindingsChange` is passed. A host that cannot save bindings (for example one without a tenant, or whose
|
|
417
|
+
schedules failed to load) leaves it out, and the editor then shows none of them. The formula preview still follows
|
|
418
|
+
`scheduleBindings`, `fieldCalendars` and `holidays`.
|
|
410
419
|
- **`scheduleBindings`** (`FieldScheduleBinding[]`, `{ fieldKey, scheduleId? }`, `fieldKey` = `PdfField.id`) is the
|
|
411
420
|
source of truth for which fields have the toggle on, and which schedule each uses (`scheduleId` undefined = the
|
|
412
421
|
default schedule). A field with no entry here is unaffected by `holidays` / `fieldCalendars`.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"field-config-panel-overlay.d.ts","sourceRoot":"","sources":["../../../src/components/field-config-panel/field-config-panel-overlay.tsx"],"names":[],"mappings":"AAGA,OAAO,EAAE,EAAE,EAAwB,MAAM,OAAO,CAAC;AACjD,OAAO,EACH,KAAK,gBAAgB,EACrB,KAAK,mBAAmB,EACxB,KAAK,oBAAoB,EACzB,KAAK,mBAAmB,EACxB,KAAK,QAAQ,EACb,KAAK,cAAc,EACnB,KAAK,QAAQ,EACb,KAAK,aAAa,EAClB,KAAK,mBAAmB,EACxB,KAAK,YAAY,EACpB,MAAM,uBAAuB,CAAC;AAI/B,UAAU,4BAA4B;IAClC,SAAS,CAAC,EAAE,YAAY,CAAC;IACzB,cAAc,CAAC,EAAE,QAAQ,EAAE,CAAC;IAC5B,kBAAkB,EAAE,mBAAmB,CAAC;IACxC,KAAK,EAAE,QAAQ,EAAE,CAAC;IAClB,oBAAoB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACrC,aAAa,EAAE,QAAQ,CAAC;IACxB,UAAU,EAAE,aAAa,EAAE,CAAC;IAC5B,oBAAoB,CAAC,EAAE,OAAO,CAAC;IAC/B,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC;IACpB,cAAc,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,gBAAgB,CAAC,CAAC;IAClD,gBAAgB,CAAC,EAAE,oBAAoB,EAAE,CAAC;IAC1C,cAAc,CAAC,EAAE,cAAc,CAAC;IAChC,qBAAqB,CAAC,EAAE,OAAO,CAAC;IAChC,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B,SAAS,CAAC,EAAE,mBAAmB,EAAE,CAAC;IAClC,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,wBAAwB,CAAC,CAAC,QAAQ,EAAE,oBAAoB,EAAE,GAAG,IAAI,CAAC;IAClE,gBAAgB,CAAC,CAAC,OAAO,EAAE,mBAAmB,GAAG,OAAO,CAAC,mBAAmB,CAAC,CAAC;IAC9E,gBAAgB,CAAC,CAAC,EAAE,EAAE,MAAM,EAAE,OAAO,EAAE,mBAAmB,GAAG,OAAO,CAAC,mBAAmB,CAAC,CAAC;IAC1F,gBAAgB,CAAC,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC7C,mBAAmB,CAAC,OAAO,EAAE,OAAO,CAAC,QAAQ,CAAC,GAAG,IAAI,CAAC;IACtD,4BAA4B,CAAC,CACzB,SAAS,EAAE,CAAC,KAAK,EAAE,QAAQ,KAAK,OAAO,EACvC,OAAO,EAAE,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,QAAQ,KAAK,OAAO,CAAC,QAAQ,CAAC,CAAC,GACtE,IAAI,CAAC;IACR,aAAa,IAAI,IAAI,CAAC;IACtB,eAAe,CAAC,IAAI,IAAI,CAAC;IACzB,mBAAmB,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;CAC7C;AAED,eAAO,MAAM,uBAAuB,EAAE,EAAE,CAAC,4BAA4B,
|
|
1
|
+
{"version":3,"file":"field-config-panel-overlay.d.ts","sourceRoot":"","sources":["../../../src/components/field-config-panel/field-config-panel-overlay.tsx"],"names":[],"mappings":"AAGA,OAAO,EAAE,EAAE,EAAwB,MAAM,OAAO,CAAC;AACjD,OAAO,EACH,KAAK,gBAAgB,EACrB,KAAK,mBAAmB,EACxB,KAAK,oBAAoB,EACzB,KAAK,mBAAmB,EACxB,KAAK,QAAQ,EACb,KAAK,cAAc,EACnB,KAAK,QAAQ,EACb,KAAK,aAAa,EAClB,KAAK,mBAAmB,EACxB,KAAK,YAAY,EACpB,MAAM,uBAAuB,CAAC;AAI/B,UAAU,4BAA4B;IAClC,SAAS,CAAC,EAAE,YAAY,CAAC;IACzB,cAAc,CAAC,EAAE,QAAQ,EAAE,CAAC;IAC5B,kBAAkB,EAAE,mBAAmB,CAAC;IACxC,KAAK,EAAE,QAAQ,EAAE,CAAC;IAClB,oBAAoB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACrC,aAAa,EAAE,QAAQ,CAAC;IACxB,UAAU,EAAE,aAAa,EAAE,CAAC;IAC5B,oBAAoB,CAAC,EAAE,OAAO,CAAC;IAC/B,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC;IACpB,cAAc,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,gBAAgB,CAAC,CAAC;IAClD,gBAAgB,CAAC,EAAE,oBAAoB,EAAE,CAAC;IAC1C,cAAc,CAAC,EAAE,cAAc,CAAC;IAChC,qBAAqB,CAAC,EAAE,OAAO,CAAC;IAChC,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B,SAAS,CAAC,EAAE,mBAAmB,EAAE,CAAC;IAClC,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,wBAAwB,CAAC,CAAC,QAAQ,EAAE,oBAAoB,EAAE,GAAG,IAAI,CAAC;IAClE,gBAAgB,CAAC,CAAC,OAAO,EAAE,mBAAmB,GAAG,OAAO,CAAC,mBAAmB,CAAC,CAAC;IAC9E,gBAAgB,CAAC,CAAC,EAAE,EAAE,MAAM,EAAE,OAAO,EAAE,mBAAmB,GAAG,OAAO,CAAC,mBAAmB,CAAC,CAAC;IAC1F,gBAAgB,CAAC,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC7C,mBAAmB,CAAC,OAAO,EAAE,OAAO,CAAC,QAAQ,CAAC,GAAG,IAAI,CAAC;IACtD,4BAA4B,CAAC,CACzB,SAAS,EAAE,CAAC,KAAK,EAAE,QAAQ,KAAK,OAAO,EACvC,OAAO,EAAE,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,QAAQ,KAAK,OAAO,CAAC,QAAQ,CAAC,CAAC,GACtE,IAAI,CAAC;IACR,aAAa,IAAI,IAAI,CAAC;IACtB,eAAe,CAAC,IAAI,IAAI,CAAC;IACzB,mBAAmB,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;CAC7C;AAED,eAAO,MAAM,uBAAuB,EAAE,EAAE,CAAC,4BAA4B,CAwIpE,CAAC"}
|
|
@@ -14,21 +14,29 @@ export const FieldConfigPanelOverlay = ({ dataModel, documentFields = [], fieldC
|
|
|
14
14
|
const handleSelectSchedule = useCallback((scheduleId) => {
|
|
15
15
|
onScheduleBindingsChange === null || onScheduleBindingsChange === void 0 ? void 0 : onScheduleBindingsChange(setFieldSchedule(scheduleBindings !== null && scheduleBindings !== void 0 ? scheduleBindings : [], selectedFieldId, scheduleId));
|
|
16
16
|
}, [scheduleBindings, selectedFieldId, onScheduleBindingsChange]);
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
17
|
+
/*
|
|
18
|
+
* The schedule UI (the Formula Builder's switch and the e-sign day offset's schedule) is offered
|
|
19
|
+
* only to a host that passes `onScheduleBindingsChange`. Without it there is no context, and
|
|
20
|
+
* everything that renders the schedule UI checks for one.
|
|
21
|
+
*/
|
|
22
|
+
const businessCalendar = useMemo(() => onScheduleBindingsChange
|
|
23
|
+
? {
|
|
24
|
+
enabled: !!selectedBinding,
|
|
25
|
+
selectedScheduleId: selectedBinding === null || selectedBinding === void 0 ? void 0 : selectedBinding.scheduleId,
|
|
26
|
+
onToggle: handleToggle,
|
|
27
|
+
onSelectSchedule: handleSelectSchedule,
|
|
28
|
+
holidayCatalog,
|
|
29
|
+
holidayCatalogLoading,
|
|
30
|
+
holidayCatalogError,
|
|
31
|
+
schedules,
|
|
32
|
+
schedulesLoading,
|
|
33
|
+
schedulesError,
|
|
34
|
+
onCreateSchedule,
|
|
35
|
+
onUpdateSchedule,
|
|
36
|
+
onDeleteSchedule,
|
|
37
|
+
}
|
|
38
|
+
: undefined, [
|
|
39
|
+
onScheduleBindingsChange,
|
|
32
40
|
selectedBinding,
|
|
33
41
|
handleToggle,
|
|
34
42
|
handleSelectSchedule,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"field-config-panel-overlay.js","sourceRoot":"","sources":["../../../src/components/field-config-panel/field-config-panel-overlay.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,EAAE,MAAM,sBAAsB,CAAC;AAC1D,OAAO,SAAS,MAAM,4DAA4D,CAAC;AAEnF,OAAO,EAAM,WAAW,EAAE,OAAO,EAAE,MAAM,OAAO,CAAC;AAajD,OAAO,EAAE,uBAAuB,EAAE,gBAAgB,EAAE,uBAAuB,EAAE,MAAM,aAAa,CAAC;AACjG,OAAO,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAC;AAkCxD,MAAM,CAAC,MAAM,uBAAuB,GAAqC,CAAC,EACtE,SAAS,EACT,cAAc,GAAG,EAAE,EACnB,cAAc,EACd,kBAAkB,EAClB,KAAK,EACL,oBAAoB,EACpB,oBAAoB,EACpB,cAAc,EACd,mBAAmB,EACnB,qBAAqB,EACrB,QAAQ,EACR,gBAAgB,EAChB,aAAa,EACb,gBAAgB,EAChB,eAAe,EACf,mBAAmB,EACnB,4BAA4B,EAC5B,mBAAmB,EACnB,wBAAwB,EACxB,gBAAgB,EAChB,UAAU,EACV,gBAAgB,EAChB,SAAS,EACT,cAAc,EACd,gBAAgB,EAChB,aAAa,GAChB,EAAE,EAAE;IACD,MAAM,eAAe,GAAG,OAAO,CAC3B,GAAG,EAAE,CAAC,uBAAuB,CAAC,aAAa,CAAC,EAAE,EAAE,gBAAgB,EAAE,QAAQ,EAAE,cAAc,CAAC,EAC3F,CAAC,aAAa,CAAC,EAAE,EAAE,gBAAgB,EAAE,QAAQ,EAAE,cAAc,CAAC,CACjE,CAAC;IAEF,MAAM,eAAe,GAAG,aAAa,CAAC,EAAE,CAAC;IACzC,MAAM,eAAe,GAAG,OAAO,CAC3B,GAAG,EAAE,CAAC,gBAAgB,aAAhB,gBAAgB,uBAAhB,gBAAgB,CAAE,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,QAAQ,KAAK,eAAe,CAAC,EACjE,CAAC,gBAAgB,EAAE,eAAe,CAAC,CACtC,CAAC;IAEF,MAAM,YAAY,GAAG,WAAW,CAC5B,CAAC,OAAgB,EAAE,EAAE;QACjB,wBAAwB,aAAxB,wBAAwB,uBAAxB,wBAAwB,CACpB,uBAAuB,CAAC,gBAAgB,aAAhB,gBAAgB,cAAhB,gBAAgB,GAAI,EAAE,EAAE,eAAe,EAAE,OAAO,CAAC,CAC5E,CAAC;IACN,CAAC,EACD,CAAC,gBAAgB,EAAE,eAAe,EAAE,wBAAwB,CAAC,CAChE,CAAC;IAEF,MAAM,oBAAoB,GAAG,WAAW,CACpC,CAAC,UAA8B,EAAE,EAAE;QAC/B,wBAAwB,aAAxB,wBAAwB,uBAAxB,wBAAwB,CACpB,gBAAgB,CAAC,gBAAgB,aAAhB,gBAAgB,cAAhB,gBAAgB,GAAI,EAAE,EAAE,eAAe,EAAE,UAAU,CAAC,CACxE,CAAC;IACN,CAAC,EACD,CAAC,gBAAgB,EAAE,eAAe,EAAE,wBAAwB,CAAC,CAChE,CAAC;IAEF,MAAM,gBAAgB,
|
|
1
|
+
{"version":3,"file":"field-config-panel-overlay.js","sourceRoot":"","sources":["../../../src/components/field-config-panel/field-config-panel-overlay.tsx"],"names":[],"mappings":"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"}
|
|
@@ -27,7 +27,7 @@ export interface PdfEditorProps {
|
|
|
27
27
|
/**
|
|
28
28
|
* Date calculated fields whose custom business-day exclusion toggle is on, and the schedule
|
|
29
29
|
* each uses (`PdfField.id` as `fieldKey`), as `PdfView`'s. Also drives the Formula Builder's
|
|
30
|
-
* toggle/picker for the selected field
|
|
30
|
+
* toggle/picker for the selected field, which are shown only with `onScheduleBindingsChange`.
|
|
31
31
|
*/
|
|
32
32
|
scheduleBindings?: FieldScheduleBinding[];
|
|
33
33
|
/** The tenant's known holidays, for the schedule editor's checklist. */
|
|
@@ -45,6 +45,11 @@ export interface PdfEditorProps {
|
|
|
45
45
|
* `PUT api/holidays/templates/{id}/bindings`). `PdfEditor` does not persist this itself —
|
|
46
46
|
* the host is expected to save it (and the bindings are typically saved separately from the
|
|
47
47
|
* template's own fields).
|
|
48
|
+
*
|
|
49
|
+
* Passing it also turns the schedule UI on: without it the Formula Builder has no "Exclude
|
|
50
|
+
* weekends & holidays" switch and the e-sign day offset has no schedule. A host that cannot save
|
|
51
|
+
* bindings (for example one without a tenant) leaves it out. It is not called for the e-sign
|
|
52
|
+
* schedule, which is stored in the field's `data`.
|
|
48
53
|
*/
|
|
49
54
|
onScheduleBindingsChange?(bindings: FieldScheduleBinding[]): void;
|
|
50
55
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"pdf-editor.d.ts","sourceRoot":"","sources":["../../../src/components/pdf-editor/pdf-editor.tsx"],"names":[],"mappings":"AACA,OAAO,EAAE,EAAE,EAAE,SAAS,EAAgC,MAAM,OAAO,CAAC;AAEpE,OAAO,EACH,KAAK,gBAAgB,EACrB,KAAK,mBAAmB,EACxB,aAAa,EACb,KAAK,oBAAoB,EACzB,KAAK,mBAAmB,EACxB,KAAK,QAAQ,EACb,KAAK,cAAc,EACnB,KAAK,QAAQ,EACb,KAAK,aAAa,EAClB,KAAK,mBAAmB,EACxB,KAAK,YAAY,EACpB,MAAM,uBAAuB,CAAC;AAI/B,OAAO,EAAa,cAAc,EAAE,MAAM,0BAA0B,CAAC;AAErE,OAAO,wBAAwB,CAAC;AAEhC,MAAM,WAAW,cAAc;IAC3B,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAChC,kBAAkB,CAAC,EAAE,SAAS,CAAC;IAC/B,gBAAgB,CAAC,EAAE,SAAS,CAAC;IAC7B,SAAS,CAAC,EAAE,YAAY,CAAC;IACzB,UAAU,CAAC,EAAE,aAAa,EAAE,CAAC;IAC7B,MAAM,CAAC,EAAE,QAAQ,EAAE,CAAC;IACpB,UAAU,CAAC,EAAE,aAAa,EAAE,CAAC;IAC7B,oBAAoB,CAAC,EAAE,OAAO,CAAC;IAC/B,KAAK,CAAC,EAAE,QAAQ,EAAE,CAAC;IACnB,SAAS,CAAC,EAAE,cAAc,CAAC,WAAW,CAAC,CAAC;IACxC;;;;OAIG;IACH,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC;IACpB,gGAAgG;IAChG,cAAc,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,gBAAgB,CAAC,CAAC;IAClD;;;;OAIG;IACH,gBAAgB,CAAC,EAAE,oBAAoB,EAAE,CAAC;IAC1C,wEAAwE;IACxE,cAAc,CAAC,EAAE,cAAc,CAAC;IAChC,qBAAqB,CAAC,EAAE,OAAO,CAAC;IAChC,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B,oFAAoF;IACpF,SAAS,CAAC,EAAE,mBAAmB,EAAE,CAAC;IAClC,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,YAAY,CAAC,EAAE,CACX,OAAO,EAAE,MAAM,EAAE,EACjB,cAAc,EAAE,CAAC,kBAAkB,EAAE,mBAAmB,KAAK,IAAI,KAChE,IAAI,CAAC;IACV
|
|
1
|
+
{"version":3,"file":"pdf-editor.d.ts","sourceRoot":"","sources":["../../../src/components/pdf-editor/pdf-editor.tsx"],"names":[],"mappings":"AACA,OAAO,EAAE,EAAE,EAAE,SAAS,EAAgC,MAAM,OAAO,CAAC;AAEpE,OAAO,EACH,KAAK,gBAAgB,EACrB,KAAK,mBAAmB,EACxB,aAAa,EACb,KAAK,oBAAoB,EACzB,KAAK,mBAAmB,EACxB,KAAK,QAAQ,EACb,KAAK,cAAc,EACnB,KAAK,QAAQ,EACb,KAAK,aAAa,EAClB,KAAK,mBAAmB,EACxB,KAAK,YAAY,EACpB,MAAM,uBAAuB,CAAC;AAI/B,OAAO,EAAa,cAAc,EAAE,MAAM,0BAA0B,CAAC;AAErE,OAAO,wBAAwB,CAAC;AAEhC,MAAM,WAAW,cAAc;IAC3B,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAChC,kBAAkB,CAAC,EAAE,SAAS,CAAC;IAC/B,gBAAgB,CAAC,EAAE,SAAS,CAAC;IAC7B,SAAS,CAAC,EAAE,YAAY,CAAC;IACzB,UAAU,CAAC,EAAE,aAAa,EAAE,CAAC;IAC7B,MAAM,CAAC,EAAE,QAAQ,EAAE,CAAC;IACpB,UAAU,CAAC,EAAE,aAAa,EAAE,CAAC;IAC7B,oBAAoB,CAAC,EAAE,OAAO,CAAC;IAC/B,KAAK,CAAC,EAAE,QAAQ,EAAE,CAAC;IACnB,SAAS,CAAC,EAAE,cAAc,CAAC,WAAW,CAAC,CAAC;IACxC;;;;OAIG;IACH,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC;IACpB,gGAAgG;IAChG,cAAc,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,gBAAgB,CAAC,CAAC;IAClD;;;;OAIG;IACH,gBAAgB,CAAC,EAAE,oBAAoB,EAAE,CAAC;IAC1C,wEAAwE;IACxE,cAAc,CAAC,EAAE,cAAc,CAAC;IAChC,qBAAqB,CAAC,EAAE,OAAO,CAAC;IAChC,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B,oFAAoF;IACpF,SAAS,CAAC,EAAE,mBAAmB,EAAE,CAAC;IAClC,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,YAAY,CAAC,EAAE,CACX,OAAO,EAAE,MAAM,EAAE,EACjB,cAAc,EAAE,CAAC,kBAAkB,EAAE,mBAAmB,KAAK,IAAI,KAChE,IAAI,CAAC;IACV;;;;;;;;;;;OAWG;IACH,wBAAwB,CAAC,CAAC,QAAQ,EAAE,oBAAoB,EAAE,GAAG,IAAI,CAAC;IAClE;;;;;OAKG;IACH,gBAAgB,CAAC,CAAC,OAAO,EAAE,mBAAmB,GAAG,OAAO,CAAC,mBAAmB,CAAC,CAAC;IAC9E;;;;OAIG;IACH,gBAAgB,CAAC,CAAC,EAAE,EAAE,MAAM,EAAE,OAAO,EAAE,mBAAmB,GAAG,OAAO,CAAC,mBAAmB,CAAC,CAAC;IAC1F;;;;;;OAMG;IACH,gBAAgB,CAAC,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC7C,aAAa,CAAC,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACvC,cAAc,CAAC,MAAM,EAAE,QAAQ,EAAE,GAAG,IAAI,CAAC;CAC5C;AAED,eAAO,MAAM,SAAS,EAAE,EAAE,CAAC,cAAc,CA0IxC,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"pdf-editor.js","sourceRoot":"","sources":["../../../src/components/pdf-editor/pdf-editor.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,sBAAsB,CAAC;AAC5C,OAAO,EAAiB,WAAW,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,OAAO,CAAC;AACpE,OAAO,EAAE,aAAa,EAAE,cAAc,EAAE,oBAAoB,EAAE,MAAM,aAAa,CAAC;AAclF,OAAO,EAAE,iCAAiC,EAAE,qBAAqB,EAAE,MAAM,aAAa,CAAC;AACvF,OAAO,EAAE,uBAAuB,EAAE,MAAM,kDAAkD,CAAC;AAC3F,OAAO,EAAE,YAAY,EAAE,MAAM,gCAAgC,CAAC;AAC9D,OAAO,EAAE,SAAS,EAAkB,MAAM,0BAA0B,CAAC;AAErE,OAAO,wBAAwB,CAAC;
|
|
1
|
+
{"version":3,"file":"pdf-editor.js","sourceRoot":"","sources":["../../../src/components/pdf-editor/pdf-editor.tsx"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -0,0 +1,184 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* The schedule UI is offered only to a host that passes `onScheduleBindingsChange`. The overlay
|
|
3
|
+
* decides that, and every place that renders the schedule UI checks the context it builds, so the
|
|
4
|
+
* panel below is replaced by a stand-in that records what the overlay gives it.
|
|
5
|
+
*/
|
|
6
|
+
jest.mock('../field-config-panel', () => ({ FieldConfigPanel: jest.fn(() => null) }));
|
|
7
|
+
// A Proxy is what `.svg` imports become under test; it is not a component.
|
|
8
|
+
jest.mock('@servicetitan/anvil2/assets/icons/material/round/close.svg', () => ({
|
|
9
|
+
__esModule: true,
|
|
10
|
+
default: () => null,
|
|
11
|
+
}));
|
|
12
|
+
|
|
13
|
+
import { TextDecoder, TextEncoder } from 'util';
|
|
14
|
+
|
|
15
|
+
// jsdom has no TextEncoder; anvil2 reads it when it is loaded, so this must run before it is imported.
|
|
16
|
+
Object.assign(globalThis, { TextEncoder, TextDecoder });
|
|
17
|
+
|
|
18
|
+
import { act, type ComponentProps } from 'react';
|
|
19
|
+
import { createRoot, type Root } from 'react-dom/client';
|
|
20
|
+
import { type FieldScheduleBinding, type PdfField } from '../../../interface/types';
|
|
21
|
+
import { FieldConfigPanel } from '../field-config-panel';
|
|
22
|
+
import { FieldConfigPanelOverlay } from '../field-config-panel-overlay';
|
|
23
|
+
|
|
24
|
+
const panel = FieldConfigPanel as unknown as jest.Mock;
|
|
25
|
+
const lastBusinessCalendar = () =>
|
|
26
|
+
panel.mock.calls[panel.mock.calls.length - 1][0].businessCalendar;
|
|
27
|
+
|
|
28
|
+
const defaultSchedule = {
|
|
29
|
+
name: 'Default',
|
|
30
|
+
isDefault: true,
|
|
31
|
+
calendar: { weekendDays: [0, 6] as (0 | 6)[], knownHolidays: [], customDates: [] },
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
describe('FieldConfigPanelOverlay', () => {
|
|
35
|
+
let container: HTMLDivElement;
|
|
36
|
+
let root: Root;
|
|
37
|
+
|
|
38
|
+
// Async, so the state anvil2 sets right after mounting is flushed inside `act`.
|
|
39
|
+
const render = (props: Partial<ComponentProps<typeof FieldConfigPanelOverlay>> = {}) =>
|
|
40
|
+
act(async () => {
|
|
41
|
+
root.render(
|
|
42
|
+
<FieldConfigPanelOverlay
|
|
43
|
+
selectedField={{ id: 'f1', type: 'calculated' } as PdfField}
|
|
44
|
+
recipients={[]}
|
|
45
|
+
forms={[]}
|
|
46
|
+
formFieldsByFormId={{}}
|
|
47
|
+
onFieldConfigChange={() => {}}
|
|
48
|
+
onDeleteField={() => {}}
|
|
49
|
+
onRequestFormFields={() => {}}
|
|
50
|
+
{...props}
|
|
51
|
+
/>,
|
|
52
|
+
);
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
beforeAll(() => {
|
|
56
|
+
(globalThis as { IS_REACT_ACT_ENVIRONMENT?: boolean }).IS_REACT_ACT_ENVIRONMENT = true;
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
beforeEach(() => {
|
|
60
|
+
panel.mockClear();
|
|
61
|
+
container = document.createElement('div');
|
|
62
|
+
document.body.appendChild(container);
|
|
63
|
+
root = createRoot(container);
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
afterEach(async () => {
|
|
67
|
+
await act(async () => root.unmount());
|
|
68
|
+
container.remove();
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
describe('without onScheduleBindingsChange', () => {
|
|
72
|
+
test('gives the panel no schedule context', async () => {
|
|
73
|
+
await render();
|
|
74
|
+
|
|
75
|
+
expect(lastBusinessCalendar()).toBeUndefined();
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
test('gives the panel no schedule context although the host passed schedules', async () => {
|
|
79
|
+
await render({
|
|
80
|
+
scheduleBindings: [{ fieldKey: 'f1' }],
|
|
81
|
+
schedules: [defaultSchedule],
|
|
82
|
+
holidayCatalog: { jurisdiction: 'US', holidays: [] },
|
|
83
|
+
onCreateSchedule: jest.fn(),
|
|
84
|
+
onUpdateSchedule: jest.fn(),
|
|
85
|
+
onDeleteSchedule: jest.fn(),
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
expect(lastBusinessCalendar()).toBeUndefined();
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
test('adds the schedule context when the host starts passing the handler', async () => {
|
|
92
|
+
await render();
|
|
93
|
+
expect(lastBusinessCalendar()).toBeUndefined();
|
|
94
|
+
|
|
95
|
+
await render({ onScheduleBindingsChange: jest.fn() });
|
|
96
|
+
|
|
97
|
+
expect(lastBusinessCalendar()).toBeDefined();
|
|
98
|
+
});
|
|
99
|
+
|
|
100
|
+
test('removes the schedule context when the host stops passing the handler', async () => {
|
|
101
|
+
await render({ onScheduleBindingsChange: jest.fn() });
|
|
102
|
+
expect(lastBusinessCalendar()).toBeDefined();
|
|
103
|
+
|
|
104
|
+
await render({ onScheduleBindingsChange: undefined });
|
|
105
|
+
|
|
106
|
+
expect(lastBusinessCalendar()).toBeUndefined();
|
|
107
|
+
});
|
|
108
|
+
});
|
|
109
|
+
|
|
110
|
+
describe('with onScheduleBindingsChange', () => {
|
|
111
|
+
let onScheduleBindingsChange: jest.Mock;
|
|
112
|
+
|
|
113
|
+
beforeEach(() => {
|
|
114
|
+
onScheduleBindingsChange = jest.fn();
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
test('gives the panel a schedule context with the switch off for a field without a binding', async () => {
|
|
118
|
+
await render({ onScheduleBindingsChange, scheduleBindings: [] });
|
|
119
|
+
|
|
120
|
+
expect(lastBusinessCalendar()).toMatchObject({ enabled: false });
|
|
121
|
+
});
|
|
122
|
+
|
|
123
|
+
test('gives the panel the schedule of the field and what the host loaded', async () => {
|
|
124
|
+
const schedules = [defaultSchedule];
|
|
125
|
+
const holidayCatalog = { jurisdiction: 'US', holidays: [] };
|
|
126
|
+
const onCreateSchedule = jest.fn();
|
|
127
|
+
await render({
|
|
128
|
+
onScheduleBindingsChange,
|
|
129
|
+
scheduleBindings: [{ fieldKey: 'f1', scheduleId: 3 }],
|
|
130
|
+
schedules,
|
|
131
|
+
holidayCatalog,
|
|
132
|
+
onCreateSchedule,
|
|
133
|
+
});
|
|
134
|
+
|
|
135
|
+
expect(lastBusinessCalendar()).toMatchObject({
|
|
136
|
+
enabled: true,
|
|
137
|
+
selectedScheduleId: 3,
|
|
138
|
+
schedules,
|
|
139
|
+
holidayCatalog,
|
|
140
|
+
onCreateSchedule,
|
|
141
|
+
});
|
|
142
|
+
});
|
|
143
|
+
|
|
144
|
+
test('follows the binding of the field that is selected next', async () => {
|
|
145
|
+
const scheduleBindings = [{ fieldKey: 'f2', scheduleId: 3 }];
|
|
146
|
+
await render({ onScheduleBindingsChange, scheduleBindings });
|
|
147
|
+
expect(lastBusinessCalendar()).toMatchObject({ enabled: false });
|
|
148
|
+
|
|
149
|
+
await render({
|
|
150
|
+
onScheduleBindingsChange,
|
|
151
|
+
scheduleBindings,
|
|
152
|
+
selectedField: { id: 'f2', type: 'calculated' } as PdfField,
|
|
153
|
+
});
|
|
154
|
+
|
|
155
|
+
expect(lastBusinessCalendar()).toMatchObject({ enabled: true, selectedScheduleId: 3 });
|
|
156
|
+
});
|
|
157
|
+
|
|
158
|
+
test('turns the switch on by sending the whole list with the field added', async () => {
|
|
159
|
+
const others: FieldScheduleBinding[] = [{ fieldKey: 'other', scheduleId: 9 }];
|
|
160
|
+
await render({ onScheduleBindingsChange, scheduleBindings: others });
|
|
161
|
+
|
|
162
|
+
lastBusinessCalendar().onToggle(true);
|
|
163
|
+
|
|
164
|
+
expect(onScheduleBindingsChange).toHaveBeenCalledWith([
|
|
165
|
+
{ fieldKey: 'other', scheduleId: 9 },
|
|
166
|
+
{ fieldKey: 'f1' },
|
|
167
|
+
]);
|
|
168
|
+
});
|
|
169
|
+
|
|
170
|
+
test('picks a schedule by sending the whole list with the field changed', async () => {
|
|
171
|
+
await render({
|
|
172
|
+
onScheduleBindingsChange,
|
|
173
|
+
scheduleBindings: [{ fieldKey: 'f1' }, { fieldKey: 'other', scheduleId: 9 }],
|
|
174
|
+
});
|
|
175
|
+
|
|
176
|
+
lastBusinessCalendar().onSelectSchedule(4);
|
|
177
|
+
|
|
178
|
+
expect(onScheduleBindingsChange).toHaveBeenCalledWith([
|
|
179
|
+
{ fieldKey: 'other', scheduleId: 9 },
|
|
180
|
+
{ fieldKey: 'f1', scheduleId: 4 },
|
|
181
|
+
]);
|
|
182
|
+
});
|
|
183
|
+
});
|
|
184
|
+
});
|
|
@@ -0,0 +1,206 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* The overlay gives the panel no schedule context when the host cannot save bindings. This checks
|
|
3
|
+
* the other half: the places that draw the schedule switch show it only with a context.
|
|
4
|
+
*/
|
|
5
|
+
import { TextDecoder, TextEncoder } from 'util';
|
|
6
|
+
|
|
7
|
+
// jsdom has no TextEncoder; anvil2 reads it when it is loaded, so this must run before it is imported.
|
|
8
|
+
Object.assign(globalThis, { TextEncoder, TextDecoder });
|
|
9
|
+
|
|
10
|
+
import { act, useState } from 'react';
|
|
11
|
+
import { createRoot, type Root } from 'react-dom/client';
|
|
12
|
+
import {
|
|
13
|
+
type CalculatedFieldFormat,
|
|
14
|
+
ESignFieldType,
|
|
15
|
+
FieldTypeEnum,
|
|
16
|
+
type PdfField,
|
|
17
|
+
} from '../../../interface/types';
|
|
18
|
+
import { AdvancedSettings } from '../advanced-settings';
|
|
19
|
+
import { ESignOptionsModal } from '../e-sign-options-modal';
|
|
20
|
+
import { FieldConfigPanel } from '../field-config-panel';
|
|
21
|
+
|
|
22
|
+
// jsdom has no matchMedia, ResizeObserver, IntersectionObserver or popover API; anvil2 uses them.
|
|
23
|
+
Object.defineProperty(window, 'matchMedia', {
|
|
24
|
+
writable: true,
|
|
25
|
+
value: (query: string) => ({
|
|
26
|
+
matches: false,
|
|
27
|
+
media: query,
|
|
28
|
+
onchange: null,
|
|
29
|
+
addListener: () => {},
|
|
30
|
+
removeListener: () => {},
|
|
31
|
+
addEventListener: () => {},
|
|
32
|
+
removeEventListener: () => {},
|
|
33
|
+
dispatchEvent: () => false,
|
|
34
|
+
}),
|
|
35
|
+
});
|
|
36
|
+
class ObserverMock {
|
|
37
|
+
observe() {}
|
|
38
|
+
unobserve() {}
|
|
39
|
+
disconnect() {}
|
|
40
|
+
}
|
|
41
|
+
global.ResizeObserver = ObserverMock as unknown as typeof ResizeObserver;
|
|
42
|
+
global.IntersectionObserver = ObserverMock as unknown as typeof IntersectionObserver;
|
|
43
|
+
HTMLElement.prototype.showPopover ??= () => {};
|
|
44
|
+
HTMLElement.prototype.hidePopover ??= () => {};
|
|
45
|
+
HTMLElement.prototype.togglePopover ??= () => false;
|
|
46
|
+
|
|
47
|
+
const SWITCH_LABEL = 'Exclude weekends & holidays from the calculation';
|
|
48
|
+
const noOp = () => {};
|
|
49
|
+
const businessCalendar = { enabled: false, onToggle: noOp, onSelectSchedule: noOp };
|
|
50
|
+
const dateFormat: CalculatedFieldFormat = { resultType: 'date', dateFormat: 'MM/DD/YYYY' };
|
|
51
|
+
const numberFormat: CalculatedFieldFormat = {
|
|
52
|
+
resultType: 'number',
|
|
53
|
+
thousandsSeparator: false,
|
|
54
|
+
decimals: 2,
|
|
55
|
+
roundingMode: 'round',
|
|
56
|
+
decimalSeparatorEnabled: false,
|
|
57
|
+
decimalSeparator: '.',
|
|
58
|
+
prefixText: '',
|
|
59
|
+
postfixText: '',
|
|
60
|
+
};
|
|
61
|
+
|
|
62
|
+
const AdvancedSettingsSubject = ({
|
|
63
|
+
format,
|
|
64
|
+
withSchedules,
|
|
65
|
+
}: {
|
|
66
|
+
format: CalculatedFieldFormat;
|
|
67
|
+
withSchedules: boolean;
|
|
68
|
+
}) => {
|
|
69
|
+
const [current, setCurrent] = useState(format);
|
|
70
|
+
|
|
71
|
+
return (
|
|
72
|
+
<AdvancedSettings
|
|
73
|
+
format={current}
|
|
74
|
+
setFormat={setCurrent}
|
|
75
|
+
businessCalendar={withSchedules ? businessCalendar : undefined}
|
|
76
|
+
/>
|
|
77
|
+
);
|
|
78
|
+
};
|
|
79
|
+
|
|
80
|
+
describe('the schedule switch', () => {
|
|
81
|
+
let container: HTMLDivElement;
|
|
82
|
+
let root: Root;
|
|
83
|
+
|
|
84
|
+
const render = (element: JSX.Element) =>
|
|
85
|
+
act(async () => {
|
|
86
|
+
root.render(element);
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
beforeAll(() => {
|
|
90
|
+
(globalThis as { IS_REACT_ACT_ENVIRONMENT?: boolean }).IS_REACT_ACT_ENVIRONMENT = true;
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
beforeEach(() => {
|
|
94
|
+
container = document.createElement('div');
|
|
95
|
+
document.body.appendChild(container);
|
|
96
|
+
root = createRoot(container);
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
afterEach(async () => {
|
|
100
|
+
await act(async () => root.unmount());
|
|
101
|
+
container.remove();
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
describe('in the advanced settings of a calculated field', () => {
|
|
105
|
+
test('is shown for a date field with a schedule context', async () => {
|
|
106
|
+
await render(<AdvancedSettingsSubject format={dateFormat} withSchedules />);
|
|
107
|
+
|
|
108
|
+
expect(container.textContent).toContain('Date format');
|
|
109
|
+
expect(container.textContent).toContain(SWITCH_LABEL);
|
|
110
|
+
});
|
|
111
|
+
|
|
112
|
+
test('is not shown for a date field without a schedule context', async () => {
|
|
113
|
+
await render(<AdvancedSettingsSubject format={dateFormat} withSchedules={false} />);
|
|
114
|
+
|
|
115
|
+
expect(container.textContent).toContain('Date format');
|
|
116
|
+
expect(container.textContent).not.toContain(SWITCH_LABEL);
|
|
117
|
+
});
|
|
118
|
+
|
|
119
|
+
test('is not shown for a number field', async () => {
|
|
120
|
+
await render(<AdvancedSettingsSubject format={numberFormat} withSchedules />);
|
|
121
|
+
|
|
122
|
+
expect(container.textContent).not.toContain(SWITCH_LABEL);
|
|
123
|
+
});
|
|
124
|
+
});
|
|
125
|
+
|
|
126
|
+
describe('in the options of an e-sign date signed offset', () => {
|
|
127
|
+
const renderOptions = (withSchedules: boolean) =>
|
|
128
|
+
render(
|
|
129
|
+
<ESignOptionsModal
|
|
130
|
+
initialState={{ rules: [{ days: 3 }] }}
|
|
131
|
+
onSave={() => {}}
|
|
132
|
+
businessCalendar={withSchedules ? businessCalendar : undefined}
|
|
133
|
+
/>,
|
|
134
|
+
);
|
|
135
|
+
|
|
136
|
+
test('is shown with a schedule context', async () => {
|
|
137
|
+
await renderOptions(true);
|
|
138
|
+
|
|
139
|
+
expect(container.textContent).toContain(SWITCH_LABEL);
|
|
140
|
+
});
|
|
141
|
+
|
|
142
|
+
test('is not shown without a schedule context', async () => {
|
|
143
|
+
await renderOptions(false);
|
|
144
|
+
|
|
145
|
+
expect(container.textContent).not.toContain(SWITCH_LABEL);
|
|
146
|
+
});
|
|
147
|
+
});
|
|
148
|
+
|
|
149
|
+
describe('in the config panel of an e-sign date signed offset field', () => {
|
|
150
|
+
const field = {
|
|
151
|
+
id: 'e1',
|
|
152
|
+
type: FieldTypeEnum.eSign,
|
|
153
|
+
subType: ESignFieldType.dateSignedOffset,
|
|
154
|
+
recipient: 'customer',
|
|
155
|
+
path: 'esign.customer.dateSignedOffset',
|
|
156
|
+
data: { rules: [{ days: 3 }] },
|
|
157
|
+
} as unknown as PdfField;
|
|
158
|
+
const onFieldConfigChange = jest.fn();
|
|
159
|
+
|
|
160
|
+
const renderPanel = (context?: typeof businessCalendar) =>
|
|
161
|
+
render(
|
|
162
|
+
<FieldConfigPanel
|
|
163
|
+
field={field}
|
|
164
|
+
recipients={[{ id: 1, name: 'customer', displayName: 'Customer' }]}
|
|
165
|
+
forms={[]}
|
|
166
|
+
hideConditionalLogic
|
|
167
|
+
businessCalendar={context}
|
|
168
|
+
onDeleteField={noOp}
|
|
169
|
+
onFieldConfigChange={onFieldConfigChange}
|
|
170
|
+
onRequestFormFields={noOp}
|
|
171
|
+
/>,
|
|
172
|
+
);
|
|
173
|
+
|
|
174
|
+
const findSwitch = () =>
|
|
175
|
+
[...container.querySelectorAll('input')].find(input =>
|
|
176
|
+
input.closest('label')?.textContent?.includes(SWITCH_LABEL),
|
|
177
|
+
);
|
|
178
|
+
|
|
179
|
+
beforeEach(() => onFieldConfigChange.mockClear());
|
|
180
|
+
|
|
181
|
+
test('is not shown without a schedule context', async () => {
|
|
182
|
+
await renderPanel();
|
|
183
|
+
|
|
184
|
+
expect(container.textContent).toContain('Number of days');
|
|
185
|
+
expect(container.textContent).not.toContain(SWITCH_LABEL);
|
|
186
|
+
});
|
|
187
|
+
|
|
188
|
+
test('is shown with a schedule context', async () => {
|
|
189
|
+
await renderPanel(businessCalendar);
|
|
190
|
+
|
|
191
|
+
expect(findSwitch()).toBeDefined();
|
|
192
|
+
});
|
|
193
|
+
|
|
194
|
+
test('stores the choice in the field data and does not call the context', async () => {
|
|
195
|
+
const onToggle = jest.fn();
|
|
196
|
+
await renderPanel({ ...businessCalendar, onToggle });
|
|
197
|
+
|
|
198
|
+
await act(async () => findSwitch()?.click());
|
|
199
|
+
|
|
200
|
+
expect(onFieldConfigChange).toHaveBeenCalledWith({
|
|
201
|
+
data: { rules: [{ days: 3 }], businessCalendarEnabled: true },
|
|
202
|
+
});
|
|
203
|
+
expect(onToggle).not.toHaveBeenCalled();
|
|
204
|
+
});
|
|
205
|
+
});
|
|
206
|
+
});
|
|
@@ -106,23 +106,32 @@ export const FieldConfigPanelOverlay: FC<FieldConfigPanelOverlayProps> = ({
|
|
|
106
106
|
[scheduleBindings, selectedFieldId, onScheduleBindingsChange],
|
|
107
107
|
);
|
|
108
108
|
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
109
|
+
/*
|
|
110
|
+
* The schedule UI (the Formula Builder's switch and the e-sign day offset's schedule) is offered
|
|
111
|
+
* only to a host that passes `onScheduleBindingsChange`. Without it there is no context, and
|
|
112
|
+
* everything that renders the schedule UI checks for one.
|
|
113
|
+
*/
|
|
114
|
+
const businessCalendar: ScheduleEditorContext | undefined = useMemo(
|
|
115
|
+
() =>
|
|
116
|
+
onScheduleBindingsChange
|
|
117
|
+
? {
|
|
118
|
+
enabled: !!selectedBinding,
|
|
119
|
+
selectedScheduleId: selectedBinding?.scheduleId,
|
|
120
|
+
onToggle: handleToggle,
|
|
121
|
+
onSelectSchedule: handleSelectSchedule,
|
|
122
|
+
holidayCatalog,
|
|
123
|
+
holidayCatalogLoading,
|
|
124
|
+
holidayCatalogError,
|
|
125
|
+
schedules,
|
|
126
|
+
schedulesLoading,
|
|
127
|
+
schedulesError,
|
|
128
|
+
onCreateSchedule,
|
|
129
|
+
onUpdateSchedule,
|
|
130
|
+
onDeleteSchedule,
|
|
131
|
+
}
|
|
132
|
+
: undefined,
|
|
125
133
|
[
|
|
134
|
+
onScheduleBindingsChange,
|
|
126
135
|
selectedBinding,
|
|
127
136
|
handleToggle,
|
|
128
137
|
handleSelectSchedule,
|
|
@@ -46,7 +46,7 @@ export interface PdfEditorProps {
|
|
|
46
46
|
/**
|
|
47
47
|
* Date calculated fields whose custom business-day exclusion toggle is on, and the schedule
|
|
48
48
|
* each uses (`PdfField.id` as `fieldKey`), as `PdfView`'s. Also drives the Formula Builder's
|
|
49
|
-
* toggle/picker for the selected field
|
|
49
|
+
* toggle/picker for the selected field, which are shown only with `onScheduleBindingsChange`.
|
|
50
50
|
*/
|
|
51
51
|
scheduleBindings?: FieldScheduleBinding[];
|
|
52
52
|
/** The tenant's known holidays, for the schedule editor's checklist. */
|
|
@@ -67,6 +67,11 @@ export interface PdfEditorProps {
|
|
|
67
67
|
* `PUT api/holidays/templates/{id}/bindings`). `PdfEditor` does not persist this itself —
|
|
68
68
|
* the host is expected to save it (and the bindings are typically saved separately from the
|
|
69
69
|
* template's own fields).
|
|
70
|
+
*
|
|
71
|
+
* Passing it also turns the schedule UI on: without it the Formula Builder has no "Exclude
|
|
72
|
+
* weekends & holidays" switch and the e-sign day offset has no schedule. A host that cannot save
|
|
73
|
+
* bindings (for example one without a tenant) leaves it out. It is not called for the e-sign
|
|
74
|
+
* schedule, which is stored in the field's `data`.
|
|
70
75
|
*/
|
|
71
76
|
onScheduleBindingsChange?(bindings: FieldScheduleBinding[]): void;
|
|
72
77
|
/**
|