@salesforcedevs/dw-components 1.3.148-canary.9 → 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 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.9",
3
+ "version": "1.3.151-canary.1",
4
4
  "description": "Lightning web components for https://developer.salesforce.com",
5
5
  "license": "MIT",
6
6
  "engines": {
@@ -14,7 +14,7 @@
14
14
  "lodash.clonedeep": "^4.5.0",
15
15
  "lodash.orderby": "^4.6.0",
16
16
  "lodash.uniqby": "^4.7.0",
17
- "query-string": "^7.1.1"
17
+ "query-string": "^7.1.3"
18
18
  },
19
19
  "devDependencies": {
20
20
  "@types/classnames": "^2.2.10",
@@ -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,40 +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
- padding-bottom: var(--dx-g-spacing-md);
44
- }
45
-
46
- .referral-email-field {
47
- --dx-c-input-width: 100%;
48
- }
49
-
50
- .spinner-container {
51
- min-height: 200px;
52
- position: relative;
53
- }
@@ -2,73 +2,35 @@
2
2
  <dx-step-sequence
3
3
  animate-transitions={animateTransitions}
4
4
  communicate-step-changes="true"
5
+ force-initially-visible={forceInitiallyVisible}
5
6
  initial-step-index={initialStepIndex}
6
7
  onstepsequencechange={handleStepSequenceChange}
8
+ optimize-position-after-animation="true"
7
9
  session-storage-id={sessionStorageId}
8
10
  use-history={useHistory}
9
11
  >
10
12
  <template for:each={stepsData} for:item="stepDatum" for:index="index">
11
13
  <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}
14
+ <dw-j2s-card-sequence-step
15
+ country-options={countries}
16
+ is-loading={isLoading}
17
+ oncountrychange={handleCountryChange}
18
+ ongetstarted={handleGetStarted}
19
+ onformsubmit={handleFormSubmit}
20
+ recaptcha-token={recaptchaToken}
21
+ selected-country={selectedCountry}
22
+ step-datum={stepDatum}
20
23
  step-index={index}
21
- step-title={stepDatum.stepTitle}
24
+ step-total-count={stepsData.length}
25
+ user-info={formIncomingUserInfo}
22
26
  >
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.formMetadata}
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>
27
+ <div
28
+ if:true={stepDatum.formData}
29
+ slot="card-step-captcha-slot"
30
+ >
31
+ <slot name="captcha-slot"></slot>
49
32
  </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
- variant={primaryActionVariant}
67
- >
68
- {stepDatum.primaryAction.text}
69
- </dx-button>
70
- </div>
71
- </dx-card-step>
33
+ </dw-j2s-card-sequence-step>
72
34
  </dx-step-sequence-step>
73
35
  </template>
74
36
  </dx-step-sequence>
@@ -1,11 +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";
5
+ import J2sCardSequenceStep from "dw/j2sCardSequenceStep";
6
6
 
7
7
  export type StepDatum = {
8
- bodyHtml?: string;
8
+ bodyHtml?:
9
+ | string
10
+ | {
11
+ default: string;
12
+ [countryCode: string]: string;
13
+ };
9
14
  formData?: {
10
15
  countriesWithReferralInput?: string[];
11
16
  countriesWithRequiredJobRole?: string[];
@@ -27,8 +32,19 @@ export type StepDatum = {
27
32
  primaryAction: {
28
33
  iconSprite?: string;
29
34
  iconSymbol?: string;
30
- link?: string;
31
- text: string;
35
+ link?:
36
+ | string
37
+ | {
38
+ default: string;
39
+ [countryCode: string]: string;
40
+ };
41
+ linkTarget?: string;
42
+ text:
43
+ | string
44
+ | {
45
+ default: string;
46
+ [countryCode: string]: string;
47
+ };
32
48
  variant?: string;
33
49
  };
34
50
  secondaryActionHtml?: string;
@@ -36,18 +52,26 @@ export type StepDatum = {
36
52
  stepTitle: string;
37
53
  };
38
54
 
39
- function isNoAnimationCookieSet() {
40
- return document.cookie
41
- .split(";")
42
- .some((ck) => ck.trim() === "no_j2s_animation=true");
43
- }
55
+ // Field names expected by DRM; see: https://salesforce.quip.com/daInAFETbPGm
56
+ export type DrmFormData = {
57
+ Email: string;
58
+ FirstName: string;
59
+ LastName: string;
60
+ MailingCountry: string;
61
+ Company__c: string;
62
+ DRM_Role__c: string;
63
+ TBID__c: string;
64
+ Opt_In__c?: boolean;
65
+ Privacy_Statement__c?: boolean;
66
+ j2s_terms?: boolean;
67
+ Referral_Email__c?: string;
68
+ };
44
69
 
45
70
  export default class J2sCardSequence extends LightningElement {
46
- _didRenderStaticInnerHtml = false;
47
71
  _isDrmLoading = false;
48
72
  _isFormSubmitting = false;
49
- _isJ2sFormInvalid = false;
50
73
  _isTbidLoading = false;
74
+ _recaptchaResetTimeoutId: number | null = null;
51
75
  _stepsData: StepDatum[] = [];
52
76
  @api animateTransitions = false;
53
77
  @api drmDomain: string = "https://drm.my.salesforce-sites.com";
@@ -62,35 +86,30 @@ export default class J2sCardSequence extends LightningElement {
62
86
  }
63
87
  set stepsData(value) {
64
88
  // normalize incoming value with uuid keys and non-required props (for cleaner HTML template), etc.
65
- this._stepsData = getListWithUuids<StepDatum>(toJson(value)).map(
66
- (stepDatum) => {
67
- const normalizedStepDatum = {
68
- ...stepDatum,
69
- headerData: stepDatum.headerData || {},
70
- primaryAction: {
71
- ...stepDatum.primaryAction,
72
- variant: stepDatum.primaryAction.variant || "primary",
73
- iconSprite:
74
- stepDatum.primaryAction.iconSprite || "general",
75
- iconSymbol:
76
- stepDatum.primaryAction.iconSymbol || "arrow-right"
77
- }
78
- };
79
-
80
- if (normalizedStepDatum.formData) {
81
- (normalizedStepDatum as any).formMetadata = JSON.stringify(
82
- normalizedStepDatum.formData
83
- );
89
+ const valueWithUuids = getListWithUuids<StepDatum>(toJson(value));
90
+ this._stepsData = valueWithUuids.map((stepDatum) => {
91
+ const normalizedStepDatum = {
92
+ ...stepDatum,
93
+ headerData: stepDatum.headerData || {},
94
+ primaryAction: {
95
+ ...stepDatum.primaryAction,
96
+ variant: stepDatum.primaryAction.variant || "primary",
97
+ iconSprite: stepDatum.primaryAction.iconSprite || "general",
98
+ iconSymbol:
99
+ stepDatum.primaryAction.iconSymbol || "arrow-right"
84
100
  }
101
+ };
85
102
 
86
- return normalizedStepDatum;
87
- }
88
- );
103
+ return normalizedStepDatum;
104
+ });
89
105
  }
90
106
 
91
- private countries = "[]";
107
+ private countries: any[] = [];
92
108
  private currentSequenceStep = 0;
109
+ private forceInitiallyVisible = false;
110
+ private formSubmissionFailureState: Partial<DrmFormData> | null = null;
93
111
  private recaptchaToken = "";
112
+ private selectedCountry = "";
94
113
  private sessionStorageId = "j2s-card-sequence";
95
114
  private tbidUserInfo: any; // TODO typings?
96
115
 
@@ -104,34 +123,25 @@ export default class J2sCardSequence extends LightningElement {
104
123
  return Boolean(this.tbidUserInfo);
105
124
  }
106
125
 
107
- private get isJ2sFormInvalid() {
108
- return this.currentSequenceStep === 1 ? this._isJ2sFormInvalid : false;
109
- }
110
- private set isJ2sFormInvalid(isFormInvalid: boolean) {
111
- this._isJ2sFormInvalid = isFormInvalid;
112
- }
113
-
114
- private get primaryActionVariant() {
115
- if (this.currentSequenceStep === 1 && this.isJ2sFormInvalid) {
116
- return "custom"; // override for disabled button styling
117
- }
118
- return this.stepsData[this.currentSequenceStep || 0].primaryAction
119
- .variant;
120
- }
121
-
122
126
  private get formIncomingUserInfo() {
123
127
  if (!this.tbidUserInfo) {
124
- return "{}";
128
+ return {} as DrmFormData;
125
129
  }
126
130
 
127
- return JSON.stringify({
128
- firstName: this.tbidUserInfo.given_name,
129
- lastName: this.tbidUserInfo.family_name,
130
- email: this.tbidUserInfo.email,
131
- jobRole: this.tbidUserInfo.custom_attributes?.Role,
132
- companyName: this.tbidUserInfo.custom_attributes?.CompanyName,
133
- country: this.tbidUserInfo.custom_attributes?.Country
134
- });
131
+ return {
132
+ FirstName: decodeURIComponent(this.tbidUserInfo.given_name),
133
+ LastName: decodeURIComponent(this.tbidUserInfo.family_name),
134
+ Email: decodeURIComponent(this.tbidUserInfo.email),
135
+ DRM_Role__c: decodeURIComponent(
136
+ this.tbidUserInfo.custom_attributes?.Role
137
+ ),
138
+ Company__c: decodeURIComponent(
139
+ this.tbidUserInfo.custom_attributes?.CompanyName
140
+ ),
141
+ MailingCountry: decodeURIComponent(
142
+ this.tbidUserInfo.custom_attributes?.Country
143
+ )
144
+ } as DrmFormData;
135
145
  }
136
146
 
137
147
  private get initialStepIndex() {
@@ -161,11 +171,13 @@ export default class J2sCardSequence extends LightningElement {
161
171
  @api
162
172
  recaptchaCallback(responseToken: string) {
163
173
  this.recaptchaToken = responseToken;
174
+ clearTimeout(this._recaptchaResetTimeoutId as number);
164
175
  }
165
176
 
166
177
  @api
167
178
  recaptchaExpiredCallback() {
168
179
  this.recaptchaToken = "";
180
+ clearTimeout(this._recaptchaResetTimeoutId as number);
169
181
  }
170
182
 
171
183
  connectedCallback() {
@@ -174,74 +186,101 @@ export default class J2sCardSequence extends LightningElement {
174
186
  // This has to be defined here since it depends on a variable that depends on sessionStorage.
175
187
  this.currentSequenceStep = this.initialStepIndex;
176
188
  this.resetCustomButtonColors();
177
- if (isNoAnimationCookieSet()) {
178
- /* eslint-disable-next-line @lwc/lwc/no-api-reassignments */
179
- this.animateTransitions = false;
189
+
190
+ try {
191
+ const isLoggingIn = sessionStorage.getItem(
192
+ `${this.sessionStorageId}__isLoginRedirect`
193
+ );
194
+ if (isLoggingIn) {
195
+ this.forceInitiallyVisible = true;
196
+ sessionStorage.removeItem(
197
+ `${this.sessionStorageId}__isLoginRedirect`
198
+ );
199
+ }
200
+ } catch (ex) {
201
+ // noop
180
202
  }
181
203
  }
182
204
 
183
205
  renderedCallback() {
184
- if (this.isLoading) {
185
- return;
206
+ if (!this.isLoading) {
207
+ (
208
+ this.template.querySelector(
209
+ "dx-step-sequence"
210
+ ) as unknown as StepSequence
211
+ )?.remeasureSteps();
186
212
  }
187
213
 
188
- if (!this._didRenderStaticInnerHtml) {
189
- this.updateStaticInnerHtml();
190
- this._didRenderStaticInnerHtml = true;
214
+ if (
215
+ this.formSubmissionFailureState &&
216
+ this.stepsData[this.currentSequenceStep].formData
217
+ ) {
218
+ const j2sCardStep = this.template.querySelectorAll(
219
+ "dw-j2s-card-sequence-step"
220
+ ) as unknown as J2sCardSequenceStep[];
221
+ j2sCardStep[this.currentSequenceStep]?.notifyFormSubmitFailure(
222
+ this.formSubmissionFailureState
223
+ );
224
+ this.formSubmissionFailureState = null;
191
225
  }
192
226
  }
193
227
 
194
- handleFormValidityChange({ detail }: CustomEvent) {
195
- this.isJ2sFormInvalid = !detail.isValid;
228
+ handleCountryChange({ detail }: CustomEvent) {
229
+ this.selectedCountry = detail;
196
230
  }
197
231
 
198
232
  handleStepSequenceChange({ detail }: CustomEvent) {
199
233
  this.currentSequenceStep = detail.stepIndex;
200
234
  this.resetCustomButtonColors();
235
+
236
+ if (
237
+ this.currentSequenceStep !== 1 &&
238
+ this.recaptchaToken &&
239
+ this._recaptchaResetTimeoutId === null
240
+ ) {
241
+ // If the recaptcha element expires on its own while you are not on the 2nd (form) step, it messes with the
242
+ // page's layout (basically breaks it). So, we need to reset it _before_ expiration if you leave that step.
243
+ // We do it with a timeout so that the token is not immediately wiped if the user goes back and forth a bit.
244
+ this._recaptchaResetTimeoutId = window.setTimeout(
245
+ () => this.resetRecaptcha(),
246
+ 1000 * 30 /* 30 seconds */
247
+ );
248
+ }
201
249
  }
202
250
 
203
- handleGetStarted(evt: Event) {
251
+ handleGetStarted() {
204
252
  // If the user is not yet logged in, we need to prevent moving immediately to the next
205
253
  // step, but set storage up so that they are on the second step when they return to the
206
254
  // site in a logged-in state; then, we need to get them to log in.
207
255
  if (!this.isLoggedIn) {
208
- evt.preventDefault();
209
256
  this.initialStepIndex = 1;
210
257
  this._isTbidLoading = true;
211
- // @ts-ignore: call out to the tbid-controller on DSC
212
- window.__startTbidLogin();
258
+ sessionStorage.setItem(
259
+ `${this.sessionStorageId}__isLoginRedirect`,
260
+ "1" /* value doesn't matter */
261
+ );
262
+ (window as any).__startTbidLogin?.(); // call out to DSC tbid controller
263
+ } else {
264
+ this.jumpToStepIndex(1);
213
265
  }
214
266
  }
215
267
 
216
- async handleFormSubmit(evt: Event) {
217
- if (!this.formHandler || this.isJ2sFormInvalid || !this.isLoggedIn) {
268
+ async handleFormSubmit({ detail: formData }: CustomEvent<DrmFormData>) {
269
+ if (!this.formHandler || !this.isLoggedIn) {
218
270
  return;
219
271
  }
220
272
 
221
- evt.preventDefault(); // don't proceed automatically to next step
222
273
  this._isFormSubmitting = true;
223
274
 
224
275
  try {
225
- const formData = (this.template.querySelector("dw-j2s-form") as any)
226
- ?.formDataForDrm;
227
- // For some countries, explicit approvals will be present; for others, it is implicitly assumed
228
- if (typeof formData.Opt_In__c !== "boolean") {
229
- formData.Opt_In__c = true;
230
- }
231
- if (typeof formData.Privacy_Statement__c !== "boolean") {
232
- formData.Privacy_Statement__c = true;
233
- }
234
-
235
- console.log("submitting", JSON.stringify(formData, null, 2));
236
276
  const res = await fetch(this.formHandler, {
237
277
  method: "POST",
238
278
  headers: {
239
- "Captcha-Response": this.recaptchaToken,
240
- "Content-Type": "application/json"
279
+ "Content-Type": "application/json",
280
+ "Captcha-Response": this.recaptchaToken
241
281
  },
242
282
  body: JSON.stringify({
243
283
  ...formData,
244
- "Content-Type": "application/json",
245
284
  handlerName: "J2S Registration Page",
246
285
  TBID__c: this.tbidUserInfo.user_id
247
286
  })
@@ -249,46 +288,29 @@ export default class J2sCardSequence extends LightningElement {
249
288
 
250
289
  if (res.ok) {
251
290
  const resData = await res.json();
252
- if (resData.status === "success") {
253
- this.jumpToStepIndex(2);
291
+ const resOutput = resData.handlePostRequestOutput || resData;
292
+ if (resOutput?.status === "success") {
293
+ this.jumpToStepIndex(2, false);
294
+ this.initialStepIndex = 0; // don't save final step in storage; rather, reset the starting step
295
+ this.resetRecaptcha();
254
296
  } else {
255
297
  throw new Error(
256
- `Form submission failed. (status: ${resData.status}, message: ${resData.errorMessage})`
298
+ `Form submission failed. (status: ${resOutput.status}, message: ${resOutput.errorMessage})`
257
299
  );
258
300
  }
301
+ } else {
302
+ throw new Error(
303
+ `Form submission failed. Non-ok response received from DRM.`
304
+ );
259
305
  }
260
306
  } catch (ex) {
261
- console.error(ex); // TODO
307
+ this.formSubmissionFailureState = formData;
308
+ console.error(ex);
262
309
  }
263
310
 
264
311
  this._isFormSubmitting = false;
265
312
  }
266
313
 
267
- primaryActionHandler(evt: Event) {
268
- const target = evt.target as HTMLButtonElement;
269
-
270
- if (!target || target.disabled) {
271
- evt.preventDefault();
272
- return;
273
- }
274
-
275
- track(target, "custEv_ctaButtonClick", {
276
- click_text: target.textContent,
277
- element_title: this.stepsData[this.currentSequenceStep].stepTitle,
278
- click_url:
279
- this.stepsData[this.currentSequenceStep].primaryAction.link ||
280
- "",
281
- element_type: "button",
282
- content_category: "cta"
283
- });
284
-
285
- if (!this.currentSequenceStep) {
286
- this.handleGetStarted(evt);
287
- } else if (this.currentSequenceStep === 1) {
288
- this.handleFormSubmit(evt);
289
- }
290
- }
291
-
292
314
  private resetCustomButtonColors() {
293
315
  let bgColor;
294
316
  let textColor;
@@ -315,42 +337,28 @@ export default class J2sCardSequence extends LightningElement {
315
337
  );
316
338
  }
317
339
 
318
- private jumpToStepIndex(stepIndex: number) {
319
- this.initialStepIndex = stepIndex; // update sessionStorage value
320
- ((this.template.querySelector(
321
- "dx-step-sequence"
322
- ) as unknown) as StepSequence)?.jumpToStep(stepIndex);
340
+ private resetRecaptcha() {
341
+ clearTimeout(this._recaptchaResetTimeoutId as number);
342
+ this._recaptchaResetTimeoutId = null;
343
+ this.recaptchaToken = "";
344
+ (window as any).grecaptcha.reset();
323
345
  }
324
346
 
325
- // HTML is received via config from DSC and should be static after initial render.
326
- private updateStaticInnerHtml() {
327
- const bodyMarkupContainers = this.template.querySelectorAll(
328
- "span.body-markup"
329
- );
330
- const secondaryActionMarkupContainers = this.template.querySelectorAll(
331
- "span.secondary-action-markup"
332
- );
333
-
334
- this.stepsData.forEach((step, stepIndex) => {
335
- const { bodyHtml, secondaryActionHtml } = step;
336
- const bodyMarkupContainer = bodyMarkupContainers[stepIndex];
337
- const secondaryActionMarkupContainer =
338
- secondaryActionMarkupContainers[stepIndex];
339
-
340
- if (bodyMarkupContainer) {
341
- bodyMarkupContainer.innerHTML = bodyHtml || "";
342
- }
343
- if (secondaryActionMarkupContainer) {
344
- secondaryActionMarkupContainer.innerHTML =
345
- secondaryActionHtml || "";
346
- }
347
- });
347
+ private jumpToStepIndex(stepIndex: number, andStoreIndex = true) {
348
+ if (andStoreIndex) {
349
+ this.initialStepIndex = stepIndex; // update sessionStorage value
350
+ }
351
+ (
352
+ this.template.querySelector(
353
+ "dx-step-sequence"
354
+ ) as unknown as StepSequence
355
+ )?.jumpToStep(stepIndex);
348
356
  }
349
357
 
350
358
  private async getCountryList() {
351
359
  this._isDrmLoading = true;
352
360
 
353
- const errorMsg = "Error while getting county list";
361
+ const errorMsg = "Error while getting country list";
354
362
  try {
355
363
  const res = await fetch(
356
364
  `${this.drmDomain}/utilities/services/apexrest/countries`
@@ -358,8 +366,7 @@ export default class J2sCardSequence extends LightningElement {
358
366
  if (!res.ok) {
359
367
  throw new Error(errorMsg);
360
368
  }
361
- const data = await res.json();
362
- this.countries = JSON.stringify(data);
369
+ this.countries = await res.json();
363
370
  } catch (error) {
364
371
  console.error(error);
365
372
  if (this.initialStepIndex > 0) {
@@ -379,6 +386,7 @@ export default class J2sCardSequence extends LightningElement {
379
386
  const res = await fetch(`${this.tbidApiBaseUrl}/userinfo`);
380
387
  if (res.ok) {
381
388
  this.tbidUserInfo = await res.json();
389
+ this.selectedCountry = this.formIncomingUserInfo.MailingCountry;
382
390
  }
383
391
  } catch (ex) {
384
392
  // noop; nothing to do here