flagon-io/g1t

public

Where people and agents ship software together. The open-source git platform for the whole job: issues, agents, checks and deploys to the edge.

g1t/apps/web/app/routes/register.tsx

84 lines2,482 bytesCodeBlame
1import { Form, Link, redirect } from "react-router";
2
3import type { Route } from "./+types/register";
4import { AuthCard } from "../components/auth-card";
5import { Button, ErrorText, Field, Input } from "../components/ui";
6import { identity } from "../lib/services.server";
7import {
8 assertSameOrigin,
9 getViewer,
10 nextPath,
11 startSession,
12} from "../lib/session.server";
13
14export function meta({}: Route.MetaArgs) {
15 return [{ title: "Create an account · g1t" }];
16}
17
18export function loader({ request, context }: Route.LoaderArgs) {
19 if (getViewer(context)) throw redirect(nextPath(request));
20 return null;
21}
22
23export async function action({ request }: Route.ActionArgs) {
24 assertSameOrigin(request);
25 const form = await request.formData();
26 const result = await identity.register(
27 String(form.get("username") ?? ""),
28 String(form.get("email") ?? ""),
29 String(form.get("password") ?? ""),
30 );
31 if (!result.ok) return { error: result.error.message };
32 throw redirect(nextPath(request), {
33 headers: { "set-cookie": startSession(result.value.sessionToken) },
34 });
35}
36
37export default function Register({ actionData }: Route.ComponentProps) {
38 return (
39 <AuthCard
40 title="Create your account"
41 subtitle="Git for AI scale"
42 footer={
43 <>
44 Already have an account?{" "}
45 <Link to="/login" className="text-fg underline underline-offset-4">
46 Sign in
47 </Link>
48 </>
49 }
50 >
51 <Form method="post" className="space-y-4">
52 <Field
53 label="Username"
54 hint="Lowercase letters, digits and hyphens. It is how you sign in and how others see you."
55 >
56 <Input
57 name="username"
58 autoComplete="username"
59 required
60 autoFocus
61 maxLength={39}
62 pattern="[a-z0-9](?:[a-z0-9]|-(?=[a-z0-9]))*"
63 />
64 </Field>
65 <Field label="Email">
66 <Input name="email" type="email" autoComplete="email" required />
67 </Field>
68 <Field label="Password" hint="At least 10 characters.">
69 <Input
70 name="password"
71 type="password"
72 autoComplete="new-password"
73 required
74 minLength={10}
75 />
76 </Field>
77 <ErrorText>{actionData?.error}</ErrorText>
78 <div className="pt-2 *:w-full">
79 <Button type="submit">Create account</Button>
80 </div>
81 </Form>
82 </AuthCard>
83 );
84}