Skip to content

g1t/apps/web/app/routes/settings/github.tsx

82 lines3,433 bytesCodeBlame
1import { Form } from "react-router";
2
3import type { Route } from "./+types/github";
4import { page } from "../../lib/meta";
5import { ErrorText, SubmitButton, TimeAgo } from "../../components/ui";
6import { Hint } from "../../components/ui/hint";
7import { assertSameOrigin, requireUser } from "../../lib/session.server";
8import { GithubMark } from "../../components/github";
9import { githubSignIn } from "../../lib/github.server";
10
11export function meta(args: Route.MetaArgs) {
12 return page(args, { title: "GitHub · Settings · g1t" });
13}
14
15export async function loader({ request, context }: Route.LoaderArgs) {
16 const user = requireUser(context, request);
17 return { github: await githubSignIn.account(user).catch(() => null) };
18}
19
20export async function action({ request, context }: Route.ActionArgs) {
21 assertSameOrigin(request);
22 const user = requireUser(context, request);
23 const form = await request.formData();
24 if (form.get("intent") === "unlink-github") {
25 const result = await githubSignIn.unlink(user);
26 return result.ok ? null : { githubError: result.error.message };
27 }
28 return null;
29}
30
31export default function GithubSettings({ loaderData, actionData }: Route.ComponentProps) {
32 const { github } = loaderData;
33 if (!github?.enabled) {
34 return <p className="text-sm text-muted">Signing in with GitHub is not set up here.</p>;
35 }
36 return (
37 <section id="github" className="scroll-mt-20">
38 {github.account ? (
39 <div className="flex flex-wrap items-center gap-x-4 gap-y-2 rounded-md border border-line px-4 py-3">
40 <GithubMark className="size-5 shrink-0" />
41 <div className="min-w-0">
42 <p className="text-sm">
43 Linked to <span className="font-mono">@{github.account.login}</span>
44 </p>
45 <p className="text-xs text-faint">
46 Since <TimeAgo at={github.account.linkedAt} />
47 {!github.account.authorized && " · access ended: link it again to import repositories"}
48 </p>
49 </div>
50 <div className="ml-auto flex items-center gap-2">
51 {!github.account.authorized && (
52 <a href="/auth/github?link=1" className="text-sm text-muted hover:text-fg">
53 Link again
54 </a>
55 )}
56 <Form method="post">
57 <input type="hidden" name="intent" value="unlink-github" />
58 <Hint label={github.hasPassword ? undefined : "GitHub is how you sign in. Set a password first."} disabled={!github.hasPassword}>
59 <SubmitButton variant="quiet" pending="Unlinking…" match={{ intent: "unlink-github" }} disabled={!github.hasPassword}>
60 Unlink
61 </SubmitButton>
62 </Hint>
63 </Form>
64 </div>
65 </div>
66 ) : (
67 <a
68 href="/auth/github?link=1"
69 className="inline-flex items-center gap-2 rounded-md border border-line px-3.5 py-2 text-sm font-medium text-fg/90 hover:border-line-strong hover:bg-surface hover:text-fg"
70 >
71 <GithubMark /> Link GitHub
72 </a>
73 )}
74 {github.account && !github.hasPassword && (
75 <p className="mt-2 text-xs text-faint">
76 GitHub is the only way you sign in, so it cannot be unlinked yet. Sign out and use Forgot your password to set one.
77 </p>
78 )}
79 <ErrorText>{actionData?.githubError}</ErrorText>
80 </section>
81 );
82}