@salesforcedevs/dw-components 1.3.148-canary.26 → 1.3.148-canary.28

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/lwc.config.json CHANGED
@@ -15,6 +15,7 @@
15
15
  "dw/eventsList",
16
16
  "dw/instrumentation",
17
17
  "dw/j2sCardSequence",
18
+ "dw/j2sCardSequenceStep",
18
19
  "dw/j2sForm",
19
20
  "dw/newsletterForm",
20
21
  "dw/podcastSubscription",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@salesforcedevs/dw-components",
3
- "version": "1.3.148-canary.26",
3
+ "version": "1.3.148-canary.28",
4
4
  "description": "Lightning web components for https://developer.salesforce.com",
5
5
  "license": "MIT",
6
6
  "engines": {
@@ -1,6 +1,4 @@
1
1
  @import "dxHelpers/reset";
2
- @import "dxHelpers/text";
3
- @import "dxHelpers/card";
4
2
 
5
3
  :host {
6
4
  --dx-c-button-custom-color: var(--dx-g-blue-vibrant-50);
@@ -14,46 +12,3 @@
14
12
  dx-step-sequence {
15
13
  scroll-margin-top: var(--dx-g-global-header-height);
16
14
  }
17
-
18
- dx-step-sequence-step:last-child dx-card-step::part(footer-container) {
19
- background-color: var(--dx-g-indigo-vibrant-95);
20
- border-radius: 8px;
21
- margin: 0 30px 30px 30px;
22
- }
23
-
24
- [slot="secondary-action-section"] {
25
- color: var(--dx-g-red-vibrant-50);
26
- position: relative;
27
- font-size: var(--dx-g-text-xs, 12px);
28
- font-family: var(--dx-g-font-sans);
29
- line-height: 18px;
30
- text-align: left;
31
- }
32
-
33
- .body-container li {
34
- line-height: var(--dx-g-text-2xl);
35
- }
36
-
37
- .body-container p:not(:last-child) {
38
- padding-bottom: 20px;
39
- }
40
-
41
- .body-markup {
42
- display: block;
43
- }
44
-
45
- .final-email-address {
46
- display: block;
47
- margin-top: 20px;
48
- line-height: 24px;
49
- color: var(--dx-g-blue-vibrant-50);
50
- }
51
-
52
- .referral-email-field {
53
- --dx-c-input-width: 100%;
54
- }
55
-
56
- .spinner-container {
57
- min-height: 200px;
58
- position: relative;
59
- }
@@ -9,67 +9,19 @@
9
9
  >
10
10
  <template for:each={stepsData} for:item="stepDatum" for:index="index">
11
11
  <dx-step-sequence-step key={stepDatum.id}>
12
- <dx-card-step
13
- header-icon-symbol={stepDatum.headerData.iconSymbol}
14
- header-icon-sprite={stepDatum.headerData.iconSprite}
15
- header-icon-color={stepDatum.headerData.iconColor}
16
- header-background-color={stepDatum.headerData.backgroundColor}
17
- header-text-color={stepDatum.headerData.textColor}
18
- show-step-number={stepDatum.showStepNumber}
19
- step-count={stepsData.length}
12
+ <dw-j2s-card-sequence-step
13
+ country-options={countries}
14
+ is-loading={isLoading}
15
+ oncountrychange={handleCountryChange}
16
+ ongetstarted={handleGetStarted}
17
+ onformsubmit={handleFormSubmit}
18
+ recaptcha-token={recaptchaToken}
19
+ selected-country={selectedCountry}
20
+ step-datum={stepDatum}
20
21
  step-index={index}
21
- step-title={stepDatum.stepTitle}
22
- >
23
- <div slot="card-body" class="body-container">
24
- <template if:true={isLoading}>
25
- <div class="spinner-container">
26
- <dx-spinner
27
- size="large"
28
- variant="brand"
29
- ></dx-spinner>
30
- </div>
31
- </template>
32
- <template if:false={isLoading}>
33
- <span lwc:dom="manual" class="body-markup"></span>
34
- <template if:true={stepDatum.formData}>
35
- <dw-j2s-form
36
- id={stepDatum.formData.formId}
37
- countries={countries}
38
- form-metadata={stepDatum.formData}
39
- incoming-user-info={formIncomingUserInfo}
40
- onformvaliditychange={handleFormValidityChange}
41
- recaptcha-token={recaptchaToken}
42
- >
43
- <div slot="form-captcha-slot">
44
- <slot name="captcha-slot"></slot>
45
- </div>
46
- </dw-j2s-form>
47
- </template>
48
- </template>
49
- </div>
50
- <div slot="secondary-action-section">
51
- <span
52
- lwc:dom="manual"
53
- class="secondary-action-markup"
54
- ></span>
55
- </div>
56
- <div slot="primary-action-section">
57
- <dx-button
58
- class="primary-action"
59
- disabled={isJ2sFormInvalid}
60
- href={stepDatum.primaryAction.link}
61
- icon-sprite={stepDatum.primaryAction.iconSprite}
62
- icon-symbol={stepDatum.primaryAction.iconSymbol}
63
- loading={isLoading}
64
- onclick={primaryActionHandler}
65
- size="large"
66
- target={primaryActionLinkTarget}
67
- variant={primaryActionVariant}
68
- >
69
- {stepDatum.primaryAction.text}
70
- </dx-button>
71
- </div>
72
- </dx-card-step>
22
+ step-total-count={stepsData.length}
23
+ user-info={formIncomingUserInfo}
24
+ ></dw-j2s-card-sequence-step>
73
25
  </dx-step-sequence-step>
74
26
  </template>
75
27
  </dx-step-sequence>
@@ -1,12 +1,16 @@
1
1
  import { api, LightningElement } from "lwc";
2
2
  import StepSequence from "dx/stepSequence";
3
3
  import { getListWithUuids } from "dxUtils/list";
4
- import { track } from "dxUtils/analytics";
5
4
  import { toJson } from "dxUtils/normalizers";
6
- import J2sForm from "dw/j2sForm";
5
+ import J2sCardSequenceStep from "dw/j2sCardSequenceStep";
7
6
 
8
7
  export type StepDatum = {
9
- bodyHtml?: string;
8
+ bodyHtml?:
9
+ | string
10
+ | {
11
+ default: string;
12
+ [countryCode: string]: string;
13
+ };
10
14
  formData?: {
11
15
  countriesWithReferralInput?: string[];
12
16
  countriesWithRequiredJobRole?: string[];
@@ -28,9 +32,19 @@ export type StepDatum = {
28
32
  primaryAction: {
29
33
  iconSprite?: string;
30
34
  iconSymbol?: string;
31
- link?: string;
35
+ link?:
36
+ | string
37
+ | {
38
+ default: string;
39
+ [countryCode: string]: string;
40
+ };
32
41
  linkTarget?: string;
33
- text: string;
42
+ text:
43
+ | string
44
+ | {
45
+ default: string;
46
+ [countryCode: string]: string;
47
+ };
34
48
  variant?: string;
35
49
  };
36
50
  secondaryActionHtml?: string;
@@ -54,10 +68,8 @@ export type DrmFormData = {
54
68
  };
55
69
 
56
70
  export default class J2sCardSequence extends LightningElement {
57
- _didRenderStaticInnerHtml = false;
58
71
  _isDrmLoading = false;
59
72
  _isFormSubmitting = false;
60
- _isJ2sFormInvalid = false;
61
73
  _isTbidLoading = false;
62
74
  _recaptchaResetTimeoutId: number | null = null;
63
75
  _stepsData: StepDatum[] = [];
@@ -92,10 +104,11 @@ export default class J2sCardSequence extends LightningElement {
92
104
  });
93
105
  }
94
106
 
95
- private countries = "[]";
107
+ private countries: any[] = [];
96
108
  private currentSequenceStep = 0;
97
- private formSubmissionFailureState = null;
109
+ private formSubmissionFailureState: Partial<DrmFormData> | null = null;
98
110
  private recaptchaToken = "";
111
+ private selectedCountry = "";
99
112
  private sessionStorageId = "j2s-card-sequence";
100
113
  private tbidUserInfo: any; // TODO typings?
101
114
 
@@ -109,28 +122,6 @@ export default class J2sCardSequence extends LightningElement {
109
122
  return Boolean(this.tbidUserInfo);
110
123
  }
111
124
 
112
- private get isJ2sFormInvalid() {
113
- return this.currentSequenceStep === 1 ? this._isJ2sFormInvalid : false;
114
- }
115
- private set isJ2sFormInvalid(isFormInvalid: boolean) {
116
- this._isJ2sFormInvalid = isFormInvalid;
117
- }
118
-
119
- private get primaryActionVariant() {
120
- if (this.currentSequenceStep === 1 && this.isJ2sFormInvalid) {
121
- return "custom"; // override for disabled button styling
122
- }
123
- return this.stepsData[this.currentSequenceStep || 0].primaryAction
124
- .variant;
125
- }
126
-
127
- private get primaryActionLinkTarget() {
128
- return (
129
- this.stepsData[this.currentSequenceStep || 0].primaryAction
130
- .linkTarget || "_blank"
131
- );
132
- }
133
-
134
125
  private get formIncomingUserInfo() {
135
126
  if (!this.tbidUserInfo) {
136
127
  return {} as DrmFormData;
@@ -197,27 +188,30 @@ export default class J2sCardSequence extends LightningElement {
197
188
  }
198
189
 
199
190
  renderedCallback() {
200
- if (this.isLoading) {
201
- this._didRenderStaticInnerHtml = false; // only when `this.isLoading` is true will static HTML need to be re-rendered, since the content will have been replaced by the spinner
202
- return;
203
- }
204
-
205
- if (!this._didRenderStaticInnerHtml) {
206
- this.updateStaticInnerHtml();
207
- this._didRenderStaticInnerHtml = true;
191
+ if (!this.isLoading) {
192
+ (
193
+ this.template.querySelector(
194
+ "dx-step-sequence"
195
+ ) as unknown as StepSequence
196
+ )?.remeasureSteps();
208
197
  }
209
198
 
210
- if (this.formSubmissionFailureState) {
211
- const j2sFormEl = (this.template.querySelector(
212
- "dw-j2s-form"
213
- ) as unknown) as J2sForm | null;
214
- j2sFormEl?.notifySubmitFailure(this.formSubmissionFailureState);
199
+ if (
200
+ this.formSubmissionFailureState &&
201
+ this.stepsData[this.currentSequenceStep].formData
202
+ ) {
203
+ const j2sCardStep = this.template.querySelectorAll(
204
+ "dw-j2s-card-sequence-step"
205
+ ) as unknown as J2sCardSequenceStep[];
206
+ j2sCardStep[this.currentSequenceStep]?.notifyFormSubmitFailure(
207
+ this.formSubmissionFailureState
208
+ );
215
209
  this.formSubmissionFailureState = null;
216
210
  }
217
211
  }
218
212
 
219
- handleFormValidityChange({ detail }: CustomEvent) {
220
- this.isJ2sFormInvalid = !detail.isValid;
213
+ handleCountryChange({ detail }: CustomEvent) {
214
+ this.selectedCountry = detail;
221
215
  }
222
216
 
223
217
  handleStepSequenceChange({ detail }: CustomEvent) {
@@ -240,38 +234,26 @@ export default class J2sCardSequence extends LightningElement {
240
234
  }
241
235
  }
242
236
 
243
- handleGetStarted(evt: Event) {
237
+ handleGetStarted() {
244
238
  // If the user is not yet logged in, we need to prevent moving immediately to the next
245
239
  // step, but set storage up so that they are on the second step when they return to the
246
240
  // site in a logged-in state; then, we need to get them to log in.
247
241
  if (!this.isLoggedIn) {
248
- evt.preventDefault();
249
242
  this.initialStepIndex = 1;
250
243
  this._isTbidLoading = true;
251
244
  (window as any).__startTbidLogin?.(); // call out to DSC tbid controller
245
+ } else {
246
+ this.jumpToStepIndex(1);
252
247
  }
253
248
  }
254
249
 
255
- async handleFormSubmit(evt: Event) {
256
- if (!this.formHandler || this.isJ2sFormInvalid || !this.isLoggedIn) {
250
+ async handleFormSubmit({ detail: formData }: CustomEvent<DrmFormData>) {
251
+ if (!this.formHandler || !this.isLoggedIn) {
257
252
  return;
258
253
  }
259
254
 
260
- evt.preventDefault(); // don't proceed automatically to next step
261
255
  this._isFormSubmitting = true;
262
256
 
263
- const j2sFormEl = (this.template.querySelector(
264
- "dw-j2s-form"
265
- ) as unknown) as J2sForm | null;
266
- const formData = j2sFormEl?.formDataForDrm;
267
- // For some countries, explicit approvals will be present; for others, it is implicitly assumed
268
- if (typeof formData.Opt_In__c !== "boolean") {
269
- formData.Opt_In__c = true;
270
- }
271
- if (typeof formData.Privacy_Statement__c !== "boolean") {
272
- formData.Privacy_Statement__c = true;
273
- }
274
-
275
257
  try {
276
258
  const res = await fetch(this.formHandler, {
277
259
  method: "POST",
@@ -310,31 +292,6 @@ export default class J2sCardSequence extends LightningElement {
310
292
  this._isFormSubmitting = false;
311
293
  }
312
294
 
313
- primaryActionHandler(evt: Event) {
314
- const target = evt.target as HTMLButtonElement;
315
-
316
- if (!target || target.disabled) {
317
- evt.preventDefault();
318
- return;
319
- }
320
-
321
- track(target, "custEv_ctaButtonClick", {
322
- click_text: target.textContent,
323
- element_title: this.stepsData[this.currentSequenceStep].stepTitle,
324
- click_url:
325
- this.stepsData[this.currentSequenceStep].primaryAction.link ||
326
- "",
327
- element_type: "button",
328
- content_category: "cta"
329
- });
330
-
331
- if (!this.currentSequenceStep) {
332
- this.handleGetStarted(evt);
333
- } else if (this.currentSequenceStep === 1) {
334
- this.handleFormSubmit(evt);
335
- }
336
- }
337
-
338
295
  private resetCustomButtonColors() {
339
296
  let bgColor;
340
297
  let textColor;
@@ -365,42 +322,11 @@ export default class J2sCardSequence extends LightningElement {
365
322
  if (andStoreIndex) {
366
323
  this.initialStepIndex = stepIndex; // update sessionStorage value
367
324
  }
368
- ((this.template.querySelector(
369
- "dx-step-sequence"
370
- ) as unknown) as StepSequence)?.jumpToStep(stepIndex);
371
- }
372
-
373
- private updateStaticInnerHtml() {
374
- const bodyMarkupContainers = this.template.querySelectorAll(
375
- "span.body-markup"
376
- );
377
- const secondaryActionMarkupContainers = this.template.querySelectorAll(
378
- "span.secondary-action-markup"
379
- );
380
-
381
- this.stepsData.forEach((step, stepIndex) => {
382
- const { bodyHtml, secondaryActionHtml } = step;
383
- const bodyMarkupContainer = bodyMarkupContainers[stepIndex];
384
- const secondaryActionMarkupContainer =
385
- secondaryActionMarkupContainers[stepIndex];
386
-
387
- if (bodyMarkupContainer) {
388
- let markup = bodyHtml;
389
- if (stepIndex === 2) {
390
- // User's email is supposed to show on final step
391
- markup = `${bodyHtml}${
392
- !this.formIncomingUserInfo.Email
393
- ? ""
394
- : `<span class="final-email-address">${this.formIncomingUserInfo.Email}</span>`
395
- }`;
396
- }
397
- bodyMarkupContainer.innerHTML = markup || "";
398
- }
399
- if (secondaryActionMarkupContainer) {
400
- secondaryActionMarkupContainer.innerHTML =
401
- secondaryActionHtml || "";
402
- }
403
- });
325
+ (
326
+ this.template.querySelector(
327
+ "dx-step-sequence"
328
+ ) as unknown as StepSequence
329
+ )?.jumpToStep(stepIndex);
404
330
  }
405
331
 
406
332
  private async getCountryList() {
@@ -414,8 +340,7 @@ export default class J2sCardSequence extends LightningElement {
414
340
  if (!res.ok) {
415
341
  throw new Error(errorMsg);
416
342
  }
417
- const data = await res.json();
418
- this.countries = JSON.stringify(data);
343
+ this.countries = await res.json();
419
344
  } catch (error) {
420
345
  console.error(error);
421
346
  if (this.initialStepIndex > 0) {
@@ -435,6 +360,7 @@ export default class J2sCardSequence extends LightningElement {
435
360
  const res = await fetch(`${this.tbidApiBaseUrl}/userinfo`);
436
361
  if (res.ok) {
437
362
  this.tbidUserInfo = await res.json();
363
+ this.selectedCountry = this.formIncomingUserInfo.MailingCountry;
438
364
  }
439
365
  } catch (ex) {
440
366
  // noop; nothing to do here
@@ -0,0 +1,47 @@
1
+ @import "dxHelpers/reset";
2
+ @import "dxHelpers/text";
3
+ @import "dxHelpers/card";
4
+
5
+ /* Special styling for the final step's actions if they are shown */
6
+ dx-card-step.final-card-with-action::part(footer-container) {
7
+ background-color: var(--dx-g-indigo-vibrant-95);
8
+ border-radius: 8px;
9
+ margin: 0 30px 30px 30px;
10
+ }
11
+
12
+ [slot="secondary-action-section"] {
13
+ color: var(--dx-g-red-vibrant-50);
14
+ position: relative;
15
+ font-size: var(--dx-g-text-xs, 12px);
16
+ font-family: var(--dx-g-font-sans);
17
+ line-height: 18px;
18
+ text-align: left;
19
+ }
20
+
21
+ .body-container li {
22
+ line-height: var(--dx-g-text-2xl);
23
+ }
24
+
25
+ .body-container p:not(:last-child) {
26
+ padding-bottom: 20px;
27
+ }
28
+
29
+ .body-markup {
30
+ display: block;
31
+ }
32
+
33
+ .final-email-address {
34
+ display: block;
35
+ margin-top: 20px;
36
+ line-height: 24px;
37
+ color: var(--dx-g-blue-vibrant-50);
38
+ }
39
+
40
+ .referral-email-field {
41
+ --dx-c-input-width: 100%;
42
+ }
43
+
44
+ .spinner-container {
45
+ min-height: 200px;
46
+ position: relative;
47
+ }
@@ -0,0 +1,59 @@
1
+ <template>
2
+ <dx-card-step
3
+ class={stepClassName}
4
+ header-icon-symbol={stepDatum.headerData.iconSymbol}
5
+ header-icon-sprite={stepDatum.headerData.iconSprite}
6
+ header-icon-color={stepDatum.headerData.iconColor}
7
+ header-background-color={stepDatum.headerData.backgroundColor}
8
+ header-text-color={stepDatum.headerData.textColor}
9
+ show-step-number={stepDatum.showStepNumber}
10
+ step-count={stepTotalCount}
11
+ step-index={stepIndex}
12
+ step-title={stepDatum.stepTitle}
13
+ >
14
+ <div slot="card-body" class="body-container">
15
+ <template if:true={isLoading}>
16
+ <div class="spinner-container">
17
+ <dx-spinner size="large" variant="brand"></dx-spinner>
18
+ </div>
19
+ </template>
20
+ <template if:false={isLoading}>
21
+ <span lwc:dom="manual" class="body-markup"></span>
22
+ <template if:true={stepDatum.formData}>
23
+ <dw-j2s-form
24
+ id={stepDatum.formData.formId}
25
+ countries={countryOptions}
26
+ form-metadata={stepDatum.formData}
27
+ incoming-user-info={userInfo}
28
+ onformvaliditychange={handleFormValidityChange}
29
+ recaptcha-token={recaptchaToken}
30
+ >
31
+ <div slot="form-captcha-slot">
32
+ <slot name="captcha-slot"></slot>
33
+ </div>
34
+ </dw-j2s-form>
35
+ </template>
36
+ </template>
37
+ </div>
38
+ <div slot="secondary-action-section">
39
+ <span lwc:dom="manual" class="secondary-action-markup"></span>
40
+ </div>
41
+ <div slot="primary-action-section">
42
+ <dx-button
43
+ if:true={showPrimaryAction}
44
+ class="primary-action"
45
+ disabled={isJ2sFormInvalid}
46
+ href={primaryActionLink}
47
+ icon-sprite={stepDatum.primaryAction.iconSprite}
48
+ icon-symbol={stepDatum.primaryAction.iconSymbol}
49
+ loading={isLoading}
50
+ onclick={handlePrimaryAction}
51
+ size="large"
52
+ target={primaryActionLinkTarget}
53
+ variant={primaryActionVariant}
54
+ >
55
+ {primaryActionText}
56
+ </dx-button>
57
+ </div>
58
+ </dx-card-step>
59
+ </template>
@@ -0,0 +1,152 @@
1
+ import { api, LightningElement } from "lwc";
2
+ import { DrmFormData, StepDatum } from "dw/j2sCardSequence";
3
+ import { track } from "dxUtils/analytics";
4
+ import J2sForm from "dw/j2sForm";
5
+
6
+ export default class J2sCardSequenceStep extends LightningElement {
7
+ @api countryOptions: any[] = [];
8
+ @api isLoading = false;
9
+ @api recaptchaToken = "";
10
+ @api selectedCountry = "";
11
+ @api stepDatum!: StepDatum;
12
+ @api stepIndex = 0;
13
+ @api stepTotalCount = 0;
14
+ @api userInfo: any = {};
15
+
16
+ @api
17
+ public notifyFormSubmitFailure(formFailureData: Partial<DrmFormData>) {
18
+ (
19
+ this.template.querySelector("dw-j2s-form") as unknown as J2sForm
20
+ )?.notifySubmitFailure(formFailureData);
21
+ }
22
+
23
+ private _isJ2sFormInvalid = false;
24
+
25
+ private get stepClassName() {
26
+ return this.stepIndex === 2 && this.selectedCountry === "IN"
27
+ ? "final-card-with-action"
28
+ : "";
29
+ }
30
+
31
+ private get isJ2sFormInvalid() {
32
+ return this.stepIndex === 1 && this._isJ2sFormInvalid;
33
+ }
34
+ private set isJ2sFormInvalid(value: boolean) {
35
+ this._isJ2sFormInvalid = value;
36
+ }
37
+
38
+ private get primaryActionLink() {
39
+ const { link } = this.stepDatum.primaryAction;
40
+ return typeof link === "string"
41
+ ? link
42
+ : link?.[this.selectedCountry] || link?.default;
43
+ }
44
+
45
+ private get primaryActionText() {
46
+ const { text } = this.stepDatum.primaryAction;
47
+ return typeof text === "string"
48
+ ? text
49
+ : text[this.selectedCountry] || text.default;
50
+ }
51
+
52
+ private get primaryActionVariant() {
53
+ if (this.stepIndex === 1 && this.isJ2sFormInvalid) {
54
+ return "custom"; // override for disabled button styling
55
+ }
56
+ return this.stepDatum.primaryAction.variant;
57
+ }
58
+
59
+ private get primaryActionLinkTarget() {
60
+ return this.stepDatum.primaryAction.linkTarget || "_blank";
61
+ }
62
+
63
+ private get showPrimaryAction() {
64
+ return this.stepIndex !== 2 || this.selectedCountry === "IN";
65
+ }
66
+
67
+ private get showSecondaryAction() {
68
+ return this.showPrimaryAction; // same requirement as above for now
69
+ }
70
+
71
+ renderedCallback() {
72
+ this.updateStaticInnerHtml();
73
+ }
74
+
75
+ handleFormValidityChange({ detail }: CustomEvent) {
76
+ this.isJ2sFormInvalid = !detail.isValid;
77
+ }
78
+
79
+ handlePrimaryAction(evt: Event) {
80
+ this.track(evt);
81
+
82
+ if (this.stepIndex === 0) {
83
+ this.dispatchEvent(new CustomEvent("getstarted"));
84
+ } else if (this.stepIndex === 1 && !this.isJ2sFormInvalid) {
85
+ const j2sFormEl = this.template.querySelector(
86
+ "dw-j2s-form"
87
+ ) as unknown as J2sForm;
88
+ const formData = j2sFormEl.formDataForDrm;
89
+
90
+ // For some countries, explicit approvals will be present; for others, it is implicitly assumed
91
+ if (typeof formData.Opt_In__c !== "boolean") {
92
+ formData.Opt_In__c = true;
93
+ }
94
+ if (typeof formData.Privacy_Statement__c !== "boolean") {
95
+ formData.Privacy_Statement__c = true;
96
+ }
97
+
98
+ this.dispatchEvent(
99
+ new CustomEvent("formsubmit", {
100
+ detail: formData
101
+ })
102
+ );
103
+ }
104
+ }
105
+
106
+ private updateStaticInnerHtml() {
107
+ const { bodyHtml, secondaryActionHtml } = this.stepDatum;
108
+ const bodyMarkupContainer =
109
+ this.template.querySelector("span.body-markup");
110
+ const secondaryActionMarkupContainer = this.template.querySelector(
111
+ "span.secondary-action-markup"
112
+ );
113
+
114
+ if (bodyMarkupContainer) {
115
+ let markup =
116
+ typeof bodyHtml === "string"
117
+ ? bodyHtml
118
+ : bodyHtml?.[this.selectedCountry] || bodyHtml?.default;
119
+
120
+ if (this.stepIndex === 2) {
121
+ // User's email is supposed to show on final step
122
+ markup = `${markup}${
123
+ !this.userInfo.Email
124
+ ? ""
125
+ : `<span class="final-email-address">${this.userInfo.Email}</span>`
126
+ }`;
127
+ }
128
+
129
+ bodyMarkupContainer.innerHTML = markup || "";
130
+ }
131
+
132
+ if (secondaryActionMarkupContainer) {
133
+ // new special exception on step 2 to only show secondary action for IN
134
+ secondaryActionMarkupContainer.innerHTML =
135
+ secondaryActionHtml && this.showSecondaryAction
136
+ ? secondaryActionHtml
137
+ : "";
138
+ }
139
+ }
140
+
141
+ private track(evt: Event) {
142
+ const target = evt.target as HTMLButtonElement;
143
+
144
+ track(target, "custEv_ctaButtonClick", {
145
+ click_text: target.textContent,
146
+ element_title: this.stepDatum.stepTitle,
147
+ click_url: this.stepDatum.primaryAction.link || "",
148
+ element_type: "button",
149
+ content_category: "cta"
150
+ });
151
+ }
152
+ }
@@ -60,7 +60,7 @@ export default class J2sForm extends LightningElementWithState<J2sFormState> {
60
60
  }
61
61
 
62
62
  @api
63
- get formDataForDrm() {
63
+ get formDataForDrm(): Partial<DrmFormData> {
64
64
  // We should be able to just get the formData from the form automatically using `new FormData(theForm)`,
65
65
  // but our custom form elements don't seem to implement what it is required for that currently. See:
66
66
  // https://web.dev/more-capable-form-controls/#defining-a-form-associated-custom-element
@@ -203,10 +203,8 @@ export default class J2sForm extends LightningElementWithState<J2sFormState> {
203
203
  handleFormFieldChange = (evt: CustomEvent) => {
204
204
  // Event target information must be read prior to debouncing; the target is gone after the debounce.
205
205
  const { target = {}, detail } = evt;
206
- const {
207
- name: targetName,
208
- required: isRequiredField
209
- } = target as HTMLInputElement;
206
+ const { name: targetName, required: isRequiredField } =
207
+ target as HTMLInputElement;
210
208
  const value =
211
209
  typeof detail === "string"
212
210
  ? detail
@@ -234,7 +232,7 @@ export default class J2sForm extends LightningElementWithState<J2sFormState> {
234
232
  };
235
233
 
236
234
  @api
237
- notifySubmitFailure(formSubmissionFailureState: DrmFormData) {
235
+ notifySubmitFailure(formSubmissionFailureState: Partial<DrmFormData>) {
238
236
  this.showSubmitFailureAlert = true;
239
237
  // After form submission failure, restore at most the following values to the form:
240
238
  const {
@@ -279,6 +277,14 @@ export default class J2sForm extends LightningElementWithState<J2sFormState> {
279
277
  showMarketingText: countryData.showMarketingText
280
278
  });
281
279
 
280
+ this.dispatchEvent(
281
+ new CustomEvent("countrychange", {
282
+ bubbles: true,
283
+ composed: true,
284
+ detail: countryCode
285
+ })
286
+ );
287
+
282
288
  // Because updating the country can update the required fields, we need to re-set form
283
289
  // validity _after_ render
284
290
  requestAnimationFrame(() =>
@@ -301,7 +307,7 @@ export default class J2sForm extends LightningElementWithState<J2sFormState> {
301
307
 
302
308
  private checkValidity() {
303
309
  return (
304
- // Boolean(this.recaptchaToken) &&
310
+ Boolean(this.recaptchaToken) &&
305
311
  this.isParticipatingCountry(this.state.MailingCountry) &&
306
312
  this.requiredFormFields.every(
307
313
  (requiredFormField) =>