@salesforcedevs/dw-components 1.3.397-canary.2 → 1.3.397-canary.4
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/deSignupForm/deSignupForm.html +5 -1
- package/src/modules/dw/deSignupForm/deSignupForm.ts +24 -29
- package/src/modules/dw/deSignupForm/submitForm.ts +3 -8
- package/src/modules/dw/recaptcha/recaptcha.css +14 -0
- package/src/modules/dw/recaptcha/recaptcha.html +12 -0
- package/src/modules/dw/recaptcha/recaptcha.ts +82 -0
package/lwc.config.json
CHANGED
package/package.json
CHANGED
|
@@ -117,7 +117,11 @@
|
|
|
117
117
|
<span lwc:dom="manual" class="legal-checkbox privacy-terms"></span>
|
|
118
118
|
</dx-checkbox>
|
|
119
119
|
|
|
120
|
-
<slot
|
|
120
|
+
<slot
|
|
121
|
+
class="form-captcha-slot"
|
|
122
|
+
name="form-captcha-slot"
|
|
123
|
+
onslotchange={onSlotChange}
|
|
124
|
+
></slot>
|
|
121
125
|
|
|
122
126
|
<dx-button
|
|
123
127
|
class="submit-button"
|
|
@@ -4,6 +4,7 @@ import { track as trackGtm } from "dxUtils/analytics";
|
|
|
4
4
|
import { submitForm, ErrorCode, SignupForm, UserData } from "./submitForm";
|
|
5
5
|
import { CountryOptions } from "typings/custom";
|
|
6
6
|
import { stateMap } from "dwUtils/forms";
|
|
7
|
+
import Recaptcha from "packages/@salesforcedevs/dw-components/src/modules/dw/recaptcha/recaptcha";
|
|
7
8
|
|
|
8
9
|
type SelectOption = { value: string; label: string };
|
|
9
10
|
type Country = SelectOption & {
|
|
@@ -47,7 +48,7 @@ export default class DeSignupForm extends LightningElement {
|
|
|
47
48
|
private marketingText: string = "";
|
|
48
49
|
private showLegalCheckbox: boolean = false;
|
|
49
50
|
private privacyText: string = "";
|
|
50
|
-
private
|
|
51
|
+
private recaptchaComponent: Recaptcha | null = null;
|
|
51
52
|
|
|
52
53
|
@track knownDuplicateUsers: string[] = [];
|
|
53
54
|
|
|
@@ -74,26 +75,6 @@ export default class DeSignupForm extends LightningElement {
|
|
|
74
75
|
return stateMap[this.country] || [];
|
|
75
76
|
}
|
|
76
77
|
|
|
77
|
-
@api
|
|
78
|
-
recaptchaCallback(responseToken: string) {
|
|
79
|
-
this.recaptchaToken = responseToken;
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
@api
|
|
83
|
-
recaptchaExpiredCallback() {
|
|
84
|
-
this.recaptchaToken = "";
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
@api
|
|
88
|
-
recaptchaErrorCallback() {
|
|
89
|
-
this.resetRecaptcha();
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
private resetRecaptcha() {
|
|
93
|
-
this.recaptchaToken = "";
|
|
94
|
-
(window as any).grecaptcha?.reset();
|
|
95
|
-
}
|
|
96
|
-
|
|
97
78
|
connectedCallback(): void {
|
|
98
79
|
this.getCountryList();
|
|
99
80
|
}
|
|
@@ -104,6 +85,10 @@ export default class DeSignupForm extends LightningElement {
|
|
|
104
85
|
this.updateInnerHtml("span.legal-checkbox", this.privacyText);
|
|
105
86
|
}
|
|
106
87
|
|
|
88
|
+
onSlotChange(e: Event) {
|
|
89
|
+
this.recaptchaComponent = e.target as Recaptcha;
|
|
90
|
+
}
|
|
91
|
+
|
|
107
92
|
createUUID() {
|
|
108
93
|
if ("crypto" in window && "randomUUID" in crypto) {
|
|
109
94
|
return crypto.randomUUID();
|
|
@@ -147,7 +132,7 @@ export default class DeSignupForm extends LightningElement {
|
|
|
147
132
|
) {
|
|
148
133
|
trackGtm(target!, "custEv_formCompletion", {
|
|
149
134
|
converting_page: `SFDC:us:signup:${convertingPage}`,
|
|
150
|
-
converting_page_url: `https://developer.salesforce.com/signup/${convertingPage}`,
|
|
135
|
+
converting_page_url: `https://developer.salesforce.com/developer-legacy/signup/${convertingPage}`,
|
|
151
136
|
form_country: formData.user.country,
|
|
152
137
|
form_name: "Dev Edition Signup",
|
|
153
138
|
form_primary_product_interest: "Developer Edition",
|
|
@@ -169,7 +154,7 @@ export default class DeSignupForm extends LightningElement {
|
|
|
169
154
|
}
|
|
170
155
|
|
|
171
156
|
const formData = this.prepareUserData();
|
|
172
|
-
if (!formData
|
|
157
|
+
if (!formData) {
|
|
173
158
|
return;
|
|
174
159
|
}
|
|
175
160
|
|
|
@@ -188,7 +173,7 @@ export default class DeSignupForm extends LightningElement {
|
|
|
188
173
|
);
|
|
189
174
|
|
|
190
175
|
this.setSubmitButtonDisabled(true);
|
|
191
|
-
submitForm(formData
|
|
176
|
+
submitForm(formData)
|
|
192
177
|
.then(() => {
|
|
193
178
|
trackGtm(event.target!, "custEv_signUp", {
|
|
194
179
|
authentication_method: "email",
|
|
@@ -196,7 +181,7 @@ export default class DeSignupForm extends LightningElement {
|
|
|
196
181
|
new_registration: true
|
|
197
182
|
});
|
|
198
183
|
this.trackFormCompletion(event.target!, formData, "success");
|
|
199
|
-
window.location.href = "/signup/success";
|
|
184
|
+
window.location.href = "/developer-legacy/signup/success";
|
|
200
185
|
})
|
|
201
186
|
.catch((error) => {
|
|
202
187
|
if (error.message === ErrorCode.GENERIC && didSubmitTimeout) {
|
|
@@ -208,10 +193,11 @@ export default class DeSignupForm extends LightningElement {
|
|
|
208
193
|
// If the timeout time has passed at the point of error, and the error code is simply "GENERIC",
|
|
209
194
|
// we do not know whether the org will ultimately be created (and we have no current way of confirming),
|
|
210
195
|
// so we navigate the user to an interim page that tells them to watch their email.
|
|
211
|
-
window.location.href =
|
|
196
|
+
window.location.href =
|
|
197
|
+
"/developer-legacy/signup/account-verification";
|
|
212
198
|
} else {
|
|
213
199
|
this.setSubmitButtonDisabled(false);
|
|
214
|
-
this.
|
|
200
|
+
this.recaptchaComponent?.reset();
|
|
215
201
|
if (error.message === ErrorCode.DUPLICATE) {
|
|
216
202
|
this.knownDuplicateUsers.push(formData.user.username);
|
|
217
203
|
} else {
|
|
@@ -256,7 +242,15 @@ export default class DeSignupForm extends LightningElement {
|
|
|
256
242
|
validCheckboxes = validCheckboxes && checkbox.reportValidity();
|
|
257
243
|
});
|
|
258
244
|
|
|
259
|
-
|
|
245
|
+
const hasInvalidCaptcha =
|
|
246
|
+
this.recaptchaComponent &&
|
|
247
|
+
!this.recaptchaComponent.reportValidity();
|
|
248
|
+
|
|
249
|
+
if (
|
|
250
|
+
fields.some((field) => !field.valid) ||
|
|
251
|
+
!validCheckboxes ||
|
|
252
|
+
hasInvalidCaptcha
|
|
253
|
+
) {
|
|
260
254
|
return null;
|
|
261
255
|
}
|
|
262
256
|
|
|
@@ -276,7 +270,8 @@ export default class DeSignupForm extends LightningElement {
|
|
|
276
270
|
user: userData as UserData,
|
|
277
271
|
default_driver: DEFAULT_DRIVER,
|
|
278
272
|
info_email: InfoEmail,
|
|
279
|
-
form_join_id_unique: this.createUUID()
|
|
273
|
+
form_join_id_unique: this.createUUID(),
|
|
274
|
+
"g-recaptcha-response": this.recaptchaComponent?.value
|
|
280
275
|
};
|
|
281
276
|
|
|
282
277
|
return formData;
|
|
@@ -24,6 +24,7 @@ export type SignupForm = {
|
|
|
24
24
|
default_driver: string;
|
|
25
25
|
info_email: "True" | "False";
|
|
26
26
|
form_join_id_unique: string;
|
|
27
|
+
"g-recaptcha-response"?: string;
|
|
27
28
|
};
|
|
28
29
|
|
|
29
30
|
type OrgStatus = "New" | "In Progress" | "Error";
|
|
@@ -79,19 +80,13 @@ const checkOrgStatus = (id: string, retries = 0): Promise<void> => {
|
|
|
79
80
|
});
|
|
80
81
|
};
|
|
81
82
|
|
|
82
|
-
export const submitForm = async (
|
|
83
|
-
formData: SignupForm,
|
|
84
|
-
recaptchaToken: string
|
|
85
|
-
): Promise<void> => {
|
|
83
|
+
export const submitForm = async (formData: SignupForm): Promise<void> => {
|
|
86
84
|
const response = await fetch(CREATE_PATH, {
|
|
87
85
|
method: "POST",
|
|
88
86
|
headers: {
|
|
89
87
|
"Content-Type": "application/json"
|
|
90
88
|
},
|
|
91
|
-
body: JSON.stringify(
|
|
92
|
-
...formData,
|
|
93
|
-
"g-recaptcha-response": recaptchaToken
|
|
94
|
-
})
|
|
89
|
+
body: JSON.stringify(formData)
|
|
95
90
|
});
|
|
96
91
|
|
|
97
92
|
if (!response.ok) {
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
@import "dxHelpers/reset";
|
|
2
|
+
@import "dxHelpers/text";
|
|
3
|
+
|
|
4
|
+
.container {
|
|
5
|
+
width: 100%;
|
|
6
|
+
display: flex;
|
|
7
|
+
justify-content: center;
|
|
8
|
+
margin-bottom: var(--dx-g-spacing-lg);
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
.error-message-box {
|
|
12
|
+
margin-top: var(--dx-g-spacing-xs);
|
|
13
|
+
display: block;
|
|
14
|
+
}
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
import { api, LightningElement } from "lwc";
|
|
2
|
+
|
|
3
|
+
declare module globalThis {
|
|
4
|
+
let grecaptcha: {
|
|
5
|
+
render(element: HTMLElement | null, recaptchaConfig: any): void;
|
|
6
|
+
reset(): void;
|
|
7
|
+
};
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export default class Recaptcha extends LightningElement {
|
|
11
|
+
private _recaptchaToken = "";
|
|
12
|
+
private errorMessage = "";
|
|
13
|
+
private slottedRecaptchaDiv: HTMLDivElement | null = null;
|
|
14
|
+
|
|
15
|
+
@api missingErrorMessage = "Complete the captcha";
|
|
16
|
+
@api recaptchaSiteKey = "";
|
|
17
|
+
|
|
18
|
+
@api // read only
|
|
19
|
+
get value() {
|
|
20
|
+
return this._recaptchaToken;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
@api
|
|
24
|
+
reset = () => this.resetRecaptcha();
|
|
25
|
+
|
|
26
|
+
@api
|
|
27
|
+
reportValidity = () => {
|
|
28
|
+
if (!this.checkValidity()) {
|
|
29
|
+
this.errorMessage = this.missingErrorMessage;
|
|
30
|
+
return false;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
this.errorMessage = "";
|
|
34
|
+
return true;
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
@api
|
|
38
|
+
checkValidity = () => {
|
|
39
|
+
return Boolean(
|
|
40
|
+
(
|
|
41
|
+
this.slottedRecaptchaDiv?.querySelector(
|
|
42
|
+
"#g-recaptcha-response"
|
|
43
|
+
) as HTMLTextAreaElement
|
|
44
|
+
)?.value
|
|
45
|
+
);
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
private onSlotChange(e: Event) {
|
|
49
|
+
this.slottedRecaptchaDiv = e.target as HTMLDivElement;
|
|
50
|
+
const smallMatchMedia = window.matchMedia(
|
|
51
|
+
"screen and (max-width: 768px)"
|
|
52
|
+
);
|
|
53
|
+
|
|
54
|
+
// render recaptcha, referencing this component's callbacks for handling events
|
|
55
|
+
globalThis.grecaptcha?.render(this.slottedRecaptchaDiv, {
|
|
56
|
+
sitekey: this.recaptchaSiteKey,
|
|
57
|
+
callback: this.recaptchaCallback,
|
|
58
|
+
"expired-callback": this.recaptchaExpiredCallback,
|
|
59
|
+
"error-callback": this.recaptchaErrorCallback,
|
|
60
|
+
size: smallMatchMedia.matches ? "compact" : "normal"
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
private recaptchaCallback = (token: string) => {
|
|
65
|
+
this._recaptchaToken = token;
|
|
66
|
+
this.errorMessage = "";
|
|
67
|
+
};
|
|
68
|
+
|
|
69
|
+
private recaptchaExpiredCallback = () => {
|
|
70
|
+
this._recaptchaToken = ""; // note: recaptcha element itself handles showing an "expired" message
|
|
71
|
+
};
|
|
72
|
+
|
|
73
|
+
private recaptchaErrorCallback = () => {
|
|
74
|
+
this.resetRecaptcha();
|
|
75
|
+
this.errorMessage = ""; // this error message is only set to a value when the form is submitted or `reportValidity` is called explicitly
|
|
76
|
+
};
|
|
77
|
+
|
|
78
|
+
private resetRecaptcha = () => {
|
|
79
|
+
this._recaptchaToken = "";
|
|
80
|
+
globalThis.grecaptcha?.reset();
|
|
81
|
+
};
|
|
82
|
+
}
|