@mindful-web/marko-web-identity-x 1.85.2 → 1.85.4
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/CLAUDE.md +19 -18
- package/browser/custom-column.vue +7 -2
- package/components/access.marko.js +2 -2
- package/components/comment-stream.marko.js +2 -2
- package/components/context.marko.js +2 -2
- package/components/form-access.marko.js +2 -2
- package/components/form-authenticate.marko.js +2 -2
- package/components/form-change-email.marko.js +2 -2
- package/components/form-login.marko.js +2 -2
- package/components/form-logout.marko.js +2 -2
- package/components/form-profile.marko.js +2 -2
- package/components/form-register.marko.js +2 -2
- package/components/google-init.marko.js +2 -2
- package/components/google-sign-in-button.marko.js +2 -2
- package/components/identify.marko.js +2 -2
- package/components/non-auth-identify.marko.js +2 -2
- package/components/progressive-profile-form.marko.js +2 -2
- package/components/subscribe.marko.js +2 -2
- package/config.js +6 -6
- package/package.json +7 -3
- package/routes/change-email-confirm.js +2 -0
- package/routes/profile.js +8 -4
- package/test/mocha.opts +2 -0
- package/test/utils/generate-required-field-payload.spec.js +92 -0
- package/test/utils/get-form-custom-fields.spec.js +76 -0
- package/utils/generate-required-field-payload.js +27 -14
- package/utils/get-form-custom-fields.js +19 -28
package/CLAUDE.md
CHANGED
|
@@ -348,7 +348,7 @@ configurations that are each a user-facing trap:
|
|
|
348
348
|
| Boot check | Why the runtime failure is worse than a failed deploy |
|
|
349
349
|
| --- | --- |
|
|
350
350
|
| `type: 'built-in'` | Unwritable ⇒ permanent gate loop. **Silent** — the only one of these with no visible symptom until a user is stuck. |
|
|
351
|
-
| `type: 'custom-boolean'` |
|
|
351
|
+
| `type: 'custom-boolean'` | The renderer bug that once made it unsatisfiable is fixed, but the gate forces every column `required: true`, and a *required* HTML5 checkbox can only ever be submitted checked — a progressive boolean could only ever record `true`, a toll rather than an answer. Re-allow only if the gate ever supports optional columns or explicit yes/no booleans. |
|
|
352
352
|
| any other type | Falls through to `custom-column.vue`'s `<pre v-else>` debug block, printing raw field metadata to a real visitor. |
|
|
353
353
|
| id missing from a non-empty `activeCustomFieldIds` | `routes/profile.js:88-104` silently discards the answer ⇒ gate loop. |
|
|
354
354
|
| rows configured with no `apiToken` | Every write uses `getOrgUserApiToken()` and the form token is signed from it. |
|
|
@@ -358,11 +358,11 @@ No coverage is lost: every field the fleet-wide impact analysis measured is a se
|
|
|
358
358
|
### Files
|
|
359
359
|
|
|
360
360
|
- `utils/get-missing-progressive-fields.js` — the diff. Matches on **`answer.field.id`**, never
|
|
361
|
-
`answer.id`. That distinction is
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
`
|
|
361
|
+
`answer.id`. That distinction is why this feature did not reuse `get-form-custom-fields.js`
|
|
362
|
+
(or `config.getGTMUserData`) at ship time: that util keyed on the answer's own `id` and its
|
|
363
|
+
truthy-empty-array check returned answer objects with no `field` — both fixed in
|
|
364
|
+
mindful-web#324, but the dedicated util stays (it also forces every column `required: true` in
|
|
365
|
+
the `missingRows` it returns, so `custom-column.vue` needs no changes).
|
|
366
366
|
- `utils/get-progressive-form-fields.js` — correct, feature-scoped replacement for
|
|
367
367
|
`get-form-custom-fields.js`. Stamps `id` with the **field** id, which is the contract
|
|
368
368
|
`custom-column.vue` reads and what `get-create-user-custom-fields.js` already emits.
|
|
@@ -612,18 +612,19 @@ reaches the bridge. The content entity is passed as `emit`'s third argument inst
|
|
|
612
612
|
Submitted **answer values are never tracked** anywhere — `fieldKeys` and the member-event's
|
|
613
613
|
`fieldIds` record which questions were asked, nothing more.
|
|
614
614
|
|
|
615
|
-
###
|
|
616
|
-
|
|
617
|
-
1.
|
|
618
|
-
`
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
615
|
+
### Follow-ups — both resolved 2026-08-15
|
|
616
|
+
|
|
617
|
+
1. ✅ **Index drop/recreate, production** — done. Both `completed_auth_*` indexes in production
|
|
618
|
+
carry `PROGRESSIVE_PROFILE_SUBMIT` in their partial filters (verified on `audience:abmedia`
|
|
619
|
+
and `audience:transpire`).
|
|
620
|
+
2. ✅ **The shared-code PR** — landed as mindful-web#324 (this package: `get-form-custom-fields.js`
|
|
621
|
+
field-id keying, `custom-column.vue` boolean binding, `routes/profile.js` allowlist,
|
|
622
|
+
`generate-required-field-payload.js` boolean branches + `hasAnswered` false-boolean fix) and
|
|
623
|
+
mindful-web#325 (the p1events bridge's `contentGatingType`→`contentGateType` rename — the gate
|
|
624
|
+
type had never reached p1events on any conversion event). The allured copied-meter frozen-clock
|
|
625
|
+
bug went separately as allured-business-media-websites#461. Progressive-profile field rows
|
|
626
|
+
still exclude `custom-boolean` — no longer for the renderer bug, but because the gate forces
|
|
627
|
+
required columns and a required checkbox can only submit `true` (see the boot-check table).
|
|
627
628
|
|
|
628
629
|
## Fleet / rollout
|
|
629
630
|
|
|
@@ -353,9 +353,14 @@ export default {
|
|
|
353
353
|
/**
|
|
354
354
|
*
|
|
355
355
|
*/
|
|
356
|
-
onCustomBooleanChange(field) {
|
|
356
|
+
onCustomBooleanChange(field, checked) {
|
|
357
|
+
// `.answer` is canonical (it's what the template binds and what `routes/profile.js`
|
|
358
|
+
// reads); `.value` is kept in sync because the payload builders read it. Assign from the
|
|
359
|
+
// emitted event rather than toggling, so the model can never invert against the checkbox.
|
|
357
360
|
// eslint-disable-next-line no-param-reassign
|
|
358
|
-
field.
|
|
361
|
+
field.answer = checked;
|
|
362
|
+
// eslint-disable-next-line no-param-reassign
|
|
363
|
+
field.value = checked;
|
|
359
364
|
// eslint-disable-next-line no-param-reassign
|
|
360
365
|
field.hasAnswered = true;
|
|
361
366
|
this.user.customBooleanFieldAnswers = this.customBooleanFieldAnswers;
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"use strict";
|
|
3
3
|
|
|
4
4
|
var marko_template = module.exports = require("marko/dist/html").t(__filename),
|
|
5
|
-
marko_componentType = "/@mindful-web/marko-web-identity-x$1.85.
|
|
5
|
+
marko_componentType = "/@mindful-web/marko-web-identity-x$1.85.4/components/access.marko",
|
|
6
6
|
marko_component = require("./access.marko"),
|
|
7
7
|
marko_renderer = require("marko/dist/runtime/components/renderer"),
|
|
8
8
|
module_objectPath_module = require("@mindful-web/object-path"),
|
|
@@ -53,7 +53,7 @@ marko_template._ = marko_renderer(render, {
|
|
|
53
53
|
}, marko_component);
|
|
54
54
|
|
|
55
55
|
marko_template.meta = {
|
|
56
|
-
id: "/@mindful-web/marko-web-identity-x$1.85.
|
|
56
|
+
id: "/@mindful-web/marko-web-identity-x$1.85.4/components/access.marko",
|
|
57
57
|
component: "./access.marko",
|
|
58
58
|
tags: [
|
|
59
59
|
"@mindful-web/marko-core/components/resolve.marko"
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"use strict";
|
|
3
3
|
|
|
4
4
|
var marko_template = module.exports = require("marko/dist/html").t(__filename),
|
|
5
|
-
marko_componentType = "/@mindful-web/marko-web-identity-x$1.85.
|
|
5
|
+
marko_componentType = "/@mindful-web/marko-web-identity-x$1.85.4/components/comment-stream.marko",
|
|
6
6
|
marko_component = require("./comment-stream.marko"),
|
|
7
7
|
marko_renderer = require("marko/dist/runtime/components/renderer"),
|
|
8
8
|
module_objectPath_module = require("@mindful-web/object-path"),
|
|
@@ -91,7 +91,7 @@ marko_template._ = marko_renderer(render, {
|
|
|
91
91
|
}, marko_component);
|
|
92
92
|
|
|
93
93
|
marko_template.meta = {
|
|
94
|
-
id: "/@mindful-web/marko-web-identity-x$1.85.
|
|
94
|
+
id: "/@mindful-web/marko-web-identity-x$1.85.4/components/comment-stream.marko",
|
|
95
95
|
component: "./comment-stream.marko",
|
|
96
96
|
tags: [
|
|
97
97
|
"@mindful-web/marko-web/components/browser-component.marko",
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"use strict";
|
|
3
3
|
|
|
4
4
|
var marko_template = module.exports = require("marko/dist/html").t(__filename),
|
|
5
|
-
marko_componentType = "/@mindful-web/marko-web-identity-x$1.85.
|
|
5
|
+
marko_componentType = "/@mindful-web/marko-web-identity-x$1.85.4/components/context.marko",
|
|
6
6
|
marko_component = require("./context.marko"),
|
|
7
7
|
marko_renderer = require("marko/dist/runtime/components/renderer"),
|
|
8
8
|
marko_dynamicTag = require("marko/dist/runtime/helpers/dynamic-tag"),
|
|
@@ -49,7 +49,7 @@ marko_template._ = marko_renderer(render, {
|
|
|
49
49
|
}, marko_component);
|
|
50
50
|
|
|
51
51
|
marko_template.meta = {
|
|
52
|
-
id: "/@mindful-web/marko-web-identity-x$1.85.
|
|
52
|
+
id: "/@mindful-web/marko-web-identity-x$1.85.4/components/context.marko",
|
|
53
53
|
component: "./context.marko",
|
|
54
54
|
tags: [
|
|
55
55
|
"@mindful-web/marko-core/components/resolve.marko"
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"use strict";
|
|
3
3
|
|
|
4
4
|
var marko_template = module.exports = require("marko/dist/html").t(__filename),
|
|
5
|
-
marko_componentType = "/@mindful-web/marko-web-identity-x$1.85.
|
|
5
|
+
marko_componentType = "/@mindful-web/marko-web-identity-x$1.85.4/components/form-access.marko",
|
|
6
6
|
marko_component = require("./form-access.marko"),
|
|
7
7
|
marko_renderer = require("marko/dist/runtime/components/renderer"),
|
|
8
8
|
module_defaultValue = require("@mindful-web/marko-core/utils/default-value"),
|
|
@@ -179,7 +179,7 @@ marko_template._ = marko_renderer(render, {
|
|
|
179
179
|
}, marko_component);
|
|
180
180
|
|
|
181
181
|
marko_template.meta = {
|
|
182
|
-
id: "/@mindful-web/marko-web-identity-x$1.85.
|
|
182
|
+
id: "/@mindful-web/marko-web-identity-x$1.85.4/components/form-access.marko",
|
|
183
183
|
component: "./form-access.marko",
|
|
184
184
|
tags: [
|
|
185
185
|
"@mindful-web/marko-web/components/browser-component.marko",
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"use strict";
|
|
3
3
|
|
|
4
4
|
var marko_template = module.exports = require("marko/dist/html").t(__filename),
|
|
5
|
-
marko_componentType = "/@mindful-web/marko-web-identity-x$1.85.
|
|
5
|
+
marko_componentType = "/@mindful-web/marko-web-identity-x$1.85.4/components/form-authenticate.marko",
|
|
6
6
|
marko_component = require("./form-authenticate.marko"),
|
|
7
7
|
marko_renderer = require("marko/dist/runtime/components/renderer"),
|
|
8
8
|
module_objectPath_module = require("@mindful-web/object-path"),
|
|
@@ -81,7 +81,7 @@ marko_template._ = marko_renderer(render, {
|
|
|
81
81
|
}, marko_component);
|
|
82
82
|
|
|
83
83
|
marko_template.meta = {
|
|
84
|
-
id: "/@mindful-web/marko-web-identity-x$1.85.
|
|
84
|
+
id: "/@mindful-web/marko-web-identity-x$1.85.4/components/form-authenticate.marko",
|
|
85
85
|
component: "./form-authenticate.marko",
|
|
86
86
|
tags: [
|
|
87
87
|
"@mindful-web/marko-web/components/browser-component.marko",
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"use strict";
|
|
3
3
|
|
|
4
4
|
var marko_template = module.exports = require("marko/dist/html").t(__filename),
|
|
5
|
-
marko_componentType = "/@mindful-web/marko-web-identity-x$1.85.
|
|
5
|
+
marko_componentType = "/@mindful-web/marko-web-identity-x$1.85.4/components/form-change-email.marko",
|
|
6
6
|
marko_component = require("./form-change-email.marko"),
|
|
7
7
|
marko_renderer = require("marko/dist/runtime/components/renderer"),
|
|
8
8
|
module_objectPath_module = require("@mindful-web/object-path"),
|
|
@@ -59,7 +59,7 @@ marko_template._ = marko_renderer(render, {
|
|
|
59
59
|
}, marko_component);
|
|
60
60
|
|
|
61
61
|
marko_template.meta = {
|
|
62
|
-
id: "/@mindful-web/marko-web-identity-x$1.85.
|
|
62
|
+
id: "/@mindful-web/marko-web-identity-x$1.85.4/components/form-change-email.marko",
|
|
63
63
|
component: "./form-change-email.marko",
|
|
64
64
|
tags: [
|
|
65
65
|
"@mindful-web/marko-web/components/browser-component.marko",
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"use strict";
|
|
3
3
|
|
|
4
4
|
var marko_template = module.exports = require("marko/dist/html").t(__filename),
|
|
5
|
-
marko_componentType = "/@mindful-web/marko-web-identity-x$1.85.
|
|
5
|
+
marko_componentType = "/@mindful-web/marko-web-identity-x$1.85.4/components/form-login.marko",
|
|
6
6
|
marko_component = require("./form-login.marko"),
|
|
7
7
|
marko_renderer = require("marko/dist/runtime/components/renderer"),
|
|
8
8
|
module_objectPath_module = require("@mindful-web/object-path"),
|
|
@@ -92,7 +92,7 @@ marko_template._ = marko_renderer(render, {
|
|
|
92
92
|
}, marko_component);
|
|
93
93
|
|
|
94
94
|
marko_template.meta = {
|
|
95
|
-
id: "/@mindful-web/marko-web-identity-x$1.85.
|
|
95
|
+
id: "/@mindful-web/marko-web-identity-x$1.85.4/components/form-login.marko",
|
|
96
96
|
component: "./form-login.marko",
|
|
97
97
|
tags: [
|
|
98
98
|
"@mindful-web/marko-web/components/browser-component.marko",
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"use strict";
|
|
3
3
|
|
|
4
4
|
var marko_template = module.exports = require("marko/dist/html").t(__filename),
|
|
5
|
-
marko_componentType = "/@mindful-web/marko-web-identity-x$1.85.
|
|
5
|
+
marko_componentType = "/@mindful-web/marko-web-identity-x$1.85.4/components/form-logout.marko",
|
|
6
6
|
marko_renderer = require("marko/dist/runtime/components/renderer"),
|
|
7
7
|
module_defaultValue = require("@mindful-web/marko-core/utils/default-value"),
|
|
8
8
|
defaultValue = module_defaultValue.default || module_defaultValue,
|
|
@@ -29,7 +29,7 @@ marko_template._ = marko_renderer(render, {
|
|
|
29
29
|
});
|
|
30
30
|
|
|
31
31
|
marko_template.meta = {
|
|
32
|
-
id: "/@mindful-web/marko-web-identity-x$1.85.
|
|
32
|
+
id: "/@mindful-web/marko-web-identity-x$1.85.4/components/form-logout.marko",
|
|
33
33
|
tags: [
|
|
34
34
|
"@mindful-web/marko-web/components/browser-component.marko"
|
|
35
35
|
]
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"use strict";
|
|
3
3
|
|
|
4
4
|
var marko_template = module.exports = require("marko/dist/html").t(__filename),
|
|
5
|
-
marko_componentType = "/@mindful-web/marko-web-identity-x$1.85.
|
|
5
|
+
marko_componentType = "/@mindful-web/marko-web-identity-x$1.85.4/components/form-profile.marko",
|
|
6
6
|
marko_component = require("./form-profile.marko"),
|
|
7
7
|
marko_renderer = require("marko/dist/runtime/components/renderer"),
|
|
8
8
|
module_objectPath_module = require("@mindful-web/object-path"),
|
|
@@ -84,7 +84,7 @@ marko_template._ = marko_renderer(render, {
|
|
|
84
84
|
}, marko_component);
|
|
85
85
|
|
|
86
86
|
marko_template.meta = {
|
|
87
|
-
id: "/@mindful-web/marko-web-identity-x$1.85.
|
|
87
|
+
id: "/@mindful-web/marko-web-identity-x$1.85.4/components/form-profile.marko",
|
|
88
88
|
component: "./form-profile.marko",
|
|
89
89
|
tags: [
|
|
90
90
|
"@mindful-web/marko-web/components/browser-component.marko",
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"use strict";
|
|
3
3
|
|
|
4
4
|
var marko_template = module.exports = require("marko/dist/html").t(__filename),
|
|
5
|
-
marko_componentType = "/@mindful-web/marko-web-identity-x$1.85.
|
|
5
|
+
marko_componentType = "/@mindful-web/marko-web-identity-x$1.85.4/components/form-register.marko",
|
|
6
6
|
marko_renderer = require("marko/dist/runtime/components/renderer"),
|
|
7
7
|
marko_assign = require("marko/dist/runtime/helpers/assign"),
|
|
8
8
|
marko_web_identity_x_form_login_template = require("./form-login.marko"),
|
|
@@ -25,7 +25,7 @@ marko_template._ = marko_renderer(render, {
|
|
|
25
25
|
});
|
|
26
26
|
|
|
27
27
|
marko_template.meta = {
|
|
28
|
-
id: "/@mindful-web/marko-web-identity-x$1.85.
|
|
28
|
+
id: "/@mindful-web/marko-web-identity-x$1.85.4/components/form-register.marko",
|
|
29
29
|
tags: [
|
|
30
30
|
"./form-login.marko"
|
|
31
31
|
]
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"use strict";
|
|
3
3
|
|
|
4
4
|
var marko_template = module.exports = require("marko/dist/html").t(__filename),
|
|
5
|
-
marko_componentType = "/@mindful-web/marko-web-identity-x$1.85.
|
|
5
|
+
marko_componentType = "/@mindful-web/marko-web-identity-x$1.85.4/components/google-init.marko",
|
|
6
6
|
marko_renderer = require("marko/dist/runtime/components/renderer"),
|
|
7
7
|
marko_attr = require("marko/dist/runtime/html/helpers/attr"),
|
|
8
8
|
marko_str = require("marko/dist/runtime/helpers/to-string");
|
|
@@ -239,5 +239,5 @@ marko_template._ = marko_renderer(render, {
|
|
|
239
239
|
});
|
|
240
240
|
|
|
241
241
|
marko_template.meta = {
|
|
242
|
-
id: "/@mindful-web/marko-web-identity-x$1.85.
|
|
242
|
+
id: "/@mindful-web/marko-web-identity-x$1.85.4/components/google-init.marko"
|
|
243
243
|
};
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"use strict";
|
|
3
3
|
|
|
4
4
|
var marko_template = module.exports = require("marko/dist/html").t(__filename),
|
|
5
|
-
marko_componentType = "/@mindful-web/marko-web-identity-x$1.85.
|
|
5
|
+
marko_componentType = "/@mindful-web/marko-web-identity-x$1.85.4/components/google-sign-in-button.marko",
|
|
6
6
|
marko_renderer = require("marko/dist/runtime/components/renderer"),
|
|
7
7
|
helpers_escape_xml = require("marko/dist/runtime/html/helpers/escape-xml"),
|
|
8
8
|
marko_escapeXml = helpers_escape_xml.x,
|
|
@@ -40,5 +40,5 @@ marko_template._ = marko_renderer(render, {
|
|
|
40
40
|
});
|
|
41
41
|
|
|
42
42
|
marko_template.meta = {
|
|
43
|
-
id: "/@mindful-web/marko-web-identity-x$1.85.
|
|
43
|
+
id: "/@mindful-web/marko-web-identity-x$1.85.4/components/google-sign-in-button.marko"
|
|
44
44
|
};
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"use strict";
|
|
3
3
|
|
|
4
4
|
var marko_template = module.exports = require("marko/dist/html").t(__filename),
|
|
5
|
-
marko_componentType = "/@mindful-web/marko-web-identity-x$1.85.
|
|
5
|
+
marko_componentType = "/@mindful-web/marko-web-identity-x$1.85.4/components/identify.marko",
|
|
6
6
|
marko_component = require("./identify.marko"),
|
|
7
7
|
marko_renderer = require("marko/dist/runtime/components/renderer"),
|
|
8
8
|
module_objectPath_module = require("@mindful-web/object-path"),
|
|
@@ -50,7 +50,7 @@ marko_template._ = marko_renderer(render, {
|
|
|
50
50
|
}, marko_component);
|
|
51
51
|
|
|
52
52
|
marko_template.meta = {
|
|
53
|
-
id: "/@mindful-web/marko-web-identity-x$1.85.
|
|
53
|
+
id: "/@mindful-web/marko-web-identity-x$1.85.4/components/identify.marko",
|
|
54
54
|
component: "./identify.marko",
|
|
55
55
|
tags: [
|
|
56
56
|
"@mindful-web/marko-web-gtm/components/push.marko",
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"use strict";
|
|
3
3
|
|
|
4
4
|
var marko_template = module.exports = require("marko/dist/html").t(__filename),
|
|
5
|
-
marko_componentType = "/@mindful-web/marko-web-identity-x$1.85.
|
|
5
|
+
marko_componentType = "/@mindful-web/marko-web-identity-x$1.85.4/components/non-auth-identify.marko",
|
|
6
6
|
marko_component = require("./non-auth-identify.marko"),
|
|
7
7
|
marko_renderer = require("marko/dist/runtime/components/renderer"),
|
|
8
8
|
marko_dynamicTag = require("marko/dist/runtime/helpers/dynamic-tag"),
|
|
@@ -45,7 +45,7 @@ marko_template._ = marko_renderer(render, {
|
|
|
45
45
|
}, marko_component);
|
|
46
46
|
|
|
47
47
|
marko_template.meta = {
|
|
48
|
-
id: "/@mindful-web/marko-web-identity-x$1.85.
|
|
48
|
+
id: "/@mindful-web/marko-web-identity-x$1.85.4/components/non-auth-identify.marko",
|
|
49
49
|
component: "./non-auth-identify.marko",
|
|
50
50
|
tags: [
|
|
51
51
|
"@mindful-web/marko-core/components/resolve.marko"
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"use strict";
|
|
3
3
|
|
|
4
4
|
var marko_template = module.exports = require("marko/dist/html").t(__filename),
|
|
5
|
-
marko_componentType = "/@mindful-web/marko-web-identity-x$1.85.
|
|
5
|
+
marko_componentType = "/@mindful-web/marko-web-identity-x$1.85.4/components/progressive-profile-form.marko",
|
|
6
6
|
marko_component = require("./progressive-profile-form.marko"),
|
|
7
7
|
marko_renderer = require("marko/dist/runtime/components/renderer"),
|
|
8
8
|
module_defaultValue = require("@mindful-web/marko-core/utils/default-value"),
|
|
@@ -137,7 +137,7 @@ marko_template._ = marko_renderer(render, {
|
|
|
137
137
|
}, marko_component);
|
|
138
138
|
|
|
139
139
|
marko_template.meta = {
|
|
140
|
-
id: "/@mindful-web/marko-web-identity-x$1.85.
|
|
140
|
+
id: "/@mindful-web/marko-web-identity-x$1.85.4/components/progressive-profile-form.marko",
|
|
141
141
|
component: "./progressive-profile-form.marko",
|
|
142
142
|
tags: [
|
|
143
143
|
"@mindful-web/marko-web/components/browser-component.marko",
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"use strict";
|
|
3
3
|
|
|
4
4
|
var marko_template = module.exports = require("marko/dist/html").t(__filename),
|
|
5
|
-
marko_componentType = "/@mindful-web/marko-web-identity-x$1.85.
|
|
5
|
+
marko_componentType = "/@mindful-web/marko-web-identity-x$1.85.4/components/subscribe.marko",
|
|
6
6
|
marko_component = require("./subscribe.marko"),
|
|
7
7
|
marko_renderer = require("marko/dist/runtime/components/renderer"),
|
|
8
8
|
module_objectPath_module = require("@mindful-web/object-path"),
|
|
@@ -73,7 +73,7 @@ marko_template._ = marko_renderer(render, {
|
|
|
73
73
|
}, marko_component);
|
|
74
74
|
|
|
75
75
|
marko_template.meta = {
|
|
76
|
-
id: "/@mindful-web/marko-web-identity-x$1.85.
|
|
76
|
+
id: "/@mindful-web/marko-web-identity-x$1.85.4/components/subscribe.marko",
|
|
77
77
|
component: "./subscribe.marko",
|
|
78
78
|
tags: [
|
|
79
79
|
"@mindful-web/marko-web/components/browser-component.marko",
|
package/config.js
CHANGED
|
@@ -15,12 +15,12 @@ const { log } = console;
|
|
|
15
15
|
* attributes-only (core/root member fields were cut on review), so a built-in column renders,
|
|
16
16
|
* accepts a value, and is then silently dropped: the user submits, gets `changed: false`, and is
|
|
17
17
|
* re-gated forever. This is the only one of these checks whose runtime failure is *silent*.
|
|
18
|
-
* - **`custom-boolean` is
|
|
19
|
-
*
|
|
20
|
-
*
|
|
21
|
-
*
|
|
22
|
-
*
|
|
23
|
-
*
|
|
18
|
+
* - **`custom-boolean` is semantically useless here.** The renderer bug that once made it
|
|
19
|
+
* unsatisfiable (custom-column.vue read `.answer` but wrote `.value`) is fixed, and the diff
|
|
20
|
+
* util, payload builder, and mutation all handle booleans — but the gate forces every column
|
|
21
|
+
* `required: true`, and a *required* HTML5 checkbox can only ever be submitted checked. A
|
|
22
|
+
* progressive boolean could therefore only ever record `true`, which is not an answer, it's a
|
|
23
|
+
* toll. Re-allow only if the gate ever supports optional columns or explicit yes/no booleans.
|
|
24
24
|
*
|
|
25
25
|
* No coverage is lost: every field the fleet-wide impact analysis measured is a select attribute.
|
|
26
26
|
*/
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mindful-web/marko-web-identity-x",
|
|
3
|
-
"version": "1.85.
|
|
3
|
+
"version": "1.85.4",
|
|
4
4
|
"description": "Marko Wrapper for IdentityX",
|
|
5
5
|
"repository": "https://github.com/parameter1/mindful-web/tree/main/packages/marko-web-identity-x",
|
|
6
6
|
"author": "Josh Worden <josh@parameter1.com>",
|
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
"lint": "eslint --ext .js --ext .vue --max-warnings 5 ./",
|
|
11
11
|
"compile": "mindful-web-marko-compile compile",
|
|
12
12
|
"prepublish": "yarn compile --silent",
|
|
13
|
-
"test": "yarn compile --no-clean && yarn lint"
|
|
13
|
+
"test": "yarn compile --no-clean && yarn lint && mocha --reporter spec"
|
|
14
14
|
},
|
|
15
15
|
"dependencies": {
|
|
16
16
|
"@mindful-web/marko-web-gtm": "^1.83.1",
|
|
@@ -39,5 +39,9 @@
|
|
|
39
39
|
"publishConfig": {
|
|
40
40
|
"access": "public"
|
|
41
41
|
},
|
|
42
|
-
"
|
|
42
|
+
"devDependencies": {
|
|
43
|
+
"chai": "^4.3.7",
|
|
44
|
+
"mocha": "^6.2.3"
|
|
45
|
+
},
|
|
46
|
+
"gitHead": "e793692becf12f650680a93a12f36f227aaace30"
|
|
43
47
|
}
|
package/routes/profile.js
CHANGED
|
@@ -85,13 +85,17 @@ module.exports = asyncRoute(async (req, res) => {
|
|
|
85
85
|
receiveEmail,
|
|
86
86
|
};
|
|
87
87
|
|
|
88
|
-
// get identity-x.forms custom
|
|
88
|
+
// get identity-x.forms custom question ids to append to ActiveCustomQuestionIds
|
|
89
89
|
const customFormFieldIds = Object.values(getAsObject(identityX, 'config.options.forms')).reduce((questions, form) => {
|
|
90
90
|
// loop over the fieldRows
|
|
91
91
|
getAsArray(form, 'fieldRows').forEach((row) => row.forEach((question) => {
|
|
92
|
-
//
|
|
93
|
-
//
|
|
94
|
-
|
|
92
|
+
// Every custom question a form renders must be writable on submit. This list filters all
|
|
93
|
+
// three answer mutations below, so omitting a type here (custom-select-only, previously)
|
|
94
|
+
// silently discarded that form's boolean/text answers unless the site also listed the id
|
|
95
|
+
// in `activeCustomFieldIds`.
|
|
96
|
+
if (question.id && typeof question.type === 'string' && question.type.startsWith('custom-')) {
|
|
97
|
+
questions.push(question.id);
|
|
98
|
+
}
|
|
95
99
|
}));
|
|
96
100
|
return questions;
|
|
97
101
|
}, []);
|
package/test/mocha.opts
ADDED
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
const { describe, it } = require('mocha');
|
|
2
|
+
const { expect } = require('chai');
|
|
3
|
+
const generate = require('../../utils/generate-required-field-payload');
|
|
4
|
+
|
|
5
|
+
const boolDef = {
|
|
6
|
+
type: 'custom-boolean', id: 'bool-1', key: 'bool-1', required: true,
|
|
7
|
+
};
|
|
8
|
+
const selectDef = {
|
|
9
|
+
type: 'custom-select', id: 'select-1', key: 'select-1', required: true,
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
const boolAnswer = (answer, { fieldId = 'bool-1', hasAnswered = true } = {}) => ({
|
|
13
|
+
id: fieldId, hasAnswered, answer, value: answer, field: { id: fieldId },
|
|
14
|
+
});
|
|
15
|
+
const selectAnswer = (optionIds, { fieldId = 'select-1' } = {}) => ({
|
|
16
|
+
id: fieldId,
|
|
17
|
+
hasAnswered: Boolean(optionIds.length),
|
|
18
|
+
answers: optionIds.map((id) => ({ id })),
|
|
19
|
+
field: { id: fieldId },
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
describe('utils/generate-required-field-payload', () => {
|
|
23
|
+
describe('required custom-boolean fields', () => {
|
|
24
|
+
it('should treat an answered `false` as answered', () => {
|
|
25
|
+
const out = generate({
|
|
26
|
+
appUser: { customBooleanFieldAnswers: [boolAnswer(false)] },
|
|
27
|
+
body: {},
|
|
28
|
+
definitions: [boolDef],
|
|
29
|
+
});
|
|
30
|
+
expect(out.appUserHasAllRequiredFields).to.equal(true);
|
|
31
|
+
expect(out.hasAllRequiredFields).to.equal(true);
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
it('should treat an unanswered boolean as missing', () => {
|
|
35
|
+
const out = generate({
|
|
36
|
+
appUser: { customBooleanFieldAnswers: [boolAnswer(null, { hasAnswered: false })] },
|
|
37
|
+
body: {},
|
|
38
|
+
definitions: [boolDef],
|
|
39
|
+
});
|
|
40
|
+
expect(out.appUserHasAllRequiredFields).to.equal(false);
|
|
41
|
+
expect(out.hasAllRequiredFields).to.equal(false);
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
it('should satisfy requirements from the submitted body and build the payload', () => {
|
|
45
|
+
const out = generate({
|
|
46
|
+
appUser: {},
|
|
47
|
+
body: { customBooleanFieldAnswers: [boolAnswer(true)] },
|
|
48
|
+
definitions: [boolDef],
|
|
49
|
+
});
|
|
50
|
+
expect(out.appUserHasAllRequiredFields).to.equal(false);
|
|
51
|
+
expect(out.hasAllRequiredFields).to.equal(true);
|
|
52
|
+
expect(out.payload.customBooleanFieldAnswers).to.deep.equal([
|
|
53
|
+
{ fieldId: 'bool-1', value: true },
|
|
54
|
+
]);
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
it('should carry a submitted `false` into the payload as false', () => {
|
|
58
|
+
const out = generate({
|
|
59
|
+
appUser: {},
|
|
60
|
+
body: { customBooleanFieldAnswers: [boolAnswer(false)] },
|
|
61
|
+
definitions: [boolDef],
|
|
62
|
+
});
|
|
63
|
+
expect(out.hasAllRequiredFields).to.equal(true);
|
|
64
|
+
expect(out.payload.customBooleanFieldAnswers).to.deep.equal([
|
|
65
|
+
{ fieldId: 'bool-1', value: false },
|
|
66
|
+
]);
|
|
67
|
+
});
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
describe('required custom-select fields (existing behavior preserved)', () => {
|
|
71
|
+
it('should treat an empty answers array as unanswered', () => {
|
|
72
|
+
const out = generate({
|
|
73
|
+
appUser: { customSelectFieldAnswers: [selectAnswer([])] },
|
|
74
|
+
body: {},
|
|
75
|
+
definitions: [selectDef],
|
|
76
|
+
});
|
|
77
|
+
expect(out.appUserHasAllRequiredFields).to.equal(false);
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
it('should satisfy from the app user and exclude satisfied fields from the body payload', () => {
|
|
81
|
+
const out = generate({
|
|
82
|
+
appUser: { customSelectFieldAnswers: [selectAnswer(['opt-1'])] },
|
|
83
|
+
body: {},
|
|
84
|
+
definitions: [selectDef],
|
|
85
|
+
});
|
|
86
|
+
expect(out.appUserHasAllRequiredFields).to.equal(true);
|
|
87
|
+
expect(out.payload.customSelectFieldAnswers).to.deep.equal([
|
|
88
|
+
{ fieldId: 'select-1', optionIds: ['opt-1'], writeInValues: [] },
|
|
89
|
+
]);
|
|
90
|
+
});
|
|
91
|
+
});
|
|
92
|
+
});
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
const { describe, it } = require('mocha');
|
|
2
|
+
const { expect } = require('chai');
|
|
3
|
+
const getFormCustomFields = require('../../utils/get-form-custom-fields');
|
|
4
|
+
|
|
5
|
+
const fields = [
|
|
6
|
+
{ id: 'bool-field-1', __typename: 'BooleanField', label: 'Opt in?' },
|
|
7
|
+
{ id: 'select-field-1', __typename: 'SelectField', label: 'Title' },
|
|
8
|
+
{ id: 'text-field-1', __typename: 'TextField', label: 'Nickname' },
|
|
9
|
+
];
|
|
10
|
+
const fieldRows = [[{ id: 'bool-field-1' }, { id: 'select-field-1' }, { id: 'text-field-1' }]];
|
|
11
|
+
|
|
12
|
+
describe('utils/get-form-custom-fields', () => {
|
|
13
|
+
it('should return unanswered stubs carrying the field id when there is no user', () => {
|
|
14
|
+
const out = getFormCustomFields({ fields, fieldRows, user: null });
|
|
15
|
+
expect(out.customBooleanFieldAnswers).to.deep.equal([
|
|
16
|
+
{
|
|
17
|
+
id: 'bool-field-1', hasAnswered: false, answer: null, value: null, field: fields[0],
|
|
18
|
+
},
|
|
19
|
+
]);
|
|
20
|
+
expect(out.customSelectFieldAnswers[0]).to.include({ id: 'select-field-1', hasAnswered: false });
|
|
21
|
+
expect(out.customTextFieldAnswers[0]).to.include({ id: 'text-field-1', hasAnswered: false });
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
it('should key user answers by field.id, not the answer document id', () => {
|
|
25
|
+
const user = {
|
|
26
|
+
customBooleanFieldAnswers: [],
|
|
27
|
+
customSelectFieldAnswers: [
|
|
28
|
+
// `id` here is an answer-document id that does NOT equal the field id.
|
|
29
|
+
{
|
|
30
|
+
id: 'answer-doc-9', hasAnswered: true, answers: [{ id: 'opt-1' }], field: { id: 'select-field-1' },
|
|
31
|
+
},
|
|
32
|
+
],
|
|
33
|
+
customTextFieldAnswers: [],
|
|
34
|
+
};
|
|
35
|
+
const out = getFormCustomFields({ fields, fieldRows, user });
|
|
36
|
+
const [select] = out.customSelectFieldAnswers;
|
|
37
|
+
expect(select.hasAnswered).to.equal(true);
|
|
38
|
+
expect(select.answers).to.deep.equal([{ id: 'opt-1' }]);
|
|
39
|
+
// Normalized for custom-column.vue, which finds answers via `ans.id === fieldId`.
|
|
40
|
+
expect(select.id).to.equal('select-field-1');
|
|
41
|
+
expect(select.field).to.equal(fields[1]);
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
it('should return an unanswered stub (not an empty object) when the user has no matching answer', () => {
|
|
45
|
+
const user = {
|
|
46
|
+
customBooleanFieldAnswers: [
|
|
47
|
+
{
|
|
48
|
+
id: 'other', hasAnswered: true, answer: true, field: { id: 'some-other-field' },
|
|
49
|
+
},
|
|
50
|
+
],
|
|
51
|
+
customSelectFieldAnswers: [],
|
|
52
|
+
customTextFieldAnswers: [],
|
|
53
|
+
};
|
|
54
|
+
const out = getFormCustomFields({ fields, fieldRows, user });
|
|
55
|
+
const [bool] = out.customBooleanFieldAnswers;
|
|
56
|
+
expect(bool.id).to.equal('bool-field-1');
|
|
57
|
+
expect(bool.hasAnswered).to.equal(false);
|
|
58
|
+
expect(bool.field).to.equal(fields[0]);
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
it('should preserve a false boolean answer', () => {
|
|
62
|
+
const user = {
|
|
63
|
+
customBooleanFieldAnswers: [
|
|
64
|
+
{
|
|
65
|
+
id: 'bool-field-1', hasAnswered: true, answer: false, value: false, field: { id: 'bool-field-1' },
|
|
66
|
+
},
|
|
67
|
+
],
|
|
68
|
+
customSelectFieldAnswers: [],
|
|
69
|
+
customTextFieldAnswers: [],
|
|
70
|
+
};
|
|
71
|
+
const out = getFormCustomFields({ fields, fieldRows, user });
|
|
72
|
+
const [bool] = out.customBooleanFieldAnswers;
|
|
73
|
+
expect(bool.hasAnswered).to.equal(true);
|
|
74
|
+
expect(bool.answer).to.equal(false);
|
|
75
|
+
});
|
|
76
|
+
});
|
|
@@ -1,7 +1,13 @@
|
|
|
1
1
|
const { get } = require('@mindful-web/object-path');
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
3
|
+
const hasAnswered = (ans) => {
|
|
4
|
+
if (!ans || !ans.hasAnswered) return false;
|
|
5
|
+
// A boolean field is answered by having been answered — `false` is a legitimate value that
|
|
6
|
+
// must not read as missing, so never truth-test it. Boolean answers carry a boolean
|
|
7
|
+
// `answer`/`value`; selects carry `answers`, texts a string `value`.
|
|
8
|
+
if (typeof ans.answer === 'boolean' || typeof ans.value === 'boolean') return true;
|
|
9
|
+
return Boolean(ans.value || (ans.answers && ans.answers.length));
|
|
10
|
+
};
|
|
5
11
|
|
|
6
12
|
const hasMappedAnswers = (map) => (id) => {
|
|
7
13
|
const ans = map.get(id);
|
|
@@ -40,10 +46,10 @@ module.exports = ({ appUser, body, definitions }) => {
|
|
|
40
46
|
|
|
41
47
|
const requiredFieldKeys = [...requiredFieldKeySet];
|
|
42
48
|
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
49
|
+
const requiredCustomBooleans = [...definitions.reduce((set, def) => {
|
|
50
|
+
if (def.type === 'custom-boolean' && def.required) set.add(def.id);
|
|
51
|
+
return set;
|
|
52
|
+
}, new Set())];
|
|
47
53
|
|
|
48
54
|
const requiredCustomSelects = [...definitions.reduce((set, def) => {
|
|
49
55
|
if (def.type === 'custom-select' && def.required) set.add(def.id);
|
|
@@ -56,15 +62,15 @@ module.exports = ({ appUser, body, definitions }) => {
|
|
|
56
62
|
}, new Set())];
|
|
57
63
|
|
|
58
64
|
const userCustomFieldAnswers = new Map([
|
|
59
|
-
|
|
65
|
+
...(get(appUser, 'customBooleanFieldAnswers') || []).map((a) => [a.field.id, a]),
|
|
60
66
|
...(get(appUser, 'customSelectFieldAnswers') || []).map((a) => [a.field.id, a]),
|
|
61
67
|
...(get(appUser, 'customTextFieldAnswers') || []).map((a) => [a.field.id, a]),
|
|
62
68
|
]);
|
|
63
69
|
|
|
64
70
|
const customFieldAnswers = new Map([
|
|
65
71
|
...userCustomFieldAnswers,
|
|
66
|
-
|
|
67
|
-
|
|
72
|
+
...(get(body, 'customBooleanFieldAnswers') || [])
|
|
73
|
+
.filter(hasAnswered).map((a) => [a.field.id, a]),
|
|
68
74
|
...(get(body, 'customSelectFieldAnswers') || []).filter(hasAnswered).map((a) => [a.field.id, a]),
|
|
69
75
|
...(get(body, 'customTextFieldAnswers') || [])
|
|
70
76
|
.filter(hasAnswered).map((a) => [a.field.id, a]),
|
|
@@ -74,9 +80,7 @@ module.exports = ({ appUser, body, definitions }) => {
|
|
|
74
80
|
requiredFieldKeys.every(
|
|
75
81
|
(key) => get(appUser, key),
|
|
76
82
|
),
|
|
77
|
-
|
|
78
|
-
// (id) => userCustomFieldAnswers.has(id) && userCustomFieldAnswers.get(id).hasAnswered,
|
|
79
|
-
// ),
|
|
83
|
+
requiredCustomBooleans.every(hasMappedAnswers(userCustomFieldAnswers)),
|
|
80
84
|
requiredCustomSelects.every(hasMappedAnswers(userCustomFieldAnswers)),
|
|
81
85
|
requiredCustomTexts.every(
|
|
82
86
|
(id) => userCustomFieldAnswers.has(id) && userCustomFieldAnswers.get(id).hasAnswered,
|
|
@@ -87,14 +91,23 @@ module.exports = ({ appUser, body, definitions }) => {
|
|
|
87
91
|
requiredFieldKeys.every(
|
|
88
92
|
(key) => get(appUser, key) || get(body, key),
|
|
89
93
|
),
|
|
90
|
-
|
|
94
|
+
requiredCustomBooleans.every(hasMappedAnswers(customFieldAnswers)),
|
|
91
95
|
requiredCustomSelects.every(hasMappedAnswers(customFieldAnswers)),
|
|
92
96
|
requiredCustomTexts.every(hasMappedAnswers(customFieldAnswers)),
|
|
93
97
|
].every((v) => v);
|
|
94
98
|
|
|
95
99
|
const payload = {
|
|
96
100
|
...(requiredFieldKeys.reduce((obj, key) => ({ ...obj, [key]: body[key] }), {})),
|
|
97
|
-
|
|
101
|
+
customBooleanFieldAnswers: requiredCustomBooleans
|
|
102
|
+
.filter(hasMappedAnswers(customFieldAnswers))
|
|
103
|
+
.map((id) => {
|
|
104
|
+
const answer = customFieldAnswers.get(id);
|
|
105
|
+
return {
|
|
106
|
+
fieldId: answer.field.id,
|
|
107
|
+
// `.answer` is canonical (what the profile route reads); fall back to `.value`.
|
|
108
|
+
value: Boolean(typeof answer.answer === 'boolean' ? answer.answer : answer.value),
|
|
109
|
+
};
|
|
110
|
+
}),
|
|
98
111
|
customSelectFieldAnswers: requiredCustomSelects
|
|
99
112
|
.filter(hasMappedAnswers(customFieldAnswers))
|
|
100
113
|
.map((id) => {
|
|
@@ -11,44 +11,35 @@ module.exports = ({
|
|
|
11
11
|
});
|
|
12
12
|
});
|
|
13
13
|
|
|
14
|
+
// A user answer is keyed by its `field.id` — never the answer's own `id`, which some backends
|
|
15
|
+
// set to the answer document id. The returned object always carries `id` = the field id and
|
|
16
|
+
// `field` = the form's field definition, because `custom-column.vue` finds answers via
|
|
17
|
+
// `ans.id === fieldId` and renders from `customField.field`.
|
|
18
|
+
const findUserAnswer = (answers, f) => {
|
|
19
|
+
const found = (answers || []).find((a) => a && a.field && a.field.id === f.id);
|
|
20
|
+
return found ? { ...found, id: f.id, field: f } : null;
|
|
21
|
+
};
|
|
22
|
+
|
|
14
23
|
// eslint-disable-next-line no-underscore-dangle
|
|
15
24
|
const customBooleanFieldAnswers = fieldRowFields.filter((f) => f.__typename === 'BooleanField').map((f) => {
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
if (userAnswer) {
|
|
19
|
-
return ({
|
|
20
|
-
...userAnswer[0],
|
|
21
|
-
});
|
|
22
|
-
}
|
|
23
|
-
}
|
|
25
|
+
const userAnswer = user ? findUserAnswer(user.customBooleanFieldAnswers, f) : null;
|
|
26
|
+
if (userAnswer) return userAnswer;
|
|
24
27
|
return ({
|
|
25
28
|
id: f.id, hasAnswered: false, answer: null, value: null, field: f,
|
|
26
29
|
});
|
|
27
30
|
});
|
|
28
|
-
// eslint-disable-next-line no-underscore-dangle
|
|
29
|
-
const customSelectFieldAnswers = fieldRowFields.filter((f) => f.__typename
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
if (userAnswer) {
|
|
33
|
-
return ({
|
|
34
|
-
...userAnswer[0],
|
|
35
|
-
});
|
|
36
|
-
}
|
|
37
|
-
}
|
|
31
|
+
// eslint-disable-next-line no-underscore-dangle
|
|
32
|
+
const customSelectFieldAnswers = fieldRowFields.filter((f) => f.__typename === 'SelectField').map((f) => {
|
|
33
|
+
const userAnswer = user ? findUserAnswer(user.customSelectFieldAnswers, f) : null;
|
|
34
|
+
if (userAnswer) return userAnswer;
|
|
38
35
|
return ({
|
|
39
36
|
id: f.id, hasAnswered: false, answers: [], field: f,
|
|
40
37
|
});
|
|
41
38
|
});
|
|
42
|
-
// eslint-disable-next-line no-underscore-dangle
|
|
43
|
-
const customTextFieldAnswers = fieldRowFields.filter((f) => f.__typename
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
if (userAnswer) {
|
|
47
|
-
return ({
|
|
48
|
-
...userAnswer[0],
|
|
49
|
-
});
|
|
50
|
-
}
|
|
51
|
-
}
|
|
39
|
+
// eslint-disable-next-line no-underscore-dangle
|
|
40
|
+
const customTextFieldAnswers = fieldRowFields.filter((f) => f.__typename === 'TextField').map((f) => {
|
|
41
|
+
const userAnswer = user ? findUserAnswer(user.customTextFieldAnswers, f) : null;
|
|
42
|
+
if (userAnswer) return userAnswer;
|
|
52
43
|
return ({
|
|
53
44
|
id: f.id, hasAnswered: false, value: null, field: f,
|
|
54
45
|
});
|