Skip to content

Commit

Permalink
sign in and sign up (mdn#2975)
Browse files Browse the repository at this point in the history
* sign-in and sign-up

Part of mdn#2449

* wip

* wip

* documentation

* tests

* use XHR for signup

* re-trigger whoami after you've signed up
  • Loading branch information
peterbe committed Jun 1, 2021
1 parent 3a6a72b commit f7a816e
Show file tree
Hide file tree
Showing 15 changed files with 587 additions and 42 deletions.
29 changes: 18 additions & 11 deletions build/spas.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,8 @@ async function buildSPAs(options) {
console.log("Wrote", path.join(outPath, path.basename(url)));
}

// Basically, this builds one `search/index.html` for every locale we intend
// to build.
// Basically, this builds one (for example) `search/index.html` for every
// locale we intend to build.
for (const root of [CONTENT_ROOT, CONTENT_TRANSLATED_ROOT]) {
if (!root) {
continue;
Expand All @@ -35,15 +35,22 @@ async function buildSPAs(options) {
if (!fs.statSync(path.join(root, locale)).isDirectory()) {
continue;
}
const url = `/${locale}/search`;
const html = renderHTML(url);
const outPath = path.join(BUILD_OUT_ROOT, locale, "search");
fs.mkdirSync(outPath, { recursive: true });
const filePath = path.join(outPath, "index.html");
fs.writeFileSync(filePath, html);
buildCount++;
if (options.verbose) {
console.log("Wrote", filePath);
const SPAs = [
{ prefix: "search", pageTitle: "Search" },
{ prefix: "signin", pageTitle: "Sign in" },
{ prefix: "signup", pageTitle: "Sign up" },
];
for (const { prefix, pageTitle } of SPAs) {
const url = `/${locale}/${prefix}`;
const html = renderHTML(url, { pageTitle });
const outPath = path.join(BUILD_OUT_ROOT, locale, prefix);
fs.mkdirSync(outPath, { recursive: true });
const filePath = path.join(outPath, "index.html");
fs.writeFileSync(filePath, html);
buildCount++;
if (options.verbose) {
console.log("Wrote", filePath);
}
}
}
}
Expand Down
17 changes: 17 additions & 0 deletions client/src/app.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import { SiteSearch } from "./site-search";
import { PageContentContainer } from "./ui/atoms/page-content";
import { PageNotFound } from "./page-not-found";
import { Banner } from "./banners";
import { SignIn, SignUp } from "./auth";

const AllFlaws = React.lazy(() => import("./flaws"));
const DocumentEdit = React.lazy(() => import("./document/forms/edit"));
Expand Down Expand Up @@ -196,6 +197,22 @@ export function App(appProps) {
</StandardLayout>
}
/>
<Route
path="/signin"
element={
<StandardLayout>
<SignIn />
</StandardLayout>
}
/>
<Route
path="/signup"
element={
<StandardLayout>
<SignUp />
</StandardLayout>
}
/>
<Route
path="/docs/*"
element={<DocumentOrPageNotFound {...appProps} />}
Expand Down
54 changes: 54 additions & 0 deletions client/src/auth/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
import React from "react";

import { PageContentContainer } from "../ui/atoms/page-content";

const SignInApp = React.lazy(() => import("./sign-in"));
const SignUpApp = React.lazy(() => import("./sign-up"));

function Container({
pageTitle,
children,
className,
}: {
pageTitle: string;
children: React.ReactNode;
className: string;
}) {
const isServer = typeof window === "undefined";
React.useEffect(() => {
document.title = pageTitle;
}, [pageTitle]);
return (
<div className={className}>
<PageContentContainer>
{/* The reason for displaying this <h1> here (and for SignUp too)
is to avoid an unnecessary "flicker".
component here is loaded SSR and is immediately present.
Only the "guts" below is lazy loaded. By having the header already
present the page feels less flickery at a very affordable cost of
allowing this to be part of the main JS bundle.
*/}
<h1>{pageTitle}</h1>
{!isServer && children}
</PageContentContainer>
</div>
);
}
export function SignIn() {
return (
<Container className="sign-in" pageTitle="Sign in">
<React.Suspense fallback={<p>Loading...</p>}>
<SignInApp />
</React.Suspense>
</Container>
);
}
export function SignUp() {
return (
<Container className="sign-up" pageTitle="Sign up">
<React.Suspense fallback={<p>Loading...</p>}>
<SignUpApp />
</React.Suspense>
</Container>
);
}
94 changes: 94 additions & 0 deletions client/src/auth/sign-in.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
import { useSearchParams } from "react-router-dom";

import { useUserData } from "../user-context";
import { useLocale } from "../hooks";

export default function SignInApp() {
const [searchParams] = useSearchParams();
const locale = useLocale();
const userData = useUserData();
const sp = new URLSearchParams();

// This is the `?next=` parameter we send into the redirect loop IF you did
// not click into this page from an existing one.
const defaultNext = `/${locale}/`;

let next = searchParams.get("next") || defaultNext;
if (next.toLowerCase() === window.location.pathname.toLowerCase()) {
// It's never OK for the ?next= variable to be to come back here to this page.
// Explicitly check that.
next = defaultNext;
}

let prefix = "";
// When doing local development with Yari, the link to authenticate in Kuma
// needs to be absolute. And we also need to send the absolute URL as the
// `next` query string parameter so Kuma sends us back when the user has
// authenticated there.
if (
process.env.NODE_ENV === "development" &&
process.env.REACT_APP_KUMA_HOST
) {
const combined = new URL(next, window.location.href);
next = combined.toString();
prefix = `http://${process.env.REACT_APP_KUMA_HOST}`;
}
sp.set("next", next);

// Temporary just long as Kuma still needs to support sign-up both as
// Kuma front-end (HTML) Yari (redirects).
// Delete this line once Kuma ONLY deals with Yari in the signup view.
sp.set("yarisignup", "1");

return (
<div>
{/* We need to wait for the userData (/api/v1/whoami) because it will
determine what we display.
We *could* render on the optimism that people most likely will be
on this page because they're NOT signed in. But it feels a bit
"ugly" if a page has to change its mind and rerender something
completely different without it being due to a user action.
*/}
{userData ? (
<>
{userData.isAuthenticated ? (
<form method="post" action={`${prefix}/${locale}/users/signout`}>
<p>
You're <b>already signed in</b>.
</p>

{/* XXX Here it would be great to link to the account settings page */}

<input type="hidden" name="next" value={next} />
<button type="submit" className="button">
Sign out
</button>
<p>
Or, <a href="/">return to the home page</a>.
</p>
</form>
) : (
<ul>
<li>
<a href={`${prefix}/users/github/login/?${sp.toString()}`}>
GitHub&trade;
</a>
</li>
<li>
<a href={`${prefix}/users/google/login/?${sp.toString()}`}>
Google&trade;
</a>
</li>
</ul>
)}
</>
) : (
<Loading />
)}
</div>
);
}

function Loading() {
return <p style={{ minHeight: 200 }}>Loading...</p>;
}
11 changes: 11 additions & 0 deletions client/src/auth/sign-up.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
.sign-up {
form {
button[disabled] {
opacity: 0.5;
}
}
// .user-details img.picture {
// width: 100px;
// border-radius: 50px;
// }
}
Loading

0 comments on commit f7a816e

Please sign in to comment.