@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 +1 -0
- package/package.json +1 -1
- package/src/modules/dw/j2sCardSequence/j2sCardSequence.css +0 -45
- package/src/modules/dw/j2sCardSequence/j2sCardSequence.html +12 -60
- package/src/modules/dw/j2sCardSequence/j2sCardSequence.ts +52 -126
- package/src/modules/dw/j2sCardSequenceStep/j2sCardSequenceStep.css +47 -0
- package/src/modules/dw/j2sCardSequenceStep/j2sCardSequenceStep.html +59 -0
- package/src/modules/dw/j2sCardSequenceStep/j2sCardSequenceStep.ts +152 -0
- package/src/modules/dw/j2sForm/j2sForm.ts +13 -7
package/lwc.config.json
CHANGED
package/package.json
CHANGED
|
@@ -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
|
-
<
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
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-
|
|
22
|
-
|
|
23
|
-
|
|
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
|
|
5
|
+
import J2sCardSequenceStep from "dw/j2sCardSequenceStep";
|
|
7
6
|
|
|
8
7
|
export type StepDatum = {
|
|
9
|
-
bodyHtml?:
|
|
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?:
|
|
35
|
+
link?:
|
|
36
|
+
| string
|
|
37
|
+
| {
|
|
38
|
+
default: string;
|
|
39
|
+
[countryCode: string]: string;
|
|
40
|
+
};
|
|
32
41
|
linkTarget?: string;
|
|
33
|
-
text:
|
|
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
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
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 (
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
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
|
-
|
|
220
|
-
this.
|
|
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(
|
|
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(
|
|
256
|
-
if (!this.formHandler ||
|
|
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
|
-
(
|
|
369
|
-
|
|
370
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
310
|
+
Boolean(this.recaptchaToken) &&
|
|
305
311
|
this.isParticipatingCountry(this.state.MailingCountry) &&
|
|
306
312
|
this.requiredFormFields.every(
|
|
307
313
|
(requiredFormField) =>
|