Skip to content
56 linesCodeBlameRaw

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.

Invite-only launch: sign in with GitHub, repository access and lifecycle, many emails, a new look1import type { Invite, InvitesOverview, User } from "@g1t/contracts";
2
Two invites, said plainly: an invite to g1t joins no workspace, an invitation to a workspace is made on its People page3import { type BringInto, bringIntoChoices, inviteDraft, peoplePages } from "./invites";
Merge workspace invitations: nobody joins a workspace without saying yes, people are found by username, your own invites can bring someone in, and nobody is left without a workspace (identity 0040)4import { readCookie } from "./mission";
5import { billing, identity } from "./services.server";
6import { WORKSPACE_COOKIE, chosenWorkspace } from "./workspace-choice";
Invite-only launch: sign in with GitHub, repository access and lifecycle, many emails, a new look7
8/** What the Invites section's forms answer. */
9export type InviteActionData = { inviteCreated?: Invite; inviteError?: string; inviteRevoked?: boolean } | null;
10
Two invites, said plainly: an invite to g1t joins no workspace, an invitation to a workspace is made on its People page11/**
12 * The workspaces an invite to g1t can also invite its person to
13 * (`bringIntoChoices`), and the People pages where a workspace invitation
14 * is made instead (`peoplePages`).
15 */
16export type BringIntoChoices = {
17 options: BringInto[];
18 note: string | null;
19 people: { slug: string; name: string; to: string }[];
20};
Merge workspace invitations: nobody joins a workspace without saying yes, people are found by username, your own invites can bring someone in, and nobody is left without a workspace (identity 0040)21
Invite-only launch: sign in with GitHub, repository access and lifecycle, many emails, a new look22/** A person's invites, or null when they cannot make any yet (email unconfirmed). */
23export async function loadInvites(user: User): Promise<InvitesOverview | null> {
24 if (!user.verified) return null;
25 return identity.listInvites(user).catch(() => null);
26}
27
Merge workspace invitations: nobody joins a workspace without saying yes, people are found by username, your own invites can bring someone in, and nobody is left without a workspace (identity 0040)28/**
Two invites, said plainly: an invite to g1t joins no workspace, an invitation to a workspace is made on its People page29 * The workspaces an invite can also invite its person to, and the People
30 * pages to invite someone to a workspace from, the one the person is in
31 * (the shell's current workspace, from its cookie) first. A workspace
32 * whose plan cannot be checked is not offered: identity would refuse it.
Merge workspace invitations: nobody joins a workspace without saying yes, people are found by username, your own invites can bring someone in, and nobody is left without a workspace (identity 0040)33 */
34export async function loadBringInto(user: User, request: Request): Promise<BringIntoChoices> {
35 const memberships = user.workspaces ?? [];
36 const owned = memberships.filter((m) => m.role === "owner").map((m) => m.slug);
37 const free = owned.length > 0 ? await billing.freeWorkspaces(owned).catch(() => owned) : [];
38 const current = chosenWorkspace(memberships, readCookie(request.headers.get("cookie"), WORKSPACE_COOKIE))?.slug ?? null;
Two invites, said plainly: an invite to g1t joins no workspace, an invitation to a workspace is made on its People page39 return { ...bringIntoChoices(memberships, free, current), people: peoplePages(memberships, current) };
Merge workspace invitations: nobody joins a workspace without saying yes, people are found by username, your own invites can bring someone in, and nobody is left without a workspace (identity 0040)40}
41
Invite-only launch: sign in with GitHub, repository access and lifecycle, many emails, a new look42/** Handles the Invites section's intents; null for any other intent. */
43export async function inviteAction(user: User, form: FormData): Promise<InviteActionData | undefined> {
44 switch (form.get("intent")) {
45 case "create-invite": {
Two invites, said plainly: an invite to g1t joins no workspace, an invitation to a workspace is made on its People page46 // A workspace goes with it only when its box is ticked (`inviteDraft`).
47 const result = await identity.createInvite(user, inviteDraft(form));
Invite-only launch: sign in with GitHub, repository access and lifecycle, many emails, a new look48 return result.ok ? { inviteCreated: result.value } : { inviteError: result.error.message };
49 }
50 case "revoke-invite": {
51 const result = await identity.revokeInvite(user, String(form.get("id") ?? ""));
52 return result.ok ? { inviteRevoked: true } : { inviteError: result.error.message };
53 }
54 }
55 return undefined;
56}

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