@sprucelabs/spruce-form-utils 12.0.22 → 12.0.23
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/build/__tests__/support/formAssert.js +0 -1
- package/build/completing/FormPlayerCard.vc.js +0 -1
- package/build/completing/formCompletionCalculator.js +0 -1
- package/build/esm/__tests__/support/formAssert.d.ts +4 -0
- package/build/esm/__tests__/support/formAssert.js +11 -0
- package/build/esm/completing/FormPlayerCard.vc.d.ts +48 -0
- package/build/esm/completing/FormPlayerCard.vc.js +202 -0
- package/build/esm/completing/formCompletionCalculator.d.ts +5 -0
- package/build/esm/completing/formCompletionCalculator.js +53 -0
- package/build/esm/index-module.d.ts +4 -0
- package/build/esm/index-module.js +4 -0
- package/build/esm/types/types-module.d.ts +21 -0
- package/build/esm/types/types-module.js +1 -0
- package/build/index-module.js +0 -1
- package/build/types/types-module.js +0 -1
- package/package.json +1 -1
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { assert } from '@sprucelabs/test-utils';
|
|
2
|
+
const formAssert = {
|
|
3
|
+
valuesAreEqual(obj, form) {
|
|
4
|
+
assert.isEqual(JSON.stringify(obj, (key, value) => {
|
|
5
|
+
return value === null ? undefined : value;
|
|
6
|
+
}, 2), JSON.stringify(form, (key, value) => {
|
|
7
|
+
return value === null ? undefined : value;
|
|
8
|
+
}, 2));
|
|
9
|
+
},
|
|
10
|
+
};
|
|
11
|
+
export default formAssert;
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { AbstractViewController, FormViewController, SwipeCardViewController, ViewControllerOptions, Router } from '@sprucelabs/heartwood-view-controllers';
|
|
2
|
+
import { SpruceSchemas } from '@sprucelabs/spruce-core-schemas';
|
|
3
|
+
export default class FormPlayerCardViewController extends AbstractViewController<SpruceSchemas.HeartwoodViewControllers.v2021_02_11.Card> {
|
|
4
|
+
private swipeVc;
|
|
5
|
+
static id: string;
|
|
6
|
+
private onChangeHandler?;
|
|
7
|
+
private builderSource;
|
|
8
|
+
private shouldIgnoreChanges;
|
|
9
|
+
private router?;
|
|
10
|
+
constructor(options: FormPlayerCardViewControllerOptions & ViewControllerOptions);
|
|
11
|
+
private SwipeVc;
|
|
12
|
+
private handleSlideChange;
|
|
13
|
+
private renderFooter;
|
|
14
|
+
private handleClickSaveProgress;
|
|
15
|
+
private handleClickSaveAndDone;
|
|
16
|
+
private handleClickNext;
|
|
17
|
+
private renderHeader;
|
|
18
|
+
setIsBusy(isLoading: boolean): void;
|
|
19
|
+
private renderSlides;
|
|
20
|
+
private handleOnChange;
|
|
21
|
+
getHasCriticalError(): boolean;
|
|
22
|
+
getIsBusy(): boolean;
|
|
23
|
+
setCriticalError(err: SpruceSchemas.HeartwoodViewControllers.v2021_02_11.CriticalError): void;
|
|
24
|
+
getSwipeVc(): SwipeCardViewController;
|
|
25
|
+
load(options: PlayerLoadOptions): Promise<void>;
|
|
26
|
+
private updateFooter;
|
|
27
|
+
setValues(values: FormPlayerImportObject['values']): Promise<void>;
|
|
28
|
+
getValues(): Record<string, any>[];
|
|
29
|
+
getFormVcs(): FormViewController<any>[];
|
|
30
|
+
getFormVc(idx: number): FormViewController<any>;
|
|
31
|
+
getSourceBuilder(): Partial<FormPlayerImportObject>;
|
|
32
|
+
render(): SpruceSchemas.HeartwoodViewControllers.v2021_02_11.Card;
|
|
33
|
+
}
|
|
34
|
+
export declare type FormPlayerImportObject = SpruceSchemas.HeartwoodViewControllers.v2021_02_11.FormBuilderImportExportObject & {
|
|
35
|
+
values: Record<string, any>[];
|
|
36
|
+
};
|
|
37
|
+
declare type ChangeHandler = (options: {
|
|
38
|
+
values: Record<string, any>[];
|
|
39
|
+
}) => Promise<void> | void;
|
|
40
|
+
export declare type FormPlayerCardViewControllerOptions = Partial<FormPlayerImportObject> & {
|
|
41
|
+
onChange?: ChangeHandler;
|
|
42
|
+
isBusy?: boolean;
|
|
43
|
+
id?: string;
|
|
44
|
+
};
|
|
45
|
+
export declare type PlayerLoadOptions = Partial<FormPlayerImportObject> & {
|
|
46
|
+
router?: Router;
|
|
47
|
+
};
|
|
48
|
+
export {};
|
|
@@ -0,0 +1,202 @@
|
|
|
1
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
2
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
3
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
4
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
5
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
6
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
7
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
8
|
+
});
|
|
9
|
+
};
|
|
10
|
+
var __rest = (this && this.__rest) || function (s, e) {
|
|
11
|
+
var t = {};
|
|
12
|
+
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
|
|
13
|
+
t[p] = s[p];
|
|
14
|
+
if (s != null && typeof Object.getOwnPropertySymbols === "function")
|
|
15
|
+
for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
|
|
16
|
+
if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
|
|
17
|
+
t[p[i]] = s[p[i]];
|
|
18
|
+
}
|
|
19
|
+
return t;
|
|
20
|
+
};
|
|
21
|
+
import { AbstractViewController, removeUniversalViewOptions, } from '@sprucelabs/heartwood-view-controllers';
|
|
22
|
+
import { SchemaError } from '@sprucelabs/schema';
|
|
23
|
+
export default class FormPlayerCardViewController extends AbstractViewController {
|
|
24
|
+
constructor(options) {
|
|
25
|
+
super(options);
|
|
26
|
+
this.shouldIgnoreChanges = false;
|
|
27
|
+
const { onChange, isBusy, id } = options, builderSource = __rest(options, ["onChange", "isBusy", "id"]);
|
|
28
|
+
this.builderSource = removeUniversalViewOptions(builderSource);
|
|
29
|
+
this.swipeVc = this.SwipeVc(id, builderSource);
|
|
30
|
+
if (!options.pages || isBusy) {
|
|
31
|
+
this.swipeVc.setIsBusy(true);
|
|
32
|
+
}
|
|
33
|
+
else if (options.values) {
|
|
34
|
+
void this.setValues(options.values);
|
|
35
|
+
}
|
|
36
|
+
this.onChangeHandler = onChange;
|
|
37
|
+
}
|
|
38
|
+
SwipeVc(id, builderSource) {
|
|
39
|
+
return this.Controller('swipeCard', {
|
|
40
|
+
id,
|
|
41
|
+
header: this.renderHeader(builderSource),
|
|
42
|
+
slides: this.renderSlides(builderSource),
|
|
43
|
+
footer: this.renderFooter(),
|
|
44
|
+
onSlideChange: this.handleSlideChange.bind(this),
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
handleSlideChange() {
|
|
48
|
+
this.updateFooter();
|
|
49
|
+
}
|
|
50
|
+
renderFooter() {
|
|
51
|
+
var _a, _b, _c, _d;
|
|
52
|
+
const totalPages = (_b = (_a = this.builderSource.pages) === null || _a === void 0 ? void 0 : _a.length) !== null && _b !== void 0 ? _b : 0;
|
|
53
|
+
const currentPage = (_d = (_c = this.swipeVc) === null || _c === void 0 ? void 0 : _c.getPresentSlide()) !== null && _d !== void 0 ? _d : 0;
|
|
54
|
+
const buttons = [
|
|
55
|
+
{
|
|
56
|
+
id: 'saveProgress',
|
|
57
|
+
label: 'Save progress',
|
|
58
|
+
onClick: this.handleClickSaveProgress.bind(this),
|
|
59
|
+
},
|
|
60
|
+
];
|
|
61
|
+
if (totalPages === currentPage + 1) {
|
|
62
|
+
buttons.push({
|
|
63
|
+
id: 'save',
|
|
64
|
+
label: 'Save and be done',
|
|
65
|
+
type: 'primary',
|
|
66
|
+
onClick: this.handleClickSaveAndDone.bind(this),
|
|
67
|
+
});
|
|
68
|
+
}
|
|
69
|
+
else {
|
|
70
|
+
buttons.push({
|
|
71
|
+
id: 'next',
|
|
72
|
+
label: 'Next page',
|
|
73
|
+
type: 'primary',
|
|
74
|
+
onClick: this.handleClickNext.bind(this),
|
|
75
|
+
});
|
|
76
|
+
}
|
|
77
|
+
return {
|
|
78
|
+
buttons,
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
handleClickSaveProgress() {
|
|
82
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
83
|
+
yield this.alert({
|
|
84
|
+
message: `Progress saved! 💪`,
|
|
85
|
+
style: 'success',
|
|
86
|
+
});
|
|
87
|
+
});
|
|
88
|
+
}
|
|
89
|
+
handleClickSaveAndDone() {
|
|
90
|
+
var _a;
|
|
91
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
92
|
+
yield this.alert({
|
|
93
|
+
message: `Progress saved, lets get outa here! 🚀`,
|
|
94
|
+
style: 'success',
|
|
95
|
+
});
|
|
96
|
+
yield ((_a = this.router) === null || _a === void 0 ? void 0 : _a.redirect('profile.root'));
|
|
97
|
+
});
|
|
98
|
+
}
|
|
99
|
+
handleClickNext() {
|
|
100
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
101
|
+
yield this.swipeVc.jumpToSlide(this.swipeVc.getPresentSlide() + 1);
|
|
102
|
+
});
|
|
103
|
+
}
|
|
104
|
+
renderHeader(options) {
|
|
105
|
+
var _a;
|
|
106
|
+
return {
|
|
107
|
+
title: (_a = options.title) !== null && _a !== void 0 ? _a : 'Loading your form...',
|
|
108
|
+
subtitle: options.subtitle,
|
|
109
|
+
};
|
|
110
|
+
}
|
|
111
|
+
setIsBusy(isLoading) {
|
|
112
|
+
this.swipeVc.setIsBusy(isLoading);
|
|
113
|
+
}
|
|
114
|
+
renderSlides(options) {
|
|
115
|
+
var _a, _b;
|
|
116
|
+
return ((_b = (_a = options.pages) === null || _a === void 0 ? void 0 : _a.map((_a) => {
|
|
117
|
+
var { title } = _a, form = __rest(_a, ["title"]);
|
|
118
|
+
return ({
|
|
119
|
+
title,
|
|
120
|
+
form: this.Controller('form', Object.assign(Object.assign({}, form), { shouldShowSubmitControls: false, onChange: () => __awaiter(this, void 0, void 0, function* () {
|
|
121
|
+
yield this.handleOnChange();
|
|
122
|
+
}) })).render(),
|
|
123
|
+
});
|
|
124
|
+
})) !== null && _b !== void 0 ? _b : []);
|
|
125
|
+
}
|
|
126
|
+
handleOnChange() {
|
|
127
|
+
var _a;
|
|
128
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
129
|
+
if (!this.shouldIgnoreChanges) {
|
|
130
|
+
yield ((_a = this.onChangeHandler) === null || _a === void 0 ? void 0 : _a.call(this, { values: this.getValues() }));
|
|
131
|
+
}
|
|
132
|
+
});
|
|
133
|
+
}
|
|
134
|
+
getHasCriticalError() {
|
|
135
|
+
return this.swipeVc.getHasCriticalError();
|
|
136
|
+
}
|
|
137
|
+
getIsBusy() {
|
|
138
|
+
return this.swipeVc.isBusy();
|
|
139
|
+
}
|
|
140
|
+
setCriticalError(err) {
|
|
141
|
+
this.swipeVc.setCriticalError(err);
|
|
142
|
+
}
|
|
143
|
+
getSwipeVc() {
|
|
144
|
+
return this.swipeVc;
|
|
145
|
+
}
|
|
146
|
+
load(options) {
|
|
147
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
148
|
+
const { router } = options, source = __rest(options, ["router"]);
|
|
149
|
+
const { title, subtitle } = this.renderHeader(source);
|
|
150
|
+
this.router = router;
|
|
151
|
+
this.swipeVc.setHeaderTitle(title !== null && title !== void 0 ? title : null);
|
|
152
|
+
this.swipeVc.setHeaderSubtitle(subtitle !== null && subtitle !== void 0 ? subtitle : null);
|
|
153
|
+
this.swipeVc.setSections(this.renderSlides(source));
|
|
154
|
+
if (source.values) {
|
|
155
|
+
yield this.setValues(source.values);
|
|
156
|
+
}
|
|
157
|
+
this.builderSource = source;
|
|
158
|
+
this.updateFooter();
|
|
159
|
+
this.swipeVc.setIsBusy(false);
|
|
160
|
+
});
|
|
161
|
+
}
|
|
162
|
+
updateFooter() {
|
|
163
|
+
this.swipeVc.setFooter(this.router ? this.renderFooter() : null);
|
|
164
|
+
}
|
|
165
|
+
setValues(values) {
|
|
166
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
167
|
+
if (!Array.isArray(values)) {
|
|
168
|
+
throw new Error('values must be an array!');
|
|
169
|
+
}
|
|
170
|
+
const vcs = this.getFormVcs();
|
|
171
|
+
this.shouldIgnoreChanges = true;
|
|
172
|
+
yield Promise.all(values.map((v, idx) => __awaiter(this, void 0, void 0, function* () { return vcs[idx].setValues(v); })));
|
|
173
|
+
this.shouldIgnoreChanges = false;
|
|
174
|
+
yield this.handleOnChange();
|
|
175
|
+
});
|
|
176
|
+
}
|
|
177
|
+
getValues() {
|
|
178
|
+
return this.getFormVcs().map((vc) => vc.getValues());
|
|
179
|
+
}
|
|
180
|
+
getFormVcs() {
|
|
181
|
+
var _a, _b;
|
|
182
|
+
return ((_b = (_a = this.swipeVc.getSlides()) === null || _a === void 0 ? void 0 : _a.map((s) => { var _a; return (_a = s.form) === null || _a === void 0 ? void 0 : _a.controller; })) !== null && _b !== void 0 ? _b : []);
|
|
183
|
+
}
|
|
184
|
+
getFormVc(idx) {
|
|
185
|
+
const formVc = this.getFormVcs()[idx];
|
|
186
|
+
if (!formVc) {
|
|
187
|
+
throw new SchemaError({
|
|
188
|
+
code: 'INVALID_PARAMETERS',
|
|
189
|
+
friendlyMessage: `I couldn't find a form at index ${idx}.`,
|
|
190
|
+
parameters: ['formIdx'],
|
|
191
|
+
});
|
|
192
|
+
}
|
|
193
|
+
return formVc;
|
|
194
|
+
}
|
|
195
|
+
getSourceBuilder() {
|
|
196
|
+
return this.builderSource;
|
|
197
|
+
}
|
|
198
|
+
render() {
|
|
199
|
+
return this.swipeVc.render();
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
FormPlayerCardViewController.id = 'form-player-card';
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { assertOptions, SchemaError } from '@sprucelabs/schema';
|
|
2
|
+
function validateOptions(pages, values) {
|
|
3
|
+
assertOptions({
|
|
4
|
+
pages,
|
|
5
|
+
values,
|
|
6
|
+
}, ['pages', 'values']);
|
|
7
|
+
if (!Array.isArray(pages)) {
|
|
8
|
+
throw new SchemaError({
|
|
9
|
+
code: 'INVALID_PARAMETERS',
|
|
10
|
+
parameters: ['pages'],
|
|
11
|
+
friendlyMessage: 'pages must be an array',
|
|
12
|
+
});
|
|
13
|
+
}
|
|
14
|
+
if (!Array.isArray(values)) {
|
|
15
|
+
throw new SchemaError({
|
|
16
|
+
code: 'INVALID_PARAMETERS',
|
|
17
|
+
parameters: ['values'],
|
|
18
|
+
friendlyMessage: 'values must be an array',
|
|
19
|
+
});
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
const formCompletionCalculator = {
|
|
23
|
+
calculate(pages, values) {
|
|
24
|
+
var _a, _b, _c, _d;
|
|
25
|
+
validateOptions(pages, values);
|
|
26
|
+
const requiredFields = [];
|
|
27
|
+
let totalFields = 0;
|
|
28
|
+
for (const page of pages) {
|
|
29
|
+
const fields = (_a = page.schema.fields) !== null && _a !== void 0 ? _a : {};
|
|
30
|
+
for (const section of page.sections) {
|
|
31
|
+
for (const field of (_b = section.fields) !== null && _b !== void 0 ? _b : []) {
|
|
32
|
+
const fieldKey = (_c = field.name) !== null && _c !== void 0 ? _c : field;
|
|
33
|
+
const f = (_d = fields[fieldKey]) !== null && _d !== void 0 ? _d : {};
|
|
34
|
+
if (f.isRequired) {
|
|
35
|
+
totalFields++;
|
|
36
|
+
requiredFields.push(fieldKey);
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
if (totalFields === 0) {
|
|
42
|
+
return 1;
|
|
43
|
+
}
|
|
44
|
+
let totalAnswered = 0;
|
|
45
|
+
for (const value of values) {
|
|
46
|
+
totalAnswered += Object.keys(value !== null && value !== void 0 ? value : {}).filter((k) => {
|
|
47
|
+
return !!value[k] && requiredFields.indexOf(k) !== -1;
|
|
48
|
+
}).length;
|
|
49
|
+
}
|
|
50
|
+
return parseFloat((totalAnswered / totalFields).toFixed(2));
|
|
51
|
+
},
|
|
52
|
+
};
|
|
53
|
+
export default formCompletionCalculator;
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
export { default as formAssert } from './__tests__/support/formAssert';
|
|
2
|
+
export { default as formCompletionCalculator } from './completing/formCompletionCalculator';
|
|
3
|
+
export { default as FormPlayerCardViewController } from './completing/FormPlayerCard.vc';
|
|
4
|
+
export * from './types/types-module';
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
export { default as formAssert } from './__tests__/support/formAssert.js';
|
|
2
|
+
export { default as formCompletionCalculator } from './completing/formCompletionCalculator.js';
|
|
3
|
+
export { default as FormPlayerCardViewController } from './completing/FormPlayerCard.vc.js';
|
|
4
|
+
export * from './types/types-module.js';
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { Scope, SpruceSchemas, ViewController } from '@sprucelabs/heartwood-view-controllers';
|
|
2
|
+
import FormPlayerCardViewController, { FormPlayerCardViewControllerOptions } from '../completing/FormPlayerCard.vc';
|
|
3
|
+
declare type Card = SpruceSchemas.HeartwoodViewControllers.v2021_02_11.Card;
|
|
4
|
+
export declare type UpdateForm = SpruceSchemas.Forms.v2021_07_02.UpdateForm;
|
|
5
|
+
export interface RemoteFormBuilderCardLoadOptions {
|
|
6
|
+
scope: Scope;
|
|
7
|
+
formId?: string;
|
|
8
|
+
}
|
|
9
|
+
export interface RemoteFormBuilderCard extends ViewController<Card> {
|
|
10
|
+
load?(options: RemoteFormBuilderCardLoadOptions): Promise<void>;
|
|
11
|
+
didSaveForm?(form: UpdateForm): Promise<void>;
|
|
12
|
+
}
|
|
13
|
+
declare module '@sprucelabs/heartwood-view-controllers/build/types/heartwood.types' {
|
|
14
|
+
interface ViewControllerMap {
|
|
15
|
+
formPlayerCard: FormPlayerCardViewController;
|
|
16
|
+
}
|
|
17
|
+
interface ViewControllerOptionsMap {
|
|
18
|
+
formPlayerCard: FormPlayerCardViewControllerOptions;
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
package/build/index-module.js
CHANGED
|
@@ -25,4 +25,3 @@ Object.defineProperty(exports, "formCompletionCalculator", { enumerable: true, g
|
|
|
25
25
|
var FormPlayerCard_vc_1 = require("./completing/FormPlayerCard.vc");
|
|
26
26
|
Object.defineProperty(exports, "FormPlayerCardViewController", { enumerable: true, get: function () { return __importDefault(FormPlayerCard_vc_1).default; } });
|
|
27
27
|
__exportStar(require("./types/types-module"), exports);
|
|
28
|
-
//# sourceMappingURL=index-module.js.map
|