g1t/apps/web/app/routes/auth-github-username.tsx

93 lines3,686 bytesCodeBlame

Pick any line to see why it is the way it is: the commit, the pull request and issue it came from, and what the agent was thinking.

Merge branch 'worktree-agent-a985c01f43538af01'1import { Form, Link, redirect } from "react-router";
Invite-only launch: sign in with GitHub, repository access and lifecycle, many emails, a new look2
3import type { Route } from "./+types/auth-github-username";
4import { AuthCard } from "../components/auth-card";
5import { GithubMark } from "../components/github";
Merge branch 'worktree-agent-a985c01f43538af01'6import { ErrorText, Field, Input, SubmitButton } from "../components/ui";
Invite-only launch: sign in with GitHub, repository access and lifecycle, many emails, a new look7import { PENDING_COOKIE, cookie, readCookie } from "../lib/github";
8import { githubSignIn } from "../lib/github.server";
9import { page } from "../lib/meta";
10import { safeNext } from "../lib/next";
11import { assertSameOrigin, startSession } from "../lib/session.server";
12
13export function meta(args: Route.MetaArgs) {
14 return page(args, { title: "Choose a username · g1t" });
15}
16
17/** A new account from GitHub, once its username (and invite) are settled. */
18export async function loader({ request }: Route.LoaderArgs) {
19 const pending = readCookie(request.headers.get("cookie"), PENDING_COOKIE);
20 if (!pending) throw redirect("/register");
21 const found = await githubSignIn.pending(pending);
22 if (!found.ok || found.value.kind !== "username") {
23 throw redirect("/register", { headers: { "set-cookie": cookie(PENDING_COOKIE, "", 0) } });
24 }
25 return found.value;
26}
27
28export async function action({ request }: Route.ActionArgs) {
29 assertSameOrigin(request);
30 const pending = readCookie(request.headers.get("cookie"), PENDING_COOKIE);
31 if (!pending) throw redirect("/register");
32 const form = await request.formData();
33 // Where to go afterwards, read before the pending sign-in is used up.
34 const found = await githubSignIn.pending(pending).catch(() => null);
35 const result = await githubSignIn.signUp(
36 pending,
37 String(form.get("username") ?? ""),
38 String(form.get("invite") ?? "").trim() || null,
39 );
40 if (!result.ok) return { error: result.error.message };
41 const headers = new Headers({ "set-cookie": startSession(result.value.sessionToken) });
42 headers.append("set-cookie", cookie(PENDING_COOKIE, "", 0));
43 throw redirect(safeNext(found?.ok ? found.value.next : "/"), { headers });
44}
45
46export default function GithubUsername({ loaderData, actionData }: Route.ComponentProps) {
47 return (
48 <AuthCard
49 title="Create your account"
50 subtitle={loaderData.inviteRequired ? "g1t is invite-only for now" : "Choose your username"}
51 footer={
52 <>
53 Have an account already?{" "}
54 <Link to="/login?github=link" className="text-fg underline underline-offset-4">
55 Sign in to link GitHub
56 </Link>
57 </>
58 }
59 >
60 <p className="mb-6 flex items-center gap-2 text-sm text-muted">
61 <GithubMark />
62 Signed in to GitHub as <span className="font-mono text-fg">@{loaderData.login}</span>
63 </p>
64 <Form method="post" className="space-y-4">
65 <Field
66 label="Username"
67 hint="Lowercase letters, digits and hyphens. It is how others see you on g1t."
68 >
69 <Input
70 name="username"
71 autoComplete="username"
72 required
73 autoFocus
74 maxLength={39}
75 defaultValue={loaderData.suggestion ?? ""}
76 pattern="[a-z0-9](?:[a-z0-9]|-(?=[a-z0-9]))*"
77 />
78 </Field>
79 {loaderData.inviteRequired && (
80 <Field label="Invite code" hint="g1t is invite-only. Ask someone on g1t for one of their invites.">
81 <Input name="invite" required autoComplete="off" spellCheck={false} />
82 </Field>
83 )}
84 <ErrorText>{actionData?.error}</ErrorText>
85 <div className="pt-2 *:w-full">
Merge branch 'worktree-agent-a985c01f43538af01'86 <SubmitButton pending="Creating account…">
Invite-only launch: sign in with GitHub, repository access and lifecycle, many emails, a new look87 Create account
Merge branch 'worktree-agent-a985c01f43538af01'88 </SubmitButton>
Invite-only launch: sign in with GitHub, repository access and lifecycle, many emails, a new look89 </div>
90 </Form>
91 </AuthCard>
92 );
93}

This file's history is long; its oldest lines are credited to the oldest commit read.