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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -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"
@@ -138,6 +138,15 @@
138
138
  :value="customField.answer"
139
139
  @input="onCustomBooleanChange(customField.id, $event)"
140
140
  />
141
+ <custom-text
142
+ v-else-if="type === 'custom-text' && customField"
143
+ :id="fieldId"
144
+ :class-name="className"
145
+ :label="label"
146
+ :required="required"
147
+ :value="customField.value"
148
+ @change="onCustomTextChange(customField, $event)"
149
+ />
141
150
  <pre v-else>
142
151
  label: {{ label }}
143
152
  key: {{ fieldKey }}
@@ -156,6 +165,7 @@ import City from './form/fields/city.vue';
156
165
  import CountryCode from './form/fields/country.vue';
157
166
  import CustomBoolean from './form/fields/custom-boolean.vue';
158
167
  import CustomSelect from './form/fields/custom-select.vue';
168
+ import CustomText from './form/fields/custom-text.vue';
159
169
  import FamilyName from './form/fields/family-name.vue';
160
170
  import FormLabel from './form/common/form-label.vue';
161
171
  import GivenName from './form/fields/given-name.vue';
@@ -177,6 +187,7 @@ export default {
177
187
  CountryCode,
178
188
  CustomSelect,
179
189
  CustomBoolean,
190
+ CustomText,
180
191
  FamilyName,
181
192
  FormLabel,
182
193
  GivenName,
@@ -208,7 +219,7 @@ export default {
208
219
  type: String,
209
220
  required: true,
210
221
  validator(value) {
211
- return ['built-in', 'custom-select', 'custom-boolean'].includes(value);
222
+ return ['built-in', 'custom-select', 'custom-boolean', 'custom-text'].includes(value);
212
223
  },
213
224
  },
214
225
  required: {
@@ -266,7 +277,20 @@ export default {
266
277
  */
267
278
  customField() {
268
279
  const { fieldId, user, type } = this;
269
- const key = type === 'custom-select' ? 'customSelectFieldAnswers' : 'customBooleanFieldAnswers';
280
+
281
+ let key = 'customSelectFieldAnswers';
282
+
283
+ switch (type) {
284
+ case 'custom-text':
285
+ key = 'customTextFieldAnswers';
286
+ break;
287
+ case 'custom-boolean':
288
+ key = 'customBooleanFieldAnswers';
289
+ break;
290
+ // ... more cases
291
+ default:
292
+ // Code to execute if no case matches the expression
293
+ }
270
294
  const found = user[key].find((ans) => ans.id === fieldId);
271
295
  return found;
272
296
  },
@@ -325,16 +349,34 @@ export default {
325
349
  const objIndex = this.customBooleanFieldAnswers.findIndex(((obj) => obj.id === id));
326
350
  const answer = !this.customBooleanFieldAnswers[objIndex].answer;
327
351
  this.customBooleanFieldAnswers[objIndex].answer = answer;
352
+ this.customBooleanFieldAnswers[objIndex].hasAnswered = true;
328
353
  this.user.customBooleanFieldAnswers = this.customBooleanFieldAnswers;
329
354
  },
330
355
 
331
356
  /**
332
357
  *
333
358
  */
334
- onCustomSelectChange(answers, $event) {
359
+ onCustomSelectChange(field, $event) {
335
360
  const ids = Array.isArray($event) ? [...$event] : [...($event ? [$event] : [])];
336
- answers.splice(0);
337
- if (ids.length) answers.push(...ids.map((id) => ({ id })));
361
+ field.answers.splice(0);
362
+ if (ids.length) {
363
+ // eslint-disable-next-line no-param-reassign
364
+ field.hasAnswered = true;
365
+ field.answers.push(...ids.map((id) => ({ id })));
366
+ }
367
+ },
368
+
369
+ /**
370
+ *
371
+ */
372
+ onCustomTextChange(field, $event) {
373
+ // hack to prevent on focus out with no value from resetting value
374
+ // @todo find a better solution!!!
375
+ const value = $event === '' && field.value !== '' ? field.value : $event;
376
+ this.customField.value = $event;
377
+ // eslint-disable-next-line max-len
378
+ const customTextFieldAnswers = this.user.customTextFieldAnswers.map((obj) => (obj.id === field.id ? { ...obj, value, hasAnswered: value !== '' } : obj));
379
+ this.user.customTextFieldAnswers = customTextFieldAnswers;
338
380
  },
339
381
  },
340
382
  };
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.31.2/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.31.2/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.31.2/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.31.2/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.31.2/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.31.2/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.31.2/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.31.2/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.31.2/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.31.2/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.31.2/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.31.2/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.31.2/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.31.2/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.31.2/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.31.2/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.31.2/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.31.2/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.31.2/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.31.2/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.31.2/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.31.2/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.31.2/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.31.2/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.31.2/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.31.2/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.31.2",
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": "b939602557484645950c536d00366b76e9ea8fca"
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,123 @@
1
+ const { get } = require('@mindful-web/object-path');
2
+
3
+ // eslint-disable-next-line max-len
4
+ const hasAnswered = (ans) => ans && ans.hasAnswered && (ans.value || (ans.answers && ans.answers.length));
5
+
6
+ const hasMappedAnswers = (map) => (id) => {
7
+ const ans = map.get(id);
8
+ return hasAnswered(ans);
9
+ };
10
+
11
+ /**
12
+ * Generates field requirement payload from supplied user/payload state
13
+ *
14
+ * @param {FieldRequirementArgs} arg
15
+ * @returns {FieldRequirementState}
16
+ */
17
+ module.exports = ({ appUser, body, definitions }) => {
18
+ // Check for required creation fields
19
+ const requiredFieldKeys = [...definitions.reduce((set, def) => {
20
+ if (def.type === 'built-in') set.add(def.key);
21
+ return set;
22
+ }, new Set())];
23
+
24
+ // const requiredCustomBooleans = [...definitions.reduce((set, def) => {
25
+ // if (def.type === 'custom-boolean') set.add(def.id);
26
+ // return set;
27
+ // }, new Set())];
28
+
29
+ const requiredCustomSelects = [...definitions.reduce((set, def) => {
30
+ if (def.type === 'custom-select') set.add(def.id);
31
+ return set;
32
+ }, new Set())];
33
+
34
+ const requiredCustomTexts = [...definitions.reduce((set, def) => {
35
+ if (def.type === 'custom-text') set.add(def.id);
36
+ return set;
37
+ }, new Set())];
38
+
39
+ const userCustomFieldAnswers = new Map([
40
+ // ...(get(appUser, 'customBooleanFieldAnswers') || []).map((a) => [a.field.id, a]),
41
+ ...(get(appUser, 'customSelectFieldAnswers') || []).map((a) => [a.field.id, a]),
42
+ ...(get(appUser, 'customTextFieldAnswers') || []).map((a) => [a.field.id, a]),
43
+ ]);
44
+
45
+ const customFieldAnswers = new Map([
46
+ ...userCustomFieldAnswers,
47
+ // ...(get(body, 'customBooleanFieldAnswers') || [])
48
+ // .filter(hasAnswered).map((a) => [a.field.id, a]),
49
+ ...(get(body, 'customSelectFieldAnswers') || []).filter(hasAnswered).map((a) => [a.field.id, a]),
50
+ ...(get(body, 'customTextFieldAnswers') || [])
51
+ .filter(hasAnswered).map((a) => [a.field.id, a]),
52
+ ]);
53
+
54
+ const appUserHasAllRequiredFields = [
55
+ requiredFieldKeys.every(
56
+ (key) => get(appUser, key),
57
+ ),
58
+ // requiredCustomBooleans.every(
59
+ // (id) => userCustomFieldAnswers.has(id) && userCustomFieldAnswers.get(id).hasAnswered,
60
+ // ),
61
+ requiredCustomSelects.every(hasMappedAnswers(userCustomFieldAnswers)),
62
+ requiredCustomTexts.every(
63
+ (id) => userCustomFieldAnswers.has(id) && userCustomFieldAnswers.get(id).hasAnswered,
64
+ ),
65
+ ].every((v) => v);
66
+
67
+ const hasAllRequiredFields = [
68
+ requiredFieldKeys.every(
69
+ (key) => get(appUser, key) || get(body, key),
70
+ ),
71
+ // requiredCustomBooleans.every(hasMappedAnswers(customFieldAnswers)),
72
+ requiredCustomSelects.every(hasMappedAnswers(customFieldAnswers)),
73
+ requiredCustomTexts.every(hasMappedAnswers(customFieldAnswers)),
74
+ ].every((v) => v);
75
+
76
+ const payload = {
77
+ ...(requiredFieldKeys.reduce((obj, key) => ({ ...obj, [key]: body[key] }), {})),
78
+ // customBooleanFieldAnswers: [], // @todo
79
+ customSelectFieldAnswers: requiredCustomSelects
80
+ .filter(hasMappedAnswers(customFieldAnswers))
81
+ .map((id) => {
82
+ const answer = customFieldAnswers.get(id);
83
+ const writeInValues = answer.answers.reduce((arr, { id: optionId, writeInValue }) => ([
84
+ ...arr,
85
+ ...(writeInValue ? [{ optionId, value: writeInValue }] : []),
86
+ ]), []);
87
+ return {
88
+ fieldId: answer.field.id,
89
+ optionIds: answer.answers.map((a) => a.id),
90
+ ...(writeInValues && { writeInValues }),
91
+ };
92
+ }),
93
+ customTextFieldAnswers: requiredCustomTexts
94
+ .filter(hasMappedAnswers(customFieldAnswers))
95
+ .map((id) => {
96
+ const answer = customFieldAnswers.get(id);
97
+ return {
98
+ fieldId: answer.field.id,
99
+ value: answer.value,
100
+ };
101
+ }), // @todo
102
+ };
103
+
104
+ return {
105
+ appUserHasAllRequiredFields,
106
+ hasAllRequiredFields,
107
+ payload,
108
+ requiredFieldKeys,
109
+ };
110
+ };
111
+
112
+ /**
113
+ * @typedef FieldRequirementArgs
114
+ * @prop {import('../utils/create-identity-builder').IdentityXAppUser?} [appUser]
115
+ * @prop {object} body The submitted kv payload
116
+ * @prop {import('..').CustomColumnDefinition[]} definitions The required field definitions
117
+ *
118
+ * @typedef FieldRequirementState
119
+ * @prop {boolean} appUserHasAllRequiredFields If the app user data met requirements
120
+ * @prop {boolean} hasAllRequiredFields If the submitted data meets requirements
121
+ * @prop {object} payload A crafted payload to update required fields
122
+ * @prop {string} requiredFieldKeys If present, the required built-in field keys
123
+ */