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

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@salesforcedevs/dw-components",
3
- "version": "1.3.148-canary.24",
3
+ "version": "1.3.148-canary.26",
4
4
  "description": "Lightning web components for https://developer.salesforce.com",
5
5
  "license": "MIT",
6
6
  "engines": {
@@ -38,6 +38,21 @@ export type StepDatum = {
38
38
  stepTitle: string;
39
39
  };
40
40
 
41
+ // Field names expected by DRM; see: https://salesforce.quip.com/daInAFETbPGm
42
+ export type DrmFormData = {
43
+ Email: string;
44
+ FirstName: string;
45
+ LastName: string;
46
+ MailingCountry: string;
47
+ Company__c: string;
48
+ DRM_Role__c: string;
49
+ TBID__c: string;
50
+ Opt_In__c?: boolean;
51
+ Privacy_Statement__c?: boolean;
52
+ j2s_terms?: boolean;
53
+ Referral_Email__c?: string;
54
+ };
55
+
41
56
  export default class J2sCardSequence extends LightningElement {
42
57
  _didRenderStaticInnerHtml = false;
43
58
  _isDrmLoading = false;
@@ -79,7 +94,7 @@ export default class J2sCardSequence extends LightningElement {
79
94
 
80
95
  private countries = "[]";
81
96
  private currentSequenceStep = 0;
82
- private didFormSubmissionFail = false;
97
+ private formSubmissionFailureState = null;
83
98
  private recaptchaToken = "";
84
99
  private sessionStorageId = "j2s-card-sequence";
85
100
  private tbidUserInfo: any; // TODO typings?
@@ -118,23 +133,23 @@ export default class J2sCardSequence extends LightningElement {
118
133
 
119
134
  private get formIncomingUserInfo() {
120
135
  if (!this.tbidUserInfo) {
121
- return {};
136
+ return {} as DrmFormData;
122
137
  }
123
138
 
124
139
  return {
125
- firstName: decodeURIComponent(this.tbidUserInfo.given_name),
126
- lastName: decodeURIComponent(this.tbidUserInfo.family_name),
127
- email: decodeURIComponent(this.tbidUserInfo.email),
128
- jobRole: decodeURIComponent(
140
+ FirstName: decodeURIComponent(this.tbidUserInfo.given_name),
141
+ LastName: decodeURIComponent(this.tbidUserInfo.family_name),
142
+ Email: decodeURIComponent(this.tbidUserInfo.email),
143
+ DRM_Role__c: decodeURIComponent(
129
144
  this.tbidUserInfo.custom_attributes?.Role
130
145
  ),
131
- companyName: decodeURIComponent(
146
+ Company__c: decodeURIComponent(
132
147
  this.tbidUserInfo.custom_attributes?.CompanyName
133
148
  ),
134
- country: decodeURIComponent(
149
+ MailingCountry: decodeURIComponent(
135
150
  this.tbidUserInfo.custom_attributes?.Country
136
151
  )
137
- };
152
+ } as DrmFormData;
138
153
  }
139
154
 
140
155
  private get initialStepIndex() {
@@ -192,12 +207,12 @@ export default class J2sCardSequence extends LightningElement {
192
207
  this._didRenderStaticInnerHtml = true;
193
208
  }
194
209
 
195
- if (this.didFormSubmissionFail) {
210
+ if (this.formSubmissionFailureState) {
196
211
  const j2sFormEl = (this.template.querySelector(
197
212
  "dw-j2s-form"
198
213
  ) as unknown) as J2sForm | null;
199
- j2sFormEl?.notifySubmitFailure();
200
- this.didFormSubmissionFail = false;
214
+ j2sFormEl?.notifySubmitFailure(this.formSubmissionFailureState);
215
+ this.formSubmissionFailureState = null;
201
216
  }
202
217
  }
203
218
 
@@ -245,22 +260,23 @@ export default class J2sCardSequence extends LightningElement {
245
260
  evt.preventDefault(); // don't proceed automatically to next step
246
261
  this._isFormSubmitting = true;
247
262
 
248
- try {
249
- const j2sFormEl = (this.template.querySelector(
250
- "dw-j2s-form"
251
- ) as unknown) as J2sForm | null;
252
- const formData = j2sFormEl?.formDataForDrm;
253
- // For some countries, explicit approvals will be present; for others, it is implicitly assumed
254
- if (typeof formData.Opt_In__c !== "boolean") {
255
- formData.Opt_In__c = true;
256
- }
257
- if (typeof formData.Privacy_Statement__c !== "boolean") {
258
- formData.Privacy_Statement__c = true;
259
- }
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
+ }
260
274
 
275
+ try {
261
276
  const res = await fetch(this.formHandler, {
262
277
  method: "POST",
263
278
  headers: {
279
+ "Content-Type": "application/json",
264
280
  "Captcha-Response": this.recaptchaToken
265
281
  },
266
282
  body: JSON.stringify({
@@ -287,7 +303,7 @@ export default class J2sCardSequence extends LightningElement {
287
303
  );
288
304
  }
289
305
  } catch (ex) {
290
- this.didFormSubmissionFail = true;
306
+ this.formSubmissionFailureState = formData;
291
307
  console.error(ex);
292
308
  }
293
309
 
@@ -373,9 +389,9 @@ export default class J2sCardSequence extends LightningElement {
373
389
  if (stepIndex === 2) {
374
390
  // User's email is supposed to show on final step
375
391
  markup = `${bodyHtml}${
376
- !this.formIncomingUserInfo.email
392
+ !this.formIncomingUserInfo.Email
377
393
  ? ""
378
- : `<span class="final-email-address">${this.formIncomingUserInfo.email}</span>`
394
+ : `<span class="final-email-address">${this.formIncomingUserInfo.Email}</span>`
379
395
  }`;
380
396
  }
381
397
  bodyMarkupContainer.innerHTML = markup || "";
@@ -11,7 +11,7 @@
11
11
  required
12
12
  validity-on-blur
13
13
  onchange={handleFormFieldChange}
14
- value={state.firstName}
14
+ value={state.FirstName}
15
15
  ></dx-input>
16
16
  <dx-input
17
17
  class="last-name-field"
@@ -22,7 +22,7 @@
22
22
  required
23
23
  validity-on-blur
24
24
  onchange={handleFormFieldChange}
25
- value={state.lastName}
25
+ value={state.LastName}
26
26
  ></dx-input>
27
27
  </div>
28
28
  <div class="form-row">
@@ -34,7 +34,7 @@
34
34
  placeholder="Your company name"
35
35
  required
36
36
  validity-on-blur
37
- value={state.companyName}
37
+ value={state.Company__c}
38
38
  onchange={handleFormFieldChange}
39
39
  ></dx-input>
40
40
  <dx-select
@@ -45,7 +45,7 @@
45
45
  options={jobRoles}
46
46
  placeholder="Select Job Role"
47
47
  required
48
- value={state.jobRole}
48
+ value={state.DRM_Role__c}
49
49
  onchange={handleFormFieldChange}
50
50
  ></dx-select>
51
51
  </div>
@@ -60,7 +60,7 @@
60
60
  disabled
61
61
  readonly="true"
62
62
  required
63
- value={state.email}
63
+ value={state.Email}
64
64
  ></dx-input>
65
65
  <dx-select
66
66
  label="Country/Region"
@@ -69,7 +69,7 @@
69
69
  options={countries}
70
70
  placeholder="Select Country/Region"
71
71
  required
72
- value={state.country}
72
+ value={state.MailingCountry}
73
73
  onchange={handleFormFieldChange}
74
74
  ></dx-select>
75
75
  </div>
@@ -80,6 +80,7 @@
80
80
  label="If anyone has referred you, please share their Email ID below, with their consent."
81
81
  validity-on-blur="true"
82
82
  type="email"
83
+ value={state.Referral_Email__c}
83
84
  onchange={handleFormFieldChange}
84
85
  ></dx-input>
85
86
  </div>
@@ -2,6 +2,7 @@ import { toJson } from "dxUtils/normalizers";
2
2
  import { api } from "lwc";
3
3
  import debounce from "debounce";
4
4
  import { LightningElementWithState } from "dxBaseElements/lightningElementWithState";
5
+ import { DrmFormData } from "dw/j2sCardSequence";
5
6
 
6
7
  // Hard-coding for now because we can't get information about an endpoint for this
7
8
  const tbidValidRoles = [
@@ -21,8 +22,7 @@ const tbidValidRoles = [
21
22
  "Product Manager"
22
23
  ];
23
24
 
24
- export type J2sFormState = {
25
- country: string;
25
+ export type J2sFormState = DrmFormData & {
26
26
  legalText: string;
27
27
  marketingText: string;
28
28
  learnMore: string;
@@ -40,7 +40,7 @@ export default class J2sForm extends LightningElementWithState<J2sFormState> {
40
40
 
41
41
  @api formMetadata: any = {};
42
42
  @api id = "";
43
- @api incomingUserInfo: any = {};
43
+ @api incomingUserInfo = {} as DrmFormData;
44
44
  @api referralText = "";
45
45
 
46
46
  @api
@@ -85,22 +85,25 @@ export default class J2sForm extends LightningElementWithState<J2sFormState> {
85
85
  this._recaptchaToken = value;
86
86
  if (!this._isInitialRender) {
87
87
  // Treat recaptcha checkbox as a required form field even though not technically marked as such:
88
- this.handleFormFieldChange({ target: { required: true } } as any);
88
+ this.setState({
89
+ isFormValid: this.checkValidity()
90
+ });
89
91
  }
90
92
  }
91
93
 
92
94
  private participatingCountryCodes = ["US", "CA", "IN"];
93
95
  private countriesWithReferralInput = ["IN"];
94
- private countriesWithRequiredJobRole = ["CA"];
95
96
  private requiredFormFields: HTMLElement[] = [];
96
97
  private showSubmitFailureAlert = false;
97
98
 
98
99
  get isNotParticipatingCountry() {
99
- return !this.isParticipatingCountry(this.state.country);
100
+ return !this.isParticipatingCountry(this.state.MailingCountry);
100
101
  }
101
102
 
102
103
  get isCountryWithReferralInput() {
103
- return this.countriesWithReferralInput.includes(this.state.country);
104
+ return this.countriesWithReferralInput.includes(
105
+ this.state.MailingCountry
106
+ );
104
107
  }
105
108
 
106
109
  get notAvailableAlertInfo() {
@@ -124,7 +127,7 @@ export default class J2sForm extends LightningElementWithState<J2sFormState> {
124
127
  isFormValid: false,
125
128
  showMarketingText: true
126
129
  };
127
- const initialCountry = initialState.country;
130
+ const initialCountry = initialState.MailingCountry;
128
131
  const initialCountryData =
129
132
  initialCountry && this._countriesLookup[initialCountry];
130
133
  if (initialCountryData) {
@@ -147,8 +150,8 @@ export default class J2sForm extends LightningElementWithState<J2sFormState> {
147
150
  }
148
151
 
149
152
  if (
150
- this.state.country &&
151
- this.state.country !== this.prevState.country
153
+ this.state.MailingCountry &&
154
+ this.state.MailingCountry !== this.prevState.MailingCountry
152
155
  ) {
153
156
  // Re-render new country's terms
154
157
  this.updateInnerHtml(
@@ -198,53 +201,77 @@ export default class J2sForm extends LightningElementWithState<J2sFormState> {
198
201
  }
199
202
 
200
203
  handleFormFieldChange = (evt: CustomEvent) => {
201
- const callbacks: Function[] = [];
202
-
203
- // Event target information must be read prior to debouncing; otherwise, the target is gone after the debounce.
204
- if ((evt.target as HTMLInputElement)?.name === "MailingCountry") {
205
- const { value } = evt.detail;
206
- callbacks.push(() => this.handleCountryChange(value));
207
- } else if ((evt.target as HTMLInputElement)?.required) {
208
- callbacks.push(() => this.handleRequiredFieldUpdate());
209
- }
210
-
211
- callbacks.push(() => {
212
- // Remove submit failure message once any change is made to the form.
213
- if (this.showSubmitFailureAlert) {
214
- this.showSubmitFailureAlert = false;
204
+ // Event target information must be read prior to debouncing; the target is gone after the debounce.
205
+ const { target = {}, detail } = evt;
206
+ const {
207
+ name: targetName,
208
+ required: isRequiredField
209
+ } = target as HTMLInputElement;
210
+ const value =
211
+ typeof detail === "string"
212
+ ? detail
213
+ : typeof detail.checked === "boolean"
214
+ ? detail.checked
215
+ : detail.value;
216
+
217
+ // Perform the real work after a debounce, in order to prevent unnecessary work on rapid form value changes:
218
+ this.callbackWithDebounce(() => {
219
+ if (targetName === "MailingCountry") {
220
+ this.handleCountryChange(value);
221
+ } else {
222
+ const nextState: Partial<J2sFormState> = {};
223
+ if (targetName) {
224
+ nextState[targetName as keyof J2sFormState] = value;
225
+ }
226
+ if (isRequiredField) {
227
+ nextState.isFormValid = this.checkValidity();
228
+ }
229
+ this.setState(nextState);
215
230
  }
216
- });
217
231
 
218
- // Don't do unnecessary work too often if form fields are rapidly being changed
219
- this.debouncedFormFieldChangeHandler(callbacks);
232
+ this.unsetSubmitFailure();
233
+ });
220
234
  };
221
235
 
222
236
  @api
223
- notifySubmitFailure() {
237
+ notifySubmitFailure(formSubmissionFailureState: DrmFormData) {
224
238
  this.showSubmitFailureAlert = true;
239
+ // After form submission failure, restore at most the following values to the form:
240
+ const {
241
+ FirstName,
242
+ LastName,
243
+ Email,
244
+ MailingCountry,
245
+ Company__c,
246
+ DRM_Role__c,
247
+ Referral_Email__c
248
+ } = formSubmissionFailureState;
249
+ this.setState({
250
+ FirstName,
251
+ LastName,
252
+ Email,
253
+ MailingCountry,
254
+ Company__c,
255
+ DRM_Role__c,
256
+ Referral_Email__c
257
+ });
225
258
  }
226
259
 
227
- private debouncedFormFieldChangeHandler = debounce(
228
- (callbacks: Function[]) => {
229
- callbacks.forEach((callback) => callback());
230
- },
231
- 1000 / 15 /* 15fps seems reasonable */
232
- );
233
-
234
- private handleRequiredFieldUpdate() {
235
- const isFormNowValid = this.checkValidity();
236
- if (this.state.isFormValid !== isFormNowValid) {
237
- this.setState({
238
- isFormValid: isFormNowValid
239
- });
260
+ private unsetSubmitFailure() {
261
+ if (this.showSubmitFailureAlert) {
262
+ this.showSubmitFailureAlert = false;
240
263
  }
241
264
  }
242
265
 
266
+ private callbackWithDebounce = debounce((callback: Function) => {
267
+ callback();
268
+ }, 1000 / 15 /* 15fps seems reasonable */);
269
+
243
270
  private handleCountryChange(countryCode: string) {
244
271
  const countryData = this._countriesLookup[countryCode];
245
272
 
246
273
  this.setState({
247
- country: countryCode,
274
+ MailingCountry: countryCode,
248
275
  learnMore: countryData.learnMore,
249
276
  legalText: countryData.legalText,
250
277
  marketingText: countryData.marketingText,
@@ -253,7 +280,7 @@ export default class J2sForm extends LightningElementWithState<J2sFormState> {
253
280
  });
254
281
 
255
282
  // Because updating the country can update the required fields, we need to re-set form
256
- // validity after render
283
+ // validity _after_ render
257
284
  requestAnimationFrame(() =>
258
285
  this.setState({
259
286
  isFormValid: this.checkValidity()
@@ -275,7 +302,7 @@ export default class J2sForm extends LightningElementWithState<J2sFormState> {
275
302
  private checkValidity() {
276
303
  return (
277
304
  // Boolean(this.recaptchaToken) &&
278
- this.isParticipatingCountry(this.state.country) &&
305
+ this.isParticipatingCountry(this.state.MailingCountry) &&
279
306
  this.requiredFormFields.every(
280
307
  (requiredFormField) =>
281
308
  // @ts-ignore