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

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