@salesforcedevs/dw-components 1.3.150 → 1.3.151-canary.1
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 +3 -0
- package/package.json +2 -3
- package/src/modules/dw/j2sCardSequence/j2sCardSequence.css +14 -0
- package/src/modules/dw/j2sCardSequence/j2sCardSequence.html +37 -0
- package/src/modules/dw/j2sCardSequence/j2sCardSequence.ts +403 -0
- package/src/modules/dw/j2sCardSequence/mockProps.ts +61 -0
- 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.css +56 -0
- package/src/modules/dw/j2sForm/j2sForm.html +162 -0
- package/src/modules/dw/j2sForm/j2sForm.ts +319 -0
- package/src/modules/dw/j2sForm/mockProps.ts +3095 -0
- package/LICENSE +0 -12
|
@@ -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
|
+
}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
.hidden {
|
|
2
|
+
display: none;
|
|
3
|
+
}
|
|
4
|
+
|
|
5
|
+
.form-row {
|
|
6
|
+
display: flex;
|
|
7
|
+
justify-content: space-between;
|
|
8
|
+
padding-bottom: var(--dx-g-spacing-md);
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
.form-row > * {
|
|
12
|
+
--dx-c-input-width: 100%;
|
|
13
|
+
|
|
14
|
+
font-family: var(--dx-g-font-sans);
|
|
15
|
+
width: calc(50% - 20px);
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
.form-row > :only-child {
|
|
19
|
+
max-width: 100%;
|
|
20
|
+
width: 100%;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
.form-row .terms {
|
|
24
|
+
--dx-c-checkbox-text-line-height: var(--dx-g-text-lg);
|
|
25
|
+
--dx-c-checkbox-font-size: var(--dx-g-text-sm);
|
|
26
|
+
|
|
27
|
+
font-family: var(--dx-g-font-sans);
|
|
28
|
+
font-size: var(--dx-c-checkbox-font-size);
|
|
29
|
+
font-weight: var(--dx-g-font-normal);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
.form-row .legal-terms-learn-more:not(.hidden) {
|
|
33
|
+
display: block;
|
|
34
|
+
padding-top: var(--dx-g-spacing-md);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
.form-row .legal-terms.no-checkbox {
|
|
38
|
+
font-family: var(--dx-g-font-sans);
|
|
39
|
+
font-size: var(--dx-g-text-xs);
|
|
40
|
+
font-weight: var(--dx-g-font-normal);
|
|
41
|
+
margin-left: 28px;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
.form-terms-container {
|
|
45
|
+
padding-top: var(--dx-g-spacing-sm);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
.form-captcha-slot {
|
|
49
|
+
align-items: center;
|
|
50
|
+
display: flex;
|
|
51
|
+
justify-content: center;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
dx-input[disabled] {
|
|
55
|
+
--dx-c-input-background: revert;
|
|
56
|
+
}
|
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<!-- For the names of the form fields, see: https://salesforce.quip.com/daInAFETbPGm -->
|
|
3
|
+
<form class="j2s-form">
|
|
4
|
+
<div class="form-row">
|
|
5
|
+
<dx-input
|
|
6
|
+
class="first-name-field"
|
|
7
|
+
label="First Name"
|
|
8
|
+
missing-error-message="Enter your first name"
|
|
9
|
+
name="FirstName"
|
|
10
|
+
placeholder="Your first name"
|
|
11
|
+
required
|
|
12
|
+
validity-on-blur
|
|
13
|
+
onchange={handleFormFieldChange}
|
|
14
|
+
value={state.FirstName}
|
|
15
|
+
></dx-input>
|
|
16
|
+
<dx-input
|
|
17
|
+
class="last-name-field"
|
|
18
|
+
label="Last Name"
|
|
19
|
+
missing-error-message="Enter your last name"
|
|
20
|
+
name="LastName"
|
|
21
|
+
placeholder="Your last name"
|
|
22
|
+
required
|
|
23
|
+
validity-on-blur
|
|
24
|
+
onchange={handleFormFieldChange}
|
|
25
|
+
value={state.LastName}
|
|
26
|
+
></dx-input>
|
|
27
|
+
</div>
|
|
28
|
+
<div class="form-row">
|
|
29
|
+
<dx-input
|
|
30
|
+
class="company-name-field"
|
|
31
|
+
label="Company Name"
|
|
32
|
+
missing-error-message="Enter your company name"
|
|
33
|
+
name="Company__c"
|
|
34
|
+
placeholder="Your company name"
|
|
35
|
+
required
|
|
36
|
+
validity-on-blur
|
|
37
|
+
value={state.Company__c}
|
|
38
|
+
onchange={handleFormFieldChange}
|
|
39
|
+
></dx-input>
|
|
40
|
+
<dx-select
|
|
41
|
+
class="job-role-field"
|
|
42
|
+
label="Job Role"
|
|
43
|
+
message-when-value-missing="Select your job role"
|
|
44
|
+
name="DRM_Role__c"
|
|
45
|
+
options={jobRoles}
|
|
46
|
+
placeholder="Select Job Role"
|
|
47
|
+
required
|
|
48
|
+
value={state.DRM_Role__c}
|
|
49
|
+
onchange={handleFormFieldChange}
|
|
50
|
+
></dx-select>
|
|
51
|
+
</div>
|
|
52
|
+
<div class="form-row">
|
|
53
|
+
<dx-input
|
|
54
|
+
name="Email"
|
|
55
|
+
type="email"
|
|
56
|
+
placeholder="Your email address"
|
|
57
|
+
label="Email"
|
|
58
|
+
missing-error-message="Enter your email address"
|
|
59
|
+
validity-on-blur="true"
|
|
60
|
+
disabled
|
|
61
|
+
readonly="true"
|
|
62
|
+
required
|
|
63
|
+
value={state.Email}
|
|
64
|
+
></dx-input>
|
|
65
|
+
<dx-select
|
|
66
|
+
label="Country/Region"
|
|
67
|
+
message-when-value-missing="Select your country/region"
|
|
68
|
+
name="MailingCountry"
|
|
69
|
+
options={countries}
|
|
70
|
+
placeholder="Select Country/Region"
|
|
71
|
+
required
|
|
72
|
+
value={state.MailingCountry}
|
|
73
|
+
onchange={handleFormFieldChange}
|
|
74
|
+
></dx-select>
|
|
75
|
+
</div>
|
|
76
|
+
<div class="form-row" if:true={isCountryWithReferralInput}>
|
|
77
|
+
<dx-input
|
|
78
|
+
name="Referral_Email__c"
|
|
79
|
+
class="referral-email-field full-width"
|
|
80
|
+
label="If anyone has referred you, please share their Email ID below, with their consent."
|
|
81
|
+
validity-on-blur="true"
|
|
82
|
+
type="email"
|
|
83
|
+
value={state.Referral_Email__c}
|
|
84
|
+
onchange={handleFormFieldChange}
|
|
85
|
+
></dx-input>
|
|
86
|
+
</div>
|
|
87
|
+
<div class="form-row" if:true={isNotParticipatingCountry}>
|
|
88
|
+
<dx-alert
|
|
89
|
+
alert-info={notAvailableAlertInfo}
|
|
90
|
+
class="full-width"
|
|
91
|
+
type="danger"
|
|
92
|
+
variant="accented"
|
|
93
|
+
></dx-alert>
|
|
94
|
+
</div>
|
|
95
|
+
<div class="form-row" if:true={showSubmitFailureAlert}>
|
|
96
|
+
<dx-alert
|
|
97
|
+
alert-info={formSubmitFailureAlertInfo}
|
|
98
|
+
class="full-width"
|
|
99
|
+
type="danger"
|
|
100
|
+
variant="accented"
|
|
101
|
+
></dx-alert>
|
|
102
|
+
</div>
|
|
103
|
+
<div class="form-terms-container">
|
|
104
|
+
<div class="form-row" if:true={state.showMarketingText}>
|
|
105
|
+
<dx-checkbox
|
|
106
|
+
value="marketing-terms"
|
|
107
|
+
name="Opt_In__c"
|
|
108
|
+
required
|
|
109
|
+
class="terms"
|
|
110
|
+
onchange={handleFormFieldChange}
|
|
111
|
+
disabled={isNotParticipatingCountry}
|
|
112
|
+
>
|
|
113
|
+
<span lwc:dom="manual" class="marketing-terms"></span>
|
|
114
|
+
</dx-checkbox>
|
|
115
|
+
</div>
|
|
116
|
+
<div class="form-row">
|
|
117
|
+
<dx-checkbox
|
|
118
|
+
value="j2s-terms"
|
|
119
|
+
name="j2s_terms"
|
|
120
|
+
required
|
|
121
|
+
class="terms"
|
|
122
|
+
onchange={handleFormFieldChange}
|
|
123
|
+
disabled={isNotParticipatingCountry}
|
|
124
|
+
>
|
|
125
|
+
<span lwc:dom="manual" class="j2s-terms"></span>
|
|
126
|
+
</dx-checkbox>
|
|
127
|
+
</div>
|
|
128
|
+
<div class="form-row">
|
|
129
|
+
<dx-checkbox
|
|
130
|
+
if:true={state.showLegalCheckbox}
|
|
131
|
+
value="legal-terms"
|
|
132
|
+
name="Privacy_Statement__c"
|
|
133
|
+
required
|
|
134
|
+
class="terms"
|
|
135
|
+
onchange={handleFormFieldChange}
|
|
136
|
+
disabled={isNotParticipatingCountry}
|
|
137
|
+
>
|
|
138
|
+
<span lwc:dom="manual" class="legal-terms"></span>
|
|
139
|
+
<template if:true={state.learnMore}>
|
|
140
|
+
|
|
141
|
+
<dx-button
|
|
142
|
+
variant="inline-inherit"
|
|
143
|
+
onclick={handleLearnMore}
|
|
144
|
+
>
|
|
145
|
+
Learn more.
|
|
146
|
+
</dx-button>
|
|
147
|
+
<span
|
|
148
|
+
lwc:dom="manual"
|
|
149
|
+
class="legal-terms-learn-more hidden"
|
|
150
|
+
></span>
|
|
151
|
+
</template>
|
|
152
|
+
</dx-checkbox>
|
|
153
|
+
<span
|
|
154
|
+
if:false={state.showLegalCheckbox}
|
|
155
|
+
lwc:dom="manual"
|
|
156
|
+
class="legal-terms no-checkbox"
|
|
157
|
+
></span>
|
|
158
|
+
</div>
|
|
159
|
+
<slot class="form-captcha-slot" name="form-captcha-slot"></slot>
|
|
160
|
+
</div>
|
|
161
|
+
</form>
|
|
162
|
+
</template>
|
|
@@ -0,0 +1,319 @@
|
|
|
1
|
+
import { toJson } from "dxUtils/normalizers";
|
|
2
|
+
import { api } from "lwc";
|
|
3
|
+
import debounce from "debounce";
|
|
4
|
+
import { LightningElementWithState } from "dxBaseElements/lightningElementWithState";
|
|
5
|
+
import { DrmFormData } from "dw/j2sCardSequence";
|
|
6
|
+
|
|
7
|
+
// Hard-coding for now because we can't get information about an endpoint for this
|
|
8
|
+
const tbidValidRoles = [
|
|
9
|
+
"Developer",
|
|
10
|
+
"Administrator",
|
|
11
|
+
"Architect",
|
|
12
|
+
"Sales Representative / Manager",
|
|
13
|
+
"Marketer",
|
|
14
|
+
"Service Agent / Supervisor",
|
|
15
|
+
"Data Analyst",
|
|
16
|
+
"Consultant",
|
|
17
|
+
"Business Operations Manager",
|
|
18
|
+
"Designer",
|
|
19
|
+
"Educator",
|
|
20
|
+
"Student",
|
|
21
|
+
"Executive",
|
|
22
|
+
"Product Manager"
|
|
23
|
+
];
|
|
24
|
+
|
|
25
|
+
export type J2sFormState = DrmFormData & {
|
|
26
|
+
legalText: string;
|
|
27
|
+
marketingText: string;
|
|
28
|
+
learnMore: string;
|
|
29
|
+
showLegalCheckbox: boolean;
|
|
30
|
+
showMarketingText: boolean;
|
|
31
|
+
isFormValid: boolean;
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
export default class J2sForm extends LightningElementWithState<J2sFormState> {
|
|
35
|
+
private _countriesJson = "";
|
|
36
|
+
private _countriesLookup: any = {}; // TODO typings
|
|
37
|
+
private _didSetFormId = false;
|
|
38
|
+
private _isInitialRender = true;
|
|
39
|
+
private _recaptchaToken = "";
|
|
40
|
+
|
|
41
|
+
@api formMetadata: any = {};
|
|
42
|
+
@api id = "";
|
|
43
|
+
@api incomingUserInfo = {} as DrmFormData;
|
|
44
|
+
@api referralText = "";
|
|
45
|
+
|
|
46
|
+
@api
|
|
47
|
+
get countries() {
|
|
48
|
+
return this._countriesJson || "[]";
|
|
49
|
+
}
|
|
50
|
+
set countries(value: string) {
|
|
51
|
+
this._countriesJson = value;
|
|
52
|
+
|
|
53
|
+
// Store a lookup table of country data by value so that we don't have to loop all the time
|
|
54
|
+
const countries = toJson(value);
|
|
55
|
+
const countriesLookup: any = {};
|
|
56
|
+
countries.forEach((country: any) => {
|
|
57
|
+
countriesLookup[country.value] = country;
|
|
58
|
+
});
|
|
59
|
+
this._countriesLookup = countriesLookup;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
@api
|
|
63
|
+
get formDataForDrm(): Partial<DrmFormData> {
|
|
64
|
+
// We should be able to just get the formData from the form automatically using `new FormData(theForm)`,
|
|
65
|
+
// but our custom form elements don't seem to implement what it is required for that currently. See:
|
|
66
|
+
// https://web.dev/more-capable-form-controls/#defining-a-form-associated-custom-element
|
|
67
|
+
const formData: any = {};
|
|
68
|
+
this.template
|
|
69
|
+
.querySelectorAll("form [name]")
|
|
70
|
+
.forEach((namedElement) => {
|
|
71
|
+
const typedElement = namedElement as HTMLInputElement;
|
|
72
|
+
formData[typedElement.name] =
|
|
73
|
+
typeof typedElement.checked === "boolean"
|
|
74
|
+
? typedElement.checked
|
|
75
|
+
: typedElement.value;
|
|
76
|
+
});
|
|
77
|
+
return formData;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
@api
|
|
81
|
+
get recaptchaToken() {
|
|
82
|
+
return this._recaptchaToken;
|
|
83
|
+
}
|
|
84
|
+
set recaptchaToken(value: string) {
|
|
85
|
+
this._recaptchaToken = value;
|
|
86
|
+
if (!this._isInitialRender) {
|
|
87
|
+
// Treat recaptcha checkbox as a required form field even though not technically marked as such:
|
|
88
|
+
this.setState({
|
|
89
|
+
isFormValid: this.checkValidity()
|
|
90
|
+
});
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
private participatingCountryCodes = ["US", "CA", "IN"];
|
|
95
|
+
private countriesWithReferralInput = ["IN"];
|
|
96
|
+
private requiredFormFields: HTMLElement[] = [];
|
|
97
|
+
private showSubmitFailureAlert = false;
|
|
98
|
+
|
|
99
|
+
get isNotParticipatingCountry() {
|
|
100
|
+
return !this.isParticipatingCountry(this.state.MailingCountry);
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
get isCountryWithReferralInput() {
|
|
104
|
+
return this.countriesWithReferralInput.includes(
|
|
105
|
+
this.state.MailingCountry
|
|
106
|
+
);
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
get notAvailableAlertInfo() {
|
|
110
|
+
return this.formMetadata.notAvailableAlertInfo;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
get formSubmitFailureAlertInfo() {
|
|
114
|
+
return this.formMetadata.formSubmitFailureAlertInfo;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
get jobRoles() {
|
|
118
|
+
return tbidValidRoles.map((role) => ({
|
|
119
|
+
label: role,
|
|
120
|
+
value: role
|
|
121
|
+
}));
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
connectedCallback() {
|
|
125
|
+
const initialState: Partial<J2sFormState> = {
|
|
126
|
+
...this.incomingUserInfo,
|
|
127
|
+
isFormValid: false,
|
|
128
|
+
showMarketingText: true
|
|
129
|
+
};
|
|
130
|
+
const initialCountry = initialState.MailingCountry;
|
|
131
|
+
const initialCountryData =
|
|
132
|
+
initialCountry && this._countriesLookup[initialCountry];
|
|
133
|
+
if (initialCountryData) {
|
|
134
|
+
initialState.showLegalCheckbox =
|
|
135
|
+
initialCountryData.showLegalCheckbox;
|
|
136
|
+
initialState.showMarketingText =
|
|
137
|
+
initialCountryData.showMarketingText;
|
|
138
|
+
initialState.legalText = initialCountryData.legalText;
|
|
139
|
+
initialState.marketingText = initialCountryData.marketingText;
|
|
140
|
+
initialState.learnMore = initialCountryData.learnMore;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
this.state = initialState as J2sFormState;
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
renderedCallback(): void {
|
|
147
|
+
if (this._isInitialRender) {
|
|
148
|
+
this.updateInnerHtml("span.j2s-terms", this.formMetadata.j2sTerms);
|
|
149
|
+
this._isInitialRender = false;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
if (
|
|
153
|
+
this.state.MailingCountry &&
|
|
154
|
+
this.state.MailingCountry !== this.prevState.MailingCountry
|
|
155
|
+
) {
|
|
156
|
+
// Re-render new country's terms
|
|
157
|
+
this.updateInnerHtml(
|
|
158
|
+
"span.marketing-terms",
|
|
159
|
+
this.state.marketingText
|
|
160
|
+
);
|
|
161
|
+
this.updateInnerHtml("span.legal-terms", this.state.legalText);
|
|
162
|
+
if (this.state.learnMore) {
|
|
163
|
+
this.updateInnerHtml(
|
|
164
|
+
"span.legal-terms-learn-more",
|
|
165
|
+
this.state.learnMore
|
|
166
|
+
);
|
|
167
|
+
} else {
|
|
168
|
+
this.updateInnerHtml("span.legal-terms-learn-more", "");
|
|
169
|
+
this.template
|
|
170
|
+
.querySelector(".legal-terms-learn-more")
|
|
171
|
+
?.classList.add("hidden");
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
if (this.state.isFormValid !== this.prevState.isFormValid) {
|
|
176
|
+
this.dispatchEvent(
|
|
177
|
+
new CustomEvent("formvaliditychange", {
|
|
178
|
+
detail: {
|
|
179
|
+
isValid: this.state.isFormValid
|
|
180
|
+
},
|
|
181
|
+
bubbles: true,
|
|
182
|
+
composed: true
|
|
183
|
+
})
|
|
184
|
+
);
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
this.requiredFormFields = Array.from(
|
|
188
|
+
this.template.querySelectorAll("[required]")
|
|
189
|
+
);
|
|
190
|
+
|
|
191
|
+
if (this.id && !this._didSetFormId) {
|
|
192
|
+
this._didSetFormId = true;
|
|
193
|
+
this.template.querySelector("form")?.setAttribute("id", this.id);
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
handleLearnMore() {
|
|
198
|
+
this.template
|
|
199
|
+
.querySelector(".legal-terms-learn-more")
|
|
200
|
+
?.classList.toggle("hidden");
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
handleFormFieldChange = (evt: CustomEvent) => {
|
|
204
|
+
// Event target information must be read prior to debouncing; the target is gone after the debounce.
|
|
205
|
+
const { target = {}, detail } = evt;
|
|
206
|
+
const { name: targetName, required: isRequiredField } =
|
|
207
|
+
target as HTMLInputElement;
|
|
208
|
+
const value =
|
|
209
|
+
typeof detail === "string"
|
|
210
|
+
? detail
|
|
211
|
+
: typeof detail.checked === "boolean"
|
|
212
|
+
? detail.checked
|
|
213
|
+
: detail.value;
|
|
214
|
+
|
|
215
|
+
// Perform the real work after a debounce, in order to prevent unnecessary work on rapid form value changes:
|
|
216
|
+
this.callbackWithDebounce(() => {
|
|
217
|
+
if (targetName === "MailingCountry") {
|
|
218
|
+
this.handleCountryChange(value);
|
|
219
|
+
} else {
|
|
220
|
+
const nextState: Partial<J2sFormState> = {};
|
|
221
|
+
if (targetName) {
|
|
222
|
+
nextState[targetName as keyof J2sFormState] = value;
|
|
223
|
+
}
|
|
224
|
+
if (isRequiredField) {
|
|
225
|
+
nextState.isFormValid = this.checkValidity();
|
|
226
|
+
}
|
|
227
|
+
this.setState(nextState);
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
this.unsetSubmitFailure();
|
|
231
|
+
});
|
|
232
|
+
};
|
|
233
|
+
|
|
234
|
+
@api
|
|
235
|
+
notifySubmitFailure(formSubmissionFailureState: Partial<DrmFormData>) {
|
|
236
|
+
this.showSubmitFailureAlert = true;
|
|
237
|
+
// After form submission failure, restore at most the following values to the form:
|
|
238
|
+
const {
|
|
239
|
+
FirstName,
|
|
240
|
+
LastName,
|
|
241
|
+
Email,
|
|
242
|
+
MailingCountry,
|
|
243
|
+
Company__c,
|
|
244
|
+
DRM_Role__c,
|
|
245
|
+
Referral_Email__c
|
|
246
|
+
} = formSubmissionFailureState;
|
|
247
|
+
this.setState({
|
|
248
|
+
FirstName,
|
|
249
|
+
LastName,
|
|
250
|
+
Email,
|
|
251
|
+
MailingCountry,
|
|
252
|
+
Company__c,
|
|
253
|
+
DRM_Role__c,
|
|
254
|
+
Referral_Email__c
|
|
255
|
+
});
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
private unsetSubmitFailure() {
|
|
259
|
+
if (this.showSubmitFailureAlert) {
|
|
260
|
+
this.showSubmitFailureAlert = false;
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
private callbackWithDebounce = debounce((callback: Function) => {
|
|
265
|
+
callback();
|
|
266
|
+
}, 1000 / 15 /* 15fps seems reasonable */);
|
|
267
|
+
|
|
268
|
+
private handleCountryChange(countryCode: string) {
|
|
269
|
+
const countryData = this._countriesLookup[countryCode];
|
|
270
|
+
|
|
271
|
+
this.setState({
|
|
272
|
+
MailingCountry: countryCode,
|
|
273
|
+
learnMore: countryData.learnMore,
|
|
274
|
+
legalText: countryData.legalText,
|
|
275
|
+
marketingText: countryData.marketingText,
|
|
276
|
+
showLegalCheckbox: countryData.showLegalCheckbox,
|
|
277
|
+
showMarketingText: countryData.showMarketingText
|
|
278
|
+
});
|
|
279
|
+
|
|
280
|
+
this.dispatchEvent(
|
|
281
|
+
new CustomEvent("countrychange", {
|
|
282
|
+
bubbles: true,
|
|
283
|
+
composed: true,
|
|
284
|
+
detail: countryCode
|
|
285
|
+
})
|
|
286
|
+
);
|
|
287
|
+
|
|
288
|
+
// Because updating the country can update the required fields, we need to re-set form
|
|
289
|
+
// validity _after_ render
|
|
290
|
+
requestAnimationFrame(() =>
|
|
291
|
+
this.setState({
|
|
292
|
+
isFormValid: this.checkValidity()
|
|
293
|
+
})
|
|
294
|
+
);
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
private updateInnerHtml(selector: string, html: string): void {
|
|
298
|
+
const element = this.template.querySelector(selector);
|
|
299
|
+
if (element) {
|
|
300
|
+
element.innerHTML = html;
|
|
301
|
+
}
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
private isParticipatingCountry(country: string) {
|
|
305
|
+
return this.participatingCountryCodes.includes(country);
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
private checkValidity() {
|
|
309
|
+
return (
|
|
310
|
+
Boolean(this.recaptchaToken) &&
|
|
311
|
+
this.isParticipatingCountry(this.state.MailingCountry) &&
|
|
312
|
+
this.requiredFormFields.every(
|
|
313
|
+
(requiredFormField) =>
|
|
314
|
+
// @ts-ignore
|
|
315
|
+
requiredFormField.checkValidity?.() === true
|
|
316
|
+
)
|
|
317
|
+
);
|
|
318
|
+
}
|
|
319
|
+
}
|