@mindful-web/marko-web-identity-x 1.20.3 → 1.30.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,9 +1,44 @@
1
1
  const gql = require('graphql-tag');
2
2
  const userFragment = require('../fragments/active-user');
3
3
 
4
- module.exports = gql`
4
+ const fieldsQuery = `
5
+ fields {
6
+ edges {
7
+ node {
8
+ id
9
+ label
10
+ active
11
+ required
12
+ externalId {
13
+ id
14
+ namespace { provider tenant type }
15
+ identifier { value type }
16
+ }
17
+ ... on SelectField {
18
+ multiple
19
+ options: choices {
20
+ id
21
+ label
22
+ ... on SelectFieldOption {
23
+ canWriteIn
24
+ }
25
+ ... on SelectFieldOptionGroup {
26
+ options {
27
+ id
28
+ label
29
+ canWriteIn
30
+ }
31
+ }
32
+ }
33
+ }
34
+ }
35
+ }
36
+ }
37
+ `;
5
38
 
39
+ module.exports = ({ withFields = false }) => gql`
6
40
  query GetActiveAppContext {
41
+ ${withFields ? fieldsQuery : ''}
7
42
  activeAppContext {
8
43
  application {
9
44
  id
@@ -127,7 +127,7 @@
127
127
  :selected="customField.answers"
128
128
  :options="customField.field.options"
129
129
  :lang="lang"
130
- @change="onCustomSelectChange(customField.answers, $event)"
130
+ @change="onCustomSelectChange(customField, $event)"
131
131
  />
132
132
  <custom-boolean
133
133
  v-else-if="type === 'custom-boolean' && customField"
@@ -325,16 +325,21 @@ export default {
325
325
  const objIndex = this.customBooleanFieldAnswers.findIndex(((obj) => obj.id === id));
326
326
  const answer = !this.customBooleanFieldAnswers[objIndex].answer;
327
327
  this.customBooleanFieldAnswers[objIndex].answer = answer;
328
+ this.customBooleanFieldAnswers[objIndex].hasAnswered = true;
328
329
  this.user.customBooleanFieldAnswers = this.customBooleanFieldAnswers;
329
330
  },
330
331
 
331
332
  /**
332
333
  *
333
334
  */
334
- onCustomSelectChange(answers, $event) {
335
+ onCustomSelectChange(field, $event) {
335
336
  const ids = Array.isArray($event) ? [...$event] : [...($event ? [$event] : [])];
336
- answers.splice(0);
337
- if (ids.length) answers.push(...ids.map((id) => ({ id })));
337
+ field.answers.splice(0);
338
+ if (ids.length) {
339
+ // eslint-disable-next-line no-param-reassign
340
+ field.hasAnswered = true;
341
+ field.answers.push(...ids.map((id) => ({ id })));
342
+ }
338
343
  },
339
344
  },
340
345
  };
package/browser/login.vue CHANGED
@@ -31,24 +31,23 @@
31
31
  <p v-if="requiresUserInput">
32
32
  Thanks! Additional information is required to continue:
33
33
  </p>
34
- <div v-if="requiresUserInput" class="row form-group">
35
- <div v-if="requiredCreateFields.includes('givenName')" class="col">
36
- <given-name
37
- v-model="givenName"
38
- :required="true"
39
- :disabled="loading"
40
- :label="defaultFieldLabels.givenName || 'First Name'"
34
+ <fieldset v-if="requiresUserInput" :disabled="loading" class="form-group">
35
+ <div v-for="(row, ridx) in requiredCreateFieldRows" :key="ridx" class="row">
36
+ <custom-column
37
+ v-for="(col, cidx) in row"
38
+ :key="`${ridx}_${cidx}`"
39
+ :label="col.label || defaultFieldLabels[col.key]"
40
+ :field-key="col.key"
41
+ :field-id="col.id"
42
+ :type="col.type"
43
+ :required="col.required"
44
+ :width="col.width || 1"
45
+ :user="activeUser"
46
+ :endpoints="endpoints"
47
+ :lang="lang"
41
48
  />
42
49
  </div>
43
- <div v-if="requiredCreateFields.includes('familyName')" class="col">
44
- <family-name
45
- v-model="familyName"
46
- :required="true"
47
- :disabled="loading"
48
- :label="defaultFieldLabels.familyName || 'Last Name'"
49
- />
50
- </div>
51
- </div>
50
+ </fieldset>
52
51
 
53
52
  <small
54
53
  v-if="emailConsentRequestEnabled && emailConsentRequest"
@@ -77,8 +76,7 @@
77
76
 
78
77
  <script>
79
78
  import Email from './form/fields/email.vue';
80
- import GivenName from './form/fields/given-name.vue';
81
- import FamilyName from './form/fields/family-name.vue';
79
+ import CustomColumn from './custom-column.vue';
82
80
 
83
81
  import cleanPath from './utils/clean-path';
84
82
  import post from './utils/post';
@@ -94,8 +92,7 @@ export default {
94
92
  */
95
93
  components: {
96
94
  Email,
97
- GivenName,
98
- FamilyName,
95
+ CustomColumn,
99
96
  },
100
97
 
101
98
  /**
@@ -185,7 +182,7 @@ export default {
185
182
  default: () => [],
186
183
  },
187
184
 
188
- requiredCreateFields: {
185
+ requiredCreateFieldRows: {
189
186
  type: Array,
190
187
  default: () => [],
191
188
  },
@@ -201,8 +198,6 @@ export default {
201
198
  */
202
199
  data: () => ({
203
200
  email: null,
204
- givenName: null,
205
- familyName: null,
206
201
  complete: false,
207
202
  error: null,
208
203
  loading: false,
@@ -311,9 +306,8 @@ export default {
311
306
  this.error = null;
312
307
  this.loading = true;
313
308
  const res = await post('/login', {
309
+ ...this.activeUser,
314
310
  email: this.email,
315
- // Append any additional required fields
316
- ...(this.requiredCreateFields.reduce((obj, key) => ({ ...obj, [key]: this[key] }), {})),
317
311
  source: this.source,
318
312
  redirectTo: this.redirectTo,
319
313
  authUrl: this.authUrl,
@@ -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.20.3/components/access.marko",
5
+ marko_componentType = "/@mindful-web/marko-web-identity-x$1.30.0/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.20.3/components/access.marko",
56
+ id: "/@mindful-web/marko-web-identity-x$1.30.0/components/access.marko",
57
57
  component: "./access.marko",
58
58
  tags: [
59
59
  "@mindful-web/marko-core/components/resolve.marko"
@@ -24,7 +24,7 @@ $ const dateFormat = input.dateFormat || defaultValue(site.config.dateFormat, "M
24
24
  consentPolicy: get(application, "organization.consentPolicy"),
25
25
  regionalConsentPolicies: get(application, "organization.regionalConsentPolicies"),
26
26
  appContextId: identityX.config.get("appContextId"),
27
- requiredCreateFields: identityX.config.getRequiredCreateFields(),
27
+ requiredCreateFieldRows: identityX.config.getRequiredCreateFieldRows(),
28
28
  defaultFieldLabels: identityX.config.get("defaultFieldLabels"),
29
29
  headerText: get(site, 'config.comments.headerText'),
30
30
  loadMoreCommentsMessage: get(site, 'config.comments.loadMoreCommentsMessage'),
@@ -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.20.3/components/comment-stream.marko",
5
+ marko_componentType = "/@mindful-web/marko-web-identity-x$1.30.0/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"),
@@ -47,7 +47,7 @@ function render(input, out, __component, component, state) {
47
47
  consentPolicy: get(application, "organization.consentPolicy"),
48
48
  regionalConsentPolicies: get(application, "organization.regionalConsentPolicies"),
49
49
  appContextId: identityX.config.get("appContextId"),
50
- requiredCreateFields: identityX.config.getRequiredCreateFields(),
50
+ requiredCreateFieldRows: identityX.config.getRequiredCreateFieldRows(),
51
51
  defaultFieldLabels: identityX.config.get("defaultFieldLabels"),
52
52
  headerText: get(site, 'config.comments.headerText'),
53
53
  loadMoreCommentsMessage: get(site, 'config.comments.loadMoreCommentsMessage'),
@@ -77,7 +77,7 @@ marko_template._ = marko_renderer(render, {
77
77
  }, marko_component);
78
78
 
79
79
  marko_template.meta = {
80
- id: "/@mindful-web/marko-web-identity-x$1.20.3/components/comment-stream.marko",
80
+ id: "/@mindful-web/marko-web-identity-x$1.30.0/components/comment-stream.marko",
81
81
  component: "./comment-stream.marko",
82
82
  tags: [
83
83
  "@mindful-web/marko-web/components/browser-component.marko",
@@ -1,15 +1,17 @@
1
1
  $ const { req } = out.global;
2
2
  $ const { identityX } = req;
3
3
  $ const isEnabled = Boolean(req.identityX);
4
- $ const loadContext = async () => (isEnabled ? identityX.loadActiveContext() : {
4
+ $ const { withFields = false } = input;
5
+ $ const loadContext = async ({ withFields }) => (isEnabled ? identityX.loadActiveContext({ withFields }) : {
5
6
  user: null,
6
7
  mergedAccessLevels: [],
7
8
  mergedTeams: [],
8
9
  hasTeams: false,
9
10
  hasUser: false,
11
+ fields: [],
10
12
  });
11
13
 
12
- <marko-web-resolve|{ resolved }| promise=loadContext()>
14
+ <marko-web-resolve|{ resolved }| promise=loadContext({ withFields })>
13
15
  $ const output = { ...resolved, isEnabled };
14
16
  <${input.renderBody} ...output />
15
17
  </marko-web-resolve>
@@ -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.20.3/components/context.marko",
5
+ marko_componentType = "/@mindful-web/marko-web-identity-x$1.30.0/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"),
@@ -19,16 +19,21 @@ function render(input, out, __component, component, state) {
19
19
 
20
20
  const isEnabled = Boolean(req.identityX);
21
21
 
22
- const loadContext = async () => (isEnabled ? identityX.loadActiveContext() : {
22
+ const { withFields = false } = input;
23
+
24
+ const loadContext = async ({ withFields }) => (isEnabled ? identityX.loadActiveContext({ withFields }) : {
23
25
  user: null,
24
26
  mergedAccessLevels: [],
25
27
  mergedTeams: [],
26
28
  hasTeams: false,
27
29
  hasUser: false,
30
+ fields: [],
28
31
  });
29
32
 
30
33
  marko_web_resolve_tag({
31
- promise: loadContext(),
34
+ promise: loadContext({
35
+ withFields: withFields
36
+ }),
32
37
  renderBody: function(out, { resolved }) {
33
38
  const output = { ...resolved, isEnabled };
34
39
 
@@ -44,7 +49,7 @@ marko_template._ = marko_renderer(render, {
44
49
  }, marko_component);
45
50
 
46
51
  marko_template.meta = {
47
- id: "/@mindful-web/marko-web-identity-x$1.20.3/components/context.marko",
52
+ id: "/@mindful-web/marko-web-identity-x$1.30.0/components/context.marko",
48
53
  component: "./context.marko",
49
54
  tags: [
50
55
  "@mindful-web/marko-core/components/resolve.marko"
@@ -48,7 +48,7 @@ $ const loginButtonLabels = defaultValue(input.loginButtonLabels, {
48
48
  defaultFieldLabels: identityX.config.get("defaultFieldLabels"),
49
49
  enableChangeEmail: identityX.config.get("enableChangeEmail"),
50
50
  endpoints: identityX.config.getEndpoints(),
51
- requiredCreateFields: identityX.config.getRequiredCreateFields(),
51
+ requiredCreateFieldRows: identityX.config.getRequiredCreateFieldRows(),
52
52
 
53
53
  // Consent
54
54
  consentPolicy: consentPolicy,
@@ -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.20.3/components/form-access.marko",
5
+ marko_componentType = "/@mindful-web/marko-web-identity-x$1.30.0/components/form-access.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,
@@ -80,7 +80,7 @@ function render(input, out, __component, component, state) {
80
80
  defaultFieldLabels: identityX.config.get("defaultFieldLabels"),
81
81
  enableChangeEmail: identityX.config.get("enableChangeEmail"),
82
82
  endpoints: identityX.config.getEndpoints(),
83
- requiredCreateFields: identityX.config.getRequiredCreateFields(),
83
+ requiredCreateFieldRows: identityX.config.getRequiredCreateFieldRows(),
84
84
 
85
85
  // Consent
86
86
  consentPolicy: consentPolicy,
@@ -114,7 +114,7 @@ marko_template._ = marko_renderer(render, {
114
114
  });
115
115
 
116
116
  marko_template.meta = {
117
- id: "/@mindful-web/marko-web-identity-x$1.20.3/components/form-access.marko",
117
+ id: "/@mindful-web/marko-web-identity-x$1.30.0/components/form-access.marko",
118
118
  tags: [
119
119
  "@mindful-web/marko-web/components/browser-component.marko"
120
120
  ]
@@ -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.20.3/components/form-authenticate.marko",
5
+ marko_componentType = "/@mindful-web/marko-web-identity-x$1.30.0/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"),
@@ -68,7 +68,7 @@ marko_template._ = marko_renderer(render, {
68
68
  }, marko_component);
69
69
 
70
70
  marko_template.meta = {
71
- id: "/@mindful-web/marko-web-identity-x$1.20.3/components/form-authenticate.marko",
71
+ id: "/@mindful-web/marko-web-identity-x$1.30.0/components/form-authenticate.marko",
72
72
  component: "./form-authenticate.marko",
73
73
  tags: [
74
74
  "@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.20.3/components/form-change-email.marko",
5
+ marko_componentType = "/@mindful-web/marko-web-identity-x$1.30.0/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.20.3/components/form-change-email.marko",
62
+ id: "/@mindful-web/marko-web-identity-x$1.30.0/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",
@@ -5,24 +5,43 @@ $ const { req, site } = out.global;
5
5
  $ const { identityX } = req;
6
6
  $ const additionalEventData = defaultValue(input.additionalEventData, {});
7
7
  $ const lang = input.lang || defaultValue(site.config.lang, "en");
8
+ $ const withFields = defaultValue(input.withFields, false);
9
+
10
+
8
11
 
9
12
  <if(Boolean(identityX))>
10
- <marko-web-identity-x-context|{ user, isEnabled, application }|>
13
+ <marko-web-identity-x-context|{ user, isEnabled, application, fields }| with-fields=true>
14
+ $ const customBooleanFieldAnswers = fields.filter((f) => f.__typename === 'BooleanField').map((f) => {
15
+ return { id: f.id, hasAnswered: false, answer: null, value: null, field: f };
16
+ });
17
+ $ const customSelectFieldAnswers = fields.filter((f) => f['__typename'] == 'SelectField').map((f) => {
18
+ return { id: f.id, hasAnswered: false, answers: [], field: f };
19
+ });
20
+ $ const customTextFieldAnswers = fields.filter((f) => f['__typename'] == 'TextField').map((f) => {
21
+ return { id: f.id, hasAnswered: false, value: null, field: f };
22
+ });
23
+ $ const activeUser = user ? user : {
24
+ email: null,
25
+ customSelectFieldAnswers,
26
+ customBooleanFieldAnswers,
27
+ customTextFieldAnswers,
28
+ }
11
29
  $ const props = {
12
30
  additionalEventData,
13
31
  source: input.source,
14
32
  actionText: input.actionText,
15
- activeUser: user,
33
+ activeUser,
16
34
  endpoints: identityX.config.getEndpoints(),
17
35
  buttonLabels: input.buttonLabels,
18
36
  redirect: input.redirect,
19
37
  loginEmailLabel: input.loginEmailLabel,
20
38
  loginEmailPlaceholder: input.loginEmailPlaceholder,
21
39
  defaultFieldLabels: identityX.config.get("defaultFieldLabels"),
22
- requiredCreateFields: identityX.config.getRequiredCreateFields(),
40
+ requiredCreateFieldRows: identityX.config.getRequiredCreateFieldRows(),
23
41
  consentPolicy: identityX.config.get("consentPolicy") || get(application, "organization.consentPolicy"),
24
42
  regionalConsentPolicies: get(application, "organization.regionalConsentPolicies"),
25
43
  appContextId: identityX.config.get("appContextId"),
44
+ fields,
26
45
  lang,
27
46
  };
28
47
  <if(isEnabled)>
@@ -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.20.3/components/form-login.marko",
5
+ marko_componentType = "/@mindful-web/marko-web-identity-x$1.30.0/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"),
@@ -27,24 +27,47 @@ function render(input, out, __component, component, state) {
27
27
 
28
28
  const lang = input.lang || defaultValue(site.config.lang, "en");
29
29
 
30
+ const withFields = defaultValue(input.withFields, false);
31
+
30
32
  if (Boolean(identityX)) {
31
33
  marko_web_identity_x_context_tag({
32
- renderBody: function(out, { user, isEnabled, application }) {
34
+ withFields: true,
35
+ renderBody: function(out, { user, isEnabled, application, fields }) {
36
+ const customBooleanFieldAnswers = fields.filter((f) => f.__typename === 'BooleanField').map((f) => {
37
+ return { id: f.id, hasAnswered: false, answer: null, value: null, field: f };
38
+ });
39
+
40
+ const customSelectFieldAnswers = fields.filter((f) => f['__typename'] == 'SelectField').map((f) => {
41
+ return { id: f.id, hasAnswered: false, answers: [], field: f };
42
+ });
43
+
44
+ const customTextFieldAnswers = fields.filter((f) => f['__typename'] == 'TextField').map((f) => {
45
+ return { id: f.id, hasAnswered: false, value: null, field: f };
46
+ });
47
+
48
+ const activeUser = user ? user : {
49
+ email: null,
50
+ customSelectFieldAnswers,
51
+ customBooleanFieldAnswers,
52
+ customTextFieldAnswers,
53
+ }
54
+
33
55
  const props = {
34
56
  additionalEventData,
35
57
  source: input.source,
36
58
  actionText: input.actionText,
37
- activeUser: user,
59
+ activeUser,
38
60
  endpoints: identityX.config.getEndpoints(),
39
61
  buttonLabels: input.buttonLabels,
40
62
  redirect: input.redirect,
41
63
  loginEmailLabel: input.loginEmailLabel,
42
64
  loginEmailPlaceholder: input.loginEmailPlaceholder,
43
65
  defaultFieldLabels: identityX.config.get("defaultFieldLabels"),
44
- requiredCreateFields: identityX.config.getRequiredCreateFields(),
66
+ requiredCreateFieldRows: identityX.config.getRequiredCreateFieldRows(),
45
67
  consentPolicy: identityX.config.get("consentPolicy") || get(application, "organization.consentPolicy"),
46
68
  regionalConsentPolicies: get(application, "organization.regionalConsentPolicies"),
47
69
  appContextId: identityX.config.get("appContextId"),
70
+ fields,
48
71
  lang,
49
72
  };
50
73
 
@@ -64,7 +87,7 @@ marko_template._ = marko_renderer(render, {
64
87
  }, marko_component);
65
88
 
66
89
  marko_template.meta = {
67
- id: "/@mindful-web/marko-web-identity-x$1.20.3/components/form-login.marko",
90
+ id: "/@mindful-web/marko-web-identity-x$1.30.0/components/form-login.marko",
68
91
  component: "./form-login.marko",
69
92
  tags: [
70
93
  "@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.20.3/components/form-logout.marko",
5
+ marko_componentType = "/@mindful-web/marko-web-identity-x$1.30.0/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.20.3/components/form-logout.marko",
32
+ id: "/@mindful-web/marko-web-identity-x$1.30.0/components/form-logout.marko",
33
33
  tags: [
34
34
  "@mindful-web/marko-web/components/browser-component.marko"
35
35
  ]
@@ -14,7 +14,7 @@ $ const lang = input.lang || defaultValue(site.config.lang, "en");
14
14
  activeUser: user,
15
15
  requiredServerFields: identityX.config.getRequiredServerFields(),
16
16
  requiredClientFields: identityX.config.getRequiredClientFields(),
17
- requiredCreateFields: identityX.config.getRequiredCreateFields(),
17
+ requiredCreateFieldRows: identityX.config.getRequiredCreateFieldRows(),
18
18
  activeCustomFieldIds: identityX.config.getActiveCustomFieldIds(),
19
19
  defaultFieldLabels: identityX.config.get("defaultFieldLabels"),
20
20
  hiddenFields: identityX.config.getHiddenFields(),
@@ -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.20.3/components/form-profile.marko",
5
+ marko_componentType = "/@mindful-web/marko-web-identity-x$1.30.0/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"),
@@ -36,7 +36,7 @@ function render(input, out, __component, component, state) {
36
36
  activeUser: user,
37
37
  requiredServerFields: identityX.config.getRequiredServerFields(),
38
38
  requiredClientFields: identityX.config.getRequiredClientFields(),
39
- requiredCreateFields: identityX.config.getRequiredCreateFields(),
39
+ requiredCreateFieldRows: identityX.config.getRequiredCreateFieldRows(),
40
40
  activeCustomFieldIds: identityX.config.getActiveCustomFieldIds(),
41
41
  defaultFieldLabels: identityX.config.get("defaultFieldLabels"),
42
42
  hiddenFields: identityX.config.getHiddenFields(),
@@ -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.20.3/components/form-profile.marko",
76
+ id: "/@mindful-web/marko-web-identity-x$1.30.0/components/form-profile.marko",
77
77
  component: "./form-profile.marko",
78
78
  tags: [
79
79
  "@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.20.3/components/form-register.marko",
5
+ marko_componentType = "/@mindful-web/marko-web-identity-x$1.30.0/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.20.3/components/form-register.marko",
28
+ id: "/@mindful-web/marko-web-identity-x$1.30.0/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.20.3/components/identify.marko",
5
+ marko_componentType = "/@mindful-web/marko-web-identity-x$1.30.0/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.20.3/components/identify.marko",
53
+ id: "/@mindful-web/marko-web-identity-x$1.30.0/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.20.3/components/non-auth-identify.marko",
5
+ marko_componentType = "/@mindful-web/marko-web-identity-x$1.30.0/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.20.3/components/non-auth-identify.marko",
48
+ id: "/@mindful-web/marko-web-identity-x$1.30.0/components/non-auth-identify.marko",
49
49
  component: "./non-auth-identify.marko",
50
50
  tags: [
51
51
  "@mindful-web/marko-core/components/resolve.marko"
@@ -0,0 +1,41 @@
1
+ import { get } from "@mindful-web/object-path";
2
+ import defaultValue from "@mindful-web/marko-core/utils/default-value";
3
+
4
+ $ const { req, site } = out.global;
5
+ $ const { identityX, query } = req;
6
+ $ const additionalEventData = defaultValue(input.additionalEventData, {});
7
+ $ const lang = input.lang || defaultValue(site.config.lang, "en");
8
+
9
+ <if(Boolean(identityX))>
10
+ <marko-web-identity-x-context|{ user, isEnabled, application }|>
11
+ $ const props = {
12
+ additionalEventData: additionalEventData,
13
+ loginSource: input.loginSource,
14
+ activeUser: user,
15
+ requiredServerFields: identityX.config.getRequiredServerFields(),
16
+ requiredClientFields: identityX.config.getRequiredClientFields(),
17
+ requiredCreateFieldRows: identityX.config.getRequiredCreateFieldRows(),
18
+ activeCustomFieldIds: identityX.config.getActiveCustomFieldIds(),
19
+ defaultFieldLabels: identityX.config.get("defaultFieldLabels"),
20
+ hiddenFields: identityX.config.getHiddenFields(),
21
+ defaultCountryCode: identityX.config.get('defaultCountryCode'),
22
+ booleanQuestionsLabel: identityX.config.get('booleanQuestionsLabel'),
23
+ callToAction: input.callToAction,
24
+ reloadPageOnSubmit: input.reloadPageOnSubmit,
25
+ buttonLabel: input.buttonLabel,
26
+ loginButtonLabels: input.loginButtonLabels,
27
+ endpoints: identityX.config.getEndpoints(),
28
+ consentPolicy: identityX.config.get("consentPolicy") || get(application, "organization.consentPolicy"),
29
+ emailConsentRequest: get(application, "organization.emailConsentRequest"),
30
+ appContextId: identityX.config.get("appContextId"),
31
+ regionalConsentPolicies: get(application, "organization.regionalConsentPolicies"),
32
+ returnTo: query.returnTo,
33
+ returnToDelay: input.returnToDelay,
34
+ enableChangeEmail: identityX.config.get("enableChangeEmail"),
35
+ lang,
36
+ };
37
+ <if(isEnabled)>
38
+ <marko-web-browser-component name="IdentityXSubscribe" props=props />
39
+ </if>
40
+ </marko-web-identity-x-context>
41
+ </if>
@@ -0,0 +1,82 @@
1
+ // Compiled using marko@4.20.2 - DO NOT EDIT
2
+ "use strict";
3
+
4
+ var marko_template = module.exports = require("marko/dist/html").t(__filename),
5
+ marko_componentType = "/@mindful-web/marko-web-identity-x$1.30.0/components/subscribe.marko",
6
+ marko_component = require("./subscribe.marko"),
7
+ marko_renderer = require("marko/dist/runtime/components/renderer"),
8
+ module_objectPath_module = require("@mindful-web/object-path"),
9
+ objectPath_module = module_objectPath_module.default || module_objectPath_module,
10
+ get = module_objectPath_module.get,
11
+ module_defaultValue = require("@mindful-web/marko-core/utils/default-value"),
12
+ defaultValue = module_defaultValue.default || module_defaultValue,
13
+ marko_web_browser_component_template = require("@mindful-web/marko-web/components/browser-component.marko"),
14
+ marko_loadTag = require("marko/dist/runtime/helpers/load-tag"),
15
+ marko_web_browser_component_tag = marko_loadTag(marko_web_browser_component_template),
16
+ marko_web_identity_x_context_template = require("./context.marko"),
17
+ marko_web_identity_x_context_tag = marko_loadTag(marko_web_identity_x_context_template);
18
+
19
+ function render(input, out, __component, component, state) {
20
+ var data = input;
21
+
22
+ const { req, site } = out.global;
23
+
24
+ const { identityX, query } = req;
25
+
26
+ const additionalEventData = defaultValue(input.additionalEventData, {});
27
+
28
+ const lang = input.lang || defaultValue(site.config.lang, "en");
29
+
30
+ if (Boolean(identityX)) {
31
+ marko_web_identity_x_context_tag({
32
+ renderBody: function(out, { user, isEnabled, application }) {
33
+ const props = {
34
+ additionalEventData: additionalEventData,
35
+ loginSource: input.loginSource,
36
+ activeUser: user,
37
+ requiredServerFields: identityX.config.getRequiredServerFields(),
38
+ requiredClientFields: identityX.config.getRequiredClientFields(),
39
+ requiredCreateFieldRows: identityX.config.getRequiredCreateFieldRows(),
40
+ activeCustomFieldIds: identityX.config.getActiveCustomFieldIds(),
41
+ defaultFieldLabels: identityX.config.get("defaultFieldLabels"),
42
+ hiddenFields: identityX.config.getHiddenFields(),
43
+ defaultCountryCode: identityX.config.get('defaultCountryCode'),
44
+ booleanQuestionsLabel: identityX.config.get('booleanQuestionsLabel'),
45
+ callToAction: input.callToAction,
46
+ reloadPageOnSubmit: input.reloadPageOnSubmit,
47
+ buttonLabel: input.buttonLabel,
48
+ loginButtonLabels: input.loginButtonLabels,
49
+ endpoints: identityX.config.getEndpoints(),
50
+ consentPolicy: identityX.config.get("consentPolicy") || get(application, "organization.consentPolicy"),
51
+ emailConsentRequest: get(application, "organization.emailConsentRequest"),
52
+ appContextId: identityX.config.get("appContextId"),
53
+ regionalConsentPolicies: get(application, "organization.regionalConsentPolicies"),
54
+ returnTo: query.returnTo,
55
+ returnToDelay: input.returnToDelay,
56
+ enableChangeEmail: identityX.config.get("enableChangeEmail"),
57
+ lang,
58
+ };
59
+
60
+ if (isEnabled) {
61
+ marko_web_browser_component_tag({
62
+ name: "IdentityXSubscribe",
63
+ props: props
64
+ }, out, __component, "1");
65
+ }
66
+ }
67
+ }, out, __component, "0");
68
+ }
69
+ }
70
+
71
+ marko_template._ = marko_renderer(render, {
72
+ e_: marko_componentType
73
+ }, marko_component);
74
+
75
+ marko_template.meta = {
76
+ id: "/@mindful-web/marko-web-identity-x$1.30.0/components/subscribe.marko",
77
+ component: "./subscribe.marko",
78
+ tags: [
79
+ "@mindful-web/marko-web/components/browser-component.marko",
80
+ "./context.marko"
81
+ ]
82
+ };
package/config.js CHANGED
@@ -12,7 +12,7 @@ class IdentityXConfiguration {
12
12
  * @param {string} [options.apiToken] An API token to use. Only required when doing write ops.
13
13
  * @param {string[]} [options.requiredServerFields] Required fields, server enforced.
14
14
  * @param {string[]} [options.requiredClientFields] Required fields, client-side only.
15
- * @param {string[]} [options.requiredCreateFields] Required fields, when creating a new user.
15
+ * @param {string[]} [options.requiredCreateFieldRows] Required fields, when creating a new user.
16
16
  * @param {string[]} [options.activeCustomFieldIds] Limit displayed custom fields, if present.
17
17
  * @param {string[]} [options.hiddenFields] The fields to hide from the profile.
18
18
  * @param {function} [options.onHookError]
@@ -23,7 +23,7 @@ class IdentityXConfiguration {
23
23
  apiToken,
24
24
  requiredServerFields = [],
25
25
  requiredClientFields = [],
26
- requiredCreateFields = [],
26
+ requiredCreateFieldRows = [],
27
27
  activeCustomFieldIds = [],
28
28
  additionalCustomFieldIds = [],
29
29
  defaultFieldLabels = {},
@@ -41,7 +41,7 @@ class IdentityXConfiguration {
41
41
  enableChangeEmail: false,
42
42
  requiredServerFields,
43
43
  requiredClientFields,
44
- requiredCreateFields,
44
+ requiredCreateFieldRows,
45
45
  activeCustomFieldIds,
46
46
  additionalCustomFieldIds,
47
47
  defaultFieldLabels,
@@ -129,8 +129,8 @@ class IdentityXConfiguration {
129
129
  return this.getAsArray('requiredClientFields');
130
130
  }
131
131
 
132
- getRequiredCreateFields() {
133
- return this.getAsArray('requiredCreateFields');
132
+ getRequiredCreateFieldRows() {
133
+ return this.getAsArray('requiredCreateFieldRows');
134
134
  }
135
135
 
136
136
  getHiddenFields() {
package/index.js CHANGED
@@ -28,3 +28,13 @@ module.exports = (app, config, {
28
28
  });
29
29
  });
30
30
  };
31
+
32
+ /**
33
+ * @typedef CustomColumnDefinition
34
+ * @prop {("built-in"|"custom-select"|"custom-boolean"|"custom-text")} type The field type
35
+ * @prop {string} [key] The "built-in" field key (givenName, etc)
36
+ * @prop {string} [id] The custom field id
37
+ * @prop {string} [label] The displayed field label
38
+ * @prop {boolean} [required] If the field should be required
39
+ * @prop {number} [width] Column width (percentage specified as decimal)
40
+ */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mindful-web/marko-web-identity-x",
3
- "version": "1.20.3",
3
+ "version": "1.30.0",
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>",
@@ -37,5 +37,5 @@
37
37
  "publishConfig": {
38
38
  "access": "public"
39
39
  },
40
- "gitHead": "c2c60b99628dc560b6cd1fe0b3d64b3bd9a69daf"
40
+ "gitHead": "c2ba676d09db1fbcec92843863485ea36469f242"
41
41
  }
package/routes/login.js CHANGED
@@ -1,5 +1,6 @@
1
1
  const gql = require('graphql-tag');
2
2
  const { asyncRoute } = require('@mindful-web/utils');
3
+ const generateRequiredFieldPayload = require('../utils/generate-required-field-payload');
3
4
 
4
5
  const mutation = gql`
5
6
  mutation SetPreLoginFields($input: SetAppUserUnverifiedDataMutationInput!) {
@@ -30,20 +31,28 @@ module.exports = asyncRoute(async (req, res) => {
30
31
  } = body;
31
32
  let appUser = await identityX.loadAppUserByEmail(email);
32
33
 
33
- // Check for required creation fields
34
- const required = identityX.config.getRequiredCreateFields();
35
- if (required.length) {
36
- // If we don't have a user, or the user is missing some of the required fields
37
- if (!appUser || (appUser && !required.every((key) => appUser[key]))) {
38
- additionalEventData.createdNewUser = true;
39
- // And they weren't presented in the login request, require them.
40
- if (!required.every((key) => body[key])) {
41
- return res.status(400).json({ ok: false, requiresUserInput: true });
42
- }
43
- }
34
+ const definitions = (identityX.config.getRequiredCreateFieldRows() || []).flat();
35
+
36
+ const {
37
+ appUserHasAllRequiredFields,
38
+ hasAllRequiredFields,
39
+ payload: requiredFieldPayload,
40
+ } = generateRequiredFieldPayload({ appUser, body, definitions });
41
+
42
+ const isVerified = appUser && appUser.verified;
43
+
44
+ // Force reverification (skip login form) for previously verified users that are missing fields
45
+ if (isVerified && !appUserHasAllRequiredFields) {
46
+ additionalEventData.forceProfileReVerification = true;
47
+ }
48
+
49
+ // If the user and/or payload is missing some of the required fields, present additional fields
50
+ if (!isVerified && !hasAllRequiredFields) {
51
+ return res.status(400).json({ ok: false, requiresUserInput: true });
44
52
  }
45
53
 
46
- if (!appUser || (appUser && !required.every((key) => appUser[key]))) {
54
+ // If the user is new, or *was* missing fields, mark them as 'created'
55
+ if (!isVerified || !appUserHasAllRequiredFields) {
47
56
  // Create the user.
48
57
  appUser = await identityX.createAppUser({ email });
49
58
  additionalEventData.createdNewUser = true;
@@ -58,12 +67,12 @@ module.exports = asyncRoute(async (req, res) => {
58
67
  }
59
68
 
60
69
  // Set the fields as unverified app data and continue login.
61
- if (required.length && additionalEventData.createdNewUser) {
70
+ if (Object.keys(requiredFieldPayload).length && !isVerified) {
62
71
  const regionalConsentAnswers = Array.isArray(body.regionalConsentAnswers)
63
72
  ? body.regionalConsentAnswers
64
73
  : [];
65
74
  const input = {
66
- ...(required.reduce((obj, key) => ({ ...obj, [key]: body[key] }), {})),
75
+ ...requiredFieldPayload,
67
76
  regionalConsentAnswers: regionalConsentAnswers
68
77
  .map((answer) => ({ policyId: answer.id, given: answer.given })),
69
78
  email,
package/service.js CHANGED
@@ -1,4 +1,4 @@
1
- const { get, getAsObject } = require('@mindful-web/object-path');
1
+ const { get, getAsArray, getAsObject } = require('@mindful-web/object-path');
2
2
  const { getResponseCookies } = require('@mindful-web/utils');
3
3
  const createClient = require('./utils/create-client');
4
4
  const getActiveContext = require('./api/queries/get-active-context');
@@ -142,19 +142,20 @@ class IdentityX {
142
142
  *
143
143
  * @returns {Promise<ActiveContext>}
144
144
  */
145
- async loadActiveContext({ forceQuery = false } = {}) {
145
+ async loadActiveContext({ forceQuery = false, withFields = false } = {}) {
146
146
  // Only run the active context query once
147
- if (!this.activeContextQuery || forceQuery) {
148
- this.activeContextQuery = this.client.query({ query: getActiveContext });
147
+ if (!this.activeContextQuery || forceQuery || withFields) {
148
+ this.activeContextQuery = this.client.query({ query: getActiveContext({ withFields }) });
149
149
  }
150
150
  const { data = {} } = await this.activeContextQuery;
151
151
  const activeContext = data.activeAppContext || {};
152
+ const fields = getAsArray(data, 'fields.edges').map((f) => f.node);
152
153
  await callHooksFor(this, 'onLoadActiveContext', {
153
154
  req: this.req,
154
155
  res: this.res,
155
156
  activeContext,
156
157
  });
157
- return activeContext;
158
+ return { ...activeContext, fields };
158
159
  }
159
160
 
160
161
  /**
@@ -0,0 +1,114 @@
1
+ const { get } = require('@mindful-web/object-path');
2
+
3
+ const hasAnswered = (ans) => ans && ans.hasAnswered && ans.answers.length;
4
+
5
+ const hasMappedAnswers = (map) => (id) => {
6
+ const ans = map.get(id);
7
+ return hasAnswered(ans);
8
+ };
9
+
10
+ /**
11
+ * Generates field requirement payload from supplied user/payload state
12
+ *
13
+ * @param {FieldRequirementArgs} arg
14
+ * @returns {FieldRequirementState}
15
+ */
16
+ module.exports = ({ appUser, body, definitions }) => {
17
+ // Check for required creation fields
18
+ const requiredFieldKeys = [...definitions.reduce((set, def) => {
19
+ if (def.type === 'built-in') set.add(def.key);
20
+ return set;
21
+ }, new Set())];
22
+
23
+ // const requiredCustomBooleans = [...definitions.reduce((set, def) => {
24
+ // if (def.type === 'custom-boolean') set.add(def.id);
25
+ // return set;
26
+ // }, new Set())];
27
+
28
+ const requiredCustomSelects = [...definitions.reduce((set, def) => {
29
+ if (def.type === 'custom-select') set.add(def.id);
30
+ return set;
31
+ }, new Set())];
32
+
33
+ // const requiredCustomTexts = [...definitions.reduce((set, def) => {
34
+ // if (def.type === 'custom-text') set.add(def.id);
35
+ // return set;
36
+ // }, new Set())];
37
+
38
+ const userCustomFieldAnswers = new Map([
39
+ // ...(get(appUser, 'customBooleanFieldAnswers') || []).map((a) => [a.field.id, a]),
40
+ ...(get(appUser, 'customSelectFieldAnswers') || []).map((a) => [a.field.id, a]),
41
+ // ...(get(appUser, 'customTextFieldAnswers') || []).map((a) => [a.field.id, a]),
42
+ ]);
43
+
44
+ const customFieldAnswers = new Map([
45
+ ...userCustomFieldAnswers,
46
+ // ...(get(body, 'customBooleanFieldAnswers') || [])
47
+ // .filter(hasAnswered).map((a) => [a.field.id, a]),
48
+ ...(get(body, 'customSelectFieldAnswers') || []).filter(hasAnswered).map((a) => [a.field.id, a]),
49
+ // ...(get(body, 'customTextFieldAnswers') || [])
50
+ // .filter(hasAnswered).map((a) => [a.field.id, a]),
51
+ ]);
52
+
53
+ const appUserHasAllRequiredFields = [
54
+ requiredFieldKeys.every(
55
+ (key) => get(appUser, key),
56
+ ),
57
+ // requiredCustomBooleans.every(
58
+ // (id) => userCustomFieldAnswers.has(id) && userCustomFieldAnswers.get(id).hasAnswered,
59
+ // ),
60
+ requiredCustomSelects.every(hasMappedAnswers(userCustomFieldAnswers)),
61
+ // requiredCustomTexts.every(
62
+ // (id) => userCustomFieldAnswers.has(id) && userCustomFieldAnswers.get(id).hasAnswered,
63
+ // ),
64
+ ].every((v) => v);
65
+
66
+ const hasAllRequiredFields = [
67
+ requiredFieldKeys.every(
68
+ (key) => get(appUser, key) || get(body, key),
69
+ ),
70
+ // requiredCustomBooleans.every(hasMappedAnswers(customFieldAnswers)),
71
+ requiredCustomSelects.every(hasMappedAnswers(customFieldAnswers)),
72
+ // requiredCustomTexts.every(hasMappedAnswers(customFieldAnswers)),
73
+ ].every((v) => v);
74
+
75
+ const payload = {
76
+ ...(requiredFieldKeys.reduce((obj, key) => ({ ...obj, [key]: body[key] }), {})),
77
+ // customBooleanFieldAnswers: [], // @todo
78
+ customSelectFieldAnswers: requiredCustomSelects
79
+ .filter(hasMappedAnswers(customFieldAnswers))
80
+ .map((id) => {
81
+ const answer = customFieldAnswers.get(id);
82
+ const writeInValues = answer.answers.reduce((arr, { id: optionId, writeInValue }) => ([
83
+ ...arr,
84
+ ...(writeInValue ? [{ optionId, value: writeInValue }] : []),
85
+ ]), []);
86
+ return {
87
+ fieldId: answer.field.id,
88
+ optionIds: answer.answers.map((a) => a.id),
89
+ ...(writeInValues && { writeInValues }),
90
+ };
91
+ }),
92
+ // customTextFieldAnswers: [], // @todo
93
+ };
94
+
95
+ return {
96
+ appUserHasAllRequiredFields,
97
+ hasAllRequiredFields,
98
+ payload,
99
+ requiredFieldKeys,
100
+ };
101
+ };
102
+
103
+ /**
104
+ * @typedef FieldRequirementArgs
105
+ * @prop {import('../utils/create-identity-builder').IdentityXAppUser?} [appUser]
106
+ * @prop {object} body The submitted kv payload
107
+ * @prop {import('..').CustomColumnDefinition[]} definitions The required field definitions
108
+ *
109
+ * @typedef FieldRequirementState
110
+ * @prop {boolean} appUserHasAllRequiredFields If the app user data met requirements
111
+ * @prop {boolean} hasAllRequiredFields If the submitted data meets requirements
112
+ * @prop {object} payload A crafted payload to update required fields
113
+ * @prop {string} requiredFieldKeys If present, the required built-in field keys
114
+ */