Skip to content

Commit 529435c

Browse files
committed
Add custom sign-in / sign-up forms
1 parent cb15105 commit 529435c

File tree

7 files changed

+168
-860
lines changed

7 files changed

+168
-860
lines changed

examples/force-an-org-custom-flow-vanilla-js/README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,4 +22,4 @@ pnpm i
2222
pnpm dev
2323
```
2424

25-
Open [http://localhost:3000](http://localhost:3000) with your browser to see the result.
25+
Open [http://localhost:5173](http://localhost:5173) with your browser to see the result.

examples/force-an-org-custom-flow-vanilla-js/index.html

Lines changed: 40 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,46 @@
99
</head>
1010

1111
<body>
12-
<div id="app"></div>
13-
<script type="module" src="./src/main.js"></script>
12+
<div id="signed-in"></div>
13+
14+
<div id="sign-up">
15+
<h2>Sign up</h2>
16+
<form id="sign-up-form">
17+
<label for="email">Enter email address</label>
18+
<input type="email" name="email" id="sign-up-email" />
19+
<label for="password">Enter password</label>
20+
<input type="password" name="password" id="sign-up-password" />
21+
<button type="submit">Continue</button>
22+
</form>
23+
</div>
24+
25+
<div id="sign-in">
26+
<h2>Sign in</h2>
27+
<form id="sign-in-form">
28+
<label for="email">Enter email address</label>
29+
<input name="email" id="sign-in-email" />
30+
<label for="password">Enter password</label>
31+
<input name="password" id="sign-in-password" />
32+
<button type="submit">Continue</button>
33+
</form>
34+
</div>
35+
36+
<form id="verifying" hidden>
37+
<h2>Verify your account</h2>
38+
<label for="totp">Enter your code</label>
39+
<input id="totp" name="code" />
40+
<label for="backupCode">This code is a backup code</label>
41+
<input type="checkbox" id="backupCode" name="backupCode" />
42+
<button type="submit" id="verify-button">Verify</button>
43+
</form>
44+
45+
<form id="create-organization" hidden>
46+
<label for="name">Name</label>
47+
<input id="name" name="name" />
48+
<button>Create organization</button>
49+
</form>
50+
51+
<script type="module" src="/src/main.js" async crossorigin="anonymous"></script>
1452
</body>
1553

1654
</html>

examples/force-an-org-custom-flow-vanilla-js/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
{
2-
"name": "clerk-javascript",
2+
"name": "clerk-force-an-org",
33
"private": true,
44
"version": "0.0.0",
55
"type": "module",

examples/force-an-org-custom-flow-vanilla-js/public/vite.svg

Lines changed: 0 additions & 1 deletion
This file was deleted.

examples/force-an-org-custom-flow-vanilla-js/src/main.js

Lines changed: 126 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -5,20 +5,137 @@ const publishableKey = import.meta.env.VITE_CLERK_PUBLISHABLE_KEY;
55
const clerk = new Clerk(publishableKey);
66
await clerk.load();
77

8-
if (clerk.isSignedIn()) {
9-
document.getElementById("app").innerHTML = `
8+
if (clerk.isSignedIn) {
9+
// Mount user button component - or any sort of protected UI relying on the user
10+
document.getElementById("signed-in").innerHTML = `
1011
<div id="user-button"></div>
1112
`;
1213

13-
const userButtonDiv = document.getElementById("user-button");
14+
const userbuttonDiv = document.getElementById("user-button");
1415

15-
clerk.mountUserButton(userButtonDiv);
16+
clerk.mountUserButton(userbuttonDiv);
1617
} else {
17-
document.getElementById("app").innerHTML = `
18-
<div id="sign-in"></div>
19-
`;
18+
// Handle the sign-in form
19+
document
20+
.getElementById("sign-in-form")
21+
.addEventListener("submit", async (e) => {
22+
e.preventDefault();
23+
24+
const formData = new FormData(e.target);
25+
const emailAddress = formData.get("email");
26+
const password = formData.get("password");
27+
28+
try {
29+
// Start the sign-in process
30+
const signInAttempt = await clerk.client.signIn.create({
31+
identifier: emailAddress,
32+
password,
33+
});
34+
35+
// If the sign-in is complete, set the user as active
36+
if (signInAttempt.status === "complete") {
37+
await clerk.setActive({ session: signInAttempt.createdSessionId });
38+
await displayNextTaskIfAny();
39+
} else {
40+
// If the status is not complete, check why. User may need to
41+
// complete further steps.
42+
console.error(JSON.stringify(signInAttempt, null, 2));
43+
}
44+
} catch (error) {
45+
// See https://clerk.com/docs/custom-flows/error-handling
46+
// for more info on error handling
47+
console.error(error);
48+
}
49+
});
50+
51+
// Handle the sign-up form
52+
document
53+
.getElementById("sign-up-form")
54+
.addEventListener("submit", async (e) => {
55+
e.preventDefault();
56+
57+
const formData = new FormData(e.target);
58+
const emailAddress = formData.get("email");
59+
const password = formData.get("password");
60+
61+
try {
62+
// Start the sign-up process using the email and password provided
63+
await clerk.client.signUp.create({ emailAddress, password });
64+
await clerk.client.signUp.prepareEmailAddressVerification();
65+
// Hide first-factor form
66+
document.getElementById("sign-up").setAttribute("hidden", "");
67+
document.getElementById("sign-in").setAttribute("hidden", "");
68+
69+
// Show verification form
70+
document.getElementById("verifying").removeAttribute("hidden");
71+
} catch (error) {
72+
// See https://clerk.com/docs/custom-flows/error-handling
73+
// for more info on error handling
74+
console.error(error);
75+
}
76+
});
77+
78+
// Handle the verification form
79+
document.getElementById("verifying").addEventListener("submit", async (e) => {
80+
const formData = new FormData(e.target);
81+
const code = formData.get("code");
82+
83+
try {
84+
// Use the code the user provided to attempt verification
85+
const signUpAttempt =
86+
await clerk.client.signUp.attemptEmailAddressVerification({
87+
code,
88+
});
89+
90+
// Now that the user is created, set the session to active.
91+
// TODO: Update this with clerk.setCurrentSession(signUpAttempt.createdSessionId)
92+
await clerk.setActive({ session: signUpAttempt.createdSessionId });
93+
// Display organization selection UI if session doesn't have a organization selected
94+
await displayNextTaskIfAny();
95+
} catch (error) {
96+
// See https://clerk.com/docs/custom-flows/error-handling
97+
// for more info on error handling
98+
console.error(error);
99+
}
100+
});
101+
102+
// Handle organization selection
103+
document
104+
.getElementById("create-organization")
105+
.addEventListener("submit", async (e) => {
106+
e.preventDefault();
107+
108+
const inputEl = document.getElementById("name");
109+
110+
if (!inputEl) {
111+
return;
112+
}
113+
114+
clerk
115+
.createOrganization({ name: inputEl.value })
116+
.then((res) => console.log(res))
117+
.catch((error) => console.log("An error occurred:", error));
118+
119+
// Hide the organization creation form after successful creation
120+
document
121+
.getElementById("create-organization")
122+
.setAttribute("hidden", "true");
123+
// Handle any remaining tasks in the flow
124+
await displayNextTaskIfAny();
125+
});
126+
}
127+
128+
// Check for any pending tasks (like organization creation) and display the corresponding UI element
129+
async function displayNextTaskIfAny() {
130+
const task = await clerk.__experimental_nextTask();
20131

21-
const signInDiv = document.getElementById("sign-in");
132+
const mapTaskKeyToElementId = {
133+
org: "create-organization",
134+
};
22135

23-
clerk.mountSignIn(signInDiv);
136+
// Here we're toggling UI visibility, but you could also navigate to different pages
137+
// if you're application supports client-side routing
138+
document
139+
.getElementById(mapTaskKeyToElementId[task.key])
140+
.removeAttribute("hidden");
24141
}

package.json

Lines changed: 0 additions & 5 deletions
This file was deleted.

0 commit comments

Comments
 (0)