129 lines
5.1 KiB
HTML
129 lines
5.1 KiB
HTML
<!doctype html>
|
|
<html lang="en">
|
|
<head>
|
|
<meta charset="utf-8">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
<title>Sign in</title>
|
|
<meta name="robots" content="noindex">
|
|
<meta name="referrer" content="no-referrer">
|
|
<link rel="stylesheet" href="/assets/app.css">
|
|
</head>
|
|
<body>
|
|
<div class="wrap">
|
|
|
|
<header class="page">
|
|
<h1 id="h1">Sign in</h1>
|
|
<p id="lead">Enter your email address and we will text a code to the phone on your account.</p>
|
|
</header>
|
|
|
|
<section style="max-width:520px">
|
|
<div class="card">
|
|
<div class="msg" id="msg"></div>
|
|
|
|
<!-- Step 1, returning visitors only: which account. An invitation skips this. -->
|
|
<form id="who" style="display:none">
|
|
<div class="field">
|
|
<label for="email">Email address</label>
|
|
<input type="email" id="email" autocomplete="email" placeholder="you@example.com" required>
|
|
</div>
|
|
<button class="btn" id="send" type="submit">Text me a code</button>
|
|
</form>
|
|
|
|
<!-- Step 2: the code from the text message. -->
|
|
<form id="code" style="display:none">
|
|
<div class="field">
|
|
<label for="digits">The code we texted you</label>
|
|
<span class="hint" id="sentto"></span>
|
|
<input type="text" id="digits" inputmode="numeric" autocomplete="one-time-code" maxlength="8"
|
|
placeholder="123456" style="font-size:22px;letter-spacing:.3em;max-width:220px" required>
|
|
</div>
|
|
<button class="btn" id="check" type="submit">Sign in</button>
|
|
<button class="btn ghost" id="again" type="button" style="margin-left:8px">Send a new code</button>
|
|
</form>
|
|
</div>
|
|
|
|
<p class="note" style="margin-top:22px" id="foot">
|
|
No invitation yet? <a href="/join.html">Join the waiting list</a>.
|
|
</p>
|
|
</section>
|
|
</div>
|
|
|
|
<script src="/assets/app.js"></script>
|
|
<script>
|
|
navBar("");
|
|
var params = new URLSearchParams(location.search);
|
|
var invite = params.get("invite") || "";
|
|
var next = safeNext(params.get("next"), "");
|
|
var email = "";
|
|
|
|
// The invitation is a credential. Take it out of the address bar straight
|
|
// away so it is not left in the history or copied with the link.
|
|
if (invite && history.replaceState) history.replaceState(null, "", "/login.html");
|
|
|
|
function show(id) {
|
|
["who", "code"].forEach(function (f) { document.getElementById(f).style.display = f === id ? "block" : "none"; });
|
|
var first = document.querySelector("#" + id + " input");
|
|
if (first) first.focus();
|
|
}
|
|
|
|
function signedIn(r) {
|
|
Session.start(r, r.user.email, r.user.display_name || "");
|
|
showMsg("msg", "You are in. Taking you through…", "ok");
|
|
var home = (r.site && r.site.home && r.site.home !== "/") ? r.site.home : "/create.html";
|
|
setTimeout(function () { location.href = next || home; }, 500);
|
|
}
|
|
|
|
async function sendCode() {
|
|
hideMsg("msg");
|
|
var r = invite ? await api("invite_open", { invite: invite }) : await api("login_start", { email: email });
|
|
if (!r || !r.ok) { showMsg("msg", (r && r.error) || "That did not work. Please try again."); return false; }
|
|
if (invite) {
|
|
document.getElementById("h1").textContent = r.first_name ? "Welcome, " + r.first_name : "Welcome";
|
|
document.getElementById("lead").textContent = "One step to finish: we have texted a code to your phone.";
|
|
document.getElementById("sentto").textContent = "Sent to " + (r.phone_hint || "your phone") + ". It can take a minute to arrive.";
|
|
} else if (r.sms === false) {
|
|
showMsg("msg", "Text messages are not switched on yet, so codes cannot be sent. Please try again later.");
|
|
return false;
|
|
} else {
|
|
document.getElementById("sentto").textContent = "If that address has an account, a code is on its way to the phone on it.";
|
|
}
|
|
show("code");
|
|
return true;
|
|
}
|
|
|
|
document.getElementById("who").addEventListener("submit", async function (e) {
|
|
e.preventDefault();
|
|
email = document.getElementById("email").value.trim();
|
|
if (!email) { showMsg("msg", "Please enter your email address."); return; }
|
|
var b = document.getElementById("send");
|
|
b.disabled = true;
|
|
await sendCode();
|
|
b.disabled = false;
|
|
});
|
|
|
|
document.getElementById("again").addEventListener("click", async function () {
|
|
this.disabled = true;
|
|
if (await sendCode()) showMsg("msg", "A new code is on its way.", "ok");
|
|
this.disabled = false;
|
|
});
|
|
|
|
document.getElementById("code").addEventListener("submit", async function (e) {
|
|
e.preventDefault();
|
|
hideMsg("msg");
|
|
var digits = document.getElementById("digits").value.replace(/\D/g, "");
|
|
if (digits.length < 4) { showMsg("msg", "Enter the code from the text message."); return; }
|
|
var b = document.getElementById("check");
|
|
b.disabled = true;
|
|
var r = invite ? await api("invite_verify", { invite: invite, code: digits })
|
|
: await api("login_verify", { email: email, code: digits });
|
|
b.disabled = false;
|
|
if (!r || !r.ok) { showMsg("msg", (r && r.error) || "That code is not right."); return; }
|
|
signedIn(r);
|
|
});
|
|
|
|
if (Session.token() && !invite) location.replace(next || "/");
|
|
else if (invite) sendCode().then(function (ok) { if (!ok) document.getElementById("foot").style.display = "block"; });
|
|
else show("who");
|
|
</script>
|
|
</body>
|
|
</html>
|