From f8aded64452cb6fff0443631bf48078114d164f1 Mon Sep 17 00:00:00 2001
From: Brian Miller
Date: Mon, 16 Oct 2023 13:50:05 -0500
Subject: [PATCH 01/23] Add progresive components and routes
Initial port from profile components and routes as it will have to support the same variation of inputs. It does have added logic to only display one question at the moment based on array of configured ids.
example: [ givenName, familyName, phone, 618a8a62934f8400ad4beb8f]
It will only display on unanswered question in order at the moment.
---
.../marko-web-identity-x/browser/index.js | 7 +
.../browser/progressive.vue | 661 ++++++++++++++++++
.../components/form-progressive.marko | 41 ++
.../components/marko.json | 12 +
packages/marko-web-identity-x/config.js | 7 +
packages/marko-web-identity-x/routes/index.js | 2 +
.../routes/progressive.js | 132 ++++
7 files changed, 862 insertions(+)
create mode 100644 packages/marko-web-identity-x/browser/progressive.vue
create mode 100644 packages/marko-web-identity-x/components/form-progressive.marko
create mode 100644 packages/marko-web-identity-x/routes/progressive.js
diff --git a/packages/marko-web-identity-x/browser/index.js b/packages/marko-web-identity-x/browser/index.js
index 454aadd0a..b4d07d165 100644
--- a/packages/marko-web-identity-x/browser/index.js
+++ b/packages/marko-web-identity-x/browser/index.js
@@ -9,6 +9,7 @@ const Download = () => import(/* webpackChunkName: "identity-x-download" */ './d
const Logout = () => import(/* webpackChunkName: "identity-x-logout" */ './logout.vue');
const Login = () => import(/* webpackChunkName: "identity-x-login" */ './login.vue');
const Profile = () => import(/* webpackChunkName: "identity-x-profile" */ './profile.vue');
+const Progressive = () => import(/* webpackChunkName: "identity-x-progressive" */ './progressive.vue');
const CommentStream = () => import(/* webpackChunkName: "identity-x-comment-stream" */ './comments/stream.vue');
const $graphql = createGraphqlClient({ uri: '/__graphql' });
@@ -25,6 +26,7 @@ export default (Browser, {
CustomLoginComponent,
CustomLogoutComponent,
CustomProfileComponent,
+ CustomProgressiveComponent,
} = {}) => {
const AccessComponent = CustomAccessComponent || Access;
const AuthenticateComponent = CustomAuthenticateComponent || Authenticate;
@@ -35,6 +37,7 @@ export default (Browser, {
const LoginComponent = CustomLoginComponent || Login;
const LogoutComponent = CustomLogoutComponent || Logout;
const ProfileComponent = CustomProfileComponent || Profile;
+ const ProgressiveComponent = CustomProgressiveComponent || Progressive;
window.IdentityX = new IdentityX();
@@ -48,6 +51,7 @@ export default (Browser, {
Browser.register('IdentityXLogin', LoginComponent, { provide: { EventBus } });
Browser.register('IdentityXLogout', LogoutComponent, { provide: { EventBus } });
Browser.register('IdentityXProfile', ProfileComponent, { provide: { EventBus } });
+ Browser.register('IdentityXProgressive', ProgressiveComponent, { provide: { EventBus } });
// Ensure the client-side IdX context is refreshed when the authentication event occurs
EventBus.$on('identity-x-authenticated', () => window.IdentityX.refreshContext());
@@ -66,6 +70,7 @@ export default (Browser, {
'identity-x-login-mounted',
'identity-x-logout-mounted',
'identity-x-profile-mounted',
+ 'identity-x-progressive-mounted',
// Actions/submissions
'identity-x-access-submitted',
'identity-x-authenticated',
@@ -79,6 +84,7 @@ export default (Browser, {
'identity-x-login-link-sent',
'identity-x-logout',
'identity-x-profile-updated',
+ 'identity-x-progressive-updated',
// Errors
'identity-x-access-errored',
'identity-x-authenticate-errored',
@@ -90,6 +96,7 @@ export default (Browser, {
'identity-x-login-errored',
'identity-x-logout-errored',
'identity-x-profile-errored',
+ 'identity-x-progressive-errored',
].forEach((event) => {
EventBus.$on(event, (args) => {
if (!window.IdentityX) return;
diff --git a/packages/marko-web-identity-x/browser/progressive.vue b/packages/marko-web-identity-x/browser/progressive.vue
new file mode 100644
index 000000000..c949d9c3a
--- /dev/null
+++ b/packages/marko-web-identity-x/browser/progressive.vue
@@ -0,0 +1,661 @@
+
+
+
+
You must be logged in to modify your user profile.
+
+
+
+
+
diff --git a/packages/marko-web-identity-x/components/form-progressive.marko b/packages/marko-web-identity-x/components/form-progressive.marko
new file mode 100644
index 000000000..f445568b7
--- /dev/null
+++ b/packages/marko-web-identity-x/components/form-progressive.marko
@@ -0,0 +1,41 @@
+import { get } from "@parameter1/base-cms-object-path";
+import defaultValue from "@parameter1/base-cms-marko-core/utils/default-value";
+
+$ const { req } = out.global;
+$ const { identityX, query } = req;
+$ const additionalEventData = defaultValue(input.additionalEventData, {});
+
+$ console.log(identityX.config.getProgresiveQuestions())
+
+
+
+ $ const props = {
+ additionalEventData: additionalEventData,
+ loginSource: input.loginSource,
+ activeUser: user,
+ requiredServerFields: identityX.config.getRequiredServerFields(),
+ requiredClientFields: identityX.config.getRequiredClientFields(),
+ requiredCreateFields: identityX.config.getRequiredCreateFields(),
+ activeCustomFieldIds: identityX.config.getActiveCustomFieldIds(),
+ progressiveFields: identityX.config.getProgresiveQuestions(),
+ defaultFieldLabels: identityX.config.get("defaultFieldLabels"),
+ hiddenFields: identityX.config.getHiddenFields(),
+ defaultCountryCode: identityX.config.get('defaultCountryCode'),
+ booleanQuestionsLabel: identityX.config.get('booleanQuestionsLabel'),
+ callToAction: input.callToAction,
+ reloadPageOnSubmit: input.reloadPageOnSubmit,
+ buttonLabel: input.buttonLabel,
+ endpoints: identityX.config.getEndpoints(),
+ consentPolicy: get(application, "organization.consentPolicy"),
+ emailConsentRequest: get(application, "organization.emailConsentRequest"),
+ appContextId: identityX.config.get("appContextId"),
+ regionalConsentPolicies: get(application, "organization.regionalConsentPolicies"),
+ returnTo: query.returnTo,
+ returnToDelay: input.returnToDelay,
+ enableChangeEmail: identityX.config.get("enableChangeEmail"),
+ };
+
+
+
+
+
diff --git a/packages/marko-web-identity-x/components/marko.json b/packages/marko-web-identity-x/components/marko.json
index c09b165e8..32c5545aa 100644
--- a/packages/marko-web-identity-x/components/marko.json
+++ b/packages/marko-web-identity-x/components/marko.json
@@ -66,6 +66,18 @@
"@return-to-delay": "number",
"@button-label": "string"
},
+ "": {
+ "template": "./form-progressive.marko",
+ "@additional-event-data": "object",
+ "@login-source": {
+ "type": "string",
+ "default-value": "default"
+ },
+ "@call-to-action": "string",
+ "@reload-page-on-submit": "boolean",
+ "@return-to-delay": "number",
+ "@button-label": "string"
+ },
"": {
"template": "./comment-stream.marko",
"@additional-event-data": "object",
diff --git a/packages/marko-web-identity-x/config.js b/packages/marko-web-identity-x/config.js
index b0544cc67..1284edbf5 100644
--- a/packages/marko-web-identity-x/config.js
+++ b/packages/marko-web-identity-x/config.js
@@ -25,6 +25,7 @@ class IdentityXConfiguration {
requiredClientFields = [],
requiredCreateFields = [],
activeCustomFieldIds = [],
+ progressiveQuestions = [],
defaultFieldLabels = {},
hiddenFields = ['city', 'street', 'addressExtra', 'phoneNumber', 'mobileNumber'],
defaultCountryCode,
@@ -42,6 +43,7 @@ class IdentityXConfiguration {
requiredClientFields,
requiredCreateFields,
activeCustomFieldIds,
+ progressiveQuestions,
defaultFieldLabels,
hiddenFields,
defaultCountryCode,
@@ -64,6 +66,7 @@ class IdentityXConfiguration {
'logout',
'register',
'profile',
+ 'progressive',
];
this.hooks = validHooks.reduce((o, name) => ({ ...o, [name]: [] }), {});
}
@@ -139,6 +142,10 @@ class IdentityXConfiguration {
return this.getAsArray('activeCustomFieldIds');
}
+ getProgresiveQuestions() {
+ return this.getAsArray('progressiveQuestions');
+ }
+
get(path, def) {
return get(this.options, path, def);
}
diff --git a/packages/marko-web-identity-x/routes/index.js b/packages/marko-web-identity-x/routes/index.js
index 7810ac807..f0db11218 100644
--- a/packages/marko-web-identity-x/routes/index.js
+++ b/packages/marko-web-identity-x/routes/index.js
@@ -15,6 +15,7 @@ const login = require('./login');
const loginFields = require('./login-fields');
const logout = require('./logout');
const profile = require('./profile');
+const progressive = require('./progressive');
const regions = require('./regions');
const router = Router();
@@ -35,6 +36,7 @@ router.post('/login-fields', loginFields);
router.post('/login', login);
router.post('/logout', logout);
router.post('/profile', profile);
+router.post('/progressive', progressive);
router.use(jsonErrorHandler());
module.exports = router;
diff --git a/packages/marko-web-identity-x/routes/progressive.js b/packages/marko-web-identity-x/routes/progressive.js
new file mode 100644
index 000000000..2faafd43d
--- /dev/null
+++ b/packages/marko-web-identity-x/routes/progressive.js
@@ -0,0 +1,132 @@
+const gql = require('graphql-tag');
+const { asyncRoute } = require('@parameter1/base-cms-utils');
+const { getAsArray } = require('@parameter1/base-cms-object-path');
+const userFragment = require('../api/fragments/active-user');
+const callHooksFor = require('../utils/call-hooks-for');
+
+const mutation = gql`
+ mutation UpdateUserProfile($input: UpdateOwnAppUserMutationInput!) {
+ updateOwnAppUser(input: $input) {
+ ...ActiveUserFragment
+ }
+ }
+
+ ${userFragment}
+`;
+
+const consentAnswers = gql`
+ mutation SetAppUserRegionalConsent($input: SetAppUserRegionalConsentMutationInput!) {
+ setAppUserRegionalConsent(input: $input) {
+ id
+ }
+ }
+`;
+
+const customBooleanFieldsMutation = gql`
+ mutation SetAppUserCustomBooleanFields($input: UpdateOwnAppUserCustomBooleanAnswersMutationInput!) {
+ updateOwnAppUserCustomBooleanAnswers(input: $input) {
+ id
+ }
+ }
+`;
+
+const customSelectFieldsMutation = gql`
+ mutation SetAppUserCustomSelectFields($input: UpdateOwnAppUserCustomSelectAnswersMutationInput!) {
+ updateOwnAppUserCustomSelectAnswers(input: $input) {
+ id
+ }
+ }
+`;
+
+module.exports = asyncRoute(async (req, res) => {
+ const { identityX, body } = req;
+ const {
+ givenName,
+ familyName,
+ organization,
+ organizationTitle,
+ countryCode,
+ regionCode,
+ postalCode,
+ city,
+ street,
+ addressExtra,
+ phoneNumber,
+ receiveEmail,
+ regionalConsentAnswers,
+ customBooleanFieldAnswers,
+ customSelectFieldAnswers,
+ additionalEventData = {},
+ } = body;
+ const input = {
+ givenName,
+ familyName,
+ organization,
+ organizationTitle,
+ countryCode,
+ regionCode,
+ postalCode,
+ city,
+ street,
+ addressExtra,
+ phoneNumber,
+ receiveEmail,
+ };
+
+ const activeCustomFieldIds = getAsArray(identityX, 'config.options.activeCustomFieldIds');
+
+ const answers = regionalConsentAnswers
+ .map((answer) => ({ policyId: answer.id, given: answer.given }));
+
+ if (answers.length) {
+ await identityX.client.mutate({ mutation: consentAnswers, variables: { input: { answers } } });
+ }
+
+ if (customBooleanFieldAnswers.length) {
+ // only update custom questions when there some :)
+ const customBooleanFieldsInput = customBooleanFieldAnswers.map((fieldAnswer) => ({
+ fieldId: fieldAnswer.field.id,
+ // can either be true, false or null. convert null to false.
+ // the form submit is effectively answers the question.
+ value: Boolean(fieldAnswer.answer),
+ })).filter(
+ activeCustomFieldIds.length > 0
+ ? ({ fieldId }) => activeCustomFieldIds.includes(fieldId)
+ : () => true,
+ );
+ await identityX.client.mutate({
+ mutation: customBooleanFieldsMutation,
+ variables: { input: { answers: customBooleanFieldsInput } },
+ });
+ }
+
+ if (customSelectFieldAnswers.length) {
+ // only update custom questions when there some :)
+ const customSelectFieldsInput = customSelectFieldAnswers.map((fieldAnswer) => ({
+ fieldId: fieldAnswer.field.id,
+ optionIds: fieldAnswer.answers.map(({ id }) => id),
+ writeInValues: fieldAnswer.answers.reduce((arr, { id, writeInValue }) => ([
+ ...arr,
+ ...(writeInValue ? [{ optionId: id, value: writeInValue }] : []),
+ ]), []),
+ })).filter(
+ activeCustomFieldIds.length > 0
+ ? ({ fieldId }) => activeCustomFieldIds.includes(fieldId)
+ : () => true,
+ );
+ await identityX.client.mutate({
+ mutation: customSelectFieldsMutation,
+ variables: { input: { answers: customSelectFieldsInput } },
+ });
+ }
+
+ const { data } = await identityX.client.mutate({ mutation, variables: { input } });
+ const { updateOwnAppUser: user } = data;
+ await callHooksFor(identityX, 'onUserProfileUpdate', {
+ additionalEventData,
+ ...(additionalEventData || {}),
+ req,
+ user,
+ });
+ res.json({ ok: true, user, additionalEventData });
+});
From 7c5dc279368043cbcf3fdba630a5d0b907772c93 Mon Sep 17 00:00:00 2001
From: Brian Miller
Date: Fri, 20 Oct 2023 07:46:38 -0500
Subject: [PATCH 02/23] remove change email from progressive
---
.../browser/progressive.vue | 19 -------------------
1 file changed, 19 deletions(-)
diff --git a/packages/marko-web-identity-x/browser/progressive.vue b/packages/marko-web-identity-x/browser/progressive.vue
index c949d9c3a..6d3775c77 100644
--- a/packages/marko-web-identity-x/browser/progressive.vue
+++ b/packages/marko-web-identity-x/browser/progressive.vue
@@ -5,25 +5,6 @@